@dxos/plugin-navtree 0.8.4-main.fd6878d → 0.8.4-staging.60fe92afc8

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 (275) 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-HMTMA33N.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 -105
  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 +25 -5
  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 +33 -4
  96. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  97. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +1 -1
  98. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  99. package/dist/types/src/components/Sidebar/L0Menu.d.ts +10 -5
  100. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  101. package/dist/types/src/components/Sidebar/L1Panel.d.ts +4 -7
  102. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  103. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +5 -4
  104. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  105. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  106. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +8 -5
  107. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  108. package/dist/types/src/components/index.d.ts +0 -3
  109. package/dist/types/src/components/index.d.ts.map +1 -1
  110. package/dist/types/src/components/types.d.ts +8 -17
  111. package/dist/types/src/components/types.d.ts.map +1 -1
  112. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts +6 -0
  113. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
  114. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  115. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  116. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +2 -0
  117. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
  118. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
  119. package/dist/types/src/containers/CommandsTrigger/index.d.ts +2 -0
  120. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
  121. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
  122. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
  123. package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
  124. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
  125. package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +1 -1
  126. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
  127. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +2 -0
  128. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
  129. package/dist/types/src/containers/index.d.ts +7 -0
  130. package/dist/types/src/containers/index.d.ts.map +1 -0
  131. package/dist/types/src/experimental/Tree.d.ts +3 -4
  132. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  133. package/dist/types/src/experimental/Tree.stories.d.ts +23 -6
  134. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  135. package/dist/types/src/hooks/index.d.ts +5 -0
  136. package/dist/types/src/hooks/index.d.ts.map +1 -0
  137. package/dist/types/src/hooks/useActions.d.ts +11 -0
  138. package/dist/types/src/hooks/useActions.d.ts.map +1 -0
  139. package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
  140. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
  141. package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
  142. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
  143. package/dist/types/src/hooks/useNavTreeState.d.ts +18 -0
  144. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
  145. package/dist/types/src/index.d.ts +1 -3
  146. package/dist/types/src/index.d.ts.map +1 -1
  147. package/dist/types/src/meta.d.ts +4 -4
  148. package/dist/types/src/meta.d.ts.map +1 -1
  149. package/dist/types/src/operations/expose.d.ts +5 -0
  150. package/dist/types/src/operations/expose.d.ts.map +1 -0
  151. package/dist/types/src/operations/index.d.ts +3 -0
  152. package/dist/types/src/operations/index.d.ts.map +1 -0
  153. package/dist/types/src/plugin.d.ts +4 -0
  154. package/dist/types/src/plugin.d.ts.map +1 -0
  155. package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
  156. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  157. package/dist/types/src/testing/generator.d.ts +5 -6
  158. package/dist/types/src/testing/generator.d.ts.map +1 -1
  159. package/dist/types/src/testing/update-state.d.ts +2 -2
  160. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  161. package/dist/types/src/translations.d.ts +8 -11
  162. package/dist/types/src/translations.d.ts.map +1 -1
  163. package/dist/types/src/types/NavTreeCapabilities.d.ts +13 -0
  164. package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -0
  165. package/dist/types/src/types/NavTreeEvents.d.ts +3 -0
  166. package/dist/types/src/types/NavTreeEvents.d.ts.map +1 -0
  167. package/dist/types/src/types/index.d.ts +4 -0
  168. package/dist/types/src/types/index.d.ts.map +1 -0
  169. package/dist/types/src/{types.d.ts → types/schema.d.ts} +14 -9
  170. package/dist/types/src/types/schema.d.ts.map +1 -0
  171. package/dist/types/src/util.d.ts +12 -8
  172. package/dist/types/src/util.d.ts.map +1 -1
  173. package/dist/types/tsconfig.tsbuildinfo +1 -1
  174. package/package.json +124 -62
  175. package/src/NavTreePlugin.node.ts +17 -0
  176. package/src/NavTreePlugin.test.ts +27 -0
  177. package/src/NavTreePlugin.tsx +56 -87
  178. package/src/NavTreePlugin.workerd.ts +16 -0
  179. package/src/capabilities/app-graph-builder.ts +34 -44
  180. package/src/capabilities/index.ts +10 -8
  181. package/src/capabilities/keyboard.ts +58 -51
  182. package/src/capabilities/operation-handler.ts +16 -0
  183. package/src/capabilities/react-surface.tsx +46 -38
  184. package/src/capabilities/state.ts +132 -84
  185. package/src/components/NavTree/NavTree.stories.tsx +112 -106
  186. package/src/components/NavTree/NavTree.tsx +69 -33
  187. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  188. package/src/components/NavTreeContext/index.ts +5 -0
  189. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +25 -19
  190. package/src/components/NavTreeItem/NavTreeItemAction.tsx +78 -54
  191. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +40 -51
  192. package/src/components/Sidebar/L0Menu.tsx +182 -210
  193. package/src/components/Sidebar/L1Panel.tsx +185 -110
  194. package/src/components/Sidebar/L1Tabs.tsx +18 -34
  195. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -9
  196. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
  197. package/src/components/index.ts +1 -3
  198. package/src/components/types.ts +13 -19
  199. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  200. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +127 -0
  201. package/src/containers/CommandsDialogContent/index.ts +5 -0
  202. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +28 -0
  203. package/src/containers/CommandsTrigger/index.ts +5 -0
  204. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +271 -0
  205. package/src/containers/NavTreeContainer/index.ts +6 -0
  206. package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +5 -4
  207. package/src/containers/NavTreeDocumentTitle/index.ts +5 -0
  208. package/src/containers/index.ts +12 -0
  209. package/src/experimental/Tree.stories.tsx +105 -110
  210. package/src/experimental/Tree.tsx +7 -24
  211. package/src/hooks/index.ts +8 -0
  212. package/src/hooks/useActions.ts +44 -0
  213. package/src/hooks/useLoadDescendents.ts +23 -0
  214. package/src/hooks/useNavTreeModel.ts +120 -0
  215. package/src/hooks/useNavTreeState.ts +35 -0
  216. package/src/index.ts +1 -3
  217. package/src/meta.ts +26 -8
  218. package/src/operations/expose.ts +42 -0
  219. package/src/operations/index.ts +7 -0
  220. package/src/plugin.ts +11 -0
  221. package/src/testing/app-graph-builder.ts +169 -238
  222. package/src/testing/generator.ts +36 -39
  223. package/src/testing/update-state.ts +6 -6
  224. package/src/translations.ts +8 -10
  225. package/src/types/NavTreeCapabilities.ts +21 -0
  226. package/src/types/NavTreeEvents.ts +12 -0
  227. package/src/types/index.ts +8 -0
  228. package/src/{types.ts → types/schema.ts} +13 -8
  229. package/src/util.ts +28 -17
  230. package/src/vite-env.d.ts +10 -0
  231. package/dist/lib/browser/app-graph-builder-6JDBQ25U.mjs +0 -45
  232. package/dist/lib/browser/app-graph-builder-6JDBQ25U.mjs.map +0 -7
  233. package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
  234. package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
  235. package/dist/lib/browser/chunk-SNGLGBFJ.mjs +0 -1469
  236. package/dist/lib/browser/chunk-SNGLGBFJ.mjs.map +0 -7
  237. package/dist/lib/browser/chunk-WCARAZ7J.mjs +0 -15
  238. package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
  239. package/dist/lib/browser/index.mjs +0 -148
  240. package/dist/lib/browser/index.mjs.map +0 -7
  241. package/dist/lib/browser/intent-resolver-N35ZIHFD.mjs +0 -47
  242. package/dist/lib/browser/intent-resolver-N35ZIHFD.mjs.map +0 -7
  243. package/dist/lib/browser/keyboard-HMTMA33N.mjs.map +0 -7
  244. package/dist/lib/browser/meta.json +0 -1
  245. package/dist/lib/browser/react-surface-WKWXMM2N.mjs +0 -51
  246. package/dist/lib/browser/react-surface-WKWXMM2N.mjs.map +0 -7
  247. package/dist/lib/browser/state-P5DGL7KS.mjs +0 -117
  248. package/dist/lib/browser/state-P5DGL7KS.mjs.map +0 -7
  249. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  250. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  251. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  252. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  253. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +0 -5
  254. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  255. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  256. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  257. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  258. package/dist/types/src/components/NavTreeContainer.d.ts +0 -9
  259. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  260. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  261. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  262. package/dist/types/src/events.d.ts +0 -4
  263. package/dist/types/src/events.d.ts.map +0 -1
  264. package/dist/types/src/hooks.d.ts +0 -3
  265. package/dist/types/src/hooks.d.ts.map +0 -1
  266. package/dist/types/src/types.d.ts.map +0 -1
  267. package/src/capabilities/capabilities.ts +0 -20
  268. package/src/capabilities/intent-resolver.ts +0 -37
  269. package/src/components/CommandsDialog/CommandsDialog.tsx +0 -118
  270. package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -35
  271. package/src/components/CommandsDialog/index.ts +0 -6
  272. package/src/components/NavTreeContainer.tsx +0 -337
  273. package/src/events.ts +0 -11
  274. package/src/hooks.ts +0 -21
  275. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
@@ -2,19 +2,21 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
6
- import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
7
- import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';
8
- import { scrollJustEnoughIntoView } from '@atlaskit/pragmatic-drag-and-drop/element/scroll-just-enough-into-view';
9
5
  import {
10
6
  type Edge,
11
7
  attachClosestEdge,
12
8
  extractClosestEdge,
13
9
  } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
10
+ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
11
+ import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
12
+ import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';
13
+ import { scrollJustEnoughIntoView } from '@atlaskit/pragmatic-drag-and-drop/element/scroll-just-enough-into-view';
14
+ import { useAtomValue } from '@effect-atom/atom-react';
14
15
  import React, {
15
16
  type MouseEvent,
16
17
  type PropsWithChildren,
17
18
  forwardRef,
19
+ memo,
18
20
  useCallback,
19
21
  useLayoutEffect,
20
22
  useMemo,
@@ -23,16 +25,28 @@ import React, {
23
25
  } from 'react';
24
26
 
25
27
  import { type Node } from '@dxos/app-graph';
26
- import { invariant } from '@dxos/invariant';
27
- import { Icon, ListItem, ScrollArea, Tooltip, toLocalizedString, useMediaQuery, useTranslation } from '@dxos/react-ui';
28
- import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
28
+ import { DxAvatar } from '@dxos/lit-ui/react';
29
+ import { useActionRunner } from '@dxos/plugin-graph';
30
+ import {
31
+ Icon,
32
+ IconButton,
33
+ ListItem,
34
+ ScrollArea,
35
+ type ThemedClassName,
36
+ Tooltip,
37
+ toLocalizedString,
38
+ useMediaQuery,
39
+ useTranslation,
40
+ } from '@dxos/react-ui';
41
+ import { Menu, type MenuItem } from '@dxos/react-ui-menu';
29
42
  import type { StackItemRearrangeHandler } from '@dxos/react-ui-stack';
30
43
  import { Tabs } from '@dxos/react-ui-tabs';
31
- import { mx } from '@dxos/react-ui-theme';
32
- import { arrayMove, getFirstTwoRenderableChars } from '@dxos/util';
44
+ import { mx } from '@dxos/ui-theme';
45
+ import { arrayMove } from '@dxos/util';
46
+
47
+ import { useNavTreeState } from '#hooks';
48
+ import { meta } from '#meta';
33
49
 
34
- import { useLoadDescendents } from '../../hooks';
35
- import { NAVTREE_PLUGIN } from '../../meta';
36
50
  import { l0ItemType } from '../../util';
37
51
  import { useNavTreeContext } from '../NavTreeContext';
38
52
  import { UserAccountAvatar } from '../UserAccountAvatar';
@@ -47,43 +61,41 @@ type L0ItemData = {
47
61
  };
48
62
 
49
63
  type L0ItemRootProps = {
50
- item: Node<any>;
51
- parent?: Node<any>;
64
+ item: Node.Node;
65
+ parent?: Node.Node;
52
66
  path: string[];
67
+ onMouseEnter?: () => void;
53
68
  };
54
69
 
55
70
  type L0ItemProps = L0ItemRootProps & {
56
- item: Node<any>;
57
- parent?: Node<any>;
71
+ item: Node.Node;
72
+ parent?: Node.Node;
58
73
  path: string[];
59
74
  pinned?: boolean;
60
75
  onRearrange?: StackItemRearrangeHandler<L0ItemData>;
76
+ onItemHover?: (params: { item: Node.Node }) => void;
61
77
  };
62
78
 
63
79
  const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
64
- const { tab, isCurrent, onSelect, onTabChange } = useNavTreeContext();
65
- const [isLg] = useMediaQuery('lg', { ssr: false });
80
+ const { onSelect, onTabChange } = useNavTreeContext();
81
+ const { getItem } = useNavTreeState();
82
+ const [isLg] = useMediaQuery('lg');
83
+ const runAction = useActionRunner();
66
84
 
67
85
  return useCallback(
68
86
  (event: MouseEvent) => {
69
87
  switch (type) {
70
88
  case 'action': {
71
- const {
72
- data: invoke,
73
- properties: { caller },
74
- } = item;
75
-
76
- return invoke?.(caller ? { node: parent, caller } : { node: parent });
89
+ const { properties: { caller } = {} } = item;
90
+ return void runAction(item as Node.Action, caller ? { parent, path, caller } : { parent, path });
77
91
  }
78
-
79
92
  case 'tab':
80
93
  return onTabChange?.(item);
81
-
82
94
  case 'link':
83
- return onSelect?.({ item, path, current: !isCurrent(path, item), option: event.altKey });
95
+ return onSelect?.({ item, path, current: !getItem(path).current, option: event.altKey });
84
96
  }
85
97
  },
86
- [item, parent, type, tab, isCurrent, onSelect, onTabChange, isLg],
98
+ [item, parent, type, getItem, onSelect, onTabChange, isLg, runAction],
87
99
  );
88
100
  };
89
101
 
@@ -91,74 +103,61 @@ const l0Breakpoints: Record<string, string> = {
91
103
  lg: 'hidden lg:grid',
92
104
  };
93
105
 
94
- const l0ItemRoot =
95
- 'group/l0item flex w-full justify-center items-center relative data[type!="collection"]:cursor-pointer app-no-drag dx-focus-ring-group';
96
-
97
- const l0ItemContent = 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm';
98
-
99
- const L0ItemRoot = forwardRef<HTMLElement, PropsWithChildren<L0ItemRootProps>>(
100
- ({ item, parent, path, children }, forwardedRef) => {
101
- const { getProps } = useNavTreeContext();
102
- const { id, testId } = getProps?.(item, path) ?? {};
103
- const type = l0ItemType(item);
104
- const itemPath = useMemo(() => [...path, item.id], [item.id, path]);
105
-
106
- const { t } = useTranslation(NAVTREE_PLUGIN);
107
- const localizedString = toLocalizedString(item.properties.label, t);
108
-
109
- const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);
110
- const rootProps =
111
- type === 'tab'
112
- ? { value: item.id, tabIndex: 0, onClick: handleClick, 'data-testid': testId, 'data-itemid': id }
113
- : type !== 'collection'
114
- ? { onClick: handleClick, 'data-testid': testId, 'data-itemid': id }
115
- : { onClick: handleClick };
116
-
117
- const Root = type === 'collection' ? 'h2' : type === 'tab' ? Tabs.TabPrimitive : 'button';
118
-
119
- return (
120
- <Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>
121
- <Root
122
- {...(rootProps as any)}
123
- data-type={type}
124
- className={mx(l0ItemRoot, l0Breakpoints[item.properties.l0Breakpoint])}
125
- ref={forwardedRef}
126
- >
127
- {children}
128
- </Root>
129
- </Tooltip.Trigger>
130
- );
131
- },
106
+ const L0ItemRoot = memo(
107
+ forwardRef<HTMLButtonElement, PropsWithChildren<L0ItemRootProps>>(
108
+ ({ item, parent, path, onMouseEnter, children }, forwardedRef) => {
109
+ const { t } = useTranslation(meta.id);
110
+ const { model } = useNavTreeContext();
111
+ const itemPath = useMemo(() => [...path, item.id], [item.id, path]);
112
+ const { id, testId } = useAtomValue(model.itemProps(itemPath));
113
+ const localizedString = toLocalizedString(item.properties.label, t);
114
+
115
+ const type = l0ItemType(item);
116
+ const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);
117
+
118
+ return (
119
+ <Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>
120
+ <Tabs.TabPrimitive
121
+ className={mx(
122
+ 'group/l0item flex w-full justify-center items-center relative',
123
+ 'dx-app-no-drag dx-focus-ring-group data[type!="collection"]:cursor-pointer',
124
+ l0Breakpoints[item.properties.l0Breakpoint],
125
+ )}
126
+ tabIndex={type === 'tab' ? 0 : undefined}
127
+ data-type={type}
128
+ data-testid={testId}
129
+ data-object-id={id}
130
+ value={item.id}
131
+ onClick={handleClick}
132
+ onMouseEnter={onMouseEnter}
133
+ ref={forwardedRef}
134
+ >
135
+ {children}
136
+ </Tabs.TabPrimitive>
137
+ </Tooltip.Trigger>
138
+ );
139
+ },
140
+ ),
132
141
  );
133
142
 
134
- const L0Avatar = ({ item }: Pick<L0ItemProps, 'item'>) => {
135
- const { t } = useTranslation(NAVTREE_PLUGIN);
136
- const type = l0ItemType(item);
137
- const hue = item.properties.hue ?? null;
138
- const hueFgStyle = hue && { style: { color: `var(--dx-${hue}SurfaceText)` } };
139
- const localizedString = toLocalizedString(item.properties.label, t);
140
- const avatarValue = useMemo(
141
- () => (type === 'tab' ? getFirstTwoRenderableChars(localizedString).join('').toUpperCase() : []),
142
- [type, item.properties.label, t],
143
- );
144
-
145
- return (
146
- <span role='img' className='place-self-center text-xl font-light' {...hueFgStyle}>
147
- {avatarValue}
148
- </span>
149
- );
150
- };
143
+ export const L0ItemActiveTabIndicator = ({ classNames }: ThemedClassName<{}>) => (
144
+ <div
145
+ className={mx(
146
+ 'hidden group-aria-selected/l0item:block absolute start-0 h-6 w-1.5 bg-accent-bg rounded-sm',
147
+ classNames,
148
+ )}
149
+ />
150
+ );
151
151
 
152
152
  // TODO(burdon): Factor out pinned (non-draggable) items.
153
- const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
154
- const { t } = useTranslation(NAVTREE_PLUGIN);
155
- const itemElement = useRef<HTMLElement | null>(null);
153
+ const L0Item = memo(({ item, parent, path, pinned, onRearrange, onItemHover }: L0ItemProps) => {
154
+ const { t } = useTranslation(meta.id);
155
+ const itemElement = useRef<HTMLButtonElement | null>(null);
156
156
  const [closestEdge, setEdge] = useState<Edge | null>(null);
157
157
  const localizedString = toLocalizedString(item.properties.label, t);
158
158
  const hue = item.properties.hue ?? null;
159
159
 
160
160
  useLayoutEffect(() => {
161
- // NOTE(thure): This is copied from StackItem, perhaps this should be DRYed out.
162
161
  if (!itemElement.current || !onRearrange) {
163
162
  return;
164
163
  }
@@ -213,178 +212,160 @@ const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
213
212
  );
214
213
  }, [item, onRearrange]);
215
214
 
215
+ const handleMouseEnter = useCallback(() => onItemHover?.({ item }), [item, onItemHover]);
216
+
216
217
  return (
217
- <L0ItemRoot ref={itemElement} item={item} parent={parent} path={path}>
218
+ <L0ItemRoot ref={itemElement} item={item} parent={parent} path={path} onMouseEnter={handleMouseEnter}>
218
219
  <div
219
- role='none'
220
220
  data-frame={true}
221
- {...(hue && { style: { background: `var(--dx-${hue}Surface)` } })}
221
+ {...(hue && { style: { background: `var(--color-${hue}-surface)` } })}
222
222
  className={mx(
223
- l0ItemContent,
223
+ 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm',
224
224
  pinned
225
- ? 'p-2 group-hover/l0item:bg-activeSurface'
226
- : 'is-[--l0-avatar-size] bs-[--l0-avatar-size] bg-activeSurface',
225
+ ? 'p-2 group-hover/l0item:bg-current-surface'
226
+ : 'w-(--dx-l0-avatar-size) h-(--dx-l0-avatar-size) bg-current-surface',
227
227
  )}
228
228
  >
229
229
  <ItemAvatar item={item} />
230
230
  </div>
231
- <div
232
- role='none'
233
- className='hidden group-aria-selected/l0item:block absolute inline-start-0 inset-block-2 is-1 bg-accentSurface rounded-ie'
234
- />
231
+ <L0ItemActiveTabIndicator />
235
232
  <span id={`${item.id}__label`} className='sr-only'>
236
233
  {localizedString}
237
234
  </span>
238
235
  {closestEdge && <ListItem.DropIndicator edge={closestEdge} />}
239
236
  </L0ItemRoot>
240
237
  );
241
- };
238
+ });
242
239
 
243
240
  const ItemAvatar = ({ item }: Pick<L0ItemProps, 'item'>) => {
244
- const type = l0ItemType(item);
241
+ const { t } = useTranslation(meta.id);
242
+
243
+ // Actions.
245
244
  if (item.properties.icon) {
246
245
  const hue = item.properties.hue ?? null;
247
- const hueFgStyle = hue && { style: { color: `var(--dx-${hue}SurfaceText)` } };
248
- return <Icon icon={item.properties.icon} size={5} {...hueFgStyle} />;
246
+ const hueFgStyle = hue && { style: { color: `var(--color-${hue}-fg)` } };
247
+ return <Icon icon={item.properties.icon} size={6} {...hueFgStyle} />;
249
248
  }
250
249
 
250
+ const type = l0ItemType(item);
251
251
  if (type === 'tab' && item.properties.disposition !== 'pin-end') {
252
- return <L0Avatar item={item} />;
252
+ const hue = item.properties.hue ?? null;
253
+ const localizedString = toLocalizedString(item.properties.label, t);
254
+ return <DxAvatar hue={hue} hueVariant='surface' variant='square' size={12} fallback={localizedString} />;
253
255
  }
254
256
 
255
257
  return null;
256
258
  };
257
259
 
258
260
  //
259
- // L0Collection
261
+ // L0Menu
260
262
  //
261
263
 
262
- const L0Collection = ({ item, path }: L0ItemProps) => {
263
- const navTreeContext = useNavTreeContext();
264
- useLoadDescendents(item);
265
- const collectionItems = navTreeContext.useItems(item);
266
- const groupPath = useMemo(() => [...path, item.id], [item.id, path]);
267
- const { id, testId } = navTreeContext.getProps?.(item, path) ?? {};
264
+ export type L0MenuProps = {
265
+ menuActions: MenuItem[];
266
+ topLevelItems: Node.Node[];
267
+ pinnedItems: Node.Node[];
268
+ userAccountItem?: Node.Node;
269
+ parent?: Node.Node;
270
+ path: string[];
271
+ onItemHover?: (params: { item: Node.Node }) => void;
272
+ };
273
+
274
+ export const L0Menu = ({
275
+ menuActions,
276
+ topLevelItems,
277
+ pinnedItems,
278
+ userAccountItem,
279
+ parent,
280
+ path,
281
+ onItemHover,
282
+ }: L0MenuProps) => {
283
+ const { t } = useTranslation(meta.id);
284
+ const runAction = useActionRunner();
285
+ const handleAction = useCallback(
286
+ (action: Node.Action, params: Node.InvokeProps) => {
287
+ void runAction(action, params);
288
+ },
289
+ [runAction],
290
+ );
268
291
 
269
292
  const handleRearrange = useCallback<StackItemRearrangeHandler<L0ItemData>>(
270
293
  (source, target, closestEdge) => {
271
- invariant(item.properties.onRearrangeChildren);
272
- const sourceIndex = collectionItems.findIndex((i) => i.id === source.id);
273
- const targetIndex = collectionItems.findIndex((i) => i.id === target.id);
294
+ const sourceItem = topLevelItems.find((i) => i.id === source.id);
295
+ if (!sourceItem?.properties.onRearrange) {
296
+ return;
297
+ }
298
+
299
+ const sourceIndex = topLevelItems.findIndex((i) => i.id === source.id);
300
+ const targetIndex = topLevelItems.findIndex((i) => i.id === target.id);
274
301
  const insertIndex =
275
302
  source.id === target.id
276
303
  ? sourceIndex
277
304
  : targetIndex +
278
305
  (sourceIndex < targetIndex ? (closestEdge === 'top' ? -1 : 0) : closestEdge === 'bottom' ? 1 : 0);
279
- const nextOrder = arrayMove([...collectionItems], sourceIndex, insertIndex);
280
- return item.properties.onRearrangeChildren(nextOrder);
306
+ const nextOrder = arrayMove([...topLevelItems], sourceIndex, insertIndex);
307
+ return sourceItem.properties.onRearrange(nextOrder.map((item) => item.data));
281
308
  },
282
- [collectionItems, item.properties.onRearrangeChildren],
309
+ [topLevelItems],
283
310
  );
284
311
 
285
- return (
286
- <div
287
- role='group'
288
- className='contents group/l0c'
289
- aria-labelledby={`${item.id}__label`}
290
- data-itemid={id}
291
- data-testid={testId}
292
- >
293
- {collectionItems.map((collectionItem) => (
294
- <L0Item
295
- key={collectionItem.id}
296
- item={collectionItem}
297
- parent={item}
298
- path={groupPath}
299
- {...(item.properties.onRearrangeChildren && { onRearrange: handleRearrange })}
300
- />
301
- ))}
302
- </div>
303
- );
304
- };
305
-
306
- //
307
- // L0Menu
308
- //
309
-
310
- export type L0MenuProps = {
311
- menuActions: MenuItem[];
312
- topLevelItems: Node<any>[];
313
- pinnedItems: Node<any>[];
314
- userAccountItem?: Node<any>;
315
- parent?: Node<any>;
316
- path: string[];
317
- };
318
-
319
- export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountItem, parent, path }: L0MenuProps) => {
320
- const { t } = useTranslation(NAVTREE_PLUGIN);
312
+ // Check if any items have onRearrange to enable drag-and-drop.
313
+ const hasRearrangeableItems = topLevelItems.some((item) => item.properties.onRearrange);
321
314
 
322
315
  return (
323
316
  <Tabs.Tablist
317
+ data-tauri-drag-region
324
318
  classNames={[
325
- 'group/l0 absolute z-[1] inset-block-0 inline-start-0 rounded-is',
326
- 'grid grid-cols-[var(--l0-size)] grid-rows-[var(--rail-size)_1fr_min-content_var(--l0-size)] contain-layout',
327
- '!is-[--l0-size] bg-baseSurface border-ie border-subduedSeparator app-drag pbe-[env(safe-area-inset-bottom)]',
319
+ 'group/l0 absolute z-[1] inset-y-0 start-0 rounded-is',
320
+ 'grid grid-cols-[var(--dx-l0-size)] grid-rows-[var(--dx-rail-size)_1fr_min-content_var(--dx-l0-size)] dx-contain-layout',
321
+ 'w-(--dx-l0-size) bg-l0-surface dx-app-drag pb-[env(safe-area-inset-bottom)]',
322
+ '[body[data-platform="macos"]_&]:pt-[30px]',
323
+ '[body[data-platform="ios"]_&]:pt-[max(env(safe-area-inset-top),0.25rem)]',
328
324
  ]}
329
325
  >
330
326
  {/* TODO(wittjosiah): Use L0Item trigger. */}
331
- <MenuProvider>
332
- <DropdownMenu.Root group={parent} items={menuActions}>
333
- <Tooltip.Trigger content={t('app menu label')} side='right' asChild>
334
- <DropdownMenu.Trigger
335
- data-testid='spacePlugin.addSpace'
336
- className={mx(l0ItemRoot, 'grid place-items-center')}
337
- >
338
- <div
339
- role='none'
340
- className={mx(
341
- l0ItemContent,
342
- 'is-[--rail-action] bs-[--rail-action] group-hover/l0item:bg-hoverSurface',
343
- )}
344
- >
345
- <Icon icon='ph--list--regular' size={5} />
346
- </div>
347
- </DropdownMenu.Trigger>
348
- </Tooltip.Trigger>
349
- </DropdownMenu.Root>
350
- </MenuProvider>
327
+ <Menu.Root onAction={handleAction}>
328
+ <Menu.Trigger asChild data-testid='spacePlugin.addSpace'>
329
+ <div className='grid place-items-center'>
330
+ <IconButton
331
+ density='lg'
332
+ variant='ghost'
333
+ size={5}
334
+ icon='ph--list--regular'
335
+ iconOnly
336
+ square
337
+ label={t('app-menu.label')}
338
+ />
339
+ </div>
340
+ </Menu.Trigger>
341
+ <Menu.Content group={parent} items={menuActions} />
342
+ </Menu.Root>
351
343
 
352
344
  {/* Space list. */}
353
- <ScrollArea.Root>
354
- <ScrollArea.Viewport>
355
- <div
356
- role='none'
357
- className={mx([
358
- 'flex flex-col gap-1 pbs-1',
359
- '[body[data-platform="darwin"]_&]:pbs-[calc(30px+0.25rem)]',
360
- '[body[data-platform="ios"]_&]:pbs-[max(env(safe-area-inset-top),0.25rem)]',
361
- ])}
362
- >
363
- {topLevelItems.map((item) => {
364
- if (l0ItemType(item) === 'collection') {
365
- return <L0Collection key={item.id} item={item} parent={parent} path={path} />;
366
- } else {
367
- return <L0Item key={item.id} item={item} parent={parent} path={path} />;
368
- }
369
- })}
370
- </div>
371
- <ScrollArea.Scrollbar orientation='vertical'>
372
- <ScrollArea.Thumb />
373
- </ScrollArea.Scrollbar>
345
+ <ScrollArea.Root centered thin orientation='vertical'>
346
+ <ScrollArea.Viewport classNames='flex flex-col gap-2 py-1'>
347
+ {topLevelItems.map((item) => (
348
+ <L0Item
349
+ key={item.id}
350
+ item={item}
351
+ parent={parent}
352
+ path={path}
353
+ onItemHover={onItemHover}
354
+ {...(hasRearrangeableItems && { onRearrange: handleRearrange })}
355
+ />
356
+ ))}
374
357
  </ScrollArea.Viewport>
375
358
  </ScrollArea.Root>
376
359
 
377
360
  {/* Actions. */}
378
- <div role='none' className='grid grid-cols-1 auto-rows-[--rail-action] pbs-2'>
379
- {pinnedItems
380
- .filter((item) => l0ItemType(item) !== 'collection')
381
- .map((item) => (
382
- <L0Item key={item.id} item={item} parent={parent} path={path} pinned />
383
- ))}
361
+ <div className='grid grid-cols-1 auto-rows-(--dx-rail-action) pt-2'>
362
+ {pinnedItems.map((item) => (
363
+ <L0Item key={item.id} item={item} parent={parent} path={path} pinned />
364
+ ))}
384
365
  </div>
385
366
 
386
367
  {userAccountItem && (
387
- <div role='none' className='grid app-no-drag'>
368
+ <div className='grid dx-app-no-drag'>
388
369
  <L0ItemRoot key={userAccountItem.id} item={userAccountItem} parent={parent} path={path}>
389
370
  <UserAccountAvatar
390
371
  userId={userAccountItem.properties.userId}
@@ -396,15 +377,6 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
396
377
  </L0ItemRoot>
397
378
  </div>
398
379
  )}
399
-
400
- <div
401
- role='none'
402
- className='hidden [body[data-platform="darwin"]_&]:block absolute block-start-0 is-[calc(var(--l0-size)-1px)] bs-[calc(40px+0.25rem)]'
403
- style={{
404
- background:
405
- 'linear-gradient(to bottom, var(--dx-sidebarSurface) 0%, var(--dx-sidebarSurface) 70%, transparent 100%)',
406
- }}
407
- />
408
380
  </Tabs.Tablist>
409
381
  );
410
382
  };