system-canvas-standalone 0.1.1 → 0.2.1
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 +830 -190
- 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_react22 = __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
|
}
|
|
@@ -14119,7 +14307,7 @@ var SystemCanvas = (() => {
|
|
|
14119
14307
|
}
|
|
14120
14308
|
|
|
14121
14309
|
// ../core/dist/text.js
|
|
14122
|
-
var GLYPH_WIDTH_RATIO = 0.
|
|
14310
|
+
var GLYPH_WIDTH_RATIO = 0.55;
|
|
14123
14311
|
function measureTextWidth(text, fontSize) {
|
|
14124
14312
|
if (!text)
|
|
14125
14313
|
return 0;
|
|
@@ -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
|
|
@@ -14484,7 +14695,12 @@ var SystemCanvas = (() => {
|
|
|
14484
14695
|
onContextMenu({
|
|
14485
14696
|
type,
|
|
14486
14697
|
target,
|
|
14487
|
-
position: canvasPos
|
|
14698
|
+
position: canvasPos,
|
|
14699
|
+
// Raw viewport coords from the original MouseEvent. Consumers
|
|
14700
|
+
// rendering a `position: fixed` floating menu need these — the
|
|
14701
|
+
// canvas-space `position` would be wrong because it walks
|
|
14702
|
+
// with the user's pan/zoom.
|
|
14703
|
+
screenPosition: { x: event.clientX, y: event.clientY }
|
|
14488
14704
|
});
|
|
14489
14705
|
};
|
|
14490
14706
|
}, [onContextMenu, viewport]);
|
|
@@ -14520,11 +14736,43 @@ var SystemCanvas = (() => {
|
|
|
14520
14736
|
var import_react3 = __toESM(require_react(), 1);
|
|
14521
14737
|
var DRAG_THRESHOLD = 3;
|
|
14522
14738
|
function useNodeDrag(options) {
|
|
14523
|
-
const { viewport, nodesRef, onCommit } = options;
|
|
14739
|
+
const { viewport, nodesRef, onCommit, svgRef, canDropNodeOn, onNodeDrop } = options;
|
|
14524
14740
|
const [dragOverrides, setDragOverrides] = (0, import_react3.useState)(() => /* @__PURE__ */ new Map());
|
|
14525
14741
|
const [isDragging, setIsDragging] = (0, import_react3.useState)(false);
|
|
14742
|
+
const [dropTargetId, setDropTargetId] = (0, import_react3.useState)(null);
|
|
14526
14743
|
const stateRef = (0, import_react3.useRef)(null);
|
|
14527
14744
|
const movedRef = (0, import_react3.useRef)(false);
|
|
14745
|
+
const canDropNodeOnRef = (0, import_react3.useRef)(canDropNodeOn);
|
|
14746
|
+
canDropNodeOnRef.current = canDropNodeOn;
|
|
14747
|
+
const onNodeDropRef = (0, import_react3.useRef)(onNodeDrop);
|
|
14748
|
+
onNodeDropRef.current = onNodeDrop;
|
|
14749
|
+
const svgRefRef = (0, import_react3.useRef)(svgRef);
|
|
14750
|
+
svgRefRef.current = svgRef;
|
|
14751
|
+
const dropTargetIdRef = (0, import_react3.useRef)(null);
|
|
14752
|
+
const computeDropTarget = (0, import_react3.useCallback)((clientX, clientY) => {
|
|
14753
|
+
const cb = canDropNodeOnRef.current;
|
|
14754
|
+
const st = stateRef.current;
|
|
14755
|
+
const nodes = nodesRef.current;
|
|
14756
|
+
const svg = svgRefRef.current?.current;
|
|
14757
|
+
if (!cb || !st || !nodes || !svg)
|
|
14758
|
+
return null;
|
|
14759
|
+
const rect = svg.getBoundingClientRect();
|
|
14760
|
+
const vp = viewport.current ?? { x: 0, y: 0, zoom: 1 };
|
|
14761
|
+
const { x, y } = screenToCanvas(clientX - rect.left, clientY - rect.top, vp);
|
|
14762
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
14763
|
+
const n = nodes[i];
|
|
14764
|
+
if (st.moving.has(n.id))
|
|
14765
|
+
continue;
|
|
14766
|
+
if (x < n.x || x > n.x + n.width)
|
|
14767
|
+
continue;
|
|
14768
|
+
if (y < n.y || y > n.y + n.height)
|
|
14769
|
+
continue;
|
|
14770
|
+
if (cb([st.source], n))
|
|
14771
|
+
return n.id;
|
|
14772
|
+
return null;
|
|
14773
|
+
}
|
|
14774
|
+
return null;
|
|
14775
|
+
}, [nodesRef, viewport]);
|
|
14528
14776
|
const onPointerMove = (0, import_react3.useCallback)((event) => {
|
|
14529
14777
|
const st = stateRef.current;
|
|
14530
14778
|
if (!st || event.pointerId !== st.pointerId)
|
|
@@ -14546,7 +14794,12 @@ var SystemCanvas = (() => {
|
|
|
14546
14794
|
next.set(id2, { x: start2.startX + dx, y: start2.startY + dy });
|
|
14547
14795
|
}
|
|
14548
14796
|
setDragOverrides(next);
|
|
14549
|
-
|
|
14797
|
+
const nextTarget = computeDropTarget(event.clientX, event.clientY);
|
|
14798
|
+
if (nextTarget !== dropTargetIdRef.current) {
|
|
14799
|
+
dropTargetIdRef.current = nextTarget;
|
|
14800
|
+
setDropTargetId(nextTarget);
|
|
14801
|
+
}
|
|
14802
|
+
}, [viewport, computeDropTarget]);
|
|
14550
14803
|
const finishDrag = (0, import_react3.useCallback)((commit) => {
|
|
14551
14804
|
const st = stateRef.current;
|
|
14552
14805
|
if (!st)
|
|
@@ -14559,17 +14812,38 @@ var SystemCanvas = (() => {
|
|
|
14559
14812
|
st.captureTarget.releasePointerCapture?.(st.pointerId);
|
|
14560
14813
|
} catch {
|
|
14561
14814
|
}
|
|
14815
|
+
const dropTarget = dropTargetIdRef.current;
|
|
14816
|
+
if (commit && movedRef.current && dropTarget) {
|
|
14817
|
+
const nodes = nodesRef.current;
|
|
14818
|
+
const target = nodes?.find((n) => n.id === dropTarget) ?? null;
|
|
14819
|
+
if (target && onNodeDropRef.current) {
|
|
14820
|
+
onNodeDropRef.current([st.source], target);
|
|
14821
|
+
stateRef.current = null;
|
|
14822
|
+
movedRef.current = false;
|
|
14823
|
+
dropTargetIdRef.current = null;
|
|
14824
|
+
setIsDragging(false);
|
|
14825
|
+
setDragOverrides(/* @__PURE__ */ new Map());
|
|
14826
|
+
setDropTargetId(null);
|
|
14827
|
+
return;
|
|
14828
|
+
}
|
|
14829
|
+
}
|
|
14562
14830
|
if (commit && movedRef.current) {
|
|
14563
14831
|
const overrides = Array.from(dragOverridesRef.current.entries());
|
|
14564
|
-
|
|
14565
|
-
|
|
14832
|
+
if (overrides.length > 0) {
|
|
14833
|
+
const updates = overrides.map(([id2, pos]) => ({
|
|
14834
|
+
id: id2,
|
|
14835
|
+
patch: { x: Math.round(pos.x), y: Math.round(pos.y) }
|
|
14836
|
+
}));
|
|
14837
|
+
onCommit(updates);
|
|
14566
14838
|
}
|
|
14567
14839
|
}
|
|
14568
14840
|
stateRef.current = null;
|
|
14569
14841
|
movedRef.current = false;
|
|
14842
|
+
dropTargetIdRef.current = null;
|
|
14570
14843
|
setIsDragging(false);
|
|
14571
14844
|
setDragOverrides(/* @__PURE__ */ new Map());
|
|
14572
|
-
|
|
14845
|
+
setDropTargetId(null);
|
|
14846
|
+
}, [onPointerMove, onCommit, nodesRef]);
|
|
14573
14847
|
const dragOverridesRef = (0, import_react3.useRef)(dragOverrides);
|
|
14574
14848
|
dragOverridesRef.current = dragOverrides;
|
|
14575
14849
|
const onPointerUpRef = (0, import_react3.useRef)(null);
|
|
@@ -14609,9 +14883,11 @@ var SystemCanvas = (() => {
|
|
|
14609
14883
|
startClientY: event.clientY,
|
|
14610
14884
|
captureTarget: event.currentTarget,
|
|
14611
14885
|
pointerId: event.pointerId,
|
|
14612
|
-
moving
|
|
14886
|
+
moving,
|
|
14887
|
+
source: node
|
|
14613
14888
|
};
|
|
14614
14889
|
movedRef.current = false;
|
|
14890
|
+
dropTargetIdRef.current = null;
|
|
14615
14891
|
try {
|
|
14616
14892
|
;
|
|
14617
14893
|
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
@@ -14621,7 +14897,7 @@ var SystemCanvas = (() => {
|
|
|
14621
14897
|
window.addEventListener("pointerup", onPointerUp);
|
|
14622
14898
|
window.addEventListener("pointercancel", onPointerCancel);
|
|
14623
14899
|
}, [nodesRef, onPointerMove, onPointerUp, onPointerCancel]);
|
|
14624
|
-
return { dragOverrides, onPointerDown, isDragging };
|
|
14900
|
+
return { dragOverrides, dropTargetId, onPointerDown, isDragging };
|
|
14625
14901
|
}
|
|
14626
14902
|
|
|
14627
14903
|
// ../react/dist/hooks/useNodeResize.js
|
|
@@ -14896,11 +15172,15 @@ var SystemCanvas = (() => {
|
|
|
14896
15172
|
return { x, y, zoom };
|
|
14897
15173
|
}
|
|
14898
15174
|
function useZoomNavigation(options) {
|
|
14899
|
-
const { enabled, config, nodes, currentCanvas, parentFrame, canvases, onResolveCanvas, onSeedCanvas, theme, getViewportSize, onEnter, onExit } = options;
|
|
15175
|
+
const { enabled, config, nodes, currentCanvas, parentFrame, canvases, onResolveCanvas, onSeedCanvas, theme, getViewportSize, getCursorScreenPos, onEnter, onExit } = options;
|
|
14900
15176
|
const committingRef = (0, import_react6.useRef)(false);
|
|
14901
15177
|
(0, import_react6.useEffect)(() => {
|
|
14902
15178
|
committingRef.current = false;
|
|
14903
15179
|
}, [currentCanvas]);
|
|
15180
|
+
const exitArmedRef = (0, import_react6.useRef)(false);
|
|
15181
|
+
(0, import_react6.useEffect)(() => {
|
|
15182
|
+
exitArmedRef.current = false;
|
|
15183
|
+
}, [currentCanvas, parentFrame]);
|
|
14904
15184
|
const prefetchRef = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
|
|
14905
15185
|
const prefetch = (0, import_react6.useCallback)((ref) => {
|
|
14906
15186
|
if (!onResolveCanvas)
|
|
@@ -14928,36 +15208,87 @@ var SystemCanvas = (() => {
|
|
|
14928
15208
|
const size = getViewportSize();
|
|
14929
15209
|
if (!size)
|
|
14930
15210
|
return;
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
const
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
15211
|
+
const cursor = getCursorScreenPos();
|
|
15212
|
+
const viewportCenterX = size.width / 2;
|
|
15213
|
+
const viewportCenterY = size.height / 2;
|
|
15214
|
+
let cursorNode = null;
|
|
15215
|
+
if (cursor) {
|
|
15216
|
+
for (const n of nodes) {
|
|
15217
|
+
if (!n.ref)
|
|
15218
|
+
continue;
|
|
15219
|
+
const screen = canvasRectToScreenRect({ x: n.x, y: n.y, width: n.width, height: n.height }, vp);
|
|
15220
|
+
if (cursor.x < screen.x || cursor.x > screen.x + screen.width || cursor.y < screen.y || cursor.y > screen.y + screen.height) {
|
|
15221
|
+
continue;
|
|
15222
|
+
}
|
|
15223
|
+
const area = screen.width * screen.height;
|
|
15224
|
+
if (!cursorNode || area < cursorNode.area) {
|
|
15225
|
+
cursorNode = { node: n, screen, area };
|
|
15226
|
+
}
|
|
15227
|
+
}
|
|
15228
|
+
}
|
|
15229
|
+
let bestCandidate = null;
|
|
15230
|
+
if (cursorNode) {
|
|
15231
|
+
const screen = cursorNode.screen;
|
|
14940
15232
|
const fillFraction = Math.max(screen.width / size.width, screen.height / size.height);
|
|
14941
|
-
if (fillFraction >= config.prefetchThreshold &&
|
|
14942
|
-
prefetch(
|
|
15233
|
+
if (fillFraction >= config.prefetchThreshold && cursorNode.node.ref) {
|
|
15234
|
+
prefetch(cursorNode.node.ref);
|
|
14943
15235
|
}
|
|
14944
15236
|
if (fillFraction >= config.enterThreshold) {
|
|
14945
|
-
|
|
14946
|
-
|
|
15237
|
+
bestCandidate = { node: cursorNode.node, screen, distSq: 0 };
|
|
15238
|
+
}
|
|
15239
|
+
for (const n of nodes) {
|
|
15240
|
+
if (!n.ref)
|
|
15241
|
+
continue;
|
|
15242
|
+
if (n === cursorNode.node)
|
|
15243
|
+
continue;
|
|
15244
|
+
const s = canvasRectToScreenRect({ x: n.x, y: n.y, width: n.width, height: n.height }, vp);
|
|
15245
|
+
const ff = Math.max(s.width / size.width, s.height / size.height);
|
|
15246
|
+
if (ff >= config.prefetchThreshold)
|
|
14947
15247
|
prefetch(n.ref);
|
|
15248
|
+
}
|
|
15249
|
+
} else {
|
|
15250
|
+
for (const n of nodes) {
|
|
15251
|
+
if (!n.ref)
|
|
15252
|
+
continue;
|
|
15253
|
+
const screen = canvasRectToScreenRect({ x: n.x, y: n.y, width: n.width, height: n.height }, vp);
|
|
15254
|
+
const centerX = screen.x + screen.width / 2;
|
|
15255
|
+
const centerY = screen.y + screen.height / 2;
|
|
15256
|
+
const centerOnScreen = centerX >= 0 && centerX <= size.width && centerY >= 0 && centerY <= size.height;
|
|
15257
|
+
if (!centerOnScreen)
|
|
14948
15258
|
continue;
|
|
15259
|
+
const fillFraction = Math.max(screen.width / size.width, screen.height / size.height);
|
|
15260
|
+
if (fillFraction >= config.prefetchThreshold && fillFraction < config.enterThreshold) {
|
|
15261
|
+
prefetch(n.ref);
|
|
14949
15262
|
}
|
|
15263
|
+
if (fillFraction >= config.enterThreshold) {
|
|
15264
|
+
const dx = centerX - viewportCenterX;
|
|
15265
|
+
const dy = centerY - viewportCenterY;
|
|
15266
|
+
const distSq = dx * dx + dy * dy;
|
|
15267
|
+
if (!bestCandidate || distSq < bestCandidate.distSq) {
|
|
15268
|
+
bestCandidate = { node: n, screen, distSq };
|
|
15269
|
+
}
|
|
15270
|
+
}
|
|
15271
|
+
}
|
|
15272
|
+
}
|
|
15273
|
+
if (bestCandidate) {
|
|
15274
|
+
const n = bestCandidate.node;
|
|
15275
|
+
const screen = bestCandidate.screen;
|
|
15276
|
+
const ref = n.ref;
|
|
15277
|
+
const childData = canvases?.[ref] ?? prefetchRef.current.get(ref)?.data;
|
|
15278
|
+
if (!childData) {
|
|
15279
|
+
prefetch(ref);
|
|
15280
|
+
} else {
|
|
14950
15281
|
const resolved = resolveCanvas(childData, theme);
|
|
14951
|
-
if (resolved.nodes.length
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
15282
|
+
if (resolved.nodes.length > 0) {
|
|
15283
|
+
const bounds = computeBoundingBox(resolved.nodes);
|
|
15284
|
+
const targetRect = expandRect(screen, config.landingScale);
|
|
15285
|
+
const landingPad = Math.min(targetRect.width, targetRect.height) * config.landingPadding;
|
|
15286
|
+
let targetTransform = fitBoundsIntoRect(bounds, targetRect, landingPad);
|
|
15287
|
+
targetTransform = clampTransformToViewport(targetTransform, bounds, size, 16);
|
|
15288
|
+
committingRef.current = true;
|
|
15289
|
+
onEnter(n, targetTransform);
|
|
15290
|
+
return;
|
|
15291
|
+
}
|
|
14961
15292
|
}
|
|
14962
15293
|
}
|
|
14963
15294
|
if (parentFrame && nodes.length > 0) {
|
|
@@ -14971,6 +15302,12 @@ var SystemCanvas = (() => {
|
|
|
14971
15302
|
height: bounds.height
|
|
14972
15303
|
}, vp);
|
|
14973
15304
|
const fillFraction = Math.max(screen.width / size.width, screen.height / size.height);
|
|
15305
|
+
if (!exitArmedRef.current) {
|
|
15306
|
+
if (fillFraction > config.exitThreshold) {
|
|
15307
|
+
exitArmedRef.current = true;
|
|
15308
|
+
}
|
|
15309
|
+
return;
|
|
15310
|
+
}
|
|
14974
15311
|
if (fillFraction <= config.exitThreshold) {
|
|
14975
15312
|
const targetTransform = fitBoundsIntoRect({
|
|
14976
15313
|
minX: parentFrame.parentNodeRect.x,
|
|
@@ -14997,6 +15334,7 @@ var SystemCanvas = (() => {
|
|
|
14997
15334
|
theme,
|
|
14998
15335
|
config,
|
|
14999
15336
|
getViewportSize,
|
|
15337
|
+
getCursorScreenPos,
|
|
15000
15338
|
prefetch,
|
|
15001
15339
|
onEnter,
|
|
15002
15340
|
onExit
|
|
@@ -17872,17 +18210,67 @@ var SystemCanvas = (() => {
|
|
|
17872
18210
|
|
|
17873
18211
|
// ../react/dist/components/NodeIcon.js
|
|
17874
18212
|
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
|
|
17875
|
-
function NodeIcon({ icon, x, y, size = 14, color: color2, opacity = 0.7, customIcons }) {
|
|
18213
|
+
function NodeIcon({ icon, x, y, size = 14, color: color2, opacity = 0.7, customIcons, mode = "stroke", viewBox = 16 }) {
|
|
17876
18214
|
const pathData = customIcons?.[icon] ?? iconPaths[icon];
|
|
17877
18215
|
if (!pathData)
|
|
17878
18216
|
return null;
|
|
17879
|
-
|
|
18217
|
+
const defaultStrokeWidth = viewBox * 0.075;
|
|
18218
|
+
return (0, import_jsx_runtime.jsx)("g", { transform: `translate(${x}, ${y})`, pointerEvents: "none", opacity, children: pathData.map((entry, i) => {
|
|
18219
|
+
const spec = typeof entry === "string" ? { d: entry } : entry;
|
|
18220
|
+
const pathMode = spec.mode ?? mode;
|
|
18221
|
+
const rawStrokeWidth = spec.strokeWidth ?? defaultStrokeWidth;
|
|
18222
|
+
const renderedStrokeWidth = rawStrokeWidth * size / viewBox;
|
|
18223
|
+
return (0, import_jsx_runtime.jsx)("path", {
|
|
18224
|
+
d: scalePathData(spec.d, size, viewBox),
|
|
18225
|
+
fill: pathMode === "fill" ? color2 : "none",
|
|
18226
|
+
stroke: pathMode === "stroke" ? color2 : "none",
|
|
18227
|
+
strokeWidth: pathMode === "stroke" ? renderedStrokeWidth : 0,
|
|
18228
|
+
strokeLinecap: pathMode === "stroke" ? "round" : void 0,
|
|
18229
|
+
strokeLinejoin: pathMode === "stroke" ? "round" : void 0,
|
|
18230
|
+
// Brand silhouettes are typically authored as a single path
|
|
18231
|
+
// whose holes are expressed with subpath winding. `evenodd`
|
|
18232
|
+
// is the safe choice; nonzero would fill some holes solid.
|
|
18233
|
+
fillRule: pathMode === "fill" ? "evenodd" : void 0
|
|
18234
|
+
}, i);
|
|
18235
|
+
}) });
|
|
17880
18236
|
}
|
|
17881
|
-
function scalePathData(d, size) {
|
|
17882
|
-
const scale = size /
|
|
17883
|
-
|
|
17884
|
-
|
|
17885
|
-
|
|
18237
|
+
function scalePathData(d, size, source) {
|
|
18238
|
+
const scale = size / source;
|
|
18239
|
+
const out = [];
|
|
18240
|
+
const numberAtStart = /^-?(?:\d+\.?\d*|\.\d+)/;
|
|
18241
|
+
let isArc = false;
|
|
18242
|
+
let arcIndex = 0;
|
|
18243
|
+
let i = 0;
|
|
18244
|
+
while (i < d.length) {
|
|
18245
|
+
const ch = d[i];
|
|
18246
|
+
if (ch === " " || ch === "," || ch === " " || ch === "\n" || ch === "\r") {
|
|
18247
|
+
i++;
|
|
18248
|
+
continue;
|
|
18249
|
+
}
|
|
18250
|
+
if (/[a-zA-Z]/.test(ch)) {
|
|
18251
|
+
out.push(ch);
|
|
18252
|
+
isArc = ch === "a" || ch === "A";
|
|
18253
|
+
arcIndex = 0;
|
|
18254
|
+
i++;
|
|
18255
|
+
continue;
|
|
18256
|
+
}
|
|
18257
|
+
if (isArc && (arcIndex === 3 || arcIndex === 4)) {
|
|
18258
|
+
out.push(ch === "0" ? "0" : "1");
|
|
18259
|
+
arcIndex = (arcIndex + 1) % 7;
|
|
18260
|
+
i++;
|
|
18261
|
+
continue;
|
|
18262
|
+
}
|
|
18263
|
+
const m = numberAtStart.exec(d.substring(i));
|
|
18264
|
+
if (!m) {
|
|
18265
|
+
i++;
|
|
18266
|
+
continue;
|
|
18267
|
+
}
|
|
18268
|
+
out.push(String(parseFloat(m[0]) * scale));
|
|
18269
|
+
if (isArc)
|
|
18270
|
+
arcIndex = (arcIndex + 1) % 7;
|
|
18271
|
+
i += m[0].length;
|
|
18272
|
+
}
|
|
18273
|
+
return out.join(" ");
|
|
17886
18274
|
}
|
|
17887
18275
|
var iconPaths = {
|
|
17888
18276
|
// Database: cylinder shape
|
|
@@ -17975,11 +18363,12 @@ var SystemCanvas = (() => {
|
|
|
17975
18363
|
// ../react/dist/components/RefIndicator.js
|
|
17976
18364
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
17977
18365
|
var import_react8 = __toESM(require_react(), 1);
|
|
17978
|
-
function RefIndicator({ node, theme, nodeX, nodeY, nodeWidth, nodeHeight, strokeColor, strokeWidth, corner = "bottom-right", size
|
|
18366
|
+
function RefIndicator({ node, theme, nodeX, nodeY, nodeWidth, nodeHeight, strokeColor, strokeWidth, corner = "bottom-right", size: sizeProp, onNavigate }) {
|
|
17979
18367
|
const [hover, setHover] = (0, import_react8.useState)(false);
|
|
17980
18368
|
const iconKind = theme.node.refIndicator.icon;
|
|
17981
18369
|
if (iconKind === "none")
|
|
17982
18370
|
return null;
|
|
18371
|
+
const size = sizeProp ?? theme.node.refIndicator.size ?? 18;
|
|
17983
18372
|
const stopAll = (e) => e.stopPropagation();
|
|
17984
18373
|
const right = nodeX + nodeWidth;
|
|
17985
18374
|
const bottom = nodeY + nodeHeight;
|
|
@@ -18025,19 +18414,22 @@ var SystemCanvas = (() => {
|
|
|
18025
18414
|
return (0, import_jsx_runtime2.jsxs)("g", { className: "system-canvas-ref-indicator", style: { cursor: "pointer" }, onClick: (e) => {
|
|
18026
18415
|
e.stopPropagation();
|
|
18027
18416
|
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 })] });
|
|
18417
|
+
}, 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
18418
|
}
|
|
18030
|
-
function Glyph({ kind, cx, cy, color: color2 }) {
|
|
18031
|
-
const s =
|
|
18419
|
+
function Glyph({ kind, cx, cy, color: color2, size }) {
|
|
18420
|
+
const s = size / 6;
|
|
18421
|
+
const sw = Math.max(1, size / 9);
|
|
18032
18422
|
switch (kind) {
|
|
18033
18423
|
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:
|
|
18424
|
+
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
18425
|
case "arrow": {
|
|
18036
18426
|
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:
|
|
18427
|
+
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" });
|
|
18428
|
+
}
|
|
18429
|
+
case "expand": {
|
|
18430
|
+
const sw2 = Math.max(1, size / 12);
|
|
18431
|
+
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
18432
|
}
|
|
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
18433
|
}
|
|
18042
18434
|
}
|
|
18043
18435
|
|
|
@@ -18164,7 +18556,7 @@ var SystemCanvas = (() => {
|
|
|
18164
18556
|
// ../react/dist/primitives/NodeText.js
|
|
18165
18557
|
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
18166
18558
|
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 }) {
|
|
18559
|
+
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
18560
|
const reactId = (0, import_react9.useId)();
|
|
18169
18561
|
const safeId = reactId.replace(/:/g, "");
|
|
18170
18562
|
if (!value)
|
|
@@ -18178,15 +18570,16 @@ var SystemCanvas = (() => {
|
|
|
18178
18570
|
const fillAttr = gradId ? `url(#${gradId})` : color2 ?? theme.node.sublabelColor;
|
|
18179
18571
|
const displayValue = uppercase ? value.toUpperCase() : value;
|
|
18180
18572
|
if (!wrap) {
|
|
18573
|
+
const rendered = truncateToWidth(displayValue, region.width, fontSize);
|
|
18181
18574
|
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:
|
|
18575
|
+
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
18576
|
}
|
|
18184
|
-
const
|
|
18185
|
-
const wrapWidth = Math.max(0, region.width - wrapInset * 2);
|
|
18186
|
-
const lines = wrapTextWithBreaks(displayValue, wrapWidth, fontSize, maxLines);
|
|
18577
|
+
const lines = wrapTextWithBreaks(displayValue, region.width, fontSize, maxLines);
|
|
18187
18578
|
if (lines.length === 0)
|
|
18188
18579
|
return null;
|
|
18189
|
-
const
|
|
18580
|
+
const blockHeight = fontSize + (lines.length - 1) * lineHeight;
|
|
18581
|
+
const topY = region.y + fontSize;
|
|
18582
|
+
const baseY = verticalAlign === "center" ? region.y + (region.height - blockHeight) / 2 + fontSize : verticalAlign === "bottom" ? region.y + region.height - blockHeight + fontSize : topY;
|
|
18190
18583
|
const clipId = `sc-text-clip-${safeId}`;
|
|
18191
18584
|
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)) }) })] });
|
|
18192
18585
|
}
|
|
@@ -18338,6 +18731,20 @@ var SystemCanvas = (() => {
|
|
|
18338
18731
|
const color2 = resolveAccessorOr(spec.color, nodeColor, ctx);
|
|
18339
18732
|
return (0, import_jsx_runtime9.jsx)(NodeDot, { region, color: color2 });
|
|
18340
18733
|
}
|
|
18734
|
+
case "icon": {
|
|
18735
|
+
const name = resolveAccessor(spec.name, ctx);
|
|
18736
|
+
if (!name)
|
|
18737
|
+
return null;
|
|
18738
|
+
const color2 = resolveAccessorOr(spec.color, nodeColor, ctx);
|
|
18739
|
+
const opacity = resolveAccessorOr(spec.opacity, 1, ctx);
|
|
18740
|
+
const mode = resolveAccessorOr(spec.mode, "stroke", ctx);
|
|
18741
|
+
const viewBox = resolveAccessorOr(spec.viewBox, 16, ctx);
|
|
18742
|
+
const auto = Math.max(8, Math.min(region.width, region.height) - 2);
|
|
18743
|
+
const size = resolveAccessorOr(spec.size, auto, ctx);
|
|
18744
|
+
const x = region.x + (region.width - size) / 2;
|
|
18745
|
+
const y = region.y + (region.height - size) / 2;
|
|
18746
|
+
return (0, import_jsx_runtime9.jsx)(NodeIcon, { icon: name, x, y, size, color: color2, opacity, customIcons: theme.icons, mode, viewBox });
|
|
18747
|
+
}
|
|
18341
18748
|
case "custom": {
|
|
18342
18749
|
return spec.render(ctx);
|
|
18343
18750
|
}
|
|
@@ -18365,20 +18772,21 @@ var SystemCanvas = (() => {
|
|
|
18365
18772
|
const contentY = y + reservedTop;
|
|
18366
18773
|
const contentWidth = Math.max(0, width - reservedLeft - reservedRight);
|
|
18367
18774
|
const contentHeight = Math.max(0, height - reservedTop - reservedBottom);
|
|
18368
|
-
const
|
|
18369
|
-
const
|
|
18370
|
-
const
|
|
18371
|
-
const sublabel = lines[1];
|
|
18775
|
+
const LABEL_PAD_X = 10;
|
|
18776
|
+
const LABEL_PAD_Y = 6;
|
|
18777
|
+
const text = node.text ?? node.id;
|
|
18372
18778
|
const hasBodySlot = slots?.body !== void 0;
|
|
18373
18779
|
const hasHeader = reservedTop > 0;
|
|
18374
|
-
const
|
|
18780
|
+
const hasInlineLeftMarker = slots?.topLeft !== void 0 && (slots.topLeft.kind === "dot" || slots.topLeft.kind === "icon") && !hasHeader;
|
|
18781
|
+
const isLeftAligned = hasHeader || hasInlineLeftMarker;
|
|
18375
18782
|
const labelFontSize = theme.node.fontSize + (hasHeader ? 1 : 0);
|
|
18376
|
-
const
|
|
18377
|
-
|
|
18378
|
-
|
|
18379
|
-
|
|
18380
|
-
|
|
18381
|
-
|
|
18783
|
+
const labelAlign = isLeftAligned ? "start" : "center";
|
|
18784
|
+
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: {
|
|
18785
|
+
x: contentX + LABEL_PAD_X,
|
|
18786
|
+
y: contentY + LABEL_PAD_Y,
|
|
18787
|
+
width: Math.max(0, contentWidth - LABEL_PAD_X * 2),
|
|
18788
|
+
height: Math.max(0, contentHeight - LABEL_PAD_Y * 2)
|
|
18789
|
+
}, 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 })] });
|
|
18382
18790
|
}
|
|
18383
18791
|
|
|
18384
18792
|
// ../react/dist/components/FileNode.js
|
|
@@ -18392,6 +18800,7 @@ var SystemCanvas = (() => {
|
|
|
18392
18800
|
const fold = 10;
|
|
18393
18801
|
const textPadding = 10 + reservedLeft;
|
|
18394
18802
|
const maxTextWidth = width - textPadding - reservedRight - fold;
|
|
18803
|
+
const LABEL_PAD_Y = 6;
|
|
18395
18804
|
const contentY = y + reservedTop;
|
|
18396
18805
|
const contentHeight = Math.max(0, height - reservedTop - reservedBottom);
|
|
18397
18806
|
const shapePath = [
|
|
@@ -18410,7 +18819,12 @@ var SystemCanvas = (() => {
|
|
|
18410
18819
|
const strokeColor = node.resolvedStroke;
|
|
18411
18820
|
const thinStroke = 0.75;
|
|
18412
18821
|
const clipId = `file-clip-${node.id}`;
|
|
18413
|
-
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)(
|
|
18822
|
+
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: {
|
|
18823
|
+
x: x + textPadding,
|
|
18824
|
+
y: dirPath ? contentY + 18 : contentY + (subpath ? 8 : LABEL_PAD_Y),
|
|
18825
|
+
width: maxTextWidth,
|
|
18826
|
+
height: dirPath ? Math.max(0, contentHeight - 18 - (subpath ? 16 : 0)) : Math.max(0, contentHeight - (subpath ? 16 : 0) - LABEL_PAD_Y * 2)
|
|
18827
|
+
}, 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 })] });
|
|
18414
18828
|
}
|
|
18415
18829
|
|
|
18416
18830
|
// ../react/dist/components/LinkNode.js
|
|
@@ -18421,14 +18835,21 @@ var SystemCanvas = (() => {
|
|
|
18421
18835
|
const contentY = y + reservedTop;
|
|
18422
18836
|
const contentWidth = Math.max(0, width - reservedLeft - reservedRight);
|
|
18423
18837
|
const contentHeight = Math.max(0, height - reservedTop - reservedBottom);
|
|
18424
|
-
const
|
|
18838
|
+
const glyphReserve = 20;
|
|
18839
|
+
const LABEL_PAD_X = 10;
|
|
18840
|
+
const LABEL_PAD_Y = 6;
|
|
18425
18841
|
let displayUrl = node.url ?? "";
|
|
18426
18842
|
try {
|
|
18427
18843
|
const url = new URL(displayUrl);
|
|
18428
18844
|
displayUrl = url.hostname;
|
|
18429
18845
|
} catch {
|
|
18430
18846
|
}
|
|
18431
|
-
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)(
|
|
18847
|
+
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: {
|
|
18848
|
+
x: contentX + glyphReserve,
|
|
18849
|
+
y: contentY + LABEL_PAD_Y,
|
|
18850
|
+
width: Math.max(0, contentWidth - glyphReserve - LABEL_PAD_X),
|
|
18851
|
+
height: Math.max(0, contentHeight - LABEL_PAD_Y * 2)
|
|
18852
|
+
}, 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 })] });
|
|
18432
18853
|
}
|
|
18433
18854
|
|
|
18434
18855
|
// ../react/dist/components/GroupNode.js
|
|
@@ -18554,7 +18975,8 @@ var SystemCanvas = (() => {
|
|
|
18554
18975
|
const isEditing = editingId === edge.id;
|
|
18555
18976
|
const baseColor = edge.color ? resolveColor(edge.color, theme).stroke : theme.edge.stroke;
|
|
18556
18977
|
const edgeColor = isSelected ? theme.node.labelColor : baseColor;
|
|
18557
|
-
const
|
|
18978
|
+
const baseStrokeWidth = edge.strokeWidth ?? theme.edge.strokeWidth;
|
|
18979
|
+
const strokeWidth = isSelected ? baseStrokeWidth * 1.75 : baseStrokeWidth;
|
|
18558
18980
|
const toEnd = edge.toEnd ?? "arrow";
|
|
18559
18981
|
const fromEnd = edge.fromEnd ?? "none";
|
|
18560
18982
|
const arrowId = "system-canvas-arrowhead";
|
|
@@ -18617,6 +19039,10 @@ var SystemCanvas = (() => {
|
|
|
18617
19039
|
const fontFamily = theme.node.fontFamily;
|
|
18618
19040
|
const fontSize = theme.node.fontSize;
|
|
18619
19041
|
const padding = 8;
|
|
19042
|
+
const slots = getCategorySlots(node, theme);
|
|
19043
|
+
const reservations = computeReflowReservations(node, theme, slots);
|
|
19044
|
+
const hasHeader = reservations.top > 0;
|
|
19045
|
+
const textAlign = node.type === "text" && !hasHeader ? "center" : "left";
|
|
18620
19046
|
const commonFieldStyle = {
|
|
18621
19047
|
width: "100%",
|
|
18622
19048
|
height: "100%",
|
|
@@ -18630,7 +19056,7 @@ var SystemCanvas = (() => {
|
|
|
18630
19056
|
borderRadius: node.resolvedCornerRadius,
|
|
18631
19057
|
outline: "none",
|
|
18632
19058
|
resize: "none",
|
|
18633
|
-
textAlign
|
|
19059
|
+
textAlign
|
|
18634
19060
|
};
|
|
18635
19061
|
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) => {
|
|
18636
19062
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
@@ -19000,7 +19426,7 @@ var SystemCanvas = (() => {
|
|
|
19000
19426
|
// ../react/dist/components/Viewport.js
|
|
19001
19427
|
var HOVER_PADDING = 10;
|
|
19002
19428
|
var EDGE_PROXIMITY = 16;
|
|
19003
|
-
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) {
|
|
19429
|
+
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) {
|
|
19004
19430
|
const { svgRef, groupRef, viewport, fitToContent, zoomToNode, setTransform } = useViewport({
|
|
19005
19431
|
minZoom,
|
|
19006
19432
|
maxZoom,
|
|
@@ -19043,6 +19469,7 @@ var SystemCanvas = (() => {
|
|
|
19043
19469
|
}, []);
|
|
19044
19470
|
const [hoveredNodeId, setHoveredNodeId] = (0, import_react15.useState)(null);
|
|
19045
19471
|
const [hoveredSide, setHoveredSide] = (0, import_react15.useState)(null);
|
|
19472
|
+
const cursorPosRef = (0, import_react15.useRef)(null);
|
|
19046
19473
|
(0, import_react15.useImperativeHandle)(ref, () => ({
|
|
19047
19474
|
zoomToNode: (node, onComplete, options) => {
|
|
19048
19475
|
navigatingRef.current = true;
|
|
@@ -19051,7 +19478,8 @@ var SystemCanvas = (() => {
|
|
|
19051
19478
|
fitToContent,
|
|
19052
19479
|
setTransform,
|
|
19053
19480
|
getSvgElement: () => svgRef.current,
|
|
19054
|
-
getViewport: () => viewport.current ?? { x: 0, y: 0, zoom: 1 }
|
|
19481
|
+
getViewport: () => viewport.current ?? { x: 0, y: 0, zoom: 1 },
|
|
19482
|
+
getCursorScreenPos: () => cursorPosRef.current
|
|
19055
19483
|
}));
|
|
19056
19484
|
const renderNodes = (0, import_react15.useMemo)(() => {
|
|
19057
19485
|
const hasDrag = dragOverrides && dragOverrides.size > 0;
|
|
@@ -19134,14 +19562,17 @@ var SystemCanvas = (() => {
|
|
|
19134
19562
|
]);
|
|
19135
19563
|
const editingNode = editingId ? renderNodes.find((n) => n.id === editingId) ?? null : null;
|
|
19136
19564
|
const handleSvgPointerMove = (0, import_react15.useCallback)((event) => {
|
|
19137
|
-
if (!edgeCreateEnabled)
|
|
19138
|
-
return;
|
|
19139
19565
|
const svg = svgRef.current;
|
|
19140
19566
|
if (!svg)
|
|
19141
19567
|
return;
|
|
19142
19568
|
const rect = svg.getBoundingClientRect();
|
|
19569
|
+
const cursorScreenX = event.clientX - rect.left;
|
|
19570
|
+
const cursorScreenY = event.clientY - rect.top;
|
|
19571
|
+
cursorPosRef.current = { x: cursorScreenX, y: cursorScreenY };
|
|
19572
|
+
if (!edgeCreateEnabled)
|
|
19573
|
+
return;
|
|
19143
19574
|
const vp = viewport.current ?? { x: 0, y: 0, zoom: 1 };
|
|
19144
|
-
const { x, y } = screenToCanvas(
|
|
19575
|
+
const { x, y } = screenToCanvas(cursorScreenX, cursorScreenY, vp);
|
|
19145
19576
|
const pad = HOVER_PADDING;
|
|
19146
19577
|
let hit = null;
|
|
19147
19578
|
for (let i = renderNodes.length - 1; i >= 0; i--) {
|
|
@@ -19185,11 +19616,13 @@ var SystemCanvas = (() => {
|
|
|
19185
19616
|
const handleSvgPointerLeave = (0, import_react15.useCallback)(() => {
|
|
19186
19617
|
setHoveredNodeId(null);
|
|
19187
19618
|
setHoveredSide(null);
|
|
19619
|
+
cursorPosRef.current = null;
|
|
19188
19620
|
}, []);
|
|
19189
19621
|
const handlesNodeId = pendingEdge?.sourceId ?? hoveredNodeId;
|
|
19190
19622
|
const handlesNode = edgeCreateEnabled && handlesNodeId ? renderNodeMap.get(handlesNodeId) ?? null : null;
|
|
19191
19623
|
const pendingSourceNode = pendingEdge ? renderNodeMap.get(pendingEdge.sourceId) ?? null : null;
|
|
19192
19624
|
const pendingTargetNode = pendingEdge?.hoveredTargetId && pendingEdge.hoveredTargetId !== pendingEdge.sourceId ? renderNodeMap.get(pendingEdge.hoveredTargetId) ?? null : null;
|
|
19625
|
+
const dropTargetNode = dropTargetId ? renderNodeMap.get(dropTargetId) ?? null : null;
|
|
19193
19626
|
const editingEdge = editingEdgeId ? edges.find((e) => e.id === editingEdgeId) ?? null : null;
|
|
19194
19627
|
const editingEdgeMidpoint = (() => {
|
|
19195
19628
|
if (!editingEdge)
|
|
@@ -19209,7 +19642,7 @@ var SystemCanvas = (() => {
|
|
|
19209
19642
|
WebkitUserSelect: "none",
|
|
19210
19643
|
MozUserSelect: "none",
|
|
19211
19644
|
msUserSelect: "none"
|
|
19212
|
-
}, 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 })] })] });
|
|
19645
|
+
}, 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 })] })] });
|
|
19213
19646
|
});
|
|
19214
19647
|
|
|
19215
19648
|
// ../react/dist/components/Breadcrumbs.js
|
|
@@ -19438,7 +19871,7 @@ var SystemCanvas = (() => {
|
|
|
19438
19871
|
const cx = visibleLeft + visibleW / 2;
|
|
19439
19872
|
if (endScreen <= colsOffsetLeft || startScreen >= width)
|
|
19440
19873
|
return null;
|
|
19441
|
-
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:
|
|
19874
|
+
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}`);
|
|
19442
19875
|
}), 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) => {
|
|
19443
19876
|
const startScreen = canvasToScreen(0, row.start, viewport).y;
|
|
19444
19877
|
const endScreen = canvasToScreen(0, row.start + row.size, viewport).y;
|
|
@@ -19450,10 +19883,10 @@ var SystemCanvas = (() => {
|
|
|
19450
19883
|
const cy = visibleTop + visibleH / 2;
|
|
19451
19884
|
if (endScreen <= rowsOffsetTop || startScreen >= height)
|
|
19452
19885
|
return null;
|
|
19453
|
-
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:
|
|
19886
|
+
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}`);
|
|
19454
19887
|
}), 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 })] });
|
|
19455
19888
|
}
|
|
19456
|
-
function
|
|
19889
|
+
function truncateToWidth2(label, availablePx, fontSize) {
|
|
19457
19890
|
if (availablePx <= 0)
|
|
19458
19891
|
return "";
|
|
19459
19892
|
const charPx = fontSize * 0.6;
|
|
@@ -19495,8 +19928,10 @@ var SystemCanvas = (() => {
|
|
|
19495
19928
|
raf = requestAnimationFrame(tick);
|
|
19496
19929
|
return () => cancelAnimationFrame(raf);
|
|
19497
19930
|
}, [getViewport]);
|
|
19498
|
-
const
|
|
19499
|
-
const
|
|
19931
|
+
const align = theme.toolbarAlign ?? "center";
|
|
19932
|
+
const anchorCanvasX = align === "left" ? node.x : align === "right" ? node.x + node.width : node.x + node.width / 2;
|
|
19933
|
+
const topAnchor = canvasToScreen(anchorCanvasX, node.y, viewport);
|
|
19934
|
+
const bottomAnchor = canvasToScreen(anchorCanvasX, node.y + node.height, viewport);
|
|
19500
19935
|
const toolbarRef = (0, import_react19.useRef)(null);
|
|
19501
19936
|
const [size, setSize] = (0, import_react19.useState)({ width: 0, height: 0 });
|
|
19502
19937
|
(0, import_react19.useEffect)(() => {
|
|
@@ -19505,17 +19940,17 @@ var SystemCanvas = (() => {
|
|
|
19505
19940
|
return;
|
|
19506
19941
|
const update = () => {
|
|
19507
19942
|
const r = el.getBoundingClientRect();
|
|
19508
|
-
setSize({ width: r.width, height: r.height });
|
|
19943
|
+
setSize((prev) => prev.width === r.width && prev.height === r.height ? prev : { width: r.width, height: r.height });
|
|
19509
19944
|
};
|
|
19510
19945
|
update();
|
|
19511
19946
|
const ro = new ResizeObserver(update);
|
|
19512
19947
|
ro.observe(el);
|
|
19513
19948
|
return () => ro.disconnect();
|
|
19514
|
-
});
|
|
19515
|
-
let left =
|
|
19516
|
-
let top =
|
|
19949
|
+
}, []);
|
|
19950
|
+
let left = align === "left" ? topAnchor.x : align === "right" ? topAnchor.x - size.width : topAnchor.x - size.width / 2;
|
|
19951
|
+
let top = topAnchor.y - size.height - NODE_GAP;
|
|
19517
19952
|
if (top < FLIP_MARGIN) {
|
|
19518
|
-
top =
|
|
19953
|
+
top = bottomAnchor.y + NODE_GAP;
|
|
19519
19954
|
}
|
|
19520
19955
|
left = Math.max(FLIP_MARGIN, Math.min(left, containerWidth - size.width - FLIP_MARGIN));
|
|
19521
19956
|
const patch = (update) => onPatch(update);
|
|
@@ -19554,7 +19989,7 @@ var SystemCanvas = (() => {
|
|
|
19554
19989
|
}
|
|
19555
19990
|
function DefaultToolbarContent({ node, theme, onPatch, onDelete }) {
|
|
19556
19991
|
const groups = (0, import_react19.useMemo)(() => getNodeActionsForNode(node, theme), [node, theme]);
|
|
19557
|
-
const showDelete =
|
|
19992
|
+
const showDelete = theme.showToolbarDelete === true;
|
|
19558
19993
|
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 })] })] });
|
|
19559
19994
|
}
|
|
19560
19995
|
function Divider2({ theme }) {
|
|
@@ -19709,16 +20144,134 @@ var SystemCanvas = (() => {
|
|
|
19709
20144
|
}, 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" }) }) });
|
|
19710
20145
|
}
|
|
19711
20146
|
|
|
20147
|
+
// ../react/dist/components/NodeContextMenuOverlay.js
|
|
20148
|
+
var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
|
|
20149
|
+
var import_react20 = __toESM(require_react(), 1);
|
|
20150
|
+
var ESTIMATED_MENU_WIDTH = 200;
|
|
20151
|
+
var MIN_MENU_WIDTH = 160;
|
|
20152
|
+
var VIEWPORT_MARGIN = 8;
|
|
20153
|
+
function NodeContextMenuOverlay({ state, config, theme, onClose }) {
|
|
20154
|
+
const rootRef = (0, import_react20.useRef)(null);
|
|
20155
|
+
const [hoveredId, setHoveredId] = (0, import_react20.useState)(null);
|
|
20156
|
+
(0, import_react20.useEffect)(() => {
|
|
20157
|
+
if (state)
|
|
20158
|
+
setHoveredId(null);
|
|
20159
|
+
}, [state]);
|
|
20160
|
+
(0, import_react20.useEffect)(() => {
|
|
20161
|
+
if (!state)
|
|
20162
|
+
return;
|
|
20163
|
+
function onDown(e) {
|
|
20164
|
+
const root2 = rootRef.current;
|
|
20165
|
+
if (!root2)
|
|
20166
|
+
return;
|
|
20167
|
+
if (root2.contains(e.target))
|
|
20168
|
+
return;
|
|
20169
|
+
onClose();
|
|
20170
|
+
}
|
|
20171
|
+
function onKey(e) {
|
|
20172
|
+
if (e.key === "Escape") {
|
|
20173
|
+
e.stopPropagation();
|
|
20174
|
+
onClose();
|
|
20175
|
+
}
|
|
20176
|
+
}
|
|
20177
|
+
function onScroll() {
|
|
20178
|
+
onClose();
|
|
20179
|
+
}
|
|
20180
|
+
window.addEventListener("mousedown", onDown);
|
|
20181
|
+
window.addEventListener("keydown", onKey);
|
|
20182
|
+
window.addEventListener("scroll", onScroll, true);
|
|
20183
|
+
window.addEventListener("blur", onClose);
|
|
20184
|
+
return () => {
|
|
20185
|
+
window.removeEventListener("mousedown", onDown);
|
|
20186
|
+
window.removeEventListener("keydown", onKey);
|
|
20187
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
20188
|
+
window.removeEventListener("blur", onClose);
|
|
20189
|
+
};
|
|
20190
|
+
}, [state, onClose]);
|
|
20191
|
+
if (!state)
|
|
20192
|
+
return null;
|
|
20193
|
+
const cm = theme.contextMenu;
|
|
20194
|
+
if (!cm)
|
|
20195
|
+
return null;
|
|
20196
|
+
const vw = typeof window !== "undefined" ? window.innerWidth : 0;
|
|
20197
|
+
const vh = typeof window !== "undefined" ? window.innerHeight : 0;
|
|
20198
|
+
const itemHeight = cm.itemPaddingY * 2 + cm.fontSize + 4;
|
|
20199
|
+
const estimatedHeight = state.items.length * itemHeight + cm.paddingY * 2;
|
|
20200
|
+
const left = vw ? Math.min(state.screenPosition.x, vw - ESTIMATED_MENU_WIDTH - VIEWPORT_MARGIN) : state.screenPosition.x;
|
|
20201
|
+
const top = vh ? Math.min(state.screenPosition.y, vh - estimatedHeight - VIEWPORT_MARGIN) : state.screenPosition.y;
|
|
20202
|
+
const matchCtx = { canvasRef: state.canvasRef };
|
|
20203
|
+
const anyIcon = state.items.some((item) => !!item.icon);
|
|
20204
|
+
return (0, import_jsx_runtime27.jsx)("div", {
|
|
20205
|
+
ref: rootRef,
|
|
20206
|
+
role: "menu",
|
|
20207
|
+
// Stop right-clicks inside the menu from bubbling into the document
|
|
20208
|
+
// listener and re-opening the canvas-level menu.
|
|
20209
|
+
onContextMenu: (e) => {
|
|
20210
|
+
e.preventDefault();
|
|
20211
|
+
e.stopPropagation();
|
|
20212
|
+
},
|
|
20213
|
+
style: {
|
|
20214
|
+
position: "fixed",
|
|
20215
|
+
left,
|
|
20216
|
+
top,
|
|
20217
|
+
zIndex: 1e3,
|
|
20218
|
+
minWidth: MIN_MENU_WIDTH,
|
|
20219
|
+
padding: `${cm.paddingY}px ${cm.paddingX}px`,
|
|
20220
|
+
background: cm.background,
|
|
20221
|
+
color: cm.itemColor,
|
|
20222
|
+
border: `1px solid ${cm.borderColor}`,
|
|
20223
|
+
borderRadius: cm.borderRadius,
|
|
20224
|
+
boxShadow: cm.shadow,
|
|
20225
|
+
fontFamily: cm.fontFamily,
|
|
20226
|
+
fontSize: cm.fontSize,
|
|
20227
|
+
backdropFilter: "blur(10px)",
|
|
20228
|
+
userSelect: "none",
|
|
20229
|
+
// `pointer-events: auto` so the menu still receives clicks even
|
|
20230
|
+
// when a parent canvas overlay disables them.
|
|
20231
|
+
pointerEvents: "auto"
|
|
20232
|
+
},
|
|
20233
|
+
children: state.items.map((item) => {
|
|
20234
|
+
const isDisabled = item.disabled?.(state.node, matchCtx) ?? false;
|
|
20235
|
+
const isHovered = !isDisabled && hoveredId === item.id;
|
|
20236
|
+
const color2 = item.destructive ? cm.destructiveItemColor : cm.itemColor;
|
|
20237
|
+
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: () => {
|
|
20238
|
+
if (isDisabled)
|
|
20239
|
+
return;
|
|
20240
|
+
config.onSelect(item.id, state.node, {
|
|
20241
|
+
canvasRef: state.canvasRef,
|
|
20242
|
+
screenPosition: state.screenPosition
|
|
20243
|
+
});
|
|
20244
|
+
onClose();
|
|
20245
|
+
}, style: {
|
|
20246
|
+
display: "flex",
|
|
20247
|
+
alignItems: "center",
|
|
20248
|
+
gap: 10,
|
|
20249
|
+
padding: `${cm.itemPaddingY}px ${cm.itemPaddingX}px`,
|
|
20250
|
+
borderRadius: Math.max(0, cm.borderRadius - 4),
|
|
20251
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
20252
|
+
opacity: isDisabled ? 0.45 : 1,
|
|
20253
|
+
background: isHovered ? cm.itemHoverBackground : "transparent",
|
|
20254
|
+
color: color2
|
|
20255
|
+
}, 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 ? (
|
|
20256
|
+
// Only reserve a spacer when other items in the same menu
|
|
20257
|
+
// do have icons — keeps labels vertically aligned in a
|
|
20258
|
+
// mixed menu without padding lone-item menus.
|
|
20259
|
+
(0, import_jsx_runtime27.jsx)("span", { style: { width: 14, flexShrink: 0 }, "aria-hidden": true })
|
|
20260
|
+
) : null, (0, import_jsx_runtime27.jsx)("span", { children: item.label })] }, item.id);
|
|
20261
|
+
})
|
|
20262
|
+
});
|
|
20263
|
+
}
|
|
20264
|
+
|
|
19712
20265
|
// ../react/dist/components/SystemCanvas.js
|
|
19713
20266
|
var CASCADE_WINDOW_MS = 1500;
|
|
19714
20267
|
var CASCADE_OFFSET = 20;
|
|
19715
|
-
var SystemCanvas = (0,
|
|
19716
|
-
const zoomNavConfig = (0,
|
|
20268
|
+
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) {
|
|
20269
|
+
const zoomNavConfig = (0, import_react21.useMemo)(() => {
|
|
19717
20270
|
const defaults = {
|
|
19718
20271
|
enterThreshold: 0.66,
|
|
19719
20272
|
exitThreshold: 0.33,
|
|
19720
20273
|
prefetchThreshold: 0.4,
|
|
19721
|
-
landingScale: 1.
|
|
20274
|
+
landingScale: 1.3,
|
|
19722
20275
|
landingPadding: 0.08,
|
|
19723
20276
|
fadeDuration: 216
|
|
19724
20277
|
};
|
|
@@ -19738,16 +20291,16 @@ var SystemCanvas = (() => {
|
|
|
19738
20291
|
}, [zoomNavigation]);
|
|
19739
20292
|
const effectiveMaxZoom = maxZoom ?? (zoomNavConfig.enabled ? 16 : 4);
|
|
19740
20293
|
const effectiveMinZoom = minZoomProp ?? (zoomNavConfig.enabled ? 0.01 : 0.1);
|
|
19741
|
-
(0,
|
|
20294
|
+
(0, import_react21.useEffect)(() => {
|
|
19742
20295
|
const env = globalThis.process?.env?.NODE_ENV;
|
|
19743
20296
|
if (editable && !canvases && env !== "production") {
|
|
19744
20297
|
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.");
|
|
19745
20298
|
}
|
|
19746
20299
|
}, [editable, canvases]);
|
|
19747
|
-
const [parentFrames, setParentFrames] = (0,
|
|
19748
|
-
const [pendingHandoff, setPendingHandoff] = (0,
|
|
19749
|
-
const suppressNextHandoffClearRef = (0,
|
|
19750
|
-
const handleBreadcrumbClick = (0,
|
|
20300
|
+
const [parentFrames, setParentFrames] = (0, import_react21.useState)([]);
|
|
20301
|
+
const [pendingHandoff, setPendingHandoff] = (0, import_react21.useState)(null);
|
|
20302
|
+
const suppressNextHandoffClearRef = (0, import_react21.useRef)(false);
|
|
20303
|
+
const handleBreadcrumbClick = (0, import_react21.useCallback)((index) => {
|
|
19751
20304
|
setParentFrames((prev) => prev.slice(0, index));
|
|
19752
20305
|
if (suppressNextHandoffClearRef.current) {
|
|
19753
20306
|
suppressNextHandoffClearRef.current = false;
|
|
@@ -19764,7 +20317,10 @@ var SystemCanvas = (() => {
|
|
|
19764
20317
|
onNavigate,
|
|
19765
20318
|
onBreadcrumbClick: handleBreadcrumbClick
|
|
19766
20319
|
});
|
|
19767
|
-
|
|
20320
|
+
(0, import_react21.useEffect)(() => {
|
|
20321
|
+
onBreadcrumbsChange?.(breadcrumbs);
|
|
20322
|
+
}, [breadcrumbs, onBreadcrumbsChange]);
|
|
20323
|
+
const theme = (0, import_react21.useMemo)(() => {
|
|
19768
20324
|
const registry = { ...themes, ...customThemes };
|
|
19769
20325
|
const resolveByName = (name) => name && registry[name] ? registry[name] : null;
|
|
19770
20326
|
if (themeProp) {
|
|
@@ -19775,22 +20331,22 @@ var SystemCanvas = (() => {
|
|
|
19775
20331
|
}
|
|
19776
20332
|
return resolveByName(currentCanvas.theme?.base) ?? resolveByName(canvas.theme?.base) ?? darkTheme;
|
|
19777
20333
|
}, [themeProp, customThemes, currentCanvas.theme?.base, canvas.theme?.base]);
|
|
19778
|
-
const { nodes, edges, nodeMap } = (0,
|
|
20334
|
+
const { nodes, edges, nodeMap } = (0, import_react21.useMemo)(() => {
|
|
19779
20335
|
const resolved = resolveCanvas(currentCanvas, theme);
|
|
19780
20336
|
const map = buildNodeMap(resolved.nodes);
|
|
19781
20337
|
return { nodes: resolved.nodes, edges: resolved.edges, nodeMap: map };
|
|
19782
20338
|
}, [currentCanvas, theme]);
|
|
19783
|
-
const nodesRef = (0,
|
|
20339
|
+
const nodesRef = (0, import_react21.useRef)(nodes);
|
|
19784
20340
|
nodesRef.current = nodes;
|
|
19785
|
-
const viewportStateRef = (0,
|
|
19786
|
-
const viewportHandleRef = (0,
|
|
19787
|
-
const navigateToRefRef = (0,
|
|
20341
|
+
const viewportStateRef = (0, import_react21.useRef)(defaultViewport ?? { x: 0, y: 0, zoom: 1 });
|
|
20342
|
+
const viewportHandleRef = (0, import_react21.useRef)(null);
|
|
20343
|
+
const navigateToRefRef = (0, import_react21.useRef)(navigateToRef);
|
|
19788
20344
|
navigateToRefRef.current = navigateToRef;
|
|
19789
|
-
const navigateToBreadcrumbRef = (0,
|
|
20345
|
+
const navigateToBreadcrumbRef = (0, import_react21.useRef)(navigateToBreadcrumb);
|
|
19790
20346
|
navigateToBreadcrumbRef.current = navigateToBreadcrumb;
|
|
19791
|
-
const breadcrumbsRef = (0,
|
|
20347
|
+
const breadcrumbsRef = (0, import_react21.useRef)(breadcrumbs);
|
|
19792
20348
|
breadcrumbsRef.current = breadcrumbs;
|
|
19793
|
-
(0,
|
|
20349
|
+
(0, import_react21.useImperativeHandle)(forwardedRef, () => ({
|
|
19794
20350
|
zoomIntoNode: (nodeId, options) => {
|
|
19795
20351
|
return new Promise((resolve) => {
|
|
19796
20352
|
const node = nodesRef.current.find((n) => n.id === nodeId);
|
|
@@ -19822,19 +20378,51 @@ var SystemCanvas = (() => {
|
|
|
19822
20378
|
navigateToBreadcrumbRef.current(0);
|
|
19823
20379
|
}
|
|
19824
20380
|
}), [forwardedRef]);
|
|
19825
|
-
const [selectedId, setSelectedId] = (0,
|
|
19826
|
-
const [editingId, setEditingId] = (0,
|
|
19827
|
-
const [selectedEdgeId, setSelectedEdgeId] = (0,
|
|
19828
|
-
const [editingEdgeId, setEditingEdgeId] = (0,
|
|
19829
|
-
(0,
|
|
20381
|
+
const [selectedId, setSelectedId] = (0, import_react21.useState)(null);
|
|
20382
|
+
const [editingId, setEditingId] = (0, import_react21.useState)(null);
|
|
20383
|
+
const [selectedEdgeId, setSelectedEdgeId] = (0, import_react21.useState)(null);
|
|
20384
|
+
const [editingEdgeId, setEditingEdgeId] = (0, import_react21.useState)(null);
|
|
20385
|
+
(0, import_react21.useEffect)(() => {
|
|
19830
20386
|
setSelectedId(null);
|
|
19831
20387
|
setEditingId(null);
|
|
19832
20388
|
setSelectedEdgeId(null);
|
|
19833
20389
|
setEditingEdgeId(null);
|
|
19834
20390
|
}, [currentCanvasRef]);
|
|
19835
|
-
const
|
|
19836
|
-
|
|
19837
|
-
|
|
20391
|
+
const onSelectionChangeRef = (0, import_react21.useRef)(onSelectionChange);
|
|
20392
|
+
(0, import_react21.useEffect)(() => {
|
|
20393
|
+
onSelectionChangeRef.current = onSelectionChange;
|
|
20394
|
+
}, [onSelectionChange]);
|
|
20395
|
+
const lastEmittedSelectionRef = (0, import_react21.useRef)({ kind: null, id: null, canvasRef: void 0 });
|
|
20396
|
+
(0, import_react21.useEffect)(() => {
|
|
20397
|
+
const cb = onSelectionChangeRef.current;
|
|
20398
|
+
let next = null;
|
|
20399
|
+
if (selectedId) {
|
|
20400
|
+
const node = nodeMap.get(selectedId);
|
|
20401
|
+
if (node)
|
|
20402
|
+
next = { kind: "node", node, canvasRef: currentCanvasRef };
|
|
20403
|
+
}
|
|
20404
|
+
if (!next && selectedEdgeId) {
|
|
20405
|
+
const edge = edges.find((e) => e.id === selectedEdgeId);
|
|
20406
|
+
if (edge)
|
|
20407
|
+
next = { kind: "edge", edge, canvasRef: currentCanvasRef };
|
|
20408
|
+
}
|
|
20409
|
+
const last = lastEmittedSelectionRef.current;
|
|
20410
|
+
const nextKind = next?.kind ?? null;
|
|
20411
|
+
const nextId = next ? next.kind === "node" ? next.node.id : next.edge.id : null;
|
|
20412
|
+
const nextRef = next?.canvasRef;
|
|
20413
|
+
if (last.kind === nextKind && last.id === nextId && last.canvasRef === nextRef) {
|
|
20414
|
+
return;
|
|
20415
|
+
}
|
|
20416
|
+
lastEmittedSelectionRef.current = {
|
|
20417
|
+
kind: nextKind,
|
|
20418
|
+
id: nextId,
|
|
20419
|
+
canvasRef: nextRef
|
|
20420
|
+
};
|
|
20421
|
+
cb?.(next);
|
|
20422
|
+
}, [selectedId, selectedEdgeId, currentCanvasRef, nodeMap, edges]);
|
|
20423
|
+
const containerRef = (0, import_react21.useRef)(null);
|
|
20424
|
+
const [containerSize, setContainerSize] = (0, import_react21.useState)({ width: 0, height: 0 });
|
|
20425
|
+
(0, import_react21.useEffect)(() => {
|
|
19838
20426
|
const el = containerRef.current;
|
|
19839
20427
|
if (!el)
|
|
19840
20428
|
return;
|
|
@@ -19849,42 +20437,67 @@ var SystemCanvas = (() => {
|
|
|
19849
20437
|
}, []);
|
|
19850
20438
|
const hasLanes = currentCanvas.columns && currentCanvas.columns.length > 0 || currentCanvas.rows && currentCanvas.rows.length > 0;
|
|
19851
20439
|
const showLaneHeaders = hasLanes && laneHeaders !== "none";
|
|
19852
|
-
const getViewportState = (0,
|
|
19853
|
-
const
|
|
20440
|
+
const getViewportState = (0, import_react21.useCallback)(() => viewportStateRef.current ?? { x: 0, y: 0, zoom: 1 }, []);
|
|
20441
|
+
const applyLaneSnap = (0, import_react21.useCallback)((id2, patch) => {
|
|
20442
|
+
if (!snapToLanes)
|
|
20443
|
+
return patch;
|
|
20444
|
+
const cols = currentCanvas.columns;
|
|
20445
|
+
const rows = currentCanvas.rows;
|
|
20446
|
+
const node = nodesRef.current.find((n) => n.id === id2);
|
|
19854
20447
|
let final = patch;
|
|
19855
|
-
|
|
19856
|
-
|
|
19857
|
-
|
|
19858
|
-
const
|
|
19859
|
-
|
|
19860
|
-
|
|
19861
|
-
|
|
19862
|
-
|
|
19863
|
-
|
|
19864
|
-
|
|
19865
|
-
|
|
19866
|
-
|
|
19867
|
-
|
|
19868
|
-
|
|
19869
|
-
|
|
19870
|
-
|
|
19871
|
-
|
|
19872
|
-
|
|
19873
|
-
|
|
19874
|
-
|
|
20448
|
+
const nx = patch.x;
|
|
20449
|
+
const ny = patch.y;
|
|
20450
|
+
if (cols && cols.length > 0 && nx != null) {
|
|
20451
|
+
const snapped = snapToLane(nx, cols, {
|
|
20452
|
+
edge: "center",
|
|
20453
|
+
size: node?.width ?? 0
|
|
20454
|
+
});
|
|
20455
|
+
final = { ...final, x: Math.round(snapped) };
|
|
20456
|
+
}
|
|
20457
|
+
if (rows && rows.length > 0 && ny != null) {
|
|
20458
|
+
const snapped = snapToLane(ny, rows, {
|
|
20459
|
+
edge: "center",
|
|
20460
|
+
size: node?.height ?? 0
|
|
20461
|
+
});
|
|
20462
|
+
final = { ...final, y: Math.round(snapped) };
|
|
20463
|
+
}
|
|
20464
|
+
return final;
|
|
20465
|
+
}, [snapToLanes, currentCanvas.columns, currentCanvas.rows]);
|
|
20466
|
+
const commitResize = (0, import_react21.useCallback)((id2, patch) => {
|
|
20467
|
+
onNodeUpdate?.(id2, applyLaneSnap(id2, patch), currentCanvasRef);
|
|
20468
|
+
}, [onNodeUpdate, currentCanvasRef, applyLaneSnap]);
|
|
20469
|
+
const commitDragBatch = (0, import_react21.useCallback)((updates) => {
|
|
20470
|
+
const final = updates.map((u) => ({
|
|
20471
|
+
id: u.id,
|
|
20472
|
+
patch: applyLaneSnap(u.id, u.patch)
|
|
20473
|
+
}));
|
|
20474
|
+
if (onNodesUpdate) {
|
|
20475
|
+
onNodesUpdate(final, currentCanvasRef);
|
|
20476
|
+
return;
|
|
19875
20477
|
}
|
|
19876
|
-
onNodeUpdate
|
|
19877
|
-
|
|
19878
|
-
|
|
20478
|
+
if (!onNodeUpdate)
|
|
20479
|
+
return;
|
|
20480
|
+
for (const { id: id2, patch } of final) {
|
|
20481
|
+
onNodeUpdate(id2, patch, currentCanvasRef);
|
|
20482
|
+
}
|
|
20483
|
+
}, [onNodeUpdate, onNodesUpdate, currentCanvasRef, applyLaneSnap]);
|
|
20484
|
+
const svgProxyRef = (0, import_react21.useRef)(null);
|
|
20485
|
+
const handleNodeDrop = (0, import_react21.useCallback)((sources, target) => {
|
|
20486
|
+
onNodeDrop?.(sources, target, { canvasRef: currentCanvasRef });
|
|
20487
|
+
}, [onNodeDrop, currentCanvasRef]);
|
|
20488
|
+
const { dragOverrides, dropTargetId, onPointerDown: onNodePointerDown } = useNodeDrag({
|
|
19879
20489
|
viewport: viewportStateRef,
|
|
19880
20490
|
nodesRef,
|
|
19881
|
-
onCommit:
|
|
20491
|
+
onCommit: commitDragBatch,
|
|
20492
|
+
svgRef: svgProxyRef,
|
|
20493
|
+
canDropNodeOn,
|
|
20494
|
+
onNodeDrop: handleNodeDrop
|
|
19882
20495
|
});
|
|
19883
20496
|
const { resizeOverrides, onHandlePointerDown: onResizeHandlePointerDown } = useNodeResize({
|
|
19884
20497
|
viewport: viewportStateRef,
|
|
19885
|
-
onCommit:
|
|
20498
|
+
onCommit: commitResize
|
|
19886
20499
|
});
|
|
19887
|
-
const selectedResolvedNode = (0,
|
|
20500
|
+
const selectedResolvedNode = (0, import_react21.useMemo)(() => {
|
|
19888
20501
|
if (!selectedId)
|
|
19889
20502
|
return null;
|
|
19890
20503
|
const base = nodeMap.get(selectedId);
|
|
@@ -19900,9 +20513,8 @@ var SystemCanvas = (() => {
|
|
|
19900
20513
|
}
|
|
19901
20514
|
return base;
|
|
19902
20515
|
}, [selectedId, nodeMap, dragOverrides, resizeOverrides]);
|
|
19903
|
-
const svgProxyRef = (0, import_react20.useRef)(null);
|
|
19904
20516
|
svgProxyRef.current = viewportHandleRef.current?.getSvgElement() ?? null;
|
|
19905
|
-
const handleEdgeCreated = (0,
|
|
20517
|
+
const handleEdgeCreated = (0, import_react21.useCallback)((edge) => {
|
|
19906
20518
|
onEdgeAdd?.(edge, currentCanvasRef);
|
|
19907
20519
|
}, [onEdgeAdd, currentCanvasRef]);
|
|
19908
20520
|
const { pending: pendingEdge, onHandlePointerDown: onConnectionHandlePointerDown } = useEdgeCreate({
|
|
@@ -19911,7 +20523,7 @@ var SystemCanvas = (() => {
|
|
|
19911
20523
|
nodesRef,
|
|
19912
20524
|
onCreate: handleEdgeCreated
|
|
19913
20525
|
});
|
|
19914
|
-
const handleNavigableNodeClick = (0,
|
|
20526
|
+
const handleNavigableNodeClick = (0, import_react21.useCallback)((node) => {
|
|
19915
20527
|
const frame2 = {
|
|
19916
20528
|
parentCanvasRef: currentCanvasRef,
|
|
19917
20529
|
parentNodeRect: {
|
|
@@ -19938,7 +20550,7 @@ var SystemCanvas = (() => {
|
|
|
19938
20550
|
navigateToRef(node);
|
|
19939
20551
|
}
|
|
19940
20552
|
}, [navigateToRef, currentCanvasRef, zoomNavConfig.enabled]);
|
|
19941
|
-
const handleZoomEnter = (0,
|
|
20553
|
+
const handleZoomEnter = (0, import_react21.useCallback)((node, targetTransform) => {
|
|
19942
20554
|
const frame2 = {
|
|
19943
20555
|
parentCanvasRef: currentCanvasRef,
|
|
19944
20556
|
parentNodeRect: {
|
|
@@ -19952,7 +20564,7 @@ var SystemCanvas = (() => {
|
|
|
19952
20564
|
setPendingHandoff(targetTransform);
|
|
19953
20565
|
navigateToRef(node);
|
|
19954
20566
|
}, [currentCanvasRef, navigateToRef]);
|
|
19955
|
-
const handleZoomExit = (0,
|
|
20567
|
+
const handleZoomExit = (0, import_react21.useCallback)((targetTransform) => {
|
|
19956
20568
|
setPendingHandoff(targetTransform);
|
|
19957
20569
|
suppressNextHandoffClearRef.current = true;
|
|
19958
20570
|
navigateToBreadcrumb(breadcrumbs.length - 2);
|
|
@@ -19975,30 +20587,58 @@ var SystemCanvas = (() => {
|
|
|
19975
20587
|
const rect = svg.getBoundingClientRect();
|
|
19976
20588
|
return { width: rect.width, height: rect.height };
|
|
19977
20589
|
},
|
|
20590
|
+
getCursorScreenPos: () => viewportHandleRef.current?.getCursorScreenPos() ?? null,
|
|
19978
20591
|
onEnter: handleZoomEnter,
|
|
19979
20592
|
onExit: handleZoomExit
|
|
19980
20593
|
});
|
|
19981
|
-
const handleViewportChange = (0,
|
|
20594
|
+
const handleViewportChange = (0, import_react21.useCallback)((vp) => {
|
|
19982
20595
|
viewportStateRef.current = vp;
|
|
19983
20596
|
handleZoomNavViewportChange(vp);
|
|
19984
20597
|
onViewportChange?.(vp);
|
|
19985
20598
|
}, [handleZoomNavViewportChange, onViewportChange]);
|
|
19986
|
-
const handleHandoffApplied = (0,
|
|
20599
|
+
const handleHandoffApplied = (0, import_react21.useCallback)(() => {
|
|
19987
20600
|
setPendingHandoff(null);
|
|
19988
20601
|
clearZoomNavCommitting();
|
|
19989
20602
|
}, [clearZoomNavCommitting]);
|
|
19990
|
-
const handleBeginEdit = (0,
|
|
20603
|
+
const handleBeginEdit = (0, import_react21.useCallback)((node) => {
|
|
19991
20604
|
setEditingId(node.id);
|
|
19992
20605
|
}, []);
|
|
19993
|
-
const handleBeginEditEdge = (0,
|
|
20606
|
+
const handleBeginEditEdge = (0, import_react21.useCallback)((edge) => {
|
|
19994
20607
|
setEditingEdgeId(edge.id);
|
|
19995
20608
|
}, []);
|
|
20609
|
+
const [contextMenuState, setContextMenuState] = (0, import_react21.useState)(null);
|
|
20610
|
+
(0, import_react21.useEffect)(() => {
|
|
20611
|
+
setContextMenuState(null);
|
|
20612
|
+
}, [currentCanvasRef]);
|
|
20613
|
+
const handleContextMenu = (0, import_react21.useCallback)((event) => {
|
|
20614
|
+
onContextMenu?.(event);
|
|
20615
|
+
if (!nodeContextMenu)
|
|
20616
|
+
return;
|
|
20617
|
+
if (event.type !== "node")
|
|
20618
|
+
return;
|
|
20619
|
+
const node = event.target;
|
|
20620
|
+
if (!node)
|
|
20621
|
+
return;
|
|
20622
|
+
const matched = filterContextMenuItems(nodeContextMenu.items, node, {
|
|
20623
|
+
canvasRef: currentCanvasRef ?? null
|
|
20624
|
+
});
|
|
20625
|
+
if (matched.length === 0) {
|
|
20626
|
+
setContextMenuState(null);
|
|
20627
|
+
return;
|
|
20628
|
+
}
|
|
20629
|
+
setContextMenuState({
|
|
20630
|
+
items: matched,
|
|
20631
|
+
node,
|
|
20632
|
+
screenPosition: event.screenPosition,
|
|
20633
|
+
canvasRef: currentCanvasRef ?? null
|
|
20634
|
+
});
|
|
20635
|
+
}, [onContextMenu, nodeContextMenu, currentCanvasRef]);
|
|
19996
20636
|
const { handleNodeClick, handleNodeDoubleClick, handleNodeNavigate, handleEdgeClick, handleEdgeDoubleClick, handleCanvasClick, handleCanvasContextMenu, handleNodeContextMenu, handleEdgeContextMenu } = useCanvasInteraction({
|
|
19997
20637
|
onNodeClick,
|
|
19998
20638
|
onNodeDoubleClick,
|
|
19999
20639
|
onEdgeClick,
|
|
20000
20640
|
onEdgeDoubleClick,
|
|
20001
|
-
onContextMenu,
|
|
20641
|
+
onContextMenu: handleContextMenu,
|
|
20002
20642
|
onNavigableNodeClick: handleNavigableNodeClick,
|
|
20003
20643
|
viewport: viewportStateRef,
|
|
20004
20644
|
editable,
|
|
@@ -20007,27 +20647,27 @@ var SystemCanvas = (() => {
|
|
|
20007
20647
|
onSelectEdge: setSelectedEdgeId,
|
|
20008
20648
|
onBeginEditEdge: handleBeginEditEdge
|
|
20009
20649
|
});
|
|
20010
|
-
const handleEditorCommit = (0,
|
|
20650
|
+
const handleEditorCommit = (0, import_react21.useCallback)((patch) => {
|
|
20011
20651
|
if (editingId) {
|
|
20012
20652
|
onNodeUpdate?.(editingId, patch, currentCanvasRef);
|
|
20013
20653
|
}
|
|
20014
20654
|
setEditingId(null);
|
|
20015
20655
|
}, [editingId, onNodeUpdate, currentCanvasRef]);
|
|
20016
|
-
const handleEditorCancel = (0,
|
|
20656
|
+
const handleEditorCancel = (0, import_react21.useCallback)(() => {
|
|
20017
20657
|
setEditingId(null);
|
|
20018
20658
|
}, []);
|
|
20019
|
-
const handleEdgeEditorCommit = (0,
|
|
20659
|
+
const handleEdgeEditorCommit = (0, import_react21.useCallback)((patch) => {
|
|
20020
20660
|
if (editingEdgeId) {
|
|
20021
20661
|
onEdgeUpdate?.(editingEdgeId, patch, currentCanvasRef);
|
|
20022
20662
|
}
|
|
20023
20663
|
setEditingEdgeId(null);
|
|
20024
20664
|
}, [editingEdgeId, onEdgeUpdate, currentCanvasRef]);
|
|
20025
|
-
const handleEdgeEditorCancel = (0,
|
|
20665
|
+
const handleEdgeEditorCancel = (0, import_react21.useCallback)(() => {
|
|
20026
20666
|
setEditingEdgeId(null);
|
|
20027
20667
|
}, []);
|
|
20028
|
-
const lastAddRef = (0,
|
|
20029
|
-
const menuOptions = (0,
|
|
20030
|
-
const addNode2 = (0,
|
|
20668
|
+
const lastAddRef = (0, import_react21.useRef)(null);
|
|
20669
|
+
const menuOptions = (0, import_react21.useMemo)(() => getNodeMenuOptions(currentCanvas, theme), [currentCanvas, theme]);
|
|
20670
|
+
const addNode2 = (0, import_react21.useCallback)((option, position) => {
|
|
20031
20671
|
let x, y;
|
|
20032
20672
|
if (position) {
|
|
20033
20673
|
x = position.x;
|
|
@@ -20059,7 +20699,7 @@ var SystemCanvas = (() => {
|
|
|
20059
20699
|
const node = createNodeFromOption(option, Math.round(x), Math.round(y), void 0, theme);
|
|
20060
20700
|
onNodeAdd?.(node, currentCanvasRef);
|
|
20061
20701
|
}, [onNodeAdd, currentCanvasRef, theme]);
|
|
20062
|
-
const handleKeyDown = (0,
|
|
20702
|
+
const handleKeyDown = (0, import_react21.useCallback)((e) => {
|
|
20063
20703
|
if (!editable)
|
|
20064
20704
|
return;
|
|
20065
20705
|
if (e.key === "Escape") {
|
|
@@ -20093,14 +20733,14 @@ var SystemCanvas = (() => {
|
|
|
20093
20733
|
currentCanvasRef
|
|
20094
20734
|
]);
|
|
20095
20735
|
const renderProps = { options: menuOptions, addNode: addNode2, theme };
|
|
20096
|
-
return (0,
|
|
20736
|
+
return (0, import_jsx_runtime28.jsxs)("div", { ref: containerRef, className: `system-canvas ${className ?? ""}`, tabIndex: editable ? 0 : -1, onKeyDown: handleKeyDown, style: {
|
|
20097
20737
|
position: "relative",
|
|
20098
20738
|
width: "100%",
|
|
20099
20739
|
height: "100%",
|
|
20100
20740
|
overflow: "hidden",
|
|
20101
20741
|
outline: "none",
|
|
20102
20742
|
...style
|
|
20103
|
-
}, children: [(0,
|
|
20743
|
+
}, 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: {
|
|
20104
20744
|
position: "absolute",
|
|
20105
20745
|
top: 12,
|
|
20106
20746
|
right: 12,
|
|
@@ -20112,12 +20752,12 @@ var SystemCanvas = (() => {
|
|
|
20112
20752
|
fontFamily: theme.node.fontFamily,
|
|
20113
20753
|
fontSize: 12,
|
|
20114
20754
|
backdropFilter: "blur(8px)"
|
|
20115
|
-
}, children: "Loading..." }), (0,
|
|
20755
|
+
}, 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) => {
|
|
20116
20756
|
onNodeUpdate?.(selectedResolvedNode.id, update, currentCanvasRef);
|
|
20117
20757
|
}, onDelete: () => {
|
|
20118
20758
|
onNodeDelete?.(selectedResolvedNode.id, currentCanvasRef);
|
|
20119
20759
|
setSelectedId(null);
|
|
20120
|
-
}, getViewport: getViewportState, containerWidth: containerSize.width, containerHeight: containerSize.height, render: renderNodeToolbar }), editable && (renderAddNodeButton ? renderAddNodeButton(renderProps) : (0,
|
|
20760
|
+
}, 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) })] });
|
|
20121
20761
|
});
|
|
20122
20762
|
|
|
20123
20763
|
// src/index.tsx
|
|
@@ -20228,7 +20868,7 @@ var SystemCanvas = (() => {
|
|
|
20228
20868
|
onEdgeUpdate: handleEdgeUpdate,
|
|
20229
20869
|
onEdgeDelete: handleEdgeDelete
|
|
20230
20870
|
};
|
|
20231
|
-
root2.render(
|
|
20871
|
+
root2.render(import_react22.default.createElement(SystemCanvas, props));
|
|
20232
20872
|
};
|
|
20233
20873
|
doRender();
|
|
20234
20874
|
return {
|