@sigx/zero-daisyui 0.2.0-beta.6 → 0.3.0-beta.1
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/README.md +78 -5
- package/dist/audit.json +271915 -0
- package/dist/components.d.ts +75 -18
- package/dist/components.js +15 -3
- package/dist/css/breakpoints.css +7 -0
- package/dist/css/components/avatar.css +12 -0
- package/dist/css/components/badge.css +130 -1
- package/dist/css/components/box.css +58 -0
- package/dist/css/components/button.css +17 -17
- package/dist/css/components/center.css +17 -0
- package/dist/css/components/checkbox.css +1 -1
- package/dist/css/components/combobox.css +57 -6
- package/dist/css/components/container.css +16 -0
- package/dist/css/components/countdown.css +5 -0
- package/dist/css/components/dialog.css +3 -2
- package/dist/css/components/drawer.css +102 -6
- package/dist/css/components/empty-state.css +164 -0
- package/dist/css/components/grid.css +32 -0
- package/dist/css/components/kbd.css +1 -1
- package/dist/css/components/menu.css +4 -4
- package/dist/css/components/nav-list.css +165 -0
- package/dist/css/components/radio-group.css +2 -2
- package/dist/css/components/select.css +1 -1
- package/dist/css/components/spacer.css +13 -0
- package/dist/css/components/stack.css +39 -0
- package/dist/css/components/steps.css +109 -28
- package/dist/css/components/table.css +276 -2
- package/dist/css/components/timeline.css +64 -1
- package/dist/css/components/tree-view.css +2 -2
- package/dist/css/index.css +2220 -279
- package/dist/css/index.d.ts +2 -0
- package/dist/css/tokens.css +9 -0
- package/dist/design-system.d.ts.map +1 -1
- package/dist/design-system.js +15 -8
- package/dist/design-system.js.map +1 -1
- package/dist/lynx/components/avatar.css +12 -0
- package/dist/lynx/components/badge.css +56 -1
- package/dist/lynx/components/box.css +54 -0
- package/dist/lynx/components/breadcrumbs.css +10 -10
- package/dist/lynx/components/button.css +15 -4
- package/dist/lynx/components/card.css +5 -5
- package/dist/lynx/components/center.css +13 -0
- package/dist/lynx/components/chat.css +10 -10
- package/dist/lynx/components/checkbox.css +1 -1
- package/dist/lynx/components/combobox.css +49 -6
- package/dist/lynx/components/container.css +11 -0
- package/dist/lynx/components/countdown.css +5 -0
- package/dist/lynx/components/dialog.css +8 -7
- package/dist/lynx/components/drawer.css +18 -0
- package/dist/lynx/components/empty-state.css +342 -0
- package/dist/lynx/components/file-upload.css +10 -10
- package/dist/lynx/components/grid.css +28 -0
- package/dist/lynx/components/kbd.css +1 -1
- package/dist/lynx/components/menu.css +4 -4
- package/dist/lynx/components/nav-list.css +302 -0
- package/dist/lynx/components/pagination.css +5 -5
- package/dist/lynx/components/radial-progress.css +5 -5
- package/dist/lynx/components/radio-group.css +2 -2
- package/dist/lynx/components/rating-group.css +5 -5
- package/dist/lynx/components/select.css +6 -6
- package/dist/lynx/components/spacer.css +11 -0
- package/dist/lynx/components/stack.css +35 -0
- package/dist/lynx/components/stats.css +10 -10
- package/dist/lynx/components/steps.css +99 -59
- package/dist/lynx/components/switch.css +5 -5
- package/dist/lynx/components/table.css +18 -12
- package/dist/lynx/components/tabs.css +5 -5
- package/dist/lynx/components/timeline.css +14 -5
- package/dist/lynx/components/tree-view.css +2 -2
- package/dist/lynx/index.css +1254 -345
- package/dist/lynx/manifest.json +354 -37
- package/dist/lynx/tokens.css +36 -0
- package/dist/manifest.json +351 -34
- package/dist/recipes.d.ts +17 -10
- package/dist/recipes.d.ts.map +1 -1
- package/dist/recipes.js +582 -173
- package/dist/recipes.js.map +1 -1
- package/dist/register.d.ts +89 -14
- package/dist/report.json +2476 -564
- package/dist/tokens.d.ts +22 -11
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +57 -7
- package/dist/tokens.js.map +1 -1
- package/package.json +28 -10
- package/src/design-system.ts +15 -8
- package/src/recipes.ts +594 -177
- package/src/tokens.ts +54 -7
- package/dist/css/components/native-select.css +0 -128
- package/dist/lynx/components/native-select.css +0 -130
package/dist/recipes.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { axisRoles, tableStackAt } from '@sigx/zero-kit/define';
|
|
2
|
+
import { roles, tokens } from './tokens.js';
|
|
2
3
|
/**
|
|
3
4
|
* Every role a consumer can pass as `color`, derived from the declaration
|
|
4
5
|
* rather than retyped — a role declared in `tokens.ts` but missing here would
|
|
@@ -6,9 +7,7 @@ import { roles } from './tokens.js';
|
|
|
6
7
|
* `-content` or `-soft` are fills or hairlines, not action colours; this
|
|
7
8
|
* design system declares none.
|
|
8
9
|
*/
|
|
9
|
-
const ROLES =
|
|
10
|
-
.filter(([, decl]) => decl.content !== false && decl.soft !== false)
|
|
11
|
-
.map(([name]) => name);
|
|
10
|
+
const ROLES = axisRoles(roles);
|
|
12
11
|
/**
|
|
13
12
|
* "…and the reading direction is right-to-left" — appended to a selector, never
|
|
14
13
|
* written alone.
|
|
@@ -506,6 +505,13 @@ const disclosureSizes = {
|
|
|
506
505
|
// daisy "collapse collapse-arrow" flavor.
|
|
507
506
|
export const collapsible = {
|
|
508
507
|
component: 'collapsible',
|
|
508
|
+
// Public to a design system derived from this one (#73).
|
|
509
|
+
hooks: {
|
|
510
|
+
properties: {
|
|
511
|
+
'--collapsible-accent': 'The accent of the open trigger.',
|
|
512
|
+
},
|
|
513
|
+
pseudo: { trigger: ['::after'] },
|
|
514
|
+
},
|
|
509
515
|
// The accent is the open heading's INK, so the default is base-content —
|
|
510
516
|
// the un-attributed render stays exactly daisy's neutral collapse and a
|
|
511
517
|
// role only arrives through `data-color`.
|
|
@@ -579,6 +585,14 @@ export const collapsible = {
|
|
|
579
585
|
// daisy "toggle" flavor.
|
|
580
586
|
export const switchRecipe = {
|
|
581
587
|
component: 'switch',
|
|
588
|
+
// Public to a design system derived from this one (#73).
|
|
589
|
+
hooks: {
|
|
590
|
+
properties: {
|
|
591
|
+
'--switch-size': 'The height; width, padding and knob travel derive from it.',
|
|
592
|
+
'--switch-accent': 'The checked track and knob accent.',
|
|
593
|
+
'--switch-ink': 'The unchecked border, knob and ring ink (daisy --input-color).',
|
|
594
|
+
},
|
|
595
|
+
},
|
|
582
596
|
/**
|
|
583
597
|
* daisy drives the whole toggle off ONE size, exactly as it drives the
|
|
584
598
|
* checkbox: `--size` is the height, the padding is a fixed eighth of it,
|
|
@@ -897,6 +911,10 @@ const lynxBtnSizes = (part) => ({
|
|
|
897
911
|
});
|
|
898
912
|
export const dialog = {
|
|
899
913
|
component: 'dialog',
|
|
914
|
+
// Public to a design system derived from this one (#73).
|
|
915
|
+
hooks: {
|
|
916
|
+
keyframes: ['zero-daisy-pop'],
|
|
917
|
+
},
|
|
900
918
|
keyframes: {
|
|
901
919
|
'zero-daisy-pop': 'from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); }',
|
|
902
920
|
},
|
|
@@ -913,7 +931,12 @@ export const dialog = {
|
|
|
913
931
|
},
|
|
914
932
|
popup: withPresence(popupPresence('translateY(8px) scale(0.97)'), {
|
|
915
933
|
base: {
|
|
916
|
-
|
|
934
|
+
// A <dialog> keeps the UA's `content-box`, and zero ships no
|
|
935
|
+
// reset — so a width or max-width meant to leave a gutter
|
|
936
|
+
// grew by the padding, and at phone width the popup ran past
|
|
937
|
+
// both edges (#101). Its box is the border box.
|
|
938
|
+
boxSizing: 'border-box',
|
|
939
|
+
padding: 'var(--space-2xl)',
|
|
917
940
|
maxWidth: '32rem',
|
|
918
941
|
width: 'calc(100% - 2rem)',
|
|
919
942
|
background: 'var(--color-base-100)',
|
|
@@ -943,14 +966,15 @@ export const dialog = {
|
|
|
943
966
|
},
|
|
944
967
|
// daisy's `modal-action`: the actions sit at the trailing edge, one
|
|
945
968
|
// step of the button gap apart, pushed down by the modal's own
|
|
946
|
-
// padding
|
|
947
|
-
//
|
|
969
|
+
// padding — daisy writes 1.5rem for both, and both now read the top
|
|
970
|
+
// of the ramp (`--space-2xl`, 1.25rem) so a density override moves
|
|
971
|
+
// the popup's inset and the footer's push-down together.
|
|
948
972
|
footer: {
|
|
949
973
|
base: {
|
|
950
974
|
display: 'flex',
|
|
951
975
|
justifyContent: 'flex-end',
|
|
952
976
|
gap: 'var(--space-md)',
|
|
953
|
-
marginBlockStart: '
|
|
977
|
+
marginBlockStart: 'var(--space-2xl)',
|
|
954
978
|
},
|
|
955
979
|
},
|
|
956
980
|
close: {
|
|
@@ -983,7 +1007,7 @@ export const dialog = {
|
|
|
983
1007
|
trigger: { base: lynxBtnPad(4) },
|
|
984
1008
|
close: { base: lynxBtnPad(4) },
|
|
985
1009
|
cancel: { base: lynxBtnPad(4) },
|
|
986
|
-
footer: { base: { marginTop: '
|
|
1010
|
+
footer: { base: { marginTop: 'var(--space-2xl)' } },
|
|
987
1011
|
},
|
|
988
1012
|
variants: { size: lynxBtnSizes('trigger') },
|
|
989
1013
|
},
|
|
@@ -1103,7 +1127,7 @@ export const menu = {
|
|
|
1103
1127
|
base: {
|
|
1104
1128
|
display: 'flex',
|
|
1105
1129
|
alignItems: 'center',
|
|
1106
|
-
gap: '
|
|
1130
|
+
gap: 'var(--space-md)',
|
|
1107
1131
|
padding: 'var(--space-md) var(--space-lg)',
|
|
1108
1132
|
fontSize: 'var(--text-sm)',
|
|
1109
1133
|
fontWeight: 'var(--weight-medium)',
|
|
@@ -1123,7 +1147,7 @@ export const menu = {
|
|
|
1123
1147
|
base: {
|
|
1124
1148
|
display: 'flex',
|
|
1125
1149
|
alignItems: 'center',
|
|
1126
|
-
gap: '
|
|
1150
|
+
gap: 'var(--space-md)',
|
|
1127
1151
|
padding: 'var(--space-md) var(--space-lg)',
|
|
1128
1152
|
fontSize: 'var(--text-sm)',
|
|
1129
1153
|
fontWeight: 'var(--weight-medium)',
|
|
@@ -1142,7 +1166,7 @@ export const menu = {
|
|
|
1142
1166
|
base: {
|
|
1143
1167
|
display: 'flex',
|
|
1144
1168
|
alignItems: 'center',
|
|
1145
|
-
gap: '
|
|
1169
|
+
gap: 'var(--space-md)',
|
|
1146
1170
|
padding: 'var(--space-md) var(--space-lg)',
|
|
1147
1171
|
fontSize: 'var(--text-sm)',
|
|
1148
1172
|
fontWeight: 'var(--weight-medium)',
|
|
@@ -1177,7 +1201,7 @@ export const menu = {
|
|
|
1177
1201
|
base: {
|
|
1178
1202
|
display: 'flex',
|
|
1179
1203
|
alignItems: 'center',
|
|
1180
|
-
gap: '
|
|
1204
|
+
gap: 'var(--space-md)',
|
|
1181
1205
|
padding: 'var(--space-md) var(--space-lg)',
|
|
1182
1206
|
fontSize: 'var(--text-sm)',
|
|
1183
1207
|
fontWeight: 'var(--weight-medium)',
|
|
@@ -1354,7 +1378,7 @@ export const checkbox = {
|
|
|
1354
1378
|
},
|
|
1355
1379
|
parts: {
|
|
1356
1380
|
root: {
|
|
1357
|
-
base: { display: 'inline-flex', alignItems: 'center', gap: '
|
|
1381
|
+
base: { display: 'inline-flex', alignItems: 'center', gap: 'var(--space-md)', cursor: 'pointer' },
|
|
1358
1382
|
states: {
|
|
1359
1383
|
disabled: { opacity: 'var(--disabled-opacity)', cursor: 'not-allowed' },
|
|
1360
1384
|
checked: {}, unchecked: {}, indeterminate: {},
|
|
@@ -1551,7 +1575,7 @@ export const radioGroup = {
|
|
|
1551
1575
|
},
|
|
1552
1576
|
parts: {
|
|
1553
1577
|
root: {
|
|
1554
|
-
base: { display: 'flex', flexDirection: 'column', gap: '
|
|
1578
|
+
base: { display: 'flex', flexDirection: 'column', gap: 'var(--space-md)' },
|
|
1555
1579
|
states: { invalid: {}, required: {} },
|
|
1556
1580
|
selectors: {
|
|
1557
1581
|
// `invalid` is a fact about the GROUP — `item-control` carries
|
|
@@ -1565,7 +1589,7 @@ export const radioGroup = {
|
|
|
1565
1589
|
states: { disabled: { opacity: 'var(--disabled-opacity)' } },
|
|
1566
1590
|
},
|
|
1567
1591
|
item: {
|
|
1568
|
-
base: { display: 'inline-flex', alignItems: 'center', gap: '
|
|
1592
|
+
base: { display: 'inline-flex', alignItems: 'center', gap: 'var(--space-md)', cursor: 'pointer' },
|
|
1569
1593
|
states: {
|
|
1570
1594
|
disabled: { opacity: 'var(--disabled-opacity)', cursor: 'not-allowed' },
|
|
1571
1595
|
checked: {}, unchecked: {},
|
|
@@ -2147,7 +2171,7 @@ export const select = {
|
|
|
2147
2171
|
display: 'flex',
|
|
2148
2172
|
alignItems: 'center',
|
|
2149
2173
|
justifyContent: 'space-between',
|
|
2150
|
-
gap: '
|
|
2174
|
+
gap: 'var(--space-md)',
|
|
2151
2175
|
padding: 'var(--space-md) var(--space-lg)',
|
|
2152
2176
|
fontSize: 'var(--text-sm)',
|
|
2153
2177
|
fontWeight: 'var(--weight-medium)',
|
|
@@ -2212,6 +2236,15 @@ const BTN_STEPS = { xs: 6, sm: 8, md: 10, lg: 12, xl: 14 };
|
|
|
2212
2236
|
const btnHeight = (step) => `calc(var(--size-field) * ${BTN_STEPS[step]})`;
|
|
2213
2237
|
export const button = {
|
|
2214
2238
|
component: 'button',
|
|
2239
|
+
// Public to a design system derived from this one (#73).
|
|
2240
|
+
hooks: {
|
|
2241
|
+
properties: {
|
|
2242
|
+
'--btn-accent': 'The fill of the solid variant.',
|
|
2243
|
+
'--btn-on-accent': 'The ink on --btn-accent.',
|
|
2244
|
+
'--btn-soft': 'The soft fill (soft variant, unfilled hover).',
|
|
2245
|
+
'--btn-ink': 'The ink of the unfilled variants.',
|
|
2246
|
+
},
|
|
2247
|
+
},
|
|
2215
2248
|
// The two axes meet here instead of multiplying. `color` sets the accent
|
|
2216
2249
|
// pair; `variant` decides how the accent is used. 8 + 4 + 5 rules rather
|
|
2217
2250
|
// than 8 × 4.
|
|
@@ -2222,9 +2255,34 @@ export const button = {
|
|
|
2222
2255
|
'--btn-ink': roleInk('primary'),
|
|
2223
2256
|
},
|
|
2224
2257
|
parts: {
|
|
2258
|
+
// The loading spinner (#50): a real part zero renders before the
|
|
2259
|
+
// label while `loading`, drawn as a ring in `currentColor` with one
|
|
2260
|
+
// transparent quadrant — it takes whatever ink the variant chose.
|
|
2261
|
+
// A literal duration and an explicit reduced-motion `none`: the kit
|
|
2262
|
+
// collapses `--duration-*` under reduced motion, and an infinite
|
|
2263
|
+
// loop at ~0s strobes rather than stops.
|
|
2264
|
+
// daisy marks a loading button with a `loading loading-spinner` span;
|
|
2265
|
+
// this is that span, zero's own now (it was a `loading` modifier's
|
|
2266
|
+
// `::before` until #50 made loading a Button state).
|
|
2267
|
+
spinner: {
|
|
2268
|
+
base: {
|
|
2269
|
+
boxSizing: 'border-box',
|
|
2270
|
+
inlineSize: '1em',
|
|
2271
|
+
blockSize: '1em',
|
|
2272
|
+
flex: 'none',
|
|
2273
|
+
borderRadius: '9999px',
|
|
2274
|
+
border: 'calc(var(--border) * 2) solid currentColor',
|
|
2275
|
+
borderBlockStartColor: 'transparent',
|
|
2276
|
+
animation: 'zero-daisyui-btn-spin 0.7s linear infinite',
|
|
2277
|
+
},
|
|
2278
|
+
at: { 'reduced-motion': { base: { animation: 'none' } } },
|
|
2279
|
+
},
|
|
2225
2280
|
root: {
|
|
2226
2281
|
base: {
|
|
2227
2282
|
appearance: 'none',
|
|
2283
|
+
// An asChild `<a>` gets no UA underline (see the README's
|
|
2284
|
+
// link-button note for the unlayered `a { color }` case).
|
|
2285
|
+
textDecoration: 'none',
|
|
2228
2286
|
display: 'inline-flex',
|
|
2229
2287
|
alignItems: 'center',
|
|
2230
2288
|
justifyContent: 'center',
|
|
@@ -2240,6 +2298,9 @@ export const button = {
|
|
|
2240
2298
|
+ 'border-color var(--duration-fast) var(--ease-standard)',
|
|
2241
2299
|
},
|
|
2242
2300
|
states: {
|
|
2301
|
+
// Work in flight (`loading`, #50): still focusable, still legible —
|
|
2302
|
+
// the label is what the reader is waiting on — so no fade here.
|
|
2303
|
+
loading: { cursor: 'progress' },
|
|
2243
2304
|
disabled: { opacity: 'var(--disabled-opacity)', cursor: 'not-allowed' },
|
|
2244
2305
|
// The ring is drawn on the page, offset clear of the button —
|
|
2245
2306
|
// ink, not fill, and the same 3:1 floor. On `--btn-accent` it
|
|
@@ -2383,37 +2444,6 @@ export const button = {
|
|
|
2383
2444
|
active: {
|
|
2384
2445
|
root: { base: { transform: 'translateY(1px)', boxShadow: 'none', filter: 'brightness(0.92)' } },
|
|
2385
2446
|
},
|
|
2386
|
-
/**
|
|
2387
|
-
* daisy's loading spinner, drawn by the recipe (#332): daisy marks
|
|
2388
|
-
* the button with a `loading loading-spinner` span; zero changes no
|
|
2389
|
-
* DOM, so the ring is a `::before` in `currentColor` with one
|
|
2390
|
-
* transparent quadrant — it inherits whatever ink the variant chose,
|
|
2391
|
-
* and the root's existing `gap` spaces it from the label. Literal
|
|
2392
|
-
* duration + explicit reduced-motion `none`, like the spinner
|
|
2393
|
-
* recipe: the kit collapses `--duration-*` under reduced motion, and
|
|
2394
|
-
* an infinite loop at ~0s strobes rather than stops.
|
|
2395
|
-
*/
|
|
2396
|
-
loading: {
|
|
2397
|
-
root: {
|
|
2398
|
-
base: { cursor: 'progress' },
|
|
2399
|
-
selectors: {
|
|
2400
|
-
'&::before': {
|
|
2401
|
-
content: '""',
|
|
2402
|
-
boxSizing: 'border-box',
|
|
2403
|
-
inlineSize: '1em',
|
|
2404
|
-
blockSize: '1em',
|
|
2405
|
-
flex: 'none',
|
|
2406
|
-
borderRadius: '9999px',
|
|
2407
|
-
border: 'calc(var(--border) * 2) solid currentColor',
|
|
2408
|
-
borderBlockStartColor: 'transparent',
|
|
2409
|
-
animation: 'zero-daisyui-btn-spin 0.7s linear infinite',
|
|
2410
|
-
},
|
|
2411
|
-
},
|
|
2412
|
-
at: {
|
|
2413
|
-
'reduced-motion': { selectors: { '&::before': { animation: 'none' } } },
|
|
2414
|
-
},
|
|
2415
|
-
},
|
|
2416
|
-
},
|
|
2417
2447
|
},
|
|
2418
2448
|
defaultVariants: { color: 'primary', variant: 'solid', size: 'md' },
|
|
2419
2449
|
keyframes: { 'zero-daisyui-btn-spin': 'to { transform: rotate(360deg) }' },
|
|
@@ -2480,6 +2510,13 @@ export const avatar = {
|
|
|
2480
2510
|
},
|
|
2481
2511
|
},
|
|
2482
2512
|
variants: {
|
|
2513
|
+
// The shape axis (zero#129) — one declaration on the root, whose
|
|
2514
|
+
// `overflow: hidden` clips the image and the fallback alike. `rounded` is daisy's selector radius; the default is the circle.
|
|
2515
|
+
shape: {
|
|
2516
|
+
circle: { root: { base: { borderRadius: '9999px' } } },
|
|
2517
|
+
square: { root: { base: { borderRadius: '0' } } },
|
|
2518
|
+
rounded: { root: { base: { borderRadius: 'var(--radius-selector)' } } },
|
|
2519
|
+
},
|
|
2483
2520
|
// daisy colours the RING, not the fallback — that is what its avatar
|
|
2484
2521
|
// does, and the fallback stays neutral so initials read the same
|
|
2485
2522
|
// whichever role is chosen.
|
|
@@ -2689,6 +2726,7 @@ export const combobox = {
|
|
|
2689
2726
|
base: {
|
|
2690
2727
|
display: 'inline-flex',
|
|
2691
2728
|
alignItems: 'stretch',
|
|
2729
|
+
flexWrap: 'wrap',
|
|
2692
2730
|
minWidth: '13rem',
|
|
2693
2731
|
...fieldControl,
|
|
2694
2732
|
transition: 'border-color var(--duration-fast) var(--ease-standard)',
|
|
@@ -2734,6 +2772,52 @@ export const combobox = {
|
|
|
2734
2772
|
'&::placeholder': { color: 'color-mix(in oklab, var(--color-base-content) 60%, transparent)' },
|
|
2735
2773
|
},
|
|
2736
2774
|
},
|
|
2775
|
+
// A chosen value under `multiple` (#39): a chip in the control, before
|
|
2776
|
+
// the input. Symmetric metrics only — the physical-direction lint and
|
|
2777
|
+
// the lynx emitter both refuse a one-sided inset.
|
|
2778
|
+
// daisy's badge: a base-200 pill, centred in the stretched row.
|
|
2779
|
+
tag: {
|
|
2780
|
+
base: {
|
|
2781
|
+
display: 'inline-flex',
|
|
2782
|
+
alignItems: 'center',
|
|
2783
|
+
alignSelf: 'center',
|
|
2784
|
+
gap: 'var(--space-2xs)',
|
|
2785
|
+
margin: 'var(--space-2xs)',
|
|
2786
|
+
padding: 'var(--space-2xs) var(--space-sm)',
|
|
2787
|
+
background: 'var(--color-base-200)',
|
|
2788
|
+
color: 'var(--color-base-content)',
|
|
2789
|
+
borderRadius: 'var(--radius-selector)',
|
|
2790
|
+
fontSize: 'var(--text-xs)',
|
|
2791
|
+
fontWeight: 'var(--weight-medium)',
|
|
2792
|
+
lineHeight: 'var(--leading-none)',
|
|
2793
|
+
},
|
|
2794
|
+
states: { disabled: {} },
|
|
2795
|
+
},
|
|
2796
|
+
'tag-label': { base: { whiteSpace: 'nowrap' } },
|
|
2797
|
+
'tag-remove': {
|
|
2798
|
+
base: {
|
|
2799
|
+
appearance: 'none',
|
|
2800
|
+
border: 'none',
|
|
2801
|
+
background: 'transparent',
|
|
2802
|
+
color: 'inherit',
|
|
2803
|
+
font: 'inherit',
|
|
2804
|
+
borderRadius: 'var(--radius-selector)',
|
|
2805
|
+
padding: '0 var(--space-2xs)',
|
|
2806
|
+
lineHeight: 'var(--leading-none)',
|
|
2807
|
+
cursor: 'pointer',
|
|
2808
|
+
transition: 'background var(--duration-fast) var(--ease-standard)',
|
|
2809
|
+
},
|
|
2810
|
+
states: {
|
|
2811
|
+
hover: { background: 'color-mix(in oklab, var(--color-base-content) 10%, transparent)' },
|
|
2812
|
+
disabled: { opacity: 'var(--disabled-opacity)', cursor: 'not-allowed' },
|
|
2813
|
+
...focusRing,
|
|
2814
|
+
},
|
|
2815
|
+
selectors: {
|
|
2816
|
+
'&[data-pressed]:not([data-disabled])': {
|
|
2817
|
+
background: 'color-mix(in oklab, var(--color-base-content) 18%, transparent)',
|
|
2818
|
+
},
|
|
2819
|
+
},
|
|
2820
|
+
},
|
|
2737
2821
|
trigger: {
|
|
2738
2822
|
base: {
|
|
2739
2823
|
appearance: 'none',
|
|
@@ -2770,7 +2854,7 @@ export const combobox = {
|
|
|
2770
2854
|
display: 'flex',
|
|
2771
2855
|
alignItems: 'center',
|
|
2772
2856
|
justifyContent: 'space-between',
|
|
2773
|
-
gap: '
|
|
2857
|
+
gap: 'var(--space-md)',
|
|
2774
2858
|
padding: 'var(--space-md) var(--space-lg)',
|
|
2775
2859
|
fontSize: 'var(--text-sm)',
|
|
2776
2860
|
fontWeight: 'var(--weight-medium)',
|
|
@@ -2802,15 +2886,15 @@ export const combobox = {
|
|
|
2802
2886
|
'--combobox-accent': `var(--color-${c})`,
|
|
2803
2887
|
} } }])),
|
|
2804
2888
|
// The control carries the height — the shared field ramp, the same one
|
|
2805
|
-
// `select`'s trigger steps on
|
|
2806
|
-
// type. `md` restates exactly the resting values so the union stays
|
|
2889
|
+
// `select`'s trigger steps on, as a floor so wrapped tags can grow it
|
|
2890
|
+
// — and the input carries the inset and the type. `md` restates exactly the resting values so the union stays
|
|
2807
2891
|
// complete.
|
|
2808
2892
|
size: {
|
|
2809
|
-
xs: { control: { base: {
|
|
2810
|
-
sm: { control: { base: {
|
|
2811
|
-
md: { control: { base: {
|
|
2812
|
-
lg: { control: { base: {
|
|
2813
|
-
xl: { control: { base: {
|
|
2893
|
+
xs: { control: { base: { minHeight: fieldHeight('xs') } }, input: { base: { padding: 'var(--space-2xs) var(--space-md)', fontSize: 'var(--text-xs)' } } },
|
|
2894
|
+
sm: { control: { base: { minHeight: fieldHeight('sm') } }, input: { base: { padding: 'var(--space-xs) var(--space-md)', fontSize: 'var(--text-sm)' } } },
|
|
2895
|
+
md: { control: { base: { minHeight: fieldHeight('md') } }, input: { base: { padding: 'var(--space-sm) var(--space-lg)', fontSize: 'var(--text-sm)' } } },
|
|
2896
|
+
lg: { control: { base: { minHeight: fieldHeight('lg') } }, input: { base: { padding: 'var(--space-md) var(--space-xl)', fontSize: 'var(--text-md)' } } },
|
|
2897
|
+
xl: { control: { base: { minHeight: fieldHeight('xl') } }, input: { base: { padding: 'var(--space-lg) var(--space-2xl)', fontSize: 'var(--text-lg)' } } },
|
|
2814
2898
|
},
|
|
2815
2899
|
},
|
|
2816
2900
|
// The visible ring lives on `control`; input and trigger delegate.
|
|
@@ -2906,6 +2990,13 @@ export const toggle = {
|
|
|
2906
2990
|
// the on item filled with the accent.
|
|
2907
2991
|
export const toggleGroup = {
|
|
2908
2992
|
component: 'toggle-group',
|
|
2993
|
+
// Public to a design system derived from this one (#73).
|
|
2994
|
+
hooks: {
|
|
2995
|
+
properties: {
|
|
2996
|
+
'--toggle-group-accent': 'The fill of an on item.',
|
|
2997
|
+
'--toggle-group-on-accent': 'The ink on --toggle-group-accent.',
|
|
2998
|
+
},
|
|
2999
|
+
},
|
|
2909
3000
|
tokens: {
|
|
2910
3001
|
'--toggle-group-accent': 'var(--color-primary)',
|
|
2911
3002
|
'--toggle-group-on-accent': 'var(--color-primary-content)',
|
|
@@ -3334,7 +3425,7 @@ export const ratingGroup = {
|
|
|
3334
3425
|
const treeRow = {
|
|
3335
3426
|
display: 'flex',
|
|
3336
3427
|
alignItems: 'center',
|
|
3337
|
-
gap: '
|
|
3428
|
+
gap: 'var(--space-md)',
|
|
3338
3429
|
padding: 'var(--space-sm) var(--space-md)',
|
|
3339
3430
|
fontSize: 'var(--tree-text)',
|
|
3340
3431
|
fontWeight: 'var(--weight-medium)',
|
|
@@ -3607,94 +3698,6 @@ export const textarea = {
|
|
|
3607
3698
|
},
|
|
3608
3699
|
},
|
|
3609
3700
|
};
|
|
3610
|
-
/**
|
|
3611
|
-
* NativeSelect (#333) — daisy "select" flavor on the platform's own picker:
|
|
3612
|
-
* the `fieldControl` box (same metrics as every field, so mixed rows line
|
|
3613
|
-
* up), `appearance: none`, and the recipe-drawn chevron at the inline end.
|
|
3614
|
-
* No open state — the platform owns the popup — so colour surfaces on the
|
|
3615
|
-
* focus ring, exactly like input's.
|
|
3616
|
-
*/
|
|
3617
|
-
export const nativeSelect = {
|
|
3618
|
-
component: 'native-select',
|
|
3619
|
-
tokens: { '--native-select-accent': 'var(--color-base-content)' },
|
|
3620
|
-
parts: {
|
|
3621
|
-
root: {
|
|
3622
|
-
base: { position: 'relative', display: 'inline-flex', alignItems: 'center' },
|
|
3623
|
-
states: { disabled: {}, invalid: {}, required: {}, placeholder: {} },
|
|
3624
|
-
},
|
|
3625
|
-
control: {
|
|
3626
|
-
base: {
|
|
3627
|
-
appearance: 'none',
|
|
3628
|
-
width: '100%',
|
|
3629
|
-
minWidth: '12rem',
|
|
3630
|
-
...fieldControl,
|
|
3631
|
-
color: 'var(--color-base-content)',
|
|
3632
|
-
font: 'inherit',
|
|
3633
|
-
fontSize: 'var(--text-sm)',
|
|
3634
|
-
padding: 'var(--space-sm) var(--space-md)',
|
|
3635
|
-
// Room for the chevron the platform no longer draws.
|
|
3636
|
-
paddingInlineEnd: 'calc(var(--space-md) + 1.25em)',
|
|
3637
|
-
cursor: 'pointer',
|
|
3638
|
-
transition: 'border-color var(--duration-fast) var(--ease-standard)',
|
|
3639
|
-
},
|
|
3640
|
-
states: {
|
|
3641
|
-
hover: { borderColor: 'var(--color-base-content)' },
|
|
3642
|
-
invalid: { borderColor: 'var(--color-error)' },
|
|
3643
|
-
disabled: { opacity: 'var(--disabled-opacity)', cursor: 'not-allowed' },
|
|
3644
|
-
required: {},
|
|
3645
|
-
// Same muting as the fields' placeholders (#264).
|
|
3646
|
-
placeholder: { color: 'color-mix(in oklab, var(--color-base-content) 60%, transparent)' },
|
|
3647
|
-
'focus-visible': { ...focusRing['focus-visible'], outline: '2px solid var(--native-select-accent)' },
|
|
3648
|
-
},
|
|
3649
|
-
},
|
|
3650
|
-
indicator: {
|
|
3651
|
-
base: {
|
|
3652
|
-
position: 'absolute',
|
|
3653
|
-
insetInlineEnd: 'var(--space-md)',
|
|
3654
|
-
pointerEvents: 'none',
|
|
3655
|
-
opacity: '0.6',
|
|
3656
|
-
fontSize: 'var(--text-sm)',
|
|
3657
|
-
},
|
|
3658
|
-
},
|
|
3659
|
-
},
|
|
3660
|
-
// The visible ring lives on the <select> itself; the wrapper delegates.
|
|
3661
|
-
skipStates: { root: ['focus-visible'] },
|
|
3662
|
-
variants: {
|
|
3663
|
-
// The ring carries the role — daisy's field chrome is neutral, so
|
|
3664
|
-
// focus is the only place colour surfaces (input's exact move).
|
|
3665
|
-
color: Object.fromEntries(ROLES.map((c) => [c, { root: { base: {
|
|
3666
|
-
'--native-select-accent': `var(--color-${c})`,
|
|
3667
|
-
} } }])),
|
|
3668
|
-
// The shared field-height ramp, on the control itself.
|
|
3669
|
-
size: {
|
|
3670
|
-
xs: { control: { base: { height: fieldHeight('xs'), fontSize: 'var(--text-xs)', padding: 'var(--space-2xs) var(--space-xs)', paddingInlineEnd: 'calc(var(--space-xs) + 1.25em)' } } },
|
|
3671
|
-
sm: { control: { base: { height: fieldHeight('sm'), fontSize: 'var(--text-xs)', padding: 'var(--space-xs) var(--space-sm)', paddingInlineEnd: 'calc(var(--space-sm) + 1.25em)' } } },
|
|
3672
|
-
md: {},
|
|
3673
|
-
lg: { control: { base: { height: fieldHeight('lg'), fontSize: 'var(--text-md)', padding: 'var(--space-md) var(--space-lg)', paddingInlineEnd: 'calc(var(--space-lg) + 1.25em)' } } },
|
|
3674
|
-
xl: { control: { base: { height: fieldHeight('xl'), fontSize: 'var(--text-lg)', padding: 'var(--space-lg) var(--space-xl)', paddingInlineEnd: 'calc(var(--space-xl) + 1.25em)' } } },
|
|
3675
|
-
},
|
|
3676
|
-
},
|
|
3677
|
-
// The chevron gutter and the indicator anchor, restated physically:
|
|
3678
|
-
// logical spellings resolve on iOS but not on Android (measured,
|
|
3679
|
-
// signalxjs/lynx#1084), so the emitter refuses them. Physical is the
|
|
3680
|
-
// lynx target's norm — no RTL flow there, so `end` IS right.
|
|
3681
|
-
targets: {
|
|
3682
|
-
lynx: {
|
|
3683
|
-
parts: {
|
|
3684
|
-
control: { base: { paddingRight: 'calc(var(--space-md) + 1.25em)' } },
|
|
3685
|
-
indicator: { base: { right: 'var(--space-md)' } },
|
|
3686
|
-
},
|
|
3687
|
-
variants: {
|
|
3688
|
-
size: {
|
|
3689
|
-
xs: { control: { base: { paddingRight: 'calc(var(--space-xs) + 1.25em)' } } },
|
|
3690
|
-
sm: { control: { base: { paddingRight: 'calc(var(--space-sm) + 1.25em)' } } },
|
|
3691
|
-
lg: { control: { base: { paddingRight: 'calc(var(--space-lg) + 1.25em)' } } },
|
|
3692
|
-
xl: { control: { base: { paddingRight: 'calc(var(--space-xl) + 1.25em)' } } },
|
|
3693
|
-
},
|
|
3694
|
-
},
|
|
3695
|
-
},
|
|
3696
|
-
},
|
|
3697
|
-
};
|
|
3698
3701
|
// ── Content tier (#311) ───────────────────────────────────────────────────
|
|
3699
3702
|
/**
|
|
3700
3703
|
* daisy "card" flavor: `bg-base-100` on a `rounded-box` with a real shadow —
|
|
@@ -3703,6 +3706,12 @@ export const nativeSelect = {
|
|
|
3703
3706
|
*/
|
|
3704
3707
|
export const card = {
|
|
3705
3708
|
component: 'card',
|
|
3709
|
+
// Public to a design system derived from this one (#73).
|
|
3710
|
+
hooks: {
|
|
3711
|
+
properties: {
|
|
3712
|
+
'--card-pad': 'The card padding.',
|
|
3713
|
+
},
|
|
3714
|
+
},
|
|
3706
3715
|
tokens: { '--card-pad': 'var(--space-xl)' },
|
|
3707
3716
|
parts: {
|
|
3708
3717
|
root: {
|
|
@@ -3857,6 +3866,87 @@ export const alert = {
|
|
|
3857
3866
|
},
|
|
3858
3867
|
},
|
|
3859
3868
|
};
|
|
3869
|
+
/**
|
|
3870
|
+
* EmptyState (zero#131) — daisy has no empty-state component; this is the
|
|
3871
|
+
* `hero`-content idiom at card scale: a centred column on the base-200
|
|
3872
|
+
* surface with the box radius, the icon in the role's ink and the surface
|
|
3873
|
+
* in its soft tint when a tone is given.
|
|
3874
|
+
*/
|
|
3875
|
+
export const emptyState = {
|
|
3876
|
+
component: 'empty-state',
|
|
3877
|
+
hooks: {
|
|
3878
|
+
properties: {
|
|
3879
|
+
'--empty-accent': 'The icon ink.',
|
|
3880
|
+
'--empty-tint': 'The surface fill.',
|
|
3881
|
+
},
|
|
3882
|
+
},
|
|
3883
|
+
tokens: {
|
|
3884
|
+
'--empty-accent': 'color-mix(in oklab, var(--color-base-content) 60%, transparent)',
|
|
3885
|
+
'--empty-tint': 'var(--color-base-200)',
|
|
3886
|
+
},
|
|
3887
|
+
parts: {
|
|
3888
|
+
root: {
|
|
3889
|
+
base: {
|
|
3890
|
+
display: 'flex',
|
|
3891
|
+
flexDirection: 'column',
|
|
3892
|
+
alignItems: 'center',
|
|
3893
|
+
textAlign: 'center',
|
|
3894
|
+
gap: 'var(--space-sm)',
|
|
3895
|
+
padding: 'var(--space-2xl) var(--space-xl)',
|
|
3896
|
+
background: 'var(--empty-tint)',
|
|
3897
|
+
color: 'var(--color-base-content)',
|
|
3898
|
+
borderRadius: 'var(--radius-box)',
|
|
3899
|
+
},
|
|
3900
|
+
},
|
|
3901
|
+
icon: {
|
|
3902
|
+
base: {
|
|
3903
|
+
display: 'inline-flex',
|
|
3904
|
+
color: 'var(--empty-accent)',
|
|
3905
|
+
fontSize: 'var(--text-2xl)',
|
|
3906
|
+
lineHeight: 'var(--leading-none)',
|
|
3907
|
+
marginBlockEnd: 'var(--space-xs)',
|
|
3908
|
+
},
|
|
3909
|
+
},
|
|
3910
|
+
title: {
|
|
3911
|
+
base: {
|
|
3912
|
+
margin: '0',
|
|
3913
|
+
fontSize: 'var(--text-lg)',
|
|
3914
|
+
fontWeight: 'var(--weight-bold)',
|
|
3915
|
+
lineHeight: 'var(--leading-tight)',
|
|
3916
|
+
},
|
|
3917
|
+
},
|
|
3918
|
+
description: {
|
|
3919
|
+
base: {
|
|
3920
|
+
maxInlineSize: '36ch',
|
|
3921
|
+
fontSize: 'var(--text-sm)',
|
|
3922
|
+
lineHeight: 'var(--leading-normal)',
|
|
3923
|
+
color: 'color-mix(in oklab, var(--color-base-content) 70%, transparent)',
|
|
3924
|
+
},
|
|
3925
|
+
},
|
|
3926
|
+
actions: {
|
|
3927
|
+
base: {
|
|
3928
|
+
display: 'flex',
|
|
3929
|
+
flexWrap: 'wrap',
|
|
3930
|
+
justifyContent: 'center',
|
|
3931
|
+
gap: 'var(--space-sm)',
|
|
3932
|
+
marginBlockStart: 'var(--space-sm)',
|
|
3933
|
+
},
|
|
3934
|
+
},
|
|
3935
|
+
},
|
|
3936
|
+
variants: {
|
|
3937
|
+
color: Object.fromEntries(ROLES.map((c) => [c, { root: { base: {
|
|
3938
|
+
'--empty-accent': roleInk(c),
|
|
3939
|
+
'--empty-tint': `var(--color-${c}-soft)`,
|
|
3940
|
+
} } }])),
|
|
3941
|
+
size: {
|
|
3942
|
+
xs: { root: { base: { padding: 'var(--space-md)', gap: 'var(--space-2xs)' } }, icon: { base: { fontSize: 'var(--text-xl)' } }, title: { base: { fontSize: 'var(--text-sm)' } }, description: { base: { fontSize: 'var(--text-xs)' } } },
|
|
3943
|
+
sm: { root: { base: { padding: 'var(--space-lg)', gap: 'var(--space-xs)' } }, icon: { base: { fontSize: 'var(--text-2xl)' } }, title: { base: { fontSize: 'var(--text-md)' } }, description: { base: { fontSize: 'var(--text-xs)' } } },
|
|
3944
|
+
md: {},
|
|
3945
|
+
lg: { root: { base: { padding: 'calc(var(--space-2xl) * 1.5) var(--space-2xl)', gap: 'var(--space-md)' } }, icon: { base: { fontSize: 'var(--text-2xl)' } }, title: { base: { fontSize: 'var(--text-xl)' } }, description: { base: { fontSize: 'var(--text-md)' } } },
|
|
3946
|
+
xl: { root: { base: { padding: 'calc(var(--space-2xl) * 2) var(--space-2xl)', gap: 'var(--space-lg)' } }, icon: { base: { fontSize: 'var(--text-2xl)' } }, title: { base: { fontSize: 'var(--text-2xl)' } }, description: { base: { fontSize: 'var(--text-md)' } } },
|
|
3947
|
+
},
|
|
3948
|
+
},
|
|
3949
|
+
};
|
|
3860
3950
|
/**
|
|
3861
3951
|
* daisy "badge" flavor: a fully-rounded pill with a hairline, filled by the
|
|
3862
3952
|
* role. No `variant` — the repo-wide decision (#175) holds everywhere except
|
|
@@ -3865,7 +3955,18 @@ export const alert = {
|
|
|
3865
3955
|
*/
|
|
3866
3956
|
export const badge = {
|
|
3867
3957
|
component: 'badge',
|
|
3958
|
+
// Public to a design system derived from this one (#73).
|
|
3959
|
+
hooks: {
|
|
3960
|
+
properties: {
|
|
3961
|
+
'--badge-dot': 'The status dot\'s fill (zero#130); the pill\'s ink at rest.',
|
|
3962
|
+
'--badge-dot-ring': 'The ring around a coloured status dot.',
|
|
3963
|
+
'--badge-fill': 'The badge fill.',
|
|
3964
|
+
'--badge-ink': 'The badge ink.',
|
|
3965
|
+
},
|
|
3966
|
+
},
|
|
3868
3967
|
tokens: {
|
|
3968
|
+
'--badge-dot': 'currentColor',
|
|
3969
|
+
'--badge-dot-ring': 'currentColor',
|
|
3869
3970
|
'--badge-fill': 'var(--color-base-200)',
|
|
3870
3971
|
'--badge-ink': 'var(--color-base-content)',
|
|
3871
3972
|
},
|
|
@@ -3881,7 +3982,7 @@ export const badge = {
|
|
|
3881
3982
|
// daisy badges are pills; a large radius rather than 9999px so
|
|
3882
3983
|
// a square-cornered theme can still say so through the token.
|
|
3883
3984
|
borderRadius: 'var(--radius-selector)',
|
|
3884
|
-
padding: '
|
|
3985
|
+
padding: 'var(--space-2xs) var(--space-lg)',
|
|
3885
3986
|
fontSize: 'var(--text-xs)',
|
|
3886
3987
|
fontWeight: 'var(--weight-semibold)',
|
|
3887
3988
|
lineHeight: 'var(--leading-normal)',
|
|
@@ -3889,12 +3990,53 @@ export const badge = {
|
|
|
3889
3990
|
textDecoration: 'none',
|
|
3890
3991
|
},
|
|
3891
3992
|
},
|
|
3993
|
+
// The status dot (zero#130). On an uncoloured pill it is the pill's
|
|
3994
|
+
// INK — a dot in `currentColor` is legible on whatever fill the pill
|
|
3995
|
+
// has. Coloured — by its own `data-color`, or by the pill's, since the
|
|
3996
|
+
// nearest carrier wins (#94) — it is the role's fill inside a ring in
|
|
3997
|
+
// the role's `-content` ink, the timeline marker's answer: a dot that
|
|
3998
|
+
// follows a solid pill of the same role still has an edge. `running` is a
|
|
3999
|
+
// static halo the pulse breathes; under reduced motion the halo
|
|
4000
|
+
// stays and the breathing stops, so the state never vanishes.
|
|
4001
|
+
dot: {
|
|
4002
|
+
base: {
|
|
4003
|
+
display: 'inline-block',
|
|
4004
|
+
flex: 'none',
|
|
4005
|
+
inlineSize: '0.5em',
|
|
4006
|
+
blockSize: '0.5em',
|
|
4007
|
+
boxSizing: 'border-box',
|
|
4008
|
+
borderRadius: '50%',
|
|
4009
|
+
background: 'var(--badge-dot)',
|
|
4010
|
+
border: '0.1em solid var(--badge-dot-ring)',
|
|
4011
|
+
},
|
|
4012
|
+
states: {
|
|
4013
|
+
running: {
|
|
4014
|
+
boxShadow: '0 0 0 0.2em color-mix(in oklch, var(--badge-dot) 35%, transparent)',
|
|
4015
|
+
animation: 'zero-daisy-badge-pulse 1.6s ease-out infinite',
|
|
4016
|
+
},
|
|
4017
|
+
},
|
|
4018
|
+
at: {
|
|
4019
|
+
'reduced-motion': { states: { running: { animation: 'none' } } },
|
|
4020
|
+
// Forced colours strip the fill and keep the border, so the
|
|
4021
|
+
// border draws the whole dot there.
|
|
4022
|
+
'forced-colors': { base: { borderWidth: '0.25em' } },
|
|
4023
|
+
},
|
|
4024
|
+
},
|
|
3892
4025
|
},
|
|
3893
4026
|
variants: {
|
|
3894
|
-
color: Object.fromEntries(ROLES.map((c) => [c, {
|
|
4027
|
+
color: Object.fromEntries(ROLES.map((c) => [c, {
|
|
4028
|
+
root: { base: {
|
|
3895
4029
|
'--badge-fill': `var(--color-${c})`,
|
|
3896
4030
|
'--badge-ink': `var(--color-${c}-content)`,
|
|
3897
|
-
} }
|
|
4031
|
+
} },
|
|
4032
|
+
// The dot's colour (zero#130): keyed under `variants.color` so the
|
|
4033
|
+
// compiler anchors it on the pill's `data-color` AND on the dot's
|
|
4034
|
+
// own re-carried one — the nearest carrier wins (#94).
|
|
4035
|
+
dot: { base: {
|
|
4036
|
+
'--badge-dot': `var(--color-${c})`,
|
|
4037
|
+
'--badge-dot-ring': `var(--color-${c}-content)`,
|
|
4038
|
+
} },
|
|
4039
|
+
}])),
|
|
3898
4040
|
size: {
|
|
3899
4041
|
xs: { root: { base: { fontSize: 'var(--text-xs)', padding: '0 var(--space-sm)' } } },
|
|
3900
4042
|
sm: { root: { base: { fontSize: 'var(--text-xs)', padding: '0 var(--space-md)' } } },
|
|
@@ -3902,6 +4044,8 @@ export const badge = {
|
|
|
3902
4044
|
lg: { root: { base: { fontSize: 'var(--text-sm)', padding: 'var(--space-2xs) var(--space-lg)' } } },
|
|
3903
4045
|
xl: { root: { base: { fontSize: 'var(--text-md)', padding: 'var(--space-xs) var(--space-xl)' } } },
|
|
3904
4046
|
},
|
|
4047
|
+
}, keyframes: {
|
|
4048
|
+
'zero-daisy-badge-pulse': 'from { box-shadow: 0 0 0 0 color-mix(in oklch, var(--badge-dot) 45%, transparent); } to { box-shadow: 0 0 0 0.5em transparent; }',
|
|
3905
4049
|
},
|
|
3906
4050
|
};
|
|
3907
4051
|
/** daisy "divider": the base-300 rule, thickening with the ramp. */
|
|
@@ -3945,6 +4089,12 @@ export const divider = {
|
|
|
3945
4089
|
*/
|
|
3946
4090
|
export const skeleton = {
|
|
3947
4091
|
component: 'skeleton',
|
|
4092
|
+
// Public to a design system derived from this one (#73).
|
|
4093
|
+
hooks: {
|
|
4094
|
+
properties: {
|
|
4095
|
+
'--skeleton-fill': 'The placeholder fill.',
|
|
4096
|
+
},
|
|
4097
|
+
},
|
|
3948
4098
|
tokens: { '--skeleton-fill': 'var(--color-base-300)' },
|
|
3949
4099
|
parts: {
|
|
3950
4100
|
root: {
|
|
@@ -4032,7 +4182,11 @@ export const kbd = {
|
|
|
4032
4182
|
alignItems: 'center',
|
|
4033
4183
|
justifyContent: 'center',
|
|
4034
4184
|
minInlineSize: '1.75em',
|
|
4035
|
-
|
|
4185
|
+
// daisy's .0625rem/.4375rem, restated as the ramp steps they
|
|
4186
|
+
// already are once the cap's own border is absorbed: the OUTER
|
|
4187
|
+
// box lands on 2xs/md, so the cap rides the ramp under a density
|
|
4188
|
+
// override while keeping daisy's painted size exactly at 1px.
|
|
4189
|
+
padding: 'calc(var(--space-2xs) - var(--border)) calc(var(--space-md) - var(--border))',
|
|
4036
4190
|
background: 'var(--kbd-fill)',
|
|
4037
4191
|
color: 'var(--kbd-ink)',
|
|
4038
4192
|
border: 'var(--border) solid var(--color-base-300)',
|
|
@@ -4261,10 +4415,31 @@ export const stats = {
|
|
|
4261
4415
|
},
|
|
4262
4416
|
},
|
|
4263
4417
|
};
|
|
4418
|
+
/**
|
|
4419
|
+
* A timeline none of whose content sits on the start side: the root carries
|
|
4420
|
+
* no start-placed content among its own items. Child combinators all the way
|
|
4421
|
+
* down, so a timeline nested inside another's content answers only for
|
|
4422
|
+
* itself.
|
|
4423
|
+
*/
|
|
4424
|
+
const TIMELINE_NO_START = '[data-scope="timeline"][data-part="root"]'
|
|
4425
|
+
+ ':not(:has(> [data-scope="timeline"][data-part="item"] > [data-scope="timeline"][data-part="content"][data-placement="start"])) > &';
|
|
4264
4426
|
/** daisy timeline: the boxed content beside a dotted axis. */
|
|
4265
4427
|
export const timeline = {
|
|
4266
4428
|
component: 'timeline',
|
|
4267
|
-
|
|
4429
|
+
// Public to a design system derived from this one (#73).
|
|
4430
|
+
hooks: {
|
|
4431
|
+
properties: {
|
|
4432
|
+
'--timeline-accent': 'The marker and connector accent.',
|
|
4433
|
+
'--timeline-ring': 'The ring around a coloured marker — the role\'s -content ink (#94).',
|
|
4434
|
+
'--timeline-marker-size': 'The marker diameter.',
|
|
4435
|
+
},
|
|
4436
|
+
},
|
|
4437
|
+
tokens: {
|
|
4438
|
+
'--timeline-accent': 'var(--color-base-content)',
|
|
4439
|
+
// The coloured dot's ring (#94); uncoloured, it IS the dot.
|
|
4440
|
+
'--timeline-ring': 'var(--timeline-accent)',
|
|
4441
|
+
'--timeline-marker-size': 'calc(var(--size-selector) * 3)',
|
|
4442
|
+
},
|
|
4268
4443
|
parts: {
|
|
4269
4444
|
root: {
|
|
4270
4445
|
base: {
|
|
@@ -4300,6 +4475,11 @@ export const timeline = {
|
|
|
4300
4475
|
gridTemplateColumns: 'auto 1fr',
|
|
4301
4476
|
flex: '1 1 0%',
|
|
4302
4477
|
},
|
|
4478
|
+
// No content on the start side anywhere in this timeline →
|
|
4479
|
+
// the start track collapses instead of holding half the item
|
|
4480
|
+
// empty (#57). Automatic, so there is no prop to forget.
|
|
4481
|
+
[`${TIMELINE_NO_START}[data-orientation="vertical"]`]: { gridTemplateColumns: '0 auto 1fr' },
|
|
4482
|
+
[`${TIMELINE_NO_START}[data-orientation="horizontal"]`]: { gridTemplateRows: '0 auto 1fr' },
|
|
4303
4483
|
},
|
|
4304
4484
|
},
|
|
4305
4485
|
marker: {
|
|
@@ -4309,12 +4489,24 @@ export const timeline = {
|
|
|
4309
4489
|
boxSizing: 'border-box',
|
|
4310
4490
|
borderRadius: '9999px',
|
|
4311
4491
|
background: 'var(--timeline-accent)',
|
|
4312
|
-
|
|
4492
|
+
// A coloured dot is the role fill inside a RING in the role's
|
|
4493
|
+
// `-content` ink (#94): a light role on a light page, or a dark
|
|
4494
|
+
// one on a dark page, has no edge of its own, and a per-entry
|
|
4495
|
+
// tone is exactly the mark a reader has to find. One half of
|
|
4496
|
+
// the role's own pair clears 3:1 against the page (the contrast
|
|
4497
|
+
// audit measures every colour). With no colour the ring is the
|
|
4498
|
+
// fill — the same solid dot as before.
|
|
4499
|
+
border: 'calc(var(--timeline-marker-size) / 6) solid var(--timeline-ring)',
|
|
4313
4500
|
display: 'flex',
|
|
4314
4501
|
alignItems: 'center',
|
|
4315
4502
|
justifyContent: 'center',
|
|
4316
4503
|
fontSize: '0',
|
|
4317
4504
|
},
|
|
4505
|
+
at: {
|
|
4506
|
+
// Forced colours strip the fill and keep the border, so the
|
|
4507
|
+
// border draws the whole dot there, as it always did.
|
|
4508
|
+
'forced-colors': { base: { borderWidth: 'calc(var(--timeline-marker-size) / 2)' } },
|
|
4509
|
+
},
|
|
4318
4510
|
selectors: {
|
|
4319
4511
|
// The axis cell, both orientations. `place-self` centres the
|
|
4320
4512
|
// dot on the line in the cross axis.
|
|
@@ -4392,6 +4584,7 @@ export const timeline = {
|
|
|
4392
4584
|
variants: {
|
|
4393
4585
|
color: Object.fromEntries(ROLES.map((c) => [c, { marker: { base: {
|
|
4394
4586
|
'--timeline-accent': `var(--color-${c})`,
|
|
4587
|
+
'--timeline-ring': `var(--color-${c}-content)`,
|
|
4395
4588
|
} } }])),
|
|
4396
4589
|
size: {
|
|
4397
4590
|
xs: { marker: { base: { '--timeline-marker-size': 'calc(var(--size-selector) * 2)' } }, content: { base: { fontSize: 'var(--text-xs)' } } },
|
|
@@ -4758,6 +4951,111 @@ export const navbar = {
|
|
|
4758
4951
|
},
|
|
4759
4952
|
},
|
|
4760
4953
|
};
|
|
4954
|
+
/**
|
|
4955
|
+
* NavList (zero#132) — daisy's `menu` idiom for a sidebar: rounded rows, a
|
|
4956
|
+
* base-200 wash on hover, and the current page as the role's soft fill in
|
|
4957
|
+
* the role's ink. `meta` is where daisy's menu puts its badge.
|
|
4958
|
+
*/
|
|
4959
|
+
export const navList = {
|
|
4960
|
+
component: 'nav-list',
|
|
4961
|
+
hooks: {
|
|
4962
|
+
properties: {
|
|
4963
|
+
'--nav-accent': 'The current link\'s ink.',
|
|
4964
|
+
'--nav-tint': 'The current link\'s fill.',
|
|
4965
|
+
'--nav-ink': 'The resting link ink.',
|
|
4966
|
+
},
|
|
4967
|
+
},
|
|
4968
|
+
tokens: {
|
|
4969
|
+
'--nav-accent': 'var(--color-base-content)',
|
|
4970
|
+
'--nav-tint': 'var(--color-base-300)',
|
|
4971
|
+
'--nav-ink': 'var(--color-base-content)',
|
|
4972
|
+
},
|
|
4973
|
+
parts: {
|
|
4974
|
+
root: {
|
|
4975
|
+
base: {
|
|
4976
|
+
display: 'flex',
|
|
4977
|
+
flexDirection: 'column',
|
|
4978
|
+
gap: 'var(--space-lg)',
|
|
4979
|
+
fontSize: 'var(--text-sm)',
|
|
4980
|
+
color: 'var(--color-base-content)',
|
|
4981
|
+
},
|
|
4982
|
+
},
|
|
4983
|
+
group: {
|
|
4984
|
+
base: { display: 'flex', flexDirection: 'column', gap: 'var(--space-xs)' },
|
|
4985
|
+
},
|
|
4986
|
+
heading: {
|
|
4987
|
+
base: {
|
|
4988
|
+
padding: '0 var(--space-lg)',
|
|
4989
|
+
fontSize: 'var(--text-xs)',
|
|
4990
|
+
fontWeight: 'var(--weight-bold)',
|
|
4991
|
+
opacity: '0.6',
|
|
4992
|
+
},
|
|
4993
|
+
},
|
|
4994
|
+
list: {
|
|
4995
|
+
base: {
|
|
4996
|
+
display: 'flex',
|
|
4997
|
+
flexDirection: 'column',
|
|
4998
|
+
gap: 'var(--space-2xs)',
|
|
4999
|
+
listStyle: 'none',
|
|
5000
|
+
margin: '0',
|
|
5001
|
+
padding: '0',
|
|
5002
|
+
},
|
|
5003
|
+
},
|
|
5004
|
+
item: { base: { display: 'block' } },
|
|
5005
|
+
link: {
|
|
5006
|
+
base: {
|
|
5007
|
+
display: 'flex',
|
|
5008
|
+
alignItems: 'center',
|
|
5009
|
+
gap: 'var(--space-sm)',
|
|
5010
|
+
textDecoration: 'none',
|
|
5011
|
+
color: 'var(--nav-ink)',
|
|
5012
|
+
padding: 'var(--space-sm) var(--space-lg)',
|
|
5013
|
+
borderRadius: 'var(--radius-field)',
|
|
5014
|
+
fontWeight: 'var(--weight-medium)',
|
|
5015
|
+
lineHeight: 'var(--leading-tight)',
|
|
5016
|
+
transition: 'background var(--duration-fast) var(--ease-standard)',
|
|
5017
|
+
},
|
|
5018
|
+
states: {
|
|
5019
|
+
hover: { background: 'var(--color-base-200)' },
|
|
5020
|
+
active: { background: 'var(--nav-tint)', color: 'var(--nav-accent)' },
|
|
5021
|
+
inactive: {},
|
|
5022
|
+
...focusRing,
|
|
5023
|
+
},
|
|
5024
|
+
},
|
|
5025
|
+
icon: {
|
|
5026
|
+
base: {
|
|
5027
|
+
display: 'inline-flex',
|
|
5028
|
+
inlineSize: '1.25em',
|
|
5029
|
+
justifyContent: 'center',
|
|
5030
|
+
flex: 'none',
|
|
5031
|
+
lineHeight: 'var(--leading-none)',
|
|
5032
|
+
},
|
|
5033
|
+
},
|
|
5034
|
+
meta: {
|
|
5035
|
+
base: {
|
|
5036
|
+
marginInlineStart: 'auto',
|
|
5037
|
+
display: 'inline-flex',
|
|
5038
|
+
alignItems: 'center',
|
|
5039
|
+
fontSize: 'var(--text-xs)',
|
|
5040
|
+
fontVariantNumeric: 'tabular-nums',
|
|
5041
|
+
opacity: '0.7',
|
|
5042
|
+
},
|
|
5043
|
+
},
|
|
5044
|
+
},
|
|
5045
|
+
variants: {
|
|
5046
|
+
color: Object.fromEntries(ROLES.map((c) => [c, { root: { base: {
|
|
5047
|
+
'--nav-accent': roleInk(c),
|
|
5048
|
+
'--nav-tint': `var(--color-${c}-soft)`,
|
|
5049
|
+
} } }])),
|
|
5050
|
+
size: {
|
|
5051
|
+
xs: { root: { base: { fontSize: 'var(--text-xs)' } }, link: { base: { padding: 'var(--space-2xs) var(--space-md)' } } },
|
|
5052
|
+
sm: { root: { base: { fontSize: 'var(--text-xs)' } }, link: { base: { padding: 'var(--space-xs) var(--space-md)' } } },
|
|
5053
|
+
md: {},
|
|
5054
|
+
lg: { root: { base: { fontSize: 'var(--text-md)' } }, link: { base: { padding: 'var(--space-md) var(--space-lg)' } } },
|
|
5055
|
+
xl: { root: { base: { fontSize: 'var(--text-lg)' } }, link: { base: { padding: 'var(--space-lg) var(--space-xl)' } } },
|
|
5056
|
+
},
|
|
5057
|
+
},
|
|
5058
|
+
};
|
|
4761
5059
|
/**
|
|
4762
5060
|
* Breadcrumbs — daisy's breadcrumbs: a compact text-sm trail, links
|
|
4763
5061
|
* underlining on hover, the current crumb plain full ink. Colour rebinds
|
|
@@ -4971,6 +5269,18 @@ export const pagination = {
|
|
|
4971
5269
|
},
|
|
4972
5270
|
},
|
|
4973
5271
|
};
|
|
5272
|
+
/**
|
|
5273
|
+
* The complete step's digit: the role hue deepened toward base-content, on
|
|
5274
|
+
* the disc's 20% tint of that role — `roleInk`'s per-role keep, capped at
|
|
5275
|
+
* 70%. The cap is the primary story: 95% on the tint measured 2.96:1 under
|
|
5276
|
+
* nord's muted primary (the static contrast matrix, #403). The per-role part
|
|
5277
|
+
* arrived with per-step colour (#112), when the matrix first measured every
|
|
5278
|
+
* role here: a flat 70% put nord's muted accent/success/warning at 2.2–2.6:1
|
|
5279
|
+
* and the dark themes' neutral (darker than the page) at 1.7–2.0:1, and
|
|
5280
|
+
* `ROLE_INK_KEEP` already knew how much hue each of those can keep.
|
|
5281
|
+
*/
|
|
5282
|
+
const stepInk = (accent, role) => `color-mix(in oklab, ${accent} `
|
|
5283
|
+
+ `${Math.min(ROLE_INK_KEEP[role] ?? 55, 70)}%, var(--color-base-content))`;
|
|
4974
5284
|
/**
|
|
4975
5285
|
* Steps — daisy's steps translated to the richer rail: bold numbered discs
|
|
4976
5286
|
* on base-200, the walked disc and line refilled with the accent pair
|
|
@@ -4983,6 +5293,9 @@ export const steps = {
|
|
|
4983
5293
|
'--steps-accent': 'var(--color-primary)',
|
|
4984
5294
|
'--steps-accent-content': 'var(--color-primary-content)',
|
|
4985
5295
|
'--steps-accent-ink': roleInk('primary'),
|
|
5296
|
+
// Read through the accent, so it resolves on the element that sets
|
|
5297
|
+
// it; a colour on the item restates it for that role.
|
|
5298
|
+
'--steps-complete-ink': stepInk('var(--steps-accent)', 'primary'),
|
|
4986
5299
|
'--steps-ind': 'calc(var(--size-selector) * 7)',
|
|
4987
5300
|
'--steps-font': 'var(--text-sm)',
|
|
4988
5301
|
},
|
|
@@ -5054,7 +5367,14 @@ export const steps = {
|
|
|
5054
5367
|
},
|
|
5055
5368
|
states: {
|
|
5056
5369
|
active: { background: 'var(--steps-accent)', color: 'var(--steps-accent-content)' },
|
|
5057
|
-
|
|
5370
|
+
// Ink deepened toward base-content, per role (`stepInk`). The
|
|
5371
|
+
// tint mixes in OKLAB: daisy's light base-100 is
|
|
5372
|
+
// `oklch(100% 0 0)`, whose 0 hue the browser interpolates as
|
|
5373
|
+
// written, so an OKLCH mix swung every role's tint toward red
|
|
5374
|
+
// (warning's yellow came out pink) — which the browser parity
|
|
5375
|
+
// check caught once per-step colour put all eight roles on
|
|
5376
|
+
// the disc (#112).
|
|
5377
|
+
complete: { background: 'color-mix(in oklab, var(--steps-accent) 20%, var(--color-base-100))', color: 'var(--steps-complete-ink)' },
|
|
5058
5378
|
inactive: { background: 'var(--color-base-200)', color: 'var(--color-base-content)' },
|
|
5059
5379
|
},
|
|
5060
5380
|
},
|
|
@@ -5103,10 +5423,15 @@ export const steps = {
|
|
|
5103
5423
|
},
|
|
5104
5424
|
},
|
|
5105
5425
|
variants: {
|
|
5106
|
-
|
|
5426
|
+
// Keyed on the ITEM, not the root (#112): the item re-carries
|
|
5427
|
+
// `color`, so a step's own value outranks the rail's, and the
|
|
5428
|
+
// disc, bridge and title inside it inherit whichever won. A root
|
|
5429
|
+
// colour still reaches every item through the carrier's donut.
|
|
5430
|
+
color: Object.fromEntries(ROLES.map((c) => [c, { item: { base: {
|
|
5107
5431
|
'--steps-accent': `var(--color-${c})`,
|
|
5108
5432
|
'--steps-accent-content': `var(--color-${c}-content)`,
|
|
5109
5433
|
'--steps-accent-ink': roleInk(c),
|
|
5434
|
+
'--steps-complete-ink': stepInk(`var(--color-${c})`, c),
|
|
5110
5435
|
} } }])),
|
|
5111
5436
|
size: {
|
|
5112
5437
|
xs: { root: { base: { '--steps-ind': 'calc(var(--size-selector) * 5)', '--steps-font': 'var(--text-xs)' } } },
|
|
@@ -5145,10 +5470,45 @@ export const steps = {
|
|
|
5145
5470
|
},
|
|
5146
5471
|
},
|
|
5147
5472
|
};
|
|
5473
|
+
/**
|
|
5474
|
+
* The modal sheet's slide (#83): in from its edge, back out to it.
|
|
5475
|
+
*
|
|
5476
|
+
* `translate` is physical, so the travel is a custom property that flips with
|
|
5477
|
+
* the placement AND the direction — off the reading start is leftward in LTR
|
|
5478
|
+
* and rightward in RTL (the `rtl` hedge, as everywhere here). Keyed on
|
|
5479
|
+
* `data-l-dock="sheet"`, the regime, which holds through the exit where
|
|
5480
|
+
* `:modal` does not, so the slide-out leaves from the sheet's own box.
|
|
5481
|
+
* Opacity stays at 1: the travel is the transition. Each direction rides the
|
|
5482
|
+
* transition declared at its destination; reduced motion drops both.
|
|
5483
|
+
*/
|
|
5484
|
+
const sheetSlide = (enter, exit) => {
|
|
5485
|
+
const sheet = '&[data-l-dock="sheet"]';
|
|
5486
|
+
const open = `${sheet}[data-state="open"]`;
|
|
5487
|
+
const travel = (tempo) => {
|
|
5488
|
+
const duration = tempo.split(' ')[0];
|
|
5489
|
+
return `translate ${tempo}, display ${duration} allow-discrete, overlay ${duration} allow-discrete`;
|
|
5490
|
+
};
|
|
5491
|
+
return {
|
|
5492
|
+
base: { '--drawer-travel': '-100%' },
|
|
5493
|
+
selectors: {
|
|
5494
|
+
'&[data-placement="end"]': { '--drawer-travel': '100%' },
|
|
5495
|
+
[`&[data-placement="start"]${rtl}`]: { '--drawer-travel': '100%' },
|
|
5496
|
+
[`&[data-placement="end"]${rtl}`]: { '--drawer-travel': '-100%' },
|
|
5497
|
+
[sheet]: { opacity: '1', translate: 'var(--drawer-travel) 0', transition: travel(exit) },
|
|
5498
|
+
[open]: { translate: 'none', transition: travel(enter) },
|
|
5499
|
+
},
|
|
5500
|
+
at: {
|
|
5501
|
+
'starting-style': { selectors: { [open]: { opacity: '1', translate: 'var(--drawer-travel) 0' } } },
|
|
5502
|
+
'reduced-motion': { selectors: { [sheet]: { transition: 'none' }, [open]: { transition: 'none' } } },
|
|
5503
|
+
},
|
|
5504
|
+
};
|
|
5505
|
+
};
|
|
5148
5506
|
/**
|
|
5149
5507
|
* Drawer — daisy's drawer-side as a native <dialog> edge sheet: base-100
|
|
5150
|
-
* paper, no border (daisy separates the drawer with the scrim),
|
|
5151
|
-
*
|
|
5508
|
+
* paper, no border (daisy separates the drawer with the scrim), sliding in
|
|
5509
|
+
* from its edge the way daisy's drawer-side does (`translate` over 0.3s,
|
|
5510
|
+
* #83). Base render is the inline mode; `data-l-dock="sheet"` is the
|
|
5511
|
+
* top-layer edge sheet.
|
|
5152
5512
|
*/
|
|
5153
5513
|
export const drawer = {
|
|
5154
5514
|
component: 'drawer',
|
|
@@ -5163,7 +5523,7 @@ export const drawer = {
|
|
|
5163
5523
|
...focusRing,
|
|
5164
5524
|
},
|
|
5165
5525
|
},
|
|
5166
|
-
panel: withPresence(popupPresence('none'), {
|
|
5526
|
+
panel: withPresence(withPresence(popupPresence('none'), sheetSlide('var(--duration-slow) var(--ease-standard)', 'var(--duration-slow) var(--ease-standard)')), {
|
|
5167
5527
|
base: {
|
|
5168
5528
|
padding: 'var(--space-lg)',
|
|
5169
5529
|
background: 'var(--color-base-100)',
|
|
@@ -5171,30 +5531,39 @@ export const drawer = {
|
|
|
5171
5531
|
border: 'none',
|
|
5172
5532
|
borderRadius: 'var(--radius-box)',
|
|
5173
5533
|
boxShadow: 'var(--shadow-xl)',
|
|
5174
|
-
|
|
5534
|
+
// The width is capped by `--l-measure` (Drawer.Panel's
|
|
5535
|
+
// `measure`, via the layout step table); this is the default
|
|
5536
|
+
// an unset `measure` leaves. A cap, not a width, because the
|
|
5537
|
+
// table spells `full` as `none` — valid only for a max. In
|
|
5538
|
+
// flow and as a sheet alike, the panel fills what it is given
|
|
5539
|
+
// up to the measure, as its border box, so `full` never
|
|
5540
|
+
// overflows by its own padding.
|
|
5541
|
+
boxSizing: 'border-box',
|
|
5542
|
+
'--l-measure': 'min(20rem, 85vw)',
|
|
5543
|
+
inlineSize: '100%',
|
|
5544
|
+
maxInlineSize: 'var(--l-measure)',
|
|
5175
5545
|
},
|
|
5176
5546
|
states: { open: {}, closed: {} },
|
|
5177
5547
|
selectors: {
|
|
5178
5548
|
/**
|
|
5179
|
-
* The
|
|
5180
|
-
*
|
|
5181
|
-
*
|
|
5182
|
-
* the
|
|
5183
|
-
* RTL mirrors
|
|
5549
|
+
* The top-layer edge sheet, keyed on the regime
|
|
5550
|
+
* (`data-l-dock="sheet"`) rather than `:modal`, which stops
|
|
5551
|
+
* matching the moment `close()` runs — so the sheet keeps its
|
|
5552
|
+
* box through the exit (#83). The base styles above are the
|
|
5553
|
+
* INLINE render. Logical insets pin the edge, so RTL mirrors
|
|
5554
|
+
* free.
|
|
5184
5555
|
*/
|
|
5185
|
-
'
|
|
5556
|
+
'&[data-l-dock="sheet"]': {
|
|
5186
5557
|
position: 'fixed',
|
|
5187
5558
|
insetBlockStart: '0',
|
|
5188
5559
|
insetBlockEnd: '0',
|
|
5189
5560
|
blockSize: '100dvh',
|
|
5190
5561
|
maxBlockSize: '100dvh',
|
|
5191
|
-
inlineSize: 'min(20rem, 85vw)',
|
|
5192
|
-
maxInlineSize: 'none',
|
|
5193
5562
|
margin: '0',
|
|
5194
5563
|
borderRadius: '0',
|
|
5195
5564
|
},
|
|
5196
|
-
'&[data-placement="start"]
|
|
5197
|
-
'&[data-placement="end"]
|
|
5565
|
+
'&[data-placement="start"][data-l-dock="sheet"]': { insetInlineStart: '0', insetInlineEnd: 'auto' },
|
|
5566
|
+
'&[data-placement="end"][data-l-dock="sheet"]': { insetInlineStart: 'auto', insetInlineEnd: '0' },
|
|
5198
5567
|
},
|
|
5199
5568
|
}),
|
|
5200
5569
|
backdrop: {
|
|
@@ -5235,7 +5604,20 @@ export const drawer = {
|
|
|
5235
5604
|
*/
|
|
5236
5605
|
export const table = {
|
|
5237
5606
|
component: 'table',
|
|
5607
|
+
// Public to a design system derived from this one (#73).
|
|
5608
|
+
hooks: {
|
|
5609
|
+
properties: {
|
|
5610
|
+
'--table-cell-align': 'Cell text alignment; zero writes it inline from the column spec.',
|
|
5611
|
+
'--table-accent': 'The header ink accent.',
|
|
5612
|
+
'--table-pad-block': 'Cell block padding.',
|
|
5613
|
+
'--table-pad-inline': 'Cell inline padding.',
|
|
5614
|
+
'--table-font': 'The table font size.',
|
|
5615
|
+
},
|
|
5616
|
+
},
|
|
5238
5617
|
tokens: {
|
|
5618
|
+
// The column spec's alignment (#55): a cell that names an aligned
|
|
5619
|
+
// column overrides it inline; everything else reads `start`.
|
|
5620
|
+
'--table-cell-align': 'start',
|
|
5239
5621
|
'--table-accent': 'var(--color-base-content)',
|
|
5240
5622
|
'--table-pad-block': 'var(--space-sm)',
|
|
5241
5623
|
'--table-pad-inline': 'var(--space-md)',
|
|
@@ -5249,6 +5631,9 @@ export const table = {
|
|
|
5249
5631
|
borderRadius: 'var(--radius-box)',
|
|
5250
5632
|
background: 'var(--color-base-100)',
|
|
5251
5633
|
},
|
|
5634
|
+
// Stacked (Table.Root stack, #55): zero lays each row out as a block
|
|
5635
|
+
// below the table's breakpoint; the card it becomes is drawn here.
|
|
5636
|
+
at: tableStackAt(tokens, 'root', { border: '0', borderRadius: '0', background: 'transparent' }),
|
|
5252
5637
|
},
|
|
5253
5638
|
table: {
|
|
5254
5639
|
base: {
|
|
@@ -5266,34 +5651,52 @@ export const table = {
|
|
|
5266
5651
|
fontSize: 'var(--text-xs)',
|
|
5267
5652
|
color: 'color-mix(in oklab, var(--color-base-content) 60%, transparent)',
|
|
5268
5653
|
},
|
|
5654
|
+
at: tableStackAt(tokens, 'caption', { paddingInline: '0' }),
|
|
5269
5655
|
},
|
|
5270
5656
|
head: {},
|
|
5271
|
-
body: {},
|
|
5657
|
+
body: { at: tableStackAt(tokens, 'body', { rowGap: 'var(--space-md)' }) },
|
|
5272
5658
|
foot: {
|
|
5273
5659
|
base: {
|
|
5274
5660
|
fontSize: 'var(--text-xs)',
|
|
5275
5661
|
color: 'color-mix(in oklab, var(--color-base-content) 60%, transparent)',
|
|
5276
5662
|
},
|
|
5663
|
+
at: tableStackAt(tokens, 'foot', { rowGap: 'var(--space-md)', marginBlockStart: 'var(--space-md)' }),
|
|
5277
5664
|
},
|
|
5278
5665
|
row: {
|
|
5279
5666
|
base: { borderBlockEnd: 'var(--border) solid var(--color-base-200)' },
|
|
5280
5667
|
states: {
|
|
5281
5668
|
selected: { background: 'var(--color-base-300)' },
|
|
5282
5669
|
},
|
|
5670
|
+
at: tableStackAt(tokens, 'row', {
|
|
5671
|
+
border: 'var(--border) solid var(--color-base-200)',
|
|
5672
|
+
borderRadius: 'var(--radius-box)',
|
|
5673
|
+
background: 'var(--color-base-100)',
|
|
5674
|
+
padding: 'var(--table-pad-block) var(--table-pad-inline)',
|
|
5675
|
+
}),
|
|
5283
5676
|
},
|
|
5284
5677
|
'header-cell': {
|
|
5285
5678
|
base: {
|
|
5286
5679
|
padding: 'var(--table-pad-block) var(--table-pad-inline)',
|
|
5287
|
-
textAlign: '
|
|
5680
|
+
textAlign: 'var(--table-cell-align)',
|
|
5288
5681
|
fontWeight: 'var(--weight-semibold)',
|
|
5289
5682
|
fontSize: 'var(--text-xs)',
|
|
5290
5683
|
color: 'color-mix(in oklab, var(--table-accent) 60%, transparent)',
|
|
5291
5684
|
},
|
|
5685
|
+
at: tableStackAt(tokens, 'header-cell', { paddingInline: '0' }),
|
|
5292
5686
|
},
|
|
5293
5687
|
cell: {
|
|
5294
5688
|
base: {
|
|
5295
5689
|
padding: 'var(--table-pad-block) var(--table-pad-inline)',
|
|
5296
|
-
textAlign: '
|
|
5690
|
+
textAlign: 'var(--table-cell-align)',
|
|
5691
|
+
},
|
|
5692
|
+
at: tableStackAt(tokens, 'cell', { paddingInline: '0', paddingBlock: 'var(--space-xs)' }),
|
|
5693
|
+
},
|
|
5694
|
+
// A stacked cell's column label, in the header's muted semibold.
|
|
5695
|
+
'cell-label': {
|
|
5696
|
+
base: {
|
|
5697
|
+
fontWeight: 'var(--weight-semibold)',
|
|
5698
|
+
fontSize: 'var(--text-xs)',
|
|
5699
|
+
color: 'color-mix(in oklab, var(--table-accent) 60%, transparent)',
|
|
5297
5700
|
},
|
|
5298
5701
|
},
|
|
5299
5702
|
},
|
|
@@ -5766,6 +6169,12 @@ export const countdown = {
|
|
|
5766
6169
|
xl: { root: { base: { '--countdown-font': 'var(--text-3xl)' } } },
|
|
5767
6170
|
},
|
|
5768
6171
|
},
|
|
6172
|
+
// One line inside a sentence (#57): the surrounding text's size and
|
|
6173
|
+
// weight instead of the display step. What stays is what makes
|
|
6174
|
+
// it a countdown — tabular digits, its ink, the per-tick entry.
|
|
6175
|
+
modifiers: {
|
|
6176
|
+
inline: { root: { base: { fontSize: 'inherit', fontWeight: 'inherit' } } },
|
|
6177
|
+
},
|
|
5769
6178
|
keyframes: { 'zero-daisyui-countdown-in': 'from { transform: translateY(0.6em); opacity: 0; }' },
|
|
5770
6179
|
};
|
|
5771
6180
|
/**
|
|
@@ -5890,10 +6299,10 @@ export const diff = {
|
|
|
5890
6299
|
export const recipes = [
|
|
5891
6300
|
tabs, collapsible, switchRecipe, dialog, popover, tooltip, menu,
|
|
5892
6301
|
field, checkbox, radioGroup, progress, slider, accordion, select, button, avatar, toast, combobox,
|
|
5893
|
-
toggle, toggleGroup, numberInput, ratingGroup, treeView, input, textarea,
|
|
5894
|
-
card, alert, badge, divider, skeleton, spinner,
|
|
6302
|
+
toggle, toggleGroup, numberInput, ratingGroup, treeView, input, textarea,
|
|
6303
|
+
card, alert, emptyState, badge, divider, skeleton, spinner,
|
|
5895
6304
|
kbd, status, indicator, stats, timeline, chat, radialProgress, join,
|
|
5896
|
-
navbar, breadcrumbs, pagination, steps, drawer,
|
|
6305
|
+
navbar, navList, breadcrumbs, pagination, steps, drawer,
|
|
5897
6306
|
table,
|
|
5898
6307
|
fileUpload,
|
|
5899
6308
|
carousel,
|