@pyreon/svelte-compat 0.17.0 → 0.26.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/svelte-compat",
3
- "version": "0.17.0",
3
+ "version": "0.26.3",
4
4
  "description": "Svelte-compatible API shim for Pyreon — write Svelte-style stores / lifecycle code that runs on Pyreon's reactive engine",
5
5
  "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/svelte-compat#readme",
6
6
  "bugs": {
@@ -14,7 +14,6 @@
14
14
  },
15
15
  "files": [
16
16
  "lib",
17
- "src",
18
17
  "README.md",
19
18
  "LICENSE"
20
19
  ],
@@ -25,22 +24,18 @@
25
24
  "types": "./lib/types/index.d.ts",
26
25
  "exports": {
27
26
  ".": {
28
- "bun": "./src/index.ts",
29
27
  "import": "./lib/index.js",
30
28
  "types": "./lib/types/index.d.ts"
31
29
  },
32
30
  "./store": {
33
- "bun": "./src/store.ts",
34
31
  "import": "./lib/store.js",
35
32
  "types": "./lib/types/store.d.ts"
36
33
  },
37
34
  "./jsx-runtime": {
38
- "bun": "./src/jsx-runtime.ts",
39
35
  "import": "./lib/jsx-runtime.js",
40
36
  "types": "./lib/types/jsx-runtime.d.ts"
41
37
  },
42
38
  "./jsx-dev-runtime": {
43
- "bun": "./src/jsx-runtime.ts",
44
39
  "import": "./lib/jsx-runtime.js",
45
40
  "types": "./lib/types/jsx-runtime.d.ts"
46
41
  }
@@ -61,12 +56,12 @@
61
56
  "@happy-dom/global-registrator": "^20.9.0",
62
57
  "@pyreon/test-utils": "^0.13.13",
63
58
  "@pyreon/vitest-config": "0.13.1",
64
- "@vitest/browser-playwright": "^4.1.7",
59
+ "@vitest/browser-playwright": "^4.1.8",
65
60
  "happy-dom": "^20.9.0"
66
61
  },
67
62
  "peerDependencies": {
68
- "@pyreon/core": "^0.26.1",
69
- "@pyreon/reactivity": "^0.26.1",
70
- "@pyreon/runtime-dom": "^0.26.1"
63
+ "@pyreon/core": "^0.26.3",
64
+ "@pyreon/reactivity": "^0.26.3",
65
+ "@pyreon/runtime-dom": "^0.26.3"
71
66
  }
72
67
  }
package/src/env.d.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Minimal process type — just enough for `process.env.NODE_ENV` checks.
3
- * Avoids requiring @types/node in consumers that import pyreon source
4
- * via the `"bun"` export condition.
5
- */
6
- declare var process: { env: { NODE_ENV?: string } }
package/src/index.ts DELETED
@@ -1,538 +0,0 @@
1
- /**
2
- * @pyreon/svelte-compat
3
- *
4
- * Svelte-compatible **importable runtime API** powered by Pyreon's
5
- * reactive engine. Mirrors the scope boundary of the sibling compat
6
- * layers (react/preact/vue/solid-compat): it shims the APIs Svelte code
7
- * actually `import`s —
8
- *
9
- * - `svelte/store` → `writable` `readable` `derived` `get` `readonly`
10
- * - `svelte` → `onMount` `onDestroy` `beforeUpdate` `afterUpdate`
11
- * `tick` `setContext` `getContext` `hasContext`
12
- * `getAllContexts` `createEventDispatcher`
13
- * `mount` `unmount` `flushSync`
14
- *
15
- * It does NOT implement the `.svelte` single-file-component compiler or
16
- * the non-importable Svelte 5 rune *syntax* (`$state`/`$derived`/
17
- * `$effect`) — those are compiler constructs, not runtime imports, the
18
- * same boundary solid-compat draws around Solid's compiler. Components
19
- * here are plain functions returning JSX that run on Pyreon via the
20
- * shared compat JSX runtime (re-render on store change).
21
- *
22
- * Store model: a faithful Svelte store — a plain Set of subscribers
23
- * notified synchronously on `set`/`update` (signal-free, exactly like
24
- * Svelte's own `writable`; `derived` subscribes to its inputs
25
- * explicitly). The store contract (`subscribe(run, invalidate?) →
26
- * unsubscribe`, lazy `start(set, update?) → stop` notifier) matches
27
- * Svelte exactly. Subscribing inside a compat component body re-renders
28
- * it on store change (the faithful `$store` auto-subscription
29
- * equivalent) without a disposable tracking effect.
30
- */
31
-
32
- import type { ComponentFn, Props, VNodeChild } from '@pyreon/core'
33
- import {
34
- ErrorBoundary,
35
- For,
36
- Match,
37
- nativeCompat,
38
- createContext as pyreonCreateContext,
39
- onMount as pyreonOnMount,
40
- onUnmount as pyreonOnUnmount,
41
- provide as pyreonProvide,
42
- useContext as pyreonUseContext,
43
- Show,
44
- Suspense,
45
- Switch,
46
- } from '@pyreon/core'
47
- import { mount as pyreonMount } from '@pyreon/runtime-dom'
48
- import { getCurrentCtx, getHookIndex, jsx } from './jsx-runtime'
49
-
50
- // Dev-mode counter sink — see packages/internals/perf-harness for contract.
51
- const _countSink = globalThis as { __pyreon_count__?: (name: string, n?: number) => void }
52
-
53
- // ─── Store types (Svelte API surface) ───────────────────────────────────────
54
-
55
- export type Subscriber<T> = (value: T) => void
56
- export type Invalidator<T> = (value?: T) => void
57
- export type Unsubscriber = () => void
58
- export type Updater<T> = (value: T) => T
59
- /** `(set, update?) => stop?` — lazy notifier, runs on first subscriber. */
60
- export type StartStopNotifier<T> = (
61
- set: (value: T) => void,
62
- update: (fn: Updater<T>) => void,
63
- ) => Unsubscriber | void
64
-
65
- export interface Readable<T> {
66
- subscribe(run: Subscriber<T>, invalidate?: Invalidator<T>): Unsubscriber
67
- }
68
- export interface Writable<T> extends Readable<T> {
69
- set(value: T): void
70
- update(updater: Updater<T>): void
71
- }
72
-
73
- const noop = () => {
74
- /* noop */
75
- }
76
-
77
- // Internal subscriptions (`get()`, `derived`'s input wiring) must NOT take
78
- // the render-aware hook-indexed path even when they happen to run during a
79
- // component render — doing so would consume the component's hook indices and
80
- // desync onMount/onDestroy. This depth counter suppresses the render-aware
81
- // branch for the duration of an internal subscribe.
82
- let _plainDepth = 0
83
- function plainSubscribe<R>(fn: () => R): R {
84
- _plainDepth++
85
- try {
86
- return fn()
87
- } finally {
88
- _plainDepth--
89
- }
90
- }
91
-
92
- // ─── writable ────────────────────────────────────────────────────────────────
93
-
94
- /**
95
- * Svelte's `safe_not_equal`: primitives dedup, objects/functions always
96
- * notify (so in-place-mutated store objects still propagate).
97
- */
98
- function safeNotEqual(a: unknown, b: unknown): boolean {
99
- // eslint-disable-next-line no-self-compare
100
- return a != a
101
- ? // eslint-disable-next-line no-self-compare
102
- b == b
103
- : a !== b || (a !== null && typeof a === 'object') || typeof a === 'function'
104
- }
105
-
106
- interface SubEntry<T> {
107
- run: Subscriber<T>
108
- invalidate: Invalidator<T>
109
- /** Component re-render trigger — set only for render-aware subscriptions. */
110
- rerender?: () => void
111
- }
112
-
113
- /**
114
- * Svelte-compatible `writable`. A faithful Svelte store: a Set of
115
- * subscribers notified synchronously on `set`/`update`. NOT signal-
116
- * backed — Svelte's own `writable` is signal-free, and `derived` here
117
- * subscribes to its inputs explicitly, so no signal auto-tracking is
118
- * needed.
119
- *
120
- * Subscribing inside a compat component body is the faithful equivalent
121
- * of Svelte's `$store` auto-subscription: the subscriber carries the
122
- * component's `scheduleRerender`, so a store write re-renders the
123
- * component — the same "write drives re-render" model the sibling
124
- * solid-compat layer uses. Crucially this is NOT a persistent tracking
125
- * effect: such an effect, created inside the wrapper accessor's run, is
126
- * collected as an inner effect and disposed on the NEXT re-render (the
127
- * cached path never recreates it), so store changes stopped propagating
128
- * after the first one. A plain subscriber Set has no such hazard — it
129
- * lives until `unsub` (registered in `ctx.unmountCallbacks`).
130
- *
131
- * `start` runs when the subscriber count goes 0→1 and its returned
132
- * `stop` runs at 1→0. Synchronous `set` calls inside `start` mutate the
133
- * value but do NOT notify (the store isn't "ready" until `start`
134
- * returns), so the first subscriber sees exactly the post-start value —
135
- * matching Svelte's `derived` (one emission, no spurious initial).
136
- */
137
- export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writable<T> {
138
- let v = value as T
139
- let stop: Unsubscriber | void
140
- const subs = new Set<SubEntry<T>>()
141
-
142
- const setVal = (next: T): void => {
143
- if (!safeNotEqual(v, next)) return
144
- v = next
145
- if (!stop) return // not "ready" — Svelte's gate (start hasn't returned)
146
- for (const s of subs) s.invalidate(v)
147
- for (const s of subs) {
148
- s.run(v)
149
- s.rerender?.()
150
- }
151
- }
152
- const set = (next: T): void => setVal(next)
153
- const update = (fn: Updater<T>): void => setVal(fn(v))
154
-
155
- const addSub = (entry: SubEntry<T>): Unsubscriber => {
156
- subs.add(entry)
157
- if (subs.size === 1) stop = start(set, update) || noop
158
- entry.run(v) // Svelte: subscriber invoked immediately with current value
159
- return () => {
160
- subs.delete(entry)
161
- if (subs.size === 0 && stop) {
162
- stop()
163
- stop = undefined
164
- }
165
- }
166
- }
167
-
168
- return {
169
- set,
170
- update,
171
- subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
172
- // Render-aware path: inside a compat component body (and not an
173
- // internal `_plainDepth` subscription), carry the component's
174
- // scheduleRerender so a store write re-renders it. Hook-indexed so
175
- // the one live subscription is created exactly once across
176
- // re-renders; the cached pass just refreshes the component-local.
177
- const ctx = _plainDepth === 0 ? getCurrentCtx() : null
178
- if (ctx) {
179
- const idx = getHookIndex()
180
- const cached = ctx.hooks[idx] as { unsub: Unsubscriber } | undefined
181
- if (cached) {
182
- run(v)
183
- // Re-push the cached unsub into the (possibly-reset)
184
- // unmountCallbacks array. When a parent re-renders and
185
- // preserves the ChildInstance, the wrapper resets
186
- // `ctx.unmountCallbacks = []` to drop stale cycle-N
187
- // callbacks before cycle-N+1 begins (`jsx-runtime.ts:172`).
188
- // Without this re-push the cached subscription's unsub is
189
- // lost from the array and the subscription stays active on
190
- // the store forever — one leaked subscriber per
191
- // `writable.subscribe()` call per parent re-render cycle.
192
- if (!ctx.unmountCallbacks.includes(cached.unsub)) {
193
- ctx.unmountCallbacks.push(cached.unsub)
194
- // Leak-class D diagnostic — emit per re-push that fires
195
- // during the cached fast-path. Non-zero confirms parent
196
- // re-renders are actually exercising the cached subscribe
197
- // path (and the unsub stays bound to the live cleanup
198
- // array). Zero on a render-heavy workload = either no
199
- // cached subscriptions OR — bug — the includes() guard
200
- // suppressed a valid re-push.
201
- if (process.env.NODE_ENV !== 'production')
202
- _countSink.__pyreon_count__?.('svelte-compat.subscribe.cachedRePush')
203
- }
204
- return cached.unsub
205
- }
206
- const entry: SubEntry<T> = {
207
- run,
208
- invalidate,
209
- rerender: () => {
210
- if (!ctx.unmounted) ctx.scheduleRerender()
211
- },
212
- }
213
- const unsub = addSub(entry)
214
- ctx.hooks[idx] = { unsub }
215
- ctx.unmountCallbacks.push(unsub)
216
- return unsub
217
- }
218
- return addSub({ run, invalidate })
219
- },
220
- }
221
- }
222
-
223
- // ─── readable ────────────────────────────────────────────────────────────────
224
-
225
- /** Svelte-compatible `readable` — a `writable` with `set`/`update` hidden. */
226
- export function readable<T>(value?: T, start?: StartStopNotifier<T>): Readable<T> {
227
- const w = writable<T>(value, start)
228
- return { subscribe: w.subscribe }
229
- }
230
-
231
- // ─── readonly ────────────────────────────────────────────────────────────────
232
-
233
- /** Svelte-compatible `readonly` — view of a store exposing only `subscribe`. */
234
- export function readonly<T>(store: Readable<T>): Readable<T> {
235
- return { subscribe: store.subscribe }
236
- }
237
-
238
- // ─── get ─────────────────────────────────────────────────────────────────────
239
-
240
- /** Svelte-compatible `get` — read a store's value synchronously. */
241
- export function get<T>(store: Readable<T>): T {
242
- let value!: T
243
- plainSubscribe(() => {
244
- const unsub = store.subscribe((v) => {
245
- value = v
246
- })
247
- unsub()
248
- })
249
- return value
250
- }
251
-
252
- // ─── derived ─────────────────────────────────────────────────────────────────
253
-
254
- type Stores =
255
- | Readable<unknown>
256
- | [Readable<unknown>, ...Array<Readable<unknown>>]
257
- | Array<Readable<unknown>>
258
- type StoresValues<T> = T extends Readable<infer U>
259
- ? U
260
- : { [K in keyof T]: T[K] extends Readable<infer U> ? U : never }
261
-
262
- /**
263
- * Svelte-compatible `derived`. Supports both the sync form
264
- * `(values) => result` and the async/cleanup form
265
- * `(values, set, update?) => stop`.
266
- */
267
- export function derived<S extends Stores, T>(
268
- stores: S,
269
- fn:
270
- | ((values: StoresValues<S>) => T)
271
- | ((
272
- values: StoresValues<S>,
273
- set: (value: T) => void,
274
- update: (fn: Updater<T>) => void,
275
- ) => Unsubscriber | void),
276
- initialValue?: T,
277
- ): Readable<T> {
278
- const single = !Array.isArray(stores)
279
- const storeArr = (single ? [stores] : stores) as Array<Readable<unknown>>
280
- const isAsync = fn.length >= 2
281
-
282
- const out = writable<T>(initialValue as T, (set, update) => {
283
- let inited = false
284
- const values: unknown[] = []
285
- let cleanup: Unsubscriber | void
286
-
287
- const sync = () => {
288
- if (cleanup) {
289
- cleanup()
290
- cleanup = undefined
291
- }
292
- const input = (single ? values[0] : values) as StoresValues<S>
293
- if (isAsync) {
294
- cleanup = (
295
- fn as (v: StoresValues<S>, s: (x: T) => void, u: (f: Updater<T>) => void) => Unsubscriber | void
296
- )(input, set, update)
297
- } else {
298
- set((fn as (v: StoresValues<S>) => T)(input))
299
- }
300
- }
301
-
302
- const unsubs = plainSubscribe(() =>
303
- storeArr.map((s, i) =>
304
- s.subscribe((v) => {
305
- values[i] = v
306
- if (inited) sync()
307
- }),
308
- ),
309
- )
310
- inited = true
311
- sync()
312
-
313
- return () => {
314
- for (const u of unsubs) u()
315
- if (cleanup) cleanup()
316
- }
317
- })
318
-
319
- return { subscribe: out.subscribe }
320
- }
321
-
322
- // ─── lifecycle (svelte) ──────────────────────────────────────────────────────
323
-
324
- type CleanupFn = () => void
325
-
326
- /** Svelte-compatible `onMount` — runs after the component's first render. */
327
- export function onMount(fn: () => CleanupFn | void): void {
328
- const ctx = getCurrentCtx()
329
- if (ctx) {
330
- const idx = getHookIndex()
331
- if (idx >= ctx.hooks.length) {
332
- // Svelte's onMount may return a cleanup that runs on destroy. The
333
- // shared jsx-runtime schedules pendingEffects post-render but never
334
- // invokes their stored cleanup on unmount, so wire it explicitly
335
- // into unmountCallbacks (runs in the wrapper's onUnmount).
336
- let cleanup: CleanupFn | undefined
337
- const unmountCb = () => {
338
- if (cleanup) cleanup()
339
- }
340
- // Store the cleanup callback in the hook slot (was `true`) so it can be
341
- // re-pushed after a parent re-render resets `ctx.unmountCallbacks`.
342
- ctx.hooks[idx] = unmountCb
343
- ctx.pendingEffects.push({
344
- fn: () => {
345
- const c = fn()
346
- cleanup = typeof c === 'function' ? c : undefined
347
- return cleanup
348
- },
349
- deps: undefined,
350
- cleanup: undefined,
351
- })
352
- ctx.unmountCallbacks.push(unmountCb)
353
- } else {
354
- // Re-render of a preserved child: the wrapper reset
355
- // `ctx.unmountCallbacks = []` (jsx-runtime.ts:172), dropping this hook's
356
- // cleanup. Re-push it so it still runs on final unmount — the lifecycle
357
- // sibling of the #739 `writable.subscribe` re-push. `includes()` guards
358
- // against a double-push within the same render.
359
- const stored = ctx.hooks[idx]
360
- if (typeof stored === 'function') {
361
- const cb = stored as () => void
362
- if (!ctx.unmountCallbacks.includes(cb)) ctx.unmountCallbacks.push(cb)
363
- }
364
- }
365
- return
366
- }
367
- pyreonOnMount(fn)
368
- }
369
-
370
- /** Svelte-compatible `onDestroy` — runs when the component unmounts. */
371
- export function onDestroy(fn: () => void): void {
372
- const ctx = getCurrentCtx()
373
- if (ctx) {
374
- const idx = getHookIndex()
375
- if (idx >= ctx.hooks.length) {
376
- // Store the callback in the hook slot (was `true`) so it survives a
377
- // parent re-render that resets `ctx.unmountCallbacks` (see onMount).
378
- ctx.hooks[idx] = fn
379
- ctx.unmountCallbacks.push(fn)
380
- } else {
381
- // Re-render: re-push the dropped destroy callback (the #739 lifecycle
382
- // sibling) so it still fires on final unmount.
383
- const stored = ctx.hooks[idx]
384
- if (typeof stored === 'function') {
385
- const cb = stored as () => void
386
- if (!ctx.unmountCallbacks.includes(cb)) ctx.unmountCallbacks.push(cb)
387
- }
388
- }
389
- return
390
- }
391
- pyreonOnUnmount(fn)
392
- }
393
-
394
- /**
395
- * Svelte-compatible `beforeUpdate` / `afterUpdate`. The compat wrapper
396
- * re-renders by tearing down + rebuilding (no per-update diff), so these
397
- * map to a post-first-render hook rather than Svelte's per-tick timing —
398
- * the documented boundary (most Svelte interop uses onMount/onDestroy).
399
- */
400
- export function beforeUpdate(fn: () => void): void {
401
- const ctx = getCurrentCtx()
402
- if (ctx) {
403
- const idx = getHookIndex()
404
- if (idx >= ctx.hooks.length) {
405
- ctx.hooks[idx] = true
406
- fn() // before the first render commits
407
- }
408
- return
409
- }
410
- fn()
411
- }
412
- export function afterUpdate(fn: () => void): void {
413
- onMount(() => {
414
- fn()
415
- })
416
- }
417
-
418
- /** Svelte-compatible `tick` — resolves after the current microtask. */
419
- export function tick(): Promise<void> {
420
- return new Promise<void>((resolve) => queueMicrotask(resolve))
421
- }
422
-
423
- // ─── context (svelte) ────────────────────────────────────────────────────────
424
-
425
- const CTX_REGISTRY = Symbol.for('pyreon:svelte-ctx-registry')
426
- type CtxMap = Map<unknown, ReturnType<typeof pyreonCreateContext<unknown>>>
427
-
428
- function ctxFor(key: unknown): ReturnType<typeof pyreonCreateContext<unknown>> {
429
- const g = globalThis as Record<symbol, unknown>
430
- let reg = g[CTX_REGISTRY] as CtxMap | undefined
431
- if (!reg) {
432
- reg = new Map()
433
- g[CTX_REGISTRY] = reg
434
- }
435
- let c = reg.get(key)
436
- if (!c) {
437
- c = pyreonCreateContext<unknown>(undefined)
438
- reg.set(key, c)
439
- }
440
- return c
441
- }
442
-
443
- /** Svelte-compatible `setContext` — provides a value for descendants. */
444
- export function setContext<T>(key: unknown, context: T): T {
445
- pyreonProvide(ctxFor(key), context)
446
- return context
447
- }
448
- /** Svelte-compatible `getContext` — reads the nearest provided value. */
449
- export function getContext<T>(key: unknown): T {
450
- return pyreonUseContext(ctxFor(key)) as T
451
- }
452
- /** Svelte-compatible `hasContext` — whether a value was provided up-tree. */
453
- export function hasContext(key: unknown): boolean {
454
- return pyreonUseContext(ctxFor(key)) !== undefined
455
- }
456
- /** Svelte-compatible `getAllContexts` — best-effort (not tracked per-key). */
457
- export function getAllContexts<T extends Map<unknown, unknown> = Map<unknown, unknown>>(): T {
458
- return new Map() as T
459
- }
460
-
461
- // ─── createEventDispatcher (svelte) ──────────────────────────────────────────
462
-
463
- /**
464
- * Svelte-compatible `createEventDispatcher`. Svelte's compiler turns
465
- * `<Child on:foo>` into a prop; here events are forwarded to the
466
- * current component's `on<Type>` / `on:<type>` prop with a CustomEvent
467
- * (mirrors how the sibling compat layers map child events to props).
468
- */
469
- export function createEventDispatcher<EventMap extends Record<string, unknown> = Record<string, unknown>>(): <
470
- Type extends keyof EventMap & string,
471
- >(
472
- type: Type,
473
- detail?: EventMap[Type],
474
- ) => boolean {
475
- const ctx = getCurrentCtx()
476
- const props = (ctx?.props ?? {}) as Record<string, unknown>
477
- return (type, detail) => {
478
- const evt =
479
- typeof CustomEvent === 'function'
480
- ? new CustomEvent(type, { detail })
481
- : ({ type, detail } as unknown as CustomEvent)
482
- const cap = `on${type.charAt(0).toUpperCase()}${type.slice(1)}`
483
- const handler = (props[cap] ?? props[`on:${type}`] ?? props[`on${type}`]) as
484
- | ((e: unknown) => void)
485
- | undefined
486
- if (typeof handler === 'function') handler(evt)
487
- return !(evt as CustomEvent).defaultPrevented
488
- }
489
- }
490
-
491
- // ─── mount / unmount / flushSync (Svelte 5 client API) ───────────────────────
492
-
493
- type MountTargetOptions<P> = { target: Element; props?: P; context?: Map<unknown, unknown> }
494
-
495
- /**
496
- * Svelte-5-compatible `mount` — mounts a compat component into a target.
497
- * Thin wrapper over Pyreon's runtime mount. Returns the props object
498
- * (Svelte 5 returns the component exports; here props are the surface).
499
- */
500
- export function mount<P extends Record<string, unknown>>(
501
- Component: (props: P) => VNodeChild,
502
- options: MountTargetOptions<P>,
503
- ): P {
504
- const props = (options.props ?? ({} as P)) as P
505
- // Route through the compat JSX runtime so the component runs inside the
506
- // shared wrapper (lifecycle + store-driven re-render), exactly as a
507
- // JSX-rendered child would.
508
- const vnode = jsx(Component as unknown as ComponentFn, props as unknown as Props)
509
- const dispose = pyreonMount(vnode, options.target as HTMLElement)
510
- ;(props as Record<symbol, unknown>)[UNMOUNT] = dispose
511
- return props
512
- }
513
-
514
- const UNMOUNT = Symbol.for('pyreon:svelte-unmount')
515
-
516
- /** Svelte-5-compatible `unmount` — disposes a component mounted via `mount`. */
517
- export function unmount(mounted: Record<symbol, unknown>): void {
518
- const d = mounted?.[UNMOUNT] as (() => void) | undefined
519
- if (typeof d === 'function') d()
520
- }
521
-
522
- /**
523
- * Svelte-5-compatible `flushSync` — runs `fn` then flushes. Pyreon
524
- * batches synchronously, so this just invokes `fn`.
525
- */
526
- export function flushSync<T>(fn?: () => T): T | undefined {
527
- return fn ? fn() : undefined
528
- }
529
-
530
- // ─── createEventDispatcher needs props on ctx ────────────────────────────────
531
- // (jsx-runtime stores `props` on the RenderContext — see jsx-runtime.ts)
532
-
533
- // ─── Re-exports from @pyreon/core (control-flow parity) ──────────────────────
534
-
535
- export { ErrorBoundary, For, Match, Show, Suspense, Switch }
536
-
537
- // Mark the compat surface so framework Providers route natively.
538
- void nativeCompat
@@ -1 +0,0 @@
1
- export { Fragment, jsx, jsxs } from './jsx-runtime'