@sigx/zero-daisyui 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/audit.json +458 -3
- package/dist/css/components/drawer.css +61 -8
- package/dist/css/components/select.css +1 -1
- package/dist/css/components/toast.css +9 -3
- package/dist/css/index.css +71 -12
- package/dist/lynx/components/button.css +2 -2
- package/dist/lynx/components/carousel.css +10 -10
- package/dist/lynx/components/checkbox.css +7 -7
- package/dist/lynx/components/combobox.css +2 -2
- package/dist/lynx/components/dialog.css +2 -2
- package/dist/lynx/components/diff.css +10 -10
- package/dist/lynx/components/drawer.css +26 -4
- package/dist/lynx/components/grid.css +1 -1
- package/dist/lynx/components/hover-card.css +1 -1
- package/dist/lynx/components/menu.css +2 -2
- package/dist/lynx/components/navbar.css +5 -5
- package/dist/lynx/components/number-input.css +1 -1
- package/dist/lynx/components/popover.css +1 -1
- package/dist/lynx/components/radio-group.css +6 -6
- package/dist/lynx/components/select.css +51 -10
- package/dist/lynx/components/slider.css +2 -2
- package/dist/lynx/components/tabs.css +1 -1
- package/dist/lynx/components/toast.css +2 -2
- package/dist/lynx/components/tooltip.css +1 -1
- package/dist/lynx/index.css +247 -184
- package/dist/lynx/manifest.json +3 -3
- package/dist/lynx/tokens.css +114 -114
- package/dist/manifest.json +1 -1
- package/dist/recipes.d.ts.map +1 -1
- package/dist/recipes.js +166 -20
- package/dist/recipes.js.map +1 -1
- package/dist/report.json +213 -25
- package/package.json +4 -4
- package/src/recipes.ts +168 -21
package/src/recipes.ts
CHANGED
|
@@ -148,6 +148,14 @@ const roleInk = (role: string): string =>
|
|
|
148
148
|
+ `${ROLE_INK_KEEP[role as keyof typeof roles] ?? 55}%, var(--color-base-content))`;
|
|
149
149
|
|
|
150
150
|
// daisy "tabs-box" flavor: a rounded container, lifted active tab.
|
|
151
|
+
/**
|
|
152
|
+
* The swipe-to-dismiss offset (#293): `createSwipe` publishes the drag as
|
|
153
|
+
* `--swipe-x` / `--swipe-y` on a toast root or a drawer sheet, and this is
|
|
154
|
+
* the one place it is read — composed first into the part's `transform`, so
|
|
155
|
+
* an enter/exit offset or a slide rides on top of it. Unset, it is nothing.
|
|
156
|
+
*/
|
|
157
|
+
const SWIPE = 'translate(var(--swipe-x, 0px), var(--swipe-y, 0px))';
|
|
158
|
+
|
|
151
159
|
/**
|
|
152
160
|
* Enter/exit presence for a top-layer popup.
|
|
153
161
|
*
|
|
@@ -2934,10 +2942,36 @@ const fieldControl: NonNullable<PartStyles['base']> = {
|
|
|
2934
2942
|
};
|
|
2935
2943
|
|
|
2936
2944
|
/**
|
|
2937
|
-
*
|
|
2938
|
-
*
|
|
2945
|
+
* The select trigger's lynx steps — `[inline padding in --size-field units,
|
|
2946
|
+
* font-size step]` — as the size variants set them (`lynxBtnPad` and the
|
|
2947
|
+
* web ramp's `fontSize`). One table, so the clear-trigger's offset below
|
|
2948
|
+
* cannot drift from the trigger it sits in.
|
|
2949
|
+
*/
|
|
2950
|
+
const SELECT_LYNX_STEPS = {
|
|
2951
|
+
xs: [2, 'xs'],
|
|
2952
|
+
sm: [3, 'sm'],
|
|
2953
|
+
md: [4, 'sm'],
|
|
2954
|
+
lg: [5, 'md'],
|
|
2955
|
+
xl: [6, 'lg'],
|
|
2956
|
+
} as const satisfies Record<keyof typeof FIELD_STEPS, readonly [number, string]>;
|
|
2957
|
+
|
|
2958
|
+
/**
|
|
2959
|
+
* Where the lynx clear-trigger's 1.5rem chip sits at one size step
|
|
2960
|
+
* (signalxjs/lynx#1184): centred in the field — the root is exactly the
|
|
2961
|
+
* trigger's height, so half the field less half the chip, from the top —
|
|
2962
|
+
* and one `--space-xs` short of the chevron's 1em box, which sits inside the
|
|
2963
|
+
* trigger's border and end padding at that step's font size. Physical
|
|
2964
|
+
* `top`/`right` and direct `calc(var())` only: lynx resolves no logical
|
|
2965
|
+
* insets on Android and no `min()`, and drops a `var()` that holds a
|
|
2966
|
+
* `calc()`.
|
|
2939
2967
|
*/
|
|
2940
|
-
const
|
|
2968
|
+
const lynxSelectClear = (step: keyof typeof SELECT_LYNX_STEPS): NonNullable<PartStyles['base']> => {
|
|
2969
|
+
const [pad, text] = SELECT_LYNX_STEPS[step];
|
|
2970
|
+
return {
|
|
2971
|
+
top: `calc(var(--size-field) * ${FIELD_STEPS[step] / 2} - 0.75rem)`,
|
|
2972
|
+
right: `calc(var(--border) + var(--size-field) * ${pad} + var(--text-${text}) + var(--space-xs))`,
|
|
2973
|
+
};
|
|
2974
|
+
};
|
|
2941
2975
|
|
|
2942
2976
|
export const select: RecipeInput = {
|
|
2943
2977
|
component: 'select',
|
|
@@ -2997,9 +3031,13 @@ export const select: RecipeInput = {
|
|
|
2997
3031
|
},
|
|
2998
3032
|
indicator: {
|
|
2999
3033
|
base: { opacity: '0.6', transition: 'transform var(--duration-normal) var(--ease-standard)' },
|
|
3000
|
-
states: {
|
|
3001
|
-
|
|
3002
|
-
|
|
3034
|
+
states: {
|
|
3035
|
+
open: { transform: 'rotate(180deg)' },
|
|
3036
|
+
closed: {},
|
|
3037
|
+
// Room for the clear-trigger laid over the field (#280) — the
|
|
3038
|
+
// `clearable` flag the runtime stamps while it renders (#387).
|
|
3039
|
+
clearable: { marginInlineStart: 'calc(var(--space-2xl) + var(--space-sm))' },
|
|
3040
|
+
},
|
|
3003
3041
|
},
|
|
3004
3042
|
// Clears the selection (#280): daisy's ghost-btn over the field's
|
|
3005
3043
|
// inline end, just before the chevron — muted like it, the base-200
|
|
@@ -3144,9 +3182,41 @@ export const select: RecipeInput = {
|
|
|
3144
3182
|
// A touch list has no highlight: the pressed item takes the
|
|
3145
3183
|
// highlighted item's wash.
|
|
3146
3184
|
item: { states: { pressed: { background: 'var(--color-base-200)' } } },
|
|
3185
|
+
// The × and the ▾ get a spacing contract (signalxjs/lynx#1184).
|
|
3186
|
+
// The web offsets the clear-trigger by "the md padding + 1em",
|
|
3187
|
+
// and the 1em is the clear-trigger's own text-sm: at lg/xl the
|
|
3188
|
+
// trigger's padding and chevron both grow, so the × slid onto
|
|
3189
|
+
// the ▾. Here the chevron is a 1em box (right-aligned, so an
|
|
3190
|
+
// unclearable select looks as before) and the clear-trigger a
|
|
3191
|
+
// 1.5rem square (WCAG 2.5.8's target) placed per size beside
|
|
3192
|
+
// it — see `lynxSelectClear`. The web's `min()` height and
|
|
3193
|
+
// `margin-block: auto` centring are dropped on lynx, which
|
|
3194
|
+
// left the box stretched to the field's full height: its
|
|
3195
|
+
// focus ring was a tall pill. The ring is inset, so it hugs
|
|
3196
|
+
// the chip and can never reach the chevron, and no gap shadow
|
|
3197
|
+
// paints past the chip's rounded corners.
|
|
3198
|
+
indicator: {
|
|
3199
|
+
base: { width: '1em', textAlign: 'right' },
|
|
3200
|
+
// The web's room for the chip (`margin-inline-start`) is a
|
|
3201
|
+
// logical spelling Android never resolves, and it is
|
|
3202
|
+
// sized off the web's own offset. Here the chip is a
|
|
3203
|
+
// 1.5rem square one `--space-xs` short of the chevron
|
|
3204
|
+
// at every size, so the room is exactly that — and the
|
|
3205
|
+
// trigger's `gap` stays between the value and the chip.
|
|
3206
|
+
// Before the `clearable` flag the web reached this with
|
|
3207
|
+
// `:has()`, which lynx cannot express: at lg/xl the value
|
|
3208
|
+
// ran under the chip and its focus ring
|
|
3209
|
+
// (signalxjs/lynx#1191).
|
|
3210
|
+
states: { clearable: { marginLeft: 'calc(1.5rem + var(--space-xs))' } },
|
|
3211
|
+
},
|
|
3212
|
+
// The value gives way to the chip instead of running under
|
|
3213
|
+
// it: one line, clipped with an ellipsis — the web's
|
|
3214
|
+
// `nowrap` button text, with a flex item's `min-width: auto`
|
|
3215
|
+
// lifted so it can shrink below its content at all.
|
|
3216
|
+
value: { base: { flexShrink: '1', minWidth: '0', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' } },
|
|
3147
3217
|
'clear-trigger': {
|
|
3148
|
-
base: {
|
|
3149
|
-
states: lynxFocus(),
|
|
3218
|
+
base: { ...lynxSelectClear('md'), width: '1.5rem', height: '1.5rem', minWidth: '1.5rem', boxSizing: 'border-box' },
|
|
3219
|
+
states: lynxFocus({ inset: true }),
|
|
3150
3220
|
},
|
|
3151
3221
|
},
|
|
3152
3222
|
variants: {
|
|
@@ -3155,13 +3225,15 @@ export const select: RecipeInput = {
|
|
|
3155
3225
|
color: Object.fromEntries(ROLES.map((c) => [c, { popup: { base: {
|
|
3156
3226
|
'--select-accent': `var(--color-${c})`,
|
|
3157
3227
|
} } }])),
|
|
3158
|
-
size:
|
|
3228
|
+
size: Object.fromEntries((Object.keys(SELECT_LYNX_STEPS) as (keyof typeof SELECT_LYNX_STEPS)[]).map((step) => [step, {
|
|
3229
|
+
trigger: { base: lynxBtnPad(SELECT_LYNX_STEPS[step][0]) },
|
|
3230
|
+
'clear-trigger': { base: lynxSelectClear(step) },
|
|
3231
|
+
}])),
|
|
3159
3232
|
},
|
|
3160
3233
|
},
|
|
3161
3234
|
},
|
|
3162
3235
|
};
|
|
3163
3236
|
|
|
3164
|
-
|
|
3165
3237
|
/**
|
|
3166
3238
|
* daisy's BUTTON ramp — `.btn`'s fixed height per size step, in `--size-field`
|
|
3167
3239
|
* units, exactly as daisyUI 5 ships it (`components/button.css`: `.btn-xs`
|
|
@@ -3780,6 +3852,8 @@ export const toast: RecipeInput = {
|
|
|
3780
3852
|
states: {
|
|
3781
3853
|
open: { opacity: '1', transform: 'none' },
|
|
3782
3854
|
closed: {},
|
|
3855
|
+
// Styled in `targets.web` — the swipe is web-only (#293).
|
|
3856
|
+
swiping: {},
|
|
3783
3857
|
},
|
|
3784
3858
|
at: {
|
|
3785
3859
|
'reduced-motion': { base: { transition: 'none' }, states: { open: { transform: 'none' } } },
|
|
@@ -3905,6 +3979,22 @@ export const toast: RecipeInput = {
|
|
|
3905
3979
|
defaultVariants: { size: 'md' },
|
|
3906
3980
|
keyframes: { 'zero-daisyui-toast-spin': 'to { transform: rotate(360deg); }' },
|
|
3907
3981
|
targets: {
|
|
3982
|
+
// The swipe (#293) — web only, since the runtime's `--swipe-*` offset
|
|
3983
|
+
// is: composed ahead of the enter/exit offset, and no pan or pinch
|
|
3984
|
+
// starts on a toast, so a touch drag is the swipe's.
|
|
3985
|
+
web: {
|
|
3986
|
+
parts: {
|
|
3987
|
+
root: {
|
|
3988
|
+
base: { transform: `${SWIPE} translateY(var(--toast-from))`, touchAction: 'none' },
|
|
3989
|
+
states: { open: { transform: SWIPE } },
|
|
3990
|
+
selectors: {
|
|
3991
|
+
// Mid-swipe the toast tracks the pointer, not a transition.
|
|
3992
|
+
'&[data-swiping]': { transition: 'none', userSelect: 'none' },
|
|
3993
|
+
},
|
|
3994
|
+
at: { 'reduced-motion': { states: { open: { transform: SWIPE } } } },
|
|
3995
|
+
},
|
|
3996
|
+
},
|
|
3997
|
+
},
|
|
3908
3998
|
lynx: {
|
|
3909
3999
|
parts: {
|
|
3910
4000
|
// The viewport is a full-width strip on lynx (the runtime pins
|
|
@@ -7337,9 +7427,11 @@ export const steps: RecipeInput = {
|
|
|
7337
7427
|
/**
|
|
7338
7428
|
* The modal sheet's slide (#83): in from its edge, back out to it.
|
|
7339
7429
|
*
|
|
7340
|
-
* `translate` is physical, so the travel is a custom property
|
|
7341
|
-
*
|
|
7342
|
-
* and rightward in RTL (the `rtl` hedge, as
|
|
7430
|
+
* `translate` is physical, so the travel is a custom property — the whole
|
|
7431
|
+
* `x y` pair — that flips with the placement AND the direction: off the
|
|
7432
|
+
* reading start is leftward in LTR and rightward in RTL (the `rtl` hedge, as
|
|
7433
|
+
* everywhere here), while a `top` / `bottom` sheet travels on Y and mirrors
|
|
7434
|
+
* in neither (#291). Keyed on
|
|
7343
7435
|
* `data-l-dock="sheet"`, the regime, which holds through the exit where
|
|
7344
7436
|
* `:modal` does not, so the slide-out leaves from the sheet's own box.
|
|
7345
7437
|
* Opacity stays at 1: the travel is the transition. Each direction rides the
|
|
@@ -7350,19 +7442,23 @@ const sheetSlide = (enter: string, exit: string): PartStyles => {
|
|
|
7350
7442
|
const open = `${sheet}[data-state="open"]`;
|
|
7351
7443
|
const travel = (tempo: string): string => {
|
|
7352
7444
|
const duration = tempo.split(' ')[0];
|
|
7353
|
-
|
|
7445
|
+
// `transform` rides along for the swipe's spring back (#293).
|
|
7446
|
+
return `translate ${tempo}, transform ${tempo}, display ${duration} allow-discrete, overlay ${duration} allow-discrete`;
|
|
7354
7447
|
};
|
|
7355
7448
|
return {
|
|
7356
|
-
base: { '--drawer-travel': '-100%' },
|
|
7449
|
+
base: { '--drawer-travel': '-100% 0' },
|
|
7357
7450
|
selectors: {
|
|
7358
|
-
'&[data-placement="end"]': { '--drawer-travel': '100%' },
|
|
7359
|
-
[`&[data-placement="start"]${rtl}`]: { '--drawer-travel': '100%' },
|
|
7360
|
-
[`&[data-placement="end"]${rtl}`]: { '--drawer-travel': '-100%' },
|
|
7361
|
-
|
|
7451
|
+
'&[data-placement="end"]': { '--drawer-travel': '100% 0' },
|
|
7452
|
+
[`&[data-placement="start"]${rtl}`]: { '--drawer-travel': '100% 0' },
|
|
7453
|
+
[`&[data-placement="end"]${rtl}`]: { '--drawer-travel': '-100% 0' },
|
|
7454
|
+
// The block edges travel on Y, and no direction mirrors them (#291).
|
|
7455
|
+
'&[data-placement="top"]': { '--drawer-travel': '0 -100%' },
|
|
7456
|
+
'&[data-placement="bottom"]': { '--drawer-travel': '0 100%' },
|
|
7457
|
+
[sheet]: { opacity: '1', translate: 'var(--drawer-travel)', transition: travel(exit) },
|
|
7362
7458
|
[open]: { translate: 'none', transition: travel(enter) },
|
|
7363
7459
|
},
|
|
7364
7460
|
at: {
|
|
7365
|
-
'starting-style': { selectors: { [open]: { opacity: '1', translate: 'var(--drawer-travel)
|
|
7461
|
+
'starting-style': { selectors: { [open]: { opacity: '1', translate: 'var(--drawer-travel)' } } },
|
|
7366
7462
|
'reduced-motion': { selectors: { [sheet]: { transition: 'none' }, [open]: { transition: 'none' } } },
|
|
7367
7463
|
},
|
|
7368
7464
|
};
|
|
@@ -7432,6 +7528,38 @@ export const drawer: RecipeInput = {
|
|
|
7432
7528
|
},
|
|
7433
7529
|
'&[data-placement="start"][data-l-dock="sheet"]': { insetInlineStart: '0', insetInlineEnd: 'auto' },
|
|
7434
7530
|
'&[data-placement="end"][data-l-dock="sheet"]': { insetInlineStart: 'auto', insetInlineEnd: '0' },
|
|
7531
|
+
/**
|
|
7532
|
+
* The block edges (#291): a sheet across the viewport's width,
|
|
7533
|
+
* pinned with `inset-block-*` — nothing here mirrors in RTL. Its
|
|
7534
|
+
* height is this recipe's: content-sized up to most of the
|
|
7535
|
+
* viewport, so the scrim stays in reach. Full width by default —
|
|
7536
|
+
* `measure` still caps the INLINE size (centred by the auto
|
|
7537
|
+
* margins), which the `:where()` keeps below the layout step
|
|
7538
|
+
* table's specificity whatever order the files load in.
|
|
7539
|
+
*/
|
|
7540
|
+
'&:where([data-placement="top"], [data-placement="bottom"])': { '--l-measure': 'none' },
|
|
7541
|
+
'&[data-placement="top"][data-l-dock="sheet"]': {
|
|
7542
|
+
insetBlockStart: '0',
|
|
7543
|
+
insetBlockEnd: 'auto',
|
|
7544
|
+
insetInlineStart: '0',
|
|
7545
|
+
insetInlineEnd: '0',
|
|
7546
|
+
marginInline: 'auto',
|
|
7547
|
+
blockSize: 'auto',
|
|
7548
|
+
maxBlockSize: '85dvh',
|
|
7549
|
+
borderEndStartRadius: 'var(--radius-box)',
|
|
7550
|
+
borderEndEndRadius: 'var(--radius-box)',
|
|
7551
|
+
},
|
|
7552
|
+
'&[data-placement="bottom"][data-l-dock="sheet"]': {
|
|
7553
|
+
insetBlockStart: 'auto',
|
|
7554
|
+
insetBlockEnd: '0',
|
|
7555
|
+
insetInlineStart: '0',
|
|
7556
|
+
insetInlineEnd: '0',
|
|
7557
|
+
marginInline: 'auto',
|
|
7558
|
+
blockSize: 'auto',
|
|
7559
|
+
maxBlockSize: '85dvh',
|
|
7560
|
+
borderStartStartRadius: 'var(--radius-box)',
|
|
7561
|
+
borderStartEndRadius: 'var(--radius-box)',
|
|
7562
|
+
},
|
|
7435
7563
|
},
|
|
7436
7564
|
}),
|
|
7437
7565
|
backdrop: {
|
|
@@ -7453,8 +7581,27 @@ export const drawer: RecipeInput = {
|
|
|
7453
7581
|
// Trigger-carried axes — see `btnColors` for why the panel is out of
|
|
7454
7582
|
// reach and the trigger is the whole story here.
|
|
7455
7583
|
variants: { color: btnColors(), size: btnSizes },
|
|
7456
|
-
// The btn paddings, restated physically — see `lynxBtnPad` (#1084).
|
|
7457
7584
|
targets: {
|
|
7585
|
+
// Swipe to dismiss (#293) — web only, since the runtime's `--swipe-*`
|
|
7586
|
+
// offset is: the sheet wears the drag offset (`SWIPE`) in every
|
|
7587
|
+
// state — so a swiped sheet leaves from where it was let go — at a
|
|
7588
|
+
// weight above the presence's own open `transform`. Mid-swipe no
|
|
7589
|
+
// transition runs. A touch pan across the dismiss axis stays the
|
|
7590
|
+
// page's; along it is the gesture's, so content taller than a
|
|
7591
|
+
// block-edge sheet scrolls in a box of its own inside the panel.
|
|
7592
|
+
web: {
|
|
7593
|
+
parts: {
|
|
7594
|
+
panel: {
|
|
7595
|
+
selectors: {
|
|
7596
|
+
'&[data-l-dock="sheet"][data-state]': { transform: SWIPE },
|
|
7597
|
+
'&[data-l-dock="sheet"][data-state="open"][data-swiping]': { transition: 'none', userSelect: 'none' },
|
|
7598
|
+
'&[data-l-dock="sheet"]:where([data-placement="start"], [data-placement="end"])': { touchAction: 'pan-y' },
|
|
7599
|
+
'&[data-l-dock="sheet"]:where([data-placement="top"], [data-placement="bottom"])': { touchAction: 'pan-x' },
|
|
7600
|
+
},
|
|
7601
|
+
},
|
|
7602
|
+
},
|
|
7603
|
+
},
|
|
7604
|
+
// The btn paddings, restated physically — see `lynxBtnPad` (#1084).
|
|
7458
7605
|
lynx: {
|
|
7459
7606
|
parts: {
|
|
7460
7607
|
trigger: { base: lynxBtnPad(4) },
|