@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.
- package/dist/{chunk-MIOMT2CB.js → chunk-AJP4OVCN.js} +29 -9
- package/dist/chunk-AJP4OVCN.js.map +1 -0
- package/dist/{chunk-XLVBYXOU.js → chunk-ETPJTPYD.js} +6 -3
- package/dist/chunk-ETPJTPYD.js.map +1 -0
- package/dist/{chunk-JRQNDXX7.cjs → chunk-FBM7V4NE.cjs} +68 -47
- package/dist/chunk-FBM7V4NE.cjs.map +1 -0
- package/dist/{chunk-W7OUWVRA.cjs → chunk-H7MDUHS5.cjs} +6 -2
- package/dist/chunk-H7MDUHS5.cjs.map +1 -0
- package/dist/{chunk-2Y5US35K.cjs → chunk-KUXNZ5MG.cjs} +12 -12
- package/dist/{chunk-2Y5US35K.cjs.map → chunk-KUXNZ5MG.cjs.map} +1 -1
- package/dist/{chunk-INNOI6TG.js → chunk-Y3A2EVVS.js} +3 -3
- package/dist/{chunk-INNOI6TG.js.map → chunk-Y3A2EVVS.js.map} +1 -1
- package/dist/forma-runtime-csp.js +178 -79
- package/dist/forma-runtime.js +178 -79
- package/dist/formajs-runtime-hardened.global.js +178 -79
- package/dist/formajs-runtime-hardened.global.js.map +1 -1
- package/dist/formajs-runtime.global.js +178 -79
- package/dist/formajs-runtime.global.js.map +1 -1
- package/dist/formajs.global.js +245 -61
- package/dist/formajs.global.js.map +1 -1
- package/dist/http.cjs +11 -11
- package/dist/http.js +2 -2
- package/dist/index.cjs +307 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -2
- package/dist/index.d.ts +34 -2
- package/dist/index.js +248 -88
- package/dist/index.js.map +1 -1
- package/dist/runtime-hardened.cjs +178 -79
- package/dist/runtime-hardened.cjs.map +1 -1
- package/dist/runtime-hardened.js +178 -79
- package/dist/runtime-hardened.js.map +1 -1
- package/dist/runtime.cjs +198 -103
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +174 -79
- package/dist/runtime.js.map +1 -1
- package/dist/server.cjs +7 -7
- package/dist/server.js +2 -2
- package/dist/tc39-compat.cjs +3 -3
- package/dist/tc39-compat.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-JRQNDXX7.cjs.map +0 -1
- package/dist/chunk-MIOMT2CB.js.map +0 -1
- package/dist/chunk-W7OUWVRA.cjs.map +0 -1
- package/dist/chunk-XLVBYXOU.js.map +0 -1
|
@@ -679,14 +679,18 @@ var FormaRuntime = (function (exports) {
|
|
|
679
679
|
}
|
|
680
680
|
const oldKeyMap = /* @__PURE__ */ new Map();
|
|
681
681
|
for (let i = 0; i < oldLen; i++) {
|
|
682
|
-
|
|
682
|
+
const k = keyFn(oldItems[i]);
|
|
683
|
+
const bucket = oldKeyMap.get(k);
|
|
684
|
+
if (bucket) bucket.push(i);
|
|
685
|
+
else oldKeyMap.set(k, [i]);
|
|
683
686
|
}
|
|
684
687
|
const oldIndices = new Array(newLen);
|
|
685
688
|
const oldUsed = new Uint8Array(oldLen);
|
|
686
689
|
for (let i = 0; i < newLen; i++) {
|
|
687
690
|
const key = keyFn(newItems[i]);
|
|
688
|
-
const
|
|
689
|
-
if (
|
|
691
|
+
const bucket = oldKeyMap.get(key);
|
|
692
|
+
if (bucket && bucket.length > 0) {
|
|
693
|
+
const oldIdx = bucket.shift();
|
|
690
694
|
oldIndices[i] = oldIdx;
|
|
691
695
|
oldUsed[oldIdx] = 1;
|
|
692
696
|
} else {
|
|
@@ -1035,12 +1039,12 @@ var FormaRuntime = (function (exports) {
|
|
|
1035
1039
|
return null;
|
|
1036
1040
|
}
|
|
1037
1041
|
function createReconciler(config) {
|
|
1038
|
-
|
|
1042
|
+
const lastHtmlByContainer = /* @__PURE__ */ new WeakMap();
|
|
1039
1043
|
return function reconcile2(container, html) {
|
|
1040
1044
|
const trimmed = html.trim();
|
|
1041
1045
|
if (!trimmed) return;
|
|
1042
|
-
if (
|
|
1043
|
-
|
|
1046
|
+
if (lastHtmlByContainer.get(container) === trimmed && container.hasChildNodes()) return;
|
|
1047
|
+
lastHtmlByContainer.set(container, trimmed);
|
|
1044
1048
|
config.disconnectObserver();
|
|
1045
1049
|
try {
|
|
1046
1050
|
if (!container.hasChildNodes() || container.children.length === 0) {
|
|
@@ -1354,9 +1358,97 @@ var FormaRuntime = (function (exports) {
|
|
|
1354
1358
|
var RE_NULLISH = /^(.+?)\s*\?\?\s*(.+)$/;
|
|
1355
1359
|
var RE_AND = /^(.+?)\s*&&\s*(.+)$/;
|
|
1356
1360
|
var RE_OR = /^(.+?)\s*\|\|\s*(.+)$/;
|
|
1357
|
-
var
|
|
1358
|
-
|
|
1359
|
-
|
|
1361
|
+
var UNARY_PRECEDERS = "+-*/%<>=!&|^~(,[{?:";
|
|
1362
|
+
function matchBinaryOp(expr, ops) {
|
|
1363
|
+
const SQ = String.fromCharCode(39);
|
|
1364
|
+
const DQ = String.fromCharCode(34);
|
|
1365
|
+
const BT = String.fromCharCode(96);
|
|
1366
|
+
const BS = String.fromCharCode(92);
|
|
1367
|
+
let depth = 0;
|
|
1368
|
+
let inSingle = false, inDouble = false, inTemplate = false, escaped = false;
|
|
1369
|
+
let prevSig = "";
|
|
1370
|
+
let bestIdx = -1;
|
|
1371
|
+
let bestOp = "";
|
|
1372
|
+
for (let i = 0; i < expr.length; i++) {
|
|
1373
|
+
const ch = expr[i];
|
|
1374
|
+
if (escaped) {
|
|
1375
|
+
escaped = false;
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1378
|
+
if (ch === BS && (inSingle || inDouble || inTemplate)) {
|
|
1379
|
+
escaped = true;
|
|
1380
|
+
continue;
|
|
1381
|
+
}
|
|
1382
|
+
if (inSingle) {
|
|
1383
|
+
if (ch === SQ) {
|
|
1384
|
+
inSingle = false;
|
|
1385
|
+
prevSig = DQ;
|
|
1386
|
+
}
|
|
1387
|
+
continue;
|
|
1388
|
+
}
|
|
1389
|
+
if (inDouble) {
|
|
1390
|
+
if (ch === DQ) {
|
|
1391
|
+
inDouble = false;
|
|
1392
|
+
prevSig = DQ;
|
|
1393
|
+
}
|
|
1394
|
+
continue;
|
|
1395
|
+
}
|
|
1396
|
+
if (inTemplate) {
|
|
1397
|
+
if (ch === BT) {
|
|
1398
|
+
inTemplate = false;
|
|
1399
|
+
prevSig = DQ;
|
|
1400
|
+
}
|
|
1401
|
+
continue;
|
|
1402
|
+
}
|
|
1403
|
+
if (ch === SQ) {
|
|
1404
|
+
inSingle = true;
|
|
1405
|
+
continue;
|
|
1406
|
+
}
|
|
1407
|
+
if (ch === DQ) {
|
|
1408
|
+
inDouble = true;
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1411
|
+
if (ch === BT) {
|
|
1412
|
+
inTemplate = true;
|
|
1413
|
+
continue;
|
|
1414
|
+
}
|
|
1415
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
1416
|
+
depth++;
|
|
1417
|
+
prevSig = ch;
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1420
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
1421
|
+
if (depth > 0) depth--;
|
|
1422
|
+
prevSig = ch;
|
|
1423
|
+
continue;
|
|
1424
|
+
}
|
|
1425
|
+
if (depth !== 0) continue;
|
|
1426
|
+
if (ch === " " || ch === " " || ch === "\n") continue;
|
|
1427
|
+
if (i > 0) {
|
|
1428
|
+
let matchedOp = "";
|
|
1429
|
+
for (const op of ops) {
|
|
1430
|
+
if (expr.startsWith(op, i)) {
|
|
1431
|
+
matchedOp = op;
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
if (matchedOp) {
|
|
1436
|
+
const isPlusMinus = matchedOp === "+" || matchedOp === "-";
|
|
1437
|
+
const unary = isPlusMinus && (prevSig === "" || UNARY_PRECEDERS.includes(prevSig));
|
|
1438
|
+
if (!unary) {
|
|
1439
|
+
bestIdx = i;
|
|
1440
|
+
bestOp = matchedOp;
|
|
1441
|
+
}
|
|
1442
|
+
i += matchedOp.length - 1;
|
|
1443
|
+
prevSig = matchedOp[matchedOp.length - 1];
|
|
1444
|
+
continue;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
prevSig = ch;
|
|
1448
|
+
}
|
|
1449
|
+
if (bestIdx === -1) return null;
|
|
1450
|
+
return { left: expr.slice(0, bestIdx).trim(), op: bestOp, right: expr.slice(bestIdx + bestOp.length).trim() };
|
|
1451
|
+
}
|
|
1360
1452
|
var RE_TEMPLATE_LIT = /^`([^`]*)`$/;
|
|
1361
1453
|
var RE_TEMPLATE_INTERP = /\$\{([^}]+)\}/g;
|
|
1362
1454
|
var RE_GROUP_METHOD_CALL = /^\((.+)\)\.(\w+)\((.*)\)$/;
|
|
@@ -2313,12 +2405,12 @@ var FormaRuntime = (function (exports) {
|
|
|
2313
2405
|
return () => left() && right();
|
|
2314
2406
|
}
|
|
2315
2407
|
}
|
|
2316
|
-
const compMatch = expr
|
|
2408
|
+
const compMatch = matchBinaryOp(expr, ["===", "!==", "==", "!=", ">=", "<=", ">", "<"]);
|
|
2317
2409
|
if (compMatch) {
|
|
2318
|
-
const left = parseExpression(compMatch
|
|
2319
|
-
const right = parseExpression(compMatch
|
|
2410
|
+
const left = parseExpression(compMatch.left, scope);
|
|
2411
|
+
const right = parseExpression(compMatch.right, scope);
|
|
2320
2412
|
if (left && right) {
|
|
2321
|
-
const op = compMatch
|
|
2413
|
+
const op = compMatch.op;
|
|
2322
2414
|
return () => {
|
|
2323
2415
|
const l = left(), r = right();
|
|
2324
2416
|
switch (op) {
|
|
@@ -2342,12 +2434,12 @@ var FormaRuntime = (function (exports) {
|
|
|
2342
2434
|
};
|
|
2343
2435
|
}
|
|
2344
2436
|
}
|
|
2345
|
-
const addMatch = expr
|
|
2437
|
+
const addMatch = matchBinaryOp(expr, ["+", "-"]);
|
|
2346
2438
|
if (addMatch) {
|
|
2347
|
-
const left = parseExpression(addMatch
|
|
2348
|
-
const right = parseExpression(addMatch
|
|
2439
|
+
const left = parseExpression(addMatch.left, scope);
|
|
2440
|
+
const right = parseExpression(addMatch.right, scope);
|
|
2349
2441
|
if (left && right) {
|
|
2350
|
-
const op = addMatch
|
|
2442
|
+
const op = addMatch.op;
|
|
2351
2443
|
return () => {
|
|
2352
2444
|
const l = left(), r = right();
|
|
2353
2445
|
if (op === "+") return l + r;
|
|
@@ -2355,12 +2447,12 @@ var FormaRuntime = (function (exports) {
|
|
|
2355
2447
|
};
|
|
2356
2448
|
}
|
|
2357
2449
|
}
|
|
2358
|
-
const mulMatch = expr
|
|
2450
|
+
const mulMatch = matchBinaryOp(expr, ["*", "/", "%"]);
|
|
2359
2451
|
if (mulMatch) {
|
|
2360
|
-
const left = parseExpression(mulMatch
|
|
2361
|
-
const right = parseExpression(mulMatch
|
|
2452
|
+
const left = parseExpression(mulMatch.left, scope);
|
|
2453
|
+
const right = parseExpression(mulMatch.right, scope);
|
|
2362
2454
|
if (left && right) {
|
|
2363
|
-
const op = mulMatch
|
|
2455
|
+
const op = mulMatch.op;
|
|
2364
2456
|
return () => {
|
|
2365
2457
|
const l = left(), r = right();
|
|
2366
2458
|
switch (op) {
|
|
@@ -2785,25 +2877,61 @@ var FormaRuntime = (function (exports) {
|
|
|
2785
2877
|
const modelExpr = !known || known.has("data-model") ? el.getAttribute("data-model") : null;
|
|
2786
2878
|
if (modelExpr) {
|
|
2787
2879
|
const prop = modelExpr.replace(RE_STRIP_BRACES, "").trim();
|
|
2788
|
-
|
|
2789
|
-
|
|
2880
|
+
let getter = scope.getters[prop];
|
|
2881
|
+
let setter = scope.setters[prop];
|
|
2882
|
+
if ((!getter || !setter) && prop.includes(".")) {
|
|
2883
|
+
getter = buildEvaluator(prop, scope);
|
|
2884
|
+
const lastDot = prop.lastIndexOf(".");
|
|
2885
|
+
const basePath = prop.slice(0, lastDot);
|
|
2886
|
+
const key = prop.slice(lastDot + 1);
|
|
2887
|
+
const baseGet = buildEvaluator(basePath, scope);
|
|
2888
|
+
setter = (v) => {
|
|
2889
|
+
const base = baseGet();
|
|
2890
|
+
if (base != null && typeof base === "object") base[key] = v;
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2790
2893
|
if (getter && setter) {
|
|
2791
2894
|
const input = el;
|
|
2895
|
+
const tag = input.tagName;
|
|
2792
2896
|
const dispose = internalEffect(() => {
|
|
2793
2897
|
const val = getter();
|
|
2794
|
-
|
|
2898
|
+
const type = input.type;
|
|
2899
|
+
if (type === "checkbox") {
|
|
2795
2900
|
input.checked = !!val;
|
|
2901
|
+
const indetExpr = el.getAttribute("data-model-indeterminate");
|
|
2902
|
+
if (indetExpr) {
|
|
2903
|
+
const indetGetter = scope.getters[indetExpr.replace(RE_STRIP_BRACES, "").trim()];
|
|
2904
|
+
if (indetGetter) input.indeterminate = !!indetGetter();
|
|
2905
|
+
}
|
|
2906
|
+
} else if (type === "radio") {
|
|
2907
|
+
input.checked = String(val) === input.value;
|
|
2908
|
+
} else if (tag === "SELECT" && input.multiple) {
|
|
2909
|
+
const sel = input;
|
|
2910
|
+
const arr = Array.isArray(val) ? val.map(String) : [];
|
|
2911
|
+
for (const opt of Array.from(sel.options)) opt.selected = arr.includes(opt.value);
|
|
2796
2912
|
} else {
|
|
2797
2913
|
input.value = String(val ?? "");
|
|
2798
2914
|
}
|
|
2799
2915
|
});
|
|
2800
2916
|
disposers.push(dispose);
|
|
2801
|
-
const event = input.type === "checkbox" ? "change" : "input";
|
|
2917
|
+
const event = input.type === "checkbox" || input.type === "radio" || tag === "SELECT" ? "change" : "input";
|
|
2802
2918
|
const onModelInput = () => {
|
|
2803
|
-
|
|
2919
|
+
const type = input.type;
|
|
2920
|
+
if (type === "checkbox") {
|
|
2804
2921
|
setter(input.checked);
|
|
2805
|
-
} else if (
|
|
2806
|
-
setter(
|
|
2922
|
+
} else if (type === "radio") {
|
|
2923
|
+
if (input.checked) setter(input.value);
|
|
2924
|
+
} else if (tag === "SELECT" && input.multiple) {
|
|
2925
|
+
const sel = input;
|
|
2926
|
+
setter(Array.from(sel.selectedOptions).map((o) => o.value));
|
|
2927
|
+
} else if (type === "number" || type === "range") {
|
|
2928
|
+
const raw = input.value;
|
|
2929
|
+
if (raw === "") {
|
|
2930
|
+
setter(null);
|
|
2931
|
+
} else {
|
|
2932
|
+
const n = Number(raw);
|
|
2933
|
+
if (!Number.isNaN(n)) setter(n);
|
|
2934
|
+
}
|
|
2807
2935
|
} else {
|
|
2808
2936
|
setter(input.value);
|
|
2809
2937
|
}
|
|
@@ -2995,59 +3123,30 @@ var FormaRuntime = (function (exports) {
|
|
|
2995
3123
|
}
|
|
2996
3124
|
}
|
|
2997
3125
|
const prevNodes = new Set(oldNodes);
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
for (const n of prevNodes) {
|
|
3019
|
-
if (!nextNodes.has(n)) {
|
|
3020
|
-
if (n.hasAttribute?.("data-forma-leaving")) continue;
|
|
3021
|
-
disposeCloneBindings2(n);
|
|
3022
|
-
}
|
|
3023
|
-
}
|
|
3024
|
-
oldItems = result.items;
|
|
3025
|
-
oldNodes = result.nodes;
|
|
3026
|
-
} else {
|
|
3027
|
-
const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
|
|
3028
|
-
const oldWrapped = oldItems;
|
|
3029
|
-
const result = reconcileList(
|
|
3030
|
-
el,
|
|
3031
|
-
oldWrapped,
|
|
3032
|
-
wrapped,
|
|
3033
|
-
oldNodes,
|
|
3034
|
-
(w) => w.__idx,
|
|
3035
|
-
(w) => createBoundClone2(w.__item, w.__idx),
|
|
3036
|
-
(node, w) => updateBoundClone2(node, w.__item, w.__idx),
|
|
3037
|
-
void 0,
|
|
3038
|
-
// beforeNode
|
|
3039
|
-
listHooks
|
|
3040
|
-
);
|
|
3041
|
-
const nextNodes = new Set(result.nodes);
|
|
3042
|
-
for (const n of prevNodes) {
|
|
3043
|
-
if (!nextNodes.has(n)) {
|
|
3044
|
-
if (n.hasAttribute?.("data-forma-leaving")) continue;
|
|
3045
|
-
disposeCloneBindings2(n);
|
|
3046
|
-
}
|
|
3126
|
+
const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
|
|
3127
|
+
const oldWrapped = oldItems;
|
|
3128
|
+
const keyFn = keyProp ? (w) => String(w.__item?.[keyProp] ?? "") : (w) => w.__idx;
|
|
3129
|
+
const result = reconcileList(
|
|
3130
|
+
el,
|
|
3131
|
+
oldWrapped,
|
|
3132
|
+
wrapped,
|
|
3133
|
+
oldNodes,
|
|
3134
|
+
keyFn,
|
|
3135
|
+
(w) => createBoundClone2(w.__item, w.__idx),
|
|
3136
|
+
(node, w) => updateBoundClone2(node, w.__item, w.__idx),
|
|
3137
|
+
void 0,
|
|
3138
|
+
// beforeNode
|
|
3139
|
+
listHooks
|
|
3140
|
+
);
|
|
3141
|
+
const nextNodes = new Set(result.nodes);
|
|
3142
|
+
for (const n of prevNodes) {
|
|
3143
|
+
if (!nextNodes.has(n)) {
|
|
3144
|
+
if (n.hasAttribute?.("data-forma-leaving")) continue;
|
|
3145
|
+
disposeCloneBindings2(n);
|
|
3047
3146
|
}
|
|
3048
|
-
oldItems = result.items;
|
|
3049
|
-
oldNodes = result.nodes;
|
|
3050
3147
|
}
|
|
3148
|
+
oldItems = result.items;
|
|
3149
|
+
oldNodes = result.nodes;
|
|
3051
3150
|
});
|
|
3052
3151
|
disposers.push(dispose);
|
|
3053
3152
|
}
|
package/dist/forma-runtime.js
CHANGED
|
@@ -788,14 +788,18 @@ var FormaRuntime = (() => {
|
|
|
788
788
|
}
|
|
789
789
|
const oldKeyMap = /* @__PURE__ */ new Map();
|
|
790
790
|
for (let i = 0; i < oldLen; i++) {
|
|
791
|
-
|
|
791
|
+
const k = keyFn(oldItems[i]);
|
|
792
|
+
const bucket = oldKeyMap.get(k);
|
|
793
|
+
if (bucket) bucket.push(i);
|
|
794
|
+
else oldKeyMap.set(k, [i]);
|
|
792
795
|
}
|
|
793
796
|
const oldIndices = new Array(newLen);
|
|
794
797
|
const oldUsed = new Uint8Array(oldLen);
|
|
795
798
|
for (let i = 0; i < newLen; i++) {
|
|
796
799
|
const key = keyFn(newItems[i]);
|
|
797
|
-
const
|
|
798
|
-
if (
|
|
800
|
+
const bucket = oldKeyMap.get(key);
|
|
801
|
+
if (bucket && bucket.length > 0) {
|
|
802
|
+
const oldIdx = bucket.shift();
|
|
799
803
|
oldIndices[i] = oldIdx;
|
|
800
804
|
oldUsed[oldIdx] = 1;
|
|
801
805
|
} else {
|
|
@@ -1144,12 +1148,12 @@ var FormaRuntime = (() => {
|
|
|
1144
1148
|
return null;
|
|
1145
1149
|
}
|
|
1146
1150
|
function createReconciler(config) {
|
|
1147
|
-
|
|
1151
|
+
const lastHtmlByContainer = /* @__PURE__ */ new WeakMap();
|
|
1148
1152
|
return function reconcile2(container, html) {
|
|
1149
1153
|
const trimmed = html.trim();
|
|
1150
1154
|
if (!trimmed) return;
|
|
1151
|
-
if (
|
|
1152
|
-
|
|
1155
|
+
if (lastHtmlByContainer.get(container) === trimmed && container.hasChildNodes()) return;
|
|
1156
|
+
lastHtmlByContainer.set(container, trimmed);
|
|
1153
1157
|
config.disconnectObserver();
|
|
1154
1158
|
try {
|
|
1155
1159
|
if (!container.hasChildNodes() || container.children.length === 0) {
|
|
@@ -1464,9 +1468,97 @@ var FormaRuntime = (() => {
|
|
|
1464
1468
|
var RE_NULLISH = /^(.+?)\s*\?\?\s*(.+)$/;
|
|
1465
1469
|
var RE_AND = /^(.+?)\s*&&\s*(.+)$/;
|
|
1466
1470
|
var RE_OR = /^(.+?)\s*\|\|\s*(.+)$/;
|
|
1467
|
-
var
|
|
1468
|
-
|
|
1469
|
-
|
|
1471
|
+
var UNARY_PRECEDERS = "+-*/%<>=!&|^~(,[{?:";
|
|
1472
|
+
function matchBinaryOp(expr, ops) {
|
|
1473
|
+
const SQ = String.fromCharCode(39);
|
|
1474
|
+
const DQ = String.fromCharCode(34);
|
|
1475
|
+
const BT = String.fromCharCode(96);
|
|
1476
|
+
const BS = String.fromCharCode(92);
|
|
1477
|
+
let depth = 0;
|
|
1478
|
+
let inSingle = false, inDouble = false, inTemplate = false, escaped = false;
|
|
1479
|
+
let prevSig = "";
|
|
1480
|
+
let bestIdx = -1;
|
|
1481
|
+
let bestOp = "";
|
|
1482
|
+
for (let i = 0; i < expr.length; i++) {
|
|
1483
|
+
const ch = expr[i];
|
|
1484
|
+
if (escaped) {
|
|
1485
|
+
escaped = false;
|
|
1486
|
+
continue;
|
|
1487
|
+
}
|
|
1488
|
+
if (ch === BS && (inSingle || inDouble || inTemplate)) {
|
|
1489
|
+
escaped = true;
|
|
1490
|
+
continue;
|
|
1491
|
+
}
|
|
1492
|
+
if (inSingle) {
|
|
1493
|
+
if (ch === SQ) {
|
|
1494
|
+
inSingle = false;
|
|
1495
|
+
prevSig = DQ;
|
|
1496
|
+
}
|
|
1497
|
+
continue;
|
|
1498
|
+
}
|
|
1499
|
+
if (inDouble) {
|
|
1500
|
+
if (ch === DQ) {
|
|
1501
|
+
inDouble = false;
|
|
1502
|
+
prevSig = DQ;
|
|
1503
|
+
}
|
|
1504
|
+
continue;
|
|
1505
|
+
}
|
|
1506
|
+
if (inTemplate) {
|
|
1507
|
+
if (ch === BT) {
|
|
1508
|
+
inTemplate = false;
|
|
1509
|
+
prevSig = DQ;
|
|
1510
|
+
}
|
|
1511
|
+
continue;
|
|
1512
|
+
}
|
|
1513
|
+
if (ch === SQ) {
|
|
1514
|
+
inSingle = true;
|
|
1515
|
+
continue;
|
|
1516
|
+
}
|
|
1517
|
+
if (ch === DQ) {
|
|
1518
|
+
inDouble = true;
|
|
1519
|
+
continue;
|
|
1520
|
+
}
|
|
1521
|
+
if (ch === BT) {
|
|
1522
|
+
inTemplate = true;
|
|
1523
|
+
continue;
|
|
1524
|
+
}
|
|
1525
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
1526
|
+
depth++;
|
|
1527
|
+
prevSig = ch;
|
|
1528
|
+
continue;
|
|
1529
|
+
}
|
|
1530
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
1531
|
+
if (depth > 0) depth--;
|
|
1532
|
+
prevSig = ch;
|
|
1533
|
+
continue;
|
|
1534
|
+
}
|
|
1535
|
+
if (depth !== 0) continue;
|
|
1536
|
+
if (ch === " " || ch === " " || ch === "\n") continue;
|
|
1537
|
+
if (i > 0) {
|
|
1538
|
+
let matchedOp = "";
|
|
1539
|
+
for (const op of ops) {
|
|
1540
|
+
if (expr.startsWith(op, i)) {
|
|
1541
|
+
matchedOp = op;
|
|
1542
|
+
break;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
if (matchedOp) {
|
|
1546
|
+
const isPlusMinus = matchedOp === "+" || matchedOp === "-";
|
|
1547
|
+
const unary = isPlusMinus && (prevSig === "" || UNARY_PRECEDERS.includes(prevSig));
|
|
1548
|
+
if (!unary) {
|
|
1549
|
+
bestIdx = i;
|
|
1550
|
+
bestOp = matchedOp;
|
|
1551
|
+
}
|
|
1552
|
+
i += matchedOp.length - 1;
|
|
1553
|
+
prevSig = matchedOp[matchedOp.length - 1];
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
prevSig = ch;
|
|
1558
|
+
}
|
|
1559
|
+
if (bestIdx === -1) return null;
|
|
1560
|
+
return { left: expr.slice(0, bestIdx).trim(), op: bestOp, right: expr.slice(bestIdx + bestOp.length).trim() };
|
|
1561
|
+
}
|
|
1470
1562
|
var RE_TEMPLATE_LIT = /^`([^`]*)`$/;
|
|
1471
1563
|
var RE_TEMPLATE_INTERP = /\$\{([^}]+)\}/g;
|
|
1472
1564
|
var RE_GROUP_METHOD_CALL = /^\((.+)\)\.(\w+)\((.*)\)$/;
|
|
@@ -2461,12 +2553,12 @@ var FormaRuntime = (() => {
|
|
|
2461
2553
|
return () => left() && right();
|
|
2462
2554
|
}
|
|
2463
2555
|
}
|
|
2464
|
-
const compMatch = expr
|
|
2556
|
+
const compMatch = matchBinaryOp(expr, ["===", "!==", "==", "!=", ">=", "<=", ">", "<"]);
|
|
2465
2557
|
if (compMatch) {
|
|
2466
|
-
const left = parseExpression(compMatch
|
|
2467
|
-
const right = parseExpression(compMatch
|
|
2558
|
+
const left = parseExpression(compMatch.left, scope);
|
|
2559
|
+
const right = parseExpression(compMatch.right, scope);
|
|
2468
2560
|
if (left && right) {
|
|
2469
|
-
const op = compMatch
|
|
2561
|
+
const op = compMatch.op;
|
|
2470
2562
|
return () => {
|
|
2471
2563
|
const l = left(), r = right();
|
|
2472
2564
|
switch (op) {
|
|
@@ -2490,12 +2582,12 @@ var FormaRuntime = (() => {
|
|
|
2490
2582
|
};
|
|
2491
2583
|
}
|
|
2492
2584
|
}
|
|
2493
|
-
const addMatch = expr
|
|
2585
|
+
const addMatch = matchBinaryOp(expr, ["+", "-"]);
|
|
2494
2586
|
if (addMatch) {
|
|
2495
|
-
const left = parseExpression(addMatch
|
|
2496
|
-
const right = parseExpression(addMatch
|
|
2587
|
+
const left = parseExpression(addMatch.left, scope);
|
|
2588
|
+
const right = parseExpression(addMatch.right, scope);
|
|
2497
2589
|
if (left && right) {
|
|
2498
|
-
const op = addMatch
|
|
2590
|
+
const op = addMatch.op;
|
|
2499
2591
|
return () => {
|
|
2500
2592
|
const l = left(), r = right();
|
|
2501
2593
|
if (op === "+") return l + r;
|
|
@@ -2503,12 +2595,12 @@ var FormaRuntime = (() => {
|
|
|
2503
2595
|
};
|
|
2504
2596
|
}
|
|
2505
2597
|
}
|
|
2506
|
-
const mulMatch = expr
|
|
2598
|
+
const mulMatch = matchBinaryOp(expr, ["*", "/", "%"]);
|
|
2507
2599
|
if (mulMatch) {
|
|
2508
|
-
const left = parseExpression(mulMatch
|
|
2509
|
-
const right = parseExpression(mulMatch
|
|
2600
|
+
const left = parseExpression(mulMatch.left, scope);
|
|
2601
|
+
const right = parseExpression(mulMatch.right, scope);
|
|
2510
2602
|
if (left && right) {
|
|
2511
|
-
const op = mulMatch
|
|
2603
|
+
const op = mulMatch.op;
|
|
2512
2604
|
return () => {
|
|
2513
2605
|
const l = left(), r = right();
|
|
2514
2606
|
switch (op) {
|
|
@@ -3003,25 +3095,61 @@ var FormaRuntime = (() => {
|
|
|
3003
3095
|
const modelExpr = !known || known.has("data-model") ? el.getAttribute("data-model") : null;
|
|
3004
3096
|
if (modelExpr) {
|
|
3005
3097
|
const prop = modelExpr.replace(RE_STRIP_BRACES, "").trim();
|
|
3006
|
-
|
|
3007
|
-
|
|
3098
|
+
let getter = scope.getters[prop];
|
|
3099
|
+
let setter = scope.setters[prop];
|
|
3100
|
+
if ((!getter || !setter) && prop.includes(".")) {
|
|
3101
|
+
getter = buildEvaluator(prop, scope);
|
|
3102
|
+
const lastDot = prop.lastIndexOf(".");
|
|
3103
|
+
const basePath = prop.slice(0, lastDot);
|
|
3104
|
+
const key = prop.slice(lastDot + 1);
|
|
3105
|
+
const baseGet = buildEvaluator(basePath, scope);
|
|
3106
|
+
setter = (v) => {
|
|
3107
|
+
const base = baseGet();
|
|
3108
|
+
if (base != null && typeof base === "object") base[key] = v;
|
|
3109
|
+
};
|
|
3110
|
+
}
|
|
3008
3111
|
if (getter && setter) {
|
|
3009
3112
|
const input = el;
|
|
3113
|
+
const tag = input.tagName;
|
|
3010
3114
|
const dispose = internalEffect(() => {
|
|
3011
3115
|
const val = getter();
|
|
3012
|
-
|
|
3116
|
+
const type = input.type;
|
|
3117
|
+
if (type === "checkbox") {
|
|
3013
3118
|
input.checked = !!val;
|
|
3119
|
+
const indetExpr = el.getAttribute("data-model-indeterminate");
|
|
3120
|
+
if (indetExpr) {
|
|
3121
|
+
const indetGetter = scope.getters[indetExpr.replace(RE_STRIP_BRACES, "").trim()];
|
|
3122
|
+
if (indetGetter) input.indeterminate = !!indetGetter();
|
|
3123
|
+
}
|
|
3124
|
+
} else if (type === "radio") {
|
|
3125
|
+
input.checked = String(val) === input.value;
|
|
3126
|
+
} else if (tag === "SELECT" && input.multiple) {
|
|
3127
|
+
const sel = input;
|
|
3128
|
+
const arr = Array.isArray(val) ? val.map(String) : [];
|
|
3129
|
+
for (const opt of Array.from(sel.options)) opt.selected = arr.includes(opt.value);
|
|
3014
3130
|
} else {
|
|
3015
3131
|
input.value = String(val ?? "");
|
|
3016
3132
|
}
|
|
3017
3133
|
});
|
|
3018
3134
|
disposers.push(dispose);
|
|
3019
|
-
const event = input.type === "checkbox" ? "change" : "input";
|
|
3135
|
+
const event = input.type === "checkbox" || input.type === "radio" || tag === "SELECT" ? "change" : "input";
|
|
3020
3136
|
const onModelInput = () => {
|
|
3021
|
-
|
|
3137
|
+
const type = input.type;
|
|
3138
|
+
if (type === "checkbox") {
|
|
3022
3139
|
setter(input.checked);
|
|
3023
|
-
} else if (
|
|
3024
|
-
setter(
|
|
3140
|
+
} else if (type === "radio") {
|
|
3141
|
+
if (input.checked) setter(input.value);
|
|
3142
|
+
} else if (tag === "SELECT" && input.multiple) {
|
|
3143
|
+
const sel = input;
|
|
3144
|
+
setter(Array.from(sel.selectedOptions).map((o) => o.value));
|
|
3145
|
+
} else if (type === "number" || type === "range") {
|
|
3146
|
+
const raw = input.value;
|
|
3147
|
+
if (raw === "") {
|
|
3148
|
+
setter(null);
|
|
3149
|
+
} else {
|
|
3150
|
+
const n = Number(raw);
|
|
3151
|
+
if (!Number.isNaN(n)) setter(n);
|
|
3152
|
+
}
|
|
3025
3153
|
} else {
|
|
3026
3154
|
setter(input.value);
|
|
3027
3155
|
}
|
|
@@ -3214,59 +3342,30 @@ var FormaRuntime = (() => {
|
|
|
3214
3342
|
}
|
|
3215
3343
|
}
|
|
3216
3344
|
const prevNodes = new Set(oldNodes);
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
for (const n of prevNodes) {
|
|
3238
|
-
if (!nextNodes.has(n)) {
|
|
3239
|
-
if (n.hasAttribute?.("data-forma-leaving")) continue;
|
|
3240
|
-
disposeCloneBindings2(n);
|
|
3241
|
-
}
|
|
3242
|
-
}
|
|
3243
|
-
oldItems = result.items;
|
|
3244
|
-
oldNodes = result.nodes;
|
|
3245
|
-
} else {
|
|
3246
|
-
const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
|
|
3247
|
-
const oldWrapped = oldItems;
|
|
3248
|
-
const result = reconcileList(
|
|
3249
|
-
el,
|
|
3250
|
-
oldWrapped,
|
|
3251
|
-
wrapped,
|
|
3252
|
-
oldNodes,
|
|
3253
|
-
(w) => w.__idx,
|
|
3254
|
-
(w) => createBoundClone2(w.__item, w.__idx),
|
|
3255
|
-
(node, w) => updateBoundClone2(node, w.__item, w.__idx),
|
|
3256
|
-
void 0,
|
|
3257
|
-
// beforeNode
|
|
3258
|
-
listHooks
|
|
3259
|
-
);
|
|
3260
|
-
const nextNodes = new Set(result.nodes);
|
|
3261
|
-
for (const n of prevNodes) {
|
|
3262
|
-
if (!nextNodes.has(n)) {
|
|
3263
|
-
if (n.hasAttribute?.("data-forma-leaving")) continue;
|
|
3264
|
-
disposeCloneBindings2(n);
|
|
3265
|
-
}
|
|
3345
|
+
const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
|
|
3346
|
+
const oldWrapped = oldItems;
|
|
3347
|
+
const keyFn = keyProp ? (w) => String(w.__item?.[keyProp] ?? "") : (w) => w.__idx;
|
|
3348
|
+
const result = reconcileList(
|
|
3349
|
+
el,
|
|
3350
|
+
oldWrapped,
|
|
3351
|
+
wrapped,
|
|
3352
|
+
oldNodes,
|
|
3353
|
+
keyFn,
|
|
3354
|
+
(w) => createBoundClone2(w.__item, w.__idx),
|
|
3355
|
+
(node, w) => updateBoundClone2(node, w.__item, w.__idx),
|
|
3356
|
+
void 0,
|
|
3357
|
+
// beforeNode
|
|
3358
|
+
listHooks
|
|
3359
|
+
);
|
|
3360
|
+
const nextNodes = new Set(result.nodes);
|
|
3361
|
+
for (const n of prevNodes) {
|
|
3362
|
+
if (!nextNodes.has(n)) {
|
|
3363
|
+
if (n.hasAttribute?.("data-forma-leaving")) continue;
|
|
3364
|
+
disposeCloneBindings2(n);
|
|
3266
3365
|
}
|
|
3267
|
-
oldItems = result.items;
|
|
3268
|
-
oldNodes = result.nodes;
|
|
3269
3366
|
}
|
|
3367
|
+
oldItems = result.items;
|
|
3368
|
+
oldNodes = result.nodes;
|
|
3270
3369
|
});
|
|
3271
3370
|
disposers.push(dispose);
|
|
3272
3371
|
}
|