@ai-matrx/canvas 0.5.0 → 0.5.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.d.cts CHANGED
@@ -249,7 +249,7 @@ interface CanvasProviderProps extends CanvasHostPorts {
249
249
  /** "auto": a pane with one tab shows a title instead of a tab strip. Default "auto". */
250
250
  readonly tabStrip?: CanvasTabStripMode;
251
251
  }
252
- declare function CanvasProvider({ children, store, persistence, onError, hotkeys, windowId: windowIdProp, layoutRules, regionWidth, tabStrip, ...hostPorts }: CanvasProviderProps): react.JSX.Element;
252
+ declare function CanvasProvider({ children, store, persistence, onError, hotkeys, windowId: windowIdProp, layoutRules, regionWidth, tabStrip, itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame, }: CanvasProviderProps): react.JSX.Element;
253
253
  /**
254
254
  * Renders a subtree as ANOTHER window of the same canvas — the web host's
255
255
  * pop-out panel: `<CanvasWindowScope windowId={id}><CanvasColumn placement="fill"/></CanvasWindowScope>`.
package/dist/react.d.ts CHANGED
@@ -249,7 +249,7 @@ interface CanvasProviderProps extends CanvasHostPorts {
249
249
  /** "auto": a pane with one tab shows a title instead of a tab strip. Default "auto". */
250
250
  readonly tabStrip?: CanvasTabStripMode;
251
251
  }
252
- declare function CanvasProvider({ children, store, persistence, onError, hotkeys, windowId: windowIdProp, layoutRules, regionWidth, tabStrip, ...hostPorts }: CanvasProviderProps): react.JSX.Element;
252
+ declare function CanvasProvider({ children, store, persistence, onError, hotkeys, windowId: windowIdProp, layoutRules, regionWidth, tabStrip, itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame, }: CanvasProviderProps): react.JSX.Element;
253
253
  /**
254
254
  * Renders a subtree as ANOTHER window of the same canvas — the web host's
255
255
  * pop-out panel: `<CanvasWindowScope windowId={id}><CanvasColumn placement="fill"/></CanvasWindowScope>`.
package/dist/react.js CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  createContext,
7
7
  useContext,
8
8
  useEffect as useEffect2,
9
+ useMemo,
9
10
  useRef as useRef2,
10
11
  useState as useState2,
11
12
  useSyncExternalStore as useSyncExternalStore2
@@ -1638,8 +1639,17 @@ function CanvasProvider({
1638
1639
  layoutRules,
1639
1640
  regionWidth = null,
1640
1641
  tabStrip = "auto",
1641
- ...hostPorts
1642
+ itemActions,
1643
+ popOut,
1644
+ dockBack,
1645
+ showMenu,
1646
+ overlay,
1647
+ onNativeBodyFrame
1642
1648
  }) {
1649
+ const hostPorts = useMemo(
1650
+ () => ({ itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame }),
1651
+ [itemActions, popOut, dockBack, showMenu, overlay, onNativeBodyFrame]
1652
+ );
1643
1653
  const portsRef = useRef2(hostPorts);
1644
1654
  portsRef.current = hostPorts;
1645
1655
  const [{ controller, layer, launcherEntries }] = useState2(() => ({
@@ -1681,7 +1691,10 @@ function CanvasProvider({
1681
1691
  window.addEventListener("keydown", onKey);
1682
1692
  return () => window.removeEventListener("keydown", onKey);
1683
1693
  }, [controller, hotkeys, windowId]);
1684
- const value = { controller, windowId, ports: hostPorts, layer, regionWidth, tabStrip, launcherEntries };
1694
+ const value = useMemo(
1695
+ () => ({ controller, windowId, ports: hostPorts, layer, regionWidth, tabStrip, launcherEntries }),
1696
+ [controller, windowId, hostPorts, layer, regionWidth, tabStrip, launcherEntries]
1697
+ );
1685
1698
  return /* @__PURE__ */ jsxs(CanvasContext.Provider, { value, children: [
1686
1699
  children,
1687
1700
  hostPorts.overlay ? null : /* @__PURE__ */ jsx2(CanvasDomOverlay, { layer })
@@ -1689,8 +1702,10 @@ function CanvasProvider({
1689
1702
  }
1690
1703
  function CanvasWindowScope({ windowId, children }) {
1691
1704
  const parent = useCanvasContext();
1692
- const id = canvasWindowId(windowId);
1693
- const value = { ...parent, windowId: id, controller: parent.controller.forWindow(id) };
1705
+ const value = useMemo(() => {
1706
+ const id = canvasWindowId(windowId);
1707
+ return { ...parent, windowId: id, controller: parent.controller.forWindow(id) };
1708
+ }, [parent, windowId]);
1694
1709
  return /* @__PURE__ */ jsx2(CanvasContext.Provider, { value, children });
1695
1710
  }
1696
1711
  function useCanvasContext() {
@@ -1812,7 +1827,7 @@ import {
1812
1827
  memo,
1813
1828
  useEffect as useEffect5,
1814
1829
  useLayoutEffect as useLayoutEffect2,
1815
- useMemo,
1830
+ useMemo as useMemo2,
1816
1831
  useRef as useRef5,
1817
1832
  useState as useState4
1818
1833
  } from "react";
@@ -2402,25 +2417,45 @@ function resetKindComponent(kind) {
2402
2417
  }
2403
2418
  function usePanePresentation(slots, paneId, isFullscreen, paneCount) {
2404
2419
  const size = useSlotSize(slots, paneId);
2405
- return useMemo(
2420
+ return useMemo2(
2406
2421
  () => canvasPresentation({ width: size.width, height: size.height, isFullscreen, paneCount }),
2407
2422
  [size.width, size.height, isFullscreen, paneCount]
2408
2423
  );
2409
2424
  }
2410
- function placedItems(state, windowId, onlyPane) {
2425
+ var hostKey = (item) => item.instance ?? item.id;
2426
+ var SEP2 = "";
2427
+ var ROW = "";
2428
+ function layerSignature(state, windowId, onlyPane) {
2411
2429
  const frame2 = canvasWindowFrame(state, windowId);
2412
- if (!frame2) return [];
2413
- const out = [];
2414
- for (const paneId of onlyPane ? [onlyPane] : listPaneIds(frame2.layout)) {
2430
+ if (!frame2) return "";
2431
+ const rows = [];
2432
+ const paneIds = listPaneIds(frame2.layout);
2433
+ for (const paneId of onlyPane ? [onlyPane] : paneIds) {
2415
2434
  const pane = state.panes[paneId];
2416
2435
  for (const itemId of pane?.itemIds ?? []) {
2417
2436
  const item = state.items[itemId];
2418
- if (item) out.push({ item, paneId, active: pane?.activeItemId === itemId });
2437
+ if (item) rows.push({ item, row: [hostKey(item), itemId, paneId, pane?.activeItemId === itemId ? "1" : "0"].join(SEP2) });
2419
2438
  }
2420
2439
  }
2421
- return out.sort((a, b) => a.item.openedAt - b.item.openedAt || hostKey(a.item).localeCompare(hostKey(b.item)));
2440
+ rows.sort((a, b) => a.item.openedAt - b.item.openedAt || hostKey(a.item).localeCompare(hostKey(b.item)));
2441
+ const head = [frame2.isOpen ? "1" : "0", frame2.isFullscreen ? "1" : "0", frame2.focusedPaneId, String(paneIds.length)].join(SEP2);
2442
+ return [head, ...rows.map((r) => r.row)].join(ROW);
2443
+ }
2444
+ function parseSignature(signature) {
2445
+ if (!signature) return null;
2446
+ const [head = "", ...rows] = signature.split(ROW);
2447
+ const [open, full, focusedPaneId = "", count = "1"] = head.split(SEP2);
2448
+ return {
2449
+ isOpen: open === "1",
2450
+ isFullscreen: full === "1",
2451
+ focusedPaneId,
2452
+ paneCount: Number(count) || 1,
2453
+ placed: rows.map((row) => {
2454
+ const [hostId = "", itemId = "", paneId = "", active] = row.split(SEP2);
2455
+ return { hostId, itemId, paneId, active: active === "1" };
2456
+ })
2457
+ };
2422
2458
  }
2423
- var hostKey = (item) => item.instance ?? item.id;
2424
2459
  function createPlacement(getRoot, slots, afterPlace) {
2425
2460
  const hosts = /* @__PURE__ */ new Map();
2426
2461
  let placing = false;
@@ -2463,57 +2498,54 @@ function createPlacement(getRoot, slots, afterPlace) {
2463
2498
  function CanvasBodyLayer() {
2464
2499
  const { windowId, layer } = useCanvasInternals();
2465
2500
  const slots = useCanvasSlots();
2466
- const state = useCanvasState((s) => s);
2501
+ const signature = useCanvasState((s) => layerSignature(s, windowId));
2467
2502
  const root = useRef5(null);
2468
2503
  const [placement] = useState4(
2469
2504
  () => slots ? createPlacement(() => root.current, slots, () => layer.native.remeasure()) : null
2470
2505
  );
2471
2506
  useIsoLayoutEffect(() => placement?.place());
2472
2507
  useIsoLayoutEffect(() => slots && placement ? slots.subscribe(placement.place) : void 0, [slots, placement]);
2473
- if (!slots || !placement) return null;
2474
- const frame2 = canvasWindowFrame(state, windowId);
2475
- if (!frame2) return null;
2476
- const paneCount = listPaneIds(frame2.layout).length;
2477
- return /* @__PURE__ */ jsx6("div", { ref: root, className: "mxc-bodies", "data-mxc-bodies": windowId, children: placedItems(state, windowId).map(({ item, paneId, active }) => /* @__PURE__ */ jsx6(
2508
+ const shape = parseSignature(signature);
2509
+ if (!slots || !placement || !shape) return null;
2510
+ return /* @__PURE__ */ jsx6("div", { ref: root, className: "mxc-bodies", "data-mxc-bodies": windowId, children: shape.placed.map(({ hostId, itemId, paneId, active }) => /* @__PURE__ */ jsx6(
2478
2511
  BodyHost,
2479
2512
  {
2480
- hostId: hostKey(item),
2481
- item,
2513
+ hostId,
2514
+ itemId,
2482
2515
  paneId,
2483
- visible: frame2.isOpen && active,
2484
- focused: active && frame2.focusedPaneId === paneId,
2485
- isFullscreen: frame2.isFullscreen,
2486
- paneCount,
2516
+ visible: shape.isOpen && active,
2517
+ focused: active && shape.focusedPaneId === paneId,
2518
+ isFullscreen: shape.isFullscreen,
2519
+ paneCount: shape.paneCount,
2487
2520
  slots,
2488
2521
  placement
2489
2522
  },
2490
- hostKey(item)
2523
+ hostId
2491
2524
  )) });
2492
2525
  }
2493
2526
  function CanvasPaneInlineBodies({ paneId, slots }) {
2494
2527
  const { windowId } = useCanvasInternals();
2495
- const state = useCanvasState((s) => s);
2496
- const frame2 = canvasWindowFrame(state, windowId);
2497
- const paneCount = frame2 ? listPaneIds(frame2.layout).length : 1;
2498
- return /* @__PURE__ */ jsx6(Fragment, { children: placedItems(state, windowId, paneId).map(({ item, active }) => /* @__PURE__ */ jsx6(
2528
+ const shape = parseSignature(useCanvasState((s) => layerSignature(s, windowId, paneId)));
2529
+ if (!shape) return null;
2530
+ return /* @__PURE__ */ jsx6(Fragment, { children: shape.placed.map(({ hostId, itemId, active }) => /* @__PURE__ */ jsx6(
2499
2531
  BodyHost,
2500
2532
  {
2501
- hostId: hostKey(item),
2502
- item,
2533
+ hostId,
2534
+ itemId,
2503
2535
  paneId,
2504
2536
  visible: active,
2505
- focused: active && frame2?.focusedPaneId === paneId,
2506
- isFullscreen: frame2?.isFullscreen ?? false,
2507
- paneCount,
2537
+ focused: active && shape.focusedPaneId === paneId,
2538
+ isFullscreen: shape.isFullscreen,
2539
+ paneCount: shape.paneCount,
2508
2540
  slots,
2509
2541
  placement: null
2510
2542
  },
2511
- hostKey(item)
2543
+ hostId
2512
2544
  )) });
2513
2545
  }
2514
- function BodyHost({
2546
+ var BodyHost = memo(function BodyHost2({
2515
2547
  hostId,
2516
- item,
2548
+ itemId,
2517
2549
  paneId,
2518
2550
  visible,
2519
2551
  focused,
@@ -2524,7 +2556,8 @@ function BodyHost({
2524
2556
  }) {
2525
2557
  const canvas = useCanvas();
2526
2558
  const { windowId, ports } = useCanvasInternals();
2527
- const kind = useItemKind(item.kind);
2559
+ const item = useCanvasState((s) => s.items[itemId]);
2560
+ const kind = useItemKind(item?.kind ?? "");
2528
2561
  const element = useRef5(null);
2529
2562
  const [everShown, setEverShown] = useState4(visible);
2530
2563
  if (visible && !everShown) setEverShown(true);
@@ -2536,6 +2569,7 @@ function BodyHost({
2536
2569
  if (!placement || !el) return void 0;
2537
2570
  return placement.register(hostId, { element: el, paneId });
2538
2571
  }, [placement, hostId, paneId]);
2572
+ if (!item) return null;
2539
2573
  return /* @__PURE__ */ jsx6(
2540
2574
  "div",
2541
2575
  {
@@ -2569,7 +2603,7 @@ function BodyHost({
2569
2603
  ) }) }) : null
2570
2604
  }
2571
2605
  );
2572
- }
2606
+ });
2573
2607
  function ItemContent({
2574
2608
  item,
2575
2609
  kind,
@@ -2705,13 +2739,15 @@ function CanvasPaneView({ paneId }) {
2705
2739
  const [ownSlots] = useState5(createCanvasSlots);
2706
2740
  const slots = columnSlots ?? ownSlots;
2707
2741
  const pane = useCanvasState((s) => s.panes[paneId]);
2708
- const items = useCanvasState((s) => s.items);
2742
+ const active = useCanvasState((s) => {
2743
+ const activeId = s.panes[paneId]?.activeItemId;
2744
+ return activeId ? s.items[activeId] : void 0;
2745
+ });
2709
2746
  const isFullscreen = useCanvasState((s) => selectCanvasIsFullscreen(s, windowId));
2710
2747
  const isOpen = useCanvasState((s) => selectCanvasIsOpen(s, windowId));
2711
2748
  const focused = useCanvasState((s) => selectCanvasFocusedPaneId(s, windowId) === paneId);
2712
2749
  const paneCount = useCanvasState((s) => selectCanvasPaneCount(s, windowId));
2713
2750
  const role = useCanvasState((s) => windowId === CANVAS_MAIN_WINDOW ? "main" : s.windows[windowId]?.role ?? "window");
2714
- const active = pane?.activeItemId ? items[pane.activeItemId] : void 0;
2715
2751
  const canGoBack = useCanvasState((s) => active ? selectCanvasCanGoBack(s, active.id) : false);
2716
2752
  const kind = useItemKind(active?.kind ?? "");
2717
2753
  const sectionRef = useRef6(null);
@@ -2800,7 +2836,7 @@ function TabStrip({ paneId, itemIds, activeItemId }) {
2800
2836
  const reveal = () => {
2801
2837
  const tab = el.querySelector('[role="tab"][aria-selected="true"]');
2802
2838
  if (!tab) return;
2803
- const left = tab.offsetLeft - el.offsetLeft;
2839
+ const left = tab.offsetLeft;
2804
2840
  const right = left + tab.offsetWidth;
2805
2841
  if (left < el.scrollLeft) el.scrollLeft = left;
2806
2842
  else if (right > el.scrollLeft + el.clientWidth) el.scrollLeft = right - el.clientWidth;