Skip to content

Commit

Permalink
feat: add slider web component (microsoft#2861)
Browse files Browse the repository at this point in the history
* Adding slider component
* horizontal and vertical orientation
* rtl support
* single-value only
  • Loading branch information
marjonlynch authored Apr 13, 2020
1 parent d295394 commit c295e01
Show file tree
Hide file tree
Showing 13 changed files with 1,079 additions and 0 deletions.
30 changes: 30 additions & 0 deletions packages/fast-components/src/slider-label/fixtures/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<fast-design-system-provider use-defaults>
<div style="display: grid;">
<!-- Basic -->
<div style="margin: 20px; position: relative;">
<fast-slider-label>
basic
</fast-slider-label>
</div>
<!-- hide mark -->
<div style="margin: 20px; position: relative;">
<fast-slider-label hide-mark="true">
hide-mark
</fast-slider-label>
</div>
<!-- position -->
<div style="margin: 20px; position: relative;">
<fast-slider-label position="10">
pos:10
</fast-slider-label>
</div>
<!-- vertical under slider-->
<div style="margin: 20px; position: relative;">
<fast-slider min="0" max="10" orientation="vertical">
<fast-slider-label position="5">
vert
</fast-slider-label>
</fast-slider>
</div>
</div>
</fast-design-system-provider>
19 changes: 19 additions & 0 deletions packages/fast-components/src/slider-label/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { customElement } from "@microsoft/fast-element";
import { designSystemConsumer } from "../design-system-consumer";
import { neutralOutlineRest } from "../styles/recipes";
import { SliderLabel } from "./slider-label";
import { SliderLabelTemplate as template } from "./slider-label.template";
import { SliderLabelStyles as styles } from "./slider-label.styles";

@customElement({
name: "fast-slider-label",
template,
styles,
})
@designSystemConsumer({
recipes: [neutralOutlineRest],
})
export class FASTSliderLabel extends SliderLabel {}
export * from "./slider-label.template";
export * from "./slider-label.styles";
export * from "./slider-label";
13 changes: 13 additions & 0 deletions packages/fast-components/src/slider-label/slider-label.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FASTDesignSystemProvider } from "../design-system-provider";
import Examples from "./fixtures/base.html";
import { FASTSliderLabel } from ".";

// Prevent tree-shaking
FASTSliderLabel;
FASTDesignSystemProvider;

export default {
title: "SliderLabel",
};

export const SliderLabel = () => Examples;
65 changes: 65 additions & 0 deletions packages/fast-components/src/slider-label/slider-label.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { css } from "@microsoft/fast-element";
import { display } from "../styles";
import { SystemColors } from "../styles/system-colors";
import { heightNumber } from "../styles/size";

export const SliderLabelStyles = css`
${display("block")} :host {
}
.root {
position: absolute;
display: grid;
}
:host(.horizontal) {
align-self: start;
grid-row: 2;
margin-top: -2px;
}
:host(.vertical) {
justify-self: start;
grid-column: 2;
margin-left: 2px;
}
.container {
display: grid;
justify-self: center;
}
:host(.horizontal) .container {
grid-template-rows: auto auto;
grid-template-columns: 0;
}
:host(.vertical) .container {
grid-template-columns: auto auto;
grid-template-rows: 0;
min-width: calc(var(--thumb-size) * 1px);
height: calc(var(--thumb-size) * 1px);
}
.label {
justify-self: center;
align-self: center;
white-space: nowrap;
justify-self: center;
max-width: 30px;
margin: 2px 0;
}
.mark {
width: calc((var(--design-unit) / 2) * 1px);
height: calc(${heightNumber} * 0.25 * 1px);
background: var(--neutral-outline-rest);
justify-self: center;
}
:host(.vertical) .mark {
transform: rotate(90deg);
align-self: center;
}
:host(.vertical) .label {
margin-left: calc((var(--design-unit) / 2) * 2px);
align-self: center;
}
@media (forced-colors: active) {
.mark {
forced-color-adjust: none;
background: ${SystemColors.FieldText};
}
}
`;
13 changes: 13 additions & 0 deletions packages/fast-components/src/slider-label/slider-label.template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { html, ref, when } from "@microsoft/fast-element";
import { SliderLabel } from "./slider-label";

export const SliderLabelTemplate = html<SliderLabel>`
<div ${ref("root")} part="root" class="root" style=${x => x.positionStyle}>
<div class="container">
${when(x => !x.hideMark, html` <div class="mark"></div> `)}
<div class="label">
<slot> </slot>
</div>
</div>
</div>
`;
93 changes: 93 additions & 0 deletions packages/fast-components/src/slider-label/slider-label.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { attr, FastElement, observable } from "@microsoft/fast-element";
import { Direction } from "@microsoft/fast-web-utilities";
import { SliderConfiguration, SliderOrientation } from "../slider";
import { convertPixelToPercent } from "../slider/slider-utilities";

const defaultConfig: SliderConfiguration = {
min: 0,
max: 0,
direction: Direction.ltr,
orientation: SliderOrientation.horizontal,
};

export class SliderLabel extends FastElement {
@observable
public positionStyle: string;

public root: HTMLDivElement;

@attr
public position: string;
private positionChanged(): void {
this.positionStyle = this.positionAsStyle();
}

@attr({ attribute: "hide-mark", mode: "boolean" })
public hideMark: boolean = false;
public config: SliderConfiguration = {
min: 0,
max: 0,
direction: Direction.ltr,
orientation: SliderOrientation.horizontal,
};

public connectedCallback(): void {
super.connectedCallback();
this.getSliderConfiguration();
this.setStyleForOrientation();
this.positionStyle = this.positionAsStyle();
}

private setStyleForOrientation = (): void => {
if (this.config.orientation === SliderOrientation.horizontal) {
this.classList.add("horizontal");
} else {
this.classList.add("vertical");
}
};

private isSliderConfig(node: any): node is SliderConfiguration {
return node.max !== undefined && node.min !== undefined;
}

private getSliderConfiguration = (): void => {
if (!this.isSliderConfig(this.parentNode)) {
this.config = defaultConfig;
} else {
const { min, max, direction, orientation } = this
.parentNode as SliderConfiguration;
this.config = {
min,
max,
direction: direction || Direction.ltr,
orientation: orientation || SliderOrientation.horizontal,
};
}
};

private positionAsStyle = (): any => {
const direction: Direction = this.config.direction
? this.config.direction
: Direction.ltr;

const pct = convertPixelToPercent(
Number(this.position),
this.config.min,
this.config.max
);
let rightNum: number = Math.round((1 - pct) * 100);
let leftNum: number = Math.round(pct * 100);
if (leftNum === Number.NaN && rightNum === Number.NaN) {
rightNum = 50;
leftNum = 50;
}

if (this.config.orientation === SliderOrientation.horizontal) {
return direction === Direction.rtl
? `right: ${leftNum}%; left: ${rightNum}%;`
: `left: ${leftNum}%; right: ${rightNum}%;`;
} else {
return `top: ${leftNum}%; bottom: ${rightNum}%;`;
}
};
}
Loading

0 comments on commit c295e01

Please sign in to comment.