@zeus-js/runtime-dom 0.1.0-beta.7 → 0.1.0-beta.9

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * runtime-dom v0.1.0-beta.7
2
+ * runtime-dom v0.1.0-beta.9
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -211,8 +211,9 @@ var ReactiveEffect = class {
211
211
  this.depsTail = void 0;
212
212
  this.flags = 5;
213
213
  this.next = void 0;
214
- this.cleanup = void 0;
214
+ this.cleanups = void 0;
215
215
  this.scheduler = void 0;
216
+ this.scope = activeEffectScope;
216
217
  if (activeEffectScope) if (activeEffectScope.active) activeEffectScope.effects.push(this);
217
218
  else this.flags &= -2;
218
219
  }
@@ -473,13 +474,20 @@ function resetTracking() {
473
474
  shouldTrack = last === void 0 ? true : last;
474
475
  }
475
476
  function cleanupEffect(e) {
476
- const { cleanup } = e;
477
- e.cleanup = void 0;
478
- if (cleanup) {
477
+ const cleanups = e.cleanups;
478
+ e.cleanups = void 0;
479
+ if (cleanups) {
479
480
  const prevSub = activeSub;
480
481
  activeSub = void 0;
481
482
  try {
482
- cleanup();
483
+ let error;
484
+ for (const cleanup of cleanups) try {
485
+ cleanup();
486
+ } catch (cleanupError) {
487
+ var _error;
488
+ (_error = error) !== null && _error !== void 0 || (error = cleanupError);
489
+ }
490
+ if (error) throw error;
483
491
  } finally {
484
492
  activeSub = prevSub;
485
493
  }
@@ -1364,6 +1372,58 @@ function isPlainObject(value) {
1364
1372
  return proto === Object.prototype || proto === null;
1365
1373
  }
1366
1374
  //#endregion
1375
+ //#region packages/core/runtime-dom/src/domOwnership.ts
1376
+ const activeLightDomHosts = /* @__PURE__ */ new WeakMap();
1377
+ const runtimeOwnedNodes = /* @__PURE__ */ new WeakSet();
1378
+ function registerLightDomHost(host, lightChildren) {
1379
+ const ownership = { lightChildren };
1380
+ activeLightDomHosts.set(host, ownership);
1381
+ return () => {
1382
+ if (activeLightDomHosts.get(host) === ownership) activeLightDomHosts.delete(host);
1383
+ };
1384
+ }
1385
+ function trackRuntimeDomInsertion(parent, node) {
1386
+ const ownership = activeLightDomHosts.get(parent);
1387
+ if (!ownership) return;
1388
+ if (node.nodeType === 11) {
1389
+ for (const child of node.childNodes) trackRuntimeNode(ownership, child);
1390
+ return;
1391
+ }
1392
+ trackRuntimeNode(ownership, node);
1393
+ }
1394
+ function isRuntimeOwnedNode(node) {
1395
+ return runtimeOwnedNodes.has(node);
1396
+ }
1397
+ function trackRuntimeNode(ownership, node) {
1398
+ if (!ownership.lightChildren.includes(node)) runtimeOwnedNodes.add(node);
1399
+ }
1400
+ //#endregion
1401
+ //#region packages/core/runtime-dom/src/range.ts
1402
+ function insertTracked(parent, value, marker = null) {
1403
+ if (value === void 0 || value == null || value === false || value === true) return [];
1404
+ if (Array.isArray(value)) {
1405
+ const nodes = [];
1406
+ for (const item of value) nodes.push(...insertTracked(parent, item, marker));
1407
+ return nodes;
1408
+ }
1409
+ const node = value instanceof Node ? value : document.createTextNode(String(value));
1410
+ trackRuntimeDomInsertion(parent, node);
1411
+ parent.insertBefore(node, marker);
1412
+ return [node];
1413
+ }
1414
+ function removeNodes$1(nodes) {
1415
+ for (const node of nodes) {
1416
+ var _node$parentNode2;
1417
+ (_node$parentNode2 = node.parentNode) === null || _node$parentNode2 === void 0 || _node$parentNode2.removeChild(node);
1418
+ }
1419
+ }
1420
+ function moveRangeBefore(nodes, parent, marker = null) {
1421
+ for (const node of nodes) {
1422
+ trackRuntimeDomInsertion(parent, node);
1423
+ parent.insertBefore(node, marker);
1424
+ }
1425
+ }
1426
+ //#endregion
1367
1427
  //#region packages/core/runtime-dom/src/hostContext.ts
1368
1428
  let currentHostContext;
1369
1429
  function getCurrentHostContext() {
@@ -1388,48 +1448,50 @@ function withCapturedHostContext(fn) {
1388
1448
  });
1389
1449
  }
1390
1450
  //#endregion
1391
- //#region packages/core/runtime-dom/src/range.ts
1392
- var DynamicRange = class {
1393
- constructor(parent, marker) {
1451
+ //#region packages/core/runtime-dom/src/scopedSubtree.ts
1452
+ function captureScopedSubtreeContext() {
1453
+ return {
1454
+ owner: getCurrentOwner(),
1455
+ host: captureCurrentHostContext()
1456
+ };
1457
+ }
1458
+ var ScopedSubtree = class {
1459
+ constructor(parent, marker, context) {
1394
1460
  this.parent = parent;
1395
1461
  this.marker = marker;
1462
+ this.context = context;
1396
1463
  this.nodes = [];
1397
1464
  }
1398
- replace(value) {
1399
- this.clear();
1400
- this.nodes = insertTracked(this.parent, value, this.marker);
1401
- }
1402
- clear() {
1403
- for (const node of this.nodes) {
1404
- var _node$parentNode;
1405
- (_node$parentNode = node.parentNode) === null || _node$parentNode === void 0 || _node$parentNode.removeChild(node);
1465
+ replace(render) {
1466
+ this.dispose();
1467
+ const scope = effectScope(true);
1468
+ let nodes = [];
1469
+ try {
1470
+ scope.run(() => {
1471
+ nodes = runWithOwner(this.context.owner, () => withHostContext(this.context.host, () => insertTracked(this.parent, render(), this.marker)));
1472
+ });
1473
+ } catch (error) {
1474
+ scope.stop();
1475
+ removeNodes$1(nodes);
1476
+ throw error;
1406
1477
  }
1478
+ this.scope = scope;
1479
+ this.nodes = nodes;
1480
+ }
1481
+ dispose() {
1482
+ var _this$scope;
1483
+ (_this$scope = this.scope) === null || _this$scope === void 0 || _this$scope.stop();
1484
+ this.scope = void 0;
1485
+ removeNodes$1(this.nodes);
1407
1486
  this.nodes = [];
1408
1487
  }
1488
+ moveBefore(marker) {
1489
+ moveRangeBefore(this.nodes, this.parent, marker);
1490
+ }
1409
1491
  current() {
1410
1492
  return this.nodes;
1411
1493
  }
1412
1494
  };
1413
- function insertTracked(parent, value, marker = null) {
1414
- if (value === void 0 || value == null || value === false || value === true) return [];
1415
- if (Array.isArray(value)) {
1416
- const nodes = [];
1417
- for (const item of value) nodes.push(...insertTracked(parent, item, marker));
1418
- return nodes;
1419
- }
1420
- const node = value instanceof Node ? value : document.createTextNode(String(value));
1421
- parent.insertBefore(node, marker);
1422
- return [node];
1423
- }
1424
- function removeNodes$1(nodes) {
1425
- for (const node of nodes) {
1426
- var _node$parentNode2;
1427
- (_node$parentNode2 = node.parentNode) === null || _node$parentNode2 === void 0 || _node$parentNode2.removeChild(node);
1428
- }
1429
- }
1430
- function moveRangeBefore(nodes, parent, marker = null) {
1431
- for (const node of nodes) parent.insertBefore(node, marker);
1432
- }
1433
1495
  //#endregion
1434
1496
  //#region packages/core/runtime-dom/src/insert.ts
1435
1497
  function insert(parent, value, marker = null) {
@@ -1440,16 +1502,13 @@ function insert(parent, value, marker = null) {
1440
1502
  insertTracked(parent, value, marker);
1441
1503
  }
1442
1504
  function mountDynamic(parent, marker, value) {
1443
- const range = new DynamicRange(parent, marker);
1444
- const hostContext = captureCurrentHostContext();
1445
- const owner = getCurrentOwner();
1505
+ const subtree = new ScopedSubtree(parent, marker, captureScopedSubtreeContext());
1446
1506
  const runner = effect(() => {
1447
- const next = runWithOwner(owner, () => withHostContext(hostContext, value));
1448
- range.replace(next);
1507
+ subtree.replace(value);
1449
1508
  });
1450
1509
  onScopeDispose(() => {
1451
1510
  stop(runner);
1452
- range.clear();
1511
+ subtree.dispose();
1453
1512
  }, true);
1454
1513
  }
1455
1514
  //#endregion
@@ -1746,11 +1805,11 @@ function bindStyle(el, value) {
1746
1805
  function patchStyle(el, prev, next) {
1747
1806
  const style = el.style;
1748
1807
  if (prev) {
1749
- for (const key in prev) if (!(key in next)) style.setProperty(toKebabCase$1(key), "");
1808
+ for (const key in prev) if (!(key in next)) style.setProperty(toKebabCase$2(key), "");
1750
1809
  }
1751
1810
  for (const key in next) {
1752
1811
  const value = next[key];
1753
- const name = toKebabCase$1(key);
1812
+ const name = toKebabCase$2(key);
1754
1813
  if (value == null) style.setProperty(name, "");
1755
1814
  else style.setProperty(name, normalizeStyleValue(key, value));
1756
1815
  }
@@ -1772,7 +1831,7 @@ const unitlessNumbers = /* @__PURE__ */ new Set([
1772
1831
  function isUnitlessNumber(key) {
1773
1832
  return unitlessNumbers.has(key);
1774
1833
  }
1775
- function toKebabCase$1(value) {
1834
+ function toKebabCase$2(value) {
1776
1835
  return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
1777
1836
  }
1778
1837
  //#endregion
@@ -1881,6 +1940,9 @@ function createComponent(component, props) {
1881
1940
  }
1882
1941
  //#endregion
1883
1942
  //#region packages/core/runtime-dom/src/list.ts
1943
+ function disposeListRecord(record) {
1944
+ record.subtree.dispose();
1945
+ }
1884
1946
  function mountFor$1(parent, marker, each, key, render) {
1885
1947
  if (!key) {
1886
1948
  mountIndexFor(parent, marker, each, render);
@@ -1889,24 +1951,20 @@ function mountFor$1(parent, marker, each, key, render) {
1889
1951
  mountKeyedFor(parent, marker, each, key, render);
1890
1952
  }
1891
1953
  function mountIndexFor(parent, marker, each, render) {
1892
- let current = [];
1893
- const owner = getCurrentOwner();
1954
+ const subtree = new ScopedSubtree(parent, marker, captureScopedSubtreeContext());
1894
1955
  const runner = effect(() => {
1895
1956
  var _each;
1896
- removeNodes$1(current);
1897
- current = [];
1898
1957
  const list = (_each = each()) !== null && _each !== void 0 ? _each : [];
1899
- for (let i = 0; i < list.length; i++) current.push(...insertTracked(parent, runWithOwner(owner, () => render(list[i], i)), marker));
1958
+ subtree.replace(() => list.map((item, index) => render(item, index)));
1900
1959
  });
1901
1960
  onScopeDispose(() => {
1902
1961
  stop(runner);
1903
- removeNodes$1(current);
1904
- current = [];
1962
+ subtree.dispose();
1905
1963
  }, true);
1906
1964
  }
1907
1965
  function mountKeyedFor(parent, marker, each, key, render) {
1908
1966
  let records = [];
1909
- const owner = getCurrentOwner();
1967
+ const subtreeContext = captureScopedSubtreeContext();
1910
1968
  const runner = effect(() => {
1911
1969
  var _each2;
1912
1970
  const nextItems = (_each2 = each()) !== null && _each2 !== void 0 ? _each2 : [];
@@ -1922,19 +1980,23 @@ function mountKeyedFor(parent, marker, each, key, render) {
1922
1980
  oldRecord.item = item;
1923
1981
  oldRecord.index = i;
1924
1982
  nextRecords.push(oldRecord);
1925
- } else nextRecords.push({
1926
- key: itemKey,
1927
- item,
1928
- index: i,
1929
- nodes: insertTracked(parent, runWithOwner(owner, () => render(item, i)), marker)
1930
- });
1983
+ } else {
1984
+ const subtree = new ScopedSubtree(parent, marker, subtreeContext);
1985
+ subtree.replace(() => render(item, i));
1986
+ nextRecords.push({
1987
+ key: itemKey,
1988
+ item,
1989
+ index: i,
1990
+ subtree
1991
+ });
1992
+ }
1931
1993
  }
1932
- for (const record of oldMap.values()) removeNodes$1(record.nodes);
1994
+ for (const record of oldMap.values()) disposeListRecord(record);
1933
1995
  for (let i = nextRecords.length - 1; i >= 0; i--) {
1934
- var _nextRecords$nodes$;
1996
+ var _nextRecords$subtree$;
1935
1997
  const record = nextRecords[i];
1936
- const anchor = i === nextRecords.length - 1 ? marker : (_nextRecords$nodes$ = nextRecords[i + 1].nodes[0]) !== null && _nextRecords$nodes$ !== void 0 ? _nextRecords$nodes$ : marker;
1937
- moveRangeBefore(record.nodes, parent, anchor);
1998
+ const anchor = i === nextRecords.length - 1 ? marker : (_nextRecords$subtree$ = nextRecords[i + 1].subtree.current()[0]) !== null && _nextRecords$subtree$ !== void 0 ? _nextRecords$subtree$ : marker;
1999
+ record.subtree.moveBefore(anchor);
1938
2000
  }
1939
2001
  emitDevtoolsEvent({
1940
2002
  type: "mount-for",
@@ -1944,7 +2006,7 @@ function mountKeyedFor(parent, marker, each, key, render) {
1944
2006
  });
1945
2007
  onScopeDispose(() => {
1946
2008
  stop(runner);
1947
- for (const record of records) removeNodes$1(record.nodes);
2009
+ for (const record of records) disposeListRecord(record);
1948
2010
  records = [];
1949
2011
  }, true);
1950
2012
  }
@@ -1968,6 +2030,254 @@ function mountFor(parent, marker, each, key, render) {
1968
2030
  mountFor$1(parent, marker, each, key, render);
1969
2031
  }
1970
2032
  //#endregion
2033
+ //#region packages/core/runtime-dom/src/customElementContract.ts
2034
+ function getCustomElementAttributeName(prop) {
2035
+ var _prop$attrName;
2036
+ if (prop.attrName === false) return void 0;
2037
+ if (!isAttributeBackedType(prop.type) && !prop.deserialize) return;
2038
+ return normalizeAttributeName((_prop$attrName = prop.attrName) !== null && _prop$attrName !== void 0 ? _prop$attrName : toKebabCase$1(prop.name));
2039
+ }
2040
+ function getCustomElementObservedAttributes(props) {
2041
+ const attributes = /* @__PURE__ */ new Set();
2042
+ for (const prop of props) {
2043
+ const attrName = getCustomElementAttributeName(prop);
2044
+ if (attrName) attributes.add(attrName);
2045
+ }
2046
+ return Array.from(attributes);
2047
+ }
2048
+ function findCustomElementPropByAttribute(props, attrName) {
2049
+ const normalizedName = normalizeAttributeName(attrName);
2050
+ return props.find((prop) => {
2051
+ return getCustomElementAttributeName(prop) === normalizedName;
2052
+ });
2053
+ }
2054
+ function coerceCustomElementAttribute(prop, value) {
2055
+ if (typeof prop.deserialize === "function") return prop.deserialize(value);
2056
+ if (prop.deserialize === true) return value;
2057
+ switch (prop.type) {
2058
+ case "boolean": return value !== null;
2059
+ case "number": return value === null ? void 0 : Number(value);
2060
+ case "string": return value !== null && value !== void 0 ? value : void 0;
2061
+ case "object":
2062
+ case "array": return coerceStructuredAttribute(prop, value);
2063
+ case "function": return;
2064
+ default: return value;
2065
+ }
2066
+ }
2067
+ function reflectCustomElementProperty(element, prop, value, reflectingAttrs) {
2068
+ const attrName = getCustomElementAttributeName(prop);
2069
+ if (!attrName || prop.serialize === true) return;
2070
+ reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.add(attrName);
2071
+ try {
2072
+ const serialized = serializeCustomElementProperty(prop, value);
2073
+ if (serialized == null) element.removeAttribute(attrName);
2074
+ else element.setAttribute(attrName, serialized);
2075
+ } finally {
2076
+ reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.delete(attrName);
2077
+ }
2078
+ }
2079
+ function createCustomElementMountLifecycle(mount) {
2080
+ let mounted;
2081
+ return {
2082
+ connect() {
2083
+ var _mounted;
2084
+ (_mounted = mounted) !== null && _mounted !== void 0 || (mounted = mount());
2085
+ return mounted;
2086
+ },
2087
+ disconnect() {
2088
+ const current = mounted;
2089
+ mounted = void 0;
2090
+ current === null || current === void 0 || current.dispose();
2091
+ },
2092
+ current() {
2093
+ return mounted;
2094
+ }
2095
+ };
2096
+ }
2097
+ function serializeCustomElementProperty(prop, value) {
2098
+ if (typeof prop.serialize === "function") return prop.serialize(value);
2099
+ if (prop.type === "boolean") return value ? "" : null;
2100
+ if (value == null) return null;
2101
+ if (prop.type === "object" || prop.type === "array") return JSON.stringify(value);
2102
+ if (prop.type === "function") return void 0;
2103
+ return String(value);
2104
+ }
2105
+ function coerceStructuredAttribute(prop, value) {
2106
+ if (value === null) return void 0;
2107
+ try {
2108
+ return JSON.parse(value);
2109
+ } catch (_unused) {
2110
+ console.warn(`[Zeus custom-element] Failed to parse JSON attribute "${getCustomElementAttributeName(prop)}".`);
2111
+ return prop.type === "array" ? [] : {};
2112
+ }
2113
+ }
2114
+ function isAttributeBackedType(type) {
2115
+ return type === "string" || type === "number" || type === "boolean";
2116
+ }
2117
+ function normalizeAttributeName(value) {
2118
+ return value.toLowerCase();
2119
+ }
2120
+ function toKebabCase$1(value) {
2121
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
2122
+ }
2123
+ //#endregion
2124
+ //#region packages/core/runtime-dom/src/slot.ts
2125
+ function createSlot(name, fallback) {
2126
+ const context = getCurrentHostContext();
2127
+ if (!context) return createNativeSlot(name, fallback);
2128
+ if (context.mode === "shadow") return createNativeSlot(name, fallback);
2129
+ if (context.projection) return context.projection.createSlot(name, fallback);
2130
+ const assigned = findLightSlotNodes(context.lightChildren, name);
2131
+ if (assigned.length > 0) return Array.from(assigned);
2132
+ return fallback ? fallback() : null;
2133
+ }
2134
+ function createLightDomProjection(host, lightChildren) {
2135
+ const outlets = [];
2136
+ let observer;
2137
+ let unregisterHost;
2138
+ const observe = () => {
2139
+ observer === null || observer === void 0 || observer.observe(host, {
2140
+ attributes: true,
2141
+ attributeFilter: ["slot"],
2142
+ childList: true,
2143
+ subtree: true
2144
+ });
2145
+ for (const node of lightChildren) {
2146
+ if (node.nodeType !== Node.ELEMENT_NODE || host.contains(node)) continue;
2147
+ observer === null || observer === void 0 || observer.observe(node, {
2148
+ attributes: true,
2149
+ attributeFilter: ["slot"]
2150
+ });
2151
+ }
2152
+ };
2153
+ const reconcile = () => {
2154
+ observer === null || observer === void 0 || observer.disconnect();
2155
+ const claimed = /* @__PURE__ */ new Set();
2156
+ for (const outlet of outlets) {
2157
+ const assigned = lightChildren.filter((node) => {
2158
+ if (claimed.has(node) || !matchesLightSlot(node, outlet.name)) return false;
2159
+ claimed.add(node);
2160
+ return true;
2161
+ });
2162
+ replaceOutletNodes(outlet, assigned.length > 0 ? assigned : outlet.fallbackNodes);
2163
+ }
2164
+ for (const node of lightChildren) if (!claimed.has(node) && host.contains(node)) {
2165
+ var _node$parentNode;
2166
+ (_node$parentNode = node.parentNode) === null || _node$parentNode === void 0 || _node$parentNode.removeChild(node);
2167
+ }
2168
+ observer === null || observer === void 0 || observer.takeRecords();
2169
+ observe();
2170
+ };
2171
+ const handleMutations = (records) => {
2172
+ const added = /* @__PURE__ */ new Set();
2173
+ const removed = /* @__PURE__ */ new Set();
2174
+ let changed = false;
2175
+ for (const record of records) {
2176
+ if (record.type === "attributes") {
2177
+ if (lightChildren.includes(record.target)) changed = true;
2178
+ continue;
2179
+ }
2180
+ for (const node of record.removedNodes) if (lightChildren.includes(node)) removed.add(node);
2181
+ if (record.target !== host) continue;
2182
+ const additions = Array.from(record.addedNodes).filter((node) => {
2183
+ return !isRuntimeOwnedNode(node);
2184
+ });
2185
+ if (additions.length === 0) continue;
2186
+ for (const node of additions) added.add(node);
2187
+ insertLightChildren(lightChildren, additions, record);
2188
+ changed = true;
2189
+ }
2190
+ for (const node of removed) {
2191
+ if (added.has(node) || host.contains(node)) continue;
2192
+ const index = lightChildren.indexOf(node);
2193
+ if (index >= 0) {
2194
+ lightChildren.splice(index, 1);
2195
+ changed = true;
2196
+ }
2197
+ }
2198
+ if (changed) reconcile();
2199
+ };
2200
+ return {
2201
+ createSlot(name, fallback) {
2202
+ const fragment = document.createDocumentFragment();
2203
+ const start = document.createComment(name ? `zeus-slot:${name}` : "zeus-slot");
2204
+ const end = document.createComment("/zeus-slot");
2205
+ fragment.append(start, end);
2206
+ const outlet = {
2207
+ name,
2208
+ start,
2209
+ end,
2210
+ fallbackNodes: fallback ? insertTracked(fragment, fallback(), end) : []
2211
+ };
2212
+ outlets.push(outlet);
2213
+ reconcile();
2214
+ return fragment;
2215
+ },
2216
+ connect() {
2217
+ var _host$ownerDocument$d;
2218
+ if (observer) return;
2219
+ const Observer = (_host$ownerDocument$d = host.ownerDocument.defaultView) === null || _host$ownerDocument$d === void 0 ? void 0 : _host$ownerDocument$d.MutationObserver;
2220
+ if (!Observer) return;
2221
+ unregisterHost = registerLightDomHost(host, lightChildren);
2222
+ observer = new Observer(handleMutations);
2223
+ observe();
2224
+ },
2225
+ disconnect() {
2226
+ observer === null || observer === void 0 || observer.disconnect();
2227
+ observer = void 0;
2228
+ unregisterHost === null || unregisterHost === void 0 || unregisterHost();
2229
+ unregisterHost = void 0;
2230
+ }
2231
+ };
2232
+ }
2233
+ function replaceOutletNodes(outlet, nextNodes) {
2234
+ const parent = outlet.end.parentNode;
2235
+ if (!parent || parent !== outlet.start.parentNode) return;
2236
+ let current = outlet.start.nextSibling;
2237
+ while (current && current !== outlet.end) {
2238
+ const next = current.nextSibling;
2239
+ parent.removeChild(current);
2240
+ current = next;
2241
+ }
2242
+ for (const node of nextNodes) parent.insertBefore(node, outlet.end);
2243
+ }
2244
+ function insertLightChildren(lightChildren, additions, record) {
2245
+ for (const node of additions) {
2246
+ const currentIndex = lightChildren.indexOf(node);
2247
+ if (currentIndex >= 0) lightChildren.splice(currentIndex, 1);
2248
+ }
2249
+ let insertionIndex = lightChildren.length;
2250
+ const previousIndex = record.previousSibling ? lightChildren.indexOf(record.previousSibling) : -1;
2251
+ const nextIndex = record.nextSibling ? lightChildren.indexOf(record.nextSibling) : -1;
2252
+ if (previousIndex >= 0) insertionIndex = previousIndex + 1;
2253
+ else if (nextIndex >= 0) insertionIndex = nextIndex;
2254
+ else if (record.previousSibling === null) insertionIndex = 0;
2255
+ lightChildren.splice(insertionIndex, 0, ...additions);
2256
+ }
2257
+ function createNativeSlot(name, fallback) {
2258
+ const slot = document.createElement("slot");
2259
+ if (name) slot.setAttribute("name", name);
2260
+ const fallbackValue = fallback === null || fallback === void 0 ? void 0 : fallback();
2261
+ if (fallbackValue != null) insert(slot, fallbackValue);
2262
+ return slot;
2263
+ }
2264
+ function findLightSlotNodes(nodes, name) {
2265
+ return nodes.filter((node) => matchesLightSlot(node, name));
2266
+ }
2267
+ function matchesLightSlot(node, name) {
2268
+ if (name) {
2269
+ if (node.nodeType !== Node.ELEMENT_NODE) return false;
2270
+ return node.getAttribute("slot") === name;
2271
+ }
2272
+ if (node.nodeType === Node.ELEMENT_NODE) return !node.hasAttribute("slot");
2273
+ return isMeaningfulTextNode(node);
2274
+ }
2275
+ function isMeaningfulTextNode(node) {
2276
+ var _node$textContent;
2277
+ if (node.nodeType !== Node.TEXT_NODE) return false;
2278
+ return Boolean((_node$textContent = node.textContent) === null || _node$textContent === void 0 ? void 0 : _node$textContent.trim());
2279
+ }
2280
+ //#endregion
1971
2281
  //#region packages/core/runtime-dom/src/defineElement.ts
1972
2282
  const ZEUS_ELEMENT_DEFINITION = Symbol.for("zeus.element.definition");
1973
2283
  function prop(input, options = {}) {
@@ -2009,8 +2319,8 @@ function createPropStore(defs) {
2009
2319
  const props = {};
2010
2320
  for (const def of defs) {
2011
2321
  const slot = state();
2012
- slots.set(def.key, slot);
2013
- Object.defineProperty(props, def.key, {
2322
+ slots.set(def.name, slot);
2323
+ Object.defineProperty(props, def.name, {
2014
2324
  configurable: false,
2015
2325
  enumerable: true,
2016
2326
  get() {
@@ -2049,7 +2359,7 @@ function defineElement(tagName, options, setup) {
2049
2359
  setup,
2050
2360
  propDefs
2051
2361
  };
2052
- const observedAttributes = propDefs.filter((def) => def.attr !== false).map((def) => def.attr);
2362
+ const observedAttributes = getCustomElementObservedAttributes(propDefs);
2053
2363
  class ZeusElement extends HTMLElement {
2054
2364
  static get observedAttributes() {
2055
2365
  return observedAttributes;
@@ -2058,7 +2368,8 @@ function defineElement(tagName, options, setup) {
2058
2368
  super();
2059
2369
  this.lightChildren = [];
2060
2370
  this.capturedLightChildren = false;
2061
- this.reflecting = false;
2371
+ this.attributeProps = /* @__PURE__ */ new Set();
2372
+ this.reflectingAttrs = /* @__PURE__ */ new Set();
2062
2373
  this.propStore = createPropStore(propDefs);
2063
2374
  this.props = this.propStore.props;
2064
2375
  applyPropDefaults(this.propStore, propDefs);
@@ -2070,17 +2381,23 @@ function defineElement(tagName, options, setup) {
2070
2381
  emit: createEmitApi(this, options.emits),
2071
2382
  expose: createExpose(this)
2072
2383
  };
2384
+ this.mountLifecycle = createCustomElementMountLifecycle(() => this.mountElement());
2073
2385
  }
2074
2386
  connectedCallback() {
2387
+ this.mountLifecycle.connect();
2388
+ }
2389
+ disconnectedCallback() {
2390
+ this.mountLifecycle.disconnect();
2391
+ }
2392
+ mountElement() {
2075
2393
  var _options$shadow, _options$consumes;
2076
- if (this.dispose) return;
2077
2394
  const shadow = (_options$shadow = options.shadow) !== null && _options$shadow !== void 0 ? _options$shadow : false;
2078
2395
  const mode = shadow ? "shadow" : "light";
2079
2396
  if (mode === "light" && !this.capturedLightChildren) {
2080
2397
  this.lightChildren = Array.from(this.childNodes);
2081
2398
  this.capturedLightChildren = true;
2082
2399
  }
2083
- this.syncAttributesToProps(propDefs);
2400
+ const projection = mode === "light" ? createLightDomProjection(this, this.lightChildren) : void 0;
2084
2401
  const owner = createOwner();
2085
2402
  for (const context of (_options$consumes = options.consumes) !== null && _options$consumes !== void 0 ? _options$consumes : []) {
2086
2403
  const resolved = resolveDOMContext(this, context);
@@ -2091,18 +2408,19 @@ function defineElement(tagName, options, setup) {
2091
2408
  const hostContext = {
2092
2409
  host: this,
2093
2410
  mode,
2094
- lightChildren: this.lightChildren
2411
+ lightChildren: this.lightChildren,
2412
+ projection
2095
2413
  };
2096
- this.dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => {
2414
+ const dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => {
2097
2415
  syncFormValue(this.props, this.setupContext, options.form);
2098
2416
  return setup(this.props, this.setupContext);
2099
2417
  })), target, { owner });
2100
2418
  mountStyles(target, options.styles);
2101
- }
2102
- disconnectedCallback() {
2103
- var _this$dispose;
2104
- (_this$dispose = this.dispose) === null || _this$dispose === void 0 || _this$dispose.call(this);
2105
- this.dispose = void 0;
2419
+ projection === null || projection === void 0 || projection.connect();
2420
+ return { dispose() {
2421
+ projection === null || projection === void 0 || projection.disconnect();
2422
+ dispose();
2423
+ } };
2106
2424
  }
2107
2425
  formAssociatedCallback(form) {
2108
2426
  var _options$form, _options$form$associa;
@@ -2121,10 +2439,11 @@ function defineElement(tagName, options, setup) {
2121
2439
  (_options$form4 = options.form) === null || _options$form4 === void 0 || (_options$form4$stateR = _options$form4.stateRestore) === null || _options$form4$stateR === void 0 || _options$form4$stateR.call(_options$form4, state, mode, this.props, this.setupContext);
2122
2440
  }
2123
2441
  attributeChangedCallback(name, oldValue, newValue) {
2124
- if (oldValue === newValue || this.reflecting) return;
2125
- const def = propDefs.find((item) => item.attr === name);
2442
+ if (oldValue === newValue || this.reflectingAttrs.has(name)) return;
2443
+ const def = propDefs.find((item) => item.attrName === name);
2126
2444
  if (!def) return;
2127
- this.propStore.set(def.key, castAttributeValue(newValue, def));
2445
+ this.attributeProps.add(def.name);
2446
+ this.propStore.set(def.name, coerceCustomElementAttribute(def, newValue));
2128
2447
  }
2129
2448
  resolveRenderTarget(shadow) {
2130
2449
  if (this.target) return this.target;
@@ -2135,24 +2454,11 @@ function defineElement(tagName, options, setup) {
2135
2454
  this.target = this.attachShadow(typeof shadow === "object" ? shadow : { mode: "open" });
2136
2455
  return this.target;
2137
2456
  }
2138
- syncAttributesToProps(defs) {
2139
- for (const def of defs) {
2140
- if (def.attr === false) continue;
2141
- const value = this.getAttribute(def.attr);
2142
- if (value !== null || def.type === Boolean) this.propStore.set(def.key, castAttributeValue(value, def));
2143
- }
2144
- }
2145
2457
  _writePropFromProperty(key, value) {
2146
- const def = propDefs.find((item) => item.key === key);
2458
+ const def = propDefs.find((item) => item.name === key);
2459
+ this.attributeProps.delete(key);
2147
2460
  this.propStore.set(key, value);
2148
- if ((def === null || def === void 0 ? void 0 : def.reflect) && def.attr !== false) {
2149
- this.reflecting = true;
2150
- try {
2151
- reflectPropToAttribute(this, def, value);
2152
- } finally {
2153
- this.reflecting = false;
2154
- }
2155
- }
2461
+ if (def === null || def === void 0 ? void 0 : def.reflect) reflectCustomElementProperty(this, def, value, this.reflectingAttrs);
2156
2462
  }
2157
2463
  }
2158
2464
  ZeusElement.formAssociated = Boolean(options.formAssociated);
@@ -2175,13 +2481,13 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
2175
2481
  applyPropDefaults(propStore, propDefs);
2176
2482
  for (const def of propDefs) {
2177
2483
  var _mountState$attribute;
2178
- if (def.attr !== false && ((_mountState$attribute = mountState.attributeProps) === null || _mountState$attribute === void 0 ? void 0 : _mountState$attribute.has(def.key))) {
2179
- propStore.set(def.key, castAttributeValue(host.getAttribute(def.attr), def));
2180
- initialValues.set(def.key, propStore.get(def.key));
2484
+ if (def.attrName !== false && ((_mountState$attribute = mountState.attributeProps) === null || _mountState$attribute === void 0 ? void 0 : _mountState$attribute.has(def.name))) {
2485
+ propStore.set(def.name, coerceCustomElementAttribute(def, host.getAttribute(def.attrName)));
2486
+ initialValues.set(def.name, propStore.get(def.name));
2181
2487
  continue;
2182
2488
  }
2183
- if (initialValues.has(def.key)) {
2184
- propStore.set(def.key, initialValues.get(def.key));
2489
+ if (initialValues.has(def.name)) {
2490
+ propStore.set(def.name, initialValues.get(def.name));
2185
2491
  continue;
2186
2492
  }
2187
2493
  /**
@@ -2189,11 +2495,11 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
2189
2495
  * back to the lazy host value map so that `element.propName` returns the
2190
2496
  * correct default value rather than undefined.
2191
2497
  */
2192
- initialValues.set(def.key, propStore.get(def.key));
2498
+ initialValues.set(def.name, propStore.get(def.name));
2193
2499
  }
2194
2500
  for (const def of propDefs) {
2195
2501
  var _mountState$attribute2;
2196
- if (def.reflect && def.serialize && !((_mountState$attribute2 = mountState.attributeProps) === null || _mountState$attribute2 === void 0 ? void 0 : _mountState$attribute2.has(def.key))) reflectExternalProp(host, def, propStore.get(def.key), mountState.reflectingAttrs);
2502
+ if (def.reflect && def.serialize && !((_mountState$attribute2 = mountState.attributeProps) === null || _mountState$attribute2 === void 0 ? void 0 : _mountState$attribute2.has(def.name))) reflectCustomElementProperty(host, def, propStore.get(def.name), mountState.reflectingAttrs);
2197
2503
  }
2198
2504
  const shadow = (_options$shadow2 = options.shadow) !== null && _options$shadow2 !== void 0 ? _options$shadow2 : false;
2199
2505
  const mode = shadow ? "shadow" : "light";
@@ -2202,6 +2508,7 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
2202
2508
  mountState.capturedLightChildren = true;
2203
2509
  }
2204
2510
  const lightChildren = (_mountState$lightChil = mountState.lightChildren) !== null && _mountState$lightChil !== void 0 ? _mountState$lightChil : [];
2511
+ const projection = mode === "light" ? createLightDomProjection(host, lightChildren) : void 0;
2205
2512
  const owner = createOwner();
2206
2513
  for (const context of (_options$consumes2 = options.consumes) !== null && _options$consumes2 !== void 0 ? _options$consumes2 : []) {
2207
2514
  const resolved = resolveDOMContext(host, context);
@@ -2212,7 +2519,8 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
2212
2519
  const hostContext = {
2213
2520
  host,
2214
2521
  mode,
2215
- lightChildren
2522
+ lightChildren,
2523
+ projection
2216
2524
  };
2217
2525
  const setupContext = {
2218
2526
  host,
@@ -2226,15 +2534,16 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
2226
2534
  return setup(propStore.props, setupContext);
2227
2535
  })), target, { owner });
2228
2536
  mountStyles(target, options.styles);
2537
+ projection === null || projection === void 0 || projection.connect();
2229
2538
  return {
2230
2539
  propertyChanged(name, _oldValue, newValue) {
2231
2540
  var _mountState$attribute3;
2232
- const def = propDefs.find((item) => item.key === name);
2233
- const fromAttribute = Boolean((def === null || def === void 0 ? void 0 : def.attr) !== false && ((_mountState$attribute3 = mountState.attributeProps) === null || _mountState$attribute3 === void 0 ? void 0 : _mountState$attribute3.has(name)));
2234
- const value = fromAttribute && def ? castAttributeValue(typeof newValue === "string" ? newValue : null, def) : newValue;
2541
+ const def = propDefs.find((item) => item.name === name);
2542
+ const fromAttribute = Boolean((def === null || def === void 0 ? void 0 : def.attrName) !== false && ((_mountState$attribute3 = mountState.attributeProps) === null || _mountState$attribute3 === void 0 ? void 0 : _mountState$attribute3.has(name)));
2543
+ const value = fromAttribute && def ? coerceCustomElementAttribute(def, typeof newValue === "string" ? newValue : null) : newValue;
2235
2544
  propStore.set(name, value);
2236
2545
  initialValues.set(name, value);
2237
- if ((def === null || def === void 0 ? void 0 : def.reflect) && !fromAttribute) reflectExternalProp(host, def, value, mountState.reflectingAttrs);
2546
+ if ((def === null || def === void 0 ? void 0 : def.reflect) && !fromAttribute) reflectCustomElementProperty(host, def, value, mountState.reflectingAttrs);
2238
2547
  },
2239
2548
  formAssociated(form) {
2240
2549
  var _options$form5, _options$form5$associ;
@@ -2253,6 +2562,7 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
2253
2562
  (_options$form8 = options.form) === null || _options$form8 === void 0 || (_options$form8$stateR = _options$form8.stateRestore) === null || _options$form8$stateR === void 0 || _options$form8$stateR.call(_options$form8, state, mode, propStore.props, setupContext);
2254
2563
  },
2255
2564
  dispose() {
2565
+ projection === null || projection === void 0 || projection.disconnect();
2256
2566
  dispose();
2257
2567
  }
2258
2568
  };
@@ -2264,18 +2574,18 @@ function normalizePropDefinitions(props) {
2264
2574
  if (typeof input === "function") {
2265
2575
  const type = input;
2266
2576
  return {
2267
- key: propKey,
2268
- attr: isAttributeBackedConstructor(type) ? toKebabCase(propKey) : false,
2269
- type,
2577
+ name: propKey,
2578
+ attrName: isAttributeBackedConstructor(type) ? toKebabCase(propKey) : false,
2579
+ type: normalizePropType(type),
2270
2580
  reflect: false
2271
2581
  };
2272
2582
  }
2273
2583
  const type = input === null || input === void 0 ? void 0 : input.type;
2274
2584
  const defaultAttr = isAttributeBackedConstructor(type) ? toKebabCase(propKey) : false;
2275
2585
  return {
2276
- key: propKey,
2277
- attr: (input === null || input === void 0 ? void 0 : input.attr) === void 0 ? defaultAttr : input.attr,
2278
- type,
2586
+ name: propKey,
2587
+ attrName: (input === null || input === void 0 ? void 0 : input.attr) === void 0 ? defaultAttr : input.attr,
2588
+ type: normalizePropType(type),
2279
2589
  reflect: Boolean(input === null || input === void 0 ? void 0 : input.reflect),
2280
2590
  default: input === null || input === void 0 ? void 0 : input.default,
2281
2591
  serialize: input === null || input === void 0 ? void 0 : input.serialize,
@@ -2287,12 +2597,12 @@ function applyPropDefaults(store, defs) {
2287
2597
  for (const def of defs) {
2288
2598
  if (!("default" in def)) continue;
2289
2599
  const value = typeof def.default === "function" ? def.default() : def.default;
2290
- store.set(def.key, value);
2600
+ store.set(def.name, value);
2291
2601
  }
2292
2602
  }
2293
2603
  function definePropAccessors(element, store, defs) {
2294
2604
  for (const def of defs) {
2295
- const key = def.key;
2605
+ const key = def.name;
2296
2606
  const hadOwnValue = Object.prototype.hasOwnProperty.call(element, key);
2297
2607
  const ownValue = hadOwnValue ? element[key] : void 0;
2298
2608
  if (hadOwnValue) delete element[key];
@@ -2314,54 +2624,6 @@ function definePropAccessors(element, store, defs) {
2314
2624
  if (hadOwnValue) element._writePropFromProperty(key, ownValue);
2315
2625
  }
2316
2626
  }
2317
- function castAttributeValue(value, def) {
2318
- if (def.deserialize) return def.deserialize(value);
2319
- if (def.type === Boolean) return value !== null;
2320
- if (value === null) return;
2321
- if (def.type === Number) return Number(value);
2322
- if (def.type === Object || def.type === Array) try {
2323
- return JSON.parse(value);
2324
- } catch (_unused) {
2325
- console.warn(`[Zeus custom-element] Failed to parse JSON attribute "${def.attr}".`);
2326
- return def.type === Array ? [] : {};
2327
- }
2328
- if (def.type === Function) return;
2329
- return value;
2330
- }
2331
- function reflectPropToAttribute(element, def, value) {
2332
- if (def.attr === false) return;
2333
- if (def.serialize) {
2334
- const serialized = def.serialize(value);
2335
- if (serialized == null) element.removeAttribute(def.attr);
2336
- else element.setAttribute(def.attr, serialized);
2337
- return;
2338
- }
2339
- if (def.type === Boolean) {
2340
- if (value) element.setAttribute(def.attr, "");
2341
- else element.removeAttribute(def.attr);
2342
- return;
2343
- }
2344
- if (value == null) {
2345
- element.removeAttribute(def.attr);
2346
- return;
2347
- }
2348
- if (def.type === Object || def.type === Array) {
2349
- element.setAttribute(def.attr, JSON.stringify(value));
2350
- return;
2351
- }
2352
- if (def.type === Function) return;
2353
- element.setAttribute(def.attr, String(value));
2354
- }
2355
- function reflectExternalProp(element, def, value, reflectingAttrs) {
2356
- if (def.attr === false) return;
2357
- const attrName = def.attr.toLowerCase();
2358
- reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.add(attrName);
2359
- try {
2360
- reflectPropToAttribute(element, def, value);
2361
- } finally {
2362
- reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.delete(attrName);
2363
- }
2364
- }
2365
2627
  function syncFormValue(props, context, form) {
2366
2628
  const valueResolver = form === null || form === void 0 ? void 0 : form.value;
2367
2629
  const stateResolver = form === null || form === void 0 ? void 0 : form.state;
@@ -2423,6 +2685,15 @@ function createExpose(host) {
2423
2685
  function isAttributeBackedConstructor(type) {
2424
2686
  return type === String || type === Number || type === Boolean;
2425
2687
  }
2688
+ function normalizePropType(type) {
2689
+ if (type === String) return "string";
2690
+ if (type === Number) return "number";
2691
+ if (type === Boolean) return "boolean";
2692
+ if (type === Object) return "object";
2693
+ if (type === Array) return "array";
2694
+ if (type === Function) return "function";
2695
+ return "unknown";
2696
+ }
2426
2697
  function resolveExternalRenderTarget(host, shadow) {
2427
2698
  var _host$shadowRoot;
2428
2699
  if (!shadow) return host;
@@ -2441,38 +2712,6 @@ function toKebabCase(value) {
2441
2712
  return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
2442
2713
  }
2443
2714
  //#endregion
2444
- //#region packages/core/runtime-dom/src/slot.ts
2445
- function createSlot(name, fallback) {
2446
- const context = getCurrentHostContext();
2447
- if (!context) return createNativeSlot(name, fallback);
2448
- if (context.mode === "shadow") return createNativeSlot(name, fallback);
2449
- const assigned = findLightSlotNodes(context.lightChildren, name);
2450
- if (assigned.length > 0) return Array.from(assigned);
2451
- return fallback ? fallback() : null;
2452
- }
2453
- function createNativeSlot(name, fallback) {
2454
- const slot = document.createElement("slot");
2455
- if (name) slot.setAttribute("name", name);
2456
- const fallbackValue = fallback === null || fallback === void 0 ? void 0 : fallback();
2457
- if (fallbackValue != null) insert(slot, fallbackValue);
2458
- return slot;
2459
- }
2460
- function findLightSlotNodes(nodes, name) {
2461
- if (name) return nodes.filter((node) => {
2462
- if (node.nodeType !== Node.ELEMENT_NODE) return false;
2463
- return node.getAttribute("slot") === name;
2464
- });
2465
- return nodes.filter((node) => {
2466
- if (node.nodeType === Node.ELEMENT_NODE) return !node.hasAttribute("slot");
2467
- return isMeaningfulTextNode(node);
2468
- });
2469
- }
2470
- function isMeaningfulTextNode(node) {
2471
- var _node$textContent;
2472
- if (node.nodeType !== Node.TEXT_NODE) return false;
2473
- return Boolean((_node$textContent = node.textContent) === null || _node$textContent === void 0 ? void 0 : _node$textContent.trim());
2474
- }
2475
- //#endregion
2476
2715
  //#region packages/core/runtime-dom/src/webComponents.ts
2477
2716
  const HOST_RESERVED_KEYS = /* @__PURE__ */ new Set([
2478
2717
  "children",
@@ -2564,4 +2803,4 @@ function normalizeHostAttrName(name) {
2564
2803
  }
2565
2804
  }
2566
2805
  //#endregion
2567
- export { For, Host, Show, Slot, ZEUS_CONTEXT_REQUEST, ZEUS_ELEMENT_DEFINITION, bindAttr, bindClass, bindEvent, bindProp, bindRef, bindStyle, bindText, bindTextContent, captureCurrentHostContext, child, createComponent, createContext, createDOMContextBoundary, createOwner, createSlot, defineElement, delegateEvents, event, getCurrentHostContext, getCurrentOwner, getElementDefinition, inject, insert, insertTracked, marker, mountDynamic, mountElementDefinition, mountFor, mountShow, normalizeClass, prop, provide, provideDOMContext, removeNodes, render, resolveDOMContext, resolveValue, runWithOwner, setAttr, setRef, template, useContext, withCapturedHostContext, withHostContext };
2806
+ export { For, Host, Show, Slot, ZEUS_CONTEXT_REQUEST, ZEUS_ELEMENT_DEFINITION, bindAttr, bindClass, bindEvent, bindProp, bindRef, bindStyle, bindText, bindTextContent, captureCurrentHostContext, child, coerceCustomElementAttribute, createComponent, createContext, createCustomElementMountLifecycle, createDOMContextBoundary, createOwner, createSlot, defineElement, delegateEvents, event, findCustomElementPropByAttribute, getCurrentHostContext, getCurrentOwner, getCustomElementAttributeName, getCustomElementObservedAttributes, getElementDefinition, inject, insert, insertTracked, marker, mountDynamic, mountElementDefinition, mountFor, mountShow, normalizeClass, prop, provide, provideDOMContext, reflectCustomElementProperty, removeNodes, render, resolveDOMContext, resolveValue, runWithOwner, setAttr, setRef, template, useContext, withCapturedHostContext, withHostContext };