@pyreon/kinetic 0.11.4 → 0.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- import type { VNode } from "@pyreon/core"
2
- import GroupRenderer from "../kinetic/GroupRenderer"
3
- import type { KineticConfig } from "../kinetic/types"
1
+ import type { VNode } from '@pyreon/core'
2
+ import GroupRenderer from '../kinetic/GroupRenderer'
3
+ import type { KineticConfig } from '../kinetic/types'
4
4
 
5
5
  // Mock rAF for deterministic testing
6
6
  let rafCallbacks: (() => void)[] = []
@@ -12,97 +12,112 @@ beforeEach(() => {
12
12
  rafCallbacks = []
13
13
 
14
14
  vi.stubGlobal(
15
- "requestAnimationFrame",
15
+ 'requestAnimationFrame',
16
16
  vi.fn((cb: () => void) => {
17
17
  rafCallbacks.push(cb)
18
18
  return rafCallbacks.length
19
19
  }),
20
20
  )
21
21
 
22
- vi.stubGlobal("cancelAnimationFrame", vi.fn())
22
+ vi.stubGlobal('cancelAnimationFrame', vi.fn())
23
23
  })
24
24
 
25
25
  afterEach(() => {
26
26
  vi.useRealTimers()
27
- vi.stubGlobal("requestAnimationFrame", originalRaf)
28
- vi.stubGlobal("cancelAnimationFrame", originalCaf)
27
+ vi.stubGlobal('requestAnimationFrame', originalRaf)
28
+ vi.stubGlobal('cancelAnimationFrame', originalCaf)
29
29
  })
30
30
 
31
31
  const makeConfig = (overrides: Partial<KineticConfig> = {}): KineticConfig => ({
32
- tag: "div",
33
- mode: "group",
34
- enter: "g-enter",
35
- enterFrom: "g-enter-from",
36
- enterTo: "g-enter-to",
37
- leave: "g-leave",
38
- leaveFrom: "g-leave-from",
39
- leaveTo: "g-leave-to",
32
+ tag: 'div',
33
+ mode: 'group',
34
+ enter: 'g-enter',
35
+ enterFrom: 'g-enter-from',
36
+ enterTo: 'g-enter-to',
37
+ leave: 'g-leave',
38
+ leaveFrom: 'g-leave-from',
39
+ leaveTo: 'g-leave-to',
40
40
  ...overrides,
41
41
  })
42
42
 
43
+ /** Unwrap reactive accessors returned by GroupRenderer. */
44
+ const unwrap = (val: any): any => {
45
+ let result = val
46
+ while (typeof result === 'function') result = result()
47
+ return result
48
+ }
49
+
43
50
  const makeKeyedChild = (key: string | number, text: string): VNode => ({
44
- type: "span",
45
- props: { "data-testid": `child-${key}` },
51
+ type: 'span',
52
+ props: { 'data-testid': `child-${key}` },
46
53
  children: [text],
47
54
  key,
48
55
  })
49
56
 
50
- describe("GroupRenderer", () => {
51
- it("returns a VNode wrapping children in config.tag", () => {
57
+ describe('GroupRenderer', () => {
58
+ it('returns a VNode wrapping children in config.tag', () => {
52
59
  const config = makeConfig()
53
- const children = [makeKeyedChild("a", "Alpha"), makeKeyedChild("b", "Beta")]
60
+ const children = [makeKeyedChild('a', 'Alpha'), makeKeyedChild('b', 'Beta')]
54
61
 
55
- const vnode = GroupRenderer({
56
- config,
57
- htmlProps: {},
58
- callbacks: {},
59
- children,
60
- })
62
+ const vnode = unwrap(
63
+ GroupRenderer({
64
+ config,
65
+ htmlProps: {},
66
+ callbacks: {},
67
+ children,
68
+ }),
69
+ )
61
70
 
62
71
  expect(vnode).not.toBeNull()
63
- expect(vnode?.type).toBe("div")
72
+ expect(vnode?.type).toBe('div')
64
73
  })
65
74
 
66
- it("uses custom tag from config", () => {
67
- const config = makeConfig({ tag: "ul" })
68
- const children = [makeKeyedChild("a", "Alpha")]
75
+ it('uses custom tag from config', () => {
76
+ const config = makeConfig({ tag: 'ul' })
77
+ const children = [makeKeyedChild('a', 'Alpha')]
69
78
 
70
- const vnode = GroupRenderer({
71
- config,
72
- htmlProps: {},
73
- callbacks: {},
74
- children,
75
- })
79
+ const vnode = unwrap(
80
+ GroupRenderer({
81
+ config,
82
+ htmlProps: {},
83
+ callbacks: {},
84
+ children,
85
+ }),
86
+ )
76
87
 
77
- expect(vnode?.type).toBe("ul")
88
+ expect(vnode?.type).toBe('ul')
78
89
  })
79
90
 
80
- it("passes htmlProps to the wrapper element", () => {
91
+ it('passes htmlProps to the wrapper element', () => {
81
92
  const config = makeConfig()
82
- const children = [makeKeyedChild("a", "Alpha")]
93
+ const children = [makeKeyedChild('a', 'Alpha')]
83
94
 
84
- const vnode = GroupRenderer({
85
- config,
86
- htmlProps: { "data-testid": "group-wrapper", class: "my-group" },
87
- callbacks: {},
88
- children,
89
- })
95
+ const vnode = unwrap(
96
+ GroupRenderer({
97
+ config,
98
+ htmlProps: { 'data-testid': 'group-wrapper', class: 'my-group' },
99
+ callbacks: {},
100
+ children,
101
+ }),
102
+ )
90
103
 
91
104
  const props = vnode?.props as Record<string, unknown>
92
- expect(props?.["data-testid"]).toBe("group-wrapper")
93
- expect(props?.class).toBe("my-group")
105
+ expect(props?.['data-testid']).toBe('group-wrapper')
106
+ expect(props?.class).toBe('my-group')
94
107
  })
95
108
 
96
- it("wraps each keyed child in a TransitionItem", () => {
109
+ it('wraps each keyed child in a TransitionItem', () => {
97
110
  const config = makeConfig()
98
- const children = [makeKeyedChild("a", "Alpha"), makeKeyedChild("b", "Beta")]
111
+ const children = [makeKeyedChild('a', 'Alpha'), makeKeyedChild('b', 'Beta')]
99
112
 
100
- const vnode = GroupRenderer({
101
- config,
102
- htmlProps: {},
103
- callbacks: {},
104
- children,
105
- })
113
+ const vnode = unwrap(
114
+ GroupRenderer({
115
+ config,
116
+ htmlProps: {},
117
+ callbacks: {},
118
+ children,
119
+ }),
120
+ )
106
121
 
107
122
  // The wrapper div should have children that are TransitionItem VNodes
108
123
  const wrapperChildren = vnode?.children
@@ -113,104 +128,114 @@ describe("GroupRenderer", () => {
113
128
  // Each child should be a TransitionItem (function component)
114
129
  for (const child of childArray) {
115
130
  const childVNode = child as VNode
116
- expect(typeof childVNode.type).toBe("function")
131
+ expect(typeof childVNode.type).toBe('function')
117
132
  }
118
133
  })
119
134
 
120
- it("sets appear=true for newly added children (non-initial)", () => {
135
+ it('sets appear=true for newly added children (non-initial)', () => {
121
136
  const config = makeConfig()
122
137
 
123
138
  // First render with initial children
124
- const initialChildren = [makeKeyedChild("a", "Alpha")]
125
- GroupRenderer({
126
- config,
127
- htmlProps: {},
128
- callbacks: {},
129
- children: initialChildren,
130
- })
139
+ const initialChildren = [makeKeyedChild('a', 'Alpha')]
140
+ unwrap(
141
+ GroupRenderer({
142
+ config,
143
+ htmlProps: {},
144
+ callbacks: {},
145
+ children: initialChildren,
146
+ }),
147
+ )
131
148
 
132
149
  // Second render with a new child added
133
- const updatedChildren = [makeKeyedChild("a", "Alpha"), makeKeyedChild("b", "Beta")]
134
- const vnode = GroupRenderer({
135
- config,
136
- htmlProps: {},
137
- callbacks: {},
138
- children: updatedChildren,
139
- })
150
+ const updatedChildren = [makeKeyedChild('a', 'Alpha'), makeKeyedChild('b', 'Beta')]
151
+ const vnode = unwrap(
152
+ GroupRenderer({
153
+ config,
154
+ htmlProps: {},
155
+ callbacks: {},
156
+ children: updatedChildren,
157
+ }),
158
+ )
140
159
 
141
160
  const wrapperChildren = vnode?.children as VNode[]
142
161
  expect(wrapperChildren.length).toBe(2)
143
162
  })
144
163
 
145
- it("passes transition class config to TransitionItem children", () => {
164
+ it('passes transition class config to TransitionItem children', () => {
146
165
  const config = makeConfig({
147
- enter: "custom-enter",
148
- enterFrom: "custom-from",
149
- enterTo: "custom-to",
150
- leave: "custom-leave",
151
- leaveFrom: "custom-lfrom",
152
- leaveTo: "custom-lto",
166
+ enter: 'custom-enter',
167
+ enterFrom: 'custom-from',
168
+ enterTo: 'custom-to',
169
+ leave: 'custom-leave',
170
+ leaveFrom: 'custom-lfrom',
171
+ leaveTo: 'custom-lto',
153
172
  })
154
- const children = [makeKeyedChild("a", "Alpha")]
173
+ const children = [makeKeyedChild('a', 'Alpha')]
155
174
 
156
- const vnode = GroupRenderer({
157
- config,
158
- htmlProps: {},
159
- callbacks: {},
160
- children,
161
- })
175
+ const vnode = unwrap(
176
+ GroupRenderer({
177
+ config,
178
+ htmlProps: {},
179
+ callbacks: {},
180
+ children,
181
+ }),
182
+ )
162
183
 
163
184
  const wrapperChildren = vnode?.children as VNode[]
164
185
  const transitionItemVNode = wrapperChildren[0] as VNode
165
186
  const tiProps = transitionItemVNode.props as Record<string, unknown>
166
187
 
167
- expect(tiProps.enter).toBe("custom-enter")
168
- expect(tiProps.enterFrom).toBe("custom-from")
169
- expect(tiProps.enterTo).toBe("custom-to")
170
- expect(tiProps.leave).toBe("custom-leave")
171
- expect(tiProps.leaveFrom).toBe("custom-lfrom")
172
- expect(tiProps.leaveTo).toBe("custom-lto")
188
+ expect(tiProps.enter).toBe('custom-enter')
189
+ expect(tiProps.enterFrom).toBe('custom-from')
190
+ expect(tiProps.enterTo).toBe('custom-to')
191
+ expect(tiProps.leave).toBe('custom-leave')
192
+ expect(tiProps.leaveFrom).toBe('custom-lfrom')
193
+ expect(tiProps.leaveTo).toBe('custom-lto')
173
194
  })
174
195
 
175
- it("passes style transition config to TransitionItem children", () => {
196
+ it('passes style transition config to TransitionItem children', () => {
176
197
  const config = makeConfig({
177
198
  enterStyle: { opacity: 0 },
178
199
  enterToStyle: { opacity: 1 },
179
- enterTransition: "opacity 300ms ease",
200
+ enterTransition: 'opacity 300ms ease',
180
201
  leaveStyle: { opacity: 1 },
181
202
  leaveToStyle: { opacity: 0 },
182
- leaveTransition: "opacity 200ms ease-in",
203
+ leaveTransition: 'opacity 200ms ease-in',
183
204
  })
184
- const children = [makeKeyedChild("a", "Alpha")]
205
+ const children = [makeKeyedChild('a', 'Alpha')]
185
206
 
186
- const vnode = GroupRenderer({
187
- config,
188
- htmlProps: {},
189
- callbacks: {},
190
- children,
191
- })
207
+ const vnode = unwrap(
208
+ GroupRenderer({
209
+ config,
210
+ htmlProps: {},
211
+ callbacks: {},
212
+ children,
213
+ }),
214
+ )
192
215
 
193
216
  const wrapperChildren = vnode?.children as VNode[]
194
217
  const tiProps = wrapperChildren[0]?.props as Record<string, unknown>
195
218
 
196
219
  expect(tiProps.enterStyle).toEqual({ opacity: 0 })
197
220
  expect(tiProps.enterToStyle).toEqual({ opacity: 1 })
198
- expect(tiProps.enterTransition).toBe("opacity 300ms ease")
221
+ expect(tiProps.enterTransition).toBe('opacity 300ms ease')
199
222
  expect(tiProps.leaveStyle).toEqual({ opacity: 1 })
200
223
  expect(tiProps.leaveToStyle).toEqual({ opacity: 0 })
201
- expect(tiProps.leaveTransition).toBe("opacity 200ms ease-in")
224
+ expect(tiProps.leaveTransition).toBe('opacity 200ms ease-in')
202
225
  })
203
226
 
204
- it("uses effectiveAppear from config when appear prop is not provided", () => {
227
+ it('uses effectiveAppear from config when appear prop is not provided', () => {
205
228
  const config = makeConfig({ appear: true })
206
- const children = [makeKeyedChild("a", "Alpha")]
229
+ const children = [makeKeyedChild('a', 'Alpha')]
207
230
 
208
- const vnode = GroupRenderer({
209
- config,
210
- htmlProps: {},
211
- callbacks: {},
212
- children,
213
- })
231
+ const vnode = unwrap(
232
+ GroupRenderer({
233
+ config,
234
+ htmlProps: {},
235
+ callbacks: {},
236
+ children,
237
+ }),
238
+ )
214
239
 
215
240
  const wrapperChildren = vnode?.children as VNode[]
216
241
  const tiProps = wrapperChildren[0]?.props as Record<string, unknown>
@@ -219,16 +244,18 @@ describe("GroupRenderer", () => {
219
244
  expect(tiProps.appear).toBe(true)
220
245
  })
221
246
 
222
- it("uses effectiveTimeout from config when timeout prop is not provided", () => {
247
+ it('uses effectiveTimeout from config when timeout prop is not provided', () => {
223
248
  const config = makeConfig({ timeout: 2000 })
224
- const children = [makeKeyedChild("a", "Alpha")]
249
+ const children = [makeKeyedChild('a', 'Alpha')]
225
250
 
226
- const vnode = GroupRenderer({
227
- config,
228
- htmlProps: {},
229
- callbacks: {},
230
- children,
231
- })
251
+ const vnode = unwrap(
252
+ GroupRenderer({
253
+ config,
254
+ htmlProps: {},
255
+ callbacks: {},
256
+ children,
257
+ }),
258
+ )
232
259
 
233
260
  const wrapperChildren = vnode?.children as VNode[]
234
261
  const tiProps = wrapperChildren[0]?.props as Record<string, unknown>
@@ -236,16 +263,18 @@ describe("GroupRenderer", () => {
236
263
  expect(tiProps.timeout).toBe(2000)
237
264
  })
238
265
 
239
- it("defaults timeout to 5000 when not provided", () => {
266
+ it('defaults timeout to 5000 when not provided', () => {
240
267
  const config = makeConfig()
241
- const children = [makeKeyedChild("a", "Alpha")]
268
+ const children = [makeKeyedChild('a', 'Alpha')]
242
269
 
243
- const vnode = GroupRenderer({
244
- config,
245
- htmlProps: {},
246
- callbacks: {},
247
- children,
248
- })
270
+ const vnode = unwrap(
271
+ GroupRenderer({
272
+ config,
273
+ htmlProps: {},
274
+ callbacks: {},
275
+ children,
276
+ }),
277
+ )
249
278
 
250
279
  const wrapperChildren = vnode?.children as VNode[]
251
280
  const tiProps = wrapperChildren[0]?.props as Record<string, unknown>
@@ -253,34 +282,38 @@ describe("GroupRenderer", () => {
253
282
  expect(tiProps.timeout).toBe(5000)
254
283
  })
255
284
 
256
- it("ignores children without keys", () => {
285
+ it('ignores children without keys', () => {
257
286
  const config = makeConfig()
258
- const keyedChild = makeKeyedChild("a", "Alpha")
259
- const unkeyedChild: VNode = { type: "span", props: {}, children: ["No key"], key: null }
260
-
261
- const vnode = GroupRenderer({
262
- config,
263
- htmlProps: {},
264
- callbacks: {},
265
- children: [keyedChild, unkeyedChild],
266
- })
287
+ const keyedChild = makeKeyedChild('a', 'Alpha')
288
+ const unkeyedChild: VNode = { type: 'span', props: {}, children: ['No key'], key: null }
289
+
290
+ const vnode = unwrap(
291
+ GroupRenderer({
292
+ config,
293
+ htmlProps: {},
294
+ callbacks: {},
295
+ children: [keyedChild, unkeyedChild],
296
+ }),
297
+ )
267
298
 
268
299
  // Only keyed child should be wrapped in TransitionItem
269
300
  const wrapperChildren = vnode?.children as VNode[]
270
301
  expect(wrapperChildren.length).toBe(1)
271
302
  })
272
303
 
273
- it("appear prop overrides config.appear", () => {
304
+ it('appear prop overrides config.appear', () => {
274
305
  const config = makeConfig({ appear: false })
275
- const children = [makeKeyedChild("a", "Alpha")]
276
-
277
- const vnode = GroupRenderer({
278
- config,
279
- htmlProps: {},
280
- appear: true,
281
- callbacks: {},
282
- children,
283
- })
306
+ const children = [makeKeyedChild('a', 'Alpha')]
307
+
308
+ const vnode = unwrap(
309
+ GroupRenderer({
310
+ config,
311
+ htmlProps: {},
312
+ appear: true,
313
+ callbacks: {},
314
+ children,
315
+ }),
316
+ )
284
317
 
285
318
  const wrapperChildren = vnode?.children as VNode[]
286
319
  const tiProps = wrapperChildren[0]?.props as Record<string, unknown>
@@ -288,17 +321,19 @@ describe("GroupRenderer", () => {
288
321
  expect(tiProps.appear).toBe(true)
289
322
  })
290
323
 
291
- it("timeout prop overrides config.timeout", () => {
324
+ it('timeout prop overrides config.timeout', () => {
292
325
  const config = makeConfig({ timeout: 2000 })
293
- const children = [makeKeyedChild("a", "Alpha")]
294
-
295
- const vnode = GroupRenderer({
296
- config,
297
- htmlProps: {},
298
- timeout: 3000,
299
- callbacks: {},
300
- children,
301
- })
326
+ const children = [makeKeyedChild('a', 'Alpha')]
327
+
328
+ const vnode = unwrap(
329
+ GroupRenderer({
330
+ config,
331
+ htmlProps: {},
332
+ timeout: 3000,
333
+ callbacks: {},
334
+ children,
335
+ }),
336
+ )
302
337
 
303
338
  const wrapperChildren = vnode?.children as VNode[]
304
339
  const tiProps = wrapperChildren[0]?.props as Record<string, unknown>
@@ -306,17 +341,19 @@ describe("GroupRenderer", () => {
306
341
  expect(tiProps.timeout).toBe(3000)
307
342
  })
308
343
 
309
- it("handleAfterLeave fires the callbacks.onAfterLeave and updates forceUpdateSignal", () => {
344
+ it('handleAfterLeave fires the callbacks.onAfterLeave and updates forceUpdateSignal', () => {
310
345
  const onAfterLeave = vi.fn()
311
346
  const config = makeConfig()
312
- const children = [makeKeyedChild("a", "Alpha")]
347
+ const children = [makeKeyedChild('a', 'Alpha')]
313
348
 
314
- const vnode = GroupRenderer({
315
- config,
316
- htmlProps: {},
317
- callbacks: { onAfterLeave },
318
- children,
319
- })
349
+ const vnode = unwrap(
350
+ GroupRenderer({
351
+ config,
352
+ htmlProps: {},
353
+ callbacks: { onAfterLeave },
354
+ children,
355
+ }),
356
+ )
320
357
 
321
358
  // Each TransitionItem child gets an onAfterLeave that calls handleAfterLeave(key)
322
359
  const wrapperChildren = vnode?.children as VNode[]
@@ -329,16 +366,18 @@ describe("GroupRenderer", () => {
329
366
  expect(onAfterLeave).toHaveBeenCalledTimes(1)
330
367
  })
331
368
 
332
- it("TransitionItem children have show returning true for current children", () => {
369
+ it('TransitionItem children have show returning true for current children', () => {
333
370
  const config = makeConfig()
334
- const children = [makeKeyedChild("a", "Alpha"), makeKeyedChild("b", "Beta")]
371
+ const children = [makeKeyedChild('a', 'Alpha'), makeKeyedChild('b', 'Beta')]
335
372
 
336
- const vnode = GroupRenderer({
337
- config,
338
- htmlProps: {},
339
- callbacks: {},
340
- children,
341
- })
373
+ const vnode = unwrap(
374
+ GroupRenderer({
375
+ config,
376
+ htmlProps: {},
377
+ callbacks: {},
378
+ children,
379
+ }),
380
+ )
342
381
 
343
382
  const wrapperChildren = vnode?.children as VNode[]
344
383
 
@@ -349,16 +388,18 @@ describe("GroupRenderer", () => {
349
388
  }
350
389
  })
351
390
 
352
- it("initial children use effectiveAppear for appear prop", () => {
391
+ it('initial children use effectiveAppear for appear prop', () => {
353
392
  const config = makeConfig({ appear: false })
354
- const children = [makeKeyedChild("a", "Alpha")]
393
+ const children = [makeKeyedChild('a', 'Alpha')]
355
394
 
356
- const vnode = GroupRenderer({
357
- config,
358
- htmlProps: {},
359
- callbacks: {},
360
- children,
361
- })
395
+ const vnode = unwrap(
396
+ GroupRenderer({
397
+ config,
398
+ htmlProps: {},
399
+ callbacks: {},
400
+ children,
401
+ }),
402
+ )
362
403
 
363
404
  const wrapperChildren = vnode?.children as VNode[]
364
405
  const tiProps = wrapperChildren[0]?.props as Record<string, unknown>
@@ -367,16 +408,18 @@ describe("GroupRenderer", () => {
367
408
  expect(tiProps.appear).toBe(false)
368
409
  })
369
410
 
370
- it("each TransitionItem child gets the element as its children", () => {
411
+ it('each TransitionItem child gets the element as its children', () => {
371
412
  const config = makeConfig()
372
- const children = [makeKeyedChild("a", "Alpha")]
373
-
374
- const vnode = GroupRenderer({
375
- config,
376
- htmlProps: {},
377
- callbacks: {},
378
- children,
379
- })
413
+ const children = [makeKeyedChild('a', 'Alpha')]
414
+
415
+ const vnode = unwrap(
416
+ GroupRenderer({
417
+ config,
418
+ htmlProps: {},
419
+ callbacks: {},
420
+ children,
421
+ }),
422
+ )
380
423
 
381
424
  const wrapperChildren = vnode?.children as VNode[]
382
425
  const tiVNode = wrapperChildren[0] as VNode