@dxos/plugin-navtree 0.8.4-main.b97322e → 0.8.4-main.bc2380dfbc

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 (276) 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-T7QS2EFI.mjs +8 -0
  28. package/dist/lib/neutral/chunk-T7QS2EFI.mjs.map +7 -0
  29. package/dist/lib/neutral/chunk-YDE5I3P5.mjs +22 -0
  30. package/dist/lib/neutral/chunk-YDE5I3P5.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-QRS6WOQH.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-3AJ6BHL4.mjs +50 -0
  55. package/dist/lib/neutral/react-surface-3AJ6BHL4.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 +436 -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 -105
  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 +12 -5
  85. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  86. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +25 -5
  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 +33 -4
  95. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  96. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +2 -2
  97. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  98. package/dist/types/src/components/Sidebar/L0Menu.d.ts +10 -5
  99. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  100. package/dist/types/src/components/Sidebar/L1Panel.d.ts +4 -8
  101. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  102. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +13 -0
  103. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -0
  104. package/dist/types/src/components/Sidebar/index.d.ts +1 -0
  105. package/dist/types/src/components/Sidebar/index.d.ts.map +1 -1
  106. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  107. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +8 -5
  108. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  109. package/dist/types/src/components/index.d.ts +0 -3
  110. package/dist/types/src/components/index.d.ts.map +1 -1
  111. package/dist/types/src/components/types.d.ts +8 -17
  112. package/dist/types/src/components/types.d.ts.map +1 -1
  113. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts +6 -0
  114. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
  115. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +28 -0
  116. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  117. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +2 -0
  118. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
  119. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
  120. package/dist/types/src/containers/CommandsTrigger/index.d.ts +2 -0
  121. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
  122. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
  123. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
  124. package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
  125. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
  126. package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +1 -1
  127. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
  128. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +2 -0
  129. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
  130. package/dist/types/src/containers/index.d.ts +7 -0
  131. package/dist/types/src/containers/index.d.ts.map +1 -0
  132. package/dist/types/src/experimental/Tree.d.ts +3 -4
  133. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  134. package/dist/types/src/experimental/Tree.stories.d.ts +23 -6
  135. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  136. package/dist/types/src/hooks/index.d.ts +5 -0
  137. package/dist/types/src/hooks/index.d.ts.map +1 -0
  138. package/dist/types/src/hooks/useActions.d.ts +5 -0
  139. package/dist/types/src/hooks/useActions.d.ts.map +1 -0
  140. package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
  141. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
  142. package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
  143. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
  144. package/dist/types/src/hooks/useNavTreeState.d.ts +18 -0
  145. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
  146. package/dist/types/src/index.d.ts +1 -3
  147. package/dist/types/src/index.d.ts.map +1 -1
  148. package/dist/types/src/meta.d.ts +3 -4
  149. package/dist/types/src/meta.d.ts.map +1 -1
  150. package/dist/types/src/operations/expose.d.ts +5 -0
  151. package/dist/types/src/operations/expose.d.ts.map +1 -0
  152. package/dist/types/src/operations/index.d.ts +3 -0
  153. package/dist/types/src/operations/index.d.ts.map +1 -0
  154. package/dist/types/src/plugin.d.ts +4 -0
  155. package/dist/types/src/plugin.d.ts.map +1 -0
  156. package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
  157. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  158. package/dist/types/src/testing/generator.d.ts +5 -6
  159. package/dist/types/src/testing/generator.d.ts.map +1 -1
  160. package/dist/types/src/testing/update-state.d.ts +2 -2
  161. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  162. package/dist/types/src/translations.d.ts +8 -10
  163. package/dist/types/src/translations.d.ts.map +1 -1
  164. package/dist/types/src/types/NavTreeCapabilities.d.ts +13 -0
  165. package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -0
  166. package/dist/types/src/types/NavTreeEvents.d.ts +3 -0
  167. package/dist/types/src/types/NavTreeEvents.d.ts.map +1 -0
  168. package/dist/types/src/types/index.d.ts +4 -0
  169. package/dist/types/src/types/index.d.ts.map +1 -0
  170. package/dist/types/src/{types.d.ts → types/schema.d.ts} +10 -9
  171. package/dist/types/src/types/schema.d.ts.map +1 -0
  172. package/dist/types/src/util.d.ts +12 -9
  173. package/dist/types/src/util.d.ts.map +1 -1
  174. package/dist/types/tsconfig.tsbuildinfo +1 -1
  175. package/package.json +127 -62
  176. package/src/NavTreePlugin.node.ts +17 -0
  177. package/src/NavTreePlugin.test.ts +27 -0
  178. package/src/NavTreePlugin.tsx +51 -88
  179. package/src/NavTreePlugin.workerd.ts +16 -0
  180. package/src/capabilities/app-graph-builder.ts +34 -44
  181. package/src/capabilities/index.ts +10 -8
  182. package/src/capabilities/keyboard.ts +58 -51
  183. package/src/capabilities/operation-handler.ts +16 -0
  184. package/src/capabilities/react-surface.tsx +46 -38
  185. package/src/capabilities/state.ts +133 -84
  186. package/src/components/NavTree/NavTree.stories.tsx +111 -103
  187. package/src/components/NavTree/NavTree.tsx +71 -35
  188. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  189. package/src/components/NavTreeContext/index.ts +5 -0
  190. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +25 -19
  191. package/src/components/NavTreeItem/NavTreeItemAction.tsx +71 -48
  192. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +70 -38
  193. package/src/components/Sidebar/L0Menu.tsx +175 -211
  194. package/src/components/Sidebar/L1Panel.tsx +213 -135
  195. package/src/components/Sidebar/L1Tabs.tsx +42 -0
  196. package/src/components/Sidebar/index.ts +1 -0
  197. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -9
  198. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
  199. package/src/components/index.ts +1 -3
  200. package/src/components/types.ts +14 -19
  201. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +46 -0
  202. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +127 -0
  203. package/src/containers/CommandsDialogContent/index.ts +5 -0
  204. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +28 -0
  205. package/src/containers/CommandsTrigger/index.ts +5 -0
  206. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +271 -0
  207. package/src/containers/NavTreeContainer/index.ts +6 -0
  208. package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +5 -4
  209. package/src/containers/NavTreeDocumentTitle/index.ts +5 -0
  210. package/src/containers/index.ts +12 -0
  211. package/src/experimental/Tree.stories.tsx +105 -110
  212. package/src/experimental/Tree.tsx +7 -24
  213. package/src/hooks/index.ts +8 -0
  214. package/src/hooks/useActions.ts +34 -0
  215. package/src/hooks/useLoadDescendents.ts +23 -0
  216. package/src/hooks/useNavTreeModel.ts +118 -0
  217. package/src/hooks/useNavTreeState.ts +35 -0
  218. package/src/index.ts +1 -3
  219. package/src/meta.ts +12 -8
  220. package/src/operations/expose.ts +42 -0
  221. package/src/operations/index.ts +7 -0
  222. package/src/plugin.ts +11 -0
  223. package/src/testing/app-graph-builder.ts +167 -238
  224. package/src/testing/generator.ts +41 -39
  225. package/src/testing/update-state.ts +6 -6
  226. package/src/translations.ts +8 -9
  227. package/src/types/NavTreeCapabilities.ts +21 -0
  228. package/src/types/NavTreeEvents.ts +12 -0
  229. package/src/types/index.ts +8 -0
  230. package/src/{types.ts → types/schema.ts} +9 -8
  231. package/src/util.ts +26 -33
  232. package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs +0 -45
  233. package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs.map +0 -7
  234. package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
  235. package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
  236. package/dist/lib/browser/chunk-SICQTLXC.mjs +0 -1442
  237. package/dist/lib/browser/chunk-SICQTLXC.mjs.map +0 -7
  238. package/dist/lib/browser/chunk-WCARAZ7J.mjs +0 -15
  239. package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
  240. package/dist/lib/browser/index.mjs +0 -149
  241. package/dist/lib/browser/index.mjs.map +0 -7
  242. package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs +0 -47
  243. package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs.map +0 -7
  244. package/dist/lib/browser/keyboard-QRS6WOQH.mjs.map +0 -7
  245. package/dist/lib/browser/meta.json +0 -1
  246. package/dist/lib/browser/react-surface-WURHCBQQ.mjs +0 -51
  247. package/dist/lib/browser/react-surface-WURHCBQQ.mjs.map +0 -7
  248. package/dist/lib/browser/state-54DY3DOY.mjs +0 -117
  249. package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
  250. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  251. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  252. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  253. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  254. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +0 -5
  255. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  256. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  257. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  258. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  259. package/dist/types/src/components/NavTreeContainer.d.ts +0 -9
  260. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  261. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  262. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  263. package/dist/types/src/events.d.ts +0 -4
  264. package/dist/types/src/events.d.ts.map +0 -1
  265. package/dist/types/src/hooks.d.ts +0 -3
  266. package/dist/types/src/hooks.d.ts.map +0 -1
  267. package/dist/types/src/types.d.ts.map +0 -1
  268. package/src/capabilities/capabilities.ts +0 -20
  269. package/src/capabilities/intent-resolver.ts +0 -37
  270. package/src/components/CommandsDialog/CommandsDialog.tsx +0 -118
  271. package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -35
  272. package/src/components/CommandsDialog/index.ts +0 -6
  273. package/src/components/NavTreeContainer.tsx +0 -313
  274. package/src/events.ts +0 -11
  275. package/src/hooks.ts +0 -21
  276. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
@@ -2,45 +2,34 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type StoryObj, type Meta } from '@storybook/react-vite';
8
- import { Schema } from 'effect';
9
- import React from 'react';
10
-
11
- import {
12
- Capabilities,
13
- IntentPlugin,
14
- LayoutAction,
15
- SettingsPlugin,
16
- contributes,
17
- createResolver,
18
- defineCapability,
19
- useCapability,
20
- } from '@dxos/app-framework';
5
+ import { Atom, type Registry } from '@effect-atom/atom-react';
6
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
7
+ import * as Effect from 'effect/Effect';
8
+ import React, { type KeyboardEvent, useCallback, useRef } from 'react';
9
+ import { expect, userEvent, within } from 'storybook/test';
10
+
11
+ import { Capabilities, Capability } from '@dxos/app-framework';
21
12
  import { withPluginManager } from '@dxos/app-framework/testing';
22
- import { live } from '@dxos/live-object';
23
- import { AttentionPlugin } from '@dxos/plugin-attention';
24
- import { ClientPlugin } from '@dxos/plugin-client';
25
- import { GraphPlugin } from '@dxos/plugin-graph';
26
- import { SpacePlugin } from '@dxos/plugin-space';
27
- import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
28
- import { ThemePlugin } from '@dxos/plugin-theme';
29
- import { faker } from '@dxos/random';
13
+ import { useAtomCapability } from '@dxos/app-framework/ui';
14
+ import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
15
+ import { Operation, OperationHandlerSet } from '@dxos/compute';
16
+ import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
17
+ import { random } from '@dxos/random';
30
18
  import { IconButton, Input, Main, Toolbar } from '@dxos/react-ui';
31
- import { useAttentionAttributes, useAttention } from '@dxos/react-ui-attention';
19
+ import { useAttention, useAttentionAttributes } from '@dxos/react-ui-attention';
32
20
  import { Stack, StackItem } from '@dxos/react-ui-stack';
33
- import { defaultTx, mx } from '@dxos/react-ui-theme';
34
- import { withLayout } from '@dxos/storybook-utils';
21
+ import { withLayout } from '@dxos/react-ui/testing';
22
+ import { mx } from '@dxos/ui-theme';
23
+
24
+ import { NavTreeContainer } from '#containers';
25
+ import { storybookGraphBuilders } from '#testing';
26
+ import { translations } from '#translations';
35
27
 
36
28
  import { NavTreePlugin } from '../../NavTreePlugin';
37
- import { storybookGraphBuilders } from '../../testing';
38
- import { translations } from '../../translations';
39
- import { NavTreeContainer } from '../NavTreeContainer';
40
29
 
41
- faker.seed(1234);
30
+ random.seed(1234);
42
31
 
43
- const StoryState = defineCapability<{ tab: string }>('story-state');
32
+ const StoryState = Capability.make<Atom.Atom<{ tab: string }>>('story-state');
44
33
 
45
34
  // TODO(burdon): Fix outline (e.g., button in sidebar nav is clipped when focused).
46
35
  // TODO(burdon): Consider similar containment of: Table, Sheet, Kanban Column, Form, etc.
@@ -55,11 +44,11 @@ const StoryPlankHeading = ({ attendableId }: { attendableId: string }) => {
55
44
  <div className='flex p-1 items-center border-b border-separator'>
56
45
  <IconButton
57
46
  density='coarse'
58
- icon='ph--atom--regular'
47
+ icon='ph--circle--regular'
59
48
  label='Test'
60
49
  iconOnly
61
50
  variant={hasAttention ? 'primary' : 'ghost'}
62
- classNames='is-[--rail-action] bs-[--rail-action]'
51
+ classNames='w-(--dx-rail-action) h-(--dx-rail-action)'
63
52
  />
64
53
  <StackItem.ResizeHandle />
65
54
  </div>
@@ -68,25 +57,36 @@ const StoryPlankHeading = ({ attendableId }: { attendableId: string }) => {
68
57
 
69
58
  const StoryPlank = ({ attendableId }: { attendableId: string }) => {
70
59
  const attentionAttrs = useAttentionAttributes(attendableId);
60
+ const rootElement = useRef<HTMLDivElement | null>(null);
61
+
62
+ // NOTE(thure): This is the same workaround as in Plank, but that component is out of scope for this story.
63
+ // TODO(thure): Tabster’s focus group should handle moving focus to Main, but something is blocking it.
64
+ const handleKeyDown = useCallback((event: KeyboardEvent) => {
65
+ if (event.target === event.currentTarget && event.key === 'Escape') {
66
+ rootElement.current?.closest('main')?.focus();
67
+ }
68
+ }, []);
71
69
 
72
70
  return (
73
71
  <StackItem.Root
74
72
  item={{ id: attendableId }}
75
73
  {...attentionAttrs}
76
- classNames='bg-baseSurface border-ie border-separator'
74
+ classNames='bg-base-surface border-e border-separator'
77
75
  size={30}
76
+ onKeyDown={handleKeyDown}
77
+ ref={rootElement}
78
78
  >
79
79
  <StoryPlankHeading attendableId={attendableId} />
80
80
  <StackItem.Content toolbar>
81
- <Toolbar.Root classNames='border-b border-subduedSeparator'>
81
+ <Toolbar.Root classNames='border-b border-subdued-separator'>
82
82
  <Toolbar.Button>Test</Toolbar.Button>
83
83
  </Toolbar.Root>
84
84
 
85
- <div className={mx(container, 'm-2 bg-activeSurface')}>
85
+ <div className={mx(container, 'm-2 bg-current-surface')}>
86
86
  <Input.Root>
87
87
  <Input.Label>Level 1 (group)</Input.Label>
88
88
  </Input.Root>
89
- <div className={mx(container, 'bg-baseSurface')}>
89
+ <div className={mx(container, 'bg-base-surface')}>
90
90
  <Input.Root>
91
91
  <Input.Label>Level 2 (base)</Input.Label>
92
92
  <Input.TextArea placeholder='Enter text' />
@@ -99,10 +99,10 @@ const StoryPlank = ({ attendableId }: { attendableId: string }) => {
99
99
  };
100
100
 
101
101
  const DefaultStory = () => {
102
- const state = useCapability(StoryState);
102
+ const state = useAtomCapability(StoryState);
103
103
 
104
104
  return (
105
- <Main.Root complementarySidebarState='closed'>
105
+ <Main.Root navigationSidebarState='expanded'>
106
106
  <Main.NavigationSidebar label='Navigation' classNames='grid'>
107
107
  <NavTreeContainer tab={state.tab} />
108
108
  </Main.NavigationSidebar>
@@ -116,85 +116,93 @@ const DefaultStory = () => {
116
116
  );
117
117
  };
118
118
 
119
- const meta: Meta<typeof NavTreeContainer> = {
120
- title: 'plugins/plugin-navtree/NavTree',
119
+ const meta = {
120
+ title: 'plugins/plugin-navtree/components/NavTree',
121
121
  component: NavTreeContainer,
122
122
  render: DefaultStory,
123
123
  decorators: [
124
+ withLayout({ layout: 'fullscreen' }),
124
125
  withPluginManager({
125
126
  plugins: [
126
- ThemePlugin({ tx: defaultTx }),
127
- StorybookLayoutPlugin({ initialState: { sidebarState: 'expanded' } }),
128
- GraphPlugin(),
129
- IntentPlugin(),
130
- SettingsPlugin(),
131
- AttentionPlugin(),
127
+ ...corePlugins(),
128
+ StorybookPlugin({
129
+ initialState: { sidebarState: 'expanded' },
130
+ }),
131
+
132
132
  NavTreePlugin(),
133
133
  ],
134
- capabilities: (context) => [
135
- contributes(StoryState, live({ tab: 'space-0' })),
136
- contributes(Capabilities.AppGraphBuilder, storybookGraphBuilders(context)),
137
- contributes(Capabilities.IntentResolver, [
138
- createResolver({
139
- intent: LayoutAction.UpdateLayout,
140
- filter: (data): data is Schema.Schema.Type<typeof LayoutAction.SwitchWorkspace.fields.input> =>
141
- Schema.is(LayoutAction.SwitchWorkspace.fields.input)(data),
142
- resolve: ({ subject }) => {
143
- const state = context.getCapability(StoryState);
144
- state.tab = subject;
145
- },
146
- }),
147
- ]),
148
- ],
134
+ capabilities: () => {
135
+ const storyStateAtom = Atom.make({ tab: 'root/space-0' }).pipe(Atom.keepAlive);
136
+ return [
137
+ Capability.contributes(StoryState, storyStateAtom),
138
+ Capability.contributes(AppCapabilities.AppGraphBuilder, storybookGraphBuilders()),
139
+ Capability.contributes(
140
+ Capabilities.OperationHandler,
141
+ OperationHandlerSet.make(
142
+ Operation.withHandler(LayoutOperation.SwitchWorkspace, ({ subject }) =>
143
+ Effect.gen(function* () {
144
+ const registry: Registry.Registry = yield* Capability.get(Capabilities.AtomRegistry);
145
+ registry.set(storyStateAtom, { tab: subject });
146
+ }),
147
+ ),
148
+ ),
149
+ ),
150
+ ];
151
+ },
149
152
  }),
150
- withLayout({ fullscreen: true }),
151
153
  ],
152
154
  parameters: {
155
+ layout: 'fullscreen',
153
156
  translations,
154
157
  },
155
- };
158
+ } satisfies Meta<typeof NavTreeContainer>;
156
159
 
157
160
  export default meta;
158
161
 
159
162
  type Story = StoryObj<typeof NavTreeContainer>;
160
163
 
161
- export const Default: Story = {};
164
+ export const Default: Story = {
165
+ play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
166
+ const canvas = within(canvasElement);
162
167
 
163
- // TODO(wittjosiah): Deduplicate plugins/capabilities with default story.
164
- export const WithClient: Story = {
165
- decorators: [
166
- withPluginManager({
167
- plugins: [
168
- ThemePlugin({ tx: defaultTx }),
169
- GraphPlugin(),
170
- IntentPlugin(),
171
- SettingsPlugin(),
172
- AttentionPlugin(),
173
- NavTreePlugin(),
174
- ClientPlugin({
175
- onClientInitialized: async (_, client) => {
176
- await client.halo.createIdentity();
177
- },
178
- }),
179
- SpacePlugin(),
180
- // Needs to be last so that the dialog and popovers have access to all contexts.
181
- StorybookLayoutPlugin({ initialState: { sidebarState: 'expanded' } }),
182
- ],
183
- capabilities: (context) => [
184
- contributes(StoryState, live({ tab: 'space-0' })),
185
- contributes(Capabilities.IntentResolver, [
186
- createResolver({
187
- intent: LayoutAction.UpdateLayout,
188
- filter: (data): data is Schema.Schema.Type<typeof LayoutAction.SwitchWorkspace.fields.input> =>
189
- Schema.is(LayoutAction.SwitchWorkspace.fields.input)(data),
190
- resolve: ({ subject }) => {
191
- const state = context.getCapability(StoryState);
192
- state.tab = subject;
193
- },
194
- }),
195
- ]),
196
- ],
197
- }),
198
- withLayout({ fullscreen: true }),
199
- ],
168
+ // Find the element with treegrid role and click on its parent
169
+ const treegridElement = await canvas.findByRole('treegrid');
170
+ const treegridParent = treegridElement.parentElement;
171
+ if (treegridParent) {
172
+ await userEvent.click(treegridParent);
173
+ }
174
+
175
+ // Press Escape
176
+ await userEvent.keyboard('{Escape}');
177
+
178
+ // Confirm that focus is on an element with attribute data-main-landmark="0"
179
+ await expect(document.activeElement).toHaveAttribute('data-main-landmark', '0');
180
+
181
+ // Press Tab
182
+ await userEvent.keyboard('{Tab}');
183
+
184
+ // Confirm that focus is now on an element with data-main-landmark="1"
185
+ await expect(document.activeElement).toHaveAttribute('data-main-landmark', '1');
186
+
187
+ // Press Tab
188
+ await userEvent.keyboard('{Tab}');
189
+
190
+ // Confirm that focus is now on an element with data-main-landmark="0"
191
+ await expect(document.activeElement).toHaveAttribute('data-main-landmark', '0');
192
+
193
+ // Press Shift-Tab
194
+ await userEvent.keyboard('{Shift>}{Tab}{/Shift}');
195
+
196
+ // Press Enter
197
+ await userEvent.keyboard('{Enter}');
198
+
199
+ // Confirm that focus is now on an element with data-attendable-id="space-0:object-0"
200
+ await expect(document.activeElement).toHaveAttribute('data-attendable-id', 'space-0:object-0');
201
+
202
+ // Press Escape
203
+ await userEvent.keyboard('{Escape}');
204
+
205
+ // Confirm that focus is now on an element with data-main-landmark="1"
206
+ await expect(document.activeElement).toHaveAttribute('data-main-landmark', '1');
207
+ },
200
208
  };
@@ -2,52 +2,36 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useMemo } from 'react';
5
+ import React, { forwardRef, useMemo } from 'react';
6
6
 
7
- import { type TreeProps } from '@dxos/react-ui-list';
7
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
8
+ import { Node, useConnections, useActions as useGraphActions } from '@dxos/plugin-graph';
8
9
  import { Tabs } from '@dxos/react-ui-tabs';
10
+ import { byPosition } from '@dxos/util';
11
+
12
+ import { useLoadDescendents } from '#hooks';
9
13
 
10
- import { useLoadDescendents } from '../../hooks';
11
- import { type NavTreeItemGraphNode } from '../../types';
12
14
  import { useNavTreeContext } from '../NavTreeContext';
13
- import { L0Menu, L1Panels, type L1PanelsProps } from '../Sidebar';
15
+ import { L0Menu, L1Tabs, type L1TabsProps } from '../Sidebar';
14
16
 
15
17
  export const NAV_TREE_ITEM = 'NavTreeItem';
16
18
 
17
- export type NavTreeProps = Pick<TreeProps<NavTreeItemGraphNode>, 'id' | 'root'> & Pick<L1PanelsProps, 'open'>;
18
-
19
- export const NavTree = ({ id, root, ...props }: NavTreeProps) => {
20
- const { tab, useItems, onBack } = useNavTreeContext();
21
- const topLevelActions = useItems(root, { disposition: 'menu', sort: true });
22
- const topLevelCollections = useItems(root, { disposition: 'collection' });
23
- const topLevelWorkspaces = useItems(root, { disposition: 'workspace' });
24
- const topLevelNavigation = useItems(root, { disposition: 'navigation' });
25
- const l0Items = useMemo(
26
- () => [
27
- // prettier-ignore
28
- ...topLevelCollections,
29
- ...topLevelWorkspaces,
30
- ...topLevelNavigation,
31
- ],
32
- [topLevelCollections, topLevelWorkspaces, topLevelNavigation],
33
- );
34
- const pinnedItems = useItems(root, { disposition: 'pin-end', sort: true });
35
- const userAccountItem = useItems(root, { disposition: 'user-account' })[0];
36
- const topLevelItems = useMemo(
37
- () => [
38
- // prettier-ignore
39
- ...l0Items,
40
- ...pinnedItems,
41
- ...(userAccountItem ? [userAccountItem] : []),
42
- ],
43
- [l0Items, pinnedItems, userAccountItem],
44
- );
19
+ export type NavTreeProps = { id: string; root?: Node.Node; tab: string } & Pick<L1TabsProps, 'open'>;
20
+
21
+ // TODO(wittjosiah): Refactor to Radix-style.
22
+ export const NavTree = forwardRef<HTMLDivElement, NavTreeProps>(({ id, root, tab, ...props }, forwardedRef) => {
23
+ const { onBack, onItemHover } = useNavTreeContext();
24
+ const { topLevelActions, l0Items, pinnedItems, userAccountItem, topLevelItems } = useTopLevelNavItems(root);
45
25
 
46
26
  useLoadDescendents(root);
47
27
  const path = useMemo(() => [id], [id]);
48
28
 
49
29
  return (
50
- <Tabs.Root value={tab} orientation='vertical' verticalVariant='stateless' classNames='relative'>
30
+ // TODO(thure): `Tabs.Root` forces all items that should be able to receive focus to use `Tabs.Tab(Primitive)` since
31
+ // it uses RovingFocus and doesn't support moving focus to an item that is not a tab. Assess whether this situation
32
+ // should change including whether it should motivate a change in the design/taxonomy, or if this means this should
33
+ // not use `react-ui-tabs` at all.
34
+ <Tabs.Root value={tab} orientation='vertical' classNames='relative' ref={forwardedRef}>
51
35
  <L0Menu
52
36
  menuActions={topLevelActions}
53
37
  topLevelItems={l0Items}
@@ -55,8 +39,60 @@ export const NavTree = ({ id, root, ...props }: NavTreeProps) => {
55
39
  userAccountItem={userAccountItem}
56
40
  path={path}
57
41
  parent={root}
42
+ onItemHover={onItemHover}
58
43
  />
59
- <L1Panels topLevelItems={topLevelItems} path={path} currentItemId={tab} onBack={onBack} {...props} />
44
+ <L1Tabs topLevelItems={topLevelItems} path={path} currentItemId={tab} onBack={onBack} {...props} />
60
45
  </Tabs.Root>
61
46
  );
47
+ });
48
+
49
+ /**
50
+ * Partitions root children into workspaces, pinned items, user-account, and top-level actions.
51
+ */
52
+ const useTopLevelNavItems = (root?: Node.Node) => {
53
+ const { graph } = useAppGraph();
54
+ const rootId = root?.id ?? Node.RootId;
55
+ const rootOutboundItems = useConnections(graph, rootId, 'child');
56
+ const rootActions = useGraphActions(graph, rootId);
57
+
58
+ const { topLevelActions, l0Items, pinnedItems, userAccountItem } = useMemo(() => {
59
+ const topLevelWorkspaces: Node.Node[] = [];
60
+ const outboundPinnedItems: Node.Node[] = [];
61
+ let userAccountItem: Node.Node | undefined;
62
+ for (const node of rootOutboundItems) {
63
+ switch (node.properties.disposition) {
64
+ case 'workspace':
65
+ topLevelWorkspaces.push(node);
66
+ break;
67
+ case 'pin-end':
68
+ outboundPinnedItems.push(node);
69
+ break;
70
+ case 'user-account':
71
+ userAccountItem ??= node;
72
+ break;
73
+ }
74
+ }
75
+
76
+ const topLevelActions = rootActions
77
+ .filter((action) => action.properties.disposition === 'menu')
78
+ .toSorted((a, b) => byPosition(a.properties, b.properties));
79
+ const pinnedItems = [
80
+ ...outboundPinnedItems,
81
+ ...rootActions.filter((action) => action.properties.disposition === 'pin-end'),
82
+ ].toSorted((a, b) => byPosition(a.properties, b.properties));
83
+
84
+ return {
85
+ pinnedItems,
86
+ topLevelActions,
87
+ userAccountItem,
88
+ l0Items: topLevelWorkspaces,
89
+ };
90
+ }, [rootActions, rootOutboundItems]);
91
+
92
+ const topLevelItems = useMemo(
93
+ () => [...l0Items, ...pinnedItems, ...(userAccountItem ? [userAccountItem] : [])],
94
+ [l0Items, pinnedItems, userAccountItem],
95
+ );
96
+
97
+ return { topLevelActions, l0Items, pinnedItems, userAccountItem, topLevelItems };
62
98
  };
@@ -6,7 +6,7 @@ import { createContext, useContext } from 'react';
6
6
 
7
7
  import { raise } from '@dxos/debug';
8
8
 
9
- import { type NavTreeContextValue } from './types';
9
+ import { type NavTreeContextValue } from '../types';
10
10
 
11
11
  export const NavTreeContext = createContext<NavTreeContextValue | null>(null);
12
12
 
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './NavTreeContext';
@@ -2,57 +2,63 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Effect from 'effect/Effect';
8
7
 
9
- import { type NodeArg } from '@dxos/app-graph';
10
- import { faker } from '@dxos/random';
11
- import { withLayout, withTheme } from '@dxos/storybook-utils';
8
+ import { RuntimePlugin } from '@dxos/app-framework';
9
+ import { withPluginManager } from '@dxos/app-framework/testing';
10
+ import { type Node } from '@dxos/app-graph';
11
+ import { corePlugins } from '@dxos/plugin-testing';
12
+ import { random } from '@dxos/random';
12
13
 
13
14
  import { NavTreeItemAction, type NavTreeItemActionMenuProps } from './NavTreeItemAction';
14
15
 
15
16
  const parent = {
16
- id: faker.string.uuid(),
17
+ id: random.string.uuid(),
17
18
  type: 'node',
18
19
  data: null,
19
20
  properties: {
20
- label: faker.lorem.words(2),
21
+ label: random.lorem.words(2),
21
22
  icon: 'ph--circle--regular',
22
23
  },
23
- } satisfies NodeArg<any>;
24
+ } satisfies Node.NodeArg<any>;
24
25
 
25
26
  // TODO(burdon): Factor out across tests.
26
- const menuActions = faker.helpers.multiple(
27
+ const menuActions = random.helpers.multiple(
27
28
  () =>
28
29
  ({
29
- id: faker.string.uuid(),
30
+ id: random.string.uuid(),
30
31
  type: 'action',
31
- data: () => {
32
- console.log('invoke');
33
- },
32
+ data: () =>
33
+ Effect.sync(() => {
34
+ console.log('invoke');
35
+ }),
34
36
  properties: {
35
- label: faker.lorem.words(2),
37
+ label: random.lorem.words(2),
36
38
  icon: 'ph--circle--regular',
37
39
  },
38
- }) satisfies NodeArg<any>,
40
+ }) satisfies Node.NodeArg<any>,
39
41
  { count: 20 },
40
42
  );
41
43
 
42
- const meta: Meta<typeof NavTreeItemAction> = {
43
- title: 'plugins/plugin-navtree/NavTreeItemAction',
44
+ const meta = {
45
+ title: 'plugins/plugin-navtree/components/NavTreeItemAction',
44
46
  component: NavTreeItemAction,
45
- decorators: [withTheme, withLayout()],
46
47
  args: {
47
48
  icon: 'ph--list--regular',
48
49
  parent,
49
50
  menuActions,
50
51
  label: 'Select action',
51
52
  } satisfies Partial<NavTreeItemActionMenuProps>,
53
+ decorators: [
54
+ withPluginManager({
55
+ plugins: [...corePlugins(), RuntimePlugin()],
56
+ }),
57
+ ],
52
58
  parameters: {
53
59
  layout: 'centered',
54
60
  },
55
- };
61
+ } satisfies Meta<typeof NavTreeItemAction>;
56
62
 
57
63
  export default meta;
58
64