@dxos/app-framework 0.7.5-labs.e27f9b9 → 0.7.5-main.2567c87

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 (184) hide show
  1. package/dist/lib/browser/{chunk-G3HBVVT5.mjs → chunk-GNLU3GAU.mjs} +819 -627
  2. package/dist/lib/browser/chunk-GNLU3GAU.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +74 -57
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +3 -10
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/chunk-FBA4BB3J.cjs +1639 -0
  9. package/dist/lib/node/chunk-FBA4BB3J.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +118 -106
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +8 -15
  14. package/dist/lib/node/testing/index.cjs.map +3 -3
  15. package/dist/lib/node-esm/{chunk-ZTB4TA6Q.mjs → chunk-KPMTPXQI.mjs} +819 -627
  16. package/dist/lib/node-esm/chunk-KPMTPXQI.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +74 -57
  18. package/dist/lib/node-esm/index.mjs.map +4 -4
  19. package/dist/lib/node-esm/meta.json +1 -1
  20. package/dist/lib/node-esm/testing/index.mjs +3 -10
  21. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  22. package/dist/types/src/App.d.ts.map +1 -1
  23. package/dist/types/src/common/capabilities.d.ts +110 -66
  24. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  25. package/dist/types/src/common/events.d.ts +1 -8
  26. package/dist/types/src/common/events.d.ts.map +1 -1
  27. package/dist/types/src/common/file.d.ts +1 -1
  28. package/dist/types/src/common/file.d.ts.map +1 -1
  29. package/dist/types/src/common/graph.d.ts +2 -2
  30. package/dist/types/src/common/graph.d.ts.map +1 -1
  31. package/dist/types/src/common/index.d.ts +1 -0
  32. package/dist/types/src/common/index.d.ts.map +1 -1
  33. package/dist/types/src/common/layout.d.ts +121 -204
  34. package/dist/types/src/common/layout.d.ts.map +1 -1
  35. package/dist/types/src/common/navigation.d.ts +241 -0
  36. package/dist/types/src/common/navigation.d.ts.map +1 -0
  37. package/dist/types/src/common/surface.d.ts +3 -3
  38. package/dist/types/src/common/surface.d.ts.map +1 -1
  39. package/dist/types/src/common/translations.d.ts +7 -7
  40. package/dist/types/src/common/translations.d.ts.map +1 -1
  41. package/dist/types/src/core/capabilities.d.ts +2 -6
  42. package/dist/types/src/core/capabilities.d.ts.map +1 -1
  43. package/dist/types/src/core/manager.d.ts +9 -2
  44. package/dist/types/src/core/manager.d.ts.map +1 -1
  45. package/dist/types/src/core/plugin.d.ts +2 -5
  46. package/dist/types/src/core/plugin.d.ts.map +1 -1
  47. package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -1
  48. package/dist/types/src/playground/generator/generator.d.ts +0 -2
  49. package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
  50. package/dist/types/src/playground/generator/plugin.d.ts.map +1 -1
  51. package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -1
  52. package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
  53. package/dist/types/src/playground/logger/schema.d.ts +1 -1
  54. package/dist/types/src/playground/logger/schema.d.ts.map +1 -1
  55. package/dist/types/src/{react → plugin-intent}/IntentContext.d.ts +1 -1
  56. package/dist/types/src/plugin-intent/IntentContext.d.ts.map +1 -0
  57. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
  58. package/dist/types/src/plugin-intent/actions.d.ts +1 -1
  59. package/dist/types/src/plugin-intent/actions.d.ts.map +1 -1
  60. package/dist/types/src/plugin-intent/index.d.ts +1 -0
  61. package/dist/types/src/plugin-intent/index.d.ts.map +1 -1
  62. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +20 -27
  63. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
  64. package/dist/types/src/plugin-intent/intent.d.ts +3 -3
  65. package/dist/types/src/plugin-intent/intent.d.ts.map +1 -1
  66. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
  67. package/dist/types/src/plugin-settings/actions.d.ts +1 -11
  68. package/dist/types/src/plugin-settings/actions.d.ts.map +1 -1
  69. package/dist/types/src/react/Surface.d.ts.map +1 -1
  70. package/dist/types/src/react/index.d.ts +0 -2
  71. package/dist/types/src/react/index.d.ts.map +1 -1
  72. package/dist/types/src/react/useCapabilities.d.ts.map +1 -1
  73. package/dist/types/src/testing/withPluginManager.d.ts +1 -1
  74. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  75. package/package.json +21 -28
  76. package/project.json +3 -3
  77. package/src/App.tsx +14 -15
  78. package/src/common/capabilities.ts +11 -26
  79. package/src/common/events.ts +1 -10
  80. package/src/common/file.ts +1 -1
  81. package/src/common/graph.ts +2 -2
  82. package/src/common/index.ts +1 -0
  83. package/src/common/layout.ts +126 -194
  84. package/src/common/navigation.ts +199 -0
  85. package/src/common/surface.ts +2 -2
  86. package/src/common/translations.ts +8 -7
  87. package/src/core/capabilities.ts +7 -16
  88. package/src/core/manager.test.ts +73 -22
  89. package/src/core/manager.ts +91 -105
  90. package/src/core/plugin.ts +3 -6
  91. package/src/playground/debug/plugin.ts +1 -1
  92. package/src/playground/generator/Toolbar.tsx +11 -11
  93. package/src/playground/generator/generator.ts +0 -25
  94. package/src/playground/generator/plugin.ts +1 -6
  95. package/src/playground/layout/plugin.ts +1 -1
  96. package/src/playground/logger/Toolbar.tsx +1 -2
  97. package/src/playground/logger/plugin.ts +3 -6
  98. package/src/playground/logger/schema.ts +1 -1
  99. package/src/{react → plugin-intent}/IntentContext.tsx +2 -2
  100. package/src/plugin-intent/IntentPlugin.tsx +43 -3
  101. package/src/plugin-intent/actions.ts +1 -1
  102. package/src/plugin-intent/errors.ts +1 -1
  103. package/src/plugin-intent/index.ts +1 -0
  104. package/src/plugin-intent/intent-dispatcher.test.ts +29 -48
  105. package/src/plugin-intent/intent-dispatcher.ts +41 -76
  106. package/src/plugin-intent/intent.ts +5 -5
  107. package/src/plugin-settings/SettingsPlugin.ts +13 -19
  108. package/src/plugin-settings/actions.ts +1 -11
  109. package/src/react/Surface.tsx +8 -11
  110. package/src/react/index.ts +0 -2
  111. package/src/react/useCapabilities.ts +0 -1
  112. package/src/testing/withPluginManager.tsx +3 -11
  113. package/tsconfig.json +3 -6
  114. package/dist/lib/browser/app-graph-builder-MOLT4EHG.mjs +0 -137
  115. package/dist/lib/browser/app-graph-builder-MOLT4EHG.mjs.map +0 -7
  116. package/dist/lib/browser/chunk-G3HBVVT5.mjs.map +0 -7
  117. package/dist/lib/browser/chunk-LDJ3T4V3.mjs +0 -32
  118. package/dist/lib/browser/chunk-LDJ3T4V3.mjs.map +0 -7
  119. package/dist/lib/browser/chunk-TGOF2WQZ.mjs +0 -285
  120. package/dist/lib/browser/chunk-TGOF2WQZ.mjs.map +0 -7
  121. package/dist/lib/browser/intent-dispatcher-LJKNIGAM.mjs +0 -11
  122. package/dist/lib/browser/intent-dispatcher-LJKNIGAM.mjs.map +0 -7
  123. package/dist/lib/browser/intent-resolver-Z724VAMC.mjs +0 -38
  124. package/dist/lib/browser/intent-resolver-Z724VAMC.mjs.map +0 -7
  125. package/dist/lib/browser/store-NWCY7LAP.mjs +0 -19
  126. package/dist/lib/browser/store-NWCY7LAP.mjs.map +0 -7
  127. package/dist/lib/browser/worker.mjs +0 -77
  128. package/dist/lib/browser/worker.mjs.map +0 -7
  129. package/dist/lib/node/app-graph-builder-G7SRXDFD.cjs +0 -146
  130. package/dist/lib/node/app-graph-builder-G7SRXDFD.cjs.map +0 -7
  131. package/dist/lib/node/chunk-55KIQ6YK.cjs +0 -1437
  132. package/dist/lib/node/chunk-55KIQ6YK.cjs.map +0 -7
  133. package/dist/lib/node/chunk-5GABBW2Q.cjs +0 -308
  134. package/dist/lib/node/chunk-5GABBW2Q.cjs.map +0 -7
  135. package/dist/lib/node/chunk-QLVQ6PND.cjs +0 -58
  136. package/dist/lib/node/chunk-QLVQ6PND.cjs.map +0 -7
  137. package/dist/lib/node/intent-dispatcher-CGUK3BCJ.cjs +0 -32
  138. package/dist/lib/node/intent-dispatcher-CGUK3BCJ.cjs.map +0 -7
  139. package/dist/lib/node/intent-resolver-7GNKPRWT.cjs +0 -45
  140. package/dist/lib/node/intent-resolver-7GNKPRWT.cjs.map +0 -7
  141. package/dist/lib/node/store-WMJSEQPC.cjs +0 -34
  142. package/dist/lib/node/store-WMJSEQPC.cjs.map +0 -7
  143. package/dist/lib/node/worker.cjs +0 -99
  144. package/dist/lib/node/worker.cjs.map +0 -7
  145. package/dist/lib/node-esm/app-graph-builder-MKLYH3NE.mjs +0 -138
  146. package/dist/lib/node-esm/app-graph-builder-MKLYH3NE.mjs.map +0 -7
  147. package/dist/lib/node-esm/chunk-47FG42II.mjs +0 -286
  148. package/dist/lib/node-esm/chunk-47FG42II.mjs.map +0 -7
  149. package/dist/lib/node-esm/chunk-CNJYZNSL.mjs +0 -34
  150. package/dist/lib/node-esm/chunk-CNJYZNSL.mjs.map +0 -7
  151. package/dist/lib/node-esm/chunk-ZTB4TA6Q.mjs.map +0 -7
  152. package/dist/lib/node-esm/intent-dispatcher-RZAWA4XD.mjs +0 -12
  153. package/dist/lib/node-esm/intent-dispatcher-RZAWA4XD.mjs.map +0 -7
  154. package/dist/lib/node-esm/intent-resolver-UIU37CKJ.mjs +0 -39
  155. package/dist/lib/node-esm/intent-resolver-UIU37CKJ.mjs.map +0 -7
  156. package/dist/lib/node-esm/store-YUWINFBN.mjs +0 -20
  157. package/dist/lib/node-esm/store-YUWINFBN.mjs.map +0 -7
  158. package/dist/lib/node-esm/worker.mjs +0 -78
  159. package/dist/lib/node-esm/worker.mjs.map +0 -7
  160. package/dist/types/src/plugin-settings/app-graph-builder.d.ts +0 -197
  161. package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +0 -1
  162. package/dist/types/src/plugin-settings/intent-resolver.d.ts +0 -4
  163. package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +0 -1
  164. package/dist/types/src/plugin-settings/store.d.ts +0 -5
  165. package/dist/types/src/plugin-settings/store.d.ts.map +0 -1
  166. package/dist/types/src/plugin-settings/translations.d.ts +0 -11
  167. package/dist/types/src/plugin-settings/translations.d.ts.map +0 -1
  168. package/dist/types/src/react/IntentContext.d.ts.map +0 -1
  169. package/dist/types/src/react/Surface.stories.d.ts +0 -16
  170. package/dist/types/src/react/Surface.stories.d.ts.map +0 -1
  171. package/dist/types/src/react/common.d.ts +0 -12
  172. package/dist/types/src/react/common.d.ts.map +0 -1
  173. package/dist/types/src/react/useIntentResolver.d.ts +0 -3
  174. package/dist/types/src/react/useIntentResolver.d.ts.map +0 -1
  175. package/dist/types/src/worker.d.ts +0 -4
  176. package/dist/types/src/worker.d.ts.map +0 -1
  177. package/src/plugin-settings/app-graph-builder.ts +0 -122
  178. package/src/plugin-settings/intent-resolver.ts +0 -28
  179. package/src/plugin-settings/store.ts +0 -20
  180. package/src/plugin-settings/translations.ts +0 -17
  181. package/src/react/Surface.stories.tsx +0 -96
  182. package/src/react/common.ts +0 -12
  183. package/src/react/useIntentResolver.ts +0 -22
  184. package/src/worker.ts +0 -11
package/project.json CHANGED
@@ -12,8 +12,7 @@
12
12
  "options": {
13
13
  "entryPoints": [
14
14
  "{projectRoot}/src/index.ts",
15
- "{projectRoot}/src/testing/index.ts",
16
- "{projectRoot}/src/worker.ts"
15
+ "{projectRoot}/src/testing/index.ts"
17
16
  ]
18
17
  }
19
18
  },
@@ -21,6 +20,7 @@
21
20
  "test": {}
22
21
  },
23
22
  "implicitDependencies": [
24
- "esbuild"
23
+ "esbuild",
24
+ "node-std"
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, useCapabilities } from './react';
14
+ import { ErrorBoundary, PluginManagerProvider } from './react';
15
15
 
16
16
  const ENABLED_KEY = 'dxos.org/app-framework/enabled';
17
17
 
@@ -96,27 +96,21 @@ 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);
101
99
  void manager.activate(Events.Startup);
102
100
 
103
101
  return () => (
104
102
  <ErrorBoundary fallback={fallback}>
105
- <PluginManagerProvider value={manager}>
106
- <App placeholder={placeholder} state={state} />
107
- </PluginManagerProvider>
103
+ <App placeholder={placeholder} manager={manager} state={state} />
108
104
  </ErrorBoundary>
109
105
  );
110
106
  };
111
107
 
112
108
  type AppProps = Required<Pick<CreateAppOptions, 'placeholder'>> & {
109
+ manager: PluginManager;
113
110
  state: { ready: boolean; error: unknown };
114
111
  };
115
112
 
116
- const App = ({ placeholder, state }: AppProps) => {
117
- const reactContexts = useCapabilities(Capabilities.ReactContext);
118
- const reactRoots = useCapabilities(Capabilities.ReactRoot);
119
-
113
+ const App = ({ placeholder, manager, state }: AppProps) => {
120
114
  if (state.error) {
121
115
  // This trigger the error boundary to provide UI feedback for the startup error.
122
116
  throw state.error;
@@ -127,13 +121,18 @@ const App = ({ placeholder, state }: AppProps) => {
127
121
  return <>{placeholder}</>;
128
122
  }
129
123
 
124
+ const reactContexts = manager.context.requestCapabilities(Capabilities.ReactContext);
125
+ const reactRoots = manager.context.requestCapabilities(Capabilities.ReactRoot);
126
+
130
127
  const ComposedContext = composeContexts(reactContexts);
131
128
  return (
132
- <ComposedContext>
133
- {reactRoots.map(({ id, root: Component }) => (
134
- <Component key={id} />
135
- ))}
136
- </ComposedContext>
129
+ <PluginManagerProvider value={manager}>
130
+ <ComposedContext>
131
+ {reactRoots.map(({ id, root: Component }) => (
132
+ <Component key={id} />
133
+ ))}
134
+ </ComposedContext>
135
+ </PluginManagerProvider>
137
136
  );
138
137
  };
139
138
 
@@ -2,16 +2,18 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Schema as S } from '@effect/schema';
6
5
  import { type FC, type PropsWithChildren } from 'react';
7
6
 
8
7
  import { type GraphBuilder } from '@dxos/app-graph';
9
- import { type ArtifactDefinition, type Tool } from '@dxos/artifact';
10
8
  import { type Space } from '@dxos/client-protocol';
9
+ import { type S } from '@dxos/echo-schema';
11
10
  import { type RootSettingsStore } from '@dxos/local-storage';
11
+ import { type DeepReadonly } from '@dxos/util';
12
12
 
13
13
  import { type FileInfo } from './file';
14
14
  import { type NodeSerializer } from './graph';
15
+ import { type Layout } from './layout';
16
+ import { type LayoutParts } from './navigation';
15
17
  import { type SurfaceDefinition } from './surface';
16
18
  import { type Resource } from './translations';
17
19
  import { defineCapability, type PluginManager } from '../core';
@@ -38,25 +40,13 @@ export namespace Capabilities {
38
40
  'dxos.org/app-framework/capability/intent-dispatcher',
39
41
  );
40
42
 
41
- export type Layout = Readonly<{
42
- mode: string;
43
- dialogOpen: boolean;
44
- sidebarOpen: boolean;
45
- complementarySidebarOpen: boolean;
46
- /**
47
- * Identifiers of items which are currently active in the application.
48
- */
49
- active: string[];
50
- /**
51
- * Identifiers of items which were previously active in the application.
52
- */
53
- inactive: string[];
54
- /**
55
- * Identifier of the item which should be scrolled into view.
56
- */
57
- scrollIntoView: string | undefined;
58
- }>;
59
- export const Layout = defineCapability<Layout>('dxos.org/app-framework/capability/layout');
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');
60
50
 
61
51
  export const Translations = defineCapability<Readonly<Resource[]>>('dxos.org/app-framework/capability/translations');
62
52
 
@@ -87,11 +77,6 @@ export namespace Capabilities {
87
77
  export type Metadata = Readonly<{ id: string; metadata: Record<string, any> }>;
88
78
  export const Metadata = defineCapability<Metadata>('dxos.org/app-framework/capability/metadata');
89
79
 
90
- export const Tools = defineCapability<Tool[]>('dxos.org/app-framework/capability/tools');
91
- export const ArtifactDefinition = defineCapability<ArtifactDefinition>(
92
- 'dxos.org/app-framework/capability/artifact-definition',
93
- );
94
-
95
80
  export type FileUploader = (file: File, space: Space) => Promise<FileInfo | undefined>;
96
81
  export const FileUploader = defineCapability<FileUploader>('dxos.org/app-framework/capability/file-uploader');
97
82
  }
@@ -15,16 +15,6 @@ 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
-
28
18
  /**
29
19
  * Fired before the intent dispatcher is activated.
30
20
  */
@@ -69,4 +59,5 @@ export namespace Events {
69
59
  */
70
60
  export const createStateEvent = (specifier: string) => defineEvent('dxos.org/app-framework/event/state', specifier);
71
61
  export const LayoutReady = createStateEvent(Capabilities.Layout.identifier);
62
+ export const LocationReady = createStateEvent(Capabilities.Location.identifier);
72
63
  }
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema as S } from '@effect/schema';
5
+ import { S } from '@dxos/echo-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, type Position } from '@dxos/util';
6
+ import { type MaybePromise } 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
- position?: Position;
19
+ disposition?: 'hoist' | 'fallback';
20
20
 
21
21
  /**
22
22
  * Takes a node and serializes it into a format that can be stored.
@@ -7,5 +7,6 @@ export * from './events';
7
7
  export * from './file';
8
8
  export * from './graph';
9
9
  export * from './layout';
10
+ export * from './navigation';
10
11
  export * from './surface';
11
12
  export * from './translations';
@@ -2,223 +2,155 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Schema as S } from '@effect/schema';
5
+ import { S } from '@dxos/echo-schema';
6
6
 
7
7
  import { Label } from '../plugin-intent';
8
8
 
9
- export const LAYOUT_PLUGIN = 'dxos.org/plugin/layout';
10
- export const LAYOUT_ACTION = `${LAYOUT_PLUGIN}/action`;
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>;
11
27
 
12
28
  /**
13
- * Expected payload for layout actions.
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.
14
34
  */
15
- export namespace LayoutAction {
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, {
22
- input: S.Struct({
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
- ),
30
- }),
31
- output: S.Void,
32
- }) {}
33
35
 
34
- //
35
- // Common layout actions.
36
- //
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>;
37
77
 
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.
78
+ //
79
+ // Intents
80
+ //
43
81
 
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
- }) {}
82
+ export const LAYOUT_PLUGIN = 'dxos.org/plugin/layout';
83
+ export const LAYOUT_ACTION = `${LAYOUT_PLUGIN}/action`;
55
84
 
56
- export class UpdateSidebar extends S.TaggedClass<UpdateSidebar>()(UPDATE_LAYOUT, {
85
+ /**
86
+ * Expected payload for layout actions.
87
+ */
88
+ export namespace LayoutAction {
89
+ export class SetLayout extends S.TaggedClass<SetLayout>()(`${LAYOUT_ACTION}/set-layout`, {
57
90
  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
- ),
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')),
67
130
  }),
68
131
  output: S.Void,
69
132
  }) {}
70
133
 
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
- }) {}
134
+ // TODO(wittjosiah): Do all these need to be separate actions?
87
135
 
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
- ),
136
+ export class SetLayoutMode extends S.TaggedClass<SetLayoutMode>()(`${LAYOUT_ACTION}/set-layout-mode`, {
137
+ input: S.Union(
138
+ S.Struct({
139
+ layoutMode: LayoutMode,
103
140
  }),
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
- ),
141
+ S.Struct({
142
+ revert: S.Literal(true),
120
143
  }),
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.' }),
136
144
  ),
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
- }),
215
145
  output: S.Void,
216
146
  }) {}
217
147
 
218
- export class Expose extends S.TaggedClass<Expose>()(UPDATE_LAYOUT, {
148
+ export class ScrollIntoView extends S.TaggedClass<ScrollIntoView>()(`${LAYOUT_ACTION}/scroll-into-view`, {
219
149
  input: S.Struct({
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.' }),
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),
222
154
  }),
223
155
  output: S.Void,
224
156
  }) {}