@pyreon/elements 0.14.0 → 0.16.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.d.ts +113 -56
- package/lib/index.js +200 -180
- package/package.json +14 -13
- package/src/Element/component.tsx +16 -4
- package/src/List/component.tsx +65 -15
- package/src/Overlay/component.tsx +6 -1
- package/src/Overlay/context.tsx +5 -1
- package/src/Portal/component.tsx +23 -10
- package/src/__tests__/Element.test.ts +157 -0
- package/src/__tests__/Iterator.test.ts +12 -3
- package/src/__tests__/Iterator.types.test.ts +237 -0
- package/src/__tests__/Overlay.test.ts +8 -1
- package/src/__tests__/Portal.test.ts +122 -48
- package/src/__tests__/Wrapper-innerhtml.test.tsx +178 -0
- package/src/__tests__/Wrapper.test.tsx +44 -0
- package/src/__tests__/elements.browser.test.tsx +77 -4
- package/src/__tests__/internElementBundle.test.ts +102 -0
- package/src/__tests__/native-markers.test.ts +13 -0
- package/src/__tests__/useOverlay.test.ts +7 -1
- package/src/__tests__/wrapper-block-cascade.test.ts +121 -0
- package/src/env.d.ts +6 -0
- package/src/helpers/Iterator/component.tsx +55 -4
- package/src/helpers/Iterator/index.ts +17 -1
- package/src/helpers/Iterator/types.ts +97 -38
- package/src/helpers/Wrapper/component.tsx +67 -30
- package/src/helpers/Wrapper/styled.ts +12 -18
- package/src/helpers/internElementBundle.ts +37 -0
- package/src/index.ts +4 -0
- package/src/types.ts +33 -2
- package/src/utils.ts +1 -4
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
package/lib/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Provider, alignContent, extendCss, makeItResponsive, value } from "@pyreon/unistyle";
|
|
2
|
-
import { Fragment, Portal, createContext, onMount, provide, splitProps, useContext } from "@pyreon/core";
|
|
2
|
+
import { Fragment, Portal, createContext, nativeCompat, onMount, onUnmount, provide, splitProps, useContext } from "@pyreon/core";
|
|
3
3
|
import { config, isEmpty, omit, pick, render, throttle } from "@pyreon/ui-core";
|
|
4
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "@pyreon/core/jsx-runtime";
|
|
4
5
|
import { signal } from "@pyreon/reactivity";
|
|
5
6
|
|
|
6
7
|
//#region src/constants.ts
|
|
@@ -8,7 +9,7 @@ const PKG_NAME = "@pyreon/elements";
|
|
|
8
9
|
|
|
9
10
|
//#endregion
|
|
10
11
|
//#region src/utils.ts
|
|
11
|
-
const IS_DEVELOPMENT =
|
|
12
|
+
const IS_DEVELOPMENT = process.env.NODE_ENV !== "production";
|
|
12
13
|
|
|
13
14
|
//#endregion
|
|
14
15
|
//#region src/helpers/Content/styled.ts
|
|
@@ -82,58 +83,6 @@ const StyledComponent = styled$2(component$1, { layer: "elements" })`
|
|
|
82
83
|
})};
|
|
83
84
|
`;
|
|
84
85
|
|
|
85
|
-
//#endregion
|
|
86
|
-
//#region ../../core/core/lib/jsx-runtime.js
|
|
87
|
-
/** Marker for fragment nodes — renders children without a wrapper element */
|
|
88
|
-
const Fragment$1 = Symbol("Pyreon.Fragment");
|
|
89
|
-
/**
|
|
90
|
-
* Hyperscript function — the compiled output of JSX.
|
|
91
|
-
* `<div class="x">hello</div>` → `h("div", { class: "x" }, "hello")`
|
|
92
|
-
*
|
|
93
|
-
* Generic on P so TypeScript validates props match the component's signature
|
|
94
|
-
* at the call site, then stores the result in the loosely-typed VNode.
|
|
95
|
-
*/
|
|
96
|
-
/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */
|
|
97
|
-
const EMPTY_PROPS = {};
|
|
98
|
-
function h(type, props, ...children) {
|
|
99
|
-
return {
|
|
100
|
-
type,
|
|
101
|
-
props: props ?? EMPTY_PROPS,
|
|
102
|
-
children: normalizeChildren(children),
|
|
103
|
-
key: props?.key ?? null
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function normalizeChildren(children) {
|
|
107
|
-
for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
|
|
108
|
-
return children;
|
|
109
|
-
}
|
|
110
|
-
function flattenChildren(children) {
|
|
111
|
-
const result = [];
|
|
112
|
-
for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));
|
|
113
|
-
else result.push(child);
|
|
114
|
-
return result;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* JSX automatic runtime.
|
|
118
|
-
*
|
|
119
|
-
* When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
|
|
120
|
-
* rewrites JSX to imports from this file automatically:
|
|
121
|
-
* <div class="x" /> → jsx("div", { class: "x" })
|
|
122
|
-
*/
|
|
123
|
-
function jsx(type, props, key) {
|
|
124
|
-
const { children, ...rest } = props;
|
|
125
|
-
const propsWithKey = key != null ? {
|
|
126
|
-
...rest,
|
|
127
|
-
key
|
|
128
|
-
} : rest;
|
|
129
|
-
if (typeof type === "function") return h(type, children !== void 0 ? {
|
|
130
|
-
...propsWithKey,
|
|
131
|
-
children
|
|
132
|
-
} : propsWithKey);
|
|
133
|
-
return h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);
|
|
134
|
-
}
|
|
135
|
-
const jsxs = jsx;
|
|
136
|
-
|
|
137
86
|
//#endregion
|
|
138
87
|
//#region src/helpers/Content/component.tsx
|
|
139
88
|
/**
|
|
@@ -182,6 +131,120 @@ const Component$9 = (props) => {
|
|
|
182
131
|
//#region src/helpers/Content/index.ts
|
|
183
132
|
var Content_default = Component$9;
|
|
184
133
|
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/Element/constants.ts
|
|
136
|
+
/**
|
|
137
|
+
* HTML tags that are inline-level by default. When Element renders one of
|
|
138
|
+
* these tags, child Content wrappers use `span` instead of `div` to
|
|
139
|
+
* preserve valid HTML nesting.
|
|
140
|
+
*/
|
|
141
|
+
const INLINE_ELEMENTS = {
|
|
142
|
+
span: true,
|
|
143
|
+
a: true,
|
|
144
|
+
button: true,
|
|
145
|
+
input: true,
|
|
146
|
+
label: true,
|
|
147
|
+
select: true,
|
|
148
|
+
textarea: true,
|
|
149
|
+
br: true,
|
|
150
|
+
img: true,
|
|
151
|
+
strong: true,
|
|
152
|
+
small: true,
|
|
153
|
+
code: true,
|
|
154
|
+
b: true,
|
|
155
|
+
big: true,
|
|
156
|
+
i: true,
|
|
157
|
+
tt: true,
|
|
158
|
+
abbr: true,
|
|
159
|
+
acronym: true,
|
|
160
|
+
cite: true,
|
|
161
|
+
dfn: true,
|
|
162
|
+
em: true,
|
|
163
|
+
kbd: true,
|
|
164
|
+
samp: true,
|
|
165
|
+
var: true,
|
|
166
|
+
bdo: true,
|
|
167
|
+
map: true,
|
|
168
|
+
object: true,
|
|
169
|
+
q: true,
|
|
170
|
+
script: true,
|
|
171
|
+
sub: true,
|
|
172
|
+
sup: true
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* HTML void/self-closing elements that cannot have children. When Element
|
|
176
|
+
* detects one of these tags, it skips rendering beforeContent/content/afterContent
|
|
177
|
+
* and returns the Wrapper alone.
|
|
178
|
+
*/
|
|
179
|
+
const EMPTY_ELEMENTS = {
|
|
180
|
+
area: true,
|
|
181
|
+
base: true,
|
|
182
|
+
br: true,
|
|
183
|
+
col: true,
|
|
184
|
+
embed: true,
|
|
185
|
+
hr: true,
|
|
186
|
+
img: true,
|
|
187
|
+
input: true,
|
|
188
|
+
keygen: true,
|
|
189
|
+
link: true,
|
|
190
|
+
textarea: true,
|
|
191
|
+
source: true,
|
|
192
|
+
track: true,
|
|
193
|
+
wbr: true
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region src/Element/utils.ts
|
|
198
|
+
/** Checks whether the given HTML tag is an inline-level element, used to determine sub-tag nesting. */
|
|
199
|
+
const isInlineElement = (tag) => {
|
|
200
|
+
if (tag && tag in INLINE_ELEMENTS) return true;
|
|
201
|
+
return false;
|
|
202
|
+
};
|
|
203
|
+
/** Checks whether the given HTML tag is a void element that cannot have children. */
|
|
204
|
+
const getShouldBeEmpty = (tag) => {
|
|
205
|
+
if (tag && tag in EMPTY_ELEMENTS) return true;
|
|
206
|
+
return false;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/helpers/internElementBundle.ts
|
|
211
|
+
/**
|
|
212
|
+
* Module-scope intern cache for `$element` bundles passed to Wrapper's styled
|
|
213
|
+
* component. Same primitive prop tuple → same object identity, so the styler's
|
|
214
|
+
* `elClassCache` (added 2026-Q2 alongside this) hits and skips the resolve
|
|
215
|
+
* pipeline. Analogous to `@pyreon/rocketstyle`'s dimension-prop memo (PR #344)
|
|
216
|
+
* but at the layer below — covers non-rocketstyle Element / Wrapper / Text usage
|
|
217
|
+
* AND the residual styled wrappers under any rocketstyle component.
|
|
218
|
+
*
|
|
219
|
+
* Cache key is a JSON-stringified shallow snapshot of the bundle. LRU-bound at
|
|
220
|
+
* 256 entries; oldest-first eviction. Bail (return the input as-is, no cache)
|
|
221
|
+
* when any value is a function (signal accessor) or a non-string object (CSS
|
|
222
|
+
* callback / CSSResult / nested object) — those cannot be safely round-tripped
|
|
223
|
+
* through JSON without losing identity guarantees.
|
|
224
|
+
*/
|
|
225
|
+
const _bundleCache = /* @__PURE__ */ new Map();
|
|
226
|
+
const BUNDLE_CAP = 256;
|
|
227
|
+
const internElementBundle = (bundle) => {
|
|
228
|
+
for (const k in bundle) {
|
|
229
|
+
const v = bundle[k];
|
|
230
|
+
if (typeof v === "function") return bundle;
|
|
231
|
+
if (v != null && typeof v === "object") return bundle;
|
|
232
|
+
}
|
|
233
|
+
const key = JSON.stringify(bundle);
|
|
234
|
+
const existing = _bundleCache.get(key);
|
|
235
|
+
if (existing) {
|
|
236
|
+
_bundleCache.delete(key);
|
|
237
|
+
_bundleCache.set(key, existing);
|
|
238
|
+
return existing;
|
|
239
|
+
}
|
|
240
|
+
if (_bundleCache.size >= BUNDLE_CAP) {
|
|
241
|
+
const oldest = _bundleCache.keys().next().value;
|
|
242
|
+
if (oldest !== void 0) _bundleCache.delete(oldest);
|
|
243
|
+
}
|
|
244
|
+
_bundleCache.set(key, bundle);
|
|
245
|
+
return bundle;
|
|
246
|
+
};
|
|
247
|
+
|
|
185
248
|
//#endregion
|
|
186
249
|
//#region src/helpers/Wrapper/styled.ts
|
|
187
250
|
/**
|
|
@@ -201,28 +264,25 @@ const childFixCSS = `
|
|
|
201
264
|
const parentFixCSS = `
|
|
202
265
|
flex-direction: column;
|
|
203
266
|
`;
|
|
204
|
-
const fullHeightCSS = `
|
|
205
|
-
height: 100%;
|
|
206
|
-
`;
|
|
207
|
-
const blockCSS = `
|
|
208
|
-
align-self: stretch;
|
|
209
|
-
flex: 1;
|
|
210
|
-
min-width: 0;
|
|
211
|
-
`;
|
|
212
|
-
const childFixPosition = (isBlock) => `display: ${isBlock ? "flex" : "inline-flex"};`;
|
|
213
267
|
const styles$1 = ({ theme: t, css: cssFn }) => cssFn`
|
|
214
|
-
${t.alignY === "block" && fullHeightCSS};
|
|
215
|
-
|
|
216
268
|
${alignContent({
|
|
217
269
|
direction: t.direction,
|
|
218
270
|
alignX: t.alignX,
|
|
219
271
|
alignY: t.alignY
|
|
220
272
|
})};
|
|
221
273
|
|
|
222
|
-
|
|
223
|
-
|
|
274
|
+
/*
|
|
275
|
+
* Always emit a value for the block-related properties so a responsive
|
|
276
|
+
* theme that flips from \`block: true\` at one breakpoint to \`block: false\`
|
|
277
|
+
* at another resets cleanly. Previously \`align-self\` / \`width\` / \`height\`
|
|
278
|
+
* were only set when the truthy branch matched, which left the prior
|
|
279
|
+
* breakpoint's values cascading through.
|
|
280
|
+
*/
|
|
281
|
+
${`align-self: ${t.block ? "stretch" : "auto"};
|
|
282
|
+
width: ${t.block ? "100%" : "auto"};
|
|
283
|
+
height: ${t.alignY === "block" ? "100%" : "auto"};`};
|
|
224
284
|
|
|
225
|
-
${!t.childFix &&
|
|
285
|
+
${!t.childFix && `display: ${t.block ? "flex" : "inline-flex"};`};
|
|
226
286
|
${t.parentFix && parentFixCSS};
|
|
227
287
|
|
|
228
288
|
${t.extraStyles && extendCss(t.extraStyles)};
|
|
@@ -292,36 +352,63 @@ const Component$8 = (props) => {
|
|
|
292
352
|
ref: own.ref,
|
|
293
353
|
as: own.tag
|
|
294
354
|
};
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
355
|
+
const needsFix = !own.dangerouslySetInnerHTML && isWebFixNeeded(own.tag);
|
|
356
|
+
const isVoidTag = !own.dangerouslySetInnerHTML && getShouldBeEmpty(own.tag);
|
|
357
|
+
const innerHTML = own.dangerouslySetInnerHTML;
|
|
358
|
+
if (!needsFix) {
|
|
359
|
+
const bundle = internElementBundle({
|
|
298
360
|
block: own.block,
|
|
299
361
|
direction: own.direction,
|
|
300
362
|
alignX: own.alignX,
|
|
301
363
|
alignY: own.alignY,
|
|
302
364
|
equalCols: own.equalCols,
|
|
303
365
|
extraStyles: own.extendCss
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
366
|
+
});
|
|
367
|
+
if (isVoidTag) return /* @__PURE__ */ jsx(styled_default$1, {
|
|
368
|
+
...commonProps,
|
|
369
|
+
$element: bundle
|
|
370
|
+
});
|
|
371
|
+
if (innerHTML) return /* @__PURE__ */ jsx(styled_default$1, {
|
|
372
|
+
...commonProps,
|
|
373
|
+
$element: bundle,
|
|
374
|
+
dangerouslySetInnerHTML: innerHTML
|
|
375
|
+
});
|
|
376
|
+
return /* @__PURE__ */ jsx(styled_default$1, {
|
|
377
|
+
...commonProps,
|
|
378
|
+
$element: bundle,
|
|
379
|
+
children: own.children
|
|
380
|
+
});
|
|
381
|
+
}
|
|
307
382
|
const asTag = own.isInline ? "span" : "div";
|
|
383
|
+
const parentBundle = internElementBundle({
|
|
384
|
+
parentFix: true,
|
|
385
|
+
block: own.block,
|
|
386
|
+
extraStyles: own.extendCss
|
|
387
|
+
});
|
|
388
|
+
const childBundle = internElementBundle({
|
|
389
|
+
childFix: true,
|
|
390
|
+
direction: own.direction,
|
|
391
|
+
alignX: own.alignX,
|
|
392
|
+
alignY: own.alignY,
|
|
393
|
+
equalCols: own.equalCols
|
|
394
|
+
});
|
|
395
|
+
if (innerHTML) return /* @__PURE__ */ jsx(styled_default$1, {
|
|
396
|
+
...commonProps,
|
|
397
|
+
$element: parentBundle,
|
|
398
|
+
children: /* @__PURE__ */ jsx(styled_default$1, {
|
|
399
|
+
as: asTag,
|
|
400
|
+
$childFix: true,
|
|
401
|
+
$element: childBundle,
|
|
402
|
+
dangerouslySetInnerHTML: innerHTML
|
|
403
|
+
})
|
|
404
|
+
});
|
|
308
405
|
return /* @__PURE__ */ jsx(styled_default$1, {
|
|
309
406
|
...commonProps,
|
|
310
|
-
$element:
|
|
311
|
-
parentFix: true,
|
|
312
|
-
block: own.block,
|
|
313
|
-
extraStyles: own.extendCss
|
|
314
|
-
},
|
|
407
|
+
$element: parentBundle,
|
|
315
408
|
children: /* @__PURE__ */ jsx(styled_default$1, {
|
|
316
409
|
as: asTag,
|
|
317
410
|
$childFix: true,
|
|
318
|
-
$element:
|
|
319
|
-
childFix: true,
|
|
320
|
-
direction: own.direction,
|
|
321
|
-
alignX: own.alignX,
|
|
322
|
-
alignY: own.alignY,
|
|
323
|
-
equalCols: own.equalCols
|
|
324
|
-
},
|
|
411
|
+
$element: childBundle,
|
|
325
412
|
children: own.children
|
|
326
413
|
})
|
|
327
414
|
});
|
|
@@ -331,81 +418,6 @@ const Component$8 = (props) => {
|
|
|
331
418
|
//#region src/helpers/Wrapper/index.ts
|
|
332
419
|
var Wrapper_default = Component$8;
|
|
333
420
|
|
|
334
|
-
//#endregion
|
|
335
|
-
//#region src/Element/constants.ts
|
|
336
|
-
/**
|
|
337
|
-
* HTML tags that are inline-level by default. When Element renders one of
|
|
338
|
-
* these tags, child Content wrappers use `span` instead of `div` to
|
|
339
|
-
* preserve valid HTML nesting.
|
|
340
|
-
*/
|
|
341
|
-
const INLINE_ELEMENTS = {
|
|
342
|
-
span: true,
|
|
343
|
-
a: true,
|
|
344
|
-
button: true,
|
|
345
|
-
input: true,
|
|
346
|
-
label: true,
|
|
347
|
-
select: true,
|
|
348
|
-
textarea: true,
|
|
349
|
-
br: true,
|
|
350
|
-
img: true,
|
|
351
|
-
strong: true,
|
|
352
|
-
small: true,
|
|
353
|
-
code: true,
|
|
354
|
-
b: true,
|
|
355
|
-
big: true,
|
|
356
|
-
i: true,
|
|
357
|
-
tt: true,
|
|
358
|
-
abbr: true,
|
|
359
|
-
acronym: true,
|
|
360
|
-
cite: true,
|
|
361
|
-
dfn: true,
|
|
362
|
-
em: true,
|
|
363
|
-
kbd: true,
|
|
364
|
-
samp: true,
|
|
365
|
-
var: true,
|
|
366
|
-
bdo: true,
|
|
367
|
-
map: true,
|
|
368
|
-
object: true,
|
|
369
|
-
q: true,
|
|
370
|
-
script: true,
|
|
371
|
-
sub: true,
|
|
372
|
-
sup: true
|
|
373
|
-
};
|
|
374
|
-
/**
|
|
375
|
-
* HTML void/self-closing elements that cannot have children. When Element
|
|
376
|
-
* detects one of these tags, it skips rendering beforeContent/content/afterContent
|
|
377
|
-
* and returns the Wrapper alone.
|
|
378
|
-
*/
|
|
379
|
-
const EMPTY_ELEMENTS = {
|
|
380
|
-
area: true,
|
|
381
|
-
base: true,
|
|
382
|
-
br: true,
|
|
383
|
-
col: true,
|
|
384
|
-
embed: true,
|
|
385
|
-
hr: true,
|
|
386
|
-
img: true,
|
|
387
|
-
input: true,
|
|
388
|
-
keygen: true,
|
|
389
|
-
link: true,
|
|
390
|
-
textarea: true,
|
|
391
|
-
source: true,
|
|
392
|
-
track: true,
|
|
393
|
-
wbr: true
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
//#endregion
|
|
397
|
-
//#region src/Element/utils.ts
|
|
398
|
-
/** Checks whether the given HTML tag is an inline-level element, used to determine sub-tag nesting. */
|
|
399
|
-
const isInlineElement = (tag) => {
|
|
400
|
-
if (tag && tag in INLINE_ELEMENTS) return true;
|
|
401
|
-
return false;
|
|
402
|
-
};
|
|
403
|
-
/** Checks whether the given HTML tag is a void element that cannot have children. */
|
|
404
|
-
const getShouldBeEmpty = (tag) => {
|
|
405
|
-
if (tag && tag in EMPTY_ELEMENTS) return true;
|
|
406
|
-
return false;
|
|
407
|
-
};
|
|
408
|
-
|
|
409
421
|
//#endregion
|
|
410
422
|
//#region src/Element/component.tsx
|
|
411
423
|
/**
|
|
@@ -500,7 +512,13 @@ const Component = (props) => {
|
|
|
500
512
|
else if (externalRef != null) externalRef.current = node;
|
|
501
513
|
};
|
|
502
514
|
if (own.equalBeforeAfter && own.beforeContent && own.afterContent) onMount(() => {
|
|
503
|
-
|
|
515
|
+
const node = equalizeRef;
|
|
516
|
+
if (!node) return void 0;
|
|
517
|
+
equalize(node, own.direction);
|
|
518
|
+
if (typeof ResizeObserver === "undefined") return void 0;
|
|
519
|
+
const observer = new ResizeObserver(() => equalize(node, own.direction));
|
|
520
|
+
observer.observe(node);
|
|
521
|
+
return () => observer.disconnect();
|
|
504
522
|
});
|
|
505
523
|
const WRAPPER_PROPS = {
|
|
506
524
|
ref: mergedRef,
|
|
@@ -522,14 +540,14 @@ const Component = (props) => {
|
|
|
522
540
|
...WRAPPER_DEV_PROPS,
|
|
523
541
|
ref: mergedRef,
|
|
524
542
|
as: own.tag,
|
|
525
|
-
$element: {
|
|
543
|
+
$element: internElementBundle({
|
|
526
544
|
block: own.block,
|
|
527
545
|
direction: wrapperDirection,
|
|
528
546
|
alignX: wrapperAlignX,
|
|
529
547
|
alignY: wrapperAlignY,
|
|
530
548
|
equalCols: own.equalCols,
|
|
531
549
|
extraStyles: own.css
|
|
532
|
-
},
|
|
550
|
+
}),
|
|
533
551
|
children: render(getChildren())
|
|
534
552
|
});
|
|
535
553
|
if (isSimpleElement) return /* @__PURE__ */ jsx(Wrapper_default, {
|
|
@@ -731,34 +749,28 @@ const Component$7 = (props) => {
|
|
|
731
749
|
};
|
|
732
750
|
return renderItems();
|
|
733
751
|
};
|
|
734
|
-
|
|
752
|
+
const Iterator = Object.assign(Component$7, {
|
|
735
753
|
isIterator: true,
|
|
736
754
|
RESERVED_PROPS
|
|
737
755
|
});
|
|
738
756
|
|
|
739
757
|
//#endregion
|
|
740
758
|
//#region src/helpers/Iterator/index.ts
|
|
741
|
-
var Iterator_default =
|
|
759
|
+
var Iterator_default = Iterator;
|
|
742
760
|
|
|
743
761
|
//#endregion
|
|
744
762
|
//#region src/List/component.tsx
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
* optional Element root wrapper. When `rootElement` is false (default),
|
|
748
|
-
* it renders a bare Iterator as a fragment. When true, the Iterator output
|
|
749
|
-
* is wrapped in an Element that receives all non-iterator props (e.g.,
|
|
750
|
-
* layout, alignment, css), allowing the list to be styled as a single block.
|
|
751
|
-
*/
|
|
752
|
-
const Component$1 = ((allProps) => {
|
|
763
|
+
const LooseIterator = Iterator_default;
|
|
764
|
+
const Component$1 = (allProps) => {
|
|
753
765
|
const [own, props] = splitProps(allProps, ["rootElement", "ref"]);
|
|
754
|
-
const renderedList = /* @__PURE__ */ jsx(
|
|
766
|
+
const renderedList = /* @__PURE__ */ jsx(LooseIterator, { ...pick(props, Iterator_default.RESERVED_PROPS) });
|
|
755
767
|
if (!own.rootElement) return renderedList;
|
|
756
768
|
return /* @__PURE__ */ jsx(Component, {
|
|
757
|
-
|
|
769
|
+
ref: own.ref,
|
|
758
770
|
...omit(props, Iterator_default.RESERVED_PROPS),
|
|
759
771
|
children: renderedList
|
|
760
772
|
});
|
|
761
|
-
}
|
|
773
|
+
};
|
|
762
774
|
const name$4 = `${PKG_NAME}/List`;
|
|
763
775
|
Component$1.displayName = name$4;
|
|
764
776
|
Component$1.pkgName = PKG_NAME;
|
|
@@ -776,6 +788,7 @@ const Component$3 = (props) => {
|
|
|
776
788
|
});
|
|
777
789
|
return /* @__PURE__ */ jsx(Fragment$1, { children: props.children });
|
|
778
790
|
};
|
|
791
|
+
nativeCompat(Component$3);
|
|
779
792
|
|
|
780
793
|
//#endregion
|
|
781
794
|
//#region src/Overlay/positioning.ts
|
|
@@ -1232,14 +1245,21 @@ const name$3 = `${PKG_NAME}/Overlay`;
|
|
|
1232
1245
|
Component$2.displayName = name$3;
|
|
1233
1246
|
Component$2.pkgName = PKG_NAME;
|
|
1234
1247
|
Component$2.PYREON__COMPONENT = name$3;
|
|
1248
|
+
nativeCompat(Component$2);
|
|
1235
1249
|
|
|
1236
1250
|
//#endregion
|
|
1237
1251
|
//#region src/Portal/component.tsx
|
|
1238
1252
|
const Component$4 = (props) => {
|
|
1239
|
-
|
|
1240
|
-
|
|
1253
|
+
if (typeof document === "undefined") return null;
|
|
1254
|
+
const tag = props.tag ?? "div";
|
|
1255
|
+
const target = props.DOMLocation ?? document.body;
|
|
1256
|
+
const wrapper = document.createElement(tag);
|
|
1257
|
+
target.appendChild(wrapper);
|
|
1258
|
+
onUnmount(() => {
|
|
1259
|
+
wrapper.remove();
|
|
1260
|
+
});
|
|
1241
1261
|
return /* @__PURE__ */ jsx(Portal, {
|
|
1242
|
-
target,
|
|
1262
|
+
target: wrapper,
|
|
1243
1263
|
children: props.children
|
|
1244
1264
|
});
|
|
1245
1265
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Foundational UI components for Pyreon",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"lib",
|
|
13
|
+
"!lib/**/*.map",
|
|
13
14
|
"!lib/analysis",
|
|
14
15
|
"README.md",
|
|
15
16
|
"LICENSE",
|
|
@@ -41,21 +42,21 @@
|
|
|
41
42
|
"typecheck": "tsc --noEmit"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
|
-
"@pyreon/core": "^0.
|
|
45
|
-
"@pyreon/reactivity": "^0.
|
|
46
|
-
"@pyreon/runtime-dom": "^0.
|
|
47
|
-
"@pyreon/test-utils": "^0.13.
|
|
48
|
-
"@pyreon/typescript": "^0.
|
|
45
|
+
"@pyreon/core": "^0.16.0",
|
|
46
|
+
"@pyreon/reactivity": "^0.16.0",
|
|
47
|
+
"@pyreon/runtime-dom": "^0.16.0",
|
|
48
|
+
"@pyreon/test-utils": "^0.13.3",
|
|
49
|
+
"@pyreon/typescript": "^0.16.0",
|
|
49
50
|
"@vitest/browser-playwright": "^4.1.4",
|
|
50
|
-
"@vitus-labs/tools-rolldown": "^
|
|
51
|
-
},
|
|
52
|
-
"peerDependencies": {
|
|
53
|
-
"@pyreon/core": "^0.14.0",
|
|
54
|
-
"@pyreon/reactivity": "^0.14.0",
|
|
55
|
-
"@pyreon/ui-core": "^0.14.0",
|
|
56
|
-
"@pyreon/unistyle": "^0.14.0"
|
|
51
|
+
"@vitus-labs/tools-rolldown": "^2.3.0"
|
|
57
52
|
},
|
|
58
53
|
"engines": {
|
|
59
54
|
"node": ">= 22"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@pyreon/core": "^0.16.0",
|
|
58
|
+
"@pyreon/reactivity": "^0.16.0",
|
|
59
|
+
"@pyreon/ui-core": "^0.16.0",
|
|
60
|
+
"@pyreon/unistyle": "^0.16.0"
|
|
60
61
|
}
|
|
61
62
|
}
|
|
@@ -11,6 +11,7 @@ import { onMount, splitProps } from '@pyreon/core'
|
|
|
11
11
|
import { render } from '@pyreon/ui-core'
|
|
12
12
|
import { PKG_NAME } from '../constants'
|
|
13
13
|
import { Content, Wrapper } from '../helpers'
|
|
14
|
+
import { internElementBundle } from '../helpers/internElementBundle'
|
|
14
15
|
import WrapperStyled from '../helpers/Wrapper/styled'
|
|
15
16
|
import { isWebFixNeeded } from '../helpers/Wrapper/utils'
|
|
16
17
|
import { IS_DEVELOPMENT } from '../utils'
|
|
@@ -136,9 +137,20 @@ const Component: PyreonElement = (props) => {
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
if (own.equalBeforeAfter && own.beforeContent && own.afterContent) {
|
|
140
|
+
// Run once on mount AND continue equalizing as the element resizes —
|
|
141
|
+
// catches async slot content (font swaps, lazy text, viewport resize)
|
|
142
|
+
// that a one-shot measurement would miss. Mirrors vitus-labs's Element
|
|
143
|
+
// useLayoutEffect + ResizeObserver pattern.
|
|
139
144
|
onMount(() => {
|
|
140
|
-
|
|
141
|
-
return undefined
|
|
145
|
+
const node = equalizeRef
|
|
146
|
+
if (!node) return undefined
|
|
147
|
+
|
|
148
|
+
equalize(node, own.direction)
|
|
149
|
+
|
|
150
|
+
if (typeof ResizeObserver === 'undefined') return undefined
|
|
151
|
+
const observer = new ResizeObserver(() => equalize(node, own.direction))
|
|
152
|
+
observer.observe(node)
|
|
153
|
+
return () => observer.disconnect()
|
|
142
154
|
})
|
|
143
155
|
}
|
|
144
156
|
|
|
@@ -180,14 +192,14 @@ const Component: PyreonElement = (props) => {
|
|
|
180
192
|
{...WRAPPER_DEV_PROPS}
|
|
181
193
|
ref={mergedRef}
|
|
182
194
|
as={own.tag}
|
|
183
|
-
$element={{
|
|
195
|
+
$element={internElementBundle({
|
|
184
196
|
block: own.block,
|
|
185
197
|
direction: wrapperDirection,
|
|
186
198
|
alignX: wrapperAlignX,
|
|
187
199
|
alignY: wrapperAlignY,
|
|
188
200
|
equalCols: own.equalCols,
|
|
189
201
|
extraStyles: own.css,
|
|
190
|
-
}}
|
|
202
|
+
})}
|
|
191
203
|
>
|
|
192
204
|
{render(getChildren())}
|
|
193
205
|
</WrapperStyled>
|