@ai-matrx/canvas 0.9.3 → 0.10.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 +38 -0
- package/dist/react.cjs +338 -132
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +103 -2
- package/dist/react.d.ts +103 -2
- package/dist/react.js +287 -81
- package/dist/react.js.map +1 -1
- package/dist/styles.css +5 -1
- package/package.json +2 -2
package/dist/react.cjs
CHANGED
|
@@ -50,6 +50,10 @@ __export(react_exports, {
|
|
|
50
50
|
CanvasWindowScope: () => CanvasWindowScope,
|
|
51
51
|
CanvasWindowTabs: () => CanvasWindowTabs,
|
|
52
52
|
beginCanvasResize: () => beginCanvasResize,
|
|
53
|
+
canvasItemElement: () => canvasItemElement,
|
|
54
|
+
canvasKindOutputProblems: () => canvasKindOutputProblems,
|
|
55
|
+
canvasKindSurface: () => canvasKindSurface,
|
|
56
|
+
canvasOutputMenu: () => canvasOutputMenu,
|
|
53
57
|
canvasSessionKey: () => canvasSessionKey,
|
|
54
58
|
defineCanvasKind: () => defineCanvasKind,
|
|
55
59
|
fitCanvasTabWindow: () => fitCanvasTabWindow,
|
|
@@ -70,6 +74,7 @@ __export(react_exports, {
|
|
|
70
74
|
useCanvasLauncherEntry: () => useCanvasLauncherEntry,
|
|
71
75
|
useCanvasMenuItems: () => useCanvasMenuItems,
|
|
72
76
|
useCanvasNativeBodies: () => useCanvasNativeBodies,
|
|
77
|
+
useCanvasOutput: () => useCanvasOutput,
|
|
73
78
|
useCanvasPresentation: () => useCanvasPresentation,
|
|
74
79
|
useCanvasState: () => useCanvasState,
|
|
75
80
|
useCanvasWindowId: () => useCanvasWindowId,
|
|
@@ -79,7 +84,7 @@ __export(react_exports, {
|
|
|
79
84
|
module.exports = __toCommonJS(react_exports);
|
|
80
85
|
|
|
81
86
|
// src/react/provider.tsx
|
|
82
|
-
var
|
|
87
|
+
var import_react4 = require("react");
|
|
83
88
|
|
|
84
89
|
// src/react/menuItems.ts
|
|
85
90
|
var import_react = require("react");
|
|
@@ -120,6 +125,163 @@ function useCanvasMenuItems(itemId, items) {
|
|
|
120
125
|
}, [itemMenus, itemId]);
|
|
121
126
|
}
|
|
122
127
|
|
|
128
|
+
// src/react/output.ts
|
|
129
|
+
var import_react2 = require("react");
|
|
130
|
+
var useIsoLayoutEffect2 = typeof window === "undefined" ? import_react2.useEffect : import_react2.useLayoutEffect;
|
|
131
|
+
function createCanvasItemOutputs() {
|
|
132
|
+
const sources = /* @__PURE__ */ new Map();
|
|
133
|
+
return {
|
|
134
|
+
register(itemId, read) {
|
|
135
|
+
let set = sources.get(itemId);
|
|
136
|
+
if (!set) sources.set(itemId, set = /* @__PURE__ */ new Set());
|
|
137
|
+
set.add(read);
|
|
138
|
+
return () => {
|
|
139
|
+
const current = sources.get(itemId);
|
|
140
|
+
current?.delete(read);
|
|
141
|
+
if (current && current.size === 0) sources.delete(itemId);
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
read(itemId) {
|
|
145
|
+
let out = {};
|
|
146
|
+
for (const read of sources.get(itemId) ?? []) {
|
|
147
|
+
try {
|
|
148
|
+
const next = read();
|
|
149
|
+
out = { ...out, ...definedOnly(next), unavailable: { ...out.unavailable, ...next.unavailable } };
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error("[@ai-matrx/canvas] a body's output handlers threw", error);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function definedOnly(handlers) {
|
|
159
|
+
const out = {};
|
|
160
|
+
if (handlers.print) out.print = handlers.print;
|
|
161
|
+
if (handlers.savePdf) out.savePdf = handlers.savePdf;
|
|
162
|
+
if (handlers.capture) out.capture = handlers.capture;
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
function canvasItemElement(itemId) {
|
|
166
|
+
if (typeof document === "undefined") return null;
|
|
167
|
+
const hosts = document.querySelectorAll(".mxc-item-host[data-item]:not([data-kept])");
|
|
168
|
+
for (const host of hosts) {
|
|
169
|
+
if (host.dataset.item === itemId) return host.querySelector(":scope > .mxc-item");
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
function canvasKindSurface(kind) {
|
|
174
|
+
return kind?.surface ?? (kind?.body === "native" ? "native" : "dom");
|
|
175
|
+
}
|
|
176
|
+
async function defaultCopyImage(image) {
|
|
177
|
+
const png = image.type === "image/png" ? image : new Blob([image], { type: "image/png" });
|
|
178
|
+
await navigator.clipboard.write([new ClipboardItem({ "image/png": png })]);
|
|
179
|
+
}
|
|
180
|
+
function canvasOutputMenu(input) {
|
|
181
|
+
const { item, kind, title, body, ports } = input;
|
|
182
|
+
const surface = canvasKindSurface(kind);
|
|
183
|
+
const request = { item, kind, surface, element: canvasItemElement(item.id), title };
|
|
184
|
+
const report = (message) => (error) => ports?.onError ? ports.onError(message, error) : console.error(`[@ai-matrx/canvas] ${message}`, error);
|
|
185
|
+
const run = (fn, message) => () => {
|
|
186
|
+
try {
|
|
187
|
+
void Promise.resolve(fn()).catch(report(message));
|
|
188
|
+
} catch (error) {
|
|
189
|
+
report(message)(error);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const kindPrint = typeof kind?.print === "function" ? kind.print : null;
|
|
193
|
+
const kindPrintReason = typeof kind?.print === "string" ? kind.print : null;
|
|
194
|
+
const kindCapture = typeof kind?.capture === "function" ? kind.capture : null;
|
|
195
|
+
const kindCaptureReason = typeof kind?.capture === "string" ? kind.capture : null;
|
|
196
|
+
const hostServes = surface === "dom";
|
|
197
|
+
let print = null;
|
|
198
|
+
if (kind?.print !== false) {
|
|
199
|
+
if (body.print) print = body.print;
|
|
200
|
+
else if (kindPrint) print = () => kindPrint(request);
|
|
201
|
+
else if (hostServes && ports?.print) print = ports.print(request);
|
|
202
|
+
}
|
|
203
|
+
const printReason = print || kind?.print === false ? null : body.unavailable?.print ?? kindPrintReason;
|
|
204
|
+
let savePdf = print;
|
|
205
|
+
if (print && body.savePdf) savePdf = body.savePdf;
|
|
206
|
+
else if (print && !body.print && !kindPrint && hostServes && ports?.savePdf) savePdf = ports.savePdf(request) ?? print;
|
|
207
|
+
let capture = null;
|
|
208
|
+
if (kind?.capture !== false) {
|
|
209
|
+
if (body.capture) capture = body.capture;
|
|
210
|
+
else if (kindCapture) capture = () => kindCapture(request);
|
|
211
|
+
else if (surface !== "native" && ports?.capture) capture = ports.capture(request);
|
|
212
|
+
}
|
|
213
|
+
const captureReason = capture || kind?.capture === false ? null : body.unavailable?.capture ?? kindCaptureReason;
|
|
214
|
+
const entries = [];
|
|
215
|
+
if (printReason) {
|
|
216
|
+
entries.push({ id: "output:print", label: `Print \u2014 ${printReason}`, disabled: true, onSelect: () => void 0 });
|
|
217
|
+
} else if (print) {
|
|
218
|
+
entries.push({ id: "output:print", label: "Print", onSelect: run(print, "Print failed") });
|
|
219
|
+
if (savePdf) entries.push({ id: "output:pdf", label: "Save as PDF", onSelect: run(savePdf, "Save as PDF failed") });
|
|
220
|
+
}
|
|
221
|
+
if (captureReason) {
|
|
222
|
+
entries.push({ id: "output:copy-image", label: `Copy image \u2014 ${captureReason}`, disabled: true, onSelect: () => void 0 });
|
|
223
|
+
} else if (capture) {
|
|
224
|
+
const copy = ports?.copyImage ?? defaultCopyImage;
|
|
225
|
+
entries.push({
|
|
226
|
+
id: "output:copy-image",
|
|
227
|
+
label: "Copy image",
|
|
228
|
+
onSelect: run(async () => copy(await capture(), request), "Copy image failed")
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (ports?.attachOptions) {
|
|
232
|
+
try {
|
|
233
|
+
entries.push(...ports.attachOptions(request, captureReason ? null : capture));
|
|
234
|
+
} catch (error) {
|
|
235
|
+
report("Attach options failed")(error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return entries;
|
|
239
|
+
}
|
|
240
|
+
function useCanvasOutput(itemId, handlers) {
|
|
241
|
+
const { itemOutputs } = useCanvasInternals();
|
|
242
|
+
const latest = (0, import_react2.useRef)(handlers);
|
|
243
|
+
latest.current = handlers;
|
|
244
|
+
useIsoLayoutEffect2(() => {
|
|
245
|
+
if (!itemId) return void 0;
|
|
246
|
+
return itemOutputs.register(itemId, () => latest.current);
|
|
247
|
+
}, [itemOutputs, itemId]);
|
|
248
|
+
}
|
|
249
|
+
function canvasKindOutputProblems(kind) {
|
|
250
|
+
const problems = [];
|
|
251
|
+
const surface = kind.surface;
|
|
252
|
+
if (surface !== "dom" && surface !== "frame" && surface !== "native") {
|
|
253
|
+
problems.push(`"${kind.id}" declares no surface ("dom" | "frame" | "native")`);
|
|
254
|
+
return problems;
|
|
255
|
+
}
|
|
256
|
+
if (kind.body === "native" && surface !== "native") problems.push(`"${kind.id}" has a native body but surface "${surface}"`);
|
|
257
|
+
if (surface !== "dom") {
|
|
258
|
+
if (kind.print === void 0) problems.push(`"${kind.id}" is a ${surface} kind with no print (a handler or an honest reason)`);
|
|
259
|
+
if (kind.capture === void 0) problems.push(`"${kind.id}" is a ${surface} kind with no capture (a handler or an honest reason)`);
|
|
260
|
+
}
|
|
261
|
+
return problems;
|
|
262
|
+
}
|
|
263
|
+
var warnedKinds = /* @__PURE__ */ new Set();
|
|
264
|
+
function watchDomSurface(element, kindId) {
|
|
265
|
+
if (typeof MutationObserver === "undefined" || warnedKinds.has(kindId)) return () => void 0;
|
|
266
|
+
const check = () => {
|
|
267
|
+
if (warnedKinds.has(kindId)) return true;
|
|
268
|
+
const found = element.querySelector("iframe, canvas");
|
|
269
|
+
if (!found) return false;
|
|
270
|
+
warnedKinds.add(kindId);
|
|
271
|
+
console.error(
|
|
272
|
+
`[@ai-matrx/canvas] kind "${kindId}" declares surface "dom" but its body contains a <${found.tagName.toLowerCase()}>. DOM print and capture cannot copy it \u2014 declare surface "frame" with its own print and capture.`,
|
|
273
|
+
found
|
|
274
|
+
);
|
|
275
|
+
return true;
|
|
276
|
+
};
|
|
277
|
+
if (check()) return () => void 0;
|
|
278
|
+
const observer = new MutationObserver(() => {
|
|
279
|
+
if (check()) observer.disconnect();
|
|
280
|
+
});
|
|
281
|
+
observer.observe(element, { childList: true, subtree: true });
|
|
282
|
+
return () => observer.disconnect();
|
|
283
|
+
}
|
|
284
|
+
|
|
123
285
|
// src/core/types.ts
|
|
124
286
|
var CANVAS_MAIN_WINDOW = "main";
|
|
125
287
|
var CANVAS_LAUNCHER_KIND = "canvas.launcher";
|
|
@@ -1691,7 +1853,7 @@ function toggleKind(controller, input) {
|
|
|
1691
1853
|
}
|
|
1692
1854
|
|
|
1693
1855
|
// src/react/layer.tsx
|
|
1694
|
-
var
|
|
1856
|
+
var import_react3 = require("react");
|
|
1695
1857
|
var import_react_dom = require("react-dom");
|
|
1696
1858
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1697
1859
|
function createCanvasLayer(getPorts) {
|
|
@@ -1758,9 +1920,9 @@ function createCanvasLayer(getPorts) {
|
|
|
1758
1920
|
};
|
|
1759
1921
|
}
|
|
1760
1922
|
function CanvasDomOverlay({ layer }) {
|
|
1761
|
-
const elements = (0,
|
|
1762
|
-
const [mounted, setMounted] = (0,
|
|
1763
|
-
(0,
|
|
1923
|
+
const elements = (0, import_react3.useSyncExternalStore)(layer.dom.subscribe, layer.dom.list, layer.dom.list);
|
|
1924
|
+
const [mounted, setMounted] = (0, import_react3.useState)(false);
|
|
1925
|
+
(0, import_react3.useEffect)(() => setMounted(true), []);
|
|
1764
1926
|
if (!mounted || elements.length === 0 || typeof document === "undefined") return null;
|
|
1765
1927
|
return (0, import_react_dom.createPortal)(
|
|
1766
1928
|
/* @__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)) }),
|
|
@@ -1776,11 +1938,11 @@ function FloatingView({ element }) {
|
|
|
1776
1938
|
return null;
|
|
1777
1939
|
}
|
|
1778
1940
|
function Tooltip({ element }) {
|
|
1779
|
-
const ref = (0,
|
|
1941
|
+
const ref = (0, import_react3.useRef)(null);
|
|
1780
1942
|
const { anchor, side, text } = element;
|
|
1781
1943
|
const top = side === "bottom" ? anchor.y + anchor.height + 6 : anchor.y - 6;
|
|
1782
1944
|
const centre = anchor.x + anchor.width / 2;
|
|
1783
|
-
(0,
|
|
1945
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
1784
1946
|
const el = ref.current;
|
|
1785
1947
|
if (!el) return;
|
|
1786
1948
|
const width = el.offsetWidth;
|
|
@@ -1796,6 +1958,13 @@ function toCanvasRect(rect) {
|
|
|
1796
1958
|
|
|
1797
1959
|
// src/react/registry.ts
|
|
1798
1960
|
function defineCanvasKind(kind) {
|
|
1961
|
+
const surface = kind.surface;
|
|
1962
|
+
if (surface !== "dom" && surface !== "frame" && surface !== "native") {
|
|
1963
|
+
throw new Error(`[@ai-matrx/canvas] kind "${kind.id}" must declare surface: "dom" | "frame" | "native".`);
|
|
1964
|
+
}
|
|
1965
|
+
if (kind.body === "native" && surface !== "native") {
|
|
1966
|
+
throw new Error(`[@ai-matrx/canvas] kind "${kind.id}" has a native body, so its surface is "native".`);
|
|
1967
|
+
}
|
|
1799
1968
|
if (!kind.component && !kind.load && kind.body !== "native" && !kind.unavailable) {
|
|
1800
1969
|
throw new Error(`[@ai-matrx/canvas] kind "${kind.id}" needs a component, a load(), a native body or an unavailable() state.`);
|
|
1801
1970
|
}
|
|
@@ -1884,7 +2053,7 @@ function escapeBelongsElsewhere(event) {
|
|
|
1884
2053
|
const active = typeof document === "undefined" ? null : document.activeElement;
|
|
1885
2054
|
return !!active?.closest?.('[role="menu"], [role="dialog"], [role="alertdialog"], [role="listbox"]');
|
|
1886
2055
|
}
|
|
1887
|
-
var CanvasContext = (0,
|
|
2056
|
+
var CanvasContext = (0, import_react4.createContext)(null);
|
|
1888
2057
|
function sessionHooksFor(kindId) {
|
|
1889
2058
|
const kind = getCanvasKind(kindId);
|
|
1890
2059
|
if (!kind || kind.restore !== "session") return void 0;
|
|
@@ -1911,13 +2080,13 @@ function CanvasProvider({
|
|
|
1911
2080
|
overlay,
|
|
1912
2081
|
onNativeBodyFrame
|
|
1913
2082
|
}) {
|
|
1914
|
-
const hostPorts = (0,
|
|
2083
|
+
const hostPorts = (0, import_react4.useMemo)(
|
|
1915
2084
|
() => ({ itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame }),
|
|
1916
2085
|
[itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame]
|
|
1917
2086
|
);
|
|
1918
|
-
const portsRef = (0,
|
|
2087
|
+
const portsRef = (0, import_react4.useRef)(hostPorts);
|
|
1919
2088
|
portsRef.current = hostPorts;
|
|
1920
|
-
const [{ controller, layer, launcherEntries, itemMenus }] = (0,
|
|
2089
|
+
const [{ controller, layer, launcherEntries, itemMenus, itemOutputs }] = (0, import_react4.useState)(() => ({
|
|
1921
2090
|
controller: createCanvasController({
|
|
1922
2091
|
store: store ?? createCanvasStore(),
|
|
1923
2092
|
persistence: persistence === void 0 ? createLocalStorageCanvasPersistence() : persistence,
|
|
@@ -1932,11 +2101,12 @@ function CanvasProvider({
|
|
|
1932
2101
|
}),
|
|
1933
2102
|
layer: createCanvasLayer(() => portsRef.current),
|
|
1934
2103
|
launcherEntries: createLauncherEntryStore(),
|
|
1935
|
-
itemMenus: createCanvasItemMenus()
|
|
2104
|
+
itemMenus: createCanvasItemMenus(),
|
|
2105
|
+
itemOutputs: createCanvasItemOutputs()
|
|
1936
2106
|
}));
|
|
1937
2107
|
const windowId = controller.windowId;
|
|
1938
|
-
(0,
|
|
1939
|
-
(0,
|
|
2108
|
+
(0, import_react4.useEffect)(() => controller.start(), [controller]);
|
|
2109
|
+
(0, import_react4.useEffect)(() => {
|
|
1940
2110
|
if (!hotkeys) return;
|
|
1941
2111
|
const isMac3 = isMacPlatform();
|
|
1942
2112
|
const applies = (when, event) => {
|
|
@@ -1957,9 +2127,9 @@ function CanvasProvider({
|
|
|
1957
2127
|
window.addEventListener("keydown", onKey);
|
|
1958
2128
|
return () => window.removeEventListener("keydown", onKey);
|
|
1959
2129
|
}, [controller, hotkeys, windowId]);
|
|
1960
|
-
const value = (0,
|
|
1961
|
-
() => ({ controller, windowId, ports: hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus }),
|
|
1962
|
-
[controller, windowId, hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus]
|
|
2130
|
+
const value = (0, import_react4.useMemo)(
|
|
2131
|
+
() => ({ controller, windowId, ports: hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus, itemOutputs }),
|
|
2132
|
+
[controller, windowId, hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus, itemOutputs]
|
|
1963
2133
|
);
|
|
1964
2134
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(CanvasContext.Provider, { value, children: [
|
|
1965
2135
|
children,
|
|
@@ -1968,14 +2138,14 @@ function CanvasProvider({
|
|
|
1968
2138
|
}
|
|
1969
2139
|
function CanvasWindowScope({ windowId, children }) {
|
|
1970
2140
|
const parent = useCanvasContext();
|
|
1971
|
-
const value = (0,
|
|
2141
|
+
const value = (0, import_react4.useMemo)(() => {
|
|
1972
2142
|
const id = canvasWindowId(windowId);
|
|
1973
2143
|
return { ...parent, windowId: id, controller: parent.controller.forWindow(id) };
|
|
1974
2144
|
}, [parent, windowId]);
|
|
1975
2145
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CanvasContext.Provider, { value, children });
|
|
1976
2146
|
}
|
|
1977
2147
|
function useCanvasContext() {
|
|
1978
|
-
const value = (0,
|
|
2148
|
+
const value = (0, import_react4.useContext)(CanvasContext);
|
|
1979
2149
|
if (!value) throw new Error("[@ai-matrx/canvas] useCanvas* must be used inside <CanvasProvider>.");
|
|
1980
2150
|
return value;
|
|
1981
2151
|
}
|
|
@@ -1983,16 +2153,16 @@ function useCanvasInternals() {
|
|
|
1983
2153
|
return useCanvasContext();
|
|
1984
2154
|
}
|
|
1985
2155
|
function useOptionalCanvasInternals() {
|
|
1986
|
-
return (0,
|
|
2156
|
+
return (0, import_react4.useContext)(CanvasContext);
|
|
1987
2157
|
}
|
|
1988
2158
|
function useCanvas() {
|
|
1989
2159
|
return useCanvasContext().controller;
|
|
1990
2160
|
}
|
|
1991
2161
|
function useOptionalCanvas() {
|
|
1992
|
-
return (0,
|
|
2162
|
+
return (0, import_react4.useContext)(CanvasContext)?.controller ?? null;
|
|
1993
2163
|
}
|
|
1994
2164
|
function useCanvasWindowId() {
|
|
1995
|
-
return (0,
|
|
2165
|
+
return (0, import_react4.useContext)(CanvasContext)?.windowId ?? CANVAS_MAIN_WINDOW;
|
|
1996
2166
|
}
|
|
1997
2167
|
function useCanvasHostPorts() {
|
|
1998
2168
|
return useCanvasContext().ports;
|
|
@@ -2001,16 +2171,16 @@ function useCanvasNativeBodies() {
|
|
|
2001
2171
|
return useCanvasContext().layer.native;
|
|
2002
2172
|
}
|
|
2003
2173
|
function useRegisterCanvasPresence() {
|
|
2004
|
-
const context = (0,
|
|
2174
|
+
const context = (0, import_react4.useContext)(CanvasContext);
|
|
2005
2175
|
const controller = context?.controller;
|
|
2006
2176
|
const windowId = context?.windowId;
|
|
2007
|
-
(0,
|
|
2177
|
+
(0, import_react4.useEffect)(() => controller?.registerPresentation(windowId), [controller, windowId]);
|
|
2008
2178
|
}
|
|
2009
2179
|
var noPresence = () => () => void 0;
|
|
2010
2180
|
function useCanvasIsPresented() {
|
|
2011
|
-
const context = (0,
|
|
2181
|
+
const context = (0, import_react4.useContext)(CanvasContext);
|
|
2012
2182
|
const controller = context?.controller;
|
|
2013
|
-
return (0,
|
|
2183
|
+
return (0, import_react4.useSyncExternalStore)(
|
|
2014
2184
|
controller ? controller.subscribePresentation : noPresence,
|
|
2015
2185
|
() => controller?.isPresented() ?? false,
|
|
2016
2186
|
() => false
|
|
@@ -2018,7 +2188,7 @@ function useCanvasIsPresented() {
|
|
|
2018
2188
|
}
|
|
2019
2189
|
function useCanvasState(selector) {
|
|
2020
2190
|
const { store } = useCanvasContext().controller;
|
|
2021
|
-
return (0,
|
|
2191
|
+
return (0, import_react4.useSyncExternalStore)(
|
|
2022
2192
|
store.subscribe,
|
|
2023
2193
|
() => selector(store.getState()),
|
|
2024
2194
|
() => selector(store.getState())
|
|
@@ -2026,9 +2196,9 @@ function useCanvasState(selector) {
|
|
|
2026
2196
|
}
|
|
2027
2197
|
var NO_SUBSCRIPTION = () => () => void 0;
|
|
2028
2198
|
function useOptionalCanvasState(selector, fallback) {
|
|
2029
|
-
const store = (0,
|
|
2199
|
+
const store = (0, import_react4.useContext)(CanvasContext)?.controller.store;
|
|
2030
2200
|
const read = () => store ? selector(store.getState()) : fallback;
|
|
2031
|
-
return (0,
|
|
2201
|
+
return (0, import_react4.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, read, read);
|
|
2032
2202
|
}
|
|
2033
2203
|
function useCanvasKindToggle(input) {
|
|
2034
2204
|
const controller = useCanvasContext().controller;
|
|
@@ -2042,28 +2212,28 @@ function useCanvasKindToggle(input) {
|
|
|
2042
2212
|
};
|
|
2043
2213
|
}
|
|
2044
2214
|
function useCanvasKinds() {
|
|
2045
|
-
(0,
|
|
2215
|
+
(0, import_react4.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
|
|
2046
2216
|
return listCanvasKinds();
|
|
2047
2217
|
}
|
|
2048
2218
|
function useCanvasKind(id) {
|
|
2049
|
-
(0,
|
|
2219
|
+
(0, import_react4.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
|
|
2050
2220
|
return getCanvasKind(id);
|
|
2051
2221
|
}
|
|
2052
2222
|
var NO_ENTRIES = Object.freeze([]);
|
|
2053
2223
|
var noEntries = () => NO_ENTRIES;
|
|
2054
2224
|
function useCanvasLauncherEntry(entry) {
|
|
2055
|
-
const store = (0,
|
|
2225
|
+
const store = (0, import_react4.useContext)(CanvasContext)?.launcherEntries;
|
|
2056
2226
|
const fingerprint = JSON.stringify([entry.kind, entry.key, entry.title ?? null, entry.data ?? null]);
|
|
2057
2227
|
const icon = entry.icon;
|
|
2058
|
-
(0,
|
|
2228
|
+
(0, import_react4.useEffect)(() => {
|
|
2059
2229
|
if (!store) return void 0;
|
|
2060
2230
|
const [kind, key, title, data] = JSON.parse(fingerprint);
|
|
2061
2231
|
return store.add({ kind, key, title, data, ...icon ? { icon } : {} });
|
|
2062
2232
|
}, [store, fingerprint, icon]);
|
|
2063
2233
|
}
|
|
2064
2234
|
function useCanvasLauncherEntries() {
|
|
2065
|
-
const store = (0,
|
|
2066
|
-
const all = (0,
|
|
2235
|
+
const store = (0, import_react4.useContext)(CanvasContext)?.launcherEntries;
|
|
2236
|
+
const all = (0, import_react4.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, store ? store.list : noEntries, store ? store.list : noEntries);
|
|
2067
2237
|
const seen = /* @__PURE__ */ new Set();
|
|
2068
2238
|
const out = [];
|
|
2069
2239
|
for (let i = all.length - 1; i >= 0; i -= 1) {
|
|
@@ -2076,14 +2246,14 @@ function useCanvasLauncherEntries() {
|
|
|
2076
2246
|
}
|
|
2077
2247
|
|
|
2078
2248
|
// src/react/CanvasColumn.tsx
|
|
2079
|
-
var
|
|
2080
|
-
var import_tap_target = require("@ai-matrx/tap-target");
|
|
2249
|
+
var import_react11 = require("react");
|
|
2250
|
+
var import_tap_target = require("@ai-matrx/design-system/tap-target");
|
|
2081
2251
|
|
|
2082
2252
|
// src/react/bodies.tsx
|
|
2083
|
-
var
|
|
2253
|
+
var import_react9 = require("react");
|
|
2084
2254
|
|
|
2085
2255
|
// src/react/chrome.tsx
|
|
2086
|
-
var
|
|
2256
|
+
var import_react5 = require("react");
|
|
2087
2257
|
|
|
2088
2258
|
// src/react/icons.tsx
|
|
2089
2259
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
@@ -2185,11 +2355,11 @@ var ChevronDownIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Glyph,
|
|
|
2185
2355
|
|
|
2186
2356
|
// src/react/chrome.tsx
|
|
2187
2357
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2188
|
-
var
|
|
2358
|
+
var useIsoLayoutEffect3 = typeof window === "undefined" ? import_react5.useEffect : import_react5.useLayoutEffect;
|
|
2189
2359
|
function useTruncated(title) {
|
|
2190
|
-
const ref = (0,
|
|
2191
|
-
const [truncated, setTruncated] = (0,
|
|
2192
|
-
|
|
2360
|
+
const ref = (0, import_react5.useRef)(null);
|
|
2361
|
+
const [truncated, setTruncated] = (0, import_react5.useState)(false);
|
|
2362
|
+
useIsoLayoutEffect3(() => {
|
|
2193
2363
|
const el = ref.current;
|
|
2194
2364
|
if (!el) return void 0;
|
|
2195
2365
|
const check = () => setTruncated(el.scrollWidth - el.clientWidth > 1);
|
|
@@ -2203,15 +2373,15 @@ function useTruncated(title) {
|
|
|
2203
2373
|
var cx = (...names) => names.filter(Boolean).join(" ");
|
|
2204
2374
|
function useTooltip(text) {
|
|
2205
2375
|
const internals = useOptionalCanvasInternals();
|
|
2206
|
-
const timer = (0,
|
|
2207
|
-
const hide = (0,
|
|
2376
|
+
const timer = (0, import_react5.useRef)(null);
|
|
2377
|
+
const hide = (0, import_react5.useRef)(null);
|
|
2208
2378
|
const close = () => {
|
|
2209
2379
|
if (timer.current) clearTimeout(timer.current);
|
|
2210
2380
|
timer.current = null;
|
|
2211
2381
|
hide.current?.();
|
|
2212
2382
|
hide.current = null;
|
|
2213
2383
|
};
|
|
2214
|
-
(0,
|
|
2384
|
+
(0, import_react5.useEffect)(() => close, []);
|
|
2215
2385
|
if (!text) return { close, handlers: {} };
|
|
2216
2386
|
if (!internals) return { close, handlers: { title: text } };
|
|
2217
2387
|
const open = (element, delay) => {
|
|
@@ -2237,7 +2407,7 @@ function useTooltip(text) {
|
|
|
2237
2407
|
}
|
|
2238
2408
|
};
|
|
2239
2409
|
}
|
|
2240
|
-
var CanvasHeaderButton = (0,
|
|
2410
|
+
var CanvasHeaderButton = (0, import_react5.forwardRef)(function CanvasHeaderButton2({ label, shortcut, available = true, size = "sm", pressed, className, children, onClick, onPointerEnter, onPointerLeave, onPointerDown, onFocus, onBlur, ...rest }, ref) {
|
|
2241
2411
|
const tooltip = useTooltip(shortcut ? `${label} (${shortcut})` : label);
|
|
2242
2412
|
const own = tooltip.handlers;
|
|
2243
2413
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -2282,12 +2452,12 @@ var CanvasHeaderButton = (0, import_react4.forwardRef)(function CanvasHeaderButt
|
|
|
2282
2452
|
}
|
|
2283
2453
|
);
|
|
2284
2454
|
});
|
|
2285
|
-
var CanvasMenuTrigger = (0,
|
|
2455
|
+
var CanvasMenuTrigger = (0, import_react5.forwardRef)(
|
|
2286
2456
|
function CanvasMenuTrigger2({ label = "More", ...props }, ref) {
|
|
2287
2457
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CanvasHeaderButton, { ref, label, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreIcon, {}) });
|
|
2288
2458
|
}
|
|
2289
2459
|
);
|
|
2290
|
-
var CanvasPanel = (0,
|
|
2460
|
+
var CanvasPanel = (0, import_react5.forwardRef)(function CanvasPanel2({
|
|
2291
2461
|
panelId,
|
|
2292
2462
|
title,
|
|
2293
2463
|
leading,
|
|
@@ -2337,7 +2507,7 @@ var CanvasPanel = (0, import_react4.forwardRef)(function CanvasPanel2({
|
|
|
2337
2507
|
function CanvasPanelEmpty({ children, className }) {
|
|
2338
2508
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { "data-slot": "canvas-panel-empty", className: cx("mxc-empty-line", className), children });
|
|
2339
2509
|
}
|
|
2340
|
-
var CanvasTab = (0,
|
|
2510
|
+
var CanvasTab = (0, import_react5.forwardRef)(function CanvasTab2({ title, icon, note, active, onSelect, onClose, className, onKeyDown, onClick, ...rest }, ref) {
|
|
2341
2511
|
const shown = title || "New tab";
|
|
2342
2512
|
const name = useTruncated(shown);
|
|
2343
2513
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -2406,9 +2576,9 @@ function BrowserTabs({ tabs, activeId, onSelect, onClose, onNew, newLabel = "New
|
|
|
2406
2576
|
] });
|
|
2407
2577
|
}
|
|
2408
2578
|
function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload, onNavigate, trailing, className }) {
|
|
2409
|
-
const [draft, setDraft] = (0,
|
|
2410
|
-
const [editing, setEditing] = (0,
|
|
2411
|
-
(0,
|
|
2579
|
+
const [draft, setDraft] = (0, import_react5.useState)(url);
|
|
2580
|
+
const [editing, setEditing] = (0, import_react5.useState)(false);
|
|
2581
|
+
(0, import_react5.useEffect)(() => {
|
|
2412
2582
|
if (!editing) setDraft(url);
|
|
2413
2583
|
}, [url, editing]);
|
|
2414
2584
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { "data-slot": "browser-bar", className: cx("mxc-browser-bar", className), children: [
|
|
@@ -2450,15 +2620,15 @@ function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload,
|
|
|
2450
2620
|
}
|
|
2451
2621
|
|
|
2452
2622
|
// src/react/dnd.ts
|
|
2453
|
-
var
|
|
2623
|
+
var import_react6 = require("react");
|
|
2454
2624
|
var CANVAS_DRAG_MIME = "application/x-matrx-canvas-item";
|
|
2455
2625
|
function useTabDrag(itemId, title) {
|
|
2456
2626
|
const { layer } = useCanvasInternals();
|
|
2457
|
-
const active = (0,
|
|
2627
|
+
const active = (0, import_react6.useRef)([]);
|
|
2458
2628
|
const end = () => {
|
|
2459
2629
|
for (const dispose of active.current.splice(0)) dispose();
|
|
2460
2630
|
};
|
|
2461
|
-
(0,
|
|
2631
|
+
(0, import_react6.useEffect)(() => end, []);
|
|
2462
2632
|
return {
|
|
2463
2633
|
draggable: true,
|
|
2464
2634
|
onDragStart: (event) => {
|
|
@@ -2473,8 +2643,8 @@ function useTabDrag(itemId, title) {
|
|
|
2473
2643
|
function usePaneDrop(paneId, getOutline) {
|
|
2474
2644
|
const canvas = useCanvas();
|
|
2475
2645
|
const { layer } = useCanvasInternals();
|
|
2476
|
-
const drop = (0,
|
|
2477
|
-
(0,
|
|
2646
|
+
const drop = (0, import_react6.useRef)(null);
|
|
2647
|
+
(0, import_react6.useEffect)(() => () => drop.current?.(), []);
|
|
2478
2648
|
const hide = () => {
|
|
2479
2649
|
drop.current?.();
|
|
2480
2650
|
drop.current = null;
|
|
@@ -2597,6 +2767,10 @@ function EmptyPaneLauncher({ paneId }) {
|
|
|
2597
2767
|
}
|
|
2598
2768
|
var CANVAS_LAUNCHER_KIND_DEFINITION = {
|
|
2599
2769
|
id: CANVAS_LAUNCHER_KIND,
|
|
2770
|
+
surface: "dom",
|
|
2771
|
+
// A launcher is a menu of things to open — nothing to print or capture.
|
|
2772
|
+
print: false,
|
|
2773
|
+
capture: false,
|
|
2600
2774
|
label: "New tab",
|
|
2601
2775
|
icon: LayoutGridIcon,
|
|
2602
2776
|
component: LauncherBody
|
|
@@ -2610,14 +2784,14 @@ function resolveItemKind(kindId, lookup) {
|
|
|
2610
2784
|
}
|
|
2611
2785
|
|
|
2612
2786
|
// src/react/presentation.tsx
|
|
2613
|
-
var
|
|
2614
|
-
var CanvasPresentationContext = (0,
|
|
2787
|
+
var import_react7 = require("react");
|
|
2788
|
+
var CanvasPresentationContext = (0, import_react7.createContext)(null);
|
|
2615
2789
|
function useCanvasPresentation() {
|
|
2616
|
-
return (0,
|
|
2790
|
+
return (0, import_react7.useContext)(CanvasPresentationContext);
|
|
2617
2791
|
}
|
|
2618
2792
|
|
|
2619
2793
|
// src/react/slots.ts
|
|
2620
|
-
var
|
|
2794
|
+
var import_react8 = require("react");
|
|
2621
2795
|
var ZERO = Object.freeze({ width: 0, height: 0 });
|
|
2622
2796
|
function createCanvasSlots() {
|
|
2623
2797
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -2684,20 +2858,20 @@ function createCanvasSlots() {
|
|
|
2684
2858
|
}
|
|
2685
2859
|
};
|
|
2686
2860
|
}
|
|
2687
|
-
var CanvasSlotsContext = (0,
|
|
2861
|
+
var CanvasSlotsContext = (0, import_react8.createContext)(null);
|
|
2688
2862
|
function useCanvasSlots() {
|
|
2689
|
-
return (0,
|
|
2863
|
+
return (0, import_react8.useContext)(CanvasSlotsContext);
|
|
2690
2864
|
}
|
|
2691
|
-
var CanvasSinglePaneContext = (0,
|
|
2865
|
+
var CanvasSinglePaneContext = (0, import_react8.createContext)(false);
|
|
2692
2866
|
function useCanvasSinglePane() {
|
|
2693
|
-
return (0,
|
|
2867
|
+
return (0, import_react8.useContext)(CanvasSinglePaneContext);
|
|
2694
2868
|
}
|
|
2695
|
-
var CanvasWindowTabsContext = (0,
|
|
2869
|
+
var CanvasWindowTabsContext = (0, import_react8.createContext)(false);
|
|
2696
2870
|
function useCanvasWindowTabs() {
|
|
2697
|
-
return (0,
|
|
2871
|
+
return (0, import_react8.useContext)(CanvasWindowTabsContext);
|
|
2698
2872
|
}
|
|
2699
2873
|
function useSlotSize(slots, paneId) {
|
|
2700
|
-
return (0,
|
|
2874
|
+
return (0, import_react8.useSyncExternalStore)(
|
|
2701
2875
|
slots.subscribe,
|
|
2702
2876
|
() => slots.size(paneId),
|
|
2703
2877
|
() => ZERO
|
|
@@ -2706,12 +2880,12 @@ function useSlotSize(slots, paneId) {
|
|
|
2706
2880
|
|
|
2707
2881
|
// src/react/bodies.tsx
|
|
2708
2882
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2709
|
-
var
|
|
2883
|
+
var useIsoLayoutEffect4 = typeof window === "undefined" ? import_react9.useEffect : import_react9.useLayoutEffect;
|
|
2710
2884
|
var LAZY = /* @__PURE__ */ Symbol.for("ai-matrx.canvas.lazy");
|
|
2711
2885
|
function kindComponent(kind) {
|
|
2712
2886
|
if (kind.component) return kind.component;
|
|
2713
2887
|
const holder = kind;
|
|
2714
|
-
if (!holder[LAZY] && kind.load) holder[LAZY] = (0,
|
|
2888
|
+
if (!holder[LAZY] && kind.load) holder[LAZY] = (0, import_react9.lazy)(kind.load);
|
|
2715
2889
|
return holder[LAZY] ?? null;
|
|
2716
2890
|
}
|
|
2717
2891
|
function resetKindComponent(kind) {
|
|
@@ -2719,7 +2893,7 @@ function resetKindComponent(kind) {
|
|
|
2719
2893
|
}
|
|
2720
2894
|
function usePanePresentation(slots, paneId, isFullscreen, paneCount) {
|
|
2721
2895
|
const size = useSlotSize(slots, paneId);
|
|
2722
|
-
return (0,
|
|
2896
|
+
return (0, import_react9.useMemo)(
|
|
2723
2897
|
() => canvasPresentation({ width: size.width, height: size.height, isFullscreen, paneCount }),
|
|
2724
2898
|
[size.width, size.height, isFullscreen, paneCount]
|
|
2725
2899
|
);
|
|
@@ -2826,12 +3000,12 @@ function CanvasBodyLayer() {
|
|
|
2826
3000
|
const slots = useCanvasSlots();
|
|
2827
3001
|
const signature = useCanvasState((s) => layerSignature(s, windowId));
|
|
2828
3002
|
const single = useCanvasSinglePane();
|
|
2829
|
-
const root = (0,
|
|
2830
|
-
const [placement] = (0,
|
|
3003
|
+
const root = (0, import_react9.useRef)(null);
|
|
3004
|
+
const [placement] = (0, import_react9.useState)(
|
|
2831
3005
|
() => slots ? createPlacement(() => root.current, slots, () => layer.native.remeasure()) : null
|
|
2832
3006
|
);
|
|
2833
|
-
|
|
2834
|
-
|
|
3007
|
+
useIsoLayoutEffect4(() => placement?.place());
|
|
3008
|
+
useIsoLayoutEffect4(() => slots && placement ? slots.subscribe(placement.place) : void 0, [slots, placement]);
|
|
2835
3009
|
const shape = parseSignature(signature);
|
|
2836
3010
|
if (!slots || !placement || !shape) return null;
|
|
2837
3011
|
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)(
|
|
@@ -2884,7 +3058,7 @@ function stepAsItem(step, openedAt) {
|
|
|
2884
3058
|
...step.instance ? { instance: step.instance } : {}
|
|
2885
3059
|
};
|
|
2886
3060
|
}
|
|
2887
|
-
var BodyHost = (0,
|
|
3061
|
+
var BodyHost = (0, import_react9.memo)(function BodyHost2({
|
|
2888
3062
|
hostId,
|
|
2889
3063
|
itemId,
|
|
2890
3064
|
kept,
|
|
@@ -2904,20 +3078,26 @@ var BodyHost = (0, import_react8.memo)(function BodyHost2({
|
|
|
2904
3078
|
return ownerItem ? keptCanvasSteps(ownerItem).find((e) => e.instance === hostId) : void 0;
|
|
2905
3079
|
});
|
|
2906
3080
|
const owner = useCanvasState((s) => kept ? s.items[itemId]?.openedAt : void 0);
|
|
2907
|
-
const keptItem = (0,
|
|
3081
|
+
const keptItem = (0, import_react9.useMemo)(() => step ? stepAsItem(step, owner ?? 0) : void 0, [step, owner]);
|
|
2908
3082
|
const item = kept ? keptItem : live;
|
|
2909
3083
|
const kind = useItemKind(item?.kind ?? "");
|
|
2910
|
-
const element = (0,
|
|
2911
|
-
const [everShown, setEverShown] = (0,
|
|
3084
|
+
const element = (0, import_react9.useRef)(null);
|
|
3085
|
+
const [everShown, setEverShown] = (0, import_react9.useState)(visible);
|
|
2912
3086
|
if (visible && !everShown) setEverShown(true);
|
|
2913
3087
|
const mounted = kind?.unmountWhenHidden ? visible : everShown;
|
|
2914
3088
|
const presentation = usePanePresentation(slots, paneId, isFullscreen, paneCount);
|
|
2915
3089
|
const drop = usePaneDrop(paneId, () => slots.section(paneId));
|
|
2916
|
-
|
|
3090
|
+
useIsoLayoutEffect4(() => {
|
|
2917
3091
|
const el = element.current;
|
|
2918
3092
|
if (!placement || !el) return void 0;
|
|
2919
3093
|
return placement.register(hostId, { element: el, paneId });
|
|
2920
3094
|
}, [placement, hostId, paneId]);
|
|
3095
|
+
const domSurface = kind?.surface === "dom" && mounted && !kept;
|
|
3096
|
+
(0, import_react9.useEffect)(() => {
|
|
3097
|
+
if (process.env.NODE_ENV === "production" || !domSurface || !kind) return void 0;
|
|
3098
|
+
const el = element.current;
|
|
3099
|
+
return el ? watchDomSurface(el, kind.id) : void 0;
|
|
3100
|
+
}, [domSurface, kind]);
|
|
2921
3101
|
if (!item) return null;
|
|
2922
3102
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2923
3103
|
"div",
|
|
@@ -2979,7 +3159,7 @@ function ItemContent({
|
|
|
2979
3159
|
}
|
|
2980
3160
|
return rendered;
|
|
2981
3161
|
}
|
|
2982
|
-
var Rendered = (0,
|
|
3162
|
+
var Rendered = (0, import_react9.memo)(function Rendered2({
|
|
2983
3163
|
kind,
|
|
2984
3164
|
item,
|
|
2985
3165
|
paneId,
|
|
@@ -2990,17 +3170,17 @@ var Rendered = (0, import_react8.memo)(function Rendered2({
|
|
|
2990
3170
|
presentation
|
|
2991
3171
|
}) {
|
|
2992
3172
|
const props = { item, data: item.data, paneId, isFocused, isVisible, canvas, windowId, presentation };
|
|
2993
|
-
const [attempt, setAttempt] = (0,
|
|
3173
|
+
const [attempt, setAttempt] = (0, import_react9.useState)(0);
|
|
2994
3174
|
const retry = () => {
|
|
2995
3175
|
resetKindComponent(kind);
|
|
2996
3176
|
setAttempt((n) => n + 1);
|
|
2997
3177
|
};
|
|
2998
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemBoundary, { item, onClose: () => canvas.close(item.id), onRetry: retry, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemBoundary, { item, onClose: () => canvas.close(item.id), onRetry: retry, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react9.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LoadingBody, { onRetry: retry, onClose: () => canvas.close(item.id) }), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(KindRender, { kind, props }) }, attempt) });
|
|
2999
3179
|
});
|
|
3000
3180
|
var CANVAS_BODY_STALL_MS = 2e4;
|
|
3001
3181
|
function LoadingBody({ onRetry, onClose }) {
|
|
3002
|
-
const [stalled, setStalled] = (0,
|
|
3003
|
-
(0,
|
|
3182
|
+
const [stalled, setStalled] = (0, import_react9.useState)(false);
|
|
3183
|
+
(0, import_react9.useEffect)(() => {
|
|
3004
3184
|
const timer = setTimeout(() => setStalled(true), CANVAS_BODY_STALL_MS);
|
|
3005
3185
|
return () => clearTimeout(timer);
|
|
3006
3186
|
}, []);
|
|
@@ -3014,8 +3194,8 @@ function KindRender({ kind, props }) {
|
|
|
3014
3194
|
}
|
|
3015
3195
|
function NativeBody({ itemId, windowId, visible, children }) {
|
|
3016
3196
|
const { layer } = useCanvasInternals();
|
|
3017
|
-
const ref = (0,
|
|
3018
|
-
const measure = (0,
|
|
3197
|
+
const ref = (0, import_react9.useRef)(null);
|
|
3198
|
+
const measure = (0, import_react9.useRef)(() => void 0);
|
|
3019
3199
|
measure.current = () => {
|
|
3020
3200
|
const el = ref.current;
|
|
3021
3201
|
const box = visible && el?.isConnected ? el.getBoundingClientRect() : null;
|
|
@@ -3026,8 +3206,8 @@ function NativeBody({ itemId, windowId, visible, children }) {
|
|
|
3026
3206
|
const rect = { ...toCanvasRect(box), devicePixelRatio: window.devicePixelRatio || 1 };
|
|
3027
3207
|
layer.native.report(itemId, rect, { visible: !layer.isBlocked(), windowId });
|
|
3028
3208
|
};
|
|
3029
|
-
|
|
3030
|
-
|
|
3209
|
+
useIsoLayoutEffect4(() => measure.current());
|
|
3210
|
+
useIsoLayoutEffect4(() => {
|
|
3031
3211
|
const el = ref.current;
|
|
3032
3212
|
const run = () => measure.current();
|
|
3033
3213
|
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(run);
|
|
@@ -3053,7 +3233,7 @@ function ItemProblem({ message, onClose, onRetry }) {
|
|
|
3053
3233
|
] })
|
|
3054
3234
|
] });
|
|
3055
3235
|
}
|
|
3056
|
-
var ItemBoundary = class extends
|
|
3236
|
+
var ItemBoundary = class extends import_react9.Component {
|
|
3057
3237
|
state = { error: null };
|
|
3058
3238
|
static getDerivedStateFromError(error) {
|
|
3059
3239
|
return { error };
|
|
@@ -3097,10 +3277,10 @@ function beginCanvasResize(mode) {
|
|
|
3097
3277
|
}
|
|
3098
3278
|
|
|
3099
3279
|
// src/react/CanvasPane.tsx
|
|
3100
|
-
var
|
|
3280
|
+
var import_react10 = require("react");
|
|
3101
3281
|
var Menu = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
|
|
3102
3282
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3103
|
-
var
|
|
3283
|
+
var useIsoLayoutEffect5 = typeof window === "undefined" ? import_react10.useEffect : import_react10.useLayoutEffect;
|
|
3104
3284
|
function itemTitle(item, kind) {
|
|
3105
3285
|
if (item.title) return item.title;
|
|
3106
3286
|
if (item.kind === CANVAS_LAUNCHER_KIND) return "New tab";
|
|
@@ -3151,7 +3331,7 @@ function CanvasPaneView({ paneId }) {
|
|
|
3151
3331
|
const canvas = useCanvas();
|
|
3152
3332
|
const { windowId, tabStrip } = useCanvasInternals();
|
|
3153
3333
|
const columnSlots = useCanvasSlots();
|
|
3154
|
-
const [ownSlots] = (0,
|
|
3334
|
+
const [ownSlots] = (0, import_react10.useState)(createCanvasSlots);
|
|
3155
3335
|
const slots = columnSlots ?? ownSlots;
|
|
3156
3336
|
const pane = useCanvasState((s) => s.panes[paneId]);
|
|
3157
3337
|
const active = useCanvasState((s) => {
|
|
@@ -3169,11 +3349,11 @@ function CanvasPaneView({ paneId }) {
|
|
|
3169
3349
|
const singlePane = useCanvasSinglePane();
|
|
3170
3350
|
const inWindowStrip = useCanvasWindowTabs() && !singlePane;
|
|
3171
3351
|
const windowTabs = useCanvasState((s) => singlePane ? windowTabsSignature(s, windowId) : "");
|
|
3172
|
-
const sectionRef = (0,
|
|
3173
|
-
const bodyRef = (0,
|
|
3352
|
+
const sectionRef = (0, import_react10.useRef)(null);
|
|
3353
|
+
const bodyRef = (0, import_react10.useRef)(null);
|
|
3174
3354
|
const presentation = usePanePresentation(slots, paneId, isFullscreen, paneCount);
|
|
3175
3355
|
const drop = usePaneDrop(paneId, () => sectionRef.current);
|
|
3176
|
-
|
|
3356
|
+
useIsoLayoutEffect5(() => {
|
|
3177
3357
|
const body = bodyRef.current;
|
|
3178
3358
|
const section = sectionRef.current;
|
|
3179
3359
|
if (body) slots.set(paneId, body);
|
|
@@ -3250,7 +3430,7 @@ function CanvasPaneView({ paneId }) {
|
|
|
3250
3430
|
}
|
|
3251
3431
|
);
|
|
3252
3432
|
}
|
|
3253
|
-
var ToolbarBoundary = class extends
|
|
3433
|
+
var ToolbarBoundary = class extends import_react10.Component {
|
|
3254
3434
|
state = { failed: false };
|
|
3255
3435
|
static getDerivedStateFromError() {
|
|
3256
3436
|
return { failed: true };
|
|
@@ -3350,14 +3530,14 @@ function TabStrip({
|
|
|
3350
3530
|
actives
|
|
3351
3531
|
}) {
|
|
3352
3532
|
const canvas = useCanvas();
|
|
3353
|
-
const strip = (0,
|
|
3354
|
-
const list = (0,
|
|
3355
|
-
const [width, setWidth] = (0,
|
|
3356
|
-
const windowStart = (0,
|
|
3357
|
-
const focusAfterMove = (0,
|
|
3358
|
-
const read = (0,
|
|
3533
|
+
const strip = (0, import_react10.useRef)(null);
|
|
3534
|
+
const list = (0, import_react10.useRef)(null);
|
|
3535
|
+
const [width, setWidth] = (0, import_react10.useState)(0);
|
|
3536
|
+
const windowStart = (0, import_react10.useRef)(0);
|
|
3537
|
+
const focusAfterMove = (0, import_react10.useRef)(false);
|
|
3538
|
+
const read = (0, import_react10.useRef)(() => {
|
|
3359
3539
|
});
|
|
3360
|
-
|
|
3540
|
+
useIsoLayoutEffect5(() => {
|
|
3361
3541
|
const el = strip.current;
|
|
3362
3542
|
if (!el) return void 0;
|
|
3363
3543
|
let live = true;
|
|
@@ -3376,10 +3556,10 @@ function TabStrip({
|
|
|
3376
3556
|
if (frame2 && typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(frame2);
|
|
3377
3557
|
};
|
|
3378
3558
|
}, []);
|
|
3379
|
-
|
|
3559
|
+
useIsoLayoutEffect5(() => {
|
|
3380
3560
|
read.current();
|
|
3381
3561
|
}, [tabs.length]);
|
|
3382
|
-
|
|
3562
|
+
useIsoLayoutEffect5(() => {
|
|
3383
3563
|
if (!focusAfterMove.current || !activeItemId) return;
|
|
3384
3564
|
focusAfterMove.current = false;
|
|
3385
3565
|
tabElement(list.current, activeItemId)?.focus();
|
|
@@ -3396,7 +3576,7 @@ function TabStrip({
|
|
|
3396
3576
|
width,
|
|
3397
3577
|
windowStart.current
|
|
3398
3578
|
);
|
|
3399
|
-
|
|
3579
|
+
useIsoLayoutEffect5(() => {
|
|
3400
3580
|
windowStart.current = fit.start;
|
|
3401
3581
|
});
|
|
3402
3582
|
const shown = entries.slice(fit.start, fit.end);
|
|
@@ -3476,8 +3656,8 @@ function tabElement(list, itemId) {
|
|
|
3476
3656
|
function TabListMenu({ tabs, activeItemId, hidden }) {
|
|
3477
3657
|
const canvas = useCanvas();
|
|
3478
3658
|
const { ports, layer } = useCanvasInternals();
|
|
3479
|
-
const blocking = (0,
|
|
3480
|
-
(0,
|
|
3659
|
+
const blocking = (0, import_react10.useRef)(null);
|
|
3660
|
+
(0, import_react10.useEffect)(() => () => blocking.current?.(), []);
|
|
3481
3661
|
const label = `All tabs (${tabs.length})`;
|
|
3482
3662
|
const trigger = (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(CanvasHeaderButton, { className: "mxc-tab-list", label, ...props, children: [
|
|
3483
3663
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mxc-tab-list-count", "aria-hidden": "true", children: hidden }),
|
|
@@ -3589,16 +3769,26 @@ function PaneMenu({
|
|
|
3589
3769
|
canSplit
|
|
3590
3770
|
}) {
|
|
3591
3771
|
const canvas = useCanvas();
|
|
3592
|
-
const { ports, layer, itemMenus } = useCanvasInternals();
|
|
3772
|
+
const { ports, layer, itemMenus, itemOutputs } = useCanvasInternals();
|
|
3593
3773
|
const moveId = tabCount > 1 ? activeItem?.id : void 0;
|
|
3594
|
-
const blocking = (0,
|
|
3595
|
-
(0,
|
|
3774
|
+
const blocking = (0, import_react10.useRef)(null);
|
|
3775
|
+
(0, import_react10.useEffect)(() => () => blocking.current?.(), []);
|
|
3596
3776
|
const buildSections = () => {
|
|
3597
3777
|
const kindItems = kind?.menuItems && kindProps ? safeMenu(() => kind.menuItems?.(kindProps)) : [];
|
|
3598
3778
|
const hostItems = activeItem && ports.itemActions ? safeMenu(() => ports.itemActions?.(activeItem, kind)) : [];
|
|
3599
3779
|
const bodyItems = activeItem ? itemMenus.read(activeItem.id) : [];
|
|
3780
|
+
const outputItems = activeItem ? safeMenu(
|
|
3781
|
+
() => canvasOutputMenu({
|
|
3782
|
+
item: activeItem,
|
|
3783
|
+
kind,
|
|
3784
|
+
title: itemTitle(activeItem, kind),
|
|
3785
|
+
body: itemOutputs.read(activeItem.id),
|
|
3786
|
+
ports: ports.output
|
|
3787
|
+
})
|
|
3788
|
+
) : [];
|
|
3600
3789
|
return [
|
|
3601
3790
|
[...kindItems, ...bodyItems, ...hostItems].map((entry) => ({ ...entry, id: `item:${entry.id}` })),
|
|
3791
|
+
outputItems.map((entry) => ({ ...entry, id: `item:${entry.id}` })),
|
|
3602
3792
|
[
|
|
3603
3793
|
// Only a split that leaves both panes usable (the layout rules' minimums) is offered.
|
|
3604
3794
|
...canSplit && canvas.fitSplit(paneId, "horizontal") === "horizontal" ? [{ id: "split-right", label: "Split right", icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SplitRightIcon, {}), onSelect: () => canvas.splitPane(paneId, "horizontal", moveId) }] : [],
|
|
@@ -3622,8 +3812,14 @@ function PaneMenu({
|
|
|
3622
3812
|
buildSections().forEach((section, i) => {
|
|
3623
3813
|
if (i > 0) entries.push({ type: "separator" });
|
|
3624
3814
|
for (const action of section) {
|
|
3625
|
-
entries.push({
|
|
3626
|
-
|
|
3815
|
+
entries.push({
|
|
3816
|
+
type: "item",
|
|
3817
|
+
id: action.id,
|
|
3818
|
+
label: action.label,
|
|
3819
|
+
...action.destructive ? { destructive: true } : {},
|
|
3820
|
+
...action.disabled ? { disabled: true } : {}
|
|
3821
|
+
});
|
|
3822
|
+
if (!action.disabled) handlers.set(action.id, action.onSelect);
|
|
3627
3823
|
}
|
|
3628
3824
|
});
|
|
3629
3825
|
const anchor = toCanvasRect(event.currentTarget.getBoundingClientRect());
|
|
@@ -3657,10 +3853,20 @@ function MenuSections({ build }) {
|
|
|
3657
3853
|
function MenuSection({ first, actions }) {
|
|
3658
3854
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3659
3855
|
first ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Menu.Separator, { className: "mxc-menu-separator" }),
|
|
3660
|
-
actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3856
|
+
actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3857
|
+
Menu.Item,
|
|
3858
|
+
{
|
|
3859
|
+
onSelect: action.onSelect,
|
|
3860
|
+
disabled: action.disabled ?? false,
|
|
3861
|
+
className: "mxc-menu-item",
|
|
3862
|
+
"data-destructive": action.destructive ? "" : void 0,
|
|
3863
|
+
children: [
|
|
3864
|
+
action.icon,
|
|
3865
|
+
action.label
|
|
3866
|
+
]
|
|
3867
|
+
},
|
|
3868
|
+
action.id
|
|
3869
|
+
))
|
|
3664
3870
|
] });
|
|
3665
3871
|
}
|
|
3666
3872
|
function safeMenu(build) {
|
|
@@ -3674,13 +3880,13 @@ function safeMenu(build) {
|
|
|
3674
3880
|
|
|
3675
3881
|
// src/react/CanvasColumn.tsx
|
|
3676
3882
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
3677
|
-
var
|
|
3883
|
+
var useIsoLayoutEffect6 = typeof window === "undefined" ? import_react11.useEffect : import_react11.useLayoutEffect;
|
|
3678
3884
|
function subscribeViewport(listener) {
|
|
3679
3885
|
window.addEventListener("resize", listener);
|
|
3680
3886
|
return () => window.removeEventListener("resize", listener);
|
|
3681
3887
|
}
|
|
3682
3888
|
function useViewportWidth() {
|
|
3683
|
-
return (0,
|
|
3889
|
+
return (0, import_react11.useSyncExternalStore)(subscribeViewport, () => window.innerWidth, () => 0);
|
|
3684
3890
|
}
|
|
3685
3891
|
function useRegionWidth() {
|
|
3686
3892
|
const viewport = useViewportWidth();
|
|
@@ -3707,11 +3913,11 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3707
3913
|
const region = useRegionWidth();
|
|
3708
3914
|
const viewport = useViewportWidth();
|
|
3709
3915
|
const singlePane = placement === "docked" && viewport > 0 && viewport <= CANVAS_PHONE_MAX_WIDTH;
|
|
3710
|
-
const [dragWidth, setDragWidth] = (0,
|
|
3711
|
-
const [slots] = (0,
|
|
3712
|
-
const ref = (0,
|
|
3916
|
+
const [dragWidth, setDragWidth] = (0, import_react11.useState)(null);
|
|
3917
|
+
const [slots] = (0, import_react11.useState)(createCanvasSlots);
|
|
3918
|
+
const ref = (0, import_react11.useRef)(null);
|
|
3713
3919
|
useRegisterCanvasPresence();
|
|
3714
|
-
(0,
|
|
3920
|
+
(0, import_react11.useEffect)(
|
|
3715
3921
|
() => controller.registerPaneMeasure((paneId) => {
|
|
3716
3922
|
const section = slots.section(paneId);
|
|
3717
3923
|
if (!section?.isConnected) return null;
|
|
@@ -3720,7 +3926,7 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3720
3926
|
}),
|
|
3721
3927
|
[controller, slots]
|
|
3722
3928
|
);
|
|
3723
|
-
(0,
|
|
3929
|
+
(0, import_react11.useEffect)(() => {
|
|
3724
3930
|
const el = ref.current;
|
|
3725
3931
|
if (!el) return void 0;
|
|
3726
3932
|
let frame2 = 0;
|
|
@@ -3794,8 +4000,8 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3794
4000
|
}
|
|
3795
4001
|
function WidthHandle({ width, region, onDrag }) {
|
|
3796
4002
|
const canvas = useCanvas();
|
|
3797
|
-
const start = (0,
|
|
3798
|
-
(0,
|
|
4003
|
+
const start = (0, import_react11.useRef)(null);
|
|
4004
|
+
(0, import_react11.useEffect)(() => () => start.current?.end(), []);
|
|
3799
4005
|
const clamp = (next) => clampDraggedCanvasWidth(next, region, canvas.rules);
|
|
3800
4006
|
const onPointerDown = (event) => {
|
|
3801
4007
|
event.preventDefault();
|
|
@@ -3842,8 +4048,8 @@ function LayoutNodeView({ node }) {
|
|
|
3842
4048
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SplitView, { node });
|
|
3843
4049
|
}
|
|
3844
4050
|
function useMeasuredSize(ref, enabled) {
|
|
3845
|
-
const [size, setSize] = (0,
|
|
3846
|
-
|
|
4051
|
+
const [size, setSize] = (0, import_react11.useState)({ width: 0, height: 0 });
|
|
4052
|
+
useIsoLayoutEffect6(() => {
|
|
3847
4053
|
const el = ref.current;
|
|
3848
4054
|
if (!enabled || !el) return;
|
|
3849
4055
|
const read = () => {
|
|
@@ -3869,8 +4075,8 @@ function childMinimums(node, orientation, rules) {
|
|
|
3869
4075
|
}
|
|
3870
4076
|
function SplitView({ node }) {
|
|
3871
4077
|
const canvas = useCanvas();
|
|
3872
|
-
const ref = (0,
|
|
3873
|
-
const [liveSizes, setLiveSizes] = (0,
|
|
4078
|
+
const ref = (0, import_react11.useRef)(null);
|
|
4079
|
+
const [liveSizes, setLiveSizes] = (0, import_react11.useState)(null);
|
|
3874
4080
|
const measured = useMeasuredSize(ref, canvas.rules.paneMinWidth > 0 || canvas.rules.paneMinHeight > 0);
|
|
3875
4081
|
const stacked = node.orientation === "horizontal" && shouldStackSplit(measured.width, node.children.length, canvas.rules);
|
|
3876
4082
|
const orientation = stacked ? "vertical" : node.orientation;
|