@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,282 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { buildProps, filterProps } from '../forward'
3
-
4
- describe('filterProps', () => {
5
- describe('keeps standard HTML props', () => {
6
- it('keeps id', () => {
7
- const result = filterProps({ id: 'test' })
8
- expect(result.id).toBe('test')
9
- })
10
-
11
- it('keeps className', () => {
12
- const result = filterProps({ className: 'foo' })
13
- expect(result.className).toBe('foo')
14
- })
15
-
16
- it('keeps style', () => {
17
- const style = { color: 'red' }
18
- const result = filterProps({ style })
19
- expect(result.style).toBe(style)
20
- })
21
-
22
- it('keeps href', () => {
23
- const result = filterProps({ href: '/path' })
24
- expect(result.href).toBe('/path')
25
- })
26
-
27
- it('keeps disabled', () => {
28
- const result = filterProps({ disabled: true })
29
- expect(result.disabled).toBe(true)
30
- })
31
-
32
- it('keeps multiple standard props at once', () => {
33
- const result = filterProps({
34
- id: 'main',
35
- tabIndex: 0,
36
- role: 'button',
37
- title: 'Click me',
38
- })
39
- expect(result).toEqual({
40
- id: 'main',
41
- tabIndex: 0,
42
- role: 'button',
43
- title: 'Click me',
44
- })
45
- })
46
- })
47
-
48
- describe('keeps data-* attributes', () => {
49
- it('keeps data-testid', () => {
50
- const result = filterProps({ 'data-testid': 'hello' })
51
- expect(result['data-testid']).toBe('hello')
52
- })
53
-
54
- it('keeps data-custom', () => {
55
- const result = filterProps({ 'data-custom': 'value' })
56
- expect(result['data-custom']).toBe('value')
57
- })
58
- })
59
-
60
- describe('keeps aria-* attributes', () => {
61
- it('keeps aria-label', () => {
62
- const result = filterProps({ 'aria-label': 'Close' })
63
- expect(result['aria-label']).toBe('Close')
64
- })
65
-
66
- it('keeps aria-hidden', () => {
67
- const result = filterProps({ 'aria-hidden': true })
68
- expect(result['aria-hidden']).toBe(true)
69
- })
70
-
71
- it('keeps aria-describedby', () => {
72
- const result = filterProps({ 'aria-describedby': 'desc' })
73
- expect(result['aria-describedby']).toBe('desc')
74
- })
75
- })
76
-
77
- describe('keeps event handlers', () => {
78
- it('keeps onClick', () => {
79
- const fn = () => undefined
80
- const result = filterProps({ onClick: fn })
81
- expect(result.onClick).toBe(fn)
82
- })
83
-
84
- it('keeps onMouseEnter', () => {
85
- const fn = () => undefined
86
- const result = filterProps({ onMouseEnter: fn })
87
- expect(result.onMouseEnter).toBe(fn)
88
- })
89
-
90
- it('keeps onKeyDown', () => {
91
- const fn = () => undefined
92
- const result = filterProps({ onKeyDown: fn })
93
- expect(result.onKeyDown).toBe(fn)
94
- })
95
- })
96
-
97
- describe('strips $-prefixed transient props', () => {
98
- it('strips $rocketstyle', () => {
99
- const result = filterProps({ $rocketstyle: { color: 'red' } })
100
- expect(result).toEqual({})
101
- })
102
-
103
- it('strips $element', () => {
104
- const result = filterProps({ $element: 'button' })
105
- expect(result).toEqual({})
106
- })
107
-
108
- it('strips $active', () => {
109
- const result = filterProps({ $active: true })
110
- expect(result).toEqual({})
111
- })
112
-
113
- it('strips multiple $-prefixed props while keeping valid ones', () => {
114
- const result = filterProps({
115
- $rocketstyle: {},
116
- $element: 'div',
117
- id: 'test',
118
- 'data-x': 'y',
119
- })
120
- expect(result).toEqual({ id: 'test', 'data-x': 'y' })
121
- })
122
- })
123
-
124
- describe('strips as prop', () => {
125
- it('strips the as prop', () => {
126
- const result = filterProps({ as: 'button' })
127
- expect(result).toEqual({})
128
- })
129
-
130
- it('strips as while keeping other props', () => {
131
- const result = filterProps({ as: 'section', id: 'main' })
132
- expect(result).toEqual({ id: 'main' })
133
- })
134
- })
135
-
136
- describe('strips unknown props', () => {
137
- it('strips customProp', () => {
138
- const result = filterProps({ customProp: 'value' })
139
- expect(result).toEqual({})
140
- })
141
-
142
- it('strips myThing', () => {
143
- const result = filterProps({ myThing: 42 })
144
- expect(result).toEqual({})
145
- })
146
-
147
- it('strips camelCase unknown props', () => {
148
- const result = filterProps({ isActive: true, backgroundColor: 'red' })
149
- expect(result).toEqual({})
150
- })
151
-
152
- it('returns empty object for all-unknown props', () => {
153
- const result = filterProps({
154
- foo: 1,
155
- bar: 2,
156
- baz: 3,
157
- customThing: 'x',
158
- })
159
- expect(result).toEqual({})
160
- })
161
- })
162
- })
163
-
164
- describe('buildProps', () => {
165
- describe('className merging', () => {
166
- it('merges generatedCls with user className', () => {
167
- const result = buildProps({ className: 'custom' }, 'pyr-abc', true)
168
- expect(result.class).toBe('pyr-abc custom')
169
- })
170
-
171
- it('merges generatedCls with user class', () => {
172
- const result = buildProps({ class: 'custom' }, 'pyr-abc', true)
173
- expect(result.class).toBe('pyr-abc custom')
174
- })
175
-
176
- it('uses only generatedCls when no user className', () => {
177
- const result = buildProps({}, 'pyr-abc', true)
178
- expect(result.class).toBe('pyr-abc')
179
- })
180
-
181
- it('uses only user className when generatedCls is empty', () => {
182
- const result = buildProps({ className: 'custom' }, '', true)
183
- expect(result.class).toBe('custom')
184
- })
185
-
186
- it('sets no class when both are empty/missing', () => {
187
- const result = buildProps({}, '', true)
188
- expect(result.class).toBeUndefined()
189
- })
190
- })
191
-
192
- describe('isDOM=false (component target)', () => {
193
- it('forwards all props except as, className, class, and $-prefixed', () => {
194
- const result = buildProps(
195
- {
196
- as: 'button',
197
- className: 'user',
198
- customProp: 'hello',
199
- $rocketstyle: {},
200
- $rocketstate: { hover: true },
201
- 'data-x': 'y',
202
- onClick: () => undefined,
203
- },
204
- 'pyr-abc',
205
- false,
206
- )
207
-
208
- expect(result.customProp).toBe('hello')
209
- expect(result.$rocketstyle).toBeUndefined()
210
- expect(result.$rocketstate).toBeUndefined()
211
- expect(result['data-x']).toBe('y')
212
- expect(result.onClick).toBeDefined()
213
- // as and className are not forwarded from rawProps (class is merged separately)
214
- expect(result.as).toBeUndefined()
215
- expect(result.class).toBe('pyr-abc user')
216
- })
217
- })
218
-
219
- describe('isDOM=true (default filtering)', () => {
220
- it('filters unknown DOM props', () => {
221
- const result = buildProps({ customProp: 'hello', unknownThing: 42 }, 'pyr-abc', true)
222
- expect(result.customProp).toBeUndefined()
223
- expect(result.unknownThing).toBeUndefined()
224
- expect(result.class).toBe('pyr-abc')
225
- })
226
-
227
- it('strips $-prefixed props', () => {
228
- const result = buildProps({ $rocketstyle: {}, $active: true, id: 'test' }, 'pyr-abc', true)
229
- expect(result.$rocketstyle).toBeUndefined()
230
- expect(result.$active).toBeUndefined()
231
- expect(result.id).toBe('test')
232
- })
233
-
234
- it('keeps data-* and aria-* attributes', () => {
235
- const result = buildProps({ 'data-testid': 'btn', 'aria-label': 'Close' }, 'pyr-abc', true)
236
- expect(result['data-testid']).toBe('btn')
237
- expect(result['aria-label']).toBe('Close')
238
- })
239
-
240
- it('keeps standard HTML attributes', () => {
241
- const result = buildProps({ id: 'main', disabled: true, tabIndex: 0 }, 'pyr-abc', true)
242
- expect(result.id).toBe('main')
243
- expect(result.disabled).toBe(true)
244
- expect(result.tabIndex).toBe(0)
245
- })
246
-
247
- it('strips as prop', () => {
248
- const result = buildProps({ as: 'section' }, 'pyr-abc', true)
249
- expect(result.as).toBeUndefined()
250
- })
251
- })
252
-
253
- describe('isDOM=true with customFilter', () => {
254
- it('uses customFilter to decide which props to forward', () => {
255
- const customFilter = (prop: string) => prop.startsWith('my')
256
- const result = buildProps(
257
- { myProp: 'yes', otherProp: 'no', id: 'skip' },
258
- 'pyr-abc',
259
- true,
260
- customFilter,
261
- )
262
- expect(result.myProp).toBe('yes')
263
- expect(result.otherProp).toBeUndefined()
264
- expect(result.id).toBeUndefined()
265
- })
266
-
267
- it('customFilter still skips as and className from rawProps', () => {
268
- const customFilter = () => true
269
- const result = buildProps(
270
- { as: 'button', className: 'user', id: 'test' },
271
- 'pyr-abc',
272
- true,
273
- customFilter,
274
- )
275
- // as is always skipped
276
- expect(result.as).toBeUndefined()
277
- // class is merged, not forwarded from rawProps
278
- expect(result.class).toBe('pyr-abc user')
279
- expect(result.id).toBe('test')
280
- })
281
- })
282
- })
@@ -1,72 +0,0 @@
1
- import { afterEach, describe, expect, it } from 'vitest'
2
- import { createGlobalStyle } from '../globalStyle'
3
- import { sheet } from '../sheet'
4
-
5
- describe('createGlobalStyle -- empty CSS paths', () => {
6
- afterEach(() => {
7
- sheet.clearAll()
8
- })
9
-
10
- it('static: returns null for empty template', () => {
11
- const GlobalStyle = createGlobalStyle``
12
- const result = GlobalStyle({})
13
- expect(result).toBeNull()
14
- })
15
-
16
- it('static: returns null for whitespace-only template', () => {
17
- const GlobalStyle = createGlobalStyle` `
18
- const result = GlobalStyle({})
19
- expect(result).toBeNull()
20
- })
21
-
22
- it('dynamic: returns null when interpolation resolves to empty CSS', () => {
23
- const GlobalStyle = createGlobalStyle`${({ theme }: any) => (theme.empty ? '' : '')}`
24
- const result = GlobalStyle({})
25
- expect(result).toBeNull()
26
- })
27
-
28
- it('dynamic: returns null when interpolation resolves to whitespace', () => {
29
- const GlobalStyle = createGlobalStyle`${() => ' '}`
30
- const result = GlobalStyle({})
31
- expect(result).toBeNull()
32
- })
33
- })
34
-
35
- describe('createGlobalStyle', () => {
36
- afterEach(() => {
37
- sheet.clearAll()
38
- })
39
-
40
- it('returns a component function', () => {
41
- const GlobalStyle = createGlobalStyle`
42
- body { margin: 0; }
43
- `
44
- expect(typeof GlobalStyle).toBe('function')
45
- })
46
-
47
- it('renders nothing (returns null)', () => {
48
- const GlobalStyle = createGlobalStyle`
49
- body { margin: 0; padding: 0; }
50
- `
51
- const result = GlobalStyle({})
52
- expect(result).toBeNull()
53
- })
54
-
55
- it('handles dynamic interpolations with theme', () => {
56
- // Dynamic path: function interpolation causes per-render resolution
57
- const GlobalStyle = createGlobalStyle`
58
- body { font-family: ${({ theme }: any) => theme?.font ?? 'sans-serif'}; }
59
- `
60
- const result = GlobalStyle({})
61
- expect(result).toBeNull()
62
- })
63
-
64
- it('handles static interpolations', () => {
65
- const color = 'red'
66
- const GlobalStyle = createGlobalStyle`
67
- body { color: ${color}; }
68
- `
69
- const result = GlobalStyle({})
70
- expect(result).toBeNull()
71
- })
72
- })
@@ -1,70 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { hash } from '../hash'
3
-
4
- describe('hash', () => {
5
- it('returns a string', () => {
6
- expect(typeof hash('test')).toBe('string')
7
- })
8
-
9
- it('is deterministic — same input always produces same output', () => {
10
- const input = 'display: flex; color: red;'
11
- expect(hash(input)).toBe(hash(input))
12
- })
13
-
14
- it('produces different hashes for different inputs', () => {
15
- expect(hash('color: red')).not.toBe(hash('color: blue'))
16
- })
17
-
18
- it('returns base-36 string (compact)', () => {
19
- const result = hash('some css')
20
- expect(result).toMatch(/^[0-9a-z]+$/)
21
- })
22
-
23
- it('handles empty string', () => {
24
- const result = hash('')
25
- expect(typeof result).toBe('string')
26
- expect(result.length).toBeGreaterThan(0)
27
- })
28
-
29
- it('handles long CSS strings', () => {
30
- const longCSS = 'display: flex; '.repeat(100)
31
- const result = hash(longCSS)
32
- expect(typeof result).toBe('string')
33
- // base-36 uint32 is at most 7 chars
34
- expect(result.length).toBeLessThan(10)
35
- })
36
-
37
- it('handles special characters in CSS', () => {
38
- const css = `@media (min-width: 48em) { .foo { content: "hello"; } }`
39
- const result = hash(css)
40
- expect(typeof result).toBe('string')
41
- })
42
-
43
- it('produces consistent hash for FNV-1a offset basis on empty string', () => {
44
- // Empty string: h stays at FNV_OFFSET = 2166136261, base36 = "zzzzzz" range
45
- const result = hash('')
46
- // Just verify it is stable
47
- expect(result).toBe(hash(''))
48
- })
49
-
50
- it('handles unicode characters', () => {
51
- const result = hash('content: "🎉";')
52
- expect(typeof result).toBe('string')
53
- expect(result.length).toBeGreaterThan(0)
54
- })
55
-
56
- it('single character inputs produce distinct hashes', () => {
57
- const hashes = new Set<string>()
58
- for (let i = 0; i < 26; i++) {
59
- hashes.add(hash(String.fromCharCode(97 + i)))
60
- }
61
- // All 26 lowercase letters should hash to unique values
62
- expect(hashes.size).toBe(26)
63
- })
64
-
65
- it('hash is unsigned 32-bit (no negative values)', () => {
66
- // base-36 of a uint32 is always positive
67
- const result = hash('test negative')
68
- expect(Number.parseInt(result, 36)).toBeGreaterThanOrEqual(0)
69
- })
70
- })
@@ -1,225 +0,0 @@
1
- /**
2
- * Tests for the hybrid injection approach:
3
- * - Client (jsdom): shared <style data-pyreon-styler> sheet
4
- * - CSS rules present in the CSSOM sheet after insertion
5
- * - `layer` option threaded from styled() through to the sheet
6
- *
7
- * Ported to VNode-level testing: we call the component function directly
8
- * and inspect the returned VNode + the sheet's CSSOM.
9
- */
10
-
11
- import type { VNode } from '@pyreon/core'
12
- import { afterEach, describe, expect, it, vi } from 'vitest'
13
- import { createGlobalStyle } from '../globalStyle'
14
- import { sheet } from '../sheet'
15
- import { styled } from '../styled'
16
-
17
- /** Helper: collect all CSS rule texts from the shared <style data-pyreon-styler> sheet. */
18
- const getSheetRules = (): string[] => {
19
- const el = document.querySelector('style[data-pyreon-styler]') as HTMLStyleElement | null
20
- if (!el?.sheet) return []
21
- return Array.from(el.sheet.cssRules).map((r) => r.cssText)
22
- }
23
-
24
- /** Helper: find rules matching a className in the CSSOM. */
25
- const findRulesFor = (className: string): string[] =>
26
- getSheetRules().filter((r) => r.includes(`.${className}`))
27
-
28
- describe('hybrid injection — CSS in shared sheet', () => {
29
- afterEach(() => {
30
- sheet.clearAll()
31
- })
32
-
33
- describe('static styled components', () => {
34
- it('injects CSS rules into the shared <style data-pyreon-styler> element', () => {
35
- const Comp = styled('div')`
36
- color: red;
37
- `
38
- const vnode = Comp({}) as VNode
39
- const className = vnode.props.class as string
40
-
41
- const rules = findRulesFor(className)
42
- expect(rules.length).toBeGreaterThanOrEqual(1)
43
- expect(rules.some((r) => r.includes('color: red'))).toBe(true)
44
- })
45
-
46
- it('multiple static components share the same <style> element', () => {
47
- const A = styled('div')`
48
- color: red;
49
- `
50
- const B = styled('span')`
51
- font-size: 20px;
52
- `
53
-
54
- A({})
55
- B({})
56
-
57
- // Both should be in the same sheet
58
- const styleEls = document.querySelectorAll('style[data-pyreon-styler]')
59
- expect(styleEls.length).toBe(1)
60
-
61
- const rules = getSheetRules()
62
- expect(rules.some((r) => r.includes('color: red'))).toBe(true)
63
- expect(rules.some((r) => r.includes('font-size: 20px'))).toBe(true)
64
- })
65
- })
66
-
67
- describe('dynamic styled components', () => {
68
- it('injects CSS into the shared sheet', () => {
69
- const Comp = styled('div')`
70
- color: ${(p: any) => p.$color};
71
- `
72
- const vnode = Comp({ $color: 'blue' }) as VNode
73
- const className = vnode.props.class as string
74
-
75
- const rules = findRulesFor(className)
76
- expect(rules.length).toBeGreaterThanOrEqual(1)
77
- expect(rules.some((r) => r.includes('color: blue'))).toBe(true)
78
- })
79
-
80
- it('different prop values inject different CSS rules into the sheet', () => {
81
- const Comp = styled('div')`
82
- color: ${(p: any) => p.$color};
83
- `
84
- const vnode1 = Comp({ $color: 'red' }) as VNode
85
- const cls1 = vnode1.props.class as string
86
-
87
- const vnode2 = Comp({ $color: 'green' }) as VNode
88
- const cls2 = vnode2.props.class as string
89
-
90
- expect(cls1).not.toBe(cls2)
91
-
92
- // Both rules should be in the sheet
93
- expect(findRulesFor(cls1).some((r) => r.includes('color: red'))).toBe(true)
94
- expect(findRulesFor(cls2).some((r) => r.includes('color: green'))).toBe(true)
95
- })
96
- })
97
-
98
- describe('createGlobalStyle', () => {
99
- it('static global styles are injected into the shared sheet', () => {
100
- const GlobalStyle = createGlobalStyle`
101
- body { margin: 0; }
102
- `
103
- // Static global styles are injected at creation time
104
- GlobalStyle({})
105
-
106
- const rules = getSheetRules()
107
- expect(rules.some((r) => r.includes('margin') && r.includes('0'))).toBe(true)
108
- })
109
- })
110
- })
111
-
112
- describe('hybrid injection — VNode output (no <style> in tree)', () => {
113
- afterEach(() => {
114
- sheet.clearAll()
115
- })
116
-
117
- describe('styled components', () => {
118
- it('static component returns a VNode of the correct tag', () => {
119
- const Comp = styled('div')`
120
- color: red;
121
- `
122
- const vnode = Comp({}) as VNode
123
-
124
- // Should return a VNode for <div>, not a <style>
125
- expect(vnode.type).toBe('div')
126
- })
127
-
128
- it('dynamic component returns a VNode of the correct tag', () => {
129
- const Comp = styled('div')`
130
- color: ${(p: any) => p.$color};
131
- `
132
- const vnode = Comp({ $color: 'red' }) as VNode
133
-
134
- expect(vnode.type).toBe('div')
135
- })
136
-
137
- it('multiple styled components produce correct VNode types', () => {
138
- const A = styled('div')`
139
- color: red;
140
- `
141
- const B = styled('span')`
142
- color: blue;
143
- `
144
-
145
- const vnodeA = A({}) as VNode
146
- const vnodeB = B({}) as VNode
147
-
148
- expect(vnodeA.type).toBe('div')
149
- expect(vnodeB.type).toBe('span')
150
- })
151
- })
152
-
153
- describe('createGlobalStyle', () => {
154
- it('static global style returns null', () => {
155
- const GlobalStyle = createGlobalStyle`body { margin: 0; }`
156
- const result = GlobalStyle({})
157
-
158
- expect(result).toBeNull()
159
- })
160
- })
161
- })
162
-
163
- describe('hybrid injection — layer option at component level', () => {
164
- afterEach(() => {
165
- sheet.clearAll()
166
- })
167
-
168
- it('static layered component generates className', () => {
169
- const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
170
- const Comp = styled('div', { layer: 'rocketstyle' })`
171
- color: red;
172
- `
173
- const vnode = Comp({}) as VNode
174
- const className = vnode.props.class as string
175
-
176
- // className is generated regardless of CSSOM @layer support
177
- expect(className).toMatch(/^pyr-/)
178
- warnSpy.mockRestore()
179
- })
180
-
181
- it('dynamic layered component generates className', () => {
182
- const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
183
- const Comp = styled('div', { layer: 'rocketstyle' })`
184
- color: ${(p: any) => p.$color};
185
- `
186
- const vnode = Comp({ $color: 'blue' }) as VNode
187
- const className = vnode.props.class as string
188
-
189
- // className is generated regardless of CSSOM @layer support
190
- expect(className).toMatch(/^pyr-/)
191
- warnSpy.mockRestore()
192
- })
193
-
194
- it('default sheet component produces valid className and injects rule', () => {
195
- const Comp = styled('div')`
196
- color: green;
197
- `
198
- const vnode = Comp({}) as VNode
199
- const className = vnode.props.class as string
200
-
201
- expect(className).toMatch(/^pyr-/)
202
- // In environments without @layer support (happy-dom), rules are inserted
203
- // without layer wrapping. In real browsers, they'd be in @layer pyreon.
204
- const rules = findRulesFor(className)
205
- expect(rules.length).toBeGreaterThanOrEqual(1)
206
- const baseRule = rules[0] as string
207
- expect(baseRule).toContain(`.${className}`)
208
- expect(baseRule).toContain('color: green')
209
- })
210
-
211
- it('layered component with @media generates className', () => {
212
- const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
213
- const Comp = styled('div', { layer: 'rocketstyle' })`
214
- color: red;
215
- @media (min-width: 768px) {
216
- font-size: 20px;
217
- }
218
- `
219
- const vnode = Comp({}) as VNode
220
- const className = vnode.props.class as string
221
-
222
- expect(className).toMatch(/^pyr-/)
223
- warnSpy.mockRestore()
224
- })
225
- })
@@ -1,14 +0,0 @@
1
- /**
2
- * Test barrel / helper file.
3
- * Re-exports commonly used test utilities from the styler source.
4
- */
5
- export { css } from '../css'
6
- export { createGlobalStyle } from '../globalStyle'
7
- export { HASH_INIT, hash, hashFinalize, hashUpdate } from '../hash'
8
- export { keyframes } from '../keyframes'
9
- export type { CSSResult, Interpolation } from '../resolve'
10
- export { clearNormCache, normalizeCSS, resolve, resolveValue } from '../resolve'
11
- export type { StyleSheetOptions } from '../sheet'
12
- export { createSheet, StyleSheet, sheet } from '../sheet'
13
- export { styled } from '../styled'
14
- export { ThemeContext, ThemeProvider, useTheme } from '../ThemeProvider'