@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,586 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export { default as AccordionItem } from './Accordion.svelte';
|
|
3
|
+
|
|
4
|
+
export interface AccordionContext {
|
|
5
|
+
/** Returns whether the item with the given value is currently expanded */
|
|
6
|
+
isOpen: (value: string) => boolean;
|
|
7
|
+
/** Expands/collapses the item with the given value */
|
|
8
|
+
toggle: (value: string) => void;
|
|
9
|
+
/** Whether the whole accordion is disabled */
|
|
10
|
+
disabled: boolean;
|
|
11
|
+
/** Whether the accordion uses dense (compact) spacing */
|
|
12
|
+
dense: boolean;
|
|
13
|
+
/** Whether the accordion uses comfortable (roomy) spacing */
|
|
14
|
+
comfortable: boolean;
|
|
15
|
+
/** Whether items are rendered as subtly filled surfaces */
|
|
16
|
+
filled: boolean;
|
|
17
|
+
/** Whether the whole accordion is wrapped in a bordered, rounded outline */
|
|
18
|
+
outline: boolean;
|
|
19
|
+
/** Whether the open item splits away from the list with a separating gap */
|
|
20
|
+
separated: boolean;
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<script lang="ts">
|
|
25
|
+
import { getContext, setContext, type Snippet } from 'svelte';
|
|
26
|
+
import Expand from './Expand.svelte';
|
|
27
|
+
|
|
28
|
+
const propId = $props.id();
|
|
29
|
+
|
|
30
|
+
let {
|
|
31
|
+
/* --- AccordionItem props --- */
|
|
32
|
+
/** The value identifying this item (required for AccordionItem) */
|
|
33
|
+
value = $bindable('') as string | string[],
|
|
34
|
+
|
|
35
|
+
/** The title text for this item's trigger */
|
|
36
|
+
title = '',
|
|
37
|
+
|
|
38
|
+
/** Custom trigger snippet (replaces default title rendering) */
|
|
39
|
+
trigger = undefined as undefined | Snippet,
|
|
40
|
+
|
|
41
|
+
/** Whether this individual item is disabled */
|
|
42
|
+
disabled = false,
|
|
43
|
+
|
|
44
|
+
/** Child content snippet */
|
|
45
|
+
children = undefined as undefined | Snippet,
|
|
46
|
+
|
|
47
|
+
/* --- Accordion container props --- */
|
|
48
|
+
/** Allow multiple panels open simultaneously */
|
|
49
|
+
multiple = false,
|
|
50
|
+
|
|
51
|
+
/** Allow closing all items (when false, at least one stays open) */
|
|
52
|
+
collapsible = true,
|
|
53
|
+
|
|
54
|
+
/** Whether to display in a condensed view */
|
|
55
|
+
dense = false,
|
|
56
|
+
|
|
57
|
+
/** Whether to display in an expanded view */
|
|
58
|
+
comfortable = false,
|
|
59
|
+
|
|
60
|
+
/** Render each item as a subtly filled surface */
|
|
61
|
+
filled = false,
|
|
62
|
+
|
|
63
|
+
/** Wrap the whole accordion in a bordered, rounded outline */
|
|
64
|
+
outline = false,
|
|
65
|
+
|
|
66
|
+
/** Animate the open item apart from the list (rounds the split edges) */
|
|
67
|
+
separated = false,
|
|
68
|
+
|
|
69
|
+
/** Show skeleton shimmer placeholders */
|
|
70
|
+
skeleton = false,
|
|
71
|
+
|
|
72
|
+
/** Number of skeleton bars to render */
|
|
73
|
+
skeleton_count = 3,
|
|
74
|
+
|
|
75
|
+
/** The ID of the element */
|
|
76
|
+
id = propId,
|
|
77
|
+
|
|
78
|
+
/** Specifies a custom class name */
|
|
79
|
+
class: class_name = '',
|
|
80
|
+
} = $props();
|
|
81
|
+
|
|
82
|
+
/* ------------------------------------------------------------------ */
|
|
83
|
+
/* Determine whether this instance is a container or an item */
|
|
84
|
+
/* ------------------------------------------------------------------ */
|
|
85
|
+
const isItem = $derived(!!title || !!trigger);
|
|
86
|
+
|
|
87
|
+
/* ------------------------------------------------------------------ */
|
|
88
|
+
/* Accordion container behaviour (context is set for containers) */
|
|
89
|
+
/* ------------------------------------------------------------------ */
|
|
90
|
+
const ctx = $state<AccordionContext>({
|
|
91
|
+
isOpen(val: string) {
|
|
92
|
+
if (Array.isArray(value)) return value.includes(val);
|
|
93
|
+
return value === val;
|
|
94
|
+
},
|
|
95
|
+
toggle(val: string) {
|
|
96
|
+
if (multiple) {
|
|
97
|
+
const arr: string[] = Array.isArray(value)
|
|
98
|
+
? [...value]
|
|
99
|
+
: value
|
|
100
|
+
? [value as string]
|
|
101
|
+
: [];
|
|
102
|
+
const idx = arr.indexOf(val);
|
|
103
|
+
if (idx >= 0) {
|
|
104
|
+
if (!collapsible && arr.length === 1) return;
|
|
105
|
+
arr.splice(idx, 1);
|
|
106
|
+
} else {
|
|
107
|
+
arr.push(val);
|
|
108
|
+
}
|
|
109
|
+
value = arr;
|
|
110
|
+
} else {
|
|
111
|
+
if (value === val) {
|
|
112
|
+
if (!collapsible) return;
|
|
113
|
+
value = '';
|
|
114
|
+
} else {
|
|
115
|
+
value = val;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
disabled,
|
|
120
|
+
dense,
|
|
121
|
+
comfortable,
|
|
122
|
+
filled,
|
|
123
|
+
outline,
|
|
124
|
+
separated,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Only set context when this is a container (not an item).
|
|
128
|
+
// Both setContext and getContext run unconditionally at the top level.
|
|
129
|
+
if (!title && !trigger) {
|
|
130
|
+
setContext<AccordionContext>('accordion', ctx);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
$effect(() => {
|
|
134
|
+
ctx.disabled = disabled;
|
|
135
|
+
ctx.dense = dense;
|
|
136
|
+
ctx.comfortable = comfortable;
|
|
137
|
+
ctx.filled = filled;
|
|
138
|
+
ctx.outline = outline;
|
|
139
|
+
ctx.separated = separated;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
/* ------------------------------------------------------------------ */
|
|
143
|
+
/* AccordionItem behaviour */
|
|
144
|
+
/* ------------------------------------------------------------------ */
|
|
145
|
+
const accordion = getContext<AccordionContext | undefined>('accordion');
|
|
146
|
+
|
|
147
|
+
const itemValue = $derived(typeof value === 'string' ? value : '');
|
|
148
|
+
const isOpen = $derived(accordion ? accordion.isOpen(itemValue) : false);
|
|
149
|
+
const isDisabled = $derived(accordion ? accordion.disabled || disabled : disabled);
|
|
150
|
+
const isDense = $derived(accordion ? accordion.dense : dense);
|
|
151
|
+
const isComfortable = $derived(accordion ? accordion.comfortable : comfortable);
|
|
152
|
+
const isFilled = $derived(accordion ? accordion.filled : filled);
|
|
153
|
+
const isOutline = $derived(accordion ? accordion.outline : outline);
|
|
154
|
+
const isSeparated = $derived(accordion ? accordion.separated : separated);
|
|
155
|
+
|
|
156
|
+
const contentId = $derived(`${id}-content`);
|
|
157
|
+
const triggerId = $derived(`${id}-trigger`);
|
|
158
|
+
|
|
159
|
+
function handleToggle(e: Event) {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
if (isDisabled || !accordion) return;
|
|
162
|
+
accordion.toggle(itemValue);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function handleKeyDown(e: KeyboardEvent) {
|
|
166
|
+
const target = e.currentTarget as HTMLElement;
|
|
167
|
+
|
|
168
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
169
|
+
e.preventDefault();
|
|
170
|
+
handleToggle(e);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const container = target.closest('.accordion');
|
|
175
|
+
if (!container) return;
|
|
176
|
+
|
|
177
|
+
const summaries = Array.from(
|
|
178
|
+
container.querySelectorAll<HTMLElement>('.summary:not([aria-disabled="true"])'),
|
|
179
|
+
);
|
|
180
|
+
const idx = summaries.indexOf(target);
|
|
181
|
+
if (idx === -1) return;
|
|
182
|
+
|
|
183
|
+
if (e.key === 'ArrowDown') {
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
summaries[(idx + 1) % summaries.length]?.focus();
|
|
186
|
+
} else if (e.key === 'ArrowUp') {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
summaries[(idx - 1 + summaries.length) % summaries.length]?.focus();
|
|
189
|
+
} else if (e.key === 'Home') {
|
|
190
|
+
e.preventDefault();
|
|
191
|
+
summaries[0]?.focus();
|
|
192
|
+
} else if (e.key === 'End') {
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
summaries[summaries.length - 1]?.focus();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
</script>
|
|
198
|
+
|
|
199
|
+
{#if isItem}
|
|
200
|
+
<!-- AccordionItem -->
|
|
201
|
+
<div
|
|
202
|
+
class={['item', class_name].filter(Boolean).join(' ')}
|
|
203
|
+
class:open={isOpen}
|
|
204
|
+
class:dense={isDense}
|
|
205
|
+
class:comfortable={isComfortable}
|
|
206
|
+
class:filled={isFilled}
|
|
207
|
+
class:outline={isOutline}
|
|
208
|
+
class:separated={isSeparated}
|
|
209
|
+
class:disabled={isDisabled}
|
|
210
|
+
{id}>
|
|
211
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
212
|
+
<div
|
|
213
|
+
class="summary"
|
|
214
|
+
role="button"
|
|
215
|
+
id={triggerId}
|
|
216
|
+
tabindex={isDisabled ? -1 : 0}
|
|
217
|
+
aria-expanded={isOpen}
|
|
218
|
+
aria-controls={contentId}
|
|
219
|
+
aria-disabled={isDisabled}
|
|
220
|
+
onclick={handleToggle}
|
|
221
|
+
onkeydown={handleKeyDown}>
|
|
222
|
+
<svg class="chevron" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
223
|
+
<path
|
|
224
|
+
d="M6 3L11 8L6 13"
|
|
225
|
+
stroke="currentColor"
|
|
226
|
+
stroke-width="1.5"
|
|
227
|
+
stroke-linecap="round"
|
|
228
|
+
stroke-linejoin="round" />
|
|
229
|
+
</svg>
|
|
230
|
+
<span class="title">
|
|
231
|
+
{#if trigger}
|
|
232
|
+
{@render trigger()}
|
|
233
|
+
{:else}
|
|
234
|
+
{title}
|
|
235
|
+
{/if}
|
|
236
|
+
</span>
|
|
237
|
+
</div>
|
|
238
|
+
<div id={contentId} role="region" aria-labelledby={triggerId}>
|
|
239
|
+
<Expand show={isOpen}>
|
|
240
|
+
<div class="panel">
|
|
241
|
+
{@render children?.()}
|
|
242
|
+
</div>
|
|
243
|
+
</Expand>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
{:else if skeleton}
|
|
247
|
+
<!-- Skeleton -->
|
|
248
|
+
<div
|
|
249
|
+
class={['accordion skeleton', class_name].filter(Boolean).join(' ')}
|
|
250
|
+
class:dense
|
|
251
|
+
class:comfortable
|
|
252
|
+
{id}
|
|
253
|
+
aria-hidden="true">
|
|
254
|
+
{#each { length: skeleton_count } as _, i}
|
|
255
|
+
<div class="skeleton-item" style:--shimmer-delay="{i * 120}ms">
|
|
256
|
+
<div class="skeleton-chevron"></div>
|
|
257
|
+
<div class="skeleton-bar" style:width="{40 + ((i * 37 + 13) % 35)}%"></div>
|
|
258
|
+
</div>
|
|
259
|
+
{/each}
|
|
260
|
+
</div>
|
|
261
|
+
{:else}
|
|
262
|
+
<!-- Accordion container -->
|
|
263
|
+
<div
|
|
264
|
+
class={['accordion', class_name].filter(Boolean).join(' ')}
|
|
265
|
+
class:dense
|
|
266
|
+
class:comfortable
|
|
267
|
+
class:filled
|
|
268
|
+
class:outline
|
|
269
|
+
class:separated
|
|
270
|
+
class:disabled
|
|
271
|
+
{id}>
|
|
272
|
+
{@render children?.()}
|
|
273
|
+
</div>
|
|
274
|
+
{/if}
|
|
275
|
+
|
|
276
|
+
<style>
|
|
277
|
+
/* ========== Accordion Container ========== */
|
|
278
|
+
.accordion {
|
|
279
|
+
width: 100%;
|
|
280
|
+
/* Flex column keeps the open-item margins additive (block-flow would
|
|
281
|
+
collapse adjacent margins), so the separation gap animates cleanly. */
|
|
282
|
+
display: flex;
|
|
283
|
+
flex-direction: column;
|
|
284
|
+
|
|
285
|
+
&.disabled {
|
|
286
|
+
opacity: 0.5;
|
|
287
|
+
pointer-events: none;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
&.skeleton {
|
|
291
|
+
pointer-events: none;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* The outline frame and filled surfaces are drawn per-item (see .item)
|
|
295
|
+
so the single frame can split into rounded pieces in separated mode. */
|
|
296
|
+
|
|
297
|
+
&.dense .skeleton-item {
|
|
298
|
+
padding: 0.5rem 0.75rem;
|
|
299
|
+
gap: 0.5rem;
|
|
300
|
+
font-size: 0.875rem;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
&.comfortable .skeleton-item {
|
|
304
|
+
padding: 1.25rem 1.5rem;
|
|
305
|
+
gap: 1rem;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* ========== AccordionItem ========== */
|
|
310
|
+
.item {
|
|
311
|
+
/* Subtle hairline separator between items (default & outline variants). */
|
|
312
|
+
border-bottom: 1px solid
|
|
313
|
+
light-dark(var(--color-border, #e5e7eb), var(--color-border, #374151));
|
|
314
|
+
perspective: 100px;
|
|
315
|
+
/* Open items glide apart; surfaces tint and corners round as the frame
|
|
316
|
+
splits into pieces (separated mode). */
|
|
317
|
+
transition:
|
|
318
|
+
margin 320ms cubic-bezier(0.23, 1, 0.32, 1),
|
|
319
|
+
border-radius 320ms cubic-bezier(0.23, 1, 0.32, 1),
|
|
320
|
+
background-color 300ms,
|
|
321
|
+
border-color 300ms;
|
|
322
|
+
|
|
323
|
+
/* The last item never draws a separator — the container edge (outline) or
|
|
324
|
+
nothing (plain/filled) closes the list. Kept as a transparent 1px so
|
|
325
|
+
every row stays the same height. */
|
|
326
|
+
&:last-child {
|
|
327
|
+
border-bottom-color: transparent;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
&.disabled {
|
|
331
|
+
opacity: 0.5;
|
|
332
|
+
pointer-events: none;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.summary {
|
|
336
|
+
display: flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
cursor: pointer;
|
|
339
|
+
padding: 1rem 1.25rem;
|
|
340
|
+
gap: 0.75rem;
|
|
341
|
+
user-select: none;
|
|
342
|
+
outline: none;
|
|
343
|
+
color: light-dark(var(--color-text, #1a1a1a), var(--color-text, #f5f5f5));
|
|
344
|
+
-webkit-tap-highlight-color: transparent;
|
|
345
|
+
transition:
|
|
346
|
+
background-color 300ms,
|
|
347
|
+
translate 200ms ease;
|
|
348
|
+
|
|
349
|
+
&:focus-visible {
|
|
350
|
+
box-shadow: inset 0 0 0 2px var(--color-accent, #1976d2);
|
|
351
|
+
border-radius: 4px;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
&:hover {
|
|
355
|
+
background: light-dark(
|
|
356
|
+
rgb(from var(--color-text, #000) r g b / 0.04),
|
|
357
|
+
rgb(from var(--color-text, #fff) r g b / 0.06)
|
|
358
|
+
);
|
|
359
|
+
transition: translate 200ms ease;
|
|
360
|
+
}
|
|
361
|
+
&:active {
|
|
362
|
+
translate: 0px 6px clamp(-7px, calc(0.2em - 6px), -2px);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
&.dense .summary {
|
|
367
|
+
padding: 0.5rem 0.75rem;
|
|
368
|
+
gap: 0.5rem;
|
|
369
|
+
font-size: 0.875rem;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
&.comfortable .summary {
|
|
373
|
+
padding: 1.25rem 1.5rem;
|
|
374
|
+
gap: 1rem;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
&.open .chevron {
|
|
378
|
+
transform: rotate(90deg);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.title {
|
|
382
|
+
flex: 1;
|
|
383
|
+
font-weight: 500;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.panel {
|
|
387
|
+
padding: 0 1.25rem 1rem;
|
|
388
|
+
color: light-dark(var(--color-text, #1a1a1a), var(--color-text, #f5f5f5));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
&.dense .panel {
|
|
392
|
+
padding: 0 0.75rem 0.5rem;
|
|
393
|
+
font-size: 0.875rem;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
&.comfortable .panel {
|
|
397
|
+
padding: 0 1.5rem 1.25rem;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* ================================================================ */
|
|
401
|
+
/* Rounded-surface variants (filled & outline) */
|
|
402
|
+
/* Both share one corner radius and keep their group's outer */
|
|
403
|
+
/* corners rounded; per-item fills/borders let the single frame */
|
|
404
|
+
/* split into rounded pieces when an item opens (separated mode). */
|
|
405
|
+
/* ================================================================ */
|
|
406
|
+
&.filled,
|
|
407
|
+
&.outline {
|
|
408
|
+
--_cr: var(--radius-lg, 10px);
|
|
409
|
+
overflow: clip;
|
|
410
|
+
|
|
411
|
+
@supports (corner-shape: squircle) {
|
|
412
|
+
corner-shape: squircle;
|
|
413
|
+
--_cr: calc(var(--radius-lg, 10px) * var(--squircle-ratio, 2));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* The group keeps rounded outer corners even while fully connected. */
|
|
417
|
+
&:first-child {
|
|
418
|
+
border-start-start-radius: var(--_cr);
|
|
419
|
+
border-start-end-radius: var(--_cr);
|
|
420
|
+
}
|
|
421
|
+
&:last-child {
|
|
422
|
+
border-end-start-radius: var(--_cr);
|
|
423
|
+
border-end-end-radius: var(--_cr);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* --- Filled — subtly tinted surfaces, hairline-separated.
|
|
428
|
+
Every item shares one fill; the open item is not tinted darker. --- */
|
|
429
|
+
&.filled {
|
|
430
|
+
background: light-dark(
|
|
431
|
+
rgb(from var(--color-text, #000) r g b / 0.04),
|
|
432
|
+
rgb(from var(--color-text, #fff) r g b / 0.05)
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* --- Outline — per-item borders that merge into one frame --- */
|
|
437
|
+
&.outline {
|
|
438
|
+
border-inline: 1px solid
|
|
439
|
+
light-dark(var(--color-border, #e5e7eb), var(--color-border, #374151));
|
|
440
|
+
}
|
|
441
|
+
/* Only the first item draws the frame's top edge while connected. */
|
|
442
|
+
&.outline:first-child {
|
|
443
|
+
border-top: 1px solid
|
|
444
|
+
light-dark(var(--color-border, #e5e7eb), var(--color-border, #374151));
|
|
445
|
+
}
|
|
446
|
+
/* The frame's bottom edge (overrides the transparent last-child separator). */
|
|
447
|
+
&.outline:last-child {
|
|
448
|
+
border-bottom-color: light-dark(
|
|
449
|
+
var(--color-border, #e5e7eb),
|
|
450
|
+
var(--color-border, #374151)
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* ================================================================ */
|
|
455
|
+
/* Separated mode — the open item splits away from the list */
|
|
456
|
+
/* ================================================================ */
|
|
457
|
+
&.separated.open {
|
|
458
|
+
margin-block: 0.625rem;
|
|
459
|
+
}
|
|
460
|
+
/* Never push the group's own outer edge — only gap toward a neighbour. */
|
|
461
|
+
&.separated.open:first-child {
|
|
462
|
+
margin-top: 0;
|
|
463
|
+
}
|
|
464
|
+
&.separated.open:last-child {
|
|
465
|
+
margin-bottom: 0;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/* The active item becomes its own fully-rounded piece. */
|
|
469
|
+
&.filled.separated.open,
|
|
470
|
+
&.outline.separated.open {
|
|
471
|
+
border-radius: var(--_cr);
|
|
472
|
+
}
|
|
473
|
+
/* Outline active closes its (now exposed) top edge. */
|
|
474
|
+
&.outline.separated.open {
|
|
475
|
+
border-top: 1px solid
|
|
476
|
+
light-dark(var(--color-border, #e5e7eb), var(--color-border, #374151));
|
|
477
|
+
}
|
|
478
|
+
/* Filled active drops the hairline that would cross its rounded bottom. */
|
|
479
|
+
&.filled.separated.open {
|
|
480
|
+
border-bottom-color: transparent;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/* The item just ABOVE the active one rounds its bottom. */
|
|
484
|
+
&.filled.separated:has(+ :global(.item.open)),
|
|
485
|
+
&.outline.separated:has(+ :global(.item.open)) {
|
|
486
|
+
border-end-start-radius: var(--_cr);
|
|
487
|
+
border-end-end-radius: var(--_cr);
|
|
488
|
+
}
|
|
489
|
+
/* Filled: drop its hairline too — the rounded edge is the boundary. */
|
|
490
|
+
&.filled.separated:has(+ :global(.item.open)) {
|
|
491
|
+
border-bottom-color: transparent;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/* The item just BELOW the active one rounds its top. */
|
|
495
|
+
&.filled.separated.open + :global(.item),
|
|
496
|
+
&.outline.separated.open + :global(.item) {
|
|
497
|
+
border-start-start-radius: var(--_cr);
|
|
498
|
+
border-start-end-radius: var(--_cr);
|
|
499
|
+
}
|
|
500
|
+
/* Outline: that lower piece needs a top edge to close it. */
|
|
501
|
+
&.outline.separated.open + :global(.item) {
|
|
502
|
+
border-top: 1px solid
|
|
503
|
+
light-dark(var(--color-border, #e5e7eb), var(--color-border, #374151));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.chevron {
|
|
508
|
+
flex-shrink: 0;
|
|
509
|
+
/* Back-out spring so the rotation overshoots slightly and settles, rather
|
|
510
|
+
than a flat ease-out. Matches the chevron flip in Button/Select/Table. */
|
|
511
|
+
transition: transform 250ms var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
|
|
512
|
+
color: light-dark(var(--color-text-disabled, #888), var(--color-text-disabled, #888));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/* ========== Skeleton ========== */
|
|
516
|
+
/* Mirrors .summary metrics (incl. dense/comfortable, nested above) so each
|
|
517
|
+
placeholder row is exactly the height of the real accordion header. */
|
|
518
|
+
.skeleton-item {
|
|
519
|
+
display: flex;
|
|
520
|
+
align-items: center;
|
|
521
|
+
gap: 0.75rem;
|
|
522
|
+
padding: 1rem 1.25rem;
|
|
523
|
+
border-bottom: 1px solid
|
|
524
|
+
light-dark(var(--color-border, #e5e7eb), var(--color-border, #374151));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.skeleton-chevron,
|
|
528
|
+
.skeleton-bar {
|
|
529
|
+
position: relative;
|
|
530
|
+
overflow: hidden;
|
|
531
|
+
background: var(--skeleton-bg, rgb(from var(--color-text, #888) r g b / 0.1));
|
|
532
|
+
|
|
533
|
+
&::after {
|
|
534
|
+
content: '';
|
|
535
|
+
position: absolute;
|
|
536
|
+
inset: 0;
|
|
537
|
+
transform: translateX(-100%);
|
|
538
|
+
background-image: linear-gradient(
|
|
539
|
+
105deg,
|
|
540
|
+
transparent 25%,
|
|
541
|
+
var(--skeleton-sheen, rgb(from var(--color-text, #888) r g b / 0.12)) 50%,
|
|
542
|
+
transparent 75%
|
|
543
|
+
);
|
|
544
|
+
animation: delight-skeleton-shimmer var(--skeleton-duration, 2.4s) ease-in-out
|
|
545
|
+
infinite;
|
|
546
|
+
animation-delay: var(--shimmer-delay, 0s);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/* The real header leads with a 16px chevron icon. */
|
|
551
|
+
.skeleton-chevron {
|
|
552
|
+
width: 16px;
|
|
553
|
+
height: 16px;
|
|
554
|
+
flex-shrink: 0;
|
|
555
|
+
border-radius: var(--radius-sm, 2px);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/* Title line — the bar's margins pad it out to one full text line (1lh)
|
|
559
|
+
so the row matches the real header's height exactly. */
|
|
560
|
+
.skeleton-bar {
|
|
561
|
+
height: 0.7em;
|
|
562
|
+
margin-block: calc((1lh - 0.7em) / 2);
|
|
563
|
+
border-radius: var(--radius-full, 1e5px);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
@keyframes -global-delight-skeleton-shimmer {
|
|
567
|
+
0% {
|
|
568
|
+
transform: translateX(-100%);
|
|
569
|
+
}
|
|
570
|
+
55%,
|
|
571
|
+
100% {
|
|
572
|
+
transform: translateX(100%);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
@media (prefers-reduced-motion: reduce) {
|
|
577
|
+
.skeleton-chevron::after,
|
|
578
|
+
.skeleton-bar::after {
|
|
579
|
+
animation: none;
|
|
580
|
+
}
|
|
581
|
+
.chevron,
|
|
582
|
+
.item {
|
|
583
|
+
transition: none;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export { default as AccordionItem } from './Accordion.svelte';
|
|
2
|
+
export interface AccordionContext {
|
|
3
|
+
/** Returns whether the item with the given value is currently expanded */
|
|
4
|
+
isOpen: (value: string) => boolean;
|
|
5
|
+
/** Expands/collapses the item with the given value */
|
|
6
|
+
toggle: (value: string) => void;
|
|
7
|
+
/** Whether the whole accordion is disabled */
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
/** Whether the accordion uses dense (compact) spacing */
|
|
10
|
+
dense: boolean;
|
|
11
|
+
/** Whether the accordion uses comfortable (roomy) spacing */
|
|
12
|
+
comfortable: boolean;
|
|
13
|
+
/** Whether items are rendered as subtly filled surfaces */
|
|
14
|
+
filled: boolean;
|
|
15
|
+
/** Whether the whole accordion is wrapped in a bordered, rounded outline */
|
|
16
|
+
outline: boolean;
|
|
17
|
+
/** Whether the open item splits away from the list with a separating gap */
|
|
18
|
+
separated: boolean;
|
|
19
|
+
}
|
|
20
|
+
import { type Snippet } from 'svelte';
|
|
21
|
+
declare const Accordion: import("svelte").Component<{
|
|
22
|
+
value?: string | string[];
|
|
23
|
+
title?: string;
|
|
24
|
+
trigger?: undefined | Snippet;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
children?: undefined | Snippet;
|
|
27
|
+
multiple?: boolean;
|
|
28
|
+
collapsible?: boolean;
|
|
29
|
+
dense?: boolean;
|
|
30
|
+
comfortable?: boolean;
|
|
31
|
+
filled?: boolean;
|
|
32
|
+
outline?: boolean;
|
|
33
|
+
separated?: boolean;
|
|
34
|
+
skeleton?: boolean;
|
|
35
|
+
skeleton_count?: number;
|
|
36
|
+
id?: string;
|
|
37
|
+
class?: string;
|
|
38
|
+
}, {}, "value">;
|
|
39
|
+
type Accordion = ReturnType<typeof Accordion>;
|
|
40
|
+
export default Accordion;
|
|
41
|
+
//# sourceMappingURL=Accordion.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Accordion.svelte.d.ts","sourceRoot":"","sources":["../../src/display/Accordion.svelte.ts"],"names":[],"mappings":"AAGC,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAChC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,sDAAsD;IACtD,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,6DAA6D;IAC7D,WAAW,EAAE,OAAO,CAAC;IACrB,2DAA2D;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAC;CACnB;AAGF,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAiO9D,QAAA,MAAM,SAAS;YA1NkE,MAAM,GAAG,MAAM,EAAE;YAAU,MAAM;cAAY,SAAS,GAAG,OAAO;eAAa,OAAO;eAAa,SAAS,GAAG,OAAO;eAAa,OAAO;kBAAgB,OAAO;YAAU,OAAO;kBAAgB,OAAO;aAAW,OAAO;cAAY,OAAO;gBAAc,OAAO;eAAa,OAAO;qBAAmB,MAAM;;YAA8B,MAAM;eA0N5W,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|