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

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 (191) hide show
  1. package/dist/lib/browser/chunk-7VLT3S46.mjs +29 -0
  2. package/dist/lib/browser/chunk-7VLT3S46.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-O3BQBYMW.mjs +1165 -0
  4. package/dist/lib/browser/chunk-O3BQBYMW.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +101 -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-BYRIQOQT.mjs +205 -0
  9. package/dist/lib/browser/operation-resolver-BYRIQOQT.mjs.map +7 -0
  10. package/dist/lib/browser/react-root-GPTKI5H2.mjs +21 -0
  11. package/dist/lib/browser/react-root-GPTKI5H2.mjs.map +7 -0
  12. package/dist/lib/browser/react-surface-LT5JJTPR.mjs +41 -0
  13. package/dist/lib/browser/react-surface-LT5JJTPR.mjs.map +7 -0
  14. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs +66 -0
  15. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs.map +7 -0
  16. package/dist/lib/browser/state-A3PGDWWZ.mjs +48 -0
  17. package/dist/lib/browser/state-A3PGDWWZ.mjs.map +7 -0
  18. package/dist/lib/browser/url-handler-HTIUY6WL.mjs +152 -0
  19. package/dist/lib/browser/url-handler-HTIUY6WL.mjs.map +7 -0
  20. package/dist/lib/node-esm/chunk-UAWM4B2S.mjs +1166 -0
  21. package/dist/lib/node-esm/chunk-UAWM4B2S.mjs.map +7 -0
  22. package/dist/lib/node-esm/chunk-VIDE5UMB.mjs +31 -0
  23. package/dist/lib/node-esm/chunk-VIDE5UMB.mjs.map +7 -0
  24. package/dist/lib/node-esm/index.mjs +102 -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-BDTFNCS2.mjs +206 -0
  28. package/dist/lib/node-esm/operation-resolver-BDTFNCS2.mjs.map +7 -0
  29. package/dist/lib/node-esm/react-root-GRG2OAI2.mjs +22 -0
  30. package/dist/lib/node-esm/react-root-GRG2OAI2.mjs.map +7 -0
  31. package/dist/lib/node-esm/react-surface-TCUSDIN2.mjs +42 -0
  32. package/dist/lib/node-esm/react-surface-TCUSDIN2.mjs.map +7 -0
  33. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs +68 -0
  34. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs.map +7 -0
  35. package/dist/lib/node-esm/state-ZCFZTTPL.mjs +49 -0
  36. package/dist/lib/node-esm/state-ZCFZTTPL.mjs.map +7 -0
  37. package/dist/lib/node-esm/url-handler-WBVVKVPC.mjs +153 -0
  38. package/dist/lib/node-esm/url-handler-WBVVKVPC.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 +12 -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 +41 -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/MobileLayout/MobileLayout.d.ts +35 -0
  84. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts.map +1 -0
  85. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts +7 -0
  86. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts.map +1 -0
  87. package/dist/types/src/components/MobileLayout/index.d.ts +2 -0
  88. package/dist/types/src/components/MobileLayout/index.d.ts.map +1 -0
  89. package/dist/types/src/components/Popover/Popover.d.ts +4 -0
  90. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -0
  91. package/dist/types/src/components/Popover/index.d.ts +2 -0
  92. package/dist/types/src/components/Popover/index.d.ts.map +1 -0
  93. package/dist/types/src/components/SimpleLayout/AppBar.d.ts +26 -0
  94. package/dist/types/src/components/SimpleLayout/AppBar.d.ts.map +1 -0
  95. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts +47 -0
  96. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts.map +1 -0
  97. package/dist/types/src/components/SimpleLayout/Drawer.d.ts +9 -0
  98. package/dist/types/src/components/SimpleLayout/Drawer.d.ts.map +1 -0
  99. package/dist/types/src/components/SimpleLayout/Main.d.ts +9 -0
  100. package/dist/types/src/components/SimpleLayout/Main.d.ts.map +1 -0
  101. package/dist/types/src/components/SimpleLayout/NavBar.d.ts +18 -0
  102. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -0
  103. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts +43 -0
  104. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts.map +1 -0
  105. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts +3 -0
  106. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts.map +1 -0
  107. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts +47 -0
  108. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts.map +1 -0
  109. package/dist/types/src/components/SimpleLayout/index.d.ts +5 -0
  110. package/dist/types/src/components/SimpleLayout/index.d.ts.map +1 -0
  111. package/dist/types/src/components/Workspace/Workspace.d.ts +11 -0
  112. package/dist/types/src/components/Workspace/Workspace.d.ts.map +1 -0
  113. package/dist/types/src/components/Workspace/index.d.ts +2 -0
  114. package/dist/types/src/components/Workspace/index.d.ts.map +1 -0
  115. package/dist/types/src/components/hooks.d.ts +5 -0
  116. package/dist/types/src/components/hooks.d.ts.map +1 -0
  117. package/dist/types/src/components/index.d.ts +7 -0
  118. package/dist/types/src/components/index.d.ts.map +1 -0
  119. package/dist/types/src/hooks/actions.d.ts +20 -0
  120. package/dist/types/src/hooks/actions.d.ts.map +1 -0
  121. package/dist/types/src/hooks/index.d.ts +7 -0
  122. package/dist/types/src/hooks/index.d.ts.map +1 -0
  123. package/dist/types/src/hooks/useAppBarProps.d.ts +7 -0
  124. package/dist/types/src/hooks/useAppBarProps.d.ts.map +1 -0
  125. package/dist/types/src/hooks/useCompanions.d.ts +12 -0
  126. package/dist/types/src/hooks/useCompanions.d.ts.map +1 -0
  127. package/dist/types/src/hooks/useDrawerActions.d.ts +13 -0
  128. package/dist/types/src/hooks/useDrawerActions.d.ts.map +1 -0
  129. package/dist/types/src/hooks/useNavbarActions.d.ts +14 -0
  130. package/dist/types/src/hooks/useNavbarActions.d.ts.map +1 -0
  131. package/dist/types/src/hooks/useSimpleLayoutState.d.ts +7 -0
  132. package/dist/types/src/hooks/useSimpleLayoutState.d.ts.map +1 -0
  133. package/dist/types/src/index.d.ts +2 -0
  134. package/dist/types/src/index.d.ts.map +1 -0
  135. package/dist/types/src/meta.d.ts +3 -0
  136. package/dist/types/src/meta.d.ts.map +1 -0
  137. package/dist/types/src/translations.d.ts +26 -0
  138. package/dist/types/src/translations.d.ts.map +1 -0
  139. package/dist/types/src/types/capabilities.d.ts +36 -0
  140. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  141. package/dist/types/src/types/events.d.ts +6 -0
  142. package/dist/types/src/types/events.d.ts.map +1 -0
  143. package/dist/types/src/types/index.d.ts +3 -0
  144. package/dist/types/src/types/index.d.ts.map +1 -0
  145. package/dist/types/tsconfig.tsbuildinfo +1 -0
  146. package/package.json +39 -29
  147. package/src/SimpleLayoutPlugin.ts +25 -8
  148. package/src/capabilities/index.ts +3 -0
  149. package/src/capabilities/operation-resolver/operation-resolver.ts +135 -53
  150. package/src/capabilities/react-root/react-root.tsx +2 -2
  151. package/src/capabilities/react-surface/index.ts +7 -0
  152. package/src/capabilities/react-surface/react-surface.tsx +41 -0
  153. package/src/capabilities/spotlight-dismiss/index.ts +7 -0
  154. package/src/{hooks/useSpotlightDismiss.ts → capabilities/spotlight-dismiss/spotlight-dismiss.ts} +31 -40
  155. package/src/capabilities/state/state.tsx +25 -33
  156. package/src/capabilities/url-handler/index.ts +7 -0
  157. package/src/capabilities/url-handler/url-handler.ts +157 -0
  158. package/src/components/ContentError.stories.tsx +1 -1
  159. package/src/components/ContentLoading.stories.tsx +1 -1
  160. package/src/components/Dialog/Dialog.tsx +14 -14
  161. package/src/components/Home/Home.tsx +64 -70
  162. package/src/components/MobileLayout/MobileLayout.stories.tsx +125 -0
  163. package/src/components/MobileLayout/MobileLayout.tsx +305 -0
  164. package/src/components/MobileLayout/index.ts +5 -0
  165. package/src/components/Popover/Popover.tsx +45 -27
  166. package/src/components/SimpleLayout/AppBar.stories.tsx +144 -0
  167. package/src/components/SimpleLayout/AppBar.tsx +101 -0
  168. package/src/components/SimpleLayout/Drawer.tsx +102 -0
  169. package/src/components/SimpleLayout/Main.tsx +53 -57
  170. package/src/components/SimpleLayout/NavBar.stories.tsx +164 -0
  171. package/src/components/SimpleLayout/NavBar.tsx +29 -86
  172. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +24 -18
  173. package/src/components/SimpleLayout/SimpleLayout.tsx +45 -7
  174. package/src/components/SimpleLayout/index.ts +3 -0
  175. package/src/components/Workspace/Workspace.tsx +119 -0
  176. package/src/components/Workspace/index.ts +5 -0
  177. package/src/components/hooks.ts +26 -0
  178. package/src/components/index.ts +2 -0
  179. package/src/hooks/actions.ts +85 -0
  180. package/src/hooks/index.ts +6 -1
  181. package/src/hooks/useAppBarProps.ts +112 -0
  182. package/src/hooks/useCompanions.ts +22 -0
  183. package/src/hooks/useDrawerActions.ts +98 -0
  184. package/src/hooks/useNavbarActions.ts +86 -0
  185. package/src/hooks/useSimpleLayoutState.ts +30 -0
  186. package/src/translations.ts +6 -0
  187. package/src/types/capabilities.ts +20 -4
  188. package/src/types/events.ts +15 -0
  189. package/src/types/index.ts +1 -0
  190. package/src/components/SimpleLayout/Banner.tsx +0 -60
  191. package/src/components/SimpleLayout/NavBarstories.tsx +0 -59
package/package.json CHANGED
@@ -1,19 +1,23 @@
1
1
  {
2
2
  "name": "@dxos/plugin-simple-layout",
3
- "version": "0.0.0",
3
+ "version": "0.8.4-main.1068cf700f",
4
4
  "description": "Simple layout plugin for minimal UI contexts like popover windows.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
13
  "sideEffects": true,
10
14
  "type": "module",
11
15
  "exports": {
12
16
  ".": {
13
- "source": "./src/index.ts",
14
- "types": "./dist/types/src/index.d.ts",
15
17
  "browser": "./dist/lib/browser/index.mjs",
16
- "node": "./dist/lib/node-esm/index.mjs"
18
+ "node": "./dist/lib/node-esm/index.mjs",
19
+ "source": "./src/index.ts",
20
+ "types": "./dist/types/src/index.d.ts"
17
21
  }
18
22
  },
19
23
  "types": "dist/types/src/index.d.ts",
@@ -22,43 +26,49 @@
22
26
  "src"
23
27
  ],
24
28
  "dependencies": {
25
- "@preact-signals/safe-react": "^0.9.0",
29
+ "@effect-atom/atom": "^0.5.1",
30
+ "@effect-atom/atom-react": "^0.5.0",
26
31
  "@radix-ui/react-context": "1.1.1",
27
- "@dxos/app-framework": "0.8.3",
28
- "@dxos/log": "0.8.3",
29
- "@dxos/react-ui-menu": "0.8.3",
30
- "@dxos/live-object": "0.8.3",
31
- "@dxos/plugin-graph": "0.8.3",
32
- "@dxos/operation": "0.0.0",
33
- "@dxos/react-ui-searchlist": "0.8.3",
34
- "@dxos/schema": "0.8.3",
35
- "@dxos/react-ui-attention": "0.8.3",
36
- "@dxos/react-ui-stack": "0.8.3",
37
- "@dxos/util": "0.8.3",
38
- "@dxos/react-ui-mosaic": "0.8.3"
32
+ "@tauri-apps/plugin-deep-link": "^2.2.0",
33
+ "@tauri-apps/plugin-haptics": "^2.3.2",
34
+ "@dxos/app-framework": "0.8.4-main.1068cf700f",
35
+ "@dxos/app-toolkit": "0.8.4-main.1068cf700f",
36
+ "@dxos/async": "0.8.4-main.1068cf700f",
37
+ "@dxos/log": "0.8.4-main.1068cf700f",
38
+ "@dxos/operation": "0.8.4-main.1068cf700f",
39
+ "@dxos/plugin-graph": "0.8.4-main.1068cf700f",
40
+ "@dxos/react-ui-attention": "0.8.4-main.1068cf700f",
41
+ "@dxos/react-ui-menu": "0.8.4-main.1068cf700f",
42
+ "@dxos/react-ui-mosaic": "0.8.4-main.1068cf700f",
43
+ "@dxos/react-ui-searchlist": "0.8.4-main.1068cf700f",
44
+ "@dxos/schema": "0.8.4-main.1068cf700f",
45
+ "@dxos/util": "0.8.4-main.1068cf700f",
46
+ "@dxos/react-ui-stack": "0.8.4-main.1068cf700f"
39
47
  },
40
48
  "devDependencies": {
41
49
  "@types/react": "~19.2.7",
42
50
  "@types/react-dom": "~19.2.3",
43
- "effect": "3.19.11",
51
+ "effect": "3.19.16",
44
52
  "react": "~19.2.3",
45
53
  "react-dom": "~19.2.3",
46
54
  "vite": "7.1.9",
47
- "@dxos/echo-signals": "0.8.3",
48
- "@dxos/plugin-search": "0.8.3",
49
- "@dxos/plugin-client": "0.8.3",
50
- "@dxos/plugin-space": "0.8.3",
51
- "@dxos/plugin-testing": "0.0.0",
52
- "@dxos/ui-theme": "0.0.0",
53
- "@dxos/react-ui": "0.8.3",
54
- "@dxos/storybook-utils": "0.8.3"
55
+ "@dxos/app-graph": "0.8.4-main.1068cf700f",
56
+ "@dxos/plugin-preview": "0.8.4-main.1068cf700f",
57
+ "@dxos/plugin-search": "0.8.4-main.1068cf700f",
58
+ "@dxos/plugin-client": "0.8.4-main.1068cf700f",
59
+ "@dxos/plugin-space": "0.8.4-main.1068cf700f",
60
+ "@dxos/react-ui": "0.8.4-main.1068cf700f",
61
+ "@dxos/storybook-utils": "0.8.4-main.1068cf700f",
62
+ "@dxos/schema": "0.8.4-main.1068cf700f",
63
+ "@dxos/ui-theme": "0.8.4-main.1068cf700f",
64
+ "@dxos/plugin-testing": "0.8.4-main.1068cf700f"
55
65
  },
56
66
  "peerDependencies": {
57
- "effect": "3.19.11",
67
+ "effect": "3.19.16",
58
68
  "react": "~19.2.3",
59
69
  "react-dom": "~19.2.3",
60
- "@dxos/react-ui": "0.8.3",
61
- "@dxos/ui-theme": "0.0.0"
70
+ "@dxos/react-ui": "0.8.4-main.1068cf700f",
71
+ "@dxos/ui-theme": "0.8.4-main.1068cf700f"
62
72
  },
63
73
  "publishConfig": {
64
74
  "access": "public"
@@ -2,11 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capability, Common, Plugin } from '@dxos/app-framework';
5
+ import { ActivationEvent, ActivationEvents, Capability, Plugin } from '@dxos/app-framework';
6
+ import { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';
6
7
 
7
- import { OperationResolver, ReactRoot, type SimpleLayoutStateOptions, State } from './capabilities';
8
+ import { OperationResolver, ReactRoot, ReactSurface, SpotlightDismiss, State, UrlHandler } from './capabilities';
8
9
  import { meta } from './meta';
9
10
  import { translations } from './translations';
11
+ import { SimpleLayoutEvents } from './types';
10
12
 
11
13
  export type SimpleLayoutPluginOptions = {
12
14
  /** Whether running in popover window context (hides mobile-specific UI). */
@@ -14,18 +16,33 @@ export type SimpleLayoutPluginOptions = {
14
16
  };
15
17
 
16
18
  export const SimpleLayoutPlugin = Plugin.define<SimpleLayoutPluginOptions>(meta).pipe(
19
+ AppPlugin.addOperationResolverModule({ activate: OperationResolver }),
20
+ AppPlugin.addTranslationsModule({ translations }),
17
21
  Plugin.addModule(({ isPopover = false }) => ({
18
22
  id: Capability.getModuleTag(State),
19
- activatesOn: Common.ActivationEvent.Startup,
20
- activatesAfter: [Common.ActivationEvent.LayoutReady],
21
- activate: () => State({ initialState: { isPopover } } satisfies SimpleLayoutStateOptions),
23
+ activatesOn: ActivationEvents.Startup,
24
+ activatesAfter: [SimpleLayoutEvents.StateReady, AppActivationEvents.LayoutReady],
25
+ activate: () => State({ initialState: { isPopover } }),
26
+ })),
27
+ Plugin.addModule(({ isPopover = false }) => ({
28
+ id: Capability.getModuleTag(SpotlightDismiss),
29
+ activatesOn: ActivationEvents.Startup,
30
+ activate: () => SpotlightDismiss({ isPopover }),
22
31
  })),
23
32
  Plugin.addModule({
24
33
  id: Capability.getModuleTag(ReactRoot),
25
- activatesOn: Common.ActivationEvent.Startup,
34
+ activatesOn: ActivationEvents.Startup,
26
35
  activate: ReactRoot,
27
36
  }),
28
- Common.Plugin.addOperationResolverModule({ activate: OperationResolver }),
29
- Common.Plugin.addTranslationsModule({ translations }),
37
+ Plugin.addModule({
38
+ id: Capability.getModuleTag(ReactSurface),
39
+ activatesOn: ActivationEvents.Startup,
40
+ activate: ReactSurface,
41
+ }),
42
+ Plugin.addModule({
43
+ id: Capability.getModuleTag(UrlHandler),
44
+ activatesOn: ActivationEvent.allOf(ActivationEvents.OperationInvokerReady, SimpleLayoutEvents.StateReady),
45
+ activate: UrlHandler,
46
+ }),
30
47
  Plugin.make,
31
48
  );
@@ -4,4 +4,7 @@
4
4
 
5
5
  export * from './operation-resolver';
6
6
  export * from './react-root';
7
+ export * from './react-surface';
8
+ export * from './spotlight-dismiss';
7
9
  export * from './state';
10
+ export * from './url-handler';
@@ -4,43 +4,80 @@
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
- import { Capability, Common } from '@dxos/app-framework';
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { LayoutOperation } from '@dxos/app-toolkit';
8
9
  import { Operation, OperationResolver } from '@dxos/operation';
10
+ import { ATTENDABLE_PATH_SEPARATOR } from '@dxos/react-ui-attention';
9
11
 
10
- import { SimpleLayoutState } from '../../types';
12
+ import { type SimpleLayoutState, SimpleLayoutState as SimpleLayoutStateCapability } from '../../types';
13
+
14
+ /** Maximum number of items to keep in navigation history. */
15
+ const MAX_HISTORY_LENGTH = 50;
16
+
17
+ /** Parse entry ID to extract primary ID and variant. */
18
+ const parseEntryId = (entryId: string) => {
19
+ const [id, variant] = entryId.split(ATTENDABLE_PATH_SEPARATOR);
20
+ return { id, variant };
21
+ };
11
22
 
12
23
  export default Capability.makeModule(
13
24
  Effect.fnUntraced(function* () {
14
- return Capability.contributes(Common.Capability.OperationResolver, [
25
+ const registry = yield* Capability.get(Capabilities.AtomRegistry);
26
+ const stateAtom = yield* Capability.get(SimpleLayoutStateCapability);
27
+
28
+ const getState = () => registry.get(stateAtom);
29
+ const updateState = (fn: (current: SimpleLayoutState) => SimpleLayoutState) => {
30
+ registry.set(stateAtom, fn(getState()));
31
+ };
32
+
33
+ return Capability.contributes(Capabilities.OperationResolver, [
34
+ //
35
+ // SetLayoutMode
36
+ //
37
+ // TODO(burdon): No-op for to fix startup bug?
38
+ OperationResolver.make({
39
+ operation: LayoutOperation.SetLayoutMode,
40
+ handler: Effect.fnUntraced(function* () {}),
41
+ }),
42
+
15
43
  //
16
44
  // UpdateSidebar - No-op for simple layout.
17
45
  //
18
46
  OperationResolver.make({
19
- operation: Common.LayoutOperation.UpdateSidebar,
47
+ operation: LayoutOperation.UpdateSidebar,
20
48
  handler: () => Effect.void,
21
49
  }),
22
50
 
23
51
  //
24
- // UpdateComplementary - No-op for simple layout.
52
+ // UpdateComplementary - Controls companion drawer.
25
53
  //
26
54
  OperationResolver.make({
27
- operation: Common.LayoutOperation.UpdateComplementary,
28
- handler: () => Effect.void,
55
+ operation: LayoutOperation.UpdateComplementary,
56
+ handler: Effect.fnUntraced(function* (input) {
57
+ if (input.state === 'closed') {
58
+ updateState((state) => ({
59
+ ...state,
60
+ drawerState: 'closed',
61
+ }));
62
+ }
63
+ }),
29
64
  }),
30
65
 
31
66
  //
32
67
  // UpdateDialog
33
68
  //
34
69
  OperationResolver.make({
35
- operation: Common.LayoutOperation.UpdateDialog,
70
+ operation: LayoutOperation.UpdateDialog,
36
71
  handler: Effect.fnUntraced(function* (input) {
37
- const layout = yield* Capability.get(SimpleLayoutState);
38
- layout.dialogOpen = input.state ?? Boolean(input.subject);
39
- layout.dialogType = input.type ?? 'default';
40
- layout.dialogBlockAlign = input.blockAlign ?? 'center';
41
- layout.dialogOverlayClasses = input.overlayClasses;
42
- layout.dialogOverlayStyle = input.overlayStyle;
43
- layout.dialogContent = input.subject ? { component: input.subject, props: input.props } : null;
72
+ updateState((state) => ({
73
+ ...state,
74
+ dialogOpen: input.state ?? Boolean(input.subject),
75
+ dialogType: input.type ?? 'default',
76
+ dialogBlockAlign: input.blockAlign ?? 'center',
77
+ dialogOverlayClasses: input.overlayClasses,
78
+ dialogOverlayStyle: input.overlayStyle,
79
+ dialogContent: input.subject ? { component: input.subject, props: input.props } : undefined,
80
+ }));
44
81
  }),
45
82
  }),
46
83
 
@@ -48,23 +85,24 @@ export default Capability.makeModule(
48
85
  // UpdatePopover
49
86
  //
50
87
  OperationResolver.make({
51
- operation: Common.LayoutOperation.UpdatePopover,
88
+ operation: LayoutOperation.UpdatePopover,
52
89
  handler: Effect.fnUntraced(function* (input) {
53
- const layout = yield* Capability.get(SimpleLayoutState);
54
- layout.popoverOpen = input.state ?? Boolean(input.subject);
55
- layout.popoverContent =
56
- typeof input.subject === 'string'
57
- ? { component: input.subject, props: input.props }
58
- : input.subject
59
- ? { subject: input.subject }
60
- : undefined;
61
- layout.popoverSide = input.side;
62
- layout.popoverVariant = input.variant;
63
- if (input.variant === 'virtual') {
64
- layout.popoverAnchor = input.anchor;
65
- } else {
66
- layout.popoverAnchorId = input.anchorId;
67
- }
90
+ updateState((state) => ({
91
+ ...state,
92
+ popoverOpen: input.state ?? Boolean(input.subject),
93
+ popoverKind: input.kind ?? 'base',
94
+ popoverTitle: input.kind === 'card' ? input.title : undefined,
95
+ popoverContent:
96
+ typeof input.subject === 'string'
97
+ ? { component: input.subject, props: input.props }
98
+ : input.subject
99
+ ? { subject: input.subject }
100
+ : undefined,
101
+ popoverSide: input.side,
102
+ popoverVariant: input.variant,
103
+ popoverAnchor: input.variant === 'virtual' ? input.anchor : state.popoverAnchor,
104
+ popoverAnchorId: input.variant !== 'virtual' ? input.anchorId : state.popoverAnchorId,
105
+ }));
68
106
  }),
69
107
  }),
70
108
 
@@ -72,16 +110,18 @@ export default Capability.makeModule(
72
110
  // SwitchWorkspace
73
111
  //
74
112
  OperationResolver.make({
75
- operation: Common.LayoutOperation.SwitchWorkspace,
113
+ operation: LayoutOperation.SwitchWorkspace,
76
114
  handler: Effect.fnUntraced(function* (input) {
77
- const layout = yield* Capability.get(SimpleLayoutState);
78
- // TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.
79
- // Ideally this should be worked into the data model in a generic way.
80
- if (!layout.workspace.startsWith('!')) {
81
- layout.previousWorkspace = layout.workspace;
82
- }
83
- layout.workspace = input.subject;
84
- layout.active = undefined;
115
+ updateState((state) => ({
116
+ ...state,
117
+ // TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.
118
+ // Ideally this should be worked into the data model in a generic way.
119
+ previousWorkspace: !state.workspace.startsWith('!') ? state.workspace : state.previousWorkspace,
120
+ workspace: input.subject,
121
+ active: undefined,
122
+ // Clear history when switching workspaces.
123
+ history: [],
124
+ }));
85
125
  }),
86
126
  }),
87
127
 
@@ -89,11 +129,11 @@ export default Capability.makeModule(
89
129
  // RevertWorkspace
90
130
  //
91
131
  OperationResolver.make({
92
- operation: Common.LayoutOperation.RevertWorkspace,
132
+ operation: LayoutOperation.RevertWorkspace,
93
133
  handler: Effect.fnUntraced(function* () {
94
- const layout = yield* Capability.get(SimpleLayoutState);
95
- yield* Operation.invoke(Common.LayoutOperation.SwitchWorkspace, {
96
- subject: layout.previousWorkspace,
134
+ const state = getState();
135
+ yield* Operation.invoke(LayoutOperation.SwitchWorkspace, {
136
+ subject: state.previousWorkspace,
97
137
  });
98
138
  }),
99
139
  }),
@@ -102,10 +142,35 @@ export default Capability.makeModule(
102
142
  // Open
103
143
  //
104
144
  OperationResolver.make({
105
- operation: Common.LayoutOperation.Open,
145
+ operation: LayoutOperation.Open,
106
146
  handler: Effect.fnUntraced(function* (input) {
107
- const layout = yield* Capability.get(SimpleLayoutState);
108
- layout.active = input.subject[0];
147
+ const id = input.subject[0];
148
+ const { id: primaryId, variant } = parseEntryId(id);
149
+ const state = getState();
150
+
151
+ // Only treat as companion when opening a variant of the current workspace/active (e.g. object~comments).
152
+ // IDs like settings~spaceId are alternate-tree nodes and should navigate main content, not open the drawer.
153
+ // TODO(wittjosiah): Factor out the change-companion operation from deck to a common layout operation.
154
+ const isCompanionOfCurrent = variant && (primaryId === state.workspace || primaryId === state.active);
155
+ if (isCompanionOfCurrent) {
156
+ updateState((state) => ({
157
+ ...state,
158
+ companionVariant: variant,
159
+ drawerState: state.drawerState === 'closed' || !state.drawerState ? 'open' : state.drawerState,
160
+ }));
161
+ } else {
162
+ // Regular navigation - update active and history (use full id for alternate-tree nodes).
163
+ updateState((state) => {
164
+ const newHistory = state.active ? [...state.history, state.active] : state.history;
165
+ const trimmedHistory =
166
+ newHistory.length > MAX_HISTORY_LENGTH ? newHistory.slice(-MAX_HISTORY_LENGTH) : newHistory;
167
+ return {
168
+ ...state,
169
+ active: id,
170
+ history: trimmedHistory,
171
+ };
172
+ });
173
+ }
109
174
  }),
110
175
  }),
111
176
 
@@ -113,10 +178,25 @@ export default Capability.makeModule(
113
178
  // Close
114
179
  //
115
180
  OperationResolver.make({
116
- operation: Common.LayoutOperation.Close,
181
+ operation: LayoutOperation.Close,
117
182
  handler: Effect.fnUntraced(function* () {
118
- const layout = yield* Capability.get(SimpleLayoutState);
119
- layout.active = undefined;
183
+ updateState((state) => {
184
+ // Pop from history if available.
185
+ if (state.history.length > 0) {
186
+ const newHistory = [...state.history];
187
+ const previousActive = newHistory.pop();
188
+ return {
189
+ ...state,
190
+ active: previousActive,
191
+ history: newHistory,
192
+ };
193
+ }
194
+ // No history, just clear active.
195
+ return {
196
+ ...state,
197
+ active: undefined,
198
+ };
199
+ });
120
200
  }),
121
201
  }),
122
202
 
@@ -124,10 +204,12 @@ export default Capability.makeModule(
124
204
  // Set
125
205
  //
126
206
  OperationResolver.make({
127
- operation: Common.LayoutOperation.Set,
207
+ operation: LayoutOperation.Set,
128
208
  handler: Effect.fnUntraced(function* (input) {
129
- const layout = yield* Capability.get(SimpleLayoutState);
130
- layout.active = input.subject[0];
209
+ updateState((state) => ({
210
+ ...state,
211
+ active: input.subject[0],
212
+ }));
131
213
  }),
132
214
  }),
133
215
  ]);
@@ -5,14 +5,14 @@
5
5
  import * as Effect from 'effect/Effect';
6
6
  import React from 'react';
7
7
 
8
- import { Capability, Common } from '@dxos/app-framework';
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
9
 
10
10
  import { SimpleLayout } from '../../components';
11
11
  import { meta } from '../../meta';
12
12
 
13
13
  export default Capability.makeModule(() =>
14
14
  Effect.succeed(
15
- Capability.contributes(Common.Capability.ReactRoot, {
15
+ Capability.contributes(Capabilities.ReactRoot, {
16
16
  id: meta.id,
17
17
  root: () => {
18
18
  return <SimpleLayout />;
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Capability } from '@dxos/app-framework';
6
+
7
+ export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -0,0 +1,41 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import React from 'react';
7
+
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { Node } from '@dxos/plugin-graph';
11
+
12
+ import { Home, Workspace } from '../../components';
13
+ import { meta } from '../../meta';
14
+
15
+ type SurfaceData = {
16
+ attendableId: string;
17
+ properties: Record<string, any>;
18
+ };
19
+
20
+ const ALLOWED_DISPOSITIONS = ['workspace', 'user-account', 'pin-end', 'alternate-tree'];
21
+
22
+ export default Capability.makeModule(() =>
23
+ Effect.succeed(
24
+ Capability.contributes(Capabilities.ReactSurface, [
25
+ Surface.create({
26
+ id: `${meta.id}/home`,
27
+ role: 'article',
28
+ filter: (data): data is SurfaceData => data.attendableId === Node.RootId,
29
+ component: () => <Home />,
30
+ }),
31
+ Surface.create({
32
+ id: `${meta.id}/workspace-article`,
33
+ role: 'article',
34
+ position: 'fallback',
35
+ filter: (data): data is SurfaceData =>
36
+ ALLOWED_DISPOSITIONS.includes((data.properties as Record<string, any>)?.disposition),
37
+ component: ({ data }) => <Workspace id={data.attendableId} />,
38
+ }),
39
+ ]),
40
+ ),
41
+ );
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Capability } from '@dxos/app-framework';
6
+
7
+ export const SpotlightDismiss = Capability.lazy('SpotlightDismiss', () => import('./spotlight-dismiss'));
@@ -5,14 +5,14 @@
5
5
  // Based on the frontend-driven dismiss pattern from:
6
6
  // https://github.com/Jedliu/tauri-template-demo
7
7
 
8
- import { useEffect } from 'react';
8
+ import * as Effect from 'effect/Effect';
9
9
 
10
+ import { Capabilities, Capability } from '@dxos/app-framework';
10
11
  import { log } from '@dxos/log';
11
12
  import { isTauri } from '@dxos/util';
12
13
 
13
14
  /**
14
15
  * Get the Tauri window API from the global object.
15
- * Returns undefined if not running in Tauri.
16
16
  */
17
17
  const getTauriWindow = (): any => {
18
18
  const tauri = (globalThis as any).__TAURI__;
@@ -21,60 +21,46 @@ const getTauriWindow = (): any => {
21
21
 
22
22
  /**
23
23
  * Get the Tauri core API (invoke) from the global object.
24
- * Returns undefined if not running in Tauri.
25
24
  */
26
25
  const getTauriCore = (): any => {
27
26
  const tauri = (globalThis as any).__TAURI__;
28
27
  return tauri?.core;
29
28
  };
30
29
 
30
+ export type SpotlightDismissOptions = {
31
+ /** Whether running in popover window context. */
32
+ isPopover?: boolean;
33
+ };
34
+
31
35
  /**
32
- * Hook to set up spotlight panel dismiss behavior.
36
+ * Capability that sets up spotlight panel dismiss behavior.
33
37
  * When running in Tauri popover mode, listens for focus loss and Escape key
34
- * to dismiss the spotlight panel.
38
+ * to dismiss the spotlight panel. Runs at startup before React renders.
35
39
  */
36
- export const useSpotlightDismiss = (isPopover: boolean | undefined) => {
37
- // Handle blur (click outside) to dismiss spotlight.
38
- useEffect(() => {
40
+ export default Capability.makeModule(({ isPopover = false }: SpotlightDismissOptions = {}) =>
41
+ Effect.promise(async () => {
39
42
  if (!isPopover || !isTauri()) {
40
- return;
43
+ return [];
41
44
  }
42
45
 
43
- let cleanup: (() => void) | undefined;
44
-
45
- const setup = async () => {
46
- try {
47
- const tauriWindow = getTauriWindow();
48
- const tauriCore = getTauriCore();
49
- if (!tauriWindow || !tauriCore) {
50
- return;
51
- }
52
-
46
+ // Set up focus listener.
47
+ let focusCleanup: (() => void) | undefined;
48
+ try {
49
+ const tauriWindow = getTauriWindow();
50
+ const tauriCore = getTauriCore();
51
+ if (tauriWindow && tauriCore) {
53
52
  const win = tauriWindow.getCurrentWindow();
54
- const unlisten = await win.onFocusChanged(async ({ payload }: { payload: boolean }) => {
53
+ focusCleanup = await win.onFocusChanged(async ({ payload }: { payload: boolean }) => {
55
54
  if (!payload) {
56
55
  await tauriCore.invoke('hide_spotlight');
57
56
  }
58
57
  });
59
- cleanup = unlisten;
60
- } catch (err) {
61
- log.catch(err);
62
58
  }
63
- };
64
-
65
- void setup();
66
-
67
- return () => {
68
- cleanup?.();
69
- };
70
- }, [isPopover]);
71
-
72
- // Handle Escape key to dismiss spotlight.
73
- useEffect(() => {
74
- if (!isPopover || !isTauri()) {
75
- return;
59
+ } catch (err) {
60
+ log.catch(err);
76
61
  }
77
62
 
63
+ // Set up Escape key listener.
78
64
  const handleKeyDown = async (event: KeyboardEvent) => {
79
65
  if (event.key === 'Escape') {
80
66
  event.preventDefault();
@@ -88,8 +74,13 @@ export const useSpotlightDismiss = (isPopover: boolean | undefined) => {
88
74
  }
89
75
  }
90
76
  };
91
-
92
77
  window.addEventListener('keydown', handleKeyDown);
93
- return () => window.removeEventListener('keydown', handleKeyDown);
94
- }, [isPopover]);
95
- };
78
+
79
+ return Capability.contributes(Capabilities.Null, null, () =>
80
+ Effect.sync(() => {
81
+ focusCleanup?.();
82
+ window.removeEventListener('keydown', handleKeyDown);
83
+ }),
84
+ );
85
+ }),
86
+ );