@n-uf/hypr-tiling 26.7.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 +145 -0
- package/README.md +242 -0
- package/dist/chunk-ZCGZOWOY.mjs +9871 -0
- package/dist/devtools.cjs +12001 -0
- package/dist/devtools.d.mts +111 -0
- package/dist/devtools.d.ts +111 -0
- package/dist/devtools.mjs +2286 -0
- package/dist/drag-easing-5WbK3T82.d.ts +605 -0
- package/dist/drag-easing-KxPPNNZT.d.mts +605 -0
- package/dist/engine.cjs +9899 -0
- package/dist/engine.d.mts +314 -0
- package/dist/engine.d.ts +314 -0
- package/dist/engine.mjs +116 -0
- package/dist/index.cjs +9833 -0
- package/dist/index.d.mts +74 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.mjs +125 -0
- package/dist/tiling-renderer-kTlSm4H4.d.mts +2185 -0
- package/dist/tiling-renderer-kTlSm4H4.d.ts +2185 -0
- package/package.json +96 -0
|
@@ -0,0 +1,2185 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Per-accent HUE tokens — the raw color atoms a theme composes. Decoupled from
|
|
5
|
+
* the previous bundled accent theme so a calm theme can borrow an accent's hue
|
|
6
|
+
* (border/text/ring) WITHOUT inheriting its heavy neon glow, and a refined
|
|
7
|
+
* theme can pick the softened glow. Every field is a literal Tailwind class so
|
|
8
|
+
* the JIT emits it.
|
|
9
|
+
*/
|
|
10
|
+
interface TilingAccentHue {
|
|
11
|
+
/** Human-facing palette label (also the picker swatch label). */
|
|
12
|
+
readonly label: string;
|
|
13
|
+
/** Solid background for a palette swatch dot. */
|
|
14
|
+
readonly swatch: string;
|
|
15
|
+
/** Resting pane border tint (low alpha). */
|
|
16
|
+
readonly surfaceBorder: string;
|
|
17
|
+
/** Resting pane colored drop-shadow tint. */
|
|
18
|
+
readonly surfaceShadow: string;
|
|
19
|
+
/** Accent title / metadata text. */
|
|
20
|
+
readonly text: string;
|
|
21
|
+
/** Strong accent text used on active chips. */
|
|
22
|
+
readonly textStrong: string;
|
|
23
|
+
/** Focused-pane border color. */
|
|
24
|
+
readonly focusBorder: string;
|
|
25
|
+
/** Focused-pane focus-ring color. */
|
|
26
|
+
readonly focusRing: string;
|
|
27
|
+
/** Full-intensity neon focus glow (box-shadow). */
|
|
28
|
+
readonly focusGlow: string;
|
|
29
|
+
/** Dialed-back focus glow for refined / calm themes (box-shadow). */
|
|
30
|
+
readonly focusGlowSoft: string;
|
|
31
|
+
/** Active tab/switcher chip border. */
|
|
32
|
+
readonly tabBorder: string;
|
|
33
|
+
/** Active tab/switcher chip translucent fill. */
|
|
34
|
+
readonly tabBg: string;
|
|
35
|
+
/** Subtle active-tab fill for low-contrast themes. */
|
|
36
|
+
readonly tabBgSoft: string;
|
|
37
|
+
}
|
|
38
|
+
/** Renderer-root + viewport surfaces. */
|
|
39
|
+
interface TilingThemeRootTokens {
|
|
40
|
+
/** Outer renderer container: bg/gradient, radius, padding, outline. */
|
|
41
|
+
readonly container: string;
|
|
42
|
+
/** Inner viewport (where the pane tree lays out): bg + radius. */
|
|
43
|
+
readonly viewport: string;
|
|
44
|
+
}
|
|
45
|
+
/** Pane host shell surfaces + interaction-state rings. */
|
|
46
|
+
interface TilingThemePaneShellTokens {
|
|
47
|
+
/** Pane article shell: bg/gradient, radius, shadow/rim, backdrop-filter. */
|
|
48
|
+
readonly surface: string;
|
|
49
|
+
/** Pane body scroll region text color/leading. */
|
|
50
|
+
readonly bodyText: string;
|
|
51
|
+
/** Pane subtitle text color. */
|
|
52
|
+
readonly subtitleText: string;
|
|
53
|
+
/** Ring on an invalid drop target. */
|
|
54
|
+
readonly invalidDropRing: string;
|
|
55
|
+
/** Opacity applied to the drag-source pane while it is picked up. */
|
|
56
|
+
readonly dragSourceOpacity: string;
|
|
57
|
+
}
|
|
58
|
+
/** Pane header chrome — resting + focused + the per-pane control buttons. */
|
|
59
|
+
interface TilingThemePaneHeaderTokens {
|
|
60
|
+
/** Resting header bar: border-b, bg, inset sheen. */
|
|
61
|
+
readonly base: string;
|
|
62
|
+
/** Additive classes when the pane is focused. */
|
|
63
|
+
readonly focused: string;
|
|
64
|
+
/** Pane title base typography (accent color applied separately). */
|
|
65
|
+
readonly titleText: string;
|
|
66
|
+
/** Resting header control button (maximize etc.). */
|
|
67
|
+
readonly controlIdle: string;
|
|
68
|
+
/** Active/pressed header control button. */
|
|
69
|
+
readonly controlActive: string;
|
|
70
|
+
/**
|
|
71
|
+
* Additive header classes when the pane is part of the Alt/Opt+click
|
|
72
|
+
* multi-selection set. Deliberately NEUTRAL (no accent) so it never collides
|
|
73
|
+
* with the accent focus frame — multi-selection and focus are orthogonal
|
|
74
|
+
* states a pane can hold simultaneously.
|
|
75
|
+
*/
|
|
76
|
+
readonly selected: string;
|
|
77
|
+
/**
|
|
78
|
+
* The small neutral "selected" check affordance rendered in the header of a
|
|
79
|
+
* multi-selected pane. Neutral tone, distinct from any accent control.
|
|
80
|
+
*/
|
|
81
|
+
readonly selectedBadge: string;
|
|
82
|
+
}
|
|
83
|
+
/** Drag-ghost shell — the lifted, portaled copy of the dragged pane. */
|
|
84
|
+
interface TilingThemeGhostTokens {
|
|
85
|
+
/** Ghost article shell (a touch more opaque + deeper shadow than a pane). */
|
|
86
|
+
readonly surface: string;
|
|
87
|
+
/** Ghost header bar. */
|
|
88
|
+
readonly header: string;
|
|
89
|
+
/** Ghost body text color. */
|
|
90
|
+
readonly bodyText: string;
|
|
91
|
+
/** Ghost subtitle text color. */
|
|
92
|
+
readonly subtitleText: string;
|
|
93
|
+
}
|
|
94
|
+
/** Split-divider / gap handle chrome across visible + hidden states. */
|
|
95
|
+
interface TilingThemeDividerTokens {
|
|
96
|
+
/** Structural base incl. focus-visible ring color. */
|
|
97
|
+
readonly base: string;
|
|
98
|
+
/** Visible + resizable handle (resting + hover). */
|
|
99
|
+
readonly visibleInteractive: string;
|
|
100
|
+
/** Visible but resize-disabled handle. */
|
|
101
|
+
readonly visibleStatic: string;
|
|
102
|
+
/** Hidden handle (no chrome, hit-area only). */
|
|
103
|
+
readonly hidden: string;
|
|
104
|
+
}
|
|
105
|
+
/** Top-bar / tab-strip chrome. */
|
|
106
|
+
interface TilingThemeTopBarTokens {
|
|
107
|
+
/** Tab-strip container: border, bg, shadow, backdrop. */
|
|
108
|
+
readonly container: string;
|
|
109
|
+
/** Strip title text. */
|
|
110
|
+
readonly titleText: string;
|
|
111
|
+
/** Accent-picker group wrapper. */
|
|
112
|
+
readonly pickerGroup: string;
|
|
113
|
+
/** Switcher-control group wrapper (theme picker etc.). */
|
|
114
|
+
readonly controlGroup: string;
|
|
115
|
+
/** Tab chip base typography/layout. */
|
|
116
|
+
readonly tabBase: string;
|
|
117
|
+
/** Inactive tab chip. */
|
|
118
|
+
readonly tabInactive: string;
|
|
119
|
+
/** Centered pane-switcher overlay card. */
|
|
120
|
+
readonly switcherCard: string;
|
|
121
|
+
/** Switcher card when the pane is NOT selected. */
|
|
122
|
+
readonly switcherCardInactive: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A complete theme: the static surface token groups plus the accent-composition
|
|
126
|
+
* resolvers. The resolvers are the contract for "how per-pane accents compose
|
|
127
|
+
* with the theme" — each theme decides how much of an accent's hue/glow it
|
|
128
|
+
* spends on the resting surface, title text, focus frame, and active tab.
|
|
129
|
+
*/
|
|
130
|
+
interface TilingTheme {
|
|
131
|
+
/**
|
|
132
|
+
* The theme's id. A built-in theme uses a `TilingThemeId` member; a
|
|
133
|
+
* consumer-authored theme mints its own id string (the `string & {}`
|
|
134
|
+
* widening keeps built-in ids autocompletable while admitting any id).
|
|
135
|
+
* `TILING_THEME_REGISTRY` stays keyed by the closed `TilingThemeId` union,
|
|
136
|
+
* so the compile-time built-in coverage guarantee is unaffected.
|
|
137
|
+
*/
|
|
138
|
+
readonly id: TilingThemeId | (string & {});
|
|
139
|
+
/** Human-readable theme label (e.g. for a theme picker). */
|
|
140
|
+
readonly label: string;
|
|
141
|
+
/** Renderer-root + viewport surface tokens. */
|
|
142
|
+
readonly root: TilingThemeRootTokens;
|
|
143
|
+
/** Pane host shell surface + interaction-state tokens. */
|
|
144
|
+
readonly paneShell: TilingThemePaneShellTokens;
|
|
145
|
+
/** Pane header chrome tokens. */
|
|
146
|
+
readonly paneHeader: TilingThemePaneHeaderTokens;
|
|
147
|
+
/** Drag-ghost shell tokens. */
|
|
148
|
+
readonly ghost: TilingThemeGhostTokens;
|
|
149
|
+
/** Split-divider / gap handle tokens. */
|
|
150
|
+
readonly divider: TilingThemeDividerTokens;
|
|
151
|
+
/** Top-bar / tab-strip chrome tokens. */
|
|
152
|
+
readonly topBar: TilingThemeTopBarTokens;
|
|
153
|
+
/** Resting pane accent composition (border tint + colored shadow). */
|
|
154
|
+
readonly resolvePaneAccentSurface: (accent: TilingTileAccent | undefined) => string;
|
|
155
|
+
/** Accent title-text color. */
|
|
156
|
+
readonly resolveAccentText: (accent: TilingTileAccent | undefined) => string;
|
|
157
|
+
/** Full focused-pane frame (structural border/ring + accent glow). */
|
|
158
|
+
readonly resolveFocusFrame: (accent: TilingTileAccent | undefined) => string;
|
|
159
|
+
/** Active tab / switcher / group-member chip. */
|
|
160
|
+
readonly resolveTabActive: (accent: TilingTileAccent | undefined) => string;
|
|
161
|
+
}
|
|
162
|
+
/** First palette member — the fallback when a tile omits `accent`. */
|
|
163
|
+
declare const DEFAULT_TILE_ACCENT: TilingTileAccent;
|
|
164
|
+
/**
|
|
165
|
+
* Ordered, enumerable accent palette — the generic capability a consumer
|
|
166
|
+
* iterates to build an accent picker.
|
|
167
|
+
*/
|
|
168
|
+
declare const TILING_TILE_ACCENTS: readonly TilingTileAccent[];
|
|
169
|
+
/**
|
|
170
|
+
* The hue atoms for every accent. Keyed by the closed `TilingTileAccent`
|
|
171
|
+
* union so the compiler enforces full coverage. Theme-independent: themes
|
|
172
|
+
* choose which atoms to apply.
|
|
173
|
+
*/
|
|
174
|
+
declare const TILING_ACCENT_HUES: Record<TilingTileAccent, TilingAccentHue>;
|
|
175
|
+
/** Picker-ready metadata (accent + label + swatch class) for every accent. */
|
|
176
|
+
declare const TILING_TILE_ACCENT_SWATCHES: readonly TilingTileAccentSwatch[];
|
|
177
|
+
/** Resolve an accent (or the default fallback) to its hue atoms. */
|
|
178
|
+
declare function accentHue(accent: TilingTileAccent | undefined): TilingAccentHue;
|
|
179
|
+
/**
|
|
180
|
+
* Built-in theme registry, keyed by the closed `TilingThemeId` union. Adding a
|
|
181
|
+
* member to `TilingThemeId` forces a new entry here (the `Record` fails to
|
|
182
|
+
* compile until filled in).
|
|
183
|
+
*/
|
|
184
|
+
declare const TILING_THEME_REGISTRY: Record<TilingThemeId, TilingTheme>;
|
|
185
|
+
/** Default library theme id (preserves the prior look at the round-1 checkpoint). */
|
|
186
|
+
declare const DEFAULT_TILING_THEME_ID: TilingThemeId;
|
|
187
|
+
/** Ordered, enumerable theme list — the generic capability a theme switcher iterates. */
|
|
188
|
+
declare const TILING_THEMES: readonly TilingTheme[];
|
|
189
|
+
/** Resolve a theme id (or the default) to its `TilingTheme`. */
|
|
190
|
+
declare function resolveTilingTheme(themeId: TilingThemeId | undefined): TilingTheme;
|
|
191
|
+
/** Provides the active theme to every renderer subcomponent. */
|
|
192
|
+
declare function TilingThemeProvider({ theme, children, }: {
|
|
193
|
+
theme: TilingTheme;
|
|
194
|
+
children: React.ReactNode;
|
|
195
|
+
}): React.ReactElement;
|
|
196
|
+
/** Reads the active theme from context (defaults to the library default). */
|
|
197
|
+
declare function useTilingTheme(): TilingTheme;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Orientation of a binary split. `"horizontal"` places its two children
|
|
201
|
+
* side-by-side (a `flex-row`, resized by a width divider); `"vertical"` stacks
|
|
202
|
+
* them (a `flex-col`, resized by a height divider).
|
|
203
|
+
*/
|
|
204
|
+
type TilingSplitAxis = "horizontal" | "vertical";
|
|
205
|
+
/**
|
|
206
|
+
* Arrangement of a split subtree's slots:
|
|
207
|
+
*
|
|
208
|
+
* - `"dwindle"` — the default recursive binary-split layout: each split
|
|
209
|
+
* distributes its two children along its `axis` by `ratio` (the original and
|
|
210
|
+
* only Phase-1/2 algorithm).
|
|
211
|
+
* - `"master"` — a master-area + stack layout (the Hyprland `master` analog).
|
|
212
|
+
* The split's descendant slots (leaves / groups, flattened in reading order)
|
|
213
|
+
* are laid out as `masterCount` master tiles in a master area plus the
|
|
214
|
+
* remaining tiles in a stack; the split's `ratio` is reused as the master-area
|
|
215
|
+
* fraction and `masterOrientation` places the master area. The binary
|
|
216
|
+
* structure beneath a master split is flattened (ignored for geometry); it
|
|
217
|
+
* still defines slot membership + order + identity, and the reducers still
|
|
218
|
+
* operate on it.
|
|
219
|
+
*/
|
|
220
|
+
type TilingLayoutMode = "dwindle" | "master";
|
|
221
|
+
/**
|
|
222
|
+
* Where the master area sits in `layoutMode: "master"`. `left`/`right` divide
|
|
223
|
+
* the container along WIDTH (master area a column, members stacked vertically);
|
|
224
|
+
* `top`/`bottom` divide along HEIGHT (master area a row, members stacked
|
|
225
|
+
* horizontally). The complement holds the stack.
|
|
226
|
+
*/
|
|
227
|
+
type TilingMasterOrientation = "left" | "right" | "top" | "bottom";
|
|
228
|
+
/** The two layout dimensions a pane can be sized along, independent of split axis. */
|
|
229
|
+
type TilingDimension = "width" | "height";
|
|
230
|
+
/**
|
|
231
|
+
* Per-dimension sizing mode for a node placed inside a split.
|
|
232
|
+
*
|
|
233
|
+
* - `"flexible"` — the node shares space by ratio along the split axis and
|
|
234
|
+
* stretches/reflows along the cross axis (the default for every dimension).
|
|
235
|
+
* - `"static"` — the node is sized to its INTRINSIC/CONTENT extent along that
|
|
236
|
+
* dimension; it is excluded from ratio distribution and resize dividers when
|
|
237
|
+
* the static dimension runs ALONG the parent split axis, and simply
|
|
238
|
+
* content-sizes (no stretch) when the static dimension is the CROSS axis.
|
|
239
|
+
*/
|
|
240
|
+
type TilingPaneSizingMode = "static" | "flexible";
|
|
241
|
+
/**
|
|
242
|
+
* Per-dimension sizing declaration for a node. Each dimension is independent:
|
|
243
|
+
* a pane can be static in `height`, in `width`, or in both. An undefined
|
|
244
|
+
* dimension defaults to `"flexible"`.
|
|
245
|
+
*
|
|
246
|
+
* The object shape is chosen over an axis list (e.g. `staticAxes: ("width" |
|
|
247
|
+
* "height")[]`) because it is explicit per-dimension, self-documenting at the
|
|
248
|
+
* call site (`sizing: { height: "static" }`), and lets a dimension be stated
|
|
249
|
+
* `"flexible"` explicitly rather than only inferred from absence.
|
|
250
|
+
*/
|
|
251
|
+
interface TilingPaneSizing {
|
|
252
|
+
/** Sizing mode for the WIDTH dimension. Undefined → `"flexible"`. */
|
|
253
|
+
width?: TilingPaneSizingMode;
|
|
254
|
+
/** Sizing mode for the HEIGHT dimension. Undefined → `"flexible"`. */
|
|
255
|
+
height?: TilingPaneSizingMode;
|
|
256
|
+
/**
|
|
257
|
+
* Pinned WIDTH in CSS px, captured from the pane's measured bounding box at the
|
|
258
|
+
* moment the user freezes the pane via the title-bar STATIC W / BOTH control.
|
|
259
|
+
* Only meaningful when `width === "static"`. When present, the static-width
|
|
260
|
+
* pane renders at exactly this pixel extent (a measured bbox FREEZE) instead of
|
|
261
|
+
* being content-sized. Undefined → the static dimension is content-sized (the
|
|
262
|
+
* legacy intrinsic behavior).
|
|
263
|
+
*/
|
|
264
|
+
widthPx?: number;
|
|
265
|
+
/**
|
|
266
|
+
* Pinned HEIGHT in CSS px, captured from the pane's measured bounding box at the
|
|
267
|
+
* moment the user freezes the pane via the title-bar STATIC H / BOTH control.
|
|
268
|
+
* Only meaningful when `height === "static"`. See `widthPx`.
|
|
269
|
+
*/
|
|
270
|
+
heightPx?: number;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* The four title-bar sizing actions a pane offers for ITSELF (no target-pane
|
|
274
|
+
* indirection — the pane the control lives in is the target):
|
|
275
|
+
*
|
|
276
|
+
* - `"flexible"` — clear any pinned dimension and return the pane to ratio
|
|
277
|
+
* distribution (FLEX).
|
|
278
|
+
* - `"static-height"` — freeze the pane's height to its measured bbox px.
|
|
279
|
+
* - `"static-width"` — freeze the pane's width to its measured bbox px.
|
|
280
|
+
* - `"static-both"` — freeze both dimensions to the measured bbox.
|
|
281
|
+
*/
|
|
282
|
+
type TilingTitleBarSizingMode = "flexible" | "static-height" | "static-width" | "static-both";
|
|
283
|
+
/**
|
|
284
|
+
* Resize capability across the two divider orientations.
|
|
285
|
+
*
|
|
286
|
+
* RESIZE AXIS CONVENTION (read carefully — the divider orientation and the
|
|
287
|
+
* resize axis are deliberately the opposite words):
|
|
288
|
+
*
|
|
289
|
+
* - A **vertical divider** sits between **side-by-side** panes. Dragging it
|
|
290
|
+
* changes their **widths** → this is a **horizontal** resize (x-axis). In the
|
|
291
|
+
* layout tree this is a split whose `axis` is `"horizontal"` (a `flex-row`
|
|
292
|
+
* container with a `cursor-col-resize` handle).
|
|
293
|
+
* - A **horizontal divider** sits between **stacked** panes. Dragging it changes
|
|
294
|
+
* their **heights** → this is a **vertical** resize (y-axis). In the layout
|
|
295
|
+
* tree this is a split whose `axis` is `"vertical"` (a `flex-col` container
|
|
296
|
+
* with a `cursor-row-resize` handle).
|
|
297
|
+
*
|
|
298
|
+
* The resize-capability token therefore matches the split `axis` token directly:
|
|
299
|
+
* `"horizontal"` gates width dividers, `"vertical"` gates height dividers.
|
|
300
|
+
*
|
|
301
|
+
* - `"both"` — every divider is resizable (this is the "entire" option). Default.
|
|
302
|
+
* - `"horizontal"` — only width dividers (side-by-side panes) are resizable.
|
|
303
|
+
* - `"vertical"` — only height dividers (stacked panes) are resizable.
|
|
304
|
+
* - `"none"` — no divider is resizable.
|
|
305
|
+
*/
|
|
306
|
+
type TilingResizeCapability = "both" | "horizontal" | "vertical" | "none";
|
|
307
|
+
/**
|
|
308
|
+
* Drag-to-rearrange feedback mode — how a pending move is shown WHILE dragging,
|
|
309
|
+
* before it is committed on drop.
|
|
310
|
+
*
|
|
311
|
+
* - `"preview"` — non-committing preview (default). The pending result is shown
|
|
312
|
+
* via the translucent PROJECTED landing overlays (S' / T' / successor) painted
|
|
313
|
+
* over the unchanged layout; the layout tree is NOT mutated until drop.
|
|
314
|
+
* - `"live"` — Hyprland-faithful detach drag. On pickup the dragged source leaf
|
|
315
|
+
* is detached and the remaining tree reflows ONCE to close the gap
|
|
316
|
+
* (`removeLeafTile`); that frozen provisional tree is held for the whole drag
|
|
317
|
+
* (it does NOT re-reflow as the cursor moves). The detached source follows the
|
|
318
|
+
* cursor as a ghost, and the drop is resolved + committed exactly ONCE on
|
|
319
|
+
* release against the original layout via the SAME resolver + reducers preview
|
|
320
|
+
* uses (`swapLeafTiles` / `insertLeafAdjacent`), so the live commit equals the
|
|
321
|
+
* preview commit for the same intent. The prop tree is never mutated pre-commit,
|
|
322
|
+
* so cancel / Escape / dragleave-abort / off-viewport revert is lossless.
|
|
323
|
+
*
|
|
324
|
+
* NOTE on vocabulary: "projected" names the RENDERING TECHNIQUE for the preview
|
|
325
|
+
* overlays (projected geometry, S' / T' / successor). "preview" vs "live" is the
|
|
326
|
+
* interaction MODE. The mode is never called "projected".
|
|
327
|
+
*/
|
|
328
|
+
type TilingDragMode = "preview" | "live";
|
|
329
|
+
/**
|
|
330
|
+
* Live-drag slot re-resolution / commitment policy after the single ghost hops
|
|
331
|
+
* INTO and FILLS a resolved slot (see
|
|
332
|
+
* `_agent/single-instance-hop-in-drag-design.md` §8):
|
|
333
|
+
*
|
|
334
|
+
* - `"zone-exit-hold"` — anchored / sticky: the seated slot is pinned through
|
|
335
|
+
* small cursor movements and re-resolves only when the cursor crosses OUT of
|
|
336
|
+
* the seated target's hit footprint (high hysteresis).
|
|
337
|
+
* - `"delta-responsive"` — DEFAULT: the seated slot re-resolves eagerly once the
|
|
338
|
+
* cursor travels beyond `reresolveDeltaPx` from the seat anchor (or exits the
|
|
339
|
+
* footprint), so the user can re-aim without fully exiting the pane.
|
|
340
|
+
*
|
|
341
|
+
* Only meaningful in `dragMode: "live"`.
|
|
342
|
+
*/
|
|
343
|
+
type TilingSlotCommitmentMode = "zone-exit-hold" | "delta-responsive";
|
|
344
|
+
/**
|
|
345
|
+
* Live-drag slot-commitment configuration. `mode` selects the re-resolution
|
|
346
|
+
* policy; `reresolveDeltaPx` is the `delta-responsive` movement threshold (CSS
|
|
347
|
+
* px) — a coarse "should I re-aim" gate distinct from the fine 6px geometric
|
|
348
|
+
* zone hysteresis, so the two never double-count.
|
|
349
|
+
*/
|
|
350
|
+
interface TilingSlotCommitmentCapability {
|
|
351
|
+
/** Re-resolution policy after the ghost seats in a slot. Default `"delta-responsive"`. */
|
|
352
|
+
mode?: TilingSlotCommitmentMode;
|
|
353
|
+
/** `delta-responsive` re-aim threshold in CSS px. Default `24`. */
|
|
354
|
+
reresolveDeltaPx?: number;
|
|
355
|
+
}
|
|
356
|
+
/** Fully-resolved slot-commitment configuration (no optional fields). */
|
|
357
|
+
interface ResolvedTilingSlotCommitmentCapability {
|
|
358
|
+
/** Resolved re-resolution policy after the ghost seats in a slot. */
|
|
359
|
+
mode: TilingSlotCommitmentMode;
|
|
360
|
+
/** Resolved `delta-responsive` re-aim threshold in CSS px. */
|
|
361
|
+
reresolveDeltaPx: number;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Touch-drag hardening configuration. The drag FSM runs on Pointer Events, so it
|
|
365
|
+
* already covers touch uniformly with mouse/pen — this capability tunes the
|
|
366
|
+
* touch-only choreography that must differ from mouse:
|
|
367
|
+
*
|
|
368
|
+
* - `enable` — when `false`, a touch press on the drag handle never starts a
|
|
369
|
+
* drag (touch is reserved for tap/scroll); mouse/pen drag is unaffected.
|
|
370
|
+
* Default `true`.
|
|
371
|
+
* - `longPressMs` — how long a finger must be held before the press becomes a
|
|
372
|
+
* drag pickup (the tap/scroll-vs-drag disambiguator). A pre-long-press
|
|
373
|
+
* scroll-axis flick releases to the page; mouse/pen skip this delay entirely.
|
|
374
|
+
* Default `220`.
|
|
375
|
+
*/
|
|
376
|
+
interface TilingTouchDragCapability {
|
|
377
|
+
/** Allow touch pointers to start a drag. Default `true`. */
|
|
378
|
+
enable?: boolean;
|
|
379
|
+
/** Long-press delay (ms) before a held touch becomes a drag. Default `220`. */
|
|
380
|
+
longPressMs?: number;
|
|
381
|
+
}
|
|
382
|
+
/** Fully-resolved touch-drag configuration (no optional fields). */
|
|
383
|
+
interface ResolvedTilingTouchDragCapability {
|
|
384
|
+
/** Resolved touch-drag enable flag. */
|
|
385
|
+
enable: boolean;
|
|
386
|
+
/** Resolved long-press delay (ms) before a held touch becomes a drag. */
|
|
387
|
+
longPressMs: number;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Drag / transition self-healing recovery configuration. Hardens the live-drag
|
|
391
|
+
* ANIMATION + TIMING layer (not the FSM, which is already un-wedgeable) against
|
|
392
|
+
* frame starvation — background-tab `requestAnimationFrame` suspension, CPU
|
|
393
|
+
* throttling, long tasks, dropped/late pointer events, interrupted transitions.
|
|
394
|
+
* The recovery primitives live in `drag-recovery.ts`; this is their typed knob
|
|
395
|
+
* surface. All deadlines are documented multiples of the animation duration or
|
|
396
|
+
* of a frame, never symptom-tuned constants. Only meaningful in
|
|
397
|
+
* `dragMode: "live"`.
|
|
398
|
+
*
|
|
399
|
+
* - `enable` — master gate for the recovery layer (idle watchdog +
|
|
400
|
+
* rAF-with-timeout arming + idempotent style teardown). Default `true`.
|
|
401
|
+
* - `maxDraggingIdleMs` — the drag idle-watchdog deadline: `armed` / `dragging`
|
|
402
|
+
* with no `POINTER_MOVE` / `TARGET_RESOLVED` progress for longer than this
|
|
403
|
+
* (measured MONOTONICALLY, so throttle-robust) force-reconciles to `idle` via
|
|
404
|
+
* the existing `POINTER_CANCEL` edge with pointer capture released. Default
|
|
405
|
+
* `30 × BASELINE_DRAG_HOP_DURATION_MS ≈ 5100ms`.
|
|
406
|
+
* - `frameDeadlineMs` — the rAF-fallback slack: each FLIP "play-to-identity"
|
|
407
|
+
* write is armed as a `requestAnimationFrame` racing a `setTimeout` of this
|
|
408
|
+
* long, first-wins + idempotent, so a starved frame never leaves an element
|
|
409
|
+
* frozen at its inverted `First`. Default `~2 frames ≈ 32ms`.
|
|
410
|
+
* - `transitionSlackMs` — the transition-completion slack: style cleanup fires
|
|
411
|
+
* on `transitionend` OR `duration + transitionSlackMs`, whichever first.
|
|
412
|
+
* Default `60ms` (names the existing `+60` mask-close slack).
|
|
413
|
+
*/
|
|
414
|
+
interface TilingDragRecoveryCapability {
|
|
415
|
+
/** Enable the self-healing recovery layer. Default `true`. */
|
|
416
|
+
enable?: boolean;
|
|
417
|
+
/** Idle-watchdog deadline (ms). Default `30 × BASELINE_DRAG_HOP_DURATION_MS ≈ 5100`. */
|
|
418
|
+
maxDraggingIdleMs?: number;
|
|
419
|
+
/** rAF-fallback slack (ms). Default `~2 frames ≈ 32`. */
|
|
420
|
+
frameDeadlineMs?: number;
|
|
421
|
+
/** Transition-completion slack (ms). Default `60`. */
|
|
422
|
+
transitionSlackMs?: number;
|
|
423
|
+
}
|
|
424
|
+
/** Fully-resolved drag-recovery configuration (no optional fields). */
|
|
425
|
+
interface ResolvedTilingDragRecoveryCapability {
|
|
426
|
+
/** Resolved self-healing recovery enable flag. */
|
|
427
|
+
enable: boolean;
|
|
428
|
+
/** Resolved idle-watchdog deadline (ms). */
|
|
429
|
+
maxDraggingIdleMs: number;
|
|
430
|
+
/** Resolved rAF-fallback slack (ms). */
|
|
431
|
+
frameDeadlineMs: number;
|
|
432
|
+
/** Resolved transition-completion slack (ms). */
|
|
433
|
+
transitionSlackMs: number;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* A single keyboard chord: a PHYSICAL `KeyboardEvent.code` value plus the
|
|
437
|
+
* modifier state required to match it. Absent modifiers resolve to `false` (the
|
|
438
|
+
* modifier must NOT be held) — a chord fully specifies its modifier requirements.
|
|
439
|
+
*
|
|
440
|
+
* The chord matches on `event.code` (the physical key, e.g. `"Enter"`,
|
|
441
|
+
* `"Escape"`, `"BracketLeft"`, `"BracketRight"`), NOT `event.key` (the produced
|
|
442
|
+
* character). This is mandatory on macOS, where holding Option(Alt) rewrites
|
|
443
|
+
* `event.key` into dead-key glyphs (Option+`]` → `"‘"`, Option+digits → special
|
|
444
|
+
* glyphs), so a `event.key`-based comparison never matches. `event.code` is
|
|
445
|
+
* stable across keyboard layouts and modifier state.
|
|
446
|
+
*/
|
|
447
|
+
interface TilingKeyChord {
|
|
448
|
+
/** Matches `KeyboardEvent.code` (e.g. `"Enter"`, `"Escape"`, `"BracketLeft"`, `"BracketRight"`, `"Digit1"`). */
|
|
449
|
+
code: string;
|
|
450
|
+
/** Require the Alt key. Default `false`. */
|
|
451
|
+
alt?: boolean;
|
|
452
|
+
/** Require the Ctrl key. Default `false`. */
|
|
453
|
+
ctrl?: boolean;
|
|
454
|
+
/** Require the Meta (Cmd / Win) key. Default `false`. */
|
|
455
|
+
meta?: boolean;
|
|
456
|
+
/** Require the Shift key. Default `false`. */
|
|
457
|
+
shift?: boolean;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Modifier requirements for the jump-to-pane digit family (`Alt+1`..`Alt+9`).
|
|
461
|
+
* The `1`..`9` digit is implied (matched against the physical `Digit1`..`Digit9`
|
|
462
|
+
* codes); only the modifier state is configurable.
|
|
463
|
+
*/
|
|
464
|
+
interface TilingKeyChordModifiers {
|
|
465
|
+
/** Require the Alt key. Default `false`. */
|
|
466
|
+
alt?: boolean;
|
|
467
|
+
/** Require the Ctrl key. Default `false`. */
|
|
468
|
+
ctrl?: boolean;
|
|
469
|
+
/** Require the Meta (Cmd / Win) key. Default `false`. */
|
|
470
|
+
meta?: boolean;
|
|
471
|
+
/** Require the Shift key. Default `false`. */
|
|
472
|
+
shift?: boolean;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Public, reactive keymap. Every field is optional; an `undefined` field
|
|
476
|
+
* resolves to its documented default via `resolveKeymap`. Action-level merge:
|
|
477
|
+
* supplying one binding leaves the others at their defaults.
|
|
478
|
+
*/
|
|
479
|
+
interface TilingKeymap {
|
|
480
|
+
/** Toggle maximize on the focused pane. Default `Alt+Enter` (code `Enter`). */
|
|
481
|
+
toggleMaximize?: TilingKeyChord;
|
|
482
|
+
/** Restore from maximize. Default `Escape`. */
|
|
483
|
+
restore?: TilingKeyChord;
|
|
484
|
+
/** Cycle to the previous pane. Default `Alt+[`. */
|
|
485
|
+
previousPane?: TilingKeyChord;
|
|
486
|
+
/** Cycle to the next pane. Default `Alt+]`. */
|
|
487
|
+
nextPane?: TilingKeyChord;
|
|
488
|
+
/** Modifier set for the `Alt+1`..`Alt+9` jump family. Default `Alt`. */
|
|
489
|
+
jumpToPane?: TilingKeyChordModifiers;
|
|
490
|
+
/** Move focus to the geometric neighbor on the LEFT. Default bare `ArrowLeft`. */
|
|
491
|
+
focusLeft?: TilingKeyChord;
|
|
492
|
+
/** Move focus to the geometric neighbor on the RIGHT. Default bare `ArrowRight`. */
|
|
493
|
+
focusRight?: TilingKeyChord;
|
|
494
|
+
/** Move focus to the geometric neighbor ABOVE. Default bare `ArrowUp`. */
|
|
495
|
+
focusUp?: TilingKeyChord;
|
|
496
|
+
/** Move focus to the geometric neighbor BELOW. Default bare `ArrowDown`. */
|
|
497
|
+
focusDown?: TilingKeyChord;
|
|
498
|
+
/**
|
|
499
|
+
* Enter keyboard MOVE MODE on the focused pane (the keyboard analog of a drag
|
|
500
|
+
* pickup). Default `Alt+M` (code `KeyM`). While in move mode the focus arrows
|
|
501
|
+
* pick a destination, `Enter` commits the relocation (`insertLeafAdjacent`),
|
|
502
|
+
* and `Escape` cancels. Only meaningful when `rearrange` is enabled.
|
|
503
|
+
*/
|
|
504
|
+
enterMoveMode?: TilingKeyChord;
|
|
505
|
+
/**
|
|
506
|
+
* Toggle focus between the current pane and the most-recently-focused other
|
|
507
|
+
* pane (the MRU "focus current-or-last" toggle; Hyprland `focuscurrentorlast`
|
|
508
|
+
* analog). Default `Alt+\`` (code `Backquote`). Only meaningful when `focus`
|
|
509
|
+
* is enabled.
|
|
510
|
+
*/
|
|
511
|
+
focusCurrentOrLast?: TilingKeyChord;
|
|
512
|
+
/**
|
|
513
|
+
* Toggle the focused subtree's layout mode dwindle ⇄ master (the Hyprland
|
|
514
|
+
* layout-toggle analog). Default `Alt+L` (code `KeyL`). Only meaningful when
|
|
515
|
+
* `masterLayout` is enabled.
|
|
516
|
+
*/
|
|
517
|
+
cycleLayoutMode?: TilingKeyChord;
|
|
518
|
+
/**
|
|
519
|
+
* Cycle the master-area orientation left → top → right → bottom → left.
|
|
520
|
+
* Default `Alt+Shift+O` (code `KeyO` + Shift). Bare `Alt+O` is avoided
|
|
521
|
+
* because Chrome/Edge on Windows/Linux reserve it for the browser menu.
|
|
522
|
+
* Switches to master layout mode automatically when invoked from dwindle.
|
|
523
|
+
*/
|
|
524
|
+
cycleMasterOrientation?: TilingKeyChord;
|
|
525
|
+
/** Add one tile to the master area (`+1` master count). Default `Alt+=` (code `Equal`). */
|
|
526
|
+
incrementMasterCount?: TilingKeyChord;
|
|
527
|
+
/** Remove one tile from the master area (`-1` master count). Default `Alt+-` (code `Minus`). */
|
|
528
|
+
decrementMasterCount?: TilingKeyChord;
|
|
529
|
+
/** Grow the master-area fraction (`+0.05` ratio). Default `Alt+.` (code `Period`). */
|
|
530
|
+
incrementMasterRatio?: TilingKeyChord;
|
|
531
|
+
/** Shrink the master-area fraction (`-0.05` ratio). Default `Alt+,` (code `Comma`). */
|
|
532
|
+
decrementMasterRatio?: TilingKeyChord;
|
|
533
|
+
/**
|
|
534
|
+
* Toggle grouping for the focused pane: group it with its reading-order
|
|
535
|
+
* neighbor, or ungroup it if already grouped (the Hyprland `togglegroup`
|
|
536
|
+
* analog). Default `Alt+G` (code `KeyG`). Only meaningful when `grouping`
|
|
537
|
+
* is enabled.
|
|
538
|
+
*/
|
|
539
|
+
toggleGroup?: TilingKeyChord;
|
|
540
|
+
/** Activate the next member tab of the focused group. Default `Alt+K` (code `KeyK`). */
|
|
541
|
+
groupTabNext?: TilingKeyChord;
|
|
542
|
+
/** Activate the previous member tab of the focused group. Default `Alt+J` (code `KeyJ`). */
|
|
543
|
+
groupTabPrevious?: TilingKeyChord;
|
|
544
|
+
}
|
|
545
|
+
/** Fully-resolved key chord (every modifier explicit). Matches `KeyboardEvent.code`. */
|
|
546
|
+
interface ResolvedTilingKeyChord {
|
|
547
|
+
/** Physical `KeyboardEvent.code` this chord matches. */
|
|
548
|
+
code: string;
|
|
549
|
+
/** Whether the Alt key must be held. */
|
|
550
|
+
alt: boolean;
|
|
551
|
+
/** Whether the Ctrl key must be held. */
|
|
552
|
+
ctrl: boolean;
|
|
553
|
+
/** Whether the Meta (Cmd / Win) key must be held. */
|
|
554
|
+
meta: boolean;
|
|
555
|
+
/** Whether the Shift key must be held. */
|
|
556
|
+
shift: boolean;
|
|
557
|
+
}
|
|
558
|
+
/** Fully-resolved jump-to-pane modifier set. */
|
|
559
|
+
interface ResolvedTilingKeyChordModifiers {
|
|
560
|
+
/** Whether the Alt key must be held. */
|
|
561
|
+
alt: boolean;
|
|
562
|
+
/** Whether the Ctrl key must be held. */
|
|
563
|
+
ctrl: boolean;
|
|
564
|
+
/** Whether the Meta (Cmd / Win) key must be held. */
|
|
565
|
+
meta: boolean;
|
|
566
|
+
/** Whether the Shift key must be held. */
|
|
567
|
+
shift: boolean;
|
|
568
|
+
}
|
|
569
|
+
/** Fully-resolved keymap (no optional fields). */
|
|
570
|
+
interface ResolvedTilingKeymap {
|
|
571
|
+
/** Resolved chord to toggle maximize on the focused pane. */
|
|
572
|
+
toggleMaximize: ResolvedTilingKeyChord;
|
|
573
|
+
/** Resolved chord to restore from maximize. */
|
|
574
|
+
restore: ResolvedTilingKeyChord;
|
|
575
|
+
/** Resolved chord to cycle to the previous pane. */
|
|
576
|
+
previousPane: ResolvedTilingKeyChord;
|
|
577
|
+
/** Resolved chord to cycle to the next pane. */
|
|
578
|
+
nextPane: ResolvedTilingKeyChord;
|
|
579
|
+
/** Resolved modifier set for the `Alt+1`..`Alt+9` jump family. */
|
|
580
|
+
jumpToPane: ResolvedTilingKeyChordModifiers;
|
|
581
|
+
/** Resolved chord to move focus to the LEFT neighbor. */
|
|
582
|
+
focusLeft: ResolvedTilingKeyChord;
|
|
583
|
+
/** Resolved chord to move focus to the RIGHT neighbor. */
|
|
584
|
+
focusRight: ResolvedTilingKeyChord;
|
|
585
|
+
/** Resolved chord to move focus to the neighbor ABOVE. */
|
|
586
|
+
focusUp: ResolvedTilingKeyChord;
|
|
587
|
+
/** Resolved chord to move focus to the neighbor BELOW. */
|
|
588
|
+
focusDown: ResolvedTilingKeyChord;
|
|
589
|
+
/** Resolved chord to enter keyboard move mode. */
|
|
590
|
+
enterMoveMode: ResolvedTilingKeyChord;
|
|
591
|
+
/** Resolved chord for the MRU focus current-or-last toggle. */
|
|
592
|
+
focusCurrentOrLast: ResolvedTilingKeyChord;
|
|
593
|
+
/** Resolved chord to toggle the focused subtree dwindle ⇄ master. */
|
|
594
|
+
cycleLayoutMode: ResolvedTilingKeyChord;
|
|
595
|
+
/** Resolved chord to cycle the master-area orientation. */
|
|
596
|
+
cycleMasterOrientation: ResolvedTilingKeyChord;
|
|
597
|
+
/** Resolved chord to add one tile to the master area. */
|
|
598
|
+
incrementMasterCount: ResolvedTilingKeyChord;
|
|
599
|
+
/** Resolved chord to remove one tile from the master area. */
|
|
600
|
+
decrementMasterCount: ResolvedTilingKeyChord;
|
|
601
|
+
/** Resolved chord to grow the master-area fraction. */
|
|
602
|
+
incrementMasterRatio: ResolvedTilingKeyChord;
|
|
603
|
+
/** Resolved chord to shrink the master-area fraction. */
|
|
604
|
+
decrementMasterRatio: ResolvedTilingKeyChord;
|
|
605
|
+
/** Resolved chord to group/ungroup the focused pane. */
|
|
606
|
+
toggleGroup: ResolvedTilingKeyChord;
|
|
607
|
+
/** Resolved chord to activate the next member tab of the focused group. */
|
|
608
|
+
groupTabNext: ResolvedTilingKeyChord;
|
|
609
|
+
/** Resolved chord to activate the previous member tab of the focused group. */
|
|
610
|
+
groupTabPrevious: ResolvedTilingKeyChord;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* A keyboard-event shape sufficient for pure keymap matching. Matching keys off
|
|
614
|
+
* the physical `code`; `key` is retained only for form-field / diagnostic use
|
|
615
|
+
* and is NOT consulted by `matchKeyChord` / `matchJumpToPaneNumber`.
|
|
616
|
+
*/
|
|
617
|
+
interface TilingKeyboardEventLike {
|
|
618
|
+
/** Physical `KeyboardEvent.code` (the key that matching consults). */
|
|
619
|
+
code: string;
|
|
620
|
+
/** Produced `KeyboardEvent.key` glyph; diagnostic only, never matched. */
|
|
621
|
+
key: string;
|
|
622
|
+
/** Whether the Alt key was held. */
|
|
623
|
+
altKey: boolean;
|
|
624
|
+
/** Whether the Ctrl key was held. */
|
|
625
|
+
ctrlKey: boolean;
|
|
626
|
+
/** Whether the Meta (Cmd / Win) key was held. */
|
|
627
|
+
metaKey: boolean;
|
|
628
|
+
/** Whether the Shift key was held. */
|
|
629
|
+
shiftKey: boolean;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* The subset of modifier flags needed to decide whether a held-modifier switch
|
|
633
|
+
* flow (the macOS Cmd+Tab-style pane switcher) should commit on key release.
|
|
634
|
+
*/
|
|
635
|
+
interface TilingKeyboardModifierState {
|
|
636
|
+
/** Whether the Alt key is held. */
|
|
637
|
+
altKey: boolean;
|
|
638
|
+
/** Whether the Ctrl key is held. */
|
|
639
|
+
ctrlKey: boolean;
|
|
640
|
+
/** Whether the Meta (Cmd / Win) key is held. */
|
|
641
|
+
metaKey: boolean;
|
|
642
|
+
/** Whether the Shift key is held. */
|
|
643
|
+
shiftKey: boolean;
|
|
644
|
+
}
|
|
645
|
+
/** Discriminated logical keyboard actions resolved from a key event. */
|
|
646
|
+
type TilingKeyboardAction = {
|
|
647
|
+
kind: "toggle-maximize";
|
|
648
|
+
} | {
|
|
649
|
+
kind: "restore";
|
|
650
|
+
} | {
|
|
651
|
+
kind: "previous-pane";
|
|
652
|
+
} | {
|
|
653
|
+
kind: "next-pane";
|
|
654
|
+
} | {
|
|
655
|
+
kind: "jump-to-pane";
|
|
656
|
+
paneNumber: number;
|
|
657
|
+
} | {
|
|
658
|
+
kind: "focus-direction";
|
|
659
|
+
direction: TilingFocusDirection;
|
|
660
|
+
} | {
|
|
661
|
+
kind: "focus-current-or-last";
|
|
662
|
+
} | {
|
|
663
|
+
kind: "enter-move-mode";
|
|
664
|
+
} | {
|
|
665
|
+
kind: "cycle-layout-mode";
|
|
666
|
+
} | {
|
|
667
|
+
kind: "cycle-master-orientation";
|
|
668
|
+
} | {
|
|
669
|
+
kind: "adjust-master-count";
|
|
670
|
+
delta: number;
|
|
671
|
+
} | {
|
|
672
|
+
kind: "adjust-master-ratio";
|
|
673
|
+
delta: number;
|
|
674
|
+
} | {
|
|
675
|
+
kind: "toggle-group";
|
|
676
|
+
} | {
|
|
677
|
+
kind: "group-tab-cycle";
|
|
678
|
+
direction: TilingPaneCycleDirection;
|
|
679
|
+
};
|
|
680
|
+
/** Pane cycle direction for the reading-order ring (next / previous, wraparound). */
|
|
681
|
+
type TilingPaneCycleDirection = "next" | "previous";
|
|
682
|
+
/**
|
|
683
|
+
* The public, typed, dispatch-style command set — the public API's imperative
|
|
684
|
+
* entry point (the Hyprland `dispatch` analog). Every internal renderer action is
|
|
685
|
+
* enumerated here so an embedding app can invoke tiler behavior programmatically
|
|
686
|
+
* (via the `TilingCommandHandle`) and so a keyboard binding can target any of
|
|
687
|
+
* them (`TilingKeyBinding`).
|
|
688
|
+
*
|
|
689
|
+
* Context-dependent commands carry an OPTIONAL `leafId`; when omitted the
|
|
690
|
+
* renderer resolves it against the CURRENT focused leaf at dispatch time (the
|
|
691
|
+
* "act on the focused pane" ergonomic). Commands that need explicit operands
|
|
692
|
+
* (swap / insert / split ops) require them.
|
|
693
|
+
*/
|
|
694
|
+
type TilingCommand = {
|
|
695
|
+
kind: "focus-pane";
|
|
696
|
+
leafId: string;
|
|
697
|
+
} | {
|
|
698
|
+
kind: "focus-direction";
|
|
699
|
+
direction: TilingFocusDirection;
|
|
700
|
+
} | {
|
|
701
|
+
kind: "focus-cycle";
|
|
702
|
+
direction: TilingPaneCycleDirection;
|
|
703
|
+
} | {
|
|
704
|
+
kind: "focus-jump";
|
|
705
|
+
paneNumber: number;
|
|
706
|
+
} | {
|
|
707
|
+
kind: "focus-current-or-last";
|
|
708
|
+
} | {
|
|
709
|
+
kind: "toggle-maximize";
|
|
710
|
+
leafId?: string;
|
|
711
|
+
} | {
|
|
712
|
+
kind: "maximize";
|
|
713
|
+
leafId?: string;
|
|
714
|
+
} | {
|
|
715
|
+
kind: "restore";
|
|
716
|
+
} | {
|
|
717
|
+
kind: "enter-move-mode";
|
|
718
|
+
leafId?: string;
|
|
719
|
+
} | {
|
|
720
|
+
kind: "move-aim";
|
|
721
|
+
direction: TilingFocusDirection;
|
|
722
|
+
} | {
|
|
723
|
+
kind: "commit-move-mode";
|
|
724
|
+
} | {
|
|
725
|
+
kind: "cancel-move-mode";
|
|
726
|
+
} | {
|
|
727
|
+
kind: "swap-panes";
|
|
728
|
+
sourceLeafId: string;
|
|
729
|
+
targetLeafId: string;
|
|
730
|
+
} | {
|
|
731
|
+
kind: "insert-adjacent";
|
|
732
|
+
sourceLeafId: string;
|
|
733
|
+
targetLeafId: string;
|
|
734
|
+
placement: TilingMovePlacement;
|
|
735
|
+
} | {
|
|
736
|
+
kind: "acquire-space";
|
|
737
|
+
leafId?: string;
|
|
738
|
+
direction: TilingFocusDirection;
|
|
739
|
+
} | {
|
|
740
|
+
kind: "set-sizing";
|
|
741
|
+
leafId?: string;
|
|
742
|
+
mode: TilingTitleBarSizingMode;
|
|
743
|
+
} | {
|
|
744
|
+
kind: "set-split-ratio";
|
|
745
|
+
splitId: string;
|
|
746
|
+
ratio: number;
|
|
747
|
+
} | {
|
|
748
|
+
kind: "toggle-split-axis";
|
|
749
|
+
splitId: string;
|
|
750
|
+
} | {
|
|
751
|
+
kind: "set-layout-mode";
|
|
752
|
+
splitId?: string;
|
|
753
|
+
mode: TilingLayoutMode;
|
|
754
|
+
} | {
|
|
755
|
+
kind: "cycle-layout-mode";
|
|
756
|
+
splitId?: string;
|
|
757
|
+
} | {
|
|
758
|
+
kind: "set-master-count";
|
|
759
|
+
splitId?: string;
|
|
760
|
+
count: number;
|
|
761
|
+
} | {
|
|
762
|
+
kind: "adjust-master-count";
|
|
763
|
+
splitId?: string;
|
|
764
|
+
delta: number;
|
|
765
|
+
} | {
|
|
766
|
+
kind: "set-master-orientation";
|
|
767
|
+
splitId?: string;
|
|
768
|
+
orientation: TilingMasterOrientation;
|
|
769
|
+
} | {
|
|
770
|
+
kind: "cycle-master-orientation";
|
|
771
|
+
splitId?: string;
|
|
772
|
+
} | {
|
|
773
|
+
kind: "adjust-master-ratio";
|
|
774
|
+
splitId?: string;
|
|
775
|
+
delta: number;
|
|
776
|
+
} | {
|
|
777
|
+
kind: "group-leaves";
|
|
778
|
+
leafIds: ReadonlyArray<string>;
|
|
779
|
+
hostLeafId?: string;
|
|
780
|
+
} | {
|
|
781
|
+
kind: "toggle-group";
|
|
782
|
+
leafId?: string;
|
|
783
|
+
} | {
|
|
784
|
+
kind: "ungroup";
|
|
785
|
+
groupId?: string;
|
|
786
|
+
} | {
|
|
787
|
+
kind: "add-to-group";
|
|
788
|
+
groupId: string;
|
|
789
|
+
sourceLeafId: string;
|
|
790
|
+
} | {
|
|
791
|
+
kind: "remove-from-group";
|
|
792
|
+
groupId: string;
|
|
793
|
+
memberId: string;
|
|
794
|
+
} | {
|
|
795
|
+
kind: "group-tab-cycle";
|
|
796
|
+
groupId?: string;
|
|
797
|
+
direction: TilingPaneCycleDirection;
|
|
798
|
+
} | {
|
|
799
|
+
kind: "group-tab-jump";
|
|
800
|
+
groupId?: string;
|
|
801
|
+
memberNumber: number;
|
|
802
|
+
};
|
|
803
|
+
/**
|
|
804
|
+
* The imperative handle exposed via `ref` on `TilingRenderer`. A consumer
|
|
805
|
+
* holds the ref and drives the tiler programmatically — `dispatch` routes a
|
|
806
|
+
* command through the SAME internal router the keyboard layer uses, so a
|
|
807
|
+
* disabled-capability command is a safe no-op (it never mutates the layout).
|
|
808
|
+
*/
|
|
809
|
+
interface TilingCommandHandle {
|
|
810
|
+
/** Route a {@link TilingCommand} through the renderer's command router. */
|
|
811
|
+
dispatch: (command: TilingCommand) => void;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* A single keyboard binding: an arbitrary chord mapped to an arbitrary command.
|
|
815
|
+
* The public chord→command registration surface (the Hyprland `bind` analog),
|
|
816
|
+
* distinct from the fixed `TilingKeymap` chord overrides (which only re-chord
|
|
817
|
+
* the built-in action set). The chord matches on `KeyboardEvent.code` exactly
|
|
818
|
+
* like `TilingKeyChord`.
|
|
819
|
+
*/
|
|
820
|
+
interface TilingKeyBinding {
|
|
821
|
+
/** The chord that triggers this binding (matched on `KeyboardEvent.code`). */
|
|
822
|
+
chord: TilingKeyChord;
|
|
823
|
+
/** The command dispatched when the chord matches. */
|
|
824
|
+
command: TilingCommand;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Consumer keyboard-binding registry. `bindings` augment (and, on a chord
|
|
828
|
+
* collision, override) the default keymap bindings; setting `replaceDefaults`
|
|
829
|
+
* suppresses the built-in keymap path entirely so ONLY these bindings are live.
|
|
830
|
+
*/
|
|
831
|
+
interface TilingKeyBindings {
|
|
832
|
+
/** Consumer chord→command bindings; augment (or override on collision) the defaults. */
|
|
833
|
+
bindings?: ReadonlyArray<TilingKeyBinding>;
|
|
834
|
+
/** When `true`, the default keymap bindings are NOT consulted. Default `false` (augment). */
|
|
835
|
+
replaceDefaults?: boolean;
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Maximize (expand-to-viewport) capability. The maximize render-mode is
|
|
839
|
+
* non-destructive — it hides sibling panes and renders the focused pane filling
|
|
840
|
+
* the tiling viewport without mutating the layout tree.
|
|
841
|
+
*/
|
|
842
|
+
interface TilingMaximizeCapability {
|
|
843
|
+
/** Enable the per-pane maximize/restore control + shortcuts. Default `true`. */
|
|
844
|
+
enable?: boolean;
|
|
845
|
+
/**
|
|
846
|
+
* Per-capability keybinding overrides for `toggleMaximize` / `restore`. These
|
|
847
|
+
* take precedence over the top-level `keymap`, which takes precedence over the
|
|
848
|
+
* documented defaults.
|
|
849
|
+
*/
|
|
850
|
+
keymap?: Pick<TilingKeymap, "toggleMaximize" | "restore">;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Tab-like pane-switching capability. Renders a tab strip across the top of the
|
|
854
|
+
* tiling region and binds the cycle / jump shortcuts. When maximized, switching
|
|
855
|
+
* panes also switches which pane is maximized.
|
|
856
|
+
*/
|
|
857
|
+
interface TilingPaneSwitchingCapability {
|
|
858
|
+
/** Enable pane switching (tab strip + cycle/jump shortcuts). Default `true`. */
|
|
859
|
+
enable?: boolean;
|
|
860
|
+
/**
|
|
861
|
+
* Render the TOP-LEVEL tab strip (the single strip across the top of the
|
|
862
|
+
* tiling region listing every pane). Default `true`. The cycle/jump shortcuts
|
|
863
|
+
* work regardless. This flag does NOT govern the per-group tab strip a
|
|
864
|
+
* tabbed-stacking group renders above its active member — that strip is
|
|
865
|
+
* governed by `grouping.showGroupTabStrip` (see
|
|
866
|
+
* {@link TilingGroupingCapability}).
|
|
867
|
+
*/
|
|
868
|
+
showTabStrip?: boolean;
|
|
869
|
+
/**
|
|
870
|
+
* Render the tab strip's pane-content visibility checkbox (the "content"
|
|
871
|
+
* toggle that flips the default-tile body between content and empty). Default
|
|
872
|
+
* `true`. Set `false` to suppress the control for embeddings that always paint
|
|
873
|
+
* their own content via a custom `renderTile` (e.g. a docs/SEO surface), where
|
|
874
|
+
* the toggle is inert chrome. Suppressing the toggle hands content ownership to
|
|
875
|
+
* the embedding: pane-content is treated as VISIBLE by default
|
|
876
|
+
* (`isPaneContentVisible` initializes `true`) for ALL drag surfaces — in-tree
|
|
877
|
+
* panes, the source slot, the hop-in slot, and the portaled drag ghost — so the
|
|
878
|
+
* ghost body matches the seated body. With no control rendered, the flag cannot
|
|
879
|
+
* be flipped off, so this default holds for the lifetime of the embedding.
|
|
880
|
+
* (Ghost-seat reservation slots still render empty — that is a drag mechanic
|
|
881
|
+
* resolved by `resolvePaneBodyRenderMode`, independent of this flag.)
|
|
882
|
+
*/
|
|
883
|
+
showContentToggle?: boolean;
|
|
884
|
+
/**
|
|
885
|
+
* Render the macOS Cmd+Tab-style visual switcher overlay while cycling panes
|
|
886
|
+
* with a held modifier (`Alt+]` / `Alt+[`). Default `true`. When `true`, a
|
|
887
|
+
* cycle press opens a centered overlay listing the panes and advances the
|
|
888
|
+
* highlight; the selection commits (focus / activate, and switch the maximized
|
|
889
|
+
* pane when maximized) on modifier release, and `Escape` cancels. When
|
|
890
|
+
* `false`, cycle presses activate the next/previous pane immediately (no
|
|
891
|
+
* overlay). The shortcuts work regardless of this flag.
|
|
892
|
+
*/
|
|
893
|
+
showSwitcherOverlay?: boolean;
|
|
894
|
+
/**
|
|
895
|
+
* Toggle a pane's maximize/restore state when its TAB in the tab strip is
|
|
896
|
+
* double-clicked. Default `true`. The double-click dispatches the SAME
|
|
897
|
+
* `toggle-maximize` command (targeting the tab's leaf) the `Alt+Enter`
|
|
898
|
+
* keybinding dispatches, so the two converge on one maximize state — a
|
|
899
|
+
* double-click maximizes, a second double-click (or `Alt+Enter`, or `Escape`)
|
|
900
|
+
* restores. Single-click tab activation is unaffected. Also gated by the
|
|
901
|
+
* `maximize` capability: with `maximize.enable: false` the double-click is a
|
|
902
|
+
* no-op even when this is `true`. Set `false` to opt out (single-click tab
|
|
903
|
+
* activation only).
|
|
904
|
+
*/
|
|
905
|
+
tabDoubleClickMaximize?: boolean;
|
|
906
|
+
/**
|
|
907
|
+
* Alt/Opt+click a pane HEADER to toggle that pane into a multi-selection set,
|
|
908
|
+
* then group the selected panes into one flat tabbed group via the existing
|
|
909
|
+
* `group-leaves` command (the same chord family as the `Alt+G` group key).
|
|
910
|
+
* Default `true`. A plain (no-modifier) header click keeps its normal
|
|
911
|
+
* focus/drag-pickup behavior; only `altKey` (Opt on macOS, Alt on
|
|
912
|
+
* Windows/Linux) presses participate in multi-selection. When `≥2`
|
|
913
|
+
* groupable panes are selected, a "Group" control appears in each selected
|
|
914
|
+
* pane's header; clicking it dispatches `group-leaves` (the clicked pane is the
|
|
915
|
+
* host slot) and clears the selection. The selection also clears on Escape, on
|
|
916
|
+
* a drag pickup, and on a plain click that establishes a single focus. When
|
|
917
|
+
* `false`, Alt/Opt+click and the Group control are no-ops. The grouping itself
|
|
918
|
+
* is independently gated by
|
|
919
|
+
* the `grouping` capability — with grouping disabled the Group control is
|
|
920
|
+
* suppressed (the multi-select dispatch is a safe no-op).
|
|
921
|
+
*/
|
|
922
|
+
multiSelectGrouping?: boolean;
|
|
923
|
+
/**
|
|
924
|
+
* Per-capability keybinding overrides for `previousPane` / `nextPane` /
|
|
925
|
+
* `jumpToPane`. These take precedence over the top-level `keymap`.
|
|
926
|
+
*/
|
|
927
|
+
keymap?: Pick<TilingKeymap, "previousPane" | "nextPane" | "jumpToPane">;
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Per-pane TITLE-BAR control capability. These controls render directly in each
|
|
931
|
+
* pane's own header (next to maximize), so they target THAT pane (no central
|
|
932
|
+
* target-pane selector). Two independent control groups:
|
|
933
|
+
*
|
|
934
|
+
* - `sizing` — the FLEX / STATIC H / STATIC W / BOTH segmented control. STATIC
|
|
935
|
+
* actions measure the pane's current rendered bbox and pin the chosen
|
|
936
|
+
* dimension(s) to that pixel value; FLEX clears the pin.
|
|
937
|
+
* - `acquireSpace` — the four directional (→ ← ↑ ↓) "grow to claim space"
|
|
938
|
+
* buttons, driven by the `growLeafToward` reducer.
|
|
939
|
+
*/
|
|
940
|
+
interface TilingPaneTitleBarControlsCapability {
|
|
941
|
+
/** Render the per-pane FLEX / STATIC H / STATIC W / BOTH sizing control. Default `true`. */
|
|
942
|
+
sizing?: boolean;
|
|
943
|
+
/** Render the per-pane directional (→ ← ↑ ↓) acquire-space controls. Default `true`. */
|
|
944
|
+
acquireSpace?: boolean;
|
|
945
|
+
}
|
|
946
|
+
/** Resolved per-pane title-bar control capability (no optional fields). */
|
|
947
|
+
interface ResolvedTilingPaneTitleBarControlsCapability {
|
|
948
|
+
/** Whether the per-pane FLEX / STATIC H / STATIC W / BOTH sizing control renders. */
|
|
949
|
+
sizing: boolean;
|
|
950
|
+
/** Whether the per-pane directional acquire-space controls render. */
|
|
951
|
+
acquireSpace: boolean;
|
|
952
|
+
}
|
|
953
|
+
/** Resolved maximize capability (no optional fields). */
|
|
954
|
+
interface ResolvedTilingMaximizeCapability {
|
|
955
|
+
/** Whether the maximize/restore control + shortcuts are live. */
|
|
956
|
+
enable: boolean;
|
|
957
|
+
}
|
|
958
|
+
/** Resolved pane-switching capability (no optional fields). */
|
|
959
|
+
interface ResolvedTilingPaneSwitchingCapability {
|
|
960
|
+
/** Whether pane switching (tab strip + cycle/jump shortcuts) is live. */
|
|
961
|
+
enable: boolean;
|
|
962
|
+
/** Whether the tab strip renders. */
|
|
963
|
+
showTabStrip: boolean;
|
|
964
|
+
/** Whether the tab strip's pane-content visibility checkbox renders. */
|
|
965
|
+
showContentToggle: boolean;
|
|
966
|
+
/** Whether the Cmd+Tab-style switcher overlay renders while cycling. */
|
|
967
|
+
showSwitcherOverlay: boolean;
|
|
968
|
+
/** Whether double-clicking a tab toggles that pane's maximize state. */
|
|
969
|
+
tabDoubleClickMaximize: boolean;
|
|
970
|
+
/** Whether Alt/Opt+click header multi-selection grouping is live. */
|
|
971
|
+
multiSelectGrouping: boolean;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* In-flight state of the macOS Cmd+Tab-style pane switcher. Present only while
|
|
975
|
+
* the operator is mid-cycle (a held-modifier switch flow is open). `null` =
|
|
976
|
+
* not switching.
|
|
977
|
+
*
|
|
978
|
+
* - `selectedLeafId` — the pane the highlight currently rests on; commit
|
|
979
|
+
* activates it.
|
|
980
|
+
* - `holdModifiers` — the modifier set captured from the chord that opened the
|
|
981
|
+
* switcher; the switch commits when any of these modifiers is released (so a
|
|
982
|
+
* custom non-Alt cycle binding still commits on release of its own modifier).
|
|
983
|
+
*/
|
|
984
|
+
interface TilingPaneSwitcherState {
|
|
985
|
+
/** The pane the highlight currently rests on; commit activates it. */
|
|
986
|
+
selectedLeafId: string;
|
|
987
|
+
/** Modifier set captured from the opening chord; commit fires on their release. */
|
|
988
|
+
holdModifiers: ResolvedTilingKeyChordModifiers;
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* In-flight state of keyboard MOVE MODE — the keyboard analog of a drag pickup,
|
|
992
|
+
* present only while the operator is relocating a pane by keyboard. `null` =
|
|
993
|
+
* not in move mode.
|
|
994
|
+
*
|
|
995
|
+
* - `sourceLeafId` — the pane being moved (the keyboard "drag source").
|
|
996
|
+
* - `targetLeafId` — the destination neighbor chosen by the last focus-arrow
|
|
997
|
+
* press (`findLeafByDirection` from the source), or `null` before any arrow.
|
|
998
|
+
* - `placement` — which edge of the target the source lands on when committed
|
|
999
|
+
* (`insertLeafAdjacent`), derived from the arrow direction, or `null` before
|
|
1000
|
+
* any arrow. Commit is a no-op when either is `null`.
|
|
1001
|
+
*/
|
|
1002
|
+
interface TilingMoveModeState {
|
|
1003
|
+
/** The pane being moved (the keyboard "drag source"). */
|
|
1004
|
+
sourceLeafId: string;
|
|
1005
|
+
/** Destination neighbor chosen by the last focus-arrow press, or `null` before any arrow. */
|
|
1006
|
+
targetLeafId: string | null;
|
|
1007
|
+
/** Edge of the target the source lands on when committed, or `null` before any arrow. */
|
|
1008
|
+
placement: TilingMovePlacement | null;
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Adjustable drag-drop HIT-ZONE GEOMETRY. These knobs shape the five-region
|
|
1012
|
+
* partition every pane uses to map a cursor position to a drop intent: one
|
|
1013
|
+
* central SWAP rectangle plus four directional INSERT trapezoids (top / right /
|
|
1014
|
+
* bottom / left) formed by the diagonals from each pane corner to the nearest
|
|
1015
|
+
* center-rectangle corner (see `drop-intent-resolver.ts`). The partition tiles
|
|
1016
|
+
* the full pane with no gaps; the same geometry drives both resolution and the
|
|
1017
|
+
* visual overlay, so the drawn zone is exactly the resolved zone.
|
|
1018
|
+
*
|
|
1019
|
+
* The model is SYMMETRIC: a single `centerRatio` sizes the center rectangle on
|
|
1020
|
+
* BOTH axes, which means the directional edge band depth is fully derived from
|
|
1021
|
+
* it as `(1 - centerRatio) / 2` per axis (there is no independent edge-band
|
|
1022
|
+
* knob, and no separate horizontal/vertical asymmetry — the diagonal-trapezoid
|
|
1023
|
+
* construction uses one ratio). CORNERS are not a distinct zone: a corner
|
|
1024
|
+
* resolves to whichever edge trapezoid contains it, with a deterministic
|
|
1025
|
+
* tie-break order (top → right → bottom → left) on an exact diagonal.
|
|
1026
|
+
*
|
|
1027
|
+
* Every field is optional; an `undefined` field resolves to the documented
|
|
1028
|
+
* default (which equals today's `TILING_DROP_INTENT_CONFIG`), so omitting this
|
|
1029
|
+
* object leaves drop-zone behavior exactly as it was.
|
|
1030
|
+
*/
|
|
1031
|
+
interface TilingDropHitZoneGeometryCapability {
|
|
1032
|
+
/**
|
|
1033
|
+
* Fraction of each pane axis spanned by the central SWAP rectangle. The
|
|
1034
|
+
* directional INSERT edge band depth is the complement, `(1 - centerRatio) /
|
|
1035
|
+
* 2`. Clamped to `[0.05, 0.95]` by the resolver. Default `0.34`. Acts as the
|
|
1036
|
+
* SYMMETRIC convenience: it sets BOTH axes unless a per-axis override
|
|
1037
|
+
* (`centerRatioX` / `centerRatioY`) is supplied for that axis.
|
|
1038
|
+
*/
|
|
1039
|
+
centerRatio?: number;
|
|
1040
|
+
/**
|
|
1041
|
+
* Per-axis HORIZONTAL (width) swap-zone fraction override. When set, it sizes
|
|
1042
|
+
* the center rectangle's X extent independently of `centerRatio`, letting a
|
|
1043
|
+
* non-square pane carry an axis-specific swap-zone proportion. Falls back to
|
|
1044
|
+
* `centerRatio` then the default `0.34`. Clamped to `[0.05, 0.95]`.
|
|
1045
|
+
*/
|
|
1046
|
+
centerRatioX?: number;
|
|
1047
|
+
/**
|
|
1048
|
+
* Per-axis VERTICAL (height) swap-zone fraction override. When set, it sizes
|
|
1049
|
+
* the center rectangle's Y extent independently of `centerRatio`. Falls back
|
|
1050
|
+
* to `centerRatio` then the default `0.34`. Clamped to `[0.05, 0.95]`.
|
|
1051
|
+
*/
|
|
1052
|
+
centerRatioY?: number;
|
|
1053
|
+
/**
|
|
1054
|
+
* Floor (CSS px) for the center rectangle's extent on each axis so tiny panes
|
|
1055
|
+
* keep a usable swap target even when `width * centerRatio` would collapse it.
|
|
1056
|
+
* Default `24`.
|
|
1057
|
+
*/
|
|
1058
|
+
centerMinPx?: number;
|
|
1059
|
+
/**
|
|
1060
|
+
* Boundary stickiness (pane-local CSS px): once the cursor is in a zone it
|
|
1061
|
+
* must cross the boundary by this much before the classification switches,
|
|
1062
|
+
* suppressing sub-pixel flicker at the trapezoid edges. `0` disables
|
|
1063
|
+
* hysteresis. Default `6`.
|
|
1064
|
+
*/
|
|
1065
|
+
hysteresisPx?: number;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Fully-resolved drop hit-zone geometry (no optional fields). `centerRatio` is
|
|
1069
|
+
* retained as the symmetric/representative value (equals `centerRatioX` when no
|
|
1070
|
+
* per-axis override diverges them) for telemetry + the single-knob showcase
|
|
1071
|
+
* display; `centerRatioX` / `centerRatioY` are the per-axis values the resolver
|
|
1072
|
+
* actually consumes.
|
|
1073
|
+
*/
|
|
1074
|
+
interface ResolvedTilingDropHitZoneGeometryCapability {
|
|
1075
|
+
/** Resolved symmetric/representative center swap-zone fraction. */
|
|
1076
|
+
centerRatio: number;
|
|
1077
|
+
/** Resolved per-axis HORIZONTAL swap-zone fraction the resolver consumes. */
|
|
1078
|
+
centerRatioX: number;
|
|
1079
|
+
/** Resolved per-axis VERTICAL swap-zone fraction the resolver consumes. */
|
|
1080
|
+
centerRatioY: number;
|
|
1081
|
+
/** Resolved floor (CSS px) for the center rectangle extent. */
|
|
1082
|
+
centerMinPx: number;
|
|
1083
|
+
/** Resolved boundary stickiness (pane-local CSS px). */
|
|
1084
|
+
hysteresisPx: number;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Public, reactive interaction-capability flags for the tiling renderer. All
|
|
1088
|
+
* fields are optional; an `undefined` field (or an `undefined` config object)
|
|
1089
|
+
* resolves to the all-enabled default via `resolveInteractionCapabilities`.
|
|
1090
|
+
*/
|
|
1091
|
+
interface TilingInteractionCapabilities {
|
|
1092
|
+
/** Divider resize capability. Default `"both"` (every divider resizable). */
|
|
1093
|
+
resize?: TilingResizeCapability;
|
|
1094
|
+
/**
|
|
1095
|
+
* Whether split-divider resize handles are visibly rendered. `false` hides
|
|
1096
|
+
* handle chrome (separator paint / hover affordance) while preserving the
|
|
1097
|
+
* divider hit-target and resize capability gating from `resize`.
|
|
1098
|
+
* Default `false`.
|
|
1099
|
+
*/
|
|
1100
|
+
resizeHandlesVisible?: boolean;
|
|
1101
|
+
/**
|
|
1102
|
+
* Live-drag slot hop-in. Selects between the two drag-presentation behaviors
|
|
1103
|
+
* for the dragged pane:
|
|
1104
|
+
*
|
|
1105
|
+
* - `true` (default, ORIGINAL): the single content-honoring ghost HOPS INTO
|
|
1106
|
+
* and FILLS the resolved slot — the seat rect is measured so the ghost seats
|
|
1107
|
+
* as the single instance and no separate empty reservation lingers beside a
|
|
1108
|
+
* free-following ghost.
|
|
1109
|
+
* - `false` (the seat-measurement is deliberately skipped): the ghost
|
|
1110
|
+
* free-follows the cursor and the in-tree content-less reservation slot stays
|
|
1111
|
+
* shown — the reservation-plus-ghost duality.
|
|
1112
|
+
*
|
|
1113
|
+
* Orthogonal to the CONTENT toggle: in BOTH modes the pane body honors content
|
|
1114
|
+
* uniformly (see `resolvePaneBodyRenderMode`). Only meaningful in
|
|
1115
|
+
* `dragMode: "live"`. Default `true`.
|
|
1116
|
+
*/
|
|
1117
|
+
slotHopInEnabled?: boolean;
|
|
1118
|
+
/**
|
|
1119
|
+
* Drag-to-rearrange (move / swap / edge-insert) capability. When `false`,
|
|
1120
|
+
* panes are not draggable and no drop overlays / hit-zones activate.
|
|
1121
|
+
* Default `true`.
|
|
1122
|
+
*/
|
|
1123
|
+
rearrange?: boolean;
|
|
1124
|
+
/**
|
|
1125
|
+
* Drag-to-rearrange feedback mode: `"preview"` (non-committing projected
|
|
1126
|
+
* overlays) vs `"live"` (Hyprland detach: source detached on pickup, frozen
|
|
1127
|
+
* tree, cursor-following ghost, commit on release). Default `"live"` (the
|
|
1128
|
+
* resolved default in `TILING_INTERACTION_CAPABILITY_DEFAULTS`).
|
|
1129
|
+
* Only meaningful when `rearrange` is enabled; live mode is also unreachable
|
|
1130
|
+
* for static-pane layouts (drag-rearrange is auto-gated off there).
|
|
1131
|
+
*/
|
|
1132
|
+
dragMode?: TilingDragMode;
|
|
1133
|
+
/**
|
|
1134
|
+
* Live-drag slot re-resolution / commitment policy (the single ghost hops INTO
|
|
1135
|
+
* and FILLS the resolved slot). Only meaningful in `dragMode: "live"`. Default
|
|
1136
|
+
* all-resolved (`mode: "delta-responsive"`, `reresolveDeltaPx: 24`).
|
|
1137
|
+
*/
|
|
1138
|
+
slotCommitment?: TilingSlotCommitmentCapability;
|
|
1139
|
+
/**
|
|
1140
|
+
* Touch-drag hardening (touch enable + long-press disambiguation). Only
|
|
1141
|
+
* meaningful when `rearrange` is enabled. Default all-resolved
|
|
1142
|
+
* (`enable: true`, `longPressMs: 220`).
|
|
1143
|
+
*/
|
|
1144
|
+
touchDrag?: TilingTouchDragCapability;
|
|
1145
|
+
/**
|
|
1146
|
+
* Drag / transition self-healing recovery (idle watchdog + rAF-with-timeout
|
|
1147
|
+
* animation arming + idempotent transient-style teardown). Hardens the
|
|
1148
|
+
* live-drag animation/timing layer against frame starvation. Only meaningful
|
|
1149
|
+
* in `dragMode: "live"`. Default all-resolved (`enable: true`,
|
|
1150
|
+
* `maxDraggingIdleMs ≈ 5100`, `frameDeadlineMs ≈ 32`, `transitionSlackMs: 60`).
|
|
1151
|
+
*/
|
|
1152
|
+
dragRecovery?: TilingDragRecoveryCapability;
|
|
1153
|
+
/**
|
|
1154
|
+
* Custom-rendered drag cursor (interaction tier "c"). When `true` (default),
|
|
1155
|
+
* an active live drag hides the OS cursor (`cursor: none` on the tiling root)
|
|
1156
|
+
* and renders a transform-pinned cursor element that follows the pointer and
|
|
1157
|
+
* reflects the drag FSM + drop validity (neutral grab / directional arrow /
|
|
1158
|
+
* swap / blocked). When `false`, the native OS cursor is used during drag.
|
|
1159
|
+
* Only meaningful in `dragMode: "live"`.
|
|
1160
|
+
*/
|
|
1161
|
+
customCursor?: boolean;
|
|
1162
|
+
/**
|
|
1163
|
+
* Ghost pickup scale as a percent of the source pane's full bbox. On drag
|
|
1164
|
+
* start the live-mode ghost animates from the source pane's full bbox to this
|
|
1165
|
+
* fraction of it; values <100% read as lifted/shrunk. The free-following ghost
|
|
1166
|
+
* rests at this scale and morphs toward the resolved slot's bbox on hop-in.
|
|
1167
|
+
* Range `[10, 150]`; clamped where consumed. Default `90`. Only meaningful in
|
|
1168
|
+
* `dragMode: "live"`; skipped under `prefers-reduced-motion`.
|
|
1169
|
+
*/
|
|
1170
|
+
ghostPickupScalePercent?: number;
|
|
1171
|
+
/**
|
|
1172
|
+
* Coherent non-intersecting transit. When `true` (default), the moving source
|
|
1173
|
+
* ghost and the displaced target never visually OVERLAP mid-transition: on a
|
|
1174
|
+
* SWAP both moving boxes scale down toward ~70% mid-transit (best-effort) then
|
|
1175
|
+
* scale back into place, coordinated with the survivor reflow so even if their
|
|
1176
|
+
* paths cross the shrunk boxes do not collide. Trivial / no-op for edge-insert
|
|
1177
|
+
* (the boxes never trade places). Only meaningful in `dragMode: "live"`;
|
|
1178
|
+
* skipped under `prefers-reduced-motion`.
|
|
1179
|
+
*/
|
|
1180
|
+
coherentTransit?: boolean;
|
|
1181
|
+
/** Pane focus selection. When `false`, focus selection is suppressed. Default `true`. */
|
|
1182
|
+
focus?: boolean;
|
|
1183
|
+
/** Maximize-to-viewport capability. Default all-enabled. */
|
|
1184
|
+
maximize?: TilingMaximizeCapability;
|
|
1185
|
+
/** Tab-like pane-switching capability. Default all-enabled. */
|
|
1186
|
+
paneSwitching?: TilingPaneSwitchingCapability;
|
|
1187
|
+
/**
|
|
1188
|
+
* Per-pane title-bar controls (in-header sizing + acquire-space). Default
|
|
1189
|
+
* all-enabled. Reactive: toggling a flag at runtime shows/hides the controls
|
|
1190
|
+
* without remount.
|
|
1191
|
+
*/
|
|
1192
|
+
paneTitleBarControls?: TilingPaneTitleBarControlsCapability;
|
|
1193
|
+
/**
|
|
1194
|
+
* Adjustable drag-drop hit-zone geometry (center swap fraction, center floor,
|
|
1195
|
+
* boundary hysteresis). Undefined → today's `TILING_DROP_INTENT_CONFIG`
|
|
1196
|
+
* defaults. Reactive: changing it at runtime re-shapes the drop zones (and
|
|
1197
|
+
* their visual overlay) immediately.
|
|
1198
|
+
*/
|
|
1199
|
+
dropHitZoneGeometry?: TilingDropHitZoneGeometryCapability;
|
|
1200
|
+
/**
|
|
1201
|
+
* Top-level keymap. Capability-level `keymap` overrides take precedence over
|
|
1202
|
+
* this; this takes precedence over the documented defaults.
|
|
1203
|
+
*/
|
|
1204
|
+
keymap?: TilingKeymap;
|
|
1205
|
+
/**
|
|
1206
|
+
* Public chord→command binding registry. Consumer bindings augment (and on a
|
|
1207
|
+
* chord collision override) the default keymap bindings; set
|
|
1208
|
+
* `replaceDefaults` to drop the built-in keymap path entirely. Undefined → the
|
|
1209
|
+
* default keymap bindings only.
|
|
1210
|
+
*/
|
|
1211
|
+
keyBindings?: TilingKeyBindings;
|
|
1212
|
+
/**
|
|
1213
|
+
* Master/stack layout engine (HT-LAYOUT-MASTER-STACK). When `true` (default),
|
|
1214
|
+
* the layout-mode + master commands (`cycle-layout-mode`,
|
|
1215
|
+
* `adjust-master-count`, `cycle-master-orientation`, `adjust-master-ratio`, …)
|
|
1216
|
+
* and their default keybindings are live, and a subtree set to
|
|
1217
|
+
* `layoutMode: "master"` renders as a master area + stack. When `false`, those
|
|
1218
|
+
* commands are no-ops (a `master`-mode tree still renders via the resolver, but
|
|
1219
|
+
* the operator cannot change the mode/params). Default `true`.
|
|
1220
|
+
*/
|
|
1221
|
+
masterLayout?: boolean;
|
|
1222
|
+
/**
|
|
1223
|
+
* Group / tabbed-stacking (HT-GROUP-TABBED-STACKING). A bare boolean is
|
|
1224
|
+
* shorthand for `{ enable }`; the object form additionally governs the
|
|
1225
|
+
* per-group tab strip via `showGroupTabStrip` (see
|
|
1226
|
+
* {@link TilingGroupingCapability}). Default `true` (grouping enabled, strip
|
|
1227
|
+
* rendered).
|
|
1228
|
+
*/
|
|
1229
|
+
grouping?: boolean | TilingGroupingCapability;
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Group / tabbed-stacking capability (HT-GROUP-TABBED-STACKING), the object
|
|
1233
|
+
* form of the `grouping` capability. A bare boolean at the `grouping` slot is
|
|
1234
|
+
* shorthand for `{ enable }`.
|
|
1235
|
+
*/
|
|
1236
|
+
interface TilingGroupingCapability {
|
|
1237
|
+
/**
|
|
1238
|
+
* Enable grouping. When `true` (default), the grouping commands
|
|
1239
|
+
* (`toggle-group`, `ungroup`, `add-to-group`, `group-tab-cycle`,
|
|
1240
|
+
* `group-tab-jump`, `group-leaves`) and their default keybindings are live,
|
|
1241
|
+
* and drag-onto-a-group's-tab-strip merges into the group. When `false`,
|
|
1242
|
+
* those commands are no-ops and drag-into-group is disabled (an existing
|
|
1243
|
+
* group still renders per this capability's `showGroupTabStrip`).
|
|
1244
|
+
*/
|
|
1245
|
+
enable?: boolean;
|
|
1246
|
+
/**
|
|
1247
|
+
* Render the per-group tab strip (the member tabs a tabbed-stacking group
|
|
1248
|
+
* paints above its active member). Default `true`. When `false`, the strip
|
|
1249
|
+
* is suppressed and the group renders only its active member; the keyboard
|
|
1250
|
+
* group commands (`group-tab-cycle`, `group-tab-jump`, `remove-from-group`,
|
|
1251
|
+
* `ungroup`) keep working, so a consumer that hides the strip can paint its
|
|
1252
|
+
* own group chrome and route it through the same commands. Note:
|
|
1253
|
+
* drag-onto-the-strip group merge requires a mounted strip, so hiding the
|
|
1254
|
+
* strip also removes that drop target. Distinct from
|
|
1255
|
+
* `paneSwitching.showTabStrip`, which governs the TOP-LEVEL tab strip only.
|
|
1256
|
+
*/
|
|
1257
|
+
showGroupTabStrip?: boolean;
|
|
1258
|
+
}
|
|
1259
|
+
/** Resolved group / tabbed-stacking capability (no optional fields). */
|
|
1260
|
+
interface ResolvedTilingGroupingCapability {
|
|
1261
|
+
/** Whether group / tabbed-stacking is enabled. */
|
|
1262
|
+
enable: boolean;
|
|
1263
|
+
/** Whether the per-group tab strip renders. */
|
|
1264
|
+
showGroupTabStrip: boolean;
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Fully-resolved interaction capabilities (no optional fields). The resolved
|
|
1268
|
+
* shape is a structural superset of `TilingInteractionCapabilities`, so a
|
|
1269
|
+
* resolved object can be re-fed to `resolveInteractionCapabilities` (idempotent)
|
|
1270
|
+
* and passed straight back into the `interaction` prop.
|
|
1271
|
+
*/
|
|
1272
|
+
interface ResolvedTilingInteractionCapabilities {
|
|
1273
|
+
/** Resolved divider resize capability. */
|
|
1274
|
+
resize: TilingResizeCapability;
|
|
1275
|
+
/** Whether split-divider resize handles are visibly rendered. */
|
|
1276
|
+
resizeHandlesVisible: boolean;
|
|
1277
|
+
/** Whether the single ghost hops into and fills the resolved slot. */
|
|
1278
|
+
slotHopInEnabled: boolean;
|
|
1279
|
+
/** Whether drag-to-rearrange is enabled. */
|
|
1280
|
+
rearrange: boolean;
|
|
1281
|
+
/** Resolved drag feedback mode (`"preview"` vs `"live"`). */
|
|
1282
|
+
dragMode: TilingDragMode;
|
|
1283
|
+
/** Resolved live-drag slot-commitment configuration. */
|
|
1284
|
+
slotCommitment: ResolvedTilingSlotCommitmentCapability;
|
|
1285
|
+
/** Resolved touch-drag hardening configuration. */
|
|
1286
|
+
touchDrag: ResolvedTilingTouchDragCapability;
|
|
1287
|
+
/** Resolved drag/transition self-healing recovery configuration. */
|
|
1288
|
+
dragRecovery: ResolvedTilingDragRecoveryCapability;
|
|
1289
|
+
/** Whether the custom-rendered drag cursor is used during live drag. */
|
|
1290
|
+
customCursor: boolean;
|
|
1291
|
+
/** Resolved ghost pickup scale as a percent of the source pane bbox. */
|
|
1292
|
+
ghostPickupScalePercent: number;
|
|
1293
|
+
/** Whether coherent non-intersecting transit is enabled. */
|
|
1294
|
+
coherentTransit: boolean;
|
|
1295
|
+
/** Whether pane focus selection is enabled. */
|
|
1296
|
+
focus: boolean;
|
|
1297
|
+
/** Resolved maximize-to-viewport capability. */
|
|
1298
|
+
maximize: ResolvedTilingMaximizeCapability;
|
|
1299
|
+
/** Resolved tab-like pane-switching capability. */
|
|
1300
|
+
paneSwitching: ResolvedTilingPaneSwitchingCapability;
|
|
1301
|
+
/** Resolved per-pane title-bar controls capability. */
|
|
1302
|
+
paneTitleBarControls: ResolvedTilingPaneTitleBarControlsCapability;
|
|
1303
|
+
/** Resolved adjustable drop hit-zone geometry. */
|
|
1304
|
+
dropHitZoneGeometry: ResolvedTilingDropHitZoneGeometryCapability;
|
|
1305
|
+
/** Resolved keymap (every chord explicit). */
|
|
1306
|
+
keymap: ResolvedTilingKeymap;
|
|
1307
|
+
/**
|
|
1308
|
+
* Resolved consumer key bindings (the raw registry passed through; an empty
|
|
1309
|
+
* binding list + `replaceDefaults: false` when omitted). The renderer matches
|
|
1310
|
+
* these before the default keymap path.
|
|
1311
|
+
*/
|
|
1312
|
+
keyBindings: ResolvedTilingKeyBindings;
|
|
1313
|
+
/** Whether the master/stack layout engine is enabled. */
|
|
1314
|
+
masterLayout: boolean;
|
|
1315
|
+
/** Resolved group / tabbed-stacking capability. */
|
|
1316
|
+
grouping: ResolvedTilingGroupingCapability;
|
|
1317
|
+
}
|
|
1318
|
+
/** Fully-resolved key-binding registry (no optional fields). */
|
|
1319
|
+
interface ResolvedTilingKeyBindings {
|
|
1320
|
+
/** Resolved consumer chord→command bindings (empty when none supplied). */
|
|
1321
|
+
bindings: ReadonlyArray<TilingKeyBinding>;
|
|
1322
|
+
/** Whether the default keymap bindings are suppressed. */
|
|
1323
|
+
replaceDefaults: boolean;
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Per-pane identity accent. A closed, typed palette so a consumer can drive a
|
|
1327
|
+
* picker from the enumerable `TILING_TILE_ACCENTS` list (exported from the
|
|
1328
|
+
* renderer) with exhaustive type-checking — adding a member here forces every
|
|
1329
|
+
* accent theme map to cover it.
|
|
1330
|
+
*/
|
|
1331
|
+
type TilingTileAccent = "cyan" | "sky" | "violet" | "indigo" | "emerald" | "amber" | "rose" | "pink";
|
|
1332
|
+
/**
|
|
1333
|
+
* Closed set of built-in visual theme ids for the renderer. A theme bundles the
|
|
1334
|
+
* class-string tokens for every surface (pane shell, header, focus frame,
|
|
1335
|
+
* ghost, dividers, root, tab strip) plus the accent-composition resolvers. The
|
|
1336
|
+
* token interfaces + registry live in `./theme`; this union is the central
|
|
1337
|
+
* contract a consumer types its `themeId` state against.
|
|
1338
|
+
*/
|
|
1339
|
+
type TilingThemeId = "neon-terminal" | "clean-flat" | "mosaic";
|
|
1340
|
+
/**
|
|
1341
|
+
* A pickable accent paired with a human label and a solid Tailwind background
|
|
1342
|
+
* class for rendering a swatch dot — the generic metadata a palette control
|
|
1343
|
+
* (e.g. the showcase top-bar picker) iterates to offer accent selection.
|
|
1344
|
+
*/
|
|
1345
|
+
interface TilingTileAccentSwatch {
|
|
1346
|
+
/** The accent this swatch selects. */
|
|
1347
|
+
accent: TilingTileAccent;
|
|
1348
|
+
/** Human-readable label for the swatch (e.g. in a picker). */
|
|
1349
|
+
label: string;
|
|
1350
|
+
/** Tailwind background class rendering the solid swatch dot. */
|
|
1351
|
+
swatchClassName: string;
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Generic tile payload. Only `id` + `title` are required so a product consumer
|
|
1355
|
+
* (e.g. a dashboard) can supply a minimal `{ id, title, content }` tile and a
|
|
1356
|
+
* custom `renderTile`. The `accent` / `rows` fields drive `DefaultTilingTile`
|
|
1357
|
+
* and the drag-pane snapshot chrome; when omitted they fall back (accent →
|
|
1358
|
+
* `"cyan"`, rows → `[]`), so a tile without them renders correctly under the
|
|
1359
|
+
* default tile surface. `content` is the slot a custom `renderTile` reads.
|
|
1360
|
+
*/
|
|
1361
|
+
interface TilingTile {
|
|
1362
|
+
/** Stable tile identity; leaf nodes reference a tile by this `id`. */
|
|
1363
|
+
id: string;
|
|
1364
|
+
/** Title shown in the pane header / tab. */
|
|
1365
|
+
title: string;
|
|
1366
|
+
/** Optional one-line description surfaced by the default tile chrome. */
|
|
1367
|
+
description?: string;
|
|
1368
|
+
/** Optional per-tile identity accent. Falls back to `"cyan"` when omitted. */
|
|
1369
|
+
accent?: TilingTileAccent;
|
|
1370
|
+
/** Optional text rows for the default tile body. Falls back to `[]`. */
|
|
1371
|
+
rows?: ReadonlyArray<string>;
|
|
1372
|
+
/** Rich body a custom `renderTile` reads (and the drag ghost paints). */
|
|
1373
|
+
content?: React.ReactNode;
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* A leaf slot: a single pane that renders one tile. The renderer's smallest
|
|
1377
|
+
* addressable layout unit — focus, drag, resize, and sizing all target a leaf
|
|
1378
|
+
* by its `id`.
|
|
1379
|
+
*/
|
|
1380
|
+
interface TilingLeafNode {
|
|
1381
|
+
/** Node discriminant. Always `"leaf"`. */
|
|
1382
|
+
kind: "leaf";
|
|
1383
|
+
/** Stable node identity, unique within the layout tree. */
|
|
1384
|
+
id: string;
|
|
1385
|
+
/** The `TilingTile.id` this leaf renders. */
|
|
1386
|
+
tileId: string;
|
|
1387
|
+
/** Per-dimension static/flexible sizing. Undefined dimensions are flexible. */
|
|
1388
|
+
sizing?: TilingPaneSizing;
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* A binary split node: divides its region between two child subtrees along
|
|
1392
|
+
* `axis` by `ratio`. In `layoutMode: "master"` the binary structure defines
|
|
1393
|
+
* slot membership/order while the master resolver drives geometry.
|
|
1394
|
+
*/
|
|
1395
|
+
interface TilingSplitNode {
|
|
1396
|
+
/** Node discriminant. Always `"split"`. */
|
|
1397
|
+
kind: "split";
|
|
1398
|
+
/** Stable node identity, unique within the layout tree. */
|
|
1399
|
+
id: string;
|
|
1400
|
+
/** Split orientation (`"horizontal"` = side-by-side, `"vertical"` = stacked). */
|
|
1401
|
+
axis: TilingSplitAxis;
|
|
1402
|
+
/** Fraction `[0, 1]` of the region allotted to `first` along `axis`. */
|
|
1403
|
+
ratio: number;
|
|
1404
|
+
/** The first (top/left) child subtree. */
|
|
1405
|
+
first: TilingLayoutNode;
|
|
1406
|
+
/** The second (bottom/right) child subtree. */
|
|
1407
|
+
second: TilingLayoutNode;
|
|
1408
|
+
/** Optional per-split gap override (CSS px) between the two children. */
|
|
1409
|
+
gapPx?: number;
|
|
1410
|
+
/** Optional per-split minimum pane extent (CSS px) enforced on resize. */
|
|
1411
|
+
minPaneSizePx?: number;
|
|
1412
|
+
/** Per-dimension static/flexible sizing. Undefined dimensions are flexible. */
|
|
1413
|
+
sizing?: TilingPaneSizing;
|
|
1414
|
+
/**
|
|
1415
|
+
* Arrangement of this subtree's slots. Undefined → `"dwindle"` (the binary
|
|
1416
|
+
* split layout — every hand-authored tree + the test baseline is unchanged).
|
|
1417
|
+
* `"master"` lays the subtree's descendant slots out as master area + stack.
|
|
1418
|
+
*/
|
|
1419
|
+
layoutMode?: TilingLayoutMode;
|
|
1420
|
+
/**
|
|
1421
|
+
* `layoutMode: "master"` only — number of slots in the master area. Undefined
|
|
1422
|
+
* → `1`. Clamped to `[1, slotCount]` by the resolver / reducers.
|
|
1423
|
+
*/
|
|
1424
|
+
masterCount?: number;
|
|
1425
|
+
/**
|
|
1426
|
+
* `layoutMode: "master"` only — where the master area sits. Undefined →
|
|
1427
|
+
* `"left"`. In master mode the split's `ratio` is reused as the master-area
|
|
1428
|
+
* fraction along this orientation's primary axis.
|
|
1429
|
+
*/
|
|
1430
|
+
masterOrientation?: TilingMasterOrientation;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* A group/member slot (HT-GROUP-TABBED-STACKING): N leaves share ONE layout slot
|
|
1434
|
+
* as a stacked group with a tab strip — only `activeMemberId` renders / is
|
|
1435
|
+
* hit-tested, the tabs switch the active member. A group is a SLOT (like a leaf),
|
|
1436
|
+
* so a slot in either dwindle or master layout can hold a group. Members are
|
|
1437
|
+
* leaves only (no nested split/group — a group of one is degenerate and collapses
|
|
1438
|
+
* back to a bare leaf).
|
|
1439
|
+
*/
|
|
1440
|
+
interface TilingGroupNode {
|
|
1441
|
+
/** Node discriminant. Always `"group"`. */
|
|
1442
|
+
kind: "group";
|
|
1443
|
+
/** Stable node identity, unique within the layout tree. */
|
|
1444
|
+
id: string;
|
|
1445
|
+
/** ≥1 member; array order is the tab order. */
|
|
1446
|
+
members: ReadonlyArray<TilingLeafNode>;
|
|
1447
|
+
/** Always one of `members[].id` — the single rendered/hit-tested member. */
|
|
1448
|
+
activeMemberId: string;
|
|
1449
|
+
/** A group can be static like a leaf (per-dimension static/flexible sizing). */
|
|
1450
|
+
sizing?: TilingPaneSizing;
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* A node in the layout tree: a leaf (single pane), a split (two subtrees), or a
|
|
1454
|
+
* group (tabbed leaves in one slot). The recursive union you own in state and
|
|
1455
|
+
* feed to `TilingRenderer` via the `layout` prop.
|
|
1456
|
+
*/
|
|
1457
|
+
type TilingLayoutNode = TilingLeafNode | TilingSplitNode | TilingGroupNode;
|
|
1458
|
+
/** Global geometry configuration for the renderer (the `config` prop). */
|
|
1459
|
+
interface TilingLayoutConfig {
|
|
1460
|
+
/** Gap (CSS px) painted in the gutters between panes. */
|
|
1461
|
+
gapPx: number;
|
|
1462
|
+
/** Minimum pane extent (CSS px) a resize divider will not shrink a pane below. */
|
|
1463
|
+
minPaneSizePx: number;
|
|
1464
|
+
/** Resize-handle hit-target thickness (CSS px). */
|
|
1465
|
+
handleSizePx: number;
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* The renderer surface a `renderTile` invocation paints:
|
|
1469
|
+
*
|
|
1470
|
+
* - `"pane"` — the seated in-tree pane (the normal, interactive case).
|
|
1471
|
+
* - `"drag-ghost"` — the floating, portaled pickup ghost that travels with the
|
|
1472
|
+
* cursor during a drag. `aria-hidden` + `pointer-events-none`: handlers are
|
|
1473
|
+
* inert no-ops, capability display flags stay real.
|
|
1474
|
+
* - `"drag-cancel"` — the cancel fly-back overlay (the ghost gliding home after
|
|
1475
|
+
* a cancelled drag). Same inert-handlers / real-flags semantics as
|
|
1476
|
+
* `"drag-ghost"`.
|
|
1477
|
+
*/
|
|
1478
|
+
type TilingRenderSurface = "pane" | "drag-ghost" | "drag-cancel";
|
|
1479
|
+
/**
|
|
1480
|
+
* One member of a tabbed group, as seen by a custom `renderTile` through
|
|
1481
|
+
* {@link TilingRenderTileGroupContext.members}. Mirrors what the built-in
|
|
1482
|
+
* group tab strip paints per tab: the member's identity, its resolved tile
|
|
1483
|
+
* payload, its 1-based position (the `group-tab-jump` operand — also the
|
|
1484
|
+
* keyboard `Alt+<n>` label), and whether it is the active (rendered) member.
|
|
1485
|
+
*/
|
|
1486
|
+
interface TilingGroupMemberView {
|
|
1487
|
+
/** The member's leaf node id. */
|
|
1488
|
+
readonly leafId: string;
|
|
1489
|
+
/** The tile id the member's leaf points at. */
|
|
1490
|
+
readonly tileId: string;
|
|
1491
|
+
/** The resolved tile payload, or `null` when the tile map has no match. */
|
|
1492
|
+
readonly tile: TilingTile | null;
|
|
1493
|
+
/**
|
|
1494
|
+
* 1-based position in the group's member order — the operand
|
|
1495
|
+
* {@link TilingRenderTileGroupContext.activateMember} takes (and the number
|
|
1496
|
+
* the built-in strip / keyboard `Alt+<n>` jump display).
|
|
1497
|
+
*/
|
|
1498
|
+
readonly memberNumber: number;
|
|
1499
|
+
/** Whether this member is the group's active (rendered) member. */
|
|
1500
|
+
readonly isActive: boolean;
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Group context on {@link TilingRenderTileProps.group}: present when the pane
|
|
1504
|
+
* being rendered is a tabbed group's ACTIVE member (the only member that
|
|
1505
|
+
* renders, per the stacking contract), `null` for loose leaves and for the
|
|
1506
|
+
* drag-ghost / drag-cancel surfaces. A custom pane uses it to paint its own
|
|
1507
|
+
* group chrome (tabs, member list, eject/ungroup controls) instead of the
|
|
1508
|
+
* built-in strip — typically with the strip suppressed via the `grouping`
|
|
1509
|
+
* capability's `showGroupTabStrip: false`.
|
|
1510
|
+
*
|
|
1511
|
+
* The callbacks route through the SAME internal command router the built-in
|
|
1512
|
+
* strip and the keyboard layer use (`group-tab-jump` / `remove-from-group` /
|
|
1513
|
+
* `ungroup`), so capability gating and observability stay uniform.
|
|
1514
|
+
*/
|
|
1515
|
+
interface TilingRenderTileGroupContext {
|
|
1516
|
+
/** The group node id. */
|
|
1517
|
+
readonly groupId: string;
|
|
1518
|
+
/** The group's members in member order (see {@link TilingGroupMemberView}). */
|
|
1519
|
+
readonly members: ReadonlyArray<TilingGroupMemberView>;
|
|
1520
|
+
/**
|
|
1521
|
+
* Activate the member at `memberNumber` (1-based; a
|
|
1522
|
+
* {@link TilingGroupMemberView.memberNumber}) — dispatches `group-tab-jump`.
|
|
1523
|
+
*/
|
|
1524
|
+
readonly activateMember: (memberNumber: number) => void;
|
|
1525
|
+
/**
|
|
1526
|
+
* Eject the member with `leafId` from the group (it re-seats as a loose
|
|
1527
|
+
* pane) — dispatches `remove-from-group`.
|
|
1528
|
+
*/
|
|
1529
|
+
readonly removeMember: (leafId: string) => void;
|
|
1530
|
+
/** Dissolve the whole group into loose panes — dispatches `ungroup`. */
|
|
1531
|
+
readonly ungroup: () => void;
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* The argument object passed to a custom `renderTile`. This is the clean,
|
|
1535
|
+
* consumer-facing pane contract: the tile payload, this pane's derived state
|
|
1536
|
+
* (focus / drag / drop / sizing), and the imperative callbacks a custom pane
|
|
1537
|
+
* surface wires to its header, drag handle, and controls. Every field is
|
|
1538
|
+
* something a custom pane legitimately reads to style itself or wires to drive
|
|
1539
|
+
* an interaction — nothing here is a debug, observability, or showcase concern
|
|
1540
|
+
* (those live on the internal render path and the `/devtools` surface).
|
|
1541
|
+
*
|
|
1542
|
+
* @remarks
|
|
1543
|
+
* A minimal custom pane needs only three wiring rules, each of which the
|
|
1544
|
+
* optional public helper primitives ({@link TilingPaneRoot},
|
|
1545
|
+
* {@link TilingDragHandle}, {@link TilingPaneAction}, {@link TilingPaneBody})
|
|
1546
|
+
* encode so they cannot be gotten wrong:
|
|
1547
|
+
* - the pane root must carry `data-leaf-id={leafId}` (the renderer resolves the
|
|
1548
|
+
* drag source through the `[data-leaf-id]` attribute) and wire `onFocus`,
|
|
1549
|
+
* `onPointerMove`, `onPointerLeave`;
|
|
1550
|
+
* - the drag handle wires `onHandlePointerDown` with `touch-action: none`;
|
|
1551
|
+
* - header action buttons must `stopPropagation` on pointer-down + click so a
|
|
1552
|
+
* click does not start a drag or steal focus;
|
|
1553
|
+
* - the body renders only when `paneBodyRenderMode === "render-content"` (the
|
|
1554
|
+
* drag ghost reuses the same render path).
|
|
1555
|
+
*/
|
|
1556
|
+
interface TilingRenderTileProps {
|
|
1557
|
+
/**
|
|
1558
|
+
* Which renderer surface these args paint (see {@link TilingRenderSurface}).
|
|
1559
|
+
* `"pane"` for the seated in-tree pane; `"drag-ghost"` for the floating
|
|
1560
|
+
* pickup ghost that follows the cursor; `"drag-cancel"` for the cancel
|
|
1561
|
+
* fly-back overlay. On the two drag surfaces every interaction handler is an
|
|
1562
|
+
* inert no-op while the capability display flags stay REAL (reflecting the
|
|
1563
|
+
* resolved capabilities), so capability-keyed chrome does not vanish
|
|
1564
|
+
* mid-drag; a custom pane that wants different drag chrome branches on this
|
|
1565
|
+
* discriminator.
|
|
1566
|
+
*/
|
|
1567
|
+
readonly surface: TilingRenderSurface;
|
|
1568
|
+
/** The leaf node id this render targets. */
|
|
1569
|
+
leafId: string;
|
|
1570
|
+
/** The resolved tile payload for this leaf. */
|
|
1571
|
+
tile: TilingTile;
|
|
1572
|
+
/** 1-based pane ordinal in current tab order (for generic pane labels). */
|
|
1573
|
+
paneOrdinal: number;
|
|
1574
|
+
/** Current pane viewport width in pixels (for responsive header/control density). */
|
|
1575
|
+
paneWidthPx: number;
|
|
1576
|
+
/**
|
|
1577
|
+
* Global pane-content visibility toggle from the tab strip checkbox.
|
|
1578
|
+
* `false` hides pane body content by default.
|
|
1579
|
+
*/
|
|
1580
|
+
isPaneContentVisible: boolean;
|
|
1581
|
+
/**
|
|
1582
|
+
* Canonical pane-body visibility decision resolved by the renderer policy.
|
|
1583
|
+
* Keeps custom tile renderers aligned with the default drag/hidden semantics.
|
|
1584
|
+
*/
|
|
1585
|
+
paneBodyRenderMode: TilingPaneBodyRenderMode;
|
|
1586
|
+
/** Whether this pane is the source of the in-flight drag. */
|
|
1587
|
+
isDragSource: boolean;
|
|
1588
|
+
/** Whether this pane is the resolved drop target of the in-flight drag. */
|
|
1589
|
+
isDropTarget: boolean;
|
|
1590
|
+
/** Whether this pane is a valid drop destination for the current drag. */
|
|
1591
|
+
isDropEligible: boolean;
|
|
1592
|
+
/** Whether the cursor is currently hovering this pane as a drop candidate. */
|
|
1593
|
+
isHoveringDropCandidate: boolean;
|
|
1594
|
+
/** Whether the current hover over this pane would be an invalid drop. */
|
|
1595
|
+
isInvalidDrop: boolean;
|
|
1596
|
+
/** Whether this pane currently holds focus. */
|
|
1597
|
+
isFocused: boolean;
|
|
1598
|
+
/** Whether drag-to-rearrange is enabled (drives handle affordance). */
|
|
1599
|
+
isRearrangeEnabled: boolean;
|
|
1600
|
+
/**
|
|
1601
|
+
* Whether this pane is the SOURCE of an in-flight keyboard move (the keyboard
|
|
1602
|
+
* analog of a drag source). Drives the "MOVING" affordance.
|
|
1603
|
+
*/
|
|
1604
|
+
isMoveSource: boolean;
|
|
1605
|
+
/**
|
|
1606
|
+
* When this pane is the pending move-mode DESTINATION, the edge of this pane
|
|
1607
|
+
* the moved source will land on (`insertLeafAdjacent` placement). `null` when
|
|
1608
|
+
* this pane is not the current move-mode target.
|
|
1609
|
+
*/
|
|
1610
|
+
moveTargetPlacement: TilingMovePlacement | null;
|
|
1611
|
+
/** Whether this pane is currently maximized (fills the tiling viewport). */
|
|
1612
|
+
isMaximized: boolean;
|
|
1613
|
+
/** Whether the maximize capability is enabled (controls header button visibility). */
|
|
1614
|
+
isMaximizeEnabled: boolean;
|
|
1615
|
+
/** Toggle maximize/restore for this pane. */
|
|
1616
|
+
onToggleMaximize: () => void;
|
|
1617
|
+
/** Whether the per-pane title-bar sizing control (FLEX / STATIC H / STATIC W / BOTH) is enabled. */
|
|
1618
|
+
isTitleBarSizingEnabled: boolean;
|
|
1619
|
+
/** Whether the per-pane title-bar directional acquire-space controls (→ ← ↑ ↓) are enabled. */
|
|
1620
|
+
isTitleBarAcquireSpaceEnabled: boolean;
|
|
1621
|
+
/** This pane's current WIDTH sizing mode (static/flexible) — drives the active control state. */
|
|
1622
|
+
widthSizingMode: TilingPaneSizingMode;
|
|
1623
|
+
/** This pane's current HEIGHT sizing mode (static/flexible) — drives the active control state. */
|
|
1624
|
+
heightSizingMode: TilingPaneSizingMode;
|
|
1625
|
+
/**
|
|
1626
|
+
* Set THIS pane's sizing mode. STATIC modes measure the pane's current bbox
|
|
1627
|
+
* (getBoundingClientRect on its `[data-leaf-id]` element) and pin the chosen
|
|
1628
|
+
* dimension(s) to that pixel value; FLEX clears the pin and returns the pane
|
|
1629
|
+
* to ratio distribution. Emits via `onLayoutChange` (controlled).
|
|
1630
|
+
*/
|
|
1631
|
+
onSetSizingMode: (mode: TilingTitleBarSizingMode) => void;
|
|
1632
|
+
/**
|
|
1633
|
+
* Grow THIS pane to claim the maximum available space in `direction` by
|
|
1634
|
+
* pushing matching-axis ancestor dividers toward the limit (siblings clamped
|
|
1635
|
+
* to their minimum). Emits via `onLayoutChange` (controlled).
|
|
1636
|
+
*/
|
|
1637
|
+
onAcquireSpace: (direction: TilingFocusDirection) => void;
|
|
1638
|
+
/** The resolved drop zone under the cursor for this pane, or `null`. */
|
|
1639
|
+
dropZone: TilingLeafDropZone | null;
|
|
1640
|
+
/** The projected landing/result preview for this pane, or `null`. */
|
|
1641
|
+
preview: TilingLeafDropPreview | null;
|
|
1642
|
+
/**
|
|
1643
|
+
* Group context when this pane is a tabbed group's ACTIVE member (the only
|
|
1644
|
+
* member that renders, per the stacking contract); `null` for loose leaves
|
|
1645
|
+
* and on the `"drag-ghost"` / `"drag-cancel"` surfaces. See
|
|
1646
|
+
* {@link TilingRenderTileGroupContext}.
|
|
1647
|
+
*/
|
|
1648
|
+
readonly group: TilingRenderTileGroupContext | null;
|
|
1649
|
+
/**
|
|
1650
|
+
* Establish single focus on this pane (and clear any in-progress
|
|
1651
|
+
* multi-selection). Wire to the pane root's `onFocus`. The renderer reads the
|
|
1652
|
+
* focus event's `target`: when a multi-selection is active and focus landed on
|
|
1653
|
+
* a header CONTROL button (Group / maximize), it is a no-op, so a click on the
|
|
1654
|
+
* Group button is not nullified by the button stealing focus first.
|
|
1655
|
+
*/
|
|
1656
|
+
onFocus: (event?: React.SyntheticEvent<HTMLElement>) => void;
|
|
1657
|
+
/**
|
|
1658
|
+
* Whether the Alt/Opt+click header multi-selection feature is live
|
|
1659
|
+
* (`paneSwitching.multiSelectGrouping` AND the `grouping` capability). When
|
|
1660
|
+
* `false`, the header click handler must treat a modified click as a plain
|
|
1661
|
+
* click and never render the Group control.
|
|
1662
|
+
*/
|
|
1663
|
+
isMultiSelectGroupingEnabled: boolean;
|
|
1664
|
+
/** Whether THIS pane is currently a member of the multi-selection set. */
|
|
1665
|
+
isMultiSelected: boolean;
|
|
1666
|
+
/**
|
|
1667
|
+
* Whether the current multi-selection (`≥2` panes) can be folded into one
|
|
1668
|
+
* flat group right now — i.e. `group-leaves` would change the layout. Any mix
|
|
1669
|
+
* of loose panes and/or existing-group members flattens into ONE group (groups
|
|
1670
|
+
* the selection touches are dissolved and their members folded in). Drives
|
|
1671
|
+
* whether the Group control is offered; `false` hides it rather than offering a
|
|
1672
|
+
* no-op (e.g. the selection is already exactly one group).
|
|
1673
|
+
*/
|
|
1674
|
+
canGroupMultiSelection: boolean;
|
|
1675
|
+
/**
|
|
1676
|
+
* Toggle THIS pane in/out of the multi-selection set. Wire to an
|
|
1677
|
+
* Alt/Opt+click on the pane header. Does not change focus.
|
|
1678
|
+
*/
|
|
1679
|
+
onToggleMultiSelect: () => void;
|
|
1680
|
+
/**
|
|
1681
|
+
* Group the current multi-selection into ONE flat tabbed group occupying the
|
|
1682
|
+
* CLICKED pane's slot (pass this pane's `leafId`), then clear the selection.
|
|
1683
|
+
* The clicked pane becomes the host (active tab); any existing group in the
|
|
1684
|
+
* selection is dissolved and folded in. Wire to the Group control.
|
|
1685
|
+
*/
|
|
1686
|
+
onGroupMultiSelection: (clickedLeafId: string) => void;
|
|
1687
|
+
/**
|
|
1688
|
+
* Pointer-Events drag pickup on the pane's drag handle (the title-bar grip).
|
|
1689
|
+
* Wire this to the handle's `onPointerDown`; the renderer arms the drag FSM,
|
|
1690
|
+
* crosses the pickup threshold, and takes pointer capture on a stable element
|
|
1691
|
+
* so reflow moving panes under the cursor can never lose or hijack the drag.
|
|
1692
|
+
* Replaces the former HTML5 `draggable` + `onDragStart`/`onDragEnd` plumbing.
|
|
1693
|
+
*/
|
|
1694
|
+
onHandlePointerDown: (event: React.PointerEvent<HTMLElement>) => void;
|
|
1695
|
+
/** Pre-drag hover telemetry (drop-intent hit-log); inert while a drag is in flight. */
|
|
1696
|
+
onPointerMove: (event: React.PointerEvent<HTMLElement>) => void;
|
|
1697
|
+
/** Clears this pane's hover telemetry when the pointer leaves it. */
|
|
1698
|
+
onPointerLeave: (event: React.PointerEvent<HTMLElement>) => void;
|
|
1699
|
+
}
|
|
1700
|
+
/** The five drop regions of a pane: a central swap zone plus four insert edges. */
|
|
1701
|
+
type TilingLeafDropZone = "center" | "left" | "right" | "top" | "bottom";
|
|
1702
|
+
/**
|
|
1703
|
+
* Resolved pane-body render decision:
|
|
1704
|
+
* - `"render-content"` — paint the tile body,
|
|
1705
|
+
* - `"render-empty"` — hidden body (content toggle off),
|
|
1706
|
+
* - `"render-reservation"` — empty ghost-seat reservation slot during a drag.
|
|
1707
|
+
*/
|
|
1708
|
+
type TilingPaneBodyRenderMode = "render-content" | "render-empty" | "render-reservation";
|
|
1709
|
+
/** Which edge of a target pane an inserted/moved pane lands on. */
|
|
1710
|
+
type TilingMovePlacement = "left" | "right" | "top" | "bottom";
|
|
1711
|
+
/** A directional focus / move target relative to the current pane. */
|
|
1712
|
+
type TilingFocusDirection = "left" | "right" | "up" | "down";
|
|
1713
|
+
/** Which side of a preview a shadow represents (drag source vs drop target). */
|
|
1714
|
+
type TilingLeafPreviewRole = "drag-source-landing-shadow" | "drop-target-result-shadow";
|
|
1715
|
+
/** Whether a preview depicts a swap or an edge-insert result. */
|
|
1716
|
+
type TilingLeafPreviewMode = "swap" | "edge-insert";
|
|
1717
|
+
/**
|
|
1718
|
+
* The outcome a drop resolves to: exchange tiles (`"swap"`), insert at an edge
|
|
1719
|
+
* (`"edge-insert"`), insert into an existing split container
|
|
1720
|
+
* (`"split-container-insert"`), merge into a tabbed group (`"group-merge"`), or
|
|
1721
|
+
* no valid action (`"none"`).
|
|
1722
|
+
*/
|
|
1723
|
+
type TilingDropAction = "swap" | "edge-insert" | "split-container-insert" | "group-merge" | "none";
|
|
1724
|
+
/** Snapshot of the tuning knobs that shaped a drop-intent resolution. */
|
|
1725
|
+
interface TilingDropIntentTuningState {
|
|
1726
|
+
/** Symmetric center swap-zone fraction in effect. */
|
|
1727
|
+
centerRatio: number;
|
|
1728
|
+
/** Edge threshold fraction derived from the center ratio. */
|
|
1729
|
+
edgeThresholdRatio: number;
|
|
1730
|
+
/** Boundary stickiness (pane-local CSS px) in effect. */
|
|
1731
|
+
hysteresisPx: number;
|
|
1732
|
+
/** `window.devicePixelRatio` the geometry snapped to. */
|
|
1733
|
+
devicePixelRatio: number;
|
|
1734
|
+
}
|
|
1735
|
+
/** Full diagnostic snapshot of a single drop-intent resolution (observability). */
|
|
1736
|
+
interface TilingDropIntentDebugState {
|
|
1737
|
+
/** The hovered leaf this resolution targets. */
|
|
1738
|
+
leafId: string;
|
|
1739
|
+
/** The resolved drop zone under the cursor. */
|
|
1740
|
+
zone: TilingLeafDropZone;
|
|
1741
|
+
/** The resolved drop action. */
|
|
1742
|
+
action: TilingDropAction;
|
|
1743
|
+
/** The nearest edge the cursor points toward (pre-fallback). */
|
|
1744
|
+
dominantEdge: Exclude<TilingLeafDropZone, "center">;
|
|
1745
|
+
/** The edge finally selected after fallbacks, or `null`. */
|
|
1746
|
+
finalEdge: Exclude<TilingLeafDropZone, "center"> | null;
|
|
1747
|
+
/** Why the dominant edge was replaced by a fallback, or `null`. */
|
|
1748
|
+
fallbackReason: string | null;
|
|
1749
|
+
/** Why the action was blocked, or `null` when unblocked. */
|
|
1750
|
+
blockedReason: string | null;
|
|
1751
|
+
/** Split axes from the root to the target, describing the containment path. */
|
|
1752
|
+
axisPath: ReadonlyArray<TilingSplitAxis>;
|
|
1753
|
+
/** Edge threshold fraction in effect. */
|
|
1754
|
+
edgeThresholdRatio: number;
|
|
1755
|
+
/** Center rectangle width (CSS px), or `null` when unmeasured. */
|
|
1756
|
+
centerRectWidthPx: number | null;
|
|
1757
|
+
/** Center rectangle height (CSS px), or `null` when unmeasured. */
|
|
1758
|
+
centerRectHeightPx: number | null;
|
|
1759
|
+
/** Cursor distance to the center rectangle (CSS px), or `null`. */
|
|
1760
|
+
centerDistancePx: number | null;
|
|
1761
|
+
/** Cursor distance to the nearest edge (CSS px), or `null`. */
|
|
1762
|
+
nearestEdgeDistancePx: number | null;
|
|
1763
|
+
/** Pane-local cursor X (CSS px), or `null`. */
|
|
1764
|
+
paneLocalX: number | null;
|
|
1765
|
+
/** Pane-local cursor Y (CSS px), or `null`. */
|
|
1766
|
+
paneLocalY: number | null;
|
|
1767
|
+
/** The ancestor split chosen for a split-container insert, or `null`. */
|
|
1768
|
+
targetSplitId: string | null;
|
|
1769
|
+
/** Which child slot of that split the insert targets, or `null`. */
|
|
1770
|
+
targetSplitPlacement: "first" | "second" | null;
|
|
1771
|
+
/** The edge zone selected on the chosen split, or `null`. */
|
|
1772
|
+
selectedSplitZone: Exclude<TilingLeafDropZone, "center"> | null;
|
|
1773
|
+
/** Cursor distance to the selected split edge (CSS px), or `null`. */
|
|
1774
|
+
selectedSplitDistancePx: number | null;
|
|
1775
|
+
/** Reasons candidate splits were rejected during resolution. */
|
|
1776
|
+
rejectedSplitReasons: ReadonlyArray<string>;
|
|
1777
|
+
/** The tuning knobs that shaped this resolution. */
|
|
1778
|
+
tuning: TilingDropIntentTuningState;
|
|
1779
|
+
}
|
|
1780
|
+
/** Per-edge validity diagnostic for the live drag hit-log. */
|
|
1781
|
+
interface TilingLiveHitEdgeDebugState {
|
|
1782
|
+
/** The edge zone this diagnostic describes. */
|
|
1783
|
+
zone: Exclude<TilingLeafDropZone, "center">;
|
|
1784
|
+
/** Whether an insert on this edge is currently valid. */
|
|
1785
|
+
isValid: boolean;
|
|
1786
|
+
/** Why the edge was rejected, or `null` when valid. */
|
|
1787
|
+
rejectionReason: string | null;
|
|
1788
|
+
}
|
|
1789
|
+
/** A cursor position in viewport (client) coordinates. */
|
|
1790
|
+
interface TilingViewportCursorState {
|
|
1791
|
+
/** Client X (CSS px). */
|
|
1792
|
+
x: number;
|
|
1793
|
+
/** Client Y (CSS px). */
|
|
1794
|
+
y: number;
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* Live drag/hover hit-log snapshot streamed via `onLiveHitLogChange` — the
|
|
1798
|
+
* observability feed the `/devtools` panel renders. `null` when there is no
|
|
1799
|
+
* active hover/drag.
|
|
1800
|
+
*/
|
|
1801
|
+
interface TilingLiveHitLogState {
|
|
1802
|
+
/** The leaf currently under the cursor. */
|
|
1803
|
+
hoveredLeafId: string;
|
|
1804
|
+
/** The pre-drag hover source leaf, or `null`. */
|
|
1805
|
+
sourceLeafId: string | null;
|
|
1806
|
+
/** The in-flight drag source leaf, or `null` when not dragging. */
|
|
1807
|
+
dragSourceLeafId: string | null;
|
|
1808
|
+
/** Current cursor position (client coords). */
|
|
1809
|
+
cursorViewport: TilingViewportCursorState;
|
|
1810
|
+
/** Measured footprint of the hover source pane, or `null`. */
|
|
1811
|
+
sourcePaneFootprint: TilingPaneFootprint | null;
|
|
1812
|
+
/** Measured footprint of the drag source pane, or `null`. */
|
|
1813
|
+
dragSourcePaneFootprint: TilingPaneFootprint | null;
|
|
1814
|
+
/** Whether a drag is currently in flight. */
|
|
1815
|
+
isDragging: boolean;
|
|
1816
|
+
/** The resolver's zone under the cursor, or `"none"`. */
|
|
1817
|
+
resolverZone: TilingLeafDropZone | "none";
|
|
1818
|
+
/** Symmetric center swap-zone fraction in effect. */
|
|
1819
|
+
centerRatio: number;
|
|
1820
|
+
/** Edge threshold fraction in effect. */
|
|
1821
|
+
edgeThresholdRatio: number;
|
|
1822
|
+
/** Center rectangle width (CSS px). */
|
|
1823
|
+
centerRectWidthPx: number;
|
|
1824
|
+
/** Center rectangle height (CSS px). */
|
|
1825
|
+
centerRectHeightPx: number;
|
|
1826
|
+
/** Whether the center (swap) zone is currently a valid target. */
|
|
1827
|
+
centerIsValid: boolean;
|
|
1828
|
+
/** Why the center zone is blocked, or `null`. */
|
|
1829
|
+
centerBlockedReason: string | null;
|
|
1830
|
+
/** Per-edge validity diagnostics for the four insert edges. */
|
|
1831
|
+
edgeDiagnostics: ReadonlyArray<TilingLiveHitEdgeDebugState>;
|
|
1832
|
+
/** The full resolved drop-intent snapshot, or `null`. */
|
|
1833
|
+
intent: TilingDropIntentDebugState | null;
|
|
1834
|
+
/** Leaf whose in-tree slot the ghost seats into (swap target or edge-insert source). */
|
|
1835
|
+
ghostSeatLeafId?: string | null;
|
|
1836
|
+
/** Resolved drop action for the active hover target (observability). */
|
|
1837
|
+
presentationDropAction?: TilingDropAction | null;
|
|
1838
|
+
}
|
|
1839
|
+
/** Per-edge validity candidate for the pane hit-zone overlay. */
|
|
1840
|
+
interface TilingPaneHitZoneCandidateDebugState {
|
|
1841
|
+
/** The edge zone this candidate describes. */
|
|
1842
|
+
zone: Exclude<TilingLeafDropZone, "center">;
|
|
1843
|
+
/** Whether an insert on this edge is currently valid. */
|
|
1844
|
+
isValid: boolean;
|
|
1845
|
+
/** Why the edge was rejected, or `null` when valid. */
|
|
1846
|
+
rejectionReason: string | null;
|
|
1847
|
+
}
|
|
1848
|
+
/** Per-pane hit-zone overlay state driving the five-region debug visualization. */
|
|
1849
|
+
interface TilingPaneHitZoneOverlayDebugState {
|
|
1850
|
+
/** The leaf this overlay is drawn over. */
|
|
1851
|
+
leafId: string;
|
|
1852
|
+
/** The active drag source leaf, or `null`. */
|
|
1853
|
+
dragSourceLeafId: string | null;
|
|
1854
|
+
/** Symmetric center swap-zone fraction. */
|
|
1855
|
+
centerRatio: number;
|
|
1856
|
+
/** Per-axis HORIZONTAL swap-zone fraction (drives the X clip-path boundaries). */
|
|
1857
|
+
centerRatioX: number;
|
|
1858
|
+
/** Per-axis VERTICAL swap-zone fraction (drives the Y clip-path boundaries). */
|
|
1859
|
+
centerRatioY: number;
|
|
1860
|
+
/** Center rectangle width (CSS px). */
|
|
1861
|
+
centerRectWidthPx: number;
|
|
1862
|
+
/** Center rectangle height (CSS px). */
|
|
1863
|
+
centerRectHeightPx: number;
|
|
1864
|
+
/** Whether the center (swap) zone is a valid target. */
|
|
1865
|
+
centerIsValid: boolean;
|
|
1866
|
+
/** Why the center zone is blocked, or `null`. */
|
|
1867
|
+
centerBlockedReason: string | null;
|
|
1868
|
+
/** Per-edge validity candidates for the four insert edges. */
|
|
1869
|
+
edgeCandidates: ReadonlyArray<TilingPaneHitZoneCandidateDebugState>;
|
|
1870
|
+
}
|
|
1871
|
+
/** A projected landing/result preview shown on a pane during a drag. */
|
|
1872
|
+
interface TilingLeafDropPreview {
|
|
1873
|
+
/** Whether this preview is the drag-source landing or the drop-target result. */
|
|
1874
|
+
role: TilingLeafPreviewRole;
|
|
1875
|
+
/** Whether the preview depicts a swap or an edge-insert. */
|
|
1876
|
+
mode: TilingLeafPreviewMode;
|
|
1877
|
+
/** The drop zone the preview corresponds to. */
|
|
1878
|
+
zone: TilingLeafDropZone;
|
|
1879
|
+
/** The other leaf involved (swap counterpart or insert neighbor). */
|
|
1880
|
+
partnerLeafId: string;
|
|
1881
|
+
}
|
|
1882
|
+
/** Options controlling how `insertLeafAdjacent` places an inserted leaf. */
|
|
1883
|
+
interface TilingInsertionOptions {
|
|
1884
|
+
/** When `true`, reuse the parent split's axis instead of the placement axis. */
|
|
1885
|
+
preserveParentSplitAxis: boolean;
|
|
1886
|
+
/** Ratio `[0, 1]` allotted to the inserted leaf in the new split. */
|
|
1887
|
+
splitRatio: number;
|
|
1888
|
+
}
|
|
1889
|
+
/** A measured pane rectangle in client coordinates (CSS px). */
|
|
1890
|
+
interface TilingPaneFootprint {
|
|
1891
|
+
/** Left edge (client X). */
|
|
1892
|
+
left: number;
|
|
1893
|
+
/** Top edge (client Y). */
|
|
1894
|
+
top: number;
|
|
1895
|
+
/** Width (CSS px). */
|
|
1896
|
+
width: number;
|
|
1897
|
+
/** Height (CSS px). */
|
|
1898
|
+
height: number;
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Hex colors for the drag/drop observability overlays (borders, projected
|
|
1902
|
+
* landing fills, and hit-zone tints). Consumed by the renderer overlays and the
|
|
1903
|
+
* `/devtools` observability panel; see `TILING_OBSERVABILITY_COLOR_DEFAULTS`.
|
|
1904
|
+
*/
|
|
1905
|
+
interface TilingObservabilityColorConfig {
|
|
1906
|
+
/** Border color of the drag source pane. */
|
|
1907
|
+
dragSourceBorderColorHex: string;
|
|
1908
|
+
/** Border color of the drag target pane. */
|
|
1909
|
+
dragTargetBorderColorHex: string;
|
|
1910
|
+
/** Border color of the projected source (S') landing. */
|
|
1911
|
+
projectedSourceBorderColorHex: string;
|
|
1912
|
+
/** Border color of the projected target (T') landing. */
|
|
1913
|
+
projectedTargetBorderColorHex: string;
|
|
1914
|
+
/** Border color of the projected successor landing. */
|
|
1915
|
+
projectedSuccessorBorderColorHex: string;
|
|
1916
|
+
/** Fill color of the projected source (S') landing. */
|
|
1917
|
+
projectedSourceFillColorHex: string;
|
|
1918
|
+
/** Fill color of the projected target (T') landing. */
|
|
1919
|
+
projectedTargetFillColorHex: string;
|
|
1920
|
+
/** Fill color of the projected successor landing. */
|
|
1921
|
+
projectedSuccessorFillColorHex: string;
|
|
1922
|
+
/** Tint of the left insert hit zone. */
|
|
1923
|
+
hitZoneLeftColorHex: string;
|
|
1924
|
+
/** Tint of the right insert hit zone. */
|
|
1925
|
+
hitZoneRightColorHex: string;
|
|
1926
|
+
/** Tint of the top insert hit zone. */
|
|
1927
|
+
hitZoneTopColorHex: string;
|
|
1928
|
+
/** Tint of the bottom insert hit zone. */
|
|
1929
|
+
hitZoneBottomColorHex: string;
|
|
1930
|
+
/** Tint of the center swap hit zone. */
|
|
1931
|
+
hitZoneCenterColorHex: string;
|
|
1932
|
+
/** Tint applied when a hit zone is blocked. */
|
|
1933
|
+
hitZoneBlockedColorHex: string;
|
|
1934
|
+
}
|
|
1935
|
+
/** Per-subject overlay/border visibility toggles for the showcase observability panel. */
|
|
1936
|
+
interface TilingObservabilityColorEnableConfig {
|
|
1937
|
+
/** Whether the drag source border overlay is drawn. */
|
|
1938
|
+
dragSourceBorderEnabled: boolean;
|
|
1939
|
+
/** Whether the drag target border overlay is drawn. */
|
|
1940
|
+
dragTargetBorderEnabled: boolean;
|
|
1941
|
+
/** Whether the projected source (S') border overlay is drawn. */
|
|
1942
|
+
projectedSourceBorderEnabled: boolean;
|
|
1943
|
+
/** Whether the projected target (T') border overlay is drawn. */
|
|
1944
|
+
projectedTargetBorderEnabled: boolean;
|
|
1945
|
+
/** Whether the projected source (S') fill overlay is drawn. */
|
|
1946
|
+
projectedSourceFillEnabled: boolean;
|
|
1947
|
+
/** Whether the projected target (T') fill overlay is drawn. */
|
|
1948
|
+
projectedTargetFillEnabled: boolean;
|
|
1949
|
+
/** Whether the projected successor border overlay is drawn. */
|
|
1950
|
+
projectedSuccessorBorderEnabled: boolean;
|
|
1951
|
+
/** Whether the projected successor fill overlay is drawn. */
|
|
1952
|
+
projectedSuccessorFillEnabled: boolean;
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* Props for the {@link TilingRenderer} component — the full controlled-component
|
|
1956
|
+
* surface. `layout` + `tiles` + `config` + `onLayoutChange` are the four
|
|
1957
|
+
* required props; everything else is optional and resolves to a documented
|
|
1958
|
+
* default.
|
|
1959
|
+
*
|
|
1960
|
+
* @remarks
|
|
1961
|
+
* The renderer is a CONTROLLED component: you hold the layout tree in state and
|
|
1962
|
+
* apply every edit it reports through `onLayoutChange`. Focus, maximize, theme,
|
|
1963
|
+
* and accent can each be left uncontrolled (renderer-managed) or lifted into
|
|
1964
|
+
* your state via the matching `on*Change` callback. Interaction behavior is
|
|
1965
|
+
* tuned entirely through the single `interaction` prop
|
|
1966
|
+
* ({@link TilingInteractionCapabilities}). This surface is debug-free: the
|
|
1967
|
+
* drag/drop observability overlays, hit-zone visualizations, and telemetry
|
|
1968
|
+
* feeds are a devtools concern, exposed through `TilingRendererObservabilityProps`
|
|
1969
|
+
* on the `@n-uf/hypr-tiling/devtools` entry rather than here.
|
|
1970
|
+
*
|
|
1971
|
+
* @example
|
|
1972
|
+
* ```tsx
|
|
1973
|
+
* const [layout, setLayout] = useState<TilingLayoutNode>(initialLayout);
|
|
1974
|
+
* return (
|
|
1975
|
+
* <TilingRenderer
|
|
1976
|
+
* layout={layout}
|
|
1977
|
+
* tiles={tiles}
|
|
1978
|
+
* config={DEFAULT_TILING_LAYOUT_CONFIG}
|
|
1979
|
+
* onLayoutChange={setLayout}
|
|
1980
|
+
* />
|
|
1981
|
+
* );
|
|
1982
|
+
* ```
|
|
1983
|
+
*
|
|
1984
|
+
* @see {@link TilingRenderer}
|
|
1985
|
+
* @see {@link TilingInteractionCapabilities}
|
|
1986
|
+
*/
|
|
1987
|
+
interface TilingRendererProps {
|
|
1988
|
+
/** The controlled layout tree to render. Apply every reported edit back here. */
|
|
1989
|
+
layout: TilingLayoutNode;
|
|
1990
|
+
/**
|
|
1991
|
+
* Tile registry, accepted as either an ordered array (resolved by `id`) or a
|
|
1992
|
+
* `Map` keyed by tile id. A dashboard can pass a plain `ReadonlyArray` of
|
|
1993
|
+
* `{ id, title, content }` tiles; the interactive lab passes a `Map`.
|
|
1994
|
+
*/
|
|
1995
|
+
tiles: ReadonlyArray<TilingTile> | ReadonlyMap<string, TilingTile>;
|
|
1996
|
+
/** Global geometry configuration (gap, min pane size, handle size). */
|
|
1997
|
+
config: TilingLayoutConfig;
|
|
1998
|
+
/** Called with the next layout tree whenever the renderer edits it (controlled). */
|
|
1999
|
+
onLayoutChange: (layout: TilingLayoutNode) => void;
|
|
2000
|
+
/** Optional class name applied to the tiling root element. */
|
|
2001
|
+
className?: string;
|
|
2002
|
+
/**
|
|
2003
|
+
* Active visual theme id. Selects which built-in `TilingTheme` paints every
|
|
2004
|
+
* renderer surface (pane shells, header, focus frame, ghost, dividers, root,
|
|
2005
|
+
* tab strip) and how per-pane accents compose with it. Undefined resolves to
|
|
2006
|
+
* the library default (`"neon-terminal"`). Reacts to prop changes without
|
|
2007
|
+
* remount — a live switch re-themes the whole tree.
|
|
2008
|
+
*/
|
|
2009
|
+
themeId?: TilingThemeId;
|
|
2010
|
+
/**
|
|
2011
|
+
* Full consumer-authored theme; takes precedence over `themeId`. Every
|
|
2012
|
+
* renderer-painted surface (pane shells, header, focus frame, ghost,
|
|
2013
|
+
* dividers, root, tab strip) and every accent-composition resolver comes
|
|
2014
|
+
* from this object, so a consumer owns the complete chrome without touching
|
|
2015
|
+
* library internals. Undefined → the built-in theme selected by `themeId`.
|
|
2016
|
+
*/
|
|
2017
|
+
theme?: TilingTheme;
|
|
2018
|
+
/**
|
|
2019
|
+
* Notified when the in-renderer theme switcher (top-bar control) requests a
|
|
2020
|
+
* different theme. Present this control only when wired; the consumer owns
|
|
2021
|
+
* the `themeId` state (controlled). Omit to hide the switcher — the theme
|
|
2022
|
+
* stays whatever `themeId` (or the `theme` prop) resolves to. Generic
|
|
2023
|
+
* mechanism; the demo theme composition lives with the consumer. BUILT-INS
|
|
2024
|
+
* ONLY: the switcher enumerates the built-in registry and reports
|
|
2025
|
+
* `TilingThemeId` members — a consumer running a custom `theme` object does
|
|
2026
|
+
* not wire this callback (its theme never appears in the switcher).
|
|
2027
|
+
*/
|
|
2028
|
+
onThemeChange?: (themeId: TilingThemeId) => void;
|
|
2029
|
+
/**
|
|
2030
|
+
* Reactive interaction-capability flags. Undefined resolves to all-enabled.
|
|
2031
|
+
* Changing this prop at runtime updates renderer behavior immediately.
|
|
2032
|
+
*/
|
|
2033
|
+
interaction?: TilingInteractionCapabilities;
|
|
2034
|
+
/** Custom pane renderer. Receives {@link TilingRenderTileProps}; omit to use the default tile. */
|
|
2035
|
+
renderTile?: (args: TilingRenderTileProps) => React.ReactNode;
|
|
2036
|
+
/** Controlled focused-leaf id. `undefined` → uncontrolled; `null` → nothing focused. */
|
|
2037
|
+
focusedLeafId?: string | null;
|
|
2038
|
+
/** Notified whenever the focused leaf changes. */
|
|
2039
|
+
onFocusedLeafChange?: (leafId: string) => void;
|
|
2040
|
+
/**
|
|
2041
|
+
* When provided, the top-bar tab strip surfaces an accent palette picker
|
|
2042
|
+
* (the enumerable `TILING_TILE_ACCENTS` swatches) that recolors the
|
|
2043
|
+
* currently-focused pane's tile. The renderer resolves the focused tile id;
|
|
2044
|
+
* the consumer owns the tile registry and applies the new accent (e.g. by
|
|
2045
|
+
* updating its tiles state). Omit to hide the picker — accent remains a
|
|
2046
|
+
* static per-tile property. Generic mechanism; the demo palette composition
|
|
2047
|
+
* lives with the consumer.
|
|
2048
|
+
*/
|
|
2049
|
+
onTileAccentChange?: (tileId: string, accent: TilingTileAccent) => void;
|
|
2050
|
+
/**
|
|
2051
|
+
* Controlled maximized-pane id. `undefined` → uncontrolled (renderer-managed
|
|
2052
|
+
* internal state). `null` → controlled, nothing maximized. A leaf id →
|
|
2053
|
+
* controlled, that pane maximized. Reacts to prop changes without remount.
|
|
2054
|
+
*/
|
|
2055
|
+
maximizedLeafId?: string | null;
|
|
2056
|
+
/** Notified whenever the maximized pane changes (`null` on restore). */
|
|
2057
|
+
onMaximizedLeafChange?: (leafId: string | null) => void;
|
|
2058
|
+
/** Whether translucent projected landing overlays are shown during a drag. */
|
|
2059
|
+
showDropPreviewOverlays?: boolean;
|
|
2060
|
+
/** Background opacity `[0, 1]` for the projected landing overlays. */
|
|
2061
|
+
projectedOverlayBackgroundAlpha?: number;
|
|
2062
|
+
/**
|
|
2063
|
+
* Master gate for all drag-motion choreography. When `false`, the ghost hop,
|
|
2064
|
+
* survivor reflow, pickup-entrance, and swap dip collapse to instant placement
|
|
2065
|
+
* (durations → ~0). Default `true`. The per-knob values (speeds, bounce) are
|
|
2066
|
+
* preserved and re-apply when re-enabled.
|
|
2067
|
+
*/
|
|
2068
|
+
dragAnimationEnabled?: boolean;
|
|
2069
|
+
/**
|
|
2070
|
+
* CSS `<easing-function>` for the dragged GHOST's hop transit (hop-in /
|
|
2071
|
+
* hop-out / pickup entrance) and the swap/edge-insert ghost motion. Undefined
|
|
2072
|
+
* → the default snappy decel `cubic-bezier(0.2, 0.8, 0.2, 1)`. An invalid /
|
|
2073
|
+
* empty string falls back to that default (never reaches the compositor as a
|
|
2074
|
+
* broken `transition`). The seated-ghost magnetic `linear()` curve and the
|
|
2075
|
+
* swap-bounce curve are NOT replaced by this knob (sampled non-bezier curves).
|
|
2076
|
+
*/
|
|
2077
|
+
dragHopEasing?: string;
|
|
2078
|
+
/**
|
|
2079
|
+
* CSS `<easing-function>` for the affected ("survivor") panes' FLIP reflow
|
|
2080
|
+
* settle. Undefined → defaults to the same curve as `dragHopEasing` so the
|
|
2081
|
+
* ghost and survivors read as one coordinated motion. Invalid / empty falls
|
|
2082
|
+
* back to the default.
|
|
2083
|
+
*/
|
|
2084
|
+
dragReflowEasing?: string;
|
|
2085
|
+
/**
|
|
2086
|
+
* Speed of the dragged GHOST's transit animation (hop-in / hop-out / pickup
|
|
2087
|
+
* entrance) as a percent of the 170ms baseline (`100` = baseline). Lower is
|
|
2088
|
+
* slower; higher is faster. Clamped to `[10, 400]`. Default `100`.
|
|
2089
|
+
*/
|
|
2090
|
+
ghostTransitSpeedPercent?: number;
|
|
2091
|
+
/**
|
|
2092
|
+
* Speed of the affected ("survivor") panes' REFLOW transform animation as a
|
|
2093
|
+
* percent of the 170ms baseline (`100` = baseline). Lower is slower; higher is
|
|
2094
|
+
* faster. Clamped to `[10, 400]`. Default `100`. When this equals
|
|
2095
|
+
* `ghostTransitSpeedPercent` the two parties are at PARITY, which the coherent
|
|
2096
|
+
* non-intersecting transit dip requires (see `coherentTransit`).
|
|
2097
|
+
*/
|
|
2098
|
+
survivorReflowSpeedPercent?: number;
|
|
2099
|
+
/**
|
|
2100
|
+
* Swap-landing bounce magnitude as a percent of full overshoot (`0` = no
|
|
2101
|
+
* overshoot, today's monotonic settle; `100` = pronounced bounce). Applies an
|
|
2102
|
+
* easeOutBack overshoot to the ghost seated hop-in and the survivor reflow
|
|
2103
|
+
* settle. Per-element (no cross-element coupling), so it is NOT gated by speed
|
|
2104
|
+
* parity. Inert while the coherent-transit dip owns the landing. Clamped to
|
|
2105
|
+
* `[0, 100]`. Default `0`. Skipped under `prefers-reduced-motion`.
|
|
2106
|
+
*/
|
|
2107
|
+
swapBounceMagnitudePercent?: number;
|
|
2108
|
+
/** Whether drop border hints are painted on candidate panes during a drag. */
|
|
2109
|
+
showDropBorderHints?: boolean;
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* The debug / observability inputs to {@link TilingRenderer}. Deliberately OFF
|
|
2113
|
+
* the consumer {@link TilingRendererProps} contract — they drive the drag/drop
|
|
2114
|
+
* observability overlays, hit-zone visualizations, and telemetry feeds that the
|
|
2115
|
+
* `/devtools` observability panel consumes, not any consumer-facing behavior.
|
|
2116
|
+
* Reach for them through the `@n-uf/hypr-tiling/devtools` entry (which exports
|
|
2117
|
+
* the renderer typed to also accept these); the curated `.` renderer surface
|
|
2118
|
+
* stays free of debug cruft.
|
|
2119
|
+
*
|
|
2120
|
+
* @public
|
|
2121
|
+
*/
|
|
2122
|
+
interface TilingRendererObservabilityProps {
|
|
2123
|
+
/** Observability hook: notified with the current projected-overlay count. */
|
|
2124
|
+
onProjectedOverlayCountChange?: (count: number) => void;
|
|
2125
|
+
/** Override colors (hex) for the drag/drop observability overlays. */
|
|
2126
|
+
observabilityColors?: TilingObservabilityColorConfig;
|
|
2127
|
+
/** Per-subject visibility toggles for the observability overlays. */
|
|
2128
|
+
observabilityColorEnables?: TilingObservabilityColorEnableConfig;
|
|
2129
|
+
/** Whether the translucent drop-intent background tint is shown during a drag. */
|
|
2130
|
+
showDropIntentTranslucentBg?: boolean;
|
|
2131
|
+
/** Whether the drop-intent debug overlay is shown. */
|
|
2132
|
+
showDropIntentDebug?: boolean;
|
|
2133
|
+
/** Whether the five-region pane hit-zone debug overlay is shown. */
|
|
2134
|
+
showPaneHitZones?: boolean;
|
|
2135
|
+
/** Opacity `[0, 1]` for the pane hit-zone debug overlay. */
|
|
2136
|
+
paneHitZonesAlpha?: number;
|
|
2137
|
+
/** Force the hit-zone overlay to treat this leaf as the drag source (debug). */
|
|
2138
|
+
paneHitZoneSourceLeafId?: string | null;
|
|
2139
|
+
/** Observability hook: notified with the resolved drop intent (or `null`). */
|
|
2140
|
+
onDropIntentChange?: (intent: TilingDropIntentDebugState | null) => void;
|
|
2141
|
+
/** Observability hook: notified with the live drag/hover hit-log (or `null`). */
|
|
2142
|
+
onLiveHitLogChange?: (state: TilingLiveHitLogState | null) => void;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
declare const TILING_OBSERVABILITY_COLOR_DEFAULTS: TilingObservabilityColorConfig;
|
|
2146
|
+
declare const TILING_OBSERVABILITY_COLOR_ENABLE_DEFAULTS: TilingObservabilityColorEnableConfig;
|
|
2147
|
+
/**
|
|
2148
|
+
* Recommended baseline layout config — the generic gap / min-pane / handle
|
|
2149
|
+
* scale. `config` stays a required renderer prop (spacing is explicit at the
|
|
2150
|
+
* call site), but consumers that don't tune spacing can spread this for a
|
|
2151
|
+
* tasteful, well-readable inter-pane gutter out of the box instead of inventing
|
|
2152
|
+
* their own magic numbers. `gapPx` + `handleSizePx` together form the visible
|
|
2153
|
+
* inter-pane gap (the divider element occupies `handleSizePx` flanked by
|
|
2154
|
+
* `gapPx / 2` margins; each child subtracts `(gapPx + handleSizePx) / 2` of
|
|
2155
|
+
* basis — see `splitGapOffsetPx` in the split renderer for the balancing math).
|
|
2156
|
+
*/
|
|
2157
|
+
declare const DEFAULT_TILING_LAYOUT_CONFIG: TilingLayoutConfig;
|
|
2158
|
+
/** Baseline ghost-hop / survivor-reflow duration at `DEFAULT_DRAG_ANIMATION_SPEED_PERCENT`. */
|
|
2159
|
+
declare const BASELINE_DRAG_HOP_DURATION_MS: number;
|
|
2160
|
+
/** Default drag animation speed percent (`100` = the baseline duration). */
|
|
2161
|
+
declare const DEFAULT_DRAG_ANIMATION_SPEED_PERCENT: number;
|
|
2162
|
+
/** Slowest (floor) drag animation speed percent the slider + clamp allow. */
|
|
2163
|
+
declare const DRAG_ANIMATION_SPEED_MIN_PERCENT: number;
|
|
2164
|
+
/** Fastest (ceiling) drag animation speed percent the slider + clamp allow. */
|
|
2165
|
+
declare const DRAG_ANIMATION_SPEED_MAX_PERCENT: number;
|
|
2166
|
+
/** Duration the drag-motion timings collapse to when `dragAnimationEnabled` is `false`. */
|
|
2167
|
+
declare const INSTANT_DRAG_DURATION_MS: number;
|
|
2168
|
+
/**
|
|
2169
|
+
* The controlled tiling renderer — the single component a consumer mounts. Its
|
|
2170
|
+
* public prop surface ({@link TilingRendererProps}) is the curated, debug-free
|
|
2171
|
+
* contract. The underlying component also accepts the devtools-tier
|
|
2172
|
+
* `TilingRendererObservabilityProps`; that widened view is exported as
|
|
2173
|
+
* `TilingRenderer` from `@n-uf/hypr-tiling/devtools` for the observability panel.
|
|
2174
|
+
*/
|
|
2175
|
+
declare const TilingRenderer: React.ForwardRefExoticComponent<TilingRendererProps & React.RefAttributes<TilingCommandHandle>>;
|
|
2176
|
+
/**
|
|
2177
|
+
* The observability-instrumented view of {@link TilingRenderer}: the SAME
|
|
2178
|
+
* component, typed to also accept {@link TilingRendererObservabilityProps} (the
|
|
2179
|
+
* drag/drop observability overlays, hit-zone visualizations, and telemetry
|
|
2180
|
+
* feeds). Exported through `@n-uf/hypr-tiling/devtools` for the observability
|
|
2181
|
+
* panel; consumers use the clean `.` renderer instead.
|
|
2182
|
+
*/
|
|
2183
|
+
declare const TilingRendererWithObservability: React.ForwardRefExoticComponent<TilingRendererProps & TilingRendererObservabilityProps & React.RefAttributes<TilingCommandHandle>>;
|
|
2184
|
+
|
|
2185
|
+
export { type ResolvedTilingSlotCommitmentCapability as $, type TilingPaneSizingMode as A, BASELINE_DRAG_HOP_DURATION_MS as B, type TilingAccentHue as C, type TilingKeyboardAction as D, type TilingKeyboardModifierState as E, type TilingMoveModeState as F, type TilingPaneSwitcherState as G, accentHue as H, INSTANT_DRAG_DURATION_MS as I, type TilingRenderTileProps as J, DEFAULT_DRAG_ANIMATION_SPEED_PERCENT as K, DEFAULT_TILE_ACCENT as L, DEFAULT_TILING_LAYOUT_CONFIG as M, DEFAULT_TILING_THEME_ID as N, DRAG_ANIMATION_SPEED_MAX_PERCENT as O, DRAG_ANIMATION_SPEED_MIN_PERCENT as P, type ResolvedTilingDragRecoveryCapability as Q, type ResolvedTilingInteractionCapabilities as R, type ResolvedTilingDropHitZoneGeometryCapability as S, type TilingLayoutNode as T, type ResolvedTilingGroupingCapability as U, type ResolvedTilingKeyBindings as V, type ResolvedTilingKeyChord as W, type ResolvedTilingKeyChordModifiers as X, type ResolvedTilingMaximizeCapability as Y, type ResolvedTilingPaneSwitchingCapability as Z, type ResolvedTilingPaneTitleBarControlsCapability as _, type TilingLayoutConfig as a, type ResolvedTilingTouchDragCapability as a0, TILING_ACCENT_HUES as a1, TILING_THEMES as a2, TILING_THEME_REGISTRY as a3, TILING_TILE_ACCENTS as a4, TILING_TILE_ACCENT_SWATCHES as a5, type TilingCommandHandle as a6, type TilingDragMode as a7, type TilingDragRecoveryCapability as a8, type TilingDropHitZoneGeometryCapability as a9, type TilingSlotCommitmentMode as aA, type TilingTheme as aB, type TilingThemeDividerTokens as aC, type TilingThemeGhostTokens as aD, type TilingThemeId as aE, type TilingThemePaneHeaderTokens as aF, type TilingThemePaneShellTokens as aG, TilingThemeProvider as aH, type TilingThemeRootTokens as aI, type TilingThemeTopBarTokens as aJ, type TilingTile as aK, type TilingTileAccent as aL, type TilingTileAccentSwatch as aM, type TilingTitleBarSizingMode as aN, type TilingTouchDragCapability as aO, resolveTilingTheme as aP, useTilingTheme as aQ, type TilingInsertionOptions as aR, type TilingGroupMemberView as aa, type TilingGroupNode as ab, type TilingGroupingCapability as ac, type TilingInteractionCapabilities as ad, type TilingKeyBindings as ae, type TilingKeyChord as af, type TilingKeyChordModifiers as ag, type TilingKeymap as ah, type TilingLayoutMode as ai, type TilingLeafDropPreview as aj, type TilingLeafNode as ak, type TilingLeafPreviewMode as al, type TilingLeafPreviewRole as am, type TilingMasterOrientation as an, type TilingMaximizeCapability as ao, type TilingMovePlacement as ap, type TilingPaneBodyRenderMode as aq, type TilingPaneCycleDirection as ar, type TilingPaneSwitchingCapability as as, type TilingPaneTitleBarControlsCapability as at, type TilingRenderSurface as au, type TilingRenderTileGroupContext as av, TilingRenderer as aw, type TilingRendererProps as ax, type TilingResizeCapability as ay, type TilingSlotCommitmentCapability as az, type TilingObservabilityColorConfig as b, type TilingObservabilityColorEnableConfig as c, type TilingDropIntentDebugState as d, type TilingLiveHitLogState as e, type TilingSplitNode as f, type TilingFocusDirection as g, TILING_OBSERVABILITY_COLOR_DEFAULTS as h, TILING_OBSERVABILITY_COLOR_ENABLE_DEFAULTS as i, type TilingDropIntentTuningState as j, type TilingLiveHitEdgeDebugState as k, type TilingPaneFootprint as l, type TilingPaneHitZoneCandidateDebugState as m, type TilingPaneHitZoneOverlayDebugState as n, TilingRendererWithObservability as o, type TilingRendererObservabilityProps as p, type TilingViewportCursorState as q, type TilingLeafDropZone as r, type TilingDropAction as s, type TilingSplitAxis as t, type ResolvedTilingKeymap as u, type TilingKeyBinding as v, type TilingKeyboardEventLike as w, type TilingCommand as x, type TilingDimension as y, type TilingPaneSizing as z };
|