@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/CHANGELOG.md +35 -0
- package/README.md +114 -4
- package/dist/controller-Dv6J6XZm.d.cts +576 -0
- package/dist/controller-Dv6J6XZm.d.ts +576 -0
- package/dist/index.cjs +743 -104
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -334
- package/dist/index.d.ts +100 -334
- package/dist/index.js +743 -104
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1476 -406
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +233 -290
- package/dist/react.d.ts +233 -290
- package/dist/react.js +1486 -404
- package/dist/react.js.map +1 -1
- package/dist/styles.css +346 -51
- package/dist/tokens.css +58 -36
- package/package.json +1 -1
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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: "
|
|
57
|
-
readonly
|
|
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
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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:
|
|
31
|
+
readonly type: "separator";
|
|
198
32
|
};
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
329
|
-
|
|
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
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
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
|
-
/**
|
|
365
|
-
|
|
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)
|
|
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
|
-
/**
|
|
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,
|
|
378
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
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,
|
|
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
|
-
|
|
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 };
|