@ai-matrx/canvas 0.9.3 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/dist/react.cjs +342 -135
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +104 -3
- package/dist/react.d.ts +104 -3
- package/dist/react.js +291 -84
- 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;
|
|
@@ -1909,15 +2078,16 @@ function CanvasProvider({
|
|
|
1909
2078
|
dockBack,
|
|
1910
2079
|
showMenu,
|
|
1911
2080
|
overlay,
|
|
1912
|
-
onNativeBodyFrame
|
|
2081
|
+
onNativeBodyFrame,
|
|
2082
|
+
output
|
|
1913
2083
|
}) {
|
|
1914
|
-
const hostPorts = (0,
|
|
1915
|
-
() => ({ itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame }),
|
|
1916
|
-
[itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame]
|
|
2084
|
+
const hostPorts = (0, import_react4.useMemo)(
|
|
2085
|
+
() => ({ itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame, output }),
|
|
2086
|
+
[itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame, output]
|
|
1917
2087
|
);
|
|
1918
|
-
const portsRef = (0,
|
|
2088
|
+
const portsRef = (0, import_react4.useRef)(hostPorts);
|
|
1919
2089
|
portsRef.current = hostPorts;
|
|
1920
|
-
const [{ controller, layer, launcherEntries, itemMenus }] = (0,
|
|
2090
|
+
const [{ controller, layer, launcherEntries, itemMenus, itemOutputs }] = (0, import_react4.useState)(() => ({
|
|
1921
2091
|
controller: createCanvasController({
|
|
1922
2092
|
store: store ?? createCanvasStore(),
|
|
1923
2093
|
persistence: persistence === void 0 ? createLocalStorageCanvasPersistence() : persistence,
|
|
@@ -1932,11 +2102,12 @@ function CanvasProvider({
|
|
|
1932
2102
|
}),
|
|
1933
2103
|
layer: createCanvasLayer(() => portsRef.current),
|
|
1934
2104
|
launcherEntries: createLauncherEntryStore(),
|
|
1935
|
-
itemMenus: createCanvasItemMenus()
|
|
2105
|
+
itemMenus: createCanvasItemMenus(),
|
|
2106
|
+
itemOutputs: createCanvasItemOutputs()
|
|
1936
2107
|
}));
|
|
1937
2108
|
const windowId = controller.windowId;
|
|
1938
|
-
(0,
|
|
1939
|
-
(0,
|
|
2109
|
+
(0, import_react4.useEffect)(() => controller.start(), [controller]);
|
|
2110
|
+
(0, import_react4.useEffect)(() => {
|
|
1940
2111
|
if (!hotkeys) return;
|
|
1941
2112
|
const isMac3 = isMacPlatform();
|
|
1942
2113
|
const applies = (when, event) => {
|
|
@@ -1957,9 +2128,9 @@ function CanvasProvider({
|
|
|
1957
2128
|
window.addEventListener("keydown", onKey);
|
|
1958
2129
|
return () => window.removeEventListener("keydown", onKey);
|
|
1959
2130
|
}, [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]
|
|
2131
|
+
const value = (0, import_react4.useMemo)(
|
|
2132
|
+
() => ({ controller, windowId, ports: hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus, itemOutputs }),
|
|
2133
|
+
[controller, windowId, hostPorts, layer, regionWidth, tabStrip, launcherEntries, itemMenus, itemOutputs]
|
|
1963
2134
|
);
|
|
1964
2135
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(CanvasContext.Provider, { value, children: [
|
|
1965
2136
|
children,
|
|
@@ -1968,14 +2139,14 @@ function CanvasProvider({
|
|
|
1968
2139
|
}
|
|
1969
2140
|
function CanvasWindowScope({ windowId, children }) {
|
|
1970
2141
|
const parent = useCanvasContext();
|
|
1971
|
-
const value = (0,
|
|
2142
|
+
const value = (0, import_react4.useMemo)(() => {
|
|
1972
2143
|
const id = canvasWindowId(windowId);
|
|
1973
2144
|
return { ...parent, windowId: id, controller: parent.controller.forWindow(id) };
|
|
1974
2145
|
}, [parent, windowId]);
|
|
1975
2146
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CanvasContext.Provider, { value, children });
|
|
1976
2147
|
}
|
|
1977
2148
|
function useCanvasContext() {
|
|
1978
|
-
const value = (0,
|
|
2149
|
+
const value = (0, import_react4.useContext)(CanvasContext);
|
|
1979
2150
|
if (!value) throw new Error("[@ai-matrx/canvas] useCanvas* must be used inside <CanvasProvider>.");
|
|
1980
2151
|
return value;
|
|
1981
2152
|
}
|
|
@@ -1983,16 +2154,16 @@ function useCanvasInternals() {
|
|
|
1983
2154
|
return useCanvasContext();
|
|
1984
2155
|
}
|
|
1985
2156
|
function useOptionalCanvasInternals() {
|
|
1986
|
-
return (0,
|
|
2157
|
+
return (0, import_react4.useContext)(CanvasContext);
|
|
1987
2158
|
}
|
|
1988
2159
|
function useCanvas() {
|
|
1989
2160
|
return useCanvasContext().controller;
|
|
1990
2161
|
}
|
|
1991
2162
|
function useOptionalCanvas() {
|
|
1992
|
-
return (0,
|
|
2163
|
+
return (0, import_react4.useContext)(CanvasContext)?.controller ?? null;
|
|
1993
2164
|
}
|
|
1994
2165
|
function useCanvasWindowId() {
|
|
1995
|
-
return (0,
|
|
2166
|
+
return (0, import_react4.useContext)(CanvasContext)?.windowId ?? CANVAS_MAIN_WINDOW;
|
|
1996
2167
|
}
|
|
1997
2168
|
function useCanvasHostPorts() {
|
|
1998
2169
|
return useCanvasContext().ports;
|
|
@@ -2001,16 +2172,16 @@ function useCanvasNativeBodies() {
|
|
|
2001
2172
|
return useCanvasContext().layer.native;
|
|
2002
2173
|
}
|
|
2003
2174
|
function useRegisterCanvasPresence() {
|
|
2004
|
-
const context = (0,
|
|
2175
|
+
const context = (0, import_react4.useContext)(CanvasContext);
|
|
2005
2176
|
const controller = context?.controller;
|
|
2006
2177
|
const windowId = context?.windowId;
|
|
2007
|
-
(0,
|
|
2178
|
+
(0, import_react4.useEffect)(() => controller?.registerPresentation(windowId), [controller, windowId]);
|
|
2008
2179
|
}
|
|
2009
2180
|
var noPresence = () => () => void 0;
|
|
2010
2181
|
function useCanvasIsPresented() {
|
|
2011
|
-
const context = (0,
|
|
2182
|
+
const context = (0, import_react4.useContext)(CanvasContext);
|
|
2012
2183
|
const controller = context?.controller;
|
|
2013
|
-
return (0,
|
|
2184
|
+
return (0, import_react4.useSyncExternalStore)(
|
|
2014
2185
|
controller ? controller.subscribePresentation : noPresence,
|
|
2015
2186
|
() => controller?.isPresented() ?? false,
|
|
2016
2187
|
() => false
|
|
@@ -2018,7 +2189,7 @@ function useCanvasIsPresented() {
|
|
|
2018
2189
|
}
|
|
2019
2190
|
function useCanvasState(selector) {
|
|
2020
2191
|
const { store } = useCanvasContext().controller;
|
|
2021
|
-
return (0,
|
|
2192
|
+
return (0, import_react4.useSyncExternalStore)(
|
|
2022
2193
|
store.subscribe,
|
|
2023
2194
|
() => selector(store.getState()),
|
|
2024
2195
|
() => selector(store.getState())
|
|
@@ -2026,9 +2197,9 @@ function useCanvasState(selector) {
|
|
|
2026
2197
|
}
|
|
2027
2198
|
var NO_SUBSCRIPTION = () => () => void 0;
|
|
2028
2199
|
function useOptionalCanvasState(selector, fallback) {
|
|
2029
|
-
const store = (0,
|
|
2200
|
+
const store = (0, import_react4.useContext)(CanvasContext)?.controller.store;
|
|
2030
2201
|
const read = () => store ? selector(store.getState()) : fallback;
|
|
2031
|
-
return (0,
|
|
2202
|
+
return (0, import_react4.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, read, read);
|
|
2032
2203
|
}
|
|
2033
2204
|
function useCanvasKindToggle(input) {
|
|
2034
2205
|
const controller = useCanvasContext().controller;
|
|
@@ -2042,28 +2213,28 @@ function useCanvasKindToggle(input) {
|
|
|
2042
2213
|
};
|
|
2043
2214
|
}
|
|
2044
2215
|
function useCanvasKinds() {
|
|
2045
|
-
(0,
|
|
2216
|
+
(0, import_react4.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
|
|
2046
2217
|
return listCanvasKinds();
|
|
2047
2218
|
}
|
|
2048
2219
|
function useCanvasKind(id) {
|
|
2049
|
-
(0,
|
|
2220
|
+
(0, import_react4.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
|
|
2050
2221
|
return getCanvasKind(id);
|
|
2051
2222
|
}
|
|
2052
2223
|
var NO_ENTRIES = Object.freeze([]);
|
|
2053
2224
|
var noEntries = () => NO_ENTRIES;
|
|
2054
2225
|
function useCanvasLauncherEntry(entry) {
|
|
2055
|
-
const store = (0,
|
|
2226
|
+
const store = (0, import_react4.useContext)(CanvasContext)?.launcherEntries;
|
|
2056
2227
|
const fingerprint = JSON.stringify([entry.kind, entry.key, entry.title ?? null, entry.data ?? null]);
|
|
2057
2228
|
const icon = entry.icon;
|
|
2058
|
-
(0,
|
|
2229
|
+
(0, import_react4.useEffect)(() => {
|
|
2059
2230
|
if (!store) return void 0;
|
|
2060
2231
|
const [kind, key, title, data] = JSON.parse(fingerprint);
|
|
2061
2232
|
return store.add({ kind, key, title, data, ...icon ? { icon } : {} });
|
|
2062
2233
|
}, [store, fingerprint, icon]);
|
|
2063
2234
|
}
|
|
2064
2235
|
function useCanvasLauncherEntries() {
|
|
2065
|
-
const store = (0,
|
|
2066
|
-
const all = (0,
|
|
2236
|
+
const store = (0, import_react4.useContext)(CanvasContext)?.launcherEntries;
|
|
2237
|
+
const all = (0, import_react4.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, store ? store.list : noEntries, store ? store.list : noEntries);
|
|
2067
2238
|
const seen = /* @__PURE__ */ new Set();
|
|
2068
2239
|
const out = [];
|
|
2069
2240
|
for (let i = all.length - 1; i >= 0; i -= 1) {
|
|
@@ -2076,14 +2247,14 @@ function useCanvasLauncherEntries() {
|
|
|
2076
2247
|
}
|
|
2077
2248
|
|
|
2078
2249
|
// src/react/CanvasColumn.tsx
|
|
2079
|
-
var
|
|
2080
|
-
var import_tap_target = require("@ai-matrx/tap-target");
|
|
2250
|
+
var import_react11 = require("react");
|
|
2251
|
+
var import_tap_target = require("@ai-matrx/design-system/tap-target");
|
|
2081
2252
|
|
|
2082
2253
|
// src/react/bodies.tsx
|
|
2083
|
-
var
|
|
2254
|
+
var import_react9 = require("react");
|
|
2084
2255
|
|
|
2085
2256
|
// src/react/chrome.tsx
|
|
2086
|
-
var
|
|
2257
|
+
var import_react5 = require("react");
|
|
2087
2258
|
|
|
2088
2259
|
// src/react/icons.tsx
|
|
2089
2260
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
@@ -2185,11 +2356,11 @@ var ChevronDownIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Glyph,
|
|
|
2185
2356
|
|
|
2186
2357
|
// src/react/chrome.tsx
|
|
2187
2358
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2188
|
-
var
|
|
2359
|
+
var useIsoLayoutEffect3 = typeof window === "undefined" ? import_react5.useEffect : import_react5.useLayoutEffect;
|
|
2189
2360
|
function useTruncated(title) {
|
|
2190
|
-
const ref = (0,
|
|
2191
|
-
const [truncated, setTruncated] = (0,
|
|
2192
|
-
|
|
2361
|
+
const ref = (0, import_react5.useRef)(null);
|
|
2362
|
+
const [truncated, setTruncated] = (0, import_react5.useState)(false);
|
|
2363
|
+
useIsoLayoutEffect3(() => {
|
|
2193
2364
|
const el = ref.current;
|
|
2194
2365
|
if (!el) return void 0;
|
|
2195
2366
|
const check = () => setTruncated(el.scrollWidth - el.clientWidth > 1);
|
|
@@ -2203,15 +2374,15 @@ function useTruncated(title) {
|
|
|
2203
2374
|
var cx = (...names) => names.filter(Boolean).join(" ");
|
|
2204
2375
|
function useTooltip(text) {
|
|
2205
2376
|
const internals = useOptionalCanvasInternals();
|
|
2206
|
-
const timer = (0,
|
|
2207
|
-
const hide = (0,
|
|
2377
|
+
const timer = (0, import_react5.useRef)(null);
|
|
2378
|
+
const hide = (0, import_react5.useRef)(null);
|
|
2208
2379
|
const close = () => {
|
|
2209
2380
|
if (timer.current) clearTimeout(timer.current);
|
|
2210
2381
|
timer.current = null;
|
|
2211
2382
|
hide.current?.();
|
|
2212
2383
|
hide.current = null;
|
|
2213
2384
|
};
|
|
2214
|
-
(0,
|
|
2385
|
+
(0, import_react5.useEffect)(() => close, []);
|
|
2215
2386
|
if (!text) return { close, handlers: {} };
|
|
2216
2387
|
if (!internals) return { close, handlers: { title: text } };
|
|
2217
2388
|
const open = (element, delay) => {
|
|
@@ -2237,7 +2408,7 @@ function useTooltip(text) {
|
|
|
2237
2408
|
}
|
|
2238
2409
|
};
|
|
2239
2410
|
}
|
|
2240
|
-
var CanvasHeaderButton = (0,
|
|
2411
|
+
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
2412
|
const tooltip = useTooltip(shortcut ? `${label} (${shortcut})` : label);
|
|
2242
2413
|
const own = tooltip.handlers;
|
|
2243
2414
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -2282,12 +2453,12 @@ var CanvasHeaderButton = (0, import_react4.forwardRef)(function CanvasHeaderButt
|
|
|
2282
2453
|
}
|
|
2283
2454
|
);
|
|
2284
2455
|
});
|
|
2285
|
-
var CanvasMenuTrigger = (0,
|
|
2456
|
+
var CanvasMenuTrigger = (0, import_react5.forwardRef)(
|
|
2286
2457
|
function CanvasMenuTrigger2({ label = "More", ...props }, ref) {
|
|
2287
2458
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CanvasHeaderButton, { ref, label, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreIcon, {}) });
|
|
2288
2459
|
}
|
|
2289
2460
|
);
|
|
2290
|
-
var CanvasPanel = (0,
|
|
2461
|
+
var CanvasPanel = (0, import_react5.forwardRef)(function CanvasPanel2({
|
|
2291
2462
|
panelId,
|
|
2292
2463
|
title,
|
|
2293
2464
|
leading,
|
|
@@ -2337,7 +2508,7 @@ var CanvasPanel = (0, import_react4.forwardRef)(function CanvasPanel2({
|
|
|
2337
2508
|
function CanvasPanelEmpty({ children, className }) {
|
|
2338
2509
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { "data-slot": "canvas-panel-empty", className: cx("mxc-empty-line", className), children });
|
|
2339
2510
|
}
|
|
2340
|
-
var CanvasTab = (0,
|
|
2511
|
+
var CanvasTab = (0, import_react5.forwardRef)(function CanvasTab2({ title, icon, note, active, onSelect, onClose, className, onKeyDown, onClick, ...rest }, ref) {
|
|
2341
2512
|
const shown = title || "New tab";
|
|
2342
2513
|
const name = useTruncated(shown);
|
|
2343
2514
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -2406,9 +2577,9 @@ function BrowserTabs({ tabs, activeId, onSelect, onClose, onNew, newLabel = "New
|
|
|
2406
2577
|
] });
|
|
2407
2578
|
}
|
|
2408
2579
|
function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload, onNavigate, trailing, className }) {
|
|
2409
|
-
const [draft, setDraft] = (0,
|
|
2410
|
-
const [editing, setEditing] = (0,
|
|
2411
|
-
(0,
|
|
2580
|
+
const [draft, setDraft] = (0, import_react5.useState)(url);
|
|
2581
|
+
const [editing, setEditing] = (0, import_react5.useState)(false);
|
|
2582
|
+
(0, import_react5.useEffect)(() => {
|
|
2412
2583
|
if (!editing) setDraft(url);
|
|
2413
2584
|
}, [url, editing]);
|
|
2414
2585
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { "data-slot": "browser-bar", className: cx("mxc-browser-bar", className), children: [
|
|
@@ -2450,15 +2621,15 @@ function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload,
|
|
|
2450
2621
|
}
|
|
2451
2622
|
|
|
2452
2623
|
// src/react/dnd.ts
|
|
2453
|
-
var
|
|
2624
|
+
var import_react6 = require("react");
|
|
2454
2625
|
var CANVAS_DRAG_MIME = "application/x-matrx-canvas-item";
|
|
2455
2626
|
function useTabDrag(itemId, title) {
|
|
2456
2627
|
const { layer } = useCanvasInternals();
|
|
2457
|
-
const active = (0,
|
|
2628
|
+
const active = (0, import_react6.useRef)([]);
|
|
2458
2629
|
const end = () => {
|
|
2459
2630
|
for (const dispose of active.current.splice(0)) dispose();
|
|
2460
2631
|
};
|
|
2461
|
-
(0,
|
|
2632
|
+
(0, import_react6.useEffect)(() => end, []);
|
|
2462
2633
|
return {
|
|
2463
2634
|
draggable: true,
|
|
2464
2635
|
onDragStart: (event) => {
|
|
@@ -2473,8 +2644,8 @@ function useTabDrag(itemId, title) {
|
|
|
2473
2644
|
function usePaneDrop(paneId, getOutline) {
|
|
2474
2645
|
const canvas = useCanvas();
|
|
2475
2646
|
const { layer } = useCanvasInternals();
|
|
2476
|
-
const drop = (0,
|
|
2477
|
-
(0,
|
|
2647
|
+
const drop = (0, import_react6.useRef)(null);
|
|
2648
|
+
(0, import_react6.useEffect)(() => () => drop.current?.(), []);
|
|
2478
2649
|
const hide = () => {
|
|
2479
2650
|
drop.current?.();
|
|
2480
2651
|
drop.current = null;
|
|
@@ -2597,6 +2768,10 @@ function EmptyPaneLauncher({ paneId }) {
|
|
|
2597
2768
|
}
|
|
2598
2769
|
var CANVAS_LAUNCHER_KIND_DEFINITION = {
|
|
2599
2770
|
id: CANVAS_LAUNCHER_KIND,
|
|
2771
|
+
surface: "dom",
|
|
2772
|
+
// A launcher is a menu of things to open — nothing to print or capture.
|
|
2773
|
+
print: false,
|
|
2774
|
+
capture: false,
|
|
2600
2775
|
label: "New tab",
|
|
2601
2776
|
icon: LayoutGridIcon,
|
|
2602
2777
|
component: LauncherBody
|
|
@@ -2610,14 +2785,14 @@ function resolveItemKind(kindId, lookup) {
|
|
|
2610
2785
|
}
|
|
2611
2786
|
|
|
2612
2787
|
// src/react/presentation.tsx
|
|
2613
|
-
var
|
|
2614
|
-
var CanvasPresentationContext = (0,
|
|
2788
|
+
var import_react7 = require("react");
|
|
2789
|
+
var CanvasPresentationContext = (0, import_react7.createContext)(null);
|
|
2615
2790
|
function useCanvasPresentation() {
|
|
2616
|
-
return (0,
|
|
2791
|
+
return (0, import_react7.useContext)(CanvasPresentationContext);
|
|
2617
2792
|
}
|
|
2618
2793
|
|
|
2619
2794
|
// src/react/slots.ts
|
|
2620
|
-
var
|
|
2795
|
+
var import_react8 = require("react");
|
|
2621
2796
|
var ZERO = Object.freeze({ width: 0, height: 0 });
|
|
2622
2797
|
function createCanvasSlots() {
|
|
2623
2798
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -2684,20 +2859,20 @@ function createCanvasSlots() {
|
|
|
2684
2859
|
}
|
|
2685
2860
|
};
|
|
2686
2861
|
}
|
|
2687
|
-
var CanvasSlotsContext = (0,
|
|
2862
|
+
var CanvasSlotsContext = (0, import_react8.createContext)(null);
|
|
2688
2863
|
function useCanvasSlots() {
|
|
2689
|
-
return (0,
|
|
2864
|
+
return (0, import_react8.useContext)(CanvasSlotsContext);
|
|
2690
2865
|
}
|
|
2691
|
-
var CanvasSinglePaneContext = (0,
|
|
2866
|
+
var CanvasSinglePaneContext = (0, import_react8.createContext)(false);
|
|
2692
2867
|
function useCanvasSinglePane() {
|
|
2693
|
-
return (0,
|
|
2868
|
+
return (0, import_react8.useContext)(CanvasSinglePaneContext);
|
|
2694
2869
|
}
|
|
2695
|
-
var CanvasWindowTabsContext = (0,
|
|
2870
|
+
var CanvasWindowTabsContext = (0, import_react8.createContext)(false);
|
|
2696
2871
|
function useCanvasWindowTabs() {
|
|
2697
|
-
return (0,
|
|
2872
|
+
return (0, import_react8.useContext)(CanvasWindowTabsContext);
|
|
2698
2873
|
}
|
|
2699
2874
|
function useSlotSize(slots, paneId) {
|
|
2700
|
-
return (0,
|
|
2875
|
+
return (0, import_react8.useSyncExternalStore)(
|
|
2701
2876
|
slots.subscribe,
|
|
2702
2877
|
() => slots.size(paneId),
|
|
2703
2878
|
() => ZERO
|
|
@@ -2706,12 +2881,12 @@ function useSlotSize(slots, paneId) {
|
|
|
2706
2881
|
|
|
2707
2882
|
// src/react/bodies.tsx
|
|
2708
2883
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2709
|
-
var
|
|
2884
|
+
var useIsoLayoutEffect4 = typeof window === "undefined" ? import_react9.useEffect : import_react9.useLayoutEffect;
|
|
2710
2885
|
var LAZY = /* @__PURE__ */ Symbol.for("ai-matrx.canvas.lazy");
|
|
2711
2886
|
function kindComponent(kind) {
|
|
2712
2887
|
if (kind.component) return kind.component;
|
|
2713
2888
|
const holder = kind;
|
|
2714
|
-
if (!holder[LAZY] && kind.load) holder[LAZY] = (0,
|
|
2889
|
+
if (!holder[LAZY] && kind.load) holder[LAZY] = (0, import_react9.lazy)(kind.load);
|
|
2715
2890
|
return holder[LAZY] ?? null;
|
|
2716
2891
|
}
|
|
2717
2892
|
function resetKindComponent(kind) {
|
|
@@ -2719,7 +2894,7 @@ function resetKindComponent(kind) {
|
|
|
2719
2894
|
}
|
|
2720
2895
|
function usePanePresentation(slots, paneId, isFullscreen, paneCount) {
|
|
2721
2896
|
const size = useSlotSize(slots, paneId);
|
|
2722
|
-
return (0,
|
|
2897
|
+
return (0, import_react9.useMemo)(
|
|
2723
2898
|
() => canvasPresentation({ width: size.width, height: size.height, isFullscreen, paneCount }),
|
|
2724
2899
|
[size.width, size.height, isFullscreen, paneCount]
|
|
2725
2900
|
);
|
|
@@ -2826,12 +3001,12 @@ function CanvasBodyLayer() {
|
|
|
2826
3001
|
const slots = useCanvasSlots();
|
|
2827
3002
|
const signature = useCanvasState((s) => layerSignature(s, windowId));
|
|
2828
3003
|
const single = useCanvasSinglePane();
|
|
2829
|
-
const root = (0,
|
|
2830
|
-
const [placement] = (0,
|
|
3004
|
+
const root = (0, import_react9.useRef)(null);
|
|
3005
|
+
const [placement] = (0, import_react9.useState)(
|
|
2831
3006
|
() => slots ? createPlacement(() => root.current, slots, () => layer.native.remeasure()) : null
|
|
2832
3007
|
);
|
|
2833
|
-
|
|
2834
|
-
|
|
3008
|
+
useIsoLayoutEffect4(() => placement?.place());
|
|
3009
|
+
useIsoLayoutEffect4(() => slots && placement ? slots.subscribe(placement.place) : void 0, [slots, placement]);
|
|
2835
3010
|
const shape = parseSignature(signature);
|
|
2836
3011
|
if (!slots || !placement || !shape) return null;
|
|
2837
3012
|
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 +3059,7 @@ function stepAsItem(step, openedAt) {
|
|
|
2884
3059
|
...step.instance ? { instance: step.instance } : {}
|
|
2885
3060
|
};
|
|
2886
3061
|
}
|
|
2887
|
-
var BodyHost = (0,
|
|
3062
|
+
var BodyHost = (0, import_react9.memo)(function BodyHost2({
|
|
2888
3063
|
hostId,
|
|
2889
3064
|
itemId,
|
|
2890
3065
|
kept,
|
|
@@ -2904,20 +3079,26 @@ var BodyHost = (0, import_react8.memo)(function BodyHost2({
|
|
|
2904
3079
|
return ownerItem ? keptCanvasSteps(ownerItem).find((e) => e.instance === hostId) : void 0;
|
|
2905
3080
|
});
|
|
2906
3081
|
const owner = useCanvasState((s) => kept ? s.items[itemId]?.openedAt : void 0);
|
|
2907
|
-
const keptItem = (0,
|
|
3082
|
+
const keptItem = (0, import_react9.useMemo)(() => step ? stepAsItem(step, owner ?? 0) : void 0, [step, owner]);
|
|
2908
3083
|
const item = kept ? keptItem : live;
|
|
2909
3084
|
const kind = useItemKind(item?.kind ?? "");
|
|
2910
|
-
const element = (0,
|
|
2911
|
-
const [everShown, setEverShown] = (0,
|
|
3085
|
+
const element = (0, import_react9.useRef)(null);
|
|
3086
|
+
const [everShown, setEverShown] = (0, import_react9.useState)(visible);
|
|
2912
3087
|
if (visible && !everShown) setEverShown(true);
|
|
2913
3088
|
const mounted = kind?.unmountWhenHidden ? visible : everShown;
|
|
2914
3089
|
const presentation = usePanePresentation(slots, paneId, isFullscreen, paneCount);
|
|
2915
3090
|
const drop = usePaneDrop(paneId, () => slots.section(paneId));
|
|
2916
|
-
|
|
3091
|
+
useIsoLayoutEffect4(() => {
|
|
2917
3092
|
const el = element.current;
|
|
2918
3093
|
if (!placement || !el) return void 0;
|
|
2919
3094
|
return placement.register(hostId, { element: el, paneId });
|
|
2920
3095
|
}, [placement, hostId, paneId]);
|
|
3096
|
+
const domSurface = kind?.surface === "dom" && mounted && !kept;
|
|
3097
|
+
(0, import_react9.useEffect)(() => {
|
|
3098
|
+
if (process.env.NODE_ENV === "production" || !domSurface || !kind) return void 0;
|
|
3099
|
+
const el = element.current;
|
|
3100
|
+
return el ? watchDomSurface(el, kind.id) : void 0;
|
|
3101
|
+
}, [domSurface, kind]);
|
|
2921
3102
|
if (!item) return null;
|
|
2922
3103
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2923
3104
|
"div",
|
|
@@ -2979,7 +3160,7 @@ function ItemContent({
|
|
|
2979
3160
|
}
|
|
2980
3161
|
return rendered;
|
|
2981
3162
|
}
|
|
2982
|
-
var Rendered = (0,
|
|
3163
|
+
var Rendered = (0, import_react9.memo)(function Rendered2({
|
|
2983
3164
|
kind,
|
|
2984
3165
|
item,
|
|
2985
3166
|
paneId,
|
|
@@ -2990,17 +3171,17 @@ var Rendered = (0, import_react8.memo)(function Rendered2({
|
|
|
2990
3171
|
presentation
|
|
2991
3172
|
}) {
|
|
2992
3173
|
const props = { item, data: item.data, paneId, isFocused, isVisible, canvas, windowId, presentation };
|
|
2993
|
-
const [attempt, setAttempt] = (0,
|
|
3174
|
+
const [attempt, setAttempt] = (0, import_react9.useState)(0);
|
|
2994
3175
|
const retry = () => {
|
|
2995
3176
|
resetKindComponent(kind);
|
|
2996
3177
|
setAttempt((n) => n + 1);
|
|
2997
3178
|
};
|
|
2998
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemBoundary, { item, onClose: () => canvas.close(item.id), onRetry: retry, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3179
|
+
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
3180
|
});
|
|
3000
3181
|
var CANVAS_BODY_STALL_MS = 2e4;
|
|
3001
3182
|
function LoadingBody({ onRetry, onClose }) {
|
|
3002
|
-
const [stalled, setStalled] = (0,
|
|
3003
|
-
(0,
|
|
3183
|
+
const [stalled, setStalled] = (0, import_react9.useState)(false);
|
|
3184
|
+
(0, import_react9.useEffect)(() => {
|
|
3004
3185
|
const timer = setTimeout(() => setStalled(true), CANVAS_BODY_STALL_MS);
|
|
3005
3186
|
return () => clearTimeout(timer);
|
|
3006
3187
|
}, []);
|
|
@@ -3014,8 +3195,8 @@ function KindRender({ kind, props }) {
|
|
|
3014
3195
|
}
|
|
3015
3196
|
function NativeBody({ itemId, windowId, visible, children }) {
|
|
3016
3197
|
const { layer } = useCanvasInternals();
|
|
3017
|
-
const ref = (0,
|
|
3018
|
-
const measure = (0,
|
|
3198
|
+
const ref = (0, import_react9.useRef)(null);
|
|
3199
|
+
const measure = (0, import_react9.useRef)(() => void 0);
|
|
3019
3200
|
measure.current = () => {
|
|
3020
3201
|
const el = ref.current;
|
|
3021
3202
|
const box = visible && el?.isConnected ? el.getBoundingClientRect() : null;
|
|
@@ -3026,8 +3207,8 @@ function NativeBody({ itemId, windowId, visible, children }) {
|
|
|
3026
3207
|
const rect = { ...toCanvasRect(box), devicePixelRatio: window.devicePixelRatio || 1 };
|
|
3027
3208
|
layer.native.report(itemId, rect, { visible: !layer.isBlocked(), windowId });
|
|
3028
3209
|
};
|
|
3029
|
-
|
|
3030
|
-
|
|
3210
|
+
useIsoLayoutEffect4(() => measure.current());
|
|
3211
|
+
useIsoLayoutEffect4(() => {
|
|
3031
3212
|
const el = ref.current;
|
|
3032
3213
|
const run = () => measure.current();
|
|
3033
3214
|
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(run);
|
|
@@ -3053,7 +3234,7 @@ function ItemProblem({ message, onClose, onRetry }) {
|
|
|
3053
3234
|
] })
|
|
3054
3235
|
] });
|
|
3055
3236
|
}
|
|
3056
|
-
var ItemBoundary = class extends
|
|
3237
|
+
var ItemBoundary = class extends import_react9.Component {
|
|
3057
3238
|
state = { error: null };
|
|
3058
3239
|
static getDerivedStateFromError(error) {
|
|
3059
3240
|
return { error };
|
|
@@ -3097,10 +3278,10 @@ function beginCanvasResize(mode) {
|
|
|
3097
3278
|
}
|
|
3098
3279
|
|
|
3099
3280
|
// src/react/CanvasPane.tsx
|
|
3100
|
-
var
|
|
3281
|
+
var import_react10 = require("react");
|
|
3101
3282
|
var Menu = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
|
|
3102
3283
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3103
|
-
var
|
|
3284
|
+
var useIsoLayoutEffect5 = typeof window === "undefined" ? import_react10.useEffect : import_react10.useLayoutEffect;
|
|
3104
3285
|
function itemTitle(item, kind) {
|
|
3105
3286
|
if (item.title) return item.title;
|
|
3106
3287
|
if (item.kind === CANVAS_LAUNCHER_KIND) return "New tab";
|
|
@@ -3151,7 +3332,7 @@ function CanvasPaneView({ paneId }) {
|
|
|
3151
3332
|
const canvas = useCanvas();
|
|
3152
3333
|
const { windowId, tabStrip } = useCanvasInternals();
|
|
3153
3334
|
const columnSlots = useCanvasSlots();
|
|
3154
|
-
const [ownSlots] = (0,
|
|
3335
|
+
const [ownSlots] = (0, import_react10.useState)(createCanvasSlots);
|
|
3155
3336
|
const slots = columnSlots ?? ownSlots;
|
|
3156
3337
|
const pane = useCanvasState((s) => s.panes[paneId]);
|
|
3157
3338
|
const active = useCanvasState((s) => {
|
|
@@ -3169,11 +3350,11 @@ function CanvasPaneView({ paneId }) {
|
|
|
3169
3350
|
const singlePane = useCanvasSinglePane();
|
|
3170
3351
|
const inWindowStrip = useCanvasWindowTabs() && !singlePane;
|
|
3171
3352
|
const windowTabs = useCanvasState((s) => singlePane ? windowTabsSignature(s, windowId) : "");
|
|
3172
|
-
const sectionRef = (0,
|
|
3173
|
-
const bodyRef = (0,
|
|
3353
|
+
const sectionRef = (0, import_react10.useRef)(null);
|
|
3354
|
+
const bodyRef = (0, import_react10.useRef)(null);
|
|
3174
3355
|
const presentation = usePanePresentation(slots, paneId, isFullscreen, paneCount);
|
|
3175
3356
|
const drop = usePaneDrop(paneId, () => sectionRef.current);
|
|
3176
|
-
|
|
3357
|
+
useIsoLayoutEffect5(() => {
|
|
3177
3358
|
const body = bodyRef.current;
|
|
3178
3359
|
const section = sectionRef.current;
|
|
3179
3360
|
if (body) slots.set(paneId, body);
|
|
@@ -3250,7 +3431,7 @@ function CanvasPaneView({ paneId }) {
|
|
|
3250
3431
|
}
|
|
3251
3432
|
);
|
|
3252
3433
|
}
|
|
3253
|
-
var ToolbarBoundary = class extends
|
|
3434
|
+
var ToolbarBoundary = class extends import_react10.Component {
|
|
3254
3435
|
state = { failed: false };
|
|
3255
3436
|
static getDerivedStateFromError() {
|
|
3256
3437
|
return { failed: true };
|
|
@@ -3350,14 +3531,14 @@ function TabStrip({
|
|
|
3350
3531
|
actives
|
|
3351
3532
|
}) {
|
|
3352
3533
|
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,
|
|
3534
|
+
const strip = (0, import_react10.useRef)(null);
|
|
3535
|
+
const list = (0, import_react10.useRef)(null);
|
|
3536
|
+
const [width, setWidth] = (0, import_react10.useState)(0);
|
|
3537
|
+
const windowStart = (0, import_react10.useRef)(0);
|
|
3538
|
+
const focusAfterMove = (0, import_react10.useRef)(false);
|
|
3539
|
+
const read = (0, import_react10.useRef)(() => {
|
|
3359
3540
|
});
|
|
3360
|
-
|
|
3541
|
+
useIsoLayoutEffect5(() => {
|
|
3361
3542
|
const el = strip.current;
|
|
3362
3543
|
if (!el) return void 0;
|
|
3363
3544
|
let live = true;
|
|
@@ -3376,10 +3557,10 @@ function TabStrip({
|
|
|
3376
3557
|
if (frame2 && typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(frame2);
|
|
3377
3558
|
};
|
|
3378
3559
|
}, []);
|
|
3379
|
-
|
|
3560
|
+
useIsoLayoutEffect5(() => {
|
|
3380
3561
|
read.current();
|
|
3381
3562
|
}, [tabs.length]);
|
|
3382
|
-
|
|
3563
|
+
useIsoLayoutEffect5(() => {
|
|
3383
3564
|
if (!focusAfterMove.current || !activeItemId) return;
|
|
3384
3565
|
focusAfterMove.current = false;
|
|
3385
3566
|
tabElement(list.current, activeItemId)?.focus();
|
|
@@ -3396,7 +3577,7 @@ function TabStrip({
|
|
|
3396
3577
|
width,
|
|
3397
3578
|
windowStart.current
|
|
3398
3579
|
);
|
|
3399
|
-
|
|
3580
|
+
useIsoLayoutEffect5(() => {
|
|
3400
3581
|
windowStart.current = fit.start;
|
|
3401
3582
|
});
|
|
3402
3583
|
const shown = entries.slice(fit.start, fit.end);
|
|
@@ -3476,8 +3657,8 @@ function tabElement(list, itemId) {
|
|
|
3476
3657
|
function TabListMenu({ tabs, activeItemId, hidden }) {
|
|
3477
3658
|
const canvas = useCanvas();
|
|
3478
3659
|
const { ports, layer } = useCanvasInternals();
|
|
3479
|
-
const blocking = (0,
|
|
3480
|
-
(0,
|
|
3660
|
+
const blocking = (0, import_react10.useRef)(null);
|
|
3661
|
+
(0, import_react10.useEffect)(() => () => blocking.current?.(), []);
|
|
3481
3662
|
const label = `All tabs (${tabs.length})`;
|
|
3482
3663
|
const trigger = (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(CanvasHeaderButton, { className: "mxc-tab-list", label, ...props, children: [
|
|
3483
3664
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mxc-tab-list-count", "aria-hidden": "true", children: hidden }),
|
|
@@ -3589,16 +3770,26 @@ function PaneMenu({
|
|
|
3589
3770
|
canSplit
|
|
3590
3771
|
}) {
|
|
3591
3772
|
const canvas = useCanvas();
|
|
3592
|
-
const { ports, layer, itemMenus } = useCanvasInternals();
|
|
3773
|
+
const { ports, layer, itemMenus, itemOutputs } = useCanvasInternals();
|
|
3593
3774
|
const moveId = tabCount > 1 ? activeItem?.id : void 0;
|
|
3594
|
-
const blocking = (0,
|
|
3595
|
-
(0,
|
|
3775
|
+
const blocking = (0, import_react10.useRef)(null);
|
|
3776
|
+
(0, import_react10.useEffect)(() => () => blocking.current?.(), []);
|
|
3596
3777
|
const buildSections = () => {
|
|
3597
3778
|
const kindItems = kind?.menuItems && kindProps ? safeMenu(() => kind.menuItems?.(kindProps)) : [];
|
|
3598
3779
|
const hostItems = activeItem && ports.itemActions ? safeMenu(() => ports.itemActions?.(activeItem, kind)) : [];
|
|
3599
3780
|
const bodyItems = activeItem ? itemMenus.read(activeItem.id) : [];
|
|
3781
|
+
const outputItems = activeItem ? safeMenu(
|
|
3782
|
+
() => canvasOutputMenu({
|
|
3783
|
+
item: activeItem,
|
|
3784
|
+
kind,
|
|
3785
|
+
title: itemTitle(activeItem, kind),
|
|
3786
|
+
body: itemOutputs.read(activeItem.id),
|
|
3787
|
+
ports: ports.output
|
|
3788
|
+
})
|
|
3789
|
+
) : [];
|
|
3600
3790
|
return [
|
|
3601
3791
|
[...kindItems, ...bodyItems, ...hostItems].map((entry) => ({ ...entry, id: `item:${entry.id}` })),
|
|
3792
|
+
outputItems.map((entry) => ({ ...entry, id: `item:${entry.id}` })),
|
|
3602
3793
|
[
|
|
3603
3794
|
// Only a split that leaves both panes usable (the layout rules' minimums) is offered.
|
|
3604
3795
|
...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 +3813,14 @@ function PaneMenu({
|
|
|
3622
3813
|
buildSections().forEach((section, i) => {
|
|
3623
3814
|
if (i > 0) entries.push({ type: "separator" });
|
|
3624
3815
|
for (const action of section) {
|
|
3625
|
-
entries.push({
|
|
3626
|
-
|
|
3816
|
+
entries.push({
|
|
3817
|
+
type: "item",
|
|
3818
|
+
id: action.id,
|
|
3819
|
+
label: action.label,
|
|
3820
|
+
...action.destructive ? { destructive: true } : {},
|
|
3821
|
+
...action.disabled ? { disabled: true } : {}
|
|
3822
|
+
});
|
|
3823
|
+
if (!action.disabled) handlers.set(action.id, action.onSelect);
|
|
3627
3824
|
}
|
|
3628
3825
|
});
|
|
3629
3826
|
const anchor = toCanvasRect(event.currentTarget.getBoundingClientRect());
|
|
@@ -3657,10 +3854,20 @@ function MenuSections({ build }) {
|
|
|
3657
3854
|
function MenuSection({ first, actions }) {
|
|
3658
3855
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3659
3856
|
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
|
-
|
|
3857
|
+
actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3858
|
+
Menu.Item,
|
|
3859
|
+
{
|
|
3860
|
+
onSelect: action.onSelect,
|
|
3861
|
+
disabled: action.disabled ?? false,
|
|
3862
|
+
className: "mxc-menu-item",
|
|
3863
|
+
"data-destructive": action.destructive ? "" : void 0,
|
|
3864
|
+
children: [
|
|
3865
|
+
action.icon,
|
|
3866
|
+
action.label
|
|
3867
|
+
]
|
|
3868
|
+
},
|
|
3869
|
+
action.id
|
|
3870
|
+
))
|
|
3664
3871
|
] });
|
|
3665
3872
|
}
|
|
3666
3873
|
function safeMenu(build) {
|
|
@@ -3674,13 +3881,13 @@ function safeMenu(build) {
|
|
|
3674
3881
|
|
|
3675
3882
|
// src/react/CanvasColumn.tsx
|
|
3676
3883
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
3677
|
-
var
|
|
3884
|
+
var useIsoLayoutEffect6 = typeof window === "undefined" ? import_react11.useEffect : import_react11.useLayoutEffect;
|
|
3678
3885
|
function subscribeViewport(listener) {
|
|
3679
3886
|
window.addEventListener("resize", listener);
|
|
3680
3887
|
return () => window.removeEventListener("resize", listener);
|
|
3681
3888
|
}
|
|
3682
3889
|
function useViewportWidth() {
|
|
3683
|
-
return (0,
|
|
3890
|
+
return (0, import_react11.useSyncExternalStore)(subscribeViewport, () => window.innerWidth, () => 0);
|
|
3684
3891
|
}
|
|
3685
3892
|
function useRegionWidth() {
|
|
3686
3893
|
const viewport = useViewportWidth();
|
|
@@ -3707,11 +3914,11 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3707
3914
|
const region = useRegionWidth();
|
|
3708
3915
|
const viewport = useViewportWidth();
|
|
3709
3916
|
const singlePane = placement === "docked" && viewport > 0 && viewport <= CANVAS_PHONE_MAX_WIDTH;
|
|
3710
|
-
const [dragWidth, setDragWidth] = (0,
|
|
3711
|
-
const [slots] = (0,
|
|
3712
|
-
const ref = (0,
|
|
3917
|
+
const [dragWidth, setDragWidth] = (0, import_react11.useState)(null);
|
|
3918
|
+
const [slots] = (0, import_react11.useState)(createCanvasSlots);
|
|
3919
|
+
const ref = (0, import_react11.useRef)(null);
|
|
3713
3920
|
useRegisterCanvasPresence();
|
|
3714
|
-
(0,
|
|
3921
|
+
(0, import_react11.useEffect)(
|
|
3715
3922
|
() => controller.registerPaneMeasure((paneId) => {
|
|
3716
3923
|
const section = slots.section(paneId);
|
|
3717
3924
|
if (!section?.isConnected) return null;
|
|
@@ -3720,7 +3927,7 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3720
3927
|
}),
|
|
3721
3928
|
[controller, slots]
|
|
3722
3929
|
);
|
|
3723
|
-
(0,
|
|
3930
|
+
(0, import_react11.useEffect)(() => {
|
|
3724
3931
|
const el = ref.current;
|
|
3725
3932
|
if (!el) return void 0;
|
|
3726
3933
|
let frame2 = 0;
|
|
@@ -3794,8 +4001,8 @@ function CanvasColumn({ className, style, onLiveWidth, placement = "docked" }) {
|
|
|
3794
4001
|
}
|
|
3795
4002
|
function WidthHandle({ width, region, onDrag }) {
|
|
3796
4003
|
const canvas = useCanvas();
|
|
3797
|
-
const start = (0,
|
|
3798
|
-
(0,
|
|
4004
|
+
const start = (0, import_react11.useRef)(null);
|
|
4005
|
+
(0, import_react11.useEffect)(() => () => start.current?.end(), []);
|
|
3799
4006
|
const clamp = (next) => clampDraggedCanvasWidth(next, region, canvas.rules);
|
|
3800
4007
|
const onPointerDown = (event) => {
|
|
3801
4008
|
event.preventDefault();
|
|
@@ -3842,8 +4049,8 @@ function LayoutNodeView({ node }) {
|
|
|
3842
4049
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SplitView, { node });
|
|
3843
4050
|
}
|
|
3844
4051
|
function useMeasuredSize(ref, enabled) {
|
|
3845
|
-
const [size, setSize] = (0,
|
|
3846
|
-
|
|
4052
|
+
const [size, setSize] = (0, import_react11.useState)({ width: 0, height: 0 });
|
|
4053
|
+
useIsoLayoutEffect6(() => {
|
|
3847
4054
|
const el = ref.current;
|
|
3848
4055
|
if (!enabled || !el) return;
|
|
3849
4056
|
const read = () => {
|
|
@@ -3869,8 +4076,8 @@ function childMinimums(node, orientation, rules) {
|
|
|
3869
4076
|
}
|
|
3870
4077
|
function SplitView({ node }) {
|
|
3871
4078
|
const canvas = useCanvas();
|
|
3872
|
-
const ref = (0,
|
|
3873
|
-
const [liveSizes, setLiveSizes] = (0,
|
|
4079
|
+
const ref = (0, import_react11.useRef)(null);
|
|
4080
|
+
const [liveSizes, setLiveSizes] = (0, import_react11.useState)(null);
|
|
3874
4081
|
const measured = useMeasuredSize(ref, canvas.rules.paneMinWidth > 0 || canvas.rules.paneMinHeight > 0);
|
|
3875
4082
|
const stacked = node.orientation === "horizontal" && shouldStackSplit(measured.width, node.children.length, canvas.rules);
|
|
3876
4083
|
const orientation = stacked ? "vertical" : node.orientation;
|