@pyreon/elements 0.16.0 → 0.18.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/lib/index.js +40 -25
- package/package.json +10 -10
- package/src/helpers/Wrapper/component.tsx +82 -29
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Provider, alignContent, extendCss, makeItResponsive, value } from "@pyreon/unistyle";
|
|
2
|
-
import { Fragment, Portal, createContext, nativeCompat, onMount, onUnmount, provide, splitProps, useContext } from "@pyreon/core";
|
|
2
|
+
import { Fragment, Portal, createContext, h, nativeCompat, onMount, onUnmount, provide, splitProps, useContext } from "@pyreon/core";
|
|
3
3
|
import { config, isEmpty, omit, pick, render, throttle } from "@pyreon/ui-core";
|
|
4
4
|
import { Fragment as Fragment$1, jsx, jsxs } from "@pyreon/core/jsx-runtime";
|
|
5
5
|
import { signal } from "@pyreon/reactivity";
|
|
@@ -331,6 +331,34 @@ const isWebFixNeeded = (tag) => {
|
|
|
331
331
|
* support `display: flex` consistently across browsers.
|
|
332
332
|
*/
|
|
333
333
|
const DEV_PROPS = IS_DEVELOPMENT ? { "data-pyr-element": "Element" } : {};
|
|
334
|
+
/**
|
|
335
|
+
* Build a props object for `h(Styled, ...)` by copying own property
|
|
336
|
+
* DESCRIPTORS from `rest`, then layering the additional fields. Compiler-
|
|
337
|
+
* emitted reactive props (`_rp(() => signal())` converted to getters by
|
|
338
|
+
* `makeReactiveProps`) survive end-to-end with their getter intact.
|
|
339
|
+
*
|
|
340
|
+
* Why we bypass JSX spread here: the standard JSX automatic-runtime
|
|
341
|
+
* compilation lowers `<Styled {...rest} foo={x}>` to roughly
|
|
342
|
+
* `jsx(Styled, { ...rest, foo: x })`. That `{...rest, foo: x}` object
|
|
343
|
+
* literal is evaluated at JS level — it fires every getter on `rest` and
|
|
344
|
+
* stores the resolved value before `jsx()` ever sees the object. No
|
|
345
|
+
* amount of in-runtime descriptor preservation can recover the getters
|
|
346
|
+
* once they've been collapsed by the surface-level spread. The fix is
|
|
347
|
+
* structural: don't use JSX spread for reactive-prop forwarding. Build
|
|
348
|
+
* the props object with descriptor preservation and pass it to `h()`
|
|
349
|
+
* directly — `h()` stores props as-is on the vnode, no copy, getters
|
|
350
|
+
* survive into mount.
|
|
351
|
+
*/
|
|
352
|
+
const buildStyledProps = (rest, refValue, asTag, extras) => {
|
|
353
|
+
const result = {};
|
|
354
|
+
const descriptors = Object.getOwnPropertyDescriptors(rest);
|
|
355
|
+
for (const key in descriptors) Object.defineProperty(result, key, descriptors[key]);
|
|
356
|
+
for (const key in DEV_PROPS) result[key] = DEV_PROPS[key];
|
|
357
|
+
result.ref = refValue;
|
|
358
|
+
result.as = asTag;
|
|
359
|
+
for (const key in extras) result[key] = extras[key];
|
|
360
|
+
return result;
|
|
361
|
+
};
|
|
334
362
|
const OWN_KEYS = [
|
|
335
363
|
"children",
|
|
336
364
|
"tag",
|
|
@@ -346,12 +374,6 @@ const OWN_KEYS = [
|
|
|
346
374
|
];
|
|
347
375
|
const Component$8 = (props) => {
|
|
348
376
|
const [own, rest] = splitProps(props, OWN_KEYS);
|
|
349
|
-
const commonProps = {
|
|
350
|
-
...rest,
|
|
351
|
-
...DEV_PROPS,
|
|
352
|
-
ref: own.ref,
|
|
353
|
-
as: own.tag
|
|
354
|
-
};
|
|
355
377
|
const needsFix = !own.dangerouslySetInnerHTML && isWebFixNeeded(own.tag);
|
|
356
378
|
const isVoidTag = !own.dangerouslySetInnerHTML && getShouldBeEmpty(own.tag);
|
|
357
379
|
const innerHTML = own.dangerouslySetInnerHTML;
|
|
@@ -364,20 +386,15 @@ const Component$8 = (props) => {
|
|
|
364
386
|
equalCols: own.equalCols,
|
|
365
387
|
extraStyles: own.extendCss
|
|
366
388
|
});
|
|
367
|
-
if (isVoidTag) return
|
|
368
|
-
|
|
369
|
-
$element: bundle
|
|
370
|
-
});
|
|
371
|
-
if (innerHTML) return /* @__PURE__ */ jsx(styled_default$1, {
|
|
372
|
-
...commonProps,
|
|
389
|
+
if (isVoidTag) return h(styled_default$1, buildStyledProps(rest, own.ref, own.tag, { $element: bundle }));
|
|
390
|
+
if (innerHTML) return h(styled_default$1, buildStyledProps(rest, own.ref, own.tag, {
|
|
373
391
|
$element: bundle,
|
|
374
392
|
dangerouslySetInnerHTML: innerHTML
|
|
375
|
-
});
|
|
376
|
-
return
|
|
377
|
-
...commonProps,
|
|
393
|
+
}));
|
|
394
|
+
return h(styled_default$1, buildStyledProps(rest, own.ref, own.tag, {
|
|
378
395
|
$element: bundle,
|
|
379
396
|
children: own.children
|
|
380
|
-
});
|
|
397
|
+
}));
|
|
381
398
|
}
|
|
382
399
|
const asTag = own.isInline ? "span" : "div";
|
|
383
400
|
const parentBundle = internElementBundle({
|
|
@@ -392,26 +409,24 @@ const Component$8 = (props) => {
|
|
|
392
409
|
alignY: own.alignY,
|
|
393
410
|
equalCols: own.equalCols
|
|
394
411
|
});
|
|
395
|
-
if (innerHTML) return
|
|
396
|
-
...commonProps,
|
|
412
|
+
if (innerHTML) return h(styled_default$1, buildStyledProps(rest, own.ref, own.tag, {
|
|
397
413
|
$element: parentBundle,
|
|
398
|
-
children:
|
|
414
|
+
children: h(styled_default$1, {
|
|
399
415
|
as: asTag,
|
|
400
416
|
$childFix: true,
|
|
401
417
|
$element: childBundle,
|
|
402
418
|
dangerouslySetInnerHTML: innerHTML
|
|
403
419
|
})
|
|
404
|
-
});
|
|
405
|
-
return
|
|
406
|
-
...commonProps,
|
|
420
|
+
}));
|
|
421
|
+
return h(styled_default$1, buildStyledProps(rest, own.ref, own.tag, {
|
|
407
422
|
$element: parentBundle,
|
|
408
|
-
children:
|
|
423
|
+
children: h(styled_default$1, {
|
|
409
424
|
as: asTag,
|
|
410
425
|
$childFix: true,
|
|
411
426
|
$element: childBundle,
|
|
412
427
|
children: own.children
|
|
413
428
|
})
|
|
414
|
-
});
|
|
429
|
+
}));
|
|
415
430
|
};
|
|
416
431
|
|
|
417
432
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Foundational UI components for Pyreon",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"typecheck": "tsc --noEmit"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@pyreon/core": "^0.
|
|
46
|
-
"@pyreon/reactivity": "^0.
|
|
47
|
-
"@pyreon/runtime-dom": "^0.
|
|
48
|
-
"@pyreon/test-utils": "^0.13.
|
|
49
|
-
"@pyreon/typescript": "^0.
|
|
45
|
+
"@pyreon/core": "^0.18.0",
|
|
46
|
+
"@pyreon/reactivity": "^0.18.0",
|
|
47
|
+
"@pyreon/runtime-dom": "^0.18.0",
|
|
48
|
+
"@pyreon/test-utils": "^0.13.5",
|
|
49
|
+
"@pyreon/typescript": "^0.18.0",
|
|
50
50
|
"@vitest/browser-playwright": "^4.1.4",
|
|
51
51
|
"@vitus-labs/tools-rolldown": "^2.3.0"
|
|
52
52
|
},
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"node": ">= 22"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@pyreon/core": "^0.
|
|
58
|
-
"@pyreon/reactivity": "^0.
|
|
59
|
-
"@pyreon/ui-core": "^0.
|
|
60
|
-
"@pyreon/unistyle": "^0.
|
|
57
|
+
"@pyreon/core": "^0.18.0",
|
|
58
|
+
"@pyreon/reactivity": "^0.18.0",
|
|
59
|
+
"@pyreon/ui-core": "^0.18.0",
|
|
60
|
+
"@pyreon/unistyle": "^0.18.0"
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* fix (parent + child Styled) because these HTML elements do not natively
|
|
5
5
|
* support `display: flex` consistently across browsers.
|
|
6
6
|
*/
|
|
7
|
-
import { splitProps } from '@pyreon/core'
|
|
7
|
+
import { h, splitProps } from '@pyreon/core'
|
|
8
8
|
import { getShouldBeEmpty } from '../../Element/utils'
|
|
9
9
|
import { IS_DEVELOPMENT } from '../../utils'
|
|
10
10
|
import { internElementBundle } from '../internElementBundle'
|
|
@@ -14,6 +14,46 @@ import { isWebFixNeeded } from './utils'
|
|
|
14
14
|
|
|
15
15
|
const DEV_PROPS: Record<string, string> = IS_DEVELOPMENT ? { 'data-pyr-element': 'Element' } : {}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Build a props object for `h(Styled, ...)` by copying own property
|
|
19
|
+
* DESCRIPTORS from `rest`, then layering the additional fields. Compiler-
|
|
20
|
+
* emitted reactive props (`_rp(() => signal())` converted to getters by
|
|
21
|
+
* `makeReactiveProps`) survive end-to-end with their getter intact.
|
|
22
|
+
*
|
|
23
|
+
* Why we bypass JSX spread here: the standard JSX automatic-runtime
|
|
24
|
+
* compilation lowers `<Styled {...rest} foo={x}>` to roughly
|
|
25
|
+
* `jsx(Styled, { ...rest, foo: x })`. That `{...rest, foo: x}` object
|
|
26
|
+
* literal is evaluated at JS level — it fires every getter on `rest` and
|
|
27
|
+
* stores the resolved value before `jsx()` ever sees the object. No
|
|
28
|
+
* amount of in-runtime descriptor preservation can recover the getters
|
|
29
|
+
* once they've been collapsed by the surface-level spread. The fix is
|
|
30
|
+
* structural: don't use JSX spread for reactive-prop forwarding. Build
|
|
31
|
+
* the props object with descriptor preservation and pass it to `h()`
|
|
32
|
+
* directly — `h()` stores props as-is on the vnode, no copy, getters
|
|
33
|
+
* survive into mount.
|
|
34
|
+
*/
|
|
35
|
+
const buildStyledProps = (
|
|
36
|
+
rest: Record<string, unknown>,
|
|
37
|
+
refValue: unknown,
|
|
38
|
+
asTag: unknown,
|
|
39
|
+
extras: Record<string, unknown>,
|
|
40
|
+
): Record<string, unknown> => {
|
|
41
|
+
const result: Record<string, unknown> = {}
|
|
42
|
+
const descriptors = Object.getOwnPropertyDescriptors(rest)
|
|
43
|
+
for (const key in descriptors) {
|
|
44
|
+
Object.defineProperty(result, key, descriptors[key]!)
|
|
45
|
+
}
|
|
46
|
+
for (const key in DEV_PROPS) {
|
|
47
|
+
result[key] = DEV_PROPS[key]
|
|
48
|
+
}
|
|
49
|
+
result.ref = refValue
|
|
50
|
+
result.as = asTag
|
|
51
|
+
for (const key in extras) {
|
|
52
|
+
result[key] = extras[key]
|
|
53
|
+
}
|
|
54
|
+
return result
|
|
55
|
+
}
|
|
56
|
+
|
|
17
57
|
// Layout / ref keys consumed by Wrapper itself. Everything else is forwarded
|
|
18
58
|
// onto the underlying DOM node. Listed as a tuple so `splitProps` narrows
|
|
19
59
|
// `own` correctly while preserving reactive prop tracking on both halves.
|
|
@@ -34,13 +74,6 @@ const OWN_KEYS: Array<keyof Props | 'ref'> = [
|
|
|
34
74
|
const Component = (props: Partial<Props> & { ref?: unknown }) => {
|
|
35
75
|
const [own, rest] = splitProps(props, OWN_KEYS)
|
|
36
76
|
|
|
37
|
-
const commonProps = {
|
|
38
|
-
...rest,
|
|
39
|
-
...DEV_PROPS,
|
|
40
|
-
ref: own.ref,
|
|
41
|
-
as: own.tag,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
77
|
const needsFix = !own.dangerouslySetInnerHTML && isWebFixNeeded(own.tag)
|
|
45
78
|
|
|
46
79
|
// Void HTML elements (hr, input, img, br, …) cannot have children. Even
|
|
@@ -69,15 +102,28 @@ const Component = (props: Partial<Props> & { ref?: unknown }) => {
|
|
|
69
102
|
extraStyles: own.extendCss,
|
|
70
103
|
})
|
|
71
104
|
if (isVoidTag) {
|
|
72
|
-
return
|
|
105
|
+
return h(
|
|
106
|
+
Styled,
|
|
107
|
+
buildStyledProps(rest as unknown as Record<string, unknown>, own.ref, own.tag, {
|
|
108
|
+
$element: bundle,
|
|
109
|
+
}),
|
|
110
|
+
)
|
|
73
111
|
}
|
|
74
112
|
if (innerHTML) {
|
|
75
|
-
return
|
|
113
|
+
return h(
|
|
114
|
+
Styled,
|
|
115
|
+
buildStyledProps(rest as unknown as Record<string, unknown>, own.ref, own.tag, {
|
|
116
|
+
$element: bundle,
|
|
117
|
+
dangerouslySetInnerHTML: innerHTML,
|
|
118
|
+
}),
|
|
119
|
+
)
|
|
76
120
|
}
|
|
77
|
-
return (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
121
|
+
return h(
|
|
122
|
+
Styled,
|
|
123
|
+
buildStyledProps(rest as unknown as Record<string, unknown>, own.ref, own.tag, {
|
|
124
|
+
$element: bundle,
|
|
125
|
+
children: own.children,
|
|
126
|
+
}),
|
|
81
127
|
)
|
|
82
128
|
}
|
|
83
129
|
|
|
@@ -103,24 +149,31 @@ const Component = (props: Partial<Props> & { ref?: unknown }) => {
|
|
|
103
149
|
// the defensive forwarding so the contract is robust against future
|
|
104
150
|
// refactors of the needsFix gate.
|
|
105
151
|
if (innerHTML) {
|
|
106
|
-
return (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
152
|
+
return h(
|
|
153
|
+
Styled,
|
|
154
|
+
buildStyledProps(rest as unknown as Record<string, unknown>, own.ref, own.tag, {
|
|
155
|
+
$element: parentBundle,
|
|
156
|
+
children: h(Styled, {
|
|
157
|
+
as: asTag,
|
|
158
|
+
$childFix: true,
|
|
159
|
+
$element: childBundle,
|
|
160
|
+
dangerouslySetInnerHTML: innerHTML,
|
|
161
|
+
}),
|
|
162
|
+
}),
|
|
115
163
|
)
|
|
116
164
|
}
|
|
117
165
|
|
|
118
|
-
return (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
166
|
+
return h(
|
|
167
|
+
Styled,
|
|
168
|
+
buildStyledProps(rest as unknown as Record<string, unknown>, own.ref, own.tag, {
|
|
169
|
+
$element: parentBundle,
|
|
170
|
+
children: h(Styled, {
|
|
171
|
+
as: asTag,
|
|
172
|
+
$childFix: true,
|
|
173
|
+
$element: childBundle,
|
|
174
|
+
children: own.children,
|
|
175
|
+
}),
|
|
176
|
+
}),
|
|
124
177
|
)
|
|
125
178
|
}
|
|
126
179
|
|