@limetech/lime-elements
Version:
464 lines (463 loc) • 18.2 kB
JavaScript
import { h, Host, } from "@stencil/core";
import { getPercentageClass } from "./get-percentage-class";
import { createRandomString } from "../../util/random-string";
const DEFAULT_FACTOR = 1;
const DEFAULT_MAX_VALUE = 100;
const DEFAULT_MIN_VALUE = 0;
const MAX_VISIBLE_STEP_DOTS = 20;
/**
* @exampleComponent limel-example-slider-basic
* @exampleComponent limel-example-slider-multiplier
* @exampleComponent limel-example-slider-multiplier-percentage-colors
* @exampleComponent limel-example-slider-unit
* @exampleComponent limel-example-slider-composite
*/
export class Slider {
constructor() {
/**
* Disables the slider when `true`,
* and visually shows that the field is editable but disabled.
* This tells the users that if certain requirements are met,
* the slider may become interactable.
*/
this.disabled = false;
/**
* Disables the slider when `true`. This visualizes the slider slightly differently.
* But shows no visual sign indicating that the slider field
* is disabled or can ever become interactable.
*/
this.readonly = false;
/**
* Default value: 1.
* The factor that the properties `value`, `valuemax`, `valuemin`, and
* `step` are multiplied by. On `change` divides the value by the factor,
* so the original format stays the same.
*/
this.factor = DEFAULT_FACTOR;
/**
* Set to `true` to indicate that the slider is required.
*/
this.required = false;
/**
* Set to `true` to indicate that the current value of the slider is invalid.
*/
this.invalid = false;
/**
* Set to `true` to display percentage-based colors on the slider.
* The colors change in intervals of 10% as the value changes,
* creating a color spectrum from red (low) → orange → yellow → green → teal (high).
*/
this.displaysPercentageColors = false;
/**
* Unit to display next to the value
*/
this.unit = '';
/**
* The maximum value allowed
*/
this.valuemax = DEFAULT_MAX_VALUE;
/**
* The minimum value allowed
*/
this.valuemin = DEFAULT_MIN_VALUE;
this.renderStepDots = (min, max) => {
if (!this.step) {
return;
}
const step = this.multiplyByFactor(this.step);
const count = Math.floor((max - min) / step) + 1;
if (count > MAX_VISIBLE_STEP_DOTS) {
return;
}
return Array.from({ length: count }, () => h("span", { class: "step-dot" }));
};
this.renderHelperLine = () => {
if (!this.helperText) {
return;
}
return (h("limel-helper-line", { helperText: this.helperText, helperTextId: this.helperTextId, invalid: this.invalid }));
};
this.handleInput = (event) => {
event.stopPropagation();
const input = event.target;
const value = Number(input.value);
this.displayValue = value;
this.setPercentageClass(value / this.factor);
};
this.handleChange = (event) => {
event.stopPropagation();
const input = event.target;
let value = Number(input.value);
const step = this.multiplyByFactor(this.step);
if (!this.isMultipleOfStep(value, step)) {
value = this.roundToStep(value, step);
}
this.change.emit(value / this.factor);
};
this.getContainerClassList = () => {
if (!this.percentageClass) {
return {};
}
return {
[this.percentageClass]: true,
};
};
this.multiplyByFactor = (value) => {
return Math.round(value * this.factor);
};
this.getValue = () => {
let value = this.value;
if (!Number.isFinite(value)) {
value = this.valuemin;
}
return value;
};
this.getFraction = () => {
const min = this.multiplyByFactor(this.valuemin);
const max = this.multiplyByFactor(this.valuemax);
if (max === min) {
return 0;
}
return Math.max(0, Math.min(1, (this.displayValue - min) / (max - min)));
};
this.setPercentageClass = (value) => {
this.percentageClass = getPercentageClass((value - this.valuemin) / (this.valuemax - this.valuemin));
};
this.isMultipleOfStep = (value, step) => {
if (!step) {
return true;
}
return value % step === 0;
};
this.roundToStep = (value, step) => {
return Math.round(value / step) * step;
};
this.labelId = createRandomString();
this.helperTextId = createRandomString();
}
componentWillLoad() {
this.displayValue = this.multiplyByFactor(this.getValue());
this.setPercentageClass(this.getValue());
}
render() {
const min = this.multiplyByFactor(this.valuemin);
const max = this.multiplyByFactor(this.valuemax);
const fraction = this.getFraction();
const inputProps = {};
if (this.step) {
inputProps.step = this.multiplyByFactor(this.step);
}
if (this.disabled || this.readonly) {
inputProps.disabled = true;
}
return (h(Host, { key: 'fa9695563f078bdab1707422cad3aaef2610e592', class: this.getContainerClassList() }, h("limel-notched-outline", { key: '8b71ef15e9544a6b346248217c2c2fa8acbba6e7', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid, disabled: this.disabled, readonly: this.readonly, hasValue: !!this.value, hasFloatingLabel: true }, h("div", { key: '0327cf7d5295bb1d56e2e34b8dca15cfc3e15c0d', slot: "content" }, h("div", { key: '83fade77119ba9fa1d24ae8fdcd54317648918b3', class: "slider", style: { '--slider-fraction': `${fraction}` } }, h("input", Object.assign({ key: '5181430787abe75b4556923e31ebe8520df977e9', type: "range", min: min, max: max, value: this.displayValue, "aria-labelledby": this.labelId, "aria-describedby": this.helperText
? this.helperTextId
: undefined, onInput: this.handleInput, onChange: this.handleChange }, inputProps)), h("div", { key: '6ee95d718f1d01e92adcf9592882ed1d32e4ba67', class: "track" }, h("div", { key: 'bba420e41501990bdeb1326e59e6eff57000848d', class: "active" }), this.renderStepDots(min, max)), h("div", { key: '46e5a45adbda4e1a650d01408c3d228f1c6be68d', class: "thumb" }, h("div", { key: 'eeba995f52ff3291e2e7818528b05c7c1dec1b32', class: "knob" }), h("div", { key: 'd0321459ed22c6870d939da54df43fe2bfef6333', class: "indicator", "aria-hidden": "true" }, this.displayValue))), h("div", { key: 'bcc4449d7605343fd64f4b89b50c8e5d665f6937', class: "range-labels" }, h("span", { key: '301c78b1640551fe814ad3b2768bb40f9b682b39', class: "min" }, this.multiplyByFactor(this.valuemin), this.unit), h("span", { key: '7f8d741f63030b6f8e88231e5215448b815bf3ca', class: "max" }, this.multiplyByFactor(this.valuemax), this.unit)))), this.renderHelperLine()));
}
watchValue() {
this.displayValue = this.multiplyByFactor(this.getValue());
this.setPercentageClass(this.getValue());
}
static get is() { return "limel-slider"; }
static get encapsulation() { return "shadow"; }
static get originalStyleUrls() {
return {
"$": ["slider.scss"]
};
}
static get styleUrls() {
return {
"$": ["slider.css"]
};
}
static get properties() {
return {
"disabled": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Disables the slider when `true`,\nand visually shows that the field is editable but disabled.\nThis tells the users that if certain requirements are met,\nthe slider may become interactable."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "disabled",
"defaultValue": "false"
},
"readonly": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Disables the slider when `true`. This visualizes the slider slightly differently.\nBut shows no visual sign indicating that the slider field\nis disabled or can ever become interactable."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "readonly",
"defaultValue": "false"
},
"factor": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Default value: 1.\nThe factor that the properties `value`, `valuemax`, `valuemin`, and\n`step` are multiplied by. On `change` divides the value by the factor,\nso the original format stays the same."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "factor",
"defaultValue": "DEFAULT_FACTOR"
},
"label": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Label to display next to the input"
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "label"
},
"helperText": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Optional helper text to display below the slider"
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "helper-text"
},
"required": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Set to `true` to indicate that the slider is required."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "required",
"defaultValue": "false"
},
"invalid": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Set to `true` to indicate that the current value of the slider is invalid."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "invalid",
"defaultValue": "false"
},
"displaysPercentageColors": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Set to `true` to display percentage-based colors on the slider.\nThe colors change in intervals of 10% as the value changes,\ncreating a color spectrum from red (low) \u2192 orange \u2192 yellow \u2192 green \u2192 teal (high)."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "displays-percentage-colors",
"defaultValue": "false"
},
"unit": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Unit to display next to the value"
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "unit",
"defaultValue": "''"
},
"value": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The value of the input"
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "value"
},
"valuemax": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The maximum value allowed"
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "valuemax",
"defaultValue": "DEFAULT_MAX_VALUE"
},
"valuemin": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The minimum value allowed"
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "valuemin",
"defaultValue": "DEFAULT_MIN_VALUE"
},
"step": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The stepping interval to use when adjusting the value"
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "step"
}
};
}
static get states() {
return {
"percentageClass": {},
"displayValue": {}
};
}
static get events() {
return [{
"method": "change",
"name": "change",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Emitted when the value has been changed"
},
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
}
}];
}
static get watchers() {
return [{
"propName": "value",
"methodName": "watchValue"
}];
}
}