@ai-matrx/canvas 0.9.3 → 0.10.0

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