compote-ui 0.31.1 → 0.33.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.
Files changed (60) hide show
  1. package/dist/components/checkbox/checkbox.svelte +34 -9
  2. package/dist/components/checkbox/checkbox.types.d.ts +5 -2
  3. package/dist/components/data-table/core/cells.d.ts +78 -0
  4. package/dist/components/data-table/core/cells.js +66 -0
  5. package/dist/components/data-table/core/create-table.svelte.d.ts +24 -0
  6. package/dist/components/data-table/core/create-table.svelte.js +74 -0
  7. package/dist/components/data-table/core/index.d.ts +3 -0
  8. package/dist/components/data-table/core/index.js +2 -0
  9. package/dist/components/data-table/data-table-column-visibility.svelte +79 -0
  10. package/dist/components/data-table/data-table-column-visibility.svelte.d.ts +29 -0
  11. package/dist/components/data-table/data-table-filters.svelte +285 -0
  12. package/dist/components/data-table/data-table-filters.svelte.d.ts +29 -0
  13. package/dist/components/data-table/data-table-title.svelte +16 -0
  14. package/dist/components/data-table/data-table-title.svelte.d.ts +10 -0
  15. package/dist/components/data-table/data-table-toolbar.svelte +16 -0
  16. package/dist/components/data-table/data-table-toolbar.svelte.d.ts +10 -0
  17. package/dist/components/data-table/data-table.svelte +342 -0
  18. package/dist/components/data-table/data-table.svelte.d.ts +32 -0
  19. package/dist/components/data-table/index.d.ts +7 -0
  20. package/dist/components/data-table/index.js +7 -0
  21. package/dist/components/field/field-input.svelte +8 -6
  22. package/dist/components/number-input/number-input.svelte +3 -0
  23. package/dist/components/popover/index.d.ts +6 -0
  24. package/dist/components/popover/index.js +6 -0
  25. package/dist/components/popover/popover-close-trigger.svelte +25 -0
  26. package/dist/components/popover/popover-close-trigger.svelte.d.ts +8 -0
  27. package/dist/components/popover/popover-content.svelte +71 -0
  28. package/dist/components/popover/popover-content.svelte.d.ts +10 -0
  29. package/dist/components/popover/popover-description.svelte +15 -0
  30. package/dist/components/popover/popover-description.svelte.d.ts +8 -0
  31. package/dist/components/popover/popover-root.svelte +24 -0
  32. package/dist/components/popover/popover-root.svelte.d.ts +11 -0
  33. package/dist/components/popover/popover-title.svelte +15 -0
  34. package/dist/components/popover/popover-title.svelte.d.ts +8 -0
  35. package/dist/components/popover/popover-trigger.svelte +17 -0
  36. package/dist/components/popover/popover-trigger.svelte.d.ts +10 -0
  37. package/dist/components/scroll-area/scroll-area-content.svelte +1 -1
  38. package/dist/components/toggle/toggle.svelte +17 -0
  39. package/dist/components/toggle/toggle.svelte.d.ts +4 -0
  40. package/dist/components/toggle/toggle.variants.d.ts +21 -0
  41. package/dist/components/toggle/toggle.variants.js +12 -0
  42. package/dist/components/toggle/types.d.ts +8 -0
  43. package/dist/components/toggle/types.js +1 -0
  44. package/dist/components/toggle-group/toggle-group-context.d.ts +8 -0
  45. package/dist/components/toggle-group/toggle-group-context.js +2 -0
  46. package/dist/components/toggle-group/toggle-group-item.svelte +7 -6
  47. package/dist/components/toggle-group/toggle-group-item.svelte.d.ts +2 -0
  48. package/dist/components/toggle-group/toggle-group.svelte +17 -2
  49. package/dist/components/toggle-group/toggle-group.svelte.d.ts +2 -0
  50. package/dist/components/tooltip/tooltip-trigger.svelte +2 -4
  51. package/dist/components/tooltip/tooltip-trigger.svelte.d.ts +2 -4
  52. package/dist/components/tree-view/tree-view.svelte +1 -1
  53. package/dist/icons/PhArrowSquareOut.svelte +18 -0
  54. package/dist/icons/PhArrowSquareOut.svelte.d.ts +5 -0
  55. package/dist/icons/index.d.ts +1 -0
  56. package/dist/icons/index.js +1 -0
  57. package/dist/index.d.ts +3 -0
  58. package/dist/index.js +2 -0
  59. package/dist/theme.css +1 -1
  60. package/package.json +12 -1
@@ -0,0 +1,342 @@
1
+ <script lang="ts" generics="TData extends RowData, TSelected = object">
2
+ import { useLocaleContext } from '@ark-ui/svelte/locale';
3
+ import { FlexRender } from '@tanstack/svelte-table';
4
+ import { cn, type ClassValue } from 'tailwind-variants';
5
+ import { PhArrowSquareOut, PhCaretDown, PhCaretUp } from '../../icons';
6
+ import Checkbox from '../checkbox/checkbox.svelte';
7
+ import type { HTMLAttributes } from 'svelte/elements';
8
+ import type { Header, RowData } from '@tanstack/svelte-table';
9
+ import {
10
+ getDataTableCellConfig,
11
+ hasCustomDataTableCell,
12
+ type DataTable,
13
+ type DataTableCell,
14
+ type DataTableCellConfig,
15
+ type DataTableColumnAlign,
16
+ type DataTableColumnMeta,
17
+ type DataTableFeatures
18
+ } from './core';
19
+
20
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'class'> & {
21
+ table: DataTable<TData, TSelected>;
22
+ class?: ClassValue;
23
+ tableClass?: ClassValue;
24
+ };
25
+
26
+ let { table, class: className, tableClass, ...rest }: Props = $props();
27
+
28
+ const locale = useLocaleContext();
29
+ const columnCount = $derived(table.getVisibleLeafColumns().length);
30
+ const headerGroupCount = $derived(table.getHeaderGroups().length);
31
+ const isRowSelectionEnabled = $derived(Boolean(table.options.enableRowSelection));
32
+ const isMultiRowSelectionEnabled = $derived(table.options.enableMultiRowSelection !== false);
33
+ const tableColumnCount = $derived(columnCount + (isRowSelectionEnabled ? 1 : 0));
34
+ const allRowsSelected = $derived(table.getIsAllRowsSelected());
35
+ const someRowsSelected = $derived(table.getIsSomeRowsSelected());
36
+ const allRowsSelectionState = $derived(
37
+ allRowsSelected ? true : someRowsSelected ? 'indeterminate' : false
38
+ );
39
+ const rowSelectionColumnSize = 40;
40
+ const tableSize = $derived(
41
+ table.getTotalSize() + (isRowSelectionEnabled ? rowSelectionColumnSize : 0)
42
+ );
43
+ const isColumnResizing = $derived(table.store.state.columnResizing.isResizingColumn !== false);
44
+
45
+ function formatNumericValue(
46
+ value: unknown,
47
+ options: Intl.NumberFormatOptions & { locale?: string }
48
+ ) {
49
+ if (typeof value !== 'number') return formatTextValue(value);
50
+ const { locale: optionLocale, ...numberFormatOptions } = options;
51
+ return new Intl.NumberFormat(optionLocale ?? locale().locale, numberFormatOptions).format(
52
+ value
53
+ );
54
+ }
55
+
56
+ function formatTextValue(value: unknown, fallback = '') {
57
+ if (value === null || value === undefined || value === '') return fallback;
58
+ return String(value);
59
+ }
60
+
61
+ function fractionOptions(options: { fractionDigits?: number }) {
62
+ if (options.fractionDigits === undefined) return {};
63
+
64
+ return {
65
+ minimumFractionDigits: options.fractionDigits,
66
+ maximumFractionDigits: options.fractionDigits
67
+ };
68
+ }
69
+
70
+ function isNumericCellConfig(cellConfig: DataTableCellConfig<TData> | undefined) {
71
+ return (
72
+ cellConfig?.type === 'number' ||
73
+ cellConfig?.type === 'currency' ||
74
+ cellConfig?.type === 'percentage'
75
+ );
76
+ }
77
+
78
+ function getLinkHref<TValue>(
79
+ cell: DataTableCell<TData, TValue>,
80
+ href: string | ((value: TValue, row: TData) => string) | undefined
81
+ ) {
82
+ const value = cell.getValue();
83
+ if (!href) return formatTextValue(value);
84
+ return typeof href === 'function' ? href(value, cell.row.original) : href;
85
+ }
86
+
87
+ function getLinkLabel(value: unknown, fallback = 'Open link') {
88
+ return formatTextValue(value, fallback);
89
+ }
90
+
91
+ function getCellMeta<TValue>(cell: DataTableCell<TData, TValue>) {
92
+ return (cell.column.columnDef.meta as DataTableColumnMeta<TData, TValue> | undefined)
93
+ ?.dataTable;
94
+ }
95
+
96
+ function getHeaderMeta(header: Header<DataTableFeatures, TData, unknown>) {
97
+ return header.column.columnDef.meta as DataTableColumnMeta<TData> | undefined;
98
+ }
99
+
100
+ function getColumnAlign(
101
+ align: DataTableColumnAlign | undefined,
102
+ cellConfig: DataTableCellConfig<TData> | undefined
103
+ ) {
104
+ return align ?? (isNumericCellConfig(cellConfig) ? 'right' : 'left');
105
+ }
106
+
107
+ function alignClass(align: DataTableColumnAlign | undefined) {
108
+ return {
109
+ left: 'text-left',
110
+ center: 'text-center',
111
+ right: 'text-right'
112
+ }[align ?? 'left'];
113
+ }
114
+
115
+ function justifyClass(align: DataTableColumnAlign | undefined) {
116
+ return {
117
+ left: 'justify-start',
118
+ center: 'justify-center',
119
+ right: 'justify-end'
120
+ }[align ?? 'left'];
121
+ }
122
+
123
+ function sortButtonDirectionClass(align: DataTableColumnAlign | undefined) {
124
+ return align === 'right' ? 'flex-row-reverse' : 'flex-row';
125
+ }
126
+
127
+ function columnSizeStyle(size: number) {
128
+ return `width: ${size}px`;
129
+ }
130
+
131
+ function tableSizeStyle() {
132
+ return `width: max(100%, ${tableSize}px)`;
133
+ }
134
+
135
+ function resizeHandleStyle(header: Header<DataTableFeatures, TData, unknown>) {
136
+ if (table.options.columnResizeMode !== 'onEnd') return undefined;
137
+ const deltaOffset = table.store.state.columnResizing.deltaOffset;
138
+ if (!header.column.getIsResizing() || deltaOffset === null) return undefined;
139
+ return `transform: translateX(${deltaOffset}px)`;
140
+ }
141
+
142
+ function getHeaderSortDirection(
143
+ header: Header<DataTableFeatures, TData, unknown>,
144
+ sortingState: unknown
145
+ ) {
146
+ void sortingState;
147
+ return header.column.getIsSorted();
148
+ }
149
+
150
+ function getHeaderSortLabel(sortDirection: false | 'asc' | 'desc') {
151
+ if (sortDirection === 'asc') return 'Sorted ascending';
152
+ if (sortDirection === 'desc') return 'Sorted descending';
153
+ return 'Not sorted';
154
+ }
155
+
156
+ function getHeaderAriaSort(sortDirection: false | 'asc' | 'desc') {
157
+ if (sortDirection === 'asc') return 'ascending';
158
+ if (sortDirection === 'desc') return 'descending';
159
+ return 'none';
160
+ }
161
+ </script>
162
+
163
+ <div
164
+ class={cn('max-h-full min-h-0 overflow-auto rounded-lg border border-surface-3', className)}
165
+ {...rest}
166
+ >
167
+ {#if isColumnResizing}
168
+ <div aria-hidden="true" class="fixed inset-0 z-50 cursor-col-resize select-none"></div>
169
+ {/if}
170
+
171
+ <table class={cn('table-fixed border-collapse text-sm', tableClass)} style={tableSizeStyle()}>
172
+ <colgroup>
173
+ {#if isRowSelectionEnabled}
174
+ <col style={columnSizeStyle(rowSelectionColumnSize)} />
175
+ {/if}
176
+ {#each table.getVisibleLeafColumns() as column (column.id)}
177
+ <col style={columnSizeStyle(column.getSize())} />
178
+ {/each}
179
+ </colgroup>
180
+ <thead class="sticky top-0 z-20 bg-surface-2 text-left text-ink-dim">
181
+ {#each table.getHeaderGroups() as headerGroup, headerGroupIndex (headerGroup.id)}
182
+ <tr>
183
+ {#if isRowSelectionEnabled && headerGroupIndex === 0}
184
+ <th
185
+ class="border-b border-surface-3 bg-surface-2 px-3 py-2 text-center align-middle font-medium"
186
+ rowspan={headerGroupCount}
187
+ >
188
+ {#if isMultiRowSelectionEnabled}
189
+ <Checkbox
190
+ size="sm"
191
+ aria-label="Select all rows"
192
+ class="mx-auto size-4"
193
+ checked={allRowsSelectionState}
194
+ onCheckedChange={({ checked }) => table.toggleAllRowsSelected(checked === true)}
195
+ />
196
+ {/if}
197
+ </th>
198
+ {/if}
199
+ {#each headerGroup.headers as header (header.id)}
200
+ {@const headerMeta = getHeaderMeta(header)?.dataTable}
201
+ {@const headerAlign = getColumnAlign(headerMeta?.align, headerMeta?.cell)}
202
+ {@const sortDirection = getHeaderSortDirection(header, table.store.state.sorting)}
203
+ <th
204
+ class={cn(
205
+ 'relative border-b border-surface-3 bg-surface-2 px-3 py-2 font-medium',
206
+ alignClass(headerAlign)
207
+ )}
208
+ colspan={header.colSpan}
209
+ aria-sort={header.column.getCanSort() ? getHeaderAriaSort(sortDirection) : undefined}
210
+ >
211
+ {#if !header.isPlaceholder}
212
+ {#if header.column.getCanSort()}
213
+ <button
214
+ type="button"
215
+ class={cn(
216
+ 'inline-flex max-w-full items-center gap-1 rounded-sm outline-none hover:text-ink data-focus-visible:outline-2 data-focus-visible:outline-offset-2 data-focus-visible:outline-ring',
217
+ justifyClass(headerAlign),
218
+ sortButtonDirectionClass(headerAlign)
219
+ )}
220
+ aria-label={`${getHeaderSortLabel(sortDirection)}. Toggle sorting.`}
221
+ onclick={header.column.getToggleSortingHandler()}
222
+ >
223
+ <span class="min-w-0 truncate">
224
+ <FlexRender {header} />
225
+ </span>
226
+ <span
227
+ class="inline-flex size-3.5 shrink-0 items-center justify-center text-ink-dim"
228
+ >
229
+ {#if sortDirection === 'asc'}
230
+ <PhCaretUp class="size-3.5" />
231
+ {:else if sortDirection === 'desc'}
232
+ <PhCaretDown class="size-3.5" />
233
+ {/if}
234
+ </span>
235
+ </button>
236
+ {:else}
237
+ <FlexRender {header} />
238
+ {/if}
239
+ {/if}
240
+ {#if header.column.getCanResize()}
241
+ <div
242
+ aria-hidden="true"
243
+ class={cn(
244
+ 'absolute top-0 -right-1 z-10 flex h-full w-2 cursor-col-resize touch-none items-center justify-center select-none before:h-4 before:w-px before:bg-border before:content-[""]'
245
+ )}
246
+ style={resizeHandleStyle(header)}
247
+ ondblclick={() => header.column.resetSize()}
248
+ onmousedown={header.getResizeHandler()}
249
+ ontouchstart={header.getResizeHandler()}
250
+ ></div>
251
+ {/if}
252
+ </th>
253
+ {/each}
254
+ </tr>
255
+ {/each}
256
+ </thead>
257
+ <tbody>
258
+ {#each table.getRowModel().rows as row (row.id)}
259
+ <tr class="border-b border-surface-3 last:border-b-0">
260
+ {#if isRowSelectionEnabled}
261
+ <td class="px-3 py-2 text-center align-middle">
262
+ <Checkbox
263
+ size="sm"
264
+ aria-label="Select row"
265
+ class="mx-auto size-4"
266
+ checked={row.getIsSelected()}
267
+ disabled={!row.getCanSelect()}
268
+ onCheckedChange={({ checked }) => row.toggleSelected(checked === true)}
269
+ />
270
+ </td>
271
+ {/if}
272
+ {#each row.getVisibleCells() as cell (cell.id)}
273
+ {@const cellMeta = getCellMeta(cell)}
274
+ {@const cellConfig = getDataTableCellConfig(cell)}
275
+ {@const cellAlign = getColumnAlign(cellMeta?.align, cellConfig)}
276
+ <td
277
+ class={cn(
278
+ 'px-3 py-2',
279
+ alignClass(cellAlign),
280
+ isNumericCellConfig(cellConfig) && 'tabular-nums'
281
+ )}
282
+ >
283
+ {#if cellConfig && !hasCustomDataTableCell(cell)}
284
+ {@const value = cell.getValue()}
285
+ {#if cellConfig.type === 'number'}
286
+ {formatNumericValue(value, {
287
+ ...cellConfig,
288
+ ...fractionOptions(cellConfig)
289
+ })}
290
+ {:else if cellConfig.type === 'currency'}
291
+ {formatNumericValue(value, {
292
+ ...cellConfig,
293
+ ...fractionOptions(cellConfig),
294
+ style: 'currency'
295
+ })}
296
+ {:else if cellConfig.type === 'percentage'}
297
+ {formatNumericValue(value, {
298
+ ...cellConfig,
299
+ ...fractionOptions(cellConfig),
300
+ style: 'percent'
301
+ })}
302
+ {:else if cellConfig.type === 'boolean'}
303
+ {value === true
304
+ ? (cellConfig.trueLabel ?? 'Yes')
305
+ : value === false
306
+ ? (cellConfig.falseLabel ?? 'No')
307
+ : (cellConfig.nullLabel ?? '')}
308
+ {:else if cellConfig.type === 'link'}
309
+ {@const href = getLinkHref(cell, cellConfig.href)}
310
+ {#if href}
311
+ <a
312
+ class="inline-flex size-7 items-center justify-center rounded-md text-primary hover:bg-surface-2"
313
+ {href}
314
+ target={cellConfig.target ?? '_blank'}
315
+ rel="external noreferrer"
316
+ aria-label={getLinkLabel(value, cellConfig.fallback)}
317
+ title={getLinkLabel(value, cellConfig.fallback)}
318
+ >
319
+ <PhArrowSquareOut class="size-4" />
320
+ </a>
321
+ {:else}
322
+ {formatTextValue(value, cellConfig.fallback)}
323
+ {/if}
324
+ {:else}
325
+ {formatTextValue(value, cellConfig.fallback)}
326
+ {/if}
327
+ {:else}
328
+ <FlexRender {cell} />
329
+ {/if}
330
+ </td>
331
+ {/each}
332
+ </tr>
333
+ {:else}
334
+ <tr>
335
+ <td class="px-3 py-6 text-center text-ink-dim" colspan={tableColumnCount}>
336
+ No results.
337
+ </td>
338
+ </tr>
339
+ {/each}
340
+ </tbody>
341
+ </table>
342
+ </div>
@@ -0,0 +1,32 @@
1
+ import { type ClassValue } from 'tailwind-variants';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { RowData } from '@tanstack/svelte-table';
4
+ import { type DataTable } from './core';
5
+ declare function $$render<TData extends RowData, TSelected = object>(): {
6
+ props: Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
7
+ table: DataTable<TData, TSelected>;
8
+ class?: ClassValue;
9
+ tableClass?: ClassValue;
10
+ };
11
+ exports: {};
12
+ bindings: "";
13
+ slots: {};
14
+ events: {};
15
+ };
16
+ declare class __sveltets_Render<TData extends RowData, TSelected = object> {
17
+ props(): ReturnType<typeof $$render<TData, TSelected>>['props'];
18
+ events(): ReturnType<typeof $$render<TData, TSelected>>['events'];
19
+ slots(): ReturnType<typeof $$render<TData, TSelected>>['slots'];
20
+ bindings(): "";
21
+ exports(): {};
22
+ }
23
+ interface $$IsomorphicComponent {
24
+ new <TData extends RowData, TSelected = object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData, TSelected>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData, TSelected>['props']>, ReturnType<__sveltets_Render<TData, TSelected>['events']>, ReturnType<__sveltets_Render<TData, TSelected>['slots']>> & {
25
+ $$bindings?: ReturnType<__sveltets_Render<TData, TSelected>['bindings']>;
26
+ } & ReturnType<__sveltets_Render<TData, TSelected>['exports']>;
27
+ <TData extends RowData, TSelected = object>(internal: unknown, props: ReturnType<__sveltets_Render<TData, TSelected>['props']> & {}): ReturnType<__sveltets_Render<TData, TSelected>['exports']>;
28
+ z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
29
+ }
30
+ declare const DataTable: $$IsomorphicComponent;
31
+ type DataTable<TData extends RowData, TSelected = object> = InstanceType<typeof DataTable<TData, TSelected>>;
32
+ export default DataTable;
@@ -0,0 +1,7 @@
1
+ export { default as Root } from './data-table.svelte';
2
+ export { default as Toolbar } from './data-table-toolbar.svelte';
3
+ export { default as Title } from './data-table-title.svelte';
4
+ export { default as ColumnVisibility } from './data-table-column-visibility.svelte';
5
+ export { default as Filters } from './data-table-filters.svelte';
6
+ export * from './core';
7
+ export * from '@tanstack/svelte-table';
@@ -0,0 +1,7 @@
1
+ export { default as Root } from './data-table.svelte';
2
+ export { default as Toolbar } from './data-table-toolbar.svelte';
3
+ export { default as Title } from './data-table-title.svelte';
4
+ export { default as ColumnVisibility } from './data-table-column-visibility.svelte';
5
+ export { default as Filters } from './data-table-filters.svelte';
6
+ export * from './core';
7
+ export * from '@tanstack/svelte-table';
@@ -14,10 +14,10 @@
14
14
 
15
15
  <div class="relative w-full">
16
16
  {#if startIcon}
17
- <div
18
- class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2.5 text-ink-dim"
19
- >
20
- {@render startIcon()}
17
+ <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center p-0.5 text-ink-dim">
18
+ <div class="flex h-full min-w-8 items-center justify-center">
19
+ {@render startIcon()}
20
+ </div>
21
21
  </div>
22
22
  {/if}
23
23
  <Field.Input
@@ -31,8 +31,10 @@
31
31
  )}
32
32
  />
33
33
  {#if endIcon}
34
- <div class="absolute inset-y-0 right-0 flex items-center pr-2.5">
35
- {@render endIcon()}
34
+ <div class="absolute inset-y-0 right-0 flex items-center justify-end p-0.5">
35
+ <div class="flex h-full min-w-8 items-center justify-center">
36
+ {@render endIcon()}
37
+ </div>
36
38
  </div>
37
39
  {/if}
38
40
  </div>
@@ -11,6 +11,7 @@
11
11
  label,
12
12
  layout = 'vertical',
13
13
  name,
14
+ onValueChange,
14
15
  ...restProps
15
16
  }: NumberInputProps = $props();
16
17
  const locale = useLocaleContext();
@@ -30,7 +31,9 @@
30
31
  value={value?.toString()}
31
32
  readOnly={readonly}
32
33
  onValueChange={(valueChangeDetails) => {
34
+ onValueChange?.(valueChangeDetails);
33
35
  if (isNaN(valueChangeDetails.valueAsNumber)) {
36
+ value = null;
34
37
  return;
35
38
  }
36
39
  value = valueChangeDetails.valueAsNumber;
@@ -0,0 +1,6 @@
1
+ export { default as Root } from './popover-root.svelte';
2
+ export { default as Trigger } from './popover-trigger.svelte';
3
+ export { default as Content } from './popover-content.svelte';
4
+ export { default as Title } from './popover-title.svelte';
5
+ export { default as Description } from './popover-description.svelte';
6
+ export { default as CloseTrigger } from './popover-close-trigger.svelte';
@@ -0,0 +1,6 @@
1
+ export { default as Root } from './popover-root.svelte';
2
+ export { default as Trigger } from './popover-trigger.svelte';
3
+ export { default as Content } from './popover-content.svelte';
4
+ export { default as Title } from './popover-title.svelte';
5
+ export { default as Description } from './popover-description.svelte';
6
+ export { default as CloseTrigger } from './popover-close-trigger.svelte';
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import { Popover } from '@ark-ui/svelte/popover';
3
+ import type { PopoverCloseTriggerBaseProps } from '@ark-ui/svelte/popover';
4
+ import { PhX } from '../../icons';
5
+ import type { ClassValue } from 'svelte/elements';
6
+
7
+ interface Props extends PopoverCloseTriggerBaseProps {
8
+ class?: ClassValue;
9
+ }
10
+
11
+ let { class: className, children, ...rest }: Props = $props();
12
+ </script>
13
+
14
+ <Popover.CloseTrigger
15
+ {...rest}
16
+ class={className ??
17
+ 'absolute top-3 right-3 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none active:opacity-50'}
18
+ >
19
+ {#if children}
20
+ {@render children()}
21
+ {:else}
22
+ <PhX class="size-4" />
23
+ <span class="sr-only">Close</span>
24
+ {/if}
25
+ </Popover.CloseTrigger>
@@ -0,0 +1,8 @@
1
+ import type { PopoverCloseTriggerBaseProps } from '@ark-ui/svelte/popover';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ interface Props extends PopoverCloseTriggerBaseProps {
4
+ class?: ClassValue;
5
+ }
6
+ declare const PopoverCloseTrigger: import("svelte").Component<Props, {}, "">;
7
+ type PopoverCloseTrigger = ReturnType<typeof PopoverCloseTrigger>;
8
+ export default PopoverCloseTrigger;
@@ -0,0 +1,71 @@
1
+ <script lang="ts">
2
+ import { Popover } from '@ark-ui/svelte/popover';
3
+ import { Portal } from '@ark-ui/svelte/portal';
4
+ import { cn } from 'tailwind-variants';
5
+ import type { ClassValue } from 'svelte/elements';
6
+ import type { Snippet } from 'svelte';
7
+
8
+ interface Props {
9
+ class?: ClassValue;
10
+ children: Snippet;
11
+ showArrow?: boolean;
12
+ }
13
+
14
+ let { class: className, children, showArrow = true }: Props = $props();
15
+ </script>
16
+
17
+ <Portal>
18
+ <Popover.Positioner>
19
+ <Popover.Content
20
+ class={cn(
21
+ 'z-50 w-72 rounded-md border bg-surface-1 p-4 shadow-md outline-none [--arrow-background:var(--compote-surface-1)] [--arrow-size:10px]',
22
+ 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
23
+ 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
24
+ className
25
+ )}
26
+ >
27
+ {#if showArrow}
28
+ <Popover.Arrow>
29
+ <Popover.ArrowTip class="border-t border-l border-border" />
30
+ </Popover.Arrow>
31
+ {/if}
32
+ {@render children()}
33
+ </Popover.Content>
34
+ </Popover.Positioner>
35
+ </Portal>
36
+
37
+ <style>
38
+ :global([data-scope='popover'][data-part='content']) {
39
+ transform-origin: var(--transform-origin);
40
+ }
41
+
42
+ :global([data-scope='popover'][data-part='content'][data-state='open']) {
43
+ animation: popover-in 150ms ease-out;
44
+ }
45
+
46
+ :global([data-scope='popover'][data-part='content'][data-state='closed']) {
47
+ animation: popover-out 100ms ease-in;
48
+ }
49
+
50
+ @keyframes popover-in {
51
+ from {
52
+ opacity: 0;
53
+ transform: scale(0.95);
54
+ }
55
+ to {
56
+ opacity: 1;
57
+ transform: scale(1);
58
+ }
59
+ }
60
+
61
+ @keyframes popover-out {
62
+ from {
63
+ opacity: 1;
64
+ transform: scale(1);
65
+ }
66
+ to {
67
+ opacity: 0;
68
+ transform: scale(0.95);
69
+ }
70
+ }
71
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { ClassValue } from 'svelte/elements';
2
+ import type { Snippet } from 'svelte';
3
+ interface Props {
4
+ class?: ClassValue;
5
+ children: Snippet;
6
+ showArrow?: boolean;
7
+ }
8
+ declare const PopoverContent: import("svelte").Component<Props, {}, "">;
9
+ type PopoverContent = ReturnType<typeof PopoverContent>;
10
+ export default PopoverContent;
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { Popover } from '@ark-ui/svelte/popover';
3
+ import type { PopoverDescriptionBaseProps } from '@ark-ui/svelte/popover';
4
+ import type { ClassValue } from 'svelte/elements';
5
+
6
+ interface Props extends PopoverDescriptionBaseProps {
7
+ class?: ClassValue;
8
+ }
9
+
10
+ let { class: className, children, ...rest }: Props = $props();
11
+ </script>
12
+
13
+ <Popover.Description {...rest} class={className ?? 'mt-1 text-sm text-ink-dim'}>
14
+ {@render children?.()}
15
+ </Popover.Description>
@@ -0,0 +1,8 @@
1
+ import type { PopoverDescriptionBaseProps } from '@ark-ui/svelte/popover';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ interface Props extends PopoverDescriptionBaseProps {
4
+ class?: ClassValue;
5
+ }
6
+ declare const PopoverDescription: import("svelte").Component<Props, {}, "">;
7
+ type PopoverDescription = ReturnType<typeof PopoverDescription>;
8
+ export default PopoverDescription;
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import { Popover } from '@ark-ui/svelte/popover';
3
+ import type { PopoverRootBaseProps } from '@ark-ui/svelte/popover';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ interface Props extends PopoverRootBaseProps {
7
+ open?: boolean;
8
+ children: Snippet;
9
+ lazyMount?: boolean;
10
+ unmountOnExit?: boolean;
11
+ }
12
+
13
+ let {
14
+ open = $bindable(),
15
+ children,
16
+ lazyMount = true,
17
+ unmountOnExit = true,
18
+ ...restProps
19
+ }: Props = $props();
20
+ </script>
21
+
22
+ <Popover.Root bind:open {lazyMount} {unmountOnExit} {...restProps}>
23
+ {@render children()}
24
+ </Popover.Root>
@@ -0,0 +1,11 @@
1
+ import type { PopoverRootBaseProps } from '@ark-ui/svelte/popover';
2
+ import type { Snippet } from 'svelte';
3
+ interface Props extends PopoverRootBaseProps {
4
+ open?: boolean;
5
+ children: Snippet;
6
+ lazyMount?: boolean;
7
+ unmountOnExit?: boolean;
8
+ }
9
+ declare const PopoverRoot: import("svelte").Component<Props, {}, "open">;
10
+ type PopoverRoot = ReturnType<typeof PopoverRoot>;
11
+ export default PopoverRoot;
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { Popover } from '@ark-ui/svelte/popover';
3
+ import type { PopoverTitleBaseProps } from '@ark-ui/svelte/popover';
4
+ import type { ClassValue } from 'svelte/elements';
5
+
6
+ interface Props extends PopoverTitleBaseProps {
7
+ class?: ClassValue;
8
+ }
9
+
10
+ let { class: className, children, ...rest }: Props = $props();
11
+ </script>
12
+
13
+ <Popover.Title {...rest} class={className ?? 'text-sm font-semibold'}>
14
+ {@render children?.()}
15
+ </Popover.Title>
@@ -0,0 +1,8 @@
1
+ import type { PopoverTitleBaseProps } from '@ark-ui/svelte/popover';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ interface Props extends PopoverTitleBaseProps {
4
+ class?: ClassValue;
5
+ }
6
+ declare const PopoverTitle: import("svelte").Component<Props, {}, "">;
7
+ type PopoverTitle = ReturnType<typeof PopoverTitle>;
8
+ export default PopoverTitle;