@dashfoo/react 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,24 +59,27 @@ a sized parent and add your CSS (see the [attribute reference](#data-dashfoo-att
59
59
 
60
60
  ## `DashfooLayout` props
61
61
 
62
- | Prop | Type | Default | Description |
63
- | ------------------------- | -------------------------------------------------- | ------- | -------------------------------------------------------------------------------------- |
64
- | `model` | `Dashfoo` | — | Controlled document. When set, the prop is the source of truth. |
65
- | `defaultModel` | `Dashfoo` | — | Uncontrolled initial document. The component owns it from there. |
66
- | `onModelChange` | `(model: Dashfoo, action?: Action) => void` | — | Called after every change with the next model and the action that caused it. |
67
- | `components` | `Record<string, ComponentType<{ node: TabNode }>>` | — | Registry mapping `tab.component` keys to components. |
68
- | `factory` | `(tab: TabNode) => ReactNode` | — | Render override. When provided, it resolves every tab and `components` is ignored. |
69
- | `persist` | `string \| { key; storage?; debounceMs? }` | — | Auto-save the model (uncontrolled mode only). A bare string is a localStorage key. |
70
- | `onAction` | `(action: Action) => Action \| null` | — | Intercept each action before it commits — return it, a replacement, or `null` to veto. |
71
- | `onActiveTabsetChange` | `(id: string \| undefined) => void` | — | Fires when the active tabset changes. |
72
- | `onMaximizedTabsetChange` | `(id: string \| undefined) => void` | — | Fires when a tabset is maximized or restored. |
73
- | `renderTabLabel` | `(tab: TabNode) => ReactNode` | — | Override the tab label (the accessible name stays `tab.name`). |
74
- | `renderTabsetToolbar` | `(tabset: TabsetNode) => ReactNode` | — | Inject custom controls into a tabset's toolbar. |
75
- | `closableTabs` | `boolean` | `true` | Show the per-tab close control. |
76
- | `renamableTabs` | `boolean` | `true` | Allow double-click inline rename. |
77
- | `maximizable` | `boolean` | `true` | Show the tabset maximize/restore control. |
78
- | `draggableTabsets` | `boolean` | `true` | Show the grip that drags a whole tabset. |
79
- | `keepMounted` | `boolean` | `false` | Keep inactive tab panels mounted (hidden) so their state survives a tab switch. |
62
+ | Prop | Type | Default | Description |
63
+ | ------------------------- | -------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
64
+ | `model` | `Dashfoo` | — | Controlled document. When set, the prop is the source of truth. |
65
+ | `defaultModel` | `Dashfoo` | — | Uncontrolled initial document. The component owns it from there. |
66
+ | `onModelChange` | `(model: Dashfoo, action?: Action) => void` | — | Called after every change with the next model and the action that caused it. |
67
+ | `components` | `Record<string, ComponentType<{ node: TabNode }>>` | — | Registry mapping `tab.component` keys to components. |
68
+ | `factory` | `(tab: TabNode) => ReactNode` | — | Render override. When provided, it resolves every tab and `components` is ignored. |
69
+ | `persist` | `string \| { key; storage?; debounceMs? }` | — | Auto-save the model (uncontrolled mode only). A bare string is a localStorage key. |
70
+ | `onAction` | `(action: Action) => Action \| null` | — | Intercept each action before it commits — return it, a replacement, or `null` to veto. |
71
+ | `onActiveTabsetChange` | `(id: string \| undefined) => void` | — | Fires when the active tabset changes. |
72
+ | `onMaximizedTabsetChange` | `(id: string \| undefined) => void` | — | Fires when a tabset is maximized or restored. |
73
+ | `renderTabLabel` | `(tab: TabNode) => ReactNode` | — | Override the tab label (the accessible name stays `tab.name`). |
74
+ | `renderTabsetToolbar` | `(tabset: TabsetNode) => ReactNode` | — | Inject custom controls into a tabset's toolbar. |
75
+ | `editable` | `boolean` | `true` | `false` renders a static layout: no drag, close, rename, or splitter resize. Tab selection, maximize, and the ref API keep working. |
76
+ | `closableTabs` | `boolean` | `true` | Show the per-tab close control. |
77
+ | `renamableTabs` | `boolean` | `true` | Allow double-click inline rename. |
78
+ | `maximizable` | `boolean` | `true` | Show the tabset maximize/restore control. |
79
+ | `draggableTabs` | `boolean` | `true` | Allow individual tabs to be dragged between tabsets. |
80
+ | `draggableTabsets` | `boolean` | `true` | Show the grip that drags a whole tabset. |
81
+ | `resizableSplits` | `boolean` | `true` | Allow dragging the splitters; `false` disables them in place (gutters keep their size). |
82
+ | `keepMounted` | `boolean` | `false` | Keep inactive tab panels mounted (hidden) so their state survives a tab switch. |
80
83
 
81
84
  You must pass either `model` or `defaultModel`. Passing neither throws.
82
85
 
@@ -175,19 +178,22 @@ with the right role and ARIA wiring, ready for you to style.
175
178
 
176
179
  ### Per-node enable flags
177
180
 
178
- The three top-level chrome props are global gates. Individual nodes can opt out
181
+ The top-level chrome props are layout-wide gates. Individual nodes can opt out
179
182
  through optional boolean fields in the model (a flag defaults to enabled unless
180
- explicitly `false`). A control shows only when both the global prop and the
181
- node's flag allow it.
182
-
183
- | Field | On node | Disables |
184
- | ----------------- | ------- | ------------------------------------------------ |
185
- | `enableClose` | tab | the close control for that tab |
186
- | `enableClose` | tabset | closing for every tab in the tabset |
187
- | `enableRename` | tab | double-click rename for that tab |
188
- | `enableDrag` | tab | dragging that tab |
189
- | `enableMaximize` | tabset | the maximize control for that tabset |
190
- | `enableSplitDock` | global | splitting a tabset on drop (drops stack instead) |
183
+ explicitly `false`). A control shows only when the `editable` umbrella, the
184
+ chrome prop, the model global, and the node's flag all allow it (`maximizable`
185
+ ignores `editable` — maximize is view state, not a structural edit).
186
+
187
+ | Field | On node | Disables |
188
+ | ------------------- | ------- | ------------------------------------------------ |
189
+ | `enableClose` | tab | the close control for that tab |
190
+ | `enableClose` | tabset | closing for every tab in the tabset |
191
+ | `enableRename` | tab | double-click rename for that tab |
192
+ | `enableDrag` | tab | dragging that tab |
193
+ | `enableMaximize` | tabset | the maximize control for that tabset |
194
+ | `tabEnableDrag` | global | tree-wide default behind `tab.enableDrag` |
195
+ | `enableSplitDock` | global | splitting a tabset on drop (drops stack instead) |
196
+ | `enableSplitResize` | global | dragging the splitters (gutters keep their size) |
191
197
 
192
198
  ```ts
193
199
  { id: "logs", type: "tab", name: "Logs", component: "logs", enableClose: false }
@@ -200,6 +206,50 @@ Rows and tabsets can carry `min` and `max` dimensions from `@dashfoo/core`.
200
206
  tabset has no node-level `min`, it uses `global.tabSetMinSize`; when that global
201
207
  is omitted, the React adapter falls back to `320px`.
202
208
 
209
+ ## External drag sources
210
+
211
+ Tabs normally move within a layout. To drag new content in from outside it — a
212
+ widget list, a palette, a marketplace — wrap both sides in `DashfooDragProvider`
213
+ and register each source with `useExternalTabSource`. Dropping a source on the
214
+ layout inserts the tab it creates (stacking on a strip or body, splitting on an
215
+ edge), exactly like an internal tab drop. A drop outside any tabset is a no-op.
216
+
217
+ ```tsx
218
+ import { createTabId, tab } from "@dashfoo/core";
219
+ import { DashfooDragProvider, DashfooLayout, useExternalTabSource } from "@dashfoo/react";
220
+
221
+ const WidgetCard = ({ component, name }: { component: string; name: string }) => {
222
+ const { ref } = useExternalTabSource({
223
+ createTab: () => tab(component, name, { id: createTabId() }),
224
+ label: name,
225
+ });
226
+ return <div ref={ref}>{name}</div>;
227
+ };
228
+
229
+ const App = () => (
230
+ <DashfooDragProvider>
231
+ <WidgetCard component="metrics" name="Metrics" />
232
+ <DashfooLayout defaultModel={model} components={registry} />
233
+ </DashfooDragProvider>
234
+ );
235
+ ```
236
+
237
+ `createTab` runs at drag start and must return a fresh `TabNode` with a unique
238
+ id per call (`createNodeId` / `createTabId` from `@dashfoo/core` mint one). The
239
+ returned node is validated against the model schema; an invalid tab warns and
240
+ cancels the drag. `DashfooDragProvider` is optional everywhere else — a
241
+ standalone layout needs no provider. Pointer drag is the only drag input, so
242
+ offer a click-to-add path (e.g. `ref.addTab(...)`) alongside the drag for
243
+ keyboard access.
244
+
245
+ `useExternalTabSource` options:
246
+
247
+ | Option | Type | Default | Description |
248
+ | ----------- | --------------- | ------------ | ------------------------------------------ |
249
+ | `createTab` | `() => TabNode` | — (required) | Builds the tab to insert; called per drag. |
250
+ | `label` | `string` | `""` | The drag preview chip text. |
251
+ | `disabled` | `boolean` | `false` | Unregisters the source while true. |
252
+
203
253
  ## Persistence
204
254
 
205
255
  The `persist` prop saves an uncontrolled layout and restores it on load. It loads
@@ -228,8 +278,10 @@ const Layout = () => {
228
278
 
229
279
  `persist` accepts a bare localStorage key or `{ key, storage?, debounceMs? }` for
230
280
  a custom store (sessionStorage, in-memory, your own). A pending save flushes on
231
- unmount, so the last change is never lost. It applies to uncontrolled mode only;
232
- in controlled mode, save the model yourself in `onModelChange`.
281
+ unmount and on page hide (reload, tab close, navigation, the page going to the
282
+ background), so the last change is never lost — even inside the debounce window.
283
+ It applies to uncontrolled mode only; in controlled mode, save the model yourself
284
+ in `onModelChange`.
233
285
 
234
286
  The lower-level `usePersistence` load/save primitive (that `persist` is built on)
235
287
  is also exported, for hosts that drive the store directly. See the
@@ -299,7 +351,7 @@ you.
299
351
  | `tabset-grip` | `button` | Drags the whole tabset. `aria-label="Move tabset"`; shown when `draggableTabsets` is on and the tabset is not maximized. |
300
352
  | `tabset-maximize` | `button` | Maximize/restore toggle. `aria-pressed` reflects state. |
301
353
  | `tabcontent` | `div` | `role="tabpanel"`, the active tab's content (or empty when none). |
302
- | `dock-indicator` | `div` | The drag preview overlay (insertion line or zone). `pointer-events: none`. |
354
+ | `dock-indicator` | `div` | The drag preview overlay (insertion line or zone pane). `pointer-events: none`. |
303
355
  | `drag-preview` | `div` | The chip that follows the pointer during a drag, showing the dragged label. |
304
356
  | `separator` | rrp `Separator` | rrp emits `data-separator` with `aria-orientation`; style splitters here. |
305
357
 
@@ -314,15 +366,14 @@ The `[data-dashfoo="dock-indicator"]` overlay positions itself inline, but every
314
366
  visual property reads from a CSS variable with a neutral fallback. Override them
315
367
  to theme the drag preview without touching layout.
316
368
 
317
- | Variable | Used for | Fallback |
318
- | ----------------------------- | ---------------------------- | ---------------------------------------------- |
319
- | `--dashfoo-dock-fill` | zone fill (split preview) | `oklch(0.556 0 0 / 0.18)` |
320
- | `--dashfoo-dock-border` | zone border color | `oklch(0.708 0 0 / 0.75)` |
321
- | `--dashfoo-dock-border-width` | zone border width | `1px` |
322
- | `--dashfoo-dock-radius` | zone corner radius | `6px` |
323
- | `--dashfoo-dock-line` | tab insertion line color | `oklch(0.556 0 0)` |
324
- | `--dashfoo-dock-line-radius` | insertion line corner radius | `2px` |
325
- | `--dashfoo-dock-transition` | indicator move animation | `left 60ms, top 60ms, width 60ms, height 60ms` |
369
+ | Variable | Used for | Fallback |
370
+ | ----------------------------- | ------------------------ | ---------------------------------------------- |
371
+ | `--dashfoo-dock-fill` | indicator fill | `oklch(0.556 0 0 / 0.18)` |
372
+ | `--dashfoo-dock-border` | indicator border color | `oklch(0.708 0 0 / 0.75)` |
373
+ | `--dashfoo-dock-border-width` | indicator border width | `1px` |
374
+ | `--dashfoo-dock-radius` | indicator corner radius | `6px` |
375
+ | `--dashfoo-dock-line-radius` | insertion-line radius | `2px` |
376
+ | `--dashfoo-dock-transition` | indicator move animation | `left 60ms, top 60ms, width 60ms, height 60ms` |
326
377
 
327
378
  Set `--dashfoo-dock-transition: none` to disable the indicator animation.
328
379
 
@@ -330,7 +381,6 @@ Set `--dashfoo-dock-transition: none` to disable the indicator animation.
330
381
  :root {
331
382
  --dashfoo-dock-fill: rgba(255, 255, 255, 0.1);
332
383
  --dashfoo-dock-border: rgba(255, 255, 255, 0.4);
333
- --dashfoo-dock-line: rgba(255, 255, 255, 0.85);
334
384
  }
335
385
  ```
336
386
 
@@ -348,8 +398,106 @@ It binds an XState actor to React, normalizes the incoming model, and exposes
348
398
  `dispatch` plus undo/redo. Uncontrolled mode gives full history; controlled mode
349
399
  routes changes through `onModelChange` and keeps the actor in sync.
350
400
 
351
- `useDashfooContext` returns the live context (`dispatch`, `renderTab`, the chrome
352
- flags) and throws outside a `<DashfooLayout>`. Use it from a custom view.
401
+ Three selector hooks read the scoped stores the primitives coordinate through.
402
+ Each takes a selector and re-renders only when the selected slice changes:
403
+
404
+ ```ts
405
+ const dispatch = useLayout((state) => state.dispatch); // layout-wide config + dispatch; throws outside <DashfooLayout>/<Layout.Root>
406
+ const node = useTabset((state) => state.node); // per-tabset state; throws outside <Tabset.Root>
407
+ const { index, tab } = useTab(); // which tab a part belongs to; throws outside <Tabset.Tab>
408
+ ```
409
+
410
+ `useDragSubject()` returns the live drag subject (`{ kind, id }` for a tab or
411
+ tabset being dragged) or `null` — including outside a drag layer — for
412
+ drag-aware styling in custom parts.
413
+
414
+ `useDropIntent()` returns the live drop intent (`{ targetId, location, index? }`
415
+ — where the drag would land if dropped right now) or `null` when nothing is
416
+ dragging or the pointer is over no valid target (empty space, a non-editable
417
+ layout, or a no-op drop the library suppresses). Together with
418
+ `dockZonePolygons` from `@dashfoo/core` it supports consumer-rendered drop
419
+ indicators and drop-zone visualizations alongside the built-in indicator. Both
420
+ hooks work anywhere under a layout; under a `DashfooDragProvider` they work
421
+ anywhere under the provider (the provider hosts the drag store, so widget lists
422
+ and overlays outside the layout observe the same drag).
423
+
424
+ ## Build your own layout
425
+
426
+ `DashfooLayout` is a thin assembly of exported primitives — you can compose the
427
+ same parts yourself when you need custom chrome. Two compound namespaces, same
428
+ pattern as `Panel`:
429
+
430
+ | Part | Element | Role |
431
+ | ----------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
432
+ | `Layout.Root` | `div[data-dashfoo="layout"]` | Creates the layout store. Takes `model`, `dispatch`, `renderTab`, and the chrome flags `DashfooLayout` accepts. |
433
+ | `Layout.DragLayer` | none (overlays) | Opts the tree into drag-dock. Omit it and everything else still works, just without dragging. |
434
+ | `Layout.Rows` | rrp split tree | Renders a `RowNode` recursively. `renderTabset` swaps in a custom tabset composition at every leaf. |
435
+ | `Layout.Tabset` | — | The stock tabset composition, for leaves that don't need custom chrome. |
436
+ | `Tabset.Root` | `div[data-dashfoo="tabset"]` | Creates the per-tabset store; owns drop registration, overflow measurement, and focus restore after close. |
437
+ | `Tabset.TabStrip` | `div[data-dashfoo="tabstrip"]` | The strip row (drag hit-testing targets this attribute). |
438
+ | `Tabset.Tablist` | `div[data-dashfoo="tablist"]` | `role="tablist"` + roving-tabindex arrow/Home/End navigation. |
439
+ | `Tabset.Tab` | `span[data-dashfoo="tab-item"]` | Per-tab wrapper; provides identity to the parts inside. |
440
+ | `Tabset.Trigger` | `button[data-dashfoo="tab"]` | The tab button: select on click, rename on double-click, draggable. Children override the label. |
441
+ | `Tabset.RenameInput` | `input[data-dashfoo="tab-rename"]` | Inline rename editor; renders only while its tab is being renamed. |
442
+ | `Tabset.CloseButton` | `button[data-dashfoo="tab-close"]` | Closes the tab with focus restore; hides when the tab isn't closable. |
443
+ | `Tabset.Content` | `div[data-dashfoo="tabcontent"]` | The `role="tabpanel"` pane(s); honors `keepMounted`. Children render-prop overrides `renderTab`. |
444
+ | `Tabset.Toolbar` | `div[data-dashfoo="tabset-toolbar"]` | Trailing toolbar container. |
445
+ | `Tabset.OverflowMenu` | menu button | Lists clipped tabs; hides when nothing overflows. |
446
+ | `Tabset.Grip` | `button[data-dashfoo="tabset-grip"]` | Drag handle for the whole tabset; hides when tabset dragging is off. |
447
+ | `Tabset.MaximizeButton` | `button[data-dashfoo="tabset-maximize"]` | Maximize/restore toggle; hides when maximize is off. |
448
+
449
+ All parts spread native props (`className`, `style`, handlers) like `Panel`;
450
+ the structural attributes (`role`, ids, `data-dashfoo`) are applied after the
451
+ spread because drag hit-testing and overflow measurement query them.
452
+
453
+ ```tsx
454
+ import { Layout, Tabset, useDashfooStore, useTab } from "@dashfoo/react";
455
+
456
+ const MyTabset = ({ node }: { node: TabsetNode }) => (
457
+ <Tabset.Root node={node}>
458
+ <Tabset.TabStrip>
459
+ <Tabset.Tablist>
460
+ {node.children.map((tab) => (
461
+ <Tabset.Tab key={tab.id} tab={tab}>
462
+ <Tabset.Trigger>
463
+ <MyLabel /> {/* reads useTab()/useTabset() */}
464
+ </Tabset.Trigger>
465
+ <Tabset.RenameInput />
466
+ <Tabset.CloseButton />
467
+ </Tabset.Tab>
468
+ ))}
469
+ </Tabset.Tablist>
470
+ <Tabset.Toolbar>
471
+ <Tabset.OverflowMenu />
472
+ <Tabset.MaximizeButton />
473
+ <Tabset.Grip />
474
+ </Tabset.Toolbar>
475
+ </Tabset.TabStrip>
476
+ <Tabset.Content />
477
+ </Tabset.Root>
478
+ );
479
+
480
+ const MyLayout = () => {
481
+ const store = useDashfooStore({ defaultModel });
482
+ return (
483
+ <Layout.Root dispatch={store.dispatch} model={store.model} renderTab={renderTab}>
484
+ <Layout.DragLayer>
485
+ <Layout.Rows node={store.model.layout} renderTabset={(node) => <MyTabset node={node} />} />
486
+ </Layout.DragLayer>
487
+ </Layout.Root>
488
+ );
489
+ };
490
+ ```
491
+
492
+ Maximize is the host's concern in a hand-built layout: when
493
+ `model.maximizedTabsetId` is set, render that tabset alone (via `findTabset`
494
+ from `@dashfoo/core`) instead of `Layout.Rows` — that's all `DashfooLayout`
495
+ does. The demo's "Raw primitives" page (`apps/demo-vite/src/pages/raw.tsx`) is
496
+ a complete working reference.
497
+
498
+ Misuse is never silent: parts outside their provider throw, and soft mistakes
499
+ (two `Tablist`s, a `Tab` whose node isn't in the tabset, renaming without a
500
+ `RenameInput`) warn with `[dashfoo]` and degrade gracefully.
353
501
 
354
502
  ## Exports
355
503
 
@@ -371,15 +519,34 @@ type PanelIconProps;
371
519
  type PanelRootProps;
372
520
  type PanelTitleProps;
373
521
 
374
- // Store
522
+ // Layout primitives (build your own layout)
523
+ Layout; // Layout.Root / Layout.DragLayer / Layout.Rows / Layout.Tabset
524
+ type LayoutRootProps;
525
+ type LayoutDragLayerProps;
526
+ type LayoutRowsProps;
527
+ type LayoutTabsetProps;
528
+
529
+ // Tabset primitives
530
+ Tabset; // Tabset.Root / .TabStrip / .Tablist / .Tab / .Trigger / .RenameInput / .CloseButton / .Content / .Toolbar / .OverflowMenu / .Grip / .MaximizeButton
531
+ type TabsetRootProps; // …and a Props type per part
532
+
533
+ // Store + selector hooks
375
534
  useDashfooStore;
376
535
  type DashfooStore;
377
536
  type UseDashfooStoreOptions;
378
-
379
- // Context
380
- DashfooContext;
381
- useDashfooContext;
382
- type DashfooContextValue;
537
+ useLayout; // select from the layout store (throws outside Layout.Root/DashfooLayout)
538
+ type LayoutState;
539
+ useTabset; // select from the enclosing tabset store (throws outside Tabset.Root)
540
+ type TabsetState;
541
+ useTab; // { tab, index } identity (throws outside Tabset.Tab)
542
+ type TabContextValue;
543
+ useDragSubject; // the live drag subject, or null
544
+ useDropIntent; // where the drag would land if dropped right now, or null
545
+
546
+ // External drag sources
547
+ DashfooDragProvider; // shares one drag manager + drag store between a layout and outside sources
548
+ useExternalTabSource;
549
+ type ExternalTabSourceOptions;
383
550
 
384
551
  // Persistence
385
552
  usePersistence; // load/save primitive (the `persist` prop builds on this)
package/dist/index.d.ts CHANGED
@@ -1,25 +1,6 @@
1
+ import { Action, Dashfoo, DockLocation, DragSubject, DropIntent, RowNode, TabNode, TabsetNode } from "@dashfoo/core";
1
2
  import { ComponentProps, ComponentType, ReactNode } from "react";
2
- import { Action, Dashfoo, DockLocation, TabNode, TabsetNode } from "@dashfoo/core";
3
-
4
- //#region src/hooks/context.d.ts
5
- type DashfooContextValue = {
6
- closableTabs: boolean;
7
- dispatch: (action: Action) => void;
8
- draggableTabsets: boolean;
9
- keepMounted: boolean;
10
- maximizable: boolean;
11
- maximizedTabsetId?: string;
12
- renamableTabs: boolean;
13
- renderTab: (tab: TabNode) => ReactNode;
14
- renderTabLabel?: (tab: TabNode) => ReactNode;
15
- renderTabsetToolbar?: (tabset: TabsetNode) => ReactNode;
16
- tabLocation: "bottom" | "top";
17
- tabsetMinSize: number;
18
- tabStripEnabled: boolean;
19
- };
20
- declare const DashfooContext: import("react").Context<DashfooContextValue | null>;
21
- declare const useDashfooContext: () => DashfooContextValue;
22
- //#endregion
3
+ import { DragDropManager } from "@dnd-kit/dom";
23
4
  //#region src/hooks/persistence.d.ts
24
5
  type StorageAdapter = {
25
6
  getItem: (key: string) => string | null;
@@ -71,7 +52,9 @@ type DashfooLayoutProps = {
71
52
  closableTabs?: boolean;
72
53
  components?: Record<string, TabComponent>;
73
54
  defaultModel?: Dashfoo;
55
+ draggableTabs?: boolean;
74
56
  draggableTabsets?: boolean;
57
+ editable?: boolean;
75
58
  factory?: (tab: TabNode) => ReactNode;
76
59
  keepMounted?: boolean;
77
60
  maximizable?: boolean;
@@ -84,9 +67,103 @@ type DashfooLayoutProps = {
84
67
  renamableTabs?: boolean;
85
68
  renderTabLabel?: (tab: TabNode) => ReactNode;
86
69
  renderTabsetToolbar?: (tabset: TabsetNode) => ReactNode;
70
+ resizableSplits?: boolean;
87
71
  };
88
72
  declare const DashfooLayout: import("react").ForwardRefExoticComponent<DashfooLayoutProps & import("react").RefAttributes<DashfooHandle>>;
89
73
  //#endregion
74
+ //#region src/components/drag-root.d.ts
75
+ declare const DashfooDragProvider: ({
76
+ children
77
+ }: {
78
+ children: ReactNode;
79
+ }) => ReactNode;
80
+ //#endregion
81
+ //#region src/hooks/drag-hooks.d.ts
82
+ type ExternalTabSourceOptions = {
83
+ createTab: () => TabNode;
84
+ disabled?: boolean;
85
+ label?: string;
86
+ };
87
+ declare const useExternalTabSource: ({
88
+ createTab,
89
+ disabled,
90
+ label
91
+ }: ExternalTabSourceOptions) => {
92
+ ref: (element: Element | null) => void;
93
+ };
94
+ declare const useDragSubject: () => DragSubject | null;
95
+ declare const useDropIntent: () => DropIntent | null;
96
+ //#endregion
97
+ //#region src/components/drag-adapter.d.ts
98
+ type DragProviderProps = {
99
+ children: ReactNode;
100
+ onCommit?: (action: Action) => void;
101
+ splitDock?: boolean;
102
+ };
103
+ //#endregion
104
+ //#region src/components/layout-root.d.ts
105
+ type LayoutRootProps = Omit<ComponentProps<"div">, "children"> & {
106
+ children: ReactNode;
107
+ closableTabs?: boolean;
108
+ dispatch: (action: Action) => void;
109
+ draggableTabs?: boolean;
110
+ draggableTabsets?: boolean;
111
+ editable?: boolean;
112
+ keepMounted?: boolean;
113
+ maximizable?: boolean;
114
+ model: Dashfoo;
115
+ renamableTabs?: boolean;
116
+ renderTab: (tab: TabNode) => ReactNode;
117
+ renderTabLabel?: (tab: TabNode) => ReactNode;
118
+ renderTabsetToolbar?: (tabset: TabsetNode) => ReactNode;
119
+ resizableSplits?: boolean;
120
+ };
121
+ //#endregion
122
+ //#region src/components/row-view.d.ts
123
+ type RowViewProps = {
124
+ node: RowNode;
125
+ renderTabset?: (node: TabsetNode) => ReactNode;
126
+ };
127
+ //#endregion
128
+ //#region src/components/tabset/tabset-view.d.ts
129
+ type TabsetViewProps = {
130
+ node: TabsetNode;
131
+ };
132
+ //#endregion
133
+ //#region src/components/layout.d.ts
134
+ declare const Layout: {
135
+ readonly DragLayer: ({
136
+ children,
137
+ onCommit,
138
+ splitDock
139
+ }: DragProviderProps) => import("react").ReactNode;
140
+ readonly Root: ({
141
+ children,
142
+ closableTabs,
143
+ dispatch,
144
+ draggableTabs,
145
+ draggableTabsets,
146
+ editable,
147
+ keepMounted,
148
+ maximizable,
149
+ model,
150
+ renamableTabs,
151
+ renderTab,
152
+ renderTabLabel,
153
+ renderTabsetToolbar,
154
+ resizableSplits,
155
+ style,
156
+ ...props
157
+ }: LayoutRootProps) => import("react").ReactNode;
158
+ readonly Rows: ({
159
+ node,
160
+ renderTabset
161
+ }: RowViewProps) => import("react").ReactNode;
162
+ readonly Tabset: ({
163
+ node
164
+ }: TabsetViewProps) => import("react").ReactNode;
165
+ };
166
+ //#endregion
90
167
  //#region src/components/panel.d.ts
91
168
  type PanelRootProps = ComponentProps<"div">;
92
169
  type PanelHeaderProps = ComponentProps<"div">;
@@ -103,6 +180,158 @@ declare const Panel: {
103
180
  readonly Title: (props: PanelTitleProps) => ReactNode;
104
181
  };
105
182
  //#endregion
183
+ //#region src/components/tabset/tabset-tab-controls.d.ts
184
+ type TabsetRenameInputProps = ComponentProps<"input">;
185
+ type TabsetCloseButtonProps = ComponentProps<"button">;
186
+ //#endregion
187
+ //#region src/components/tabset/tabset-content.d.ts
188
+ type TabsetContentProps = Omit<ComponentProps<"div">, "children"> & {
189
+ children?: (tab: TabNode) => ReactNode;
190
+ };
191
+ //#endregion
192
+ //#region src/components/tabset/tabset-toolbar.d.ts
193
+ type TabsetToolbarProps = ComponentProps<"div">;
194
+ type TabsetGripProps = ComponentProps<"button">;
195
+ type TabsetMaximizeButtonProps = ComponentProps<"button">;
196
+ //#endregion
197
+ //#region src/components/tabset/tabset-root.d.ts
198
+ type TabsetRootProps = ComponentProps<"div"> & {
199
+ node: TabsetNode;
200
+ };
201
+ //#endregion
202
+ //#region src/components/tabset/tabset-tab.d.ts
203
+ type TabsetTabProps = ComponentProps<"span"> & {
204
+ tab: TabNode;
205
+ };
206
+ type TabsetTriggerProps = ComponentProps<"button">;
207
+ //#endregion
208
+ //#region src/components/tabset/tabset-tablist.d.ts
209
+ type TabsetTabStripProps = ComponentProps<"div">;
210
+ type TabsetTablistProps = ComponentProps<"div">;
211
+ //#endregion
212
+ //#region src/components/tabset/tabset.d.ts
213
+ declare const Tabset: {
214
+ readonly CloseButton: ({
215
+ children,
216
+ onClick,
217
+ ...props
218
+ }: TabsetCloseButtonProps) => import("react").ReactNode;
219
+ readonly Content: ({
220
+ children,
221
+ style,
222
+ ...props
223
+ }: TabsetContentProps) => import("react").ReactNode;
224
+ readonly Grip: ({
225
+ children,
226
+ ref: userRef,
227
+ ...props
228
+ }: TabsetGripProps) => import("react").ReactNode;
229
+ readonly MaximizeButton: ({
230
+ children,
231
+ onClick,
232
+ ...props
233
+ }: TabsetMaximizeButtonProps) => import("react").ReactNode;
234
+ readonly OverflowMenu: () => import("react").ReactNode;
235
+ readonly RenameInput: (props: TabsetRenameInputProps) => import("react").ReactNode;
236
+ readonly Root: ({
237
+ children,
238
+ node,
239
+ ref: userRef,
240
+ style,
241
+ ...props
242
+ }: TabsetRootProps) => import("react").ReactNode;
243
+ readonly Tab: ({
244
+ children,
245
+ ref: userRef,
246
+ tab,
247
+ ...props
248
+ }: TabsetTabProps) => import("react").ReactNode;
249
+ readonly Tablist: ({
250
+ onKeyDown,
251
+ ref: userRef,
252
+ style,
253
+ ...props
254
+ }: TabsetTablistProps) => import("react").ReactNode;
255
+ readonly TabStrip: ({
256
+ style,
257
+ ...props
258
+ }: TabsetTabStripProps) => import("react").ReactNode;
259
+ readonly Toolbar: ({
260
+ style,
261
+ ...props
262
+ }: TabsetToolbarProps) => import("react").ReactNode;
263
+ readonly Trigger: ({
264
+ children,
265
+ onClick,
266
+ onDoubleClick,
267
+ ref: userRef,
268
+ ...props
269
+ }: TabsetTriggerProps) => import("react").ReactNode;
270
+ };
271
+ //#endregion
272
+ //#region src/components/tab-overflow.d.ts
273
+ type OverflowItem = {
274
+ id: string;
275
+ name: string;
276
+ };
277
+ //#endregion
278
+ //#region src/components/tabset/tabset-store.d.ts
279
+ type TabsetState = {
280
+ activeTab: TabNode | undefined;
281
+ cancelRename: () => void;
282
+ closeTab: (tabId: string) => void;
283
+ commitRename: (tabId: string, value: string) => void;
284
+ dispatch: (action: Action) => void;
285
+ editingTabId: string | null;
286
+ isMaximized: boolean;
287
+ node: TabsetNode;
288
+ overflowItems: Array<OverflowItem>;
289
+ registerRenameInput: () => () => void;
290
+ registerTablist: (element: HTMLDivElement | null) => void;
291
+ renameInputCount: number;
292
+ renameTab: (tabId: string, name: string) => void;
293
+ restoreFocus: boolean;
294
+ selectOverflowTab: (tabId: string) => void;
295
+ selectTab: (index: number, options?: {
296
+ focus?: boolean;
297
+ }) => void;
298
+ showMaximize: boolean;
299
+ startEditing: (tabId: string) => void;
300
+ tablistElement: HTMLDivElement | null;
301
+ tabsClosable: boolean;
302
+ tabsRenamable: boolean;
303
+ toggleMaximize: () => void;
304
+ visualSelected: number;
305
+ };
306
+ declare const useTabset: <T>(selector: (state: TabsetState) => T) => T;
307
+ type TabContextValue = {
308
+ index: number;
309
+ tab: TabNode;
310
+ };
311
+ declare const useTab: () => TabContextValue;
312
+ //#endregion
313
+ //#region src/hooks/layout-store.d.ts
314
+ type LayoutState = {
315
+ closableTabs: boolean;
316
+ dispatch: (action: Action) => void;
317
+ draggableTabs: boolean;
318
+ draggableTabsets: boolean;
319
+ editable: boolean;
320
+ keepMounted: boolean;
321
+ maximizable: boolean;
322
+ maximizedTabsetId: string | undefined;
323
+ renamableTabs: boolean;
324
+ renderTab: (tab: TabNode) => ReactNode;
325
+ renderTabLabel: ((tab: TabNode) => ReactNode) | undefined;
326
+ renderTabsetToolbar: ((tabset: TabsetNode) => ReactNode) | undefined;
327
+ resizableSplits: boolean;
328
+ splitDock: boolean;
329
+ tabLocation: "bottom" | "top";
330
+ tabsetMinSize: number;
331
+ tabStripEnabled: boolean;
332
+ };
333
+ declare const useLayout: <T>(selector: (state: LayoutState) => T) => T;
334
+ //#endregion
106
335
  //#region src/hooks/responsive.d.ts
107
336
  type Breakpoint = {
108
337
  id: string;
@@ -148,5 +377,5 @@ type UseDashfooStoreOptions = {
148
377
  };
149
378
  declare const useDashfooStore: (options: UseDashfooStoreOptions) => DashfooStore;
150
379
  //#endregion
151
- export { type Breakpoint, DashfooContext, type DashfooContextValue, type DashfooHandle, DashfooLayout, type DashfooLayoutProps, type DashfooStore, Panel, type PanelBadgeProps, type PanelBodyProps, type PanelHeaderProps, type PanelIconProps, type PanelRootProps, type PanelTitleProps, type PersistConfig, type Persistence, type ResponsiveModel, type StorageAdapter, type TabComponent, type UseDashfooStoreOptions, type UseResponsiveModelOptions, activeBreakpoint, localStorageAdapter, matchBreakpoint, memoryStorageAdapter, useDashfooContext, useDashfooStore, usePersistence, useResponsiveModel };
380
+ export { type Breakpoint, DashfooDragProvider, type DashfooHandle, DashfooLayout, type DashfooLayoutProps, type DashfooStore, type ExternalTabSourceOptions, Layout, type DragProviderProps as LayoutDragLayerProps, type LayoutRootProps, type RowViewProps as LayoutRowsProps, type LayoutState, type TabsetViewProps as LayoutTabsetProps, Panel, type PanelBadgeProps, type PanelBodyProps, type PanelHeaderProps, type PanelIconProps, type PanelRootProps, type PanelTitleProps, type PersistConfig, type Persistence, type ResponsiveModel, type StorageAdapter, type TabComponent, type TabContextValue, Tabset, type TabsetCloseButtonProps, type TabsetContentProps, type TabsetGripProps, type TabsetMaximizeButtonProps, type TabsetRenameInputProps, type TabsetRootProps, type TabsetState, type TabsetTabProps, type TabsetTabStripProps, type TabsetTablistProps, type TabsetToolbarProps, type TabsetTriggerProps, type UseDashfooStoreOptions, type UseResponsiveModelOptions, activeBreakpoint, localStorageAdapter, matchBreakpoint, memoryStorageAdapter, useDashfooStore, useDragSubject, useDropIntent, useExternalTabSource, useLayout, usePersistence, useResponsiveModel, useTab, useTabset };
152
381
  //# sourceMappingURL=index.d.ts.map