@pyreon/elements 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/lib/index.d.ts +8 -8
- package/lib/index.js +172 -148
- package/package.json +12 -11
- package/src/Element/component.tsx +59 -16
- package/src/Overlay/component.tsx +6 -1
- package/src/Overlay/context.tsx +5 -1
- package/src/__tests__/Element.test.ts +95 -46
- package/src/__tests__/Overlay.test.ts +8 -1
- package/src/__tests__/Wrapper.test.tsx +44 -0
- package/src/__tests__/elements.browser.test.tsx +30 -4
- package/src/__tests__/equalBeforeAfter.test.ts +4 -4
- package/src/__tests__/integration.test.tsx +36 -5
- package/src/__tests__/internElementBundle.test.ts +102 -0
- package/src/__tests__/native-markers.test.ts +13 -0
- package/src/__tests__/perf-stress.browser.test.tsx +119 -0
- package/src/__tests__/responsiveProps.test.ts +59 -28
- package/src/__tests__/useOverlay.test.ts +7 -1
- package/src/env.d.ts +6 -0
- package/src/helpers/Wrapper/component.tsx +35 -30
- package/src/helpers/internElementBundle.ts +37 -0
- package/src/utils.ts +1 -4
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Provider } from "@pyreon/unistyle";
|
|
2
|
-
import * as _pyreon_core0 from "@pyreon/core";
|
|
2
|
+
import * as _$_pyreon_core0 from "@pyreon/core";
|
|
3
3
|
import { ComponentFn, PyreonHTMLAttributes, VNodeChild } from "@pyreon/core";
|
|
4
4
|
import { BreakpointKeys, HTMLTags, HTMLTextTags, config, render } from "@pyreon/ui-core";
|
|
5
|
-
import * as _pyreon_reactivity0 from "@pyreon/reactivity";
|
|
5
|
+
import * as _$_pyreon_reactivity0 from "@pyreon/reactivity";
|
|
6
6
|
|
|
7
7
|
//#region src/types.d.ts
|
|
8
8
|
type ExtractNullableKeys<T> = { [P in keyof T as T[P] extends null | undefined ? never : P]: T[P] };
|
|
@@ -256,7 +256,7 @@ interface OverlayContext {
|
|
|
256
256
|
}
|
|
257
257
|
declare const Component$3: (props: OverlayContext & {
|
|
258
258
|
children: VNodeChild;
|
|
259
|
-
}) => _pyreon_core0.VNode;
|
|
259
|
+
}) => _$_pyreon_core0.VNode;
|
|
260
260
|
//#endregion
|
|
261
261
|
//#region src/Overlay/positioning.d.ts
|
|
262
262
|
type Align$1 = 'bottom' | 'top' | 'left' | 'right';
|
|
@@ -304,10 +304,10 @@ declare const useOverlay: ({
|
|
|
304
304
|
}?: Partial<UseOverlayProps>) => {
|
|
305
305
|
triggerRef: (node: HTMLElement | null) => void;
|
|
306
306
|
contentRef: (node: HTMLElement | null) => void;
|
|
307
|
-
active: _pyreon_reactivity0.Signal<boolean>;
|
|
307
|
+
active: _$_pyreon_reactivity0.Signal<boolean>;
|
|
308
308
|
align: Align$1;
|
|
309
|
-
alignX: _pyreon_reactivity0.Signal<AlignX$2>;
|
|
310
|
-
alignY: _pyreon_reactivity0.Signal<AlignY$2>;
|
|
309
|
+
alignX: _$_pyreon_reactivity0.Signal<AlignX$2>;
|
|
310
|
+
alignY: _$_pyreon_reactivity0.Signal<AlignY$2>;
|
|
311
311
|
showContent: () => void;
|
|
312
312
|
hideContent: () => void;
|
|
313
313
|
blocked: () => boolean;
|
|
@@ -315,8 +315,8 @@ declare const useOverlay: ({
|
|
|
315
315
|
setUnblocked: () => void;
|
|
316
316
|
setupListeners: () => () => void;
|
|
317
317
|
Provider: (props: OverlayContext & {
|
|
318
|
-
children: _pyreon_core0.VNodeChild;
|
|
319
|
-
}) => _pyreon_core0.VNode;
|
|
318
|
+
children: _$_pyreon_core0.VNodeChild;
|
|
319
|
+
}) => _$_pyreon_core0.VNode;
|
|
320
320
|
};
|
|
321
321
|
//#endregion
|
|
322
322
|
//#region src/Overlay/component.d.ts
|
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, 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
|
/**
|
|
@@ -292,36 +355,47 @@ const Component$8 = (props) => {
|
|
|
292
355
|
ref: own.ref,
|
|
293
356
|
as: own.tag
|
|
294
357
|
};
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
358
|
+
const needsFix = !own.dangerouslySetInnerHTML && isWebFixNeeded(own.tag);
|
|
359
|
+
const isVoidTag = !own.dangerouslySetInnerHTML && getShouldBeEmpty(own.tag);
|
|
360
|
+
if (!needsFix) {
|
|
361
|
+
const bundle = internElementBundle({
|
|
298
362
|
block: own.block,
|
|
299
363
|
direction: own.direction,
|
|
300
364
|
alignX: own.alignX,
|
|
301
365
|
alignY: own.alignY,
|
|
302
366
|
equalCols: own.equalCols,
|
|
303
367
|
extraStyles: own.extendCss
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
368
|
+
});
|
|
369
|
+
if (isVoidTag) return /* @__PURE__ */ jsx(styled_default$1, {
|
|
370
|
+
...commonProps,
|
|
371
|
+
$element: bundle
|
|
372
|
+
});
|
|
373
|
+
return /* @__PURE__ */ jsx(styled_default$1, {
|
|
374
|
+
...commonProps,
|
|
375
|
+
$element: bundle,
|
|
376
|
+
children: own.children
|
|
377
|
+
});
|
|
378
|
+
}
|
|
307
379
|
const asTag = own.isInline ? "span" : "div";
|
|
380
|
+
const parentBundle = internElementBundle({
|
|
381
|
+
parentFix: true,
|
|
382
|
+
block: own.block,
|
|
383
|
+
extraStyles: own.extendCss
|
|
384
|
+
});
|
|
385
|
+
const childBundle = internElementBundle({
|
|
386
|
+
childFix: true,
|
|
387
|
+
direction: own.direction,
|
|
388
|
+
alignX: own.alignX,
|
|
389
|
+
alignY: own.alignY,
|
|
390
|
+
equalCols: own.equalCols
|
|
391
|
+
});
|
|
308
392
|
return /* @__PURE__ */ jsx(styled_default$1, {
|
|
309
393
|
...commonProps,
|
|
310
|
-
$element:
|
|
311
|
-
parentFix: true,
|
|
312
|
-
block: own.block,
|
|
313
|
-
extraStyles: own.extendCss
|
|
314
|
-
},
|
|
394
|
+
$element: parentBundle,
|
|
315
395
|
children: /* @__PURE__ */ jsx(styled_default$1, {
|
|
316
396
|
as: asTag,
|
|
317
397
|
$childFix: true,
|
|
318
|
-
$element:
|
|
319
|
-
childFix: true,
|
|
320
|
-
direction: own.direction,
|
|
321
|
-
alignX: own.alignX,
|
|
322
|
-
alignY: own.alignY,
|
|
323
|
-
equalCols: own.equalCols
|
|
324
|
-
},
|
|
398
|
+
$element: childBundle,
|
|
325
399
|
children: own.children
|
|
326
400
|
})
|
|
327
401
|
});
|
|
@@ -331,81 +405,6 @@ const Component$8 = (props) => {
|
|
|
331
405
|
//#region src/helpers/Wrapper/index.ts
|
|
332
406
|
var Wrapper_default = Component$8;
|
|
333
407
|
|
|
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
408
|
//#endregion
|
|
410
409
|
//#region src/Element/component.tsx
|
|
411
410
|
/**
|
|
@@ -416,6 +415,7 @@ const getShouldBeEmpty = (tag) => {
|
|
|
416
415
|
* like void elements (input, img) and inline elements (span, a) by
|
|
417
416
|
* skipping children or switching sub-tags accordingly.
|
|
418
417
|
*/
|
|
418
|
+
const WRAPPER_DEV_PROPS = IS_DEVELOPMENT ? { "data-pyr-element": "Element" } : {};
|
|
419
419
|
const equalize = (el, direction) => {
|
|
420
420
|
const beforeEl = el.firstElementChild;
|
|
421
421
|
const afterEl = el.lastElementChild;
|
|
@@ -515,6 +515,28 @@ const Component = (props) => {
|
|
|
515
515
|
...rest,
|
|
516
516
|
...WRAPPER_PROPS
|
|
517
517
|
});
|
|
518
|
+
const needsFix = !rest.dangerouslySetInnerHTML && isWebFixNeeded(own.tag);
|
|
519
|
+
if (isSimpleElement && !needsFix) return /* @__PURE__ */ jsx(styled_default$1, {
|
|
520
|
+
...rest,
|
|
521
|
+
...WRAPPER_DEV_PROPS,
|
|
522
|
+
ref: mergedRef,
|
|
523
|
+
as: own.tag,
|
|
524
|
+
$element: internElementBundle({
|
|
525
|
+
block: own.block,
|
|
526
|
+
direction: wrapperDirection,
|
|
527
|
+
alignX: wrapperAlignX,
|
|
528
|
+
alignY: wrapperAlignY,
|
|
529
|
+
equalCols: own.equalCols,
|
|
530
|
+
extraStyles: own.css
|
|
531
|
+
}),
|
|
532
|
+
children: render(getChildren())
|
|
533
|
+
});
|
|
534
|
+
if (isSimpleElement) return /* @__PURE__ */ jsx(Wrapper_default, {
|
|
535
|
+
...rest,
|
|
536
|
+
...WRAPPER_PROPS,
|
|
537
|
+
isInline,
|
|
538
|
+
children: render(getChildren())
|
|
539
|
+
});
|
|
518
540
|
return /* @__PURE__ */ jsxs(Wrapper_default, {
|
|
519
541
|
...rest,
|
|
520
542
|
...WRAPPER_PROPS,
|
|
@@ -532,7 +554,7 @@ const Component = (props) => {
|
|
|
532
554
|
gap: own.gap,
|
|
533
555
|
children: own.beforeContent
|
|
534
556
|
}),
|
|
535
|
-
|
|
557
|
+
/* @__PURE__ */ jsx(Content_default, {
|
|
536
558
|
tag: SUB_TAG,
|
|
537
559
|
contentType: "content",
|
|
538
560
|
parentDirection: wrapperDirection,
|
|
@@ -753,6 +775,7 @@ const Component$3 = (props) => {
|
|
|
753
775
|
});
|
|
754
776
|
return /* @__PURE__ */ jsx(Fragment$1, { children: props.children });
|
|
755
777
|
};
|
|
778
|
+
nativeCompat(Component$3);
|
|
756
779
|
|
|
757
780
|
//#endregion
|
|
758
781
|
//#region src/Overlay/positioning.ts
|
|
@@ -1209,6 +1232,7 @@ const name$3 = `${PKG_NAME}/Overlay`;
|
|
|
1209
1232
|
Component$2.displayName = name$3;
|
|
1210
1233
|
Component$2.pkgName = PKG_NAME;
|
|
1211
1234
|
Component$2.PYREON__COMPONENT = name$3;
|
|
1235
|
+
nativeCompat(Component$2);
|
|
1212
1236
|
|
|
1213
1237
|
//#endregion
|
|
1214
1238
|
//#region src/Portal/component.tsx
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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,19 +42,19 @@
|
|
|
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.15.0",
|
|
46
|
+
"@pyreon/reactivity": "^0.15.0",
|
|
47
|
+
"@pyreon/runtime-dom": "^0.15.0",
|
|
48
|
+
"@pyreon/test-utils": "^0.13.2",
|
|
49
|
+
"@pyreon/typescript": "^0.15.0",
|
|
49
50
|
"@vitest/browser-playwright": "^4.1.4",
|
|
50
|
-
"@vitus-labs/tools-rolldown": "^
|
|
51
|
+
"@vitus-labs/tools-rolldown": "^2.3.0"
|
|
51
52
|
},
|
|
52
53
|
"peerDependencies": {
|
|
53
|
-
"@pyreon/core": "^0.
|
|
54
|
-
"@pyreon/reactivity": "^0.
|
|
55
|
-
"@pyreon/ui-core": "^0.
|
|
56
|
-
"@pyreon/unistyle": "^0.
|
|
54
|
+
"@pyreon/core": "^0.15.0",
|
|
55
|
+
"@pyreon/reactivity": "^0.15.0",
|
|
56
|
+
"@pyreon/ui-core": "^0.15.0",
|
|
57
|
+
"@pyreon/unistyle": "^0.15.0"
|
|
57
58
|
},
|
|
58
59
|
"engines": {
|
|
59
60
|
"node": ">= 22"
|
|
@@ -11,9 +11,17 @@ 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'
|
|
15
|
+
import WrapperStyled from '../helpers/Wrapper/styled'
|
|
16
|
+
import { isWebFixNeeded } from '../helpers/Wrapper/utils'
|
|
17
|
+
import { IS_DEVELOPMENT } from '../utils'
|
|
14
18
|
import type { PyreonElement } from './types'
|
|
15
19
|
import { getShouldBeEmpty, isInlineElement } from './utils'
|
|
16
20
|
|
|
21
|
+
const WRAPPER_DEV_PROPS: Record<string, string> = IS_DEVELOPMENT
|
|
22
|
+
? { 'data-pyr-element': 'Element' }
|
|
23
|
+
: {}
|
|
24
|
+
|
|
17
25
|
const equalize = (el: HTMLElement, direction: unknown) => {
|
|
18
26
|
const beforeEl = el.firstElementChild as HTMLElement | null
|
|
19
27
|
const afterEl = el.lastElementChild as HTMLElement | null
|
|
@@ -156,6 +164,45 @@ const Component: PyreonElement = (props) => {
|
|
|
156
164
|
return <Wrapper {...rest} {...WRAPPER_PROPS} />
|
|
157
165
|
}
|
|
158
166
|
|
|
167
|
+
// Simple-Element fast path: no beforeContent / afterContent slots, and no
|
|
168
|
+
// button/fieldset/legend two-layer flex fix needed. Inline the Wrapper
|
|
169
|
+
// helper directly into a single Styled invocation — saves one component
|
|
170
|
+
// hop, one splitProps call, and one mountChild per Element. The Wrapper
|
|
171
|
+
// helper still exists for the rare needsFix case below; tests that asserted
|
|
172
|
+
// Wrapper appears in the VNode tree are updated to the new shape.
|
|
173
|
+
const dangerouslySetInnerHTML = (rest as { dangerouslySetInnerHTML?: unknown })
|
|
174
|
+
.dangerouslySetInnerHTML
|
|
175
|
+
const needsFix = !dangerouslySetInnerHTML && isWebFixNeeded(own.tag)
|
|
176
|
+
|
|
177
|
+
if (isSimpleElement && !needsFix) {
|
|
178
|
+
return (
|
|
179
|
+
<WrapperStyled
|
|
180
|
+
{...rest}
|
|
181
|
+
{...WRAPPER_DEV_PROPS}
|
|
182
|
+
ref={mergedRef}
|
|
183
|
+
as={own.tag}
|
|
184
|
+
$element={internElementBundle({
|
|
185
|
+
block: own.block,
|
|
186
|
+
direction: wrapperDirection,
|
|
187
|
+
alignX: wrapperAlignX,
|
|
188
|
+
alignY: wrapperAlignY,
|
|
189
|
+
equalCols: own.equalCols,
|
|
190
|
+
extraStyles: own.css,
|
|
191
|
+
})}
|
|
192
|
+
>
|
|
193
|
+
{render(getChildren())}
|
|
194
|
+
</WrapperStyled>
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (isSimpleElement) {
|
|
199
|
+
return (
|
|
200
|
+
<Wrapper {...rest} {...WRAPPER_PROPS} isInline={isInline}>
|
|
201
|
+
{render(getChildren())}
|
|
202
|
+
</Wrapper>
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
|
|
159
206
|
return (
|
|
160
207
|
<Wrapper {...rest} {...WRAPPER_PROPS} isInline={isInline}>
|
|
161
208
|
{own.beforeContent && (
|
|
@@ -174,22 +221,18 @@ const Component: PyreonElement = (props) => {
|
|
|
174
221
|
</Content>
|
|
175
222
|
)}
|
|
176
223
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
>
|
|
190
|
-
{getChildren()}
|
|
191
|
-
</Content>
|
|
192
|
-
)}
|
|
224
|
+
<Content
|
|
225
|
+
tag={SUB_TAG}
|
|
226
|
+
contentType="content"
|
|
227
|
+
parentDirection={wrapperDirection}
|
|
228
|
+
extendCss={own.contentCss}
|
|
229
|
+
direction={contentDirection}
|
|
230
|
+
alignX={contentAlignX}
|
|
231
|
+
alignY={contentAlignY}
|
|
232
|
+
equalCols={own.equalCols}
|
|
233
|
+
>
|
|
234
|
+
{getChildren()}
|
|
235
|
+
</Content>
|
|
193
236
|
|
|
194
237
|
{own.afterContent && (
|
|
195
238
|
<Content
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { VNodeChild } from '@pyreon/core'
|
|
10
|
-
import { onMount, Portal, splitProps } from '@pyreon/core'
|
|
10
|
+
import { nativeCompat, onMount, Portal, splitProps } from '@pyreon/core'
|
|
11
11
|
import { render } from '@pyreon/ui-core'
|
|
12
12
|
import { PKG_NAME } from '../constants'
|
|
13
13
|
import type { Content, PyreonComponent } from '../types'
|
|
@@ -132,4 +132,9 @@ Component.displayName = name
|
|
|
132
132
|
Component.pkgName = PKG_NAME
|
|
133
133
|
Component.PYREON__COMPONENT = name
|
|
134
134
|
|
|
135
|
+
// Mark as native — compat-mode jsx() runtimes skip wrapCompatComponent so
|
|
136
|
+
// Overlay's onMount + Portal + useOverlay hook setup run inside Pyreon's
|
|
137
|
+
// setup frame.
|
|
138
|
+
nativeCompat(Component)
|
|
139
|
+
|
|
135
140
|
export default Component
|
package/src/Overlay/context.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { VNodeChild } from '@pyreon/core'
|
|
8
|
-
import { createContext, provide, useContext } from '@pyreon/core'
|
|
8
|
+
import { createContext, nativeCompat, provide, useContext } from '@pyreon/core'
|
|
9
9
|
|
|
10
10
|
export interface OverlayContext {
|
|
11
11
|
blocked: boolean | (() => boolean)
|
|
@@ -29,4 +29,8 @@ const Component = (props: OverlayContext & { children: VNodeChild }) => {
|
|
|
29
29
|
return <>{props.children}</>
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// Mark as native — invoked by Overlay internally; needs Pyreon's setup
|
|
33
|
+
// frame for provide(context, ...) to reach descendant overlays.
|
|
34
|
+
nativeCompat(Component)
|
|
35
|
+
|
|
32
36
|
export default Component
|