canvasengine 2.0.0-beta.30 → 2.0.0-beta.31

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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { h as a } from "./index-C-iY-lCt.js";
2
- import { A as r, B as n, w as o, C as c, m as l, l as p, D as S, v as m, a5 as u, a4 as g, a2 as b, n as d, G as C, c as j, M as T, N as E, O, P as f, a3 as v, R as w, o as h, p as D, S as P, q as k, r as x, T as y, b as A, V as H, t as M, a1 as V, a0 as B, _ as G, d as N, J as R, H as q, K as U, e as z, W as I, $ as J, f as K, g as L, x as Q, j as W, i as X, y as Y, k as Z, X as _, I as $, Q as F, L as aa, Z as sa, z as ea, s as ta, U as ia, Y as ra, a as na, u as oa } from "./index-C-iY-lCt.js";
1
+ import { h as a } from "./index-DNDNQN-q.js";
2
+ import { A as r, B as n, w as o, C as c, m as l, l as p, D as S, v as m, a5 as u, a4 as g, a2 as b, n as d, G as C, c as j, M as T, N as E, O, P as f, a3 as v, R as w, o as h, p as D, S as P, q as k, r as x, T as y, b as A, V as H, t as M, a1 as V, a0 as B, _ as G, d as N, J as R, H as q, K as U, e as z, W as I, $ as J, f as K, g as L, x as Q, j as W, i as X, y as Y, k as Z, X as _, I as $, Q as F, L as aa, Z as sa, z as ea, s as ta, U as ia, Y as ra, a as na, u as oa } from "./index-DNDNQN-q.js";
3
3
  const e = a.Howler;
4
4
  export {
5
5
  r as ArraySubject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasengine",
3
- "version": "2.0.0-beta.30",
3
+ "version": "2.0.0-beta.31",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -254,44 +254,116 @@ export function createComponent(tag: string, props?: Props): Element {
254
254
  }
255
255
  };
256
256
 
257
- async function createElement(parent: Element, child: Element) {
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
+ */
290
+ async function createElement(parent: Element, child: Element | Observable<any> | Promise<Element>) {
258
291
  if (isPromise(child)) {
259
292
  child = await child;
260
293
  }
261
294
  if (child instanceof Observable) {
262
- child.subscribe(
263
- ({
264
- elements: comp,
265
- prev,
266
- }: {
267
- elements: Element[];
268
- prev?: Element;
269
- }) => {
270
- // if prev, insert element after this
271
- const components = comp.filter((c) => c !== null);
272
- if (prev) {
273
- components.forEach((c) => {
274
- const index = parent.props.children.indexOf(prev.props.key);
275
- onMount(parent, c, index + 1);
276
- propagateContext(c);
277
- });
278
- return;
279
- }
280
- components.forEach((component) => {
281
- if (!Array.isArray(component)) {
282
- onMount(parent, component);
283
- propagateContext(component);
284
- } else {
285
- component.forEach((comp) => {
286
- onMount(parent, comp);
287
- propagateContext(comp);
288
- });
289
- }
290
- });
291
- elementsListen.next(undefined)
295
+ // Subscribe to the observable and handle the emitted values
296
+ const subscription = child.subscribe(
297
+ (value: any) => {
298
+ // Handle different types of observable emissions
299
+ if (value && typeof value === 'object' && 'elements' in value) {
300
+ // Handle FlowObservable result (from loop, cond, etc.)
301
+ const {
302
+ elements: comp,
303
+ prev,
304
+ }: {
305
+ elements: Element[];
306
+ prev?: Element;
307
+ } = value;
308
+
309
+ 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
+ });
344
+ } else if (isElement(value)) {
345
+ // Handle direct Element emission
346
+ onMount(parent, value);
347
+ 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
+ }
360
+ elementsListen.next(undefined);
292
361
  }
293
362
  );
294
- } else {
363
+
364
+ // Store subscription for cleanup
365
+ parent.effectSubscriptions.push(subscription);
366
+ } else if (isElement(child)) {
295
367
  onMount(parent, child);
296
368
  await propagateContext(child);
297
369
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ Observable,
2
3
  Subscription
3
4
  } from "rxjs";
4
5
  import type { Element } from "./reactive";
@@ -124,6 +125,9 @@ export function h<C extends ComponentFunction<any>>(
124
125
  else if ('tag' in componentFunction) {
125
126
  component = componentFunction
126
127
  }
128
+ else if (componentFunction instanceof Observable) {
129
+ component = componentFunction as any
130
+ }
127
131
  else {
128
132
  component = componentFunction({ ...props, children }) as Element;
129
133
  }