@dxos/plugin-navtree 0.8.4-main.fffef41 → 0.9.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 (273) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +376 -0
  3. package/README.md +1 -1
  4. package/dist/lib/neutral/CommandsDialogContent-UBGIQ5FI.mjs +112 -0
  5. package/dist/lib/neutral/CommandsDialogContent-UBGIQ5FI.mjs.map +7 -0
  6. package/dist/lib/neutral/CommandsTrigger-BH5WLMHK.mjs +27 -0
  7. package/dist/lib/neutral/CommandsTrigger-BH5WLMHK.mjs.map +7 -0
  8. package/dist/lib/neutral/NavTreeContainer-6AR4BFDD.mjs +12 -0
  9. package/dist/lib/neutral/NavTreeContainer-6AR4BFDD.mjs.map +7 -0
  10. package/dist/lib/neutral/NavTreeDocumentTitle-H3E6ZLYE.mjs +22 -0
  11. package/dist/lib/neutral/NavTreeDocumentTitle-H3E6ZLYE.mjs.map +7 -0
  12. package/dist/lib/neutral/NavTreePlugin.mjs +68 -0
  13. package/dist/lib/neutral/NavTreePlugin.mjs.map +7 -0
  14. package/dist/lib/neutral/NavTreePlugin.node.mjs +18 -0
  15. package/dist/lib/neutral/NavTreePlugin.node.mjs.map +7 -0
  16. package/dist/lib/neutral/NavTreePlugin.workerd.mjs +16 -0
  17. package/dist/lib/neutral/NavTreePlugin.workerd.mjs.map +7 -0
  18. package/dist/lib/neutral/app-graph-builder-Z347LKSF.mjs +42 -0
  19. package/dist/lib/neutral/app-graph-builder-Z347LKSF.mjs.map +7 -0
  20. package/dist/lib/neutral/capabilities/index.mjs +17 -0
  21. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  22. package/dist/lib/neutral/chunk-5OPDKH6B.mjs +273 -0
  23. package/dist/lib/neutral/chunk-5OPDKH6B.mjs.map +7 -0
  24. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  25. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  26. package/dist/lib/neutral/chunk-JOSNCOV4.mjs +79 -0
  27. package/dist/lib/neutral/chunk-JOSNCOV4.mjs.map +7 -0
  28. package/dist/lib/neutral/chunk-MDGKDQMZ.mjs +37 -0
  29. package/dist/lib/neutral/chunk-MDGKDQMZ.mjs.map +7 -0
  30. package/dist/lib/neutral/chunk-T7QS2EFI.mjs +8 -0
  31. package/dist/lib/neutral/chunk-T7QS2EFI.mjs.map +7 -0
  32. package/dist/lib/neutral/chunk-ZSWYB7JW.mjs +27 -0
  33. package/dist/lib/neutral/chunk-ZSWYB7JW.mjs.map +7 -0
  34. package/dist/lib/neutral/components/index.mjs +805 -0
  35. package/dist/lib/neutral/components/index.mjs.map +7 -0
  36. package/dist/lib/neutral/containers/index.mjs +20 -0
  37. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  38. package/dist/lib/neutral/expose-26FV4W5D.mjs +38 -0
  39. package/dist/lib/neutral/expose-26FV4W5D.mjs.map +7 -0
  40. package/dist/lib/neutral/hooks/index.mjs +178 -0
  41. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  42. package/dist/lib/neutral/index.mjs +34 -0
  43. package/dist/lib/neutral/index.mjs.map +7 -0
  44. package/dist/lib/{browser/keyboard-YYTYJW4M.mjs → neutral/keyboard-EJ65BVTC.mjs} +25 -20
  45. package/dist/lib/neutral/keyboard-EJ65BVTC.mjs.map +7 -0
  46. package/dist/lib/neutral/meta.json +1 -0
  47. package/dist/lib/neutral/meta.mjs +12 -0
  48. package/dist/lib/neutral/meta.mjs.map +7 -0
  49. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs +13 -0
  50. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs.map +7 -0
  51. package/dist/lib/neutral/operations/index.mjs +8 -0
  52. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  53. package/dist/lib/neutral/plugin.mjs +16 -0
  54. package/dist/lib/neutral/plugin.mjs.map +7 -0
  55. package/dist/lib/neutral/react-surface-Q5XMAG7Z.mjs +50 -0
  56. package/dist/lib/neutral/react-surface-Q5XMAG7Z.mjs.map +7 -0
  57. package/dist/lib/neutral/state-VVJEWUHM.mjs +126 -0
  58. package/dist/lib/neutral/state-VVJEWUHM.mjs.map +7 -0
  59. package/dist/lib/neutral/testing/index.mjs +439 -0
  60. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  61. package/dist/lib/neutral/translations.mjs +23 -0
  62. package/dist/lib/neutral/translations.mjs.map +7 -0
  63. package/dist/lib/neutral/types/index.mjs +10 -0
  64. package/dist/lib/neutral/types/index.mjs.map +7 -0
  65. package/dist/types/src/NavTreePlugin.d.ts +3 -1
  66. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  67. package/dist/types/src/NavTreePlugin.node.d.ts +4 -0
  68. package/dist/types/src/NavTreePlugin.node.d.ts.map +1 -0
  69. package/dist/types/src/NavTreePlugin.test.d.ts +2 -0
  70. package/dist/types/src/NavTreePlugin.test.d.ts.map +1 -0
  71. package/dist/types/src/NavTreePlugin.workerd.d.ts +4 -0
  72. package/dist/types/src/NavTreePlugin.workerd.d.ts.map +1 -0
  73. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  74. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  75. package/dist/types/src/capabilities/index.d.ts +7 -108
  76. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  77. package/dist/types/src/capabilities/keyboard.d.ts +3 -2
  78. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
  79. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  80. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  81. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  82. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  83. package/dist/types/src/capabilities/state.d.ts +4 -18
  84. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  85. package/dist/types/src/components/NavTree/NavTree.d.ts +11 -4
  86. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  87. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +10 -12
  88. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  89. package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
  90. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
  91. package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
  92. package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
  93. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +13 -9
  94. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  95. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +3 -2
  96. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  97. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  98. package/dist/types/src/components/Sidebar/L0Menu.d.ts +8 -5
  99. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  100. package/dist/types/src/components/Sidebar/L1Panel.d.ts +4 -7
  101. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  102. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +5 -4
  103. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  104. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  105. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  106. package/dist/types/src/components/index.d.ts +0 -3
  107. package/dist/types/src/components/index.d.ts.map +1 -1
  108. package/dist/types/src/components/types.d.ts +8 -17
  109. package/dist/types/src/components/types.d.ts.map +1 -1
  110. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts +6 -0
  111. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
  112. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  113. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  114. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +2 -0
  115. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
  116. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
  117. package/dist/types/src/containers/CommandsTrigger/index.d.ts +2 -0
  118. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
  119. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
  120. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
  121. package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
  122. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
  123. package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +1 -1
  124. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
  125. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +2 -0
  126. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
  127. package/dist/types/src/containers/index.d.ts +7 -0
  128. package/dist/types/src/containers/index.d.ts.map +1 -0
  129. package/dist/types/src/experimental/Tree.d.ts +2 -2
  130. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  131. package/dist/types/src/experimental/Tree.stories.d.ts +18 -4
  132. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  133. package/dist/types/src/hooks/index.d.ts +5 -0
  134. package/dist/types/src/hooks/index.d.ts.map +1 -0
  135. package/dist/types/src/hooks/useActions.d.ts +11 -0
  136. package/dist/types/src/hooks/useActions.d.ts.map +1 -0
  137. package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
  138. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
  139. package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
  140. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
  141. package/dist/types/src/hooks/useNavTreeState.d.ts +18 -0
  142. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
  143. package/dist/types/src/index.d.ts +1 -3
  144. package/dist/types/src/index.d.ts.map +1 -1
  145. package/dist/types/src/meta.d.ts +4 -3
  146. package/dist/types/src/meta.d.ts.map +1 -1
  147. package/dist/types/src/operations/expose.d.ts +5 -0
  148. package/dist/types/src/operations/expose.d.ts.map +1 -0
  149. package/dist/types/src/operations/index.d.ts +3 -0
  150. package/dist/types/src/operations/index.d.ts.map +1 -0
  151. package/dist/types/src/plugin.d.ts +4 -0
  152. package/dist/types/src/plugin.d.ts.map +1 -0
  153. package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
  154. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  155. package/dist/types/src/testing/generator.d.ts +5 -6
  156. package/dist/types/src/testing/generator.d.ts.map +1 -1
  157. package/dist/types/src/testing/update-state.d.ts +2 -2
  158. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  159. package/dist/types/src/translations.d.ts +8 -11
  160. package/dist/types/src/translations.d.ts.map +1 -1
  161. package/dist/types/src/types/NavTreeCapabilities.d.ts +13 -0
  162. package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -0
  163. package/dist/types/src/types/NavTreeEvents.d.ts +3 -0
  164. package/dist/types/src/types/NavTreeEvents.d.ts.map +1 -0
  165. package/dist/types/src/types/index.d.ts +4 -0
  166. package/dist/types/src/types/index.d.ts.map +1 -0
  167. package/dist/types/src/{types.d.ts → types/schema.d.ts} +10 -6
  168. package/dist/types/src/types/schema.d.ts.map +1 -0
  169. package/dist/types/src/util.d.ts +12 -8
  170. package/dist/types/src/util.d.ts.map +1 -1
  171. package/dist/types/tsconfig.tsbuildinfo +1 -1
  172. package/package.json +124 -62
  173. package/src/NavTreePlugin.node.ts +17 -0
  174. package/src/NavTreePlugin.test.ts +27 -0
  175. package/src/NavTreePlugin.tsx +46 -76
  176. package/src/NavTreePlugin.workerd.ts +16 -0
  177. package/src/capabilities/app-graph-builder.ts +34 -45
  178. package/src/capabilities/index.ts +10 -8
  179. package/src/capabilities/keyboard.ts +58 -51
  180. package/src/capabilities/operation-handler.ts +16 -0
  181. package/src/capabilities/react-surface.tsx +46 -38
  182. package/src/capabilities/state.ts +132 -84
  183. package/src/components/NavTree/NavTree.stories.tsx +55 -63
  184. package/src/components/NavTree/NavTree.tsx +65 -33
  185. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  186. package/src/components/NavTreeContext/index.ts +5 -0
  187. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +23 -15
  188. package/src/components/NavTreeItem/NavTreeItemAction.tsx +75 -52
  189. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +25 -42
  190. package/src/components/Sidebar/L0Menu.tsx +155 -184
  191. package/src/components/Sidebar/L1Panel.tsx +181 -101
  192. package/src/components/Sidebar/L1Tabs.tsx +18 -34
  193. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +2 -3
  194. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +1 -1
  195. package/src/components/index.ts +1 -3
  196. package/src/components/types.ts +13 -19
  197. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  198. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +127 -0
  199. package/src/containers/CommandsDialogContent/index.ts +5 -0
  200. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +28 -0
  201. package/src/containers/CommandsTrigger/index.ts +5 -0
  202. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +271 -0
  203. package/src/containers/NavTreeContainer/index.ts +6 -0
  204. package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +4 -3
  205. package/src/containers/NavTreeDocumentTitle/index.ts +5 -0
  206. package/src/containers/index.ts +12 -0
  207. package/src/experimental/Tree.stories.tsx +82 -85
  208. package/src/experimental/Tree.tsx +5 -5
  209. package/src/hooks/index.ts +8 -0
  210. package/src/hooks/useActions.ts +44 -0
  211. package/src/hooks/useLoadDescendents.ts +23 -0
  212. package/src/hooks/useNavTreeModel.ts +120 -0
  213. package/src/hooks/useNavTreeState.ts +35 -0
  214. package/src/index.ts +1 -3
  215. package/src/meta.ts +22 -7
  216. package/src/operations/expose.ts +42 -0
  217. package/src/operations/index.ts +7 -0
  218. package/src/plugin.ts +11 -0
  219. package/src/testing/app-graph-builder.ts +168 -238
  220. package/src/testing/generator.ts +35 -38
  221. package/src/testing/update-state.ts +6 -6
  222. package/src/translations.ts +8 -10
  223. package/src/types/NavTreeCapabilities.ts +21 -0
  224. package/src/types/NavTreeEvents.ts +12 -0
  225. package/src/types/index.ts +8 -0
  226. package/src/{types.ts → types/schema.ts} +9 -5
  227. package/src/util.ts +28 -17
  228. package/src/vite-env.d.ts +10 -0
  229. package/dist/lib/browser/app-graph-builder-OHSCN3GX.mjs +0 -46
  230. package/dist/lib/browser/app-graph-builder-OHSCN3GX.mjs.map +0 -7
  231. package/dist/lib/browser/chunk-5VLWX4PK.mjs +0 -15
  232. package/dist/lib/browser/chunk-5VLWX4PK.mjs.map +0 -7
  233. package/dist/lib/browser/chunk-7D2MPHXV.mjs +0 -1483
  234. package/dist/lib/browser/chunk-7D2MPHXV.mjs.map +0 -7
  235. package/dist/lib/browser/chunk-E6MZBCU5.mjs +0 -19
  236. package/dist/lib/browser/chunk-E6MZBCU5.mjs.map +0 -7
  237. package/dist/lib/browser/index.mjs +0 -146
  238. package/dist/lib/browser/index.mjs.map +0 -7
  239. package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs +0 -47
  240. package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs.map +0 -7
  241. package/dist/lib/browser/keyboard-YYTYJW4M.mjs.map +0 -7
  242. package/dist/lib/browser/meta.json +0 -1
  243. package/dist/lib/browser/react-surface-J7MWWAGD.mjs +0 -51
  244. package/dist/lib/browser/react-surface-J7MWWAGD.mjs.map +0 -7
  245. package/dist/lib/browser/state-EUSVT6BI.mjs +0 -117
  246. package/dist/lib/browser/state-EUSVT6BI.mjs.map +0 -7
  247. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  248. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  249. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  250. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  251. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +0 -5
  252. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  253. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  254. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  255. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  256. package/dist/types/src/components/NavTreeContainer.d.ts +0 -9
  257. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  258. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  259. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  260. package/dist/types/src/events.d.ts +0 -4
  261. package/dist/types/src/events.d.ts.map +0 -1
  262. package/dist/types/src/hooks.d.ts +0 -3
  263. package/dist/types/src/hooks.d.ts.map +0 -1
  264. package/dist/types/src/types.d.ts.map +0 -1
  265. package/src/capabilities/capabilities.ts +0 -20
  266. package/src/capabilities/intent-resolver.ts +0 -37
  267. package/src/components/CommandsDialog/CommandsDialog.tsx +0 -126
  268. package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -36
  269. package/src/components/CommandsDialog/index.ts +0 -6
  270. package/src/components/NavTreeContainer.tsx +0 -369
  271. package/src/events.ts +0 -11
  272. package/src/hooks.ts +0 -21
  273. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
@@ -0,0 +1,44 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useMemo } from 'react';
6
+
7
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
8
+ import { Graph, Node, useActions as useGraphActions } from '@dxos/plugin-graph';
9
+
10
+ import { type FlattenedActions } from '#types';
11
+
12
+ /**
13
+ * Flattens grouped actions and filters to the list-item dispositions rendered as
14
+ * navtree item actions. Shared by row (`NavTreeItemColumns`) and header (`L1Panel`)
15
+ * so both apply the same normalization rule.
16
+ */
17
+ export const getListActions = ({ actions, groupedActions }: FlattenedActions): Node.Action[] =>
18
+ actions
19
+ .flatMap((action) => (Node.isAction(action) ? [action] : (groupedActions[action.id] ?? [])))
20
+ .filter((action) => ['list-item', 'list-item-primary'].includes(action.properties?.disposition));
21
+
22
+ /** Returns flattened actions and grouped sub-actions for a given graph node. */
23
+ export const useActions = (node: Node.Node): FlattenedActions => {
24
+ const { graph } = useAppGraph();
25
+ const actions = useGraphActions(graph, node.id);
26
+
27
+ return useMemo(() => {
28
+ return actions.reduce(
29
+ (acc: FlattenedActions, arg) => {
30
+ if (arg.properties.disposition === 'item') {
31
+ return acc;
32
+ }
33
+
34
+ acc.actions.push(arg);
35
+ if (!Node.isAction(arg)) {
36
+ const actionGroup = Graph.getActions(graph, arg.id);
37
+ acc.groupedActions[arg.id] = actionGroup;
38
+ }
39
+ return acc;
40
+ },
41
+ { actions: [], groupedActions: {} },
42
+ );
43
+ }, [actions]);
44
+ };
@@ -0,0 +1,23 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useEffect } from 'react';
6
+
7
+ import { type Node } from '@dxos/app-graph';
8
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
9
+ import { Graph } from '@dxos/plugin-graph';
10
+
11
+ /**
12
+ * Expands a root node in the app graph.
13
+ */
14
+ export const useLoadDescendents = (root?: Node.Node) => {
15
+ const { graph } = useAppGraph();
16
+ useEffect(() => {
17
+ if (!root) {
18
+ return;
19
+ }
20
+
21
+ Graph.expand(graph, root.id, 'child');
22
+ }, [graph, root]);
23
+ };
@@ -0,0 +1,120 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Atom } from '@effect-atom/atom-react';
6
+ import * as Option from 'effect/Option';
7
+ import { useMemo } from 'react';
8
+
9
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
10
+ import { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck';
11
+ import { type Node } from '@dxos/plugin-graph';
12
+ import { Path, type TreeModel } from '@dxos/react-ui-list';
13
+ import { mx } from '@dxos/ui-theme';
14
+
15
+ import { type NavTreeItemGraphNode } from '#types';
16
+
17
+ import { filterItems } from '../util';
18
+ import { useNavTreeState } from './useNavTreeState';
19
+
20
+ // TODO(wittjosiah): Move companion/hidden nodes to their own edge categories so this filter is unnecessary.
21
+ const isVisibleChild = (node: Node.Node): boolean =>
22
+ node.type !== PLANK_COMPANION_TYPE && node.properties.disposition !== 'hidden';
23
+
24
+ /** Create an atom family for item display props keyed by path. */
25
+ const createItemPropsFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>
26
+ Atom.family((pathKey: string) => {
27
+ const path = Path.parts(pathKey);
28
+ const id = Path.last(pathKey);
29
+ return Atom.make((get) => {
30
+ const nodeOpt = get(graph.node(id));
31
+ const node = Option.getOrElse(nodeOpt, () => undefined);
32
+ if (!node) {
33
+ return { id, label: id };
34
+ }
35
+ const safeChildren = get(graph.connections(node.id, 'child')).filter((child) => !path.includes(child.id));
36
+ const visibleChildren = safeChildren.filter(isVisibleChild);
37
+ const parentOf =
38
+ visibleChildren.length > 0
39
+ ? visibleChildren.map((child) => child.id)
40
+ : node.properties.role === 'branch'
41
+ ? []
42
+ : undefined;
43
+ const parentId = path.length >= 2 ? path[path.length - 2] : undefined;
44
+ const parentNode = parentId ? Option.getOrElse(get(graph.node(parentId)), () => undefined) : undefined;
45
+ const droppable =
46
+ node.properties.droppable === false || parentNode?.properties.childrenDroppable === false ? false : undefined;
47
+
48
+ return {
49
+ id: node.id,
50
+ parentOf,
51
+ disabled: node.properties.disabled,
52
+ draggable: node.properties.draggable,
53
+ droppable,
54
+ label: node.properties.label ?? node.id,
55
+ className: mx(node.properties.className, node.properties.modified && 'italic'),
56
+ headingClassName: node.properties.headingClassName,
57
+ icon: node.properties.icon,
58
+ iconHue: node.properties.iconHue,
59
+ testId: node.properties.testId,
60
+ count: node.properties.count,
61
+ modifiedCount: node.properties.modifiedCount,
62
+ };
63
+ }).pipe(Atom.keepAlive);
64
+ });
65
+
66
+ /** Create an atom family for outbound child IDs keyed by parent ID (pre-sorted by position on write). */
67
+ const createChildIdsFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>
68
+ Atom.family((id: string) =>
69
+ Atom.make((get) => get(graph.connections(id, 'child')).map((child) => child.id)).pipe(Atom.keepAlive),
70
+ );
71
+
72
+ /** Create an atom family for item resolution keyed by ID. */
73
+ const createItemFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>
74
+ Atom.family((id: string) =>
75
+ Atom.make((get) => {
76
+ const node = Option.getOrElse(get(graph.node(id)), () => undefined);
77
+ return node && filterItems(node) ? node : undefined;
78
+ }).pipe(Atom.keepAlive),
79
+ );
80
+
81
+ /** Create an atom family for open state keyed by path. */
82
+ const createItemOpenFamily = (getItemAtom: ReturnType<typeof useNavTreeState>['getItemAtom']) =>
83
+ Atom.family((pathKey: string) => {
84
+ const path = Path.parts(pathKey);
85
+ const stateAtom = getItemAtom(path);
86
+ return Atom.make((get) => get(stateAtom).open).pipe(Atom.keepAlive);
87
+ });
88
+
89
+ /** Create an atom family for current (selected) state keyed by path. */
90
+ const createItemCurrentFamily = (getItemAtom: ReturnType<typeof useNavTreeState>['getItemAtom']) =>
91
+ Atom.family((pathKey: string) => {
92
+ const path = Path.parts(pathKey);
93
+ const stateAtom = getItemAtom(path);
94
+ return Atom.make((get) => get(stateAtom).current).pipe(Atom.keepAlive);
95
+ });
96
+
97
+ /**
98
+ * Creates a TreeModel backed by the app graph and navtree state.
99
+ */
100
+ export const useNavTreeModel = (rootId: string): TreeModel<NavTreeItemGraphNode> => {
101
+ const { graph } = useAppGraph();
102
+ const { getItemAtom } = useNavTreeState();
103
+
104
+ const itemPropsFamily = useMemo(() => createItemPropsFamily(graph), [graph]);
105
+ const childIdsFamily = useMemo(() => createChildIdsFamily(graph), [graph]);
106
+ const itemFamily = useMemo(() => createItemFamily(graph), [graph]);
107
+ const itemOpenFamily = useMemo(() => createItemOpenFamily(getItemAtom), [getItemAtom]);
108
+ const itemCurrentFamily = useMemo(() => createItemCurrentFamily(getItemAtom), [getItemAtom]);
109
+
110
+ return useMemo(
111
+ () => ({
112
+ item: (id: string) => itemFamily(id),
113
+ itemProps: (path: string[]) => itemPropsFamily(Path.create(...path)),
114
+ itemOpen: (path: string[]) => itemOpenFamily(Path.create(...path)),
115
+ itemCurrent: (path: string[]) => itemCurrentFamily(Path.create(...path)),
116
+ childIds: (parentId?: string) => childIdsFamily(parentId ?? rootId),
117
+ }),
118
+ [itemFamily, itemPropsFamily, itemOpenFamily, itemCurrentFamily, childIdsFamily, rootId],
119
+ );
120
+ };
@@ -0,0 +1,35 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Atom, useAtomValue } from '@effect-atom/atom-react';
6
+ import { useMemo } from 'react';
7
+
8
+ import { useCapability } from '@dxos/app-framework/ui';
9
+
10
+ import { NavTreeCapabilities } from '#types';
11
+
12
+ export type UseNavTreeStateResult = {
13
+ getItem: (path: string[]) => NavTreeCapabilities.NavTreeItemState;
14
+ getItemAtom: (path: string[]) => Atom.Atom<NavTreeCapabilities.NavTreeItemState>;
15
+ setItem: (path: string[], key: 'open' | 'current', next: boolean) => void;
16
+ };
17
+
18
+ /**
19
+ * Hook that provides access to navtree state functions.
20
+ * For reactive subscriptions, use `useNavTreeItemState` or `useAtomValue(getItemAtom(path))`.
21
+ */
22
+ export const useNavTreeState = (): UseNavTreeStateResult => {
23
+ return useCapability(NavTreeCapabilities.State);
24
+ };
25
+
26
+ /**
27
+ * Hook that subscribes to a single navtree item's state.
28
+ * Use this for fine-grained reactivity.
29
+ */
30
+ export const useNavTreeItemState = (path: string[]): NavTreeCapabilities.NavTreeItemState => {
31
+ const { getItemAtom } = useCapability(NavTreeCapabilities.State);
32
+ const pathKey = useMemo(() => path.join('~'), [path]);
33
+ const atom = useMemo(() => getItemAtom(path), [getItemAtom, pathKey]);
34
+ return useAtomValue(atom);
35
+ };
package/src/index.ts CHANGED
@@ -2,8 +2,6 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export { NavTreeCapabilities } from './capabilities';
6
- export { NavTreeEvents } from './events';
7
- export * from './NavTreePlugin';
8
5
  export * from './meta';
6
+ export * from './types';
9
7
  export * from './util';
package/src/meta.ts CHANGED
@@ -2,19 +2,34 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type PluginMeta } from '@dxos/app-framework';
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { DXN } from '@dxos/keys';
6
7
  import { trim } from '@dxos/util';
7
8
 
8
- export const meta: PluginMeta = {
9
- id: 'dxos.org/plugin/navtree',
9
+ export const meta = Plugin.makeMeta({
10
+ key: DXN.make('org.dxos.plugin.navtree'),
10
11
  name: 'Navtree',
12
+ author: 'DXOS',
13
+ spec: 'PLUGIN.mdl',
11
14
  description: trim`
12
- Hierarchical navigation tree for browsing spaces, folders, and objects.
13
- Provides sidebar navigation with collapsible sections and quick access to workspace content.
15
+ NavTreePlugin renders the application graph as a collapsible hierarchical tree in the Composer sidebar.
16
+ It manages workspace tabs at the root level and provides expand/collapse navigation for spaces, folders,
17
+ and objects, with open/current state persisted to localStorage across sessions.
18
+
19
+ The plugin wires drag-and-drop rearrangement and cross-parent transfer of tree items via Pragmatic DnD,
20
+ and registers graph-action keyboard shortcuts (including the ⌘K / Ctrl+K command palette) through a
21
+ global Keyboard singleton that tracks context as the user navigates.
22
+
23
+ An operation handler for LayoutOperation.Expose expands ancestor paths on demand so that any
24
+ programmatically activated item is scrolled into view in the tree.
25
+
26
+ A commands dialog surfaces all discoverable graph actions as a searchable palette, making it the primary
27
+ keyboard-first entry point for power users.
14
28
  `,
15
- };
29
+ tags: ['system'],
30
+ });
16
31
 
17
32
  // TODO(wittjosiah): Factor out.
18
33
  export const KEY_BINDING = 'KeyBinding';
19
34
  // TODO(wittjosiah): Factor out.
20
- export const COMMANDS_DIALOG = `${meta.id}/CommandsDialog`;
35
+ export const COMMANDS_DIALOG = DXN.make(`${meta.id}.commandsDialog`);
@@ -0,0 +1,42 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Option from 'effect/Option';
7
+
8
+ import { Capability } from '@dxos/app-framework';
9
+ import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
10
+ import { Operation } from '@dxos/compute';
11
+ import { log } from '@dxos/log';
12
+ import { Graph } from '@dxos/plugin-graph';
13
+ import { expandAttendableId } from '@dxos/react-ui-attention';
14
+
15
+ import { NavTreeCapabilities } from '../types';
16
+
17
+ const handler: Operation.WithHandler<typeof LayoutOperation.Expose> = LayoutOperation.Expose.pipe(
18
+ Operation.withHandler(
19
+ Effect.fnUntraced(function* ({ subject }) {
20
+ const { graph } = yield* Capability.get(AppCapabilities.AppGraph);
21
+ const { getItem, setItem } = yield* Capability.get(NavTreeCapabilities.State);
22
+
23
+ const prefixes = expandAttendableId(subject);
24
+
25
+ for (const qualifiedId of prefixes) {
26
+ Graph.expand(graph, qualifiedId, 'child');
27
+
28
+ const treePath = prefixes.slice(0, prefixes.indexOf(qualifiedId) + 1);
29
+ const state = getItem(treePath);
30
+ if (!state.open) {
31
+ setItem(treePath, 'open', true);
32
+ }
33
+ }
34
+
35
+ if (Option.isNone(Graph.getNode(graph, subject))) {
36
+ log('Node not found after expansion', { subject });
37
+ }
38
+ }),
39
+ ),
40
+ );
41
+
42
+ export default handler;
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { OperationHandlerSet } from '@dxos/compute';
6
+
7
+ export const NavTreeOperationHandlerSet = OperationHandlerSet.lazy(() => import('./expose'));
package/src/plugin.ts ADDED
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Plugin } from '@dxos/app-framework';
6
+
7
+ import { meta } from './meta';
8
+
9
+ export const NavTreePlugin = Plugin.lazy(meta, () => import('#plugin'));
10
+
11
+ export { NavTreeOperationHandlerSet } from './operations';