@getforma/core 1.1.0 → 1.3.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.
Files changed (45) hide show
  1. package/dist/{chunk-MIOMT2CB.js → chunk-AJP4OVCN.js} +29 -9
  2. package/dist/chunk-AJP4OVCN.js.map +1 -0
  3. package/dist/{chunk-XLVBYXOU.js → chunk-ETPJTPYD.js} +6 -3
  4. package/dist/chunk-ETPJTPYD.js.map +1 -0
  5. package/dist/{chunk-JRQNDXX7.cjs → chunk-FBM7V4NE.cjs} +68 -47
  6. package/dist/chunk-FBM7V4NE.cjs.map +1 -0
  7. package/dist/{chunk-W7OUWVRA.cjs → chunk-H7MDUHS5.cjs} +6 -2
  8. package/dist/chunk-H7MDUHS5.cjs.map +1 -0
  9. package/dist/{chunk-2Y5US35K.cjs → chunk-KUXNZ5MG.cjs} +12 -12
  10. package/dist/{chunk-2Y5US35K.cjs.map → chunk-KUXNZ5MG.cjs.map} +1 -1
  11. package/dist/{chunk-INNOI6TG.js → chunk-Y3A2EVVS.js} +3 -3
  12. package/dist/{chunk-INNOI6TG.js.map → chunk-Y3A2EVVS.js.map} +1 -1
  13. package/dist/forma-runtime-csp.js +178 -79
  14. package/dist/forma-runtime.js +178 -79
  15. package/dist/formajs-runtime-hardened.global.js +178 -79
  16. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  17. package/dist/formajs-runtime.global.js +178 -79
  18. package/dist/formajs-runtime.global.js.map +1 -1
  19. package/dist/formajs.global.js +245 -61
  20. package/dist/formajs.global.js.map +1 -1
  21. package/dist/http.cjs +11 -11
  22. package/dist/http.js +2 -2
  23. package/dist/index.cjs +307 -143
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +34 -2
  26. package/dist/index.d.ts +34 -2
  27. package/dist/index.js +248 -88
  28. package/dist/index.js.map +1 -1
  29. package/dist/runtime-hardened.cjs +178 -79
  30. package/dist/runtime-hardened.cjs.map +1 -1
  31. package/dist/runtime-hardened.js +178 -79
  32. package/dist/runtime-hardened.js.map +1 -1
  33. package/dist/runtime.cjs +198 -103
  34. package/dist/runtime.cjs.map +1 -1
  35. package/dist/runtime.js +174 -79
  36. package/dist/runtime.js.map +1 -1
  37. package/dist/server.cjs +7 -7
  38. package/dist/server.js +2 -2
  39. package/dist/tc39-compat.cjs +3 -3
  40. package/dist/tc39-compat.js +1 -1
  41. package/package.json +1 -1
  42. package/dist/chunk-JRQNDXX7.cjs.map +0 -1
  43. package/dist/chunk-MIOMT2CB.js.map +0 -1
  44. package/dist/chunk-W7OUWVRA.cjs.map +0 -1
  45. package/dist/chunk-XLVBYXOU.js.map +0 -1
package/dist/runtime.js CHANGED
@@ -1,7 +1,7 @@
1
- import { reconcileList } from './chunk-MIOMT2CB.js';
1
+ import { reconcileList } from './chunk-AJP4OVCN.js';
2
2
  import { isEventHandlerAttr, isUrlAttr, isDangerousUrl } from './chunk-2QQBKQIF.js';
3
- import { internalEffect, batch } from './chunk-INNOI6TG.js';
4
- import { createSignal, createComputed } from './chunk-XLVBYXOU.js';
3
+ import { internalEffect, batch } from './chunk-Y3A2EVVS.js';
4
+ import { createSignal, createComputed } from './chunk-ETPJTPYD.js';
5
5
 
6
6
  // src/dom/reconcile.ts
7
7
  function getBindTargets(el) {
@@ -273,12 +273,12 @@ function findInsertionPoint(parent, newChild, newChildren) {
273
273
  return null;
274
274
  }
275
275
  function createReconciler(config) {
276
- let _lastHtml = "";
276
+ const lastHtmlByContainer = /* @__PURE__ */ new WeakMap();
277
277
  return function reconcile2(container, html) {
278
278
  const trimmed = html.trim();
279
279
  if (!trimmed) return;
280
- if (trimmed === _lastHtml && container.hasChildNodes()) return;
281
- _lastHtml = trimmed;
280
+ if (lastHtmlByContainer.get(container) === trimmed && container.hasChildNodes()) return;
281
+ lastHtmlByContainer.set(container, trimmed);
282
282
  config.disconnectObserver();
283
283
  try {
284
284
  if (!container.hasChildNodes() || container.children.length === 0) {
@@ -569,9 +569,97 @@ var RE_TERNARY = /^(.+?)\s*\?\s*(.+?)\s*:\s*(.+)$/;
569
569
  var RE_NULLISH = /^(.+?)\s*\?\?\s*(.+)$/;
570
570
  var RE_AND = /^(.+?)\s*&&\s*(.+)$/;
571
571
  var RE_OR = /^(.+?)\s*\|\|\s*(.+)$/;
572
- var RE_COMPARISON = /^(.+?)\s*(===|!==|==|!=|>=|<=|>|<)\s*(.+)$/;
573
- var RE_MUL = /^(.+?)\s*([*/%])\s*(.+)$/;
574
- var RE_ADD = /^(.+?)\s*([+-])\s*(.+)$/;
572
+ var UNARY_PRECEDERS = "+-*/%<>=!&|^~(,[{?:";
573
+ function matchBinaryOp(expr, ops) {
574
+ const SQ = String.fromCharCode(39);
575
+ const DQ = String.fromCharCode(34);
576
+ const BT = String.fromCharCode(96);
577
+ const BS = String.fromCharCode(92);
578
+ let depth = 0;
579
+ let inSingle = false, inDouble = false, inTemplate = false, escaped = false;
580
+ let prevSig = "";
581
+ let bestIdx = -1;
582
+ let bestOp = "";
583
+ for (let i = 0; i < expr.length; i++) {
584
+ const ch = expr[i];
585
+ if (escaped) {
586
+ escaped = false;
587
+ continue;
588
+ }
589
+ if (ch === BS && (inSingle || inDouble || inTemplate)) {
590
+ escaped = true;
591
+ continue;
592
+ }
593
+ if (inSingle) {
594
+ if (ch === SQ) {
595
+ inSingle = false;
596
+ prevSig = DQ;
597
+ }
598
+ continue;
599
+ }
600
+ if (inDouble) {
601
+ if (ch === DQ) {
602
+ inDouble = false;
603
+ prevSig = DQ;
604
+ }
605
+ continue;
606
+ }
607
+ if (inTemplate) {
608
+ if (ch === BT) {
609
+ inTemplate = false;
610
+ prevSig = DQ;
611
+ }
612
+ continue;
613
+ }
614
+ if (ch === SQ) {
615
+ inSingle = true;
616
+ continue;
617
+ }
618
+ if (ch === DQ) {
619
+ inDouble = true;
620
+ continue;
621
+ }
622
+ if (ch === BT) {
623
+ inTemplate = true;
624
+ continue;
625
+ }
626
+ if (ch === "(" || ch === "[" || ch === "{") {
627
+ depth++;
628
+ prevSig = ch;
629
+ continue;
630
+ }
631
+ if (ch === ")" || ch === "]" || ch === "}") {
632
+ if (depth > 0) depth--;
633
+ prevSig = ch;
634
+ continue;
635
+ }
636
+ if (depth !== 0) continue;
637
+ if (ch === " " || ch === " " || ch === "\n") continue;
638
+ if (i > 0) {
639
+ let matchedOp = "";
640
+ for (const op of ops) {
641
+ if (expr.startsWith(op, i)) {
642
+ matchedOp = op;
643
+ break;
644
+ }
645
+ }
646
+ if (matchedOp) {
647
+ const isPlusMinus = matchedOp === "+" || matchedOp === "-";
648
+ const unary = isPlusMinus && (prevSig === "" || UNARY_PRECEDERS.includes(prevSig));
649
+ if (!unary) {
650
+ bestIdx = i;
651
+ bestOp = matchedOp;
652
+ }
653
+ i += matchedOp.length - 1;
654
+ prevSig = matchedOp[matchedOp.length - 1];
655
+ continue;
656
+ }
657
+ }
658
+ prevSig = ch;
659
+ }
660
+ if (bestIdx === -1) return null;
661
+ return { left: expr.slice(0, bestIdx).trim(), op: bestOp, right: expr.slice(bestIdx + bestOp.length).trim() };
662
+ }
575
663
  var RE_TEMPLATE_LIT = /^`([^`]*)`$/;
576
664
  var RE_TEMPLATE_INTERP = /\$\{([^}]+)\}/g;
577
665
  var RE_GROUP_METHOD_CALL = /^\((.+)\)\.(\w+)\((.*)\)$/;
@@ -1566,12 +1654,12 @@ function parseExpressionUncached(expr, scope) {
1566
1654
  return () => left() && right();
1567
1655
  }
1568
1656
  }
1569
- const compMatch = expr.match(RE_COMPARISON);
1657
+ const compMatch = matchBinaryOp(expr, ["===", "!==", "==", "!=", ">=", "<=", ">", "<"]);
1570
1658
  if (compMatch) {
1571
- const left = parseExpression(compMatch[1].trim(), scope);
1572
- const right = parseExpression(compMatch[3].trim(), scope);
1659
+ const left = parseExpression(compMatch.left, scope);
1660
+ const right = parseExpression(compMatch.right, scope);
1573
1661
  if (left && right) {
1574
- const op = compMatch[2];
1662
+ const op = compMatch.op;
1575
1663
  return () => {
1576
1664
  const l = left(), r = right();
1577
1665
  switch (op) {
@@ -1595,12 +1683,12 @@ function parseExpressionUncached(expr, scope) {
1595
1683
  };
1596
1684
  }
1597
1685
  }
1598
- const addMatch = expr.match(RE_ADD);
1686
+ const addMatch = matchBinaryOp(expr, ["+", "-"]);
1599
1687
  if (addMatch) {
1600
- const left = parseExpression(addMatch[1].trim(), scope);
1601
- const right = parseExpression(addMatch[3].trim(), scope);
1688
+ const left = parseExpression(addMatch.left, scope);
1689
+ const right = parseExpression(addMatch.right, scope);
1602
1690
  if (left && right) {
1603
- const op = addMatch[2];
1691
+ const op = addMatch.op;
1604
1692
  return () => {
1605
1693
  const l = left(), r = right();
1606
1694
  if (op === "+") return l + r;
@@ -1608,12 +1696,12 @@ function parseExpressionUncached(expr, scope) {
1608
1696
  };
1609
1697
  }
1610
1698
  }
1611
- const mulMatch = expr.match(RE_MUL);
1699
+ const mulMatch = matchBinaryOp(expr, ["*", "/", "%"]);
1612
1700
  if (mulMatch) {
1613
- const left = parseExpression(mulMatch[1].trim(), scope);
1614
- const right = parseExpression(mulMatch[3].trim(), scope);
1701
+ const left = parseExpression(mulMatch.left, scope);
1702
+ const right = parseExpression(mulMatch.right, scope);
1615
1703
  if (left && right) {
1616
- const op = mulMatch[2];
1704
+ const op = mulMatch.op;
1617
1705
  return () => {
1618
1706
  const l = left(), r = right();
1619
1707
  switch (op) {
@@ -2108,25 +2196,61 @@ function bindElement(el, scope, disposers) {
2108
2196
  const modelExpr = !known || known.has("data-model") ? el.getAttribute("data-model") : null;
2109
2197
  if (modelExpr) {
2110
2198
  const prop = modelExpr.replace(RE_STRIP_BRACES, "").trim();
2111
- const getter = scope.getters[prop];
2112
- const setter = scope.setters[prop];
2199
+ let getter = scope.getters[prop];
2200
+ let setter = scope.setters[prop];
2201
+ if ((!getter || !setter) && prop.includes(".")) {
2202
+ getter = buildEvaluator(prop, scope);
2203
+ const lastDot = prop.lastIndexOf(".");
2204
+ const basePath = prop.slice(0, lastDot);
2205
+ const key = prop.slice(lastDot + 1);
2206
+ const baseGet = buildEvaluator(basePath, scope);
2207
+ setter = (v) => {
2208
+ const base = baseGet();
2209
+ if (base != null && typeof base === "object") base[key] = v;
2210
+ };
2211
+ }
2113
2212
  if (getter && setter) {
2114
2213
  const input = el;
2214
+ const tag = input.tagName;
2115
2215
  const dispose = internalEffect(() => {
2116
2216
  const val = getter();
2117
- if (input.type === "checkbox") {
2217
+ const type = input.type;
2218
+ if (type === "checkbox") {
2118
2219
  input.checked = !!val;
2220
+ const indetExpr = el.getAttribute("data-model-indeterminate");
2221
+ if (indetExpr) {
2222
+ const indetGetter = scope.getters[indetExpr.replace(RE_STRIP_BRACES, "").trim()];
2223
+ if (indetGetter) input.indeterminate = !!indetGetter();
2224
+ }
2225
+ } else if (type === "radio") {
2226
+ input.checked = String(val) === input.value;
2227
+ } else if (tag === "SELECT" && input.multiple) {
2228
+ const sel = input;
2229
+ const arr = Array.isArray(val) ? val.map(String) : [];
2230
+ for (const opt of Array.from(sel.options)) opt.selected = arr.includes(opt.value);
2119
2231
  } else {
2120
2232
  input.value = String(val ?? "");
2121
2233
  }
2122
2234
  });
2123
2235
  disposers.push(dispose);
2124
- const event = input.type === "checkbox" ? "change" : "input";
2236
+ const event = input.type === "checkbox" || input.type === "radio" || tag === "SELECT" ? "change" : "input";
2125
2237
  const onModelInput = () => {
2126
- if (input.type === "checkbox") {
2238
+ const type = input.type;
2239
+ if (type === "checkbox") {
2127
2240
  setter(input.checked);
2128
- } else if (input.type === "number" || input.type === "range") {
2129
- setter(Number(input.value));
2241
+ } else if (type === "radio") {
2242
+ if (input.checked) setter(input.value);
2243
+ } else if (tag === "SELECT" && input.multiple) {
2244
+ const sel = input;
2245
+ setter(Array.from(sel.selectedOptions).map((o) => o.value));
2246
+ } else if (type === "number" || type === "range") {
2247
+ const raw = input.value;
2248
+ if (raw === "") {
2249
+ setter(null);
2250
+ } else {
2251
+ const n = Number(raw);
2252
+ if (!Number.isNaN(n)) setter(n);
2253
+ }
2130
2254
  } else {
2131
2255
  setter(input.value);
2132
2256
  }
@@ -2318,59 +2442,30 @@ function bindElement(el, scope, disposers) {
2318
2442
  }
2319
2443
  }
2320
2444
  const prevNodes = new Set(oldNodes);
2321
- if (keyProp) {
2322
- const result = reconcileList(
2323
- el,
2324
- oldItems,
2325
- rawItems,
2326
- oldNodes,
2327
- (item) => String(item?.[keyProp] ?? ""),
2328
- (item) => {
2329
- const idx = rawItems.indexOf(item);
2330
- return createBoundClone2(item, idx);
2331
- },
2332
- (node, item) => {
2333
- const idx = rawItems.indexOf(item);
2334
- updateBoundClone2(node, item, idx);
2335
- },
2336
- void 0,
2337
- // beforeNode
2338
- listHooks
2339
- );
2340
- const nextNodes = new Set(result.nodes);
2341
- for (const n of prevNodes) {
2342
- if (!nextNodes.has(n)) {
2343
- if (n.hasAttribute?.("data-forma-leaving")) continue;
2344
- disposeCloneBindings2(n);
2345
- }
2346
- }
2347
- oldItems = result.items;
2348
- oldNodes = result.nodes;
2349
- } else {
2350
- const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
2351
- const oldWrapped = oldItems;
2352
- const result = reconcileList(
2353
- el,
2354
- oldWrapped,
2355
- wrapped,
2356
- oldNodes,
2357
- (w) => w.__idx,
2358
- (w) => createBoundClone2(w.__item, w.__idx),
2359
- (node, w) => updateBoundClone2(node, w.__item, w.__idx),
2360
- void 0,
2361
- // beforeNode
2362
- listHooks
2363
- );
2364
- const nextNodes = new Set(result.nodes);
2365
- for (const n of prevNodes) {
2366
- if (!nextNodes.has(n)) {
2367
- if (n.hasAttribute?.("data-forma-leaving")) continue;
2368
- disposeCloneBindings2(n);
2369
- }
2445
+ const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
2446
+ const oldWrapped = oldItems;
2447
+ const keyFn = keyProp ? (w) => String(w.__item?.[keyProp] ?? "") : (w) => w.__idx;
2448
+ const result = reconcileList(
2449
+ el,
2450
+ oldWrapped,
2451
+ wrapped,
2452
+ oldNodes,
2453
+ keyFn,
2454
+ (w) => createBoundClone2(w.__item, w.__idx),
2455
+ (node, w) => updateBoundClone2(node, w.__item, w.__idx),
2456
+ void 0,
2457
+ // beforeNode
2458
+ listHooks
2459
+ );
2460
+ const nextNodes = new Set(result.nodes);
2461
+ for (const n of prevNodes) {
2462
+ if (!nextNodes.has(n)) {
2463
+ if (n.hasAttribute?.("data-forma-leaving")) continue;
2464
+ disposeCloneBindings2(n);
2370
2465
  }
2371
- oldItems = result.items;
2372
- oldNodes = result.nodes;
2373
2466
  }
2467
+ oldItems = result.items;
2468
+ oldNodes = result.nodes;
2374
2469
  });
2375
2470
  disposers.push(dispose);
2376
2471
  }