@domql/element 3.1.2 → 3.2.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 (135) hide show
  1. package/README.md +4 -6
  2. package/children.js +45 -18
  3. package/create.js +58 -46
  4. package/define.js +1 -1
  5. package/dist/cjs/children.js +43 -13
  6. package/dist/cjs/create.js +57 -27
  7. package/dist/cjs/define.js +1 -1
  8. package/dist/cjs/event/animationFrame.js +96 -0
  9. package/dist/cjs/event/can.js +28 -0
  10. package/dist/cjs/event/index.js +20 -0
  11. package/dist/cjs/event/on.js +84 -0
  12. package/dist/cjs/event/store.js +27 -0
  13. package/dist/cjs/extend.js +88 -0
  14. package/dist/cjs/index.js +9 -6
  15. package/dist/cjs/iterate.js +89 -33
  16. package/dist/cjs/methods/set.js +5 -0
  17. package/dist/cjs/methods/v2.js +1 -1
  18. package/dist/cjs/mixins/attr.js +3 -2
  19. package/dist/cjs/mixins/classList.js +11 -1
  20. package/dist/cjs/mixins/content.js +72 -0
  21. package/dist/cjs/mixins/html.js +1 -2
  22. package/dist/cjs/mixins/registry.js +2 -2
  23. package/dist/cjs/mixins/scope.js +1 -1
  24. package/dist/cjs/mixins/state.js +4 -4
  25. package/dist/cjs/mixins/style.js +11 -2
  26. package/dist/cjs/mixins/text.js +9 -5
  27. package/dist/cjs/node.js +22 -19
  28. package/dist/cjs/render/append.js +72 -0
  29. package/dist/cjs/render/cache.js +80 -0
  30. package/dist/cjs/render/create.js +25 -0
  31. package/dist/cjs/render/index.js +20 -0
  32. package/dist/cjs/set.js +33 -40
  33. package/dist/cjs/update.js +100 -69
  34. package/dist/cjs/utils/applyParam.js +7 -7
  35. package/dist/cjs/utils/extendUtils.js +132 -0
  36. package/dist/cjs/utils/index.js +2 -0
  37. package/dist/cjs/utils/propEvents.js +56 -0
  38. package/dist/esm/children.js +44 -14
  39. package/dist/esm/create.js +58 -27
  40. package/dist/esm/define.js +1 -1
  41. package/dist/esm/event/animationFrame.js +76 -0
  42. package/dist/esm/event/can.js +8 -0
  43. package/dist/esm/event/index.js +3 -0
  44. package/dist/esm/event/on.js +64 -0
  45. package/dist/esm/event/store.js +7 -0
  46. package/dist/esm/extend.js +74 -0
  47. package/dist/esm/index.js +8 -6
  48. package/dist/esm/iterate.js +90 -35
  49. package/dist/esm/methods/set.js +10 -0
  50. package/dist/esm/methods/v2.js +1 -1
  51. package/dist/esm/mixins/attr.js +4 -3
  52. package/dist/esm/mixins/classList.js +11 -1
  53. package/dist/esm/mixins/content.js +52 -0
  54. package/dist/esm/mixins/html.js +1 -2
  55. package/dist/esm/mixins/registry.js +1 -1
  56. package/dist/esm/mixins/scope.js +1 -1
  57. package/dist/esm/mixins/state.js +5 -5
  58. package/dist/esm/mixins/style.js +12 -3
  59. package/dist/esm/mixins/text.js +10 -6
  60. package/dist/esm/node.js +22 -19
  61. package/dist/esm/render/append.js +52 -0
  62. package/dist/esm/render/cache.js +60 -0
  63. package/dist/esm/render/create.js +5 -0
  64. package/dist/esm/render/index.js +3 -0
  65. package/dist/esm/set.js +34 -41
  66. package/dist/esm/update.js +100 -71
  67. package/dist/esm/utils/applyParam.js +8 -8
  68. package/dist/esm/utils/extendUtils.js +119 -0
  69. package/dist/esm/utils/index.js +1 -0
  70. package/dist/esm/utils/propEvents.js +36 -0
  71. package/dist/iife/index.js +4718 -0
  72. package/extend.js +95 -0
  73. package/index.js +9 -6
  74. package/iterate.js +100 -38
  75. package/node.js +25 -23
  76. package/package.json +44 -20
  77. package/set.js +28 -32
  78. package/update.js +111 -82
  79. package/__tests__/checkIfOnUpdate.test.js +0 -103
  80. package/__tests__/children.test.js +0 -213
  81. package/__tests__/define.test.js +0 -75
  82. package/__tests__/inheritStateUpdates.test.js +0 -79
  83. package/__tests__/renderElement.test.js +0 -131
  84. package/__tests__/resetElement.test.js +0 -44
  85. package/__tests__/set.test.js +0 -316
  86. package/__tests__/throughExecProps.test.js +0 -86
  87. package/__tests__/throughInitialDefine.test.js +0 -104
  88. package/__tests__/throughInitialExec.test.js +0 -92
  89. package/__tests__/throughUpdatedDefine.test.js +0 -92
  90. package/__tests__/throughUpdatedExec.test.js +0 -110
  91. package/__tests__/tree.test.js +0 -15
  92. package/__tests__/update.test.js +0 -256
  93. package/dist/cjs/__tests__/checkIfOnUpdate.test.js +0 -73
  94. package/dist/cjs/__tests__/children.test.js +0 -177
  95. package/dist/cjs/__tests__/define.test.js +0 -75
  96. package/dist/cjs/__tests__/inheritStateUpdates.test.js +0 -62
  97. package/dist/cjs/__tests__/renderElement.test.js +0 -138
  98. package/dist/cjs/__tests__/resetElement.test.js +0 -35
  99. package/dist/cjs/__tests__/set.test.js +0 -256
  100. package/dist/cjs/__tests__/throughExecProps.test.js +0 -62
  101. package/dist/cjs/__tests__/throughInitialDefine.test.js +0 -79
  102. package/dist/cjs/__tests__/throughInitialExec.test.js +0 -73
  103. package/dist/cjs/__tests__/throughUpdatedDefine.test.js +0 -69
  104. package/dist/cjs/__tests__/throughUpdatedExec.test.js +0 -84
  105. package/dist/cjs/__tests__/tree.test.js +0 -11
  106. package/dist/cjs/__tests__/update.test.js +0 -222
  107. package/dist/cjs/package.json +0 -4
  108. package/dist/esm/__tests__/checkIfOnUpdate.test.js +0 -73
  109. package/dist/esm/__tests__/children.test.js +0 -177
  110. package/dist/esm/__tests__/define.test.js +0 -53
  111. package/dist/esm/__tests__/inheritStateUpdates.test.js +0 -62
  112. package/dist/esm/__tests__/renderElement.test.js +0 -116
  113. package/dist/esm/__tests__/resetElement.test.js +0 -35
  114. package/dist/esm/__tests__/set.test.js +0 -256
  115. package/dist/esm/__tests__/throughExecProps.test.js +0 -62
  116. package/dist/esm/__tests__/throughInitialDefine.test.js +0 -79
  117. package/dist/esm/__tests__/throughInitialExec.test.js +0 -73
  118. package/dist/esm/__tests__/throughUpdatedDefine.test.js +0 -69
  119. package/dist/esm/__tests__/throughUpdatedExec.test.js +0 -84
  120. package/dist/esm/__tests__/tree.test.js +0 -11
  121. package/dist/esm/__tests__/update.test.js +0 -222
  122. package/methods/set.js +0 -63
  123. package/methods/v2.js +0 -83
  124. package/mixins/attr.js +0 -32
  125. package/mixins/classList.js +0 -54
  126. package/mixins/data.js +0 -26
  127. package/mixins/html.js +0 -21
  128. package/mixins/index.js +0 -23
  129. package/mixins/registry.js +0 -46
  130. package/mixins/scope.js +0 -23
  131. package/mixins/state.js +0 -19
  132. package/mixins/style.js +0 -16
  133. package/mixins/text.js +0 -26
  134. package/utils/applyParam.js +0 -34
  135. package/utils/index.js +0 -3
package/update.js CHANGED
@@ -11,17 +11,15 @@ import {
11
11
  isUndefined,
12
12
  merge,
13
13
  overwriteDeep,
14
- deepClone,
15
14
  isMethod,
16
15
  findInheritedState,
17
- deepMerge,
18
16
  OPTIONS,
19
17
  updateProps,
20
18
  captureSnapshot,
21
19
  propertizeUpdate
22
20
  } from '@domql/utils'
23
21
 
24
- import { applyEvent, triggerEventOn, triggerEventOnUpdate } from '@domql/event'
22
+ import { applyEvent, triggerEventOn, triggerEventOnUpdate } from './event/index.js'
25
23
  import { createState } from '@domql/state'
26
24
 
27
25
  import { create } from './create.js'
@@ -45,15 +43,11 @@ const UPDATE_DEFAULT_OPTIONS = {
45
43
  exclude: METHODS_EXL
46
44
  }
47
45
 
48
- export const update = async function (params = {}, opts) {
49
- const calleeElementCache = opts?.calleeElement
50
- const options = deepClone(
51
- isObject(opts)
52
- ? deepMerge(opts, UPDATE_DEFAULT_OPTIONS)
53
- : UPDATE_DEFAULT_OPTIONS,
54
- { exclude: ['calleeElement'] }
55
- )
56
- options.calleeElement = calleeElementCache
46
+ export const update = function (params = {}, opts) {
47
+ // Shallow copy is sufficient - all values are primitives/references that shouldn't be cloned
48
+ const options = isObject(opts)
49
+ ? { ...UPDATE_DEFAULT_OPTIONS, ...opts }
50
+ : { ...UPDATE_DEFAULT_OPTIONS }
57
51
  const element = this
58
52
 
59
53
  let ref = element.__ref
@@ -66,7 +60,7 @@ export const update = async function (params = {}, opts) {
66
60
  if (snapshotHasUpdated) return
67
61
 
68
62
  if (!options.preventListeners) {
69
- await triggerEventOnUpdate('startUpdate', params, element, options)
63
+ triggerEventOnUpdate('startUpdate', params, element, options)
70
64
  }
71
65
 
72
66
  const { parent, node, key } = element
@@ -87,29 +81,32 @@ export const update = async function (params = {}, opts) {
87
81
  // apply new updates
88
82
  params = propertizeUpdate.call(element, params)
89
83
 
90
- const inheritState = await inheritStateUpdates(element, options)
84
+ const inheritState = inheritStateUpdates(element, options)
91
85
  if (inheritState === false) return
92
86
 
93
- const ifFails = await checkIfOnUpdate(element, parent, options)
87
+ const ifFails = checkIfOnUpdate(element, parent, options)
94
88
  if (ifFails) return
95
89
 
96
90
  if (ref.__if && !options.preventPropsUpdate) {
97
91
  const hasParentProps =
98
92
  parent.props && (parent.props[key] || parent.props.childProps)
99
- const hasFunctionInProps = ref.__propsStack.filter(v => isFunction(v))
100
- const props = params.props || hasParentProps || hasFunctionInProps.length
93
+ const hasFunctionInProps = ref.__propsStack.some(isFunction)
94
+ const props = params.props || hasParentProps || hasFunctionInProps
101
95
  if (props) updateProps(props, element, parent)
102
96
  }
103
97
 
104
98
  if (!options.preventBeforeUpdateListener && !options.preventListeners) {
105
- const simulate = { ...params, ...element }
106
- const beforeUpdateReturns = await triggerEventOnUpdate(
107
- 'beforeUpdate',
108
- params,
109
- simulate,
110
- options
111
- )
112
- if (beforeUpdateReturns === false) return element
99
+ const hasBeforeUpdate = element.on?.beforeUpdate || element.props?.onBeforeUpdate
100
+ if (hasBeforeUpdate) {
101
+ const simulate = { ...params, ...element }
102
+ const beforeUpdateReturns = triggerEventOnUpdate(
103
+ 'beforeUpdate',
104
+ params,
105
+ simulate,
106
+ options
107
+ )
108
+ if (beforeUpdateReturns === false) return element
109
+ }
113
110
  }
114
111
 
115
112
  // apply new updates
@@ -121,14 +118,11 @@ export const update = async function (params = {}, opts) {
121
118
  throughUpdatedDefine(element)
122
119
 
123
120
  if (!options.isForced && !options.preventListeners) {
124
- await triggerEventOn('beforeClassAssign', element, options)
121
+ triggerEventOn('beforeClassAssign', element, options)
125
122
  }
126
123
 
127
124
  if (!ref.__if) return false
128
- if (!node) {
129
- // return createNode(element, options)
130
- return
131
- }
125
+ if (!node) return
132
126
 
133
127
  const {
134
128
  preventUpdate,
@@ -152,15 +146,24 @@ export const update = async function (params = {}, opts) {
152
146
  } else options.preventUpdateAfterCount++
153
147
  }
154
148
 
149
+ // Convert arrays to Sets once for O(1) lookups during iteration
150
+ const preventUpdateSet = isArray(preventUpdate) ? new Set(preventUpdate) : null
151
+ const preventDefineUpdateSet = isArray(preventDefineUpdate) ? new Set(preventDefineUpdate) : null
152
+
155
153
  for (const param in element) {
156
154
  const prop = element[param]
157
155
 
158
- if (!Object.hasOwnProperty.call(element, param)) continue
156
+ if (!Object.prototype.hasOwnProperty.call(element, param)) continue
159
157
 
160
158
  const isInPreventUpdate =
161
- isArray(preventUpdate) && preventUpdate.includes(param)
159
+ preventUpdateSet && preventUpdateSet.has(param)
162
160
  const isInPreventDefineUpdate =
163
- isArray(preventDefineUpdate) && preventDefineUpdate.includes(param)
161
+ preventDefineUpdateSet && preventDefineUpdateSet.has(param)
162
+
163
+ // Skip onXxx event handler functions (e.g. onClick) that may remain at root level
164
+ const isRootEventHandler = isFunction(prop) && param.length > 2 &&
165
+ param.charCodeAt(0) === 111 && param.charCodeAt(1) === 110 && // 'on'
166
+ param.charCodeAt(2) >= 65 && param.charCodeAt(2) <= 90 // A-Z
164
167
 
165
168
  if (
166
169
  isUndefined(prop) ||
@@ -168,8 +171,9 @@ export const update = async function (params = {}, opts) {
168
171
  isInPreventDefineUpdate ||
169
172
  preventDefineUpdate === true ||
170
173
  preventDefineUpdate === param ||
171
- (preventStateUpdate && param) === 'state' ||
174
+ (preventStateUpdate && param === 'state') ||
172
175
  isMethod(param, element) ||
176
+ isRootEventHandler ||
173
177
  isObject(REGISTRY[param])
174
178
  ) {
175
179
  continue
@@ -177,7 +181,7 @@ export const update = async function (params = {}, opts) {
177
181
 
178
182
  if (preventStateUpdate === 'once') options.preventStateUpdate = false
179
183
 
180
- const isElement = await applyParam(param, element, options)
184
+ const isElement = applyParam(param, element, options)
181
185
  if (isElement) {
182
186
  const { hasDefine, hasContextDefine } = isElement
183
187
  const canUpdate =
@@ -190,43 +194,89 @@ export const update = async function (params = {}, opts) {
190
194
  options.onEachUpdate(param, element, element.state, element.context)
191
195
  }
192
196
 
193
- const childUpdateCall = async () =>
194
- await update.call(prop, params[prop], {
197
+ const childParams = params[param]
198
+ if (childParams === undefined && !options.isForced) continue
199
+
200
+ const childUpdateCall = () =>
201
+ update.call(prop, childParams, {
195
202
  ...options,
196
203
  currentSnapshot: snapshotOnCallee,
197
204
  calleeElement
198
205
  })
199
206
 
200
207
  if (lazyLoad) {
201
- window.requestAnimationFrame(async () => {
208
+ window.requestAnimationFrame(() => {
202
209
  // eslint-disable-line
203
- await childUpdateCall()
210
+ childUpdateCall()
204
211
  // handle lazy load
205
- if (!options.preventUpdateListener) {
206
- await triggerEventOn('lazyLoad', element, options)
212
+ if (!options.preventUpdateListener && !options.preventListeners) {
213
+ triggerEventOn('lazyLoad', element, options)
207
214
  }
208
215
  })
209
- } else await childUpdateCall()
216
+ } else childUpdateCall()
210
217
  }
211
218
  }
212
219
 
213
220
  if (!preventContentUpdate) {
214
- const children = params.children || element.children
215
- const content = children
216
- ? await setChildren(children, element, opts)
217
- : element.children || params.content
221
+ // Update existing content element if it's a live DOMQL element
222
+ const contentKey = ref.contentElementKey || 'content'
223
+ const existingContent = element[contentKey]
224
+
225
+ // Re-evaluate children if the element has a children property
226
+ const childrenProp = params.children || element.children
227
+ if (childrenProp) {
228
+ const content = setChildren(childrenProp, element, opts)
229
+ if (content && !ref.__noChildrenDifference) {
230
+ setContent(content, element, options)
231
+ } else if (existingContent?.__ref && isFunction(existingContent.update)) {
232
+ const lazyLoad = element.props?.lazyLoad || options.lazyLoad
233
+ const contentUpdateCall = () =>
234
+ update.call(existingContent, params[contentKey], {
235
+ ...options,
236
+ currentSnapshot: snapshotOnCallee,
237
+ calleeElement
238
+ })
239
+
240
+ if (lazyLoad) {
241
+ window.requestAnimationFrame(() => {
242
+ contentUpdateCall()
243
+ if (!options.preventUpdateListener && !options.preventListeners) {
244
+ triggerEventOn('lazyLoad', element, options)
245
+ }
246
+ })
247
+ } else contentUpdateCall()
248
+ }
249
+ } else if (existingContent?.__ref && isFunction(existingContent.update)) {
250
+ const lazyLoad = element.props?.lazyLoad || options.lazyLoad
251
+ const contentUpdateCall = () =>
252
+ update.call(existingContent, params[contentKey], {
253
+ ...options,
254
+ currentSnapshot: snapshotOnCallee,
255
+ calleeElement
256
+ })
218
257
 
219
- if (content) {
220
- await setContent(content, element, options)
258
+ if (lazyLoad) {
259
+ window.requestAnimationFrame(() => {
260
+ contentUpdateCall()
261
+ if (!options.preventUpdateListener && !options.preventListeners) {
262
+ triggerEventOn('lazyLoad', element, options)
263
+ }
264
+ })
265
+ } else contentUpdateCall()
266
+ } else {
267
+ const content = element.children || params.content
268
+ if (content) {
269
+ setContent(content, element, options)
270
+ }
221
271
  }
222
272
  }
223
273
 
224
- if (!preventUpdateListener) {
225
- await triggerEventOn('update', element, options)
274
+ if (!preventUpdateListener && !options.preventListeners) {
275
+ triggerEventOn('update', element, options)
226
276
  }
227
277
  }
228
278
 
229
- const checkIfOnUpdate = async (element, parent, options) => {
279
+ const checkIfOnUpdate = (element, parent, options) => {
230
280
  if ((!isFunction(element.if) && !isFunction(element.props?.if)) || !parent) {
231
281
  return
232
282
  }
@@ -275,8 +325,7 @@ const checkIfOnUpdate = async (element, parent, options) => {
275
325
 
276
326
  const nextElement = element.nextElement()
277
327
  const nextNode = nextElement?.node // document.body.contains(previousElement.node)
278
- const hasNext = nextNode?.parentNode // && document.body.contains(nextElement.node)
279
- // const hasNext = nextElement && document.body.contains(nextElement.node)
328
+ const hasNext = nextNode?.parentNode
280
329
 
281
330
  const attachOptions = (hasPrevious || hasNext) && {
282
331
  position: hasPrevious ? 'after' : hasNext ? 'before' : null,
@@ -285,7 +334,7 @@ const checkIfOnUpdate = async (element, parent, options) => {
285
334
 
286
335
  delete element.__ref
287
336
  delete element.parent
288
- const createdElement = await create(
337
+ const createdElement = create(
289
338
  element,
290
339
  parent,
291
340
  element.key,
@@ -298,11 +347,7 @@ const checkIfOnUpdate = async (element, parent, options) => {
298
347
  element.on &&
299
348
  isFunction(element.on.update)
300
349
  ) {
301
- await applyEvent(
302
- element.on.update,
303
- createdElement,
304
- createdElement.state
305
- )
350
+ applyEvent(element.on.update, createdElement, createdElement.state)
306
351
  }
307
352
  return createdElement
308
353
  }
@@ -326,7 +371,7 @@ const checkIfOnUpdate = async (element, parent, options) => {
326
371
  * @param {boolean} [options.preventStateUpdateListener] - If true, prevent the 'stateUpdate' event listener.
327
372
  * @returns {boolean} - If returns false, it breaks the update function
328
373
  */
329
- const inheritStateUpdates = async (element, options) => {
374
+ const inheritStateUpdates = (element, options) => {
330
375
  const { __ref: ref } = element
331
376
  const stateKey = ref.__state
332
377
  const { parent, state } = element
@@ -337,7 +382,7 @@ const inheritStateUpdates = async (element, options) => {
337
382
 
338
383
  // If does not have own state inherit from parent
339
384
  if (!stateKey && !ref.__hasRootState) {
340
- element.state = (parent && parent.state) || {}
385
+ element.state = parent?.state || {}
341
386
  return
342
387
  }
343
388
 
@@ -361,7 +406,7 @@ const inheritStateUpdates = async (element, options) => {
361
406
 
362
407
  // Trigger on.beforeStateUpdate event
363
408
  if (!options.preventBeforeStateUpdateListener && !options.preventListeners) {
364
- const initStateReturns = await triggerEventOnUpdate(
409
+ const initStateReturns = triggerEventOnUpdate(
365
410
  'beforeStateUpdate',
366
411
  keyInParentState,
367
412
  element,
@@ -371,22 +416,17 @@ const inheritStateUpdates = async (element, options) => {
371
416
  }
372
417
 
373
418
  // Recreate the state again
374
- const newState = await createStateUpdate(element, parent, options)
419
+ const newState = createStateUpdate(element, parent, options)
375
420
 
376
421
  // Trigger on.stateUpdate event
377
422
  if (!options.preventStateUpdateListener && !options.preventListeners) {
378
- await triggerEventOnUpdate(
379
- 'stateUpdate',
380
- newState.parse(),
381
- element,
382
- options
383
- )
423
+ triggerEventOnUpdate('stateUpdate', newState.parse(), element, options)
384
424
  }
385
425
  }
386
426
 
387
- const createStateUpdate = async (element, parent, options) => {
427
+ const createStateUpdate = (element, parent, options) => {
388
428
  const __stateChildren = element.state.__children
389
- const newState = await createState(element, parent)
429
+ const newState = createState(element, parent)
390
430
  element.state = newState
391
431
  for (const child in __stateChildren) {
392
432
  // check this for inherited states
@@ -398,14 +438,3 @@ const createStateUpdate = async (element, parent, options) => {
398
438
  }
399
439
 
400
440
  export default update
401
-
402
- // save updates history
403
- // const overwriteChanges = overwriteDeep(element, params, { exclude: METHODS_EXL })
404
- // // const overwriteChanges = overwriteDeep(element, params)
405
- // const propsChanges = throughExecProps(element)
406
- // const execChanges = throughUpdatedExec(element, { ignore: UPDATE_DEFAULT_OPTIONS })
407
- // const definedChanges = throughUpdatedDefine(element)
408
- // if (options.stackChanges && ref.__stackChanges) {
409
- // const stackChanges = merge(definedChanges, merge(execChanges, overwriteChanges))
410
- // ref.__stackChanges.push(stackChanges)
411
- // }
@@ -1,103 +0,0 @@
1
- import { update } from '../update'
2
-
3
- describe('checkIfOnUpdate via update()', () => {
4
- let element, parent, options
5
-
6
- beforeEach(() => {
7
- parent = {
8
- node: document.createElement('div'),
9
- props: {},
10
- state: {}
11
- }
12
-
13
- element = {
14
- __ref: {
15
- __if: undefined,
16
- __state: null,
17
- __hasRootState: false,
18
- __execProps: {},
19
- contentElementKey: 'content'
20
- },
21
- parent,
22
- props: {},
23
- state: {
24
- update: (el, st) => {
25
- return st
26
- }
27
- },
28
- context: {
29
- defaultExtends: {}
30
- },
31
- node: document.createElement('div'),
32
- if: () => true,
33
- previousElement: () => {
34
- return {}
35
- },
36
- nextElement: () => {
37
- return {}
38
- },
39
- removeContent: () => {
40
- return true
41
- }
42
- }
43
-
44
- options = {}
45
- })
46
-
47
- it('uses props.if when element.if missing', async () => {
48
- delete element.if
49
- element.props.if = () => false
50
- await update.call(element, {}, options)
51
- expect(element.node).toEqual(document.createElement('div'))
52
- })
53
-
54
- it('retains state when __hasRootState=true', async () => {
55
- element.__ref.__hasRootState = true
56
- element.state.critical = true
57
- element.__ref.__if = false
58
-
59
- await update.call(element, {}, options)
60
-
61
- expect(element.state.critical).toBe(true)
62
- expect(element.state.preserved).toBeUndefined()
63
- })
64
-
65
- it('processes nested content with parseDeep', async () => {
66
- element.content = {
67
- parseDeep: () => ({ parsed: true }),
68
- existing: 'data'
69
- }
70
-
71
- await update.call(element, {}, options)
72
-
73
- expect(element.content.parsed).toBe(true)
74
- expect(element.content.existing).toBeUndefined()
75
- })
76
-
77
- it('reattaches after previous sibling', async () => {
78
- const prevNode = document.createElement('span')
79
- parent.node.appendChild(prevNode)
80
-
81
- await update.call(element, {}, options)
82
-
83
- const newElement = parent.node.children[0]
84
- expect(newElement).toEqual(document.createElement('span'))
85
- expect(newElement.previousSibling).toBe(null)
86
- })
87
-
88
- // it('reattaches before next sibling', async () => {
89
- // const nextNode = document.createElement('p')
90
- // parent.node.appendChild(nextNode)
91
-
92
- // await update.call(element, {}, options)
93
-
94
- // const newElement = parent.node.children[0]
95
- // expect(newElement).toEqual(document.createElement('p'))
96
- // expect(newElement.nextSibling).toBe(null)
97
- // })
98
-
99
- // it('appends to parent when no siblings exist', async () => {
100
- // await update.call(element, {}, options)
101
- // expect(parent.node.children).toHaveLength(0)
102
- // })
103
- })
@@ -1,213 +0,0 @@
1
- import { jest } from '@jest/globals'
2
- import { setChildren } from '../children'
3
-
4
- describe('children', () => {
5
- let element, node
6
-
7
- beforeEach(() => {
8
- element = {
9
- __ref: {},
10
- state: {},
11
- props: {},
12
- call: jest.fn(),
13
- removeContent: jest.fn(),
14
- content: null
15
- }
16
- node = {}
17
- })
18
-
19
- it('handles null/undefined params', async () => {
20
- const result = await setChildren(null, element, node)
21
- expect(result).toBeUndefined()
22
- })
23
-
24
- it('handles direct string children', async () => {
25
- const result = await setChildren('Hello World', element, node)
26
- expect(result).toEqual({ tag: 'fragment', 0: { text: 'Hello World' } })
27
- })
28
-
29
- it('handles numeric children', async () => {
30
- const result = await setChildren(42, element, node)
31
- expect(result).toEqual({ tag: 'fragment', 0: { text: 42 } })
32
- })
33
-
34
- it('handles array of primitive values with childrenAs prop', async () => {
35
- const result = await setChildren(['one', 'two'], element, node)
36
-
37
- expect(result).toEqual({
38
- tag: 'fragment',
39
- 0: { text: 'one' },
40
- 1: { text: 'two' }
41
- })
42
- })
43
-
44
- it('handles array of primitive values with childrenAs state', async () => {
45
- element.props.childrenAs = 'state'
46
- const result = await setChildren(['one', 'two'], element, node)
47
-
48
- expect(result).toEqual({
49
- tag: 'fragment',
50
- 0: { state: { value: 'one' } },
51
- 1: { state: { value: 'two' } }
52
- })
53
- })
54
-
55
- it('caches children and detects changes', async () => {
56
- const children1 = [{ id: 1 }, { id: 2 }]
57
- const children2 = [{ id: 1 }, { id: 2 }]
58
- const children3 = [{ id: 1 }, { id: 3 }]
59
-
60
- // First call
61
- await setChildren(children1, element, node)
62
- expect(element.__ref.__childrenCache).toEqual(children1)
63
- expect(element.__ref.__noChildrenDifference).toBeUndefined()
64
-
65
- // Same content, different reference
66
- await setChildren(children2, element, node)
67
- expect(element.__ref.__noChildrenDifference).toBe(true)
68
-
69
- // Different content
70
- await setChildren(children3, element, node)
71
- expect(element.__ref.__noChildrenDifference).toBeUndefined()
72
- expect(element.__ref.__childrenCache).toEqual(children3)
73
- })
74
-
75
- it('handles mixed React and normal components', async () => {
76
- const mixedChildren = [
77
- { type: 'div', text: 'Normal' },
78
- { $$typeof: Symbol('react') },
79
- { type: 'span', text: 'Another' }
80
- ]
81
-
82
- await setChildren(mixedChildren, element, node)
83
-
84
- expect(element.call).toHaveBeenCalledWith(
85
- 'renderReact',
86
- [mixedChildren[1]],
87
- element
88
- )
89
- })
90
-
91
- it('handles state-based children', async () => {
92
- element.state = {
93
- items: ['a', 'b'],
94
- parse: () => ['parsed a', 'parsed b']
95
- }
96
-
97
- const result = await setChildren('state', element, node)
98
- expect(result).toEqual({
99
- tag: 'fragment',
100
- 0: { text: 'parsed a' },
101
- 1: { text: 'parsed b' }
102
- })
103
- })
104
-
105
- it('handles async function parameters', async () => {
106
- const asyncParam = async () => ['async1', 'async2']
107
- const result = await setChildren(asyncParam, element, node)
108
-
109
- expect(result).toEqual({
110
- tag: 'fragment',
111
- 0: { text: 'async1' },
112
- 1: { text: 'async2' }
113
- })
114
- })
115
-
116
- it('handles nested object structures', async () => {
117
- const nestedChildren = {
118
- header: { text: 'Title' },
119
- content: {
120
- nested: { text: 'Content' }
121
- }
122
- }
123
-
124
- const result = await setChildren(nestedChildren, element, node)
125
- expect(result).toEqual({
126
- tag: 'fragment',
127
- 0: { text: 'Title' },
128
- 1: { nested: { text: 'Content' } }
129
- })
130
- })
131
-
132
- it('handles empty arrays and objects', async () => {
133
- let result = await setChildren([], element, node)
134
- expect(result).toEqual({
135
- tag: 'fragment'
136
- })
137
-
138
- result = await setChildren({}, element, node)
139
- expect(result).toEqual({
140
- tag: 'fragment'
141
- })
142
- })
143
-
144
- it('handles falsy values in arrays', async () => {
145
- const result = await setChildren(
146
- [null, undefined, false, 0, ''],
147
- element,
148
- node
149
- )
150
- expect(result).toEqual({
151
- tag: 'fragment',
152
- 3: { text: 0 },
153
- 4: { text: '' }
154
- })
155
- })
156
-
157
- it('handles React components with falsy values in array', async () => {
158
- const mixedChildren = [
159
- null,
160
- { $$typeof: Symbol('react') },
161
- undefined,
162
- { $$typeof: Symbol('react') },
163
- false
164
- ]
165
-
166
- await setChildren(mixedChildren, element, node)
167
-
168
- expect(element.call).toHaveBeenCalledWith(
169
- 'renderReact',
170
- [mixedChildren[1], mixedChildren[3]],
171
- element
172
- )
173
- })
174
-
175
- it('handles nested state parsing', async () => {
176
- element.state = {
177
- nested: {
178
- items: ['c', 'd']
179
- }
180
- }
181
- element.state.nested.__proto__.parse = () => ['parsed c', 'parsed d']
182
-
183
- const result = await setChildren('nested', element, node)
184
- expect(result).toEqual({
185
- tag: 'fragment',
186
- 0: { state: ['c', 'd'] }
187
- })
188
- })
189
-
190
- it('handles mixed state and regular objects', async () => {
191
- element.state = {
192
- header: { parse: () => 'Header' },
193
- footer: { parse: () => 'Footer' }
194
- }
195
-
196
- const result = await setChildren(
197
- {
198
- header: 'header',
199
- content: { text: 'Content' },
200
- footer: 'footer'
201
- },
202
- element,
203
- node
204
- )
205
-
206
- expect(result).toEqual({
207
- tag: 'fragment',
208
- 0: { text: 'header' },
209
- 1: { text: 'Content' },
210
- 2: { text: 'footer' }
211
- })
212
- })
213
- })