@dynamix-layout/core 1.2.0 → 2.0.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 +28 -0
- package/README.md +23 -192
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +519 -0
- package/dist/index.d.ts +519 -0
- package/dist/index.js +1338 -0
- package/dist/index.umd.js +1 -0
- package/package.json +12 -11
- package/dist/core.cjs +0 -57
- package/dist/core.es.js +0 -1381
- package/dist/core.iife.js +0 -57
- package/dist/core.umd.js +0 -57
- package/dist/types/index.d.cts +0 -522
- package/dist/types/index.d.ts +0 -522
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Positions an absolutely positioned element. Adapters use this on their fast
|
|
3
|
+
* path (drags), so pointer moves never need a framework re-render.
|
|
4
|
+
* @param element - An absolutely positioned element inside the layout root.
|
|
5
|
+
* @param rect - Where to put it, in layout-root coordinates.
|
|
6
|
+
* @example
|
|
7
|
+
* layout.subscribe((s) => s.rects.tabsets.forEach((rect, id) => applyRect(panels.get(id)!, rect)))
|
|
8
|
+
*/
|
|
9
|
+
export declare function applyRect(element: HTMLElement, rect: Rect): void;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Coalesces bursts of updates (pointer events can fire several times per
|
|
13
|
+
* frame) into at most one `onFlush` call per animation frame.
|
|
14
|
+
* @param onFlush - Called with the latest scheduled value, at most once per frame.
|
|
15
|
+
* @returns `schedule`, `flush` and `cancel`.
|
|
16
|
+
* @example
|
|
17
|
+
* const frame = createFrameScheduler((point: Point) => layout.updateDrag(point))
|
|
18
|
+
* element.addEventListener('pointermove', (e) => frame.schedule(toRootPoint(e)))
|
|
19
|
+
* element.addEventListener('pointerup', () => { frame.flush(); layout.endDrag() })
|
|
20
|
+
*/
|
|
21
|
+
export declare function createFrameScheduler<T>(onFlush: (value: T) => void): FrameScheduler<T>;
|
|
22
|
+
|
|
23
|
+
/** Generates ids for new rows and tabsets. */
|
|
24
|
+
export declare type CreateId = (kind: 'row' | 'tabset', hint?: string) => string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Creates a layout instance.
|
|
28
|
+
*
|
|
29
|
+
* @param options - Open tabs, an optional saved layout (v1 or v2), sizes and callbacks.
|
|
30
|
+
* @returns An instance that shares nothing with other instances. It never
|
|
31
|
+
* touches the DOM; call `setContainerRect` to give it a size.
|
|
32
|
+
* @throws {DynamixLayoutError} `INVALID_LAYOUT` or `UNSUPPORTED_VERSION` for a
|
|
33
|
+
* bad `initialLayout`; `DUPLICATE_TAB_ID` for duplicate tab ids in development.
|
|
34
|
+
* @example
|
|
35
|
+
* const layout = createLayout({
|
|
36
|
+
* tabs: [{ id: 'editor' }, { id: 'terminal' }],
|
|
37
|
+
* onLayoutChange: (json) => localStorage.setItem('layout', JSON.stringify(json)),
|
|
38
|
+
* })
|
|
39
|
+
* layout.subscribe((snapshot) => render(snapshot))
|
|
40
|
+
* layout.setContainerRect({ x: 0, y: 0, width: 1200, height: 800 })
|
|
41
|
+
*/
|
|
42
|
+
export declare function createLayout(options: LayoutOptions): Layout;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Direction a row lays out its children in.
|
|
46
|
+
* `'horizontal'` places them side by side; `'vertical'` stacks them.
|
|
47
|
+
*/
|
|
48
|
+
export declare type Direction = 'horizontal' | 'vertical';
|
|
49
|
+
|
|
50
|
+
/** What is being dragged. */
|
|
51
|
+
export declare type DragSource = {
|
|
52
|
+
readonly type: 'tab';
|
|
53
|
+
readonly tabId: string;
|
|
54
|
+
} | {
|
|
55
|
+
readonly type: 'tabset';
|
|
56
|
+
readonly tabsetId: string;
|
|
57
|
+
} | {
|
|
58
|
+
readonly type: 'splitter';
|
|
59
|
+
readonly splitterId: string;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** The current drag, if any. */
|
|
63
|
+
export declare interface DragState {
|
|
64
|
+
readonly source: DragSource;
|
|
65
|
+
/** Where a tab or tabset would land; `null` over nothing valid. */
|
|
66
|
+
readonly target: DropTarget | null;
|
|
67
|
+
/** Rect of the drop indicator for `target`. */
|
|
68
|
+
readonly indicator: Rect | null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Tab bar geometry the engine can't know (label widths), keyed by tabset id. */
|
|
72
|
+
export declare interface DropMeasurements {
|
|
73
|
+
readonly tabBars: ReadonlyMap<string, TabBarMeasurement>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Where a dragged tab or tabset is dropped. */
|
|
77
|
+
export declare type DropTarget = {
|
|
78
|
+
readonly type: 'tabset';
|
|
79
|
+
readonly tabsetId: string;
|
|
80
|
+
readonly position: Side | 'center';
|
|
81
|
+
} | {
|
|
82
|
+
readonly type: 'tab';
|
|
83
|
+
readonly tabId: string;
|
|
84
|
+
readonly position: 'before' | 'after';
|
|
85
|
+
} | {
|
|
86
|
+
readonly type: 'root';
|
|
87
|
+
readonly position: Side;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Thrown for invalid input: malformed saved layouts, unsupported versions,
|
|
92
|
+
* and duplicate tab ids in development. Actions never throw.
|
|
93
|
+
* @example
|
|
94
|
+
* try {
|
|
95
|
+
* layout.load(JSON.parse(stored))
|
|
96
|
+
* } catch (error) {
|
|
97
|
+
* if (error instanceof DynamixLayoutError) console.warn(error.code, error.path)
|
|
98
|
+
* else throw error
|
|
99
|
+
* }
|
|
100
|
+
*/
|
|
101
|
+
export declare class DynamixLayoutError extends Error {
|
|
102
|
+
readonly code: DynamixLayoutErrorCode;
|
|
103
|
+
/** Where in the input the problem is, e.g. `root.children[1].weight`. */
|
|
104
|
+
readonly path?: string;
|
|
105
|
+
constructor(code: DynamixLayoutErrorCode, message: string, path?: string);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Codes of errors thrown by the layout. */
|
|
109
|
+
export declare type DynamixLayoutErrorCode = 'INVALID_LAYOUT' | 'UNSUPPORTED_VERSION' | 'DUPLICATE_TAB_ID';
|
|
110
|
+
|
|
111
|
+
export declare interface FrameScheduler<T> {
|
|
112
|
+
/** Remember `value`; `onFlush` runs with the latest value on the next frame. */
|
|
113
|
+
schedule: (value: T) => void;
|
|
114
|
+
/** Run a pending flush now (e.g. on pointer up). */
|
|
115
|
+
flush: () => void;
|
|
116
|
+
/** Drop a pending flush (e.g. on unmount). */
|
|
117
|
+
cancel: () => void;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Rect of the drop zone on one edge of the layout, centred on that edge.
|
|
122
|
+
* @param container - The layout's container rect (`snapshot.rects.container`).
|
|
123
|
+
* @param side - The edge.
|
|
124
|
+
* @param options - Zone length (share of the edge) and thickness.
|
|
125
|
+
* @returns The zone rect, in layout-root coordinates.
|
|
126
|
+
* @example
|
|
127
|
+
* const zone = getRootDropZoneRect(snapshot.rects.container, 'left')
|
|
128
|
+
*/
|
|
129
|
+
export declare function getRootDropZoneRect(container: Rect, side: Side, options?: RootDropZoneOptions): Rect;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param tabset - The tabset's rect and state.
|
|
133
|
+
* @param tabBarHeight - Height of a horizontal tab bar.
|
|
134
|
+
* @returns The rect to give the tab bar element, and whether to rotate it.
|
|
135
|
+
* @example
|
|
136
|
+
* const { rect, isRotated } = getTabBarPlacement(snapshot.rects.tabsets.get(id)!, snapshot.tabsets.get(id)!, 40)
|
|
137
|
+
* applyRect(tabBar, rect)
|
|
138
|
+
* tabBar.style.transform = isRotated ? 'rotate(90deg)' : ''
|
|
139
|
+
*/
|
|
140
|
+
export declare function getTabBarPlacement(tabsetRect: Rect, tabset: {
|
|
141
|
+
readonly isFolded: boolean;
|
|
142
|
+
readonly parentDirection: Direction;
|
|
143
|
+
}, tabBarHeight: number): TabBarPlacement;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Area of a tabset below its tab bar; never negative when squeezed.
|
|
147
|
+
* @param tabsetRect - The tabset's rect.
|
|
148
|
+
* @param tabBarHeight - Height of its tab bar (0 without one).
|
|
149
|
+
* @returns The content area.
|
|
150
|
+
* @example
|
|
151
|
+
* applyRect(content, getTabContentRect(snapshot.rects.tabsets.get(tab.tabsetId)!, 40))
|
|
152
|
+
*/
|
|
153
|
+
export declare function getTabContentRect(tabsetRect: Rect, tabBarHeight: number): Rect;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @returns `true` when `input` looks like a layout saved by v1.
|
|
157
|
+
* @param input - Anything, e.g. parsed JSON from storage.
|
|
158
|
+
* @example
|
|
159
|
+
* const saved = JSON.parse(localStorage.getItem('layout') ?? 'null')
|
|
160
|
+
* const layout = isLayoutV1(saved) ? migrateLayoutFromV1(saved) : saved
|
|
161
|
+
*/
|
|
162
|
+
export declare function isLayoutV1(input: unknown): input is LayoutTreeV1;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* A layout instance. Independent of every other instance; holds no timers and
|
|
166
|
+
* never touches the DOM. Actions return `true` when they changed the layout and
|
|
167
|
+
* `false` when they were refused or did nothing; they never throw.
|
|
168
|
+
*/
|
|
169
|
+
export declare interface Layout {
|
|
170
|
+
/** The current immutable snapshot. */
|
|
171
|
+
getSnapshot(): LayoutSnapshot;
|
|
172
|
+
/** Calls `listener` after every change. @returns A function that unsubscribes. */
|
|
173
|
+
subscribe(listener: (snapshot: LayoutSnapshot) => void): () => void;
|
|
174
|
+
/** Area to fill, in the coordinates every rect uses (`x`/`y` is usually the padding). */
|
|
175
|
+
setContainerRect(rect: Rect): void;
|
|
176
|
+
/** Replaces the open tabs: unlisted tabs are removed, new ones added and activated. */
|
|
177
|
+
setTabs(tabs: readonly TabInit[]): void;
|
|
178
|
+
/** Changes sizes without rebuilding anything. */
|
|
179
|
+
setOptions(options: LayoutSizeOptions): void;
|
|
180
|
+
moveTab(tabId: string, target: DropTarget): boolean;
|
|
181
|
+
moveTabset(tabsetId: string, target: DropTarget): boolean;
|
|
182
|
+
selectTab(tabId: string): boolean;
|
|
183
|
+
addTab(tab: TabInit, target?: DropTarget): boolean;
|
|
184
|
+
removeTab(tabId: string): boolean;
|
|
185
|
+
/** Moves a splitter so its centre is at `point`, clamped to the neighbours' minimum sizes. */
|
|
186
|
+
resizeSplitter(splitterId: string, point: Point): boolean;
|
|
187
|
+
/** Moves a splitter by `delta` px along its row (keyboard resizing). */
|
|
188
|
+
moveSplitterBy(splitterId: string, delta: number): boolean;
|
|
189
|
+
maximize(tabsetId: string): boolean;
|
|
190
|
+
restore(): boolean;
|
|
191
|
+
toggleMaximize(tabsetId: string): boolean;
|
|
192
|
+
fold(tabsetId: string): boolean;
|
|
193
|
+
unfold(tabsetId: string): boolean;
|
|
194
|
+
toggleFold(tabsetId: string): boolean;
|
|
195
|
+
/** Starts a pointer or keyboard drag. Tab and tabset drags leave maximized mode first. */
|
|
196
|
+
startDrag(source: DragSource): boolean;
|
|
197
|
+
/** Updates the drop target (tabs) or splitter position (splitters); never calls `onLayoutChange`. */
|
|
198
|
+
updateDrag(point: Point, measurements?: DropMeasurements): void;
|
|
199
|
+
/** Sets the drop target directly (keyboard move mode). */
|
|
200
|
+
setDragTarget(target: DropTarget | null, measurements?: DropMeasurements): void;
|
|
201
|
+
/** Commits the drag with one `onLayoutChange`. @returns Whether the layout changed. */
|
|
202
|
+
endDrag(): boolean;
|
|
203
|
+
/** Ends the drag and undoes any splitter movement. */
|
|
204
|
+
cancelDrag(): void;
|
|
205
|
+
getDropTarget(point: Point, source: DragSource, measurements?: DropMeasurements): DropTarget | null;
|
|
206
|
+
getDropIndicatorRect(target: DropTarget, measurements?: DropMeasurements): Rect | null;
|
|
207
|
+
/** Every valid target for `source`, in reading order. */
|
|
208
|
+
listDropTargets(source: DragSource): readonly DropTarget[];
|
|
209
|
+
/** For `aria-valuenow`, `aria-valuemin` and `aria-valuemax`. */
|
|
210
|
+
getSplitterBounds(splitterId: string): SplitterBounds | null;
|
|
211
|
+
/** Replaces the layout (v1 or v2) without calling `onLayoutChange`. */
|
|
212
|
+
load(layout: LayoutJSON | LayoutTreeV1): void;
|
|
213
|
+
/** Back to `initialLayout`, or the default layout of the current tabs. */
|
|
214
|
+
reset(): void;
|
|
215
|
+
/** The current layout. The same object is returned until the layout changes. */
|
|
216
|
+
toJSON(): LayoutJSON;
|
|
217
|
+
/** Removes every listener; later actions are ignored with a warning. */
|
|
218
|
+
destroy(): void;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Version written by {@link toLayoutJSON}. */
|
|
222
|
+
export declare const LAYOUT_VERSION = 2;
|
|
223
|
+
|
|
224
|
+
/** Why `onLayoutChange` was called. */
|
|
225
|
+
export declare type LayoutChangeReason = 'move' | 'resize' | 'select' | 'fold' | 'maximize' | 'tabs' | 'reset';
|
|
226
|
+
|
|
227
|
+
/** A saved layout. Splitters and pixel sizes are not stored. */
|
|
228
|
+
export declare interface LayoutJSON {
|
|
229
|
+
version: 2;
|
|
230
|
+
root: RowJSON;
|
|
231
|
+
/** Id of the maximized tabset, if any. */
|
|
232
|
+
maximizedTabsetId?: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Any node of the layout tree. */
|
|
236
|
+
export declare type LayoutNode = RowNode | TabsetNode | TabNode;
|
|
237
|
+
|
|
238
|
+
/** Options for `createLayout`. */
|
|
239
|
+
export declare interface LayoutOptions extends LayoutSizeOptions {
|
|
240
|
+
/** Open tabs. Their order only matters for the default layout. */
|
|
241
|
+
tabs: readonly TabInit[];
|
|
242
|
+
/**
|
|
243
|
+
* A saved layout (v2, or a v1 tree that is migrated automatically).
|
|
244
|
+
* @default the default layout built from `tabs`
|
|
245
|
+
*/
|
|
246
|
+
initialLayout?: LayoutJSON | LayoutTreeV1 | null;
|
|
247
|
+
/**
|
|
248
|
+
* Id factory for rows and tabsets.
|
|
249
|
+
* @default deterministic per instance (`ts-<first tab>`, `row-<n>`)
|
|
250
|
+
*/
|
|
251
|
+
createId?: CreateId;
|
|
252
|
+
/** Called after every committed change; never for drag frames or `load`. */
|
|
253
|
+
onLayoutChange?: (layout: LayoutJSON, reason: LayoutChangeReason) => void;
|
|
254
|
+
/** @default `console.warn` in development, silent in production */
|
|
255
|
+
onWarning?: WarningHandler;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Every rect of a layout, in layout-root coordinates. */
|
|
259
|
+
export declare interface LayoutRects {
|
|
260
|
+
/** Area the layout fills; larger than the container when it can't fit. */
|
|
261
|
+
readonly container: Rect;
|
|
262
|
+
readonly rows: ReadonlyMap<string, Rect>;
|
|
263
|
+
/** As displayed: a maximized tabset gets the whole container. */
|
|
264
|
+
readonly tabsets: ReadonlyMap<string, Rect>;
|
|
265
|
+
readonly splitters: ReadonlyMap<string, Rect>;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Sizes that can change after creation. */
|
|
269
|
+
export declare interface LayoutSizeOptions {
|
|
270
|
+
/** Smallest size of a tabset. @default { width: 40, height: 40 } */
|
|
271
|
+
minPanelSize?: {
|
|
272
|
+
width: number;
|
|
273
|
+
height: number;
|
|
274
|
+
};
|
|
275
|
+
/** Thickness of splitters. @default 10 */
|
|
276
|
+
splitterSize?: number;
|
|
277
|
+
/** Size of a folded tabset along its row. @default minPanelSize.height */
|
|
278
|
+
foldedSize?: number;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* An immutable view of the layout. Every field keeps its previous reference
|
|
283
|
+
* unless it changed, and so does every entry of every map, so consumers can
|
|
284
|
+
* compare by reference at any depth.
|
|
285
|
+
*/
|
|
286
|
+
export declare interface LayoutSnapshot {
|
|
287
|
+
readonly root: RowNode;
|
|
288
|
+
readonly tabsets: ReadonlyMap<string, TabsetState>;
|
|
289
|
+
readonly splitters: ReadonlyMap<string, SplitterState>;
|
|
290
|
+
readonly tabs: ReadonlyMap<string, TabState>;
|
|
291
|
+
readonly rects: LayoutRects;
|
|
292
|
+
readonly maximizedTabsetId: string | null;
|
|
293
|
+
readonly drag: DragState | null;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* A layout saved by v1 (`DynamixLayoutCore._root.toJSON()`). Accepted
|
|
298
|
+
* everywhere a {@link LayoutJSON} is, and migrated automatically.
|
|
299
|
+
*/
|
|
300
|
+
export declare interface LayoutTreeV1 {
|
|
301
|
+
typNode: 'row' | 'tabset' | 'tab' | 'bond';
|
|
302
|
+
nodName: string;
|
|
303
|
+
uidNode: string;
|
|
304
|
+
nodPart: number;
|
|
305
|
+
nodOpen?: string | boolean;
|
|
306
|
+
nodKids?: readonly LayoutTreeV1[];
|
|
307
|
+
nodFold?: boolean;
|
|
308
|
+
nodMaxd?: string;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** A non-fatal problem, such as a repaired saved layout. */
|
|
312
|
+
export declare interface LayoutWarning {
|
|
313
|
+
readonly code: LayoutWarningCode;
|
|
314
|
+
readonly message: string;
|
|
315
|
+
readonly path?: string;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Codes of non-fatal problems reported through `onWarning`. */
|
|
319
|
+
export declare type LayoutWarningCode = 'MIGRATED_FROM_V1' | 'DUPLICATE_TAB_ID' | 'INVALID_ACTIVE_TAB' | 'INVALID_WEIGHT' | 'UNKNOWN_ID' | 'DESTROYED';
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Converts a layout saved by v1 to the v2 format, losslessly:
|
|
323
|
+
* - a tab's identity was its label (`nodName`), which becomes its `id`; v1
|
|
324
|
+
* tab `uidNode`s were per-session and are dropped;
|
|
325
|
+
* - `nodPart` becomes `weight` (same meaning), so the layout renders
|
|
326
|
+
* pixel-identically;
|
|
327
|
+
* - directions, implicit in v1 (the root is horizontal and every level flips),
|
|
328
|
+
* become explicit;
|
|
329
|
+
* - `nodOpen`, `nodFold` and `nodMaxd` become `activeTabId`, `isFolded` and
|
|
330
|
+
* `maximizedTabsetId`.
|
|
331
|
+
*
|
|
332
|
+
* Damaged input is repaired where possible (see the migration guide):
|
|
333
|
+
* duplicate tabs keep their first occurrence, unknown active tabs fall back to
|
|
334
|
+
* the first tab, empty tabsets and rows are removed, stray tabs are wrapped in
|
|
335
|
+
* a tabset, and the result is normalized.
|
|
336
|
+
*
|
|
337
|
+
* @param tree - The v1 layout (`DynamixLayoutCore._root.toJSON()`).
|
|
338
|
+
* @returns The equivalent v2 layout.
|
|
339
|
+
* @throws {DynamixLayoutError} `INVALID_LAYOUT` when `tree` is not a v1 layout.
|
|
340
|
+
* @example
|
|
341
|
+
* const saved = JSON.parse(localStorage.getItem('layout')!)
|
|
342
|
+
* const layout = isLayoutV1(saved) ? migrateLayoutFromV1(saved) : saved
|
|
343
|
+
*/
|
|
344
|
+
export declare function migrateLayoutFromV1(tree: LayoutTreeV1, options?: {
|
|
345
|
+
onWarning?: WarningHandler;
|
|
346
|
+
}): LayoutJSON;
|
|
347
|
+
|
|
348
|
+
/** A point in layout-root coordinates (the root's top-left corner is 0,0). */
|
|
349
|
+
export declare interface Point {
|
|
350
|
+
readonly x: number;
|
|
351
|
+
readonly y: number;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** A rectangle in layout-root coordinates. */
|
|
355
|
+
export declare interface Rect {
|
|
356
|
+
readonly x: number;
|
|
357
|
+
readonly y: number;
|
|
358
|
+
readonly width: number;
|
|
359
|
+
readonly height: number;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Size of the root-edge drop zones (v1 `RootSplitterHoverEl`). */
|
|
363
|
+
export declare interface RootDropZoneOptions {
|
|
364
|
+
/** Share of the edge the zone covers. @default 0.25 */
|
|
365
|
+
readonly length?: number;
|
|
366
|
+
/** Thickness in px. @default 8 */
|
|
367
|
+
readonly thickness?: number;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** A saved row. */
|
|
371
|
+
export declare interface RowJSON {
|
|
372
|
+
type: 'row';
|
|
373
|
+
id: string;
|
|
374
|
+
/** Share of the parent's space above the minimum sizes (like CSS flex-grow). */
|
|
375
|
+
weight: number;
|
|
376
|
+
direction: Direction;
|
|
377
|
+
children: (RowJSON | TabsetJSON)[];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** A row of tabsets and rows separated by splitters. */
|
|
381
|
+
export declare interface RowNode {
|
|
382
|
+
readonly type: 'row';
|
|
383
|
+
readonly id: string;
|
|
384
|
+
/** See {@link TabsetNode.weight}. Ignored on the root. */
|
|
385
|
+
readonly weight: number;
|
|
386
|
+
readonly direction: Direction;
|
|
387
|
+
readonly children: readonly (RowNode | TabsetNode)[];
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/** A side of a tabset or of the whole layout. */
|
|
391
|
+
export declare type Side = 'top' | 'bottom' | 'left' | 'right';
|
|
392
|
+
|
|
393
|
+
/** Splitter position and limits in px along its row. */
|
|
394
|
+
export declare interface SplitterBounds {
|
|
395
|
+
/** Size of the panel before the splitter. */
|
|
396
|
+
readonly value: number;
|
|
397
|
+
readonly min: number;
|
|
398
|
+
readonly max: number;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** Derived state of one splitter. */
|
|
402
|
+
export declare interface SplitterState {
|
|
403
|
+
readonly id: string;
|
|
404
|
+
readonly rowId: string;
|
|
405
|
+
/** The row's direction: a `'horizontal'` row has a vertical splitter bar. */
|
|
406
|
+
readonly direction: Direction;
|
|
407
|
+
readonly beforeId: string;
|
|
408
|
+
readonly afterId: string;
|
|
409
|
+
/** Next to a folded tabset, so it can't be dragged. */
|
|
410
|
+
readonly isLocked: boolean;
|
|
411
|
+
readonly isHidden: boolean;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/** A tab bar and its tabs as rendered, in layout-root coordinates. */
|
|
415
|
+
export declare interface TabBarMeasurement {
|
|
416
|
+
readonly rect: Rect;
|
|
417
|
+
/** Drawn as a rotated strip (a folded tabset in a side-by-side row). */
|
|
418
|
+
readonly isRotated?: boolean;
|
|
419
|
+
readonly tabs: readonly {
|
|
420
|
+
readonly id: string;
|
|
421
|
+
readonly rect: Rect;
|
|
422
|
+
}[];
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Where a tabset's tab bar goes. */
|
|
426
|
+
export declare interface TabBarPlacement {
|
|
427
|
+
/** Box to give the tab bar element before `isRotated` is applied. */
|
|
428
|
+
readonly rect: Rect;
|
|
429
|
+
/**
|
|
430
|
+
* A folded tabset in a side-by-side row shows its tab bar as a vertical
|
|
431
|
+
* strip: an element `height` wide and `width` tall, rotated 90° around its
|
|
432
|
+
* top-left corner and placed at the strip's right edge.
|
|
433
|
+
*/
|
|
434
|
+
readonly isRotated: boolean;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** A tab the layout should contain. */
|
|
438
|
+
export declare interface TabInit {
|
|
439
|
+
/** Unique, stable id. It's also what saved layouts store. */
|
|
440
|
+
readonly id: string;
|
|
441
|
+
/** Where the tab goes the first time it appears. @default the last active tabset */
|
|
442
|
+
readonly target?: DropTarget;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** A saved tab: only the id the application gave it. */
|
|
446
|
+
export declare interface TabJSON {
|
|
447
|
+
type: 'tab';
|
|
448
|
+
id: string;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/** A tab. Its `id` is the id the application gave the tab. */
|
|
452
|
+
export declare interface TabNode {
|
|
453
|
+
readonly type: 'tab';
|
|
454
|
+
readonly id: string;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** A saved tabset. */
|
|
458
|
+
export declare interface TabsetJSON {
|
|
459
|
+
type: 'tabset';
|
|
460
|
+
id: string;
|
|
461
|
+
weight: number;
|
|
462
|
+
activeTabId?: string;
|
|
463
|
+
/** Written only when true. */
|
|
464
|
+
isFolded?: boolean;
|
|
465
|
+
children: TabJSON[];
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** A group of tabs that shows one of them at a time. */
|
|
469
|
+
export declare interface TabsetNode {
|
|
470
|
+
readonly type: 'tabset';
|
|
471
|
+
readonly id: string;
|
|
472
|
+
/**
|
|
473
|
+
* Share of the parent row's space above the minimum sizes, like CSS
|
|
474
|
+
* `flex-grow` with `flex-basis` set to the minimum size.
|
|
475
|
+
*/
|
|
476
|
+
readonly weight: number;
|
|
477
|
+
/** Always the id of one of `children`. */
|
|
478
|
+
readonly activeTabId: string;
|
|
479
|
+
/** Folded to a strip along its row. */
|
|
480
|
+
readonly isFolded: boolean;
|
|
481
|
+
/** Never empty. */
|
|
482
|
+
readonly children: readonly TabNode[];
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** Derived state of one tabset. */
|
|
486
|
+
export declare interface TabsetState {
|
|
487
|
+
readonly id: string;
|
|
488
|
+
readonly tabIds: readonly string[];
|
|
489
|
+
readonly activeTabId: string;
|
|
490
|
+
/** Direction of the row this tabset sits in. */
|
|
491
|
+
readonly parentDirection: Direction;
|
|
492
|
+
readonly isFolded: boolean;
|
|
493
|
+
readonly isMaximized: boolean;
|
|
494
|
+
/** Hidden because another tabset is maximized (its content stays mounted). */
|
|
495
|
+
readonly isHidden: boolean;
|
|
496
|
+
readonly canFold: boolean;
|
|
497
|
+
readonly canMaximize: boolean;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/** Derived state of one tab. */
|
|
501
|
+
export declare interface TabState {
|
|
502
|
+
readonly id: string;
|
|
503
|
+
readonly tabsetId: string;
|
|
504
|
+
readonly isActive: boolean;
|
|
505
|
+
/** Active and its tabset neither folded nor hidden. */
|
|
506
|
+
readonly isVisible: boolean;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* The version of this package, for debugging (replaces v1's console banner).
|
|
511
|
+
* @example
|
|
512
|
+
* console.info('dynamix-layout', version)
|
|
513
|
+
*/
|
|
514
|
+
export declare const version: string;
|
|
515
|
+
|
|
516
|
+
/** Receives warnings. */
|
|
517
|
+
export declare type WarningHandler = (warning: LayoutWarning) => void;
|
|
518
|
+
|
|
519
|
+
export { }
|