@dxos/app-framework 0.6.14-main.2b6a0f3 → 0.6.14-main.f49f251

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 (210) hide show
  1. package/dist/lib/browser/chunk-3E7RY3CE.mjs +72 -0
  2. package/dist/lib/browser/chunk-3E7RY3CE.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-653Y45CL.mjs +41 -0
  4. package/dist/lib/browser/chunk-653Y45CL.mjs.map +7 -0
  5. package/dist/lib/browser/{plugin-MM66VRCO.mjs → chunk-CDLQO5K2.mjs} +66 -20
  6. package/dist/lib/browser/chunk-CDLQO5K2.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-EQTQGGE6.mjs +214 -0
  8. package/dist/lib/browser/chunk-EQTQGGE6.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +78 -212
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/plugin-intent-Q5KFPKFA.mjs +22 -0
  13. package/dist/lib/browser/plugin-intent-Q5KFPKFA.mjs.map +7 -0
  14. package/dist/lib/browser/plugin-settings-OM3G2QFY.mjs +11 -0
  15. package/dist/lib/browser/plugin-settings-OM3G2QFY.mjs.map +7 -0
  16. package/dist/lib/browser/plugin-surface-ZQXFAL46.mjs +24 -0
  17. package/dist/lib/browser/plugin-surface-ZQXFAL46.mjs.map +7 -0
  18. package/dist/lib/node/chunk-EF67TRWJ.cjs +236 -0
  19. package/dist/lib/node/chunk-EF67TRWJ.cjs.map +7 -0
  20. package/dist/lib/node/chunk-JZ2JVKRY.cjs +58 -0
  21. package/dist/lib/node/chunk-JZ2JVKRY.cjs.map +7 -0
  22. package/dist/lib/node/{chunk-62W6CMGM.cjs → chunk-QBM42OQ6.cjs} +56 -5
  23. package/dist/lib/node/chunk-QBM42OQ6.cjs.map +7 -0
  24. package/dist/lib/node/{plugin-QV7ESETI.cjs → chunk-VOKMWTKO.cjs} +74 -20
  25. package/dist/lib/node/chunk-VOKMWTKO.cjs.map +7 -0
  26. package/dist/lib/node/index.cjs +89 -223
  27. package/dist/lib/node/index.cjs.map +4 -4
  28. package/dist/lib/node/meta.json +1 -1
  29. package/dist/lib/node/plugin-intent-FMC4SDI3.cjs +43 -0
  30. package/dist/lib/node/plugin-intent-FMC4SDI3.cjs.map +7 -0
  31. package/dist/lib/node/plugin-settings-OZ6IKAE5.cjs +32 -0
  32. package/dist/lib/node/plugin-settings-OZ6IKAE5.cjs.map +7 -0
  33. package/dist/lib/node/plugin-surface-B5NHOBSW.cjs +45 -0
  34. package/dist/lib/node/plugin-surface-B5NHOBSW.cjs.map +7 -0
  35. package/dist/lib/node-esm/chunk-3FCLBEOX.mjs +215 -0
  36. package/dist/lib/node-esm/chunk-3FCLBEOX.mjs.map +7 -0
  37. package/dist/lib/node-esm/chunk-EYCTSFEJ.mjs +74 -0
  38. package/dist/lib/node-esm/chunk-EYCTSFEJ.mjs.map +7 -0
  39. package/dist/lib/node-esm/{plugin-5AAUGDB3.mjs → chunk-MYNXI5VG.mjs} +66 -20
  40. package/dist/lib/node-esm/chunk-MYNXI5VG.mjs.map +7 -0
  41. package/dist/lib/node-esm/chunk-YNU7FTGJ.mjs +43 -0
  42. package/dist/lib/node-esm/chunk-YNU7FTGJ.mjs.map +7 -0
  43. package/dist/lib/node-esm/index.mjs +78 -212
  44. package/dist/lib/node-esm/index.mjs.map +4 -4
  45. package/dist/lib/node-esm/meta.json +1 -1
  46. package/dist/lib/node-esm/plugin-intent-KETLP7UL.mjs +23 -0
  47. package/dist/lib/node-esm/plugin-intent-KETLP7UL.mjs.map +7 -0
  48. package/dist/lib/node-esm/plugin-settings-37UVWF2V.mjs +12 -0
  49. package/dist/lib/node-esm/plugin-settings-37UVWF2V.mjs.map +7 -0
  50. package/dist/lib/node-esm/plugin-surface-QXQRR534.mjs +25 -0
  51. package/dist/lib/node-esm/plugin-surface-QXQRR534.mjs.map +7 -0
  52. package/dist/types/src/App.d.ts +2 -2
  53. package/dist/types/src/App.d.ts.map +1 -1
  54. package/dist/types/src/plugins/common/file.d.ts +1 -1
  55. package/dist/types/src/plugins/common/file.d.ts.map +1 -1
  56. package/dist/types/src/plugins/common/graph.d.ts +1 -1
  57. package/dist/types/src/plugins/common/graph.d.ts.map +1 -1
  58. package/dist/types/src/plugins/common/index.d.ts +0 -1
  59. package/dist/types/src/plugins/common/index.d.ts.map +1 -1
  60. package/dist/types/src/plugins/common/layout.d.ts +6 -6
  61. package/dist/types/src/plugins/common/layout.d.ts.map +1 -1
  62. package/dist/types/src/plugins/common/metadata.d.ts +1 -1
  63. package/dist/types/src/plugins/common/metadata.d.ts.map +1 -1
  64. package/dist/types/src/plugins/common/navigation.d.ts +8 -8
  65. package/dist/types/src/plugins/common/navigation.d.ts.map +1 -1
  66. package/dist/types/src/plugins/common/translations.d.ts +1 -1
  67. package/dist/types/src/plugins/common/translations.d.ts.map +1 -1
  68. package/dist/types/src/plugins/helpers.d.ts +20 -5
  69. package/dist/types/src/plugins/helpers.d.ts.map +1 -1
  70. package/dist/types/src/plugins/index.d.ts +4 -3
  71. package/dist/types/src/plugins/index.d.ts.map +1 -1
  72. package/dist/types/src/plugins/{PluginHost/PluginHost.d.ts → plugin-host/HostPlugin.d.ts} +6 -6
  73. package/dist/types/src/plugins/plugin-host/HostPlugin.d.ts.map +1 -0
  74. package/dist/types/src/plugins/{PluginHost → plugin-host}/PluginContainer.d.ts +2 -2
  75. package/dist/types/src/plugins/plugin-host/PluginContainer.d.ts.map +1 -0
  76. package/dist/types/src/plugins/plugin-host/PluginContext.d.ts.map +1 -0
  77. package/dist/types/src/plugins/plugin-host/index.d.ts +4 -0
  78. package/dist/types/src/plugins/plugin-host/index.d.ts.map +1 -0
  79. package/dist/types/src/plugins/plugin-host/plugin.d.ts.map +1 -0
  80. package/dist/types/src/plugins/plugin-host/plugin.test.d.ts.map +1 -0
  81. package/dist/types/src/plugins/plugin-intent/IntentContext.d.ts.map +1 -0
  82. package/dist/types/src/plugins/{IntentPlugin/plugin.d.ts → plugin-intent/IntentPlugin.d.ts} +3 -4
  83. package/dist/types/src/plugins/plugin-intent/IntentPlugin.d.ts.map +1 -0
  84. package/dist/types/src/plugins/plugin-intent/helpers.d.ts.map +1 -0
  85. package/dist/types/src/plugins/plugin-intent/index.d.ts +6 -0
  86. package/dist/types/src/plugins/plugin-intent/index.d.ts.map +1 -0
  87. package/dist/types/src/plugins/{IntentPlugin → plugin-intent}/intent.d.ts +1 -1
  88. package/dist/types/src/plugins/plugin-intent/intent.d.ts.map +1 -0
  89. package/dist/types/src/plugins/plugin-intent/meta.d.ts.map +1 -0
  90. package/dist/types/src/plugins/{IntentPlugin → plugin-intent}/provides.d.ts +2 -2
  91. package/dist/types/src/plugins/plugin-intent/provides.d.ts.map +1 -0
  92. package/dist/types/src/plugins/plugin-settings/SettingsPlugin.d.ts +4 -0
  93. package/dist/types/src/plugins/plugin-settings/SettingsPlugin.d.ts.map +1 -0
  94. package/dist/types/src/plugins/plugin-settings/index.d.ts +4 -0
  95. package/dist/types/src/plugins/plugin-settings/index.d.ts.map +1 -0
  96. package/dist/types/src/plugins/plugin-settings/meta.d.ts +5 -0
  97. package/dist/types/src/plugins/plugin-settings/meta.d.ts.map +1 -0
  98. package/dist/types/src/plugins/plugin-settings/provides.d.ts +13 -0
  99. package/dist/types/src/plugins/plugin-settings/provides.d.ts.map +1 -0
  100. package/dist/types/src/plugins/plugin-surface/ErrorBoundary.d.ts.map +1 -0
  101. package/dist/types/src/plugins/{SurfacePlugin → plugin-surface}/Surface.d.ts +4 -0
  102. package/dist/types/src/plugins/plugin-surface/Surface.d.ts.map +1 -0
  103. package/dist/types/src/plugins/plugin-surface/SurfacePlugin.d.ts +7 -0
  104. package/dist/types/src/plugins/plugin-surface/SurfacePlugin.d.ts.map +1 -0
  105. package/dist/types/src/plugins/plugin-surface/SurfaceRootContext.d.ts.map +1 -0
  106. package/dist/types/src/plugins/plugin-surface/helpers.d.ts.map +1 -0
  107. package/dist/types/src/plugins/{SurfacePlugin → plugin-surface}/index.d.ts +2 -0
  108. package/dist/types/src/plugins/plugin-surface/index.d.ts.map +1 -0
  109. package/dist/types/src/plugins/plugin-surface/meta.d.ts.map +1 -0
  110. package/dist/types/src/plugins/{SurfacePlugin → plugin-surface}/provides.d.ts +1 -1
  111. package/dist/types/src/plugins/plugin-surface/provides.d.ts.map +1 -0
  112. package/package.json +14 -16
  113. package/src/App.tsx +13 -12
  114. package/src/plugins/common/file.ts +1 -1
  115. package/src/plugins/common/graph.ts +1 -1
  116. package/src/plugins/common/index.ts +0 -1
  117. package/src/plugins/common/layout.ts +6 -3
  118. package/src/plugins/common/metadata.ts +1 -1
  119. package/src/plugins/common/navigation.ts +6 -3
  120. package/src/plugins/common/translations.ts +2 -8
  121. package/src/plugins/helpers.ts +55 -11
  122. package/src/plugins/index.ts +4 -3
  123. package/src/plugins/{PluginHost/PluginHost.tsx → plugin-host/HostPlugin.tsx} +10 -9
  124. package/src/plugins/{PluginHost → plugin-host}/PluginContainer.tsx +2 -2
  125. package/src/plugins/{PluginHost → plugin-host}/PluginContext.tsx +1 -0
  126. package/src/plugins/{PluginHost → plugin-host}/index.ts +2 -1
  127. package/src/plugins/{IntentPlugin/plugin.tsx → plugin-intent/IntentPlugin.tsx} +3 -6
  128. package/src/plugins/{IntentPlugin → plugin-intent}/index.ts +4 -0
  129. package/src/plugins/{IntentPlugin → plugin-intent}/intent.ts +1 -1
  130. package/src/plugins/{IntentPlugin → plugin-intent}/provides.ts +5 -2
  131. package/src/plugins/plugin-settings/SettingsPlugin.tsx +22 -0
  132. package/src/plugins/plugin-settings/index.ts +9 -0
  133. package/src/plugins/plugin-settings/meta.ts +9 -0
  134. package/src/plugins/plugin-settings/provides.ts +29 -0
  135. package/src/plugins/{SurfacePlugin → plugin-surface}/Surface.tsx +60 -46
  136. package/src/plugins/{SurfacePlugin/plugin.tsx → plugin-surface/SurfacePlugin.tsx} +2 -4
  137. package/src/plugins/{SurfacePlugin → plugin-surface}/index.ts +4 -0
  138. package/src/plugins/{SurfacePlugin → plugin-surface}/provides.ts +2 -1
  139. package/dist/lib/browser/chunk-J45KR4DI.mjs +0 -52
  140. package/dist/lib/browser/chunk-J45KR4DI.mjs.map +0 -7
  141. package/dist/lib/browser/chunk-S5CI6EUQ.mjs +0 -20
  142. package/dist/lib/browser/chunk-S5CI6EUQ.mjs.map +0 -7
  143. package/dist/lib/browser/chunk-SB4XRTGZ.mjs +0 -25
  144. package/dist/lib/browser/chunk-SB4XRTGZ.mjs.map +0 -7
  145. package/dist/lib/browser/plugin-MM66VRCO.mjs.map +0 -7
  146. package/dist/lib/browser/plugin-Y4KRQJE4.mjs +0 -40
  147. package/dist/lib/browser/plugin-Y4KRQJE4.mjs.map +0 -7
  148. package/dist/lib/node/chunk-62W6CMGM.cjs.map +0 -7
  149. package/dist/lib/node/chunk-DFST5IG5.cjs +0 -77
  150. package/dist/lib/node/chunk-DFST5IG5.cjs.map +0 -7
  151. package/dist/lib/node/chunk-PJGE52CN.cjs +0 -47
  152. package/dist/lib/node/chunk-PJGE52CN.cjs.map +0 -7
  153. package/dist/lib/node/plugin-6TEDSCXW.cjs +0 -62
  154. package/dist/lib/node/plugin-6TEDSCXW.cjs.map +0 -7
  155. package/dist/lib/node/plugin-QV7ESETI.cjs.map +0 -7
  156. package/dist/lib/node-esm/chunk-IY7HCP4K.mjs +0 -22
  157. package/dist/lib/node-esm/chunk-IY7HCP4K.mjs.map +0 -7
  158. package/dist/lib/node-esm/chunk-MBHRXQTR.mjs +0 -27
  159. package/dist/lib/node-esm/chunk-MBHRXQTR.mjs.map +0 -7
  160. package/dist/lib/node-esm/chunk-P2TQLXZR.mjs +0 -54
  161. package/dist/lib/node-esm/chunk-P2TQLXZR.mjs.map +0 -7
  162. package/dist/lib/node-esm/plugin-5AAUGDB3.mjs.map +0 -7
  163. package/dist/lib/node-esm/plugin-J5IRJLM6.mjs +0 -41
  164. package/dist/lib/node-esm/plugin-J5IRJLM6.mjs.map +0 -7
  165. package/dist/types/src/plugins/IntentPlugin/IntentContext.d.ts.map +0 -1
  166. package/dist/types/src/plugins/IntentPlugin/helpers.d.ts.map +0 -1
  167. package/dist/types/src/plugins/IntentPlugin/index.d.ts +0 -4
  168. package/dist/types/src/plugins/IntentPlugin/index.d.ts.map +0 -1
  169. package/dist/types/src/plugins/IntentPlugin/intent.d.ts.map +0 -1
  170. package/dist/types/src/plugins/IntentPlugin/meta.d.ts.map +0 -1
  171. package/dist/types/src/plugins/IntentPlugin/plugin.d.ts.map +0 -1
  172. package/dist/types/src/plugins/IntentPlugin/provides.d.ts.map +0 -1
  173. package/dist/types/src/plugins/PluginHost/PluginContainer.d.ts.map +0 -1
  174. package/dist/types/src/plugins/PluginHost/PluginContext.d.ts.map +0 -1
  175. package/dist/types/src/plugins/PluginHost/PluginHost.d.ts.map +0 -1
  176. package/dist/types/src/plugins/PluginHost/index.d.ts +0 -4
  177. package/dist/types/src/plugins/PluginHost/index.d.ts.map +0 -1
  178. package/dist/types/src/plugins/PluginHost/plugin.d.ts.map +0 -1
  179. package/dist/types/src/plugins/PluginHost/plugin.test.d.ts.map +0 -1
  180. package/dist/types/src/plugins/SurfacePlugin/ErrorBoundary.d.ts.map +0 -1
  181. package/dist/types/src/plugins/SurfacePlugin/Surface.d.ts.map +0 -1
  182. package/dist/types/src/plugins/SurfacePlugin/SurfaceRootContext.d.ts.map +0 -1
  183. package/dist/types/src/plugins/SurfacePlugin/helpers.d.ts.map +0 -1
  184. package/dist/types/src/plugins/SurfacePlugin/index.d.ts.map +0 -1
  185. package/dist/types/src/plugins/SurfacePlugin/meta.d.ts.map +0 -1
  186. package/dist/types/src/plugins/SurfacePlugin/plugin.d.ts +0 -8
  187. package/dist/types/src/plugins/SurfacePlugin/plugin.d.ts.map +0 -1
  188. package/dist/types/src/plugins/SurfacePlugin/provides.d.ts.map +0 -1
  189. package/dist/types/src/plugins/common/settings.d.ts +0 -9
  190. package/dist/types/src/plugins/common/settings.d.ts.map +0 -1
  191. package/src/plugins/common/settings.ts +0 -22
  192. /package/dist/types/src/plugins/{PluginHost → plugin-host}/PluginContext.d.ts +0 -0
  193. /package/dist/types/src/plugins/{PluginHost → plugin-host}/plugin.d.ts +0 -0
  194. /package/dist/types/src/plugins/{PluginHost → plugin-host}/plugin.test.d.ts +0 -0
  195. /package/dist/types/src/plugins/{IntentPlugin → plugin-intent}/IntentContext.d.ts +0 -0
  196. /package/dist/types/src/plugins/{IntentPlugin → plugin-intent}/helpers.d.ts +0 -0
  197. /package/dist/types/src/plugins/{IntentPlugin → plugin-intent}/meta.d.ts +0 -0
  198. /package/dist/types/src/plugins/{SurfacePlugin → plugin-surface}/ErrorBoundary.d.ts +0 -0
  199. /package/dist/types/src/plugins/{SurfacePlugin → plugin-surface}/SurfaceRootContext.d.ts +0 -0
  200. /package/dist/types/src/plugins/{SurfacePlugin → plugin-surface}/helpers.d.ts +0 -0
  201. /package/dist/types/src/plugins/{SurfacePlugin → plugin-surface}/meta.d.ts +0 -0
  202. /package/src/plugins/{PluginHost → plugin-host}/plugin.test.ts +0 -0
  203. /package/src/plugins/{PluginHost → plugin-host}/plugin.ts +0 -0
  204. /package/src/plugins/{IntentPlugin → plugin-intent}/IntentContext.tsx +0 -0
  205. /package/src/plugins/{IntentPlugin → plugin-intent}/helpers.ts +0 -0
  206. /package/src/plugins/{IntentPlugin → plugin-intent}/meta.ts +0 -0
  207. /package/src/plugins/{SurfacePlugin → plugin-surface}/ErrorBoundary.tsx +0 -0
  208. /package/src/plugins/{SurfacePlugin → plugin-surface}/SurfaceRootContext.tsx +0 -0
  209. /package/src/plugins/{SurfacePlugin → plugin-surface}/helpers.ts +0 -0
  210. /package/src/plugins/{SurfacePlugin → plugin-surface}/meta.ts +0 -0
@@ -4,8 +4,8 @@
4
4
 
5
5
  import { z } from 'zod';
6
6
 
7
- import { type IntentData } from '../IntentPlugin';
8
- import type { Plugin } from '../PluginHost';
7
+ import { type Plugin } from '../plugin-host';
8
+ import { type IntentData } from '../plugin-intent';
9
9
 
10
10
  //
11
11
  // Provides
@@ -90,7 +90,10 @@ export const parseLayoutPlugin = (plugin: Plugin) => {
90
90
  // Intents
91
91
  //
92
92
 
93
- const LAYOUT_ACTION = 'dxos.org/plugin/layout';
93
+ const LAYOUT_PLUGIN = 'dxos.org/plugin/layout';
94
+
95
+ const LAYOUT_ACTION = `${LAYOUT_PLUGIN}/action`;
96
+
94
97
  export enum LayoutAction {
95
98
  SET_LAYOUT = `${LAYOUT_ACTION}/set-layout`,
96
99
  SET_LAYOUT_MODE = `${LAYOUT_ACTION}/set-layout-mode`,
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type Plugin } from '../PluginHost';
5
+ import { type Plugin } from '../plugin-host';
6
6
 
7
7
  export type Metadata = Record<string, any>;
8
8
 
@@ -5,8 +5,8 @@
5
5
  import { Schema as S } from '@effect/schema';
6
6
  import { z } from 'zod';
7
7
 
8
- import type { IntentData } from '../IntentPlugin';
9
- import type { Plugin } from '../PluginHost';
8
+ import { type Plugin } from '../plugin-host';
9
+ import { type IntentData } from '../plugin-intent';
10
10
 
11
11
  // NOTE(thure): These are chosen from RFC 1738’s `safe` characters: http://www.faqs.org/rfcs/rfc1738.html
12
12
  export const SLUG_LIST_SEPARATOR = '+';
@@ -133,7 +133,10 @@ export const partLength = (layout: LayoutParts | undefined, part: LayoutPart | u
133
133
  // Intents
134
134
  //
135
135
 
136
- const NAVIGATION_ACTION = 'dxos.org/plugin/navigation';
136
+ const NAVIGATION_PLUGIN = 'dxos.org/plugin/navigation';
137
+
138
+ const NAVIGATION_ACTION = `${NAVIGATION_PLUGIN}/action`;
139
+
137
140
  export enum NavigationAction {
138
141
  OPEN = `${NAVIGATION_ACTION}/open`,
139
142
  ADD_TO_ACTIVE = `${NAVIGATION_ACTION}/add-to-active`,
@@ -4,8 +4,9 @@
4
4
 
5
5
  import { z } from 'zod';
6
6
 
7
- import type { Plugin } from '../PluginHost';
7
+ import { type Plugin } from '../plugin-host';
8
8
 
9
+ // TODO(burdon): Replace zed with effect.
9
10
  export const ResourceKey = z.union([z.string(), z.record(z.any())]);
10
11
  export type ResourceKey = z.infer<typeof ResourceKey>;
11
12
 
@@ -26,13 +27,6 @@ export type TranslationsProvides = {
26
27
  translations: Readonly<Resource[]>;
27
28
  };
28
29
 
29
- // TODO(wittjosiah): Add TranslationsProvides.
30
- // export type TranslationsProvides = {
31
- // translations: {
32
- // t: TFunction;
33
- // };
34
- // };
35
-
36
30
  /**
37
31
  * Type guard for translation plugins.
38
32
  */
@@ -2,14 +2,16 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { Context, type DisposeCallback } from '@dxos/context';
5
6
  import { raise } from '@dxos/debug';
7
+ import { invariant } from '@dxos/invariant';
6
8
 
7
- import { type Plugin } from './PluginHost';
9
+ import { type Plugin, type PluginDefinition } from './plugin-host';
8
10
 
9
11
  /**
10
- * Define a plugin
12
+ * Resolvers allow different instances of plugins to provide a particular capability.
11
13
  */
12
- export const definePlugin = <TProvides>(plugin: Plugin<TProvides>): Plugin<TProvides> => plugin;
14
+ export type PluginResolver<T> = (plugin: Plugin) => Plugin<T> | undefined;
13
15
 
14
16
  /**
15
17
  * Find a plugin by ID.
@@ -30,10 +32,8 @@ export const getPlugin = <T>(plugins: Plugin[], id: string): Plugin<T> => {
30
32
  /**
31
33
  * Filter a list of plugins to only those that match a predicate.
32
34
  */
33
- export const filterPlugins = <T>(
34
- plugins: Plugin[],
35
- predicate: (plugin: Plugin) => Plugin<T> | undefined,
36
- ): Plugin<T>[] => plugins.map((plugin) => predicate(plugin)).filter((plugin): plugin is Plugin<T> => !!plugin);
35
+ export const filterPlugins = <T>(plugins: Plugin[], predicate: PluginResolver<T>): Plugin<T>[] =>
36
+ plugins.map((plugin) => predicate(plugin)).filter((plugin): plugin is Plugin<T> => !!plugin);
37
37
 
38
38
  /**
39
39
  * Resolves a plugin by predicate.
@@ -42,7 +42,51 @@ export const filterPlugins = <T>(
42
42
  * import { parseIntentPlugin, resolvePlugin } from '@dxos/app-framework';
43
43
  * const intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
44
44
  */
45
- export const resolvePlugin = <T>(
46
- plugins: Plugin[],
47
- predicate: (plugin: Plugin) => Plugin<T> | undefined,
48
- ): Plugin<T> | undefined => filterPlugins(plugins, predicate)[0];
45
+ export const resolvePlugin = <T>(plugins: Plugin[], predicate: PluginResolver<T>): Plugin<T> | undefined =>
46
+ filterPlugins(plugins, predicate)[0];
47
+
48
+ class PluginContext {
49
+ // TODO(burdon): Use Resource (@dima)?
50
+ public readonly ctx = new Context();
51
+
52
+ private _plugins?: Plugin[];
53
+
54
+ init(plugins: Plugin[]) {
55
+ this._plugins = plugins;
56
+ }
57
+
58
+ getPlugin<T>(id: string): Plugin<T> {
59
+ invariant(this._plugins);
60
+ return getPlugin(this._plugins, id);
61
+ }
62
+
63
+ resolvePlugin<T>(resolver: PluginResolver<T>): Plugin<T>;
64
+ resolvePlugin<T>(resolver: PluginResolver<T>, required = false): Plugin<T> | undefined {
65
+ invariant(this._plugins, 'context not initialized');
66
+ const plugin = resolvePlugin(this._plugins, resolver);
67
+ if (required && !plugin) {
68
+ // TODO(burdon): Resolver should have a name.
69
+ throw new Error('Plugin not found.');
70
+ }
71
+
72
+ return plugin;
73
+ }
74
+
75
+ onDispose(cb: DisposeCallback) {
76
+ this.ctx.onDispose(cb);
77
+ }
78
+
79
+ dispose() {
80
+ void this.ctx.dispose();
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Plugin helper with dependency injection and life-cycle support.
86
+ */
87
+ export const definePlugin = <Provides>(
88
+ cb: (context: PluginContext) => PluginDefinition<Provides>,
89
+ ): (() => PluginDefinition<Provides>) => {
90
+ const context = new PluginContext();
91
+ return () => cb(context);
92
+ };
@@ -5,6 +5,7 @@
5
5
  export * from './common';
6
6
  export * from './helpers';
7
7
 
8
- export * from './IntentPlugin';
9
- export * from './PluginHost';
10
- export * from './SurfacePlugin';
8
+ export * from './plugin-intent';
9
+ export * from './plugin-host';
10
+ export * from './plugin-settings';
11
+ export * from './plugin-surface';
@@ -9,9 +9,9 @@ import { LocalStorageStore } from '@dxos/local-storage';
9
9
  import { PluginContainer } from './PluginContainer';
10
10
  import { type PluginContext, PluginProvider } from './PluginContext';
11
11
  import { type Plugin, type PluginDefinition, type PluginMeta } from './plugin';
12
- import { ErrorBoundary } from '../SurfacePlugin';
12
+ import { ErrorBoundary } from '../plugin-surface';
13
13
 
14
- export type BootstrapPluginsParams = {
14
+ export type HostPluginParams = {
15
15
  plugins: Record<string, () => Promise<PluginDefinition>>;
16
16
  // Ordered list of plugins.
17
17
  meta: PluginMeta[];
@@ -21,32 +21,33 @@ export type BootstrapPluginsParams = {
21
21
  placeholder?: ReactNode;
22
22
  };
23
23
 
24
- export type PluginHostProvides = {
24
+ export type HostPluginProvides = {
25
25
  plugins: PluginContext;
26
26
  };
27
27
 
28
28
  export const parsePluginHost = (plugin: Plugin) =>
29
- (plugin.provides as PluginHostProvides).plugins ? (plugin as Plugin<PluginHostProvides>) : undefined;
29
+ (plugin.provides as HostPluginProvides).plugins ? (plugin as Plugin<HostPluginProvides>) : undefined;
30
30
 
31
- const PLUGIN_HOST = 'dxos.org/plugin/host';
31
+ const HOST_PLUGIN = 'dxos.org/plugin/host';
32
32
 
33
33
  /**
34
34
  * Bootstraps an application by initializing plugins and rendering root components.
35
35
  */
36
- export const PluginHost = ({
36
+ export const HostPlugin = ({
37
37
  plugins,
38
38
  meta,
39
39
  core,
40
40
  defaults = [],
41
41
  fallback = DefaultFallback,
42
42
  placeholder = null,
43
- }: BootstrapPluginsParams): PluginDefinition<PluginHostProvides> => {
44
- const state = new LocalStorageStore<PluginContext>(PLUGIN_HOST, {
43
+ }: HostPluginParams): PluginDefinition<HostPluginProvides> => {
44
+ const state = new LocalStorageStore<PluginContext>(HOST_PLUGIN, {
45
45
  ready: false,
46
46
  core,
47
47
  enabled: [...defaults],
48
48
  plugins: [],
49
49
  available: meta.filter(({ id }) => !core.includes(id)),
50
+ // TODO(burdon): Functions should not be part of the settings type.
50
51
  setPlugin: (id: string, enabled: boolean) => {
51
52
  if (enabled) {
52
53
  state.values.enabled.push(id);
@@ -62,7 +63,7 @@ export const PluginHost = ({
62
63
 
63
64
  return {
64
65
  meta: {
65
- id: PLUGIN_HOST,
66
+ id: HOST_PLUGIN,
66
67
  name: 'Plugin host',
67
68
  },
68
69
  provides: {
@@ -6,11 +6,11 @@ import React, { type JSX, type FC, type PropsWithChildren, type ReactNode, useEf
6
6
 
7
7
  import { log } from '@dxos/log';
8
8
 
9
+ import { type HostPluginParams } from './HostPlugin';
9
10
  import { type PluginContext } from './PluginContext';
10
- import { type BootstrapPluginsParams } from './PluginHost';
11
11
  import { type Plugin, type PluginDefinition, type PluginProvides } from './plugin';
12
12
 
13
- export type PluginContainerProps = Pick<BootstrapPluginsParams, 'core'> & {
13
+ export type PluginContainerProps = Pick<HostPluginParams, 'core'> & {
14
14
  plugins: Record<string, () => Promise<PluginDefinition>>;
15
15
  state: PluginContext;
16
16
  placeholder: ReactNode;
@@ -41,6 +41,7 @@ export type PluginContext = {
41
41
  * Mark plugin as enabled.
42
42
  * Requires reload to take effect.
43
43
  */
44
+ // TODO(burdon): Functions should not be part of the settings type.
44
45
  setPlugin: (id: string, enabled: boolean) => void;
45
46
  };
46
47
 
@@ -3,5 +3,6 @@
3
3
  //
4
4
 
5
5
  export * from './plugin';
6
+
7
+ export * from './HostPlugin';
6
8
  export * from './PluginContext';
7
- export * from './PluginHost';
@@ -17,8 +17,8 @@ import {
17
17
  parseIntentResolverPlugin,
18
18
  IntentAction,
19
19
  } from './provides';
20
- import type { PluginDefinition } from '../PluginHost';
21
20
  import { filterPlugins, findPlugin } from '../helpers';
21
+ import { type PluginDefinition } from '../plugin-host';
22
22
 
23
23
  const EXECUTION_LIMIT = 1000;
24
24
  const HISTORY_LIMIT = 100;
@@ -27,7 +27,7 @@ const HISTORY_LIMIT = 100;
27
27
  * Allows plugins to register intent handlers and routes sent intents to the appropriate plugin.
28
28
  * Inspired by https://developer.android.com/reference/android/content/Intent.
29
29
  */
30
- const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
30
+ export const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
31
31
  const state = create<IntentContext>({
32
32
  dispatch: async () => ({}),
33
33
  undo: async () => ({}),
@@ -54,8 +54,7 @@ const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
54
54
  }
55
55
 
56
56
  const plugin = findPlugin<IntentResolverProvides>(plugins, intent.plugin);
57
- const result = plugin?.provides.intent.resolver(intent, plugins);
58
- return result;
57
+ return plugin?.provides.intent.resolver(intent, plugins);
59
58
  }
60
59
 
61
60
  for (const entry of dynamicResolvers) {
@@ -150,5 +149,3 @@ const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
150
149
  },
151
150
  };
152
151
  };
153
-
154
- export default IntentPlugin;
@@ -2,7 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { IntentPlugin } from './IntentPlugin';
6
+
5
7
  export * from './intent';
6
8
  export * from './provides';
7
9
 
8
10
  export * from './IntentContext';
11
+
12
+ export default IntentPlugin;
@@ -4,7 +4,7 @@
4
4
 
5
5
  import type { MaybePromise } from '@dxos/util';
6
6
 
7
- import type { Plugin } from '../PluginHost';
7
+ import type { Plugin } from '../plugin-host';
8
8
 
9
9
  export type IntentData<T extends Record<string, any> = Record<string, any>> = T & {
10
10
  /**
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { type IntentContext } from './IntentContext';
6
6
  import { type IntentResolver } from './intent';
7
- import { type Plugin } from '../PluginHost';
7
+ import { type Plugin } from '../plugin-host';
8
8
 
9
9
  export type IntentResolverProvides = {
10
10
  intent: {
@@ -26,7 +26,10 @@ export const parseIntentResolverPlugin = (plugin: Plugin) =>
26
26
  // Intents
27
27
  //
28
28
 
29
- const INTENT_ACTION = 'dxos.org/plugin/intent';
29
+ const INTENT_PLUGIN = 'dxos.org/plugin/intent';
30
+
31
+ const INTENT_ACTION = `${INTENT_PLUGIN}/action`;
32
+
30
33
  export enum IntentAction {
31
34
  /**
32
35
  * Fired after an intent is dispatched if the intent is undoable.
@@ -0,0 +1,22 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { RootSettingsStore } from '@dxos/local-storage';
6
+
7
+ import SettingsMeta from './meta';
8
+ import { type SettingsPluginProvides } from './provides';
9
+ import { type PluginDefinition } from '../plugin-host';
10
+
11
+ export const SettingsPlugin = (): PluginDefinition<SettingsPluginProvides> => {
12
+ // Global settings singleton.
13
+ // TODO(burdon): Make settings storage extensible so that other plugins can decide the persistence of them.
14
+ const settingsStore = new RootSettingsStore();
15
+
16
+ return {
17
+ meta: SettingsMeta,
18
+ provides: {
19
+ settingsStore,
20
+ },
21
+ };
22
+ };
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { SettingsPlugin } from './SettingsPlugin';
6
+
7
+ export * from './provides';
8
+
9
+ export default SettingsPlugin;
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ const SettingsMeta = {
6
+ id: 'dxos.org/plugin/settings',
7
+ };
8
+
9
+ export default SettingsMeta;
@@ -0,0 +1,29 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type SettingsStoreFactory, type SettingsValue } from '@dxos/local-storage';
6
+
7
+ import { type Plugin } from '../plugin-host';
8
+
9
+ export type SettingsProvides<T extends SettingsValue> = {
10
+ settings: T;
11
+ };
12
+
13
+ export type SettingsPluginProvides = {
14
+ settingsStore: SettingsStoreFactory;
15
+ };
16
+
17
+ export const parseSettingsPlugin = (plugin: Plugin) => {
18
+ return typeof (plugin.provides as any).settingsStore === 'object'
19
+ ? (plugin as Plugin<SettingsPluginProvides>)
20
+ : undefined;
21
+ };
22
+
23
+ const SETTINGS_PLUGIN = 'dxos.org/plugin/settings';
24
+
25
+ const SETTINGS_ACTION = `${SETTINGS_PLUGIN}/action`;
26
+
27
+ export enum SettingsAction {
28
+ OPEN = `${SETTINGS_ACTION}/open`,
29
+ }
@@ -18,6 +18,7 @@ import React, {
18
18
  } from 'react';
19
19
 
20
20
  import { raise } from '@dxos/debug';
21
+ import { log } from '@dxos/log';
21
22
 
22
23
  import { ErrorBoundary } from './ErrorBoundary';
23
24
  import { type SurfaceComponent, type SurfaceResult, useSurfaceRoot } from './SurfaceRootContext';
@@ -31,6 +32,11 @@ export type Direction = 'inline' | 'inline-reverse' | 'block' | 'block-reverse';
31
32
  * SurfaceProps are the props that are passed to the Surface component.
32
33
  */
33
34
  export type SurfaceProps = PropsWithChildren<{
35
+ /**
36
+ * Optional ID for debugging.
37
+ */
38
+ id?: string;
39
+
34
40
  /**
35
41
  * Role defines how the data should be rendered.
36
42
  */
@@ -82,40 +88,45 @@ export type SurfaceProps = PropsWithChildren<{
82
88
  [key: string]: unknown;
83
89
  }>;
84
90
 
91
+ let count = 0;
92
+
85
93
  /**
86
94
  * A surface is a named region of the screen that can be populated by plugins.
87
95
  */
88
96
  export const Surface = memo(
89
- forwardRef<HTMLElement, SurfaceProps>(({ role, name = role, fallback, placeholder, ...rest }, forwardedRef) => {
90
- const props = { role, name, fallback, ...rest };
91
- const { debugInfo } = useSurfaceRoot();
92
-
93
- // Track debug info.
94
- const [id] = useState<string>(Math.random().toString(36).slice(2));
95
- useEffect(() => {
96
- debugInfo?.set(id, { id, created: Date.now(), name, role, renderCount: 0 });
97
- return () => {
98
- debugInfo?.delete(id);
99
- };
100
- }, [id]);
101
- if (debugInfo?.get(id)) {
102
- debugInfo.get(id)!.renderCount++;
103
- }
104
-
105
- const context = useContext(SurfaceContext);
106
- const data = props.data ?? ((name && context?.surfaces?.[name]?.data) || {});
107
-
108
- const resolver = <SurfaceResolver {...props} ref={forwardedRef} />;
109
- const suspense = placeholder ? <Suspense fallback={placeholder}>{resolver}</Suspense> : resolver;
110
-
111
- return fallback ? (
112
- <ErrorBoundary data={data} fallback={fallback}>
113
- {suspense}
114
- </ErrorBoundary>
115
- ) : (
116
- suspense
117
- );
118
- }),
97
+ forwardRef<HTMLElement, SurfaceProps>(
98
+ ({ id: _id, role, name = role, fallback, placeholder, ...rest }, forwardedRef) => {
99
+ const props = { role, name, fallback, ...rest };
100
+ const { debugInfo } = useSurfaceRoot();
101
+
102
+ // Track debug info.
103
+ const [id] = useState<string>(() => _id ?? `surface-${++count}`);
104
+ useEffect(() => {
105
+ debugInfo?.set(id, { id, created: Date.now(), name, role, renderCount: 0 });
106
+ return () => {
107
+ debugInfo?.delete(id);
108
+ };
109
+ }, [id]);
110
+
111
+ if (debugInfo?.get(id)) {
112
+ debugInfo.get(id)!.renderCount++;
113
+ }
114
+
115
+ const context = useContext(SurfaceContext);
116
+ const data = props.data ?? ((name && context?.surfaces?.[name]?.data) || {});
117
+
118
+ const resolver = <SurfaceResolver {...props} id={id} ref={forwardedRef} />;
119
+ const suspense = placeholder ? <Suspense fallback={placeholder}>{resolver}</Suspense> : resolver;
120
+
121
+ return fallback ? (
122
+ <ErrorBoundary data={data} fallback={fallback}>
123
+ {suspense}
124
+ </ErrorBoundary>
125
+ ) : (
126
+ suspense
127
+ );
128
+ },
129
+ ),
119
130
  );
120
131
 
121
132
  const SurfaceContext = createContext<SurfaceProps | undefined>(undefined);
@@ -123,6 +134,9 @@ const SurfaceContext = createContext<SurfaceProps | undefined>(undefined);
123
134
  export const useSurface = (): SurfaceProps =>
124
135
  useContext(SurfaceContext) ?? raise(new Error('Surface context not found'));
125
136
 
137
+ /**
138
+ * Root surface component.
139
+ */
126
140
  const SurfaceResolver = forwardRef<HTMLElement, SurfaceProps>((props, forwardedRef) => {
127
141
  const { components } = useSurfaceRoot();
128
142
  const parent = useContext(SurfaceContext);
@@ -152,30 +166,30 @@ const resolveNodes = (
152
166
  ...props.data,
153
167
  };
154
168
 
155
- const nodes = Object.entries(components)
169
+ const candidates = Object.entries(components)
156
170
  .map(([key, component]): [string, SurfaceResult] | undefined => {
171
+ // TODO(burdon): Avoid variable return types in plugin contract.
157
172
  const result = component({ ...props, data }, forwardedRef);
158
173
  if (!result || typeof result !== 'object') {
159
174
  return undefined;
160
175
  }
161
176
 
162
- return 'node' in result ? [key, result] : isValidElement(result) ? [key, { node: result }] : undefined;
163
- })
164
- .filter((result): result is [string, SurfaceResult] => Boolean(result))
165
- .sort(([, a], [, b]) => {
166
- const aDisposition = a.disposition ?? 'default';
167
- const bDisposition = b.disposition ?? 'default';
168
- if (aDisposition === bDisposition) {
169
- return 0;
170
- } else if (aDisposition === 'hoist' || bDisposition === 'fallback') {
171
- return -1;
172
- } else if (bDisposition === 'hoist' || aDisposition === 'fallback') {
173
- return 1;
177
+ // Normalize tuple.
178
+ if ('node' in result) {
179
+ return [key, result];
180
+ } else if (isValidElement(result)) {
181
+ return [key, { node: result }];
182
+ } else {
183
+ log.warn('invalid result', { result });
184
+ return undefined;
174
185
  }
175
-
176
- return 0;
177
186
  })
178
- .map(([key, result]) => <Fragment key={key}>{result.node}</Fragment>);
187
+ .filter((result): result is [string, SurfaceResult] => Boolean(result))
188
+ .sort(([, { disposition: a = 'default' }], [, { disposition: b = 'default' }]) => {
189
+ return a === b ? 0 : a === 'hoist' || b === 'fallback' ? -1 : b === 'hoist' || a === 'fallback' ? 1 : 0;
190
+ });
179
191
 
192
+ // TODO(burdon): Does this prematurely process the node?
193
+ const nodes = candidates.map(([key, result]) => <Fragment key={key}>{result.node}</Fragment>);
180
194
  return props.limit ? nodes.slice(0, props.limit) : nodes;
181
195
  };
@@ -9,13 +9,13 @@ import { create } from '@dxos/echo-schema';
9
9
  import { SurfaceProvider, type SurfaceRootContext } from './SurfaceRootContext';
10
10
  import SurfaceMeta from './meta';
11
11
  import { parseSurfacePlugin, type SurfacePluginProvides } from './provides';
12
- import { type PluginDefinition } from '../PluginHost';
13
12
  import { filterPlugins } from '../helpers';
13
+ import { type PluginDefinition } from '../plugin-host';
14
14
 
15
15
  /**
16
16
  * Provides a registry of surface components.
17
17
  */
18
- const SurfacePlugin = (): PluginDefinition<SurfacePluginProvides> => {
18
+ export const SurfacePlugin = (): PluginDefinition<SurfacePluginProvides> => {
19
19
  const state = create<SurfaceRootContext>({ components: {}, debugInfo: new Map() });
20
20
 
21
21
  return {
@@ -31,5 +31,3 @@ const SurfacePlugin = (): PluginDefinition<SurfacePluginProvides> => {
31
31
  },
32
32
  };
33
33
  };
34
-
35
- export default SurfacePlugin;
@@ -2,9 +2,13 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { SurfacePlugin } from './SurfacePlugin';
6
+
5
7
  export * from './helpers';
6
8
  export * from './provides';
7
9
 
8
10
  export * from './ErrorBoundary';
9
11
  export * from './Surface';
10
12
  export * from './SurfaceRootContext';
13
+
14
+ export default SurfacePlugin;
@@ -3,8 +3,9 @@
3
3
  //
4
4
 
5
5
  import { type SurfaceComponent, type SurfaceRootContext } from './SurfaceRootContext';
6
- import { type Plugin } from '../PluginHost';
6
+ import { type Plugin } from '../plugin-host';
7
7
 
8
+ // TODO(burdon): Predicate based providers?
8
9
  export type SurfaceProvides = {
9
10
  surface: {
10
11
  /**