@dxos/plugin-simple-layout 0.8.4-main.d05673bc65 → 0.8.4-main.fcc0d83b33

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 (218) hide show
  1. package/dist/lib/browser/index.mjs +15 -68
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/translations.mjs +34 -0
  5. package/dist/lib/browser/translations.mjs.map +7 -0
  6. package/dist/lib/node-esm/index.mjs +15 -67
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/translations.mjs +36 -0
  10. package/dist/lib/node-esm/translations.mjs.map +7 -0
  11. package/dist/types/src/SimpleLayoutPlugin.d.ts +1 -1
  12. package/dist/types/src/SimpleLayoutPlugin.d.ts.map +1 -1
  13. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  14. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  15. package/dist/types/src/capabilities/index.d.ts +21 -6
  16. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  17. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  18. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  19. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  20. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  21. package/dist/types/src/capabilities/{spotlight-dismiss/spotlight-dismiss.d.ts → spotlight-dismiss.d.ts} +1 -1
  22. package/dist/types/src/capabilities/spotlight-dismiss.d.ts.map +1 -0
  23. package/dist/types/src/capabilities/{state/state.d.ts → state.d.ts} +1 -1
  24. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  25. package/dist/types/src/capabilities/{url-handler/url-handler.d.ts → url-handler.d.ts} +1 -1
  26. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
  27. package/dist/types/src/components/ContentError.stories.d.ts +26 -19
  28. package/dist/types/src/components/ContentError.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts +19 -0
  30. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts.map +1 -0
  31. package/dist/types/src/components/DebugOverlay/index.d.ts +2 -0
  32. package/dist/types/src/components/DebugOverlay/index.d.ts.map +1 -0
  33. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  34. package/dist/types/src/components/Home/Home.d.ts.map +1 -1
  35. package/dist/types/src/components/Loading/Loading.d.ts +3 -0
  36. package/dist/types/src/components/Loading/Loading.d.ts.map +1 -0
  37. package/dist/types/src/components/{ContentLoading/ContentLoading.stories.d.ts → Loading/Loading.stories.d.ts} +1 -1
  38. package/dist/types/src/components/Loading/Loading.stories.d.ts.map +1 -0
  39. package/dist/types/src/components/Loading/index.d.ts +2 -0
  40. package/dist/types/src/components/Loading/index.d.ts.map +1 -0
  41. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts +2 -2
  42. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts.map +1 -1
  43. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/NavBranch/NavBranch.d.ts.map +1 -1
  45. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  46. package/dist/types/src/components/SimpleLayout/AppBar.d.ts +5 -7
  47. package/dist/types/src/components/SimpleLayout/AppBar.d.ts.map +1 -1
  48. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts +29 -22
  49. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts.map +1 -1
  50. package/dist/types/src/components/SimpleLayout/Drawer.d.ts +4 -7
  51. package/dist/types/src/components/SimpleLayout/Drawer.d.ts.map +1 -1
  52. package/dist/types/src/components/SimpleLayout/Main.d.ts +4 -7
  53. package/dist/types/src/components/SimpleLayout/Main.d.ts.map +1 -1
  54. package/dist/types/src/components/SimpleLayout/NavBar.d.ts +5 -7
  55. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -1
  56. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts +29 -23
  57. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts.map +1 -1
  58. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts.map +1 -1
  59. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts +26 -25
  60. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts.map +1 -1
  61. package/dist/types/src/components/hooks.d.ts.map +1 -1
  62. package/dist/types/src/components/index.d.ts +2 -1
  63. package/dist/types/src/components/index.d.ts.map +1 -1
  64. package/dist/types/src/hooks/actions.d.ts +2 -2
  65. package/dist/types/src/hooks/actions.d.ts.map +1 -1
  66. package/dist/types/src/hooks/useAppBarProps.d.ts +2 -2
  67. package/dist/types/src/hooks/useAppBarProps.d.ts.map +1 -1
  68. package/dist/types/src/hooks/useCompanions.d.ts.map +1 -1
  69. package/dist/types/src/hooks/useDrawerActions.d.ts.map +1 -1
  70. package/dist/types/src/hooks/useSimpleLayoutState.d.ts +1 -1
  71. package/dist/types/src/hooks/useSimpleLayoutState.d.ts.map +1 -1
  72. package/dist/types/src/operations/close.d.ts +5 -0
  73. package/dist/types/src/operations/close.d.ts.map +1 -0
  74. package/dist/types/src/operations/index.d.ts +3 -0
  75. package/dist/types/src/operations/index.d.ts.map +1 -0
  76. package/dist/types/src/operations/open.d.ts +5 -0
  77. package/dist/types/src/operations/open.d.ts.map +1 -0
  78. package/dist/types/src/operations/revert-workspace.d.ts +5 -0
  79. package/dist/types/src/operations/revert-workspace.d.ts.map +1 -0
  80. package/dist/types/src/operations/set-layout-mode.d.ts +5 -0
  81. package/dist/types/src/operations/set-layout-mode.d.ts.map +1 -0
  82. package/dist/types/src/operations/set.d.ts +5 -0
  83. package/dist/types/src/operations/set.d.ts.map +1 -0
  84. package/dist/types/src/operations/state-access.d.ts +8 -0
  85. package/dist/types/src/operations/state-access.d.ts.map +1 -0
  86. package/dist/types/src/operations/switch-workspace.d.ts +5 -0
  87. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -0
  88. package/dist/types/src/operations/update-complementary.d.ts +5 -0
  89. package/dist/types/src/operations/update-complementary.d.ts.map +1 -0
  90. package/dist/types/src/operations/update-dialog.d.ts +5 -0
  91. package/dist/types/src/operations/update-dialog.d.ts.map +1 -0
  92. package/dist/types/src/operations/update-popover.d.ts +5 -0
  93. package/dist/types/src/operations/update-popover.d.ts.map +1 -0
  94. package/dist/types/src/operations/update-sidebar.d.ts +5 -0
  95. package/dist/types/src/operations/update-sidebar.d.ts.map +1 -0
  96. package/dist/types/src/translations.d.ts +26 -20
  97. package/dist/types/src/translations.d.ts.map +1 -1
  98. package/dist/types/src/types/capabilities.d.ts +10 -2
  99. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  100. package/dist/types/src/types/events.d.ts.map +1 -1
  101. package/dist/types/tsconfig.tsbuildinfo +1 -1
  102. package/package.json +47 -30
  103. package/src/SimpleLayoutPlugin.ts +16 -7
  104. package/src/capabilities/app-graph-builder.ts +21 -0
  105. package/src/capabilities/index.ts +13 -6
  106. package/src/capabilities/operation-handler.ts +14 -0
  107. package/src/capabilities/{react-root/react-root.tsx → react-root.tsx} +2 -2
  108. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +12 -5
  109. package/src/capabilities/{state/state.tsx → state.tsx} +2 -2
  110. package/src/capabilities/url-handler.ts +161 -0
  111. package/src/components/ContentError.stories.tsx +1 -1
  112. package/src/components/DebugOverlay/DebugOverlay.tsx +96 -0
  113. package/src/components/DebugOverlay/index.ts +5 -0
  114. package/src/components/Dialog/Dialog.tsx +14 -3
  115. package/src/components/Home/Home.tsx +29 -29
  116. package/src/components/{ContentLoading/ContentLoading.stories.tsx → Loading/Loading.stories.tsx} +4 -4
  117. package/src/components/{ContentLoading/ContentLoading.tsx → Loading/Loading.tsx} +1 -1
  118. package/src/components/{ContentLoading → Loading}/index.ts +1 -1
  119. package/src/components/MobileLayout/MobileLayout.stories.tsx +21 -17
  120. package/src/components/MobileLayout/MobileLayout.tsx +118 -49
  121. package/src/components/NavBranch/NavBranch.tsx +26 -32
  122. package/src/components/Popover/Popover.tsx +10 -16
  123. package/src/components/SimpleLayout/AppBar.stories.tsx +10 -10
  124. package/src/components/SimpleLayout/AppBar.tsx +60 -60
  125. package/src/components/SimpleLayout/Drawer.tsx +30 -22
  126. package/src/components/SimpleLayout/Main.tsx +19 -23
  127. package/src/components/SimpleLayout/NavBar.stories.tsx +2 -2
  128. package/src/components/SimpleLayout/NavBar.tsx +8 -9
  129. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +44 -67
  130. package/src/components/SimpleLayout/SimpleLayout.tsx +33 -34
  131. package/src/components/hooks.ts +1 -1
  132. package/src/components/index.ts +2 -1
  133. package/src/hooks/actions.ts +4 -3
  134. package/src/hooks/useAppBarProps.ts +8 -28
  135. package/src/hooks/useDrawerActions.ts +6 -6
  136. package/src/hooks/useNavbarActions.ts +3 -3
  137. package/src/hooks/useSimpleLayoutState.ts +1 -1
  138. package/src/operations/close.ts +34 -0
  139. package/src/operations/index.ts +16 -0
  140. package/src/operations/open.ts +63 -0
  141. package/src/operations/revert-workspace.ts +22 -0
  142. package/src/operations/set-layout-mode.ts +12 -0
  143. package/src/operations/set.ts +23 -0
  144. package/src/operations/state-access.ts +19 -0
  145. package/src/operations/switch-workspace.ts +26 -0
  146. package/src/operations/update-complementary.ts +35 -0
  147. package/src/operations/update-dialog.ts +28 -0
  148. package/src/operations/update-popover.ts +35 -0
  149. package/src/operations/update-sidebar.ts +12 -0
  150. package/src/translations.ts +21 -19
  151. package/src/types/capabilities.ts +3 -3
  152. package/dist/lib/browser/chunk-MDPEKLKR.mjs +0 -1163
  153. package/dist/lib/browser/chunk-MDPEKLKR.mjs.map +0 -7
  154. package/dist/lib/browser/chunk-MRR7PXSM.mjs +0 -29
  155. package/dist/lib/browser/chunk-MRR7PXSM.mjs.map +0 -7
  156. package/dist/lib/browser/operation-resolver-VTZ6HZ4B.mjs +0 -194
  157. package/dist/lib/browser/operation-resolver-VTZ6HZ4B.mjs.map +0 -7
  158. package/dist/lib/browser/react-root-WVQYY2JA.mjs +0 -21
  159. package/dist/lib/browser/react-root-WVQYY2JA.mjs.map +0 -7
  160. package/dist/lib/browser/react-surface-VLBR37ED.mjs +0 -44
  161. package/dist/lib/browser/react-surface-VLBR37ED.mjs.map +0 -7
  162. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs +0 -66
  163. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs.map +0 -7
  164. package/dist/lib/browser/state-TXSMUWYI.mjs +0 -48
  165. package/dist/lib/browser/state-TXSMUWYI.mjs.map +0 -7
  166. package/dist/lib/browser/url-handler-RBRONH7S.mjs +0 -151
  167. package/dist/lib/browser/url-handler-RBRONH7S.mjs.map +0 -7
  168. package/dist/lib/node-esm/chunk-DCKASLMP.mjs +0 -1164
  169. package/dist/lib/node-esm/chunk-DCKASLMP.mjs.map +0 -7
  170. package/dist/lib/node-esm/chunk-WMNTJ2MK.mjs +0 -31
  171. package/dist/lib/node-esm/chunk-WMNTJ2MK.mjs.map +0 -7
  172. package/dist/lib/node-esm/operation-resolver-R7CQ6ERU.mjs +0 -195
  173. package/dist/lib/node-esm/operation-resolver-R7CQ6ERU.mjs.map +0 -7
  174. package/dist/lib/node-esm/react-root-XBNDM7BE.mjs +0 -22
  175. package/dist/lib/node-esm/react-root-XBNDM7BE.mjs.map +0 -7
  176. package/dist/lib/node-esm/react-surface-U5NHA367.mjs +0 -45
  177. package/dist/lib/node-esm/react-surface-U5NHA367.mjs.map +0 -7
  178. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs +0 -68
  179. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs.map +0 -7
  180. package/dist/lib/node-esm/state-JMX6FAG4.mjs +0 -49
  181. package/dist/lib/node-esm/state-JMX6FAG4.mjs.map +0 -7
  182. package/dist/lib/node-esm/url-handler-QSMCH3JB.mjs +0 -152
  183. package/dist/lib/node-esm/url-handler-QSMCH3JB.mjs.map +0 -7
  184. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  185. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  186. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  187. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  188. package/dist/types/src/capabilities/react-root/index.d.ts +0 -6
  189. package/dist/types/src/capabilities/react-root/index.d.ts.map +0 -1
  190. package/dist/types/src/capabilities/react-root/react-root.d.ts.map +0 -1
  191. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  192. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  193. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  194. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts +0 -3
  195. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts.map +0 -1
  196. package/dist/types/src/capabilities/spotlight-dismiss/spotlight-dismiss.d.ts.map +0 -1
  197. package/dist/types/src/capabilities/state/index.d.ts +0 -13
  198. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  199. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  200. package/dist/types/src/capabilities/url-handler/index.d.ts +0 -3
  201. package/dist/types/src/capabilities/url-handler/index.d.ts.map +0 -1
  202. package/dist/types/src/capabilities/url-handler/url-handler.d.ts.map +0 -1
  203. package/dist/types/src/components/ContentLoading/ContentLoading.d.ts +0 -3
  204. package/dist/types/src/components/ContentLoading/ContentLoading.d.ts.map +0 -1
  205. package/dist/types/src/components/ContentLoading/ContentLoading.stories.d.ts.map +0 -1
  206. package/dist/types/src/components/ContentLoading/index.d.ts +0 -2
  207. package/dist/types/src/components/ContentLoading/index.d.ts.map +0 -1
  208. package/src/capabilities/operation-resolver/index.ts +0 -10
  209. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -202
  210. package/src/capabilities/react-root/index.ts +0 -7
  211. package/src/capabilities/react-surface/index.ts +0 -7
  212. package/src/capabilities/spotlight-dismiss/index.ts +0 -7
  213. package/src/capabilities/state/index.ts +0 -9
  214. package/src/capabilities/url-handler/index.ts +0 -7
  215. package/src/capabilities/url-handler/url-handler.ts +0 -133
  216. /package/dist/types/src/capabilities/{react-root/react-root.d.ts → react-root.d.ts} +0 -0
  217. /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
  218. /package/src/capabilities/{spotlight-dismiss/spotlight-dismiss.ts → spotlight-dismiss.ts} +0 -0
@@ -2,58 +2,57 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { useEffect, useRef, useState } from 'react';
5
+ import React, { useLayoutEffect, useRef, useState } from 'react';
6
6
 
7
7
  import { Splitter, type SplitterMode } from '@dxos/react-ui';
8
8
  import { Mosaic } from '@dxos/react-ui-mosaic';
9
9
 
10
- import { useSimpleLayoutState } from '../../hooks';
10
+ import { useSimpleLayoutState } from '#hooks';
11
+
12
+ import { DebugOverlay } from '../DebugOverlay';
11
13
  import { Dialog } from '../Dialog';
12
14
  import { MobileLayout } from '../MobileLayout';
13
15
  import { PopoverContent, PopoverRoot } from '../Popover';
14
-
15
16
  import { Drawer } from './Drawer';
16
17
  import { Main } from './Main';
17
18
 
18
- // TODO(burdon): Mobile/Desktop variance?
19
19
  export const SimpleLayout = () => {
20
20
  const { state } = useSimpleLayoutState();
21
21
  const [keyboardOpen, setKeyboardOpen] = useState(false);
22
- const [splitterMode, setSplitterMode] = useState<SplitterMode>('upper');
22
+ const [splitterMode, setSplitterMode] = useState<SplitterMode>('top');
23
23
 
24
24
  const drawerRef = useRef<HTMLDivElement>(null);
25
- useEffect(() => {
26
- if (keyboardOpen) {
27
- // Determine which panel has focus and expand that one.
28
- const activeElement = document.activeElement;
29
- const drawerHasFocus = drawerRef.current?.contains(activeElement);
30
- setSplitterMode(drawerHasFocus ? 'lower' : 'upper');
31
- } else {
32
- setSplitterMode(state.drawerState === 'closed' ? 'upper' : state.drawerState === 'open' ? 'both' : 'lower');
25
+
26
+ // Restore Splitter mode when keyboard closes.
27
+ useLayoutEffect(() => {
28
+ if (!keyboardOpen) {
29
+ setSplitterMode(state.drawerState === 'closed' ? 'top' : state.drawerState === 'open' ? 'split' : 'bottom');
33
30
  }
34
31
  }, [state.drawerState, keyboardOpen]);
35
32
 
36
33
  return (
37
- <Mosaic.Root classNames='contents'>
38
- <MobileLayout.Root
39
- classNames='bg-toolbar-surface'
40
- onKeyboardOpenChange={(keyboardOpen: boolean) => setKeyboardOpen(keyboardOpen)}
41
- >
42
- <MobileLayout.Panel safe={{ top: true, bottom: splitterMode === 'upper' }}>
43
- <PopoverRoot>
44
- <Splitter.Root mode={splitterMode} ratio={0.55}>
45
- <Splitter.Panel position='upper'>
46
- <Main />
47
- </Splitter.Panel>
48
- <Splitter.Panel position='lower' ref={drawerRef}>
49
- <Drawer />
50
- </Splitter.Panel>
51
- </Splitter.Root>
52
- <Dialog />
53
- <PopoverContent />
54
- </PopoverRoot>
55
- </MobileLayout.Panel>
56
- </MobileLayout.Root>
57
- </Mosaic.Root>
34
+ <DebugOverlay.Root enabled={false}>
35
+ <PopoverRoot>
36
+ <Mosaic.Root>
37
+ <MobileLayout.Root
38
+ classNames='dx-container grid relative bg-toolbar-surface'
39
+ onKeyboardOpenChange={(nextKeyboardOpen) => setKeyboardOpen(nextKeyboardOpen)}
40
+ >
41
+ <MobileLayout.Panel safe={{ top: true, bottom: splitterMode === 'top' }}>
42
+ <Splitter.Root mode={splitterMode} ratio={0.55}>
43
+ <Splitter.Panel position='top'>
44
+ <Main />
45
+ </Splitter.Panel>
46
+ <Splitter.Panel position='bottom' ref={drawerRef}>
47
+ <Drawer />
48
+ </Splitter.Panel>
49
+ </Splitter.Root>
50
+ <Dialog />
51
+ <PopoverContent />
52
+ </MobileLayout.Panel>
53
+ </MobileLayout.Root>
54
+ </Mosaic.Root>
55
+ </PopoverRoot>
56
+ </DebugOverlay.Root>
58
57
  );
59
58
  };
@@ -4,9 +4,9 @@
4
4
 
5
5
  import { useEffect } from 'react';
6
6
 
7
- import { expandAttendableId } from '@dxos/react-ui-attention';
8
7
  import { useAppGraph } from '@dxos/app-toolkit/ui';
9
8
  import { Graph } from '@dxos/plugin-graph';
9
+ import { expandAttendableId } from '@dxos/react-ui-attention';
10
10
 
11
11
  /**
12
12
  * Expand graph nodes along the full path from root to the given node ID.
@@ -2,8 +2,9 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './ContentLoading';
5
+ export * from './DebugOverlay';
6
6
  export * from './Home';
7
+ export * from './Loading';
7
8
  export * from './MobileLayout';
8
9
  export * from './Popover';
9
10
  export * from './SimpleLayout';
@@ -5,12 +5,13 @@
5
5
  import { type Atom } from '@effect-atom/atom-react';
6
6
  import * as Effect from 'effect/Effect';
7
7
 
8
- import { type AppCapabilities, getCompanionVariant } from '@dxos/app-toolkit';
8
+ import { type AppCapabilities } from '@dxos/app-toolkit';
9
9
  import { Node } from '@dxos/plugin-graph';
10
+ import { getLinkedVariant } from '@dxos/react-ui-attention';
10
11
  import { type ActionGraphProps } from '@dxos/react-ui-menu';
11
12
  import { byPosition } from '@dxos/util';
12
13
 
13
- import { type SimpleLayoutState } from '../types';
14
+ import { type SimpleLayoutState } from '#types';
14
15
 
15
16
  // TODO(wittjosiah): Factor out to shared location with plugin-deck.
16
17
  export const PLANK_COMPANION_TYPE = 'org.dxos.plugin.deck.plank-companion';
@@ -51,7 +52,7 @@ export const createCompanionActions = (
51
52
  const edges: ActionGraphProps['edges'] = [];
52
53
 
53
54
  companions.forEach((companion: Node.Node) => {
54
- const companionVariant = getCompanionVariant(companion.id);
55
+ const companionVariant = getLinkedVariant(companion.id);
55
56
  const companionAction = {
56
57
  id: `${idPrefix}-companion-${companion.id}`,
57
58
  type: Node.ActionType,
@@ -3,7 +3,6 @@
3
3
  //
4
4
 
5
5
  import { Atom, useAtomValue } from '@effect-atom/atom-react';
6
- import * as Effect from 'effect/Effect';
7
6
  import * as Option from 'effect/Option';
8
7
  import { useCallback, useMemo } from 'react';
9
8
 
@@ -14,9 +13,9 @@ import { Graph, Node, useActionRunner, useNode } from '@dxos/plugin-graph';
14
13
  import { toLocalizedString, useTranslation } from '@dxos/react-ui';
15
14
  import { type ActionGraphProps } from '@dxos/react-ui-menu';
16
15
 
17
- import { type AppBarProps } from '../components';
18
- import { meta } from '../meta';
19
- import { SimpleLayoutState as SimpleLayoutStateCapability } from '../types';
16
+ import { type AppBarProps } from '#components';
17
+ import { meta } from '#meta';
18
+ import { SimpleLayoutState as SimpleLayoutStateCapability } from '#types';
20
19
 
21
20
  /**
22
21
  * Hook that computes all AppBar props from the app graph.
@@ -27,7 +26,7 @@ export const useAppBarProps = (): Omit<AppBarProps, 'classNames'> => {
27
26
  const stateAtom = useCapability(SimpleLayoutStateCapability);
28
27
  const state = useAtomValue(stateAtom);
29
28
  const { graph } = useAppGraph();
30
- const { invokeSync } = useOperationInvoker();
29
+ const { invokePromise } = useOperationInvoker();
31
30
  const runAction = useActionRunner();
32
31
 
33
32
  // Derive activeId from state.
@@ -55,25 +54,6 @@ export const useAppBarProps = (): Omit<AppBarProps, 'classNames'> => {
55
54
  relation: 'child',
56
55
  }));
57
56
 
58
- // Add alternate-tree action (e.g. Settings) from the workspace node.
59
- const workspaceConnections = state.workspace ? get(graph.connections(state.workspace, 'child')) : [];
60
- const alternateTreeNode = workspaceConnections.find(
61
- (node: Node.Node) => node.properties.disposition === 'alternate-tree',
62
- );
63
- if (alternateTreeNode && activeId !== alternateTreeNode.id) {
64
- const settingsAction = {
65
- id: `appbar-settings-${alternateTreeNode.id}`,
66
- type: Node.ActionType,
67
- data: () => Effect.sync(() => invokeSync(LayoutOperation.Open, { subject: [alternateTreeNode.id] })),
68
- properties: {
69
- label: alternateTreeNode.properties.label ?? alternateTreeNode.id,
70
- icon: alternateTreeNode.properties.icon ?? 'ph--placeholder--regular',
71
- },
72
- };
73
- nodes.push(settingsAction);
74
- edges.push({ source: 'root', target: settingsAction.id, relation: 'child' });
75
- }
76
-
77
57
  return { nodes, edges };
78
58
  }),
79
59
  [graph, stateAtom],
@@ -91,15 +71,15 @@ export const useAppBarProps = (): Omit<AppBarProps, 'classNames'> => {
91
71
 
92
72
  // If history is empty and this is a workspace, go to home.
93
73
  if (state.history.length === 0 && isWorkspace) {
94
- invokeSync(LayoutOperation.SwitchWorkspace, { subject: Node.RootId });
74
+ void invokePromise(LayoutOperation.SwitchWorkspace, { subject: Node.RootId });
95
75
  } else {
96
76
  // Otherwise, close (which will pop from history or clear active).
97
- invokeSync(LayoutOperation.Close, { subject: [state.active] });
77
+ void invokePromise(LayoutOperation.Close, { subject: [state.active] });
98
78
  }
99
79
  } else {
100
- invokeSync(LayoutOperation.SwitchWorkspace, { subject: Node.RootId });
80
+ void invokePromise(LayoutOperation.SwitchWorkspace, { subject: Node.RootId });
101
81
  }
102
- }, [graph, invokeSync, state.active, state.history.length]);
82
+ }, [graph, invokePromise, state.active, state.history.length]);
103
83
 
104
84
  // Compute popover anchor ID.
105
85
  const popoverAnchorId = node && state.popoverAnchorId === `${meta.id}:${node.id}` ? state.popoverAnchorId : undefined;
@@ -12,9 +12,9 @@ import { Node, useActionRunner } from '@dxos/plugin-graph';
12
12
  import { useTranslation } from '@dxos/react-ui';
13
13
  import { type ActionExecutor, type ActionGraphProps, createGapSeparator } from '@dxos/react-ui-menu';
14
14
 
15
- import { useMobileLayout } from '../components';
16
- import { meta } from '../meta';
17
- import { SimpleLayoutState as SimpleLayoutStateCapability } from '../types';
15
+ import { useMobileLayout } from '#components';
16
+ import { meta } from '#meta';
17
+ import { SimpleLayoutState as SimpleLayoutStateCapability } from '#types';
18
18
 
19
19
  import { createCompanionActions } from './actions';
20
20
  import { useSimpleLayoutState } from './useSimpleLayoutState';
@@ -47,7 +47,7 @@ export const useDrawerActions = (consumerName: string): DrawerActions => {
47
47
  // Add companion tab actions.
48
48
  const { nodes, edges } = createCompanionActions(graph, stateAtom, get, {
49
49
  idPrefix: 'drawer',
50
- selectedVariant: state.companionVariant,
50
+ selectedVariant: state.drawerState !== 'closed' ? state.companionVariant : undefined,
51
51
  updateState,
52
52
  });
53
53
 
@@ -64,7 +64,7 @@ export const useDrawerActions = (consumerName: string): DrawerActions => {
64
64
  type: Node.ActionType,
65
65
  properties: {
66
66
  icon: isExpanded ? 'ph--arrow-down--regular' : 'ph--arrow-up--regular',
67
- label: isExpanded ? t('collapse drawer label') : t('expand drawer label'),
67
+ label: isExpanded ? t('collapse-drawer.label') : t('expand-drawer.label'),
68
68
  iconOnly: true,
69
69
  },
70
70
  data: () =>
@@ -80,7 +80,7 @@ export const useDrawerActions = (consumerName: string): DrawerActions => {
80
80
  type: Node.ActionType,
81
81
  properties: {
82
82
  icon: 'ph--x--regular',
83
- label: t('close drawer label'),
83
+ label: t('close-drawer.label'),
84
84
  iconOnly: true,
85
85
  },
86
86
  data: () =>
@@ -16,8 +16,8 @@ import {
16
16
  createMenuItemGroup,
17
17
  } from '@dxos/react-ui-menu';
18
18
 
19
- import { meta } from '../meta';
20
- import { SimpleLayoutState } from '../types';
19
+ import { meta } from '#meta';
20
+ import { SimpleLayoutState } from '#types';
21
21
 
22
22
  import { createCompanionActions } from './actions';
23
23
  import { useSimpleLayoutState } from './useSimpleLayoutState';
@@ -62,7 +62,7 @@ export const useNavbarActions = (): NavbarActions => {
62
62
  variant: 'dropdownMenu',
63
63
  icon: 'ph--list--regular',
64
64
  iconOnly: true,
65
- label: t('main menu label'),
65
+ label: t('main-menu.label'),
66
66
  testId: 'simpleLayoutPlugin.addSpace',
67
67
  });
68
68
  nodes.push(mainMenuGroup);
@@ -7,7 +7,7 @@ import { useCallback, useContext } from 'react';
7
7
 
8
8
  import { useCapability } from '@dxos/app-framework/ui';
9
9
 
10
- import { SimpleLayoutState } from '../types';
10
+ import { SimpleLayoutState } from '#types';
11
11
 
12
12
  export type UseSimpleLayoutState = {
13
13
  state: SimpleLayoutState;
@@ -0,0 +1,34 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ import { layoutStateAccess } from './state-access';
9
+
10
+ const handler: Operation.WithHandler<typeof LayoutOperation.Close> = LayoutOperation.Close.pipe(
11
+ Operation.withHandler(
12
+ Effect.fnUntraced(function* () {
13
+ const { updateState } = yield* layoutStateAccess;
14
+
15
+ updateState((state) => {
16
+ if (state.history.length > 0) {
17
+ const newHistory = [...state.history];
18
+ const previousActive = newHistory.pop();
19
+ return {
20
+ ...state,
21
+ active: previousActive,
22
+ history: newHistory,
23
+ };
24
+ }
25
+ return {
26
+ ...state,
27
+ active: undefined,
28
+ };
29
+ });
30
+ }),
31
+ ),
32
+ );
33
+
34
+ export default handler;
@@ -0,0 +1,16 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import { OperationHandlerSet } from '@dxos/compute';
4
+
5
+ export const SimpleLayoutOperationHandlerSet = OperationHandlerSet.lazy(
6
+ () => import('./close'),
7
+ () => import('./open'),
8
+ () => import('./revert-workspace'),
9
+ () => import('./set'),
10
+ () => import('./set-layout-mode'),
11
+ () => import('./switch-workspace'),
12
+ () => import('./update-complementary'),
13
+ () => import('./update-dialog'),
14
+ () => import('./update-popover'),
15
+ () => import('./update-sidebar'),
16
+ );
@@ -0,0 +1,63 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { Capability } from '@dxos/app-framework';
6
+ import {
7
+ AppCapabilities,
8
+ LayoutOperation,
9
+ createEdgeExistenceChecker,
10
+ validateNavigationTarget,
11
+ } from '@dxos/app-toolkit';
12
+ import { Operation } from '@dxos/compute';
13
+ import { Context } from '@dxos/context';
14
+ import { ClientCapabilities } from '@dxos/plugin-client/types';
15
+
16
+ import { layoutStateAccess } from './state-access';
17
+
18
+ const handler: Operation.WithHandler<typeof LayoutOperation.Open> = LayoutOperation.Open.pipe(
19
+ Operation.withHandler(
20
+ Effect.fnUntraced(function* (input) {
21
+ const { graph } = yield* Capability.get(AppCapabilities.AppGraph);
22
+ const { updateState } = yield* layoutStateAccess;
23
+ const id = input.subject[0];
24
+
25
+ // Validate navigation target, redirecting to 404 if not found.
26
+ const capabilities = yield* Capability.Service;
27
+ const pathResolvers = capabilities.getAll(AppCapabilities.NavigationPathResolver);
28
+ const checkRemoteExistence = yield* Capability.get(ClientCapabilities.Client).pipe(
29
+ Effect.map((client) =>
30
+ createEdgeExistenceChecker((spaceId, body) => client.edge.http.execQuery(new Context(), spaceId, body)),
31
+ ),
32
+ Effect.catchAll(() => Effect.succeed(undefined)),
33
+ );
34
+
35
+ const validatedId =
36
+ input.navigation === 'immediate'
37
+ ? id
38
+ : yield* validateNavigationTarget({
39
+ graph,
40
+ subjectId: id,
41
+ pathResolvers,
42
+ checkRemoteExistence,
43
+ });
44
+
45
+ updateState((state) => {
46
+ const newHistory = state.active ? [...state.history, state.active] : state.history;
47
+ const trimmedHistory =
48
+ newHistory.length > MAX_HISTORY_LENGTH ? newHistory.slice(-MAX_HISTORY_LENGTH) : newHistory;
49
+ return {
50
+ ...state,
51
+ active: validatedId,
52
+ history: trimmedHistory,
53
+ };
54
+ });
55
+
56
+ return [validatedId];
57
+ }),
58
+ ),
59
+ );
60
+
61
+ export default handler;
62
+
63
+ const MAX_HISTORY_LENGTH = 50;
@@ -0,0 +1,22 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ import { layoutStateAccess } from './state-access';
9
+
10
+ const handler: Operation.WithHandler<typeof LayoutOperation.RevertWorkspace> = LayoutOperation.RevertWorkspace.pipe(
11
+ Operation.withHandler(
12
+ Effect.fnUntraced(function* () {
13
+ const { getState } = yield* layoutStateAccess;
14
+ const state = getState();
15
+ yield* Operation.invoke(LayoutOperation.SwitchWorkspace, {
16
+ subject: state.previousWorkspace,
17
+ });
18
+ }),
19
+ ),
20
+ );
21
+
22
+ export default handler;
@@ -0,0 +1,12 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ const handler: Operation.WithHandler<typeof LayoutOperation.SetLayoutMode> = LayoutOperation.SetLayoutMode.pipe(
9
+ Operation.withHandler(Effect.fnUntraced(function* () {})),
10
+ );
11
+
12
+ export default handler;
@@ -0,0 +1,23 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ import { layoutStateAccess } from './state-access';
9
+
10
+ const handler: Operation.WithHandler<typeof LayoutOperation.Set> = LayoutOperation.Set.pipe(
11
+ Operation.withHandler(
12
+ Effect.fnUntraced(function* (input) {
13
+ const { updateState } = yield* layoutStateAccess;
14
+
15
+ updateState((state) => ({
16
+ ...state,
17
+ active: input.subject[0],
18
+ }));
19
+ }),
20
+ ),
21
+ );
22
+
23
+ export default handler;
@@ -0,0 +1,19 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { Capabilities, Capability } from '@dxos/app-framework';
6
+
7
+ import { type SimpleLayoutState, SimpleLayoutState as SimpleLayoutStateCapability } from '../types';
8
+
9
+ export const layoutStateAccess = Effect.gen(function* () {
10
+ const registry = yield* Capability.get(Capabilities.AtomRegistry);
11
+ const stateAtom = yield* Capability.get(SimpleLayoutStateCapability);
12
+
13
+ return {
14
+ getState: () => registry.get(stateAtom),
15
+ updateState: (fn: (current: SimpleLayoutState) => SimpleLayoutState) => {
16
+ registry.set(stateAtom, fn(registry.get(stateAtom)));
17
+ },
18
+ };
19
+ });
@@ -0,0 +1,26 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { isPinnedWorkspace, LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ import { layoutStateAccess } from './state-access';
9
+
10
+ const handler: Operation.WithHandler<typeof LayoutOperation.SwitchWorkspace> = LayoutOperation.SwitchWorkspace.pipe(
11
+ Operation.withHandler(
12
+ Effect.fnUntraced(function* (input) {
13
+ const { updateState } = yield* layoutStateAccess;
14
+
15
+ updateState((state) => ({
16
+ ...state,
17
+ previousWorkspace: !isPinnedWorkspace(state.workspace) ? state.workspace : state.previousWorkspace,
18
+ workspace: input.subject,
19
+ active: undefined,
20
+ history: [],
21
+ }));
22
+ }),
23
+ ),
24
+ );
25
+
26
+ export default handler;
@@ -0,0 +1,35 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+ import { getLinkedVariant } from '@dxos/react-ui-attention';
8
+
9
+ import { layoutStateAccess } from './state-access';
10
+
11
+ const handler: Operation.WithHandler<typeof LayoutOperation.UpdateComplementary> =
12
+ LayoutOperation.UpdateComplementary.pipe(
13
+ Operation.withHandler(
14
+ Effect.fnUntraced(function* (input) {
15
+ const { updateState } = yield* layoutStateAccess;
16
+
17
+ if (input.state === 'closed') {
18
+ updateState((state) => ({
19
+ ...state,
20
+ drawerState: 'closed',
21
+ companionVariant: undefined,
22
+ }));
23
+ } else if (input.subject) {
24
+ const variant = getLinkedVariant(input.subject);
25
+ updateState((state) => ({
26
+ ...state,
27
+ companionVariant: variant,
28
+ drawerState: input.state === 'expanded' ? 'expanded' : 'open',
29
+ }));
30
+ }
31
+ }),
32
+ ),
33
+ );
34
+
35
+ export default handler;
@@ -0,0 +1,28 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ import { layoutStateAccess } from './state-access';
9
+
10
+ const handler: Operation.WithHandler<typeof LayoutOperation.UpdateDialog> = LayoutOperation.UpdateDialog.pipe(
11
+ Operation.withHandler(
12
+ Effect.fnUntraced(function* (input) {
13
+ const { updateState } = yield* layoutStateAccess;
14
+
15
+ updateState((state) => ({
16
+ ...state,
17
+ dialogOpen: input.state ?? Boolean(input.subject),
18
+ dialogType: input.type ?? 'default',
19
+ dialogBlockAlign: input.blockAlign ?? 'center',
20
+ dialogOverlayClasses: input.overlayClasses,
21
+ dialogOverlayStyle: input.overlayStyle,
22
+ dialogContent: input.subject ? { component: input.subject, props: input.props } : undefined,
23
+ }));
24
+ }),
25
+ ),
26
+ );
27
+
28
+ export default handler;
@@ -0,0 +1,35 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ import { layoutStateAccess } from './state-access';
9
+
10
+ const handler: Operation.WithHandler<typeof LayoutOperation.UpdatePopover> = LayoutOperation.UpdatePopover.pipe(
11
+ Operation.withHandler(
12
+ Effect.fnUntraced(function* (input) {
13
+ const { updateState } = yield* layoutStateAccess;
14
+
15
+ updateState((state) => ({
16
+ ...state,
17
+ popoverOpen: input.state ?? Boolean(input.subject),
18
+ popoverKind: input.kind ?? 'base',
19
+ popoverTitle: input.kind === 'card' ? input.title : undefined,
20
+ popoverContent:
21
+ typeof input.subject === 'string'
22
+ ? { component: input.subject, props: input.props }
23
+ : input.subject
24
+ ? { subject: input.subject }
25
+ : undefined,
26
+ popoverSide: input.side,
27
+ popoverVariant: input.variant,
28
+ popoverAnchor: input.variant === 'virtual' ? input.anchor : state.popoverAnchor,
29
+ popoverAnchorId: input.variant !== 'virtual' ? input.anchorId : state.popoverAnchorId,
30
+ }));
31
+ }),
32
+ ),
33
+ );
34
+
35
+ export default handler;
@@ -0,0 +1,12 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { LayoutOperation } from '@dxos/app-toolkit';
6
+ import { Operation } from '@dxos/compute';
7
+
8
+ const handler: Operation.WithHandler<typeof LayoutOperation.UpdateSidebar> = LayoutOperation.UpdateSidebar.pipe(
9
+ Operation.withHandler(() => Effect.void),
10
+ );
11
+
12
+ export default handler;