@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/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 import_react3 = require("react");
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 import_react2 = require("react");
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, import_react2.useSyncExternalStore)(layer.dom.subscribe, layer.dom.list, layer.dom.list);
1762
- const [mounted, setMounted] = (0, import_react2.useState)(false);
1763
- (0, import_react2.useEffect)(() => setMounted(true), []);
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, import_react2.useRef)(null);
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, import_react2.useLayoutEffect)(() => {
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, import_react3.createContext)(null);
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, import_react3.useMemo)(
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, import_react3.useRef)(hostPorts);
2088
+ const portsRef = (0, import_react4.useRef)(hostPorts);
1919
2089
  portsRef.current = hostPorts;
1920
- const [{ controller, layer, launcherEntries, itemMenus }] = (0, import_react3.useState)(() => ({
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, import_react3.useEffect)(() => controller.start(), [controller]);
1939
- (0, import_react3.useEffect)(() => {
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, import_react3.useMemo)(
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, import_react3.useMemo)(() => {
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, import_react3.useContext)(CanvasContext);
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, import_react3.useContext)(CanvasContext);
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, import_react3.useContext)(CanvasContext)?.controller ?? null;
2163
+ return (0, import_react4.useContext)(CanvasContext)?.controller ?? null;
1993
2164
  }
1994
2165
  function useCanvasWindowId() {
1995
- return (0, import_react3.useContext)(CanvasContext)?.windowId ?? CANVAS_MAIN_WINDOW;
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, import_react3.useContext)(CanvasContext);
2175
+ const context = (0, import_react4.useContext)(CanvasContext);
2005
2176
  const controller = context?.controller;
2006
2177
  const windowId = context?.windowId;
2007
- (0, import_react3.useEffect)(() => controller?.registerPresentation(windowId), [controller, windowId]);
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, import_react3.useContext)(CanvasContext);
2182
+ const context = (0, import_react4.useContext)(CanvasContext);
2012
2183
  const controller = context?.controller;
2013
- return (0, import_react3.useSyncExternalStore)(
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, import_react3.useSyncExternalStore)(
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, import_react3.useContext)(CanvasContext)?.controller.store;
2200
+ const store = (0, import_react4.useContext)(CanvasContext)?.controller.store;
2030
2201
  const read = () => store ? selector(store.getState()) : fallback;
2031
- return (0, import_react3.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, read, read);
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, import_react3.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
2216
+ (0, import_react4.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
2046
2217
  return listCanvasKinds();
2047
2218
  }
2048
2219
  function useCanvasKind(id) {
2049
- (0, import_react3.useSyncExternalStore)(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
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, import_react3.useContext)(CanvasContext)?.launcherEntries;
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, import_react3.useEffect)(() => {
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, import_react3.useContext)(CanvasContext)?.launcherEntries;
2066
- const all = (0, import_react3.useSyncExternalStore)(store ? store.subscribe : NO_SUBSCRIPTION, store ? store.list : noEntries, store ? store.list : noEntries);
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 import_react10 = require("react");
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 import_react8 = require("react");
2254
+ var import_react9 = require("react");
2084
2255
 
2085
2256
  // src/react/chrome.tsx
2086
- var import_react4 = require("react");
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 useIsoLayoutEffect2 = typeof window === "undefined" ? import_react4.useEffect : import_react4.useLayoutEffect;
2359
+ var useIsoLayoutEffect3 = typeof window === "undefined" ? import_react5.useEffect : import_react5.useLayoutEffect;
2189
2360
  function useTruncated(title) {
2190
- const ref = (0, import_react4.useRef)(null);
2191
- const [truncated, setTruncated] = (0, import_react4.useState)(false);
2192
- useIsoLayoutEffect2(() => {
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, import_react4.useRef)(null);
2207
- const hide = (0, import_react4.useRef)(null);
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, import_react4.useEffect)(() => close, []);
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, import_react4.forwardRef)(function CanvasHeaderButton2({ label, shortcut, available = true, size = "sm", pressed, className, children, onClick, onPointerEnter, onPointerLeave, onPointerDown, onFocus, onBlur, ...rest }, ref) {
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, import_react4.forwardRef)(
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, import_react4.forwardRef)(function CanvasPanel2({
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, import_react4.forwardRef)(function CanvasTab2({ title, icon, note, active, onSelect, onClose, className, onKeyDown, onClick, ...rest }, ref) {
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, import_react4.useState)(url);
2410
- const [editing, setEditing] = (0, import_react4.useState)(false);
2411
- (0, import_react4.useEffect)(() => {
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 import_react5 = require("react");
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, import_react5.useRef)([]);
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, import_react5.useEffect)(() => end, []);
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, import_react5.useRef)(null);
2477
- (0, import_react5.useEffect)(() => () => drop.current?.(), []);
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 import_react6 = require("react");
2614
- var CanvasPresentationContext = (0, import_react6.createContext)(null);
2788
+ var import_react7 = require("react");
2789
+ var CanvasPresentationContext = (0, import_react7.createContext)(null);
2615
2790
  function useCanvasPresentation() {
2616
- return (0, import_react6.useContext)(CanvasPresentationContext);
2791
+ return (0, import_react7.useContext)(CanvasPresentationContext);
2617
2792
  }
2618
2793
 
2619
2794
  // src/react/slots.ts
2620
- var import_react7 = require("react");
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, import_react7.createContext)(null);
2862
+ var CanvasSlotsContext = (0, import_react8.createContext)(null);
2688
2863
  function useCanvasSlots() {
2689
- return (0, import_react7.useContext)(CanvasSlotsContext);
2864
+ return (0, import_react8.useContext)(CanvasSlotsContext);
2690
2865
  }
2691
- var CanvasSinglePaneContext = (0, import_react7.createContext)(false);
2866
+ var CanvasSinglePaneContext = (0, import_react8.createContext)(false);
2692
2867
  function useCanvasSinglePane() {
2693
- return (0, import_react7.useContext)(CanvasSinglePaneContext);
2868
+ return (0, import_react8.useContext)(CanvasSinglePaneContext);
2694
2869
  }
2695
- var CanvasWindowTabsContext = (0, import_react7.createContext)(false);
2870
+ var CanvasWindowTabsContext = (0, import_react8.createContext)(false);
2696
2871
  function useCanvasWindowTabs() {
2697
- return (0, import_react7.useContext)(CanvasWindowTabsContext);
2872
+ return (0, import_react8.useContext)(CanvasWindowTabsContext);
2698
2873
  }
2699
2874
  function useSlotSize(slots, paneId) {
2700
- return (0, import_react7.useSyncExternalStore)(
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 useIsoLayoutEffect3 = typeof window === "undefined" ? import_react8.useEffect : import_react8.useLayoutEffect;
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, import_react8.lazy)(kind.load);
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, import_react8.useMemo)(
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, import_react8.useRef)(null);
2830
- const [placement] = (0, import_react8.useState)(
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
- useIsoLayoutEffect3(() => placement?.place());
2834
- useIsoLayoutEffect3(() => slots && placement ? slots.subscribe(placement.place) : void 0, [slots, placement]);
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, import_react8.memo)(function BodyHost2({
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, import_react8.useMemo)(() => step ? stepAsItem(step, owner ?? 0) : void 0, [step, owner]);
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, import_react8.useRef)(null);
2911
- const [everShown, setEverShown] = (0, import_react8.useState)(visible);
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
- useIsoLayoutEffect3(() => {
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, import_react8.memo)(function Rendered2({
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, import_react8.useState)(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)(import_react8.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) });
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, import_react8.useState)(false);
3003
- (0, import_react8.useEffect)(() => {
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, import_react8.useRef)(null);
3018
- const measure = (0, import_react8.useRef)(() => void 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
- useIsoLayoutEffect3(() => measure.current());
3030
- useIsoLayoutEffect3(() => {
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 import_react8.Component {
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 import_react9 = require("react");
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 useIsoLayoutEffect4 = typeof window === "undefined" ? import_react9.useEffect : import_react9.useLayoutEffect;
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, import_react9.useState)(createCanvasSlots);
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, import_react9.useRef)(null);
3173
- const bodyRef = (0, import_react9.useRef)(null);
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
- useIsoLayoutEffect4(() => {
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 import_react9.Component {
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, import_react9.useRef)(null);
3354
- const list = (0, import_react9.useRef)(null);
3355
- const [width, setWidth] = (0, import_react9.useState)(0);
3356
- const windowStart = (0, import_react9.useRef)(0);
3357
- const focusAfterMove = (0, import_react9.useRef)(false);
3358
- const read = (0, import_react9.useRef)(() => {
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
- useIsoLayoutEffect4(() => {
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
- useIsoLayoutEffect4(() => {
3560
+ useIsoLayoutEffect5(() => {
3380
3561
  read.current();
3381
3562
  }, [tabs.length]);
3382
- useIsoLayoutEffect4(() => {
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
- useIsoLayoutEffect4(() => {
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, import_react9.useRef)(null);
3480
- (0, import_react9.useEffect)(() => () => blocking.current?.(), []);
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, import_react9.useRef)(null);
3595
- (0, import_react9.useEffect)(() => () => blocking.current?.(), []);
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({ type: "item", id: action.id, label: action.label, ...action.destructive ? { destructive: true } : {} });
3626
- handlers.set(action.id, action.onSelect);
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)(Menu.Item, { onSelect: action.onSelect, className: "mxc-menu-item", "data-destructive": action.destructive ? "" : void 0, children: [
3661
- action.icon,
3662
- action.label
3663
- ] }, action.id))
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 useIsoLayoutEffect5 = typeof window === "undefined" ? import_react10.useEffect : import_react10.useLayoutEffect;
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, import_react10.useSyncExternalStore)(subscribeViewport, () => window.innerWidth, () => 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, import_react10.useState)(null);
3711
- const [slots] = (0, import_react10.useState)(createCanvasSlots);
3712
- const ref = (0, import_react10.useRef)(null);
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, import_react10.useEffect)(
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, import_react10.useEffect)(() => {
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, import_react10.useRef)(null);
3798
- (0, import_react10.useEffect)(() => () => start.current?.end(), []);
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, import_react10.useState)({ width: 0, height: 0 });
3846
- useIsoLayoutEffect5(() => {
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, import_react10.useRef)(null);
3873
- const [liveSizes, setLiveSizes] = (0, import_react10.useState)(null);
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;