createDom function

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

Creates a single DOM Node from a resolved Morphic.

FragmentMorphic cannot be passed here directly — fragments produce multiple sibling nodes and have no single root. Use createDomNodes when the caller may encounter a fragment.

The optional componentOwner marks the root element as belonging to a specific Component, registering it with the ComponentRuntime for granular diffing. For child components, ownership is looked up via ComponentRuntime.ownerOf.

Implementation

Node createDom(Morphic node, {Component? componentOwner}) {
  if (node is FragmentMorphic) {
    throw UnsupportedError(
      'createDom cannot create a single node from FragmentMorphic. '
      'Use createDomNodes() instead, or ensure fragments are only used '
      'as children of an ElementMorphic.',
    );
  }

  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) {
        _registerHandler(element, key, attr);
      }
    });

    // ── Children ─────────────────────────────────────────────────────────
    // Each child may be a fragment — use createDomNodes to expand them.
    final morphicChildren = node.children.cast<Morphic>();
    for (final child in morphicChildren) {
      Component? childOwner;
      try {
        childOwner = RenderContext.runtime.ownerOf(child);
      } catch (_) {}

      for (final domNode in createDomNodes(child, componentOwner: childOwner)) {
        element.append(domNode);
      }
    }

    // ── Component node registration ───────────────────────────────────────
    if (componentOwner != null) {
      try {
        RenderContext.runtime.registerComponentDomNode(componentOwner, element);
      } catch (_) {}
    }

    return element;
  }

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