@dxos/plugin-simple-layout 0.0.0 → 0.8.4-main.21d9917

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 (154) hide show
  1. package/dist/lib/browser/chunk-CLPGTNWJ.mjs +29 -0
  2. package/dist/lib/browser/chunk-CLPGTNWJ.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-FK4M7GJV.mjs +613 -0
  4. package/dist/lib/browser/chunk-FK4M7GJV.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +94 -0
  6. package/dist/lib/browser/index.mjs.map +7 -0
  7. package/dist/lib/browser/meta.json +1 -0
  8. package/dist/lib/browser/operation-resolver-LTB63NKP.mjs +168 -0
  9. package/dist/lib/browser/operation-resolver-LTB63NKP.mjs.map +7 -0
  10. package/dist/lib/browser/react-root-6ARAPH3O.mjs +21 -0
  11. package/dist/lib/browser/react-root-6ARAPH3O.mjs.map +7 -0
  12. package/dist/lib/browser/react-surface-SO7B23GS.mjs +39 -0
  13. package/dist/lib/browser/react-surface-SO7B23GS.mjs.map +7 -0
  14. package/dist/lib/browser/spotlight-dismiss-VSNOPETH.mjs +66 -0
  15. package/dist/lib/browser/spotlight-dismiss-VSNOPETH.mjs.map +7 -0
  16. package/dist/lib/browser/state-H4IGICBB.mjs +45 -0
  17. package/dist/lib/browser/state-H4IGICBB.mjs.map +7 -0
  18. package/dist/lib/browser/url-handler-7CFGTLNG.mjs +54 -0
  19. package/dist/lib/browser/url-handler-7CFGTLNG.mjs.map +7 -0
  20. package/dist/lib/node-esm/chunk-EGFZAVBD.mjs +614 -0
  21. package/dist/lib/node-esm/chunk-EGFZAVBD.mjs.map +7 -0
  22. package/dist/lib/node-esm/chunk-MUVVYBUE.mjs +31 -0
  23. package/dist/lib/node-esm/chunk-MUVVYBUE.mjs.map +7 -0
  24. package/dist/lib/node-esm/index.mjs +95 -0
  25. package/dist/lib/node-esm/index.mjs.map +7 -0
  26. package/dist/lib/node-esm/meta.json +1 -0
  27. package/dist/lib/node-esm/operation-resolver-7O6O7T4Q.mjs +169 -0
  28. package/dist/lib/node-esm/operation-resolver-7O6O7T4Q.mjs.map +7 -0
  29. package/dist/lib/node-esm/react-root-2CPA2ZUS.mjs +22 -0
  30. package/dist/lib/node-esm/react-root-2CPA2ZUS.mjs.map +7 -0
  31. package/dist/lib/node-esm/react-surface-FKAV56MO.mjs +40 -0
  32. package/dist/lib/node-esm/react-surface-FKAV56MO.mjs.map +7 -0
  33. package/dist/lib/node-esm/spotlight-dismiss-L5PCWIJG.mjs +68 -0
  34. package/dist/lib/node-esm/spotlight-dismiss-L5PCWIJG.mjs.map +7 -0
  35. package/dist/lib/node-esm/state-QIU2LMLT.mjs +46 -0
  36. package/dist/lib/node-esm/state-QIU2LMLT.mjs.map +7 -0
  37. package/dist/lib/node-esm/url-handler-4LYP3JM7.mjs +55 -0
  38. package/dist/lib/node-esm/url-handler-4LYP3JM7.mjs.map +7 -0
  39. package/dist/types/src/SimpleLayoutPlugin.d.ts +7 -0
  40. package/dist/types/src/SimpleLayoutPlugin.d.ts.map +1 -0
  41. package/dist/types/src/capabilities/index.d.ts +7 -0
  42. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  43. package/dist/types/src/capabilities/operation-resolver/index.d.ts +3 -0
  44. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -0
  45. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +5 -0
  46. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -0
  47. package/dist/types/src/capabilities/react-root/index.d.ts +6 -0
  48. package/dist/types/src/capabilities/react-root/index.d.ts.map +1 -0
  49. package/dist/types/src/capabilities/react-root/react-root.d.ts +9 -0
  50. package/dist/types/src/capabilities/react-root/react-root.d.ts.map +1 -0
  51. package/dist/types/src/capabilities/react-surface/index.d.ts +3 -0
  52. package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -0
  53. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +5 -0
  54. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -0
  55. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts +3 -0
  56. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts.map +1 -0
  57. package/dist/types/src/capabilities/spotlight-dismiss/spotlight-dismiss.d.ts +14 -0
  58. package/dist/types/src/capabilities/spotlight-dismiss/spotlight-dismiss.d.ts.map +1 -0
  59. package/dist/types/src/capabilities/state/index.d.ts +13 -0
  60. package/dist/types/src/capabilities/state/index.d.ts.map +1 -0
  61. package/dist/types/src/capabilities/state/state.d.ts +19 -0
  62. package/dist/types/src/capabilities/state/state.d.ts.map +1 -0
  63. package/dist/types/src/capabilities/url-handler/index.d.ts +3 -0
  64. package/dist/types/src/capabilities/url-handler/index.d.ts.map +1 -0
  65. package/dist/types/src/capabilities/url-handler/url-handler.d.ts +10 -0
  66. package/dist/types/src/capabilities/url-handler/url-handler.d.ts.map +1 -0
  67. package/dist/types/src/components/ContentError.d.ts +5 -0
  68. package/dist/types/src/components/ContentError.d.ts.map +1 -0
  69. package/dist/types/src/components/ContentError.stories.d.ts +35 -0
  70. package/dist/types/src/components/ContentError.stories.d.ts.map +1 -0
  71. package/dist/types/src/components/ContentLoading.d.ts +3 -0
  72. package/dist/types/src/components/ContentLoading.d.ts.map +1 -0
  73. package/dist/types/src/components/ContentLoading.stories.d.ts +13 -0
  74. package/dist/types/src/components/ContentLoading.stories.d.ts.map +1 -0
  75. package/dist/types/src/components/Dialog/Dialog.d.ts +3 -0
  76. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -0
  77. package/dist/types/src/components/Dialog/index.d.ts +2 -0
  78. package/dist/types/src/components/Dialog/index.d.ts.map +1 -0
  79. package/dist/types/src/components/Home/Home.d.ts +7 -0
  80. package/dist/types/src/components/Home/Home.d.ts.map +1 -0
  81. package/dist/types/src/components/Home/index.d.ts +2 -0
  82. package/dist/types/src/components/Home/index.d.ts.map +1 -0
  83. package/dist/types/src/components/Popover/Popover.d.ts +4 -0
  84. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -0
  85. package/dist/types/src/components/Popover/index.d.ts +2 -0
  86. package/dist/types/src/components/Popover/index.d.ts.map +1 -0
  87. package/dist/types/src/components/SimpleLayout/Banner.d.ts +8 -0
  88. package/dist/types/src/components/SimpleLayout/Banner.d.ts.map +1 -0
  89. package/dist/types/src/components/SimpleLayout/Main.d.ts +9 -0
  90. package/dist/types/src/components/SimpleLayout/Main.d.ts.map +1 -0
  91. package/dist/types/src/components/SimpleLayout/NavBar.d.ts +8 -0
  92. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -0
  93. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts +39 -0
  94. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts.map +1 -0
  95. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts +3 -0
  96. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts.map +1 -0
  97. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts +37 -0
  98. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts.map +1 -0
  99. package/dist/types/src/components/SimpleLayout/index.d.ts +2 -0
  100. package/dist/types/src/components/SimpleLayout/index.d.ts.map +1 -0
  101. package/dist/types/src/components/Workspace/Workspace.d.ts +9 -0
  102. package/dist/types/src/components/Workspace/Workspace.d.ts.map +1 -0
  103. package/dist/types/src/components/Workspace/index.d.ts +2 -0
  104. package/dist/types/src/components/Workspace/index.d.ts.map +1 -0
  105. package/dist/types/src/components/hooks.d.ts +5 -0
  106. package/dist/types/src/components/hooks.d.ts.map +1 -0
  107. package/dist/types/src/components/index.d.ts +6 -0
  108. package/dist/types/src/components/index.d.ts.map +1 -0
  109. package/dist/types/src/hooks/index.d.ts +2 -0
  110. package/dist/types/src/hooks/index.d.ts.map +1 -0
  111. package/dist/types/src/hooks/useSimpleLayoutState.d.ts +7 -0
  112. package/dist/types/src/hooks/useSimpleLayoutState.d.ts.map +1 -0
  113. package/dist/types/src/index.d.ts +2 -0
  114. package/dist/types/src/index.d.ts.map +1 -0
  115. package/dist/types/src/meta.d.ts +3 -0
  116. package/dist/types/src/meta.d.ts.map +1 -0
  117. package/dist/types/src/translations.d.ts +20 -0
  118. package/dist/types/src/translations.d.ts.map +1 -0
  119. package/dist/types/src/types/capabilities.d.ts +31 -0
  120. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  121. package/dist/types/src/types/events.d.ts +6 -0
  122. package/dist/types/src/types/events.d.ts.map +1 -0
  123. package/dist/types/src/types/index.d.ts +3 -0
  124. package/dist/types/src/types/index.d.ts.map +1 -0
  125. package/dist/types/tsconfig.tsbuildinfo +1 -0
  126. package/package.json +29 -24
  127. package/src/SimpleLayoutPlugin.ts +20 -4
  128. package/src/capabilities/index.ts +3 -0
  129. package/src/capabilities/operation-resolver/operation-resolver.ts +82 -39
  130. package/src/capabilities/react-surface/index.ts +7 -0
  131. package/src/capabilities/react-surface/react-surface.tsx +40 -0
  132. package/src/capabilities/spotlight-dismiss/index.ts +7 -0
  133. package/src/{hooks/useSpotlightDismiss.ts → capabilities/spotlight-dismiss/spotlight-dismiss.ts} +31 -40
  134. package/src/capabilities/state/state.tsx +21 -32
  135. package/src/capabilities/url-handler/index.ts +7 -0
  136. package/src/capabilities/url-handler/url-handler.ts +80 -0
  137. package/src/components/Dialog/Dialog.tsx +14 -14
  138. package/src/components/Home/Home.tsx +53 -61
  139. package/src/components/Popover/Popover.tsx +45 -27
  140. package/src/components/SimpleLayout/Banner.tsx +50 -28
  141. package/src/components/SimpleLayout/Main.tsx +40 -44
  142. package/src/components/SimpleLayout/NavBar.tsx +18 -41
  143. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +2 -9
  144. package/src/components/SimpleLayout/SimpleLayout.tsx +0 -1
  145. package/src/components/Workspace/Workspace.tsx +115 -0
  146. package/src/components/Workspace/index.ts +5 -0
  147. package/src/components/hooks.ts +30 -0
  148. package/src/components/index.ts +1 -0
  149. package/src/hooks/index.ts +1 -1
  150. package/src/hooks/useSimpleLayoutState.ts +30 -0
  151. package/src/types/capabilities.ts +8 -1
  152. package/src/types/events.ts +14 -0
  153. package/src/types/index.ts +1 -0
  154. /package/src/components/SimpleLayout/{NavBarstories.tsx → NavBar.stories.tsx} +0 -0
@@ -6,33 +6,18 @@ import React from 'react';
6
6
 
7
7
  import { useAppGraph } from '@dxos/app-framework/react';
8
8
  import { Node, useActionRunner, useConnections } from '@dxos/plugin-graph';
9
- import {
10
- Avatar,
11
- Button,
12
- ButtonGroup,
13
- DensityProvider,
14
- IconButton,
15
- type Size,
16
- Tooltip,
17
- useTranslation,
18
- } from '@dxos/react-ui';
9
+ import { IconButton, type ThemedClassName, Toolbar, Tooltip, useTranslation } from '@dxos/react-ui';
19
10
  import { DropdownMenu, MenuProvider } from '@dxos/react-ui-menu';
20
- import { mx, surfaceZIndex } from '@dxos/ui-theme';
11
+ import { mx } from '@dxos/ui-theme';
21
12
 
22
13
  import { meta } from '../../meta';
23
14
 
24
- const buttonProps = {
25
- iconOnly: true,
26
- size: 6 as Size,
27
- classNames: 'aspect-square',
28
- };
29
-
30
- export type NavBarProps = {
15
+ export type NavBarProps = ThemedClassName<{
31
16
  activeId?: string;
32
17
  onActiveIdChange?: (nextActiveId: string | null) => void;
33
- };
18
+ }>;
34
19
 
35
- export const NavBar = ({ activeId, onActiveIdChange }: NavBarProps) => {
20
+ export const NavBar = ({ classNames, activeId, onActiveIdChange }: NavBarProps) => {
36
21
  const { t } = useTranslation(meta.id);
37
22
  const { graph } = useAppGraph();
38
23
  const runAction = useActionRunner();
@@ -43,16 +28,17 @@ export const NavBar = ({ activeId, onActiveIdChange }: NavBarProps) => {
43
28
  const isBrowseActive = activeId !== 'notifications' && activeId !== 'profile';
44
29
 
45
30
  return (
46
- <DensityProvider density='coarse'>
47
- <nav
48
- className={mx(
49
- 'fixed inset-inline-0',
50
- 'grid grid-cols-[min-content_min-content] gap-2 place-content-center',
51
- 'block-end-[--dx-mobile-bottombar-inset-bottom,0px] bs-[--dx-mobile-bottombar-content-height,64px]',
52
- 'bg-baseSurface border-bs border-separator',
53
- surfaceZIndex({ level: 'menu' }),
54
- )}
55
- >
31
+ <Toolbar.Root classNames={mx('justify-center', classNames)}>
32
+ <MenuProvider onAction={runAction}>
33
+ <DropdownMenu.Root items={menuActions}>
34
+ <Tooltip.Trigger asChild content={t('app menu label')}>
35
+ <DropdownMenu.Trigger asChild data-testid='spacePlugin.addSpace'>
36
+ <IconButton icon='ph--plus--regular' iconOnly label={t('main menu label')} />
37
+ </DropdownMenu.Trigger>
38
+ </Tooltip.Trigger>
39
+ </DropdownMenu.Root>
40
+ </MenuProvider>
41
+ {/*
56
42
  <ButtonGroup>
57
43
  <IconButton
58
44
  {...buttonProps}
@@ -82,16 +68,7 @@ export const NavBar = ({ activeId, onActiveIdChange }: NavBarProps) => {
82
68
  </Avatar.Root>
83
69
  </Button>
84
70
  </ButtonGroup>
85
- <MenuProvider onAction={runAction}>
86
- <DropdownMenu.Root items={menuActions}>
87
- <Tooltip.Trigger asChild content={t('app menu label')} side='right'>
88
- <DropdownMenu.Trigger asChild data-testid='spacePlugin.addSpace'>
89
- <IconButton {...buttonProps} icon='ph--plus--regular' label={t('main menu label')} />
90
- </DropdownMenu.Trigger>
91
- </Tooltip.Trigger>
92
- </DropdownMenu.Root>
93
- </MenuProvider>
94
- </nav>
95
- </DensityProvider>
71
+ */}
72
+ </Toolbar.Root>
96
73
  );
97
74
  };
@@ -69,17 +69,10 @@ const createPluginManager = ({ isPopover }: { isPopover: boolean }) => {
69
69
  plugins: [
70
70
  ...corePlugins(),
71
71
  ClientPlugin({
72
- onClientInitialized: ({ client }) =>
73
- Effect.gen(function* () {
74
- yield* Effect.promise(() => client.halo.createIdentity());
75
- yield* Effect.promise(async () => {
76
- await client.spaces.create({ name: 'Work Space' });
77
- await client.spaces.create({ name: 'Shared Project' });
78
- });
79
- }),
72
+ types: [Collection.Collection],
80
73
  }),
81
- SpacePlugin({}),
82
74
  SearchPlugin(),
75
+ SpacePlugin({}),
83
76
  TestPlugin({ isPopover }),
84
77
  ],
85
78
  });
@@ -9,7 +9,6 @@ import { PopoverContent, PopoverRoot } from '../Popover';
9
9
 
10
10
  import { Main } from './Main';
11
11
 
12
- // TODO(wittjosiah): Support toast.
13
12
  export const SimpleLayout = () => {
14
13
  return (
15
14
  <PopoverRoot>
@@ -0,0 +1,115 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useEffect, useRef } from 'react';
6
+
7
+ import { Common } from '@dxos/app-framework';
8
+ import { useAppGraph, useOperationInvoker } from '@dxos/app-framework/react';
9
+ import { type Node, useConnections } from '@dxos/plugin-graph';
10
+ import { Avatar, Icon, Toolbar, toLocalizedString, useTranslation } from '@dxos/react-ui';
11
+ import { Card, Layout, Mosaic, type StackTileComponent } from '@dxos/react-ui-mosaic';
12
+ import { SearchList, useSearchListItem, useSearchListResults } from '@dxos/react-ui-searchlist';
13
+ import { mx } from '@dxos/ui-theme';
14
+
15
+ import { meta } from '../../meta';
16
+ import { useLoadDescendents } from '../hooks';
17
+
18
+ export type WorkspaceProps = {
19
+ id: string;
20
+ };
21
+
22
+ /**
23
+ *
24
+ */
25
+ // TODO(burdon): Rename or motivate name in comment.
26
+ export const Workspace = ({ id }: WorkspaceProps) => {
27
+ const { t } = useTranslation(meta.id);
28
+ const { graph } = useAppGraph();
29
+
30
+ // Expand the workspace node to load its children.
31
+ useLoadDescendents(id);
32
+
33
+ // Get direct children of the workspace node.
34
+ const children = useConnections(graph, id, 'outbound');
35
+
36
+ const { results, handleSearch } = useSearchListResults({
37
+ items: children,
38
+ extract: (child) => toLocalizedString(child.properties.label, t),
39
+ });
40
+
41
+ return (
42
+ <Layout.Main toolbar>
43
+ <SearchList.Root onSearch={handleSearch}>
44
+ <Toolbar.Root>
45
+ <SearchList.Input placeholder={t('search placeholder')} autoFocus />
46
+ </Toolbar.Root>
47
+ <SearchList.Content>
48
+ <Mosaic.Container asChild>
49
+ <Mosaic.Viewport padding>
50
+ <Mosaic.Stack items={results} getId={(child) => child.id} Tile={WorkspaceChildTile} />
51
+ </Mosaic.Viewport>
52
+ </Mosaic.Container>
53
+ </SearchList.Content>
54
+ </SearchList.Root>
55
+ </Layout.Main>
56
+ );
57
+ };
58
+
59
+ const WorkspaceChildTile: StackTileComponent<Node.Node> = ({ data }) => {
60
+ const { t } = useTranslation(meta.id);
61
+ const { invokeSync } = useOperationInvoker();
62
+ const ref = useRef<HTMLDivElement>(null);
63
+ const { selectedValue, registerItem, unregisterItem } = useSearchListItem();
64
+ const isSelected = selectedValue === data.id;
65
+
66
+ const name = toLocalizedString(data.properties.label, t);
67
+
68
+ const handleSelect = useCallback(
69
+ () => invokeSync(Common.LayoutOperation.Open, { subject: [data.id] }),
70
+ [invokeSync, data.id],
71
+ );
72
+
73
+ // Register this item with the search context.
74
+ useEffect(() => {
75
+ if (ref.current) {
76
+ registerItem(data.id, ref.current, handleSelect);
77
+ }
78
+
79
+ return () => unregisterItem(data.id);
80
+ }, [data.id, handleSelect, registerItem, unregisterItem]);
81
+
82
+ // Scroll into view when selected.
83
+ useEffect(() => {
84
+ if (isSelected && ref.current) {
85
+ ref.current.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
86
+ }
87
+ }, [isSelected]);
88
+
89
+ return (
90
+ <Card.Root
91
+ ref={ref}
92
+ role='button'
93
+ fullWidth
94
+ tabIndex={-1} // TODO(burdon): Use Mosaic.Focus.
95
+ data-selected={isSelected}
96
+ classNames={mx('dx-focus-ring', isSelected && 'bg-hoverOverlay')}
97
+ onClick={handleSelect}
98
+ >
99
+ <Card.Toolbar density='coarse'>
100
+ <Avatar.Root>
101
+ <Avatar.Content
102
+ hue={data.properties.hue}
103
+ icon={data.properties.icon}
104
+ hueVariant='transparent'
105
+ variant='square'
106
+ size={12}
107
+ fallback={name}
108
+ />
109
+ <Avatar.Label>{name}</Avatar.Label>
110
+ <Icon icon='ph--caret-right--regular' />
111
+ </Avatar.Root>
112
+ </Card.Toolbar>
113
+ </Card.Root>
114
+ );
115
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './Workspace';
@@ -0,0 +1,30 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useEffect } from 'react';
6
+
7
+ import { useAppGraph } from '@dxos/app-framework/react';
8
+ import { Graph } from '@dxos/plugin-graph';
9
+
10
+ /**
11
+ * Hook to expand graph nodes two levels deep when directly linked to.
12
+ */
13
+ export const useLoadDescendents = (nodeId?: string) => {
14
+ const { graph } = useAppGraph();
15
+
16
+ useEffect(() => {
17
+ const frame = requestAnimationFrame(() => {
18
+ if (nodeId) {
19
+ // First level: expand the node itself.
20
+ Graph.expand(graph, nodeId, 'outbound');
21
+ // Second level: expand each child.
22
+ Graph.getConnections(graph, nodeId, 'outbound').forEach((child) => {
23
+ Graph.expand(graph, child.id, 'outbound');
24
+ });
25
+ }
26
+ });
27
+
28
+ return () => cancelAnimationFrame(frame);
29
+ }, [nodeId, graph]);
30
+ };
@@ -6,3 +6,4 @@ export * from './ContentLoading';
6
6
  export * from './Home';
7
7
  export * from './Popover';
8
8
  export * from './SimpleLayout';
9
+ export * from './Workspace';
@@ -2,4 +2,4 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './useSpotlightDismiss';
5
+ export * from './useSimpleLayoutState';
@@ -0,0 +1,30 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
+ import { useCallback, useContext } from 'react';
7
+
8
+ import { useCapability } from '@dxos/app-framework/react';
9
+
10
+ import { type SimpleLayoutState, SimpleLayoutState as SimpleLayoutStateCapability } from '../types';
11
+
12
+ export type SimpleLayoutStateHook = {
13
+ state: SimpleLayoutState;
14
+ updateState: (fn: (current: SimpleLayoutState) => SimpleLayoutState) => void;
15
+ };
16
+
17
+ export const useSimpleLayoutState = (): SimpleLayoutStateHook => {
18
+ const registry = useContext(RegistryContext);
19
+ const stateAtom = useCapability(SimpleLayoutStateCapability);
20
+ const state = useAtomValue(stateAtom);
21
+
22
+ const updateState = useCallback(
23
+ (fn: (current: SimpleLayoutState) => SimpleLayoutState) => {
24
+ registry.set(stateAtom, fn(registry.get(stateAtom)));
25
+ },
26
+ [registry, stateAtom],
27
+ );
28
+
29
+ return { state, updateState };
30
+ };
@@ -2,7 +2,10 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { type Atom } from '@effect-atom/atom-react';
6
+
5
7
  import { Capability } from '@dxos/app-framework';
8
+ import { type Label } from '@dxos/react-ui';
6
9
 
7
10
  import { meta } from '../meta';
8
11
 
@@ -24,14 +27,18 @@ export type SimpleLayoutState = {
24
27
  popoverVariant?: 'virtual' | 'react';
25
28
  popoverAnchor?: HTMLButtonElement;
26
29
  popoverAnchorId?: string;
30
+ popoverKind?: 'base' | 'card';
31
+ popoverTitle?: Label;
27
32
  popoverContent?: any;
28
33
 
29
34
  workspace: string;
30
35
  previousWorkspace: string;
31
36
  active?: string;
37
+ /** Stack of previously active item IDs for back navigation. */
38
+ history: string[];
32
39
 
33
40
  /** Whether running in popover window context (hides mobile-specific UI). */
34
41
  isPopover?: boolean;
35
42
  };
36
43
 
37
- export const SimpleLayoutState = Capability.make<SimpleLayoutState>(`${meta.id}/state`);
44
+ export const SimpleLayoutState = Capability.make<Atom.Writable<SimpleLayoutState>>(`${meta.id}/state`);
@@ -0,0 +1,14 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type ActivationEvent, Common } from '@dxos/app-framework';
6
+
7
+ import { SimpleLayoutState } from './capabilities';
8
+
9
+ export namespace SimpleLayoutEvents {
10
+ /** Fired when SimpleLayoutState capability is ready. */
11
+ export const StateReady: ActivationEvent.ActivationEvent = Common.ActivationEvent.createStateEvent(
12
+ SimpleLayoutState.identifier,
13
+ );
14
+ }
@@ -3,3 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './capabilities';
6
+ export * from './events';