@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.
- package/README.md +32 -32
- package/lib/index.d.ts +25 -6
- package/lib/index.js +122 -97
- package/package.json +25 -24
- package/src/__tests__/attrs.test.ts +49 -49
- package/src/__tests__/chaining.test.ts +27 -27
- package/src/__tests__/collection.test.ts +12 -12
- package/src/__tests__/compose.test.ts +10 -10
- package/src/__tests__/context.test.ts +65 -65
- package/src/__tests__/createLocalProvider.test.ts +53 -53
- package/src/__tests__/dimensions.test.ts +54 -54
- package/src/__tests__/e2e-styler.test.ts +142 -136
- package/src/__tests__/hooks.test.ts +41 -70
- package/src/__tests__/isRocketComponent.test.ts +11 -11
- package/src/__tests__/misc.test.ts +91 -91
- package/src/__tests__/providerConsumer.test.ts +54 -126
- package/src/__tests__/rocketstyleIntegration.test.ts +182 -255
- package/src/__tests__/themeUtils.test.ts +173 -173
- package/src/cache/index.ts +1 -1
- package/src/constants/booleanTags.ts +25 -25
- package/src/constants/defaultDimensions.ts +5 -5
- package/src/constants/index.ts +16 -16
- package/src/context/context.ts +13 -10
- package/src/context/createLocalProvider.ts +26 -13
- package/src/context/localContext.ts +2 -2
- package/src/hoc/index.ts +1 -1
- package/src/hoc/rocketstyleAttrsHoc.ts +26 -29
- package/src/hooks/index.ts +2 -2
- package/src/hooks/usePseudoState.ts +3 -3
- package/src/hooks/useTheme.ts +14 -17
- package/src/index.ts +32 -15
- package/src/init.ts +12 -12
- package/src/isRocketComponent.ts +2 -2
- package/src/rocketstyle.ts +125 -112
- package/src/types/attrs.ts +2 -2
- package/src/types/config.ts +4 -4
- package/src/types/configuration.ts +5 -5
- package/src/types/dimensions.ts +5 -5
- package/src/types/hoc.ts +1 -1
- package/src/types/rocketComponent.ts +4 -4
- package/src/types/rocketstyle.ts +10 -10
- package/src/types/styles.ts +9 -4
- package/src/types/theme.ts +4 -4
- package/src/types/utils.ts +1 -1
- package/src/utils/attrs.ts +2 -2
- package/src/utils/chaining.ts +2 -2
- package/src/utils/compose.ts +1 -1
- package/src/utils/dimensions.ts +6 -6
- package/src/utils/statics.ts +2 -2
- package/src/utils/styles.ts +2 -2
- package/src/utils/theme.ts +10 -10
|
@@ -1,148 +1,95 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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(
|
|
88
|
-
it(
|
|
34
|
+
describe('rocketstyle factory', () => {
|
|
35
|
+
it('creates a component from factory', () => {
|
|
89
36
|
const Button = rocketstyle()({
|
|
90
|
-
name:
|
|
37
|
+
name: 'TestButton',
|
|
91
38
|
component: BaseComponent,
|
|
92
39
|
})
|
|
93
40
|
expect(Button).toBeDefined()
|
|
94
|
-
expect(typeof Button).toBe(
|
|
41
|
+
expect(typeof Button).toBe('function')
|
|
95
42
|
})
|
|
96
43
|
|
|
97
|
-
it(
|
|
44
|
+
it('sets IS_ROCKETSTYLE on the component', () => {
|
|
98
45
|
const Button = rocketstyle()({
|
|
99
|
-
name:
|
|
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(
|
|
53
|
+
it('sets displayName on the component', () => {
|
|
107
54
|
const Button = rocketstyle()({
|
|
108
|
-
name:
|
|
55
|
+
name: 'MyButton',
|
|
109
56
|
component: BaseComponent,
|
|
110
57
|
})
|
|
111
|
-
expect(Button.displayName).toBe(
|
|
58
|
+
expect(Button.displayName).toBe('MyButton')
|
|
112
59
|
})
|
|
113
60
|
|
|
114
|
-
it(
|
|
61
|
+
it('throws when component is missing', () => {
|
|
115
62
|
expect(() => {
|
|
116
|
-
rocketstyle()({ name:
|
|
117
|
-
}).toThrow(
|
|
63
|
+
rocketstyle()({ name: 'Test', component: undefined as any })
|
|
64
|
+
}).toThrow('component')
|
|
118
65
|
})
|
|
119
66
|
|
|
120
|
-
it(
|
|
67
|
+
it('throws when name is missing', () => {
|
|
121
68
|
expect(() => {
|
|
122
|
-
rocketstyle()({ name:
|
|
123
|
-
}).toThrow(
|
|
69
|
+
rocketstyle()({ name: '', component: BaseComponent })
|
|
70
|
+
}).toThrow('name')
|
|
124
71
|
})
|
|
125
72
|
|
|
126
|
-
it(
|
|
73
|
+
it('throws when dimension uses reserved key', () => {
|
|
127
74
|
expect(() => {
|
|
128
|
-
rocketstyle({ dimensions: { attrs:
|
|
129
|
-
name:
|
|
75
|
+
rocketstyle({ dimensions: { attrs: 'attrs' } as any })({
|
|
76
|
+
name: 'Test',
|
|
130
77
|
component: BaseComponent,
|
|
131
78
|
})
|
|
132
|
-
}).toThrow(
|
|
79
|
+
}).toThrow('invalid')
|
|
133
80
|
})
|
|
134
81
|
|
|
135
|
-
it(
|
|
82
|
+
it('allows custom dimensions', () => {
|
|
136
83
|
const Button = rocketstyle({
|
|
137
|
-
dimensions: { colors:
|
|
138
|
-
})({ name:
|
|
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(
|
|
90
|
+
it('defaults useBooleans to true', () => {
|
|
144
91
|
const Button = rocketstyle()({
|
|
145
|
-
name:
|
|
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(
|
|
102
|
+
describe('chaining methods', () => {
|
|
156
103
|
const Button: any = rocketstyle()({
|
|
157
|
-
name:
|
|
104
|
+
name: 'ChainButton',
|
|
158
105
|
component: BaseComponent,
|
|
159
106
|
})
|
|
160
107
|
|
|
161
|
-
it(
|
|
162
|
-
const Enhanced = Button.attrs(() => ({ label:
|
|
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(
|
|
169
|
-
const Enhanced = Button.attrs(() => ({ label:
|
|
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(
|
|
177
|
-
const Enhanced = Button.attrs(() => ({ label:
|
|
178
|
-
filter: [
|
|
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(
|
|
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(
|
|
190
|
-
const Enhanced = Button.statics({ customMeta:
|
|
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(
|
|
139
|
+
expect(Enhanced.meta.customMeta).toBe('value')
|
|
193
140
|
})
|
|
194
141
|
|
|
195
|
-
it(
|
|
196
|
-
const Enhanced = Button.theme(() => ({ color:
|
|
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(
|
|
202
|
-
const Enhanced = Button.styles(() =>
|
|
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(
|
|
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(
|
|
213
|
-
const Enhanced = Button.theme(() => ({ color:
|
|
214
|
-
.attrs(() => ({ label:
|
|
215
|
-
.config({ name:
|
|
216
|
-
.statics({ version:
|
|
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(
|
|
166
|
+
expect(Enhanced.meta.version).toBe('1.0')
|
|
220
167
|
})
|
|
221
168
|
|
|
222
|
-
it(
|
|
169
|
+
it('.getStaticDimensions() returns dimension info', () => {
|
|
223
170
|
const Themed = Button.states(() => ({
|
|
224
|
-
primary: { color:
|
|
225
|
-
secondary: { color:
|
|
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(
|
|
181
|
+
it('.getDefaultAttrs() evaluates attrs chain', () => {
|
|
235
182
|
const WithAttrs = Button.attrs((props: any) => ({
|
|
236
|
-
label:
|
|
183
|
+
label: 'default',
|
|
237
184
|
...props,
|
|
238
185
|
}))
|
|
239
|
-
const result = WithAttrs.getDefaultAttrs({}, {},
|
|
240
|
-
expect(result.label).toBe(
|
|
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(
|
|
248
|
-
it(
|
|
194
|
+
describe('rendering', () => {
|
|
195
|
+
it('renders a basic rocketstyle component', () => {
|
|
249
196
|
const Button: any = rocketstyle()({
|
|
250
|
-
name:
|
|
197
|
+
name: 'RenderButton',
|
|
251
198
|
component: BaseComponent,
|
|
252
199
|
}).config({})
|
|
253
200
|
|
|
254
|
-
const result = renderProps(Button, { children:
|
|
201
|
+
const result = renderProps(Button, { children: 'Hello' })
|
|
255
202
|
expect(result).toBeDefined()
|
|
256
203
|
})
|
|
257
204
|
|
|
258
|
-
it(
|
|
205
|
+
it('adds data-rocketstyle attribute in dev mode', () => {
|
|
259
206
|
const Button: any = rocketstyle()({
|
|
260
|
-
name:
|
|
207
|
+
name: 'DevButton',
|
|
261
208
|
component: BaseComponent,
|
|
262
209
|
}).config({})
|
|
263
210
|
|
|
264
211
|
const result = renderProps(Button)
|
|
265
|
-
expect(result[
|
|
212
|
+
expect(result['data-rocketstyle']).toBe('DevButton')
|
|
266
213
|
})
|
|
267
214
|
|
|
268
|
-
it(
|
|
215
|
+
it('renders with attrs defaults', () => {
|
|
269
216
|
const Button: any = rocketstyle()({
|
|
270
|
-
name:
|
|
217
|
+
name: 'AttrsButton',
|
|
271
218
|
component: BaseComponent,
|
|
272
|
-
}).attrs((() => ({
|
|
219
|
+
}).attrs((() => ({ 'data-default': 'yes' })) as any)
|
|
273
220
|
|
|
274
221
|
const result = renderProps(Button)
|
|
275
|
-
expect(result[
|
|
222
|
+
expect(result['data-default']).toBe('yes')
|
|
276
223
|
})
|
|
277
224
|
|
|
278
|
-
it(
|
|
225
|
+
it('explicit props override attrs', () => {
|
|
279
226
|
const Button: any = rocketstyle()({
|
|
280
|
-
name:
|
|
227
|
+
name: 'OverrideButton',
|
|
281
228
|
component: BaseComponent,
|
|
282
|
-
}).attrs((() => ({
|
|
229
|
+
}).attrs((() => ({ 'data-val': 'from-attrs' })) as any)
|
|
283
230
|
|
|
284
|
-
const result = renderProps(Button, {
|
|
285
|
-
expect(result[
|
|
231
|
+
const result = renderProps(Button, { 'data-val': 'from-props' })
|
|
232
|
+
expect(result['data-val']).toBe('from-props')
|
|
286
233
|
})
|
|
287
234
|
|
|
288
|
-
it(
|
|
235
|
+
it('renders with theme', () => {
|
|
289
236
|
const Button: any = rocketstyle()({
|
|
290
|
-
name:
|
|
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(
|
|
245
|
+
it('renders with dimension states', () => {
|
|
299
246
|
const Button: any = rocketstyle()({
|
|
300
|
-
name:
|
|
247
|
+
name: 'StatesButton',
|
|
301
248
|
component: BaseComponent,
|
|
302
249
|
})
|
|
303
|
-
.theme(() => ({ color:
|
|
250
|
+
.theme(() => ({ color: 'default' }))
|
|
304
251
|
.states(() => ({
|
|
305
|
-
primary: { color:
|
|
306
|
-
secondary: { color:
|
|
252
|
+
primary: { color: 'blue' },
|
|
253
|
+
secondary: { color: 'green' },
|
|
307
254
|
}))
|
|
308
255
|
|
|
309
|
-
const result = renderProps(Button, { state:
|
|
256
|
+
const result = renderProps(Button, { state: 'primary' })
|
|
310
257
|
expect(result).toBeDefined()
|
|
311
258
|
})
|
|
312
259
|
|
|
313
|
-
it(
|
|
260
|
+
it('renders with boolean dimension props', () => {
|
|
314
261
|
const Button: any = rocketstyle()({
|
|
315
|
-
name:
|
|
262
|
+
name: 'BoolButton',
|
|
316
263
|
component: BaseComponent,
|
|
317
264
|
}).states(() => ({
|
|
318
|
-
primary: { color:
|
|
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(
|
|
273
|
+
it('renders with priority attrs', () => {
|
|
327
274
|
const Button: any = rocketstyle()({
|
|
328
|
-
name:
|
|
275
|
+
name: 'PriorityButton',
|
|
329
276
|
component: BaseComponent,
|
|
330
|
-
}).attrs((() => ({
|
|
277
|
+
}).attrs((() => ({ 'data-priority': 'yes' })) as any, { priority: true })
|
|
331
278
|
|
|
332
279
|
const result = renderProps(Button)
|
|
333
|
-
expect(result[
|
|
280
|
+
expect(result['data-priority']).toBe('yes')
|
|
334
281
|
})
|
|
335
282
|
})
|
|
336
283
|
|
|
337
284
|
// --------------------------------------------------------
|
|
338
285
|
// DEBUG option
|
|
339
286
|
// --------------------------------------------------------
|
|
340
|
-
describe(
|
|
341
|
-
it(
|
|
342
|
-
const debugSpy = vi.spyOn(console,
|
|
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:
|
|
294
|
+
name: 'DebugButton',
|
|
348
295
|
component: BaseComponent,
|
|
349
296
|
}).config({ DEBUG: true })
|
|
350
297
|
|
|
351
298
|
renderProps(Button)
|
|
352
299
|
expect(debugSpy).toHaveBeenCalledWith(
|
|
353
|
-
|
|
300
|
+
'[rocketstyle] DebugButton render:',
|
|
354
301
|
expect.objectContaining({
|
|
355
|
-
component:
|
|
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(
|
|
367
|
-
const debugSpy = vi.spyOn(console,
|
|
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:
|
|
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(
|
|
387
|
-
it(
|
|
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:
|
|
396
|
-
props: { ...rest,
|
|
342
|
+
type: 'div',
|
|
343
|
+
props: { ...rest, 'data-state': state },
|
|
397
344
|
children,
|
|
398
345
|
key: null,
|
|
399
346
|
})
|
|
400
|
-
PassPropsComponent.displayName =
|
|
347
|
+
PassPropsComponent.displayName = 'PassPropsComponent'
|
|
401
348
|
|
|
402
349
|
const Button: any = rocketstyle()({
|
|
403
|
-
name:
|
|
350
|
+
name: 'PassPropsButton',
|
|
404
351
|
component: PassPropsComponent,
|
|
405
352
|
})
|
|
406
353
|
.states(() => ({
|
|
407
|
-
primary: { color:
|
|
408
|
-
secondary: { color:
|
|
354
|
+
primary: { color: 'blue' },
|
|
355
|
+
secondary: { color: 'green' },
|
|
409
356
|
}))
|
|
410
|
-
.config({ passProps: [
|
|
357
|
+
.config({ passProps: ['state'] } as any)
|
|
411
358
|
|
|
412
|
-
const result = renderProps(Button, { state:
|
|
413
|
-
expect(result[
|
|
359
|
+
const result = renderProps(Button, { state: 'primary' })
|
|
360
|
+
expect(result['data-state']).toBe('primary')
|
|
414
361
|
})
|
|
415
362
|
|
|
416
|
-
it(
|
|
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:
|
|
425
|
-
props: { ...rest,
|
|
371
|
+
type: 'div',
|
|
372
|
+
props: { ...rest, 'data-state': state ?? 'none' },
|
|
426
373
|
children,
|
|
427
374
|
key: null,
|
|
428
375
|
})
|
|
429
|
-
PassPropsComponent.displayName =
|
|
376
|
+
PassPropsComponent.displayName = 'NoPassPropsComponent'
|
|
430
377
|
|
|
431
378
|
const Button: any = rocketstyle()({
|
|
432
|
-
name:
|
|
379
|
+
name: 'NoPassPropsButton',
|
|
433
380
|
component: PassPropsComponent,
|
|
434
381
|
}).states(() => ({
|
|
435
|
-
primary: { color:
|
|
382
|
+
primary: { color: 'blue' },
|
|
436
383
|
}))
|
|
437
384
|
|
|
438
|
-
const result = renderProps(Button, { state:
|
|
385
|
+
const result = renderProps(Button, { state: 'primary' })
|
|
439
386
|
// Without passProps, the state prop should be filtered out
|
|
440
|
-
expect(result[
|
|
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(
|
|
448
|
-
it(
|
|
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:
|
|
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 =
|
|
403
|
+
MarkedComponent.displayName = 'MarkedComponent'
|
|
457
404
|
|
|
458
405
|
const Outer: any = rocketstyle()({
|
|
459
|
-
name:
|
|
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(
|
|
412
|
+
expect(Outer.displayName).toBe('OuterComponent')
|
|
466
413
|
})
|
|
467
414
|
|
|
468
|
-
it(
|
|
415
|
+
it('renders IS_ROCKETSTYLE component when chained with config', () => {
|
|
469
416
|
const MarkedComponent: any = ({ children, $rocketstyle, $rocketstate, ...rest }: any) => ({
|
|
470
|
-
type:
|
|
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 =
|
|
423
|
+
MarkedComponent.displayName = 'MarkedComponent'
|
|
477
424
|
|
|
478
425
|
const Outer: any = rocketstyle()({
|
|
479
|
-
name:
|
|
426
|
+
name: 'OuterChained',
|
|
480
427
|
component: MarkedComponent,
|
|
481
428
|
}).config({})
|
|
482
429
|
|
|
483
|
-
const result = renderProps(Outer, { children:
|
|
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(
|
|
492
|
-
it(
|
|
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:
|
|
442
|
+
name: 'EmptyDimensions',
|
|
496
443
|
component: BaseComponent,
|
|
497
444
|
})
|
|
498
|
-
}).toThrow(
|
|
445
|
+
}).toThrow('dimensions')
|
|
499
446
|
})
|
|
500
447
|
})
|
|
501
448
|
|
|
502
449
|
// --------------------------------------------------------
|
|
503
450
|
// multiple dimension values
|
|
504
451
|
// --------------------------------------------------------
|
|
505
|
-
describe(
|
|
506
|
-
it(
|
|
452
|
+
describe('multiple dimension values', () => {
|
|
453
|
+
it('renders with array values for multi-key dimensions', () => {
|
|
507
454
|
const Button: any = rocketstyle()({
|
|
508
|
-
name:
|
|
455
|
+
name: 'MultiButton',
|
|
509
456
|
component: BaseComponent,
|
|
510
457
|
}).multiple(() => ({
|
|
511
|
-
bold: { fontWeight:
|
|
512
|
-
italic: { fontStyle:
|
|
513
|
-
underline: { textDecoration:
|
|
458
|
+
bold: { fontWeight: 'bold' },
|
|
459
|
+
italic: { fontStyle: 'italic' },
|
|
460
|
+
underline: { textDecoration: 'underline' },
|
|
514
461
|
}))
|
|
515
462
|
|
|
516
|
-
const result = renderProps(Button, { multiple: [
|
|
463
|
+
const result = renderProps(Button, { multiple: ['bold', 'italic'] })
|
|
517
464
|
expect(result).toBeDefined()
|
|
518
465
|
})
|
|
519
466
|
|
|
520
|
-
it(
|
|
467
|
+
it('renders with single value for non-multi dimensions', () => {
|
|
521
468
|
const Button: any = rocketstyle()({
|
|
522
|
-
name:
|
|
469
|
+
name: 'SingleDimButton',
|
|
523
470
|
component: BaseComponent,
|
|
524
471
|
})
|
|
525
472
|
.states(() => ({
|
|
526
|
-
primary: { color:
|
|
527
|
-
secondary: { color:
|
|
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:
|
|
481
|
+
const result = renderProps(Button, { state: 'primary', size: 'large' })
|
|
535
482
|
expect(result).toBeDefined()
|
|
536
483
|
})
|
|
537
484
|
|
|
538
|
-
it(
|
|
485
|
+
it('renders with boolean shorthand for multi-key dimensions', () => {
|
|
539
486
|
const Button: any = rocketstyle()({
|
|
540
|
-
name:
|
|
487
|
+
name: 'MultiBoolButton',
|
|
541
488
|
component: BaseComponent,
|
|
542
489
|
}).multiple(() => ({
|
|
543
|
-
bold: { fontWeight:
|
|
544
|
-
italic: { fontStyle:
|
|
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(
|
|
557
|
-
it(
|
|
503
|
+
describe('rendering without Provider context', () => {
|
|
504
|
+
it('renders component without any Provider (useContext returns default)', () => {
|
|
558
505
|
const Button: any = rocketstyle()({
|
|
559
|
-
name:
|
|
506
|
+
name: 'NoProviderButton',
|
|
560
507
|
component: BaseComponent,
|
|
561
508
|
}).config({})
|
|
562
509
|
|
|
563
510
|
// Call without any context pushed
|
|
564
|
-
const vnode = Button({ children:
|
|
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(
|
|
574
|
-
it(
|
|
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:
|
|
587
|
-
component:
|
|
523
|
+
name: 'ThemeInjButton',
|
|
524
|
+
component: ThemeCapture,
|
|
588
525
|
})
|
|
589
|
-
.theme(() => ({ color:
|
|
526
|
+
.theme(() => ({ color: 'blue', bg: 'white' }))
|
|
590
527
|
.states(() => ({
|
|
591
|
-
primary: { color:
|
|
528
|
+
primary: { color: 'red' },
|
|
592
529
|
}))
|
|
593
530
|
|
|
594
|
-
const
|
|
595
|
-
expect(
|
|
596
|
-
expect(
|
|
597
|
-
expect(
|
|
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(
|
|
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:
|
|
613
|
-
component:
|
|
539
|
+
name: 'StateInjButton',
|
|
540
|
+
component: ThemeCapture,
|
|
614
541
|
}).states(() => ({
|
|
615
|
-
primary: { color:
|
|
542
|
+
primary: { color: 'blue' },
|
|
616
543
|
}))
|
|
617
544
|
|
|
618
|
-
const vnode = withThemeContext(() =>
|
|
545
|
+
const vnode = withThemeContext(() => Button({ state: 'primary' }))
|
|
619
546
|
expect(vnode.$rocketstate).toBeDefined()
|
|
620
|
-
expect(vnode.$rocketstate.state).toBe(
|
|
547
|
+
expect(vnode.$rocketstate.state).toBe('primary')
|
|
621
548
|
})
|
|
622
549
|
})
|