All files / lib/core/runtime lifecycle.js

91.89% Statements 68/74
71.42% Branches 10/14
100% Functions 3/3
91.89% Lines 68/74

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75403x 403x 403x 403x 403x 403x 403x 403x 403x 403x 403x 403x 403x 403x 403x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x 332x     332x 332x 332x 403x 403x 403x 403x 403x 403x 403x 403x 192x 192x 192x 192x 192x     192x 192x 192x 192x 192x 192x 192x     192x 192x 192x 192x 192x 2x 192x 190x 190x 192x 403x  
import { styleMountManager } from './StyleMountManager.js';
import { profile } from '../utils/profiler.js';
import { logger } from './AvenxLogger.js';
 
/**
 * Manages the lifecycle of Avenx components.
 */
export class LifecycleManager {
  /**
   * Mounts a component to a target element and performs the initial update.
   * Injects runtime styles for the component class if not already present.
   * @param {AvenxComponent} component - The component instance to mount.
   * @param {Element|string} target - The target DOM element or selector.
   */
  mount(component, target) {
    const enableProfiling = !!(component.$app?.enableProfiling || (typeof window !== 'undefined' && window.__avenx_enable_profiling));
    profile(enableProfiling, component.constructor.name, 'mount', () => {
      const targetEl = typeof target === 'string' ? document.querySelector(target) : target;
 
      // Mount runtime styles (deduplicated per component class)
      styleMountManager.mount(component.constructor);
 
      component.__setMountTarget(targetEl);
      if (component.__beforeMount) {
        component.__beforeMount();
      }
      component.update();
      if (component.__afterMount) {
        component.__afterMount();
      }
      if (typeof component.onEnter === 'function') {
        try {
          component.onEnter();
        } catch (err) {
          logger.error('Error in onEnter hook:', err);
        }
      }
    });
  }
 
  /**
   * Unmounts a component and triggers its transition hooks.
   * If onBeforeLeave returns a Promise, unmounting is postponed.
   * @param {AvenxComponent} component - The component instance.
   * @returns {Promise<void>|void}
   */
  unmount(component) {
    let beforeLeaveResult;
    if (typeof component.onBeforeLeave === 'function') {
      try {
        beforeLeaveResult = component.onBeforeLeave();
      } catch (err) {
        logger.error('Error in onBeforeLeave hook:', err);
      }
    }
 
    const doTeardown = () => {
      if (typeof component.onLeave === 'function') {
        try {
          component.onLeave();
        } catch (err) {
          logger.error('Error in onLeave hook:', err);
        }
      }
      component.__performTeardown();
    };
 
    if (beforeLeaveResult instanceof Promise) {
      return beforeLeaveResult.then(doTeardown);
    } else {
      doTeardown();
    }
  }
}