@pyreon/rocketstyle 0.11.5 → 0.11.7

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 (51) hide show
  1. package/README.md +32 -32
  2. package/lib/index.d.ts +25 -6
  3. package/lib/index.js +122 -97
  4. package/package.json +25 -24
  5. package/src/__tests__/attrs.test.ts +49 -49
  6. package/src/__tests__/chaining.test.ts +27 -27
  7. package/src/__tests__/collection.test.ts +12 -12
  8. package/src/__tests__/compose.test.ts +10 -10
  9. package/src/__tests__/context.test.ts +65 -65
  10. package/src/__tests__/createLocalProvider.test.ts +53 -53
  11. package/src/__tests__/dimensions.test.ts +54 -54
  12. package/src/__tests__/e2e-styler.test.ts +142 -136
  13. package/src/__tests__/hooks.test.ts +41 -70
  14. package/src/__tests__/isRocketComponent.test.ts +11 -11
  15. package/src/__tests__/misc.test.ts +91 -91
  16. package/src/__tests__/providerConsumer.test.ts +54 -126
  17. package/src/__tests__/rocketstyleIntegration.test.ts +182 -255
  18. package/src/__tests__/themeUtils.test.ts +173 -173
  19. package/src/cache/index.ts +1 -1
  20. package/src/constants/booleanTags.ts +25 -25
  21. package/src/constants/defaultDimensions.ts +5 -5
  22. package/src/constants/index.ts +16 -16
  23. package/src/context/context.ts +13 -10
  24. package/src/context/createLocalProvider.ts +26 -13
  25. package/src/context/localContext.ts +2 -2
  26. package/src/hoc/index.ts +1 -1
  27. package/src/hoc/rocketstyleAttrsHoc.ts +26 -29
  28. package/src/hooks/index.ts +2 -2
  29. package/src/hooks/usePseudoState.ts +3 -3
  30. package/src/hooks/useTheme.ts +14 -17
  31. package/src/index.ts +32 -15
  32. package/src/init.ts +12 -12
  33. package/src/isRocketComponent.ts +2 -2
  34. package/src/rocketstyle.ts +125 -112
  35. package/src/types/attrs.ts +2 -2
  36. package/src/types/config.ts +4 -4
  37. package/src/types/configuration.ts +5 -5
  38. package/src/types/dimensions.ts +5 -5
  39. package/src/types/hoc.ts +1 -1
  40. package/src/types/rocketComponent.ts +4 -4
  41. package/src/types/rocketstyle.ts +10 -10
  42. package/src/types/styles.ts +9 -4
  43. package/src/types/theme.ts +4 -4
  44. package/src/types/utils.ts +1 -1
  45. package/src/utils/attrs.ts +2 -2
  46. package/src/utils/chaining.ts +2 -2
  47. package/src/utils/compose.ts +1 -1
  48. package/src/utils/dimensions.ts +6 -6
  49. package/src/utils/statics.ts +2 -2
  50. package/src/utils/styles.ts +2 -2
  51. package/src/utils/theme.ts +10 -10
@@ -1,148 +1,95 @@
1
- import { popContext, pushContext } from "@pyreon/core"
2
- import { config } from "@pyreon/ui-core"
3
- import { context } from "../context/context"
4
- import rocketstyle from "../init"
5
- import isRocketComponent from "../isRocketComponent"
6
-
7
- // Mock styled function that returns the component unchanged
8
- const mockStyled = (component: any) => {
9
- const taggedTemplate = (_strings: any, ..._args: any[]) => component
10
- return taggedTemplate
11
- }
12
-
13
- const mockCss = (_strings: any, ..._args: any[]) => ""
14
-
15
- // Store originals to restore later
16
- const originalStyled = config.styled
17
- const originalCss = config.css
18
-
1
+ import {
2
+ ThemeCapture,
3
+ getComputedTheme,
4
+ initTestConfig,
5
+ renderProps,
6
+ withThemeContext,
7
+ } from '@pyreon/test-utils'
8
+ import rocketstyle from '../init'
9
+ import isRocketComponent from '../isRocketComponent'
10
+
11
+ let cleanup: () => void
19
12
  beforeAll(() => {
20
- config.init({
21
- css: mockCss as any,
22
- styled: mockStyled as any,
23
- component: "div",
24
- textComponent: "span",
25
- })
26
- })
27
-
28
- afterAll(() => {
29
- config.styled = originalStyled
30
- config.css = originalCss
13
+ cleanup = initTestConfig()
31
14
  })
15
+ afterAll(() => cleanup())
32
16
 
33
17
  /**
34
18
  * Base component that filters internal props and returns a VNode-like object.
35
19
  * In Pyreon, components are plain functions — no forwardRef needed.
36
20
  */
37
21
  const BaseComponent: any = ({ children, $rocketstyle, $rocketstate, ...rest }: any) => ({
38
- type: "div",
22
+ type: 'div',
39
23
  props: rest,
40
24
  children,
41
25
  key: null,
42
- $rocketstyle,
43
- $rocketstate,
26
+ $rocketstyle: typeof $rocketstyle === 'function' ? $rocketstyle() : $rocketstyle,
27
+ $rocketstate: typeof $rocketstate === 'function' ? $rocketstate() : $rocketstate,
44
28
  })
45
- BaseComponent.displayName = "BaseComponent"
46
-
47
- /** Helper to push a theme context for testing */
48
- const withThemeContext = (fn: () => any) => {
49
- pushContext(
50
- new Map([
51
- [
52
- context.id,
53
- {
54
- theme: { rootSize: 16 },
55
- mode: "light",
56
- isDark: false,
57
- isLight: true,
58
- },
59
- ],
60
- ]),
61
- )
62
- try {
63
- return fn()
64
- } finally {
65
- popContext()
66
- }
67
- }
68
-
69
- /** Unwrap reactive accessors (EnhancedComponent returns a function for mode switching). */
70
- const unwrap = (val: any): any => {
71
- let result = val
72
- while (typeof result === "function" && !result.IS_ROCKETSTYLE) result = result()
73
- return result
74
- }
75
-
76
- /** Helper: call the component and return its output for inspection. */
77
- const renderProps = (Component: any, props: Record<string, any> = {}) => {
78
- return withThemeContext(() => {
79
- const vnode = unwrap(Component(props))
80
- return vnode?.props ?? vnode
81
- })
82
- }
29
+ BaseComponent.displayName = 'BaseComponent'
83
30
 
84
31
  // --------------------------------------------------------
85
32
  // rocketstyle factory
86
33
  // --------------------------------------------------------
87
- describe("rocketstyle factory", () => {
88
- it("creates a component from factory", () => {
34
+ describe('rocketstyle factory', () => {
35
+ it('creates a component from factory', () => {
89
36
  const Button = rocketstyle()({
90
- name: "TestButton",
37
+ name: 'TestButton',
91
38
  component: BaseComponent,
92
39
  })
93
40
  expect(Button).toBeDefined()
94
- expect(typeof Button).toBe("function")
41
+ expect(typeof Button).toBe('function')
95
42
  })
96
43
 
97
- it("sets IS_ROCKETSTYLE on the component", () => {
44
+ it('sets IS_ROCKETSTYLE on the component', () => {
98
45
  const Button = rocketstyle()({
99
- name: "TestButton",
46
+ name: 'TestButton',
100
47
  component: BaseComponent,
101
48
  })
102
49
  expect(Button.IS_ROCKETSTYLE).toBe(true)
103
50
  expect(isRocketComponent(Button)).toBe(true)
104
51
  })
105
52
 
106
- it("sets displayName on the component", () => {
53
+ it('sets displayName on the component', () => {
107
54
  const Button = rocketstyle()({
108
- name: "MyButton",
55
+ name: 'MyButton',
109
56
  component: BaseComponent,
110
57
  })
111
- expect(Button.displayName).toBe("MyButton")
58
+ expect(Button.displayName).toBe('MyButton')
112
59
  })
113
60
 
114
- it("throws when component is missing", () => {
61
+ it('throws when component is missing', () => {
115
62
  expect(() => {
116
- rocketstyle()({ name: "Test", component: undefined as any })
117
- }).toThrow("component")
63
+ rocketstyle()({ name: 'Test', component: undefined as any })
64
+ }).toThrow('component')
118
65
  })
119
66
 
120
- it("throws when name is missing", () => {
67
+ it('throws when name is missing', () => {
121
68
  expect(() => {
122
- rocketstyle()({ name: "", component: BaseComponent })
123
- }).toThrow("name")
69
+ rocketstyle()({ name: '', component: BaseComponent })
70
+ }).toThrow('name')
124
71
  })
125
72
 
126
- it("throws when dimension uses reserved key", () => {
73
+ it('throws when dimension uses reserved key', () => {
127
74
  expect(() => {
128
- rocketstyle({ dimensions: { attrs: "attrs" } as any })({
129
- name: "Test",
75
+ rocketstyle({ dimensions: { attrs: 'attrs' } as any })({
76
+ name: 'Test',
130
77
  component: BaseComponent,
131
78
  })
132
- }).toThrow("invalid")
79
+ }).toThrow('invalid')
133
80
  })
134
81
 
135
- it("allows custom dimensions", () => {
82
+ it('allows custom dimensions', () => {
136
83
  const Button = rocketstyle({
137
- dimensions: { colors: "color", shapes: "shape" },
138
- })({ name: "CustomButton", component: BaseComponent })
84
+ dimensions: { colors: 'color', shapes: 'shape' },
85
+ })({ name: 'CustomButton', component: BaseComponent })
139
86
  expect(Button).toBeDefined()
140
87
  expect(Button.IS_ROCKETSTYLE).toBe(true)
141
88
  })
142
89
 
143
- it("defaults useBooleans to true", () => {
90
+ it('defaults useBooleans to true', () => {
144
91
  const Button = rocketstyle()({
145
- name: "Test",
92
+ name: 'Test',
146
93
  component: BaseComponent,
147
94
  })
148
95
  expect(Button).toBeDefined()
@@ -152,77 +99,77 @@ describe("rocketstyle factory", () => {
152
99
  // --------------------------------------------------------
153
100
  // chaining methods
154
101
  // --------------------------------------------------------
155
- describe("chaining methods", () => {
102
+ describe('chaining methods', () => {
156
103
  const Button: any = rocketstyle()({
157
- name: "ChainButton",
104
+ name: 'ChainButton',
158
105
  component: BaseComponent,
159
106
  })
160
107
 
161
- it(".attrs() returns a new component", () => {
162
- const Enhanced = Button.attrs(() => ({ label: "test" }))
108
+ it('.attrs() returns a new component', () => {
109
+ const Enhanced = Button.attrs(() => ({ label: 'test' }))
163
110
  expect(Enhanced).toBeDefined()
164
111
  expect(Enhanced.IS_ROCKETSTYLE).toBe(true)
165
112
  expect(Enhanced).not.toBe(Button)
166
113
  })
167
114
 
168
- it(".attrs() with priority option", () => {
169
- const Enhanced = Button.attrs(() => ({ label: "priority" }), {
115
+ it('.attrs() with priority option', () => {
116
+ const Enhanced = Button.attrs(() => ({ label: 'priority' }), {
170
117
  priority: true,
171
118
  })
172
119
  expect(Enhanced).toBeDefined()
173
120
  expect(Enhanced.IS_ROCKETSTYLE).toBe(true)
174
121
  })
175
122
 
176
- it(".attrs() with filter option", () => {
177
- const Enhanced = Button.attrs(() => ({ label: "filtered" }), {
178
- filter: ["internal"],
123
+ it('.attrs() with filter option', () => {
124
+ const Enhanced = Button.attrs(() => ({ label: 'filtered' }), {
125
+ filter: ['internal'],
179
126
  })
180
127
  expect(Enhanced).toBeDefined()
181
128
  })
182
129
 
183
- it(".config() returns a new component", () => {
130
+ it('.config() returns a new component', () => {
184
131
  const Enhanced = Button.config({ DEBUG: true })
185
132
  expect(Enhanced).toBeDefined()
186
133
  expect(Enhanced.IS_ROCKETSTYLE).toBe(true)
187
134
  })
188
135
 
189
- it(".statics() returns a new component", () => {
190
- const Enhanced = Button.statics({ customMeta: "value" })
136
+ it('.statics() returns a new component', () => {
137
+ const Enhanced = Button.statics({ customMeta: 'value' })
191
138
  expect(Enhanced).toBeDefined()
192
- expect(Enhanced.meta.customMeta).toBe("value")
139
+ expect(Enhanced.meta.customMeta).toBe('value')
193
140
  })
194
141
 
195
- it(".theme() returns a new component", () => {
196
- const Enhanced = Button.theme(() => ({ color: "blue" }))
142
+ it('.theme() returns a new component', () => {
143
+ const Enhanced = Button.theme(() => ({ color: 'blue' }))
197
144
  expect(Enhanced).toBeDefined()
198
145
  expect(Enhanced.IS_ROCKETSTYLE).toBe(true)
199
146
  })
200
147
 
201
- it(".styles() returns a new component", () => {
202
- const Enhanced = Button.styles(() => "color: red;")
148
+ it('.styles() returns a new component', () => {
149
+ const Enhanced = Button.styles(() => 'color: red;')
203
150
  expect(Enhanced).toBeDefined()
204
151
  })
205
152
 
206
- it(".compose() returns a new component", () => {
153
+ it('.compose() returns a new component', () => {
207
154
  const hoc = (C: any) => C
208
155
  const Enhanced = Button.compose({ myHoc: hoc })
209
156
  expect(Enhanced).toBeDefined()
210
157
  })
211
158
 
212
- it("supports chaining multiple methods", () => {
213
- const Enhanced = Button.theme(() => ({ color: "blue" }))
214
- .attrs(() => ({ label: "test" }))
215
- .config({ name: "EnhancedButton" })
216
- .statics({ version: "1.0" })
159
+ it('supports chaining multiple methods', () => {
160
+ const Enhanced = Button.theme(() => ({ color: 'blue' }))
161
+ .attrs(() => ({ label: 'test' }))
162
+ .config({ name: 'EnhancedButton' })
163
+ .statics({ version: '1.0' })
217
164
 
218
165
  expect(Enhanced.IS_ROCKETSTYLE).toBe(true)
219
- expect(Enhanced.meta.version).toBe("1.0")
166
+ expect(Enhanced.meta.version).toBe('1.0')
220
167
  })
221
168
 
222
- it(".getStaticDimensions() returns dimension info", () => {
169
+ it('.getStaticDimensions() returns dimension info', () => {
223
170
  const Themed = Button.states(() => ({
224
- primary: { color: "red" },
225
- secondary: { color: "blue" },
171
+ primary: { color: 'red' },
172
+ secondary: { color: 'blue' },
226
173
  }))
227
174
 
228
175
  const info = Themed.getStaticDimensions({ rootSize: 16 })
@@ -231,63 +178,63 @@ describe("chaining methods", () => {
231
178
  expect(info.multiKeys).toBeDefined()
232
179
  })
233
180
 
234
- it(".getDefaultAttrs() evaluates attrs chain", () => {
181
+ it('.getDefaultAttrs() evaluates attrs chain', () => {
235
182
  const WithAttrs = Button.attrs((props: any) => ({
236
- label: "default",
183
+ label: 'default',
237
184
  ...props,
238
185
  }))
239
- const result = WithAttrs.getDefaultAttrs({}, {}, "light")
240
- expect(result.label).toBe("default")
186
+ const result = WithAttrs.getDefaultAttrs({}, {}, 'light')
187
+ expect(result.label).toBe('default')
241
188
  })
242
189
  })
243
190
 
244
191
  // --------------------------------------------------------
245
192
  // rendering
246
193
  // --------------------------------------------------------
247
- describe("rendering", () => {
248
- it("renders a basic rocketstyle component", () => {
194
+ describe('rendering', () => {
195
+ it('renders a basic rocketstyle component', () => {
249
196
  const Button: any = rocketstyle()({
250
- name: "RenderButton",
197
+ name: 'RenderButton',
251
198
  component: BaseComponent,
252
199
  }).config({})
253
200
 
254
- const result = renderProps(Button, { children: "Hello" })
201
+ const result = renderProps(Button, { children: 'Hello' })
255
202
  expect(result).toBeDefined()
256
203
  })
257
204
 
258
- it("adds data-rocketstyle attribute in dev mode", () => {
205
+ it('adds data-rocketstyle attribute in dev mode', () => {
259
206
  const Button: any = rocketstyle()({
260
- name: "DevButton",
207
+ name: 'DevButton',
261
208
  component: BaseComponent,
262
209
  }).config({})
263
210
 
264
211
  const result = renderProps(Button)
265
- expect(result["data-rocketstyle"]).toBe("DevButton")
212
+ expect(result['data-rocketstyle']).toBe('DevButton')
266
213
  })
267
214
 
268
- it("renders with attrs defaults", () => {
215
+ it('renders with attrs defaults', () => {
269
216
  const Button: any = rocketstyle()({
270
- name: "AttrsButton",
217
+ name: 'AttrsButton',
271
218
  component: BaseComponent,
272
- }).attrs((() => ({ "data-default": "yes" })) as any)
219
+ }).attrs((() => ({ 'data-default': 'yes' })) as any)
273
220
 
274
221
  const result = renderProps(Button)
275
- expect(result["data-default"]).toBe("yes")
222
+ expect(result['data-default']).toBe('yes')
276
223
  })
277
224
 
278
- it("explicit props override attrs", () => {
225
+ it('explicit props override attrs', () => {
279
226
  const Button: any = rocketstyle()({
280
- name: "OverrideButton",
227
+ name: 'OverrideButton',
281
228
  component: BaseComponent,
282
- }).attrs((() => ({ "data-val": "from-attrs" })) as any)
229
+ }).attrs((() => ({ 'data-val': 'from-attrs' })) as any)
283
230
 
284
- const result = renderProps(Button, { "data-val": "from-props" })
285
- expect(result["data-val"]).toBe("from-props")
231
+ const result = renderProps(Button, { 'data-val': 'from-props' })
232
+ expect(result['data-val']).toBe('from-props')
286
233
  })
287
234
 
288
- it("renders with theme", () => {
235
+ it('renders with theme', () => {
289
236
  const Button: any = rocketstyle()({
290
- name: "ThemedButton",
237
+ name: 'ThemedButton',
291
238
  component: BaseComponent,
292
239
  }).theme(() => ({ fontSize: 14 }))
293
240
 
@@ -295,27 +242,27 @@ describe("rendering", () => {
295
242
  expect(result).toBeDefined()
296
243
  })
297
244
 
298
- it("renders with dimension states", () => {
245
+ it('renders with dimension states', () => {
299
246
  const Button: any = rocketstyle()({
300
- name: "StatesButton",
247
+ name: 'StatesButton',
301
248
  component: BaseComponent,
302
249
  })
303
- .theme(() => ({ color: "default" }))
250
+ .theme(() => ({ color: 'default' }))
304
251
  .states(() => ({
305
- primary: { color: "blue" },
306
- secondary: { color: "green" },
252
+ primary: { color: 'blue' },
253
+ secondary: { color: 'green' },
307
254
  }))
308
255
 
309
- const result = renderProps(Button, { state: "primary" })
256
+ const result = renderProps(Button, { state: 'primary' })
310
257
  expect(result).toBeDefined()
311
258
  })
312
259
 
313
- it("renders with boolean dimension props", () => {
260
+ it('renders with boolean dimension props', () => {
314
261
  const Button: any = rocketstyle()({
315
- name: "BoolButton",
262
+ name: 'BoolButton',
316
263
  component: BaseComponent,
317
264
  }).states(() => ({
318
- primary: { color: "blue" },
265
+ primary: { color: 'blue' },
319
266
  }))
320
267
 
321
268
  // boolean prop 'primary' should map to state='primary'
@@ -323,36 +270,36 @@ describe("rendering", () => {
323
270
  expect(result).toBeDefined()
324
271
  })
325
272
 
326
- it("renders with priority attrs", () => {
273
+ it('renders with priority attrs', () => {
327
274
  const Button: any = rocketstyle()({
328
- name: "PriorityButton",
275
+ name: 'PriorityButton',
329
276
  component: BaseComponent,
330
- }).attrs((() => ({ "data-priority": "yes" })) as any, { priority: true })
277
+ }).attrs((() => ({ 'data-priority': 'yes' })) as any, { priority: true })
331
278
 
332
279
  const result = renderProps(Button)
333
- expect(result["data-priority"]).toBe("yes")
280
+ expect(result['data-priority']).toBe('yes')
334
281
  })
335
282
  })
336
283
 
337
284
  // --------------------------------------------------------
338
285
  // DEBUG option
339
286
  // --------------------------------------------------------
340
- describe("DEBUG option", () => {
341
- it("calls console.debug when DEBUG is enabled", () => {
342
- const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => {
287
+ describe('DEBUG option', () => {
288
+ it('calls console.debug when DEBUG is enabled', () => {
289
+ const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {
343
290
  /* no-op */
344
291
  })
345
292
 
346
293
  const Button: any = rocketstyle()({
347
- name: "DebugButton",
294
+ name: 'DebugButton',
348
295
  component: BaseComponent,
349
296
  }).config({ DEBUG: true })
350
297
 
351
298
  renderProps(Button)
352
299
  expect(debugSpy).toHaveBeenCalledWith(
353
- "[rocketstyle] DebugButton render:",
300
+ '[rocketstyle] DebugButton render:',
354
301
  expect.objectContaining({
355
- component: "DebugButton",
302
+ component: 'DebugButton',
356
303
  rocketstate: expect.any(Object),
357
304
  rocketstyle: expect.any(Object),
358
305
  dimensions: expect.any(Object),
@@ -363,13 +310,13 @@ describe("DEBUG option", () => {
363
310
  debugSpy.mockRestore()
364
311
  })
365
312
 
366
- it("does not call console.debug when DEBUG is not set", () => {
367
- const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => {
313
+ it('does not call console.debug when DEBUG is not set', () => {
314
+ const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {
368
315
  /* no-op */
369
316
  })
370
317
 
371
318
  const Button: any = rocketstyle()({
372
- name: "NoDebugButton",
319
+ name: 'NoDebugButton',
373
320
  component: BaseComponent,
374
321
  }).config({})
375
322
 
@@ -383,8 +330,8 @@ describe("DEBUG option", () => {
383
330
  // --------------------------------------------------------
384
331
  // passProps option
385
332
  // --------------------------------------------------------
386
- describe("passProps option", () => {
387
- it("passes styling props through when passProps is configured", () => {
333
+ describe('passProps option', () => {
334
+ it('passes styling props through when passProps is configured', () => {
388
335
  const PassPropsComponent: any = ({
389
336
  children,
390
337
  $rocketstyle,
@@ -392,28 +339,28 @@ describe("passProps option", () => {
392
339
  state,
393
340
  ...rest
394
341
  }: any) => ({
395
- type: "div",
396
- props: { ...rest, "data-state": state },
342
+ type: 'div',
343
+ props: { ...rest, 'data-state': state },
397
344
  children,
398
345
  key: null,
399
346
  })
400
- PassPropsComponent.displayName = "PassPropsComponent"
347
+ PassPropsComponent.displayName = 'PassPropsComponent'
401
348
 
402
349
  const Button: any = rocketstyle()({
403
- name: "PassPropsButton",
350
+ name: 'PassPropsButton',
404
351
  component: PassPropsComponent,
405
352
  })
406
353
  .states(() => ({
407
- primary: { color: "blue" },
408
- secondary: { color: "green" },
354
+ primary: { color: 'blue' },
355
+ secondary: { color: 'green' },
409
356
  }))
410
- .config({ passProps: ["state"] } as any)
357
+ .config({ passProps: ['state'] } as any)
411
358
 
412
- const result = renderProps(Button, { state: "primary" })
413
- expect(result["data-state"]).toBe("primary")
359
+ const result = renderProps(Button, { state: 'primary' })
360
+ expect(result['data-state']).toBe('primary')
414
361
  })
415
362
 
416
- it("does not pass styling props without passProps", () => {
363
+ it('does not pass styling props without passProps', () => {
417
364
  const PassPropsComponent: any = ({
418
365
  children,
419
366
  $rocketstyle,
@@ -421,66 +368,66 @@ describe("passProps option", () => {
421
368
  state,
422
369
  ...rest
423
370
  }: any) => ({
424
- type: "div",
425
- props: { ...rest, "data-state": state ?? "none" },
371
+ type: 'div',
372
+ props: { ...rest, 'data-state': state ?? 'none' },
426
373
  children,
427
374
  key: null,
428
375
  })
429
- PassPropsComponent.displayName = "NoPassPropsComponent"
376
+ PassPropsComponent.displayName = 'NoPassPropsComponent'
430
377
 
431
378
  const Button: any = rocketstyle()({
432
- name: "NoPassPropsButton",
379
+ name: 'NoPassPropsButton',
433
380
  component: PassPropsComponent,
434
381
  }).states(() => ({
435
- primary: { color: "blue" },
382
+ primary: { color: 'blue' },
436
383
  }))
437
384
 
438
- const result = renderProps(Button, { state: "primary" })
385
+ const result = renderProps(Button, { state: 'primary' })
439
386
  // Without passProps, the state prop should be filtered out
440
- expect(result["data-state"]).toBe("none")
387
+ expect(result['data-state']).toBe('none')
441
388
  })
442
389
  })
443
390
 
444
391
  // --------------------------------------------------------
445
392
  // IS_ROCKETSTYLE component wrapping
446
393
  // --------------------------------------------------------
447
- describe("IS_ROCKETSTYLE component wrapping", () => {
448
- it("skips styled() wrapping when component already has IS_ROCKETSTYLE", () => {
394
+ describe('IS_ROCKETSTYLE component wrapping', () => {
395
+ it('skips styled() wrapping when component already has IS_ROCKETSTYLE', () => {
449
396
  const MarkedComponent: any = ({ children, $rocketstyle, $rocketstate, ...rest }: any) => ({
450
- type: "div",
397
+ type: 'div',
451
398
  props: rest,
452
399
  children,
453
400
  key: null,
454
401
  })
455
402
  MarkedComponent.IS_ROCKETSTYLE = true
456
- MarkedComponent.displayName = "MarkedComponent"
403
+ MarkedComponent.displayName = 'MarkedComponent'
457
404
 
458
405
  const Outer: any = rocketstyle()({
459
- name: "OuterComponent",
406
+ name: 'OuterComponent',
460
407
  component: MarkedComponent,
461
408
  })
462
409
 
463
410
  expect(Outer).toBeDefined()
464
411
  expect(Outer.IS_ROCKETSTYLE).toBe(true)
465
- expect(Outer.displayName).toBe("OuterComponent")
412
+ expect(Outer.displayName).toBe('OuterComponent')
466
413
  })
467
414
 
468
- it("renders IS_ROCKETSTYLE component when chained with config", () => {
415
+ it('renders IS_ROCKETSTYLE component when chained with config', () => {
469
416
  const MarkedComponent: any = ({ children, $rocketstyle, $rocketstate, ...rest }: any) => ({
470
- type: "div",
417
+ type: 'div',
471
418
  props: rest,
472
419
  children,
473
420
  key: null,
474
421
  })
475
422
  MarkedComponent.IS_ROCKETSTYLE = true
476
- MarkedComponent.displayName = "MarkedComponent"
423
+ MarkedComponent.displayName = 'MarkedComponent'
477
424
 
478
425
  const Outer: any = rocketstyle()({
479
- name: "OuterChained",
426
+ name: 'OuterChained',
480
427
  component: MarkedComponent,
481
428
  }).config({})
482
429
 
483
- const result = renderProps(Outer, { children: "Wrapped" })
430
+ const result = renderProps(Outer, { children: 'Wrapped' })
484
431
  expect(result).toBeDefined()
485
432
  })
486
433
  })
@@ -488,60 +435,60 @@ describe("IS_ROCKETSTYLE component wrapping", () => {
488
435
  // --------------------------------------------------------
489
436
  // empty dimensions validation
490
437
  // --------------------------------------------------------
491
- describe("empty dimensions validation", () => {
492
- it("throws when dimensions is an empty object", () => {
438
+ describe('empty dimensions validation', () => {
439
+ it('throws when dimensions is an empty object', () => {
493
440
  expect(() => {
494
441
  rocketstyle({ dimensions: {} as any })({
495
- name: "EmptyDimensions",
442
+ name: 'EmptyDimensions',
496
443
  component: BaseComponent,
497
444
  })
498
- }).toThrow("dimensions")
445
+ }).toThrow('dimensions')
499
446
  })
500
447
  })
501
448
 
502
449
  // --------------------------------------------------------
503
450
  // multiple dimension values
504
451
  // --------------------------------------------------------
505
- describe("multiple dimension values", () => {
506
- it("renders with array values for multi-key dimensions", () => {
452
+ describe('multiple dimension values', () => {
453
+ it('renders with array values for multi-key dimensions', () => {
507
454
  const Button: any = rocketstyle()({
508
- name: "MultiButton",
455
+ name: 'MultiButton',
509
456
  component: BaseComponent,
510
457
  }).multiple(() => ({
511
- bold: { fontWeight: "bold" },
512
- italic: { fontStyle: "italic" },
513
- underline: { textDecoration: "underline" },
458
+ bold: { fontWeight: 'bold' },
459
+ italic: { fontStyle: 'italic' },
460
+ underline: { textDecoration: 'underline' },
514
461
  }))
515
462
 
516
- const result = renderProps(Button, { multiple: ["bold", "italic"] })
463
+ const result = renderProps(Button, { multiple: ['bold', 'italic'] })
517
464
  expect(result).toBeDefined()
518
465
  })
519
466
 
520
- it("renders with single value for non-multi dimensions", () => {
467
+ it('renders with single value for non-multi dimensions', () => {
521
468
  const Button: any = rocketstyle()({
522
- name: "SingleDimButton",
469
+ name: 'SingleDimButton',
523
470
  component: BaseComponent,
524
471
  })
525
472
  .states(() => ({
526
- primary: { color: "blue" },
527
- secondary: { color: "green" },
473
+ primary: { color: 'blue' },
474
+ secondary: { color: 'green' },
528
475
  }))
529
476
  .sizes(() => ({
530
477
  small: { fontSize: 12 },
531
478
  large: { fontSize: 18 },
532
479
  }))
533
480
 
534
- const result = renderProps(Button, { state: "primary", size: "large" })
481
+ const result = renderProps(Button, { state: 'primary', size: 'large' })
535
482
  expect(result).toBeDefined()
536
483
  })
537
484
 
538
- it("renders with boolean shorthand for multi-key dimensions", () => {
485
+ it('renders with boolean shorthand for multi-key dimensions', () => {
539
486
  const Button: any = rocketstyle()({
540
- name: "MultiBoolButton",
487
+ name: 'MultiBoolButton',
541
488
  component: BaseComponent,
542
489
  }).multiple(() => ({
543
- bold: { fontWeight: "bold" },
544
- italic: { fontStyle: "italic" },
490
+ bold: { fontWeight: 'bold' },
491
+ italic: { fontStyle: 'italic' },
545
492
  }))
546
493
 
547
494
  // Boolean shorthand for multi-key: both bold and italic as boolean props
@@ -553,15 +500,15 @@ describe("multiple dimension values", () => {
553
500
  // --------------------------------------------------------
554
501
  // rendering without Provider context
555
502
  // --------------------------------------------------------
556
- describe("rendering without Provider context", () => {
557
- it("renders component without any Provider (useContext returns default)", () => {
503
+ describe('rendering without Provider context', () => {
504
+ it('renders component without any Provider (useContext returns default)', () => {
558
505
  const Button: any = rocketstyle()({
559
- name: "NoProviderButton",
506
+ name: 'NoProviderButton',
560
507
  component: BaseComponent,
561
508
  }).config({})
562
509
 
563
510
  // Call without any context pushed
564
- const vnode = Button({ children: "NoCtx" }) as any
511
+ const vnode = Button({ children: 'NoCtx' }) as any
565
512
  const result = vnode?.props ?? vnode
566
513
  expect(result).toBeDefined()
567
514
  })
@@ -570,53 +517,33 @@ describe("rendering without Provider context", () => {
570
517
  // --------------------------------------------------------
571
518
  // $rocketstyle and $rocketstate are passed to inner component
572
519
  // --------------------------------------------------------
573
- describe("theme and state injection", () => {
574
- it("passes $rocketstyle theme to inner component", () => {
575
- const Receiver: any = ({ $rocketstyle, $rocketstate, ...rest }: any) => ({
576
- type: "div",
577
- props: rest,
578
- children: [],
579
- key: null,
580
- $rocketstyle,
581
- $rocketstate,
582
- })
583
- Receiver.displayName = "Receiver"
584
-
520
+ describe('theme and state injection', () => {
521
+ it('passes $rocketstyle theme to inner component', () => {
585
522
  const Button: any = rocketstyle()({
586
- name: "ThemeInjButton",
587
- component: Receiver,
523
+ name: 'ThemeInjButton',
524
+ component: ThemeCapture,
588
525
  })
589
- .theme(() => ({ color: "blue", bg: "white" }))
526
+ .theme(() => ({ color: 'blue', bg: 'white' }))
590
527
  .states(() => ({
591
- primary: { color: "red" },
528
+ primary: { color: 'red' },
592
529
  }))
593
530
 
594
- const vnode = withThemeContext(() => unwrap(Button({ state: "primary" })))
595
- expect(vnode.$rocketstyle).toBeDefined()
596
- expect(vnode.$rocketstyle.color).toBe("red")
597
- expect(vnode.$rocketstyle.bg).toBe("white")
531
+ const rs = getComputedTheme(Button, { state: 'primary' })
532
+ expect(rs).toBeDefined()
533
+ expect(rs.color).toBe('red')
534
+ expect(rs.bg).toBe('white')
598
535
  })
599
536
 
600
- it("passes $rocketstate with active dimensions to inner component", () => {
601
- const Receiver: any = ({ $rocketstyle, $rocketstate, ...rest }: any) => ({
602
- type: "div",
603
- props: rest,
604
- children: [],
605
- key: null,
606
- $rocketstyle,
607
- $rocketstate,
608
- })
609
- Receiver.displayName = "Receiver"
610
-
537
+ it('passes $rocketstate with active dimensions to inner component', () => {
611
538
  const Button: any = rocketstyle()({
612
- name: "StateInjButton",
613
- component: Receiver,
539
+ name: 'StateInjButton',
540
+ component: ThemeCapture,
614
541
  }).states(() => ({
615
- primary: { color: "blue" },
542
+ primary: { color: 'blue' },
616
543
  }))
617
544
 
618
- const vnode = withThemeContext(() => unwrap(Button({ state: "primary" })))
545
+ const vnode = withThemeContext(() => Button({ state: 'primary' }))
619
546
  expect(vnode.$rocketstate).toBeDefined()
620
- expect(vnode.$rocketstate.state).toBe("primary")
547
+ expect(vnode.$rocketstate.state).toBe('primary')
621
548
  })
622
549
  })