@zenithbuild/runtime 0.6.17 → 0.7.1

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.
Files changed (2) hide show
  1. package/dist/hydrate.js +194 -18
  2. package/package.json +1 -1
package/dist/hydrate.js CHANGED
@@ -15,6 +15,7 @@ const ALIAS_CONFLICT = Symbol('alias_conflict');
15
15
  const ACTIVE_MARKER_CLASS = 'z-active';
16
16
  const UNRESOLVED_LITERAL = Symbol('unresolved_literal');
17
17
  const LEGACY_MARKUP_HELPER = 'html';
18
+ const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
18
19
  const BOOLEAN_ATTRIBUTES = new Set([
19
20
  'disabled', 'checked', 'selected', 'readonly', 'multiple',
20
21
  'hidden', 'autofocus', 'required', 'open'
@@ -161,8 +162,13 @@ export function hydrate(payload) {
161
162
  }
162
163
  const nodes = _resolveNodes(root, marker.selector, marker.index, marker.kind, marker.source);
163
164
  markerNodesByIndex.set(marker.index, nodes);
164
- const value = _evaluateExpression(expressions[marker.index], stateValues, stateKeys, signalMap, componentBindings, params, ssrData, marker.kind, props, exprFns, marker, null);
165
- _applyMarkerValue(nodes, marker, value);
165
+ try {
166
+ const value = _evaluateExpression(expressions[marker.index], stateValues, stateKeys, signalMap, componentBindings, params, ssrData, marker.kind, props, exprFns, marker, null);
167
+ _applyMarkerValue(nodes, marker, value);
168
+ }
169
+ catch (evalErr) {
170
+ throw evalErr;
171
+ }
166
172
  }
167
173
  for (let i = 0; i < expressions.length; i++) {
168
174
  if (!markerIndices.has(i)) {
@@ -661,7 +667,9 @@ function _resolveComponentProps(propTable, signalMap, context = {}) {
661
667
  return resolved;
662
668
  }
663
669
  function _resolveNodes(root, selector, index, kind, source = undefined) {
664
- const nodes = root.querySelectorAll(selector);
670
+ const nodes = selector.startsWith('comment:')
671
+ ? _resolveCommentNodes(root, selector.slice('comment:'.length))
672
+ : root.querySelectorAll(selector);
665
673
  if (!nodes || nodes.length === 0) {
666
674
  const isRef = kind === 'ref';
667
675
  throwZenithRuntimeError({
@@ -679,6 +687,23 @@ function _resolveNodes(root, selector, index, kind, source = undefined) {
679
687
  }
680
688
  return nodes;
681
689
  }
690
+ function _resolveCommentNodes(root, markerText) {
691
+ const walkerRoot = root && root.nodeType === 9 && root.documentElement ? root.documentElement : root;
692
+ const doc = walkerRoot && walkerRoot.ownerDocument ? walkerRoot.ownerDocument : walkerRoot;
693
+ if (!walkerRoot || !doc || typeof doc.createTreeWalker !== 'function') {
694
+ return [];
695
+ }
696
+ const nodes = [];
697
+ const walker = doc.createTreeWalker(walkerRoot, NodeFilter.SHOW_COMMENT);
698
+ let current = walker.nextNode();
699
+ while (current) {
700
+ if (current.data === markerText) {
701
+ nodes.push(current);
702
+ }
703
+ current = walker.nextNode();
704
+ }
705
+ return nodes;
706
+ }
682
707
  function _resolveExpressionSignalIndices(binding) {
683
708
  if (!binding || typeof binding !== 'object') {
684
709
  return [];
@@ -696,20 +721,25 @@ function _evaluateExpression(binding, stateValues, stateKeys, signalMap, compone
696
721
  const fns = Array.isArray(exprFns) ? exprFns : [];
697
722
  const fn = fns[binding.fn_index];
698
723
  if (typeof fn === 'function') {
699
- return fn({
700
- signalMap,
701
- params,
702
- ssrData,
703
- props: props || {},
704
- componentBindings,
705
- zenhtml: _zenhtml,
706
- fragment(html) {
707
- return {
708
- __zenith_fragment: true,
709
- html: html === null || html === undefined || html === false ? '' : String(html)
710
- };
711
- }
712
- });
724
+ try {
725
+ return fn({
726
+ signalMap,
727
+ params,
728
+ ssrData,
729
+ props: props || {},
730
+ componentBindings,
731
+ zenhtml: _zenhtml,
732
+ fragment(html) {
733
+ return {
734
+ __zenith_fragment: true,
735
+ html: html === null || html === undefined || html === false ? '' : String(html)
736
+ };
737
+ }
738
+ });
739
+ }
740
+ catch (fnErr) {
741
+ throw fnErr;
742
+ }
713
743
  }
714
744
  }
715
745
  if (binding.signal_index !== null && binding.signal_index !== undefined) {
@@ -1438,6 +1468,10 @@ function _applyMarkerValue(nodes, marker, value) {
1438
1468
  try {
1439
1469
  const node = nodes[i];
1440
1470
  if (marker.kind === 'text') {
1471
+ if (node && node.nodeType === 8) {
1472
+ _applyCommentMarkerValue(node, value, `${markerPath}.text`);
1473
+ continue;
1474
+ }
1441
1475
  if (_isStructuralFragment(value)) {
1442
1476
  _mountStructuralFragment(node, value, `${markerPath}.text`);
1443
1477
  continue;
@@ -1474,6 +1508,33 @@ function _applyMarkerValue(nodes, marker, value) {
1474
1508
  }
1475
1509
  }
1476
1510
  }
1511
+ function _applyCommentMarkerValue(anchor, value, rootPath) {
1512
+ if (_isStructuralFragment(value)) {
1513
+ _mountStructuralFragmentIntoCommentRange(anchor, value, rootPath);
1514
+ return;
1515
+ }
1516
+ const end = _clearCommentPlaceholderContent(anchor);
1517
+ const parent = end.parentNode;
1518
+ if (!parent) {
1519
+ return;
1520
+ }
1521
+ const html = _renderFragmentValue(value, rootPath);
1522
+ if (html !== null) {
1523
+ parent.insertBefore(_createContextualFragment(parent, html), end);
1524
+ return;
1525
+ }
1526
+ const textNode = (parent.ownerDocument || document).createTextNode(_coerceText(value, rootPath));
1527
+ parent.insertBefore(textNode, end);
1528
+ }
1529
+ function _createContextualFragment(parent, html) {
1530
+ const doc = parent.ownerDocument || document;
1531
+ if (!doc || typeof doc.createRange !== 'function') {
1532
+ throw new Error('[Zenith Runtime] comment placeholder HTML rendering requires Range#createContextualFragment');
1533
+ }
1534
+ const range = doc.createRange();
1535
+ range.selectNode(parent);
1536
+ return range.createContextualFragment(html);
1537
+ }
1477
1538
  function _isStructuralFragment(value) {
1478
1539
  if (Array.isArray(value)) {
1479
1540
  for (let i = 0; i < value.length; i++) {
@@ -1484,6 +1545,116 @@ function _isStructuralFragment(value) {
1484
1545
  }
1485
1546
  return value && typeof value === 'object' && value.__zenith_fragment === true && typeof value.mount === 'function';
1486
1547
  }
1548
+ function _ensureCommentPlaceholderEnd(anchor) {
1549
+ let end = anchor.__z_range_end || null;
1550
+ if (end && end.parentNode === anchor.parentNode) {
1551
+ return end;
1552
+ }
1553
+ const parent = anchor.parentNode;
1554
+ if (!parent) {
1555
+ return null;
1556
+ }
1557
+ end = (anchor.ownerDocument || document).createComment(`/ ${anchor.data}`);
1558
+ parent.insertBefore(end, anchor.nextSibling);
1559
+ anchor.__z_range_end = end;
1560
+ return end;
1561
+ }
1562
+ function _clearCommentPlaceholderContent(anchor) {
1563
+ if (anchor.__z_unmounts) {
1564
+ for (let i = 0; i < anchor.__z_unmounts.length; i++) {
1565
+ try {
1566
+ anchor.__z_unmounts[i]();
1567
+ }
1568
+ catch (e) { }
1569
+ }
1570
+ }
1571
+ anchor.__z_unmounts = [];
1572
+ const end = _ensureCommentPlaceholderEnd(anchor);
1573
+ if (!end) {
1574
+ return anchor;
1575
+ }
1576
+ let current = anchor.nextSibling;
1577
+ while (current && current !== end) {
1578
+ const next = current.nextSibling;
1579
+ if (current.parentNode) {
1580
+ current.parentNode.removeChild(current);
1581
+ }
1582
+ current = next;
1583
+ }
1584
+ return end;
1585
+ }
1586
+ function _mountStructuralFragmentIntoCommentRange(anchor, value, rootPath = 'renderable') {
1587
+ const end = _clearCommentPlaceholderContent(anchor);
1588
+ const parent = end.parentNode;
1589
+ if (!parent) {
1590
+ return;
1591
+ }
1592
+ const doc = parent.ownerDocument || document;
1593
+ const newUnmounts = [];
1594
+ function insertHtml(html) {
1595
+ const fragment = _createContextualFragment(parent, html);
1596
+ const nodes = Array.from(fragment.childNodes);
1597
+ parent.insertBefore(fragment, end);
1598
+ for (let i = 0; i < nodes.length; i++) {
1599
+ const inserted = nodes[i];
1600
+ newUnmounts.push(() => {
1601
+ if (inserted.parentNode)
1602
+ inserted.parentNode.removeChild(inserted);
1603
+ });
1604
+ }
1605
+ }
1606
+ function mountItem(item, path) {
1607
+ if (Array.isArray(item)) {
1608
+ for (let i = 0; i < item.length; i++)
1609
+ mountItem(item[i], `${path}[${i}]`);
1610
+ return;
1611
+ }
1612
+ if (item && item.__zenith_fragment === true && typeof item.mount === 'function') {
1613
+ const fragment = doc.createDocumentFragment();
1614
+ item.mount(fragment);
1615
+ const nodes = Array.from(fragment.childNodes);
1616
+ parent.insertBefore(fragment, end);
1617
+ for (let i = 0; i < nodes.length; i++) {
1618
+ const inserted = nodes[i];
1619
+ newUnmounts.push(() => {
1620
+ if (inserted.parentNode)
1621
+ inserted.parentNode.removeChild(inserted);
1622
+ });
1623
+ }
1624
+ if (typeof item.unmount === 'function') {
1625
+ newUnmounts.push(item.unmount.bind(item));
1626
+ }
1627
+ return;
1628
+ }
1629
+ if (item && item.__zenith_fragment === true && typeof item.html === 'string') {
1630
+ insertHtml(item.html);
1631
+ return;
1632
+ }
1633
+ const text = _coerceText(item, path);
1634
+ if (text || text === '') {
1635
+ const textNode = doc.createTextNode(text);
1636
+ parent.insertBefore(textNode, end);
1637
+ newUnmounts.push(() => {
1638
+ if (textNode.parentNode)
1639
+ textNode.parentNode.removeChild(textNode);
1640
+ });
1641
+ }
1642
+ }
1643
+ try {
1644
+ mountItem(value, rootPath);
1645
+ }
1646
+ catch (error) {
1647
+ rethrowZenithRuntimeError(error, {
1648
+ phase: 'render',
1649
+ code: 'FRAGMENT_MOUNT_FAILED',
1650
+ message: 'Fragment mount failed',
1651
+ path: rootPath,
1652
+ hint: 'Verify fragment values and nested renderable arrays.',
1653
+ docsLink: DOCS_LINKS.markerTable
1654
+ });
1655
+ }
1656
+ anchor.__z_unmounts = newUnmounts;
1657
+ }
1487
1658
  function _mountStructuralFragment(container, value, rootPath = 'renderable') {
1488
1659
  if (container.__z_unmounts) {
1489
1660
  for (let i = 0; i < container.__z_unmounts.length; i++) {
@@ -1619,7 +1790,12 @@ function _applyAttribute(node, attrName, value) {
1619
1790
  return;
1620
1791
  }
1621
1792
  if (attrName === 'class' || attrName === 'className') {
1622
- node.className = value === null || value === undefined || value === false ? '' : String(value);
1793
+ const classValue = value === null || value === undefined || value === false ? '' : String(value);
1794
+ if (node && node.namespaceURI === SVG_NAMESPACE && typeof node.setAttribute === 'function') {
1795
+ node.setAttribute('class', classValue);
1796
+ return;
1797
+ }
1798
+ node.className = classValue;
1623
1799
  return;
1624
1800
  }
1625
1801
  if (attrName === 'style') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenithbuild/runtime",
3
- "version": "0.6.17",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {