@dxos/plugin-navtree 0.8.4-main.84f28bd → 0.8.4-main.8baae0fced

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 (295) 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-VRTNKDBX.mjs +23 -0
  30. package/dist/lib/neutral/chunk-VRTNKDBX.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/{node-esm/keyboard-MOZWHFUM.mjs → neutral/keyboard-EJ65BVTC.mjs} +25 -21
  44. package/dist/lib/neutral/keyboard-EJ65BVTC.mjs.map +7 -0
  45. package/dist/lib/neutral/meta.json +1 -0
  46. package/dist/lib/neutral/meta.mjs +12 -0
  47. package/dist/lib/neutral/meta.mjs.map +7 -0
  48. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs +13 -0
  49. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs.map +7 -0
  50. package/dist/lib/neutral/operations/index.mjs +8 -0
  51. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  52. package/dist/lib/neutral/plugin.mjs +16 -0
  53. package/dist/lib/neutral/plugin.mjs.map +7 -0
  54. package/dist/lib/neutral/react-surface-EWCZMKVX.mjs +50 -0
  55. package/dist/lib/neutral/react-surface-EWCZMKVX.mjs.map +7 -0
  56. package/dist/lib/neutral/state-VVITVXWM.mjs +127 -0
  57. package/dist/lib/neutral/state-VVITVXWM.mjs.map +7 -0
  58. package/dist/lib/neutral/testing/index.mjs +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 +1 -4
  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 +5 -6
  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 -61
  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 +73 -50
  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 +2 -4
  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 +110 -115
  212. package/src/experimental/Tree.tsx +17 -35
  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 +13 -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-TZA65AKW.mjs +0 -1428
  237. package/dist/lib/browser/chunk-TZA65AKW.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 +0 -51
  245. package/dist/lib/browser/keyboard-QRS6WOQH.mjs.map +0 -7
  246. package/dist/lib/browser/meta.json +0 -1
  247. package/dist/lib/browser/react-surface-N2HPMYCU.mjs +0 -51
  248. package/dist/lib/browser/react-surface-N2HPMYCU.mjs.map +0 -7
  249. package/dist/lib/browser/state-54DY3DOY.mjs +0 -117
  250. package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
  251. package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs +0 -46
  252. package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs.map +0 -7
  253. package/dist/lib/node-esm/chunk-CY7QWR4R.mjs +0 -1429
  254. package/dist/lib/node-esm/chunk-CY7QWR4R.mjs.map +0 -7
  255. package/dist/lib/node-esm/chunk-P2JGW3WR.mjs +0 -18
  256. package/dist/lib/node-esm/chunk-P2JGW3WR.mjs.map +0 -7
  257. package/dist/lib/node-esm/chunk-V3QXFDDP.mjs +0 -16
  258. package/dist/lib/node-esm/chunk-V3QXFDDP.mjs.map +0 -7
  259. package/dist/lib/node-esm/index.mjs +0 -150
  260. package/dist/lib/node-esm/index.mjs.map +0 -7
  261. package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs +0 -48
  262. package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs.map +0 -7
  263. package/dist/lib/node-esm/keyboard-MOZWHFUM.mjs.map +0 -7
  264. package/dist/lib/node-esm/meta.json +0 -1
  265. package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs +0 -52
  266. package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs.map +0 -7
  267. package/dist/lib/node-esm/state-Z3OTRC2I.mjs +0 -118
  268. package/dist/lib/node-esm/state-Z3OTRC2I.mjs.map +0 -7
  269. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  270. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  271. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  272. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  273. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +0 -5
  274. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  275. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  276. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  277. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  278. package/dist/types/src/components/NavTreeContainer.d.ts +0 -9
  279. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  280. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  281. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  282. package/dist/types/src/events.d.ts +0 -4
  283. package/dist/types/src/events.d.ts.map +0 -1
  284. package/dist/types/src/hooks.d.ts +0 -3
  285. package/dist/types/src/hooks.d.ts.map +0 -1
  286. package/dist/types/src/types.d.ts.map +0 -1
  287. package/src/capabilities/capabilities.ts +0 -20
  288. package/src/capabilities/intent-resolver.ts +0 -37
  289. package/src/components/CommandsDialog/CommandsDialog.tsx +0 -118
  290. package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -37
  291. package/src/components/CommandsDialog/index.ts +0 -6
  292. package/src/components/NavTreeContainer.tsx +0 -314
  293. package/src/events.ts +0 -11
  294. package/src/hooks.ts +0 -21
  295. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
@@ -2,58 +2,65 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities as AppCapabilities, contributes, type PluginContext } from '@dxos/app-framework';
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { AppCapabilities } from '@dxos/app-toolkit';
6
9
  import { debounce } from '@dxos/async';
7
10
  import { Keyboard } from '@dxos/keyboard';
8
- import { isAction, type Node } from '@dxos/plugin-graph';
11
+ import { Graph, Node, runAction } from '@dxos/plugin-graph';
9
12
  import { getHostPlatform } from '@dxos/util';
10
13
 
11
- import { KEY_BINDING } from '../meta';
12
-
13
- export default (context: PluginContext) => {
14
- const { graph } = context.getCapability(AppCapabilities.AppGraph);
15
-
16
- // TODO(wittjosiah): Factor out.
17
- // TODO(wittjosiah): Handle removal of actions.
18
- const visitor = (node: Node, path: string[]) => {
19
- let shortcut: string | undefined;
20
- if (typeof node.properties.keyBinding === 'object') {
21
- const availablePlatforms = Object.keys(node.properties.keyBinding);
22
- const platform = getHostPlatform();
23
- shortcut = availablePlatforms.includes(platform)
24
- ? node.properties.keyBinding[platform]
25
- : platform === 'ios'
26
- ? node.properties.keyBinding.macos // Fallback to macos if ios-specific bindings not provided.
27
- : platform === 'linux' || platform === 'unknown'
28
- ? node.properties.keyBinding.windows // Fallback to windows if platform-specific bindings not provided.
29
- : undefined;
30
- } else {
31
- shortcut = node.properties.keyBinding;
32
- }
33
-
34
- if (shortcut && isAction(node)) {
35
- Keyboard.singleton.getContext(path.slice(0, -1).join('/')).bind({
36
- shortcut,
37
- handler: () => {
38
- void node.data({ parent: node, caller: KEY_BINDING });
39
- },
40
- data: node.properties.label,
41
- });
42
- }
43
- };
44
-
45
- const eventHandler = debounce(() => {
46
- graph.traverse({ visitor });
47
- }, 500);
48
-
49
- const unsubscribe = graph.onNodeChanged.on(eventHandler);
50
-
51
- // TODO(burdon): Create context and plugin.
52
- Keyboard.singleton.initialize();
53
- Keyboard.singleton.setCurrentContext(graph.root.id);
54
-
55
- return contributes(AppCapabilities.Null, null, () => {
56
- unsubscribe();
57
- Keyboard.singleton.destroy();
58
- });
59
- };
14
+ import { KEY_BINDING } from '#meta';
15
+
16
+ export default Capability.makeModule(
17
+ Effect.fnUntraced(function* () {
18
+ const { graph } = yield* Capability.get(AppCapabilities.AppGraph);
19
+ const invoker = yield* Capability.get(Capabilities.OperationInvoker);
20
+ const pluginContext = yield* Capability.Service;
21
+
22
+ // TODO(wittjosiah): Factor out.
23
+ // TODO(wittjosiah): Handle removal of actions.
24
+ const visitor = (node: Node.Node, path: string[]) => {
25
+ let shortcut: string | undefined;
26
+ if (typeof node.properties.keyBinding === 'object') {
27
+ const availablePlatforms = Object.keys(node.properties.keyBinding);
28
+ const platform = getHostPlatform();
29
+ shortcut = availablePlatforms.includes(platform)
30
+ ? node.properties.keyBinding[platform]
31
+ : platform === 'ios'
32
+ ? node.properties.keyBinding.macos // Fallback to macos if ios-specific bindings not provided.
33
+ : platform === 'linux' || platform === 'unknown'
34
+ ? node.properties.keyBinding.windows // Fallback to windows if platform-specific bindings not provided.
35
+ : undefined;
36
+ } else {
37
+ shortcut = node.properties.keyBinding;
38
+ }
39
+
40
+ if (shortcut && Node.isAction(node)) {
41
+ Keyboard.singleton.getContext(path.slice(0, -1).join('/')).bind({
42
+ shortcut,
43
+ handler: () => void runAction(invoker, pluginContext, node, { parent: node, caller: KEY_BINDING }),
44
+ data: node.properties.label,
45
+ });
46
+ }
47
+ };
48
+
49
+ const eventHandler = debounce(() => {
50
+ Graph.traverse(graph, { relation: ['child', 'action'], visitor });
51
+ }, 500);
52
+
53
+ const unsubscribe = graph.onNodeChanged.on(eventHandler);
54
+
55
+ // TODO(burdon): Create context and plugin.
56
+ Keyboard.singleton.initialize();
57
+ Keyboard.singleton.setCurrentContext(Node.RootId);
58
+
59
+ return Capability.contributes(Capabilities.Null, null, () =>
60
+ Effect.sync(() => {
61
+ unsubscribe();
62
+ Keyboard.singleton.destroy();
63
+ }),
64
+ );
65
+ }),
66
+ );
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import type { OperationHandlerSet } from '@dxos/compute';
9
+
10
+ import { NavTreeOperationHandlerSet } from '#operations';
11
+
12
+ export default Capability.makeModule<OperationHandlerSet.OperationHandlerSet>(
13
+ Effect.fnUntraced(function* () {
14
+ return Capability.contributes(Capabilities.OperationHandler, NavTreeOperationHandlerSet);
15
+ }),
16
+ );
@@ -2,44 +2,52 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
5
+ import * as Effect from 'effect/Effect';
6
+ import React, { type ComponentProps } from 'react';
6
7
 
7
- import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
8
- import { isGraphNode } from '@dxos/plugin-graph';
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
11
+ import { Node } from '@dxos/plugin-graph';
9
12
 
10
- import { CommandsDialogContent, CommandsTrigger, NavTreeDocumentTitle, NavTreeContainer } from '../components';
11
- import { COMMANDS_DIALOG, NAVTREE_PLUGIN } from '../meta';
13
+ import { CommandsDialogContent, CommandsTrigger, NavTreeContainer, NavTreeDocumentTitle } from '#containers';
14
+ import { COMMANDS_DIALOG } from '#meta';
12
15
 
13
- export default () =>
14
- contributes(Capabilities.ReactSurface, [
15
- createSurface({
16
- id: COMMANDS_DIALOG,
17
- role: 'dialog',
18
- filter: (data): data is { props: { selected?: string } } => data.component === COMMANDS_DIALOG,
19
- component: ({ data }) => <CommandsDialogContent {...data.props} />,
20
- }),
21
- createSurface({
22
- id: `${NAVTREE_PLUGIN}/navigation`,
23
- role: 'navigation',
24
- filter: (data): data is { popoverAnchorId?: string; topbar: boolean; current: string } =>
25
- typeof data.current === 'string',
26
- component: ({ data }) => (
27
- <NavTreeContainer
28
- tab={data.current}
29
- popoverAnchorId={data.popoverAnchorId as string | undefined}
30
- topbar={data.topbar as boolean}
31
- />
32
- ),
33
- }),
34
- createSurface({
35
- id: `${NAVTREE_PLUGIN}/document-title`,
36
- role: 'document-title',
37
- component: ({ data }) => <NavTreeDocumentTitle node={isGraphNode(data.subject) ? data.subject : undefined} />,
38
- }),
39
- createSurface({
40
- id: `${NAVTREE_PLUGIN}/search-input`,
41
- role: 'search-input',
42
- position: 'fallback',
43
- component: () => <CommandsTrigger />,
44
- }),
45
- ]);
16
+ export default Capability.makeModule(() =>
17
+ Effect.succeed(
18
+ Capability.contributes(Capabilities.ReactSurface, [
19
+ Surface.create({
20
+ id: COMMANDS_DIALOG,
21
+ filter: AppSurface.component<ComponentProps<typeof CommandsDialogContent>>(AppSurface.Dialog, COMMANDS_DIALOG),
22
+ component: ({ data, ref }) => <CommandsDialogContent {...data.props} ref={ref} />,
23
+ }),
24
+ Surface.create({
25
+ id: 'navigation',
26
+ role: 'navigation',
27
+ filter: (data): data is { popoverAnchorId?: string; current: string } => typeof data.current === 'string',
28
+ component: ({ data, ref }) => {
29
+ return (
30
+ <NavTreeContainer
31
+ tab={data.current}
32
+ popoverAnchorId={data.popoverAnchorId as string | undefined}
33
+ ref={ref}
34
+ />
35
+ );
36
+ },
37
+ }),
38
+ Surface.create({
39
+ id: 'document-title',
40
+ role: 'document-title',
41
+ component: ({ data }) => (
42
+ <NavTreeDocumentTitle node={Node.isGraphNode(data.subject) ? data.subject : undefined} />
43
+ ),
44
+ }),
45
+ Surface.create({
46
+ id: 'search-input',
47
+ role: 'search-input',
48
+ position: 'last',
49
+ component: () => <CommandsTrigger />,
50
+ }),
51
+ ]),
52
+ ),
53
+ );
@@ -2,103 +2,152 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { effect, untracked } from '@preact/signals-core';
5
+ import { Atom } from '@effect-atom/atom-react';
6
+ import * as Effect from 'effect/Effect';
6
7
 
7
- import { Capabilities, contributes, type PluginContext } from '@dxos/app-framework';
8
- import { type Live } from '@dxos/echo';
9
- import { live } from '@dxos/live-object';
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { AppCapabilities } from '@dxos/app-toolkit';
10
+ import { Graph, Node } from '@dxos/plugin-graph';
10
11
  import { Path } from '@dxos/react-ui-list';
11
12
 
12
- import { NavTreeCapabilities } from './capabilities';
13
- import { NAVTREE_PLUGIN } from '../meta';
13
+ import { meta } from '#meta';
14
+ import { NavTreeCapabilities } from '#types';
14
15
 
15
- const KEY = `${NAVTREE_PLUGIN}/state/v1`;
16
+ const KEY = `${meta.id}.state.v1`;
16
17
 
17
- const getInitialState = () => {
18
+ /** Default item state for new entries. */
19
+ const defaultItemState: NavTreeCapabilities.NavTreeItemState = { open: false, current: false };
20
+
21
+ /** L0 (top-level workspace) paths are direct children of root — not part of the expandable tree model. */
22
+ const isTopLevelPath = (path: string[]): boolean => path.length === 2 && path[0] === Node.RootId;
23
+
24
+ /** Default state entries for initial tree structure. */
25
+ // TODO(thure): Initialize these dynamically.
26
+ const defaultStateEntries: [string, NavTreeCapabilities.NavTreeItemState][] = [
27
+ ['root', { open: true, current: false }],
28
+ ];
29
+
30
+ const getInitialState = (): Map<string, NavTreeCapabilities.NavTreeItemState> => {
18
31
  const stringified = localStorage.getItem(KEY);
19
32
  if (!stringified) {
20
- return;
33
+ return new Map(defaultStateEntries);
21
34
  }
22
35
 
23
36
  try {
24
37
  const cached: [string, { open: boolean; current: boolean }][] = JSON.parse(stringified);
25
- return cached.map(([key, value]): [string, Live<{ open: boolean; current: boolean }>] => [
26
- key,
27
- live({ open: value.open, current: false }),
28
- ]);
29
- } catch {}
38
+ return new Map(cached.map(([key, value]) => [key, { open: value.open, current: false }]));
39
+ } catch {
40
+ return new Map(defaultStateEntries);
41
+ }
30
42
  };
31
43
 
32
- export default (context: PluginContext) => {
33
- const layout = context.getCapability(Capabilities.Layout);
34
-
35
- // TODO(wittjosiah): This currently needs to be not a Live at the root.
36
- // If it is a Live then React errors when initializing new paths because of state change during render.
37
- // Ideally this could be a Live but be able to access and update the root level without breaking render.
38
- // Wrapping accesses and updates in `untracked` didn't seem to work in all cases.
39
- const state = new Map<string, Live<{ open: boolean; current: boolean; alternateTree?: boolean }>>(
40
- getInitialState() ?? [
41
- // TODO(thure): Initialize these dynamically.
42
- ['root', live({ open: true, current: false })],
43
- ['root~dxos.org/plugin/space-spaces', live({ open: true, current: false })],
44
- ['root~dxos.org/plugin/files', live({ open: true, current: false })],
45
- ],
46
- );
47
-
48
- const getItem = (_path: string[]) => {
49
- const path = Path.create(..._path);
50
- const value = state.get(path) ?? live({ open: false, current: false, alternateTree: false });
51
- if (!state.has(path)) {
52
- state.set(path, value);
53
- }
54
-
55
- return value;
56
- };
57
-
58
- const setItem = (path: string[], key: 'open' | 'current' | 'alternateTree', next: boolean) => {
59
- const value = getItem(path);
60
- value[key] = next;
61
-
62
- localStorage.setItem(KEY, JSON.stringify(Array.from(state.entries())));
63
- };
64
-
65
- const isOpen = (path: string[]) => getItem(path).open;
66
- const isCurrent = (path: string[]) => getItem(path).current;
67
- const isAlternateTree = (path: string[]) => {
68
- const item = getItem(path);
69
- return item.alternateTree ?? false;
70
- };
71
-
72
- let previous: string[] = [];
73
- const unsubscribe = effect(() => {
74
- const removed = previous.filter((id) => !layout.active.includes(id));
75
- previous = layout.active;
76
-
77
- const handleUpdate = () => {
78
- removed.forEach((id) => {
79
- const keys = Array.from(state.keys()).filter((key) => Path.last(key) === id);
80
- keys.forEach((key) => {
81
- setItem(Path.parts(key), 'current', false);
82
- });
83
- });
44
+ export default Capability.makeModule(
45
+ Effect.fnUntraced(function* () {
46
+ const registry = yield* Capability.get(Capabilities.AtomRegistry);
47
+ const layoutAtom = yield* Capability.get(AppCapabilities.Layout);
48
+
49
+ // Backing state for persistence (not reactive).
50
+ const backingState = getInitialState();
51
+
52
+ // Per-path atom family for fine-grained reactivity.
53
+ // keepAlive prevents atoms from being garbage collected when components unmount,
54
+ // ensuring state is preserved across deletion/restoration cycles.
55
+ const itemAtomFamily = Atom.family((pathString: string) =>
56
+ Atom.make<NavTreeCapabilities.NavTreeItemState>(backingState.get(pathString) ?? { ...defaultItemState }).pipe(
57
+ Atom.keepAlive,
58
+ ),
59
+ );
60
+
61
+ const getItemAtom = (path: string[]): Atom.Atom<NavTreeCapabilities.NavTreeItemState> => {
62
+ const pathString = Path.create(...path);
63
+ if (!backingState.has(pathString)) {
64
+ backingState.set(pathString, { ...defaultItemState });
65
+ }
66
+ return itemAtomFamily(pathString);
67
+ };
84
68
 
85
- layout.active.forEach((id) => {
86
- const keys = Array.from(new Set([...state.keys(), id])).filter((key) => Path.last(key) === id);
87
- keys.forEach((key) => {
88
- setItem(Path.parts(key), 'current', true);
89
- });
90
- });
69
+ const getItem = (path: string[]): NavTreeCapabilities.NavTreeItemState => {
70
+ return registry.get(getItemAtom(path));
91
71
  };
92
72
 
93
- // TODO(wittjosiah): This is setTimeout because there's a race between the keys be initialized.
94
- // Keys are initialized on the first render of an item in the navtree.
95
- // This could be avoided if the location was a path as well and not just an id.
96
- const timeout = setTimeout(handleUpdate, 500);
97
- untracked(() => handleUpdate());
98
- return () => clearTimeout(timeout);
99
- });
100
-
101
- return contributes(NavTreeCapabilities.State, { state, getItem, setItem, isOpen, isCurrent, isAlternateTree }, () =>
102
- unsubscribe(),
103
- );
104
- };
73
+ const setItem = (path: string[], key: 'open' | 'current', next: boolean) => {
74
+ const pathString = Path.create(...path);
75
+ const atom = itemAtomFamily(pathString);
76
+ const currentValue = registry.get(atom);
77
+ const newValue = { ...currentValue, [key]: next };
78
+
79
+ registry.set(atom, newValue);
80
+
81
+ if (!(key === 'open' && isTopLevelPath(path))) {
82
+ backingState.set(pathString, newValue);
83
+ localStorage.setItem(KEY, JSON.stringify(Array.from(backingState.entries())));
84
+ }
85
+ };
86
+
87
+ // Subscribe to layout changes to update current state.
88
+ let previous: string[] = [];
89
+ const unsubscribe = registry.subscribe(layoutAtom, (layout) => {
90
+ const removed = previous.filter((id) => !layout.active.includes(id));
91
+ previous = layout.active;
92
+
93
+ const handleUpdate = () => {
94
+ // Mark removed items as not current.
95
+ removed.forEach((id) => {
96
+ const keys = Array.from(backingState.keys()).filter((key) => Path.last(key) === id);
97
+ keys.forEach((key) => {
98
+ setItem(Path.parts(key), 'current', false);
99
+ });
100
+ });
101
+
102
+ // Mark active items as current.
103
+ layout.active.forEach((id: string) => {
104
+ const keys = Array.from(new Set([...backingState.keys(), id])).filter((key) => Path.last(key) === id);
105
+ keys.forEach((key) => {
106
+ setItem(Path.parts(key), 'current', true);
107
+ });
108
+ });
109
+ };
110
+
111
+ // TODO(wittjosiah): This is setTimeout because there's a race between the keys being initialized.
112
+ // Keys are initialized on the first render of an item in the navtree.
113
+ // This could be avoided if the location was a path as well and not just an id.
114
+ const timeout = setTimeout(handleUpdate, 500);
115
+ handleUpdate();
116
+ return () => clearTimeout(timeout);
117
+ });
118
+
119
+ // Once graph is ready, expand every node marked open in state so the graph has children loaded for rendering.
120
+ yield* Effect.gen(function* () {
121
+ const { graph } = yield* Capability.waitFor(AppCapabilities.AppGraph);
122
+
123
+ // Always expand the active workspace so its subtree is initialized.
124
+ const layout = registry.get(layoutAtom);
125
+ if (layout.workspace) {
126
+ Graph.expand(graph, layout.workspace, 'child');
127
+ }
128
+
129
+ // Expand persisted open nodes, skipping inactive workspace tabs.
130
+ const openPaths = Array.from(backingState.entries())
131
+ .filter(([, state]) => state.open)
132
+ .map(([pathString]) => Path.parts(pathString))
133
+ .filter((path) => !isTopLevelPath(path));
134
+ for (const path of openPaths) {
135
+ const nodeId = path[path.length - 1];
136
+ if (!nodeId) {
137
+ continue;
138
+ }
139
+ Graph.expand(graph, nodeId, 'child');
140
+ }
141
+ }).pipe(Effect.forkDaemon);
142
+
143
+ return Capability.contributes(
144
+ NavTreeCapabilities.State,
145
+ {
146
+ getItem,
147
+ getItemAtom,
148
+ setItem,
149
+ },
150
+ () => Effect.sync(() => unsubscribe()),
151
+ );
152
+ }),
153
+ );