@jxsuite/runtime 4.0.3 → 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,18 +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;
3174
+ var _hostSeeded = new Set;
3039
3175
  function preloadModule(specifier, mod) {
3040
- if (typeof mod === "function") {
3176
+ _hostSeeded.add(specifier);
3177
+ if (isFunction2(mod)) {
3041
3178
  _moduleCache.delete(specifier);
3042
3179
  _moduleLoaders.set(specifier, mod);
3043
3180
  return;
@@ -3054,17 +3191,21 @@ function seededModule(src) {
3054
3191
  if (!pending) {
3055
3192
  return;
3056
3193
  }
3057
- if (typeof pending !== "function") {
3194
+ if (!isFunction2(pending)) {
3058
3195
  return pending;
3059
3196
  }
3060
- const load = Promise.resolve(pending()).then((mod) => {
3061
- _moduleCache.set(src, mod);
3062
- _moduleLoaders.delete(src);
3063
- return mod;
3064
- }, (error) => {
3065
- _moduleLoaders.set(src, pending);
3066
- throw error;
3067
- });
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
+ })();
3068
3209
  _moduleLoaders.set(src, load);
3069
3210
  return load;
3070
3211
  }
@@ -3082,7 +3223,7 @@ async function resolveFunction(def, state, key, base) {
3082
3223
  return noop;
3083
3224
  }
3084
3225
  let fn;
3085
- if (typeof def.body === "string") {
3226
+ if (isString2(def.body)) {
3086
3227
  const params = resolveParamNames(def);
3087
3228
  fn = new Function(...params, def.body);
3088
3229
  Object.defineProperty(fn, "name", {
@@ -3102,20 +3243,11 @@ async function resolveFunction(def, state, key, base) {
3102
3243
  } else if (seeded) {
3103
3244
  mod = seeded;
3104
3245
  } else {
3105
- if (base) {
3106
- const resolvedSrc = new URL(src, base).href;
3107
- try {
3108
- mod = await import(resolvedSrc);
3109
- } catch {
3110
- mod = await import(src);
3111
- }
3112
- } else {
3113
- mod = await import(src);
3114
- }
3246
+ mod = await importSource(src, base);
3115
3247
  _moduleCache.set(src, mod);
3116
3248
  }
3117
3249
  const candidate = mod[exportName] ?? mod.default?.[exportName];
3118
- if (typeof candidate !== "function") {
3250
+ if (!isFunction2(candidate)) {
3119
3251
  throw new TypeError(`Jx: export "${exportName}" not found or not a function in "${src}"`);
3120
3252
  }
3121
3253
  fn = candidate;
@@ -3123,11 +3255,7 @@ async function resolveFunction(def, state, key, base) {
3123
3255
  const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;
3124
3256
  let isComputed = false;
3125
3257
  if (!hasParams) {
3126
- if (typeof def.body === "string") {
3127
- isComputed = bodyReturnsValue(def.body);
3128
- } else if (fn) {
3129
- isComputed = fn.length <= 1 && bodyReturnsValue(fn.toString());
3130
- }
3258
+ isComputed = isString2(def.body) ? bodyReturnsValue(def.body) : fn.length <= 1 && bodyReturnsValue(fn.toString());
3131
3259
  }
3132
3260
  if (isComputed) {
3133
3261
  return computed(() => fn(state));
@@ -3172,6 +3300,22 @@ var RESERVED_KEYS = new Set([
3172
3300
  "cases",
3173
3301
  "observedAttributes"
3174
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
+ }
3175
3319
  var warnedRefChildren = new Set;
3176
3320
  var SVG_NS = "http://www.w3.org/2000/svg";
3177
3321
  var MATHML_NS = "http://www.w3.org/1998/Math/MathML";
@@ -3186,11 +3330,13 @@ function elementNamespace(tagName, inherited) {
3186
3330
  }
3187
3331
  function renderNode(def, state, options) {
3188
3332
  const path = options?._path ?? [];
3189
- if (typeof def === "string" || typeof def === "number" || typeof def === "boolean") {
3333
+ if (isString2(def) || isNumber(def) || isBoolean(def)) {
3190
3334
  const textNode = document.createTextNode(String(def));
3191
- if (typeof def === "string" && isTemplateString(def)) {
3192
- effect(() => {
3335
+ if (isTemplateString(def)) {
3336
+ bindTemplate(def, () => {
3193
3337
  textNode.textContent = evaluateTemplate(def, state);
3338
+ }, () => {
3339
+ textNode.textContent = "";
3194
3340
  });
3195
3341
  }
3196
3342
  return textNode;
@@ -3199,9 +3345,9 @@ function renderNode(def, state, options) {
3199
3345
  for (const [key, val] of Object.entries(def)) {
3200
3346
  if (key.startsWith("$") && !RESERVED_KEYS.has(key)) {
3201
3347
  if (localState === state) {
3202
- localState = Object.create(state);
3348
+ localState = inheritScope(state);
3203
3349
  }
3204
- localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;
3350
+ localState[key] = isRef2(val) ? resolveRef(val.$ref, state) : val;
3205
3351
  }
3206
3352
  }
3207
3353
  if ("$ref" in def && !def.tagName) {
@@ -3236,7 +3382,7 @@ function renderNode(def, state, options) {
3236
3382
  if (def.style && tagName.includes("-")) {
3237
3383
  callSiteStyles.set(el, def.style);
3238
3384
  }
3239
- applyStyle(el, def.style ?? {}, localState["$media"] ?? {}, localState);
3385
+ applyStyle(el, def.style ?? {}, scopeMedia(localState), localState);
3240
3386
  applyAttributes(el, def.attributes ?? {}, localState);
3241
3387
  const kids = def.children;
3242
3388
  if (isMappedArray(kids)) {
@@ -3272,11 +3418,10 @@ function applyProperties(el, def, state) {
3272
3418
  function bindHandler(el, key, val, state) {
3273
3419
  const type = key.slice(2);
3274
3420
  const scope = state;
3275
- if (isRefObj(val)) {
3421
+ if (isRef2(val)) {
3276
3422
  const handler = resolveRef(val.$ref, state);
3277
- if (typeof handler === "function") {
3278
- const handlerFn = handler;
3279
- el.addEventListener(type, (e) => handlerFn(scope, e));
3423
+ if (isEventHandler(handler)) {
3424
+ el.addEventListener(type, (e) => handler(scope, e));
3280
3425
  }
3281
3426
  return true;
3282
3427
  }
@@ -3287,7 +3432,7 @@ function bindHandler(el, key, val, state) {
3287
3432
  });
3288
3433
  return true;
3289
3434
  }
3290
- if (isFunctionDef(val) && typeof val.body === "string") {
3435
+ if (isFunctionDef(val) && isString2(val.body)) {
3291
3436
  const params = resolveParamNames(val);
3292
3437
  const fn = new Function(...params, val.body);
3293
3438
  el.addEventListener(type, (e) => fn(scope, e));
@@ -3308,12 +3453,12 @@ function bindDefinitionHandlers(host, def, state) {
3308
3453
  }
3309
3454
  }
3310
3455
  function bindProperty(el, key, val, state) {
3311
- const target = el;
3456
+ const target = elementProperties(el);
3312
3457
  const boundProp = boundPropKey(key, val, state);
3313
3458
  if (boundProp) {
3314
3459
  el.dataset.jxBoundProp = boundProp;
3315
3460
  }
3316
- const asAsset = (resolved) => typeof resolved === "string" ? canvasAssetValue(el.tagName, key, resolved) : resolved;
3461
+ const asAsset = (resolved) => isString2(resolved) ? canvasAssetValue(el.tagName, key, resolved) : resolved;
3317
3462
  const write = (resolved) => {
3318
3463
  const node = el;
3319
3464
  if (key === "className" && !(node instanceof HTMLElement)) {
@@ -3325,7 +3470,7 @@ function bindProperty(el, key, val, state) {
3325
3470
  }
3326
3471
  target[key] = resolved;
3327
3472
  };
3328
- if (isRefObj(val)) {
3473
+ if (isRef2(val)) {
3329
3474
  const refVal = val;
3330
3475
  if (key === "id") {
3331
3476
  target[key] = resolveRef(refVal.$ref, state);
@@ -3337,8 +3482,9 @@ function bindProperty(el, key, val, state) {
3337
3482
  return;
3338
3483
  }
3339
3484
  if (isTemplateString(val)) {
3340
- effect(() => {
3341
- write(asAsset(evaluateTemplate(val, state)));
3485
+ const template = val;
3486
+ bindTemplate(template, () => {
3487
+ write(asAsset(evaluateTemplate(template, state)));
3342
3488
  });
3343
3489
  return;
3344
3490
  }
@@ -3424,14 +3570,14 @@ function textSink(tag) {
3424
3570
  write();
3425
3571
  },
3426
3572
  text() {
3427
- return tag.textContent ?? "";
3573
+ return tag.textContent;
3428
3574
  }
3429
3575
  };
3430
3576
  }
3431
3577
  function openSink(doc) {
3432
3578
  const view = doc.defaultView;
3433
3579
  const SheetConstructor = view?.CSSStyleSheet;
3434
- if (typeof SheetConstructor === "function" && Array.isArray(doc.adoptedStyleSheets)) {
3580
+ if (isFunction2(SheetConstructor) && Array.isArray(doc.adoptedStyleSheets)) {
3435
3581
  try {
3436
3582
  const sheet = new SheetConstructor;
3437
3583
  doc.adoptedStyleSheets = [...doc.adoptedStyleSheets, sheet];
@@ -3442,9 +3588,12 @@ function openSink(doc) {
3442
3588
  }
3443
3589
  const tag = doc.createElement("style");
3444
3590
  tag.dataset.jxSheet = "";
3445
- (doc.head ?? doc.documentElement).append(tag);
3591
+ (documentHead(doc) ?? doc.documentElement).append(tag);
3446
3592
  return tag.sheet ? cssomSink(tag.sheet, () => tag.remove()) : textSink(tag);
3447
3593
  }
3594
+ function documentHead(doc) {
3595
+ return doc.head;
3596
+ }
3448
3597
  var sheetStates = new WeakMap;
3449
3598
  function sheetStateFor(doc) {
3450
3599
  const existing = sheetStates.get(doc);
@@ -3534,7 +3683,7 @@ function documentStyleText(doc = document) {
3534
3683
  `);
3535
3684
  }
3536
3685
  function declaresDisplay(style) {
3537
- return Boolean(style) && typeof style === "object" && "display" in style;
3686
+ return isNonNullObject(style) && "display" in style;
3538
3687
  }
3539
3688
  var callSiteStyles = new WeakMap;
3540
3689
  function mergeStyle(base, over) {
@@ -3544,7 +3693,7 @@ function mergeStyle(base, over) {
3544
3693
  const out = { ...base };
3545
3694
  for (const [key, value] of Object.entries(over)) {
3546
3695
  const prior = out[key];
3547
- 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;
3548
3697
  }
3549
3698
  return out;
3550
3699
  }
@@ -3556,7 +3705,7 @@ function reapplyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3556
3705
  }
3557
3706
  function applyStyleInto(el, styleDef, mediaQueries, state, live) {
3558
3707
  releaseElementStyles(el);
3559
- const doc = el.ownerDocument ?? document;
3708
+ const doc = el.ownerDocument;
3560
3709
  const sheetState = sheetStateFor(doc);
3561
3710
  const transposeSelector = (_canvasDelinkPopovers || _canvasDelinkCommands) && canvasStamped(el) ? (selector) => transposeCanvasOverlaySelector(selector, {
3562
3711
  dialog: el.tagName === "DIALOG"
@@ -3571,11 +3720,16 @@ function applyStyleInto(el, styleDef, mediaQueries, state, live) {
3571
3720
  sources.push({ name: property, value });
3572
3721
  return null;
3573
3722
  }
3574
- if (serial < 0) {
3575
- ({ serial } = sheetState);
3576
- 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}`;
3577
3732
  }
3578
- const name = `--jx-r${serial}-${indirect}`;
3579
3733
  indirect += 1;
3580
3734
  sources.push({ name, value });
3581
3735
  return `var(${name})`;
@@ -3618,7 +3772,7 @@ function applyStyleInto(el, styleDef, mediaQueries, state, live) {
3618
3772
  scope.run(() => {
3619
3773
  for (const { name, value } of sources) {
3620
3774
  effect(() => {
3621
- const resolved = isRefObj(value) ? resolveRef(value.$ref, state) : evaluateTemplate(value, state);
3775
+ const resolved = isRef2(value) ? resolveRef(value.$ref, state) : evaluateTemplate(value, state);
3622
3776
  el.style.setProperty(name, canvasStyleValue(String(resolved ?? "")));
3623
3777
  });
3624
3778
  }
@@ -3647,7 +3801,7 @@ function applyAttributes(el, attrs, state) {
3647
3801
  el.removeAttribute(attr);
3648
3802
  return;
3649
3803
  }
3650
- if (typeof resolved === "boolean") {
3804
+ if (isBoolean(resolved)) {
3651
3805
  const text = booleanAttrValue(attr, resolved);
3652
3806
  if (text === null) {
3653
3807
  el.removeAttribute(attr);
@@ -3658,10 +3812,10 @@ function applyAttributes(el, attrs, state) {
3658
3812
  }
3659
3813
  el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved)));
3660
3814
  };
3661
- if (isRefObj(v)) {
3815
+ if (isRef2(v)) {
3662
3816
  effect(() => write(resolveRef(v.$ref, state)));
3663
3817
  } else if (isTemplateString(v)) {
3664
- effect(() => write(evaluateAttrTemplate(v, state)));
3818
+ bindTemplate(v, () => write(evaluateValueTemplate(v, state)));
3665
3819
  } else {
3666
3820
  write(v);
3667
3821
  }
@@ -3672,7 +3826,7 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3672
3826
  const anchor = document.createComment("jx-array");
3673
3827
  parentEl.append(anchor);
3674
3828
  const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef, key: keyRef } = arrayDef;
3675
- const keyPointer = isRefObj(keyRef) ? keyRef.$ref : null;
3829
+ const keyPointer = isRef2(keyRef) ? keyRef.$ref : null;
3676
3830
  const instancePath = _instancePath;
3677
3831
  let warned = false;
3678
3832
  const warnOnce = (message) => {
@@ -3683,12 +3837,12 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3683
3837
  };
3684
3838
  let rows = [];
3685
3839
  const teardown = (row) => {
3686
- row.scope.stop();
3687
3840
  row.node.remove();
3841
+ row.scope.stop();
3688
3842
  };
3689
3843
  const createRow = (key, item, index) => {
3690
3844
  const map = shallowReactive({ index, item });
3691
- const child = Object.create(state);
3845
+ const child = inheritScope(state);
3692
3846
  child.$map = map;
3693
3847
  Object.defineProperty(child, "$map/item", { enumerable: true, get: () => map.item });
3694
3848
  Object.defineProperty(child, "$map/index", { enumerable: true, get: () => map.index });
@@ -3735,17 +3889,19 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3735
3889
  rows = next;
3736
3890
  };
3737
3891
  const update = () => {
3738
- let items = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
3739
- if (Array.isArray(items) && isRefObj(filterRef)) {
3892
+ let items = isRef2(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
3893
+ if (Array.isArray(items) && isRef2(filterRef)) {
3740
3894
  const fn = resolveRef(filterRef.$ref, state);
3741
- if (typeof fn === "function") {
3895
+ if (isFunction2(fn)) {
3742
3896
  items = items.filter(fn);
3743
3897
  }
3744
3898
  }
3745
- if (Array.isArray(items) && isRefObj(sortRef)) {
3899
+ if (Array.isArray(items) && isRef2(sortRef)) {
3746
3900
  const fn = resolveRef(sortRef.$ref, state);
3747
- if (typeof fn === "function") {
3748
- items = [...items].toSorted(fn);
3901
+ if (isFunction2(fn)) {
3902
+ const compare = fn;
3903
+ const unsorted = items;
3904
+ items = [...unsorted].toSorted(compare);
3749
3905
  }
3750
3906
  }
3751
3907
  const list = Array.isArray(items) && mapDef ? items : [];
@@ -3809,7 +3965,7 @@ function mappedRowKey(pointer, item, index, warnOnce) {
3809
3965
  return index;
3810
3966
  }
3811
3967
  function resolveTagName(tagName, scope) {
3812
- if (typeof tagName === "string") {
3968
+ if (isString2(tagName)) {
3813
3969
  return tagName;
3814
3970
  }
3815
3971
  if (!isTagExpression(tagName)) {
@@ -3830,7 +3986,7 @@ function renderSwitch(def, state, options) {
3830
3986
  options.onNodeCreated(container, path, def, state);
3831
3987
  }
3832
3988
  applyProperties(container, def, state);
3833
- applyStyle(container, def.style ?? {}, state["$media"] ?? {}, state);
3989
+ applyStyle(container, def.style ?? {}, scopeMedia(state), state);
3834
3990
  applyAttributes(container, def.attributes ?? {}, state);
3835
3991
  let generation = 0;
3836
3992
  let live = null;
@@ -3840,9 +3996,9 @@ function renderSwitch(def, state, options) {
3840
3996
  live = null;
3841
3997
  };
3842
3998
  effect(() => {
3843
- if (!isRefObj(def.$switch)) {
3844
- retire();
3999
+ if (!isRef2(def.$switch)) {
3845
4000
  container.replaceChildren();
4001
+ retire();
3846
4002
  generation += 1;
3847
4003
  return;
3848
4004
  }
@@ -3851,8 +4007,8 @@ function renderSwitch(def, state, options) {
3851
4007
  return;
3852
4008
  }
3853
4009
  renderedKey = key;
3854
- retire();
3855
4010
  container.replaceChildren();
4011
+ retire();
3856
4012
  generation += 1;
3857
4013
  const caseDef = def.cases?.[key];
3858
4014
  if (!caseDef) {
@@ -3862,7 +4018,7 @@ function renderSwitch(def, state, options) {
3862
4018
  const scope = effectScope(true);
3863
4019
  live = scope;
3864
4020
  const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3865
- if (isRefObj(caseDef)) {
4021
+ if (isRef2(caseDef)) {
3866
4022
  const { href } = new URL(caseDef.$ref, options?._ctx?.base ?? location.href);
3867
4023
  resolve(href, options?._ctx).then(async (doc) => {
3868
4024
  if (gen !== generation) {
@@ -3887,6 +4043,7 @@ function renderSwitch(def, state, options) {
3887
4043
  onScopeDispose(retire, true);
3888
4044
  return container;
3889
4045
  }
4046
+ var scopeRef = ref;
3890
4047
  async function resolvePrototype(def, state, key, base, ctx) {
3891
4048
  if (def.$src) {
3892
4049
  return resolveExternalPrototype(def, state, key, base);
@@ -3919,7 +4076,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3919
4076
  signal: controller.signal,
3920
4077
  ...def.headers && { headers: def.headers },
3921
4078
  ...def.body && {
3922
- body: typeof def.body === "object" ? JSON.stringify(def.body) : def.body
4079
+ body: isNonNullObject(def.body) ? JSON.stringify(def.body) : def.body
3923
4080
  }
3924
4081
  }).then((r) => r.ok ? r.json() : Promise.reject(r.statusText)).then((d) => {
3925
4082
  s.value = d;
@@ -3942,7 +4099,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3942
4099
  const p = {};
3943
4100
  for (const [k, v] of Object.entries(def)) {
3944
4101
  if (k !== "$prototype") {
3945
- 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;
3946
4103
  }
3947
4104
  }
3948
4105
  return new URLSearchParams(p).toString();
@@ -3959,7 +4116,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3959
4116
  } catch {
3960
4117
  init = def.default ?? null;
3961
4118
  }
3962
- const storageState = ref(init);
4119
+ const storageState = scopeRef(init);
3963
4120
  effect(() => {
3964
4121
  const v = storageState.value;
3965
4122
  if (v === null) {
@@ -3987,7 +4144,7 @@ async function resolvePrototype(def, state, key, base, ctx) {
3987
4144
  return raw;
3988
4145
  }
3989
4146
  };
3990
- const cookieState = ref(read() ?? def.default ?? null);
4147
+ const cookieState = scopeRef(read() ?? def.default ?? null);
3991
4148
  effect(() => {
3992
4149
  document.cookie = serializeCookie(name, cookieState.value, def);
3993
4150
  });
@@ -4045,8 +4202,9 @@ async function resolvePrototype(def, state, key, base, ctx) {
4045
4202
  return fd;
4046
4203
  }
4047
4204
  case "Blob": {
4048
- return new Blob(def.parts ?? [], {
4049
- 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"
4050
4208
  });
4051
4209
  }
4052
4210
  case "ReadableStream": {
@@ -4070,6 +4228,15 @@ var EXTERNAL_RESERVED = new Set([
4070
4228
  "arguments",
4071
4229
  "name"
4072
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
+ }
4073
4240
  async function resolveExternalPrototype(def, state, key, base) {
4074
4241
  const src = def.$src;
4075
4242
  if (!src || !src.endsWith(".class.json")) {
@@ -4086,11 +4253,11 @@ async function importAndInstantiate(def, src, exportName, base) {
4086
4253
  mod = seeded;
4087
4254
  } else {
4088
4255
  try {
4089
- mod = await import(src);
4256
+ mod = await importModule(src);
4090
4257
  } catch {
4091
4258
  if (base) {
4092
4259
  const resolvedSrc = new URL(src, base).href;
4093
- mod = await import(resolvedSrc);
4260
+ mod = await importModule(resolvedSrc);
4094
4261
  } else {
4095
4262
  throw new Error(`Failed to import "${src}"`);
4096
4263
  }
@@ -4101,27 +4268,13 @@ async function importAndInstantiate(def, src, exportName, base) {
4101
4268
  if (!ExportedClass) {
4102
4269
  throw new Error(`Jx: export "${exportName}" not found in "${src}"`);
4103
4270
  }
4104
- if (typeof ExportedClass !== "function") {
4271
+ if (!isFunction2(ExportedClass)) {
4105
4272
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a class`);
4106
4273
  }
4107
- const config = {};
4108
- for (const [k, v] of Object.entries(def)) {
4109
- if (!EXTERNAL_RESERVED.has(k)) {
4110
- config[k] = v;
4111
- }
4112
- }
4113
- const Ctor = ExportedClass;
4114
- const instance = new Ctor(config);
4115
- let value;
4116
- if (typeof instance.resolve === "function") {
4117
- value = await instance.resolve();
4118
- } else if ("value" in instance) {
4119
- ({ value } = instance);
4120
- } else {
4121
- value = instance;
4122
- }
4123
- const s = ref(value);
4124
- 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)) {
4125
4278
  instance.subscribe((newVal) => {
4126
4279
  s.value = newVal;
4127
4280
  });
@@ -4160,33 +4313,23 @@ async function resolveClassJson(def, state, key, base) {
4160
4313
  }
4161
4314
  }
4162
4315
  const DynClass = classFromSchema(classDef);
4163
- const config = {};
4164
- for (const [k, v] of Object.entries(def)) {
4165
- if (!EXTERNAL_RESERVED.has(k)) {
4166
- config[k] = v;
4167
- }
4168
- }
4169
- const instance = new DynClass(config);
4170
- let value;
4171
- if (typeof instance.resolve === "function") {
4172
- value = await instance.resolve();
4173
- } else if ("value" in instance) {
4174
- ({ value } = instance);
4175
- } else {
4176
- value = instance;
4177
- }
4178
- const s = ref(value);
4179
- 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)) {
4180
4320
  instance.subscribe((newVal) => {
4181
4321
  s.value = newVal;
4182
4322
  });
4183
4323
  }
4184
4324
  return s;
4185
4325
  }
4326
+ function isCtorDef(rawCtor) {
4327
+ return isNonNullObject(rawCtor);
4328
+ }
4186
4329
  function classFromSchema(classDef) {
4187
4330
  const fields = classDef.$defs?.fields ?? {};
4188
4331
  const rawCtor = classDef.$defs?.constructor;
4189
- const ctor = typeof rawCtor === "object" ? rawCtor : undefined;
4332
+ const ctor = isCtorDef(rawCtor) ? rawCtor : undefined;
4190
4333
  const methods = classDef.$defs?.methods ?? {};
4191
4334
 
4192
4335
  class DynClass {
@@ -4207,7 +4350,8 @@ function classFromSchema(classDef) {
4207
4350
  if (ctor?.body) {
4208
4351
  const bodyStr = Array.isArray(ctor.body) ? ctor.body.join(`
4209
4352
  `) : ctor.body;
4210
- new Function("config", bodyStr).call(this, config);
4353
+ const init = new Function("config", bodyStr);
4354
+ init.call(this, config);
4211
4355
  }
4212
4356
  }
4213
4357
  }
@@ -4215,10 +4359,10 @@ function classFromSchema(classDef) {
4215
4359
  const name = typedMethod.identifier ?? key;
4216
4360
  const params = (typedMethod.parameters ?? []).map((p) => {
4217
4361
  if (p.$ref) {
4218
- return p.$ref.split("/").pop();
4362
+ return p.$ref.split("/").pop() ?? "";
4219
4363
  }
4220
4364
  const n = p.identifier ?? p.name;
4221
- return typeof n === "string" ? n : "arg";
4365
+ return isString2(n) ? n : "arg";
4222
4366
  });
4223
4367
  const bodyStr = Array.isArray(typedMethod.body) ? typedMethod.body.join(`
4224
4368
  `) : typedMethod.body ?? "";
@@ -4245,16 +4389,10 @@ function classFromSchema(classDef) {
4245
4389
  configurable: true,
4246
4390
  value: classDef.title
4247
4391
  });
4248
- const dynCtor = DynClass;
4249
- return dynCtor;
4392
+ return DynClass;
4250
4393
  }
4251
4394
  async function resolveViaDevProxy(def, state, key, base) {
4252
- const config = {};
4253
- for (const [k, v] of Object.entries(def)) {
4254
- if (!EXTERNAL_RESERVED.has(k)) {
4255
- config[k] = v;
4256
- }
4257
- }
4395
+ const config = externalConfig(def);
4258
4396
  const hasTemplates = Object.values(config).some((v) => isTemplateString(v));
4259
4397
  const doResolve = (resolvedConfig) => fetch(resolveProxyPath("/__jx_resolve__"), {
4260
4398
  body: JSON.stringify({
@@ -4290,57 +4428,56 @@ async function resolveViaDevProxy(def, state, key, base) {
4290
4428
  }
4291
4429
  return s;
4292
4430
  }
4431
+ function latestServerCall(s, invoke, label) {
4432
+ let seq = 0;
4433
+ return (args) => {
4434
+ seq += 1;
4435
+ const n = seq;
4436
+ new Promise((settle) => {
4437
+ settle(invoke(args));
4438
+ }).then((result) => {
4439
+ if (n === seq) {
4440
+ s.value = result;
4441
+ }
4442
+ }).catch((error) => {
4443
+ if (n === seq) {
4444
+ console.error(label, error);
4445
+ }
4446
+ });
4447
+ };
4448
+ }
4293
4449
  async function resolveServerFunction(def, state, key, base) {
4294
4450
  const src = def.$src;
4295
4451
  const exportName = def.$export;
4296
- let mod;
4297
- const seeded = seededModule(src);
4298
- if (seeded instanceof Promise) {
4299
- mod = await seeded;
4300
- } else if (seeded) {
4301
- mod = seeded;
4302
- } else {
4303
- try {
4304
- mod = await import(src);
4305
- } catch {
4306
- if (base) {
4307
- try {
4308
- const resolvedSrc = new URL(src, base).href;
4309
- mod = await import(resolvedSrc);
4310
- } catch {
4311
- return resolveServerFunctionViaProxy(def, state, key, base);
4312
- }
4313
- } else {
4314
- return resolveServerFunctionViaProxy(def, state, key, base);
4315
- }
4316
- }
4317
- _moduleCache.set(src, mod);
4452
+ const seeded = _hostSeeded.has(src) ? seededModule(src) : undefined;
4453
+ if (!seeded) {
4454
+ return resolveServerFunctionViaProxy(def, state, key, base);
4318
4455
  }
4456
+ const mod = seeded instanceof Promise ? await seeded : seeded;
4319
4457
  const candidate = mod[exportName] ?? mod.default?.[exportName];
4320
4458
  if (!candidate) {
4321
4459
  throw new Error(`Jx: export "${exportName}" not found in "${src}" for "${key}"`);
4322
4460
  }
4323
- if (typeof candidate !== "function") {
4461
+ if (!isFunction2(candidate)) {
4324
4462
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a function`);
4325
4463
  }
4326
4464
  const fn = candidate;
4327
4465
  const rawArgs = def.arguments ?? {};
4328
- const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
4466
+ const hasReactiveArg = Object.values(rawArgs).some((v) => isRef2(v));
4329
4467
  const resolveArgs = () => {
4330
4468
  const args = {};
4331
4469
  for (const [k, v] of Object.entries(rawArgs)) {
4332
- args[k] = isRefObj(v) ? resolveRef(v.$ref, state) : v;
4470
+ args[k] = isRef2(v) ? resolveRef(v.$ref, state) : v;
4333
4471
  }
4334
4472
  return args;
4335
4473
  };
4336
4474
  const s = ref(null);
4337
4475
  if (hasReactiveArg) {
4476
+ const call = latestServerCall(s, fn, "Jx server function:");
4338
4477
  effect(() => {
4339
4478
  const args = resolveArgs();
4340
4479
  onEffectCleanup(() => {});
4341
- fn(args).then((result) => {
4342
- s.value = result;
4343
- }).catch(() => {});
4480
+ call(args);
4344
4481
  });
4345
4482
  } else {
4346
4483
  s.value = await fn(resolveArgs());
@@ -4349,11 +4486,11 @@ async function resolveServerFunction(def, state, key, base) {
4349
4486
  }
4350
4487
  async function resolveServerFunctionViaProxy(def, state, key, base) {
4351
4488
  const rawArgs = def.arguments ?? {};
4352
- const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
4489
+ const hasReactiveArg = Object.values(rawArgs).some((v) => isRef2(v));
4353
4490
  const resolveArgs = () => {
4354
4491
  const args = {};
4355
4492
  for (const [k, v] of Object.entries(rawArgs)) {
4356
- args[k] = isRefObj(v) ? resolveRef(v.$ref, state) : v;
4493
+ args[k] = isRef2(v) ? resolveRef(v.$ref, state) : v;
4357
4494
  }
4358
4495
  return args;
4359
4496
  };
@@ -4373,23 +4510,20 @@ async function resolveServerFunctionViaProxy(def, state, key, base) {
4373
4510
  return r.json();
4374
4511
  });
4375
4512
  const s = ref(null);
4513
+ const call = latestServerCall(s, doResolve, "Jx server proxy:");
4376
4514
  if (hasReactiveArg) {
4377
4515
  effect(() => {
4378
4516
  const args = resolveArgs();
4379
4517
  onEffectCleanup(() => {});
4380
- doResolve(args).then((result) => {
4381
- s.value = result;
4382
- }).catch((error) => console.error("Jx server proxy:", error));
4518
+ call(args);
4383
4519
  });
4384
4520
  } else {
4385
- doResolve(resolveArgs()).then((result) => {
4386
- s.value = result;
4387
- }).catch((error) => console.error("Jx server proxy:", error));
4521
+ call(resolveArgs());
4388
4522
  }
4389
4523
  return s;
4390
4524
  }
4391
4525
  function resolveRef(refPath, state) {
4392
- if (typeof refPath !== "string") {
4526
+ if (!isString2(refPath)) {
4393
4527
  return refPath;
4394
4528
  }
4395
4529
  if (refPath.startsWith("$map/") || refPath.startsWith("#/$map/")) {
@@ -4397,7 +4531,7 @@ function resolveRef(refPath, state) {
4397
4531
  const [, key] = parts;
4398
4532
  const map = state.$map;
4399
4533
  const base = map?.[key] ?? state[`$map/${key}`];
4400
- return parts.length > 2 ? getPath2(base, parts.slice(2).join("/")) : base;
4534
+ return parts.length > 2 ? readPath(base, parts.slice(2).join("/")) : base;
4401
4535
  }
4402
4536
  if (refPath.startsWith("#/state/")) {
4403
4537
  return readPath(state, refPath.slice("#/state/".length));
@@ -4406,46 +4540,39 @@ function resolveRef(refPath, state) {
4406
4540
  return readPath(state, refPath.slice("parent#/".length));
4407
4541
  }
4408
4542
  if (refPath.startsWith("window#/")) {
4409
- return getPath2(globalThis.window, refPath.slice("window#/".length));
4543
+ return readPath(globalThis.window, refPath.slice("window#/".length));
4410
4544
  }
4411
4545
  if (refPath.startsWith("document#/")) {
4412
- return getPath2(globalThis.document, refPath.slice("document#/".length));
4546
+ return readPath(globalThis.document, refPath.slice("document#/".length));
4413
4547
  }
4414
4548
  return readPath(state, refPath) ?? null;
4415
4549
  }
4416
4550
  function isSignal(v) {
4417
4551
  return isRef(v);
4418
4552
  }
4419
- function isRefObj(v) {
4420
- return isRef2(v);
4421
- }
4422
- function getPath2(obj, path) {
4423
- return readPath(obj, path);
4424
- }
4425
4553
  function absorbAttribute(state, name, value, defaults) {
4426
4554
  const camelKey = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
4427
4555
  const current = state[camelKey];
4428
- if (typeof current === "boolean") {
4556
+ if (isBoolean(current)) {
4429
4557
  state[camelKey] = value !== null && value !== "false";
4430
4558
  return;
4431
4559
  }
4432
4560
  if (value === null) {
4433
4561
  const declared = defaults?.get(camelKey);
4434
- state[camelKey] = declared === undefined ? typeof current === "number" ? 0 : "" : declared;
4562
+ state[camelKey] = declared === undefined ? isNumber(current) ? 0 : "" : declared;
4435
4563
  return;
4436
4564
  }
4437
- state[camelKey] = typeof current === "number" ? Number(value) : value;
4565
+ state[camelKey] = isNumber(current) ? Number(value) : value;
4438
4566
  }
4439
4567
  function declaredDefaults(def) {
4440
4568
  const out = new Map;
4441
4569
  for (const [key, entry] of Object.entries(def.state ?? {})) {
4442
- if (entry !== null && typeof entry === "object") {
4443
- const obj = entry;
4444
- if ("default" in obj) {
4445
- out.set(key, obj["default"]);
4570
+ if (isNonNullObject(entry)) {
4571
+ if ("default" in entry) {
4572
+ out.set(key, entry.default);
4446
4573
  continue;
4447
4574
  }
4448
- if (COMPUTED_STATE_KEYS.some((marker) => (marker in obj))) {
4575
+ if (COMPUTED_STATE_KEYS.some((marker) => (marker in entry))) {
4449
4576
  continue;
4450
4577
  }
4451
4578
  }
@@ -4465,6 +4592,15 @@ function instanceSupplies(el, key) {
4465
4592
  const kebab = key.replaceAll(/[A-Z]/gu, (c) => `-${c.toLowerCase()}`);
4466
4593
  return kebab !== key && el.hasAttribute(kebab);
4467
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
+ }
4468
4604
  function refusePrivateProp(key, where) {
4469
4605
  if (!isPrivateStateKey(key)) {
4470
4606
  return false;
@@ -4480,17 +4616,17 @@ function _resetPrivatePropWarnings() {
4480
4616
  _privatePropWarned.clear();
4481
4617
  }
4482
4618
  function mergeProps(def, parentState) {
4483
- const child = Object.create(parentState);
4619
+ const child = inheritScope(parentState);
4484
4620
  for (const [k, v] of Object.entries(def.$props ?? {})) {
4485
4621
  if (refusePrivateProp(k, "$props")) {
4486
4622
  continue;
4487
4623
  }
4488
- child[k] = isRefObj(v) ? resolveRef(v.$ref, parentState) : v;
4624
+ child[k] = isRef2(v) ? resolveRef(v.$ref, parentState) : v;
4489
4625
  }
4490
4626
  return child;
4491
4627
  }
4492
4628
  function toCSSText(rules) {
4493
- 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("; ");
4494
4630
  }
4495
4631
  var _rootMedia = {};
4496
4632
  var _elementDefs = new Map;
@@ -4522,7 +4658,7 @@ function setRootMedia(map) {
4522
4658
  }
4523
4659
  async function registerElements(elements, base, ctx) {
4524
4660
  for (const entry of elements) {
4525
- if (typeof entry === "string") {
4661
+ if (isString2(entry)) {
4526
4662
  try {
4527
4663
  const specifier = entry.startsWith("/") || entry.startsWith(".") ? entry : `/node_modules/${entry}`;
4528
4664
  await import(specifier);
@@ -4531,7 +4667,7 @@ async function registerElements(elements, base, ctx) {
4531
4667
  }
4532
4668
  continue;
4533
4669
  }
4534
- if (!isRefObj(entry)) {
4670
+ if (!isRef2(entry)) {
4535
4671
  continue;
4536
4672
  }
4537
4673
  const { href } = new URL(entry.$ref, base);
@@ -4557,7 +4693,7 @@ function injectHead(entries, _base) {
4557
4693
  const attrs = { ...entry.attributes };
4558
4694
  for (const key of ["href", "src"]) {
4559
4695
  const v = attrs[key];
4560
- if (typeof v !== "string" || v === "") {
4696
+ if (!isString2(v) || v === "") {
4561
4697
  continue;
4562
4698
  }
4563
4699
  if (!v.startsWith("/") && !v.startsWith(".") && !v.startsWith("http")) {
@@ -4575,7 +4711,7 @@ function injectHead(entries, _base) {
4575
4711
  el.setAttribute(k, String(v));
4576
4712
  }
4577
4713
  if (entry.textContent) {
4578
- 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;
4579
4715
  }
4580
4716
  document.head.append(el);
4581
4717
  }
@@ -4583,6 +4719,18 @@ function injectHead(entries, _base) {
4583
4719
  var MAX_COMPONENT_NESTING = 32;
4584
4720
  var ROOT_INSTANCE_PATH = { expansion: 0, frames: [] };
4585
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
+ }
4586
4734
  function underInstancePath(path, fn) {
4587
4735
  const was = _instancePath;
4588
4736
  _instancePath = path;
@@ -4609,7 +4757,7 @@ function samePropValue(a, b) {
4609
4757
  }
4610
4758
  }
4611
4759
  function isPlainData(value) {
4612
- if (typeof value !== "object" || value === null) {
4760
+ if (!isNonNullObject(value)) {
4613
4761
  return false;
4614
4762
  }
4615
4763
  const raw = toRaw(value);
@@ -4642,17 +4790,18 @@ function extendInstancePath(path, frame) {
4642
4790
  var _definedSources = new Set;
4643
4791
  async function defineElement(source, baseUrl) {
4644
4792
  let base = baseUrl;
4645
- let doc = source;
4646
- if (typeof source === "string") {
4793
+ let source_;
4794
+ if (isString2(source)) {
4647
4795
  base = new URL(source, base ?? location.href).href;
4648
4796
  if (_definedSources.has(base)) {
4649
4797
  return;
4650
4798
  }
4651
4799
  _definedSources.add(base);
4652
- doc = await resolve(source);
4800
+ source_ = await resolve(source);
4801
+ } else {
4802
+ source_ = source;
4653
4803
  }
4654
4804
  base ??= location.href;
4655
- const source_ = doc;
4656
4805
  const { tagName } = source_;
4657
4806
  if (!tagName || !tagName.includes("-")) {
4658
4807
  throw new Error(`Jx defineElement: tagName "${tagName}" must contain a hyphen`);
@@ -4697,7 +4846,8 @@ async function defineElement(source, baseUrl) {
4697
4846
  if (propsAttr) {
4698
4847
  try {
4699
4848
  const props = JSON.parse(propsAttr);
4700
- 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) {
4701
4851
  if (refusePrivateProp(key, "data-jx-props")) {
4702
4852
  continue;
4703
4853
  }
@@ -4726,9 +4876,10 @@ async function defineElement(source, baseUrl) {
4726
4876
  if (isPrivateStateKey(key)) {
4727
4877
  continue;
4728
4878
  }
4729
- if (key in this && this[key] !== undefined && instanceSupplies(this, key)) {
4730
- state[key] = this[key];
4731
- 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];
4732
4883
  }
4733
4884
  }
4734
4885
  let ownPath;
@@ -4736,69 +4887,117 @@ async function defineElement(source, baseUrl) {
4736
4887
  ownPath = extendInstancePath(enclosingPath, { props: supplied, tag: tagName });
4737
4888
  } catch (error) {
4738
4889
  this.replaceChildren();
4739
- if (!this.isConnected) {
4740
- return;
4741
- }
4742
- console.error(`Jx: <${tagName}> was not rendered:`, error);
4743
- this.dispatchEvent(new ErrorEvent("jx-error", {
4744
- bubbles: true,
4745
- composed: true,
4746
- error,
4747
- message: error instanceof Error ? error.message : String(error)
4748
- }));
4890
+ reportUnrendered(this, tagName, error instanceof Error ? error : new Error(String(error)));
4749
4891
  return;
4750
4892
  }
4751
4893
  for (const key of Object.keys(def.state ?? {})) {
4752
4894
  if (isPrivateStateKey(key)) {
4753
4895
  continue;
4754
4896
  }
4755
- if (!(key in HTMLElement.prototype)) {
4756
- Object.defineProperty(this, key, {
4757
- configurable: true,
4758
- get: () => state[key],
4759
- set: (v) => {
4760
- state[key] = v;
4761
- }
4762
- });
4763
- }
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
+ });
4764
4906
  }
4765
4907
  this._state = state;
4766
- const slottedChildren = [...this.childNodes];
4908
+ const slottedChildren = captureSlotted(this);
4767
4909
  this.replaceChildren();
4768
- 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 };
4769
4912
  const hostStyle = mergeStyle(defStyle, callSiteStyles.get(this));
4770
- applyStyle(this, hostStyle, state["$media"] ?? {}, state);
4913
+ applyStyle(this, hostStyle, scopeMedia(state), state);
4771
4914
  applyAttributes(this, def.attributes ?? {}, state);
4772
4915
  bindDefinitionHandlers(this, def, state);
4773
4916
  if (!Array.isArray(def.children) && def.textContent !== undefined) {
4774
4917
  bindProperty(this, "textContent", def.textContent, state);
4775
4918
  }
4776
4919
  const children = Array.isArray(def.children) ? def.children : [];
4777
- const wasInside = _canvasInsideStampedHost;
4778
- _canvasInsideStampedHost ||= this.dataset.jxPath !== undefined;
4779
- try {
4780
- underInstancePath(ownPath, () => {
4781
- for (const childDef of children) {
4782
- this.append(renderNode(childDef, state));
4783
- }
4784
- });
4785
- } finally {
4786
- _canvasInsideStampedHost = wasInside;
4787
- }
4788
- distributeSlots(this, slottedChildren);
4789
- const { onMount } = state;
4790
- if (typeof onMount === "function") {
4791
- 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;
4792
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
+ });
4793
4990
  }
4794
4991
  disconnectedCallback() {
4795
- if (typeof this._state?.onUnmount === "function") {
4796
- this._state.onUnmount(this._state);
4992
+ const state = this._state;
4993
+ if (state && isScopeHook(state.onUnmount)) {
4994
+ state.onUnmount(state);
4797
4995
  }
4798
4996
  }
4799
4997
  adoptedCallback() {
4800
- if (typeof this._state?.onAdopted === "function") {
4801
- this._state.onAdopted(this._state);
4998
+ const state = this._state;
4999
+ if (state && isScopeHook(state.onAdopted)) {
5000
+ state.onAdopted(state);
4802
5001
  }
4803
5002
  }
4804
5003
  attributeChangedCallback(name, oldVal, newVal) {
@@ -4820,16 +5019,21 @@ function renderCustomElementWithProps(def, state, options, path) {
4820
5019
  continue;
4821
5020
  }
4822
5021
  const write = (resolved) => {
4823
- 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
+ }
4824
5028
  };
4825
- if (isRefObj(val)) {
5029
+ if (isRef2(val)) {
4826
5030
  const refVal = val;
4827
5031
  write(resolveRef(refVal.$ref, state));
4828
5032
  effect(() => {
4829
5033
  write(resolveRef(refVal.$ref, state));
4830
5034
  });
4831
5035
  } else if (isTemplateString(val)) {
4832
- effect(() => {
5036
+ bindTemplate(val, () => {
4833
5037
  write(evaluateTemplate(val, state));
4834
5038
  });
4835
5039
  } else {
@@ -4839,7 +5043,7 @@ function renderCustomElementWithProps(def, state, options, path) {
4839
5043
  if (def.style) {
4840
5044
  callSiteStyles.set(el, def.style);
4841
5045
  }
4842
- applyStyle(el, def.style ?? {}, state["$media"] ?? {}, state);
5046
+ applyStyle(el, def.style ?? {}, scopeMedia(state), state);
4843
5047
  applyAttributes(el, def.attributes ?? {}, state);
4844
5048
  applyProperties(el, def, state);
4845
5049
  const children = Array.isArray(def.children) ? def.children : [];
@@ -4854,28 +5058,93 @@ function renderCustomElementWithProps(def, state, options, path) {
4854
5058
  }
4855
5059
  return el;
4856
5060
  }
4857
- function distributeSlots(host, slottedChildren) {
4858
- 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")];
4859
5113
  if (slots.length === 0) {
4860
5114
  return;
4861
5115
  }
4862
- const named = new Map;
4863
- const unnamed = [];
4864
- for (const child of slottedChildren) {
4865
- if (child.nodeType === Node.ELEMENT_NODE && child.getAttribute("slot")) {
4866
- const name = child.getAttribute("slot");
4867
- if (!named.has(name)) {
4868
- named.set(name, []);
4869
- }
4870
- named.get(name).push(child);
4871
- } else {
4872
- 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;
4873
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);
5128
+ }
5129
+ group.push(n);
4874
5130
  }
5131
+ const taken = new Set;
4875
5132
  for (const slot of slots) {
4876
- const name = slot.getAttribute("name");
4877
- const matches = name ? named.get(name) ?? [] : unnamed;
4878
- 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);
4879
5148
  }
4880
5149
  }
4881
5150
  export {
@@ -4884,6 +5153,10 @@ export {
4884
5153
  Jx,
4885
5154
  MAX_COMPONENT_NESTING,
4886
5155
  RESERVED_KEYS,
5156
+ SLOT_ATTR,
5157
+ SLOT_MARK,
5158
+ SLOT_RECORD_KEY,
5159
+ SLOT_WHITESPACE,
4887
5160
  SUPPORTED_SCHEMA_VERSION,
4888
5161
  _resetPrivatePropWarnings,
4889
5162
  applyStyle,
@@ -4892,9 +5165,11 @@ export {
4892
5165
  buildStyleRules,
4893
5166
  camelToKebab,
4894
5167
  canvasStyleValue,
5168
+ captureSlotted,
4895
5169
  cssPropertyName,
4896
5170
  cssRuleText,
4897
5171
  defineElement,
5172
+ distributeSlots,
4898
5173
  documentStyleText,
4899
5174
  elementDefinition,
4900
5175
  enumeratedAttrNames,
@@ -4928,12 +5203,13 @@ export {
4928
5203
  setCanvasDelinkCommands,
4929
5204
  setCanvasDelinkPopovers,
4930
5205
  setCanvasViewportTranspose,
5206
+ setNpmModuleResolver,
4931
5207
  setResolveToken,
4932
5208
  setRootMedia,
4933
5209
  setSkipAutoRequests,
4934
- setSkipContentResolution,
4935
5210
  setSkipServerFunctions,
4936
5211
  setStampPropBindings,
5212
+ setTemplateErrorHandler,
4937
5213
  splitSelectorList,
4938
5214
  toCSSText,
4939
5215
  transposeCanvasOverlaySelector,
@@ -4941,5 +5217,5 @@ export {
4941
5217
  transposeCanvasUnits
4942
5218
  };
4943
5219
 
4944
- //# debugId=AA34AE79F7363B3164756E2164756E21
5220
+ //# debugId=F9E5ED7079B70E8764756E2164756E21
4945
5221
  //# sourceMappingURL=runtime.js.map