@dorsk/tsumikit 0.78.0 → 0.80.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/components/atoms/Artwork.svelte +5 -3
- package/dist/components/atoms/Badge.svelte +2 -5
- package/dist/components/atoms/Button.svelte +327 -17
- package/dist/components/atoms/Button.svelte.d.ts +4 -1
- package/dist/components/atoms/Card.svelte +160 -12
- package/dist/components/atoms/Checkbox.svelte +181 -3
- package/dist/components/atoms/Gauge.svelte +2 -2
- package/dist/components/atoms/Input.svelte +41 -3
- package/dist/components/atoms/Kbd.svelte +1 -1
- package/dist/components/atoms/Link.svelte +61 -0
- package/dist/components/atoms/Progress.svelte +75 -2
- package/dist/components/atoms/Progress.svelte.d.ts +1 -0
- package/dist/components/atoms/SegmentedProgress.svelte +2 -2
- package/dist/components/atoms/Select.svelte +39 -3
- package/dist/components/atoms/Skeleton.svelte +54 -3
- package/dist/components/atoms/Skeleton.svelte.d.ts +1 -0
- package/dist/components/atoms/Slider.svelte +8 -6
- package/dist/components/atoms/Spinner.svelte +152 -3
- package/dist/components/atoms/Spinner.svelte.d.ts +1 -1
- package/dist/components/atoms/Swatch.svelte +1 -1
- package/dist/components/atoms/Switch.svelte +138 -2
- package/dist/components/atoms/Textarea.svelte +42 -3
- package/dist/components/atoms/Thinking.svelte +130 -0
- package/dist/components/atoms/Thinking.svelte.d.ts +15 -0
- package/dist/components/layouts/AppShell.svelte +6 -6
- package/dist/components/layouts/MasterDetail.svelte +3 -3
- package/dist/components/layouts/NavBar.svelte +4 -4
- package/dist/components/layouts/NavSection.svelte +1 -1
- package/dist/components/layouts/ResizablePanel.svelte +7 -7
- package/dist/components/layouts/TabBar.svelte +2 -2
- package/dist/components/molecules/Accordion.svelte +2 -2
- package/dist/components/molecules/AttachmentList.svelte +2 -2
- package/dist/components/molecules/CapBar.svelte +2 -2
- package/dist/components/molecules/CodeBlock.svelte +5 -5
- package/dist/components/molecules/Combobox.svelte +3 -3
- package/dist/components/molecules/CopyButton.svelte +146 -5
- package/dist/components/molecules/Drawer.svelte +8 -8
- package/dist/components/molecules/EmojiPicker.svelte +1 -1
- package/dist/components/molecules/Field.svelte +55 -1
- package/dist/components/molecules/FileButton.svelte +20 -6
- package/dist/components/molecules/FilterInput.svelte +4 -4
- package/dist/components/molecules/GitRef.svelte +2 -2
- package/dist/components/molecules/GlyphStack.svelte +21 -3
- package/dist/components/molecules/InputGroup.svelte +3 -3
- package/dist/components/molecules/LookPicker.svelte +87 -0
- package/dist/components/molecules/LookPicker.svelte.d.ts +17 -0
- package/dist/components/molecules/Modal.svelte +5 -5
- package/dist/components/molecules/MotionSettings.svelte +166 -0
- package/dist/components/molecules/MotionSettings.svelte.d.ts +18 -0
- package/dist/components/molecules/OptionButton.svelte +8 -3
- package/dist/components/molecules/Pagination.svelte +3 -1
- package/dist/components/molecules/Popover.svelte +18 -11
- package/dist/components/molecules/Prose.svelte +6 -6
- package/dist/components/molecules/RadialMenu.svelte +3 -3
- package/dist/components/molecules/RadioGroup.svelte +67 -4
- package/dist/components/molecules/RichSelect.svelte +6 -4
- package/dist/components/molecules/SectionHeader.svelte +1 -1
- package/dist/components/molecules/SeekSlider.svelte +6 -6
- package/dist/components/molecules/SegmentedControl.svelte +7 -7
- package/dist/components/molecules/SortableList.svelte +2 -2
- package/dist/components/molecules/SplitButton.svelte +1 -1
- package/dist/components/molecules/Tabs.svelte +160 -7
- package/dist/components/molecules/ThemePicker.svelte +1 -1
- package/dist/components/molecules/Timestamp.svelte +1 -1
- package/dist/components/molecules/Toggle.svelte +5 -3
- package/dist/components/molecules/Tooltip.svelte +2 -2
- package/dist/components/molecules/VolumeSlider.svelte +3 -3
- package/dist/components/organisms/ConversationFeed.svelte +1 -1
- package/dist/components/organisms/ConversationPanel.svelte +3 -3
- package/dist/components/organisms/DataTable.svelte +18 -16
- package/dist/fx.d.ts +149 -0
- package/dist/fx.js +111 -0
- package/dist/fx.md +58 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +8 -2
- package/dist/looks/README.md +101 -0
- package/dist/looks/depth.css +939 -0
- package/dist/looks/editorial.css +545 -0
- package/dist/looks/tactile.css +871 -0
- package/dist/pointer.d.ts +3 -0
- package/dist/pointer.js +40 -0
- package/dist/stores/fx.svelte.d.ts +17 -0
- package/dist/stores/fx.svelte.js +64 -0
- package/dist/stores/theme.svelte.d.ts +8 -2
- package/dist/stores/theme.svelte.js +33 -7
- package/dist/styles/themes.css +249 -249
- package/dist/styles/tokens.css +37 -2
- package/dist/theme-mode.d.ts +31 -0
- package/dist/theme-mode.js +19 -0
- package/package.json +3 -2
|
@@ -102,13 +102,14 @@
|
|
|
102
102
|
justify-content: center;
|
|
103
103
|
overflow: hidden;
|
|
104
104
|
flex: none;
|
|
105
|
-
background: var(--
|
|
106
|
-
border:
|
|
105
|
+
background: var(--surface-fill-2);
|
|
106
|
+
border: var(--edge-width) solid var(--surface-edge);
|
|
107
107
|
color: var(--text-muted);
|
|
108
108
|
container-type: inline-size;
|
|
109
109
|
transition:
|
|
110
110
|
border-color var(--dur-fast) var(--ease),
|
|
111
111
|
box-shadow var(--dur-fast) var(--ease),
|
|
112
|
+
translate var(--dur-fast) var(--ease-out),
|
|
112
113
|
scale var(--dur-fast) var(--ease-out);
|
|
113
114
|
}
|
|
114
115
|
.r-sm {
|
|
@@ -125,8 +126,9 @@
|
|
|
125
126
|
}
|
|
126
127
|
@media (hover: hover) and (pointer: fine) {
|
|
127
128
|
.hover:hover {
|
|
128
|
-
border-color: var(--
|
|
129
|
+
border-color: var(--surface-edge-strong);
|
|
129
130
|
box-shadow: var(--shadow-md);
|
|
131
|
+
translate: 0 calc(-1 * var(--hover-lift));
|
|
130
132
|
}
|
|
131
133
|
}
|
|
132
134
|
.hover:active {
|
|
@@ -195,7 +195,7 @@
|
|
|
195
195
|
--icon-size: var(--icon-xs);
|
|
196
196
|
background: var(--badge-bg, var(--bg-elevated-2));
|
|
197
197
|
color: var(--badge-fg, var(--text-muted));
|
|
198
|
-
border:
|
|
198
|
+
border: var(--edge-width) solid var(--badge-border, var(--border));
|
|
199
199
|
white-space: nowrap;
|
|
200
200
|
max-width: var(--badge-max-width, 100%);
|
|
201
201
|
}
|
|
@@ -213,7 +213,7 @@
|
|
|
213
213
|
line-height: var(--lh-none);
|
|
214
214
|
}
|
|
215
215
|
.toned {
|
|
216
|
-
color: var(--badge-fg, var(--badge-tone));
|
|
216
|
+
color: var(--badge-fg, color-mix(in oklab, var(--badge-tone) 75%, var(--text)));
|
|
217
217
|
border-color: var(--badge-border, color-mix(in srgb, var(--badge-tone) 40%, transparent));
|
|
218
218
|
background: var(--badge-bg, color-mix(in srgb, var(--badge-tone) 12%, transparent));
|
|
219
219
|
}
|
|
@@ -310,15 +310,12 @@
|
|
|
310
310
|
font: inherit;
|
|
311
311
|
line-height: var(--lh-none);
|
|
312
312
|
cursor: pointer;
|
|
313
|
-
opacity: 0.6;
|
|
314
313
|
transition:
|
|
315
|
-
opacity var(--dur-fast) var(--ease),
|
|
316
314
|
background var(--dur-fast) var(--ease),
|
|
317
315
|
scale var(--dur-fast) var(--ease-out);
|
|
318
316
|
}
|
|
319
317
|
@media (hover: hover) and (pointer: fine) {
|
|
320
318
|
.action:hover {
|
|
321
|
-
opacity: 1;
|
|
322
319
|
background: color-mix(in srgb, currentColor 12%, transparent);
|
|
323
320
|
transition-duration: var(--dur-instant);
|
|
324
321
|
}
|
|
@@ -57,8 +57,20 @@
|
|
|
57
57
|
// moving layout; `compact` opts out in dense tables.
|
|
58
58
|
hitArea?: 'auto' | 'compact';
|
|
59
59
|
// Async/busy state: shows a spinner, blocks clicks, sets aria-busy. Stays
|
|
60
|
-
// disabled-equivalent while true (so a double-submit can't fire).
|
|
61
|
-
|
|
60
|
+
// disabled-equivalent while true (so a double-submit can't fire). `'done'`
|
|
61
|
+
// is the settled state after a busy run: clickable again, a check beside
|
|
62
|
+
// the label (with `loadingStyle="morph"` the label springs back in).
|
|
63
|
+
loading?: boolean | 'done';
|
|
64
|
+
// How a busy button shows it: an inline spinner before the label, the label
|
|
65
|
+
// morphing into a centred spinner at constant width, or a progress fill
|
|
66
|
+
// pouring in from the left (driven by `progress`).
|
|
67
|
+
loadingStyle?: 'spinner' | 'morph' | 'fill';
|
|
68
|
+
// 0–1 for `loadingStyle="fill"`; omit for an indeterminate idle fill.
|
|
69
|
+
progress?: number;
|
|
70
|
+
// Text beside the check in the `'done'` state; defaults to the children.
|
|
71
|
+
// With `morph`, keep the children constant and set this instead so both
|
|
72
|
+
// stacked labels size the button and its width never changes.
|
|
73
|
+
doneLabel?: string;
|
|
62
74
|
// Corner count indicator (unread, selected, pending). Hidden at 0/undefined;
|
|
63
75
|
// shows `${countMax}+` past the cap while the accessible name carries the
|
|
64
76
|
// exact number. Tint via `--btn-count-bg` / `--btn-count-fg`.
|
|
@@ -100,6 +112,9 @@
|
|
|
100
112
|
collapseLabel = 'never',
|
|
101
113
|
hitArea = 'auto',
|
|
102
114
|
loading = false,
|
|
115
|
+
loadingStyle = 'spinner',
|
|
116
|
+
progress,
|
|
117
|
+
doneLabel,
|
|
103
118
|
count,
|
|
104
119
|
countMax = 99,
|
|
105
120
|
layout = 'inline',
|
|
@@ -120,7 +135,10 @@
|
|
|
120
135
|
// A link-flavoured Button is a real <a>; native `disabled`/`type` don't apply,
|
|
121
136
|
// so an inactive link drops `href` (no focus, no keyboard activation).
|
|
122
137
|
const tag = $derived(href !== undefined || as === 'a' ? 'a' : 'button');
|
|
123
|
-
const
|
|
138
|
+
const busy = $derived(loading === true);
|
|
139
|
+
const done = $derived(loading === 'done');
|
|
140
|
+
const layered = $derived(loadingStyle !== 'spinner');
|
|
141
|
+
const inactive = $derived(disabled || busy);
|
|
124
142
|
const elementAttrs = $derived(
|
|
125
143
|
tag === 'a'
|
|
126
144
|
? inactive
|
|
@@ -174,7 +192,7 @@
|
|
|
174
192
|
{...rest}
|
|
175
193
|
{...elementAttrs}
|
|
176
194
|
aria-label={ariaLabel}
|
|
177
|
-
aria-busy={
|
|
195
|
+
aria-busy={busy || undefined}
|
|
178
196
|
aria-pressed={pressed ?? rest['aria-pressed']}
|
|
179
197
|
aria-keyshortcuts={rest['aria-keyshortcuts'] ?? keyHint}
|
|
180
198
|
{title}
|
|
@@ -198,6 +216,7 @@
|
|
|
198
216
|
class:btn-collapse-container={collapseLabel === 'container'}
|
|
199
217
|
class:hit-compact={hitArea === 'compact'}
|
|
200
218
|
style:--btn-box={box ? `var(--box-${box})` : undefined}
|
|
219
|
+
style:--btn-progress={loadingStyle === 'fill' && progress !== undefined ? Math.min(1, Math.max(0, progress)) : undefined}
|
|
201
220
|
class:btn-tone-accent={t === 'accent'}
|
|
202
221
|
class:btn-tone-success={t === 'ok'}
|
|
203
222
|
class:btn-tone-info={t === 'info'}
|
|
@@ -205,13 +224,17 @@
|
|
|
205
224
|
class:btn-tone-danger={t === 'danger'}
|
|
206
225
|
class:btn-icon-inline={iconInline}
|
|
207
226
|
class:hover-danger={hoverDanger}
|
|
208
|
-
class:loading
|
|
227
|
+
class:loading={busy}
|
|
228
|
+
class:btn-done={done}
|
|
229
|
+
class:btn-morph={loadingStyle === 'morph'}
|
|
230
|
+
class:btn-fill={loadingStyle === 'fill'}
|
|
209
231
|
class:btn-counted={counted}
|
|
210
232
|
class:btn-stacked={stacked}
|
|
211
233
|
class:btn-hinted={keyHint !== undefined}
|
|
212
234
|
onclick={handleClick}
|
|
213
235
|
>
|
|
214
|
-
{#if
|
|
236
|
+
{#if loadingStyle === 'fill'}<span class="btn-fill-bar" aria-hidden="true"></span>{/if}
|
|
237
|
+
{#if busy && !layered}<span class="btn-spinner" aria-hidden="true"></span>{:else if done && !layered}<span class="btn-check" aria-hidden="true"><Icon name="check" /></span>{/if}
|
|
215
238
|
{#if glyph !== undefined}
|
|
216
239
|
<span class="btn-glyph" aria-hidden="true">
|
|
217
240
|
{#if typeof glyph !== 'string'}{@render glyph()}{:else if isIconName(glyph)}<Icon name={glyph} />{:else}{glyph}{/if}
|
|
@@ -219,6 +242,16 @@
|
|
|
219
242
|
{/if}
|
|
220
243
|
{#if stacked}
|
|
221
244
|
<span class="btn-stack-label">{@render children?.()}</span>
|
|
245
|
+
{:else if layered}
|
|
246
|
+
<span class="btn-layers">
|
|
247
|
+
<span class="btn-layer btn-layer-label">{@render children?.()}</span>
|
|
248
|
+
{#if loadingStyle === 'morph'}
|
|
249
|
+
<span class="btn-layer btn-layer-spin" aria-hidden="true"></span>
|
|
250
|
+
<span class="btn-layer btn-layer-done" aria-hidden="true"><Icon name="check" />{#if doneLabel !== undefined}{doneLabel}{:else}{@render children?.()}{/if}</span>
|
|
251
|
+
{:else}
|
|
252
|
+
<span class="btn-layer btn-layer-ink" aria-hidden="true">{@render children?.()}</span>
|
|
253
|
+
{/if}
|
|
254
|
+
</span>
|
|
222
255
|
{:else}
|
|
223
256
|
{@render children?.()}
|
|
224
257
|
{/if}
|
|
@@ -242,21 +275,28 @@
|
|
|
242
275
|
padding: var(--sp-2) var(--btn-px-md);
|
|
243
276
|
min-height: var(--btn-size, var(--control-height-default));
|
|
244
277
|
max-width: 100%;
|
|
245
|
-
border:
|
|
278
|
+
border: var(--edge-width) solid var(--btn-border, var(--btn-edge));
|
|
246
279
|
border-radius: var(--btn-radius, var(--r-md));
|
|
247
|
-
background: var(--btn-bg, var(--
|
|
280
|
+
background: var(--btn-bg, var(--btn-fill));
|
|
281
|
+
--btn-shadow-rest: var(--btn-shadow);
|
|
282
|
+
--btn-shadow-lift: var(--btn-shadow-hover);
|
|
283
|
+
box-shadow: var(--btn-shadow-rest);
|
|
248
284
|
color: var(--btn-fg, var(--text));
|
|
249
285
|
font-weight: var(--fw-medium);
|
|
250
286
|
font-size: var(--control-fs-md);
|
|
251
287
|
line-height: var(--lh-none);
|
|
252
288
|
--icon-size: var(--control-icon-md);
|
|
253
|
-
--btn-scale-dur: var(--dur-
|
|
289
|
+
--btn-scale-dur: var(--dur-release);
|
|
290
|
+
--btn-scale-ease: var(--ease-spring-bounce);
|
|
254
291
|
transition:
|
|
255
292
|
background var(--dur-fast) ease,
|
|
256
293
|
border-color var(--dur-fast) ease,
|
|
294
|
+
box-shadow var(--dur-fast) ease,
|
|
257
295
|
color var(--dur-fast) ease,
|
|
258
296
|
opacity var(--dur-fast) ease,
|
|
259
|
-
|
|
297
|
+
filter var(--dur-fast) ease,
|
|
298
|
+
translate var(--dur-fast) var(--ease-out),
|
|
299
|
+
scale var(--btn-scale-dur) var(--btn-scale-ease);
|
|
260
300
|
user-select: none;
|
|
261
301
|
white-space: normal;
|
|
262
302
|
overflow-wrap: break-word;
|
|
@@ -265,9 +305,13 @@
|
|
|
265
305
|
opacity: var(--disabled-opacity);
|
|
266
306
|
cursor: not-allowed;
|
|
267
307
|
}
|
|
268
|
-
|
|
308
|
+
.btn:focus-visible:not(.btn-link, .btn-icon-inline, [aria-pressed='true']) {
|
|
309
|
+
box-shadow: var(--btn-shadow-rest), var(--focus-glow);
|
|
310
|
+
}
|
|
311
|
+
/* Press: scale in over --dur-press, spring back over --dur-release. */
|
|
269
312
|
.btn:active:not(:disabled, [aria-disabled='true'], .loading, .btn-link) {
|
|
270
313
|
--btn-scale-dur: var(--dur-press);
|
|
314
|
+
--btn-scale-ease: var(--ease-out);
|
|
271
315
|
scale: var(--press-scale);
|
|
272
316
|
}
|
|
273
317
|
.btn-icon:active:not(:disabled, [aria-disabled='true'], .loading),
|
|
@@ -277,8 +321,10 @@
|
|
|
277
321
|
scale: var(--press-scale-sm);
|
|
278
322
|
}
|
|
279
323
|
.btn-primary {
|
|
280
|
-
background: var(--btn-bg, var(--
|
|
281
|
-
border-color: var(--btn-border, var(--
|
|
324
|
+
background: var(--btn-bg, var(--btn-primary-fill));
|
|
325
|
+
border-color: var(--btn-border, var(--btn-primary-edge));
|
|
326
|
+
--btn-shadow-rest: var(--btn-primary-shadow);
|
|
327
|
+
--btn-shadow-lift: var(--btn-primary-shadow-hover);
|
|
282
328
|
color: var(--btn-fg, var(--text-on-accent));
|
|
283
329
|
font-weight: var(--fw-semibold);
|
|
284
330
|
}
|
|
@@ -289,6 +335,8 @@
|
|
|
289
335
|
.btn-ghost {
|
|
290
336
|
background: var(--btn-bg, transparent);
|
|
291
337
|
border-color: var(--btn-border, transparent);
|
|
338
|
+
--btn-shadow-rest: none;
|
|
339
|
+
--btn-shadow-lift: none;
|
|
292
340
|
}
|
|
293
341
|
.btn-sm {
|
|
294
342
|
min-height: var(--btn-size, var(--control-height-compact));
|
|
@@ -372,9 +420,9 @@
|
|
|
372
420
|
height: var(--btn-size, var(--control-height));
|
|
373
421
|
min-height: var(--btn-size, var(--control-height));
|
|
374
422
|
padding: 0 var(--control-px-md);
|
|
375
|
-
border:
|
|
423
|
+
border: var(--edge-width) solid var(--btn-border, var(--btn-edge));
|
|
376
424
|
border-radius: var(--btn-radius, var(--r-md));
|
|
377
|
-
background: var(--btn-bg, var(--
|
|
425
|
+
background: var(--btn-bg, var(--btn-fill));
|
|
378
426
|
color: var(--btn-fg, var(--text));
|
|
379
427
|
font-weight: var(--fw-medium);
|
|
380
428
|
font-size: var(--control-fs-md);
|
|
@@ -390,8 +438,8 @@
|
|
|
390
438
|
the primary action with the neutral --surface; restore the accent fill when
|
|
391
439
|
both are present. */
|
|
392
440
|
.btn-control.btn-primary {
|
|
393
|
-
background: var(--btn-bg, var(--
|
|
394
|
-
border-color: var(--btn-border, var(--
|
|
441
|
+
background: var(--btn-bg, var(--btn-primary-fill));
|
|
442
|
+
border-color: var(--btn-border, var(--btn-primary-edge));
|
|
395
443
|
color: var(--btn-fg, var(--text-on-accent));
|
|
396
444
|
}
|
|
397
445
|
.btn-control.btn-tone-success {
|
|
@@ -730,6 +778,8 @@
|
|
|
730
778
|
@media (hover: hover) and (pointer: fine) {
|
|
731
779
|
.btn:hover:not(:disabled) {
|
|
732
780
|
border-color: var(--accent);
|
|
781
|
+
translate: 0 calc(-1 * var(--hover-lift));
|
|
782
|
+
--btn-shadow-rest: var(--btn-shadow-lift);
|
|
733
783
|
}
|
|
734
784
|
.btn-primary:hover:not(:disabled) {
|
|
735
785
|
filter: brightness(1.08);
|
|
@@ -782,15 +832,275 @@
|
|
|
782
832
|
.btn-link:hover:not(:disabled) {
|
|
783
833
|
background: none;
|
|
784
834
|
border: none;
|
|
835
|
+
translate: none;
|
|
785
836
|
text-decoration: underline;
|
|
786
837
|
}
|
|
787
838
|
.btn-icon-inline:hover:not(:disabled) {
|
|
788
839
|
border: none;
|
|
789
840
|
background: none;
|
|
841
|
+
translate: none;
|
|
790
842
|
color: var(--text);
|
|
791
843
|
}
|
|
792
844
|
.btn-icon-inline.hover-danger:hover:not(:disabled) {
|
|
793
845
|
color: var(--danger);
|
|
794
846
|
}
|
|
795
847
|
}
|
|
848
|
+
/* Loading styles. `morph`: label, spinner and done check stack in one grid
|
|
849
|
+
cell so the width never changes. `fill`: a progress bar under the label,
|
|
850
|
+
the label recoloured where the bar has passed. */
|
|
851
|
+
.btn-check {
|
|
852
|
+
display: inline-flex;
|
|
853
|
+
flex: none;
|
|
854
|
+
--icon-size: 0.9em;
|
|
855
|
+
}
|
|
856
|
+
.btn-layers {
|
|
857
|
+
position: relative;
|
|
858
|
+
display: grid;
|
|
859
|
+
place-items: center;
|
|
860
|
+
min-width: 0;
|
|
861
|
+
}
|
|
862
|
+
.btn-layer {
|
|
863
|
+
grid-area: 1 / 1;
|
|
864
|
+
display: inline-flex;
|
|
865
|
+
align-items: center;
|
|
866
|
+
gap: var(--sp-2);
|
|
867
|
+
white-space: nowrap;
|
|
868
|
+
font-variant-numeric: tabular-nums;
|
|
869
|
+
transition:
|
|
870
|
+
opacity var(--dur-base) var(--ease-out),
|
|
871
|
+
scale var(--dur-base) var(--ease-out),
|
|
872
|
+
translate var(--dur-base) var(--ease-out);
|
|
873
|
+
}
|
|
874
|
+
.btn-layer-spin {
|
|
875
|
+
width: 1em;
|
|
876
|
+
height: 1em;
|
|
877
|
+
border-radius: var(--r-pill);
|
|
878
|
+
mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 1.5px));
|
|
879
|
+
background: conic-gradient(from 0deg, transparent 0 30%, currentColor);
|
|
880
|
+
opacity: 0;
|
|
881
|
+
scale: 0.4;
|
|
882
|
+
}
|
|
883
|
+
.btn-layer-done {
|
|
884
|
+
opacity: 0;
|
|
885
|
+
translate: 0 0.5em;
|
|
886
|
+
--icon-size: 0.9em;
|
|
887
|
+
}
|
|
888
|
+
.btn-morph.loading .btn-layer-label,
|
|
889
|
+
.btn-morph.btn-done .btn-layer-label {
|
|
890
|
+
opacity: 0;
|
|
891
|
+
scale: 0.85;
|
|
892
|
+
}
|
|
893
|
+
.btn-morph.loading .btn-layer-spin {
|
|
894
|
+
opacity: 1;
|
|
895
|
+
scale: 1;
|
|
896
|
+
animation: btn-spin 0.9s linear infinite;
|
|
897
|
+
}
|
|
898
|
+
.btn-morph.btn-done .btn-layer-done {
|
|
899
|
+
opacity: 1;
|
|
900
|
+
translate: none;
|
|
901
|
+
transition-timing-function: var(--ease-spring-bounce);
|
|
902
|
+
transition-duration: var(--dur-spring);
|
|
903
|
+
}
|
|
904
|
+
.btn-fill {
|
|
905
|
+
position: relative;
|
|
906
|
+
isolation: isolate;
|
|
907
|
+
overflow: hidden;
|
|
908
|
+
--btn-progress-fill: var(--accent);
|
|
909
|
+
--btn-progress-fg: var(--text-on-accent);
|
|
910
|
+
}
|
|
911
|
+
.btn-fill.btn-primary {
|
|
912
|
+
--btn-progress-fill: color-mix(in srgb, var(--text-on-accent) 22%, transparent);
|
|
913
|
+
--btn-progress-fg: currentColor;
|
|
914
|
+
}
|
|
915
|
+
.btn-fill-bar {
|
|
916
|
+
position: absolute;
|
|
917
|
+
inset: 0;
|
|
918
|
+
z-index: 0;
|
|
919
|
+
background: var(--btn-progress-fill);
|
|
920
|
+
scale: var(--btn-progress, 0) 1;
|
|
921
|
+
transform-origin: left;
|
|
922
|
+
transition: scale var(--dur-slow) var(--ease-out);
|
|
923
|
+
pointer-events: none;
|
|
924
|
+
}
|
|
925
|
+
.btn-fill .btn-layers {
|
|
926
|
+
z-index: 1;
|
|
927
|
+
}
|
|
928
|
+
.btn-layer-ink {
|
|
929
|
+
position: absolute;
|
|
930
|
+
inset: 0;
|
|
931
|
+
justify-content: center;
|
|
932
|
+
color: var(--btn-progress-fg);
|
|
933
|
+
clip-path: inset(0 calc((1 - var(--btn-progress, 0)) * 100%) 0 0);
|
|
934
|
+
transition: clip-path var(--dur-slow) var(--ease-out);
|
|
935
|
+
}
|
|
936
|
+
.btn-fill:not(.loading, .btn-done) .btn-fill-bar,
|
|
937
|
+
.btn-fill:not(.loading, .btn-done) .btn-layer-ink {
|
|
938
|
+
transition-duration: var(--dur-fast);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/* Ambient hover: an effect chosen by `data-fx-hover` on the nearest ancestor
|
|
942
|
+
that sets it (`smoke` when none does, `none` turns it off). Two layers under
|
|
943
|
+
the content run their loop only while hovered; keyboard focus holds a still
|
|
944
|
+
frame. Boxless buttons and a corner count (clipped by overflow) opt out. */
|
|
945
|
+
.btn {
|
|
946
|
+
--fx-ink: color-mix(in srgb, var(--btn-tone, var(--accent)) 26%, transparent);
|
|
947
|
+
--fx-ember: color-mix(in srgb, var(--warn) 55%, var(--accent));
|
|
948
|
+
--fx-a1: color-mix(in srgb, var(--accent) 34%, transparent);
|
|
949
|
+
--fx-a2: color-mix(in srgb, var(--info) 30%, transparent);
|
|
950
|
+
--fx-a3: color-mix(in srgb, var(--ok) 30%, transparent);
|
|
951
|
+
}
|
|
952
|
+
.btn-danger {
|
|
953
|
+
--fx-ink: color-mix(in srgb, var(--danger) 26%, transparent);
|
|
954
|
+
}
|
|
955
|
+
.btn-primary {
|
|
956
|
+
--fx-ink: color-mix(in srgb, var(--text-on-accent) 16%, transparent);
|
|
957
|
+
--fx-ember: color-mix(in srgb, var(--warn) 70%, var(--text-on-accent));
|
|
958
|
+
--fx-a1: color-mix(in srgb, var(--text-on-accent) 18%, transparent);
|
|
959
|
+
--fx-a2: color-mix(in srgb, var(--info) 45%, transparent);
|
|
960
|
+
--fx-a3: color-mix(in srgb, var(--ok) 40%, transparent);
|
|
961
|
+
}
|
|
962
|
+
@media (hover: hover) and (pointer: fine) {
|
|
963
|
+
.btn:where(:not(.btn-link, .btn-icon-inline, .btn-counted)):where(:not(:global([data-fx-hover]) *), :global([data-fx-hover]:not([data-fx-hover='none'])) *) {
|
|
964
|
+
position: relative;
|
|
965
|
+
isolation: isolate;
|
|
966
|
+
overflow: hidden;
|
|
967
|
+
}
|
|
968
|
+
.btn:where(:not(.btn-link, .btn-icon-inline, .btn-counted)):where(:not(:global([data-fx-hover]) *), :global([data-fx-hover]:not([data-fx-hover='none'])) *)::before,
|
|
969
|
+
.btn:where(:not(.btn-link, .btn-icon-inline, .btn-counted)):where(:not(:global([data-fx-hover]) *), :global([data-fx-hover]:not([data-fx-hover='none'])) *)::after {
|
|
970
|
+
content: '';
|
|
971
|
+
position: absolute;
|
|
972
|
+
inset: 0;
|
|
973
|
+
z-index: -1;
|
|
974
|
+
pointer-events: none;
|
|
975
|
+
opacity: 0;
|
|
976
|
+
transition: opacity var(--dur-fast) ease;
|
|
977
|
+
}
|
|
978
|
+
.btn:hover:not(:disabled)::before,
|
|
979
|
+
.btn:hover:not(:disabled)::after,
|
|
980
|
+
.btn:focus-visible::before,
|
|
981
|
+
.btn:focus-visible::after {
|
|
982
|
+
opacity: 1;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/* smoke: two soft puffs drift up and across the fill */
|
|
986
|
+
.btn:where(:not(:global([data-fx-hover]) *), :global([data-fx-hover='smoke']) *):where(:not(:global([data-fx-hover='smoke'] [data-fx-hover]:not([data-fx-hover='smoke'])) *))::before,
|
|
987
|
+
.btn:where(:not(:global([data-fx-hover]) *), :global([data-fx-hover='smoke']) *):where(:not(:global([data-fx-hover='smoke'] [data-fx-hover]:not([data-fx-hover='smoke'])) *))::after {
|
|
988
|
+
inset: -60% -30%;
|
|
989
|
+
background:
|
|
990
|
+
radial-gradient(40% 55% at 30% 60%, var(--fx-ink), transparent 70%),
|
|
991
|
+
radial-gradient(35% 45% at 70% 40%, var(--fx-ink), transparent 70%);
|
|
992
|
+
translate: 0 15%;
|
|
993
|
+
animation: fx-smoke 7s var(--ease-in-out) infinite alternate;
|
|
994
|
+
}
|
|
995
|
+
.btn:where(:not(:global([data-fx-hover]) *), :global([data-fx-hover='smoke']) *):where(:not(:global([data-fx-hover='smoke'] [data-fx-hover]:not([data-fx-hover='smoke'])) *))::after {
|
|
996
|
+
background:
|
|
997
|
+
radial-gradient(30% 40% at 55% 70%, var(--fx-ink), transparent 70%),
|
|
998
|
+
radial-gradient(25% 35% at 20% 30%, var(--fx-ink), transparent 70%);
|
|
999
|
+
translate: 0 -10%;
|
|
1000
|
+
animation: fx-smoke-b 9s var(--ease-in-out) infinite alternate;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/* ember: a warm glow breathes at the bottom edge, sparks rise; press sinks 1px */
|
|
1004
|
+
.btn:where(:global([data-fx-hover='ember']) *):where(:not(:global([data-fx-hover='ember'] [data-fx-hover]:not([data-fx-hover='ember'])) *)) {
|
|
1005
|
+
--press-scale: var(--press-scale-lg);
|
|
1006
|
+
}
|
|
1007
|
+
.btn:where(:global([data-fx-hover='ember']) *):where(:not(:global([data-fx-hover='ember'] [data-fx-hover]:not([data-fx-hover='ember'])) *)):active:not(:disabled, [aria-disabled='true'], .loading, .btn-link) {
|
|
1008
|
+
translate: 0 calc(var(--shift-xs) / 2 - var(--hover-lift));
|
|
1009
|
+
--btn-shadow-rest: none;
|
|
1010
|
+
}
|
|
1011
|
+
.btn:where(:global([data-fx-hover='ember']) *):where(:not(:global([data-fx-hover='ember'] [data-fx-hover]:not([data-fx-hover='ember'])) *))::before {
|
|
1012
|
+
background: radial-gradient(70% 90% at 50% 115%, color-mix(in srgb, var(--fx-ember) 55%, transparent), transparent 70%);
|
|
1013
|
+
transform-origin: 50% 100%;
|
|
1014
|
+
animation: fx-ember 2.4s var(--ease-in-out) infinite;
|
|
1015
|
+
}
|
|
1016
|
+
.btn:where(:global([data-fx-hover='ember']) *):where(:not(:global([data-fx-hover='ember'] [data-fx-hover]:not([data-fx-hover='ember'])) *))::after {
|
|
1017
|
+
inset: 0 0 -100% 0;
|
|
1018
|
+
background:
|
|
1019
|
+
radial-gradient(circle at 18% 62%, var(--fx-ember) 0 1px, transparent 1.6px),
|
|
1020
|
+
radial-gradient(circle at 36% 88%, var(--fx-ember) 0 1.3px, transparent 1.9px),
|
|
1021
|
+
radial-gradient(circle at 52% 70%, var(--fx-ember) 0 0.9px, transparent 1.5px),
|
|
1022
|
+
radial-gradient(circle at 70% 94%, var(--fx-ember) 0 1.2px, transparent 1.8px),
|
|
1023
|
+
radial-gradient(circle at 84% 58%, var(--fx-ember) 0 1px, transparent 1.6px),
|
|
1024
|
+
radial-gradient(circle at 92% 80%, var(--fx-ember) 0 0.8px, transparent 1.4px);
|
|
1025
|
+
animation: fx-sparks 3.2s linear infinite;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/* aurora: accent, info and success flow through the fill in two crossing layers */
|
|
1029
|
+
.btn:where(:global([data-fx-hover='aurora']) *):where(:not(:global([data-fx-hover='aurora'] [data-fx-hover]:not([data-fx-hover='aurora'])) *))::before,
|
|
1030
|
+
.btn:where(:global([data-fx-hover='aurora']) *):where(:not(:global([data-fx-hover='aurora'] [data-fx-hover]:not([data-fx-hover='aurora'])) *))::after {
|
|
1031
|
+
inset: 0 auto 0 0;
|
|
1032
|
+
width: 300%;
|
|
1033
|
+
background: linear-gradient(90deg, var(--fx-a1), var(--fx-a2), var(--fx-a3), var(--fx-a1));
|
|
1034
|
+
background-size: 33.3334% 100%;
|
|
1035
|
+
mask-image: radial-gradient(120% 110% at 50% -10%, #000 40%, transparent 100%);
|
|
1036
|
+
translate: -33.3334% 0;
|
|
1037
|
+
animation: fx-aurora 7s linear infinite;
|
|
1038
|
+
}
|
|
1039
|
+
.btn:where(:global([data-fx-hover='aurora']) *):where(:not(:global([data-fx-hover='aurora'] [data-fx-hover]:not([data-fx-hover='aurora'])) *))::after {
|
|
1040
|
+
background: linear-gradient(90deg, var(--fx-a3), var(--fx-a1), var(--fx-a2), var(--fx-a3));
|
|
1041
|
+
background-size: 33.3334% 100%;
|
|
1042
|
+
mask-image: radial-gradient(120% 110% at 50% 110%, #000 30%, transparent 100%);
|
|
1043
|
+
translate: -66.6667% 0;
|
|
1044
|
+
animation: fx-aurora-back 11s linear infinite;
|
|
1045
|
+
}
|
|
1046
|
+
.btn:not(:hover)::before,
|
|
1047
|
+
.btn:not(:hover)::after,
|
|
1048
|
+
.btn:disabled::before,
|
|
1049
|
+
.btn:disabled::after {
|
|
1050
|
+
animation-play-state: paused;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
@keyframes fx-smoke {
|
|
1054
|
+
from {
|
|
1055
|
+
translate: -14% 22%;
|
|
1056
|
+
rotate: -4deg;
|
|
1057
|
+
}
|
|
1058
|
+
to {
|
|
1059
|
+
translate: 12% -20%;
|
|
1060
|
+
rotate: 5deg;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
@keyframes fx-smoke-b {
|
|
1064
|
+
from {
|
|
1065
|
+
translate: 10% 18%;
|
|
1066
|
+
rotate: 3deg;
|
|
1067
|
+
}
|
|
1068
|
+
to {
|
|
1069
|
+
translate: -12% -22%;
|
|
1070
|
+
rotate: -5deg;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
@keyframes fx-ember {
|
|
1074
|
+
0%,
|
|
1075
|
+
100% {
|
|
1076
|
+
scale: 1 1;
|
|
1077
|
+
}
|
|
1078
|
+
50% {
|
|
1079
|
+
scale: 1.12 1.25;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
@keyframes fx-sparks {
|
|
1083
|
+
from {
|
|
1084
|
+
translate: 0 0;
|
|
1085
|
+
}
|
|
1086
|
+
to {
|
|
1087
|
+
translate: 0 -100%;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
@keyframes fx-aurora {
|
|
1091
|
+
from {
|
|
1092
|
+
translate: -33.3334% 0;
|
|
1093
|
+
}
|
|
1094
|
+
to {
|
|
1095
|
+
translate: 0 0;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
@keyframes fx-aurora-back {
|
|
1099
|
+
from {
|
|
1100
|
+
translate: -33.3334% 0;
|
|
1101
|
+
}
|
|
1102
|
+
to {
|
|
1103
|
+
translate: -66.6667% 0;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
796
1106
|
</style>
|
|
@@ -23,7 +23,10 @@ type ButtonProps = HTMLButtonAttributes & {
|
|
|
23
23
|
hoverDanger?: boolean;
|
|
24
24
|
collapseLabel?: 'never' | 'mobile' | 'container';
|
|
25
25
|
hitArea?: 'auto' | 'compact';
|
|
26
|
-
loading?: boolean;
|
|
26
|
+
loading?: boolean | 'done';
|
|
27
|
+
loadingStyle?: 'spinner' | 'morph' | 'fill';
|
|
28
|
+
progress?: number;
|
|
29
|
+
doneLabel?: string;
|
|
27
30
|
count?: number;
|
|
28
31
|
countMax?: number;
|
|
29
32
|
layout?: 'inline' | 'stacked';
|