@ai-matrx/canvas 0.2.2 → 0.4.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.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ComponentType, ReactNode, CSSProperties, ButtonHTMLAttributes, HTMLAttributes, ReactElement } from 'react';
3
- import { D as CanvasRect, d as CanvasPaneId, C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, i as CanvasItem, h as CanvasController, G as CanvasSessionEvent, E as CanvasSessionAttachReason, F as CanvasSessionDetachReason, e as CanvasStoreBinding, B as CanvasPersistencePort, v as CanvasErrorSink, x as CanvasLayoutRules, f as CanvasState } from './controller-Dv6J6XZm.cjs';
3
+ import { F as CanvasRect, d as CanvasPaneId, C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, i as CanvasItem, h as CanvasController, I as CanvasSessionEvent, G as CanvasSessionAttachReason, H as CanvasSessionDetachReason, e as CanvasStoreBinding, E as CanvasPersistencePort, w as CanvasErrorSink, z as CanvasLayoutRules, T as ToggleKindInput, y as CanvasKindVisibility, f as CanvasState } from './toggleKind-A9v45oSb.cjs';
4
4
 
5
5
  /** One floating thing. Plain data, so a host can draw it in another process. */
6
6
  type CanvasFloating = {
@@ -133,6 +133,13 @@ interface CanvasKind<TData extends CanvasJson = CanvasJson> {
133
133
  readonly HeaderLeading?: ComponentType<CanvasKindProps<TData>>;
134
134
  /** The kind's own button, rendered left of the pane's "…" menu. */
135
135
  readonly HeaderAction?: ComponentType<CanvasKindProps<TData>>;
136
+ /**
137
+ * A toolbar ROW between the pane header and the body, for the active item
138
+ * only (a browser's back / forward / reload / address / screenshot). Always
139
+ * DOM, never covered by a native view: a `body: "native"` frame is measured
140
+ * BELOW it.
141
+ */
142
+ readonly Toolbar?: ComponentType<CanvasKindProps<TData>>;
136
143
  /** Kind-specific entries for the pane's "…" menu. */
137
144
  readonly menuItems?: (props: CanvasKindProps<TData>) => readonly CanvasMenuItem[];
138
145
  }
@@ -230,6 +237,16 @@ declare function useCanvasState<T>(selector: (state: CanvasState) => T): T;
230
237
  * embed). `fallback` must be referentially stable (a primitive or null).
231
238
  */
232
239
  declare function useOptionalCanvasState<T>(selector: (state: CanvasState) => T, fallback: T): T;
240
+ /**
241
+ * A toolbar icon's view of one kind: "absent" | "background" | "visible"
242
+ * (a primitive, so it never loops), plus the click that toggles or focuses it.
243
+ */
244
+ declare function useCanvasKindToggle(input: ToggleKindInput): {
245
+ readonly visibility: CanvasKindVisibility;
246
+ readonly isOpen: boolean;
247
+ readonly isVisible: boolean;
248
+ readonly toggle: () => CanvasKindVisibility;
249
+ };
233
250
  /** Re-renders when kinds register, so late-registered kinds appear. */
234
251
  declare function useCanvasKinds(): readonly AnyCanvasKind[];
235
252
  declare function useCanvasKind(id: string): AnyCanvasKind | undefined;
@@ -372,4 +389,4 @@ interface BrowserBarProps {
372
389
  /** A browser's back · forward · reload · address bar, for a kind's leading slot or its body. */
373
390
  declare function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload, onNavigate, trailing, className }: BrowserBarProps): react.JSX.Element;
374
391
 
375
- export { type AnyCanvasKind, BrowserBar, type BrowserBarProps, type BrowserTab, BrowserTabs, type BrowserTabsProps, CanvasColumn, type CanvasColumnProps, type CanvasFloating, CanvasFrame, CanvasHeaderButton, type CanvasHeaderButtonProps, type CanvasHostPorts, type CanvasKind, type CanvasKindProps, type CanvasMenuEntry, type CanvasMenuItem, CanvasMenuTrigger, type CanvasNativeBodyFrame, type CanvasNativeBodyInfo, type CanvasNativeRect, type CanvasOverlayPort, CanvasPaneView, CanvasPanel, CanvasPanelEmpty, type CanvasPanelProps, CanvasProvider, type CanvasProviderProps, type CanvasShowMenu, CanvasTab, type CanvasTabProps, type CanvasTabStripMode, CanvasToggle, CanvasWindowScope, canvasSessionKey, defineCanvasKind, getCanvasKind, itemTitle, listCanvasKinds, registerCanvasKind, registerCanvasKinds, useCanvas, useCanvasColumnWidth, useCanvasHostPorts, useCanvasIsPresented, useCanvasKind, useCanvasKinds, useCanvasNativeBodies, useCanvasState, useCanvasWindowId, useOptionalCanvas, useOptionalCanvasState };
392
+ export { type AnyCanvasKind, BrowserBar, type BrowserBarProps, type BrowserTab, BrowserTabs, type BrowserTabsProps, CanvasColumn, type CanvasColumnProps, type CanvasFloating, CanvasFrame, CanvasHeaderButton, type CanvasHeaderButtonProps, type CanvasHostPorts, type CanvasKind, type CanvasKindProps, type CanvasMenuEntry, type CanvasMenuItem, CanvasMenuTrigger, type CanvasNativeBodyFrame, type CanvasNativeBodyInfo, type CanvasNativeRect, type CanvasOverlayPort, CanvasPaneView, CanvasPanel, CanvasPanelEmpty, type CanvasPanelProps, CanvasProvider, type CanvasProviderProps, type CanvasShowMenu, CanvasTab, type CanvasTabProps, type CanvasTabStripMode, CanvasToggle, CanvasWindowScope, canvasSessionKey, defineCanvasKind, getCanvasKind, itemTitle, listCanvasKinds, registerCanvasKind, registerCanvasKinds, useCanvas, useCanvasColumnWidth, useCanvasHostPorts, useCanvasIsPresented, useCanvasKind, useCanvasKindToggle, useCanvasKinds, useCanvasNativeBodies, useCanvasState, useCanvasWindowId, useOptionalCanvas, useOptionalCanvasState };
package/dist/react.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ComponentType, ReactNode, CSSProperties, ButtonHTMLAttributes, HTMLAttributes, ReactElement } from 'react';
3
- import { D as CanvasRect, d as CanvasPaneId, C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, i as CanvasItem, h as CanvasController, G as CanvasSessionEvent, E as CanvasSessionAttachReason, F as CanvasSessionDetachReason, e as CanvasStoreBinding, B as CanvasPersistencePort, v as CanvasErrorSink, x as CanvasLayoutRules, f as CanvasState } from './controller-Dv6J6XZm.js';
3
+ import { F as CanvasRect, d as CanvasPaneId, C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, i as CanvasItem, h as CanvasController, I as CanvasSessionEvent, G as CanvasSessionAttachReason, H as CanvasSessionDetachReason, e as CanvasStoreBinding, E as CanvasPersistencePort, w as CanvasErrorSink, z as CanvasLayoutRules, T as ToggleKindInput, y as CanvasKindVisibility, f as CanvasState } from './toggleKind-A9v45oSb.js';
4
4
 
5
5
  /** One floating thing. Plain data, so a host can draw it in another process. */
6
6
  type CanvasFloating = {
@@ -133,6 +133,13 @@ interface CanvasKind<TData extends CanvasJson = CanvasJson> {
133
133
  readonly HeaderLeading?: ComponentType<CanvasKindProps<TData>>;
134
134
  /** The kind's own button, rendered left of the pane's "…" menu. */
135
135
  readonly HeaderAction?: ComponentType<CanvasKindProps<TData>>;
136
+ /**
137
+ * A toolbar ROW between the pane header and the body, for the active item
138
+ * only (a browser's back / forward / reload / address / screenshot). Always
139
+ * DOM, never covered by a native view: a `body: "native"` frame is measured
140
+ * BELOW it.
141
+ */
142
+ readonly Toolbar?: ComponentType<CanvasKindProps<TData>>;
136
143
  /** Kind-specific entries for the pane's "…" menu. */
137
144
  readonly menuItems?: (props: CanvasKindProps<TData>) => readonly CanvasMenuItem[];
138
145
  }
@@ -230,6 +237,16 @@ declare function useCanvasState<T>(selector: (state: CanvasState) => T): T;
230
237
  * embed). `fallback` must be referentially stable (a primitive or null).
231
238
  */
232
239
  declare function useOptionalCanvasState<T>(selector: (state: CanvasState) => T, fallback: T): T;
240
+ /**
241
+ * A toolbar icon's view of one kind: "absent" | "background" | "visible"
242
+ * (a primitive, so it never loops), plus the click that toggles or focuses it.
243
+ */
244
+ declare function useCanvasKindToggle(input: ToggleKindInput): {
245
+ readonly visibility: CanvasKindVisibility;
246
+ readonly isOpen: boolean;
247
+ readonly isVisible: boolean;
248
+ readonly toggle: () => CanvasKindVisibility;
249
+ };
233
250
  /** Re-renders when kinds register, so late-registered kinds appear. */
234
251
  declare function useCanvasKinds(): readonly AnyCanvasKind[];
235
252
  declare function useCanvasKind(id: string): AnyCanvasKind | undefined;
@@ -372,4 +389,4 @@ interface BrowserBarProps {
372
389
  /** A browser's back · forward · reload · address bar, for a kind's leading slot or its body. */
373
390
  declare function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload, onNavigate, trailing, className }: BrowserBarProps): react.JSX.Element;
374
391
 
375
- export { type AnyCanvasKind, BrowserBar, type BrowserBarProps, type BrowserTab, BrowserTabs, type BrowserTabsProps, CanvasColumn, type CanvasColumnProps, type CanvasFloating, CanvasFrame, CanvasHeaderButton, type CanvasHeaderButtonProps, type CanvasHostPorts, type CanvasKind, type CanvasKindProps, type CanvasMenuEntry, type CanvasMenuItem, CanvasMenuTrigger, type CanvasNativeBodyFrame, type CanvasNativeBodyInfo, type CanvasNativeRect, type CanvasOverlayPort, CanvasPaneView, CanvasPanel, CanvasPanelEmpty, type CanvasPanelProps, CanvasProvider, type CanvasProviderProps, type CanvasShowMenu, CanvasTab, type CanvasTabProps, type CanvasTabStripMode, CanvasToggle, CanvasWindowScope, canvasSessionKey, defineCanvasKind, getCanvasKind, itemTitle, listCanvasKinds, registerCanvasKind, registerCanvasKinds, useCanvas, useCanvasColumnWidth, useCanvasHostPorts, useCanvasIsPresented, useCanvasKind, useCanvasKinds, useCanvasNativeBodies, useCanvasState, useCanvasWindowId, useOptionalCanvas, useOptionalCanvasState };
392
+ export { type AnyCanvasKind, BrowserBar, type BrowserBarProps, type BrowserTab, BrowserTabs, type BrowserTabsProps, CanvasColumn, type CanvasColumnProps, type CanvasFloating, CanvasFrame, CanvasHeaderButton, type CanvasHeaderButtonProps, type CanvasHostPorts, type CanvasKind, type CanvasKindProps, type CanvasMenuEntry, type CanvasMenuItem, CanvasMenuTrigger, type CanvasNativeBodyFrame, type CanvasNativeBodyInfo, type CanvasNativeRect, type CanvasOverlayPort, CanvasPaneView, CanvasPanel, CanvasPanelEmpty, type CanvasPanelProps, CanvasProvider, type CanvasProviderProps, type CanvasShowMenu, CanvasTab, type CanvasTabProps, type CanvasTabStripMode, CanvasToggle, CanvasWindowScope, canvasSessionKey, defineCanvasKind, getCanvasKind, itemTitle, listCanvasKinds, registerCanvasKind, registerCanvasKinds, useCanvas, useCanvasColumnWidth, useCanvasHostPorts, useCanvasIsPresented, useCanvasKind, useCanvasKindToggle, useCanvasKinds, useCanvasNativeBodies, useCanvasState, useCanvasWindowId, useOptionalCanvas, useOptionalCanvasState };
package/dist/react.js CHANGED
@@ -1220,6 +1220,44 @@ function selectCanvasWindowItemCount(s, windowId) {
1220
1220
  }
1221
1221
  var NO_WINDOWS = Object.freeze({});
1222
1222
 
1223
+ // src/core/toggleKind.ts
1224
+ var CANVAS_DEFAULT_KEY = "default";
1225
+ function selectCanvasKindVisibility(state, kind, key = CANVAS_DEFAULT_KEY) {
1226
+ const itemId = canvasItemId(kind, key);
1227
+ if (!state.items[itemId]) return "absent";
1228
+ const windowId = canvasWindowOfItem(state, itemId);
1229
+ if (!windowId) return "background";
1230
+ const isOpen = canvasWindowFrame(state, windowId)?.isOpen ?? false;
1231
+ const pane = Object.values(state.panes).find((p) => p.itemIds.includes(itemId));
1232
+ return isOpen && pane?.activeItemId === itemId ? "visible" : "background";
1233
+ }
1234
+ function toggleKind(controller, input) {
1235
+ const key = input.key ?? CANVAS_DEFAULT_KEY;
1236
+ const itemId = canvasItemId(input.kind, key);
1237
+ const before = selectCanvasKindVisibility(controller.getState(), input.kind, key);
1238
+ if (before === "visible") {
1239
+ if ((input.whenVisible ?? "close") === "close") {
1240
+ controller.close(itemId);
1241
+ } else {
1242
+ controller.hide(canvasWindowOfItem(controller.getState(), itemId) ?? void 0);
1243
+ }
1244
+ return selectCanvasKindVisibility(controller.getState(), input.kind, key);
1245
+ }
1246
+ if (before === "background") {
1247
+ controller.open({ kind: input.kind, key });
1248
+ const windowId = canvasWindowOfItem(controller.getState(), itemId);
1249
+ if (windowId) controller.show(windowId);
1250
+ return selectCanvasKindVisibility(controller.getState(), input.kind, key);
1251
+ }
1252
+ const opened = controller.open({
1253
+ kind: input.kind,
1254
+ key,
1255
+ ...input.data !== void 0 ? { data: input.data } : {},
1256
+ ...input.title !== void 0 ? { title: input.title } : {}
1257
+ });
1258
+ return opened ? selectCanvasKindVisibility(controller.getState(), input.kind, key) : "absent";
1259
+ }
1260
+
1223
1261
  // src/react/layer.tsx
1224
1262
  import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
1225
1263
  import { createPortal } from "react-dom";
@@ -1519,6 +1557,17 @@ function useOptionalCanvasState(selector, fallback) {
1519
1557
  const read = () => store ? selector(store.getState()) : fallback;
1520
1558
  return useSyncExternalStore2(store ? store.subscribe : NO_SUBSCRIPTION, read, read);
1521
1559
  }
1560
+ function useCanvasKindToggle(input) {
1561
+ const controller = useCanvasContext().controller;
1562
+ const key = input.key ?? CANVAS_DEFAULT_KEY;
1563
+ const visibility = useCanvasState((s) => selectCanvasKindVisibility(s, input.kind, key));
1564
+ return {
1565
+ visibility,
1566
+ isOpen: visibility !== "absent",
1567
+ isVisible: visibility === "visible",
1568
+ toggle: () => toggleKind(controller, input)
1569
+ };
1570
+ }
1522
1571
  function useCanvasKinds() {
1523
1572
  useSyncExternalStore2(subscribeCanvasKinds, getCanvasKindsVersion, getCanvasKindsVersion);
1524
1573
  return listCanvasKinds();
@@ -1959,6 +2008,7 @@ function CanvasPaneView({ paneId }) {
1959
2008
  const kindProps = active && kind ? { item: active, data: active.data, paneId, isFocused: focused, canvas, windowId } : null;
1960
2009
  const Leading = kind?.HeaderLeading;
1961
2010
  const Action = kind?.HeaderAction;
2011
+ const Toolbar = kind?.Toolbar;
1962
2012
  const single = tabStrip === "auto" && pane.itemIds.length === 1 && active;
1963
2013
  const hideDrop = () => {
1964
2014
  drop.current?.();
@@ -1985,7 +2035,7 @@ function CanvasPaneView({ paneId }) {
1985
2035
  canvas.moveItem(itemId, paneId);
1986
2036
  };
1987
2037
  const closeLabel = role === "pop-out" && paneCount === 1 ? "Close window" : paneCount > 1 ? "Close pane" : "Close canvas";
1988
- return /* @__PURE__ */ jsx5(
2038
+ return /* @__PURE__ */ jsxs4(
1989
2039
  CanvasPanel,
1990
2040
  {
1991
2041
  ref: sectionRef,
@@ -2010,15 +2060,30 @@ function CanvasPaneView({ paneId }) {
2010
2060
  onDragOver,
2011
2061
  onDragLeave,
2012
2062
  onDrop,
2013
- children: pane.itemIds.length === 0 ? /* @__PURE__ */ jsx5(Launcher, { paneId }) : pane.itemIds.map((itemId) => {
2014
- const item = items[itemId];
2015
- if (!item) return null;
2016
- const isActive = itemId === pane.activeItemId;
2017
- return /* @__PURE__ */ jsx5(ItemBody, { item, paneId, windowId, isActive, isFocused: focused && isActive, hasNativePort: !!ports.onNativeBodyFrame }, itemId);
2018
- })
2063
+ children: [
2064
+ Toolbar && kindProps ? /* @__PURE__ */ jsx5("div", { className: "mxc-item-toolbar", "data-kind": active?.kind, children: /* @__PURE__ */ jsx5(ToolbarBoundary, { kindId: kind?.id ?? "", children: /* @__PURE__ */ jsx5(Toolbar, { ...kindProps }) }) }) : null,
2065
+ pane.itemIds.length === 0 ? /* @__PURE__ */ jsx5(Launcher, { paneId }) : pane.itemIds.map((itemId) => {
2066
+ const item = items[itemId];
2067
+ if (!item) return null;
2068
+ const isActive = itemId === pane.activeItemId;
2069
+ return /* @__PURE__ */ jsx5(ItemBody, { item, paneId, windowId, isActive, isFocused: focused && isActive, hasNativePort: !!ports.onNativeBodyFrame }, itemId);
2070
+ })
2071
+ ]
2019
2072
  }
2020
2073
  );
2021
2074
  }
2075
+ var ToolbarBoundary = class extends Component {
2076
+ state = { failed: false };
2077
+ static getDerivedStateFromError() {
2078
+ return { failed: true };
2079
+ }
2080
+ componentDidCatch(error) {
2081
+ console.error(`[@ai-matrx/canvas] "${this.props.kindId}" Toolbar threw`, error);
2082
+ }
2083
+ render() {
2084
+ return this.state.failed ? null : this.props.children;
2085
+ }
2086
+ };
2022
2087
  function SingleTitle({ item, kind }) {
2023
2088
  const title = itemTitle(item, kind);
2024
2089
  const drag = useTabDrag(item.id, title);
@@ -2534,6 +2599,7 @@ export {
2534
2599
  useCanvasHostPorts,
2535
2600
  useCanvasIsPresented,
2536
2601
  useCanvasKind,
2602
+ useCanvasKindToggle,
2537
2603
  useCanvasKinds,
2538
2604
  useCanvasNativeBodies,
2539
2605
  useCanvasState,