@dxos/plugin-navtree 0.8.4-main.ead640a → 0.8.4-main.effb148878

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 (271) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/neutral/CommandsDialogContent-UBGIQ5FI.mjs +112 -0
  4. package/dist/lib/neutral/CommandsDialogContent-UBGIQ5FI.mjs.map +7 -0
  5. package/dist/lib/neutral/CommandsTrigger-BH5WLMHK.mjs +27 -0
  6. package/dist/lib/neutral/CommandsTrigger-BH5WLMHK.mjs.map +7 -0
  7. package/dist/lib/neutral/NavTreeContainer-6AR4BFDD.mjs +12 -0
  8. package/dist/lib/neutral/NavTreeContainer-6AR4BFDD.mjs.map +7 -0
  9. package/dist/lib/neutral/NavTreeDocumentTitle-H3E6ZLYE.mjs +22 -0
  10. package/dist/lib/neutral/NavTreeDocumentTitle-H3E6ZLYE.mjs.map +7 -0
  11. package/dist/lib/neutral/NavTreePlugin.mjs +56 -0
  12. package/dist/lib/neutral/NavTreePlugin.mjs.map +7 -0
  13. package/dist/lib/neutral/NavTreePlugin.node.mjs +18 -0
  14. package/dist/lib/neutral/NavTreePlugin.node.mjs.map +7 -0
  15. package/dist/lib/neutral/NavTreePlugin.workerd.mjs +16 -0
  16. package/dist/lib/neutral/NavTreePlugin.workerd.mjs.map +7 -0
  17. package/dist/lib/neutral/app-graph-builder-Z347LKSF.mjs +42 -0
  18. package/dist/lib/neutral/app-graph-builder-Z347LKSF.mjs.map +7 -0
  19. package/dist/lib/neutral/capabilities/index.mjs +17 -0
  20. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  21. package/dist/lib/neutral/chunk-5OPDKH6B.mjs +273 -0
  22. package/dist/lib/neutral/chunk-5OPDKH6B.mjs.map +7 -0
  23. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  24. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  25. package/dist/lib/neutral/chunk-JOSNCOV4.mjs +79 -0
  26. package/dist/lib/neutral/chunk-JOSNCOV4.mjs.map +7 -0
  27. package/dist/lib/neutral/chunk-RWLAJYUL.mjs +35 -0
  28. package/dist/lib/neutral/chunk-RWLAJYUL.mjs.map +7 -0
  29. package/dist/lib/neutral/chunk-T7QS2EFI.mjs +8 -0
  30. package/dist/lib/neutral/chunk-T7QS2EFI.mjs.map +7 -0
  31. package/dist/lib/neutral/chunk-ZSWYB7JW.mjs +27 -0
  32. package/dist/lib/neutral/chunk-ZSWYB7JW.mjs.map +7 -0
  33. package/dist/lib/neutral/components/index.mjs +879 -0
  34. package/dist/lib/neutral/components/index.mjs.map +7 -0
  35. package/dist/lib/neutral/containers/index.mjs +20 -0
  36. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  37. package/dist/lib/neutral/expose-26FV4W5D.mjs +38 -0
  38. package/dist/lib/neutral/expose-26FV4W5D.mjs.map +7 -0
  39. package/dist/lib/neutral/hooks/index.mjs +169 -0
  40. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  41. package/dist/lib/neutral/index.mjs +34 -0
  42. package/dist/lib/neutral/index.mjs.map +7 -0
  43. package/dist/lib/{browser/keyboard-AHSAWKXA.mjs → neutral/keyboard-EJ65BVTC.mjs} +25 -20
  44. package/dist/lib/neutral/keyboard-EJ65BVTC.mjs.map +7 -0
  45. package/dist/lib/neutral/meta.json +1 -0
  46. package/dist/lib/neutral/meta.mjs +12 -0
  47. package/dist/lib/neutral/meta.mjs.map +7 -0
  48. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs +13 -0
  49. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs.map +7 -0
  50. package/dist/lib/neutral/operations/index.mjs +8 -0
  51. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  52. package/dist/lib/neutral/plugin.mjs +16 -0
  53. package/dist/lib/neutral/plugin.mjs.map +7 -0
  54. package/dist/lib/neutral/react-surface-EWCZMKVX.mjs +50 -0
  55. package/dist/lib/neutral/react-surface-EWCZMKVX.mjs.map +7 -0
  56. package/dist/lib/neutral/state-VVITVXWM.mjs +127 -0
  57. package/dist/lib/neutral/state-VVITVXWM.mjs.map +7 -0
  58. package/dist/lib/neutral/testing/index.mjs +433 -0
  59. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  60. package/dist/lib/neutral/translations.mjs +23 -0
  61. package/dist/lib/neutral/translations.mjs.map +7 -0
  62. package/dist/lib/neutral/types/index.mjs +10 -0
  63. package/dist/lib/neutral/types/index.mjs.map +7 -0
  64. package/dist/types/src/NavTreePlugin.d.ts +3 -1
  65. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  66. package/dist/types/src/NavTreePlugin.node.d.ts +4 -0
  67. package/dist/types/src/NavTreePlugin.node.d.ts.map +1 -0
  68. package/dist/types/src/NavTreePlugin.test.d.ts +2 -0
  69. package/dist/types/src/NavTreePlugin.test.d.ts.map +1 -0
  70. package/dist/types/src/NavTreePlugin.workerd.d.ts +4 -0
  71. package/dist/types/src/NavTreePlugin.workerd.d.ts.map +1 -0
  72. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  73. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  74. package/dist/types/src/capabilities/index.d.ts +7 -108
  75. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  76. package/dist/types/src/capabilities/keyboard.d.ts +3 -2
  77. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  79. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  80. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  81. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  82. package/dist/types/src/capabilities/state.d.ts +4 -18
  83. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  84. package/dist/types/src/components/NavTree/NavTree.d.ts +11 -4
  85. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  86. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +10 -12
  87. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  88. package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
  89. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
  90. package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
  91. package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
  92. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +13 -9
  93. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  94. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +3 -2
  95. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  96. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  97. package/dist/types/src/components/Sidebar/L0Menu.d.ts +8 -5
  98. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  99. package/dist/types/src/components/Sidebar/L1Panel.d.ts +4 -7
  100. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  101. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +5 -4
  102. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  103. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  104. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  105. package/dist/types/src/components/index.d.ts +0 -3
  106. package/dist/types/src/components/index.d.ts.map +1 -1
  107. package/dist/types/src/components/types.d.ts +8 -17
  108. package/dist/types/src/components/types.d.ts.map +1 -1
  109. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts +6 -0
  110. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
  111. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  112. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  113. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +2 -0
  114. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
  115. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
  116. package/dist/types/src/containers/CommandsTrigger/index.d.ts +2 -0
  117. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
  118. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
  119. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
  120. package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
  121. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
  122. package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +1 -1
  123. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
  124. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +2 -0
  125. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
  126. package/dist/types/src/containers/index.d.ts +7 -0
  127. package/dist/types/src/containers/index.d.ts.map +1 -0
  128. package/dist/types/src/experimental/Tree.d.ts +2 -2
  129. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  130. package/dist/types/src/experimental/Tree.stories.d.ts +18 -4
  131. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  132. package/dist/types/src/hooks/index.d.ts +5 -0
  133. package/dist/types/src/hooks/index.d.ts.map +1 -0
  134. package/dist/types/src/hooks/useActions.d.ts +5 -0
  135. package/dist/types/src/hooks/useActions.d.ts.map +1 -0
  136. package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
  137. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
  138. package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
  139. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
  140. package/dist/types/src/hooks/useNavTreeState.d.ts +18 -0
  141. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
  142. package/dist/types/src/index.d.ts +1 -3
  143. package/dist/types/src/index.d.ts.map +1 -1
  144. package/dist/types/src/meta.d.ts +2 -2
  145. package/dist/types/src/meta.d.ts.map +1 -1
  146. package/dist/types/src/operations/expose.d.ts +5 -0
  147. package/dist/types/src/operations/expose.d.ts.map +1 -0
  148. package/dist/types/src/operations/index.d.ts +3 -0
  149. package/dist/types/src/operations/index.d.ts.map +1 -0
  150. package/dist/types/src/plugin.d.ts +4 -0
  151. package/dist/types/src/plugin.d.ts.map +1 -0
  152. package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
  153. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  154. package/dist/types/src/testing/generator.d.ts +5 -6
  155. package/dist/types/src/testing/generator.d.ts.map +1 -1
  156. package/dist/types/src/testing/update-state.d.ts +2 -2
  157. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  158. package/dist/types/src/translations.d.ts +8 -11
  159. package/dist/types/src/translations.d.ts.map +1 -1
  160. package/dist/types/src/types/NavTreeCapabilities.d.ts +13 -0
  161. package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -0
  162. package/dist/types/src/types/NavTreeEvents.d.ts +3 -0
  163. package/dist/types/src/types/NavTreeEvents.d.ts.map +1 -0
  164. package/dist/types/src/types/index.d.ts +4 -0
  165. package/dist/types/src/types/index.d.ts.map +1 -0
  166. package/dist/types/src/{types.d.ts → types/schema.d.ts} +7 -7
  167. package/dist/types/src/types/schema.d.ts.map +1 -0
  168. package/dist/types/src/util.d.ts +12 -8
  169. package/dist/types/src/util.d.ts.map +1 -1
  170. package/dist/types/tsconfig.tsbuildinfo +1 -1
  171. package/package.json +126 -59
  172. package/src/NavTreePlugin.node.ts +17 -0
  173. package/src/NavTreePlugin.test.ts +27 -0
  174. package/src/NavTreePlugin.tsx +41 -77
  175. package/src/NavTreePlugin.workerd.ts +16 -0
  176. package/src/capabilities/app-graph-builder.ts +34 -45
  177. package/src/capabilities/index.ts +10 -8
  178. package/src/capabilities/keyboard.ts +58 -51
  179. package/src/capabilities/operation-handler.ts +16 -0
  180. package/src/capabilities/react-surface.tsx +46 -38
  181. package/src/capabilities/state.ts +132 -84
  182. package/src/components/NavTree/NavTree.stories.tsx +51 -57
  183. package/src/components/NavTree/NavTree.tsx +65 -33
  184. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  185. package/src/components/NavTreeContext/index.ts +5 -0
  186. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +23 -15
  187. package/src/components/NavTreeItem/NavTreeItemAction.tsx +75 -52
  188. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +46 -20
  189. package/src/components/Sidebar/L0Menu.tsx +155 -184
  190. package/src/components/Sidebar/L1Panel.tsx +203 -102
  191. package/src/components/Sidebar/L1Tabs.tsx +18 -34
  192. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +2 -3
  193. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +1 -1
  194. package/src/components/index.ts +1 -3
  195. package/src/components/types.ts +13 -19
  196. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  197. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +127 -0
  198. package/src/containers/CommandsDialogContent/index.ts +5 -0
  199. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +28 -0
  200. package/src/containers/CommandsTrigger/index.ts +5 -0
  201. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +271 -0
  202. package/src/containers/NavTreeContainer/index.ts +6 -0
  203. package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +4 -3
  204. package/src/containers/NavTreeDocumentTitle/index.ts +5 -0
  205. package/src/containers/index.ts +12 -0
  206. package/src/experimental/Tree.stories.tsx +82 -85
  207. package/src/experimental/Tree.tsx +4 -4
  208. package/src/hooks/index.ts +8 -0
  209. package/src/hooks/useActions.ts +34 -0
  210. package/src/hooks/useLoadDescendents.ts +23 -0
  211. package/src/hooks/useNavTreeModel.ts +118 -0
  212. package/src/hooks/useNavTreeState.ts +35 -0
  213. package/src/index.ts +1 -3
  214. package/src/meta.ts +23 -4
  215. package/src/operations/expose.ts +42 -0
  216. package/src/operations/index.ts +7 -0
  217. package/src/plugin.ts +11 -0
  218. package/src/testing/app-graph-builder.ts +167 -239
  219. package/src/testing/generator.ts +35 -38
  220. package/src/testing/update-state.ts +6 -6
  221. package/src/translations.ts +8 -10
  222. package/src/types/NavTreeCapabilities.ts +21 -0
  223. package/src/types/NavTreeEvents.ts +12 -0
  224. package/src/types/index.ts +8 -0
  225. package/src/{types.ts → types/schema.ts} +6 -6
  226. package/src/util.ts +28 -17
  227. package/dist/lib/browser/app-graph-builder-YAPMENYT.mjs +0 -46
  228. package/dist/lib/browser/app-graph-builder-YAPMENYT.mjs.map +0 -7
  229. package/dist/lib/browser/chunk-IMFXKPSB.mjs +0 -1482
  230. package/dist/lib/browser/chunk-IMFXKPSB.mjs.map +0 -7
  231. package/dist/lib/browser/chunk-LPAREX6J.mjs +0 -15
  232. package/dist/lib/browser/chunk-LPAREX6J.mjs.map +0 -7
  233. package/dist/lib/browser/chunk-ZENLR72O.mjs +0 -14
  234. package/dist/lib/browser/chunk-ZENLR72O.mjs.map +0 -7
  235. package/dist/lib/browser/index.mjs +0 -146
  236. package/dist/lib/browser/index.mjs.map +0 -7
  237. package/dist/lib/browser/intent-resolver-TCQXGF6U.mjs +0 -47
  238. package/dist/lib/browser/intent-resolver-TCQXGF6U.mjs.map +0 -7
  239. package/dist/lib/browser/keyboard-AHSAWKXA.mjs.map +0 -7
  240. package/dist/lib/browser/meta.json +0 -1
  241. package/dist/lib/browser/react-surface-AH2TP73M.mjs +0 -51
  242. package/dist/lib/browser/react-surface-AH2TP73M.mjs.map +0 -7
  243. package/dist/lib/browser/state-2Q623V7U.mjs +0 -117
  244. package/dist/lib/browser/state-2Q623V7U.mjs.map +0 -7
  245. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  246. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  247. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  248. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  249. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +0 -5
  250. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  251. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  252. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  253. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  254. package/dist/types/src/components/NavTreeContainer.d.ts +0 -9
  255. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  256. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  257. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  258. package/dist/types/src/events.d.ts +0 -4
  259. package/dist/types/src/events.d.ts.map +0 -1
  260. package/dist/types/src/hooks.d.ts +0 -3
  261. package/dist/types/src/hooks.d.ts.map +0 -1
  262. package/dist/types/src/types.d.ts.map +0 -1
  263. package/src/capabilities/capabilities.ts +0 -20
  264. package/src/capabilities/intent-resolver.ts +0 -37
  265. package/src/components/CommandsDialog/CommandsDialog.tsx +0 -118
  266. package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -35
  267. package/src/components/CommandsDialog/index.ts +0 -6
  268. package/src/components/NavTreeContainer.tsx +0 -346
  269. package/src/events.ts +0 -11
  270. package/src/hooks.ts +0 -21
  271. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
@@ -3,38 +3,16 @@
3
3
  //
4
4
 
5
5
  import { type Meta } from '@storybook/react-vite';
6
- import React, { type JSX, type PropsWithChildren, useEffect, useState } from 'react';
6
+ import React, { useEffect, useState } from 'react';
7
7
 
8
- import { faker } from '@dxos/random';
9
- import { Icon, IconButton } from '@dxos/react-ui';
8
+ import { random } from '@dxos/random';
9
+ import { Icon, IconButton, Panel, ScrollArea } from '@dxos/react-ui';
10
10
  import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
- import { mx } from '@dxos/react-ui-theme';
11
+ import { mx } from '@dxos/ui-theme';
12
12
 
13
13
  import { type ItemMap, Tree, type TreeNodeData, type TreeProps, visitNodes, visitor } from './Tree';
14
14
 
15
- faker.seed(1234);
16
-
17
- /**
18
- * Space:
19
- * - Space panels are separated from each other to give them more weight than folders.
20
- * - Private space isn't different (just first, different icon).
21
- * - Edit titles in place.
22
- *
23
- * Navigation:
24
- * - up/down across spaces/folder peers
25
- * - right to enter space/folder children
26
- * - left to parent
27
- */
28
- const Container = ({ children, sidebar }: PropsWithChildren<{ sidebar: JSX.Element }>) => {
29
- return (
30
- <div className='flex'>
31
- {/* TODO(burdon): Custom thin scrollbar. */}
32
- {/* TODO(burdon): Horizontal scrolling within navtree? */}
33
- <div className='flex flex-col overflow-y-auto w-[300px] bg-neutral-100 dark:bg-neutral-950'>{sidebar}</div>
34
- <div className='flex flex-col grow overflow-hidden'>{children}</div>
35
- </div>
36
- );
37
- };
15
+ random.seed(1234);
38
16
 
39
17
  // TODO(burdon): Generate.
40
18
  const data: TreeNodeData[] = [
@@ -43,34 +21,34 @@ const data: TreeNodeData[] = [
43
21
  title: 'plugins/Root',
44
22
  children: [
45
23
  {
46
- id: faker.string.uuid(),
24
+ id: random.string.uuid(),
47
25
  title: 'plugins/Personal Space',
48
26
  color: 'text-green-400',
49
27
  iconName: 'ph--house--regular',
50
28
  children: [
51
29
  {
52
- id: faker.string.uuid(),
53
- title: faker.commerce.productName(),
30
+ id: random.string.uuid(),
31
+ title: random.commerce.productName(),
54
32
  },
55
33
  {
56
- id: faker.string.uuid(),
57
- title: faker.commerce.productName(),
34
+ id: random.string.uuid(),
35
+ title: random.commerce.productName(),
58
36
  },
59
37
  {
60
- id: faker.string.uuid(),
61
- title: faker.commerce.productName(),
38
+ id: random.string.uuid(),
39
+ title: random.commerce.productName(),
62
40
  children: [
63
41
  {
64
- id: faker.string.uuid(),
65
- title: faker.commerce.productName(),
42
+ id: random.string.uuid(),
43
+ title: random.commerce.productName(),
66
44
  children: [
67
45
  {
68
- id: faker.string.uuid(),
69
- title: faker.commerce.productName(),
46
+ id: random.string.uuid(),
47
+ title: random.commerce.productName(),
70
48
  },
71
49
  {
72
- id: faker.string.uuid(),
73
- title: faker.commerce.productName(),
50
+ id: random.string.uuid(),
51
+ title: random.commerce.productName(),
74
52
  },
75
53
  ],
76
54
  },
@@ -79,24 +57,24 @@ const data: TreeNodeData[] = [
79
57
  ],
80
58
  },
81
59
  {
82
- id: faker.string.uuid(),
83
- title: faker.commerce.productName(),
60
+ id: random.string.uuid(),
61
+ title: random.commerce.productName(),
84
62
  iconName: 'ph--planet--regular',
85
63
  children: [
86
64
  {
87
- id: faker.string.uuid(),
88
- title: faker.commerce.productName(),
65
+ id: random.string.uuid(),
66
+ title: random.commerce.productName(),
89
67
  },
90
68
  ],
91
69
  },
92
70
  {
93
- id: faker.string.uuid(),
94
- title: faker.commerce.productName(),
71
+ id: random.string.uuid(),
72
+ title: random.commerce.productName(),
95
73
  iconName: 'ph--sailboat--regular',
96
74
  },
97
75
  {
98
- id: faker.string.uuid(),
99
- title: faker.commerce.productName(),
76
+ id: random.string.uuid(),
77
+ title: random.commerce.productName(),
100
78
  iconName: 'ph--planet--regular',
101
79
  },
102
80
  ],
@@ -134,7 +112,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
134
112
  }
135
113
  }, []);
136
114
 
137
- const handleCreateItem: TreeProps['onMenuAction'] = (id, action) => {
115
+ const handleCreateItem: TreeProps['onMenuAction'] = (id) => {
138
116
  setItems((items) => {
139
117
  let parent: TreeNodeData | undefined;
140
118
  visitNodes(root, (node) => {
@@ -144,8 +122,8 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
144
122
  });
145
123
 
146
124
  (parent!.children ??= []).push({
147
- id: faker.string.uuid(),
148
- title: faker.commerce.productName(),
125
+ id: random.string.uuid(),
126
+ title: random.commerce.productName(),
149
127
  });
150
128
 
151
129
  setOpenItems((open) => ({ ...open, [parent!.id]: true }));
@@ -157,9 +135,9 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
157
135
  const handleCreateSpace = () => {
158
136
  setItems((items) => {
159
137
  items[0].children?.push({
160
- id: faker.string.uuid(),
138
+ id: random.string.uuid(),
161
139
  iconName: 'ph--planet--regular',
162
- title: faker.commerce.productName(),
140
+ title: random.commerce.productName(),
163
141
  });
164
142
 
165
143
  return { ...items };
@@ -167,49 +145,68 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
167
145
  };
168
146
 
169
147
  return (
170
- <div className='flex flex-col overflow-hidden'>
171
- <div className='flex flex-col overflow-y-auto'>
172
- <Tree
173
- className='p-0.5 gap-1'
174
- node={root}
175
- open={openItems}
176
- selected={selectedItems}
177
- active={activeItems}
178
- onChangeOpen={(id, open) => setOpenItems((items) => ({ ...items, [id]: open }))}
179
- onChangeSelected={(id, open) => setSelectedItems((items) => ({ ...items, [id]: open }))}
180
- onMenuAction={handleCreateItem}
181
- getSlots={(node, open, depth, ancestors) => {
182
- if (depth === 1) {
183
- return {
184
- root: 'rounded bg-white dark:bg-neutral-850',
185
- header: mx('rounded-t bg-neutral-50 dark:bg-neutral-900', !open && 'rounded-b'),
186
- };
187
- }
188
- }}
189
- />
190
- </div>
191
-
192
- <div className='flex items-center my-2 px-2 gap-2'>
193
- <IconButton icon='ph--plus-circle--regular' iconOnly label='Create space' onClick={handleCreateSpace} />
194
- <span className='grow text-sm' onClick={handleCreateSpace}>
195
- New space
196
- </span>
197
- <Icon icon='ph--list--regular' />
198
- </div>
199
- </div>
148
+ <Panel.Root>
149
+ <Panel.Content asChild>
150
+ <ScrollArea.Root orientation='vertical' thin>
151
+ <ScrollArea.Viewport>
152
+ <Tree
153
+ className='p-0.5 gap-1'
154
+ node={root}
155
+ open={openItems}
156
+ selected={selectedItems}
157
+ active={activeItems}
158
+ onChangeOpen={(id, open) => setOpenItems((items) => ({ ...items, [id]: open }))}
159
+ onChangeSelected={(id, open) => setSelectedItems((items) => ({ ...items, [id]: open }))}
160
+ onMenuAction={handleCreateItem}
161
+ getSlots={(node, open, depth) => {
162
+ if (depth === 1) {
163
+ return {
164
+ root: 'rounded-sm bg-white dark:bg-neutral-850',
165
+ header: mx('rounded-t bg-neutral-50 dark:bg-neutral-900', !open && 'rounded-b'),
166
+ };
167
+ }
168
+ }}
169
+ />
170
+ </ScrollArea.Viewport>
171
+ </ScrollArea.Root>
172
+ </Panel.Content>
173
+ <Panel.Statusbar>
174
+ <div className='flex items-center my-2 px-2 gap-2'>
175
+ <IconButton icon='ph--plus-circle--regular' iconOnly label='Create space' onClick={handleCreateSpace} />
176
+ <span className='grow text-sm' onClick={handleCreateSpace}>
177
+ New space
178
+ </span>
179
+ <Icon icon='ph--list--regular' />
180
+ </div>
181
+ </Panel.Statusbar>
182
+ </Panel.Root>
200
183
  );
201
184
  };
202
185
 
203
186
  const meta = {
204
187
  title: 'plugins/plugin-navtree/experimental/Tree',
205
188
  component: Tree,
206
- decorators: [withTheme, withLayout({ container: 'column' })],
189
+ decorators: [withTheme(), withLayout({ layout: 'column', classNames: 'w-[20rem]' })],
190
+ parameters: {
191
+ layout: 'fullscreen',
192
+ },
207
193
  } satisfies Meta<typeof Tree>;
208
194
 
209
195
  export default meta;
210
196
 
197
+ /**
198
+ * Space:
199
+ * - Space panels are separated from each other to give them more weight than folders.
200
+ * - Private space isn't different (just first, different icon).
201
+ * - Edit titles in place.
202
+ *
203
+ * Navigation:
204
+ * - up/down across spaces/folder peers
205
+ * - right to enter space/folder children
206
+ * - left to parent
207
+ */
211
208
  export const Default = () => {
212
- return <Container sidebar={<Sidebar mutate />} />;
209
+ return <Sidebar mutate />;
213
210
  };
214
211
 
215
212
  export const Visitor = () => {
@@ -5,7 +5,7 @@
5
5
  import React, { type HTMLAttributes, type PropsWithChildren } from 'react';
6
6
 
7
7
  import { type ClassNameValue, Icon, type Size } from '@dxos/react-ui';
8
- import { mx } from '@dxos/react-ui-theme';
8
+ import { mx } from '@dxos/ui-theme';
9
9
 
10
10
  export const IconButton = ({
11
11
  iconName,
@@ -193,9 +193,9 @@ export const TreeNodeRow = (props: TreeNodeProps & { className?: string }) => {
193
193
  <Grid
194
194
  style={{ paddingLeft: `${(depth - 1) * 24}px` }}
195
195
  className={mx(
196
- 'group w-full items-center cursor-pointer bg-hoverSurface',
196
+ 'group w-full items-center cursor-pointer bg-hover-surface',
197
197
  // TODO(burdon): Use data-active.
198
- selected?.[id] && 'bg-activeSurface',
198
+ selected?.[id] && 'bg-current-surface',
199
199
  className,
200
200
  )}
201
201
  onClick={() => selected && onChangeSelected?.(id, !selected[id])}
@@ -220,7 +220,7 @@ export const TreeNode = (props: TreeNodeProps & { ancestors?: TreeNodeData[] })
220
220
  const { root, header } = getSlots?.(props.node, open?.[id] ?? false, depth, ancestors) ?? {};
221
221
 
222
222
  return (
223
- <div role='none' className={mx('flex flex-col', root)}>
223
+ <div className={mx('flex flex-col', root)}>
224
224
  <TreeNodeRow {...props} className={header} />
225
225
  {(children?.length ?? 0) > 0 && open?.[id] && <TreeChildNodes {...props} ancestors={ancestors} />}
226
226
  </div>
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './useActions';
6
+ export * from './useLoadDescendents';
7
+ export * from './useNavTreeModel';
8
+ export * from './useNavTreeState';
@@ -0,0 +1,34 @@
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
+ /** Returns flattened actions and grouped sub-actions for a given graph node. */
13
+ export const useActions = (node: Node.Node): FlattenedActions => {
14
+ const { graph } = useAppGraph();
15
+ const actions = useGraphActions(graph, node.id);
16
+
17
+ return useMemo(() => {
18
+ return actions.reduce(
19
+ (acc: FlattenedActions, arg) => {
20
+ if (arg.properties.disposition === 'item') {
21
+ return acc;
22
+ }
23
+
24
+ acc.actions.push(arg);
25
+ if (!Node.isAction(arg)) {
26
+ const actionGroup = Graph.getActions(graph, arg.id);
27
+ acc.groupedActions[arg.id] = actionGroup;
28
+ }
29
+ return acc;
30
+ },
31
+ { actions: [], groupedActions: {} },
32
+ );
33
+ }, [actions]);
34
+ };
@@ -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,118 @@
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
+ };
61
+ }).pipe(Atom.keepAlive);
62
+ });
63
+
64
+ /** Create an atom family for outbound child IDs keyed by parent ID (pre-sorted by position on write). */
65
+ const createChildIdsFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>
66
+ Atom.family((id: string) =>
67
+ Atom.make((get) => get(graph.connections(id, 'child')).map((child) => child.id)).pipe(Atom.keepAlive),
68
+ );
69
+
70
+ /** Create an atom family for item resolution keyed by ID. */
71
+ const createItemFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>
72
+ Atom.family((id: string) =>
73
+ Atom.make((get) => {
74
+ const node = Option.getOrElse(get(graph.node(id)), () => undefined);
75
+ return node && filterItems(node) ? node : undefined;
76
+ }).pipe(Atom.keepAlive),
77
+ );
78
+
79
+ /** Create an atom family for open state keyed by path. */
80
+ const createItemOpenFamily = (getItemAtom: ReturnType<typeof useNavTreeState>['getItemAtom']) =>
81
+ Atom.family((pathKey: string) => {
82
+ const path = Path.parts(pathKey);
83
+ const stateAtom = getItemAtom(path);
84
+ return Atom.make((get) => get(stateAtom).open).pipe(Atom.keepAlive);
85
+ });
86
+
87
+ /** Create an atom family for current (selected) state keyed by path. */
88
+ const createItemCurrentFamily = (getItemAtom: ReturnType<typeof useNavTreeState>['getItemAtom']) =>
89
+ Atom.family((pathKey: string) => {
90
+ const path = Path.parts(pathKey);
91
+ const stateAtom = getItemAtom(path);
92
+ return Atom.make((get) => get(stateAtom).current).pipe(Atom.keepAlive);
93
+ });
94
+
95
+ /**
96
+ * Creates a TreeModel backed by the app graph and navtree state.
97
+ */
98
+ export const useNavTreeModel = (rootId: string): TreeModel<NavTreeItemGraphNode> => {
99
+ const { graph } = useAppGraph();
100
+ const { getItemAtom } = useNavTreeState();
101
+
102
+ const itemPropsFamily = useMemo(() => createItemPropsFamily(graph), [graph]);
103
+ const childIdsFamily = useMemo(() => createChildIdsFamily(graph), [graph]);
104
+ const itemFamily = useMemo(() => createItemFamily(graph), [graph]);
105
+ const itemOpenFamily = useMemo(() => createItemOpenFamily(getItemAtom), [getItemAtom]);
106
+ const itemCurrentFamily = useMemo(() => createItemCurrentFamily(getItemAtom), [getItemAtom]);
107
+
108
+ return useMemo(
109
+ () => ({
110
+ item: (id: string) => itemFamily(id),
111
+ itemProps: (path: string[]) => itemPropsFamily(Path.create(...path)),
112
+ itemOpen: (path: string[]) => itemOpenFamily(Path.create(...path)),
113
+ itemCurrent: (path: string[]) => itemCurrentFamily(Path.create(...path)),
114
+ childIds: (parentId?: string) => childIdsFamily(parentId ?? rootId),
115
+ }),
116
+ [itemFamily, itemPropsFamily, itemOpenFamily, itemCurrentFamily, childIdsFamily, rootId],
117
+ );
118
+ };
@@ -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,14 +2,33 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type PluginMeta } from '@dxos/app-framework';
5
+ import { type Plugin } from '@dxos/app-framework';
6
+ import { trim } from '@dxos/util';
6
7
 
7
- export const meta: PluginMeta = {
8
- id: 'dxos.org/plugin/navtree',
8
+ export const meta: Plugin.Meta = {
9
+ id: 'org.dxos.plugin.navtree',
9
10
  name: 'Navtree',
11
+ author: 'DXOS',
12
+ spec: 'PLUGIN.mdl',
13
+ description: trim`
14
+ NavTreePlugin renders the application graph as a collapsible hierarchical tree in the Composer sidebar.
15
+ It manages workspace tabs at the root level and provides expand/collapse navigation for spaces, folders,
16
+ and objects, with open/current state persisted to localStorage across sessions.
17
+
18
+ The plugin wires drag-and-drop rearrangement and cross-parent transfer of tree items via Pragmatic DnD,
19
+ and registers graph-action keyboard shortcuts (including the ⌘K / Ctrl+K command palette) through a
20
+ global Keyboard singleton that tracks context as the user navigates.
21
+
22
+ An operation handler for LayoutOperation.Expose expands ancestor paths on demand so that any
23
+ programmatically activated item is scrolled into view in the tree.
24
+
25
+ A commands dialog surfaces all discoverable graph actions as a searchable palette, making it the primary
26
+ keyboard-first entry point for power users.
27
+ `,
28
+ tags: ['system'],
10
29
  };
11
30
 
12
31
  // TODO(wittjosiah): Factor out.
13
32
  export const KEY_BINDING = 'KeyBinding';
14
33
  // TODO(wittjosiah): Factor out.
15
- export const COMMANDS_DIALOG = `${meta.id}/CommandsDialog`;
34
+ export const COMMANDS_DIALOG = `${meta.id}.commands-dialog`;
@@ -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';