@dxos/app-framework 0.3.11-main.f14932f → 0.3.11-main.f4c1077

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 (38) hide show
  1. package/dist/lib/browser/{chunk-QYIBDGYI.mjs → chunk-7MQ2DVDI.mjs} +2 -3
  2. package/dist/lib/browser/{chunk-QYIBDGYI.mjs.map → chunk-7MQ2DVDI.mjs.map} +2 -2
  3. package/dist/lib/browser/index.mjs +180 -147
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/{plugin-YLDDUID4.mjs → plugin-PGPBA2JO.mjs} +36 -13
  7. package/dist/lib/browser/plugin-PGPBA2JO.mjs.map +7 -0
  8. package/dist/lib/node/{chunk-YWRBMGDT.cjs → chunk-FETX4EGX.cjs} +5 -6
  9. package/dist/lib/node/{chunk-YWRBMGDT.cjs.map → chunk-FETX4EGX.cjs.map} +2 -2
  10. package/dist/lib/node/index.cjs +180 -149
  11. package/dist/lib/node/index.cjs.map +3 -3
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/{plugin-NP3IH5Q3.cjs → plugin-HLGHD6N5.cjs} +43 -19
  14. package/dist/lib/node/plugin-HLGHD6N5.cjs.map +7 -0
  15. package/dist/types/src/plugins/IntentPlugin/intent.d.ts +33 -2
  16. package/dist/types/src/plugins/IntentPlugin/intent.d.ts.map +1 -1
  17. package/dist/types/src/plugins/IntentPlugin/plugin.d.ts.map +1 -1
  18. package/dist/types/src/plugins/PluginHost/PluginHost.d.ts +4 -2
  19. package/dist/types/src/plugins/PluginHost/PluginHost.d.ts.map +1 -1
  20. package/dist/types/src/plugins/PluginHost/plugin.d.ts +1 -1
  21. package/dist/types/src/plugins/PluginHost/plugin.d.ts.map +1 -1
  22. package/dist/types/src/plugins/SurfacePlugin/Surface.d.ts +4 -5
  23. package/dist/types/src/plugins/SurfacePlugin/Surface.d.ts.map +1 -1
  24. package/dist/types/src/plugins/common/layout.d.ts +15 -14
  25. package/dist/types/src/plugins/common/layout.d.ts.map +1 -1
  26. package/package.json +8 -7
  27. package/project.json +3 -1
  28. package/src/plugins/IntentPlugin/IntentContext.tsx +1 -1
  29. package/src/plugins/IntentPlugin/intent.ts +38 -2
  30. package/src/plugins/IntentPlugin/plugin.tsx +38 -9
  31. package/src/plugins/PluginHost/PluginHost.tsx +92 -57
  32. package/src/plugins/PluginHost/plugin.ts +2 -1
  33. package/src/plugins/SurfacePlugin/Surface.tsx +15 -21
  34. package/src/plugins/common/layout.ts +15 -14
  35. package/src/vite-env.d.ts +5 -0
  36. package/tsconfig.json +3 -0
  37. package/dist/lib/browser/plugin-YLDDUID4.mjs.map +0 -7
  38. package/dist/lib/node/plugin-NP3IH5Q3.cjs.map +0 -7
@@ -1,12 +1,14 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type PluginContext } from './PluginContext';
3
3
  import { type Plugin, type PluginDefinition } from './plugin';
4
+ import { ErrorBoundary } from '../SurfacePlugin';
4
5
  export type BootstrapPluginsParams = {
5
6
  order: PluginDefinition['meta'][];
6
7
  plugins: Record<string, () => Promise<PluginDefinition>>;
7
8
  core?: string[];
8
9
  defaults?: string[];
9
- fallback?: ReactNode;
10
+ fallback?: ErrorBoundary['props']['fallback'];
11
+ placeholder?: ReactNode;
10
12
  };
11
13
  export type PluginHostProvides = {
12
14
  plugins: PluginContext;
@@ -15,7 +17,7 @@ export declare const parsePluginHost: (plugin: Plugin) => Plugin<PluginHostProvi
15
17
  /**
16
18
  * Bootstraps an application by initializing plugins and rendering root components.
17
19
  */
18
- export declare const PluginHost: ({ order, plugins: definitions, core, defaults, fallback, }: BootstrapPluginsParams) => PluginDefinition<PluginHostProvides>;
20
+ export declare const PluginHost: ({ order, plugins: definitions, core, defaults, fallback, placeholder, }: BootstrapPluginsParams) => PluginDefinition<PluginHostProvides>;
19
21
  /**
20
22
  * Resolve a `PluginDefinition` into a fully initialized `Plugin`.
21
23
  */
@@ -1 +1 @@
1
- {"version":3,"file":"PluginHost.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/PluginHost.tsx"],"names":[],"mappings":"AAKA,OAAc,EAA8C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAK1F,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,gBAAgB,EAAuB,MAAM,UAAU,CAAC;AAEnF,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,MAAM,2CACwD,CAAC;AAIvG;;GAEG;AACH,eAAO,MAAM,UAAU,+DAMpB,sBAAsB,KAAG,iBAAiB,kBAAkB,CAmF9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,4EAS5B,CAAC"}
1
+ {"version":3,"file":"PluginHost.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/PluginHost.tsx"],"names":[],"mappings":"AAKA,OAAc,EAA8C,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAKpG,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,gBAAgB,EAAuB,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;IAC9C,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,MAAM,2CACwD,CAAC;AAIvG;;GAEG;AACH,eAAO,MAAM,UAAU,4EAOpB,sBAAsB,KAAG,iBAAiB,kBAAkB,CAkC9D,CAAC;AAmFF;;GAEG;AACH,eAAO,MAAM,gBAAgB,4EAS5B,CAAC"}
@@ -70,7 +70,7 @@ export type PluginDefinition<TProvides = {}, TInitializeProvides = {}> = Omit<Pl
70
70
  *
71
71
  * @return Capabilities provided by the plugin which are merged with base capabilities.
72
72
  */
73
- initialize?: () => Promise<PluginProvides<TInitializeProvides>>;
73
+ initialize?: () => Promise<PluginProvides<TInitializeProvides> | void>;
74
74
  /**
75
75
  * Called once all plugins have been initialized.
76
76
  * This is the place to do any initialization which requires other plugins to be ready.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,SAAS,IAAI,SAAS,GAAG;IAClD;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAKhC,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,MAAM,CAAC,SAAS,GAAG,EAAE,IAAI;IACnC,IAAI,EAAE;QACJ;;;;;;WAMG;QACH,EAAE,EAAE,MAAM,CAAC;QAEX;;;;WAIG;QAEH,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;QAEd;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAElB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAEhB;;WAEG;QAEH,aAAa,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;KAC/B,CAAC;IAEF;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,SAAS,GAAG,EAAE,EAAE,mBAAmB,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG;IAClG;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC;IAEzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAEhE;;;;;OAKG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,UAAU,SAAU,MAAM,CAAC,MAAM,CAAC;IAjF3C;;;;;;OAMG;QACC,MAAM;IAEV;;;;OAIG;;IAIH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;CA0CiD,CAAC;AAEzD,KAAK,UAAU,CAAC,CAAC,IAAI,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,gBAAgB,CAAA;CAAE,CAAC,CAAC;AAEhF,yBAAiB,MAAM,CAAC;IACf,MAAM,IAAI,yFAKhB,CAAC;CACH"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,SAAS,IAAI,SAAS,GAAG;IAClD;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAKhC,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,MAAM,CAAC,SAAS,GAAG,EAAE,IAAI;IACnC,IAAI,EAAE;QACJ;;;;;;WAMG;QACH,EAAE,EAAE,MAAM,CAAC;QAEX;;;;WAIG;QAEH,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;QAEd;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAElB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAEhB;;WAEG;QAEH,aAAa,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;KAC/B,CAAC;IAEF;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,SAAS,GAAG,EAAE,EAAE,mBAAmB,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG;IAClG;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC;IAEzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC,CAAC;IAEvE;;;;;OAKG;IAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,UAAU,SAAU,MAAM,CAAC,MAAM,CAAC;IAlF3C;;;;;;OAMG;QACC,MAAM;IAEV;;;;OAIG;;IAIH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;CA2CiD,CAAC;AAEzD,KAAK,UAAU,CAAC,CAAC,IAAI,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,gBAAgB,CAAA;CAAE,CAAC,CAAC;AAEhF,yBAAiB,MAAM,CAAC;IACf,MAAM,IAAI,yFAKhB,CAAC;CACH"}
@@ -1,4 +1,4 @@
1
- import React, { type FC, type PropsWithChildren } from 'react';
1
+ import React, { type ReactNode, type PropsWithChildren } from 'react';
2
2
  import { ErrorBoundary } from './ErrorBoundary';
3
3
  /**
4
4
  * Direction determines how multiple components are laid out.
@@ -28,11 +28,10 @@ export type SurfaceProps = PropsWithChildren<{
28
28
  */
29
29
  fallback?: ErrorBoundary['props']['fallback'];
30
30
  /**
31
- * If specified, this will render if no plugin can offer renderable content for the surface.
32
- *
33
- * @deprecated Provide a component with `disposition: 'fallback'` instead.
31
+ * If specified, the Surface will be wrapped in a suspense boundary.
32
+ * The placeholder component will be rendered while the surface component is loading.
34
33
  */
35
- contentFallback?: FC<{}>;
34
+ placeholder?: ReactNode;
36
35
  /**
37
36
  * If more than one component is resolved, the limit determines how many are rendered.
38
37
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Surface.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/SurfacePlugin/Surface.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAEZ,KAAK,EAAE,EAIP,KAAK,iBAAiB,EAEvB,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,gBAAgB,GAAG,OAAO,GAAG,eAAe,CAAC;AAEhF,MAAM,MAAM,YAAY,GAAG,iBAAiB,CAAC;IAC3C;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC;IAEnE;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;IAE9C;;;;OAIG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IAEzB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;OAGG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,OAAO,yGAkBnB,CAAC"}
1
+ {"version":3,"file":"Surface.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/SurfacePlugin/Surface.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAEZ,KAAK,SAAS,EAGd,KAAK,iBAAiB,EAGvB,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,gBAAgB,GAAG,OAAO,GAAG,eAAe,CAAC;AAEhF,MAAM,MAAM,YAAY,GAAG,iBAAiB,CAAC;IAC3C;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC;IAEnE;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;IAE9C;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;OAGG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,OAAO,yGAiBnB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { type IntentData } from '../IntentPlugin';
2
3
  import type { Plugin } from '../PluginHost';
3
4
  /**
4
5
  * Basic state provided by a layout plugin.
@@ -63,28 +64,28 @@ export declare enum LayoutAction {
63
64
  * Expected payload for layout actions.
64
65
  */
65
66
  export declare namespace LayoutAction {
66
- type ToggleFullscreen = {
67
+ type ToggleFullscreen = IntentData<{
67
68
  state?: boolean;
68
- };
69
- type ToggleSidebar = {
69
+ }>;
70
+ type ToggleSidebar = IntentData<{
70
71
  state?: boolean;
71
- };
72
- type ToggleComplementarySidebar = {
72
+ }>;
73
+ type ToggleComplementarySidebar = IntentData<{
73
74
  state?: boolean;
74
- };
75
- type OpenDialog = {
75
+ }>;
76
+ type OpenDialog = IntentData<{
76
77
  component: string;
77
78
  subject: any;
78
- };
79
- type CloseDialog = {};
80
- type OpenPopover = {
79
+ }>;
80
+ type CloseDialog = IntentData<{}>;
81
+ type OpenPopover = IntentData<{
81
82
  anchorId: string;
82
83
  component: string;
83
84
  subject: any;
84
- };
85
- type ClosePopover = {};
86
- type Activate = {
85
+ }>;
86
+ type ClosePopover = IntentData<{}>;
87
+ type Activate = IntentData<{
87
88
  id: string;
88
- };
89
+ }>;
89
90
  }
90
91
  //# sourceMappingURL=layout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/common/layout.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAM5C;;GAEG;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBjB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,WAAY,MAAM,uCAG/C,CAAC;AAQF,oBAAY,YAAY;IACtB,iBAAiB,6CAAuC;IACxD,cAAc,0CAAoC;IAClD,4BAA4B,wDAAkD;IAC9E,WAAW,uCAAiC;IAC5C,YAAY,wCAAkC;IAC9C,YAAY,wCAAkC;IAC9C,aAAa,yCAAmC;IAChD,QAAQ,oCAA8B;IACtC,KAAK,iCAA2B;CACjC;AAED;;GAEG;AACH,yBAAiB,YAAY,CAAC;IAC5B,KAAY,gBAAgB,GAAG;QAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IAEF,KAAY,aAAa,GAAG;QAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IAEF,KAAY,0BAA0B,GAAG;QACvC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IAEF,KAAY,UAAU,GAAG;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,GAAG,CAAC;KACd,CAAC;IAEF,KAAY,WAAW,GAAG,EAAE,CAAC;IAE7B,KAAY,WAAW,GAAG;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,GAAG,CAAC;KACd,CAAC;IAEF,KAAY,YAAY,GAAG,EAAE,CAAC;IAE9B,KAAY,QAAQ,GAAG;QACrB,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;CACH"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/common/layout.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAM5C;;GAEG;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBjB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,WAAY,MAAM,uCAG/C,CAAC;AAQF,oBAAY,YAAY;IACtB,iBAAiB,6CAAuC;IACxD,cAAc,0CAAoC;IAClD,4BAA4B,wDAAkD;IAC9E,WAAW,uCAAiC;IAC5C,YAAY,wCAAkC;IAC9C,YAAY,wCAAkC;IAC9C,aAAa,yCAAmC;IAChD,QAAQ,oCAA8B;IACtC,KAAK,iCAA2B;CACjC;AAED;;GAEG;AACH,yBAAiB,YAAY,CAAC;IAC5B,KAAY,gBAAgB,GAAG,UAAU,CAAC;QACxC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;IAEH,KAAY,aAAa,GAAG,UAAU,CAAC;QACrC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;IAEH,KAAY,0BAA0B,GAAG,UAAU,CAAC;QAClD,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;IAEH,KAAY,UAAU,GAAG,UAAU,CAAC;QAClC,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,GAAG,CAAC;KACd,CAAC,CAAC;IAEH,KAAY,WAAW,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;IAEzC,KAAY,WAAW,GAAG,UAAU,CAAC;QACnC,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,GAAG,CAAC;KACd,CAAC,CAAC;IAEH,KAAY,YAAY,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;IAE1C,KAAY,QAAQ,GAAG,UAAU,CAAC;QAChC,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC,CAAC;CACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/app-framework",
3
- "version": "0.3.11-main.f14932f",
3
+ "version": "0.3.11-main.f4c1077",
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",
@@ -16,12 +16,13 @@
16
16
  "@preact/signals-react": "^1.3.6",
17
17
  "deepsignal": "1.4.0-shallow.0",
18
18
  "zod": "^3.22.4",
19
- "@dxos/app-graph": "0.3.11-main.f14932f",
20
- "@dxos/async": "0.3.11-main.f14932f",
21
- "@dxos/debug": "0.3.11-main.f14932f",
22
- "@dxos/invariant": "0.3.11-main.f14932f",
23
- "@dxos/log": "0.3.11-main.f14932f",
24
- "@dxos/local-storage": "0.3.11-main.f14932f"
19
+ "@dxos/app-graph": "0.3.11-main.f4c1077",
20
+ "@dxos/async": "0.3.11-main.f4c1077",
21
+ "@dxos/debug": "0.3.11-main.f4c1077",
22
+ "@dxos/local-storage": "0.3.11-main.f4c1077",
23
+ "@dxos/log": "0.3.11-main.f4c1077",
24
+ "@dxos/invariant": "0.3.11-main.f4c1077",
25
+ "@dxos/util": "0.3.11-main.f4c1077"
25
26
  },
26
27
  "devDependencies": {
27
28
  "@types/react": "^18.0.21",
package/project.json CHANGED
@@ -19,7 +19,9 @@
19
19
  }
20
20
  }
21
21
  },
22
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
22
23
  "implicitDependencies": [
23
24
  "test"
24
- ]
25
+ ],
26
+ "name": "app-framework"
25
27
  }
@@ -15,7 +15,7 @@ export type IntentContext = {
15
15
  };
16
16
 
17
17
  const IntentContext: Context<IntentContext> = createContext<IntentContext>({
18
- dispatch: async () => {},
18
+ dispatch: async () => ({}),
19
19
  registerResolver: () => () => {},
20
20
  });
21
21
 
@@ -2,8 +2,17 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import type { MaybePromise } from '@dxos/util';
6
+
5
7
  import type { Plugin } from '../PluginHost';
6
8
 
9
+ export type IntentData<T extends Record<string, any> = Record<string, any>> = T & {
10
+ /**
11
+ * The data from the result of the previous intent.
12
+ */
13
+ result?: any;
14
+ };
15
+
7
16
  /**
8
17
  * An intent is an abstract description of an operation to be performed.
9
18
  * Intents allow actions to be performed across plugins.
@@ -24,7 +33,28 @@ export type Intent = {
24
33
  /**
25
34
  * Any data needed to perform the desired action.
26
35
  */
36
+ data?: IntentData;
37
+ };
38
+
39
+ export type IntentResult = {
40
+ /**
41
+ * The output of the action that was performed.
42
+ *
43
+ * If the intent is apart of a chain of intents, the data will be passed to the next intent.
44
+ */
27
45
  data?: any;
46
+
47
+ /**
48
+ * An error that occurred while performing the action.
49
+ *
50
+ * If the intent is apart of a chain of intents and an error occurs, the chain will be aborted.
51
+ */
52
+ error?: Error;
53
+
54
+ /**
55
+ * Other intent chains to be triggered.
56
+ */
57
+ intents?: Intent[][];
28
58
  };
29
59
 
30
60
  /**
@@ -33,6 +63,12 @@ export type Intent = {
33
63
  *
34
64
  * @returns The result of the last intent.
35
65
  */
36
- export type IntentDispatcher = (intent: Intent | Intent[]) => Promise<any>;
66
+ export type IntentDispatcher = (intent: Intent | Intent[]) => Promise<IntentResult | void>;
37
67
 
38
- export type IntentResolver = (intent: Intent, plugins: Plugin[]) => any;
68
+ /**
69
+ * Resolves an intent that was dispatched.
70
+ * If the intent is not handled, nothing should be returned.
71
+ *
72
+ * @returns The result of the intent.
73
+ */
74
+ export type IntentResolver = (intent: Intent, plugins: Plugin[]) => MaybePromise<IntentResult | void>;
@@ -5,19 +5,23 @@
5
5
  import { deepSignal } from 'deepsignal/react';
6
6
  import React from 'react';
7
7
 
8
+ import { log } from '@dxos/log';
9
+
8
10
  import { type IntentContext, IntentProvider } from './IntentContext';
9
- import type { Intent, IntentResolver } from './intent';
11
+ import type { Intent, IntentResolver, IntentResult } from './intent';
10
12
  import IntentMeta from './meta';
11
13
  import { type IntentPluginProvides, type IntentResolverProvides, parseIntentResolverPlugin } from './provides';
12
14
  import type { PluginDefinition } from '../PluginHost';
13
15
  import { filterPlugins, findPlugin } from '../helpers';
14
16
 
17
+ const EXECUTION_LIMIT = 1000;
18
+
15
19
  /**
16
20
  * Allows plugins to register intent handlers and routes sent intents to the appropriate plugin.
17
21
  * Inspired by https://developer.android.com/reference/android/content/Intent.
18
22
  */
19
23
  const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
20
- const state = deepSignal<IntentContext>({ dispatch: async () => {}, registerResolver: () => () => {} });
24
+ const state = deepSignal<IntentContext>({ dispatch: async () => ({}), registerResolver: () => () => {} });
21
25
 
22
26
  const dynamicResolvers = new Set<{ plugin: string; resolver: IntentResolver }>();
23
27
 
@@ -29,7 +33,7 @@ const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
29
33
  if (intent.plugin) {
30
34
  for (const entry of dynamicResolvers) {
31
35
  if (entry.plugin === intent.plugin) {
32
- const result = entry.resolver(intent, plugins);
36
+ const result = await entry.resolver(intent, plugins);
33
37
  if (result) {
34
38
  return result;
35
39
  }
@@ -37,11 +41,12 @@ const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
37
41
  }
38
42
 
39
43
  const plugin = findPlugin<IntentResolverProvides>(plugins, intent.plugin);
40
- return plugin?.provides.intent.resolver(intent, plugins);
44
+ const result = plugin?.provides.intent.resolver(intent, plugins);
45
+ return result;
41
46
  }
42
47
 
43
48
  for (const entry of dynamicResolvers) {
44
- const result = entry.resolver(intent, plugins);
49
+ const result = await entry.resolver(intent, plugins);
45
50
  if (result) {
46
51
  return result;
47
52
  }
@@ -54,18 +59,42 @@ const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
54
59
  return result;
55
60
  }
56
61
  }
62
+
63
+ // https://vitejs.dev/guide/env-and-mode#env-variables
64
+ // TODO(wittjosiah): How to handle this more generically?
65
+ if (import.meta?.env?.DEV) {
66
+ log.warn('No plugin found to handle intent', intent);
67
+ }
57
68
  };
58
69
 
59
70
  // Sequentially dispatch array of invents.
60
- state.dispatch = async (intentOrArray) => {
61
- let result: any = null;
71
+ const dispatchChain = async (intentOrArray: Intent | Intent[], depth = 0) => {
72
+ if (depth > EXECUTION_LIMIT) {
73
+ return {
74
+ error: new Error(
75
+ `Intent execution limit exceeded (${EXECUTION_LIMIT} iterations). This is likely due to an infinite loop within intent resolvers.`,
76
+ ),
77
+ };
78
+ }
79
+
80
+ let result: IntentResult | undefined;
62
81
  for (const intent of Array.isArray(intentOrArray) ? intentOrArray : [intentOrArray]) {
63
- const data = intent.data ? { ...result, ...intent.data } : result;
64
- result = await dispatch({ ...intent, data });
82
+ const data = intent.data ? { result: result?.data, ...intent.data } : result?.data;
83
+ result = (await dispatch({ ...intent, data })) ?? undefined;
84
+
85
+ if (result?.error) {
86
+ break;
87
+ }
88
+
89
+ result?.intents?.forEach((intents) => {
90
+ void dispatchChain(intents, depth + 1);
91
+ });
65
92
  }
93
+
66
94
  return result;
67
95
  };
68
96
 
97
+ state.dispatch = dispatchChain;
69
98
  state.registerResolver = (plugin, resolver) => {
70
99
  const entry = { plugin, resolver };
71
100
  dynamicResolvers.add(entry);
@@ -3,20 +3,22 @@
3
3
  //
4
4
 
5
5
  import { shallow } from 'deepsignal/react';
6
- import React, { useEffect, type FC, type PropsWithChildren, type ReactNode } from 'react';
6
+ import React, { useEffect, type FC, type PropsWithChildren, type ReactNode, useState } from 'react';
7
7
 
8
8
  import { LocalStorageStore } from '@dxos/local-storage';
9
9
  import { log } from '@dxos/log';
10
10
 
11
11
  import { type PluginContext, PluginProvider } from './PluginContext';
12
12
  import { type Plugin, type PluginDefinition, type PluginProvides } from './plugin';
13
+ import { ErrorBoundary } from '../SurfacePlugin';
13
14
 
14
15
  export type BootstrapPluginsParams = {
15
16
  order: PluginDefinition['meta'][];
16
17
  plugins: Record<string, () => Promise<PluginDefinition>>;
17
18
  core?: string[];
18
19
  defaults?: string[];
19
- fallback?: ReactNode;
20
+ fallback?: ErrorBoundary['props']['fallback'];
21
+ placeholder?: ReactNode;
20
22
  };
21
23
 
22
24
  export type PluginHostProvides = {
@@ -36,7 +38,8 @@ export const PluginHost = ({
36
38
  plugins: definitions,
37
39
  core = [],
38
40
  defaults = [],
39
- fallback = null,
41
+ fallback = DefaultFallback,
42
+ placeholder = null,
40
43
  }: BootstrapPluginsParams): PluginDefinition<PluginHostProvides> => {
41
44
  const state = new LocalStorageStore<PluginContext>(PLUGIN_HOST, {
42
45
  ready: false,
@@ -63,65 +66,97 @@ export const PluginHost = ({
63
66
  plugins: state.values,
64
67
  context: ({ children }) => <PluginProvider value={state.values}>{children}</PluginProvider>,
65
68
  root: () => {
66
- useEffect(() => {
67
- log('initializing plugins', { enabled: state.values.enabled });
68
- const timeout = setTimeout(async () => {
69
- const enabledIds = [...core, ...state.values.enabled].sort((a, b) => {
70
- const indexA = order.findIndex(({ id }) => id === a);
71
- const indexB = order.findIndex(({ id }) => id === b);
72
- return indexA - indexB;
73
- });
74
-
75
- const enabled = await Promise.all(
76
- enabledIds
77
- .map((id) => definitions[id])
78
- // If local storage indicates a plugin is enabled, but it is not available, ignore it.
79
- .filter((definition): definition is () => Promise<PluginDefinition> => Boolean(definition))
80
- .map((definition) => definition()),
81
- );
82
-
83
- const plugins = await Promise.all(
84
- enabled.map(async (definition) => {
85
- const plugin = await initializePlugin(definition).catch((err) => {
86
- console.error('Failed to initialize plugin:', definition.meta.id, err);
87
- return undefined;
88
- });
89
- return plugin;
90
- }),
91
- ).then((plugins) => plugins.filter((plugin): plugin is Plugin => Boolean(plugin)));
92
- log('plugins initialized', { plugins });
93
-
94
- await Promise.all(
95
- enabled.map(async (pluginDefinition) => {
96
- await pluginDefinition.ready?.(plugins);
97
- }),
98
- );
99
- log('plugins ready', { plugins });
100
-
101
- state.values.plugins = shallow(plugins);
102
- state.values.ready = true;
103
- });
104
-
105
- return () => {
106
- clearTimeout(timeout);
107
- state.values.ready = false;
108
- // TODO(wittjosiah): Does this ever need to be called prior to having dynamic plugins?
109
- // void Promise.all(enabled.map((definition) => definition.unload?.()));
110
- };
111
- }, []);
112
-
113
- if (!state.values.ready) {
114
- return <>{fallback}</>;
115
- }
116
-
117
- const ComposedContext = composeContext(state.values.plugins);
118
-
119
- return <ComposedContext>{rootComponents(state.values.plugins)}</ComposedContext>;
69
+ return (
70
+ <ErrorBoundary fallback={fallback}>
71
+ <Root order={order} core={core} definitions={definitions} state={state.values} placeholder={placeholder} />
72
+ </ErrorBoundary>
73
+ );
120
74
  },
121
75
  },
122
76
  };
123
77
  };
124
78
 
79
+ const DefaultFallback = ({ error }: { error: Error }) => {
80
+ return (
81
+ <div style={{ padding: '1rem' }}>
82
+ {/* TODO(wittjosiah): Link to docs for replacing default. */}
83
+ <h1 style={{ fontSize: '1.2rem', fontWeight: 700, margin: '0.5rem 0' }}>{error.message}</h1>
84
+ <pre>{error.stack}</pre>
85
+ </div>
86
+ );
87
+ };
88
+
89
+ type RootProps = {
90
+ order: PluginDefinition['meta'][];
91
+ state: PluginContext;
92
+ definitions: Record<string, () => Promise<PluginDefinition>>;
93
+ core: string[];
94
+ placeholder: ReactNode;
95
+ };
96
+
97
+ const Root = ({ order, core: corePluginIds, definitions, state, placeholder }: RootProps) => {
98
+ const [error, setError] = useState<unknown>();
99
+
100
+ useEffect(() => {
101
+ log('initializing plugins', { enabled: state.enabled });
102
+ const timeout = setTimeout(async () => {
103
+ try {
104
+ const enabledIds = [...corePluginIds, ...state.enabled].sort((a, b) => {
105
+ const indexA = order.findIndex(({ id }) => id === a);
106
+ const indexB = order.findIndex(({ id }) => id === b);
107
+ return indexA - indexB;
108
+ });
109
+
110
+ const enabled = await Promise.all(
111
+ enabledIds
112
+ .map((id) => definitions[id])
113
+ // If local storage indicates a plugin is enabled, but it is not available, ignore it.
114
+ .filter((definition): definition is () => Promise<PluginDefinition> => Boolean(definition))
115
+ .map((definition) => definition()),
116
+ );
117
+
118
+ const plugins = await Promise.all(
119
+ enabled.map(async (definition) => {
120
+ const plugin = await initializePlugin(definition).catch((err) => {
121
+ console.error('Failed to initialize plugin:', definition.meta.id, err);
122
+ return undefined;
123
+ });
124
+ return plugin;
125
+ }),
126
+ ).then((plugins) => plugins.filter((plugin): plugin is Plugin => Boolean(plugin)));
127
+ log('plugins initialized', { plugins });
128
+
129
+ await Promise.all(enabled.map((pluginDefinition) => pluginDefinition.ready?.(plugins)));
130
+ log('plugins ready', { plugins });
131
+
132
+ state.plugins = shallow(plugins);
133
+ state.ready = true;
134
+ } catch (err) {
135
+ setError(err);
136
+ }
137
+ });
138
+
139
+ return () => {
140
+ clearTimeout(timeout);
141
+ state.ready = false;
142
+ // TODO(wittjosiah): Does this ever need to be called prior to having dynamic plugins?
143
+ // void Promise.all(enabled.map((definition) => definition.unload?.()));
144
+ };
145
+ }, []);
146
+
147
+ if (error) {
148
+ throw error;
149
+ }
150
+
151
+ if (!state.ready) {
152
+ return <>{placeholder}</>;
153
+ }
154
+
155
+ const ComposedContext = composeContext(state.plugins);
156
+
157
+ return <ComposedContext>{rootComponents(state.plugins)}</ComposedContext>;
158
+ };
159
+
125
160
  /**
126
161
  * Resolve a `PluginDefinition` into a fully initialized `Plugin`.
127
162
  */
@@ -91,7 +91,7 @@ export type PluginDefinition<TProvides = {}, TInitializeProvides = {}> = Omit<Pl
91
91
  *
92
92
  * @return Capabilities provided by the plugin which are merged with base capabilities.
93
93
  */
94
- initialize?: () => Promise<PluginProvides<TInitializeProvides>>;
94
+ initialize?: () => Promise<PluginProvides<TInitializeProvides> | void>;
95
95
 
96
96
  /**
97
97
  * Called once all plugins have been initialized.
@@ -99,6 +99,7 @@ export type PluginDefinition<TProvides = {}, TInitializeProvides = {}> = Omit<Pl
99
99
  *
100
100
  * @param plugins All plugins which successfully initialized.
101
101
  */
102
+ // TODO(wittjosiah): Rename `ready` to a verb?
102
103
  ready?: (plugins: Plugin[]) => Promise<void>;
103
104
 
104
105
  /**
@@ -4,12 +4,12 @@
4
4
 
5
5
  import React, {
6
6
  forwardRef,
7
- type FC,
8
7
  type ReactNode,
9
8
  Fragment,
10
9
  type ForwardedRef,
11
10
  type PropsWithChildren,
12
11
  isValidElement,
12
+ Suspense,
13
13
  } from 'react';
14
14
  import { createContext, useContext } from 'react';
15
15
 
@@ -50,11 +50,10 @@ export type SurfaceProps = PropsWithChildren<{
50
50
  fallback?: ErrorBoundary['props']['fallback'];
51
51
 
52
52
  /**
53
- * If specified, this will render if no plugin can offer renderable content for the surface.
54
- *
55
- * @deprecated Provide a component with `disposition: 'fallback'` instead.
53
+ * If specified, the Surface will be wrapped in a suspense boundary.
54
+ * The placeholder component will be rendered while the surface component is loading.
56
55
  */
57
- contentFallback?: FC<{}>;
56
+ placeholder?: ReactNode;
58
57
 
59
58
  /**
60
59
  * If more than one component is resolved, the limit determines how many are rendered.
@@ -78,21 +77,20 @@ export type SurfaceProps = PropsWithChildren<{
78
77
  * A surface is a named region of the screen that can be populated by plugins.
79
78
  */
80
79
  export const Surface = forwardRef<HTMLElement, SurfaceProps>(
81
- ({ role, name = role, fallback, ...rest }, forwardedRef) => {
80
+ ({ role, name = role, fallback, placeholder, ...rest }, forwardedRef) => {
82
81
  const props = { role, name, fallback, ...rest };
83
82
  const context = useContext(SurfaceContext);
84
83
  const data = props.data ?? ((name && context?.surfaces?.[name]?.data) || {});
85
84
 
86
- return (
87
- <>
88
- {fallback ? (
89
- <ErrorBoundary data={data} fallback={fallback}>
90
- <SurfaceResolver {...props} ref={forwardedRef} />
91
- </ErrorBoundary>
92
- ) : (
93
- <SurfaceResolver {...props} ref={forwardedRef} />
94
- )}
95
- </>
85
+ const resolver = <SurfaceResolver {...props} ref={forwardedRef} />;
86
+ const suspense = placeholder ? <Suspense fallback={placeholder}>{resolver}</Suspense> : resolver;
87
+
88
+ return fallback ? (
89
+ <ErrorBoundary data={data} fallback={fallback}>
90
+ {suspense}
91
+ </ErrorBoundary>
92
+ ) : (
93
+ suspense
96
94
  );
97
95
  },
98
96
  );
@@ -111,11 +109,7 @@ const SurfaceResolver = forwardRef<HTMLElement, SurfaceProps>((props, forwardedR
111
109
  },
112
110
  };
113
111
 
114
- return (
115
- <SurfaceContext.Provider value={currentContext}>
116
- {nodes.length > 0 ? nodes : props.contentFallback ? <props.contentFallback /> : null}
117
- </SurfaceContext.Provider>
118
- );
112
+ return <SurfaceContext.Provider value={currentContext}>{nodes}</SurfaceContext.Provider>;
119
113
  });
120
114
 
121
115
  const resolveNodes = (