@pyreon/mcp 0.11.4 → 0.11.6
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 +9 -9
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/package.json +13 -13
- package/src/api-reference.ts +176 -176
- package/src/index.ts +43 -43
- package/src/project-scanner.ts +1 -1
- package/src/tests/api-reference.test.ts +4 -4
- package/src/tests/project-scanner.test.ts +82 -82
package/src/api-reference.ts
CHANGED
|
@@ -17,8 +17,8 @@ export const API_REFERENCE: Record<string, ApiEntry> = {
|
|
|
17
17
|
// @pyreon/reactivity
|
|
18
18
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
signature:
|
|
20
|
+
'reactivity/signal': {
|
|
21
|
+
signature: 'signal<T>(initialValue: T, options?: { name?: string }): Signal<T>',
|
|
22
22
|
example: `const count = signal(0)
|
|
23
23
|
|
|
24
24
|
// Read (subscribes to updates):
|
|
@@ -33,15 +33,15 @@ count.update(n => n + 1) // 6
|
|
|
33
33
|
// Read without subscribing:
|
|
34
34
|
count.peek() // 6`,
|
|
35
35
|
notes:
|
|
36
|
-
|
|
36
|
+
'Signals are callable functions, NOT .value getters. Components run once — signal reads in JSX auto-subscribe. Optional { name } for debugging — auto-injected by @pyreon/vite-plugin in dev mode.',
|
|
37
37
|
mistakes: `- \`count.value\` → Use \`count()\` to read
|
|
38
38
|
- \`{count}\` in JSX → Use \`{count()}\` to read (or let the compiler wrap it)
|
|
39
39
|
- \`const [val, setVal] = signal(0)\` → Not destructurable. Use \`const val = signal(0)\``,
|
|
40
40
|
},
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
'reactivity/computed': {
|
|
43
43
|
signature:
|
|
44
|
-
|
|
44
|
+
'computed<T>(fn: () => T, options?: { equals?: (a: T, b: T) => boolean }): Computed<T>',
|
|
45
45
|
example: `const count = signal(0)
|
|
46
46
|
const doubled = computed(() => count() * 2)
|
|
47
47
|
|
|
@@ -49,13 +49,13 @@ doubled() // 0
|
|
|
49
49
|
count.set(5)
|
|
50
50
|
doubled() // 10`,
|
|
51
51
|
notes:
|
|
52
|
-
|
|
52
|
+
'Dependencies auto-tracked. No dependency array needed. Memoized — only recomputes when dependencies change.',
|
|
53
53
|
mistakes: `- \`computed(() => count)\` → Must call signal: \`computed(() => count())\`
|
|
54
54
|
- Don't use for side effects — use effect() instead`,
|
|
55
55
|
},
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
signature:
|
|
57
|
+
'reactivity/effect': {
|
|
58
|
+
signature: 'effect(fn: () => (() => void) | void): () => void',
|
|
59
59
|
example: `const count = signal(0)
|
|
60
60
|
|
|
61
61
|
// Auto-tracks count() dependency:
|
|
@@ -77,26 +77,26 @@ effect(() => {
|
|
|
77
77
|
return () => window.removeEventListener("resize", handler)
|
|
78
78
|
})`,
|
|
79
79
|
notes:
|
|
80
|
-
|
|
80
|
+
'Returns a dispose function. Dependencies auto-tracked on each run. Use onCleanup() inside to register cleanup that runs before re-execution. For DOM-specific effects, use renderEffect().',
|
|
81
81
|
mistakes: `- Don't pass a dependency array — Pyreon auto-tracks
|
|
82
82
|
- \`effect(() => { count })\` → Must call: \`effect(() => { count() })\``,
|
|
83
83
|
},
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
signature:
|
|
85
|
+
'reactivity/onCleanup': {
|
|
86
|
+
signature: 'onCleanup(fn: () => void): void',
|
|
87
87
|
example: `effect(() => {
|
|
88
88
|
const handler = () => console.log(count())
|
|
89
89
|
window.addEventListener("resize", handler)
|
|
90
90
|
onCleanup(() => window.removeEventListener("resize", handler))
|
|
91
91
|
})`,
|
|
92
92
|
notes:
|
|
93
|
-
|
|
93
|
+
'Registers a cleanup function inside an effect. Runs between re-executions (before the effect re-runs) and when the effect is disposed.',
|
|
94
94
|
mistakes: `- Using onCleanup outside an effect — it only works inside effect() or renderEffect()
|
|
95
95
|
- Confusing with onUnmount — onCleanup is for effects, onUnmount is for components`,
|
|
96
96
|
},
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
signature:
|
|
98
|
+
'reactivity/batch': {
|
|
99
|
+
signature: 'batch(fn: () => void): void',
|
|
100
100
|
example: `const a = signal(1)
|
|
101
101
|
const b = signal(2)
|
|
102
102
|
|
|
@@ -105,11 +105,11 @@ batch(() => {
|
|
|
105
105
|
a.set(10)
|
|
106
106
|
b.set(20)
|
|
107
107
|
})`,
|
|
108
|
-
notes:
|
|
108
|
+
notes: 'Defers all signal notifications until the batch completes. Nested batches are merged.',
|
|
109
109
|
},
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
signature:
|
|
111
|
+
'reactivity/createStore': {
|
|
112
|
+
signature: 'createStore<T extends object>(initialValue: T): T',
|
|
113
113
|
example: `const store = createStore({
|
|
114
114
|
user: { name: "Alice", age: 30 },
|
|
115
115
|
items: [1, 2, 3]
|
|
@@ -119,12 +119,12 @@ batch(() => {
|
|
|
119
119
|
store.user.name = "Bob" // only name subscribers fire
|
|
120
120
|
store.items.push(4) // only items subscribers fire`,
|
|
121
121
|
notes:
|
|
122
|
-
|
|
122
|
+
'Deep proxy — nested objects are automatically reactive. Use reconcile() for bulk updates.',
|
|
123
123
|
},
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
'reactivity/createResource': {
|
|
126
126
|
signature:
|
|
127
|
-
|
|
127
|
+
'createResource<T>(fetcher: () => Promise<T>, options?: ResourceOptions): Resource<T>',
|
|
128
128
|
example: `const users = createResource(() => fetch("/api/users").then(r => r.json()))
|
|
129
129
|
|
|
130
130
|
// In JSX:
|
|
@@ -134,11 +134,11 @@ store.items.push(4) // only items subscribers fire`,
|
|
|
134
134
|
</For>
|
|
135
135
|
</Show>`,
|
|
136
136
|
notes:
|
|
137
|
-
|
|
137
|
+
'Integrates with Suspense. Access .loading(), .error(), and call resource() for the value.',
|
|
138
138
|
},
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
signature:
|
|
140
|
+
'reactivity/untrack': {
|
|
141
|
+
signature: 'untrack<T>(fn: () => T): T',
|
|
142
142
|
example: `import { untrack } from "@pyreon/reactivity"
|
|
143
143
|
|
|
144
144
|
// Read signals without subscribing:
|
|
@@ -147,26 +147,26 @@ effect(() => {
|
|
|
147
147
|
console.log("Count changed:", count(), "user is", name)
|
|
148
148
|
})`,
|
|
149
149
|
notes:
|
|
150
|
-
|
|
150
|
+
'Alias for runUntracked. Reads signals inside fn without adding them as dependencies of the current effect/computed.',
|
|
151
151
|
},
|
|
152
152
|
|
|
153
153
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
154
154
|
// @pyreon/core
|
|
155
155
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
'core/h': {
|
|
158
158
|
signature:
|
|
159
|
-
|
|
159
|
+
'h<P>(type: ComponentFn<P> | string | symbol, props: P | null, ...children: VNodeChild[]): VNode',
|
|
160
160
|
example: `// Usually use JSX instead:
|
|
161
161
|
const vnode = h("div", { class: "container" },
|
|
162
162
|
h("h1", null, "Hello"),
|
|
163
163
|
h(Counter, { initial: 0 })
|
|
164
164
|
)`,
|
|
165
|
-
notes:
|
|
165
|
+
notes: 'Low-level API. Prefer JSX which compiles to h() calls (or _tpl() for templates).',
|
|
166
166
|
},
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
signature:
|
|
168
|
+
'core/Fragment': {
|
|
169
|
+
signature: 'Fragment: symbol',
|
|
170
170
|
example: `// JSX:
|
|
171
171
|
<>
|
|
172
172
|
<h1>Title</h1>
|
|
@@ -177,8 +177,8 @@ const vnode = h("div", { class: "container" },
|
|
|
177
177
|
h(Fragment, null, h("h1", null, "Title"), h("p", null, "Content"))`,
|
|
178
178
|
},
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
signature:
|
|
180
|
+
'core/onMount': {
|
|
181
|
+
signature: 'onMount(fn: () => CleanupFn | void): void',
|
|
182
182
|
example: `const Timer = () => {
|
|
183
183
|
const count = signal(0)
|
|
184
184
|
|
|
@@ -189,19 +189,19 @@ h(Fragment, null, h("h1", null, "Title"), h("p", null, "Content"))`,
|
|
|
189
189
|
|
|
190
190
|
return <div>{count()}</div>
|
|
191
191
|
}`,
|
|
192
|
-
notes:
|
|
192
|
+
notes: 'Optionally return a cleanup function that runs on unmount.',
|
|
193
193
|
mistakes: `- Forgetting cleanup: \`onMount(() => { const id = setInterval(...) })\` → Return cleanup: \`onMount(() => { const id = setInterval(...); return () => clearInterval(id) })\``,
|
|
194
194
|
},
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
signature:
|
|
196
|
+
'core/onUnmount': {
|
|
197
|
+
signature: 'onUnmount(fn: () => void): void',
|
|
198
198
|
example: `onUnmount(() => {
|
|
199
199
|
console.log("Component removed from DOM")
|
|
200
200
|
})`,
|
|
201
201
|
},
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
signature:
|
|
203
|
+
'core/createContext': {
|
|
204
|
+
signature: 'createContext<T>(defaultValue: T): Context<T>',
|
|
205
205
|
example: `const ThemeContext = createContext<"light" | "dark">("light")
|
|
206
206
|
|
|
207
207
|
// Provide:
|
|
@@ -217,13 +217,13 @@ const Child = () => {
|
|
|
217
217
|
}`,
|
|
218
218
|
},
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
signature:
|
|
220
|
+
'core/useContext': {
|
|
221
|
+
signature: 'useContext<T>(ctx: Context<T>): T',
|
|
222
222
|
example: `const theme = useContext(ThemeContext) // returns provided value or default`,
|
|
223
223
|
},
|
|
224
224
|
|
|
225
|
-
|
|
226
|
-
signature:
|
|
225
|
+
'core/provide': {
|
|
226
|
+
signature: 'provide<T>(ctx: Context<T>, value: T): void',
|
|
227
227
|
example: `const ThemeCtx = createContext<"light" | "dark">("light")
|
|
228
228
|
|
|
229
229
|
function App() {
|
|
@@ -231,21 +231,21 @@ function App() {
|
|
|
231
231
|
return <Child />
|
|
232
232
|
}`,
|
|
233
233
|
notes:
|
|
234
|
-
|
|
234
|
+
'Pushes a context value and auto-cleans up on unmount. Preferred over manual pushContext/popContext. Must be called during component setup.',
|
|
235
235
|
},
|
|
236
236
|
|
|
237
|
-
|
|
238
|
-
signature:
|
|
237
|
+
'core/ExtractProps': {
|
|
238
|
+
signature: 'type ExtractProps<T> = T extends ComponentFn<infer P> ? P : T',
|
|
239
239
|
example: `const Greet: ComponentFn<{ name: string }> = ({ name }) => <h1>{name}</h1>
|
|
240
240
|
|
|
241
241
|
type Props = ExtractProps<typeof Greet>
|
|
242
242
|
// { name: string }`,
|
|
243
243
|
notes:
|
|
244
|
-
|
|
244
|
+
'Extracts the props type from a ComponentFn. Passes through unchanged if T is not a ComponentFn.',
|
|
245
245
|
},
|
|
246
246
|
|
|
247
|
-
|
|
248
|
-
signature:
|
|
247
|
+
'core/HigherOrderComponent': {
|
|
248
|
+
signature: 'type HigherOrderComponent<HOP, P> = ComponentFn<HOP & P>',
|
|
249
249
|
example: `function withLogger<P>(Wrapped: ComponentFn<P>): HigherOrderComponent<{ logLevel?: string }, P> {
|
|
250
250
|
return (props) => {
|
|
251
251
|
console.log(\`[\${props.logLevel ?? "info"}] Rendering\`)
|
|
@@ -256,8 +256,8 @@ type Props = ExtractProps<typeof Greet>
|
|
|
256
256
|
"Typed HOC pattern — HOP is the props the HOC adds, P is the wrapped component's own props.",
|
|
257
257
|
},
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
signature:
|
|
259
|
+
'core/For': {
|
|
260
|
+
signature: '<For each={items} by={keyFn}>{renderFn}</For>',
|
|
261
261
|
example: `const items = signal([
|
|
262
262
|
{ id: 1, name: "Apple" },
|
|
263
263
|
{ id: 2, name: "Banana" },
|
|
@@ -272,17 +272,17 @@ type Props = ExtractProps<typeof Greet>
|
|
|
272
272
|
- \`{items().map(...)}\` → Use <For> for reactive list rendering`,
|
|
273
273
|
},
|
|
274
274
|
|
|
275
|
-
|
|
276
|
-
signature:
|
|
275
|
+
'core/Show': {
|
|
276
|
+
signature: '<Show when={condition} fallback={alternative}>{children}</Show>',
|
|
277
277
|
example: `<Show when={isLoggedIn()} fallback={<LoginForm />}>
|
|
278
278
|
<Dashboard />
|
|
279
279
|
</Show>`,
|
|
280
280
|
notes:
|
|
281
|
-
|
|
281
|
+
'More efficient than ternary for signal-driven conditions. Only mounts/unmounts when condition changes.',
|
|
282
282
|
},
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
signature:
|
|
284
|
+
'core/Suspense': {
|
|
285
|
+
signature: '<Suspense fallback={loadingUI}>{children}</Suspense>',
|
|
286
286
|
example: `const LazyPage = lazy(() => import("./HeavyPage"))
|
|
287
287
|
|
|
288
288
|
<Suspense fallback={<div>Loading...</div>}>
|
|
@@ -290,9 +290,9 @@ type Props = ExtractProps<typeof Greet>
|
|
|
290
290
|
</Suspense>`,
|
|
291
291
|
},
|
|
292
292
|
|
|
293
|
-
|
|
293
|
+
'core/lazy': {
|
|
294
294
|
signature:
|
|
295
|
-
|
|
295
|
+
'lazy(loader: () => Promise<{ default: ComponentFn }>, options?: LazyOptions): LazyComponent',
|
|
296
296
|
example: `const Settings = lazy(() => import("./pages/Settings"))
|
|
297
297
|
|
|
298
298
|
// Use in JSX (wrap with Suspense):
|
|
@@ -301,16 +301,16 @@ type Props = ExtractProps<typeof Greet>
|
|
|
301
301
|
</Suspense>`,
|
|
302
302
|
},
|
|
303
303
|
|
|
304
|
-
|
|
305
|
-
signature:
|
|
304
|
+
'core/Dynamic': {
|
|
305
|
+
signature: '<Dynamic component={comp} {...props} />',
|
|
306
306
|
example: `const components = { home: HomePage, about: AboutPage }
|
|
307
307
|
const current = signal("home")
|
|
308
308
|
|
|
309
309
|
<Dynamic component={components[current()]} />`,
|
|
310
310
|
},
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
signature:
|
|
312
|
+
'core/ErrorBoundary': {
|
|
313
|
+
signature: '<ErrorBoundary onCatch={handler} fallback={errorUI}>{children}</ErrorBoundary>',
|
|
314
314
|
example: `<ErrorBoundary
|
|
315
315
|
onCatch={(err) => console.error(err)}
|
|
316
316
|
fallback={(err) => <div>Error: {err.message}</div>}
|
|
@@ -319,8 +319,8 @@ const current = signal("home")
|
|
|
319
319
|
</ErrorBoundary>`,
|
|
320
320
|
},
|
|
321
321
|
|
|
322
|
-
|
|
323
|
-
signature:
|
|
322
|
+
'core/cx': {
|
|
323
|
+
signature: 'cx(...values: ClassValue[]): string',
|
|
324
324
|
example: `import { cx } from "@pyreon/core"
|
|
325
325
|
|
|
326
326
|
cx("foo", "bar") // "foo bar"
|
|
@@ -332,13 +332,13 @@ cx(["a", ["b", { c: true }]]) // nested arrays
|
|
|
332
332
|
<div class={["base", cond && "active"]} />
|
|
333
333
|
<div class={{ base: true, active: isActive() }} />`,
|
|
334
334
|
notes:
|
|
335
|
-
|
|
335
|
+
'Combines class values into a single string. Accepts strings, booleans, objects, arrays (nested). Falsy values are ignored. ClassValue type is also exported from @pyreon/core.',
|
|
336
336
|
mistakes: `- \`class={cx(...)}\` works but is redundant — class prop already accepts ClassValue
|
|
337
337
|
- \`class={condition ? "a" : undefined}\` → Use \`class={[condition && "a"]}\` or \`class={{ a: condition }}\``,
|
|
338
338
|
},
|
|
339
339
|
|
|
340
|
-
|
|
341
|
-
signature:
|
|
340
|
+
'core/splitProps': {
|
|
341
|
+
signature: 'splitProps<T, K extends keyof T>(props: T, keys: K[]): [Pick<T, K>, Omit<T, K>]',
|
|
342
342
|
example: `import { splitProps } from "@pyreon/core"
|
|
343
343
|
|
|
344
344
|
const Button = (props: { class?: string; onClick: () => void; children: VNodeChild }) => {
|
|
@@ -346,13 +346,13 @@ const Button = (props: { class?: string; onClick: () => void; children: VNodeChi
|
|
|
346
346
|
return <button {...rest} class={cx("btn", local.class)} />
|
|
347
347
|
}`,
|
|
348
348
|
notes:
|
|
349
|
-
|
|
349
|
+
'Splits a props object into two: picked keys and the rest. Preserves signal reactivity on both halves.',
|
|
350
350
|
mistakes: `- Destructuring props directly breaks reactivity — use splitProps instead
|
|
351
351
|
- \`const { class: cls, ...rest } = props\` → \`const [local, rest] = splitProps(props, ["class"])\``,
|
|
352
352
|
},
|
|
353
353
|
|
|
354
|
-
|
|
355
|
-
signature:
|
|
354
|
+
'core/mergeProps': {
|
|
355
|
+
signature: 'mergeProps<T extends object[]>(...sources: T): MergedProps<T>',
|
|
356
356
|
example: `import { mergeProps } from "@pyreon/core"
|
|
357
357
|
|
|
358
358
|
const Button = (props: { size?: string; variant?: string }) => {
|
|
@@ -360,11 +360,11 @@ const Button = (props: { size?: string; variant?: string }) => {
|
|
|
360
360
|
return <button class={\`btn-\${merged.size} btn-\${merged.variant}\`} />
|
|
361
361
|
}`,
|
|
362
362
|
notes:
|
|
363
|
-
|
|
363
|
+
'Merges multiple props objects. Last source wins for each key. Preserves reactivity — reads are lazy.',
|
|
364
364
|
},
|
|
365
365
|
|
|
366
|
-
|
|
367
|
-
signature:
|
|
366
|
+
'core/createUniqueId': {
|
|
367
|
+
signature: 'createUniqueId(): string',
|
|
368
368
|
example: `import { createUniqueId } from "@pyreon/core"
|
|
369
369
|
|
|
370
370
|
const LabeledInput = (props: { label: string }) => {
|
|
@@ -384,8 +384,8 @@ const LabeledInput = (props: { label: string }) => {
|
|
|
384
384
|
// @pyreon/router
|
|
385
385
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
386
386
|
|
|
387
|
-
|
|
388
|
-
signature:
|
|
387
|
+
'router/createRouter': {
|
|
388
|
+
signature: 'createRouter(options: RouterOptions | RouteRecord[]): Router',
|
|
389
389
|
example: `const router = createRouter([
|
|
390
390
|
{ path: "/", component: Home },
|
|
391
391
|
{ path: "/user/:id", component: User, loader: ({ params }) => fetchUser(params.id) },
|
|
@@ -395,8 +395,8 @@ const LabeledInput = (props: { label: string }) => {
|
|
|
395
395
|
])`,
|
|
396
396
|
},
|
|
397
397
|
|
|
398
|
-
|
|
399
|
-
signature:
|
|
398
|
+
'router/RouterProvider': {
|
|
399
|
+
signature: '<RouterProvider router={router}>{children}</RouterProvider>',
|
|
400
400
|
example: `const App = () => (
|
|
401
401
|
<RouterProvider router={router}>
|
|
402
402
|
<nav><RouterLink to="/">Home</RouterLink></nav>
|
|
@@ -405,8 +405,8 @@ const LabeledInput = (props: { label: string }) => {
|
|
|
405
405
|
)`,
|
|
406
406
|
},
|
|
407
407
|
|
|
408
|
-
|
|
409
|
-
signature:
|
|
408
|
+
'router/RouterView': {
|
|
409
|
+
signature: '<RouterView />',
|
|
410
410
|
example: `// Renders the matched route's component
|
|
411
411
|
<RouterView />
|
|
412
412
|
|
|
@@ -419,14 +419,14 @@ const Admin = () => (
|
|
|
419
419
|
)`,
|
|
420
420
|
},
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
signature:
|
|
422
|
+
'router/RouterLink': {
|
|
423
|
+
signature: '<RouterLink to={path} activeClass={cls} exactActiveClass={cls} />',
|
|
424
424
|
example: `<RouterLink to="/" activeClass="nav-active">Home</RouterLink>
|
|
425
425
|
<RouterLink to={{ name: "user", params: { id: "42" } }}>Profile</RouterLink>`,
|
|
426
426
|
},
|
|
427
427
|
|
|
428
|
-
|
|
429
|
-
signature:
|
|
428
|
+
'router/useRouter': {
|
|
429
|
+
signature: 'useRouter(): Router',
|
|
430
430
|
example: `const router = useRouter()
|
|
431
431
|
|
|
432
432
|
router.push("/settings")
|
|
@@ -437,8 +437,8 @@ router.forward()
|
|
|
437
437
|
router.go(-2)`,
|
|
438
438
|
},
|
|
439
439
|
|
|
440
|
-
|
|
441
|
-
signature:
|
|
440
|
+
'router/useRoute': {
|
|
441
|
+
signature: 'useRoute<TPath extends string>(): () => ResolvedRoute<ExtractParams<TPath>>',
|
|
442
442
|
example: `// Type-safe params:
|
|
443
443
|
const route = useRoute<"/user/:id">()
|
|
444
444
|
const userId = route().params.id // string
|
|
@@ -448,9 +448,9 @@ route().query
|
|
|
448
448
|
route().meta`,
|
|
449
449
|
},
|
|
450
450
|
|
|
451
|
-
|
|
451
|
+
'router/useSearchParams': {
|
|
452
452
|
signature:
|
|
453
|
-
|
|
453
|
+
'useSearchParams<T>(defaults?: T): [get: () => T, set: (updates: Partial<T>) => Promise<void>]',
|
|
454
454
|
example: `const [search, setSearch] = useSearchParams({ page: "1", sort: "name" })
|
|
455
455
|
|
|
456
456
|
// Read:
|
|
@@ -460,8 +460,8 @@ search().page // "1"
|
|
|
460
460
|
setSearch({ page: "2" })`,
|
|
461
461
|
},
|
|
462
462
|
|
|
463
|
-
|
|
464
|
-
signature:
|
|
463
|
+
'router/useLoaderData': {
|
|
464
|
+
signature: 'useLoaderData<T>(): T',
|
|
465
465
|
example: `// Route: { path: "/user/:id", component: User, loader: ({ params }) => fetchUser(params.id) }
|
|
466
466
|
|
|
467
467
|
const User = () => {
|
|
@@ -474,8 +474,8 @@ const User = () => {
|
|
|
474
474
|
// @pyreon/head
|
|
475
475
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
476
476
|
|
|
477
|
-
|
|
478
|
-
signature:
|
|
477
|
+
'head/useHead': {
|
|
478
|
+
signature: 'useHead(input: UseHeadInput | (() => UseHeadInput)): void',
|
|
479
479
|
example: `// Static:
|
|
480
480
|
useHead({ title: "My Page", meta: [{ name: "description", content: "..." }] })
|
|
481
481
|
|
|
@@ -486,8 +486,8 @@ useHead(() => ({
|
|
|
486
486
|
}))`,
|
|
487
487
|
},
|
|
488
488
|
|
|
489
|
-
|
|
490
|
-
signature:
|
|
489
|
+
'head/HeadProvider': {
|
|
490
|
+
signature: '<HeadProvider>{children}</HeadProvider>',
|
|
491
491
|
example: `// Client-side setup:
|
|
492
492
|
mount(
|
|
493
493
|
<HeadProvider>
|
|
@@ -501,8 +501,8 @@ mount(
|
|
|
501
501
|
// @pyreon/server
|
|
502
502
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
503
503
|
|
|
504
|
-
|
|
505
|
-
signature:
|
|
504
|
+
'server/createHandler': {
|
|
505
|
+
signature: 'createHandler(options: HandlerOptions): (req: Request) => Promise<Response>',
|
|
506
506
|
example: `import { createHandler } from "@pyreon/server"
|
|
507
507
|
|
|
508
508
|
export default createHandler({
|
|
@@ -513,9 +513,9 @@ export default createHandler({
|
|
|
513
513
|
})`,
|
|
514
514
|
},
|
|
515
515
|
|
|
516
|
-
|
|
516
|
+
'server/island': {
|
|
517
517
|
signature:
|
|
518
|
-
|
|
518
|
+
'island(loader: () => Promise<ComponentFn>, options: { name: string; hydrate?: HydrationStrategy }): ComponentFn',
|
|
519
519
|
example: `const SearchBar = island(
|
|
520
520
|
() => import("./SearchBar"),
|
|
521
521
|
{ name: "SearchBar", hydrate: "visible" }
|
|
@@ -524,8 +524,8 @@ export default createHandler({
|
|
|
524
524
|
// Hydration strategies: "load" | "idle" | "visible" | "media" | "never"`,
|
|
525
525
|
},
|
|
526
526
|
|
|
527
|
-
|
|
528
|
-
signature:
|
|
527
|
+
'server/prerender': {
|
|
528
|
+
signature: 'prerender(options: PrerenderOptions): Promise<PrerenderResult>',
|
|
529
529
|
example: `await prerender({
|
|
530
530
|
handler,
|
|
531
531
|
paths: ["/", "/about", "/blog/1", "/blog/2"],
|
|
@@ -537,8 +537,8 @@ export default createHandler({
|
|
|
537
537
|
// @pyreon/runtime-dom
|
|
538
538
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
539
539
|
|
|
540
|
-
|
|
541
|
-
signature:
|
|
540
|
+
'runtime-dom/mount': {
|
|
541
|
+
signature: 'mount(root: VNodeChild, container: Element): () => void',
|
|
542
542
|
example: `import { mount } from "@pyreon/runtime-dom"
|
|
543
543
|
|
|
544
544
|
const dispose = mount(<App />, document.getElementById("app")!)
|
|
@@ -549,16 +549,16 @@ dispose()`,
|
|
|
549
549
|
- Container must not be null/undefined`,
|
|
550
550
|
},
|
|
551
551
|
|
|
552
|
-
|
|
553
|
-
signature:
|
|
552
|
+
'runtime-dom/hydrateRoot': {
|
|
553
|
+
signature: 'hydrateRoot(root: VNodeChild, container: Element): () => void',
|
|
554
554
|
example: `import { hydrateRoot } from "@pyreon/runtime-dom"
|
|
555
555
|
|
|
556
556
|
// Hydrate server-rendered HTML:
|
|
557
557
|
hydrateRoot(<App />, document.getElementById("app")!)`,
|
|
558
558
|
},
|
|
559
559
|
|
|
560
|
-
|
|
561
|
-
signature:
|
|
560
|
+
'runtime-dom/Transition': {
|
|
561
|
+
signature: '<Transition name={name} mode={mode}>{children}</Transition>',
|
|
562
562
|
example: `<Transition name="fade" mode="out-in">
|
|
563
563
|
<Show when={visible()}>
|
|
564
564
|
<div>Content</div>
|
|
@@ -575,8 +575,8 @@ hydrateRoot(<App />, document.getElementById("app")!)`,
|
|
|
575
575
|
// @pyreon/store
|
|
576
576
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
577
577
|
|
|
578
|
-
|
|
579
|
-
signature:
|
|
578
|
+
'store/defineStore': {
|
|
579
|
+
signature: 'defineStore<T>(id: string, setup: () => T): () => StoreApi<T>',
|
|
580
580
|
example: `const useCounter = defineStore('counter', () => {
|
|
581
581
|
const count = signal(0)
|
|
582
582
|
const increment = () => count.update(n => n + 1)
|
|
@@ -587,16 +587,16 @@ const { store } = useCounter()
|
|
|
587
587
|
store.count() // 0
|
|
588
588
|
store.increment() // reactive update`,
|
|
589
589
|
notes:
|
|
590
|
-
|
|
590
|
+
'Composition-style stores. Singleton by ID. Returns StoreApi with .store, .patch(), .subscribe(), .onAction(), .reset(), .dispose().',
|
|
591
591
|
},
|
|
592
592
|
|
|
593
593
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
594
594
|
// @pyreon/form
|
|
595
595
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
596
596
|
|
|
597
|
-
|
|
597
|
+
'form/useForm': {
|
|
598
598
|
signature:
|
|
599
|
-
|
|
599
|
+
'useForm<T>(options: { initialValues: T, onSubmit: (values: T) => void | Promise<void>, schema?, validateOn?, debounceMs? }): FormInstance<T>',
|
|
600
600
|
example: `const form = useForm({
|
|
601
601
|
initialValues: { name: '', email: '' },
|
|
602
602
|
onSubmit: async (values) => await api.save(values),
|
|
@@ -606,11 +606,11 @@ store.increment() // reactive update`,
|
|
|
606
606
|
form.handleSubmit() // triggers validation + onSubmit
|
|
607
607
|
form.reset() // reset to initial values`,
|
|
608
608
|
notes:
|
|
609
|
-
|
|
609
|
+
'Signal-based form state. Use useField() for individual field binding, useFieldArray() for dynamic arrays.',
|
|
610
610
|
},
|
|
611
611
|
|
|
612
|
-
|
|
613
|
-
signature:
|
|
612
|
+
'form/useField': {
|
|
613
|
+
signature: 'useField<T>(form: FormInstance<T>, name: keyof T): FieldInstance',
|
|
614
614
|
example: `const name = useField(form, 'name')
|
|
615
615
|
|
|
616
616
|
<input {...name.register()} />
|
|
@@ -621,23 +621,23 @@ form.reset() // reset to initial values`,
|
|
|
621
621
|
// @pyreon/query
|
|
622
622
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
623
623
|
|
|
624
|
-
|
|
624
|
+
'query/useQuery': {
|
|
625
625
|
signature:
|
|
626
|
-
|
|
626
|
+
'useQuery<T>(options: { queryKey: unknown[], queryFn: () => Promise<T>, ... }): { data: Signal<T>, error: Signal<Error>, isFetching: Signal<boolean>, ... }',
|
|
627
627
|
example: `const { data, error, isFetching } = useQuery({
|
|
628
628
|
queryKey: ['users'],
|
|
629
629
|
queryFn: () => fetch('/api/users').then(r => r.json()),
|
|
630
630
|
})`,
|
|
631
631
|
notes:
|
|
632
|
-
|
|
632
|
+
'TanStack Query adapter. Fine-grained signals per field. Reactive options via function getter. Also: useMutation, useInfiniteQuery, useSuspenseQuery, useSubscription (WebSocket).',
|
|
633
633
|
},
|
|
634
634
|
|
|
635
635
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
636
636
|
// @pyreon/permissions
|
|
637
637
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
638
638
|
|
|
639
|
-
|
|
640
|
-
signature:
|
|
639
|
+
'permissions/createPermissions': {
|
|
640
|
+
signature: 'createPermissions<T extends PermissionMap>(initial?: T): PermissionsInstance',
|
|
641
641
|
example: `const can = createPermissions({
|
|
642
642
|
'posts.read': true,
|
|
643
643
|
'posts.delete': (post) => post.authorId === userId,
|
|
@@ -657,8 +657,8 @@ can.any('admin.users', 'posts.read')`,
|
|
|
657
657
|
// @pyreon/machine
|
|
658
658
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
659
659
|
|
|
660
|
-
|
|
661
|
-
signature:
|
|
660
|
+
'machine/createMachine': {
|
|
661
|
+
signature: 'createMachine<S, E>(config: MachineConfig<S, E>): Machine<S, E>',
|
|
662
662
|
example: `const traffic = createMachine({
|
|
663
663
|
initial: 'red',
|
|
664
664
|
states: {
|
|
@@ -673,31 +673,31 @@ traffic.send('NEXT') // 'green'
|
|
|
673
673
|
traffic.matches('green') // true
|
|
674
674
|
traffic.can('NEXT') // true`,
|
|
675
675
|
notes:
|
|
676
|
-
|
|
676
|
+
'Constrained signal with type-safe transitions. Guards: { target, guard: (payload?) => boolean }. No context — use signals alongside.',
|
|
677
677
|
},
|
|
678
678
|
|
|
679
679
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
680
680
|
// @pyreon/storage
|
|
681
681
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
682
682
|
|
|
683
|
-
|
|
683
|
+
'storage/useStorage': {
|
|
684
684
|
signature:
|
|
685
|
-
|
|
685
|
+
'useStorage<T>(key: string, defaultValue: T, options?: StorageOptions<T>): StorageSignal<T>',
|
|
686
686
|
example: `const theme = useStorage('theme', 'light')
|
|
687
687
|
theme() // 'light'
|
|
688
688
|
theme.set('dark') // persists + cross-tab sync
|
|
689
689
|
theme.remove() // delete from storage`,
|
|
690
690
|
notes:
|
|
691
|
-
|
|
691
|
+
'localStorage by default. Also: useSessionStorage, useCookie, useIndexedDB, useMemoryStorage, createStorage(backend). All return StorageSignal<T> extending Signal<T> with .remove().',
|
|
692
692
|
},
|
|
693
693
|
|
|
694
694
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
695
695
|
// @pyreon/i18n
|
|
696
696
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
697
697
|
|
|
698
|
-
|
|
698
|
+
'i18n/createI18n': {
|
|
699
699
|
signature:
|
|
700
|
-
|
|
700
|
+
'createI18n(options: { locale: string, messages: Record<string, Record<string, string>>, loader?, fallbackLocale?, pluralRules? }): I18nInstance',
|
|
701
701
|
example: `const i18n = createI18n({
|
|
702
702
|
locale: 'en',
|
|
703
703
|
messages: { en: { greeting: 'Hello, {{name}}!' } },
|
|
@@ -708,15 +708,15 @@ const { t, locale } = useI18n()
|
|
|
708
708
|
t('greeting', { name: 'World' }) // "Hello, World!"
|
|
709
709
|
locale.set('fr') // switch reactively`,
|
|
710
710
|
notes:
|
|
711
|
-
|
|
711
|
+
'Interpolation with {{name}}, pluralization with _one/_other suffixes. Namespace lazy loading. <Trans> component for rich JSX interpolation.',
|
|
712
712
|
},
|
|
713
713
|
|
|
714
714
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
715
715
|
// @pyreon/document
|
|
716
716
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
717
717
|
|
|
718
|
-
|
|
719
|
-
signature:
|
|
718
|
+
'document/createDocument': {
|
|
719
|
+
signature: 'createDocument(props?: DocumentProps): DocumentBuilder',
|
|
720
720
|
example: `const doc = createDocument({ title: 'Report' })
|
|
721
721
|
.heading('Sales Report')
|
|
722
722
|
.table({ columns: ['Region', 'Revenue'], rows: [['US', '$1M']] })
|
|
@@ -727,15 +727,15 @@ await doc.toDocx() // Word document
|
|
|
727
727
|
await doc.toSlack() // Slack Block Kit JSON
|
|
728
728
|
await doc.toNotion() // Notion blocks`,
|
|
729
729
|
notes:
|
|
730
|
-
|
|
730
|
+
'14+ output formats. JSX primitives: Document, Page, Heading, Text, Table, Image, List, Code, etc. Heavy renderers lazy-loaded.',
|
|
731
731
|
},
|
|
732
732
|
|
|
733
733
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
734
734
|
// @pyreon/flow
|
|
735
735
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
736
736
|
|
|
737
|
-
|
|
738
|
-
signature:
|
|
737
|
+
'flow/createFlow': {
|
|
738
|
+
signature: 'createFlow(config: { nodes: FlowNode[], edges: FlowEdge[], ... }): FlowInstance',
|
|
739
739
|
example: `const flow = createFlow({
|
|
740
740
|
nodes: [
|
|
741
741
|
{ id: '1', position: { x: 0, y: 0 }, data: { label: 'Start' } },
|
|
@@ -749,16 +749,16 @@ await flow.layout('layered') // auto-layout via elkjs
|
|
|
749
749
|
|
|
750
750
|
<Flow instance={flow}><Background /><Controls /><MiniMap /></Flow>`,
|
|
751
751
|
notes:
|
|
752
|
-
|
|
752
|
+
'Signal-native nodes/edges. Auto-layout via elkjs (lazy-loaded). Pan/zoom via pointer events + CSS transforms. No D3.',
|
|
753
753
|
},
|
|
754
754
|
|
|
755
755
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
756
756
|
// @pyreon/code
|
|
757
757
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
758
758
|
|
|
759
|
-
|
|
759
|
+
'code/createEditor': {
|
|
760
760
|
signature:
|
|
761
|
-
|
|
761
|
+
'createEditor(config: { value?: string, language?: string, theme?: string, minimap?: boolean, ... }): EditorInstance',
|
|
762
762
|
example: `const editor = createEditor({
|
|
763
763
|
value: '// hello',
|
|
764
764
|
language: 'typescript',
|
|
@@ -780,9 +780,9 @@ editor.insert('new code')
|
|
|
780
780
|
// @pyreon/hotkeys
|
|
781
781
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
782
782
|
|
|
783
|
-
|
|
783
|
+
'hotkeys/useHotkey': {
|
|
784
784
|
signature:
|
|
785
|
-
|
|
785
|
+
'useHotkey(shortcut: string, handler: (e: KeyboardEvent) => void, options?: HotkeyOptions): void',
|
|
786
786
|
example: `useHotkey('mod+s', (e) => {
|
|
787
787
|
e.preventDefault()
|
|
788
788
|
save()
|
|
@@ -798,8 +798,8 @@ useHotkeyScope('editor') // activate scope for component lifetime`,
|
|
|
798
798
|
// @pyreon/table
|
|
799
799
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
800
800
|
|
|
801
|
-
|
|
802
|
-
signature:
|
|
801
|
+
'table/useTable': {
|
|
802
|
+
signature: 'useTable<T>(options: TableOptions<T>): Table<T>',
|
|
803
803
|
example: `const table = useTable({
|
|
804
804
|
data: () => users(),
|
|
805
805
|
columns: [
|
|
@@ -810,31 +810,31 @@ useHotkeyScope('editor') // activate scope for component lifetime`,
|
|
|
810
810
|
|
|
811
811
|
// flexRender for column templates:
|
|
812
812
|
flexRender(cell.column.columnDef.cell, cell.getContext())`,
|
|
813
|
-
notes:
|
|
813
|
+
notes: 'TanStack Table adapter with reactive options and auto state sync.',
|
|
814
814
|
},
|
|
815
815
|
|
|
816
816
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
817
817
|
// @pyreon/virtual
|
|
818
818
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
819
819
|
|
|
820
|
-
|
|
820
|
+
'virtual/useVirtualizer': {
|
|
821
821
|
signature:
|
|
822
|
-
|
|
822
|
+
'useVirtualizer(options: VirtualizerOptions): { virtualItems: Signal, totalSize: Signal, scrollToIndex: (i) => void, ... }',
|
|
823
823
|
example: `const { virtualItems, totalSize } = useVirtualizer({
|
|
824
824
|
count: 10000,
|
|
825
825
|
getScrollElement: () => scrollRef.current,
|
|
826
826
|
estimateSize: () => 35,
|
|
827
827
|
})`,
|
|
828
|
-
notes:
|
|
828
|
+
notes: 'TanStack Virtual adapter. Also: useWindowVirtualizer for window-scoped virtualization.',
|
|
829
829
|
},
|
|
830
830
|
|
|
831
831
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
832
832
|
// @pyreon/feature
|
|
833
833
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
834
834
|
|
|
835
|
-
|
|
835
|
+
'feature/defineFeature': {
|
|
836
836
|
signature:
|
|
837
|
-
|
|
837
|
+
'defineFeature<T>(config: { name: string, schema: FeatureSchema<T>, api: FeatureApi<T> }): Feature<T>',
|
|
838
838
|
example: `const Posts = defineFeature({
|
|
839
839
|
name: 'posts',
|
|
840
840
|
schema: { title: 'string', body: 'string', author: reference('users') },
|
|
@@ -848,7 +848,7 @@ Posts.useCreate() // mutation
|
|
|
848
848
|
Posts.useForm(id) // edit form with validation
|
|
849
849
|
Posts.useTable() // TanStack Table config`,
|
|
850
850
|
notes:
|
|
851
|
-
|
|
851
|
+
'Schema-driven CRUD. Composes @pyreon/query, @pyreon/form, @pyreon/validation, @pyreon/store, @pyreon/table.',
|
|
852
852
|
},
|
|
853
853
|
|
|
854
854
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -859,8 +859,8 @@ Posts.useTable() // TanStack Table config`,
|
|
|
859
859
|
// @pyreon/lint
|
|
860
860
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
861
861
|
|
|
862
|
-
|
|
863
|
-
signature:
|
|
862
|
+
'lint/lint': {
|
|
863
|
+
signature: 'lint(options?: LintOptions): LintResult',
|
|
864
864
|
example: `import { lint } from "@pyreon/lint"
|
|
865
865
|
|
|
866
866
|
const result = lint({ paths: ["src/"], preset: "recommended" })
|
|
@@ -869,23 +869,23 @@ console.log(result.totalErrors, result.totalWarnings)
|
|
|
869
869
|
// With config file auto-loading + rule overrides
|
|
870
870
|
lint({ paths: ["."], ruleOverrides: { "pyreon/no-classname": "off" } })`,
|
|
871
871
|
notes:
|
|
872
|
-
|
|
872
|
+
'Programmatic API. 55 rules across 12 categories. Auto-loads .pyreonlintrc.json. Presets: recommended, strict, app, lib. Uses oxc-parser with AST caching.',
|
|
873
873
|
},
|
|
874
874
|
|
|
875
|
-
|
|
875
|
+
'lint/lintFile': {
|
|
876
876
|
signature:
|
|
877
|
-
|
|
877
|
+
'lintFile(filePath: string, sourceText: string, rules: Rule[], config: LintConfig, cache?: AstCache): LintFileResult',
|
|
878
878
|
example: `import { lintFile, allRules, getPreset, AstCache } from "@pyreon/lint"
|
|
879
879
|
|
|
880
880
|
const cache = new AstCache()
|
|
881
881
|
const config = getPreset("recommended")
|
|
882
882
|
const result = lintFile("app.tsx", source, allRules, config, cache)`,
|
|
883
|
-
notes:
|
|
883
|
+
notes: 'Low-level single-file API. Optional AstCache for repeat runs (FNV-1a hash keyed).',
|
|
884
884
|
},
|
|
885
885
|
|
|
886
|
-
|
|
886
|
+
'lint/cli': {
|
|
887
887
|
signature:
|
|
888
|
-
|
|
888
|
+
'pyreon-lint [--preset name] [--fix] [--format text|json|compact] [--quiet] [--watch] [--list] [--config path] [--ignore path] [--rule id=severity] [path...]',
|
|
889
889
|
example: `pyreon-lint --preset strict --quiet # CI mode
|
|
890
890
|
pyreon-lint --fix # auto-fix
|
|
891
891
|
pyreon-lint --watch src/ # watch mode
|
|
@@ -899,7 +899,7 @@ pyreon-lint --format json # machine-readable`,
|
|
|
899
899
|
// @pyreon/ui-core
|
|
900
900
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
901
901
|
|
|
902
|
-
|
|
902
|
+
'ui-core/PyreonUI': {
|
|
903
903
|
signature:
|
|
904
904
|
"PyreonUI(props: { theme?: Theme; mode?: 'light' | 'dark' | 'system'; inversed?: boolean; children: VNodeChild }): VNodeChild",
|
|
905
905
|
example: `import { PyreonUI } from "@pyreon/ui-core"
|
|
@@ -919,7 +919,7 @@ const theme = enrichTheme({ colors: { primary: "#3b82f6" } })
|
|
|
919
919
|
- Forgetting enrichTheme() → raw theme objects miss default breakpoints/spacing`,
|
|
920
920
|
},
|
|
921
921
|
|
|
922
|
-
|
|
922
|
+
'ui-core/useMode': {
|
|
923
923
|
signature: "useMode(): Signal<'light' | 'dark'>",
|
|
924
924
|
example: `import { useMode } from "@pyreon/ui-core"
|
|
925
925
|
|
|
@@ -934,8 +934,8 @@ const mode = useMode()
|
|
|
934
934
|
// @pyreon/unistyle
|
|
935
935
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
936
936
|
|
|
937
|
-
|
|
938
|
-
signature:
|
|
937
|
+
'unistyle/enrichTheme': {
|
|
938
|
+
signature: 'enrichTheme(theme: PartialTheme): Theme',
|
|
939
939
|
example: `import { enrichTheme } from "@pyreon/unistyle"
|
|
940
940
|
|
|
941
941
|
const theme = enrichTheme({
|
|
@@ -945,7 +945,7 @@ const theme = enrichTheme({
|
|
|
945
945
|
|
|
946
946
|
// Merges user overrides with default breakpoints, spacing, and units`,
|
|
947
947
|
notes:
|
|
948
|
-
|
|
948
|
+
'Merges a partial theme with the full default theme (breakpoints, spacing, unit utilities). Always use when passing a theme to PyreonUI.',
|
|
949
949
|
},
|
|
950
950
|
|
|
951
951
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -956,9 +956,9 @@ const theme = enrichTheme({
|
|
|
956
956
|
// @pyreon/rx
|
|
957
957
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
958
958
|
|
|
959
|
-
|
|
959
|
+
'rx/filter': {
|
|
960
960
|
signature:
|
|
961
|
-
|
|
961
|
+
'filter<T>(source: Signal<T[]> | T[], predicate: (item: T) => boolean): Computed<T[]> | T[]',
|
|
962
962
|
example: `import { filter } from '@pyreon/rx'
|
|
963
963
|
|
|
964
964
|
// Signal input → Computed output (auto-tracks):
|
|
@@ -969,11 +969,11 @@ evens() // [2, 4]
|
|
|
969
969
|
// Plain input → plain output:
|
|
970
970
|
const result = filter([1, 2, 3, 4, 5], n => n > 3) // [4, 5]`,
|
|
971
971
|
notes:
|
|
972
|
-
|
|
972
|
+
'Every @pyreon/rx function is overloaded: Signal<T[]> input produces Computed<T[]>, plain T[] input produces plain T[]. 24 functions total: filter, map, sortBy, groupBy, keyBy, uniqBy, take, skip, last, chunk, flatten, find, mapValues, count, sum, min, max, average, distinct, scan, combine, debounce, throttle, search.',
|
|
973
973
|
},
|
|
974
974
|
|
|
975
|
-
|
|
976
|
-
signature:
|
|
975
|
+
'rx/pipe': {
|
|
976
|
+
signature: 'pipe<T>(source: Signal<T[]> | T[], ...operators: Operator[]): Computed<T[]> | T[]',
|
|
977
977
|
example: `import { pipe, filter, sortBy, map } from '@pyreon/rx'
|
|
978
978
|
|
|
979
979
|
const users = signal([
|
|
@@ -991,16 +991,16 @@ const result = pipe(
|
|
|
991
991
|
)
|
|
992
992
|
// Computed<string[]> → ["Bob", "Charlie"]`,
|
|
993
993
|
notes:
|
|
994
|
-
|
|
994
|
+
'Pipe composes operators left-to-right. Signal source produces reactive Computed that re-derives when source changes.',
|
|
995
995
|
},
|
|
996
996
|
|
|
997
997
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
998
998
|
// @pyreon/toast
|
|
999
999
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1000
1000
|
|
|
1001
|
-
|
|
1001
|
+
'toast/toast': {
|
|
1002
1002
|
signature:
|
|
1003
|
-
|
|
1003
|
+
'toast(message: string, options?: ToastOptions): string\ntoast.success/error/warning/info/loading(message): string\ntoast.update(id, options): void\ntoast.dismiss(id?): void\ntoast.promise(promise, { loading, success, error }): string',
|
|
1004
1004
|
example: `import { toast, Toaster } from '@pyreon/toast'
|
|
1005
1005
|
|
|
1006
1006
|
// Basic:
|
|
@@ -1034,9 +1034,9 @@ toast.dismiss() // all
|
|
|
1034
1034
|
// @pyreon/url-state
|
|
1035
1035
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1036
1036
|
|
|
1037
|
-
|
|
1037
|
+
'url-state/useUrlState': {
|
|
1038
1038
|
signature:
|
|
1039
|
-
|
|
1039
|
+
'useUrlState<T>(key: string, defaultValue: T): UrlStateSignal<T>\nuseUrlState<T extends Record<string, unknown>>(schema: T): UrlStateSchema<T>',
|
|
1040
1040
|
example: `import { useUrlState } from '@pyreon/url-state'
|
|
1041
1041
|
|
|
1042
1042
|
// Single param — synced to ?page=:
|
|
@@ -1050,16 +1050,16 @@ filters.page() // 1
|
|
|
1050
1050
|
filters.sort() // "name"
|
|
1051
1051
|
filters.set({ page: 2, sort: 'date' })`,
|
|
1052
1052
|
notes:
|
|
1053
|
-
|
|
1053
|
+
'Auto type coercion (numbers, booleans, arrays). Uses replaceState (no history spam). Configurable debounce. SSR-safe — reads request URL on server.',
|
|
1054
1054
|
},
|
|
1055
1055
|
|
|
1056
1056
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1057
1057
|
// @pyreon/query — useSSE
|
|
1058
1058
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1059
1059
|
|
|
1060
|
-
|
|
1060
|
+
'query/useSSE': {
|
|
1061
1061
|
signature:
|
|
1062
|
-
|
|
1062
|
+
'useSSE<T>(options: { queryKey: unknown[], url: string, transform?: (event: MessageEvent) => T, ... }): { data: Signal<T>, error: Signal<Error>, status: Signal<string> }',
|
|
1063
1063
|
example: `import { useSSE } from '@pyreon/query'
|
|
1064
1064
|
|
|
1065
1065
|
const { data, error, status } = useSSE({
|
|
@@ -1072,15 +1072,15 @@ const { data, error, status } = useSSE({
|
|
|
1072
1072
|
// Auto-reconnects on disconnect
|
|
1073
1073
|
// Integrates with QueryClient for cache invalidation`,
|
|
1074
1074
|
notes:
|
|
1075
|
-
|
|
1075
|
+
'Server-Sent Events hook. Same pattern as useSubscription but read-only (no send). Integrates with QueryClient cache.',
|
|
1076
1076
|
},
|
|
1077
1077
|
|
|
1078
1078
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1079
1079
|
// @pyreon/router — useIsActive
|
|
1080
1080
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1081
1081
|
|
|
1082
|
-
|
|
1083
|
-
signature:
|
|
1082
|
+
'router/useIsActive': {
|
|
1083
|
+
signature: 'useIsActive(path: string, exact?: boolean): () => boolean',
|
|
1084
1084
|
example: `import { useIsActive } from '@pyreon/router'
|
|
1085
1085
|
|
|
1086
1086
|
const isHome = useIsActive('/')
|
|
@@ -1090,11 +1090,11 @@ const isExactAdmin = useIsActive('/admin', true) // exact only
|
|
|
1090
1090
|
// Reactive — updates when route changes:
|
|
1091
1091
|
<a class={{ active: isAdmin() }} href="/admin">Admin</a>`,
|
|
1092
1092
|
notes:
|
|
1093
|
-
|
|
1093
|
+
'Returns a reactive boolean. Segment-aware prefix matching: /admin matches /admin/users but not /admin-panel. Pass exact=true for exact-only matching.',
|
|
1094
1094
|
},
|
|
1095
1095
|
|
|
1096
|
-
|
|
1097
|
-
signature:
|
|
1096
|
+
'storybook/renderToCanvas': {
|
|
1097
|
+
signature: 'renderToCanvas(context: StoryContext, canvasElement: HTMLElement): void',
|
|
1098
1098
|
example: `// .storybook/main.ts:
|
|
1099
1099
|
export default { framework: '@pyreon/storybook' }
|
|
1100
1100
|
|
|
@@ -1109,6 +1109,6 @@ export const Primary: StoryObj<typeof meta> = {
|
|
|
1109
1109
|
args: { variant: 'primary', label: 'Click me' },
|
|
1110
1110
|
}`,
|
|
1111
1111
|
notes:
|
|
1112
|
-
|
|
1112
|
+
'Storybook renderer for Pyreon components. Re-exports h, Fragment, signal, computed, effect, mount for story convenience.',
|
|
1113
1113
|
},
|
|
1114
1114
|
}
|