@sigx/zero-daisyui 0.13.0 → 0.14.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/dist/audit.json +60 -0
- package/dist/css/components/combobox.css +5 -0
- package/dist/css/components/spinner.css +5 -5
- package/dist/css/index.css +10 -5
- package/dist/lynx/components/alert.css +42 -6
- package/dist/lynx/components/avatar-group.css +13 -1
- package/dist/lynx/components/avatar.css +56 -1
- package/dist/lynx/components/badge.css +209 -4
- package/dist/lynx/components/card.css +12 -1
- package/dist/lynx/components/combobox.css +5 -0
- package/dist/lynx/components/divider.css +45 -0
- package/dist/lynx/components/empty-state.css +7 -1
- package/dist/lynx/components/kbd.css +15 -1
- package/dist/lynx/components/skeleton.css +1 -1
- package/dist/lynx/components/spinner.css +32 -12
- package/dist/lynx/components/stats.css +39 -3
- package/dist/lynx/components/status.css +197 -1
- package/dist/lynx/components/textarea.css +1 -1
- package/dist/lynx/components/toast.css +331 -10
- package/dist/lynx/index.css +1005 -43
- package/dist/lynx/manifest.json +3 -3
- package/dist/manifest.json +1 -1
- package/dist/recipes.d.ts +6 -1
- package/dist/recipes.d.ts.map +1 -1
- package/dist/recipes.js +653 -9
- package/dist/recipes.js.map +1 -1
- package/dist/report.json +23 -64
- package/package.json +4 -4
- package/src/recipes.ts +653 -9
package/src/recipes.ts
CHANGED
|
@@ -3773,6 +3773,80 @@ export const avatar: RecipeInput = {
|
|
|
3773
3773
|
xl: { root: { base: { '--avatar-size': 'calc(var(--size-selector) * 16)', '--avatar-text': 'var(--text-lg)' } } },
|
|
3774
3774
|
},
|
|
3775
3775
|
},
|
|
3776
|
+
// signalxjs/lynx#1237 — the lynx layout for what the web gets from grid.
|
|
3777
|
+
targets: {
|
|
3778
|
+
lynx: {
|
|
3779
|
+
parts: {
|
|
3780
|
+
// No grid on lynx (signalxjs/lynx#1075): the web stacks the
|
|
3781
|
+
// image and the fallback in one grid cell. Here the root is a
|
|
3782
|
+
// flex box that does not shrink in a row, and both faces are
|
|
3783
|
+
// laid over it absolutely — the fallback, later in the tree,
|
|
3784
|
+
// paints over a pending image exactly as the grid's second
|
|
3785
|
+
// item does. lynx-zero renders neither face while its state
|
|
3786
|
+
// hides it (`hiddenIn`), so the web's `&:not([hidden])`
|
|
3787
|
+
// display rule has nothing to replace.
|
|
3788
|
+
root: {
|
|
3789
|
+
base: {
|
|
3790
|
+
display: 'flex',
|
|
3791
|
+
flexDirection: 'row',
|
|
3792
|
+
alignItems: 'center',
|
|
3793
|
+
justifyContent: 'center',
|
|
3794
|
+
flexShrink: '0',
|
|
3795
|
+
},
|
|
3796
|
+
},
|
|
3797
|
+
// Each face also rounds itself to the root's shape (below),
|
|
3798
|
+
// rather than trusting the root's clip to round an image on
|
|
3799
|
+
// both engines.
|
|
3800
|
+
image: {
|
|
3801
|
+
base: { position: 'absolute', top: '0', left: '0', borderRadius: '9999px' },
|
|
3802
|
+
},
|
|
3803
|
+
fallback: {
|
|
3804
|
+
base: {
|
|
3805
|
+
position: 'absolute',
|
|
3806
|
+
top: '0',
|
|
3807
|
+
left: '0',
|
|
3808
|
+
borderRadius: '9999px',
|
|
3809
|
+
display: 'flex',
|
|
3810
|
+
alignItems: 'center',
|
|
3811
|
+
justifyContent: 'center',
|
|
3812
|
+
textAlign: 'center',
|
|
3813
|
+
},
|
|
3814
|
+
},
|
|
3815
|
+
},
|
|
3816
|
+
variants: {
|
|
3817
|
+
shape: Object.fromEntries(([
|
|
3818
|
+
['circle', '9999px'], ['square', '0'], ['rounded', 'var(--radius-selector)'],
|
|
3819
|
+
] as const).map(([shape, radius]) => [shape, {
|
|
3820
|
+
image: { base: { borderRadius: radius } },
|
|
3821
|
+
fallback: { base: { borderRadius: radius } },
|
|
3822
|
+
}])),
|
|
3823
|
+
},
|
|
3824
|
+
// Every avatar after the first in an AvatarGroup overlaps its
|
|
3825
|
+
// neighbour by a quarter of its own box — the web's
|
|
3826
|
+
// `avatar-group` compose, `&:not(:first-child)`. Lynx has neither
|
|
3827
|
+
// the nested-scope compose nor `:first-child`, so lynx-zero stamps
|
|
3828
|
+
// those avatars `stacked` itself (`zx-m-stacked`, in mount order).
|
|
3829
|
+
// A lynx-zero rendering detail, not a modifier an author sets, so
|
|
3830
|
+
// it is styled from raw lynx css, one rule per avatar size.
|
|
3831
|
+
css: `
|
|
3832
|
+
.zx-avatar__root.zx-m-stacked {
|
|
3833
|
+
margin-left: calc(var(--size-selector) * -2.5);
|
|
3834
|
+
}
|
|
3835
|
+
.zx-avatar__root.zx-m-stacked.zx-a-size-xs {
|
|
3836
|
+
margin-left: calc(var(--size-selector) * -1.5);
|
|
3837
|
+
}
|
|
3838
|
+
.zx-avatar__root.zx-m-stacked.zx-a-size-sm {
|
|
3839
|
+
margin-left: calc(var(--size-selector) * -2);
|
|
3840
|
+
}
|
|
3841
|
+
.zx-avatar__root.zx-m-stacked.zx-a-size-lg {
|
|
3842
|
+
margin-left: calc(var(--size-selector) * -3);
|
|
3843
|
+
}
|
|
3844
|
+
.zx-avatar__root.zx-m-stacked.zx-a-size-xl {
|
|
3845
|
+
margin-left: calc(var(--size-selector) * -4);
|
|
3846
|
+
}
|
|
3847
|
+
`,
|
|
3848
|
+
},
|
|
3849
|
+
},
|
|
3776
3850
|
};
|
|
3777
3851
|
|
|
3778
3852
|
/**
|
|
@@ -3867,6 +3941,33 @@ export const avatarGroup: RecipeInput = {
|
|
|
3867
3941
|
md: {},
|
|
3868
3942
|
},
|
|
3869
3943
|
},
|
|
3944
|
+
// signalxjs/lynx#1237. The avatars inside take the group's size and
|
|
3945
|
+
// colour from lynx-zero (the `composes` above has no class form on this
|
|
3946
|
+
// target), and their overlap is the avatar recipe's `stacked` rule.
|
|
3947
|
+
targets: {
|
|
3948
|
+
lynx: {
|
|
3949
|
+
parts: {
|
|
3950
|
+
// A row that sizes to its faces (a lynx view stretches to its
|
|
3951
|
+
// column otherwise).
|
|
3952
|
+
root: { base: { display: 'flex', flexDirection: 'row', width: 'max-content' } },
|
|
3953
|
+
// `inline-grid` centring as flex, and the logical inline
|
|
3954
|
+
// padding and overlap as physical spellings — logical
|
|
3955
|
+
// margins and paddings resolve on iOS but not on Android
|
|
3956
|
+
// (signalxjs/lynx#1084); lynx has no RTL flow, so start IS left.
|
|
3957
|
+
overflow: {
|
|
3958
|
+
base: {
|
|
3959
|
+
display: 'flex',
|
|
3960
|
+
alignItems: 'center',
|
|
3961
|
+
justifyContent: 'center',
|
|
3962
|
+
flexShrink: '0',
|
|
3963
|
+
paddingLeft: 'var(--space-2xs)',
|
|
3964
|
+
paddingRight: 'var(--space-2xs)',
|
|
3965
|
+
marginLeft: 'calc(var(--avatar-group-size) * -0.25)',
|
|
3966
|
+
},
|
|
3967
|
+
},
|
|
3968
|
+
},
|
|
3969
|
+
},
|
|
3970
|
+
},
|
|
3870
3971
|
};
|
|
3871
3972
|
|
|
3872
3973
|
/**
|
|
@@ -4163,7 +4264,99 @@ export const toast: RecipeInput = {
|
|
|
4163
4264
|
base: { position: 'absolute', top: 'var(--space-xs)', right: 'var(--space-xs)' },
|
|
4164
4265
|
states: lynxFocus({ gap: 'var(--toast-bg)' }),
|
|
4165
4266
|
},
|
|
4267
|
+
// The promise toast's mark (signalxjs/lynx#1196). No grid and
|
|
4268
|
+
// no `:has()`: the mark is laid over the card's leading
|
|
4269
|
+
// padding, at the root's own padding offsets (per size,
|
|
4270
|
+
// below), and lynx-zero stamps `marked` on every part of a
|
|
4271
|
+
// toast that shows it, so the text steps aside (the raw css
|
|
4272
|
+
// below) — the web's leading grid column.
|
|
4273
|
+
indicator: {
|
|
4274
|
+
base: {
|
|
4275
|
+
position: 'absolute',
|
|
4276
|
+
left: 'var(--space-lg)',
|
|
4277
|
+
top: 'var(--space-md)',
|
|
4278
|
+
width: 'var(--toast-mark)',
|
|
4279
|
+
height: 'var(--toast-mark)',
|
|
4280
|
+
},
|
|
4281
|
+
states: {
|
|
4282
|
+
// daisy's ring in the toast's ink. The track is the
|
|
4283
|
+
// ink at 25%, which cannot bake over the recipe-local
|
|
4284
|
+
// `--toast-ink`: the neutral toast's track mixes the
|
|
4285
|
+
// theme's base-content, and each colour's twin (the
|
|
4286
|
+
// variants below) its role. Longhands, and the head as
|
|
4287
|
+
// `border-top-color`: logical spellings are not lynx's
|
|
4288
|
+
// (signalxjs/lynx#1084), and a var-bearing shorthand
|
|
4289
|
+
// would repaint the head after the cascade (#1161).
|
|
4290
|
+
loading: {
|
|
4291
|
+
// The shared shorthand is dropped on lynx (its
|
|
4292
|
+
// track cannot bake); a static one here keeps it
|
|
4293
|
+
// that way should the shared value ever bake.
|
|
4294
|
+
border: '0 solid transparent',
|
|
4295
|
+
borderStyle: 'solid',
|
|
4296
|
+
...lynxSides('border{}Width', 'calc(var(--border) * 2)'),
|
|
4297
|
+
...lynxSides('border{}Color', 'color-mix(in oklab, var(--color-base-content) 25%, transparent)', ['Right', 'Bottom', 'Left']),
|
|
4298
|
+
borderTopColor: 'var(--toast-ink)',
|
|
4299
|
+
},
|
|
4300
|
+
// The tick without clip-path, which lynx does not apply
|
|
4301
|
+
// (signalxjs/lynx#1216): the checkbox's two-border
|
|
4302
|
+
// check — a box 3/8 of the mark wide and 3/4 tall with
|
|
4303
|
+
// its right and bottom borders drawn, turned 45° —
|
|
4304
|
+
// pulled to the middle of the mark's slot by its
|
|
4305
|
+
// margins. The fill the web cuts the tick from is
|
|
4306
|
+
// cleared.
|
|
4307
|
+
complete: {
|
|
4308
|
+
background: 'transparent',
|
|
4309
|
+
boxSizing: 'border-box',
|
|
4310
|
+
width: 'calc(var(--toast-mark) * 0.375)',
|
|
4311
|
+
height: 'calc(var(--toast-mark) * 0.75)',
|
|
4312
|
+
marginLeft: 'calc(var(--toast-mark) * 0.3125)',
|
|
4313
|
+
borderStyle: 'solid',
|
|
4314
|
+
borderColor: TOAST_SUCCESS_INK,
|
|
4315
|
+
borderTopWidth: '0',
|
|
4316
|
+
borderLeftWidth: '0',
|
|
4317
|
+
borderRightWidth: 'calc(var(--border) * 2)',
|
|
4318
|
+
borderBottomWidth: 'calc(var(--border) * 2)',
|
|
4319
|
+
transform: 'rotate(45deg)',
|
|
4320
|
+
},
|
|
4321
|
+
// The cross without clip-path: its two diagonal bars
|
|
4322
|
+
// as hard-stop gradients over a clear fill.
|
|
4323
|
+
error: {
|
|
4324
|
+
background: `linear-gradient(45deg, transparent 41%, ${TOAST_ERROR_INK} 41%, ${TOAST_ERROR_INK} 59%, transparent 59%), `
|
|
4325
|
+
+ `linear-gradient(-45deg, transparent 41%, ${TOAST_ERROR_INK} 41%, ${TOAST_ERROR_INK} 59%, transparent 59%)`,
|
|
4326
|
+
},
|
|
4327
|
+
},
|
|
4328
|
+
},
|
|
4329
|
+
},
|
|
4330
|
+
variants: {
|
|
4331
|
+
// Each colour's ring track: its role at 25% (the web's mix
|
|
4332
|
+
// over `--toast-ink`, which is that role).
|
|
4333
|
+
color: Object.fromEntries(ROLES.map((role) => [role, {
|
|
4334
|
+
indicator: {
|
|
4335
|
+
states: {
|
|
4336
|
+
loading: lynxSides('border{}Color', `color-mix(in oklab, var(--color-${role}) 25%, transparent)`, ['Right', 'Bottom', 'Left']),
|
|
4337
|
+
},
|
|
4338
|
+
},
|
|
4339
|
+
}])),
|
|
4340
|
+
// The mark sits at the root's padding offsets for its size.
|
|
4341
|
+
size: {
|
|
4342
|
+
xs: { indicator: { base: { left: 'var(--space-md)', top: 'var(--space-xs)' } } },
|
|
4343
|
+
sm: { indicator: { base: { left: 'var(--space-md)', top: 'var(--space-sm)' } } },
|
|
4344
|
+
lg: { indicator: { base: { left: 'var(--space-xl)', top: 'var(--space-lg)' } } },
|
|
4345
|
+
xl: { indicator: { base: { left: 'var(--space-2xl)', top: 'var(--space-xl)' } } },
|
|
4346
|
+
},
|
|
4166
4347
|
},
|
|
4348
|
+
// The text of a marked toast steps past the mark and the web's
|
|
4349
|
+
// column gap. `marked` is a lynx-zero rendering detail (the
|
|
4350
|
+
// spelling of `:has(> indicator)`), not a modifier an author sets,
|
|
4351
|
+
// so it is styled from raw lynx css. The reduced-motion and
|
|
4352
|
+
// forced-colors stops cannot follow: lynx emits no `@media`.
|
|
4353
|
+
css: `
|
|
4354
|
+
.zx-toast__title.zx-m-marked,
|
|
4355
|
+
.zx-toast__description.zx-m-marked,
|
|
4356
|
+
.zx-toast__action.zx-m-marked {
|
|
4357
|
+
margin-left: calc(var(--toast-mark) + var(--space-md));
|
|
4358
|
+
}
|
|
4359
|
+
`,
|
|
4167
4360
|
},
|
|
4168
4361
|
},
|
|
4169
4362
|
// The viewport's `open` (the stack expanded) is a fact this skin has no
|
|
@@ -4259,7 +4452,8 @@ export const combobox: RecipeInput = {
|
|
|
4259
4452
|
fontWeight: 'var(--weight-medium)',
|
|
4260
4453
|
lineHeight: 'var(--leading-none)',
|
|
4261
4454
|
},
|
|
4262
|
-
|
|
4455
|
+
// Arrowed onto from the input (#411).
|
|
4456
|
+
states: { disabled: {}, ...focusRing },
|
|
4263
4457
|
},
|
|
4264
4458
|
'tag-label': { base: { whiteSpace: 'nowrap' } },
|
|
4265
4459
|
'tag-remove': {
|
|
@@ -5638,11 +5832,18 @@ export const textarea: RecipeInput = {
|
|
|
5638
5832
|
// lands on top of the 2px gap and paints one solid band. A fixed-height
|
|
5639
5833
|
// box never re-lays out; this auto-height one does, as its native field
|
|
5640
5834
|
// measures and grows. So the ring is spelled with one outset shadow and
|
|
5641
|
-
//
|
|
5835
|
+
// inset shadows, which paint areas the outset never reaches: the ring
|
|
5642
5836
|
// just outside the box, the box's own border repainted as the base-100
|
|
5643
|
-
// gap, and the hairline redrawn inside it by the inset spread, in the
|
|
5837
|
+
// gap, and the hairline redrawn inside it by the edge inset's spread, in the
|
|
5644
5838
|
// edge colour (`--textarea-edge`, the error colour while invalid). The
|
|
5645
5839
|
// gap is the border's width instead of the web's 2px.
|
|
5840
|
+
//
|
|
5841
|
+
// Android paints inset shadows OVER the border, where iOS paints them
|
|
5842
|
+
// under it (signalxjs/lynx#1230): the base-100 border vanished and the
|
|
5843
|
+
// whole 2px inset showed as a grey band against the ring. So the gap is
|
|
5844
|
+
// also drawn as a 1px base-100 inset stacked above the edge inset. On
|
|
5845
|
+
// Android that inset is the gap. On iOS the border already covers it,
|
|
5846
|
+
// whichever order the layers end up in, so iOS paints as before.
|
|
5646
5847
|
targets: {
|
|
5647
5848
|
lynx: {
|
|
5648
5849
|
parts: {
|
|
@@ -5659,6 +5860,9 @@ export const textarea: RecipeInput = {
|
|
|
5659
5860
|
outline: 'none',
|
|
5660
5861
|
borderColor: 'var(--color-base-100)',
|
|
5661
5862
|
boxShadow: '0 0 0 2px var(--textarea-accent), '
|
|
5863
|
+
// The gap: the border's width in base-100,
|
|
5864
|
+
// for Android, which paints this over the border.
|
|
5865
|
+
+ 'inset 0 0 0 1px var(--color-base-100), '
|
|
5662
5866
|
// Twice the border (1px in every shipped
|
|
5663
5867
|
// theme): the inner half shows as the hairline.
|
|
5664
5868
|
+ 'inset 0 0 0 2px var(--textarea-edge)',
|
|
@@ -5785,6 +5989,42 @@ export const card: RecipeInput = {
|
|
|
5785
5989
|
xl: { root: { base: { '--card-pad': 'var(--space-2xl)' } } },
|
|
5786
5990
|
},
|
|
5787
5991
|
},
|
|
5992
|
+
targets: {
|
|
5993
|
+
lynx: {
|
|
5994
|
+
parts: {
|
|
5995
|
+
// The root does not clip on lynx: a clipping layer takes its
|
|
5996
|
+
// own shadow with it on iOS, and the card's elevation is the
|
|
5997
|
+
// daisy look. The media band rounds its own corners instead
|
|
5998
|
+
// (below), which is all the clip was for.
|
|
5999
|
+
root: { base: { overflow: 'visible' } },
|
|
6000
|
+
// `inline-size` has no lynx spelling; the image selector and
|
|
6001
|
+
// the `:first-child` / `:last-child` corners are dropped (no
|
|
6002
|
+
// child or structural pseudo-classes). The band clips its
|
|
6003
|
+
// own content, so an `<image>` inside it takes the corners.
|
|
6004
|
+
media: { base: { width: '100%', overflow: 'hidden' } },
|
|
6005
|
+
// A lynx view is a column unless told otherwise.
|
|
6006
|
+
footer: { base: { flexDirection: 'row' } },
|
|
6007
|
+
},
|
|
6008
|
+
// The corners the media band shares with the card
|
|
6009
|
+
// (signalxjs/lynx#1235). Lynx has no `:first-child` or
|
|
6010
|
+
// `:last-child`, so lynx-zero stamps the band itself from its
|
|
6011
|
+
// mount order among the card's bands, as `data-mod-first` /
|
|
6012
|
+
// `data-mod-last` (the `zx-m-first` / `zx-m-last` classes). They
|
|
6013
|
+
// are a lynx-zero rendering detail, not modifiers an author sets,
|
|
6014
|
+
// so they are not declared in the vocabulary and are styled from
|
|
6015
|
+
// raw lynx css (toggle-group's join ends are the precedent).
|
|
6016
|
+
css: `
|
|
6017
|
+
.zx-card__media.zx-m-first {
|
|
6018
|
+
border-top-left-radius: var(--radius-box);
|
|
6019
|
+
border-top-right-radius: var(--radius-box);
|
|
6020
|
+
}
|
|
6021
|
+
.zx-card__media.zx-m-last {
|
|
6022
|
+
border-bottom-left-radius: var(--radius-box);
|
|
6023
|
+
border-bottom-right-radius: var(--radius-box);
|
|
6024
|
+
}
|
|
6025
|
+
`,
|
|
6026
|
+
},
|
|
6027
|
+
},
|
|
5788
6028
|
};
|
|
5789
6029
|
|
|
5790
6030
|
/**
|
|
@@ -5876,6 +6116,87 @@ export const alert: RecipeInput = {
|
|
|
5876
6116
|
xl: { root: { base: { padding: 'var(--space-xl) var(--space-2xl)' } } },
|
|
5877
6117
|
},
|
|
5878
6118
|
},
|
|
6119
|
+
targets: {
|
|
6120
|
+
// No grid on lynx (signalxjs/lynx#1075, #1235): the web's three
|
|
6121
|
+
// columns (the icon over both rows | the title over the description
|
|
6122
|
+
// | the close button) are rebuilt as a flex column with the icon and
|
|
6123
|
+
// the close button placed absolutely — the toast's close pin is the
|
|
6124
|
+
// precedent. The padding moves onto two properties so the icon and
|
|
6125
|
+
// the close button can follow it per size.
|
|
6126
|
+
lynx: {
|
|
6127
|
+
tokens: {
|
|
6128
|
+
'--alert-pad-y': 'var(--space-md)',
|
|
6129
|
+
'--alert-pad-x': 'var(--space-lg)',
|
|
6130
|
+
},
|
|
6131
|
+
parts: {
|
|
6132
|
+
root: {
|
|
6133
|
+
base: {
|
|
6134
|
+
display: 'flex',
|
|
6135
|
+
flexDirection: 'column',
|
|
6136
|
+
alignItems: 'stretch',
|
|
6137
|
+
gap: 'var(--space-sm)',
|
|
6138
|
+
position: 'relative',
|
|
6139
|
+
boxSizing: 'border-box',
|
|
6140
|
+
padding: 'var(--alert-pad-y) var(--alert-pad-x)',
|
|
6141
|
+
},
|
|
6142
|
+
},
|
|
6143
|
+
// The icon column: a --text-xl slot at the padding edge,
|
|
6144
|
+
// centred over the alert's height (the web's two-row span).
|
|
6145
|
+
icon: {
|
|
6146
|
+
base: {
|
|
6147
|
+
position: 'absolute',
|
|
6148
|
+
left: 'var(--alert-pad-x)',
|
|
6149
|
+
top: '0',
|
|
6150
|
+
bottom: '0',
|
|
6151
|
+
width: 'var(--text-xl)',
|
|
6152
|
+
display: 'flex',
|
|
6153
|
+
justifyContent: 'center',
|
|
6154
|
+
},
|
|
6155
|
+
},
|
|
6156
|
+
// Pinned top-right, its glyph on the padding edge. `inherit`
|
|
6157
|
+
// is spelled as the root's own ink.
|
|
6158
|
+
close: {
|
|
6159
|
+
base: {
|
|
6160
|
+
position: 'absolute',
|
|
6161
|
+
top: 'calc(var(--alert-pad-y) - var(--space-2xs))',
|
|
6162
|
+
right: 'calc(var(--alert-pad-x) - var(--space-2xs))',
|
|
6163
|
+
color: 'var(--color-base-content)',
|
|
6164
|
+
fontSize: 'var(--text-md)',
|
|
6165
|
+
},
|
|
6166
|
+
states: lynxFocus({ gap: 'var(--alert-tint)' }),
|
|
6167
|
+
},
|
|
6168
|
+
},
|
|
6169
|
+
variants: {
|
|
6170
|
+
size: {
|
|
6171
|
+
xs: { root: { base: { '--alert-pad-y': 'var(--space-2xs)', '--alert-pad-x': 'var(--space-sm)' } } },
|
|
6172
|
+
sm: { root: { base: { '--alert-pad-y': 'var(--space-xs)', '--alert-pad-x': 'var(--space-md)' } } },
|
|
6173
|
+
lg: { root: { base: { '--alert-pad-y': 'var(--space-lg)', '--alert-pad-x': 'var(--space-xl)' } } },
|
|
6174
|
+
xl: { root: { base: { '--alert-pad-y': 'var(--space-xl)', '--alert-pad-x': 'var(--space-2xl)' } } },
|
|
6175
|
+
},
|
|
6176
|
+
},
|
|
6177
|
+
// The title and description keep clear of the icon column and
|
|
6178
|
+
// the close button's corner. Lynx has no `:has()`, so lynx-zero
|
|
6179
|
+
// stamps what the alert renders onto both text parts, as
|
|
6180
|
+
// `data-mod-with-icon` / `data-mod-with-close` (the
|
|
6181
|
+
// `zx-m-with-icon` / `zx-m-with-close` classes) — a lynx-zero
|
|
6182
|
+
// rendering detail like toggle-group's join ends, styled from raw
|
|
6183
|
+
// lynx css.
|
|
6184
|
+
css: `
|
|
6185
|
+
.zx-alert__title.zx-m-with-icon {
|
|
6186
|
+
margin-left: calc(var(--text-xl) + var(--space-md));
|
|
6187
|
+
}
|
|
6188
|
+
.zx-alert__description.zx-m-with-icon {
|
|
6189
|
+
margin-left: calc(var(--text-xl) + var(--space-md));
|
|
6190
|
+
}
|
|
6191
|
+
.zx-alert__title.zx-m-with-close {
|
|
6192
|
+
margin-right: calc(var(--text-md) + var(--space-md));
|
|
6193
|
+
}
|
|
6194
|
+
.zx-alert__description.zx-m-with-close {
|
|
6195
|
+
margin-right: calc(var(--text-md) + var(--space-md));
|
|
6196
|
+
}
|
|
6197
|
+
`,
|
|
6198
|
+
},
|
|
6199
|
+
},
|
|
5879
6200
|
};
|
|
5880
6201
|
|
|
5881
6202
|
/**
|
|
@@ -5958,6 +6279,25 @@ export const emptyState: RecipeInput = {
|
|
|
5958
6279
|
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)' } } },
|
|
5959
6280
|
},
|
|
5960
6281
|
},
|
|
6282
|
+
// signalxjs/lynx#1236 — the lynx replacements for what the shared
|
|
6283
|
+
// sections cannot say there.
|
|
6284
|
+
targets: {
|
|
6285
|
+
lynx: {
|
|
6286
|
+
parts: {
|
|
6287
|
+
// Physical margins: Android resolves no logical margin
|
|
6288
|
+
// (signalxjs/lynx#1084).
|
|
6289
|
+
icon: { base: { marginBottom: 'var(--space-xs)' } },
|
|
6290
|
+
// Title and description are lynx `<text>`: a view's
|
|
6291
|
+
// `text-align` and `color` do not reach one unless the app
|
|
6292
|
+
// turned CSS inheritance on, so each states its own ink and
|
|
6293
|
+
// centring. The web's 36ch measure becomes the root's width:
|
|
6294
|
+
// `ch` is unmeasured on lynx.
|
|
6295
|
+
title: { base: { color: 'var(--color-base-content)', textAlign: 'center' } },
|
|
6296
|
+
description: { base: { textAlign: 'center', maxInlineSize: '100%' } },
|
|
6297
|
+
actions: { base: { flexDirection: 'row', marginTop: 'var(--space-sm)' } },
|
|
6298
|
+
},
|
|
6299
|
+
},
|
|
6300
|
+
},
|
|
5961
6301
|
};
|
|
5962
6302
|
|
|
5963
6303
|
/**
|
|
@@ -6060,6 +6400,62 @@ export const badge: RecipeInput = {
|
|
|
6060
6400
|
}, keyframes: {
|
|
6061
6401
|
'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; }',
|
|
6062
6402
|
},
|
|
6403
|
+
/**
|
|
6404
|
+
* Lynx (signalxjs/lynx#1234). The dot's `currentColor` never resolves
|
|
6405
|
+
* there (lynx#1079), so the uncoloured dot and its ring take the pill's
|
|
6406
|
+
* ink token, the value `currentColor` names on the web. The running halo
|
|
6407
|
+
* and pulse mix the recipe-local `--badge-dot`, which cannot bake, so the
|
|
6408
|
+
* halo is its own token mixed from each role's `--color-*` (baked per
|
|
6409
|
+
* theme) and the pulse breathes opacity instead of the halo's spread.
|
|
6410
|
+
* `inline-size`/`block-size` do not resolve on lynx (lynx#1145): the dot
|
|
6411
|
+
* is sized physically. A lynx view has no inline formatting context, so
|
|
6412
|
+
* the pill is content-sized with an explicit row (lynx#1165), and its
|
|
6413
|
+
* hairline and the dot's ring are longhands (lynx#1161/#1162).
|
|
6414
|
+
*/
|
|
6415
|
+
targets: {
|
|
6416
|
+
lynx: {
|
|
6417
|
+
tokens: {
|
|
6418
|
+
'--badge-dot': 'var(--badge-ink)',
|
|
6419
|
+
'--badge-dot-ring': 'var(--badge-ink)',
|
|
6420
|
+
'--badge-dot-halo': 'color-mix(in oklch, var(--color-base-content) 35%, transparent)',
|
|
6421
|
+
},
|
|
6422
|
+
parts: {
|
|
6423
|
+
root: {
|
|
6424
|
+
base: {
|
|
6425
|
+
...lynxBtnFit,
|
|
6426
|
+
flexDirection: 'row',
|
|
6427
|
+
border: '0 solid transparent',
|
|
6428
|
+
...lynxSides('border{}Width', 'var(--border)'),
|
|
6429
|
+
},
|
|
6430
|
+
},
|
|
6431
|
+
dot: {
|
|
6432
|
+
base: {
|
|
6433
|
+
display: 'flex',
|
|
6434
|
+
width: '0.5em',
|
|
6435
|
+
height: '0.5em',
|
|
6436
|
+
flexShrink: '0',
|
|
6437
|
+
border: '0 solid transparent',
|
|
6438
|
+
...lynxSides('border{}Width', '0.1em'),
|
|
6439
|
+
...lynxSides('border{}Color', 'var(--badge-dot-ring)'),
|
|
6440
|
+
},
|
|
6441
|
+
states: {
|
|
6442
|
+
running: {
|
|
6443
|
+
boxShadow: '0 0 0 0.2em var(--badge-dot-halo)',
|
|
6444
|
+
animation: 'zero-daisy-badge-pulse 1.6s ease-in-out infinite',
|
|
6445
|
+
},
|
|
6446
|
+
},
|
|
6447
|
+
},
|
|
6448
|
+
},
|
|
6449
|
+
variants: {
|
|
6450
|
+
color: Object.fromEntries(ROLES.map((c) => [c, {
|
|
6451
|
+
dot: { base: { '--badge-dot-halo': `color-mix(in oklch, var(--color-${c}) 35%, transparent)` } },
|
|
6452
|
+
}])),
|
|
6453
|
+
},
|
|
6454
|
+
keyframes: {
|
|
6455
|
+
'zero-daisy-badge-pulse': 'from, to { opacity: 1; } 50% { opacity: 0.45; }',
|
|
6456
|
+
},
|
|
6457
|
+
},
|
|
6458
|
+
},
|
|
6063
6459
|
};
|
|
6064
6460
|
|
|
6065
6461
|
/** daisy "divider": the base-300 rule, thickening with the ramp. */
|
|
@@ -6130,6 +6526,11 @@ export const divider: RecipeInput = {
|
|
|
6130
6526
|
},
|
|
6131
6527
|
targets: {
|
|
6132
6528
|
lynx: {
|
|
6529
|
+
// `auto` behind a custom property, so the labelled root's size
|
|
6530
|
+
// is var-bearing too and can beat the var-bearing line thickness
|
|
6531
|
+
// below (lynx expands var() declarations after the cascade,
|
|
6532
|
+
// signalxjs/lynx#1161).
|
|
6533
|
+
tokens: { '--divider-fit': 'auto' },
|
|
6133
6534
|
parts: {
|
|
6134
6535
|
// Lynx drops the ::before/::after segments the rule is drawn
|
|
6135
6536
|
// with above, which left the lynx divider with no line and,
|
|
@@ -6144,7 +6545,64 @@ export const divider: RecipeInput = {
|
|
|
6144
6545
|
'&[data-orientation="vertical"]': { inlineSize: 'var(--divider-thickness)' },
|
|
6145
6546
|
},
|
|
6146
6547
|
},
|
|
6548
|
+
// The label's inset, physical (Android resolves no logical
|
|
6549
|
+
// padding, signalxjs/lynx#1084), and flush on the side its
|
|
6550
|
+
// placement gave up. Lynx has no descendant combinator from
|
|
6551
|
+
// the root, so lynx-zero stamps the root's orientation on the
|
|
6552
|
+
// label itself; vertical, the inset turns to the block axis.
|
|
6553
|
+
// Every zero is spelled through var() so it beats the
|
|
6554
|
+
// var-bearing inset (signalxjs/lynx#1161).
|
|
6555
|
+
label: {
|
|
6556
|
+
base: {
|
|
6557
|
+
paddingLeft: 'var(--space-md)',
|
|
6558
|
+
paddingRight: 'var(--space-md)',
|
|
6559
|
+
},
|
|
6560
|
+
selectors: {
|
|
6561
|
+
'&[data-placement="start"]': { paddingLeft: 'calc(var(--space-md) * 0)' },
|
|
6562
|
+
'&[data-placement="end"]': { paddingRight: 'calc(var(--space-md) * 0)' },
|
|
6563
|
+
'&[data-orientation="vertical"]': {
|
|
6564
|
+
paddingLeft: 'calc(var(--space-md) * 0)',
|
|
6565
|
+
paddingRight: 'calc(var(--space-md) * 0)',
|
|
6566
|
+
paddingTop: 'var(--space-sm)',
|
|
6567
|
+
paddingBottom: 'var(--space-sm)',
|
|
6568
|
+
},
|
|
6569
|
+
'&[data-orientation="vertical"][data-placement="start"]': { paddingTop: 'calc(var(--space-sm) * 0)' },
|
|
6570
|
+
'&[data-orientation="vertical"][data-placement="end"]': { paddingBottom: 'calc(var(--space-sm) * 0)' },
|
|
6571
|
+
},
|
|
6572
|
+
},
|
|
6147
6573
|
},
|
|
6574
|
+
// A labelled divider (signalxjs/lynx#1236). With no pseudo-
|
|
6575
|
+
// elements, lynx-zero draws the rule's two segments as views
|
|
6576
|
+
// carrying the root's own line classes plus `zx-m-segment` —
|
|
6577
|
+
// so each paints this recipe's line, ink and thickness ramp — and
|
|
6578
|
+
// leaves out the one on the label's placed side (the web's
|
|
6579
|
+
// `:has(> [data-placement])::before { display: none }`). The root
|
|
6580
|
+
// holding them is stamped `zx-m-labelled` and stops being a line:
|
|
6581
|
+
// no fill, its cross size following the label, a row when
|
|
6582
|
+
// horizontal. Both are lynx-zero rendering details, not
|
|
6583
|
+
// modifiers an author sets, so they are styled from raw lynx css
|
|
6584
|
+
// (the toggle-group join ends' reasoning).
|
|
6585
|
+
css: `
|
|
6586
|
+
.zx-divider__root.zx-m-labelled {
|
|
6587
|
+
--divider-ink: transparent;
|
|
6588
|
+
}
|
|
6589
|
+
.zx-divider__root.zx-m-labelled.zx-o-horizontal {
|
|
6590
|
+
flex-direction: row;
|
|
6591
|
+
block-size: var(--divider-fit);
|
|
6592
|
+
}
|
|
6593
|
+
.zx-divider__root.zx-m-labelled.zx-o-vertical {
|
|
6594
|
+
inline-size: var(--divider-fit);
|
|
6595
|
+
}
|
|
6596
|
+
.zx-divider__root.zx-m-segment {
|
|
6597
|
+
flex: 1 1 0;
|
|
6598
|
+
}
|
|
6599
|
+
.zx-divider__root.zx-m-segment.zx-o-horizontal {
|
|
6600
|
+
min-width: 0;
|
|
6601
|
+
}
|
|
6602
|
+
.zx-divider__root.zx-m-segment.zx-o-vertical {
|
|
6603
|
+
min-height: 0;
|
|
6604
|
+
}
|
|
6605
|
+
`,
|
|
6148
6606
|
},
|
|
6149
6607
|
},
|
|
6150
6608
|
};
|
|
@@ -6201,13 +6659,29 @@ export const skeleton: RecipeInput = {
|
|
|
6201
6659
|
keyframes: {
|
|
6202
6660
|
'zero-daisyui-skeleton': 'from, to { opacity: 1; } 50% { opacity: 0.55; }',
|
|
6203
6661
|
},
|
|
6662
|
+
// signalxjs/lynx#1237. The pulse is an opacity loop on the part itself —
|
|
6663
|
+
// no pseudo-element, so it carries as is; only its keyframes are
|
|
6664
|
+
// restated as three plain stops, not the `from, to` selector list. The
|
|
6665
|
+
// reduced-motion stop cannot follow: lynx emits no `@media`.
|
|
6666
|
+
targets: {
|
|
6667
|
+
lynx: {
|
|
6668
|
+
keyframes: {
|
|
6669
|
+
'zero-daisyui-skeleton': '0% { opacity: 1; } 50% { opacity: 0.55; } 100% { opacity: 1; }',
|
|
6670
|
+
},
|
|
6671
|
+
},
|
|
6672
|
+
},
|
|
6204
6673
|
};
|
|
6205
6674
|
|
|
6206
|
-
/**
|
|
6675
|
+
/**
|
|
6676
|
+
* daisy "loading-spinner": the ring, with one quadrant in the role's ink.
|
|
6677
|
+
* Sized on daisy's `loading-*` ramp — `--size-selector * 4…8` (16–32px), md
|
|
6678
|
+
* the `loading` default of `* 6` (signalxjs/lynx#1237: the ramp was
|
|
6679
|
+
* `--size-field * 0.35…0.9`, a 2px box that the 2px border swallowed).
|
|
6680
|
+
*/
|
|
6207
6681
|
export const spinner: RecipeInput = {
|
|
6208
6682
|
component: 'spinner',
|
|
6209
6683
|
tokens: {
|
|
6210
|
-
'--spinner-size': 'calc(var(--size-
|
|
6684
|
+
'--spinner-size': 'calc(var(--size-selector) * 6)',
|
|
6211
6685
|
'--spinner-ink': 'var(--color-primary)',
|
|
6212
6686
|
'--spinner-track': 'var(--color-base-300)',
|
|
6213
6687
|
},
|
|
@@ -6231,14 +6705,40 @@ export const spinner: RecipeInput = {
|
|
|
6231
6705
|
'--spinner-ink': `var(--color-${c})`,
|
|
6232
6706
|
} } }])),
|
|
6233
6707
|
size: {
|
|
6234
|
-
xs: { root: { base: { '--spinner-size': 'calc(var(--size-
|
|
6235
|
-
sm: { root: { base: { '--spinner-size': 'calc(var(--size-
|
|
6708
|
+
xs: { root: { base: { '--spinner-size': 'calc(var(--size-selector) * 4)' } } },
|
|
6709
|
+
sm: { root: { base: { '--spinner-size': 'calc(var(--size-selector) * 5)' } } },
|
|
6236
6710
|
md: {},
|
|
6237
|
-
lg: { root: { base: { '--spinner-size': 'calc(var(--size-
|
|
6238
|
-
xl: { root: { base: { '--spinner-size': 'calc(var(--size-
|
|
6711
|
+
lg: { root: { base: { '--spinner-size': 'calc(var(--size-selector) * 7)' } } },
|
|
6712
|
+
xl: { root: { base: { '--spinner-size': 'calc(var(--size-selector) * 8)' } } },
|
|
6239
6713
|
},
|
|
6240
6714
|
},
|
|
6241
6715
|
keyframes: { 'zero-daisyui-spin': 'to { transform: rotate(360deg); }' },
|
|
6716
|
+
// signalxjs/lynx#1237 — the ring in physical spellings. The logical box
|
|
6717
|
+
// size and `border-block-start-color` are not lynx's; the ring is
|
|
6718
|
+
// restated as longhands, because a var-bearing `border` shorthand
|
|
6719
|
+
// expands after the cascade and would repaint the head in the track
|
|
6720
|
+
// colour (signalxjs/lynx#1161). A flex box, since `inline-block` is not a
|
|
6721
|
+
// lynx display value, that keeps its size in a row. The reduced-motion
|
|
6722
|
+
// stop cannot follow: lynx emits no `@media`.
|
|
6723
|
+
targets: {
|
|
6724
|
+
lynx: {
|
|
6725
|
+
parts: {
|
|
6726
|
+
root: {
|
|
6727
|
+
base: {
|
|
6728
|
+
display: 'flex',
|
|
6729
|
+
flexShrink: '0',
|
|
6730
|
+
width: 'var(--spinner-size)',
|
|
6731
|
+
height: 'var(--spinner-size)',
|
|
6732
|
+
border: '0 solid transparent',
|
|
6733
|
+
borderStyle: 'solid',
|
|
6734
|
+
...lynxSides('border{}Width', 'calc(var(--border) * 2)'),
|
|
6735
|
+
...lynxSides('border{}Color', 'var(--spinner-track)', ['Right', 'Bottom', 'Left']),
|
|
6736
|
+
borderTopColor: 'var(--spinner-ink)',
|
|
6737
|
+
},
|
|
6738
|
+
},
|
|
6739
|
+
},
|
|
6740
|
+
},
|
|
6741
|
+
},
|
|
6242
6742
|
};
|
|
6243
6743
|
|
|
6244
6744
|
// ── The content-tier sweep (#334) ─────────────────────────────────────────
|
|
@@ -6285,6 +6785,35 @@ export const kbd: RecipeInput = {
|
|
|
6285
6785
|
xl: { root: { base: { fontSize: 'var(--text-md)', padding: 'var(--space-xs) var(--space-lg)' } } },
|
|
6286
6786
|
},
|
|
6287
6787
|
},
|
|
6788
|
+
/**
|
|
6789
|
+
* Lynx (signalxjs/lynx#1234). `min-inline-size` and the logical bottom
|
|
6790
|
+
* edge do not resolve on lynx (lynx#1145, #1084), so the cap's floor is
|
|
6791
|
+
* a physical `min-width` and its doubled bottom edge a physical
|
|
6792
|
+
* longhand; the whole hairline is longhands so a var-bearing shorthand
|
|
6793
|
+
* cannot expand over the thicker edge (lynx#1161/#1162). A lynx view has
|
|
6794
|
+
* no inline formatting context: the cap is content-sized with an
|
|
6795
|
+
* explicit row (lynx#1165).
|
|
6796
|
+
*/
|
|
6797
|
+
targets: {
|
|
6798
|
+
lynx: {
|
|
6799
|
+
parts: {
|
|
6800
|
+
root: {
|
|
6801
|
+
base: {
|
|
6802
|
+
...lynxBtnFit,
|
|
6803
|
+
flexDirection: 'row',
|
|
6804
|
+
minWidth: '1.75em',
|
|
6805
|
+
border: '0 solid transparent',
|
|
6806
|
+
...lynxSides('border{}Width', 'var(--border)', ['Top', 'Right', 'Left']),
|
|
6807
|
+
borderBottomWidth: 'calc(var(--border) * 2)',
|
|
6808
|
+
...lynxSides('border{}Color', 'var(--color-base-300)'),
|
|
6809
|
+
},
|
|
6810
|
+
},
|
|
6811
|
+
},
|
|
6812
|
+
variants: {
|
|
6813
|
+
size: { xs: { root: { base: { minWidth: '1.5em' } } } },
|
|
6814
|
+
},
|
|
6815
|
+
},
|
|
6816
|
+
},
|
|
6288
6817
|
};
|
|
6289
6818
|
|
|
6290
6819
|
/**
|
|
@@ -6326,6 +6855,37 @@ export const status: RecipeInput = {
|
|
|
6326
6855
|
xl: { root: { base: { '--status-size': 'calc(var(--size-selector) * 3.5)' } } },
|
|
6327
6856
|
},
|
|
6328
6857
|
},
|
|
6858
|
+
/**
|
|
6859
|
+
* Lynx (signalxjs/lynx#1234). The halo mixes the recipe-local
|
|
6860
|
+
* `--status-ink`, which cannot bake, so it is its own token mixed from
|
|
6861
|
+
* each role's `--color-*` (baked per theme). `inline-size`/`block-size`
|
|
6862
|
+
* do not resolve on lynx (lynx#1145): the dot is sized physically, and
|
|
6863
|
+
* it is a flex box rather than an inline-block the engine has no
|
|
6864
|
+
* formatting context for.
|
|
6865
|
+
*/
|
|
6866
|
+
targets: {
|
|
6867
|
+
lynx: {
|
|
6868
|
+
tokens: {
|
|
6869
|
+
'--status-halo': 'color-mix(in oklch, var(--color-base-content) 25%, transparent)',
|
|
6870
|
+
},
|
|
6871
|
+
parts: {
|
|
6872
|
+
root: {
|
|
6873
|
+
base: {
|
|
6874
|
+
display: 'flex',
|
|
6875
|
+
flexShrink: '0',
|
|
6876
|
+
width: 'var(--status-size)',
|
|
6877
|
+
height: 'var(--status-size)',
|
|
6878
|
+
boxShadow: '0 0 0 calc(var(--status-size) / 4) var(--status-halo)',
|
|
6879
|
+
},
|
|
6880
|
+
},
|
|
6881
|
+
},
|
|
6882
|
+
variants: {
|
|
6883
|
+
color: Object.fromEntries(ROLES.map((c) => [c, { root: { base: {
|
|
6884
|
+
'--status-halo': `color-mix(in oklch, var(--color-${c}) 25%, transparent)`,
|
|
6885
|
+
} } }])),
|
|
6886
|
+
},
|
|
6887
|
+
},
|
|
6888
|
+
},
|
|
6329
6889
|
};
|
|
6330
6890
|
|
|
6331
6891
|
/**
|
|
@@ -6510,6 +7070,90 @@ export const stats: RecipeInput = {
|
|
|
6510
7070
|
xl: { value: { base: { fontSize: 'var(--text-3xl)' } } },
|
|
6511
7071
|
},
|
|
6512
7072
|
},
|
|
7073
|
+
// signalxjs/lynx#1236 — the lynx replacements for what the shared
|
|
7074
|
+
// sections cannot say there.
|
|
7075
|
+
targets: {
|
|
7076
|
+
lynx: {
|
|
7077
|
+
parts: {
|
|
7078
|
+
// A row unless vertical: a lynx flex container does not
|
|
7079
|
+
// default to one.
|
|
7080
|
+
root: { base: { flexDirection: 'row' } },
|
|
7081
|
+
// Lynx has no grid, so `display: grid` left the item in the
|
|
7082
|
+
// engine's default linear layout. The bands stack in a
|
|
7083
|
+
// centred column instead, and the figure is pinned to the
|
|
7084
|
+
// item's end edge (below). The padding as longhands, so the
|
|
7085
|
+
// `figure` rule below can widen one side by specificity (a
|
|
7086
|
+
// var-bearing `padding` shorthand would expand over it,
|
|
7087
|
+
// signalxjs/lynx#1161).
|
|
7088
|
+
item: {
|
|
7089
|
+
base: {
|
|
7090
|
+
display: 'flex',
|
|
7091
|
+
flexDirection: 'column',
|
|
7092
|
+
justifyContent: 'center',
|
|
7093
|
+
position: 'relative',
|
|
7094
|
+
padding: '0',
|
|
7095
|
+
paddingTop: 'var(--space-lg)',
|
|
7096
|
+
paddingBottom: 'var(--space-lg)',
|
|
7097
|
+
paddingLeft: 'var(--space-xl)',
|
|
7098
|
+
paddingRight: 'var(--space-xl)',
|
|
7099
|
+
},
|
|
7100
|
+
selectors: {
|
|
7101
|
+
// The seams: lynx has no sibling combinator, so the
|
|
7102
|
+
// web's `item + item` edge cannot be selected. Every
|
|
7103
|
+
// item draws its leading seam and the `first`
|
|
7104
|
+
// modifier takes it off the first (raw css below).
|
|
7105
|
+
'&[data-orientation="horizontal"]': {
|
|
7106
|
+
borderLeftWidth: 'var(--border)',
|
|
7107
|
+
borderLeftStyle: 'solid',
|
|
7108
|
+
borderLeftColor: 'var(--color-base-200)',
|
|
7109
|
+
},
|
|
7110
|
+
'&[data-orientation="vertical"]': {
|
|
7111
|
+
borderTopWidth: 'var(--border)',
|
|
7112
|
+
borderTopStyle: 'solid',
|
|
7113
|
+
borderTopColor: 'var(--color-base-200)',
|
|
7114
|
+
},
|
|
7115
|
+
},
|
|
7116
|
+
},
|
|
7117
|
+
// The web's second grid column, spanning the three bands and
|
|
7118
|
+
// centred on them: pinned to the item's end edge, inside its
|
|
7119
|
+
// padding, and centred top to bottom.
|
|
7120
|
+
figure: {
|
|
7121
|
+
base: {
|
|
7122
|
+
position: 'absolute',
|
|
7123
|
+
top: '0',
|
|
7124
|
+
bottom: '0',
|
|
7125
|
+
right: 'var(--space-xl)',
|
|
7126
|
+
// The web centres the grid cell with align-self; the
|
|
7127
|
+
// insets place it here.
|
|
7128
|
+
alignSelf: 'auto',
|
|
7129
|
+
display: 'flex',
|
|
7130
|
+
flexDirection: 'column',
|
|
7131
|
+
justifyContent: 'center',
|
|
7132
|
+
},
|
|
7133
|
+
},
|
|
7134
|
+
},
|
|
7135
|
+
// lynx-zero stamps the row's first item `zx-m-first` (mount
|
|
7136
|
+
// order; no `:first-child`) and an item holding a figure
|
|
7137
|
+
// `zx-m-figure`. Rendering details, not author modifiers, so raw
|
|
7138
|
+
// lynx css (the toggle-group join ends' reasoning). The first
|
|
7139
|
+
// item drops the leading seam, its zero width spelled through
|
|
7140
|
+
// var() to beat the var-bearing seam (signalxjs/lynx#1161). An
|
|
7141
|
+
// item with a figure keeps the figure's column clear: the
|
|
7142
|
+
// padding, the web's `--space-md` column gap, and a 2rem figure
|
|
7143
|
+
// (daisy's `stat-figure` holds a `size-8` icon or avatar).
|
|
7144
|
+
css: `
|
|
7145
|
+
.zx-stats__item.zx-m-first.zx-o-horizontal {
|
|
7146
|
+
border-left-width: calc(var(--border) * 0);
|
|
7147
|
+
}
|
|
7148
|
+
.zx-stats__item.zx-m-first.zx-o-vertical {
|
|
7149
|
+
border-top-width: calc(var(--border) * 0);
|
|
7150
|
+
}
|
|
7151
|
+
.zx-stats__item.zx-m-figure {
|
|
7152
|
+
padding-right: calc(var(--space-xl) + var(--space-md) + 2rem);
|
|
7153
|
+
}
|
|
7154
|
+
`,
|
|
7155
|
+
},
|
|
7156
|
+
},
|
|
6513
7157
|
};
|
|
6514
7158
|
|
|
6515
7159
|
/**
|