@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/index.d.cts CHANGED
@@ -1,99 +1,5 @@
1
- /**
2
- * @ai-matrx/canvas — core types.
3
- *
4
- * The canvas is ONE docked column on the right edge of an application. It holds
5
- * panes; panes hold tabs; every tab is one CanvasItem. A CanvasItem is
6
- * identified by `kind` + `key`, so opening the same thing twice always lands on
7
- * the existing tab instead of creating a duplicate.
8
- *
9
- * Everything in CanvasState is plain JSON: it lives in the host's Redux store
10
- * (or the package's own standalone store), it is persisted between sessions,
11
- * and it can be inspected. No functions, no class instances, no React nodes.
12
- */
13
- /** Any value that survives JSON.stringify → JSON.parse unchanged. */
14
- type CanvasJson = string | number | boolean | null | readonly CanvasJson[] | {
15
- readonly [key: string]: CanvasJson | undefined;
16
- };
17
- declare const itemIdBrand: unique symbol;
18
- declare const paneIdBrand: unique symbol;
19
- declare const splitIdBrand: unique symbol;
20
- /** `${kind}::${key}` — the identity of one thing on the canvas. */
21
- type CanvasItemId = string & {
22
- readonly [itemIdBrand]: true;
23
- };
24
- type CanvasPaneId = string & {
25
- readonly [paneIdBrand]: true;
26
- };
27
- type CanvasSplitId = string & {
28
- readonly [splitIdBrand]: true;
29
- };
30
- interface CanvasItem {
31
- readonly id: CanvasItemId;
32
- /** Registered kind id (see `registerCanvasKind`). */
33
- readonly kind: string;
34
- /** Stable key inside the kind — an artifact id, a conversation id, "default". */
35
- readonly key: string;
36
- /** Explicit tab title. `null` ⇒ the kind's `title(data)` or its label. */
37
- readonly title: string | null;
38
- readonly data: CanvasJson;
39
- readonly openedAt: number;
40
- readonly updatedAt: number;
41
- }
42
- interface CanvasPane {
43
- readonly id: CanvasPaneId;
44
- readonly itemIds: readonly CanvasItemId[];
45
- readonly activeItemId: CanvasItemId | null;
46
- }
47
- /** "horizontal" = children side by side; "vertical" = children stacked. */
48
- type CanvasOrientation = "horizontal" | "vertical";
49
- type CanvasLayoutNode = {
50
- readonly type: "pane";
51
- readonly paneId: CanvasPaneId;
52
- } | {
53
- readonly type: "split";
54
- readonly id: CanvasSplitId;
55
- readonly orientation: CanvasOrientation;
56
- readonly children: readonly CanvasLayoutNode[];
57
- /** Fractions, one per child, summing to 1. */
58
- readonly sizes: readonly number[];
59
- };
60
- interface CanvasState {
61
- readonly version: 1;
62
- readonly isOpen: boolean;
63
- readonly isFullscreen: boolean;
64
- /** Column width in CSS pixels (desktop). */
65
- readonly width: number;
66
- readonly layout: CanvasLayoutNode;
67
- readonly panes: {
68
- readonly [paneId: string]: CanvasPane;
69
- };
70
- readonly items: {
71
- readonly [itemId: string]: CanvasItem;
72
- };
73
- readonly focusedPaneId: CanvasPaneId;
74
- /** Monotonic counter for minting pane/split ids — keeps the reducer pure. */
75
- readonly seq: number;
76
- /** True once a persisted snapshot was applied (or there was none). */
77
- readonly hydrated: boolean;
78
- }
79
- /** Where a newly opened item goes. Existing items never move on open. */
80
- type CanvasOpenTarget = "focused" | "split-right" | "split-down" | {
81
- readonly paneId: CanvasPaneId;
82
- };
83
- interface CanvasOpenInput {
84
- readonly kind: string;
85
- readonly key: string;
86
- readonly title?: string | null | undefined;
87
- readonly data?: CanvasJson | undefined;
88
- readonly target?: CanvasOpenTarget | undefined;
89
- /** Reveal the canvas when it is put away. Default true. */
90
- readonly reveal?: boolean | undefined;
91
- /** Make the item the pane's active tab. Default true. */
92
- readonly activate?: boolean | undefined;
93
- }
94
- declare const CANVAS_MIN_WIDTH = 360;
95
- declare const CANVAS_DEFAULT_WIDTH = 640;
96
- declare const CANVAS_MIN_SPLIT_FRACTION = 0.12;
1
+ import { C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, c as CanvasLayoutNode, d as CanvasPaneId, e as CanvasStoreBinding, f as CanvasState, g as CanvasAction, h as CanvasController, i as CanvasItem, j as CanvasExtraWindow, k as CanvasPane, l as canvasWindowOfItem } from './controller-Dv6J6XZm.cjs';
2
+ export { m as CANVAS_DEFAULT_WIDTH, n as CANVAS_DESKTOP_LAYOUT_RULES, o as CANVAS_MAIN_WINDOW, p as CANVAS_MIN_SPLIT_FRACTION, q as CANVAS_MIN_WIDTH, r as CANVAS_STORAGE_KEY, s as CANVAS_WEB_LAYOUT_RULES, t as CanvasControllerOptions, u as CanvasErrorReport, v as CanvasErrorSink, w as CanvasKeyValueStore, x as CanvasLayoutRules, y as CanvasOpenInput, z as CanvasOpenTarget, A as CanvasOrientation, B as CanvasPersistencePort, D as CanvasRect, E as CanvasSessionAttachReason, F as CanvasSessionDetachReason, G as CanvasSessionEvent, H as CanvasSessionHooks, I as CanvasSplitId, J as CanvasWindowCloseMode, K as CanvasWindowFrame, L as CanvasWindowPorts, R as ReduxStoreLike, M as bindCanvasToReduxStore, N as canvasActions, O as canvasReducer, P as canvasWindowFrame, Q as canvasWindowOfPane, S as clampDraggedCanvasWidth, T as consoleCanvasErrorSink, U as createCanvasController, V as createCanvasStore, W as createInitialCanvasState, X as createKeyValueCanvasPersistence, Y as createLocalStorageCanvasPersistence, Z as defaultCanvasWidth, _ as fitCanvasWidth, $ as foldCanvasWindows, a0 as isCanvasAction, a1 as listCanvasWindowIds, a2 as resolveCanvasLayoutRules, a3 as sanitizeCanvasSnapshot, a4 as shouldStackSplit, a5 as toPersistableSnapshot } from './controller-Dv6J6XZm.cjs';
97
3
 
98
4
  declare function canvasItemId(kind: string, key: string): CanvasItemId;
99
5
  declare function parseCanvasItemId(id: CanvasItemId): {
@@ -107,6 +13,8 @@ declare function parseCanvasItemId(id: CanvasItemId): {
107
13
  */
108
14
  declare function findNonJson(value: unknown, path?: string): string | null;
109
15
  declare function isCanvasJson(value: unknown): value is CanvasJson;
16
+ /** Brands a host's window id. `CANVAS_MAIN_WINDOW` is the default window. */
17
+ declare function canvasWindowId(id: string): CanvasWindowId;
110
18
 
111
19
  /**
112
20
  * Pure helpers over the canvas layout tree. Every function returns a new tree
@@ -118,263 +26,121 @@ declare function listPaneIds(node: CanvasLayoutNode): CanvasPaneId[];
118
26
  declare function normalizeSizes(sizes: readonly number[], count: number): number[];
119
27
 
120
28
  /**
121
- * THE canvas reducer. Plain Redux-compatible reducer + action creators with no
122
- * Redux Toolkit dependency, so it mounts in a host's RTK store
123
- * (`canvasHost: canvasReducer`) or runs inside the package's own standalone
124
- * store with identical behaviour.
29
+ * A canvas store that lives in ANOTHER process — an Electron renderer bound to
30
+ * the one store in the main process over IPC.
125
31
  *
126
- * Identity law: an item is `kind::key`. Opening an item that is already on the
127
- * canvas never duplicates it — it refreshes its data/title, activates its tab
128
- * and focuses its pane, wherever that pane is.
32
+ * - dispatch is async and fire-and-forget: the action goes to the owner, and
33
+ * the state changes when the owner's next snapshot arrives (no optimistic
34
+ * copy that could disagree with the owner);
35
+ * - every update is a WHOLE snapshot with no shared object identity, so each
36
+ * one is merged into the previous state structurally: anything unchanged
37
+ * keeps its old reference, an identical snapshot changes nothing and wakes
38
+ * nobody — selector results stay stable and useSyncExternalStore never loops;
39
+ * - the binding is marked `authority: "remote"`: the owner hydrates and saves,
40
+ * so a controller over it never does.
41
+ *
42
+ * The owner side (main process) is the ordinary `createCanvasStore()` +
43
+ * `createCanvasController({ persistence })`; see the README.
129
44
  */
130
45
 
131
- declare const P = "matrxCanvas/";
132
- type CanvasAction = {
133
- type: `${typeof P}open`;
134
- payload: CanvasOpenInput & {
135
- now: number;
136
- };
137
- } | {
138
- type: `${typeof P}update`;
139
- payload: {
140
- itemId: CanvasItemId;
141
- data?: CanvasJson | undefined;
142
- title?: string | null | undefined;
143
- now: number;
144
- };
145
- } | {
146
- type: `${typeof P}rekey`;
147
- payload: {
148
- itemId: CanvasItemId;
149
- key: string;
150
- };
151
- } | {
152
- type: `${typeof P}closeItem`;
153
- payload: {
154
- itemId: CanvasItemId;
155
- };
156
- } | {
157
- type: `${typeof P}closeOthers`;
158
- payload: {
159
- itemId: CanvasItemId;
160
- };
161
- } | {
162
- type: `${typeof P}activate`;
163
- payload: {
164
- itemId: CanvasItemId;
165
- };
166
- } | {
167
- type: `${typeof P}focusPane`;
168
- payload: {
169
- paneId: CanvasPaneId;
170
- };
171
- } | {
172
- type: `${typeof P}moveItem`;
173
- payload: {
174
- itemId: CanvasItemId;
175
- toPaneId: CanvasPaneId;
176
- index?: number | undefined;
177
- };
178
- } | {
179
- type: `${typeof P}splitPane`;
180
- payload: {
181
- paneId: CanvasPaneId;
182
- orientation: CanvasOrientation;
183
- moveItemId?: CanvasItemId | undefined;
184
- };
185
- } | {
186
- type: `${typeof P}closePane`;
187
- payload: {
188
- paneId: CanvasPaneId;
189
- };
190
- } | {
191
- type: `${typeof P}resizeSplit`;
192
- payload: {
193
- splitId: CanvasSplitId;
194
- sizes: readonly number[];
195
- };
196
- } | {
197
- type: `${typeof P}setOpen`;
198
- payload: {
199
- open: boolean;
200
- };
201
- } | {
202
- type: `${typeof P}toggle`;
203
- } | {
204
- type: `${typeof P}setFullscreen`;
205
- payload: {
206
- fullscreen: boolean;
207
- };
208
- } | {
209
- type: `${typeof P}setWidth`;
210
- payload: {
211
- width: number;
212
- };
213
- } | {
214
- type: `${typeof P}hydrate`;
215
- payload: {
216
- snapshot: CanvasState | null;
217
- };
218
- } | {
219
- type: `${typeof P}reset`;
220
- };
221
- declare const canvasActions: {
222
- readonly open: (input: CanvasOpenInput) => CanvasAction;
223
- readonly update: (itemId: CanvasItemId, patch: {
224
- data?: CanvasJson | undefined;
225
- title?: string | null | undefined;
226
- }) => CanvasAction;
227
- /** Gives an item a new identity in place (e.g. a draft that was just saved and now has an id). */
228
- readonly rekey: (itemId: CanvasItemId, key: string) => CanvasAction;
229
- readonly closeItem: (itemId: CanvasItemId) => CanvasAction;
230
- readonly closeOthers: (itemId: CanvasItemId) => CanvasAction;
231
- readonly activate: (itemId: CanvasItemId) => CanvasAction;
232
- readonly focusPane: (paneId: CanvasPaneId) => CanvasAction;
233
- readonly moveItem: (itemId: CanvasItemId, toPaneId: CanvasPaneId, index?: number) => CanvasAction;
234
- readonly splitPane: (paneId: CanvasPaneId, orientation: CanvasOrientation, moveItemId?: CanvasItemId) => CanvasAction;
235
- readonly closePane: (paneId: CanvasPaneId) => CanvasAction;
236
- readonly resizeSplit: (splitId: CanvasSplitId, sizes: readonly number[]) => CanvasAction;
237
- readonly setOpen: (open: boolean) => CanvasAction;
238
- readonly toggle: () => CanvasAction;
239
- readonly setFullscreen: (fullscreen: boolean) => CanvasAction;
240
- readonly setWidth: (width: number) => CanvasAction;
241
- readonly hydrate: (snapshot: CanvasState | null) => CanvasAction;
242
- readonly reset: () => CanvasAction;
243
- };
244
- declare function isCanvasAction(action: unknown): action is CanvasAction;
245
- declare function createInitialCanvasState(): CanvasState;
46
+ interface RemoteCanvasStoreOptions {
47
+ /** The owner's state at connect time (e.g. from an `invoke("canvas:get")`). */
48
+ readonly initialSnapshot: CanvasState;
49
+ /** Sends one action to the owner. A rejection is reported, never swallowed. */
50
+ readonly dispatch: (action: CanvasAction) => Promise<void> | void;
51
+ /** Delivers every new owner snapshot; returns the unsubscribe. */
52
+ readonly subscribe: (onSnapshot: (snapshot: CanvasState) => void) => () => void;
53
+ /** Where a failed dispatch is reported. Default: console.error. */
54
+ readonly onError?: ((error: unknown, action: CanvasAction) => void) | undefined;
55
+ }
56
+ interface RemoteCanvasStore extends CanvasStoreBinding {
57
+ /** Stops listening to the owner. */
58
+ dispose(): void;
59
+ }
60
+ declare function createRemoteCanvasStore(options: RemoteCanvasStoreOptions): RemoteCanvasStore;
246
61
  /**
247
- * Validates a persisted snapshot. Anything malformed is dropped back to the
248
- * initial state rather than half-applied — a corrupt layout must never crash
249
- * the shell.
62
+ * Returns `next`, but with every subtree that is deep-equal to the same subtree
63
+ * of `prev` replaced by `prev`'s object. When nothing changed it returns `prev`
64
+ * itself. Plain JSON only (what crosses a process boundary).
250
65
  */
251
- declare function sanitizeCanvasSnapshot(raw: unknown): CanvasState | null;
252
- declare function canvasReducer(state: CanvasState | undefined, action: {
253
- type: string;
254
- }): CanvasState;
66
+ declare function shareStructure<T>(prev: T, next: T): T;
255
67
 
256
68
  /**
257
- * The store seam. The canvas never owns a second copy of its state: it reads
258
- * and writes through a CanvasStoreBinding.
259
- *
260
- * - A host WITH Redux mounts `canvasReducer` in its root reducer and binds it:
261
- * bindCanvasToReduxStore(store, (root) => root.canvasHost)
262
- * - A host WITHOUT Redux (a Vite tool, an Electron window) calls
263
- * createCanvasStore()
264
- * which runs the very same reducer in a tiny standalone store.
69
+ * The canvas's keyboard shortcuts, as DATA. A web host gets them bound in the
70
+ * DOM by `CanvasProvider`; a desktop host binds the same table in its main
71
+ * process (menu accelerators / `before-input-event`), because keys pressed
72
+ * inside a native web view never reach the renderer's DOM. Every shortcut runs
73
+ * through `runCanvasCommand`, so both paths do exactly the same thing.
265
74
  */
266
75
 
267
- interface CanvasStoreBinding {
268
- getState(): CanvasState;
269
- dispatch(action: CanvasAction): void;
270
- subscribe(listener: () => void): () => void;
271
- }
272
- declare function createCanvasStore(initial?: CanvasState): CanvasStoreBinding;
273
- /** The minimum of a Redux store the canvas needs. */
274
- interface ReduxStoreLike<TRoot> {
275
- getState(): TRoot;
276
- dispatch(action: CanvasAction): unknown;
277
- subscribe(listener: () => void): () => void;
76
+ type CanvasCommandId = "canvas.toggle" | "canvas.toggleFullscreen" | "canvas.exitFullscreen" | "canvas.closeTab" | "canvas.nextTab" | "canvas.previousTab" | "canvas.splitRight" | "canvas.splitDown";
77
+ /**
78
+ * When a shortcut applies:
79
+ * - "presented": a canvas column is on screen in this window;
80
+ * - "fullscreen": the canvas is expanded (and Escape is not owned by a menu or dialog);
81
+ * - "canvas-focus": keyboard focus is inside the canvas (a tab, a pane, a native body).
82
+ */
83
+ type CanvasShortcutWhen = "presented" | "fullscreen" | "canvas-focus";
84
+ interface CanvasShortcut {
85
+ readonly id: CanvasCommandId;
86
+ /** Electron accelerator syntax: "CmdOrCtrl+\\", "Escape", "Ctrl+Shift+Tab". */
87
+ readonly accelerator: string;
88
+ readonly when: CanvasShortcutWhen;
89
+ readonly label: string;
90
+ /** False when browsers reserve the keys (⌘W, Ctrl+Tab): only a desktop host can bind it. */
91
+ readonly web: boolean;
278
92
  }
279
- declare function bindCanvasToReduxStore<TRoot>(store: ReduxStoreLike<TRoot>, select: (root: TRoot) => CanvasState): CanvasStoreBinding;
280
-
93
+ declare const CANVAS_SHORTCUTS: readonly CanvasShortcut[];
94
+ /** The tooltip hint for a command, e.g. "⌘\\" on a Mac. */
95
+ declare function canvasShortcutHint(id: CanvasCommandId, isMac: boolean): string | null;
281
96
  /**
282
- * Remembering the canvas between sessions — a table stake, never optional.
283
- *
284
- * The default port writes to localStorage under a versioned key. Items whose
285
- * kind opts out (`restore: false`, e.g. a live session that cannot come back)
286
- * are dropped from the snapshot, and panes they leave empty are dropped too.
97
+ * Runs one command against a window's canvas. Returns true when it did
98
+ * something (so a binding knows whether to swallow the key).
287
99
  */
288
-
289
- interface CanvasPersistencePort {
290
- load(): CanvasState | null | Promise<CanvasState | null>;
291
- save(snapshot: CanvasState): void | Promise<void>;
100
+ declare function runCanvasCommand(controller: CanvasController, id: CanvasCommandId, windowId?: CanvasWindowId): boolean;
101
+ /** The subset of a KeyboardEvent an accelerator is matched against. */
102
+ interface CanvasKeyInput {
103
+ readonly key: string;
104
+ readonly code?: string;
105
+ readonly metaKey: boolean;
106
+ readonly ctrlKey: boolean;
107
+ readonly altKey: boolean;
108
+ readonly shiftKey: boolean;
292
109
  }
293
- declare const CANVAS_STORAGE_KEY = "ai-matrx.canvas.v1";
294
- declare function createLocalStorageCanvasPersistence(key?: string, storage?: Pick<Storage, "getItem" | "setItem"> | null): CanvasPersistencePort;
295
- /** Builds the snapshot that is actually written: only restorable items. */
296
- declare function toPersistableSnapshot(state: CanvasState, isRestorable: (kind: string) => boolean): CanvasState;
297
-
298
110
  /**
299
- * The canvas controller: the ONE imperative API every caller uses. It wraps a
300
- * store binding, validates what callers hand it (so the reducer stays pure and
301
- * trusting), and owns hydration + autosave.
302
- *
303
- * Nothing fails silently: a refused open (non-JSON data, unknown kind) is
304
- * reported through the error sink and returns false.
111
+ * Whether a key event is this accelerator. "CmdOrCtrl" is ⌘ on a Mac and Ctrl
112
+ * elsewhere; symbol keys match by physical key (⌥\ types « on a Mac).
305
113
  */
114
+ declare function matchesCanvasAccelerator(input: CanvasKeyInput, accelerator: string, isMac: boolean): boolean;
306
115
 
307
- interface CanvasErrorReport {
308
- readonly code: "non-json-data" | "unknown-kind" | "persistence-load" | "persistence-save";
309
- readonly message: string;
310
- readonly detail?: unknown;
311
- }
312
- type CanvasErrorSink = (report: CanvasErrorReport) => void;
313
- declare const consoleCanvasErrorSink: CanvasErrorSink;
314
- interface CanvasControllerOptions {
315
- readonly store: CanvasStoreBinding;
316
- readonly persistence?: CanvasPersistencePort | null | undefined;
317
- /** Kinds that may not come back after a reload. Default: every kind restores. */
318
- readonly isRestorable?: ((kind: string) => boolean) | undefined;
319
- /** When given, opens of an unregistered kind are refused and reported. */
320
- readonly isKnownKind?: ((kind: string) => boolean) | undefined;
321
- readonly onError?: CanvasErrorSink | undefined;
322
- readonly saveDelayMs?: number | undefined;
323
- /**
324
- * Whether a remembered "open" may be restored right now. A host returns
325
- * false where an open canvas would take the whole screen (a phone).
326
- */
327
- readonly mayRestoreOpen?: (() => boolean) | undefined;
328
- }
329
- interface CanvasController {
330
- readonly store: CanvasStoreBinding;
331
- getState(): CanvasState;
332
- open(input: CanvasOpenInput): CanvasItemId | null;
333
- update(itemId: CanvasItemId, patch: {
334
- data?: CanvasJson | undefined;
335
- title?: string | null | undefined;
336
- }): boolean;
337
- /** Gives an item a new identity in place (a draft that was saved and now has a durable id). */
338
- rekey(itemId: CanvasItemId, key: string): CanvasItemId | null;
339
- close(itemId: CanvasItemId): void;
340
- closeOthers(itemId: CanvasItemId): void;
341
- activate(itemId: CanvasItemId): void;
342
- focusPane(paneId: CanvasPaneId): void;
343
- moveItem(itemId: CanvasItemId, toPaneId: CanvasPaneId, index?: number): void;
344
- splitPane(paneId: CanvasPaneId, orientation: CanvasOrientation, moveItemId?: CanvasItemId): void;
345
- closePane(paneId: CanvasPaneId): void;
346
- resizeSplit(splitId: CanvasSplitId, sizes: readonly number[]): void;
347
- show(): void;
348
- hide(): void;
349
- toggle(): void;
350
- setFullscreen(fullscreen: boolean): void;
351
- setWidth(width: number): void;
352
- /** Is this exact thing on the canvas right now? */
353
- has(kind: string, key: string): boolean;
354
- /**
355
- * Is a canvas column on screen? A store can exist in a layout that shows no
356
- * column (a kiosk, a meeting stage); opening there must be refused aloud.
357
- */
358
- isPresented(): boolean;
359
- /** Called by a column on mount; returns the unmount callback. */
360
- registerPresentation(): () => void;
361
- subscribePresentation(listener: () => void): () => void;
362
- /** Loads the persisted snapshot and starts autosave. Returns a disposer. */
363
- start(): () => void;
364
- }
365
- declare function createCanvasController(options: CanvasControllerOptions): CanvasController;
116
+ /**
117
+ * Selectors over CanvasState. Each returns a value that is referentially
118
+ * stable for an unchanged state, so they are safe in useSyncExternalStore and
119
+ * in a host's useSelector. Window-scoped selectors default to the main window;
120
+ * an unknown window reads as closed and empty.
121
+ */
366
122
 
367
- declare const selectCanvasIsOpen: (s: CanvasState) => boolean;
368
- declare const selectCanvasIsFullscreen: (s: CanvasState) => boolean;
369
- declare const selectCanvasWidth: (s: CanvasState) => number;
370
- declare const selectCanvasLayout: (s: CanvasState) => CanvasLayoutNode;
371
- declare const selectCanvasFocusedPaneId: (s: CanvasState) => CanvasPaneId;
123
+ declare const selectCanvasIsOpen: (s: CanvasState, windowId?: CanvasWindowId) => boolean;
124
+ declare const selectCanvasIsFullscreen: (s: CanvasState, windowId?: CanvasWindowId) => boolean;
125
+ /** The width the person chose, or null while the host's layout rule decides. */
126
+ declare const selectCanvasWidth: (s: CanvasState, windowId?: CanvasWindowId) => number | null;
127
+ declare const selectCanvasLayout: (s: CanvasState, windowId?: CanvasWindowId) => CanvasLayoutNode | null;
128
+ declare const selectCanvasFocusedPaneId: (s: CanvasState, windowId?: CanvasWindowId) => CanvasPaneId | null;
372
129
  declare const selectCanvasIsHydrated: (s: CanvasState) => boolean;
130
+ /** Every item on the canvas, in every window. */
373
131
  declare const selectCanvasItemCount: (s: CanvasState) => number;
374
132
  declare const selectCanvasPane: (s: CanvasState, paneId: CanvasPaneId) => CanvasPane | undefined;
375
133
  declare const selectCanvasItem: (s: CanvasState, itemId: CanvasItemId) => CanvasItem | undefined;
376
- declare function selectCanvasPaneCount(s: CanvasState): number;
377
- /** The item the person is looking at in the focused pane. */
378
- declare function selectCanvasActiveItem(s: CanvasState): CanvasItem | null;
134
+ declare function selectCanvasPaneCount(s: CanvasState, windowId?: CanvasWindowId): number;
135
+ /** Items shown in one window. */
136
+ declare function selectCanvasWindowItemCount(s: CanvasState, windowId?: CanvasWindowId): number;
137
+ /** The item the person is looking at in a window's focused pane. */
138
+ declare function selectCanvasActiveItem(s: CanvasState, windowId?: CanvasWindowId): CanvasItem | null;
139
+ /** Windows other than main (second app windows and pop-outs), by id. Stable per state. */
140
+ declare function selectCanvasWindows(s: CanvasState): CanvasState["windows"];
141
+ /** One extra window, or undefined (main is never in this map). */
142
+ declare const selectCanvasExtraWindow: (s: CanvasState, windowId: CanvasWindowId) => CanvasExtraWindow | undefined;
143
+ /** The window an item is in, or null when it is not on the canvas. */
144
+ declare const selectCanvasWindowOfItem: typeof canvasWindowOfItem;
379
145
 
380
- export { CANVAS_DEFAULT_WIDTH, CANVAS_MIN_SPLIT_FRACTION, CANVAS_MIN_WIDTH, CANVAS_STORAGE_KEY, type CanvasAction, type CanvasController, type CanvasControllerOptions, type CanvasErrorReport, type CanvasErrorSink, type CanvasItem, type CanvasItemId, type CanvasJson, type CanvasLayoutNode, type CanvasOpenInput, type CanvasOpenTarget, type CanvasOrientation, type CanvasPane, type CanvasPaneId, type CanvasPersistencePort, type CanvasSplitId, type CanvasState, type CanvasStoreBinding, type ReduxStoreLike, bindCanvasToReduxStore, canvasActions, canvasItemId, canvasReducer, consoleCanvasErrorSink, createCanvasController, createCanvasStore, createInitialCanvasState, createLocalStorageCanvasPersistence, findNonJson, isCanvasAction, isCanvasJson, listPaneIds, normalizeSizes, parseCanvasItemId, sanitizeCanvasSnapshot, selectCanvasActiveItem, selectCanvasFocusedPaneId, selectCanvasIsFullscreen, selectCanvasIsHydrated, selectCanvasIsOpen, selectCanvasItem, selectCanvasItemCount, selectCanvasLayout, selectCanvasPane, selectCanvasPaneCount, selectCanvasWidth, toPersistableSnapshot };
146
+ export { CANVAS_SHORTCUTS, CanvasAction, type CanvasCommandId, CanvasController, CanvasExtraWindow, CanvasItem, CanvasItemId, CanvasJson, type CanvasKeyInput, CanvasLayoutNode, CanvasPane, CanvasPaneId, type CanvasShortcut, type CanvasShortcutWhen, CanvasState, CanvasStoreBinding, CanvasWindowId, type RemoteCanvasStore, type RemoteCanvasStoreOptions, canvasItemId, canvasShortcutHint, canvasWindowId, canvasWindowOfItem, createRemoteCanvasStore, findNonJson, isCanvasJson, listPaneIds, matchesCanvasAccelerator, normalizeSizes, parseCanvasItemId, runCanvasCommand, selectCanvasActiveItem, selectCanvasExtraWindow, selectCanvasFocusedPaneId, selectCanvasIsFullscreen, selectCanvasIsHydrated, selectCanvasIsOpen, selectCanvasItem, selectCanvasItemCount, selectCanvasLayout, selectCanvasPane, selectCanvasPaneCount, selectCanvasWidth, selectCanvasWindowItemCount, selectCanvasWindowOfItem, selectCanvasWindows, shareStructure };