@expressivecss/expressive 0.1.0-alpha.3 → 0.2.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 (154) hide show
  1. package/LICENSE +82 -2
  2. package/README.md +153 -43
  3. package/dist/css/expressive.css +7121 -9658
  4. package/dist/css/expressive.css.map +1 -0
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -0
  7. package/dist/js/expressive.cjs +7521 -0
  8. package/dist/js/expressive.cjs.map +7 -0
  9. package/dist/js/expressive.js +7383 -8099
  10. package/dist/js/expressive.js.map +7 -1
  11. package/dist/js/expressive.min.js +75 -1
  12. package/dist/js/expressive.min.js.map +7 -1
  13. package/dist/js/expressive.mjs +7292 -7998
  14. package/dist/js/expressive.mjs.map +7 -1
  15. package/dist/types/behaviors/dialogs.d.ts +25 -0
  16. package/dist/{js → types}/components/autocomplete.d.ts +10 -1
  17. package/dist/{js → types}/components/buttons.d.ts +11 -1
  18. package/dist/{js → types}/components/cards.d.ts +10 -1
  19. package/dist/{js → types}/components/carousel.d.ts +4 -5
  20. package/dist/{js/forms/character-counter.d.ts → types/components/characterCounter.d.ts} +1 -1
  21. package/dist/{js → types}/components/chips.d.ts +1 -1
  22. package/dist/{js → types}/components/collapsible.d.ts +1 -1
  23. package/dist/{js → types}/components/datepicker.d.ts +63 -2
  24. package/dist/{js → types}/components/dropdown.d.ts +3 -3
  25. package/dist/types/components/index.d.ts +23 -0
  26. package/dist/{js/components/materialbox.d.ts → types/components/lightbox.d.ts} +21 -21
  27. package/dist/{js → types}/components/modal.d.ts +1 -1
  28. package/dist/{js → types}/components/parallax.d.ts +11 -5
  29. package/dist/{js → types}/components/pushpin.d.ts +1 -1
  30. package/dist/{js/forms → types/components}/range.d.ts +3 -3
  31. package/dist/types/components/registry.d.ts +107 -0
  32. package/dist/{js → types}/components/scrollspy.d.ts +6 -9
  33. package/dist/{js/forms → types/components}/select.d.ts +11 -2
  34. package/dist/{js → types}/components/sidenav.d.ts +1 -1
  35. package/dist/{js → types}/components/slider.d.ts +3 -2
  36. package/dist/{js → types}/components/tabs.d.ts +3 -2
  37. package/dist/{js/components/tap-target.d.ts → types/components/tapTarget.d.ts} +2 -2
  38. package/dist/{js → types}/components/timepicker.d.ts +13 -5
  39. package/dist/{js/components/toast.d.ts → types/components/toasts.d.ts} +28 -4
  40. package/dist/{js → types}/components/tooltip.d.ts +2 -2
  41. package/dist/types/core/bounding.d.ts +6 -0
  42. package/dist/{js/foundation → types/core}/component.d.ts +1 -1
  43. package/dist/types/core/edges.d.ts +6 -0
  44. package/dist/{js/foundation → types/core}/utils.d.ts +21 -14
  45. package/dist/types/index.d.ts +7 -0
  46. package/dist/{js/plugins/docked-display.d.ts → types/plugins/dockedDisplayPlugin.d.ts} +7 -0
  47. package/package.json +60 -36
  48. package/src/sass/README.md +200 -0
  49. package/src/sass/abstracts/_breakpoints.scss +69 -0
  50. package/src/sass/abstracts/_elevation.scss +34 -0
  51. package/src/sass/abstracts/_index.scss +7 -0
  52. package/src/sass/abstracts/_mixins.scss +171 -0
  53. package/src/sass/abstracts/_variables.scss +57 -0
  54. package/src/{scss/layout/_table.scss → sass/base/_global.scss} +64 -2
  55. package/src/{scss/layout → sass/base}/_grid.scss +6 -6
  56. package/src/sass/base/_index.scss +6 -0
  57. package/src/{scss/foundation → sass/base}/_normalize.scss +51 -139
  58. package/src/sass/base/_typography.scss +90 -0
  59. package/src/sass/components/_badges.scss +77 -0
  60. package/src/{scss → sass}/components/_breadcrumb.scss +2 -0
  61. package/src/sass/components/_buttons.scss +407 -0
  62. package/src/sass/components/_cards.scss +328 -0
  63. package/src/{scss → sass}/components/_carousel.scss +5 -3
  64. package/src/sass/components/_chips.scss +140 -0
  65. package/src/sass/components/_collapsible.scss +81 -0
  66. package/src/{scss → sass}/components/_collection.scss +2 -2
  67. package/src/{scss/components/_date-picker.scss → sass/components/_datepicker.scss} +51 -44
  68. package/src/sass/components/_docked-display.scss +11 -0
  69. package/src/sass/components/_dropdown.scss +129 -0
  70. package/src/{scss/components/_material-icons.scss → sass/components/_icons-material-design.scss} +2 -0
  71. package/src/sass/components/_index.scss +35 -0
  72. package/src/{scss/components/_material-box.scss → sass/components/_lightbox.scss} +6 -4
  73. package/src/sass/components/_modal.scss +208 -0
  74. package/src/sass/components/_navbar.scss +345 -0
  75. package/src/{scss/layout/_footer.scss → sass/components/_page-footer.scss} +7 -6
  76. package/src/{scss → sass}/components/_pagination.scss +4 -3
  77. package/src/{scss → sass}/components/_parallax.scss +4 -1
  78. package/src/{scss → sass}/components/_preloader.scss +19 -97
  79. package/src/{scss → sass}/components/_pulse.scss +2 -0
  80. package/src/sass/components/_pushpin.scss +11 -0
  81. package/src/{scss → sass}/components/_sidenav.scss +99 -82
  82. package/src/{scss → sass}/components/_slider.scss +3 -1
  83. package/src/{scss/components/_table-of-contents.scss → sass/components/_table_of_contents.scss} +2 -0
  84. package/src/sass/components/_tabs.scss +232 -0
  85. package/src/{scss/components/_tap-target.scss → sass/components/_tapTarget.scss} +24 -22
  86. package/src/{scss/components/_time-picker.scss → sass/components/_timepicker.scss} +56 -56
  87. package/src/sass/components/_toast.scss +260 -0
  88. package/src/sass/components/_toolbar.scss +192 -0
  89. package/src/sass/components/_tooltip.scss +166 -0
  90. package/src/{scss → sass}/components/_transitions.scss +4 -4
  91. package/src/sass/components/forms/_checkboxes.scss +288 -0
  92. package/src/sass/components/forms/_fieldset.scss +128 -0
  93. package/src/{scss → sass/components}/forms/_file-input.scss +11 -9
  94. package/src/{scss → sass/components}/forms/_index.scss +2 -0
  95. package/src/sass/components/forms/_input-fields.scss +326 -0
  96. package/src/sass/components/forms/_radio-buttons.scss +190 -0
  97. package/src/sass/components/forms/_range.scss +310 -0
  98. package/src/sass/components/forms/_select.scss +103 -0
  99. package/src/sass/components/forms/_switches.scss +239 -0
  100. package/src/sass/expressive.scss +60 -0
  101. package/src/sass/tokens/_index.scss +4 -0
  102. package/src/sass/tokens/_reference.scss +265 -0
  103. package/src/sass/tokens/_theme.scss +49 -0
  104. package/src/sass/utilities/_helpers.scss +63 -0
  105. package/src/sass/utilities/_index.scss +8 -0
  106. package/src/{scss → sass}/utilities/_spacing.scss +4 -3
  107. package/src/sass/utilities/_typescale.scss +45 -0
  108. package/src/sass/utilities/_visibility.scss +63 -0
  109. package/src/sass/utilities/_z-depth.scss +18 -0
  110. package/dist/js/components/index.d.ts +0 -21
  111. package/dist/js/forms/index.d.ts +0 -4
  112. package/dist/js/foundation/index.d.ts +0 -2
  113. package/dist/js/index.d.ts +0 -52
  114. package/dist/js/plugins/index.d.ts +0 -1
  115. package/src/scss/components/_appbar.scss +0 -454
  116. package/src/scss/components/_badges.scss +0 -77
  117. package/src/scss/components/_buttons.scss +0 -412
  118. package/src/scss/components/_cards.scss +0 -267
  119. package/src/scss/components/_chips.scss +0 -147
  120. package/src/scss/components/_collapsible.scss +0 -84
  121. package/src/scss/components/_dropdown.scss +0 -98
  122. package/src/scss/components/_index.scss +0 -28
  123. package/src/scss/components/_modal.scss +0 -84
  124. package/src/scss/components/_tabs.scss +0 -176
  125. package/src/scss/components/_toast.scss +0 -70
  126. package/src/scss/components/_tooltip.scss +0 -49
  127. package/src/scss/components/_video.scss +0 -15
  128. package/src/scss/expressive.scss +0 -7
  129. package/src/scss/forms/_checkboxes.scss +0 -199
  130. package/src/scss/forms/_input-fields.scss +0 -360
  131. package/src/scss/forms/_radio-buttons.scss +0 -114
  132. package/src/scss/forms/_range.scss +0 -148
  133. package/src/scss/forms/_select.scss +0 -108
  134. package/src/scss/forms/_switches.scss +0 -127
  135. package/src/scss/foundation/_base.scss +0 -71
  136. package/src/scss/foundation/_color-palette.scss +0 -402
  137. package/src/scss/foundation/_index.scss +0 -10
  138. package/src/scss/foundation/_mixins.scss +0 -198
  139. package/src/scss/foundation/_motion.scss +0 -70
  140. package/src/scss/foundation/_shape.scss +0 -30
  141. package/src/scss/foundation/_state-layers.scss +0 -68
  142. package/src/scss/foundation/_theme.scss +0 -238
  143. package/src/scss/foundation/_tokens.scss +0 -511
  144. package/src/scss/foundation/_variables.scss +0 -57
  145. package/src/scss/layout/_index.scss +0 -3
  146. package/src/scss/utilities/_a11y.scss +0 -77
  147. package/src/scss/utilities/_elevation.scss +0 -63
  148. package/src/scss/utilities/_helpers.scss +0 -50
  149. package/src/scss/utilities/_index.scss +0 -7
  150. package/src/scss/utilities/_responsive.scss +0 -62
  151. package/src/scss/utilities/_typography.scss +0 -115
  152. /package/dist/{js/forms → types/behaviors}/forms.d.ts +0 -0
  153. /package/dist/{js/components → types/behaviors}/waves.d.ts +0 -0
  154. /package/src/{scss → sass}/utilities/_colors.scss +0 -0
@@ -0,0 +1,310 @@
1
+ @use "../../abstracts" as *;
2
+
3
+ // Sliders (range).
4
+ //
5
+ // Anatomy is the HTML. An <input type="range"> is the control. A wrapping
6
+ // <label> (or .range / .range-field) is the host for the value label.
7
+ // .slider is the carousel — do not put it on a range.
8
+ // Helpers: .vertical, .small, .large. There is no required <span>.
9
+ //
10
+ // Tokens follow https://m3.material.io/components/sliders/specs (Expressive)
11
+ // track 16dp, fully rounded
12
+ // gap 6dp between handle and each track
13
+ // active primary
14
+ // inactive secondary-container
15
+ // handle 4×44dp, fully rounded, primary; 2dp when pressed
16
+ // state 40dp, 8% hover / 10% focus
17
+ // label inverse-surface / inverse-on-surface, body-small
18
+ // disabled 38%
19
+ //
20
+ // Range.Init() (import-time) sets --md-comp-slider-active-fraction so
21
+ // the active track can follow the value. Not in AutoInit(). Dual-handle
22
+ // range and discrete ticks are not implemented.
23
+
24
+ .range,
25
+ .range-field,
26
+ label:has(> [type="range"]) {
27
+ --md-comp-slider-track-height: 16px;
28
+ --md-comp-slider-handle-width: 4px;
29
+ --md-comp-slider-handle-width-pressed: 2px;
30
+ --md-comp-slider-handle-height: 44px;
31
+ --md-comp-slider-gap: 6px;
32
+ --md-comp-slider-active-track-color: var(--md-sys-color-primary);
33
+ --md-comp-slider-inactive-track-color: var(--md-sys-color-secondary-container);
34
+ --md-comp-slider-handle-color: var(--md-sys-color-primary);
35
+ --md-comp-slider-gradient: to right;
36
+
37
+ position: relative;
38
+ display: block;
39
+ overflow: visible;
40
+ color: var(--md-sys-color-on-surface);
41
+ @include typescale("body-large");
42
+ font-family: $font-stack;
43
+ }
44
+
45
+ .range.small,
46
+ .range-field.small,
47
+ label.small:has(> [type="range"]),
48
+ .range.small [type="range"],
49
+ .range-field.small [type="range"],
50
+ label.small > [type="range"] {
51
+ --md-comp-slider-track-height: 8px;
52
+ --md-comp-slider-handle-height: 32px;
53
+ }
54
+
55
+ .range.large,
56
+ .range-field.large,
57
+ label.large:has(> [type="range"]),
58
+ .range.large [type="range"],
59
+ .range-field.large [type="range"],
60
+ label.large > [type="range"] {
61
+ --md-comp-slider-track-height: 24px;
62
+ --md-comp-slider-handle-height: 52px;
63
+ }
64
+
65
+ .range.vertical,
66
+ .range-field.vertical,
67
+ label.vertical:has(> [type="range"]) {
68
+ --md-comp-slider-gradient: to top;
69
+ display: inline-flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ width: auto;
73
+ }
74
+
75
+ .range.vertical [type="range"],
76
+ .range-field.vertical [type="range"],
77
+ label.vertical > [type="range"] {
78
+ --md-comp-slider-gradient: to top;
79
+ }
80
+
81
+ input[type="range"] {
82
+ --md-comp-slider-track-height: 16px;
83
+ --md-comp-slider-handle-width: 4px;
84
+ --md-comp-slider-handle-width-pressed: 2px;
85
+ --md-comp-slider-handle-height: 44px;
86
+ --md-comp-slider-gap: 6px;
87
+ --md-comp-slider-active-track-color: var(--md-sys-color-primary);
88
+ --md-comp-slider-inactive-track-color: var(--md-sys-color-secondary-container);
89
+ --md-comp-slider-handle-color: var(--md-sys-color-primary);
90
+ --md-comp-slider-gradient: to right;
91
+ --md-comp-slider-active-fraction: 0%;
92
+
93
+ appearance: none;
94
+ box-sizing: border-box;
95
+ display: block;
96
+ width: 100%;
97
+ height: var(--md-comp-slider-handle-height);
98
+ margin: 8px 0;
99
+ padding: 0;
100
+ border: none;
101
+ background-color: transparent;
102
+ cursor: grab;
103
+ outline: none;
104
+ accent-color: var(--md-comp-slider-active-track-color);
105
+
106
+ &:active {
107
+ cursor: grabbing;
108
+ }
109
+
110
+ &:disabled {
111
+ cursor: default;
112
+ opacity: 0.38;
113
+ }
114
+ }
115
+
116
+ .range.vertical > [type="range"],
117
+ .range-field.vertical > [type="range"],
118
+ label.vertical > [type="range"] {
119
+ writing-mode: vertical-lr;
120
+ direction: rtl;
121
+ width: var(--md-comp-slider-handle-height);
122
+ height: 200px;
123
+ margin: 0 8px;
124
+ }
125
+
126
+ // Gap around the handle so the tracks do not run under it (M3 stop gap).
127
+ @mixin range-track-fill {
128
+ background-image: linear-gradient(
129
+ var(--md-comp-slider-gradient),
130
+ var(--md-comp-slider-active-track-color)
131
+ max(0%, calc(var(--md-comp-slider-active-fraction) - var(--md-comp-slider-gap) - var(--md-comp-slider-handle-width) / 2)),
132
+ transparent
133
+ max(0%, calc(var(--md-comp-slider-active-fraction) - var(--md-comp-slider-gap) - var(--md-comp-slider-handle-width) / 2)),
134
+ transparent
135
+ min(100%, calc(var(--md-comp-slider-active-fraction) + var(--md-comp-slider-gap) + var(--md-comp-slider-handle-width) / 2)),
136
+ var(--md-comp-slider-inactive-track-color)
137
+ min(100%, calc(var(--md-comp-slider-active-fraction) + var(--md-comp-slider-gap) + var(--md-comp-slider-handle-width) / 2))
138
+ );
139
+ }
140
+
141
+ @mixin range-track {
142
+ box-sizing: border-box;
143
+ width: 100%;
144
+ height: var(--md-comp-slider-track-height);
145
+ border: none;
146
+ border-radius: calc(var(--md-comp-slider-track-height) / 2);
147
+ background-color: transparent;
148
+ }
149
+
150
+ @mixin range-track-vertical {
151
+ width: var(--md-comp-slider-track-height);
152
+ height: 100%;
153
+ }
154
+
155
+ @mixin range-thumb {
156
+ appearance: none;
157
+ -webkit-appearance: none;
158
+ box-sizing: border-box;
159
+ border: none;
160
+ width: var(--md-comp-slider-handle-width);
161
+ height: var(--md-comp-slider-handle-height);
162
+ border-radius: calc(var(--md-comp-slider-handle-width) / 2);
163
+ background: var(--md-comp-slider-handle-color);
164
+ box-shadow: none;
165
+ cursor: grab;
166
+ transition: box-shadow .2s ease, width .15s ease, height .15s ease;
167
+ }
168
+
169
+ @mixin range-thumb-vertical {
170
+ width: var(--md-comp-slider-handle-height);
171
+ height: var(--md-comp-slider-handle-width);
172
+ border-radius: calc(var(--md-comp-slider-handle-width) / 2);
173
+ }
174
+
175
+ input[type="range"]::-webkit-slider-runnable-track {
176
+ @include range-track;
177
+ @include range-track-fill;
178
+ }
179
+
180
+ input[type="range"]::-webkit-slider-thumb {
181
+ @include range-thumb;
182
+ margin-top: calc((var(--md-comp-slider-track-height) - var(--md-comp-slider-handle-height)) / 2);
183
+ }
184
+
185
+ input[type="range"]:hover:not(:disabled)::-webkit-slider-thumb {
186
+ box-shadow: 0 0 0 18px color-mix(in oklab, var(--md-comp-slider-handle-color) 8%, transparent);
187
+ }
188
+
189
+ .keyboard-focused input[type="range"]:focus:not(:disabled)::-webkit-slider-thumb,
190
+ input[type="range"]:focus-visible:not(:disabled)::-webkit-slider-thumb {
191
+ box-shadow: 0 0 0 18px color-mix(in oklab, var(--md-comp-slider-handle-color) 10%, transparent);
192
+ }
193
+
194
+ input[type="range"]:active:not(:disabled)::-webkit-slider-thumb {
195
+ width: var(--md-comp-slider-handle-width-pressed);
196
+ }
197
+
198
+ .range.vertical > [type="range"]::-webkit-slider-runnable-track,
199
+ .range-field.vertical > [type="range"]::-webkit-slider-runnable-track,
200
+ label.vertical > [type="range"]::-webkit-slider-runnable-track {
201
+ @include range-track-vertical;
202
+ // writing-mode does not swap physical width/height on these pseudos.
203
+ // Center the 16dp track inside the 44dp-wide input.
204
+ margin-left: calc((var(--md-comp-slider-handle-height) - var(--md-comp-slider-track-height)) / 2);
205
+ }
206
+
207
+ .range.vertical > [type="range"]::-webkit-slider-thumb,
208
+ .range-field.vertical > [type="range"]::-webkit-slider-thumb,
209
+ label.vertical > [type="range"]::-webkit-slider-thumb {
210
+ @include range-thumb-vertical;
211
+ margin-top: 0;
212
+ margin-left: calc((var(--md-comp-slider-track-height) - var(--md-comp-slider-handle-height)) / 2);
213
+ }
214
+
215
+ .range.vertical > [type="range"]:active:not(:disabled)::-webkit-slider-thumb,
216
+ .range-field.vertical > [type="range"]:active:not(:disabled)::-webkit-slider-thumb,
217
+ label.vertical > [type="range"]:active:not(:disabled)::-webkit-slider-thumb {
218
+ width: var(--md-comp-slider-handle-height);
219
+ height: var(--md-comp-slider-handle-width-pressed);
220
+ }
221
+
222
+ input[type="range"]::-moz-range-track {
223
+ @include range-track;
224
+ @include range-track-fill;
225
+ }
226
+
227
+ input[type="range"]::-moz-range-thumb {
228
+ @include range-thumb;
229
+ }
230
+
231
+ input[type="range"]:hover:not(:disabled)::-moz-range-thumb {
232
+ box-shadow: 0 0 0 18px color-mix(in oklab, var(--md-comp-slider-handle-color) 8%, transparent);
233
+ }
234
+
235
+ .keyboard-focused input[type="range"]:focus:not(:disabled)::-moz-range-thumb,
236
+ input[type="range"]:focus-visible:not(:disabled)::-moz-range-thumb {
237
+ box-shadow: 0 0 0 18px color-mix(in oklab, var(--md-comp-slider-handle-color) 10%, transparent);
238
+ }
239
+
240
+ input[type="range"]:active:not(:disabled)::-moz-range-thumb {
241
+ width: var(--md-comp-slider-handle-width-pressed);
242
+ }
243
+
244
+ .range.vertical > [type="range"]::-moz-range-track,
245
+ .range-field.vertical > [type="range"]::-moz-range-track,
246
+ label.vertical > [type="range"]::-moz-range-track {
247
+ @include range-track-vertical;
248
+ margin-left: calc((var(--md-comp-slider-handle-height) - var(--md-comp-slider-track-height)) / 2);
249
+ }
250
+
251
+ .range.vertical > [type="range"]::-moz-range-thumb,
252
+ .range-field.vertical > [type="range"]::-moz-range-thumb,
253
+ label.vertical > [type="range"]::-moz-range-thumb {
254
+ @include range-thumb-vertical;
255
+ margin-left: calc((var(--md-comp-slider-track-height) - var(--md-comp-slider-handle-height)) / 2);
256
+ }
257
+
258
+ .range.vertical > [type="range"]:active:not(:disabled)::-moz-range-thumb,
259
+ .range-field.vertical > [type="range"]:active:not(:disabled)::-moz-range-thumb,
260
+ label.vertical > [type="range"]:active:not(:disabled)::-moz-range-thumb {
261
+ width: var(--md-comp-slider-handle-height);
262
+ height: var(--md-comp-slider-handle-width-pressed);
263
+ }
264
+
265
+ // Value label — M3 labeled slider. The JS plugin inserts this after the input.
266
+ input[type="range"] + .thumb {
267
+ position: absolute;
268
+ left: 0;
269
+ top: 0;
270
+ z-index: 2;
271
+ box-sizing: border-box;
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: center;
275
+ min-width: 28px;
276
+ min-height: 28px;
277
+ padding: 4px 8px;
278
+ border: none;
279
+ border-radius: 14px;
280
+ background-color: var(--md-sys-color-inverse-surface);
281
+ color: var(--md-sys-color-inverse-on-surface);
282
+ pointer-events: none;
283
+ opacity: 0;
284
+ transform: translate(-50%, calc(-100% - 12px)) scale(0.9);
285
+ transform-origin: center bottom;
286
+ transition: opacity .15s ease, transform .15s ease;
287
+ @include typescale("body-small");
288
+
289
+ .value {
290
+ display: block;
291
+ color: inherit;
292
+ font: inherit;
293
+ }
294
+
295
+ &.active {
296
+ opacity: 1;
297
+ transform: translate(-50%, calc(-100% - 12px)) scale(1);
298
+ }
299
+ }
300
+
301
+ .range.vertical > [type="range"] + .thumb,
302
+ .range-field.vertical > [type="range"] + .thumb,
303
+ label.vertical > [type="range"] + .thumb {
304
+ transform: translate(calc(100% + 12px), -50%) scale(0.9);
305
+ transform-origin: left center;
306
+
307
+ &.active {
308
+ transform: translate(calc(100% + 12px), -50%) scale(1);
309
+ }
310
+ }
@@ -0,0 +1,103 @@
1
+ @use "../../abstracts" as *;
2
+
3
+ select.browser-default {
4
+ opacity: 1;
5
+ color: var(--md-sys-color-on-background);
6
+ }
7
+
8
+ // TODO: Change to ".select" and not use tag name directly
9
+ // Keep selects useable without javascript
10
+
11
+ select {
12
+ background-color: var(--md-sys-color-surface);
13
+ width: 100%;
14
+ padding: 5px;
15
+ border: 1px solid var(--md-sys-color-outline-variant);
16
+ border-radius: 2px;
17
+ height: 3rem;
18
+ }
19
+
20
+ .select-wrapper:focus-within {
21
+ outline: 2px solid var(--md-sys-color-primary);
22
+ border-radius: 4px;
23
+ }
24
+
25
+ .select-wrapper {
26
+ position: relative;
27
+
28
+ .caret {
29
+ position: absolute;
30
+ right: 0;
31
+ top: 0;
32
+ bottom: 0;
33
+ margin: auto 0;
34
+ z-index: 0;
35
+ fill: var(--md-sys-color-on-background);
36
+ pointer-events: none;
37
+ }
38
+
39
+ // Hide select with overflow hidden instead of using display none
40
+ // (this prevents form validation errors with hidden form elements)
41
+ .hide-select {
42
+ width: 0;
43
+ height: 0;
44
+ overflow: hidden;
45
+ position: absolute;
46
+ top: 0;
47
+ z-index: -1;
48
+ }
49
+ }
50
+
51
+ select:disabled {
52
+ color: var(--md-sys-color-on-surface);
53
+ }
54
+
55
+ .select-wrapper.disabled {
56
+ + label {
57
+ color: var(--md-sys-color-on-surface);
58
+ }
59
+ .caret {
60
+ fill: var(--md-sys-color-on-surface);
61
+ }
62
+ }
63
+
64
+ .select-wrapper input.select-dropdown:disabled {
65
+ color: var(--md-sys-color-on-surface);
66
+ cursor: default;
67
+ user-select: none;
68
+ }
69
+
70
+ .select-wrapper i {
71
+ color: var(--md-sys-color-on-surface);
72
+ }
73
+
74
+ .select-dropdown li.disabled,
75
+ .select-dropdown li.disabled > span,
76
+ .select-dropdown li.optgroup {
77
+ color: var(--md-sys-color-on-surface);
78
+ //background-color: transparent;
79
+ }
80
+
81
+ // Icons
82
+ .select-dropdown li {
83
+ img {
84
+ height: $dropdown-item-height - 10;
85
+ width: $dropdown-item-height - 10;
86
+ margin: 5px 15px;
87
+ float: right;
88
+ }
89
+ }
90
+
91
+ // Optgroup styles
92
+ .select-dropdown li.optgroup {
93
+ border-top: 1px solid rgba(0, 0, 0, 0.04);
94
+ &.selected > span {
95
+ color: var(--md-sys-color-on-background);
96
+ }
97
+ & > span {
98
+ color: var(--md-sys-color-on-surface-variant);
99
+ }
100
+ & ~ li.optgroup-option {
101
+ padding-left: 1rem;
102
+ }
103
+ }
@@ -0,0 +1,239 @@
1
+ @use "../../abstracts" as *;
2
+
3
+ // Switches.
4
+ //
5
+ // Anatomy is the HTML. A <label class="switch"> wrapping
6
+ // <input type="checkbox"> is the control. The label text is a sibling of
7
+ // the input — no .lever required. input + .lever and input + span still
8
+ // work (legacy / BeerCSS).
9
+ //
10
+ // Tokens follow https://m3.material.io/components/switch/specs
11
+ // track 52×32dp, 16dp corners
12
+ // unselected surface-variant + 2dp outline, 16dp handle
13
+ // selected primary track, 24dp on-primary handle
14
+ // state layer 40dp, 8% hover / 10% focus
15
+ // touch target 48dp
16
+ // label body-large / on-surface
17
+ // disabled 38%
18
+
19
+ .switch {
20
+ --md-comp-switch-track-width: 52px;
21
+ --md-comp-switch-track-height: 32px;
22
+ --md-comp-switch-handle-unselected: 16px;
23
+ --md-comp-switch-handle-selected: 24px;
24
+
25
+ display: inline-flex;
26
+ align-items: center;
27
+ gap: 12px;
28
+ min-height: 48px;
29
+ margin: 0;
30
+ cursor: pointer;
31
+ user-select: none;
32
+ -webkit-tap-highlight-color: transparent;
33
+ color: var(--md-sys-color-on-surface);
34
+ @include typescale("body-large");
35
+ font-family: $font-stack;
36
+ }
37
+
38
+ .switch label {
39
+ display: inline-flex;
40
+ align-items: center;
41
+ gap: 12px;
42
+ cursor: pointer;
43
+ user-select: none;
44
+ }
45
+
46
+ // Hide the native control only when a following span/lever draws the track.
47
+ .switch [type="checkbox"]:has(+ .lever),
48
+ .switch [type="checkbox"]:has(+ span) {
49
+ position: absolute;
50
+ opacity: 0;
51
+ width: 0;
52
+ height: 0;
53
+ pointer-events: none;
54
+ }
55
+
56
+ // Paint the switch on the checkbox when there is no lever/span.
57
+ .switch [type="checkbox"]:not(:has(+ .lever)):not(:has(+ span)) {
58
+ appearance: none;
59
+ position: static;
60
+ opacity: 1;
61
+ pointer-events: auto;
62
+ flex: 0 0 var(--md-comp-switch-track-width);
63
+ box-sizing: border-box;
64
+ width: var(--md-comp-switch-track-width);
65
+ height: var(--md-comp-switch-track-height);
66
+ margin: 0;
67
+ padding: 0;
68
+ border: 2px solid var(--md-sys-color-outline);
69
+ border-radius: 16px;
70
+ background-color: var(--md-sys-color-surface-variant);
71
+ background-image: radial-gradient(
72
+ circle,
73
+ var(--md-sys-color-outline) 0 8px,
74
+ transparent 8.5px
75
+ );
76
+ background-repeat: no-repeat;
77
+ background-position: 8px center;
78
+ cursor: pointer;
79
+ transition: background-color .2s ease, background-position .2s ease,
80
+ background-size .2s ease, border-color .2s ease, box-shadow .2s ease;
81
+
82
+ &:checked {
83
+ border-color: var(--md-sys-color-primary);
84
+ background-color: var(--md-sys-color-primary);
85
+ background-image: radial-gradient(
86
+ circle,
87
+ var(--md-sys-color-on-primary) 0 12px,
88
+ transparent 12.5px
89
+ );
90
+ background-position: calc(100% - 14px) center;
91
+ }
92
+
93
+ &:hover {
94
+ box-shadow: 0 0 0 8px color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
95
+ }
96
+
97
+ &:checked:hover {
98
+ box-shadow: 0 0 0 8px color-mix(in oklab, var(--md-sys-color-primary) 8%, transparent);
99
+ }
100
+
101
+ &:focus-visible,
102
+ &.tabbed:focus {
103
+ box-shadow: 0 0 0 8px color-mix(in oklab, var(--md-sys-color-primary) 10%, transparent);
104
+ outline: none;
105
+ }
106
+
107
+ &:disabled {
108
+ opacity: 0.38;
109
+ box-shadow: none;
110
+ cursor: default;
111
+ }
112
+ }
113
+
114
+ .switch:has(> [type="checkbox"]:disabled),
115
+ .switch:has([type="checkbox"]:disabled) label {
116
+ color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
117
+ cursor: default;
118
+ }
119
+
120
+ // Legacy / BeerCSS: input + .lever or input + span draws the same anatomy.
121
+ .switch [type="checkbox"] + .lever,
122
+ .switch [type="checkbox"] + span {
123
+ position: relative;
124
+ display: inline-flex;
125
+ align-items: center;
126
+ flex: 0 0 auto;
127
+ box-sizing: border-box;
128
+ width: var(--md-comp-switch-track-width);
129
+ height: var(--md-comp-switch-track-height);
130
+ margin: 0;
131
+ padding: 0;
132
+ border: 2px solid var(--md-sys-color-outline);
133
+ border-radius: 16px;
134
+ background-color: var(--md-sys-color-surface-variant);
135
+ vertical-align: middle;
136
+ transition: background-color .2s ease, border-color .2s ease, box-shadow .2s ease;
137
+
138
+ &::before,
139
+ &::after {
140
+ content: "";
141
+ position: absolute;
142
+ top: 6px;
143
+ left: 6px;
144
+ width: 16px;
145
+ height: 16px;
146
+ border-radius: 50%;
147
+ transition: left .2s ease, top .2s ease, width .2s ease, height .2s ease,
148
+ background-color .2s ease, transform .2s ease;
149
+ }
150
+
151
+ &::after {
152
+ background-color: var(--md-sys-color-outline);
153
+ }
154
+ }
155
+
156
+ .switch [type="checkbox"]:checked + .lever,
157
+ .switch [type="checkbox"]:checked + span {
158
+ border-color: var(--md-sys-color-primary);
159
+ background-color: var(--md-sys-color-primary);
160
+
161
+ &::before,
162
+ &::after {
163
+ top: 2px;
164
+ left: 22px;
165
+ width: 24px;
166
+ height: 24px;
167
+ }
168
+
169
+ &::after {
170
+ background-color: var(--md-sys-color-on-primary);
171
+ }
172
+ }
173
+
174
+ .switch [type="checkbox"]:hover + .lever,
175
+ .switch [type="checkbox"]:hover + span {
176
+ box-shadow: 0 0 0 8px color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
177
+ }
178
+
179
+ .switch [type="checkbox"]:checked:hover + .lever,
180
+ .switch [type="checkbox"]:checked:hover + span {
181
+ box-shadow: 0 0 0 8px color-mix(in oklab, var(--md-sys-color-primary) 8%, transparent);
182
+ }
183
+
184
+ .switch [type="checkbox"]:focus-visible + .lever,
185
+ .switch [type="checkbox"].tabbed:focus + .lever,
186
+ .switch [type="checkbox"]:focus-visible + span,
187
+ .switch [type="checkbox"].tabbed:focus + span {
188
+ box-shadow: 0 0 0 8px color-mix(in oklab, var(--md-sys-color-primary) 10%, transparent);
189
+ }
190
+
191
+ .switch [type="checkbox"]:disabled + .lever,
192
+ .switch [type="checkbox"]:disabled + span {
193
+ opacity: 0.38;
194
+ box-shadow: none;
195
+ cursor: default;
196
+ }
197
+
198
+ // BeerCSS: span holds the label text as well as the track.
199
+ .switch [type="checkbox"] + span:not(.lever):not(:empty) {
200
+ width: auto;
201
+ min-width: var(--md-comp-switch-track-width);
202
+ height: auto;
203
+ min-height: var(--md-comp-switch-track-height);
204
+ padding-left: calc(var(--md-comp-switch-track-width) + 12px);
205
+ border: 0;
206
+ background-color: transparent;
207
+ border-radius: 0;
208
+
209
+ &::before {
210
+ border: 2px solid var(--md-sys-color-outline);
211
+ background-color: var(--md-sys-color-surface-variant);
212
+ box-sizing: border-box;
213
+ width: var(--md-comp-switch-track-width);
214
+ height: var(--md-comp-switch-track-height);
215
+ border-radius: 16px;
216
+ top: 0;
217
+ left: 0;
218
+ }
219
+
220
+ &::after {
221
+ top: 8px;
222
+ left: 8px;
223
+ }
224
+ }
225
+
226
+ .switch [type="checkbox"]:checked + span:not(.lever):not(:empty) {
227
+ background-color: transparent;
228
+ border-color: transparent;
229
+
230
+ &::before {
231
+ border-color: var(--md-sys-color-primary);
232
+ background-color: var(--md-sys-color-primary);
233
+ }
234
+
235
+ &::after {
236
+ top: 4px;
237
+ left: 24px;
238
+ }
239
+ }
@@ -0,0 +1,60 @@
1
+ @charset "UTF-8";
2
+
3
+ // ExpressiveCSS entry point.
4
+ //
5
+ // This is the only place cascade order is decided, so a rule's position is
6
+ // always answerable from this file. Layers:
7
+ //
8
+ // abstracts - variables, functions, mixins. Emits nothing, so it is not a
9
+ // cascade layer at all; partials pull it in with
10
+ // `@use "../abstracts" as *;`. Forwarded below so that
11
+ // downstream projects consuming this file keep access to the
12
+ // breakpoint mixins, z-depth() and btn-*.
13
+ // tokens - :root custom properties (M3 reference palette + theme).
14
+ // base - normalize, element defaults, typography, grid.
15
+ // components - widgets.
16
+ // utilities - helper classes.
17
+ //
18
+ // Order used to be expressed purely as @forward order, with utilities emitted
19
+ // before components so a component rule would win at equal specificity. It is
20
+ // now a real @layer list, which changes three things:
21
+ //
22
+ // 1. Utilities moved after components. Layer order beats specificity
23
+ // outright, so a helper class now wins over a component rule without
24
+ // needing to out-specify it.
25
+ // 2. Unlayered CSS beats every layer. A consumer can override any component
26
+ // with a plain `.btn { ... }` - no specificity war, no load-order
27
+ // dependence on where the framework sits in their bundle.
28
+ // 3. !important is NOT dropped from utilities. Layer order reverses for
29
+ // important declarations, so an important rule inside `utilities` would
30
+ // also beat a consumer's own !important - but a *normal* rule in a layer
31
+ // loses to any unlayered consumer rule. Since `.hide`, `.m-3` and the
32
+ // palette classes exist precisely to be unconditional, they keep their
33
+ // flags and keep winning. Dropping them would silently make `.hide` lose
34
+ // to any unlayered `display` the consumer had already written.
35
+ //
36
+ // @forward cannot appear inside @layer, so each layer is pulled in with
37
+ // meta.load-css() instead. abstracts emits no CSS, so loading it separately
38
+ // below duplicates nothing.
39
+
40
+ @use "sass:meta";
41
+
42
+ @forward "abstracts";
43
+
44
+ @layer tokens, base, components, utilities;
45
+
46
+ @layer tokens {
47
+ @include meta.load-css("tokens");
48
+ }
49
+
50
+ @layer base {
51
+ @include meta.load-css("base");
52
+ }
53
+
54
+ @layer components {
55
+ @include meta.load-css("components");
56
+ }
57
+
58
+ @layer utilities {
59
+ @include meta.load-css("utilities");
60
+ }