@sigx/zero-daisyui 0.10.0 → 0.12.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 +5 -0
- package/dist/audit.json +458 -3
- package/dist/css/components/drawer.css +19 -2
- package/dist/css/components/radio-group.css +6 -0
- package/dist/css/components/select.css +1 -1
- package/dist/css/components/toast.css +9 -3
- package/dist/css/index.css +35 -6
- package/dist/lynx/components/checkbox.css +4 -2
- package/dist/lynx/components/drawer.css +2 -2
- package/dist/lynx/components/fieldset.css +10 -1
- package/dist/lynx/components/input.css +40 -2
- package/dist/lynx/components/number-input.css +18 -3
- package/dist/lynx/components/radio-group.css +10 -2
- package/dist/lynx/components/select.css +12 -0
- package/dist/lynx/components/textarea.css +23 -2
- package/dist/lynx/components/toggle-group.css +41 -2
- package/dist/lynx/components/toggle.css +27 -2
- package/dist/lynx/index.css +187 -18
- package/dist/lynx/manifest.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/recipes.d.ts.map +1 -1
- package/dist/recipes.js +350 -19
- package/dist/recipes.js.map +1 -1
- package/dist/report.json +34 -37
- package/package.json +4 -4
- package/src/recipes.ts +352 -21
package/dist/recipes.js
CHANGED
|
@@ -129,6 +129,13 @@ const ROLE_INK_KEEP = {
|
|
|
129
129
|
const roleInk = (role) => `color-mix(in oklab, var(--color-${role}) `
|
|
130
130
|
+ `${ROLE_INK_KEEP[role] ?? 55}%, var(--color-base-content))`;
|
|
131
131
|
// daisy "tabs-box" flavor: a rounded container, lifted active tab.
|
|
132
|
+
/**
|
|
133
|
+
* The swipe-to-dismiss offset (#293): `createSwipe` publishes the drag as
|
|
134
|
+
* `--swipe-x` / `--swipe-y` on a toast root or a drawer sheet, and this is
|
|
135
|
+
* the one place it is read — composed first into the part's `transform`, so
|
|
136
|
+
* an enter/exit offset or a slide rides on top of it. Unset, it is nothing.
|
|
137
|
+
*/
|
|
138
|
+
const SWIPE = 'translate(var(--swipe-x, 0px), var(--swipe-y, 0px))';
|
|
132
139
|
/**
|
|
133
140
|
* Enter/exit presence for a top-layer popup.
|
|
134
141
|
*
|
|
@@ -1614,6 +1621,10 @@ export const field = {
|
|
|
1614
1621
|
label: {
|
|
1615
1622
|
base: { fontSize: 'var(--text-sm)', fontWeight: 'var(--weight-semibold)', color: 'var(--field-accent)' },
|
|
1616
1623
|
states: { disabled: { opacity: 'var(--disabled-opacity)' } },
|
|
1624
|
+
// lynx has no pseudo-elements and the anatomy no part to carry
|
|
1625
|
+
// the asterisk, so it stays a web-only mark: on lynx a required
|
|
1626
|
+
// field still stamps `required` on its root and label, and the
|
|
1627
|
+
// control inside adopts it (signalxjs/lynx#1205).
|
|
1617
1628
|
selectors: {
|
|
1618
1629
|
'&[data-required]::after': { content: '" *"', color: roleInk('error') },
|
|
1619
1630
|
},
|
|
@@ -1704,6 +1715,33 @@ export const fieldset = {
|
|
|
1704
1715
|
xl: { legend: { base: { fontSize: 'var(--text-lg)' } } },
|
|
1705
1716
|
},
|
|
1706
1717
|
},
|
|
1718
|
+
// Lynx has no grid: the one-column track becomes a flex column (the gap
|
|
1719
|
+
// survives), and the block/inline paddings are restated physically —
|
|
1720
|
+
// logical spellings resolve on iOS but not on Android (signalxjs/lynx#1084).
|
|
1721
|
+
targets: {
|
|
1722
|
+
lynx: {
|
|
1723
|
+
parts: {
|
|
1724
|
+
root: {
|
|
1725
|
+
base: {
|
|
1726
|
+
display: 'flex',
|
|
1727
|
+
flexDirection: 'column',
|
|
1728
|
+
paddingTop: 'var(--space-xs)',
|
|
1729
|
+
paddingBottom: 'var(--space-xs)',
|
|
1730
|
+
paddingLeft: '0',
|
|
1731
|
+
paddingRight: '0',
|
|
1732
|
+
},
|
|
1733
|
+
},
|
|
1734
|
+
legend: {
|
|
1735
|
+
base: {
|
|
1736
|
+
paddingTop: 'var(--space-sm)',
|
|
1737
|
+
paddingBottom: 'var(--space-sm)',
|
|
1738
|
+
paddingLeft: '0',
|
|
1739
|
+
paddingRight: '0',
|
|
1740
|
+
},
|
|
1741
|
+
},
|
|
1742
|
+
},
|
|
1743
|
+
},
|
|
1744
|
+
},
|
|
1707
1745
|
};
|
|
1708
1746
|
/**
|
|
1709
1747
|
* daisy's tick, drawn by a clip-path that GROWS.
|
|
@@ -1932,11 +1970,25 @@ export const checkbox = {
|
|
|
1932
1970
|
targets: {
|
|
1933
1971
|
lynx: {
|
|
1934
1972
|
parts: {
|
|
1973
|
+
// The box/label row, pinned: `inline-flex` is rewritten to
|
|
1974
|
+
// `flex`, and the row must not depend on the engine's
|
|
1975
|
+
// default direction (signalxjs/lynx#1203).
|
|
1976
|
+
root: { base: { display: 'flex', flexDirection: 'row' } },
|
|
1935
1977
|
control: {
|
|
1936
1978
|
// The web fallback (`color-mix(in oklab, … currentColor …)`)
|
|
1937
1979
|
// exists for consumers that unset the accent; this package
|
|
1938
1980
|
// always defines it, so the plain accent IS the ring.
|
|
1939
|
-
|
|
1981
|
+
//
|
|
1982
|
+
// `inline-block` is not a lynx display value (no inline
|
|
1983
|
+
// formatting context); a flex box keeps daisy's geometry —
|
|
1984
|
+
// the padding insets the 100%-sized indicator either way.
|
|
1985
|
+
base: { display: 'flex', border: 'var(--border) solid var(--checkbox-accent)' },
|
|
1986
|
+
// The ring as spread shadows that follow the box's radius
|
|
1987
|
+
// (signalxjs/lynx#1163 — lynx's `outline` ignores it and
|
|
1988
|
+
// has no offset), keeping the box's inset depth line.
|
|
1989
|
+
states: {
|
|
1990
|
+
'focus-visible': lynxFocusRing('var(--checkbox-accent)', { under: '0 1px var(--depth-shade) inset' }),
|
|
1991
|
+
},
|
|
1940
1992
|
},
|
|
1941
1993
|
indicator: {
|
|
1942
1994
|
// The tick's fill: the control's `color:` names
|
|
@@ -1982,6 +2034,11 @@ export const radioGroup = {
|
|
|
1982
2034
|
// `invalid` paints on each `item-control`, which carries the flag
|
|
1983
2035
|
// itself (#267) — the root only groups the items.
|
|
1984
2036
|
states: { invalid: {}, required: {} },
|
|
2037
|
+
// `orientation="horizontal"` lays the items in a wrapping row —
|
|
2038
|
+
// checkbox-group's rule (signalxjs/zero#393).
|
|
2039
|
+
selectors: {
|
|
2040
|
+
'&[data-orientation="horizontal"]': { flexDirection: 'row', flexWrap: 'wrap', columnGap: 'var(--space-lg)' },
|
|
2041
|
+
},
|
|
1985
2042
|
},
|
|
1986
2043
|
label: {
|
|
1987
2044
|
base: { fontSize: 'var(--text-sm)', fontWeight: 'var(--weight-semibold)' },
|
|
@@ -2089,9 +2146,20 @@ export const radioGroup = {
|
|
|
2089
2146
|
targets: {
|
|
2090
2147
|
lynx: {
|
|
2091
2148
|
parts: {
|
|
2149
|
+
// The control/label row, pinned — as checkbox's root
|
|
2150
|
+
// (signalxjs/lynx#1203).
|
|
2151
|
+
item: { base: { display: 'flex', flexDirection: 'row' } },
|
|
2092
2152
|
'item-control': {
|
|
2093
|
-
|
|
2094
|
-
|
|
2153
|
+
// `display: flex` in place of `inline-block`, which lynx
|
|
2154
|
+
// does not have — the padding still insets the dot.
|
|
2155
|
+
base: { display: 'flex', border: 'var(--border) solid var(--radio-accent)' },
|
|
2156
|
+
states: {
|
|
2157
|
+
checked: { borderColor: 'var(--radio-accent)' },
|
|
2158
|
+
// The round ring (signalxjs/lynx#1163): spread
|
|
2159
|
+
// shadows follow the 9999px radius where `outline`
|
|
2160
|
+
// drew a square.
|
|
2161
|
+
'focus-visible': lynxFocusRing('var(--radio-accent)', { under: '0 1px var(--depth-shade) inset' }),
|
|
2162
|
+
},
|
|
2095
2163
|
},
|
|
2096
2164
|
'item-indicator': {
|
|
2097
2165
|
states: { checked: { backgroundColor: 'var(--radio-accent)' } },
|
|
@@ -2846,11 +2914,6 @@ const fieldControl = {
|
|
|
2846
2914
|
borderRadius: 'var(--radius-field)',
|
|
2847
2915
|
boxShadow: 'var(--shadow-xs)',
|
|
2848
2916
|
};
|
|
2849
|
-
/**
|
|
2850
|
-
* A select whose clear-trigger is rendered (#280) — anchored on the root, so
|
|
2851
|
-
* a part inside the trigger can make room for the button laid over it.
|
|
2852
|
-
*/
|
|
2853
|
-
const SELECT_CLEARABLE = '[data-scope="select"][data-part="root"]:has(> [data-scope="select"][data-part="clear-trigger"]) &';
|
|
2854
2917
|
/**
|
|
2855
2918
|
* The select trigger's lynx steps — `[inline padding in --size-field units,
|
|
2856
2919
|
* font-size step]` — as the size variants set them (`lynxBtnPad` and the
|
|
@@ -2939,9 +3002,13 @@ export const select = {
|
|
|
2939
3002
|
},
|
|
2940
3003
|
indicator: {
|
|
2941
3004
|
base: { opacity: '0.6', transition: 'transform var(--duration-normal) var(--ease-standard)' },
|
|
2942
|
-
states: {
|
|
2943
|
-
|
|
2944
|
-
|
|
3005
|
+
states: {
|
|
3006
|
+
open: { transform: 'rotate(180deg)' },
|
|
3007
|
+
closed: {},
|
|
3008
|
+
// Room for the clear-trigger laid over the field (#280) — the
|
|
3009
|
+
// `clearable` flag the runtime stamps while it renders (#387).
|
|
3010
|
+
clearable: { marginInlineStart: 'calc(var(--space-2xl) + var(--space-sm))' },
|
|
3011
|
+
},
|
|
2945
3012
|
},
|
|
2946
3013
|
// Clears the selection (#280): daisy's ghost-btn over the field's
|
|
2947
3014
|
// inline end, just before the chevron — muted like it, the base-200
|
|
@@ -3099,7 +3166,25 @@ export const select = {
|
|
|
3099
3166
|
// focus ring was a tall pill. The ring is inset, so it hugs
|
|
3100
3167
|
// the chip and can never reach the chevron, and no gap shadow
|
|
3101
3168
|
// paints past the chip's rounded corners.
|
|
3102
|
-
indicator: {
|
|
3169
|
+
indicator: {
|
|
3170
|
+
base: { width: '1em', textAlign: 'right' },
|
|
3171
|
+
// The web's room for the chip (`margin-inline-start`) is a
|
|
3172
|
+
// logical spelling Android never resolves, and it is
|
|
3173
|
+
// sized off the web's own offset. Here the chip is a
|
|
3174
|
+
// 1.5rem square one `--space-xs` short of the chevron
|
|
3175
|
+
// at every size, so the room is exactly that — and the
|
|
3176
|
+
// trigger's `gap` stays between the value and the chip.
|
|
3177
|
+
// Before the `clearable` flag the web reached this with
|
|
3178
|
+
// `:has()`, which lynx cannot express: at lg/xl the value
|
|
3179
|
+
// ran under the chip and its focus ring
|
|
3180
|
+
// (signalxjs/lynx#1191).
|
|
3181
|
+
states: { clearable: { marginLeft: 'calc(1.5rem + var(--space-xs))' } },
|
|
3182
|
+
},
|
|
3183
|
+
// The value gives way to the chip instead of running under
|
|
3184
|
+
// it: one line, clipped with an ellipsis — the web's
|
|
3185
|
+
// `nowrap` button text, with a flex item's `min-width: auto`
|
|
3186
|
+
// lifted so it can shrink below its content at all.
|
|
3187
|
+
value: { base: { flexShrink: '1', minWidth: '0', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' } },
|
|
3103
3188
|
'clear-trigger': {
|
|
3104
3189
|
base: { ...lynxSelectClear('md'), width: '1.5rem', height: '1.5rem', minWidth: '1.5rem', boxSizing: 'border-box' },
|
|
3105
3190
|
states: lynxFocus({ inset: true }),
|
|
@@ -3725,6 +3810,8 @@ export const toast = {
|
|
|
3725
3810
|
states: {
|
|
3726
3811
|
open: { opacity: '1', transform: 'none' },
|
|
3727
3812
|
closed: {},
|
|
3813
|
+
// Styled in `targets.web` — the swipe is web-only (#293).
|
|
3814
|
+
swiping: {},
|
|
3728
3815
|
},
|
|
3729
3816
|
at: {
|
|
3730
3817
|
'reduced-motion': { base: { transition: 'none' }, states: { open: { transform: 'none' } } },
|
|
@@ -3850,6 +3937,22 @@ export const toast = {
|
|
|
3850
3937
|
defaultVariants: { size: 'md' },
|
|
3851
3938
|
keyframes: { 'zero-daisyui-toast-spin': 'to { transform: rotate(360deg); }' },
|
|
3852
3939
|
targets: {
|
|
3940
|
+
// The swipe (#293) — web only, since the runtime's `--swipe-*` offset
|
|
3941
|
+
// is: composed ahead of the enter/exit offset, and no pan or pinch
|
|
3942
|
+
// starts on a toast, so a touch drag is the swipe's.
|
|
3943
|
+
web: {
|
|
3944
|
+
parts: {
|
|
3945
|
+
root: {
|
|
3946
|
+
base: { transform: `${SWIPE} translateY(var(--toast-from))`, touchAction: 'none' },
|
|
3947
|
+
states: { open: { transform: SWIPE } },
|
|
3948
|
+
selectors: {
|
|
3949
|
+
// Mid-swipe the toast tracks the pointer, not a transition.
|
|
3950
|
+
'&[data-swiping]': { transition: 'none', userSelect: 'none' },
|
|
3951
|
+
},
|
|
3952
|
+
at: { 'reduced-motion': { states: { open: { transform: SWIPE } } } },
|
|
3953
|
+
},
|
|
3954
|
+
},
|
|
3955
|
+
},
|
|
3853
3956
|
lynx: {
|
|
3854
3957
|
parts: {
|
|
3855
3958
|
// The viewport is a full-width strip on lynx (the runtime pins
|
|
@@ -4245,6 +4348,45 @@ export const toggle = {
|
|
|
4245
4348
|
},
|
|
4246
4349
|
},
|
|
4247
4350
|
defaultVariants: { color: 'primary', size: 'md' },
|
|
4351
|
+
// signalxjs/lynx#1204 — the lynx replacements for what this recipe's
|
|
4352
|
+
// shared sections cannot say there.
|
|
4353
|
+
targets: {
|
|
4354
|
+
lynx: {
|
|
4355
|
+
parts: {
|
|
4356
|
+
root: {
|
|
4357
|
+
// daisy's content-sized, never-squeezed btn (lynx#1165):
|
|
4358
|
+
// a lynx view has no inline formatting context, so the
|
|
4359
|
+
// toggle stretched to its column and a squeezed label
|
|
4360
|
+
// wrapped per character. The glyph + label sit in a row.
|
|
4361
|
+
// The hairline as longhands: a var-bearing `border`
|
|
4362
|
+
// shorthand expands after the cascade and would beat
|
|
4363
|
+
// any edge a later rule restates (lynx#1161/#1162).
|
|
4364
|
+
base: {
|
|
4365
|
+
...lynxBtnFit,
|
|
4366
|
+
flexDirection: 'row',
|
|
4367
|
+
border: '0 solid transparent',
|
|
4368
|
+
...lynxSides('border{}Width', 'var(--border)'),
|
|
4369
|
+
...lynxSides('border{}Color', 'var(--color-base-300)'),
|
|
4370
|
+
},
|
|
4371
|
+
states: {
|
|
4372
|
+
// No hover on a touch platform: the held toggle
|
|
4373
|
+
// takes the wash daisy's hover gives it. The shared
|
|
4374
|
+
// pressed rule adds the btn's 1px sink.
|
|
4375
|
+
pressed: { background: 'var(--color-base-300)' },
|
|
4376
|
+
on: lynxSides('border{}Color', 'var(--toggle-accent)'),
|
|
4377
|
+
// lynx's `outline` ignores the radius and has no
|
|
4378
|
+
// offset (lynx#1163): the ring as spread shadows.
|
|
4379
|
+
'focus-visible': lynxFocusRing('var(--toggle-accent)'),
|
|
4380
|
+
},
|
|
4381
|
+
selectors: {
|
|
4382
|
+
// A held on toggle keeps its fill (the web's
|
|
4383
|
+
// `[data-state=on]:hover` stays on the accent too).
|
|
4384
|
+
'&[data-state="on"][data-pressed]': { background: 'var(--toggle-accent)' },
|
|
4385
|
+
},
|
|
4386
|
+
},
|
|
4387
|
+
},
|
|
4388
|
+
},
|
|
4389
|
+
},
|
|
4248
4390
|
};
|
|
4249
4391
|
// daisy "join" of btns: one bordered capsule, hairline seams between items,
|
|
4250
4392
|
// the on item filled with the accent.
|
|
@@ -4353,6 +4495,65 @@ export const toggleGroup = {
|
|
|
4353
4495
|
])),
|
|
4354
4496
|
},
|
|
4355
4497
|
defaultVariants: { color: 'primary' },
|
|
4498
|
+
// signalxjs/lynx#1204 — the lynx replacements for what this recipe's
|
|
4499
|
+
// shared sections cannot say there.
|
|
4500
|
+
targets: {
|
|
4501
|
+
lynx: {
|
|
4502
|
+
parts: {
|
|
4503
|
+
root: {
|
|
4504
|
+
// Content-sized like the web's inline-flex capsule (a
|
|
4505
|
+
// lynx view stretches to its column otherwise), a row
|
|
4506
|
+
// unless vertical, and the frame as longhands so the
|
|
4507
|
+
// orientation rules below can drop one edge by
|
|
4508
|
+
// specificity (a var-bearing `border` shorthand would
|
|
4509
|
+
// expand over them, lynx#1161/#1162).
|
|
4510
|
+
base: {
|
|
4511
|
+
width: 'max-content',
|
|
4512
|
+
flexShrink: '0',
|
|
4513
|
+
flexDirection: 'row',
|
|
4514
|
+
border: '0 solid transparent',
|
|
4515
|
+
...lynxSides('border{}Width', 'var(--border)'),
|
|
4516
|
+
...lynxSides('border{}Color', 'var(--color-base-300)'),
|
|
4517
|
+
},
|
|
4518
|
+
selectors: {
|
|
4519
|
+
// The join seams: lynx has no sibling combinator, so
|
|
4520
|
+
// the web's `item + item` edge cannot be selected.
|
|
4521
|
+
// Every item draws its leading seam instead (below),
|
|
4522
|
+
// and the frame gives up that edge — the first item's
|
|
4523
|
+
// seam stands in for it, inside the frame's clip.
|
|
4524
|
+
'&[data-orientation="horizontal"]': { borderLeftWidth: '0' },
|
|
4525
|
+
'&[data-orientation="vertical"]': { borderTopWidth: '0' },
|
|
4526
|
+
},
|
|
4527
|
+
},
|
|
4528
|
+
item: {
|
|
4529
|
+
base: { flexShrink: '0', flexWrap: 'nowrap' },
|
|
4530
|
+
states: {
|
|
4531
|
+
// No hover on a touch platform: a held item takes the
|
|
4532
|
+
// wash daisy's hover gives it; an on item keeps its
|
|
4533
|
+
// fill (the selector below).
|
|
4534
|
+
pressed: { background: 'var(--color-base-300)' },
|
|
4535
|
+
// The frame clips its items, so the ring is drawn
|
|
4536
|
+
// inside the item (lynx's `outline` has no offset
|
|
4537
|
+
// and ignores the radius, lynx#1163).
|
|
4538
|
+
'focus-visible': lynxFocusRing('var(--toggle-group-accent)', { inset: true }),
|
|
4539
|
+
},
|
|
4540
|
+
selectors: {
|
|
4541
|
+
'&[data-state="on"][data-pressed]': { background: 'var(--toggle-group-accent)' },
|
|
4542
|
+
'&[data-orientation="horizontal"]': {
|
|
4543
|
+
borderLeftWidth: 'var(--border)',
|
|
4544
|
+
borderLeftStyle: 'solid',
|
|
4545
|
+
borderLeftColor: 'var(--color-base-300)',
|
|
4546
|
+
},
|
|
4547
|
+
'&[data-orientation="vertical"]': {
|
|
4548
|
+
borderTopWidth: 'var(--border)',
|
|
4549
|
+
borderTopStyle: 'solid',
|
|
4550
|
+
borderTopColor: 'var(--color-base-300)',
|
|
4551
|
+
},
|
|
4552
|
+
},
|
|
4553
|
+
},
|
|
4554
|
+
},
|
|
4555
|
+
},
|
|
4556
|
+
},
|
|
4356
4557
|
};
|
|
4357
4558
|
// daisy "join" of an input and two btns: one bordered capsule (the control),
|
|
4358
4559
|
// hairline seams on the triggers' inner edges, neutral btn fills for the steppers.
|
|
@@ -4496,14 +4697,53 @@ export const numberInput = {
|
|
|
4496
4697
|
xl: { control: { base: { height: fieldHeight('xl') } }, input: { base: { fontSize: 'var(--text-lg)', padding: 'var(--space-lg) var(--space-xl)' } } },
|
|
4497
4698
|
},
|
|
4498
4699
|
},
|
|
4499
|
-
//
|
|
4500
|
-
//
|
|
4501
|
-
//
|
|
4700
|
+
// Lynx restatements:
|
|
4701
|
+
// - the steppers' inline padding and their seams, physically: logical
|
|
4702
|
+
// spellings resolve on iOS but not on Android (measured,
|
|
4703
|
+
// signalxjs/lynx#1084);
|
|
4704
|
+
// - the steppers are views around a text glyph, with none of a
|
|
4705
|
+
// button's content centering;
|
|
4706
|
+
// - the native input takes no `inherit`: its ink is spelled out, and it
|
|
4707
|
+
// grows into any room a stretched control leaves between the steppers;
|
|
4708
|
+
// - the web root is inline-flex and hugs its content; lynx's flex column
|
|
4709
|
+
// stretches, so the children align to the start instead;
|
|
4710
|
+
// - the focus ring is `lynxFocusRing` (lynx's outline ignores the radius
|
|
4711
|
+
// and has no offset, signalxjs/lynx#1163). A shadow must not be
|
|
4712
|
+
// clipped by the box's own `overflow: hidden`, so the control stops
|
|
4713
|
+
// clipping and the steppers round their own outer corners instead.
|
|
4502
4714
|
targets: {
|
|
4503
4715
|
lynx: {
|
|
4504
4716
|
parts: {
|
|
4505
|
-
|
|
4506
|
-
|
|
4717
|
+
root: { base: { alignItems: 'flex-start' } },
|
|
4718
|
+
control: {
|
|
4719
|
+
base: { overflow: 'visible' },
|
|
4720
|
+
states: { 'focus-visible': lynxFocusRing('var(--number-input-accent)') },
|
|
4721
|
+
},
|
|
4722
|
+
input: { base: { color: 'var(--color-base-content)', flexGrow: '1' } },
|
|
4723
|
+
'increment-trigger': {
|
|
4724
|
+
base: {
|
|
4725
|
+
display: 'flex',
|
|
4726
|
+
alignItems: 'center',
|
|
4727
|
+
justifyContent: 'center',
|
|
4728
|
+
paddingLeft: 'var(--space-lg)',
|
|
4729
|
+
paddingRight: 'var(--space-lg)',
|
|
4730
|
+
borderLeft: 'var(--border) solid var(--color-base-300)',
|
|
4731
|
+
borderTopRightRadius: 'var(--radius-field)',
|
|
4732
|
+
borderBottomRightRadius: 'var(--radius-field)',
|
|
4733
|
+
},
|
|
4734
|
+
},
|
|
4735
|
+
'decrement-trigger': {
|
|
4736
|
+
base: {
|
|
4737
|
+
display: 'flex',
|
|
4738
|
+
alignItems: 'center',
|
|
4739
|
+
justifyContent: 'center',
|
|
4740
|
+
paddingLeft: 'var(--space-lg)',
|
|
4741
|
+
paddingRight: 'var(--space-lg)',
|
|
4742
|
+
borderRight: 'var(--border) solid var(--color-base-300)',
|
|
4743
|
+
borderTopLeftRadius: 'var(--radius-field)',
|
|
4744
|
+
borderBottomLeftRadius: 'var(--radius-field)',
|
|
4745
|
+
},
|
|
4746
|
+
},
|
|
4507
4747
|
},
|
|
4508
4748
|
},
|
|
4509
4749
|
},
|
|
@@ -4906,6 +5146,14 @@ const affixSize = (fontSize) => ({
|
|
|
4906
5146
|
'clear-trigger': { base: { fontSize } },
|
|
4907
5147
|
'visibility-trigger': { base: { fontSize } },
|
|
4908
5148
|
});
|
|
5149
|
+
/**
|
|
5150
|
+
* A text field's placeholder ink on lynx (signalxjs/lynx#1205): the web's
|
|
5151
|
+
* `::placeholder` mix, for lynx's `-x-placeholder-color` property — the
|
|
5152
|
+
* emitter bakes the `color-mix()` to one literal per theme.
|
|
5153
|
+
*/
|
|
5154
|
+
const textFieldPlaceholder = 'color-mix(in oklab, var(--color-base-content) 60%, transparent)';
|
|
5155
|
+
/** The ghost field button's held look on lynx — the web's hover wash, on a press. */
|
|
5156
|
+
const fieldButtonHeld = { color: 'var(--color-base-content)', background: 'var(--color-base-200)' };
|
|
4909
5157
|
/**
|
|
4910
5158
|
* daisy "input" flavor: the shared field box with nothing in it but the text.
|
|
4911
5159
|
* Same `fieldControl` metrics as select's trigger, combobox's control and the
|
|
@@ -5027,6 +5275,53 @@ export const input = {
|
|
|
5027
5275
|
xl: { control: { base: { height: fieldHeight('xl') } }, input: { base: { fontSize: 'var(--text-lg)', padding: 'var(--space-lg) var(--space-xl)' } }, ...affixSize('var(--text-lg)') },
|
|
5028
5276
|
},
|
|
5029
5277
|
},
|
|
5278
|
+
// lynx (signalxjs/lynx#1205). The field is a native text widget inside
|
|
5279
|
+
// a view `control`, so what the web gets from the cascade is restated:
|
|
5280
|
+
targets: {
|
|
5281
|
+
lynx: {
|
|
5282
|
+
parts: {
|
|
5283
|
+
// The web control is an `inline-flex` row; the emitter's
|
|
5284
|
+
// `flex` rewrite keeps no direction, so the row is explicit.
|
|
5285
|
+
// No `:hover` border on a touch platform — the ring below
|
|
5286
|
+
// (box-shadow spread, signalxjs/lynx#1163) is the focus cue,
|
|
5287
|
+
// in the root's accent like the web outline.
|
|
5288
|
+
control: {
|
|
5289
|
+
base: { flexDirection: 'row' },
|
|
5290
|
+
states: { 'focus-visible': lynxFocusRing('var(--input-accent)') },
|
|
5291
|
+
},
|
|
5292
|
+
// `color: inherit` never reaches a native text field, and
|
|
5293
|
+
// `::placeholder` does not exist: the ink is explicit and the
|
|
5294
|
+
// placeholder takes lynx's own `-x-placeholder-color`, the
|
|
5295
|
+
// web's 60% mix baked per theme.
|
|
5296
|
+
input: {
|
|
5297
|
+
base: {
|
|
5298
|
+
color: 'var(--color-base-content)',
|
|
5299
|
+
'-x-placeholder-color': textFieldPlaceholder,
|
|
5300
|
+
flexGrow: '1',
|
|
5301
|
+
flexShrink: '1',
|
|
5302
|
+
},
|
|
5303
|
+
},
|
|
5304
|
+
// The adornment's edge padding, physical: Android never
|
|
5305
|
+
// resolves the logical spellings (signalxjs/lynx#1084).
|
|
5306
|
+
adornment: {
|
|
5307
|
+
selectors: {
|
|
5308
|
+
'&[data-placement="start"]': { paddingLeft: 'var(--space-md)' },
|
|
5309
|
+
'&[data-placement="end"]': { paddingRight: 'var(--space-md)' },
|
|
5310
|
+
},
|
|
5311
|
+
},
|
|
5312
|
+
// Same for the ghost buttons' end margin; the web's `:hover`
|
|
5313
|
+
// wash answers a press instead.
|
|
5314
|
+
'clear-trigger': {
|
|
5315
|
+
base: { marginRight: 'var(--space-xs)' },
|
|
5316
|
+
states: { pressed: fieldButtonHeld },
|
|
5317
|
+
},
|
|
5318
|
+
'visibility-trigger': {
|
|
5319
|
+
base: { marginRight: 'var(--space-xs)' },
|
|
5320
|
+
states: { pressed: fieldButtonHeld },
|
|
5321
|
+
},
|
|
5322
|
+
},
|
|
5323
|
+
},
|
|
5324
|
+
},
|
|
5030
5325
|
};
|
|
5031
5326
|
/**
|
|
5032
5327
|
* daisy "textarea" flavor. The `fieldControl` box minus its `height`: the
|
|
@@ -5094,6 +5389,22 @@ export const textarea = {
|
|
|
5094
5389
|
xl: { textarea: { base: { fontSize: 'var(--text-lg)', minHeight: `calc(${fieldHeight('xl')} * 2)`, padding: 'var(--space-lg) var(--space-xl)' } } },
|
|
5095
5390
|
},
|
|
5096
5391
|
},
|
|
5392
|
+
// lynx (signalxjs/lynx#1205): lynx-zero renders the part as a view (the
|
|
5393
|
+
// box, whose state classes repaint) around the native field, which wears
|
|
5394
|
+
// the part's base class as its text face. So the ink and the placeholder
|
|
5395
|
+
// are explicit here — `color: inherit` and `::placeholder` never reach a
|
|
5396
|
+
// native widget — and the web's `:hover` border and outline ring become
|
|
5397
|
+
// the lynx focus ring in the root's accent (signalxjs/lynx#1163).
|
|
5398
|
+
targets: {
|
|
5399
|
+
lynx: {
|
|
5400
|
+
parts: {
|
|
5401
|
+
textarea: {
|
|
5402
|
+
base: { color: 'var(--color-base-content)', '-x-placeholder-color': textFieldPlaceholder },
|
|
5403
|
+
states: { 'focus-visible': lynxFocusRing('var(--textarea-accent)') },
|
|
5404
|
+
},
|
|
5405
|
+
},
|
|
5406
|
+
},
|
|
5407
|
+
},
|
|
5097
5408
|
};
|
|
5098
5409
|
// ── Content tier (#311) ───────────────────────────────────────────────────
|
|
5099
5410
|
/**
|
|
@@ -7249,7 +7560,8 @@ const sheetSlide = (enter, exit) => {
|
|
|
7249
7560
|
const open = `${sheet}[data-state="open"]`;
|
|
7250
7561
|
const travel = (tempo) => {
|
|
7251
7562
|
const duration = tempo.split(' ')[0];
|
|
7252
|
-
|
|
7563
|
+
// `transform` rides along for the swipe's spring back (#293).
|
|
7564
|
+
return `translate ${tempo}, transform ${tempo}, display ${duration} allow-discrete, overlay ${duration} allow-discrete`;
|
|
7253
7565
|
};
|
|
7254
7566
|
return {
|
|
7255
7567
|
base: { '--drawer-travel': '-100% 0' },
|
|
@@ -7383,8 +7695,27 @@ export const drawer = {
|
|
|
7383
7695
|
// Trigger-carried axes — see `btnColors` for why the panel is out of
|
|
7384
7696
|
// reach and the trigger is the whole story here.
|
|
7385
7697
|
variants: { color: btnColors(), size: btnSizes },
|
|
7386
|
-
// The btn paddings, restated physically — see `lynxBtnPad` (#1084).
|
|
7387
7698
|
targets: {
|
|
7699
|
+
// Swipe to dismiss (#293) — web only, since the runtime's `--swipe-*`
|
|
7700
|
+
// offset is: the sheet wears the drag offset (`SWIPE`) in every
|
|
7701
|
+
// state — so a swiped sheet leaves from where it was let go — at a
|
|
7702
|
+
// weight above the presence's own open `transform`. Mid-swipe no
|
|
7703
|
+
// transition runs. A touch pan across the dismiss axis stays the
|
|
7704
|
+
// page's; along it is the gesture's, so content taller than a
|
|
7705
|
+
// block-edge sheet scrolls in a box of its own inside the panel.
|
|
7706
|
+
web: {
|
|
7707
|
+
parts: {
|
|
7708
|
+
panel: {
|
|
7709
|
+
selectors: {
|
|
7710
|
+
'&[data-l-dock="sheet"][data-state]': { transform: SWIPE },
|
|
7711
|
+
'&[data-l-dock="sheet"][data-state="open"][data-swiping]': { transition: 'none', userSelect: 'none' },
|
|
7712
|
+
'&[data-l-dock="sheet"]:where([data-placement="start"], [data-placement="end"])': { touchAction: 'pan-y' },
|
|
7713
|
+
'&[data-l-dock="sheet"]:where([data-placement="top"], [data-placement="bottom"])': { touchAction: 'pan-x' },
|
|
7714
|
+
},
|
|
7715
|
+
},
|
|
7716
|
+
},
|
|
7717
|
+
},
|
|
7718
|
+
// The btn paddings, restated physically — see `lynxBtnPad` (#1084).
|
|
7388
7719
|
lynx: {
|
|
7389
7720
|
parts: {
|
|
7390
7721
|
trigger: { base: lynxBtnPad(4) },
|