@ai-matrx/canvas 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +17 -2
- package/dist/index.cjs +76 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.js +76 -7
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +441 -199
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +77 -44
- package/dist/react.d.ts +77 -44
- package/dist/react.js +396 -153
- package/dist/react.js.map +1 -1
- package/dist/styles.css +88 -37
- package/dist/{toggleKind-DhDmWExm.d.cts → toggleKind-CAI7pndj.d.cts} +21 -2
- package/dist/{toggleKind-DhDmWExm.d.ts → toggleKind-CAI7pndj.d.ts} +21 -2
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -34,6 +34,8 @@ var react_exports = {};
|
|
|
34
34
|
__export(react_exports, {
|
|
35
35
|
BrowserBar: () => BrowserBar,
|
|
36
36
|
BrowserTabs: () => BrowserTabs,
|
|
37
|
+
CANVAS_ACTIVE_TAB_MIN_WIDTH: () => CANVAS_ACTIVE_TAB_MIN_WIDTH,
|
|
38
|
+
CANVAS_TAB_MIN_WIDTH: () => CANVAS_TAB_MIN_WIDTH,
|
|
37
39
|
CanvasColumn: () => CanvasColumn,
|
|
38
40
|
CanvasFrame: () => CanvasFrame,
|
|
39
41
|
CanvasHeaderButton: () => CanvasHeaderButton,
|
|
@@ -46,8 +48,10 @@ __export(react_exports, {
|
|
|
46
48
|
CanvasTab: () => CanvasTab,
|
|
47
49
|
CanvasToggle: () => CanvasToggle,
|
|
48
50
|
CanvasWindowScope: () => CanvasWindowScope,
|
|
51
|
+
beginCanvasResize: () => beginCanvasResize,
|
|
49
52
|
canvasSessionKey: () => canvasSessionKey,
|
|
50
53
|
defineCanvasKind: () => defineCanvasKind,
|
|
54
|
+
fitCanvasTabs: () => fitCanvasTabs,
|
|
51
55
|
getCanvasKind: () => getCanvasKind,
|
|
52
56
|
itemTitle: () => itemTitle,
|
|
53
57
|
listCanvasKinds: () => listCanvasKinds,
|
|
@@ -62,6 +66,7 @@ __export(react_exports, {
|
|
|
62
66
|
useCanvasKinds: () => useCanvasKinds,
|
|
63
67
|
useCanvasLauncherEntries: () => useCanvasLauncherEntries,
|
|
64
68
|
useCanvasLauncherEntry: () => useCanvasLauncherEntry,
|
|
69
|
+
useCanvasMenuItems: () => useCanvasMenuItems,
|
|
65
70
|
useCanvasNativeBodies: () => useCanvasNativeBodies,
|
|
66
71
|
useCanvasPresentation: () => useCanvasPresentation,
|
|
67
72
|
useCanvasState: () => useCanvasState,
|
|
@@ -72,7 +77,46 @@ __export(react_exports, {
|
|
|
72
77
|
module.exports = __toCommonJS(react_exports);
|
|
73
78
|
|
|
74
79
|
// src/react/provider.tsx
|
|
75
|
-
var
|
|
80
|
+
var import_react3 = require("react");
|
|
81
|
+
|
|
82
|
+
// src/react/menuItems.ts
|
|
83
|
+
var import_react = require("react");
|
|
84
|
+
var useIsoLayoutEffect = typeof window === "undefined" ? import_react.useEffect : import_react.useLayoutEffect;
|
|
85
|
+
function createCanvasItemMenus() {
|
|
86
|
+
const sources = /* @__PURE__ */ new Map();
|
|
87
|
+
return {
|
|
88
|
+
register(itemId, read) {
|
|
89
|
+
let set = sources.get(itemId);
|
|
90
|
+
if (!set) sources.set(itemId, set = /* @__PURE__ */ new Set());
|
|
91
|
+
set.add(read);
|
|
92
|
+
return () => {
|
|
93
|
+
const current = sources.get(itemId);
|
|
94
|
+
current?.delete(read);
|
|
95
|
+
if (current && current.size === 0) sources.delete(itemId);
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
read(itemId) {
|
|
99
|
+
const out = [];
|
|
100
|
+
for (const read of sources.get(itemId) ?? []) {
|
|
101
|
+
try {
|
|
102
|
+
out.push(...read());
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("[@ai-matrx/canvas] a body's menu entries threw", error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function useCanvasMenuItems(itemId, items) {
|
|
112
|
+
const { itemMenus } = useCanvasInternals();
|
|
113
|
+
const latest = (0, import_react.useRef)(items);
|
|
114
|
+
latest.current = items;
|
|
115
|
+
useIsoLayoutEffect(() => {
|
|
116
|
+
if (!itemId) return void 0;
|
|
117
|
+
return itemMenus.register(itemId, () => latest.current);
|
|
118
|
+
}, [itemMenus, itemId]);
|
|
119
|
+
}
|
|
76
120
|
|
|
77
121
|
// src/core/types.ts
|
|
78
122
|
var CANVAS_MAIN_WINDOW = "main";
|
|
@@ -241,6 +285,8 @@ var canvasActions = {
|
|
|
241
285
|
navigate: (itemId, to) => ({ type: `${P}navigate`, payload: { itemId, to, now: Date.now() } }),
|
|
242
286
|
/** Returns a tab to what it showed before its last navigate. */
|
|
243
287
|
back: (itemId) => ({ type: `${P}back`, payload: { itemId, now: Date.now() } }),
|
|
288
|
+
/** Re-does the last Back (the step Back left), with that step's live body. */
|
|
289
|
+
forward: (itemId) => ({ type: `${P}forward`, payload: { itemId, now: Date.now() } }),
|
|
244
290
|
closeItem: (itemId) => ({ type: `${P}closeItem`, payload: { itemId } }),
|
|
245
291
|
closeOthers: (itemId) => ({ type: `${P}closeOthers`, payload: { itemId } }),
|
|
246
292
|
activate: (itemId) => ({ type: `${P}activate`, payload: { itemId } }),
|
|
@@ -441,6 +487,7 @@ function newItem(kind, key, title, data, now, steps) {
|
|
|
441
487
|
const id = canvasItemId(kind, key);
|
|
442
488
|
const history = steps?.history ?? [];
|
|
443
489
|
const kept = steps?.kept ?? [];
|
|
490
|
+
const forward = steps?.forward ?? [];
|
|
444
491
|
return {
|
|
445
492
|
id,
|
|
446
493
|
kind,
|
|
@@ -452,7 +499,8 @@ function newItem(kind, key, title, data, now, steps) {
|
|
|
452
499
|
// A reused instance is the SAME live body coming back (Back, or returning to a kept step).
|
|
453
500
|
instance: steps?.instance ?? `${now.toString(36)}:${id}`,
|
|
454
501
|
...history.length > 0 ? { history: history.slice(-CANVAS_HISTORY_LIMIT) } : {},
|
|
455
|
-
...kept.length > 0 ? { kept: kept.slice(-CANVAS_KEEP_ALIVE_DEPTH) } : {}
|
|
502
|
+
...kept.length > 0 ? { kept: kept.slice(-CANVAS_KEEP_ALIVE_DEPTH) } : {},
|
|
503
|
+
...forward.length > 0 ? { forward: forward.slice(-CANVAS_HISTORY_LIMIT) } : {}
|
|
456
504
|
};
|
|
457
505
|
}
|
|
458
506
|
function historyEntry(item) {
|
|
@@ -498,12 +546,14 @@ function sanitizeHistory(raw) {
|
|
|
498
546
|
function sanitizeItem(item) {
|
|
499
547
|
const history = sanitizeHistory(item.history);
|
|
500
548
|
const kept = sanitizeHistory(item.kept).slice(-CANVAS_KEEP_ALIVE_DEPTH);
|
|
501
|
-
const
|
|
549
|
+
const forward = sanitizeHistory(item.forward);
|
|
550
|
+
const { history: _history, kept: _kept, forward: _forward, instance, ...rest } = item;
|
|
502
551
|
return {
|
|
503
552
|
...rest,
|
|
504
553
|
...typeof instance === "string" && instance ? { instance } : {},
|
|
505
554
|
...history.length > 0 ? { history } : {},
|
|
506
|
-
...kept.length > 0 ? { kept } : {}
|
|
555
|
+
...kept.length > 0 ? { kept } : {},
|
|
556
|
+
...forward.length > 0 ? { forward } : {}
|
|
507
557
|
};
|
|
508
558
|
}
|
|
509
559
|
function clampWidth(width) {
|
|
@@ -694,6 +744,9 @@ function canvasReducer(state = createInitialCanvasState(), action) {
|
|
|
694
744
|
const keptIndex = keptAll.findIndex((entry) => canvasItemId(entry.kind, entry.key) === targetId);
|
|
695
745
|
const revived = keptIndex >= 0 ? keptAll[keptIndex] : void 0;
|
|
696
746
|
const kept = keptAll.filter((_, i) => i !== keptIndex);
|
|
747
|
+
const forwardAll = current.forward ?? [];
|
|
748
|
+
const nextForward = forwardAll[forwardAll.length - 1];
|
|
749
|
+
const forward = nextForward && canvasItemId(nextForward.kind, nextForward.key) === targetId ? forwardAll.slice(0, -1) : [];
|
|
697
750
|
return replaceInPlace(
|
|
698
751
|
state,
|
|
699
752
|
current,
|
|
@@ -703,7 +756,7 @@ function canvasReducer(state = createInitialCanvasState(), action) {
|
|
|
703
756
|
to.title !== void 0 ? to.title : revived?.title ?? null,
|
|
704
757
|
to.data !== void 0 ? to.data : revived?.data ?? null,
|
|
705
758
|
now,
|
|
706
|
-
{ history, kept, instance: revived?.instance }
|
|
759
|
+
{ history, kept, forward, instance: revived?.instance }
|
|
707
760
|
)
|
|
708
761
|
);
|
|
709
762
|
}
|
|
@@ -719,10 +772,36 @@ function canvasReducer(state = createInitialCanvasState(), action) {
|
|
|
719
772
|
return focusExisting(canvasReducer(state, canvasActions.closeItem(itemId)), targetId);
|
|
720
773
|
}
|
|
721
774
|
const kept = [...(current.kept ?? []).filter((k) => canvasItemId(k.kind, k.key) !== itemId), historyEntry(current)];
|
|
775
|
+
const forward = [...current.forward ?? [], historyEntry(current)];
|
|
722
776
|
return replaceInPlace(
|
|
723
777
|
state,
|
|
724
778
|
current,
|
|
725
|
-
newItem(entry.kind, entry.key, entry.title, entry.data, now, { history: history.slice(0, -1), kept, instance: entry.instance })
|
|
779
|
+
newItem(entry.kind, entry.key, entry.title, entry.data, now, { history: history.slice(0, -1), kept, forward, instance: entry.instance })
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
case `${P}forward`: {
|
|
783
|
+
const { itemId, now } = action.payload;
|
|
784
|
+
const current = state.items[itemId];
|
|
785
|
+
const forwardAll = current?.forward ?? [];
|
|
786
|
+
const entry = forwardAll[forwardAll.length - 1];
|
|
787
|
+
if (!current || !entry || !paneOf(state, itemId)) return state;
|
|
788
|
+
const targetId = canvasItemId(entry.kind, entry.key);
|
|
789
|
+
if (targetId === itemId) return state;
|
|
790
|
+
if (state.items[targetId]) {
|
|
791
|
+
return focusExisting(canvasReducer(state, canvasActions.closeItem(itemId)), targetId);
|
|
792
|
+
}
|
|
793
|
+
const keptAll = current.kept ?? [];
|
|
794
|
+
const revived = keptAll.find((k) => canvasItemId(k.kind, k.key) === targetId);
|
|
795
|
+
const kept = keptAll.filter((k) => canvasItemId(k.kind, k.key) !== targetId);
|
|
796
|
+
return replaceInPlace(
|
|
797
|
+
state,
|
|
798
|
+
current,
|
|
799
|
+
newItem(entry.kind, entry.key, entry.title, entry.data, now, {
|
|
800
|
+
history: [...current.history ?? [], historyEntry(current)],
|
|
801
|
+
kept,
|
|
802
|
+
forward: forwardAll.slice(0, -1),
|
|
803
|
+
instance: revived?.instance ?? entry.instance
|
|
804
|
+
})
|
|
726
805
|
);
|
|
727
806
|
}
|
|
728
807
|
case `${P}closeItem`: {
|
|
@@ -974,6 +1053,7 @@ function toPersistableSnapshot(state, isRestorable) {
|
|
|
974
1053
|
}
|
|
975
1054
|
|
|
976
1055
|
// src/core/rules.ts
|
|
1056
|
+
var CANVAS_PANE_MIN_WIDTH = 280;
|
|
977
1057
|
var CANVAS_WEB_LAYOUT_RULES = {
|
|
978
1058
|
defaultWidth: CANVAS_DEFAULT_WIDTH,
|
|
979
1059
|
minWidth: CANVAS_MIN_WIDTH,
|
|
@@ -981,7 +1061,9 @@ var CANVAS_WEB_LAYOUT_RULES = {
|
|
|
981
1061
|
// Split down 70/30 like the desktop: what opens below (notifications, a feed) is the smaller pane.
|
|
982
1062
|
stackSplit: 0.7,
|
|
983
1063
|
sideSplit: 0.5,
|
|
984
|
-
|
|
1064
|
+
// A pane narrower than this cannot show a header (Back, a readable tab, "+", the menu, close) and a
|
|
1065
|
+
// body side by side with another: a split right that would go under it stacks instead.
|
|
1066
|
+
paneMinWidth: CANVAS_PANE_MIN_WIDTH
|
|
985
1067
|
};
|
|
986
1068
|
var clampFraction = (value, fallback) => Number.isFinite(value) ? Math.min(0.88, Math.max(0.12, value)) : fallback;
|
|
987
1069
|
function resolveCanvasLayoutRules(rules) {
|
|
@@ -1020,6 +1102,9 @@ var CANVAS_SHORTCUTS = [
|
|
|
1020
1102
|
{ id: "canvas.toggleFullscreen", accelerator: "CmdOrCtrl+Shift+Enter", when: "canvas-focus", label: "Expand canvas", web: true },
|
|
1021
1103
|
{ id: "canvas.splitRight", accelerator: "CmdOrCtrl+Alt+\\", when: "canvas-focus", label: "Split right", web: true },
|
|
1022
1104
|
{ id: "canvas.splitDown", accelerator: "CmdOrCtrl+Alt+Shift+\\", when: "canvas-focus", label: "Split down", web: true },
|
|
1105
|
+
// Browsers own ⌘[ / ⌘] for their own history: data for a desktop host (and the header's Back / Forward).
|
|
1106
|
+
{ id: "canvas.back", accelerator: "CmdOrCtrl+[", when: "canvas-focus", label: "Back", web: false },
|
|
1107
|
+
{ id: "canvas.forward", accelerator: "CmdOrCtrl+]", when: "canvas-focus", label: "Forward", web: false },
|
|
1023
1108
|
{ id: "canvas.closeTab", accelerator: "CmdOrCtrl+W", when: "canvas-focus", label: "Close tab", web: false },
|
|
1024
1109
|
{ id: "canvas.nextTab", accelerator: "Ctrl+Tab", when: "canvas-focus", label: "Next tab", web: false },
|
|
1025
1110
|
{ id: "canvas.previousTab", accelerator: "Ctrl+Shift+Tab", when: "canvas-focus", label: "Previous tab", web: false }
|
|
@@ -1069,11 +1154,17 @@ function runCanvasCommand(controller, id, windowId = controller.windowId) {
|
|
|
1069
1154
|
if (!frame2?.isOpen || !pane) return false;
|
|
1070
1155
|
controller.splitPane(pane.id, id === "canvas.splitRight" ? "horizontal" : "vertical", pane.itemIds.length > 1 ? pane.activeItemId ?? void 0 : void 0);
|
|
1071
1156
|
return true;
|
|
1157
|
+
case "canvas.back":
|
|
1158
|
+
if (!frame2?.isOpen || !pane?.activeItemId) return false;
|
|
1159
|
+
return controller.back(pane.activeItemId) !== null;
|
|
1160
|
+
case "canvas.forward":
|
|
1161
|
+
if (!frame2?.isOpen || !pane?.activeItemId) return false;
|
|
1162
|
+
return controller.forward(pane.activeItemId) !== null;
|
|
1072
1163
|
default:
|
|
1073
1164
|
return false;
|
|
1074
1165
|
}
|
|
1075
1166
|
}
|
|
1076
|
-
var CODE_FOR = { "\\": "Backslash", Tab: "Tab", Escape: "Escape", Enter: "Enter" };
|
|
1167
|
+
var CODE_FOR = { "\\": "Backslash", "[": "BracketLeft", "]": "BracketRight", Tab: "Tab", Escape: "Escape", Enter: "Enter" };
|
|
1077
1168
|
function matchesCanvasAccelerator(input, accelerator, isMac3) {
|
|
1078
1169
|
const parts = accelerator.split("+");
|
|
1079
1170
|
const key = parts.pop() ?? "";
|
|
@@ -1190,6 +1281,13 @@ function view(shared, windowId) {
|
|
|
1190
1281
|
dispatch(canvasActions.back(itemId));
|
|
1191
1282
|
return canvasItemId(entry.kind, entry.key);
|
|
1192
1283
|
},
|
|
1284
|
+
forward(itemId) {
|
|
1285
|
+
const forward = store.getState().items[itemId]?.forward ?? [];
|
|
1286
|
+
const entry = forward[forward.length - 1];
|
|
1287
|
+
if (!entry) return null;
|
|
1288
|
+
dispatch(canvasActions.forward(itemId));
|
|
1289
|
+
return canvasItemId(entry.kind, entry.key);
|
|
1290
|
+
},
|
|
1193
1291
|
newTab(paneId) {
|
|
1194
1292
|
const state = store.getState();
|
|
1195
1293
|
const frame2 = canvasWindowFrame(state, windowId);
|
|
@@ -1456,6 +1554,16 @@ function selectCanvasWindowItemCount(s, windowId) {
|
|
|
1456
1554
|
var NO_WINDOWS = Object.freeze({});
|
|
1457
1555
|
var NO_HISTORY = Object.freeze([]);
|
|
1458
1556
|
var selectCanvasCanGoBack = (s, itemId) => (s.items[itemId]?.history?.length ?? 0) > 0;
|
|
1557
|
+
var selectCanvasCanGoForward = (s, itemId) => (s.items[itemId]?.forward?.length ?? 0) > 0;
|
|
1558
|
+
function selectCanvasPresentedPaneId(s, windowId) {
|
|
1559
|
+
const f = frame(s, windowId);
|
|
1560
|
+
if (!f) return null;
|
|
1561
|
+
const ids = listPaneIds(f.layout);
|
|
1562
|
+
const holds = (id) => (s.panes[id]?.itemIds.length ?? 0) > 0;
|
|
1563
|
+
const focused = ids.find((id) => id === f.focusedPaneId);
|
|
1564
|
+
if (focused && holds(focused)) return focused;
|
|
1565
|
+
return ids.find(holds) ?? focused ?? ids[0] ?? null;
|
|
1566
|
+
}
|
|
1459
1567
|
|
|
1460
1568
|
// src/core/presentation.ts
|
|
1461
1569
|
var CANVAS_PHONE_MAX_WIDTH = 767;
|
|
@@ -1499,7 +1607,9 @@ function toggleKind(controller, input) {
|
|
|
1499
1607
|
const before = selectCanvasKindVisibility(controller.getState(), input.kind, key);
|
|
1500
1608
|
if (before === "visible") {
|
|
1501
1609
|
if ((input.whenVisible ?? "close") === "close") {
|
|
1610
|
+
const windowId = canvasWindowOfItem(controller.getState(), itemId);
|
|
1502
1611
|
controller.close(itemId);
|
|
1612
|
+
if (windowId && selectCanvasWindowItemCount(controller.getState(), windowId) === 0) controller.hide(windowId);
|
|
1503
1613
|
} else {
|
|
1504
1614
|
controller.hide(canvasWindowOfItem(controller.getState(), itemId) ?? void 0);
|
|
1505
1615
|
}
|
|
@@ -1521,7 +1631,7 @@ function toggleKind(controller, input) {
|
|
|
1521
1631
|
}
|
|
1522
1632
|
|
|
1523
1633
|
// src/react/layer.tsx
|
|
1524
|
-
var
|
|
1634
|
+
var import_react2 = require("react");
|
|
1525
1635
|
var import_react_dom = require("react-dom");
|
|
1526
1636
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1527
1637
|
function createCanvasLayer(getPorts) {
|
|
@@ -1588,9 +1698,9 @@ function createCanvasLayer(getPorts) {
|
|
|
1588
1698
|
};
|
|
1589
1699
|
}
|
|
1590
1700
|
function CanvasDomOverlay({ layer }) {
|
|
1591
|
-
const elements = (0,
|
|
1592
|
-
const [mounted, setMounted] = (0,
|
|
1593
|
-
(0,
|
|
1701
|
+
const elements = (0, import_react2.useSyncExternalStore)(layer.dom.subscribe, layer.dom.list, layer.dom.list);
|
|
1702
|
+
const [mounted, setMounted] = (0, import_react2.useState)(false);
|
|
1703
|
+
(0, import_react2.useEffect)(() => setMounted(true), []);
|
|
1594
1704
|
if (!mounted || elements.length === 0 || typeof document === "undefined") return null;
|
|
1595
1705
|
return (0, import_react_dom.createPortal)(
|
|
1596
1706
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mxc-overlay", "aria-hidden": "true", children: elements.map(([id, element]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FloatingView, { element }, id)) }),
|
|
@@ -1606,11 +1716,11 @@ function FloatingView({ element }) {
|
|
|
1606
1716
|
return null;
|
|
1607
1717
|
}
|
|
1608
1718
|
function Tooltip({ element }) {
|
|
1609
|
-
const ref = (0,
|
|
1719
|
+
const ref = (0, import_react2.useRef)(null);
|
|
1610
1720
|
const { anchor, side, text } = element;
|
|
1611
1721
|
const top = side === "bottom" ? anchor.y + anchor.height + 6 : anchor.y - 6;
|
|
1612
1722
|
const centre = anchor.x + anchor.width / 2;
|
|
1613
|
-
(0,
|
|
1723
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
1614
1724
|
const el = ref.current;
|
|
1615
1725
|
if (!el) return;
|
|
1616
1726
|
const width = el.offsetWidth;
|
|
@@ -1714,7 +1824,7 @@ function escapeBelongsElsewhere(event) {
|
|
|
1714
1824
|
const active = typeof document === "undefined" ? null : document.activeElement;
|
|
1715
1825
|
return !!active?.closest?.('[role="menu"], [role="dialog"], [role="alertdialog"], [role="listbox"]');
|
|
1716
1826
|
}
|
|
1717
|
-
var CanvasContext = (0,
|
|
1827
|
+
var CanvasContext = (0, import_react3.createContext)(null);
|
|
1718
1828
|
function sessionHooksFor(kindId) {
|
|
1719
1829
|
const kind = getCanvasKind(kindId);
|
|
1720
1830
|
if (!kind || kind.restore !== "session") return void 0;
|
|
@@ -1741,13 +1851,13 @@ function CanvasProvider({
|
|
|
1741
1851
|
overlay,
|
|
1742
1852
|
onNativeBodyFrame
|
|
1743
1853
|
}) {
|
|
1744
|
-
const hostPorts = (0,
|
|
1854
|
+
const hostPorts = (0, import_react3.useMemo)(
|
|
1745
1855
|
() => ({ itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame }),
|
|
1746
1856
|
[itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame]
|
|
1747
1857
|
);
|
|
1748
|
-
const portsRef = (0,
|
|
1858
|
+
const portsRef = (0, import_react3.useRef)(hostPorts);
|
|
1749
1859
|
portsRef.current = hostPorts;
|
|
1750
|
-
const [{ controller, layer, launcherEntries }] = (0,
|
|
1860
|
+
const [{ controller, layer, launcherEntries, itemMenus }] = (0, import_react3.useState)(() => ({
|
|
1751
1861
|
controller: createCanvasController({
|
|
1752
1862
|
store: store ?? createCanvasStore(),
|
|
1753
1863
|
persistence: persistence === void 0 ? createLocalStorageCanvasPersistence() : persistence,
|
|
@@ -1761,11 +1871,12 @@ function CanvasProvider({
|
|
|
1761
1871
|
preferredTarget: (kind) => getCanvasKind(kind)?.preferredTarget
|
|
1762
1872
|
}),
|
|
1763
1873
|
layer: createCanvasLayer(() => portsRef.current),
|
|
1764
|
-
launcherEntries: createLauncherEntryStore()
|
|
1874
|
+
launcherEntries: createLauncherEntryStore(),
|
|
1875
|
+
itemMenus: createCanvasItemMenus()
|
|
1765
1876
|
}));
|
|
1766
1877
|
const windowId = controller.windowId;
|
|
1767
|
-
(0,
|
|
1768
|
-
(0,
|
|
1878
|
+
(0, import_react3.useEffect)(() => controller.start(), [controller]);
|
|
1879
|
+
(0, import_react3.useEffect)(() => {
|
|
1769
1880
|
if (!hotkeys) return;
|
|
1770
1881
|
const isMac3 = isMacPlatform();
|
|
1771
1882
|
const applies = (when, event) => {
|
|
@@ -1786,9 +1897,9 @@ function CanvasProvider({
|
|
|
1786
1897
|
window.addEventListener("keydown", onKey);
|
|
1787
1898
|
return () => window.removeEventListener("keydown", onKey);
|
|
1788
1899
|
}, [controller, hotkeys, windowId]);
|
|
1789
|
-
const value = (0,
|
|
1790
|
-
() => ({ controller, windowId, ports: hostPorts, layer, regionWidth, tabStrip, launcherEntries }),
|
|
1791
|
-
[controller, windowId, hostPorts, layer, regionWidth, tabStrip, launcherEntries]
|
|
1900
|
+
const value = (0, import_react3.useMemo)(
|
|
1901
|
+
() => ({ controller, windowId, ports: hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus }),
|
|
1902
|
+
[controller, windowId, hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus]
|
|
1792
1903
|
);
|
|
1793
1904
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(CanvasContext.Provider, { value, children: [
|
|
1794
1905
|
children,
|
|
@@ -1797,14 +1908,14 @@ function CanvasProvider({
|
|
|
1797
1908
|
}
|
|
1798
1909
|
function CanvasWindowScope({ windowId, children }) {
|
|
1799
1910
|
const parent = useCanvasContext();
|
|
1800
|
-
const value = (0,
|
|
1911
|
+
const value = (0, import_react3.useMemo)(() => {
|
|
1801
1912
|
const id = canvasWindowId(windowId);
|
|
1802
1913
|
return { ...parent, windowId: id, controller: parent.controller.forWindow(id) };
|
|
1803
1914
|
}, [parent, windowId]);
|
|
1804
1915
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CanvasContext.Provider, { value, children });
|
|
1805
1916
|
}
|
|
1806
1917
|
function useCanvasContext() {
|
|
1807
|
-
const value = (0,
|
|
1918
|
+
const value = (0, import_react3.useContext)(CanvasContext);
|
|
1808
1919
|
if (!value) throw new Error("[@ai-matrx/canvas] useCanvas* must be used inside <CanvasProvider>.");
|
|
1809
1920
|
return value;
|
|
1810
1921
|
}
|
|
@@ -1812,16 +1923,16 @@ function useCanvasInternals() {
|
|
|
1812
1923
|
return useCanvasContext();
|
|
1813
1924
|
}
|
|
1814
1925
|
function useOptionalCanvasInternals() {
|
|
1815
|
-
return (0,
|
|
1926
|
+
return (0, import_react3.useContext)(CanvasContext);
|
|
1816
1927
|
}
|
|
1817
1928
|
function useCanvas() {
|
|
1818
1929
|
return useCanvasContext().controller;
|
|
1819
1930
|
}
|
|
1820
1931
|
function useOptionalCanvas() {
|
|
1821
|
-
return (0,
|
|
1932
|
+
return (0, import_react3.useContext)(CanvasContext)?.controller ?? null;
|
|
1822
1933
|
}
|
|
1823
1934
|
function useCanvasWindowId() {
|
|
1824
|
-
return (0,
|
|
1935
|
+
return (0, import_react3.useContext)(CanvasContext)?.windowId ?? CANVAS_MAIN_WINDOW;
|
|
1825
1936
|
}
|
|
1826
1937
|
function useCanvasHostPorts() {
|
|
1827
1938
|
return useCanvasContext().ports;
|
|
@@ -1830,16 +1941,16 @@ function useCanvasNativeBodies() {
|
|
|
1830
1941
|
return useCanvasContext().layer.native;
|
|
1831
1942
|
}
|
|
1832
1943
|
function useRegisterCanvasPresence() {
|
|
1833
|
-
const context = (0,
|
|
1944
|
+
const context = (0, import_react3.useContext)(CanvasContext);
|
|
1834
1945
|
const controller = context?.controller;
|
|
1835
1946
|
const windowId = context?.windowId;
|
|
1836
|
-
(0,
|
|
1947
|
+
(0, import_react3.useEffect)(() => controller?.registerPresentation(windowId), [controller, windowId]);
|
|
1837
1948
|
}
|
|
1838
1949
|
var noPresence = () => () => void 0;
|
|
1839
1950
|
function useCanvasIsPresented() {
|
|
1840
|
-
const context = (0,
|
|
1951
|
+
const context = (0, import_react3.useContext)(CanvasContext);
|
|
1841
1952
|
const controller = context?.controller;
|
|
1842
|
-
return (0,
|
|
1953
|
+
return (0, import_react3.useSyncExternalStore)(
|
|
1843
1954
|
controller ? controller.subscribePresentation : noPresence,
|
|
1844
1955
|
() => controller?.isPresented() ?? false,
|
|
1845
1956
|
() => false
|
|
@@ -1847,7 +1958,7 @@ function useCanvasIsPresented() {
|
|
|
1847
1958
|
}
|
|
1848
1959
|
function useCanvasState(selector) {
|
|
1849
1960
|
const { store } = useCanvasContext().controller;
|
|
1850
|
-
return (0,
|
|
1961
|
+
return (0, import_react3.useSyncExternalStore)(
|
|
1851
1962
|
store.subscribe,
|
|
1852
1963
|
() => selector(store.getState()),
|
|
1853
1964
|
() => selector(store.getState())
|
|
@@ -1855,9 +1966,9 @@ function useCanvasState(selector) {
|
|
|
1855
1966
|
}
|
|
1856
1967
|
var NO_SUBSCRIPTION = () => () => void 0;
|
|
1857
1968
|
function useOptionalCanvasState(selector, fallback) {
|
|
1858
|
-
const store = (0,
|
|
1969
|
+
const store = (0, import_react3.useContext)(CanvasContext)?.controller.store;
|
|
1859
1970
|
const read = () => store ? selector(store.getState()) : fallback;
|
|
1860
|
-
return (0,
|
|
1971
|
+
return (0, import_react3.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, read, read);
|
|
1861
1972
|
}
|
|
1862
1973
|
function useCanvasKindToggle(input) {
|
|
1863
1974
|
const controller = useCanvasContext().controller;
|
|
@@ -1871,28 +1982,28 @@ function useCanvasKindToggle(input) {
|
|
|
1871
1982
|
};
|
|
1872
1983
|
}
|
|
1873
1984
|
function useCanvasKinds() {
|
|
1874
|
-
(0,
|
|
1985
|
+
(0, import_react3.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
|
|
1875
1986
|
return listCanvasKinds();
|
|
1876
1987
|
}
|
|
1877
1988
|
function useCanvasKind(id) {
|
|
1878
|
-
(0,
|
|
1989
|
+
(0, import_react3.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
|
|
1879
1990
|
return getCanvasKind(id);
|
|
1880
1991
|
}
|
|
1881
1992
|
var NO_ENTRIES = Object.freeze([]);
|
|
1882
1993
|
var noEntries = () => NO_ENTRIES;
|
|
1883
1994
|
function useCanvasLauncherEntry(entry) {
|
|
1884
|
-
const store = (0,
|
|
1995
|
+
const store = (0, import_react3.useContext)(CanvasContext)?.launcherEntries;
|
|
1885
1996
|
const fingerprint = JSON.stringify([entry.kind, entry.key, entry.title ?? null, entry.data ?? null]);
|
|
1886
1997
|
const icon = entry.icon;
|
|
1887
|
-
(0,
|
|
1998
|
+
(0, import_react3.useEffect)(() => {
|
|
1888
1999
|
if (!store) return void 0;
|
|
1889
2000
|
const [kind, key, title, data] = JSON.parse(fingerprint);
|
|
1890
2001
|
return store.add({ kind, key, title, data, ...icon ? { icon } : {} });
|
|
1891
2002
|
}, [store, fingerprint, icon]);
|
|
1892
2003
|
}
|
|
1893
2004
|
function useCanvasLauncherEntries() {
|
|
1894
|
-
const store = (0,
|
|
1895
|
-
const all = (0,
|
|
2005
|
+
const store = (0, import_react3.useContext)(CanvasContext)?.launcherEntries;
|
|
2006
|
+
const all = (0, import_react3.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, store ? store.list : noEntries, store ? store.list : noEntries);
|
|
1896
2007
|
const seen = /* @__PURE__ */ new Set();
|
|
1897
2008
|
const out = [];
|
|
1898
2009
|
for (let i = all.length - 1; i >= 0; i -= 1) {
|
|
@@ -1905,14 +2016,14 @@ function useCanvasLauncherEntries() {
|
|
|
1905
2016
|
}
|
|
1906
2017
|
|
|
1907
2018
|
// src/react/CanvasColumn.tsx
|
|
1908
|
-
var
|
|
2019
|
+
var import_react10 = require("react");
|
|
1909
2020
|
var import_tap_target = require("@ai-matrx/tap-target");
|
|
1910
2021
|
|
|
1911
2022
|
// src/react/bodies.tsx
|
|
1912
|
-
var
|
|
2023
|
+
var import_react8 = require("react");
|
|
1913
2024
|
|
|
1914
2025
|
// src/react/chrome.tsx
|
|
1915
|
-
var
|
|
2026
|
+
var import_react4 = require("react");
|
|
1916
2027
|
|
|
1917
2028
|
// src/react/icons.tsx
|
|
1918
2029
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
@@ -2010,23 +2121,37 @@ var LayoutGridIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Glyph,
|
|
|
2010
2121
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" }),
|
|
2011
2122
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { width: "7", height: "7", x: "3", y: "14", rx: "1" })
|
|
2012
2123
|
] });
|
|
2013
|
-
var
|
|
2014
|
-
var ChevronRightIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Glyph, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m9 18 6-6-6-6" }) });
|
|
2124
|
+
var ChevronDownIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Glyph, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 9 6 6 6-6" }) });
|
|
2015
2125
|
|
|
2016
2126
|
// src/react/chrome.tsx
|
|
2017
2127
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2128
|
+
var useIsoLayoutEffect2 = typeof window === "undefined" ? import_react4.useEffect : import_react4.useLayoutEffect;
|
|
2129
|
+
function useTruncated(title) {
|
|
2130
|
+
const ref = (0, import_react4.useRef)(null);
|
|
2131
|
+
const [truncated, setTruncated] = (0, import_react4.useState)(false);
|
|
2132
|
+
useIsoLayoutEffect2(() => {
|
|
2133
|
+
const el = ref.current;
|
|
2134
|
+
if (!el) return void 0;
|
|
2135
|
+
const check = () => setTruncated(el.scrollWidth - el.clientWidth > 1);
|
|
2136
|
+
check();
|
|
2137
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(check);
|
|
2138
|
+
observer?.observe(el);
|
|
2139
|
+
return () => observer?.disconnect();
|
|
2140
|
+
}, [title]);
|
|
2141
|
+
return { ref, truncated };
|
|
2142
|
+
}
|
|
2018
2143
|
var cx = (...names) => names.filter(Boolean).join(" ");
|
|
2019
2144
|
function useTooltip(text) {
|
|
2020
2145
|
const internals = useOptionalCanvasInternals();
|
|
2021
|
-
const timer = (0,
|
|
2022
|
-
const hide = (0,
|
|
2146
|
+
const timer = (0, import_react4.useRef)(null);
|
|
2147
|
+
const hide = (0, import_react4.useRef)(null);
|
|
2023
2148
|
const close = () => {
|
|
2024
2149
|
if (timer.current) clearTimeout(timer.current);
|
|
2025
2150
|
timer.current = null;
|
|
2026
2151
|
hide.current?.();
|
|
2027
2152
|
hide.current = null;
|
|
2028
2153
|
};
|
|
2029
|
-
(0,
|
|
2154
|
+
(0, import_react4.useEffect)(() => close, []);
|
|
2030
2155
|
if (!text) return { close, handlers: {} };
|
|
2031
2156
|
if (!internals) return { close, handlers: { title: text } };
|
|
2032
2157
|
const open = (element, delay) => {
|
|
@@ -2052,7 +2177,7 @@ function useTooltip(text) {
|
|
|
2052
2177
|
}
|
|
2053
2178
|
};
|
|
2054
2179
|
}
|
|
2055
|
-
var CanvasHeaderButton = (0,
|
|
2180
|
+
var CanvasHeaderButton = (0, import_react4.forwardRef)(function CanvasHeaderButton2({ label, shortcut, available = true, size = "sm", pressed, className, children, onClick, onPointerEnter, onPointerLeave, onPointerDown, onFocus, onBlur, ...rest }, ref) {
|
|
2056
2181
|
const tooltip = useTooltip(shortcut ? `${label} (${shortcut})` : label);
|
|
2057
2182
|
const own = tooltip.handlers;
|
|
2058
2183
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -2097,12 +2222,12 @@ var CanvasHeaderButton = (0, import_react3.forwardRef)(function CanvasHeaderButt
|
|
|
2097
2222
|
}
|
|
2098
2223
|
);
|
|
2099
2224
|
});
|
|
2100
|
-
var CanvasMenuTrigger = (0,
|
|
2225
|
+
var CanvasMenuTrigger = (0, import_react4.forwardRef)(
|
|
2101
2226
|
function CanvasMenuTrigger2({ label = "More", ...props }, ref) {
|
|
2102
2227
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CanvasHeaderButton, { ref, label, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreIcon, {}) });
|
|
2103
2228
|
}
|
|
2104
2229
|
);
|
|
2105
|
-
var CanvasPanel = (0,
|
|
2230
|
+
var CanvasPanel = (0, import_react4.forwardRef)(function CanvasPanel2({
|
|
2106
2231
|
panelId,
|
|
2107
2232
|
title,
|
|
2108
2233
|
leading,
|
|
@@ -2152,8 +2277,9 @@ var CanvasPanel = (0, import_react3.forwardRef)(function CanvasPanel2({
|
|
|
2152
2277
|
function CanvasPanelEmpty({ children, className }) {
|
|
2153
2278
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { "data-slot": "canvas-panel-empty", className: cx("mxc-empty-line", className), children });
|
|
2154
2279
|
}
|
|
2155
|
-
var CanvasTab = (0,
|
|
2280
|
+
var CanvasTab = (0, import_react4.forwardRef)(function CanvasTab2({ title, icon, note, active, onSelect, onClose, className, onKeyDown, onClick, ...rest }, ref) {
|
|
2156
2281
|
const shown = title || "New tab";
|
|
2282
|
+
const name = useTruncated(shown);
|
|
2157
2283
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2158
2284
|
"div",
|
|
2159
2285
|
{
|
|
@@ -2163,6 +2289,7 @@ var CanvasTab = (0, import_react3.forwardRef)(function CanvasTab2({ title, icon,
|
|
|
2163
2289
|
tabIndex: active ? 0 : -1,
|
|
2164
2290
|
"data-slot": "browser-tab",
|
|
2165
2291
|
"data-active": active ? "" : void 0,
|
|
2292
|
+
"data-truncated": name.truncated ? "" : void 0,
|
|
2166
2293
|
title: shown,
|
|
2167
2294
|
className: cx("mxc-tab", className),
|
|
2168
2295
|
...rest,
|
|
@@ -2180,7 +2307,7 @@ var CanvasTab = (0, import_react3.forwardRef)(function CanvasTab2({ title, icon,
|
|
|
2180
2307
|
},
|
|
2181
2308
|
children: [
|
|
2182
2309
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mxc-tab-icon", children: icon }),
|
|
2183
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mxc-tab-title", children: shown }),
|
|
2310
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { ref: name.ref, className: "mxc-tab-title", children: shown }),
|
|
2184
2311
|
note ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mxc-tab-note", "data-slot": "browser-tab-note", children: note }) : null,
|
|
2185
2312
|
onClose ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2186
2313
|
"button",
|
|
@@ -2219,9 +2346,9 @@ function BrowserTabs({ tabs, activeId, onSelect, onClose, onNew, newLabel = "New
|
|
|
2219
2346
|
] });
|
|
2220
2347
|
}
|
|
2221
2348
|
function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload, onNavigate, trailing, className }) {
|
|
2222
|
-
const [draft, setDraft] = (0,
|
|
2223
|
-
const [editing, setEditing] = (0,
|
|
2224
|
-
(0,
|
|
2349
|
+
const [draft, setDraft] = (0, import_react4.useState)(url);
|
|
2350
|
+
const [editing, setEditing] = (0, import_react4.useState)(false);
|
|
2351
|
+
(0, import_react4.useEffect)(() => {
|
|
2225
2352
|
if (!editing) setDraft(url);
|
|
2226
2353
|
}, [url, editing]);
|
|
2227
2354
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { "data-slot": "browser-bar", className: cx("mxc-browser-bar", className), children: [
|
|
@@ -2263,15 +2390,15 @@ function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload,
|
|
|
2263
2390
|
}
|
|
2264
2391
|
|
|
2265
2392
|
// src/react/dnd.ts
|
|
2266
|
-
var
|
|
2393
|
+
var import_react5 = require("react");
|
|
2267
2394
|
var CANVAS_DRAG_MIME = "application/x-matrx-canvas-item";
|
|
2268
2395
|
function useTabDrag(itemId, title) {
|
|
2269
2396
|
const { layer } = useCanvasInternals();
|
|
2270
|
-
const active = (0,
|
|
2397
|
+
const active = (0, import_react5.useRef)([]);
|
|
2271
2398
|
const end = () => {
|
|
2272
2399
|
for (const dispose of active.current.splice(0)) dispose();
|
|
2273
2400
|
};
|
|
2274
|
-
(0,
|
|
2401
|
+
(0, import_react5.useEffect)(() => end, []);
|
|
2275
2402
|
return {
|
|
2276
2403
|
draggable: true,
|
|
2277
2404
|
onDragStart: (event) => {
|
|
@@ -2286,8 +2413,8 @@ function useTabDrag(itemId, title) {
|
|
|
2286
2413
|
function usePaneDrop(paneId, getOutline) {
|
|
2287
2414
|
const canvas = useCanvas();
|
|
2288
2415
|
const { layer } = useCanvasInternals();
|
|
2289
|
-
const drop = (0,
|
|
2290
|
-
(0,
|
|
2416
|
+
const drop = (0, import_react5.useRef)(null);
|
|
2417
|
+
(0, import_react5.useEffect)(() => () => drop.current?.(), []);
|
|
2291
2418
|
const hide = () => {
|
|
2292
2419
|
drop.current?.();
|
|
2293
2420
|
drop.current = null;
|
|
@@ -2418,16 +2545,19 @@ function useItemKind(kindId) {
|
|
|
2418
2545
|
const registered = useCanvasKind(kindId);
|
|
2419
2546
|
return kindId === CANVAS_LAUNCHER_KIND ? CANVAS_LAUNCHER_KIND_DEFINITION : registered;
|
|
2420
2547
|
}
|
|
2548
|
+
function resolveItemKind(kindId, lookup) {
|
|
2549
|
+
return kindId === CANVAS_LAUNCHER_KIND ? CANVAS_LAUNCHER_KIND_DEFINITION : lookup(kindId);
|
|
2550
|
+
}
|
|
2421
2551
|
|
|
2422
2552
|
// src/react/presentation.tsx
|
|
2423
|
-
var
|
|
2424
|
-
var CanvasPresentationContext = (0,
|
|
2553
|
+
var import_react6 = require("react");
|
|
2554
|
+
var CanvasPresentationContext = (0, import_react6.createContext)(null);
|
|
2425
2555
|
function useCanvasPresentation() {
|
|
2426
|
-
return (0,
|
|
2556
|
+
return (0, import_react6.useContext)(CanvasPresentationContext);
|
|
2427
2557
|
}
|
|
2428
2558
|
|
|
2429
2559
|
// src/react/slots.ts
|
|
2430
|
-
var
|
|
2560
|
+
var import_react7 = require("react");
|
|
2431
2561
|
var ZERO = Object.freeze({ width: 0, height: 0 });
|
|
2432
2562
|
function createCanvasSlots() {
|
|
2433
2563
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -2494,16 +2624,16 @@ function createCanvasSlots() {
|
|
|
2494
2624
|
}
|
|
2495
2625
|
};
|
|
2496
2626
|
}
|
|
2497
|
-
var CanvasSlotsContext = (0,
|
|
2627
|
+
var CanvasSlotsContext = (0, import_react7.createContext)(null);
|
|
2498
2628
|
function useCanvasSlots() {
|
|
2499
|
-
return (0,
|
|
2629
|
+
return (0, import_react7.useContext)(CanvasSlotsContext);
|
|
2500
2630
|
}
|
|
2501
|
-
var CanvasSinglePaneContext = (0,
|
|
2631
|
+
var CanvasSinglePaneContext = (0, import_react7.createContext)(false);
|
|
2502
2632
|
function useCanvasSinglePane() {
|
|
2503
|
-
return (0,
|
|
2633
|
+
return (0, import_react7.useContext)(CanvasSinglePaneContext);
|
|
2504
2634
|
}
|
|
2505
2635
|
function useSlotSize(slots, paneId) {
|
|
2506
|
-
return (0,
|
|
2636
|
+
return (0, import_react7.useSyncExternalStore)(
|
|
2507
2637
|
slots.subscribe,
|
|
2508
2638
|
() => slots.size(paneId),
|
|
2509
2639
|
() => ZERO
|
|
@@ -2512,12 +2642,12 @@ function useSlotSize(slots, paneId) {
|
|
|
2512
2642
|
|
|
2513
2643
|
// src/react/bodies.tsx
|
|
2514
2644
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2515
|
-
var
|
|
2645
|
+
var useIsoLayoutEffect3 = typeof window === "undefined" ? import_react8.useEffect : import_react8.useLayoutEffect;
|
|
2516
2646
|
var LAZY = /* @__PURE__ */ Symbol.for("ai-matrx.canvas.lazy");
|
|
2517
2647
|
function kindComponent(kind) {
|
|
2518
2648
|
if (kind.component) return kind.component;
|
|
2519
2649
|
const holder = kind;
|
|
2520
|
-
if (!holder[LAZY] && kind.load) holder[LAZY] = (0,
|
|
2650
|
+
if (!holder[LAZY] && kind.load) holder[LAZY] = (0, import_react8.lazy)(kind.load);
|
|
2521
2651
|
return holder[LAZY] ?? null;
|
|
2522
2652
|
}
|
|
2523
2653
|
function resetKindComponent(kind) {
|
|
@@ -2525,7 +2655,7 @@ function resetKindComponent(kind) {
|
|
|
2525
2655
|
}
|
|
2526
2656
|
function usePanePresentation(slots, paneId, isFullscreen, paneCount) {
|
|
2527
2657
|
const size = useSlotSize(slots, paneId);
|
|
2528
|
-
return (0,
|
|
2658
|
+
return (0, import_react8.useMemo)(
|
|
2529
2659
|
() => canvasPresentation({ width: size.width, height: size.height, isFullscreen, paneCount }),
|
|
2530
2660
|
[size.width, size.height, isFullscreen, paneCount]
|
|
2531
2661
|
);
|
|
@@ -2563,17 +2693,24 @@ function layerSignature(state, windowId, onlyPane) {
|
|
|
2563
2693
|
}
|
|
2564
2694
|
}
|
|
2565
2695
|
rows.sort((a, b) => a.born - b.born || a.hostId.localeCompare(b.hostId));
|
|
2566
|
-
const head = [
|
|
2696
|
+
const head = [
|
|
2697
|
+
frame2.isOpen ? "1" : "0",
|
|
2698
|
+
frame2.isFullscreen ? "1" : "0",
|
|
2699
|
+
frame2.focusedPaneId,
|
|
2700
|
+
String(paneIds.length),
|
|
2701
|
+
selectCanvasPresentedPaneId(state, windowId) ?? ""
|
|
2702
|
+
].join(SEP2);
|
|
2567
2703
|
return [head, ...rows.map((r) => r.row)].join(ROW);
|
|
2568
2704
|
}
|
|
2569
2705
|
function parseSignature(signature) {
|
|
2570
2706
|
if (!signature) return null;
|
|
2571
2707
|
const [head = "", ...rows] = signature.split(ROW);
|
|
2572
|
-
const [open, full, focusedPaneId = "", count = "1"] = head.split(SEP2);
|
|
2708
|
+
const [open, full, focusedPaneId = "", count = "1", presentedPaneId = ""] = head.split(SEP2);
|
|
2573
2709
|
return {
|
|
2574
2710
|
isOpen: open === "1",
|
|
2575
2711
|
isFullscreen: full === "1",
|
|
2576
2712
|
focusedPaneId,
|
|
2713
|
+
presentedPaneId,
|
|
2577
2714
|
paneCount: Number(count) || 1,
|
|
2578
2715
|
placed: rows.map((row) => {
|
|
2579
2716
|
const [hostId = "", itemId = "", paneId = "", active, kept] = row.split(SEP2);
|
|
@@ -2625,12 +2762,12 @@ function CanvasBodyLayer() {
|
|
|
2625
2762
|
const slots = useCanvasSlots();
|
|
2626
2763
|
const signature = useCanvasState((s) => layerSignature(s, windowId));
|
|
2627
2764
|
const single = useCanvasSinglePane();
|
|
2628
|
-
const root = (0,
|
|
2629
|
-
const [placement] = (0,
|
|
2765
|
+
const root = (0, import_react8.useRef)(null);
|
|
2766
|
+
const [placement] = (0, import_react8.useState)(
|
|
2630
2767
|
() => slots ? createPlacement(() => root.current, slots, () => layer.native.remeasure()) : null
|
|
2631
2768
|
);
|
|
2632
|
-
|
|
2633
|
-
|
|
2769
|
+
useIsoLayoutEffect3(() => placement?.place());
|
|
2770
|
+
useIsoLayoutEffect3(() => slots && placement ? slots.subscribe(placement.place) : void 0, [slots, placement]);
|
|
2634
2771
|
const shape = parseSignature(signature);
|
|
2635
2772
|
if (!slots || !placement || !shape) return null;
|
|
2636
2773
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: root, className: "mxc-bodies", "data-mxc-bodies": windowId, children: shape.placed.map(({ hostId, itemId, paneId, active, kept }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
@@ -2640,7 +2777,7 @@ function CanvasBodyLayer() {
|
|
|
2640
2777
|
itemId,
|
|
2641
2778
|
kept,
|
|
2642
2779
|
paneId,
|
|
2643
|
-
visible: shape.isOpen && active && (!single || paneId === shape.
|
|
2780
|
+
visible: shape.isOpen && active && (!single || paneId === shape.presentedPaneId),
|
|
2644
2781
|
focused: active && shape.focusedPaneId === paneId,
|
|
2645
2782
|
isFullscreen: shape.isFullscreen,
|
|
2646
2783
|
paneCount: shape.paneCount,
|
|
@@ -2683,7 +2820,7 @@ function stepAsItem(step, openedAt) {
|
|
|
2683
2820
|
...step.instance ? { instance: step.instance } : {}
|
|
2684
2821
|
};
|
|
2685
2822
|
}
|
|
2686
|
-
var BodyHost = (0,
|
|
2823
|
+
var BodyHost = (0, import_react8.memo)(function BodyHost2({
|
|
2687
2824
|
hostId,
|
|
2688
2825
|
itemId,
|
|
2689
2826
|
kept,
|
|
@@ -2703,16 +2840,16 @@ var BodyHost = (0, import_react7.memo)(function BodyHost2({
|
|
|
2703
2840
|
return ownerItem ? keptCanvasSteps(ownerItem).find((e) => e.instance === hostId) : void 0;
|
|
2704
2841
|
});
|
|
2705
2842
|
const owner = useCanvasState((s) => kept ? s.items[itemId]?.openedAt : void 0);
|
|
2706
|
-
const keptItem = (0,
|
|
2843
|
+
const keptItem = (0, import_react8.useMemo)(() => step ? stepAsItem(step, owner ?? 0) : void 0, [step, owner]);
|
|
2707
2844
|
const item = kept ? keptItem : live;
|
|
2708
2845
|
const kind = useItemKind(item?.kind ?? "");
|
|
2709
|
-
const element = (0,
|
|
2710
|
-
const [everShown, setEverShown] = (0,
|
|
2846
|
+
const element = (0, import_react8.useRef)(null);
|
|
2847
|
+
const [everShown, setEverShown] = (0, import_react8.useState)(visible);
|
|
2711
2848
|
if (visible && !everShown) setEverShown(true);
|
|
2712
2849
|
const mounted = kind?.unmountWhenHidden ? visible : everShown;
|
|
2713
2850
|
const presentation = usePanePresentation(slots, paneId, isFullscreen, paneCount);
|
|
2714
2851
|
const drop = usePaneDrop(paneId, () => slots.section(paneId));
|
|
2715
|
-
|
|
2852
|
+
useIsoLayoutEffect3(() => {
|
|
2716
2853
|
const el = element.current;
|
|
2717
2854
|
if (!placement || !el) return void 0;
|
|
2718
2855
|
return placement.register(hostId, { element: el, paneId });
|
|
@@ -2778,7 +2915,7 @@ function ItemContent({
|
|
|
2778
2915
|
}
|
|
2779
2916
|
return rendered;
|
|
2780
2917
|
}
|
|
2781
|
-
var Rendered = (0,
|
|
2918
|
+
var Rendered = (0, import_react8.memo)(function Rendered2({
|
|
2782
2919
|
kind,
|
|
2783
2920
|
item,
|
|
2784
2921
|
paneId,
|
|
@@ -2789,7 +2926,7 @@ var Rendered = (0, import_react7.memo)(function Rendered2({
|
|
|
2789
2926
|
presentation
|
|
2790
2927
|
}) {
|
|
2791
2928
|
const props = { item, data: item.data, paneId, isFocused, isVisible, canvas, windowId, presentation };
|
|
2792
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemBoundary, { item, onClose: () => canvas.close(item.id), onRetry: () => resetKindComponent(kind), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2929
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemBoundary, { item, onClose: () => canvas.close(item.id), onRetry: () => resetKindComponent(kind), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react8.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mxc-loading", "aria-busy": "true" }), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(KindRender, { kind, props }) }) });
|
|
2793
2930
|
});
|
|
2794
2931
|
function KindRender({ kind, props }) {
|
|
2795
2932
|
const Render = kindComponent(kind);
|
|
@@ -2798,8 +2935,8 @@ function KindRender({ kind, props }) {
|
|
|
2798
2935
|
}
|
|
2799
2936
|
function NativeBody({ itemId, windowId, visible, children }) {
|
|
2800
2937
|
const { layer } = useCanvasInternals();
|
|
2801
|
-
const ref = (0,
|
|
2802
|
-
const measure = (0,
|
|
2938
|
+
const ref = (0, import_react8.useRef)(null);
|
|
2939
|
+
const measure = (0, import_react8.useRef)(() => void 0);
|
|
2803
2940
|
measure.current = () => {
|
|
2804
2941
|
const el = ref.current;
|
|
2805
2942
|
const box = visible && el?.isConnected ? el.getBoundingClientRect() : null;
|
|
@@ -2810,8 +2947,8 @@ function NativeBody({ itemId, windowId, visible, children }) {
|
|
|
2810
2947
|
const rect = { ...toCanvasRect(box), devicePixelRatio: window.devicePixelRatio || 1 };
|
|
2811
2948
|
layer.native.report(itemId, rect, { visible: !layer.isBlocked(), windowId });
|
|
2812
2949
|
};
|
|
2813
|
-
|
|
2814
|
-
|
|
2950
|
+
useIsoLayoutEffect3(() => measure.current());
|
|
2951
|
+
useIsoLayoutEffect3(() => {
|
|
2815
2952
|
const el = ref.current;
|
|
2816
2953
|
const run = () => measure.current();
|
|
2817
2954
|
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(run);
|
|
@@ -2837,7 +2974,7 @@ function ItemProblem({ message, onClose, onRetry }) {
|
|
|
2837
2974
|
] })
|
|
2838
2975
|
] });
|
|
2839
2976
|
}
|
|
2840
|
-
var ItemBoundary = class extends
|
|
2977
|
+
var ItemBoundary = class extends import_react8.Component {
|
|
2841
2978
|
state = { error: null };
|
|
2842
2979
|
static getDerivedStateFromError(error) {
|
|
2843
2980
|
return { error };
|
|
@@ -2863,11 +3000,28 @@ var ItemBoundary = class extends import_react7.Component {
|
|
|
2863
3000
|
}
|
|
2864
3001
|
};
|
|
2865
3002
|
|
|
3003
|
+
// src/react/resizeGesture.ts
|
|
3004
|
+
function beginCanvasResize(mode) {
|
|
3005
|
+
if (typeof document === "undefined") return () => void 0;
|
|
3006
|
+
const root = document.documentElement;
|
|
3007
|
+
root.dataset.mxcResizing = mode;
|
|
3008
|
+
document.getSelection?.()?.removeAllRanges();
|
|
3009
|
+
const refuse = (event) => event.preventDefault();
|
|
3010
|
+
document.addEventListener("selectstart", refuse, true);
|
|
3011
|
+
let ended = false;
|
|
3012
|
+
return () => {
|
|
3013
|
+
if (ended) return;
|
|
3014
|
+
ended = true;
|
|
3015
|
+
delete root.dataset.mxcResizing;
|
|
3016
|
+
document.removeEventListener("selectstart", refuse, true);
|
|
3017
|
+
};
|
|
3018
|
+
}
|
|
3019
|
+
|
|
2866
3020
|
// src/react/CanvasPane.tsx
|
|
2867
|
-
var
|
|
3021
|
+
var import_react9 = require("react");
|
|
2868
3022
|
var Menu = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
|
|
2869
3023
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2870
|
-
var
|
|
3024
|
+
var useIsoLayoutEffect4 = typeof window === "undefined" ? import_react9.useEffect : import_react9.useLayoutEffect;
|
|
2871
3025
|
function itemTitle(item, kind) {
|
|
2872
3026
|
if (item.title) return item.title;
|
|
2873
3027
|
if (item.kind === CANVAS_LAUNCHER_KIND) return "New tab";
|
|
@@ -2904,7 +3058,7 @@ function CanvasPaneView({ paneId }) {
|
|
|
2904
3058
|
const canvas = useCanvas();
|
|
2905
3059
|
const { windowId, tabStrip } = useCanvasInternals();
|
|
2906
3060
|
const columnSlots = useCanvasSlots();
|
|
2907
|
-
const [ownSlots] = (0,
|
|
3061
|
+
const [ownSlots] = (0, import_react9.useState)(createCanvasSlots);
|
|
2908
3062
|
const slots = columnSlots ?? ownSlots;
|
|
2909
3063
|
const pane = useCanvasState((s) => s.panes[paneId]);
|
|
2910
3064
|
const active = useCanvasState((s) => {
|
|
@@ -2917,14 +3071,15 @@ function CanvasPaneView({ paneId }) {
|
|
|
2917
3071
|
const paneCount = useCanvasState((s) => selectCanvasPaneCount(s, windowId));
|
|
2918
3072
|
const role = useCanvasState((s) => windowId === CANVAS_MAIN_WINDOW ? "main" : s.windows[windowId]?.role ?? "window");
|
|
2919
3073
|
const canGoBack = useCanvasState((s) => active ? selectCanvasCanGoBack(s, active.id) : false);
|
|
3074
|
+
const canGoForward = useCanvasState((s) => active ? selectCanvasCanGoForward(s, active.id) : false);
|
|
2920
3075
|
const kind = useItemKind(active?.kind ?? "");
|
|
2921
3076
|
const singlePane = useCanvasSinglePane();
|
|
2922
3077
|
const windowTabs = useCanvasState((s) => singlePane ? windowTabsSignature(s, windowId) : "");
|
|
2923
|
-
const sectionRef = (0,
|
|
2924
|
-
const bodyRef = (0,
|
|
3078
|
+
const sectionRef = (0, import_react9.useRef)(null);
|
|
3079
|
+
const bodyRef = (0, import_react9.useRef)(null);
|
|
2925
3080
|
const presentation = usePanePresentation(slots, paneId, isFullscreen, paneCount);
|
|
2926
3081
|
const drop = usePaneDrop(paneId, () => sectionRef.current);
|
|
2927
|
-
|
|
3082
|
+
useIsoLayoutEffect4(() => {
|
|
2928
3083
|
const body = bodyRef.current;
|
|
2929
3084
|
const section = sectionRef.current;
|
|
2930
3085
|
if (body) slots.set(paneId, body);
|
|
@@ -2952,7 +3107,17 @@ function CanvasPaneView({ paneId }) {
|
|
|
2952
3107
|
focused,
|
|
2953
3108
|
"data-mxc-pane": paneId,
|
|
2954
3109
|
header: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2955
|
-
canGoBack && active ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CanvasHeaderButton, { className: "mxc-back", label: "Back", onClick: () => void canvas.back(active.id), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ArrowLeftIcon, {}) }) : null,
|
|
3110
|
+
canGoBack && active ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CanvasHeaderButton, { className: "mxc-back", label: "Back", shortcut: canvasShortcutHint("canvas.back", isMac()), onClick: () => void canvas.back(active.id), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ArrowLeftIcon, {}) }) : null,
|
|
3111
|
+
canGoForward && active ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3112
|
+
CanvasHeaderButton,
|
|
3113
|
+
{
|
|
3114
|
+
className: "mxc-forward",
|
|
3115
|
+
label: "Forward",
|
|
3116
|
+
shortcut: canvasShortcutHint("canvas.forward", isMac()),
|
|
3117
|
+
onClick: () => void canvas.forward(active.id),
|
|
3118
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ArrowRightIcon, {})
|
|
3119
|
+
}
|
|
3120
|
+
) : null,
|
|
2956
3121
|
single && active ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SingleTitle, { item: active, kind }) : tabs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabStrip, { tabs, activeItemId: pane.activeItemId }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mxc-panel-title", children: "New tab" }),
|
|
2957
3122
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CanvasHeaderButton, { className: "mxc-new-tab", label: "New tab", onClick: () => void canvas.newTab(paneId), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PlusIcon, {}) })
|
|
2958
3123
|
] }),
|
|
@@ -2961,7 +3126,19 @@ function CanvasPaneView({ paneId }) {
|
|
|
2961
3126
|
// Its own gapless row: a kind's tap buttons space themselves (the tap-target placement rule).
|
|
2962
3127
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mxc-kind-actions", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Action, { ...kindProps }) })
|
|
2963
3128
|
) : null,
|
|
2964
|
-
renderMenu: () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3129
|
+
renderMenu: () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3130
|
+
PaneMenu,
|
|
3131
|
+
{
|
|
3132
|
+
paneId,
|
|
3133
|
+
windowId,
|
|
3134
|
+
activeItem: active,
|
|
3135
|
+
kind,
|
|
3136
|
+
kindProps,
|
|
3137
|
+
tabCount: pane.itemIds.length,
|
|
3138
|
+
role,
|
|
3139
|
+
canSplit: !singlePane
|
|
3140
|
+
}
|
|
3141
|
+
),
|
|
2965
3142
|
expanded: isFullscreen,
|
|
2966
3143
|
onToggleExpand: () => canvas.setFullscreen(!isFullscreen),
|
|
2967
3144
|
expandShortcut: canvasShortcutHint("canvas.toggleFullscreen", isMac()),
|
|
@@ -2979,7 +3156,7 @@ function CanvasPaneView({ paneId }) {
|
|
|
2979
3156
|
}
|
|
2980
3157
|
);
|
|
2981
3158
|
}
|
|
2982
|
-
var ToolbarBoundary = class extends
|
|
3159
|
+
var ToolbarBoundary = class extends import_react9.Component {
|
|
2983
3160
|
state = { failed: false };
|
|
2984
3161
|
static getDerivedStateFromError() {
|
|
2985
3162
|
return { failed: true };
|
|
@@ -2995,77 +3172,135 @@ function SingleTitle({ item, kind }) {
|
|
|
2995
3172
|
const canvas = useCanvas();
|
|
2996
3173
|
const title = itemTitle(item, kind);
|
|
2997
3174
|
const drag = useTabDrag(item.id, title);
|
|
3175
|
+
const name = useTruncated(title);
|
|
2998
3176
|
const Icon = kind?.icon ?? AlertIcon;
|
|
2999
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "mxc-panel-title mxc-single-title", "data-draggable": "", title, ...drag, children: [
|
|
3177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "mxc-panel-title mxc-single-title", "data-draggable": "", "data-truncated": name.truncated ? "" : void 0, title, ...drag, children: [
|
|
3000
3178
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { className: "mxc-title-icon" }),
|
|
3001
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mxc-tab-title", children: title }),
|
|
3179
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { ref: name.ref, className: "mxc-tab-title", children: title }),
|
|
3002
3180
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "mxc-tab-close", "data-slot": "browser-tab-close", "aria-label": `Close ${title}`, onClick: () => canvas.close(item.id), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {}) })
|
|
3003
3181
|
] });
|
|
3004
3182
|
}
|
|
3183
|
+
var CANVAS_TAB_MIN_WIDTH = 78;
|
|
3184
|
+
var CANVAS_ACTIVE_TAB_MIN_WIDTH = 100;
|
|
3185
|
+
var TAB_LIST_BUTTON_ROOM = 30;
|
|
3186
|
+
var TAB_GAP = 2;
|
|
3187
|
+
function fitCanvasTabs(count, activeIndex, width) {
|
|
3188
|
+
if (count <= 0) return { start: 0, end: 0, overflow: false, compact: false };
|
|
3189
|
+
const need = (n) => CANVAS_ACTIVE_TAB_MIN_WIDTH + (n - 1) * (CANVAS_TAB_MIN_WIDTH + TAB_GAP);
|
|
3190
|
+
if (width <= 0 || need(count) <= width) return { start: 0, end: count, overflow: false, compact: false };
|
|
3191
|
+
if (count === 1) return { start: 0, end: 1, overflow: false, compact: true };
|
|
3192
|
+
let fit = 1;
|
|
3193
|
+
while (fit + 1 < count && need(fit + 1) + TAB_LIST_BUTTON_ROOM <= width) fit += 1;
|
|
3194
|
+
const active = Math.min(Math.max(activeIndex, 0), count - 1);
|
|
3195
|
+
const start = active < fit ? 0 : active - fit + 1;
|
|
3196
|
+
return { start, end: start + fit, overflow: true, compact: need(fit) + TAB_LIST_BUTTON_ROOM > width };
|
|
3197
|
+
}
|
|
3005
3198
|
function TabStrip({ tabs, activeItemId }) {
|
|
3006
|
-
const
|
|
3007
|
-
const
|
|
3008
|
-
const
|
|
3009
|
-
|
|
3010
|
-
const el = strip.current;
|
|
3011
|
-
if (!el) return;
|
|
3012
|
-
const start = el.scrollLeft > 1;
|
|
3013
|
-
const end = el.scrollLeft + el.clientWidth < el.scrollWidth - 1;
|
|
3014
|
-
setOverflow((prev) => prev.start === start && prev.end === end ? prev : { start, end });
|
|
3015
|
-
};
|
|
3016
|
-
const tabKey = tabs.map((tab) => tab.itemId).join("|");
|
|
3017
|
-
useIsoLayoutEffect2(() => {
|
|
3199
|
+
const canvas = useCanvas();
|
|
3200
|
+
const strip = (0, import_react9.useRef)(null);
|
|
3201
|
+
const [width, setWidth] = (0, import_react9.useState)(0);
|
|
3202
|
+
useIsoLayoutEffect4(() => {
|
|
3018
3203
|
const el = strip.current;
|
|
3019
3204
|
if (!el) return void 0;
|
|
3020
|
-
const
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
const left = tab.offsetLeft;
|
|
3024
|
-
const right = left + tab.offsetWidth;
|
|
3025
|
-
if (left < el.scrollLeft) el.scrollLeft = left;
|
|
3026
|
-
else if (right > el.scrollLeft + el.clientWidth) el.scrollLeft = right - el.clientWidth;
|
|
3027
|
-
}
|
|
3028
|
-
measure.current();
|
|
3029
|
-
};
|
|
3030
|
-
reveal();
|
|
3031
|
-
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(reveal);
|
|
3205
|
+
const read = () => setWidth(Math.floor(el.getBoundingClientRect().width));
|
|
3206
|
+
read();
|
|
3207
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(read);
|
|
3032
3208
|
observer?.observe(el);
|
|
3033
|
-
for (const tab of el.querySelectorAll('[role="tab"]')) observer?.observe(tab);
|
|
3034
3209
|
return () => observer?.disconnect();
|
|
3035
|
-
}, [
|
|
3036
|
-
const
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
if (typeof el.scrollBy === "function") el.scrollBy({ left: by, behavior: "smooth" });
|
|
3041
|
-
else el.scrollLeft += by;
|
|
3042
|
-
};
|
|
3043
|
-
const overflowing = overflow.start || overflow.end;
|
|
3210
|
+
}, []);
|
|
3211
|
+
const activeIndex = Math.max(0, tabs.findIndex((tab) => tab.itemId === activeItemId));
|
|
3212
|
+
const fit = fitCanvasTabs(tabs.length, activeIndex, width);
|
|
3213
|
+
const shown = tabs.slice(fit.start, fit.end);
|
|
3214
|
+
const hidden = tabs.length - shown.length;
|
|
3044
3215
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3045
3216
|
"div",
|
|
3046
3217
|
{
|
|
3218
|
+
ref: strip,
|
|
3047
3219
|
className: "mxc-tabstrip",
|
|
3048
|
-
"data-overflow":
|
|
3049
|
-
"data-
|
|
3050
|
-
"
|
|
3220
|
+
"data-overflow": fit.overflow ? "" : void 0,
|
|
3221
|
+
"data-compact": fit.compact ? "" : void 0,
|
|
3222
|
+
style: { ["--mxc-tab-min"]: `${CANVAS_TAB_MIN_WIDTH}px`, ["--mxc-tab-active-min"]: `${CANVAS_ACTIVE_TAB_MIN_WIDTH}px` },
|
|
3051
3223
|
children: [
|
|
3052
|
-
overflowing ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CanvasHeaderButton, { className: "mxc-tabs-scroll", label: "Scroll tabs left", available: overflow.start, onClick: () => page(-1), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}) }) : null,
|
|
3053
3224
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3054
3225
|
"div",
|
|
3055
3226
|
{
|
|
3056
|
-
ref: strip,
|
|
3057
3227
|
className: "mxc-tabs",
|
|
3058
3228
|
role: "tablist",
|
|
3059
3229
|
"aria-label": "Canvas tabs",
|
|
3060
|
-
onScroll: () => measure.current(),
|
|
3061
3230
|
onWheel: (event) => {
|
|
3062
|
-
|
|
3063
|
-
|
|
3231
|
+
if (!fit.overflow || Math.abs(event.deltaY) < Math.abs(event.deltaX) || tabs.length < 2) return;
|
|
3232
|
+
const next = tabs[(activeIndex + (event.deltaY > 0 ? 1 : -1) + tabs.length) % tabs.length];
|
|
3233
|
+
if (next) canvas.activate(next.itemId);
|
|
3064
3234
|
},
|
|
3065
|
-
children:
|
|
3235
|
+
children: shown.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ItemTab, { itemId: tab.itemId, paneId: tab.paneId, index: tab.index, active: tab.itemId === activeItemId }, tab.itemId))
|
|
3066
3236
|
}
|
|
3067
3237
|
),
|
|
3068
|
-
|
|
3238
|
+
fit.overflow ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabListMenu, { tabs, activeItemId, hidden }) : null
|
|
3239
|
+
]
|
|
3240
|
+
}
|
|
3241
|
+
);
|
|
3242
|
+
}
|
|
3243
|
+
function TabListMenu({ tabs, activeItemId, hidden }) {
|
|
3244
|
+
const canvas = useCanvas();
|
|
3245
|
+
const { ports, layer } = useCanvasInternals();
|
|
3246
|
+
const blocking = (0, import_react9.useRef)(null);
|
|
3247
|
+
(0, import_react9.useEffect)(() => () => blocking.current?.(), []);
|
|
3248
|
+
const label = `All tabs (${tabs.length})`;
|
|
3249
|
+
const trigger = (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(CanvasHeaderButton, { className: "mxc-tab-list", label, "data-hidden-count": hidden, ...props, children: [
|
|
3250
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {}),
|
|
3251
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mxc-tab-list-count", "aria-hidden": "true", children: hidden })
|
|
3252
|
+
] });
|
|
3253
|
+
const showMenu = ports.showMenu;
|
|
3254
|
+
if (showMenu) {
|
|
3255
|
+
return trigger({
|
|
3256
|
+
onClick: (event) => {
|
|
3257
|
+
const state = canvas.getState();
|
|
3258
|
+
const entries = tabs.map((tab) => {
|
|
3259
|
+
const item = state.items[tab.itemId];
|
|
3260
|
+
const title = item ? itemTitle(item, resolveItemKind(item.kind, getCanvasKind)) : tab.itemId;
|
|
3261
|
+
return { type: "item", id: tab.itemId, label: tab.itemId === activeItemId ? `${title} (current)` : title };
|
|
3262
|
+
});
|
|
3263
|
+
void showMenu(entries, toCanvasRect(event.currentTarget.getBoundingClientRect())).then(
|
|
3264
|
+
(chosen) => {
|
|
3265
|
+
if (chosen) canvas.activate(chosen);
|
|
3266
|
+
},
|
|
3267
|
+
(error) => console.error("[@ai-matrx/canvas] the host menu failed", error)
|
|
3268
|
+
);
|
|
3269
|
+
}
|
|
3270
|
+
});
|
|
3271
|
+
}
|
|
3272
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3273
|
+
Menu.Root,
|
|
3274
|
+
{
|
|
3275
|
+
onOpenChange: (open) => {
|
|
3276
|
+
blocking.current?.();
|
|
3277
|
+
blocking.current = open ? layer.beginBlocking() : null;
|
|
3278
|
+
},
|
|
3279
|
+
children: [
|
|
3280
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Trigger, { asChild: true, children: trigger({}) }),
|
|
3281
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Content, { align: "end", sideOffset: 4, className: "mxc-menu mxc-tab-list-menu", "aria-label": "All tabs", children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabListEntry, { itemId: tab.itemId, active: tab.itemId === activeItemId }, tab.itemId)) }) })
|
|
3282
|
+
]
|
|
3283
|
+
}
|
|
3284
|
+
);
|
|
3285
|
+
}
|
|
3286
|
+
function TabListEntry({ itemId, active }) {
|
|
3287
|
+
const canvas = useCanvas();
|
|
3288
|
+
const item = useCanvasState((s) => s.items[itemId]);
|
|
3289
|
+
const kind = useItemKind(item?.kind ?? "");
|
|
3290
|
+
if (!item) return null;
|
|
3291
|
+
const Icon = kind?.icon ?? AlertIcon;
|
|
3292
|
+
const title = itemTitle(item, kind);
|
|
3293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3294
|
+
Menu.Item,
|
|
3295
|
+
{
|
|
3296
|
+
className: "mxc-menu-item mxc-tab-list-item",
|
|
3297
|
+
"data-active": active ? "" : void 0,
|
|
3298
|
+
"aria-current": active ? "true" : void 0,
|
|
3299
|
+
title,
|
|
3300
|
+
onSelect: () => canvas.activate(itemId),
|
|
3301
|
+
children: [
|
|
3302
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, {}),
|
|
3303
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mxc-tab-list-title", children: title })
|
|
3069
3304
|
]
|
|
3070
3305
|
}
|
|
3071
3306
|
);
|
|
@@ -3109,42 +3344,48 @@ function PaneMenu({
|
|
|
3109
3344
|
kind,
|
|
3110
3345
|
kindProps,
|
|
3111
3346
|
tabCount,
|
|
3112
|
-
role
|
|
3347
|
+
role,
|
|
3348
|
+
canSplit
|
|
3113
3349
|
}) {
|
|
3114
3350
|
const canvas = useCanvas();
|
|
3115
|
-
const { ports, layer } = useCanvasInternals();
|
|
3351
|
+
const { ports, layer, itemMenus } = useCanvasInternals();
|
|
3116
3352
|
const moveId = tabCount > 1 ? activeItem?.id : void 0;
|
|
3117
|
-
const blocking = (0,
|
|
3118
|
-
(0,
|
|
3119
|
-
const
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
[
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3353
|
+
const blocking = (0, import_react9.useRef)(null);
|
|
3354
|
+
(0, import_react9.useEffect)(() => () => blocking.current?.(), []);
|
|
3355
|
+
const buildSections = () => {
|
|
3356
|
+
const kindItems = kind?.menuItems && kindProps ? safeMenu(() => kind.menuItems?.(kindProps)) : [];
|
|
3357
|
+
const hostItems = activeItem && ports.itemActions ? safeMenu(() => ports.itemActions?.(activeItem, kind)) : [];
|
|
3358
|
+
const bodyItems = activeItem ? itemMenus.read(activeItem.id) : [];
|
|
3359
|
+
return [
|
|
3360
|
+
[...kindItems, ...bodyItems, ...hostItems].map((entry) => ({ ...entry, id: `item:${entry.id}` })),
|
|
3361
|
+
[
|
|
3362
|
+
...canSplit ? [
|
|
3363
|
+
{ id: "split-right", label: "Split right", icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SplitRightIcon, {}), onSelect: () => canvas.splitPane(paneId, "horizontal", moveId) },
|
|
3364
|
+
{ id: "split-down", label: "Split down", icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SplitDownIcon, {}), onSelect: () => canvas.splitPane(paneId, "vertical", moveId) }
|
|
3365
|
+
] : [],
|
|
3366
|
+
...activeItem && role === "pop-out" ? [{ id: "dock-back", label: "Dock back", icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DockIcon, {}), onSelect: () => void canvas.dockBack(activeItem.id) }] : activeItem && ports.popOut ? [{ id: "pop-out", label: "Pop out", icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PopOutIcon, {}), onSelect: () => void canvas.popOut(activeItem.id) }] : []
|
|
3367
|
+
],
|
|
3368
|
+
activeItem ? [
|
|
3369
|
+
{ id: "close-tab", label: "Close tab", onSelect: () => canvas.close(activeItem.id) },
|
|
3370
|
+
...tabCount > 1 ? [{ id: "close-others", label: "Close other tabs", onSelect: () => canvas.closeOthers(activeItem.id) }] : []
|
|
3371
|
+
] : []
|
|
3372
|
+
].filter((section) => section.length > 0);
|
|
3373
|
+
};
|
|
3133
3374
|
const showMenu = ports.showMenu;
|
|
3134
3375
|
if (showMenu) {
|
|
3135
|
-
const entries = [];
|
|
3136
|
-
const handlers = /* @__PURE__ */ new Map();
|
|
3137
|
-
sections.forEach((section, i) => {
|
|
3138
|
-
if (i > 0) entries.push({ type: "separator" });
|
|
3139
|
-
for (const action of section) {
|
|
3140
|
-
entries.push({ type: "item", id: action.id, label: action.label, ...action.destructive ? { destructive: true } : {} });
|
|
3141
|
-
handlers.set(action.id, action.onSelect);
|
|
3142
|
-
}
|
|
3143
|
-
});
|
|
3144
3376
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3145
3377
|
CanvasMenuTrigger,
|
|
3146
3378
|
{
|
|
3147
3379
|
onClick: (event) => {
|
|
3380
|
+
const entries = [];
|
|
3381
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
3382
|
+
buildSections().forEach((section, i) => {
|
|
3383
|
+
if (i > 0) entries.push({ type: "separator" });
|
|
3384
|
+
for (const action of section) {
|
|
3385
|
+
entries.push({ type: "item", id: action.id, label: action.label, ...action.destructive ? { destructive: true } : {} });
|
|
3386
|
+
handlers.set(action.id, action.onSelect);
|
|
3387
|
+
}
|
|
3388
|
+
});
|
|
3148
3389
|
const anchor = toCanvasRect(event.currentTarget.getBoundingClientRect());
|
|
3149
3390
|
void showMenu(entries, anchor).then(
|
|
3150
3391
|
(chosen) => {
|
|
@@ -3165,11 +3406,14 @@ function PaneMenu({
|
|
|
3165
3406
|
},
|
|
3166
3407
|
children: [
|
|
3167
3408
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CanvasMenuTrigger, {}) }),
|
|
3168
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Content, { align: "end", sideOffset: 4, className: "mxc-menu", children:
|
|
3409
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Content, { align: "end", sideOffset: 4, className: "mxc-menu", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MenuSections, { build: buildSections }) }) })
|
|
3169
3410
|
]
|
|
3170
3411
|
}
|
|
3171
3412
|
);
|
|
3172
3413
|
}
|
|
3414
|
+
function MenuSections({ build }) {
|
|
3415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: build().map((section, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MenuSection, { first: i === 0, actions: section }, i)) });
|
|
3416
|
+
}
|
|
3173
3417
|
function MenuSection({ first, actions }) {
|
|
3174
3418
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3175
3419
|
first ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Separator, { className: "mxc-menu-separator" }),
|
|
@@ -3190,13 +3434,13 @@ function safeMenu(build) {
|
|
|
3190
3434
|
|
|
3191
3435
|
// src/react/CanvasColumn.tsx
|
|
3192
3436
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
3193
|
-
var
|
|
3437
|
+
var useIsoLayoutEffect5 = typeof window === "undefined" ? import_react10.useEffect : import_react10.useLayoutEffect;
|
|
3194
3438
|
function subscribeViewport(listener) {
|
|
3195
3439
|
window.addEventListener("resize", listener);
|
|
3196
3440
|
return () => window.removeEventListener("resize", listener);
|
|
3197
3441
|
}
|
|
3198
3442
|
function useViewportWidth() {
|
|
3199
|
-
return (0,
|
|
3443
|
+
return (0, import_react10.useSyncExternalStore)(subscribeViewport, () => window.innerWidth, () => 0);
|
|
3200
3444
|
}
|
|
3201
3445
|
function useRegionWidth() {
|
|
3202
3446
|
const viewport = useViewportWidth();
|
|
@@ -3219,15 +3463,15 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3219
3463
|
const isFullscreen = useCanvasState((s) => selectCanvasIsFullscreen(s, windowId));
|
|
3220
3464
|
const width = useCanvasState((s) => selectCanvasWidth(s, windowId));
|
|
3221
3465
|
const layout = useCanvasState((s) => selectCanvasLayout(s, windowId));
|
|
3222
|
-
const
|
|
3466
|
+
const presentedPaneId = useCanvasState((s) => selectCanvasPresentedPaneId(s, windowId));
|
|
3223
3467
|
const region = useRegionWidth();
|
|
3224
3468
|
const viewport = useViewportWidth();
|
|
3225
3469
|
const singlePane = placement === "docked" && viewport > 0 && viewport <= CANVAS_PHONE_MAX_WIDTH;
|
|
3226
|
-
const [dragWidth, setDragWidth] = (0,
|
|
3227
|
-
const [slots] = (0,
|
|
3228
|
-
const ref = (0,
|
|
3470
|
+
const [dragWidth, setDragWidth] = (0, import_react10.useState)(null);
|
|
3471
|
+
const [slots] = (0, import_react10.useState)(createCanvasSlots);
|
|
3472
|
+
const ref = (0, import_react10.useRef)(null);
|
|
3229
3473
|
useRegisterCanvasPresence();
|
|
3230
|
-
(0,
|
|
3474
|
+
(0, import_react10.useEffect)(() => {
|
|
3231
3475
|
const el = ref.current;
|
|
3232
3476
|
if (!el) return void 0;
|
|
3233
3477
|
let frame2 = 0;
|
|
@@ -3288,7 +3532,7 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3288
3532
|
}
|
|
3289
3533
|
) : null,
|
|
3290
3534
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CanvasSlotsContext.Provider, { value: slots, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(CanvasSinglePaneContext.Provider, { value: singlePane, children: [
|
|
3291
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mxc-layout", "data-single-pane": singlePane ? "" : void 0, children: singlePane ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CanvasPaneView, { paneId:
|
|
3535
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mxc-layout", "data-single-pane": singlePane ? "" : void 0, children: singlePane ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CanvasPaneView, { paneId: presentedPaneId ?? listPaneIds(layout)[0] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LayoutNodeView, { node: layout }) }),
|
|
3292
3536
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CanvasBodyLayer, {})
|
|
3293
3537
|
] }) })
|
|
3294
3538
|
] })
|
|
@@ -3297,13 +3541,14 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3297
3541
|
}
|
|
3298
3542
|
function WidthHandle({ width, region, onDrag }) {
|
|
3299
3543
|
const canvas = useCanvas();
|
|
3300
|
-
const start = (0,
|
|
3544
|
+
const start = (0, import_react10.useRef)(null);
|
|
3545
|
+
(0, import_react10.useEffect)(() => () => start.current?.end(), []);
|
|
3301
3546
|
const clamp = (next) => clampDraggedCanvasWidth(next, region, canvas.rules);
|
|
3302
3547
|
const onPointerDown = (event) => {
|
|
3303
3548
|
event.preventDefault();
|
|
3304
3549
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
3305
|
-
start.current
|
|
3306
|
-
|
|
3550
|
+
start.current?.end();
|
|
3551
|
+
start.current = { x: event.clientX, width, end: beginCanvasResize("") };
|
|
3307
3552
|
};
|
|
3308
3553
|
const onPointerMove = (event) => {
|
|
3309
3554
|
if (!start.current) return;
|
|
@@ -3312,8 +3557,8 @@ function WidthHandle({ width, region, onDrag }) {
|
|
|
3312
3557
|
const finish = (event) => {
|
|
3313
3558
|
if (!start.current) return;
|
|
3314
3559
|
const next = clamp(start.current.width + (start.current.x - event.clientX));
|
|
3560
|
+
start.current.end();
|
|
3315
3561
|
start.current = null;
|
|
3316
|
-
delete document.documentElement.dataset.mxcResizing;
|
|
3317
3562
|
onDrag(null);
|
|
3318
3563
|
canvas.setWidth(next);
|
|
3319
3564
|
};
|
|
@@ -3330,6 +3575,7 @@ function WidthHandle({ width, region, onDrag }) {
|
|
|
3330
3575
|
onPointerMove,
|
|
3331
3576
|
onPointerUp: finish,
|
|
3332
3577
|
onPointerCancel: finish,
|
|
3578
|
+
onLostPointerCapture: finish,
|
|
3333
3579
|
onDoubleClick: () => canvas.setWidth(clamp(Math.round(region / 2))),
|
|
3334
3580
|
onKeyDown: (event) => {
|
|
3335
3581
|
if (event.key === "ArrowLeft") canvas.setWidth(clamp(width + 32));
|
|
@@ -3338,17 +3584,13 @@ function WidthHandle({ width, region, onDrag }) {
|
|
|
3338
3584
|
}
|
|
3339
3585
|
);
|
|
3340
3586
|
}
|
|
3341
|
-
function presentedPane(layout, focused) {
|
|
3342
|
-
const ids = listPaneIds(layout);
|
|
3343
|
-
return ids.find((id) => id === focused) ?? ids[0];
|
|
3344
|
-
}
|
|
3345
3587
|
function LayoutNodeView({ node }) {
|
|
3346
3588
|
if (node.type === "pane") return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CanvasPaneView, { paneId: node.paneId });
|
|
3347
3589
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SplitView, { node });
|
|
3348
3590
|
}
|
|
3349
3591
|
function useMeasuredWidth(ref, enabled) {
|
|
3350
|
-
const [width, setWidth] = (0,
|
|
3351
|
-
|
|
3592
|
+
const [width, setWidth] = (0, import_react10.useState)(0);
|
|
3593
|
+
useIsoLayoutEffect5(() => {
|
|
3352
3594
|
const el = ref.current;
|
|
3353
3595
|
if (!enabled || !el) return;
|
|
3354
3596
|
setWidth(el.getBoundingClientRect().width);
|
|
@@ -3361,8 +3603,8 @@ function useMeasuredWidth(ref, enabled) {
|
|
|
3361
3603
|
}
|
|
3362
3604
|
function SplitView({ node }) {
|
|
3363
3605
|
const canvas = useCanvas();
|
|
3364
|
-
const ref = (0,
|
|
3365
|
-
const [liveSizes, setLiveSizes] = (0,
|
|
3606
|
+
const ref = (0, import_react10.useRef)(null);
|
|
3607
|
+
const [liveSizes, setLiveSizes] = (0, import_react10.useState)(null);
|
|
3366
3608
|
const sizes = liveSizes ?? node.sizes;
|
|
3367
3609
|
const measuredWidth = useMeasuredWidth(ref, node.orientation === "horizontal" && canvas.rules.paneMinWidth > 0);
|
|
3368
3610
|
const stacked = node.orientation === "horizontal" && shouldStackSplit(measuredWidth, node.children.length, canvas.rules);
|
|
@@ -3379,7 +3621,7 @@ function SplitView({ node }) {
|
|
|
3379
3621
|
const base = [...node.sizes];
|
|
3380
3622
|
const pair = (base[index] ?? 0) + (base[index + 1] ?? 0);
|
|
3381
3623
|
const target = event.currentTarget;
|
|
3382
|
-
|
|
3624
|
+
const end = beginCanvasResize(horizontal ? "col" : "row");
|
|
3383
3625
|
const compute = (pos) => {
|
|
3384
3626
|
const delta = (pos - origin) / total;
|
|
3385
3627
|
const min = CANVAS_MIN_SPLIT_FRACTION;
|
|
@@ -3394,7 +3636,7 @@ function SplitView({ node }) {
|
|
|
3394
3636
|
target.removeEventListener("pointermove", move);
|
|
3395
3637
|
target.removeEventListener("pointerup", up);
|
|
3396
3638
|
target.removeEventListener("pointercancel", up);
|
|
3397
|
-
|
|
3639
|
+
end();
|
|
3398
3640
|
setLiveSizes(null);
|
|
3399
3641
|
canvas.resizeSplit(node.id, compute(horizontal ? e.clientX : e.clientY));
|
|
3400
3642
|
};
|