@delightstack/components 0.1.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/LICENSE +21 -0
- package/README.md +136 -0
- package/SKILL.md +149 -0
- package/bin/agents.js +63 -0
- package/dist/actions/Alert.svelte +202 -0
- package/dist/actions/Alert.svelte.d.ts +36 -0
- package/dist/actions/Alert.svelte.d.ts.map +1 -0
- package/dist/actions/Button.svelte +1450 -0
- package/dist/actions/Button.svelte.d.ts +56 -0
- package/dist/actions/Button.svelte.d.ts.map +1 -0
- package/dist/actions/ButtonGroup.svelte +111 -0
- package/dist/actions/ButtonGroup.svelte.d.ts +41 -0
- package/dist/actions/ButtonGroup.svelte.d.ts.map +1 -0
- package/dist/actions/CommandPalette.svelte +939 -0
- package/dist/actions/CommandPalette.svelte.d.ts +37 -0
- package/dist/actions/CommandPalette.svelte.d.ts.map +1 -0
- package/dist/actions/ContextMenu.svelte +138 -0
- package/dist/actions/ContextMenu.svelte.d.ts +54 -0
- package/dist/actions/ContextMenu.svelte.d.ts.map +1 -0
- package/dist/actions/Modal.svelte +474 -0
- package/dist/actions/Modal.svelte.d.ts +28 -0
- package/dist/actions/Modal.svelte.d.ts.map +1 -0
- package/dist/actions/Popover.svelte +1214 -0
- package/dist/actions/Popover.svelte.d.ts +31 -0
- package/dist/actions/Popover.svelte.d.ts.map +1 -0
- package/dist/actions/Portal.svelte +80 -0
- package/dist/actions/Portal.svelte.d.ts +17 -0
- package/dist/actions/Portal.svelte.d.ts.map +1 -0
- package/dist/actions/ThemeToggle.svelte +345 -0
- package/dist/actions/ThemeToggle.svelte.d.ts +15 -0
- package/dist/actions/ThemeToggle.svelte.d.ts.map +1 -0
- package/dist/actions/index.d.ts +13 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +10 -0
- package/dist/actions/scrollbar.d.ts +48 -0
- package/dist/actions/scrollbar.d.ts.map +1 -0
- package/dist/actions/scrollbar.js +404 -0
- package/dist/display/Accordion.svelte +586 -0
- package/dist/display/Accordion.svelte.d.ts +41 -0
- package/dist/display/Accordion.svelte.d.ts.map +1 -0
- package/dist/display/Avatar.svelte +527 -0
- package/dist/display/Avatar.svelte.d.ts +22 -0
- package/dist/display/Avatar.svelte.d.ts.map +1 -0
- package/dist/display/AvatarGroup.svelte +298 -0
- package/dist/display/AvatarGroup.svelte.d.ts +31 -0
- package/dist/display/AvatarGroup.svelte.d.ts.map +1 -0
- package/dist/display/Calendar.svelte +1366 -0
- package/dist/display/Calendar.svelte.d.ts +58 -0
- package/dist/display/Calendar.svelte.d.ts.map +1 -0
- package/dist/display/Chart.svelte +1426 -0
- package/dist/display/Chart.svelte.d.ts +35 -0
- package/dist/display/Chart.svelte.d.ts.map +1 -0
- package/dist/display/Code.svelte +780 -0
- package/dist/display/Code.svelte.d.ts +19 -0
- package/dist/display/Code.svelte.d.ts.map +1 -0
- package/dist/display/Comparison.svelte +686 -0
- package/dist/display/Comparison.svelte.d.ts +22 -0
- package/dist/display/Comparison.svelte.d.ts.map +1 -0
- package/dist/display/Counter.svelte +285 -0
- package/dist/display/Counter.svelte.d.ts +21 -0
- package/dist/display/Counter.svelte.d.ts.map +1 -0
- package/dist/display/Expand.svelte +48 -0
- package/dist/display/Expand.svelte.d.ts +9 -0
- package/dist/display/Expand.svelte.d.ts.map +1 -0
- package/dist/display/List.svelte +294 -0
- package/dist/display/List.svelte.d.ts +40 -0
- package/dist/display/List.svelte.d.ts.map +1 -0
- package/dist/display/ListContextReset.svelte +19 -0
- package/dist/display/ListContextReset.svelte.d.ts +7 -0
- package/dist/display/ListContextReset.svelte.d.ts.map +1 -0
- package/dist/display/ListItem.svelte +834 -0
- package/dist/display/ListItem.svelte.d.ts +22 -0
- package/dist/display/ListItem.svelte.d.ts.map +1 -0
- package/dist/display/QR.svelte +1193 -0
- package/dist/display/QR.svelte.d.ts +23 -0
- package/dist/display/QR.svelte.d.ts.map +1 -0
- package/dist/display/SplitPane.svelte +744 -0
- package/dist/display/SplitPane.svelte.d.ts +25 -0
- package/dist/display/SplitPane.svelte.d.ts.map +1 -0
- package/dist/display/Stat.svelte +439 -0
- package/dist/display/Stat.svelte.d.ts +24 -0
- package/dist/display/Stat.svelte.d.ts.map +1 -0
- package/dist/display/Table.svelte +4654 -0
- package/dist/display/Table.svelte.d.ts +249 -0
- package/dist/display/Table.svelte.d.ts.map +1 -0
- package/dist/display/TableCellEditor.svelte +935 -0
- package/dist/display/TableCellEditor.svelte.d.ts +58 -0
- package/dist/display/TableCellEditor.svelte.d.ts.map +1 -0
- package/dist/display/Timeline.svelte +1258 -0
- package/dist/display/Timeline.svelte.d.ts +43 -0
- package/dist/display/Timeline.svelte.d.ts.map +1 -0
- package/dist/display/Tree.svelte +1740 -0
- package/dist/display/Tree.svelte.d.ts +74 -0
- package/dist/display/Tree.svelte.d.ts.map +1 -0
- package/dist/display/Typewriter.svelte +338 -0
- package/dist/display/Typewriter.svelte.d.ts +22 -0
- package/dist/display/Typewriter.svelte.d.ts.map +1 -0
- package/dist/display/index.d.ts +24 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +18 -0
- package/dist/feedback/Callout.svelte +529 -0
- package/dist/feedback/Callout.svelte.d.ts +24 -0
- package/dist/feedback/Callout.svelte.d.ts.map +1 -0
- package/dist/feedback/Confetti.svelte +631 -0
- package/dist/feedback/Confetti.svelte.d.ts +90 -0
- package/dist/feedback/Confetti.svelte.d.ts.map +1 -0
- package/dist/feedback/Progress.svelte +382 -0
- package/dist/feedback/Progress.svelte.d.ts +25 -0
- package/dist/feedback/Progress.svelte.d.ts.map +1 -0
- package/dist/feedback/Toast.svelte +967 -0
- package/dist/feedback/Toast.svelte.d.ts +54 -0
- package/dist/feedback/Toast.svelte.d.ts.map +1 -0
- package/dist/feedback/index.d.ts +7 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/index.js +4 -0
- package/dist/form/Checkbox.svelte +449 -0
- package/dist/form/Checkbox.svelte.d.ts +27 -0
- package/dist/form/Checkbox.svelte.d.ts.map +1 -0
- package/dist/form/Fieldset.svelte +410 -0
- package/dist/form/Fieldset.svelte.d.ts +22 -0
- package/dist/form/Fieldset.svelte.d.ts.map +1 -0
- package/dist/form/FileUpload.svelte +934 -0
- package/dist/form/FileUpload.svelte.d.ts +41 -0
- package/dist/form/FileUpload.svelte.d.ts.map +1 -0
- package/dist/form/Form.svelte +530 -0
- package/dist/form/Form.svelte.d.ts +120 -0
- package/dist/form/Form.svelte.d.ts.map +1 -0
- package/dist/form/Input.svelte +2858 -0
- package/dist/form/Input.svelte.d.ts +66 -0
- package/dist/form/Input.svelte.d.ts.map +1 -0
- package/dist/form/Radio.svelte +507 -0
- package/dist/form/Radio.svelte.d.ts +39 -0
- package/dist/form/Radio.svelte.d.ts.map +1 -0
- package/dist/form/Range.svelte +912 -0
- package/dist/form/Range.svelte.d.ts +33 -0
- package/dist/form/Range.svelte.d.ts.map +1 -0
- package/dist/form/Rating.svelte +429 -0
- package/dist/form/Rating.svelte.d.ts +28 -0
- package/dist/form/Rating.svelte.d.ts.map +1 -0
- package/dist/form/Select.svelte +1933 -0
- package/dist/form/Select.svelte.d.ts +54 -0
- package/dist/form/Select.svelte.d.ts.map +1 -0
- package/dist/form/Toggle.svelte +645 -0
- package/dist/form/Toggle.svelte.d.ts +50 -0
- package/dist/form/Toggle.svelte.d.ts.map +1 -0
- package/dist/form/index.d.ts +15 -0
- package/dist/form/index.d.ts.map +1 -0
- package/dist/form/index.js +10 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/layout/README.md +172 -0
- package/dist/media/Carousel.svelte +2424 -0
- package/dist/media/Carousel.svelte.d.ts +47 -0
- package/dist/media/Carousel.svelte.d.ts.map +1 -0
- package/dist/media/Gallery.svelte +2881 -0
- package/dist/media/Gallery.svelte.d.ts +82 -0
- package/dist/media/Gallery.svelte.d.ts.map +1 -0
- package/dist/media/Image.svelte +389 -0
- package/dist/media/Image.svelte.d.ts +33 -0
- package/dist/media/Image.svelte.d.ts.map +1 -0
- package/dist/media/PDF.svelte +1793 -0
- package/dist/media/PDF.svelte.d.ts +44 -0
- package/dist/media/PDF.svelte.d.ts.map +1 -0
- package/dist/media/Panorama.svelte +1391 -0
- package/dist/media/Panorama.svelte.d.ts +47 -0
- package/dist/media/Panorama.svelte.d.ts.map +1 -0
- package/dist/media/Video.svelte +2501 -0
- package/dist/media/Video.svelte.d.ts +58 -0
- package/dist/media/Video.svelte.d.ts.map +1 -0
- package/dist/media/carousel.d.ts +211 -0
- package/dist/media/carousel.d.ts.map +1 -0
- package/dist/media/carousel.js +408 -0
- package/dist/media/index.d.ts +11 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +5 -0
- package/dist/navigation/BottomSheet.svelte +636 -0
- package/dist/navigation/BottomSheet.svelte.d.ts +27 -0
- package/dist/navigation/BottomSheet.svelte.d.ts.map +1 -0
- package/dist/navigation/Breadcrumbs.svelte +611 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts +28 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts.map +1 -0
- package/dist/navigation/Pagination.svelte +641 -0
- package/dist/navigation/Pagination.svelte.d.ts +27 -0
- package/dist/navigation/Pagination.svelte.d.ts.map +1 -0
- package/dist/navigation/Steps.svelte +965 -0
- package/dist/navigation/Steps.svelte.d.ts +43 -0
- package/dist/navigation/Steps.svelte.d.ts.map +1 -0
- package/dist/navigation/Tabs.svelte +698 -0
- package/dist/navigation/Tabs.svelte.d.ts +41 -0
- package/dist/navigation/Tabs.svelte.d.ts.map +1 -0
- package/dist/navigation/index.d.ts +8 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +5 -0
- package/package.json +139 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
let lastClickedElement = undefined as HTMLElement | undefined;
|
|
3
|
+
let lastClickedListenerCount = 0;
|
|
4
|
+
function onDocumentClick(event: MouseEvent) {
|
|
5
|
+
lastClickedElement = event.target as HTMLElement;
|
|
6
|
+
}
|
|
7
|
+
/** Listen for the last clicked element while at least one modal is mounted. Returns a cleanup */
|
|
8
|
+
function listenForLastClickedElement() {
|
|
9
|
+
if (!document) return;
|
|
10
|
+
lastClickedListenerCount++;
|
|
11
|
+
if (lastClickedListenerCount === 1) {
|
|
12
|
+
document.addEventListener('pointerdown', onDocumentClick);
|
|
13
|
+
}
|
|
14
|
+
return () => {
|
|
15
|
+
lastClickedListenerCount--;
|
|
16
|
+
if (lastClickedListenerCount === 0) {
|
|
17
|
+
document.removeEventListener('pointerdown', onDocumentClick);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script lang="ts">
|
|
24
|
+
import { crossfade, fade, scale } from 'svelte/transition';
|
|
25
|
+
import { quartOut } from 'svelte/easing';
|
|
26
|
+
import { type Snippet } from 'svelte';
|
|
27
|
+
import { focusTrap, generateID, ripple } from '@delightstack/utilities';
|
|
28
|
+
import Button from './Button.svelte';
|
|
29
|
+
import { scrollbar } from './scrollbar';
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
/** Title text displayed as the dialog header */
|
|
33
|
+
title = '',
|
|
34
|
+
|
|
35
|
+
/** Determines whether the dialog is open or not */
|
|
36
|
+
open = $bindable(false) as boolean,
|
|
37
|
+
|
|
38
|
+
/** Determines whether the dialog can be conventially closed using the escape key or backdrop click. */
|
|
39
|
+
closable = true,
|
|
40
|
+
|
|
41
|
+
/** Whether the close icon should be hidden or not */
|
|
42
|
+
disable_close_icon = false,
|
|
43
|
+
|
|
44
|
+
/** The ID of the modal - used to set/unset transition targets automatically */
|
|
45
|
+
modal_id = '',
|
|
46
|
+
|
|
47
|
+
/** The CSS string width of the modal (when on desktop) */
|
|
48
|
+
width = '',
|
|
49
|
+
|
|
50
|
+
/** The CSS string height of the modal (when on desktop) */
|
|
51
|
+
height = '',
|
|
52
|
+
|
|
53
|
+
/** The CSS string maximum width of the modal */
|
|
54
|
+
max_width = 'calc(100vw - 2rem)',
|
|
55
|
+
|
|
56
|
+
/** The CSS string maximum height of the modal */
|
|
57
|
+
max_height = 'calc(100svh - 2rem)',
|
|
58
|
+
|
|
59
|
+
/** The element that the modal will be animated from when opening */
|
|
60
|
+
transition_target = undefined as HTMLElement | Element | undefined,
|
|
61
|
+
|
|
62
|
+
/** The css style string added to the component from the parent */
|
|
63
|
+
style = '',
|
|
64
|
+
|
|
65
|
+
/** Specifies a custom class name for the dialog */
|
|
66
|
+
class: class_name = '',
|
|
67
|
+
|
|
68
|
+
/** The snippet used to render the modal body */
|
|
69
|
+
children = undefined as undefined | Snippet,
|
|
70
|
+
|
|
71
|
+
/** The snippet used to render the header bar */
|
|
72
|
+
header = undefined as undefined | Snippet,
|
|
73
|
+
|
|
74
|
+
/** The snippet used to render a child at the start of the header bar. Can't be used if 'header' is supplied */
|
|
75
|
+
header_start = undefined as undefined | Snippet,
|
|
76
|
+
|
|
77
|
+
/** The snippet used to render a child at the end of the header bar. Can't be used if 'header' is supplied */
|
|
78
|
+
header_end = undefined as undefined | Snippet,
|
|
79
|
+
|
|
80
|
+
/** The snippet used to render the modal footer */
|
|
81
|
+
footer = undefined as undefined | Snippet,
|
|
82
|
+
|
|
83
|
+
/** The snippet used to render the modal footer at the start. Can't be used if 'footer' is supplied */
|
|
84
|
+
footer_start = undefined as undefined | Snippet,
|
|
85
|
+
|
|
86
|
+
/** The snippet used to render the modal footer at the end. Can't be used if 'footer' is supplied */
|
|
87
|
+
footer_end = undefined as undefined | Snippet,
|
|
88
|
+
|
|
89
|
+
/** The function to call when the dialog is closed. If false is returned, the modal will not be closed */
|
|
90
|
+
onclose = undefined as undefined | (() => boolean | undefined | void),
|
|
91
|
+
|
|
92
|
+
/** The function to call when the dialog is opened */
|
|
93
|
+
onopen = undefined as undefined | (() => void),
|
|
94
|
+
|
|
95
|
+
/** The function to call when the backdrop is clicked */
|
|
96
|
+
onbackdropclick = undefined as undefined | (() => void),
|
|
97
|
+
|
|
98
|
+
...rest
|
|
99
|
+
} = $props();
|
|
100
|
+
|
|
101
|
+
const titleId = `modal-title-${generateID({ length: 6 })}`;
|
|
102
|
+
const bodyId = `modal-body-${generateID({ length: 6 })}`;
|
|
103
|
+
const easing = (t: number, factor = 0.5) => quartOut(t) * factor + (1 - factor);
|
|
104
|
+
let _open = $state(open);
|
|
105
|
+
$effect(() => listenForLastClickedElement());
|
|
106
|
+
$effect(() => {
|
|
107
|
+
if (open === _open) return;
|
|
108
|
+
const target = transition_target || lastClickedElement;
|
|
109
|
+
if (target && open) send(target, { key: 'modal' });
|
|
110
|
+
_open = open;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Setup the send/receive animation so the modal body can be animated into existence
|
|
114
|
+
const [send, receive] = crossfade({
|
|
115
|
+
duration: 300,
|
|
116
|
+
easing,
|
|
117
|
+
fallback: (node) => {
|
|
118
|
+
const style = getComputedStyle(node);
|
|
119
|
+
const transform = style.transform === 'none' ? '' : style.transform;
|
|
120
|
+
return {
|
|
121
|
+
duration: 300,
|
|
122
|
+
easing,
|
|
123
|
+
css: (t) => `transform: ${transform} translateZ(0px) scale(${t}); opacity: ${t}`,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
function close() {
|
|
129
|
+
if (closable && _open) {
|
|
130
|
+
const accepted = onclose?.() ?? true;
|
|
131
|
+
if (accepted) {
|
|
132
|
+
_open = false;
|
|
133
|
+
open = false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function handleEscapeKey({ key }: KeyboardEvent) {
|
|
138
|
+
if (key === 'Escape') close();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function mountModal(node: HTMLElement) {
|
|
142
|
+
if (onopen) onopen();
|
|
143
|
+
if (transition_target) transition_target = undefined;
|
|
144
|
+
return {
|
|
145
|
+
destroy: () => {
|
|
146
|
+
if (_open) return;
|
|
147
|
+
if (onclose) onclose();
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
</script>
|
|
152
|
+
|
|
153
|
+
<svelte:window onkeyup={handleEscapeKey} />
|
|
154
|
+
|
|
155
|
+
{#if _open}
|
|
156
|
+
<div
|
|
157
|
+
class={['modal', class_name].filter(Boolean).join(' ')}
|
|
158
|
+
{style}
|
|
159
|
+
in:receive={{ key: 'modal' }}
|
|
160
|
+
out:scale={{ duration: 100, start: 0.75 }}
|
|
161
|
+
role="dialog"
|
|
162
|
+
aria-modal="true"
|
|
163
|
+
aria-labelledby={titleId}
|
|
164
|
+
aria-describedby={bodyId}
|
|
165
|
+
{@attach focusTrap({
|
|
166
|
+
escapeDeactivates: false,
|
|
167
|
+
allowOutsideClick: true,
|
|
168
|
+
returnFocusOnDeactivate: true,
|
|
169
|
+
initialFocus: false,
|
|
170
|
+
})}
|
|
171
|
+
use:mountModal
|
|
172
|
+
{...rest}>
|
|
173
|
+
<div
|
|
174
|
+
class="body"
|
|
175
|
+
class:has-footer={!!(footer || footer_start || footer_end)}
|
|
176
|
+
id={bodyId}
|
|
177
|
+
style:width
|
|
178
|
+
style:height
|
|
179
|
+
style:max-width={max_width}
|
|
180
|
+
style:max-height={max_height}
|
|
181
|
+
{@attach scrollbar()}>
|
|
182
|
+
{#if (closable && !disable_close_icon) || title || header || header_start || header_end}
|
|
183
|
+
<header
|
|
184
|
+
class:bar={title || header || header_start || header_end}
|
|
185
|
+
class:no-close={!closable || disable_close_icon}>
|
|
186
|
+
{#if closable && !disable_close_icon}
|
|
187
|
+
<div class="close">
|
|
188
|
+
<Button transparent icon onclick={close} size="0">
|
|
189
|
+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
190
|
+
<path
|
|
191
|
+
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
|
|
192
|
+
</svg>
|
|
193
|
+
</Button>
|
|
194
|
+
</div>
|
|
195
|
+
{/if}
|
|
196
|
+
{#if title}<h2>{title}</h2>{/if}
|
|
197
|
+
{#if header}
|
|
198
|
+
{@render header()}
|
|
199
|
+
{:else}
|
|
200
|
+
{#if header_start}{@render header_start()}{/if}
|
|
201
|
+
<div class="spacer"></div>
|
|
202
|
+
{#if header_end}{@render header_end()}{/if}
|
|
203
|
+
{/if}
|
|
204
|
+
</header>
|
|
205
|
+
{/if}
|
|
206
|
+
{#if children}{@render children()}{/if}
|
|
207
|
+
{#if footer || footer_start || footer_end}
|
|
208
|
+
<footer>
|
|
209
|
+
{#if footer}
|
|
210
|
+
{@render footer()}
|
|
211
|
+
{:else}
|
|
212
|
+
{#if footer_start}{@render footer_start()}{/if}
|
|
213
|
+
<div class="spacer"></div>
|
|
214
|
+
{#if footer_end}{@render footer_end()}{/if}
|
|
215
|
+
{/if}
|
|
216
|
+
</footer>
|
|
217
|
+
{/if}
|
|
218
|
+
</div>
|
|
219
|
+
<div class="modal-fg"></div>
|
|
220
|
+
</div>
|
|
221
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
222
|
+
<div
|
|
223
|
+
class="modal-bg"
|
|
224
|
+
style:cursor={closable ? 'pointer' : ''}
|
|
225
|
+
style:pointer-events={closable ? '' : 'none'}
|
|
226
|
+
role="button"
|
|
227
|
+
tabindex="-1"
|
|
228
|
+
{@attach ripple()}
|
|
229
|
+
onclick={() => {
|
|
230
|
+
if (onbackdropclick) onbackdropclick();
|
|
231
|
+
close();
|
|
232
|
+
}}
|
|
233
|
+
in:fade={{ duration: 250, delay: 50 }}
|
|
234
|
+
out:fade={{ duration: 120 }}>
|
|
235
|
+
</div>
|
|
236
|
+
{/if}
|
|
237
|
+
|
|
238
|
+
<style>
|
|
239
|
+
:global(html:has(.modal)) {
|
|
240
|
+
overflow: hidden;
|
|
241
|
+
}
|
|
242
|
+
:global(::view-transition-old(modal-fg)),
|
|
243
|
+
:global(::view-transition-new(modal-fg)) {
|
|
244
|
+
/* Prevent the default animation,
|
|
245
|
+
so both views remain opacity:1 throughout the transition */
|
|
246
|
+
animation: none;
|
|
247
|
+
/* Use normal blending,
|
|
248
|
+
so the new view sits on top and obscures the old view */
|
|
249
|
+
mix-blend-mode: normal;
|
|
250
|
+
/* Make the height the same as the group,
|
|
251
|
+
meaning the view size might not match its aspect-ratio. */
|
|
252
|
+
height: 100%;
|
|
253
|
+
/* Clip any overflow of the view */
|
|
254
|
+
overflow: clip;
|
|
255
|
+
}
|
|
256
|
+
.modal {
|
|
257
|
+
/* panel sits one above the backdrop, which is at --layer-modal */
|
|
258
|
+
--layer: calc(var(--layer-modal) + 1);
|
|
259
|
+
/* Private tokens: the panel wants a bigger radius/shadow than the shared
|
|
260
|
+
defaults, but redefining --radius-lg/--shadow-md here would leak into
|
|
261
|
+
every component rendered inside the modal. The radius is clamped so an
|
|
262
|
+
over-rounded --radius-2xl can't turn this large panel into a blob — see
|
|
263
|
+
--radius-cap. Every panel surface (.body/.modal-fg/.close) inherits it. */
|
|
264
|
+
--_radius: min(var(--radius-2xl), var(--radius-cap, 40px));
|
|
265
|
+
--_shadow: var(--shadow-lg);
|
|
266
|
+
display: grid;
|
|
267
|
+
position: fixed;
|
|
268
|
+
z-index: var(--layer);
|
|
269
|
+
top: 0;
|
|
270
|
+
left: 0;
|
|
271
|
+
bottom: 0;
|
|
272
|
+
right: 0;
|
|
273
|
+
grid-template-columns: 100%;
|
|
274
|
+
grid-template-rows: 100%;
|
|
275
|
+
width: 100%;
|
|
276
|
+
height: 100%;
|
|
277
|
+
align-content: center;
|
|
278
|
+
justify-content: center;
|
|
279
|
+
pointer-events: none;
|
|
280
|
+
|
|
281
|
+
@media (min-width: 768px) {
|
|
282
|
+
overflow: hidden;
|
|
283
|
+
grid-template-rows: max-content;
|
|
284
|
+
grid-template-columns: max-content;
|
|
285
|
+
border-radius: var(--_radius);
|
|
286
|
+
@supports (corner-shape: squircle) {
|
|
287
|
+
corner-shape: squircle;
|
|
288
|
+
border-radius: calc(var(--_radius) * var(--squircle-ratio, 2));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
header {
|
|
293
|
+
display: flex;
|
|
294
|
+
align-items: center;
|
|
295
|
+
position: absolute;
|
|
296
|
+
bottom: 0;
|
|
297
|
+
left: 0;
|
|
298
|
+
background-color: var(--color-bg);
|
|
299
|
+
z-index: 2;
|
|
300
|
+
gap: 0.5rem;
|
|
301
|
+
padding: 0.5rem 0.5rem 0.5rem 0;
|
|
302
|
+
overflow-x: auto;
|
|
303
|
+
@media (max-width: 767px) {
|
|
304
|
+
width: 100%;
|
|
305
|
+
:global(> *) {
|
|
306
|
+
flex-shrink: 0;
|
|
307
|
+
}
|
|
308
|
+
h2 {
|
|
309
|
+
font-size: 1.15rem;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
@media (min-width: 768px) {
|
|
313
|
+
&.bar {
|
|
314
|
+
padding: 0;
|
|
315
|
+
position: sticky;
|
|
316
|
+
margin: -1.5rem -1rem 0.5rem -1.25rem;
|
|
317
|
+
height: 4rem;
|
|
318
|
+
top: calc(-2rem - 1px);
|
|
319
|
+
bottom: unset;
|
|
320
|
+
left: unset;
|
|
321
|
+
overflow-x: hidden;
|
|
322
|
+
/* Without a close button the title sits on the edge of the bar;
|
|
323
|
+
pad it so its distance from the panel's left edge matches its
|
|
324
|
+
distance from the top. */
|
|
325
|
+
&.no-close {
|
|
326
|
+
padding-inline-start: 1.25rem;
|
|
327
|
+
/*padding-block-start: 0.5rem;*/
|
|
328
|
+
margin-block-start: -1rem;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
@media (max-width: 767px) {
|
|
333
|
+
&.no-close {
|
|
334
|
+
padding-inline-start: 0.75rem;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
&:not(.bar) {
|
|
338
|
+
background-color: transparent;
|
|
339
|
+
position: sticky;
|
|
340
|
+
left: 0;
|
|
341
|
+
top: -1rem;
|
|
342
|
+
bottom: unset;
|
|
343
|
+
height: 4rem;
|
|
344
|
+
width: 4rem;
|
|
345
|
+
margin: -3rem 0 0 -2rem;
|
|
346
|
+
overflow: hidden;
|
|
347
|
+
@media (min-width: 768px) {
|
|
348
|
+
left: -1rem;
|
|
349
|
+
top: -2rem;
|
|
350
|
+
margin: -2rem 0 0 -2rem;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
.close {
|
|
354
|
+
position: sticky;
|
|
355
|
+
left: 0;
|
|
356
|
+
background-color: var(--color-bg);
|
|
357
|
+
border-radius: var(--_radius);
|
|
358
|
+
@supports (corner-shape: squircle) {
|
|
359
|
+
corner-shape: squircle;
|
|
360
|
+
border-radius: calc(var(--_radius) * var(--squircle-ratio, 2));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
.spacer {
|
|
364
|
+
flex: 1;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
.body {
|
|
369
|
+
grid-column: 1 / 1;
|
|
370
|
+
grid-row: 1 / 1;
|
|
371
|
+
height: 100%;
|
|
372
|
+
z-index: 1;
|
|
373
|
+
padding: 1rem 0.5rem;
|
|
374
|
+
view-transition-name: modal-body;
|
|
375
|
+
overflow-y: auto;
|
|
376
|
+
overflow-x: hidden;
|
|
377
|
+
overscroll-behavior: contain;
|
|
378
|
+
pointer-events: auto;
|
|
379
|
+
/* The overlay scrollbar takes no layout space (the native gutter that
|
|
380
|
+
scrollbar-gutter: stable both-edges used to reserve is gone), so the
|
|
381
|
+
inline padding carries the full edge distance itself. */
|
|
382
|
+
scrollbar-gutter: stable both-edges;
|
|
383
|
+
@media (max-width: 767px) {
|
|
384
|
+
min-width: 100vw;
|
|
385
|
+
padding-bottom: 4rem;
|
|
386
|
+
}
|
|
387
|
+
@media (min-width: 768px) {
|
|
388
|
+
padding: 2rem 2.5rem;
|
|
389
|
+
/* The body is the scroll container, so its own rounded clip is what
|
|
390
|
+
actually crops the sticky header/footer. Match the panel's squircle
|
|
391
|
+
corners — without this their square boxes bleed over the curve. */
|
|
392
|
+
border-radius: var(--_radius);
|
|
393
|
+
@supports (corner-shape: squircle) {
|
|
394
|
+
corner-shape: squircle;
|
|
395
|
+
border-radius: calc(var(--_radius) * var(--squircle-ratio, 2));
|
|
396
|
+
}
|
|
397
|
+
/* The footer carries its own bottom spacing (and must end flush with
|
|
398
|
+
the body's content box for sticky positioning to leave it at the
|
|
399
|
+
bottom edge — a negative margin over padding gets clamped back up,
|
|
400
|
+
overlapping the content above). */
|
|
401
|
+
&.has-footer {
|
|
402
|
+
padding-bottom: 0;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
/* Corner inset for the styled-native fallback (pre-JS / no overlay) */
|
|
406
|
+
--scrollbar-track-inset: calc(var(--_radius, 10px) / 2);
|
|
407
|
+
}
|
|
408
|
+
footer {
|
|
409
|
+
display: flex;
|
|
410
|
+
align-items: center;
|
|
411
|
+
gap: 0.5rem;
|
|
412
|
+
justify-content: flex-end;
|
|
413
|
+
background-color: var(--color-bg);
|
|
414
|
+
border-top: 1px solid var(--color-border, rgb(from var(--color-text) r g b / 0.1));
|
|
415
|
+
/* Full-bleed: negative inline margins cancel the body's padding so the
|
|
416
|
+
divider spans edge to edge, like the header bar. */
|
|
417
|
+
margin: 1rem -0.5rem 0;
|
|
418
|
+
padding: 0.75rem 1rem;
|
|
419
|
+
@media (min-width: 768px) {
|
|
420
|
+
/* The body drops its bottom padding when a footer is present (see
|
|
421
|
+
.body.has-footer), so the footer ends flush with the modal's
|
|
422
|
+
bottom edge and sticks there while long content scrolls underneath.
|
|
423
|
+
Actions sit closer to the edge than body content would (1rem vs the
|
|
424
|
+
body's 2rem) — a chrome row, not content. */
|
|
425
|
+
position: sticky;
|
|
426
|
+
bottom: 0;
|
|
427
|
+
z-index: 2;
|
|
428
|
+
margin: 1.5rem -2.5rem 0;
|
|
429
|
+
/* Inline padding matches the block padding, so the action buttons sit
|
|
430
|
+
the same distance from the bottom and side edges. */
|
|
431
|
+
padding: 1.5rem;
|
|
432
|
+
}
|
|
433
|
+
/* On mobile the footer stays in flow: the header bar is pinned to the
|
|
434
|
+
bottom of the screen there, and the body's 4rem bottom padding keeps
|
|
435
|
+
the footer clear of it. */
|
|
436
|
+
}
|
|
437
|
+
.modal-fg {
|
|
438
|
+
view-transition-name: modal-fg;
|
|
439
|
+
z-index: -1;
|
|
440
|
+
grid-column: 1 / 1;
|
|
441
|
+
grid-row: 1 / 1;
|
|
442
|
+
height: 100%;
|
|
443
|
+
background-color: var(--color-bg);
|
|
444
|
+
z-index: -1;
|
|
445
|
+
box-shadow: var(--_shadow);
|
|
446
|
+
@media (min-width: 768px) {
|
|
447
|
+
border-radius: var(--_radius);
|
|
448
|
+
@supports (corner-shape: squircle) {
|
|
449
|
+
corner-shape: squircle;
|
|
450
|
+
border-radius: calc(var(--_radius) * var(--squircle-ratio, 2));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
.modal-bg {
|
|
455
|
+
--layer: var(--layer-modal);
|
|
456
|
+
position: fixed;
|
|
457
|
+
top: 0;
|
|
458
|
+
bottom: 0;
|
|
459
|
+
right: 0;
|
|
460
|
+
left: 0;
|
|
461
|
+
backdrop-filter: blur(15px);
|
|
462
|
+
z-index: var(--layer);
|
|
463
|
+
&::after {
|
|
464
|
+
content: '';
|
|
465
|
+
background-color: var(--color-text);
|
|
466
|
+
position: absolute;
|
|
467
|
+
top: 0;
|
|
468
|
+
left: 0;
|
|
469
|
+
right: 0;
|
|
470
|
+
bottom: 0;
|
|
471
|
+
opacity: 0.2;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
</style>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
declare const Modal: import("svelte").Component<{
|
|
3
|
+
title?: string;
|
|
4
|
+
open?: boolean;
|
|
5
|
+
closable?: boolean;
|
|
6
|
+
disable_close_icon?: boolean;
|
|
7
|
+
modal_id?: string;
|
|
8
|
+
width?: string;
|
|
9
|
+
height?: string;
|
|
10
|
+
max_width?: string;
|
|
11
|
+
max_height?: string;
|
|
12
|
+
transition_target?: HTMLElement | Element | undefined;
|
|
13
|
+
style?: string;
|
|
14
|
+
class?: string;
|
|
15
|
+
children?: undefined | Snippet;
|
|
16
|
+
header?: undefined | Snippet;
|
|
17
|
+
header_start?: undefined | Snippet;
|
|
18
|
+
header_end?: undefined | Snippet;
|
|
19
|
+
footer?: undefined | Snippet;
|
|
20
|
+
footer_start?: undefined | Snippet;
|
|
21
|
+
footer_end?: undefined | Snippet;
|
|
22
|
+
onclose?: undefined | (() => boolean | undefined | void);
|
|
23
|
+
onopen?: undefined | (() => void);
|
|
24
|
+
onbackdropclick?: undefined | (() => void);
|
|
25
|
+
} & Record<string, any>, {}, "open">;
|
|
26
|
+
type Modal = ReturnType<typeof Modal>;
|
|
27
|
+
export default Modal;
|
|
28
|
+
//# sourceMappingURL=Modal.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../src/actions/Modal.svelte.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAmMtC,QAAA,MAAM,KAAK;YAxL2C,MAAM;WAAS,OAAO;eAAa,OAAO;yBAAuB,OAAO;eAAa,MAAM;YAAU,MAAM;aAAW,MAAM;gBAAc,MAAM;iBAAe,MAAM;wBAAsB,WAAW,GAAG,OAAO,GAAG,SAAS;YAAU,MAAM;YAAU,MAAM;eAAa,SAAS,GAAG,OAAO;aAAW,SAAS,GAAG,OAAO;mBAAiB,SAAS,GAAG,OAAO;iBAAe,SAAS,GAAG,OAAO;aAAW,SAAS,GAAG,OAAO;mBAAiB,SAAS,GAAG,OAAO;iBAAe,SAAS,GAAG,OAAO;cAAY,SAAS,GAAG,CAAC,MAAM,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;aAAW,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC;sBAAoB,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC;oCAwLhnB,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
|