svelte-origin 0.0.0 → 1.0.0-next.49
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/LLM.md +545 -0
- package/README.md +678 -1
- package/dist/aliases.d.ts +45 -0
- package/dist/cli.d.ts +20 -0
- package/dist/cli.js +163 -0
- package/dist/generate-dts.d.ts +31 -0
- package/dist/globals.d.ts +649 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +108 -0
- package/dist/plugin.d.ts +176 -0
- package/dist/plugin.js +81 -0
- package/dist/post-process.d.ts +31 -0
- package/dist/post-process.js +99 -0
- package/dist/preprocess.d.ts +119 -0
- package/dist/preprocess.js +81 -0
- package/dist/runtime/attrs.d.ts +65 -0
- package/dist/runtime/index.d.ts +8 -0
- package/dist/runtime/index.js +28 -0
- package/dist/runtime/origin.d.ts +170 -0
- package/dist/runtime/types.d.ts +193 -0
- package/dist/runtime-inline.d.ts +117 -0
- package/dist/runtime-inline.min.js +1 -0
- package/dist/schema-resolver.d.ts +61 -0
- package/dist/shared-state.d.ts +47 -0
- package/dist/transform/ast-parser.d.ts +282 -0
- package/dist/transform/attrs-for-transform.d.ts +17 -0
- package/dist/transform/attrs-origin-transform.d.ts +38 -0
- package/dist/transform/attrs-schema.d.ts +63 -0
- package/dist/transform/codegen.d.ts +15 -0
- package/dist/transform/comments.d.ts +31 -0
- package/dist/transform/core.d.ts +37 -0
- package/dist/transform/declaration-parser.d.ts +77 -0
- package/dist/transform/element-types.d.ts +10 -0
- package/dist/transform/expression-utils.d.ts +59 -0
- package/dist/transform/origin-body-helpers.d.ts +143 -0
- package/dist/transform/origin-create-transform.d.ts +32 -0
- package/dist/transform/origin-destructure-transform.d.ts +62 -0
- package/dist/transform/origin-transform.d.ts +51 -0
- package/dist/transform/patterns.d.ts +86 -0
- package/dist/transform/reserved-keywords.d.ts +87 -0
- package/dist/transform/schema-codegen.d.ts +105 -0
- package/dist/transform/schema-parse.d.ts +50 -0
- package/dist/transform/schema-types.d.ts +40 -0
- package/dist/transform/schema.d.ts +11 -0
- package/dist/transform/standalone-attrs-transform.d.ts +36 -0
- package/dist/utils.d.ts +21 -0
- package/dist/vite-dts.d.ts +17 -0
- package/dist/vite-dts.js +24 -0
- package/package.json +79 -3
package/LLM.md
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
# svelte-origin - LLM Reference
|
|
2
|
+
|
|
3
|
+
> Quick-reference documentation for LLM assistance with svelte-origin v3.0
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`svelte-origin` provides a macro-based system for defining reusable state + props + methods patterns in Svelte 5. Origins are factories that create reactive instances with props, state, derived values, and methods.
|
|
8
|
+
|
|
9
|
+
**IMPORTANT**: This library uses **compile-time macros** (prefixed with `$`). These are transformed during build and do NOT exist at runtime.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The `$origin` Namespace
|
|
14
|
+
|
|
15
|
+
All macros live under the `$origin` namespace:
|
|
16
|
+
|
|
17
|
+
| Macro | Context | Description |
|
|
18
|
+
|-------|---------|-------------|
|
|
19
|
+
| `$origin({...})` | `.svelte.ts` files | Define an origin factory |
|
|
20
|
+
| `$origin.props({...})` | Anywhere | Define props schema with defaults |
|
|
21
|
+
| `$origin.component(Factory)` | ⚠️ `.svelte` only | Create origin from component `$props()` |
|
|
22
|
+
| `$origin.create(Factory, {...})` | ✅ Everywhere | Programmatic origin creation with reactivity |
|
|
23
|
+
| `$origin.bind(variable)` | Inside `$origin.create()` | Bind prop to existing reactive variable |
|
|
24
|
+
| `$origin.for(Factory)` | ⚠️ `.svelte` only | Forward props to child origin/element |
|
|
25
|
+
| `$origin.Props<typeof Factory>` | Type context | Extract component props type |
|
|
26
|
+
| `$origin.Of<typeof Factory>` | Type context | Extract origin instance type |
|
|
27
|
+
| `$bindable(value)` | Inside `$origin.props({})` | Mark a prop as two-way bindable |
|
|
28
|
+
|
|
29
|
+
### Context Restrictions
|
|
30
|
+
|
|
31
|
+
- ⚠️ **Component-only macros** (`$origin.component()`, `$origin.for()`): Using these in `.svelte.ts` or `.svelte.js` module files will throw a helpful compile-time error
|
|
32
|
+
- ✅ **Universal macros** (`$origin.create()`, `$origin.props()`): Work in any context
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Defining Origins (`.svelte.ts` files)
|
|
37
|
+
|
|
38
|
+
Origins are defined in `.svelte.ts` files using the `$origin()` macro:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// counter.svelte.ts
|
|
42
|
+
export const Counter = $origin({
|
|
43
|
+
props: $origin.props({
|
|
44
|
+
label: 'Counter', // Default string
|
|
45
|
+
count: $bindable(0), // Bindable number (two-way)
|
|
46
|
+
step: 1 // Default number
|
|
47
|
+
}),
|
|
48
|
+
|
|
49
|
+
// Internal state (not exposed - prefix with _)
|
|
50
|
+
_history: [] as number[],
|
|
51
|
+
|
|
52
|
+
// Derived values (use getters + $derived)
|
|
53
|
+
get doubled() {
|
|
54
|
+
return $derived(this.props.count * 2)
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Methods
|
|
58
|
+
increment() {
|
|
59
|
+
this._history.push(this.props.count)
|
|
60
|
+
this.props.count += this.props.step
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
decrement() {
|
|
64
|
+
this._history.push(this.props.count)
|
|
65
|
+
this.props.count -= this.props.step
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Key Rules for Origin Definitions
|
|
71
|
+
|
|
72
|
+
1. **Use `this.props.*`** to access props (not `props.*`)
|
|
73
|
+
2. **Use `$derived()`** for computed/derived values (must be inside a getter)
|
|
74
|
+
3. **Use `$bindable(defaultValue)`** for two-way bindable props
|
|
75
|
+
4. **Prefix with `_`** for internal/private state (convention - excluded from public types)
|
|
76
|
+
5. **Never use `$state()`** for props - props are automatically reactive
|
|
77
|
+
6. **Use `$state()`** for internal state (non-props) that needs reactivity
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Using Origins in Components
|
|
82
|
+
|
|
83
|
+
### `$origin.component(Factory)` — Standard Component Usage
|
|
84
|
+
|
|
85
|
+
**This is the ONLY way to use origins inside `.svelte` components when you want props to flow from the parent.**
|
|
86
|
+
|
|
87
|
+
> ⚠️ **Component-only:** This macro throws an error if used in `.svelte.ts` module files.
|
|
88
|
+
|
|
89
|
+
```svelte
|
|
90
|
+
<!-- Counter.svelte -->
|
|
91
|
+
<script lang="ts">
|
|
92
|
+
import { Counter } from './counter.svelte'
|
|
93
|
+
|
|
94
|
+
let counter = $origin.component(Counter)
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<div>
|
|
98
|
+
<span>{counter.props.label}: {counter.props.count}</span>
|
|
99
|
+
<button onclick={counter.increment}>+{counter.props.step}</button>
|
|
100
|
+
<button onclick={counter.decrement}>-{counter.props.step}</button>
|
|
101
|
+
<small>Doubled: {counter.doubled}</small>
|
|
102
|
+
</div>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**What happens at compile time:**
|
|
106
|
+
|
|
107
|
+
```svelte
|
|
108
|
+
<script lang="ts">
|
|
109
|
+
import { Counter } from './counter.svelte'
|
|
110
|
+
|
|
111
|
+
type $$Props = $origin.Props<typeof Counter>
|
|
112
|
+
let { label = 'Counter', count = $bindable(0), step = 1 } = $props()
|
|
113
|
+
let __attrs = {
|
|
114
|
+
get label() { return label },
|
|
115
|
+
get count() { return count },
|
|
116
|
+
set count(v) { count = v },
|
|
117
|
+
get step() { return step }
|
|
118
|
+
}
|
|
119
|
+
let counter = Counter(__attrs)
|
|
120
|
+
</script>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The component's props are **automatically extracted** from the origin's schema. The parent component can pass these props normally:
|
|
124
|
+
|
|
125
|
+
```svelte
|
|
126
|
+
<Counter label="My Counter" count={5} step={2} />
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Programmatic Origin Creation
|
|
132
|
+
|
|
133
|
+
### ⚠️ NEVER Call the Factory Directly
|
|
134
|
+
|
|
135
|
+
**WRONG** - This DOES NOT maintain reactivity:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
// ❌ BAD - Never do this!
|
|
139
|
+
const counter = Counter({
|
|
140
|
+
count: 0,
|
|
141
|
+
label: 'Test'
|
|
142
|
+
})
|
|
143
|
+
// counter.props.count = 5 ← This WON'T trigger reactivity!
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The input object `{ count: 0, label: 'Test' }` is a **plain object**, not a reactive proxy. Setting `counter.props.count` won't trigger Svelte's reactivity system.
|
|
147
|
+
|
|
148
|
+
### ✅ Use `$origin.create()` Instead
|
|
149
|
+
|
|
150
|
+
**CORRECT** - Use `$origin.create()` for programmatic creation:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// ✅ GOOD - Always use $origin.create()
|
|
154
|
+
const counter = $origin.create(Counter, {
|
|
155
|
+
count: 0,
|
|
156
|
+
label: 'Test'
|
|
157
|
+
})
|
|
158
|
+
// counter.props.count ← Readable, but NOT settable (read-only)
|
|
159
|
+
// counter.increment() ← Methods can still modify props internally!
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
> **Note:** Props passed directly are **read-only** (getter-only). To set props externally, use `$origin.bind()`.
|
|
163
|
+
|
|
164
|
+
### `$origin.create()` Works Everywhere
|
|
165
|
+
|
|
166
|
+
Unlike `$origin.component()` which only works in `.svelte` files, `$origin.create()` can be used in:
|
|
167
|
+
|
|
168
|
+
- ✅ `.svelte` component scripts
|
|
169
|
+
- ✅ `.svelte.ts` / `.svelte.js` module files
|
|
170
|
+
- ✅ Inside `$origin()` init callbacks
|
|
171
|
+
- ✅ Inside origin method bodies
|
|
172
|
+
- ✅ Module scripts (`<script module>`)
|
|
173
|
+
|
|
174
|
+
**What happens at compile time (regular props → getter-only):**
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
let __attrs = {
|
|
178
|
+
// Regular props are getter-only (read-only from outside)
|
|
179
|
+
get count() { return 0 },
|
|
180
|
+
get label() { return 'Test' }
|
|
181
|
+
}
|
|
182
|
+
const counter = Counter(__attrs)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**What happens with `$origin.bind()` (getter + setter):**
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
let myCount = $state(0)
|
|
189
|
+
let __attrs = {
|
|
190
|
+
get count() { return myCount },
|
|
191
|
+
set count(v) { myCount = v } // Two-way binding!
|
|
192
|
+
}
|
|
193
|
+
const counter = Counter(__attrs)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `$origin.bind(variable)` — Required for Settable Props
|
|
197
|
+
|
|
198
|
+
To set an origin's prop externally (or sync with existing state), you **must** use `$origin.bind()`:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
// In an origin's init or .svelte.ts file
|
|
202
|
+
let sharedItems = $state(['a', 'b', 'c'])
|
|
203
|
+
|
|
204
|
+
const list = $origin.create(ListOrigin, {
|
|
205
|
+
items: $origin.bind(sharedItems) // Two-way binding!
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
// Both are now in sync:
|
|
209
|
+
sharedItems.push('d') // list.props.items now includes 'd'
|
|
210
|
+
list.props.items = ['x'] // sharedItems is now ['x']
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Mix bound and unbound props:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
let count = $state(0)
|
|
217
|
+
|
|
218
|
+
const counter = $origin.create(Counter, {
|
|
219
|
+
count: $origin.bind(count), // Settable (two-way)
|
|
220
|
+
label: 'My Counter', // Read-only
|
|
221
|
+
step: 2 // Read-only
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
counter.props.count = 10 // ✅ Works - updates `count` too
|
|
225
|
+
counter.props.label = 'New' // ❌ No effect (read-only)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Prop Forwarding
|
|
231
|
+
|
|
232
|
+
### `$origin.for(Factory)` — Forward Props to Child
|
|
233
|
+
|
|
234
|
+
> ⚠️ **Component-only:** This macro throws an error if used in `.svelte.ts` module files.
|
|
235
|
+
|
|
236
|
+
Use in wrapper components that need to pass props through:
|
|
237
|
+
|
|
238
|
+
```svelte
|
|
239
|
+
<!-- Wrapper.svelte -->
|
|
240
|
+
<script lang="ts">
|
|
241
|
+
import { Counter } from './counter.svelte'
|
|
242
|
+
import CounterComponent from './Counter.svelte'
|
|
243
|
+
|
|
244
|
+
let counterProps = $origin.for(Counter)
|
|
245
|
+
</script>
|
|
246
|
+
|
|
247
|
+
<div class="wrapper">
|
|
248
|
+
<CounterComponent {...counterProps} />
|
|
249
|
+
</div>
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### `$origin.for('element')` — Forward Props to HTML Elements
|
|
253
|
+
|
|
254
|
+
```svelte
|
|
255
|
+
<!-- CustomInput.svelte -->
|
|
256
|
+
<script lang="ts">
|
|
257
|
+
let inputProps = $origin.for('input')
|
|
258
|
+
</script>
|
|
259
|
+
|
|
260
|
+
<input {...inputProps} class="custom-input" />
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Inheritance
|
|
266
|
+
|
|
267
|
+
Origins can extend other origins using array syntax:
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
// base.svelte.ts
|
|
271
|
+
export const BaseCounter = $origin({
|
|
272
|
+
props: $origin.props({
|
|
273
|
+
count: $bindable(0)
|
|
274
|
+
}),
|
|
275
|
+
|
|
276
|
+
increment() {
|
|
277
|
+
this.props.count++
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
// extended.svelte.ts
|
|
282
|
+
export const ExtendedCounter = $origin([BaseCounter], {
|
|
283
|
+
props: $origin.props({
|
|
284
|
+
step: 1 // Additional prop (merged with parent)
|
|
285
|
+
}),
|
|
286
|
+
|
|
287
|
+
// Override with super call
|
|
288
|
+
increment() {
|
|
289
|
+
this.super.increment() // Call parent
|
|
290
|
+
console.log('Incremented!')
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
// New method
|
|
294
|
+
incrementByStep() {
|
|
295
|
+
this.props.count += this.props.step
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Inheritance Rules
|
|
301
|
+
|
|
302
|
+
1. Child props are **merged** with parent props (left-to-right, child overrides)
|
|
303
|
+
2. Use `this.super.*` to call parent methods
|
|
304
|
+
3. Child methods override parent methods with same name
|
|
305
|
+
4. Derived values can be overridden
|
|
306
|
+
5. Multi-level inheritance works: `this.super.super.*` for grandparent
|
|
307
|
+
|
|
308
|
+
### Standalone Props Inheritance
|
|
309
|
+
|
|
310
|
+
Props can also inherit from other props schemas:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
export const BaseAttrs = $origin.props({
|
|
314
|
+
id: '',
|
|
315
|
+
class: ''
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
export const WidgetAttrs = $origin.props([BaseAttrs], {
|
|
319
|
+
label: 'Widget',
|
|
320
|
+
active: false
|
|
321
|
+
})
|
|
322
|
+
// WidgetAttrs has: id, class, label, active
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Type Helpers
|
|
328
|
+
|
|
329
|
+
### `$origin.Props<typeof Factory>`
|
|
330
|
+
|
|
331
|
+
Extract the component props type from an origin factory. Useful for typing in non-component contexts:
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
import { Counter } from './counter.svelte'
|
|
335
|
+
|
|
336
|
+
// Use in utility functions or type definitions
|
|
337
|
+
function processProps(props: $origin.Props<typeof Counter>) {
|
|
338
|
+
console.log(props.count)
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
> ⚠️ **Anti-pattern:** Do NOT manually declare `type $$Props = ...` in `.svelte` components.
|
|
343
|
+
> `svelte-origin` automatically generates the correct `$$Props` type from the origin schema.
|
|
344
|
+
> Manually declaring it can cause type mismatches and breaks the automatic prop extraction.
|
|
345
|
+
|
|
346
|
+
### `$origin.Of<typeof Factory>`
|
|
347
|
+
|
|
348
|
+
Extract the instance type from an origin factory:
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
import { Counter } from './counter.svelte'
|
|
352
|
+
|
|
353
|
+
// Type a variable that will hold an origin instance
|
|
354
|
+
let counter: $origin.Of<typeof Counter>
|
|
355
|
+
|
|
356
|
+
// Useful for optional or lazy initialization
|
|
357
|
+
let maybeCounter: $origin.Of<typeof Counter> | undefined = undefined
|
|
358
|
+
|
|
359
|
+
// Also works with generic factories
|
|
360
|
+
const List = <T>() => $origin({ props: $origin.props({ items: [] as T[] }) })
|
|
361
|
+
type StringListInstance = $origin.Of<ReturnType<typeof List<string>>>
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Reactivity Internals
|
|
367
|
+
|
|
368
|
+
### How Props Become Reactive
|
|
369
|
+
|
|
370
|
+
Origins use **getter/setter pairs** to maintain reactivity. The key distinction:
|
|
371
|
+
|
|
372
|
+
| Source | Props become | Settable externally? |
|
|
373
|
+
|--------|--------------|---------------------|
|
|
374
|
+
| `$origin.component()` | Connected to `$props()` | ✅ Bindable props only |
|
|
375
|
+
| `$origin.create({ prop: value })` | Getter-only | ❌ No |
|
|
376
|
+
| `$origin.create({ prop: $origin.bind(var) })` | Getter + setter | ✅ Yes |
|
|
377
|
+
|
|
378
|
+
**Getter-only props (default for `$origin.create`):**
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
// Input
|
|
382
|
+
$origin.create(Counter, { count: 0 })
|
|
383
|
+
|
|
384
|
+
// Output - getter-only
|
|
385
|
+
let __attrs = { get count() { return 0 } }
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Getter + setter props (with `$origin.bind`):**
|
|
389
|
+
|
|
390
|
+
```ts
|
|
391
|
+
// Input
|
|
392
|
+
let count = $state(0)
|
|
393
|
+
$origin.create(Counter, { count: $origin.bind(count) })
|
|
394
|
+
|
|
395
|
+
// Output - getter AND setter
|
|
396
|
+
let __attrs = {
|
|
397
|
+
get count() { return count },
|
|
398
|
+
set count(v) { count = v }
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Why Internal Methods Still Work
|
|
403
|
+
|
|
404
|
+
Even though external setting doesn't work for regular props, **origin methods** can still modify props internally because they work through `this.props.*` which bypasses the external getter-only constraint:
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
// Origin method can modify props
|
|
408
|
+
increment() {
|
|
409
|
+
this.props.count++ // ✅ Works - internal modification
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Common Patterns
|
|
416
|
+
|
|
417
|
+
### State Machine Origin
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
export const StateMachine = $origin({
|
|
421
|
+
props: $origin.props({
|
|
422
|
+
initial: 'idle' as 'idle' | 'loading' | 'success' | 'error'
|
|
423
|
+
}),
|
|
424
|
+
|
|
425
|
+
_currentState: null as string | null,
|
|
426
|
+
|
|
427
|
+
get state() {
|
|
428
|
+
return $derived(this._currentState ?? this.props.initial)
|
|
429
|
+
},
|
|
430
|
+
|
|
431
|
+
transition(to: string) {
|
|
432
|
+
this._currentState = to
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
get isLoading() {
|
|
436
|
+
return $derived(this.state === 'loading')
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Form Field Origin
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
export const FormField = $origin({
|
|
445
|
+
props: $origin.props({
|
|
446
|
+
value: $bindable(''),
|
|
447
|
+
label: '',
|
|
448
|
+
required: false,
|
|
449
|
+
validate: ((v: string) => true) as (v: string) => boolean | string
|
|
450
|
+
}),
|
|
451
|
+
|
|
452
|
+
_touched: false,
|
|
453
|
+
|
|
454
|
+
get error() {
|
|
455
|
+
if (!this._touched) return null
|
|
456
|
+
const result = this.props.validate(this.props.value)
|
|
457
|
+
return $derived(result === true ? null : result)
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
get isValid() {
|
|
461
|
+
return $derived(this.error === null)
|
|
462
|
+
},
|
|
463
|
+
|
|
464
|
+
touch() {
|
|
465
|
+
this._touched = true
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
reset() {
|
|
469
|
+
this.props.value = ''
|
|
470
|
+
this._touched = false
|
|
471
|
+
}
|
|
472
|
+
})
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Composing Origins
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
// Create child origin inside parent using init callback
|
|
479
|
+
export const Parent = $origin({
|
|
480
|
+
props: $origin.props({
|
|
481
|
+
items: [] as string[]
|
|
482
|
+
}),
|
|
483
|
+
|
|
484
|
+
// Child origin with bound props
|
|
485
|
+
_child: null as ReturnType<typeof ChildOrigin> | null
|
|
486
|
+
}, function() {
|
|
487
|
+
// Init callback - runs when instance is created
|
|
488
|
+
this._child = $origin.create(ChildOrigin, {
|
|
489
|
+
items: $origin.bind(this.props.items) // Sync with parent
|
|
490
|
+
})
|
|
491
|
+
})
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Quick Reference
|
|
497
|
+
|
|
498
|
+
### File Types & Allowed Macros
|
|
499
|
+
|
|
500
|
+
| Extension | Purpose | Macros Available |
|
|
501
|
+
|-----------|---------|------------------|
|
|
502
|
+
| `.svelte.ts` | Origin definitions | `$origin()`, `$origin.props()`, `$origin.create()`, `$origin.bind()`, `$bindable()` |
|
|
503
|
+
| `.svelte` | Svelte components | `$origin.component()`, `$origin.for()`, `$origin.create()`, `$origin.bind()` |
|
|
504
|
+
|
|
505
|
+
### Context-Specific Macros
|
|
506
|
+
|
|
507
|
+
| Macro | `.svelte` | `.svelte.ts` | Init callbacks |
|
|
508
|
+
|-------|:---------:|:------------:|:--------------:|
|
|
509
|
+
| `$origin.component()` | ✅ | ❌ throws | ❌ throws |
|
|
510
|
+
| `$origin.for()` | ✅ | ❌ throws | ❌ throws |
|
|
511
|
+
| `$origin.create()` | ✅ | ✅ | ✅ |
|
|
512
|
+
| `$origin.bind()` | ✅ | ✅ | ✅ |
|
|
513
|
+
| `$origin.props()` | ✅ | ✅ | ✅ |
|
|
514
|
+
|
|
515
|
+
### Do's and Don'ts
|
|
516
|
+
|
|
517
|
+
| ✅ DO | ❌ DON'T |
|
|
518
|
+
|-------|----------|
|
|
519
|
+
| Use `$origin.component(Factory)` in `.svelte` components | Use `$origin.component()` in `.svelte.ts` files |
|
|
520
|
+
| Use `$origin.create(Factory, props)` for programmatic creation | Call `Factory({...})` directly (breaks reactivity) |
|
|
521
|
+
| Use `$origin.bind(variable)` for two-way shared state | Pass reactive variables without binding |
|
|
522
|
+
| Use `$derived()` for computed values in getters | Use `$state()` for props (they're already reactive) |
|
|
523
|
+
| Access props via `this.props.*` | Destructure props at top level of definition |
|
|
524
|
+
| Prefix private state with `_` | Expose internal state publicly |
|
|
525
|
+
| Let svelte-origin auto-generate `$$Props` | Manually declare `type $$Props = ...` |
|
|
526
|
+
| Use `$origin.Of<typeof F>` for instance types | Use `ReturnType<typeof F>` (less inference) |
|
|
527
|
+
| Use `$origin.Props<typeof F>` for type utilities | Use `$$Props` directly in component code |
|
|
528
|
+
|
|
529
|
+
### Common LLM Pitfalls
|
|
530
|
+
|
|
531
|
+
1. **Calling factory directly** - `Counter({...})` loses reactivity. Always use `$origin.create()` or `$origin.component()`.
|
|
532
|
+
|
|
533
|
+
2. **Using `$origin.component()` in module files** - This only works in `.svelte` files. In `.svelte.ts`, use `$origin.create()`.
|
|
534
|
+
|
|
535
|
+
3. **Using `$origin.for()` in module files** - This only works in `.svelte` files.
|
|
536
|
+
|
|
537
|
+
4. **Forgetting `this.props`** - Inside origins, always use `this.props.count`, not just `count` or `props.count`.
|
|
538
|
+
|
|
539
|
+
5. **Using `$state()` for props** - Props passed to `$origin.props({...})` are automatically reactive. Don't wrap defaults in `$state()`.
|
|
540
|
+
|
|
541
|
+
6. **Missing `$derived()` in getters** - Computed values must use `$derived()` inside getters for reactivity.
|
|
542
|
+
|
|
543
|
+
7. **Expecting settable props without `$origin.bind()`** - Props in `$origin.create({ prop: value })` are **read-only**. To set props externally, use `$origin.bind(variable)`.
|
|
544
|
+
|
|
545
|
+
8. **Manually declaring `$$Props`** - Never write `type $$Props = ...` in components using `$origin.component()`. The transformer auto-generates this from the origin schema. Manual declarations cause type conflicts and may break prop extraction. Ensure `svelte.config.js` includes the svelte-origin preprocessor for proper type generation.
|