compote-ui 0.62.1 → 0.62.2
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/README.md +6 -0
- package/package.json +13 -3
- package/skills/component-usage/SKILL.md +202 -0
- package/skills/component-usage/references/buttons.md +27 -0
- package/skills/component-usage/references/component-export-map.md +54 -0
- package/skills/component-usage/references/files-and-images.md +75 -0
- package/skills/component-usage/references/forms-and-inputs.md +94 -0
- package/skills/component-usage/references/interactive-components.md +33 -0
- package/skills/component-usage/references/layout-and-display.md +82 -0
- package/skills/component-usage/references/overlays-and-floating-ui.md +80 -0
- package/skills/data-table/SKILL.md +247 -0
- package/skills/data-table/references/column-options.md +53 -0
- package/skills/data-table/references/table-state-and-reactivity.md +45 -0
- package/skills/data-table/references/virtual-table.md +44 -0
- package/skills/getting-started/SKILL.md +173 -0
- package/skills/getting-started/references/install-and-peers.md +45 -0
- package/skills/production-checklist/SKILL.md +181 -0
- package/skills/production-checklist/references/production-audit.md +40 -0
- package/skills/theming/SKILL.md +147 -0
- package/skills/theming/references/theme-tokens.md +56 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Overlays And Floating UI
|
|
2
|
+
|
|
3
|
+
`Dialog`, `Drawer`, `Menu`, `Popover`, `HoverCard`, `Tooltip`, and `Toast` are namespace exports.
|
|
4
|
+
|
|
5
|
+
Dialog:
|
|
6
|
+
|
|
7
|
+
```svelte
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
let open = $state(false);
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<Dialog.Root bind:open>
|
|
13
|
+
<Dialog.Title>Confirm Action</Dialog.Title>
|
|
14
|
+
<Dialog.Description>This cannot be undone.</Dialog.Description>
|
|
15
|
+
<Dialog.Footer>
|
|
16
|
+
<Dialog.CloseTrigger>Cancel</Dialog.CloseTrigger>
|
|
17
|
+
<Button onclick={() => (open = false)}>Confirm</Button>
|
|
18
|
+
</Dialog.Footer>
|
|
19
|
+
<Dialog.CloseTrigger />
|
|
20
|
+
</Dialog.Root>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use `onOpenChange`, not `onClose`:
|
|
24
|
+
|
|
25
|
+
```svelte
|
|
26
|
+
<Dialog.Root
|
|
27
|
+
bind:open
|
|
28
|
+
onOpenChange={(details) => {
|
|
29
|
+
if (!details.open) handleClose();
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
33
|
+
</Dialog.Root>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Drawer content renders backdrop and positioner internally:
|
|
37
|
+
|
|
38
|
+
```svelte
|
|
39
|
+
<Drawer.Root bind:open>
|
|
40
|
+
<Drawer.Content>
|
|
41
|
+
<Drawer.CloseTrigger />
|
|
42
|
+
<Drawer.Header>
|
|
43
|
+
<Drawer.Title>Edit Record</Drawer.Title>
|
|
44
|
+
</Drawer.Header>
|
|
45
|
+
<Drawer.Body>Scrollable content</Drawer.Body>
|
|
46
|
+
<Drawer.Footer>
|
|
47
|
+
<Button variant="ghost" onclick={() => (open = false)}>Cancel</Button>
|
|
48
|
+
<Button>Save</Button>
|
|
49
|
+
</Drawer.Footer>
|
|
50
|
+
</Drawer.Content>
|
|
51
|
+
</Drawer.Root>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
AlertDialog is for confirmations:
|
|
55
|
+
|
|
56
|
+
```svelte
|
|
57
|
+
<AlertDialog
|
|
58
|
+
bind:open={deleteOpen}
|
|
59
|
+
title="Delete item?"
|
|
60
|
+
description="This action cannot be undone."
|
|
61
|
+
variant="destructive"
|
|
62
|
+
confirmLabel="Delete"
|
|
63
|
+
onConfirm={handleDelete}
|
|
64
|
+
/>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Toast setup belongs in layout:
|
|
68
|
+
|
|
69
|
+
```svelte
|
|
70
|
+
<Toast.Toaster />
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Then fire toasts anywhere:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { toast } from 'compote-ui';
|
|
77
|
+
|
|
78
|
+
toast.success('Saved');
|
|
79
|
+
toast.error('Save failed', { description: 'Please try again.' });
|
|
80
|
+
```
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: data-table
|
|
3
|
+
description: >
|
|
4
|
+
Load when using compote-ui/data-table or compote-ui/data-table/virtual.
|
|
5
|
+
Covers TanStack Table v9 wrapper usage, createTable,
|
|
6
|
+
createDataTableColumnHelper, table columns, row selection, filters,
|
|
7
|
+
formatting, toolbars, virtualized imports, and optional peer dependencies.
|
|
8
|
+
metadata:
|
|
9
|
+
type: composition
|
|
10
|
+
library: compote-ui
|
|
11
|
+
library_version: '0.62.1'
|
|
12
|
+
requires:
|
|
13
|
+
- component-usage
|
|
14
|
+
- theming
|
|
15
|
+
sources:
|
|
16
|
+
- package.json
|
|
17
|
+
- src/lib/components/data-table-v9/index.ts
|
|
18
|
+
- src/lib/components/data-table-v9/types.ts
|
|
19
|
+
- src/lib/components/data-table-v9/features.ts
|
|
20
|
+
- src/lib/components/data-table-v9/column-helper.ts
|
|
21
|
+
- src/lib/components/data-table-v9/create-table.svelte.ts
|
|
22
|
+
- src/lib/components/data-table-v9/data-table.svelte
|
|
23
|
+
- src/lib/components/data-table-v9/virtual/data-table-virtualized.svelte
|
|
24
|
+
- src/lib/components/data-table-v9/virtual/data-table-virtual-rows.svelte
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
This skill builds on component-usage and theming. Read those first for Compote namespace imports and theme token behavior.
|
|
28
|
+
|
|
29
|
+
# Compote UI — Data Table
|
|
30
|
+
|
|
31
|
+
Use `compote-ui/data-table` for regular tables and `compote-ui/data-table/virtual` for virtualized rows.
|
|
32
|
+
|
|
33
|
+
## Integration Setup
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bun add @tanstack/svelte-table
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```svelte
|
|
40
|
+
<script lang="ts">
|
|
41
|
+
import * as DataTable from 'compote-ui/data-table';
|
|
42
|
+
|
|
43
|
+
type Invoice = {
|
|
44
|
+
id: string;
|
|
45
|
+
customer: string;
|
|
46
|
+
total: number;
|
|
47
|
+
paid: boolean;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
let invoices = $state<Invoice[]>([
|
|
51
|
+
{ id: 'inv_1', customer: 'Ada', total: 1200, paid: true },
|
|
52
|
+
{ id: 'inv_2', customer: 'Grace', total: 800, paid: false }
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
const col = DataTable.createDataTableColumnHelper<Invoice>();
|
|
56
|
+
const columns = col.columns([
|
|
57
|
+
col.accessor('id', { header: 'ID', enableHiding: false }),
|
|
58
|
+
col.accessor('customer', { header: 'Customer', grow: true }),
|
|
59
|
+
col.accessor('total', { header: 'Total', type: 'currency', align: 'right' }),
|
|
60
|
+
col.accessor('paid', { header: 'Paid', type: 'boolean', align: 'center' })
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const table = DataTable.createTable({
|
|
64
|
+
get data() {
|
|
65
|
+
return invoices;
|
|
66
|
+
},
|
|
67
|
+
columns,
|
|
68
|
+
getRowId: (row) => row.id,
|
|
69
|
+
enableRowSelection: true
|
|
70
|
+
});
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<DataTable.Toolbar>
|
|
74
|
+
<DataTable.Title>Invoices</DataTable.Title>
|
|
75
|
+
{#snippet center()}
|
|
76
|
+
<DataTable.Search {table} class="w-56" />
|
|
77
|
+
{/snippet}
|
|
78
|
+
{#snippet right()}
|
|
79
|
+
<DataTable.ColumnFilter {table} />
|
|
80
|
+
<DataTable.ColumnVisibility {table} />
|
|
81
|
+
{/snippet}
|
|
82
|
+
</DataTable.Toolbar>
|
|
83
|
+
|
|
84
|
+
<div class="h-96 min-h-0">
|
|
85
|
+
<DataTable.Root {table} caption="Invoices" />
|
|
86
|
+
</div>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Core Integration Patterns
|
|
90
|
+
|
|
91
|
+
### Use accessorFn with an explicit id
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const columns = col.columns([
|
|
95
|
+
col.accessorFn((row) => row.quantity * row.price, {
|
|
96
|
+
id: 'total',
|
|
97
|
+
header: 'Total',
|
|
98
|
+
type: 'currency',
|
|
99
|
+
align: 'right'
|
|
100
|
+
})
|
|
101
|
+
]);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Make runtime column changes reactive
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const idCol = col.accessor('id', { header: 'ID', enableHiding: false });
|
|
108
|
+
const totalCol = col.accessor('total', { header: 'Total', type: 'currency' });
|
|
109
|
+
|
|
110
|
+
let columns = $state.raw([idCol]);
|
|
111
|
+
|
|
112
|
+
const table = DataTable.createTable({
|
|
113
|
+
get data() {
|
|
114
|
+
return invoices;
|
|
115
|
+
},
|
|
116
|
+
get columns() {
|
|
117
|
+
return columns;
|
|
118
|
+
},
|
|
119
|
+
getRowId: (row) => row.id
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
function toggleTotal() {
|
|
123
|
+
columns = columns.includes(totalCol)
|
|
124
|
+
? columns.filter((column) => column !== totalCol)
|
|
125
|
+
: [...columns, totalCol];
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Use virtual import for large row sets
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
bun add @tanstack/svelte-virtual
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```svelte
|
|
136
|
+
<script lang="ts">
|
|
137
|
+
import * as VirtualDataTable from 'compote-ui/data-table/virtual';
|
|
138
|
+
|
|
139
|
+
const table = VirtualDataTable.createTable({
|
|
140
|
+
get data() {
|
|
141
|
+
return rows;
|
|
142
|
+
},
|
|
143
|
+
columns,
|
|
144
|
+
getRowId: (row) => row.id,
|
|
145
|
+
enableRowSelection: true
|
|
146
|
+
});
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<div class="h-96 min-h-0">
|
|
150
|
+
<VirtualDataTable.Root {table} caption="Large dataset" />
|
|
151
|
+
</div>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Common Mistakes
|
|
155
|
+
|
|
156
|
+
### CRITICAL Missing id for accessorFn column
|
|
157
|
+
|
|
158
|
+
Wrong:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
col.accessorFn((row) => row.a + row.b, { header: 'Total' });
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Correct:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
col.accessorFn((row) => row.a + row.b, { id: 'total', header: 'Total' });
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Accessor function columns cannot derive a stable column id from a key.
|
|
171
|
+
|
|
172
|
+
Source: `src/lib/components/data-table-v9/create-table.svelte.ts`
|
|
173
|
+
|
|
174
|
+
### HIGH Non-reactive reassigned columns
|
|
175
|
+
|
|
176
|
+
Wrong:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
let columns = $state([idCol, nameCol]);
|
|
180
|
+
const table = DataTable.createTable({ data: rows, columns });
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Correct:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
let columns = $state.raw([idCol, nameCol]);
|
|
187
|
+
const table = DataTable.createTable({
|
|
188
|
+
get data() {
|
|
189
|
+
return rows;
|
|
190
|
+
},
|
|
191
|
+
get columns() {
|
|
192
|
+
return columns;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Reassigned columns must be passed through a getter and kept raw so identity checks keep working.
|
|
198
|
+
|
|
199
|
+
Source: `src/routes/components/data-table-v9/+page.svelte`, `src/lib/components/data-table-v9/create-table.svelte.ts`
|
|
200
|
+
|
|
201
|
+
### HIGH Rendering table without height constraint
|
|
202
|
+
|
|
203
|
+
Wrong:
|
|
204
|
+
|
|
205
|
+
```svelte
|
|
206
|
+
<DataTable.Root {table} />
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Correct:
|
|
210
|
+
|
|
211
|
+
```svelte
|
|
212
|
+
<div class="h-96 min-h-0">
|
|
213
|
+
<DataTable.Root {table} caption="Invoices" />
|
|
214
|
+
</div>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`DataTable.Root` fills its container and uses internal scrolling.
|
|
218
|
+
|
|
219
|
+
Source: `src/lib/components/data-table-v9/data-table.svelte`
|
|
220
|
+
|
|
221
|
+
### HIGH Importing virtual table without optional peer
|
|
222
|
+
|
|
223
|
+
Wrong:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import * as VirtualDataTable from 'compote-ui/data-table/virtual';
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Correct:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
bun add @tanstack/svelte-virtual
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
import * as VirtualDataTable from 'compote-ui/data-table/virtual';
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The virtual subpath imports `@tanstack/svelte-virtual`.
|
|
240
|
+
|
|
241
|
+
Source: `package.json`, `src/lib/components/data-table-v9/virtual/data-table-virtual-rows.svelte`
|
|
242
|
+
|
|
243
|
+
## References
|
|
244
|
+
|
|
245
|
+
- [Column options](references/column-options.md)
|
|
246
|
+
- [Table state and reactivity](references/table-state-and-reactivity.md)
|
|
247
|
+
- [Virtual table](references/virtual-table.md)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Column Options
|
|
2
|
+
|
|
3
|
+
Column helper:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
const col = DataTable.createDataTableColumnHelper<Row>();
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Accessors:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
col.accessor('fieldName', { header: 'Field' });
|
|
13
|
+
col.accessorFn((row) => row.a + row.b, { id: 'sum', header: 'Sum' });
|
|
14
|
+
col.group('Group', [col.accessor('name', { header: 'Name' })]);
|
|
15
|
+
col.columns([col.accessor('id', { header: 'ID' })]);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Common options:
|
|
19
|
+
|
|
20
|
+
- `header: string`
|
|
21
|
+
- `type?: 'text' | 'number' | 'currency' | 'percent' | 'boolean' | 'select' | 'url' | 'phone' | 'date' | 'time' | 'date-time'`
|
|
22
|
+
- `align?: 'left' | 'center' | 'right'`
|
|
23
|
+
- `size?: number`
|
|
24
|
+
- `minSize?: number`
|
|
25
|
+
- `maxSize?: number`
|
|
26
|
+
- `enableResizing?: boolean`
|
|
27
|
+
- `enableHiding?: boolean`
|
|
28
|
+
- `enableSorting?: boolean`
|
|
29
|
+
- `enableColumnFilter?: boolean`
|
|
30
|
+
- `filterFn?: FilterFn | string`
|
|
31
|
+
- `formatOptions?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions`
|
|
32
|
+
- `formatLocale?: string`
|
|
33
|
+
- `cell?: (value, row) => string | number | boolean | null | undefined`
|
|
34
|
+
- `cellComponent?: Component`
|
|
35
|
+
- `cellProps?: (value, row) => Record<string, unknown>`
|
|
36
|
+
- `cellSnippet?: Snippet`
|
|
37
|
+
- `pinned?: 'left' | 'right'`
|
|
38
|
+
- `grow?: boolean`
|
|
39
|
+
- `sum?: boolean`
|
|
40
|
+
- `footer?: (values: unknown[]) => string | number | undefined`
|
|
41
|
+
|
|
42
|
+
Type defaults:
|
|
43
|
+
|
|
44
|
+
- `number`, `currency`: right aligned, size `120`
|
|
45
|
+
- `percent`: right aligned, size `100`
|
|
46
|
+
- `date`: center aligned, size `110`
|
|
47
|
+
- `time`: center aligned, size `80`
|
|
48
|
+
- `date-time`: center aligned, size `160`
|
|
49
|
+
- `boolean`: center aligned, size `90`
|
|
50
|
+
- `url`: center aligned, sorting disabled, size `60`
|
|
51
|
+
- `phone`: left aligned, size `160`
|
|
52
|
+
|
|
53
|
+
Use one `grow: true` column to absorb extra horizontal space.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Table State And Reactivity
|
|
2
|
+
|
|
3
|
+
Use reactive getters for state that changes:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
const table = DataTable.createTable({
|
|
7
|
+
get data() {
|
|
8
|
+
return rows;
|
|
9
|
+
},
|
|
10
|
+
get columns() {
|
|
11
|
+
return columns;
|
|
12
|
+
},
|
|
13
|
+
getRowId: (row) => row.id
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use `$state.raw` for column arrays that are reassigned:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
let columns = $state.raw([idCol, nameCol]);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Read table state:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const selected = $derived(table.getSelectedRowModel().rows.map((row) => row.original));
|
|
27
|
+
const sorting = $derived(table.store.state.sorting);
|
|
28
|
+
const filters = $derived(table.store.state.columnFilters);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Persist column visibility with the observer callback:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const table = DataTable.createTable({
|
|
35
|
+
get data() {
|
|
36
|
+
return rows;
|
|
37
|
+
},
|
|
38
|
+
columns,
|
|
39
|
+
onColumnVisibilityChange: (visibility) => {
|
|
40
|
+
localStorage.setItem('column-visibility', JSON.stringify(visibility));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Initial `columnVisibility`, `columnSizing`, and `columnPinning` are computed when the table is created. Columns added later default to visible and use their own size.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Virtual Table
|
|
2
|
+
|
|
3
|
+
Use `compote-ui/data-table/virtual` for large row counts.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun add @tanstack/svelte-virtual
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```svelte
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import * as VirtualDataTable from 'compote-ui/data-table/virtual';
|
|
12
|
+
|
|
13
|
+
const table = VirtualDataTable.createTable({
|
|
14
|
+
get data() {
|
|
15
|
+
return rows;
|
|
16
|
+
},
|
|
17
|
+
columns,
|
|
18
|
+
getRowId: (row) => row.id,
|
|
19
|
+
enableRowSelection: true
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<VirtualDataTable.Toolbar>
|
|
24
|
+
<VirtualDataTable.Title>Large Table</VirtualDataTable.Title>
|
|
25
|
+
{#snippet center()}
|
|
26
|
+
<VirtualDataTable.Search {table} class="w-56" />
|
|
27
|
+
{/snippet}
|
|
28
|
+
{#snippet right()}
|
|
29
|
+
<VirtualDataTable.ColumnFilter {table} />
|
|
30
|
+
<VirtualDataTable.ColumnVisibility {table} />
|
|
31
|
+
{/snippet}
|
|
32
|
+
</VirtualDataTable.Toolbar>
|
|
33
|
+
|
|
34
|
+
<div class="h-96 min-h-0">
|
|
35
|
+
<VirtualDataTable.Root {table} caption="Large dataset" />
|
|
36
|
+
</div>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Differences from regular table:
|
|
40
|
+
|
|
41
|
+
- Import path is `compote-ui/data-table/virtual`.
|
|
42
|
+
- Add the optional `@tanstack/svelte-virtual` peer.
|
|
43
|
+
- Rows are absolutely positioned with transforms.
|
|
44
|
+
- The table uses grid layout internally.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: getting-started
|
|
3
|
+
description: >
|
|
4
|
+
Load when setting up compote-ui in a Svelte or SvelteKit app. Covers npm install,
|
|
5
|
+
bun add, importing tailwindcss before compote-ui/theme.css, first imports from
|
|
6
|
+
compote-ui, Toast.Toaster placement, Svelte 5 runes usage, and peer dependency basics.
|
|
7
|
+
metadata:
|
|
8
|
+
type: lifecycle
|
|
9
|
+
library: compote-ui
|
|
10
|
+
library_version: '0.62.1'
|
|
11
|
+
sources:
|
|
12
|
+
- package.json
|
|
13
|
+
- README.md
|
|
14
|
+
- CLAUDE.md
|
|
15
|
+
- AGENTS.md
|
|
16
|
+
- src/lib/index.ts
|
|
17
|
+
- src/routes/layout.css
|
|
18
|
+
- src/lib/theme.css
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Compote UI — Getting Started
|
|
22
|
+
|
|
23
|
+
Use Svelte 5 runes, import Tailwind first, then import `compote-ui/theme.css`.
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install compote-ui
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bun add compote-ui
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
@import 'tailwindcss';
|
|
37
|
+
@import 'compote-ui/theme.css';
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```svelte
|
|
41
|
+
<script lang="ts">
|
|
42
|
+
import { Button, Card } from 'compote-ui';
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<Card.Root>
|
|
46
|
+
<Card.Header>
|
|
47
|
+
<Card.Title>Account</Card.Title>
|
|
48
|
+
<Card.Description>Manage account settings.</Card.Description>
|
|
49
|
+
</Card.Header>
|
|
50
|
+
<Card.Content>
|
|
51
|
+
<Button>Save</Button>
|
|
52
|
+
</Card.Content>
|
|
53
|
+
</Card.Root>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Core Patterns
|
|
57
|
+
|
|
58
|
+
### Use Svelte 5 bindings
|
|
59
|
+
|
|
60
|
+
```svelte
|
|
61
|
+
<script lang="ts">
|
|
62
|
+
import { Dialog, Button } from 'compote-ui';
|
|
63
|
+
|
|
64
|
+
let open = $state(false);
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<Button onclick={() => (open = true)}>Open</Button>
|
|
68
|
+
|
|
69
|
+
<Dialog.Root bind:open>
|
|
70
|
+
<Dialog.Title>Confirm</Dialog.Title>
|
|
71
|
+
<Dialog.Description>Confirm the action.</Dialog.Description>
|
|
72
|
+
</Dialog.Root>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Render toast output once
|
|
76
|
+
|
|
77
|
+
```svelte
|
|
78
|
+
<script lang="ts">
|
|
79
|
+
import { Toast } from 'compote-ui';
|
|
80
|
+
|
|
81
|
+
let { children } = $props();
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<Toast.Toaster />
|
|
85
|
+
{@render children()}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { toast } from 'compote-ui';
|
|
90
|
+
|
|
91
|
+
toast.success('Saved');
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Add optional peers only when used
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
bun add @tanstack/svelte-table
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
bun add @tanstack/svelte-virtual
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Use `@tanstack/svelte-table` with `compote-ui/data-table`; add `@tanstack/svelte-virtual` only with `compote-ui/data-table/virtual`.
|
|
105
|
+
|
|
106
|
+
## Common Mistakes
|
|
107
|
+
|
|
108
|
+
### CRITICAL Missing theme CSS import
|
|
109
|
+
|
|
110
|
+
Wrong:
|
|
111
|
+
|
|
112
|
+
```css
|
|
113
|
+
@import 'tailwindcss';
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Correct:
|
|
117
|
+
|
|
118
|
+
```css
|
|
119
|
+
@import 'tailwindcss';
|
|
120
|
+
@import 'compote-ui/theme.css';
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Components rely on `theme.css` for Compote CSS variables and Tailwind token definitions.
|
|
124
|
+
|
|
125
|
+
Source: `src/lib/theme.css`, `src/routes/layout.css`
|
|
126
|
+
|
|
127
|
+
### HIGH Using Svelte legacy props
|
|
128
|
+
|
|
129
|
+
Wrong:
|
|
130
|
+
|
|
131
|
+
```svelte
|
|
132
|
+
<script lang="ts">
|
|
133
|
+
export let open = false;
|
|
134
|
+
$: visible = open;
|
|
135
|
+
</script>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Correct:
|
|
139
|
+
|
|
140
|
+
```svelte
|
|
141
|
+
<script lang="ts">
|
|
142
|
+
let { open = $bindable(false) } = $props();
|
|
143
|
+
const visible = $derived(open);
|
|
144
|
+
</script>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The project uses Svelte 5 runes mode globally.
|
|
148
|
+
|
|
149
|
+
Source: `CLAUDE.md`, `svelte.config.js`
|
|
150
|
+
|
|
151
|
+
### MEDIUM Installing table peers for every app
|
|
152
|
+
|
|
153
|
+
Wrong:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
bun add compote-ui @tanstack/svelte-table @tanstack/svelte-virtual
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Correct:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
bun add compote-ui
|
|
163
|
+
bun add @tanstack/svelte-table
|
|
164
|
+
bun add @tanstack/svelte-virtual
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Install TanStack peers only when the consuming app imports the matching data-table subpath.
|
|
168
|
+
|
|
169
|
+
Source: `package.json`, `src/lib/index.ts`
|
|
170
|
+
|
|
171
|
+
## References
|
|
172
|
+
|
|
173
|
+
- [Install and peers](references/install-and-peers.md)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Install And Peers
|
|
2
|
+
|
|
3
|
+
Consumer apps may use either npm or bun:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install compote-ui
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add compote-ui
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Repository development uses bun exclusively:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun install
|
|
17
|
+
bun run check
|
|
18
|
+
bun run lint
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Peer dependency guidance:
|
|
22
|
+
|
|
23
|
+
- `svelte`: required, Svelte 5.
|
|
24
|
+
- `@tanstack/svelte-table`: required only for `compote-ui/data-table`.
|
|
25
|
+
- `@tanstack/svelte-virtual`: required only for `compote-ui/data-table/virtual`.
|
|
26
|
+
|
|
27
|
+
Consumer stylesheet setup:
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
@import 'tailwindcss';
|
|
31
|
+
@import 'compote-ui/theme.css';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
App-level toast setup:
|
|
35
|
+
|
|
36
|
+
```svelte
|
|
37
|
+
<script lang="ts">
|
|
38
|
+
import { Toast } from 'compote-ui';
|
|
39
|
+
|
|
40
|
+
let { children } = $props();
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<Toast.Toaster />
|
|
44
|
+
{@render children()}
|
|
45
|
+
```
|