@pyreon/styler 0.11.4 → 0.11.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 (36) hide show
  1. package/README.md +27 -23
  2. package/lib/index.d.ts +9 -2
  3. package/lib/index.js +47 -4
  4. package/package.json +22 -22
  5. package/src/ThemeProvider.ts +10 -3
  6. package/src/__tests__/ThemeProvider.test.ts +21 -21
  7. package/src/__tests__/benchmark.bench.ts +56 -45
  8. package/src/__tests__/composition-chain.test.ts +200 -151
  9. package/src/__tests__/forward.test.ts +122 -122
  10. package/src/__tests__/globalStyle.test.ts +18 -18
  11. package/src/__tests__/hash.test.ts +27 -27
  12. package/src/__tests__/hybrid-injection.test.ts +83 -59
  13. package/src/__tests__/index.ts +10 -10
  14. package/src/__tests__/insertion-effect.test.ts +45 -32
  15. package/src/__tests__/integration.test.ts +81 -51
  16. package/src/__tests__/keyframes.test.ts +13 -13
  17. package/src/__tests__/memory-growth.test.ts +21 -21
  18. package/src/__tests__/p3-features.test.ts +162 -104
  19. package/src/__tests__/shared.test.ts +51 -33
  20. package/src/__tests__/sheet-advanced.test.ts +227 -227
  21. package/src/__tests__/sheet-split-atrules.test.ts +85 -85
  22. package/src/__tests__/sheet.test.ts +69 -69
  23. package/src/__tests__/styled-ssr.test.ts +36 -28
  24. package/src/__tests__/styled.test.ts +214 -145
  25. package/src/__tests__/theme.test.ts +11 -11
  26. package/src/__tests__/useCSS.test.ts +89 -59
  27. package/src/css.ts +1 -1
  28. package/src/forward.ts +187 -187
  29. package/src/globalStyle.ts +5 -5
  30. package/src/index.ts +15 -15
  31. package/src/keyframes.ts +3 -3
  32. package/src/resolve.ts +14 -14
  33. package/src/shared.ts +2 -2
  34. package/src/sheet.ts +26 -26
  35. package/src/styled.tsx +145 -100
  36. package/src/useCSS.ts +4 -4
@@ -6,100 +6,131 @@
6
6
  * CSS properties like `position: absolute` might get lost.
7
7
  */
8
8
 
9
- import type { VNode } from "@pyreon/core"
10
- import { h } from "@pyreon/core"
11
- import { describe, expect, it } from "vitest"
12
- import { css } from "../css"
13
- import { normalizeCSS, resolve, resolveValue } from "../resolve"
14
- import { createSheet } from "../sheet"
15
- import { styled } from "../styled"
9
+ import type { VNode } from '@pyreon/core'
10
+ import { h } from '@pyreon/core'
11
+ import { describe, expect, it } from 'vitest'
12
+ import { css } from '../css'
13
+ import { normalizeCSS, resolve, resolveValue } from '../resolve'
14
+ import { createSheet } from '../sheet'
15
+ import { styled } from '../styled'
16
16
 
17
17
  // =====================================================================
18
18
  // LAYER 1: resolve() with nested CSSResults — the raw resolution chain
19
19
  // =====================================================================
20
20
 
21
- describe("resolve composition chain", () => {
22
- describe("CSSResult nesting (css-in-css)", () => {
23
- it("resolves nested css`...` calls", () => {
24
- const inner = css`color: red;`
25
- const outer = css`${inner} font-size: 16px;`
21
+ describe('resolve composition chain', () => {
22
+ describe('CSSResult nesting (css-in-css)', () => {
23
+ it('resolves nested css`...` calls', () => {
24
+ const inner = css`
25
+ color: red;
26
+ `
27
+ const outer = css`
28
+ ${inner} font-size: 16px;
29
+ `
26
30
  const result = normalizeCSS(resolve(outer.strings, outer.values, {}))
27
- expect(result).toContain("color: red;")
28
- expect(result).toContain("font-size: 16px;")
31
+ expect(result).toContain('color: red;')
32
+ expect(result).toContain('font-size: 16px;')
29
33
  })
30
34
 
31
- it("resolves deeply nested css calls (3 levels)", () => {
32
- const level3 = css`position: absolute;`
33
- const level2 = css`${level3} display: flex;`
34
- const level1 = css`${level2} color: blue;`
35
+ it('resolves deeply nested css calls (3 levels)', () => {
36
+ const level3 = css`
37
+ position: absolute;
38
+ `
39
+ const level2 = css`
40
+ ${level3} display: flex;
41
+ `
42
+ const level1 = css`
43
+ ${level2} color: blue;
44
+ `
35
45
  const result = normalizeCSS(resolve(level1.strings, level1.values, {}))
36
- expect(result).toContain("position: absolute;")
37
- expect(result).toContain("display: flex;")
38
- expect(result).toContain("color: blue;")
46
+ expect(result).toContain('position: absolute;')
47
+ expect(result).toContain('display: flex;')
48
+ expect(result).toContain('color: blue;')
39
49
  })
40
50
 
41
- it("resolves array of CSS strings (processDescriptor fragments)", () => {
51
+ it('resolves array of CSS strings (processDescriptor fragments)', () => {
42
52
  // This mimics unistyle/styles/index.ts: fragments array from propertyMap
43
53
  const fragments = [
44
- "",
45
- "",
46
- "position: absolute;",
47
- "",
48
- "display: flex;",
49
- "",
50
- "height: 2.5rem;",
51
- "",
54
+ '',
55
+ '',
56
+ 'position: absolute;',
57
+ '',
58
+ 'display: flex;',
59
+ '',
60
+ 'height: 2.5rem;',
61
+ '',
52
62
  ]
53
- const result = css`${fragments}`
63
+ const result = css`
64
+ ${fragments}
65
+ `
54
66
  const resolved = normalizeCSS(resolve(result.strings, result.values, {}))
55
- expect(resolved).toContain("position: absolute;")
56
- expect(resolved).toContain("display: flex;")
57
- expect(resolved).toContain("height: 2.5rem;")
67
+ expect(resolved).toContain('position: absolute;')
68
+ expect(resolved).toContain('display: flex;')
69
+ expect(resolved).toContain('height: 2.5rem;')
58
70
  })
59
71
 
60
- it("resolves CSSResult wrapping an array of fragments", () => {
72
+ it('resolves CSSResult wrapping an array of fragments', () => {
61
73
  // styles() returns css`${fragments}` where fragments is an array
62
- const fragments = ["position: absolute;", "", "color: red;"]
63
- const stylesResult = css`${fragments}`
74
+ const fragments = ['position: absolute;', '', 'color: red;']
75
+ const stylesResult = css`
76
+ ${fragments}
77
+ `
64
78
  // makeItResponsive wraps: css`${renderStyles(theme)}`
65
- const mirResult = css`${stylesResult}`
79
+ const mirResult = css`
80
+ ${stylesResult}
81
+ `
66
82
  const resolved = normalizeCSS(resolve(mirResult.strings, mirResult.values, {}))
67
- expect(resolved).toContain("position: absolute;")
68
- expect(resolved).toContain("color: red;")
83
+ expect(resolved).toContain('position: absolute;')
84
+ expect(resolved).toContain('color: red;')
69
85
  })
70
86
  })
71
87
 
72
- describe("function interpolations (styled component render path)", () => {
73
- it("resolves function that returns a CSSResult", () => {
74
- const fn = (props: any) => css`color: ${props.color};`
75
- const template = css`${fn}`
76
- const result = normalizeCSS(resolve(template.strings, template.values, { color: "red" }))
77
- expect(result).toContain("color: red;")
88
+ describe('function interpolations (styled component render path)', () => {
89
+ it('resolves function that returns a CSSResult', () => {
90
+ const fn = (props: any) =>
91
+ css`
92
+ color: ${props.color};
93
+ `
94
+ const template = css`
95
+ ${fn}
96
+ `
97
+ const result = normalizeCSS(resolve(template.strings, template.values, { color: 'red' }))
98
+ expect(result).toContain('color: red;')
78
99
  })
79
100
 
80
- it("resolves function that returns an array (makeItResponsive responsive path)", () => {
101
+ it('resolves function that returns an array (makeItResponsive responsive path)', () => {
81
102
  // makeItResponsive returns an array when breakpoints exist
82
103
  const fn = () => [
83
- css`position: absolute;`,
84
- css`@media (min-width: 36em) { font-size: 2rem; }`,
104
+ css`
105
+ position: absolute;
106
+ `,
107
+ css`
108
+ @media (min-width: 36em) {
109
+ font-size: 2rem;
110
+ }
111
+ `,
85
112
  ]
86
- const template = css`${fn}`
113
+ const template = css`
114
+ ${fn}
115
+ `
87
116
  const result = normalizeCSS(resolve(template.strings, template.values, {}))
88
- expect(result).toContain("position: absolute;")
89
- expect(result).toContain("@media")
90
- expect(result).toContain("font-size: 2rem;")
117
+ expect(result).toContain('position: absolute;')
118
+ expect(result).toContain('@media')
119
+ expect(result).toContain('font-size: 2rem;')
91
120
  })
92
121
 
93
- it("resolves function returning CSSResult containing another function", () => {
122
+ it('resolves function returning CSSResult containing another function', () => {
94
123
  // This is the exact rocketstyle pattern:
95
124
  // .styles((css) => css`${({$rocketstyle}) => { ... return css`${baseTheme};` }}`)
96
125
  const innerFn = (props: any) => {
97
126
  const theme = props.$rocketstyle
98
127
  const fragments = [
99
- theme.position ? `position: ${theme.position};` : "",
100
- theme.display ? `display: ${theme.display};` : "",
128
+ theme.position ? `position: ${theme.position};` : '',
129
+ theme.display ? `display: ${theme.display};` : '',
101
130
  ]
102
- return css`${fragments}`
131
+ return css`
132
+ ${fragments}
133
+ `
103
134
  }
104
135
 
105
136
  const outerResult = css`
@@ -109,15 +140,15 @@ describe("resolve composition chain", () => {
109
140
 
110
141
  const resolved = normalizeCSS(
111
142
  resolve(outerResult.strings, outerResult.values, {
112
- $rocketstyle: { position: "absolute", display: "flex" },
143
+ $rocketstyle: { position: 'absolute', display: 'flex' },
113
144
  }),
114
145
  )
115
- expect(resolved).toContain("font-weight: 500;")
116
- expect(resolved).toContain("position: absolute;")
117
- expect(resolved).toContain("display: flex;")
146
+ expect(resolved).toContain('font-weight: 500;')
147
+ expect(resolved).toContain('position: absolute;')
148
+ expect(resolved).toContain('display: flex;')
118
149
  })
119
150
 
120
- it("resolves the full rocketstyle+unistyle chain pattern", () => {
151
+ it('resolves the full rocketstyle+unistyle chain pattern', () => {
121
152
  // Simulates the full chain:
122
153
  // 1. processDescriptor generates CSS string fragments
123
154
  // 2. styles() wraps them in css`${fragments}`
@@ -135,12 +166,12 @@ describe("resolve composition chain", () => {
135
166
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: complex logic is inherent to this function
136
167
  }) => {
137
168
  const fragments = [
138
- t.position ? `position: ${t.position};` : "",
139
- t.display ? `display: ${t.display};` : "",
140
- t.height ? `height: ${t.height}rem;` : "",
141
- t.fontSize ? `font-size: ${t.fontSize}rem;` : "",
142
- t.backgroundColor ? `background-color: ${t.backgroundColor};` : "",
143
- t.color ? `color: ${t.color};` : "",
169
+ t.position ? `position: ${t.position};` : '',
170
+ t.display ? `display: ${t.display};` : '',
171
+ t.height ? `height: ${t.height}rem;` : '',
172
+ t.fontSize ? `font-size: ${t.fontSize}rem;` : '',
173
+ t.backgroundColor ? `background-color: ${t.backgroundColor};` : '',
174
+ t.color ? `color: ${t.color};` : '',
144
175
  ]
145
176
  return cssFn`${fragments}`
146
177
  }
@@ -180,31 +211,31 @@ describe("resolve composition chain", () => {
180
211
  const stylesArray = [stylesCb(css)]
181
212
 
182
213
  // This is the styled component template resolution
183
- const templateStrings = Object.assign(["\n ", ";\n"], {
184
- raw: ["\n ", ";\n"],
214
+ const templateStrings = Object.assign(['\n ', ';\n'], {
215
+ raw: ['\n ', ';\n'],
185
216
  }) as unknown as TemplateStringsArray
186
217
 
187
218
  const resolved = normalizeCSS(
188
219
  resolve(templateStrings, [stylesArray], {
189
220
  $rocketstyle: {
190
- position: "absolute",
191
- display: "flex",
221
+ position: 'absolute',
222
+ display: 'flex',
192
223
  height: 2.5,
193
- backgroundColor: "#0070f3",
194
- color: "#fff",
224
+ backgroundColor: '#0070f3',
225
+ color: '#fff',
195
226
  },
196
227
  }),
197
228
  )
198
229
 
199
- expect(resolved).toContain("position: absolute;")
200
- expect(resolved).toContain("display: flex;")
201
- expect(resolved).toContain("height: 2.5rem;")
202
- expect(resolved).toContain("background-color: #0070f3;")
203
- expect(resolved).toContain("color: #fff;")
204
- expect(resolved).toContain("font-weight: 500;")
230
+ expect(resolved).toContain('position: absolute;')
231
+ expect(resolved).toContain('display: flex;')
232
+ expect(resolved).toContain('height: 2.5rem;')
233
+ expect(resolved).toContain('background-color: #0070f3;')
234
+ expect(resolved).toContain('color: #fff;')
235
+ expect(resolved).toContain('font-weight: 500;')
205
236
  })
206
237
 
207
- it("resolves the full chain with responsive breakpoints", () => {
238
+ it('resolves the full chain with responsive breakpoints', () => {
208
239
  const unistyleStyles = ({
209
240
  theme: t,
210
241
  css: cssFn,
@@ -213,8 +244,8 @@ describe("resolve composition chain", () => {
213
244
  css: typeof css
214
245
  }) => {
215
246
  const fragments = [
216
- t.position ? `position: ${t.position};` : "",
217
- t.height ? `height: ${t.height}rem;` : "",
247
+ t.position ? `position: ${t.position};` : '',
248
+ t.height ? `height: ${t.height}rem;` : '',
218
249
  ]
219
250
  return cssFn`${fragments}`
220
251
  }
@@ -240,7 +271,7 @@ describe("resolve composition chain", () => {
240
271
  const breakpoints = { xs: 0, md: 768 }
241
272
  const rootSize = 16
242
273
  const media = createMedia(css, breakpoints, rootSize)
243
- const sortedBreakpoints = ["xs", "md"]
274
+ const sortedBreakpoints = ['xs', 'md']
244
275
 
245
276
  // Simulate makeItResponsive with responsive path
246
277
  const makeItResponsiveResp = (config: {
@@ -256,13 +287,13 @@ describe("resolve composition chain", () => {
256
287
  // position: 'absolute' -> only first breakpoint
257
288
  // height: { xs: 2.5, md: 5 } -> different per breakpoint
258
289
  const optimizedTheme: Record<string, Record<string, any>> = {
259
- xs: { position: "absolute", height: 2.5 },
290
+ xs: { position: 'absolute', height: 2.5 },
260
291
  md: { height: 5 },
261
292
  }
262
293
 
263
294
  return sortedBreakpoints.map((item) => {
264
295
  const breakpointTheme = optimizedTheme[item]
265
- if (!breakpointTheme || !media) return ""
296
+ if (!breakpointTheme || !media) return ''
266
297
  const result = renderStyles(breakpointTheme)
267
298
  return (media as Record<string, any>)[item]`
268
299
  ${result};
@@ -287,23 +318,23 @@ describe("resolve composition chain", () => {
287
318
 
288
319
  const stylesArray = [stylesCb(css)]
289
320
 
290
- const templateStrings = Object.assign(["\n ", ";\n"], {
291
- raw: ["\n ", ";\n"],
321
+ const templateStrings = Object.assign(['\n ', ';\n'], {
322
+ raw: ['\n ', ';\n'],
292
323
  }) as unknown as TemplateStringsArray
293
324
 
294
325
  const resolved = normalizeCSS(
295
326
  resolve(templateStrings, [stylesArray], {
296
- $rocketstyle: { position: "absolute", height: { xs: 2.5, md: 5 } },
327
+ $rocketstyle: { position: 'absolute', height: { xs: 2.5, md: 5 } },
297
328
  }),
298
329
  )
299
330
 
300
331
  // Base breakpoint (xs) should have position + height
301
- expect(resolved).toContain("position: absolute;")
302
- expect(resolved).toContain("height: 2.5rem;")
332
+ expect(resolved).toContain('position: absolute;')
333
+ expect(resolved).toContain('height: 2.5rem;')
303
334
 
304
335
  // md breakpoint should be in @media
305
- expect(resolved).toContain("@media")
306
- expect(resolved).toContain("height: 5rem;")
336
+ expect(resolved).toContain('@media')
337
+ expect(resolved).toContain('height: 5rem;')
307
338
  })
308
339
  })
309
340
  })
@@ -312,28 +343,28 @@ describe("resolve composition chain", () => {
312
343
  // LAYER 2: styled component rendering — verify CSS injection + className
313
344
  // =====================================================================
314
345
 
315
- describe("styled component composition", () => {
316
- it("handles array of functions as single interpolation (calculateStyles pattern)", () => {
346
+ describe('styled component composition', () => {
347
+ it('handles array of functions as single interpolation (calculateStyles pattern)', () => {
317
348
  // This is EXACTLY what rocketstyle does:
318
349
  // styled(component, { boost: true })`${calculateStyles(styles)};`
319
350
  // calculateStyles returns an array of function results
320
351
 
321
- const fn1 = (props: any) => `position: ${props.$rocketstyle?.position ?? "static"};`
322
- const fn2 = (props: any) => `color: ${props.$rocketstyle?.color ?? "inherit"};`
352
+ const fn1 = (props: any) => `position: ${props.$rocketstyle?.position ?? 'static'};`
353
+ const fn2 = (props: any) => `color: ${props.$rocketstyle?.color ?? 'inherit'};`
323
354
 
324
- const Comp = styled("div")`
355
+ const Comp = styled('div')`
325
356
  ${[fn1, fn2]};
326
357
  `
327
358
 
328
- const vnode = Comp({ $rocketstyle: { position: "absolute", color: "red" } }) as VNode
359
+ const vnode = Comp({ $rocketstyle: { position: 'absolute', color: 'red' } }) as VNode
329
360
  expect(vnode.props.class).toMatch(/^pyr-/)
330
361
  })
331
362
 
332
- it("handles function returning css`...` with nested function returning array", () => {
363
+ it('handles function returning css`...` with nested function returning array', () => {
333
364
  // This mimics the full .styles() -> makeItResponsive -> unistyle chain
334
365
  const innerFn = (props: any) => {
335
366
  const t = props.$rocketstyle
336
- return [t.position ? `position: ${t.position};` : "", t.color ? `color: ${t.color};` : ""]
367
+ return [t.position ? `position: ${t.position};` : '', t.color ? `color: ${t.color};` : '']
337
368
  }
338
369
 
339
370
  const outerCssResult = css`
@@ -341,25 +372,25 @@ describe("styled component composition", () => {
341
372
  ${innerFn};
342
373
  `
343
374
 
344
- const Comp = styled("div")`
375
+ const Comp = styled('div')`
345
376
  ${[outerCssResult]};
346
377
  `
347
378
 
348
- const vnode = Comp({ $rocketstyle: { position: "absolute", color: "blue" } }) as VNode
379
+ const vnode = Comp({ $rocketstyle: { position: 'absolute', color: 'blue' } }) as VNode
349
380
  expect(vnode.props.class).toMatch(/^pyr-/)
350
381
 
351
382
  // Verify the CSS resolves correctly
352
383
  const cssText = normalizeCSS(
353
384
  resolve(outerCssResult.strings, outerCssResult.values, {
354
- $rocketstyle: { position: "absolute", color: "blue" },
385
+ $rocketstyle: { position: 'absolute', color: 'blue' },
355
386
  }),
356
387
  )
357
- expect(cssText).toContain("position: absolute;")
358
- expect(cssText).toContain("color: blue;")
359
- expect(cssText).toContain("font-weight: bold;")
388
+ expect(cssText).toContain('position: absolute;')
389
+ expect(cssText).toContain('color: blue;')
390
+ expect(cssText).toContain('font-weight: bold;')
360
391
  })
361
392
 
362
- it("handles css result wrapping a makeItResponsive-like function", () => {
393
+ it('handles css result wrapping a makeItResponsive-like function', () => {
363
394
  // makeItResponsive returns a FUNCTION
364
395
  // This function is used as interpolation in css`${baseTheme};`
365
396
  // That css result is used as interpolation in css`${fn};`
@@ -367,67 +398,81 @@ describe("styled component composition", () => {
367
398
 
368
399
  const makeItResponsiveLike = (theme: Record<string, any>) => (_props: any) => {
369
400
  const fragments = Object.entries(theme).map(([k, v]) => `${k}: ${v};`)
370
- return css`${fragments}`
401
+ return css`
402
+ ${fragments}
403
+ `
371
404
  }
372
405
 
373
406
  const styleCallback = css`
374
407
  font-weight: 500;
375
408
  ${(props: any) => {
376
409
  const baseTheme = makeItResponsiveLike(props.$rocketstyle)
377
- return css`${baseTheme};`
410
+ return css`
411
+ ${baseTheme};
412
+ `
378
413
  }};
379
414
  `
380
415
 
381
- const Comp = styled("div")`
416
+ const Comp = styled('div')`
382
417
  ${[styleCallback]};
383
418
  `
384
419
 
385
- const vnode = Comp({ $rocketstyle: { position: "absolute", display: "flex" } }) as VNode
420
+ const vnode = Comp({ $rocketstyle: { position: 'absolute', display: 'flex' } }) as VNode
386
421
  expect(vnode.props.class).toMatch(/^pyr-/)
387
422
 
388
423
  // Resolve manually to verify CSS content
389
424
  const cssText = normalizeCSS(
390
425
  resolve(styleCallback.strings, styleCallback.values, {
391
- $rocketstyle: { position: "absolute", display: "flex" },
426
+ $rocketstyle: { position: 'absolute', display: 'flex' },
392
427
  }),
393
428
  )
394
- expect(cssText).toContain("position: absolute;")
395
- expect(cssText).toContain("display: flex;")
429
+ expect(cssText).toContain('position: absolute;')
430
+ expect(cssText).toContain('display: flex;')
396
431
  })
397
432
 
398
- it("wrapping a component: outer styled inherits inner className", () => {
433
+ it('wrapping a component: outer styled inherits inner className', () => {
399
434
  // Inner is a Pyreon component wrapped by rocketstyle's styled()
400
- const Inner = (props: { class?: string; $rocketstyle?: any; "data-testid"?: string }) =>
401
- h("div", { class: props.class, "data-testid": "inner" })
435
+ const Inner = (props: { class?: string; $rocketstyle?: any; 'data-testid'?: string }) =>
436
+ h('div', { class: props.class, 'data-testid': 'inner' })
402
437
 
403
438
  const Outer = styled(Inner)`
404
439
  ${(props: any) => {
405
440
  const t = props.$rocketstyle || {}
406
- return `position: ${t.position || "static"};`
441
+ return `position: ${t.position || 'static'};`
407
442
  }};
408
443
  `
409
444
 
410
- const vnode = Outer({ $rocketstyle: { position: "absolute" } }) as VNode
445
+ const vnode = Outer({ $rocketstyle: { position: 'absolute' } }) as VNode
411
446
  // Outer renders Inner, passing className
412
447
  expect(vnode.props.class).toMatch(/^pyr-/)
413
448
  })
414
449
 
415
- it("CSS output contains all properties from composition chain", () => {
450
+ it('CSS output contains all properties from composition chain', () => {
416
451
  const fragments = [
417
- "position: absolute;",
418
- "",
419
- "display: flex;",
420
- "height: 2.5rem;",
421
- "",
422
- "background-color: #0070f3;",
452
+ 'position: absolute;',
453
+ '',
454
+ 'display: flex;',
455
+ 'height: 2.5rem;',
456
+ '',
457
+ 'background-color: #0070f3;',
423
458
  ]
424
- const cssText = normalizeCSS(resolve(css`${fragments}`.strings, css`${fragments}`.values, {}))
459
+ const cssText = normalizeCSS(
460
+ resolve(
461
+ css`
462
+ ${fragments}
463
+ `.strings,
464
+ css`
465
+ ${fragments}
466
+ `.values,
467
+ {},
468
+ ),
469
+ )
425
470
 
426
471
  // Verify the resolved CSS text contains all declarations
427
- expect(cssText).toContain("position: absolute;")
428
- expect(cssText).toContain("display: flex;")
429
- expect(cssText).toContain("height: 2.5rem;")
430
- expect(cssText).toContain("background-color: #0070f3;")
472
+ expect(cssText).toContain('position: absolute;')
473
+ expect(cssText).toContain('display: flex;')
474
+ expect(cssText).toContain('height: 2.5rem;')
475
+ expect(cssText).toContain('background-color: #0070f3;')
431
476
 
432
477
  // Verify it can be inserted into a sheet
433
478
  const s = createSheet()
@@ -435,7 +480,7 @@ describe("styled component composition", () => {
435
480
  expect(className).toMatch(/^pyr-/)
436
481
  })
437
482
 
438
- it("handles the exact rocketstyle pattern with ThemeProvider context", () => {
483
+ it('handles the exact rocketstyle pattern with ThemeProvider context', () => {
439
484
  // Full pattern: styled component -> function interpolation
440
485
  // -> css result -> function -> css result -> array fragments
441
486
  // Note: In VNode-level testing, we verify resolve output directly
@@ -444,30 +489,34 @@ describe("styled component composition", () => {
444
489
  const innerFn = (props: any) => {
445
490
  const t = props.$rocketstyle || {}
446
491
  const fragments = [
447
- t.position ? `position: ${t.position};` : "",
448
- t.color ? `color: ${t.color};` : "",
449
- t.fontSize ? `font-size: ${t.fontSize};` : "",
492
+ t.position ? `position: ${t.position};` : '',
493
+ t.color ? `color: ${t.color};` : '',
494
+ t.fontSize ? `font-size: ${t.fontSize};` : '',
450
495
  ]
451
- return css`${fragments}`
496
+ return css`
497
+ ${fragments}
498
+ `
452
499
  }
453
500
 
454
- const Comp = styled("div")`
501
+ const Comp = styled('div')`
455
502
  ${(props: any) => {
456
503
  const t = props.$rocketstyle || {}
457
504
  const fragments = [
458
- t.position ? `position: ${t.position};` : "",
459
- t.color ? `color: ${t.color};` : "",
460
- t.fontSize ? `font-size: ${t.fontSize};` : "",
505
+ t.position ? `position: ${t.position};` : '',
506
+ t.color ? `color: ${t.color};` : '',
507
+ t.fontSize ? `font-size: ${t.fontSize};` : '',
461
508
  ]
462
- return css`${fragments}`
509
+ return css`
510
+ ${fragments}
511
+ `
463
512
  }};
464
513
  `
465
514
 
466
515
  const vnode = Comp({
467
516
  $rocketstyle: {
468
- position: "absolute",
469
- color: "#fff",
470
- fontSize: "14px",
517
+ position: 'absolute',
518
+ color: '#fff',
519
+ fontSize: '14px',
471
520
  },
472
521
  }) as VNode
473
522
  expect(vnode.props.class).toMatch(/^pyr-/)
@@ -476,14 +525,14 @@ describe("styled component composition", () => {
476
525
  const resolved = normalizeCSS(
477
526
  resolveValue(innerFn, {
478
527
  $rocketstyle: {
479
- position: "absolute",
480
- color: "#fff",
481
- fontSize: "14px",
528
+ position: 'absolute',
529
+ color: '#fff',
530
+ fontSize: '14px',
482
531
  },
483
532
  }),
484
533
  )
485
- expect(resolved).toContain("position: absolute;")
486
- expect(resolved).toContain("color: #fff;")
487
- expect(resolved).toContain("font-size: 14px;")
534
+ expect(resolved).toContain('position: absolute;')
535
+ expect(resolved).toContain('color: #fff;')
536
+ expect(resolved).toContain('font-size: 14px;')
488
537
  })
489
538
  })