@pyreon/styler 0.24.4 → 0.24.6

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.
Files changed (47) hide show
  1. package/package.json +5 -7
  2. package/src/ThemeProvider.ts +0 -65
  3. package/src/__tests__/ThemeProvider.test.ts +0 -67
  4. package/src/__tests__/benchmark.bench.ts +0 -200
  5. package/src/__tests__/composition-chain.test.ts +0 -537
  6. package/src/__tests__/css.test.ts +0 -70
  7. package/src/__tests__/dev-gate-treeshake.test.ts +0 -85
  8. package/src/__tests__/forward.test.ts +0 -282
  9. package/src/__tests__/globalStyle.test.ts +0 -72
  10. package/src/__tests__/hash.test.ts +0 -70
  11. package/src/__tests__/hybrid-injection.test.ts +0 -225
  12. package/src/__tests__/index.ts +0 -14
  13. package/src/__tests__/inject-rules.browser.test.ts +0 -40
  14. package/src/__tests__/insertion-effect.test.ts +0 -119
  15. package/src/__tests__/integration-dom.test.ts +0 -58
  16. package/src/__tests__/integration.test.ts +0 -179
  17. package/src/__tests__/keyframes.test.ts +0 -68
  18. package/src/__tests__/memory-growth.test.ts +0 -220
  19. package/src/__tests__/native-marker.test.ts +0 -9
  20. package/src/__tests__/p3-features.test.ts +0 -316
  21. package/src/__tests__/resolve-cache.test.ts +0 -94
  22. package/src/__tests__/resolve.test.ts +0 -308
  23. package/src/__tests__/shared.test.ts +0 -133
  24. package/src/__tests__/sheet-advanced.test.ts +0 -659
  25. package/src/__tests__/sheet-split-atrules.test.ts +0 -410
  26. package/src/__tests__/sheet.test.ts +0 -250
  27. package/src/__tests__/static-styler-resolve-cost.test.ts +0 -160
  28. package/src/__tests__/styled-reactive.test.ts +0 -74
  29. package/src/__tests__/styled-ssr.test.ts +0 -75
  30. package/src/__tests__/styled.test.ts +0 -511
  31. package/src/__tests__/styler.browser.test.tsx +0 -194
  32. package/src/__tests__/theme.test.ts +0 -33
  33. package/src/__tests__/useCSS.test.ts +0 -172
  34. package/src/css.ts +0 -13
  35. package/src/env.d.ts +0 -6
  36. package/src/forward.ts +0 -308
  37. package/src/globalStyle.ts +0 -53
  38. package/src/hash.ts +0 -28
  39. package/src/index.ts +0 -15
  40. package/src/keyframes.ts +0 -36
  41. package/src/manifest.ts +0 -332
  42. package/src/resolve.ts +0 -225
  43. package/src/shared.ts +0 -22
  44. package/src/sheet.ts +0 -635
  45. package/src/styled.tsx +0 -503
  46. package/src/tests/manifest-snapshot.test.ts +0 -51
  47. package/src/useCSS.ts +0 -20
@@ -1,160 +0,0 @@
1
- /**
2
- * Measurement gate: per-mount cost of a fully-static `styled()` component.
3
- *
4
- * BACKGROUND. "Proposed compiler win #2 — static styler extraction" theorised
5
- * that a fully-static styled component (`styled('div')`\`color: red\``, no
6
- * function interpolations) wastes a per-mount `styler.resolve`, and that a
7
- * bounded runtime memo slice could be carved out of the (multi-week,
8
- * roadmap-scale) compile-time extraction effort. This gate MEASURES that
9
- * premise with the real `styler.resolve` / `styler.staticVNode.hit` /
10
- * `styler.sheet.insert*` perf counters and DISPROVES it for the runtime
11
- * layer: the static path is already optimal.
12
- *
13
- * WHAT THE COUNTERS PROVE (the contrast IS the proof — self-discriminating,
14
- * no fake fix to revert; same shape as the static-text baking gate):
15
- *
16
- * Fully-static `styled('div')`\`color: red\`` (values.length === 0):
17
- * - `createStyledComponent` takes `raw = strings[0]` — `resolve()` is
18
- * NEVER called → `styler.resolve` === 0 for the lifetime.
19
- * - `sheet.insert` fires EXACTLY ONCE at component-creation time
20
- * (definition, not mount) → `styler.sheet.insert` === 1.
21
- * - Every mount with no extra props returns the pre-built
22
- * `cachedEmptyVNode` → `styler.staticVNode.hit` === N, with ZERO
23
- * additional resolve / sheet work per mount.
24
- *
25
- * Contrast — function-interpolated `styled('div')`\`color: ${p => p.c}\``
26
- * with NO `$rocketstyle` / `$element` identity (the only shape that DOES
27
- * re-resolve per call): `styler.resolve` === N. This is CORRECT, not waste
28
- * — the CSS genuinely depends on per-call props; and real-app shapes
29
- * (rocketstyle dimensions, Element `$element` interning) already hit
30
- * `classCache` / `elClassCache` so they collapse to ~0 (proven elsewhere:
31
- * PR #344 dimension memo, the `$element` interning gate). So #2's runtime
32
- * layer needs no fix; the remaining #2 surface is purely compile-time /
33
- * bundle (don't ship the styled wrapper + sheet.insert for provably-static
34
- * CSS at all) — that is the roadmap item, deliberately NOT half-built here.
35
- *
36
- * Bisect note: there is intentionally no fix to revert. The discriminating
37
- * assertion is `static.resolve === 0 && dynamic.resolve === N` in the SAME
38
- * run — if the static path ever regressed to per-mount resolve, the static
39
- * block's `toBe(0)` fails while the dynamic block still passes, pinpointing
40
- * the regression to the static fast path specifically.
41
- */
42
- import { afterEach, beforeEach, describe, expect, it } from 'vitest'
43
- import { sheet } from '../sheet'
44
- import { styled } from '../styled'
45
-
46
- type Sink = { __pyreon_count__?: (name: string, n?: number) => void }
47
- const g = globalThis as Sink
48
-
49
- let counts: Map<string, number>
50
-
51
- const get = (name: string): number => counts.get(name) ?? 0
52
-
53
- beforeEach(() => {
54
- counts = new Map()
55
- g.__pyreon_count__ = (name: string, n = 1) => {
56
- counts.set(name, (counts.get(name) ?? 0) + n)
57
- }
58
- })
59
-
60
- afterEach(() => {
61
- delete g.__pyreon_count__
62
- // clearAll (not reset) — fires onSheetClear so styled.tsx's
63
- // staticComponentCache / _hotCache reset between cases; otherwise the
64
- // single-entry hot cache leaks a prior case's component.
65
- sheet.clearAll()
66
- })
67
-
68
- const N = 100
69
-
70
- describe('static styled() per-mount cost (measurement gate)', () => {
71
- it('a fully-static component resolves ZERO times and inserts ONCE, regardless of mount count', () => {
72
- // Distinct source-location template literal → its own
73
- // TemplateStringsArray identity (independent of every other case).
74
- const Comp = styled('div')`
75
- color: red;
76
- padding: 4px;
77
- `
78
-
79
- // The sheet.insert at *definition* time already happened above. Snapshot
80
- // AFTER definition so the per-mount measurement is isolated from the
81
- // one-time creation cost.
82
- const insertsAtDefinition = get('styler.sheet.insert')
83
- expect(insertsAtDefinition).toBe(1) // exactly one — at creation, not mount
84
- expect(get('styler.resolve')).toBe(0) // values.length===0 → raw=strings[0], no resolve()
85
-
86
- for (let i = 0; i < N; i++) Comp({})
87
-
88
- // THE PROOF: N mounts added ZERO resolves and ZERO new sheet inserts.
89
- expect(get('styler.resolve')).toBe(0)
90
- expect(get('styler.sheet.insert')).toBe(1) // still just the creation insert
91
- expect(get('styler.sheet.insert.hit')).toBe(0) // never re-inserted
92
- // Every mount took the pre-built cachedEmptyVNode fast path.
93
- expect(get('styler.staticVNode.hit')).toBe(N)
94
- })
95
-
96
- it('two distinct static components: 2 inserts total, 0 resolves, N/2 hits each', () => {
97
- const A = styled('div')`
98
- color: blue;
99
- `
100
- const B = styled('span')`
101
- color: green;
102
- `
103
- expect(get('styler.sheet.insert')).toBe(2) // one per definition
104
- expect(get('styler.resolve')).toBe(0)
105
-
106
- for (let i = 0; i < N / 2; i++) {
107
- A({})
108
- B({})
109
- }
110
-
111
- expect(get('styler.resolve')).toBe(0)
112
- expect(get('styler.sheet.insert')).toBe(2)
113
- expect(get('styler.staticVNode.hit')).toBe(N) // N/2 + N/2
114
- })
115
-
116
- it('CONTRAST — a function-interpolated styled with no rocketstyle/$element identity DOES resolve per call (correct, not waste)', () => {
117
- const Dyn = styled('div')<{ c: string }>`
118
- color: ${(p) => p.c};
119
- `
120
- // No object $rocketstyle / $rocketstate / $element on rawProps → neither
121
- // classCache nor elClassCache can fire; doResolve() runs every call.
122
- // Same prop value each call → cssText identical → sheet dedups (hit).
123
- for (let i = 0; i < N; i++) Dyn({ c: 'red' })
124
-
125
- expect(get('styler.resolve')).toBe(N) // genuinely per-call (CSS depends on props)
126
- expect(get('styler.staticVNode.hit')).toBe(0) // never the static fast path
127
- // `styler.sheet.insert` counts every insert() CALL (one per mount here);
128
- // `.hit` is the dedup subset — identical cssText each call, so all but
129
- // the first hit the insertCache and inject NO new DOM rule. The dynamic
130
- // path still pays the resolve() + the insert() call-overhead per mount;
131
- // only the actual rule injection is deduped. That call-overhead is the
132
- // residual the rocketstyle/$element identity caches (classCache /
133
- // elClassCache) eliminate in real-app shapes — proven elsewhere.
134
- expect(get('styler.sheet.insert')).toBe(N) // one insert() call per mount
135
- expect(get('styler.sheet.insert.hit')).toBe(N - 1) // first builds cache, rest dedup
136
- })
137
-
138
- it('SELF-DISCRIMINATING — static.resolve===0 AND dynamic.resolve===N in one run', () => {
139
- const Static = styled('div')`
140
- margin: 8px;
141
- `
142
- counts = new Map() // isolate from the definition insert
143
- for (let i = 0; i < N; i++) Static({})
144
- const staticResolve = get('styler.resolve')
145
-
146
- const Dyn = styled('div')<{ c: string }>`
147
- color: ${(p) => p.c};
148
- `
149
- counts = new Map()
150
- for (let i = 0; i < N; i++) Dyn({ c: 'blue' })
151
- const dynResolve = get('styler.resolve')
152
-
153
- // The discriminator: if the static fast path ever regressed to
154
- // per-mount resolve, this is the assertion that pinpoints it — the
155
- // static side moves off 0 while the dynamic side stays at N.
156
- expect(staticResolve).toBe(0)
157
- expect(dynResolve).toBe(N)
158
- expect(dynResolve - staticResolve).toBe(N)
159
- })
160
- })
@@ -1,74 +0,0 @@
1
- import type { VNode } from '@pyreon/core'
2
- import { pushContext } from '@pyreon/core'
3
- import { signal } from '@pyreon/reactivity'
4
- import { afterEach, describe, expect, it } from 'vitest'
5
- import { sheet } from '../sheet'
6
- import { styled } from '../styled'
7
- import { ThemeContext } from '../ThemeProvider'
8
-
9
- describe('DynamicStyled reactive class path', () => {
10
- afterEach(() => {
11
- sheet.reset()
12
- })
13
-
14
- function withTheme(fn: () => void) {
15
- // Push a reactive ThemeContext so useThemeAccessor() works inside Comp
16
- pushContext(new Map([[ThemeContext.id, () => ({}) as any]]))
17
- fn()
18
- }
19
-
20
- it('creates a VNode with class when $rocketstyle is a function accessor', () => {
21
- const modeSig = signal<'light' | 'dark'>('light')
22
- const rsAccessor = () => ({
23
- color: modeSig() === 'light' ? 'red' : 'blue',
24
- })
25
- const rsStateAccessor = () => ({ state: 'default' })
26
-
27
- const Comp = styled('div')`
28
- color: ${(p: any) => p.$rocketstyle?.color ?? 'black'};
29
- `
30
-
31
- let vnode: VNode | null = null
32
- withTheme(() => {
33
- vnode = Comp({ $rocketstyle: rsAccessor, $rocketstate: rsStateAccessor }) as VNode
34
- })
35
-
36
- expect(vnode).toBeTruthy()
37
- // The VNode has a class from initial resolve
38
- expect(vnode!.props.class).toBeTruthy()
39
- expect(typeof vnode!.props.class).toBe('string')
40
- expect(vnode!.props.class).toContain('pyr-')
41
- })
42
-
43
- it('static $rocketstyle (plain object) also resolves correctly', () => {
44
- const Comp = styled('div')`
45
- color: ${(p: any) => p.$rocketstyle?.color ?? 'black'};
46
- `
47
-
48
- let vnode: VNode | null = null
49
- withTheme(() => {
50
- vnode = Comp({ $rocketstyle: { color: 'green' }, $rocketstate: { state: 'x' } }) as VNode
51
- })
52
-
53
- expect(vnode).toBeTruthy()
54
- expect(vnode!.props.class).toBeTruthy()
55
- expect(typeof vnode!.props.class).toBe('string')
56
- })
57
-
58
- it('ref callback is wired when reactive path is active', () => {
59
- const rsAccessor = () => ({ color: 'red' })
60
- const rsStateAccessor = () => ({ state: 'default' })
61
-
62
- const Comp = styled('div')`
63
- color: ${(p: any) => p.$rocketstyle?.color};
64
- `
65
-
66
- let vnode: VNode | null = null
67
- withTheme(() => {
68
- vnode = Comp({ $rocketstyle: rsAccessor, $rocketstate: rsStateAccessor }) as VNode
69
- })
70
-
71
- // The reactive path wires a ref callback for classList mutation
72
- expect(typeof vnode!.props.ref).toBe('function')
73
- })
74
- })
@@ -1,75 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2
-
3
- /**
4
- * SSR tests for styled() and createGlobalStyle(). Re-imports modules
5
- * with `document` deleted so IS_SERVER evaluates to true.
6
- */
7
- describe('styled -- SSR mode', () => {
8
- let originalDocument: typeof document
9
-
10
- beforeEach(() => {
11
- vi.resetModules()
12
- originalDocument = globalThis.document
13
- // @ts-expect-error - intentionally deleting for SSR simulation
14
- delete globalThis.document
15
- })
16
-
17
- afterEach(() => {
18
- globalThis.document = originalDocument
19
- })
20
-
21
- it('static: creates component with SSR injection path', async () => {
22
- const { styled } = await import('../styled')
23
- const Comp = styled('div')`
24
- color: red;
25
- `
26
- expect((Comp as any).displayName).toBe('styled(div)')
27
- })
28
-
29
- it('static: empty CSS template in SSR', async () => {
30
- const { styled } = await import('../styled')
31
- const Comp = styled('div')``
32
- expect((Comp as any).displayName).toBe('styled(div)')
33
- })
34
-
35
- it('static: boost option in SSR', async () => {
36
- const { styled } = await import('../styled')
37
- const Comp = styled('div', { layer: 'rocketstyle' })`
38
- color: blue;
39
- `
40
- expect((Comp as any).displayName).toBe('styled(div)')
41
- })
42
-
43
- it('static: shouldForwardProp in SSR', async () => {
44
- const { styled } = await import('../styled')
45
- const Comp = styled('div', {
46
- shouldForwardProp: (p) => p !== 'color',
47
- })`
48
- display: flex;
49
- `
50
- expect((Comp as any).displayName).toBe('styled(div)')
51
- })
52
-
53
- it('static: styled.div shorthand in SSR', async () => {
54
- const { styled } = await import('../styled')
55
- const Comp = styled.div`
56
- color: green;
57
- `
58
- expect((Comp as any).displayName).toBe('styled(div)')
59
- })
60
-
61
- it('createGlobalStyle: static SSR path', async () => {
62
- const { createGlobalStyle } = await import('../globalStyle')
63
- const GlobalStyle = createGlobalStyle`body { margin: 0; }`
64
- // Static path injects immediately and returns a function that produces null
65
- const result = GlobalStyle({})
66
- expect(result).toBeNull()
67
- })
68
-
69
- it('createGlobalStyle: empty CSS in SSR returns null', async () => {
70
- const { createGlobalStyle } = await import('../globalStyle')
71
- const GlobalStyle = createGlobalStyle``
72
- const result = GlobalStyle({})
73
- expect(result).toBeNull()
74
- })
75
- })