createDom function

Node createDom(
  1. Morphic node, {
  2. Component? componentOwner,
})

Creates a real DOM Node from a resolved Morphic tree.

The optional componentOwner identifies which Component this element is the root output of. When provided, the created node is registered with the ComponentRuntime so that requestUpdateFor can diff it directly on future morphs without traversing the full tree.

Pass componentOwner only for the root element of a component's render output — never for nested elements within the same component.

Implementation

Node createDom(Morphic node, {Component? componentOwner}) {
  if (node is TextMorphic) {
    return document.createTextNode(node.value);
  }

  if (node is ElementMorphic) {
    final element = document.createElement(node.tag);

    // ── Attributes ───────────────────────────────────────────────────────
    node.attributes.forEach((key, attr) {
      if (attr is StringAttribute) {
        element.setAttribute(key, attr.value);
      } else if (attr is BooleanAttribute) {
        if (attr.value) element.setAttribute(key, '');
      } else if (attr is ClassAttribute) {
        element.setAttribute('class', attr.classes);
      } else if (attr is StyleAttribute) {
        final htmlElement = element as HTMLElement;
        attr.styles.forEach((k, value) {
          htmlElement.style.setProperty(_toKebabCase(k), value);
        });
      } else if (attr is EventAttribute) {
        // Register via mutable wrapper so patch can update the callback
        // without touching the DOM listener registration.
        _registerHandler(element, key, attr);
      }
    });

    // ── Children ─────────────────────────────────────────────────────────
    final morphicChildren = node.children.cast<Morphic>();
    for (final child in morphicChildren) {
      element.append(createDom(child));
    }

    // ── Component node registration ───────────────────────────────────────
    if (componentOwner != null) {
      try {
        RenderContext.runtime.registerComponentDomNode(componentOwner, element);
      } catch (_) {
        // RenderContext not active in static render paths or tests.
      }
    }

    return element;
  }

  throw UnsupportedError('Unknown node type: ${node.runtimeType}');
}