system-canvas-standalone 0.1.2 → 0.2.2
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/system-canvas.js +863 -197
- package/dist/system-canvas.js.map +1 -1
- package/dist/system-canvas.min.js +10 -10
- package/dist/system-canvas.min.js.map +1 -1
- package/package.json +22 -6
package/dist/system-canvas.js
CHANGED
|
@@ -12759,12 +12759,12 @@ var SystemCanvas = (() => {
|
|
|
12759
12759
|
render: () => render,
|
|
12760
12760
|
themes: () => themes
|
|
12761
12761
|
});
|
|
12762
|
-
var
|
|
12762
|
+
var import_react24 = __toESM(require_react(), 1);
|
|
12763
12763
|
var import_client = __toESM(require_client(), 1);
|
|
12764
12764
|
|
|
12765
12765
|
// ../react/dist/components/SystemCanvas.js
|
|
12766
|
-
var
|
|
12767
|
-
var
|
|
12766
|
+
var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
|
|
12767
|
+
var import_react21 = __toESM(require_react(), 1);
|
|
12768
12768
|
|
|
12769
12769
|
// ../core/dist/themes/dark.js
|
|
12770
12770
|
var darkTheme = {
|
|
@@ -12827,6 +12827,25 @@ var SystemCanvas = (() => {
|
|
|
12827
12827
|
fontFamily: "'JetBrains Mono', 'Fira Code', 'SF Mono', monospace",
|
|
12828
12828
|
fontSize: 12
|
|
12829
12829
|
},
|
|
12830
|
+
contextMenu: {
|
|
12831
|
+
background: "rgba(15, 23, 42, 0.96)",
|
|
12832
|
+
// slate-900 near-opaque
|
|
12833
|
+
borderColor: "rgba(71, 85, 105, 0.6)",
|
|
12834
|
+
// slate-600
|
|
12835
|
+
borderRadius: 8,
|
|
12836
|
+
itemColor: "#e2e8f0",
|
|
12837
|
+
// slate-200
|
|
12838
|
+
itemHoverBackground: "rgba(71, 85, 105, 0.35)",
|
|
12839
|
+
destructiveItemColor: "#fb7185",
|
|
12840
|
+
// rose-400
|
|
12841
|
+
fontFamily: "'JetBrains Mono', 'Fira Code', 'SF Mono', monospace",
|
|
12842
|
+
fontSize: 12,
|
|
12843
|
+
paddingY: 4,
|
|
12844
|
+
paddingX: 4,
|
|
12845
|
+
itemPaddingY: 5,
|
|
12846
|
+
itemPaddingX: 10,
|
|
12847
|
+
shadow: "0 8px 24px rgba(0,0,0,0.35)"
|
|
12848
|
+
},
|
|
12830
12849
|
lanes: {
|
|
12831
12850
|
bandFillEven: "rgba(30, 41, 59, 0.18)",
|
|
12832
12851
|
// slate-800 soft
|
|
@@ -12912,6 +12931,21 @@ var SystemCanvas = (() => {
|
|
|
12912
12931
|
fontFamily: "'JetBrains Mono', monospace",
|
|
12913
12932
|
fontSize: 11
|
|
12914
12933
|
},
|
|
12934
|
+
contextMenu: {
|
|
12935
|
+
background: "rgba(0, 0, 0, 0.96)",
|
|
12936
|
+
borderColor: "rgba(55, 65, 81, 0.7)",
|
|
12937
|
+
borderRadius: 6,
|
|
12938
|
+
itemColor: "#d1d5db",
|
|
12939
|
+
itemHoverBackground: "rgba(0, 255, 136, 0.12)",
|
|
12940
|
+
destructiveItemColor: "#f87171",
|
|
12941
|
+
fontFamily: "'JetBrains Mono', monospace",
|
|
12942
|
+
fontSize: 11,
|
|
12943
|
+
paddingY: 3,
|
|
12944
|
+
paddingX: 3,
|
|
12945
|
+
itemPaddingY: 5,
|
|
12946
|
+
itemPaddingX: 10,
|
|
12947
|
+
shadow: "0 8px 24px rgba(0,255,136,0.08)"
|
|
12948
|
+
},
|
|
12915
12949
|
lanes: {
|
|
12916
12950
|
bandFillEven: "rgba(17, 17, 17, 0.7)",
|
|
12917
12951
|
bandFillOdd: "rgba(0, 0, 0, 0)",
|
|
@@ -12998,6 +13032,21 @@ var SystemCanvas = (() => {
|
|
|
12998
13032
|
fontFamily: "'Inter', 'Helvetica Neue', sans-serif",
|
|
12999
13033
|
fontSize: 12
|
|
13000
13034
|
},
|
|
13035
|
+
contextMenu: {
|
|
13036
|
+
background: "rgba(255, 255, 255, 0.98)",
|
|
13037
|
+
borderColor: "rgba(203, 213, 225, 0.9)",
|
|
13038
|
+
borderRadius: 8,
|
|
13039
|
+
itemColor: "#1e293b",
|
|
13040
|
+
itemHoverBackground: "rgba(148, 163, 184, 0.18)",
|
|
13041
|
+
destructiveItemColor: "#dc2626",
|
|
13042
|
+
fontFamily: "'Inter', 'Helvetica Neue', sans-serif",
|
|
13043
|
+
fontSize: 12,
|
|
13044
|
+
paddingY: 4,
|
|
13045
|
+
paddingX: 4,
|
|
13046
|
+
itemPaddingY: 5,
|
|
13047
|
+
itemPaddingX: 10,
|
|
13048
|
+
shadow: "0 8px 24px rgba(15,23,42,0.12)"
|
|
13049
|
+
},
|
|
13001
13050
|
lanes: {
|
|
13002
13051
|
bandFillEven: "rgba(148, 163, 184, 0.10)",
|
|
13003
13052
|
// slate-400 soft
|
|
@@ -13077,6 +13126,21 @@ var SystemCanvas = (() => {
|
|
|
13077
13126
|
fontFamily: "'JetBrains Mono', monospace",
|
|
13078
13127
|
fontSize: 11
|
|
13079
13128
|
},
|
|
13129
|
+
contextMenu: {
|
|
13130
|
+
background: "rgba(10, 22, 40, 0.97)",
|
|
13131
|
+
borderColor: "rgba(74, 144, 217, 0.45)",
|
|
13132
|
+
borderRadius: 6,
|
|
13133
|
+
itemColor: "#d4e5f7",
|
|
13134
|
+
itemHoverBackground: "rgba(74, 144, 217, 0.18)",
|
|
13135
|
+
destructiveItemColor: "#fb7185",
|
|
13136
|
+
fontFamily: "'JetBrains Mono', monospace",
|
|
13137
|
+
fontSize: 11,
|
|
13138
|
+
paddingY: 3,
|
|
13139
|
+
paddingX: 3,
|
|
13140
|
+
itemPaddingY: 5,
|
|
13141
|
+
itemPaddingX: 10,
|
|
13142
|
+
shadow: "0 8px 24px rgba(10,22,40,0.5)"
|
|
13143
|
+
},
|
|
13080
13144
|
lanes: {
|
|
13081
13145
|
bandFillEven: "rgba(19, 34, 68, 0.45)",
|
|
13082
13146
|
bandFillOdd: "rgba(19, 34, 68, 0.15)",
|
|
@@ -13154,6 +13218,21 @@ var SystemCanvas = (() => {
|
|
|
13154
13218
|
fontFamily: "'IBM Plex Mono', monospace",
|
|
13155
13219
|
fontSize: 12
|
|
13156
13220
|
},
|
|
13221
|
+
contextMenu: {
|
|
13222
|
+
background: "rgba(26, 23, 20, 0.97)",
|
|
13223
|
+
borderColor: "rgba(107, 94, 74, 0.6)",
|
|
13224
|
+
borderRadius: 8,
|
|
13225
|
+
itemColor: "#e8ddd0",
|
|
13226
|
+
itemHoverBackground: "rgba(107, 94, 74, 0.3)",
|
|
13227
|
+
destructiveItemColor: "#fb7185",
|
|
13228
|
+
fontFamily: "'IBM Plex Mono', monospace",
|
|
13229
|
+
fontSize: 12,
|
|
13230
|
+
paddingY: 4,
|
|
13231
|
+
paddingX: 4,
|
|
13232
|
+
itemPaddingY: 5,
|
|
13233
|
+
itemPaddingX: 10,
|
|
13234
|
+
shadow: "0 8px 24px rgba(0,0,0,0.4)"
|
|
13235
|
+
},
|
|
13157
13236
|
lanes: {
|
|
13158
13237
|
bandFillEven: "rgba(42, 37, 32, 0.55)",
|
|
13159
13238
|
bandFillOdd: "rgba(42, 37, 32, 0.2)",
|
|
@@ -13232,6 +13311,21 @@ var SystemCanvas = (() => {
|
|
|
13232
13311
|
fontFamily: "'Inter', 'Helvetica Neue', sans-serif",
|
|
13233
13312
|
fontSize: 12
|
|
13234
13313
|
},
|
|
13314
|
+
contextMenu: {
|
|
13315
|
+
background: "rgba(15, 17, 21, 0.96)",
|
|
13316
|
+
borderColor: "rgba(63, 69, 83, 0.8)",
|
|
13317
|
+
borderRadius: 8,
|
|
13318
|
+
itemColor: "#e8ebf2",
|
|
13319
|
+
itemHoverBackground: "rgba(90, 100, 120, 0.3)",
|
|
13320
|
+
destructiveItemColor: "#fb7185",
|
|
13321
|
+
fontFamily: "'Inter', 'Helvetica Neue', sans-serif",
|
|
13322
|
+
fontSize: 12,
|
|
13323
|
+
paddingY: 4,
|
|
13324
|
+
paddingX: 4,
|
|
13325
|
+
itemPaddingY: 5,
|
|
13326
|
+
itemPaddingX: 10,
|
|
13327
|
+
shadow: "0 8px 24px rgba(0,0,0,0.4)"
|
|
13328
|
+
},
|
|
13235
13329
|
// Slightly stronger lane fills than the other themes — roadmap columns
|
|
13236
13330
|
// should read as the primary structure of the canvas.
|
|
13237
13331
|
lanes: {
|
|
@@ -13458,10 +13552,16 @@ var SystemCanvas = (() => {
|
|
|
13458
13552
|
group: { ...base.group, ...partial.group },
|
|
13459
13553
|
breadcrumbs: { ...base.breadcrumbs, ...partial.breadcrumbs },
|
|
13460
13554
|
lanes: { ...base.lanes, ...partial.lanes },
|
|
13555
|
+
// contextMenu is optional on CanvasTheme but darkTheme always defines it,
|
|
13556
|
+
// so the resolved theme is guaranteed to have a populated block as long
|
|
13557
|
+
// as `base` is a complete theme (which is the contract).
|
|
13558
|
+
contextMenu: partial.contextMenu ? { ...base.contextMenu, ...partial.contextMenu } : base.contextMenu,
|
|
13461
13559
|
presetColors: { ...base.presetColors, ...partial.presetColors },
|
|
13462
13560
|
categories: { ...base.categories, ...partial.categories },
|
|
13463
13561
|
icons: partial.icons ? { ...base.icons ?? {}, ...partial.icons } : base.icons,
|
|
13464
|
-
nodeActions: partial.nodeActions ?? base.nodeActions
|
|
13562
|
+
nodeActions: partial.nodeActions ?? base.nodeActions,
|
|
13563
|
+
showToolbarDelete: partial.showToolbarDelete ?? base.showToolbarDelete,
|
|
13564
|
+
toolbarAlign: partial.toolbarAlign ?? base.toolbarAlign
|
|
13465
13565
|
};
|
|
13466
13566
|
}
|
|
13467
13567
|
function resolveColor(color2, theme) {
|
|
@@ -13809,6 +13909,29 @@ var SystemCanvas = (() => {
|
|
|
13809
13909
|
return getNodeActions(theme);
|
|
13810
13910
|
}
|
|
13811
13911
|
|
|
13912
|
+
// ../core/dist/contextMenu.js
|
|
13913
|
+
function matchesContextMenuItem(item, node, ctx) {
|
|
13914
|
+
const m = item.match;
|
|
13915
|
+
if (!m)
|
|
13916
|
+
return true;
|
|
13917
|
+
if (m.categories) {
|
|
13918
|
+
if (!node.category)
|
|
13919
|
+
return false;
|
|
13920
|
+
if (!m.categories.includes(node.category))
|
|
13921
|
+
return false;
|
|
13922
|
+
}
|
|
13923
|
+
if (m.types) {
|
|
13924
|
+
if (!m.types.includes(node.type))
|
|
13925
|
+
return false;
|
|
13926
|
+
}
|
|
13927
|
+
if (m.when && !m.when(node, ctx))
|
|
13928
|
+
return false;
|
|
13929
|
+
return true;
|
|
13930
|
+
}
|
|
13931
|
+
function filterContextMenuItems(items, node, ctx) {
|
|
13932
|
+
return items.filter((item) => matchesContextMenuItem(item, node, ctx));
|
|
13933
|
+
}
|
|
13934
|
+
|
|
13812
13935
|
// ../core/dist/rollup.js
|
|
13813
13936
|
function rollupNodes(canvas, predicate) {
|
|
13814
13937
|
const nodes = canvas?.nodes ?? [];
|
|
@@ -13839,6 +13962,23 @@ var SystemCanvas = (() => {
|
|
|
13839
13962
|
var TAB_BADGE_EM = 1.4;
|
|
13840
13963
|
var TAB_BADGE_LIFT = 10;
|
|
13841
13964
|
var TAB_BADGE_OVERHANG = 8;
|
|
13965
|
+
function cornerSlotClearance(spec, fontSize) {
|
|
13966
|
+
if (!spec)
|
|
13967
|
+
return 0;
|
|
13968
|
+
if (spec.kind !== "dot" && spec.kind !== "icon")
|
|
13969
|
+
return 0;
|
|
13970
|
+
const corner = CORNER_EM * fontSize;
|
|
13971
|
+
let renderedWidth = corner;
|
|
13972
|
+
if (spec.kind === "icon") {
|
|
13973
|
+
const explicitSize = spec.size;
|
|
13974
|
+
if (typeof explicitSize === "number" && explicitSize > corner) {
|
|
13975
|
+
renderedWidth = explicitSize;
|
|
13976
|
+
}
|
|
13977
|
+
}
|
|
13978
|
+
const gap = Math.max(8, Math.round(fontSize * 0.75));
|
|
13979
|
+
const overhang = Math.max(0, (renderedWidth - corner) / 2);
|
|
13980
|
+
return overhang + corner + gap;
|
|
13981
|
+
}
|
|
13842
13982
|
function computeCategorySlotRegions(node, theme, slots) {
|
|
13843
13983
|
const { x, y, width, height } = node;
|
|
13844
13984
|
const fs = theme.node.fontSize;
|
|
@@ -13906,12 +14046,16 @@ var SystemCanvas = (() => {
|
|
|
13906
14046
|
width: tab,
|
|
13907
14047
|
height: tab
|
|
13908
14048
|
},
|
|
13909
|
-
topLeft: {
|
|
13910
|
-
|
|
13911
|
-
y: y + CORNER_INSET
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
14049
|
+
topLeft: (() => {
|
|
14050
|
+
const usesInlineRow = slots?.topLeft !== void 0 && (slots.topLeft.kind === "dot" || slots.topLeft.kind === "icon") && slots.header === void 0;
|
|
14051
|
+
const slotY = usesInlineRow ? y + (height - corner) / 2 : y + CORNER_INSET;
|
|
14052
|
+
return {
|
|
14053
|
+
x: x + CORNER_INSET,
|
|
14054
|
+
y: slotY,
|
|
14055
|
+
width: corner,
|
|
14056
|
+
height: corner
|
|
14057
|
+
};
|
|
14058
|
+
})(),
|
|
13915
14059
|
topRight: {
|
|
13916
14060
|
x: x + width - CORNER_INSET - corner,
|
|
13917
14061
|
y: y + CORNER_INSET,
|
|
@@ -13930,18 +14074,49 @@ var SystemCanvas = (() => {
|
|
|
13930
14074
|
width: corner,
|
|
13931
14075
|
height: corner
|
|
13932
14076
|
},
|
|
13933
|
-
header: {
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
14077
|
+
header: (() => {
|
|
14078
|
+
let hx = x + HEADER_INSET_X;
|
|
14079
|
+
let hw = Math.max(0, width - HEADER_INSET_X * 2);
|
|
14080
|
+
const leftClear = cornerSlotClearance(slots?.topLeft, fs);
|
|
14081
|
+
if (leftClear > 0) {
|
|
14082
|
+
const leftEdge = x + CORNER_INSET + leftClear;
|
|
14083
|
+
const shift = Math.max(0, leftEdge - hx);
|
|
14084
|
+
hx += shift;
|
|
14085
|
+
hw = Math.max(0, hw - shift);
|
|
14086
|
+
}
|
|
14087
|
+
const rightClear = cornerSlotClearance(slots?.topRight, fs);
|
|
14088
|
+
if (rightClear > 0) {
|
|
14089
|
+
const rightEdge = x + width - CORNER_INSET - rightClear;
|
|
14090
|
+
const currentRight = hx + hw;
|
|
14091
|
+
const shrink = Math.max(0, currentRight - rightEdge);
|
|
14092
|
+
hw = Math.max(0, hw - shrink);
|
|
14093
|
+
}
|
|
14094
|
+
return { x: hx, y: y + HEADER_INSET_Y, width: hw, height: header };
|
|
14095
|
+
})(),
|
|
14096
|
+
footer: (() => {
|
|
14097
|
+
let fx = x + HEADER_INSET_X;
|
|
14098
|
+
let fw = Math.max(0, width - HEADER_INSET_X * 2);
|
|
14099
|
+
const leftClear = cornerSlotClearance(slots?.bottomLeft, fs);
|
|
14100
|
+
if (leftClear > 0) {
|
|
14101
|
+
const leftEdge = x + CORNER_INSET + leftClear;
|
|
14102
|
+
const shift = Math.max(0, leftEdge - fx);
|
|
14103
|
+
fx += shift;
|
|
14104
|
+
fw = Math.max(0, fw - shift);
|
|
14105
|
+
}
|
|
14106
|
+
const rightClear = cornerSlotClearance(slots?.bottomRight, fs);
|
|
14107
|
+
if (rightClear > 0) {
|
|
14108
|
+
const rightEdge = x + width - CORNER_INSET - rightClear;
|
|
14109
|
+
const currentRight = fx + fw;
|
|
14110
|
+
const shrink = Math.max(0, currentRight - rightEdge);
|
|
14111
|
+
fw = Math.max(0, fw - shrink);
|
|
14112
|
+
}
|
|
14113
|
+
return {
|
|
14114
|
+
x: fx,
|
|
14115
|
+
y: y + height - FOOTER_INSET_Y - footer,
|
|
14116
|
+
width: fw,
|
|
14117
|
+
height: footer
|
|
14118
|
+
};
|
|
14119
|
+
})(),
|
|
13945
14120
|
body: {
|
|
13946
14121
|
x: bodyX,
|
|
13947
14122
|
y: bodyY,
|
|
@@ -14064,13 +14239,26 @@ var SystemCanvas = (() => {
|
|
|
14064
14239
|
left = regions.leftEdge.width + 4;
|
|
14065
14240
|
if (slots.rightEdge)
|
|
14066
14241
|
right = regions.rightEdge.width + 4;
|
|
14067
|
-
if (slots.topLeft && slots.topLeft.kind === "dot") {
|
|
14068
|
-
|
|
14242
|
+
if (slots.topLeft && (slots.topLeft.kind === "dot" || slots.topLeft.kind === "icon")) {
|
|
14243
|
+
const region = regions.topLeft;
|
|
14244
|
+
let renderedWidth = region.width;
|
|
14245
|
+
if (slots.topLeft.kind === "icon") {
|
|
14246
|
+
const explicitSize = slots.topLeft.size;
|
|
14247
|
+
if (typeof explicitSize === "number" && explicitSize > region.width) {
|
|
14248
|
+
renderedWidth = explicitSize;
|
|
14249
|
+
}
|
|
14250
|
+
}
|
|
14251
|
+
const iconLeftFromNode = region.x - node.x + (region.width - renderedWidth) / 2;
|
|
14252
|
+
const gap = Math.max(8, Math.round(theme.node.fontSize * 0.75));
|
|
14253
|
+
left = Math.max(left, iconLeftFromNode + renderedWidth + gap);
|
|
14069
14254
|
}
|
|
14070
|
-
const
|
|
14255
|
+
const hasTopRowSignal = slots.header !== void 0 || slots.topRight !== void 0 || slots.bodyTop !== void 0 || slots.footer !== void 0;
|
|
14256
|
+
const hasInlineLeftMarker = slots.topLeft !== void 0 && (slots.topLeft.kind === "dot" || slots.topLeft.kind === "icon");
|
|
14257
|
+
const isDashboard = hasTopRowSignal || hasInlineLeftMarker;
|
|
14071
14258
|
if (isDashboard) {
|
|
14072
|
-
if (!slots.header)
|
|
14259
|
+
if (hasTopRowSignal && !slots.header) {
|
|
14073
14260
|
top = Math.max(top, HEADER_INSET_Y);
|
|
14261
|
+
}
|
|
14074
14262
|
left = Math.max(left, HEADER_INSET_X);
|
|
14075
14263
|
right = Math.max(right, HEADER_INSET_X);
|
|
14076
14264
|
}
|
|
@@ -14168,6 +14356,29 @@ var SystemCanvas = (() => {
|
|
|
14168
14356
|
}
|
|
14169
14357
|
return out;
|
|
14170
14358
|
}
|
|
14359
|
+
function truncateToWidth(text, maxWidth, fontSize) {
|
|
14360
|
+
if (!text)
|
|
14361
|
+
return text;
|
|
14362
|
+
if (maxWidth <= 0)
|
|
14363
|
+
return text;
|
|
14364
|
+
if (measureTextWidth(text, fontSize) <= maxWidth)
|
|
14365
|
+
return text;
|
|
14366
|
+
const ellipsis = "\u2026";
|
|
14367
|
+
let lo = 0;
|
|
14368
|
+
let hi = text.length;
|
|
14369
|
+
let best = 0;
|
|
14370
|
+
while (lo <= hi) {
|
|
14371
|
+
const mid = lo + hi >> 1;
|
|
14372
|
+
const candidate = text.slice(0, mid) + ellipsis;
|
|
14373
|
+
if (measureTextWidth(candidate, fontSize) <= maxWidth) {
|
|
14374
|
+
best = mid;
|
|
14375
|
+
lo = mid + 1;
|
|
14376
|
+
} else {
|
|
14377
|
+
hi = mid - 1;
|
|
14378
|
+
}
|
|
14379
|
+
}
|
|
14380
|
+
return text.slice(0, best) + ellipsis;
|
|
14381
|
+
}
|
|
14171
14382
|
function ellipsize(line, maxWidth, fontSize) {
|
|
14172
14383
|
const ellipsis = "\u2026";
|
|
14173
14384
|
if (measureTextWidth(line + ellipsis, fontSize) <= maxWidth) {
|
|
@@ -14180,7 +14391,7 @@ var SystemCanvas = (() => {
|
|
|
14180
14391
|
if (measureTextWidth(candidate, fontSize) <= maxWidth)
|
|
14181
14392
|
return candidate;
|
|
14182
14393
|
}
|
|
14183
|
-
return line
|
|
14394
|
+
return truncateToWidth(line, maxWidth, fontSize);
|
|
14184
14395
|
}
|
|
14185
14396
|
|
|
14186
14397
|
// ../core/dist/canvas.js
|
|
@@ -14438,15 +14649,19 @@ var SystemCanvas = (() => {
|
|
|
14438
14649
|
// ../react/dist/hooks/useCanvasInteraction.js
|
|
14439
14650
|
var import_react2 = __toESM(require_react(), 1);
|
|
14440
14651
|
function useCanvasInteraction(options) {
|
|
14441
|
-
const { onNodeClick, onNodeDoubleClick, onEdgeClick, onEdgeDoubleClick, onContextMenu, onNavigableNodeClick, viewport, editable, onSelect, onBeginEdit, onSelectEdge, onBeginEditEdge } = options;
|
|
14652
|
+
const { onNodeClick, onNodeDoubleClick, onEdgeClick, onEdgeDoubleClick, onContextMenu, onNavigableNodeClick, viewport, editable, onSelect, onToggleSelect, onBeginEdit, onSelectEdge, onBeginEditEdge } = options;
|
|
14442
14653
|
const handleNodeClick = (0, import_react2.useCallback)((node, event) => {
|
|
14443
14654
|
event.stopPropagation();
|
|
14444
14655
|
if (editable) {
|
|
14445
|
-
|
|
14446
|
-
|
|
14656
|
+
if (event.shiftKey && onToggleSelect) {
|
|
14657
|
+
onToggleSelect(node.id);
|
|
14658
|
+
} else {
|
|
14659
|
+
onSelect?.(node.id);
|
|
14660
|
+
onSelectEdge?.(null);
|
|
14661
|
+
}
|
|
14447
14662
|
}
|
|
14448
14663
|
onNodeClick?.(node);
|
|
14449
|
-
}, [editable, onNodeClick, onSelect, onSelectEdge]);
|
|
14664
|
+
}, [editable, onNodeClick, onSelect, onToggleSelect, onSelectEdge]);
|
|
14450
14665
|
const handleNodeDoubleClick = (0, import_react2.useCallback)((node, event) => {
|
|
14451
14666
|
event.stopPropagation();
|
|
14452
14667
|
onNodeDoubleClick?.(node);
|
|
@@ -14484,7 +14699,12 @@ var SystemCanvas = (() => {
|
|
|
14484
14699
|
onContextMenu({
|
|
14485
14700
|
type,
|
|
14486
14701
|
target,
|
|
14487
|
-
position: canvasPos
|
|
14702
|
+
position: canvasPos,
|
|
14703
|
+
// Raw viewport coords from the original MouseEvent. Consumers
|
|
14704
|
+
// rendering a `position: fixed` floating menu need these — the
|
|
14705
|
+
// canvas-space `position` would be wrong because it walks
|
|
14706
|
+
// with the user's pan/zoom.
|
|
14707
|
+
screenPosition: { x: event.clientX, y: event.clientY }
|
|
14488
14708
|
});
|
|
14489
14709
|
};
|
|
14490
14710
|
}, [onContextMenu, viewport]);
|
|
@@ -14520,11 +14740,45 @@ var SystemCanvas = (() => {
|
|
|
14520
14740
|
var import_react3 = __toESM(require_react(), 1);
|
|
14521
14741
|
var DRAG_THRESHOLD = 3;
|
|
14522
14742
|
function useNodeDrag(options) {
|
|
14523
|
-
const { viewport, nodesRef, onCommit } = options;
|
|
14743
|
+
const { viewport, nodesRef, onCommit, svgRef, canDropNodeOn, onNodeDrop, selectedIdsRef } = options;
|
|
14524
14744
|
const [dragOverrides, setDragOverrides] = (0, import_react3.useState)(() => /* @__PURE__ */ new Map());
|
|
14525
14745
|
const [isDragging, setIsDragging] = (0, import_react3.useState)(false);
|
|
14746
|
+
const [dropTargetId, setDropTargetId] = (0, import_react3.useState)(null);
|
|
14526
14747
|
const stateRef = (0, import_react3.useRef)(null);
|
|
14527
14748
|
const movedRef = (0, import_react3.useRef)(false);
|
|
14749
|
+
const canDropNodeOnRef = (0, import_react3.useRef)(canDropNodeOn);
|
|
14750
|
+
canDropNodeOnRef.current = canDropNodeOn;
|
|
14751
|
+
const onNodeDropRef = (0, import_react3.useRef)(onNodeDrop);
|
|
14752
|
+
onNodeDropRef.current = onNodeDrop;
|
|
14753
|
+
const svgRefRef = (0, import_react3.useRef)(svgRef);
|
|
14754
|
+
svgRefRef.current = svgRef;
|
|
14755
|
+
const emptySetRef = (0, import_react3.useRef)(/* @__PURE__ */ new Set());
|
|
14756
|
+
const effectiveSelectedIdsRef = selectedIdsRef ?? emptySetRef;
|
|
14757
|
+
const dropTargetIdRef = (0, import_react3.useRef)(null);
|
|
14758
|
+
const computeDropTarget = (0, import_react3.useCallback)((clientX, clientY) => {
|
|
14759
|
+
const cb = canDropNodeOnRef.current;
|
|
14760
|
+
const st = stateRef.current;
|
|
14761
|
+
const nodes = nodesRef.current;
|
|
14762
|
+
const svg = svgRefRef.current?.current;
|
|
14763
|
+
if (!cb || !st || !nodes || !svg)
|
|
14764
|
+
return null;
|
|
14765
|
+
const rect = svg.getBoundingClientRect();
|
|
14766
|
+
const vp = viewport.current ?? { x: 0, y: 0, zoom: 1 };
|
|
14767
|
+
const { x, y } = screenToCanvas(clientX - rect.left, clientY - rect.top, vp);
|
|
14768
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
14769
|
+
const n = nodes[i];
|
|
14770
|
+
if (st.moving.has(n.id))
|
|
14771
|
+
continue;
|
|
14772
|
+
if (x < n.x || x > n.x + n.width)
|
|
14773
|
+
continue;
|
|
14774
|
+
if (y < n.y || y > n.y + n.height)
|
|
14775
|
+
continue;
|
|
14776
|
+
if (cb([st.source], n))
|
|
14777
|
+
return n.id;
|
|
14778
|
+
return null;
|
|
14779
|
+
}
|
|
14780
|
+
return null;
|
|
14781
|
+
}, [nodesRef, viewport]);
|
|
14528
14782
|
const onPointerMove = (0, import_react3.useCallback)((event) => {
|
|
14529
14783
|
const st = stateRef.current;
|
|
14530
14784
|
if (!st || event.pointerId !== st.pointerId)
|
|
@@ -14546,7 +14800,12 @@ var SystemCanvas = (() => {
|
|
|
14546
14800
|
next.set(id2, { x: start2.startX + dx, y: start2.startY + dy });
|
|
14547
14801
|
}
|
|
14548
14802
|
setDragOverrides(next);
|
|
14549
|
-
|
|
14803
|
+
const nextTarget = computeDropTarget(event.clientX, event.clientY);
|
|
14804
|
+
if (nextTarget !== dropTargetIdRef.current) {
|
|
14805
|
+
dropTargetIdRef.current = nextTarget;
|
|
14806
|
+
setDropTargetId(nextTarget);
|
|
14807
|
+
}
|
|
14808
|
+
}, [viewport, computeDropTarget]);
|
|
14550
14809
|
const finishDrag = (0, import_react3.useCallback)((commit) => {
|
|
14551
14810
|
const st = stateRef.current;
|
|
14552
14811
|
if (!st)
|
|
@@ -14559,17 +14818,38 @@ var SystemCanvas = (() => {
|
|
|
14559
14818
|
st.captureTarget.releasePointerCapture?.(st.pointerId);
|
|
14560
14819
|
} catch {
|
|
14561
14820
|
}
|
|
14821
|
+
const dropTarget = dropTargetIdRef.current;
|
|
14822
|
+
if (commit && movedRef.current && dropTarget) {
|
|
14823
|
+
const nodes = nodesRef.current;
|
|
14824
|
+
const target = nodes?.find((n) => n.id === dropTarget) ?? null;
|
|
14825
|
+
if (target && onNodeDropRef.current) {
|
|
14826
|
+
onNodeDropRef.current([st.source], target);
|
|
14827
|
+
stateRef.current = null;
|
|
14828
|
+
movedRef.current = false;
|
|
14829
|
+
dropTargetIdRef.current = null;
|
|
14830
|
+
setIsDragging(false);
|
|
14831
|
+
setDragOverrides(/* @__PURE__ */ new Map());
|
|
14832
|
+
setDropTargetId(null);
|
|
14833
|
+
return;
|
|
14834
|
+
}
|
|
14835
|
+
}
|
|
14562
14836
|
if (commit && movedRef.current) {
|
|
14563
14837
|
const overrides = Array.from(dragOverridesRef.current.entries());
|
|
14564
|
-
|
|
14565
|
-
|
|
14838
|
+
if (overrides.length > 0) {
|
|
14839
|
+
const updates = overrides.map(([id2, pos]) => ({
|
|
14840
|
+
id: id2,
|
|
14841
|
+
patch: { x: Math.round(pos.x), y: Math.round(pos.y) }
|
|
14842
|
+
}));
|
|
14843
|
+
onCommit(updates);
|
|
14566
14844
|
}
|
|
14567
14845
|
}
|
|
14568
14846
|
stateRef.current = null;
|
|
14569
14847
|
movedRef.current = false;
|
|
14848
|
+
dropTargetIdRef.current = null;
|
|
14570
14849
|
setIsDragging(false);
|
|
14571
14850
|
setDragOverrides(/* @__PURE__ */ new Map());
|
|
14572
|
-
|
|
14851
|
+
setDropTargetId(null);
|
|
14852
|
+
}, [onPointerMove, onCommit, nodesRef]);
|
|
14573
14853
|
const dragOverridesRef = (0, import_react3.useRef)(dragOverrides);
|
|
14574
14854
|
dragOverridesRef.current = dragOverrides;
|
|
14575
14855
|
const onPointerUpRef = (0, import_react3.useRef)(null);
|
|
@@ -14595,12 +14875,22 @@ var SystemCanvas = (() => {
|
|
|
14595
14875
|
return;
|
|
14596
14876
|
event.stopPropagation();
|
|
14597
14877
|
const moving = /* @__PURE__ */ new Map();
|
|
14598
|
-
|
|
14599
|
-
if (
|
|
14600
|
-
const
|
|
14601
|
-
|
|
14602
|
-
if (
|
|
14603
|
-
moving.set(
|
|
14878
|
+
const sel = effectiveSelectedIdsRef.current;
|
|
14879
|
+
if (sel && sel.size > 1 && sel.has(node.id) && nodesRef.current) {
|
|
14880
|
+
for (const id2 of sel) {
|
|
14881
|
+
const n = nodesRef.current.find((r) => r.id === id2);
|
|
14882
|
+
if (n) {
|
|
14883
|
+
moving.set(id2, { startX: n.x, startY: n.y });
|
|
14884
|
+
}
|
|
14885
|
+
}
|
|
14886
|
+
} else {
|
|
14887
|
+
moving.set(node.id, { startX: node.x, startY: node.y });
|
|
14888
|
+
if (node.type === "group" && nodesRef.current) {
|
|
14889
|
+
const children2 = getGroupChildren(node, nodesRef.current);
|
|
14890
|
+
for (const c of children2) {
|
|
14891
|
+
if (!moving.has(c.id)) {
|
|
14892
|
+
moving.set(c.id, { startX: c.x, startY: c.y });
|
|
14893
|
+
}
|
|
14604
14894
|
}
|
|
14605
14895
|
}
|
|
14606
14896
|
}
|
|
@@ -14609,9 +14899,11 @@ var SystemCanvas = (() => {
|
|
|
14609
14899
|
startClientY: event.clientY,
|
|
14610
14900
|
captureTarget: event.currentTarget,
|
|
14611
14901
|
pointerId: event.pointerId,
|
|
14612
|
-
moving
|
|
14902
|
+
moving,
|
|
14903
|
+
source: node
|
|
14613
14904
|
};
|
|
14614
14905
|
movedRef.current = false;
|
|
14906
|
+
dropTargetIdRef.current = null;
|
|
14615
14907
|
try {
|
|
14616
14908
|
;
|
|
14617
14909
|
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
@@ -14621,7 +14913,7 @@ var SystemCanvas = (() => {
|
|
|
14621
14913
|
window.addEventListener("pointerup", onPointerUp);
|
|
14622
14914
|
window.addEventListener("pointercancel", onPointerCancel);
|
|
14623
14915
|
}, [nodesRef, onPointerMove, onPointerUp, onPointerCancel]);
|
|
14624
|
-
return { dragOverrides, onPointerDown, isDragging };
|
|
14916
|
+
return { dragOverrides, dropTargetId, onPointerDown, isDragging };
|
|
14625
14917
|
}
|
|
14626
14918
|
|
|
14627
14919
|
// ../react/dist/hooks/useNodeResize.js
|
|
@@ -14896,11 +15188,15 @@ var SystemCanvas = (() => {
|
|
|
14896
15188
|
return { x, y, zoom };
|
|
14897
15189
|
}
|
|
14898
15190
|
function useZoomNavigation(options) {
|
|
14899
|
-
const { enabled, config, nodes, currentCanvas, parentFrame, canvases, onResolveCanvas, onSeedCanvas, theme, getViewportSize, onEnter, onExit } = options;
|
|
15191
|
+
const { enabled, config, nodes, currentCanvas, parentFrame, canvases, onResolveCanvas, onSeedCanvas, theme, getViewportSize, getCursorScreenPos, onEnter, onExit } = options;
|
|
14900
15192
|
const committingRef = (0, import_react6.useRef)(false);
|
|
14901
15193
|
(0, import_react6.useEffect)(() => {
|
|
14902
15194
|
committingRef.current = false;
|
|
14903
15195
|
}, [currentCanvas]);
|
|
15196
|
+
const exitArmedRef = (0, import_react6.useRef)(false);
|
|
15197
|
+
(0, import_react6.useEffect)(() => {
|
|
15198
|
+
exitArmedRef.current = false;
|
|
15199
|
+
}, [currentCanvas, parentFrame]);
|
|
14904
15200
|
const prefetchRef = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
|
|
14905
15201
|
const prefetch = (0, import_react6.useCallback)((ref) => {
|
|
14906
15202
|
if (!onResolveCanvas)
|
|
@@ -14928,36 +15224,87 @@ var SystemCanvas = (() => {
|
|
|
14928
15224
|
const size = getViewportSize();
|
|
14929
15225
|
if (!size)
|
|
14930
15226
|
return;
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
const
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
15227
|
+
const cursor = getCursorScreenPos();
|
|
15228
|
+
const viewportCenterX = size.width / 2;
|
|
15229
|
+
const viewportCenterY = size.height / 2;
|
|
15230
|
+
let cursorNode = null;
|
|
15231
|
+
if (cursor) {
|
|
15232
|
+
for (const n of nodes) {
|
|
15233
|
+
if (!n.ref)
|
|
15234
|
+
continue;
|
|
15235
|
+
const screen = canvasRectToScreenRect({ x: n.x, y: n.y, width: n.width, height: n.height }, vp);
|
|
15236
|
+
if (cursor.x < screen.x || cursor.x > screen.x + screen.width || cursor.y < screen.y || cursor.y > screen.y + screen.height) {
|
|
15237
|
+
continue;
|
|
15238
|
+
}
|
|
15239
|
+
const area = screen.width * screen.height;
|
|
15240
|
+
if (!cursorNode || area < cursorNode.area) {
|
|
15241
|
+
cursorNode = { node: n, screen, area };
|
|
15242
|
+
}
|
|
15243
|
+
}
|
|
15244
|
+
}
|
|
15245
|
+
let bestCandidate = null;
|
|
15246
|
+
if (cursorNode) {
|
|
15247
|
+
const screen = cursorNode.screen;
|
|
14940
15248
|
const fillFraction = Math.max(screen.width / size.width, screen.height / size.height);
|
|
14941
|
-
if (fillFraction >= config.prefetchThreshold &&
|
|
14942
|
-
prefetch(
|
|
15249
|
+
if (fillFraction >= config.prefetchThreshold && cursorNode.node.ref) {
|
|
15250
|
+
prefetch(cursorNode.node.ref);
|
|
14943
15251
|
}
|
|
14944
15252
|
if (fillFraction >= config.enterThreshold) {
|
|
14945
|
-
|
|
14946
|
-
|
|
15253
|
+
bestCandidate = { node: cursorNode.node, screen, distSq: 0 };
|
|
15254
|
+
}
|
|
15255
|
+
for (const n of nodes) {
|
|
15256
|
+
if (!n.ref)
|
|
15257
|
+
continue;
|
|
15258
|
+
if (n === cursorNode.node)
|
|
15259
|
+
continue;
|
|
15260
|
+
const s = canvasRectToScreenRect({ x: n.x, y: n.y, width: n.width, height: n.height }, vp);
|
|
15261
|
+
const ff = Math.max(s.width / size.width, s.height / size.height);
|
|
15262
|
+
if (ff >= config.prefetchThreshold)
|
|
14947
15263
|
prefetch(n.ref);
|
|
15264
|
+
}
|
|
15265
|
+
} else {
|
|
15266
|
+
for (const n of nodes) {
|
|
15267
|
+
if (!n.ref)
|
|
15268
|
+
continue;
|
|
15269
|
+
const screen = canvasRectToScreenRect({ x: n.x, y: n.y, width: n.width, height: n.height }, vp);
|
|
15270
|
+
const centerX = screen.x + screen.width / 2;
|
|
15271
|
+
const centerY = screen.y + screen.height / 2;
|
|
15272
|
+
const centerOnScreen = centerX >= 0 && centerX <= size.width && centerY >= 0 && centerY <= size.height;
|
|
15273
|
+
if (!centerOnScreen)
|
|
14948
15274
|
continue;
|
|
15275
|
+
const fillFraction = Math.max(screen.width / size.width, screen.height / size.height);
|
|
15276
|
+
if (fillFraction >= config.prefetchThreshold && fillFraction < config.enterThreshold) {
|
|
15277
|
+
prefetch(n.ref);
|
|
15278
|
+
}
|
|
15279
|
+
if (fillFraction >= config.enterThreshold) {
|
|
15280
|
+
const dx = centerX - viewportCenterX;
|
|
15281
|
+
const dy = centerY - viewportCenterY;
|
|
15282
|
+
const distSq = dx * dx + dy * dy;
|
|
15283
|
+
if (!bestCandidate || distSq < bestCandidate.distSq) {
|
|
15284
|
+
bestCandidate = { node: n, screen, distSq };
|
|
15285
|
+
}
|
|
14949
15286
|
}
|
|
15287
|
+
}
|
|
15288
|
+
}
|
|
15289
|
+
if (bestCandidate) {
|
|
15290
|
+
const n = bestCandidate.node;
|
|
15291
|
+
const screen = bestCandidate.screen;
|
|
15292
|
+
const ref = n.ref;
|
|
15293
|
+
const childData = canvases?.[ref] ?? prefetchRef.current.get(ref)?.data;
|
|
15294
|
+
if (!childData) {
|
|
15295
|
+
prefetch(ref);
|
|
15296
|
+
} else {
|
|
14950
15297
|
const resolved = resolveCanvas(childData, theme);
|
|
14951
|
-
if (resolved.nodes.length
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
15298
|
+
if (resolved.nodes.length > 0) {
|
|
15299
|
+
const bounds = computeBoundingBox(resolved.nodes);
|
|
15300
|
+
const targetRect = expandRect(screen, config.landingScale);
|
|
15301
|
+
const landingPad = Math.min(targetRect.width, targetRect.height) * config.landingPadding;
|
|
15302
|
+
let targetTransform = fitBoundsIntoRect(bounds, targetRect, landingPad);
|
|
15303
|
+
targetTransform = clampTransformToViewport(targetTransform, bounds, size, 16);
|
|
15304
|
+
committingRef.current = true;
|
|
15305
|
+
onEnter(n, targetTransform);
|
|
15306
|
+
return;
|
|
15307
|
+
}
|
|
14961
15308
|
}
|
|
14962
15309
|
}
|
|
14963
15310
|
if (parentFrame && nodes.length > 0) {
|
|
@@ -14971,6 +15318,12 @@ var SystemCanvas = (() => {
|
|
|
14971
15318
|
height: bounds.height
|
|
14972
15319
|
}, vp);
|
|
14973
15320
|
const fillFraction = Math.max(screen.width / size.width, screen.height / size.height);
|
|
15321
|
+
if (!exitArmedRef.current) {
|
|
15322
|
+
if (fillFraction > config.exitThreshold) {
|
|
15323
|
+
exitArmedRef.current = true;
|
|
15324
|
+
}
|
|
15325
|
+
return;
|
|
15326
|
+
}
|
|
14974
15327
|
if (fillFraction <= config.exitThreshold) {
|
|
14975
15328
|
const targetTransform = fitBoundsIntoRect({
|
|
14976
15329
|
minX: parentFrame.parentNodeRect.x,
|
|
@@ -14997,6 +15350,7 @@ var SystemCanvas = (() => {
|
|
|
14997
15350
|
theme,
|
|
14998
15351
|
config,
|
|
14999
15352
|
getViewportSize,
|
|
15353
|
+
getCursorScreenPos,
|
|
15000
15354
|
prefetch,
|
|
15001
15355
|
onEnter,
|
|
15002
15356
|
onExit
|
|
@@ -17754,7 +18108,7 @@ var SystemCanvas = (() => {
|
|
|
17754
18108
|
|
|
17755
18109
|
// ../react/dist/hooks/useViewport.js
|
|
17756
18110
|
function useViewport(options) {
|
|
17757
|
-
const { minZoom, maxZoom, defaultViewport, onViewportChange } = options;
|
|
18111
|
+
const { minZoom, maxZoom, defaultViewport, onViewportChange, marqueeActiveRef } = options;
|
|
17758
18112
|
const svgRef = (0, import_react7.useRef)(null);
|
|
17759
18113
|
const groupRef = (0, import_react7.useRef)(null);
|
|
17760
18114
|
const viewport = (0, import_react7.useRef)(defaultViewport ?? { x: 0, y: 0, zoom: 1 });
|
|
@@ -17767,6 +18121,8 @@ var SystemCanvas = (() => {
|
|
|
17767
18121
|
if (!svg || !group)
|
|
17768
18122
|
return;
|
|
17769
18123
|
const zoomBehavior = zoom_default2().scaleExtent([minZoom, maxZoom]).filter((event) => {
|
|
18124
|
+
if (marqueeActiveRef?.current && event.type !== "wheel")
|
|
18125
|
+
return false;
|
|
17770
18126
|
if (event.button)
|
|
17771
18127
|
return false;
|
|
17772
18128
|
if (event.type === "wheel")
|
|
@@ -17872,17 +18228,67 @@ var SystemCanvas = (() => {
|
|
|
17872
18228
|
|
|
17873
18229
|
// ../react/dist/components/NodeIcon.js
|
|
17874
18230
|
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
|
|
17875
|
-
function NodeIcon({ icon, x, y, size = 14, color: color2, opacity = 0.7, customIcons }) {
|
|
18231
|
+
function NodeIcon({ icon, x, y, size = 14, color: color2, opacity = 0.7, customIcons, mode = "stroke", viewBox = 16 }) {
|
|
17876
18232
|
const pathData = customIcons?.[icon] ?? iconPaths[icon];
|
|
17877
18233
|
if (!pathData)
|
|
17878
18234
|
return null;
|
|
17879
|
-
|
|
18235
|
+
const defaultStrokeWidth = viewBox * 0.075;
|
|
18236
|
+
return (0, import_jsx_runtime.jsx)("g", { transform: `translate(${x}, ${y})`, pointerEvents: "none", opacity, children: pathData.map((entry, i) => {
|
|
18237
|
+
const spec = typeof entry === "string" ? { d: entry } : entry;
|
|
18238
|
+
const pathMode = spec.mode ?? mode;
|
|
18239
|
+
const rawStrokeWidth = spec.strokeWidth ?? defaultStrokeWidth;
|
|
18240
|
+
const renderedStrokeWidth = rawStrokeWidth * size / viewBox;
|
|
18241
|
+
return (0, import_jsx_runtime.jsx)("path", {
|
|
18242
|
+
d: scalePathData(spec.d, size, viewBox),
|
|
18243
|
+
fill: pathMode === "fill" ? color2 : "none",
|
|
18244
|
+
stroke: pathMode === "stroke" ? color2 : "none",
|
|
18245
|
+
strokeWidth: pathMode === "stroke" ? renderedStrokeWidth : 0,
|
|
18246
|
+
strokeLinecap: pathMode === "stroke" ? "round" : void 0,
|
|
18247
|
+
strokeLinejoin: pathMode === "stroke" ? "round" : void 0,
|
|
18248
|
+
// Brand silhouettes are typically authored as a single path
|
|
18249
|
+
// whose holes are expressed with subpath winding. `evenodd`
|
|
18250
|
+
// is the safe choice; nonzero would fill some holes solid.
|
|
18251
|
+
fillRule: pathMode === "fill" ? "evenodd" : void 0
|
|
18252
|
+
}, i);
|
|
18253
|
+
}) });
|
|
17880
18254
|
}
|
|
17881
|
-
function scalePathData(d, size) {
|
|
17882
|
-
const scale = size /
|
|
17883
|
-
|
|
17884
|
-
|
|
17885
|
-
|
|
18255
|
+
function scalePathData(d, size, source) {
|
|
18256
|
+
const scale = size / source;
|
|
18257
|
+
const out = [];
|
|
18258
|
+
const numberAtStart = /^-?(?:\d+\.?\d*|\.\d+)/;
|
|
18259
|
+
let isArc = false;
|
|
18260
|
+
let arcIndex = 0;
|
|
18261
|
+
let i = 0;
|
|
18262
|
+
while (i < d.length) {
|
|
18263
|
+
const ch = d[i];
|
|
18264
|
+
if (ch === " " || ch === "," || ch === " " || ch === "\n" || ch === "\r") {
|
|
18265
|
+
i++;
|
|
18266
|
+
continue;
|
|
18267
|
+
}
|
|
18268
|
+
if (/[a-zA-Z]/.test(ch)) {
|
|
18269
|
+
out.push(ch);
|
|
18270
|
+
isArc = ch === "a" || ch === "A";
|
|
18271
|
+
arcIndex = 0;
|
|
18272
|
+
i++;
|
|
18273
|
+
continue;
|
|
18274
|
+
}
|
|
18275
|
+
if (isArc && (arcIndex === 3 || arcIndex === 4)) {
|
|
18276
|
+
out.push(ch === "0" ? "0" : "1");
|
|
18277
|
+
arcIndex = (arcIndex + 1) % 7;
|
|
18278
|
+
i++;
|
|
18279
|
+
continue;
|
|
18280
|
+
}
|
|
18281
|
+
const m = numberAtStart.exec(d.substring(i));
|
|
18282
|
+
if (!m) {
|
|
18283
|
+
i++;
|
|
18284
|
+
continue;
|
|
18285
|
+
}
|
|
18286
|
+
out.push(String(parseFloat(m[0]) * scale));
|
|
18287
|
+
if (isArc)
|
|
18288
|
+
arcIndex = (arcIndex + 1) % 7;
|
|
18289
|
+
i += m[0].length;
|
|
18290
|
+
}
|
|
18291
|
+
return out.join(" ");
|
|
17886
18292
|
}
|
|
17887
18293
|
var iconPaths = {
|
|
17888
18294
|
// Database: cylinder shape
|
|
@@ -17975,11 +18381,12 @@ var SystemCanvas = (() => {
|
|
|
17975
18381
|
// ../react/dist/components/RefIndicator.js
|
|
17976
18382
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
17977
18383
|
var import_react8 = __toESM(require_react(), 1);
|
|
17978
|
-
function RefIndicator({ node, theme, nodeX, nodeY, nodeWidth, nodeHeight, strokeColor, strokeWidth, corner = "bottom-right", size
|
|
18384
|
+
function RefIndicator({ node, theme, nodeX, nodeY, nodeWidth, nodeHeight, strokeColor, strokeWidth, corner = "bottom-right", size: sizeProp, onNavigate }) {
|
|
17979
18385
|
const [hover, setHover] = (0, import_react8.useState)(false);
|
|
17980
18386
|
const iconKind = theme.node.refIndicator.icon;
|
|
17981
18387
|
if (iconKind === "none")
|
|
17982
18388
|
return null;
|
|
18389
|
+
const size = sizeProp ?? theme.node.refIndicator.size ?? 18;
|
|
17983
18390
|
const stopAll = (e) => e.stopPropagation();
|
|
17984
18391
|
const right = nodeX + nodeWidth;
|
|
17985
18392
|
const bottom = nodeY + nodeHeight;
|
|
@@ -18025,19 +18432,22 @@ var SystemCanvas = (() => {
|
|
|
18025
18432
|
return (0, import_jsx_runtime2.jsxs)("g", { className: "system-canvas-ref-indicator", style: { cursor: "pointer" }, onClick: (e) => {
|
|
18026
18433
|
e.stopPropagation();
|
|
18027
18434
|
onNavigate(node, e);
|
|
18028
|
-
}, onDoubleClick: stopAll, onPointerDown: stopAll, onMouseDown: stopAll, onPointerEnter: () => setHover(true), onPointerLeave: () => setHover(false), children: [hover && (0, import_jsx_runtime2.jsx)("path", { d: hoverPath, fill: hoverFill, pointerEvents: "none" }), (0, import_jsx_runtime2.jsx)("path", { d: carvePath, fill: "none", stroke: strokeColor, strokeWidth: sw, strokeLinecap: "butt", strokeLinejoin: "round", pointerEvents: "none" }), (0, import_jsx_runtime2.jsx)("rect", { x: squareX, y: squareY, width: size, height: size, fill: "transparent" }), (0, import_jsx_runtime2.jsx)(Glyph, { kind: iconKind, cx, cy, color: hover ? hoverGlyph : restGlyph })] });
|
|
18435
|
+
}, onDoubleClick: stopAll, onPointerDown: stopAll, onMouseDown: stopAll, onPointerEnter: () => setHover(true), onPointerLeave: () => setHover(false), children: [hover && (0, import_jsx_runtime2.jsx)("path", { d: hoverPath, fill: hoverFill, pointerEvents: "none" }), (0, import_jsx_runtime2.jsx)("path", { d: carvePath, fill: "none", stroke: strokeColor, strokeWidth: sw, strokeLinecap: "butt", strokeLinejoin: "round", pointerEvents: "none" }), (0, import_jsx_runtime2.jsx)("rect", { x: squareX, y: squareY, width: size, height: size, fill: "transparent" }), (0, import_jsx_runtime2.jsx)(Glyph, { kind: iconKind, cx, cy, color: hover ? hoverGlyph : restGlyph, size })] });
|
|
18029
18436
|
}
|
|
18030
|
-
function Glyph({ kind, cx, cy, color: color2 }) {
|
|
18031
|
-
const s =
|
|
18437
|
+
function Glyph({ kind, cx, cy, color: color2, size }) {
|
|
18438
|
+
const s = size / 6;
|
|
18439
|
+
const sw = Math.max(1, size / 9);
|
|
18032
18440
|
switch (kind) {
|
|
18033
18441
|
case "chevron":
|
|
18034
|
-
return (0, import_jsx_runtime2.jsx)("path", { d: `M ${cx - s / 2} ${cy - s} L ${cx + s / 2} ${cy} L ${cx - s / 2} ${cy + s}`, fill: "none", stroke: color2, strokeWidth:
|
|
18442
|
+
return (0, import_jsx_runtime2.jsx)("path", { d: `M ${cx - s / 2} ${cy - s} L ${cx + s / 2} ${cy} L ${cx - s / 2} ${cy + s}`, fill: "none", stroke: color2, strokeWidth: sw, strokeLinecap: "round", strokeLinejoin: "round", pointerEvents: "none" });
|
|
18035
18443
|
case "arrow": {
|
|
18036
18444
|
const h = s * 0.9;
|
|
18037
|
-
return (0, import_jsx_runtime2.jsx)("path", { d: `M ${cx - s} ${cy} L ${cx + s} ${cy} M ${cx + s - h} ${cy - h} L ${cx + s} ${cy} L ${cx + s - h} ${cy + h}`, fill: "none", stroke: color2, strokeWidth:
|
|
18445
|
+
return (0, import_jsx_runtime2.jsx)("path", { d: `M ${cx - s} ${cy} L ${cx + s} ${cy} M ${cx + s - h} ${cy - h} L ${cx + s} ${cy} L ${cx + s - h} ${cy + h}`, fill: "none", stroke: color2, strokeWidth: sw, strokeLinecap: "round", strokeLinejoin: "round", pointerEvents: "none" });
|
|
18446
|
+
}
|
|
18447
|
+
case "expand": {
|
|
18448
|
+
const sw2 = Math.max(1, size / 12);
|
|
18449
|
+
return (0, import_jsx_runtime2.jsxs)("g", { pointerEvents: "none", children: [(0, import_jsx_runtime2.jsx)("path", { d: `M ${cx - s} ${cy - s} L ${cx + s} ${cy - s} L ${cx + s} ${cy + s} L ${cx - s} ${cy + s} Z`, fill: "none", stroke: color2, strokeWidth: sw2, strokeLinejoin: "round" }), (0, import_jsx_runtime2.jsx)("line", { x1: cx, y1: cy - s + 1, x2: cx, y2: cy + s - 1, stroke: color2, strokeWidth: sw2, strokeLinecap: "round" }), (0, import_jsx_runtime2.jsx)("line", { x1: cx - s + 1, y1: cy, x2: cx + s - 1, y2: cy, stroke: color2, strokeWidth: sw2, strokeLinecap: "round" })] });
|
|
18038
18450
|
}
|
|
18039
|
-
case "expand":
|
|
18040
|
-
return (0, import_jsx_runtime2.jsxs)("g", { pointerEvents: "none", children: [(0, import_jsx_runtime2.jsx)("path", { d: `M ${cx - s} ${cy - s} L ${cx + s} ${cy - s} L ${cx + s} ${cy + s} L ${cx - s} ${cy + s} Z`, fill: "none", stroke: color2, strokeWidth: 1.5, strokeLinejoin: "round" }), (0, import_jsx_runtime2.jsx)("line", { x1: cx, y1: cy - s + 1, x2: cx, y2: cy + s - 1, stroke: color2, strokeWidth: 1.5, strokeLinecap: "round" }), (0, import_jsx_runtime2.jsx)("line", { x1: cx - s + 1, y1: cy, x2: cx + s - 1, y2: cy, stroke: color2, strokeWidth: 1.5, strokeLinecap: "round" })] });
|
|
18041
18451
|
}
|
|
18042
18452
|
}
|
|
18043
18453
|
|
|
@@ -18164,7 +18574,7 @@ var SystemCanvas = (() => {
|
|
|
18164
18574
|
// ../react/dist/primitives/NodeText.js
|
|
18165
18575
|
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
18166
18576
|
var import_react9 = __toESM(require_react(), 1);
|
|
18167
|
-
function NodeText({ region, value, theme, color: color2, fill, align = "start", fontWeight = 500, uppercase = false, useLabelFont = false, fontFamily, fontSize: fontSizeProp, wrap = false, maxLines, lineHeight: lineHeightProp }) {
|
|
18577
|
+
function NodeText({ region, value, theme, color: color2, fill, align = "start", fontWeight = 500, uppercase = false, useLabelFont = false, fontFamily, fontSize: fontSizeProp, wrap = false, maxLines, lineHeight: lineHeightProp, verticalAlign = "top" }) {
|
|
18168
18578
|
const reactId = (0, import_react9.useId)();
|
|
18169
18579
|
const safeId = reactId.replace(/:/g, "");
|
|
18170
18580
|
if (!value)
|
|
@@ -18178,13 +18588,16 @@ var SystemCanvas = (() => {
|
|
|
18178
18588
|
const fillAttr = gradId ? `url(#${gradId})` : color2 ?? theme.node.sublabelColor;
|
|
18179
18589
|
const displayValue = uppercase ? value.toUpperCase() : value;
|
|
18180
18590
|
if (!wrap) {
|
|
18591
|
+
const rendered = truncateToWidth(displayValue, region.width, fontSize);
|
|
18181
18592
|
const y = region.y + region.height / 2 + fontSize * 0.36;
|
|
18182
|
-
return (0, import_jsx_runtime7.jsxs)("g", { pointerEvents: "none", children: [fill && (0, import_jsx_runtime7.jsx)(GradientDef, { id: gradId, fill }), (0, import_jsx_runtime7.jsx)("text", { x, y, fill: fillAttr, fontSize, fontWeight, fontFamily: font, textAnchor: anchor, letterSpacing: uppercase ? 0.8 : 0.2, pointerEvents: "none", children:
|
|
18593
|
+
return (0, import_jsx_runtime7.jsxs)("g", { pointerEvents: "none", children: [fill && (0, import_jsx_runtime7.jsx)(GradientDef, { id: gradId, fill }), (0, import_jsx_runtime7.jsx)("text", { x, y, fill: fillAttr, fontSize, fontWeight, fontFamily: font, textAnchor: anchor, letterSpacing: uppercase ? 0.8 : 0.2, pointerEvents: "none", children: rendered })] });
|
|
18183
18594
|
}
|
|
18184
18595
|
const lines = wrapTextWithBreaks(displayValue, region.width, fontSize, maxLines);
|
|
18185
18596
|
if (lines.length === 0)
|
|
18186
18597
|
return null;
|
|
18187
|
-
const
|
|
18598
|
+
const blockHeight = fontSize + (lines.length - 1) * lineHeight;
|
|
18599
|
+
const topY = region.y + fontSize;
|
|
18600
|
+
const baseY = verticalAlign === "center" ? region.y + (region.height - blockHeight) / 2 + fontSize : verticalAlign === "bottom" ? region.y + region.height - blockHeight + fontSize : topY;
|
|
18188
18601
|
const clipId = `sc-text-clip-${safeId}`;
|
|
18189
18602
|
return (0, import_jsx_runtime7.jsxs)("g", { pointerEvents: "none", children: [(0, import_jsx_runtime7.jsxs)("defs", { children: [fill && (0, import_jsx_runtime7.jsx)(GradientDef, { id: gradId, fill }), (0, import_jsx_runtime7.jsx)("clipPath", { id: clipId, children: (0, import_jsx_runtime7.jsx)("rect", { x: region.x, y: region.y, width: region.width, height: region.height }) })] }), (0, import_jsx_runtime7.jsx)("g", { clipPath: `url(#${clipId})`, pointerEvents: "none", children: (0, import_jsx_runtime7.jsx)("text", { x, y: baseY, fill: fillAttr, fontSize, fontWeight, fontFamily: font, textAnchor: anchor, letterSpacing: uppercase ? 0.8 : 0.2, pointerEvents: "none", children: lines.map((line, i) => (0, import_jsx_runtime7.jsx)("tspan", { x, dy: i === 0 ? 0 : lineHeight, children: line || " " }, i)) }) })] });
|
|
18190
18603
|
}
|
|
@@ -18336,6 +18749,20 @@ var SystemCanvas = (() => {
|
|
|
18336
18749
|
const color2 = resolveAccessorOr(spec.color, nodeColor, ctx);
|
|
18337
18750
|
return (0, import_jsx_runtime9.jsx)(NodeDot, { region, color: color2 });
|
|
18338
18751
|
}
|
|
18752
|
+
case "icon": {
|
|
18753
|
+
const name = resolveAccessor(spec.name, ctx);
|
|
18754
|
+
if (!name)
|
|
18755
|
+
return null;
|
|
18756
|
+
const color2 = resolveAccessorOr(spec.color, nodeColor, ctx);
|
|
18757
|
+
const opacity = resolveAccessorOr(spec.opacity, 1, ctx);
|
|
18758
|
+
const mode = resolveAccessorOr(spec.mode, "stroke", ctx);
|
|
18759
|
+
const viewBox = resolveAccessorOr(spec.viewBox, 16, ctx);
|
|
18760
|
+
const auto = Math.max(8, Math.min(region.width, region.height) - 2);
|
|
18761
|
+
const size = resolveAccessorOr(spec.size, auto, ctx);
|
|
18762
|
+
const x = region.x + (region.width - size) / 2;
|
|
18763
|
+
const y = region.y + (region.height - size) / 2;
|
|
18764
|
+
return (0, import_jsx_runtime9.jsx)(NodeIcon, { icon: name, x, y, size, color: color2, opacity, customIcons: theme.icons, mode, viewBox });
|
|
18765
|
+
}
|
|
18339
18766
|
case "custom": {
|
|
18340
18767
|
return spec.render(ctx);
|
|
18341
18768
|
}
|
|
@@ -18363,20 +18790,21 @@ var SystemCanvas = (() => {
|
|
|
18363
18790
|
const contentY = y + reservedTop;
|
|
18364
18791
|
const contentWidth = Math.max(0, width - reservedLeft - reservedRight);
|
|
18365
18792
|
const contentHeight = Math.max(0, height - reservedTop - reservedBottom);
|
|
18366
|
-
const
|
|
18367
|
-
const
|
|
18368
|
-
const
|
|
18369
|
-
const sublabel = lines[1];
|
|
18793
|
+
const LABEL_PAD_X = 10;
|
|
18794
|
+
const LABEL_PAD_Y = 6;
|
|
18795
|
+
const text = node.text ?? node.id;
|
|
18370
18796
|
const hasBodySlot = slots?.body !== void 0;
|
|
18371
18797
|
const hasHeader = reservedTop > 0;
|
|
18372
|
-
const
|
|
18798
|
+
const hasInlineLeftMarker = slots?.topLeft !== void 0 && (slots.topLeft.kind === "dot" || slots.topLeft.kind === "icon") && !hasHeader;
|
|
18799
|
+
const isLeftAligned = hasHeader || hasInlineLeftMarker;
|
|
18373
18800
|
const labelFontSize = theme.node.fontSize + (hasHeader ? 1 : 0);
|
|
18374
|
-
const
|
|
18375
|
-
|
|
18376
|
-
|
|
18377
|
-
|
|
18378
|
-
|
|
18379
|
-
|
|
18801
|
+
const labelAlign = isLeftAligned ? "start" : "center";
|
|
18802
|
+
return (0, import_jsx_runtime10.jsxs)("g", { className: "system-canvas-node system-canvas-node--text", style: { cursor: onPointerDown ? "move" : node.isNavigable ? "pointer" : "default" }, onClick: (e) => onClick(node, e), onDoubleClick: (e) => onDoubleClick(node, e), onContextMenu: (e) => onContextMenu(node, e), onPointerDown: onPointerDown ? (e) => onPointerDown(node, e) : void 0, children: [(0, import_jsx_runtime10.jsx)("rect", { x, y, width, height, rx: node.resolvedCornerRadius, fill: theme.background }), (0, import_jsx_runtime10.jsx)("rect", { x, y, width, height, rx: node.resolvedCornerRadius, fill: node.resolvedFill, stroke: node.resolvedStroke, strokeWidth: theme.node.strokeWidth }), !isEditing && !hasBodySlot && (0, import_jsx_runtime10.jsx)(NodeText, { region: {
|
|
18803
|
+
x: contentX + LABEL_PAD_X,
|
|
18804
|
+
y: contentY + LABEL_PAD_Y,
|
|
18805
|
+
width: Math.max(0, contentWidth - LABEL_PAD_X * 2),
|
|
18806
|
+
height: Math.max(0, contentHeight - LABEL_PAD_Y * 2)
|
|
18807
|
+
}, value: text, theme, color: theme.node.labelColor, align: labelAlign, fontWeight: 600, fontSize: labelFontSize, useLabelFont: true, wrap: true, verticalAlign: hasHeader ? "top" : "center" }), node.resolvedIcon && (0, import_jsx_runtime10.jsx)(NodeIcon, { icon: node.resolvedIcon, x: x + 8 + reservedLeft, y: contentY + contentHeight / 2 - 7, size: 14, color: node.resolvedStroke, opacity: 0.7, customIcons: theme.icons }), slots && (0, import_jsx_runtime10.jsx)(CategorySlotsLayer, { node, theme, canvases, slots }), node.isNavigable && (0, import_jsx_runtime10.jsx)(RefIndicator, { node, theme, nodeX: x, nodeY: y, nodeWidth: width, nodeHeight: height, strokeColor: node.resolvedStroke, strokeWidth: theme.node.strokeWidth, corner: toKebabCorner(refCorner), onNavigate })] });
|
|
18380
18808
|
}
|
|
18381
18809
|
|
|
18382
18810
|
// ../react/dist/components/FileNode.js
|
|
@@ -18390,6 +18818,7 @@ var SystemCanvas = (() => {
|
|
|
18390
18818
|
const fold = 10;
|
|
18391
18819
|
const textPadding = 10 + reservedLeft;
|
|
18392
18820
|
const maxTextWidth = width - textPadding - reservedRight - fold;
|
|
18821
|
+
const LABEL_PAD_Y = 6;
|
|
18393
18822
|
const contentY = y + reservedTop;
|
|
18394
18823
|
const contentHeight = Math.max(0, height - reservedTop - reservedBottom);
|
|
18395
18824
|
const shapePath = [
|
|
@@ -18408,7 +18837,12 @@ var SystemCanvas = (() => {
|
|
|
18408
18837
|
const strokeColor = node.resolvedStroke;
|
|
18409
18838
|
const thinStroke = 0.75;
|
|
18410
18839
|
const clipId = `file-clip-${node.id}`;
|
|
18411
|
-
return (0, import_jsx_runtime11.jsxs)("g", { className: "system-canvas-node system-canvas-node--file", style: { cursor: onPointerDown ? "move" : node.isNavigable ? "pointer" : "default" }, onClick: (e) => onClick(node, e), onDoubleClick: (e) => onDoubleClick(node, e), onContextMenu: (e) => onContextMenu(node, e), onPointerDown: onPointerDown ? (e) => onPointerDown(node, e) : void 0, children: [(0, import_jsx_runtime11.jsx)("defs", { children: (0, import_jsx_runtime11.jsx)("clipPath", { id: clipId, children: (0, import_jsx_runtime11.jsx)("rect", { x: x + textPadding, y: contentY, width: maxTextWidth, height: contentHeight }) }) }), (0, import_jsx_runtime11.jsx)("path", { d: shapePath, fill: theme.background }), (0, import_jsx_runtime11.jsx)("path", { d: shapePath, fill: node.resolvedFill, stroke: strokeColor, strokeWidth: thinStroke }), (0, import_jsx_runtime11.jsx)("path", { d: foldPath, fill: "none", stroke: strokeColor, strokeWidth: thinStroke, opacity: 0.5 }), !isEditing && !slots?.body && (0, import_jsx_runtime11.jsxs)("g", { clipPath: `url(#${clipId})`, children: [dirPath && (0, import_jsx_runtime11.jsxs)("text", { x: x + textPadding, y: contentY + 14, fill: theme.node.sublabelColor, fontSize: theme.node.sublabelFontSize - 1, fontFamily: theme.node.fontFamily, pointerEvents: "none", opacity: 0.6, children: [dirPath, "/"] }), (0, import_jsx_runtime11.jsx)(
|
|
18840
|
+
return (0, import_jsx_runtime11.jsxs)("g", { className: "system-canvas-node system-canvas-node--file", style: { cursor: onPointerDown ? "move" : node.isNavigable ? "pointer" : "default" }, onClick: (e) => onClick(node, e), onDoubleClick: (e) => onDoubleClick(node, e), onContextMenu: (e) => onContextMenu(node, e), onPointerDown: onPointerDown ? (e) => onPointerDown(node, e) : void 0, children: [(0, import_jsx_runtime11.jsx)("defs", { children: (0, import_jsx_runtime11.jsx)("clipPath", { id: clipId, children: (0, import_jsx_runtime11.jsx)("rect", { x: x + textPadding, y: contentY, width: maxTextWidth, height: contentHeight }) }) }), (0, import_jsx_runtime11.jsx)("path", { d: shapePath, fill: theme.background }), (0, import_jsx_runtime11.jsx)("path", { d: shapePath, fill: node.resolvedFill, stroke: strokeColor, strokeWidth: thinStroke }), (0, import_jsx_runtime11.jsx)("path", { d: foldPath, fill: "none", stroke: strokeColor, strokeWidth: thinStroke, opacity: 0.5 }), !isEditing && !slots?.body && (0, import_jsx_runtime11.jsxs)("g", { clipPath: `url(#${clipId})`, children: [dirPath && (0, import_jsx_runtime11.jsxs)("text", { x: x + textPadding, y: contentY + 14, fill: theme.node.sublabelColor, fontSize: theme.node.sublabelFontSize - 1, fontFamily: theme.node.fontFamily, pointerEvents: "none", opacity: 0.6, children: [dirPath, "/"] }), (0, import_jsx_runtime11.jsx)(NodeText, { region: {
|
|
18841
|
+
x: x + textPadding,
|
|
18842
|
+
y: dirPath ? contentY + 18 : contentY + (subpath ? 8 : LABEL_PAD_Y),
|
|
18843
|
+
width: maxTextWidth,
|
|
18844
|
+
height: dirPath ? Math.max(0, contentHeight - 18 - (subpath ? 16 : 0)) : Math.max(0, contentHeight - (subpath ? 16 : 0) - LABEL_PAD_Y * 2)
|
|
18845
|
+
}, value: fileName, theme, color: theme.node.labelColor, align: "start", fontWeight: 500, fontSize: theme.node.fontSize - 1, wrap: true, verticalAlign: dirPath ? "top" : "center" }), subpath && (0, import_jsx_runtime11.jsx)("text", { x: x + textPadding, y: contentY + (dirPath ? 40 : contentHeight / 2 + theme.node.fontSize + 2), fill: theme.node.sublabelColor, fontSize: theme.node.sublabelFontSize, fontFamily: theme.node.fontFamily, pointerEvents: "none", children: subpath })] }), slots && (0, import_jsx_runtime11.jsx)(CategorySlotsLayer, { node, theme, canvases, slots }), node.isNavigable && (0, import_jsx_runtime11.jsx)(RefIndicator, { node, theme, nodeX: x, nodeY: y, nodeWidth: width, nodeHeight: height, strokeColor, strokeWidth: thinStroke, corner: toKebabCorner(refCorner), onNavigate })] });
|
|
18412
18846
|
}
|
|
18413
18847
|
|
|
18414
18848
|
// ../react/dist/components/LinkNode.js
|
|
@@ -18419,14 +18853,21 @@ var SystemCanvas = (() => {
|
|
|
18419
18853
|
const contentY = y + reservedTop;
|
|
18420
18854
|
const contentWidth = Math.max(0, width - reservedLeft - reservedRight);
|
|
18421
18855
|
const contentHeight = Math.max(0, height - reservedTop - reservedBottom);
|
|
18422
|
-
const
|
|
18856
|
+
const glyphReserve = 20;
|
|
18857
|
+
const LABEL_PAD_X = 10;
|
|
18858
|
+
const LABEL_PAD_Y = 6;
|
|
18423
18859
|
let displayUrl = node.url ?? "";
|
|
18424
18860
|
try {
|
|
18425
18861
|
const url = new URL(displayUrl);
|
|
18426
18862
|
displayUrl = url.hostname;
|
|
18427
18863
|
} catch {
|
|
18428
18864
|
}
|
|
18429
|
-
return (0, import_jsx_runtime12.jsxs)("g", { className: "system-canvas-node system-canvas-node--link", style: { cursor: onPointerDown ? "move" : "pointer" }, onClick: (e) => onClick(node, e), onDoubleClick: (e) => onDoubleClick(node, e), onContextMenu: (e) => onContextMenu(node, e), onPointerDown: onPointerDown ? (e) => onPointerDown(node, e) : void 0, children: [(0, import_jsx_runtime12.jsx)("rect", { x, y, width, height, rx: node.resolvedCornerRadius, fill: theme.background }), (0, import_jsx_runtime12.jsx)("rect", { x, y, width, height, rx: node.resolvedCornerRadius, fill: node.resolvedFill, stroke: node.resolvedStroke, strokeWidth: theme.node.strokeWidth }), !isEditing && !slots?.body && (0, import_jsx_runtime12.jsx)("text", { x: contentX + 12, y: contentY + contentHeight / 2 + 4, fill: node.resolvedStroke, fontSize: 12, fontFamily: theme.node.fontFamily, pointerEvents: "none", opacity: 0.6, children: "\u29C9" }), !isEditing && !slots?.body && (0, import_jsx_runtime12.jsx)(
|
|
18865
|
+
return (0, import_jsx_runtime12.jsxs)("g", { className: "system-canvas-node system-canvas-node--link", style: { cursor: onPointerDown ? "move" : "pointer" }, onClick: (e) => onClick(node, e), onDoubleClick: (e) => onDoubleClick(node, e), onContextMenu: (e) => onContextMenu(node, e), onPointerDown: onPointerDown ? (e) => onPointerDown(node, e) : void 0, children: [(0, import_jsx_runtime12.jsx)("rect", { x, y, width, height, rx: node.resolvedCornerRadius, fill: theme.background }), (0, import_jsx_runtime12.jsx)("rect", { x, y, width, height, rx: node.resolvedCornerRadius, fill: node.resolvedFill, stroke: node.resolvedStroke, strokeWidth: theme.node.strokeWidth }), !isEditing && !slots?.body && (0, import_jsx_runtime12.jsx)("text", { x: contentX + 12, y: contentY + contentHeight / 2 + 4, fill: node.resolvedStroke, fontSize: 12, fontFamily: theme.node.fontFamily, pointerEvents: "none", opacity: 0.6, children: "\u29C9" }), !isEditing && !slots?.body && (0, import_jsx_runtime12.jsx)(NodeText, { region: {
|
|
18866
|
+
x: contentX + glyphReserve,
|
|
18867
|
+
y: contentY + LABEL_PAD_Y,
|
|
18868
|
+
width: Math.max(0, contentWidth - glyphReserve - LABEL_PAD_X),
|
|
18869
|
+
height: Math.max(0, contentHeight - LABEL_PAD_Y * 2)
|
|
18870
|
+
}, value: displayUrl, theme, color: theme.node.labelColor, align: "center", fontWeight: 600, fontSize: theme.node.fontSize, wrap: true, verticalAlign: "center" }), slots && (0, import_jsx_runtime12.jsx)(CategorySlotsLayer, { node, theme, canvases, slots }), node.isNavigable && (0, import_jsx_runtime12.jsx)(RefIndicator, { node, theme, nodeX: x, nodeY: y, nodeWidth: width, nodeHeight: height, strokeColor: node.resolvedStroke, strokeWidth: theme.node.strokeWidth, corner: toKebabCorner(refCorner), onNavigate })] });
|
|
18430
18871
|
}
|
|
18431
18872
|
|
|
18432
18873
|
// ../react/dist/components/GroupNode.js
|
|
@@ -18552,7 +18993,8 @@ var SystemCanvas = (() => {
|
|
|
18552
18993
|
const isEditing = editingId === edge.id;
|
|
18553
18994
|
const baseColor = edge.color ? resolveColor(edge.color, theme).stroke : theme.edge.stroke;
|
|
18554
18995
|
const edgeColor = isSelected ? theme.node.labelColor : baseColor;
|
|
18555
|
-
const
|
|
18996
|
+
const baseStrokeWidth = edge.strokeWidth ?? theme.edge.strokeWidth;
|
|
18997
|
+
const strokeWidth = isSelected ? baseStrokeWidth * 1.75 : baseStrokeWidth;
|
|
18556
18998
|
const toEnd = edge.toEnd ?? "arrow";
|
|
18557
18999
|
const fromEnd = edge.fromEnd ?? "none";
|
|
18558
19000
|
const arrowId = "system-canvas-arrowhead";
|
|
@@ -18615,6 +19057,10 @@ var SystemCanvas = (() => {
|
|
|
18615
19057
|
const fontFamily = theme.node.fontFamily;
|
|
18616
19058
|
const fontSize = theme.node.fontSize;
|
|
18617
19059
|
const padding = 8;
|
|
19060
|
+
const slots = getCategorySlots(node, theme);
|
|
19061
|
+
const reservations = computeReflowReservations(node, theme, slots);
|
|
19062
|
+
const hasHeader = reservations.top > 0;
|
|
19063
|
+
const textAlign = node.type === "text" && !hasHeader ? "center" : "left";
|
|
18618
19064
|
const commonFieldStyle = {
|
|
18619
19065
|
width: "100%",
|
|
18620
19066
|
height: "100%",
|
|
@@ -18628,7 +19074,7 @@ var SystemCanvas = (() => {
|
|
|
18628
19074
|
borderRadius: node.resolvedCornerRadius,
|
|
18629
19075
|
outline: "none",
|
|
18630
19076
|
resize: "none",
|
|
18631
|
-
textAlign
|
|
19077
|
+
textAlign
|
|
18632
19078
|
};
|
|
18633
19079
|
return (0, import_jsx_runtime17.jsx)("foreignObject", { x: node.x, y: node.y, width: node.width, height: node.height, onPointerDown: stopPointer, onMouseDown: stopPointer, onClick: stopPointer, onDoubleClick: stopPointer, children: node.type === "text" ? (0, import_jsx_runtime17.jsx)("textarea", { ref: textareaRef, value, onChange: (e) => setValue(e.target.value), onBlur: commit, onKeyDown: (e) => {
|
|
18634
19080
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
@@ -18998,7 +19444,7 @@ var SystemCanvas = (() => {
|
|
|
18998
19444
|
// ../react/dist/components/Viewport.js
|
|
18999
19445
|
var HOVER_PADDING = 10;
|
|
19000
19446
|
var EDGE_PROXIMITY = 16;
|
|
19001
|
-
var Viewport = (0, import_react15.forwardRef)(function Viewport2({ nodes, edges, nodeMap, theme, edgeStyle, columns, rows, canvases, minZoom, maxZoom, defaultViewport, onViewportChange, onNodeClick, onNodeDoubleClick, onNodeNavigate, onEdgeClick, onEdgeDoubleClick, onCanvasClick, onCanvasContextMenu, onNodeContextMenu, onEdgeContextMenu, onNodePointerDown, selectedId, editingId, selectedEdgeId, editingEdgeId, dragOverrides, resizeOverrides, onResizeHandlePointerDown, onEditorCommit, onEditorCancel, onEdgeEditorCommit, onEdgeEditorCancel, pendingEdge, onConnectionHandlePointerDown, edgeCreateEnabled, autoFit = "canvas-change", canvasRef, handoffTransform, onHandoffApplied, handoffFadeMs = 0 }, ref) {
|
|
19447
|
+
var Viewport = (0, import_react15.forwardRef)(function Viewport2({ nodes, edges, nodeMap, theme, edgeStyle, columns, rows, canvases, minZoom, maxZoom, defaultViewport, onViewportChange, onNodeClick, onNodeDoubleClick, onNodeNavigate, onEdgeClick, onEdgeDoubleClick, onCanvasClick, onCanvasContextMenu, onNodeContextMenu, onEdgeContextMenu, onNodePointerDown, selectedId, editingId, selectedEdgeId, editingEdgeId, dragOverrides, dropTargetId, resizeOverrides, onResizeHandlePointerDown, onEditorCommit, onEditorCancel, onEdgeEditorCommit, onEdgeEditorCancel, pendingEdge, onConnectionHandlePointerDown, edgeCreateEnabled, autoFit = "canvas-change", canvasRef, handoffTransform, onHandoffApplied, handoffFadeMs = 0 }, ref) {
|
|
19002
19448
|
const { svgRef, groupRef, viewport, fitToContent, zoomToNode, setTransform } = useViewport({
|
|
19003
19449
|
minZoom,
|
|
19004
19450
|
maxZoom,
|
|
@@ -19041,6 +19487,7 @@ var SystemCanvas = (() => {
|
|
|
19041
19487
|
}, []);
|
|
19042
19488
|
const [hoveredNodeId, setHoveredNodeId] = (0, import_react15.useState)(null);
|
|
19043
19489
|
const [hoveredSide, setHoveredSide] = (0, import_react15.useState)(null);
|
|
19490
|
+
const cursorPosRef = (0, import_react15.useRef)(null);
|
|
19044
19491
|
(0, import_react15.useImperativeHandle)(ref, () => ({
|
|
19045
19492
|
zoomToNode: (node, onComplete, options) => {
|
|
19046
19493
|
navigatingRef.current = true;
|
|
@@ -19049,7 +19496,8 @@ var SystemCanvas = (() => {
|
|
|
19049
19496
|
fitToContent,
|
|
19050
19497
|
setTransform,
|
|
19051
19498
|
getSvgElement: () => svgRef.current,
|
|
19052
|
-
getViewport: () => viewport.current ?? { x: 0, y: 0, zoom: 1 }
|
|
19499
|
+
getViewport: () => viewport.current ?? { x: 0, y: 0, zoom: 1 },
|
|
19500
|
+
getCursorScreenPos: () => cursorPosRef.current
|
|
19053
19501
|
}));
|
|
19054
19502
|
const renderNodes = (0, import_react15.useMemo)(() => {
|
|
19055
19503
|
const hasDrag = dragOverrides && dragOverrides.size > 0;
|
|
@@ -19132,14 +19580,17 @@ var SystemCanvas = (() => {
|
|
|
19132
19580
|
]);
|
|
19133
19581
|
const editingNode = editingId ? renderNodes.find((n) => n.id === editingId) ?? null : null;
|
|
19134
19582
|
const handleSvgPointerMove = (0, import_react15.useCallback)((event) => {
|
|
19135
|
-
if (!edgeCreateEnabled)
|
|
19136
|
-
return;
|
|
19137
19583
|
const svg = svgRef.current;
|
|
19138
19584
|
if (!svg)
|
|
19139
19585
|
return;
|
|
19140
19586
|
const rect = svg.getBoundingClientRect();
|
|
19587
|
+
const cursorScreenX = event.clientX - rect.left;
|
|
19588
|
+
const cursorScreenY = event.clientY - rect.top;
|
|
19589
|
+
cursorPosRef.current = { x: cursorScreenX, y: cursorScreenY };
|
|
19590
|
+
if (!edgeCreateEnabled)
|
|
19591
|
+
return;
|
|
19141
19592
|
const vp = viewport.current ?? { x: 0, y: 0, zoom: 1 };
|
|
19142
|
-
const { x, y } = screenToCanvas(
|
|
19593
|
+
const { x, y } = screenToCanvas(cursorScreenX, cursorScreenY, vp);
|
|
19143
19594
|
const pad = HOVER_PADDING;
|
|
19144
19595
|
let hit = null;
|
|
19145
19596
|
for (let i = renderNodes.length - 1; i >= 0; i--) {
|
|
@@ -19183,11 +19634,13 @@ var SystemCanvas = (() => {
|
|
|
19183
19634
|
const handleSvgPointerLeave = (0, import_react15.useCallback)(() => {
|
|
19184
19635
|
setHoveredNodeId(null);
|
|
19185
19636
|
setHoveredSide(null);
|
|
19637
|
+
cursorPosRef.current = null;
|
|
19186
19638
|
}, []);
|
|
19187
19639
|
const handlesNodeId = pendingEdge?.sourceId ?? hoveredNodeId;
|
|
19188
19640
|
const handlesNode = edgeCreateEnabled && handlesNodeId ? renderNodeMap.get(handlesNodeId) ?? null : null;
|
|
19189
19641
|
const pendingSourceNode = pendingEdge ? renderNodeMap.get(pendingEdge.sourceId) ?? null : null;
|
|
19190
19642
|
const pendingTargetNode = pendingEdge?.hoveredTargetId && pendingEdge.hoveredTargetId !== pendingEdge.sourceId ? renderNodeMap.get(pendingEdge.hoveredTargetId) ?? null : null;
|
|
19643
|
+
const dropTargetNode = dropTargetId ? renderNodeMap.get(dropTargetId) ?? null : null;
|
|
19191
19644
|
const editingEdge = editingEdgeId ? edges.find((e) => e.id === editingEdgeId) ?? null : null;
|
|
19192
19645
|
const editingEdgeMidpoint = (() => {
|
|
19193
19646
|
if (!editingEdge)
|
|
@@ -19207,7 +19660,7 @@ var SystemCanvas = (() => {
|
|
|
19207
19660
|
WebkitUserSelect: "none",
|
|
19208
19661
|
MozUserSelect: "none",
|
|
19209
19662
|
msUserSelect: "none"
|
|
19210
|
-
}, onClick: onCanvasClick, onContextMenu: onCanvasContextMenu, onPointerMove: handleSvgPointerMove, onPointerLeave: handleSvgPointerLeave, children: [(0, import_jsx_runtime22.jsx)("defs", { children: (0, import_jsx_runtime22.jsx)("pattern", { id: "system-canvas-grid", width: theme.grid.size, height: theme.grid.size, patternUnits: "userSpaceOnUse", children: (0, import_jsx_runtime22.jsx)("path", { d: `M ${theme.grid.size} 0 L 0 0 0 ${theme.grid.size}`, fill: "none", stroke: theme.grid.color, strokeWidth: theme.grid.strokeWidth }) }) }), (0, import_jsx_runtime22.jsx)("rect", { x: "-50000", y: "-50000", width: "100000", height: "100000", fill: "url(#system-canvas-grid)" }), (0, import_jsx_runtime22.jsxs)("g", { ref: groupRef, children: [(0, import_jsx_runtime22.jsx)(LanesBackground, { columns, rows, theme }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedId, editingId, canvases, only: "groups" }), (0, import_jsx_runtime22.jsx)(EdgeRenderer, { edges, nodeMap: renderNodeMap, theme, defaultEdgeStyle: edgeStyle, onClick: onEdgeClick, onDoubleClick: onEdgeDoubleClick, onContextMenu: onEdgeContextMenu, selectedId: selectedEdgeId, editingId: editingEdgeId }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedId, editingId, onResizeHandlePointerDown, canvases, only: "non-groups" }), pendingTargetNode && (0, import_jsx_runtime22.jsx)("rect", { className: "system-canvas-drop-target", x: pendingTargetNode.x - 4, y: pendingTargetNode.y - 4, width: pendingTargetNode.width + 8, height: pendingTargetNode.height + 8, rx: pendingTargetNode.resolvedCornerRadius + 4, fill: "none", stroke: theme.node.labelColor, strokeWidth: 2, opacity: 0.85, pointerEvents: "none" }), pendingEdge && pendingSourceNode && (0, import_jsx_runtime22.jsx)(PendingEdgeRenderer, { sourceNode: pendingSourceNode, sourceSide: pendingEdge.sourceSide, cursor: pendingEdge.cursor, targetNode: pendingTargetNode, theme, defaultEdgeStyle: edgeStyle }), handlesNode && onConnectionHandlePointerDown && (0, import_jsx_runtime22.jsx)(ConnectionHandles, { node: handlesNode, theme, onHandlePointerDown: onConnectionHandlePointerDown, immediate: !!pendingEdge, activeSide: hoveredSide }), editingNode && onEditorCommit && onEditorCancel && (0, import_jsx_runtime22.jsx)(NodeEditor, { node: editingNode, theme, onCommit: onEditorCommit, onCancel: onEditorCancel }), editingEdge && editingEdgeMidpoint && onEdgeEditorCommit && onEdgeEditorCancel && (0, import_jsx_runtime22.jsx)(EdgeLabelEditor, { initialLabel: editingEdge.label ?? "", midpoint: editingEdgeMidpoint, theme, onCommit: onEdgeEditorCommit, onCancel: onEdgeEditorCancel })] })] });
|
|
19663
|
+
}, onClick: onCanvasClick, onContextMenu: onCanvasContextMenu, onPointerMove: handleSvgPointerMove, onPointerLeave: handleSvgPointerLeave, children: [(0, import_jsx_runtime22.jsx)("defs", { children: (0, import_jsx_runtime22.jsx)("pattern", { id: "system-canvas-grid", width: theme.grid.size, height: theme.grid.size, patternUnits: "userSpaceOnUse", children: (0, import_jsx_runtime22.jsx)("path", { d: `M ${theme.grid.size} 0 L 0 0 0 ${theme.grid.size}`, fill: "none", stroke: theme.grid.color, strokeWidth: theme.grid.strokeWidth }) }) }), (0, import_jsx_runtime22.jsx)("rect", { x: "-50000", y: "-50000", width: "100000", height: "100000", fill: "url(#system-canvas-grid)" }), (0, import_jsx_runtime22.jsxs)("g", { ref: groupRef, children: [(0, import_jsx_runtime22.jsx)(LanesBackground, { columns, rows, theme }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedId, editingId, canvases, only: "groups" }), (0, import_jsx_runtime22.jsx)(EdgeRenderer, { edges, nodeMap: renderNodeMap, theme, defaultEdgeStyle: edgeStyle, onClick: onEdgeClick, onDoubleClick: onEdgeDoubleClick, onContextMenu: onEdgeContextMenu, selectedId: selectedEdgeId, editingId: editingEdgeId }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedId, editingId, onResizeHandlePointerDown, canvases, only: "non-groups" }), pendingTargetNode && (0, import_jsx_runtime22.jsx)("rect", { className: "system-canvas-drop-target", x: pendingTargetNode.x - 4, y: pendingTargetNode.y - 4, width: pendingTargetNode.width + 8, height: pendingTargetNode.height + 8, rx: pendingTargetNode.resolvedCornerRadius + 4, fill: "none", stroke: theme.node.labelColor, strokeWidth: 2, opacity: 0.85, pointerEvents: "none" }), dropTargetNode && (0, import_jsx_runtime22.jsx)("rect", { className: "system-canvas-drop-target system-canvas-node-drop-target", x: dropTargetNode.x - 4, y: dropTargetNode.y - 4, width: dropTargetNode.width + 8, height: dropTargetNode.height + 8, rx: dropTargetNode.resolvedCornerRadius + 4, fill: "none", stroke: theme.node.labelColor, strokeWidth: 2, strokeDasharray: "6 4", opacity: 0.9, pointerEvents: "none" }), pendingEdge && pendingSourceNode && (0, import_jsx_runtime22.jsx)(PendingEdgeRenderer, { sourceNode: pendingSourceNode, sourceSide: pendingEdge.sourceSide, cursor: pendingEdge.cursor, targetNode: pendingTargetNode, theme, defaultEdgeStyle: edgeStyle }), handlesNode && onConnectionHandlePointerDown && (0, import_jsx_runtime22.jsx)(ConnectionHandles, { node: handlesNode, theme, onHandlePointerDown: onConnectionHandlePointerDown, immediate: !!pendingEdge, activeSide: hoveredSide }), editingNode && onEditorCommit && onEditorCancel && (0, import_jsx_runtime22.jsx)(NodeEditor, { node: editingNode, theme, onCommit: onEditorCommit, onCancel: onEditorCancel }), editingEdge && editingEdgeMidpoint && onEdgeEditorCommit && onEdgeEditorCancel && (0, import_jsx_runtime22.jsx)(EdgeLabelEditor, { initialLabel: editingEdge.label ?? "", midpoint: editingEdgeMidpoint, theme, onCommit: onEdgeEditorCommit, onCancel: onEdgeEditorCancel })] })] });
|
|
19211
19664
|
});
|
|
19212
19665
|
|
|
19213
19666
|
// ../react/dist/components/Breadcrumbs.js
|
|
@@ -19436,7 +19889,7 @@ var SystemCanvas = (() => {
|
|
|
19436
19889
|
const cx = visibleLeft + visibleW / 2;
|
|
19437
19890
|
if (endScreen <= colsOffsetLeft || startScreen >= width)
|
|
19438
19891
|
return null;
|
|
19439
|
-
return (0, import_jsx_runtime25.jsxs)("g", { children: [(0, import_jsx_runtime25.jsx)("line", { x1: startScreen, y1: pinned ? headerSize : y + headerSize, x2: startScreen, y2: pinned ? 0 : y, stroke: lanesTheme.dividerColor, strokeWidth: lanesTheme.dividerWidth }), (0, import_jsx_runtime25.jsx)("text", { x: cx, y: (pinned ? 0 : y) + headerSize / 2, textAnchor: "middle", dominantBaseline: "middle", fill: lanesTheme.headerTextColor, fontFamily: lanesTheme.headerFontFamily, fontSize: lanesTheme.headerFontSize, style: { userSelect: "none" }, children:
|
|
19892
|
+
return (0, import_jsx_runtime25.jsxs)("g", { children: [(0, import_jsx_runtime25.jsx)("line", { x1: startScreen, y1: pinned ? headerSize : y + headerSize, x2: startScreen, y2: pinned ? 0 : y, stroke: lanesTheme.dividerColor, strokeWidth: lanesTheme.dividerWidth }), (0, import_jsx_runtime25.jsx)("text", { x: cx, y: (pinned ? 0 : y) + headerSize / 2, textAnchor: "middle", dominantBaseline: "middle", fill: lanesTheme.headerTextColor, fontFamily: lanesTheme.headerFontFamily, fontSize: lanesTheme.headerFontSize, style: { userSelect: "none" }, children: truncateToWidth2(col.label, visibleW - pad * 2, lanesTheme.headerFontSize) })] }, `colh-${col.id}`);
|
|
19440
19893
|
}), pinned && (0, import_jsx_runtime25.jsx)("line", { x1: colsOffsetLeft, y1: headerSize, x2: width, y2: headerSize, stroke: lanesTheme.dividerColor, strokeWidth: lanesTheme.dividerWidth })] }), hasRows && (0, import_jsx_runtime25.jsxs)("g", { children: [pinned && (0, import_jsx_runtime25.jsx)("rect", { x: 0, y: rowsOffsetTop, width: headerSize, height: height - rowsOffsetTop, fill: lanesTheme.headerBackground }), rows.map((row) => {
|
|
19441
19894
|
const startScreen = canvasToScreen(0, row.start, viewport).y;
|
|
19442
19895
|
const endScreen = canvasToScreen(0, row.start + row.size, viewport).y;
|
|
@@ -19448,10 +19901,10 @@ var SystemCanvas = (() => {
|
|
|
19448
19901
|
const cy = visibleTop + visibleH / 2;
|
|
19449
19902
|
if (endScreen <= rowsOffsetTop || startScreen >= height)
|
|
19450
19903
|
return null;
|
|
19451
|
-
return (0, import_jsx_runtime25.jsxs)("g", { children: [(0, import_jsx_runtime25.jsx)("line", { x1: pinned ? 0 : x, y1: startScreen, x2: pinned ? headerSize : x + headerSize, y2: startScreen, stroke: lanesTheme.dividerColor, strokeWidth: lanesTheme.dividerWidth }), (0, import_jsx_runtime25.jsx)("text", { x: (pinned ? 0 : x) + headerSize / 2, y: cy, textAnchor: "middle", dominantBaseline: "middle", fill: lanesTheme.headerTextColor, fontFamily: lanesTheme.headerFontFamily, fontSize: lanesTheme.headerFontSize, transform: `rotate(-90 ${(pinned ? 0 : x) + headerSize / 2} ${cy})`, style: { userSelect: "none" }, children:
|
|
19904
|
+
return (0, import_jsx_runtime25.jsxs)("g", { children: [(0, import_jsx_runtime25.jsx)("line", { x1: pinned ? 0 : x, y1: startScreen, x2: pinned ? headerSize : x + headerSize, y2: startScreen, stroke: lanesTheme.dividerColor, strokeWidth: lanesTheme.dividerWidth }), (0, import_jsx_runtime25.jsx)("text", { x: (pinned ? 0 : x) + headerSize / 2, y: cy, textAnchor: "middle", dominantBaseline: "middle", fill: lanesTheme.headerTextColor, fontFamily: lanesTheme.headerFontFamily, fontSize: lanesTheme.headerFontSize, transform: `rotate(-90 ${(pinned ? 0 : x) + headerSize / 2} ${cy})`, style: { userSelect: "none" }, children: truncateToWidth2(row.label, visibleH - pad * 2, lanesTheme.headerFontSize) })] }, `rowh-${row.id}`);
|
|
19452
19905
|
}), pinned && (0, import_jsx_runtime25.jsx)("line", { x1: headerSize, y1: rowsOffsetTop, x2: headerSize, y2: height, stroke: lanesTheme.dividerColor, strokeWidth: lanesTheme.dividerWidth })] }), hasColumns && hasRows && pinned && (0, import_jsx_runtime25.jsx)("rect", { x: 0, y: 0, width: headerSize, height: headerSize, fill: lanesTheme.headerBackground })] });
|
|
19453
19906
|
}
|
|
19454
|
-
function
|
|
19907
|
+
function truncateToWidth2(label, availablePx, fontSize) {
|
|
19455
19908
|
if (availablePx <= 0)
|
|
19456
19909
|
return "";
|
|
19457
19910
|
const charPx = fontSize * 0.6;
|
|
@@ -19493,8 +19946,10 @@ var SystemCanvas = (() => {
|
|
|
19493
19946
|
raf = requestAnimationFrame(tick);
|
|
19494
19947
|
return () => cancelAnimationFrame(raf);
|
|
19495
19948
|
}, [getViewport]);
|
|
19496
|
-
const
|
|
19497
|
-
const
|
|
19949
|
+
const align = theme.toolbarAlign ?? "center";
|
|
19950
|
+
const anchorCanvasX = align === "left" ? node.x : align === "right" ? node.x + node.width : node.x + node.width / 2;
|
|
19951
|
+
const topAnchor = canvasToScreen(anchorCanvasX, node.y, viewport);
|
|
19952
|
+
const bottomAnchor = canvasToScreen(anchorCanvasX, node.y + node.height, viewport);
|
|
19498
19953
|
const toolbarRef = (0, import_react19.useRef)(null);
|
|
19499
19954
|
const [size, setSize] = (0, import_react19.useState)({ width: 0, height: 0 });
|
|
19500
19955
|
(0, import_react19.useEffect)(() => {
|
|
@@ -19503,17 +19958,17 @@ var SystemCanvas = (() => {
|
|
|
19503
19958
|
return;
|
|
19504
19959
|
const update = () => {
|
|
19505
19960
|
const r = el.getBoundingClientRect();
|
|
19506
|
-
setSize({ width: r.width, height: r.height });
|
|
19961
|
+
setSize((prev) => prev.width === r.width && prev.height === r.height ? prev : { width: r.width, height: r.height });
|
|
19507
19962
|
};
|
|
19508
19963
|
update();
|
|
19509
19964
|
const ro = new ResizeObserver(update);
|
|
19510
19965
|
ro.observe(el);
|
|
19511
19966
|
return () => ro.disconnect();
|
|
19512
|
-
});
|
|
19513
|
-
let left =
|
|
19514
|
-
let top =
|
|
19967
|
+
}, []);
|
|
19968
|
+
let left = align === "left" ? topAnchor.x : align === "right" ? topAnchor.x - size.width : topAnchor.x - size.width / 2;
|
|
19969
|
+
let top = topAnchor.y - size.height - NODE_GAP;
|
|
19515
19970
|
if (top < FLIP_MARGIN) {
|
|
19516
|
-
top =
|
|
19971
|
+
top = bottomAnchor.y + NODE_GAP;
|
|
19517
19972
|
}
|
|
19518
19973
|
left = Math.max(FLIP_MARGIN, Math.min(left, containerWidth - size.width - FLIP_MARGIN));
|
|
19519
19974
|
const patch = (update) => onPatch(update);
|
|
@@ -19552,7 +20007,7 @@ var SystemCanvas = (() => {
|
|
|
19552
20007
|
}
|
|
19553
20008
|
function DefaultToolbarContent({ node, theme, onPatch, onDelete }) {
|
|
19554
20009
|
const groups = (0, import_react19.useMemo)(() => getNodeActionsForNode(node, theme), [node, theme]);
|
|
19555
|
-
const showDelete =
|
|
20010
|
+
const showDelete = theme.showToolbarDelete === true;
|
|
19556
20011
|
return (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [groups.map((group, i) => (0, import_jsx_runtime26.jsxs)(import_react19.default.Fragment, { children: [i > 0 && (0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)(ActionGroupView, { group, node, theme, onPatch })] }, group.id)), showDelete && (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [(0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)(DeleteButton, { theme, onDelete })] })] });
|
|
19557
20012
|
}
|
|
19558
20013
|
function Divider2({ theme }) {
|
|
@@ -19707,16 +20162,134 @@ var SystemCanvas = (() => {
|
|
|
19707
20162
|
}, children: (0, import_jsx_runtime26.jsx)("svg", { width: DELETE_SIZE, height: DELETE_SIZE, viewBox: "0 0 16 16", children: (0, import_jsx_runtime26.jsx)("path", { d: "M 3 5 L 13 5 M 6 5 L 6 3 L 10 3 L 10 5 M 5 5 L 5.5 14 L 10.5 14 L 11 5 M 7 7 L 7 12 M 9 7 L 9 12", fill: "none", stroke: "currentColor", strokeWidth: 1.2, strokeLinecap: "round", strokeLinejoin: "round" }) }) });
|
|
19708
20163
|
}
|
|
19709
20164
|
|
|
20165
|
+
// ../react/dist/components/NodeContextMenuOverlay.js
|
|
20166
|
+
var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
|
|
20167
|
+
var import_react20 = __toESM(require_react(), 1);
|
|
20168
|
+
var ESTIMATED_MENU_WIDTH = 200;
|
|
20169
|
+
var MIN_MENU_WIDTH = 160;
|
|
20170
|
+
var VIEWPORT_MARGIN = 8;
|
|
20171
|
+
function NodeContextMenuOverlay({ state, config, theme, onClose }) {
|
|
20172
|
+
const rootRef = (0, import_react20.useRef)(null);
|
|
20173
|
+
const [hoveredId, setHoveredId] = (0, import_react20.useState)(null);
|
|
20174
|
+
(0, import_react20.useEffect)(() => {
|
|
20175
|
+
if (state)
|
|
20176
|
+
setHoveredId(null);
|
|
20177
|
+
}, [state]);
|
|
20178
|
+
(0, import_react20.useEffect)(() => {
|
|
20179
|
+
if (!state)
|
|
20180
|
+
return;
|
|
20181
|
+
function onDown(e) {
|
|
20182
|
+
const root2 = rootRef.current;
|
|
20183
|
+
if (!root2)
|
|
20184
|
+
return;
|
|
20185
|
+
if (root2.contains(e.target))
|
|
20186
|
+
return;
|
|
20187
|
+
onClose();
|
|
20188
|
+
}
|
|
20189
|
+
function onKey(e) {
|
|
20190
|
+
if (e.key === "Escape") {
|
|
20191
|
+
e.stopPropagation();
|
|
20192
|
+
onClose();
|
|
20193
|
+
}
|
|
20194
|
+
}
|
|
20195
|
+
function onScroll() {
|
|
20196
|
+
onClose();
|
|
20197
|
+
}
|
|
20198
|
+
window.addEventListener("mousedown", onDown);
|
|
20199
|
+
window.addEventListener("keydown", onKey);
|
|
20200
|
+
window.addEventListener("scroll", onScroll, true);
|
|
20201
|
+
window.addEventListener("blur", onClose);
|
|
20202
|
+
return () => {
|
|
20203
|
+
window.removeEventListener("mousedown", onDown);
|
|
20204
|
+
window.removeEventListener("keydown", onKey);
|
|
20205
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
20206
|
+
window.removeEventListener("blur", onClose);
|
|
20207
|
+
};
|
|
20208
|
+
}, [state, onClose]);
|
|
20209
|
+
if (!state)
|
|
20210
|
+
return null;
|
|
20211
|
+
const cm = theme.contextMenu;
|
|
20212
|
+
if (!cm)
|
|
20213
|
+
return null;
|
|
20214
|
+
const vw = typeof window !== "undefined" ? window.innerWidth : 0;
|
|
20215
|
+
const vh = typeof window !== "undefined" ? window.innerHeight : 0;
|
|
20216
|
+
const itemHeight = cm.itemPaddingY * 2 + cm.fontSize + 4;
|
|
20217
|
+
const estimatedHeight = state.items.length * itemHeight + cm.paddingY * 2;
|
|
20218
|
+
const left = vw ? Math.min(state.screenPosition.x, vw - ESTIMATED_MENU_WIDTH - VIEWPORT_MARGIN) : state.screenPosition.x;
|
|
20219
|
+
const top = vh ? Math.min(state.screenPosition.y, vh - estimatedHeight - VIEWPORT_MARGIN) : state.screenPosition.y;
|
|
20220
|
+
const matchCtx = { canvasRef: state.canvasRef };
|
|
20221
|
+
const anyIcon = state.items.some((item) => !!item.icon);
|
|
20222
|
+
return (0, import_jsx_runtime27.jsx)("div", {
|
|
20223
|
+
ref: rootRef,
|
|
20224
|
+
role: "menu",
|
|
20225
|
+
// Stop right-clicks inside the menu from bubbling into the document
|
|
20226
|
+
// listener and re-opening the canvas-level menu.
|
|
20227
|
+
onContextMenu: (e) => {
|
|
20228
|
+
e.preventDefault();
|
|
20229
|
+
e.stopPropagation();
|
|
20230
|
+
},
|
|
20231
|
+
style: {
|
|
20232
|
+
position: "fixed",
|
|
20233
|
+
left,
|
|
20234
|
+
top,
|
|
20235
|
+
zIndex: 1e3,
|
|
20236
|
+
minWidth: MIN_MENU_WIDTH,
|
|
20237
|
+
padding: `${cm.paddingY}px ${cm.paddingX}px`,
|
|
20238
|
+
background: cm.background,
|
|
20239
|
+
color: cm.itemColor,
|
|
20240
|
+
border: `1px solid ${cm.borderColor}`,
|
|
20241
|
+
borderRadius: cm.borderRadius,
|
|
20242
|
+
boxShadow: cm.shadow,
|
|
20243
|
+
fontFamily: cm.fontFamily,
|
|
20244
|
+
fontSize: cm.fontSize,
|
|
20245
|
+
backdropFilter: "blur(10px)",
|
|
20246
|
+
userSelect: "none",
|
|
20247
|
+
// `pointer-events: auto` so the menu still receives clicks even
|
|
20248
|
+
// when a parent canvas overlay disables them.
|
|
20249
|
+
pointerEvents: "auto"
|
|
20250
|
+
},
|
|
20251
|
+
children: state.items.map((item) => {
|
|
20252
|
+
const isDisabled = item.disabled?.(state.node, matchCtx) ?? false;
|
|
20253
|
+
const isHovered = !isDisabled && hoveredId === item.id;
|
|
20254
|
+
const color2 = item.destructive ? cm.destructiveItemColor : cm.itemColor;
|
|
20255
|
+
return (0, import_jsx_runtime27.jsxs)("div", { role: "menuitem", "aria-disabled": isDisabled, onMouseEnter: () => !isDisabled && setHoveredId(item.id), onMouseLeave: () => setHoveredId((id2) => id2 === item.id ? null : id2), onClick: () => {
|
|
20256
|
+
if (isDisabled)
|
|
20257
|
+
return;
|
|
20258
|
+
config.onSelect(item.id, state.node, {
|
|
20259
|
+
canvasRef: state.canvasRef,
|
|
20260
|
+
screenPosition: state.screenPosition
|
|
20261
|
+
});
|
|
20262
|
+
onClose();
|
|
20263
|
+
}, style: {
|
|
20264
|
+
display: "flex",
|
|
20265
|
+
alignItems: "center",
|
|
20266
|
+
gap: 10,
|
|
20267
|
+
padding: `${cm.itemPaddingY}px ${cm.itemPaddingX}px`,
|
|
20268
|
+
borderRadius: Math.max(0, cm.borderRadius - 4),
|
|
20269
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
20270
|
+
opacity: isDisabled ? 0.45 : 1,
|
|
20271
|
+
background: isHovered ? cm.itemHoverBackground : "transparent",
|
|
20272
|
+
color: color2
|
|
20273
|
+
}, children: [item.icon ? (0, import_jsx_runtime27.jsx)("svg", { width: 14, height: 14, viewBox: "0 0 16 16", style: { flexShrink: 0, overflow: "visible" }, children: (0, import_jsx_runtime27.jsx)(NodeIcon, { icon: item.icon, x: 0, y: 0, size: 14, color: color2, opacity: 1, customIcons: theme.icons }) }) : anyIcon ? (
|
|
20274
|
+
// Only reserve a spacer when other items in the same menu
|
|
20275
|
+
// do have icons — keeps labels vertically aligned in a
|
|
20276
|
+
// mixed menu without padding lone-item menus.
|
|
20277
|
+
(0, import_jsx_runtime27.jsx)("span", { style: { width: 14, flexShrink: 0 }, "aria-hidden": true })
|
|
20278
|
+
) : null, (0, import_jsx_runtime27.jsx)("span", { children: item.label })] }, item.id);
|
|
20279
|
+
})
|
|
20280
|
+
});
|
|
20281
|
+
}
|
|
20282
|
+
|
|
19710
20283
|
// ../react/dist/components/SystemCanvas.js
|
|
19711
20284
|
var CASCADE_WINDOW_MS = 1500;
|
|
19712
20285
|
var CASCADE_OFFSET = 20;
|
|
19713
|
-
var SystemCanvas = (0,
|
|
19714
|
-
const zoomNavConfig = (0,
|
|
20286
|
+
var SystemCanvas = (0, import_react21.forwardRef)(function SystemCanvas2({ canvas, onResolveCanvas, canvases, rootLabel = "Home", onNavigate, onBreadcrumbClick, onBreadcrumbsChange, onNodeClick, onNodeDoubleClick, onEdgeClick, onEdgeDoubleClick, onContextMenu, onSelectionChange, nodeContextMenu, editable = false, onNodeAdd, onNodeUpdate, onNodesUpdate, onNodeDelete, onEdgeUpdate, onEdgeDelete, onEdgeAdd, canDropNodeOn, onNodeDrop, renderAddNodeButton, showNodeToolbar = true, renderNodeToolbar, theme: themeProp, themes: customThemes, edgeStyle = "bezier", defaultViewport, minZoom: minZoomProp, maxZoom, onViewportChange, autoFit = "canvas-change", laneHeaders = "pinned", snapToLanes = false, zoomNavigation = false, className, style }, forwardedRef) {
|
|
20287
|
+
const zoomNavConfig = (0, import_react21.useMemo)(() => {
|
|
19715
20288
|
const defaults = {
|
|
19716
20289
|
enterThreshold: 0.66,
|
|
19717
20290
|
exitThreshold: 0.33,
|
|
19718
20291
|
prefetchThreshold: 0.4,
|
|
19719
|
-
landingScale: 1.
|
|
20292
|
+
landingScale: 1.3,
|
|
19720
20293
|
landingPadding: 0.08,
|
|
19721
20294
|
fadeDuration: 216
|
|
19722
20295
|
};
|
|
@@ -19736,16 +20309,16 @@ var SystemCanvas = (() => {
|
|
|
19736
20309
|
}, [zoomNavigation]);
|
|
19737
20310
|
const effectiveMaxZoom = maxZoom ?? (zoomNavConfig.enabled ? 16 : 4);
|
|
19738
20311
|
const effectiveMinZoom = minZoomProp ?? (zoomNavConfig.enabled ? 0.01 : 0.1);
|
|
19739
|
-
(0,
|
|
20312
|
+
(0, import_react21.useEffect)(() => {
|
|
19740
20313
|
const env = globalThis.process?.env?.NODE_ENV;
|
|
19741
20314
|
if (editable && !canvases && env !== "production") {
|
|
19742
20315
|
console.warn("[system-canvas] `editable` is enabled but `canvases` prop is missing. Edits to sub-canvases will not be reflected without a synchronous ref \u2192 CanvasData map.");
|
|
19743
20316
|
}
|
|
19744
20317
|
}, [editable, canvases]);
|
|
19745
|
-
const [parentFrames, setParentFrames] = (0,
|
|
19746
|
-
const [pendingHandoff, setPendingHandoff] = (0,
|
|
19747
|
-
const suppressNextHandoffClearRef = (0,
|
|
19748
|
-
const handleBreadcrumbClick = (0,
|
|
20318
|
+
const [parentFrames, setParentFrames] = (0, import_react21.useState)([]);
|
|
20319
|
+
const [pendingHandoff, setPendingHandoff] = (0, import_react21.useState)(null);
|
|
20320
|
+
const suppressNextHandoffClearRef = (0, import_react21.useRef)(false);
|
|
20321
|
+
const handleBreadcrumbClick = (0, import_react21.useCallback)((index) => {
|
|
19749
20322
|
setParentFrames((prev) => prev.slice(0, index));
|
|
19750
20323
|
if (suppressNextHandoffClearRef.current) {
|
|
19751
20324
|
suppressNextHandoffClearRef.current = false;
|
|
@@ -19762,7 +20335,10 @@ var SystemCanvas = (() => {
|
|
|
19762
20335
|
onNavigate,
|
|
19763
20336
|
onBreadcrumbClick: handleBreadcrumbClick
|
|
19764
20337
|
});
|
|
19765
|
-
|
|
20338
|
+
(0, import_react21.useEffect)(() => {
|
|
20339
|
+
onBreadcrumbsChange?.(breadcrumbs);
|
|
20340
|
+
}, [breadcrumbs, onBreadcrumbsChange]);
|
|
20341
|
+
const theme = (0, import_react21.useMemo)(() => {
|
|
19766
20342
|
const registry = { ...themes, ...customThemes };
|
|
19767
20343
|
const resolveByName = (name) => name && registry[name] ? registry[name] : null;
|
|
19768
20344
|
if (themeProp) {
|
|
@@ -19773,22 +20349,22 @@ var SystemCanvas = (() => {
|
|
|
19773
20349
|
}
|
|
19774
20350
|
return resolveByName(currentCanvas.theme?.base) ?? resolveByName(canvas.theme?.base) ?? darkTheme;
|
|
19775
20351
|
}, [themeProp, customThemes, currentCanvas.theme?.base, canvas.theme?.base]);
|
|
19776
|
-
const { nodes, edges, nodeMap } = (0,
|
|
20352
|
+
const { nodes, edges, nodeMap } = (0, import_react21.useMemo)(() => {
|
|
19777
20353
|
const resolved = resolveCanvas(currentCanvas, theme);
|
|
19778
20354
|
const map = buildNodeMap(resolved.nodes);
|
|
19779
20355
|
return { nodes: resolved.nodes, edges: resolved.edges, nodeMap: map };
|
|
19780
20356
|
}, [currentCanvas, theme]);
|
|
19781
|
-
const nodesRef = (0,
|
|
20357
|
+
const nodesRef = (0, import_react21.useRef)(nodes);
|
|
19782
20358
|
nodesRef.current = nodes;
|
|
19783
|
-
const viewportStateRef = (0,
|
|
19784
|
-
const viewportHandleRef = (0,
|
|
19785
|
-
const navigateToRefRef = (0,
|
|
20359
|
+
const viewportStateRef = (0, import_react21.useRef)(defaultViewport ?? { x: 0, y: 0, zoom: 1 });
|
|
20360
|
+
const viewportHandleRef = (0, import_react21.useRef)(null);
|
|
20361
|
+
const navigateToRefRef = (0, import_react21.useRef)(navigateToRef);
|
|
19786
20362
|
navigateToRefRef.current = navigateToRef;
|
|
19787
|
-
const navigateToBreadcrumbRef = (0,
|
|
20363
|
+
const navigateToBreadcrumbRef = (0, import_react21.useRef)(navigateToBreadcrumb);
|
|
19788
20364
|
navigateToBreadcrumbRef.current = navigateToBreadcrumb;
|
|
19789
|
-
const breadcrumbsRef = (0,
|
|
20365
|
+
const breadcrumbsRef = (0, import_react21.useRef)(breadcrumbs);
|
|
19790
20366
|
breadcrumbsRef.current = breadcrumbs;
|
|
19791
|
-
(0,
|
|
20367
|
+
(0, import_react21.useImperativeHandle)(forwardedRef, () => ({
|
|
19792
20368
|
zoomIntoNode: (nodeId, options) => {
|
|
19793
20369
|
return new Promise((resolve) => {
|
|
19794
20370
|
const node = nodesRef.current.find((n) => n.id === nodeId);
|
|
@@ -19820,19 +20396,51 @@ var SystemCanvas = (() => {
|
|
|
19820
20396
|
navigateToBreadcrumbRef.current(0);
|
|
19821
20397
|
}
|
|
19822
20398
|
}), [forwardedRef]);
|
|
19823
|
-
const [selectedId, setSelectedId] = (0,
|
|
19824
|
-
const [editingId, setEditingId] = (0,
|
|
19825
|
-
const [selectedEdgeId, setSelectedEdgeId] = (0,
|
|
19826
|
-
const [editingEdgeId, setEditingEdgeId] = (0,
|
|
19827
|
-
(0,
|
|
20399
|
+
const [selectedId, setSelectedId] = (0, import_react21.useState)(null);
|
|
20400
|
+
const [editingId, setEditingId] = (0, import_react21.useState)(null);
|
|
20401
|
+
const [selectedEdgeId, setSelectedEdgeId] = (0, import_react21.useState)(null);
|
|
20402
|
+
const [editingEdgeId, setEditingEdgeId] = (0, import_react21.useState)(null);
|
|
20403
|
+
(0, import_react21.useEffect)(() => {
|
|
19828
20404
|
setSelectedId(null);
|
|
19829
20405
|
setEditingId(null);
|
|
19830
20406
|
setSelectedEdgeId(null);
|
|
19831
20407
|
setEditingEdgeId(null);
|
|
19832
20408
|
}, [currentCanvasRef]);
|
|
19833
|
-
const
|
|
19834
|
-
|
|
19835
|
-
|
|
20409
|
+
const onSelectionChangeRef = (0, import_react21.useRef)(onSelectionChange);
|
|
20410
|
+
(0, import_react21.useEffect)(() => {
|
|
20411
|
+
onSelectionChangeRef.current = onSelectionChange;
|
|
20412
|
+
}, [onSelectionChange]);
|
|
20413
|
+
const lastEmittedSelectionRef = (0, import_react21.useRef)({ kind: null, id: null, canvasRef: void 0 });
|
|
20414
|
+
(0, import_react21.useEffect)(() => {
|
|
20415
|
+
const cb = onSelectionChangeRef.current;
|
|
20416
|
+
let next = null;
|
|
20417
|
+
if (selectedId) {
|
|
20418
|
+
const node = nodeMap.get(selectedId);
|
|
20419
|
+
if (node)
|
|
20420
|
+
next = { kind: "node", node, canvasRef: currentCanvasRef };
|
|
20421
|
+
}
|
|
20422
|
+
if (!next && selectedEdgeId) {
|
|
20423
|
+
const edge = edges.find((e) => e.id === selectedEdgeId);
|
|
20424
|
+
if (edge)
|
|
20425
|
+
next = { kind: "edge", edge, canvasRef: currentCanvasRef };
|
|
20426
|
+
}
|
|
20427
|
+
const last = lastEmittedSelectionRef.current;
|
|
20428
|
+
const nextKind = next?.kind ?? null;
|
|
20429
|
+
const nextId = next ? next.kind === "node" ? next.node.id : next.edge.id : null;
|
|
20430
|
+
const nextRef = next?.canvasRef;
|
|
20431
|
+
if (last.kind === nextKind && last.id === nextId && last.canvasRef === nextRef) {
|
|
20432
|
+
return;
|
|
20433
|
+
}
|
|
20434
|
+
lastEmittedSelectionRef.current = {
|
|
20435
|
+
kind: nextKind,
|
|
20436
|
+
id: nextId,
|
|
20437
|
+
canvasRef: nextRef
|
|
20438
|
+
};
|
|
20439
|
+
cb?.(next);
|
|
20440
|
+
}, [selectedId, selectedEdgeId, currentCanvasRef, nodeMap, edges]);
|
|
20441
|
+
const containerRef = (0, import_react21.useRef)(null);
|
|
20442
|
+
const [containerSize, setContainerSize] = (0, import_react21.useState)({ width: 0, height: 0 });
|
|
20443
|
+
(0, import_react21.useEffect)(() => {
|
|
19836
20444
|
const el = containerRef.current;
|
|
19837
20445
|
if (!el)
|
|
19838
20446
|
return;
|
|
@@ -19847,42 +20455,67 @@ var SystemCanvas = (() => {
|
|
|
19847
20455
|
}, []);
|
|
19848
20456
|
const hasLanes = currentCanvas.columns && currentCanvas.columns.length > 0 || currentCanvas.rows && currentCanvas.rows.length > 0;
|
|
19849
20457
|
const showLaneHeaders = hasLanes && laneHeaders !== "none";
|
|
19850
|
-
const getViewportState = (0,
|
|
19851
|
-
const
|
|
20458
|
+
const getViewportState = (0, import_react21.useCallback)(() => viewportStateRef.current ?? { x: 0, y: 0, zoom: 1 }, []);
|
|
20459
|
+
const applyLaneSnap = (0, import_react21.useCallback)((id2, patch) => {
|
|
20460
|
+
if (!snapToLanes)
|
|
20461
|
+
return patch;
|
|
20462
|
+
const cols = currentCanvas.columns;
|
|
20463
|
+
const rows = currentCanvas.rows;
|
|
20464
|
+
const node = nodesRef.current.find((n) => n.id === id2);
|
|
19852
20465
|
let final = patch;
|
|
19853
|
-
|
|
19854
|
-
|
|
19855
|
-
|
|
19856
|
-
const
|
|
19857
|
-
|
|
19858
|
-
|
|
19859
|
-
|
|
19860
|
-
|
|
19861
|
-
|
|
19862
|
-
|
|
19863
|
-
|
|
19864
|
-
|
|
19865
|
-
|
|
19866
|
-
|
|
19867
|
-
|
|
19868
|
-
|
|
19869
|
-
|
|
19870
|
-
|
|
19871
|
-
|
|
19872
|
-
|
|
20466
|
+
const nx = patch.x;
|
|
20467
|
+
const ny = patch.y;
|
|
20468
|
+
if (cols && cols.length > 0 && nx != null) {
|
|
20469
|
+
const snapped = snapToLane(nx, cols, {
|
|
20470
|
+
edge: "center",
|
|
20471
|
+
size: node?.width ?? 0
|
|
20472
|
+
});
|
|
20473
|
+
final = { ...final, x: Math.round(snapped) };
|
|
20474
|
+
}
|
|
20475
|
+
if (rows && rows.length > 0 && ny != null) {
|
|
20476
|
+
const snapped = snapToLane(ny, rows, {
|
|
20477
|
+
edge: "center",
|
|
20478
|
+
size: node?.height ?? 0
|
|
20479
|
+
});
|
|
20480
|
+
final = { ...final, y: Math.round(snapped) };
|
|
20481
|
+
}
|
|
20482
|
+
return final;
|
|
20483
|
+
}, [snapToLanes, currentCanvas.columns, currentCanvas.rows]);
|
|
20484
|
+
const commitResize = (0, import_react21.useCallback)((id2, patch) => {
|
|
20485
|
+
onNodeUpdate?.(id2, applyLaneSnap(id2, patch), currentCanvasRef);
|
|
20486
|
+
}, [onNodeUpdate, currentCanvasRef, applyLaneSnap]);
|
|
20487
|
+
const commitDragBatch = (0, import_react21.useCallback)((updates) => {
|
|
20488
|
+
const final = updates.map((u) => ({
|
|
20489
|
+
id: u.id,
|
|
20490
|
+
patch: applyLaneSnap(u.id, u.patch)
|
|
20491
|
+
}));
|
|
20492
|
+
if (onNodesUpdate) {
|
|
20493
|
+
onNodesUpdate(final, currentCanvasRef);
|
|
20494
|
+
return;
|
|
19873
20495
|
}
|
|
19874
|
-
onNodeUpdate
|
|
19875
|
-
|
|
19876
|
-
|
|
20496
|
+
if (!onNodeUpdate)
|
|
20497
|
+
return;
|
|
20498
|
+
for (const { id: id2, patch } of final) {
|
|
20499
|
+
onNodeUpdate(id2, patch, currentCanvasRef);
|
|
20500
|
+
}
|
|
20501
|
+
}, [onNodeUpdate, onNodesUpdate, currentCanvasRef, applyLaneSnap]);
|
|
20502
|
+
const svgProxyRef = (0, import_react21.useRef)(null);
|
|
20503
|
+
const handleNodeDrop = (0, import_react21.useCallback)((sources, target) => {
|
|
20504
|
+
onNodeDrop?.(sources, target, { canvasRef: currentCanvasRef });
|
|
20505
|
+
}, [onNodeDrop, currentCanvasRef]);
|
|
20506
|
+
const { dragOverrides, dropTargetId, onPointerDown: onNodePointerDown } = useNodeDrag({
|
|
19877
20507
|
viewport: viewportStateRef,
|
|
19878
20508
|
nodesRef,
|
|
19879
|
-
onCommit:
|
|
20509
|
+
onCommit: commitDragBatch,
|
|
20510
|
+
svgRef: svgProxyRef,
|
|
20511
|
+
canDropNodeOn,
|
|
20512
|
+
onNodeDrop: handleNodeDrop
|
|
19880
20513
|
});
|
|
19881
20514
|
const { resizeOverrides, onHandlePointerDown: onResizeHandlePointerDown } = useNodeResize({
|
|
19882
20515
|
viewport: viewportStateRef,
|
|
19883
|
-
onCommit:
|
|
20516
|
+
onCommit: commitResize
|
|
19884
20517
|
});
|
|
19885
|
-
const selectedResolvedNode = (0,
|
|
20518
|
+
const selectedResolvedNode = (0, import_react21.useMemo)(() => {
|
|
19886
20519
|
if (!selectedId)
|
|
19887
20520
|
return null;
|
|
19888
20521
|
const base = nodeMap.get(selectedId);
|
|
@@ -19898,9 +20531,8 @@ var SystemCanvas = (() => {
|
|
|
19898
20531
|
}
|
|
19899
20532
|
return base;
|
|
19900
20533
|
}, [selectedId, nodeMap, dragOverrides, resizeOverrides]);
|
|
19901
|
-
const svgProxyRef = (0, import_react20.useRef)(null);
|
|
19902
20534
|
svgProxyRef.current = viewportHandleRef.current?.getSvgElement() ?? null;
|
|
19903
|
-
const handleEdgeCreated = (0,
|
|
20535
|
+
const handleEdgeCreated = (0, import_react21.useCallback)((edge) => {
|
|
19904
20536
|
onEdgeAdd?.(edge, currentCanvasRef);
|
|
19905
20537
|
}, [onEdgeAdd, currentCanvasRef]);
|
|
19906
20538
|
const { pending: pendingEdge, onHandlePointerDown: onConnectionHandlePointerDown } = useEdgeCreate({
|
|
@@ -19909,7 +20541,7 @@ var SystemCanvas = (() => {
|
|
|
19909
20541
|
nodesRef,
|
|
19910
20542
|
onCreate: handleEdgeCreated
|
|
19911
20543
|
});
|
|
19912
|
-
const handleNavigableNodeClick = (0,
|
|
20544
|
+
const handleNavigableNodeClick = (0, import_react21.useCallback)((node) => {
|
|
19913
20545
|
const frame2 = {
|
|
19914
20546
|
parentCanvasRef: currentCanvasRef,
|
|
19915
20547
|
parentNodeRect: {
|
|
@@ -19936,7 +20568,7 @@ var SystemCanvas = (() => {
|
|
|
19936
20568
|
navigateToRef(node);
|
|
19937
20569
|
}
|
|
19938
20570
|
}, [navigateToRef, currentCanvasRef, zoomNavConfig.enabled]);
|
|
19939
|
-
const handleZoomEnter = (0,
|
|
20571
|
+
const handleZoomEnter = (0, import_react21.useCallback)((node, targetTransform) => {
|
|
19940
20572
|
const frame2 = {
|
|
19941
20573
|
parentCanvasRef: currentCanvasRef,
|
|
19942
20574
|
parentNodeRect: {
|
|
@@ -19950,7 +20582,7 @@ var SystemCanvas = (() => {
|
|
|
19950
20582
|
setPendingHandoff(targetTransform);
|
|
19951
20583
|
navigateToRef(node);
|
|
19952
20584
|
}, [currentCanvasRef, navigateToRef]);
|
|
19953
|
-
const handleZoomExit = (0,
|
|
20585
|
+
const handleZoomExit = (0, import_react21.useCallback)((targetTransform) => {
|
|
19954
20586
|
setPendingHandoff(targetTransform);
|
|
19955
20587
|
suppressNextHandoffClearRef.current = true;
|
|
19956
20588
|
navigateToBreadcrumb(breadcrumbs.length - 2);
|
|
@@ -19973,30 +20605,58 @@ var SystemCanvas = (() => {
|
|
|
19973
20605
|
const rect = svg.getBoundingClientRect();
|
|
19974
20606
|
return { width: rect.width, height: rect.height };
|
|
19975
20607
|
},
|
|
20608
|
+
getCursorScreenPos: () => viewportHandleRef.current?.getCursorScreenPos() ?? null,
|
|
19976
20609
|
onEnter: handleZoomEnter,
|
|
19977
20610
|
onExit: handleZoomExit
|
|
19978
20611
|
});
|
|
19979
|
-
const handleViewportChange = (0,
|
|
20612
|
+
const handleViewportChange = (0, import_react21.useCallback)((vp) => {
|
|
19980
20613
|
viewportStateRef.current = vp;
|
|
19981
20614
|
handleZoomNavViewportChange(vp);
|
|
19982
20615
|
onViewportChange?.(vp);
|
|
19983
20616
|
}, [handleZoomNavViewportChange, onViewportChange]);
|
|
19984
|
-
const handleHandoffApplied = (0,
|
|
20617
|
+
const handleHandoffApplied = (0, import_react21.useCallback)(() => {
|
|
19985
20618
|
setPendingHandoff(null);
|
|
19986
20619
|
clearZoomNavCommitting();
|
|
19987
20620
|
}, [clearZoomNavCommitting]);
|
|
19988
|
-
const handleBeginEdit = (0,
|
|
20621
|
+
const handleBeginEdit = (0, import_react21.useCallback)((node) => {
|
|
19989
20622
|
setEditingId(node.id);
|
|
19990
20623
|
}, []);
|
|
19991
|
-
const handleBeginEditEdge = (0,
|
|
20624
|
+
const handleBeginEditEdge = (0, import_react21.useCallback)((edge) => {
|
|
19992
20625
|
setEditingEdgeId(edge.id);
|
|
19993
20626
|
}, []);
|
|
20627
|
+
const [contextMenuState, setContextMenuState] = (0, import_react21.useState)(null);
|
|
20628
|
+
(0, import_react21.useEffect)(() => {
|
|
20629
|
+
setContextMenuState(null);
|
|
20630
|
+
}, [currentCanvasRef]);
|
|
20631
|
+
const handleContextMenu = (0, import_react21.useCallback)((event) => {
|
|
20632
|
+
onContextMenu?.(event);
|
|
20633
|
+
if (!nodeContextMenu)
|
|
20634
|
+
return;
|
|
20635
|
+
if (event.type !== "node")
|
|
20636
|
+
return;
|
|
20637
|
+
const node = event.target;
|
|
20638
|
+
if (!node)
|
|
20639
|
+
return;
|
|
20640
|
+
const matched = filterContextMenuItems(nodeContextMenu.items, node, {
|
|
20641
|
+
canvasRef: currentCanvasRef ?? null
|
|
20642
|
+
});
|
|
20643
|
+
if (matched.length === 0) {
|
|
20644
|
+
setContextMenuState(null);
|
|
20645
|
+
return;
|
|
20646
|
+
}
|
|
20647
|
+
setContextMenuState({
|
|
20648
|
+
items: matched,
|
|
20649
|
+
node,
|
|
20650
|
+
screenPosition: event.screenPosition,
|
|
20651
|
+
canvasRef: currentCanvasRef ?? null
|
|
20652
|
+
});
|
|
20653
|
+
}, [onContextMenu, nodeContextMenu, currentCanvasRef]);
|
|
19994
20654
|
const { handleNodeClick, handleNodeDoubleClick, handleNodeNavigate, handleEdgeClick, handleEdgeDoubleClick, handleCanvasClick, handleCanvasContextMenu, handleNodeContextMenu, handleEdgeContextMenu } = useCanvasInteraction({
|
|
19995
20655
|
onNodeClick,
|
|
19996
20656
|
onNodeDoubleClick,
|
|
19997
20657
|
onEdgeClick,
|
|
19998
20658
|
onEdgeDoubleClick,
|
|
19999
|
-
onContextMenu,
|
|
20659
|
+
onContextMenu: handleContextMenu,
|
|
20000
20660
|
onNavigableNodeClick: handleNavigableNodeClick,
|
|
20001
20661
|
viewport: viewportStateRef,
|
|
20002
20662
|
editable,
|
|
@@ -20005,27 +20665,27 @@ var SystemCanvas = (() => {
|
|
|
20005
20665
|
onSelectEdge: setSelectedEdgeId,
|
|
20006
20666
|
onBeginEditEdge: handleBeginEditEdge
|
|
20007
20667
|
});
|
|
20008
|
-
const handleEditorCommit = (0,
|
|
20668
|
+
const handleEditorCommit = (0, import_react21.useCallback)((patch) => {
|
|
20009
20669
|
if (editingId) {
|
|
20010
20670
|
onNodeUpdate?.(editingId, patch, currentCanvasRef);
|
|
20011
20671
|
}
|
|
20012
20672
|
setEditingId(null);
|
|
20013
20673
|
}, [editingId, onNodeUpdate, currentCanvasRef]);
|
|
20014
|
-
const handleEditorCancel = (0,
|
|
20674
|
+
const handleEditorCancel = (0, import_react21.useCallback)(() => {
|
|
20015
20675
|
setEditingId(null);
|
|
20016
20676
|
}, []);
|
|
20017
|
-
const handleEdgeEditorCommit = (0,
|
|
20677
|
+
const handleEdgeEditorCommit = (0, import_react21.useCallback)((patch) => {
|
|
20018
20678
|
if (editingEdgeId) {
|
|
20019
20679
|
onEdgeUpdate?.(editingEdgeId, patch, currentCanvasRef);
|
|
20020
20680
|
}
|
|
20021
20681
|
setEditingEdgeId(null);
|
|
20022
20682
|
}, [editingEdgeId, onEdgeUpdate, currentCanvasRef]);
|
|
20023
|
-
const handleEdgeEditorCancel = (0,
|
|
20683
|
+
const handleEdgeEditorCancel = (0, import_react21.useCallback)(() => {
|
|
20024
20684
|
setEditingEdgeId(null);
|
|
20025
20685
|
}, []);
|
|
20026
|
-
const lastAddRef = (0,
|
|
20027
|
-
const menuOptions = (0,
|
|
20028
|
-
const addNode2 = (0,
|
|
20686
|
+
const lastAddRef = (0, import_react21.useRef)(null);
|
|
20687
|
+
const menuOptions = (0, import_react21.useMemo)(() => getNodeMenuOptions(currentCanvas, theme), [currentCanvas, theme]);
|
|
20688
|
+
const addNode2 = (0, import_react21.useCallback)((option, position) => {
|
|
20029
20689
|
let x, y;
|
|
20030
20690
|
if (position) {
|
|
20031
20691
|
x = position.x;
|
|
@@ -20057,7 +20717,7 @@ var SystemCanvas = (() => {
|
|
|
20057
20717
|
const node = createNodeFromOption(option, Math.round(x), Math.round(y), void 0, theme);
|
|
20058
20718
|
onNodeAdd?.(node, currentCanvasRef);
|
|
20059
20719
|
}, [onNodeAdd, currentCanvasRef, theme]);
|
|
20060
|
-
const handleKeyDown = (0,
|
|
20720
|
+
const handleKeyDown = (0, import_react21.useCallback)((e) => {
|
|
20061
20721
|
if (!editable)
|
|
20062
20722
|
return;
|
|
20063
20723
|
if (e.key === "Escape") {
|
|
@@ -20091,14 +20751,14 @@ var SystemCanvas = (() => {
|
|
|
20091
20751
|
currentCanvasRef
|
|
20092
20752
|
]);
|
|
20093
20753
|
const renderProps = { options: menuOptions, addNode: addNode2, theme };
|
|
20094
|
-
return (0,
|
|
20754
|
+
return (0, import_jsx_runtime28.jsxs)("div", { ref: containerRef, className: `system-canvas ${className ?? ""}`, tabIndex: editable ? 0 : -1, onKeyDown: handleKeyDown, style: {
|
|
20095
20755
|
position: "relative",
|
|
20096
20756
|
width: "100%",
|
|
20097
20757
|
height: "100%",
|
|
20098
20758
|
overflow: "hidden",
|
|
20099
20759
|
outline: "none",
|
|
20100
20760
|
...style
|
|
20101
|
-
}, children: [(0,
|
|
20761
|
+
}, children: [(0, import_jsx_runtime28.jsx)(Breadcrumbs, { breadcrumbs, theme: theme.breadcrumbs, onNavigate: navigateToBreadcrumb }), isLoading && (0, import_jsx_runtime28.jsx)("div", { className: "system-canvas-loading", style: {
|
|
20102
20762
|
position: "absolute",
|
|
20103
20763
|
top: 12,
|
|
20104
20764
|
right: 12,
|
|
@@ -20110,14 +20770,20 @@ var SystemCanvas = (() => {
|
|
|
20110
20770
|
fontFamily: theme.node.fontFamily,
|
|
20111
20771
|
fontSize: 12,
|
|
20112
20772
|
backdropFilter: "blur(8px)"
|
|
20113
|
-
}, children: "Loading..." }), (0,
|
|
20773
|
+
}, children: "Loading..." }), (0, import_jsx_runtime28.jsx)(Viewport, { ref: viewportHandleRef, nodes, edges, nodeMap, theme, edgeStyle, columns: currentCanvas.columns, rows: currentCanvas.rows, canvases, minZoom: effectiveMinZoom, maxZoom: effectiveMaxZoom, defaultViewport, autoFit, canvasRef: currentCanvasRef, handoffTransform: pendingHandoff, onHandoffApplied: handleHandoffApplied, handoffFadeMs: zoomNavConfig.fadeDuration, onViewportChange: handleViewportChange, onNodeClick: handleNodeClick, onNodeDoubleClick: handleNodeDoubleClick, onNodeNavigate: handleNodeNavigate, onEdgeClick: handleEdgeClick, onEdgeDoubleClick: handleEdgeDoubleClick, onCanvasClick: editable ? handleCanvasClick : void 0, onCanvasContextMenu: handleCanvasContextMenu, onNodeContextMenu: handleNodeContextMenu, onEdgeContextMenu: handleEdgeContextMenu, onNodePointerDown: editable ? onNodePointerDown : void 0, selectedId: editable ? selectedId : null, editingId: editable ? editingId : null, selectedEdgeId: editable ? selectedEdgeId : null, editingEdgeId: editable ? editingEdgeId : null, dragOverrides, dropTargetId, resizeOverrides, onResizeHandlePointerDown: editable ? onResizeHandlePointerDown : void 0, onEditorCommit: handleEditorCommit, onEditorCancel: handleEditorCancel, onEdgeEditorCommit: handleEdgeEditorCommit, onEdgeEditorCancel: handleEdgeEditorCancel, pendingEdge: editable ? pendingEdge : null, onConnectionHandlePointerDown: editable ? onConnectionHandlePointerDown : void 0, edgeCreateEnabled: editable }), showLaneHeaders && (0, import_jsx_runtime28.jsx)(LaneHeaders, { columns: currentCanvas.columns, rows: currentCanvas.rows, theme, getViewport: getViewportState, width: containerSize.width, height: containerSize.height, pinned: laneHeaders === "pinned" }), editable && showNodeToolbar && selectedResolvedNode && !editingId && (0, import_jsx_runtime28.jsx)(NodeToolbar, { node: selectedResolvedNode, theme, onPatch: (update) => {
|
|
20114
20774
|
onNodeUpdate?.(selectedResolvedNode.id, update, currentCanvasRef);
|
|
20115
20775
|
}, onDelete: () => {
|
|
20116
20776
|
onNodeDelete?.(selectedResolvedNode.id, currentCanvasRef);
|
|
20117
20777
|
setSelectedId(null);
|
|
20118
|
-
}, getViewport: getViewportState, containerWidth: containerSize.width, containerHeight: containerSize.height, render: renderNodeToolbar }), editable && (renderAddNodeButton ? renderAddNodeButton(renderProps) : (0,
|
|
20778
|
+
}, getViewport: getViewportState, containerWidth: containerSize.width, containerHeight: containerSize.height, render: renderNodeToolbar }), editable && (renderAddNodeButton ? renderAddNodeButton(renderProps) : (0, import_jsx_runtime28.jsx)(AddNodeButton, { ...renderProps })), nodeContextMenu && (0, import_jsx_runtime28.jsx)(NodeContextMenuOverlay, { state: contextMenuState, config: nodeContextMenu, theme, onClose: () => setContextMenuState(null) })] });
|
|
20119
20779
|
});
|
|
20120
20780
|
|
|
20781
|
+
// ../react/dist/hooks/useMultiSelect.js
|
|
20782
|
+
var import_react22 = __toESM(require_react(), 1);
|
|
20783
|
+
|
|
20784
|
+
// ../react/dist/hooks/useMultiSelectClipboard.js
|
|
20785
|
+
var import_react23 = __toESM(require_react(), 1);
|
|
20786
|
+
|
|
20121
20787
|
// src/index.tsx
|
|
20122
20788
|
function resolveThemeOption(theme) {
|
|
20123
20789
|
if (typeof theme === "string") {
|
|
@@ -20226,7 +20892,7 @@ var SystemCanvas = (() => {
|
|
|
20226
20892
|
onEdgeUpdate: handleEdgeUpdate,
|
|
20227
20893
|
onEdgeDelete: handleEdgeDelete
|
|
20228
20894
|
};
|
|
20229
|
-
root2.render(
|
|
20895
|
+
root2.render(import_react24.default.createElement(SystemCanvas, props));
|
|
20230
20896
|
};
|
|
20231
20897
|
doRender();
|
|
20232
20898
|
return {
|