@dxos/plugin-navtree 0.8.4-main.c85a9c8dae → 0.8.4-main.d9fc60f731

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 (258) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +376 -0
  3. package/README.md +1 -1
  4. package/dist/lib/{browser/CommandsDialogContent-A27AKTHH.mjs → neutral/CommandsDialogContent-UBGIQ5FI.mjs} +24 -23
  5. package/dist/lib/neutral/CommandsDialogContent-UBGIQ5FI.mjs.map +7 -0
  6. package/dist/lib/{browser/CommandsTrigger-HBZYQCGV.mjs → neutral/CommandsTrigger-BH5WLMHK.mjs} +8 -14
  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/{browser/NavTreeDocumentTitle-GEE3URWH.mjs → neutral/NavTreeDocumentTitle-H3E6ZLYE.mjs} +5 -9
  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/{browser/app-graph-builder-XGA4GPGL.mjs → neutral/app-graph-builder-Z347LKSF.mjs} +10 -12
  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 +807 -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-OJZC54PK.mjs → neutral/keyboard-EJ65BVTC.mjs} +8 -6
  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/{browser/react-surface-AYHOAJ4I.mjs → neutral/react-surface-Q5XMAG7Z.mjs} +11 -20
  56. package/dist/lib/neutral/react-surface-Q5XMAG7Z.mjs.map +7 -0
  57. package/dist/lib/{browser/state-AC3EETN7.mjs → neutral/state-VVITVXWM.mjs} +7 -11
  58. package/dist/lib/neutral/state-VVITVXWM.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 +1 -0
  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.map +1 -0
  74. package/dist/types/src/capabilities/index.d.ts +7 -5
  75. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  76. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -0
  77. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  78. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  79. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  80. package/dist/types/src/capabilities/state.d.ts +6 -0
  81. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  82. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  83. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +9 -11
  84. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  85. package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
  86. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
  87. package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
  88. package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
  89. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +7 -3
  90. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  91. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +1 -1
  92. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  93. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  94. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  95. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  96. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  97. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  98. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  99. package/dist/types/src/components/types.d.ts +1 -2
  100. package/dist/types/src/components/types.d.ts.map +1 -1
  101. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -1
  102. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  103. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  104. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +1 -2
  105. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -1
  106. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -1
  107. package/dist/types/src/containers/CommandsTrigger/index.d.ts +1 -2
  108. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -1
  109. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -1
  110. package/dist/types/src/containers/NavTreeContainer/index.d.ts +2 -2
  111. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -1
  112. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -1
  113. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +1 -2
  114. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -1
  115. package/dist/types/src/containers/index.d.ts +1 -1
  116. package/dist/types/src/containers/index.d.ts.map +1 -1
  117. package/dist/types/src/experimental/Tree.d.ts +2 -2
  118. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  119. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  120. package/dist/types/src/hooks/useActions.d.ts +6 -2
  121. package/dist/types/src/hooks/useActions.d.ts.map +1 -1
  122. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -1
  123. package/dist/types/src/hooks/useNavTreeModel.d.ts +1 -1
  124. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -1
  125. package/dist/types/src/hooks/useNavTreeState.d.ts +2 -6
  126. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -1
  127. package/dist/types/src/index.d.ts +1 -2
  128. package/dist/types/src/index.d.ts.map +1 -1
  129. package/dist/types/src/meta.d.ts +3 -2
  130. package/dist/types/src/meta.d.ts.map +1 -1
  131. package/dist/types/src/operations/expose.d.ts +5 -0
  132. package/dist/types/src/operations/expose.d.ts.map +1 -0
  133. package/dist/types/src/operations/index.d.ts +3 -0
  134. package/dist/types/src/operations/index.d.ts.map +1 -0
  135. package/dist/types/src/plugin.d.ts +4 -0
  136. package/dist/types/src/plugin.d.ts.map +1 -0
  137. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  138. package/dist/types/src/testing/generator.d.ts.map +1 -1
  139. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  140. package/dist/types/src/translations.d.ts +8 -11
  141. package/dist/types/src/translations.d.ts.map +1 -1
  142. package/dist/types/src/types/NavTreeCapabilities.d.ts +13 -0
  143. package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -0
  144. package/dist/types/src/types/NavTreeEvents.d.ts +3 -0
  145. package/dist/types/src/types/NavTreeEvents.d.ts.map +1 -0
  146. package/dist/types/src/types/index.d.ts +2 -2
  147. package/dist/types/src/types/index.d.ts.map +1 -1
  148. package/dist/types/src/types/schema.d.ts +4 -0
  149. package/dist/types/src/types/schema.d.ts.map +1 -1
  150. package/dist/types/src/util.d.ts +2 -2
  151. package/dist/types/src/util.d.ts.map +1 -1
  152. package/dist/types/tsconfig.tsbuildinfo +1 -1
  153. package/package.json +110 -50
  154. package/src/NavTreePlugin.node.ts +17 -0
  155. package/src/NavTreePlugin.test.ts +27 -0
  156. package/src/NavTreePlugin.tsx +16 -27
  157. package/src/NavTreePlugin.workerd.ts +16 -0
  158. package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +7 -7
  159. package/src/capabilities/index.ts +11 -5
  160. package/src/capabilities/{keyboard/keyboard.ts → keyboard.ts} +2 -2
  161. package/src/capabilities/operation-handler.ts +16 -0
  162. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +9 -9
  163. package/src/capabilities/{state/state.ts → state.ts} +14 -10
  164. package/src/components/NavTree/NavTree.stories.tsx +23 -24
  165. package/src/components/NavTree/NavTree.tsx +5 -4
  166. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  167. package/src/components/NavTreeContext/index.ts +5 -0
  168. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +8 -10
  169. package/src/components/NavTreeItem/NavTreeItemAction.tsx +66 -48
  170. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +22 -63
  171. package/src/components/Sidebar/L0Menu.tsx +62 -81
  172. package/src/components/Sidebar/L1Panel.tsx +99 -158
  173. package/src/components/Sidebar/L1Tabs.tsx +0 -1
  174. package/src/components/types.ts +1 -2
  175. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  176. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +52 -58
  177. package/src/containers/CommandsDialogContent/index.ts +1 -3
  178. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +7 -5
  179. package/src/containers/CommandsTrigger/index.ts +1 -3
  180. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +28 -27
  181. package/src/containers/NavTreeContainer/index.ts +2 -3
  182. package/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.tsx +2 -2
  183. package/src/containers/NavTreeDocumentTitle/index.ts +1 -3
  184. package/src/containers/index.ts +1 -1
  185. package/src/experimental/Tree.stories.tsx +27 -27
  186. package/src/experimental/Tree.tsx +2 -2
  187. package/src/hooks/useActions.ts +26 -20
  188. package/src/hooks/useNavTreeModel.ts +13 -5
  189. package/src/hooks/useNavTreeState.ts +2 -9
  190. package/src/index.ts +1 -2
  191. package/src/meta.ts +22 -7
  192. package/src/operations/expose.ts +42 -0
  193. package/src/operations/index.ts +7 -0
  194. package/src/plugin.ts +11 -0
  195. package/src/testing/app-graph-builder.ts +47 -41
  196. package/src/testing/generator.ts +23 -28
  197. package/src/translations.ts +8 -10
  198. package/src/types/NavTreeCapabilities.ts +21 -0
  199. package/src/types/NavTreeEvents.ts +12 -0
  200. package/src/types/index.ts +3 -2
  201. package/src/types/schema.ts +4 -0
  202. package/src/util.ts +2 -2
  203. package/src/vite-env.d.ts +10 -0
  204. package/dist/lib/browser/CommandsDialogContent-A27AKTHH.mjs.map +0 -7
  205. package/dist/lib/browser/CommandsTrigger-HBZYQCGV.mjs.map +0 -7
  206. package/dist/lib/browser/NavTreeContainer-B5K4FUJS.mjs +0 -12
  207. package/dist/lib/browser/NavTreeContainer-B5K4FUJS.mjs.map +0 -7
  208. package/dist/lib/browser/NavTreeDocumentTitle-GEE3URWH.mjs.map +0 -7
  209. package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs.map +0 -7
  210. package/dist/lib/browser/chunk-DQCYMXEU.mjs +0 -1426
  211. package/dist/lib/browser/chunk-DQCYMXEU.mjs.map +0 -7
  212. package/dist/lib/browser/chunk-H3OJ4WLF.mjs +0 -14
  213. package/dist/lib/browser/chunk-H3OJ4WLF.mjs.map +0 -7
  214. package/dist/lib/browser/chunk-X2HDG62A.mjs +0 -23
  215. package/dist/lib/browser/chunk-X2HDG62A.mjs.map +0 -7
  216. package/dist/lib/browser/chunk-YKTYPINZ.mjs +0 -19
  217. package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +0 -7
  218. package/dist/lib/browser/index.mjs +0 -141
  219. package/dist/lib/browser/index.mjs.map +0 -7
  220. package/dist/lib/browser/keyboard-OJZC54PK.mjs.map +0 -7
  221. package/dist/lib/browser/meta.json +0 -1
  222. package/dist/lib/browser/operation-resolver-BNAMYOHF.mjs +0 -53
  223. package/dist/lib/browser/operation-resolver-BNAMYOHF.mjs.map +0 -7
  224. package/dist/lib/browser/react-surface-AYHOAJ4I.mjs.map +0 -7
  225. package/dist/lib/browser/state-AC3EETN7.mjs.map +0 -7
  226. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  227. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  228. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  229. package/dist/types/src/capabilities/keyboard/index.d.ts +0 -3
  230. package/dist/types/src/capabilities/keyboard/index.d.ts.map +0 -1
  231. package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +0 -1
  232. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  233. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  234. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  235. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  236. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  237. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  238. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  239. package/dist/types/src/capabilities/state/index.d.ts +0 -3
  240. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  241. package/dist/types/src/capabilities/state/state.d.ts +0 -6
  242. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  243. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  244. package/dist/types/src/types/capabilities.d.ts +0 -16
  245. package/dist/types/src/types/capabilities.d.ts.map +0 -1
  246. package/dist/types/src/types/events.d.ts +0 -5
  247. package/dist/types/src/types/events.d.ts.map +0 -1
  248. package/src/capabilities/app-graph-builder/index.ts +0 -7
  249. package/src/capabilities/keyboard/index.ts +0 -7
  250. package/src/capabilities/operation-resolver/index.ts +0 -7
  251. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -44
  252. package/src/capabilities/react-surface/index.ts +0 -7
  253. package/src/capabilities/state/index.ts +0 -7
  254. package/src/types/capabilities.ts +0 -21
  255. package/src/types/events.ts +0 -12
  256. /package/dist/types/src/capabilities/{app-graph-builder/app-graph-builder.d.ts → app-graph-builder.d.ts} +0 -0
  257. /package/dist/types/src/capabilities/{keyboard/keyboard.d.ts → keyboard.d.ts} +0 -0
  258. /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
@@ -7,14 +7,14 @@ import * as Option from 'effect/Option';
7
7
  import { useMemo } from 'react';
8
8
 
9
9
  import { useAppGraph } from '@dxos/app-toolkit/ui';
10
- import { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
10
+ import { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck';
11
11
  import { type Node } from '@dxos/plugin-graph';
12
12
  import { Path, type TreeModel } from '@dxos/react-ui-list';
13
13
  import { mx } from '@dxos/ui-theme';
14
14
 
15
- import { type NavTreeItemGraphNode } from '../types';
16
- import { filterItems } from '../util';
15
+ import { type NavTreeItemGraphNode } from '#types';
17
16
 
17
+ import { filterItems } from '../util';
18
18
  import { useNavTreeState } from './useNavTreeState';
19
19
 
20
20
  // TODO(wittjosiah): Move companion/hidden nodes to their own edge categories so this filter is unnecessary.
@@ -40,16 +40,25 @@ const createItemPropsFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =
40
40
  : node.properties.role === 'branch'
41
41
  ? []
42
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
+
43
48
  return {
44
49
  id: node.id,
45
50
  parentOf,
46
51
  disabled: node.properties.disabled,
52
+ draggable: node.properties.draggable,
53
+ droppable,
47
54
  label: node.properties.label ?? node.id,
48
55
  className: mx(node.properties.className, node.properties.modified && 'italic'),
49
56
  headingClassName: node.properties.headingClassName,
50
57
  icon: node.properties.icon,
51
58
  iconHue: node.properties.iconHue,
52
59
  testId: node.properties.testId,
60
+ count: node.properties.count,
61
+ modifiedCount: node.properties.modifiedCount,
53
62
  };
54
63
  }).pipe(Atom.keepAlive);
55
64
  });
@@ -65,8 +74,7 @@ const createItemFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>
65
74
  Atom.family((id: string) =>
66
75
  Atom.make((get) => {
67
76
  const node = Option.getOrElse(get(graph.node(id)), () => undefined);
68
- const passed = node ? filterItems(node) : false;
69
- return node && passed ? node : undefined;
77
+ return node && filterItems(node) ? node : undefined;
70
78
  }).pipe(Atom.keepAlive),
71
79
  );
72
80
 
@@ -7,12 +7,12 @@ import { useMemo } from 'react';
7
7
 
8
8
  import { useCapability } from '@dxos/app-framework/ui';
9
9
 
10
- import { NavTreeCapabilities } from '../types';
10
+ import { NavTreeCapabilities } from '#types';
11
11
 
12
12
  export type UseNavTreeStateResult = {
13
13
  getItem: (path: string[]) => NavTreeCapabilities.NavTreeItemState;
14
14
  getItemAtom: (path: string[]) => Atom.Atom<NavTreeCapabilities.NavTreeItemState>;
15
- setItem: (path: string[], key: 'open' | 'current' | 'alternateTree', next: boolean) => void;
15
+ setItem: (path: string[], key: 'open' | 'current', next: boolean) => void;
16
16
  };
17
17
 
18
18
  /**
@@ -33,10 +33,3 @@ export const useNavTreeItemState = (path: string[]): NavTreeCapabilities.NavTree
33
33
  const atom = useMemo(() => getItemAtom(path), [getItemAtom, pathKey]);
34
34
  return useAtomValue(atom);
35
35
  };
36
-
37
- /**
38
- * Hook that subscribes to the alternateTree state for a tree item.
39
- */
40
- export const useIsAlternateTree = (path: string[], _item?: any): boolean => {
41
- return useNavTreeItemState(path).alternateTree ?? false;
42
- };
package/src/index.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export { NavTreeCapabilities, NavTreeEvents } from './types';
6
- export * from './NavTreePlugin';
7
5
  export * from './meta';
6
+ export * from './types';
8
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 Plugin } 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: Plugin.Meta = {
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';
@@ -7,8 +7,8 @@ import * as Effect from 'effect/Effect';
7
7
 
8
8
  import { type BuilderExtensions } from '@dxos/app-graph';
9
9
  import { log } from '@dxos/log';
10
- import { GraphBuilder, NodeMatcher } from '@dxos/plugin-graph';
11
- import { faker } from '@dxos/random';
10
+ import { GraphBuilder, Node, NodeMatcher } from '@dxos/plugin-graph';
11
+ import { random } from '@dxos/random';
12
12
 
13
13
  export const storybookGraphBuilders = (): BuilderExtensions => {
14
14
  const propertiesCache = new Map<string, Record<string, unknown>>();
@@ -26,18 +26,18 @@ export const storybookGraphBuilders = (): BuilderExtensions => {
26
26
  Effect.all([
27
27
  // Create app menu actions.
28
28
  GraphBuilder.createExtension({
29
- id: 'app-menu',
29
+ id: 'appMenu',
30
30
  match: NodeMatcher.whenRoot,
31
31
  actions: () =>
32
32
  Effect.succeed(
33
33
  Array.from({ length: 5 }, (_, i) => ({
34
- id: `app-menu/action-${i}`,
34
+ id: `action-${i}`,
35
35
  data: Effect.fnUntraced(function* () {
36
36
  log.info('action', { id: 'app-menu', index: i });
37
37
  }),
38
38
  properties: {
39
39
  label: `Action ${i}`,
40
- icon: faker.properties.icon(),
40
+ icon: random.properties.icon(),
41
41
  disposition: 'menu',
42
42
  },
43
43
  })),
@@ -45,11 +45,11 @@ export const storybookGraphBuilders = (): BuilderExtensions => {
45
45
  }),
46
46
  // Create user account node.
47
47
  GraphBuilder.createExtension({
48
- id: 'user-account',
48
+ id: 'userAccount',
49
49
  match: NodeMatcher.whenRoot,
50
50
  connector: () =>
51
51
  Effect.succeed([
52
- {
52
+ Node.make({
53
53
  id: 'user-account',
54
54
  type: 'user-account',
55
55
  properties: {
@@ -57,37 +57,37 @@ export const storybookGraphBuilders = (): BuilderExtensions => {
57
57
  icon: 'ph--user--regular',
58
58
  disposition: 'user-account',
59
59
  userId: '1234567890ABCDEF',
60
- hue: faker.properties.hue(),
61
- emoji: faker.properties.emoji(),
60
+ hue: random.properties.hue(),
61
+ emoji: random.properties.emoji(),
62
62
  status: 'active',
63
63
  },
64
64
  nodes: [
65
- {
65
+ Node.make({
66
66
  id: 'profile',
67
67
  type: 'profile',
68
68
  properties: {
69
69
  label: 'Profile',
70
70
  icon: 'ph--user--regular',
71
71
  },
72
- },
73
- {
72
+ }),
73
+ Node.make({
74
74
  id: 'devices',
75
75
  type: 'devices',
76
76
  properties: {
77
77
  label: 'Devices',
78
78
  icon: 'ph--devices--regular',
79
79
  },
80
- },
81
- {
80
+ }),
81
+ Node.make({
82
82
  id: 'security',
83
83
  type: 'security',
84
84
  properties: {
85
85
  label: 'Security',
86
86
  icon: 'ph--key--regular',
87
87
  },
88
- },
88
+ }),
89
89
  ],
90
- },
90
+ }),
91
91
  ]),
92
92
  }),
93
93
  // Create space (workspace) nodes directly under root.
@@ -111,32 +111,34 @@ export const storybookGraphBuilders = (): BuilderExtensions => {
111
111
  return value;
112
112
  });
113
113
 
114
- return Array.from({ length: get(count) }, (_, i) => ({
115
- id: `space-${i}`,
116
- type: 'space',
117
- properties: getProperties(`space-${i}`, {
118
- label: `Space ${i}`,
119
- icon: faker.properties.icon(),
120
- hue: faker.properties.hue(),
121
- disposition: 'workspace',
114
+ return Array.from({ length: get(count) }, (_, i) =>
115
+ Node.make({
116
+ id: `space-${i}`,
117
+ type: 'space',
118
+ properties: getProperties(`space-${i}`, {
119
+ label: `Space ${i}`,
120
+ icon: random.properties.icon(),
121
+ hue: random.properties.hue(),
122
+ disposition: 'workspace',
123
+ }),
122
124
  }),
123
- }));
125
+ );
124
126
  }),
125
127
  }),
126
128
  // Create space actions.
127
129
  GraphBuilder.createExtension({
128
- id: 'space-actions',
130
+ id: 'spaceActions',
129
131
  match: NodeMatcher.whenNodeType('space'),
130
132
  actions: () =>
131
133
  Effect.succeed(
132
134
  Array.from({ length: 5 }, (_, i) => ({
133
- id: `space-actions/action-${i}`,
135
+ id: `action-${i}`,
134
136
  data: Effect.fnUntraced(function* () {
135
137
  log.info('action', { id: 'space-actions', index: i });
136
138
  }),
137
- properties: getProperties(`space-actions/action-${i}`, {
139
+ properties: getProperties(`action-${i}`, {
138
140
  label: `Action ${i}`,
139
- icon: faker.properties.icon(),
141
+ icon: random.properties.icon(),
140
142
  }),
141
143
  })),
142
144
  ),
@@ -162,30 +164,34 @@ export const storybookGraphBuilders = (): BuilderExtensions => {
162
164
  return value;
163
165
  });
164
166
 
165
- return Array.from({ length: get(count) }, (_, i) => ({
166
- id: `object-${i}`,
167
- type: 'object',
168
- properties: getProperties(`object-${i}`, {
169
- label: `Object ${i}`,
170
- icon: faker.properties.icon(),
167
+ return Array.from({ length: get(count) }, (_, i) =>
168
+ Node.make({
169
+ id: `object-${i}`,
170
+ type: 'object',
171
+ properties: getProperties(`object-${i}`, {
172
+ label: `Object ${i}`,
173
+ icon: random.properties.icon(),
174
+ ...(i % 3 === 0 && { count: (i + 1) * 2 }),
175
+ ...(i % 3 === 1 && { modifiedCount: i + 1 }),
176
+ }),
171
177
  }),
172
- }));
178
+ );
173
179
  }),
174
180
  }),
175
181
  // Create object actions.
176
182
  GraphBuilder.createExtension({
177
- id: 'object-actions',
183
+ id: 'objectActions',
178
184
  match: NodeMatcher.whenNodeType('object'),
179
185
  actions: () =>
180
186
  Effect.succeed(
181
187
  Array.from({ length: 5 }, (_, i) => ({
182
- id: `object-actions/action-${i}`,
188
+ id: `action-${i}`,
183
189
  data: Effect.fnUntraced(function* () {
184
- log.info('action', { id: 'object-actions', index: i });
190
+ log.info('action', { id: 'objectActions', index: i });
185
191
  }),
186
- properties: getProperties(`object-actions/action-${i}`, {
192
+ properties: getProperties(`action-${i}`, {
187
193
  label: `Action ${i}`,
188
- icon: faker.properties.icon(),
194
+ icon: random.properties.icon(),
189
195
  }),
190
196
  })),
191
197
  ),
@@ -5,9 +5,9 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
 
7
7
  import { type Node } from '@dxos/app-graph';
8
- import { Obj, Type } from '@dxos/echo';
8
+ import { DXN, Obj, Type } from '@dxos/echo';
9
9
  import { TestSchema } from '@dxos/echo/testing';
10
- import { faker } from '@dxos/random';
10
+ import { random } from '@dxos/random';
11
11
  import { range } from '@dxos/util';
12
12
 
13
13
  // TODO(burdon): Reconcile with @dxos/plugin-debug, @dxos/react-ui/testing.
@@ -43,16 +43,16 @@ export const Priority = [1, 2, 3, 4, 5];
43
43
  export const defaultGenerators: { [type: string]: ObjectDataGenerator } = {
44
44
  document: {
45
45
  createData: () => ({
46
- title: faker.lorem.sentence(3),
47
- body: faker.lorem.sentences({ min: 1, max: faker.number.int({ min: 1, max: 3 }) }),
46
+ title: random.lorem.sentence(3),
47
+ body: random.lorem.sentences({ min: 1, max: random.number.int({ min: 1, max: 3 }) }),
48
48
  }),
49
49
  },
50
50
 
51
51
  image: {
52
52
  createData: () => ({
53
- title: faker.lorem.sentence(3),
54
- image: faker.helpers.arrayElement(data.images),
55
- body: faker.datatype.boolean() ? faker.lorem.sentences() : undefined,
53
+ title: random.lorem.sentence(3),
54
+ image: random.helpers.arrayElement(data.images),
55
+ body: random.datatype.boolean() ? random.lorem.sentences() : undefined,
56
56
  }),
57
57
  },
58
58
 
@@ -63,18 +63,13 @@ export const defaultGenerators: { [type: string]: ObjectDataGenerator } = {
63
63
  repo: Schema.String,
64
64
  status: Schema.String,
65
65
  priority: Schema.Number,
66
- }).pipe(
67
- Type.object({
68
- typename: 'example.com/type/Project',
69
- version: '0.1.0',
70
- }),
71
- ),
66
+ }).pipe(Type.makeObject(DXN.make('com.example.type.project', '0.1.0'))),
72
67
 
73
68
  createData: () => ({
74
- title: faker.commerce.productName(),
75
- repo: faker.datatype.boolean({ probability: 0.3 }) ? faker.internet.url() : undefined,
76
- status: faker.helpers.arrayElement(Status),
77
- priority: faker.helpers.arrayElement(Priority),
69
+ title: random.commerce.productName(),
70
+ repo: random.datatype.boolean({ probability: 0.3 }) ? random.internet.url() : undefined,
71
+ status: random.helpers.arrayElement(Status),
72
+ priority: random.helpers.arrayElement(Priority),
78
73
  }),
79
74
  },
80
75
  };
@@ -99,7 +94,7 @@ export class TestObjectGenerator {
99
94
  }
100
95
 
101
96
  createObject({ types }: { types?: string[] } = {}) {
102
- const type = faker.helpers.arrayElement(types ?? Object.keys(this.factories));
97
+ const type = random.helpers.arrayElement(types ?? Object.keys(this.factories));
103
98
  const factory = this.factories[type];
104
99
  return factory?.createObject();
105
100
  }
@@ -136,7 +131,7 @@ export const createTree = () => {
136
131
  nodes: [...Array(4)].map(() => {
137
132
  const l0 = generator.createObject();
138
133
  return {
139
- id: faker.string.uuid(),
134
+ id: random.string.uuid(),
140
135
  data: null,
141
136
  type: 'category',
142
137
  properties: {
@@ -148,7 +143,7 @@ export const createTree = () => {
148
143
  ...[...Array(4)].map(() => {
149
144
  const l1 = generator.createObject();
150
145
  return {
151
- id: faker.string.uuid(),
146
+ id: random.string.uuid(),
152
147
  data: null,
153
148
  type: 'document',
154
149
  properties: {
@@ -157,20 +152,20 @@ export const createTree = () => {
157
152
  },
158
153
  nodes: [
159
154
  {
160
- id: `${faker.string.uuid()}__a1`,
155
+ id: `${random.string.uuid()}__a1`,
161
156
  data: () => {},
162
157
  type: 'action',
163
158
  properties: {
164
- label: faker.lorem.words(2),
159
+ label: random.lorem.words(2),
165
160
  icon: 'ph--boat--regular',
166
161
  },
167
162
  },
168
163
  {
169
- id: `${faker.string.uuid()}__a2`,
164
+ id: `${random.string.uuid()}__a2`,
170
165
  data: () => {},
171
166
  type: 'action',
172
167
  properties: {
173
- label: faker.lorem.words(2),
168
+ label: random.lorem.words(2),
174
169
  icon: 'ph--train-simple--regular',
175
170
  },
176
171
  },
@@ -178,20 +173,20 @@ export const createTree = () => {
178
173
  } satisfies Node.NodeArg<any>;
179
174
  }),
180
175
  {
181
- id: `${faker.string.uuid()}__a1`,
176
+ id: `${random.string.uuid()}__a1`,
182
177
  data: () => {},
183
178
  type: 'action',
184
179
  properties: {
185
- label: faker.lorem.words(2),
180
+ label: random.lorem.words(2),
186
181
  icon: 'ph--boat--regular',
187
182
  },
188
183
  },
189
184
  {
190
- id: `${faker.string.uuid()}__a2`,
185
+ id: `${random.string.uuid()}__a2`,
191
186
  data: () => {},
192
187
  type: 'action',
193
188
  properties: {
194
- label: faker.lorem.words(2),
189
+ label: random.lorem.words(2),
195
190
  icon: 'ph--train-simple--regular',
196
191
  },
197
192
  },
@@ -4,21 +4,19 @@
4
4
 
5
5
  import { type Resource } from '@dxos/react-ui';
6
6
 
7
- import { meta } from './meta';
7
+ import { meta } from '#meta';
8
8
 
9
9
  export const translations = [
10
10
  {
11
11
  'en-US': {
12
12
  [meta.id]: {
13
- 'app menu label': 'App menu',
14
- 'open settings label': 'Settings',
15
- 'open commands label': 'Search commands',
16
- 'commands dialog title': 'Commands',
17
- 'command list input placeholder': 'Search for commands…',
18
- 'node actions menu invoker label': 'More options',
19
- 'tree item actions label': 'More actions',
20
- 'empty branch message': ' ',
21
- 'button back': 'Back to Space',
13
+ 'app-menu.label': 'App menu',
14
+ 'open-commands.label': 'Search commands',
15
+ 'commands-dialog.title': 'Commands',
16
+ 'command-list-input.placeholder': 'Search for commands…',
17
+ 'node-actions-menu-invoker.label': 'More options',
18
+ 'tree-item-actions.label': 'More actions',
19
+ 'button-back.button': 'Back to Space',
22
20
  },
23
21
  },
24
22
  },
@@ -0,0 +1,21 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ // @import-as-namespace
6
+
7
+ import { type Atom } from '@effect-atom/atom-react';
8
+
9
+ import { Capability } from '@dxos/app-framework';
10
+
11
+ import { meta } from '#meta';
12
+
13
+ export type NavTreeItemState = { open: boolean; current: boolean };
14
+
15
+ export type NavTreeStateStore = {
16
+ getItem: (path: string[]) => NavTreeItemState;
17
+ getItemAtom: (path: string[]) => Atom.Atom<NavTreeItemState>;
18
+ setItem: (path: string[], key: 'open' | 'current', next: boolean) => void;
19
+ };
20
+
21
+ export const State = Capability.make<NavTreeStateStore>(`${meta.id}.capability.state`);
@@ -0,0 +1,12 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ // @import-as-namespace
6
+
7
+ import { type ActivationEvent } from '@dxos/app-framework';
8
+ import { AppActivationEvents } from '@dxos/app-toolkit';
9
+
10
+ import { meta } from '#meta';
11
+
12
+ export const StateReady: ActivationEvent.ActivationEvent = AppActivationEvents.createStateEvent(meta.id);
@@ -2,6 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './capabilities';
6
- export * from './events';
7
5
  export * from './schema';
6
+
7
+ export * as NavTreeCapabilities from './NavTreeCapabilities';
8
+ export * as NavTreeEvents from './NavTreeEvents';
@@ -43,6 +43,10 @@ export type NodeProperties = SharedProperties & {
43
43
  error?: string;
44
44
  modified?: boolean;
45
45
  palette?: string;
46
+ /** Optional item count rendered as a neutral badge after the label. */
47
+ count?: number;
48
+ /** Optional count of new/modified items; when greater than zero it shows as a rose badge in place of `count`. */
49
+ modifiedCount?: number;
46
50
  };
47
51
 
48
52
  export type ActionProperties = SharedProperties & {
package/src/util.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  import { Graph, Node } from '@dxos/plugin-graph';
6
6
  import { isNonNullable } from '@dxos/util';
7
7
 
8
- import { type NavTreeItemGraphNode } from './types';
8
+ import { type NavTreeItemGraphNode } from '#types';
9
9
 
10
10
  export const getParent = (
11
11
  graph: Graph.ReadableGraph,
@@ -93,7 +93,7 @@ export const getChildren = (
93
93
  * Determines whether a node should be visible based on its disposition.
94
94
  */
95
95
  export const filterItems = (node: Node.Node, disposition?: string) => {
96
- if (!disposition && (node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')) {
96
+ if (!disposition && node.properties.disposition === 'hidden') {
97
97
  return false;
98
98
  } else if (!disposition) {
99
99
  const action = Node.isAction(node);
@@ -0,0 +1,10 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ //
4
+ // Copyright 2026 DXOS.org
5
+ //
6
+
7
+ declare module '*.mdl?raw' {
8
+ const content: string;
9
+ export default content;
10
+ }