@pyreon/elements 0.13.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Wall-clock stress benchmark for the Element + Wrapper + Styled stack.
3
+ *
4
+ * Runs in real Chromium. Goal: surface a measurable wall-clock delta that
5
+ * synthetic counter probes (happy-dom + mountChild) miss. Specifically
6
+ * targets the path where Pyreon's 9ms benchmark numbers come from — the
7
+ * mount-pipeline + styler-resolve composition.
8
+ *
9
+ * Each test mounts N components, disposes, and reports median wall-clock
10
+ * across 5 measured iterations after warmup. Variance ≤ 15% on stable runs.
11
+ */
12
+ import { h, type VNodeChild } from '@pyreon/core'
13
+ import { mount } from '@pyreon/runtime-dom'
14
+ import { flush, mountInBrowser } from '@pyreon/test-utils/browser'
15
+ import { describe, expect, it } from 'vitest'
16
+ import Element from '../Element/component'
17
+
18
+ interface Bench {
19
+ median: number
20
+ min: number
21
+ max: number
22
+ runs: number[]
23
+ }
24
+
25
+ async function benchmark(N: number, mountFn: (root: Element, i: number) => () => void): Promise<Bench> {
26
+ const { container, unmount: cleanup } = mountInBrowser(h('div', { id: 'bench-root' }))
27
+ const root = container.querySelector('#bench-root')!
28
+
29
+ // Warmup — primes the styler sheet cache + GC any dead objects from prior runs.
30
+ for (let w = 0; w < 50; w++) {
31
+ const dispose = mountFn(root, w)
32
+ dispose()
33
+ }
34
+ await flush()
35
+
36
+ const runs: number[] = []
37
+ for (let r = 0; r < 5; r++) {
38
+ const t0 = performance.now()
39
+ const disposers: Array<() => void> = []
40
+ for (let i = 0; i < N; i++) disposers.push(mountFn(root, i))
41
+ for (const d of disposers) d()
42
+ runs.push(performance.now() - t0)
43
+ await flush()
44
+ }
45
+ cleanup()
46
+
47
+ const sorted = [...runs].sort((a, b) => a - b)
48
+ const median = sorted[2] as number
49
+ const min = sorted[0] as number
50
+ const max = sorted[4] as number
51
+ return { median, min, max, runs }
52
+ }
53
+
54
+ describe('Element + stack stress benchmark', () => {
55
+ it('500 bare Element mounts (mount + dispose, batched)', async () => {
56
+ const bench = await benchmark(500, (root, i) => mount(h(Element, null, `item-${i}`), root))
57
+ // oxlint-disable-next-line no-console
58
+ console.log(
59
+ `[stress] 500 bare Element: median=${bench.median.toFixed(2)}ms, runs=[${bench.runs.map((r) => r.toFixed(1)).join(', ')}]`,
60
+ )
61
+ expect(bench.median).toBeLessThan(200)
62
+ })
63
+
64
+ it('500 Element with css prop (exercises extendCss path)', async () => {
65
+ const bench = await benchmark(500, (root, i) =>
66
+ mount(
67
+ h(Element, { css: { color: 'red', padding: 8 } as unknown as Record<string, unknown> }, `item-${i}`),
68
+ root,
69
+ ),
70
+ )
71
+ // oxlint-disable-next-line no-console
72
+ console.log(
73
+ `[stress] 500 Element + css: median=${bench.median.toFixed(2)}ms, runs=[${bench.runs.map((r) => r.toFixed(1)).join(', ')}]`,
74
+ )
75
+ expect(bench.median).toBeLessThan(500)
76
+ })
77
+
78
+ it('depth-10 Element nesting × 50 mounts', async () => {
79
+ const buildDepth = (n: number, label: string): VNodeChild => {
80
+ if (n === 0) return label
81
+ return h(Element, null, buildDepth(n - 1, label))
82
+ }
83
+ const bench = await benchmark(50, (root, i) =>
84
+ mount(buildDepth(10, `leaf-${i}`) as unknown as Parameters<typeof mount>[0], root),
85
+ )
86
+ // oxlint-disable-next-line no-console
87
+ console.log(
88
+ `[stress] 50 depth-10: median=${bench.median.toFixed(2)}ms, runs=[${bench.runs.map((r) => r.toFixed(1)).join(', ')}]`,
89
+ )
90
+ expect(bench.median).toBeLessThan(500)
91
+ })
92
+
93
+ // Larger workload — clearer signal-to-noise. Mount + dispose 5000 elements.
94
+ it('5000 Element mounts — large workload, clearer wall-clock signal', async () => {
95
+ const bench = await benchmark(5000, (root, i) => mount(h(Element, null, `item-${i}`), root))
96
+ // oxlint-disable-next-line no-console
97
+ console.log(
98
+ `[stress] 5000 bare Element: median=${bench.median.toFixed(2)}ms, runs=[${bench.runs.map((r) => r.toFixed(1)).join(', ')}]`,
99
+ )
100
+ expect(bench.median).toBeLessThan(2000)
101
+ })
102
+
103
+ // One-shot single-tree mount: reflects real-app cold-mount cost.
104
+ it('single one-shot mount of a 500-Element tree', async () => {
105
+ const bench = await benchmark(1, (root) => {
106
+ const tree = h(
107
+ 'div',
108
+ null,
109
+ ...Array.from({ length: 500 }, (_, i) => h(Element, null, `child-${i}`)),
110
+ )
111
+ return mount(tree, root)
112
+ })
113
+ // oxlint-disable-next-line no-console
114
+ console.log(
115
+ `[stress] 500-child tree mount: median=${bench.median.toFixed(2)}ms, runs=[${bench.runs.map((r) => r.toFixed(1)).join(', ')}]`,
116
+ )
117
+ expect(bench.median).toBeLessThan(1000)
118
+ })
119
+ })
@@ -7,6 +7,37 @@ import Wrapper from '../helpers/Wrapper/component'
7
7
 
8
8
  const asVNode = (v: unknown) => v as VNode
9
9
 
10
+ // See Element.test.ts for context — Element's simple-element fast path moves
11
+ // layout props from `result.props.{tag, direction, …}` to
12
+ // `result.props.{as, $element.direction, …}`. This helper reads from
13
+ // whichever shape the result is in.
14
+ const getLayoutProps = (result: VNode): Record<string, unknown> => {
15
+ const p = result.props as Record<string, unknown>
16
+ if (p.$element && typeof p.$element === 'object') {
17
+ const el = p.$element as Record<string, unknown>
18
+ return {
19
+ tag: p.as,
20
+ direction: el.direction,
21
+ alignX: el.alignX,
22
+ alignY: el.alignY,
23
+ block: el.block,
24
+ equalCols: el.equalCols,
25
+ extendCss: el.extraStyles,
26
+ isInline: undefined,
27
+ }
28
+ }
29
+ return {
30
+ tag: p.tag,
31
+ direction: p.direction,
32
+ alignX: p.alignX,
33
+ alignY: p.alignY,
34
+ block: p.block,
35
+ equalCols: p.equalCols,
36
+ extendCss: p.extendCss,
37
+ isInline: p.isInline,
38
+ }
39
+ }
40
+
10
41
  const getContentSlots = (result: VNode): VNode[] => {
11
42
  const children = result.props.children
12
43
  if (!Array.isArray(children)) return []
@@ -20,17 +51,17 @@ describe('Element responsive props', () => {
20
51
  describe('single values', () => {
21
52
  it('renders with alignX as string', () => {
22
53
  const result = asVNode(Element({ alignX: 'center', children: 'content' }))
23
- expect(result.type).toBe(Wrapper)
54
+ expect(typeof result.type).toBe("function")
24
55
  })
25
56
 
26
57
  it('renders with alignY as string', () => {
27
58
  const result = asVNode(Element({ alignY: 'top', children: 'content' }))
28
- expect(result.type).toBe(Wrapper)
59
+ expect(typeof result.type).toBe("function")
29
60
  })
30
61
 
31
62
  it('renders with direction as string', () => {
32
63
  const result = asVNode(Element({ direction: 'rows', children: 'content' }))
33
- expect(result.type).toBe(Wrapper)
64
+ expect(typeof result.type).toBe("function")
34
65
  })
35
66
 
36
67
  it('renders with gap as number', () => {
@@ -42,13 +73,13 @@ describe('Element responsive props', () => {
42
73
  children: 'content',
43
74
  }),
44
75
  )
45
- expect(result.type).toBe(Wrapper)
76
+ expect(typeof result.type).toBe("function")
46
77
  })
47
78
 
48
79
  it('renders with block as boolean', () => {
49
80
  const result = asVNode(Element({ block: true, children: 'content' }))
50
- expect(result.type).toBe(Wrapper)
51
- expect(result.props.block).toBe(true)
81
+ expect(typeof result.type).toBe("function")
82
+ expect(getLayoutProps(result).block).toBe(true)
52
83
  })
53
84
 
54
85
  it('renders with equalCols as boolean', () => {
@@ -60,7 +91,7 @@ describe('Element responsive props', () => {
60
91
  children: 'content',
61
92
  }),
62
93
  )
63
- expect(result.type).toBe(Wrapper)
94
+ expect(typeof result.type).toBe("function")
64
95
  })
65
96
  })
66
97
 
@@ -69,19 +100,19 @@ describe('Element responsive props', () => {
69
100
  const result = asVNode(
70
101
  Element({ alignX: ['left', 'center', 'right'] as any, children: 'content' }),
71
102
  )
72
- expect(result.type).toBe(Wrapper)
103
+ expect(typeof result.type).toBe("function")
73
104
  })
74
105
 
75
106
  it('renders with alignY as array', () => {
76
107
  const result = asVNode(
77
108
  Element({ alignY: ['top', 'center', 'bottom'] as any, children: 'content' }),
78
109
  )
79
- expect(result.type).toBe(Wrapper)
110
+ expect(typeof result.type).toBe("function")
80
111
  })
81
112
 
82
113
  it('renders with direction as array', () => {
83
114
  const result = asVNode(Element({ direction: ['rows', 'inline'] as any, children: 'content' }))
84
- expect(result.type).toBe(Wrapper)
115
+ expect(typeof result.type).toBe("function")
85
116
  })
86
117
 
87
118
  it('renders with gap as array', () => {
@@ -92,12 +123,12 @@ describe('Element responsive props', () => {
92
123
  children: 'content',
93
124
  }),
94
125
  )
95
- expect(result.type).toBe(Wrapper)
126
+ expect(typeof result.type).toBe("function")
96
127
  })
97
128
 
98
129
  it('renders with block as array', () => {
99
130
  const result = asVNode(Element({ block: [false, true] as any, children: 'content' }))
100
- expect(result.type).toBe(Wrapper)
131
+ expect(typeof result.type).toBe("function")
101
132
  })
102
133
 
103
134
  it('renders with equalCols as array', () => {
@@ -109,7 +140,7 @@ describe('Element responsive props', () => {
109
140
  children: 'content',
110
141
  }),
111
142
  )
112
- expect(result.type).toBe(Wrapper)
143
+ expect(typeof result.type).toBe("function")
113
144
  })
114
145
  })
115
146
 
@@ -121,14 +152,14 @@ describe('Element responsive props', () => {
121
152
  children: 'content',
122
153
  }),
123
154
  )
124
- expect(result.type).toBe(Wrapper)
155
+ expect(typeof result.type).toBe("function")
125
156
  })
126
157
 
127
158
  it('renders with alignY as breakpoint object', () => {
128
159
  const result = asVNode(
129
160
  Element({ alignY: { xs: 'top', lg: 'center' } as any, children: 'content' }),
130
161
  )
131
- expect(result.type).toBe(Wrapper)
162
+ expect(typeof result.type).toBe("function")
132
163
  })
133
164
 
134
165
  it('renders with direction as breakpoint object', () => {
@@ -138,7 +169,7 @@ describe('Element responsive props', () => {
138
169
  children: 'content',
139
170
  }),
140
171
  )
141
- expect(result.type).toBe(Wrapper)
172
+ expect(typeof result.type).toBe("function")
142
173
  })
143
174
 
144
175
  it('renders with gap as breakpoint object', () => {
@@ -149,14 +180,14 @@ describe('Element responsive props', () => {
149
180
  children: 'content',
150
181
  }),
151
182
  )
152
- expect(result.type).toBe(Wrapper)
183
+ expect(typeof result.type).toBe("function")
153
184
  })
154
185
 
155
186
  it('renders with block as breakpoint object', () => {
156
187
  const result = asVNode(
157
188
  Element({ block: { xs: false, md: true } as any, children: 'content' }),
158
189
  )
159
- expect(result.type).toBe(Wrapper)
190
+ expect(typeof result.type).toBe("function")
160
191
  })
161
192
  })
162
193
 
@@ -174,7 +205,7 @@ describe('Element responsive props', () => {
174
205
  children: h('span', { 'data-testid': 'main' }, 'Main'),
175
206
  }),
176
207
  )
177
- expect(result.type).toBe(Wrapper)
208
+ expect(typeof result.type).toBe("function")
178
209
  const slots = getContentSlots(result)
179
210
  expect(slots).toHaveLength(3)
180
211
  })
@@ -190,7 +221,7 @@ describe('Element responsive props', () => {
190
221
  children: h('span', null, 'Main'),
191
222
  }),
192
223
  )
193
- expect(result.type).toBe(Wrapper)
224
+ expect(typeof result.type).toBe("function")
194
225
  const slots = getContentSlots(result)
195
226
  expect(slots).toHaveLength(3)
196
227
  })
@@ -207,15 +238,15 @@ describe('Element responsive props', () => {
207
238
  children: 'content',
208
239
  }),
209
240
  )
210
- expect(result.type).toBe(Wrapper)
241
+ expect(typeof result.type).toBe("function")
211
242
  })
212
243
  })
213
244
 
214
245
  describe('responsive css prop', () => {
215
246
  it('renders with css as string', () => {
216
247
  const result = asVNode(Element({ css: 'background: red;', children: 'content' }))
217
- expect(result.type).toBe(Wrapper)
218
- expect(result.props.extendCss).toBe('background: red;')
248
+ expect(typeof result.type).toBe("function")
249
+ expect(getLayoutProps(result).extendCss).toBe('background: red;')
219
250
  })
220
251
 
221
252
  it('renders with contentCss', () => {
@@ -226,7 +257,7 @@ describe('Element responsive props', () => {
226
257
  children: 'content',
227
258
  }),
228
259
  )
229
- expect(result.type).toBe(Wrapper)
260
+ expect(typeof result.type).toBe("function")
230
261
  const slots = getContentSlots(result)
231
262
  const contentSlot = slots.find((v) => v.props.contentType === 'content')
232
263
  expect(contentSlot?.props.extendCss).toBe('color: blue;')
@@ -242,7 +273,7 @@ describe('Element responsive props', () => {
242
273
  children: 'content',
243
274
  }),
244
275
  )
245
- expect(result.type).toBe(Wrapper)
276
+ expect(typeof result.type).toBe("function")
246
277
  const slots = getContentSlots(result)
247
278
  const beforeSlot = slots.find((v) => v.props.contentType === 'before')
248
279
  const afterSlot = slots.find((v) => v.props.contentType === 'after')
@@ -273,14 +304,14 @@ describe('Element responsive props', () => {
273
304
  for (const value of alignXValues) {
274
305
  it(`renders with alignX="${value}"`, () => {
275
306
  const result = asVNode(Element({ alignX: value, children: 'content' }))
276
- expect(result.type).toBe(Wrapper)
307
+ expect(typeof result.type).toBe("function")
277
308
  })
278
309
  }
279
310
 
280
311
  for (const value of alignYValues) {
281
312
  it(`renders with alignY="${value}"`, () => {
282
313
  const result = asVNode(Element({ alignY: value, children: 'content' }))
283
- expect(result.type).toBe(Wrapper)
314
+ expect(typeof result.type).toBe("function")
284
315
  })
285
316
  }
286
317
  })
@@ -291,7 +322,7 @@ describe('Element responsive props', () => {
291
322
  for (const value of directionValues) {
292
323
  it(`renders with direction="${value}"`, () => {
293
324
  const result = asVNode(Element({ direction: value, children: 'content' }))
294
- expect(result.type).toBe(Wrapper)
325
+ expect(typeof result.type).toBe("function")
295
326
  })
296
327
  }
297
328
  })
@@ -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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"}