compote-ui 0.80.0 → 0.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/data-table-v9/column-filter-kind.d.ts +10 -1
- package/dist/components/data-table-v9/column-filter-kind.js +7 -0
- package/dist/components/data-table-v9/data-table-head.svelte +230 -230
- package/dist/components/data-table-v9/data-table.svelte +154 -154
- package/dist/components/data-table-v9/filter-editors/boolean-filter-editor.svelte +45 -45
- package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte +39 -33
- package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte.d.ts +7 -2
- package/dist/components/data-table-v9/filter-editors/date-range-filter-editor.svelte +52 -52
- package/dist/components/data-table-v9/filter-editors/range-filter-editor.svelte +51 -51
- package/dist/components/data-table-v9/filter-editors/select-filter-editor.svelte +59 -59
- package/dist/components/data-table-v9/filter-editors/text-filter-editor.svelte +20 -20
- package/dist/components/data-table-v9/header/column-header-filter.svelte +66 -66
- package/dist/components/data-table-v9/index.d.ts +9 -1
- package/dist/components/data-table-v9/index.js +7 -0
- package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte +203 -203
- package/dist/components/data-table-v9/types.d.ts +3 -1
- package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte +82 -82
- package/dist/components/data-table-v9/virtual/index.d.ts +2 -2
- package/dist/components/data-table-v9/virtual/index.js +1 -1
- package/dist/components/dialog/alert-dialog.svelte +73 -73
- package/dist/components/dialog/dialog-root.svelte +45 -45
- package/dist/components/drawer/drawer-content.svelte +213 -213
- package/dist/components/popover/popover-content.svelte +97 -97
- package/dist/components/popover/popover-description.svelte +19 -19
- package/dist/components/popover/popover-root.svelte +27 -27
- package/dist/components/popover/popover-title.svelte +19 -19
- package/dist/icons/PhFunnelFill.svelte +19 -19
- package/package.json +1 -1
- package/skills/component-usage/references/overlays-and-floating-ui.md +278 -278
- package/skills/data-table/SKILL.md +362 -314
- package/skills/data-table/references/column-options.md +175 -175
- package/skills/data-table/references/table-state-and-reactivity.md +65 -65
|
@@ -1,278 +1,278 @@
|
|
|
1
|
-
# Overlays And Floating UI
|
|
2
|
-
|
|
3
|
-
`Dialog`, `Drawer`, `Menu`, `Popover`, `HoverCard`, `Tooltip`, and `Toast` are namespace exports.
|
|
4
|
-
`AlertDialog` is a single component, not a namespace.
|
|
5
|
-
|
|
6
|
-
## Dialog
|
|
7
|
-
|
|
8
|
-
```svelte
|
|
9
|
-
<script lang="ts">
|
|
10
|
-
let open = $state(false);
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<Dialog.Root bind:open>
|
|
14
|
-
<Dialog.Title>Confirm Action</Dialog.Title>
|
|
15
|
-
<Dialog.Description>This cannot be undone.</Dialog.Description>
|
|
16
|
-
<Dialog.Footer>
|
|
17
|
-
<Dialog.CloseTrigger>Cancel</Dialog.CloseTrigger>
|
|
18
|
-
<Button onclick={() => (open = false)}>Confirm</Button>
|
|
19
|
-
</Dialog.Footer>
|
|
20
|
-
<Dialog.CloseTrigger />
|
|
21
|
-
</Dialog.Root>
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Use `onOpenChange`, not `onClose` — `Dialog` has no `onClose` prop:
|
|
25
|
-
|
|
26
|
-
```svelte
|
|
27
|
-
<Dialog.Root
|
|
28
|
-
bind:open
|
|
29
|
-
onOpenChange={(details) => {
|
|
30
|
-
if (!details.open) handleClose();
|
|
31
|
-
}}
|
|
32
|
-
>
|
|
33
|
-
<Dialog.Title>Title</Dialog.Title>
|
|
34
|
-
</Dialog.Root>
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
`Dialog.CloseTrigger` with no children renders an absolute-positioned X icon in the corner
|
|
38
|
-
automatically — no separate placement needed. With children, it renders as an inline button (for
|
|
39
|
-
`Dialog.Footer`). `contentClass` sets dialog width (e.g. `contentClass="max-w-4xl"`).
|
|
40
|
-
|
|
41
|
-
**Stacking:** z-index defaults to `50`. Set the `--layer-index` CSS variable on the dialog's
|
|
42
|
-
container to offset it (e.g. `style="--layer-index: 10"` → z-index 60) — use this when a dialog
|
|
43
|
-
must appear above another fixed element like a drawer.
|
|
44
|
-
|
|
45
|
-
## Drawer
|
|
46
|
-
|
|
47
|
-
Slide-in panel anchored to a viewport edge, with swipe-to-dismiss and snap points.
|
|
48
|
-
`Drawer.Content` renders the backdrop and positioner internally — compose only
|
|
49
|
-
`Header`/`Body`/`Footer`.
|
|
50
|
-
|
|
51
|
-
```svelte
|
|
52
|
-
<Drawer.Root bind:open>
|
|
53
|
-
<Drawer.Content>
|
|
54
|
-
<Drawer.CloseTrigger />
|
|
55
|
-
<Drawer.Header>
|
|
56
|
-
<Drawer.Title>Edit Record</Drawer.Title>
|
|
57
|
-
</Drawer.Header>
|
|
58
|
-
<Drawer.Body>Scrollable content</Drawer.Body>
|
|
59
|
-
<Drawer.Footer>
|
|
60
|
-
<Button variant="ghost" onclick={() => (open = false)}>Cancel</Button>
|
|
61
|
-
<Button>Save</Button>
|
|
62
|
-
</Drawer.Footer>
|
|
63
|
-
</Drawer.Content>
|
|
64
|
-
</Drawer.Root>
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
`swipeDirection?: 'up' | 'down' | 'start' | 'end'` (default `'down'`) controls which edge it slides
|
|
68
|
-
from: `'down'` = bottom sheet (default), `'up'` = top, `'start'` = left (LTR), `'end'` = right
|
|
69
|
-
(LTR). `Drawer.Body` scrolls internally via `ScrollArea` — no fixed height needed. Safe to open a
|
|
70
|
-
`Dialog` from inside a `Drawer` (it portals above it, same z-index, stacked by DOM order).
|
|
71
|
-
|
|
72
|
-
Sizing and styling overrides:
|
|
73
|
-
|
|
74
|
-
```svelte
|
|
75
|
-
<!-- Custom height (bottom/top drawers, default 96svh) -->
|
|
76
|
-
<Drawer.Content maxHeight="50vh">...</Drawer.Content>
|
|
77
|
-
|
|
78
|
-
<!-- Custom width (side drawers, default 25rem) -->
|
|
79
|
-
<Drawer.Content maxWidth="32rem">...</Drawer.Content>
|
|
80
|
-
|
|
81
|
-
<!-- Custom backdrop/positioner classes (power users) -->
|
|
82
|
-
<Drawer.Content backdropClass="bg-black/80" positionerClass="items-center">...</Drawer.Content>
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
`Drawer.Grabber`/`Drawer.GrabberIndicator` render a drag handle (top edge for bottom/top drawers,
|
|
86
|
-
open edge for side drawers) — repositions automatically per `swipeDirection`.
|
|
87
|
-
|
|
88
|
-
## AlertDialog
|
|
89
|
-
|
|
90
|
-
For confirmations — built-in confirm/cancel buttons, no custom body.
|
|
91
|
-
|
|
92
|
-
```svelte
|
|
93
|
-
<AlertDialog
|
|
94
|
-
bind:open={deleteOpen}
|
|
95
|
-
title="Delete item?"
|
|
96
|
-
description="This action cannot be undone."
|
|
97
|
-
variant="destructive"
|
|
98
|
-
confirmLabel="Delete"
|
|
99
|
-
onConfirm={handleDelete}
|
|
100
|
-
/>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Props: `open` (bindable), `title`, `description?: string | string[]`,
|
|
104
|
-
`variant?: 'default' | 'destructive'`, `confirmLabel?`, `cancelLabel?`, `onConfirm?`, `onCancel?`.
|
|
105
|
-
|
|
106
|
-
## Menu
|
|
107
|
-
|
|
108
|
-
Composable dropdown with items, groups, checkboxes, radio items, context trigger, and submenus.
|
|
109
|
-
|
|
110
|
-
```svelte
|
|
111
|
-
<Menu.Root>
|
|
112
|
-
<Menu.Trigger variant="outline">
|
|
113
|
-
Options
|
|
114
|
-
<Menu.Indicator />
|
|
115
|
-
</Menu.Trigger>
|
|
116
|
-
<Menu.Content>
|
|
117
|
-
<Menu.Item value="new">New File</Menu.Item>
|
|
118
|
-
<Menu.Item value="save">Save</Menu.Item>
|
|
119
|
-
<Menu.Separator />
|
|
120
|
-
<Menu.Item value="quit" disabled>Quit</Menu.Item>
|
|
121
|
-
</Menu.Content>
|
|
122
|
-
</Menu.Root>
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Groups, checkboxes, and radio items:
|
|
126
|
-
|
|
127
|
-
```svelte
|
|
128
|
-
<Menu.Content>
|
|
129
|
-
<Menu.ItemGroup>
|
|
130
|
-
<Menu.ItemGroupLabel>View</Menu.ItemGroupLabel>
|
|
131
|
-
<Menu.CheckboxItem value="sidebar" checked={sidebar} onCheckedChange={(v) => (sidebar = v)}>
|
|
132
|
-
Show Sidebar
|
|
133
|
-
</Menu.CheckboxItem>
|
|
134
|
-
</Menu.ItemGroup>
|
|
135
|
-
<Menu.RadioItemGroup value={theme} onValueChange={(d) => (theme = d.value)}>
|
|
136
|
-
<Menu.RadioItem value="light">Light</Menu.RadioItem>
|
|
137
|
-
<Menu.RadioItem value="dark">Dark</Menu.RadioItem>
|
|
138
|
-
</Menu.RadioItemGroup>
|
|
139
|
-
</Menu.Content>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Right-click context menu — use `Menu.ContextTrigger` instead of `Menu.Trigger`:
|
|
143
|
-
|
|
144
|
-
```svelte
|
|
145
|
-
<Menu.Root>
|
|
146
|
-
<Menu.ContextTrigger>
|
|
147
|
-
<div class="rounded border p-8 text-center">Right-click here</div>
|
|
148
|
-
</Menu.ContextTrigger>
|
|
149
|
-
<Menu.Content>
|
|
150
|
-
<Menu.Item value="copy">Copy</Menu.Item>
|
|
151
|
-
</Menu.Content>
|
|
152
|
-
</Menu.Root>
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Submenu — nest a `Menu.Root` after a `Menu.TriggerItem`:
|
|
156
|
-
|
|
157
|
-
```svelte
|
|
158
|
-
<Menu.Content>
|
|
159
|
-
<Menu.TriggerItem>Export as...</Menu.TriggerItem>
|
|
160
|
-
<Menu.Root>
|
|
161
|
-
<Menu.Content>
|
|
162
|
-
<Menu.Item value="pdf">PDF</Menu.Item>
|
|
163
|
-
<Menu.Item value="csv">CSV</Menu.Item>
|
|
164
|
-
</Menu.Content>
|
|
165
|
-
</Menu.Root>
|
|
166
|
-
</Menu.Content>
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## Popover
|
|
170
|
-
|
|
171
|
-
Composable floating panel anchored to a trigger.
|
|
172
|
-
|
|
173
|
-
```svelte
|
|
174
|
-
<Popover.Root>
|
|
175
|
-
<Popover.Trigger>
|
|
176
|
-
<Button>Open Popover</Button>
|
|
177
|
-
</Popover.Trigger>
|
|
178
|
-
<Popover.Content>
|
|
179
|
-
<Popover.Title>Popover Title</Popover.Title>
|
|
180
|
-
<Popover.Description>Content here.</Popover.Description>
|
|
181
|
-
<Popover.CloseTrigger />
|
|
182
|
-
</Popover.Content>
|
|
183
|
-
</Popover.Root>
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
`Popover.Content` accepts `showArrow?: boolean` (default `true`) and forwards other props to Ark's
|
|
187
|
-
`Popover.Content`. Control placement via `<Popover.Root positioning={{ placement: 'right' }}>`.
|
|
188
|
-
|
|
189
|
-
The dialog is labelled automatically: while a `Popover.Title` / `Popover.Description` is rendered
|
|
190
|
-
inside, `Popover.Content` gets `aria-labelledby` / `aria-describedby` pointing at it — no `ids` or
|
|
191
|
-
manual `aria-*` needed (Zag alone misses them because content mounts lazily). An explicit
|
|
192
|
-
`aria-labelledby` / `aria-describedby` (or `aria-label`, for the title) on `Popover.Content` wins.
|
|
193
|
-
|
|
194
|
-
## HoverCard
|
|
195
|
-
|
|
196
|
-
Floating card that opens on **hover**, not click — key difference from `Popover`. Use `asChild` on
|
|
197
|
-
the trigger to render any element (e.g. a link) instead of the default button.
|
|
198
|
-
|
|
199
|
-
```svelte
|
|
200
|
-
<HoverCard.Root>
|
|
201
|
-
<p>
|
|
202
|
-
Liked by
|
|
203
|
-
<HoverCard.Trigger>
|
|
204
|
-
{#snippet asChild(props)}
|
|
205
|
-
<a href="/profile" {...props()} class="font-medium text-primary underline"> @sarah_chen </a>
|
|
206
|
-
{/snippet}
|
|
207
|
-
</HoverCard.Trigger>
|
|
208
|
-
</p>
|
|
209
|
-
<HoverCard.Content>
|
|
210
|
-
<p class="text-sm text-ink">Bio text here.</p>
|
|
211
|
-
</HoverCard.Content>
|
|
212
|
-
</HoverCard.Root>
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
`openDelay?: number` (default `600`), `closeDelay?: number` (default `300`) on `HoverCard.Root`.
|
|
216
|
-
|
|
217
|
-
## Tooltip
|
|
218
|
-
|
|
219
|
-
Namespace export wrapping Ark UI Tooltip — short text hint shown on hover/focus.
|
|
220
|
-
|
|
221
|
-
```svelte
|
|
222
|
-
<Tooltip.Root>
|
|
223
|
-
<Tooltip.Trigger>
|
|
224
|
-
<Button variant="ghost" size="icon" aria-label="Info"><PhInfo /></Button>
|
|
225
|
-
</Tooltip.Trigger>
|
|
226
|
-
<Tooltip.Content>More information</Tooltip.Content>
|
|
227
|
-
</Tooltip.Root>
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
Prefer `Tooltip` over `HoverCard` for a single line of supplementary text; use `HoverCard` for
|
|
231
|
-
richer content (profile previews, formatted descriptions).
|
|
232
|
-
|
|
233
|
-
## Toast
|
|
234
|
-
|
|
235
|
-
Toaster setup belongs once in the root layout:
|
|
236
|
-
|
|
237
|
-
```svelte
|
|
238
|
-
<!-- +layout.svelte -->
|
|
239
|
-
<Toast.Toaster />
|
|
240
|
-
{@render children()}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
Then fire toasts anywhere:
|
|
244
|
-
|
|
245
|
-
```ts
|
|
246
|
-
import { toast } from 'compote-ui';
|
|
247
|
-
|
|
248
|
-
toast.success('Saved');
|
|
249
|
-
toast.error('Save failed', { description: 'Please try again.' });
|
|
250
|
-
toast.promise(saveData(), {
|
|
251
|
-
loading: { title: 'Saving…' },
|
|
252
|
-
success: { title: 'Saved' },
|
|
253
|
-
error: { title: 'Save failed' }
|
|
254
|
-
});
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
Shorthand helpers: `toast.info()`, `toast.success()`, `toast.warning()`, `toast.error()`,
|
|
258
|
-
`toast.loading()` — first arg is the title, second an optional options object; each returns the
|
|
259
|
-
toast `id` usable with `toast.update(id, options)` / `toast.dismiss(id)`. `loading` shows a
|
|
260
|
-
spinner and does not auto-dismiss. `toast.create(options)` remains available for full control.
|
|
261
|
-
|
|
262
|
-
Action button (e.g. Undo):
|
|
263
|
-
|
|
264
|
-
```ts
|
|
265
|
-
toast.create({
|
|
266
|
-
title: 'File deleted',
|
|
267
|
-
type: 'info',
|
|
268
|
-
action: { label: 'Undo', onClick: () => restore() }
|
|
269
|
-
});
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
`toast.create()` options: `title: string`, `description?: string`,
|
|
273
|
-
`type?: 'info' | 'success' | 'error' | 'warning' | 'loading'`, `duration?: number` (ms, overrides
|
|
274
|
-
the toaster default for this toast), `action?: { label: string; onClick: () => void }`.
|
|
275
|
-
|
|
276
|
-
`Toast.Toaster` props: `class?: ClassValue`, `toaster?: CreateToasterReturn` (a custom instance
|
|
277
|
-
from `createToaster()` for a different `placement`/`max`/`duration` — defaults to the shared
|
|
278
|
-
`toast` singleton). Default placement is `bottom-end`; timers pause while the tab is hidden.
|
|
1
|
+
# Overlays And Floating UI
|
|
2
|
+
|
|
3
|
+
`Dialog`, `Drawer`, `Menu`, `Popover`, `HoverCard`, `Tooltip`, and `Toast` are namespace exports.
|
|
4
|
+
`AlertDialog` is a single component, not a namespace.
|
|
5
|
+
|
|
6
|
+
## Dialog
|
|
7
|
+
|
|
8
|
+
```svelte
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
let open = $state(false);
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Dialog.Root bind:open>
|
|
14
|
+
<Dialog.Title>Confirm Action</Dialog.Title>
|
|
15
|
+
<Dialog.Description>This cannot be undone.</Dialog.Description>
|
|
16
|
+
<Dialog.Footer>
|
|
17
|
+
<Dialog.CloseTrigger>Cancel</Dialog.CloseTrigger>
|
|
18
|
+
<Button onclick={() => (open = false)}>Confirm</Button>
|
|
19
|
+
</Dialog.Footer>
|
|
20
|
+
<Dialog.CloseTrigger />
|
|
21
|
+
</Dialog.Root>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Use `onOpenChange`, not `onClose` — `Dialog` has no `onClose` prop:
|
|
25
|
+
|
|
26
|
+
```svelte
|
|
27
|
+
<Dialog.Root
|
|
28
|
+
bind:open
|
|
29
|
+
onOpenChange={(details) => {
|
|
30
|
+
if (!details.open) handleClose();
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
34
|
+
</Dialog.Root>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`Dialog.CloseTrigger` with no children renders an absolute-positioned X icon in the corner
|
|
38
|
+
automatically — no separate placement needed. With children, it renders as an inline button (for
|
|
39
|
+
`Dialog.Footer`). `contentClass` sets dialog width (e.g. `contentClass="max-w-4xl"`).
|
|
40
|
+
|
|
41
|
+
**Stacking:** z-index defaults to `50`. Set the `--layer-index` CSS variable on the dialog's
|
|
42
|
+
container to offset it (e.g. `style="--layer-index: 10"` → z-index 60) — use this when a dialog
|
|
43
|
+
must appear above another fixed element like a drawer.
|
|
44
|
+
|
|
45
|
+
## Drawer
|
|
46
|
+
|
|
47
|
+
Slide-in panel anchored to a viewport edge, with swipe-to-dismiss and snap points.
|
|
48
|
+
`Drawer.Content` renders the backdrop and positioner internally — compose only
|
|
49
|
+
`Header`/`Body`/`Footer`.
|
|
50
|
+
|
|
51
|
+
```svelte
|
|
52
|
+
<Drawer.Root bind:open>
|
|
53
|
+
<Drawer.Content>
|
|
54
|
+
<Drawer.CloseTrigger />
|
|
55
|
+
<Drawer.Header>
|
|
56
|
+
<Drawer.Title>Edit Record</Drawer.Title>
|
|
57
|
+
</Drawer.Header>
|
|
58
|
+
<Drawer.Body>Scrollable content</Drawer.Body>
|
|
59
|
+
<Drawer.Footer>
|
|
60
|
+
<Button variant="ghost" onclick={() => (open = false)}>Cancel</Button>
|
|
61
|
+
<Button>Save</Button>
|
|
62
|
+
</Drawer.Footer>
|
|
63
|
+
</Drawer.Content>
|
|
64
|
+
</Drawer.Root>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`swipeDirection?: 'up' | 'down' | 'start' | 'end'` (default `'down'`) controls which edge it slides
|
|
68
|
+
from: `'down'` = bottom sheet (default), `'up'` = top, `'start'` = left (LTR), `'end'` = right
|
|
69
|
+
(LTR). `Drawer.Body` scrolls internally via `ScrollArea` — no fixed height needed. Safe to open a
|
|
70
|
+
`Dialog` from inside a `Drawer` (it portals above it, same z-index, stacked by DOM order).
|
|
71
|
+
|
|
72
|
+
Sizing and styling overrides:
|
|
73
|
+
|
|
74
|
+
```svelte
|
|
75
|
+
<!-- Custom height (bottom/top drawers, default 96svh) -->
|
|
76
|
+
<Drawer.Content maxHeight="50vh">...</Drawer.Content>
|
|
77
|
+
|
|
78
|
+
<!-- Custom width (side drawers, default 25rem) -->
|
|
79
|
+
<Drawer.Content maxWidth="32rem">...</Drawer.Content>
|
|
80
|
+
|
|
81
|
+
<!-- Custom backdrop/positioner classes (power users) -->
|
|
82
|
+
<Drawer.Content backdropClass="bg-black/80" positionerClass="items-center">...</Drawer.Content>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`Drawer.Grabber`/`Drawer.GrabberIndicator` render a drag handle (top edge for bottom/top drawers,
|
|
86
|
+
open edge for side drawers) — repositions automatically per `swipeDirection`.
|
|
87
|
+
|
|
88
|
+
## AlertDialog
|
|
89
|
+
|
|
90
|
+
For confirmations — built-in confirm/cancel buttons, no custom body.
|
|
91
|
+
|
|
92
|
+
```svelte
|
|
93
|
+
<AlertDialog
|
|
94
|
+
bind:open={deleteOpen}
|
|
95
|
+
title="Delete item?"
|
|
96
|
+
description="This action cannot be undone."
|
|
97
|
+
variant="destructive"
|
|
98
|
+
confirmLabel="Delete"
|
|
99
|
+
onConfirm={handleDelete}
|
|
100
|
+
/>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Props: `open` (bindable), `title`, `description?: string | string[]`,
|
|
104
|
+
`variant?: 'default' | 'destructive'`, `confirmLabel?`, `cancelLabel?`, `onConfirm?`, `onCancel?`.
|
|
105
|
+
|
|
106
|
+
## Menu
|
|
107
|
+
|
|
108
|
+
Composable dropdown with items, groups, checkboxes, radio items, context trigger, and submenus.
|
|
109
|
+
|
|
110
|
+
```svelte
|
|
111
|
+
<Menu.Root>
|
|
112
|
+
<Menu.Trigger variant="outline">
|
|
113
|
+
Options
|
|
114
|
+
<Menu.Indicator />
|
|
115
|
+
</Menu.Trigger>
|
|
116
|
+
<Menu.Content>
|
|
117
|
+
<Menu.Item value="new">New File</Menu.Item>
|
|
118
|
+
<Menu.Item value="save">Save</Menu.Item>
|
|
119
|
+
<Menu.Separator />
|
|
120
|
+
<Menu.Item value="quit" disabled>Quit</Menu.Item>
|
|
121
|
+
</Menu.Content>
|
|
122
|
+
</Menu.Root>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Groups, checkboxes, and radio items:
|
|
126
|
+
|
|
127
|
+
```svelte
|
|
128
|
+
<Menu.Content>
|
|
129
|
+
<Menu.ItemGroup>
|
|
130
|
+
<Menu.ItemGroupLabel>View</Menu.ItemGroupLabel>
|
|
131
|
+
<Menu.CheckboxItem value="sidebar" checked={sidebar} onCheckedChange={(v) => (sidebar = v)}>
|
|
132
|
+
Show Sidebar
|
|
133
|
+
</Menu.CheckboxItem>
|
|
134
|
+
</Menu.ItemGroup>
|
|
135
|
+
<Menu.RadioItemGroup value={theme} onValueChange={(d) => (theme = d.value)}>
|
|
136
|
+
<Menu.RadioItem value="light">Light</Menu.RadioItem>
|
|
137
|
+
<Menu.RadioItem value="dark">Dark</Menu.RadioItem>
|
|
138
|
+
</Menu.RadioItemGroup>
|
|
139
|
+
</Menu.Content>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Right-click context menu — use `Menu.ContextTrigger` instead of `Menu.Trigger`:
|
|
143
|
+
|
|
144
|
+
```svelte
|
|
145
|
+
<Menu.Root>
|
|
146
|
+
<Menu.ContextTrigger>
|
|
147
|
+
<div class="rounded border p-8 text-center">Right-click here</div>
|
|
148
|
+
</Menu.ContextTrigger>
|
|
149
|
+
<Menu.Content>
|
|
150
|
+
<Menu.Item value="copy">Copy</Menu.Item>
|
|
151
|
+
</Menu.Content>
|
|
152
|
+
</Menu.Root>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Submenu — nest a `Menu.Root` after a `Menu.TriggerItem`:
|
|
156
|
+
|
|
157
|
+
```svelte
|
|
158
|
+
<Menu.Content>
|
|
159
|
+
<Menu.TriggerItem>Export as...</Menu.TriggerItem>
|
|
160
|
+
<Menu.Root>
|
|
161
|
+
<Menu.Content>
|
|
162
|
+
<Menu.Item value="pdf">PDF</Menu.Item>
|
|
163
|
+
<Menu.Item value="csv">CSV</Menu.Item>
|
|
164
|
+
</Menu.Content>
|
|
165
|
+
</Menu.Root>
|
|
166
|
+
</Menu.Content>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Popover
|
|
170
|
+
|
|
171
|
+
Composable floating panel anchored to a trigger.
|
|
172
|
+
|
|
173
|
+
```svelte
|
|
174
|
+
<Popover.Root>
|
|
175
|
+
<Popover.Trigger>
|
|
176
|
+
<Button>Open Popover</Button>
|
|
177
|
+
</Popover.Trigger>
|
|
178
|
+
<Popover.Content>
|
|
179
|
+
<Popover.Title>Popover Title</Popover.Title>
|
|
180
|
+
<Popover.Description>Content here.</Popover.Description>
|
|
181
|
+
<Popover.CloseTrigger />
|
|
182
|
+
</Popover.Content>
|
|
183
|
+
</Popover.Root>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`Popover.Content` accepts `showArrow?: boolean` (default `true`) and forwards other props to Ark's
|
|
187
|
+
`Popover.Content`. Control placement via `<Popover.Root positioning={{ placement: 'right' }}>`.
|
|
188
|
+
|
|
189
|
+
The dialog is labelled automatically: while a `Popover.Title` / `Popover.Description` is rendered
|
|
190
|
+
inside, `Popover.Content` gets `aria-labelledby` / `aria-describedby` pointing at it — no `ids` or
|
|
191
|
+
manual `aria-*` needed (Zag alone misses them because content mounts lazily). An explicit
|
|
192
|
+
`aria-labelledby` / `aria-describedby` (or `aria-label`, for the title) on `Popover.Content` wins.
|
|
193
|
+
|
|
194
|
+
## HoverCard
|
|
195
|
+
|
|
196
|
+
Floating card that opens on **hover**, not click — key difference from `Popover`. Use `asChild` on
|
|
197
|
+
the trigger to render any element (e.g. a link) instead of the default button.
|
|
198
|
+
|
|
199
|
+
```svelte
|
|
200
|
+
<HoverCard.Root>
|
|
201
|
+
<p>
|
|
202
|
+
Liked by
|
|
203
|
+
<HoverCard.Trigger>
|
|
204
|
+
{#snippet asChild(props)}
|
|
205
|
+
<a href="/profile" {...props()} class="font-medium text-primary underline"> @sarah_chen </a>
|
|
206
|
+
{/snippet}
|
|
207
|
+
</HoverCard.Trigger>
|
|
208
|
+
</p>
|
|
209
|
+
<HoverCard.Content>
|
|
210
|
+
<p class="text-sm text-ink">Bio text here.</p>
|
|
211
|
+
</HoverCard.Content>
|
|
212
|
+
</HoverCard.Root>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
`openDelay?: number` (default `600`), `closeDelay?: number` (default `300`) on `HoverCard.Root`.
|
|
216
|
+
|
|
217
|
+
## Tooltip
|
|
218
|
+
|
|
219
|
+
Namespace export wrapping Ark UI Tooltip — short text hint shown on hover/focus.
|
|
220
|
+
|
|
221
|
+
```svelte
|
|
222
|
+
<Tooltip.Root>
|
|
223
|
+
<Tooltip.Trigger>
|
|
224
|
+
<Button variant="ghost" size="icon" aria-label="Info"><PhInfo /></Button>
|
|
225
|
+
</Tooltip.Trigger>
|
|
226
|
+
<Tooltip.Content>More information</Tooltip.Content>
|
|
227
|
+
</Tooltip.Root>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Prefer `Tooltip` over `HoverCard` for a single line of supplementary text; use `HoverCard` for
|
|
231
|
+
richer content (profile previews, formatted descriptions).
|
|
232
|
+
|
|
233
|
+
## Toast
|
|
234
|
+
|
|
235
|
+
Toaster setup belongs once in the root layout:
|
|
236
|
+
|
|
237
|
+
```svelte
|
|
238
|
+
<!-- +layout.svelte -->
|
|
239
|
+
<Toast.Toaster />
|
|
240
|
+
{@render children()}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Then fire toasts anywhere:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
import { toast } from 'compote-ui';
|
|
247
|
+
|
|
248
|
+
toast.success('Saved');
|
|
249
|
+
toast.error('Save failed', { description: 'Please try again.' });
|
|
250
|
+
toast.promise(saveData(), {
|
|
251
|
+
loading: { title: 'Saving…' },
|
|
252
|
+
success: { title: 'Saved' },
|
|
253
|
+
error: { title: 'Save failed' }
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Shorthand helpers: `toast.info()`, `toast.success()`, `toast.warning()`, `toast.error()`,
|
|
258
|
+
`toast.loading()` — first arg is the title, second an optional options object; each returns the
|
|
259
|
+
toast `id` usable with `toast.update(id, options)` / `toast.dismiss(id)`. `loading` shows a
|
|
260
|
+
spinner and does not auto-dismiss. `toast.create(options)` remains available for full control.
|
|
261
|
+
|
|
262
|
+
Action button (e.g. Undo):
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
toast.create({
|
|
266
|
+
title: 'File deleted',
|
|
267
|
+
type: 'info',
|
|
268
|
+
action: { label: 'Undo', onClick: () => restore() }
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
`toast.create()` options: `title: string`, `description?: string`,
|
|
273
|
+
`type?: 'info' | 'success' | 'error' | 'warning' | 'loading'`, `duration?: number` (ms, overrides
|
|
274
|
+
the toaster default for this toast), `action?: { label: string; onClick: () => void }`.
|
|
275
|
+
|
|
276
|
+
`Toast.Toaster` props: `class?: ClassValue`, `toaster?: CreateToasterReturn` (a custom instance
|
|
277
|
+
from `createToaster()` for a different `placement`/`max`/`duration` — defaults to the shared
|
|
278
|
+
`toast` singleton). Default placement is `bottom-end`; timers pause while the tab is hidden.
|