material-inspired-component-library 9.1.0 → 9.1.2

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 (73) hide show
  1. package/README.md +2 -1
  2. package/components/appbar/index.scss +1 -1
  3. package/components/badge/README.md +43 -12
  4. package/components/badge/index.scss +15 -21
  5. package/components/bottomsheet/README.md +53 -22
  6. package/components/bottomsheet/index.scss +62 -45
  7. package/components/button/_shared.scss +9 -9
  8. package/components/card/README.md +55 -25
  9. package/components/card/index.scss +57 -38
  10. package/components/checkbox/README.md +97 -28
  11. package/components/checkbox/index.scss +39 -29
  12. package/components/chip/index.scss +6 -6
  13. package/components/datepicker/README.md +184 -59
  14. package/components/datepicker/index.scss +85 -21
  15. package/components/dialog/README.md +151 -56
  16. package/components/dialog/index.scss +50 -62
  17. package/components/iconbutton/index.scss +8 -8
  18. package/components/list/index.scss +15 -11
  19. package/components/menu/index.scss +13 -13
  20. package/components/navigationbar/index.scss +7 -1
  21. package/components/navigationrail/index.scss +27 -22
  22. package/components/radio/README.md +52 -12
  23. package/components/radio/index.scss +59 -41
  24. package/components/select/index.scss +3 -3
  25. package/components/sidesheet/README.md +90 -37
  26. package/components/sidesheet/index.scss +51 -41
  27. package/components/slider/README.md +35 -9
  28. package/components/slider/index.scss +182 -153
  29. package/components/snackbar/README.md +43 -25
  30. package/components/snackbar/index.scss +22 -27
  31. package/components/stepper/index.scss +5 -5
  32. package/components/switch/README.md +32 -4
  33. package/components/switch/index.scss +57 -52
  34. package/components/timepicker/README.md +131 -55
  35. package/components/timepicker/index.scss +47 -26
  36. package/dist/appbar.css +1 -1
  37. package/dist/badge.css +1 -1
  38. package/dist/bottomsheet.css +1 -1
  39. package/dist/bottomsheet.js +1 -1
  40. package/dist/button.css +1 -1
  41. package/dist/card.css +1 -1
  42. package/dist/checkbox.css +1 -1
  43. package/dist/checkbox.js +1 -1
  44. package/dist/chip.css +1 -1
  45. package/dist/components/checkbox/index.d.ts +1 -0
  46. package/dist/datepicker.css +1 -1
  47. package/dist/datepicker.js +1 -1
  48. package/dist/dialog.css +1 -1
  49. package/dist/foundations/form/index.js +1 -1
  50. package/dist/iconbutton.css +1 -1
  51. package/dist/layout.css +1 -1
  52. package/dist/list.css +1 -1
  53. package/dist/menu.css +1 -1
  54. package/dist/micl.css +1 -1
  55. package/dist/micl.js +1 -1
  56. package/dist/navigationbar.css +1 -1
  57. package/dist/navigationrail.css +1 -1
  58. package/dist/radio.css +1 -1
  59. package/dist/select.css +1 -1
  60. package/dist/sidesheet.css +1 -1
  61. package/dist/slider.css +1 -1
  62. package/dist/slider.js +1 -1
  63. package/dist/snackbar.css +1 -1
  64. package/dist/snackbar.js +1 -1
  65. package/dist/stepper.css +1 -1
  66. package/dist/stepper.js +1 -1
  67. package/dist/switch.css +1 -1
  68. package/dist/timepicker.css +1 -1
  69. package/dist/timepicker.js +1 -1
  70. package/foundations/layout/_tokens.scss +55 -0
  71. package/foundations/layout/index.scss +5 -35
  72. package/package.json +2 -2
  73. package/{components/checkbox/_label.scss → styles/togglelabel.scss} +11 -3
@@ -35,13 +35,18 @@ This will initialize any Slider component, including those that will be added to
35
35
  A live example of the [Slider component](https://henkpb.github.io/micl/slider.html) is available to interact with.
36
36
 
37
37
  ## Variants
38
- Sliders come in **five different sizes**: extra small (`xs`), small (`s`), medium (`m`), large (`l`), and extra large (`xl`). To set a specific size, append the appropriate postfix to the `micl-slider` CSS class name:
38
+ Sliders come in **five different sizes**: extra small (`xs`), small (`s`), medium (`m`), large (`l`), and extra large (`xl`). To set a specific size, append the appropriate size suffix to the `micl-slider` CSS class name:
39
39
 
40
40
  ```HTML
41
41
  <input type="range" class="micl-slider-s" min="1" max="10" step="1" value="6">
42
42
  ```
43
43
 
44
- Add a `<datalist>` element to suggest predefined values. The slider will show tick marks for these values.
44
+ By default, the slider is displayed **horizontally**. To display the slider **vertically**, add the `micl-slider--vertical` CSS class.
45
+
46
+ Adding the `disabled` boolean attribute to the `input` element causes the slider to be displayed in a disabled state.
47
+
48
+ Every slider shows a **stop indicator** at the end of its track. Add a `<datalist>` element and reference it with the `list` attribute to get a discrete slider, which shows a stop indicator at each listed value. The values do not have to be evenly spaced.
49
+
45
50
  ```HTML
46
51
  <input type="range" class="micl-slider-l" min="0" max="100" value="25" step="25" list="markers">
47
52
  <datalist id="markers">
@@ -53,7 +58,20 @@ Add a `<datalist>` element to suggest predefined values. The slider will show ti
53
58
  </datalist>
54
59
  ```
55
60
 
56
- By default, the slider is displayed **horizontally**. To display the slider **vertically**, add the `micl-slider--vertical` CSS class.
61
+ > [!NOTE]
62
+ > The listed values are suggestions, not stopping points: browsers move the value by `step` and do not snap to the datalist. Give the slider a `step` that matches the listed values if users should only be able to select those.
63
+ > The datalist is read once, when the slider is initialized. The script mirrors the slider's value on every `input` event. When a slider's value is changed programmatically or via a form reset, you must manually dispatch an `input` event so the track and value indicator update to reflect the new value:
64
+ >
65
+ > ```JavaScript
66
+ > slider.value = 40;
67
+ > slider.dispatchEvent(new Event("input", { bubbles: true }));
68
+ > ```
69
+
70
+ By default, a slider relies on the browser's default dimensions. You can adjust its length by setting the CSS `inline-size` property (this controls the width of a horizontal slider or the height of a vertical one).
71
+
72
+ ```HTML
73
+ <input type="range" class="micl-slider-m micl-slider--vertical" style="inline-size:240px" aria-label="Volume">
74
+ ```
57
75
 
58
76
  For displaying an icon inside a medium-, large- or extra large-sized slider, wrap the icon and the slider inside a slider container:
59
77
 
@@ -64,8 +82,6 @@ For displaying an icon inside a medium-, large- or extra large-sized slider, wra
64
82
  </div>
65
83
  ```
66
84
 
67
- Adding the `disabled` boolean attribute to the `input` element causes the slider to be displayed in a disabled state.
68
-
69
85
  The Slider component is aware of the `dir` global attribute that indicates the directionality of text.
70
86
 
71
87
  ## Theming
@@ -79,7 +95,8 @@ Each slider can be themed with CSS custom properties that follow the Material De
79
95
  | `--md-comp-slider-active-track-color` | The color of the active (filled) part of the track | `--md-sys-color-primary` |
80
96
  | `--md-comp-slider-inactive-track-color` | The color of the inactive part of the track | `--md-sys-color-secondary-container` |
81
97
  | `--md-comp-slider-handle-color` | The color of the handle | `--md-sys-color-primary` |
82
- | `--md-comp-slider-stop-indicator-color` | The color of the tick marks (blended with the track) | `--md-sys-color-on-primary` |
98
+ | `--md-comp-slider-active-stop-indicator-container-color` | The color of the stop indicators on the active track | `--md-sys-color-on-primary` |
99
+ | `--md-comp-slider-inactive-stop-indicator-container-color` | The color of the stop indicators on the inactive track | `--md-sys-color-on-secondary-container` |
83
100
  | `--md-comp-slider-value-indicator-container-color` | The background color of the value indicator | `--md-sys-color-inverse-surface` |
84
101
  | `--md-comp-slider-value-indicator-label-text-color` | The text color of the value indicator | `--md-sys-color-inverse-on-surface` |
85
102
 
@@ -89,13 +106,22 @@ Each slider can be themed with CSS custom properties that follow the Material De
89
106
  <input type="range" class="micl-slider-m" style="--md-comp-slider-active-track-color:var(--md-sys-color-tertiary)">
90
107
  ```
91
108
 
109
+ ## Accessibility
110
+ The slider is a native `<input type="range">`, so keyboard operation and the announced value come from the browser. Give every slider an accessible name, either with a `<label for>` element or with an `aria-label` attribute. The value indicator is purely visual; if the raw value is not meaningful to users, add `aria-valuetext` and keep it updated.
111
+
112
+ ```HTML
113
+ <label for="volume">Volume</label>
114
+ <input type="range" class="micl-slider-m" id="volume" min="0" max="100" value="60">
115
+ ```
116
+
92
117
  ## Compatibility
93
- This component uses the `color-mix` CSS functional notation, which might not be supported in your browser. Please check [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix#browser_compatibility) for details.
118
+ This component relies on the `:has()` pseudo-class, typed `attr()` values, CSS anchor positioning, the `color-mix()` function, and `writing-mode: sideways-lr` for vertical sliders. Please check [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/attr#browser_compatibility) for details.
94
119
 
95
120
  > [!NOTE]
96
- > **Gecko browsers** The Slider component uses the `::after` pseudo-element to display the value indicator. For this to work on **Gecko** browsers, like Mozilla Firefox, wrap the Slider component inside a slider container:
121
+ > **Gecko browsers** The value indicator of a standalone slider is drawn with the `::after` pseudo-element, which **Gecko** browsers like Mozilla Firefox do not render on `<input>` elements. To show the value indicator in these browsers, wrap the slider inside a slider container; the indicator then works in every browser and any layout:
97
122
  > ```HTML
98
123
  > <div class="micl-slider__container">
99
- > <input type="range" class="micl-slider-l" value="0">
124
+ > <input type="range" class="micl-slider-l" value="0" aria-label="Brightness">
100
125
  > </div>
101
126
  > ```
127
+ > The container positions the value indicator from the size custom properties, so set `--md-comp-slider-track-height` and `--md-comp-slider-handle-height` on the container or an ancestor rather than on the `input` element.
@@ -37,75 +37,38 @@
37
37
  @include motion.duration('medium2');
38
38
  @include motion.duration('long2');
39
39
 
40
- @mixin slider-track() {
40
+ @mixin slider-inactive() {
41
41
  block-size: var(--_track-height);
42
- border-radius: var(--_track-shape);
43
- background-color: inherit;
44
- background-image: linear-gradient(
45
- var(--_direction),
46
- var(--_active-track-color) var(--_thumb-position),
47
- transparent var(--_thumb-position) calc(var(--_thumb-position) + 16px),
48
- var(--_inactive-track-color) calc(var(--_thumb-position) + 16px)
49
- );
42
+ clip-path: var(--_inactive-clip);
43
+ color: var(--_inactive-stop-color);
44
+ background-color: var(--_inactive-track-color);
45
+ background-image: var(--_end-stop), var(--_stops);
50
46
  }
51
- @mixin slider-track-disabled() {
52
- background-image: linear-gradient(
53
- var(--_direction),
54
- color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-state-layer-opacity), transparent) var(--_thumb-position),
55
- transparent var(--_thumb-position) calc(var(--_thumb-position) + 16px),
56
- color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent) calc(var(--_thumb-position) + 16px)
57
- );
47
+ @mixin slider-active() {
48
+ block-size: var(--_track-height);
49
+ clip-path: var(--_active-clip);
50
+ color: var(--_active-stop-color);
51
+ background-color: var(--_active-track-color);
52
+ background-image: var(--_stops);
58
53
  }
59
54
  @mixin slider-thumb() {
60
55
  appearance: none;
61
56
  box-sizing: content-box;
62
57
  position: relative;
63
- inline-size: 16px;
58
+ inline-size: calc(4px - 2 * var(--_handle-inset));
64
59
  block-size: var(--_handle-height);
65
60
  inset: 0;
66
61
  inset-block-start: calc(-1 * (var(--_handle-height) - var(--_track-height) + 8px) / 2);
67
62
  padding-block: 4px;
63
+ padding-inline: calc(6px + var(--_handle-inset));
68
64
  border: none;
69
- border-radius: 8px;
70
- background-image: linear-gradient(
71
- var(--_direction),
72
- transparent 0px,
73
- transparent var(--_thumb-space),
74
- var(--_handle-color) var(--_thumb-space),
75
- var(--_handle-color) 10px,
76
- transparent 10px,
77
- transparent 16px
78
- );
65
+ border-radius: var(--_handle-radius);
66
+ outline: var(--_handle-outline);
67
+ background-color: var(--_handle-color);
79
68
  background-clip: content-box;
80
- cursor: pointer;
69
+ cursor: var(--_cursor);
81
70
  z-index: 2;
82
71
  }
83
- @mixin slider-thumb-disabled() {
84
- background-image: linear-gradient(
85
- var(--_direction),
86
- transparent 0px,
87
- transparent var(--_thumb-space),
88
- color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-state-layer-opacity), var(--md-sys-color-surface)) var(--_thumb-space),
89
- color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-state-layer-opacity), var(--md-sys-color-surface)) 10px,
90
- transparent 10px,
91
- transparent 16px
92
- );
93
- cursor: default;
94
- }
95
- // The 4px wide handle narrows to 2px while pressed.
96
- @mixin slider-thumb-active() {
97
- background-image: linear-gradient(
98
- var(--_direction),
99
- transparent 0px,
100
- transparent calc(var(--_thumb-space) + 1px),
101
- var(--_handle-color) calc(var(--_thumb-space) + 1px),
102
- var(--_handle-color) calc(var(--_thumb-space) + 3px),
103
- transparent calc(var(--_thumb-space) + 3px),
104
- transparent calc(2 * var(--_thumb-space) + 4px)
105
- );
106
- outline: none;
107
- cursor: grabbing;
108
- }
109
72
  @mixin slider-tip() {
110
73
  @include typography.label-large;
111
74
  --_tip-space: 4px;
@@ -116,9 +79,7 @@
116
79
  inline-size: fit-content;
117
80
  min-inline-size: 48px;
118
81
  block-size: 40px;
119
- inset: 0;
120
- inset-block-start: calc(-1 * ((var(--_handle-height) - var(--_track-height)) / 2) - 40px - var(--_tip-space));
121
- inset-inline-start: calc(-16px + (100% - 16px) * var(--_fraction));
82
+ inset: auto;
122
83
  padding-block: 12px;
123
84
  padding-inline: 16px;
124
85
  border-radius: 20px;
@@ -129,80 +90,137 @@
129
90
  z-index: 3;
130
91
  transition: opacity var(--md-sys-motion-duration-long2) motion.$md-sys-motion-easing-emphasized-decelerate;
131
92
  }
132
- @mixin slider-progress() {
133
- block-size: var(--_track-height);
93
+ @mixin slider-tip-visible() {
94
+ opacity: 1;
95
+ transition: opacity var(--md-sys-motion-duration-medium2) motion.$md-sys-motion-easing-emphasized-accelerate;
134
96
  }
135
97
 
136
- input[type=range].micl-slider-xs {
98
+ input[type=range].micl-slider-xs,
99
+ .micl-slider__container:has(> .micl-slider-xs) {
137
100
  --_handle-height: var(--md-comp-slider-handle-height, 44px);
138
101
  --_track-height: var(--md-comp-slider-track-height, 16px);
139
102
  --_track-shape: var(--md-comp-slider-track-shape, var(--md-sys-shape-corner-small));
140
103
  }
141
- input[type=range].micl-slider-s {
104
+ input[type=range].micl-slider-s,
105
+ .micl-slider__container:has(> .micl-slider-s) {
142
106
  --_handle-height: var(--md-comp-slider-handle-height, 44px);
143
107
  --_track-height: var(--md-comp-slider-track-height, 24px);
144
108
  --_track-shape: var(--md-comp-slider-track-shape, var(--md-sys-shape-corner-small));
145
109
  }
146
- input[type=range].micl-slider-m {
110
+ input[type=range].micl-slider-m,
111
+ .micl-slider__container:has(> .micl-slider-m) {
147
112
  --_handle-height: var(--md-comp-slider-handle-height, 52px);
148
113
  --_track-height: var(--md-comp-slider-track-height, 40px);
149
114
  --_track-shape: var(--md-comp-slider-track-shape, var(--md-sys-shape-corner-medium));
150
115
  }
151
- input[type=range].micl-slider-l {
116
+ input[type=range].micl-slider-l,
117
+ .micl-slider__container:has(> .micl-slider-l) {
152
118
  --_handle-height: var(--md-comp-slider-handle-height, 68px);
153
119
  --_track-height: var(--md-comp-slider-track-height, 56px);
154
120
  --_track-shape: var(--md-comp-slider-track-shape, var(--md-sys-shape-corner-large));
155
121
  }
156
- input[type=range].micl-slider-xl {
122
+ input[type=range].micl-slider-xl,
123
+ .micl-slider__container:has(> .micl-slider-xl) {
157
124
  --_handle-height: var(--md-comp-slider-handle-height, 108px);
158
125
  --_track-height: var(--md-comp-slider-track-height, 96px);
159
126
  --_track-shape: var(--md-comp-slider-track-shape, var(--md-sys-shape-corner-extra-large));
160
127
  }
161
128
 
162
129
  input[type=range][class*=micl-slider-] {
163
- --_thumb-space: 6px;
164
- --_direction: to right;
165
- --_fraction: calc((var(--micl-slider-value) - var(--micl-slider-min)) / (var(--micl-slider-max) - var(--micl-slider-min)));
130
+ --_min: var(--micl-slider-min, attr(min type(<number>), 0));
131
+ --_max: var(--micl-slider-max, attr(max type(<number>), 100));
132
+ --_value: var(--micl-slider-value, attr(value type(<number>), calc((var(--_min) + var(--_max)) / 2)));
133
+ --_fraction: calc((var(--_value) - var(--_min)) / (var(--_max) - var(--_min)));
166
134
  --_thumb-position: calc(var(--_fraction) * (100% - 16px));
135
+ --_handle-inset: 0px;
136
+ --_handle-outline: none;
137
+ --_cursor: pointer;
167
138
  --_active-track-color: var(--md-comp-slider-active-track-color, var(--md-sys-color-primary));
168
139
  --_inactive-track-color: var(--md-comp-slider-inactive-track-color, var(--md-sys-color-secondary-container));
169
140
  --_handle-color: var(--md-comp-slider-handle-color, var(--md-sys-color-primary));
141
+ --_active-stop-color: var(--md-comp-slider-active-stop-indicator-container-color, var(--md-sys-color-on-primary));
142
+ --_inactive-stop-color: var(--md-comp-slider-inactive-stop-indicator-container-color, var(--md-sys-color-on-secondary-container));
143
+ --_direction: to right;
144
+ --_handle-radius: 8px / calc(6px - var(--_handle-inset));
145
+ --_kx: 1;
146
+ --_cx: 0px;
147
+ --_ky: 0;
148
+ --_cy: 50%;
149
+ --_stops: var(--micl-slider-stops, none);
150
+ --_stops-progress: var(--micl-slider-stops-progress, none);
151
+ --_end-stop: radial-gradient(
152
+ circle 2px at
153
+ calc(var(--_kx) * (100% - 8px) + var(--_cx))
154
+ calc(var(--_ky) * (100% - 8px) + var(--_cy)),
155
+ currentColor 100%,
156
+ transparent 0
157
+ );
158
+ --_active-fill: linear-gradient(var(--_direction), var(--_active-track-color) calc(var(--_thumb-position) - 2px), transparent 0);
159
+ --_corner-offset: calc(var(--_fraction) * (100% - 12px) - 4px);
160
+ --_corner-direction: to bottom;
161
+ --_corner-start: 2px 100%;
162
+ --_corner-end: 2px 0;
163
+ --_corner-image:
164
+ linear-gradient(var(--_corner-direction), transparent 2px, var(--_active-track-color) 0 calc(100% - 2px), transparent 0),
165
+ radial-gradient(circle 2px at var(--_corner-start), var(--_active-track-color) 100%, transparent 0),
166
+ radial-gradient(circle 2px at var(--_corner-end), var(--_active-track-color) 100%, transparent 0);
167
+ --_corner-size: 4px 100%, 4px 2px, 4px 2px;
168
+ --_corner-position: left var(--_corner-offset) center, left var(--_corner-offset) top 0, left var(--_corner-offset) bottom 0;
169
+ --_inactive-clip: inset(0 0 0 calc(var(--_thumb-position) + 16px) round 2px var(--_track-shape) var(--_track-shape) 2px);
170
+ --_active-clip: inset(0 calc(100% - var(--_thumb-position)) 0 0 round var(--_track-shape) 2px 2px var(--_track-shape));
171
+ --_progress-inset: calc(16px * var(--_fraction));
172
+ --_progress-radius: calc(2px + 16px * var(--_fraction)) 2px;
170
173
 
171
174
  appearance: none;
172
175
  position: relative;
173
176
  block-size: var(--_track-height);
174
177
  margin: 0;
175
178
  outline: none;
176
- color: var(--md-sys-color-surface-container-low);
177
- background-color: inherit;
179
+ border-radius: var(--_track-shape);
180
+ background-color: transparent;
181
+ background-image: var(--_corner-image), var(--_active-fill);
182
+ background-size: var(--_corner-size), auto;
183
+ background-position: var(--_corner-position), 0 0;
184
+ background-repeat: no-repeat;
178
185
  accent-color: var(--md-sys-color-primary);
179
186
 
180
187
  &::before {
181
- content: attr(data-miclsliderticks);
182
- box-sizing: border-box;
188
+ @include slider-inactive;
189
+
190
+ content: "";
183
191
  position: absolute;
184
- inline-size: 100%;
185
- max-inline-size: 100%;
186
- block-size: var(--_track-height);
187
- line-height: var(--_track-height);
188
- padding: 0 4px;
189
192
  inset: 0;
190
- color: var(--md-comp-slider-stop-indicator-color, var(--md-sys-color-on-primary));
191
- mix-blend-mode: difference;
192
- text-align: end;
193
- text-wrap-mode: nowrap;
194
193
  }
195
- &::after {
194
+ &:not(:disabled)::after {
196
195
  @include slider-tip;
196
+
197
+ inset-block-start: calc(-1 * ((var(--_handle-height) - var(--_track-height)) / 2) - 40px - var(--_tip-space));
198
+ inset-inline-start: calc(-16px + (100% - 16px) * var(--_fraction));
197
199
  }
198
- &::-webkit-slider-container {
199
- background-color: inherit;
200
+ &:disabled::after {
201
+ @include slider-active;
202
+
203
+ content: "";
204
+ position: absolute;
205
+ inset: 0;
200
206
  }
201
207
  &::-webkit-slider-runnable-track {
202
- @include slider-track;
208
+ block-size: var(--_track-height);
209
+ color: var(--_active-stop-color);
210
+ background-color: transparent;
211
+ background-image: var(--_stops);
203
212
  }
204
213
  &::-moz-range-track {
205
- @include slider-track;
214
+ @include slider-inactive;
215
+ }
216
+ &::-moz-range-progress {
217
+ box-sizing: border-box;
218
+ block-size: var(--_track-height);
219
+ border-inline-end: var(--_progress-inset) solid transparent;
220
+ color: var(--_active-stop-color);
221
+ background-clip: padding-box;
222
+ background-color: transparent;
223
+ background-image: var(--_stops-progress);
206
224
  }
207
225
  &::-webkit-slider-thumb {
208
226
  @include slider-thumb;
@@ -210,72 +228,92 @@ input[type=range][class*=micl-slider-] {
210
228
  &::-moz-range-thumb {
211
229
  @include slider-thumb;
212
230
  }
213
- &::-moz-range-progress {
214
- @include slider-progress;
215
- }
216
231
  &:disabled {
232
+ --_active-track-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-state-layer-opacity), transparent);
233
+ --_inactive-track-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
234
+ --_handle-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-state-layer-opacity), var(--md-sys-color-surface));
235
+ --_active-stop-color: var(--md-sys-color-inverse-on-surface);
236
+ --_inactive-stop-color: var(--md-sys-color-on-surface);
237
+ --_cursor: default;
238
+
239
+ background-image: none;
240
+
217
241
  &::-webkit-slider-runnable-track {
218
- @include slider-track-disabled;
242
+ background-image: none;
219
243
  }
220
- &::-moz-range-track {
221
- @include slider-track-disabled;
244
+ &::-moz-range-progress {
245
+ border-start-start-radius: var(--_track-shape);
246
+ border-end-start-radius: var(--_track-shape);
247
+ border-start-end-radius: var(--_progress-radius);
248
+ border-end-end-radius: var(--_progress-radius);
249
+ background-color: var(--_active-track-color);
222
250
  }
223
- &::-webkit-slider-thumb {
224
- @include slider-thumb-disabled;
251
+ }
252
+ &:not(:disabled) {
253
+ &:is(:active, :focus)::after {
254
+ @include slider-tip-visible;
225
255
  }
226
- &::-moz-range-thumb {
227
- @include slider-thumb-disabled;
256
+ // The 4px wide handle narrows to 2px while focused or pressed.
257
+ &:focus-visible {
258
+ --_handle-inset: 1px;
259
+ --_handle-outline: var(--md-sys-state-focus-indicator-thickness) solid var(--md-sys-color-secondary);
260
+ }
261
+ &:active {
262
+ --_handle-inset: 1px;
263
+ --_handle-outline: none;
264
+ --_cursor: grabbing;
228
265
  }
229
266
  }
230
267
  &.micl-slider--vertical {
231
268
  --_direction: to top;
269
+ --_kx: 0;
270
+ --_cx: 50%;
271
+ --_ky: -1;
272
+ --_cy: 100%;
273
+ --_handle-radius: calc(6px - var(--_handle-inset)) / 8px;
274
+ --_corner-direction: to right;
275
+ --_corner-start: 100% 2px;
276
+ --_corner-end: 0 2px;
277
+ --_corner-size: 100% 4px, 2px 4px, 2px 4px;
278
+ --_corner-position: center bottom var(--_corner-offset), left 0 bottom var(--_corner-offset), right 0 bottom var(--_corner-offset);
279
+ --_inactive-clip: inset(0 0 calc(var(--_thumb-position) + 16px) 0 round var(--_track-shape) var(--_track-shape) 2px 2px);
280
+ --_active-clip: inset(calc(100% - var(--_thumb-position)) 0 0 0 round 2px 2px var(--_track-shape) var(--_track-shape));
281
+ --_progress-radius: 2px calc(2px + 16px * var(--_fraction));
232
282
 
233
283
  writing-mode: sideways-lr;
234
284
 
235
- &::after {
285
+ &:not(:disabled)::after {
236
286
  --_tip-space: 8px;
237
287
 
238
288
  transform: rotate(90deg);
239
289
  }
240
290
  }
241
- &:not(:disabled) {
242
- &:active::after,
243
- &:focus::after,
244
- &:focus-visible::after {
245
- opacity: 1;
246
- transition: opacity var(--md-sys-motion-duration-medium2) motion.$md-sys-motion-easing-emphasized-accelerate;
247
- }
248
- &:focus-visible {
249
- &::-webkit-slider-thumb {
250
- outline: var(--md-sys-state-focus-indicator-thickness) solid var(--md-sys-color-secondary);
251
- }
252
- &::-moz-range-thumb {
253
- outline: var(--md-sys-state-focus-indicator-thickness) solid var(--md-sys-color-secondary);
254
- }
255
- }
256
- &:active {
257
- &::-webkit-slider-thumb {
258
- @include slider-thumb-active;
259
- }
260
- &::-moz-range-thumb {
261
- @include slider-thumb-active;
262
- }
263
- }
291
+ &:dir(rtl):not(.micl-slider--vertical) {
292
+ --_direction: to left;
293
+ --_kx: -1;
294
+ --_cx: 100%;
295
+ --_corner-start: calc(100% - 2px) 100%;
296
+ --_corner-end: calc(100% - 2px) 0;
297
+ --_corner-position: right var(--_corner-offset) center, right var(--_corner-offset) top 0, right var(--_corner-offset) bottom 0;
298
+ --_inactive-clip: inset(0 calc(var(--_thumb-position) + 16px) 0 0 round var(--_track-shape) 2px 2px var(--_track-shape));
299
+ --_active-clip: inset(0 0 0 calc(100% - var(--_thumb-position)) round 2px var(--_track-shape) var(--_track-shape) 2px);
264
300
  }
265
301
  }
266
302
 
267
303
  .micl-slider__container {
304
+ --_fraction: calc((var(--micl-slider-value) - var(--micl-slider-min)) / (var(--micl-slider-max) - var(--micl-slider-min)));
305
+
268
306
  display: grid;
269
307
  grid-template-areas: "slider-icon";
308
+ position: relative;
270
309
  flex-shrink: 0;
271
310
  align-items: center;
272
311
  justify-items: flex-start;
273
- background-color: inherit;
312
+ anchor-scope: --micl-slider;
274
313
 
275
314
  &:has(> .micl-slider-m,> .micl-slider-l,> .micl-slider-xl) {
276
315
  .micl-slider__icon {
277
316
  grid-area: slider-icon;
278
- inset: 0;
279
317
  margin: 6px;
280
318
  font-size: var(--md-sys-icon-size, 24px);
281
319
  color: var(--md-sys-color-on-primary);
@@ -284,52 +322,43 @@ input[type=range][class*=micl-slider-] {
284
322
  }
285
323
  &> input[type=range] {
286
324
  grid-area: slider-icon;
325
+ anchor-name: --micl-slider;
326
+
327
+ &:not(:disabled)::after {
328
+ content: none;
329
+ }
287
330
  }
288
331
  .micl-slider__icon:has(+ input[type=range].micl-slider-xl),
289
332
  input[type=range].micl-slider-xl + .micl-slider__icon {
290
333
  margin: 8px;
291
334
  font-size: 32px;
292
335
  }
293
- }
294
-
295
- // Gecko does not render generated content on <input>: the value indicator is
296
- // repeated on the container, which mirrors the slider variables (see index.ts).
297
- @supports (-moz-appearance:none) {
298
- .micl-slider__container {
299
- &:has(> input[type=range]) {
300
- --_fraction: calc((var(--micl-slider-value) - var(--micl-slider-min)) / (var(--micl-slider-max) - var(--micl-slider-min)));
336
+ &::after {
337
+ @include slider-tip;
301
338
 
302
- position: relative;
339
+ position-anchor: --micl-slider;
340
+ inset-block-start: calc(anchor(start) - (var(--_handle-height) - var(--_track-height)) / 2 - 40px - var(--_tip-space));
341
+ inset-inline-start: calc(anchor(start) - 16px + (anchor-size(inline) - 16px) * var(--_fraction));
342
+ }
343
+ &:has(> input[type=range]:not(:disabled):is(:active, :focus))::after {
344
+ @include slider-tip-visible;
345
+ }
346
+ &:has(> .micl-slider--vertical) {
347
+ writing-mode: sideways-lr;
303
348
 
304
- &::after {
305
- @include slider-tip;
306
- }
307
- }
308
- &:has(> input[type=range]:not(:disabled):active)::after,
309
- &:has(> input[type=range]:not(:disabled):focus)::after,
310
- &:has(> input[type=range]:not(:disabled):focus-visible)::after {
311
- opacity: 1;
312
- }
313
- &:has(> input[type=range].micl-slider--vertical) {
314
- --_direction: to top;
315
- writing-mode: sideways-lr;
349
+ &::after {
350
+ --_tip-space: 8px;
316
351
 
317
- &::after {
318
- --_tip-space: 8px;
319
- transform: rotate(90deg);
320
- }
352
+ transform: rotate(90deg);
321
353
  }
322
354
  }
323
355
  }
324
356
 
325
357
  input[type=range].micl-slider--vertical:dir(rtl),
326
- .micl-slider__container:dir(rtl):has(> input[type=range].micl-slider--vertical) {
358
+ .micl-slider__container:dir(rtl):has(> .micl-slider--vertical) {
327
359
  writing-mode: sideways-rl;
328
-
329
- &::after {
330
- transform: rotate(-90deg);
331
- }
332
360
  }
333
- input[type=range][class*=micl-slider-]:dir(rtl):not(.micl-slider--vertical) {
334
- --_direction: to left;
361
+ input[type=range].micl-slider--vertical:dir(rtl):not(:disabled)::after,
362
+ .micl-slider__container:dir(rtl):has(> .micl-slider--vertical)::after {
363
+ transform: rotate(-90deg);
335
364
  }