@juspay/svelte-ui-components 4.31.3 → 4.32.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/Accordion/Accordion.svelte +6 -1
- package/dist/Animations/ModalAnimation.svelte +71 -8
- package/dist/Animations/OverlayAnimation.svelte +29 -4
- package/dist/Animations/tokenizedFly.d.ts +17 -0
- package/dist/Animations/tokenizedFly.js +153 -0
- package/dist/AreaChart/AreaChart.svelte +7 -5
- package/dist/BarChart/BarChart.svelte +2 -1
- package/dist/Book/Book.svelte +6 -3
- package/dist/ChatBubble/ChatBubble.svelte +18 -3
- package/dist/Checkbox/Checkbox.svelte +15 -3
- package/dist/Choicebox/Choicebox.svelte +24 -2
- package/dist/Combobox/Combobox.svelte +15 -1
- package/dist/CommandMenu/CommandMenu.svelte +72 -2
- package/dist/ContextMenu/ContextMenu.svelte +41 -1
- package/dist/DualAxisBarChart/DualAxisBarChart.svelte +4 -3
- package/dist/FunnelChart/FunnelChart.svelte +5 -4
- package/dist/Gallery/Gallery.svelte +53 -1
- package/dist/Gallery/properties.d.ts +5 -3
- package/dist/Gauge/Gauge.svelte +2 -1
- package/dist/LineChart/LineChart.svelte +7 -5
- package/dist/MediaPlayer/MediaPlayer.svelte +9 -1
- package/dist/MediaPlayer/MediaPlayer.svelte.d.ts +1 -1
- package/dist/MediaUpload/MediaUpload.svelte +1 -1
- package/dist/Menu/Menu.svelte +38 -1
- package/dist/Modal/Modal.svelte +18 -4
- package/dist/Pagination/Pagination.svelte +9 -1
- package/dist/PieChart/PieChart.svelte +2 -2
- package/dist/Radio/Radio.svelte +14 -2
- package/dist/RatingGroup/RatingGroup.svelte +9 -0
- package/dist/SankeyChart/SankeyChart.svelte +6 -3
- package/dist/Select/Select.svelte +26 -4
- package/dist/Sheet/Sheet.svelte +34 -2
- package/dist/Slider/Slider.svelte +26 -5
- package/dist/Table/Table.svelte +9 -2
- package/dist/Tabs/Tabs.svelte +27 -4
- package/dist/TaskList/TaskList.svelte +10 -2
- package/dist/ThemeSwitcher/ThemeSwitcher.svelte +13 -6
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte +5 -3
- package/dist/Toast/Toast.svelte +216 -116
- package/dist/Toggle/Toggle.svelte +8 -4
- package/dist/ToolCallLog/ToolCallLog.svelte +10 -2
- package/dist/Tooltip/Tooltip.svelte +4 -2
- package/dist-wc/index.js +599 -410
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { lockBodyScroll, unlockBodyScroll } from '../utils';
|
|
5
5
|
import { registerDismissible } from '../_interaction/dismissal';
|
|
6
6
|
import { getActiveElement } from '../_interaction/focus';
|
|
7
|
+
import { tokenizedFly } from '../Animations/tokenizedFly';
|
|
7
8
|
import { SvelteMap } from 'svelte/reactivity';
|
|
8
9
|
import Img from '../Img/Img.svelte';
|
|
9
10
|
import searchSvg from '../assets/search.svg?raw';
|
|
@@ -25,6 +26,27 @@
|
|
|
25
26
|
const uid = $props.id();
|
|
26
27
|
const listboxId = `command-menu-listbox-${uid}`;
|
|
27
28
|
|
|
29
|
+
// Centered, medium-large panel: --distance-large / --duration-base tiers —
|
|
30
|
+
// a command palette warrants more presence than a small anchored dropdown.
|
|
31
|
+
// 200ms matches --duration-base exactly, so the duration chain picks up that
|
|
32
|
+
// named tier before falling to --motion-duration. easingTokens is new:
|
|
33
|
+
// tokenizedFly now parses a CSS easing-token string (keyword or cubic-bezier)
|
|
34
|
+
// into a JS EasingFunction, so --command-menu-panel-transition-easing has a
|
|
35
|
+
// live hook -- --ease-smooth-out is the shared named tier, cubicOut stays the
|
|
36
|
+
// ultimate JS fallback if no token resolves.
|
|
37
|
+
const panelTransitionParams = {
|
|
38
|
+
y: 30,
|
|
39
|
+
durationTokens: [
|
|
40
|
+
'--command-menu-panel-transition-duration',
|
|
41
|
+
'--duration-base',
|
|
42
|
+
'--motion-duration'
|
|
43
|
+
],
|
|
44
|
+
fallbackDuration: 200,
|
|
45
|
+
distanceTokens: ['--command-menu-panel-transition-distance', '--distance-large'],
|
|
46
|
+
fallbackDistance: 30,
|
|
47
|
+
easingTokens: ['--command-menu-panel-transition-easing', '--ease-smooth-out', '--motion-easing']
|
|
48
|
+
};
|
|
49
|
+
|
|
28
50
|
let query = $state('');
|
|
29
51
|
let activeIndex = $state(0);
|
|
30
52
|
let inputElement: HTMLInputElement | null = $state(null);
|
|
@@ -86,7 +108,14 @@
|
|
|
86
108
|
flatItems.length > 0 ? `command-menu-option-${uid}-${activeIndex}` : null
|
|
87
109
|
);
|
|
88
110
|
|
|
111
|
+
// Guarded rather than assumed single-fire: out:tokenizedFly keeps the dialog
|
|
112
|
+
// (and its handlers) mounted for the outro's duration, so a second Escape,
|
|
113
|
+
// outside click, or item interaction landing during that window would
|
|
114
|
+
// otherwise fire onclose/onselect again before Svelte actually tears it down.
|
|
89
115
|
function close() {
|
|
116
|
+
if (!open) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
90
119
|
open = false;
|
|
91
120
|
query = '';
|
|
92
121
|
activeIndex = 0;
|
|
@@ -94,7 +123,7 @@
|
|
|
94
123
|
}
|
|
95
124
|
|
|
96
125
|
function selectItem(item: CommandItem) {
|
|
97
|
-
if (item.disabled) {
|
|
126
|
+
if (!open || item.disabled) {
|
|
98
127
|
return;
|
|
99
128
|
}
|
|
100
129
|
onselect?.(item);
|
|
@@ -228,6 +257,23 @@
|
|
|
228
257
|
// point in a fresh open. Ctrl+K stays on `handleGlobalKeyDown`/`window`
|
|
229
258
|
// below rather than moving here: it is an OPEN shortcut that must keep
|
|
230
259
|
// working while the menu is closed, and this layer only exists while open.
|
|
260
|
+
// KNOWN LIMITATION, not yet fixed: this action's mount function -- and so
|
|
261
|
+
// this capture -- only runs once, when `.command-menu-overlay` is first
|
|
262
|
+
// created. `open` is `$bindable`, so an external trigger button and the
|
|
263
|
+
// built-in Ctrl+K shortcut commonly coexist; if the menu is reopened via a
|
|
264
|
+
// DIFFERENT trigger while still mid-outro from a just-finished close
|
|
265
|
+
// (out:tokenizedFly's ~200ms fallback keeps this instance alive, and Svelte
|
|
266
|
+
// reverses rather than recreates the block on a same-window reopen), this
|
|
267
|
+
// function does not run again -- `openerElement` stays whatever the FIRST
|
|
268
|
+
// opener was, and focus incorrectly returns there instead of to the trigger
|
|
269
|
+
// that actually opened the currently-visible session. A correct fix needs
|
|
270
|
+
// to re-capture on every logical open, not just the first DOM mount (e.g. an
|
|
271
|
+
// `$effect` watching `open`), while still finding the right shadow-DOM-aware
|
|
272
|
+
// active element (getActiveElement needs an already-connected node, and this
|
|
273
|
+
// component renders nothing while closed) and without racing the focus-the-
|
|
274
|
+
// input logic below it. Deferred rather than shipped half-verified: a wrong
|
|
275
|
+
// guess here risks a worse regression (stealing focus into the wrong
|
|
276
|
+
// element on every open) than the narrow bug it would fix.
|
|
231
277
|
function scrollLockAction(node: HTMLElement) {
|
|
232
278
|
const opener = getActiveElement(node);
|
|
233
279
|
if (openerElement === null && opener instanceof HTMLElement) {
|
|
@@ -267,6 +313,23 @@
|
|
|
267
313
|
</script>
|
|
268
314
|
|
|
269
315
|
{#if open}
|
|
316
|
+
<!-- `open` flips false (and aria-expanded on the trigger follows suit) the
|
|
317
|
+
instant close()/selectItem() run, but this whole subtree stays mounted
|
|
318
|
+
for .command-menu-dialog's out:tokenizedFly outro below -- Svelte only
|
|
319
|
+
destroys an ancestor once a descendant's own out-transition finishes.
|
|
320
|
+
`inert` pulls the fading-but-still-mounted dialog out of the
|
|
321
|
+
accessibility tree (and out of tab order) on that same instant, so a
|
|
322
|
+
screen reader doesn't still see role="dialog" aria-modal="true" for a
|
|
323
|
+
surface that's already reported itself closed. Set on BOTH this element
|
|
324
|
+
and .command-menu-dialog below, not just the one carrying
|
|
325
|
+
role="dialog": verified live that Svelte stops applying reactive
|
|
326
|
+
attribute updates to an ancestor once a descendant's own outro begins,
|
|
327
|
+
so the binding here alone would go stale the moment the transition
|
|
328
|
+
starts -- only the element actually running the out: transition is
|
|
329
|
+
guaranteed to keep updating through it. close()/selectItem() are
|
|
330
|
+
already guarded against a stray interaction landing here regardless --
|
|
331
|
+
this is the matching fix for what AT perceives, not a second copy of
|
|
332
|
+
that guard. -->
|
|
270
333
|
<div
|
|
271
334
|
class="command-menu-overlay {classes ?? ''}"
|
|
272
335
|
use:scrollLockAction
|
|
@@ -276,10 +339,17 @@
|
|
|
276
339
|
aria-modal="true"
|
|
277
340
|
aria-label="Command menu"
|
|
278
341
|
tabindex="-1"
|
|
342
|
+
inert={!open}
|
|
279
343
|
data-pw={typeof testId === 'string' ? testId : null}
|
|
280
344
|
testID={typeof testId === 'string' ? testId : null}
|
|
281
345
|
>
|
|
282
|
-
<div
|
|
346
|
+
<div
|
|
347
|
+
class="command-menu-dialog"
|
|
348
|
+
bind:this={dialogElement}
|
|
349
|
+
inert={!open}
|
|
350
|
+
in:tokenizedFly={panelTransitionParams}
|
|
351
|
+
out:tokenizedFly={panelTransitionParams}
|
|
352
|
+
>
|
|
283
353
|
<div class="command-menu-input-wrapper">
|
|
284
354
|
{#if typeof searchIcon === 'function'}
|
|
285
355
|
{@render searchIcon()}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { registerDismissible } from '../_interaction/dismissal';
|
|
3
3
|
import { getActiveElement } from '../_interaction/focus';
|
|
4
|
+
import { tokenizedFly } from '../Animations/tokenizedFly';
|
|
4
5
|
import type { ContextMenuProperties, ContextMenuItem } from './properties';
|
|
5
6
|
|
|
6
7
|
let {
|
|
@@ -25,6 +26,27 @@
|
|
|
25
26
|
// the menu goes away, matching Menu.svelte's own restore-on-close contract.
|
|
26
27
|
let openerElement: HTMLElement | null = $state(null);
|
|
27
28
|
|
|
29
|
+
// Small anchored dropdown: --distance-medium / --duration-quick tiers — snappier
|
|
30
|
+
// and less travel than CommandMenu's centered palette, matching Menu.svelte's own.
|
|
31
|
+
// 150ms matches --duration-quick exactly, so the duration chain picks up that
|
|
32
|
+
// named tier before falling to --motion-duration. easingTokens is new:
|
|
33
|
+
// tokenizedFly now parses a CSS easing-token string (keyword or cubic-bezier)
|
|
34
|
+
// into a JS EasingFunction, so --context-menu-panel-transition-easing has a
|
|
35
|
+
// live hook -- --ease-smooth-out is the shared named tier, cubicOut stays the
|
|
36
|
+
// ultimate JS fallback if no token resolves.
|
|
37
|
+
const panelTransitionParams = {
|
|
38
|
+
y: 12,
|
|
39
|
+
durationTokens: [
|
|
40
|
+
'--context-menu-panel-transition-duration',
|
|
41
|
+
'--duration-quick',
|
|
42
|
+
'--motion-duration'
|
|
43
|
+
],
|
|
44
|
+
fallbackDuration: 150,
|
|
45
|
+
distanceTokens: ['--context-menu-panel-transition-distance', '--distance-medium'],
|
|
46
|
+
fallbackDistance: 12,
|
|
47
|
+
easingTokens: ['--context-menu-panel-transition-easing', '--ease-smooth-out', '--motion-easing']
|
|
48
|
+
};
|
|
49
|
+
|
|
28
50
|
let selectableItems: ContextMenuItem[] = $derived(
|
|
29
51
|
items.filter((item) => !item.separator && !item.disabled)
|
|
30
52
|
);
|
|
@@ -57,7 +79,14 @@
|
|
|
57
79
|
});
|
|
58
80
|
}
|
|
59
81
|
|
|
82
|
+
// Guarded rather than assumed single-fire: out:tokenizedFly keeps the dropdown
|
|
83
|
+
// (and its handlers) mounted for the outro's duration, so a second Escape,
|
|
84
|
+
// outside click, or item interaction landing during that window would
|
|
85
|
+
// otherwise fire onclose/onselect again before Svelte actually tears it down.
|
|
60
86
|
function close() {
|
|
87
|
+
if (!open) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
61
90
|
cancelOpenFrame();
|
|
62
91
|
open = false;
|
|
63
92
|
focusedIndex = -1;
|
|
@@ -83,7 +112,7 @@
|
|
|
83
112
|
}
|
|
84
113
|
|
|
85
114
|
function selectMenuItem(item: ContextMenuItem) {
|
|
86
|
-
if (item.disabled) {
|
|
115
|
+
if (!open || item.disabled) {
|
|
87
116
|
return;
|
|
88
117
|
}
|
|
89
118
|
onselect?.(item);
|
|
@@ -225,14 +254,25 @@
|
|
|
225
254
|
</div>
|
|
226
255
|
|
|
227
256
|
{#if open}
|
|
257
|
+
<!-- `open` flips false the instant close()/selectMenuItem() run, but this
|
|
258
|
+
subtree stays mounted for the out:tokenizedFly outro below -- Svelte
|
|
259
|
+
only destroys it once its own out-transition finishes. `inert` pulls
|
|
260
|
+
the fading-but-still-mounted dropdown out of the accessibility tree
|
|
261
|
+
(and tab order) on that same instant, matching what the trigger's own
|
|
262
|
+
state already reports. close()/selectMenuItem() are already guarded
|
|
263
|
+
against a stray interaction landing here regardless -- this is the
|
|
264
|
+
matching fix for what AT perceives, not a second copy of that guard. -->
|
|
228
265
|
<div
|
|
229
266
|
class="context-menu-dropdown"
|
|
230
267
|
style="left: {posX}px; top: {posY}px; --context-menu-max-height: {maxHeight};"
|
|
231
268
|
bind:this={menuEl}
|
|
232
269
|
role="menu"
|
|
233
270
|
tabindex="-1"
|
|
271
|
+
inert={!open}
|
|
234
272
|
onkeydown={handleMenuKeydown}
|
|
235
273
|
use:dismissalAction
|
|
274
|
+
in:tokenizedFly={panelTransitionParams}
|
|
275
|
+
out:tokenizedFly={panelTransitionParams}
|
|
236
276
|
>
|
|
237
277
|
{#each items as item (item.value)}
|
|
238
278
|
{#if item.separator}
|
|
@@ -655,7 +655,8 @@
|
|
|
655
655
|
}
|
|
656
656
|
|
|
657
657
|
.bar-shape {
|
|
658
|
-
transition: opacity
|
|
658
|
+
transition: opacity
|
|
659
|
+
var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
659
660
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
660
661
|
cursor: pointer;
|
|
661
662
|
}
|
|
@@ -677,9 +678,9 @@
|
|
|
677
678
|
|
|
678
679
|
.line-dot {
|
|
679
680
|
transition:
|
|
680
|
-
r var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
681
|
+
r var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
681
682
|
var(--chart-transition-easing, var(--motion-easing, ease)),
|
|
682
|
-
opacity var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
683
|
+
opacity var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
683
684
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
684
685
|
cursor: pointer;
|
|
685
686
|
}
|
|
@@ -431,11 +431,11 @@
|
|
|
431
431
|
|
|
432
432
|
.funnel-bar {
|
|
433
433
|
transition:
|
|
434
|
-
opacity var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
434
|
+
opacity var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
435
435
|
var(--chart-transition-easing, var(--motion-easing, ease)),
|
|
436
|
-
y var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
436
|
+
y var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
437
437
|
var(--chart-transition-easing, var(--motion-easing, ease)),
|
|
438
|
-
height var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
438
|
+
height var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
439
439
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
440
440
|
cursor: pointer;
|
|
441
441
|
}
|
|
@@ -463,7 +463,8 @@
|
|
|
463
463
|
}
|
|
464
464
|
|
|
465
465
|
.funnel-connector {
|
|
466
|
-
transition: d
|
|
466
|
+
transition: d
|
|
467
|
+
var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
467
468
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
468
469
|
}
|
|
469
470
|
|
|
@@ -79,6 +79,54 @@
|
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Resolves a CSS time value (e.g. `"0.2s"`, `"150ms"`) to milliseconds.
|
|
84
|
+
* Returns `null` rather than 0 when nothing parses, so an explicit `0s`
|
|
85
|
+
* override is never confused with "no token set".
|
|
86
|
+
*/
|
|
87
|
+
function parseCssDurationMs(value: string): number | null {
|
|
88
|
+
const text = value.trim();
|
|
89
|
+
if (text.length === 0) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const amount = Number.parseFloat(text);
|
|
93
|
+
if (!Number.isFinite(amount)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (text.endsWith('ms')) {
|
|
97
|
+
return amount;
|
|
98
|
+
}
|
|
99
|
+
if (text.endsWith('s')) {
|
|
100
|
+
return amount * 1000;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Wraps `fade` so the lightbox honours the CSS token chain
|
|
107
|
+
* (`--gallery-lightbox-transition-duration` / `--duration-base` /
|
|
108
|
+
* `--motion-duration`, resolved once on `.lightbox` below as
|
|
109
|
+
* `--_gallery-lightbox-transition-duration`) when a consumer sets one, and
|
|
110
|
+
* otherwise falls back to the `lightboxTransitionDuration` prop --
|
|
111
|
+
* unchanged default of 200ms when NEITHER is set. An explicit prop wins over
|
|
112
|
+
* the CSS token when BOTH are set, not the other way around: `--motion-duration`
|
|
113
|
+
* is an ambient, root-level default meant for a consumer who never touches
|
|
114
|
+
* this component directly, while `lightboxTransitionDuration` is an explicit,
|
|
115
|
+
* per-instance choice -- the more specific override has to win, the same way
|
|
116
|
+
* an inline style beats a stylesheet rule. `typeof … === 'number'` (not `??`)
|
|
117
|
+
* is what makes that precedence real: `??` would let the CSS token jump the
|
|
118
|
+
* queue the moment a consumer sets one globally, silently overriding a prop
|
|
119
|
+
* they explicitly passed to this specific instance.
|
|
120
|
+
*/
|
|
121
|
+
function lightboxFade(node: Element) {
|
|
122
|
+
if (typeof lightboxTransitionDuration === 'number') {
|
|
123
|
+
return fade(node, { duration: lightboxTransitionDuration });
|
|
124
|
+
}
|
|
125
|
+
const raw = getComputedStyle(node).getPropertyValue('--_gallery-lightbox-transition-duration');
|
|
126
|
+
const duration = parseCssDurationMs(raw) ?? 200;
|
|
127
|
+
return fade(node, { duration });
|
|
128
|
+
}
|
|
129
|
+
|
|
82
130
|
function openLightbox(index: number, opener: EventTarget | null): void {
|
|
83
131
|
if (opener instanceof HTMLElement) {
|
|
84
132
|
openerElement = opener;
|
|
@@ -273,7 +321,7 @@
|
|
|
273
321
|
use:lightboxAction
|
|
274
322
|
onclick={handleBackdropClick}
|
|
275
323
|
onkeydown={handleLightboxKeydown}
|
|
276
|
-
transition:
|
|
324
|
+
transition:lightboxFade
|
|
277
325
|
>
|
|
278
326
|
<div class="lightbox-close" bind:this={closeButtonWrap}>
|
|
279
327
|
<Button ariaLabel="Close gallery" onclick={closeLightbox}>
|
|
@@ -527,6 +575,10 @@
|
|
|
527
575
|
align-items: center;
|
|
528
576
|
background: var(--gallery-lightbox-background, #000000e6);
|
|
529
577
|
-webkit-tap-highlight-color: transparent;
|
|
578
|
+
--_gallery-lightbox-transition-duration: var(
|
|
579
|
+
--gallery-lightbox-transition-duration,
|
|
580
|
+
var(--duration-base, var(--motion-duration))
|
|
581
|
+
);
|
|
530
582
|
}
|
|
531
583
|
|
|
532
584
|
.lightbox:focus {
|
|
@@ -28,9 +28,11 @@ export type OptionalGalleryProperties = {
|
|
|
28
28
|
testId?: string;
|
|
29
29
|
classes?: string;
|
|
30
30
|
/**
|
|
31
|
-
* Duration (ms) of the lightbox's `fade` transition
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* Duration (ms) of the lightbox's `fade` transition, used whenever the
|
|
32
|
+
* `--gallery-lightbox-transition-duration` CSS token (and its
|
|
33
|
+
* `--duration-base` / `--motion-duration` fallbacks) resolve to nothing.
|
|
34
|
+
* A transition directive's parameters are plain JS, so `Gallery.svelte`
|
|
35
|
+
* bridges the token chain in via `getComputedStyle` — same shape as
|
|
34
36
|
* Toast's `inAnimationDuration`/`outAnimationDuration`. Defaults to the
|
|
35
37
|
* library's existing 200ms so omitting it renders identically to before.
|
|
36
38
|
*/
|
package/dist/Gauge/Gauge.svelte
CHANGED
|
@@ -99,7 +99,8 @@
|
|
|
99
99
|
.bar {
|
|
100
100
|
stroke: var(--gauge-bar-color, #2196f3);
|
|
101
101
|
stroke-width: var(--gauge-stroke-width, 8);
|
|
102
|
-
transition: stroke-dashoffset var(--gauge-transition-duration, 0.3s)
|
|
102
|
+
transition: stroke-dashoffset var(--gauge-transition-duration, var(--motion-duration, 0.3s))
|
|
103
|
+
var(--gauge-transition-easing, var(--motion-easing, ease));
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
.label {
|
|
@@ -1062,9 +1062,10 @@
|
|
|
1062
1062
|
}
|
|
1063
1063
|
.line-area-fill {
|
|
1064
1064
|
transition:
|
|
1065
|
-
fill-opacity
|
|
1065
|
+
fill-opacity
|
|
1066
|
+
var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
1066
1067
|
var(--chart-transition-easing, var(--motion-easing, ease)),
|
|
1067
|
-
opacity var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
1068
|
+
opacity var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
1068
1069
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
1069
1070
|
pointer-events: none;
|
|
1070
1071
|
}
|
|
@@ -1072,7 +1073,8 @@
|
|
|
1072
1073
|
opacity: var(--linechart-dimmed-opacity, 0.2);
|
|
1073
1074
|
}
|
|
1074
1075
|
.line-path {
|
|
1075
|
-
transition: opacity
|
|
1076
|
+
transition: opacity
|
|
1077
|
+
var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
1076
1078
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
1077
1079
|
stroke-linecap: round;
|
|
1078
1080
|
stroke-linejoin: round;
|
|
@@ -1089,9 +1091,9 @@
|
|
|
1089
1091
|
}
|
|
1090
1092
|
.dot {
|
|
1091
1093
|
transition:
|
|
1092
|
-
r var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
1094
|
+
r var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
1093
1095
|
var(--chart-transition-easing, var(--motion-easing, ease)),
|
|
1094
|
-
opacity var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
1096
|
+
opacity var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
1095
1097
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
1096
1098
|
stroke: var(--chart-dot-stroke, light-dark(#fff, #111827));
|
|
1097
1099
|
stroke-width: 2;
|
|
@@ -455,7 +455,15 @@
|
|
|
455
455
|
z-index: var(--media-player-overlay-z-index, 20);
|
|
456
456
|
border-radius: inherit;
|
|
457
457
|
background-color: var(--media-player-overlay-color, transparent);
|
|
458
|
-
transition: var(
|
|
458
|
+
transition: var(
|
|
459
|
+
--media-player-overlay-transition,
|
|
460
|
+
background-color
|
|
461
|
+
var(
|
|
462
|
+
--media-player-overlay-transition-duration,
|
|
463
|
+
var(--duration-base, var(--motion-duration, 0.2s))
|
|
464
|
+
)
|
|
465
|
+
var(--media-player-overlay-transition-easing, var(--motion-easing, ease))
|
|
466
|
+
);
|
|
459
467
|
--center-controls-visibility: var(--media-player-center-controls-visibility, hidden);
|
|
460
468
|
--bottom-controls-visibility: var(--media-player-bottom-controls-visibility, hidden);
|
|
461
469
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { MediaPlayerProperties } from './properties';
|
|
2
|
-
declare const MediaPlayer: import("svelte").Component<MediaPlayerProperties, {}, "muted" | "
|
|
2
|
+
declare const MediaPlayer: import("svelte").Component<MediaPlayerProperties, {}, "muted" | "playing" | "duration" | "currentTime">;
|
|
3
3
|
type MediaPlayer = ReturnType<typeof MediaPlayer>;
|
|
4
4
|
export default MediaPlayer;
|
|
@@ -542,7 +542,7 @@
|
|
|
542
542
|
consumer overriding the token is most likely adding more of it. Dropping the
|
|
543
543
|
whole declaration is right here because every end state is a resting state. */
|
|
544
544
|
@media (prefers-reduced-motion: reduce) {
|
|
545
|
-
.
|
|
545
|
+
.card {
|
|
546
546
|
transition: none;
|
|
547
547
|
}
|
|
548
548
|
}
|
package/dist/Menu/Menu.svelte
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import Img from '../Img/Img.svelte';
|
|
5
5
|
import { computeMenuDropdownPosition } from './dropdownPosition';
|
|
6
6
|
import { eventHitsInside, registerDismissible } from '../_interaction/dismissal';
|
|
7
|
+
import { tokenizedFly } from '../Animations/tokenizedFly';
|
|
7
8
|
import type { MenuProperties, MenuItem, MenuPlacement } from './properties';
|
|
8
9
|
|
|
9
10
|
let {
|
|
@@ -79,6 +80,23 @@
|
|
|
79
80
|
// Gap between trigger and portaled panel, matching the --menu-margin default.
|
|
80
81
|
const PORTAL_MENU_GAP = 4;
|
|
81
82
|
|
|
83
|
+
// Small anchored dropdown: --distance-medium / --duration-quick tiers — snappier
|
|
84
|
+
// and less travel than CommandMenu's centered palette. 150ms matches
|
|
85
|
+
// --duration-quick exactly, so the duration chain picks up that named tier
|
|
86
|
+
// before falling to --motion-duration. easingTokens is new: tokenizedFly now
|
|
87
|
+
// parses a CSS easing-token string (keyword or cubic-bezier) into a JS
|
|
88
|
+
// EasingFunction, so --menu-panel-transition-easing has a live hook --
|
|
89
|
+
// --ease-smooth-out is the shared named tier, cubicOut stays the ultimate JS
|
|
90
|
+
// fallback if no token resolves.
|
|
91
|
+
const panelTransitionParams = {
|
|
92
|
+
y: 12,
|
|
93
|
+
durationTokens: ['--menu-panel-transition-duration', '--duration-quick', '--motion-duration'],
|
|
94
|
+
fallbackDuration: 150,
|
|
95
|
+
distanceTokens: ['--menu-panel-transition-distance', '--distance-medium'],
|
|
96
|
+
fallbackDistance: 12,
|
|
97
|
+
easingTokens: ['--menu-panel-transition-easing', '--ease-smooth-out', '--motion-easing']
|
|
98
|
+
};
|
|
99
|
+
|
|
82
100
|
// Keep the portaled panel anchored to its trigger while the page scrolls or
|
|
83
101
|
// resizes. Mirrors the chart-tooltip portal pattern; $effect is the sanctioned
|
|
84
102
|
// reactive escape hatch here for untracked window listeners. Reposition work is
|
|
@@ -213,7 +231,15 @@
|
|
|
213
231
|
});
|
|
214
232
|
}
|
|
215
233
|
|
|
234
|
+
// Guarded rather than assumed single-fire: out:tokenizedFly keeps the dropdown
|
|
235
|
+
// (and its handlers) mounted for the outro's duration, so a second Escape,
|
|
236
|
+
// outside click, or item interaction landing during that window would
|
|
237
|
+
// otherwise fire onclose/onselect (and re-run focus restoration) again before
|
|
238
|
+
// Svelte actually tears it down.
|
|
216
239
|
function close() {
|
|
240
|
+
if (!open) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
217
243
|
open = false;
|
|
218
244
|
focusedIndex = -1;
|
|
219
245
|
typeaheadQuery = '';
|
|
@@ -243,7 +269,7 @@
|
|
|
243
269
|
}
|
|
244
270
|
|
|
245
271
|
function selectItem(item: MenuItem) {
|
|
246
|
-
if (item.disabled === true) {
|
|
272
|
+
if (!open || item.disabled === true) {
|
|
247
273
|
return;
|
|
248
274
|
}
|
|
249
275
|
onselect?.(item);
|
|
@@ -453,6 +479,14 @@
|
|
|
453
479
|
{/if}
|
|
454
480
|
|
|
455
481
|
{#if open}
|
|
482
|
+
<!-- `open` flips false the instant close()/selectItem() run, but this
|
|
483
|
+
subtree stays mounted for the out:tokenizedFly outro below -- Svelte
|
|
484
|
+
only destroys it once its own out-transition finishes. `inert` pulls
|
|
485
|
+
the fading-but-still-mounted dropdown out of the accessibility tree
|
|
486
|
+
(and tab order) on that same instant, matching what aria-expanded on
|
|
487
|
+
the trigger already reports. close()/selectItem() are already guarded
|
|
488
|
+
against a stray interaction landing here regardless -- this is the
|
|
489
|
+
matching fix for what AT perceives, not a second copy of that guard. -->
|
|
456
490
|
<div
|
|
457
491
|
class="menu-dropdown menu-dropdown-{placement === 'auto' ? resolvedPlacement : placement}"
|
|
458
492
|
class:menu-dropdown-measuring={measuringPlacement}
|
|
@@ -463,10 +497,13 @@
|
|
|
463
497
|
id={menuId}
|
|
464
498
|
aria-label={menuAriaLabel}
|
|
465
499
|
tabindex="-1"
|
|
500
|
+
inert={!open}
|
|
466
501
|
style={portalStyle}
|
|
467
502
|
onkeydown={handleMenuKeydown}
|
|
468
503
|
use:portalToRoot
|
|
469
504
|
use:dismissalAction
|
|
505
|
+
in:tokenizedFly={panelTransitionParams}
|
|
506
|
+
out:tokenizedFly={panelTransitionParams}
|
|
470
507
|
>
|
|
471
508
|
{#each items as item (item.value)}
|
|
472
509
|
{#if item.separator === true}
|
package/dist/Modal/Modal.svelte
CHANGED
|
@@ -106,10 +106,18 @@
|
|
|
106
106
|
};
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
+
// Debounced through the same leading-edge debounce() handleOverlayClick
|
|
110
|
+
// already uses below, for the same reason: OverlayAnimation's out:tokenizedFly
|
|
111
|
+
// keeps the popstate listener registered (onMount/onDestroy span the outro,
|
|
112
|
+
// ~350ms fallback) for as long as the overlay is still fading out, so a
|
|
113
|
+
// second rapid back-press in that window would otherwise fire onclose/
|
|
114
|
+
// ondismiss a second time for one dismissal.
|
|
109
115
|
const handlePopstate = (): void => {
|
|
110
116
|
backPressed = true;
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
debounce(() => {
|
|
118
|
+
onclose?.();
|
|
119
|
+
ondismiss?.();
|
|
120
|
+
});
|
|
113
121
|
};
|
|
114
122
|
|
|
115
123
|
const handleRightImageClick = (event: MouseEvent): void => {
|
|
@@ -161,9 +169,15 @@
|
|
|
161
169
|
// dismissible layer and Escape is pressed -- same callbacks the old
|
|
162
170
|
// Escape branch in handleKeyDown used to invoke directly, just gated on
|
|
163
171
|
// ownership now instead of firing for every open modal unconditionally.
|
|
172
|
+
// Debounced through the same debounce() handleOverlayClick/handlePopstate
|
|
173
|
+
// use, for the same reason: a second Escape landing while
|
|
174
|
+
// OverlayAnimation's out:tokenizedFly outro is still keeping this modal's
|
|
175
|
+
// dismissal listeners registered would otherwise fire the callbacks twice.
|
|
164
176
|
const handleEscape = (): void => {
|
|
165
|
-
|
|
166
|
-
|
|
177
|
+
debounce(() => {
|
|
178
|
+
onoverlayclick?.();
|
|
179
|
+
ondismiss?.();
|
|
180
|
+
});
|
|
167
181
|
};
|
|
168
182
|
|
|
169
183
|
// The overlay's own Enter/Space activation, additional to the shared
|
|
@@ -159,7 +159,15 @@
|
|
|
159
159
|
display: flex;
|
|
160
160
|
align-items: center;
|
|
161
161
|
justify-content: center;
|
|
162
|
-
transition: var(
|
|
162
|
+
transition: var(
|
|
163
|
+
--pagination-transition,
|
|
164
|
+
background
|
|
165
|
+
var(--pagination-transition-duration, var(--duration-quick, var(--motion-duration, 0.15s)))
|
|
166
|
+
var(--pagination-transition-easing, var(--motion-easing, ease)),
|
|
167
|
+
color
|
|
168
|
+
var(--pagination-transition-duration, var(--duration-quick, var(--motion-duration, 0.15s)))
|
|
169
|
+
var(--pagination-transition-easing, var(--motion-easing, ease))
|
|
170
|
+
);
|
|
163
171
|
}
|
|
164
172
|
|
|
165
173
|
.page-button:hover:not(:disabled):not(.active) {
|
|
@@ -662,9 +662,9 @@
|
|
|
662
662
|
stroke: var(--piechart-stroke-color, #fff);
|
|
663
663
|
stroke-width: var(--piechart-stroke-width, 2);
|
|
664
664
|
transition:
|
|
665
|
-
transform var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
665
|
+
transform var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
666
666
|
var(--chart-transition-easing, var(--motion-easing, ease)),
|
|
667
|
-
opacity var(--chart-transition-duration, var(--motion-duration, 0.2s))
|
|
667
|
+
opacity var(--chart-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
668
668
|
var(--chart-transition-easing, var(--motion-easing, ease));
|
|
669
669
|
transform-origin: 0 0;
|
|
670
670
|
cursor: pointer;
|
package/dist/Radio/Radio.svelte
CHANGED
|
@@ -122,7 +122,15 @@
|
|
|
122
122
|
border: var(--radio-border, 2px solid #9e9e9e);
|
|
123
123
|
border-radius: var(--radio-border-radius, 50%);
|
|
124
124
|
background-color: var(--radio-background, #ffffff);
|
|
125
|
-
|
|
125
|
+
/* --radio-transition wraps the WHOLE value, not just the duration -- see the
|
|
126
|
+
matching comment on Checkbox's .box rule for why appending a separate
|
|
127
|
+
easing term after it (the prior shape here) breaks a consumer override
|
|
128
|
+
that already includes its own timing function. */
|
|
129
|
+
transition: var(
|
|
130
|
+
--radio-transition,
|
|
131
|
+
var(--radio-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
132
|
+
var(--radio-transition-easing, var(--motion-easing, ease))
|
|
133
|
+
);
|
|
126
134
|
box-sizing: border-box;
|
|
127
135
|
flex-shrink: 0;
|
|
128
136
|
}
|
|
@@ -150,7 +158,11 @@
|
|
|
150
158
|
height: 0;
|
|
151
159
|
border-radius: var(--radio-dot-border-radius, 50%);
|
|
152
160
|
background-color: var(--radio-dot-color, #2196f3);
|
|
153
|
-
transition: var(
|
|
161
|
+
transition: var(
|
|
162
|
+
--radio-transition,
|
|
163
|
+
var(--radio-transition-duration, var(--duration-base, var(--motion-duration, 0.2s)))
|
|
164
|
+
var(--radio-transition-easing, var(--motion-easing, ease))
|
|
165
|
+
);
|
|
154
166
|
}
|
|
155
167
|
|
|
156
168
|
.radio-dot.checked {
|
|
@@ -240,12 +240,21 @@
|
|
|
240
240
|
width: var(--rating-group-star-size, 24px);
|
|
241
241
|
height: var(--rating-group-star-size, 24px);
|
|
242
242
|
flex-shrink: 0;
|
|
243
|
+
transition: transform
|
|
244
|
+
var(--rating-group-star-transition-duration, var(--motion-duration, 0.15s))
|
|
245
|
+
var(--rating-group-star-transition-easing, var(--motion-easing, ease));
|
|
243
246
|
}
|
|
244
247
|
|
|
245
248
|
.rating-group:not(.disabled):not(.readonly) .star:hover {
|
|
246
249
|
transform: var(--rating-group-star-hover-transform, scale(1.1));
|
|
247
250
|
}
|
|
248
251
|
|
|
252
|
+
@media (prefers-reduced-motion: reduce) {
|
|
253
|
+
.star {
|
|
254
|
+
transition: none;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
249
258
|
.star-empty,
|
|
250
259
|
.star-fill {
|
|
251
260
|
position: absolute;
|