@exegia/corpora-ui 0.19.0 → 0.21.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/dist-lib/components/blocks/auth/__tests__/auth-state-atom.test.d.ts +1 -0
- package/dist-lib/components/blocks/auth/auth-flow-atom.d.ts +77 -0
- package/dist-lib/components/blocks/auth/auth-session-atom.d.ts +28 -0
- package/dist-lib/components/blocks/auth/auth-state-type.d.ts +71 -0
- package/dist-lib/components/blocks/auth/auth-state.d.ts +9 -0
- package/dist-lib/components/blocks/auth/use-auth-state.d.ts +52 -0
- package/dist-lib/components/blocks/nav/sidebar/__tests__/ai-sidebar-atom.test.d.ts +1 -0
- package/dist-lib/components/blocks/nav/sidebar/__tests__/use-ai-sidebar.test.d.ts +1 -0
- package/dist-lib/components/blocks/nav/sidebar/ai-sidebar-atom.d.ts +217 -0
- package/dist-lib/components/blocks/nav/sidebar/ai-sidebar.d.ts +11 -2
- package/dist-lib/components/blocks/nav/sidebar/index.d.ts +3 -1
- package/dist-lib/components/blocks/nav/sidebar/sidebar-context.d.ts +3 -0
- package/dist-lib/components/blocks/nav/sidebar/sidebar-row.d.ts +3 -1
- package/dist-lib/components/blocks/nav/sidebar/type.d.ts +191 -29
- package/dist-lib/components/blocks/nav/sidebar/use-ai-sidebar-state.d.ts +29 -0
- package/dist-lib/components/blocks/nav/sidebar/use-ai-sidebar.d.ts +27 -31
- package/dist-lib/components/blocks/nav/sidebar/utils.d.ts +6 -1
- package/dist-lib/components/blocks/profile/index.d.ts +7 -0
- package/dist-lib/components/blocks/profile/profile-card-atom.d.ts +68 -0
- package/dist-lib/components/blocks/profile/profile-card-block.d.ts +28 -39
- package/dist-lib/components/blocks/profile/type.d.ts +80 -0
- package/dist-lib/components/blocks/profile/use-profile-card-state.d.ts +24 -0
- package/dist-lib/components/blocks/profile/use-profile-card.d.ts +34 -0
- package/dist-lib/components/blocks/scaffold/constants.d.ts +5 -0
- package/dist-lib/components/blocks/scaffold/scaffold-canvas.d.ts +2 -0
- package/dist-lib/components/blocks/scaffold/scaffold-panel.d.ts +1 -1
- package/dist-lib/components/blocks/scaffold/scaffold-tab.d.ts +6 -1
- package/dist-lib/components/blocks/scaffold/type.d.ts +28 -0
- package/dist-lib/components/blocks/scaffold/use-panel-visibility.d.ts +19 -0
- package/dist-lib/components/blocks/scaffold/utils.d.ts +6 -0
- package/dist-lib/components/blocks/shell/__tests__/shell-fit-atom.test.d.ts +1 -0
- package/dist-lib/components/blocks/shell/__tests__/shell-metrics.test.d.ts +1 -0
- package/dist-lib/components/blocks/shell/animated-panel-provider.d.ts +1 -1
- package/dist-lib/components/blocks/shell/animated-panel.d.ts +1 -1
- package/dist-lib/components/blocks/shell/index.d.ts +4 -0
- package/dist-lib/components/blocks/shell/shell-fit-atom.d.ts +68 -0
- package/dist-lib/components/blocks/shell/shell-metrics.d.ts +54 -0
- package/dist-lib/components/blocks/shell/type.d.ts +115 -3
- package/dist-lib/components/blocks/shell/use-shell-fit-state.d.ts +25 -0
- package/dist-lib/components/blocks/shell/use-shell-fit.d.ts +14 -0
- package/dist-lib/components/blocks/shell/use-shell-panels.d.ts +12 -1
- package/dist-lib/components/blocks/shell/utils.d.ts +32 -0
- package/dist-lib/components/composed/tree/__tests__/tree-atom.test.d.ts +1 -0
- package/dist-lib/components/composed/tree/__tests__/tree.test.d.ts +1 -0
- package/dist-lib/components/composed/tree/__tests__/use-tree.test.d.ts +1 -0
- package/dist-lib/components/composed/tree/constants.d.ts +35 -0
- package/dist-lib/components/composed/tree/index.d.ts +6 -0
- package/dist-lib/components/composed/tree/tree-atom.d.ts +160 -0
- package/dist-lib/components/composed/tree/tree-context.d.ts +4 -0
- package/dist-lib/components/composed/tree/tree-node.d.ts +12 -0
- package/dist-lib/components/composed/tree/tree.d.ts +19 -0
- package/dist-lib/components/composed/tree/type.d.ts +290 -0
- package/dist-lib/components/composed/tree/use-tree-dnd.d.ts +18 -0
- package/dist-lib/components/composed/tree/use-tree-state.d.ts +25 -0
- package/dist-lib/components/composed/tree/use-tree.d.ts +24 -0
- package/dist-lib/components/composed/tree/utils.d.ts +28 -0
- package/dist-lib/components/composed/user-avatar.d.ts +5 -28
- package/dist-lib/components/user-avatar/__tests__/user-avatar.test.d.ts +1 -0
- package/dist-lib/components/user-avatar/audio-wave.d.ts +2 -0
- package/dist-lib/components/user-avatar/component.d.ts +3 -0
- package/dist-lib/components/user-avatar/fallback.d.ts +5 -0
- package/dist-lib/components/user-avatar/index.d.ts +18 -0
- package/dist-lib/components/user-avatar/presence-badge.d.ts +16 -0
- package/dist-lib/components/user-avatar/type.d.ts +71 -0
- package/dist-lib/components/user-avatar/use-user-avatar-state.d.ts +26 -0
- package/dist-lib/components/user-avatar/use-user-avatar.d.ts +32 -0
- package/dist-lib/components/user-avatar/user-avatar-atom.d.ts +55 -0
- package/dist-lib/components/user-avatar/utils.d.ts +2 -0
- package/dist-lib/index.d.ts +6 -2
- package/dist-lib/index.js +3576 -1366
- package/dist-lib/index.js.map +1 -1
- package/dist-lib/state/exegia-provider.d.ts +51 -0
- package/dist-lib/state/index.d.ts +4 -0
- package/dist-lib/state/store.d.ts +17 -0
- package/package.json +16 -12
- package/src/components/beste/piece/browser-frame.tsx +9 -6
- package/src/components/blocks/auth/__tests__/auth-state-atom.test.tsx +247 -0
- package/src/components/blocks/auth/auth-flow-atom.ts +238 -0
- package/src/components/blocks/auth/auth-session-atom.ts +82 -0
- package/src/components/blocks/auth/auth-state-type.ts +97 -0
- package/src/components/blocks/auth/auth-state.ts +52 -0
- package/src/components/blocks/auth/use-auth-state.ts +127 -0
- package/src/components/blocks/nav/sidebar/__tests__/ai-sidebar-atom.test.tsx +325 -0
- package/src/components/blocks/nav/sidebar/__tests__/use-ai-sidebar.test.tsx +310 -0
- package/src/components/blocks/nav/sidebar/ai-sidebar-atom.ts +698 -0
- package/src/components/blocks/nav/sidebar/ai-sidebar.tsx +112 -76
- package/src/components/blocks/nav/sidebar/index.ts +53 -1
- package/src/components/blocks/nav/sidebar/sidebar-context.ts +15 -0
- package/src/components/blocks/nav/sidebar/sidebar-row.tsx +119 -50
- package/src/components/blocks/nav/sidebar/type.ts +228 -29
- package/src/components/blocks/nav/sidebar/use-ai-sidebar-state.ts +123 -0
- package/src/components/blocks/nav/sidebar/use-ai-sidebar.ts +455 -225
- package/src/components/blocks/nav/sidebar/utils.ts +29 -1
- package/src/components/blocks/profile/__tests__/profile-card-block.test.tsx +194 -0
- package/src/components/blocks/profile/index.ts +28 -0
- package/src/components/blocks/profile/profile-card-atom.ts +247 -0
- package/src/components/blocks/profile/profile-card-block.tsx +153 -74
- package/src/components/blocks/profile/type.ts +95 -0
- package/src/components/blocks/profile/use-profile-card-state.ts +67 -0
- package/src/components/blocks/profile/use-profile-card.ts +126 -0
- package/src/components/blocks/scaffold/__tests__/scaffold.test.tsx +160 -1
- package/src/components/blocks/scaffold/constants.ts +7 -0
- package/src/components/blocks/scaffold/panel-menu-button.tsx +3 -0
- package/src/components/blocks/scaffold/scaffold-canvas.tsx +48 -5
- package/src/components/blocks/scaffold/scaffold-inspector.tsx +3 -2
- package/src/components/blocks/scaffold/scaffold-main.tsx +1 -1
- package/src/components/blocks/scaffold/scaffold-panel.tsx +41 -5
- package/src/components/blocks/scaffold/scaffold-root.tsx +18 -3
- package/src/components/blocks/scaffold/scaffold-sidebar.tsx +1 -1
- package/src/components/blocks/scaffold/scaffold-tab.tsx +45 -7
- package/src/components/blocks/scaffold/type.ts +28 -0
- package/src/components/blocks/scaffold/use-panel-visibility.ts +180 -0
- package/src/components/blocks/scaffold/utils.ts +19 -0
- package/src/components/blocks/shell/__tests__/shell-fit-atom.test.tsx +360 -0
- package/src/components/blocks/shell/__tests__/shell-layout.test.tsx +192 -3
- package/src/components/blocks/shell/__tests__/shell-metrics.test.ts +108 -0
- package/src/components/blocks/shell/animated-panel-inset.tsx +5 -1
- package/src/components/blocks/shell/animated-panel-provider.tsx +77 -11
- package/src/components/blocks/shell/animated-panel-trigger.tsx +4 -0
- package/src/components/blocks/shell/animated-panel.tsx +126 -29
- package/src/components/blocks/shell/index.ts +18 -0
- package/src/components/blocks/shell/shell-fit-atom.ts +243 -0
- package/src/components/blocks/shell/shell-layout.tsx +55 -53
- package/src/components/blocks/shell/shell-metrics.ts +79 -0
- package/src/components/blocks/shell/type.ts +130 -3
- package/src/components/blocks/shell/use-shell-fit-state.ts +49 -0
- package/src/components/blocks/shell/use-shell-fit.ts +135 -0
- package/src/components/blocks/shell/use-shell-panels.ts +57 -4
- package/src/components/blocks/shell/utils.ts +44 -4
- package/src/components/composed/tree/CLAUDE.md +132 -0
- package/src/components/composed/tree/__tests__/tree-atom.test.tsx +217 -0
- package/src/components/composed/tree/__tests__/tree.test.tsx +525 -0
- package/src/components/composed/tree/__tests__/use-tree.test.tsx +333 -0
- package/src/components/composed/tree/constants.ts +60 -0
- package/src/components/composed/tree/index.ts +51 -0
- package/src/components/composed/tree/tree-atom.ts +590 -0
- package/src/components/composed/tree/tree-context.ts +13 -0
- package/src/components/composed/tree/tree-node.tsx +490 -0
- package/src/components/composed/tree/tree.tsx +286 -0
- package/src/components/composed/tree/type.ts +322 -0
- package/src/components/composed/tree/use-tree-dnd.ts +179 -0
- package/src/components/composed/tree/use-tree-state.ts +105 -0
- package/src/components/composed/tree/use-tree.ts +307 -0
- package/src/components/composed/tree/utils.ts +172 -0
- package/src/components/composed/user-avatar.tsx +11 -96
- package/src/components/docs/component-preview.tsx +11 -11
- package/src/components/user-avatar/__tests__/user-avatar.test.tsx +245 -0
- package/src/components/user-avatar/audio-wave.tsx +22 -0
- package/src/components/user-avatar/component.tsx +152 -0
- package/src/components/user-avatar/fallback.tsx +26 -0
- package/src/components/user-avatar/index.ts +34 -0
- package/src/components/user-avatar/presence-badge.tsx +56 -0
- package/src/components/user-avatar/type.ts +85 -0
- package/src/components/user-avatar/use-user-avatar-state.ts +60 -0
- package/src/components/user-avatar/use-user-avatar.ts +144 -0
- package/src/components/user-avatar/user-avatar-atom.ts +198 -0
- package/src/components/user-avatar/utils.ts +8 -0
- package/src/index.css +211 -153
- package/src/index.ts +35 -2
- package/src/state/exegia-provider.tsx +79 -0
- package/src/state/index.ts +4 -0
- package/src/state/store.ts +19 -0
|
@@ -6,95 +6,241 @@ import {
|
|
|
6
6
|
useCallback,
|
|
7
7
|
useEffect,
|
|
8
8
|
useId,
|
|
9
|
+
useLayoutEffect,
|
|
9
10
|
useMemo,
|
|
10
11
|
useRef,
|
|
11
12
|
useState,
|
|
12
13
|
} from "react";
|
|
14
|
+
import { useAtomValue, useSetAtom, useStore } from "jotai";
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
aiSidebarAnnouncementAtom,
|
|
18
|
+
aiSidebarDraggingIdAtom,
|
|
19
|
+
aiSidebarDropTargetAtom,
|
|
20
|
+
aiSidebarExpandedIdsAtom,
|
|
21
|
+
aiSidebarFlatAtom,
|
|
22
|
+
aiSidebarFocusedIdAtom,
|
|
23
|
+
aiSidebarHoveredIdAtom,
|
|
24
|
+
aiSidebarItemsAtom,
|
|
25
|
+
aiSidebarMenuOpenIdAtom,
|
|
26
|
+
aiSidebarMovePendingAtom,
|
|
27
|
+
aiSidebarOwnActiveIdAtom,
|
|
28
|
+
aiSidebarOwnedExpandedIdsAtom,
|
|
29
|
+
aiSidebarOwnedItemsAtom,
|
|
30
|
+
aiSidebarRenamingIdAtom,
|
|
31
|
+
cancelAISidebarRenameAtom,
|
|
32
|
+
clearAISidebarHoverAtom,
|
|
33
|
+
closeAISidebarMenuAtom,
|
|
34
|
+
collapseAISidebarRowAtom,
|
|
35
|
+
collapseAllAISidebarRowsAtom,
|
|
36
|
+
endAISidebarDragAtom,
|
|
37
|
+
expandAISidebarRowAtom,
|
|
38
|
+
expandAllAISidebarRowsAtom,
|
|
39
|
+
focusAISidebarRowAtom,
|
|
40
|
+
mountAISidebarAtom,
|
|
41
|
+
moveAISidebarRowAtom,
|
|
42
|
+
normalizeAISidebarFocusAtom,
|
|
43
|
+
openAISidebarMenuAtom,
|
|
44
|
+
projectAISidebarActiveIdAtom,
|
|
45
|
+
projectAISidebarExpandedIdsAtom,
|
|
46
|
+
projectAISidebarItemsAtom,
|
|
47
|
+
removeAISidebarInstance,
|
|
48
|
+
renameAISidebarRowAtom,
|
|
49
|
+
resetAISidebarAtom,
|
|
50
|
+
revealAISidebarRowAtom,
|
|
51
|
+
selectAISidebarRowAtom,
|
|
52
|
+
setAISidebarHandlersAtom,
|
|
53
|
+
setAISidebarHoveredAtom,
|
|
54
|
+
startAISidebarRenameAtom,
|
|
55
|
+
toggleAISidebarRowAtom,
|
|
56
|
+
} from "./ai-sidebar-atom.ts";
|
|
13
57
|
import type {
|
|
14
|
-
|
|
15
|
-
|
|
58
|
+
AISidebarConfig,
|
|
59
|
+
AISidebarController,
|
|
60
|
+
AISidebarHandlers,
|
|
61
|
+
AISidebarSeed,
|
|
16
62
|
FlatResource,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from "./type.ts"
|
|
63
|
+
UseAISidebarOptions,
|
|
64
|
+
} from "./type.ts";
|
|
20
65
|
import {
|
|
21
66
|
canContain,
|
|
22
67
|
containsResource,
|
|
23
68
|
findResource,
|
|
24
69
|
flattenResources,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
70
|
+
} from "./utils.ts";
|
|
71
|
+
|
|
72
|
+
export type { UseAISidebarOptions };
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The AI sidebar's headless controller — every behaviour the block
|
|
76
|
+
* performs, callable from outside it: select, expand/collapse (one row,
|
|
77
|
+
* every row, or just the ancestors of one), move focus, rename, open a
|
|
78
|
+
* row's action menu, reorder.
|
|
79
|
+
*
|
|
80
|
+
* `items`, `activeId` and `expandedIds` are each controlled when passed
|
|
81
|
+
* and hook-owned via their `default*` twin otherwise. Reorder and rename
|
|
82
|
+
* are applied to the data optimistically and rolled back if
|
|
83
|
+
* `onMove`/`onRename` rejects, so a consumer never reduces the tree
|
|
84
|
+
* itself — `moveResource` and `renameResource` are exported for the ones
|
|
85
|
+
* who keep their data elsewhere.
|
|
86
|
+
*
|
|
87
|
+
* ```tsx
|
|
88
|
+
* const sidebar = useAISidebar({ defaultItems: resources })
|
|
89
|
+
* <AISidebar controller={sidebar} />
|
|
90
|
+
* <Button onClick={sidebar.collapseAll}>Collapse all</Button>
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* State lives in Jotai atoms keyed by `sidebarId`, so anything under
|
|
94
|
+
* `ExegiaProvider` can drive this sidebar without the controller — name it
|
|
95
|
+
* and reach for `useAISidebarState(sidebarId)` /
|
|
96
|
+
* `useAISidebarActions(sidebarId)` elsewhere.
|
|
97
|
+
*/
|
|
98
|
+
export function useAISidebar(
|
|
99
|
+
options: UseAISidebarOptions
|
|
100
|
+
): AISidebarController {
|
|
101
|
+
const {
|
|
102
|
+
items,
|
|
103
|
+
defaultItems = [],
|
|
104
|
+
onItemsChange,
|
|
105
|
+
onMove,
|
|
106
|
+
onMoveError,
|
|
107
|
+
onRename,
|
|
108
|
+
activeId,
|
|
109
|
+
defaultActiveId = null,
|
|
110
|
+
onActiveChange,
|
|
111
|
+
onExpandedChange,
|
|
112
|
+
} = options;
|
|
113
|
+
|
|
114
|
+
// A generated key isolates unnamed sidebars from each other; an explicit
|
|
115
|
+
// `sidebarId` is the app's handle on this one.
|
|
116
|
+
const generatedId = useId();
|
|
117
|
+
const sidebarId = options.sidebarId ?? generatedId;
|
|
118
|
+
const store = useStore();
|
|
119
|
+
const hoverLayoutId = useId();
|
|
120
|
+
|
|
121
|
+
const controlledExpandedIds = options.expandedIds;
|
|
122
|
+
const controlsItems = items !== undefined;
|
|
123
|
+
const controlsActiveId = activeId !== undefined;
|
|
124
|
+
const controlsExpandedIds = controlledExpandedIds !== undefined;
|
|
125
|
+
|
|
126
|
+
// Primitives only, so this object is stable and the store write below runs
|
|
127
|
+
// once per real change rather than once per render.
|
|
128
|
+
const config = useMemo<AISidebarConfig>(
|
|
129
|
+
() => ({ controlsItems, controlsActiveId, controlsExpandedIds }),
|
|
130
|
+
[controlsActiveId, controlsExpandedIds, controlsItems]
|
|
59
131
|
);
|
|
60
|
-
|
|
61
|
-
|
|
132
|
+
|
|
133
|
+
const handlers = useMemo<AISidebarHandlers>(
|
|
134
|
+
() => ({
|
|
135
|
+
onItemsChange,
|
|
136
|
+
onMove,
|
|
137
|
+
onMoveError,
|
|
138
|
+
onRename,
|
|
139
|
+
onActiveChange,
|
|
140
|
+
onExpandedChange,
|
|
141
|
+
}),
|
|
142
|
+
[
|
|
143
|
+
onActiveChange,
|
|
144
|
+
onExpandedChange,
|
|
145
|
+
onItemsChange,
|
|
146
|
+
onMove,
|
|
147
|
+
onMoveError,
|
|
148
|
+
onRename,
|
|
149
|
+
]
|
|
62
150
|
);
|
|
63
|
-
const [draggingId, setDraggingId] = useState<string | null>(null);
|
|
64
|
-
const [dropTarget, setDropTarget] = useState<DropTarget | null>(null);
|
|
65
|
-
const [menuOpenId, setMenuOpenId] = useState<string | null>(null);
|
|
66
|
-
const [renamingId, setRenamingId] = useState<string | null>(null);
|
|
67
|
-
const [hoveredId, setHoveredId] = useState<string | null>(null);
|
|
68
|
-
const hoverLayoutId = useId();
|
|
69
|
-
const [announcement, setAnnouncement] = useState("");
|
|
70
|
-
const rowRefs = useRef(new Map<string, HTMLDivElement>());
|
|
71
|
-
const movePendingRef = useRef(false);
|
|
72
|
-
const renderedItems = internalItems;
|
|
73
|
-
const selectedId = activeId ?? internalActiveId;
|
|
74
151
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
152
|
+
// Read once: the `default*` options describe the mount, not every render.
|
|
153
|
+
const [seed] = useState<AISidebarSeed>(() => ({
|
|
154
|
+
items: items ?? defaultItems,
|
|
155
|
+
activeId: defaultActiveId,
|
|
156
|
+
focusedId: activeId ?? defaultActiveId,
|
|
157
|
+
expandedIds: [
|
|
158
|
+
...(controlledExpandedIds ?? options.defaultExpandedIds ?? []),
|
|
159
|
+
],
|
|
160
|
+
}));
|
|
161
|
+
|
|
162
|
+
const mount = useSetAtom(mountAISidebarAtom(sidebarId));
|
|
163
|
+
const publishHandlers = useSetAtom(setAISidebarHandlersAtom(sidebarId));
|
|
164
|
+
const projectItems = useSetAtom(projectAISidebarItemsAtom(sidebarId));
|
|
165
|
+
const projectActiveId = useSetAtom(projectAISidebarActiveIdAtom(sidebarId));
|
|
166
|
+
const projectExpandedIds = useSetAtom(
|
|
167
|
+
projectAISidebarExpandedIdsAtom(sidebarId)
|
|
168
|
+
);
|
|
169
|
+
const normalizeFocus = useSetAtom(normalizeAISidebarFocusAtom(sidebarId));
|
|
170
|
+
|
|
171
|
+
// Handlers first — they must be in the store before any action can fire.
|
|
172
|
+
// Rewritten every commit; no read atom depends on them, so nobody
|
|
173
|
+
// re-renders for it.
|
|
174
|
+
useLayoutEffect(() => {
|
|
175
|
+
publishHandlers(handlers);
|
|
176
|
+
}, [handlers, publishHandlers]);
|
|
177
|
+
|
|
178
|
+
// Before paint, so a seeded row never paints closed for a frame.
|
|
179
|
+
useLayoutEffect(() => {
|
|
180
|
+
mount(config, seed);
|
|
181
|
+
}, [config, mount, seed]);
|
|
182
|
+
|
|
183
|
+
// Controlled props stay the source of truth; the store carries a projection
|
|
184
|
+
// so the action atoms and remote readers see current data.
|
|
185
|
+
useLayoutEffect(() => {
|
|
186
|
+
if (items !== undefined) projectItems(items);
|
|
187
|
+
}, [items, projectItems]);
|
|
188
|
+
|
|
189
|
+
useLayoutEffect(() => {
|
|
190
|
+
if (activeId !== undefined) projectActiveId(activeId);
|
|
191
|
+
}, [activeId, projectActiveId]);
|
|
192
|
+
|
|
193
|
+
useLayoutEffect(() => {
|
|
194
|
+
if (controlledExpandedIds !== undefined)
|
|
195
|
+
projectExpandedIds(controlledExpandedIds);
|
|
196
|
+
}, [controlledExpandedIds, projectExpandedIds]);
|
|
197
|
+
|
|
198
|
+
// A sidebar the hook keyed is scrap once its component goes. An explicit
|
|
199
|
+
// `sidebarId` is the app's key and outlives the mount.
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
if (options.sidebarId !== undefined) return;
|
|
202
|
+
return () => removeAISidebarInstance(sidebarId);
|
|
203
|
+
}, [options.sidebarId, sidebarId]);
|
|
204
|
+
|
|
205
|
+
// Never `aiSidebarItemsAtom` — see the note on `aiSidebarOwnedItemsAtom`.
|
|
206
|
+
const ownedItems = useAtomValue(aiSidebarOwnedItemsAtom(sidebarId));
|
|
207
|
+
const renderedItems = items ?? ownedItems;
|
|
208
|
+
// `activeId ?? own` rather than the projected atom: a controlled `activeId`
|
|
209
|
+
// of `null` has always fallen through to the hook-owned selection.
|
|
210
|
+
const ownActiveId = useAtomValue(aiSidebarOwnActiveIdAtom(sidebarId));
|
|
211
|
+
const selectedId = activeId ?? ownActiveId;
|
|
212
|
+
const ownExpandedIds = useAtomValue(aiSidebarOwnedExpandedIdsAtom(sidebarId));
|
|
213
|
+
const expandedIds = useMemo(
|
|
214
|
+
() =>
|
|
215
|
+
controlledExpandedIds ? new Set(controlledExpandedIds) : ownExpandedIds,
|
|
216
|
+
[controlledExpandedIds, ownExpandedIds]
|
|
217
|
+
);
|
|
218
|
+
const focusedId = useAtomValue(aiSidebarFocusedIdAtom(sidebarId));
|
|
219
|
+
const renamingId = useAtomValue(aiSidebarRenamingIdAtom(sidebarId));
|
|
220
|
+
const menuOpenId = useAtomValue(aiSidebarMenuOpenIdAtom(sidebarId));
|
|
221
|
+
const draggingId = useAtomValue(aiSidebarDraggingIdAtom(sidebarId));
|
|
222
|
+
const dropTarget = useAtomValue(aiSidebarDropTargetAtom(sidebarId));
|
|
223
|
+
const hoveredId = useAtomValue(aiSidebarHoveredIdAtom(sidebarId));
|
|
224
|
+
const announcement = useAtomValue(aiSidebarAnnouncementAtom(sidebarId));
|
|
225
|
+
const movePending = useAtomValue(aiSidebarMovePendingAtom(sidebarId));
|
|
80
226
|
|
|
81
227
|
const flat = useMemo(
|
|
82
228
|
() => flattenResources(renderedItems, expandedIds),
|
|
83
|
-
[expandedIds, renderedItems]
|
|
229
|
+
[expandedIds, renderedItems]
|
|
84
230
|
);
|
|
85
231
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
232
|
+
// The roving target must name a row that still renders: one that folds away
|
|
233
|
+
// hands focus to the first visible row instead of pointing at nothing. Last
|
|
234
|
+
// of the layout effects, so it reads the projections this commit wrote.
|
|
235
|
+
useLayoutEffect(() => {
|
|
236
|
+
normalizeFocus();
|
|
237
|
+
}, [flat, focusedId, normalizeFocus]);
|
|
92
238
|
|
|
93
239
|
useEffect(() => {
|
|
94
240
|
if (!menuOpenId) return;
|
|
95
241
|
const frame = requestAnimationFrame(() => {
|
|
96
242
|
const menus = Array.from(
|
|
97
|
-
document.querySelectorAll<HTMLElement>("[data-sidebar-resource-menu]")
|
|
243
|
+
document.querySelectorAll<HTMLElement>("[data-sidebar-resource-menu]")
|
|
98
244
|
);
|
|
99
245
|
menus
|
|
100
246
|
.find((menu) => menu.dataset.sidebarResourceMenu === menuOpenId)
|
|
@@ -104,107 +250,112 @@ export function useAISidebar({
|
|
|
104
250
|
return () => cancelAnimationFrame(frame);
|
|
105
251
|
}, [menuOpenId]);
|
|
106
252
|
|
|
107
|
-
const
|
|
108
|
-
(
|
|
109
|
-
|
|
110
|
-
onItemsChange?.(next);
|
|
111
|
-
},
|
|
112
|
-
[onItemsChange],
|
|
253
|
+
const getItem = useCallback(
|
|
254
|
+
(id: string) => findResource(renderedItems, id),
|
|
255
|
+
[renderedItems]
|
|
113
256
|
);
|
|
114
257
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
setAnnouncement("Wait for the current move to finish.");
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const before = renderedItems;
|
|
122
|
-
const next = moveResource(before, move);
|
|
123
|
-
if (!next || next === before) return;
|
|
124
|
-
|
|
125
|
-
movePendingRef.current = true;
|
|
126
|
-
updateItems(next);
|
|
127
|
-
setDropTarget(null);
|
|
128
|
-
setDraggingId(null);
|
|
129
|
-
const moved = findResource(before, move.itemId);
|
|
130
|
-
const target = move.targetId ? findResource(before, move.targetId) : null;
|
|
131
|
-
setAnnouncement(
|
|
132
|
-
target
|
|
133
|
-
? `Moved ${moved?.label ?? "item"} ${move.position} ${target.label}.`
|
|
134
|
-
: `Moved ${moved?.label ?? "item"} to the top level.`,
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
await onMove?.(move);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
updateItems(before);
|
|
141
|
-
setAnnouncement(`Move failed. ${moved?.label ?? "Item"} was restored.`);
|
|
142
|
-
onMoveError?.(error, move);
|
|
143
|
-
} finally {
|
|
144
|
-
movePendingRef.current = false;
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
[onMove, onMoveError, renderedItems, updateItems],
|
|
258
|
+
const isExpanded = useCallback(
|
|
259
|
+
(id: string) => expandedIds.has(id),
|
|
260
|
+
[expandedIds]
|
|
148
261
|
);
|
|
149
262
|
|
|
263
|
+
// `useSetAtom` setters are already stable — no useCallback needed.
|
|
264
|
+
const select = useSetAtom(selectAISidebarRowAtom(sidebarId));
|
|
265
|
+
const expand = useSetAtom(expandAISidebarRowAtom(sidebarId));
|
|
266
|
+
const collapse = useSetAtom(collapseAISidebarRowAtom(sidebarId));
|
|
267
|
+
const toggleExpanded = useSetAtom(toggleAISidebarRowAtom(sidebarId));
|
|
268
|
+
const expandAll = useSetAtom(expandAllAISidebarRowsAtom(sidebarId));
|
|
269
|
+
const collapseAll = useSetAtom(collapseAllAISidebarRowsAtom(sidebarId));
|
|
270
|
+
const reveal = useSetAtom(revealAISidebarRowAtom(sidebarId));
|
|
271
|
+
const startRename = useSetAtom(startAISidebarRenameAtom(sidebarId));
|
|
272
|
+
const cancelRename = useSetAtom(cancelAISidebarRenameAtom(sidebarId));
|
|
273
|
+
const rename = useSetAtom(renameAISidebarRowAtom(sidebarId));
|
|
274
|
+
const openMenu = useSetAtom(openAISidebarMenuAtom(sidebarId));
|
|
275
|
+
const closeMenuInStore = useSetAtom(closeAISidebarMenuAtom(sidebarId));
|
|
276
|
+
const move = useSetAtom(moveAISidebarRowAtom(sidebarId));
|
|
277
|
+
const reset = useSetAtom(resetAISidebarAtom(sidebarId));
|
|
278
|
+
const setFocusedRow = useSetAtom(focusAISidebarRowAtom(sidebarId));
|
|
279
|
+
const onRowHover = useSetAtom(setAISidebarHoveredAtom(sidebarId));
|
|
280
|
+
const clearHover = useSetAtom(clearAISidebarHoverAtom(sidebarId));
|
|
281
|
+
const onRowDragEnd = useSetAtom(endAISidebarDragAtom(sidebarId));
|
|
282
|
+
const setDraggingId = useSetAtom(aiSidebarDraggingIdAtom(sidebarId));
|
|
283
|
+
const setDropTarget = useSetAtom(aiSidebarDropTargetAtom(sidebarId));
|
|
284
|
+
|
|
285
|
+
// The one piece of row state that cannot live in the store: these are DOM
|
|
286
|
+
// nodes. The block owns them, and every DOM focus move goes through here.
|
|
287
|
+
const rowRefs = useRef(new Map<string, HTMLDivElement>());
|
|
288
|
+
|
|
289
|
+
const setRowRef = useCallback((id: string, node: HTMLDivElement | null) => {
|
|
290
|
+
if (node) rowRefs.current.set(id, node);
|
|
291
|
+
else rowRefs.current.delete(id);
|
|
292
|
+
}, []);
|
|
293
|
+
|
|
150
294
|
const focusRow = useCallback((id: string) => {
|
|
151
|
-
setFocusedId(id);
|
|
152
295
|
requestAnimationFrame(() => rowRefs.current.get(id)?.focus());
|
|
153
296
|
}, []);
|
|
154
297
|
|
|
155
|
-
const
|
|
298
|
+
const focus = useCallback(
|
|
156
299
|
(id: string) => {
|
|
157
|
-
|
|
158
|
-
|
|
300
|
+
setFocusedRow(id);
|
|
301
|
+
focusRow(id);
|
|
159
302
|
},
|
|
160
|
-
[
|
|
303
|
+
[focusRow, setFocusedRow]
|
|
161
304
|
);
|
|
162
305
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
306
|
+
// Closing returns focus to the row that owned the menu — otherwise focus
|
|
307
|
+
// falls back to the body and the keyboard user loses their place. The atom
|
|
308
|
+
// hands back the id it closed so only the DOM half happens here.
|
|
309
|
+
const closeMenu = useCallback(() => {
|
|
310
|
+
const closed = closeMenuInStore();
|
|
311
|
+
if (closed) focusRow(closed);
|
|
312
|
+
}, [closeMenuInStore, focusRow]);
|
|
313
|
+
|
|
314
|
+
// Roving nav reads the visible rows out of the store when a key lands
|
|
315
|
+
// rather than closing over them, so one stable handler serves every row.
|
|
316
|
+
const readFlat = useCallback(
|
|
317
|
+
() => store.get(aiSidebarFlatAtom(sidebarId)),
|
|
318
|
+
[sidebarId, store]
|
|
319
|
+
);
|
|
171
320
|
|
|
172
|
-
const
|
|
321
|
+
const onRowKeyDown = useCallback(
|
|
173
322
|
(event: KeyboardEvent<HTMLDivElement>, row: FlatResource) => {
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
const
|
|
323
|
+
const flatRows = readFlat();
|
|
324
|
+
const expanded = store.get(aiSidebarExpandedIdsAtom(sidebarId));
|
|
325
|
+
const index = flatRows.findIndex(({ item }) => item.id === row.item.id);
|
|
326
|
+
const previous = flatRows[index - 1];
|
|
327
|
+
const next = flatRows[index + 1];
|
|
177
328
|
const moveModifier = event.altKey && event.shiftKey;
|
|
178
329
|
|
|
179
330
|
if (event.key === "ArrowDown" && !moveModifier && next) {
|
|
180
331
|
event.preventDefault();
|
|
181
|
-
|
|
332
|
+
focus(next.item.id);
|
|
182
333
|
return;
|
|
183
334
|
}
|
|
184
335
|
if (event.key === "ArrowUp" && !moveModifier && previous) {
|
|
185
336
|
event.preventDefault();
|
|
186
|
-
|
|
337
|
+
focus(previous.item.id);
|
|
187
338
|
return;
|
|
188
339
|
}
|
|
189
|
-
if (event.key === "Home" &&
|
|
340
|
+
if (event.key === "Home" && flatRows[0]) {
|
|
190
341
|
event.preventDefault();
|
|
191
|
-
|
|
342
|
+
focus(flatRows[0].item.id);
|
|
192
343
|
return;
|
|
193
344
|
}
|
|
194
|
-
if (event.key === "End" &&
|
|
345
|
+
if (event.key === "End" && flatRows.at(-1)) {
|
|
195
346
|
event.preventDefault();
|
|
196
|
-
|
|
347
|
+
focus(flatRows.at(-1)?.item.id ?? row.item.id);
|
|
197
348
|
return;
|
|
198
349
|
}
|
|
199
350
|
|
|
200
351
|
if (row.item.disabled) {
|
|
201
352
|
if (event.key === "ArrowLeft" && row.parentId) {
|
|
202
353
|
event.preventDefault();
|
|
203
|
-
|
|
354
|
+
focus(row.parentId);
|
|
204
355
|
} else if (
|
|
205
356
|
moveModifier ||
|
|
206
357
|
["ArrowRight", "Enter", " ", "F2", "ContextMenu"].includes(
|
|
207
|
-
event.key
|
|
358
|
+
event.key
|
|
208
359
|
) ||
|
|
209
360
|
(event.shiftKey && event.key === "F10")
|
|
210
361
|
) {
|
|
@@ -215,91 +366,135 @@ export function useAISidebar({
|
|
|
215
366
|
|
|
216
367
|
if (moveModifier && event.key === "ArrowUp" && previous) {
|
|
217
368
|
event.preventDefault();
|
|
218
|
-
void
|
|
369
|
+
void move({
|
|
370
|
+
itemId: row.item.id,
|
|
371
|
+
targetId: previous.item.id,
|
|
372
|
+
position: "before",
|
|
373
|
+
});
|
|
219
374
|
return;
|
|
220
375
|
}
|
|
221
376
|
if (moveModifier && event.key === "ArrowDown" && next) {
|
|
222
377
|
event.preventDefault();
|
|
223
|
-
void
|
|
378
|
+
void move({
|
|
379
|
+
itemId: row.item.id,
|
|
380
|
+
targetId: next.item.id,
|
|
381
|
+
position: "after",
|
|
382
|
+
});
|
|
224
383
|
return;
|
|
225
384
|
}
|
|
226
|
-
if (
|
|
385
|
+
if (
|
|
386
|
+
moveModifier &&
|
|
387
|
+
event.key === "ArrowRight" &&
|
|
388
|
+
previous &&
|
|
389
|
+
canContain(previous.item)
|
|
390
|
+
) {
|
|
227
391
|
event.preventDefault();
|
|
228
|
-
|
|
229
|
-
void
|
|
392
|
+
expand(previous.item.id);
|
|
393
|
+
void move({
|
|
394
|
+
itemId: row.item.id,
|
|
395
|
+
targetId: previous.item.id,
|
|
396
|
+
position: "inside",
|
|
397
|
+
});
|
|
230
398
|
return;
|
|
231
399
|
}
|
|
232
400
|
if (moveModifier && event.key === "ArrowLeft" && row.parentId) {
|
|
233
401
|
event.preventDefault();
|
|
234
|
-
void
|
|
402
|
+
void move({
|
|
403
|
+
itemId: row.item.id,
|
|
404
|
+
targetId: row.parentId,
|
|
405
|
+
position: "after",
|
|
406
|
+
});
|
|
235
407
|
return;
|
|
236
408
|
}
|
|
237
409
|
|
|
238
410
|
if (event.key === "ArrowRight" && canContain(row.item)) {
|
|
239
411
|
event.preventDefault();
|
|
240
|
-
if (!
|
|
241
|
-
else if (next?.parentId === row.item.id)
|
|
412
|
+
if (!expanded.has(row.item.id)) expand(row.item.id);
|
|
413
|
+
else if (next?.parentId === row.item.id) focus(next.item.id);
|
|
242
414
|
} else if (event.key === "ArrowLeft") {
|
|
243
415
|
event.preventDefault();
|
|
244
|
-
if (
|
|
245
|
-
else if (row.parentId)
|
|
416
|
+
if (expanded.has(row.item.id)) collapse(row.item.id);
|
|
417
|
+
else if (row.parentId) focus(row.parentId);
|
|
246
418
|
} else if (event.key === "Enter" || event.key === " ") {
|
|
247
419
|
event.preventDefault();
|
|
248
|
-
if (canContain(row.item))
|
|
420
|
+
if (canContain(row.item)) toggleExpanded(row.item.id);
|
|
249
421
|
else select(row.item.id);
|
|
250
422
|
} else if (event.key === "F2") {
|
|
251
423
|
event.preventDefault();
|
|
252
|
-
|
|
253
|
-
} else if (
|
|
424
|
+
startRename(row.item.id);
|
|
425
|
+
} else if (
|
|
426
|
+
event.key === "ContextMenu" ||
|
|
427
|
+
(event.shiftKey && event.key === "F10")
|
|
428
|
+
) {
|
|
254
429
|
event.preventDefault();
|
|
255
|
-
|
|
430
|
+
openMenu(row.item.id);
|
|
256
431
|
}
|
|
257
432
|
},
|
|
258
|
-
[
|
|
433
|
+
[
|
|
434
|
+
collapse,
|
|
435
|
+
expand,
|
|
436
|
+
focus,
|
|
437
|
+
move,
|
|
438
|
+
openMenu,
|
|
439
|
+
readFlat,
|
|
440
|
+
select,
|
|
441
|
+
sidebarId,
|
|
442
|
+
startRename,
|
|
443
|
+
store,
|
|
444
|
+
toggleExpanded,
|
|
445
|
+
]
|
|
259
446
|
);
|
|
260
447
|
|
|
261
|
-
|
|
448
|
+
// The drag handlers read drag state out of the store when they run instead
|
|
449
|
+
// of closing over it. That is what keeps them stable for the life of the
|
|
450
|
+
// sidebar, so every row can share one set without re-rendering on a drag.
|
|
451
|
+
const onRootDragOver = useCallback(
|
|
262
452
|
(event: DragEvent<HTMLDivElement>) => {
|
|
263
|
-
if (
|
|
453
|
+
if (
|
|
454
|
+
!store.get(aiSidebarDraggingIdAtom(sidebarId)) ||
|
|
455
|
+
event.target !== event.currentTarget
|
|
456
|
+
)
|
|
457
|
+
return;
|
|
264
458
|
event.preventDefault();
|
|
265
459
|
setDropTarget({ id: null, position: "after" });
|
|
266
460
|
},
|
|
267
|
-
[
|
|
461
|
+
[setDropTarget, sidebarId, store]
|
|
268
462
|
);
|
|
269
463
|
|
|
270
|
-
const
|
|
464
|
+
const onDrop = useCallback(
|
|
271
465
|
(event: DragEvent<HTMLDivElement>) => {
|
|
272
466
|
event.preventDefault();
|
|
273
467
|
event.stopPropagation();
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
468
|
+
const dragging = store.get(aiSidebarDraggingIdAtom(sidebarId));
|
|
469
|
+
const target = store.get(aiSidebarDropTargetAtom(sidebarId));
|
|
470
|
+
if (dragging && target) {
|
|
471
|
+
void move({
|
|
472
|
+
itemId: dragging,
|
|
473
|
+
targetId: target.id,
|
|
474
|
+
position: target.position,
|
|
279
475
|
});
|
|
280
476
|
}
|
|
281
477
|
},
|
|
282
|
-
[
|
|
478
|
+
[move, sidebarId, store]
|
|
283
479
|
);
|
|
284
480
|
|
|
285
|
-
const
|
|
481
|
+
const onRowDragStart = useCallback(
|
|
286
482
|
(event: DragEvent<HTMLDivElement>, id: string) => {
|
|
287
483
|
setDraggingId(id);
|
|
288
484
|
event.dataTransfer.effectAllowed = "move";
|
|
289
485
|
event.dataTransfer.setData("text/plain", id);
|
|
290
486
|
},
|
|
291
|
-
[]
|
|
487
|
+
[setDraggingId]
|
|
292
488
|
);
|
|
293
489
|
|
|
294
|
-
const
|
|
295
|
-
setDraggingId(null);
|
|
296
|
-
setDropTarget(null);
|
|
297
|
-
}, []);
|
|
298
|
-
|
|
299
|
-
const handleRowDragOver = useCallback(
|
|
490
|
+
const onRowDragOver = useCallback(
|
|
300
491
|
(event: DragEvent<HTMLDivElement>, targetRow: FlatResource) => {
|
|
301
|
-
|
|
302
|
-
|
|
492
|
+
const dragging = store.get(aiSidebarDraggingIdAtom(sidebarId));
|
|
493
|
+
if (!dragging || dragging === targetRow.item.id) return;
|
|
494
|
+
const source = findResource(
|
|
495
|
+
store.get(aiSidebarItemsAtom(sidebarId)),
|
|
496
|
+
dragging
|
|
497
|
+
);
|
|
303
498
|
if (source && containsResource(source, targetRow.item.id)) return;
|
|
304
499
|
event.preventDefault();
|
|
305
500
|
event.stopPropagation();
|
|
@@ -316,71 +511,106 @@ export function useAISidebar({
|
|
|
316
511
|
: "after";
|
|
317
512
|
setDropTarget({ id: targetRow.item.id, position });
|
|
318
513
|
},
|
|
319
|
-
[
|
|
514
|
+
[setDropTarget, sidebarId, store]
|
|
320
515
|
);
|
|
321
516
|
|
|
322
|
-
const
|
|
323
|
-
(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
517
|
+
const dnd = useMemo(
|
|
518
|
+
() => ({
|
|
519
|
+
draggingId,
|
|
520
|
+
dropTarget,
|
|
521
|
+
onRootDragOver,
|
|
522
|
+
onDrop,
|
|
523
|
+
onRowDragStart,
|
|
524
|
+
onRowDragEnd,
|
|
525
|
+
onRowDragOver,
|
|
526
|
+
}),
|
|
527
|
+
[
|
|
528
|
+
draggingId,
|
|
529
|
+
dropTarget,
|
|
530
|
+
onRootDragOver,
|
|
531
|
+
onDrop,
|
|
532
|
+
onRowDragStart,
|
|
533
|
+
onRowDragEnd,
|
|
534
|
+
onRowDragOver,
|
|
535
|
+
]
|
|
335
536
|
);
|
|
336
537
|
|
|
337
|
-
const
|
|
338
|
-
(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
538
|
+
const hover = useMemo(
|
|
539
|
+
() => ({
|
|
540
|
+
hoveredId,
|
|
541
|
+
layoutId: hoverLayoutId,
|
|
542
|
+
onRowHover,
|
|
543
|
+
clear: clearHover,
|
|
544
|
+
}),
|
|
545
|
+
[clearHover, hoverLayoutId, hoveredId, onRowHover]
|
|
343
546
|
);
|
|
344
547
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
548
|
+
return useMemo<AISidebarController>(
|
|
549
|
+
() => ({
|
|
550
|
+
sidebarId,
|
|
551
|
+
items: renderedItems,
|
|
552
|
+
flat,
|
|
553
|
+
getItem,
|
|
554
|
+
selectedId,
|
|
555
|
+
select,
|
|
556
|
+
expandedIds,
|
|
557
|
+
isExpanded,
|
|
558
|
+
expand,
|
|
559
|
+
collapse,
|
|
560
|
+
toggleExpanded,
|
|
561
|
+
expandAll,
|
|
562
|
+
collapseAll,
|
|
563
|
+
reveal,
|
|
564
|
+
focusedId,
|
|
565
|
+
focus,
|
|
566
|
+
renamingId,
|
|
567
|
+
startRename,
|
|
568
|
+
cancelRename,
|
|
569
|
+
rename,
|
|
570
|
+
menuOpenId,
|
|
571
|
+
openMenu,
|
|
572
|
+
closeMenu,
|
|
573
|
+
move,
|
|
574
|
+
movePending,
|
|
575
|
+
announcement,
|
|
576
|
+
reset,
|
|
577
|
+
dnd,
|
|
578
|
+
hover,
|
|
579
|
+
onRowKeyDown,
|
|
580
|
+
setRowRef,
|
|
581
|
+
}),
|
|
582
|
+
[
|
|
583
|
+
sidebarId,
|
|
584
|
+
renderedItems,
|
|
585
|
+
flat,
|
|
586
|
+
getItem,
|
|
587
|
+
selectedId,
|
|
588
|
+
select,
|
|
589
|
+
expandedIds,
|
|
590
|
+
isExpanded,
|
|
591
|
+
expand,
|
|
592
|
+
collapse,
|
|
593
|
+
toggleExpanded,
|
|
594
|
+
expandAll,
|
|
595
|
+
collapseAll,
|
|
596
|
+
reveal,
|
|
597
|
+
focusedId,
|
|
598
|
+
focus,
|
|
599
|
+
renamingId,
|
|
600
|
+
startRename,
|
|
601
|
+
cancelRename,
|
|
602
|
+
rename,
|
|
603
|
+
menuOpenId,
|
|
604
|
+
openMenu,
|
|
605
|
+
closeMenu,
|
|
606
|
+
move,
|
|
607
|
+
movePending,
|
|
608
|
+
announcement,
|
|
609
|
+
reset,
|
|
610
|
+
dnd,
|
|
611
|
+
hover,
|
|
612
|
+
onRowKeyDown,
|
|
613
|
+
setRowRef,
|
|
614
|
+
]
|
|
615
|
+
);
|
|
386
616
|
}
|