@juspay/svelte-ui-components 4.12.0 → 4.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Sheet/Sheet.svelte +37 -4
- package/dist/Snippet/Snippet.svelte +47 -26
- package/dist/Snippet/copyState.svelte.d.ts +47 -0
- package/dist/Snippet/copyState.svelte.js +69 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist-wc/index.js +75 -31
- package/package.json +1 -1
package/dist/Sheet/Sheet.svelte
CHANGED
|
@@ -99,16 +99,26 @@
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
function scrollLockAction(
|
|
102
|
+
function scrollLockAction(node: HTMLElement) {
|
|
103
|
+
const previousFocus = document.activeElement;
|
|
104
|
+
let active = true;
|
|
103
105
|
lockBodyScroll();
|
|
104
106
|
tick().then(() => {
|
|
105
|
-
if (sheetPanel !== null) {
|
|
107
|
+
if (active && sheetPanel !== null) {
|
|
106
108
|
sheetPanel.focus();
|
|
107
109
|
}
|
|
108
110
|
});
|
|
109
111
|
return {
|
|
110
112
|
destroy() {
|
|
113
|
+
active = false;
|
|
111
114
|
unlockBodyScroll();
|
|
115
|
+
if (
|
|
116
|
+
previousFocus instanceof HTMLElement &&
|
|
117
|
+
previousFocus.isConnected &&
|
|
118
|
+
(document.activeElement === document.body || node.contains(document.activeElement))
|
|
119
|
+
) {
|
|
120
|
+
previousFocus.focus();
|
|
121
|
+
}
|
|
112
122
|
}
|
|
113
123
|
};
|
|
114
124
|
}
|
|
@@ -295,22 +305,45 @@
|
|
|
295
305
|
border-left: var(--sheet-border, none);
|
|
296
306
|
}
|
|
297
307
|
|
|
308
|
+
/* Top/bottom stretch edge to edge by default, exactly as before: --sheet-
|
|
309
|
+
band-width is `auto`, so `margin-inline: auto` has nothing to distribute
|
|
310
|
+
and the panel still spans --sheet-left to --sheet-right.
|
|
311
|
+
|
|
312
|
+
Setting --sheet-band-width (or --sheet-band-max-width) caps it, and the
|
|
313
|
+
auto margins then centre it between those same two insets -- which is the
|
|
314
|
+
shape a bottom "launch" sheet wants above phone widths, and previously
|
|
315
|
+
had to be faked with hand-computed calc() offsets.
|
|
316
|
+
|
|
317
|
+
Deliberately NOT --sheet-width/--sheet-max-width, even though the issue
|
|
318
|
+
proposed those names. Those already mean "the width of a left/right
|
|
319
|
+
panel", so a consumer who themes them for their side sheets would find
|
|
320
|
+
their bottom sheets silently reshaped by an upgrade. side="center" avoids
|
|
321
|
+
the same collision the same way, with its own --sheet-center-* tokens. */
|
|
298
322
|
.sheet-panel.top,
|
|
299
323
|
.sheet-panel.bottom {
|
|
300
324
|
left: var(--sheet-left, 0);
|
|
301
325
|
right: var(--sheet-right, 0);
|
|
302
326
|
height: var(--sheet-height, 300px);
|
|
303
327
|
max-height: var(--sheet-max-height, 100vh);
|
|
328
|
+
width: var(--sheet-band-width, auto);
|
|
329
|
+
max-width: var(--sheet-band-max-width, none);
|
|
330
|
+
box-sizing: var(--sheet-band-box-sizing, content-box);
|
|
331
|
+
margin-inline: auto;
|
|
332
|
+
border: var(--sheet-band-border, none);
|
|
304
333
|
}
|
|
305
334
|
|
|
335
|
+
/* A capped panel is a floating card and needs all four edges; an
|
|
336
|
+
edge-to-edge one deliberately draws only the edge it enters from. The
|
|
337
|
+
entering edge falls back through --sheet-border so an existing theme that
|
|
338
|
+
sets only that keeps rendering exactly as it did. */
|
|
306
339
|
.sheet-panel.top {
|
|
307
340
|
top: var(--sheet-top, 0);
|
|
308
|
-
border-bottom: var(--sheet-border, none);
|
|
341
|
+
border-bottom: var(--sheet-band-border, var(--sheet-border, none));
|
|
309
342
|
}
|
|
310
343
|
|
|
311
344
|
.sheet-panel.bottom {
|
|
312
345
|
bottom: var(--sheet-bottom, 0);
|
|
313
|
-
border-top: var(--sheet-border, none);
|
|
346
|
+
border-top: var(--sheet-band-border, var(--sheet-border, none));
|
|
314
347
|
}
|
|
315
348
|
|
|
316
349
|
/* `side="center"` is a fixed-size floating dialog, not an edge-anchored
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { SnippetProperties } from './properties';
|
|
4
4
|
import Button from '../Button/Button.svelte';
|
|
5
5
|
import copySvg from '../assets/copy.svg?raw';
|
|
6
|
-
import {
|
|
6
|
+
import { createCopyState } from './copyState.svelte';
|
|
7
7
|
|
|
8
8
|
let {
|
|
9
9
|
text,
|
|
@@ -17,29 +17,25 @@
|
|
|
17
17
|
classes
|
|
18
18
|
}: SnippetProperties = $props();
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
await navigator.clipboard.writeText(text);
|
|
34
|
-
copied = true;
|
|
35
|
-
oncopy?.();
|
|
36
|
-
resetTimer.arm(() => {
|
|
37
|
-
copied = false;
|
|
38
|
-
}, copyResetMs);
|
|
39
|
-
} catch {
|
|
40
|
-
// Clipboard API unavailable (non-secure context, iframe restrictions)
|
|
20
|
+
// The whole copy affordance -- clipboard write, `copied` flag, the reset
|
|
21
|
+
// timer's single-pending guarantee from #530, and teardown -- lives in
|
|
22
|
+
// `createCopyState` so a consumer who wants the behaviour without this
|
|
23
|
+
// component's `<code>` box can have it (#574). Getters rather than plain
|
|
24
|
+
// values, because the factory reads its options at copy time and these are
|
|
25
|
+
// props: passing them by value would freeze whatever they were at mount.
|
|
26
|
+
const copyState = createCopyState({
|
|
27
|
+
get copyResetMs() {
|
|
28
|
+
return copyResetMs;
|
|
29
|
+
},
|
|
30
|
+
get oncopy() {
|
|
31
|
+
return oncopy;
|
|
41
32
|
}
|
|
42
|
-
}
|
|
33
|
+
});
|
|
34
|
+
onDestroy(copyState.destroy);
|
|
35
|
+
|
|
36
|
+
const handleCopy = (): void => {
|
|
37
|
+
void copyState.copy(text);
|
|
38
|
+
};
|
|
43
39
|
</script>
|
|
44
40
|
|
|
45
41
|
<div
|
|
@@ -53,9 +49,13 @@
|
|
|
53
49
|
</code>
|
|
54
50
|
{#if showCopyButton}
|
|
55
51
|
<div class="snippet-copy">
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
<!-- The label is only supplied while the button shows an icon and has no
|
|
53
|
+
visible text of its own. Keeping it once the label swaps to
|
|
54
|
+
"Copied!" would leave a screen reader announcing "Copy to clipboard"
|
|
55
|
+
over the visible feedback (WCAG 2.5.3, Label in Name). -->
|
|
56
|
+
<Button onclick={handleCopy} {...copyState.copied ? {} : { ariaLabel: 'Copy to clipboard' }}>
|
|
57
|
+
{#if copyState.copied}
|
|
58
|
+
<span class="snippet-copied">{copiedLabel}</span>
|
|
59
59
|
{:else if typeof copyIcon === 'function'}
|
|
60
60
|
{@render copyIcon()}
|
|
61
61
|
{:else}
|
|
@@ -64,6 +64,13 @@
|
|
|
64
64
|
{/if}
|
|
65
65
|
</Button>
|
|
66
66
|
</div>
|
|
67
|
+
<!-- A live region has to be in the DOM *before* its text changes, or many
|
|
68
|
+
screen-reader/browser pairs never announce it. The visible label is
|
|
69
|
+
swapped inside the button, so the announcement lives here instead:
|
|
70
|
+
always rendered, outside the button, with only its text changing. -->
|
|
71
|
+
<span class="snippet-status" role="status" aria-live="polite"
|
|
72
|
+
>{copyState.copied ? copiedLabel : ''}</span
|
|
73
|
+
>
|
|
67
74
|
{/if}
|
|
68
75
|
</div>
|
|
69
76
|
|
|
@@ -132,6 +139,20 @@
|
|
|
132
139
|
height: 100%;
|
|
133
140
|
}
|
|
134
141
|
|
|
142
|
+
/* Announced, never shown: the visible "Copied!" is the label inside the
|
|
143
|
+
button, and repeating it on screen would read as a duplicate. */
|
|
144
|
+
.snippet-status {
|
|
145
|
+
position: absolute;
|
|
146
|
+
width: 1px;
|
|
147
|
+
height: 1px;
|
|
148
|
+
margin: -1px;
|
|
149
|
+
padding: 0;
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
clip-path: inset(50%);
|
|
152
|
+
white-space: nowrap;
|
|
153
|
+
border: 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
135
156
|
.snippet-copied {
|
|
136
157
|
color: var(--snippet-copied-color, #4caf50);
|
|
137
158
|
font-size: var(--snippet-copied-font-size, 12px);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The copy-and-flash affordance behind `Snippet`, without its presentation.
|
|
3
|
+
*
|
|
4
|
+
* `Snippet` couples two separable things: this state machine — clipboard
|
|
5
|
+
* write, `copied` flag, reset timer, teardown — and a `<code>` box with a
|
|
6
|
+
* `$`-style prompt. A consumer who wants "copy this value" beside arbitrary
|
|
7
|
+
* content (a hostname in a settings row, a token, a URL) could take only the
|
|
8
|
+
* pair, so the affordance got hand-rolled outside the library instead. That
|
|
9
|
+
* is how the timer safety added in #530 failed to reach the surfaces most
|
|
10
|
+
* likely to need it: a duplicate has its own bare `setTimeout` and its own
|
|
11
|
+
* bugs.
|
|
12
|
+
*
|
|
13
|
+
* Extracted as a headless factory rather than a Svelte action because the
|
|
14
|
+
* caller has to *render* from `copied` — swapping a label for an icon — and
|
|
15
|
+
* an action can attach behaviour to an element but cannot hand state back to
|
|
16
|
+
* the template. The split follows `Tooltip/tooltip-action.ts`, which likewise
|
|
17
|
+
* keeps timing logic outside the component that uses it.
|
|
18
|
+
*
|
|
19
|
+
* Options are read at copy time, not captured at creation, so a caller with
|
|
20
|
+
* reactive values can pass getters:
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* const state = createCopyState({
|
|
24
|
+
* get copyResetMs() { return copyResetMs; },
|
|
25
|
+
* get oncopy() { return oncopy; }
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export type CopyStateOptions = {
|
|
30
|
+
/** Milliseconds before `copied` reverts. Defaults to `2000`. */
|
|
31
|
+
copyResetMs?: number;
|
|
32
|
+
/** Called once per successful copy. Never called when the write fails. */
|
|
33
|
+
oncopy?: () => void;
|
|
34
|
+
};
|
|
35
|
+
export type CopyState = {
|
|
36
|
+
/** True from a successful copy until the reset delay elapses. */
|
|
37
|
+
readonly copied: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Writes `text` to the clipboard. Resolves `true` on success, `false` if
|
|
40
|
+
* the clipboard was unavailable or refused — it never rejects, so a caller
|
|
41
|
+
* needs no try/catch of its own.
|
|
42
|
+
*/
|
|
43
|
+
copy: (text: string) => Promise<boolean>;
|
|
44
|
+
/** Cancels any pending reset. Call from the owner's teardown. */
|
|
45
|
+
destroy: () => void;
|
|
46
|
+
};
|
|
47
|
+
export declare function createCopyState(options?: CopyStateOptions): CopyState;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createCopyResetTimer } from './copyResetTimer';
|
|
2
|
+
const DEFAULT_COPY_RESET_MS = 2000;
|
|
3
|
+
/**
|
|
4
|
+
* The type says `number`, but a plain-JS or web-component caller can pass
|
|
5
|
+
* anything, and a getter can throw. Either would reach `setTimeout` as `NaN`
|
|
6
|
+
* — which fires immediately, so the feedback never appears — or leave the
|
|
7
|
+
* flag stuck on with no timer at all. An unusable delay must degrade to the
|
|
8
|
+
* default rather than break the affordance it controls.
|
|
9
|
+
*/
|
|
10
|
+
function resolveResetDelay(options) {
|
|
11
|
+
let requested;
|
|
12
|
+
try {
|
|
13
|
+
requested = options.copyResetMs;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return DEFAULT_COPY_RESET_MS;
|
|
17
|
+
}
|
|
18
|
+
if (typeof requested !== 'number' || !Number.isFinite(requested) || requested < 0) {
|
|
19
|
+
return DEFAULT_COPY_RESET_MS;
|
|
20
|
+
}
|
|
21
|
+
return requested;
|
|
22
|
+
}
|
|
23
|
+
export function createCopyState(options = {}) {
|
|
24
|
+
let copied = $state(false);
|
|
25
|
+
let destroyed = false;
|
|
26
|
+
const resetTimer = createCopyResetTimer();
|
|
27
|
+
return {
|
|
28
|
+
get copied() {
|
|
29
|
+
return copied;
|
|
30
|
+
},
|
|
31
|
+
async copy(text) {
|
|
32
|
+
if (destroyed) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
await navigator.clipboard.writeText(text);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* Clipboard unavailable: non-secure context, sandboxed iframe, or a
|
|
40
|
+
permission refusal. Reporting success here — and flashing "Copied!"
|
|
41
|
+
over a clipboard that never received the text — is the one outcome
|
|
42
|
+
worse than showing no feedback at all. */
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
// The clipboard promise can settle after its owner has unmounted.
|
|
46
|
+
if (destroyed) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// Resolved before the flag is set, so a throwing getter cannot leave
|
|
50
|
+
// `copied` true with nothing armed to clear it.
|
|
51
|
+
const delay = resolveResetDelay(options);
|
|
52
|
+
copied = true;
|
|
53
|
+
resetTimer.arm(() => {
|
|
54
|
+
copied = false;
|
|
55
|
+
}, delay);
|
|
56
|
+
try {
|
|
57
|
+
options.oncopy?.();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// A notification callback cannot undo the successful clipboard write.
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
},
|
|
64
|
+
destroy() {
|
|
65
|
+
destroyed = true;
|
|
66
|
+
resetTimer.cancel();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -102,6 +102,7 @@ export { default as Gallery } from './Gallery/Gallery.svelte';
|
|
|
102
102
|
export { ChatController } from './Chat/controller.svelte';
|
|
103
103
|
export { partyOf } from './Chat/roles';
|
|
104
104
|
export { SpeechToTextController } from './SpeechToText/controller.svelte';
|
|
105
|
+
export { createCopyState } from './Snippet/copyState.svelte';
|
|
105
106
|
export type * from './Button/properties';
|
|
106
107
|
export type * from './Modal/properties';
|
|
107
108
|
export type * from './Input/properties';
|
|
@@ -139,6 +140,7 @@ export type * from './Progress/properties';
|
|
|
139
140
|
export type * from './Pill/properties';
|
|
140
141
|
export type * from './Pagination/properties';
|
|
141
142
|
export type * from './Snippet/properties';
|
|
143
|
+
export type * from './Snippet/copyState.svelte';
|
|
142
144
|
export type * from './Gauge/properties';
|
|
143
145
|
export type * from './SplitButton/properties';
|
|
144
146
|
export type * from './KeyboardInput/properties';
|
package/dist/index.js
CHANGED
|
@@ -102,6 +102,7 @@ export { default as Gallery } from './Gallery/Gallery.svelte';
|
|
|
102
102
|
export { ChatController } from './Chat/controller.svelte';
|
|
103
103
|
export { partyOf } from './Chat/roles';
|
|
104
104
|
export { SpeechToTextController } from './SpeechToText/controller.svelte';
|
|
105
|
+
export { createCopyState } from './Snippet/copyState.svelte';
|
|
105
106
|
export { createSoundKit } from './SoundKit/SoundKit';
|
|
106
107
|
export { validateInput, lockBodyScroll, unlockBodyScroll } from './utils';
|
|
107
108
|
export { formatNumberIndian } from './_chart/format';
|
package/dist-wc/index.js
CHANGED
|
@@ -17676,7 +17676,7 @@ customElements.define("sui-select", create_custom_element(Select_wc, {
|
|
|
17676
17676
|
//#region src/lib/Sheet/Sheet.svelte
|
|
17677
17677
|
var root$31 = /* @__PURE__ */ from_html("<span class=\"sheet-title svelte-1dln6bq\"> </span>"), root_1$28 = /* @__PURE__ */ from_html("<div class=\"sheet-close-button svelte-1dln6bq\"><!></div>"), root_2$22 = /* @__PURE__ */ from_html("<div class=\"sheet-header svelte-1dln6bq\"><!> <!></div>"), root_3$20 = /* @__PURE__ */ from_html("<div class=\"sheet-footer svelte-1dln6bq\"><!></div>"), root_4$16 = /* @__PURE__ */ from_html("<div tabindex=\"-1\"><div role=\"dialog\" aria-modal=\"true\" tabindex=\"-1\"><!> <div class=\"sheet-content svelte-1dln6bq\"><!></div> <!></div></div>"), $$css$33 = {
|
|
17678
17678
|
hash: "svelte-1dln6bq",
|
|
17679
|
-
code: ".sheet-overlay.svelte-1dln6bq {position:fixed;top:0;left:0;right:0;bottom:0;z-index:var(--sheet-overlay-z-index, 15);-webkit-tap-highlight-color:transparent;}.overlay-visible.svelte-1dln6bq {background-color:var(--sheet-overlay-background, #00000066);}.overlay-invisible.svelte-1dln6bq {background-color:transparent;}.overlay-interactive.svelte-1dln6bq {pointer-events:auto;}.overlay-noninteractive.svelte-1dln6bq {pointer-events:none;}.sheet-panel.svelte-1dln6bq {position:fixed;display:flex;flex-direction:column;background-color:var(--sheet-background, #ffffff);box-shadow:var(--sheet-box-shadow, -2px 0 8px rgba(0, 0, 0, 0.15));z-index:var(--sheet-z-index, 16);pointer-events:auto;outline:none;}\n\n /* The panel itself is the initial focus target on open (scrollLockAction\n focuses it directly, and it's the Tab-trap's own boundary), so removing\n its outline unconditionally left a keyboard user with no visible sign\n focus had moved into the sheet at all -- particularly visible on the\n \"Raw\" variant, which has no focusable child for focus to land on\n instead. :focus-visible restores a ring precisely when the browser\n judges it's from keyboard/programmatic focus rather than a mouse click,\n so clicking the trigger still shows nothing new. outline-offset is\n negative (inset) rather than the usual positive offset other components\n in this library use, because left/right/top/bottom panels sit flush\n against a viewport edge -- a positive offset would clip there. */.sheet-panel.svelte-1dln6bq:focus-visible {outline:var(--sheet-panel-focus-outline, 2px solid #2563eb);outline-offset:var(--sheet-panel-focus-outline-offset, -2px);}\n\n /* --sheet-top/-right/-bottom/-left all default to the previous hardcoded\n edge-to-edge values below, so an unconfigured Sheet renders unchanged.\n Overriding one (e.g. --sheet-top to clear a fixed header, or --sheet-bottom:\n auto to size to content) turns the panel from an edge-to-edge slide-in into\n an anchored floating panel, without needing a different component. */.sheet-panel.left.svelte-1dln6bq,\n .sheet-panel.right.svelte-1dln6bq {top:var(--sheet-top, 0);bottom:var(--sheet-bottom, 0);width:var(--sheet-width, 400px);max-width:var(--sheet-max-width, 100vw);}.sheet-panel.left.svelte-1dln6bq {left:var(--sheet-left, 0);border-right:var(--sheet-border, none);}.sheet-panel.right.svelte-1dln6bq {right:var(--sheet-right, 0);border-left:var(--sheet-border, none);}.sheet-panel.top.svelte-1dln6bq,\n .sheet-panel.bottom.svelte-1dln6bq {left:var(--sheet-left, 0);right:var(--sheet-right, 0);height:var(--sheet-height, 300px);max-height:var(--sheet-max-height, 100vh);}.sheet-panel.top.svelte-1dln6bq {top:var(--sheet-top, 0);border-bottom:var(--sheet-border, none);}.sheet-panel.bottom.svelte-1dln6bq {bottom:var(--sheet-bottom, 0);border-top:var(--sheet-border, none);}\n\n /* `side=\"center\"` is a fixed-size floating dialog, not an edge-anchored\n panel: no top/bottom/left/right offset, sized by its own tokens rather\n than --sheet-width/--sheet-height (so an existing left/right/top/bottom\n theme is untouched by adding this variant), and centered with a\n transform instead of stretching to an edge. */.sheet-panel.center.svelte-1dln6bq {top:50%;left:50%;transform:translate(-50%, -50%);width:var(--sheet-center-width, 480px);max-width:var(--sheet-center-max-width, calc(100vw - 32px));max-height:var(--sheet-center-max-height, 90vh);}.sheet-header.svelte-1dln6bq {display:flex;align-items:center;padding:var(--sheet-header-padding, 16px 20px);background-color:var(--sheet-header-background, inherit);border-bottom:var(--sheet-header-border-bottom, 1px solid #e0e0e0);flex-shrink:0;}.sheet-title.svelte-1dln6bq {flex:1;font-size:var(--sheet-title-font-size, 18px);font-weight:var(--sheet-title-font-weight, 600);font-family:var(--sheet-title-font-family, inherit);color:var(--sheet-title-color, #1a1a1a);line-height:var(--sheet-title-line-height, 1.4);}.sheet-close-button.svelte-1dln6bq {--button-width: var(--sheet-close-button-size, 32px);--button-height: var(--sheet-close-button-size, 32px);--button-border: none;--button-border-radius: var(--sheet-close-button-border-radius, var(--radius, 4px));--button-color: var(--sheet-close-button-background, transparent);--button-text-color: var(--sheet-close-button-color, #666666);--button-font-size: var(--sheet-close-button-font-size, 16px);--button-padding: 0;--button-hover-color: var(--sheet-close-button-hover-background, #f0f0f0);flex-shrink:0;display:flex;align-items:center;justify-content:center;}.sheet-content.svelte-1dln6bq {flex:1;overflow-y:var(--sheet-content-overflow-y, auto);padding:var(--sheet-content-padding, 20px);scrollbar-width:var(--sheet-scrollbar-width, none);}.sheet-content.svelte-1dln6bq::-webkit-scrollbar {display:none;}.sheet-footer.svelte-1dln6bq {padding:var(--sheet-footer-padding, 16px 20px);background-color:var(--sheet-footer-background, inherit);border-top:var(--sheet-footer-border-top, 1px solid #e0e0e0);flex-shrink:0;}"
|
|
17679
|
+
code: ".sheet-overlay.svelte-1dln6bq {position:fixed;top:0;left:0;right:0;bottom:0;z-index:var(--sheet-overlay-z-index, 15);-webkit-tap-highlight-color:transparent;}.overlay-visible.svelte-1dln6bq {background-color:var(--sheet-overlay-background, #00000066);}.overlay-invisible.svelte-1dln6bq {background-color:transparent;}.overlay-interactive.svelte-1dln6bq {pointer-events:auto;}.overlay-noninteractive.svelte-1dln6bq {pointer-events:none;}.sheet-panel.svelte-1dln6bq {position:fixed;display:flex;flex-direction:column;background-color:var(--sheet-background, #ffffff);box-shadow:var(--sheet-box-shadow, -2px 0 8px rgba(0, 0, 0, 0.15));z-index:var(--sheet-z-index, 16);pointer-events:auto;outline:none;}\n\n /* The panel itself is the initial focus target on open (scrollLockAction\n focuses it directly, and it's the Tab-trap's own boundary), so removing\n its outline unconditionally left a keyboard user with no visible sign\n focus had moved into the sheet at all -- particularly visible on the\n \"Raw\" variant, which has no focusable child for focus to land on\n instead. :focus-visible restores a ring precisely when the browser\n judges it's from keyboard/programmatic focus rather than a mouse click,\n so clicking the trigger still shows nothing new. outline-offset is\n negative (inset) rather than the usual positive offset other components\n in this library use, because left/right/top/bottom panels sit flush\n against a viewport edge -- a positive offset would clip there. */.sheet-panel.svelte-1dln6bq:focus-visible {outline:var(--sheet-panel-focus-outline, 2px solid #2563eb);outline-offset:var(--sheet-panel-focus-outline-offset, -2px);}\n\n /* --sheet-top/-right/-bottom/-left all default to the previous hardcoded\n edge-to-edge values below, so an unconfigured Sheet renders unchanged.\n Overriding one (e.g. --sheet-top to clear a fixed header, or --sheet-bottom:\n auto to size to content) turns the panel from an edge-to-edge slide-in into\n an anchored floating panel, without needing a different component. */.sheet-panel.left.svelte-1dln6bq,\n .sheet-panel.right.svelte-1dln6bq {top:var(--sheet-top, 0);bottom:var(--sheet-bottom, 0);width:var(--sheet-width, 400px);max-width:var(--sheet-max-width, 100vw);}.sheet-panel.left.svelte-1dln6bq {left:var(--sheet-left, 0);border-right:var(--sheet-border, none);}.sheet-panel.right.svelte-1dln6bq {right:var(--sheet-right, 0);border-left:var(--sheet-border, none);}\n\n /* Top/bottom stretch edge to edge by default, exactly as before: --sheet-\n band-width is `auto`, so `margin-inline: auto` has nothing to distribute\n and the panel still spans --sheet-left to --sheet-right.\n\n Setting --sheet-band-width (or --sheet-band-max-width) caps it, and the\n auto margins then centre it between those same two insets -- which is the\n shape a bottom \"launch\" sheet wants above phone widths, and previously\n had to be faked with hand-computed calc() offsets.\n\n Deliberately NOT --sheet-width/--sheet-max-width, even though the issue\n proposed those names. Those already mean \"the width of a left/right\n panel\", so a consumer who themes them for their side sheets would find\n their bottom sheets silently reshaped by an upgrade. side=\"center\" avoids\n the same collision the same way, with its own --sheet-center-* tokens. */.sheet-panel.top.svelte-1dln6bq,\n .sheet-panel.bottom.svelte-1dln6bq {left:var(--sheet-left, 0);right:var(--sheet-right, 0);height:var(--sheet-height, 300px);max-height:var(--sheet-max-height, 100vh);width:var(--sheet-band-width, auto);max-width:var(--sheet-band-max-width, none);box-sizing:var(--sheet-band-box-sizing, content-box);margin-inline:auto;border:var(--sheet-band-border, none);}\n\n /* A capped panel is a floating card and needs all four edges; an\n edge-to-edge one deliberately draws only the edge it enters from. The\n entering edge falls back through --sheet-border so an existing theme that\n sets only that keeps rendering exactly as it did. */.sheet-panel.top.svelte-1dln6bq {top:var(--sheet-top, 0);border-bottom:var(--sheet-band-border, var(--sheet-border, none));}.sheet-panel.bottom.svelte-1dln6bq {bottom:var(--sheet-bottom, 0);border-top:var(--sheet-band-border, var(--sheet-border, none));}\n\n /* `side=\"center\"` is a fixed-size floating dialog, not an edge-anchored\n panel: no top/bottom/left/right offset, sized by its own tokens rather\n than --sheet-width/--sheet-height (so an existing left/right/top/bottom\n theme is untouched by adding this variant), and centered with a\n transform instead of stretching to an edge. */.sheet-panel.center.svelte-1dln6bq {top:50%;left:50%;transform:translate(-50%, -50%);width:var(--sheet-center-width, 480px);max-width:var(--sheet-center-max-width, calc(100vw - 32px));max-height:var(--sheet-center-max-height, 90vh);}.sheet-header.svelte-1dln6bq {display:flex;align-items:center;padding:var(--sheet-header-padding, 16px 20px);background-color:var(--sheet-header-background, inherit);border-bottom:var(--sheet-header-border-bottom, 1px solid #e0e0e0);flex-shrink:0;}.sheet-title.svelte-1dln6bq {flex:1;font-size:var(--sheet-title-font-size, 18px);font-weight:var(--sheet-title-font-weight, 600);font-family:var(--sheet-title-font-family, inherit);color:var(--sheet-title-color, #1a1a1a);line-height:var(--sheet-title-line-height, 1.4);}.sheet-close-button.svelte-1dln6bq {--button-width: var(--sheet-close-button-size, 32px);--button-height: var(--sheet-close-button-size, 32px);--button-border: none;--button-border-radius: var(--sheet-close-button-border-radius, var(--radius, 4px));--button-color: var(--sheet-close-button-background, transparent);--button-text-color: var(--sheet-close-button-color, #666666);--button-font-size: var(--sheet-close-button-font-size, 16px);--button-padding: 0;--button-hover-color: var(--sheet-close-button-hover-background, #f0f0f0);flex-shrink:0;display:flex;align-items:center;justify-content:center;}.sheet-content.svelte-1dln6bq {flex:1;overflow-y:var(--sheet-content-overflow-y, auto);padding:var(--sheet-content-padding, 20px);scrollbar-width:var(--sheet-scrollbar-width, none);}.sheet-content.svelte-1dln6bq::-webkit-scrollbar {display:none;}.sheet-footer.svelte-1dln6bq {padding:var(--sheet-footer-padding, 16px 20px);background-color:var(--sheet-footer-background, inherit);border-top:var(--sheet-footer-border-top, 1px solid #e0e0e0);flex-shrink:0;}"
|
|
17680
17680
|
};
|
|
17681
17681
|
function Sheet(e, t) {
|
|
17682
17682
|
push(t, !0), append_styles$1(e, $$css$33);
|
|
@@ -17731,10 +17731,11 @@ function Sheet(e, t) {
|
|
|
17731
17731
|
}
|
|
17732
17732
|
}
|
|
17733
17733
|
function Re(e) {
|
|
17734
|
+
let t = document.activeElement, n = !0;
|
|
17734
17735
|
return lockBodyScroll(), tick().then(() => {
|
|
17735
|
-
get(te) !== null && get(te).focus();
|
|
17736
|
+
n && get(te) !== null && get(te).focus();
|
|
17736
17737
|
}), { destroy() {
|
|
17737
|
-
unlockBodyScroll();
|
|
17738
|
+
n = !1, unlockBodyScroll(), t instanceof HTMLElement && t.isConnected && (document.activeElement === document.body || e.contains(document.activeElement)) && t.focus();
|
|
17738
17739
|
} };
|
|
17739
17740
|
}
|
|
17740
17741
|
function Ue() {
|
|
@@ -18013,23 +18014,66 @@ function createCopyResetTimer() {
|
|
|
18013
18014
|
};
|
|
18014
18015
|
}
|
|
18015
18016
|
//#endregion
|
|
18017
|
+
//#region src/lib/Snippet/copyState.svelte.ts
|
|
18018
|
+
var DEFAULT_COPY_RESET_MS = 2e3;
|
|
18019
|
+
function resolveResetDelay(e) {
|
|
18020
|
+
let t;
|
|
18021
|
+
try {
|
|
18022
|
+
t = e.copyResetMs;
|
|
18023
|
+
} catch {
|
|
18024
|
+
return DEFAULT_COPY_RESET_MS;
|
|
18025
|
+
}
|
|
18026
|
+
return typeof t != "number" || !Number.isFinite(t) || t < 0 ? DEFAULT_COPY_RESET_MS : t;
|
|
18027
|
+
}
|
|
18028
|
+
function createCopyState(e = {}) {
|
|
18029
|
+
let t = /* @__PURE__ */ state(!1), n = !1, i = createCopyResetTimer();
|
|
18030
|
+
return {
|
|
18031
|
+
get copied() {
|
|
18032
|
+
return get(t);
|
|
18033
|
+
},
|
|
18034
|
+
async copy(a) {
|
|
18035
|
+
if (n) return !1;
|
|
18036
|
+
try {
|
|
18037
|
+
await navigator.clipboard.writeText(a);
|
|
18038
|
+
} catch {
|
|
18039
|
+
return !1;
|
|
18040
|
+
}
|
|
18041
|
+
if (n) return !1;
|
|
18042
|
+
let o = resolveResetDelay(e);
|
|
18043
|
+
set(t, !0), i.arm(() => {
|
|
18044
|
+
set(t, !1);
|
|
18045
|
+
}, o);
|
|
18046
|
+
try {
|
|
18047
|
+
e.oncopy?.();
|
|
18048
|
+
} catch {}
|
|
18049
|
+
return !0;
|
|
18050
|
+
},
|
|
18051
|
+
destroy() {
|
|
18052
|
+
n = !0, i.cancel();
|
|
18053
|
+
}
|
|
18054
|
+
};
|
|
18055
|
+
}
|
|
18056
|
+
//#endregion
|
|
18016
18057
|
//#region src/lib/Snippet/Snippet.svelte
|
|
18017
|
-
var root$30 = /* @__PURE__ */ from_html("<span class=\"snippet-copied svelte-ql5iye\"
|
|
18058
|
+
var root$30 = /* @__PURE__ */ from_html("<span class=\"snippet-copied svelte-ql5iye\"> </span>"), root_1$27 = /* @__PURE__ */ from_html("<span class=\"snippet-copy-icon svelte-ql5iye\"></span>"), root_2$21 = /* @__PURE__ */ from_html("<div class=\"snippet-copy svelte-ql5iye\"><!></div> <span class=\"snippet-status svelte-ql5iye\" role=\"status\" aria-live=\"polite\"> </span>", 1), root_3$19 = /* @__PURE__ */ from_html("<div><code class=\"snippet-code svelte-ql5iye\"><span class=\"snippet-prompt svelte-ql5iye\"> </span> <span class=\"snippet-text svelte-ql5iye\"> </span></code> <!></div>"), $$css$32 = {
|
|
18018
18059
|
hash: "svelte-ql5iye",
|
|
18019
|
-
code: ".snippet.svelte-ql5iye {display:flex;align-items:center;justify-content:space-between;gap:var(--snippet-gap, 8px);background:var(--snippet-background, #1e1e1e);border:var(--snippet-border, 1px solid #333);border-radius:var(--snippet-border-radius, var(--radius, 4px));padding:var(--snippet-padding, 12px 16px);font-family:var(--snippet-font-family, monospace);font-size:var(--snippet-font-size, 14px);color:var(--snippet-color, #e0e0e0);margin:var(--snippet-margin, 0);}.snippet-code.svelte-ql5iye {display:flex;align-items:center;overflow:hidden;flex:1;min-width:0;}.snippet-prompt.svelte-ql5iye {color:var(--snippet-prompt-color, #888);margin-right:var(--snippet-prompt-margin-right, 8px);flex-shrink:0;}.snippet-text.svelte-ql5iye {color:var(--snippet-text-color, #e0e0e0);font-family:var(--snippet-text-font-family, inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.snippet-copy.svelte-ql5iye {--button-color: var(--snippet-copy-background, transparent);--button-text-color: var(--snippet-copy-color, #888);--button-border: var(--snippet-copy-border, none);--button-padding: var(--snippet-copy-padding, 4px);--button-border-radius: var(--snippet-copy-border-radius, var(--radius, 4px));--cursor: var(--snippet-copy-cursor, pointer);--button-hover-color: var(--snippet-copy-hover-background, #333);display:flex;align-items:center;justify-content:center;flex-shrink:0;}.snippet-copy-icon.svelte-ql5iye {display:inline-flex;align-items:center;justify-content:center;width:var(--snippet-copy-size, 16px);height:var(--snippet-copy-size, 16px);}.snippet-copy-icon.svelte-ql5iye svg {width:100%;height:100%;}.snippet-copied.svelte-ql5iye {color:var(--snippet-copied-color, #4caf50);font-size:var(--snippet-copied-font-size, 12px);font-family:var(--snippet-font-family, monospace);}"
|
|
18060
|
+
code: ".snippet.svelte-ql5iye {display:flex;align-items:center;justify-content:space-between;gap:var(--snippet-gap, 8px);background:var(--snippet-background, #1e1e1e);border:var(--snippet-border, 1px solid #333);border-radius:var(--snippet-border-radius, var(--radius, 4px));padding:var(--snippet-padding, 12px 16px);font-family:var(--snippet-font-family, monospace);font-size:var(--snippet-font-size, 14px);color:var(--snippet-color, #e0e0e0);margin:var(--snippet-margin, 0);}.snippet-code.svelte-ql5iye {display:flex;align-items:center;overflow:hidden;flex:1;min-width:0;}.snippet-prompt.svelte-ql5iye {color:var(--snippet-prompt-color, #888);margin-right:var(--snippet-prompt-margin-right, 8px);flex-shrink:0;}.snippet-text.svelte-ql5iye {color:var(--snippet-text-color, #e0e0e0);font-family:var(--snippet-text-font-family, inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.snippet-copy.svelte-ql5iye {--button-color: var(--snippet-copy-background, transparent);--button-text-color: var(--snippet-copy-color, #888);--button-border: var(--snippet-copy-border, none);--button-padding: var(--snippet-copy-padding, 4px);--button-border-radius: var(--snippet-copy-border-radius, var(--radius, 4px));--cursor: var(--snippet-copy-cursor, pointer);--button-hover-color: var(--snippet-copy-hover-background, #333);display:flex;align-items:center;justify-content:center;flex-shrink:0;}.snippet-copy-icon.svelte-ql5iye {display:inline-flex;align-items:center;justify-content:center;width:var(--snippet-copy-size, 16px);height:var(--snippet-copy-size, 16px);}.snippet-copy-icon.svelte-ql5iye svg {width:100%;height:100%;}\n\n /* Announced, never shown: the visible \"Copied!\" is the label inside the\n button, and repeating it on screen would read as a duplicate. */.snippet-status.svelte-ql5iye {position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;}.snippet-copied.svelte-ql5iye {color:var(--snippet-copied-color, #4caf50);font-size:var(--snippet-copied-font-size, 12px);font-family:var(--snippet-font-family, monospace);}"
|
|
18020
18061
|
};
|
|
18021
18062
|
function Snippet(e, t) {
|
|
18022
18063
|
push(t, !0), append_styles$1(e, $$css$32);
|
|
18023
|
-
let n = prop(t, "text", 7), i = prop(t, "prompt", 7, "$"), a = prop(t, "showCopyButton", 7, !0), o = prop(t, "testId", 7), s = prop(t, "copyIcon", 7), c = prop(t, "copiedLabel", 7, "Copied!"), l = prop(t, "copyResetMs", 7, 2e3), u = prop(t, "oncopy", 7), f = prop(t, "classes", 7), p =
|
|
18024
|
-
|
|
18025
|
-
|
|
18026
|
-
|
|
18027
|
-
|
|
18028
|
-
|
|
18029
|
-
|
|
18030
|
-
|
|
18031
|
-
|
|
18032
|
-
|
|
18064
|
+
let n = prop(t, "text", 7), i = prop(t, "prompt", 7, "$"), a = prop(t, "showCopyButton", 7, !0), o = prop(t, "testId", 7), s = prop(t, "copyIcon", 7), c = prop(t, "copiedLabel", 7, "Copied!"), l = prop(t, "copyResetMs", 7, 2e3), u = prop(t, "oncopy", 7), f = prop(t, "classes", 7), p = createCopyState({
|
|
18065
|
+
get copyResetMs() {
|
|
18066
|
+
return l();
|
|
18067
|
+
},
|
|
18068
|
+
get oncopy() {
|
|
18069
|
+
return u();
|
|
18070
|
+
}
|
|
18071
|
+
});
|
|
18072
|
+
onDestroy(p.destroy);
|
|
18073
|
+
let h = () => {
|
|
18074
|
+
p.copy(n());
|
|
18075
|
+
};
|
|
18076
|
+
var S = {
|
|
18033
18077
|
get text() {
|
|
18034
18078
|
return n();
|
|
18035
18079
|
},
|
|
@@ -18084,15 +18128,13 @@ function Snippet(e, t) {
|
|
|
18084
18128
|
set classes(e) {
|
|
18085
18129
|
f(e), flushSync();
|
|
18086
18130
|
}
|
|
18087
|
-
},
|
|
18088
|
-
reset(
|
|
18089
|
-
var
|
|
18090
|
-
reset(
|
|
18091
|
-
var
|
|
18092
|
-
var t = root_2$21();
|
|
18093
|
-
Button(child(
|
|
18094
|
-
onclick: S,
|
|
18095
|
-
ariaLabel: "Copy to clipboard",
|
|
18131
|
+
}, C = root_3$19(), k = child(C), R = child(k), G = child(R, !0);
|
|
18132
|
+
reset(R);
|
|
18133
|
+
var te = sibling(R, 2), ne = child(te, !0);
|
|
18134
|
+
reset(te), reset(k);
|
|
18135
|
+
var re = sibling(k, 2), be = (e) => {
|
|
18136
|
+
var t = root_2$21(), n = first_child(t);
|
|
18137
|
+
Button(child(n), spread_props({ onclick: h }, () => p.copied ? {} : { ariaLabel: "Copy to clipboard" }, {
|
|
18096
18138
|
children: (e, t) => {
|
|
18097
18139
|
var n = comment(), i = first_child(n), a = (e) => {
|
|
18098
18140
|
var t = root$30(), n = child(t, !0);
|
|
@@ -18105,17 +18147,19 @@ function Snippet(e, t) {
|
|
|
18105
18147
|
html(t, () => copy_default, !0), reset(t), append(e, t);
|
|
18106
18148
|
};
|
|
18107
18149
|
if_block(i, (e) => {
|
|
18108
|
-
|
|
18150
|
+
p.copied ? e(a) : typeof s() == "function" ? e(o, 1) : e(l, -1);
|
|
18109
18151
|
}), append(e, n);
|
|
18110
18152
|
},
|
|
18111
18153
|
$$slots: { default: !0 }
|
|
18112
|
-
}), reset(
|
|
18154
|
+
})), reset(n);
|
|
18155
|
+
var i = sibling(n, 2), a = child(i, !0);
|
|
18156
|
+
reset(i), template_effect(() => set_text(a, p.copied ? c() : "")), append(e, t);
|
|
18113
18157
|
};
|
|
18114
|
-
return if_block(
|
|
18115
|
-
a() && e(
|
|
18116
|
-
}), reset(
|
|
18117
|
-
set_class(
|
|
18118
|
-
}), append(e,
|
|
18158
|
+
return if_block(re, (e) => {
|
|
18159
|
+
a() && e(be);
|
|
18160
|
+
}), reset(C), template_effect(() => {
|
|
18161
|
+
set_class(C, 1, `snippet ${f() ?? "" ?? ""}`, "svelte-ql5iye"), set_attribute(C, "data-pw", typeof o() == "string" ? o() : null), set_attribute(C, "testid", typeof o() == "string" ? o() : null), set_text(G, i()), set_text(ne, n());
|
|
18162
|
+
}), append(e, C), pop(S);
|
|
18119
18163
|
}
|
|
18120
18164
|
create_custom_element(Snippet, {
|
|
18121
18165
|
text: {},
|