@dxos/app-framework 0.7.5-main.9d2a38b → 0.7.5-main.e9bb01b

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 (181) hide show
  1. package/dist/lib/browser/app-graph-builder-F7VZ6LRN.mjs +137 -0
  2. package/dist/lib/browser/app-graph-builder-F7VZ6LRN.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-GNLU3GAU.mjs → chunk-ATRNTMSS.mjs} +623 -819
  4. package/dist/lib/browser/chunk-ATRNTMSS.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-LDJ3T4V3.mjs +32 -0
  6. package/dist/lib/browser/chunk-LDJ3T4V3.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-WS6SU6HI.mjs +285 -0
  8. package/dist/lib/browser/chunk-WS6SU6HI.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +57 -74
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs +11 -0
  12. package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs.map +7 -0
  13. package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs +38 -0
  14. package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs.map +7 -0
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/store-QU2IKFAI.mjs +19 -0
  17. package/dist/lib/browser/store-QU2IKFAI.mjs.map +7 -0
  18. package/dist/lib/browser/testing/index.mjs +10 -3
  19. package/dist/lib/browser/testing/index.mjs.map +3 -3
  20. package/dist/lib/browser/worker.mjs +77 -0
  21. package/dist/lib/browser/worker.mjs.map +7 -0
  22. package/dist/lib/node/app-graph-builder-JGBADFF7.cjs +146 -0
  23. package/dist/lib/node/app-graph-builder-JGBADFF7.cjs.map +7 -0
  24. package/dist/lib/node/chunk-QLVQ6PND.cjs +58 -0
  25. package/dist/lib/node/chunk-QLVQ6PND.cjs.map +7 -0
  26. package/dist/lib/node/chunk-WKC6YMEQ.cjs +1433 -0
  27. package/dist/lib/node/chunk-WKC6YMEQ.cjs.map +7 -0
  28. package/dist/lib/node/chunk-WRWRZKZU.cjs +308 -0
  29. package/dist/lib/node/chunk-WRWRZKZU.cjs.map +7 -0
  30. package/dist/lib/node/index.cjs +106 -118
  31. package/dist/lib/node/index.cjs.map +4 -4
  32. package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs +32 -0
  33. package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs.map +7 -0
  34. package/dist/lib/node/intent-resolver-3TKCXP4S.cjs +45 -0
  35. package/dist/lib/node/intent-resolver-3TKCXP4S.cjs.map +7 -0
  36. package/dist/lib/node/meta.json +1 -1
  37. package/dist/lib/node/store-4QMUUU2A.cjs +34 -0
  38. package/dist/lib/node/store-4QMUUU2A.cjs.map +7 -0
  39. package/dist/lib/node/testing/index.cjs +15 -8
  40. package/dist/lib/node/testing/index.cjs.map +3 -3
  41. package/dist/lib/node/worker.cjs +99 -0
  42. package/dist/lib/node/worker.cjs.map +7 -0
  43. package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs +138 -0
  44. package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs.map +7 -0
  45. package/dist/lib/node-esm/{chunk-KPMTPXQI.mjs → chunk-44J2VZBB.mjs} +623 -819
  46. package/dist/lib/node-esm/chunk-44J2VZBB.mjs.map +7 -0
  47. package/dist/lib/node-esm/chunk-CNJYZNSL.mjs +34 -0
  48. package/dist/lib/node-esm/chunk-CNJYZNSL.mjs.map +7 -0
  49. package/dist/lib/node-esm/chunk-HTLXL32I.mjs +286 -0
  50. package/dist/lib/node-esm/chunk-HTLXL32I.mjs.map +7 -0
  51. package/dist/lib/node-esm/index.mjs +57 -74
  52. package/dist/lib/node-esm/index.mjs.map +4 -4
  53. package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs +12 -0
  54. package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs.map +7 -0
  55. package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs +39 -0
  56. package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs.map +7 -0
  57. package/dist/lib/node-esm/meta.json +1 -1
  58. package/dist/lib/node-esm/store-VWDAYUQY.mjs +20 -0
  59. package/dist/lib/node-esm/store-VWDAYUQY.mjs.map +7 -0
  60. package/dist/lib/node-esm/testing/index.mjs +10 -3
  61. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  62. package/dist/lib/node-esm/worker.mjs +78 -0
  63. package/dist/lib/node-esm/worker.mjs.map +7 -0
  64. package/dist/types/src/App.d.ts.map +1 -1
  65. package/dist/types/src/common/capabilities.d.ts +63 -110
  66. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  67. package/dist/types/src/common/events.d.ts +8 -1
  68. package/dist/types/src/common/events.d.ts.map +1 -1
  69. package/dist/types/src/common/file.d.ts +1 -1
  70. package/dist/types/src/common/file.d.ts.map +1 -1
  71. package/dist/types/src/common/graph.d.ts +2 -2
  72. package/dist/types/src/common/graph.d.ts.map +1 -1
  73. package/dist/types/src/common/index.d.ts +0 -1
  74. package/dist/types/src/common/index.d.ts.map +1 -1
  75. package/dist/types/src/common/layout.d.ts +204 -121
  76. package/dist/types/src/common/layout.d.ts.map +1 -1
  77. package/dist/types/src/common/surface.d.ts +3 -3
  78. package/dist/types/src/common/surface.d.ts.map +1 -1
  79. package/dist/types/src/common/translations.d.ts +7 -7
  80. package/dist/types/src/common/translations.d.ts.map +1 -1
  81. package/dist/types/src/core/capabilities.d.ts +6 -2
  82. package/dist/types/src/core/capabilities.d.ts.map +1 -1
  83. package/dist/types/src/core/manager.d.ts +2 -9
  84. package/dist/types/src/core/manager.d.ts.map +1 -1
  85. package/dist/types/src/core/plugin.d.ts +5 -2
  86. package/dist/types/src/core/plugin.d.ts.map +1 -1
  87. package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -1
  88. package/dist/types/src/playground/generator/generator.d.ts +2 -0
  89. package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
  90. package/dist/types/src/playground/generator/plugin.d.ts.map +1 -1
  91. package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -1
  92. package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
  93. package/dist/types/src/playground/logger/schema.d.ts +1 -1
  94. package/dist/types/src/playground/logger/schema.d.ts.map +1 -1
  95. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
  96. package/dist/types/src/plugin-intent/actions.d.ts +1 -1
  97. package/dist/types/src/plugin-intent/actions.d.ts.map +1 -1
  98. package/dist/types/src/plugin-intent/index.d.ts +0 -1
  99. package/dist/types/src/plugin-intent/index.d.ts.map +1 -1
  100. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +27 -20
  101. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
  102. package/dist/types/src/plugin-intent/intent.d.ts +3 -3
  103. package/dist/types/src/plugin-intent/intent.d.ts.map +1 -1
  104. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
  105. package/dist/types/src/plugin-settings/actions.d.ts +11 -1
  106. package/dist/types/src/plugin-settings/actions.d.ts.map +1 -1
  107. package/dist/types/src/plugin-settings/app-graph-builder.d.ts +197 -0
  108. package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -0
  109. package/dist/types/src/plugin-settings/intent-resolver.d.ts +4 -0
  110. package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +1 -0
  111. package/dist/types/src/plugin-settings/store.d.ts +5 -0
  112. package/dist/types/src/plugin-settings/store.d.ts.map +1 -0
  113. package/dist/types/src/plugin-settings/translations.d.ts +11 -0
  114. package/dist/types/src/plugin-settings/translations.d.ts.map +1 -0
  115. package/dist/types/src/{plugin-intent → react}/IntentContext.d.ts +1 -1
  116. package/dist/types/src/react/IntentContext.d.ts.map +1 -0
  117. package/dist/types/src/react/Surface.d.ts.map +1 -1
  118. package/dist/types/src/react/Surface.stories.d.ts +16 -0
  119. package/dist/types/src/react/Surface.stories.d.ts.map +1 -0
  120. package/dist/types/src/react/common.d.ts +12 -0
  121. package/dist/types/src/react/common.d.ts.map +1 -0
  122. package/dist/types/src/react/index.d.ts +2 -0
  123. package/dist/types/src/react/index.d.ts.map +1 -1
  124. package/dist/types/src/react/useIntentResolver.d.ts +3 -0
  125. package/dist/types/src/react/useIntentResolver.d.ts.map +1 -0
  126. package/dist/types/src/testing/withPluginManager.d.ts +1 -1
  127. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  128. package/dist/types/src/worker.d.ts +4 -0
  129. package/dist/types/src/worker.d.ts.map +1 -0
  130. package/package.json +26 -20
  131. package/project.json +3 -3
  132. package/src/App.tsx +15 -14
  133. package/src/common/capabilities.ts +20 -11
  134. package/src/common/events.ts +10 -1
  135. package/src/common/file.ts +1 -1
  136. package/src/common/graph.ts +2 -2
  137. package/src/common/index.ts +0 -1
  138. package/src/common/layout.ts +194 -126
  139. package/src/common/surface.ts +2 -2
  140. package/src/common/translations.ts +7 -8
  141. package/src/core/capabilities.ts +16 -7
  142. package/src/core/manager.test.ts +22 -73
  143. package/src/core/manager.ts +105 -91
  144. package/src/core/plugin.ts +6 -3
  145. package/src/playground/debug/plugin.ts +1 -1
  146. package/src/playground/generator/Toolbar.tsx +11 -11
  147. package/src/playground/generator/generator.ts +25 -0
  148. package/src/playground/generator/plugin.ts +6 -1
  149. package/src/playground/layout/plugin.ts +1 -1
  150. package/src/playground/logger/Toolbar.tsx +2 -1
  151. package/src/playground/logger/plugin.ts +6 -3
  152. package/src/playground/logger/schema.ts +1 -1
  153. package/src/plugin-intent/IntentPlugin.tsx +3 -43
  154. package/src/plugin-intent/actions.ts +1 -1
  155. package/src/plugin-intent/index.ts +0 -1
  156. package/src/plugin-intent/intent-dispatcher.test.ts +48 -29
  157. package/src/plugin-intent/intent-dispatcher.ts +76 -41
  158. package/src/plugin-intent/intent.ts +5 -5
  159. package/src/plugin-settings/SettingsPlugin.ts +19 -13
  160. package/src/plugin-settings/actions.ts +11 -1
  161. package/src/plugin-settings/app-graph-builder.ts +122 -0
  162. package/src/plugin-settings/intent-resolver.ts +28 -0
  163. package/src/plugin-settings/store.ts +20 -0
  164. package/src/plugin-settings/translations.ts +17 -0
  165. package/src/{plugin-intent → react}/IntentContext.tsx +2 -2
  166. package/src/react/Surface.stories.tsx +96 -0
  167. package/src/react/Surface.tsx +11 -8
  168. package/src/react/common.ts +12 -0
  169. package/src/react/index.ts +2 -0
  170. package/src/react/useIntentResolver.ts +22 -0
  171. package/src/testing/withPluginManager.tsx +11 -3
  172. package/src/worker.ts +11 -0
  173. package/tsconfig.json +3 -3
  174. package/dist/lib/browser/chunk-GNLU3GAU.mjs.map +0 -7
  175. package/dist/lib/node/chunk-FBA4BB3J.cjs +0 -1639
  176. package/dist/lib/node/chunk-FBA4BB3J.cjs.map +0 -7
  177. package/dist/lib/node-esm/chunk-KPMTPXQI.mjs.map +0 -7
  178. package/dist/types/src/common/navigation.d.ts +0 -241
  179. package/dist/types/src/common/navigation.d.ts.map +0 -1
  180. package/dist/types/src/plugin-intent/IntentContext.d.ts.map +0 -1
  181. package/src/common/navigation.ts +0 -199
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/app-framework",
3
- "version": "0.7.5-main.9d2a38b",
3
+ "version": "0.7.5-main.e9bb01b",
4
4
  "description": "A framework for building applications from composible plugins.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -17,6 +17,11 @@
17
17
  "types": "./dist/types/src/testing/index.d.ts",
18
18
  "browser": "./dist/lib/browser/testing/index.mjs",
19
19
  "node": "./dist/lib/node-esm/testing/index.mjs"
20
+ },
21
+ "./worker": {
22
+ "types": "./dist/types/src/worker.d.ts",
23
+ "browser": "./dist/lib/browser/worker.mjs",
24
+ "node": "./dist/lib/node-esm/worker.mjs"
20
25
  }
21
26
  },
22
27
  "types": "dist/types/src/index.d.ts",
@@ -24,38 +29,39 @@
24
29
  "*": {
25
30
  "./testing": [
26
31
  "dist/types/src/testing/index.d.ts"
32
+ ],
33
+ "./worker": [
34
+ "dist/types/src/worker.d.ts"
27
35
  ]
28
36
  }
29
37
  },
30
38
  "dependencies": {
31
39
  "@effect/schema": "^0.75.5",
32
- "@phosphor-icons/react": "^2.1.5",
33
40
  "@preact/signals-core": "^1.6.0",
34
41
  "effect": "^3.12.1",
35
- "zod": "^3.22.4",
36
- "@dxos/async": "0.7.5-main.9d2a38b",
37
- "@dxos/app-graph": "0.7.5-main.9d2a38b",
38
- "@dxos/client-protocol": "0.7.5-main.9d2a38b",
39
- "@dxos/context": "0.7.5-main.9d2a38b",
40
- "@dxos/debug": "0.7.5-main.9d2a38b",
41
- "@dxos/echo-schema": "0.7.5-main.9d2a38b",
42
- "@dxos/live-object": "0.7.5-main.9d2a38b",
43
- "@dxos/invariant": "0.7.5-main.9d2a38b",
44
- "@dxos/local-storage": "0.7.5-main.9d2a38b",
45
- "@dxos/react-hooks": "0.7.5-main.9d2a38b",
46
- "@dxos/storybook-utils": "0.7.5-main.9d2a38b",
47
- "@dxos/util": "0.7.5-main.9d2a38b",
48
- "@dxos/log": "0.7.5-main.9d2a38b"
42
+ "@dxos/app-graph": "0.7.5-main.e9bb01b",
43
+ "@dxos/async": "0.7.5-main.e9bb01b",
44
+ "@dxos/client-protocol": "0.7.5-main.e9bb01b",
45
+ "@dxos/invariant": "0.7.5-main.e9bb01b",
46
+ "@dxos/live-object": "0.7.5-main.e9bb01b",
47
+ "@dxos/debug": "0.7.5-main.e9bb01b",
48
+ "@dxos/local-storage": "0.7.5-main.e9bb01b",
49
+ "@dxos/log": "0.7.5-main.e9bb01b",
50
+ "@dxos/react-hooks": "0.7.5-main.e9bb01b",
51
+ "@dxos/util": "0.7.5-main.e9bb01b"
49
52
  },
50
53
  "devDependencies": {
54
+ "@phosphor-icons/react": "^2.1.5",
51
55
  "@types/react": "~18.2.0",
52
56
  "react": "~18.2.0",
53
- "@dxos/echo-signals": "0.7.5-main.9d2a38b",
54
- "@dxos/react-ui": "0.7.5-main.9d2a38b",
55
- "@dxos/react-ui-syntax-highlighter": "0.7.5-main.9d2a38b"
57
+ "@dxos/echo-signals": "0.7.5-main.e9bb01b",
58
+ "@dxos/random": "0.7.5-main.e9bb01b",
59
+ "@dxos/echo-schema": "0.7.5-main.e9bb01b",
60
+ "@dxos/react-ui": "0.7.5-main.e9bb01b",
61
+ "@dxos/react-ui-syntax-highlighter": "0.7.5-main.e9bb01b",
62
+ "@dxos/storybook-utils": "0.7.5-main.e9bb01b"
56
63
  },
57
64
  "peerDependencies": {
58
- "@phosphor-icons/react": "^2.1.5",
59
65
  "react": "~18.2.0"
60
66
  },
61
67
  "publishConfig": {
package/project.json CHANGED
@@ -12,7 +12,8 @@
12
12
  "options": {
13
13
  "entryPoints": [
14
14
  "{projectRoot}/src/index.ts",
15
- "{projectRoot}/src/testing/index.ts"
15
+ "{projectRoot}/src/testing/index.ts",
16
+ "{projectRoot}/src/worker.ts"
16
17
  ]
17
18
  }
18
19
  },
@@ -20,7 +21,6 @@
20
21
  "test": {}
21
22
  },
22
23
  "implicitDependencies": [
23
- "esbuild",
24
- "node-std"
24
+ "esbuild"
25
25
  ]
26
26
  }
package/src/App.tsx CHANGED
@@ -11,7 +11,7 @@ import { create } from '@dxos/live-object';
11
11
  import { Capabilities, Events } from './common';
12
12
  import { PluginManager, type PluginManagerOptions, type Plugin } from './core';
13
13
  import { topologicalSort } from './helpers';
14
- import { ErrorBoundary, PluginManagerProvider } from './react';
14
+ import { ErrorBoundary, PluginManagerProvider, useCapabilities } from './react';
15
15
 
16
16
  const ENABLED_KEY = 'dxos.org/app-framework/enabled';
17
17
 
@@ -96,21 +96,27 @@ export const createApp = ({
96
96
 
97
97
  setupDevtools(manager);
98
98
 
99
+ // TODO(wittjosiah): Factor out such that this could be called per surface role when attempting to render.
100
+ void manager.activate(Events.SetupSurfaces);
99
101
  void manager.activate(Events.Startup);
100
102
 
101
103
  return () => (
102
104
  <ErrorBoundary fallback={fallback}>
103
- <App placeholder={placeholder} manager={manager} state={state} />
105
+ <PluginManagerProvider value={manager}>
106
+ <App placeholder={placeholder} state={state} />
107
+ </PluginManagerProvider>
104
108
  </ErrorBoundary>
105
109
  );
106
110
  };
107
111
 
108
112
  type AppProps = Required<Pick<CreateAppOptions, 'placeholder'>> & {
109
- manager: PluginManager;
110
113
  state: { ready: boolean; error: unknown };
111
114
  };
112
115
 
113
- const App = ({ placeholder, manager, state }: AppProps) => {
116
+ const App = ({ placeholder, state }: AppProps) => {
117
+ const reactContexts = useCapabilities(Capabilities.ReactContext);
118
+ const reactRoots = useCapabilities(Capabilities.ReactRoot);
119
+
114
120
  if (state.error) {
115
121
  // This trigger the error boundary to provide UI feedback for the startup error.
116
122
  throw state.error;
@@ -121,18 +127,13 @@ const App = ({ placeholder, manager, state }: AppProps) => {
121
127
  return <>{placeholder}</>;
122
128
  }
123
129
 
124
- const reactContexts = manager.context.requestCapabilities(Capabilities.ReactContext);
125
- const reactRoots = manager.context.requestCapabilities(Capabilities.ReactRoot);
126
-
127
130
  const ComposedContext = composeContexts(reactContexts);
128
131
  return (
129
- <PluginManagerProvider value={manager}>
130
- <ComposedContext>
131
- {reactRoots.map(({ id, root: Component }) => (
132
- <Component key={id} />
133
- ))}
134
- </ComposedContext>
135
- </PluginManagerProvider>
132
+ <ComposedContext>
133
+ {reactRoots.map(({ id, root: Component }) => (
134
+ <Component key={id} />
135
+ ))}
136
+ </ComposedContext>
136
137
  );
137
138
  };
138
139
 
@@ -2,18 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { type Schema as S } from '@effect/schema';
5
6
  import { type FC, type PropsWithChildren } from 'react';
6
7
 
7
8
  import { type GraphBuilder } from '@dxos/app-graph';
8
9
  import { type Space } from '@dxos/client-protocol';
9
- import { type S } from '@dxos/echo-schema';
10
10
  import { type RootSettingsStore } from '@dxos/local-storage';
11
- import { type DeepReadonly } from '@dxos/util';
12
11
 
13
12
  import { type FileInfo } from './file';
14
13
  import { type NodeSerializer } from './graph';
15
- import { type Layout } from './layout';
16
- import { type LayoutParts } from './navigation';
17
14
  import { type SurfaceDefinition } from './surface';
18
15
  import { type Resource } from './translations';
19
16
  import { defineCapability, type PluginManager } from '../core';
@@ -40,13 +37,25 @@ export namespace Capabilities {
40
37
  'dxos.org/app-framework/capability/intent-dispatcher',
41
38
  );
42
39
 
43
- export const Layout = defineCapability<Readonly<Layout>>('dxos.org/app-framework/capability/layout');
44
- export const MutableLayout = defineCapability<Layout>('dxos.org/app-framework/capability/layout');
45
-
46
- export type MutableLocation = { active: LayoutParts; closed: string[] };
47
- export type Location = DeepReadonly<MutableLocation>;
48
- export const Location = defineCapability<Location>('dxos.org/app-framework/capability/location');
49
- export const MutableLocation = defineCapability<MutableLocation>('dxos.org/app-framework/capability/location');
40
+ export type Layout = Readonly<{
41
+ mode: string;
42
+ dialogOpen: boolean;
43
+ sidebarOpen: boolean;
44
+ complementarySidebarOpen: boolean;
45
+ /**
46
+ * Identifiers of items which are currently active in the application.
47
+ */
48
+ active: string[];
49
+ /**
50
+ * Identifiers of items which were previously active in the application.
51
+ */
52
+ inactive: string[];
53
+ /**
54
+ * Identifier of the item which should be scrolled into view.
55
+ */
56
+ scrollIntoView: string | undefined;
57
+ }>;
58
+ export const Layout = defineCapability<Layout>('dxos.org/app-framework/capability/layout');
50
59
 
51
60
  export const Translations = defineCapability<Readonly<Resource[]>>('dxos.org/app-framework/capability/translations');
52
61
 
@@ -15,6 +15,16 @@ export namespace Events {
15
15
  // Dependent Events
16
16
  //
17
17
 
18
+ /**
19
+ * Fired to load any newly available surfaces.
20
+ */
21
+ export const SetupSurfaces = defineEvent('dxos.org/app-framework/event/setup-surfaces');
22
+
23
+ /**
24
+ * Fired to load any newly available metadata.
25
+ */
26
+ export const SetupMetadata = defineEvent('dxos.org/app-framework/event/setup-metadata');
27
+
18
28
  /**
19
29
  * Fired before the intent dispatcher is activated.
20
30
  */
@@ -59,5 +69,4 @@ export namespace Events {
59
69
  */
60
70
  export const createStateEvent = (specifier: string) => defineEvent('dxos.org/app-framework/event/state', specifier);
61
71
  export const LayoutReady = createStateEvent(Capabilities.Layout.identifier);
62
- export const LocationReady = createStateEvent(Capabilities.Location.identifier);
63
72
  }
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { S } from '@dxos/echo-schema';
5
+ import { Schema as S } from '@effect/schema';
6
6
 
7
7
  // TODO(burdon): See Accept attribute (uses MIME types).
8
8
  // E.g., 'image/*': ['.jpg', '.jpeg', '.png', '.gif'],
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import type { Node } from '@dxos/app-graph';
6
- import { type MaybePromise } from '@dxos/util';
6
+ import { type MaybePromise, type Position } from '@dxos/util';
7
7
 
8
8
  // TODO(wittjosiah): Factor out.
9
9
  export type SerializedNode = {
@@ -16,7 +16,7 @@ export type SerializedNode = {
16
16
  export type NodeSerializer<T = any> = {
17
17
  inputType: string;
18
18
  outputType: string;
19
- disposition?: 'hoist' | 'fallback';
19
+ position?: Position;
20
20
 
21
21
  /**
22
22
  * Takes a node and serializes it into a format that can be stored.
@@ -7,6 +7,5 @@ export * from './events';
7
7
  export * from './file';
8
8
  export * from './graph';
9
9
  export * from './layout';
10
- export * from './navigation';
11
10
  export * from './surface';
12
11
  export * from './translations';
@@ -2,83 +2,10 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { S } from '@dxos/echo-schema';
5
+ import { Schema as S } from '@effect/schema';
6
6
 
7
7
  import { Label } from '../plugin-intent';
8
8
 
9
- //
10
- // Provides
11
- //
12
-
13
- export const Toast = S.Struct({
14
- id: S.String,
15
- title: S.optional(Label),
16
- description: S.optional(Label),
17
- icon: S.optional(S.String),
18
- duration: S.optional(S.Number),
19
- closeLabel: S.optional(Label),
20
- actionLabel: S.optional(Label),
21
- actionAlt: S.optional(Label),
22
- // TODO(wittjosiah): Make class with customizable method?
23
- onAction: S.optional(S.Any),
24
- });
25
-
26
- export type Toast = S.Schema.Type<typeof Toast>;
27
-
28
- /**
29
- * Basic state provided by a layout plugin.
30
- *
31
- * Layout provides the state of global UI landmarks, such as the sidebar, dialog, and popover.
32
- * Generally only one dialog or popover should be open at a time, a layout plugin should manage this.
33
- * For other landmarks, such as toasts, rendering them in the layout prevents them from unmounting when navigating.
34
- */
35
-
36
- const LayoutMode = S.Union(S.Literal('deck'), S.Literal('solo'), S.Literal('fullscreen'));
37
- export const isLayoutMode = (value: any): value is LayoutMode => S.is(LayoutMode)(value);
38
- export type LayoutMode = S.Schema.Type<typeof LayoutMode>;
39
-
40
- export const Layout = S.mutable(
41
- S.Struct({
42
- layoutMode: LayoutMode,
43
-
44
- sidebarOpen: S.Boolean,
45
- complementarySidebarOpen: S.Boolean,
46
- /**
47
- * @deprecated Data to be passed to the complementary sidebar Surface.
48
- */
49
- complementarySidebarContent: S.optional(S.Any),
50
-
51
- dialogOpen: S.Boolean,
52
- /**
53
- * Data to be passed to the dialog Surface.
54
- */
55
- dialogContent: S.optional(S.Any),
56
- // TODO(wittjosiah): Custom properties?
57
- dialogBlockAlign: S.optional(S.Literal('start', 'center')),
58
- dialogType: S.optional(S.Literal('default', 'alert')),
59
-
60
- popoverOpen: S.Boolean,
61
- /**
62
- * Data to be passed to the popover Surface.
63
- */
64
- popoverContent: S.optional(S.Any),
65
- popoverAnchorId: S.optional(S.String),
66
-
67
- toasts: S.mutable(S.Array(Toast)),
68
-
69
- /**
70
- * The identifier of a component to scroll into view when it is mounted.
71
- */
72
- scrollIntoView: S.optional(S.String),
73
- }),
74
- );
75
-
76
- export type Layout = S.Schema.Type<typeof Layout>;
77
-
78
- //
79
- // Intents
80
- //
81
-
82
9
  export const LAYOUT_PLUGIN = 'dxos.org/plugin/layout';
83
10
  export const LAYOUT_ACTION = `${LAYOUT_PLUGIN}/action`;
84
11
 
@@ -86,71 +13,212 @@ export const LAYOUT_ACTION = `${LAYOUT_PLUGIN}/action`;
86
13
  * Expected payload for layout actions.
87
14
  */
88
15
  export namespace LayoutAction {
89
- export class SetLayout extends S.TaggedClass<SetLayout>()(`${LAYOUT_ACTION}/set-layout`, {
16
+ export const UPDATE_LAYOUT = `${LAYOUT_ACTION}/update-layout`;
17
+
18
+ /**
19
+ * Generic layout action.
20
+ */
21
+ export class UpdateLayout extends S.TaggedClass<UpdateLayout>()(UPDATE_LAYOUT, {
90
22
  input: S.Struct({
91
- /**
92
- * Element to set the state of.
93
- */
94
- element: S.Literal('fullscreen', 'sidebar', 'complementary', 'dialog', 'popover', 'toast'),
95
-
96
- /**
97
- * Whether the element is on or off.
98
- *
99
- * If omitted, the element's state will be toggled or set based on other provided data.
100
- * For example, if `component` is provided, the state will be set to `true`.
101
- */
102
- state: S.optional(S.Boolean),
103
-
104
- /**
105
- * Component to render in the dialog or popover.
106
- */
107
- component: S.optional(S.String),
108
-
109
- /**
110
- * Data to be passed to the dialog or popover Surface.
111
- */
112
- subject: S.optional(S.Any),
113
-
114
- /**
115
- * Anchor ID for the popover.
116
- */
117
- anchorId: S.optional(S.String),
118
-
119
- // TODO(wittjosiah): Custom properties?
120
-
121
- /**
122
- * Block alignment for the dialog.
123
- */
124
- dialogBlockAlign: S.optional(S.Literal('start', 'center')),
125
-
126
- /**
127
- * Type of dialog.
128
- */
129
- dialogType: S.optional(S.Literal('default', 'alert')),
23
+ part: S.String.annotations({ description: 'The part of the layout to mutate.' }),
24
+ subject: S.optional(S.Any.annotations({ description: 'The subject of the layout update.' })),
25
+ options: S.optional(
26
+ S.Record({ key: S.String, value: S.Any }).annotations({
27
+ description: 'Additional options for the layout action.',
28
+ }),
29
+ ),
130
30
  }),
131
31
  output: S.Void,
132
32
  }) {}
133
33
 
134
- // TODO(wittjosiah): Do all these need to be separate actions?
34
+ //
35
+ // Common layout actions.
36
+ //
37
+
38
+ // NOTE: These are layout actions which are currently in common use.
39
+ // They constrain the generic layout action types to provide additional type safety.
40
+ // However, they all follow the same generic structure and intent id.
41
+ // This allows for plugins to update the layout without depending on a specific layout plugin.
42
+ // The expectation is that other norms other than these will emerge over time.
43
+
44
+ export class SetLayoutMode extends S.TaggedClass<SetLayoutMode>()(UPDATE_LAYOUT, {
45
+ input: S.Struct({
46
+ part: S.Literal('mode').annotations({ description: 'Setting the layout mode.' }),
47
+ subject: S.optional(S.String.annotations({ description: 'Item which is the subject of the new layout mode.' })),
48
+ options: S.Union(
49
+ S.Struct({ mode: S.String.annotations({ description: 'The new layout mode.' }) }),
50
+ S.Struct({ revert: S.Boolean.annotations({ description: 'Revert to the previous layout mode.' }) }),
51
+ ),
52
+ }),
53
+ output: S.Void,
54
+ }) {}
135
55
 
136
- export class SetLayoutMode extends S.TaggedClass<SetLayoutMode>()(`${LAYOUT_ACTION}/set-layout-mode`, {
137
- input: S.Union(
138
- S.Struct({
139
- layoutMode: LayoutMode,
56
+ export class UpdateSidebar extends S.TaggedClass<UpdateSidebar>()(UPDATE_LAYOUT, {
57
+ input: S.Struct({
58
+ part: S.Literal('sidebar').annotations({ description: 'Updating the sidebar.' }),
59
+ subject: S.optional(S.String.annotations({ description: 'URI of the component to display in the sidebar.' })),
60
+ options: S.optional(
61
+ S.Struct({
62
+ state: S.Literal('closed', 'collapsed', 'expanded').annotations({
63
+ description: 'Whether the sidebar is closed, collapsed, or expanded.',
64
+ }),
65
+ }),
66
+ ),
67
+ }),
68
+ output: S.Void,
69
+ }) {}
70
+
71
+ export class UpdateComplementary extends S.TaggedClass<UpdateComplementary>()(UPDATE_LAYOUT, {
72
+ input: S.Struct({
73
+ part: S.Literal('complementary').annotations({ description: 'Updating the complementary sidebar.' }),
74
+ subject: S.optional(
75
+ S.String.annotations({ description: 'URI of the component to display in the complementary area.' }),
76
+ ),
77
+ options: S.optional(
78
+ S.Struct({
79
+ state: S.Literal('closed', 'collapsed', 'expanded').annotations({
80
+ description: 'Whether the complementary sidebar is closed, collapsed, or expanded.',
81
+ }),
82
+ }),
83
+ ),
84
+ }),
85
+ output: S.Void,
86
+ }) {}
87
+
88
+ export class UpdateDialog extends S.TaggedClass<UpdateDialog>()(UPDATE_LAYOUT, {
89
+ input: S.Struct({
90
+ part: S.Literal('dialog').annotations({ description: 'Updating the dialog.' }),
91
+ subject: S.optional(S.String.annotations({ description: 'URI of the component to display in the dialog.' })),
92
+ options: S.Struct({
93
+ state: S.optional(S.Boolean.annotations({ description: 'Whether the dialog is open or closed.' })),
94
+ blockAlign: S.optional(
95
+ S.Literal('start', 'center').annotations({ description: 'The alignment of the dialog.' }),
96
+ ),
97
+ type: S.optional(S.Literal('default', 'alert').annotations({ description: 'The type of dialog.' })),
98
+ props: S.optional(
99
+ S.Record({ key: S.String, value: S.Any }).annotations({
100
+ description: 'Additional props for the dialog.',
101
+ }),
102
+ ),
140
103
  }),
141
- S.Struct({
142
- revert: S.Literal(true),
104
+ }),
105
+ output: S.Void,
106
+ }) {}
107
+
108
+ export class UpdatePopover extends S.TaggedClass<UpdatePopover>()(UPDATE_LAYOUT, {
109
+ input: S.Struct({
110
+ part: S.Literal('popover').annotations({ description: 'Updating the popover.' }),
111
+ subject: S.optional(S.String.annotations({ description: 'URI of the component to display in the popover.' })),
112
+ options: S.Struct({
113
+ anchorId: S.String.annotations({ description: 'The id of the element to anchor the popover to.' }),
114
+ state: S.optional(S.Boolean.annotations({ description: 'Whether the popover is open or closed.' })),
115
+ props: S.optional(
116
+ S.Record({ key: S.String, value: S.Any }).annotations({
117
+ description: 'Additional props for the popover.',
118
+ }),
119
+ ),
143
120
  }),
121
+ }),
122
+ output: S.Void,
123
+ }) {}
124
+
125
+ export const Toast = S.Struct({
126
+ id: S.String.annotations({ description: 'The id of the toast.' }),
127
+ title: S.optional(Label.annotations({ description: 'The title of the toast.' })),
128
+ description: S.optional(Label.annotations({ description: 'The description of the toast.' })),
129
+ icon: S.optional(S.String.annotations({ description: 'The icon of the toast.' })),
130
+ duration: S.optional(S.Number.annotations({ description: 'The duration of the toast.' })),
131
+ closeLabel: S.optional(Label.annotations({ description: 'The label of the close button.' })),
132
+ actionLabel: S.optional(Label.annotations({ description: 'The label of the action button.' })),
133
+ actionAlt: S.optional(Label.annotations({ description: 'The alt text of the action button.' })),
134
+ onAction: S.optional(
135
+ S.Any.annotations({ description: 'The action to perform when the action button is clicked.' }),
144
136
  ),
137
+ });
138
+
139
+ export interface Toast extends Omit<S.Schema.Type<typeof Toast>, 'onAction'> {
140
+ onAction?: () => void;
141
+ }
142
+
143
+ export class AddToast extends S.TaggedClass<AddToast>()(UPDATE_LAYOUT, {
144
+ input: S.Struct({
145
+ part: S.Literal('toast').annotations({ description: 'Adding a toast.' }),
146
+ subject: Toast.annotations({ description: 'The toast to add.' }),
147
+ }),
148
+ output: S.Void,
149
+ }) {}
150
+
151
+ export class SwitchWorkspace extends S.TaggedClass<SwitchWorkspace>()(UPDATE_LAYOUT, {
152
+ input: S.Struct({
153
+ part: S.Literal('workspace').annotations({ description: 'Switching the workspace.' }),
154
+ subject: S.String.annotations({ description: 'The id of the workspace to switch to.' }),
155
+ }),
156
+ output: S.Void,
157
+ }) {}
158
+
159
+ export class Open extends S.TaggedClass<Open>()(UPDATE_LAYOUT, {
160
+ input: S.Struct({
161
+ part: S.Literal('main').annotations({ description: 'Opening an item in the main content area.' }),
162
+ subject: S.Array(S.String.annotations({ description: 'Ids of the items to open.' })),
163
+ options: S.optional(
164
+ S.Struct({
165
+ state: S.optional(S.Literal(true).annotations({ description: 'The items are being added.' })),
166
+ key: S.optional(
167
+ S.String.annotations({ description: 'If provided, will replace item with a matching key (id prefix).' }),
168
+ ),
169
+ scrollIntoView: S.optional(S.Boolean.annotations({ description: 'Scroll the items into view.' })),
170
+ pivotId: S.optional(S.String.annotations({ description: 'The id of the item to place new items next to.' })),
171
+ positioning: S.optional(
172
+ S.Union(
173
+ S.Literal('start').annotations({ description: 'The items are being added before the pivot item.' }),
174
+ S.Literal('end').annotations({ description: 'The items are being added after the pivot item.' }),
175
+ ),
176
+ ),
177
+ }),
178
+ ),
179
+ }),
180
+ output: S.Void,
181
+ }) {}
182
+
183
+ export class Set extends S.TaggedClass<Set>()(UPDATE_LAYOUT, {
184
+ input: S.Struct({
185
+ part: S.Literal('main').annotations({ description: 'Setting items in the main content area.' }),
186
+ subject: S.Array(S.String.annotations({ description: 'Ids of the items to set.' })),
187
+ options: S.Struct({
188
+ override: S.Literal(true).annotations({ description: 'Override the current items in the main content area.' }),
189
+ }),
190
+ }),
191
+ output: S.Void,
192
+ }) {}
193
+
194
+ export class Close extends S.TaggedClass<Close>()(UPDATE_LAYOUT, {
195
+ input: S.Struct({
196
+ part: S.Literal('main').annotations({ description: 'Closing items in the main content area.' }),
197
+ subject: S.Array(S.String.annotations({ description: 'Ids of the items to close.' })),
198
+ options: S.Struct({
199
+ state: S.Literal(false).annotations({ description: 'The items are being removed.' }),
200
+ }),
201
+ }),
202
+ output: S.Void,
203
+ }) {}
204
+
205
+ export class ScrollIntoView extends S.TaggedClass<ScrollIntoView>()(UPDATE_LAYOUT, {
206
+ input: S.Struct({
207
+ part: S.Literal('current').annotations({ description: 'Setting the current item' }),
208
+ subject: S.optional(S.String.annotations({ description: 'The id of the item to set as current.' })),
209
+ options: S.optional(
210
+ S.Record({ key: S.String, value: S.Any }).annotations({
211
+ description: 'Additional options for the scroll into view.',
212
+ }),
213
+ ),
214
+ }),
145
215
  output: S.Void,
146
216
  }) {}
147
217
 
148
- export class ScrollIntoView extends S.TaggedClass<ScrollIntoView>()(`${LAYOUT_ACTION}/scroll-into-view`, {
218
+ export class Expose extends S.TaggedClass<Expose>()(UPDATE_LAYOUT, {
149
219
  input: S.Struct({
150
- id: S.optional(S.String),
151
- // TODO(wittjosiah): Factor out to thread scroll into view action?
152
- cursor: S.optional(S.String),
153
- ref: S.optional(S.String),
220
+ part: S.Literal('navigation').annotations({ description: 'Exposing an item in the navigation area.' }),
221
+ subject: S.String.annotations({ description: 'The id of the item to expose.' }),
154
222
  }),
155
223
  output: S.Void,
156
224
  }) {}
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { type JSX, type ForwardedRef, type PropsWithChildren, type ReactNode } from 'react';
6
6
 
7
- import { type GuardedType, type MakeOptional, type Disposition } from '@dxos/util';
7
+ import { type GuardedType, type MakeOptional, type Position } from '@dxos/util';
8
8
 
9
9
  import { type ErrorBoundary } from '../react';
10
10
 
@@ -73,7 +73,7 @@ export type SurfaceComponent<T extends Record<string, any> = Record<string, unkn
73
73
  export type SurfaceDefinition<T extends Record<string, any> = any> = Readonly<{
74
74
  id: string;
75
75
  role: string | string[];
76
- disposition?: Disposition;
76
+ position?: Position;
77
77
  filter?: (data: Record<string, unknown>) => data is T;
78
78
  component: SurfaceComponent<GuardedType<SurfaceDefinition<T>['filter']>>;
79
79
  }>;
@@ -2,17 +2,16 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { z } from 'zod';
5
+ import { Schema as S } from '@effect/schema';
6
6
 
7
- // TODO(burdon): Replace zod with effect.
8
- export const ResourceKey = z.union([z.string(), z.record(z.any())]);
9
- export type ResourceKey = z.infer<typeof ResourceKey>;
7
+ export const ResourceKey = S.Union(S.String, S.Record({ key: S.String, value: S.Any }));
8
+ export type ResourceKey = S.Schema.Type<typeof ResourceKey>;
10
9
 
11
- export const ResourceLanguage = z.record(ResourceKey);
12
- export type ResourceLanguage = z.infer<typeof ResourceLanguage>;
10
+ export const ResourceLanguage = S.Record({ key: S.String, value: ResourceKey });
11
+ export type ResourceLanguage = S.Schema.Type<typeof ResourceLanguage>;
13
12
 
14
13
  /**
15
14
  * A resource is a collection of translations for a language.
16
15
  */
17
- export const Resource = z.record(ResourceLanguage);
18
- export type Resource = z.infer<typeof Resource>;
16
+ export const Resource = S.Record({ key: S.String, value: ResourceLanguage });
17
+ export type Resource = S.Schema.Type<typeof Resource>;