canvasengine 2.0.0-beta.36 → 2.0.0-beta.38

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.
@@ -14,6 +14,7 @@ import {
14
14
  bufferTime,
15
15
  filter,
16
16
  throttleTime,
17
+ combineLatest,
17
18
  } from "rxjs";
18
19
  import { ComponentInstance } from "../components/DisplayObject";
19
20
  import { Directive, applyDirective } from "./directive";
@@ -101,7 +102,15 @@ function destroyElement(element: Element | Element[]) {
101
102
  element.componentInstance.onDestroy(element.parent as any, () => {
102
103
  element.propSubscriptions?.forEach((sub) => sub.unsubscribe());
103
104
  element.effectSubscriptions?.forEach((sub) => sub.unsubscribe());
104
- element.effectUnmounts?.forEach((fn) => fn?.());
105
+ element.effectUnmounts?.forEach((fn) => {
106
+ if (isPromise(fn)) {
107
+ (fn as unknown as Promise<any>).then((retFn) => {
108
+ retFn?.();
109
+ });
110
+ } else {
111
+ fn?.();
112
+ }
113
+ });
105
114
  });
106
115
  } else {
107
116
  // If componentInstance is undefined or doesn't have onDestroy, still clean up subscriptions
@@ -173,8 +182,8 @@ export function createComponent(tag: string, props?: Props): Element {
173
182
  instance.onUpdate?.(
174
183
  path == ""
175
184
  ? {
176
- [key]: value,
177
- }
185
+ [key]: value,
186
+ }
178
187
  : set({}, path + "." + key, value)
179
188
  );
180
189
  })
@@ -209,9 +218,79 @@ export function createComponent(tag: string, props?: Props): Element {
209
218
  }
210
219
  }
211
220
 
212
- function onMount(parent: Element, element: Element, index?: number) {
213
- element.props.context = parent.props.context;
214
- element.parent = parent;
221
+ /**
222
+ * Checks if all dependencies are ready (not undefined).
223
+ * Handles signals synchronously and promises asynchronously.
224
+ * For reactive signals, sets up subscriptions to mount when all become ready.
225
+ *
226
+ * @param deps - Array of signals, promises, or direct values
227
+ * @returns Promise<boolean> - true if all dependencies are ready
228
+ */
229
+ async function checkDependencies(
230
+ deps: any[]
231
+ ): Promise<boolean> {
232
+ const values = await Promise.all(
233
+ deps.map(async (dep) => {
234
+ if (isSignal(dep)) {
235
+ return dep(); // Read current signal value
236
+ } else if (isPromise(dep)) {
237
+ return await dep; // Await promise resolution
238
+ }
239
+ return dep; // Direct value
240
+ })
241
+ );
242
+ return values.every((v) => v !== undefined);
243
+ }
244
+
245
+ /**
246
+ * Sets up subscriptions to reactive signal dependencies.
247
+ * When all signals become defined, mounts the component.
248
+ */
249
+ function setupDependencySubscriptions(
250
+ parent: Element,
251
+ element: Element,
252
+ deps: any[],
253
+ index?: number
254
+ ) {
255
+ const signalDeps = deps.filter((dep) => isSignal(dep));
256
+ const promiseDeps = deps.filter((dep) => isPromise(dep));
257
+
258
+ if (signalDeps.length === 0) {
259
+ // No reactive signals, nothing to subscribe to
260
+ return;
261
+ }
262
+
263
+ // Create observables from signals
264
+ const signalObservables = signalDeps.map((sig) => sig.observable);
265
+
266
+ // Combine all signal observables
267
+ const subscription = combineLatest(signalObservables).subscribe(
268
+ async () => {
269
+ // Check if all dependencies are now ready
270
+ const allReady = await checkDependencies(deps);
271
+ if (allReady) {
272
+ // Unsubscribe - we only need to mount once
273
+ subscription.unsubscribe();
274
+ // Remove from subscriptions
275
+ const idx = element.propSubscriptions.indexOf(subscription);
276
+ if (idx > -1) {
277
+ element.propSubscriptions.splice(idx, 1);
278
+ }
279
+ // Now mount the component
280
+ performMount(parent, element, index);
281
+ propagateContext(element);
282
+ }
283
+ }
284
+ );
285
+
286
+ // Store subscription for cleanup
287
+ element.propSubscriptions.push(subscription);
288
+ }
289
+
290
+ /**
291
+ * Performs the actual mounting of the component.
292
+ */
293
+ function performMount(parent: Element, element: Element, index?: number) {
215
294
  element.componentInstance.onMount?.(element, index);
216
295
  for (let name in element.directives) {
217
296
  element.directives[name].onMount?.(element);
@@ -219,6 +298,24 @@ export function createComponent(tag: string, props?: Props): Element {
219
298
  element.effectMounts.forEach((fn: any) => {
220
299
  element.effectUnmounts.push(fn(element));
221
300
  });
301
+ }
302
+
303
+ async function onMount(parent: Element, element: Element, index?: number) {
304
+ element.props.context = parent.props.context;
305
+ element.parent = parent;
306
+
307
+ // Check dependencies before mounting
308
+ if (element.props.dependencies && Array.isArray(element.props.dependencies)) {
309
+ const deps = element.props.dependencies;
310
+ const ready = await checkDependencies(deps);
311
+ if (!ready) {
312
+ // Set up subscriptions for reactive signals to trigger mount later
313
+ setupDependencySubscriptions(parent, element, deps, index);
314
+ return;
315
+ }
316
+ }
317
+
318
+ performMount(parent, element, index);
222
319
  };
223
320
 
224
321
  async function propagateContext(element) {
@@ -229,19 +326,19 @@ export function createComponent(tag: string, props?: Props): Element {
229
326
  }
230
327
  else {
231
328
  await new Promise((resolve) => {
232
- let lastElement = null
233
- element.propSubscriptions.push(element.propObservables.attach.observable.subscribe(async (args) => {
234
- const value = args?.value ?? args
235
- if (!value) {
236
- throw new Error(`attach in ${element.tag} is undefined or null, add a component`)
237
- }
238
- if (lastElement) {
239
- destroyElement(lastElement)
240
- }
241
- lastElement = value
242
- await createElement(element, value)
243
- resolve(undefined)
244
- }))
329
+ let lastElement = null
330
+ element.propSubscriptions.push(element.propObservables.attach.observable.subscribe(async (args) => {
331
+ const value = args?.value ?? args
332
+ if (!value) {
333
+ throw new Error(`attach in ${element.tag} is undefined or null, add a component`)
334
+ }
335
+ if (lastElement) {
336
+ destroyElement(lastElement)
337
+ }
338
+ lastElement = value
339
+ await createElement(element, value)
340
+ resolve(undefined)
341
+ }))
245
342
  })
246
343
  }
247
344
  }
@@ -254,39 +351,39 @@ export function createComponent(tag: string, props?: Props): Element {
254
351
  }
255
352
  };
256
353
 
257
- /**
258
- * Creates and mounts a child element to a parent element.
259
- * Handles different types of children: Elements, Promises resolving to Elements, and Observables.
260
- *
261
- * @description This function is designed to handle reactive child components that can be:
262
- * - Direct Element instances
263
- * - Promises that resolve to Elements (for async components)
264
- * - Observables that emit Elements, arrays of Elements, or FlowObservable results
265
- * - Nested observables within arrays or FlowObservable results (handled recursively)
266
- *
267
- * For Observables, it subscribes to the stream and automatically mounts/unmounts elements
268
- * as they are emitted. The function handles nested observables recursively, ensuring that
269
- * observables within arrays or FlowObservable results are also properly subscribed to.
270
- * All subscriptions are stored in the parent's effectSubscriptions for automatic cleanup.
271
- *
272
- * @param {Element} parent - The parent element to mount the child to
273
- * @param {Element | Observable<any> | Promise<Element>} child - The child to create and mount
274
- *
275
- * @example
276
- * ```typescript
277
- * // Direct element
278
- * await createElement(parent, childElement);
279
- *
280
- * // Observable of elements (from cond, loop, etc.)
281
- * await createElement(parent, cond(signal(visible), () => h(Container)));
282
- *
283
- * // Observable that emits arrays containing other observables
284
- * await createElement(parent, observableOfObservables);
285
- *
286
- * // Promise resolving to element
287
- * await createElement(parent, import('./MyComponent').then(mod => h(mod.default)));
288
- * ```
289
- */
354
+ /**
355
+ * Creates and mounts a child element to a parent element.
356
+ * Handles different types of children: Elements, Promises resolving to Elements, and Observables.
357
+ *
358
+ * @description This function is designed to handle reactive child components that can be:
359
+ * - Direct Element instances
360
+ * - Promises that resolve to Elements (for async components)
361
+ * - Observables that emit Elements, arrays of Elements, or FlowObservable results
362
+ * - Nested observables within arrays or FlowObservable results (handled recursively)
363
+ *
364
+ * For Observables, it subscribes to the stream and automatically mounts/unmounts elements
365
+ * as they are emitted. The function handles nested observables recursively, ensuring that
366
+ * observables within arrays or FlowObservable results are also properly subscribed to.
367
+ * All subscriptions are stored in the parent's effectSubscriptions for automatic cleanup.
368
+ *
369
+ * @param {Element} parent - The parent element to mount the child to
370
+ * @param {Element | Observable<any> | Promise<Element>} child - The child to create and mount
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * // Direct element
375
+ * await createElement(parent, childElement);
376
+ *
377
+ * // Observable of elements (from cond, loop, etc.)
378
+ * await createElement(parent, cond(signal(visible), () => h(Container)));
379
+ *
380
+ * // Observable that emits arrays containing other observables
381
+ * await createElement(parent, observableOfObservables);
382
+ *
383
+ * // Promise resolving to element
384
+ * await createElement(parent, import('./MyComponent').then(mod => h(mod.default)));
385
+ * ```
386
+ */
290
387
  async function createElement(parent: Element, child: Element | Observable<any> | Promise<Element>) {
291
388
  if (isPromise(child)) {
292
389
  child = await child;
@@ -305,62 +402,62 @@ export function createComponent(tag: string, props?: Props): Element {
305
402
  elements: Element[];
306
403
  prev?: Element;
307
404
  } = value;
308
-
405
+
309
406
  const components = comp.filter((c) => c !== null);
310
- if (prev) {
311
- components.forEach(async (c) => {
312
- const index = parent.props.children.indexOf(prev.props.key);
313
- if (c instanceof Observable) {
314
- // Handle observable component recursively
315
- await createElement(parent, c);
316
- } else if (isElement(c)) {
317
- onMount(parent, c, index + 1);
318
- propagateContext(c);
319
- }
320
- });
321
- return;
322
- }
323
- components.forEach(async (component) => {
324
- if (!Array.isArray(component)) {
325
- if (component instanceof Observable) {
326
- // Handle observable component recursively
327
- await createElement(parent, component);
328
- } else if (isElement(component)) {
329
- onMount(parent, component);
330
- propagateContext(component);
331
- }
332
- } else {
333
- component.forEach(async (comp) => {
334
- if (comp instanceof Observable) {
335
- // Handle observable component recursively
336
- await createElement(parent, comp);
337
- } else if (isElement(comp)) {
338
- onMount(parent, comp);
339
- propagateContext(comp);
340
- }
341
- });
342
- }
343
- });
407
+ if (prev) {
408
+ components.forEach(async (c) => {
409
+ const index = parent.props.children.indexOf(prev.props.key);
410
+ if (c instanceof Observable) {
411
+ // Handle observable component recursively
412
+ await createElement(parent, c);
413
+ } else if (isElement(c)) {
414
+ onMount(parent, c, index + 1);
415
+ propagateContext(c);
416
+ }
417
+ });
418
+ return;
419
+ }
420
+ components.forEach(async (component) => {
421
+ if (!Array.isArray(component)) {
422
+ if (component instanceof Observable) {
423
+ // Handle observable component recursively
424
+ await createElement(parent, component);
425
+ } else if (isElement(component)) {
426
+ onMount(parent, component);
427
+ propagateContext(component);
428
+ }
429
+ } else {
430
+ component.forEach(async (comp) => {
431
+ if (comp instanceof Observable) {
432
+ // Handle observable component recursively
433
+ await createElement(parent, comp);
434
+ } else if (isElement(comp)) {
435
+ onMount(parent, comp);
436
+ propagateContext(comp);
437
+ }
438
+ });
439
+ }
440
+ });
344
441
  } else if (isElement(value)) {
345
442
  // Handle direct Element emission
346
443
  onMount(parent, value);
347
444
  propagateContext(value);
348
- } else if (Array.isArray(value)) {
349
- // Handle array of elements (which can also be observables)
350
- value.forEach(async (element) => {
351
- if (element instanceof Observable) {
352
- // Handle observable element recursively
353
- await createElement(parent, element);
354
- } else if (isElement(element)) {
355
- onMount(parent, element);
356
- propagateContext(element);
357
- }
358
- });
359
- }
445
+ } else if (Array.isArray(value)) {
446
+ // Handle array of elements (which can also be observables)
447
+ value.forEach(async (element) => {
448
+ if (element instanceof Observable) {
449
+ // Handle observable element recursively
450
+ await createElement(parent, element);
451
+ } else if (isElement(element)) {
452
+ onMount(parent, element);
453
+ propagateContext(element);
454
+ }
455
+ });
456
+ }
360
457
  elementsListen.next(undefined);
361
458
  }
362
459
  );
363
-
460
+
364
461
  // Store subscription for cleanup
365
462
  parent.effectSubscriptions.push(subscription);
366
463
  } else if (isElement(child)) {
@@ -397,170 +494,174 @@ export function loop<T>(
397
494
  let elementMap = new Map<string | number, Element>();
398
495
  let isFirstSubscription = true;
399
496
 
400
- const isArraySignal = (signal: any): signal is WritableArraySignal<T[]> =>
497
+ const isArraySignal = (signal: any): signal is WritableArraySignal<T[]> =>
401
498
  Array.isArray(signal());
402
499
 
403
500
  return new Observable<FlowResult>(subscriber => {
404
501
  const subscription = isArraySignal(itemsSubject)
405
502
  ? itemsSubject.observable.subscribe(change => {
406
- if (isFirstSubscription) {
407
- isFirstSubscription = false;
408
- elements.forEach(el => el.destroy());
409
- elements = [];
410
- elementMap.clear();
411
-
412
- const items = itemsSubject();
413
- if (items) {
414
- items.forEach((item, index) => {
415
- const element = createElementFn(item, index);
416
- if (element) {
417
- elements.push(element);
418
- elementMap.set(index, element);
419
- }
420
- });
421
- }
422
- subscriber.next({
423
- elements: [...elements]
503
+ if (isFirstSubscription) {
504
+ isFirstSubscription = false;
505
+ elements.forEach(el => el.destroy());
506
+ elements = [];
507
+ elementMap.clear();
508
+
509
+ const items = itemsSubject();
510
+ if (items) {
511
+ items.forEach((item, index) => {
512
+ const element = createElementFn(item, index);
513
+ if (element) {
514
+ elements.push(element);
515
+ elementMap.set(index, element);
516
+ }
424
517
  });
425
- return;
426
518
  }
519
+ subscriber.next({
520
+ elements: [...elements]
521
+ });
522
+ return;
523
+ }
427
524
 
428
- if (change.type === 'init' || change.type === 'reset') {
429
- elements.forEach(el => destroyElement(el));
430
- elements = [];
431
- elementMap.clear();
432
-
433
- const items = itemsSubject();
434
- if (items) {
435
- items.forEach((item, index) => {
436
- const element = createElementFn(item, index);
437
- if (element) {
438
- elements.push(element);
439
- elementMap.set(index, element);
440
- }
441
- });
442
- }
443
- } else if (change.type === 'add' && change.index !== undefined) {
444
- const newElements = change.items.map((item, i) => {
445
- const element = createElementFn(item as T, change.index! + i);
525
+ // Handle computed signals that emit array values directly (not ArrayChange objects)
526
+ // When a computed emits, `change` is the array itself, not an object with `type`
527
+ const isDirectArrayChange = Array.isArray(change) || (change && typeof change === 'object' && !('type' in change));
528
+
529
+ if (change.type === 'init' || change.type === 'reset' || isDirectArrayChange) {
530
+ elements.forEach(el => destroyElement(el));
531
+ elements = [];
532
+ elementMap.clear();
533
+
534
+ const items = itemsSubject();
535
+ if (items) {
536
+ items.forEach((item, index) => {
537
+ const element = createElementFn(item, index);
446
538
  if (element) {
447
- elementMap.set(change.index! + i, element);
539
+ elements.push(element);
540
+ elementMap.set(index, element);
448
541
  }
449
- return element;
450
- }).filter((el): el is Element => el !== null);
451
-
452
- elements.splice(change.index, 0, ...newElements);
453
- } else if (change.type === 'remove' && change.index !== undefined) {
454
- const removed = elements.splice(change.index, 1);
455
- removed.forEach(el => {
456
- destroyElement(el)
457
- elementMap.delete(change.index!);
458
542
  });
459
- } else if (change.type === 'update' && change.index !== undefined && change.items.length === 1) {
460
- const index = change.index;
461
- const newItem = change.items[0];
462
-
463
- // Check if the previous item at this index was effectively undefined or non-existent
464
- if (index >= elements.length || elements[index] === undefined || !elementMap.has(index)) {
465
- // Treat as add operation
466
- const newElement = createElementFn(newItem as T, index);
467
- if (newElement) {
468
- elements.splice(index, 0, newElement); // Insert at the correct index
469
- elementMap.set(index, newElement);
470
- // Adjust indices in elementMap for subsequent elements might be needed if map relied on exact indices
471
- // This simple implementation assumes keys are stable or createElementFn handles context correctly
472
- } else {
473
- console.warn(`Element creation returned null for index ${index} during add-like update.`);
474
- }
543
+ }
544
+ } else if (change.type === 'add' && change.index !== undefined) {
545
+ const newElements = change.items.map((item, i) => {
546
+ const element = createElementFn(item as T, change.index! + i);
547
+ if (element) {
548
+ elementMap.set(change.index! + i, element);
549
+ }
550
+ return element;
551
+ }).filter((el): el is Element => el !== null);
552
+
553
+ elements.splice(change.index, 0, ...newElements);
554
+ } else if (change.type === 'remove' && change.index !== undefined) {
555
+ const removed = elements.splice(change.index, 1);
556
+ removed.forEach(el => {
557
+ destroyElement(el)
558
+ elementMap.delete(change.index!);
559
+ });
560
+ } else if (change.type === 'update' && change.index !== undefined && change.items.length === 1) {
561
+ const index = change.index;
562
+ const newItem = change.items[0];
563
+
564
+ // Check if the previous item at this index was effectively undefined or non-existent
565
+ if (index >= elements.length || elements[index] === undefined || !elementMap.has(index)) {
566
+ // Treat as add operation
567
+ const newElement = createElementFn(newItem as T, index);
568
+ if (newElement) {
569
+ elements.splice(index, 0, newElement); // Insert at the correct index
570
+ elementMap.set(index, newElement);
571
+ // Adjust indices in elementMap for subsequent elements might be needed if map relied on exact indices
572
+ // This simple implementation assumes keys are stable or createElementFn handles context correctly
475
573
  } else {
476
- // Treat as a standard update operation
477
- const oldElement = elements[index];
478
- destroyElement(oldElement)
479
- const newElement = createElementFn(newItem as T, index);
480
- if (newElement) {
481
- elements[index] = newElement;
482
- elementMap.set(index, newElement);
483
- } else {
484
- // Handle case where new element creation returns null
485
- elements.splice(index, 1);
486
- elementMap.delete(index);
487
- }
574
+ console.warn(`Element creation returned null for index ${index} during add-like update.`);
575
+ }
576
+ } else {
577
+ // Treat as a standard update operation
578
+ const oldElement = elements[index];
579
+ destroyElement(oldElement)
580
+ const newElement = createElementFn(newItem as T, index);
581
+ if (newElement) {
582
+ elements[index] = newElement;
583
+ elementMap.set(index, newElement);
584
+ } else {
585
+ // Handle case where new element creation returns null
586
+ elements.splice(index, 1);
587
+ elementMap.delete(index);
488
588
  }
489
589
  }
590
+ }
490
591
 
491
- subscriber.next({
492
- elements: [...elements] // Create a new array to ensure change detection
493
- });
494
- })
592
+ subscriber.next({
593
+ elements: [...elements] // Create a new array to ensure change detection
594
+ });
595
+ })
495
596
  : (itemsSubject as WritableObjectSignal<T>).observable.subscribe(change => {
496
- const key = change.key as string | number
497
- if (isFirstSubscription) {
498
- isFirstSubscription = false;
499
- elements.forEach(el => destroyElement(el));
500
- elements = [];
501
- elementMap.clear();
502
-
503
- const items = (itemsSubject as WritableObjectSignal<T>)();
504
- if (items) {
505
- Object.entries(items).forEach(([key, value]) => {
506
- const element = createElementFn(value, key);
507
- if (element) {
508
- elements.push(element);
509
- elementMap.set(key, element);
510
- }
511
- });
512
- }
513
- subscriber.next({
514
- elements: [...elements]
597
+ const key = change.key as string | number
598
+ if (isFirstSubscription) {
599
+ isFirstSubscription = false;
600
+ elements.forEach(el => destroyElement(el));
601
+ elements = [];
602
+ elementMap.clear();
603
+
604
+ const items = (itemsSubject as WritableObjectSignal<T>)();
605
+ if (items) {
606
+ Object.entries(items).forEach(([key, value]) => {
607
+ const element = createElementFn(value, key);
608
+ if (element) {
609
+ elements.push(element);
610
+ elementMap.set(key, element);
611
+ }
515
612
  });
516
- return;
517
613
  }
614
+ subscriber.next({
615
+ elements: [...elements]
616
+ });
617
+ return;
618
+ }
518
619
 
519
- if (change.type === 'init' || change.type === 'reset') {
520
- elements.forEach(el => destroyElement(el));
521
- elements = [];
522
- elementMap.clear();
523
-
524
- const items = (itemsSubject as WritableObjectSignal<T>)();
525
- if (items) {
526
- Object.entries(items).forEach(([key, value]) => {
527
- const element = createElementFn(value, key);
528
- if (element) {
529
- elements.push(element);
530
- elementMap.set(key, element);
531
- }
532
- });
533
- }
534
- } else if (change.type === 'add' && change.key && change.value !== undefined) {
535
- const element = createElementFn(change.value as T, key);
536
- if (element) {
537
- elements.push(element);
538
- elementMap.set(key, element);
539
- }
540
- } else if (change.type === 'remove' && change.key) {
541
- const index = elements.findIndex(el => elementMap.get(key) === el);
542
- if (index !== -1) {
543
- const [removed] = elements.splice(index, 1);
544
- destroyElement(removed)
545
- elementMap.delete(key);
546
- }
547
- } else if (change.type === 'update' && change.key && change.value !== undefined) {
548
- const index = elements.findIndex(el => elementMap.get(key) === el);
549
- if (index !== -1) {
550
- const oldElement = elements[index];
551
- destroyElement(oldElement)
552
- const newElement = createElementFn(change.value as T, key);
553
- if (newElement) {
554
- elements[index] = newElement;
555
- elementMap.set(key, newElement);
620
+ if (change.type === 'init' || change.type === 'reset') {
621
+ elements.forEach(el => destroyElement(el));
622
+ elements = [];
623
+ elementMap.clear();
624
+
625
+ const items = (itemsSubject as WritableObjectSignal<T>)();
626
+ if (items) {
627
+ Object.entries(items).forEach(([key, value]) => {
628
+ const element = createElementFn(value, key);
629
+ if (element) {
630
+ elements.push(element);
631
+ elementMap.set(key, element);
556
632
  }
633
+ });
634
+ }
635
+ } else if (change.type === 'add' && change.key && change.value !== undefined) {
636
+ const element = createElementFn(change.value as T, key);
637
+ if (element) {
638
+ elements.push(element);
639
+ elementMap.set(key, element);
640
+ }
641
+ } else if (change.type === 'remove' && change.key) {
642
+ const index = elements.findIndex(el => elementMap.get(key) === el);
643
+ if (index !== -1) {
644
+ const [removed] = elements.splice(index, 1);
645
+ destroyElement(removed)
646
+ elementMap.delete(key);
647
+ }
648
+ } else if (change.type === 'update' && change.key && change.value !== undefined) {
649
+ const index = elements.findIndex(el => elementMap.get(key) === el);
650
+ if (index !== -1) {
651
+ const oldElement = elements[index];
652
+ destroyElement(oldElement)
653
+ const newElement = createElementFn(change.value as T, key);
654
+ if (newElement) {
655
+ elements[index] = newElement;
656
+ elementMap.set(key, newElement);
557
657
  }
558
658
  }
659
+ }
559
660
 
560
- subscriber.next({
561
- elements: [...elements] // Create a new array to ensure change detection
562
- });
661
+ subscriber.next({
662
+ elements: [...elements] // Create a new array to ensure change detection
563
663
  });
664
+ });
564
665
 
565
666
  return subscription;
566
667
  });
@@ -652,7 +753,7 @@ export function cond(
652
753
  ];
653
754
 
654
755
  // All conditions are now signals, so we always use the reactive path
655
- return new Observable<{elements: Element[], type?: "init" | "remove"}>(subscriber => {
756
+ return new Observable<{ elements: Element[], type?: "init" | "remove" }>(subscriber => {
656
757
  const subscriptions: Subscription[] = [];
657
758
 
658
759
  const evaluateConditions = () => {
@@ -661,7 +762,7 @@ export function cond(
661
762
  for (let i = 0; i < allConditions.length; i++) {
662
763
  const condition = allConditions[i].condition;
663
764
  const conditionValue = condition();
664
-
765
+
665
766
  if (conditionValue) {
666
767
  matchingIndex = i;
667
768
  break;