@fanfare-io/fanfare-sdk-react 0.21.0 → 0.23.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 +12 -0
- package/dist/components/checkout/card-brand.d.ts +2 -0
- package/dist/components/checkout/checkout-processing-panel.d.ts +2 -1
- package/dist/components/checkout/payment-collection-panel.d.ts +3 -3
- package/dist/components/checkout/payment-method-list.d.ts +18 -0
- package/dist/components/checkout/receipt-panel.d.ts +4 -3
- package/dist/components/primitives/countdown.d.ts +53 -14
- package/dist/components/primitives/spinner.d.ts +5 -0
- package/dist/components/widgets/experience-widget.d.ts +23 -0
- package/dist/components/widgets/internal/auction-ledger.d.ts +1 -12
- package/dist/components/widgets/internal/selection-branches.d.ts +0 -2
- package/dist/index-DbLojDF1.js +8337 -0
- package/dist/index.js +4 -4
- package/dist/stripe-card-field-DIxqCt1r.js +186 -0
- package/dist/styles/base.css +1 -1
- package/dist/styles/index.d.ts +0 -1
- package/dist/styles/theme.css +583 -1
- package/dist/theme/font-loader.d.ts +58 -0
- package/dist/theme/theme-context.d.ts +8 -0
- package/package.json +6 -7
- package/dist/index-DWJSw9N8.js +0 -7861
- package/dist/stripe-card-field-CPZoyAm1.js +0 -170
package/dist/styles/theme.css
CHANGED
|
@@ -55,6 +55,23 @@
|
|
|
55
55
|
|
|
56
56
|
[data-fanfare-variant="retro"] {
|
|
57
57
|
--ff-variant: "retro";
|
|
58
|
+
/* Inconsolata's advance is 0.5; 0.58 also covers the fallback monospace stack a host that
|
|
59
|
+
* does not load the face renders with. */
|
|
60
|
+
--ff-numeral-advance: 0.58;
|
|
61
|
+
--ff-countdown-cell-padding: 0.5rem 0.75rem;
|
|
62
|
+
--ff-countdown-cell-border-width: 2px;
|
|
63
|
+
--ff-countdown-reserve-cell: 1.75rem;
|
|
64
|
+
--ff-countdown-reserve-gap: 1rem;
|
|
65
|
+
--ff-countdown-cell-bg: var(--ff-color-background);
|
|
66
|
+
--ff-countdown-cell-shadow: 3px 3px 0 var(--ff-color-foreground);
|
|
67
|
+
--ff-progress-bar-shadow: inset 0 -3px 0 rgba(0, 0, 0, 0.2);
|
|
68
|
+
--ff-card-shadow: 6px 6px 0 var(--ff-color-foreground);
|
|
69
|
+
--ff-card-shadow-elevated: var(--ff-card-shadow);
|
|
70
|
+
--ff-countdown-separator-display: none;
|
|
71
|
+
--ff-countdown-inline-weight: 800;
|
|
72
|
+
--ff-countdown-tone-critical-bg: #ff3a00;
|
|
73
|
+
--ff-countdown-tone-critical-fg: #ffffff;
|
|
74
|
+
--ff-countdown-numeral-font: var(--ff-font-mono);
|
|
58
75
|
--ff-color-background: #f4f1ea;
|
|
59
76
|
--ff-color-foreground: #000000;
|
|
60
77
|
--ff-color-muted: #444444;
|
|
@@ -63,7 +80,7 @@
|
|
|
63
80
|
/*
|
|
64
81
|
* Note: retro intentionally does NOT override --ff-color-danger. The
|
|
65
82
|
* brutalist `#ff3a00` orange is a Countdown-critical-urgency accent only
|
|
66
|
-
* (
|
|
83
|
+
* (scoped to the countdown unit rule below), not a global semantic
|
|
67
84
|
* destructive color. Destructive buttons / error views keep the customer's
|
|
68
85
|
* (or @theme default) danger token under retro.
|
|
69
86
|
*/
|
|
@@ -74,15 +91,51 @@
|
|
|
74
91
|
|
|
75
92
|
[data-fanfare-variant="rounded"] {
|
|
76
93
|
--ff-variant: "rounded";
|
|
94
|
+
--ff-countdown-cell-radius: 14px;
|
|
95
|
+
--ff-countdown-cell-padding: 0.75rem 1rem;
|
|
96
|
+
--ff-countdown-cell-border-width: 1px;
|
|
97
|
+
--ff-countdown-cell-bg: var(--ff-color-background);
|
|
98
|
+
--ff-countdown-cell-shadow: 0 2px 12px -3px rgba(0, 0, 0, 0.08);
|
|
99
|
+
--ff-countdown-cell-shadow-hover: 0 4px 16px -4px rgba(0, 0, 0, 0.12);
|
|
100
|
+
--ff-countdown-separator-display: none;
|
|
101
|
+
--ff-countdown-inline-weight: 600;
|
|
102
|
+
--ff-countdown-reserve-cell: 2.125rem;
|
|
103
|
+
--ff-countdown-reserve-gap: 1rem;
|
|
104
|
+
--ff-card-shadow: 0 2px 12px -3px rgba(0, 0, 0, 0.08);
|
|
105
|
+
--ff-card-shadow-hover: 0 4px 16px -4px rgba(0, 0, 0, 0.12);
|
|
106
|
+
--ff-card-shadow-elevated: var(--ff-card-shadow);
|
|
107
|
+
--ff-card-shadow-elevated-hover: var(--ff-card-shadow-hover);
|
|
108
|
+
--ff-progress-shadow: inset 0 1px 4px -1px rgba(0, 0, 0, 0.06);
|
|
109
|
+
--ff-progress-bar-shadow: 0 0 10px -2px var(--ff-color-primary);
|
|
110
|
+
--ff-loading-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.08);
|
|
111
|
+
--ff-button-shadow: 0 2px 12px -3px rgba(0, 0, 0, 0.08);
|
|
112
|
+
--ff-button-shadow-hover: 0 4px 16px -4px rgba(0, 0, 0, 0.12);
|
|
113
|
+
--ff-button-shadow-active: inset 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
114
|
+
--ff-button-shadow-primary: 0 2px 12px -3px rgba(0, 0, 0, 0.08), 0 0 12px -6px var(--ff-color-primary);
|
|
115
|
+
--ff-input-shadow: inset 0 1px 4px -1px rgba(0, 0, 0, 0.06);
|
|
116
|
+
--ff-input-shadow-focus: inset 0 1px 4px -1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(var(--ff-color-primary-rgb), 0.12);
|
|
117
|
+
--ff-otp-shadow: inset 0 1px 4px -1px rgba(0, 0, 0, 0.06);
|
|
118
|
+
--ff-otp-shadow-focus: inset 0 1px 4px -1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(var(--ff-color-primary-rgb), 0.12);
|
|
119
|
+
--ff-otp-shadow-focus-error:
|
|
120
|
+
inset 0 1px 4px -1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(var(--ff-color-danger-rgb), 0.12);
|
|
77
121
|
}
|
|
78
122
|
|
|
79
123
|
[data-fanfare-variant="clean"] {
|
|
80
124
|
--ff-variant: "clean";
|
|
125
|
+
--ff-numeral-advance: 0.58;
|
|
126
|
+
--ff-countdown-cell-gap: 0.125rem;
|
|
127
|
+
--ff-countdown-inline-weight: 500;
|
|
128
|
+
--ff-countdown-inline-tracking: 0.02em;
|
|
129
|
+
--ff-countdown-reserve-gap: 2rem;
|
|
130
|
+
--ff-countdown-numeral-font: var(--ff-font-mono);
|
|
81
131
|
--ff-color-background: #ffffff;
|
|
82
132
|
--ff-color-foreground: #0a0a0a;
|
|
83
133
|
--ff-color-muted: #737373;
|
|
84
134
|
--ff-color-muted-foreground: #737373;
|
|
85
135
|
--ff-color-border: #e8e8e8;
|
|
136
|
+
--ff-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
|
|
137
|
+
--ff-card-shadow-elevated: var(--ff-card-shadow);
|
|
138
|
+
--ff-progress-bar-shadow: 0 0 #0000;
|
|
86
139
|
--ff-font-sans: "Figtree", system-ui, sans-serif;
|
|
87
140
|
--ff-font-heading: "Figtree", system-ui, sans-serif;
|
|
88
141
|
--ff-font-mono: "Inconsolata", "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
@@ -98,6 +151,154 @@
|
|
|
98
151
|
font-family: var(--ff-font-sans);
|
|
99
152
|
color: var(--ff-color-foreground);
|
|
100
153
|
background-color: var(--ff-color-surface);
|
|
154
|
+
--ff-widget-max-width: 24rem;
|
|
155
|
+
|
|
156
|
+
/* The advance width of one digit as a fraction of the font size, for the
|
|
157
|
+
* variant's numeral typeface. Fitting a fixed-width glyph run to a
|
|
158
|
+
* container needs it; over-stating it only shrinks the numerals. */
|
|
159
|
+
--ff-numeral-advance: 0.65;
|
|
160
|
+
|
|
161
|
+
/* Display text that fits its container: a `cqi`-driven scale between a
|
|
162
|
+
* legible floor and a ceiling the design allows. */
|
|
163
|
+
--ff-stat-min: 1.5rem;
|
|
164
|
+
--ff-stat-scale: 9cqi;
|
|
165
|
+
--ff-stat-max: 2.25rem;
|
|
166
|
+
--ff-stat-weight: 700;
|
|
167
|
+
--ff-title-min: 1rem;
|
|
168
|
+
--ff-title-scale: 6cqi;
|
|
169
|
+
--ff-title-max: 1.25rem;
|
|
170
|
+
--ff-title-weight: 600;
|
|
171
|
+
|
|
172
|
+
/* Countdown: geometry, colour, label placement, separator and inline type,
|
|
173
|
+
* overridden per variant in the blocks above. */
|
|
174
|
+
--ff-countdown-cell-gap: 0.75rem;
|
|
175
|
+
--ff-countdown-cell-padding: 0;
|
|
176
|
+
--ff-countdown-cell-radius: 0;
|
|
177
|
+
--ff-countdown-cell-border-width: 0px;
|
|
178
|
+
--ff-countdown-cell-bg: transparent;
|
|
179
|
+
--ff-countdown-cell-shadow: none;
|
|
180
|
+
--ff-countdown-cell-shadow-hover: var(--ff-countdown-cell-shadow);
|
|
181
|
+
--ff-countdown-numeral-color: var(--ff-color-foreground);
|
|
182
|
+
--ff-countdown-numeral-font: var(--ff-font-heading);
|
|
183
|
+
--ff-countdown-label-color: var(--ff-color-muted-foreground);
|
|
184
|
+
--ff-countdown-label-size: 0.625rem;
|
|
185
|
+
--ff-countdown-label-order: 1;
|
|
186
|
+
--ff-countdown-separator-glyph: "/";
|
|
187
|
+
--ff-countdown-separator-display: inline;
|
|
188
|
+
--ff-countdown-separator-color: var(--ff-color-muted-foreground);
|
|
189
|
+
--ff-countdown-inline-size: inherit;
|
|
190
|
+
--ff-countdown-inline-weight: 600;
|
|
191
|
+
--ff-countdown-inline-tracking: 0;
|
|
192
|
+
|
|
193
|
+
/* Numeral fitting: the bounds the fitted numeral size is clamped to, and
|
|
194
|
+
* the horizontal space the numerals cannot have — the panel's own padding
|
|
195
|
+
* plus, per variant, each cell's padding and border and each gap's width
|
|
196
|
+
* and separator glyph. Rounded up: over-reserving shrinks the numerals,
|
|
197
|
+
* under-reserving overflows the widget. */
|
|
198
|
+
--ff-countdown-numeral-min: 1.25rem;
|
|
199
|
+
--ff-countdown-numeral-max: 2.5rem;
|
|
200
|
+
--ff-countdown-reserve-outer: 2.5rem;
|
|
201
|
+
--ff-countdown-reserve-cell: 0rem;
|
|
202
|
+
--ff-countdown-reserve-gap: 3rem;
|
|
203
|
+
|
|
204
|
+
/* Countdown urgency: the colours a warning or critical cell takes. */
|
|
205
|
+
--ff-countdown-tone-warning-color: var(--ff-color-warning);
|
|
206
|
+
--ff-countdown-tone-critical-color: var(--ff-color-danger);
|
|
207
|
+
--ff-countdown-tone-critical-bg: transparent;
|
|
208
|
+
--ff-countdown-tone-critical-fg: inherit;
|
|
209
|
+
|
|
210
|
+
/* Panel geometry: the padding around a panel's stack and the gap between
|
|
211
|
+
* the rows of that stack and of a panel body. */
|
|
212
|
+
--ff-panel-gap: 1.25rem;
|
|
213
|
+
--ff-panel-padding: 1.25rem;
|
|
214
|
+
|
|
215
|
+
/* Surface elevation, one token per surface and per interactive state it
|
|
216
|
+
* distinguishes. A variant that raises a surface overrides these. */
|
|
217
|
+
--ff-card-shadow: none;
|
|
218
|
+
--ff-card-shadow-hover: var(--ff-card-shadow);
|
|
219
|
+
|
|
220
|
+
/* The `elevated` card is raised above its aesthetic's resting surface, so it
|
|
221
|
+
* carries its own pair rather than reading the resting one. The default is
|
|
222
|
+
* the elevation the variant-less card has always drawn. */
|
|
223
|
+
--ff-card-shadow-elevated: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
224
|
+
--ff-card-shadow-elevated-hover: var(--ff-card-shadow-elevated);
|
|
225
|
+
--ff-progress-shadow: none;
|
|
226
|
+
--ff-progress-bar-shadow: none;
|
|
227
|
+
--ff-loading-shadow: none;
|
|
228
|
+
|
|
229
|
+
/* Surfaces that also carry a focus ring compose their shadow with it
|
|
230
|
+
* through Tailwind's own shadow utility, so the empty value here is the
|
|
231
|
+
* transparent shadow that composes rather than the `none` that would
|
|
232
|
+
* invalidate the whole list — and the ring with it. */
|
|
233
|
+
--ff-button-shadow: 0 0 #0000;
|
|
234
|
+
--ff-button-shadow-hover: var(--ff-button-shadow);
|
|
235
|
+
--ff-button-shadow-active: var(--ff-button-shadow);
|
|
236
|
+
--ff-button-shadow-primary: var(--ff-button-shadow);
|
|
237
|
+
--ff-input-shadow: 0 0 #0000;
|
|
238
|
+
--ff-input-shadow-focus: var(--ff-input-shadow);
|
|
239
|
+
--ff-otp-shadow: 0 0 #0000;
|
|
240
|
+
--ff-otp-shadow-focus: var(--ff-otp-shadow);
|
|
241
|
+
--ff-otp-shadow-focus-error: var(--ff-otp-shadow-focus);
|
|
242
|
+
|
|
243
|
+
/* Selector rows (a product, a payment method): the box a row draws and the
|
|
244
|
+
* square a product thumbnail occupies inside it. */
|
|
245
|
+
--ff-row-gap: 0.75rem;
|
|
246
|
+
--ff-row-padding: 0.75rem;
|
|
247
|
+
--ff-row-radius: 0.375rem;
|
|
248
|
+
--ff-row-thumb-size: 2.75rem;
|
|
249
|
+
--ff-row-thumb-size-narrow: 2.5rem;
|
|
250
|
+
|
|
251
|
+
/* Ledger rows: the rule drawn between them, and the colour each tone
|
|
252
|
+
* carries on the marker glyph and the value. */
|
|
253
|
+
--ff-ledger-row-padding: 0.375rem;
|
|
254
|
+
--ff-ledger-border-color: color-mix(in oklab, var(--ff-color-border) 40%, transparent);
|
|
255
|
+
--ff-ledger-tone-default: var(--ff-color-foreground);
|
|
256
|
+
--ff-ledger-tone-muted: var(--ff-color-muted);
|
|
257
|
+
--ff-ledger-tone-live: var(--ff-color-primary);
|
|
258
|
+
--ff-ledger-tone-danger: var(--ff-color-danger);
|
|
259
|
+
--ff-ledger-tone-success: var(--ff-color-success);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Hero is the same countdown at a larger scale: a taller numeral ceiling, a
|
|
264
|
+
* wider cell gap, and a gap reserve that counts that gap either side of the
|
|
265
|
+
* larger separator glyph. The variants that draw no separator reserve the
|
|
266
|
+
* gap alone.
|
|
267
|
+
*/
|
|
268
|
+
.fanfare-themed [data-slot="countdown"][data-size="hero"] {
|
|
269
|
+
--ff-countdown-numeral-max: 3.75rem;
|
|
270
|
+
--ff-countdown-cell-gap: 1rem;
|
|
271
|
+
--ff-countdown-reserve-gap: 3.75rem;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.fanfare-themed[data-fanfare-variant="retro"] [data-slot="countdown"][data-size="hero"],
|
|
275
|
+
.fanfare-themed[data-fanfare-variant="rounded"] [data-slot="countdown"][data-size="hero"] {
|
|
276
|
+
--ff-countdown-reserve-gap: 1rem;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Four unit labels plus three separators need more width than the widget
|
|
281
|
+
* has, so a countdown showing four cells drops its separators at every size
|
|
282
|
+
* and reserves the cell gap alone between cells.
|
|
283
|
+
*/
|
|
284
|
+
.fanfare-themed [data-slot="countdown"][data-units="4"] {
|
|
285
|
+
--ff-countdown-separator-display: none;
|
|
286
|
+
--ff-countdown-reserve-gap: var(--ff-countdown-cell-gap);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* The boxed variants' cell padding alone would leave four cells no room for
|
|
291
|
+
* numerals at the narrowest widget width the cells layout renders at, so a
|
|
292
|
+
* four-cell row narrows each cell's side padding; the cell reserve follows.
|
|
293
|
+
*/
|
|
294
|
+
.fanfare-themed[data-fanfare-variant="rounded"] [data-slot="countdown"][data-units="4"] {
|
|
295
|
+
--ff-countdown-cell-padding: 0.75rem 0.5rem;
|
|
296
|
+
--ff-countdown-reserve-cell: 1.125rem;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.fanfare-themed[data-fanfare-variant="retro"] [data-slot="countdown"][data-units="4"] {
|
|
300
|
+
--ff-countdown-cell-padding: 0.5rem 0.5rem;
|
|
301
|
+
--ff-countdown-reserve-cell: 1.5rem;
|
|
101
302
|
}
|
|
102
303
|
|
|
103
304
|
/**
|
|
@@ -141,3 +342,384 @@
|
|
|
141
342
|
}
|
|
142
343
|
}
|
|
143
344
|
}
|
|
345
|
+
|
|
346
|
+
@layer components {
|
|
347
|
+
/**
|
|
348
|
+
* Countdown token consumers. The layer keeps a one-off Tailwind utility
|
|
349
|
+
* winning over these rules, and the `.fanfare-themed` prefix keeps them from
|
|
350
|
+
* reaching a host page's own markup once the stylesheet is imported.
|
|
351
|
+
*/
|
|
352
|
+
/**
|
|
353
|
+
* Cells are a two-row grid: every unit spans both rows through a subgrid, so
|
|
354
|
+
* the numerals share the first row and each separator centres on that row
|
|
355
|
+
* whatever size the numerals fit to.
|
|
356
|
+
*/
|
|
357
|
+
.fanfare-themed [data-slot="countdown-cells"] {
|
|
358
|
+
column-gap: var(--ff-countdown-cell-gap);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.fanfare-themed [data-slot="countdown-unit"] {
|
|
362
|
+
padding: var(--ff-countdown-cell-padding);
|
|
363
|
+
border-radius: var(--ff-countdown-cell-radius);
|
|
364
|
+
border-width: var(--ff-countdown-cell-border-width);
|
|
365
|
+
border-style: solid;
|
|
366
|
+
background-color: var(--ff-countdown-cell-bg);
|
|
367
|
+
box-shadow: var(--ff-countdown-cell-shadow);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/* Hover elevation is gated on a real pointer, so a tap does not leave a
|
|
371
|
+
* cell raised. */
|
|
372
|
+
@media (hover: hover) {
|
|
373
|
+
.fanfare-themed [data-slot="countdown-unit"]:hover {
|
|
374
|
+
box-shadow: var(--ff-countdown-cell-shadow-hover);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* Per-digit boxes inherit the numeral face from their unit. */
|
|
379
|
+
.fanfare-themed [data-slot="countdown-unit-digits"] {
|
|
380
|
+
color: var(--ff-countdown-numeral-color);
|
|
381
|
+
font-family: var(--ff-countdown-numeral-font);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Per-unit numerals size themselves to the widget: the container's inline
|
|
386
|
+
* size less the reserved chrome, divided across every digit on screen
|
|
387
|
+
* (`--ff-countdown-digits`, across `--ff-countdown-cells` cells, at the
|
|
388
|
+
* variant's advance ratio). The per-digit granularity is excluded — its cells are fixed boxes
|
|
389
|
+
* whose numerals are sized by utility to match.
|
|
390
|
+
*
|
|
391
|
+
* `cqi` cannot name a container, so it binds to the nearest one. Every
|
|
392
|
+
* countdown the SDK renders sits under the widget root and outside
|
|
393
|
+
* `ProductSelector`'s own container, so this reads the widget's width.
|
|
394
|
+
*/
|
|
395
|
+
.fanfare-themed [data-cells="unit"] [data-slot="countdown-unit-digits"] {
|
|
396
|
+
font-size: clamp(
|
|
397
|
+
var(--ff-countdown-numeral-min),
|
|
398
|
+
calc(
|
|
399
|
+
(
|
|
400
|
+
100cqi - var(--ff-countdown-reserve-outer) - var(--ff-countdown-cells) * var(--ff-countdown-reserve-cell) -
|
|
401
|
+
(var(--ff-countdown-cells) - 1) * var(--ff-countdown-reserve-gap)
|
|
402
|
+
) /
|
|
403
|
+
(var(--ff-countdown-digits) * var(--ff-numeral-advance))
|
|
404
|
+
),
|
|
405
|
+
var(--ff-countdown-numeral-max)
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.fanfare-themed [data-slot="countdown-unit-label"] {
|
|
410
|
+
order: var(--ff-countdown-label-order);
|
|
411
|
+
font-size: var(--ff-countdown-label-size);
|
|
412
|
+
color: var(--ff-countdown-label-color);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.fanfare-themed [data-slot="countdown-separator"] {
|
|
416
|
+
display: var(--ff-countdown-separator-display);
|
|
417
|
+
color: var(--ff-countdown-separator-color);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.fanfare-themed [data-slot="countdown-separator"]::before {
|
|
421
|
+
content: var(--ff-countdown-separator-glyph);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.fanfare-themed [data-layout="inline"][data-slot="countdown"],
|
|
425
|
+
.fanfare-themed [data-slot="countdown-inline"] {
|
|
426
|
+
font-size: var(--ff-countdown-inline-size);
|
|
427
|
+
font-weight: var(--ff-countdown-inline-weight);
|
|
428
|
+
letter-spacing: var(--ff-countdown-inline-tracking);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Both layouts publish the resolved tone on their root: the cells layout
|
|
433
|
+
* colours each unit's numerals, the inline layout colours the single line,
|
|
434
|
+
* and the cells layout's narrow-container inline fallback picks up the same
|
|
435
|
+
* rule.
|
|
436
|
+
*/
|
|
437
|
+
.fanfare-themed [data-slot="countdown-unit"][data-tone="warning"] [data-slot="countdown-unit-digits"],
|
|
438
|
+
.fanfare-themed [data-slot="countdown"][data-tone="warning"] [data-slot="countdown-inline"] {
|
|
439
|
+
color: var(--ff-countdown-tone-warning-color);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.fanfare-themed [data-slot="countdown-unit"][data-tone="critical"] [data-slot="countdown-unit-digits"],
|
|
443
|
+
.fanfare-themed [data-slot="countdown"][data-tone="critical"] [data-slot="countdown-inline"] {
|
|
444
|
+
color: var(--ff-countdown-tone-critical-color);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Retro's urgency accent is part of that variant's aesthetic rather than the
|
|
449
|
+
* global danger semantic, so the filled cell is scoped to the retro variant
|
|
450
|
+
* instead of moving `--ff-color-danger`. Other variants keep the cell surface
|
|
451
|
+
* their geometry tokens give them and carry urgency in the numeral colour
|
|
452
|
+
* alone.
|
|
453
|
+
*/
|
|
454
|
+
.fanfare-themed[data-fanfare-variant="retro"] [data-slot="countdown-unit"][data-tone="critical"] {
|
|
455
|
+
background-color: var(--ff-countdown-tone-critical-bg);
|
|
456
|
+
color: var(--ff-countdown-tone-critical-fg);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* The global critical rule sets the numeral colour directly, so the filled
|
|
461
|
+
* cell's foreground has to be restated on the numerals and label rather than
|
|
462
|
+
* relied on through inheritance.
|
|
463
|
+
*/
|
|
464
|
+
.fanfare-themed[data-fanfare-variant="retro"]
|
|
465
|
+
[data-slot="countdown-unit"][data-tone="critical"]
|
|
466
|
+
[data-slot="countdown-unit-digits"],
|
|
467
|
+
.fanfare-themed[data-fanfare-variant="retro"]
|
|
468
|
+
[data-slot="countdown-unit"][data-tone="critical"]
|
|
469
|
+
[data-slot="countdown-unit-label"] {
|
|
470
|
+
color: var(--ff-countdown-tone-critical-fg);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Display text that is prose rather than a fixed glyph run: it scales with
|
|
475
|
+
* the widget between a legible floor and the design's ceiling, so a narrow
|
|
476
|
+
* embed shrinks the words instead of wrapping or clipping them.
|
|
477
|
+
*/
|
|
478
|
+
.fanfare-themed [data-slot="stat-value"] {
|
|
479
|
+
font-size: clamp(var(--ff-stat-min), var(--ff-stat-scale), var(--ff-stat-max));
|
|
480
|
+
font-weight: var(--ff-stat-weight);
|
|
481
|
+
line-height: 1.2;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.fanfare-themed [data-slot="panel-title"] {
|
|
485
|
+
font-size: clamp(var(--ff-title-min), var(--ff-title-scale), var(--ff-title-max));
|
|
486
|
+
font-weight: var(--ff-title-weight);
|
|
487
|
+
line-height: 1.4;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* The payment panel's section heading reads at body scale under its badge
|
|
492
|
+
* and hero stat. A retry moves focus to it so a screen reader starts from
|
|
493
|
+
* the explanation; it is not a control, and the Retry badge already marks
|
|
494
|
+
* the state, so the programmatic focus draws no ring.
|
|
495
|
+
*/
|
|
496
|
+
.fanfare-themed [data-slot="checkout-title"] {
|
|
497
|
+
color: var(--ff-color-foreground);
|
|
498
|
+
font-size: 0.875rem;
|
|
499
|
+
font-weight: 600;
|
|
500
|
+
line-height: 1.25rem;
|
|
501
|
+
outline: none;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.fanfare-themed [data-slot="panel-body"],
|
|
505
|
+
.fanfare-themed [data-slot="panel-stack"] {
|
|
506
|
+
gap: var(--ff-panel-gap);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.fanfare-themed [data-slot="panel-stack"] {
|
|
510
|
+
padding: var(--ff-panel-padding);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Every Card carries `data-fanfare-card` whatever `data-slot` its consumer
|
|
515
|
+
* publishes on it, so the surface rules key on that marker rather than on a
|
|
516
|
+
* slot name a panel is free to replace.
|
|
517
|
+
*/
|
|
518
|
+
.fanfare-themed [data-fanfare-card] {
|
|
519
|
+
box-shadow: var(--ff-card-shadow);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* A raised card publishes `data-elevated`, so its elevation is a token the
|
|
524
|
+
* variant reaches rather than a utility that outranks every variant's
|
|
525
|
+
* aesthetic.
|
|
526
|
+
*/
|
|
527
|
+
.fanfare-themed [data-fanfare-card][data-elevated] {
|
|
528
|
+
box-shadow: var(--ff-card-shadow-elevated);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
@media (hover: hover) {
|
|
532
|
+
.fanfare-themed [data-fanfare-card]:hover {
|
|
533
|
+
box-shadow: var(--ff-card-shadow-hover);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.fanfare-themed [data-fanfare-card][data-elevated]:hover {
|
|
537
|
+
box-shadow: var(--ff-card-shadow-elevated-hover);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.fanfare-themed [data-slot="progress-track"] {
|
|
542
|
+
box-shadow: var(--ff-progress-shadow);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
.fanfare-themed [data-slot="progress-bar"] {
|
|
546
|
+
box-shadow: var(--ff-progress-bar-shadow);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.fanfare-themed [data-slot="loading-spinner"] {
|
|
550
|
+
box-shadow: var(--ff-loading-shadow);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
.fanfare-themed [data-slot="product-selector-row"],
|
|
554
|
+
.fanfare-themed [data-slot="payment-method-row"] {
|
|
555
|
+
gap: var(--ff-row-gap);
|
|
556
|
+
padding: var(--ff-row-padding);
|
|
557
|
+
border-radius: var(--ff-row-radius);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* A payment method row draws the product selector's row, so a payment choice
|
|
562
|
+
* reads as the same kind of choice as the item it pays for. The native radio
|
|
563
|
+
* stays in the row: it carries the group's keyboard model, and the row takes
|
|
564
|
+
* its checked and focus states from it.
|
|
565
|
+
*/
|
|
566
|
+
.fanfare-themed [data-slot="payment-method-row"] {
|
|
567
|
+
display: flex;
|
|
568
|
+
align-items: center;
|
|
569
|
+
width: 100%;
|
|
570
|
+
cursor: pointer;
|
|
571
|
+
border: 1px solid color-mix(in oklab, var(--ff-color-border) 40%, transparent);
|
|
572
|
+
background-color: var(--ff-color-background);
|
|
573
|
+
transition:
|
|
574
|
+
background-color 150ms,
|
|
575
|
+
border-color 150ms,
|
|
576
|
+
box-shadow 150ms;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
@media (hover: hover) {
|
|
580
|
+
.fanfare-themed [data-slot="payment-method-row"]:hover {
|
|
581
|
+
background-color: var(--ff-color-secondary);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.fanfare-themed [data-slot="payment-method-row"]:has(:checked) {
|
|
586
|
+
border-color: var(--ff-color-foreground);
|
|
587
|
+
box-shadow: inset 0 0 0 1px var(--ff-color-foreground);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.fanfare-themed [data-slot="payment-method-row"]:has(:focus-visible) {
|
|
591
|
+
outline: 2px solid var(--ff-color-primary);
|
|
592
|
+
outline-offset: 2px;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.fanfare-themed [data-slot="payment-method-row"] > input {
|
|
596
|
+
flex-shrink: 0;
|
|
597
|
+
width: 1rem;
|
|
598
|
+
height: 1rem;
|
|
599
|
+
margin: 0;
|
|
600
|
+
outline: none;
|
|
601
|
+
accent-color: var(--ff-color-foreground);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.fanfare-themed [data-slot="payment-method-row"] > svg {
|
|
605
|
+
flex-shrink: 0;
|
|
606
|
+
width: 1.25rem;
|
|
607
|
+
height: 1.25rem;
|
|
608
|
+
color: var(--ff-color-muted);
|
|
609
|
+
fill: none;
|
|
610
|
+
stroke: currentColor;
|
|
611
|
+
stroke-width: 1.5;
|
|
612
|
+
stroke-linecap: round;
|
|
613
|
+
stroke-linejoin: round;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* The card field's frame draws the variant's text input around Stripe's
|
|
618
|
+
* iframe. Focus and validity live inside that iframe, where no selector
|
|
619
|
+
* reaches, so the element's own events publish them on the frame.
|
|
620
|
+
*/
|
|
621
|
+
.fanfare-themed [data-fanfare-field="stripe-card-frame"][data-framed] {
|
|
622
|
+
padding: 0.625rem 0.75rem;
|
|
623
|
+
border: 1px solid var(--ff-color-border);
|
|
624
|
+
border-radius: 0.375rem;
|
|
625
|
+
background-color: var(--ff-color-background);
|
|
626
|
+
transition:
|
|
627
|
+
border-color 200ms,
|
|
628
|
+
box-shadow 200ms,
|
|
629
|
+
background-color 200ms;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.fanfare-themed [data-fanfare-field="stripe-card-frame"][data-focused] {
|
|
633
|
+
border-color: var(--ff-color-primary);
|
|
634
|
+
box-shadow: 0 0 0 2px color-mix(in oklab, var(--ff-color-primary) 20%, transparent);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.fanfare-themed[data-fanfare-variant="retro"] [data-fanfare-field="stripe-card-frame"][data-framed] {
|
|
638
|
+
border: 3px solid var(--ff-color-foreground);
|
|
639
|
+
border-radius: 0;
|
|
640
|
+
box-shadow: inset 3px 3px 0 var(--ff-color-secondary);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.fanfare-themed[data-fanfare-variant="retro"] [data-fanfare-field="stripe-card-frame"][data-focused] {
|
|
644
|
+
border-color: var(--ff-color-primary);
|
|
645
|
+
box-shadow: inset 3px 3px 0 var(--ff-color-primary);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.fanfare-themed[data-fanfare-variant="rounded"] [data-fanfare-field="stripe-card-frame"][data-framed] {
|
|
649
|
+
border-color: color-mix(in oklab, var(--ff-color-foreground) 12%, transparent);
|
|
650
|
+
border-radius: 0.75rem;
|
|
651
|
+
background-color: color-mix(in oklch, var(--ff-color-foreground) 3%, var(--ff-color-background));
|
|
652
|
+
box-shadow: var(--ff-input-shadow);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.fanfare-themed[data-fanfare-variant="rounded"] [data-fanfare-field="stripe-card-frame"][data-focused] {
|
|
656
|
+
border-color: color-mix(in oklab, var(--ff-color-primary) 50%, transparent);
|
|
657
|
+
background-color: var(--ff-color-background);
|
|
658
|
+
box-shadow: var(--ff-input-shadow-focus);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.fanfare-themed[data-fanfare-variant="clean"] [data-fanfare-field="stripe-card-frame"][data-framed] {
|
|
662
|
+
padding-inline: 0;
|
|
663
|
+
border-width: 0 0 1px;
|
|
664
|
+
border-color: color-mix(in oklab, var(--ff-color-foreground) 20%, transparent);
|
|
665
|
+
border-radius: 0;
|
|
666
|
+
background-color: transparent;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.fanfare-themed[data-fanfare-variant="clean"] [data-fanfare-field="stripe-card-frame"][data-focused] {
|
|
670
|
+
border-color: var(--ff-color-primary);
|
|
671
|
+
box-shadow: none;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/* Stated after the variants, at their specificity, so every variant shows it. */
|
|
675
|
+
.fanfare-themed [data-fanfare-field="stripe-card-frame"][data-framed][data-invalid] {
|
|
676
|
+
border-color: var(--ff-color-danger);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.fanfare-themed [data-slot="product-thumb"] {
|
|
680
|
+
width: var(--ff-row-thumb-size);
|
|
681
|
+
height: var(--ff-row-thumb-size);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* The thumbnail takes its narrow side length once the picker's own container
|
|
686
|
+
* is too tight for the wide one. The query is unnamed so it binds to that
|
|
687
|
+
* container — the nearest one — rather than to the widget, which a picker
|
|
688
|
+
* rendered on its own need not sit inside.
|
|
689
|
+
*/
|
|
690
|
+
@container not (min-width: 400px) {
|
|
691
|
+
.fanfare-themed [data-slot="product-thumb"] {
|
|
692
|
+
width: var(--ff-row-thumb-size-narrow);
|
|
693
|
+
height: var(--ff-row-thumb-size-narrow);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.fanfare-themed [data-slot="ledger-row"] {
|
|
698
|
+
padding-block: var(--ff-ledger-row-padding);
|
|
699
|
+
border-bottom-color: var(--ff-ledger-border-color);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Tone is published on the row and inherited by the marker glyph and the
|
|
704
|
+
* value; the label states its own muted colour and is unaffected.
|
|
705
|
+
*/
|
|
706
|
+
.fanfare-themed [data-slot="ledger-row"][data-tone="default"] {
|
|
707
|
+
color: var(--ff-ledger-tone-default);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.fanfare-themed [data-slot="ledger-row"][data-tone="muted"] {
|
|
711
|
+
color: var(--ff-ledger-tone-muted);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.fanfare-themed [data-slot="ledger-row"][data-tone="live"] {
|
|
715
|
+
color: var(--ff-ledger-tone-live);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.fanfare-themed [data-slot="ledger-row"][data-tone="danger"] {
|
|
719
|
+
color: var(--ff-ledger-tone-danger);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.fanfare-themed [data-slot="ledger-row"][data-tone="success"] {
|
|
723
|
+
color: var(--ff-ledger-tone-success);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { WidgetVariant } from '@fanfare-io/fanfare-sdk-core/theme';
|
|
2
|
+
/** The catalogue categories, each with its own fallback stack. */
|
|
3
|
+
export type FontCategory = "Display" | "Handwriting" | "Monospace" | "Sans Serif" | "Serif";
|
|
4
|
+
export interface FontCatalogueEntry {
|
|
5
|
+
category: FontCategory;
|
|
6
|
+
/** The weights the family publishes; requesting one it lacks fails the whole font request. */
|
|
7
|
+
weights: number[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Generic stacks a browser can render without a network request, so a family that fails to load
|
|
11
|
+
* degrades to a face of the same flavour rather than to the default serif.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CATEGORY_FALLBACKS: Record<FontCategory, string>;
|
|
14
|
+
/**
|
|
15
|
+
* CSS generic families and CSS-wide keywords. A font value that is one of these names no family at
|
|
16
|
+
* all, so it is neither fetchable nor quotable: quoting it would make the browser look for a family
|
|
17
|
+
* literally called `serif`. Kept lowercase because family names are case-insensitive in CSS.
|
|
18
|
+
*/
|
|
19
|
+
export declare const GENERIC_FONT_KEYWORDS: ReadonlySet<string>;
|
|
20
|
+
/** The families the admin font picker offers, in the picker's own order. */
|
|
21
|
+
export declare const FONT_CATALOGUE: Record<string, FontCatalogueEntry>;
|
|
22
|
+
/** Whether a family resolves without a network request. Family names are case-insensitive in CSS. */
|
|
23
|
+
export declare const isSystemFont: (family: string) => boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The catalogue's own spelling of a family. CSS matches family names case-insensitively, but the
|
|
26
|
+
* Google Fonts css2 endpoint does not — it rejects `figtree` outright — so a host's casing is
|
|
27
|
+
* resolved to the catalogue's before anything is requested.
|
|
28
|
+
*/
|
|
29
|
+
export declare const catalogueFamilyName: (family: string) => string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The Google Fonts stylesheet for a family, asking for exactly the weights it publishes — the
|
|
32
|
+
* css2 endpoint rejects the whole request when it names a weight the family lacks, and several
|
|
33
|
+
* curated families publish fewer than the usual 400/500/600/700. A family outside the catalogue
|
|
34
|
+
* has no known weight list, so it is requested without a weight axis at all.
|
|
35
|
+
*/
|
|
36
|
+
export declare const googleFontStylesheetHref: (family: string) => string;
|
|
37
|
+
/** The faces a variant's own token block names: its text face, and its mono face where it has one. */
|
|
38
|
+
export interface VariantFamilies {
|
|
39
|
+
body: string;
|
|
40
|
+
mono?: string;
|
|
41
|
+
}
|
|
42
|
+
/** The families each variant's own token block names, used when a theme names none of its own. */
|
|
43
|
+
export declare const VARIANT_DEFAULT_FAMILIES: Record<WidgetVariant, VariantFamilies>;
|
|
44
|
+
/**
|
|
45
|
+
* The faces to fetch for a variant. A variant name the build does not know still reaches here — a
|
|
46
|
+
* theme served by a newer admin, or a hand-written element attribute — and takes the default
|
|
47
|
+
* variant's faces, which are the ones its token block falls back to as well.
|
|
48
|
+
*/
|
|
49
|
+
export declare const variantFamilies: (variant: string | undefined) => VariantFamilies;
|
|
50
|
+
/**
|
|
51
|
+
* Requests a family's stylesheet at most once per page. The link is inserted for print only and
|
|
52
|
+
* promoted to every medium once it has loaded, so a slow or unreachable font origin never holds
|
|
53
|
+
* first paint. A request that fails leaves nothing behind and is never retried — the theme's
|
|
54
|
+
* fallback stack carries the text, and a second attempt would spend the same latency again.
|
|
55
|
+
*/
|
|
56
|
+
export declare function ensureFontStylesheet(family: string): void;
|
|
57
|
+
/** Test-only seam: forgets which families were requested. Never exported from the package entry. */
|
|
58
|
+
export declare function resetFontLoaderCache(): void;
|