@pyreon/preact-compat 0.14.0 → 0.15.0
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 +20 -0
- package/lib/analysis/index.js.html +1 -1
- package/lib/analysis/jsx-runtime.js.html +1 -1
- package/lib/index.js +2 -3
- package/lib/jsx-runtime.js +2 -3
- package/package.json +8 -4
- package/src/index.ts +2 -4
- package/src/jsx-runtime.ts +5 -7
- package/src/preact-compat.browser.test.ts +37 -0
- package/src/tests/native-marker-bypass.test.tsx +63 -0
- package/lib/hooks.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/jsx-runtime.js.map +0 -1
- package/lib/signals.js.map +0 -1
- package/lib/types/hooks.d.ts.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/jsx-runtime.d.ts.map +0 -1
- package/lib/types/signals.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -124,3 +124,23 @@ Preact Signals API (mirrors `@preact/signals`).
|
|
|
124
124
|
- **`computed(fn)`** -- returns `{ value }` read-only accessor.
|
|
125
125
|
- **`effect(fn)`** -- reactive side effect, returns dispose function.
|
|
126
126
|
- **`batch(fn)`** -- coalesce multiple signal writes.
|
|
127
|
+
|
|
128
|
+
## Composing Pyreon framework components inside preact-compat
|
|
129
|
+
|
|
130
|
+
Pyreon's framework components (`RouterView`, `PyreonUI`, `FormProvider`, `QueryClientProvider`, …) ship marked with `nativeCompat()` from `@pyreon/core` — preact-compat's JSX runtime detects the marker and routes them through Pyreon's setup frame instead of the compat wrapper. **You don't need to do anything** for the 24 components shipped marked.
|
|
131
|
+
|
|
132
|
+
If you write your **own** Pyreon-flavored helper that uses `provide()` / `onMount()` / `onUnmount()` / `effect()` at component-body scope and use it in a preact-compat app, mark it explicitly:
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
import { nativeCompat, provide, createContext } from '@pyreon/core'
|
|
136
|
+
|
|
137
|
+
const MyCtx = createContext<string>('default')
|
|
138
|
+
|
|
139
|
+
function MyProvider(props: { value: string; children?: unknown }) {
|
|
140
|
+
provide(MyCtx, props.value)
|
|
141
|
+
return props.children as never
|
|
142
|
+
}
|
|
143
|
+
nativeCompat(MyProvider) // ← required for compat-mode apps
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Without the marker, the wrapper relocates the body's render context and `provide()` lands in a torn-down context stack — descendants read the default. See [`packages/core/core/src/compat-marker.ts`](../../core/core/src/compat-marker.ts) for details.
|
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src/index.ts","uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src/index.ts","uid":"2f430366-1"}]}],"isRoot":true},"nodeParts":{"2f430366-1":{"renderedLength":3276,"gzipLength":1311,"brotliLength":0,"metaUid":"2f430366-0"}},"nodeMetas":{"2f430366-0":{"id":"/src/index.ts","moduleParts":{"index.js":"2f430366-1"},"imported":[{"uid":"2f430366-2"},{"uid":"2f430366-3"},{"uid":"2f430366-4"}],"importedBy":[],"isEntry":true},"2f430366-2":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"2f430366-0"}]},"2f430366-3":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"2f430366-0"}]},"2f430366-4":{"id":"@pyreon/runtime-dom","moduleParts":{},"imported":[],"importedBy":[{"uid":"2f430366-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"jsx-runtime.js","children":[{"name":"src","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"jsx-runtime.js","children":[{"name":"src","children":[{"uid":"86b5580e-1","name":"jsx-runtime.ts"},{"uid":"86b5580e-3","name":"jsx-dev-runtime.ts"}]}]}],"isRoot":true},"nodeParts":{"86b5580e-1":{"renderedLength":5335,"gzipLength":1477,"brotliLength":0,"metaUid":"86b5580e-0"},"86b5580e-3":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"86b5580e-2"}},"nodeMetas":{"86b5580e-0":{"id":"/src/jsx-runtime.ts","moduleParts":{"jsx-runtime.js":"86b5580e-1"},"imported":[{"uid":"86b5580e-4"},{"uid":"86b5580e-5"}],"importedBy":[{"uid":"86b5580e-2"}]},"86b5580e-2":{"id":"/src/jsx-dev-runtime.ts","moduleParts":{"jsx-runtime.js":"86b5580e-3"},"imported":[{"uid":"86b5580e-0"}],"importedBy":[],"isEntry":true},"86b5580e-4":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"86b5580e-0"}]},"86b5580e-5":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"86b5580e-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ErrorBoundary, Fragment, Portal, Suspense, createContext as createContext$1, createRef, h as pyreonH, lazy, provide, useContext } from "@pyreon/core";
|
|
1
|
+
import { ErrorBoundary, Fragment, Portal, Suspense, createContext as createContext$1, createRef, h as pyreonH, lazy, nativeCompat, provide, useContext } from "@pyreon/core";
|
|
2
2
|
import { batch, signal } from "@pyreon/reactivity";
|
|
3
3
|
import { hydrateRoot, mount } from "@pyreon/runtime-dom";
|
|
4
4
|
|
|
@@ -19,7 +19,6 @@ function render(vnode, container) {
|
|
|
19
19
|
function hydrate(vnode, container) {
|
|
20
20
|
hydrateRoot(container, vnode);
|
|
21
21
|
}
|
|
22
|
-
const NATIVE_COMPONENT = Symbol.for("pyreon:native-compat");
|
|
23
22
|
/**
|
|
24
23
|
* Preact-compatible createContext — returns a context with a `.Provider` component.
|
|
25
24
|
*/
|
|
@@ -29,7 +28,7 @@ function createContext(defaultValue) {
|
|
|
29
28
|
provide(ctx, props.value);
|
|
30
29
|
return props.children;
|
|
31
30
|
});
|
|
32
|
-
Provider
|
|
31
|
+
nativeCompat(Provider);
|
|
33
32
|
return {
|
|
34
33
|
...ctx,
|
|
35
34
|
Provider
|
package/lib/jsx-runtime.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fragment, h, onUnmount } from "@pyreon/core";
|
|
1
|
+
import { Fragment, h, isNativeCompat, onUnmount } from "@pyreon/core";
|
|
2
2
|
import { signal } from "@pyreon/reactivity";
|
|
3
3
|
|
|
4
4
|
//#region src/jsx-runtime.ts
|
|
@@ -32,7 +32,6 @@ function scheduleEffects(ctx, entries) {
|
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
-
const NATIVE_COMPONENT = Symbol.for("pyreon:native-compat");
|
|
36
35
|
function isClassComponent(type) {
|
|
37
36
|
return type.prototype != null && typeof type.prototype.render === "function";
|
|
38
37
|
}
|
|
@@ -138,7 +137,7 @@ function jsx(type, props, key) {
|
|
|
138
137
|
...propsWithKey,
|
|
139
138
|
children
|
|
140
139
|
} : propsWithKey;
|
|
141
|
-
if (type
|
|
140
|
+
if (isNativeCompat(type)) return h(type, componentProps);
|
|
142
141
|
return h(wrapCompatComponent(type), componentProps);
|
|
143
142
|
}
|
|
144
143
|
const childArray = children === void 0 ? [] : Array.isArray(children) ? children : [children];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/preact-compat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Preact-compatible API shim for Pyreon — write Preact-style code that runs on Pyreon's reactive engine",
|
|
5
5
|
"homepage": "https://github.com/pyreon/pyreon/tree/main/packages/preact-compat#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"lib",
|
|
17
|
+
"!lib/**/*.map",
|
|
17
18
|
"src",
|
|
18
19
|
"README.md",
|
|
19
20
|
"LICENSE"
|
|
@@ -57,17 +58,20 @@
|
|
|
57
58
|
"build": "vl_rolldown_build",
|
|
58
59
|
"dev": "vl_rolldown_build-watch",
|
|
59
60
|
"test": "vitest run",
|
|
61
|
+
"test:browser": "vitest run --config ./vitest.browser.config.ts",
|
|
60
62
|
"typecheck": "tsc --noEmit",
|
|
61
63
|
"lint": "oxlint .",
|
|
62
64
|
"prepublishOnly": "bun run build"
|
|
63
65
|
},
|
|
64
66
|
"dependencies": {
|
|
65
|
-
"@pyreon/core": "^0.
|
|
66
|
-
"@pyreon/reactivity": "^0.
|
|
67
|
-
"@pyreon/runtime-dom": "^0.
|
|
67
|
+
"@pyreon/core": "^0.15.0",
|
|
68
|
+
"@pyreon/reactivity": "^0.15.0",
|
|
69
|
+
"@pyreon/runtime-dom": "^0.15.0"
|
|
68
70
|
},
|
|
69
71
|
"devDependencies": {
|
|
70
72
|
"@happy-dom/global-registrator": "^20.8.9",
|
|
73
|
+
"@pyreon/test-utils": "^0.13.2",
|
|
74
|
+
"@vitest/browser-playwright": "^4.1.4",
|
|
71
75
|
"happy-dom": "^20.8.3"
|
|
72
76
|
}
|
|
73
77
|
}
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
ErrorBoundary,
|
|
19
19
|
Fragment,
|
|
20
20
|
lazy,
|
|
21
|
+
nativeCompat,
|
|
21
22
|
Portal,
|
|
22
23
|
provide,
|
|
23
24
|
Suspense,
|
|
@@ -64,9 +65,6 @@ export interface PreactContext<T> {
|
|
|
64
65
|
Provider: ComponentFn<{ value: T; children?: VNodeChild }>
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
// Tag the Provider so wrapCompatComponent skips it (it's already a native component)
|
|
68
|
-
const NATIVE_COMPONENT = Symbol.for('pyreon:native-compat')
|
|
69
|
-
|
|
70
68
|
/**
|
|
71
69
|
* Preact-compatible createContext — returns a context with a `.Provider` component.
|
|
72
70
|
*/
|
|
@@ -77,7 +75,7 @@ export function createContext<T>(defaultValue: T): PreactContext<T> {
|
|
|
77
75
|
return props.children
|
|
78
76
|
}) as ComponentFn<{ value: T; children?: VNodeChild }>
|
|
79
77
|
// Mark as native so jsx() doesn't wrap it with wrapCompatComponent
|
|
80
|
-
|
|
78
|
+
nativeCompat(Provider)
|
|
81
79
|
return { ...ctx, Provider }
|
|
82
80
|
}
|
|
83
81
|
|
package/src/jsx-runtime.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'
|
|
13
|
-
import { Fragment, h, onUnmount } from '@pyreon/core'
|
|
13
|
+
import { Fragment, h, isNativeCompat, onUnmount } from '@pyreon/core'
|
|
14
14
|
import { signal } from '@pyreon/reactivity'
|
|
15
15
|
import type { Component } from './index'
|
|
16
16
|
|
|
@@ -80,10 +80,6 @@ function scheduleEffects(ctx: RenderContext, entries: EffectEntry[]): void {
|
|
|
80
80
|
})
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
// ─── Native component marker ────────────────────────────────────────────────
|
|
84
|
-
|
|
85
|
-
const NATIVE_COMPONENT = Symbol.for('pyreon:native-compat')
|
|
86
|
-
|
|
87
83
|
// ─── Class component detection ──────────────────────────────────────────────
|
|
88
84
|
|
|
89
85
|
function isClassComponent(type: Function): boolean {
|
|
@@ -241,8 +237,10 @@ export function jsx(
|
|
|
241
237
|
|
|
242
238
|
if (typeof type === 'function') {
|
|
243
239
|
const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey
|
|
244
|
-
// Native Pyreon components (
|
|
245
|
-
|
|
240
|
+
// Native Pyreon components (context Provider, RouterView, QueryClientProvider,
|
|
241
|
+
// etc.) skip compat wrapping — see `@pyreon/core`'s `nativeCompat()` for the
|
|
242
|
+
// full contract.
|
|
243
|
+
if (isNativeCompat(type)) {
|
|
246
244
|
return h(type as ComponentFn, componentProps)
|
|
247
245
|
}
|
|
248
246
|
// Wrap Preact-style component for re-render support
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { mountInBrowser } from '@pyreon/test-utils/browser'
|
|
3
|
+
import { createElement, Fragment } from './index'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Real-browser smoke test for `@pyreon/preact-compat`.
|
|
7
|
+
*
|
|
8
|
+
* Per the test-environment-parity rule (`pyreon/require-browser-smoke-test`),
|
|
9
|
+
* every browser-categorized package must ship at least one
|
|
10
|
+
* `*.browser.test.*` file. This catches regressions that happy-dom unit
|
|
11
|
+
* tests can hide: importing the public API and mounting through Preact's
|
|
12
|
+
* `h` shim in real Chromium.
|
|
13
|
+
*/
|
|
14
|
+
describe('@pyreon/preact-compat — browser smoke', () => {
|
|
15
|
+
it('mounts a Preact-style element via createElement', () => {
|
|
16
|
+
const vnode = createElement('div', { id: 'preact', class: 'shim' }, 'hello, preact')
|
|
17
|
+
const { container, unmount } = mountInBrowser(vnode)
|
|
18
|
+
const el = container.querySelector('#preact')!
|
|
19
|
+
expect(el.textContent).toBe('hello, preact')
|
|
20
|
+
expect(el.classList.contains('shim')).toBe(true)
|
|
21
|
+
unmount()
|
|
22
|
+
expect(document.getElementById('preact')).toBeNull()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('mounts a Fragment with multiple children', () => {
|
|
26
|
+
const vnode = createElement(
|
|
27
|
+
Fragment,
|
|
28
|
+
null,
|
|
29
|
+
createElement('span', { id: 'a' }, 'A'),
|
|
30
|
+
createElement('span', { id: 'b' }, 'B'),
|
|
31
|
+
)
|
|
32
|
+
const { container, unmount } = mountInBrowser(vnode)
|
|
33
|
+
expect(container.querySelector('#a')?.textContent).toBe('A')
|
|
34
|
+
expect(container.querySelector('#b')?.textContent).toBe('B')
|
|
35
|
+
unmount()
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ComponentFn } from '@pyreon/core'
|
|
2
|
+
import { createContext, h, nativeCompat, provide, useContext } from '@pyreon/core'
|
|
3
|
+
import { mount } from '@pyreon/runtime-dom'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import { jsx } from '../jsx-runtime'
|
|
6
|
+
|
|
7
|
+
// Per-compat unit-level regression test for the marker-bypass contract.
|
|
8
|
+
// See `react-compat/src/tests/native-marker-bypass.test.tsx` for the full
|
|
9
|
+
// rationale + bisect-verification notes — same shape, four parallel files
|
|
10
|
+
// (one per compat layer) so a regression in any one doesn't go unnoticed.
|
|
11
|
+
//
|
|
12
|
+
// Bisect-verified per file: removing the `if (isNativeCompat(type))` branch
|
|
13
|
+
// from preact-compat's jsx-runtime causes test #1 to fail with
|
|
14
|
+
// `expected [Function wrapped] to be [Function Native]`.
|
|
15
|
+
|
|
16
|
+
function container(): HTMLElement {
|
|
17
|
+
const el = document.createElement('div')
|
|
18
|
+
document.body.appendChild(el)
|
|
19
|
+
return el
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe('preact-compat — nativeCompat() marker bypass', () => {
|
|
23
|
+
it('jsx() routes marked components through h() directly (no wrapper)', () => {
|
|
24
|
+
const Native = (props: { children?: unknown }) => h('div', null, props.children as never)
|
|
25
|
+
nativeCompat(Native)
|
|
26
|
+
|
|
27
|
+
const vnode = jsx(Native, {})
|
|
28
|
+
|
|
29
|
+
expect(vnode.type).toBe(Native)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('jsx() wraps UNMARKED components (control — bypass is selective)', () => {
|
|
33
|
+
const Unmarked = (props: { children?: unknown }) => h('div', null, props.children as never)
|
|
34
|
+
|
|
35
|
+
const vnode = jsx(Unmarked, {})
|
|
36
|
+
|
|
37
|
+
expect(vnode.type).not.toBe(Unmarked)
|
|
38
|
+
expect(typeof vnode.type).toBe('function')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('marked Provider mounts inside Pyreon setup frame — provide() reaches descendants', () => {
|
|
42
|
+
const Ctx = createContext<string>('default')
|
|
43
|
+
|
|
44
|
+
const Provider: ComponentFn = (props) => {
|
|
45
|
+
provide(Ctx, props.value as string)
|
|
46
|
+
return props.children as never
|
|
47
|
+
}
|
|
48
|
+
nativeCompat(Provider)
|
|
49
|
+
|
|
50
|
+
const Consumer: ComponentFn = () => {
|
|
51
|
+
const value = useContext(Ctx)
|
|
52
|
+
return h('span', { 'data-value': value }, value)
|
|
53
|
+
}
|
|
54
|
+
nativeCompat(Consumer)
|
|
55
|
+
|
|
56
|
+
const el = container()
|
|
57
|
+
mount(jsx(Provider, { value: 'native', children: jsx(Consumer, {}) }), el)
|
|
58
|
+
|
|
59
|
+
const span = el.querySelector('span')
|
|
60
|
+
expect(span?.getAttribute('data-value')).toBe('native')
|
|
61
|
+
expect(span?.textContent).toBe('native')
|
|
62
|
+
})
|
|
63
|
+
})
|
package/lib/hooks.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","names":[],"sources":["../src/jsx-runtime.ts","../src/hooks.ts"],"sourcesContent":["/**\n * Compat JSX runtime for Preact compatibility mode.\n *\n * When `jsxImportSource` is redirected to `@pyreon/preact-compat` (via the vite\n * plugin's `compat: \"preact\"` option), OXC rewrites JSX to import from this file.\n *\n * For component VNodes, we wrap the component function so it returns a reactive\n * accessor — enabling Preact-style re-renders on state change while Pyreon's\n * existing renderer handles all DOM work.\n */\n\nimport type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'\nimport { Fragment, h, onUnmount } from '@pyreon/core'\nimport { signal } from '@pyreon/reactivity'\nimport type { Component } from './index'\n\nexport { Fragment }\n\n// ─── Render context (used by hooks) ──────────────────────────────────────────\n\nexport interface RenderContext {\n hooks: unknown[]\n scheduleRerender: () => void\n /** Effect entries pending execution after render */\n pendingEffects: EffectEntry[]\n /** Layout effect entries pending execution after render */\n pendingLayoutEffects: EffectEntry[]\n /** Set to true when the component is unmounted */\n unmounted: boolean\n}\n\nexport interface EffectEntry {\n fn: () => (() => void) | void\n deps: unknown[] | undefined\n cleanup: (() => void) | undefined\n}\n\nlet _currentCtx: RenderContext | null = null\nlet _hookIndex = 0\n\nexport function getCurrentCtx(): RenderContext | null {\n return _currentCtx\n}\n\nexport function getHookIndex(): number {\n return _hookIndex++\n}\n\nexport function beginRender(ctx: RenderContext): void {\n _currentCtx = ctx\n _hookIndex = 0\n ctx.pendingEffects = []\n ctx.pendingLayoutEffects = []\n}\n\nexport function endRender(): void {\n _currentCtx = null\n _hookIndex = 0\n}\n\n// ─── Effect runners ──────────────────────────────────────────────────────────\n\nfunction runLayoutEffects(entries: EffectEntry[]): void {\n for (const entry of entries) {\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n}\n\nfunction scheduleEffects(ctx: RenderContext, entries: EffectEntry[]): void {\n if (entries.length === 0) return\n queueMicrotask(() => {\n for (const entry of entries) {\n if (ctx.unmounted) return\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n })\n}\n\n// ─── Native component marker ────────────────────────────────────────────────\n\nconst NATIVE_COMPONENT = Symbol.for('pyreon:native-compat')\n\n// ─── Class component detection ──────────────────────────────────────────────\n\nfunction isClassComponent(type: Function): boolean {\n return type.prototype != null && typeof type.prototype.render === 'function'\n}\n\n// ─── Class component wrapping ───────────────────────────────────────────────\n\nfunction wrapClassComponent(ClassComp: Function): ComponentFn {\n const wrapped = ((props: Props) => {\n const instance = new (ClassComp as new (props: Props) => Component)(props)\n const version = signal(0)\n let updateScheduled = false\n\n // Override setState to trigger re-render via version signal\n const origSetState = instance.setState.bind(instance)\n instance.setState = (partial: Partial<Record<string, unknown>>) => {\n origSetState(partial)\n if (!updateScheduled) {\n updateScheduled = true\n queueMicrotask(() => {\n updateScheduled = false\n version.set(version.peek() + 1)\n })\n }\n }\n\n // Override forceUpdate\n instance.forceUpdate = () => {\n version.set(version.peek() + 1)\n }\n\n // Lifecycle: componentWillUnmount\n let didMountFired = false\n onUnmount(() => {\n if (typeof instance.componentWillUnmount === 'function') {\n instance.componentWillUnmount()\n }\n })\n\n // Return reactive accessor for re-renders\n return () => {\n const ver = version() // track for re-renders\n instance.props = props // update props on re-render\n\n // shouldComponentUpdate only applies after mount (ver > 0 means setState/forceUpdate)\n if (didMountFired && ver > 0 && typeof instance.shouldComponentUpdate === 'function') {\n if (!instance.shouldComponentUpdate(props, instance.state)) {\n return instance._lastResult // skip render\n }\n }\n\n const result = instance.render()\n instance._lastResult = result\n\n // componentDidMount fires once after the initial render settles\n if (!didMountFired) {\n didMountFired = true\n if (typeof instance.componentDidMount === 'function') {\n queueMicrotask(() => instance.componentDidMount!())\n }\n } else if (ver > 0) {\n // componentDidUpdate only fires on explicit re-renders (setState/forceUpdate)\n if (typeof instance.componentDidUpdate === 'function') {\n queueMicrotask(() => instance.componentDidUpdate!())\n }\n }\n\n return result\n }\n }) as unknown as ComponentFn\n return wrapped\n}\n\n// ─── Component wrapping ──────────────────────────────────────────────────────\n\nconst _wrapperCache = new WeakMap<Function, ComponentFn>()\n\nfunction wrapCompatComponent(preactComponent: Function): ComponentFn {\n let wrapped = _wrapperCache.get(preactComponent)\n if (wrapped) return wrapped\n\n // Handle class components (those with prototype.render)\n if (isClassComponent(preactComponent)) {\n wrapped = wrapClassComponent(preactComponent)\n _wrapperCache.set(preactComponent, wrapped)\n return wrapped\n }\n\n // The wrapper returns a reactive accessor (() => VNodeChild) which Pyreon's\n // mountChild treats as a reactive expression via mountReactive.\n wrapped = ((props: Props) => {\n const ctx: RenderContext = {\n hooks: [],\n scheduleRerender: () => {\n // Will be replaced below after version signal is created\n },\n pendingEffects: [],\n pendingLayoutEffects: [],\n unmounted: false,\n }\n\n const version = signal(0)\n let updateScheduled = false\n\n ctx.scheduleRerender = () => {\n if (ctx.unmounted || updateScheduled) return\n updateScheduled = true\n queueMicrotask(() => {\n updateScheduled = false\n if (!ctx.unmounted) version.set(version.peek() + 1)\n })\n }\n\n // Register cleanup for all hooks on unmount\n onUnmount(() => {\n ctx.unmounted = true\n for (const hook of ctx.hooks) {\n if (hook && typeof hook === 'object' && 'cleanup' in hook) {\n const entry = hook as EffectEntry\n if (typeof entry.cleanup === 'function') entry.cleanup()\n }\n }\n })\n\n // Return reactive accessor — Pyreon's mountChild calls mountReactive\n return () => {\n version() // tracked read — triggers re-execution when state changes\n beginRender(ctx)\n const result = (preactComponent as ComponentFn)(props)\n const layoutEffects = ctx.pendingLayoutEffects\n const effects = ctx.pendingEffects\n endRender()\n\n runLayoutEffects(layoutEffects)\n scheduleEffects(ctx, effects)\n\n return result\n }\n }) as unknown as ComponentFn\n\n _wrapperCache.set(preactComponent, wrapped)\n return wrapped\n}\n\n// ─── JSX functions ───────────────────────────────────────────────────────────\n\nexport function jsx(\n type: string | ComponentFn | symbol,\n props: Props & { children?: VNodeChild | VNodeChild[] },\n key?: string | number | null,\n): VNode {\n const { children, ...rest } = props\n const propsWithKey = (key != null ? { ...rest, key } : rest) as Props\n\n if (typeof type === 'function') {\n const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey\n // Native Pyreon components (e.g. context Provider) skip compat wrapping\n if ((type as unknown as Record<symbol, boolean>)[NATIVE_COMPONENT]) {\n return h(type as ComponentFn, componentProps)\n }\n // Wrap Preact-style component for re-render support\n const wrapped = wrapCompatComponent(type)\n return h(wrapped, componentProps)\n }\n\n // DOM element or symbol (Fragment): children go in vnode.children\n const childArray = children === undefined ? [] : Array.isArray(children) ? children : [children]\n\n // Map Preact-style attributes to standard HTML attributes\n if (typeof type === 'string') {\n if (propsWithKey.className !== undefined) {\n propsWithKey.class = propsWithKey.className\n delete propsWithKey.className\n }\n if (propsWithKey.htmlFor !== undefined) {\n propsWithKey.for = propsWithKey.htmlFor\n delete propsWithKey.htmlFor\n }\n\n // Preact's onChange fires on every keystroke for form elements (like onInput)\n if (\n (type === 'input' || type === 'textarea' || type === 'select') &&\n propsWithKey.onChange !== undefined\n ) {\n if (propsWithKey.onInput === undefined) {\n propsWithKey.onInput = propsWithKey.onChange\n }\n delete propsWithKey.onChange\n }\n\n // autoFocus → autofocus\n if (propsWithKey.autoFocus !== undefined) {\n propsWithKey.autofocus = propsWithKey.autoFocus\n delete propsWithKey.autoFocus\n }\n\n // defaultValue / defaultChecked → value / checked when no controlled value\n if (type === 'input' || type === 'textarea') {\n if (propsWithKey.defaultValue !== undefined && propsWithKey.value === undefined) {\n propsWithKey.value = propsWithKey.defaultValue\n delete propsWithKey.defaultValue\n }\n if (propsWithKey.defaultChecked !== undefined && propsWithKey.checked === undefined) {\n propsWithKey.checked = propsWithKey.defaultChecked\n delete propsWithKey.defaultChecked\n }\n }\n\n // Strip Preact-only props that have no DOM equivalent\n delete propsWithKey.suppressHydrationWarning\n }\n\n return h(type, propsWithKey, ...(childArray as VNodeChild[]))\n}\n\nexport const jsxs = jsx\nexport const jsxDEV = jsx\n","/**\n * @pyreon/preact-compat/hooks\n *\n * Preact-compatible hooks — separate import like `preact/hooks`.\n *\n * Components re-render on state change — just like Preact. Hooks return plain\n * values and use deps arrays for memoization. Existing Preact code works\n * unchanged when paired with `pyreon({ compat: \"preact\" })` in your vite config.\n */\n\nimport type { VNodeChild } from '@pyreon/core'\nimport { onErrorCaptured, useContext } from '@pyreon/core'\nimport type { EffectEntry } from './jsx-runtime'\nimport { getCurrentCtx, getHookIndex } from './jsx-runtime'\n\nexport { useContext }\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction requireCtx() {\n const ctx = getCurrentCtx()\n if (!ctx) throw new Error('Hook called outside of a component render')\n return ctx\n}\n\nfunction depsChanged(a: unknown[] | undefined, b: unknown[] | undefined): boolean {\n if (a === undefined || b === undefined) return true\n if (a.length !== b.length) return true\n for (let i = 0; i < a.length; i++) {\n if (!Object.is(a[i], b[i])) return true\n }\n return false\n}\n\nfunction shallowEqual<P extends Record<string, unknown>>(a: P, b: P): boolean {\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n if (keysA.length !== keysB.length) return false\n for (const k of keysA) {\n if (!Object.is(a[k], b[k])) return false\n }\n return true\n}\n\n// ─── useState ────────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useState` — returns `[value, setter]`.\n * Triggers a component re-render when the setter is called.\n *\n * The setter has stable identity across renders (same reference every time).\n */\nexport function useState<T>(initial: T | (() => T)): [T, (v: T | ((prev: T) => T)) => void] {\n const ctx = requireCtx()\n const idx = getHookIndex()\n\n if (ctx.hooks.length <= idx) {\n const val = typeof initial === 'function' ? (initial as () => T)() : initial\n // Store both value and a STABLE setter in one hook slot so setter identity\n // never changes across renders (Preact/React guarantee).\n const entry = { value: val, setter: null as unknown as (v: T | ((prev: T) => T)) => void }\n entry.setter = (v: T | ((prev: T) => T)) => {\n const current = entry.value\n const next = typeof v === 'function' ? (v as (prev: T) => T)(current) : v\n if (Object.is(current, next)) return\n entry.value = next\n ctx.scheduleRerender()\n }\n ctx.hooks.push(entry)\n }\n\n const entry = ctx.hooks[idx] as { value: T; setter: (v: T | ((prev: T) => T)) => void }\n return [entry.value, entry.setter]\n}\n\n// ─── useEffect ───────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useEffect` — runs after render when deps change.\n * Returns cleanup on unmount and before re-running.\n */\nexport function useEffect(fn: () => (() => void) | void, deps?: unknown[]): void {\n const ctx = requireCtx()\n const idx = getHookIndex()\n\n if (ctx.hooks.length <= idx) {\n // First render — always run\n const entry: EffectEntry = { fn, deps, cleanup: undefined }\n ctx.hooks.push(entry)\n ctx.pendingEffects.push(entry)\n } else {\n const entry = ctx.hooks[idx] as EffectEntry\n if (depsChanged(entry.deps, deps)) {\n entry.fn = fn\n entry.deps = deps\n ctx.pendingEffects.push(entry)\n }\n }\n}\n\n// ─── useLayoutEffect ─────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useLayoutEffect` — runs synchronously after DOM mutations.\n */\nexport function useLayoutEffect(fn: () => (() => void) | void, deps?: unknown[]): void {\n const ctx = requireCtx()\n const idx = getHookIndex()\n\n if (ctx.hooks.length <= idx) {\n const entry: EffectEntry = { fn, deps, cleanup: undefined }\n ctx.hooks.push(entry)\n ctx.pendingLayoutEffects.push(entry)\n } else {\n const entry = ctx.hooks[idx] as EffectEntry\n if (depsChanged(entry.deps, deps)) {\n entry.fn = fn\n entry.deps = deps\n ctx.pendingLayoutEffects.push(entry)\n }\n }\n}\n\n// ─── useMemo ─────────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useMemo` — returns the cached value, recomputed when deps change.\n */\nexport function useMemo<T>(fn: () => T, deps: unknown[]): T {\n const ctx = requireCtx()\n const idx = getHookIndex()\n\n if (ctx.hooks.length <= idx) {\n const value = fn()\n ctx.hooks.push({ value, deps })\n return value\n }\n\n const entry = ctx.hooks[idx] as { value: T; deps: unknown[] }\n if (depsChanged(entry.deps, deps)) {\n entry.value = fn()\n entry.deps = deps\n }\n return entry.value\n}\n\n// ─── useCallback ─────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useCallback` — returns the cached function when deps haven't changed.\n */\nexport function useCallback<T extends (...args: never[]) => unknown>(fn: T, deps: unknown[]): T {\n return useMemo(() => fn, deps)\n}\n\n// ─── useRef ──────────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useRef` — returns `{ current }` persisted across re-renders.\n */\nexport function useRef<T>(initial?: T): { current: T | null } {\n const ctx = requireCtx()\n const idx = getHookIndex()\n\n if (ctx.hooks.length <= idx) {\n const ref = { current: initial !== undefined ? (initial as T) : null }\n ctx.hooks.push(ref)\n }\n\n return ctx.hooks[idx] as { current: T | null }\n}\n\n// ─── useReducer ──────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useReducer` — returns `[state, dispatch]`.\n * Supports the 3-argument form: `useReducer(reducer, initialArg, init)`.\n *\n * Dispatch has stable identity across renders (same reference every time).\n */\nexport function useReducer<S, A>(\n reducer: (state: S, action: A) => S,\n initialArg: S | (() => S),\n init?: (arg: S) => S,\n): [S, (action: A) => void] {\n const ctx = requireCtx()\n const idx = getHookIndex()\n\n if (ctx.hooks.length <= idx) {\n let initial: S\n if (init) {\n initial = init(initialArg as S)\n } else if (typeof initialArg === 'function') {\n initial = (initialArg as () => S)()\n } else {\n initial = initialArg\n }\n // Store both value and a STABLE dispatch in one hook slot so dispatch identity\n // never changes across renders (Preact/React guarantee).\n const entry = { value: initial, dispatch: null as unknown as (action: A) => void }\n entry.dispatch = (action: A) => {\n const current = entry.value\n const next = reducer(current, action)\n if (Object.is(current, next)) return\n entry.value = next\n ctx.scheduleRerender()\n }\n ctx.hooks.push(entry)\n }\n\n const entry = ctx.hooks[idx] as { value: S; dispatch: (action: A) => void }\n return [entry.value, entry.dispatch]\n}\n\n// ─── useId ───────────────────────────────────────────────────────────────────\n\nlet _idCounter = 0\n\n/**\n * Preact-compatible `useId` — returns a stable unique string per hook call.\n */\nexport function useId(): string {\n const ctx = requireCtx()\n const idx = getHookIndex()\n\n if (ctx.hooks.length <= idx) {\n ctx.hooks.push(`:r${(_idCounter++).toString(36)}:`)\n }\n\n return ctx.hooks[idx] as string\n}\n\n// ─── Optimization ────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `memo` — wraps a component to skip re-render when props\n * are shallowly equal.\n *\n * Each component INSTANCE gets its own props/result cache via a hook slot,\n * so two `<MemoComp />` usages don't share memoization state.\n */\nexport function memo<P extends Record<string, unknown>>(\n component: (props: P) => VNodeChild,\n areEqual?: (prevProps: P, nextProps: P) => boolean,\n): (props: P) => VNodeChild {\n const compare = areEqual ?? shallowEqual\n\n // Fallback closure-level cache for calls outside a compat render context\n // (e.g. direct function calls in tests). Inside a render context, each\n // component instance gets its own cache via a hook slot.\n let _fallbackPrevProps: P | null = null\n let _fallbackPrevResult: VNodeChild = null\n\n const memoized = (props: P) => {\n const ctx = getCurrentCtx()\n if (ctx) {\n // Per-instance cache via hook slot\n const idx = getHookIndex()\n if (ctx.hooks.length <= idx) {\n ctx.hooks.push({ prevProps: null as P | null, prevResult: null as VNodeChild })\n }\n const cache = ctx.hooks[idx] as { prevProps: P | null; prevResult: VNodeChild }\n if (cache.prevProps !== null && compare(cache.prevProps, props)) {\n return cache.prevResult\n }\n cache.prevProps = props\n cache.prevResult = component(props)\n return cache.prevResult\n }\n // No compat context — use closure-level fallback cache\n if (_fallbackPrevProps !== null && compare(_fallbackPrevProps, props)) {\n return _fallbackPrevResult\n }\n _fallbackPrevProps = props\n _fallbackPrevResult = component(props)\n return _fallbackPrevResult\n }\n memoized.displayName =\n (component as unknown as { displayName?: string }).displayName || component.name || 'Memo'\n return memoized\n}\n\n// ─── forwardRef ─────────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `forwardRef` — pass-through in Pyreon.\n * Refs are regular props in Pyreon, so no wrapper is needed.\n * The render function receives (props, ref) — we merge ref into props.\n */\nexport function forwardRef<P extends Record<string, unknown>>(\n render: (props: P, ref: { current: unknown } | null) => VNodeChild,\n): (props: P & { ref?: { current: unknown } | null }) => VNodeChild {\n const forwarded = (props: P & { ref?: { current: unknown } | null }) => {\n const { ref, ...rest } = props\n return render(rest as P, ref ?? null)\n }\n forwarded.displayName =\n (render as unknown as { displayName?: string }).displayName || render.name || 'ForwardRef'\n return forwarded\n}\n\n// ─── useImperativeHandle ────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useImperativeHandle`.\n */\nexport function useImperativeHandle<T>(\n ref: { current: T | null } | null | undefined,\n init: () => T,\n deps?: unknown[],\n): void {\n useLayoutEffect(() => {\n if (ref) ref.current = init()\n return () => {\n if (ref) ref.current = null\n }\n }, deps)\n}\n\n// ─── useDebugValue ──────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useDebugValue` — no-op in Pyreon (no Preact DevTools integration).\n */\nexport function useDebugValue<T>(_value: T, _format?: (v: T) => unknown): void {}\n\n// ─── useTransition ──────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useTransition` — returns `[isPending, startTransition]`.\n *\n * In Pyreon's signal-based reactivity there is no concept of concurrent\n * rendering lanes. The callback is executed synchronously and `isPending`\n * is always `false`. This shim exists so Preact/React code that uses\n * `useTransition` compiles and runs without changes.\n */\nexport function useTransition(): [boolean, (fn: () => void) => void] {\n return [false, (fn) => fn()]\n}\n\n// ─── useDeferredValue ───────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useDeferredValue` — returns the value as-is.\n *\n * In Pyreon's signal-based reactivity there are no concurrent rendering lanes,\n * so the value is never \"deferred\". This shim exists so Preact/React code that\n * uses `useDeferredValue` compiles and runs without changes.\n */\nexport function useDeferredValue<T>(value: T): T {\n return value\n}\n\n// ─── useErrorBoundary ────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `useErrorBoundary`.\n * Wraps Pyreon's `onErrorCaptured`.\n */\nexport { onErrorCaptured as useErrorBoundary }\n"],"mappings":";;;AAqCA,IAAI,cAAoC;AACxC,IAAI,aAAa;AAEjB,SAAgB,gBAAsC;AACpD,QAAO;;AAGT,SAAgB,eAAuB;AACrC,QAAO;;;;;AC1BT,SAAS,aAAa;CACpB,MAAM,MAAM,eAAe;AAC3B,KAAI,CAAC,IAAK,OAAM,IAAI,MAAM,4CAA4C;AACtE,QAAO;;AAGT,SAAS,YAAY,GAA0B,GAAmC;AAChF,KAAI,MAAM,UAAa,MAAM,OAAW,QAAO;AAC/C,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,IAC5B,KAAI,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,GAAG,CAAE,QAAO;AAErC,QAAO;;AAGT,SAAS,aAAgD,GAAM,GAAe;CAC5E,MAAM,QAAQ,OAAO,KAAK,EAAE;CAC5B,MAAM,QAAQ,OAAO,KAAK,EAAE;AAC5B,KAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAC1C,MAAK,MAAM,KAAK,MACd,KAAI,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,GAAG,CAAE,QAAO;AAErC,QAAO;;;;;;;;AAWT,SAAgB,SAAY,SAAgE;CAC1F,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,cAAc;AAE1B,KAAI,IAAI,MAAM,UAAU,KAAK;EAI3B,MAAM,QAAQ;GAAE,OAHJ,OAAO,YAAY,aAAc,SAAqB,GAAG;GAGzC,QAAQ;GAAsD;AAC1F,QAAM,UAAU,MAA4B;GAC1C,MAAM,UAAU,MAAM;GACtB,MAAM,OAAO,OAAO,MAAM,aAAc,EAAqB,QAAQ,GAAG;AACxE,OAAI,OAAO,GAAG,SAAS,KAAK,CAAE;AAC9B,SAAM,QAAQ;AACd,OAAI,kBAAkB;;AAExB,MAAI,MAAM,KAAK,MAAM;;CAGvB,MAAM,QAAQ,IAAI,MAAM;AACxB,QAAO,CAAC,MAAM,OAAO,MAAM,OAAO;;;;;;AASpC,SAAgB,UAAU,IAA+B,MAAwB;CAC/E,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,cAAc;AAE1B,KAAI,IAAI,MAAM,UAAU,KAAK;EAE3B,MAAM,QAAqB;GAAE;GAAI;GAAM,SAAS;GAAW;AAC3D,MAAI,MAAM,KAAK,MAAM;AACrB,MAAI,eAAe,KAAK,MAAM;QACzB;EACL,MAAM,QAAQ,IAAI,MAAM;AACxB,MAAI,YAAY,MAAM,MAAM,KAAK,EAAE;AACjC,SAAM,KAAK;AACX,SAAM,OAAO;AACb,OAAI,eAAe,KAAK,MAAM;;;;;;;AAUpC,SAAgB,gBAAgB,IAA+B,MAAwB;CACrF,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,cAAc;AAE1B,KAAI,IAAI,MAAM,UAAU,KAAK;EAC3B,MAAM,QAAqB;GAAE;GAAI;GAAM,SAAS;GAAW;AAC3D,MAAI,MAAM,KAAK,MAAM;AACrB,MAAI,qBAAqB,KAAK,MAAM;QAC/B;EACL,MAAM,QAAQ,IAAI,MAAM;AACxB,MAAI,YAAY,MAAM,MAAM,KAAK,EAAE;AACjC,SAAM,KAAK;AACX,SAAM,OAAO;AACb,OAAI,qBAAqB,KAAK,MAAM;;;;;;;AAU1C,SAAgB,QAAW,IAAa,MAAoB;CAC1D,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,cAAc;AAE1B,KAAI,IAAI,MAAM,UAAU,KAAK;EAC3B,MAAM,QAAQ,IAAI;AAClB,MAAI,MAAM,KAAK;GAAE;GAAO;GAAM,CAAC;AAC/B,SAAO;;CAGT,MAAM,QAAQ,IAAI,MAAM;AACxB,KAAI,YAAY,MAAM,MAAM,KAAK,EAAE;AACjC,QAAM,QAAQ,IAAI;AAClB,QAAM,OAAO;;AAEf,QAAO,MAAM;;;;;AAQf,SAAgB,YAAqD,IAAO,MAAoB;AAC9F,QAAO,cAAc,IAAI,KAAK;;;;;AAQhC,SAAgB,OAAU,SAAoC;CAC5D,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,cAAc;AAE1B,KAAI,IAAI,MAAM,UAAU,KAAK;EAC3B,MAAM,MAAM,EAAE,SAAS,YAAY,SAAa,UAAgB,MAAM;AACtE,MAAI,MAAM,KAAK,IAAI;;AAGrB,QAAO,IAAI,MAAM;;;;;;;;AAWnB,SAAgB,WACd,SACA,YACA,MAC0B;CAC1B,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,cAAc;AAE1B,KAAI,IAAI,MAAM,UAAU,KAAK;EAC3B,IAAI;AACJ,MAAI,KACF,WAAU,KAAK,WAAgB;WACtB,OAAO,eAAe,WAC/B,WAAW,YAAwB;MAEnC,WAAU;EAIZ,MAAM,QAAQ;GAAE,OAAO;GAAS,UAAU;GAAwC;AAClF,QAAM,YAAY,WAAc;GAC9B,MAAM,UAAU,MAAM;GACtB,MAAM,OAAO,QAAQ,SAAS,OAAO;AACrC,OAAI,OAAO,GAAG,SAAS,KAAK,CAAE;AAC9B,SAAM,QAAQ;AACd,OAAI,kBAAkB;;AAExB,MAAI,MAAM,KAAK,MAAM;;CAGvB,MAAM,QAAQ,IAAI,MAAM;AACxB,QAAO,CAAC,MAAM,OAAO,MAAM,SAAS;;AAKtC,IAAI,aAAa;;;;AAKjB,SAAgB,QAAgB;CAC9B,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,cAAc;AAE1B,KAAI,IAAI,MAAM,UAAU,IACtB,KAAI,MAAM,KAAK,MAAM,cAAc,SAAS,GAAG,CAAC,GAAG;AAGrD,QAAO,IAAI,MAAM;;;;;;;;;AAYnB,SAAgB,KACd,WACA,UAC0B;CAC1B,MAAM,UAAU,YAAY;CAK5B,IAAI,qBAA+B;CACnC,IAAI,sBAAkC;CAEtC,MAAM,YAAY,UAAa;EAC7B,MAAM,MAAM,eAAe;AAC3B,MAAI,KAAK;GAEP,MAAM,MAAM,cAAc;AAC1B,OAAI,IAAI,MAAM,UAAU,IACtB,KAAI,MAAM,KAAK;IAAE,WAAW;IAAkB,YAAY;IAAoB,CAAC;GAEjF,MAAM,QAAQ,IAAI,MAAM;AACxB,OAAI,MAAM,cAAc,QAAQ,QAAQ,MAAM,WAAW,MAAM,CAC7D,QAAO,MAAM;AAEf,SAAM,YAAY;AAClB,SAAM,aAAa,UAAU,MAAM;AACnC,UAAO,MAAM;;AAGf,MAAI,uBAAuB,QAAQ,QAAQ,oBAAoB,MAAM,CACnE,QAAO;AAET,uBAAqB;AACrB,wBAAsB,UAAU,MAAM;AACtC,SAAO;;AAET,UAAS,cACN,UAAkD,eAAe,UAAU,QAAQ;AACtF,QAAO;;;;;;;AAUT,SAAgB,WACd,QACkE;CAClE,MAAM,aAAa,UAAqD;EACtE,MAAM,EAAE,KAAK,GAAG,SAAS;AACzB,SAAO,OAAO,MAAW,OAAO,KAAK;;AAEvC,WAAU,cACP,OAA+C,eAAe,OAAO,QAAQ;AAChF,QAAO;;;;;AAQT,SAAgB,oBACd,KACA,MACA,MACM;AACN,uBAAsB;AACpB,MAAI,IAAK,KAAI,UAAU,MAAM;AAC7B,eAAa;AACX,OAAI,IAAK,KAAI,UAAU;;IAExB,KAAK;;;;;AAQV,SAAgB,cAAiB,QAAW,SAAmC;;;;;;;;;AAY/E,SAAgB,gBAAqD;AACnE,QAAO,CAAC,QAAQ,OAAO,IAAI,CAAC;;;;;;;;;AAY9B,SAAgB,iBAAoB,OAAa;AAC/C,QAAO"}
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["pyreonCreateContext"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @pyreon/preact-compat\n *\n * Preact-compatible API shim that runs on Pyreon's reactive engine.\n *\n * Provides the core Preact API surface: h, Fragment, render, hydrate,\n * Component class, PureComponent, createContext, createRef, cloneElement,\n * toChildArray, isValidElement, createPortal, lazy, Suspense, ErrorBoundary,\n * and the options hook object.\n *\n * For hooks, import from \"@pyreon/preact-compat/hooks\".\n * For signals, import from \"@pyreon/preact-compat/signals\".\n */\n\nimport type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'\nimport {\n createRef,\n ErrorBoundary,\n Fragment,\n lazy,\n Portal,\n provide,\n Suspense,\n createContext as pyreonCreateContext,\n h as pyreonH,\n useContext,\n} from '@pyreon/core'\nimport { batch, signal } from '@pyreon/reactivity'\nimport { hydrateRoot, mount } from '@pyreon/runtime-dom'\n\n// ─── Core JSX ────────────────────────────────────────────────────────────────\n\n/** Preact's hyperscript function — maps directly to Pyreon's h() */\nexport { pyreonH as h }\n\n/** Alias: Preact also exports createElement */\nexport const createElement = pyreonH\n\nexport { Fragment }\n\n// ─── Render / Hydrate ────────────────────────────────────────────────────────\n\n/**\n * Preact's `render(vnode, container)`.\n * Maps to Pyreon's `mount(vnode, container)`.\n */\nexport function render(vnode: VNodeChild, container: Element): void {\n mount(vnode, container)\n}\n\n/**\n * Preact's `hydrate(vnode, container)`.\n * Maps to Pyreon's `hydrateRoot(container, vnode)`.\n */\nexport function hydrate(vnode: VNodeChild, container: Element): void {\n hydrateRoot(container, vnode as VNode)\n}\n\n// ─── Context ─────────────────────────────────────────────────────────────────\n\nexport interface PreactContext<T> {\n readonly id: symbol\n readonly defaultValue: T\n Provider: ComponentFn<{ value: T; children?: VNodeChild }>\n}\n\n// Tag the Provider so wrapCompatComponent skips it (it's already a native component)\nconst NATIVE_COMPONENT = Symbol.for('pyreon:native-compat')\n\n/**\n * Preact-compatible createContext — returns a context with a `.Provider` component.\n */\nexport function createContext<T>(defaultValue: T): PreactContext<T> {\n const ctx = pyreonCreateContext<T>(defaultValue)\n const Provider = ((props: { value: T; children?: VNodeChild }) => {\n provide(ctx, props.value)\n return props.children\n }) as ComponentFn<{ value: T; children?: VNodeChild }>\n // Mark as native so jsx() doesn't wrap it with wrapCompatComponent\n ;(Provider as unknown as Record<symbol, boolean>)[NATIVE_COMPONENT] = true\n return { ...ctx, Provider }\n}\n\nexport { useContext }\n\n// ─── Refs ────────────────────────────────────────────────────────────────────\n\nexport { createRef }\n\n// ─── Component class ─────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible class-based Component.\n *\n * Wraps Pyreon's signal-based reactivity so `setState` triggers re-renders.\n * Usage: `class MyComp extends Component { render() { ... } }`\n */\nexport class Component<\n P extends Props = Props,\n S extends Record<string, unknown> = Record<string, unknown>,\n> {\n props: P\n state: S\n _stateSignal: ReturnType<typeof signal<S>>\n _lastResult?: VNodeChild\n\n // Lifecycle methods (overridden by subclasses)\n componentDidMount?(): void\n componentDidUpdate?(): void\n componentWillUnmount?(): void\n shouldComponentUpdate?(nextProps: P, nextState: S): boolean\n\n constructor(props: P) {\n this.props = props\n this.state = {} as S\n this._stateSignal = signal<S>(this.state)\n }\n\n /**\n * Update state — accepts a partial state object or an updater function.\n * Merges into existing state (shallow merge, like Preact/React).\n */\n setState(partial: Partial<S> | ((prev: S) => Partial<S>)): void {\n batch(() => {\n const current = this._stateSignal()\n const update =\n typeof partial === 'function' ? (partial as (prev: S) => Partial<S>)(current) : partial\n const next = { ...current, ...update } as S\n this.state = next\n this._stateSignal.set(next)\n })\n }\n\n /**\n * Force a re-render. In Pyreon this triggers the state signal to re-fire.\n */\n forceUpdate(): void {\n this._stateSignal.set({ ...this.state })\n }\n\n /**\n * Override in subclass to return VNode tree.\n */\n render(): VNodeChild {\n return null\n }\n}\n\n// ─── PureComponent ──────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible PureComponent — extends Component.\n * In Pyreon's compat layer this behaves identically to Component\n * (signal-based reactivity already avoids unnecessary re-renders).\n */\nexport class PureComponent<\n P extends Props = Props,\n S extends Record<string, unknown> = Record<string, unknown>,\n> extends Component<P, S> {}\n\n// ─── cloneElement ────────────────────────────────────────────────────────────\n\n/**\n * Clone a VNode with merged props (like Preact's cloneElement).\n */\nexport function cloneElement(vnode: VNode, props?: Props, ...children: VNodeChild[]): VNode {\n const mergedProps = props ? { ...vnode.props, ...props } : { ...vnode.props }\n const mergedChildren = children.length > 0 ? children : vnode.children\n return {\n type: vnode.type,\n props: mergedProps,\n children: mergedChildren,\n key: (props?.key as string | number | null) ?? vnode.key,\n }\n}\n\n// ─── toChildArray ────────────────────────────────────────────────────────────\n\n/**\n * Flatten children into a flat array, filtering out null/undefined/boolean.\n * Matches Preact's `toChildArray` utility.\n */\ntype NestedChildren = VNodeChild | NestedChildren[]\n\nexport function toChildArray(children: NestedChildren): VNodeChild[] {\n const result: VNodeChild[] = []\n flatten(children, result)\n return result\n}\n\nfunction flatten(value: NestedChildren, out: VNodeChild[]): void {\n if (value == null || typeof value === 'boolean') return\n if (Array.isArray(value)) {\n for (const child of value) {\n flatten(child, out)\n }\n } else {\n out.push(value as VNodeChild)\n }\n}\n\n// ─── isValidElement ──────────────────────────────────────────────────────────\n\n/**\n * Check if a value is a VNode (like Preact's isValidElement).\n */\nexport function isValidElement(x: unknown): x is VNode {\n return (\n x !== null &&\n typeof x === 'object' &&\n 'type' in (x as Record<string, unknown>) &&\n 'props' in (x as Record<string, unknown>) &&\n 'children' in (x as Record<string, unknown>)\n )\n}\n\n// ─── createPortal ───────────────────────────────────────────────────────────\n\n/**\n * Preact-compatible `createPortal(children, target)`.\n */\nexport function createPortal(children: VNodeChild, target: Element): VNodeChild {\n return Portal({ target, children })\n}\n\n// ─── Suspense / lazy / ErrorBoundary ─────────────────────────────────────────\n\nexport { ErrorBoundary, lazy, Suspense }\n\n// ─── options ─────────────────────────────────────────────────────────────────\n\n/**\n * Preact's plugin/hook system. Exposed as an empty object for compatibility\n * with libraries that check for `options._hook`, `options.vnode`, etc.\n */\nexport const options: Record<string, unknown> = {}\n\n// ─── version ────────────────────────────────────────────────────────────────\n\nexport const version = '10.0.0-pyreon'\n"],"mappings":";;;;;;AAoCA,MAAa,gBAAgB;;;;;AAU7B,SAAgB,OAAO,OAAmB,WAA0B;AAClE,OAAM,OAAO,UAAU;;;;;;AAOzB,SAAgB,QAAQ,OAAmB,WAA0B;AACnE,aAAY,WAAW,MAAe;;AAYxC,MAAM,mBAAmB,OAAO,IAAI,uBAAuB;;;;AAK3D,SAAgB,cAAiB,cAAmC;CAClE,MAAM,MAAMA,gBAAuB,aAAa;CAChD,MAAM,aAAa,UAA+C;AAChE,UAAQ,KAAK,MAAM,MAAM;AACzB,SAAO,MAAM;;AAGd,CAAC,SAAgD,oBAAoB;AACtE,QAAO;EAAE,GAAG;EAAK;EAAU;;;;;;;;AAiB7B,IAAa,YAAb,MAGE;CACA;CACA;CACA;CACA;CAQA,YAAY,OAAU;AACpB,OAAK,QAAQ;AACb,OAAK,QAAQ,EAAE;AACf,OAAK,eAAe,OAAU,KAAK,MAAM;;;;;;CAO3C,SAAS,SAAuD;AAC9D,cAAY;GACV,MAAM,UAAU,KAAK,cAAc;GACnC,MAAM,SACJ,OAAO,YAAY,aAAc,QAAoC,QAAQ,GAAG;GAClF,MAAM,OAAO;IAAE,GAAG;IAAS,GAAG;IAAQ;AACtC,QAAK,QAAQ;AACb,QAAK,aAAa,IAAI,KAAK;IAC3B;;;;;CAMJ,cAAoB;AAClB,OAAK,aAAa,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC;;;;;CAM1C,SAAqB;AACnB,SAAO;;;;;;;;AAWX,IAAa,gBAAb,cAGU,UAAgB;;;;AAO1B,SAAgB,aAAa,OAAc,OAAe,GAAG,UAA+B;CAC1F,MAAM,cAAc,QAAQ;EAAE,GAAG,MAAM;EAAO,GAAG;EAAO,GAAG,EAAE,GAAG,MAAM,OAAO;CAC7E,MAAM,iBAAiB,SAAS,SAAS,IAAI,WAAW,MAAM;AAC9D,QAAO;EACL,MAAM,MAAM;EACZ,OAAO;EACP,UAAU;EACV,KAAM,OAAO,OAAkC,MAAM;EACtD;;AAWH,SAAgB,aAAa,UAAwC;CACnE,MAAM,SAAuB,EAAE;AAC/B,SAAQ,UAAU,OAAO;AACzB,QAAO;;AAGT,SAAS,QAAQ,OAAuB,KAAyB;AAC/D,KAAI,SAAS,QAAQ,OAAO,UAAU,UAAW;AACjD,KAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,SAAS,MAClB,SAAQ,OAAO,IAAI;KAGrB,KAAI,KAAK,MAAoB;;;;;AASjC,SAAgB,eAAe,GAAwB;AACrD,QACE,MAAM,QACN,OAAO,MAAM,YACb,UAAW,KACX,WAAY,KACZ,cAAe;;;;;AASnB,SAAgB,aAAa,UAAsB,QAA6B;AAC9E,QAAO,OAAO;EAAE;EAAQ;EAAU,CAAC;;;;;;AAarC,MAAa,UAAmC,EAAE;AAIlD,MAAa,UAAU"}
|
package/lib/jsx-runtime.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-runtime.js","names":[],"sources":["../src/jsx-runtime.ts"],"sourcesContent":["/**\n * Compat JSX runtime for Preact compatibility mode.\n *\n * When `jsxImportSource` is redirected to `@pyreon/preact-compat` (via the vite\n * plugin's `compat: \"preact\"` option), OXC rewrites JSX to import from this file.\n *\n * For component VNodes, we wrap the component function so it returns a reactive\n * accessor — enabling Preact-style re-renders on state change while Pyreon's\n * existing renderer handles all DOM work.\n */\n\nimport type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'\nimport { Fragment, h, onUnmount } from '@pyreon/core'\nimport { signal } from '@pyreon/reactivity'\nimport type { Component } from './index'\n\nexport { Fragment }\n\n// ─── Render context (used by hooks) ──────────────────────────────────────────\n\nexport interface RenderContext {\n hooks: unknown[]\n scheduleRerender: () => void\n /** Effect entries pending execution after render */\n pendingEffects: EffectEntry[]\n /** Layout effect entries pending execution after render */\n pendingLayoutEffects: EffectEntry[]\n /** Set to true when the component is unmounted */\n unmounted: boolean\n}\n\nexport interface EffectEntry {\n fn: () => (() => void) | void\n deps: unknown[] | undefined\n cleanup: (() => void) | undefined\n}\n\nlet _currentCtx: RenderContext | null = null\nlet _hookIndex = 0\n\nexport function getCurrentCtx(): RenderContext | null {\n return _currentCtx\n}\n\nexport function getHookIndex(): number {\n return _hookIndex++\n}\n\nexport function beginRender(ctx: RenderContext): void {\n _currentCtx = ctx\n _hookIndex = 0\n ctx.pendingEffects = []\n ctx.pendingLayoutEffects = []\n}\n\nexport function endRender(): void {\n _currentCtx = null\n _hookIndex = 0\n}\n\n// ─── Effect runners ──────────────────────────────────────────────────────────\n\nfunction runLayoutEffects(entries: EffectEntry[]): void {\n for (const entry of entries) {\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n}\n\nfunction scheduleEffects(ctx: RenderContext, entries: EffectEntry[]): void {\n if (entries.length === 0) return\n queueMicrotask(() => {\n for (const entry of entries) {\n if (ctx.unmounted) return\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n })\n}\n\n// ─── Native component marker ────────────────────────────────────────────────\n\nconst NATIVE_COMPONENT = Symbol.for('pyreon:native-compat')\n\n// ─── Class component detection ──────────────────────────────────────────────\n\nfunction isClassComponent(type: Function): boolean {\n return type.prototype != null && typeof type.prototype.render === 'function'\n}\n\n// ─── Class component wrapping ───────────────────────────────────────────────\n\nfunction wrapClassComponent(ClassComp: Function): ComponentFn {\n const wrapped = ((props: Props) => {\n const instance = new (ClassComp as new (props: Props) => Component)(props)\n const version = signal(0)\n let updateScheduled = false\n\n // Override setState to trigger re-render via version signal\n const origSetState = instance.setState.bind(instance)\n instance.setState = (partial: Partial<Record<string, unknown>>) => {\n origSetState(partial)\n if (!updateScheduled) {\n updateScheduled = true\n queueMicrotask(() => {\n updateScheduled = false\n version.set(version.peek() + 1)\n })\n }\n }\n\n // Override forceUpdate\n instance.forceUpdate = () => {\n version.set(version.peek() + 1)\n }\n\n // Lifecycle: componentWillUnmount\n let didMountFired = false\n onUnmount(() => {\n if (typeof instance.componentWillUnmount === 'function') {\n instance.componentWillUnmount()\n }\n })\n\n // Return reactive accessor for re-renders\n return () => {\n const ver = version() // track for re-renders\n instance.props = props // update props on re-render\n\n // shouldComponentUpdate only applies after mount (ver > 0 means setState/forceUpdate)\n if (didMountFired && ver > 0 && typeof instance.shouldComponentUpdate === 'function') {\n if (!instance.shouldComponentUpdate(props, instance.state)) {\n return instance._lastResult // skip render\n }\n }\n\n const result = instance.render()\n instance._lastResult = result\n\n // componentDidMount fires once after the initial render settles\n if (!didMountFired) {\n didMountFired = true\n if (typeof instance.componentDidMount === 'function') {\n queueMicrotask(() => instance.componentDidMount!())\n }\n } else if (ver > 0) {\n // componentDidUpdate only fires on explicit re-renders (setState/forceUpdate)\n if (typeof instance.componentDidUpdate === 'function') {\n queueMicrotask(() => instance.componentDidUpdate!())\n }\n }\n\n return result\n }\n }) as unknown as ComponentFn\n return wrapped\n}\n\n// ─── Component wrapping ──────────────────────────────────────────────────────\n\nconst _wrapperCache = new WeakMap<Function, ComponentFn>()\n\nfunction wrapCompatComponent(preactComponent: Function): ComponentFn {\n let wrapped = _wrapperCache.get(preactComponent)\n if (wrapped) return wrapped\n\n // Handle class components (those with prototype.render)\n if (isClassComponent(preactComponent)) {\n wrapped = wrapClassComponent(preactComponent)\n _wrapperCache.set(preactComponent, wrapped)\n return wrapped\n }\n\n // The wrapper returns a reactive accessor (() => VNodeChild) which Pyreon's\n // mountChild treats as a reactive expression via mountReactive.\n wrapped = ((props: Props) => {\n const ctx: RenderContext = {\n hooks: [],\n scheduleRerender: () => {\n // Will be replaced below after version signal is created\n },\n pendingEffects: [],\n pendingLayoutEffects: [],\n unmounted: false,\n }\n\n const version = signal(0)\n let updateScheduled = false\n\n ctx.scheduleRerender = () => {\n if (ctx.unmounted || updateScheduled) return\n updateScheduled = true\n queueMicrotask(() => {\n updateScheduled = false\n if (!ctx.unmounted) version.set(version.peek() + 1)\n })\n }\n\n // Register cleanup for all hooks on unmount\n onUnmount(() => {\n ctx.unmounted = true\n for (const hook of ctx.hooks) {\n if (hook && typeof hook === 'object' && 'cleanup' in hook) {\n const entry = hook as EffectEntry\n if (typeof entry.cleanup === 'function') entry.cleanup()\n }\n }\n })\n\n // Return reactive accessor — Pyreon's mountChild calls mountReactive\n return () => {\n version() // tracked read — triggers re-execution when state changes\n beginRender(ctx)\n const result = (preactComponent as ComponentFn)(props)\n const layoutEffects = ctx.pendingLayoutEffects\n const effects = ctx.pendingEffects\n endRender()\n\n runLayoutEffects(layoutEffects)\n scheduleEffects(ctx, effects)\n\n return result\n }\n }) as unknown as ComponentFn\n\n _wrapperCache.set(preactComponent, wrapped)\n return wrapped\n}\n\n// ─── JSX functions ───────────────────────────────────────────────────────────\n\nexport function jsx(\n type: string | ComponentFn | symbol,\n props: Props & { children?: VNodeChild | VNodeChild[] },\n key?: string | number | null,\n): VNode {\n const { children, ...rest } = props\n const propsWithKey = (key != null ? { ...rest, key } : rest) as Props\n\n if (typeof type === 'function') {\n const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey\n // Native Pyreon components (e.g. context Provider) skip compat wrapping\n if ((type as unknown as Record<symbol, boolean>)[NATIVE_COMPONENT]) {\n return h(type as ComponentFn, componentProps)\n }\n // Wrap Preact-style component for re-render support\n const wrapped = wrapCompatComponent(type)\n return h(wrapped, componentProps)\n }\n\n // DOM element or symbol (Fragment): children go in vnode.children\n const childArray = children === undefined ? [] : Array.isArray(children) ? children : [children]\n\n // Map Preact-style attributes to standard HTML attributes\n if (typeof type === 'string') {\n if (propsWithKey.className !== undefined) {\n propsWithKey.class = propsWithKey.className\n delete propsWithKey.className\n }\n if (propsWithKey.htmlFor !== undefined) {\n propsWithKey.for = propsWithKey.htmlFor\n delete propsWithKey.htmlFor\n }\n\n // Preact's onChange fires on every keystroke for form elements (like onInput)\n if (\n (type === 'input' || type === 'textarea' || type === 'select') &&\n propsWithKey.onChange !== undefined\n ) {\n if (propsWithKey.onInput === undefined) {\n propsWithKey.onInput = propsWithKey.onChange\n }\n delete propsWithKey.onChange\n }\n\n // autoFocus → autofocus\n if (propsWithKey.autoFocus !== undefined) {\n propsWithKey.autofocus = propsWithKey.autoFocus\n delete propsWithKey.autoFocus\n }\n\n // defaultValue / defaultChecked → value / checked when no controlled value\n if (type === 'input' || type === 'textarea') {\n if (propsWithKey.defaultValue !== undefined && propsWithKey.value === undefined) {\n propsWithKey.value = propsWithKey.defaultValue\n delete propsWithKey.defaultValue\n }\n if (propsWithKey.defaultChecked !== undefined && propsWithKey.checked === undefined) {\n propsWithKey.checked = propsWithKey.defaultChecked\n delete propsWithKey.defaultChecked\n }\n }\n\n // Strip Preact-only props that have no DOM equivalent\n delete propsWithKey.suppressHydrationWarning\n }\n\n return h(type, propsWithKey, ...(childArray as VNodeChild[]))\n}\n\nexport const jsxs = jsx\nexport const jsxDEV = jsx\n"],"mappings":"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"}
|
package/lib/signals.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signals.js","names":["pyreonSignal","pyreonComputed","pyreonRunUntracked","pyreonEffect"],"sources":["../src/signals.ts"],"sourcesContent":["/**\n * @pyreon/preact-compat/signals\n *\n * Preact Signals compatibility layer (`@preact/signals` style).\n * Wraps Pyreon's signal/computed in `{ value }` accessor objects.\n */\n\nimport type { Effect } from '@pyreon/reactivity'\nimport {\n batch as pyreonBatch,\n computed as pyreonComputed,\n effect as pyreonEffect,\n runUntracked as pyreonRunUntracked,\n signal as pyreonSignal,\n} from '@pyreon/reactivity'\n\n// ─── Signal ──────────────────────────────────────────────────────────────────\n\nexport interface ReadonlySignal<T> {\n readonly value: T\n peek(): T\n}\n\nexport interface WritableSignal<T> extends ReadonlySignal<T> {\n value: T\n}\n\n/**\n * Create a Preact-style signal with `.value` accessor.\n *\n * @example\n * const count = signal(0)\n * count.value++ // write\n * console.log(count.value) // read (tracked)\n */\nexport function signal<T>(initial: T): WritableSignal<T> {\n const s = pyreonSignal<T>(initial)\n return {\n get value(): T {\n return s()\n },\n set value(v: T) {\n s.set(v)\n },\n peek(): T {\n return s.peek()\n },\n }\n}\n\n// ─── Computed ────────────────────────────────────────────────────────────────\n\n/**\n * Create a Preact-style computed with `.value` accessor.\n *\n * @example\n * const doubled = computed(() => count.value * 2)\n * console.log(doubled.value)\n */\nexport function computed<T>(fn: () => T): ReadonlySignal<T> {\n const c = pyreonComputed(fn)\n return {\n get value(): T {\n return c()\n },\n peek(): T {\n return pyreonRunUntracked(() => c())\n },\n }\n}\n\n// ─── Effect ──────────────────────────────────────────────────────────────────\n\n/**\n * Run a side-effect that auto-tracks signal reads.\n * Returns a dispose function.\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n // Pyreon's effect() natively supports cleanup return values\n const e: Effect = pyreonEffect(fn)\n return () => {\n e.dispose()\n }\n}\n\n// ─── Batch ───────────────────────────────────────────────────────────────────\n\n/**\n * Batch multiple signal writes into a single update.\n */\nexport { pyreonBatch as batch }\n"],"mappings":";;;;;;;;;;;AAmCA,SAAgB,OAAU,SAA+B;CACvD,MAAM,IAAIA,SAAgB,QAAQ;AAClC,QAAO;EACL,IAAI,QAAW;AACb,UAAO,GAAG;;EAEZ,IAAI,MAAM,GAAM;AACd,KAAE,IAAI,EAAE;;EAEV,OAAU;AACR,UAAO,EAAE,MAAM;;EAElB;;;;;;;;;AAYH,SAAgB,SAAY,IAAgC;CAC1D,MAAM,IAAIC,WAAe,GAAG;AAC5B,QAAO;EACL,IAAI,QAAW;AACb,UAAO,GAAG;;EAEZ,OAAU;AACR,UAAOC,mBAAyB,GAAG,CAAC;;EAEvC;;;;;;AASH,SAAgB,OAAO,IAA2C;CAEhE,MAAM,IAAYC,SAAa,GAAG;AAClC,cAAa;AACX,IAAE,SAAS"}
|
package/lib/types/hooks.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hooks2.d.ts","names":[],"sources":["../../../src/hooks.ts"],"mappings":";;;;;;;;;iBAoDgB,QAAA,GAAA,CAAY,OAAA,EAAS,CAAA,UAAW,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAA,KAAM,IAAA,EAAM,CAAA,KAAM,CAAA;;;;;iBA6B/D,SAAA,CAAU,EAAA,6BAA+B,IAAA;;;AAAzD;iBAwBgB,eAAA,CAAgB,EAAA,6BAA+B,IAAA;;;;iBAuB/C,OAAA,GAAA,CAAW,EAAA,QAAU,CAAA,EAAG,IAAA,cAAkB,CAAA;;;;iBAuB1C,WAAA,eAA0B,IAAA,sBAAA,CAA2B,EAAA,EAAI,CAAA,EAAG,IAAA,cAAkB,CAAA;AAvB9F;;;AAAA,iBAgCgB,MAAA,GAAA,CAAU,OAAA,GAAU,CAAA;EAAM,OAAA,EAAS,CAAA;AAAA;;;;;;AATnD;iBA6BgB,UAAA,MAAA,CACd,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,UAAA,EAAY,CAAA,UAAW,CAAA,GACvB,IAAA,IAAQ,GAAA,EAAK,CAAA,KAAM,CAAA,IACjB,CAAA,GAAI,MAAA,EAAQ,CAAA;;;;iBAqCA,KAAA,CAAA;;;;;;;AA7DhB;iBAiFgB,IAAA,WAAe,MAAA,kBAAA,CAC7B,SAAA,GAAY,KAAA,EAAO,CAAA,KAAM,UAAA,EACzB,QAAA,IAAY,SAAA,EAAW,CAAA,EAAG,SAAA,EAAW,CAAA,gBACnC,KAAA,EAAO,CAAA,KAAM,UAAA;;;;;;iBA6CD,UAAA,WAAqB,MAAA,kBAAA,CACnC,MAAA,GAAS,KAAA,EAAO,CAAA,EAAG,GAAA;EAAO,OAAA;AAAA,aAA8B,UAAA,IACtD,KAAA,EAAO,CAAA;EAAM,GAAA;IAAQ,OAAA;EAAA;AAAA,MAAgC,UAAA;;;;iBAezC,mBAAA,GAAA,CACd,GAAA;EAAO,OAAA,EAAS,CAAA;AAAA,sBAChB,IAAA,QAAY,CAAA,EACZ,IAAA;;;;iBAec,aAAA,GAAA,CAAiB,MAAA,EAAQ,CAAA,EAAG,OAAA,IAAW,CAAA,EAAG,CAAA;;;;;;;;;iBAY1C,aAAA,CAAA,cAA4B,EAAA;;;;;;;;iBAa5B,gBAAA,GAAA,CAAoB,KAAA,EAAO,CAAA,GAAI,CAAA"}
|
package/lib/types/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/index.ts"],"mappings":";;;;;cAoCa,aAAA,SAAa,OAAA;;;;;iBAUV,MAAA,CAAO,KAAA,EAAO,UAAA,EAAY,SAAA,EAAW,OAAA;;;;AAcrD;iBANgB,OAAA,CAAQ,KAAA,EAAO,UAAA,EAAY,SAAA,EAAW,OAAA;AAAA,UAMrC,aAAA;EAAA,SACN,EAAA;EAAA,SACA,YAAA,EAAc,CAAA;EACvB,QAAA,EAAU,WAAA;IAAc,KAAA,EAAO,CAAA;IAAG,QAAA,GAAW,UAAA;EAAA;AAAA;;;;iBAS/B,aAAA,GAAA,CAAiB,YAAA,EAAc,CAAA,GAAI,aAAA,CAAc,CAAA;;;;;;AAAjE;cAyBa,SAAA,WACD,KAAA,GAAQ,KAAA,YACR,MAAA,oBAA0B,MAAA;EAEpC,KAAA,EAAO,CAAA;EACP,KAAA,EAAO,CAAA;EACP,YAAA,EAAc,UAAA,QAAkB,MAAA,CAAO,CAAA;EACvC,WAAA,GAAc,UAAA;EAGd,iBAAA,CAAA,CAAA;EACA,kBAAA,CAAA,CAAA;EACA,oBAAA,CAAA,CAAA;EACA,qBAAA,CAAA,CAAuB,SAAA,EAAW,CAAA,EAAG,SAAA,EAAW,CAAA;cAEpC,KAAA,EAAO,CAAA;EAxC8B;;;;EAkDjD,QAAA,CAAS,OAAA,EAAS,OAAA,CAAQ,CAAA,MAAO,IAAA,EAAM,CAAA,KAAM,OAAA,CAAQ,CAAA;EAzBjC;;;EAuCpB,WAAA,CAAA;EArCU;;;EA4CV,MAAA,CAAA,GAAU,UAAA;AAAA;;;;;;cAYC,aAAA,WACD,KAAA,GAAQ,KAAA,YACR,MAAA,oBAA0B,MAAA,2BAC5B,SAAA,CAAU,CAAA,EAAG,CAAA;;;;iBAOP,YAAA,CAAa,KAAA,EAAO,KAAA,EAAO,KAAA,GAAQ,KAAA,KAAU,QAAA,EAAU,UAAA,KAAe,KAAA;;;;;KAiBjF,cAAA,GAAiB,UAAA,GAAa,cAAA;AAAA,iBAEnB,YAAA,CAAa,QAAA,EAAU,cAAA,GAAiB,UAAA;;;;iBAsBxC,cAAA,CAAe,CAAA,YAAa,CAAA,IAAK,KAAA;;;;iBAejC,YAAA,CAAa,QAAA,EAAU,UAAA,EAAY,MAAA,EAAQ,OAAA,GAAU,UAAA;;;;;cAcxD,OAAA,EAAS,MAAA;AAAA,cAIT,OAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-runtime2.d.ts","names":[],"sources":["../../../src/jsx-runtime.ts"],"mappings":";;;iBAyOgB,GAAA,CACd,IAAA,WAAe,WAAA,WACf,KAAA,EAAO,KAAA;EAAU,QAAA,GAAW,UAAA,GAAa,UAAA;AAAA,GACzC,GAAA,4BACC,KAAA;AAAA,cAiEU,IAAA,SAAI,GAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signals2.d.ts","names":[],"sources":["../../../src/signals.ts"],"mappings":";;;UAkBiB,cAAA;EAAA,SACN,KAAA,EAAO,CAAA;EAChB,IAAA,IAAQ,CAAA;AAAA;AAAA,UAGO,cAAA,YAA0B,cAAA,CAAe,CAAA;EACxD,KAAA,EAAO,CAAA;AAAA;AADT;;;;;;;;AAAA,iBAYgB,MAAA,GAAA,CAAU,OAAA,EAAS,CAAA,GAAI,cAAA,CAAe,CAAA;;;;;;;AAAtD;iBAwBgB,QAAA,GAAA,CAAY,EAAA,QAAU,CAAA,GAAI,cAAA,CAAe,CAAA;;;;;iBAkBzC,MAAA,CAAO,EAAA"}
|