@fluixi-ui/skin-material 0.2.1-alpha.0 → 0.3.0-alpha.10
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.
- package/material.css +718 -30
- package/material.css.js +8 -0
- package/package.json +3 -2
package/material.css
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* geometry, filled text fields, emphasized motion, Roboto. (True click-origin
|
|
11
11
|
* ripple needs JS; the state layer stands in for it here.)
|
|
12
12
|
*/
|
|
13
|
-
@layer flx.tokens, flx.components, flx.skin;
|
|
13
|
+
@layer flx.reset, flx.base, flx.tokens, flx.components, flx.skin, flx.fx;
|
|
14
14
|
|
|
15
15
|
/* Self-hosted Roboto (variable, latin subset) — no CDN / privacy dependency. */
|
|
16
16
|
@font-face {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/* ---- Button: pill shape, state layer, filled/tonal/outlined/text ---------- */
|
|
43
|
-
[data-ui='material'] :where([data-variant]) {
|
|
43
|
+
[data-ui='material'] :where([data-variant]:not([data-badge])) {
|
|
44
44
|
position: relative;
|
|
45
45
|
overflow: hidden;
|
|
46
46
|
border-radius: 9999px;
|
|
@@ -56,44 +56,40 @@
|
|
|
56
56
|
/* The Material "state layer": a currentColor overlay that fades in on interaction.
|
|
57
57
|
On a filled button currentColor is the on-primary ink (white) → a subtle
|
|
58
58
|
lightening; on outlined/text/tonal it's the primary colour. */
|
|
59
|
-
[data-ui='material'] :where([data-variant])::before {
|
|
59
|
+
[data-ui='material'] :where([data-variant]:not([data-badge]))::before {
|
|
60
60
|
content: '';
|
|
61
61
|
position: absolute;
|
|
62
62
|
inset: 0;
|
|
63
|
+
/* Follow the button's own shape so the hover layer is rounded even where the
|
|
64
|
+
button isn't clipping (e.g. a glow button, which overflows). */
|
|
65
|
+
border-radius: inherit;
|
|
63
66
|
background: currentColor;
|
|
64
67
|
opacity: 0;
|
|
65
68
|
pointer-events: none;
|
|
66
69
|
transition: opacity var(--flx-ui-duration-fast) var(--flx-ui-ease-standard);
|
|
67
70
|
}
|
|
68
|
-
[data-ui='material'] :where([data-variant]:hover)::before { opacity: 0.08; }
|
|
69
|
-
[data-ui='material'] :where([data-variant]:focus-visible)::before { opacity: 0.12; }
|
|
70
|
-
[data-ui='material'] :where([data-variant]:active)::before { opacity: 0.16; }
|
|
71
|
-
[data-ui='material'] :where([data-variant]:focus-visible) { box-shadow: none; outline: none; }
|
|
72
|
-
[data-ui='material'] :where([data-variant][disabled], [data-variant]:disabled) {
|
|
71
|
+
[data-ui='material'] :where([data-variant]:not([data-badge]):hover)::before { opacity: 0.08; }
|
|
72
|
+
[data-ui='material'] :where([data-variant]:not([data-badge]):focus-visible)::before { opacity: 0.12; }
|
|
73
|
+
[data-ui='material'] :where([data-variant]:not([data-badge]):active)::before { opacity: 0.16; }
|
|
74
|
+
[data-ui='material'] :where([data-variant]:not([data-badge]):focus-visible) { box-shadow: none; outline: none; }
|
|
75
|
+
[data-ui='material'] :where([data-variant]:not([data-badge])[disabled], [data-variant]:not([data-badge]):disabled) {
|
|
73
76
|
box-shadow: none;
|
|
74
77
|
opacity: 0.38;
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
/* Filled (solid) = the classic contained button: rests on elevation, lifts
|
|
78
81
|
further on hover. Elevation is per-variant — outlined/text/tonal stay flat. */
|
|
79
|
-
[data-ui='material'] :where([data-variant='solid']) { box-shadow: var(--flx-ui-shadow-sm); }
|
|
80
|
-
[data-ui='material'] :where([data-variant='solid']:hover) { box-shadow: var(--flx-ui-shadow-md); }
|
|
81
|
-
[data-ui='material'] :where([data-variant='solid']:active) { box-shadow: var(--flx-ui-shadow-sm); }
|
|
82
|
+
[data-ui='material'] :where([data-variant='solid']:not([data-badge])) { box-shadow: var(--flx-ui-shadow-sm); }
|
|
83
|
+
[data-ui='material'] :where([data-variant='solid']:not([data-badge]):hover) { box-shadow: var(--flx-ui-shadow-md); }
|
|
84
|
+
[data-ui='material'] :where([data-variant='solid']:not([data-badge]):active) { box-shadow: var(--flx-ui-shadow-sm); }
|
|
82
85
|
/* Tonal (soft): secondary-container feel. */
|
|
83
|
-
[data-ui='material'] :where([data-variant='soft']) { background: var(--flx-ui-color-primary-subtle); color: var(--flx-ui-color-primary-active); }
|
|
86
|
+
[data-ui='material'] :where([data-variant='soft']:not([data-badge])) { background: var(--flx-ui-color-primary-subtle); color: var(--flx-ui-color-primary-active); }
|
|
84
87
|
/* Outlined: 1px hairline, no fill. */
|
|
85
|
-
[data-ui='material'] :where([data-variant='outline']) { border: 1px solid var(--flx-ui-color-border-strong); }
|
|
88
|
+
[data-ui='material'] :where([data-variant='outline']:not([data-badge])) { border: 1px solid var(--flx-ui-color-border-strong); }
|
|
86
89
|
/* Text: tighter padding, no border. */
|
|
87
|
-
[data-ui='material'] :where([data-variant='ghost']) { padding: 0 12px; }
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
not buttons): restore size, keep the pill, drop the state layer. */
|
|
91
|
-
[data-ui='material'] :where(.flx-ui-badge[data-variant]) {
|
|
92
|
-
height: auto;
|
|
93
|
-
padding: 2px 10px;
|
|
94
|
-
box-shadow: none;
|
|
95
|
-
}
|
|
96
|
-
[data-ui='material'] :where(.flx-ui-badge[data-variant])::before { content: none; }
|
|
90
|
+
[data-ui='material'] :where([data-variant='ghost']:not([data-badge])) { padding: 0 12px; }
|
|
91
|
+
/* Badges carry [data-variant] too, but every button rule above excludes
|
|
92
|
+
[data-badge], so a badge is never treated as a button — no guard needed. */
|
|
97
93
|
|
|
98
94
|
/* ---- Switch: M3 geometry (52×32 track, growing thumb) --------------------- */
|
|
99
95
|
[data-ui='material'] :where([role='switch']) {
|
|
@@ -129,9 +125,26 @@
|
|
|
129
125
|
border-width: 2px;
|
|
130
126
|
border-radius: 2px;
|
|
131
127
|
}
|
|
128
|
+
/* The check (rotated border) and indeterminate bar are flex items; the tighter
|
|
129
|
+
2px-border box lets flex shrink them to a sliver on the main axis. Pin them. */
|
|
130
|
+
[data-ui='material'] :where([role='checkbox'][data-state='checked'])::after,
|
|
131
|
+
[data-ui='material'] :where([role='checkbox'][data-state='indeterminate'])::after {
|
|
132
|
+
flex: none;
|
|
133
|
+
}
|
|
134
|
+
[data-ui='material'] :where([role='checkbox'][data-state='checked'])::after {
|
|
135
|
+
width: 4px;
|
|
136
|
+
height: 8px;
|
|
137
|
+
margin-top: -3px;
|
|
138
|
+
}
|
|
139
|
+
/* Multi-select listbox/select indicator box → match the material checkbox. */
|
|
140
|
+
[data-ui='material'] :where([data-select-item-indicator]) {
|
|
141
|
+
box-sizing: border-box;
|
|
142
|
+
border-width: 2px;
|
|
143
|
+
border-radius: 2px;
|
|
144
|
+
}
|
|
132
145
|
|
|
133
146
|
/* ---- Slider: M3 filled thumb -------------------------------------------- */
|
|
134
|
-
[data-ui='material'] :where([role='slider']) {
|
|
147
|
+
[data-ui='material'] :where([data-slider] [role='slider']) {
|
|
135
148
|
width: 20px;
|
|
136
149
|
height: 20px;
|
|
137
150
|
background: var(--flx-ui-color-primary);
|
|
@@ -146,18 +159,48 @@
|
|
|
146
159
|
border-top-right-radius: 3px;
|
|
147
160
|
}
|
|
148
161
|
|
|
149
|
-
/* ----
|
|
150
|
-
|
|
162
|
+
/* ---- Text field / select / combobox appearance --------------------------
|
|
163
|
+
Baseline (no data-field-variant) and the explicit `filled` variant → M3
|
|
164
|
+
filled underline; `outlined` → M3 outlined box. 4px M3 radius (the tokens'
|
|
165
|
+
radius-md is 12px here). */
|
|
166
|
+
[data-ui='material'] :where(
|
|
167
|
+
[data-input]:not([data-field-variant]),
|
|
168
|
+
[data-combobox-control]:not([data-field-variant]),
|
|
169
|
+
button[role='combobox']:not([data-field-variant]),
|
|
170
|
+
[data-field-variant='filled']) {
|
|
151
171
|
background: var(--flx-ui-color-bg-muted);
|
|
152
|
-
border:
|
|
172
|
+
border: 1px solid transparent;
|
|
153
173
|
border-bottom: 1px solid var(--flx-ui-color-border-strong);
|
|
154
174
|
border-radius: 4px 4px 0 0;
|
|
155
175
|
}
|
|
156
|
-
[data-ui='material'] :where(
|
|
176
|
+
[data-ui='material'] :where(
|
|
177
|
+
[data-input]:not([data-field-variant]):focus,
|
|
178
|
+
[data-combobox-control]:not([data-field-variant]):focus-within,
|
|
179
|
+
button[role='combobox']:not([data-field-variant]):focus-visible,
|
|
180
|
+
button[role='combobox']:not([data-field-variant])[data-state='open'],
|
|
181
|
+
[data-field-variant='filled']:focus,
|
|
182
|
+
[data-field-variant='filled']:focus-visible,
|
|
183
|
+
[data-field-variant='filled']:focus-within) {
|
|
157
184
|
border-bottom: 2px solid var(--flx-ui-color-primary);
|
|
158
185
|
box-shadow: none;
|
|
159
186
|
outline: none;
|
|
160
187
|
}
|
|
188
|
+
/* Outlined → M3 outlined box (4px), 2px primary border on focus. */
|
|
189
|
+
[data-ui='material'] :where([data-field-variant='outlined']) {
|
|
190
|
+
background: transparent;
|
|
191
|
+
border: 1px solid var(--flx-ui-color-border-strong);
|
|
192
|
+
border-radius: 4px;
|
|
193
|
+
}
|
|
194
|
+
[data-ui='material'] :where([data-field-variant='outlined']:focus, [data-field-variant='outlined']:focus-visible, [data-field-variant='outlined']:focus-within) {
|
|
195
|
+
border: 2px solid var(--flx-ui-color-primary);
|
|
196
|
+
box-shadow: none;
|
|
197
|
+
outline: none;
|
|
198
|
+
}
|
|
199
|
+
/* The combobox's inner input must stay bare — the wrapper carries the field. */
|
|
200
|
+
[data-ui='material'] :where([data-combobox-control] [role='combobox']) {
|
|
201
|
+
background: transparent;
|
|
202
|
+
border: none;
|
|
203
|
+
}
|
|
161
204
|
|
|
162
205
|
/* ---- Menus & lists: full-bleed M3 rows, roomier padding ------------------- */
|
|
163
206
|
[data-ui='material'] :where([role='menuitem'], [role='option']) {
|
|
@@ -180,15 +223,331 @@
|
|
|
180
223
|
border-radius: 4px;
|
|
181
224
|
}
|
|
182
225
|
|
|
226
|
+
/* ---- Drawer (M3 side sheet): round the trailing (interior) edge only, keep
|
|
227
|
+
the screen-edge corners flush; M3 elevation instead of the heavy default. -- */
|
|
228
|
+
[data-ui='material'] :where([data-drawer-content]) {
|
|
229
|
+
box-shadow: var(--flx-ui-shadow-lg);
|
|
230
|
+
}
|
|
231
|
+
[data-ui='material'] :where([data-drawer-content][data-side='left']) {
|
|
232
|
+
border-radius: 0 16px 16px 0;
|
|
233
|
+
}
|
|
234
|
+
[data-ui='material'] :where([data-drawer-content][data-side='right']) {
|
|
235
|
+
border-radius: 16px 0 0 16px;
|
|
236
|
+
}
|
|
237
|
+
[data-ui='material'] :where([data-drawer-content][data-side='top']) {
|
|
238
|
+
border-radius: 0 0 16px 16px;
|
|
239
|
+
}
|
|
240
|
+
[data-ui='material'] :where([data-drawer-content][data-side='bottom']) {
|
|
241
|
+
border-radius: 16px 16px 0 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* ---- Bottom sheet (M3): 28dp top corners, M3 elevation, and the standard
|
|
245
|
+
32×4dp on-surface-variant drag handle. --------------------------------- */
|
|
246
|
+
[data-ui='material'] :where([data-bottom-sheet-content]) {
|
|
247
|
+
border-radius: 28px 28px 0 0;
|
|
248
|
+
box-shadow: var(--flx-ui-shadow-lg);
|
|
249
|
+
}
|
|
250
|
+
[data-ui='material'] :where([data-bottom-sheet-handle])::before {
|
|
251
|
+
width: 32px;
|
|
252
|
+
height: 4px;
|
|
253
|
+
border-radius: 9999px;
|
|
254
|
+
background: var(--flx-ui-color-fg-muted);
|
|
255
|
+
opacity: 0.4;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* ---- Surface & Card: M3 elevation (softer than the raw shadow tokens, which
|
|
259
|
+
are tuned for pop-overs; on a plain container they read too heavy) ------- */
|
|
260
|
+
[data-ui='material'] :where([data-surface]) {
|
|
261
|
+
border-radius: 12px;
|
|
262
|
+
}
|
|
263
|
+
[data-ui='material'] :where([data-surface][data-elevation='0']) {
|
|
264
|
+
box-shadow: none;
|
|
265
|
+
}
|
|
266
|
+
[data-ui='material'] :where([data-surface][data-elevation='1']),
|
|
267
|
+
[data-ui='material'] :where([data-card]) {
|
|
268
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.14), 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
269
|
+
}
|
|
270
|
+
[data-ui='material'] :where([data-surface][data-elevation='2']) {
|
|
271
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.13), 0 2px 6px rgba(0, 0, 0, 0.1);
|
|
272
|
+
}
|
|
273
|
+
[data-ui='material'] :where([data-surface][data-elevation='3']) {
|
|
274
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14), 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
275
|
+
}
|
|
276
|
+
[data-ui='material'] :where([data-surface][data-elevation='4']) {
|
|
277
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.14), 0 6px 12px rgba(0, 0, 0, 0.1);
|
|
278
|
+
}
|
|
279
|
+
[data-ui='material'] :where([data-card]) {
|
|
280
|
+
border-radius: 12px;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/* ---- Calendar: M3 date grid — circular days, outlined "today", state-layer
|
|
284
|
+
nav, and a tonal band across a selected range. ------------------------- */
|
|
285
|
+
[data-ui='material'] :where([data-calendar-day]) {
|
|
286
|
+
border-radius: 9999px;
|
|
287
|
+
font-weight: 500;
|
|
288
|
+
}
|
|
289
|
+
[data-ui='material'] :where([data-calendar-day]:hover:not([data-disabled]):not([data-selected])) {
|
|
290
|
+
background: color-mix(in oklab, var(--flx-ui-color-primary) 10%, transparent);
|
|
291
|
+
color: inherit;
|
|
292
|
+
}
|
|
293
|
+
[data-ui='material'] :where([data-calendar-day][data-today]:not([data-selected])) {
|
|
294
|
+
border: 1px solid var(--flx-ui-color-primary);
|
|
295
|
+
color: var(--flx-ui-color-primary);
|
|
296
|
+
}
|
|
297
|
+
[data-ui='material'] :where([data-calendar-nav]) {
|
|
298
|
+
border: none;
|
|
299
|
+
border-radius: 9999px;
|
|
300
|
+
}
|
|
301
|
+
[data-ui='material'] :where([data-calendar-nav]:hover:not([disabled])) {
|
|
302
|
+
background: color-mix(in oklab, currentColor 8%, transparent);
|
|
303
|
+
}
|
|
304
|
+
/* Range: circular ends, a flat secondary-container band through the middle. */
|
|
305
|
+
[data-ui='material'] :where([data-range] [data-calendar-day][data-selected]) {
|
|
306
|
+
border-radius: 0;
|
|
307
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
308
|
+
color: var(--flx-ui-color-primary-active);
|
|
309
|
+
}
|
|
310
|
+
[data-ui='material'] :where([data-range] [data-calendar-day][data-selection-start]) {
|
|
311
|
+
border-radius: 9999px 0 0 9999px;
|
|
312
|
+
}
|
|
313
|
+
[data-ui='material'] :where([data-range] [data-calendar-day][data-selection-end]) {
|
|
314
|
+
border-radius: 0 9999px 9999px 0;
|
|
315
|
+
}
|
|
316
|
+
[data-ui='material'] :where([data-range] [data-calendar-day][data-selection-start][data-selection-end]) {
|
|
317
|
+
border-radius: 9999px;
|
|
318
|
+
}
|
|
319
|
+
[data-ui='material'] :where([data-calendar-day][data-selection-start], [data-calendar-day][data-selection-end]) {
|
|
320
|
+
background: var(--flx-ui-color-primary);
|
|
321
|
+
color: var(--flx-ui-color-primary-fg);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* ---- Date field & date picker: filled segmented control + M3 date-picker
|
|
325
|
+
surface, matching the filled text-field language above. ---------------- */
|
|
326
|
+
/* The field frame carries the filled fill + underline; the segment input nested
|
|
327
|
+
inside the picker control stays transparent so the underline isn't doubled. */
|
|
328
|
+
[data-ui='material'] :where([data-date-field-input], [data-date-picker-control]) {
|
|
329
|
+
background: var(--flx-ui-color-bg-muted);
|
|
330
|
+
border: none;
|
|
331
|
+
border-bottom: 1px solid var(--flx-ui-color-border-strong);
|
|
332
|
+
border-radius: 4px 4px 0 0;
|
|
333
|
+
}
|
|
334
|
+
[data-ui='material'] :where([data-date-field-input]:focus-within, [data-date-picker-control]:focus-within) {
|
|
335
|
+
border-bottom: 2px solid var(--flx-ui-color-primary);
|
|
336
|
+
box-shadow: none;
|
|
337
|
+
outline: none;
|
|
338
|
+
}
|
|
339
|
+
[data-ui='material'] :where([data-date-picker-input]) {
|
|
340
|
+
background: transparent;
|
|
341
|
+
border: none;
|
|
342
|
+
}
|
|
343
|
+
[data-ui='material'] :where([data-date-picker-content]) {
|
|
344
|
+
border-radius: 16px;
|
|
345
|
+
box-shadow: 0 4px 8px 3px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/* ---- Accordion: flat M3 list — no outer frame, dividers between items, a
|
|
349
|
+
state-layer on the header rather than a filled hover. ------------------ */
|
|
350
|
+
[data-ui='material'] :where([data-accordion]) {
|
|
351
|
+
border: none;
|
|
352
|
+
border-radius: 0;
|
|
353
|
+
}
|
|
354
|
+
[data-ui='material'] :where([data-accordion-item]:not(:last-child)) {
|
|
355
|
+
border-bottom: 1px solid var(--flx-ui-color-border);
|
|
356
|
+
}
|
|
357
|
+
[data-ui='material'] :where([data-accordion-trigger]) {
|
|
358
|
+
padding: 16px var(--flx-ui-space-4);
|
|
359
|
+
font-weight: 500;
|
|
360
|
+
}
|
|
361
|
+
[data-ui='material'] :where([data-accordion-trigger]:hover:not([data-disabled])) {
|
|
362
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 6%, transparent);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* ---- Radio: M3 20px target ---------------------------------------------- */
|
|
366
|
+
[data-ui='material'] :where([role='radio']) {
|
|
367
|
+
width: 20px;
|
|
368
|
+
height: 20px;
|
|
369
|
+
border-width: 2px;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* ---- Toggle / segmented button: selected = secondary-container ----------- */
|
|
373
|
+
[data-ui='material'] :where([aria-pressed][data-state='on']) {
|
|
374
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
375
|
+
border-color: transparent;
|
|
376
|
+
color: var(--flx-ui-color-primary-active);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/* ---- Number field: filled control row to match the text fields ---------- */
|
|
380
|
+
[data-ui='material'] :where([data-number-field-input-row]) {
|
|
381
|
+
background: var(--flx-ui-color-bg-muted);
|
|
382
|
+
border: none;
|
|
383
|
+
border-bottom: 1px solid var(--flx-ui-color-border-strong);
|
|
384
|
+
border-radius: 4px 4px 0 0;
|
|
385
|
+
}
|
|
386
|
+
[data-ui='material'] :where([data-number-field-input-row]:focus-within) {
|
|
387
|
+
border-bottom: 2px solid var(--flx-ui-color-primary);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/* ---- Linear progress: 4dp fully-rounded track, tonal remainder ---------- */
|
|
391
|
+
[data-ui='material'] :where([role='progressbar']:not([data-circular])) {
|
|
392
|
+
height: 4px;
|
|
393
|
+
border-radius: 9999px;
|
|
394
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/* ---- Sidenav: M3 navigation drawer — full-pill items, state-layer hover,
|
|
398
|
+
secondary-container active, elevated menu flyout. --------------------- */
|
|
399
|
+
[data-ui='material'] :where([data-sidenav-link], [data-sidenav-sub-trigger]) {
|
|
400
|
+
border-radius: 9999px;
|
|
401
|
+
font-weight: 500;
|
|
402
|
+
}
|
|
403
|
+
[data-ui='material'] :where([data-sidenav-link]:hover:not([data-active]),
|
|
404
|
+
[data-sidenav-sub-trigger]:hover:not([data-active])) {
|
|
405
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 8%, transparent);
|
|
406
|
+
color: inherit;
|
|
407
|
+
}
|
|
408
|
+
[data-ui='material'] :where([data-sidenav-link][data-active],
|
|
409
|
+
[data-sidenav-sub-trigger][data-active]) {
|
|
410
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
411
|
+
color: var(--flx-ui-color-primary-active);
|
|
412
|
+
font-weight: 600;
|
|
413
|
+
}
|
|
414
|
+
[data-ui='material'] :where([data-sidenav-trigger]) {
|
|
415
|
+
border-radius: 9999px;
|
|
416
|
+
}
|
|
417
|
+
/* Flyout: an elevated M3 menu surface; its rows keep the pill treatment. */
|
|
418
|
+
[data-ui='material'] :where([data-sidenav-sub-content][data-flyout]) {
|
|
419
|
+
border-radius: 12px;
|
|
420
|
+
box-shadow: var(--flx-ui-shadow-lg);
|
|
421
|
+
padding: var(--flx-ui-space-2);
|
|
422
|
+
}
|
|
423
|
+
[data-ui='material'] :where([data-sidenav][data-mobile]) {
|
|
424
|
+
border-radius: 0 16px 16px 0;
|
|
425
|
+
}
|
|
426
|
+
[data-ui='material'] :where([data-sidenav][data-mobile][data-side='right']) {
|
|
427
|
+
border-radius: 16px 0 0 16px;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/* ---- Pagination: circular pages, filled current ------------------------- */
|
|
431
|
+
[data-ui='material'] :where([data-pagination-page], [data-pagination-prev], [data-pagination-next]) {
|
|
432
|
+
border-radius: 9999px;
|
|
433
|
+
}
|
|
434
|
+
[data-ui='material'] :where([data-pagination-page]:hover:not([data-current])) {
|
|
435
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 8%, transparent);
|
|
436
|
+
}
|
|
437
|
+
[data-ui='material'] :where([data-pagination-page][data-current]) {
|
|
438
|
+
background: var(--flx-ui-color-primary);
|
|
439
|
+
color: var(--flx-ui-color-primary-fg);
|
|
440
|
+
border-color: transparent;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/* ---- Stepper: circular numbered indicators ------------------------------ */
|
|
444
|
+
[data-ui='material'] :where([data-stepper-indicator]) {
|
|
445
|
+
border-radius: 9999px;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/* ---- Breadcrumb: state-layer link affordance ---------------------------- */
|
|
449
|
+
/* Padded pill targets so the state-layer has room to breathe (M3). */
|
|
450
|
+
[data-ui='material'] :where([data-breadcrumb-link]) {
|
|
451
|
+
padding: 2px 8px;
|
|
452
|
+
margin: 0 -2px;
|
|
453
|
+
border-radius: 999px;
|
|
454
|
+
}
|
|
455
|
+
[data-ui='material'] :where([data-breadcrumb-link]:hover) {
|
|
456
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 8%, transparent);
|
|
457
|
+
color: var(--flx-ui-color-fg);
|
|
458
|
+
}
|
|
459
|
+
[data-ui='material'] :where([data-breadcrumb-page]) {
|
|
460
|
+
padding: 2px 8px;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* ---- Toolbar: M3 surface + pill state-layer buttons ---------------------- */
|
|
464
|
+
[data-ui='material'] :where([role='toolbar']) {
|
|
465
|
+
border-radius: 8px;
|
|
466
|
+
gap: 2px;
|
|
467
|
+
}
|
|
468
|
+
[data-ui='material'] :where([role='toolbar'] > button:not([aria-pressed])) {
|
|
469
|
+
border-radius: 999px;
|
|
470
|
+
}
|
|
471
|
+
[data-ui='material'] :where([role='toolbar'] > button:not([aria-pressed]):hover) {
|
|
472
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 8%, transparent);
|
|
473
|
+
color: var(--flx-ui-color-fg);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* ---- Navigation menu & menubar: state-layer triggers, rounded ----------- */
|
|
477
|
+
[data-ui='material'] :where([data-navigation-menu-trigger]:hover),
|
|
478
|
+
[data-ui='material'] :where([role='menubar'] > [role='menuitem']:hover) {
|
|
479
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 8%, transparent);
|
|
480
|
+
border-radius: 8px;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/* ---- Command & menu rows: M3 state layer over the flat rows -------------- */
|
|
484
|
+
[data-ui='material'] :where([data-command-item][data-active]) {
|
|
485
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 8%, transparent);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/* ---- Table: flat M3 data table — no frame, divider-only rows, sentence-case
|
|
489
|
+
header (no all-caps), state-layer hover/selection, comfortable density -- */
|
|
490
|
+
[data-ui='material'] :where([data-table]) {
|
|
491
|
+
border: none;
|
|
492
|
+
border-radius: 0;
|
|
493
|
+
}
|
|
494
|
+
[data-ui='material'] :where([data-table-head]) {
|
|
495
|
+
background: transparent;
|
|
496
|
+
color: var(--flx-ui-color-fg-muted);
|
|
497
|
+
font-size: var(--flx-ui-font-size-sm);
|
|
498
|
+
font-weight: 500;
|
|
499
|
+
letter-spacing: normal;
|
|
500
|
+
text-transform: none;
|
|
501
|
+
padding: var(--flx-ui-space-3);
|
|
502
|
+
border-bottom: var(--flx-ui-border-width-thin) solid var(--flx-ui-color-border);
|
|
503
|
+
}
|
|
504
|
+
[data-ui='material'] :where([data-table-cell]) {
|
|
505
|
+
padding: var(--flx-ui-space-3);
|
|
506
|
+
}
|
|
507
|
+
[data-ui='material'] :where([data-table-body] > [data-table-row]:hover) {
|
|
508
|
+
background: color-mix(in oklab, var(--flx-ui-color-fg) 5%, transparent);
|
|
509
|
+
}
|
|
510
|
+
[data-ui='material'] :where([data-table-row][data-selected]),
|
|
511
|
+
[data-ui='material'] :where([data-table-row][data-selected]:hover) {
|
|
512
|
+
background: color-mix(in oklab, var(--flx-ui-color-primary) 10%, transparent);
|
|
513
|
+
}
|
|
514
|
+
/* Header is transparent now, so pinned cells need an opaque surface fill. */
|
|
515
|
+
[data-ui='material'] :where([data-table-cell][data-pinned]),
|
|
516
|
+
[data-ui='material'] :where([data-table-head][data-pinned]) {
|
|
517
|
+
background: var(--flx-ui-color-bg);
|
|
518
|
+
}
|
|
519
|
+
/* Compact density under Material. */
|
|
520
|
+
[data-ui='material'] :where([data-table][data-density='compact'] [data-table-head]),
|
|
521
|
+
[data-ui='material'] :where([data-table][data-density='compact'] [data-table-cell]) {
|
|
522
|
+
padding: var(--flx-ui-space-1) var(--flx-ui-space-2);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/* ---- Toast: M3 snackbar shape + elevation (keeps the type accent) -------- */
|
|
526
|
+
[data-ui='material'] :where([data-toast]) {
|
|
527
|
+
border-radius: 4px;
|
|
528
|
+
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2), 0 1px 18px rgba(0, 0, 0, 0.12);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/* ---- Alert: M3 medium radius ------------------------------------------- */
|
|
532
|
+
[data-ui='material'] :where([data-alert]) {
|
|
533
|
+
border-radius: 12px;
|
|
534
|
+
}
|
|
535
|
+
|
|
183
536
|
/* ---- Click-origin ripple (installed by the ripple primitive) ------------- */
|
|
184
|
-
[data-ui='material'] :where([data-variant], [role='menuitem'], [role='option'], [role='tab']) {
|
|
537
|
+
[data-ui='material'] :where([data-variant]:not([data-badge]), [role='menuitem'], [role='option'], [role='tab']) {
|
|
185
538
|
position: relative;
|
|
186
539
|
overflow: hidden;
|
|
187
540
|
}
|
|
541
|
+
/* A glow button draws its ring on ::after at the border edge; the ripple's
|
|
542
|
+
overflow:hidden would clip it, so let a glow button overflow. */
|
|
543
|
+
[data-ui='material'] :where([data-variant]:not([data-badge])[data-glow]) {
|
|
544
|
+
overflow: visible;
|
|
545
|
+
}
|
|
188
546
|
[data-ui='material'] .flx-mat-ripple {
|
|
189
547
|
position: absolute;
|
|
190
548
|
border-radius: 50%;
|
|
191
|
-
|
|
549
|
+
/* Overridable per-control via --flx-mat-ripple-color; defaults to the ink. */
|
|
550
|
+
background: var(--flx-mat-ripple-color, currentColor);
|
|
192
551
|
opacity: 0;
|
|
193
552
|
transform: scale(0);
|
|
194
553
|
pointer-events: none;
|
|
@@ -210,4 +569,333 @@
|
|
|
210
569
|
opacity: 0;
|
|
211
570
|
}
|
|
212
571
|
}
|
|
572
|
+
|
|
573
|
+
/* ---- Progress: M3 linear (4px, tonal track) ------------------------------- */
|
|
574
|
+
[data-ui='material'] :where([role='progressbar']:not([data-circular])) {
|
|
575
|
+
height: 4px;
|
|
576
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
577
|
+
}
|
|
578
|
+
[data-ui='material'] :where([role='progressbar']:not([data-circular]))::after {
|
|
579
|
+
background: var(--flx-ui-color-primary);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/* ---- Slider: M3 (thin tonal track, filled active range) ------------------- */
|
|
583
|
+
[data-ui='material'] :where([data-slider-track]) {
|
|
584
|
+
height: 4px;
|
|
585
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
586
|
+
}
|
|
587
|
+
[data-ui='material'] :where([data-slider-range]) {
|
|
588
|
+
background: var(--flx-ui-color-primary);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/* ---- Badge: M3 label (medium weight, subtle tracking) --------------------- */
|
|
592
|
+
[data-ui='material'] :where([data-badge]) {
|
|
593
|
+
font-weight: var(--flx-ui-font-weight-medium);
|
|
594
|
+
letter-spacing: 0.02em;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/* ---- Avatar: M3 rounded-square option stays circular; add tonal ring ------ */
|
|
598
|
+
[data-ui='material'] :where([data-avatar]) {
|
|
599
|
+
font-weight: var(--flx-ui-font-weight-medium);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/* ---- Statistic: M3 display number (tighter tracking) ---------------------- */
|
|
603
|
+
[data-ui='material'] :where([data-statistic-value]) {
|
|
604
|
+
font-weight: var(--flx-ui-font-weight-semibold);
|
|
605
|
+
letter-spacing: -0.01em;
|
|
606
|
+
}
|
|
607
|
+
[data-ui='material'] :where([data-statistic-label]) {
|
|
608
|
+
letter-spacing: 0.06em;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/* ---- Empty: M3 icon tile (rounded-large, tonal) --------------------------- */
|
|
612
|
+
[data-ui='material'] :where([data-empty-icon]) {
|
|
613
|
+
width: 48px;
|
|
614
|
+
height: 48px;
|
|
615
|
+
border-radius: 16px;
|
|
616
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
617
|
+
color: var(--flx-ui-color-primary);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/* ---- Timeline: M3 dot state-layer ---------------------------------------- */
|
|
621
|
+
[data-ui='material'] :where([data-timeline-indicator]:empty)::before {
|
|
622
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--flx-timeline-dot) 14%, transparent);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/* ---- Descriptions: M3 term (medium, tracked) ------------------------------ */
|
|
626
|
+
[data-ui='material'] :where([data-descriptions-term]) {
|
|
627
|
+
font-weight: var(--flx-ui-font-weight-medium);
|
|
628
|
+
letter-spacing: 0.04em;
|
|
629
|
+
text-transform: uppercase;
|
|
630
|
+
font-size: var(--flx-ui-font-size-2xs, 11px);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/* ---- Switch: Material (thin track, prominent thumb, ripple state-layer) ---- */
|
|
634
|
+
[data-ui='material'] :where([role='switch']) {
|
|
635
|
+
width: 34px;
|
|
636
|
+
height: 14px;
|
|
637
|
+
padding: 0;
|
|
638
|
+
border: none;
|
|
639
|
+
overflow: visible;
|
|
640
|
+
position: relative;
|
|
641
|
+
border-radius: 999px;
|
|
642
|
+
background: color-mix(in srgb, var(--flx-ui-color-fg) 26%, transparent);
|
|
643
|
+
}
|
|
644
|
+
[data-ui='material'] :where([role='switch'][data-state='checked']) {
|
|
645
|
+
background: color-mix(in srgb, var(--flx-ui-color-primary) 50%, transparent);
|
|
646
|
+
filter: none;
|
|
647
|
+
}
|
|
648
|
+
[data-ui='material'] :where([role='switch']:hover:not([data-disabled])) {
|
|
649
|
+
filter: none;
|
|
650
|
+
}
|
|
651
|
+
/* Thumb — 20px circle, larger than the 14px track so it overlaps it. */
|
|
652
|
+
[data-ui='material'] :where([role='switch'])::after {
|
|
653
|
+
content: '';
|
|
654
|
+
position: absolute;
|
|
655
|
+
top: 50%;
|
|
656
|
+
left: 0;
|
|
657
|
+
width: 20px;
|
|
658
|
+
height: 20px;
|
|
659
|
+
margin: 0;
|
|
660
|
+
border-radius: 50%;
|
|
661
|
+
background: #fff;
|
|
662
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
|
663
|
+
transform: translate(-2px, -50%);
|
|
664
|
+
transition:
|
|
665
|
+
transform var(--flx-ui-duration-normal) var(--flx-ui-ease-emphasized),
|
|
666
|
+
background var(--flx-ui-duration-fast) var(--flx-ui-ease-standard);
|
|
667
|
+
}
|
|
668
|
+
[data-ui='material'] :where([role='switch'][data-state='checked'])::after {
|
|
669
|
+
background: var(--flx-ui-color-primary);
|
|
670
|
+
transform: translate(16px, -50%);
|
|
671
|
+
}
|
|
672
|
+
/* Ripple / state-layer — a translucent disc behind the thumb, following it. */
|
|
673
|
+
[data-ui='material'] :where([role='switch'])::before {
|
|
674
|
+
content: '';
|
|
675
|
+
position: absolute;
|
|
676
|
+
top: 50%;
|
|
677
|
+
left: 0;
|
|
678
|
+
width: 40px;
|
|
679
|
+
height: 40px;
|
|
680
|
+
border-radius: 50%;
|
|
681
|
+
background: var(--flx-ui-color-fg);
|
|
682
|
+
opacity: 0;
|
|
683
|
+
pointer-events: none;
|
|
684
|
+
transform: translate(-12px, -50%) scale(0.7);
|
|
685
|
+
transition:
|
|
686
|
+
opacity var(--flx-ui-duration-fast) var(--flx-ui-ease-standard),
|
|
687
|
+
transform var(--flx-ui-duration-normal) var(--flx-ui-ease-emphasized);
|
|
688
|
+
}
|
|
689
|
+
[data-ui='material'] :where([role='switch'][data-state='checked'])::before {
|
|
690
|
+
background: var(--flx-ui-color-primary);
|
|
691
|
+
transform: translate(6px, -50%) scale(0.7);
|
|
692
|
+
}
|
|
693
|
+
[data-ui='material'] :where([role='switch']:hover:not([data-disabled]))::before {
|
|
694
|
+
opacity: 0.09;
|
|
695
|
+
transform: translate(-12px, -50%) scale(1);
|
|
696
|
+
}
|
|
697
|
+
[data-ui='material'] :where([role='switch'][data-state='checked']:hover:not([data-disabled]))::before {
|
|
698
|
+
transform: translate(6px, -50%) scale(1);
|
|
699
|
+
}
|
|
700
|
+
[data-ui='material'] :where([role='switch']:active:not([data-disabled]))::before {
|
|
701
|
+
opacity: 0.18;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/* ---- Slider thumb: Material filled handle + ripple state-layer ------------- */
|
|
705
|
+
[data-ui='material'] :where([data-slider] [role='slider']) {
|
|
706
|
+
background: var(--flx-ui-color-primary);
|
|
707
|
+
border-color: var(--flx-ui-color-primary);
|
|
708
|
+
}
|
|
709
|
+
[data-ui='material'] :where([data-slider] [role='slider'])::before {
|
|
710
|
+
content: '';
|
|
711
|
+
position: absolute;
|
|
712
|
+
top: 50%;
|
|
713
|
+
left: 50%;
|
|
714
|
+
width: 40px;
|
|
715
|
+
height: 40px;
|
|
716
|
+
border-radius: 50%;
|
|
717
|
+
background: var(--flx-ui-color-primary);
|
|
718
|
+
opacity: 0;
|
|
719
|
+
pointer-events: none;
|
|
720
|
+
transform: translate(-50%, -50%) scale(0.4);
|
|
721
|
+
transition:
|
|
722
|
+
opacity var(--flx-ui-duration-fast) var(--flx-ui-ease-standard),
|
|
723
|
+
transform var(--flx-ui-duration-normal) var(--flx-ui-ease-emphasized);
|
|
724
|
+
}
|
|
725
|
+
[data-ui='material'] :where([data-slider] [role='slider']:hover:not([data-disabled]))::before {
|
|
726
|
+
opacity: 0.12;
|
|
727
|
+
transform: translate(-50%, -50%) scale(1);
|
|
728
|
+
}
|
|
729
|
+
[data-ui='material'] :where([data-slider] [role='slider']:active)::before,
|
|
730
|
+
[data-ui='material'] :where([data-slider] [role='slider']:focus-visible)::before {
|
|
731
|
+
opacity: 0.2;
|
|
732
|
+
transform: translate(-50%, -50%) scale(1);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/* ---- Popup surfaces: one consistent M3 shape (small radius, tight elevation)
|
|
736
|
+
* Unifies every floating surface — menus, listboxes, datepicker, command,
|
|
737
|
+
* hovercard, nav-menu — which previously ranged from radius-md (12px) to
|
|
738
|
+
* radius-lg (16px) with a heavy shadow-lg. Tooltip already matches at 4px. */
|
|
739
|
+
[data-ui='material'] :where(
|
|
740
|
+
[role='menu'],
|
|
741
|
+
[role='listbox'],
|
|
742
|
+
[data-date-picker-content],
|
|
743
|
+
[data-navigation-menu-content],
|
|
744
|
+
[data-command],
|
|
745
|
+
[data-hovercard-content]
|
|
746
|
+
) {
|
|
747
|
+
border-radius: 4px;
|
|
748
|
+
box-shadow:
|
|
749
|
+
0 2px 6px rgba(0, 0, 0, 0.16),
|
|
750
|
+
0 1px 3px rgba(0, 0, 0, 0.1);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/* ---- Checkbox & radio: M3 state-layer ripple -------------------------------
|
|
754
|
+
* The ripple lives on ::before at z-index:-1 so it paints ABOVE the control's
|
|
755
|
+
* background but BELOW its content (the base check/dot on ::after). This leaves
|
|
756
|
+
* the base marks completely untouched — do NOT restyle ::after here, the base
|
|
757
|
+
* check is a flex-centred rotated border and the radio dot is position:absolute;
|
|
758
|
+
* inset:3px, both of which break if position/box-sizing is overridden. */
|
|
759
|
+
[data-ui='material'] :where([role='checkbox']),
|
|
760
|
+
[data-ui='material'] :where([role='radio']) {
|
|
761
|
+
position: relative;
|
|
762
|
+
overflow: visible;
|
|
763
|
+
}
|
|
764
|
+
[data-ui='material'] :where([role='checkbox'])::before,
|
|
765
|
+
[data-ui='material'] :where([role='radio'])::before {
|
|
766
|
+
content: '';
|
|
767
|
+
position: absolute;
|
|
768
|
+
z-index: -1;
|
|
769
|
+
top: 50%;
|
|
770
|
+
left: 50%;
|
|
771
|
+
width: 40px;
|
|
772
|
+
height: 40px;
|
|
773
|
+
border-radius: 50%;
|
|
774
|
+
background: var(--flx-ui-color-primary);
|
|
775
|
+
opacity: 0;
|
|
776
|
+
pointer-events: none;
|
|
777
|
+
transform: translate(-50%, -50%) scale(0.5);
|
|
778
|
+
transition:
|
|
779
|
+
opacity var(--flx-ui-duration-fast) var(--flx-ui-ease-standard),
|
|
780
|
+
transform var(--flx-ui-duration-normal) var(--flx-ui-ease-emphasized);
|
|
781
|
+
}
|
|
782
|
+
[data-ui='material'] :where([role='checkbox']:hover:not([data-disabled]))::before,
|
|
783
|
+
[data-ui='material'] :where([role='radio']:hover:not([data-disabled]))::before {
|
|
784
|
+
opacity: 0.1;
|
|
785
|
+
transform: translate(-50%, -50%) scale(1);
|
|
786
|
+
}
|
|
787
|
+
[data-ui='material'] :where([role='checkbox']:active:not([data-disabled]))::before,
|
|
788
|
+
[data-ui='material'] :where([role='radio']:active:not([data-disabled]))::before,
|
|
789
|
+
[data-ui='material'] :where([role='checkbox']:focus-visible)::before,
|
|
790
|
+
[data-ui='material'] :where([role='radio']:focus-visible)::before {
|
|
791
|
+
opacity: 0.18;
|
|
792
|
+
transform: translate(-50%, -50%) scale(1);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/* ---- Circular progress: 4dp tonal track, round cap (matches linear) ------ */
|
|
796
|
+
[data-ui='material'] :where([data-progress-track]) {
|
|
797
|
+
stroke: var(--flx-ui-color-primary-subtle);
|
|
798
|
+
}
|
|
799
|
+
[data-ui='material'] :where([data-progress-indicator]) {
|
|
800
|
+
stroke-linecap: round;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/* ---- Avatar group: tonal secondary-container overflow chip --------------- */
|
|
804
|
+
[data-ui='material'] :where([data-avatar-group-overflow]) {
|
|
805
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
806
|
+
color: var(--flx-ui-color-primary-active);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/* ---- Rating: filled primary stars, roomier M3 spacing ------------------- */
|
|
810
|
+
[data-ui='material'] :where([data-rating]) {
|
|
811
|
+
--flx-ui-rating-gap: 4px;
|
|
812
|
+
--flx-ui-rating-color: var(--flx-ui-color-primary);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/* ---- PIN input: M3 filled cells with the shared underline treatment ------ */
|
|
816
|
+
[data-ui='material'] :where([data-pin-input-field]) {
|
|
817
|
+
background: var(--flx-ui-color-bg-muted);
|
|
818
|
+
border: none;
|
|
819
|
+
border-bottom: 1px solid var(--flx-ui-color-border-strong);
|
|
820
|
+
border-radius: 4px 4px 0 0;
|
|
821
|
+
}
|
|
822
|
+
[data-ui='material'] :where([data-pin-input-field]:focus, [data-pin-input-field]:focus-visible) {
|
|
823
|
+
border-bottom: 2px solid var(--flx-ui-color-primary);
|
|
824
|
+
box-shadow: none;
|
|
825
|
+
outline: none;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/* ---- Icon button: M3 round, size-aware (overrides the fixed 40px pill) ---- */
|
|
829
|
+
[data-ui='material'] :where([data-icon-button]) {
|
|
830
|
+
padding: 0;
|
|
831
|
+
width: var(--flx-ui-size-md);
|
|
832
|
+
height: var(--flx-ui-size-md);
|
|
833
|
+
border-radius: 9999px;
|
|
834
|
+
}
|
|
835
|
+
[data-ui='material'] :where([data-icon-button][data-size='sm']) {
|
|
836
|
+
width: var(--flx-ui-size-sm);
|
|
837
|
+
height: var(--flx-ui-size-sm);
|
|
838
|
+
}
|
|
839
|
+
[data-ui='material'] :where([data-icon-button][data-size='lg']) {
|
|
840
|
+
width: var(--flx-ui-size-lg);
|
|
841
|
+
height: var(--flx-ui-size-lg);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/* ---- FAB: M3 primary-container, resting elevation, larger radius. Re-assert
|
|
845
|
+
the FAB geometry the fixed-40px button rule above would otherwise impose. */
|
|
846
|
+
[data-ui='material'] :where([data-fab]) {
|
|
847
|
+
width: 56px;
|
|
848
|
+
height: 56px;
|
|
849
|
+
padding: 0;
|
|
850
|
+
border-radius: 16px;
|
|
851
|
+
background: var(--flx-ui-color-primary-subtle);
|
|
852
|
+
color: var(--flx-ui-color-primary-active);
|
|
853
|
+
box-shadow: var(--flx-ui-shadow-md);
|
|
854
|
+
}
|
|
855
|
+
[data-ui='material'] :where([data-fab]:hover:not([data-disabled])) {
|
|
856
|
+
box-shadow: var(--flx-ui-shadow-lg);
|
|
857
|
+
}
|
|
858
|
+
[data-ui='material'] :where([data-fab][data-fab-size='sm']) { width: 40px; height: 40px; border-radius: 12px; }
|
|
859
|
+
[data-ui='material'] :where([data-fab][data-fab-size='lg']) { width: 64px; height: 64px; border-radius: 28px; }
|
|
860
|
+
[data-ui='material'] :where([data-fab][data-fab-extended]) {
|
|
861
|
+
width: auto;
|
|
862
|
+
height: 56px;
|
|
863
|
+
padding: 0 20px;
|
|
864
|
+
border-radius: 16px;
|
|
865
|
+
}
|
|
866
|
+
/* A solid-toned FAB keeps the primary fill instead of the tonal container. */
|
|
867
|
+
[data-ui='material'] :where([data-fab][data-variant='solid']) {
|
|
868
|
+
background: var(--flx-ui-color-primary);
|
|
869
|
+
color: var(--flx-ui-color-primary-fg);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/* ---- Speed dial: elevated action buttons -------------------------------- */
|
|
873
|
+
[data-ui='material'] :where([data-speed-dial-action]) {
|
|
874
|
+
box-shadow: var(--flx-ui-shadow-sm);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/* ---- Carousel: M3 expanding indicators + circular controls -------------- */
|
|
878
|
+
[data-ui='material'] :where([data-carousel-dot]) {
|
|
879
|
+
border-radius: var(--flx-ui-radius-full, 999px);
|
|
880
|
+
transition: width var(--flx-ui-duration-normal, 250ms) var(--flx-ui-ease-standard, ease),
|
|
881
|
+
background var(--flx-ui-duration-fast) var(--flx-ui-ease-standard);
|
|
882
|
+
}
|
|
883
|
+
/* Active indicator grows into a pill, à la M3 carousels. */
|
|
884
|
+
[data-ui='material'] :where([data-carousel-dot][data-active]) {
|
|
885
|
+
width: 24px;
|
|
886
|
+
background: var(--flx-ui-color-primary);
|
|
887
|
+
}
|
|
888
|
+
[data-ui='material'] :where([data-carousel-prev], [data-carousel-next]) {
|
|
889
|
+
display: inline-grid;
|
|
890
|
+
place-items: center;
|
|
891
|
+
inline-size: 40px;
|
|
892
|
+
block-size: 40px;
|
|
893
|
+
border: 0;
|
|
894
|
+
border-radius: var(--flx-ui-radius-full, 999px);
|
|
895
|
+
background: var(--flx-ui-color-bg-muted);
|
|
896
|
+
color: var(--flx-ui-color-fg);
|
|
897
|
+
}
|
|
898
|
+
[data-ui='material'] :where([data-carousel-prev]:hover:not([disabled]), [data-carousel-next]:hover:not([disabled])) {
|
|
899
|
+
background: color-mix(in srgb, var(--flx-ui-color-fg) 8%, var(--flx-ui-color-bg-muted));
|
|
900
|
+
}
|
|
213
901
|
}
|
package/material.css.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const href = new URL('./material.css', import.meta.url).href;
|
|
2
|
+
if (typeof document !== 'undefined' && !document.querySelector(`link[data-flx-ui="${href}"]`)) {
|
|
3
|
+
const link = document.createElement('link');
|
|
4
|
+
link.rel = 'stylesheet';
|
|
5
|
+
link.href = href;
|
|
6
|
+
link.dataset.flxUi = href;
|
|
7
|
+
document.head.appendChild(link);
|
|
8
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluixi-ui/skin-material",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-alpha.10",
|
|
4
4
|
"description": "Material Design skin for Fluixi UI — activate with data-ui=\"material\"",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"dist",
|
|
22
22
|
"fonts",
|
|
23
23
|
"material.css",
|
|
24
|
+
"material.css.js",
|
|
24
25
|
"README.md",
|
|
25
26
|
"LICENSE"
|
|
26
27
|
],
|
|
@@ -34,6 +35,6 @@
|
|
|
34
35
|
}
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
|
-
"build": "tsc -p tsconfig.lib.json"
|
|
38
|
+
"build": "tsc -p tsconfig.lib.json && node ../../scripts/css-loaders.mjs material.css"
|
|
38
39
|
}
|
|
39
40
|
}
|