@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.
@@ -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 };