@dxos/plugin-navtree 0.9.1-staging.ee54ba693a → 0.11.0

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 (187) hide show
  1. package/PLUGIN.mdl +8 -6
  2. package/dist/lib/NavTreePlugin.mjs +40 -0
  3. package/dist/lib/NavTreePlugin.mjs.map +1 -0
  4. package/dist/lib/capabilities.mjs +11 -0
  5. package/dist/lib/capabilities.mjs.map +1 -0
  6. package/dist/lib/chunk-CommandsDialogContent.mjs +100 -0
  7. package/dist/lib/chunk-CommandsDialogContent.mjs.map +1 -0
  8. package/dist/lib/chunk-CommandsTrigger.mjs +27 -0
  9. package/dist/lib/chunk-CommandsTrigger.mjs.map +1 -0
  10. package/dist/lib/chunk-NavTreeDocumentTitle.mjs +17 -0
  11. package/dist/lib/chunk-NavTreeDocumentTitle.mjs.map +1 -0
  12. package/dist/lib/chunk-app-graph-builder.mjs +33 -0
  13. package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
  14. package/dist/lib/chunk-expose.mjs +31 -0
  15. package/dist/lib/chunk-expose.mjs.map +1 -0
  16. package/dist/lib/chunk-keyboard.mjs +49 -0
  17. package/dist/lib/chunk-keyboard.mjs.map +1 -0
  18. package/dist/lib/{neutral/chunk-IRQMJLRY.mjs → chunk-meta.mjs} +14 -23
  19. package/dist/lib/chunk-meta.mjs.map +1 -0
  20. package/dist/lib/chunk-operation-handler.mjs +11 -0
  21. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  22. package/dist/lib/chunk-react-surface.mjs +46 -0
  23. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  24. package/dist/lib/chunk-state.mjs +106 -0
  25. package/dist/lib/chunk-state.mjs.map +1 -0
  26. package/dist/lib/chunk-types.mjs +26 -0
  27. package/dist/lib/chunk-types.mjs.map +1 -0
  28. package/dist/lib/chunk-util.mjs +51 -0
  29. package/dist/lib/chunk-util.mjs.map +1 -0
  30. package/dist/lib/components.mjs +723 -0
  31. package/dist/lib/components.mjs.map +1 -0
  32. package/dist/lib/containers.mjs +231 -0
  33. package/dist/lib/containers.mjs.map +1 -0
  34. package/dist/lib/hooks.mjs +162 -0
  35. package/dist/lib/hooks.mjs.map +1 -0
  36. package/dist/lib/index.mjs +4 -0
  37. package/dist/lib/meta.mjs +2 -0
  38. package/dist/lib/operations.mjs +7 -0
  39. package/dist/lib/operations.mjs.map +1 -0
  40. package/dist/lib/plugin.mjs +9 -0
  41. package/dist/lib/plugin.mjs.map +1 -0
  42. package/dist/lib/testing.mjs +397 -0
  43. package/dist/lib/testing.mjs.map +1 -0
  44. package/dist/lib/translations.mjs +17 -0
  45. package/dist/lib/translations.mjs.map +1 -0
  46. package/dist/lib/types.mjs +2 -0
  47. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  48. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  49. package/dist/types/src/capabilities/keyboard.d.ts +1 -1
  50. package/dist/types/src/capabilities/nav-tree-view-state.d.ts +12 -0
  51. package/dist/types/src/capabilities/nav-tree-view-state.d.ts.map +1 -0
  52. package/dist/types/src/capabilities/nav-tree-view-state.test.d.ts +2 -0
  53. package/dist/types/src/capabilities/nav-tree-view-state.test.d.ts.map +1 -0
  54. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  55. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  56. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  57. package/dist/types/src/capabilities/state.d.ts +1 -1
  58. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  59. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +3 -0
  60. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  61. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -1
  62. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +1 -1
  63. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  64. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  65. package/dist/types/src/components/Sidebar/L1Panel.d.ts +5 -2
  66. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  67. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  68. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -1
  69. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +2 -0
  70. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -1
  71. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts +4 -1
  72. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -1
  73. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -1
  74. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts +5 -2
  75. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -1
  76. package/dist/types/src/experimental/Tree.d.ts +0 -1
  77. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  78. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  79. package/dist/types/src/experimental/visit-nodes.d.ts +3 -0
  80. package/dist/types/src/experimental/visit-nodes.d.ts.map +1 -0
  81. package/dist/types/src/hooks/useActions.d.ts +3 -1
  82. package/dist/types/src/hooks/useActions.d.ts.map +1 -1
  83. package/dist/types/src/translations.d.ts +2 -0
  84. package/dist/types/src/translations.d.ts.map +1 -1
  85. package/dist/types/src/types/NavTreeCapabilities.d.ts +1 -1
  86. package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -1
  87. package/dist/types/src/types/schema.d.ts +1 -1
  88. package/dist/types/src/types/schema.d.ts.map +1 -1
  89. package/dist/types/src/util.d.ts.map +1 -1
  90. package/dist/types/tsconfig.tsbuildinfo +1 -1
  91. package/package.json +47 -52
  92. package/src/NavTreePlugin.tsx +3 -1
  93. package/src/capabilities/nav-tree-view-state.test.ts +55 -0
  94. package/src/capabilities/nav-tree-view-state.ts +19 -0
  95. package/src/capabilities/{react-surface.tsx → react-surface.ts} +8 -9
  96. package/src/capabilities/state.ts +47 -38
  97. package/src/components/NavTree/NavTree.stories.tsx +26 -5
  98. package/src/components/NavTree/NavTree.tsx +10 -13
  99. package/src/components/NavTreeItem/NavTreeItemAction.tsx +1 -1
  100. package/src/components/Sidebar/L0Menu.tsx +9 -3
  101. package/src/components/Sidebar/L1Panel.tsx +52 -20
  102. package/src/components/Sidebar/L1Tabs.tsx +6 -0
  103. package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +49 -44
  104. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +2 -0
  105. package/src/containers/NavTreeContainer/NavTreeContainer.tsx +17 -18
  106. package/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.tsx +2 -0
  107. package/src/experimental/Tree.stories.tsx +2 -1
  108. package/src/experimental/Tree.tsx +2 -18
  109. package/src/experimental/visit-nodes.ts +27 -0
  110. package/src/hooks/useActions.ts +15 -4
  111. package/src/hooks/useNavTreeModel.ts +1 -1
  112. package/src/operations/expose.ts +2 -2
  113. package/src/testing/app-graph-builder.ts +1 -1
  114. package/src/translations.ts +3 -0
  115. package/src/types/NavTreeCapabilities.ts +1 -1
  116. package/src/types/schema.ts +1 -1
  117. package/src/util.ts +7 -9
  118. package/dist/lib/neutral/CommandsDialogContent-TEKBCQ3U.mjs +0 -112
  119. package/dist/lib/neutral/CommandsDialogContent-TEKBCQ3U.mjs.map +0 -7
  120. package/dist/lib/neutral/CommandsTrigger-HGCI22SP.mjs +0 -27
  121. package/dist/lib/neutral/CommandsTrigger-HGCI22SP.mjs.map +0 -7
  122. package/dist/lib/neutral/NavTreeContainer-ICDKC2GI.mjs +0 -12
  123. package/dist/lib/neutral/NavTreeContainer-ICDKC2GI.mjs.map +0 -7
  124. package/dist/lib/neutral/NavTreeDocumentTitle-RMERXZGK.mjs +0 -22
  125. package/dist/lib/neutral/NavTreeDocumentTitle-RMERXZGK.mjs.map +0 -7
  126. package/dist/lib/neutral/NavTreePlugin.mjs +0 -68
  127. package/dist/lib/neutral/NavTreePlugin.mjs.map +0 -7
  128. package/dist/lib/neutral/NavTreePlugin.node.mjs +0 -18
  129. package/dist/lib/neutral/NavTreePlugin.node.mjs.map +0 -7
  130. package/dist/lib/neutral/NavTreePlugin.workerd.mjs +0 -16
  131. package/dist/lib/neutral/NavTreePlugin.workerd.mjs.map +0 -7
  132. package/dist/lib/neutral/app-graph-builder-2DYAIROU.mjs +0 -42
  133. package/dist/lib/neutral/app-graph-builder-2DYAIROU.mjs.map +0 -7
  134. package/dist/lib/neutral/capabilities/index.mjs +0 -17
  135. package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
  136. package/dist/lib/neutral/chunk-4RN6TH36.mjs +0 -292
  137. package/dist/lib/neutral/chunk-4RN6TH36.mjs.map +0 -7
  138. package/dist/lib/neutral/chunk-BAVI2K7A.mjs +0 -27
  139. package/dist/lib/neutral/chunk-BAVI2K7A.mjs.map +0 -7
  140. package/dist/lib/neutral/chunk-EAN4K6OL.mjs +0 -8
  141. package/dist/lib/neutral/chunk-EAN4K6OL.mjs.map +0 -7
  142. package/dist/lib/neutral/chunk-IRQMJLRY.mjs.map +0 -7
  143. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  144. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  145. package/dist/lib/neutral/chunk-JOSNCOV4.mjs +0 -79
  146. package/dist/lib/neutral/chunk-JOSNCOV4.mjs.map +0 -7
  147. package/dist/lib/neutral/components/index.mjs +0 -814
  148. package/dist/lib/neutral/components/index.mjs.map +0 -7
  149. package/dist/lib/neutral/containers/index.mjs +0 -20
  150. package/dist/lib/neutral/containers/index.mjs.map +0 -7
  151. package/dist/lib/neutral/expose-HIBA2NQG.mjs +0 -38
  152. package/dist/lib/neutral/expose-HIBA2NQG.mjs.map +0 -7
  153. package/dist/lib/neutral/hooks/index.mjs +0 -181
  154. package/dist/lib/neutral/hooks/index.mjs.map +0 -7
  155. package/dist/lib/neutral/index.mjs +0 -34
  156. package/dist/lib/neutral/index.mjs.map +0 -7
  157. package/dist/lib/neutral/keyboard-JM2HCF5N.mjs +0 -58
  158. package/dist/lib/neutral/keyboard-JM2HCF5N.mjs.map +0 -7
  159. package/dist/lib/neutral/meta.json +0 -1
  160. package/dist/lib/neutral/meta.mjs +0 -12
  161. package/dist/lib/neutral/meta.mjs.map +0 -7
  162. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs +0 -13
  163. package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs.map +0 -7
  164. package/dist/lib/neutral/operations/index.mjs +0 -8
  165. package/dist/lib/neutral/operations/index.mjs.map +0 -7
  166. package/dist/lib/neutral/plugin.mjs +0 -16
  167. package/dist/lib/neutral/plugin.mjs.map +0 -7
  168. package/dist/lib/neutral/react-surface-QPMUEDZX.mjs +0 -48
  169. package/dist/lib/neutral/react-surface-QPMUEDZX.mjs.map +0 -7
  170. package/dist/lib/neutral/state-PDZU4PIP.mjs +0 -126
  171. package/dist/lib/neutral/state-PDZU4PIP.mjs.map +0 -7
  172. package/dist/lib/neutral/testing/index.mjs +0 -439
  173. package/dist/lib/neutral/testing/index.mjs.map +0 -7
  174. package/dist/lib/neutral/translations.mjs +0 -23
  175. package/dist/lib/neutral/translations.mjs.map +0 -7
  176. package/dist/lib/neutral/types/index.mjs +0 -10
  177. package/dist/lib/neutral/types/index.mjs.map +0 -7
  178. package/dist/types/src/NavTreePlugin.node.d.ts +0 -4
  179. package/dist/types/src/NavTreePlugin.node.d.ts.map +0 -1
  180. package/dist/types/src/NavTreePlugin.test.d.ts +0 -2
  181. package/dist/types/src/NavTreePlugin.test.d.ts.map +0 -1
  182. package/dist/types/src/NavTreePlugin.workerd.d.ts +0 -4
  183. package/dist/types/src/NavTreePlugin.workerd.d.ts.map +0 -1
  184. package/src/NavTreePlugin.node.ts +0 -17
  185. package/src/NavTreePlugin.test.ts +0 -27
  186. package/src/NavTreePlugin.workerd.ts +0 -16
  187. /package/src/components/NavTreeContext/{NavTreeContext.tsx → NavTreeContext.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-navtree",
3
- "version": "0.9.1-staging.ee54ba693a",
3
+ "version": "0.11.0",
4
4
  "description": "DXOS Surface plugin for a tree view visualization of the graph.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -16,76 +16,70 @@
16
16
  "#capabilities": {
17
17
  "source": "./src/capabilities/index.ts",
18
18
  "types": "./dist/types/src/capabilities/index.d.ts",
19
- "default": "./dist/lib/neutral/capabilities/index.mjs"
19
+ "default": "./dist/lib/capabilities.mjs"
20
20
  },
21
21
  "#components": {
22
22
  "source": "./src/components/index.ts",
23
23
  "types": "./dist/types/src/components/index.d.ts",
24
- "default": "./dist/lib/neutral/components/index.mjs"
24
+ "default": "./dist/lib/components.mjs"
25
25
  },
26
26
  "#containers": {
27
27
  "source": "./src/containers/index.ts",
28
28
  "types": "./dist/types/src/containers/index.d.ts",
29
- "default": "./dist/lib/neutral/containers/index.mjs"
29
+ "default": "./dist/lib/containers.mjs"
30
30
  },
31
31
  "#hooks": {
32
32
  "source": "./src/hooks/index.ts",
33
33
  "types": "./dist/types/src/hooks/index.d.ts",
34
- "default": "./dist/lib/neutral/hooks/index.mjs"
34
+ "default": "./dist/lib/hooks.mjs"
35
35
  },
36
36
  "#meta": {
37
37
  "source": "./src/meta.ts",
38
38
  "types": "./dist/types/src/meta.d.ts",
39
- "default": "./dist/lib/neutral/meta.mjs"
39
+ "default": "./dist/lib/meta.mjs"
40
40
  },
41
41
  "#operations": {
42
42
  "source": "./src/operations/index.ts",
43
43
  "types": "./dist/types/src/operations/index.d.ts",
44
- "default": "./dist/lib/neutral/operations/index.mjs"
44
+ "default": "./dist/lib/operations.mjs"
45
45
  },
46
46
  "#plugin": {
47
- "source": {
48
- "workerd": "./src/NavTreePlugin.workerd.ts",
49
- "node": "./src/NavTreePlugin.node.ts",
50
- "default": "./src/NavTreePlugin.tsx"
51
- },
47
+ "source": "./src/NavTreePlugin.tsx",
52
48
  "types": "./dist/types/src/NavTreePlugin.d.ts",
53
- "workerd": "./dist/lib/neutral/NavTreePlugin.workerd.mjs",
54
- "node": "./dist/lib/neutral/NavTreePlugin.node.mjs",
55
- "default": "./dist/lib/neutral/NavTreePlugin.mjs"
49
+ "default": "./dist/lib/NavTreePlugin.mjs"
56
50
  },
57
51
  "#testing": {
58
52
  "source": "./src/testing/index.ts",
59
53
  "types": "./dist/types/src/testing/index.d.ts",
60
- "default": "./dist/lib/neutral/testing/index.mjs"
54
+ "default": "./dist/lib/testing.mjs"
61
55
  },
62
56
  "#translations": {
63
57
  "source": "./src/translations.ts",
64
58
  "types": "./dist/types/src/translations.d.ts",
65
- "default": "./dist/lib/neutral/translations.mjs"
59
+ "default": "./dist/lib/translations.mjs"
66
60
  },
67
61
  "#types": {
68
62
  "source": "./src/types/index.ts",
69
63
  "types": "./dist/types/src/types/index.d.ts",
70
- "default": "./dist/lib/neutral/types/index.mjs"
64
+ "default": "./dist/lib/types.mjs"
71
65
  }
72
66
  },
73
67
  "exports": {
74
68
  ".": {
75
69
  "source": "./src/index.ts",
76
70
  "types": "./dist/types/src/index.d.ts",
77
- "default": "./dist/lib/neutral/index.mjs"
71
+ "import": "./dist/lib/index.mjs"
78
72
  },
79
73
  "./assets/PLUGIN.mdl": "./PLUGIN.mdl",
80
74
  "./plugin": {
81
75
  "source": "./src/plugin.ts",
82
76
  "types": "./dist/types/src/plugin.d.ts",
83
- "default": "./dist/lib/neutral/plugin.mjs"
77
+ "import": "./dist/lib/plugin.mjs"
84
78
  },
85
79
  "./translations": {
86
80
  "source": "./src/translations.ts",
87
81
  "types": "./dist/types/src/translations.d.ts",
88
- "default": "./dist/lib/neutral/translations.mjs"
82
+ "import": "./dist/lib/translations.mjs"
89
83
  }
90
84
  },
91
85
  "types": "dist/types/src/index.d.ts",
@@ -98,26 +92,27 @@
98
92
  "dependencies": {
99
93
  "@atlaskit/pragmatic-drag-and-drop": "1.7.7",
100
94
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0",
101
- "@dxos/app-framework": "0.9.1-staging.ee54ba693a",
102
- "@dxos/app-graph": "0.9.1-staging.ee54ba693a",
103
- "@dxos/compute": "0.9.1-staging.ee54ba693a",
104
- "@dxos/debug": "0.9.1-staging.ee54ba693a",
105
- "@dxos/app-toolkit": "0.9.1-staging.ee54ba693a",
106
- "@dxos/async": "0.9.1-staging.ee54ba693a",
107
- "@dxos/echo": "0.9.1-staging.ee54ba693a",
108
- "@dxos/keyboard": "0.9.1-staging.ee54ba693a",
109
- "@dxos/keys": "0.9.1-staging.ee54ba693a",
110
- "@dxos/lit-ui": "0.9.1-staging.ee54ba693a",
111
- "@dxos/log": "0.9.1-staging.ee54ba693a",
112
- "@dxos/plugin-deck": "0.9.1-staging.ee54ba693a",
113
- "@dxos/plugin-graph": "0.9.1-staging.ee54ba693a",
114
- "@dxos/random": "0.9.1-staging.ee54ba693a",
115
- "@dxos/react-ui-list": "0.9.1-staging.ee54ba693a",
116
- "@dxos/react-ui-attention": "0.9.1-staging.ee54ba693a",
117
- "@dxos/react-ui-menu": "0.9.1-staging.ee54ba693a",
118
- "@dxos/react-ui-search": "0.9.1-staging.ee54ba693a",
119
- "@dxos/react-ui-tabs": "0.9.1-staging.ee54ba693a",
120
- "@dxos/util": "0.9.1-staging.ee54ba693a"
95
+ "@effect-atom/atom": "^0.5.3",
96
+ "@dxos/app-framework": "0.11.0",
97
+ "@dxos/app-graph": "0.11.0",
98
+ "@dxos/app-toolkit": "0.11.0",
99
+ "@dxos/async": "0.11.0",
100
+ "@dxos/compute": "0.11.0",
101
+ "@dxos/debug": "0.11.0",
102
+ "@dxos/echo": "0.11.0",
103
+ "@dxos/keyboard": "0.11.0",
104
+ "@dxos/keys": "0.11.0",
105
+ "@dxos/lit-ui": "0.11.0",
106
+ "@dxos/log": "0.11.0",
107
+ "@dxos/plugin-deck": "0.11.0",
108
+ "@dxos/plugin-graph": "0.11.0",
109
+ "@dxos/random": "0.11.0",
110
+ "@dxos/react-ui-attention": "0.11.0",
111
+ "@dxos/react-ui-list": "0.11.0",
112
+ "@dxos/react-ui-menu": "0.11.0",
113
+ "@dxos/react-ui-search": "0.11.0",
114
+ "@dxos/react-ui-tabs": "0.11.0",
115
+ "@dxos/util": "0.11.0"
121
116
  },
122
117
  "devDependencies": {
123
118
  "@effect-atom/atom-react": "^0.5.0",
@@ -127,15 +122,15 @@
127
122
  "effect": "3.21.4",
128
123
  "react": "~19.2.7",
129
124
  "react-dom": "~19.2.7",
130
- "vite": "^8.0.16",
131
- "@dxos/plugin-attention": "0.9.1-staging.ee54ba693a",
132
- "@dxos/plugin-client": "0.9.1-staging.ee54ba693a",
133
- "@dxos/plugin-space": "0.9.1-staging.ee54ba693a",
134
- "@dxos/storybook-utils": "0.9.1-staging.ee54ba693a",
135
- "@dxos/react-ui": "0.9.1-staging.ee54ba693a",
136
- "@dxos/ui-theme": "0.9.1-staging.ee54ba693a",
137
- "@dxos/plugin-theme": "0.9.1-staging.ee54ba693a",
138
- "@dxos/plugin-testing": "0.9.1-staging.ee54ba693a"
125
+ "vite": "^8.1.4",
126
+ "@dxos/plugin-attention": "0.11.0",
127
+ "@dxos/plugin-client": "0.11.0",
128
+ "@dxos/plugin-space": "0.11.0",
129
+ "@dxos/plugin-testing": "0.11.0",
130
+ "@dxos/plugin-theme": "0.11.0",
131
+ "@dxos/react-ui": "0.11.0",
132
+ "@dxos/ui-theme": "0.11.0",
133
+ "@dxos/storybook-utils": "0.11.0"
139
134
  },
140
135
  "peerDependencies": {
141
136
  "@effect-atom/atom-react": "^0.5.0",
@@ -143,8 +138,8 @@
143
138
  "effect": "3.21.4",
144
139
  "react": "~19.2.7",
145
140
  "react-dom": "~19.2.7",
146
- "@dxos/ui-theme": "0.9.1-staging.ee54ba693a",
147
- "@dxos/react-ui": "0.9.1-staging.ee54ba693a"
141
+ "@dxos/ui-theme": "^0.11.0",
142
+ "@dxos/react-ui": "^0.11.0"
148
143
  },
149
144
  "publishConfig": {
150
145
  "access": "public"
@@ -6,6 +6,7 @@ import * as Effect from 'effect/Effect';
6
6
 
7
7
  import { ActivationEvent, ActivationEvents, Capabilities, Capability, Plugin } from '@dxos/app-framework';
8
8
  import { AppActivationEvents, AppCapabilities, AppPlugin, LayoutOperation } from '@dxos/app-toolkit';
9
+ import { AttentionEvents } from '@dxos/plugin-attention';
9
10
  import { Graph } from '@dxos/plugin-graph';
10
11
 
11
12
  import { AppGraphBuilder, Keyboard, OperationHandler, ReactSurface, State } from '#capabilities';
@@ -23,7 +24,8 @@ export const NavTreePlugin = Plugin.define(meta).pipe(
23
24
  AppPlugin.addTranslationsModule({ translations }),
24
25
  Plugin.addModule({
25
26
  id: 'state',
26
- activatesOn: AppActivationEvents.LayoutReady,
27
+ // Wait for AttentionReady too so the ViewState Manager (the expansion persistence backend) is available.
28
+ activatesOn: ActivationEvent.allOf(AppActivationEvents.LayoutReady, AttentionEvents.AttentionReady),
27
29
  firesAfterActivation: [NavTreeEvents.StateReady],
28
30
  activate: State,
29
31
  }),
@@ -0,0 +1,55 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Registry } from '@effect-atom/atom';
6
+ import { describe, test } from 'vitest';
7
+
8
+ import { LocalBackend, MemoryBackend, ViewState } from '@dxos/react-ui-attention';
9
+
10
+ import { navTreeOpenAspect } from './nav-tree-view-state';
11
+
12
+ // Minimal in-memory Storage stand-in (no real localStorage in the test runner).
13
+ const fakeStorage = (): Storage => {
14
+ const map = new Map<string, string>();
15
+ return {
16
+ get length() {
17
+ return map.size;
18
+ },
19
+ key: (index) => [...map.keys()][index] ?? null,
20
+ getItem: (key) => map.get(key) ?? null,
21
+ setItem: (key, value) => void map.set(key, value),
22
+ removeItem: (key) => void map.delete(key),
23
+ clear: () => map.clear(),
24
+ } as Storage;
25
+ };
26
+
27
+ const makeManager = (registry: Registry.Registry, storage: Storage) =>
28
+ new ViewState.Manager({
29
+ registry,
30
+ backends: { memory: new MemoryBackend(), local: new LocalBackend({ registry, storage }) },
31
+ });
32
+
33
+ describe('navTreeOpenAspect', () => {
34
+ test('declares a local aspect that defaults to collapsed', ({ expect }) => {
35
+ expect(navTreeOpenAspect.key).toEqual('navtree-open');
36
+ expect(navTreeOpenAspect.backend).toEqual('local');
37
+ expect(navTreeOpenAspect.defaultValue()).toEqual({ open: false });
38
+ });
39
+
40
+ test('expansion persists per path and re-seeds on reload', ({ expect }) => {
41
+ const storage = fakeStorage();
42
+
43
+ // First session: expand two paths.
44
+ const first = makeManager(Registry.make(), storage);
45
+ first.set(navTreeOpenAspect, 'root~a', { open: true });
46
+ first.set(navTreeOpenAspect, 'root~b', { open: true });
47
+
48
+ // Second session (new registry + manager, same storage) mirrors a reload: the persisted paths and
49
+ // their `open` values are recovered via `contexts` + `get` — exactly how navtree seeds backingState.
50
+ const second = makeManager(Registry.make(), storage);
51
+ expect(second.contexts(navTreeOpenAspect).toSorted()).toEqual(['root~a', 'root~b']);
52
+ expect(second.get(navTreeOpenAspect, 'root~a')).toEqual({ open: true });
53
+ expect(second.get(navTreeOpenAspect, 'unseen')).toEqual({ open: false });
54
+ });
55
+ });
@@ -0,0 +1,19 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+
7
+ import { ViewState } from '@dxos/react-ui-attention/types';
8
+
9
+ /**
10
+ * Per-path navtree expansion, persisted (localStorage) via the ViewState `local` backend keyed by
11
+ * tree path — replaces the hand-rolled single-blob localStorage store. Only `open` is durable; the
12
+ * `current` highlight is ephemeral (driven by the active layout) and never persisted.
13
+ */
14
+ export const navTreeOpenAspect = ViewState.define({
15
+ key: 'navtree-open',
16
+ backend: 'local',
17
+ schema: Schema.Struct({ open: Schema.Boolean }),
18
+ defaultValue: () => ({ open: false }),
19
+ });
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import React, { type ComponentProps } from 'react';
6
+ import { type ComponentProps } from 'react';
7
7
 
8
8
  import { Capabilities, Capability } from '@dxos/app-framework';
9
9
  import { Surface } from '@dxos/app-framework/ui';
@@ -20,27 +20,26 @@ export default Capability.makeModule(() =>
20
20
  Surface.create({
21
21
  id: COMMANDS_DIALOG,
22
22
  filter: AppSurface.component<ComponentProps<typeof CommandsDialogContent>>(AppSurface.Dialog, COMMANDS_DIALOG),
23
- component: ({ data, ref }) => <CommandsDialogContent {...data.props} ref={ref} />,
23
+ component: CommandsDialogContent,
24
+ props: ({ data: { props }, ref }) => ({ ...props, ref }),
24
25
  }),
25
26
  Surface.create({
26
27
  id: 'navigation',
27
28
  filter: Surface.makeFilter(AppSurface.Navigation),
28
- component: ({ data, ref }) => (
29
- <NavTreeContainer tab={data.current} popoverAnchorId={data.popoverAnchorId} ref={ref} />
30
- ),
29
+ component: NavTreeContainer,
30
+ props: ({ data: { current, popoverAnchorId }, ref }) => ({ tab: current, popoverAnchorId, ref }),
31
31
  }),
32
32
  Surface.create({
33
33
  id: 'documentTitle',
34
34
  filter: Surface.makeFilter(AppSurface.DocumentTitle),
35
- component: ({ data }) => (
36
- <NavTreeDocumentTitle node={Node.isGraphNode(data.subject) ? data.subject : undefined} />
37
- ),
35
+ component: NavTreeDocumentTitle,
36
+ props: ({ data: { subject } }) => ({ node: Node.isGraphNode(subject) ? subject : undefined }),
38
37
  }),
39
38
  Surface.create({
40
39
  id: 'searchInput',
41
40
  filter: Surface.makeFilter(AppSurface.SearchInput),
42
41
  position: Position.last,
43
- component: () => <CommandsTrigger />,
42
+ component: CommandsTrigger,
44
43
  }),
45
44
  ]),
46
45
  ),
@@ -2,21 +2,21 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Atom } from '@effect-atom/atom-react';
5
+ import { Atom } from '@effect-atom/atom';
6
6
  import * as Effect from 'effect/Effect';
7
7
 
8
8
  import { Capabilities, Capability } from '@dxos/app-framework';
9
9
  import { AppCapabilities } from '@dxos/app-toolkit';
10
+ import { AttentionCapabilities } from '@dxos/plugin-attention';
10
11
  import { Graph, Node } from '@dxos/plugin-graph';
11
12
  import { Path } from '@dxos/react-ui-list';
12
13
 
13
- import { meta } from '#meta';
14
14
  import { NavTreeCapabilities } from '#types';
15
15
 
16
- const KEY = `${meta.profile.key}.state.v1`;
16
+ import { navTreeOpenAspect } from './nav-tree-view-state';
17
17
 
18
- /** Default item state for new entries. */
19
- const defaultItemState: NavTreeCapabilities.NavTreeItemState = { open: false, current: false };
18
+ /** Default `open` value for new entries; `current` is derived from the layout when the entry is created. */
19
+ const defaultOpen = false;
20
20
 
21
21
  /** L0 (top-level workspace) paths are direct children of root — not part of the expandable tree model. */
22
22
  const isTopLevelPath = (path: string[]): boolean => path.length === 2 && path[0] === Node.RootId;
@@ -27,41 +27,52 @@ const defaultStateEntries: [string, NavTreeCapabilities.NavTreeItemState][] = [
27
27
  ['root', { open: true, current: false }],
28
28
  ];
29
29
 
30
- const getInitialState = (): Map<string, NavTreeCapabilities.NavTreeItemState> => {
31
- const stringified = localStorage.getItem(KEY);
32
- if (!stringified) {
33
- return new Map(defaultStateEntries);
34
- }
35
-
36
- try {
37
- const cached: [string, { open: boolean; current: boolean }][] = JSON.parse(stringified);
38
- return new Map(cached.map(([key, value]) => [key, { open: value.open, current: false }]));
39
- } catch {
40
- return new Map(defaultStateEntries);
41
- }
42
- };
43
-
44
30
  export default Capability.makeModule(
45
31
  Effect.fnUntraced(function* () {
46
32
  const registry = yield* Capability.get(Capabilities.AtomRegistry);
47
33
  const layoutAtom = yield* Capability.get(AppCapabilities.Layout);
34
+ // Persistence backend for per-path expansion (`open`); replaces the hand-rolled localStorage blob.
35
+ const viewState = yield* Capability.get(AttentionCapabilities.ViewState);
36
+
37
+ // Mirror of the layout's active planks. An item registers its path only on its first render, which
38
+ // can happen long after the layout change that made it current, so entries derive `current` from
39
+ // this at creation time rather than waiting for the next layout notification.
40
+ let activeIds: readonly string[] = registry.get(layoutAtom).active;
41
+
42
+ /** Item state for a path not seen before: `current` follows the layout, `open` starts closed. */
43
+ const initialItemState = (pathString: string): NavTreeCapabilities.NavTreeItemState => ({
44
+ open: defaultOpen,
45
+ current: activeIds.includes(Path.last(pathString)),
46
+ });
48
47
 
49
- // Backing state for persistence (not reactive).
50
- const backingState = getInitialState();
48
+ // Backing state (not reactive), seeded from the persisted `open` values; `current` is ephemeral.
49
+ const persistedPaths = viewState.contexts(navTreeOpenAspect);
50
+ const backingState: Map<string, NavTreeCapabilities.NavTreeItemState> =
51
+ persistedPaths.length === 0
52
+ ? new Map(defaultStateEntries)
53
+ : new Map(
54
+ persistedPaths.map((pathString) => [
55
+ pathString,
56
+ {
57
+ open: viewState.get(navTreeOpenAspect, pathString).open,
58
+ current: activeIds.includes(Path.last(pathString)),
59
+ },
60
+ ]),
61
+ );
51
62
 
52
63
  // Per-path atom family for fine-grained reactivity.
53
64
  // keepAlive prevents atoms from being garbage collected when components unmount,
54
65
  // ensuring state is preserved across deletion/restoration cycles.
55
66
  const itemAtomFamily = Atom.family((pathString: string) =>
56
- Atom.make<NavTreeCapabilities.NavTreeItemState>(backingState.get(pathString) ?? { ...defaultItemState }).pipe(
57
- Atom.keepAlive,
58
- ),
67
+ Atom.make<NavTreeCapabilities.NavTreeItemState>(
68
+ backingState.get(pathString) ?? initialItemState(pathString),
69
+ ).pipe(Atom.keepAlive),
59
70
  );
60
71
 
61
72
  const getItemAtom = (path: string[]): Atom.Atom<NavTreeCapabilities.NavTreeItemState> => {
62
73
  const pathString = Path.create(...path);
63
74
  if (!backingState.has(pathString)) {
64
- backingState.set(pathString, { ...defaultItemState });
75
+ backingState.set(pathString, initialItemState(pathString));
65
76
  }
66
77
  return itemAtomFamily(pathString);
67
78
  };
@@ -77,18 +88,18 @@ export default Capability.makeModule(
77
88
  const newValue = { ...currentValue, [key]: next };
78
89
 
79
90
  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())));
91
+ // Track every touched path so the layout subscription can find it; only `open` is durable, and
92
+ // top-level workspace paths are excluded (their expansion is not part of the tree model).
93
+ backingState.set(pathString, newValue);
94
+ if (key === 'open' && !isTopLevelPath(path)) {
95
+ viewState.set(navTreeOpenAspect, pathString, { open: next });
84
96
  }
85
97
  };
86
98
 
87
99
  // Subscribe to layout changes to update current state.
88
- let previous: string[] = [];
89
100
  const unsubscribe = registry.subscribe(layoutAtom, (layout) => {
90
- const removed = previous.filter((id) => !layout.active.includes(id));
91
- previous = layout.active;
101
+ const removed = activeIds.filter((id) => !layout.active.includes(id));
102
+ activeIds = layout.active;
92
103
 
93
104
  const handleUpdate = () => {
94
105
  // Mark removed items as not current.
@@ -108,12 +119,10 @@ export default Capability.makeModule(
108
119
  });
109
120
  };
110
121
 
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
- // Defer so item path atoms exist and we do not setState during tree render.
115
- const timeout = setTimeout(handleUpdate, 500);
116
- return () => clearTimeout(timeout);
122
+ // Deferred only far enough to leave the layout notification (writing item atoms synchronously here
123
+ // would set state during the tree's render pass). Items whose path is not registered yet no longer
124
+ // need waiting out — they seed `current` from `activeIds` when they register.
125
+ queueMicrotask(handleUpdate);
117
126
  });
118
127
 
119
128
  // Once graph is ready, expand every node marked open in state so the graph has children loaded for rendering.
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Atom, type Registry } from '@effect-atom/atom-react';
5
+ import { Atom, type Registry } from '@effect-atom/atom';
6
6
  import { type Meta, type StoryObj } from '@storybook/react-vite';
7
7
  import * as Effect from 'effect/Effect';
8
8
  import React, { useEffect, useRef } from 'react';
@@ -10,7 +10,7 @@ import { expect, userEvent, within } from 'storybook/test';
10
10
 
11
11
  import { Capabilities, Capability } from '@dxos/app-framework';
12
12
  import { withPluginManager } from '@dxos/app-framework/testing';
13
- import { useAtomCapability } from '@dxos/app-framework/ui';
13
+ import { useAtomCapability, useOperationInvoker } from '@dxos/app-framework/ui';
14
14
  import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
15
15
  import { Operation, OperationHandlerSet } from '@dxos/compute';
16
16
  import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
@@ -76,7 +76,7 @@ const StoryPlank = ({ attendableId }: { attendableId: string }) => {
76
76
  <Panel.Root
77
77
  {...attentionAttrs}
78
78
  role='article'
79
- classNames='is-[30rem] shrink-0 bs-full bg-base-surface border-e border-separator'
79
+ classNames='w-[30rem] shrink-0 h-full dx-base-surface border-e border-separator'
80
80
  >
81
81
  <StoryPlankHeading attendableId={attendableId} />
82
82
  <Panel.Content classNames='grid'>
@@ -88,7 +88,7 @@ const StoryPlank = ({ attendableId }: { attendableId: string }) => {
88
88
  <Input.Root>
89
89
  <Input.Label>Level 1 (group)</Input.Label>
90
90
  </Input.Root>
91
- <div className={mx(container, 'bg-base-surface')}>
91
+ <div className={mx(container, 'dx-base-surface')}>
92
92
  <Input.Root>
93
93
  <Input.Label>Level 2 (base)</Input.Label>
94
94
  <Input.TextArea placeholder='Enter text' />
@@ -110,7 +110,7 @@ const DefaultStory = () => {
110
110
  <NavTreeContainer tab={state.tab} />
111
111
  </Main.NavigationSidebar>
112
112
  <Main.Content bounce handlesFocus>
113
- <div role='none' className='flex grow overflow-x-auto'>
113
+ <div className='flex grow overflow-x-auto'>
114
114
  <StoryPlank attendableId='space-0:object-0' />
115
115
  <StoryPlank attendableId='space-0:object-1' />
116
116
  </div>
@@ -119,6 +119,18 @@ const DefaultStory = () => {
119
119
  );
120
120
  };
121
121
 
122
+ /** A workspace absent from the graph (a dead link, or persisted deck state after a profile switch). */
123
+ const MISSING_WORKSPACE = 'root/B4NRQGGJ7XSDT4WMGXCTZNBLTDYIWGXNQIB6JW3AVLW3G';
124
+
125
+ const UnavailableWorkspaceStory = () => {
126
+ const { invokePromise } = useOperationInvoker();
127
+ useEffect(() => {
128
+ void invokePromise(LayoutOperation.SwitchWorkspace, { subject: MISSING_WORKSPACE });
129
+ }, [invokePromise]);
130
+
131
+ return <DefaultStory />;
132
+ };
133
+
122
134
  const meta = {
123
135
  title: 'plugins/plugin-navtree/components/NavTree',
124
136
  component: NavTreeContainer,
@@ -211,3 +223,12 @@ export const Default: Story = {
211
223
  await expect(document.activeElement).toHaveAttribute('data-main-landmark', '1');
212
224
  },
213
225
  };
226
+
227
+ export const UnavailableWorkspace: Story = {
228
+ render: UnavailableWorkspaceStory,
229
+ play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
230
+ const canvas = within(canvasElement);
231
+ // Plugin startup plus the message's own render delay; allow for a slow CI runner.
232
+ await canvas.findByTestId('navtree.workspace.unavailable', {}, { timeout: 15000 });
233
+ },
234
+ };
@@ -5,7 +5,8 @@
5
5
  import React, { forwardRef, useMemo } from 'react';
6
6
 
7
7
  import { useAppGraph } from '@dxos/app-toolkit/ui';
8
- import { Node, useConnections, useActions as useGraphActions } from '@dxos/plugin-graph';
8
+ import { Node } from '@dxos/plugin-graph';
9
+ import { useConnections, useActions as useGraphActions } from '@dxos/plugin-graph/hooks';
9
10
  import { type MenuItem } from '@dxos/react-ui-menu';
10
11
  import { Tabs } from '@dxos/react-ui-tabs';
11
12
  import { Position } from '@dxos/util';
@@ -61,25 +62,21 @@ const useTopLevelNavItems = (root?: Node.Node) => {
61
62
  const outboundPinnedItems: Node.Node[] = [];
62
63
  let userAccountItem: Node.Node | undefined;
63
64
  for (const node of rootOutboundItems) {
64
- switch (node.properties.disposition) {
65
- case 'workspace':
66
- topLevelWorkspaces.push(node);
67
- break;
68
- case 'pin-end':
69
- outboundPinnedItems.push(node);
70
- break;
71
- case 'user-account':
72
- userAccountItem ??= node;
73
- break;
65
+ if (Node.hasDisposition(node, 'workspace')) {
66
+ topLevelWorkspaces.push(node);
67
+ } else if (Node.hasDisposition(node, 'pin-end')) {
68
+ outboundPinnedItems.push(node);
69
+ } else if (Node.hasDisposition(node, 'user-account')) {
70
+ userAccountItem ??= node;
74
71
  }
75
72
  }
76
73
 
77
74
  const topLevelActions = rootActions
78
- .filter((action) => action.properties.disposition === 'menu')
75
+ .filter((action) => Node.hasDisposition(action, 'menu'))
79
76
  .toSorted((a, b) => Position.compare(a.properties, b.properties));
80
77
  const pinnedItems = [
81
78
  ...outboundPinnedItems,
82
- ...rootActions.filter((action) => action.properties.disposition === 'pin-end'),
79
+ ...rootActions.filter((action) => Node.hasDisposition(action, 'pin-end')),
83
80
  ].toSorted((a, b) => Position.compare(a.properties, b.properties));
84
81
 
85
82
  return {
@@ -5,7 +5,7 @@
5
5
  import React, { useCallback } from 'react';
6
6
 
7
7
  import { type Node } from '@dxos/app-graph';
8
- import { useActionRunner } from '@dxos/plugin-graph';
8
+ import { useActionRunner } from '@dxos/plugin-graph/hooks';
9
9
  import { IconButton, toLocalizedString, useDensityContext, useTranslation } from '@dxos/react-ui';
10
10
  import { composable, composableProps } from '@dxos/react-ui';
11
11
  import { Menu, type MenuItem } from '@dxos/react-ui-menu';
@@ -26,7 +26,7 @@ import React, {
26
26
 
27
27
  import { type Node } from '@dxos/app-graph';
28
28
  import { DxAvatar } from '@dxos/lit-ui/react';
29
- import { useActionRunner } from '@dxos/plugin-graph';
29
+ import { useActionRunner } from '@dxos/plugin-graph/hooks';
30
30
  import {
31
31
  Icon,
32
32
  IconButton,
@@ -99,7 +99,13 @@ const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
99
99
  case 'tab':
100
100
  return onTabChange?.(item);
101
101
  case 'link':
102
- return onSelect?.({ item, path, current: !getItem(path).current, option: event.altKey });
102
+ return onSelect?.({
103
+ item,
104
+ path,
105
+ current: !getItem(path).current,
106
+ option: event.altKey,
107
+ shift: event.shiftKey,
108
+ });
103
109
  }
104
110
  },
105
111
  [item, parent, type, getItem, onSelect, onTabChange, isLg, runAction],
@@ -325,7 +331,7 @@ export const L0Menu = ({
325
331
  classNames={[
326
332
  'group/l0 absolute z-[1] inset-y-0 start-0 rounded-is',
327
333
  'grid grid-cols-[var(--dx-l0-size)] grid-rows-[var(--dx-rail-size)_1fr_min-content_var(--dx-l0-size)] dx-contain-layout',
328
- 'w-(--dx-l0-size) bg-l0-surface dx-app-drag pb-[env(safe-area-inset-bottom)]',
334
+ 'w-(--dx-l0-size) dx-l0-surface dx-app-drag pb-[env(safe-area-inset-bottom)]',
329
335
  '[body[data-platform="macos"]_&]:pt-[30px]',
330
336
  '[body[data-platform="ios"]_&]:pt-[max(env(safe-area-inset-top),0.25rem)]',
331
337
  ]}