@exegia/corpora-ui 0.18.0 → 0.20.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.
Files changed (78) hide show
  1. package/dist-lib/components/blocks/nav/sidebar/__tests__/use-ai-sidebar.test.d.ts +1 -0
  2. package/dist-lib/components/blocks/nav/sidebar/ai-sidebar.d.ts +11 -2
  3. package/dist-lib/components/blocks/nav/sidebar/type.d.ts +83 -1
  4. package/dist-lib/components/blocks/nav/sidebar/use-ai-sidebar.d.ts +22 -31
  5. package/dist-lib/components/blocks/nav/sidebar/utils.d.ts +5 -0
  6. package/dist-lib/components/blocks/scaffold/constants.d.ts +8 -0
  7. package/dist-lib/components/blocks/scaffold/index.d.ts +3 -1
  8. package/dist-lib/components/blocks/scaffold/panel-menu-button.d.ts +4 -3
  9. package/dist-lib/components/blocks/scaffold/scaffold-actions.d.ts +5 -4
  10. package/dist-lib/components/blocks/scaffold/scaffold-canvas.d.ts +2 -0
  11. package/dist-lib/components/blocks/scaffold/scaffold-panel.d.ts +1 -1
  12. package/dist-lib/components/blocks/scaffold/scaffold-tab.d.ts +14 -0
  13. package/dist-lib/components/blocks/scaffold/type.d.ts +58 -28
  14. package/dist-lib/components/blocks/scaffold/use-panel-visibility.d.ts +19 -0
  15. package/dist-lib/components/blocks/scaffold/utils.d.ts +12 -0
  16. package/dist-lib/components/composed/tree/__tests__/tree.test.d.ts +1 -0
  17. package/dist-lib/components/composed/tree/__tests__/use-tree.test.d.ts +1 -0
  18. package/dist-lib/components/composed/tree/constants.d.ts +35 -0
  19. package/dist-lib/components/composed/tree/index.d.ts +4 -0
  20. package/dist-lib/components/composed/tree/tree-context.d.ts +4 -0
  21. package/dist-lib/components/composed/tree/tree-node.d.ts +7 -0
  22. package/dist-lib/components/composed/tree/tree.d.ts +19 -0
  23. package/dist-lib/components/composed/tree/type.d.ts +192 -0
  24. package/dist-lib/components/composed/tree/use-tree-dnd.d.ts +7 -0
  25. package/dist-lib/components/composed/tree/use-tree.d.ts +20 -0
  26. package/dist-lib/components/composed/tree/utils.d.ts +28 -0
  27. package/dist-lib/components/user-avatar/audio-wave.d.ts +2 -0
  28. package/dist-lib/components/user-avatar/component.d.ts +10 -0
  29. package/dist-lib/components/user-avatar/fallback.d.ts +5 -0
  30. package/dist-lib/components/user-avatar/index.d.ts +13 -0
  31. package/dist-lib/components/user-avatar/type.d.ts +26 -0
  32. package/dist-lib/components/user-avatar/utils.d.ts +2 -0
  33. package/dist-lib/index.d.ts +1 -0
  34. package/dist-lib/index.js +2309 -1285
  35. package/dist-lib/index.js.map +1 -1
  36. package/package.json +2 -1
  37. package/src/components/beste/piece/browser-frame.tsx +9 -6
  38. package/src/components/blocks/nav/sidebar/__tests__/use-ai-sidebar.test.tsx +310 -0
  39. package/src/components/blocks/nav/sidebar/ai-sidebar.tsx +90 -60
  40. package/src/components/blocks/nav/sidebar/type.ts +105 -1
  41. package/src/components/blocks/nav/sidebar/use-ai-sidebar.ts +293 -116
  42. package/src/components/blocks/nav/sidebar/utils.ts +28 -0
  43. package/src/components/blocks/scaffold/__tests__/scaffold.test.tsx +268 -26
  44. package/src/components/blocks/scaffold/constants.ts +11 -0
  45. package/src/components/blocks/scaffold/index.ts +4 -1
  46. package/src/components/blocks/scaffold/panel-menu-button.tsx +96 -115
  47. package/src/components/blocks/scaffold/scaffold-actions.tsx +41 -50
  48. package/src/components/blocks/scaffold/scaffold-canvas.tsx +48 -5
  49. package/src/components/blocks/scaffold/scaffold-inspector.tsx +27 -3
  50. package/src/components/blocks/scaffold/scaffold-main.tsx +1 -1
  51. package/src/components/blocks/scaffold/scaffold-panel.tsx +56 -30
  52. package/src/components/blocks/scaffold/scaffold-root.tsx +18 -3
  53. package/src/components/blocks/scaffold/scaffold-sidebar.tsx +1 -1
  54. package/src/components/blocks/scaffold/scaffold-tab.tsx +104 -0
  55. package/src/components/blocks/scaffold/type.ts +62 -33
  56. package/src/components/blocks/scaffold/use-panel-visibility.ts +180 -0
  57. package/src/components/blocks/scaffold/utils.ts +35 -0
  58. package/src/components/composed/tree/__tests__/tree.test.tsx +400 -0
  59. package/src/components/composed/tree/__tests__/use-tree.test.tsx +332 -0
  60. package/src/components/composed/tree/constants.ts +60 -0
  61. package/src/components/composed/tree/index.ts +13 -0
  62. package/src/components/composed/tree/tree-context.ts +13 -0
  63. package/src/components/composed/tree/tree-node.tsx +451 -0
  64. package/src/components/composed/tree/tree.tsx +278 -0
  65. package/src/components/composed/tree/type.ts +212 -0
  66. package/src/components/composed/tree/use-tree-dnd.ts +148 -0
  67. package/src/components/composed/tree/use-tree.ts +306 -0
  68. package/src/components/composed/tree/utils.ts +172 -0
  69. package/src/components/composed/user-avatar.tsx +4 -1
  70. package/src/components/docs/component-preview.tsx +11 -11
  71. package/src/components/user-avatar/audio-wave.tsx +22 -0
  72. package/src/components/user-avatar/component.tsx +53 -0
  73. package/src/components/user-avatar/fallback.tsx +26 -0
  74. package/src/components/user-avatar/index.ts +15 -0
  75. package/src/components/user-avatar/type.ts +35 -0
  76. package/src/components/user-avatar/utils.ts +8 -0
  77. package/src/index.css +211 -153
  78. package/src/index.ts +1 -0
@@ -1,2 +1,11 @@
1
- import { AISidebarProps } from './type';
2
- export declare function AISidebar({ renderIcon, renderMenu, renderActionsTrigger, ariaLabel, className, ...options }: AISidebarProps): import("react").JSX.Element;
1
+ import { AISidebarComponentProps } from './type';
2
+ /**
3
+ * Resource tree for the app rail: nested rows with drag-and-drop reorder,
4
+ * inline rename, per-row action menus and full keyboard navigation.
5
+ *
6
+ * Two ways to drive it. Pass the data and handlers as props and the block
7
+ * owns its state, or hold a `useAISidebar` controller and pass it as
8
+ * `controller` — the same rendering, but select, expand, rename, reorder
9
+ * and menu state are then callable from anywhere in your app.
10
+ */
11
+ export declare function AISidebar(props: AISidebarComponentProps): import("react").JSX.Element;
@@ -17,7 +17,10 @@ export interface SidebarResourceMenuControls {
17
17
  close: () => void;
18
18
  rename: () => void;
19
19
  }
20
- export interface AISidebarProps {
20
+ /** Options for `useAISidebar`. `items`, `activeId` and `expandedIds` are
21
+ * each controlled when passed and hook-owned via their `default*` twin
22
+ * otherwise. */
23
+ export interface UseAISidebarOptions {
21
24
  items?: SidebarResource[];
22
25
  defaultItems?: SidebarResource[];
23
26
  onItemsChange?: (items: SidebarResource[]) => void;
@@ -28,7 +31,77 @@ export interface AISidebarProps {
28
31
  activeId?: string | null;
29
32
  defaultActiveId?: string | null;
30
33
  onActiveChange?: (id: string) => void;
34
+ expandedIds?: string[];
31
35
  defaultExpandedIds?: string[];
36
+ onExpandedChange?: (ids: string[]) => void;
37
+ }
38
+ /** Everything the sidebar can do, callable from outside the block — a
39
+ * toolbar, a command palette, a route change. Returned by `useAISidebar`
40
+ * and accepted by `<AISidebar controller={…} />`. */
41
+ export interface AISidebarController {
42
+ items: SidebarResource[];
43
+ /** Visible rows in order, each with its depth and parent id. */
44
+ flat: FlatResource[];
45
+ getItem: (id: string) => SidebarResource | undefined;
46
+ selectedId: string | null;
47
+ select: (id: string) => void;
48
+ expandedIds: ReadonlySet<string>;
49
+ isExpanded: (id: string) => boolean;
50
+ expand: (id: string) => void;
51
+ collapse: (id: string) => void;
52
+ toggleExpanded: (id: string) => void;
53
+ expandAll: () => void;
54
+ collapseAll: () => void;
55
+ /** Open every ancestor of `id`, leaving the rest of the tree alone. */
56
+ reveal: (id: string) => void;
57
+ /** Roving-focus target. `focus` also moves DOM focus to the row. */
58
+ focusedId: string | null;
59
+ focus: (id: string) => void;
60
+ renamingId: string | null;
61
+ startRename: (id: string) => void;
62
+ cancelRename: () => void;
63
+ /** Commit a rename and leave rename mode. Applied optimistically and
64
+ * rolled back if `onRename` rejects. Blank and unchanged labels are
65
+ * dropped. */
66
+ rename: (id: string, label: string) => void;
67
+ menuOpenId: string | null;
68
+ openMenu: (id: string) => void;
69
+ closeMenu: () => void;
70
+ /** Reorder, applied optimistically and rolled back if `onMove` rejects.
71
+ * Refuses moves the data forbids (into itself, into a non-container). */
72
+ move: (move: SidebarResourceMove) => Promise<void>;
73
+ /** A move is in flight — further moves are refused until it settles. */
74
+ movePending: boolean;
75
+ /** Live-region text for the last move or rename outcome. */
76
+ announcement: string;
77
+ /** @internal Row wiring the view threads through — drag state, the
78
+ * hover pill and roving keyboard nav all belong to the rendering. */
79
+ dnd: AISidebarDndState;
80
+ hover: AISidebarHoverState;
81
+ onRowKeyDown: (event: KeyboardEvent<HTMLDivElement>, row: FlatResource) => void;
82
+ setRowRef: (id: string, node: HTMLDivElement | null) => void;
83
+ }
84
+ /** @internal */
85
+ export interface AISidebarDndState {
86
+ draggingId: string | null;
87
+ dropTarget: DropTarget | null;
88
+ onRootDragOver: (event: DragEvent<HTMLDivElement>) => void;
89
+ onDrop: (event: DragEvent<HTMLDivElement>) => void;
90
+ onRowDragStart: (event: DragEvent<HTMLDivElement>, id: string) => void;
91
+ onRowDragEnd: () => void;
92
+ onRowDragOver: (event: DragEvent<HTMLDivElement>, row: FlatResource) => void;
93
+ }
94
+ /** @internal */
95
+ export interface AISidebarHoverState {
96
+ hoveredId: string | null;
97
+ /** Shared motion layoutId that lets the pill travel between rows. */
98
+ layoutId: string;
99
+ onRowHover: (id: string, hovered: boolean) => void;
100
+ clear: () => void;
101
+ }
102
+ export interface AISidebarProps extends UseAISidebarOptions {
103
+ /** Never set on the data form — `controller` selects the other one. */
104
+ controller?: never;
32
105
  renderIcon?: (item: SidebarResource) => ReactNode;
33
106
  renderMenu?: (item: SidebarResource, controls: SidebarResourceMenuControls) => ReactNode;
34
107
  /**
@@ -39,6 +112,15 @@ export interface AISidebarProps {
39
112
  ariaLabel?: string;
40
113
  className?: string;
41
114
  }
115
+ /** Presentational props, shared by both forms of `<AISidebar>`. */
116
+ export type AISidebarViewProps = Pick<AISidebarProps, "renderIcon" | "renderMenu" | "renderActionsTrigger" | "ariaLabel" | "className">;
117
+ /** Drive the block from a `useAISidebar` controller instead of raw props —
118
+ * the controller carries the data and every handler. */
119
+ export interface AISidebarControllerProps extends AISidebarViewProps {
120
+ controller: AISidebarController;
121
+ }
122
+ /** Either form: raw props, or a `useAISidebar` controller. */
123
+ export type AISidebarComponentProps = AISidebarProps | AISidebarControllerProps;
42
124
  export interface FlatResource {
43
125
  item: SidebarResource;
44
126
  depth: number;
@@ -1,31 +1,22 @@
1
- import { DragEvent, KeyboardEvent } from 'react';
2
- import { AISidebarProps, DropTarget, FlatResource } from './type.ts';
3
- export type UseAISidebarOptions = Pick<AISidebarProps, "items" | "defaultItems" | "onItemsChange" | "onMove" | "onMoveError" | "onRename" | "activeId" | "defaultActiveId" | "onActiveChange" | "defaultExpandedIds">;
4
- export declare function useAISidebar({ items, defaultItems, onItemsChange, onMove, onMoveError, onRename, activeId, defaultActiveId, onActiveChange, defaultExpandedIds, }: UseAISidebarOptions): {
5
- flat: FlatResource[];
6
- selectedId: string | null;
7
- expandedIds: Set<string>;
8
- focusedId: string | null;
9
- setFocusedId: import('react').Dispatch<import('react').SetStateAction<string | null>>;
10
- draggingId: string | null;
11
- dropTarget: DropTarget | null;
12
- hoveredId: string | null;
13
- hoverLayoutId: string;
14
- handleRowHover: (id: string, hovered: boolean) => void;
15
- clearHover: () => void;
16
- menuOpenId: string | null;
17
- renamingId: string | null;
18
- setRenamingId: import('react').Dispatch<import('react').SetStateAction<string | null>>;
19
- announcement: string;
20
- select: (id: string) => void;
21
- toggle: (id: string) => void;
22
- handleKeyDown: (event: KeyboardEvent<HTMLDivElement>, row: FlatResource) => void;
23
- handleRootDragOver: (event: DragEvent<HTMLDivElement>) => void;
24
- handleDrop: (event: DragEvent<HTMLDivElement>) => void;
25
- handleRowDragStart: (event: DragEvent<HTMLDivElement>, id: string) => void;
26
- handleRowDragEnd: () => void;
27
- handleRowDragOver: (event: DragEvent<HTMLDivElement>, targetRow: FlatResource) => void;
28
- commitRename: (row: FlatResource, label: string) => void;
29
- handleMenuOpenChange: (row: FlatResource, open: boolean) => void;
30
- setRowRef: (id: string, node: HTMLDivElement | null) => void;
31
- };
1
+ import { AISidebarController, UseAISidebarOptions } from './type.ts';
2
+ export type { UseAISidebarOptions };
3
+ /**
4
+ * The AI sidebar's headless controller — every behaviour the block
5
+ * performs, callable from outside it: select, expand/collapse (one row,
6
+ * every row, or just the ancestors of one), move focus, rename, open a
7
+ * row's action menu, reorder.
8
+ *
9
+ * `items`, `activeId` and `expandedIds` are each controlled when passed
10
+ * and hook-owned via their `default*` twin otherwise. Reorder and rename
11
+ * are applied to the data optimistically either way and rolled back if
12
+ * `onMove`/`onRename` rejects, so a consumer never reduces the tree
13
+ * itself — `moveResource` and `renameResource` are exported for the ones
14
+ * who keep their data elsewhere.
15
+ *
16
+ * ```tsx
17
+ * const sidebar = useAISidebar({ defaultItems: resources })
18
+ * <AISidebar controller={sidebar} />
19
+ * <Button onClick={sidebar.collapseAll}>Collapse all</Button>
20
+ * ```
21
+ */
22
+ export declare function useAISidebar(options: UseAISidebarOptions): AISidebarController;
@@ -6,6 +6,11 @@ export declare const ROW_REVEAL: {
6
6
  export declare function canContain(item: SidebarResource): boolean;
7
7
  export declare function flattenResources(items: SidebarResource[], expanded: Set<string>, depth?: number, parentId?: string | null): FlatResource[];
8
8
  export declare function findResource(items: SidebarResource[], id: string): SidebarResource | undefined;
9
+ /** Ids of every ancestor of `id` (nearest last); empty when absent. */
10
+ export declare function ancestorIdsOf(items: SidebarResource[], id: string): string[];
11
+ /** Ids of every row that can hold children and has some — the set
12
+ * `expandAll` opens. */
13
+ export declare function expandableIdsOf(items: SidebarResource[]): string[];
9
14
  export declare function containsResource(item: SidebarResource, id: string): boolean;
10
15
  export declare function removeResource(items: SidebarResource[], id: string): {
11
16
  items: SidebarResource[];
@@ -2,6 +2,14 @@
2
2
  export declare const SCAFFOLD_SIDEBAR_WIDTH = 64;
3
3
  /** Inspector drawer width in px. */
4
4
  export declare const SCAFFOLD_INSPECTOR_WIDTH = 272;
5
+ /** Most panels the canvas holds at once — omit Actions' `onAdd` when the
6
+ * count reaches it so the Add segment hides. */
7
+ export declare const SCAFFOLD_PANEL_CAPACITY = 3;
8
+ /** Narrowest a panel may render, in px. When the canvas can't grant every
9
+ * panel this width, the scaffold hides panels until the rest fit. */
10
+ export declare const SCAFFOLD_PANEL_MIN_WIDTH = 320;
11
+ /** Gap in px between side-by-side panels on the canvas (`gap-2`). */
12
+ export declare const SCAFFOLD_CANVAS_GAP = 8;
5
13
  /** Gap in px between the drawer/actions and the viewport edges. */
6
14
  export declare const SCAFFOLD_EDGE_GUTTER = 10;
7
15
  /** Vertical room in px reserved above the canvas for the actions cluster. */
@@ -7,12 +7,13 @@ import { ScaffoldMain } from './scaffold-main';
7
7
  import { ScaffoldPanel } from './scaffold-panel';
8
8
  import { ScaffoldRoot } from './scaffold-root';
9
9
  import { ScaffoldSidebar } from './scaffold-sidebar';
10
+ import { ScaffoldTab } from './scaffold-tab';
10
11
  import { ScaffoldSubPanel } from './scaffold-sub-panel.tsx';
11
12
  export { useScaffoldContext } from './scaffold-context';
12
13
  export { useScaffold } from './use-scaffold';
13
14
  export type * from './type';
14
15
  export * from './constants';
15
- export { PanelCloseButton, PanelMenuButton, ScaffoldActions, ScaffoldCanvas, ScaffoldInspector, ScaffoldMain, ScaffoldPanel, ScaffoldRoot, ScaffoldSidebar, };
16
+ export { PanelCloseButton, PanelMenuButton, ScaffoldActions, ScaffoldCanvas, ScaffoldInspector, ScaffoldMain, ScaffoldPanel, ScaffoldRoot, ScaffoldSidebar, ScaffoldTab, };
16
17
  export declare const Scaffold: {
17
18
  Root: typeof ScaffoldRoot;
18
19
  Sidebar: typeof ScaffoldSidebar;
@@ -20,6 +21,7 @@ export declare const Scaffold: {
20
21
  Actions: typeof ScaffoldActions;
21
22
  Canvas: typeof ScaffoldCanvas;
22
23
  Panel: typeof ScaffoldPanel;
24
+ Tab: typeof ScaffoldTab;
23
25
  Inspector: typeof ScaffoldInspector;
24
26
  SubPanel: typeof ScaffoldSubPanel;
25
27
  };
@@ -1,7 +1,8 @@
1
1
  import { PanelMenuButtonProps } from './type';
2
2
  import * as React from "react";
3
3
  /**
4
- * Floating swap affordance centered on the seam between a panel's primary
5
- * surface and its secondary strip.
4
+ * Floating menu affordance centered on the seam between a panel's primary
5
+ * surface and its secondary strip: a compact ⋯ toggle that morphs into the
6
+ * Expand | Swap (| Close) actions.
6
7
  */
7
- export declare function PanelMenuButton({ onClick, onExpand, secondaryExpanded, label, sound, className, }: PanelMenuButtonProps): React.ReactElement;
8
+ export declare function PanelMenuButton({ onClick, onExpand, onCloseSecondary, secondaryExpanded, swapped, label, sound, className, }: PanelMenuButtonProps): React.ReactElement;
@@ -2,8 +2,9 @@ import { ScaffoldActionsProps } from './type';
2
2
  import * as React from "react";
3
3
  /**
4
4
  * The floating pill cluster in the main region's top-right corner — the
5
- * design's "Panel Context Menu": an Add segment plus an overflow segment
6
- * whose badge counts the non-visible panels. Slides left in step with the
7
- * inspector opening.
5
+ * design's "Panel Context Menu": one tab per open panel (`Scaffold.Tab`
6
+ * children) plus an Add segment. Add renders only while `onAdd` is
7
+ * present — omit it once the canvas holds `SCAFFOLD_PANEL_CAPACITY`
8
+ * panels. Slides left in step with the inspector opening.
8
9
  */
9
- export declare function ScaffoldActions({ onAdd, addLabel, addIcon, overflowCount, onBrowse, browseLabel, sound, className, children, ...rest }: ScaffoldActionsProps): React.ReactElement;
10
+ export declare function ScaffoldActions({ onAdd, addLabel, addIcon, sound, className, children, ...rest }: ScaffoldActionsProps): React.ReactElement;
@@ -3,5 +3,7 @@ import * as React from "react";
3
3
  /**
4
4
  * The panel row below the action cluster: 8px gutters, 8px gaps, panels
5
5
  * side by side. Key each `Scaffold.Panel` child so closes animate out.
6
+ * Measures its own width and hides id'd panels (oldest activation first)
7
+ * whenever it can't grant each one `SCAFFOLD_PANEL_MIN_WIDTH`.
6
8
  */
7
9
  export declare function ScaffoldCanvas({ className, children, ...rest }: ScaffoldCanvasProps): React.ReactElement;
@@ -7,4 +7,4 @@ import * as React from "react";
7
7
  * the two cards with a layout morph — the strip glides up and grows into the
8
8
  * primary slot while the primary card shrinks down into the strip.
9
9
  */
10
- export declare function ScaffoldPanel({ children, SecondaryPanel, onClose, onSwap, name, closeLabel, swapLabel, sound, className, }: ScaffoldPanelProps): React.ReactElement;
10
+ export declare function ScaffoldPanel({ id, children, SecondaryPanel, onSwap, onCloseSecondary, name, swapLabel, sound, className, }: ScaffoldPanelProps): React.ReactElement;
@@ -0,0 +1,14 @@
1
+ import { ScaffoldTabProps } from './type';
2
+ import * as React from "react";
3
+ /**
4
+ * A panel's tab inside the action cluster: its label plus a close
5
+ * affordance. Render one per open panel as Actions children, keyed —
6
+ * closes animate out of the pill. Omit `onClose` on the last remaining
7
+ * panel's tab; the canvas keeps at least one panel open.
8
+ *
9
+ * With `panelId` (matching a `Scaffold.Panel`'s `id`), the tab also fronts
10
+ * that panel's visibility: a hidden panel dims its tab behind an eye-off
11
+ * icon, and pressing the label toggles the panel — showing one past
12
+ * capacity hides the least-recently-activated panel in its place.
13
+ */
14
+ export declare function ScaffoldTab({ children, panelId, onClose, closeLabel, sound, className, ...rest }: ScaffoldTabProps): React.ReactElement;
@@ -7,6 +7,25 @@ export interface ScaffoldContextValue {
7
7
  inspectorWidth: number;
8
8
  setInspectorOpen: (open: boolean) => void;
9
9
  toggleInspector: () => void;
10
+ /** How many panels currently fit side by side, from the measured canvas
11
+ * width at `SCAFFOLD_PANEL_MIN_WIDTH` per panel (1..`SCAFFOLD_PANEL_CAPACITY`). */
12
+ panelCapacity: number;
13
+ /** Ids of id'd panels the scaffold is currently hiding — auto-hidden by
14
+ * capacity pressure or toggled away from a tab. */
15
+ hiddenPanelIds: readonly string[];
16
+ isPanelHidden: (id: string) => boolean;
17
+ /** Show/hide an id'd panel. Showing past capacity auto-hides the
18
+ * least-recently-activated visible panel; the last visible one never hides. */
19
+ togglePanelVisibility: (id: string) => void;
20
+ /** Id of the panel whose tab the pointer is resting on — the canvas
21
+ * spotlights it by fading every other id'd panel to 0.35 opacity. */
22
+ hoveredPanelId: string | null;
23
+ /** @internal Tabs report pointer enter/leave on their label. */
24
+ setPanelHovered: (id: string, hovered: boolean) => void;
25
+ /** @internal Canvas reports its ordered panel ids. */
26
+ registerPanelIds: (ids: readonly string[]) => void;
27
+ /** @internal Canvas reports its measured width. */
28
+ setCanvasWidth: (width: number) => void;
10
29
  }
11
30
  export interface ScaffoldRootProps extends ComponentProps<"div"> {
12
31
  /** Controlled inspector state — pair with `onInspectorOpenChange`, or
@@ -25,58 +44,63 @@ export type ScaffoldCanvasProps = ComponentProps<"div">;
25
44
  * on `motion.*` elements — strip them from pass-through HTML props. */
26
45
  type MotionSafe<T> = Omit<T, "onDrag" | "onDragStart" | "onDragEnd" | "onAnimationStart" | "onAnimationEnd" | "onAnimationIteration">;
27
46
  export interface ScaffoldActionsProps extends MotionSafe<Omit<ComponentProps<"div">, "children">> {
28
- /** Called when the Add segment is pressed. */
47
+ /** Called when the Add segment is pressed. The segment renders only
48
+ * while this is present — omit it to hide Add, e.g. once the canvas
49
+ * holds `SCAFFOLD_PANEL_CAPACITY` panels. */
29
50
  onAdd?: () => void;
30
51
  /** Label of the Add segment. */
31
52
  addLabel?: ReactNode;
32
53
  /** Replaces the default add icon. */
33
54
  addIcon?: ReactNode;
34
- /** Number of non-visible panels tucked into the overflow dropdown —
35
- * the badge on the browse segment. The segment renders when this or
36
- * `onBrowse` is present; the badge only when > 0. Per the design
37
- * comments the dropdown menu itself is a later iteration; for now the
38
- * segment just keeps the count. */
39
- overflowCount?: number;
40
- /** Called when the overflow (stacked-panels) segment is pressed. */
41
- onBrowse?: () => void;
42
- /** Accessible name of the overflow segment. */
43
- browseLabel?: string;
44
- /** Extra segments appended after the built-in ones. */
55
+ /** The panel tabs (`Scaffold.Tab`, one per open panel) and any extra
56
+ * segments, rendered before Add. Key each tab — closes animate out. */
45
57
  children?: ReactNode;
46
58
  /** Emit interaction-sound attributes (inert until an app binds cuelume). */
47
59
  sound?: boolean;
48
60
  }
49
61
  export type TScaffoldPanelChild<T extends ScaffoldSubPanelProps = ScaffoldSubPanelProps> = ReactElement<T, React.JSXElementConstructor<T>>;
50
62
  export interface ScaffoldPanelProps {
63
+ /** Stable id opting the panel into responsive hiding: the canvas hides
64
+ * id'd panels when it can't grant each `SCAFFOLD_PANEL_MIN_WIDTH`, and a
65
+ * `Scaffold.Tab` with the matching `panelId` reflects and toggles it.
66
+ * Omitted, the panel always renders. */
67
+ id?: string;
51
68
  /** The panel's content, rendered in a card with a drop shadow. */
52
69
  children: ReactNode;
53
70
  /** The panel's content, rendered in a card with a drop shadow. */
54
71
  SecondaryPanel?: TScaffoldPanelChild;
55
- /** Renders the floating close button in the panel's top-right corner. */
56
- onClose?: () => void;
57
- /** Renders the floating swap button over the primary/secondary gap.
58
- * Only shown when `secondary` is present. Clicking it trades the two
59
- * cards with a layout morph — flip the slot content here so each card
60
- * carries its subject to its new home. */
72
+ /** Reveals the Swap action in the seam menu (needs `SecondaryPanel`).
73
+ * Swapping trades the two cards with a layout morph — flip the slot
74
+ * content here so each card carries its subject to its new home. */
61
75
  onSwap?: () => void;
62
- /** Controlled swap state — while true the strip's card sits in the
63
- * primary slot. Omit letting the panel toggle it on swap clicks. */
64
- swapped?: boolean;
65
- /** Initial swap state when uncontrolled. */
66
- defaultSwapped?: boolean;
67
- /** Fixed width in px; omitted, the panel flexes to share the canvas. */
68
- width?: number;
76
+ /** Reveals the Close action in the seam menu — remove `SecondaryPanel`
77
+ * here; the strip and the menu leave together. */
78
+ onCloseSecondary?: () => void;
69
79
  /** Accessible name of the panel region. */
70
80
  name?: string;
71
81
  /** Emit interaction-sound attributes on the floating buttons. */
72
82
  sound?: boolean;
73
- /** Accessible name of the close button. */
74
- closeLabel?: string;
75
- /** Accessible name of the swap button. */
83
+ /** Accessible name of the seam-menu toggle. */
76
84
  swapLabel?: string;
77
85
  /** Extra class names for the panel's root element. */
78
86
  className?: string;
79
87
  }
88
+ export interface ScaffoldTabProps extends MotionSafe<Omit<ComponentProps<"div">, "children">> {
89
+ /** The tab's label. */
90
+ children?: ReactNode;
91
+ /** Id of the panel this tab fronts (`Scaffold.Panel`'s `id`). The tab
92
+ * then shows whether the panel is hidden and pressing its label toggles
93
+ * visibility — showing past capacity hides another panel in its place. */
94
+ panelId?: string;
95
+ /** Renders the tab's close button. The button renders only while this
96
+ * is present — omit it to pin the tab, e.g. on the last remaining
97
+ * panel (the canvas keeps at least one open). */
98
+ onClose?: () => void;
99
+ /** Accessible name of the close button. */
100
+ closeLabel?: string;
101
+ /** Emit interaction-sound attributes on the close button. */
102
+ sound?: boolean;
103
+ }
80
104
  export type TSubPanelPosition = "bottom" | "top";
81
105
  export type TSubPanelVariant = "card" | "subtle" | "inset";
82
106
  export interface ScaffoldSubPanelProps extends MotionSafe<Omit<ComponentProps<"div">, "children">> {
@@ -113,9 +137,15 @@ export interface PanelMenuButtonProps extends PanelFloatingButtonProps {
113
137
  /** Called when the Expand action is pressed — the panel trades which
114
138
  * sub-panel holds the flexible slot. */
115
139
  onExpand?: () => void;
140
+ /** Renders the Close action; called when it is pressed — the consumer
141
+ * removes the secondary strip. */
142
+ onCloseSecondary?: () => void;
116
143
  /** Whether the secondary strip currently holds the flexible slot —
117
144
  * flips the Expand chevron between down and up. */
118
145
  secondaryExpanded?: boolean;
146
+ /** Whether the panel is swapped (column-reverse). Mirrors the Expand
147
+ * chevron so it keeps pointing at the sub-panel that grows next. */
148
+ swapped?: boolean;
119
149
  }
120
150
  export interface UseScaffoldOptions {
121
151
  /** Initial inspector state. Closed by default. */
@@ -0,0 +1,19 @@
1
+ export interface PanelVisibility {
2
+ /** How many panels currently fit side by side (1..capacity cap). */
3
+ panelCapacity: number;
4
+ /** Ids of panels currently hidden (auto + user), for tabs to reflect. */
5
+ hiddenPanelIds: readonly string[];
6
+ isPanelHidden: (id: string) => boolean;
7
+ togglePanelVisibility: (id: string) => void;
8
+ /** Id of the panel whose tab is hovered — the canvas spotlights it. */
9
+ hoveredPanelId: string | null;
10
+ /** @internal Tabs report pointer enter/leave on their label. */
11
+ setPanelHovered: (id: string, hovered: boolean) => void;
12
+ /** @internal Canvas reports its ordered panel ids each render. */
13
+ registerPanelIds: (ids: readonly string[]) => void;
14
+ /** @internal Canvas reports its measured width. */
15
+ setCanvasWidth: (width: number) => void;
16
+ }
17
+ /** Owns which panels are hidden as the canvas gains and loses room.
18
+ * Lives in `Scaffold.Root`; Canvas and Tab reach it through context. */
19
+ export declare function usePanelVisibility(): PanelVisibility;
@@ -1,5 +1,12 @@
1
+ import { Variants } from 'motion/react';
1
2
  import { ClassNameValue } from 'tailwind-merge';
2
3
  import { TSubPanelVariant } from './type.ts';
4
+ /**
5
+ * How many panels fit on a canvas of `width` px, granting each
6
+ * `SCAFFOLD_PANEL_MIN_WIDTH` plus the gaps between them. Clamped to
7
+ * [1, SCAFFOLD_PANEL_CAPACITY]; an unmeasured canvas (`null`) fits the cap.
8
+ */
9
+ export declare function getPanelCapacity(width: number | null): number;
3
10
  /** Desktop backdrop the whole scaffold sits on — a soft warm-gray wash. */
4
11
  export declare const scaffoldBackgroundClass: ClassNameValue;
5
12
  /** Card surface shared by a panel's primary area and secondary strip. */
@@ -11,5 +18,10 @@ export declare const floatingButtonClass: ClassNameValue;
11
18
  export declare const revealOnPanelHoverClass: ClassNameValue;
12
19
  /** Pill segment inside the actions cluster (Add, browse). */
13
20
  export declare const actionSegmentClass: ClassNameValue;
21
+ /** Pill segments (seam-menu actions, tabs, Add) blur/fade in place while
22
+ * the track morphs around them. The exit is a fast tween, not the layout
23
+ * spring — the track stays overflow-visible, so popped-out segments must be
24
+ * gone before the shrinking pill leaves them behind as a ghost. */
25
+ export declare const segmentVariants: Variants;
14
26
  /** Map of sub-panel variants to their corresponding side. */
15
27
  export declare const subPanelVariant: Record<TSubPanelVariant, ClassNameValue>;
@@ -0,0 +1,35 @@
1
+ import { Transition, Variants } from 'motion/react';
2
+ /** `--ease-smooth-out` as a motion/react easing tuple. */
3
+ export declare const TREE_EASE: readonly [0.22, 1, 0.36, 1];
4
+ /** Branch open — `--duration-fast` territory (accordion open). */
5
+ export declare const TREE_OPEN_DURATION = 0.25;
6
+ /** Branch close — quicker than open, per open/close asymmetry. */
7
+ export declare const TREE_CLOSE_DURATION = 0.15;
8
+ /** Chevron flip and label fades. */
9
+ export declare const TREE_MICRO_DURATION = 0.15;
10
+ /** Sidebar rail label reveal/hide when `collapsed` flips. */
11
+ export declare const TREE_COLLAPSE_DURATION = 0.2;
12
+ /** The collapsed rail's width in px — an icon row plus its padding. Kept in
13
+ * sync with the `w-11` resting class the rail falls back to before its
14
+ * expanded width has been measured. */
15
+ export declare const RAIL_COLLAPSED_WIDTH = 44;
16
+ /** Rail label text fade — starts as the width growth is finishing, so the
17
+ * label never reads as clipped mid-grow. */
18
+ export declare const TREE_LABEL_REVEAL_DELAY = 0.01;
19
+ /** A branch's children group: grows open with a soft stagger, folds shut
20
+ * faster. Height rides layout ("auto"), paint fades. */
21
+ export declare const TREE_BRANCH_VARIANTS: Variants;
22
+ /** Branch close — a plain target, NOT the "closed" variant label: a
23
+ * labeled exit orchestrates every variant child and AnimatePresence then
24
+ * waits on the whole subtree before unmounting. */
25
+ export declare const TREE_BRANCH_EXIT: {
26
+ height: number;
27
+ opacity: number;
28
+ transition: {
29
+ duration: number;
30
+ ease: readonly [0.22, 1, 0.36, 1];
31
+ };
32
+ };
33
+ /** One row inside an opening branch — a short blurred rise. */
34
+ export declare const TREE_ROW_VARIANTS: Variants;
35
+ export declare const TREE_MICRO_TRANSITION: Transition;
@@ -0,0 +1,4 @@
1
+ export { Tree } from './tree';
2
+ export { useTree } from './use-tree';
3
+ export { moveNode, renameNode } from './utils';
4
+ export type { TreeController, TreeControllerProps, TreeDataProps, TreeDropPosition, TreeNode, TreeProps, TreeVariant, UseTreeOptions, } from './type';
@@ -0,0 +1,4 @@
1
+ import { TreeContextValue } from './type';
2
+ import * as React from "react";
3
+ export declare const TreeContext: React.Context<TreeContextValue | null>;
4
+ export declare function useTreeContext(): TreeContextValue;
@@ -0,0 +1,7 @@
1
+ import { TreeNode } from './type';
2
+ import * as React from "react";
3
+ export interface TreeRowProps {
4
+ node: TreeNode;
5
+ depth: number;
6
+ }
7
+ export declare function TreeRow({ node, depth }: TreeRowProps): React.ReactElement;
@@ -0,0 +1,19 @@
1
+ import { TreeProps } from './type';
2
+ import * as React from "react";
3
+ /**
4
+ * A nested item tree with four shapes: `navigation` (app nav — 3-level
5
+ * data promotes the top level to collapsible section names), `toc`
6
+ * (routes on top, in-page `#` anchors at the leaves), `sidebar` (a
7
+ * single-level rail that collapses to icons) and `files` (a compact file
8
+ * explorer with rename, drag-and-drop and trailing row actions).
9
+ *
10
+ * Two ways to drive it. Data-driven like the sidebar block: pass `items`,
11
+ * wire `onNavigate` into your router. Or hold a `useTree` controller and
12
+ * pass it as `tree` — same rendering, but expand, collapse, select, rename
13
+ * and reorder are then callable from anywhere in your app.
14
+ *
15
+ * Branches expand with a soft height morph and row stagger; the rail's
16
+ * labels fold away when `collapsed` flips. Arrow keys walk visible rows,
17
+ * expand and collapse; F2 renames in `files`.
18
+ */
19
+ export declare function Tree(props: TreeProps): React.ReactElement;