@pyreon/core 0.13.1 → 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 +10 -1
- package/lib/analysis/index.js.html +1 -1
- package/lib/analysis/jsx-dev-runtime.js.html +1 -1
- package/lib/analysis/jsx-runtime.js.html +1 -1
- package/lib/index.js +168 -34
- package/lib/jsx-dev-runtime.js +7 -0
- package/lib/jsx-runtime.js +7 -0
- package/lib/types/index.d.ts +112 -15
- package/lib/types/jsx-dev-runtime.d.ts +6 -3
- package/lib/types/jsx-runtime.d.ts +6 -3
- package/package.json +3 -2
- package/src/compat-marker.ts +79 -0
- package/src/component.ts +2 -1
- package/src/context.ts +38 -7
- package/src/dynamic.ts +16 -5
- package/src/error-boundary.ts +15 -2
- package/src/index.ts +2 -0
- package/src/jsx-runtime.ts +20 -2
- package/src/lifecycle.ts +17 -6
- package/src/manifest.ts +43 -3
- package/src/props.ts +19 -6
- package/src/show.ts +19 -6
- package/src/suspense.ts +1 -2
- package/src/telemetry.ts +30 -2
- package/src/tests/compat-marker.test.ts +96 -0
- package/src/tests/component.test.ts +5 -5
- package/src/tests/context.test.ts +3 -3
- package/src/tests/core.test.ts +11 -11
- package/src/tests/dynamic.test.ts +33 -1
- package/src/tests/error-boundary.test.ts +1 -1
- package/src/tests/lifecycle.test.ts +18 -18
- package/src/tests/manifest-snapshot.test.ts +6 -1
- package/src/tests/native-marker-error-boundary.test.ts +12 -0
- package/src/tests/reactive-context.test.ts +3 -3
- package/src/tests/reactive-props.test.ts +87 -0
- package/src/tests/show.test.ts +76 -0
- package/src/tests/telemetry.test.ts +61 -0
- package/src/types.ts +9 -5
- package/lib/index.js.map +0 -1
- package/lib/jsx-dev-runtime.js.map +0 -1
- package/lib/jsx-runtime.js.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/jsx-dev-runtime.d.ts.map +0 -1
- package/lib/types/jsx-runtime.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -44,6 +44,13 @@ function Counter() {
|
|
|
44
44
|
- **`onUpdate(fn)`** -- Runs after each reactive update.
|
|
45
45
|
- **`onErrorCaptured(fn)`** -- Captures errors thrown by descendant components.
|
|
46
46
|
|
|
47
|
+
Lifecycle hook arrays are lazy-allocated -- `LifecycleHooks.mount`/`.unmount`/`.update`/`.error` start as `null` and are only allocated on first hook registration. Components with no hooks (the majority) pay zero allocation cost.
|
|
48
|
+
|
|
49
|
+
### Props Reactivity
|
|
50
|
+
|
|
51
|
+
- **`makeReactiveProps(raw)`** -- Converts compiler-emitted `_rp()` wrappers into getter properties. Uses a scan-first strategy: checks for any branded reactive prop before allocating the result object. Static-only components return `raw` immediately with no allocation.
|
|
52
|
+
- **`_rp(fn)`** -- Brands a function as a reactive prop wrapper (compiler-emitted, not user-facing).
|
|
53
|
+
|
|
47
54
|
### Context
|
|
48
55
|
|
|
49
56
|
- **`createContext<T>(defaultValue?): Context<T>`** -- Creates a context with an optional default.
|
|
@@ -82,7 +89,9 @@ function Counter() {
|
|
|
82
89
|
|
|
83
90
|
### Types
|
|
84
91
|
|
|
85
|
-
`VNode`, `VNodeChild`, `VNodeChildAtom`, `Props`, `ComponentFn`, `ExtractProps`, `HigherOrderComponent`, `ComponentInstance`, `LifecycleHooks`, `CleanupFn`, `NativeItem`, `Ref`, `Context`, `LazyComponent`, `ShowProps`, `SwitchProps`, `MatchProps`, `ForProps`, `PortalProps`, `ErrorContext`, `ErrorHandler`, `ClassValue`, `TargetedEvent`, `PyreonHTMLAttributes`, `CSSProperties`, `StyleValue`, `CanvasAttributes`
|
|
92
|
+
`VNode`, `VNodeChild`, `VNodeChildAtom`, `VNodeChildAccessor`, `Props`, `ComponentFn`, `ExtractProps`, `HigherOrderComponent`, `ComponentInstance`, `LifecycleHooks`, `CleanupFn`, `NativeItem`, `Ref`, `Context`, `LazyComponent`, `ShowProps`, `SwitchProps`, `MatchProps`, `ForProps`, `PortalProps`, `ErrorContext`, `ErrorHandler`, `ClassValue`, `TargetedEvent`, `PyreonHTMLAttributes`, `CSSProperties`, `StyleValue`, `CanvasAttributes`
|
|
93
|
+
|
|
94
|
+
**VNodeChild union ordering**: `VNodeChild = VNodeChildAccessor | VNodeChildAtom | VNodeChildAtom[]` — the accessor type is FIRST so TypeScript matches `{() => cond && <X />}` against the function arm without falling through to `VNodeChildAtom` and erroring on `false | VNode`.
|
|
86
95
|
|
|
87
96
|
## License
|
|
88
97
|
|
|
@@ -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","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"824f9243-1","name":"lifecycle.ts"},{"uid":"824f9243-3","name":"component.ts"},{"uid":"824f9243-5","name":"compat-marker.ts"},{"uid":"824f9243-7","name":"context.ts"},{"uid":"824f9243-9","name":"h.ts"},{"uid":"824f9243-11","name":"dynamic.ts"},{"uid":"824f9243-13","name":"telemetry.ts"},{"uid":"824f9243-15","name":"error-boundary.ts"},{"uid":"824f9243-17","name":"for.ts"},{"uid":"824f9243-19","name":"lazy.ts"},{"uid":"824f9243-21","name":"map-array.ts"},{"uid":"824f9243-23","name":"portal.ts"},{"uid":"824f9243-25","name":"props.ts"},{"uid":"824f9243-27","name":"ref.ts"},{"uid":"824f9243-29","name":"show.ts"},{"uid":"824f9243-31","name":"style.ts"},{"uid":"824f9243-33","name":"suspense.ts"},{"uid":"824f9243-35","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"824f9243-1":{"renderedLength":3078,"gzipLength":1313,"brotliLength":0,"metaUid":"824f9243-0"},"824f9243-3":{"renderedLength":1471,"gzipLength":693,"brotliLength":0,"metaUid":"824f9243-2"},"824f9243-5":{"renderedLength":3173,"gzipLength":1409,"brotliLength":0,"metaUid":"824f9243-4"},"824f9243-7":{"renderedLength":3600,"gzipLength":1542,"brotliLength":0,"metaUid":"824f9243-6"},"824f9243-9":{"renderedLength":1082,"gzipLength":597,"brotliLength":0,"metaUid":"824f9243-8"},"824f9243-11":{"renderedLength":490,"gzipLength":291,"brotliLength":0,"metaUid":"824f9243-10"},"824f9243-13":{"renderedLength":1208,"gzipLength":633,"brotliLength":0,"metaUid":"824f9243-12"},"824f9243-15":{"renderedLength":1659,"gzipLength":842,"brotliLength":0,"metaUid":"824f9243-14"},"824f9243-17":{"renderedLength":700,"gzipLength":478,"brotliLength":0,"metaUid":"824f9243-16"},"824f9243-19":{"renderedLength":461,"gzipLength":273,"brotliLength":0,"metaUid":"824f9243-18"},"824f9243-21":{"renderedLength":1018,"gzipLength":571,"brotliLength":0,"metaUid":"824f9243-20"},"824f9243-23":{"renderedLength":818,"gzipLength":491,"brotliLength":0,"metaUid":"824f9243-22"},"824f9243-25":{"renderedLength":4339,"gzipLength":1641,"brotliLength":0,"metaUid":"824f9243-24"},"824f9243-27":{"renderedLength":86,"gzipLength":98,"brotliLength":0,"metaUid":"824f9243-26"},"824f9243-29":{"renderedLength":2022,"gzipLength":854,"brotliLength":0,"metaUid":"824f9243-28"},"824f9243-31":{"renderedLength":1858,"gzipLength":825,"brotliLength":0,"metaUid":"824f9243-30"},"824f9243-33":{"renderedLength":1104,"gzipLength":614,"brotliLength":0,"metaUid":"824f9243-32"},"824f9243-35":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"824f9243-34"}},"nodeMetas":{"824f9243-0":{"id":"/src/lifecycle.ts","moduleParts":{"index.js":"824f9243-1"},"imported":[],"importedBy":[{"uid":"824f9243-34"},{"uid":"824f9243-2"},{"uid":"824f9243-6"},{"uid":"824f9243-14"}]},"824f9243-2":{"id":"/src/component.ts","moduleParts":{"index.js":"824f9243-3"},"imported":[{"uid":"824f9243-0"}],"importedBy":[{"uid":"824f9243-34"},{"uid":"824f9243-14"}]},"824f9243-4":{"id":"/src/compat-marker.ts","moduleParts":{"index.js":"824f9243-5"},"imported":[],"importedBy":[{"uid":"824f9243-34"},{"uid":"824f9243-14"}]},"824f9243-6":{"id":"/src/context.ts","moduleParts":{"index.js":"824f9243-7"},"imported":[{"uid":"824f9243-36"},{"uid":"824f9243-0"}],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-8":{"id":"/src/h.ts","moduleParts":{"index.js":"824f9243-9"},"imported":[],"importedBy":[{"uid":"824f9243-34"},{"uid":"824f9243-10"},{"uid":"824f9243-18"},{"uid":"824f9243-32"}]},"824f9243-10":{"id":"/src/dynamic.ts","moduleParts":{"index.js":"824f9243-11"},"imported":[{"uid":"824f9243-8"}],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-12":{"id":"/src/telemetry.ts","moduleParts":{"index.js":"824f9243-13"},"imported":[],"importedBy":[{"uid":"824f9243-34"},{"uid":"824f9243-14"}]},"824f9243-14":{"id":"/src/error-boundary.ts","moduleParts":{"index.js":"824f9243-15"},"imported":[{"uid":"824f9243-36"},{"uid":"824f9243-4"},{"uid":"824f9243-2"},{"uid":"824f9243-0"},{"uid":"824f9243-12"}],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-16":{"id":"/src/for.ts","moduleParts":{"index.js":"824f9243-17"},"imported":[],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-18":{"id":"/src/lazy.ts","moduleParts":{"index.js":"824f9243-19"},"imported":[{"uid":"824f9243-36"},{"uid":"824f9243-8"}],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-20":{"id":"/src/map-array.ts","moduleParts":{"index.js":"824f9243-21"},"imported":[],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-22":{"id":"/src/portal.ts","moduleParts":{"index.js":"824f9243-23"},"imported":[],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-24":{"id":"/src/props.ts","moduleParts":{"index.js":"824f9243-25"},"imported":[],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-26":{"id":"/src/ref.ts","moduleParts":{"index.js":"824f9243-27"},"imported":[],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-28":{"id":"/src/show.ts","moduleParts":{"index.js":"824f9243-29"},"imported":[],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-30":{"id":"/src/style.ts","moduleParts":{"index.js":"824f9243-31"},"imported":[],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-32":{"id":"/src/suspense.ts","moduleParts":{"index.js":"824f9243-33"},"imported":[{"uid":"824f9243-8"}],"importedBy":[{"uid":"824f9243-34"}]},"824f9243-34":{"id":"/src/index.ts","moduleParts":{"index.js":"824f9243-35"},"imported":[{"uid":"824f9243-2"},{"uid":"824f9243-4"},{"uid":"824f9243-6"},{"uid":"824f9243-10"},{"uid":"824f9243-14"},{"uid":"824f9243-16"},{"uid":"824f9243-8"},{"uid":"824f9243-18"},{"uid":"824f9243-0"},{"uid":"824f9243-20"},{"uid":"824f9243-22"},{"uid":"824f9243-24"},{"uid":"824f9243-26"},{"uid":"824f9243-28"},{"uid":"824f9243-30"},{"uid":"824f9243-32"},{"uid":"824f9243-12"}],"importedBy":[],"isEntry":true},"824f9243-36":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"824f9243-6"},{"uid":"824f9243-14"},{"uid":"824f9243-18"}]}},"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-dev-runtime.js","children":[{"name":"src","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"jsx-dev-runtime.js","children":[{"name":"src","children":[{"uid":"3319ebff-1","name":"h.ts"},{"uid":"3319ebff-3","name":"jsx-runtime.ts"},{"uid":"3319ebff-5","name":"jsx-dev-runtime.ts"}]}]}],"isRoot":true},"nodeParts":{"3319ebff-1":{"renderedLength":1082,"gzipLength":597,"brotliLength":0,"metaUid":"3319ebff-0"},"3319ebff-3":{"renderedLength":1103,"gzipLength":640,"brotliLength":0,"metaUid":"3319ebff-2"},"3319ebff-5":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"3319ebff-4"}},"nodeMetas":{"3319ebff-0":{"id":"/src/h.ts","moduleParts":{"jsx-dev-runtime.js":"3319ebff-1"},"imported":[],"importedBy":[{"uid":"3319ebff-2"}]},"3319ebff-2":{"id":"/src/jsx-runtime.ts","moduleParts":{"jsx-dev-runtime.js":"3319ebff-3"},"imported":[{"uid":"3319ebff-0"}],"importedBy":[{"uid":"3319ebff-4"}]},"3319ebff-4":{"id":"/src/jsx-dev-runtime.ts","moduleParts":{"jsx-dev-runtime.js":"3319ebff-5"},"imported":[{"uid":"3319ebff-2"}],"importedBy":[],"isEntry":true}},"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":"843e1a91-1","name":"h.ts"},{"uid":"843e1a91-3","name":"jsx-runtime.ts"}]}]}],"isRoot":true},"nodeParts":{"843e1a91-1":{"renderedLength":1082,"gzipLength":597,"brotliLength":0,"metaUid":"843e1a91-0"},"843e1a91-3":{"renderedLength":1103,"gzipLength":640,"brotliLength":0,"metaUid":"843e1a91-2"}},"nodeMetas":{"843e1a91-0":{"id":"/src/h.ts","moduleParts":{"jsx-runtime.js":"843e1a91-1"},"imported":[],"importedBy":[{"uid":"843e1a91-2"}]},"843e1a91-2":{"id":"/src/jsx-runtime.ts","moduleParts":{"jsx-runtime.js":"843e1a91-3"},"imported":[{"uid":"843e1a91-0"}],"importedBy":[],"isEntry":true}},"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,7 +1,7 @@
|
|
|
1
|
-
import { signal } from "@pyreon/reactivity";
|
|
1
|
+
import { setSnapshotCapture, signal } from "@pyreon/reactivity";
|
|
2
2
|
|
|
3
3
|
//#region src/lifecycle.ts
|
|
4
|
-
const __DEV__$3 =
|
|
4
|
+
const __DEV__$3 = process.env.NODE_ENV !== "production";
|
|
5
5
|
let _current = null;
|
|
6
6
|
function setCurrentHooks(hooks) {
|
|
7
7
|
_current = hooks;
|
|
@@ -52,21 +52,30 @@ function warnOutsideSetup(hookName) {
|
|
|
52
52
|
*/
|
|
53
53
|
function onMount(fn) {
|
|
54
54
|
warnOutsideSetup("onMount");
|
|
55
|
-
_current
|
|
55
|
+
if (_current) {
|
|
56
|
+
if (_current.mount === null) _current.mount = [];
|
|
57
|
+
_current.mount.push(fn);
|
|
58
|
+
}
|
|
56
59
|
}
|
|
57
60
|
/**
|
|
58
61
|
* Register a callback to run when the component is removed from the DOM.
|
|
59
62
|
*/
|
|
60
63
|
function onUnmount(fn) {
|
|
61
64
|
warnOutsideSetup("onUnmount");
|
|
62
|
-
_current
|
|
65
|
+
if (_current) {
|
|
66
|
+
if (_current.unmount === null) _current.unmount = [];
|
|
67
|
+
_current.unmount.push(fn);
|
|
68
|
+
}
|
|
63
69
|
}
|
|
64
70
|
/**
|
|
65
71
|
* Register a callback to run after each reactive update.
|
|
66
72
|
*/
|
|
67
73
|
function onUpdate(fn) {
|
|
68
74
|
warnOutsideSetup("onUpdate");
|
|
69
|
-
_current
|
|
75
|
+
if (_current) {
|
|
76
|
+
if (_current.update === null) _current.update = [];
|
|
77
|
+
_current.update.push(fn);
|
|
78
|
+
}
|
|
70
79
|
}
|
|
71
80
|
/**
|
|
72
81
|
* Register an error handler for this component subtree.
|
|
@@ -83,7 +92,10 @@ function onUpdate(fn) {
|
|
|
83
92
|
*/
|
|
84
93
|
function onErrorCaptured(fn) {
|
|
85
94
|
warnOutsideSetup("onErrorCaptured");
|
|
86
|
-
_current
|
|
95
|
+
if (_current) {
|
|
96
|
+
if (_current.error === null) _current.error = [];
|
|
97
|
+
_current.error.push(fn);
|
|
98
|
+
}
|
|
87
99
|
}
|
|
88
100
|
|
|
89
101
|
//#endregion
|
|
@@ -103,10 +115,10 @@ function defineComponent(fn) {
|
|
|
103
115
|
*/
|
|
104
116
|
function runWithHooks(fn, props) {
|
|
105
117
|
const hooks = {
|
|
106
|
-
mount:
|
|
107
|
-
unmount:
|
|
108
|
-
update:
|
|
109
|
-
error:
|
|
118
|
+
mount: null,
|
|
119
|
+
unmount: null,
|
|
120
|
+
update: null,
|
|
121
|
+
error: null
|
|
110
122
|
};
|
|
111
123
|
setCurrentHooks(hooks);
|
|
112
124
|
let vnode = null;
|
|
@@ -125,6 +137,7 @@ function runWithHooks(fn, props) {
|
|
|
125
137
|
* Returns true if any handler marked the error as handled.
|
|
126
138
|
*/
|
|
127
139
|
function propagateError(err, hooks) {
|
|
140
|
+
if (!hooks.error) return false;
|
|
128
141
|
for (const handler of hooks.error) if (handler(err) === true) return true;
|
|
129
142
|
return false;
|
|
130
143
|
}
|
|
@@ -144,6 +157,80 @@ function dispatchToErrorBoundary(err) {
|
|
|
144
157
|
return handler ? handler(err) : false;
|
|
145
158
|
}
|
|
146
159
|
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/compat-marker.ts
|
|
162
|
+
/**
|
|
163
|
+
* Compat-mode native-component marker.
|
|
164
|
+
*
|
|
165
|
+
* Pyreon ships compat layers (`@pyreon/{react,preact,vue,solid}-compat`) that
|
|
166
|
+
* wrap every JSX-called component function to emulate that source framework's
|
|
167
|
+
* render-on-state-change semantics. That wrapping is correct for user code
|
|
168
|
+
* (the whole point of compat mode) but corrupts Pyreon framework components
|
|
169
|
+
* — those manage their own reactivity via `provide()` / signals / lifecycle
|
|
170
|
+
* hooks, and wrapping them runs their setup body inside the compat layer's
|
|
171
|
+
* render context instead of Pyreon's, breaking `provide()` and
|
|
172
|
+
* `onMount()` / `onUnmount()` calls.
|
|
173
|
+
*
|
|
174
|
+
* Framework components opt out of compat wrapping by setting a well-known
|
|
175
|
+
* registry symbol (`Symbol.for('pyreon:native-compat')`) on the function.
|
|
176
|
+
* The compat layer reads that symbol and routes marked components straight
|
|
177
|
+
* through Pyreon's `h()` mount path. The symbol is registry-shared, so no
|
|
178
|
+
* import direction between framework and compat is implied — both sides
|
|
179
|
+
* reference the same global symbol via the helpers exported here.
|
|
180
|
+
*
|
|
181
|
+
* Audience: framework-package authors writing JSX components in `@pyreon/*`
|
|
182
|
+
* packages whose setup body uses `provide()` / lifecycle hooks / signal
|
|
183
|
+
* subscriptions. Wrap exported components with `nativeCompat()`. One line
|
|
184
|
+
* per export site; zero runtime cost beyond a single property write at
|
|
185
|
+
* module load.
|
|
186
|
+
*/
|
|
187
|
+
/**
|
|
188
|
+
* The well-known registry symbol that marks a component as a Pyreon native
|
|
189
|
+
* framework component. Compat layers check this symbol to decide whether to
|
|
190
|
+
* skip their `wrapCompatComponent` call.
|
|
191
|
+
*
|
|
192
|
+
* Exported for advanced cases where a caller needs to test the marker
|
|
193
|
+
* directly (most callers should use `isNativeCompat()`).
|
|
194
|
+
*/
|
|
195
|
+
const NATIVE_COMPAT_MARKER = Symbol.for("pyreon:native-compat");
|
|
196
|
+
/**
|
|
197
|
+
* Mark a Pyreon framework component as "self-managing" — compat layers will
|
|
198
|
+
* skip their React/Vue/Solid/Preact-style wrapping and route the component
|
|
199
|
+
* directly through Pyreon's mount path. Use on every `@pyreon/*` JSX
|
|
200
|
+
* component whose setup body uses `provide()`, lifecycle hooks
|
|
201
|
+
* (`onMount` / `onUnmount`), signal-driven reactivity, or any other Pyreon
|
|
202
|
+
* native pattern that depends on the active component-setup frame.
|
|
203
|
+
*
|
|
204
|
+
* Idempotent: re-applying the marker is a no-op. Non-function inputs pass
|
|
205
|
+
* through unchanged so callers don't have to typecheck before wrapping.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* import { nativeCompat, provide } from '@pyreon/core'
|
|
209
|
+
*
|
|
210
|
+
* export const RouterView = nativeCompat(function RouterView(props) {
|
|
211
|
+
* provide(RouterContext, ...)
|
|
212
|
+
* return <div data-pyreon-router-view>{children}</div>
|
|
213
|
+
* })
|
|
214
|
+
*/
|
|
215
|
+
function nativeCompat(fn) {
|
|
216
|
+
if (typeof fn === "function") fn[NATIVE_COMPAT_MARKER] = true;
|
|
217
|
+
return fn;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Read whether a component has been marked as a Pyreon native framework
|
|
221
|
+
* component. Compat-layer code calls this from its `jsx()` to decide whether
|
|
222
|
+
* to wrap or pass through.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* import { isNativeCompat } from '@pyreon/core'
|
|
226
|
+
*
|
|
227
|
+
* if (isNativeCompat(type)) return h(type, props)
|
|
228
|
+
* return wrapCompatComponent(type)(props)
|
|
229
|
+
*/
|
|
230
|
+
function isNativeCompat(fn) {
|
|
231
|
+
return typeof fn === "function" && fn[NATIVE_COMPAT_MARKER] === true;
|
|
232
|
+
}
|
|
233
|
+
|
|
147
234
|
//#endregion
|
|
148
235
|
//#region src/context.ts
|
|
149
236
|
/**
|
|
@@ -178,7 +265,7 @@ function setContextStackProvider(fn) {
|
|
|
178
265
|
function getStack() {
|
|
179
266
|
return _stackProvider();
|
|
180
267
|
}
|
|
181
|
-
|
|
268
|
+
process.env.NODE_ENV;
|
|
182
269
|
function pushContext(values) {
|
|
183
270
|
getStack().push(values);
|
|
184
271
|
}
|
|
@@ -235,18 +322,31 @@ function captureContextStack() {
|
|
|
235
322
|
}
|
|
236
323
|
/**
|
|
237
324
|
* Execute `fn()` with a previously captured context stack active.
|
|
238
|
-
*
|
|
325
|
+
*
|
|
326
|
+
* After `fn()` returns, removes ONLY the snapshot frames this call pushed
|
|
327
|
+
* — anything `fn()` itself pushed (typically provider frames from
|
|
328
|
+
* `provide()` calls during component mount) stays on the stack so
|
|
329
|
+
* subsequent reactive re-runs (e.g. `_bind` text bindings,
|
|
330
|
+
* `renderEffect` callbacks) can still find ancestor providers via
|
|
331
|
+
* `useContext`. Pre-fix this method was `stack.length = savedLength`,
|
|
332
|
+
* which destructively truncated provider frames pushed during mount —
|
|
333
|
+
* silently breaking `useMode()` / `useTheme()` / `useRouter()` etc. on
|
|
334
|
+
* every signal-driven update under a `mountReactive` boundary.
|
|
239
335
|
*/
|
|
240
336
|
function restoreContextStack(snapshot, fn) {
|
|
241
337
|
const stack = getStack();
|
|
242
|
-
const
|
|
338
|
+
const insertIndex = stack.length;
|
|
243
339
|
for (const frame of snapshot) stack.push(frame);
|
|
244
340
|
try {
|
|
245
341
|
return fn();
|
|
246
342
|
} finally {
|
|
247
|
-
stack.length
|
|
343
|
+
stack.splice(insertIndex, snapshot.length);
|
|
248
344
|
}
|
|
249
345
|
}
|
|
346
|
+
setSnapshotCapture({
|
|
347
|
+
capture: () => captureContextStack(),
|
|
348
|
+
restore: (snap, fn) => restoreContextStack(snap, fn)
|
|
349
|
+
});
|
|
250
350
|
|
|
251
351
|
//#endregion
|
|
252
352
|
//#region src/h.ts
|
|
@@ -282,12 +382,14 @@ function flattenChildren(children) {
|
|
|
282
382
|
|
|
283
383
|
//#endregion
|
|
284
384
|
//#region src/dynamic.ts
|
|
285
|
-
const __DEV__$2 =
|
|
385
|
+
const __DEV__$2 = process.env.NODE_ENV !== "production";
|
|
286
386
|
function Dynamic(props) {
|
|
287
|
-
const { component, ...rest } = props;
|
|
387
|
+
const { component, children, ...rest } = props;
|
|
288
388
|
if (__DEV__$2 && !component) console.warn("[Pyreon] <Dynamic> received a falsy `component` prop. Nothing will be rendered.");
|
|
289
389
|
if (!component) return null;
|
|
290
|
-
return h(component, rest);
|
|
390
|
+
if (children === void 0) return h(component, rest);
|
|
391
|
+
if (Array.isArray(children)) return h(component, rest, ...children);
|
|
392
|
+
return h(component, rest, children);
|
|
291
393
|
}
|
|
292
394
|
|
|
293
395
|
//#endregion
|
|
@@ -295,10 +397,17 @@ function Dynamic(props) {
|
|
|
295
397
|
let _handlers = [];
|
|
296
398
|
/**
|
|
297
399
|
* Register a global error handler. Called whenever a component throws in any
|
|
298
|
-
* lifecycle phase
|
|
400
|
+
* lifecycle phase, OR an effect throws in `@pyreon/reactivity`. Returns an
|
|
401
|
+
* unregister function.
|
|
402
|
+
*
|
|
403
|
+
* Also installs a `globalThis.__pyreon_report_error__` bridge so the
|
|
404
|
+
* reactivity package (which can't depend on core) can forward effect errors
|
|
405
|
+
* into the same telemetry pipeline. Pre-fix the two surfaces were
|
|
406
|
+
* disconnected — Sentry/Datadog wiring missed effect-thrown errors.
|
|
299
407
|
*/
|
|
300
408
|
function registerErrorHandler(handler) {
|
|
301
409
|
_handlers.push(handler);
|
|
410
|
+
_installReactivityBridge();
|
|
302
411
|
return () => {
|
|
303
412
|
_handlers = _handlers.filter((h) => h !== handler);
|
|
304
413
|
};
|
|
@@ -312,10 +421,22 @@ function reportError(ctx) {
|
|
|
312
421
|
h(ctx);
|
|
313
422
|
} catch {}
|
|
314
423
|
}
|
|
424
|
+
const _bridgeHost = globalThis;
|
|
425
|
+
function _installReactivityBridge() {
|
|
426
|
+
if (_bridgeHost.__pyreon_report_error__) return;
|
|
427
|
+
_bridgeHost.__pyreon_report_error__ = (err, phase) => {
|
|
428
|
+
reportError({
|
|
429
|
+
component: "Effect",
|
|
430
|
+
phase,
|
|
431
|
+
error: err,
|
|
432
|
+
timestamp: Date.now()
|
|
433
|
+
});
|
|
434
|
+
};
|
|
435
|
+
}
|
|
315
436
|
|
|
316
437
|
//#endregion
|
|
317
438
|
//#region src/error-boundary.ts
|
|
318
|
-
const __DEV__$1 =
|
|
439
|
+
const __DEV__$1 = process.env.NODE_ENV !== "production";
|
|
319
440
|
/**
|
|
320
441
|
* ErrorBoundary — catches errors thrown by child components and renders a
|
|
321
442
|
* fallback UI instead of crashing the whole tree.
|
|
@@ -363,6 +484,7 @@ function ErrorBoundary(props) {
|
|
|
363
484
|
return typeof ch === "function" ? ch() : ch;
|
|
364
485
|
};
|
|
365
486
|
}
|
|
487
|
+
nativeCompat(ErrorBoundary);
|
|
366
488
|
|
|
367
489
|
//#endregion
|
|
368
490
|
//#region src/for.ts
|
|
@@ -577,20 +699,28 @@ function _rp(fn) {
|
|
|
577
699
|
* Returns the same object if no reactive props found (fast path).
|
|
578
700
|
*/
|
|
579
701
|
function makeReactiveProps(raw) {
|
|
702
|
+
const keys = Object.keys(raw);
|
|
703
|
+
let hasAny = false;
|
|
704
|
+
for (let i = 0; i < keys.length; i++) {
|
|
705
|
+
const val = raw[keys[i]];
|
|
706
|
+
if (typeof val === "function" && val[REACTIVE_PROP]) {
|
|
707
|
+
hasAny = true;
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (!hasAny) return raw;
|
|
580
712
|
const result = {};
|
|
581
|
-
let
|
|
582
|
-
|
|
713
|
+
for (let i = 0; i < keys.length; i++) {
|
|
714
|
+
const key = keys[i];
|
|
583
715
|
const val = raw[key];
|
|
584
|
-
if (typeof val === "function" && val[REACTIVE_PROP]) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
hasGetters = true;
|
|
591
|
-
} else result[key] = val;
|
|
716
|
+
if (typeof val === "function" && val[REACTIVE_PROP]) Object.defineProperty(result, key, {
|
|
717
|
+
get: val,
|
|
718
|
+
enumerable: true,
|
|
719
|
+
configurable: true
|
|
720
|
+
});
|
|
721
|
+
else result[key] = val;
|
|
592
722
|
}
|
|
593
|
-
return
|
|
723
|
+
return result;
|
|
594
724
|
}
|
|
595
725
|
let _idCounter = 0;
|
|
596
726
|
/**
|
|
@@ -616,6 +746,9 @@ function createRef() {
|
|
|
616
746
|
|
|
617
747
|
//#endregion
|
|
618
748
|
//#region src/show.ts
|
|
749
|
+
function callWhen(when) {
|
|
750
|
+
return typeof when === "function" ? when() : when;
|
|
751
|
+
}
|
|
619
752
|
/**
|
|
620
753
|
* Conditionally render children based on a reactive condition.
|
|
621
754
|
*
|
|
@@ -630,7 +763,7 @@ function createRef() {
|
|
|
630
763
|
* )
|
|
631
764
|
*/
|
|
632
765
|
function Show(props) {
|
|
633
|
-
return (() => props.when
|
|
766
|
+
return (() => callWhen(props.when) ? props.children ?? null : props.fallback ?? null);
|
|
634
767
|
}
|
|
635
768
|
/**
|
|
636
769
|
* A branch inside `<Switch>`. Renders when `when()` is truthy.
|
|
@@ -670,7 +803,8 @@ function Switch(props) {
|
|
|
670
803
|
const branches = normalizeBranches(props.children);
|
|
671
804
|
for (const branch of branches) {
|
|
672
805
|
if (!isMatchVNode(branch)) continue;
|
|
673
|
-
|
|
806
|
+
const matchProps = branch.props;
|
|
807
|
+
if (callWhen(matchProps.when)) return resolveMatchChildren(branch);
|
|
674
808
|
}
|
|
675
809
|
return props.fallback ?? null;
|
|
676
810
|
});
|
|
@@ -760,7 +894,7 @@ function normalizeStyleValue(key, value) {
|
|
|
760
894
|
|
|
761
895
|
//#endregion
|
|
762
896
|
//#region src/suspense.ts
|
|
763
|
-
const __DEV__ =
|
|
897
|
+
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
764
898
|
/**
|
|
765
899
|
* Suspense — shows `fallback` while a lazy child component is still loading.
|
|
766
900
|
*
|
|
@@ -788,5 +922,5 @@ function Suspense(props) {
|
|
|
788
922
|
}
|
|
789
923
|
|
|
790
924
|
//#endregion
|
|
791
|
-
export { CSS_UNITLESS, Dynamic, EMPTY_PROPS, ErrorBoundary, For, ForSymbol, Fragment, Match, MatchSymbol, Portal, PortalSymbol, REACTIVE_PROP, Show, Suspense, Switch, _rp, captureContextStack, createContext, createReactiveContext, createRef, createUniqueId, cx, defineComponent, dispatchToErrorBoundary, h, lazy, makeReactiveProps, mapArray, mergeProps, normalizeStyleValue, onErrorCaptured, onMount, onUnmount, onUpdate, popContext, propagateError, provide, pushContext, registerErrorHandler, reportError, restoreContextStack, runWithHooks, setContextStackProvider, splitProps, toKebabCase, useContext, withContext };
|
|
925
|
+
export { CSS_UNITLESS, Dynamic, EMPTY_PROPS, ErrorBoundary, For, ForSymbol, Fragment, Match, MatchSymbol, NATIVE_COMPAT_MARKER, Portal, PortalSymbol, REACTIVE_PROP, Show, Suspense, Switch, _rp, captureContextStack, createContext, createReactiveContext, createRef, createUniqueId, cx, defineComponent, dispatchToErrorBoundary, h, isNativeCompat, lazy, makeReactiveProps, mapArray, mergeProps, nativeCompat, normalizeStyleValue, onErrorCaptured, onMount, onUnmount, onUpdate, popContext, propagateError, provide, pushContext, registerErrorHandler, reportError, restoreContextStack, runWithHooks, setContextStackProvider, splitProps, toKebabCase, useContext, withContext };
|
|
792
926
|
//# sourceMappingURL=index.js.map
|
package/lib/jsx-dev-runtime.js
CHANGED
|
@@ -37,6 +37,13 @@ function flattenChildren(children) {
|
|
|
37
37
|
* When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
|
|
38
38
|
* rewrites JSX to imports from this file automatically:
|
|
39
39
|
* <div class="x" /> → jsx("div", { class: "x" })
|
|
40
|
+
*
|
|
41
|
+
* The triple-slash reference above makes this file self-declare its DOM-lib
|
|
42
|
+
* dependency. Without it, any consumer whose tsconfig has `lib: ["ESNext"]`
|
|
43
|
+
* (no DOM) — e.g. backend-only packages like @pyreon/cli — fails to typecheck
|
|
44
|
+
* once `@pyreon/core` becomes resolvable from their dependency graph (e.g. via
|
|
45
|
+
* a transitive devDep), because tsc auto-resolves jsxImportSource and pulls
|
|
46
|
+
* jsx-runtime.ts into the consumer's compilation unit.
|
|
40
47
|
*/
|
|
41
48
|
function jsx(type, props, key) {
|
|
42
49
|
const { children, ...rest } = props;
|
package/lib/jsx-runtime.js
CHANGED
|
@@ -37,6 +37,13 @@ function flattenChildren(children) {
|
|
|
37
37
|
* When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
|
|
38
38
|
* rewrites JSX to imports from this file automatically:
|
|
39
39
|
* <div class="x" /> → jsx("div", { class: "x" })
|
|
40
|
+
*
|
|
41
|
+
* The triple-slash reference above makes this file self-declare its DOM-lib
|
|
42
|
+
* dependency. Without it, any consumer whose tsconfig has `lib: ["ESNext"]`
|
|
43
|
+
* (no DOM) — e.g. backend-only packages like @pyreon/cli — fails to typecheck
|
|
44
|
+
* once `@pyreon/core` becomes resolvable from their dependency graph (e.g. via
|
|
45
|
+
* a transitive devDep), because tsc auto-resolves jsxImportSource and pulls
|
|
46
|
+
* jsx-runtime.ts into the consumer's compilation unit.
|
|
40
47
|
*/
|
|
41
48
|
function jsx(type, props, key) {
|
|
42
49
|
const { children, ...rest } = props;
|