@colletdev/docs 0.2.1
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 +60 -0
- package/angular.md +254 -0
- package/cli.mjs +300 -0
- package/components.md +2268 -0
- package/core.md +684 -0
- package/index.md +53 -0
- package/package.json +40 -0
- package/react.md +290 -0
- package/svelte.md +234 -0
- package/vue.md +195 -0
package/index.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Collet Documentation
|
|
2
|
+
|
|
3
|
+
48 accessible web components built in Rust, compiled to WASM, distributed as
|
|
4
|
+
Custom Elements with first-class framework wrappers.
|
|
5
|
+
|
|
6
|
+
## Packages
|
|
7
|
+
|
|
8
|
+
| Package | Description | Peer Dependencies |
|
|
9
|
+
|---------|-------------|-------------------|
|
|
10
|
+
| `@collet/core` | Custom Elements + WASM runtime + CSS tokens | — |
|
|
11
|
+
| `@collet/react` | React 18+ wrappers with typed refs and hooks | `react >= 18`, `@collet/core` |
|
|
12
|
+
| `@collet/vue` | Vue 3.3+ wrappers with Volar support | `vue >= 3.3`, `@collet/core` |
|
|
13
|
+
| `@collet/svelte` | Svelte 5 wrappers with runes and snippets | `svelte >= 5`, `@collet/core` |
|
|
14
|
+
| `@collet/angular` | Angular 16+ standalone wrappers with CVA | `@angular/core >= 16`, `@collet/core` |
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @collet/core @collet/react # or vue/svelte/angular
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { init } from '@collet/core';
|
|
24
|
+
import { Button } from '@collet/react';
|
|
25
|
+
|
|
26
|
+
await init();
|
|
27
|
+
|
|
28
|
+
<Button label="Click me" variant="filled" onClick={(e) => console.log(e.detail)} />
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Documentation Files
|
|
32
|
+
|
|
33
|
+
| File | Size | Contents |
|
|
34
|
+
|------|------|----------|
|
|
35
|
+
| [core.md](./core.md) | 22 KB | Initialization, theming, CSS architecture, SSR, events, slots, form integration |
|
|
36
|
+
| [components.md](./components.md) | 64 KB | All 48 components: multi-framework imports, props, events, methods, types |
|
|
37
|
+
| [react.md](./react.md) | 6 KB | React 18+ patterns: forwardRef, hooks, event callbacks, SSR |
|
|
38
|
+
| [vue.md](./vue.md) | 5 KB | Vue 3.3+ patterns: Composition API, Volar, expose(), slots |
|
|
39
|
+
| [svelte.md](./svelte.md) | 5 KB | Svelte 5 patterns: runes, callback props, snippets, migration |
|
|
40
|
+
| [angular.md](./angular.md) | 6 KB | Angular 16+ patterns: standalone, CVA, OnPush, template binding |
|
|
41
|
+
|
|
42
|
+
## Generation
|
|
43
|
+
|
|
44
|
+
This documentation is auto-generated from the component manifest and kept
|
|
45
|
+
in sync by the build pipeline. Regenerate with:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node scripts/generate-skill-docs.mjs
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
|
|
53
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@colletdev/docs",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Collet component library documentation — API reference, framework guides, and AI agent setup",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"collet-docs": "./cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./index.md",
|
|
11
|
+
"./components": "./components.md",
|
|
12
|
+
"./react": "./react.md",
|
|
13
|
+
"./vue": "./vue.md",
|
|
14
|
+
"./svelte": "./svelte.md",
|
|
15
|
+
"./angular": "./angular.md",
|
|
16
|
+
"./core": "./core.md"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"*.md",
|
|
20
|
+
"cli.mjs"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"collet",
|
|
24
|
+
"documentation",
|
|
25
|
+
"web-components",
|
|
26
|
+
"react",
|
|
27
|
+
"vue",
|
|
28
|
+
"svelte",
|
|
29
|
+
"angular",
|
|
30
|
+
"rust",
|
|
31
|
+
"wasm"
|
|
32
|
+
],
|
|
33
|
+
"author": "Dan",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/Danrozen87/collet",
|
|
38
|
+
"directory": "packages/docs"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/react.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# Collet React Reference
|
|
2
|
+
|
|
3
|
+
React wrappers for the Collet component library. Auto-generated from
|
|
4
|
+
`custom-elements.json` via `scripts/generate-react.mjs`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Package
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
@colletdev/react
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Peer dependencies:** `react >= 18.0.0`, `@colletdev/core >= 0.1.0`
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
React wrappers are thin `forwardRef` components that render the underlying
|
|
19
|
+
`<cx-*>` Custom Element. They handle:
|
|
20
|
+
|
|
21
|
+
- **Attribute serialization** — objects/arrays go through `JSON.stringify`
|
|
22
|
+
- **Event bridging** — `on{Event}` props attach listeners for `cx-{event}` CustomEvents
|
|
23
|
+
- **Slot projection** — named slots via `<div slot="name" style={{display:'contents'}}>`
|
|
24
|
+
- **Typed imperative refs** — `useImperativeHandle` exposes typed methods
|
|
25
|
+
|
|
26
|
+
### Package Structure
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
packages/react/
|
|
30
|
+
generated/ ← Auto-generated wrappers (DO NOT EDIT)
|
|
31
|
+
button.tsx
|
|
32
|
+
dialog.tsx
|
|
33
|
+
...
|
|
34
|
+
index.ts ← Barrel exports
|
|
35
|
+
types.ts ← Shared TypeScript interfaces
|
|
36
|
+
elements.d.ts ← JSX IntrinsicElements augmentation
|
|
37
|
+
dist/ ← Compiled output (JS + .d.ts)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Patterns
|
|
43
|
+
|
|
44
|
+
### Basic Usage
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { Button, Dialog, type DialogRef } from '@colletdev/react';
|
|
48
|
+
|
|
49
|
+
function App() {
|
|
50
|
+
const dialogRef = useRef<DialogRef>(null);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<>
|
|
54
|
+
<Button label="Open" onClick={() => dialogRef.current?.open()} />
|
|
55
|
+
<Dialog
|
|
56
|
+
ref={dialogRef}
|
|
57
|
+
title="Confirm"
|
|
58
|
+
onClose={(e) => console.log(e.detail.reason)}
|
|
59
|
+
footer={<Button label="OK" variant="filled" />}
|
|
60
|
+
>
|
|
61
|
+
<p>Are you sure?</p>
|
|
62
|
+
</Dialog>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Event Callbacks
|
|
69
|
+
|
|
70
|
+
All events use `on{PascalEvent}` naming. The callback receives a `CustomEvent<Detail>`:
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<TextInput
|
|
74
|
+
label="Email"
|
|
75
|
+
onInput={(e) => setValue(e.detail.value)} // InputDetail
|
|
76
|
+
onChange={(e) => validate(e.detail.value)} // InputDetail
|
|
77
|
+
onFocus={(e) => setFocused(true)} // FocusDetail
|
|
78
|
+
onKeydown={(e) => { // KeyboardDetail
|
|
79
|
+
if (e.detail.key === 'Enter') submit();
|
|
80
|
+
}}
|
|
81
|
+
/>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Overlays (Dialog, Drawer)
|
|
85
|
+
|
|
86
|
+
Overlays support both declarative and imperative control. **Always keep them
|
|
87
|
+
mounted** — never conditionally render with `{show && <Dialog>}`. This matches
|
|
88
|
+
MUI, Radix, Ant Design, and every major React UI library.
|
|
89
|
+
|
|
90
|
+
**Declarative (recommended):**
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
const [open, setOpen] = useState(false);
|
|
94
|
+
|
|
95
|
+
<Button label="Open" onClick={() => setOpen(true)} />
|
|
96
|
+
<Dialog
|
|
97
|
+
open={open}
|
|
98
|
+
onClose={() => setOpen(false)}
|
|
99
|
+
title="Confirm"
|
|
100
|
+
footer={<Button label="OK" variant="filled" onClick={() => setOpen(false)} />}
|
|
101
|
+
>
|
|
102
|
+
<p>Are you sure?</p>
|
|
103
|
+
</Dialog>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Imperative (ref-based):**
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
const ref = useRef<DialogRef>(null);
|
|
110
|
+
|
|
111
|
+
<Button label="Open" onClick={() => ref.current?.open()} />
|
|
112
|
+
<Dialog ref={ref} title="Confirm" onClose={() => console.log('closed')}>
|
|
113
|
+
<p>Are you sure?</p>
|
|
114
|
+
</Dialog>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Both patterns work for Dialog and Drawer. The component owns its animation
|
|
118
|
+
lifecycle — open/close transitions play fully without being interrupted by
|
|
119
|
+
React state changes.
|
|
120
|
+
|
|
121
|
+
**Do NOT conditionally render overlays:**
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
// WRONG — unmounting kills exit animation, breaks accessibility
|
|
125
|
+
{isOpen && <Drawer open title="Settings">...</Drawer>}
|
|
126
|
+
|
|
127
|
+
// CORRECT — always mounted, visibility controlled by open prop
|
|
128
|
+
<Drawer open={isOpen} onClose={() => setIsOpen(false)} title="Settings">...</Drawer>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Imperative Refs
|
|
132
|
+
|
|
133
|
+
Components with `open/close/focus` methods expose typed refs:
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { Select, type SelectRef } from '@colletdev/react';
|
|
137
|
+
|
|
138
|
+
const ref = useRef<SelectRef>(null);
|
|
139
|
+
ref.current?.open(); // Opens dropdown
|
|
140
|
+
ref.current?.close(); // Closes dropdown
|
|
141
|
+
ref.current?.focus(); // Focuses trigger
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Named Slots
|
|
145
|
+
|
|
146
|
+
Named slots use React props that accept `ReactNode`:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
<Card
|
|
150
|
+
header={<h3>Title</h3>}
|
|
151
|
+
footer={<Button label="Action" />}
|
|
152
|
+
>
|
|
153
|
+
<p>Body content (default slot)</p>
|
|
154
|
+
</Card>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Under the hood, these render as `<div slot="name" style={{display:'contents'}}>`.
|
|
158
|
+
|
|
159
|
+
### Complex Props (Structured Data)
|
|
160
|
+
|
|
161
|
+
Props that accept arrays/objects are serialized to JSON attributes via `useEffect`:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<Table
|
|
165
|
+
caption="Users"
|
|
166
|
+
columns={[
|
|
167
|
+
{ id: 'name', header: 'Name', sortable: true },
|
|
168
|
+
{ id: 'email', header: 'Email' },
|
|
169
|
+
]}
|
|
170
|
+
rows={[
|
|
171
|
+
{ id: '1', cells: { name: 'Alice', email: 'alice@example.com' } },
|
|
172
|
+
]}
|
|
173
|
+
sorts={[{ column_id: 'name', direction: 'asc' }]}
|
|
174
|
+
onSort={(e) => handleSort(e.detail)}
|
|
175
|
+
/>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Form Integration
|
|
179
|
+
|
|
180
|
+
Form-associated components work with uncontrolled forms via `name` prop:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
<form onSubmit={handleSubmit}>
|
|
184
|
+
<TextInput name="email" label="Email" required />
|
|
185
|
+
<Select name="country" label="Country" items={countries} />
|
|
186
|
+
<Button label="Submit" kind="submit" />
|
|
187
|
+
</form>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
For controlled forms, use event callbacks:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
const [value, setValue] = useState('');
|
|
194
|
+
<TextInput
|
|
195
|
+
label="Name"
|
|
196
|
+
value={value}
|
|
197
|
+
onInput={(e) => setValue(e.detail.value)}
|
|
198
|
+
/>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### DOM Collision Handling
|
|
202
|
+
|
|
203
|
+
React 19 sets DOM properties directly on Custom Elements. The wrappers
|
|
204
|
+
automatically route these through `useEffect` + `setAttribute`:
|
|
205
|
+
|
|
206
|
+
- **HTML properties** (`title`, `width`, `loading`, `role`) — bypasses HTMLElement property setters
|
|
207
|
+
- **Form properties** (`name`, `value`, `type`) — on form components (TextInput, Select, Slider, etc.)
|
|
208
|
+
- **Numeric attributes** (`lines`, `min`, `max`, `step`, `duration`, `currentPage`, etc.) — ensures `attributeChangedCallback` fires for `_numericAttrs` coercion
|
|
209
|
+
- **Complex data** (`columns`, `rows`, `items`, etc.) — JSON-serialized objects/arrays
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
// All of these work correctly — routed through setAttribute automatically
|
|
213
|
+
<Dialog title="My Dialog" />
|
|
214
|
+
<Slider min={0} max={100} step={5} value={50} />
|
|
215
|
+
<Skeleton variant="text" lines={3} />
|
|
216
|
+
<Pagination currentPage={1} pageSize={10} totalItems={100} />
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
No special handling needed from consumers.
|
|
220
|
+
|
|
221
|
+
### Markdown Support
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
import { useMarkdown } from '@colletdev/react';
|
|
225
|
+
import { MessagePart, type MessagePartRef } from '@colletdev/react';
|
|
226
|
+
|
|
227
|
+
// Static markdown
|
|
228
|
+
const html = useMarkdown('**Hello** world');
|
|
229
|
+
|
|
230
|
+
// Streaming markdown (AI chat)
|
|
231
|
+
const { ref, startStream, appendTokens, endStream } = useMarkdownStream();
|
|
232
|
+
<MessagePart ref={ref} stream />
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Server Rendering
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
// Next.js App Router — Server Component
|
|
239
|
+
import { createRenderer } from '@colletdev/core/server';
|
|
240
|
+
|
|
241
|
+
export default async function Page() {
|
|
242
|
+
const cx = await createRenderer();
|
|
243
|
+
const buttonHtml = cx.renderDSD('button', { label: 'Click', id: 'btn-1' });
|
|
244
|
+
return <div dangerouslySetInnerHTML={{ __html: buttonHtml }} />;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## TypeScript
|
|
251
|
+
|
|
252
|
+
All props, events, and ref types are fully typed. Import types from `@colletdev/react`:
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
import type {
|
|
256
|
+
// Structured data props
|
|
257
|
+
TableColumn, TableRow, SelectOption, MenuEntry,
|
|
258
|
+
// Event details
|
|
259
|
+
InputDetail, ClickDetail, CloseDetail,
|
|
260
|
+
// Ref types (from component exports)
|
|
261
|
+
DialogRef, SelectRef, TextInputRef,
|
|
262
|
+
} from '@colletdev/react';
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### JSX IntrinsicElements
|
|
266
|
+
|
|
267
|
+
`@colletdev/react` augments `JSX.IntrinsicElements` with all `cx-*` elements
|
|
268
|
+
for direct Custom Element usage when wrappers aren't needed:
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
// Works with full type checking
|
|
272
|
+
<cx-button label="Raw CE" variant="filled" />
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Codegen
|
|
278
|
+
|
|
279
|
+
React wrappers are generated by `scripts/generate-react.mjs`. Configuration
|
|
280
|
+
lives in both the React generator (inline maps) and `scripts/component-config.mjs`
|
|
281
|
+
(shared across all framework generators).
|
|
282
|
+
|
|
283
|
+
**Do not edit** files in `packages/react/generated/` — they are overwritten
|
|
284
|
+
by `bash scripts/build-packages.sh`.
|
|
285
|
+
|
|
286
|
+
Custom files (preserved by codegen):
|
|
287
|
+
- `generated/message-part.tsx` — streaming markdown support
|
|
288
|
+
- `generated/use-markdown.ts` — `useMarkdown()` hook
|
|
289
|
+
- `generated/use-markdown-stream.ts` — `useMarkdownStream()` hook
|
|
290
|
+
- `generated/drawer.tsx` — custom drawer implementation
|
package/svelte.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Collet Svelte Reference
|
|
2
|
+
|
|
3
|
+
Svelte 5 wrappers for the Collet component library. Auto-generated from
|
|
4
|
+
`custom-elements.json` via `scripts/generate-svelte.mjs`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Package
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
@colletdev/svelte
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Peer dependencies:** `svelte >= 5.0.0`, `@colletdev/core >= 0.1.0`
|
|
15
|
+
|
|
16
|
+
Ships raw `.svelte` source files — consumers compile with their own Svelte toolchain.
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
Svelte wrappers use Svelte 5 runes (`$props`, `$effect`) for reactive prop
|
|
21
|
+
syncing and event bridging. They handle:
|
|
22
|
+
|
|
23
|
+
- **Attribute serialization** — objects/arrays synced via `$effect` + `setAttribute`
|
|
24
|
+
- **Event bridging** — callback props (`onClick`, `onChange`) wired via `$effect` listeners
|
|
25
|
+
- **Slot projection** — `{@render children?.()}` for default, `{@render footer?.()}` for named
|
|
26
|
+
- **Imperative methods** — `export function open()` exposed to consumers
|
|
27
|
+
|
|
28
|
+
### Package Structure
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
packages/svelte/
|
|
32
|
+
src/ ← Auto-generated wrappers (DO NOT EDIT)
|
|
33
|
+
button.svelte
|
|
34
|
+
button.svelte.d.ts
|
|
35
|
+
dialog.svelte
|
|
36
|
+
dialog.svelte.d.ts
|
|
37
|
+
...
|
|
38
|
+
index.ts ← Barrel exports + type re-exports
|
|
39
|
+
types.ts ← Shared TypeScript interfaces
|
|
40
|
+
elements.d.ts ← SvelteHTMLElements augmentation
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Patterns
|
|
46
|
+
|
|
47
|
+
### Basic Usage
|
|
48
|
+
|
|
49
|
+
```svelte
|
|
50
|
+
<script lang="ts">
|
|
51
|
+
import Button from '@colletdev/svelte/button.svelte';
|
|
52
|
+
import Dialog from '@colletdev/svelte/dialog.svelte';
|
|
53
|
+
|
|
54
|
+
let dialog: { open: () => void; close: () => void };
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<Button label="Open" onClick={() => dialog.open()} />
|
|
58
|
+
<Dialog
|
|
59
|
+
bind:this={dialog}
|
|
60
|
+
title="Confirm"
|
|
61
|
+
onClose={(e) => console.log(e.detail.reason)}
|
|
62
|
+
>
|
|
63
|
+
<p>Are you sure?</p>
|
|
64
|
+
{#snippet footer()}
|
|
65
|
+
<Button label="OK" variant="filled" />
|
|
66
|
+
{/snippet}
|
|
67
|
+
</Dialog>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Event Callbacks
|
|
71
|
+
|
|
72
|
+
Svelte 5 uses callback props instead of `on:event` directives:
|
|
73
|
+
|
|
74
|
+
```svelte
|
|
75
|
+
<TextInput
|
|
76
|
+
label="Email"
|
|
77
|
+
onInput={(e) => value = e.detail.value}
|
|
78
|
+
onChange={(e) => validate(e.detail.value)}
|
|
79
|
+
onFocus={(e) => focused = true}
|
|
80
|
+
onKeydown={(e) => {
|
|
81
|
+
if (e.detail.key === 'Enter') submit();
|
|
82
|
+
}}
|
|
83
|
+
/>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Callback props are typed: `(event: CustomEvent<InputDetail>) => void`.
|
|
87
|
+
|
|
88
|
+
### Imperative Methods
|
|
89
|
+
|
|
90
|
+
Components expose methods via `export function`. Access through `bind:this`:
|
|
91
|
+
|
|
92
|
+
```svelte
|
|
93
|
+
<script lang="ts">
|
|
94
|
+
import Select from '@colletdev/svelte/select.svelte';
|
|
95
|
+
|
|
96
|
+
let select: { open: () => void; close: () => void; focus: () => void };
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<Select bind:this={select} label="Country" items={countries} />
|
|
100
|
+
<button onclick={() => select.open()}>Open dropdown</button>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Named Slots (Snippets)
|
|
104
|
+
|
|
105
|
+
Svelte 5 uses `{#snippet}` for named slots:
|
|
106
|
+
|
|
107
|
+
```svelte
|
|
108
|
+
<Card>
|
|
109
|
+
{#snippet header()}
|
|
110
|
+
<h3>Title</h3>
|
|
111
|
+
{/snippet}
|
|
112
|
+
|
|
113
|
+
<p>Body content (default slot via children)</p>
|
|
114
|
+
|
|
115
|
+
{#snippet footer()}
|
|
116
|
+
<Button label="Action" />
|
|
117
|
+
{/snippet}
|
|
118
|
+
</Card>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The wrapper renders snippets inside `<div slot="name">` wrappers for
|
|
122
|
+
Shadow DOM slot projection.
|
|
123
|
+
|
|
124
|
+
### Complex Props (Structured Data)
|
|
125
|
+
|
|
126
|
+
Props accepting arrays/objects are synced via `$effect` + `setAttribute(JSON.stringify())`:
|
|
127
|
+
|
|
128
|
+
```svelte
|
|
129
|
+
<Table
|
|
130
|
+
caption="Users"
|
|
131
|
+
columns={[
|
|
132
|
+
{ id: 'name', header: 'Name', sortable: true },
|
|
133
|
+
{ id: 'email', header: 'Email' },
|
|
134
|
+
]}
|
|
135
|
+
rows={rows}
|
|
136
|
+
sorts={[{ column_id: 'name', direction: 'asc' }]}
|
|
137
|
+
onSort={(e) => handleSort(e.detail)}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Form Integration
|
|
142
|
+
|
|
143
|
+
```svelte
|
|
144
|
+
<form onsubmit={handleSubmit}>
|
|
145
|
+
<TextInput name="email" label="Email" required />
|
|
146
|
+
<Select name="country" label="Country" items={countries} />
|
|
147
|
+
<Button label="Submit" kind="submit" />
|
|
148
|
+
</form>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### DOM Collision Handling
|
|
152
|
+
|
|
153
|
+
Attributes like `title`, `width`, `loading` are routed through `$effect` +
|
|
154
|
+
`setAttribute` to avoid Svelte setting them as DOM properties:
|
|
155
|
+
|
|
156
|
+
```svelte
|
|
157
|
+
<!-- Works correctly -->
|
|
158
|
+
<Dialog title="My Dialog" />
|
|
159
|
+
<Table loading={75} />
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## TypeScript
|
|
165
|
+
|
|
166
|
+
### Type Imports
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import type {
|
|
170
|
+
TableColumn, TableRow, SelectOption, MenuEntry,
|
|
171
|
+
InputDetail, ClickDetail, CloseDetail,
|
|
172
|
+
} from '@colletdev/svelte';
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Component Types
|
|
176
|
+
|
|
177
|
+
Each `.svelte` file has a `.svelte.d.ts` companion with full prop types:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import type { Component } from 'svelte';
|
|
181
|
+
|
|
182
|
+
interface ButtonProps {
|
|
183
|
+
label?: string;
|
|
184
|
+
variant?: 'filled' | 'ghost' | 'outline' | 'underline' | 'side-indicator';
|
|
185
|
+
// ... all props typed
|
|
186
|
+
onClick?: (event: CustomEvent<ClickDetail>) => void;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
declare const Button: Component<ButtonProps, { /* exports */ }>;
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### SvelteHTMLElements Augmentation
|
|
193
|
+
|
|
194
|
+
`@colletdev/svelte` augments `SvelteHTMLElements` for direct Custom Element usage:
|
|
195
|
+
|
|
196
|
+
```svelte
|
|
197
|
+
<!-- Type-checked cx-* elements -->
|
|
198
|
+
<cx-button label="Raw CE" variant="filled" />
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Import the augmentation in `app.d.ts`:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
/// <reference types="@colletdev/svelte/elements" />
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Svelte 5 Migration Notes
|
|
210
|
+
|
|
211
|
+
The wrappers are Svelte 5 native. Key differences from Svelte 4:
|
|
212
|
+
|
|
213
|
+
| Svelte 4 | Svelte 5 (Collet) |
|
|
214
|
+
|----------|-------------------|
|
|
215
|
+
| `export let prop` | `let { prop } = $props()` |
|
|
216
|
+
| `on:click` | `onclick` callback prop |
|
|
217
|
+
| `<slot />` | `{@render children?.()}` |
|
|
218
|
+
| `<slot name="x" />` | `{@render x?.()}` |
|
|
219
|
+
| `onMount(() => {})` | `$effect(() => { ... })` |
|
|
220
|
+
| `$: derived` | `let derived = $derived(...)` |
|
|
221
|
+
| `SvelteComponent` | `Component` type |
|
|
222
|
+
| `createEventDispatcher` | Callback props |
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Codegen
|
|
227
|
+
|
|
228
|
+
Svelte wrappers are generated by `scripts/generate-svelte.mjs`. Configuration
|
|
229
|
+
lives in `scripts/component-config.mjs` (shared across all framework generators).
|
|
230
|
+
|
|
231
|
+
**Do not edit** files in `packages/svelte/src/` — they are overwritten by
|
|
232
|
+
`bash scripts/build-packages.sh`.
|
|
233
|
+
|
|
234
|
+
Raw source ships to consumers (no pre-compilation needed).
|