@dxos/plugin-navtree 0.8.4-main.4a85c3132b → 0.8.4-main.4f23b4e393

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 (244) hide show
  1. package/dist/lib/{browser/CommandsDialogContent-A27AKTHH.mjs → neutral/CommandsDialogContent-UBGIQ5FI.mjs} +24 -23
  2. package/dist/lib/neutral/CommandsDialogContent-UBGIQ5FI.mjs.map +7 -0
  3. package/dist/lib/{browser/CommandsTrigger-HBZYQCGV.mjs → neutral/CommandsTrigger-BH5WLMHK.mjs} +8 -14
  4. package/dist/lib/neutral/CommandsTrigger-BH5WLMHK.mjs.map +7 -0
  5. package/dist/lib/neutral/NavTreeContainer-6AR4BFDD.mjs +12 -0
  6. package/dist/lib/neutral/NavTreeContainer-6AR4BFDD.mjs.map +7 -0
  7. package/dist/lib/{browser/NavTreeDocumentTitle-GEE3URWH.mjs → neutral/NavTreeDocumentTitle-H3E6ZLYE.mjs} +5 -9
  8. package/dist/lib/neutral/NavTreeDocumentTitle-H3E6ZLYE.mjs.map +7 -0
  9. package/dist/lib/neutral/NavTreePlugin.mjs +56 -0
  10. package/dist/lib/neutral/NavTreePlugin.mjs.map +7 -0
  11. package/dist/lib/neutral/NavTreePlugin.node.mjs +18 -0
  12. package/dist/lib/neutral/NavTreePlugin.node.mjs.map +7 -0
  13. package/dist/lib/{browser/app-graph-builder-XGA4GPGL.mjs → neutral/app-graph-builder-Z347LKSF.mjs} +10 -12
  14. package/dist/lib/neutral/app-graph-builder-Z347LKSF.mjs.map +7 -0
  15. package/dist/lib/neutral/capabilities/index.mjs +17 -0
  16. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  17. package/dist/lib/neutral/chunk-5OPDKH6B.mjs +273 -0
  18. package/dist/lib/neutral/chunk-5OPDKH6B.mjs.map +7 -0
  19. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  20. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  21. package/dist/lib/neutral/chunk-JOSNCOV4.mjs +79 -0
  22. package/dist/lib/neutral/chunk-JOSNCOV4.mjs.map +7 -0
  23. package/dist/lib/neutral/chunk-T7QS2EFI.mjs +8 -0
  24. package/dist/lib/neutral/chunk-T7QS2EFI.mjs.map +7 -0
  25. package/dist/lib/{browser/chunk-YKTYPINZ.mjs → neutral/chunk-YDE5I3P5.mjs} +7 -4
  26. package/dist/lib/neutral/chunk-YDE5I3P5.mjs.map +7 -0
  27. package/dist/lib/neutral/chunk-ZSWYB7JW.mjs +27 -0
  28. package/dist/lib/neutral/chunk-ZSWYB7JW.mjs.map +7 -0
  29. package/dist/lib/neutral/components/index.mjs +878 -0
  30. package/dist/lib/neutral/components/index.mjs.map +7 -0
  31. package/dist/lib/neutral/containers/index.mjs +20 -0
  32. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  33. package/dist/lib/neutral/expose-26FV4W5D.mjs +38 -0
  34. package/dist/lib/neutral/expose-26FV4W5D.mjs.map +7 -0
  35. package/dist/lib/neutral/hooks/index.mjs +169 -0
  36. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  37. package/dist/lib/neutral/index.mjs +34 -0
  38. package/dist/lib/neutral/index.mjs.map +7 -0
  39. package/dist/lib/{browser/keyboard-OJZC54PK.mjs → neutral/keyboard-EJ65BVTC.mjs} +8 -6
  40. package/dist/lib/neutral/keyboard-EJ65BVTC.mjs.map +7 -0
  41. package/dist/lib/neutral/meta.json +1 -0
  42. package/dist/lib/neutral/meta.mjs +12 -0
  43. package/dist/lib/neutral/meta.mjs.map +7 -0
  44. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs +13 -0
  45. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs.map +7 -0
  46. package/dist/lib/neutral/operations/index.mjs +8 -0
  47. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  48. package/dist/lib/neutral/plugin.mjs +16 -0
  49. package/dist/lib/neutral/plugin.mjs.map +7 -0
  50. package/dist/lib/{browser/react-surface-AYHOAJ4I.mjs → neutral/react-surface-3AJ6BHL4.mjs} +10 -19
  51. package/dist/lib/neutral/react-surface-3AJ6BHL4.mjs.map +7 -0
  52. package/dist/lib/{browser/state-AC3EETN7.mjs → neutral/state-VVITVXWM.mjs} +7 -11
  53. package/dist/lib/neutral/state-VVITVXWM.mjs.map +7 -0
  54. package/dist/lib/neutral/testing/index.mjs +436 -0
  55. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  56. package/dist/lib/neutral/translations.mjs +23 -0
  57. package/dist/lib/neutral/translations.mjs.map +7 -0
  58. package/dist/lib/neutral/types/index.mjs +10 -0
  59. package/dist/lib/neutral/types/index.mjs.map +7 -0
  60. package/dist/types/src/NavTreePlugin.d.ts +1 -0
  61. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  62. package/dist/types/src/NavTreePlugin.node.d.ts +4 -0
  63. package/dist/types/src/NavTreePlugin.node.d.ts.map +1 -0
  64. package/dist/types/src/NavTreePlugin.test.d.ts +2 -0
  65. package/dist/types/src/NavTreePlugin.test.d.ts.map +1 -0
  66. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  67. package/dist/types/src/capabilities/index.d.ts +7 -5
  68. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  69. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -0
  70. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  71. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  72. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  73. package/dist/types/src/capabilities/state.d.ts +6 -0
  74. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  75. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  76. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +9 -11
  77. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  78. package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
  79. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
  80. package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
  81. package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
  82. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +7 -3
  83. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  84. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +1 -1
  85. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  86. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  87. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  88. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  89. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  90. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  91. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  92. package/dist/types/src/components/types.d.ts +1 -2
  93. package/dist/types/src/components/types.d.ts.map +1 -1
  94. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -1
  95. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  96. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  97. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +1 -2
  98. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -1
  99. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -1
  100. package/dist/types/src/containers/CommandsTrigger/index.d.ts +1 -2
  101. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -1
  102. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -1
  103. package/dist/types/src/containers/NavTreeContainer/index.d.ts +2 -2
  104. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -1
  105. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -1
  106. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +1 -2
  107. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -1
  108. package/dist/types/src/containers/index.d.ts +1 -1
  109. package/dist/types/src/containers/index.d.ts.map +1 -1
  110. package/dist/types/src/experimental/Tree.d.ts +2 -2
  111. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  112. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  113. package/dist/types/src/hooks/useActions.d.ts +2 -4
  114. package/dist/types/src/hooks/useActions.d.ts.map +1 -1
  115. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -1
  116. package/dist/types/src/hooks/useNavTreeModel.d.ts +1 -1
  117. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -1
  118. package/dist/types/src/hooks/useNavTreeState.d.ts +2 -6
  119. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -1
  120. package/dist/types/src/index.d.ts +1 -2
  121. package/dist/types/src/index.d.ts.map +1 -1
  122. package/dist/types/src/meta.d.ts.map +1 -1
  123. package/dist/types/src/operations/expose.d.ts +5 -0
  124. package/dist/types/src/operations/expose.d.ts.map +1 -0
  125. package/dist/types/src/operations/index.d.ts +3 -0
  126. package/dist/types/src/operations/index.d.ts.map +1 -0
  127. package/dist/types/src/plugin.d.ts +4 -0
  128. package/dist/types/src/plugin.d.ts.map +1 -0
  129. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  130. package/dist/types/src/testing/generator.d.ts.map +1 -1
  131. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  132. package/dist/types/src/translations.d.ts +8 -11
  133. package/dist/types/src/translations.d.ts.map +1 -1
  134. package/dist/types/src/types/NavTreeCapabilities.d.ts +13 -0
  135. package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -0
  136. package/dist/types/src/types/NavTreeEvents.d.ts +3 -0
  137. package/dist/types/src/types/NavTreeEvents.d.ts.map +1 -0
  138. package/dist/types/src/types/index.d.ts +2 -2
  139. package/dist/types/src/types/index.d.ts.map +1 -1
  140. package/dist/types/src/util.d.ts +2 -2
  141. package/dist/types/src/util.d.ts.map +1 -1
  142. package/dist/types/tsconfig.tsbuildinfo +1 -1
  143. package/package.json +107 -47
  144. package/src/NavTreePlugin.node.ts +17 -0
  145. package/src/NavTreePlugin.test.ts +27 -0
  146. package/src/NavTreePlugin.tsx +8 -25
  147. package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +7 -7
  148. package/src/capabilities/index.ts +11 -5
  149. package/src/capabilities/{keyboard/keyboard.ts → keyboard.ts} +2 -2
  150. package/src/capabilities/operation-handler.ts +16 -0
  151. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +8 -8
  152. package/src/capabilities/{state/state.ts → state.ts} +14 -10
  153. package/src/components/NavTree/NavTree.stories.tsx +18 -17
  154. package/src/components/NavTree/NavTree.tsx +3 -2
  155. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  156. package/src/components/NavTreeContext/index.ts +5 -0
  157. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +6 -8
  158. package/src/components/NavTreeItem/NavTreeItemAction.tsx +62 -45
  159. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +8 -6
  160. package/src/components/Sidebar/L0Menu.tsx +54 -81
  161. package/src/components/Sidebar/L1Panel.tsx +98 -135
  162. package/src/components/Sidebar/L1Tabs.tsx +0 -1
  163. package/src/components/types.ts +1 -2
  164. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  165. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +52 -58
  166. package/src/containers/CommandsDialogContent/index.ts +1 -3
  167. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +7 -5
  168. package/src/containers/CommandsTrigger/index.ts +1 -3
  169. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +28 -27
  170. package/src/containers/NavTreeContainer/index.ts +2 -3
  171. package/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.tsx +2 -2
  172. package/src/containers/NavTreeDocumentTitle/index.ts +1 -3
  173. package/src/containers/index.ts +1 -1
  174. package/src/experimental/Tree.stories.tsx +27 -27
  175. package/src/experimental/Tree.tsx +2 -2
  176. package/src/hooks/useActions.ts +18 -22
  177. package/src/hooks/useNavTreeModel.ts +11 -5
  178. package/src/hooks/useNavTreeState.ts +2 -9
  179. package/src/index.ts +1 -2
  180. package/src/meta.ts +3 -2
  181. package/src/operations/expose.ts +42 -0
  182. package/src/operations/index.ts +7 -0
  183. package/src/plugin.ts +11 -0
  184. package/src/testing/app-graph-builder.ts +40 -36
  185. package/src/testing/generator.ts +22 -22
  186. package/src/translations.ts +8 -10
  187. package/src/types/NavTreeCapabilities.ts +21 -0
  188. package/src/types/NavTreeEvents.ts +12 -0
  189. package/src/types/index.ts +3 -2
  190. package/src/util.ts +2 -2
  191. package/dist/lib/browser/CommandsDialogContent-A27AKTHH.mjs.map +0 -7
  192. package/dist/lib/browser/CommandsTrigger-HBZYQCGV.mjs.map +0 -7
  193. package/dist/lib/browser/NavTreeContainer-B5K4FUJS.mjs +0 -12
  194. package/dist/lib/browser/NavTreeContainer-B5K4FUJS.mjs.map +0 -7
  195. package/dist/lib/browser/NavTreeDocumentTitle-GEE3URWH.mjs.map +0 -7
  196. package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs.map +0 -7
  197. package/dist/lib/browser/chunk-DQCYMXEU.mjs +0 -1426
  198. package/dist/lib/browser/chunk-DQCYMXEU.mjs.map +0 -7
  199. package/dist/lib/browser/chunk-H3OJ4WLF.mjs +0 -14
  200. package/dist/lib/browser/chunk-H3OJ4WLF.mjs.map +0 -7
  201. package/dist/lib/browser/chunk-X2HDG62A.mjs +0 -23
  202. package/dist/lib/browser/chunk-X2HDG62A.mjs.map +0 -7
  203. package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +0 -7
  204. package/dist/lib/browser/index.mjs +0 -141
  205. package/dist/lib/browser/index.mjs.map +0 -7
  206. package/dist/lib/browser/keyboard-OJZC54PK.mjs.map +0 -7
  207. package/dist/lib/browser/meta.json +0 -1
  208. package/dist/lib/browser/operation-resolver-BNAMYOHF.mjs +0 -53
  209. package/dist/lib/browser/operation-resolver-BNAMYOHF.mjs.map +0 -7
  210. package/dist/lib/browser/react-surface-AYHOAJ4I.mjs.map +0 -7
  211. package/dist/lib/browser/state-AC3EETN7.mjs.map +0 -7
  212. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  213. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  214. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  215. package/dist/types/src/capabilities/keyboard/index.d.ts +0 -3
  216. package/dist/types/src/capabilities/keyboard/index.d.ts.map +0 -1
  217. package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +0 -1
  218. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  219. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  220. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  221. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  222. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  223. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  224. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  225. package/dist/types/src/capabilities/state/index.d.ts +0 -3
  226. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  227. package/dist/types/src/capabilities/state/state.d.ts +0 -6
  228. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  229. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  230. package/dist/types/src/types/capabilities.d.ts +0 -16
  231. package/dist/types/src/types/capabilities.d.ts.map +0 -1
  232. package/dist/types/src/types/events.d.ts +0 -5
  233. package/dist/types/src/types/events.d.ts.map +0 -1
  234. package/src/capabilities/app-graph-builder/index.ts +0 -7
  235. package/src/capabilities/keyboard/index.ts +0 -7
  236. package/src/capabilities/operation-resolver/index.ts +0 -7
  237. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -44
  238. package/src/capabilities/react-surface/index.ts +0 -7
  239. package/src/capabilities/state/index.ts +0 -7
  240. package/src/types/capabilities.ts +0 -21
  241. package/src/types/events.ts +0 -12
  242. /package/dist/types/src/capabilities/{app-graph-builder/app-graph-builder.d.ts → app-graph-builder.d.ts} +0 -0
  243. /package/dist/types/src/capabilities/{keyboard/keyboard.d.ts → keyboard.d.ts} +0 -0
  244. /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
@@ -2,21 +2,22 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import * as Effect from 'effect/Effect';
6
5
  import * as Option from 'effect/Option';
7
6
  import React, { memo, useCallback, useMemo } from 'react';
8
7
 
9
8
  import { Node } from '@dxos/app-graph';
9
+ import { isPinnedWorkspace } from '@dxos/app-toolkit';
10
10
  import { useAppGraph } from '@dxos/app-toolkit/ui';
11
- import { Graph, useActionRunner, useConnections, useEdges } from '@dxos/plugin-graph';
11
+ import { Graph, useActionRunner, useEdges } from '@dxos/plugin-graph';
12
12
  import { DensityProvider, IconButton, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';
13
13
  import { Tree } from '@dxos/react-ui-list';
14
14
  import { Menu, type MenuItem } from '@dxos/react-ui-menu';
15
15
  import { Tabs } from '@dxos/react-ui-tabs';
16
16
  import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';
17
17
 
18
- import { useActions, useIsAlternateTree, useLoadDescendents } from '../../hooks';
19
- import { meta } from '../../meta';
18
+ import { useActions, useLoadDescendents } from '#hooks';
19
+ import { meta } from '#meta';
20
+
20
21
  import { NAV_TREE_ITEM } from '../NavTree';
21
22
  import { useNavTreeContext } from '../NavTreeContext';
22
23
  import { NavTreeItemAction, NavTreeItemColumns } from '../NavTreeItem';
@@ -39,7 +40,7 @@ const L1Panel$ = ({ open, path, item, isCurrent, onBack }: L1PanelProps) => {
39
40
  const shouldRenderContent = isCurrent || isActivated;
40
41
 
41
42
  return (
42
- <Tabs.Tabpanel
43
+ <Tabs.Panel
43
44
  key={item.id}
44
45
  value={item.id}
45
46
  classNames={[
@@ -54,7 +55,7 @@ const L1Panel$ = ({ open, path, item, isCurrent, onBack }: L1PanelProps) => {
54
55
  {...(!open && { inert: true })}
55
56
  >
56
57
  {shouldRenderContent && <L1PanelContent open={open} path={path} item={item} onBack={onBack} />}
57
- </Tabs.Tabpanel>
58
+ </Tabs.Panel>
58
59
  );
59
60
  };
60
61
 
@@ -81,49 +82,27 @@ const useIsActivatedWorkspace = (item: Node.Node): boolean => {
81
82
  const L1PanelContent = ({ path, item, onBack }: Pick<L1PanelProps, 'open' | 'path' | 'item' | 'onBack'>) => {
82
83
  const navTreeContext = useNavTreeContext();
83
84
 
84
- const alternateTree = useAlternateTreeItem(item);
85
- const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
86
- const isAlternate = useIsAlternateTree(alternatePath, item);
87
-
88
85
  return (
89
86
  <DensityProvider density='fine'>
90
87
  <L1PanelHeader path={path} item={item} onBack={onBack} />
91
88
  <ScrollArea.Root thin orientation='vertical'>
92
89
  <ScrollArea.Viewport>
93
- {isAlternate && alternateTree ? (
94
- <Tree
95
- model={navTreeContext.model}
96
- id={alternateTree.id}
97
- rootId={alternateTree.id}
98
- path={alternatePath}
99
- levelOffset={5}
100
- gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
101
- renderColumns={NavTreeItemColumns}
102
- blockInstruction={navTreeContext.blockInstruction}
103
- canDrop={navTreeContext.canDrop}
104
- canSelect={navTreeContext.canSelect}
105
- onOpenChange={navTreeContext.onOpenChange}
106
- onSelect={navTreeContext.onSelect}
107
- onItemHover={navTreeContext.onItemHover}
108
- />
109
- ) : (
110
- <Tree
111
- model={navTreeContext.model}
112
- id={item.id}
113
- rootId={item.id}
114
- path={path}
115
- levelOffset={5}
116
- gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
117
- draggable
118
- renderColumns={NavTreeItemColumns}
119
- blockInstruction={navTreeContext.blockInstruction}
120
- canDrop={navTreeContext.canDrop}
121
- canSelect={navTreeContext.canSelect}
122
- onOpenChange={navTreeContext.onOpenChange}
123
- onSelect={navTreeContext.onSelect}
124
- onItemHover={navTreeContext.onItemHover}
125
- />
126
- )}
90
+ <Tree
91
+ model={navTreeContext.model}
92
+ id={item.id}
93
+ rootId={item.id}
94
+ path={path}
95
+ levelOffset={5}
96
+ gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
97
+ draggable
98
+ renderColumns={NavTreeItemColumns}
99
+ blockInstruction={navTreeContext.blockInstruction}
100
+ canDrop={navTreeContext.canDrop}
101
+ canSelect={navTreeContext.canSelect}
102
+ onOpenChange={navTreeContext.onOpenChange}
103
+ onSelect={navTreeContext.onSelect}
104
+ onItemHover={navTreeContext.onItemHover}
105
+ />
127
106
  </ScrollArea.Viewport>
128
107
  </ScrollArea.Root>
129
108
  </DensityProvider>
@@ -137,152 +116,136 @@ const L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'item' | 'path
137
116
  const { t } = useTranslation(meta.id);
138
117
  const { renderItemEnd: ItemEnd } = useNavTreeContext();
139
118
  const title = toLocalizedString(item.properties.label, t);
140
- const backCapableWorkspace = item.id.startsWith('!');
119
+ const backCapableWorkspace = isPinnedWorkspace(item.id);
141
120
 
142
121
  const { primaryAction, groupedActions, menuActions, onAction } = useL1MenuActions({ item, path });
143
122
  useLoadDescendents(item);
144
123
 
145
124
  return (
146
- <div className='flex w-full items-center border-b border-subdued-separator dx-app-drag dx-density-coarse pe-1'>
125
+ <div
126
+ data-tauri-drag-region
127
+ className='flex w-full items-center border-b border-subdued-separator dx-app-drag dx-density-coarse pe-1'
128
+ >
147
129
  {backCapableWorkspace ? (
148
130
  <IconButton
149
- size={5}
150
131
  density='coarse'
151
132
  classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
152
133
  variant='ghost'
153
134
  icon='ph--caret-left--regular'
154
135
  iconOnly
155
- label={t('button back')}
136
+ label={t('button-back.button')}
156
137
  data-testid='treeView.primaryTreeButton'
157
138
  onClick={() => onBack?.()}
158
139
  />
159
140
  ) : (
160
- <div className='w-6' />
141
+ <div data-tauri-drag-region className='w-6' />
161
142
  )}
162
- <h2 className='flex-1 truncate min-w-0'>{title}</h2>
143
+ <h2 data-tauri-drag-region className='flex-1 truncate min-w-0'>
144
+ {title}
145
+ </h2>
163
146
  {/* TODO(wittjosiah): Reconcile with NavTreeItemColumns. */}
164
- <div role='none' className='contents dx-app-no-drag'>
147
+ <div className='contents dx-app-no-drag'>
165
148
  {primaryAction?.properties?.disposition === 'list-item-primary' && !primaryAction?.properties?.disabled && (
166
149
  <NavTreeItemAction
167
150
  testId={primaryAction.properties?.testId}
168
151
  label={toLocalizedString(primaryAction.properties?.label, t)}
169
152
  icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
170
153
  parent={item}
154
+ path={path}
171
155
  monolithic={Node.isAction(primaryAction)}
172
156
  menuActions={Node.isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction?.id ?? '']}
173
157
  menuType={primaryAction.properties?.menuType}
174
158
  caller={NAV_TREE_ITEM}
175
159
  />
176
160
  )}
177
- {menuActions.length === 1 && (
178
- <IconButton
179
- size={5}
180
- density='coarse'
181
- classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
182
- variant='ghost'
183
- icon={menuActions[0].properties?.icon ?? 'ph--placeholder--regular'}
184
- iconOnly
185
- label={toLocalizedString(menuActions[0].properties?.label, t)}
186
- data-testid={menuActions[0].properties?.testId}
187
- onClick={() => onAction(menuActions[0] as Node.Action)}
188
- />
189
- )}
190
- {menuActions.length > 1 && (
191
- <Menu.Root caller={NAV_TREE_ITEM} onAction={onAction}>
192
- <Menu.Trigger asChild>
193
- <IconButton
194
- size={5}
195
- density='coarse'
196
- classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
197
- variant='ghost'
198
- icon='ph--dots-three-vertical--regular'
199
- iconOnly
200
- label={t('tree item actions label')}
201
- data-testid='navtree.treeItem.actionsLevel0'
202
- />
203
- </Menu.Trigger>
204
- <Menu.Content group={item} items={menuActions as MenuItem[]} />
205
- </Menu.Root>
206
- )}
161
+ <MenuActions item={item} menuActions={menuActions} onAction={onAction} />
207
162
  {ItemEnd && <ItemEnd node={item} open />}
208
163
  </div>
209
164
  </div>
210
165
  );
211
166
  };
212
167
 
168
+ type L1MenuActions = {
169
+ primaryAction: Node.ActionLike;
170
+ groupedActions: Record<string, Node.Action[]>;
171
+ menuActions: Node.Action[];
172
+ onAction: (action: Node.Action, params?: Node.InvokeProps) => void;
173
+ };
174
+
213
175
  /**
214
- * Builds the menu actions for the L1 panel header, combining graph actions with a synthetic settings/back action.
176
+ * Header menu actions for an L1 workspace tab. Renders nothing for an empty
177
+ * `menuActions`, a single inline icon button for one action, and a
178
+ * `…`-menu trigger for multiple.
215
179
  */
216
- const useL1MenuActions = ({ item, path }: Pick<L1PanelProps, 'item' | 'path'>) => {
180
+ const MenuActions = ({
181
+ item,
182
+ menuActions,
183
+ onAction,
184
+ }: {
185
+ item: Node.Node;
186
+ } & Pick<L1MenuActions, 'menuActions' | 'onAction'>) => {
217
187
  const { t } = useTranslation(meta.id);
218
- const { setAlternateTree } = useNavTreeContext();
219
- const { graph } = useAppGraph();
220
- const runAction = useActionRunner();
221
188
 
222
- const alternateTree = useAlternateTreeItem(item);
223
- const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
224
- const isAlternate = useIsAlternateTree(alternatePath, item);
189
+ if (menuActions.length === 0) {
190
+ return null;
191
+ }
192
+
193
+ if (menuActions.length === 1) {
194
+ return (
195
+ <IconButton
196
+ density='coarse'
197
+ classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
198
+ variant='ghost'
199
+ icon={menuActions[0].properties?.icon ?? 'ph--placeholder--regular'}
200
+ iconOnly
201
+ label={toLocalizedString(menuActions[0].properties?.label, t)}
202
+ data-testid={menuActions[0].properties?.testId}
203
+ onClick={() => onAction(menuActions[0] as Node.Action)}
204
+ />
205
+ );
206
+ }
207
+
208
+ return (
209
+ <Menu.Root caller={NAV_TREE_ITEM} onAction={onAction}>
210
+ <Menu.Trigger asChild>
211
+ <IconButton
212
+ density='coarse'
213
+ classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
214
+ variant='ghost'
215
+ icon='ph--dots-three-vertical--regular'
216
+ iconOnly
217
+ label={t('tree-item-actions.label')}
218
+ data-testid='navtree.treeItem.actionsLevel0'
219
+ />
220
+ </Menu.Trigger>
221
+ <Menu.Content group={item} items={menuActions as MenuItem[]} />
222
+ </Menu.Root>
223
+ );
224
+ };
225
+
226
+ /**
227
+ * Builds the menu actions for the L1 panel header.
228
+ */
229
+ const useL1MenuActions = ({ item, path }: Pick<L1PanelProps, 'item' | 'path'>): L1MenuActions => {
230
+ const runAction = useActionRunner();
225
231
 
226
- // Graph actions.
227
232
  const { actions: actionsProp, groupedActions } = useActions(item);
228
233
  const [primaryAction, ...secondaryActions] = actionsProp.toSorted((a, _b) =>
229
234
  a.properties?.disposition === 'list-item-primary' ? -1 : 1,
230
235
  );
231
236
 
232
- const graphMenuActions = (
233
- primaryAction?.properties?.disposition === 'list-item-primary' ? secondaryActions : actionsProp
234
- )
237
+ const menuActions = (primaryAction?.properties?.disposition === 'list-item-primary' ? secondaryActions : actionsProp)
235
238
  .flatMap((action) => (Node.isAction(action) ? [action] : []))
236
239
  .filter((a) => ['list-item', 'list-item-primary'].includes(a.properties?.disposition));
237
240
 
238
- // Synthetic settings/back action.
239
- const settingsActionId = `${item.id}~settings`;
240
- const settingsAction = useMemo((): Node.Action | undefined => {
241
- if (!alternateTree) {
242
- return undefined;
243
- }
244
- return {
245
- id: settingsActionId,
246
- type: Node.ActionType,
247
- data: () => Effect.void,
248
- properties: {
249
- label: isAlternate ? ['button back', { ns: meta.id }] : (alternateTree.properties.label ?? alternateTree.id),
250
- icon: isAlternate
251
- ? 'ph--arrow-u-down-left--regular'
252
- : (alternateTree.properties.icon ?? 'ph--placeholder--regular'),
253
- disposition: 'list-item',
254
- testId: isAlternate ? 'navtree.backToSpace' : 'navtree.spaceSettings',
255
- },
256
- } as Node.Action;
257
- }, [alternateTree, isAlternate, settingsActionId, t]);
258
-
259
- const menuActions = useMemo(
260
- () => [...graphMenuActions, ...(settingsAction ? [settingsAction] : [])],
261
- [graphMenuActions, settingsAction],
262
- );
263
-
264
241
  const onAction = useCallback(
265
242
  (action: Node.Action, params?: Node.InvokeProps) => {
266
- if (action.id === settingsActionId) {
267
- if (alternateTree && !isAlternate) {
268
- Graph.expand(graph, alternateTree.id, 'child');
269
- }
270
- setAlternateTree?.(alternatePath, !isAlternate);
271
- } else {
272
- void runAction(action, params);
273
- }
243
+ void runAction(action, { ...params, path });
274
244
  },
275
- [settingsActionId, setAlternateTree, alternatePath, isAlternate, runAction, graph, alternateTree],
245
+ [runAction, path],
276
246
  );
277
247
 
278
248
  return { primaryAction, groupedActions, menuActions, onAction };
279
249
  };
280
250
 
281
- /** Finds the first child with disposition 'alternate-tree' using graph connections directly. */
282
- const useAlternateTreeItem = (item: Node.Node): Node.Node | undefined => {
283
- const { graph } = useAppGraph();
284
- const connections = useConnections(graph, item.id, 'child');
285
- return connections.find((node) => node.properties.disposition === 'alternate-tree');
286
- };
287
-
288
251
  export const L1Panel = memo(L1Panel$);
@@ -7,7 +7,6 @@ import React from 'react';
7
7
  import { type Node } from '@dxos/app-graph';
8
8
 
9
9
  import { l0ItemType } from '../../util';
10
-
11
10
  import { L1Panel, type L1PanelProps } from './L1Panel';
12
11
 
13
12
  export type L1TabsProps = Pick<L1PanelProps, 'open' | 'onBack'> & {
@@ -8,7 +8,7 @@ import { type Node } from '@dxos/app-graph';
8
8
  import type { Density } from '@dxos/react-ui';
9
9
  import type { TreeModel, TreeProps } from '@dxos/react-ui-list';
10
10
 
11
- import type { NavTreeItemGraphNode } from '../types';
11
+ import type { NavTreeItemGraphNode } from '#types';
12
12
 
13
13
  import type { L1PanelProps } from './Sidebar';
14
14
 
@@ -16,7 +16,6 @@ export type NavTreeContextValue = {
16
16
  model: TreeModel<NavTreeItemGraphNode>;
17
17
  popoverAnchorId?: string;
18
18
  renderItemEnd?: FC<{ node: Node.Node; open: boolean }>;
19
- setAlternateTree?: (path: string[], open: boolean) => void;
20
19
  onTabChange?: (node: NavTreeItemGraphNode) => void;
21
20
  } & Pick<
22
21
  TreeProps<NavTreeItemGraphNode>,
@@ -0,0 +1,46 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React from 'react';
7
+
8
+ import { withPluginManager } from '@dxos/app-framework/testing';
9
+ import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
10
+ import { Dialog } from '@dxos/react-ui';
11
+ import { withLayout } from '@dxos/react-ui/testing';
12
+
13
+ import { translations } from '#translations';
14
+
15
+ import { NavTreePlugin } from '../../NavTreePlugin';
16
+ import { CommandsDialogContent } from './CommandsDialogContent';
17
+
18
+ const DefaultStory = () => (
19
+ <Dialog.Root defaultOpen>
20
+ <Dialog.Overlay>
21
+ <CommandsDialogContent />
22
+ </Dialog.Overlay>
23
+ </Dialog.Root>
24
+ );
25
+
26
+ const meta = {
27
+ title: 'plugins/plugin-navtree/containers/CommandsDialogContent',
28
+ component: CommandsDialogContent,
29
+ render: DefaultStory,
30
+ decorators: [
31
+ withLayout({ layout: 'fullscreen' }),
32
+ withPluginManager({
33
+ plugins: [...corePlugins(), StorybookPlugin({}), NavTreePlugin()],
34
+ }),
35
+ ],
36
+ parameters: {
37
+ layout: 'fullscreen',
38
+ translations,
39
+ },
40
+ } satisfies Meta<typeof CommandsDialogContent>;
41
+
42
+ export default meta;
43
+
44
+ type Story = StoryObj<typeof meta>;
45
+
46
+ export const Default: Story = {};
@@ -11,11 +11,11 @@ import { Keyboard, keySymbols } from '@dxos/keyboard';
11
11
  import { Graph, Node, useActionRunner } from '@dxos/plugin-graph';
12
12
  import { useActions } from '@dxos/plugin-graph';
13
13
  import { Button, Dialog, toLocalizedString, useTranslation } from '@dxos/react-ui';
14
- import { SearchList, useSearchListResults } from '@dxos/react-ui-searchlist';
14
+ import { SearchList, useSearchListResults } from '@dxos/react-ui-search';
15
15
  import { osTranslations } from '@dxos/ui-theme';
16
16
  import { getHostPlatform } from '@dxos/util';
17
17
 
18
- import { KEY_BINDING, meta } from '../../meta';
18
+ import { KEY_BINDING, meta } from '#meta';
19
19
 
20
20
  export type CommandsDialogContentProps = {
21
21
  selected?: string;
@@ -25,7 +25,7 @@ export type CommandsDialogContentProps = {
25
25
  export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogContentProps>(
26
26
  ({ selected: initial }, forwardedRef) => {
27
27
  const { t } = useTranslation(meta.id);
28
- const { invokeSync } = useOperationInvoker();
28
+ const { invokePromise } = useOperationInvoker();
29
29
  const runAction = useActionRunner();
30
30
  const { graph } = useAppGraph();
31
31
  const [selected, setSelected] = useState<string | undefined>(initial);
@@ -38,13 +38,12 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
38
38
  const actionMap = new Set<string>();
39
39
  const actions: Node.ActionLike[] = [];
40
40
  Graph.traverse(graph, {
41
- relation: 'child',
41
+ relation: ['child', 'action'],
42
42
  visitor: (node, path) => {
43
- if (
44
- (Node.isAction(node) || Node.isActionGroup(node)) &&
45
- !actionMap.has(node.id) &&
46
- current.startsWith(path.slice(0, -1).join('/'))
47
- ) {
43
+ const isActionLike = Node.isAction(node) || Node.isActionGroup(node);
44
+ const parentId = path.at(-2) ?? '';
45
+ const matches = current === parentId || current.startsWith(parentId + '/');
46
+ if (isActionLike && !actionMap.has(node.id) && matches) {
48
47
  actionMap.add(node.id);
49
48
  actions.push(node);
50
49
  }
@@ -71,62 +70,57 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
71
70
 
72
71
  return (
73
72
  <Dialog.Content ref={forwardedRef}>
74
- <Dialog.Title>{t('commands dialog title', { ns: meta.id })}</Dialog.Title>
73
+ <Dialog.Title srOnly>{t('commands-dialog.title', { ns: meta.id })}</Dialog.Title>
75
74
  <SearchList.Root onSearch={handleSearch}>
76
- <SearchList.Content>
77
- <SearchList.Input placeholder={t('command list input placeholder')} />
78
- <SearchList.Viewport>
79
- {results.map((action) => {
80
- const shortcut =
81
- typeof action.properties.keyBinding === 'string'
82
- ? action.properties.keyBinding
83
- : action.properties.keyBinding?.[getHostPlatform()];
75
+ <SearchList.Input placeholder={t('command-list-input.placeholder')} />
76
+ <SearchList.Viewport>
77
+ {results.map((action) => {
78
+ const shortcut =
79
+ typeof action.properties.keyBinding === 'string'
80
+ ? action.properties.keyBinding
81
+ : action.properties.keyBinding?.[getHostPlatform()];
84
82
 
85
- return (
86
- <SearchList.Item
87
- value={action.id}
88
- key={action.id}
89
- label={toLocalizedString(action.properties.label, t)}
90
- icon={action.properties.icon}
91
- suffix={shortcut ? keySymbols(shortcut).join('') : undefined}
92
- onSelect={() => {
93
- if (action.properties.disabled) {
94
- return;
95
- }
83
+ return (
84
+ <SearchList.Item
85
+ value={action.id}
86
+ key={action.id}
87
+ label={toLocalizedString(action.properties.label, t)}
88
+ icon={action.properties.icon}
89
+ suffix={shortcut ? keySymbols(shortcut).join('') : undefined}
90
+ onSelect={() => {
91
+ if (action.properties.disabled) {
92
+ return;
93
+ }
96
94
 
97
- if (Node.isActionGroup(action)) {
98
- setSelected(action.id);
99
- return;
100
- }
95
+ if (Node.isActionGroup(action)) {
96
+ setSelected(action.id);
97
+ return;
98
+ }
101
99
 
102
- invokeSync(LayoutOperation.UpdateDialog, { state: false });
103
- setTimeout(() => {
104
- const node = Graph.getConnections(
105
- graph,
106
- group?.id ?? action.id,
107
- Node.childRelation('inbound'),
108
- )[0];
109
- if (node && Node.isAction(action)) {
110
- void runAction(action, { parent: node, caller: KEY_BINDING });
111
- }
112
- });
113
- }}
114
- classNames='flex items-center gap-2'
115
- disabled={action.properties.disabled}
116
- {...(action.properties?.testId && {
117
- 'data-testid': action.properties.testId,
118
- })}
119
- />
120
- );
121
- })}
122
- </SearchList.Viewport>
123
- </SearchList.Content>
100
+ void invokePromise(LayoutOperation.UpdateDialog, { state: false });
101
+ setTimeout(() => {
102
+ const lookupId = group?.id ?? action.id;
103
+ const node = Graph.getConnections(graph, lookupId, Node.actionRelation('inbound'))[0];
104
+ if (node && Node.isAction(action)) {
105
+ void runAction(action, { parent: node, caller: KEY_BINDING });
106
+ }
107
+ });
108
+ }}
109
+ classNames='flex items-center gap-2'
110
+ disabled={action.properties.disabled}
111
+ {...(action.properties?.testId && {
112
+ 'data-testid': action.properties.testId,
113
+ })}
114
+ />
115
+ );
116
+ })}
117
+ </SearchList.Viewport>
124
118
  </SearchList.Root>
125
- <div role='none' className='p-form-padding'>
119
+ <Dialog.ActionBar>
126
120
  <Dialog.Close asChild>
127
- <Button classNames='w-full'>{t('close label', { ns: osTranslations })}</Button>
121
+ <Button classNames='w-full'>{t('close.label', { ns: osTranslations })}</Button>
128
122
  </Dialog.Close>
129
- </div>
123
+ </Dialog.ActionBar>
130
124
  </Dialog.Content>
131
125
  );
132
126
  },
@@ -2,6 +2,4 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { CommandsDialogContent } from './CommandsDialogContent';
6
-
7
- export default CommandsDialogContent;
5
+ export { CommandsDialogContent as default } from './CommandsDialogContent';
@@ -8,19 +8,21 @@ import { useOperationInvoker } from '@dxos/app-framework/ui';
8
8
  import { LayoutOperation } from '@dxos/app-toolkit';
9
9
  import { Button, Icon, useTranslation } from '@dxos/react-ui';
10
10
 
11
- import { COMMANDS_DIALOG, meta } from '../../meta';
11
+ import { COMMANDS_DIALOG, meta } from '#meta';
12
12
 
13
13
  // TODO(thure): Refactor to be handled by a more appropriate plugin.
14
14
  export const CommandsTrigger = () => {
15
- const { invokeSync } = useOperationInvoker();
15
+ const { invokePromise } = useOperationInvoker();
16
16
  const { t } = useTranslation(meta.id);
17
17
  return (
18
18
  <Button
19
19
  classNames='m-1 px-1 lg:px-2'
20
- onClick={() => invokeSync(LayoutOperation.UpdateDialog, { subject: COMMANDS_DIALOG, blockAlign: 'start' })}
20
+ onClick={() =>
21
+ void invokePromise(LayoutOperation.UpdateDialog, { subject: COMMANDS_DIALOG, blockAlign: 'start' })
22
+ }
21
23
  >
22
- <span className='text-description font-normal grow text-start'>{t('command list input placeholder')}</span>
23
- <Icon icon='ph--magnifying-glass--regular' size={5} />
24
+ <span className='text-description font-normal grow text-start'>{t('command-list-input.placeholder')}</span>
25
+ <Icon icon='ph--magnifying-glass--regular' />
24
26
  </Button>
25
27
  );
26
28
  };
@@ -2,6 +2,4 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { CommandsTrigger } from './CommandsTrigger';
6
-
7
- export default CommandsTrigger;
5
+ export { CommandsTrigger as default } from './CommandsTrigger';