@dxos/plugin-simple-layout 0.8.4-main.6fa680abb7 → 0.8.4-main.74a063c4e0

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 (205) hide show
  1. package/dist/lib/browser/index.mjs +34 -55
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +34 -54
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/SimpleLayoutPlugin.d.ts +1 -1
  8. package/dist/types/src/SimpleLayoutPlugin.d.ts.map +1 -1
  9. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  10. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  11. package/dist/types/src/capabilities/index.d.ts +21 -6
  12. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  13. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  14. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  15. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  16. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  17. package/dist/types/src/capabilities/spotlight-dismiss.d.ts.map +1 -0
  18. package/dist/types/src/capabilities/{state/state.d.ts → state.d.ts} +1 -1
  19. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  20. package/dist/types/src/capabilities/{url-handler/url-handler.d.ts → url-handler.d.ts} +1 -1
  21. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
  22. package/dist/types/src/components/ContentError.stories.d.ts +25 -18
  23. package/dist/types/src/components/ContentError.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts +19 -0
  25. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts.map +1 -0
  26. package/dist/types/src/components/DebugOverlay/index.d.ts +2 -0
  27. package/dist/types/src/components/DebugOverlay/index.d.ts.map +1 -0
  28. package/dist/types/src/components/Home/Home.d.ts.map +1 -1
  29. package/dist/types/src/components/Loading/Loading.d.ts +3 -0
  30. package/dist/types/src/components/Loading/Loading.d.ts.map +1 -0
  31. package/dist/types/src/components/{ContentLoading/ContentLoading.stories.d.ts → Loading/Loading.stories.d.ts} +1 -1
  32. package/dist/types/src/components/Loading/Loading.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/Loading/index.d.ts +2 -0
  34. package/dist/types/src/components/Loading/index.d.ts.map +1 -0
  35. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts.map +1 -1
  36. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/NavBranch/NavBranch.d.ts.map +1 -1
  38. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  39. package/dist/types/src/components/SimpleLayout/AppBar.d.ts +9 -7
  40. package/dist/types/src/components/SimpleLayout/AppBar.d.ts.map +1 -1
  41. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts +28 -21
  42. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts.map +1 -1
  43. package/dist/types/src/components/SimpleLayout/Drawer.d.ts.map +1 -1
  44. package/dist/types/src/components/SimpleLayout/Main.d.ts.map +1 -1
  45. package/dist/types/src/components/SimpleLayout/NavBar.d.ts +9 -7
  46. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -1
  47. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts +32 -22
  48. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts.map +1 -1
  49. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts.map +1 -1
  50. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts +26 -25
  51. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/index.d.ts +2 -1
  53. package/dist/types/src/components/index.d.ts.map +1 -1
  54. package/dist/types/src/hooks/actions.d.ts +1 -1
  55. package/dist/types/src/hooks/actions.d.ts.map +1 -1
  56. package/dist/types/src/hooks/useAppBarProps.d.ts +1 -1
  57. package/dist/types/src/hooks/useAppBarProps.d.ts.map +1 -1
  58. package/dist/types/src/hooks/useSimpleLayoutState.d.ts +1 -1
  59. package/dist/types/src/hooks/useSimpleLayoutState.d.ts.map +1 -1
  60. package/dist/types/src/operations/close.d.ts +5 -0
  61. package/dist/types/src/operations/close.d.ts.map +1 -0
  62. package/dist/types/src/operations/index.d.ts +3 -0
  63. package/dist/types/src/operations/index.d.ts.map +1 -0
  64. package/dist/types/src/operations/open.d.ts +5 -0
  65. package/dist/types/src/operations/open.d.ts.map +1 -0
  66. package/dist/types/src/operations/revert-workspace.d.ts +5 -0
  67. package/dist/types/src/operations/revert-workspace.d.ts.map +1 -0
  68. package/dist/types/src/operations/set-layout-mode.d.ts +5 -0
  69. package/dist/types/src/operations/set-layout-mode.d.ts.map +1 -0
  70. package/dist/types/src/operations/set.d.ts +5 -0
  71. package/dist/types/src/operations/set.d.ts.map +1 -0
  72. package/dist/types/src/operations/state-access.d.ts +8 -0
  73. package/dist/types/src/operations/state-access.d.ts.map +1 -0
  74. package/dist/types/src/operations/switch-workspace.d.ts +5 -0
  75. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -0
  76. package/dist/types/src/operations/update-complementary.d.ts +5 -0
  77. package/dist/types/src/operations/update-complementary.d.ts.map +1 -0
  78. package/dist/types/src/operations/update-dialog.d.ts +5 -0
  79. package/dist/types/src/operations/update-dialog.d.ts.map +1 -0
  80. package/dist/types/src/operations/update-popover.d.ts +5 -0
  81. package/dist/types/src/operations/update-popover.d.ts.map +1 -0
  82. package/dist/types/src/operations/update-sidebar.d.ts +5 -0
  83. package/dist/types/src/operations/update-sidebar.d.ts.map +1 -0
  84. package/dist/types/src/translations.d.ts +26 -19
  85. package/dist/types/src/translations.d.ts.map +1 -1
  86. package/dist/types/src/types/capabilities.d.ts +10 -2
  87. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  88. package/dist/types/tsconfig.tsbuildinfo +1 -1
  89. package/package.json +39 -29
  90. package/src/SimpleLayoutPlugin.ts +15 -5
  91. package/src/capabilities/app-graph-builder.ts +21 -0
  92. package/src/capabilities/index.ts +13 -6
  93. package/src/capabilities/operation-handler.ts +14 -0
  94. package/src/capabilities/{react-root/react-root.tsx → react-root.tsx} +2 -2
  95. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +11 -4
  96. package/src/capabilities/{state/state.tsx → state.tsx} +2 -2
  97. package/src/capabilities/url-handler.ts +161 -0
  98. package/src/components/DebugOverlay/DebugOverlay.tsx +96 -0
  99. package/src/components/DebugOverlay/index.ts +5 -0
  100. package/src/components/Dialog/Dialog.tsx +3 -3
  101. package/src/components/Home/Home.tsx +29 -29
  102. package/src/components/{ContentLoading/ContentLoading.stories.tsx → Loading/Loading.stories.tsx} +4 -4
  103. package/src/components/{ContentLoading/ContentLoading.tsx → Loading/Loading.tsx} +1 -1
  104. package/src/components/{ContentLoading → Loading}/index.ts +1 -1
  105. package/src/components/MobileLayout/MobileLayout.stories.tsx +21 -17
  106. package/src/components/MobileLayout/MobileLayout.tsx +118 -49
  107. package/src/components/NavBranch/NavBranch.tsx +29 -31
  108. package/src/components/Popover/Popover.tsx +7 -16
  109. package/src/components/SimpleLayout/AppBar.stories.tsx +8 -9
  110. package/src/components/SimpleLayout/AppBar.tsx +60 -60
  111. package/src/components/SimpleLayout/Drawer.tsx +23 -21
  112. package/src/components/SimpleLayout/Main.tsx +17 -21
  113. package/src/components/SimpleLayout/NavBar.stories.tsx +1 -2
  114. package/src/components/SimpleLayout/NavBar.tsx +8 -9
  115. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +43 -66
  116. package/src/components/SimpleLayout/SimpleLayout.tsx +33 -34
  117. package/src/components/hooks.ts +1 -1
  118. package/src/components/index.ts +2 -1
  119. package/src/hooks/actions.ts +4 -3
  120. package/src/hooks/useAppBarProps.ts +9 -9
  121. package/src/hooks/useDrawerActions.ts +6 -6
  122. package/src/hooks/useNavbarActions.ts +3 -3
  123. package/src/hooks/useSimpleLayoutState.ts +1 -1
  124. package/src/operations/close.ts +34 -0
  125. package/src/operations/index.ts +16 -0
  126. package/src/operations/open.ts +63 -0
  127. package/src/operations/revert-workspace.ts +22 -0
  128. package/src/operations/set-layout-mode.ts +12 -0
  129. package/src/operations/set.ts +23 -0
  130. package/src/operations/state-access.ts +19 -0
  131. package/src/operations/switch-workspace.ts +26 -0
  132. package/src/operations/update-complementary.ts +35 -0
  133. package/src/operations/update-dialog.ts +28 -0
  134. package/src/operations/update-popover.ts +35 -0
  135. package/src/operations/update-sidebar.ts +12 -0
  136. package/src/translations.ts +21 -19
  137. package/src/types/capabilities.ts +3 -3
  138. package/dist/lib/browser/chunk-MDPEKLKR.mjs +0 -1163
  139. package/dist/lib/browser/chunk-MDPEKLKR.mjs.map +0 -7
  140. package/dist/lib/browser/chunk-MRR7PXSM.mjs +0 -29
  141. package/dist/lib/browser/chunk-MRR7PXSM.mjs.map +0 -7
  142. package/dist/lib/browser/operation-resolver-VTZ6HZ4B.mjs +0 -194
  143. package/dist/lib/browser/operation-resolver-VTZ6HZ4B.mjs.map +0 -7
  144. package/dist/lib/browser/react-root-WVQYY2JA.mjs +0 -21
  145. package/dist/lib/browser/react-root-WVQYY2JA.mjs.map +0 -7
  146. package/dist/lib/browser/react-surface-VLBR37ED.mjs +0 -44
  147. package/dist/lib/browser/react-surface-VLBR37ED.mjs.map +0 -7
  148. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs +0 -66
  149. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs.map +0 -7
  150. package/dist/lib/browser/state-TXSMUWYI.mjs +0 -48
  151. package/dist/lib/browser/state-TXSMUWYI.mjs.map +0 -7
  152. package/dist/lib/browser/url-handler-RBRONH7S.mjs +0 -151
  153. package/dist/lib/browser/url-handler-RBRONH7S.mjs.map +0 -7
  154. package/dist/lib/node-esm/chunk-DCKASLMP.mjs +0 -1164
  155. package/dist/lib/node-esm/chunk-DCKASLMP.mjs.map +0 -7
  156. package/dist/lib/node-esm/chunk-WMNTJ2MK.mjs +0 -31
  157. package/dist/lib/node-esm/chunk-WMNTJ2MK.mjs.map +0 -7
  158. package/dist/lib/node-esm/operation-resolver-R7CQ6ERU.mjs +0 -195
  159. package/dist/lib/node-esm/operation-resolver-R7CQ6ERU.mjs.map +0 -7
  160. package/dist/lib/node-esm/react-root-XBNDM7BE.mjs +0 -22
  161. package/dist/lib/node-esm/react-root-XBNDM7BE.mjs.map +0 -7
  162. package/dist/lib/node-esm/react-surface-U5NHA367.mjs +0 -45
  163. package/dist/lib/node-esm/react-surface-U5NHA367.mjs.map +0 -7
  164. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs +0 -68
  165. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs.map +0 -7
  166. package/dist/lib/node-esm/state-JMX6FAG4.mjs +0 -49
  167. package/dist/lib/node-esm/state-JMX6FAG4.mjs.map +0 -7
  168. package/dist/lib/node-esm/url-handler-QSMCH3JB.mjs +0 -152
  169. package/dist/lib/node-esm/url-handler-QSMCH3JB.mjs.map +0 -7
  170. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  171. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  172. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  173. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  174. package/dist/types/src/capabilities/react-root/index.d.ts +0 -6
  175. package/dist/types/src/capabilities/react-root/index.d.ts.map +0 -1
  176. package/dist/types/src/capabilities/react-root/react-root.d.ts.map +0 -1
  177. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  178. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  179. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  180. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts +0 -3
  181. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts.map +0 -1
  182. package/dist/types/src/capabilities/spotlight-dismiss/spotlight-dismiss.d.ts.map +0 -1
  183. package/dist/types/src/capabilities/state/index.d.ts +0 -13
  184. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  185. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  186. package/dist/types/src/capabilities/url-handler/index.d.ts +0 -3
  187. package/dist/types/src/capabilities/url-handler/index.d.ts.map +0 -1
  188. package/dist/types/src/capabilities/url-handler/url-handler.d.ts.map +0 -1
  189. package/dist/types/src/components/ContentLoading/ContentLoading.d.ts +0 -3
  190. package/dist/types/src/components/ContentLoading/ContentLoading.d.ts.map +0 -1
  191. package/dist/types/src/components/ContentLoading/ContentLoading.stories.d.ts.map +0 -1
  192. package/dist/types/src/components/ContentLoading/index.d.ts +0 -2
  193. package/dist/types/src/components/ContentLoading/index.d.ts.map +0 -1
  194. package/src/capabilities/operation-resolver/index.ts +0 -10
  195. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -202
  196. package/src/capabilities/react-root/index.ts +0 -7
  197. package/src/capabilities/react-surface/index.ts +0 -7
  198. package/src/capabilities/spotlight-dismiss/index.ts +0 -7
  199. package/src/capabilities/state/index.ts +0 -9
  200. package/src/capabilities/url-handler/index.ts +0 -7
  201. package/src/capabilities/url-handler/url-handler.ts +0 -133
  202. /package/dist/types/src/capabilities/{react-root/react-root.d.ts → react-root.d.ts} +0 -0
  203. /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
  204. /package/dist/types/src/capabilities/{spotlight-dismiss/spotlight-dismiss.d.ts → spotlight-dismiss.d.ts} +0 -0
  205. /package/src/capabilities/{spotlight-dismiss/spotlight-dismiss.ts → spotlight-dismiss.ts} +0 -0
@@ -5,16 +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';
8
+ import { IconButton, Popover, Toolbar, useTranslation } from '@dxos/react-ui';
9
9
  import { type ActionExecutor, type ActionGraphProps, Menu, useMenuActions } from '@dxos/react-ui-menu';
10
- import { mx, osTranslations } from '@dxos/ui-theme';
10
+ import { composable, composableProps, osTranslations } from '@dxos/ui-theme';
11
+
12
+ import { meta } from '#meta';
11
13
 
12
- import { meta } from '../../meta';
13
14
  import { useMobileLayout } from '../MobileLayout';
14
15
 
15
16
  const APP_BAR_NAME = 'SimpleLayout.AppBar';
16
17
 
17
- export type AppBarProps = ThemedClassName<{
18
+ export type AppBarProps = {
18
19
  /** Title/label to display in the banner. */
19
20
  title?: string;
20
21
  /** Action graph atom for the dropdown menu. */
@@ -27,68 +28,67 @@ export type AppBarProps = ThemedClassName<{
27
28
  onAction?: ActionExecutor;
28
29
  /** Callback when back button is clicked. */
29
30
  onBack?: () => void;
30
- }>;
31
+ };
31
32
 
32
33
  /**
33
34
  * AppBar component that renders a title, optional back button, and actions dropdown.
34
35
  */
35
- export const AppBar = ({
36
- classNames,
37
- title,
38
- actions,
39
- showBackButton,
40
- popoverAnchorId,
41
- onAction,
42
- onBack,
43
- }: AppBarProps) => {
44
- const { t } = useTranslation(meta.id);
45
- const menu = useMenuActions(actions);
46
- const actionsValue = useAtomValue(actions);
47
- const hasActions = actionsValue.nodes.length > 0;
48
- 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);
49
43
 
50
- // Fall back to app name if no title provided.
51
- 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 });
52
46
 
53
- // Wrap the menu trigger with Popover.Anchor when the popoverAnchorId is set.
54
- 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;
55
49
 
56
- return (
57
- <Toolbar.Root
58
- role='banner'
59
- classNames={mx(
60
- 'grid grid-cols-[var(--dx-rail-size)_1fr_var(--dx-rail-size)] items-center',
61
- 'dx-density-fine',
62
- classNames,
63
- )}
64
- >
65
- {keyboardOpen ? (
66
- <IconButton variant='ghost' icon='ph--x--regular' iconOnly label={t('done label')} />
67
- ) : showBackButton ? (
68
- <IconButton variant='ghost' icon='ph--caret-left--regular' iconOnly label={t('back label')} onClick={onBack} />
69
- ) : (
70
- <div />
71
- )}
72
- <h1 className='text-center truncate font-thin uppercase'>{displayTitle}</h1>
73
- {hasActions ? (
74
- <AnchorRoot>
75
- <Menu.Root {...menu} caller={meta.id} onAction={onAction}>
76
- <Menu.Trigger asChild>
77
- <IconButton
78
- variant='ghost'
79
- icon='ph--dots-three-vertical--regular'
80
- iconOnly
81
- label={t('actions menu label')}
82
- />
83
- </Menu.Trigger>
84
- <Menu.Content />
85
- </Menu.Root>
86
- </AnchorRoot>
87
- ) : (
88
- <span />
89
- )}
90
- </Toolbar.Root>
91
- );
92
- };
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>
76
+ <IconButton
77
+ variant='ghost'
78
+ icon='ph--dots-three-vertical--regular'
79
+ iconOnly
80
+ label={t('actions-menu.label')}
81
+ />
82
+ </Menu.Trigger>
83
+ <Menu.Content />
84
+ </Menu.Root>
85
+ </AnchorRoot>
86
+ ) : (
87
+ <span />
88
+ )}
89
+ </Toolbar.Root>
90
+ );
91
+ },
92
+ );
93
93
 
94
94
  AppBar.displayName = APP_BAR_NAME;
@@ -5,14 +5,15 @@
5
5
  import React, { useMemo } from 'react';
6
6
 
7
7
  import { Surface } from '@dxos/app-framework/ui';
8
- import { getCompanionVariant } from '@dxos/app-toolkit';
9
- import { useAppGraph } from '@dxos/app-toolkit/ui';
8
+ import { type AppSurface, useAppGraph } from '@dxos/app-toolkit/ui';
10
9
  import { type Node, useNode } from '@dxos/plugin-graph';
11
10
  import { ErrorFallback, Panel } from '@dxos/react-ui';
11
+ import { getLinkedVariant } from '@dxos/react-ui-attention';
12
12
  import { Menu, useMenuActions } from '@dxos/react-ui-menu';
13
13
 
14
- import { useCompanions, useDrawerActions, useSimpleLayoutState } from '../../hooks';
15
- import { ContentLoading } from '../ContentLoading';
14
+ import { useCompanions, useDrawerActions, useSimpleLayoutState } from '#hooks';
15
+
16
+ import { Loading } from '../Loading';
16
17
 
17
18
  const DRAWER_NAME = 'SimpleLayout.Drawer';
18
19
 
@@ -23,7 +24,7 @@ export const Drawer = () => {
23
24
  const { graph } = useAppGraph();
24
25
  const { state: layoutState } = useSimpleLayoutState();
25
26
 
26
- const placeholder = useMemo(() => <ContentLoading />, []);
27
+ const placeholder = useMemo(() => <Loading />, []);
27
28
 
28
29
  // Get all companions for the current active (primary) item.
29
30
  const activeId = layoutState.active ?? layoutState.workspace;
@@ -35,30 +36,31 @@ export const Drawer = () => {
35
36
  const parentNode = useNode(graph, activeId);
36
37
 
37
38
  // Build Surface data for the companion content.
38
- const data = useMemo(() => {
39
- return (
40
- node && {
41
- attendableId: companionId,
42
- subject: node.data,
43
- companionTo: parentNode?.data,
44
- properties: node.properties,
45
- variant,
46
- }
47
- );
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
+ };
48
50
  }, [companionId, node, parentNode, variant]);
49
51
 
50
52
  // Get drawer actions (tabs + toolbar buttons).
51
53
  const { actions, onAction } = useDrawerActions(DRAWER_NAME);
52
- const menu = useMenuActions(actions);
54
+ const menuActions = useMenuActions(actions);
53
55
 
54
56
  return (
55
57
  <Panel.Root>
56
58
  <Panel.Toolbar>
57
- <Menu.Root {...menu} alwaysActive onAction={onAction}>
58
- <Menu.Toolbar density='coarse' />
59
+ <Menu.Root {...menuActions} alwaysActive onAction={onAction}>
60
+ <Menu.Toolbar />
59
61
  </Menu.Root>
60
62
  </Panel.Toolbar>
61
- <Panel.Content asChild>
63
+ <Panel.Content>
62
64
  <Surface.Surface role='article' data={data} limit={1} fallback={ErrorFallback} placeholder={placeholder} />
63
65
  </Panel.Content>
64
66
  </Panel.Root>
@@ -79,7 +81,7 @@ const useSelectedCompanion = (companions: Node.Node[], preferredVariant?: string
79
81
 
80
82
  // Try to find companion matching the preferred variant.
81
83
  if (preferredVariant) {
82
- const preferred = companions.find((c) => getCompanionVariant(c.id) === preferredVariant);
84
+ const preferred = companions.find((c) => getLinkedVariant(c.id) === preferredVariant);
83
85
  if (preferred) {
84
86
  return preferred;
85
87
  }
@@ -90,7 +92,7 @@ const useSelectedCompanion = (companions: Node.Node[], preferredVariant?: string
90
92
  }, [companions, preferredVariant]);
91
93
 
92
94
  const companionId = selectedCompanion?.id;
93
- const variant = companionId ? getCompanionVariant(companionId) : undefined;
95
+ const variant = companionId ? getLinkedVariant(companionId) : undefined;
94
96
 
95
97
  return { selectedCompanion, companionId, variant };
96
98
  };
@@ -7,15 +7,14 @@ import React, { useMemo } from 'react';
7
7
  import { Surface } from '@dxos/app-framework/ui';
8
8
  import { useAppGraph } from '@dxos/app-toolkit/ui';
9
9
  import { useNode } from '@dxos/plugin-graph';
10
- import { ErrorFallback } from '@dxos/react-ui';
10
+ import { ErrorFallback, Panel } from '@dxos/react-ui';
11
11
  import { useAttentionAttributes } from '@dxos/react-ui-attention';
12
- import { mx } from '@dxos/ui-theme';
13
12
 
14
- import { useAppBarProps, useNavbarActions, useSimpleLayoutState } from '../../hooks';
15
- import { ContentLoading } from '../ContentLoading';
13
+ import { useAppBarProps, useNavbarActions, useSimpleLayoutState } from '#hooks';
14
+
16
15
  import { useExpandPath } from '../hooks';
16
+ import { Loading } from '../Loading';
17
17
  import { useMobileLayout } from '../MobileLayout';
18
-
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);
@@ -53,18 +52,11 @@ export const Main = () => {
53
52
  const showNavBar = !keyboardOpen && !state.isPopover && state.drawerState === 'closed';
54
53
 
55
54
  return (
56
- <div
57
- role='none'
58
- className={mx(
59
- 'h-full grid overflow-hidden bg-toolbar-surface',
60
- showNavBar
61
- ? 'grid-rows-[var(--dx-rail-action)_1fr_var(--dx-toolbar-size)]'
62
- : 'grid-rows-[var(--dx-rail-action)_1fr]',
63
- )}
64
- {...attentionAttrs}
65
- >
66
- <AppBar {...appBarProps} />
67
- <article className='h-full overflow-hidden bg-base-surface'>
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'>
68
60
  <Surface.Surface
69
61
  key={id}
70
62
  role='article'
@@ -73,9 +65,13 @@ export const Main = () => {
73
65
  fallback={ErrorFallback}
74
66
  placeholder={placeholder}
75
67
  />
76
- </article>
77
- {showNavBar && <NavBar classNames='border-y border-subdued-separator' actions={actions} onAction={onAction} />}
78
- </div>
68
+ </Panel.Content>
69
+ {showNavBar && (
70
+ <Panel.Statusbar asChild>
71
+ <NavBar actions={actions} onAction={onAction} />
72
+ </Panel.Statusbar>
73
+ )}
74
+ </Panel.Root>
79
75
  );
80
76
  };
81
77
 
@@ -7,12 +7,11 @@ 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, createGapSeparator, createMenuAction, createMenuItemGroup } 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
14
  import { translations } from '../../translations';
15
-
16
15
  import { NavBar } from './NavBar';
17
16
 
18
17
  const MAIN_MENU_GROUP_ID = 'navbar-main-menu';
@@ -5,30 +5,29 @@
5
5
  import { type Atom } from '@effect-atom/atom-react';
6
6
  import React from 'react';
7
7
 
8
- import { type ThemedClassName } from '@dxos/react-ui';
9
8
  import { type ActionExecutor, type ActionGraphProps, Menu, useMenuActions } from '@dxos/react-ui-menu';
10
- import { mx } from '@dxos/ui-theme';
9
+ import { composable, composableProps } from '@dxos/ui-theme';
11
10
 
12
11
  const NAVBAR_NAME = 'SimpleLayout.NavBar';
13
12
 
14
- export type NavBarProps = ThemedClassName<{
13
+ export type NavBarProps = {
15
14
  /** Action graph atom for the toolbar. */
16
15
  actions: Atom.Atom<ActionGraphProps>;
17
16
  /** Action executor callback. */
18
17
  onAction?: ActionExecutor;
19
- }>;
18
+ };
20
19
 
21
20
  /**
22
21
  * Presentational navbar component that renders a toolbar from an action graph.
23
22
  */
24
- export const NavBar = ({ classNames, actions, onAction }: NavBarProps) => {
25
- const menu = useMenuActions(actions);
23
+ export const NavBar = composable<HTMLDivElement, NavBarProps>(({ actions, onAction, ...props }, forwardedRef) => {
24
+ const menuActions = useMenuActions(actions);
26
25
 
27
26
  return (
28
- <Menu.Root {...menu} alwaysActive onAction={onAction}>
29
- <Menu.Toolbar density='coarse' classNames={mx(classNames)} />
27
+ <Menu.Root {...menuActions} alwaysActive onAction={onAction}>
28
+ <Menu.Toolbar {...composableProps(props)} ref={forwardedRef} />
30
29
  </Menu.Root>
31
30
  );
32
- };
31
+ });
33
32
 
34
33
  NavBar.displayName = NAVBAR_NAME;
@@ -5,80 +5,69 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import * as Effect from 'effect/Effect';
7
7
 
8
- import { ActivationEvents, Capabilities, Capability, Plugin } from '@dxos/app-framework';
8
+ import { ActivationEvents, Capability, Plugin } from '@dxos/app-framework';
9
9
  import { withPluginManager } from '@dxos/app-framework/testing';
10
- import { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';
10
+ import { AppActivationEvents } from '@dxos/app-toolkit';
11
11
  import { Collection } from '@dxos/echo';
12
- import { ClientOperation, ClientPlugin } from '@dxos/plugin-client';
12
+ import { ClientPlugin } from '@dxos/plugin-client';
13
13
  import { SearchPlugin } from '@dxos/plugin-search';
14
14
  import { SpacePlugin } from '@dxos/plugin-space';
15
- import { SpaceOperation } from '@dxos/plugin-space/types';
16
15
  import { corePlugins } from '@dxos/plugin-testing';
17
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
18
- import { translations as searchTranslation } from '@dxos/react-ui-searchlist';
16
+ import { translations as searchTranslation } from '@dxos/react-ui-search';
17
+ import { withLayout } from '@dxos/react-ui/testing';
18
+
19
+ import { ReactRoot, ReactSurface, State } from '#capabilities';
20
+ import { meta as pluginMeta } from '#meta';
21
+ import { SimpleLayoutEvents } from '#types';
19
22
 
20
- import { OperationResolver, type SimpleLayoutStateOptions, State } from '../../capabilities';
21
- import { meta as pluginMeta } from '../../meta';
22
23
  import { type SimpleLayoutPluginOptions } from '../../SimpleLayoutPlugin';
23
24
  import { translations } from '../../translations';
24
-
25
25
  import { SimpleLayout } from './SimpleLayout';
26
26
 
27
- const TestPlugin = Plugin.define<SimpleLayoutPluginOptions>(pluginMeta).pipe(
28
- AppPlugin.addOperationResolverModule({ activate: OperationResolver }),
29
- Plugin.addModule(({ isPopover = false }) => ({
30
- id: Capability.getModuleTag(State),
31
- activatesOn: ActivationEvents.Startup,
32
- activatesAfter: [AppActivationEvents.LayoutReady],
33
- activate: () => State({ initialState: { isPopover } } satisfies SimpleLayoutStateOptions),
34
- })),
35
- Plugin.addModule({
36
- id: 'setup',
37
- activatesOn: ActivationEvents.OperationInvokerReady,
38
- activate: Effect.fnUntraced(function* () {
39
- const { invoke } = yield* Capability.get(Capabilities.OperationInvoker);
40
- yield* invoke(ClientOperation.CreateIdentity, {});
41
- const { space: work } = yield* invoke(SpaceOperation.Create, { name: 'Work Space' });
42
- const { space: sharedProject } = yield* invoke(SpaceOperation.Create, { name: 'Shared Project' });
43
-
44
- // Add collections to Work Space.
45
- yield* invoke(SpaceOperation.AddObject, {
46
- target: work.db,
47
- object: Collection.make({ name: 'Projects', objects: [] }),
48
- });
49
- yield* invoke(SpaceOperation.AddObject, {
50
- target: work.db,
51
- object: Collection.make({ name: 'Documents', objects: [] }),
52
- });
53
-
54
- // Add collections to Shared Project.
55
- yield* invoke(SpaceOperation.AddObject, {
56
- target: sharedProject.db,
57
- object: Collection.make({ name: 'Tasks', objects: [] }),
58
- });
59
- yield* invoke(SpaceOperation.AddObject, {
60
- target: sharedProject.db,
61
- object: Collection.make({ name: 'Notes', objects: [] }),
62
- });
63
- }),
64
- }),
65
- Plugin.make,
66
- );
67
-
68
- const createPluginManager = ({ isPopover }: { isPopover: boolean }) => {
27
+ const createPluginManager = ({ isPopover }: { isPopover?: boolean }) => {
69
28
  return withPluginManager({
29
+ setupEvents: [AppActivationEvents.SetupSettings],
70
30
  plugins: [
71
31
  ...corePlugins(),
72
32
  ClientPlugin({
73
33
  types: [Collection.Collection],
34
+ onClientInitialized: ({ client }) =>
35
+ Effect.gen(function* () {
36
+ yield* Effect.promise(() => client.halo.createIdentity());
37
+ }),
74
38
  }),
39
+
75
40
  SearchPlugin(),
76
41
  SpacePlugin({}),
77
- TestPlugin({ isPopover }),
42
+
43
+ // TODO(burdon): This should be factored ouf from SimpleLayoutPlugin.
44
+ Plugin.define<SimpleLayoutPluginOptions>(pluginMeta).pipe(
45
+ Plugin.addModule(({ isPopover = false }) => ({
46
+ id: Capability.getModuleTag(State),
47
+ activatesOn: ActivationEvents.Startup,
48
+ activatesAfter: [SimpleLayoutEvents.StateReady, AppActivationEvents.LayoutReady],
49
+ activate: () => State({ initialState: { isPopover } }),
50
+ })),
51
+ Plugin.addModule({
52
+ id: Capability.getModuleTag(ReactRoot),
53
+ activatesOn: ActivationEvents.Startup,
54
+ activate: ReactRoot,
55
+ }),
56
+ Plugin.addModule({
57
+ id: Capability.getModuleTag(ReactSurface),
58
+ activatesOn: ActivationEvents.Startup,
59
+ activate: ReactSurface,
60
+ }),
61
+ Plugin.make,
62
+ )({ isPopover }),
78
63
  ],
79
64
  });
80
65
  };
81
66
 
67
+ /**
68
+ * NOTE: To expose to iphone on network:
69
+ * `moon run storybook-react:serve dev -H 0.0.0.0`
70
+ */
82
71
  const meta = {
83
72
  title: 'plugins/plugin-simple-layout/components/SimpleLayout',
84
73
  component: SimpleLayout,
@@ -92,22 +81,10 @@ export default meta;
92
81
 
93
82
  type Story = StoryObj<typeof meta>;
94
83
 
95
- /**
96
- * NOTE: To expose to iphone on network:
97
- * `moon run storybook-react:serve dev -H 0.0.0.0`
98
- */
99
84
  export const Default: Story = {
100
- decorators: [
101
- withTheme(),
102
- withLayout({ layout: 'column', classNames: 'relative' }),
103
- createPluginManager({ isPopover: false }),
104
- ],
85
+ decorators: [withLayout({ layout: 'column', classNames: 'relative' }), createPluginManager({})],
105
86
  };
106
87
 
107
88
  export const Popover: Story = {
108
- decorators: [
109
- withTheme(),
110
- withLayout({ layout: 'column', classNames: 'relative' }),
111
- createPluginManager({ isPopover: true }),
112
- ],
89
+ decorators: [withLayout({ layout: 'column', classNames: 'relative' }), createPluginManager({ isPopover: true })],
113
90
  };
@@ -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 classNames='dx-container grid relative'>
37
+ <MobileLayout.Root
38
+ classNames='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,