@pyreon/core 0.11.4 → 0.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +33 -5
- package/lib/index.js.map +1 -1
- package/lib/jsx-dev-runtime.js.map +1 -1
- package/lib/jsx-runtime.js.map +1 -1
- package/lib/types/index.d.ts +145 -98
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/jsx-dev-runtime.d.ts +94 -94
- package/lib/types/jsx-runtime.d.ts +94 -94
- package/package.json +11 -11
- package/src/component.ts +2 -2
- package/src/context.ts +75 -4
- package/src/dynamic.ts +4 -4
- package/src/error-boundary.ts +10 -10
- package/src/for.ts +8 -2
- package/src/h.ts +4 -4
- package/src/index.ts +30 -27
- package/src/jsx-dev-runtime.ts +1 -1
- package/src/jsx-runtime.ts +108 -108
- package/src/lazy.ts +4 -4
- package/src/lifecycle.ts +6 -6
- package/src/portal.ts +2 -2
- package/src/show.ts +4 -4
- package/src/style.ts +51 -51
- package/src/suspense.ts +8 -8
- package/src/telemetry.ts +1 -1
- package/src/tests/component.test.ts +60 -60
- package/src/tests/context.test.ts +102 -102
- package/src/tests/core.test.ts +376 -376
- package/src/tests/cx.test.ts +34 -34
- package/src/tests/dynamic.test.ts +28 -28
- package/src/tests/error-boundary.test.ts +51 -51
- package/src/tests/for.test.ts +26 -26
- package/src/tests/h.test.ts +100 -100
- package/src/tests/jsx-compat.test.tsx +41 -41
- package/src/tests/lazy.test.ts +28 -28
- package/src/tests/lifecycle.test.ts +35 -35
- package/src/tests/map-array.test.ts +36 -36
- package/src/tests/portal.test.ts +21 -21
- package/src/tests/props-extended.test.ts +51 -51
- package/src/tests/props.test.ts +62 -62
- package/src/tests/ref.test.ts +20 -20
- package/src/tests/show.test.ts +94 -94
- package/src/tests/style.test.ts +101 -101
- package/src/tests/suspense.test.ts +44 -44
- package/src/tests/telemetry.test.ts +35 -35
|
@@ -48,7 +48,7 @@ declare function jsx(type: string | ComponentFn | symbol, props: Props & {
|
|
|
48
48
|
children?: VNodeChild | VNodeChild[];
|
|
49
49
|
}, key?: string | number | null): VNode;
|
|
50
50
|
declare const jsxs: typeof jsx;
|
|
51
|
-
type Booleanish = boolean |
|
|
51
|
+
type Booleanish = boolean | 'true' | 'false';
|
|
52
52
|
type CSSProperties = { [K in keyof CSSStyleDeclaration]?: string | number };
|
|
53
53
|
type StyleValue = string | CSSProperties;
|
|
54
54
|
/** Event with typed currentTarget — used in element-specific event handlers. */
|
|
@@ -65,58 +65,58 @@ interface PyreonHTMLAttributes<E extends Element = HTMLElement> {
|
|
|
65
65
|
tabIndex?: number | (() => number) | undefined;
|
|
66
66
|
title?: string | (() => string) | undefined;
|
|
67
67
|
lang?: string | undefined;
|
|
68
|
-
dir?:
|
|
68
|
+
dir?: 'ltr' | 'rtl' | 'auto' | undefined;
|
|
69
69
|
hidden?: boolean | (() => boolean) | undefined;
|
|
70
70
|
draggable?: Booleanish | undefined;
|
|
71
|
-
contentEditable?: Booleanish |
|
|
71
|
+
contentEditable?: Booleanish | 'inherit' | 'plaintext-only' | undefined;
|
|
72
72
|
spellCheck?: Booleanish | undefined;
|
|
73
|
-
autoCapitalize?:
|
|
74
|
-
translate?:
|
|
75
|
-
enterKeyHint?:
|
|
76
|
-
inputMode?:
|
|
73
|
+
autoCapitalize?: 'off' | 'on' | 'sentences' | 'words' | 'characters' | undefined;
|
|
74
|
+
translate?: 'yes' | 'no' | undefined;
|
|
75
|
+
enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send' | undefined;
|
|
76
|
+
inputMode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url' | undefined;
|
|
77
77
|
is?: string | undefined;
|
|
78
78
|
slot?: string | undefined;
|
|
79
79
|
part?: string | undefined;
|
|
80
|
-
popover?:
|
|
80
|
+
popover?: 'auto' | 'manual' | undefined;
|
|
81
81
|
popoverTarget?: string | undefined;
|
|
82
|
-
popoverTargetAction?:
|
|
82
|
+
popoverTargetAction?: 'toggle' | 'show' | 'hide' | undefined;
|
|
83
83
|
inert?: boolean | undefined;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
84
|
+
'aria-label'?: string | (() => string) | undefined;
|
|
85
|
+
'aria-hidden'?: Booleanish | (() => Booleanish) | undefined;
|
|
86
|
+
'aria-disabled'?: Booleanish | (() => Booleanish) | undefined;
|
|
87
|
+
'aria-expanded'?: Booleanish | (() => Booleanish) | undefined;
|
|
88
|
+
'aria-selected'?: Booleanish | (() => Booleanish) | undefined;
|
|
89
|
+
'aria-checked'?: Booleanish | 'mixed' | (() => Booleanish | 'mixed') | undefined;
|
|
90
|
+
'aria-current'?: Booleanish | 'page' | 'step' | 'location' | 'date' | 'time' | undefined;
|
|
91
|
+
'aria-live'?: 'off' | 'assertive' | 'polite' | undefined;
|
|
92
|
+
'aria-atomic'?: Booleanish | undefined;
|
|
93
|
+
'aria-busy'?: Booleanish | undefined;
|
|
94
|
+
'aria-controls'?: string | undefined;
|
|
95
|
+
'aria-describedby'?: string | undefined;
|
|
96
|
+
'aria-labelledby'?: string | undefined;
|
|
97
|
+
'aria-placeholder'?: string | undefined;
|
|
98
|
+
'aria-required'?: Booleanish | (() => Booleanish) | undefined;
|
|
99
|
+
'aria-invalid'?: Booleanish | 'grammar' | 'spelling' | undefined;
|
|
100
|
+
'aria-valuemin'?: number | undefined;
|
|
101
|
+
'aria-valuemax'?: number | undefined;
|
|
102
|
+
'aria-valuenow'?: number | undefined;
|
|
103
|
+
'aria-valuetext'?: string | undefined;
|
|
104
|
+
'aria-haspopup'?: Booleanish | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | undefined;
|
|
105
|
+
'aria-posinset'?: number | undefined;
|
|
106
|
+
'aria-setsize'?: number | undefined;
|
|
107
|
+
'aria-level'?: number | undefined;
|
|
108
|
+
'aria-multiline'?: Booleanish | undefined;
|
|
109
|
+
'aria-multiselectable'?: Booleanish | undefined;
|
|
110
|
+
'aria-orientation'?: 'horizontal' | 'vertical' | undefined;
|
|
111
|
+
'aria-readonly'?: Booleanish | (() => Booleanish) | undefined;
|
|
112
|
+
'aria-sort'?: 'none' | 'ascending' | 'descending' | 'other' | undefined;
|
|
113
|
+
'aria-autocomplete'?: 'none' | 'inline' | 'list' | 'both' | undefined;
|
|
114
|
+
'aria-colcount'?: number | undefined;
|
|
115
|
+
'aria-colindex'?: number | undefined;
|
|
116
|
+
'aria-colspan'?: number | undefined;
|
|
117
|
+
'aria-rowcount'?: number | undefined;
|
|
118
|
+
'aria-rowindex'?: number | undefined;
|
|
119
|
+
'aria-rowspan'?: number | undefined;
|
|
120
120
|
ref?: RefProp<E> | undefined;
|
|
121
121
|
key?: string | number | undefined;
|
|
122
122
|
children?: VNodeChild | VNodeChild[];
|
|
@@ -202,7 +202,7 @@ interface InputAttributes extends PyreonHTMLAttributes<HTMLInputElement> {
|
|
|
202
202
|
accept?: string | undefined;
|
|
203
203
|
autoComplete?: string | undefined;
|
|
204
204
|
autoFocus?: boolean | undefined;
|
|
205
|
-
capture?:
|
|
205
|
+
capture?: 'user' | 'environment' | string | undefined;
|
|
206
206
|
form?: string | undefined;
|
|
207
207
|
formNoValidate?: boolean | undefined;
|
|
208
208
|
list?: string | undefined;
|
|
@@ -217,12 +217,12 @@ interface AnchorAttributes extends PyreonHTMLAttributes<HTMLAnchorElement> {
|
|
|
217
217
|
hreflang?: string | undefined;
|
|
218
218
|
ping?: string | undefined;
|
|
219
219
|
referrerPolicy?: string | undefined;
|
|
220
|
-
target?:
|
|
220
|
+
target?: '_blank' | '_self' | '_parent' | '_top' | string | undefined;
|
|
221
221
|
rel?: string | undefined;
|
|
222
222
|
download?: string | boolean | undefined;
|
|
223
223
|
}
|
|
224
224
|
interface ButtonAttributes extends PyreonHTMLAttributes<HTMLButtonElement> {
|
|
225
|
-
type?:
|
|
225
|
+
type?: 'button' | 'submit' | 'reset' | undefined;
|
|
226
226
|
disabled?: boolean | (() => boolean) | undefined;
|
|
227
227
|
name?: string | undefined;
|
|
228
228
|
value?: string | undefined;
|
|
@@ -247,7 +247,7 @@ interface TextareaAttributes extends PyreonHTMLAttributes<HTMLTextAreaElement> {
|
|
|
247
247
|
name?: string | undefined;
|
|
248
248
|
autoFocus?: boolean | undefined;
|
|
249
249
|
form?: string | undefined;
|
|
250
|
-
wrap?:
|
|
250
|
+
wrap?: 'hard' | 'soft' | undefined;
|
|
251
251
|
}
|
|
252
252
|
interface SelectAttributes extends PyreonHTMLAttributes<HTMLSelectElement> {
|
|
253
253
|
value?: string | string[] | (() => string | string[]) | undefined;
|
|
@@ -268,7 +268,7 @@ interface OptionAttributes extends PyreonHTMLAttributes<HTMLOptionElement> {
|
|
|
268
268
|
}
|
|
269
269
|
interface FormAttributes extends PyreonHTMLAttributes<HTMLFormElement> {
|
|
270
270
|
action?: string | undefined;
|
|
271
|
-
method?:
|
|
271
|
+
method?: 'get' | 'post' | undefined;
|
|
272
272
|
encType?: string | undefined;
|
|
273
273
|
noValidate?: boolean | undefined;
|
|
274
274
|
target?: string | undefined;
|
|
@@ -282,13 +282,13 @@ interface ImgAttributes extends PyreonHTMLAttributes<HTMLImageElement> {
|
|
|
282
282
|
alt?: string | (() => string) | undefined;
|
|
283
283
|
width?: number | string | (() => number | string) | undefined;
|
|
284
284
|
height?: number | string | (() => number | string) | undefined;
|
|
285
|
-
loading?:
|
|
286
|
-
decoding?:
|
|
287
|
-
crossOrigin?:
|
|
285
|
+
loading?: 'lazy' | 'eager' | undefined;
|
|
286
|
+
decoding?: 'auto' | 'async' | 'sync' | undefined;
|
|
287
|
+
crossOrigin?: 'anonymous' | 'use-credentials' | undefined;
|
|
288
288
|
referrerPolicy?: string | undefined;
|
|
289
289
|
srcSet?: string | (() => string) | undefined;
|
|
290
290
|
sizes?: string | (() => string) | undefined;
|
|
291
|
-
fetchPriority?:
|
|
291
|
+
fetchPriority?: 'high' | 'low' | 'auto' | undefined;
|
|
292
292
|
}
|
|
293
293
|
interface VideoAttributes extends PyreonHTMLAttributes<HTMLVideoElement> {
|
|
294
294
|
src?: string | (() => string) | undefined;
|
|
@@ -299,9 +299,9 @@ interface VideoAttributes extends PyreonHTMLAttributes<HTMLVideoElement> {
|
|
|
299
299
|
muted?: boolean | undefined;
|
|
300
300
|
loop?: boolean | undefined;
|
|
301
301
|
poster?: string | (() => string) | undefined;
|
|
302
|
-
preload?:
|
|
302
|
+
preload?: 'none' | 'metadata' | 'auto' | undefined;
|
|
303
303
|
playsInline?: boolean | undefined;
|
|
304
|
-
crossOrigin?:
|
|
304
|
+
crossOrigin?: 'anonymous' | 'use-credentials' | undefined;
|
|
305
305
|
disablePictureInPicture?: boolean | undefined;
|
|
306
306
|
disableRemotePlayback?: boolean | undefined;
|
|
307
307
|
}
|
|
@@ -311,8 +311,8 @@ interface AudioAttributes extends PyreonHTMLAttributes<HTMLAudioElement> {
|
|
|
311
311
|
autoPlay?: boolean | undefined;
|
|
312
312
|
muted?: boolean | undefined;
|
|
313
313
|
loop?: boolean | undefined;
|
|
314
|
-
preload?:
|
|
315
|
-
crossOrigin?:
|
|
314
|
+
preload?: 'none' | 'metadata' | 'auto' | undefined;
|
|
315
|
+
crossOrigin?: 'anonymous' | 'use-credentials' | undefined;
|
|
316
316
|
}
|
|
317
317
|
interface LabelAttributes extends PyreonHTMLAttributes<HTMLLabelElement> {
|
|
318
318
|
htmlFor?: string | undefined;
|
|
@@ -322,7 +322,7 @@ interface LabelAttributes extends PyreonHTMLAttributes<HTMLLabelElement> {
|
|
|
322
322
|
interface ThAttributes extends PyreonHTMLAttributes<HTMLTableCellElement> {
|
|
323
323
|
colSpan?: number | undefined;
|
|
324
324
|
rowSpan?: number | undefined;
|
|
325
|
-
scope?:
|
|
325
|
+
scope?: 'col' | 'row' | 'colgroup' | 'rowgroup' | undefined;
|
|
326
326
|
abbr?: string | undefined;
|
|
327
327
|
headers?: string | undefined;
|
|
328
328
|
}
|
|
@@ -340,7 +340,7 @@ interface IframeAttributes extends PyreonHTMLAttributes<HTMLIFrameElement> {
|
|
|
340
340
|
height?: number | string | undefined;
|
|
341
341
|
allow?: string | undefined;
|
|
342
342
|
allowFullScreen?: boolean | undefined;
|
|
343
|
-
loading?:
|
|
343
|
+
loading?: 'lazy' | 'eager' | undefined;
|
|
344
344
|
name?: string | undefined;
|
|
345
345
|
sandbox?: string | undefined;
|
|
346
346
|
referrerPolicy?: string | undefined;
|
|
@@ -352,7 +352,7 @@ interface LinkAttributes extends PyreonHTMLAttributes<HTMLLinkElement> {
|
|
|
352
352
|
type?: string | undefined;
|
|
353
353
|
as?: string | undefined;
|
|
354
354
|
media?: string | undefined;
|
|
355
|
-
crossOrigin?:
|
|
355
|
+
crossOrigin?: 'anonymous' | 'use-credentials' | undefined;
|
|
356
356
|
integrity?: string | undefined;
|
|
357
357
|
referrerPolicy?: string | undefined;
|
|
358
358
|
}
|
|
@@ -368,7 +368,7 @@ interface ScriptAttributes extends PyreonHTMLAttributes<HTMLScriptElement> {
|
|
|
368
368
|
type?: string | undefined;
|
|
369
369
|
async?: boolean | undefined;
|
|
370
370
|
defer?: boolean | undefined;
|
|
371
|
-
crossOrigin?:
|
|
371
|
+
crossOrigin?: 'anonymous' | 'use-credentials' | undefined;
|
|
372
372
|
integrity?: string | undefined;
|
|
373
373
|
noModule?: boolean | undefined;
|
|
374
374
|
referrerPolicy?: string | undefined;
|
|
@@ -401,7 +401,7 @@ interface DialogAttributes extends PyreonHTMLAttributes<HTMLDialogElement> {
|
|
|
401
401
|
interface OlAttributes extends PyreonHTMLAttributes<HTMLOListElement> {
|
|
402
402
|
start?: number | undefined;
|
|
403
403
|
reversed?: boolean | undefined;
|
|
404
|
-
type?:
|
|
404
|
+
type?: '1' | 'a' | 'A' | 'i' | 'I' | undefined;
|
|
405
405
|
}
|
|
406
406
|
interface CanvasAttributes extends PyreonHTMLAttributes<HTMLCanvasElement> {
|
|
407
407
|
width?: number | string | undefined;
|
|
@@ -412,12 +412,12 @@ interface SvgAttributes extends PyreonHTMLAttributes<SVGElement> {
|
|
|
412
412
|
xmlns?: string | undefined;
|
|
413
413
|
fill?: string | (() => string) | undefined;
|
|
414
414
|
stroke?: string | (() => string) | undefined;
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
415
|
+
'stroke-width'?: string | number | undefined;
|
|
416
|
+
'stroke-linecap'?: 'butt' | 'round' | 'square' | undefined;
|
|
417
|
+
'stroke-linejoin'?: 'miter' | 'round' | 'bevel' | undefined;
|
|
418
|
+
'fill-rule'?: 'nonzero' | 'evenodd' | undefined;
|
|
419
|
+
'clip-rule'?: 'nonzero' | 'evenodd' | undefined;
|
|
420
|
+
'clip-path'?: string | undefined;
|
|
421
421
|
d?: string | undefined;
|
|
422
422
|
cx?: string | number | undefined;
|
|
423
423
|
cy?: string | number | undefined;
|
|
@@ -435,33 +435,33 @@ interface SvgAttributes extends PyreonHTMLAttributes<SVGElement> {
|
|
|
435
435
|
transform?: string | (() => string) | undefined;
|
|
436
436
|
opacity?: string | number | (() => string | number) | undefined;
|
|
437
437
|
points?: string | undefined;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
gradientUnits?:
|
|
438
|
+
'font-size'?: string | number | undefined;
|
|
439
|
+
'text-anchor'?: 'start' | 'middle' | 'end' | undefined;
|
|
440
|
+
'dominant-baseline'?: string | undefined;
|
|
441
|
+
gradientUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
442
442
|
gradientTransform?: string | undefined;
|
|
443
|
-
patternUnits?:
|
|
444
|
-
patternContentUnits?:
|
|
443
|
+
patternUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
444
|
+
patternContentUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
445
445
|
patternTransform?: string | undefined;
|
|
446
|
-
spreadMethod?:
|
|
446
|
+
spreadMethod?: 'pad' | 'reflect' | 'repeat' | undefined;
|
|
447
447
|
markerWidth?: string | number | undefined;
|
|
448
448
|
markerHeight?: string | number | undefined;
|
|
449
|
-
markerUnits?:
|
|
449
|
+
markerUnits?: 'strokeWidth' | 'userSpaceOnUse' | undefined;
|
|
450
450
|
orient?: string | number | undefined;
|
|
451
451
|
refX?: string | number | undefined;
|
|
452
452
|
refY?: string | number | undefined;
|
|
453
|
-
maskUnits?:
|
|
454
|
-
maskContentUnits?:
|
|
455
|
-
clipPathUnits?:
|
|
456
|
-
filterUnits?:
|
|
457
|
-
primitiveUnits?:
|
|
453
|
+
maskUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
454
|
+
maskContentUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
455
|
+
clipPathUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
456
|
+
filterUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
457
|
+
primitiveUnits?: 'userSpaceOnUse' | 'objectBoundingBox' | undefined;
|
|
458
458
|
preserveAspectRatio?: string | undefined;
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
459
|
+
'color-interpolation'?: string | undefined;
|
|
460
|
+
'color-interpolation-filters'?: string | undefined;
|
|
461
|
+
'shape-rendering'?: string | undefined;
|
|
462
|
+
'image-rendering'?: string | undefined;
|
|
463
|
+
'text-rendering'?: string | undefined;
|
|
464
|
+
'pointer-events'?: string | undefined;
|
|
465
465
|
visibility?: string | undefined;
|
|
466
466
|
display?: string | undefined;
|
|
467
467
|
overflow?: string | undefined;
|
|
@@ -469,10 +469,10 @@ interface SvgAttributes extends PyreonHTMLAttributes<SVGElement> {
|
|
|
469
469
|
dx?: string | number | undefined;
|
|
470
470
|
dy?: string | number | undefined;
|
|
471
471
|
textLength?: string | number | undefined;
|
|
472
|
-
lengthAdjust?:
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
472
|
+
lengthAdjust?: 'spacing' | 'spacingAndGlyphs' | undefined;
|
|
473
|
+
'writing-mode'?: string | undefined;
|
|
474
|
+
'letter-spacing'?: string | number | undefined;
|
|
475
|
+
'word-spacing'?: string | number | undefined;
|
|
476
476
|
pathLength?: number | undefined;
|
|
477
477
|
href?: string | undefined;
|
|
478
478
|
}
|
|
@@ -615,8 +615,8 @@ declare global {
|
|
|
615
615
|
radialGradient: SvgAttributes;
|
|
616
616
|
stop: SvgAttributes & {
|
|
617
617
|
offset?: string | number;
|
|
618
|
-
|
|
619
|
-
|
|
618
|
+
'stop-color'?: string;
|
|
619
|
+
'stop-opacity'?: string | number;
|
|
620
620
|
};
|
|
621
621
|
details: DetailsAttributes;
|
|
622
622
|
summary: PyreonHTMLAttributes;
|
package/package.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/core",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.6",
|
|
4
4
|
"description": "Core component model and lifecycle for Pyreon",
|
|
5
|
+
"homepage": "https://github.com/pyreon/pyreon/tree/main/packages/core#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/pyreon/pyreon/issues"
|
|
8
|
+
},
|
|
5
9
|
"license": "MIT",
|
|
6
10
|
"repository": {
|
|
7
11
|
"type": "git",
|
|
8
12
|
"url": "https://github.com/pyreon/pyreon.git",
|
|
9
13
|
"directory": "packages/core/core"
|
|
10
14
|
},
|
|
11
|
-
"homepage": "https://github.com/pyreon/pyreon/tree/main/packages/core#readme",
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/pyreon/pyreon/issues"
|
|
14
|
-
},
|
|
15
15
|
"files": [
|
|
16
16
|
"lib",
|
|
17
17
|
"src",
|
|
18
18
|
"README.md",
|
|
19
19
|
"LICENSE"
|
|
20
20
|
],
|
|
21
|
-
"sideEffects": false,
|
|
22
21
|
"type": "module",
|
|
22
|
+
"sideEffects": false,
|
|
23
23
|
"main": "./lib/index.js",
|
|
24
24
|
"module": "./lib/index.js",
|
|
25
25
|
"types": "./lib/types/index.d.ts",
|
|
@@ -40,18 +40,18 @@
|
|
|
40
40
|
"types": "./lib/types/jsx-dev-runtime.d.ts"
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
43
46
|
"scripts": {
|
|
44
47
|
"build": "vl_rolldown_build",
|
|
45
48
|
"dev": "vl_rolldown_build-watch",
|
|
46
49
|
"test": "vitest run",
|
|
47
50
|
"typecheck": "tsc --noEmit",
|
|
48
|
-
"lint": "
|
|
51
|
+
"lint": "oxlint .",
|
|
49
52
|
"prepublishOnly": "bun run build"
|
|
50
53
|
},
|
|
51
54
|
"dependencies": {
|
|
52
|
-
"@pyreon/reactivity": "^0.11.
|
|
53
|
-
},
|
|
54
|
-
"publishConfig": {
|
|
55
|
-
"access": "public"
|
|
55
|
+
"@pyreon/reactivity": "^0.11.6"
|
|
56
56
|
}
|
|
57
57
|
}
|
package/src/component.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { setCurrentHooks } from
|
|
2
|
-
import type { ComponentFn, LifecycleHooks, Props, VNodeChild } from
|
|
1
|
+
import { setCurrentHooks } from './lifecycle'
|
|
2
|
+
import type { ComponentFn, LifecycleHooks, Props, VNodeChild } from './types'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Identity wrapper — marks a function as a Pyreon component and preserves its type.
|
package/src/context.ts
CHANGED
|
@@ -5,15 +5,42 @@
|
|
|
5
5
|
* The renderer maintains the context stack as it walks the VNode tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { onUnmount } from
|
|
8
|
+
import { onUnmount } from './lifecycle'
|
|
9
9
|
|
|
10
10
|
export interface Context<T> {
|
|
11
11
|
readonly id: symbol
|
|
12
12
|
readonly defaultValue: T
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/** Branded marker for reactive contexts — distinguishes from regular Context at type level. */
|
|
16
|
+
declare const REACTIVE_BRAND: unique symbol
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A context whose value is a reactive accessor `() => T`.
|
|
20
|
+
*
|
|
21
|
+
* When you `useContext(reactiveCtx)`, TypeScript returns `() => T` —
|
|
22
|
+
* you MUST call the accessor to read the value. This prevents the
|
|
23
|
+
* destructuring trap that breaks reactivity with getter-based objects.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const ModeCtx = createReactiveContext<'light' | 'dark'>('light')
|
|
27
|
+
* // Provider: provide(ModeCtx, () => modeSignal())
|
|
28
|
+
* // Consumer: const getMode = useContext(ModeCtx); getMode() // 'light'
|
|
29
|
+
*/
|
|
30
|
+
export interface ReactiveContext<T> extends Context<() => T> {
|
|
31
|
+
readonly [REACTIVE_BRAND]: T
|
|
32
|
+
}
|
|
33
|
+
|
|
15
34
|
export function createContext<T>(defaultValue: T): Context<T> {
|
|
16
|
-
return { id: Symbol(
|
|
35
|
+
return { id: Symbol('PyreonContext'), defaultValue }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a reactive context. Consumers get `() => T` and must call it.
|
|
40
|
+
* This is the safe pattern for values that change over time (mode, locale, etc.).
|
|
41
|
+
*/
|
|
42
|
+
export function createReactiveContext<T>(defaultValue: T): ReactiveContext<T> {
|
|
43
|
+
return createContext<() => T>(() => defaultValue) as ReactiveContext<T>
|
|
17
44
|
}
|
|
18
45
|
|
|
19
46
|
// ─── Runtime context stack (managed by the renderer) ─────────────────────────
|
|
@@ -37,7 +64,7 @@ function getStack(): Map<symbol, unknown>[] {
|
|
|
37
64
|
return _stackProvider()
|
|
38
65
|
}
|
|
39
66
|
|
|
40
|
-
const __DEV__ = typeof process !==
|
|
67
|
+
const __DEV__ = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'
|
|
41
68
|
|
|
42
69
|
export function pushContext(values: Map<symbol, unknown>) {
|
|
43
70
|
getStack().push(values)
|
|
@@ -48,7 +75,7 @@ export function popContext() {
|
|
|
48
75
|
if (__DEV__ && stack.length === 0) {
|
|
49
76
|
// biome-ignore lint/suspicious/noConsole: dev-only warning
|
|
50
77
|
console.warn(
|
|
51
|
-
|
|
78
|
+
'[Pyreon] popContext() called on an empty context stack. This likely indicates a missing Provider.',
|
|
52
79
|
)
|
|
53
80
|
return
|
|
54
81
|
}
|
|
@@ -58,7 +85,12 @@ export function popContext() {
|
|
|
58
85
|
/**
|
|
59
86
|
* Read the nearest provided value for a context.
|
|
60
87
|
* Falls back to `context.defaultValue` if none found.
|
|
88
|
+
*
|
|
89
|
+
* For ReactiveContext<T>, returns `() => T` — you MUST call the accessor.
|
|
90
|
+
* For regular Context<T>, returns `T` directly.
|
|
61
91
|
*/
|
|
92
|
+
export function useContext<T>(context: ReactiveContext<T>): () => T
|
|
93
|
+
export function useContext<T>(context: Context<T>): T
|
|
62
94
|
export function useContext<T>(context: Context<T>): T {
|
|
63
95
|
const stack = getStack()
|
|
64
96
|
for (let i = stack.length - 1; i >= 0; i--) {
|
|
@@ -99,3 +131,42 @@ export function withContext<T>(context: Context<T>, value: T, fn: () => void) {
|
|
|
99
131
|
popContext()
|
|
100
132
|
}
|
|
101
133
|
}
|
|
134
|
+
|
|
135
|
+
// ─── Context snapshot for deferred mounting ─────────────────────────────────
|
|
136
|
+
|
|
137
|
+
export type ContextSnapshot = Map<symbol, unknown>[]
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Capture a snapshot of the current context stack.
|
|
141
|
+
*
|
|
142
|
+
* Used by `mountReactive` to preserve the context that was active when a
|
|
143
|
+
* reactive boundary (e.g. `<Show>`, `<For>`) was set up. When the boundary
|
|
144
|
+
* later mounts new children inside an effect, the snapshot is restored so
|
|
145
|
+
* those children can see ancestor providers via `useContext()`.
|
|
146
|
+
*/
|
|
147
|
+
export function captureContextStack(): ContextSnapshot {
|
|
148
|
+
// Shallow copy — each frame (Map) is shared by reference, which is
|
|
149
|
+
// correct because providers don't mutate frames after creation.
|
|
150
|
+
return [...getStack()]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Execute `fn()` with a previously captured context stack active.
|
|
155
|
+
* Restores the original stack after `fn()` completes (even on throw).
|
|
156
|
+
*/
|
|
157
|
+
export function restoreContextStack<T>(snapshot: ContextSnapshot, fn: () => T): T {
|
|
158
|
+
const stack = getStack()
|
|
159
|
+
const savedLength = stack.length
|
|
160
|
+
|
|
161
|
+
// Push all captured frames onto the current stack
|
|
162
|
+
for (const frame of snapshot) {
|
|
163
|
+
stack.push(frame)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
return fn()
|
|
168
|
+
} finally {
|
|
169
|
+
// Remove only the frames we pushed (preserve anything added by fn)
|
|
170
|
+
stack.length = savedLength
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/dynamic.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { h } from
|
|
2
|
-
import type { ComponentFn, Props, VNode } from
|
|
1
|
+
import { h } from './h'
|
|
2
|
+
import type { ComponentFn, Props, VNode } from './types'
|
|
3
3
|
|
|
4
|
-
const __DEV__ = typeof process !==
|
|
4
|
+
const __DEV__ = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'
|
|
5
5
|
|
|
6
6
|
export interface DynamicProps extends Props {
|
|
7
7
|
component: ComponentFn | string
|
|
@@ -11,7 +11,7 @@ export function Dynamic(props: DynamicProps): VNode | null {
|
|
|
11
11
|
const { component, ...rest } = props
|
|
12
12
|
if (__DEV__ && !component) {
|
|
13
13
|
// biome-ignore lint/suspicious/noConsole: dev-only warning
|
|
14
|
-
console.warn(
|
|
14
|
+
console.warn('[Pyreon] <Dynamic> received a falsy `component` prop. Nothing will be rendered.')
|
|
15
15
|
}
|
|
16
16
|
if (!component) return null
|
|
17
17
|
return h(component as string | ComponentFn, rest as Props)
|
package/src/error-boundary.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { signal } from
|
|
2
|
-
import { popErrorBoundary, pushErrorBoundary } from
|
|
3
|
-
import { onUnmount } from
|
|
4
|
-
import { reportError } from
|
|
5
|
-
import type { VNodeChild, VNodeChildAtom } from
|
|
1
|
+
import { signal } from '@pyreon/reactivity'
|
|
2
|
+
import { popErrorBoundary, pushErrorBoundary } from './component'
|
|
3
|
+
import { onUnmount } from './lifecycle'
|
|
4
|
+
import { reportError } from './telemetry'
|
|
5
|
+
import type { VNodeChild, VNodeChildAtom } from './types'
|
|
6
6
|
|
|
7
|
-
const __DEV__ = typeof process !==
|
|
7
|
+
const __DEV__ = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* ErrorBoundary — catches errors thrown by child components and renders a
|
|
@@ -37,10 +37,10 @@ export function ErrorBoundary(props: {
|
|
|
37
37
|
fallback: (err: unknown, reset: () => void) => VNodeChild
|
|
38
38
|
children?: VNodeChild
|
|
39
39
|
}): VNodeChild {
|
|
40
|
-
if (__DEV__ && typeof props.fallback !==
|
|
40
|
+
if (__DEV__ && typeof props.fallback !== 'function') {
|
|
41
41
|
// biome-ignore lint/suspicious/noConsole: dev-only warning
|
|
42
42
|
console.warn(
|
|
43
|
-
|
|
43
|
+
'[Pyreon] <ErrorBoundary> expects `fallback` to be a function: (err, reset) => VNode. ' +
|
|
44
44
|
`Received ${typeof props.fallback}.`,
|
|
45
45
|
)
|
|
46
46
|
}
|
|
@@ -51,7 +51,7 @@ export function ErrorBoundary(props: {
|
|
|
51
51
|
const handler = (err: unknown): boolean => {
|
|
52
52
|
if (error.peek() !== null) return false // already in error state — let outer boundary catch it
|
|
53
53
|
error.set(err)
|
|
54
|
-
reportError({ component:
|
|
54
|
+
reportError({ component: 'ErrorBoundary', phase: 'render', error: err, timestamp: Date.now() })
|
|
55
55
|
return true
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -63,6 +63,6 @@ export function ErrorBoundary(props: {
|
|
|
63
63
|
const err = error()
|
|
64
64
|
if (err != null) return props.fallback(err, reset) as VNodeChildAtom
|
|
65
65
|
const ch = props.children
|
|
66
|
-
return (typeof ch ===
|
|
66
|
+
return (typeof ch === 'function' ? ch() : ch) as VNodeChildAtom
|
|
67
67
|
}
|
|
68
68
|
}
|
package/src/for.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
import type { NativeItem, Props, VNode } from
|
|
1
|
+
import type { NativeItem, Props, VNode } from './types'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Symbol used as the VNode type for a For list — runtime-dom handles it
|
|
5
5
|
* via mountFor, bypassing the generic VNode reconciler.
|
|
6
6
|
*/
|
|
7
|
-
export const ForSymbol: unique symbol = Symbol(
|
|
7
|
+
export const ForSymbol: unique symbol = Symbol('pyreon.For')
|
|
8
8
|
|
|
9
9
|
export interface ForProps<T> {
|
|
10
10
|
each: () => T[]
|
|
11
|
+
/** Keying function — use `by` not `key` (JSX extracts `key` for VNode reconciliation). */
|
|
11
12
|
by: (item: T) => string | number
|
|
12
13
|
children: (item: T) => VNode | NativeItem
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use `by` instead of `key`. In Pyreon, `<For>` uses `by` for keying.
|
|
16
|
+
* JSX reserves `key` for VNode reconciliation — it won't reach the component.
|
|
17
|
+
*/
|
|
18
|
+
key?: never
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
/**
|
package/src/h.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ComponentFn, Props, VNode, VNodeChild } from
|
|
1
|
+
import type { ComponentFn, Props, VNode, VNodeChild } from './types'
|
|
2
2
|
|
|
3
3
|
/** Marker for fragment nodes — renders children without a wrapper element */
|
|
4
|
-
export const Fragment: unique symbol = Symbol(
|
|
4
|
+
export const Fragment: unique symbol = Symbol('Pyreon.Fragment')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Hyperscript function — the compiled output of JSX.
|
|
@@ -14,8 +14,8 @@ export const Fragment: unique symbol = Symbol("Pyreon.Fragment")
|
|
|
14
14
|
export const EMPTY_PROPS: Props = {} as Props
|
|
15
15
|
|
|
16
16
|
/** Makes `children` optional in P (if present) so it can be passed as rest args to h(). */
|
|
17
|
-
type PropsWithOptionalChildren<P extends Props> = Omit<P,
|
|
18
|
-
(
|
|
17
|
+
type PropsWithOptionalChildren<P extends Props> = Omit<P, 'children'> &
|
|
18
|
+
('children' extends keyof P ? { children?: P['children'] } : unknown)
|
|
19
19
|
|
|
20
20
|
// Overload: component with typed props — children is optional in the props object
|
|
21
21
|
// because it can be passed as rest args. Extra keys are allowed via `& Props`.
|