@jxsuite/runtime 4.1.0 → 5.1.0

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.
package/dist/runtime.js CHANGED
@@ -43,7 +43,7 @@ var toHandlerKey = cacheStringFunction((str) => {
43
43
  return s;
44
44
  });
45
45
  var hasChanged = (value, oldValue) => !Object.is(value, oldValue);
46
- var specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;
46
+ var specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,playsinline,readonly`;
47
47
  var isBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected`);
48
48
 
49
49
  // ../../node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js
@@ -805,19 +805,41 @@ var arrayInstrumentations = {
805
805
  };
806
806
  function iterator(self2, method, wrapValue) {
807
807
  const arr = shallowReadArray(self2);
808
- const iter = arr[method]();
808
+ const methodFn = arr[method];
809
+ const iter = methodFn.call(arr);
809
810
  if (arr !== self2 && !isShallow(self2)) {
810
- iter._next = iter.next;
811
- iter.next = () => {
812
- const result = iter._next();
813
- if (!result.done) {
814
- result.value = wrapValue(result.value);
811
+ if (iter[Symbol.toStringTag] === "Array Iterator") {
812
+ const wrapped = Object.create(Object.getPrototypeOf(iter));
813
+ wrapped.next = () => wrapResult(iter.next(), wrapValue);
814
+ if (methodFn !== arrayProto[method]) {
815
+ Object.defineProperties(wrapped, {
816
+ return: {
817
+ get() {
818
+ const fn = iter.return;
819
+ return typeof fn === "function" ? fn.bind(iter) : fn;
820
+ }
821
+ },
822
+ throw: {
823
+ get() {
824
+ const fn = iter.throw;
825
+ return typeof fn === "function" ? fn.bind(iter) : fn;
826
+ }
827
+ }
828
+ });
815
829
  }
816
- return result;
817
- };
830
+ return wrapped;
831
+ }
832
+ iter._next = iter.next;
833
+ iter.next = () => wrapResult(iter._next(), wrapValue);
818
834
  }
819
835
  return iter;
820
836
  }
837
+ function wrapResult(result, wrapValue) {
838
+ if (!result.done) {
839
+ result.value = wrapValue(result.value);
840
+ }
841
+ return result;
842
+ }
821
843
  var arrayProto = Array.prototype;
822
844
  function apply(self2, method, fn, thisArg, wrappedRetFn, args) {
823
845
  const arr = shallowReadArray(self2);
@@ -1192,6 +1214,8 @@ function createInstrumentationGetter(isReadonly2, shallow) {
1192
1214
  return !isReadonly2;
1193
1215
  } else if (key === "__v_isReadonly") {
1194
1216
  return isReadonly2;
1217
+ } else if (key === "__v_isShallow") {
1218
+ return shallow;
1195
1219
  } else if (key === "__v_raw") {
1196
1220
  return target;
1197
1221
  }
@@ -1403,6 +1427,21 @@ function computed(getterOrOptions, debugOptions, isSSR = false) {
1403
1427
  }
1404
1428
 
1405
1429
  // ../schema/src/guards.ts
1430
+ function isString2(value) {
1431
+ return typeof value === "string";
1432
+ }
1433
+ function isNumber(value) {
1434
+ return typeof value === "number";
1435
+ }
1436
+ function isBoolean(value) {
1437
+ return typeof value === "boolean";
1438
+ }
1439
+ function isFunction2(value) {
1440
+ return typeof value === "function";
1441
+ }
1442
+ function isNonNullObject(value) {
1443
+ return typeof value === "object" && value !== null;
1444
+ }
1406
1445
  function isJsonObject(value) {
1407
1446
  return typeof value === "object" && value !== null && !Array.isArray(value);
1408
1447
  }
@@ -1452,14 +1491,17 @@ function isTemplateString(value) {
1452
1491
  function bodyReturnsValue(body) {
1453
1492
  return /\breturn\b[^\S\n]*(?![;}\s]|$)/.test(body);
1454
1493
  }
1494
+ function isNestedStyle(value) {
1495
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1496
+ }
1455
1497
  function paramNames(parameters) {
1456
1498
  if (!parameters) {
1457
1499
  return [];
1458
1500
  }
1459
- return parameters.map((p) => typeof p === "string" ? p : p.name);
1501
+ return parameters.map((p) => isString2(p) ? p : p.name);
1460
1502
  }
1461
1503
  function isTagExpression(tagName) {
1462
- if (!isJsonObject(tagName) || !isJsonObject(tagName.$expression)) {
1504
+ if (typeof tagName !== "object" || tagName === null || Array.isArray(tagName) || !isJsonObject(tagName.$expression)) {
1463
1505
  return false;
1464
1506
  }
1465
1507
  const expression = tagName.$expression;
@@ -1467,7 +1509,7 @@ function isTagExpression(tagName) {
1467
1509
  return typeof expression.value === "string" && typeof expression.initial === "string";
1468
1510
  }
1469
1511
  if (expression.operator === "switch") {
1470
- return isJsonObject(expression.cases) && Object.values(expression.cases).every((tag) => typeof tag === "string") && typeof expression.default === "string";
1512
+ return isJsonObject(expression.cases) && Object.values(expression.cases).every((tag) => isString2(tag)) && typeof expression.default === "string";
1471
1513
  }
1472
1514
  return false;
1473
1515
  }
@@ -1541,7 +1583,10 @@ function splitSelectorList(selector) {
1541
1583
  }
1542
1584
  }
1543
1585
  members.push(selector.slice(start));
1544
- const trimmed = members.map((member) => member.trim()).filter((member) => member !== "");
1586
+ const trimmed = members.flatMap((member) => {
1587
+ const text = member.trim();
1588
+ return text === "" ? [] : [text];
1589
+ });
1545
1590
  return trimmed.length > 0 ? trimmed : [selector];
1546
1591
  }
1547
1592
  function transposeCanvasPopoverSelector(selector) {
@@ -1558,7 +1603,7 @@ function transposeOpenAttribute(selector, options) {
1558
1603
  return out + selector.slice(from);
1559
1604
  }
1560
1605
  let start = at;
1561
- while (start > 0 && !COMPOUND_BREAK.test(selector[start - 1])) {
1606
+ while (start > 0 && !COMPOUND_BREAK.test(selector.charAt(start - 1))) {
1562
1607
  start -= 1;
1563
1608
  }
1564
1609
  const type = LEADING_TYPE.exec(selector.slice(start, at))?.[0]?.toLowerCase();
@@ -1577,8 +1622,8 @@ function transposeCanvasOverlaySelector(selector, options = {}) {
1577
1622
  var COLOR_SCHEME_ATTR = "data-color-scheme";
1578
1623
  var COLOR_SCHEME_STORAGE_KEY = "jx-color-scheme";
1579
1624
  function pureSchemeOf(query) {
1580
- const m = /^\(\s*prefers-color-scheme\s*:\s*(light|dark)\s*\)$/.exec(query.trim());
1581
- return m?.[1] ?? null;
1625
+ const scheme = /^\(\s*prefers-color-scheme\s*:\s*(light|dark)\s*\)$/.exec(query.trim())?.[1];
1626
+ return scheme === "light" || scheme === "dark" ? scheme : null;
1582
1627
  }
1583
1628
  function schemeSelectors(selector, scheme) {
1584
1629
  if (selector === ":root" || selector === "html") {
@@ -1663,7 +1708,7 @@ function buildStyleRules(style, options = {}) {
1663
1708
  if (isRef2(value)) {
1664
1709
  return reactive ? resolveValue?.(property, value, target) ?? null : null;
1665
1710
  }
1666
- if (typeof value === "object") {
1711
+ if (isNonNullObject(value)) {
1667
1712
  return null;
1668
1713
  }
1669
1714
  const raw = String(value);
@@ -1704,15 +1749,18 @@ function buildStyleRules(style, options = {}) {
1704
1749
  resolved = transposed;
1705
1750
  }
1706
1751
  const text = cssRuleText(conditions, resolved, declarations);
1707
- rules.push({
1752
+ const rule = {
1708
1753
  text,
1709
1754
  conditions: [...conditions],
1710
1755
  selector: resolved,
1711
1756
  declarations,
1712
1757
  target,
1713
- key: hashCss(text),
1714
- ...typeof description === "string" && description !== "" ? { description } : {}
1715
- });
1758
+ key: hashCss(text)
1759
+ };
1760
+ if (isString2(description) && description !== "") {
1761
+ rule.description = description;
1762
+ }
1763
+ rules.push(rule);
1716
1764
  };
1717
1765
  const emitKeyframes = (atKey, block, conditions) => {
1718
1766
  const name = atKey.slice("@keyframes".length).trim();
@@ -1859,7 +1907,13 @@ function readPath(root, path) {
1859
1907
  // src/expression.ts
1860
1908
  function scopeMap(state) {
1861
1909
  const map = state.$map;
1862
- return map && typeof map === "object" ? map : undefined;
1910
+ return isNonNullObject(map) ? map : undefined;
1911
+ }
1912
+ function isNodeOperand(operand) {
1913
+ return isNonNullObject(operand) && !Array.isArray(operand) && "operator" in operand;
1914
+ }
1915
+ function isRefOperand(operand) {
1916
+ return isNonNullObject(operand) && !Array.isArray(operand) && "$ref" in operand;
1863
1917
  }
1864
1918
  var MUTATING_OPS = new Set([
1865
1919
  "=",
@@ -1978,34 +2032,57 @@ var BLESSED_GLOBALS = new Set([
1978
2032
  "String/fromCodePoint",
1979
2033
  ...INTL_HELPER_PATHS
1980
2034
  ]);
1981
- var BLESSED_HELPERS = {
1982
- "Intl/compare": (a, b, locale, options) => new Intl.Collator(locale ?? DEFAULT_FORMAT_LOCALE, options).compare(a, b),
1983
- "Intl/displayName": (code, type, locale, options) => new Intl.DisplayNames(locale ?? DEFAULT_FORMAT_LOCALE, {
1984
- ...options,
1985
- type: type ?? "language"
1986
- }).of(code),
1987
- "Intl/formatDate": (value, locale, options) => new Intl.DateTimeFormat(locale ?? DEFAULT_FORMAT_LOCALE, {
1988
- timeZone: DEFAULT_TIME_ZONE,
1989
- ...options
1990
- }).format(new Date(value)),
1991
- "Intl/formatList": (values, locale, options) => new Intl.ListFormat(locale ?? DEFAULT_FORMAT_LOCALE, options).format(values),
1992
- "Intl/formatNumber": (value, locale, options) => new Intl.NumberFormat(locale ?? DEFAULT_FORMAT_LOCALE, options).format(value),
1993
- "Intl/formatRelativeTime": (value, unit, locale, options) => new Intl.RelativeTimeFormat(locale ?? DEFAULT_FORMAT_LOCALE, options).format(value, unit),
1994
- "Intl/plural": (value, locale, options) => new Intl.PluralRules(locale ?? DEFAULT_FORMAT_LOCALE, options).select(value),
1995
- "Intl/segment": (value, granularity, locale) => [
1996
- ...new Intl.Segmenter(locale ?? DEFAULT_FORMAT_LOCALE, {
1997
- granularity: granularity ?? "grapheme"
1998
- }).segment(value)
1999
- ].map((part) => part.segment)
2000
- };
2035
+ var BLESSED_HELPERS = new Map([
2036
+ [
2037
+ "Intl/compare",
2038
+ (a, b, locale, options) => new Intl.Collator(locale ?? DEFAULT_FORMAT_LOCALE, options).compare(a, b)
2039
+ ],
2040
+ [
2041
+ "Intl/displayName",
2042
+ (code, type, locale, options) => new Intl.DisplayNames(locale ?? DEFAULT_FORMAT_LOCALE, {
2043
+ ...options,
2044
+ type: type ?? "language"
2045
+ }).of(code)
2046
+ ],
2047
+ [
2048
+ "Intl/formatDate",
2049
+ (value, locale, options) => new Intl.DateTimeFormat(locale ?? DEFAULT_FORMAT_LOCALE, {
2050
+ timeZone: DEFAULT_TIME_ZONE,
2051
+ ...options
2052
+ }).format(new Date(value))
2053
+ ],
2054
+ [
2055
+ "Intl/formatList",
2056
+ (values, locale, options) => new Intl.ListFormat(locale ?? DEFAULT_FORMAT_LOCALE, options).format(values)
2057
+ ],
2058
+ [
2059
+ "Intl/formatNumber",
2060
+ (value, locale, options) => new Intl.NumberFormat(locale ?? DEFAULT_FORMAT_LOCALE, options).format(value)
2061
+ ],
2062
+ [
2063
+ "Intl/formatRelativeTime",
2064
+ (value, unit, locale, options) => new Intl.RelativeTimeFormat(locale ?? DEFAULT_FORMAT_LOCALE, options).format(value, unit)
2065
+ ],
2066
+ [
2067
+ "Intl/plural",
2068
+ (value, locale, options) => new Intl.PluralRules(locale ?? DEFAULT_FORMAT_LOCALE, options).select(value)
2069
+ ],
2070
+ [
2071
+ "Intl/segment",
2072
+ (value, granularity, locale) => [
2073
+ ...new Intl.Segmenter(locale ?? DEFAULT_FORMAT_LOCALE, {
2074
+ granularity: granularity ?? "grapheme"
2075
+ }).segment(value)
2076
+ ].map((part) => part.segment)
2077
+ ]
2078
+ ]);
2001
2079
  function withPageLocale(path, args, state) {
2002
2080
  const index = INTL_LOCALE_PARAM[path];
2003
2081
  if (index === undefined || index < 0 || args[index] != null) {
2004
2082
  return args;
2005
2083
  }
2006
- const page = state.$page;
2007
- const locale = page?.locale;
2008
- if (typeof locale !== "string" || locale === "") {
2084
+ const locale = readPath(state.$page, "locale");
2085
+ if (!isString2(locale) || locale === "") {
2009
2086
  return args;
2010
2087
  }
2011
2088
  const filled = [...args];
@@ -2038,20 +2115,23 @@ function resolveOperand(operand, state, event, iterCtx, trace) {
2038
2115
  if (operand === null || operand === undefined) {
2039
2116
  return operand;
2040
2117
  }
2041
- if (typeof operand === "object" && !Array.isArray(operand) && "operator" in operand) {
2118
+ if (isNodeOperand(operand)) {
2042
2119
  return evaluateExpression(operand, state, event, iterCtx, trace);
2043
2120
  }
2044
- if (typeof operand === "object" && !Array.isArray(operand) && "$ref" in operand) {
2121
+ if (isRefOperand(operand)) {
2045
2122
  const resolved = resolveExprRef(operand.$ref, state, event, iterCtx);
2046
2123
  trace?.report(trace.path ?? [], resolved);
2047
2124
  return resolved;
2048
2125
  }
2049
2126
  if (Array.isArray(operand)) {
2050
- return operand.map((o, i) => resolveOperand(o, state, event, iterCtx, subTrace(trace, i)));
2127
+ return resolveOperands(operand, state, event, iterCtx, trace);
2051
2128
  }
2052
2129
  trace?.report(trace.path ?? [], operand);
2053
2130
  return operand;
2054
2131
  }
2132
+ function resolveOperands(operands, state, event, iterCtx, trace) {
2133
+ return operands.map((o, i) => resolveOperand(o, state, event, iterCtx, subTrace(trace, i)));
2134
+ }
2055
2135
  function calleeOwner(ref, state, event, iterCtx) {
2056
2136
  const parentRef = (prefix) => {
2057
2137
  const rest = ref.slice(prefix.length);
@@ -2081,11 +2161,11 @@ function resolveExprRef(ref, state, event, iterCtx) {
2081
2161
  if (ref.startsWith("$args/")) {
2082
2162
  const parts = ref.slice("$args/".length).split("/");
2083
2163
  const base = iterCtx?.args?.[parts[0]];
2084
- return parts.length > 1 ? getPath(base, parts.slice(1).join("/")) : base;
2164
+ return parts.length > 1 ? readPath(base, parts.slice(1).join("/")) : base;
2085
2165
  }
2086
2166
  if (ref.startsWith("event#/")) {
2087
2167
  const path = ref.slice("event#/".length);
2088
- return getPath(event, path);
2168
+ return readPath(event, path);
2089
2169
  }
2090
2170
  if (ref.startsWith("$map/")) {
2091
2171
  const parts = ref.split("/");
@@ -2099,7 +2179,7 @@ function resolveExprRef(ref, state, event, iterCtx) {
2099
2179
  } else {
2100
2180
  base = map?.[key] ?? state[`$map/${key}`];
2101
2181
  }
2102
- return parts.length > 2 ? getPath(base, parts.slice(2).join("/")) : base;
2182
+ return parts.length > 2 ? readPath(base, parts.slice(2).join("/")) : base;
2103
2183
  }
2104
2184
  if (ref.startsWith("#/state/")) {
2105
2185
  return readPath(state, ref.slice("#/state/".length));
@@ -2108,10 +2188,10 @@ function resolveExprRef(ref, state, event, iterCtx) {
2108
2188
  return readPath(state, ref.slice("parent#/".length));
2109
2189
  }
2110
2190
  if (ref.startsWith("window#/")) {
2111
- return getPath(globalThis.window, ref.slice("window#/".length));
2191
+ return readPath(globalThis.window, ref.slice("window#/".length));
2112
2192
  }
2113
2193
  if (ref.startsWith("document#/")) {
2114
- return getPath(globalThis.document, ref.slice("document#/".length));
2194
+ return readPath(globalThis.document, ref.slice("document#/".length));
2115
2195
  }
2116
2196
  return readPath(state, ref) ?? null;
2117
2197
  }
@@ -2131,7 +2211,7 @@ function resolveWritableRef(ref, state, _event, iterCtx) {
2131
2211
  if (parts.length > 2) {
2132
2212
  const pathParts = parts.slice(2);
2133
2213
  const lastKey = pathParts.pop();
2134
- const obj = pathParts.length > 0 ? getPath(base, pathParts.join("/")) : base;
2214
+ const obj = pathParts.length > 0 ? readPath(base, pathParts.join("/")) : base;
2135
2215
  return { key: lastKey, obj };
2136
2216
  }
2137
2217
  return {
@@ -2160,6 +2240,37 @@ function evaluateExpression(node, state, event, iterCtx, trace) {
2160
2240
  trace?.report(trace.path ?? [], result);
2161
2241
  return result;
2162
2242
  }
2243
+ function applyCoercingOperator(operator, left, right) {
2244
+ switch (operator) {
2245
+ case "+": {
2246
+ return left + right;
2247
+ }
2248
+ case "-": {
2249
+ return left - right;
2250
+ }
2251
+ case "*": {
2252
+ return left * right;
2253
+ }
2254
+ case "/": {
2255
+ return left / right;
2256
+ }
2257
+ case "%": {
2258
+ return left % right;
2259
+ }
2260
+ case "<": {
2261
+ return left < right;
2262
+ }
2263
+ case "<=": {
2264
+ return left <= right;
2265
+ }
2266
+ case ">": {
2267
+ return left > right;
2268
+ }
2269
+ default: {
2270
+ return left >= right;
2271
+ }
2272
+ }
2273
+ }
2163
2274
  function evaluateNode(node, state, event, iterCtx, trace) {
2164
2275
  const { operator, target, value, initial } = node;
2165
2276
  if (!BLESSED_OPERATORS.has(operator)) {
@@ -2175,8 +2286,8 @@ function evaluateNode(node, state, event, iterCtx, trace) {
2175
2286
  }
2176
2287
  }
2177
2288
  if (operator === "call") {
2178
- const calleeRef = target?.$ref;
2179
- if (typeof calleeRef !== "string") {
2289
+ const calleeRef = isRefOperand(target) ? target.$ref : undefined;
2290
+ if (!isString2(calleeRef)) {
2180
2291
  throw new TypeError("$expression: call target must be a $ref pointer");
2181
2292
  }
2182
2293
  const callDepth = (iterCtx?.callDepth ?? 0) + 1;
@@ -2189,28 +2300,28 @@ function evaluateNode(node, state, event, iterCtx, trace) {
2189
2300
  throw new Error(`$expression: "${calleeRef}" is not a blessed pure global`);
2190
2301
  }
2191
2302
  const globalPath = calleeRef.slice("window#/".length);
2192
- const helper = BLESSED_HELPERS[globalPath];
2303
+ const helper = BLESSED_HELPERS.get(globalPath);
2193
2304
  if (helper) {
2194
2305
  return helper(...withPageLocale(globalPath, argValues, state));
2195
2306
  }
2196
- const fn = getPath(globalThis.window, globalPath);
2307
+ const fn = readPath(globalThis.window, globalPath);
2197
2308
  const lastSlash = globalPath.lastIndexOf("/");
2198
- const thisArg = lastSlash === -1 ? globalThis.window : getPath(globalThis.window, globalPath.slice(0, lastSlash));
2309
+ const thisArg = lastSlash === -1 ? globalThis.window : readPath(globalThis.window, globalPath.slice(0, lastSlash));
2199
2310
  return fn.apply(thisArg, argValues);
2200
2311
  }
2201
2312
  const callee = resolveExprRef(calleeRef, state, event, iterCtx);
2202
- if (typeof callee === "function") {
2313
+ if (isFunction2(callee)) {
2203
2314
  return callee.apply(calleeOwner(calleeRef, state, event, iterCtx), argValues);
2204
2315
  }
2205
- if (callee && typeof callee === "object" && "$expression" in callee) {
2316
+ if (isNonNullObject(callee) && "$expression" in callee) {
2206
2317
  const def = callee;
2207
2318
  const args = {};
2208
2319
  for (const [i, p] of (def.parameters ?? []).entries()) {
2209
- const name = typeof p === "string" ? p : p?.name ?? "";
2320
+ const name = isString2(p) ? p : p?.name ?? "";
2210
2321
  if (!name) {
2211
2322
  continue;
2212
2323
  }
2213
- args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
2324
+ args[name] = argValues[i] === undefined && isNonNullObject(p) && "default" in p ? p.default : argValues[i];
2214
2325
  }
2215
2326
  return evaluateExpression(def.$expression, state, event, { args, callDepth });
2216
2327
  }
@@ -2247,39 +2358,12 @@ function evaluateNode(node, state, event, iterCtx, trace) {
2247
2358
  const left = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
2248
2359
  const right = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
2249
2360
  switch (operator) {
2250
- case "+": {
2251
- return left + right;
2252
- }
2253
- case "-": {
2254
- return left - right;
2255
- }
2256
- case "*": {
2257
- return left * right;
2258
- }
2259
- case "/": {
2260
- return left / right;
2261
- }
2262
- case "%": {
2263
- return left % right;
2264
- }
2265
2361
  case "===": {
2266
2362
  return left === right;
2267
2363
  }
2268
2364
  case "!==": {
2269
2365
  return left !== right;
2270
2366
  }
2271
- case "<": {
2272
- return left < right;
2273
- }
2274
- case "<=": {
2275
- return left <= right;
2276
- }
2277
- case ">": {
2278
- return left > right;
2279
- }
2280
- case ">=": {
2281
- return left >= right;
2282
- }
2283
2367
  case "&&": {
2284
2368
  return left && right;
2285
2369
  }
@@ -2290,42 +2374,14 @@ function evaluateNode(node, state, event, iterCtx, trace) {
2290
2374
  return left ?? right;
2291
2375
  }
2292
2376
  default: {
2293
- break;
2377
+ return applyCoercingOperator(operator, left, right);
2294
2378
  }
2295
2379
  }
2296
2380
  }
2297
2381
  if (ASSIGNMENT_OPS.has(operator)) {
2298
2382
  const rhs = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
2299
2383
  const { obj, key } = resolveWritableRef(target.$ref, state, event, iterCtx);
2300
- switch (operator) {
2301
- case "=": {
2302
- obj[key] = rhs;
2303
- break;
2304
- }
2305
- case "+=": {
2306
- const current = obj[key];
2307
- obj[key] = current + rhs;
2308
- break;
2309
- }
2310
- case "-=": {
2311
- const current = obj[key];
2312
- obj[key] = current - rhs;
2313
- break;
2314
- }
2315
- case "*=": {
2316
- const current = obj[key];
2317
- obj[key] = current * rhs;
2318
- break;
2319
- }
2320
- case "/=": {
2321
- const current = obj[key];
2322
- obj[key] = current / rhs;
2323
- break;
2324
- }
2325
- default: {
2326
- break;
2327
- }
2328
- }
2384
+ obj[key] = operator === "=" ? rhs : applyCoercingOperator(operator.slice(0, -1), obj[key], rhs);
2329
2385
  return;
2330
2386
  }
2331
2387
  if (ARRAY_METHOD_OPS.has(operator)) {
@@ -2354,34 +2410,32 @@ function evaluateNode(node, state, event, iterCtx, trace) {
2354
2410
  }
2355
2411
  if (PURE_METHOD_OPS.has(operator)) {
2356
2412
  const receiver = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
2357
- const args = value === undefined ? [] : Array.isArray(value) ? resolveOperand(value, state, event, iterCtx, subTrace(trace, "value")) : [resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"))];
2358
- const method = receiver?.[operator];
2359
- if (typeof method !== "function") {
2413
+ const args = value === undefined ? [] : Array.isArray(value) ? resolveOperands(value, state, event, iterCtx, subTrace(trace, "value")) : [resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"))];
2414
+ const method = readPath(receiver, operator);
2415
+ if (!isFunction2(method)) {
2360
2416
  return;
2361
2417
  }
2362
2418
  return method.apply(receiver, args);
2363
2419
  }
2364
2420
  if (AGGREGATE_OPS.has(operator)) {
2365
2421
  const arr = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
2422
+ const perItem = value;
2366
2423
  if (operator === "reduce") {
2367
2424
  let acc = resolveOperand(initial, state, event, iterCtx, subTrace(trace, "initial"));
2368
2425
  for (const [index, item] of arr.entries()) {
2369
- acc = evaluateExpression(value, state, event, { acc, index, item }, index === 0 ? subTrace(trace, "value") : undefined);
2426
+ acc = evaluateExpression(perItem, state, event, { acc, index, item }, index === 0 ? subTrace(trace, "value") : undefined);
2370
2427
  }
2371
2428
  return acc;
2372
2429
  }
2373
2430
  if (operator === "map") {
2374
- return arr.map((item, index) => evaluateExpression(value, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
2431
+ return arr.map((item, index) => evaluateExpression(perItem, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
2375
2432
  }
2376
2433
  if (operator === "filter") {
2377
- return arr.filter((item, index) => evaluateExpression(value, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
2434
+ return arr.filter((item, index) => evaluateExpression(perItem, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
2378
2435
  }
2379
2436
  }
2380
2437
  return;
2381
2438
  }
2382
- function getPath(obj, path) {
2383
- return readPath(obj, path);
2384
- }
2385
2439
  function evaluateOperand(operand, state, event, iterCtx) {
2386
2440
  return resolveOperand(operand, state, event, iterCtx);
2387
2441
  }
@@ -2428,37 +2482,41 @@ function formatSrcset(candidates) {
2428
2482
  }
2429
2483
 
2430
2484
  // src/statements.ts
2431
- function statementKind(statement) {
2485
+ function classifyStatement(statement) {
2432
2486
  if ("operator" in statement) {
2433
- return "expression";
2487
+ return { kind: "expression", node: statement };
2434
2488
  }
2435
2489
  if ("if" in statement) {
2436
- return "if";
2490
+ return { kind: "if", node: statement };
2437
2491
  }
2438
2492
  if ("$switch" in statement) {
2439
- return "switch";
2493
+ return { kind: "switch", node: statement };
2440
2494
  }
2441
2495
  if ("stopPropagation" in statement) {
2442
- return "stopPropagation";
2496
+ return { kind: "stopPropagation" };
2443
2497
  }
2444
2498
  if ("preventDefault" in statement) {
2445
- return "preventDefault";
2499
+ return { kind: "preventDefault" };
2446
2500
  }
2447
- return "dispatch";
2501
+ return { kind: "dispatch", node: statement };
2502
+ }
2503
+ function isThenable(value) {
2504
+ return (isNonNullObject(value) || isFunction2(value)) && "then" in value && isFunction2(value.then);
2448
2505
  }
2449
2506
  async function runStatements(statements, state, event, opts = {}) {
2450
2507
  const iterCtx = opts.args ? { args: opts.args } : undefined;
2451
2508
  for (const statement of statements) {
2452
- switch (statementKind(statement)) {
2509
+ const classified = classifyStatement(statement);
2510
+ switch (classified.kind) {
2453
2511
  case "expression": {
2454
- const result = evaluateExpression(statement, state, event, iterCtx);
2455
- if (result && typeof result.then === "function") {
2512
+ const result = evaluateExpression(classified.node, state, event, iterCtx);
2513
+ if (isThenable(result)) {
2456
2514
  await result;
2457
2515
  }
2458
2516
  break;
2459
2517
  }
2460
2518
  case "if": {
2461
- const branch = statement;
2519
+ const branch = classified.node;
2462
2520
  const taken = evaluateOperand(branch.if, state, event, iterCtx) ? branch.then : branch.else;
2463
2521
  if (Array.isArray(taken)) {
2464
2522
  await runStatements(taken, state, event, opts);
@@ -2466,7 +2524,7 @@ async function runStatements(statements, state, event, opts = {}) {
2466
2524
  break;
2467
2525
  }
2468
2526
  case "switch": {
2469
- const branch = statement;
2527
+ const branch = classified.node;
2470
2528
  const key = String(evaluateOperand(branch.$switch, state, event, iterCtx));
2471
2529
  const cases = branch.cases ?? {};
2472
2530
  const taken = Object.hasOwn(cases, key) ? cases[key] : branch.default;
@@ -2476,8 +2534,8 @@ async function runStatements(statements, state, event, opts = {}) {
2476
2534
  break;
2477
2535
  }
2478
2536
  case "dispatch": {
2479
- const dispatch = statement;
2480
- const fallback = typeof opts.target === "function" ? opts.target() : opts.target;
2537
+ const dispatch = classified.node;
2538
+ const fallback = isFunction2(opts.target) ? opts.target() : opts.target;
2481
2539
  const target = event?.currentTarget ?? fallback;
2482
2540
  if (!target) {
2483
2541
  break;
@@ -2553,7 +2611,7 @@ function serializeCookie(name, value, options) {
2553
2611
  var SUPPORTED_SCHEMA_VERSION = 1;
2554
2612
  var _schemaVersionWarned = false;
2555
2613
  function checkSchemaVersion($schema) {
2556
- if (_schemaVersionWarned || typeof $schema !== "string") {
2614
+ if (_schemaVersionWarned || !isString2($schema)) {
2557
2615
  return;
2558
2616
  }
2559
2617
  const match = $schema.match(/\/schema\/v(\d+)\b/);
@@ -2563,19 +2621,28 @@ function checkSchemaVersion($schema) {
2563
2621
  }
2564
2622
  }
2565
2623
  async function Jx(source, target = document.body, options) {
2566
- const base = options?.base ? new URL(options.base, location.href).href : typeof source === "string" ? new URL(source, location.href).href : location.href;
2624
+ const base = options?.base ? new URL(options.base, location.href).href : isString2(source) ? new URL(source, location.href).href : location.href;
2567
2625
  const doc = await resolve(source);
2568
2626
  if (doc.$media) {
2569
2627
  _rootMedia = doc.$media;
2570
2628
  }
2571
- const mounted = await mount(doc, target, {
2572
- base,
2573
- ...options?.onNodeCreated ? { onNodeCreated: options.onNodeCreated } : {},
2574
- ...options?.signal ? { signal: options.signal } : {}
2575
- });
2629
+ const mountOptions = { base };
2630
+ if (options?.onNodeCreated) {
2631
+ mountOptions.onNodeCreated = options.onNodeCreated;
2632
+ }
2633
+ if (options?.signal) {
2634
+ mountOptions.signal = options.signal;
2635
+ }
2636
+ const mounted = await mount(doc, target, mountOptions);
2576
2637
  return mounted.scope;
2577
2638
  }
2639
+ function isScopeHook(value) {
2640
+ return isFunction2(value);
2641
+ }
2578
2642
  var HOST_SCOPE_RESERVED = /^[$#]/;
2643
+ function hostScopeOf(scope) {
2644
+ return scope;
2645
+ }
2579
2646
  function assertHostScope(scope) {
2580
2647
  for (const key of Object.keys(scope)) {
2581
2648
  if (HOST_SCOPE_RESERVED.test(key)) {
@@ -2584,17 +2651,23 @@ function assertHostScope(scope) {
2584
2651
  }
2585
2652
  }
2586
2653
  async function mount(doc, target, options = {}) {
2587
- const hostScope = options.scope ?? {};
2654
+ const hostScope = options.scope ? hostScopeOf(options.scope) : {};
2588
2655
  assertHostScope(hostScope);
2589
2656
  const base = options.base ? new URL(options.base, location.href).href : location.href;
2590
2657
  const ctx = {
2591
2658
  base,
2592
2659
  media: options.media ?? doc.$media ?? null,
2593
- root: null,
2594
- ...options.resolver ? { resolver: options.resolver } : {},
2595
- ...options.skipServerFunctions === undefined ? {} : { skipServerFunctions: options.skipServerFunctions },
2596
- ...options.skipAutoRequests === undefined ? {} : { skipAutoRequests: options.skipAutoRequests }
2660
+ root: null
2597
2661
  };
2662
+ if (options.resolver) {
2663
+ ctx.resolver = options.resolver;
2664
+ }
2665
+ if (options.skipServerFunctions !== undefined) {
2666
+ ctx.skipServerFunctions = options.skipServerFunctions;
2667
+ }
2668
+ if (options.skipAutoRequests !== undefined) {
2669
+ ctx.skipAutoRequests = options.skipAutoRequests;
2670
+ }
2598
2671
  checkSchemaVersion(doc.$schema);
2599
2672
  if (doc.$elements) {
2600
2673
  await registerElements(doc.$elements, base, ctx);
@@ -2611,9 +2684,11 @@ async function mount(doc, target, options = {}) {
2611
2684
  elements.add(el.tagName.toLowerCase());
2612
2685
  }
2613
2686
  options.onNodeCreated?.(el, path, def, state);
2614
- },
2615
- ...options.onNodeMoved ? { onNodeMoved: options.onNodeMoved } : {}
2687
+ }
2616
2688
  };
2689
+ if (options.onNodeMoved) {
2690
+ renderOptions.onNodeMoved = options.onNodeMoved;
2691
+ }
2617
2692
  const { result: root, stop } = runScoped(() => renderNode(doc, scope, renderOptions));
2618
2693
  ctx.root = root;
2619
2694
  let mounted = false;
@@ -2624,11 +2699,11 @@ async function mount(doc, target, options = {}) {
2624
2699
  }
2625
2700
  disposed = true;
2626
2701
  options.signal?.removeEventListener("abort", dispose);
2702
+ root.remove();
2627
2703
  stop();
2628
- if (mounted && typeof scope.onUnmount === "function") {
2704
+ if (mounted && isScopeHook(scope.onUnmount)) {
2629
2705
  scope.onUnmount(scope);
2630
2706
  }
2631
- root.remove();
2632
2707
  };
2633
2708
  if (options.signal?.aborted) {
2634
2709
  dispose();
@@ -2636,7 +2711,7 @@ async function mount(doc, target, options = {}) {
2636
2711
  options.signal?.addEventListener("abort", dispose, { once: true });
2637
2712
  target.append(root);
2638
2713
  mounted = true;
2639
- if (typeof scope.onMount === "function") {
2714
+ if (isScopeHook(scope.onMount)) {
2640
2715
  scope.onMount(scope);
2641
2716
  }
2642
2717
  }
@@ -2650,8 +2725,11 @@ function preloadDocument(url, doc) {
2650
2725
  _resolveCache.set(new URL(url, location.href).href, settled);
2651
2726
  } catch {}
2652
2727
  }
2728
+ function responseContentType(res) {
2729
+ return res.headers?.get("Content-Type") ?? "";
2730
+ }
2653
2731
  async function resolve(source, ctx) {
2654
- if (typeof source !== "string") {
2732
+ if (!isString2(source)) {
2655
2733
  return source;
2656
2734
  }
2657
2735
  const served = ctx?.resolver?.(source);
@@ -2665,7 +2743,7 @@ async function resolve(source, ctx) {
2665
2743
  if (!res.ok) {
2666
2744
  throw new Error(`Jx: failed to fetch ${source} (${res.status})`);
2667
2745
  }
2668
- const contentType = res.headers?.get("Content-Type") ?? "";
2746
+ const contentType = responseContentType(res);
2669
2747
  if (contentType.includes("text/html")) {
2670
2748
  throw new Error(`Jx: ${source} returned HTML, not a document — the host answered a missing file with its ` + `app shell (a single-page fallback), so this path is not served.`);
2671
2749
  }
@@ -2702,7 +2780,6 @@ function setResolveToken(token) {
2702
2780
  function resolveProxyPath(path) {
2703
2781
  return _resolveToken ? `${path}?token=${encodeURIComponent(_resolveToken)}` : path;
2704
2782
  }
2705
- function setSkipContentResolution(_v) {}
2706
2783
  function observeScope(fn) {
2707
2784
  const scope = effectScope(true);
2708
2785
  scope.run(() => {
@@ -2725,19 +2802,19 @@ function setCanvasViewportTranspose(on) {
2725
2802
  _canvasViewportTranspose = on;
2726
2803
  }
2727
2804
  var VIEWPORT_UNIT_RE = /(-?\d*\.?\d+)(?:s|l|d)?v(h|w|min|max|i|b)\b/gi;
2728
- var VIEWPORT_UNIT_MAP = {
2729
- b: "cqb",
2730
- h: "cqh",
2731
- i: "cqi",
2732
- max: "cqmax",
2733
- min: "cqmin",
2734
- w: "cqw"
2735
- };
2805
+ var VIEWPORT_UNIT_MAP = new Map([
2806
+ ["b", "cqb"],
2807
+ ["h", "cqh"],
2808
+ ["i", "cqi"],
2809
+ ["max", "cqmax"],
2810
+ ["min", "cqmin"],
2811
+ ["w", "cqw"]
2812
+ ]);
2736
2813
  function transposeCanvasUnits(value) {
2737
2814
  if (!_canvasViewportTranspose || !value.includes("v")) {
2738
2815
  return value;
2739
2816
  }
2740
- return value.replace(VIEWPORT_UNIT_RE, (_m, num, dim) => `${num}${VIEWPORT_UNIT_MAP[dim.toLowerCase()] ?? `cq${dim}`}`);
2817
+ return value.replace(VIEWPORT_UNIT_RE, (_m, num, dim) => `${num}${VIEWPORT_UNIT_MAP.get(dim.toLowerCase()) ?? `cq${dim}`}`);
2741
2818
  }
2742
2819
  var _canvasDelinkAnchors = false;
2743
2820
  function setCanvasDelinkAnchors(on) {
@@ -2792,15 +2869,14 @@ function canvasAssetValue(tagName, key, value) {
2792
2869
  const name = key.toLowerCase();
2793
2870
  if (SRCSET_KEYS.has(name)) {
2794
2871
  const candidates = parseSrcset(value);
2795
- let changed = false;
2796
2872
  const next = candidates.map((candidate) => {
2797
2873
  const resolved = _canvasAssetResolver?.(candidate.url, name) ?? null;
2798
2874
  if (resolved === null || resolved === candidate.url) {
2799
2875
  return candidate;
2800
2876
  }
2801
- changed = true;
2802
2877
  return { descriptor: candidate.descriptor, url: resolved };
2803
2878
  });
2879
+ const changed = next.some((candidate, index) => candidate !== candidates[index]);
2804
2880
  return changed ? formatSrcset(next) : value;
2805
2881
  }
2806
2882
  if (!isAssetKey(tagName, name)) {
@@ -2831,23 +2907,23 @@ function boundPropKey(key, val, state) {
2831
2907
  return null;
2832
2908
  }
2833
2909
  let sub = null;
2834
- if (isRefObj(val)) {
2910
+ if (isRef2(val)) {
2835
2911
  if (!val.$ref.startsWith("#/state/")) {
2836
2912
  return null;
2837
2913
  }
2838
2914
  const rest = val.$ref.slice("#/state/".length);
2839
2915
  sub = rest && !rest.includes("/") ? rest : null;
2840
- } else if (typeof val === "string") {
2916
+ } else if (isString2(val)) {
2841
2917
  sub = PURE_STATE_TEMPLATE.exec(val)?.[1] ?? null;
2842
2918
  }
2843
2919
  if (!sub) {
2844
2920
  return null;
2845
2921
  }
2846
2922
  const stored = toRaw(state)[sub];
2847
- if (isRef(stored) || typeof stored === "function") {
2923
+ if (isRef(stored) || isFunction2(stored)) {
2848
2924
  return null;
2849
2925
  }
2850
- if (typeof stored === "object" && stored !== null) {
2926
+ if (isNonNullObject(stored)) {
2851
2927
  return null;
2852
2928
  }
2853
2929
  return sub;
@@ -2885,13 +2961,13 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2885
2961
  }
2886
2962
  }
2887
2963
  for (const [key, def] of Object.entries(defs)) {
2888
- if (typeof def === "string") {
2964
+ if (isString2(def)) {
2889
2965
  if (!def.includes("${")) {
2890
2966
  raw[key] = def;
2891
2967
  }
2892
2968
  continue;
2893
2969
  }
2894
- if (typeof def === "number" || typeof def === "boolean" || def === null) {
2970
+ if (isNumber(def) || isBoolean(def) || def === null) {
2895
2971
  raw[key] = def;
2896
2972
  continue;
2897
2973
  }
@@ -2899,7 +2975,7 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2899
2975
  raw[key] = def;
2900
2976
  continue;
2901
2977
  }
2902
- if (typeof def === "object") {
2978
+ if (isNonNullObject(def)) {
2903
2979
  if (def.$prototype) {
2904
2980
  continue;
2905
2981
  }
@@ -2921,8 +2997,8 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2921
2997
  }
2922
2998
  const state = reactive(raw);
2923
2999
  for (const [key, def] of Object.entries(defs)) {
2924
- if (typeof def === "string" && def.includes("${")) {
2925
- state[key] = computed(() => evaluateTemplate(def, state));
3000
+ if (isString2(def) && def.includes("${")) {
3001
+ state[key] = computed(() => evaluateValueTemplate(def, state));
2926
3002
  }
2927
3003
  }
2928
3004
  for (const [key, def] of Object.entries(defs)) {
@@ -2930,17 +3006,7 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2930
3006
  const node = def.$expression;
2931
3007
  if (isNamedFormulaDef(def)) {
2932
3008
  const params = def.parameters;
2933
- state[key] = (...argValues) => {
2934
- const args = {};
2935
- for (const [i, p] of params.entries()) {
2936
- const name = typeof p === "string" ? p : p?.name ?? "";
2937
- if (!name) {
2938
- continue;
2939
- }
2940
- args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
2941
- }
2942
- return evaluateExpression(node, state, null, { args });
2943
- };
3009
+ state[key] = (...argValues) => evaluateExpression(node, state, null, { args: bindPositionalArgs(params, argValues) });
2944
3010
  } else if (isMutating(node.operator)) {
2945
3011
  const handler = (s, event) => evaluateExpression(node, s, event);
2946
3012
  state[key] = handler;
@@ -2954,17 +3020,10 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2954
3020
  const { body } = def;
2955
3021
  if (Array.isArray(def.parameters) && def.parameters.length > 0) {
2956
3022
  const params = def.parameters;
2957
- state[key] = (...argValues) => {
2958
- const args = {};
2959
- for (const [i, p] of params.entries()) {
2960
- const name = typeof p === "string" ? p : p?.name ?? "";
2961
- if (!name) {
2962
- continue;
2963
- }
2964
- args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
2965
- }
2966
- return runStatements(body, state, null, { args, target: dispatchRoot });
2967
- };
3023
+ state[key] = (...argValues) => runStatements(body, state, null, {
3024
+ args: bindPositionalArgs(params, argValues),
3025
+ target: dispatchRoot
3026
+ });
2968
3027
  } else {
2969
3028
  const handler = (s, event) => {
2970
3029
  runStatements(body, s, event ?? null, { target: dispatchRoot });
@@ -2995,6 +3054,17 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2995
3054
  }
2996
3055
  return state;
2997
3056
  }
3057
+ function bindPositionalArgs(parameters, argValues) {
3058
+ const args = {};
3059
+ for (const [i, p] of parameters.entries()) {
3060
+ const name = isString2(p) ? p : p?.name ?? "";
3061
+ if (!name) {
3062
+ continue;
3063
+ }
3064
+ args[name] = argValues[i] === undefined && p !== null && !isString2(p) && "default" in p ? p.default : argValues[i];
3065
+ }
3066
+ return args;
3067
+ }
2998
3068
  function hasSchemaKeywords(obj) {
2999
3069
  for (const k of Object.keys(obj)) {
3000
3070
  if (SCHEMA_KEYWORDS2.has(k)) {
@@ -3003,10 +3073,50 @@ function hasSchemaKeywords(obj) {
3003
3073
  }
3004
3074
  return false;
3005
3075
  }
3076
+ var TEMPLATE_PARAMS = ["state", "$map", "item", "index", "$site", "$page"];
3077
+ function templateArgs(state) {
3078
+ const $map = rowContext(state);
3079
+ return [state, $map, $map?.item, $map?.index, state.$site, state.$page];
3080
+ }
3006
3081
  function evaluateTemplate(str, state) {
3007
- const $map = state?.$map;
3008
- const fn = new Function("state", "$map", "item", "index", `return \`${str}\``);
3009
- return fn(state, $map, $map?.item, $map?.index);
3082
+ let fn = textTemplates.get(str);
3083
+ if (!fn) {
3084
+ fn = new Function(...TEMPLATE_PARAMS, `return \`${str}\``);
3085
+ remember(textTemplates, str, fn);
3086
+ }
3087
+ return fn(...templateArgs(state));
3088
+ }
3089
+ var textTemplates = new Map;
3090
+ var valueTemplates = new Map;
3091
+ var TEMPLATE_CACHE_MAX = 4096;
3092
+ function remember(cache, source, fn) {
3093
+ if (cache.size >= TEMPLATE_CACHE_MAX) {
3094
+ cache.clear();
3095
+ }
3096
+ cache.set(source, fn);
3097
+ }
3098
+ var reportedTemplates = new Set;
3099
+ var _templateErrorHandler = null;
3100
+ function setTemplateErrorHandler(handler) {
3101
+ _templateErrorHandler = handler;
3102
+ }
3103
+ function bindTemplate(source, run, fallback) {
3104
+ effect(() => {
3105
+ try {
3106
+ run();
3107
+ } catch (error) {
3108
+ if (_templateErrorHandler) {
3109
+ _templateErrorHandler(error instanceof Error ? error : new Error(String(error)), source);
3110
+ } else if (!reportedTemplates.has(source)) {
3111
+ reportedTemplates.add(source);
3112
+ console.warn(`jx: template ${JSON.stringify(source)} threw:`, error);
3113
+ }
3114
+ fallback?.();
3115
+ }
3116
+ });
3117
+ }
3118
+ function rowContext(state) {
3119
+ return state.$map;
3010
3120
  }
3011
3121
  function isSingleExpression(str) {
3012
3122
  if (!str.startsWith("${") || !str.endsWith("}")) {
@@ -3026,20 +3136,45 @@ function isSingleExpression(str) {
3026
3136
  }
3027
3137
  return false;
3028
3138
  }
3029
- function evaluateAttrTemplate(str, state) {
3139
+ function evaluateValueTemplate(str, state) {
3030
3140
  if (!isSingleExpression(str)) {
3031
3141
  return evaluateTemplate(str, state);
3032
3142
  }
3033
- const $map = state?.$map;
3034
- const fn = new Function("state", "$map", "item", "index", `return (${str.slice(2, -1)})`);
3035
- return fn(state, $map, $map?.item, $map?.index);
3143
+ let fn = valueTemplates.get(str);
3144
+ if (!fn) {
3145
+ fn = new Function(...TEMPLATE_PARAMS, `return (${str.slice(2, -1)})`);
3146
+ remember(valueTemplates, str, fn);
3147
+ }
3148
+ return fn(...templateArgs(state));
3149
+ }
3150
+ var _npmModuleResolver = null;
3151
+ function setNpmModuleResolver(resolver) {
3152
+ _npmModuleResolver = resolver;
3153
+ }
3154
+ var NPM_SCHEME = "npm:";
3155
+ async function importSource(src, base) {
3156
+ if (src.startsWith(NPM_SCHEME)) {
3157
+ const specifier = src.slice(NPM_SCHEME.length);
3158
+ return importModule(_npmModuleResolver?.(specifier) ?? specifier);
3159
+ }
3160
+ if (base) {
3161
+ try {
3162
+ return await importModule(new URL(src, base).href);
3163
+ } catch {
3164
+ return importModule(src);
3165
+ }
3166
+ }
3167
+ return importModule(src);
3168
+ }
3169
+ function importModule(specifier) {
3170
+ return import(specifier);
3036
3171
  }
3037
3172
  var _moduleCache = new Map;
3038
3173
  var _moduleLoaders = new Map;
3039
3174
  var _hostSeeded = new Set;
3040
3175
  function preloadModule(specifier, mod) {
3041
3176
  _hostSeeded.add(specifier);
3042
- if (typeof mod === "function") {
3177
+ if (isFunction2(mod)) {
3043
3178
  _moduleCache.delete(specifier);
3044
3179
  _moduleLoaders.set(specifier, mod);
3045
3180
  return;
@@ -3056,17 +3191,21 @@ function seededModule(src) {
3056
3191
  if (!pending) {
3057
3192
  return;
3058
3193
  }
3059
- if (typeof pending !== "function") {
3194
+ if (!isFunction2(pending)) {
3060
3195
  return pending;
3061
3196
  }
3062
- const load = Promise.resolve(pending()).then((mod) => {
3063
- _moduleCache.set(src, mod);
3064
- _moduleLoaders.delete(src);
3065
- return mod;
3066
- }, (error) => {
3067
- _moduleLoaders.set(src, pending);
3068
- throw error;
3069
- });
3197
+ const started = pending();
3198
+ const load = (async () => {
3199
+ try {
3200
+ const mod = await started;
3201
+ _moduleCache.set(src, mod);
3202
+ _moduleLoaders.delete(src);
3203
+ return mod;
3204
+ } catch (error) {
3205
+ _moduleLoaders.set(src, pending);
3206
+ throw error;
3207
+ }
3208
+ })();
3070
3209
  _moduleLoaders.set(src, load);
3071
3210
  return load;
3072
3211
  }
@@ -3084,7 +3223,7 @@ async function resolveFunction(def, state, key, base) {
3084
3223
  return noop;
3085
3224
  }
3086
3225
  let fn;
3087
- if (typeof def.body === "string") {
3226
+ if (isString2(def.body)) {
3088
3227
  const params = resolveParamNames(def);
3089
3228
  fn = new Function(...params, def.body);
3090
3229
  Object.defineProperty(fn, "name", {
@@ -3104,20 +3243,11 @@ async function resolveFunction(def, state, key, base) {
3104
3243
  } else if (seeded) {
3105
3244
  mod = seeded;
3106
3245
  } else {
3107
- if (base) {
3108
- const resolvedSrc = new URL(src, base).href;
3109
- try {
3110
- mod = await import(resolvedSrc);
3111
- } catch {
3112
- mod = await import(src);
3113
- }
3114
- } else {
3115
- mod = await import(src);
3116
- }
3246
+ mod = await importSource(src, base);
3117
3247
  _moduleCache.set(src, mod);
3118
3248
  }
3119
3249
  const candidate = mod[exportName] ?? mod.default?.[exportName];
3120
- if (typeof candidate !== "function") {
3250
+ if (!isFunction2(candidate)) {
3121
3251
  throw new TypeError(`Jx: export "${exportName}" not found or not a function in "${src}"`);
3122
3252
  }
3123
3253
  fn = candidate;
@@ -3125,11 +3255,7 @@ async function resolveFunction(def, state, key, base) {
3125
3255
  const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;
3126
3256
  let isComputed = false;
3127
3257
  if (!hasParams) {
3128
- if (typeof def.body === "string") {
3129
- isComputed = bodyReturnsValue(def.body);
3130
- } else if (fn) {
3131
- isComputed = fn.length <= 1 && bodyReturnsValue(fn.toString());
3132
- }
3258
+ isComputed = isString2(def.body) ? bodyReturnsValue(def.body) : fn.length <= 1 && bodyReturnsValue(fn.toString());
3133
3259
  }
3134
3260
  if (isComputed) {
3135
3261
  return computed(() => fn(state));
@@ -3174,6 +3300,22 @@ var RESERVED_KEYS = new Set([
3174
3300
  "cases",
3175
3301
  "observedAttributes"
3176
3302
  ]);
3303
+ function inheritScope(parent) {
3304
+ return Object.create(parent);
3305
+ }
3306
+ function scopeMedia(state) {
3307
+ return state["$media"] ?? {};
3308
+ }
3309
+ function elementProperties(el) {
3310
+ return el;
3311
+ }
3312
+ function instanceStateOf(el) {
3313
+ const state = elementProperties(el)._state;
3314
+ return isNonNullObject(state) ? state : null;
3315
+ }
3316
+ function isEventHandler(value) {
3317
+ return isFunction2(value);
3318
+ }
3177
3319
  var warnedRefChildren = new Set;
3178
3320
  var SVG_NS = "http://www.w3.org/2000/svg";
3179
3321
  var MATHML_NS = "http://www.w3.org/1998/Math/MathML";
@@ -3188,11 +3330,13 @@ function elementNamespace(tagName, inherited) {
3188
3330
  }
3189
3331
  function renderNode(def, state, options) {
3190
3332
  const path = options?._path ?? [];
3191
- if (typeof def === "string" || typeof def === "number" || typeof def === "boolean") {
3333
+ if (isString2(def) || isNumber(def) || isBoolean(def)) {
3192
3334
  const textNode = document.createTextNode(String(def));
3193
- if (typeof def === "string" && isTemplateString(def)) {
3194
- effect(() => {
3335
+ if (isTemplateString(def)) {
3336
+ bindTemplate(def, () => {
3195
3337
  textNode.textContent = evaluateTemplate(def, state);
3338
+ }, () => {
3339
+ textNode.textContent = "";
3196
3340
  });
3197
3341
  }
3198
3342
  return textNode;
@@ -3201,9 +3345,9 @@ function renderNode(def, state, options) {
3201
3345
  for (const [key, val] of Object.entries(def)) {
3202
3346
  if (key.startsWith("$") && !RESERVED_KEYS.has(key)) {
3203
3347
  if (localState === state) {
3204
- localState = Object.create(state);
3348
+ localState = inheritScope(state);
3205
3349
  }
3206
- localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;
3350
+ localState[key] = isRef2(val) ? resolveRef(val.$ref, state) : val;
3207
3351
  }
3208
3352
  }
3209
3353
  if ("$ref" in def && !def.tagName) {
@@ -3238,7 +3382,7 @@ function renderNode(def, state, options) {
3238
3382
  if (def.style && tagName.includes("-")) {
3239
3383
  callSiteStyles.set(el, def.style);
3240
3384
  }
3241
- applyStyle(el, def.style ?? {}, localState["$media"] ?? {}, localState);
3385
+ applyStyle(el, def.style ?? {}, scopeMedia(localState), localState);
3242
3386
  applyAttributes(el, def.attributes ?? {}, localState);
3243
3387
  const kids = def.children;
3244
3388
  if (isMappedArray(kids)) {
@@ -3274,11 +3418,10 @@ function applyProperties(el, def, state) {
3274
3418
  function bindHandler(el, key, val, state) {
3275
3419
  const type = key.slice(2);
3276
3420
  const scope = state;
3277
- if (isRefObj(val)) {
3421
+ if (isRef2(val)) {
3278
3422
  const handler = resolveRef(val.$ref, state);
3279
- if (typeof handler === "function") {
3280
- const handlerFn = handler;
3281
- el.addEventListener(type, (e) => handlerFn(scope, e));
3423
+ if (isEventHandler(handler)) {
3424
+ el.addEventListener(type, (e) => handler(scope, e));
3282
3425
  }
3283
3426
  return true;
3284
3427
  }
@@ -3289,7 +3432,7 @@ function bindHandler(el, key, val, state) {
3289
3432
  });
3290
3433
  return true;
3291
3434
  }
3292
- if (isFunctionDef(val) && typeof val.body === "string") {
3435
+ if (isFunctionDef(val) && isString2(val.body)) {
3293
3436
  const params = resolveParamNames(val);
3294
3437
  const fn = new Function(...params, val.body);
3295
3438
  el.addEventListener(type, (e) => fn(scope, e));
@@ -3310,12 +3453,12 @@ function bindDefinitionHandlers(host, def, state) {
3310
3453
  }
3311
3454
  }
3312
3455
  function bindProperty(el, key, val, state) {
3313
- const target = el;
3456
+ const target = elementProperties(el);
3314
3457
  const boundProp = boundPropKey(key, val, state);
3315
3458
  if (boundProp) {
3316
3459
  el.dataset.jxBoundProp = boundProp;
3317
3460
  }
3318
- const asAsset = (resolved) => typeof resolved === "string" ? canvasAssetValue(el.tagName, key, resolved) : resolved;
3461
+ const asAsset = (resolved) => isString2(resolved) ? canvasAssetValue(el.tagName, key, resolved) : resolved;
3319
3462
  const write = (resolved) => {
3320
3463
  const node = el;
3321
3464
  if (key === "className" && !(node instanceof HTMLElement)) {
@@ -3327,7 +3470,7 @@ function bindProperty(el, key, val, state) {
3327
3470
  }
3328
3471
  target[key] = resolved;
3329
3472
  };
3330
- if (isRefObj(val)) {
3473
+ if (isRef2(val)) {
3331
3474
  const refVal = val;
3332
3475
  if (key === "id") {
3333
3476
  target[key] = resolveRef(refVal.$ref, state);
@@ -3339,8 +3482,9 @@ function bindProperty(el, key, val, state) {
3339
3482
  return;
3340
3483
  }
3341
3484
  if (isTemplateString(val)) {
3342
- effect(() => {
3343
- write(asAsset(evaluateTemplate(val, state)));
3485
+ const template = val;
3486
+ bindTemplate(template, () => {
3487
+ write(asAsset(evaluateTemplate(template, state)));
3344
3488
  });
3345
3489
  return;
3346
3490
  }
@@ -3426,14 +3570,14 @@ function textSink(tag) {
3426
3570
  write();
3427
3571
  },
3428
3572
  text() {
3429
- return tag.textContent ?? "";
3573
+ return tag.textContent;
3430
3574
  }
3431
3575
  };
3432
3576
  }
3433
3577
  function openSink(doc) {
3434
3578
  const view = doc.defaultView;
3435
3579
  const SheetConstructor = view?.CSSStyleSheet;
3436
- if (typeof SheetConstructor === "function" && Array.isArray(doc.adoptedStyleSheets)) {
3580
+ if (isFunction2(SheetConstructor) && Array.isArray(doc.adoptedStyleSheets)) {
3437
3581
  try {
3438
3582
  const sheet = new SheetConstructor;
3439
3583
  doc.adoptedStyleSheets = [...doc.adoptedStyleSheets, sheet];
@@ -3444,9 +3588,12 @@ function openSink(doc) {
3444
3588
  }
3445
3589
  const tag = doc.createElement("style");
3446
3590
  tag.dataset.jxSheet = "";
3447
- (doc.head ?? doc.documentElement).append(tag);
3591
+ (documentHead(doc) ?? doc.documentElement).append(tag);
3448
3592
  return tag.sheet ? cssomSink(tag.sheet, () => tag.remove()) : textSink(tag);
3449
3593
  }
3594
+ function documentHead(doc) {
3595
+ return doc.head;
3596
+ }
3450
3597
  var sheetStates = new WeakMap;
3451
3598
  function sheetStateFor(doc) {
3452
3599
  const existing = sheetStates.get(doc);
@@ -3536,7 +3683,7 @@ function documentStyleText(doc = document) {
3536
3683
  `);
3537
3684
  }
3538
3685
  function declaresDisplay(style) {
3539
- return Boolean(style) && typeof style === "object" && "display" in style;
3686
+ return isNonNullObject(style) && "display" in style;
3540
3687
  }
3541
3688
  var callSiteStyles = new WeakMap;
3542
3689
  function mergeStyle(base, over) {
@@ -3546,7 +3693,7 @@ function mergeStyle(base, over) {
3546
3693
  const out = { ...base };
3547
3694
  for (const [key, value] of Object.entries(over)) {
3548
3695
  const prior = out[key];
3549
- out[key] = prior !== null && typeof prior === "object" && value !== null && typeof value === "object" && !Array.isArray(value) ? mergeStyle(prior, value) : value;
3696
+ out[key] = isNestedStyle(value) && isNonNullObject(prior) ? mergeStyle(Array.isArray(prior) ? Object.fromEntries(Object.entries(prior)) : prior, value) : value;
3550
3697
  }
3551
3698
  return out;
3552
3699
  }
@@ -3558,7 +3705,7 @@ function reapplyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3558
3705
  }
3559
3706
  function applyStyleInto(el, styleDef, mediaQueries, state, live) {
3560
3707
  releaseElementStyles(el);
3561
- const doc = el.ownerDocument ?? document;
3708
+ const doc = el.ownerDocument;
3562
3709
  const sheetState = sheetStateFor(doc);
3563
3710
  const transposeSelector = (_canvasDelinkPopovers || _canvasDelinkCommands) && canvasStamped(el) ? (selector) => transposeCanvasOverlaySelector(selector, {
3564
3711
  dialog: el.tagName === "DIALOG"
@@ -3573,11 +3720,16 @@ function applyStyleInto(el, styleDef, mediaQueries, state, live) {
3573
3720
  sources.push({ name: property, value });
3574
3721
  return null;
3575
3722
  }
3576
- if (serial < 0) {
3577
- ({ serial } = sheetState);
3578
- sheetState.serial += 1;
3723
+ let name;
3724
+ if (target === "self") {
3725
+ name = `--jx-s${indirect}`;
3726
+ } else {
3727
+ if (serial < 0) {
3728
+ ({ serial } = sheetState);
3729
+ sheetState.serial += 1;
3730
+ }
3731
+ name = `--jx-r${serial}-${indirect}`;
3579
3732
  }
3580
- const name = `--jx-r${serial}-${indirect}`;
3581
3733
  indirect += 1;
3582
3734
  sources.push({ name, value });
3583
3735
  return `var(${name})`;
@@ -3620,7 +3772,7 @@ function applyStyleInto(el, styleDef, mediaQueries, state, live) {
3620
3772
  scope.run(() => {
3621
3773
  for (const { name, value } of sources) {
3622
3774
  effect(() => {
3623
- const resolved = isRefObj(value) ? resolveRef(value.$ref, state) : evaluateTemplate(value, state);
3775
+ const resolved = isRef2(value) ? resolveRef(value.$ref, state) : evaluateTemplate(value, state);
3624
3776
  el.style.setProperty(name, canvasStyleValue(String(resolved ?? "")));
3625
3777
  });
3626
3778
  }
@@ -3649,7 +3801,7 @@ function applyAttributes(el, attrs, state) {
3649
3801
  el.removeAttribute(attr);
3650
3802
  return;
3651
3803
  }
3652
- if (typeof resolved === "boolean") {
3804
+ if (isBoolean(resolved)) {
3653
3805
  const text = booleanAttrValue(attr, resolved);
3654
3806
  if (text === null) {
3655
3807
  el.removeAttribute(attr);
@@ -3660,10 +3812,10 @@ function applyAttributes(el, attrs, state) {
3660
3812
  }
3661
3813
  el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved)));
3662
3814
  };
3663
- if (isRefObj(v)) {
3815
+ if (isRef2(v)) {
3664
3816
  effect(() => write(resolveRef(v.$ref, state)));
3665
3817
  } else if (isTemplateString(v)) {
3666
- effect(() => write(evaluateAttrTemplate(v, state)));
3818
+ bindTemplate(v, () => write(evaluateValueTemplate(v, state)));
3667
3819
  } else {
3668
3820
  write(v);
3669
3821
  }
@@ -3674,7 +3826,7 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3674
3826
  const anchor = document.createComment("jx-array");
3675
3827
  parentEl.append(anchor);
3676
3828
  const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef, key: keyRef } = arrayDef;
3677
- const keyPointer = isRefObj(keyRef) ? keyRef.$ref : null;
3829
+ const keyPointer = isRef2(keyRef) ? keyRef.$ref : null;
3678
3830
  const instancePath = _instancePath;
3679
3831
  let warned = false;
3680
3832
  const warnOnce = (message) => {
@@ -3685,12 +3837,12 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3685
3837
  };
3686
3838
  let rows = [];
3687
3839
  const teardown = (row) => {
3688
- row.scope.stop();
3689
3840
  row.node.remove();
3841
+ row.scope.stop();
3690
3842
  };
3691
3843
  const createRow = (key, item, index) => {
3692
3844
  const map = shallowReactive({ index, item });
3693
- const child = Object.create(state);
3845
+ const child = inheritScope(state);
3694
3846
  child.$map = map;
3695
3847
  Object.defineProperty(child, "$map/item", { enumerable: true, get: () => map.item });
3696
3848
  Object.defineProperty(child, "$map/index", { enumerable: true, get: () => map.index });
@@ -3737,17 +3889,19 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3737
3889
  rows = next;
3738
3890
  };
3739
3891
  const update = () => {
3740
- let items = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
3741
- if (Array.isArray(items) && isRefObj(filterRef)) {
3892
+ let items = isRef2(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
3893
+ if (Array.isArray(items) && isRef2(filterRef)) {
3742
3894
  const fn = resolveRef(filterRef.$ref, state);
3743
- if (typeof fn === "function") {
3895
+ if (isFunction2(fn)) {
3744
3896
  items = items.filter(fn);
3745
3897
  }
3746
3898
  }
3747
- if (Array.isArray(items) && isRefObj(sortRef)) {
3899
+ if (Array.isArray(items) && isRef2(sortRef)) {
3748
3900
  const fn = resolveRef(sortRef.$ref, state);
3749
- if (typeof fn === "function") {
3750
- items = [...items].toSorted(fn);
3901
+ if (isFunction2(fn)) {
3902
+ const compare = fn;
3903
+ const unsorted = items;
3904
+ items = [...unsorted].toSorted(compare);
3751
3905
  }
3752
3906
  }
3753
3907
  const list = Array.isArray(items) && mapDef ? items : [];
@@ -3811,7 +3965,7 @@ function mappedRowKey(pointer, item, index, warnOnce) {
3811
3965
  return index;
3812
3966
  }
3813
3967
  function resolveTagName(tagName, scope) {
3814
- if (typeof tagName === "string") {
3968
+ if (isString2(tagName)) {
3815
3969
  return tagName;
3816
3970
  }
3817
3971
  if (!isTagExpression(tagName)) {
@@ -3832,7 +3986,7 @@ function renderSwitch(def, state, options) {
3832
3986
  options.onNodeCreated(container, path, def, state);
3833
3987
  }
3834
3988
  applyProperties(container, def, state);
3835
- applyStyle(container, def.style ?? {}, state["$media"] ?? {}, state);
3989
+ applyStyle(container, def.style ?? {}, scopeMedia(state), state);
3836
3990
  applyAttributes(container, def.attributes ?? {}, state);
3837
3991
  let generation = 0;
3838
3992
  let live = null;
@@ -3842,9 +3996,9 @@ function renderSwitch(def, state, options) {
3842
3996
  live = null;
3843
3997
  };
3844
3998
  effect(() => {
3845
- if (!isRefObj(def.$switch)) {
3846
- retire();
3999
+ if (!isRef2(def.$switch)) {
3847
4000
  container.replaceChildren();
4001
+ retire();
3848
4002
  generation += 1;
3849
4003
  return;
3850
4004
  }
@@ -3853,8 +4007,8 @@ function renderSwitch(def, state, options) {
3853
4007
  return;
3854
4008
  }
3855
4009
  renderedKey = key;
3856
- retire();
3857
4010
  container.replaceChildren();
4011
+ retire();
3858
4012
  generation += 1;
3859
4013
  const caseDef = def.cases?.[key];
3860
4014
  if (!caseDef) {
@@ -3864,7 +4018,7 @@ function renderSwitch(def, state, options) {
3864
4018
  const scope = effectScope(true);
3865
4019
  live = scope;
3866
4020
  const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3867
- if (isRefObj(caseDef)) {
4021
+ if (isRef2(caseDef)) {
3868
4022
  const { href } = new URL(caseDef.$ref, options?._ctx?.base ?? location.href);
3869
4023
  resolve(href, options?._ctx).then(async (doc) => {
3870
4024
  if (gen !== generation) {
@@ -3889,6 +4043,7 @@ function renderSwitch(def, state, options) {
3889
4043
  onScopeDispose(retire, true);
3890
4044
  return container;
3891
4045
  }
4046
+ var scopeRef = ref;
3892
4047
  async function resolvePrototype(def, state, key, base, ctx) {
3893
4048
  if (def.$src) {
3894
4049
  return resolveExternalPrototype(def, state, key, base);
@@ -3921,7 +4076,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3921
4076
  signal: controller.signal,
3922
4077
  ...def.headers && { headers: def.headers },
3923
4078
  ...def.body && {
3924
- body: typeof def.body === "object" ? JSON.stringify(def.body) : def.body
4079
+ body: isNonNullObject(def.body) ? JSON.stringify(def.body) : def.body
3925
4080
  }
3926
4081
  }).then((r) => r.ok ? r.json() : Promise.reject(r.statusText)).then((d) => {
3927
4082
  s.value = d;
@@ -3944,7 +4099,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3944
4099
  const p = {};
3945
4100
  for (const [k, v] of Object.entries(def)) {
3946
4101
  if (k !== "$prototype") {
3947
- p[k] = isRefObj(v) ? resolveRef(v.$ref, state) : isTemplateString(v) ? evaluateTemplate(v, state) : v;
4102
+ p[k] = isRef2(v) ? resolveRef(v.$ref, state) : isTemplateString(v) ? evaluateTemplate(v, state) : v;
3948
4103
  }
3949
4104
  }
3950
4105
  return new URLSearchParams(p).toString();
@@ -3961,7 +4116,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3961
4116
  } catch {
3962
4117
  init = def.default ?? null;
3963
4118
  }
3964
- const storageState = ref(init);
4119
+ const storageState = scopeRef(init);
3965
4120
  effect(() => {
3966
4121
  const v = storageState.value;
3967
4122
  if (v === null) {
@@ -3989,7 +4144,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3989
4144
  return raw;
3990
4145
  }
3991
4146
  };
3992
- const cookieState = ref(read() ?? def.default ?? null);
4147
+ const cookieState = scopeRef(read() ?? def.default ?? null);
3993
4148
  effect(() => {
3994
4149
  document.cookie = serializeCookie(name, cookieState.value, def);
3995
4150
  });
@@ -4047,8 +4202,9 @@ async function resolvePrototype(def, state, key, base, ctx) {
4047
4202
  return fd;
4048
4203
  }
4049
4204
  case "Blob": {
4050
- return new Blob(def.parts ?? [], {
4051
- type: typeof def.type === "string" ? def.type : "text/plain"
4205
+ const parts = def.parts;
4206
+ return new Blob(parts ?? [], {
4207
+ type: isString2(def.type) ? def.type : "text/plain"
4052
4208
  });
4053
4209
  }
4054
4210
  case "ReadableStream": {
@@ -4072,6 +4228,15 @@ var EXTERNAL_RESERVED = new Set([
4072
4228
  "arguments",
4073
4229
  "name"
4074
4230
  ]);
4231
+ function externalConfig(def) {
4232
+ const config = {};
4233
+ for (const [k, v] of Object.entries(def)) {
4234
+ if (!EXTERNAL_RESERVED.has(k)) {
4235
+ config[k] = v;
4236
+ }
4237
+ }
4238
+ return config;
4239
+ }
4075
4240
  async function resolveExternalPrototype(def, state, key, base) {
4076
4241
  const src = def.$src;
4077
4242
  if (!src || !src.endsWith(".class.json")) {
@@ -4088,11 +4253,11 @@ async function importAndInstantiate(def, src, exportName, base) {
4088
4253
  mod = seeded;
4089
4254
  } else {
4090
4255
  try {
4091
- mod = await import(src);
4256
+ mod = await importModule(src);
4092
4257
  } catch {
4093
4258
  if (base) {
4094
4259
  const resolvedSrc = new URL(src, base).href;
4095
- mod = await import(resolvedSrc);
4260
+ mod = await importModule(resolvedSrc);
4096
4261
  } else {
4097
4262
  throw new Error(`Failed to import "${src}"`);
4098
4263
  }
@@ -4103,27 +4268,13 @@ async function importAndInstantiate(def, src, exportName, base) {
4103
4268
  if (!ExportedClass) {
4104
4269
  throw new Error(`Jx: export "${exportName}" not found in "${src}"`);
4105
4270
  }
4106
- if (typeof ExportedClass !== "function") {
4271
+ if (!isFunction2(ExportedClass)) {
4107
4272
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a class`);
4108
4273
  }
4109
- const config = {};
4110
- for (const [k, v] of Object.entries(def)) {
4111
- if (!EXTERNAL_RESERVED.has(k)) {
4112
- config[k] = v;
4113
- }
4114
- }
4115
- const Ctor = ExportedClass;
4116
- const instance = new Ctor(config);
4117
- let value;
4118
- if (typeof instance.resolve === "function") {
4119
- value = await instance.resolve();
4120
- } else if ("value" in instance) {
4121
- ({ value } = instance);
4122
- } else {
4123
- value = instance;
4124
- }
4125
- const s = ref(value);
4126
- if (typeof instance.subscribe === "function") {
4274
+ const instance = new ExportedClass(externalConfig(def));
4275
+ const value = isFunction2(instance.resolve) ? await instance.resolve() : ("value" in instance) ? instance.value : instance;
4276
+ const s = scopeRef(value);
4277
+ if (isFunction2(instance.subscribe)) {
4127
4278
  instance.subscribe((newVal) => {
4128
4279
  s.value = newVal;
4129
4280
  });
@@ -4162,33 +4313,23 @@ async function resolveClassJson(def, state, key, base) {
4162
4313
  }
4163
4314
  }
4164
4315
  const DynClass = classFromSchema(classDef);
4165
- const config = {};
4166
- for (const [k, v] of Object.entries(def)) {
4167
- if (!EXTERNAL_RESERVED.has(k)) {
4168
- config[k] = v;
4169
- }
4170
- }
4171
- const instance = new DynClass(config);
4172
- let value;
4173
- if (typeof instance.resolve === "function") {
4174
- value = await instance.resolve();
4175
- } else if ("value" in instance) {
4176
- ({ value } = instance);
4177
- } else {
4178
- value = instance;
4179
- }
4180
- const s = ref(value);
4181
- if (typeof instance.subscribe === "function") {
4316
+ const instance = new DynClass(externalConfig(def));
4317
+ const value = isFunction2(instance.resolve) ? await instance.resolve() : ("value" in instance) ? instance.value : instance;
4318
+ const s = scopeRef(value);
4319
+ if (isFunction2(instance.subscribe)) {
4182
4320
  instance.subscribe((newVal) => {
4183
4321
  s.value = newVal;
4184
4322
  });
4185
4323
  }
4186
4324
  return s;
4187
4325
  }
4326
+ function isCtorDef(rawCtor) {
4327
+ return isNonNullObject(rawCtor);
4328
+ }
4188
4329
  function classFromSchema(classDef) {
4189
4330
  const fields = classDef.$defs?.fields ?? {};
4190
4331
  const rawCtor = classDef.$defs?.constructor;
4191
- const ctor = typeof rawCtor === "object" ? rawCtor : undefined;
4332
+ const ctor = isCtorDef(rawCtor) ? rawCtor : undefined;
4192
4333
  const methods = classDef.$defs?.methods ?? {};
4193
4334
 
4194
4335
  class DynClass {
@@ -4209,7 +4350,8 @@ function classFromSchema(classDef) {
4209
4350
  if (ctor?.body) {
4210
4351
  const bodyStr = Array.isArray(ctor.body) ? ctor.body.join(`
4211
4352
  `) : ctor.body;
4212
- new Function("config", bodyStr).call(this, config);
4353
+ const init = new Function("config", bodyStr);
4354
+ init.call(this, config);
4213
4355
  }
4214
4356
  }
4215
4357
  }
@@ -4217,10 +4359,10 @@ function classFromSchema(classDef) {
4217
4359
  const name = typedMethod.identifier ?? key;
4218
4360
  const params = (typedMethod.parameters ?? []).map((p) => {
4219
4361
  if (p.$ref) {
4220
- return p.$ref.split("/").pop();
4362
+ return p.$ref.split("/").pop() ?? "";
4221
4363
  }
4222
4364
  const n = p.identifier ?? p.name;
4223
- return typeof n === "string" ? n : "arg";
4365
+ return isString2(n) ? n : "arg";
4224
4366
  });
4225
4367
  const bodyStr = Array.isArray(typedMethod.body) ? typedMethod.body.join(`
4226
4368
  `) : typedMethod.body ?? "";
@@ -4247,16 +4389,10 @@ function classFromSchema(classDef) {
4247
4389
  configurable: true,
4248
4390
  value: classDef.title
4249
4391
  });
4250
- const dynCtor = DynClass;
4251
- return dynCtor;
4392
+ return DynClass;
4252
4393
  }
4253
4394
  async function resolveViaDevProxy(def, state, key, base) {
4254
- const config = {};
4255
- for (const [k, v] of Object.entries(def)) {
4256
- if (!EXTERNAL_RESERVED.has(k)) {
4257
- config[k] = v;
4258
- }
4259
- }
4395
+ const config = externalConfig(def);
4260
4396
  const hasTemplates = Object.values(config).some((v) => isTemplateString(v));
4261
4397
  const doResolve = (resolvedConfig) => fetch(resolveProxyPath("/__jx_resolve__"), {
4262
4398
  body: JSON.stringify({
@@ -4322,16 +4458,16 @@ async function resolveServerFunction(def, state, key, base) {
4322
4458
  if (!candidate) {
4323
4459
  throw new Error(`Jx: export "${exportName}" not found in "${src}" for "${key}"`);
4324
4460
  }
4325
- if (typeof candidate !== "function") {
4461
+ if (!isFunction2(candidate)) {
4326
4462
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a function`);
4327
4463
  }
4328
4464
  const fn = candidate;
4329
4465
  const rawArgs = def.arguments ?? {};
4330
- const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
4466
+ const hasReactiveArg = Object.values(rawArgs).some((v) => isRef2(v));
4331
4467
  const resolveArgs = () => {
4332
4468
  const args = {};
4333
4469
  for (const [k, v] of Object.entries(rawArgs)) {
4334
- args[k] = isRefObj(v) ? resolveRef(v.$ref, state) : v;
4470
+ args[k] = isRef2(v) ? resolveRef(v.$ref, state) : v;
4335
4471
  }
4336
4472
  return args;
4337
4473
  };
@@ -4350,11 +4486,11 @@ async function resolveServerFunction(def, state, key, base) {
4350
4486
  }
4351
4487
  async function resolveServerFunctionViaProxy(def, state, key, base) {
4352
4488
  const rawArgs = def.arguments ?? {};
4353
- const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
4489
+ const hasReactiveArg = Object.values(rawArgs).some((v) => isRef2(v));
4354
4490
  const resolveArgs = () => {
4355
4491
  const args = {};
4356
4492
  for (const [k, v] of Object.entries(rawArgs)) {
4357
- args[k] = isRefObj(v) ? resolveRef(v.$ref, state) : v;
4493
+ args[k] = isRef2(v) ? resolveRef(v.$ref, state) : v;
4358
4494
  }
4359
4495
  return args;
4360
4496
  };
@@ -4387,7 +4523,7 @@ async function resolveServerFunctionViaProxy(def, state, key, base) {
4387
4523
  return s;
4388
4524
  }
4389
4525
  function resolveRef(refPath, state) {
4390
- if (typeof refPath !== "string") {
4526
+ if (!isString2(refPath)) {
4391
4527
  return refPath;
4392
4528
  }
4393
4529
  if (refPath.startsWith("$map/") || refPath.startsWith("#/$map/")) {
@@ -4395,7 +4531,7 @@ function resolveRef(refPath, state) {
4395
4531
  const [, key] = parts;
4396
4532
  const map = state.$map;
4397
4533
  const base = map?.[key] ?? state[`$map/${key}`];
4398
- return parts.length > 2 ? getPath2(base, parts.slice(2).join("/")) : base;
4534
+ return parts.length > 2 ? readPath(base, parts.slice(2).join("/")) : base;
4399
4535
  }
4400
4536
  if (refPath.startsWith("#/state/")) {
4401
4537
  return readPath(state, refPath.slice("#/state/".length));
@@ -4404,46 +4540,39 @@ function resolveRef(refPath, state) {
4404
4540
  return readPath(state, refPath.slice("parent#/".length));
4405
4541
  }
4406
4542
  if (refPath.startsWith("window#/")) {
4407
- return getPath2(globalThis.window, refPath.slice("window#/".length));
4543
+ return readPath(globalThis.window, refPath.slice("window#/".length));
4408
4544
  }
4409
4545
  if (refPath.startsWith("document#/")) {
4410
- return getPath2(globalThis.document, refPath.slice("document#/".length));
4546
+ return readPath(globalThis.document, refPath.slice("document#/".length));
4411
4547
  }
4412
4548
  return readPath(state, refPath) ?? null;
4413
4549
  }
4414
4550
  function isSignal(v) {
4415
4551
  return isRef(v);
4416
4552
  }
4417
- function isRefObj(v) {
4418
- return isRef2(v);
4419
- }
4420
- function getPath2(obj, path) {
4421
- return readPath(obj, path);
4422
- }
4423
4553
  function absorbAttribute(state, name, value, defaults) {
4424
4554
  const camelKey = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
4425
4555
  const current = state[camelKey];
4426
- if (typeof current === "boolean") {
4556
+ if (isBoolean(current)) {
4427
4557
  state[camelKey] = value !== null && value !== "false";
4428
4558
  return;
4429
4559
  }
4430
4560
  if (value === null) {
4431
4561
  const declared = defaults?.get(camelKey);
4432
- state[camelKey] = declared === undefined ? typeof current === "number" ? 0 : "" : declared;
4562
+ state[camelKey] = declared === undefined ? isNumber(current) ? 0 : "" : declared;
4433
4563
  return;
4434
4564
  }
4435
- state[camelKey] = typeof current === "number" ? Number(value) : value;
4565
+ state[camelKey] = isNumber(current) ? Number(value) : value;
4436
4566
  }
4437
4567
  function declaredDefaults(def) {
4438
4568
  const out = new Map;
4439
4569
  for (const [key, entry] of Object.entries(def.state ?? {})) {
4440
- if (entry !== null && typeof entry === "object") {
4441
- const obj = entry;
4442
- if ("default" in obj) {
4443
- out.set(key, obj["default"]);
4570
+ if (isNonNullObject(entry)) {
4571
+ if ("default" in entry) {
4572
+ out.set(key, entry.default);
4444
4573
  continue;
4445
4574
  }
4446
- if (COMPUTED_STATE_KEYS.some((marker) => (marker in obj))) {
4575
+ if (COMPUTED_STATE_KEYS.some((marker) => (marker in entry))) {
4447
4576
  continue;
4448
4577
  }
4449
4578
  }
@@ -4463,6 +4592,15 @@ function instanceSupplies(el, key) {
4463
4592
  const kebab = key.replaceAll(/[A-Z]/gu, (c) => `-${c.toLowerCase()}`);
4464
4593
  return kebab !== key && el.hasAttribute(kebab);
4465
4594
  }
4595
+ function nativeSetter(el, key) {
4596
+ for (let proto = Reflect.getPrototypeOf(el);proto; proto = Reflect.getPrototypeOf(proto)) {
4597
+ const descriptor = Object.getOwnPropertyDescriptor(proto, key);
4598
+ if (descriptor) {
4599
+ return descriptor.set;
4600
+ }
4601
+ }
4602
+ return;
4603
+ }
4466
4604
  function refusePrivateProp(key, where) {
4467
4605
  if (!isPrivateStateKey(key)) {
4468
4606
  return false;
@@ -4478,17 +4616,17 @@ function _resetPrivatePropWarnings() {
4478
4616
  _privatePropWarned.clear();
4479
4617
  }
4480
4618
  function mergeProps(def, parentState) {
4481
- const child = Object.create(parentState);
4619
+ const child = inheritScope(parentState);
4482
4620
  for (const [k, v] of Object.entries(def.$props ?? {})) {
4483
4621
  if (refusePrivateProp(k, "$props")) {
4484
4622
  continue;
4485
4623
  }
4486
- child[k] = isRefObj(v) ? resolveRef(v.$ref, parentState) : v;
4624
+ child[k] = isRef2(v) ? resolveRef(v.$ref, parentState) : v;
4487
4625
  }
4488
4626
  return child;
4489
4627
  }
4490
4628
  function toCSSText(rules) {
4491
- return Object.entries(rules).filter(([k, v]) => !isNestedSelectorKey(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${cssPropertyName(p)}: ${canvasStyleValue(String(v))}`).join("; ");
4629
+ return Object.entries(rules).filter(([k, v]) => !isNestedSelectorKey(k) && !isNonNullObject(v)).map(([p, v]) => `${cssPropertyName(p)}: ${canvasStyleValue(String(v))}`).join("; ");
4492
4630
  }
4493
4631
  var _rootMedia = {};
4494
4632
  var _elementDefs = new Map;
@@ -4520,7 +4658,7 @@ function setRootMedia(map) {
4520
4658
  }
4521
4659
  async function registerElements(elements, base, ctx) {
4522
4660
  for (const entry of elements) {
4523
- if (typeof entry === "string") {
4661
+ if (isString2(entry)) {
4524
4662
  try {
4525
4663
  const specifier = entry.startsWith("/") || entry.startsWith(".") ? entry : `/node_modules/${entry}`;
4526
4664
  await import(specifier);
@@ -4529,7 +4667,7 @@ async function registerElements(elements, base, ctx) {
4529
4667
  }
4530
4668
  continue;
4531
4669
  }
4532
- if (!isRefObj(entry)) {
4670
+ if (!isRef2(entry)) {
4533
4671
  continue;
4534
4672
  }
4535
4673
  const { href } = new URL(entry.$ref, base);
@@ -4555,7 +4693,7 @@ function injectHead(entries, _base) {
4555
4693
  const attrs = { ...entry.attributes };
4556
4694
  for (const key of ["href", "src"]) {
4557
4695
  const v = attrs[key];
4558
- if (typeof v !== "string" || v === "") {
4696
+ if (!isString2(v) || v === "") {
4559
4697
  continue;
4560
4698
  }
4561
4699
  if (!v.startsWith("/") && !v.startsWith(".") && !v.startsWith("http")) {
@@ -4573,7 +4711,7 @@ function injectHead(entries, _base) {
4573
4711
  el.setAttribute(k, String(v));
4574
4712
  }
4575
4713
  if (entry.textContent) {
4576
- el.textContent = typeof entry.textContent === "object" ? JSON.stringify(entry.textContent, null, 2) : entry.textContent;
4714
+ el.textContent = isNonNullObject(entry.textContent) ? JSON.stringify(entry.textContent, null, 2) : entry.textContent;
4577
4715
  }
4578
4716
  document.head.append(el);
4579
4717
  }
@@ -4581,6 +4719,18 @@ function injectHead(entries, _base) {
4581
4719
  var MAX_COMPONENT_NESTING = 32;
4582
4720
  var ROOT_INSTANCE_PATH = { expansion: 0, frames: [] };
4583
4721
  var _instancePath = ROOT_INSTANCE_PATH;
4722
+ function reportUnrendered(host, tagName, error) {
4723
+ if (!host.isConnected) {
4724
+ return;
4725
+ }
4726
+ console.error(`Jx: <${tagName}> was not rendered:`, error);
4727
+ host.dispatchEvent(new ErrorEvent("jx-error", {
4728
+ bubbles: true,
4729
+ composed: true,
4730
+ error,
4731
+ message: error.message
4732
+ }));
4733
+ }
4584
4734
  function underInstancePath(path, fn) {
4585
4735
  const was = _instancePath;
4586
4736
  _instancePath = path;
@@ -4607,7 +4757,7 @@ function samePropValue(a, b) {
4607
4757
  }
4608
4758
  }
4609
4759
  function isPlainData(value) {
4610
- if (typeof value !== "object" || value === null) {
4760
+ if (!isNonNullObject(value)) {
4611
4761
  return false;
4612
4762
  }
4613
4763
  const raw = toRaw(value);
@@ -4640,17 +4790,18 @@ function extendInstancePath(path, frame) {
4640
4790
  var _definedSources = new Set;
4641
4791
  async function defineElement(source, baseUrl) {
4642
4792
  let base = baseUrl;
4643
- let doc = source;
4644
- if (typeof source === "string") {
4793
+ let source_;
4794
+ if (isString2(source)) {
4645
4795
  base = new URL(source, base ?? location.href).href;
4646
4796
  if (_definedSources.has(base)) {
4647
4797
  return;
4648
4798
  }
4649
4799
  _definedSources.add(base);
4650
- doc = await resolve(source);
4800
+ source_ = await resolve(source);
4801
+ } else {
4802
+ source_ = source;
4651
4803
  }
4652
4804
  base ??= location.href;
4653
- const source_ = doc;
4654
4805
  const { tagName } = source_;
4655
4806
  if (!tagName || !tagName.includes("-")) {
4656
4807
  throw new Error(`Jx defineElement: tagName "${tagName}" must contain a hyphen`);
@@ -4695,7 +4846,8 @@ async function defineElement(source, baseUrl) {
4695
4846
  if (propsAttr) {
4696
4847
  try {
4697
4848
  const props = JSON.parse(propsAttr);
4698
- for (const [key, val] of Object.entries(props)) {
4849
+ const entries = isNonNullObject(props) || isString2(props) ? Object.entries(props) : [];
4850
+ for (const [key, val] of entries) {
4699
4851
  if (refusePrivateProp(key, "data-jx-props")) {
4700
4852
  continue;
4701
4853
  }
@@ -4724,9 +4876,10 @@ async function defineElement(source, baseUrl) {
4724
4876
  if (isPrivateStateKey(key)) {
4725
4877
  continue;
4726
4878
  }
4727
- if (key in this && this[key] !== undefined && instanceSupplies(this, key)) {
4728
- state[key] = this[key];
4729
- supplied[key] = this[key];
4879
+ const own = elementProperties(this);
4880
+ if (key in this && own[key] !== undefined && instanceSupplies(this, key)) {
4881
+ state[key] = own[key];
4882
+ supplied[key] = own[key];
4730
4883
  }
4731
4884
  }
4732
4885
  let ownPath;
@@ -4734,69 +4887,117 @@ async function defineElement(source, baseUrl) {
4734
4887
  ownPath = extendInstancePath(enclosingPath, { props: supplied, tag: tagName });
4735
4888
  } catch (error) {
4736
4889
  this.replaceChildren();
4737
- if (!this.isConnected) {
4738
- return;
4739
- }
4740
- console.error(`Jx: <${tagName}> was not rendered:`, error);
4741
- this.dispatchEvent(new ErrorEvent("jx-error", {
4742
- bubbles: true,
4743
- composed: true,
4744
- error,
4745
- message: error instanceof Error ? error.message : String(error)
4746
- }));
4890
+ reportUnrendered(this, tagName, error instanceof Error ? error : new Error(String(error)));
4747
4891
  return;
4748
4892
  }
4749
4893
  for (const key of Object.keys(def.state ?? {})) {
4750
4894
  if (isPrivateStateKey(key)) {
4751
4895
  continue;
4752
4896
  }
4753
- if (!(key in HTMLElement.prototype)) {
4754
- Object.defineProperty(this, key, {
4755
- configurable: true,
4756
- get: () => state[key],
4757
- set: (v) => {
4758
- state[key] = v;
4759
- }
4760
- });
4761
- }
4897
+ const native = nativeSetter(this, key);
4898
+ Object.defineProperty(this, key, {
4899
+ configurable: true,
4900
+ get: () => state[key],
4901
+ set: (v) => {
4902
+ native?.call(this, v);
4903
+ state[key] = v;
4904
+ }
4905
+ });
4762
4906
  }
4763
4907
  this._state = state;
4764
- const slottedChildren = [...this.childNodes];
4908
+ const slottedChildren = captureSlotted(this);
4765
4909
  this.replaceChildren();
4766
- const defStyle = declaresDisplay(def.style) ? def.style : { display: "block", ...def.style };
4910
+ const ownStyle = def.style;
4911
+ const defStyle = ownStyle && declaresDisplay(ownStyle) ? ownStyle : { display: "block", ...ownStyle };
4767
4912
  const hostStyle = mergeStyle(defStyle, callSiteStyles.get(this));
4768
- applyStyle(this, hostStyle, state["$media"] ?? {}, state);
4913
+ applyStyle(this, hostStyle, scopeMedia(state), state);
4769
4914
  applyAttributes(this, def.attributes ?? {}, state);
4770
4915
  bindDefinitionHandlers(this, def, state);
4771
4916
  if (!Array.isArray(def.children) && def.textContent !== undefined) {
4772
4917
  bindProperty(this, "textContent", def.textContent, state);
4773
4918
  }
4774
4919
  const children = Array.isArray(def.children) ? def.children : [];
4775
- const wasInside = _canvasInsideStampedHost;
4776
- _canvasInsideStampedHost ||= this.dataset.jxPath !== undefined;
4777
- try {
4778
- underInstancePath(ownPath, () => {
4779
- for (const childDef of children) {
4780
- this.append(renderNode(childDef, state));
4781
- }
4782
- });
4783
- } finally {
4784
- _canvasInsideStampedHost = wasInside;
4785
- }
4786
- distributeSlots(this, slottedChildren);
4787
- const { onMount } = state;
4788
- if (typeof onMount === "function") {
4789
- queueMicrotask(() => onMount(state, this));
4920
+ const draw = () => {
4921
+ const wasInside = _canvasInsideStampedHost;
4922
+ _canvasInsideStampedHost ||= this.dataset.jxPath !== undefined;
4923
+ let failure = null;
4924
+ try {
4925
+ underInstancePath(ownPath, () => {
4926
+ for (const childDef of children) {
4927
+ this.append(renderNode(childDef, state));
4928
+ }
4929
+ });
4930
+ } catch (error) {
4931
+ failure = error instanceof Error ? error : new Error(String(error));
4932
+ } finally {
4933
+ _canvasInsideStampedHost = wasInside;
4934
+ }
4935
+ distributeSlots(this, slottedChildren);
4936
+ return failure;
4937
+ };
4938
+ const mounted = () => {
4939
+ const { onMount } = state;
4940
+ if (isScopeHook(onMount)) {
4941
+ queueMicrotask(() => onMount.call(this, state, this));
4942
+ }
4943
+ };
4944
+ let attempt = runScoped(draw);
4945
+ const failure = attempt.result;
4946
+ if (!failure) {
4947
+ mounted();
4948
+ return;
4790
4949
  }
4950
+ reportUnrendered(this, tagName, failure);
4951
+ const inputs = [...declaredDefaults(def).keys()].filter((key) => !isPrivateStateKey(key));
4952
+ let lastMessage = failure.message;
4953
+ let queued = false;
4954
+ const watch = effect(() => {
4955
+ for (const key of inputs) {
4956
+ state[key];
4957
+ }
4958
+ }, {
4959
+ scheduler: () => {
4960
+ if (queued) {
4961
+ return;
4962
+ }
4963
+ queued = true;
4964
+ queueMicrotask(() => {
4965
+ queued = false;
4966
+ if (!this.isConnected) {
4967
+ watch.effect.stop();
4968
+ return;
4969
+ }
4970
+ watch();
4971
+ attempt.stop();
4972
+ this.replaceChildren();
4973
+ pauseTracking();
4974
+ try {
4975
+ attempt = runScoped(draw);
4976
+ } finally {
4977
+ resetTracking();
4978
+ }
4979
+ const again = attempt.result;
4980
+ if (!again) {
4981
+ watch.effect.stop();
4982
+ mounted();
4983
+ } else if (again.message !== lastMessage) {
4984
+ lastMessage = again.message;
4985
+ reportUnrendered(this, tagName, again);
4986
+ }
4987
+ });
4988
+ }
4989
+ });
4791
4990
  }
4792
4991
  disconnectedCallback() {
4793
- if (typeof this._state?.onUnmount === "function") {
4794
- this._state.onUnmount(this._state);
4992
+ const state = this._state;
4993
+ if (state && isScopeHook(state.onUnmount)) {
4994
+ state.onUnmount(state);
4795
4995
  }
4796
4996
  }
4797
4997
  adoptedCallback() {
4798
- if (typeof this._state?.onAdopted === "function") {
4799
- this._state.onAdopted(this._state);
4998
+ const state = this._state;
4999
+ if (state && isScopeHook(state.onAdopted)) {
5000
+ state.onAdopted(state);
4800
5001
  }
4801
5002
  }
4802
5003
  attributeChangedCallback(name, oldVal, newVal) {
@@ -4818,16 +5019,21 @@ function renderCustomElementWithProps(def, state, options, path) {
4818
5019
  continue;
4819
5020
  }
4820
5021
  const write = (resolved) => {
4821
- el[key] = typeof resolved === "string" ? canvasAssetValue(el.tagName, key, resolved) : resolved;
5022
+ const value = isString2(resolved) ? canvasAssetValue(el.tagName, key, resolved) : resolved;
5023
+ elementProperties(el)[key] = value;
5024
+ const instanceState = instanceStateOf(el);
5025
+ if (instanceState && key in HTMLElement.prototype && Object.hasOwn(toRaw(instanceState), key)) {
5026
+ instanceState[key] = value;
5027
+ }
4822
5028
  };
4823
- if (isRefObj(val)) {
5029
+ if (isRef2(val)) {
4824
5030
  const refVal = val;
4825
5031
  write(resolveRef(refVal.$ref, state));
4826
5032
  effect(() => {
4827
5033
  write(resolveRef(refVal.$ref, state));
4828
5034
  });
4829
5035
  } else if (isTemplateString(val)) {
4830
- effect(() => {
5036
+ bindTemplate(val, () => {
4831
5037
  write(evaluateTemplate(val, state));
4832
5038
  });
4833
5039
  } else {
@@ -4837,7 +5043,7 @@ function renderCustomElementWithProps(def, state, options, path) {
4837
5043
  if (def.style) {
4838
5044
  callSiteStyles.set(el, def.style);
4839
5045
  }
4840
- applyStyle(el, def.style ?? {}, state["$media"] ?? {}, state);
5046
+ applyStyle(el, def.style ?? {}, scopeMedia(state), state);
4841
5047
  applyAttributes(el, def.attributes ?? {}, state);
4842
5048
  applyProperties(el, def, state);
4843
5049
  const children = Array.isArray(def.children) ? def.children : [];
@@ -4852,28 +5058,93 @@ function renderCustomElementWithProps(def, state, options, path) {
4852
5058
  }
4853
5059
  return el;
4854
5060
  }
4855
- function distributeSlots(host, slottedChildren) {
4856
- const slots = host.querySelectorAll("slot");
5061
+ function isElementNode(node) {
5062
+ return node.nodeType === Node.ELEMENT_NODE;
5063
+ }
5064
+ function isTextNode(node) {
5065
+ return node.nodeType === Node.TEXT_NODE;
5066
+ }
5067
+ function isCommentNode(node) {
5068
+ return node.nodeType === Node.COMMENT_NODE;
5069
+ }
5070
+ var SLOT_WHITESPACE = /^[\t\n\f\r ]+$/u;
5071
+ var SLOT_MARK = "jx-slot";
5072
+ var SLOT_ATTR = "data-jx-slots";
5073
+ var SLOT_RECORD_KEY = "jx.slot.group";
5074
+ var slotRecord = (() => {
5075
+ const key = Symbol.for(SLOT_RECORD_KEY);
5076
+ const holder = globalThis;
5077
+ holder[key] ??= new WeakMap;
5078
+ return holder[key];
5079
+ })();
5080
+ function captureSlotted(host) {
5081
+ const id = host.getAttribute(SLOT_ATTR);
5082
+ if (id === null) {
5083
+ return [...host.childNodes];
5084
+ }
5085
+ host.removeAttribute(SLOT_ATTR);
5086
+ const opener = `${SLOT_MARK} ${id} `;
5087
+ const closer = `/${SLOT_MARK} ${id}`;
5088
+ const openers = [];
5089
+ const walker = host.ownerDocument.createTreeWalker(host, NodeFilter.SHOW_COMMENT);
5090
+ for (let n = walker.nextNode();n; n = walker.nextNode()) {
5091
+ if (isCommentNode(n) && n.data.startsWith(opener)) {
5092
+ openers.push(n);
5093
+ }
5094
+ }
5095
+ const captured = [];
5096
+ for (const open of openers) {
5097
+ const name = decodeURIComponent(open.data.slice(opener.length));
5098
+ for (let n = open.nextSibling;n; n = n.nextSibling) {
5099
+ if (isCommentNode(n) && n.data === closer) {
5100
+ break;
5101
+ }
5102
+ slotRecord.set(n, name);
5103
+ captured.push(n);
5104
+ }
5105
+ }
5106
+ return captured;
5107
+ }
5108
+ function slotGroupHasContent(group) {
5109
+ return group.some((n) => isElementNode(n) || isTextNode(n) && n.data !== "");
5110
+ }
5111
+ function distributeSlots(host, captured) {
5112
+ const slots = [...host.querySelectorAll("slot")];
4857
5113
  if (slots.length === 0) {
4858
5114
  return;
4859
5115
  }
4860
- const named = new Map;
4861
- const unnamed = [];
4862
- for (const child of slottedChildren) {
4863
- if (child.nodeType === Node.ELEMENT_NODE && child.getAttribute("slot")) {
4864
- const name = child.getAttribute("slot");
4865
- if (!named.has(name)) {
4866
- named.set(name, []);
4867
- }
4868
- named.get(name).push(child);
4869
- } else {
4870
- unnamed.push(child);
5116
+ const groups = new Map;
5117
+ for (const n of captured) {
5118
+ if (isTextNode(n) && SLOT_WHITESPACE.test(n.data)) {
5119
+ continue;
5120
+ }
5121
+ const recorded = slotRecord.get(n);
5122
+ slotRecord.delete(n);
5123
+ const name = recorded ?? (isElementNode(n) ? n.getAttribute("slot") ?? "" : "");
5124
+ let group = groups.get(name);
5125
+ if (!group) {
5126
+ group = [];
5127
+ groups.set(name, group);
4871
5128
  }
5129
+ group.push(n);
4872
5130
  }
5131
+ const taken = new Set;
4873
5132
  for (const slot of slots) {
4874
- const name = slot.getAttribute("name");
4875
- const matches = name ? named.get(name) ?? [] : unnamed;
4876
- slot.replaceWith(...matches.length > 0 ? matches : [...slot.childNodes]);
5133
+ const name = slot.getAttribute("name") ?? "";
5134
+ let group = [];
5135
+ if (!taken.has(name)) {
5136
+ taken.add(name);
5137
+ group = groups.get(name) ?? [];
5138
+ }
5139
+ const placed = slotGroupHasContent(group) ? group : [...group, ...slot.childNodes];
5140
+ const parent = slot.parentElement;
5141
+ if (parent && parent !== host && parent.localName.includes("-")) {
5142
+ const forwarded = slotRecord.get(slot) ?? slot.getAttribute("slot") ?? "";
5143
+ for (const n of placed) {
5144
+ slotRecord.set(n, forwarded);
5145
+ }
5146
+ }
5147
+ slot.replaceWith(...placed);
4877
5148
  }
4878
5149
  }
4879
5150
  export {
@@ -4882,6 +5153,10 @@ export {
4882
5153
  Jx,
4883
5154
  MAX_COMPONENT_NESTING,
4884
5155
  RESERVED_KEYS,
5156
+ SLOT_ATTR,
5157
+ SLOT_MARK,
5158
+ SLOT_RECORD_KEY,
5159
+ SLOT_WHITESPACE,
4885
5160
  SUPPORTED_SCHEMA_VERSION,
4886
5161
  _resetPrivatePropWarnings,
4887
5162
  applyStyle,
@@ -4890,9 +5165,11 @@ export {
4890
5165
  buildStyleRules,
4891
5166
  camelToKebab,
4892
5167
  canvasStyleValue,
5168
+ captureSlotted,
4893
5169
  cssPropertyName,
4894
5170
  cssRuleText,
4895
5171
  defineElement,
5172
+ distributeSlots,
4896
5173
  documentStyleText,
4897
5174
  elementDefinition,
4898
5175
  enumeratedAttrNames,
@@ -4926,12 +5203,13 @@ export {
4926
5203
  setCanvasDelinkCommands,
4927
5204
  setCanvasDelinkPopovers,
4928
5205
  setCanvasViewportTranspose,
5206
+ setNpmModuleResolver,
4929
5207
  setResolveToken,
4930
5208
  setRootMedia,
4931
5209
  setSkipAutoRequests,
4932
- setSkipContentResolution,
4933
5210
  setSkipServerFunctions,
4934
5211
  setStampPropBindings,
5212
+ setTemplateErrorHandler,
4935
5213
  splitSelectorList,
4936
5214
  toCSSText,
4937
5215
  transposeCanvasOverlaySelector,
@@ -4939,5 +5217,5 @@ export {
4939
5217
  transposeCanvasUnits
4940
5218
  };
4941
5219
 
4942
- //# debugId=9BAF2C3B31911D4B64756E2164756E21
5220
+ //# debugId=F9E5ED7079B70E8764756E2164756E21
4943
5221
  //# sourceMappingURL=runtime.js.map