@pyreon/rocketstyle 0.24.5 → 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.
- package/package.json +8 -10
- package/src/__tests__/attrs-overloads.test.ts +0 -97
- package/src/__tests__/attrs.test.ts +0 -190
- package/src/__tests__/cache-key-boolean-collision.test.ts +0 -54
- package/src/__tests__/chaining.test.ts +0 -86
- package/src/__tests__/collection.test.ts +0 -35
- package/src/__tests__/compose.test.ts +0 -36
- package/src/__tests__/context.test.ts +0 -200
- package/src/__tests__/createLocalProvider.test.ts +0 -280
- package/src/__tests__/dimensions.test.ts +0 -183
- package/src/__tests__/e2e-styler.test.ts +0 -299
- package/src/__tests__/hooks.test.ts +0 -178
- package/src/__tests__/isRocketComponent.test.ts +0 -48
- package/src/__tests__/memo-cap.test.ts +0 -174
- package/src/__tests__/minimal-theme.test.ts +0 -62
- package/src/__tests__/misc.test.ts +0 -204
- package/src/__tests__/native-marker.test.ts +0 -9
- package/src/__tests__/providerConsumer.test.ts +0 -183
- package/src/__tests__/reactive-props-preservation.test.ts +0 -195
- package/src/__tests__/rocketstyle.browser.test.tsx +0 -481
- package/src/__tests__/rocketstyleIntegration.test.ts +0 -711
- package/src/__tests__/theme-integration.test.tsx +0 -254
- package/src/__tests__/themeUtils.test.ts +0 -463
- package/src/cache/LocalThemeManager.ts +0 -14
- package/src/cache/index.ts +0 -3
- package/src/constants/booleanTags.ts +0 -32
- package/src/constants/defaultDimensions.ts +0 -23
- package/src/constants/index.ts +0 -59
- package/src/context/context.ts +0 -70
- package/src/context/createLocalProvider.ts +0 -97
- package/src/context/localContext.ts +0 -37
- package/src/env.d.ts +0 -6
- package/src/hoc/index.ts +0 -3
- package/src/hoc/rocketstyleAttrsHoc.ts +0 -76
- package/src/hooks/index.ts +0 -4
- package/src/hooks/usePseudoState.ts +0 -79
- package/src/hooks/useTheme.ts +0 -48
- package/src/index.ts +0 -95
- package/src/init.ts +0 -93
- package/src/isRocketComponent.ts +0 -16
- package/src/rocketstyle.ts +0 -640
- package/src/types/attrs.ts +0 -23
- package/src/types/config.ts +0 -48
- package/src/types/configuration.ts +0 -69
- package/src/types/dimensions.ts +0 -109
- package/src/types/hoc.ts +0 -5
- package/src/types/pseudo.ts +0 -19
- package/src/types/rocketComponent.ts +0 -24
- package/src/types/rocketstyle.ts +0 -220
- package/src/types/styles.ts +0 -61
- package/src/types/theme.ts +0 -18
- package/src/types/utils.ts +0 -98
- package/src/utils/attrs.ts +0 -181
- package/src/utils/chaining.ts +0 -58
- package/src/utils/collection.ts +0 -9
- package/src/utils/compose.ts +0 -11
- package/src/utils/dimensions.ts +0 -126
- package/src/utils/statics.ts +0 -44
- package/src/utils/styles.ts +0 -18
- package/src/utils/theme.ts +0 -211
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import type { VNodeChild } from '@pyreon/core'
|
|
2
|
-
import { h, useContext } from '@pyreon/core'
|
|
3
|
-
import { Provider as CoreProvider } from '@pyreon/ui-core'
|
|
4
|
-
import Provider from '../context/context'
|
|
5
|
-
|
|
6
|
-
// Mock @pyreon/core useContext to return controlled values
|
|
7
|
-
vi.mock('@pyreon/core', async (importOriginal) => {
|
|
8
|
-
const original = await importOriginal<typeof import('@pyreon/core')>()
|
|
9
|
-
return {
|
|
10
|
-
...original,
|
|
11
|
-
useContext: vi.fn(() => (() => ({}))),
|
|
12
|
-
}
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
// Mock @pyreon/ui-core Provider and context
|
|
16
|
-
vi.mock('@pyreon/ui-core', async (importOriginal) => {
|
|
17
|
-
const original = await importOriginal<typeof import('@pyreon/ui-core')>()
|
|
18
|
-
return {
|
|
19
|
-
...original,
|
|
20
|
-
Provider: vi.fn(((props: Record<string, unknown>) => ({
|
|
21
|
-
type: 'div',
|
|
22
|
-
props: { ...props, 'data-provider': 'core' },
|
|
23
|
-
children: props.children,
|
|
24
|
-
key: null,
|
|
25
|
-
})) as any),
|
|
26
|
-
context: original.context,
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const mockedUseContext = vi.mocked(useContext)
|
|
31
|
-
const mockedCoreProvider = vi.mocked(CoreProvider)
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
vi.clearAllMocks()
|
|
35
|
-
// Default: empty context
|
|
36
|
-
mockedUseContext.mockReturnValue((() => ({})) as any)
|
|
37
|
-
mockedCoreProvider.mockImplementation(((props: Record<string, unknown>) => ({
|
|
38
|
-
type: 'div',
|
|
39
|
-
props: { ...props, 'data-provider': 'core' },
|
|
40
|
-
children: props.children as VNodeChild,
|
|
41
|
-
key: null,
|
|
42
|
-
})) as any)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
describe('Provider (context)', () => {
|
|
46
|
-
it('uses MODE_DEFAULT (light) when no mode is provided', () => {
|
|
47
|
-
mockedUseContext.mockReturnValue((() => ({})) as any)
|
|
48
|
-
|
|
49
|
-
const children = h('span', null, 'Hello')
|
|
50
|
-
Provider({ children })
|
|
51
|
-
|
|
52
|
-
expect(mockedCoreProvider).toHaveBeenCalledTimes(1)
|
|
53
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
54
|
-
expect(callArgs.mode).toBe('light')
|
|
55
|
-
expect(callArgs.isLight).toBe(true)
|
|
56
|
-
expect(callArgs.isDark).toBe(false)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('passes mode directly when inversed is false', () => {
|
|
60
|
-
mockedUseContext.mockReturnValue((() => ({ mode: 'dark' })) as any)
|
|
61
|
-
|
|
62
|
-
const children = h('span', null, 'Hello')
|
|
63
|
-
Provider({ children, mode: 'dark', inversed: false })
|
|
64
|
-
|
|
65
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
66
|
-
expect(callArgs.mode).toBe('dark')
|
|
67
|
-
expect(callArgs.isDark).toBe(true)
|
|
68
|
-
expect(callArgs.isLight).toBe(false)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('passes mode directly when inversed is undefined', () => {
|
|
72
|
-
const children = h('span', null, 'Hello')
|
|
73
|
-
Provider({ children, mode: 'dark' })
|
|
74
|
-
|
|
75
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
76
|
-
expect(callArgs.mode).toBe('dark')
|
|
77
|
-
expect(callArgs.isDark).toBe(true)
|
|
78
|
-
expect(callArgs.isLight).toBe(false)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('inverts light to dark when inversed is true', () => {
|
|
82
|
-
const children = h('span', null, 'Hello')
|
|
83
|
-
Provider({ children, mode: 'light', inversed: true })
|
|
84
|
-
|
|
85
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
86
|
-
expect(callArgs.mode).toBe('dark')
|
|
87
|
-
expect(callArgs.isDark).toBe(true)
|
|
88
|
-
expect(callArgs.isLight).toBe(false)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('inverts dark to light when inversed is true', () => {
|
|
92
|
-
const children = h('span', null, 'Hello')
|
|
93
|
-
Provider({ children, mode: 'dark', inversed: true })
|
|
94
|
-
|
|
95
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
96
|
-
expect(callArgs.mode).toBe('light')
|
|
97
|
-
expect(callArgs.isLight).toBe(true)
|
|
98
|
-
expect(callArgs.isDark).toBe(false)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('passes theme to provider when provided', () => {
|
|
102
|
-
const theme = { rootSize: 16, breakpoints: { sm: 576 } }
|
|
103
|
-
const children = h('span', null, 'Hello')
|
|
104
|
-
Provider({ children, theme })
|
|
105
|
-
|
|
106
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
107
|
-
expect(callArgs.theme).toEqual(theme)
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
it('does not pass theme key when theme is undefined', () => {
|
|
111
|
-
const children = h('span', null, 'Hello')
|
|
112
|
-
Provider({ children })
|
|
113
|
-
|
|
114
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
115
|
-
expect('theme' in callArgs).toBe(false)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it('uses custom provider when specified', () => {
|
|
119
|
-
const customProvider = vi.fn((props: Record<string, unknown>) => ({
|
|
120
|
-
type: 'section',
|
|
121
|
-
props,
|
|
122
|
-
children: props.children as VNodeChild,
|
|
123
|
-
key: null,
|
|
124
|
-
}))
|
|
125
|
-
|
|
126
|
-
const children = h('span', null, 'Hello')
|
|
127
|
-
Provider({ children, provider: customProvider as any })
|
|
128
|
-
|
|
129
|
-
expect(customProvider).toHaveBeenCalledTimes(1)
|
|
130
|
-
// CoreProvider should NOT have been called
|
|
131
|
-
expect(mockedCoreProvider).not.toHaveBeenCalled()
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
it('defaults to CoreProvider when no provider prop is given', () => {
|
|
135
|
-
const children = h('span', null, 'Hello')
|
|
136
|
-
Provider({ children })
|
|
137
|
-
|
|
138
|
-
expect(mockedCoreProvider).toHaveBeenCalledTimes(1)
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
it('passes children through to the provider', () => {
|
|
142
|
-
const children = { type: 'span', props: {}, children: ['Hello World'], key: null }
|
|
143
|
-
Provider({ children })
|
|
144
|
-
|
|
145
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
146
|
-
expect(callArgs.children).toBe(children)
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('passes provider reference to the provider call', () => {
|
|
150
|
-
const children = h('span', null, 'Hello')
|
|
151
|
-
Provider({ children })
|
|
152
|
-
|
|
153
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
154
|
-
expect(callArgs.provider).toBe(CoreProvider)
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
it('returns null when provider returns null', () => {
|
|
158
|
-
mockedCoreProvider.mockReturnValue(null as any)
|
|
159
|
-
|
|
160
|
-
const children = h('span', null, 'Hello')
|
|
161
|
-
const result = Provider({ children })
|
|
162
|
-
|
|
163
|
-
expect(result).toBeNull()
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
it('returns null when provider returns undefined', () => {
|
|
167
|
-
mockedCoreProvider.mockReturnValue(undefined as any)
|
|
168
|
-
|
|
169
|
-
const children = h('span', null, 'Hello')
|
|
170
|
-
const result = Provider({ children })
|
|
171
|
-
|
|
172
|
-
expect(result).toBeNull()
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
it('merges context values with incoming props (props take precedence)', () => {
|
|
176
|
-
mockedUseContext.mockReturnValue((() => ({
|
|
177
|
-
mode: 'light',
|
|
178
|
-
theme: { rootSize: 12 },
|
|
179
|
-
})) as any)
|
|
180
|
-
|
|
181
|
-
const overrideTheme = { rootSize: 20 }
|
|
182
|
-
const children = h('span', null, 'Hello')
|
|
183
|
-
Provider({ children, theme: overrideTheme, mode: 'dark' })
|
|
184
|
-
|
|
185
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
186
|
-
expect(callArgs.mode).toBe('dark')
|
|
187
|
-
expect(callArgs.theme).toEqual(overrideTheme)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('uses context mode when no mode prop is given', () => {
|
|
191
|
-
mockedUseContext.mockReturnValue((() => ({ mode: 'dark' })) as any)
|
|
192
|
-
|
|
193
|
-
const children = h('span', null, 'Hello')
|
|
194
|
-
Provider({ children })
|
|
195
|
-
|
|
196
|
-
const callArgs = mockedCoreProvider.mock.calls[0]?.[0] as Record<string, unknown>
|
|
197
|
-
expect(callArgs.mode).toBe('dark')
|
|
198
|
-
expect(callArgs.isDark).toBe(true)
|
|
199
|
-
})
|
|
200
|
-
})
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
import { h, provide } from '@pyreon/core'
|
|
2
|
-
import createLocalProvider from '../context/createLocalProvider'
|
|
3
|
-
|
|
4
|
-
// Mock @pyreon/core provide
|
|
5
|
-
vi.mock('@pyreon/core', async (importOriginal) => {
|
|
6
|
-
const original = await importOriginal<typeof import('@pyreon/core')>()
|
|
7
|
-
return {
|
|
8
|
-
...original,
|
|
9
|
-
provide: vi.fn(),
|
|
10
|
-
}
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
const mockedProvide = vi.mocked(provide)
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
vi.clearAllMocks()
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
/** Simple base component that returns its received props as a VNode for inspection. */
|
|
20
|
-
const BaseComponent: any = vi.fn((props: Record<string, unknown>) => ({
|
|
21
|
-
type: 'div',
|
|
22
|
-
props,
|
|
23
|
-
children: props.children,
|
|
24
|
-
key: null,
|
|
25
|
-
}))
|
|
26
|
-
|
|
27
|
-
describe('createLocalProvider', () => {
|
|
28
|
-
it('returns a component function', () => {
|
|
29
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
30
|
-
expect(typeof HOC).toBe('function')
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('calls the wrapped component with forwarded props', () => {
|
|
34
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
35
|
-
|
|
36
|
-
HOC({ 'data-testid': 'test', title: 'Hello', children: 'Content' } as any)
|
|
37
|
-
|
|
38
|
-
expect(BaseComponent).toHaveBeenCalledTimes(1)
|
|
39
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
40
|
-
expect(callProps['data-testid']).toBe('test')
|
|
41
|
-
expect(callProps.title).toBe('Hello')
|
|
42
|
-
expect(callProps.children).toBe('Content')
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('provides local context via provide()', () => {
|
|
46
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
47
|
-
|
|
48
|
-
HOC({} as any)
|
|
49
|
-
|
|
50
|
-
expect(mockedProvide).toHaveBeenCalledTimes(1)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('initial pseudo state is all false', () => {
|
|
54
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
55
|
-
|
|
56
|
-
HOC({} as any)
|
|
57
|
-
|
|
58
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
59
|
-
const rocketstate = callProps.$rocketstate as Record<string, unknown>
|
|
60
|
-
const pseudo = rocketstate?.pseudo as Record<string, boolean>
|
|
61
|
-
|
|
62
|
-
expect(pseudo.hover).toBe(false)
|
|
63
|
-
expect(pseudo.focus).toBe(false)
|
|
64
|
-
expect(pseudo.pressed).toBe(false)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('injects mouse and focus event handlers', () => {
|
|
68
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
69
|
-
|
|
70
|
-
HOC({} as any)
|
|
71
|
-
|
|
72
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
73
|
-
expect(typeof callProps.onMouseEnter).toBe('function')
|
|
74
|
-
expect(typeof callProps.onMouseLeave).toBe('function')
|
|
75
|
-
expect(typeof callProps.onMouseDown).toBe('function')
|
|
76
|
-
expect(typeof callProps.onMouseUp).toBe('function')
|
|
77
|
-
expect(typeof callProps.onFocus).toBe('function')
|
|
78
|
-
expect(typeof callProps.onBlur).toBe('function')
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('forwards original onMouseEnter handler', () => {
|
|
82
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
83
|
-
const originalHandler = vi.fn()
|
|
84
|
-
const mockEvent = new MouseEvent('mouseenter')
|
|
85
|
-
|
|
86
|
-
HOC({ onMouseEnter: originalHandler } as any)
|
|
87
|
-
|
|
88
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
89
|
-
;(callProps.onMouseEnter as (e: MouseEvent) => void)(mockEvent)
|
|
90
|
-
|
|
91
|
-
expect(originalHandler).toHaveBeenCalledWith(mockEvent)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('forwards original onMouseLeave handler', () => {
|
|
95
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
96
|
-
const originalHandler = vi.fn()
|
|
97
|
-
const mockEvent = new MouseEvent('mouseleave')
|
|
98
|
-
|
|
99
|
-
HOC({ onMouseLeave: originalHandler } as any)
|
|
100
|
-
|
|
101
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
102
|
-
;(callProps.onMouseLeave as (e: MouseEvent) => void)(mockEvent)
|
|
103
|
-
|
|
104
|
-
expect(originalHandler).toHaveBeenCalledWith(mockEvent)
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('forwards original onMouseDown handler', () => {
|
|
108
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
109
|
-
const originalHandler = vi.fn()
|
|
110
|
-
const mockEvent = new MouseEvent('mousedown')
|
|
111
|
-
|
|
112
|
-
HOC({ onMouseDown: originalHandler } as any)
|
|
113
|
-
|
|
114
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
115
|
-
;(callProps.onMouseDown as (e: MouseEvent) => void)(mockEvent)
|
|
116
|
-
|
|
117
|
-
expect(originalHandler).toHaveBeenCalledWith(mockEvent)
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('forwards original onMouseUp handler', () => {
|
|
121
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
122
|
-
const originalHandler = vi.fn()
|
|
123
|
-
const mockEvent = new MouseEvent('mouseup')
|
|
124
|
-
|
|
125
|
-
HOC({ onMouseUp: originalHandler } as any)
|
|
126
|
-
|
|
127
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
128
|
-
;(callProps.onMouseUp as (e: MouseEvent) => void)(mockEvent)
|
|
129
|
-
|
|
130
|
-
expect(originalHandler).toHaveBeenCalledWith(mockEvent)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('forwards original onFocus handler', () => {
|
|
134
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
135
|
-
const originalHandler = vi.fn()
|
|
136
|
-
const mockEvent = new FocusEvent('focus')
|
|
137
|
-
|
|
138
|
-
HOC({ onFocus: originalHandler } as any)
|
|
139
|
-
|
|
140
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
141
|
-
;(callProps.onFocus as (e: FocusEvent) => void)(mockEvent)
|
|
142
|
-
|
|
143
|
-
expect(originalHandler).toHaveBeenCalledWith(mockEvent)
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
it('forwards original onBlur handler', () => {
|
|
147
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
148
|
-
const originalHandler = vi.fn()
|
|
149
|
-
const mockEvent = new FocusEvent('blur')
|
|
150
|
-
|
|
151
|
-
HOC({ onBlur: originalHandler } as any)
|
|
152
|
-
|
|
153
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
154
|
-
;(callProps.onBlur as (e: FocusEvent) => void)(mockEvent)
|
|
155
|
-
|
|
156
|
-
expect(originalHandler).toHaveBeenCalledWith(mockEvent)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
it('does not forward event handlers that were not provided', () => {
|
|
160
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
161
|
-
|
|
162
|
-
HOC({} as any)
|
|
163
|
-
|
|
164
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
165
|
-
// The HOC event handlers should not throw when no original handler exists
|
|
166
|
-
expect(() => {
|
|
167
|
-
;(callProps.onMouseEnter as (e: MouseEvent) => void)(new MouseEvent('mouseenter'))
|
|
168
|
-
;(callProps.onMouseLeave as (e: MouseEvent) => void)(new MouseEvent('mouseleave'))
|
|
169
|
-
;(callProps.onMouseDown as (e: MouseEvent) => void)(new MouseEvent('mousedown'))
|
|
170
|
-
;(callProps.onMouseUp as (e: MouseEvent) => void)(new MouseEvent('mouseup'))
|
|
171
|
-
;(callProps.onFocus as (e: FocusEvent) => void)(new FocusEvent('focus'))
|
|
172
|
-
;(callProps.onBlur as (e: FocusEvent) => void)(new FocusEvent('blur'))
|
|
173
|
-
}).not.toThrow()
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('merges existing $rocketstate with pseudo state', () => {
|
|
177
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
178
|
-
|
|
179
|
-
HOC({
|
|
180
|
-
$rocketstate: { someExisting: 'value', pseudo: { disabled: true } },
|
|
181
|
-
} as any)
|
|
182
|
-
|
|
183
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
184
|
-
const rocketstate = callProps.$rocketstate as Record<string, unknown>
|
|
185
|
-
|
|
186
|
-
expect(rocketstate.someExisting).toBe('value')
|
|
187
|
-
const pseudo = rocketstate.pseudo as Record<string, unknown>
|
|
188
|
-
expect(pseudo.disabled).toBe(true)
|
|
189
|
-
expect(pseudo.hover).toBe(false)
|
|
190
|
-
expect(pseudo.focus).toBe(false)
|
|
191
|
-
expect(pseudo.pressed).toBe(false)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
it('provides updated state to local context', () => {
|
|
195
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
196
|
-
|
|
197
|
-
HOC({} as any)
|
|
198
|
-
|
|
199
|
-
expect(mockedProvide).toHaveBeenCalledTimes(1)
|
|
200
|
-
const [, providedValue] = mockedProvide.mock.calls[0] as [unknown, Record<string, unknown>]
|
|
201
|
-
const pseudo = providedValue.pseudo as Record<string, boolean>
|
|
202
|
-
expect(pseudo.hover).toBe(false)
|
|
203
|
-
expect(pseudo.focus).toBe(false)
|
|
204
|
-
expect(pseudo.pressed).toBe(false)
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('does not pass event handler props to wrapped component as original handler names', () => {
|
|
208
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
209
|
-
const originalMouseEnter = vi.fn()
|
|
210
|
-
|
|
211
|
-
HOC({ onMouseEnter: originalMouseEnter, customProp: 'keep' } as any)
|
|
212
|
-
|
|
213
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
214
|
-
// The wrapped component should receive the HOC event handlers, not the original ones
|
|
215
|
-
expect(callProps.customProp).toBe('keep')
|
|
216
|
-
// The onMouseEnter on the component should be the HOC wrapper, not the original
|
|
217
|
-
expect(callProps.onMouseEnter).not.toBe(originalMouseEnter)
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
it('strips $rocketstate from forwarded props and passes updated version', () => {
|
|
221
|
-
const HOC = createLocalProvider(BaseComponent)
|
|
222
|
-
const originalState = { existing: true }
|
|
223
|
-
|
|
224
|
-
HOC({ $rocketstate: originalState } as any)
|
|
225
|
-
|
|
226
|
-
const callProps = BaseComponent.mock.calls[0]?.[0] as Record<string, unknown>
|
|
227
|
-
const rocketstate = callProps.$rocketstate as Record<string, unknown>
|
|
228
|
-
// Should have merged pseudo state
|
|
229
|
-
expect(rocketstate.pseudo).toBeDefined()
|
|
230
|
-
// Original state is preserved
|
|
231
|
-
expect(rocketstate.existing).toBe(true)
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
it('returns the result of the wrapped component', () => {
|
|
235
|
-
const expectedResult = {
|
|
236
|
-
type: 'div',
|
|
237
|
-
props: { 'data-result': 'yes' },
|
|
238
|
-
children: ['Result'],
|
|
239
|
-
key: null,
|
|
240
|
-
}
|
|
241
|
-
const MockComponent = vi.fn(() => expectedResult)
|
|
242
|
-
const HOC = createLocalProvider(MockComponent as any)
|
|
243
|
-
|
|
244
|
-
const result = HOC({} as any)
|
|
245
|
-
|
|
246
|
-
expect(result).toBe(expectedResult)
|
|
247
|
-
})
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
// ─── createLocalProvider — real h() round-trip ──────────────────────
|
|
251
|
-
//
|
|
252
|
-
// The tests above use a `BaseComponent` mock that returns
|
|
253
|
-
// `{ type, props, children, key }` literals and assert against the
|
|
254
|
-
// shape. This block re-runs key contracts with a base component
|
|
255
|
-
// that returns real h() output — same divergence guard as the
|
|
256
|
-
// attrs / connector-document parallels.
|
|
257
|
-
|
|
258
|
-
describe('createLocalProvider — real h() round-trip', () => {
|
|
259
|
-
it('passes children through a real h() base component', () => {
|
|
260
|
-
const BaseComponentH = vi.fn((props: Record<string, unknown>) =>
|
|
261
|
-
h('div', { 'data-real-h': 'yes', ...props }, props.children as never),
|
|
262
|
-
)
|
|
263
|
-
const HOC = createLocalProvider(BaseComponentH as any)
|
|
264
|
-
const result = HOC({ children: 'hello' } as any) as any
|
|
265
|
-
expect(BaseComponentH).toHaveBeenCalled()
|
|
266
|
-
expect(result.type).toBe('div')
|
|
267
|
-
expect(result.props['data-real-h']).toBe('yes')
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
it('forwards arbitrary props through real h() output', () => {
|
|
271
|
-
const BaseComponentH = vi.fn((props: Record<string, unknown>) =>
|
|
272
|
-
h('button', props, props.label as never),
|
|
273
|
-
)
|
|
274
|
-
const HOC = createLocalProvider(BaseComponentH as any)
|
|
275
|
-
const result = HOC({ label: 'Click', 'data-id': '42' } as any) as any
|
|
276
|
-
expect(result.type).toBe('button')
|
|
277
|
-
expect(result.props.label).toBe('Click')
|
|
278
|
-
expect(result.props['data-id']).toBe('42')
|
|
279
|
-
})
|
|
280
|
-
})
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getDimensionsMap,
|
|
3
|
-
getDimensionsValues,
|
|
4
|
-
getKeys,
|
|
5
|
-
getMultipleDimensions,
|
|
6
|
-
getTransformDimensions,
|
|
7
|
-
getValues,
|
|
8
|
-
isMultiKey,
|
|
9
|
-
isValidKey,
|
|
10
|
-
} from '../utils/dimensions'
|
|
11
|
-
|
|
12
|
-
describe('isValidKey', () => {
|
|
13
|
-
it('returns true for truthy values', () => {
|
|
14
|
-
expect(isValidKey('a')).toBe(true)
|
|
15
|
-
expect(isValidKey(1)).toBe(true)
|
|
16
|
-
expect(isValidKey(true)).toBe(true)
|
|
17
|
-
expect(isValidKey(0)).toBe(true)
|
|
18
|
-
expect(isValidKey('')).toBe(true)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('returns false for undefined, null, false', () => {
|
|
22
|
-
expect(isValidKey(undefined)).toBe(false)
|
|
23
|
-
expect(isValidKey(null)).toBe(false)
|
|
24
|
-
expect(isValidKey(false)).toBe(false)
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
describe('isMultiKey', () => {
|
|
29
|
-
it('returns [true, propName] for object with propName', () => {
|
|
30
|
-
expect(isMultiKey({ propName: 'tags', multi: true })).toEqual([true, 'tags'])
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('returns [false, value] for string', () => {
|
|
34
|
-
expect(isMultiKey('variant')).toEqual([false, 'variant'])
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
describe('getKeys', () => {
|
|
39
|
-
it('returns object keys', () => {
|
|
40
|
-
expect(getKeys({ a: 1, b: 2 })).toEqual(['a', 'b'])
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('returns empty array for empty object', () => {
|
|
44
|
-
expect(getKeys({})).toEqual([])
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
describe('getValues', () => {
|
|
49
|
-
it('returns object values', () => {
|
|
50
|
-
expect(getValues({ a: 1, b: 2 })).toEqual([1, 2])
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
describe('getDimensionsValues', () => {
|
|
55
|
-
it('extracts string dimension values', () => {
|
|
56
|
-
const dimensions = { size: 'size', variant: 'variant' }
|
|
57
|
-
expect(getDimensionsValues(dimensions)).toEqual(['size', 'variant'])
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('extracts propName from object dimensions', () => {
|
|
61
|
-
const dimensions = {
|
|
62
|
-
size: 'size',
|
|
63
|
-
tags: { propName: 'tags', multi: true },
|
|
64
|
-
}
|
|
65
|
-
expect(getDimensionsValues(dimensions)).toEqual(['size', 'tags'])
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
describe('getMultipleDimensions', () => {
|
|
70
|
-
it('identifies multi-key dimensions', () => {
|
|
71
|
-
const dimensions = {
|
|
72
|
-
size: 'size',
|
|
73
|
-
tags: { propName: 'tags', multi: true },
|
|
74
|
-
}
|
|
75
|
-
expect(getMultipleDimensions(dimensions)).toEqual({ tags: true })
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('returns empty for no multi dimensions', () => {
|
|
79
|
-
const dimensions = { size: 'size', variant: 'variant' }
|
|
80
|
-
expect(getMultipleDimensions(dimensions)).toEqual({})
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('skips multi=false', () => {
|
|
84
|
-
const dimensions = {
|
|
85
|
-
tags: { propName: 'tags', multi: false },
|
|
86
|
-
}
|
|
87
|
-
expect(getMultipleDimensions(dimensions)).toEqual({})
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
describe('getDimensionsMap', () => {
|
|
92
|
-
it('builds keysMap and keywords from themes', () => {
|
|
93
|
-
const themes = {
|
|
94
|
-
size: { small: { fontSize: 12 }, large: { fontSize: 18 } },
|
|
95
|
-
}
|
|
96
|
-
const result = getDimensionsMap({ themes })
|
|
97
|
-
expect(result.keysMap).toEqual({
|
|
98
|
-
size: { small: true, large: true },
|
|
99
|
-
})
|
|
100
|
-
expect(result.keywords.size).toBe(true)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('adds dimension keys to keywords when useBooleans', () => {
|
|
104
|
-
const themes = {
|
|
105
|
-
size: { small: { fontSize: 12 }, large: { fontSize: 18 } },
|
|
106
|
-
}
|
|
107
|
-
const result = getDimensionsMap({ themes, useBooleans: true })
|
|
108
|
-
expect(result.keywords.small).toBe(true)
|
|
109
|
-
expect(result.keywords.large).toBe(true)
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('skips invalid values (false, null, undefined)', () => {
|
|
113
|
-
const themes = {
|
|
114
|
-
size: { small: { fontSize: 12 }, disabled: false, hidden: null },
|
|
115
|
-
}
|
|
116
|
-
const result = getDimensionsMap({ themes })
|
|
117
|
-
expect(result.keysMap.size).toEqual({ small: true })
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('returns empty for empty themes', () => {
|
|
121
|
-
const result = getDimensionsMap({ themes: {} })
|
|
122
|
-
expect(result.keysMap).toEqual({})
|
|
123
|
-
expect(result.keywords).toEqual({})
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
it('includes function values (transform modifiers) as valid keys', () => {
|
|
127
|
-
const themes = {
|
|
128
|
-
modifier: {
|
|
129
|
-
outlined: (theme: any) => ({ color: theme.bg }),
|
|
130
|
-
ghost: () => ({ bg: 'transparent' }),
|
|
131
|
-
},
|
|
132
|
-
}
|
|
133
|
-
const result = getDimensionsMap({ themes })
|
|
134
|
-
expect(result.keysMap).toEqual({
|
|
135
|
-
modifier: { outlined: true, ghost: true },
|
|
136
|
-
})
|
|
137
|
-
expect(result.keywords.modifier).toBe(true)
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
it('includes function values as boolean keywords when useBooleans', () => {
|
|
141
|
-
const themes = {
|
|
142
|
-
modifier: {
|
|
143
|
-
outlined: (theme: any) => ({ color: theme.bg }),
|
|
144
|
-
},
|
|
145
|
-
}
|
|
146
|
-
const result = getDimensionsMap({ themes, useBooleans: true })
|
|
147
|
-
expect(result.keywords.outlined).toBe(true)
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
describe('getTransformDimensions', () => {
|
|
152
|
-
it('identifies transform dimensions', () => {
|
|
153
|
-
const dimensions = {
|
|
154
|
-
states: 'state',
|
|
155
|
-
modifiers: { propName: 'modifier', multi: true, transform: true },
|
|
156
|
-
}
|
|
157
|
-
expect(getTransformDimensions(dimensions)).toEqual({ modifier: true })
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('returns empty when no transform dimensions exist', () => {
|
|
161
|
-
const dimensions = {
|
|
162
|
-
states: 'state',
|
|
163
|
-
sizes: 'size',
|
|
164
|
-
multiple: { propName: 'multiple', multi: true },
|
|
165
|
-
}
|
|
166
|
-
expect(getTransformDimensions(dimensions)).toEqual({})
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
it('skips dimensions without transform flag', () => {
|
|
170
|
-
const dimensions = {
|
|
171
|
-
states: 'state',
|
|
172
|
-
tags: { propName: 'tags', multi: true },
|
|
173
|
-
}
|
|
174
|
-
expect(getTransformDimensions(dimensions)).toEqual({})
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
it('skips transform=false', () => {
|
|
178
|
-
const dimensions = {
|
|
179
|
-
modifiers: { propName: 'modifier', multi: true, transform: false },
|
|
180
|
-
}
|
|
181
|
-
expect(getTransformDimensions(dimensions)).toEqual({})
|
|
182
|
-
})
|
|
183
|
-
})
|