@statistikzh/leu 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/Accordion.d.ts +1 -1
  3. package/dist/Accordion.js +1 -1
  4. package/dist/Breadcrumb.d.ts +1 -1
  5. package/dist/Breadcrumb.js +1 -1
  6. package/dist/Button.d.ts +45 -1
  7. package/dist/Button.d.ts.map +1 -1
  8. package/dist/Button.js +473 -6
  9. package/dist/ButtonGroup.d.ts +1 -1
  10. package/dist/ButtonGroup.js +1 -1
  11. package/dist/Checkbox.d.ts +1 -1
  12. package/dist/Checkbox.js +1 -1
  13. package/dist/CheckboxGroup.d.ts +1 -1
  14. package/dist/CheckboxGroup.js +1 -1
  15. package/dist/Chip.d.ts +1 -1
  16. package/dist/Chip.js +1 -1
  17. package/dist/ChipGroup.d.ts +1 -1
  18. package/dist/ChipGroup.js +2 -2
  19. package/dist/ChipLink.js +1 -1
  20. package/dist/ChipRemovable.js +1 -1
  21. package/dist/ChipSelectable.js +1 -1
  22. package/dist/Dialog.d.ts +17 -0
  23. package/dist/Dialog.d.ts.map +1 -0
  24. package/dist/Dialog.js +255 -0
  25. package/dist/Dropdown.d.ts +1 -1
  26. package/dist/Dropdown.d.ts.map +1 -1
  27. package/dist/Dropdown.js +3 -2
  28. package/dist/Icon.d.ts +1 -1
  29. package/dist/Icon.js +1 -1
  30. package/dist/Input.d.ts +1 -1
  31. package/dist/Input.d.ts.map +1 -1
  32. package/dist/Input.js +3 -1
  33. package/dist/{LeuElement-7ab5ef5e.d.ts → LeuElement-78b4a998.d.ts} +1 -1
  34. package/dist/LeuElement-78b4a998.d.ts.map +1 -0
  35. package/dist/{LeuElement-7ab5ef5e.js → LeuElement-78b4a998.js} +1 -1
  36. package/dist/Menu.d.ts +1 -1
  37. package/dist/Menu.js +1 -1
  38. package/dist/MenuItem.d.ts +1 -1
  39. package/dist/MenuItem.js +1 -1
  40. package/dist/Pagination.d.ts +1 -1
  41. package/dist/Pagination.d.ts.map +1 -1
  42. package/dist/Pagination.js +3 -2
  43. package/dist/Popup.d.ts +1 -1
  44. package/dist/Popup.js +1 -1
  45. package/dist/Radio.d.ts +1 -1
  46. package/dist/Radio.js +1 -1
  47. package/dist/RadioGroup.d.ts +1 -1
  48. package/dist/RadioGroup.js +1 -1
  49. package/dist/Range.d.ts +60 -0
  50. package/dist/Range.d.ts.map +1 -0
  51. package/dist/Range.js +414 -0
  52. package/dist/ScrollTop.d.ts +1 -1
  53. package/dist/ScrollTop.d.ts.map +1 -1
  54. package/dist/ScrollTop.js +3 -2
  55. package/dist/Select.d.ts +1 -1
  56. package/dist/Select.d.ts.map +1 -1
  57. package/dist/Select.js +3 -2
  58. package/dist/Spinner.d.ts +1 -1
  59. package/dist/Spinner.js +1 -1
  60. package/dist/Table.d.ts +1 -1
  61. package/dist/Table.d.ts.map +1 -1
  62. package/dist/Table.js +3 -2
  63. package/dist/VisuallyHidden.d.ts +1 -1
  64. package/dist/VisuallyHidden.js +1 -1
  65. package/dist/hasSlotController-fd1950b4.d.ts +38 -0
  66. package/dist/hasSlotController-fd1950b4.d.ts.map +1 -0
  67. package/dist/hasSlotController-fd1950b4.js +75 -0
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.js +3 -2
  70. package/dist/leu-accordion.js +1 -1
  71. package/dist/leu-breadcrumb.js +1 -1
  72. package/dist/leu-button-group.js +1 -1
  73. package/dist/leu-button.d.ts +1 -1
  74. package/dist/leu-button.d.ts.map +1 -1
  75. package/dist/leu-button.js +3 -2
  76. package/dist/leu-checkbox-group.js +1 -1
  77. package/dist/leu-checkbox.js +1 -1
  78. package/dist/leu-chip-group.js +1 -1
  79. package/dist/leu-chip-link.js +1 -1
  80. package/dist/leu-chip-removable.js +1 -1
  81. package/dist/leu-chip-selectable.js +1 -1
  82. package/dist/leu-dialog.d.ts +3 -0
  83. package/dist/leu-dialog.d.ts.map +1 -0
  84. package/dist/leu-dialog.js +11 -0
  85. package/dist/leu-dropdown.js +3 -2
  86. package/dist/leu-icon.js +1 -1
  87. package/dist/leu-input.js +1 -1
  88. package/dist/leu-menu-item.js +1 -1
  89. package/dist/leu-menu.js +1 -1
  90. package/dist/leu-pagination.js +3 -2
  91. package/dist/leu-popup.js +1 -1
  92. package/dist/leu-radio-group.js +1 -1
  93. package/dist/leu-radio.js +1 -1
  94. package/dist/leu-range.d.ts +3 -0
  95. package/dist/leu-range.d.ts.map +1 -0
  96. package/dist/leu-range.js +7 -0
  97. package/dist/leu-scroll-top.js +3 -2
  98. package/dist/leu-select.js +3 -2
  99. package/dist/leu-spinner.js +1 -1
  100. package/dist/leu-table.js +3 -2
  101. package/dist/leu-visually-hidden.js +1 -1
  102. package/dist/theme.css +318 -192
  103. package/dist/vscode.html-custom-data.json +35 -0
  104. package/dist/vue/index.d.ts +60 -0
  105. package/dist/web-types.json +73 -1
  106. package/package.json +1 -1
  107. package/rollup.config.js +4 -1
  108. package/scripts/postcss-leu-font-styles.cjs +29 -35
  109. package/src/components/chip/chip-group.css +1 -1
  110. package/src/components/dialog/Dialog.js +100 -0
  111. package/src/components/dialog/dialog.css +162 -0
  112. package/src/components/dialog/leu-dialog.js +5 -0
  113. package/src/components/dialog/stories/dialog.stories.js +144 -0
  114. package/src/components/dialog/test/dialog.test.js +85 -0
  115. package/src/components/input/input.css +2 -0
  116. package/src/components/range/Range.js +237 -0
  117. package/src/components/range/leu-range.js +5 -0
  118. package/src/components/range/range.css +181 -0
  119. package/src/components/range/stories/range-slider.stories.js +142 -0
  120. package/src/components/range/test/range-test.js +24 -0
  121. package/src/styles/custom-properties.css +27 -0
  122. package/src/styles/font-definitions.json +27 -19
  123. package/src/styles/style.stories.js +61 -0
  124. package/dist/Button-5a8009c5.d.ts +0 -83
  125. package/dist/Button-5a8009c5.d.ts.map +0 -1
  126. package/dist/Button-5a8009c5.js +0 -544
  127. package/dist/LeuElement-7ab5ef5e.d.ts.map +0 -1
@@ -0,0 +1,144 @@
1
+ import { html } from "lit"
2
+ import "../leu-dialog.js"
3
+ import "../../input/leu-input.js"
4
+ import "../../button/leu-button.js"
5
+
6
+ export default {
7
+ title: "Dialog",
8
+ component: "leu-dialog",
9
+ parameters: {
10
+ design: {
11
+ type: "figma",
12
+ url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?node-id=16052-88818&node-type=canvas&t=swv3JY6UIoCBUpXa-11",
13
+ },
14
+ },
15
+ }
16
+
17
+ function openDialog() {
18
+ document.querySelector("leu-dialog").show()
19
+ }
20
+
21
+ function closeDialog() {
22
+ document.querySelector("leu-dialog").close()
23
+ }
24
+
25
+ function OpenDialogButton() {
26
+ return html` <leu-button @click=${() => openDialog()}>
27
+ Open dialog
28
+ </leu-button>`
29
+ }
30
+
31
+ function Template({ label, sublabel }) {
32
+ return html`
33
+ ${OpenDialogButton()}
34
+
35
+ <leu-dialog label="${label}" sublabel="${sublabel}">
36
+ <leu-input label="Eingabe"></leu-input>
37
+ <br />
38
+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
39
+ eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
40
+ voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
41
+ clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
42
+ amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
43
+ nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed
44
+ diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
45
+ Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
46
+ sit amet.
47
+ </leu-dialog>
48
+ `
49
+ }
50
+
51
+ export const Regular = Template.bind({})
52
+ Regular.args = {
53
+ label: "Property: label",
54
+ rubric: "Property: sublabel",
55
+ }
56
+
57
+ function ActionButtonsTemplate({ label, sublabel }) {
58
+ return html`
59
+ ${OpenDialogButton()}
60
+
61
+ <leu-dialog label="${label}" sublabel="${sublabel}">
62
+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
63
+ eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
64
+ voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
65
+ clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
66
+ amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
67
+ nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed
68
+ diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
69
+ Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
70
+ sit amet.
71
+ <slot slot="actionbar">
72
+ <leu-button
73
+ variant="secondary"
74
+ @click=${() => {
75
+ // eslint-disable-next-line no-alert
76
+ alert("Fenster wird geschlossen")
77
+ closeDialog()
78
+ }}
79
+ >
80
+ Abbrechen
81
+ </leu-button>
82
+ <leu-button
83
+ @click=${() => {
84
+ // eslint-disable-next-line no-alert
85
+ alert("Fenster wird offen gelassen")
86
+ }}
87
+ >
88
+ Anwenden
89
+ </leu-button>
90
+ </slot>
91
+ </leu-dialog>
92
+ `
93
+ }
94
+
95
+ export const ActionButtons = ActionButtonsTemplate.bind({})
96
+ ActionButtons.args = {
97
+ label: "Property: label",
98
+ sublabel: "Property: sublabel",
99
+ }
100
+
101
+ function SmallContentTemplate({ label, sublabel }) {
102
+ return html`
103
+ ${OpenDialogButton()}
104
+
105
+ <leu-dialog label="${label}" sublabel="${sublabel}">
106
+ <p>Ein kurzer Text</p>
107
+ </leu-dialog>
108
+ `
109
+ }
110
+
111
+ export const SmallContent = SmallContentTemplate.bind({})
112
+ SmallContent.args = {
113
+ label: "Dialog Titel",
114
+ sublabel: "Property: sublabel",
115
+ }
116
+
117
+ function ScrollablePageTemplate({ label, sublabel }) {
118
+ return html`
119
+ <div style="height: 200vh">
120
+ ${OpenDialogButton()}
121
+
122
+ <leu-dialog label="${label}" sublabel="${sublabel}">
123
+ <leu-input label="Eingabe"></leu-input>
124
+ <br />
125
+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
126
+ eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
127
+ voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
128
+ clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
129
+ amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
130
+ nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
131
+ sed diam voluptua. At vero eos et accusam et justo duo dolores et ea
132
+ rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem
133
+ ipsum dolor sit amet.
134
+ </leu-dialog>
135
+ </div>
136
+ <div style="height: 200vh">${OpenDialogButton()}</div>
137
+ `
138
+ }
139
+
140
+ export const ScrollablePage = ScrollablePageTemplate.bind({})
141
+ ScrollablePage.args = {
142
+ label: "Dialog Titel",
143
+ sublabel: "Property: sublabel",
144
+ }
@@ -0,0 +1,85 @@
1
+ import { html } from "lit"
2
+ import { fixture, expect } from "@open-wc/testing"
3
+
4
+ import "../leu-dialog.js"
5
+
6
+ async function defaultFixture() {
7
+ return fixture(
8
+ html`<leu-dialog label="Title" sublabel="Category">
9
+ This is the content of the dialog.
10
+ </leu-dialog>`
11
+ )
12
+ }
13
+
14
+ describe("LeuDialog", () => {
15
+ it("is a defined element", async () => {
16
+ const el = await customElements.get("leu-dialog")
17
+
18
+ expect(el).not.to.be.undefined
19
+ })
20
+
21
+ it("passes the a11y audit", async () => {
22
+ const el = await defaultFixture()
23
+
24
+ await expect(el).shadowDom.to.be.accessible()
25
+ })
26
+
27
+ it("passes the a11y audit when the modal is open", async () => {
28
+ const el = await defaultFixture()
29
+
30
+ el.show()
31
+
32
+ await expect(el).shadowDom.to.be.accessible()
33
+ })
34
+
35
+ it("opens the dialog when calling show()", async () => {
36
+ const el = await defaultFixture()
37
+
38
+ el.show()
39
+
40
+ const dialog = el.shadowRoot.querySelector("dialog")
41
+
42
+ expect(dialog.open).to.be.true
43
+ })
44
+
45
+ it("closes the dialog when calling close()", async () => {
46
+ const el = await defaultFixture()
47
+
48
+ el.show()
49
+ el.close()
50
+
51
+ const dialog = el.shadowRoot.querySelector("dialog")
52
+
53
+ expect(dialog.open).to.be.false
54
+ })
55
+
56
+ it("renders a label and a sublabel", async () => {
57
+ const el = await defaultFixture()
58
+
59
+ const label = el.shadowRoot.querySelector("h1")
60
+ const sublabel = el.shadowRoot.querySelector(".subtitle")
61
+
62
+ expect(label).to.have.text("Title")
63
+ expect(sublabel).to.have.text("Category")
64
+ })
65
+
66
+ it("renders a close button", async () => {
67
+ const el = await defaultFixture()
68
+
69
+ const closeButton = el.shadowRoot.querySelector(".close-button")
70
+
71
+ expect(closeButton).to.exist
72
+ })
73
+
74
+ it("closes the dialog when clicking the close button", async () => {
75
+ const el = await defaultFixture()
76
+ const dialog = el.shadowRoot.querySelector("dialog")
77
+
78
+ el.show()
79
+
80
+ const closeButton = el.shadowRoot.querySelector(".close-button")
81
+ expect(dialog.open).to.be.true
82
+ closeButton.click()
83
+ expect(dialog.open).to.be.false
84
+ })
85
+ })
@@ -54,6 +54,7 @@
54
54
 
55
55
  border: var(--input-border-width) solid var(--input-border-color);
56
56
  border-radius: 2px;
57
+ background: var(--leu-color-black-0);
57
58
 
58
59
  line-height: 1;
59
60
  }
@@ -79,6 +80,7 @@
79
80
  color: var(--input-color);
80
81
 
81
82
  border: 0;
83
+ background: var(--leu-color-black-0);
82
84
 
83
85
  padding-block: 2rem 1rem;
84
86
  }
@@ -0,0 +1,237 @@
1
+ import { html } from "lit"
2
+
3
+ import styles from "./range.css"
4
+ import { LeuElement } from "../../lib/LeuElement.js"
5
+
6
+ const defaultValueConverter = {
7
+ fromAttribute(value) {
8
+ return value.split(",").map((v) => Number(v.trim()))
9
+ },
10
+ toAttribute(value) {
11
+ return value.join(",")
12
+ },
13
+ }
14
+
15
+ const RANGE_LABELS = ["Von", "Bis"]
16
+
17
+ /**
18
+ * @tagname leu-range
19
+ */
20
+ export class LeuRange extends LeuElement {
21
+ static styles = styles
22
+
23
+ static shadowRootOptions = {
24
+ ...LeuElement.shadowRootOptions,
25
+ delegatesFocus: true,
26
+ }
27
+
28
+ static properties = {
29
+ defaultValue: { converter: defaultValueConverter, attribute: "value" },
30
+ min: { type: Number, reflect: true },
31
+ max: { type: Number, reflect: true },
32
+ step: { type: Number, reflect: true },
33
+ name: { type: String, reflect: true },
34
+ label: { type: String, reflect: true },
35
+ disabled: { type: Boolean, reflect: true },
36
+ multiple: { type: Boolean, reflect: true },
37
+ }
38
+
39
+ constructor() {
40
+ super()
41
+ this.defaultValue = [50]
42
+ this.min = 0
43
+ this.max = 100
44
+ this.step = 1
45
+ this.name = ""
46
+ this.label = ""
47
+ this.disabled = false
48
+ this.multiple = false
49
+ }
50
+
51
+ updated() {
52
+ this._updateStyles()
53
+ }
54
+
55
+ _updateStyles() {
56
+ const normalizedRange = this._getNormalizedRange()
57
+ this.style.setProperty("--low", normalizedRange[0].toString())
58
+ this.style.setProperty("--high", normalizedRange[1].toString())
59
+
60
+ const inputs = this.multiple
61
+ ? [this._getBaseInput(), this._getGhostInput()]
62
+ : [this._getBaseInput()]
63
+
64
+ inputs.forEach((input) => {
65
+ /** @type {HTMLOutputElement} */
66
+ const output = this.shadowRoot.querySelector(`.output[for=${input.id}]`)
67
+ const normalizedValue = this._getNormalizedValue(input.valueAsNumber)
68
+ output.style.setProperty("--value", normalizedValue.toString())
69
+ output.value = input.value
70
+ })
71
+ }
72
+
73
+ get value() {
74
+ const inputs = Array.from(this.shadowRoot.querySelectorAll("input"))
75
+ return inputs.map((input) => input.value).join(",")
76
+ }
77
+
78
+ /**
79
+ * Sets the value of the underlying input element(s).
80
+ * The value has to be an array if "multiple" range is used.
81
+ * Otherwise it has to be a string.
82
+ * @param {string | Array} value
83
+ */
84
+ set value(value) {
85
+ if (this.multiple && Array.isArray(value)) {
86
+ const inputs = Array.from(this.shadowRoot.querySelectorAll("input"))
87
+ value.forEach((v, i) => {
88
+ inputs[i].value = v
89
+ })
90
+ this._updateStyles()
91
+ } else if (!this.multiple) {
92
+ this._getBaseInput().value = value
93
+ this._updateStyles()
94
+ }
95
+ }
96
+
97
+ get valueAsArray() {
98
+ return Array.from(this.shadowRoot.querySelectorAll("input")).map(
99
+ (input) => input.valueAsNumber
100
+ )
101
+ }
102
+
103
+ get valueLow() {
104
+ const inputs = Array.from(this.shadowRoot.querySelectorAll("input"))
105
+
106
+ if (this.multiple) {
107
+ return inputs.map((input) => input.valueAsNumber).sort((a, b) => a - b)[0]
108
+ }
109
+
110
+ return inputs[0].value
111
+ }
112
+
113
+ get valueHigh() {
114
+ const inputs = Array.from(this.shadowRoot.querySelectorAll("input"))
115
+
116
+ if (this.multiple) {
117
+ return inputs.map((input) => input.valueAsNumber).sort((a, b) => a - b)[1]
118
+ }
119
+
120
+ return inputs[0].value
121
+ }
122
+
123
+ /**
124
+ * @returns {HTMLInputElement | null}
125
+ */
126
+ _getBaseInput() {
127
+ return this.shadowRoot.querySelector(".range--base")
128
+ }
129
+
130
+ /**
131
+ * @returns {HTMLInputElement | null}
132
+ */
133
+ _getGhostInput() {
134
+ return this.shadowRoot.querySelector(".range--ghost")
135
+ }
136
+
137
+ /**
138
+ *
139
+ * @param {number} _index
140
+ * @param {InputEvent & {target: HTMLInputElement}} _e
141
+ */
142
+ _handleInput(_index, _e) {
143
+ this._updateStyles()
144
+ }
145
+
146
+ /**
147
+ *
148
+ * @param {number} value
149
+ * @returns {number}
150
+ */
151
+ _getNormalizedValue(value) {
152
+ return (value - this.min) / (this.max - this.min)
153
+ }
154
+
155
+ _getNormalizedRange() {
156
+ if (this.multiple) {
157
+ return this.valueAsArray
158
+ .map((value) => this._getNormalizedValue(value))
159
+ .sort((a, b) => a - b)
160
+ }
161
+
162
+ return [0, this._getNormalizedValue(this.valueAsArray[0])]
163
+ }
164
+
165
+ /**
166
+ * Determine if the "click" (pointer event) is closer the
167
+ * the value of the other input element. Swap the values if this is the case.
168
+ * @param {PointerEvent & {target: HTMLInputElement}} e
169
+ */
170
+ _handlePointerDown(e) {
171
+ const clickValue =
172
+ this.min + ((this.max - this.min) * e.offsetX) / this.offsetWidth
173
+ const middleValue = (this.valueAsArray[0] + this.valueAsArray[1]) / 2
174
+
175
+ if (
176
+ (e.target.valueAsNumber === this.valueLow) ===
177
+ clickValue > middleValue
178
+ ) {
179
+ /**
180
+ * As the pointerdown event is fired before the input event, we first overwrite the value
181
+ * of the input element that was not clicked on. The active input element will update itself.
182
+ */
183
+ // this._value = [e.target.valueAsNumber, e.target.valueAsNumber]
184
+ this._getGhostInput().value = e.target.value
185
+ }
186
+ }
187
+
188
+ render() {
189
+ const inputs = this.multiple ? ["base", "ghost"] : ["base"]
190
+
191
+ const { multiple, disabled, label, defaultValue } = this
192
+
193
+ return html`
194
+ <div
195
+ role=${multiple ? "group" : undefined}
196
+ aria-labelledby=${multiple ? "group-label" : undefined}
197
+ >
198
+ ${multiple
199
+ ? html`<span id="group-label" class="label">${label}</span>`
200
+ : html`<label for="input-base" class="label">${label}</label>`}
201
+ <div class="outputs">
202
+ ${inputs.map(
203
+ (type, index) =>
204
+ html`<output
205
+ class="output"
206
+ for="input-${type}"
207
+ value=${defaultValue[index]}
208
+ ></output>`
209
+ )}
210
+ </div>
211
+ <div class="inputs">
212
+ ${inputs.map(
213
+ (type, index) =>
214
+ html`
215
+ <input
216
+ @input=${(e) => this._handleInput(index, e)}
217
+ @pointerdown=${multiple && !disabled && index === 0
218
+ ? this._handlePointerDown
219
+ : undefined}
220
+ type="range"
221
+ class="range range--${type}"
222
+ id="input-${type}"
223
+ name=${this.name}
224
+ min=${this.min}
225
+ max=${this.max}
226
+ step=${this.step}
227
+ aria-label=${multiple ? RANGE_LABELS[index] : undefined}
228
+ ?disabled=${disabled}
229
+ .value=${defaultValue[index].toString()}
230
+ />
231
+ `
232
+ )}
233
+ </div>
234
+ </div>
235
+ `
236
+ }
237
+ }
@@ -0,0 +1,5 @@
1
+ import { LeuRange } from "./Range.js"
2
+
3
+ export { LeuRange }
4
+
5
+ LeuRange.define("leu-range")
@@ -0,0 +1,181 @@
1
+ :host {
2
+ --range-color: var(--leu-color-black-40);
3
+ --range-color-disabled: var(--leu-color-black-20);
4
+ --range-color-focus: var(--leu-color-func-cyan);
5
+
6
+ --range-track-background-color: var(--leu-color-black-10);
7
+ --range-track-height: 4px;
8
+ --range-track-radius: var(--range-track-height);
9
+
10
+ --range-track-value-color: var(--leu-color-func-cyan);
11
+ --range-track-value-width: 0;
12
+ --range-track-value-min: 0;
13
+
14
+ --range-thumb-color: var(--leu-color-black-0);
15
+ --range-thumb-border-color: var(--range-color);
16
+ --range-thumb-hover-border-color: var(--leu-color-black-100);
17
+ --range-thumb-diameter: 32px;
18
+
19
+ --range-value-color: var(--leu-color-black-100);
20
+ --range-value-color-disabled: var(--range-color-disabled);
21
+
22
+ --range-font-regular: var(--leu-font-family-regular);
23
+ --range-font-black: var(--leu-font-family-black);
24
+
25
+ display: block;
26
+ box-sizing: border-box;
27
+
28
+ font-family: var(--range-font-regular);
29
+ }
30
+
31
+ :host([disabled]) {
32
+ --range-track-background: var(--range-color-disabled);
33
+ --range-track-value-color: var(--range-color-disabled);
34
+ --range-thumb-border-color: var(--range-color-disabled);
35
+ --range-thumb-hover-border-color: var(--range-color-disabled);
36
+ --range-value-color: var(--range-value-color-disabled);
37
+ }
38
+
39
+ /*************************** */
40
+
41
+ .label {
42
+ display: inline-block;
43
+ margin-block-end: 0.5rem;
44
+ color: var(--leu-color-black-100);
45
+ font: var(--leu-t-regular-regular-font);
46
+ }
47
+
48
+ .outputs {
49
+ position: relative;
50
+ height: 1.5rem;
51
+ margin-block-end: 0.25rem;
52
+ }
53
+
54
+ .output {
55
+ position: absolute;
56
+
57
+ text-align: center;
58
+ font: var(--leu-t-tiny-black-font);
59
+ color: var(--range-value-color);
60
+
61
+ min-width: var(--range-thumb-diameter);
62
+
63
+ --_stop: calc(100% - var(--range-thumb-diameter));
64
+ --_start: 0%;
65
+
66
+ left: calc(var(--value) * (var(--_stop) - var(--_start)) + var(--_start));
67
+ transform: translateX(calc(-50% + var(--range-thumb-diameter) / 2));
68
+ }
69
+
70
+ .inputs {
71
+ position: relative;
72
+ }
73
+
74
+ .range {
75
+ appearance: none;
76
+ width: 100%;
77
+ height: var(--range-thumb-diameter);
78
+ padding: 0;
79
+ margin: 0;
80
+ background: transparent;
81
+
82
+ --_track-background: linear-gradient(
83
+ to right,
84
+ var(--range-track-background-color) calc(var(--low) * 100%),
85
+ var(--range-track-value-color) 0,
86
+ var(--range-track-value-color) calc(var(--high) * 100%),
87
+ var(--range-track-background-color) 0
88
+ );
89
+ }
90
+
91
+ .range--ghost {
92
+ position: absolute;
93
+ top: 0;
94
+ left: 0;
95
+ z-index: 1;
96
+ pointer-events: none;
97
+ }
98
+
99
+ .range:focus {
100
+ outline: none;
101
+ }
102
+
103
+ /* Thumb */
104
+
105
+ .range::-moz-range-thumb {
106
+ cursor: pointer;
107
+ background: var(--range-thumb-color);
108
+
109
+ border: 2px var(--range-thumb-border-color) solid;
110
+ border-radius: 50%;
111
+
112
+ height: var(--range-thumb-diameter);
113
+ width: var(--range-thumb-diameter);
114
+
115
+ pointer-events: all;
116
+ }
117
+
118
+ .range:disabled::-moz-range-thumb {
119
+ cursor: not-allowed;
120
+ }
121
+
122
+ .range:focus-visible::-moz-range-thumb {
123
+ outline: 2px solid var(--range-color-focus);
124
+ outline-offset: 2px;
125
+ }
126
+
127
+ .range::-moz-range-thumb:hover,
128
+ .range:focus-visible::-moz-range-thumb {
129
+ border-color: var(--range-thumb-hover-border-color);
130
+ }
131
+
132
+ .range::-webkit-slider-thumb {
133
+ appearance: none;
134
+ cursor: pointer;
135
+ background: var(--range-thumb-color);
136
+
137
+ border: 2px var(--range-thumb-border-color) solid;
138
+ border-radius: 50%;
139
+
140
+ height: var(--range-thumb-diameter);
141
+ width: var(--range-thumb-diameter);
142
+ margin-top: calc(var(--range-thumb-diameter) / -2 + 2px);
143
+
144
+ pointer-events: all;
145
+ }
146
+
147
+ .range:disabled::-webkit-slider-thumb {
148
+ cursor: not-allowed;
149
+ }
150
+
151
+ .range:focus::-webkit-slider-thumb {
152
+ outline: 2px solid var(--range-color-focus);
153
+ outline-offset: 2px;
154
+ }
155
+
156
+ .range:focus::-webkit-slider-thumb,
157
+ .range::-webkit-slider-thumb:hover {
158
+ border-color: var(--range-thumb-hover-border-color);
159
+ }
160
+
161
+ /* Track */
162
+
163
+ .range::-moz-range-track {
164
+ background: var(--_track-background);
165
+ border-radius: var(--range-track-radius);
166
+ height: var(--range-track-height);
167
+ }
168
+
169
+ .range--ghost::-moz-range-track {
170
+ background: transparent;
171
+ }
172
+
173
+ .range::-webkit-slider-runnable-track {
174
+ background: var(--_track-background);
175
+ border-radius: var(--range-track-radius);
176
+ height: var(--range-track-height);
177
+ }
178
+
179
+ .range--ghost::-webkit-slider-runnable-track {
180
+ background: transparent;
181
+ }