@jxsuite/studio 0.37.1 → 1.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/iframe-entry.js +622 -49
- package/dist/iframe-entry.js.map +15 -12
- package/dist/studio.css +1333 -0
- package/dist/studio.js +103709 -81001
- package/dist/studio.js.map +201 -157
- package/package.json +47 -45
- package/src/account-status.ts +39 -0
- package/src/browse/browse.ts +10 -14
- package/src/canvas/canvas-live-render.ts +21 -2
- package/src/canvas/canvas-render.ts +35 -16
- package/src/canvas/canvas-utils.ts +118 -72
- package/src/canvas/iframe-entry.ts +20 -0
- package/src/canvas/iframe-eval.ts +155 -0
- package/src/canvas/iframe-host.ts +132 -6
- package/src/canvas/iframe-inline-edit.ts +107 -1
- package/src/canvas/iframe-protocol.ts +43 -3
- package/src/canvas/iframe-render.ts +18 -0
- package/src/collab/collab-session.ts +23 -8
- package/src/collab/collab-state.ts +6 -3
- package/src/component-props.ts +104 -0
- package/src/editor/context-menu.ts +1 -1
- package/src/editor/inline-edit-apply.ts +36 -1
- package/src/editor/inline-edit.ts +58 -1
- package/src/editor/repeater-scope.ts +8 -13
- package/src/editor/shortcuts.ts +41 -12
- package/src/files/file-ops.ts +14 -0
- package/src/files/files.ts +56 -1
- package/src/format/format-host.ts +63 -1
- package/src/grid/cell-editors.ts +288 -0
- package/src/grid/cell-popovers.ts +108 -0
- package/src/grid/csv-codec.ts +122 -0
- package/src/grid/edit-buffer.ts +490 -0
- package/src/grid/grid-controller.ts +417 -0
- package/src/grid/grid-layout.ts +83 -0
- package/src/grid/grid-open.ts +167 -0
- package/src/grid/grid-panel.ts +302 -0
- package/src/grid/grid-source.ts +210 -0
- package/src/grid/grid-view.ts +367 -0
- package/src/grid/schema-columns.ts +261 -0
- package/src/grid/sources/connector-source.ts +217 -0
- package/src/grid/sources/content-source.ts +542 -0
- package/src/grid/sources/csv-file-source.ts +247 -0
- package/src/grid/tabulator-tables.d.ts +120 -0
- package/src/new-project/add-repo-modal.ts +183 -0
- package/src/new-project/new-project-modal.ts +22 -3
- package/src/page-params.ts +34 -8
- package/src/panels/ai-chat/chat-markdown.ts +2 -2
- package/src/panels/ai-panel.ts +61 -4
- package/src/panels/block-action-bar.ts +8 -3
- package/src/panels/chat-panel.ts +98 -0
- package/src/panels/data-grid.ts +241 -0
- package/src/panels/editors.ts +43 -17
- package/src/panels/events-panel.ts +137 -44
- package/src/panels/formula-workspace.ts +379 -0
- package/src/panels/frontmatter-fields.ts +231 -0
- package/src/panels/frontmatter-panel.ts +132 -0
- package/src/panels/git-panel.ts +1 -1
- package/src/panels/head-panel.ts +11 -175
- package/src/panels/properties-panel.ts +154 -144
- package/src/panels/right-panel.ts +9 -47
- package/src/panels/signals-panel.ts +217 -460
- package/src/panels/statement-editor.ts +710 -0
- package/src/panels/statusbar.ts +1 -1
- package/src/panels/style-panel.ts +25 -1
- package/src/panels/stylebook-panel.ts +0 -2
- package/src/panels/tab-bar.ts +175 -6
- package/src/panels/tab-strip.ts +62 -6
- package/src/panels/toolbar.ts +37 -3
- package/src/panels/welcome-screen.ts +50 -0
- package/src/platform-errors.ts +30 -0
- package/src/platforms/cloud.ts +172 -89
- package/src/platforms/devserver.ts +172 -0
- package/src/services/ai-project-tools.ts +541 -0
- package/src/services/ai-session-store.ts +28 -0
- package/src/services/ai-system-prompt.ts +194 -24
- package/src/services/ai-tools.ts +88 -21
- package/src/services/automation.ts +16 -0
- package/src/services/context-resolver.ts +73 -0
- package/src/services/data-service.ts +155 -0
- package/src/services/document-assistant.ts +81 -11
- package/src/services/gated-registry.ts +72 -0
- package/src/services/live-preview.ts +0 -0
- package/src/services/monaco-setup.ts +75 -26
- package/src/services/preview-eval.ts +68 -0
- package/src/services/project-adoption.ts +31 -0
- package/src/settings/contributed-section.ts +406 -0
- package/src/settings/extension-sections.ts +145 -0
- package/src/settings/schema-field-ui.ts +4 -2
- package/src/settings/settings-modal.ts +101 -42
- package/src/site-context.ts +12 -1
- package/src/store.ts +4 -0
- package/src/studio.ts +107 -52
- package/src/tabs/patch-ops.ts +25 -0
- package/src/tabs/tab.ts +39 -1
- package/src/tabs/transact.ts +61 -14
- package/src/types.ts +132 -1
- package/src/ui/dynamic-slot.ts +272 -0
- package/src/ui/expression-editor.ts +423 -125
- package/src/ui/field-row.ts +5 -0
- package/src/ui/form-controls.ts +322 -0
- package/src/ui/formula-catalog.ts +557 -0
- package/src/ui/formula-chips.ts +216 -0
- package/src/ui/formula-palette.ts +211 -0
- package/src/ui/layers.ts +40 -0
- package/src/ui/media-picker.ts +1 -1
- package/src/ui/panel-resize.ts +15 -1
- package/src/ui/progress-modal.ts +2 -2
- package/src/ui/schema-form.ts +524 -0
- package/src/utils/preview-format.ts +26 -0
- package/src/utils/studio-utils.ts +4 -3
- package/src/view.ts +4 -4
- package/src/workspace/workspace.ts +14 -0
- package/src/settings/content-types-editor.ts +0 -599
package/dist/iframe-entry.js
CHANGED
|
@@ -113,8 +113,9 @@ class EffectScope {
|
|
|
113
113
|
this._isPaused = true;
|
|
114
114
|
let i, l;
|
|
115
115
|
if (this.scopes) {
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
const scopes = this.scopes.slice();
|
|
117
|
+
for (i = 0, l = scopes.length;i < l; i++) {
|
|
118
|
+
scopes[i].pause();
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
for (i = 0, l = this.effects.length;i < l; i++) {
|
|
@@ -128,12 +129,14 @@ class EffectScope {
|
|
|
128
129
|
this._isPaused = false;
|
|
129
130
|
let i, l;
|
|
130
131
|
if (this.scopes) {
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
const scopes = this.scopes.slice();
|
|
133
|
+
for (i = 0, l = scopes.length;i < l; i++) {
|
|
134
|
+
scopes[i].resume();
|
|
133
135
|
}
|
|
134
136
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
const effects = this.effects.slice();
|
|
138
|
+
for (i = 0, l = effects.length;i < l; i++) {
|
|
139
|
+
effects[i].resume();
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
}
|
|
@@ -187,8 +190,9 @@ class EffectScope {
|
|
|
187
190
|
}
|
|
188
191
|
this.cleanups.length = 0;
|
|
189
192
|
if (this.scopes) {
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
const scopes = this.scopes.slice();
|
|
194
|
+
for (i = 0, l = scopes.length;i < l; i++) {
|
|
195
|
+
scopes[i].stop(true);
|
|
192
196
|
}
|
|
193
197
|
this.scopes.length = 0;
|
|
194
198
|
}
|
|
@@ -1444,33 +1448,142 @@ var BINARY_OPS = new Set([
|
|
|
1444
1448
|
">",
|
|
1445
1449
|
">=",
|
|
1446
1450
|
"&&",
|
|
1447
|
-
"||"
|
|
1451
|
+
"||",
|
|
1452
|
+
"??"
|
|
1448
1453
|
]);
|
|
1449
1454
|
var ASSIGNMENT_OPS = new Set(["=", "+=", "-=", "*=", "/="]);
|
|
1450
1455
|
var ARRAY_METHOD_OPS = new Set(["push", "pop", "shift", "unshift", "splice"]);
|
|
1451
1456
|
var AGGREGATE_OPS = new Set(["reduce", "map", "filter"]);
|
|
1457
|
+
var CONDITIONAL_OPS = new Set(["?:", "switch"]);
|
|
1458
|
+
var PURE_METHOD_OPS = new Set([
|
|
1459
|
+
"includes",
|
|
1460
|
+
"indexOf",
|
|
1461
|
+
"lastIndexOf",
|
|
1462
|
+
"join",
|
|
1463
|
+
"slice",
|
|
1464
|
+
"concat",
|
|
1465
|
+
"at",
|
|
1466
|
+
"flat",
|
|
1467
|
+
"toSorted",
|
|
1468
|
+
"toReversed",
|
|
1469
|
+
"toSpliced",
|
|
1470
|
+
"with",
|
|
1471
|
+
"toUpperCase",
|
|
1472
|
+
"toLowerCase",
|
|
1473
|
+
"trim",
|
|
1474
|
+
"trimStart",
|
|
1475
|
+
"trimEnd",
|
|
1476
|
+
"split",
|
|
1477
|
+
"startsWith",
|
|
1478
|
+
"endsWith",
|
|
1479
|
+
"padStart",
|
|
1480
|
+
"padEnd",
|
|
1481
|
+
"replaceAll",
|
|
1482
|
+
"repeat",
|
|
1483
|
+
"charAt",
|
|
1484
|
+
"normalize",
|
|
1485
|
+
"toLocaleUpperCase",
|
|
1486
|
+
"toLocaleLowerCase",
|
|
1487
|
+
"toFixed",
|
|
1488
|
+
"toPrecision",
|
|
1489
|
+
"toLocaleString"
|
|
1490
|
+
]);
|
|
1452
1491
|
var BLESSED_OPERATORS = new Set([
|
|
1453
1492
|
...MUTATING_OPS,
|
|
1454
1493
|
...UNARY_OPS,
|
|
1455
1494
|
...BINARY_OPS,
|
|
1456
|
-
...AGGREGATE_OPS
|
|
1495
|
+
...AGGREGATE_OPS,
|
|
1496
|
+
...CONDITIONAL_OPS,
|
|
1497
|
+
...PURE_METHOD_OPS,
|
|
1498
|
+
"call"
|
|
1499
|
+
]);
|
|
1500
|
+
var BLESSED_GLOBALS = new Set([
|
|
1501
|
+
"isNaN",
|
|
1502
|
+
"isFinite",
|
|
1503
|
+
"parseFloat",
|
|
1504
|
+
"parseInt",
|
|
1505
|
+
"encodeURIComponent",
|
|
1506
|
+
"decodeURIComponent",
|
|
1507
|
+
"structuredClone",
|
|
1508
|
+
"Math/abs",
|
|
1509
|
+
"Math/ceil",
|
|
1510
|
+
"Math/floor",
|
|
1511
|
+
"Math/round",
|
|
1512
|
+
"Math/trunc",
|
|
1513
|
+
"Math/sign",
|
|
1514
|
+
"Math/sqrt",
|
|
1515
|
+
"Math/cbrt",
|
|
1516
|
+
"Math/pow",
|
|
1517
|
+
"Math/exp",
|
|
1518
|
+
"Math/log",
|
|
1519
|
+
"Math/log2",
|
|
1520
|
+
"Math/log10",
|
|
1521
|
+
"Math/min",
|
|
1522
|
+
"Math/max",
|
|
1523
|
+
"Math/hypot",
|
|
1524
|
+
"Number/isInteger",
|
|
1525
|
+
"Number/isFinite",
|
|
1526
|
+
"Number/isNaN",
|
|
1527
|
+
"Number/parseFloat",
|
|
1528
|
+
"Number/parseInt",
|
|
1529
|
+
"JSON/parse",
|
|
1530
|
+
"JSON/stringify",
|
|
1531
|
+
"Object/keys",
|
|
1532
|
+
"Object/values",
|
|
1533
|
+
"Object/entries",
|
|
1534
|
+
"Object/fromEntries",
|
|
1535
|
+
"Array/from",
|
|
1536
|
+
"Array/isArray",
|
|
1537
|
+
"Array/of",
|
|
1538
|
+
"String/fromCharCode",
|
|
1539
|
+
"String/fromCodePoint",
|
|
1540
|
+
"Intl/formatNumber",
|
|
1541
|
+
"Intl/formatDate",
|
|
1542
|
+
"Intl/formatRelativeTime"
|
|
1457
1543
|
]);
|
|
1544
|
+
var BLESSED_HELPERS = {
|
|
1545
|
+
"Intl/formatDate": (value, locale, options) => new Intl.DateTimeFormat(locale, options).format(new Date(value)),
|
|
1546
|
+
"Intl/formatNumber": (value, locale, options) => new Intl.NumberFormat(locale, options).format(value),
|
|
1547
|
+
"Intl/formatRelativeTime": (value, unit, locale, options) => new Intl.RelativeTimeFormat(locale, options).format(value, unit)
|
|
1548
|
+
};
|
|
1549
|
+
function isBlessedGlobal(ref2) {
|
|
1550
|
+
return ref2.startsWith("window#/") && BLESSED_GLOBALS.has(ref2.slice("window#/".length));
|
|
1551
|
+
}
|
|
1458
1552
|
function isMutating(op) {
|
|
1459
1553
|
return MUTATING_OPS.has(op);
|
|
1460
1554
|
}
|
|
1461
|
-
|
|
1555
|
+
var MAX_CALL_DEPTH = 64;
|
|
1556
|
+
var MAX_REPORT_DEPTH = 64;
|
|
1557
|
+
function subTrace(trace, seg) {
|
|
1558
|
+
if (!trace) {
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
const depth = (trace.depth ?? 0) + 1;
|
|
1562
|
+
if (depth > MAX_REPORT_DEPTH) {
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
return {
|
|
1566
|
+
depth,
|
|
1567
|
+
path: [...trace.path ?? [], ...Array.isArray(seg) ? seg : [seg]],
|
|
1568
|
+
report: trace.report
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
function resolveOperand(operand, state, event, iterCtx, trace) {
|
|
1462
1572
|
if (operand === null || operand === undefined) {
|
|
1463
1573
|
return operand;
|
|
1464
1574
|
}
|
|
1465
1575
|
if (typeof operand === "object" && !Array.isArray(operand) && "operator" in operand) {
|
|
1466
|
-
return evaluateExpression(operand, state, event, iterCtx);
|
|
1576
|
+
return evaluateExpression(operand, state, event, iterCtx, trace);
|
|
1467
1577
|
}
|
|
1468
1578
|
if (typeof operand === "object" && !Array.isArray(operand) && "$ref" in operand) {
|
|
1469
|
-
|
|
1579
|
+
const resolved = resolveExprRef(operand.$ref, state, event, iterCtx);
|
|
1580
|
+
trace?.report(trace.path ?? [], resolved);
|
|
1581
|
+
return resolved;
|
|
1470
1582
|
}
|
|
1471
1583
|
if (Array.isArray(operand)) {
|
|
1472
|
-
return operand.map((o) => resolveOperand(o, state, event, iterCtx));
|
|
1584
|
+
return operand.map((o, i) => resolveOperand(o, state, event, iterCtx, subTrace(trace, i)));
|
|
1473
1585
|
}
|
|
1586
|
+
trace?.report(trace.path ?? [], operand);
|
|
1474
1587
|
return operand;
|
|
1475
1588
|
}
|
|
1476
1589
|
function resolveExprRef(ref2, state, event, iterCtx) {
|
|
@@ -1480,6 +1593,11 @@ function resolveExprRef(ref2, state, event, iterCtx) {
|
|
|
1480
1593
|
if (ref2.startsWith("$reduce/")) {
|
|
1481
1594
|
return iterCtx?.acc;
|
|
1482
1595
|
}
|
|
1596
|
+
if (ref2.startsWith("$args/")) {
|
|
1597
|
+
const parts = ref2.slice("$args/".length).split("/");
|
|
1598
|
+
const base = iterCtx?.args?.[parts[0]];
|
|
1599
|
+
return parts.length > 1 ? getPath(base, parts.slice(1).join("/")) : base;
|
|
1600
|
+
}
|
|
1483
1601
|
if (ref2.startsWith("event#/")) {
|
|
1484
1602
|
const path = ref2.slice("event#/".length);
|
|
1485
1603
|
return getPath(event, path);
|
|
@@ -1557,13 +1675,18 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
|
|
|
1557
1675
|
}
|
|
1558
1676
|
return { key: ref2, obj: state };
|
|
1559
1677
|
}
|
|
1560
|
-
function evaluateExpression(node, state, event, iterCtx) {
|
|
1678
|
+
function evaluateExpression(node, state, event, iterCtx, trace) {
|
|
1679
|
+
const result = evaluateNode(node, state, event, iterCtx, trace);
|
|
1680
|
+
trace?.report(trace.path ?? [], result);
|
|
1681
|
+
return result;
|
|
1682
|
+
}
|
|
1683
|
+
function evaluateNode(node, state, event, iterCtx, trace) {
|
|
1561
1684
|
const { operator, target, value, initial } = node;
|
|
1562
1685
|
if (!BLESSED_OPERATORS.has(operator)) {
|
|
1563
1686
|
throw new Error(`$expression: unknown operator "${operator}"`);
|
|
1564
1687
|
}
|
|
1565
1688
|
if (UNARY_OPS.has(operator) && !("value" in node)) {
|
|
1566
|
-
const operand = resolveOperand(target, state, event, iterCtx);
|
|
1689
|
+
const operand = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1567
1690
|
if (operator === "!") {
|
|
1568
1691
|
return !operand;
|
|
1569
1692
|
}
|
|
@@ -1571,9 +1694,78 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1571
1694
|
return -operand;
|
|
1572
1695
|
}
|
|
1573
1696
|
}
|
|
1697
|
+
if (operator === "call") {
|
|
1698
|
+
const calleeRef = target?.$ref;
|
|
1699
|
+
if (typeof calleeRef !== "string") {
|
|
1700
|
+
throw new TypeError("$expression: call target must be a $ref pointer");
|
|
1701
|
+
}
|
|
1702
|
+
const callDepth = (iterCtx?.callDepth ?? 0) + 1;
|
|
1703
|
+
if (callDepth > MAX_CALL_DEPTH) {
|
|
1704
|
+
throw new Error(`$expression: call depth exceeded (${MAX_CALL_DEPTH})`);
|
|
1705
|
+
}
|
|
1706
|
+
const argValues = Array.isArray(value) ? value.map((o, i) => resolveOperand(o, state, event, iterCtx, subTrace(trace, ["value", i]))) : [];
|
|
1707
|
+
if (calleeRef.startsWith("window#/")) {
|
|
1708
|
+
if (!isBlessedGlobal(calleeRef)) {
|
|
1709
|
+
throw new Error(`$expression: "${calleeRef}" is not a blessed pure global`);
|
|
1710
|
+
}
|
|
1711
|
+
const globalPath = calleeRef.slice("window#/".length);
|
|
1712
|
+
const helper = BLESSED_HELPERS[globalPath];
|
|
1713
|
+
if (helper) {
|
|
1714
|
+
return helper(...argValues);
|
|
1715
|
+
}
|
|
1716
|
+
const fn = getPath(globalThis.window, globalPath);
|
|
1717
|
+
const lastSlash = globalPath.lastIndexOf("/");
|
|
1718
|
+
const thisArg = lastSlash === -1 ? globalThis.window : getPath(globalThis.window, globalPath.slice(0, lastSlash));
|
|
1719
|
+
return fn.apply(thisArg, argValues);
|
|
1720
|
+
}
|
|
1721
|
+
const callee = resolveExprRef(calleeRef, state, event, iterCtx);
|
|
1722
|
+
if (typeof callee === "function") {
|
|
1723
|
+
return callee(...argValues);
|
|
1724
|
+
}
|
|
1725
|
+
if (callee && typeof callee === "object" && "$expression" in callee) {
|
|
1726
|
+
const def2 = callee;
|
|
1727
|
+
const args = {};
|
|
1728
|
+
for (const [i, p] of (def2.parameters ?? []).entries()) {
|
|
1729
|
+
const name = typeof p === "string" ? p : p?.name ?? "";
|
|
1730
|
+
if (!name) {
|
|
1731
|
+
continue;
|
|
1732
|
+
}
|
|
1733
|
+
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
1734
|
+
}
|
|
1735
|
+
return evaluateExpression(def2.$expression, state, event, { args, callDepth });
|
|
1736
|
+
}
|
|
1737
|
+
throw new TypeError(`$expression: call target "${calleeRef}" is not callable`);
|
|
1738
|
+
}
|
|
1739
|
+
if (CONDITIONAL_OPS.has(operator)) {
|
|
1740
|
+
if (operator === "?:") {
|
|
1741
|
+
const test = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1742
|
+
if (trace) {
|
|
1743
|
+
const consequent = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1744
|
+
const alternate = resolveOperand(initial, state, event, iterCtx, subTrace(trace, "initial"));
|
|
1745
|
+
return test ? consequent : alternate;
|
|
1746
|
+
}
|
|
1747
|
+
return test ? resolveOperand(value, state, event, iterCtx) : resolveOperand(initial, state, event, iterCtx);
|
|
1748
|
+
}
|
|
1749
|
+
const discriminant = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1750
|
+
const key = String(discriminant);
|
|
1751
|
+
const cases = node.cases ?? {};
|
|
1752
|
+
const matched = Object.hasOwn(cases, key);
|
|
1753
|
+
if (trace) {
|
|
1754
|
+
let result;
|
|
1755
|
+
for (const [k, caseOperand] of Object.entries(cases)) {
|
|
1756
|
+
const v = resolveOperand(caseOperand, state, event, iterCtx, subTrace(trace, ["cases", k]));
|
|
1757
|
+
if (k === key) {
|
|
1758
|
+
result = v;
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
const fallback = resolveOperand(node.default, state, event, iterCtx, subTrace(trace, "default"));
|
|
1762
|
+
return matched ? result : fallback;
|
|
1763
|
+
}
|
|
1764
|
+
return matched ? resolveOperand(cases[key], state, event, iterCtx) : resolveOperand(node.default, state, event, iterCtx);
|
|
1765
|
+
}
|
|
1574
1766
|
if (BINARY_OPS.has(operator)) {
|
|
1575
|
-
const left = resolveOperand(target, state, event, iterCtx);
|
|
1576
|
-
const right = resolveOperand(value, state, event, iterCtx);
|
|
1767
|
+
const left = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1768
|
+
const right = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1577
1769
|
switch (operator) {
|
|
1578
1770
|
case "+": {
|
|
1579
1771
|
return left + right;
|
|
@@ -1614,13 +1806,16 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1614
1806
|
case "||": {
|
|
1615
1807
|
return left || right;
|
|
1616
1808
|
}
|
|
1809
|
+
case "??": {
|
|
1810
|
+
return left ?? right;
|
|
1811
|
+
}
|
|
1617
1812
|
default: {
|
|
1618
1813
|
break;
|
|
1619
1814
|
}
|
|
1620
1815
|
}
|
|
1621
1816
|
}
|
|
1622
1817
|
if (ASSIGNMENT_OPS.has(operator)) {
|
|
1623
|
-
const rhs = resolveOperand(value, state, event, iterCtx);
|
|
1818
|
+
const rhs = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1624
1819
|
const { obj, key } = resolveWritableRef(target.$ref, state, event, iterCtx);
|
|
1625
1820
|
switch (operator) {
|
|
1626
1821
|
case "=": {
|
|
@@ -1654,13 +1849,13 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1654
1849
|
return;
|
|
1655
1850
|
}
|
|
1656
1851
|
if (ARRAY_METHOD_OPS.has(operator)) {
|
|
1657
|
-
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1852
|
+
const arr = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1658
1853
|
switch (operator) {
|
|
1659
1854
|
case "push": {
|
|
1660
|
-
return arr.push(resolveOperand(value, state, event, iterCtx));
|
|
1855
|
+
return arr.push(resolveOperand(value, state, event, iterCtx, subTrace(trace, "value")));
|
|
1661
1856
|
}
|
|
1662
1857
|
case "unshift": {
|
|
1663
|
-
return arr.unshift(resolveOperand(value, state, event, iterCtx));
|
|
1858
|
+
return arr.unshift(resolveOperand(value, state, event, iterCtx, subTrace(trace, "value")));
|
|
1664
1859
|
}
|
|
1665
1860
|
case "pop": {
|
|
1666
1861
|
return arr.pop();
|
|
@@ -1669,7 +1864,7 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1669
1864
|
return arr.shift();
|
|
1670
1865
|
}
|
|
1671
1866
|
case "splice": {
|
|
1672
|
-
const args = resolveOperand(value, state, event, iterCtx);
|
|
1867
|
+
const args = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1673
1868
|
return arr.splice(...args);
|
|
1674
1869
|
}
|
|
1675
1870
|
default: {
|
|
@@ -1677,32 +1872,29 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1677
1872
|
}
|
|
1678
1873
|
}
|
|
1679
1874
|
}
|
|
1875
|
+
if (PURE_METHOD_OPS.has(operator)) {
|
|
1876
|
+
const receiver = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1877
|
+
const args = value === undefined ? [] : Array.isArray(value) ? resolveOperand(value, state, event, iterCtx, subTrace(trace, "value")) : [resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"))];
|
|
1878
|
+
const method = receiver?.[operator];
|
|
1879
|
+
if (typeof method !== "function") {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
return method.apply(receiver, args);
|
|
1883
|
+
}
|
|
1680
1884
|
if (AGGREGATE_OPS.has(operator)) {
|
|
1681
|
-
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1885
|
+
const arr = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1682
1886
|
if (operator === "reduce") {
|
|
1683
|
-
let acc = resolveOperand(initial, state, event, iterCtx);
|
|
1887
|
+
let acc = resolveOperand(initial, state, event, iterCtx, subTrace(trace, "initial"));
|
|
1684
1888
|
for (const [index, item] of arr.entries()) {
|
|
1685
|
-
acc = evaluateExpression(value, state, event, {
|
|
1686
|
-
acc,
|
|
1687
|
-
index,
|
|
1688
|
-
item
|
|
1689
|
-
});
|
|
1889
|
+
acc = evaluateExpression(value, state, event, { acc, index, item }, index === 0 ? subTrace(trace, "value") : undefined);
|
|
1690
1890
|
}
|
|
1691
1891
|
return acc;
|
|
1692
1892
|
}
|
|
1693
1893
|
if (operator === "map") {
|
|
1694
|
-
return arr.map((item, index) => evaluateExpression(value, state, event, {
|
|
1695
|
-
...iterCtx,
|
|
1696
|
-
index,
|
|
1697
|
-
item
|
|
1698
|
-
}));
|
|
1894
|
+
return arr.map((item, index) => evaluateExpression(value, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
|
|
1699
1895
|
}
|
|
1700
1896
|
if (operator === "filter") {
|
|
1701
|
-
return arr.filter((item, index) => evaluateExpression(value, state, event, {
|
|
1702
|
-
...iterCtx,
|
|
1703
|
-
index,
|
|
1704
|
-
item
|
|
1705
|
-
}));
|
|
1897
|
+
return arr.filter((item, index) => evaluateExpression(value, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
|
|
1706
1898
|
}
|
|
1707
1899
|
}
|
|
1708
1900
|
return;
|
|
@@ -1714,6 +1906,9 @@ function getPath(obj, path) {
|
|
|
1714
1906
|
}
|
|
1715
1907
|
return current;
|
|
1716
1908
|
}
|
|
1909
|
+
function evaluateOperand(operand, state, event, iterCtx) {
|
|
1910
|
+
return resolveOperand(operand, state, event, iterCtx);
|
|
1911
|
+
}
|
|
1717
1912
|
|
|
1718
1913
|
// ../schema/src/guards.ts
|
|
1719
1914
|
function isJsonObject(value) {
|
|
@@ -1728,6 +1923,12 @@ function isFunctionDef(value) {
|
|
|
1728
1923
|
function isExpressionDef(value) {
|
|
1729
1924
|
return isJsonObject(value) && isJsonObject(value.$expression);
|
|
1730
1925
|
}
|
|
1926
|
+
function isNamedFormulaDef(value) {
|
|
1927
|
+
return isExpressionDef(value) && Array.isArray(value.parameters) && value.parameters.length > 0;
|
|
1928
|
+
}
|
|
1929
|
+
function hasStructuredBody(value) {
|
|
1930
|
+
return isFunctionDef(value) && Array.isArray(value.body);
|
|
1931
|
+
}
|
|
1731
1932
|
function isPrototypeDef(value) {
|
|
1732
1933
|
return isJsonObject(value) && typeof value.$prototype === "string" && value.$prototype !== "Function";
|
|
1733
1934
|
}
|
|
@@ -1763,6 +1964,74 @@ function paramNames(parameters) {
|
|
|
1763
1964
|
return parameters.map((p) => typeof p === "string" ? p : p.name);
|
|
1764
1965
|
}
|
|
1765
1966
|
|
|
1967
|
+
// ../runtime/src/statements.ts
|
|
1968
|
+
function statementKind(statement) {
|
|
1969
|
+
if ("operator" in statement) {
|
|
1970
|
+
return "expression";
|
|
1971
|
+
}
|
|
1972
|
+
if ("if" in statement) {
|
|
1973
|
+
return "if";
|
|
1974
|
+
}
|
|
1975
|
+
if ("$switch" in statement) {
|
|
1976
|
+
return "switch";
|
|
1977
|
+
}
|
|
1978
|
+
return "dispatch";
|
|
1979
|
+
}
|
|
1980
|
+
async function runStatements(statements, state, event, opts = {}) {
|
|
1981
|
+
const iterCtx = opts.args ? { args: opts.args } : undefined;
|
|
1982
|
+
for (const statement of statements) {
|
|
1983
|
+
switch (statementKind(statement)) {
|
|
1984
|
+
case "expression": {
|
|
1985
|
+
const result = evaluateExpression(statement, state, event, iterCtx);
|
|
1986
|
+
if (result && typeof result.then === "function") {
|
|
1987
|
+
await result;
|
|
1988
|
+
}
|
|
1989
|
+
break;
|
|
1990
|
+
}
|
|
1991
|
+
case "if": {
|
|
1992
|
+
const branch = statement;
|
|
1993
|
+
const taken = evaluateOperand(branch.if, state, event, iterCtx) ? branch.then : branch.else;
|
|
1994
|
+
if (Array.isArray(taken)) {
|
|
1995
|
+
await runStatements(taken, state, event, opts);
|
|
1996
|
+
}
|
|
1997
|
+
break;
|
|
1998
|
+
}
|
|
1999
|
+
case "switch": {
|
|
2000
|
+
const branch = statement;
|
|
2001
|
+
const key = String(evaluateOperand(branch.$switch, state, event, iterCtx));
|
|
2002
|
+
const cases = branch.cases ?? {};
|
|
2003
|
+
const taken = Object.hasOwn(cases, key) ? cases[key] : branch.default;
|
|
2004
|
+
if (Array.isArray(taken)) {
|
|
2005
|
+
await runStatements(taken, state, event, opts);
|
|
2006
|
+
}
|
|
2007
|
+
break;
|
|
2008
|
+
}
|
|
2009
|
+
case "dispatch": {
|
|
2010
|
+
const dispatch = statement;
|
|
2011
|
+
const target = opts.target ?? event?.currentTarget;
|
|
2012
|
+
if (!target) {
|
|
2013
|
+
break;
|
|
2014
|
+
}
|
|
2015
|
+
const init = {};
|
|
2016
|
+
if ("detail" in dispatch) {
|
|
2017
|
+
init.detail = evaluateOperand(dispatch.detail, state, event, iterCtx);
|
|
2018
|
+
}
|
|
2019
|
+
if (dispatch.bubbles !== undefined) {
|
|
2020
|
+
init.bubbles = dispatch.bubbles;
|
|
2021
|
+
}
|
|
2022
|
+
if (dispatch.composed !== undefined) {
|
|
2023
|
+
init.composed = dispatch.composed;
|
|
2024
|
+
}
|
|
2025
|
+
target.dispatchEvent(new CustomEvent(dispatch.dispatchEvent, init));
|
|
2026
|
+
break;
|
|
2027
|
+
}
|
|
2028
|
+
default: {
|
|
2029
|
+
break;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
|
|
1766
2035
|
// ../runtime/src/runtime.ts
|
|
1767
2036
|
var _resolveCache = new Map;
|
|
1768
2037
|
async function resolve(source) {
|
|
@@ -1851,6 +2120,37 @@ function canvasAttrName(el, key) {
|
|
|
1851
2120
|
}
|
|
1852
2121
|
return key;
|
|
1853
2122
|
}
|
|
2123
|
+
var _stampPropBindings = false;
|
|
2124
|
+
function setStampPropBindings(on) {
|
|
2125
|
+
_stampPropBindings = on;
|
|
2126
|
+
}
|
|
2127
|
+
var PURE_STATE_TEMPLATE = /^\s*\$\{\s*state\.(\w+)\s*\}\s*$/;
|
|
2128
|
+
function boundPropKey(key, val, state) {
|
|
2129
|
+
if (!_stampPropBindings || key !== "textContent") {
|
|
2130
|
+
return null;
|
|
2131
|
+
}
|
|
2132
|
+
let sub = null;
|
|
2133
|
+
if (isRefObj(val)) {
|
|
2134
|
+
if (!val.$ref.startsWith("#/state/")) {
|
|
2135
|
+
return null;
|
|
2136
|
+
}
|
|
2137
|
+
const rest = val.$ref.slice("#/state/".length);
|
|
2138
|
+
sub = rest && !rest.includes("/") ? rest : null;
|
|
2139
|
+
} else if (typeof val === "string") {
|
|
2140
|
+
sub = PURE_STATE_TEMPLATE.exec(val)?.[1] ?? null;
|
|
2141
|
+
}
|
|
2142
|
+
if (!sub) {
|
|
2143
|
+
return null;
|
|
2144
|
+
}
|
|
2145
|
+
const stored = toRaw(state)[sub];
|
|
2146
|
+
if (isRef(stored) || typeof stored === "function") {
|
|
2147
|
+
return null;
|
|
2148
|
+
}
|
|
2149
|
+
if (typeof stored === "object" && stored !== null) {
|
|
2150
|
+
return null;
|
|
2151
|
+
}
|
|
2152
|
+
return sub;
|
|
2153
|
+
}
|
|
1854
2154
|
async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
1855
2155
|
const raw = {};
|
|
1856
2156
|
for (const [key, val] of Object.entries(parentScope)) {
|
|
@@ -1914,7 +2214,20 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1914
2214
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1915
2215
|
if (isExpressionDef(def2)) {
|
|
1916
2216
|
const node = def2.$expression;
|
|
1917
|
-
if (
|
|
2217
|
+
if (isNamedFormulaDef(def2)) {
|
|
2218
|
+
const params = def2.parameters;
|
|
2219
|
+
state[key] = (...argValues) => {
|
|
2220
|
+
const args = {};
|
|
2221
|
+
for (const [i, p] of params.entries()) {
|
|
2222
|
+
const name = typeof p === "string" ? p : p?.name ?? "";
|
|
2223
|
+
if (!name) {
|
|
2224
|
+
continue;
|
|
2225
|
+
}
|
|
2226
|
+
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
2227
|
+
}
|
|
2228
|
+
return evaluateExpression(node, state, null, { args });
|
|
2229
|
+
};
|
|
2230
|
+
} else if (isMutating(node.operator)) {
|
|
1918
2231
|
const handler = (s, event) => evaluateExpression(node, s, event);
|
|
1919
2232
|
state[key] = handler;
|
|
1920
2233
|
} else {
|
|
@@ -1923,7 +2236,28 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1923
2236
|
}
|
|
1924
2237
|
}
|
|
1925
2238
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1926
|
-
if (
|
|
2239
|
+
if (hasStructuredBody(def2)) {
|
|
2240
|
+
const { body } = def2;
|
|
2241
|
+
if (Array.isArray(def2.parameters) && def2.parameters.length > 0) {
|
|
2242
|
+
const params = def2.parameters;
|
|
2243
|
+
state[key] = (...argValues) => {
|
|
2244
|
+
const args = {};
|
|
2245
|
+
for (const [i, p] of params.entries()) {
|
|
2246
|
+
const name = typeof p === "string" ? p : p?.name ?? "";
|
|
2247
|
+
if (!name) {
|
|
2248
|
+
continue;
|
|
2249
|
+
}
|
|
2250
|
+
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
2251
|
+
}
|
|
2252
|
+
return runStatements(body, state, null, { args });
|
|
2253
|
+
};
|
|
2254
|
+
} else {
|
|
2255
|
+
const handler = (s, event) => {
|
|
2256
|
+
runStatements(body, s, event ?? null);
|
|
2257
|
+
};
|
|
2258
|
+
state[key] = handler;
|
|
2259
|
+
}
|
|
2260
|
+
} else if (isFunctionDef(def2)) {
|
|
1927
2261
|
state[key] = await resolveFunction(def2, state, key, base);
|
|
1928
2262
|
}
|
|
1929
2263
|
}
|
|
@@ -1974,7 +2308,7 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
1974
2308
|
return noop;
|
|
1975
2309
|
}
|
|
1976
2310
|
let fn;
|
|
1977
|
-
if (def2.body) {
|
|
2311
|
+
if (typeof def2.body === "string") {
|
|
1978
2312
|
const params = resolveParamNames(def2);
|
|
1979
2313
|
fn = new Function(...params, def2.body);
|
|
1980
2314
|
Object.defineProperty(fn, "name", {
|
|
@@ -2012,7 +2346,7 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
2012
2346
|
const hasParams = (def2.parameters ?? def2.arguments ?? []).length > 0;
|
|
2013
2347
|
let isComputed = false;
|
|
2014
2348
|
if (!hasParams) {
|
|
2015
|
-
if (def2.body) {
|
|
2349
|
+
if (typeof def2.body === "string") {
|
|
2016
2350
|
isComputed = /\breturn\b/.test(def2.body);
|
|
2017
2351
|
} else if (fn) {
|
|
2018
2352
|
isComputed = fn.length <= 1 && /\breturn\b/.test(fn.toString());
|
|
@@ -2138,7 +2472,15 @@ function applyProperties(el, def2, state) {
|
|
|
2138
2472
|
}
|
|
2139
2473
|
continue;
|
|
2140
2474
|
}
|
|
2141
|
-
if (
|
|
2475
|
+
if (hasStructuredBody(val)) {
|
|
2476
|
+
const { body } = val;
|
|
2477
|
+
const scope = state;
|
|
2478
|
+
el.addEventListener(key.slice(2), (e) => {
|
|
2479
|
+
runStatements(body, scope, e);
|
|
2480
|
+
});
|
|
2481
|
+
continue;
|
|
2482
|
+
}
|
|
2483
|
+
if (isFunctionDef(val) && typeof val.body === "string") {
|
|
2142
2484
|
const params = resolveParamNames(val);
|
|
2143
2485
|
const fn = new Function(...params, val.body);
|
|
2144
2486
|
const scope = state;
|
|
@@ -2157,6 +2499,10 @@ function applyProperties(el, def2, state) {
|
|
|
2157
2499
|
}
|
|
2158
2500
|
function bindProperty(el, key, val, state) {
|
|
2159
2501
|
const target = el;
|
|
2502
|
+
const boundProp = boundPropKey(key, val, state);
|
|
2503
|
+
if (boundProp) {
|
|
2504
|
+
el.dataset.jxBoundProp = boundProp;
|
|
2505
|
+
}
|
|
2160
2506
|
if (isRefObj(val)) {
|
|
2161
2507
|
const refVal = val;
|
|
2162
2508
|
if (key === "id") {
|
|
@@ -3304,6 +3650,18 @@ var EDIT_PLACEHOLDER_CSS = `
|
|
|
3304
3650
|
font-size: 13px;
|
|
3305
3651
|
pointer-events: none;
|
|
3306
3652
|
}
|
|
3653
|
+
[data-jx-bound-prop]:hover {
|
|
3654
|
+
cursor: text;
|
|
3655
|
+
outline: 1px dashed color-mix(in srgb, #808080 40%, transparent);
|
|
3656
|
+
outline-offset: 1px;
|
|
3657
|
+
}
|
|
3658
|
+
[data-jx-bound-prop]:empty:not([contenteditable="plaintext-only"]):not([contenteditable="true"])::after {
|
|
3659
|
+
content: "Empty \\2014 double-click to edit";
|
|
3660
|
+
color: color-mix(in srgb, #808080 40%, transparent);
|
|
3661
|
+
font-style: italic;
|
|
3662
|
+
font-size: 13px;
|
|
3663
|
+
pointer-events: none;
|
|
3664
|
+
}
|
|
3307
3665
|
`;
|
|
3308
3666
|
function syncEditModeCss(doc, mode) {
|
|
3309
3667
|
const existing = doc.head.querySelector(`#${EDIT_PLACEHOLDER_STYLE_ID}`);
|
|
@@ -3509,6 +3867,7 @@ async function renderResolvedDocument(opts) {
|
|
|
3509
3867
|
setSkipServerFunctions(opts.mode !== "preview");
|
|
3510
3868
|
setCanvasViewportTranspose(true);
|
|
3511
3869
|
setCanvasDelinkAnchors(opts.mode !== "preview");
|
|
3870
|
+
setStampPropBindings(opts.mode === "design" || opts.mode === "edit");
|
|
3512
3871
|
applySiteStyle(opts.siteStyle);
|
|
3513
3872
|
injectHead(opts.doc);
|
|
3514
3873
|
syncEditModeCss(opts.container.ownerDocument, opts.mode);
|
|
@@ -4073,6 +4432,8 @@ var splitFn = null;
|
|
|
4073
4432
|
var insertFn = null;
|
|
4074
4433
|
var endFn = null;
|
|
4075
4434
|
var _blurCloseSuspended = false;
|
|
4435
|
+
var _plainMode = false;
|
|
4436
|
+
var _plainOriginal = "";
|
|
4076
4437
|
function suspendBlurClose() {
|
|
4077
4438
|
_blurCloseSuspended = true;
|
|
4078
4439
|
}
|
|
@@ -4082,7 +4443,7 @@ function resumeBlurClose() {
|
|
|
4082
4443
|
function isEditableBlock(el) {
|
|
4083
4444
|
return EDITABLE_BLOCKS.has(el.tagName.toLowerCase());
|
|
4084
4445
|
}
|
|
4085
|
-
function startEditing(el, path, callbacks) {
|
|
4446
|
+
function startEditing(el, path, callbacks, opts) {
|
|
4086
4447
|
if (activeEl) {
|
|
4087
4448
|
stopEditing(true);
|
|
4088
4449
|
}
|
|
@@ -4092,7 +4453,17 @@ function startEditing(el, path, callbacks) {
|
|
|
4092
4453
|
splitFn = callbacks.onSplit;
|
|
4093
4454
|
insertFn = callbacks.onInsert;
|
|
4094
4455
|
endFn = callbacks.onEnd;
|
|
4095
|
-
|
|
4456
|
+
_plainMode = opts?.plainText === true;
|
|
4457
|
+
_plainOriginal = _plainMode ? el.textContent ?? "" : "";
|
|
4458
|
+
if (_plainMode) {
|
|
4459
|
+
try {
|
|
4460
|
+
el.contentEditable = "plaintext-only";
|
|
4461
|
+
} catch {
|
|
4462
|
+
el.contentEditable = "true";
|
|
4463
|
+
}
|
|
4464
|
+
} else {
|
|
4465
|
+
el.contentEditable = "true";
|
|
4466
|
+
}
|
|
4096
4467
|
el.style.pointerEvents = "auto";
|
|
4097
4468
|
el.style.outline = "2px solid var(--accent, #4a9eff)";
|
|
4098
4469
|
el.style.outlineOffset = "1px";
|
|
@@ -4131,6 +4502,8 @@ function stopEditing(silent = false) {
|
|
|
4131
4502
|
commitFn = null;
|
|
4132
4503
|
splitFn = null;
|
|
4133
4504
|
insertFn = null;
|
|
4505
|
+
_plainMode = false;
|
|
4506
|
+
_plainOriginal = "";
|
|
4134
4507
|
if (silent) {
|
|
4135
4508
|
endFn = null;
|
|
4136
4509
|
} else if (endFn) {
|
|
@@ -4152,6 +4525,27 @@ function isSlashActive() {
|
|
|
4152
4525
|
return slash.isOpen();
|
|
4153
4526
|
}
|
|
4154
4527
|
function handleKeydown(e) {
|
|
4528
|
+
if (_plainMode) {
|
|
4529
|
+
if (e.key === "Escape") {
|
|
4530
|
+
e.preventDefault();
|
|
4531
|
+
e.stopPropagation();
|
|
4532
|
+
if (activeEl) {
|
|
4533
|
+
activeEl.textContent = _plainOriginal;
|
|
4534
|
+
}
|
|
4535
|
+
stopEditing();
|
|
4536
|
+
return;
|
|
4537
|
+
}
|
|
4538
|
+
if (e.key === "Enter") {
|
|
4539
|
+
e.preventDefault();
|
|
4540
|
+
e.stopPropagation();
|
|
4541
|
+
stopEditing();
|
|
4542
|
+
return;
|
|
4543
|
+
}
|
|
4544
|
+
if ((e.ctrlKey || e.metaKey) && ["b", "i", "u", "`"].includes(e.key)) {
|
|
4545
|
+
e.preventDefault();
|
|
4546
|
+
}
|
|
4547
|
+
return;
|
|
4548
|
+
}
|
|
4155
4549
|
if (e.key === "Escape") {
|
|
4156
4550
|
e.preventDefault();
|
|
4157
4551
|
e.stopPropagation();
|
|
@@ -4271,6 +4665,11 @@ function commitChanges() {
|
|
|
4271
4665
|
if (!commitFn || !activeEl || !activePath) {
|
|
4272
4666
|
return;
|
|
4273
4667
|
}
|
|
4668
|
+
if (_plainMode) {
|
|
4669
|
+
commitFn(activePath, null, (activeEl.textContent ?? "").replaceAll(`
|
|
4670
|
+
`, " "));
|
|
4671
|
+
return;
|
|
4672
|
+
}
|
|
4274
4673
|
normalizeInlineContent(activeEl);
|
|
4275
4674
|
const result = elementToJx(activeEl);
|
|
4276
4675
|
commitFn(activePath, result.children ?? null, result.textContent ?? null);
|
|
@@ -5152,6 +5551,31 @@ function findEditableTarget(target) {
|
|
|
5152
5551
|
}
|
|
5153
5552
|
return null;
|
|
5154
5553
|
}
|
|
5554
|
+
function findPropBoundTarget(target) {
|
|
5555
|
+
let el = target instanceof Element ? target : null;
|
|
5556
|
+
while (el) {
|
|
5557
|
+
if (el instanceof HTMLElement) {
|
|
5558
|
+
if (el.dataset.jxBoundProp) {
|
|
5559
|
+
return { el, prop: el.dataset.jxBoundProp };
|
|
5560
|
+
}
|
|
5561
|
+
if (el.dataset.jxPath) {
|
|
5562
|
+
return null;
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
el = el.parentElement;
|
|
5566
|
+
}
|
|
5567
|
+
return null;
|
|
5568
|
+
}
|
|
5569
|
+
function ownerInstanceOf(el) {
|
|
5570
|
+
let cur = el.parentElement;
|
|
5571
|
+
while (cur) {
|
|
5572
|
+
if (cur.tagName.includes("-")) {
|
|
5573
|
+
return cur;
|
|
5574
|
+
}
|
|
5575
|
+
cur = cur.parentElement;
|
|
5576
|
+
}
|
|
5577
|
+
return null;
|
|
5578
|
+
}
|
|
5155
5579
|
function elementForPath(container, path) {
|
|
5156
5580
|
const serialized = serializeJxPath(path);
|
|
5157
5581
|
const esc = serialized.replaceAll("\\", String.raw`\\`).replaceAll("'", String.raw`\'`);
|
|
@@ -5268,6 +5692,36 @@ function startIframeInlineEdit(channel, container, opts) {
|
|
|
5268
5692
|
cacheRange();
|
|
5269
5693
|
onSelectionChange();
|
|
5270
5694
|
};
|
|
5695
|
+
const propEditableAt = (hostPath, prop) => {
|
|
5696
|
+
const shadowDoc = opts?.getShadowDoc?.();
|
|
5697
|
+
if (!shadowDoc) {
|
|
5698
|
+
return true;
|
|
5699
|
+
}
|
|
5700
|
+
const node = getNodeAtPath(shadowDoc, hostPath);
|
|
5701
|
+
const raw = node?.$props?.[prop];
|
|
5702
|
+
if (raw == null) {
|
|
5703
|
+
return true;
|
|
5704
|
+
}
|
|
5705
|
+
if (typeof raw === "object") {
|
|
5706
|
+
return false;
|
|
5707
|
+
}
|
|
5708
|
+
return !(typeof raw === "string" && raw.includes("${"));
|
|
5709
|
+
};
|
|
5710
|
+
const enterPropEditAt = (el, hostPath, prop) => {
|
|
5711
|
+
channel.post({ kind: "editStart", path: hostPath, prop });
|
|
5712
|
+
suspendBlurClose();
|
|
5713
|
+
startEditing(el, hostPath, {
|
|
5714
|
+
onCommit: (p, _children, textContent) => channel.post({ kind: "editCommitProp", path: p, prop, value: textContent ?? "" }),
|
|
5715
|
+
onEnd: () => {
|
|
5716
|
+
resumeBlurClose();
|
|
5717
|
+
clearHighlight();
|
|
5718
|
+
lastNonEmptyRange = null;
|
|
5719
|
+
channel.post({ kind: "editEnd" });
|
|
5720
|
+
},
|
|
5721
|
+
onInsert: () => {},
|
|
5722
|
+
onSplit: () => {}
|
|
5723
|
+
}, { plainText: true });
|
|
5724
|
+
};
|
|
5271
5725
|
const applyFormatIntent = (intent) => {
|
|
5272
5726
|
const el = getActiveElement();
|
|
5273
5727
|
if (!el) {
|
|
@@ -5296,6 +5750,18 @@ function startIframeInlineEdit(channel, container, opts) {
|
|
|
5296
5750
|
if (!editingAllowed()) {
|
|
5297
5751
|
return;
|
|
5298
5752
|
}
|
|
5753
|
+
const propHit = findPropBoundTarget(e.target);
|
|
5754
|
+
if (propHit) {
|
|
5755
|
+
const host = ownerInstanceOf(propHit.el);
|
|
5756
|
+
const hostPathRaw = host?.dataset.jxPath;
|
|
5757
|
+
if (host && hostPathRaw) {
|
|
5758
|
+
const hostPath = parseJxPath(hostPathRaw);
|
|
5759
|
+
if (propEditableAt(hostPath, propHit.prop)) {
|
|
5760
|
+
enterPropEditAt(propHit.el, hostPath, propHit.prop);
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
return;
|
|
5764
|
+
}
|
|
5299
5765
|
const hit = findEditableTarget(e.target);
|
|
5300
5766
|
if (hit) {
|
|
5301
5767
|
enterEditAt(hit.el, hit.path);
|
|
@@ -5850,6 +6316,107 @@ function textDisplayValue(node) {
|
|
|
5850
6316
|
return String(v);
|
|
5851
6317
|
}
|
|
5852
6318
|
|
|
6319
|
+
// src/utils/preview-format.ts
|
|
6320
|
+
var MAX_BADGE_LENGTH = 48;
|
|
6321
|
+
function formatPreviewValue(value) {
|
|
6322
|
+
if (value === undefined) {
|
|
6323
|
+
return "undefined";
|
|
6324
|
+
}
|
|
6325
|
+
let text;
|
|
6326
|
+
try {
|
|
6327
|
+
text = typeof value === "string" ? JSON.stringify(value) : JSON.stringify(value) ?? "undefined";
|
|
6328
|
+
} catch {
|
|
6329
|
+
text = String(value);
|
|
6330
|
+
}
|
|
6331
|
+
if (text.length > MAX_BADGE_LENGTH) {
|
|
6332
|
+
text = `${text.slice(0, MAX_BADGE_LENGTH - 1)}…`;
|
|
6333
|
+
}
|
|
6334
|
+
return text;
|
|
6335
|
+
}
|
|
6336
|
+
|
|
6337
|
+
// src/canvas/iframe-eval.ts
|
|
6338
|
+
function isNamedFormulaEntry(entry) {
|
|
6339
|
+
return typeof entry === "object" && entry !== null && !Array.isArray(entry) && "$expression" in entry && Array.isArray(entry.parameters);
|
|
6340
|
+
}
|
|
6341
|
+
function cloneLiveScope(defs, rawState) {
|
|
6342
|
+
const out = {};
|
|
6343
|
+
for (const key of Object.keys(defs)) {
|
|
6344
|
+
try {
|
|
6345
|
+
const value = defs[key];
|
|
6346
|
+
if (typeof value === "function") {
|
|
6347
|
+
if (isNamedFormulaEntry(rawState?.[key])) {
|
|
6348
|
+
out[key] = value;
|
|
6349
|
+
}
|
|
6350
|
+
continue;
|
|
6351
|
+
}
|
|
6352
|
+
const json = JSON.stringify(value);
|
|
6353
|
+
out[key] = json === undefined ? null : JSON.parse(json);
|
|
6354
|
+
} catch {
|
|
6355
|
+
out[key] = null;
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6358
|
+
return out;
|
|
6359
|
+
}
|
|
6360
|
+
function bindRepeaterContext(scope, shadowDoc, contextPath) {
|
|
6361
|
+
if (!contextPath || contextPath.length === 0) {
|
|
6362
|
+
return scope;
|
|
6363
|
+
}
|
|
6364
|
+
let node = shadowDoc;
|
|
6365
|
+
let bound = scope;
|
|
6366
|
+
for (const seg of contextPath) {
|
|
6367
|
+
if (!node || typeof node !== "object") {
|
|
6368
|
+
break;
|
|
6369
|
+
}
|
|
6370
|
+
const rec = node;
|
|
6371
|
+
if (rec.$prototype === "Array" && seg === "map") {
|
|
6372
|
+
const itemsDef = rec.items;
|
|
6373
|
+
const items = itemsDef && typeof itemsDef === "object" && "$ref" in itemsDef ? resolveRef(itemsDef.$ref, bound) : itemsDef;
|
|
6374
|
+
if (Array.isArray(items) && items.length > 0) {
|
|
6375
|
+
let item;
|
|
6376
|
+
try {
|
|
6377
|
+
item = structuredClone(items[0]);
|
|
6378
|
+
} catch {
|
|
6379
|
+
item = null;
|
|
6380
|
+
}
|
|
6381
|
+
const child = Object.create(bound);
|
|
6382
|
+
child.$map = { index: 0, item };
|
|
6383
|
+
child["$map/item"] = item;
|
|
6384
|
+
child["$map/index"] = 0;
|
|
6385
|
+
bound = child;
|
|
6386
|
+
}
|
|
6387
|
+
}
|
|
6388
|
+
node = rec[seg];
|
|
6389
|
+
}
|
|
6390
|
+
return bound;
|
|
6391
|
+
}
|
|
6392
|
+
function evaluateLiveExprs(exprs, defs, shadowDoc, contextPath) {
|
|
6393
|
+
const rawState = shadowDoc && typeof shadowDoc === "object" ? shadowDoc.state ?? null : null;
|
|
6394
|
+
return exprs.map(({ id, node }) => {
|
|
6395
|
+
const values = new Map;
|
|
6396
|
+
let scope;
|
|
6397
|
+
try {
|
|
6398
|
+
scope = bindRepeaterContext(cloneLiveScope(defs, rawState), shadowDoc, contextPath);
|
|
6399
|
+
} catch (error) {
|
|
6400
|
+
return { error: error instanceof Error ? error.message : String(error), id, values: [] };
|
|
6401
|
+
}
|
|
6402
|
+
try {
|
|
6403
|
+
if (!node || typeof node !== "object" || !("operator" in node)) {
|
|
6404
|
+
throw new Error("not an expression node");
|
|
6405
|
+
}
|
|
6406
|
+
evaluateExpression(node, scope, null, undefined, {
|
|
6407
|
+
report: (path, value) => values.set(path.join("/"), formatPreviewValue(value))
|
|
6408
|
+
});
|
|
6409
|
+
return { id, values: [...values.entries()] };
|
|
6410
|
+
} catch (error) {
|
|
6411
|
+
return {
|
|
6412
|
+
error: error instanceof Error ? error.message : String(error),
|
|
6413
|
+
id,
|
|
6414
|
+
values: [...values.entries()]
|
|
6415
|
+
};
|
|
6416
|
+
}
|
|
6417
|
+
});
|
|
6418
|
+
}
|
|
6419
|
+
|
|
5853
6420
|
// src/canvas/serialize-scope.ts
|
|
5854
6421
|
var MAX_VALUE_CHARS = 256000;
|
|
5855
6422
|
var LARGE_VALUE_PLACEHOLDER = "[large value omitted]";
|
|
@@ -5983,7 +6550,8 @@ function startCanvasIframe(opts) {
|
|
|
5983
6550
|
});
|
|
5984
6551
|
const stopKeyForwarding = startKeyForwarding(channel, container.ownerDocument);
|
|
5985
6552
|
const stopInlineEdit = startIframeInlineEdit(channel, container, {
|
|
5986
|
-
getMode: () => currentMode
|
|
6553
|
+
getMode: () => currentMode,
|
|
6554
|
+
getShadowDoc: () => shadowDoc
|
|
5987
6555
|
});
|
|
5988
6556
|
const stopSlashBridge = startIframeSlashBridge(channel, container.ownerDocument);
|
|
5989
6557
|
const stopGrabDetector = startGrabDetector(channel, container.ownerDocument, {
|
|
@@ -6074,6 +6642,11 @@ function startCanvasIframe(opts) {
|
|
|
6074
6642
|
});
|
|
6075
6643
|
return;
|
|
6076
6644
|
}
|
|
6645
|
+
if (msg.kind === "evalExpr") {
|
|
6646
|
+
const results = msg.gen === renderedGen && renderCtx && shadowDoc ? evaluateLiveExprs(msg.exprs, renderCtx.defs, shadowDoc, msg.contextPath) : [];
|
|
6647
|
+
channel.post({ gen: msg.gen, kind: "evalResult", reqId: msg.reqId, results });
|
|
6648
|
+
return;
|
|
6649
|
+
}
|
|
6077
6650
|
if (msg.kind === "patch") {
|
|
6078
6651
|
const { gen: gen2 } = msg;
|
|
6079
6652
|
if (gen2 < renderedGen) {
|
|
@@ -6243,5 +6816,5 @@ export {
|
|
|
6243
6816
|
bootCanvasIframe
|
|
6244
6817
|
};
|
|
6245
6818
|
|
|
6246
|
-
//# debugId=
|
|
6819
|
+
//# debugId=861006CEFE04044264756E2164756E21
|
|
6247
6820
|
//# sourceMappingURL=iframe-entry.js.map
|