@pyreon/elements 0.14.0 → 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 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 = import.meta.env?.DEV === true;
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
- if (!(!own.dangerouslySetInnerHTML && isWebFixNeeded(own.tag))) return /* @__PURE__ */ jsx(styled_default$1, {
296
- ...commonProps,
297
- $element: {
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
- children: own.children
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
  /**
@@ -522,14 +521,14 @@ const Component = (props) => {
522
521
  ...WRAPPER_DEV_PROPS,
523
522
  ref: mergedRef,
524
523
  as: own.tag,
525
- $element: {
524
+ $element: internElementBundle({
526
525
  block: own.block,
527
526
  direction: wrapperDirection,
528
527
  alignX: wrapperAlignX,
529
528
  alignY: wrapperAlignY,
530
529
  equalCols: own.equalCols,
531
530
  extraStyles: own.css
532
- },
531
+ }),
533
532
  children: render(getChildren())
534
533
  });
535
534
  if (isSimpleElement) return /* @__PURE__ */ jsx(Wrapper_default, {
@@ -776,6 +775,7 @@ const Component$3 = (props) => {
776
775
  });
777
776
  return /* @__PURE__ */ jsx(Fragment$1, { children: props.children });
778
777
  };
778
+ nativeCompat(Component$3);
779
779
 
780
780
  //#endregion
781
781
  //#region src/Overlay/positioning.ts
@@ -1232,6 +1232,7 @@ const name$3 = `${PKG_NAME}/Overlay`;
1232
1232
  Component$2.displayName = name$3;
1233
1233
  Component$2.pkgName = PKG_NAME;
1234
1234
  Component$2.PYREON__COMPONENT = name$3;
1235
+ nativeCompat(Component$2);
1235
1236
 
1236
1237
  //#endregion
1237
1238
  //#region src/Portal/component.tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/elements",
3
- "version": "0.14.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.14.0",
45
- "@pyreon/reactivity": "^0.14.0",
46
- "@pyreon/runtime-dom": "^0.14.0",
45
+ "@pyreon/core": "^0.15.0",
46
+ "@pyreon/reactivity": "^0.15.0",
47
+ "@pyreon/runtime-dom": "^0.15.0",
47
48
  "@pyreon/test-utils": "^0.13.2",
48
- "@pyreon/typescript": "^0.14.0",
49
+ "@pyreon/typescript": "^0.15.0",
49
50
  "@vitest/browser-playwright": "^4.1.4",
50
- "@vitus-labs/tools-rolldown": "^1.15.3"
51
+ "@vitus-labs/tools-rolldown": "^2.3.0"
51
52
  },
52
53
  "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"
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,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'
@@ -180,14 +181,14 @@ const Component: PyreonElement = (props) => {
180
181
  {...WRAPPER_DEV_PROPS}
181
182
  ref={mergedRef}
182
183
  as={own.tag}
183
- $element={{
184
+ $element={internElementBundle({
184
185
  block: own.block,
185
186
  direction: wrapperDirection,
186
187
  alignX: wrapperAlignX,
187
188
  alignY: wrapperAlignY,
188
189
  equalCols: own.equalCols,
189
190
  extraStyles: own.css,
190
- }}
191
+ })}
191
192
  >
192
193
  {render(getChildren())}
193
194
  </WrapperStyled>
@@ -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
@@ -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
@@ -37,7 +37,14 @@ vi.mock('@pyreon/reactivity', () => {
37
37
  return s
38
38
  }
39
39
 
40
- return { signal }
40
+ // No-op: `@pyreon/core/context.ts` calls `setSnapshotCapture(...)` at
41
+ // module load to install the reactive-effect context-snapshot DI hook.
42
+ // Mocked tests don't drive real reactive scoping, so accept the call
43
+ // and discard. Required since `@pyreon/core` imports `setSnapshotCapture`
44
+ // from `@pyreon/reactivity` — without this stub the mock factory throws
45
+ // "No 'setSnapshotCapture' export is defined on the '@pyreon/reactivity' mock."
46
+ const setSnapshotCapture = () => {}
47
+ return { signal, setSnapshotCapture }
41
48
  })
42
49
 
43
50
  // onMount / onUnmount are no-ops outside a renderer
@@ -149,4 +149,48 @@ describe('Wrapper component', () => {
149
149
  expect((result.props.$element as any).parentFix).toBeUndefined()
150
150
  })
151
151
  })
152
+
153
+ // Void HTML elements (hr, input, img, br, …) cannot have children. Element
154
+ // already skips passing children to Wrapper for void tags, but the JSX
155
+ // `{own.children}` slot still serialized `undefined` into the vnode and
156
+ // tripped runtime-dom's void-element warning. Wrapper now drops the slot
157
+ // entirely for void tags.
158
+ describe('void HTML elements drop the children slot', () => {
159
+ const VOID_TAGS = ['hr', 'input', 'img', 'br', 'area', 'base', 'col', 'embed', 'link', 'source', 'track', 'wbr'] as const
160
+
161
+ for (const tag of VOID_TAGS) {
162
+ it(`omits children for <${tag}>`, () => {
163
+ // Cast to any — the Wrapper Props.tag type narrows out void
164
+ // elements, but the runtime guard still has to cover the case
165
+ // where a void tag reaches Wrapper (e.g. via rocketstyle attrs
166
+ // composing `tag: 'hr'` from a callback whose return type is wider).
167
+ const result = asVNode(Wrapper({ tag } as any))
168
+ expect(result.type).toBe(Styled)
169
+ expect(result.props.children).toBeUndefined()
170
+ expect(result.children).toEqual([])
171
+ })
172
+ }
173
+
174
+ it('still renders children for non-void tags', () => {
175
+ const result = asVNode(Wrapper({ tag: 'div', children: 'kept' }))
176
+ expect(result.props.children).toBe('kept')
177
+ })
178
+
179
+ it('omits children even when caller accidentally passes them to a void tag', () => {
180
+ const result = asVNode(Wrapper({ tag: 'hr', children: 'should-not-leak' }))
181
+ expect(result.props.children).toBeUndefined()
182
+ })
183
+
184
+ it('dangerouslySetInnerHTML on a normally-void tag bypasses the void path', () => {
185
+ const result = asVNode(
186
+ Wrapper({
187
+ tag: 'hr',
188
+ dangerouslySetInnerHTML: { __html: '<b>x</b>' },
189
+ } as any),
190
+ )
191
+ // dangerouslySetInnerHTML opts out of the void-element guard
192
+ // because the tag becomes a custom element / shadow host case.
193
+ expect(result.type).toBe(Styled)
194
+ })
195
+ })
152
196
  })
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource @pyreon/core */
2
- import { describe, expect, it } from 'vitest'
2
+ import { describe, expect, it, vi } from 'vitest'
3
3
  import { signal } from '@pyreon/reactivity'
4
4
  import { flush, mountInBrowser } from '@pyreon/test-utils/browser'
5
5
  import { Element } from '../Element'
@@ -52,8 +52,34 @@ describe('@pyreon/elements browser smoke', () => {
52
52
  expect(document.querySelector('[data-portal-id="p"]')).toBeNull()
53
53
  })
54
54
 
55
- it('runs in a real browser — `typeof process` is undefined, `import.meta.env.DEV` is true', () => {
56
- expect(typeof process).toBe('undefined')
57
- expect(import.meta.env.DEV).toBe(true)
55
+ it('runs in a real browser — Vitest defines `process.env.NODE_ENV !== "production"`', () => {
56
+ // Sanity check the test env: dev gates use bundler-agnostic
57
+ // `process.env.NODE_ENV !== 'production'`. Every modern bundler
58
+ // (incl. Vitest's Vite) replaces this at build time. In a real-browser
59
+ // test run the literal lands as `"development" !== "production"` →
60
+ // `true`, so dev warnings fire as expected.
61
+ expect(process.env.NODE_ENV).not.toBe('production')
62
+ })
63
+
64
+ // Void HTML elements via Element must not trip runtime-dom's
65
+ // "<X> is a void element and cannot have children" warning.
66
+ // Wrapper used to leak an `undefined` child into the vnode for void tags.
67
+ describe('void HTML element tags', () => {
68
+ const voidTags: Array<'hr' | 'br' | 'input' | 'img'> = ['hr', 'br', 'input', 'img']
69
+
70
+ for (const tag of voidTags) {
71
+ it(`<${tag}> mounts without "void element" console.warn`, () => {
72
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
73
+ const { container, unmount } = mountInBrowser(<Element tag={tag} data-id={tag} />)
74
+ const el = container.querySelector(`[data-id="${tag}"]`)
75
+ expect(el?.tagName.toLowerCase()).toBe(tag)
76
+ const voidWarnings = warnSpy.mock.calls.filter((args) =>
77
+ typeof args[0] === 'string' && args[0].includes('void element'),
78
+ )
79
+ expect(voidWarnings).toEqual([])
80
+ warnSpy.mockRestore()
81
+ unmount()
82
+ })
83
+ }
58
84
  })
59
85
  })
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Unit tests for internElementBundle() — the module-scope LRU cache that
3
+ * gives same-shape Element layouts a stable object identity. Locks in the
4
+ * bail conditions (functions, non-string objects) and the LRU semantics
5
+ * so a future refactor can't silently break the styler classCache hit.
6
+ */
7
+ import { describe, expect, it } from 'vitest'
8
+ import { internElementBundle } from '../helpers/internElementBundle'
9
+
10
+ describe('internElementBundle', () => {
11
+ it('returns the same identity for the same primitive prop tuple', () => {
12
+ const a = internElementBundle({
13
+ block: false,
14
+ direction: 'inline',
15
+ alignX: 'left',
16
+ alignY: 'center',
17
+ equalCols: false,
18
+ extraStyles: undefined,
19
+ })
20
+ const b = internElementBundle({
21
+ block: false,
22
+ direction: 'inline',
23
+ alignX: 'left',
24
+ alignY: 'center',
25
+ equalCols: false,
26
+ extraStyles: undefined,
27
+ })
28
+ expect(a).toBe(b)
29
+ })
30
+
31
+ it('returns different identity when any primitive value differs', () => {
32
+ const a = internElementBundle({ block: false, direction: 'inline' })
33
+ const b = internElementBundle({ block: true, direction: 'inline' })
34
+ const c = internElementBundle({ block: false, direction: 'rows' })
35
+ expect(a).not.toBe(b)
36
+ expect(a).not.toBe(c)
37
+ expect(b).not.toBe(c)
38
+ })
39
+
40
+ it('handles different bundle shapes independently (parentFix vs childFix)', () => {
41
+ const parent = internElementBundle({
42
+ parentFix: true,
43
+ block: false,
44
+ extraStyles: undefined,
45
+ })
46
+ const child = internElementBundle({
47
+ childFix: true,
48
+ direction: 'inline',
49
+ alignX: 'left',
50
+ alignY: 'center',
51
+ equalCols: false,
52
+ })
53
+ expect(parent).not.toBe(child)
54
+ // Same shape repeats are interned
55
+ const parent2 = internElementBundle({
56
+ parentFix: true,
57
+ block: false,
58
+ extraStyles: undefined,
59
+ })
60
+ expect(parent).toBe(parent2)
61
+ })
62
+
63
+ it('bails (returns the input untouched) when a value is a function', () => {
64
+ const fn = () => 'red'
65
+ const a = internElementBundle({ block: false, extraStyles: fn })
66
+ const b = internElementBundle({ block: false, extraStyles: fn })
67
+ // Both calls bail — neither is cached, so identities differ.
68
+ expect(a).not.toBe(b)
69
+ // The returned object IS the input (untouched).
70
+ expect(a).toEqual({ block: false, extraStyles: fn })
71
+ })
72
+
73
+ it('bails when a value is a non-null object (CSSResult / nested object)', () => {
74
+ const cssResult = { strings: ['color: red'], values: [] }
75
+ const a = internElementBundle({ block: false, extraStyles: cssResult })
76
+ const b = internElementBundle({ block: false, extraStyles: cssResult })
77
+ expect(a).not.toBe(b)
78
+ })
79
+
80
+ it('treats string extraStyles as cacheable (the common pre-resolved CSS case)', () => {
81
+ const a = internElementBundle({ block: false, extraStyles: 'color: red' })
82
+ const b = internElementBundle({ block: false, extraStyles: 'color: red' })
83
+ expect(a).toBe(b)
84
+ const c = internElementBundle({ block: false, extraStyles: 'color: blue' })
85
+ expect(a).not.toBe(c)
86
+ })
87
+
88
+ it('null and undefined are distinct cache keys (JSON serializes them differently)', () => {
89
+ const aNull = internElementBundle({ extraStyles: null })
90
+ const aUndef = internElementBundle({ extraStyles: undefined })
91
+ expect(aNull).not.toBe(aUndef)
92
+ })
93
+
94
+ it('LRU touch on hit moves entry to most-recent position', () => {
95
+ // Hit the same bundle twice — second call should still return the same
96
+ // identity (LRU touch keeps it alive).
97
+ const key = `lru-touch-${Math.random()}`
98
+ const first = internElementBundle({ direction: key })
99
+ const second = internElementBundle({ direction: key })
100
+ expect(first).toBe(second)
101
+ })
102
+ })
@@ -0,0 +1,13 @@
1
+ import { isNativeCompat } from '@pyreon/core'
2
+ import { describe, expect, it } from 'vitest'
3
+ import Overlay from '../Overlay/component'
4
+ import OverlayContextProvider from '../Overlay/context'
5
+
6
+ describe('native-compat markers — @pyreon/elements', () => {
7
+ it('Overlay is marked native', () => {
8
+ expect(isNativeCompat(Overlay)).toBe(true)
9
+ })
10
+ it('Overlay context Provider is marked native', () => {
11
+ expect(isNativeCompat(OverlayContextProvider)).toBe(true)
12
+ })
13
+ })
@@ -34,7 +34,13 @@ vi.mock('@pyreon/reactivity', () => {
34
34
  return s
35
35
  }
36
36
 
37
- return { signal }
37
+ // See sibling Overlay.test.ts mock: `@pyreon/core` imports
38
+ // `setSnapshotCapture` and calls it at module load to install the
39
+ // reactive-effect context-snapshot DI hook. The mock provides a no-op
40
+ // so the `@pyreon/core` import doesn't throw "No 'setSnapshotCapture'
41
+ // export is defined on the '@pyreon/reactivity' mock."
42
+ const setSnapshotCapture = () => {}
43
+ return { signal, setSnapshotCapture }
38
44
  })
39
45
 
40
46
  vi.mock('@pyreon/core', async (importOriginal) => {
package/src/env.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Minimal process type — just enough for `process.env.NODE_ENV` checks.
3
+ * Avoids requiring @types/node in consumers that import pyreon source
4
+ * via the `"bun"` export condition.
5
+ */
6
+ declare var process: { env: { NODE_ENV?: string } }
@@ -5,7 +5,9 @@
5
5
  * support `display: flex` consistently across browsers.
6
6
  */
7
7
  import { splitProps } from '@pyreon/core'
8
+ import { getShouldBeEmpty } from '../../Element/utils'
8
9
  import { IS_DEVELOPMENT } from '../../utils'
10
+ import { internElementBundle } from '../internElementBundle'
9
11
  import Styled from './styled'
10
12
  import type { Props } from './types'
11
13
  import { isWebFixNeeded } from './utils'
@@ -41,46 +43,49 @@ const Component = (props: Partial<Props> & { ref?: unknown }) => {
41
43
 
42
44
  const needsFix = !own.dangerouslySetInnerHTML && isWebFixNeeded(own.tag)
43
45
 
46
+ // Void HTML elements (hr, input, img, br, …) cannot have children. Even
47
+ // a falsy `{own.children}` slot becomes `[undefined]` in the vnode and
48
+ // trips runtime-dom's void-element warning. Element already skips passing
49
+ // children to Wrapper for void tags; this guard makes sure the empty
50
+ // slot is dropped here too instead of leaking into the JSX.
51
+ const isVoidTag = !own.dangerouslySetInnerHTML && getShouldBeEmpty(own.tag)
52
+
44
53
  if (!needsFix) {
54
+ const bundle = internElementBundle({
55
+ block: own.block,
56
+ direction: own.direction,
57
+ alignX: own.alignX,
58
+ alignY: own.alignY,
59
+ equalCols: own.equalCols,
60
+ extraStyles: own.extendCss,
61
+ })
62
+ if (isVoidTag) {
63
+ return <Styled {...commonProps} $element={bundle} />
64
+ }
45
65
  return (
46
- <Styled
47
- {...commonProps}
48
- $element={{
49
- block: own.block,
50
- direction: own.direction,
51
- alignX: own.alignX,
52
- alignY: own.alignY,
53
- equalCols: own.equalCols,
54
- extraStyles: own.extendCss,
55
- }}
56
- >
66
+ <Styled {...commonProps} $element={bundle}>
57
67
  {own.children}
58
68
  </Styled>
59
69
  )
60
70
  }
61
71
 
62
72
  const asTag = own.isInline ? 'span' : 'div'
73
+ const parentBundle = internElementBundle({
74
+ parentFix: true as const,
75
+ block: own.block,
76
+ extraStyles: own.extendCss,
77
+ })
78
+ const childBundle = internElementBundle({
79
+ childFix: true as const,
80
+ direction: own.direction,
81
+ alignX: own.alignX,
82
+ alignY: own.alignY,
83
+ equalCols: own.equalCols,
84
+ })
63
85
 
64
86
  return (
65
- <Styled
66
- {...commonProps}
67
- $element={{
68
- parentFix: true as const,
69
- block: own.block,
70
- extraStyles: own.extendCss,
71
- }}
72
- >
73
- <Styled
74
- as={asTag}
75
- $childFix
76
- $element={{
77
- childFix: true as const,
78
- direction: own.direction,
79
- alignX: own.alignX,
80
- alignY: own.alignY,
81
- equalCols: own.equalCols,
82
- }}
83
- >
87
+ <Styled {...commonProps} $element={parentBundle}>
88
+ <Styled as={asTag} $childFix $element={childBundle}>
84
89
  {own.children}
85
90
  </Styled>
86
91
  </Styled>
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Module-scope intern cache for `$element` bundles passed to Wrapper's styled
3
+ * component. Same primitive prop tuple → same object identity, so the styler's
4
+ * `elClassCache` (added 2026-Q2 alongside this) hits and skips the resolve
5
+ * pipeline. Analogous to `@pyreon/rocketstyle`'s dimension-prop memo (PR #344)
6
+ * but at the layer below — covers non-rocketstyle Element / Wrapper / Text usage
7
+ * AND the residual styled wrappers under any rocketstyle component.
8
+ *
9
+ * Cache key is a JSON-stringified shallow snapshot of the bundle. LRU-bound at
10
+ * 256 entries; oldest-first eviction. Bail (return the input as-is, no cache)
11
+ * when any value is a function (signal accessor) or a non-string object (CSS
12
+ * callback / CSSResult / nested object) — those cannot be safely round-tripped
13
+ * through JSON without losing identity guarantees.
14
+ */
15
+ const _bundleCache = new Map<string, Record<string, unknown>>()
16
+ const BUNDLE_CAP = 256
17
+
18
+ export const internElementBundle = <T extends Record<string, unknown>>(bundle: T): T => {
19
+ for (const k in bundle) {
20
+ const v = bundle[k]
21
+ if (typeof v === 'function') return bundle
22
+ if (v != null && typeof v === 'object') return bundle
23
+ }
24
+ const key = JSON.stringify(bundle)
25
+ const existing = _bundleCache.get(key)
26
+ if (existing) {
27
+ _bundleCache.delete(key)
28
+ _bundleCache.set(key, existing)
29
+ return existing as T
30
+ }
31
+ if (_bundleCache.size >= BUNDLE_CAP) {
32
+ const oldest = _bundleCache.keys().next().value
33
+ if (oldest !== undefined) _bundleCache.delete(oldest)
34
+ }
35
+ _bundleCache.set(key, bundle)
36
+ return bundle
37
+ }
package/src/utils.ts CHANGED
@@ -2,7 +2,4 @@
2
2
  // literal-replaced so prod bundles tree-shake the dev branch to zero bytes.
3
3
  // Typed through a narrowing interface so downstream packages don't need
4
4
  // `vite/client` in their tsconfigs to type-check this file transitively.
5
- interface ViteMeta {
6
- readonly env?: { readonly DEV?: boolean }
7
- }
8
- export const IS_DEVELOPMENT: boolean = (import.meta as ViteMeta).env?.DEV === true
5
+ export const IS_DEVELOPMENT: boolean = process.env.NODE_ENV !== 'production'
@@ -1 +0,0 @@
1
- {"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/types.ts","../../src/Element/types.ts","../../src/Element/component.tsx","../../src/helpers/Iterator/types.ts","../../src/helpers/Iterator/component.tsx","../../src/List/component.tsx","../../src/Overlay/context.tsx","../../src/Overlay/positioning.ts","../../src/Overlay/useOverlay.tsx","../../src/Overlay/component.tsx","../../src/Portal/component.tsx","../../src/Text/component.tsx","../../src/Util/component.tsx"],"mappings":"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"}
package/lib/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["styles","component","Fragment","Component","Styled","component","styles","Component","Styled","component","Wrapper","WrapperStyled","Content","name","Component","component","Component","Iterator","Element","name","Component","Component","name","Component","CorePortal","name","Component","Styled","name","Component"],"sources":["../src/constants.ts","../src/utils.ts","../src/helpers/Content/styled.ts","../../../core/core/lib/jsx-runtime.js","../src/helpers/Content/component.tsx","../src/helpers/Content/index.ts","../src/helpers/Wrapper/styled.ts","../src/helpers/Wrapper/constants.ts","../src/helpers/Wrapper/utils.ts","../src/helpers/Wrapper/component.tsx","../src/helpers/Wrapper/index.ts","../src/Element/constants.ts","../src/Element/utils.ts","../src/Element/component.tsx","../src/helpers/Iterator/component.tsx","../src/helpers/Iterator/index.ts","../src/List/component.tsx","../src/Overlay/context.tsx","../src/Overlay/positioning.ts","../src/Overlay/useOverlay.tsx","../src/Overlay/component.tsx","../src/Portal/component.tsx","../src/Text/styled.ts","../src/Text/component.tsx","../src/Util/component.tsx"],"sourcesContent":["export const PKG_NAME = '@pyreon/elements' as const\n","// `import.meta.env.DEV` is provided by Vite/Rolldown at build time and\n// literal-replaced so prod bundles tree-shake the dev branch to zero bytes.\n// Typed through a narrowing interface so downstream packages don't need\n// `vite/client` in their tsconfigs to type-check this file transitively.\ninterface ViteMeta {\n readonly env?: { readonly DEV?: boolean }\n}\nexport const IS_DEVELOPMENT: boolean = (import.meta as ViteMeta).env?.DEV === true\n","/**\n * Styled component for content areas (before/content/after). Applies\n * responsive flex alignment, gap spacing between slots based on parent\n * direction (margin-right for inline, margin-bottom for rows), and\n * equalCols flex distribution. The \"content\" slot gets `flex: 1` to\n * fill remaining space between before and after.\n */\nimport { config } from '@pyreon/ui-core'\nimport { alignContent, extendCss, makeItResponsive, value } from '@pyreon/unistyle'\nimport type { ResponsiveStylesCallback } from '../../types'\nimport type { StyledProps, ThemeProps } from './types'\n\nconst { styled, css, component } = config\n\nconst equalColsCSS = `\n flex: 1;\n`\n\nconst typeContentCSS = `\n flex: 1;\n`\n\n// --------------------------------------------------------\n// calculate spacing between before / content / after\n// --------------------------------------------------------\nconst gapDimensions = {\n inline: {\n before: 'margin-right',\n after: 'margin-left',\n },\n reverseInline: {\n before: 'margin-right',\n after: 'margin-left',\n },\n rows: {\n before: 'margin-bottom',\n after: 'margin-top',\n },\n reverseRows: {\n before: 'margin-bottom',\n after: 'margin-top',\n },\n} as const\n\nconst calculateGap = ({\n direction,\n type,\n value: gapValue,\n}: {\n direction: keyof typeof gapDimensions\n type: ThemeProps['contentType']\n value: string | number | null | undefined\n}) => {\n if (!direction || !type || type === 'content') return undefined\n\n const finalStyles = `${gapDimensions[direction][type]}: ${gapValue};`\n\n return finalStyles\n}\n\n// --------------------------------------------------------\n// calculations of styles to be rendered\n// --------------------------------------------------------\nconst styles: ResponsiveStylesCallback = ({ css: cssFn, theme: t, rootSize }) => cssFn`\n ${alignContent({\n direction: t.direction,\n alignX: t.alignX,\n alignY: t.alignY,\n })};\n\n ${t.equalCols && equalColsCSS};\n\n ${\n t.gap &&\n t.contentType &&\n calculateGap({\n direction: t.parentDirection,\n type: t.contentType,\n value: value(t.gap, rootSize),\n })\n };\n\n ${t.extraStyles && extendCss(t.extraStyles as Parameters<typeof extendCss>[0])};\n`\n\nconst platformCSS = `box-sizing: border-box;`\n\nconst StyledComponent = styled(component, { layer: 'elements' })`\n ${platformCSS};\n\n display: flex;\n align-self: stretch;\n flex-wrap: wrap;\n\n ${(({ $contentType }: StyledProps) => $contentType === 'content' && typeContentCSS) as any};\n\n ${makeItResponsive({\n key: '$element',\n styles,\n css,\n normalize: true,\n })};\n`\n\nexport default StyledComponent\n","//#region src/h.ts\n/** Marker for fragment nodes — renders children without a wrapper element */\nconst Fragment = Symbol(\"Pyreon.Fragment\");\n/**\n* Hyperscript function — the compiled output of JSX.\n* `<div class=\"x\">hello</div>` → `h(\"div\", { class: \"x\" }, \"hello\")`\n*\n* Generic on P so TypeScript validates props match the component's signature\n* at the call site, then stores the result in the loosely-typed VNode.\n*/\n/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */\nconst EMPTY_PROPS = {};\nfunction h(type, props, ...children) {\n\treturn {\n\t\ttype,\n\t\tprops: props ?? EMPTY_PROPS,\n\t\tchildren: normalizeChildren(children),\n\t\tkey: props?.key ?? null\n\t};\n}\nfunction normalizeChildren(children) {\n\tfor (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);\n\treturn children;\n}\nfunction flattenChildren(children) {\n\tconst result = [];\n\tfor (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));\n\telse result.push(child);\n\treturn result;\n}\n\n//#endregion\n//#region src/jsx-runtime.ts\n/**\n* JSX automatic runtime.\n*\n* When tsconfig has `\"jsxImportSource\": \"@pyreon/core\"`, the TS/bundler compiler\n* rewrites JSX to imports from this file automatically:\n* <div class=\"x\" /> → jsx(\"div\", { class: \"x\" })\n*/\nfunction jsx(type, props, key) {\n\tconst { children, ...rest } = props;\n\tconst propsWithKey = key != null ? {\n\t\t...rest,\n\t\tkey\n\t} : rest;\n\tif (typeof type === \"function\") return h(type, children !== void 0 ? {\n\t\t...propsWithKey,\n\t\tchildren\n\t} : propsWithKey);\n\treturn h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);\n}\nconst jsxs = jsx;\n\n//#endregion\nexport { Fragment, jsx, jsxs };\n//# sourceMappingURL=jsx-runtime.js.map","/**\n * Content area used inside Element to render one of the three\n * layout slots (before, content, after). Passes alignment, direction,\n * gap, and equalCols styling props to the underlying styled component.\n * Adds a `data-pyr-element` attribute in development for debugging.\n *\n * Children are rendered via core `render()`.\n */\nimport { splitProps } from '@pyreon/core'\nimport { render } from '@pyreon/ui-core'\nimport { IS_DEVELOPMENT } from '../../utils'\nimport Styled from './styled'\nimport type { Props } from './types'\n\nconst Component = (props: Partial<Props>) => {\n const [own, rest] = splitProps(props, [\n 'contentType',\n 'tag',\n 'parentDirection',\n 'direction',\n 'alignX',\n 'alignY',\n 'equalCols',\n 'gap',\n 'extendCss',\n 'children',\n ])\n\n const debugProps = IS_DEVELOPMENT\n ? {\n 'data-pyr-element': own.contentType,\n }\n : {}\n\n const stylingProps = {\n contentType: own.contentType,\n parentDirection: own.parentDirection,\n direction: own.direction,\n alignX: own.alignX,\n alignY: own.alignY,\n equalCols: own.equalCols,\n gap: own.gap,\n extraStyles: own.extendCss,\n }\n\n return (\n <Styled as={own.tag} $contentType={own.contentType} $element={stylingProps} {...debugProps} {...rest}>\n {render(own.children)}\n </Styled>\n )\n}\n\nexport default Component\n","import component from './component'\n\nexport default component\n","/**\n * Styled component for the Element wrapper layer. Handles responsive\n * block/inline-flex display, direction, alignment, and custom CSS injection.\n * Includes special handling for the `parentFix` / `childFix` flags that\n * split flex behavior across two DOM nodes for button/fieldset/legend\n * elements where a single flex container is insufficient.\n */\nimport { config } from '@pyreon/ui-core'\nimport { alignContent, extendCss, makeItResponsive } from '@pyreon/unistyle'\nimport type { ResponsiveStylesCallback } from '../../types'\nimport type { StyledProps } from './types'\n\nconst { styled, css, component } = config\n\nconst childFixCSS = `\n display: flex;\n flex: 1;\n width: 100%;\n height: 100%;\n`\n\nconst parentFixCSS = `\n flex-direction: column;\n`\n\nconst fullHeightCSS = `\n height: 100%;\n`\n\nconst blockCSS = `\n align-self: stretch;\n flex: 1;\n min-width: 0;\n`\n\nconst childFixPosition = (isBlock?: boolean) => `display: ${isBlock ? 'flex' : 'inline-flex'};`\n\nconst styles: ResponsiveStylesCallback = ({ theme: t, css: cssFn }) => cssFn`\n ${t.alignY === 'block' && fullHeightCSS};\n\n ${alignContent({\n direction: t.direction,\n alignX: t.alignX,\n alignY: t.alignY,\n })};\n\n ${t.block && blockCSS};\n ${t.alignY === 'block' && t.block && fullHeightCSS};\n\n ${!t.childFix && childFixPosition(t.block)};\n ${t.parentFix && parentFixCSS};\n\n ${t.extraStyles && extendCss(t.extraStyles as Parameters<typeof extendCss>[0])};\n`\n\nconst platformCSS = `box-sizing: border-box;`\n\nexport default styled(component, { layer: 'elements' })`\n position: relative;\n ${platformCSS};\n\n ${(({ $childFix }: StyledProps) => $childFix && childFixCSS) as any};\n\n ${makeItResponsive({\n key: '$element',\n styles,\n css,\n normalize: true,\n })};\n`\n","/**\n * HTML elements that need a two-layer DOM workaround because browsers do not\n * fully support flexbox layout on button, fieldset, and legend elements.\n * @see https://stackoverflow.com/questions/35464067/flexbox-not-working-on-button-or-fieldset-elements\n */\nexport const INLINE_ELEMENTS_FLEX_FIX = {\n button: true,\n fieldset: true,\n legend: true,\n}\n","import { INLINE_ELEMENTS_FLEX_FIX } from './constants'\n\ntype IsWebFixNeeded = (tag?: string) => boolean\nexport const isWebFixNeeded: IsWebFixNeeded = (tag) => {\n if (tag && tag in INLINE_ELEMENTS_FLEX_FIX) return true\n return false\n}\n","/**\n * Wrapper component that serves as the outermost styled container for Element.\n * On web, it detects button/fieldset/legend tags and applies a two-layer flex\n * fix (parent + child Styled) because these HTML elements do not natively\n * support `display: flex` consistently across browsers.\n */\nimport { splitProps } from '@pyreon/core'\nimport { IS_DEVELOPMENT } from '../../utils'\nimport Styled from './styled'\nimport type { Props } from './types'\nimport { isWebFixNeeded } from './utils'\n\nconst DEV_PROPS: Record<string, string> = IS_DEVELOPMENT ? { 'data-pyr-element': 'Element' } : {}\n\n// Layout / ref keys consumed by Wrapper itself. Everything else is forwarded\n// onto the underlying DOM node. Listed as a tuple so `splitProps` narrows\n// `own` correctly while preserving reactive prop tracking on both halves.\nconst OWN_KEYS: Array<keyof Props | 'ref'> = [\n 'children',\n 'tag',\n 'block',\n 'extendCss',\n 'direction',\n 'alignX',\n 'alignY',\n 'equalCols',\n 'isInline',\n 'ref',\n 'dangerouslySetInnerHTML',\n]\n\nconst Component = (props: Partial<Props> & { ref?: unknown }) => {\n const [own, rest] = splitProps(props, OWN_KEYS)\n\n const commonProps = {\n ...rest,\n ...DEV_PROPS,\n ref: own.ref,\n as: own.tag,\n }\n\n const needsFix = !own.dangerouslySetInnerHTML && isWebFixNeeded(own.tag)\n\n if (!needsFix) {\n return (\n <Styled\n {...commonProps}\n $element={{\n block: own.block,\n direction: own.direction,\n alignX: own.alignX,\n alignY: own.alignY,\n equalCols: own.equalCols,\n extraStyles: own.extendCss,\n }}\n >\n {own.children}\n </Styled>\n )\n }\n\n const asTag = own.isInline ? 'span' : 'div'\n\n return (\n <Styled\n {...commonProps}\n $element={{\n parentFix: true as const,\n block: own.block,\n extraStyles: own.extendCss,\n }}\n >\n <Styled\n as={asTag}\n $childFix\n $element={{\n childFix: true as const,\n direction: own.direction,\n alignX: own.alignX,\n alignY: own.alignY,\n equalCols: own.equalCols,\n }}\n >\n {own.children}\n </Styled>\n </Styled>\n )\n}\n\nexport default Component\n","import component from './component'\n\nexport default component\n","/** Props consumed by Element that should not be forwarded to the underlying DOM node. */\nexport const RESERVED_PROPS = [\n 'innerRef',\n 'tag',\n 'block',\n 'label',\n 'children',\n 'beforeContent',\n 'afterContent',\n\n 'equalCols',\n 'vertical',\n 'direction',\n 'alignX',\n 'alignY',\n\n 'css',\n 'contentCss',\n 'beforeContentCss',\n 'afterContentCss',\n\n 'contentDirection',\n 'contentAlignX',\n 'contentAlignY',\n\n 'beforeContentDirection',\n 'beforeContentAlignX',\n 'beforeContentAlignY',\n\n 'afterContentDirection',\n 'afterContentAlignX',\n 'afterContentAlignY',\n] as const\n\n/**\n * HTML tags that are inline-level by default. When Element renders one of\n * these tags, child Content wrappers use `span` instead of `div` to\n * preserve valid HTML nesting.\n */\nexport const INLINE_ELEMENTS = {\n span: true,\n a: true,\n button: true,\n input: true,\n label: true,\n select: true,\n textarea: true,\n br: true,\n img: true,\n strong: true,\n small: true,\n code: true,\n b: true,\n big: true,\n i: true,\n tt: true,\n abbr: true,\n acronym: true,\n cite: true,\n dfn: true,\n em: true,\n kbd: true,\n samp: true,\n var: true,\n bdo: true,\n map: true,\n object: true,\n q: true,\n script: true,\n sub: true,\n sup: true,\n}\n\n/**\n * HTML void/self-closing elements that cannot have children. When Element\n * detects one of these tags, it skips rendering beforeContent/content/afterContent\n * and returns the Wrapper alone.\n */\nexport const EMPTY_ELEMENTS = {\n area: true,\n base: true,\n br: true,\n col: true,\n embed: true,\n hr: true,\n img: true,\n input: true,\n keygen: true,\n link: true,\n textarea: true,\n // 'meta': true,\n // 'param': true,\n source: true,\n track: true,\n wbr: true,\n}\n","import { EMPTY_ELEMENTS, INLINE_ELEMENTS } from './constants'\n\ntype GetValue = (tag?: string) => boolean\n\n/** Checks whether the given HTML tag is an inline-level element, used to determine sub-tag nesting. */\nexport const isInlineElement: GetValue = (tag) => {\n if (tag && tag in INLINE_ELEMENTS) return true\n return false\n}\n\n/** Checks whether the given HTML tag is a void element that cannot have children. */\nexport const getShouldBeEmpty: GetValue = (tag) => {\n if (tag && tag in EMPTY_ELEMENTS) return true\n return false\n}\n","/**\n * Core building block of the elements package. Renders a three-section layout\n * (beforeContent / content / afterContent) inside a flex Wrapper. When only\n * content is present, the Wrapper inherits content-level alignment directly\n * to avoid an unnecessary nesting layer. Handles HTML-specific edge cases\n * like void elements (input, img) and inline elements (span, a) by\n * skipping children or switching sub-tags accordingly.\n */\n\nimport { onMount, splitProps } from '@pyreon/core'\nimport { render } from '@pyreon/ui-core'\nimport { PKG_NAME } from '../constants'\nimport { Content, Wrapper } from '../helpers'\nimport WrapperStyled from '../helpers/Wrapper/styled'\nimport { isWebFixNeeded } from '../helpers/Wrapper/utils'\nimport { IS_DEVELOPMENT } from '../utils'\nimport type { PyreonElement } from './types'\nimport { getShouldBeEmpty, isInlineElement } from './utils'\n\nconst WRAPPER_DEV_PROPS: Record<string, string> = IS_DEVELOPMENT\n ? { 'data-pyr-element': 'Element' }\n : {}\n\nconst equalize = (el: HTMLElement, direction: unknown) => {\n const beforeEl = el.firstElementChild as HTMLElement | null\n const afterEl = el.lastElementChild as HTMLElement | null\n\n if (beforeEl && afterEl && beforeEl !== afterEl) {\n const type: 'height' | 'width' = direction === 'rows' ? 'height' : 'width'\n const prop = type === 'height' ? 'offsetHeight' : 'offsetWidth'\n const beforeSize = beforeEl[prop]\n const afterSize = afterEl[prop]\n\n if (Number.isInteger(beforeSize) && Number.isInteger(afterSize)) {\n const maxSize = `${Math.max(beforeSize, afterSize)}px`\n beforeEl.style[type] = maxSize\n afterEl.style[type] = maxSize\n }\n }\n}\n\nconst defaultDirection = 'inline'\nconst defaultContentDirection = 'rows'\nconst defaultAlignX = 'left'\nconst defaultAlignY = 'center'\n\nconst Component: PyreonElement = (props) => {\n const [own, rest] = splitProps(props, [\n 'innerRef',\n 'tag',\n 'label',\n 'content',\n 'children',\n 'beforeContent',\n 'afterContent',\n 'equalBeforeAfter',\n 'block',\n 'equalCols',\n 'gap',\n 'direction',\n 'alignX',\n 'alignY',\n 'css',\n 'contentCss',\n 'beforeContentCss',\n 'afterContentCss',\n 'contentDirection',\n 'contentAlignX',\n 'contentAlignY',\n 'beforeContentDirection',\n 'beforeContentAlignX',\n 'beforeContentAlignY',\n 'afterContentDirection',\n 'afterContentAlignX',\n 'afterContentAlignY',\n 'ref',\n ])\n\n const alignX = own.alignX ?? defaultAlignX\n const alignY = own.alignY ?? defaultAlignY\n const contentDirection = own.contentDirection ?? defaultContentDirection\n const contentAlignX = own.contentAlignX ?? defaultAlignX\n const contentAlignY = own.contentAlignY ?? defaultAlignY\n const beforeContentDirection = own.beforeContentDirection ?? defaultDirection\n const beforeContentAlignX = own.beforeContentAlignX ?? defaultAlignX\n const beforeContentAlignY = own.beforeContentAlignY ?? defaultAlignY\n const afterContentDirection = own.afterContentDirection ?? defaultDirection\n const afterContentAlignX = own.afterContentAlignX ?? defaultAlignX\n const afterContentAlignY = own.afterContentAlignY ?? defaultAlignY\n\n // --------------------------------------------------------\n // check if should render only single element\n // --------------------------------------------------------\n const shouldBeEmpty = !!rest.dangerouslySetInnerHTML || getShouldBeEmpty(own.tag)\n\n // --------------------------------------------------------\n // if not single element, calculate values\n // --------------------------------------------------------\n const isSimpleElement = !own.beforeContent && !own.afterContent\n // Getter — preserves reactivity of own.content (which may be _rp() wrapped).\n // Reading own.content via ?? at setup would capture the value once.\n const getChildren = () => own.children ?? own.content ?? own.label\n\n const isInline = isInlineElement(own.tag)\n const SUB_TAG = isInline ? 'span' : undefined\n\n // --------------------------------------------------------\n // direction & alignX & alignY calculations\n // --------------------------------------------------------\n let wrapperDirection: typeof own.direction = own.direction\n let wrapperAlignX: typeof alignX = alignX\n let wrapperAlignY: typeof alignY = alignY\n\n if (isSimpleElement) {\n if (contentDirection) wrapperDirection = contentDirection\n if (contentAlignX) wrapperAlignX = contentAlignX\n if (contentAlignY) wrapperAlignY = contentAlignY\n } else if (own.direction) {\n wrapperDirection = own.direction\n } else {\n wrapperDirection = defaultDirection\n }\n\n // --------------------------------------------------------\n // equalBeforeAfter: measure & equalize slot dimensions\n // --------------------------------------------------------\n let equalizeRef: HTMLElement | null = null\n const externalRef = own.ref ?? own.innerRef\n\n const mergedRef = (node: HTMLElement | null) => {\n equalizeRef = node\n if (typeof externalRef === 'function') (externalRef as (el: HTMLElement | null) => void)(node)\n else if (externalRef != null) {\n ;(externalRef as unknown as { current: HTMLElement | null }).current = node\n }\n }\n\n if (own.equalBeforeAfter && own.beforeContent && own.afterContent) {\n onMount(() => {\n if (equalizeRef) equalize(equalizeRef, own.direction)\n return undefined\n })\n }\n\n // --------------------------------------------------------\n // common wrapper props\n // --------------------------------------------------------\n const WRAPPER_PROPS = {\n ref: mergedRef,\n extendCss: own.css,\n tag: own.tag,\n block: own.block,\n direction: wrapperDirection,\n alignX: wrapperAlignX,\n alignY: wrapperAlignY,\n as: undefined, // reset styled-components `as` prop\n }\n\n // --------------------------------------------------------\n // return simple/empty element like input or image etc.\n // --------------------------------------------------------\n if (shouldBeEmpty) {\n return <Wrapper {...rest} {...WRAPPER_PROPS} />\n }\n\n // Simple-Element fast path: no beforeContent / afterContent slots, and no\n // button/fieldset/legend two-layer flex fix needed. Inline the Wrapper\n // helper directly into a single Styled invocation — saves one component\n // hop, one splitProps call, and one mountChild per Element. The Wrapper\n // helper still exists for the rare needsFix case below; tests that asserted\n // Wrapper appears in the VNode tree are updated to the new shape.\n const dangerouslySetInnerHTML = (rest as { dangerouslySetInnerHTML?: unknown })\n .dangerouslySetInnerHTML\n const needsFix = !dangerouslySetInnerHTML && isWebFixNeeded(own.tag)\n\n if (isSimpleElement && !needsFix) {\n return (\n <WrapperStyled\n {...rest}\n {...WRAPPER_DEV_PROPS}\n ref={mergedRef}\n as={own.tag}\n $element={{\n block: own.block,\n direction: wrapperDirection,\n alignX: wrapperAlignX,\n alignY: wrapperAlignY,\n equalCols: own.equalCols,\n extraStyles: own.css,\n }}\n >\n {render(getChildren())}\n </WrapperStyled>\n )\n }\n\n if (isSimpleElement) {\n return (\n <Wrapper {...rest} {...WRAPPER_PROPS} isInline={isInline}>\n {render(getChildren())}\n </Wrapper>\n )\n }\n\n return (\n <Wrapper {...rest} {...WRAPPER_PROPS} isInline={isInline}>\n {own.beforeContent && (\n <Content\n tag={SUB_TAG}\n contentType=\"before\"\n parentDirection={wrapperDirection}\n extendCss={own.beforeContentCss}\n direction={beforeContentDirection}\n alignX={beforeContentAlignX}\n alignY={beforeContentAlignY}\n equalCols={own.equalCols}\n gap={own.gap}\n >\n {own.beforeContent}\n </Content>\n )}\n\n <Content\n tag={SUB_TAG}\n contentType=\"content\"\n parentDirection={wrapperDirection}\n extendCss={own.contentCss}\n direction={contentDirection}\n alignX={contentAlignX}\n alignY={contentAlignY}\n equalCols={own.equalCols}\n >\n {getChildren()}\n </Content>\n\n {own.afterContent && (\n <Content\n tag={SUB_TAG}\n contentType=\"after\"\n parentDirection={wrapperDirection}\n extendCss={own.afterContentCss}\n direction={afterContentDirection}\n alignX={afterContentAlignX}\n alignY={afterContentAlignY}\n equalCols={own.equalCols}\n gap={own.gap}\n >\n {own.afterContent}\n </Content>\n )}\n </Wrapper>\n )\n}\n\nconst name = `${PKG_NAME}/Element` as const\n\nComponent.displayName = name\nComponent.pkgName = PKG_NAME\nComponent.PYREON__COMPONENT = name\n\nexport default Component\n","/**\n * Data-driven list renderer that supports three input modes: children,\n * an array of primitives, or an array of objects.\n * Each item receives positional metadata (first, last, odd, even, position)\n * and optional injected props via `itemProps`. Items can be individually\n * wrapped with `wrapComponent`. Children always take priority over the\n * component+data prop pattern.\n */\n\nimport type { VNode, VNodeChild } from '@pyreon/core'\nimport { Fragment } from '@pyreon/core'\nimport { isEmpty, render } from '@pyreon/ui-core'\nimport type { ExtendedProps, ObjectValue, Props, SimpleValue } from './types'\n\ntype ClassifiedData =\n | { type: 'simple'; data: SimpleValue[] }\n | { type: 'complex'; data: ObjectValue[] }\n | null\n\nconst classifyData = (data: unknown[]): ClassifiedData => {\n const items = data.filter(\n (item) =>\n item != null && !(typeof item === 'object' && isEmpty(item as Record<string, unknown>)),\n )\n\n if (items.length === 0) return null\n\n let isSimple = true\n let isComplex = true\n\n for (const item of items) {\n if (typeof item === 'string' || typeof item === 'number') {\n isComplex = false\n } else if (typeof item === 'object') {\n isSimple = false\n } else {\n isSimple = false\n isComplex = false\n }\n }\n\n if (isSimple) return { type: 'simple', data: items as SimpleValue[] }\n if (isComplex) return { type: 'complex', data: items as ObjectValue[] }\n return null\n}\n\nconst RESERVED_PROPS = [\n 'children',\n 'component',\n 'wrapComponent',\n 'data',\n 'itemKey',\n 'valueName',\n 'itemProps',\n 'wrapProps',\n] as const\n\ntype AttachItemProps = ({ i, length }: { i: number; length: number }) => ExtendedProps\n\nconst attachItemProps: AttachItemProps = ({ i, length }: { i: number; length: number }) => {\n const position = i + 1\n\n return {\n index: i,\n first: position === 1,\n last: position === length,\n odd: position % 2 === 1,\n even: position % 2 === 0,\n position,\n }\n}\n\nconst Component = (props: Props) => {\n const {\n itemKey,\n valueName,\n children,\n component,\n data,\n wrapComponent: Wrapper,\n wrapProps,\n itemProps,\n } = props\n\n const injectItemProps = typeof itemProps === 'function' ? itemProps : () => itemProps\n\n const injectWrapItemProps = typeof wrapProps === 'function' ? wrapProps : () => wrapProps\n\n const getKey = (item: string | number, index: number) => {\n if (typeof itemKey === 'function') return itemKey(item, index)\n return index\n }\n\n const renderChild = (child: VNodeChild, total = 1, i = 0) => {\n if (!itemProps && !Wrapper) return child\n\n const extendedProps = attachItemProps({\n i,\n length: total,\n })\n\n const finalItemProps = itemProps ? injectItemProps({}, extendedProps) : {}\n\n if (Wrapper) {\n const finalWrapProps = wrapProps ? injectWrapItemProps({}, extendedProps) : {}\n\n return (\n <Wrapper key={i} {...finalWrapProps}>\n {render(child, finalItemProps)}\n </Wrapper>\n )\n }\n\n return render(child, {\n key: i,\n ...finalItemProps,\n })\n }\n\n // --------------------------------------------------------\n // render children\n // --------------------------------------------------------\n const renderChildren = () => {\n if (!children) return null\n\n // if children is Array\n if (Array.isArray(children)) {\n return children.map((item, i) => renderChild(item, children.length, i))\n }\n\n // if children is Fragment — check VNode type\n if (\n typeof children === 'object' &&\n 'type' in (children as VNode) &&\n (children as VNode).type === Fragment\n ) {\n const fragmentChildren = (children as VNode).children as VNodeChild[]\n const childrenLength = fragmentChildren.length\n\n return fragmentChildren.map((item, i) => renderChild(item, childrenLength, i))\n }\n\n // if single child\n return renderChild(children)\n }\n\n // --------------------------------------------------------\n // render array of strings or numbers\n // --------------------------------------------------------\n const renderSimpleArray = (simpleData: SimpleValue[]) => {\n const { length } = simpleData\n\n if (length === 0) return null\n\n return simpleData.map((item, i) => {\n const key = getKey(item, i)\n const keyName = valueName ?? 'children'\n const extendedProps = attachItemProps({\n i,\n length,\n })\n\n const finalItemProps = {\n ...(itemProps ? injectItemProps({ [keyName]: item }, extendedProps) : {}),\n [keyName]: item,\n }\n\n if (Wrapper) {\n const finalWrapProps = wrapProps\n ? injectWrapItemProps({ [keyName]: item }, extendedProps)\n : {}\n\n return (\n <Wrapper key={key} {...finalWrapProps}>\n {render(component, finalItemProps)}\n </Wrapper>\n )\n }\n\n return render(component, { key, ...finalItemProps })\n })\n }\n\n // --------------------------------------------------------\n // render array of objects\n // --------------------------------------------------------\n const getObjectKey = (item: ObjectValue, index: number) => {\n if (!itemKey) return item.key ?? item.id ?? item.itemId ?? index\n if (typeof itemKey === 'function') return itemKey(item, index)\n if (typeof itemKey === 'string') return item[itemKey]\n\n return index\n }\n\n const renderComplexArray = (complexData: ObjectValue[]) => {\n const { length } = complexData\n\n if (length === 0) return null\n\n return complexData.map((item, i) => {\n const { component: itemComponent, ...restItem } = item\n const renderItem = itemComponent ?? component\n const key = getObjectKey(restItem, i)\n const extendedProps = attachItemProps({\n i,\n length,\n })\n\n const finalItemProps = {\n ...(itemProps ? injectItemProps(item, extendedProps) : {}),\n ...restItem,\n }\n\n if (Wrapper && !itemComponent) {\n const finalWrapProps = wrapProps ? injectWrapItemProps(item, extendedProps) : {}\n\n return (\n <Wrapper key={key} {...finalWrapProps}>\n {render(renderItem, finalItemProps)}\n </Wrapper>\n )\n }\n\n return render(renderItem, { key, ...finalItemProps })\n })\n }\n\n // --------------------------------------------------------\n // render list items\n // --------------------------------------------------------\n const renderItems = (): VNodeChild => {\n // children have priority over props component + data\n if (children) return renderChildren() as VNodeChild\n\n // render props component + data\n if (component && Array.isArray(data)) {\n const classified = classifyData(data)\n if (!classified) return null\n if (classified.type === 'simple') return renderSimpleArray(classified.data) as VNodeChild\n return renderComplexArray(classified.data) as VNodeChild\n }\n\n return null\n }\n\n return renderItems()\n}\n\nexport default Object.assign(Component, {\n isIterator: true as const,\n RESERVED_PROPS,\n})\n","import component from './component'\nimport type {\n ElementType,\n ExtendedProps,\n MaybeNull,\n ObjectValue,\n Props,\n PropsCallback,\n SimpleValue,\n} from './types'\n\nexport type { ElementType, ExtendedProps, MaybeNull, ObjectValue, Props, PropsCallback, SimpleValue }\n\nexport default component\n","/**\n * List component that combines Iterator (data-driven rendering) with an\n * optional Element root wrapper. When `rootElement` is false (default),\n * it renders a bare Iterator as a fragment. When true, the Iterator output\n * is wrapped in an Element that receives all non-iterator props (e.g.,\n * layout, alignment, css), allowing the list to be styled as a single block.\n */\nimport { splitProps } from '@pyreon/core'\nimport { omit, pick } from '@pyreon/ui-core'\nimport { PKG_NAME } from '../constants'\nimport type { ElementProps, PyreonElement } from '../Element'\nimport { Element } from '../Element'\nimport type { Props as IteratorProps } from '../helpers/Iterator'\nimport Iterator from '../helpers/Iterator'\nimport type { MergeTypes } from '../types'\n\ntype ListProps = {\n /**\n * A boolean value. When set to `false`, component returns fragment.\n * When set to `true`, component returns as the **root** element `Element`\n * component.\n */\n rootElement?: boolean\n /**\n * Label prop from `Element` component is being ignored.\n */\n label: never\n /**\n * Content prop from `Element` component is being ignored.\n */\n content: never\n}\n\nexport type Props = MergeTypes<[IteratorProps, ListProps]> & Partial<Omit<ElementProps, 'children' | 'content' | 'label'>>\n\nconst Component: PyreonElement<Props> = ((allProps: Partial<Props & ElementProps>) => {\n const [own, props] = splitProps(allProps, ['rootElement', 'ref'])\n const renderedList = <Iterator {...pick(props, Iterator.RESERVED_PROPS)} />\n\n if (!own.rootElement) return renderedList\n\n return (\n <Element {...(own.ref ? { ref: own.ref } : {})} {...omit(props, Iterator.RESERVED_PROPS)}>\n {renderedList}\n </Element>\n )\n}) as PyreonElement<Props>\n\nconst name = `${PKG_NAME}/List` as const\n\nComponent.displayName = name\nComponent.pkgName = PKG_NAME\nComponent.PYREON__COMPONENT = name\n\nexport default Component\n","/**\n * Context for nested overlay coordination. When a child overlay opens, it\n * sets the parent's blocked state to true, preventing the parent from\n * closing in response to click/hover events that belong to the child.\n */\n\nimport type { VNodeChild } from '@pyreon/core'\nimport { createContext, provide, useContext } from '@pyreon/core'\n\nexport interface OverlayContext {\n blocked: boolean | (() => boolean)\n setBlocked: () => void\n setUnblocked: () => void\n}\n\nconst context = createContext<OverlayContext>({} as OverlayContext)\n\nexport const useOverlayContext = () => useContext(context)\n\nconst Component = (props: OverlayContext & { children: VNodeChild }) => {\n const ctx = {\n blocked: props.blocked,\n setBlocked: props.setBlocked,\n setUnblocked: props.setUnblocked,\n }\n\n provide(context, ctx)\n\n return <>{props.children}</>\n}\n\nexport default Component\n","/**\n * Pure positioning helpers for the Overlay component. Split out from\n * `useOverlay.tsx` so the SSR-fallback branches (`typeof window === 'undefined'`)\n * can be exercised directly by tests that stub `globalThis.window` — the\n * `useOverlay` hook itself runs these via event handlers registered inside\n * `onMount`, which are unreachable during module-level test imports in\n * happy-dom (where `window` is always defined).\n */\n\nexport type OverlayPosition = Partial<{\n top: number | string\n bottom: number | string\n left: number | string\n right: number | string\n}>\n\nexport type Align = 'bottom' | 'top' | 'left' | 'right'\nexport type AlignX = 'left' | 'center' | 'right'\nexport type AlignY = 'bottom' | 'top' | 'center'\n\nexport type PositionResult = {\n pos: OverlayPosition\n resolvedAlignX: AlignX\n resolvedAlignY: AlignY\n}\n\nconst sel = <T,>(cond: boolean, a: T, b: T): T => (cond ? a : b)\n\nexport const calcDropdownVertical = (\n c: DOMRect,\n t: DOMRect,\n align: 'top' | 'bottom',\n alignX: AlignX,\n offsetX: number,\n offsetY: number,\n): PositionResult => {\n // SSR-fallback: positioning only runs in the mounted browser context, but\n // the explicit guard documents the SSR-safety contract at the callsite\n // and lets `no-window-in-ssr` prove it locally. Return shape mirrors the\n // \"no element\" path below (empty `pos`, alignment preserved).\n if (typeof window === 'undefined') return { pos: {}, resolvedAlignX: alignX, resolvedAlignY: align }\n const pos: OverlayPosition = {}\n\n const topPos = t.top - offsetY - c.height\n const bottomPos = t.bottom + offsetY\n const leftPos = t.left + offsetX\n const rightPos = t.right - offsetX - c.width\n\n const fitsTop = topPos >= 0\n const fitsBottom = bottomPos + c.height <= window.innerHeight\n const fitsLeft = leftPos + c.width <= window.innerWidth\n const fitsRight = rightPos >= 0\n\n const useTop = sel(align === 'top', fitsTop, !fitsBottom)\n pos.top = sel(useTop, topPos, bottomPos)\n const resolvedAlignY: AlignY = sel(useTop, 'top', 'bottom')\n\n let resolvedAlignX: AlignX = alignX\n if (alignX === 'left') {\n pos.left = sel(fitsLeft, leftPos, rightPos)\n resolvedAlignX = sel(fitsLeft, 'left', 'right')\n } else if (alignX === 'right') {\n pos.left = sel(fitsRight, rightPos, leftPos)\n resolvedAlignX = sel(fitsRight, 'right', 'left')\n } else {\n const center = t.left + (t.right - t.left) / 2 - c.width / 2\n const fitsCL = center >= 0\n const fitsCR = center + c.width <= window.innerWidth\n\n if (fitsCL && fitsCR) {\n resolvedAlignX = 'center'\n pos.left = center\n } else if (fitsCL) {\n resolvedAlignX = 'left'\n pos.left = leftPos\n } else if (fitsCR) {\n resolvedAlignX = 'right'\n pos.left = rightPos\n }\n }\n\n return { pos, resolvedAlignX, resolvedAlignY }\n}\n\nexport const calcDropdownHorizontal = (\n c: DOMRect,\n t: DOMRect,\n align: 'left' | 'right',\n alignY: AlignY,\n offsetX: number,\n offsetY: number,\n): PositionResult => {\n if (typeof window === 'undefined') return { pos: {}, resolvedAlignX: align, resolvedAlignY: alignY }\n const pos: OverlayPosition = {}\n\n const leftPos = t.left - offsetX - c.width\n const rightPos = t.right + offsetX\n const topPos = t.top + offsetY\n const bottomPos = t.bottom - offsetY - c.height\n\n const fitsLeft = leftPos >= 0\n const fitsRight = rightPos + c.width <= window.innerWidth\n const fitsTop = topPos + c.height <= window.innerHeight\n const fitsBottom = bottomPos >= 0\n\n const useLeft = sel(align === 'left', fitsLeft, !fitsRight)\n pos.left = sel(useLeft, leftPos, rightPos)\n const resolvedAlignX: AlignX = sel(useLeft, 'left', 'right')\n\n let resolvedAlignY: AlignY = alignY\n if (alignY === 'top') {\n pos.top = sel(fitsTop, topPos, bottomPos)\n resolvedAlignY = sel(fitsTop, 'top', 'bottom')\n } else if (alignY === 'bottom') {\n pos.top = sel(fitsBottom, bottomPos, topPos)\n resolvedAlignY = sel(fitsBottom, 'bottom', 'top')\n } else {\n const center = t.top + (t.bottom - t.top) / 2 - c.height / 2\n const fitsCT = center >= 0\n const fitsCB = center + c.height <= window.innerHeight\n\n if (fitsCT && fitsCB) {\n resolvedAlignY = 'center'\n pos.top = center\n } else if (fitsCT) {\n resolvedAlignY = 'top'\n pos.top = topPos\n } else if (fitsCB) {\n resolvedAlignY = 'bottom'\n pos.top = bottomPos\n }\n }\n\n return { pos, resolvedAlignX, resolvedAlignY }\n}\n\nexport const calcModalPos = (\n c: DOMRect,\n alignX: AlignX,\n alignY: AlignY,\n offsetX: number,\n offsetY: number,\n): OverlayPosition => {\n if (typeof window === 'undefined') return {}\n const pos: OverlayPosition = {}\n\n switch (alignX) {\n case 'right':\n pos.right = offsetX\n break\n case 'left':\n pos.left = offsetX\n break\n case 'center':\n pos.left = window.innerWidth / 2 - c.width / 2\n break\n default:\n pos.right = offsetX\n }\n\n switch (alignY) {\n case 'top':\n pos.top = offsetY\n break\n case 'center':\n pos.top = window.innerHeight / 2 - c.height / 2\n break\n case 'bottom':\n pos.bottom = offsetY\n break\n default:\n pos.top = offsetY\n }\n\n return pos\n}\n\nexport const adjustForAncestor = (\n pos: OverlayPosition,\n ancestor: { top: number; left: number },\n): OverlayPosition => {\n if (ancestor.top === 0 && ancestor.left === 0) return pos\n\n const result = { ...pos }\n if (typeof result.top === 'number') result.top -= ancestor.top\n if (typeof result.bottom === 'number') result.bottom += ancestor.top\n if (typeof result.left === 'number') result.left -= ancestor.left\n if (typeof result.right === 'number') result.right += ancestor.left\n\n return result\n}\n","/**\n * Core hook powering the Overlay component. Manages open/close state, DOM\n * event listeners (click, hover, scroll, resize, ESC key), and dynamic\n * positioning of overlay content relative to its trigger. Supports dropdown,\n * tooltip, popover, and modal types with automatic edge-of-viewport flipping.\n * Event handlers are throttled for performance, and nested overlay blocking\n * is coordinated through the overlay context.\n */\n\nimport { signal } from '@pyreon/reactivity'\nimport { throttle } from '@pyreon/ui-core'\nimport { value } from '@pyreon/unistyle'\nimport { IS_DEVELOPMENT } from '../utils'\nimport Provider, { useOverlayContext } from './context'\nimport {\n adjustForAncestor,\n calcDropdownHorizontal,\n calcDropdownVertical,\n calcModalPos,\n type Align,\n type AlignX,\n type AlignY,\n type OverlayPosition,\n} from './positioning'\n\nexport type UseOverlayProps = Partial<{\n isOpen: boolean\n openOn: 'click' | 'hover' | 'manual'\n closeOn: 'click' | 'clickOnTrigger' | 'clickOutsideContent' | 'hover' | 'manual'\n type: 'dropdown' | 'tooltip' | 'popover' | 'modal' | 'custom'\n position: 'absolute' | 'fixed' | 'relative' | 'static'\n align: Align\n alignX: AlignX\n alignY: AlignY\n offsetX: number\n offsetY: number\n throttleDelay: number\n parentContainer: HTMLElement | null\n closeOnEsc: boolean\n hoverDelay: number\n disabled: boolean\n onOpen: () => void\n onClose: () => void\n}>\n\n// Reference counter for nested modals sharing document.body overflow lock.\nlet modalOverflowCount = 0\n\nconst devWarn = (msg: string) => {\n if (!IS_DEVELOPMENT) return\n // oxlint-disable-next-line no-console\n console.warn(msg)\n}\n\n\ntype ComputeResult = {\n pos: OverlayPosition\n resolvedAlignX?: AlignX\n resolvedAlignY?: AlignY\n}\n\nconst computePosition = (\n type: string,\n align: Align,\n alignX: AlignX,\n alignY: AlignY,\n offsetX: number,\n offsetY: number,\n triggerEl: HTMLElement | null,\n contentEl: HTMLElement | null,\n ancestorOffset: { top: number; left: number },\n): ComputeResult => {\n const isDropdown = ['dropdown', 'tooltip', 'popover'].includes(type)\n\n if (isDropdown && (!triggerEl || !contentEl)) {\n devWarn(\n `[@pyreon/elements] Overlay (${type}): ` +\n `${triggerEl ? 'contentRef' : 'triggerRef'} is not attached. ` +\n 'Position cannot be calculated without both refs.',\n )\n return { pos: {} }\n }\n\n if (isDropdown && triggerEl && contentEl) {\n const c = contentEl.getBoundingClientRect()\n const t = triggerEl.getBoundingClientRect()\n const result =\n align === 'top' || align === 'bottom'\n ? calcDropdownVertical(c, t, align, alignX, offsetX, offsetY)\n : calcDropdownHorizontal(c, t, align as 'left' | 'right', alignY, offsetX, offsetY)\n\n return {\n pos: adjustForAncestor(result.pos, ancestorOffset),\n resolvedAlignX: result.resolvedAlignX,\n resolvedAlignY: result.resolvedAlignY,\n }\n }\n\n if (type === 'modal') {\n if (!contentEl) {\n devWarn(\n '[@pyreon/elements] Overlay (modal): contentRef is not attached. ' +\n 'Modal position cannot be calculated without a content element.',\n )\n return { pos: {} }\n }\n const c = contentEl.getBoundingClientRect()\n return {\n pos: adjustForAncestor(calcModalPos(c, alignX, alignY, offsetX, offsetY), ancestorOffset),\n }\n }\n\n return { pos: {} }\n}\n\nconst processVisibilityEvent = (\n e: Event,\n active: boolean,\n openOn: string,\n closeOn: string,\n isTrigger: (evt: Event) => boolean,\n isContent: (evt: Event) => boolean,\n showContent: () => void,\n hideContent: () => void,\n) => {\n if (!active && openOn === 'click' && e.type === 'click' && isTrigger(e)) {\n showContent()\n return\n }\n\n if (!active) return\n\n if (closeOn === 'hover' && e.type === 'scroll') {\n hideContent()\n return\n }\n\n if (e.type !== 'click') return\n\n if (closeOn === 'click') {\n hideContent()\n } else if (closeOn === 'clickOnTrigger' && isTrigger(e)) {\n hideContent()\n } else if (closeOn === 'clickOutsideContent' && !isContent(e)) {\n hideContent()\n }\n}\n\nconst useOverlay = ({\n isOpen = false,\n openOn = 'click',\n closeOn = 'click',\n type = 'dropdown',\n position = 'fixed',\n align = 'bottom',\n alignX: propAlignX = 'left',\n alignY: propAlignY = 'bottom',\n offsetX = 0,\n offsetY = 0,\n throttleDelay = 200,\n parentContainer,\n closeOnEsc = true,\n hoverDelay = 100,\n disabled,\n onOpen,\n onClose,\n}: Partial<UseOverlayProps> = {}) => {\n const ctx = useOverlayContext()\n\n // Signal-based state\n const active = signal(isOpen)\n const isContentLoaded = signal(false)\n const innerAlignX = signal(propAlignX)\n const innerAlignY = signal(propAlignY)\n const blockedCount = signal(0)\n\n const blocked = () => blockedCount() > 0\n\n // DOM refs (plain variables, component runs once)\n let triggerEl: HTMLElement | null = null\n let contentEl: HTMLElement | null = null\n const _prevFocusEl: HTMLElement | null = null\n let hoverTimeout: ReturnType<typeof setTimeout> | null = null\n\n const triggerRef = (node: HTMLElement | null) => {\n triggerEl = node\n }\n\n const contentRefCallback = (node: HTMLElement | null) => {\n contentEl = node\n isContentLoaded.set(!!node)\n }\n\n const setBlocked = () => blockedCount.update((c) => c + 1)\n const setUnblocked = () => blockedCount.update((c) => Math.max(0, c - 1))\n\n const showContent = () => {\n active.set(true)\n onOpen?.()\n ctx.setBlocked?.()\n }\n\n const hideContent = () => {\n active.set(false)\n isContentLoaded.set(false)\n onClose?.()\n ctx.setUnblocked?.()\n }\n\n // Position calculation helpers\n const getAncestorOffset = () => {\n if (typeof document === 'undefined') return { top: 0, left: 0 }\n if (position !== 'absolute' || !contentEl) {\n return { top: 0, left: 0 }\n }\n\n const offsetParent = contentEl.offsetParent as HTMLElement | null\n if (!offsetParent || offsetParent === document.body) {\n return { top: 0, left: 0 }\n }\n\n const rect = offsetParent.getBoundingClientRect()\n return { top: rect.top, left: rect.left }\n }\n\n const calculateContentPosition = () => {\n if (!active() || !isContentLoaded()) return {}\n\n const result = computePosition(\n type,\n align,\n propAlignX,\n propAlignY,\n offsetX,\n offsetY,\n triggerEl,\n contentEl,\n getAncestorOffset(),\n )\n\n if (result.resolvedAlignX) innerAlignX.set(result.resolvedAlignX)\n if (result.resolvedAlignY) innerAlignY.set(result.resolvedAlignY)\n\n return result.pos\n }\n\n const assignContentPosition = (values: OverlayPosition = {}) => {\n if (!contentEl) return\n\n const el = contentEl\n const setValue = (param?: string | number) => value(param, 16) as string\n\n el.style.position = position\n\n el.style.top = values.top != null ? setValue(values.top) : ''\n el.style.bottom = values.bottom != null ? setValue(values.bottom) : ''\n el.style.left = values.left != null ? setValue(values.left) : ''\n el.style.right = values.right != null ? setValue(values.right) : ''\n }\n\n const setContentPosition = () => {\n const currentPosition = calculateContentPosition()\n assignContentPosition(currentPosition)\n }\n\n const isNodeOrChild = (getRef: () => HTMLElement | null) => (e: Event) => {\n const ref = getRef()\n if (e?.target && ref) {\n return ref.contains(e.target as Element) || e.target === ref\n }\n return false\n }\n\n const handleVisibilityByEventType = (e: Event) => {\n if (blocked() || disabled) return\n\n processVisibilityEvent(\n e,\n active(),\n openOn,\n closeOn,\n isNodeOrChild(() => triggerEl),\n isNodeOrChild(() => contentEl),\n showContent,\n hideContent,\n )\n }\n\n const handleContentPosition = throttle(() => setContentPosition(), throttleDelay)\n\n const handleClick = (e: Event) => handleVisibilityByEventType(e)\n\n const handleVisibility = throttle((e: Event) => handleVisibilityByEventType(e), throttleDelay)\n\n // --------------------------------------------------------------------------\n // Set up all event listeners on mount, clean up on unmount\n // --------------------------------------------------------------------------\n const setupListeners = () => {\n if (typeof window === 'undefined') return () => {}\n const cleanups: (() => void)[] = []\n\n // Click-based open/close\n const enabledClick =\n openOn === 'click' || ['click', 'clickOnTrigger', 'clickOutsideContent'].includes(closeOn)\n\n if (enabledClick) {\n window.addEventListener('click', handleClick)\n cleanups.push(() => window.removeEventListener('click', handleClick))\n }\n\n // ESC key\n if (closeOnEsc) {\n const handleEscKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && active() && !blocked()) {\n hideContent()\n }\n }\n window.addEventListener('keydown', handleEscKey)\n cleanups.push(() => window.removeEventListener('keydown', handleEscKey))\n }\n\n // Hover-based open/close\n const enabledHover = openOn === 'hover' || closeOn === 'hover'\n if (enabledHover) {\n const clearHoverTimeout = () => {\n if (hoverTimeout != null) {\n clearTimeout(hoverTimeout)\n hoverTimeout = null\n }\n }\n\n const scheduleHide = () => {\n clearHoverTimeout()\n hoverTimeout = setTimeout(hideContent, hoverDelay)\n }\n\n const onTriggerEnter = () => {\n clearHoverTimeout()\n if (openOn === 'hover' && !active()) showContent()\n }\n\n const onTriggerLeave = () => {\n if (closeOn === 'hover' && active()) scheduleHide()\n }\n\n const onContentEnter = () => {\n clearHoverTimeout()\n }\n\n const onContentLeave = () => {\n if (closeOn === 'hover' && active()) scheduleHide()\n }\n\n // We need to defer listener attachment until refs are available\n const attachHoverListeners = () => {\n if (triggerEl) {\n triggerEl.addEventListener('mouseenter', onTriggerEnter)\n triggerEl.addEventListener('mouseleave', onTriggerLeave)\n }\n if (contentEl) {\n contentEl.addEventListener('mouseenter', onContentEnter)\n contentEl.addEventListener('mouseleave', onContentLeave)\n }\n }\n\n attachHoverListeners()\n\n cleanups.push(() => {\n clearHoverTimeout()\n if (triggerEl) {\n triggerEl.removeEventListener('mouseenter', onTriggerEnter)\n triggerEl.removeEventListener('mouseleave', onTriggerLeave)\n }\n if (contentEl) {\n contentEl.removeEventListener('mouseenter', onContentEnter)\n contentEl.removeEventListener('mouseleave', onContentLeave)\n }\n })\n }\n\n // Resize/scroll repositioning\n const shouldSetOverflow = type === 'modal'\n\n const onScroll = (e: Event) => {\n handleContentPosition()\n handleVisibility(e)\n }\n\n if (shouldSetOverflow) {\n modalOverflowCount++\n if (modalOverflowCount === 1) document.body.style.overflow = 'hidden'\n }\n\n window.addEventListener('resize', handleContentPosition)\n window.addEventListener('scroll', onScroll, { passive: true })\n cleanups.push(() => {\n handleContentPosition.cancel()\n handleVisibility.cancel()\n if (shouldSetOverflow) {\n modalOverflowCount--\n if (modalOverflowCount === 0) document.body.style.overflow = ''\n }\n window.removeEventListener('resize', handleContentPosition)\n window.removeEventListener('scroll', onScroll)\n })\n\n // Parent container scroll\n if (parentContainer) {\n if (closeOn !== 'hover') parentContainer.style.overflow = 'hidden'\n\n const onParentScroll = (e: Event) => {\n handleContentPosition()\n handleVisibility(e)\n }\n\n parentContainer.addEventListener('scroll', onParentScroll, {\n passive: true,\n })\n cleanups.push(() => {\n parentContainer.style.overflow = ''\n parentContainer.removeEventListener('scroll', onParentScroll)\n })\n }\n\n // Cleanup function\n return () => {\n for (const cleanup of cleanups) cleanup()\n }\n }\n\n // Handle disabled state\n if (disabled) {\n active.set(false)\n }\n\n return {\n triggerRef,\n contentRef: contentRefCallback,\n active,\n align,\n alignX: innerAlignX,\n alignY: innerAlignY,\n showContent,\n hideContent,\n blocked,\n setBlocked,\n setUnblocked,\n setupListeners,\n Provider,\n }\n}\n\nexport default useOverlay\n","/**\n * Overlay component that renders a trigger element and conditionally shows\n * content via a Portal. The trigger receives a ref and optional show/hide\n * callbacks; the content is positioned and managed by the useOverlay hook.\n * A context Provider wraps the content to support nested overlays (e.g.,\n * a dropdown inside another dropdown) via blocked-state propagation.\n */\n\nimport type { VNodeChild } from '@pyreon/core'\nimport { onMount, Portal, splitProps } from '@pyreon/core'\nimport { render } from '@pyreon/ui-core'\nimport { PKG_NAME } from '../constants'\nimport type { Content, PyreonComponent } from '../types'\nimport useOverlay, { type UseOverlayProps } from './useOverlay'\n\nconst IS_BROWSER = typeof window !== 'undefined'\n\ntype Align = 'bottom' | 'top' | 'left' | 'right'\ntype AlignX = 'left' | 'center' | 'right'\ntype AlignY = 'bottom' | 'top' | 'center'\n\ntype TriggerRenderer = (\n props: Partial<{\n active: boolean\n showContent: () => void\n hideContent: () => void\n }>,\n) => VNodeChild\n\ntype ContentRenderer = (\n props: Partial<{\n active: boolean\n showContent: () => void\n hideContent: () => void\n align: Align\n alignX: AlignX\n alignY: AlignY\n }>,\n) => VNodeChild\n\nexport type Props = {\n children: ContentRenderer | Content\n trigger: TriggerRenderer | Content\n DOMLocation?: HTMLElement\n triggerRefName?: string\n contentRefName?: string\n} & UseOverlayProps\n\nconst Component: PyreonComponent<Props> = (props) => {\n const [own, overlayProps] = splitProps(props, [\n 'children',\n 'trigger',\n 'DOMLocation',\n 'triggerRefName',\n 'contentRefName',\n ])\n\n const triggerRefName = own.triggerRefName ?? 'ref'\n const contentRefName = own.contentRefName ?? 'ref'\n\n const {\n active,\n triggerRef,\n contentRef,\n showContent,\n hideContent,\n align,\n alignX,\n alignY,\n setupListeners,\n Provider,\n ...ctx\n } = useOverlay(overlayProps)\n\n const { openOn, closeOn, type } = overlayProps\n\n const passHandlers =\n openOn === 'manual' || closeOn === 'manual' || closeOn === 'clickOutsideContent'\n\n const ariaHasPopup = (() => {\n switch (type) {\n case 'modal':\n return 'dialog' as const\n case 'tooltip':\n return 'true' as const\n default:\n return 'menu' as const\n }\n })()\n\n // Set up event listeners on mount\n onMount(() => {\n const cleanup = setupListeners()\n return cleanup\n })\n\n return (\n <>\n {render(own.trigger, {\n [triggerRefName]: triggerRef,\n active: active(),\n 'aria-expanded': active(),\n 'aria-haspopup': ariaHasPopup,\n ...(passHandlers ? { showContent, hideContent } : {}),\n })}\n\n {() =>\n IS_BROWSER && active() ? (\n <Portal target={own.DOMLocation ?? document.body}>\n <Provider {...ctx}>\n {render(own.children, {\n [contentRefName]: contentRef,\n role: type === 'modal' ? 'dialog' : undefined,\n 'aria-modal': type === 'modal' ? true : undefined,\n active: active(),\n align,\n alignX: alignX(),\n alignY: alignY(),\n ...(passHandlers ? { showContent, hideContent } : {}),\n })}\n </Provider>\n </Portal>\n ) : null\n }\n </>\n )\n}\n\nconst name = `${PKG_NAME}/Overlay` as const\n\nComponent.displayName = name\nComponent.pkgName = PKG_NAME\nComponent.PYREON__COMPONENT = name\n\nexport default Component\n","/**\n * Portal component stub. In Pyreon, the actual Portal is provided by\n * @pyreon/core's runtime-dom. This component re-exports it for API\n * compatibility with the elements package structure.\n */\n\nimport type { VNodeChild } from '@pyreon/core'\nimport { Portal as CorePortal } from '@pyreon/core'\nimport { PKG_NAME } from '../constants'\nimport type { PyreonComponent } from '../types'\n\nexport interface Props {\n /**\n * Defines a HTML DOM where children to be appended.\n */\n DOMLocation?: HTMLElement\n /**\n * Children to be rendered within **Portal** component.\n */\n children: VNodeChild\n /**\n * Valid HTML Tag\n */\n tag?: string\n}\n\nconst Component: PyreonComponent<Props> = (props) => {\n const target = props.DOMLocation ?? (typeof document !== 'undefined' ? document.body : undefined)\n\n if (!target) return null\n\n return <CorePortal target={target}>{props.children}</CorePortal>\n}\n\nconst name = `${PKG_NAME}/Portal` as const\n\nComponent.displayName = name\nComponent.pkgName = PKG_NAME\nComponent.PYREON__COMPONENT = name\n\nexport default Component\n","/**\n * Styled text primitive that inherits color, font-weight, and line-height\n * from its parent so it blends seamlessly into any context. Additional\n * styles can be injected via the responsive `extraStyles` prop processed\n * through makeItResponsive.\n */\nimport { config } from '@pyreon/ui-core'\nimport { extendCss, makeItResponsive } from '@pyreon/unistyle'\nimport type { ResponsiveStylesCallback } from '../types'\n\nconst { styled, css, textComponent } = config\n\nconst styles: ResponsiveStylesCallback = ({ css: cssFn, theme: t }) => cssFn`\n ${t.extraStyles && extendCss(t.extraStyles)};\n`\n\nexport default styled(textComponent, { layer: 'elements' })`\n ${css`\n color: inherit;\n font-weight: inherit;\n line-height: 1;\n `};\n\n ${makeItResponsive({\n key: '$text',\n styles,\n css,\n normalize: false,\n })};\n`\n","/**\n * Text component for rendering inline or block-level text. Supports a\n * `paragraph` shorthand that automatically renders as a `<p>` tag, or\n * a custom `tag` for semantic HTML (h1-h6, span, etc.). Marked with\n * a static `isText` flag so other components can detect text children.\n */\n\nimport { splitProps } from '@pyreon/core'\nimport type { PyreonHTMLAttributes, VNodeChild } from '@pyreon/core'\nimport type { HTMLTextTags } from '@pyreon/ui-core'\nimport { PKG_NAME } from '../constants'\nimport type { ExtendCss, PyreonComponent } from '../types'\nimport Styled from './styled'\n\nexport type Props = Partial<{\n /**\n * Label can be used instead of children for inline syntax. But **children** prop takes a precedence\n */\n label: VNodeChild\n /**\n * Children to be rendered within **Text** component.\n */\n children: VNodeChild\n /**\n * Defines whether should behave as a block text element. Automatically adds **p** HTML tag\n */\n paragraph: boolean\n /**\n * Defines what kind of HTML tag should be rendered\n */\n tag: HTMLTextTags\n /**\n * If an additional styling needs to be added, it can be do so via injecting styles using this property.\n */\n css: ExtendCss\n}> &\n PyreonHTMLAttributes\n\nconst Component: PyreonComponent<Props> & {\n isText?: true\n} = (props) => {\n const [own, rest] = splitProps(props, ['paragraph', 'label', 'children', 'tag', 'css', 'ref'])\n\n let finalTag: string | undefined\n\n if (own.paragraph) finalTag = 'p'\n else {\n finalTag = own.tag\n }\n\n return (\n <Styled ref={own.ref} as={finalTag} $text={{ extraStyles: own.css }} {...rest}>\n {own.children ?? own.label}\n </Styled>\n )\n}\n\n// ----------------------------------------------\n// DEFINE STATICS\n// ----------------------------------------------\nconst name = `${PKG_NAME}/Text` as const\n\nComponent.displayName = name\nComponent.pkgName = PKG_NAME\nComponent.PYREON__COMPONENT = name\nComponent.isText = true\n\nexport default Component\n","/**\n * Utility wrapper that injects className and/or style props into its\n * children without adding any DOM nodes of its own. Uses the core `render`\n * helper to clone children with the merged props.\n */\n\nimport type { VNode, VNodeChild } from '@pyreon/core'\nimport { render } from '@pyreon/ui-core'\nimport { PKG_NAME } from '../constants'\nimport type { PyreonComponent } from '../types'\n\nexport interface Props {\n /**\n * Children to be rendered within **Util** component.\n */\n children: VNodeChild\n /**\n * Class name(s) to be added to children component.\n */\n className?: string | string[] | undefined\n /**\n * Style property to extend children component inline styles\n */\n style?: Record<string, unknown> | undefined\n}\n\nconst Component: PyreonComponent<Props> = (({ children, className, style }: Props) => {\n const mergedClasses = Array.isArray(className) ? className.join(' ') : className\n\n const finalProps: Record<string, any> = {}\n if (style) finalProps.style = style\n if (mergedClasses) finalProps.className = mergedClasses\n\n return render(children, finalProps) as VNode | null\n}) as PyreonComponent<Props>\n\nconst name = `${PKG_NAME}/Util` as const\n\nComponent.displayName = name\nComponent.pkgName = PKG_NAME\nComponent.PYREON__COMPONENT = name\n\nexport default Component\n"],"mappings":"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"}