@ai-matrx/canvas 0.1.0 → 0.2.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.ts CHANGED
@@ -1,283 +1,48 @@
1
1
  import * as react from 'react';
2
- import { ComponentType, ReactNode, CSSProperties } from 'react';
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
4
 
4
- /**
5
- * @ai-matrx/canvas — core types.
6
- *
7
- * The canvas is ONE docked column on the right edge of an application. It holds
8
- * panes; panes hold tabs; every tab is one CanvasItem. A CanvasItem is
9
- * identified by `kind` + `key`, so opening the same thing twice always lands on
10
- * the existing tab instead of creating a duplicate.
11
- *
12
- * Everything in CanvasState is plain JSON: it lives in the host's Redux store
13
- * (or the package's own standalone store), it is persisted between sessions,
14
- * and it can be inspected. No functions, no class instances, no React nodes.
15
- */
16
- /** Any value that survives JSON.stringify → JSON.parse unchanged. */
17
- type CanvasJson = string | number | boolean | null | readonly CanvasJson[] | {
18
- readonly [key: string]: CanvasJson | undefined;
19
- };
20
- declare const itemIdBrand: unique symbol;
21
- declare const paneIdBrand: unique symbol;
22
- declare const splitIdBrand: unique symbol;
23
- /** `${kind}::${key}` — the identity of one thing on the canvas. */
24
- type CanvasItemId = string & {
25
- readonly [itemIdBrand]: true;
26
- };
27
- type CanvasPaneId = string & {
28
- readonly [paneIdBrand]: true;
29
- };
30
- type CanvasSplitId = string & {
31
- readonly [splitIdBrand]: true;
32
- };
33
- interface CanvasItem {
34
- readonly id: CanvasItemId;
35
- /** Registered kind id (see `registerCanvasKind`). */
36
- readonly kind: string;
37
- /** Stable key inside the kind — an artifact id, a conversation id, "default". */
38
- readonly key: string;
39
- /** Explicit tab title. `null` ⇒ the kind's `title(data)` or its label. */
40
- readonly title: string | null;
41
- readonly data: CanvasJson;
42
- readonly openedAt: number;
43
- readonly updatedAt: number;
44
- }
45
- interface CanvasPane {
46
- readonly id: CanvasPaneId;
47
- readonly itemIds: readonly CanvasItemId[];
48
- readonly activeItemId: CanvasItemId | null;
49
- }
50
- /** "horizontal" = children side by side; "vertical" = children stacked. */
51
- type CanvasOrientation = "horizontal" | "vertical";
52
- type CanvasLayoutNode = {
53
- readonly type: "pane";
54
- readonly paneId: CanvasPaneId;
5
+ /** One floating thing. Plain data, so a host can draw it in another process. */
6
+ type CanvasFloating = {
7
+ readonly type: "tooltip";
8
+ readonly text: string;
9
+ readonly anchor: CanvasRect;
10
+ readonly side: "top" | "bottom";
55
11
  } | {
56
- readonly type: "split";
57
- readonly id: CanvasSplitId;
58
- readonly orientation: CanvasOrientation;
59
- readonly children: readonly CanvasLayoutNode[];
60
- /** Fractions, one per child, summing to 1. */
61
- readonly sizes: readonly number[];
62
- };
63
- interface CanvasState {
64
- readonly version: 1;
65
- readonly isOpen: boolean;
66
- readonly isFullscreen: boolean;
67
- /** Column width in CSS pixels (desktop). */
68
- readonly width: number;
69
- readonly layout: CanvasLayoutNode;
70
- readonly panes: {
71
- readonly [paneId: string]: CanvasPane;
72
- };
73
- readonly items: {
74
- readonly [itemId: string]: CanvasItem;
75
- };
76
- readonly focusedPaneId: CanvasPaneId;
77
- /** Monotonic counter for minting pane/split ids — keeps the reducer pure. */
78
- readonly seq: number;
79
- /** True once a persisted snapshot was applied (or there was none). */
80
- readonly hydrated: boolean;
81
- }
82
- /** Where a newly opened item goes. Existing items never move on open. */
83
- type CanvasOpenTarget = "focused" | "split-right" | "split-down" | {
12
+ readonly type: "drop-indicator";
13
+ readonly rect: CanvasRect;
84
14
  readonly paneId: CanvasPaneId;
15
+ } | {
16
+ readonly type: "tab-drag";
17
+ readonly itemId: CanvasItemId;
18
+ readonly title: string;
85
19
  };
86
- interface CanvasOpenInput {
87
- readonly kind: string;
88
- readonly key: string;
89
- readonly title?: string | null | undefined;
90
- readonly data?: CanvasJson | undefined;
91
- readonly target?: CanvasOpenTarget | undefined;
92
- /** Reveal the canvas when it is put away. Default true. */
93
- readonly reveal?: boolean | undefined;
94
- /** Make the item the pane's active tab. Default true. */
95
- readonly activate?: boolean | undefined;
20
+ interface CanvasOverlayPort {
21
+ /** Shows a floating element above everything (native views included); returns its remover. */
22
+ show(element: CanvasFloating): () => void;
96
23
  }
97
-
98
- /**
99
- * THE canvas reducer. Plain Redux-compatible reducer + action creators with no
100
- * Redux Toolkit dependency, so it mounts in a host's RTK store
101
- * (`canvasHost: canvasReducer`) or runs inside the package's own standalone
102
- * store with identical behaviour.
103
- *
104
- * Identity law: an item is `kind::key`. Opening an item that is already on the
105
- * canvas never duplicates it — it refreshes its data/title, activates its tab
106
- * and focuses its pane, wherever that pane is.
107
- */
108
-
109
- declare const P = "matrxCanvas/";
110
- type CanvasAction = {
111
- type: `${typeof P}open`;
112
- payload: CanvasOpenInput & {
113
- now: number;
114
- };
115
- } | {
116
- type: `${typeof P}update`;
117
- payload: {
118
- itemId: CanvasItemId;
119
- data?: CanvasJson | undefined;
120
- title?: string | null | undefined;
121
- now: number;
122
- };
123
- } | {
124
- type: `${typeof P}rekey`;
125
- payload: {
126
- itemId: CanvasItemId;
127
- key: string;
128
- };
129
- } | {
130
- type: `${typeof P}closeItem`;
131
- payload: {
132
- itemId: CanvasItemId;
133
- };
134
- } | {
135
- type: `${typeof P}closeOthers`;
136
- payload: {
137
- itemId: CanvasItemId;
138
- };
139
- } | {
140
- type: `${typeof P}activate`;
141
- payload: {
142
- itemId: CanvasItemId;
143
- };
144
- } | {
145
- type: `${typeof P}focusPane`;
146
- payload: {
147
- paneId: CanvasPaneId;
148
- };
149
- } | {
150
- type: `${typeof P}moveItem`;
151
- payload: {
152
- itemId: CanvasItemId;
153
- toPaneId: CanvasPaneId;
154
- index?: number | undefined;
155
- };
156
- } | {
157
- type: `${typeof P}splitPane`;
158
- payload: {
159
- paneId: CanvasPaneId;
160
- orientation: CanvasOrientation;
161
- moveItemId?: CanvasItemId | undefined;
162
- };
163
- } | {
164
- type: `${typeof P}closePane`;
165
- payload: {
166
- paneId: CanvasPaneId;
167
- };
168
- } | {
169
- type: `${typeof P}resizeSplit`;
170
- payload: {
171
- splitId: CanvasSplitId;
172
- sizes: readonly number[];
173
- };
174
- } | {
175
- type: `${typeof P}setOpen`;
176
- payload: {
177
- open: boolean;
178
- };
179
- } | {
180
- type: `${typeof P}toggle`;
181
- } | {
182
- type: `${typeof P}setFullscreen`;
183
- payload: {
184
- fullscreen: boolean;
185
- };
186
- } | {
187
- type: `${typeof P}setWidth`;
188
- payload: {
189
- width: number;
190
- };
191
- } | {
192
- type: `${typeof P}hydrate`;
193
- payload: {
194
- snapshot: CanvasState | null;
195
- };
24
+ /** A serializable "…" menu: the package keeps the handlers, a host draws the entries. */
25
+ type CanvasMenuEntry = {
26
+ readonly type: "item";
27
+ readonly id: string;
28
+ readonly label: string;
29
+ readonly destructive?: boolean;
196
30
  } | {
197
- type: `${typeof P}reset`;
31
+ readonly type: "separator";
198
32
  };
199
-
200
- /**
201
- * The store seam. The canvas never owns a second copy of its state: it reads
202
- * and writes through a CanvasStoreBinding.
203
- *
204
- * - A host WITH Redux mounts `canvasReducer` in its root reducer and binds it:
205
- * bindCanvasToReduxStore(store, (root) => root.canvasHost)
206
- * - A host WITHOUT Redux (a Vite tool, an Electron window) calls
207
- * createCanvasStore()
208
- * which runs the very same reducer in a tiny standalone store.
209
- */
210
-
211
- interface CanvasStoreBinding {
212
- getState(): CanvasState;
213
- dispatch(action: CanvasAction): void;
214
- subscribe(listener: () => void): () => void;
33
+ /** Shows a menu at `anchor` (e.g. Electron `Menu.popup`); resolves the chosen entry id, or null. */
34
+ type CanvasShowMenu = (entries: readonly CanvasMenuEntry[], anchor: CanvasRect) => Promise<string | null>;
35
+ /** A native body's frame: window CSS pixels plus the device pixel ratio. */
36
+ interface CanvasNativeRect extends CanvasRect {
37
+ readonly devicePixelRatio: number;
215
38
  }
216
-
217
- /**
218
- * Remembering the canvas between sessions — a table stake, never optional.
219
- *
220
- * The default port writes to localStorage under a versioned key. Items whose
221
- * kind opts out (`restore: false`, e.g. a live session that cannot come back)
222
- * are dropped from the snapshot, and panes they leave empty are dropped too.
223
- */
224
-
225
- interface CanvasPersistencePort {
226
- load(): CanvasState | null | Promise<CanvasState | null>;
227
- save(snapshot: CanvasState): void | Promise<void>;
228
- }
229
-
230
- /**
231
- * The canvas controller: the ONE imperative API every caller uses. It wraps a
232
- * store binding, validates what callers hand it (so the reducer stays pure and
233
- * trusting), and owns hydration + autosave.
234
- *
235
- * Nothing fails silently: a refused open (non-JSON data, unknown kind) is
236
- * reported through the error sink and returns false.
237
- */
238
-
239
- interface CanvasErrorReport {
240
- readonly code: "non-json-data" | "unknown-kind" | "persistence-load" | "persistence-save";
241
- readonly message: string;
242
- readonly detail?: unknown;
243
- }
244
- type CanvasErrorSink = (report: CanvasErrorReport) => void;
245
- interface CanvasController {
246
- readonly store: CanvasStoreBinding;
247
- getState(): CanvasState;
248
- open(input: CanvasOpenInput): CanvasItemId | null;
249
- update(itemId: CanvasItemId, patch: {
250
- data?: CanvasJson | undefined;
251
- title?: string | null | undefined;
252
- }): boolean;
253
- /** Gives an item a new identity in place (a draft that was saved and now has a durable id). */
254
- rekey(itemId: CanvasItemId, key: string): CanvasItemId | null;
255
- close(itemId: CanvasItemId): void;
256
- closeOthers(itemId: CanvasItemId): void;
257
- activate(itemId: CanvasItemId): void;
258
- focusPane(paneId: CanvasPaneId): void;
259
- moveItem(itemId: CanvasItemId, toPaneId: CanvasPaneId, index?: number): void;
260
- splitPane(paneId: CanvasPaneId, orientation: CanvasOrientation, moveItemId?: CanvasItemId): void;
261
- closePane(paneId: CanvasPaneId): void;
262
- resizeSplit(splitId: CanvasSplitId, sizes: readonly number[]): void;
263
- show(): void;
264
- hide(): void;
265
- toggle(): void;
266
- setFullscreen(fullscreen: boolean): void;
267
- setWidth(width: number): void;
268
- /** Is this exact thing on the canvas right now? */
269
- has(kind: string, key: string): boolean;
270
- /**
271
- * Is a canvas column on screen? A store can exist in a layout that shows no
272
- * column (a kiosk, a meeting stage); opening there must be refused aloud.
273
- */
274
- isPresented(): boolean;
275
- /** Called by a column on mount; returns the unmount callback. */
276
- registerPresentation(): () => void;
277
- subscribePresentation(listener: () => void): () => void;
278
- /** Loads the persisted snapshot and starts autosave. Returns a disposer. */
279
- start(): () => void;
39
+ interface CanvasNativeBodyInfo {
40
+ /** False while package DOM floats over the canvas (a DOM menu, a tab drag): hide the native view. */
41
+ readonly visible: boolean;
42
+ readonly windowId: CanvasWindowId;
280
43
  }
44
+ /** Reports where a native body sits; null when it is hidden or gone. Called in the frame the layout changed. */
45
+ type CanvasNativeBodyFrame = (itemId: CanvasItemId, rect: CanvasNativeRect | null, info: CanvasNativeBodyInfo) => void;
281
46
 
282
47
  /**
283
48
  * THE canvas kind registry. A kind is one sort of thing the canvas can show —
@@ -301,7 +66,9 @@ interface CanvasKindProps<TData extends CanvasJson = CanvasJson> {
301
66
  readonly data: TData;
302
67
  readonly paneId: CanvasPaneId;
303
68
  readonly isFocused: boolean;
69
+ /** The canvas, acting for the window this pane is in. */
304
70
  readonly canvas: CanvasController;
71
+ readonly windowId: CanvasWindowId;
305
72
  }
306
73
  interface CanvasMenuItem {
307
74
  readonly id: string;
@@ -317,7 +84,7 @@ interface CanvasKind<TData extends CanvasJson = CanvasJson> {
317
84
  readonly icon: ComponentType<{
318
85
  className?: string;
319
86
  }>;
320
- /** Eager component. Provide this OR `load`. */
87
+ /** Eager component. Provide this OR `load` (optional for a native body or an `unavailable` placeholder). */
321
88
  readonly component?: ComponentType<CanvasKindProps<TData>>;
322
89
  /** Lazy component — the kind's code loads only when a tab of it renders. */
323
90
  readonly load?: () => Promise<{
@@ -325,16 +92,45 @@ interface CanvasKind<TData extends CanvasJson = CanvasJson> {
325
92
  }>;
326
93
  /** Tab title from the item's data. Falls back to the item's title, then `label`. */
327
94
  readonly title?: (data: TData, item: CanvasItem) => string;
328
- /** Comes back after a reload. Default true; false for live sessions that cannot resume. */
329
- readonly restore?: boolean;
95
+ /**
96
+ * Comes back after a reload. Default true; false for live things that cannot
97
+ * resume. "session": the tab is a view onto a process the HOST keeps (a
98
+ * terminal) — it comes back, closing it DETACHES (onDetach) instead of
99
+ * killing, and a restore or a move REATTACHES (onAttach).
100
+ */
101
+ readonly restore?: boolean | "session";
102
+ /** restore "session": the session's key. Default: `data.sessionKey` when it is a string. */
103
+ readonly sessionKey?: (data: TData, item: CanvasItem) => string | null;
104
+ /** restore "session": the tab now shows this session ("open" | "restore" | "arrive"). */
105
+ readonly onAttach?: (event: CanvasSessionEvent<CanvasSessionAttachReason>) => void;
106
+ /** restore "session": the tab no longer shows it ("close" | "leave" | "unmount"). Never kill the process here. */
107
+ readonly onDetach?: (event: CanvasSessionEvent<CanvasSessionDetachReason>) => void;
330
108
  /** Stays mounted while its tab is in the background (live chat, a running tool). */
331
109
  readonly keepAlive?: boolean;
110
+ /**
111
+ * "native": the body is drawn by the HOST outside the DOM (an Electron
112
+ * WebContentsView). The pane renders a placeholder and reports its rect
113
+ * through the provider's `onNativeBodyFrame`. Default "dom".
114
+ */
115
+ readonly body?: "dom" | "native";
116
+ /**
117
+ * An honest one-line state instead of the body while its backend is not
118
+ * there ("Files · next release", "No changes to show"). Return null to show
119
+ * the body. Read on every render.
120
+ */
121
+ readonly unavailable?: (data: TData, item: CanvasItem) => string | null;
332
122
  /** When set, the kind is offered in an empty pane's launcher. */
333
123
  readonly launcher?: {
334
124
  readonly key: string;
335
125
  readonly data: TData;
336
126
  readonly title?: string;
337
127
  };
128
+ /**
129
+ * Controls at the START of the pane header, after the title or tabs: a
130
+ * "+ new terminal", a browser's back / forward / reload / address bar. The
131
+ * slot grows to fill the header.
132
+ */
133
+ readonly HeaderLeading?: ComponentType<CanvasKindProps<TData>>;
338
134
  /** The kind's own button, rendered left of the pane's "…" menu. */
339
135
  readonly HeaderAction?: ComponentType<CanvasKindProps<TData>>;
340
136
  /** Kind-specific entries for the pane's "…" menu. */
@@ -347,6 +143,8 @@ type AnyCanvasKind = CanvasKind<CanvasJson>;
347
143
  * the registry stores the erased form (the cast is the one registration seam).
348
144
  */
349
145
  declare function defineCanvasKind<TData extends CanvasJson>(kind: CanvasKind<TData>): AnyCanvasKind;
146
+ /** The session key of an item of a session kind (`kind.sessionKey`, else `data.sessionKey`). */
147
+ declare function canvasSessionKey(kind: AnyCanvasKind, item: CanvasItem): string | null;
350
148
  /** Registers (or replaces) a kind. Returns an unregister function. */
351
149
  declare function registerCanvasKind(kind: AnyCanvasKind): () => void;
352
150
  declare function registerCanvasKinds(kinds: readonly AnyCanvasKind[]): () => void;
@@ -354,33 +152,75 @@ declare function getCanvasKind(id: string): AnyCanvasKind | undefined;
354
152
  declare function listCanvasKinds(): AnyCanvasKind[];
355
153
 
356
154
  /**
357
- * Host capabilities that apply to EVERY kind — this is how saving, sharing and
358
- * history are "handled globally": the host answers them once, here, and every
359
- * item that qualifies gets the entries in its "…" menu.
155
+ * What the host answers ONCE for every kind. Saving, sharing and history are
156
+ * "handled globally" here; the window ports let a desktop host draw floating
157
+ * things and native bodies its own way. Every port has a working default.
360
158
  */
361
159
  interface CanvasHostPorts {
362
160
  /** Extra "…" menu entries for an item (share, save to cloud, version history…). */
363
- readonly itemActions?: (item: CanvasItem, kind: AnyCanvasKind | undefined) => readonly CanvasMenuItem[];
364
- /** Pops an item out into a floating window. Absent ⇒ no "Pop out" entry. */
365
- readonly popOut?: (item: CanvasItem) => void;
161
+ readonly itemActions?: ((item: CanvasItem, kind: AnyCanvasKind | undefined) => readonly CanvasMenuItem[]) | undefined;
162
+ /**
163
+ * Opens a window that renders this canvas for the returned window id (web: a
164
+ * floating panel with <CanvasWindowScope>; desktop: a BrowserWindow with its
165
+ * own provider). The item then moves there. Absent ⇒ no "Pop out" entry, and
166
+ * `controller.popOut` is refused aloud.
167
+ */
168
+ readonly popOut?: ((item: CanvasItem) => Promise<{
169
+ readonly windowId: string;
170
+ } | null>) | undefined;
171
+ /** A tab docked back out of `fromWindowId`. Close that window once the state no longer lists it. */
172
+ readonly dockBack?: ((itemId: CanvasItemId, fromWindowId: CanvasWindowId) => void) | undefined;
173
+ /** Draws the "…" menu (Electron `Menu.popup`). Default: the package's DOM menu. */
174
+ readonly showMenu?: CanvasShowMenu | undefined;
175
+ /** Draws tooltips, drop indicators and tab drags above native views. Default: in the DOM. */
176
+ readonly overlay?: CanvasOverlayPort | undefined;
177
+ /** Where each native-body kind's view goes, reported in the frame the layout changed. */
178
+ readonly onNativeBodyFrame?: CanvasNativeBodyFrame | undefined;
366
179
  }
180
+ type CanvasTabStripMode = "auto" | "always";
367
181
  interface CanvasProviderProps extends CanvasHostPorts {
368
182
  readonly children: ReactNode;
369
- /** A Redux-bound store (bindCanvasToReduxStore). Omit for a standalone store. */
183
+ /** A Redux-bound store (bindCanvasToReduxStore), a remote one (createRemoteCanvasStore), or omit for a standalone store. */
370
184
  readonly store?: CanvasStoreBinding;
371
- /** `null` turns memory off. Default: localStorage. */
185
+ /** `null` turns memory off. Default: localStorage. Ignored for a remote store (its owner saves). */
372
186
  readonly persistence?: CanvasPersistencePort | null;
373
187
  readonly onError?: CanvasErrorSink;
374
- /** ⌘\ / Ctrl+\ toggles the canvas; Escape leaves full screen. Default true. */
188
+ /** Binds the shortcut table's web shortcuts (⌘\ toggles, Esc leaves expand…). Default true. */
375
189
  readonly hotkeys?: boolean;
190
+ /** The window this provider renders. Default: the main window. */
191
+ readonly windowId?: string;
192
+ /** Width and split numbers, read once. Default: CANVAS_WEB_LAYOUT_RULES. */
193
+ readonly layoutRules?: Partial<CanvasLayoutRules>;
194
+ /** Live width of the region the canvas shares with the content beside it (desktop: right of the sidebar). Default: the window. */
195
+ readonly regionWidth?: number | null;
196
+ /** "auto": a pane with one tab shows a title instead of a tab strip. Default "auto". */
197
+ readonly tabStrip?: CanvasTabStripMode;
376
198
  }
377
- declare function CanvasProvider({ children, store, persistence, onError, hotkeys, itemActions, popOut, }: CanvasProviderProps): react.JSX.Element;
378
- /** The controller: open, close, toggle, split… */
199
+ declare function CanvasProvider({ children, store, persistence, onError, hotkeys, windowId: windowIdProp, layoutRules, regionWidth, tabStrip, ...hostPorts }: CanvasProviderProps): react.JSX.Element;
200
+ /**
201
+ * Renders a subtree as ANOTHER window of the same canvas — the web host's
202
+ * pop-out panel: `<CanvasWindowScope windowId={id}><CanvasColumn placement="fill"/></CanvasWindowScope>`.
203
+ */
204
+ declare function CanvasWindowScope({ windowId, children }: {
205
+ windowId: string;
206
+ children: ReactNode;
207
+ }): react.JSX.Element;
208
+ /** The controller (acting for this window): open, close, toggle, split… */
379
209
  declare function useCanvas(): CanvasController;
380
210
  /** Same as useCanvas, but null outside a provider (for components that may render anywhere). */
381
211
  declare function useOptionalCanvas(): CanvasController | null;
212
+ /** The window this subtree renders. */
213
+ declare function useCanvasWindowId(): CanvasWindowId;
382
214
  declare function useCanvasHostPorts(): CanvasHostPorts;
383
- /** True when a canvas column is on screen in this tree — the ONE availability answer. */
215
+ /**
216
+ * Native-body controls. `remeasure()` re-reports every native body's frame now —
217
+ * call it on each animation frame while the host animates its own layout (a
218
+ * sidebar collapsing moves the canvas without resizing it).
219
+ */
220
+ declare function useCanvasNativeBodies(): {
221
+ readonly remeasure: () => void;
222
+ };
223
+ /** True when a canvas column is on screen for this window — the ONE availability answer. */
384
224
  declare function useCanvasIsPresented(): boolean;
385
225
  /** Subscribes to a slice of canvas state. The selector must return stable values. */
386
226
  declare function useCanvasState<T>(selector: (state: CanvasState) => T): T;
@@ -394,22 +234,24 @@ declare function useOptionalCanvasState<T>(selector: (state: CanvasState) => T,
394
234
  declare function useCanvasKinds(): readonly AnyCanvasKind[];
395
235
  declare function useCanvasKind(id: string): AnyCanvasKind | undefined;
396
236
 
397
- /** The column's rendered width in px: 0 when put away, null when full screen. */
237
+ /** The column's rendered width in px for this window: 0 when put away, null when expanded. */
398
238
  declare function useCanvasColumnWidth(): number | null;
399
239
  interface CanvasColumnProps {
400
240
  readonly className?: string;
401
241
  readonly style?: CSSProperties;
402
242
  /** Called with the live width while the edge is dragged, then null — lets a host shell reflow in step. */
403
243
  readonly onLiveWidth?: (width: number | null) => void;
244
+ /** "docked": the right-edge column with a width handle. "fill": fills its container (a pop-out window). */
245
+ readonly placement?: "docked" | "fill";
404
246
  }
405
- declare function CanvasColumn({ className, style, onLiveWidth }: CanvasColumnProps): react.JSX.Element | null;
406
- /** THE one button that opens and puts away the canvas. */
247
+ declare function CanvasColumn({ className, style, onLiveWidth, placement }: CanvasColumnProps): react.JSX.Element | null;
248
+ /** THE one button that opens and puts away the canvas (this window's). */
407
249
  declare function CanvasToggle({ className }: {
408
250
  className?: string;
409
251
  }): react.JSX.Element;
410
252
  /**
411
253
  * For hosts without their own shell (a Vite app, an Electron window): the app
412
- * on the left, the canvas column on the right, full screen handled.
254
+ * on the left, the canvas column on the right, expand handled.
413
255
  */
414
256
  declare function CanvasFrame({ children, className }: {
415
257
  children: ReactNode;
@@ -421,4 +263,105 @@ declare function CanvasPaneView({ paneId }: {
421
263
  paneId: CanvasPaneId;
422
264
  }): react.JSX.Element | null;
423
265
 
424
- export { type AnyCanvasKind, CanvasColumn, type CanvasColumnProps, CanvasFrame, type CanvasHostPorts, type CanvasKind, type CanvasKindProps, type CanvasMenuItem, CanvasPaneView, CanvasProvider, type CanvasProviderProps, CanvasToggle, defineCanvasKind, getCanvasKind, itemTitle, listCanvasKinds, registerCanvasKind, registerCanvasKinds, useCanvas, useCanvasColumnWidth, useCanvasHostPorts, useCanvasIsPresented, useCanvasKind, useCanvasKinds, useCanvasState, useOptionalCanvas, useOptionalCanvasState };
266
+ interface CanvasHeaderButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | "title"> {
267
+ /** Accessible name and tooltip. */
268
+ readonly label: string;
269
+ /** Appended to the tooltip, e.g. "⌘\\". */
270
+ readonly shortcut?: string | null | undefined;
271
+ /** False draws the button dimmed and inert (a browser's Back with no history). Default true. */
272
+ readonly available?: boolean;
273
+ /** "sm" = a pane-header action (24px); "md" = a browser bar button (28px). */
274
+ readonly size?: "sm" | "md";
275
+ readonly pressed?: boolean;
276
+ readonly children: ReactNode;
277
+ }
278
+ /** The one icon button of the canvas chrome. */
279
+ declare const CanvasHeaderButton: react.ForwardRefExoticComponent<CanvasHeaderButtonProps & react.RefAttributes<HTMLButtonElement>>;
280
+ interface CanvasPanelProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
281
+ readonly panelId: string;
282
+ /** The header title (a single-tab pane, a panel with no tabs). */
283
+ readonly title: ReactNode;
284
+ /** Controls after the title or tabs: "+ new terminal", a browser's bar. Grows to fill the header. */
285
+ readonly leading?: ReactNode;
286
+ /** A custom start of the header instead of the title (a tab strip). `leading` still follows it. */
287
+ readonly header?: ReactNode;
288
+ /** Controls just before the "…" menu (a kind's own button). */
289
+ readonly actions?: ReactNode;
290
+ /** The "…" menu: the host renders its own menu around the trigger it receives. */
291
+ readonly renderMenu?: ((trigger: ReactElement) => ReactNode) | undefined;
292
+ readonly expanded?: boolean | undefined;
293
+ readonly onToggleExpand?: (() => void) | undefined;
294
+ readonly expandShortcut?: string | null | undefined;
295
+ /** Phones only: put the canvas away without closing anything. */
296
+ readonly onHide?: (() => void) | undefined;
297
+ readonly onClose?: (() => void) | undefined;
298
+ readonly closeLabel?: string | undefined;
299
+ readonly focused?: boolean | undefined;
300
+ /** Where the header's own body element goes (the pane body). */
301
+ readonly bodyProps?: HTMLAttributes<HTMLDivElement> | undefined;
302
+ }
303
+ /** The menu trigger every panel shares. */
304
+ declare const CanvasMenuTrigger: react.ForwardRefExoticComponent<Omit<CanvasHeaderButtonProps, "children" | "label"> & {
305
+ label?: string;
306
+ } & react.RefAttributes<HTMLButtonElement>>;
307
+ /** The frame every canvas panel shares: header (title or tabs · leading · actions · … · expand · close) over a body. */
308
+ declare const CanvasPanel: react.ForwardRefExoticComponent<CanvasPanelProps & react.RefAttributes<HTMLElement>>;
309
+ /** The one-line honest state of a panel with nothing to show, or whose backend has not shipped. */
310
+ declare function CanvasPanelEmpty({ children, className }: {
311
+ children: ReactNode;
312
+ className?: string;
313
+ }): react.JSX.Element;
314
+ interface CanvasTabProps extends Omit<HTMLAttributes<HTMLDivElement>, "title" | "onSelect"> {
315
+ readonly title: string;
316
+ readonly icon: ReactNode;
317
+ /** Small trailing state after the title, e.g. "exited". */
318
+ readonly note?: string | undefined;
319
+ readonly active: boolean;
320
+ readonly onSelect: () => void;
321
+ /** Absent ⇒ no close button. */
322
+ readonly onClose?: (() => void) | undefined;
323
+ }
324
+ /** One tab of a strip. */
325
+ declare const CanvasTab: react.ForwardRefExoticComponent<CanvasTabProps & react.RefAttributes<HTMLDivElement>>;
326
+ interface BrowserTab {
327
+ readonly id: string;
328
+ readonly title: string;
329
+ /** A favicon URL; a globe is drawn without one. */
330
+ readonly icon?: string | null | undefined;
331
+ /** A glyph instead of a favicon (a terminal tab draws its prompt icon). */
332
+ readonly glyph?: ReactNode;
333
+ /** Small trailing state after the title, e.g. "exited". */
334
+ readonly note?: string | undefined;
335
+ }
336
+ interface BrowserTabsProps {
337
+ readonly tabs: readonly BrowserTab[];
338
+ readonly activeId: string | null;
339
+ readonly onSelect: (id: string) => void;
340
+ readonly onClose: (id: string) => void;
341
+ /** Absent ⇒ no "+" button. */
342
+ readonly onNew?: (() => void) | undefined;
343
+ /** The "+" button's name (default "New tab"). */
344
+ readonly newLabel?: string;
345
+ /** The tab list's name (default "Tabs"). */
346
+ readonly label?: string;
347
+ readonly className?: string;
348
+ }
349
+ /** A tab strip for any panel with its own tabs: a browser's pages, a terminal's shells. */
350
+ declare function BrowserTabs({ tabs, activeId, onSelect, onClose, onNew, newLabel, label, className }: BrowserTabsProps): react.JSX.Element;
351
+ interface BrowserBarProps {
352
+ readonly url: string;
353
+ readonly canGoBack: boolean;
354
+ readonly canGoForward: boolean;
355
+ readonly onBack: () => void;
356
+ readonly onForward: () => void;
357
+ readonly onReload: () => void;
358
+ /** Called with the typed address when the person presses Enter. */
359
+ readonly onNavigate: (address: string) => void;
360
+ /** Controls after the address (screenshot, open in your browser, more). */
361
+ readonly trailing?: ReactNode;
362
+ readonly className?: string;
363
+ }
364
+ /** A browser's back · forward · reload · address bar, for a kind's leading slot or its body. */
365
+ declare function BrowserBar({ url, canGoBack, canGoForward, onBack, onForward, onReload, onNavigate, trailing, className }: BrowserBarProps): react.JSX.Element;
366
+
367
+ 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 };