@dxos/plugin-simple-layout 0.8.4-main.1068cf700f → 0.8.4-main.1c7ec43d41

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 (242) hide show
  1. package/dist/lib/browser/SimpleLayoutPlugin-Q5BZE6KD.mjs +50 -0
  2. package/dist/lib/browser/SimpleLayoutPlugin-Q5BZE6KD.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +21 -97
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/translations.mjs +34 -0
  7. package/dist/lib/browser/translations.mjs.map +7 -0
  8. package/dist/lib/node-esm/SimpleLayoutPlugin-OD45TNPO.mjs +52 -0
  9. package/dist/lib/node-esm/SimpleLayoutPlugin-OD45TNPO.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +21 -96
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/translations.mjs +36 -0
  14. package/dist/lib/node-esm/translations.mjs.map +7 -0
  15. package/dist/types/src/SimpleLayoutPlugin.d.ts +2 -1
  16. package/dist/types/src/SimpleLayoutPlugin.d.ts.map +1 -1
  17. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  18. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  19. package/dist/types/src/capabilities/index.d.ts +21 -6
  20. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  21. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  22. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  23. package/dist/types/src/capabilities/{react-root/react-root.d.ts → react-root.d.ts} +1 -1
  24. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  25. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  26. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  27. package/dist/types/src/capabilities/{spotlight-dismiss/spotlight-dismiss.d.ts → spotlight-dismiss.d.ts} +1 -1
  28. package/dist/types/src/capabilities/spotlight-dismiss.d.ts.map +1 -0
  29. package/dist/types/src/capabilities/{state/state.d.ts → state.d.ts} +2 -2
  30. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  31. package/dist/types/src/capabilities/url-handler.d.ts +12 -0
  32. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
  33. package/dist/types/src/components/ContentError.stories.d.ts +27 -22
  34. package/dist/types/src/components/ContentError.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts +19 -0
  36. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts.map +1 -0
  37. package/dist/types/src/components/DebugOverlay/index.d.ts +2 -0
  38. package/dist/types/src/components/DebugOverlay/index.d.ts.map +1 -0
  39. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  40. package/dist/types/src/components/Home/Home.d.ts.map +1 -1
  41. package/dist/types/src/components/Loading/Loading.d.ts +3 -0
  42. package/dist/types/src/components/Loading/Loading.d.ts.map +1 -0
  43. package/dist/types/src/components/{ContentLoading.stories.d.ts → Loading/Loading.stories.d.ts} +1 -1
  44. package/dist/types/src/components/Loading/Loading.stories.d.ts.map +1 -0
  45. package/dist/types/src/components/Loading/index.d.ts +2 -0
  46. package/dist/types/src/components/Loading/index.d.ts.map +1 -0
  47. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts +2 -2
  48. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts.map +1 -1
  49. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts.map +1 -1
  50. package/dist/types/src/components/NavBranch/NavBranch.d.ts +11 -0
  51. package/dist/types/src/components/NavBranch/NavBranch.d.ts.map +1 -0
  52. package/dist/types/src/components/NavBranch/index.d.ts +2 -0
  53. package/dist/types/src/components/NavBranch/index.d.ts.map +1 -0
  54. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  55. package/dist/types/src/components/SimpleLayout/AppBar.d.ts +5 -7
  56. package/dist/types/src/components/SimpleLayout/AppBar.d.ts.map +1 -1
  57. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts +29 -22
  58. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts.map +1 -1
  59. package/dist/types/src/components/SimpleLayout/Drawer.d.ts +4 -7
  60. package/dist/types/src/components/SimpleLayout/Drawer.d.ts.map +1 -1
  61. package/dist/types/src/components/SimpleLayout/Main.d.ts +4 -7
  62. package/dist/types/src/components/SimpleLayout/Main.d.ts.map +1 -1
  63. package/dist/types/src/components/SimpleLayout/NavBar.d.ts +5 -7
  64. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -1
  65. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts +29 -23
  66. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts.map +1 -1
  67. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts.map +1 -1
  68. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts +26 -25
  69. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts.map +1 -1
  70. package/dist/types/src/components/hooks.d.ts +4 -2
  71. package/dist/types/src/components/hooks.d.ts.map +1 -1
  72. package/dist/types/src/components/index.d.ts +3 -2
  73. package/dist/types/src/components/index.d.ts.map +1 -1
  74. package/dist/types/src/hooks/actions.d.ts +5 -6
  75. package/dist/types/src/hooks/actions.d.ts.map +1 -1
  76. package/dist/types/src/hooks/useAppBarProps.d.ts +2 -2
  77. package/dist/types/src/hooks/useAppBarProps.d.ts.map +1 -1
  78. package/dist/types/src/hooks/useCompanions.d.ts.map +1 -1
  79. package/dist/types/src/hooks/useDrawerActions.d.ts.map +1 -1
  80. package/dist/types/src/hooks/useNavbarActions.d.ts.map +1 -1
  81. package/dist/types/src/hooks/useSimpleLayoutState.d.ts +1 -1
  82. package/dist/types/src/hooks/useSimpleLayoutState.d.ts.map +1 -1
  83. package/dist/types/src/index.d.ts +3 -1
  84. package/dist/types/src/index.d.ts.map +1 -1
  85. package/dist/types/src/meta.d.ts.map +1 -1
  86. package/dist/types/src/operations/close.d.ts +5 -0
  87. package/dist/types/src/operations/close.d.ts.map +1 -0
  88. package/dist/types/src/operations/index.d.ts +3 -0
  89. package/dist/types/src/operations/index.d.ts.map +1 -0
  90. package/dist/types/src/operations/open.d.ts +5 -0
  91. package/dist/types/src/operations/open.d.ts.map +1 -0
  92. package/dist/types/src/operations/revert-workspace.d.ts +5 -0
  93. package/dist/types/src/operations/revert-workspace.d.ts.map +1 -0
  94. package/dist/types/src/operations/set-layout-mode.d.ts +5 -0
  95. package/dist/types/src/operations/set-layout-mode.d.ts.map +1 -0
  96. package/dist/types/src/operations/set.d.ts +5 -0
  97. package/dist/types/src/operations/set.d.ts.map +1 -0
  98. package/dist/types/src/operations/state-access.d.ts +8 -0
  99. package/dist/types/src/operations/state-access.d.ts.map +1 -0
  100. package/dist/types/src/operations/switch-workspace.d.ts +5 -0
  101. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -0
  102. package/dist/types/src/operations/update-complementary.d.ts +5 -0
  103. package/dist/types/src/operations/update-complementary.d.ts.map +1 -0
  104. package/dist/types/src/operations/update-dialog.d.ts +5 -0
  105. package/dist/types/src/operations/update-dialog.d.ts.map +1 -0
  106. package/dist/types/src/operations/update-popover.d.ts +5 -0
  107. package/dist/types/src/operations/update-popover.d.ts.map +1 -0
  108. package/dist/types/src/operations/update-sidebar.d.ts +5 -0
  109. package/dist/types/src/operations/update-sidebar.d.ts.map +1 -0
  110. package/dist/types/src/translations.d.ts +26 -20
  111. package/dist/types/src/translations.d.ts.map +1 -1
  112. package/dist/types/src/types/capabilities.d.ts +10 -2
  113. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  114. package/dist/types/src/types/events.d.ts.map +1 -1
  115. package/dist/types/tsconfig.tsbuildinfo +1 -1
  116. package/package.json +49 -30
  117. package/src/SimpleLayoutPlugin.ts +18 -7
  118. package/src/capabilities/app-graph-builder.ts +21 -0
  119. package/src/capabilities/index.ts +13 -6
  120. package/src/capabilities/operation-handler.ts +14 -0
  121. package/src/capabilities/{react-root/react-root.tsx → react-root.tsx} +2 -2
  122. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +17 -8
  123. package/src/capabilities/{state/state.tsx → state.tsx} +2 -2
  124. package/src/capabilities/url-handler.ts +161 -0
  125. package/src/components/ContentError.stories.tsx +8 -7
  126. package/src/components/DebugOverlay/DebugOverlay.tsx +96 -0
  127. package/src/components/DebugOverlay/index.ts +5 -0
  128. package/src/components/Dialog/Dialog.tsx +15 -4
  129. package/src/components/Home/Home.tsx +38 -32
  130. package/src/components/{ContentLoading.stories.tsx → Loading/Loading.stories.tsx} +4 -4
  131. package/src/components/{ContentLoading.tsx → Loading/Loading.tsx} +2 -2
  132. package/src/components/Loading/index.ts +5 -0
  133. package/src/components/MobileLayout/MobileLayout.stories.tsx +38 -30
  134. package/src/components/MobileLayout/MobileLayout.tsx +118 -49
  135. package/src/components/{Workspace/Workspace.tsx → NavBranch/NavBranch.tsx} +44 -39
  136. package/src/components/{Workspace → NavBranch}/index.ts +1 -1
  137. package/src/components/Popover/Popover.tsx +12 -8
  138. package/src/components/SimpleLayout/AppBar.stories.tsx +12 -12
  139. package/src/components/SimpleLayout/AppBar.tsx +56 -63
  140. package/src/components/SimpleLayout/Drawer.tsx +38 -36
  141. package/src/components/SimpleLayout/Main.tsx +22 -25
  142. package/src/components/SimpleLayout/NavBar.stories.tsx +9 -9
  143. package/src/components/SimpleLayout/NavBar.tsx +10 -17
  144. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +46 -69
  145. package/src/components/SimpleLayout/SimpleLayout.tsx +33 -34
  146. package/src/components/hooks.ts +8 -8
  147. package/src/components/index.ts +3 -2
  148. package/src/hooks/actions.ts +17 -18
  149. package/src/hooks/useAppBarProps.ts +14 -31
  150. package/src/hooks/useCompanions.ts +1 -1
  151. package/src/hooks/useDrawerActions.ts +15 -13
  152. package/src/hooks/useNavbarActions.ts +13 -12
  153. package/src/hooks/useSimpleLayoutState.ts +1 -1
  154. package/src/index.ts +7 -1
  155. package/src/meta.ts +2 -1
  156. package/src/operations/close.ts +34 -0
  157. package/src/operations/index.ts +16 -0
  158. package/src/operations/open.ts +63 -0
  159. package/src/operations/revert-workspace.ts +22 -0
  160. package/src/operations/set-layout-mode.ts +12 -0
  161. package/src/operations/set.ts +23 -0
  162. package/src/operations/state-access.ts +19 -0
  163. package/src/operations/switch-workspace.ts +26 -0
  164. package/src/operations/update-complementary.ts +35 -0
  165. package/src/operations/update-dialog.ts +28 -0
  166. package/src/operations/update-popover.ts +35 -0
  167. package/src/operations/update-sidebar.ts +12 -0
  168. package/src/translations.ts +21 -19
  169. package/src/types/capabilities.ts +4 -4
  170. package/src/types/events.ts +1 -1
  171. package/dist/lib/browser/chunk-7VLT3S46.mjs +0 -29
  172. package/dist/lib/browser/chunk-7VLT3S46.mjs.map +0 -7
  173. package/dist/lib/browser/chunk-O3BQBYMW.mjs +0 -1165
  174. package/dist/lib/browser/chunk-O3BQBYMW.mjs.map +0 -7
  175. package/dist/lib/browser/operation-resolver-BYRIQOQT.mjs +0 -205
  176. package/dist/lib/browser/operation-resolver-BYRIQOQT.mjs.map +0 -7
  177. package/dist/lib/browser/react-root-GPTKI5H2.mjs +0 -21
  178. package/dist/lib/browser/react-root-GPTKI5H2.mjs.map +0 -7
  179. package/dist/lib/browser/react-surface-LT5JJTPR.mjs +0 -41
  180. package/dist/lib/browser/react-surface-LT5JJTPR.mjs.map +0 -7
  181. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs +0 -66
  182. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs.map +0 -7
  183. package/dist/lib/browser/state-A3PGDWWZ.mjs +0 -48
  184. package/dist/lib/browser/state-A3PGDWWZ.mjs.map +0 -7
  185. package/dist/lib/browser/url-handler-HTIUY6WL.mjs +0 -152
  186. package/dist/lib/browser/url-handler-HTIUY6WL.mjs.map +0 -7
  187. package/dist/lib/node-esm/chunk-UAWM4B2S.mjs +0 -1166
  188. package/dist/lib/node-esm/chunk-UAWM4B2S.mjs.map +0 -7
  189. package/dist/lib/node-esm/chunk-VIDE5UMB.mjs +0 -31
  190. package/dist/lib/node-esm/chunk-VIDE5UMB.mjs.map +0 -7
  191. package/dist/lib/node-esm/operation-resolver-BDTFNCS2.mjs +0 -206
  192. package/dist/lib/node-esm/operation-resolver-BDTFNCS2.mjs.map +0 -7
  193. package/dist/lib/node-esm/react-root-GRG2OAI2.mjs +0 -22
  194. package/dist/lib/node-esm/react-root-GRG2OAI2.mjs.map +0 -7
  195. package/dist/lib/node-esm/react-surface-TCUSDIN2.mjs +0 -42
  196. package/dist/lib/node-esm/react-surface-TCUSDIN2.mjs.map +0 -7
  197. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs +0 -68
  198. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs.map +0 -7
  199. package/dist/lib/node-esm/state-ZCFZTTPL.mjs +0 -49
  200. package/dist/lib/node-esm/state-ZCFZTTPL.mjs.map +0 -7
  201. package/dist/lib/node-esm/url-handler-WBVVKVPC.mjs +0 -153
  202. package/dist/lib/node-esm/url-handler-WBVVKVPC.mjs.map +0 -7
  203. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  204. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  205. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  206. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  207. package/dist/types/src/capabilities/react-root/index.d.ts +0 -6
  208. package/dist/types/src/capabilities/react-root/index.d.ts.map +0 -1
  209. package/dist/types/src/capabilities/react-root/react-root.d.ts.map +0 -1
  210. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  211. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  212. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  213. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  214. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts +0 -3
  215. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts.map +0 -1
  216. package/dist/types/src/capabilities/spotlight-dismiss/spotlight-dismiss.d.ts.map +0 -1
  217. package/dist/types/src/capabilities/state/index.d.ts +0 -13
  218. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  219. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  220. package/dist/types/src/capabilities/url-handler/index.d.ts +0 -3
  221. package/dist/types/src/capabilities/url-handler/index.d.ts.map +0 -1
  222. package/dist/types/src/capabilities/url-handler/url-handler.d.ts +0 -12
  223. package/dist/types/src/capabilities/url-handler/url-handler.d.ts.map +0 -1
  224. package/dist/types/src/components/ContentError.d.ts +0 -5
  225. package/dist/types/src/components/ContentError.d.ts.map +0 -1
  226. package/dist/types/src/components/ContentLoading.d.ts +0 -3
  227. package/dist/types/src/components/ContentLoading.d.ts.map +0 -1
  228. package/dist/types/src/components/ContentLoading.stories.d.ts.map +0 -1
  229. package/dist/types/src/components/Workspace/Workspace.d.ts +0 -11
  230. package/dist/types/src/components/Workspace/Workspace.d.ts.map +0 -1
  231. package/dist/types/src/components/Workspace/index.d.ts +0 -2
  232. package/dist/types/src/components/Workspace/index.d.ts.map +0 -1
  233. package/src/capabilities/operation-resolver/index.ts +0 -10
  234. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -217
  235. package/src/capabilities/react-root/index.ts +0 -7
  236. package/src/capabilities/react-surface/index.ts +0 -7
  237. package/src/capabilities/spotlight-dismiss/index.ts +0 -7
  238. package/src/capabilities/state/index.ts +0 -9
  239. package/src/capabilities/url-handler/index.ts +0 -7
  240. package/src/capabilities/url-handler/url-handler.ts +0 -157
  241. package/src/components/ContentError.tsx +0 -23
  242. /package/src/capabilities/{spotlight-dismiss/spotlight-dismiss.ts → spotlight-dismiss.ts} +0 -0
@@ -2,67 +2,72 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useEffect, useRef } from 'react';
5
+ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
6
6
 
7
7
  import { useOperationInvoker } from '@dxos/app-framework/ui';
8
8
  import { LayoutOperation } from '@dxos/app-toolkit';
9
9
  import { useAppGraph } from '@dxos/app-toolkit/ui';
10
10
  import { type Node, useConnections } from '@dxos/plugin-graph';
11
- import { Avatar, Icon, Layout, ScrollArea, Toolbar, toLocalizedString, useTranslation } from '@dxos/react-ui';
12
- import { Card, Mosaic, type StackTileComponent } from '@dxos/react-ui-mosaic';
13
- import { SearchList, useSearchListItem, useSearchListResults } from '@dxos/react-ui-searchlist';
11
+ import { Avatar, Icon, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';
12
+ import { Card } from '@dxos/react-ui';
13
+ import { Mosaic, type MosaicStackTileComponent } from '@dxos/react-ui-mosaic';
14
+ import { SearchPanel, useSearchListItem, useSearchListResults } from '@dxos/react-ui-search';
14
15
  import { mx } from '@dxos/ui-theme';
15
16
 
16
- import { meta } from '../../meta';
17
- import { useLoadDescendents } from '../hooks';
17
+ import { meta } from '#meta';
18
18
 
19
- export type WorkspaceProps = {
19
+ import { useExpandPath } from '../hooks';
20
+
21
+ export type NavBranchProps = {
20
22
  id: string;
21
23
  };
22
24
 
23
25
  /**
24
- * Displays the contents of a workspace disposition graph node as a searchable list.
25
- * Shows direct children of the workspace with icons and labels,
26
- * allowing users to filter via search and navigate by selecting an item.
26
+ * Renders the children of a graph branch node as a searchable mosaic list.
27
+ * Used for any node with `role: 'branch'` or a workspace disposition, including
28
+ * spaces, collection sections, type sections, and schema nodes.
27
29
  */
28
- export const Workspace = ({ id }: WorkspaceProps) => {
30
+ export const NavBranch = ({ id }: NavBranchProps) => {
29
31
  const { t } = useTranslation(meta.id);
30
32
  const { graph } = useAppGraph();
31
33
 
32
- // Expand the workspace node to load its children.
33
- useLoadDescendents(id);
34
+ useExpandPath(id);
35
+
36
+ const children = useConnections(graph, id, 'child');
34
37
 
35
- // Get direct children of the workspace node.
36
- const children = useConnections(graph, id, 'outbound');
38
+ const visibleChildren = useMemo(
39
+ () => children.filter((node) => node.properties.disposition !== 'hidden'),
40
+ [children],
41
+ );
37
42
 
38
43
  const { results, handleSearch } = useSearchListResults({
39
- items: children,
44
+ items: visibleChildren,
40
45
  extract: (child) => toLocalizedString(child.properties.label, t),
41
46
  });
42
47
 
43
48
  return (
44
- <Layout.Main toolbar>
45
- <SearchList.Root onSearch={handleSearch}>
46
- <Toolbar.Root>
47
- <SearchList.Input placeholder={t('search placeholder')} autoFocus />
48
- </Toolbar.Root>
49
- <SearchList.Content>
50
- <Mosaic.Container asChild>
51
- <ScrollArea.Root orientation='vertical'>
52
- <ScrollArea.Viewport classNames='p-2'>
53
- <Mosaic.Stack items={results} getId={(child) => child.id} Tile={WorkspaceChildTile} />
54
- </ScrollArea.Viewport>
55
- </ScrollArea.Root>
56
- </Mosaic.Container>
57
- </SearchList.Content>
58
- </SearchList.Root>
59
- </Layout.Main>
49
+ <SearchPanel onSearch={handleSearch}>
50
+ <Mosaic.Container asChild>
51
+ <ScrollArea.Root centered padding thin>
52
+ <ScrollArea.Viewport>
53
+ <Mosaic.Stack
54
+ classNames='gap-1'
55
+ draggable={false}
56
+ items={results}
57
+ getId={(item) => item.id}
58
+ Tile={NavBranchTile}
59
+ />
60
+ </ScrollArea.Viewport>
61
+ </ScrollArea.Root>
62
+ </Mosaic.Container>
63
+ </SearchPanel>
60
64
  );
61
65
  };
62
66
 
63
- const WorkspaceChildTile: StackTileComponent<Node.Node> = ({ data }) => {
67
+ const NavBranchTile: MosaicStackTileComponent<Node.Node> = (props) => {
68
+ const data = props.data;
64
69
  const { t } = useTranslation(meta.id);
65
- const { invokeSync } = useOperationInvoker();
70
+ const { invokePromise } = useOperationInvoker();
66
71
  const ref = useRef<HTMLDivElement>(null);
67
72
  const { selectedValue, registerItem, unregisterItem } = useSearchListItem();
68
73
  const isSelected = selectedValue === data.id;
@@ -70,8 +75,8 @@ const WorkspaceChildTile: StackTileComponent<Node.Node> = ({ data }) => {
70
75
  const name = toLocalizedString(data.properties.label, t);
71
76
 
72
77
  const handleSelect = useCallback(
73
- () => invokeSync(LayoutOperation.Open, { subject: [data.id] }),
74
- [invokeSync, data.id],
78
+ () => void invokePromise(LayoutOperation.Open, { subject: [data.id] }),
79
+ [invokePromise, data.id],
75
80
  );
76
81
 
77
82
  // Register this item with the search context.
@@ -97,17 +102,17 @@ const WorkspaceChildTile: StackTileComponent<Node.Node> = ({ data }) => {
97
102
  fullWidth
98
103
  tabIndex={-1} // TODO(burdon): Use Mosaic.Focus.
99
104
  data-selected={isSelected}
100
- classNames={mx('dx-focus-ring', isSelected && 'bg-hoverOverlay')}
105
+ classNames={mx('dx-focus-ring cursor-pointer', isSelected && 'bg-hover-overlay')}
101
106
  onClick={handleSelect}
102
107
  >
103
- <Card.Toolbar density='coarse'>
108
+ <Card.Toolbar>
104
109
  <Avatar.Root>
105
110
  <Avatar.Content
106
111
  hue={data.properties.hue}
107
112
  icon={data.properties.icon}
108
113
  hueVariant='transparent'
109
114
  variant='square'
110
- size={12}
115
+ size={8}
111
116
  fallback={name}
112
117
  />
113
118
  <Avatar.Label>{name}</Avatar.Label>
@@ -2,4 +2,4 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './Workspace';
5
+ export * from './NavBranch';
@@ -6,11 +6,12 @@ import { createContext } from '@radix-ui/react-context';
6
6
  import React, { type PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
 
8
8
  import { Surface } from '@dxos/app-framework/ui';
9
+ import { AppSurface } from '@dxos/app-toolkit/ui';
9
10
  import { Popover, type PopoverContentInteractOutsideEvent, toLocalizedString, useTranslation } from '@dxos/react-ui';
10
- import { Card } from '@dxos/react-ui-mosaic';
11
+ import { Card } from '@dxos/react-ui';
11
12
 
12
- import { useSimpleLayoutState } from '../../hooks';
13
- import { meta } from '../../meta';
13
+ import { useSimpleLayoutState } from '#hooks';
14
+ import { meta } from '#meta';
14
15
 
15
16
  const DEBOUNCE_DELAY = 40;
16
17
 
@@ -57,7 +58,6 @@ export const PopoverContent = () => {
57
58
  const { t } = useTranslation(meta.id);
58
59
  const { state, updateState } = useSimpleLayoutState();
59
60
  const { setOpen } = useLayoutPopoverContext('PopoverContent');
60
-
61
61
  const handleClose = useCallback(() => {
62
62
  setOpen(false);
63
63
  updateState((s) => ({
@@ -100,16 +100,20 @@ export const PopoverContent = () => {
100
100
  onEscapeKeyDown={handleInteractOutside}
101
101
  >
102
102
  <Popover.Viewport>
103
- {state.popoverKind === 'base' && <Surface.Surface role='popover' data={state.popoverContent} limit={1} />}
103
+ {state.popoverKind === 'base' && state.popoverContent && 'component' in state.popoverContent && (
104
+ <Surface.Surface type={AppSurface.Popover} data={state.popoverContent} limit={1} />
105
+ )}
104
106
  {state.popoverKind === 'card' && (
105
- <Card.Root border={false} classNames='popover-card-max-width'>
107
+ <Card.Root border={false} classNames='dx-card-popover'>
106
108
  <Card.Toolbar>
107
109
  {/* TODO(wittjosiah): Cleaner way to handle no drag handle in toolbar? */}
108
110
  <span />
109
111
  {state.popoverTitle ? <Card.Title>{toLocalizedString(state.popoverTitle, t)}</Card.Title> : <span />}
110
- <Card.Close onClick={handleClose} />
112
+ <Card.CloseIconButton onClick={handleClose} />
111
113
  </Card.Toolbar>
112
- <Surface.Surface role='card--content' data={state.popoverContent} limit={1} />
114
+ {state.popoverContent && 'subject' in state.popoverContent && (
115
+ <Surface.Surface type={AppSurface.Card} data={state.popoverContent} limit={1} />
116
+ )}
113
117
  </Card.Root>
114
118
  )}
115
119
  </Popover.Viewport>
@@ -7,13 +7,13 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
7
7
  import React, { useMemo } from 'react';
8
8
  import { type Mock, expect, fn, screen, userEvent, within } from 'storybook/test';
9
9
 
10
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
10
  import { type ActionGraphProps, createMenuAction } from '@dxos/react-ui-menu';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
12
  import { withRegistry } from '@dxos/storybook-utils';
13
13
 
14
- import { translations } from '../../translations';
15
- import { MobileLayout } from '../MobileLayout';
14
+ import { translations } from '#translations';
16
15
 
16
+ import { MobileLayout } from '../MobileLayout';
17
17
  import { AppBar, type AppBarProps } from './AppBar';
18
18
 
19
19
  const buildEmptyActions = (): ActionGraphProps => ({ nodes: [], edges: [] });
@@ -21,29 +21,29 @@ const buildEmptyActions = (): ActionGraphProps => ({ nodes: [], edges: [] });
21
21
  const buildDefaultActions = (): ActionGraphProps => {
22
22
  const result: ActionGraphProps = { nodes: [], edges: [] };
23
23
  const actions = [
24
- createMenuAction('action-edit', () => console.log('Edit'), {
24
+ createMenuAction('action-edit.menu', () => console.log('Edit'), {
25
25
  icon: 'ph--pencil--regular',
26
26
  label: 'Edit',
27
27
  }),
28
- createMenuAction('action-share', () => console.log('Share'), {
28
+ createMenuAction('action-share.menu', () => console.log('Share'), {
29
29
  icon: 'ph--share--regular',
30
30
  label: 'Share',
31
31
  }),
32
- createMenuAction('action-delete', () => console.log('Delete'), {
32
+ createMenuAction('action-delete.menu', () => console.log('Delete'), {
33
33
  icon: 'ph--trash--regular',
34
34
  label: 'Delete',
35
35
  }),
36
36
  ];
37
37
  result.nodes.push(...actions);
38
- result.edges.push(...actions.map((a) => ({ source: 'root', target: a.id })));
38
+ result.edges.push(...actions.map((a) => ({ source: 'root', target: a.id, relation: 'child' })));
39
39
  return result;
40
40
  };
41
41
 
42
- type StoryProps = Omit<AppBarProps, 'actions'> & {
42
+ type DefaultStoryProps = Omit<AppBarProps, 'actions'> & {
43
43
  actions: ActionGraphProps;
44
44
  };
45
45
 
46
- const DefaultStory = ({ actions: actionsProp, ...props }: StoryProps) => {
46
+ const DefaultStory = ({ actions: actionsProp, ...props }: DefaultStoryProps) => {
47
47
  const actions = useMemo(() => Atom.make(actionsProp).pipe(Atom.keepAlive), [actionsProp]);
48
48
  return (
49
49
  <MobileLayout.Root>
@@ -53,7 +53,7 @@ const DefaultStory = ({ actions: actionsProp, ...props }: StoryProps) => {
53
53
  };
54
54
 
55
55
  const meta = {
56
- title: 'plugins/plugin-simple-layout/AppBar',
56
+ title: 'plugins/plugin-simple-layout/components/AppBar',
57
57
  render: DefaultStory,
58
58
  decorators: [
59
59
  withTheme(),
@@ -71,7 +71,7 @@ const meta = {
71
71
 
72
72
  export default meta;
73
73
 
74
- type Story = StoryObj<StoryProps>;
74
+ type Story = StoryObj<DefaultStoryProps>;
75
75
 
76
76
  export const Default: Story = {
77
77
  tags: ['test'],
@@ -104,7 +104,7 @@ export const Default: Story = {
104
104
  const editAction = await screen.findByRole('menuitem', { name: /edit/i });
105
105
  await userEvent.click(editAction);
106
106
  await expect(args.onAction).toHaveBeenCalledTimes(1);
107
- await expect((args.onAction as Mock).mock.calls[0][0]).toHaveProperty('id', 'action-edit');
107
+ await expect((args.onAction as Mock).mock.calls[0][0]).toHaveProperty('id', 'action-edit.menu');
108
108
  },
109
109
  };
110
110
 
@@ -5,22 +5,17 @@
5
5
  import { type Atom, useAtomValue } from '@effect-atom/atom-react';
6
6
  import React, { Fragment } from 'react';
7
7
 
8
- import { IconButton, Popover, type ThemedClassName, Toolbar, useTranslation } from '@dxos/react-ui';
9
- import {
10
- type ActionExecutor,
11
- type ActionGraphProps,
12
- DropdownMenu,
13
- MenuProvider,
14
- useMenuActions,
15
- } from '@dxos/react-ui-menu';
16
- import { mx, osTranslations } from '@dxos/ui-theme';
8
+ import { IconButton, Popover, Toolbar, useTranslation } from '@dxos/react-ui';
9
+ import { type ActionExecutor, type ActionGraphProps, Menu, useMenuActions } from '@dxos/react-ui-menu';
10
+ import { composable, composableProps, osTranslations } from '@dxos/ui-theme';
11
+
12
+ import { meta } from '#meta';
17
13
 
18
- import { meta } from '../../meta';
19
14
  import { useMobileLayout } from '../MobileLayout';
20
15
 
21
16
  const APP_BAR_NAME = 'SimpleLayout.AppBar';
22
17
 
23
- export type AppBarProps = ThemedClassName<{
18
+ export type AppBarProps = {
24
19
  /** Title/label to display in the banner. */
25
20
  title?: string;
26
21
  /** Action graph atom for the dropdown menu. */
@@ -33,69 +28,67 @@ export type AppBarProps = ThemedClassName<{
33
28
  onAction?: ActionExecutor;
34
29
  /** Callback when back button is clicked. */
35
30
  onBack?: () => void;
36
- }>;
31
+ };
37
32
 
38
33
  /**
39
34
  * AppBar component that renders a title, optional back button, and actions dropdown.
40
35
  */
41
- export const AppBar = ({
42
- classNames,
43
- title,
44
- actions,
45
- showBackButton,
46
- popoverAnchorId,
47
- onAction,
48
- onBack,
49
- }: AppBarProps) => {
50
- const { t } = useTranslation(meta.id);
51
- const menu = useMenuActions(actions);
52
- const actionsValue = useAtomValue(actions);
53
- const hasActions = actionsValue.nodes.length > 0;
54
- const { keyboardOpen } = useMobileLayout(APP_BAR_NAME);
36
+ export const AppBar = composable<HTMLDivElement, AppBarProps>(
37
+ ({ classNames, title, actions, showBackButton, popoverAnchorId, onAction, onBack, ...props }, forwardedRef) => {
38
+ const { t } = useTranslation(meta.id);
39
+ const menuActions = useMenuActions(actions);
40
+ const actionsValue = useAtomValue(actions);
41
+ const hasActions = actionsValue.nodes.length > 0;
42
+ const { keyboardOpen } = useMobileLayout(APP_BAR_NAME);
55
43
 
56
- // Fall back to app name if no title provided.
57
- const displayTitle = title ?? t('current app name', { ns: osTranslations });
44
+ // Fall back to app name if no title provided.
45
+ const displayTitle = title ?? t('current-app.name', { ns: osTranslations });
58
46
 
59
- // Wrap the menu trigger with Popover.Anchor when the popoverAnchorId is set.
60
- const AnchorRoot = popoverAnchorId ? Popover.Anchor : Fragment;
47
+ // Wrap the menu trigger with Popover.Anchor when the popoverAnchorId is set.
48
+ const AnchorRoot = popoverAnchorId ? Popover.Anchor : Fragment;
61
49
 
62
- return (
63
- <Toolbar.Root
64
- role='banner'
65
- classNames={mx(
66
- 'grid grid-cols-[var(--rail-size)_1fr_var(--rail-size)] bs-[var(--rail-action)] items-center',
67
- 'density-fine',
68
- classNames,
69
- )}
70
- >
71
- {keyboardOpen ? (
72
- <IconButton variant='ghost' icon='ph--x--regular' iconOnly label={t('done label')} />
73
- ) : showBackButton ? (
74
- <IconButton variant='ghost' icon='ph--caret-left--regular' iconOnly label={t('back label')} onClick={onBack} />
75
- ) : (
76
- <div />
77
- )}
78
- <h1 className='text-center truncate font-thin uppercase'>{displayTitle}</h1>
79
- {hasActions ? (
80
- <AnchorRoot>
81
- <MenuProvider {...menu} onAction={onAction}>
82
- <DropdownMenu.Root caller={meta.id}>
83
- <DropdownMenu.Trigger asChild>
50
+ return (
51
+ <Toolbar.Root
52
+ {...composableProps(props, {
53
+ role: 'banner',
54
+ classNames: 'grid grid-cols-[var(--dx-rail-size)_1fr_var(--dx-rail-size)] items-center dx-density-fine',
55
+ })}
56
+ ref={forwardedRef}
57
+ >
58
+ {keyboardOpen ? (
59
+ <IconButton variant='ghost' icon='ph--x--regular' iconOnly label={t('done.label')} />
60
+ ) : showBackButton ? (
61
+ <IconButton
62
+ variant='ghost'
63
+ icon='ph--caret-left--regular'
64
+ iconOnly
65
+ label={t('back.label')}
66
+ onClick={onBack}
67
+ />
68
+ ) : (
69
+ <div />
70
+ )}
71
+ <h1 className='text-center truncate font-thin uppercase'>{displayTitle}</h1>
72
+ {hasActions ? (
73
+ <AnchorRoot>
74
+ <Menu.Root {...menuActions} caller={meta.id} onAction={onAction}>
75
+ <Menu.Trigger asChild>
84
76
  <IconButton
85
77
  variant='ghost'
86
78
  icon='ph--dots-three-vertical--regular'
87
79
  iconOnly
88
- label={t('actions menu label')}
80
+ label={t('actions-menu.label')}
89
81
  />
90
- </DropdownMenu.Trigger>
91
- </DropdownMenu.Root>
92
- </MenuProvider>
93
- </AnchorRoot>
94
- ) : (
95
- <span />
96
- )}
97
- </Toolbar.Root>
98
- );
99
- };
82
+ </Menu.Trigger>
83
+ <Menu.Content />
84
+ </Menu.Root>
85
+ </AnchorRoot>
86
+ ) : (
87
+ <span />
88
+ )}
89
+ </Toolbar.Root>
90
+ );
91
+ },
92
+ );
100
93
 
101
94
  AppBar.displayName = APP_BAR_NAME;
@@ -5,15 +5,15 @@
5
5
  import React, { useMemo } from 'react';
6
6
 
7
7
  import { Surface } from '@dxos/app-framework/ui';
8
- import { useAppGraph } from '@dxos/app-toolkit/ui';
8
+ import { AppSurface, useAppGraph } from '@dxos/app-toolkit/ui';
9
9
  import { type Node, useNode } from '@dxos/plugin-graph';
10
- import { Layout } from '@dxos/react-ui';
11
- import { ATTENDABLE_PATH_SEPARATOR } from '@dxos/react-ui-attention';
12
- import { MenuProvider, ToolbarMenu, useMenuActions } from '@dxos/react-ui-menu';
10
+ import { ErrorFallback, Panel } from '@dxos/react-ui';
11
+ import { getLinkedVariant } from '@dxos/react-ui-attention';
12
+ import { Menu, useMenuActions } from '@dxos/react-ui-menu';
13
13
 
14
- import { useCompanions, useDrawerActions, useSimpleLayoutState } from '../../hooks';
15
- import { ContentError } from '../ContentError';
16
- import { ContentLoading } from '../ContentLoading';
14
+ import { useCompanions, useDrawerActions, useSimpleLayoutState } from '#hooks';
15
+
16
+ import { Loading } from '../Loading';
17
17
 
18
18
  const DRAWER_NAME = 'SimpleLayout.Drawer';
19
19
 
@@ -24,7 +24,7 @@ export const Drawer = () => {
24
24
  const { graph } = useAppGraph();
25
25
  const { state: layoutState } = useSimpleLayoutState();
26
26
 
27
- const placeholder = useMemo(() => <ContentLoading />, []);
27
+ const placeholder = useMemo(() => <Loading />, []);
28
28
 
29
29
  // Get all companions for the current active (primary) item.
30
30
  const activeId = layoutState.active ?? layoutState.workspace;
@@ -36,40 +36,45 @@ export const Drawer = () => {
36
36
  const parentNode = useNode(graph, activeId);
37
37
 
38
38
  // Build Surface data for the companion content.
39
- const data = useMemo(() => {
40
- return (
41
- node && {
42
- attendableId: companionId,
43
- subject: node.data,
44
- companionTo: parentNode?.data,
45
- properties: node.properties,
46
- variant,
47
- }
48
- );
39
+ const data = useMemo<AppSurface.ArticleData | undefined>(() => {
40
+ if (!node || !companionId) {
41
+ return undefined;
42
+ }
43
+ return {
44
+ attendableId: companionId,
45
+ subject: node.data,
46
+ companionTo: parentNode?.data,
47
+ properties: node.properties,
48
+ variant,
49
+ };
49
50
  }, [companionId, node, parentNode, variant]);
50
51
 
51
52
  // Get drawer actions (tabs + toolbar buttons).
52
53
  const { actions, onAction } = useDrawerActions(DRAWER_NAME);
53
- const menu = useMenuActions(actions);
54
+ const menuActions = useMenuActions(actions);
54
55
 
55
56
  return (
56
- <Layout.Main toolbar>
57
- <MenuProvider {...menu} onAction={onAction} alwaysActive>
58
- <ToolbarMenu density='coarse' />
59
- </MenuProvider>
60
- <Surface.Surface role='article' data={data} limit={1} fallback={ContentError} placeholder={placeholder} />
61
- </Layout.Main>
57
+ <Panel.Root>
58
+ <Panel.Toolbar>
59
+ <Menu.Root {...menuActions} alwaysActive onAction={onAction}>
60
+ <Menu.Toolbar />
61
+ </Menu.Root>
62
+ </Panel.Toolbar>
63
+ <Panel.Content>
64
+ <Surface.Surface
65
+ type={AppSurface.Article}
66
+ data={data}
67
+ limit={1}
68
+ fallback={ErrorFallback}
69
+ placeholder={placeholder}
70
+ />
71
+ </Panel.Content>
72
+ </Panel.Root>
62
73
  );
63
74
  };
64
75
 
65
76
  Drawer.displayName = DRAWER_NAME;
66
77
 
67
- /** Parse entry ID to extract primary ID and variant. */
68
- const parseEntryId = (entryId: string) => {
69
- const [id, variant] = entryId.split(ATTENDABLE_PATH_SEPARATOR);
70
- return { id, variant };
71
- };
72
-
73
78
  /**
74
79
  * Resolves which companion to show based on variant preference.
75
80
  * Falls back to first available if preferred variant not available.
@@ -82,10 +87,7 @@ const useSelectedCompanion = (companions: Node.Node[], preferredVariant?: string
82
87
 
83
88
  // Try to find companion matching the preferred variant.
84
89
  if (preferredVariant) {
85
- const preferred = companions.find((c) => {
86
- const { variant } = parseEntryId(c.id);
87
- return variant === preferredVariant;
88
- });
90
+ const preferred = companions.find((c) => getLinkedVariant(c.id) === preferredVariant);
89
91
  if (preferred) {
90
92
  return preferred;
91
93
  }
@@ -96,7 +98,7 @@ const useSelectedCompanion = (companions: Node.Node[], preferredVariant?: string
96
98
  }, [companions, preferredVariant]);
97
99
 
98
100
  const companionId = selectedCompanion?.id;
99
- const { variant } = parseEntryId(companionId ?? '');
101
+ const variant = companionId ? getLinkedVariant(companionId) : undefined;
100
102
 
101
103
  return { selectedCompanion, companionId, variant };
102
104
  };
@@ -5,17 +5,16 @@
5
5
  import React, { useMemo } from 'react';
6
6
 
7
7
  import { Surface } from '@dxos/app-framework/ui';
8
- import { useAppGraph } from '@dxos/app-toolkit/ui';
8
+ import { AppSurface, useAppGraph } from '@dxos/app-toolkit/ui';
9
9
  import { useNode } from '@dxos/plugin-graph';
10
+ import { ErrorFallback, Panel } from '@dxos/react-ui';
10
11
  import { useAttentionAttributes } from '@dxos/react-ui-attention';
11
- import { mx } from '@dxos/ui-theme';
12
12
 
13
- import { useAppBarProps, useNavbarActions, useSimpleLayoutState } from '../../hooks';
14
- import { ContentError } from '../ContentError';
15
- import { ContentLoading } from '../ContentLoading';
16
- import { useLoadDescendents } from '../hooks';
17
- import { useMobileLayout } from '../MobileLayout/MobileLayout';
13
+ import { useAppBarProps, useNavbarActions, useSimpleLayoutState } from '#hooks';
18
14
 
15
+ import { useExpandPath } from '../hooks';
16
+ import { Loading } from '../Loading';
17
+ import { useMobileLayout } from '../MobileLayout';
19
18
  import { AppBar } from './AppBar';
20
19
  import { NavBar } from './NavBar';
21
20
 
@@ -32,7 +31,7 @@ export const Main = () => {
32
31
  const { actions, onAction } = useNavbarActions();
33
32
  const appBarProps = useAppBarProps();
34
33
 
35
- const placeholder = useMemo(() => <ContentLoading />, []);
34
+ const placeholder = useMemo(() => <Loading />, []);
36
35
 
37
36
  const { graph } = useAppGraph();
38
37
  const node = useNode(graph, id);
@@ -47,34 +46,32 @@ export const Main = () => {
47
46
  );
48
47
  }, [id, node, node?.data, node?.properties, state.popoverAnchorId]);
49
48
 
50
- // Ensures that children are loaded so that they are available to navigate to.
51
- useLoadDescendents(id);
49
+ useExpandPath(id);
52
50
 
53
51
  // TODO(burdon): BUG: When showing ANY statusbar the size progressively shrinks when the keyboard opens/closes.
54
52
  const showNavBar = !keyboardOpen && !state.isPopover && state.drawerState === 'closed';
55
53
 
56
54
  return (
57
- <div
58
- role='none'
59
- className={mx(
60
- 'bs-full grid overflow-hidden bg-toolbarSurface',
61
- showNavBar ? 'grid-rows-[var(--rail-action)_1fr_var(--toolbar-size)]' : 'grid-rows-[var(--rail-action)_1fr]',
62
- )}
63
- {...attentionAttrs}
64
- >
65
- <AppBar {...appBarProps} />
66
- <article className='bs-full overflow-hidden bg-baseSurface'>
55
+ <Panel.Root {...attentionAttrs} className='dx-document'>
56
+ <Panel.Toolbar asChild>
57
+ <AppBar {...appBarProps} />
58
+ </Panel.Toolbar>
59
+ <Panel.Content role='article' className='bg-base-surface'>
67
60
  <Surface.Surface
68
61
  key={id}
69
- role='article'
62
+ type={AppSurface.Article}
70
63
  data={data}
71
64
  limit={1}
72
- fallback={ContentError}
65
+ fallback={ErrorFallback}
73
66
  placeholder={placeholder}
74
67
  />
75
- </article>
76
- {showNavBar && <NavBar classNames='border-bs border-subduedSeparator' actions={actions} onAction={onAction} />}
77
- </div>
68
+ </Panel.Content>
69
+ {showNavBar && (
70
+ <Panel.Statusbar asChild>
71
+ <NavBar actions={actions} onAction={onAction} />
72
+ </Panel.Statusbar>
73
+ )}
74
+ </Panel.Root>
78
75
  );
79
76
  };
80
77