@dxos/app-framework 0.8.4-main.406dc2a → 0.8.4-main.548089c

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 (117) hide show
  1. package/dist/lib/browser/{app-graph-builder-LG4RG2LM.mjs → app-graph-builder-JPUFNED5.mjs} +7 -7
  2. package/dist/lib/browser/app-graph-builder-JPUFNED5.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-2GRQ4QXA.mjs → chunk-LVSO2N4X.mjs} +160 -199
  4. package/dist/lib/browser/chunk-LVSO2N4X.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-FRUTKCPG.mjs → chunk-XRAWIHTQ.mjs} +101 -90
  6. package/dist/lib/browser/chunk-XRAWIHTQ.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +5 -33
  8. package/dist/lib/browser/index.mjs.map +2 -2
  9. package/dist/lib/browser/{intent-dispatcher-6SHA5B3N.mjs → intent-dispatcher-TNEVDPI6.mjs} +2 -2
  10. package/dist/lib/browser/{intent-resolver-UZZ4OANZ.mjs → intent-resolver-SYLXP62Y.mjs} +2 -2
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/react/index.mjs +32 -0
  13. package/dist/lib/browser/{store-ACBEYK4B.mjs → store-3HDXKFXP.mjs} +2 -2
  14. package/dist/lib/browser/testing/index.mjs +5 -4
  15. package/dist/lib/browser/testing/index.mjs.map +3 -3
  16. package/dist/lib/node-esm/{app-graph-builder-FMHVHPWA.mjs → app-graph-builder-VO6RTSOS.mjs} +7 -7
  17. package/dist/lib/node-esm/app-graph-builder-VO6RTSOS.mjs.map +7 -0
  18. package/dist/lib/node-esm/{chunk-KSPOOYT3.mjs → chunk-FO5NIDOR.mjs} +160 -199
  19. package/dist/lib/node-esm/chunk-FO5NIDOR.mjs.map +7 -0
  20. package/dist/lib/node-esm/{chunk-CXT6CYPE.mjs → chunk-JH3SFOXA.mjs} +101 -90
  21. package/dist/lib/node-esm/chunk-JH3SFOXA.mjs.map +7 -0
  22. package/dist/lib/node-esm/index.mjs +5 -33
  23. package/dist/lib/node-esm/index.mjs.map +2 -2
  24. package/dist/lib/node-esm/{intent-dispatcher-SIYQ5ZIU.mjs → intent-dispatcher-WUNOPJES.mjs} +2 -2
  25. package/dist/lib/node-esm/{intent-resolver-7FYJMXAG.mjs → intent-resolver-VTZI3NO7.mjs} +2 -2
  26. package/dist/lib/node-esm/meta.json +1 -1
  27. package/dist/lib/node-esm/react/index.mjs +33 -0
  28. package/dist/lib/node-esm/{store-6OBLTVXC.mjs → store-PAJPVOLG.mjs} +2 -2
  29. package/dist/lib/node-esm/testing/index.mjs +5 -4
  30. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  31. package/dist/types/src/common/capabilities.d.ts +36 -42
  32. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  33. package/dist/types/src/common/surface.d.ts +1 -0
  34. package/dist/types/src/common/surface.d.ts.map +1 -1
  35. package/dist/types/src/core/capabilities.d.ts +12 -12
  36. package/dist/types/src/core/capabilities.d.ts.map +1 -1
  37. package/dist/types/src/core/manager.d.ts +1 -1
  38. package/dist/types/src/core/manager.d.ts.map +1 -1
  39. package/dist/types/src/core/plugin.d.ts +4 -0
  40. package/dist/types/src/core/plugin.d.ts.map +1 -1
  41. package/dist/types/src/index.d.ts +0 -2
  42. package/dist/types/src/index.d.ts.map +1 -1
  43. package/dist/types/src/playground/generator/Main.d.ts.map +1 -1
  44. package/dist/types/src/react/App.d.ts.map +1 -0
  45. package/dist/types/src/react/App.stories.d.ts.map +1 -0
  46. package/dist/types/src/react/DefaultFallback.d.ts.map +1 -0
  47. package/dist/types/src/react/Surface.d.ts +4 -4
  48. package/dist/types/src/react/Surface.d.ts.map +1 -1
  49. package/dist/types/src/react/Surface.stories.d.ts +3 -6
  50. package/dist/types/src/react/Surface.stories.d.ts.map +1 -1
  51. package/dist/types/src/react/index.d.ts +2 -0
  52. package/dist/types/src/react/index.d.ts.map +1 -1
  53. package/dist/types/src/react/types.d.ts +6 -0
  54. package/dist/types/src/react/types.d.ts.map +1 -0
  55. package/dist/types/src/{components → react}/useApp.d.ts +2 -2
  56. package/dist/types/src/react/useApp.d.ts.map +1 -0
  57. package/dist/types/src/react/useLoading.d.ts.map +1 -0
  58. package/dist/types/src/testing/withPluginManager.d.ts +4 -3
  59. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  60. package/dist/types/tsconfig.tsbuildinfo +1 -1
  61. package/moon.yml +1 -1
  62. package/package.json +36 -33
  63. package/src/common/capabilities.ts +18 -19
  64. package/src/common/collaboration.ts +2 -2
  65. package/src/common/surface.ts +1 -0
  66. package/src/core/capabilities.test.ts +1 -1
  67. package/src/core/capabilities.ts +23 -19
  68. package/src/core/manager.ts +2 -2
  69. package/src/core/plugin.ts +5 -0
  70. package/src/index.ts +0 -2
  71. package/src/playground/generator/Main.tsx +0 -1
  72. package/src/playground/playground.stories.tsx +1 -1
  73. package/src/plugin-settings/app-graph-builder.ts +5 -5
  74. package/src/plugin-settings/translations.ts +1 -1
  75. package/src/{components → react}/App.tsx +1 -1
  76. package/src/{components → react}/DefaultFallback.tsx +1 -1
  77. package/src/react/Surface.stories.tsx +69 -45
  78. package/src/react/Surface.tsx +56 -33
  79. package/src/react/index.ts +4 -0
  80. package/src/react/types.ts +13 -0
  81. package/src/{components → react}/useApp.tsx +13 -12
  82. package/src/react/useCapabilities.ts +2 -2
  83. package/src/testing/withPluginManager.tsx +9 -4
  84. package/tsconfig.json +9 -0
  85. package/dist/lib/browser/app-graph-builder-LG4RG2LM.mjs.map +0 -7
  86. package/dist/lib/browser/chunk-2GRQ4QXA.mjs.map +0 -7
  87. package/dist/lib/browser/chunk-FRUTKCPG.mjs.map +0 -7
  88. package/dist/lib/browser/worker.mjs +0 -77
  89. package/dist/lib/node-esm/app-graph-builder-FMHVHPWA.mjs.map +0 -7
  90. package/dist/lib/node-esm/chunk-CXT6CYPE.mjs.map +0 -7
  91. package/dist/lib/node-esm/chunk-KSPOOYT3.mjs.map +0 -7
  92. package/dist/lib/node-esm/worker.mjs +0 -78
  93. package/dist/types/src/components/App.d.ts.map +0 -1
  94. package/dist/types/src/components/App.stories.d.ts.map +0 -1
  95. package/dist/types/src/components/DefaultFallback.d.ts.map +0 -1
  96. package/dist/types/src/components/index.d.ts +0 -2
  97. package/dist/types/src/components/index.d.ts.map +0 -1
  98. package/dist/types/src/components/useApp.d.ts.map +0 -1
  99. package/dist/types/src/components/useLoading.d.ts.map +0 -1
  100. package/dist/types/src/worker.d.ts +0 -4
  101. package/dist/types/src/worker.d.ts.map +0 -1
  102. package/src/components/index.ts +0 -5
  103. package/src/worker.ts +0 -11
  104. /package/dist/lib/browser/{intent-dispatcher-6SHA5B3N.mjs.map → intent-dispatcher-TNEVDPI6.mjs.map} +0 -0
  105. /package/dist/lib/browser/{intent-resolver-UZZ4OANZ.mjs.map → intent-resolver-SYLXP62Y.mjs.map} +0 -0
  106. /package/dist/lib/browser/{worker.mjs.map → react/index.mjs.map} +0 -0
  107. /package/dist/lib/browser/{store-ACBEYK4B.mjs.map → store-3HDXKFXP.mjs.map} +0 -0
  108. /package/dist/lib/node-esm/{intent-dispatcher-SIYQ5ZIU.mjs.map → intent-dispatcher-WUNOPJES.mjs.map} +0 -0
  109. /package/dist/lib/node-esm/{intent-resolver-7FYJMXAG.mjs.map → intent-resolver-VTZI3NO7.mjs.map} +0 -0
  110. /package/dist/lib/node-esm/{worker.mjs.map → react/index.mjs.map} +0 -0
  111. /package/dist/lib/node-esm/{store-6OBLTVXC.mjs.map → store-PAJPVOLG.mjs.map} +0 -0
  112. /package/dist/types/src/{components → react}/App.d.ts +0 -0
  113. /package/dist/types/src/{components → react}/App.stories.d.ts +0 -0
  114. /package/dist/types/src/{components → react}/DefaultFallback.d.ts +0 -0
  115. /package/dist/types/src/{components → react}/useLoading.d.ts +0 -0
  116. /package/src/{components → react}/App.stories.tsx +0 -0
  117. /package/src/{components → react}/useLoading.tsx +0 -0
package/moon.yml CHANGED
@@ -10,8 +10,8 @@ tasks:
10
10
  compile:
11
11
  args:
12
12
  - '--entryPoint=src/index.ts'
13
+ - '--entryPoint=src/react/index.ts'
13
14
  - '--entryPoint=src/testing/index.ts'
14
- - '--entryPoint=src/worker.ts'
15
15
  - '--preactSignalTracking'
16
16
  test:
17
17
  inputs:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/app-framework",
3
- "version": "0.8.4-main.406dc2a",
3
+ "version": "0.8.4-main.548089c",
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",
@@ -15,27 +15,27 @@
15
15
  "browser": "./dist/lib/browser/index.mjs",
16
16
  "node": "./dist/lib/node-esm/index.mjs"
17
17
  },
18
+ "./react": {
19
+ "source": "./src/react/index.ts",
20
+ "types": "./dist/types/src/react/index.d.ts",
21
+ "browser": "./dist/lib/browser/react/index.mjs",
22
+ "node": "./dist/lib/node-esm/react/index.mjs"
23
+ },
18
24
  "./testing": {
19
25
  "source": "./src/testing/index.ts",
20
26
  "types": "./dist/types/src/testing/index.d.ts",
21
27
  "browser": "./dist/lib/browser/testing/index.mjs",
22
28
  "node": "./dist/lib/node-esm/testing/index.mjs"
23
- },
24
- "./worker": {
25
- "source": "./src/worker.ts",
26
- "types": "./dist/types/src/worker.d.ts",
27
- "browser": "./dist/lib/browser/worker.mjs",
28
- "node": "./dist/lib/node-esm/worker.mjs"
29
29
  }
30
30
  },
31
31
  "types": "dist/types/src/index.d.ts",
32
32
  "typesVersions": {
33
33
  "*": {
34
+ "react": [
35
+ "dist/types/src/react/index.d.ts"
36
+ ],
34
37
  "testing": [
35
38
  "dist/types/src/testing/index.d.ts"
36
- ],
37
- "worker": [
38
- "dist/types/src/worker.d.ts"
39
39
  ]
40
40
  }
41
41
  },
@@ -44,38 +44,41 @@
44
44
  "@effect/experimental": "0.56.0",
45
45
  "@preact-signals/safe-react": "^0.9.0",
46
46
  "@preact/signals-core": "^1.12.1",
47
- "@dxos/ai": "0.8.4-main.406dc2a",
48
- "@dxos/app-graph": "0.8.4-main.406dc2a",
49
- "@dxos/async": "0.8.4-main.406dc2a",
50
- "@dxos/blueprints": "0.8.4-main.406dc2a",
51
- "@dxos/client-protocol": "0.8.4-main.406dc2a",
52
- "@dxos/functions": "0.8.4-main.406dc2a",
53
- "@dxos/debug": "0.8.4-main.406dc2a",
54
- "@dxos/invariant": "0.8.4-main.406dc2a",
55
- "@dxos/keys": "0.8.4-main.406dc2a",
56
- "@dxos/live-object": "0.8.4-main.406dc2a",
57
- "@dxos/log": "0.8.4-main.406dc2a",
58
- "@dxos/react-hooks": "0.8.4-main.406dc2a",
59
- "@dxos/schema": "0.8.4-main.406dc2a",
60
- "@dxos/echo": "0.8.4-main.406dc2a",
61
- "@dxos/util": "0.8.4-main.406dc2a",
62
- "@dxos/local-storage": "0.8.4-main.406dc2a"
47
+ "@dxos/ai": "0.8.4-main.548089c",
48
+ "@dxos/assistant": "0.8.4-main.548089c",
49
+ "@dxos/async": "0.8.4-main.548089c",
50
+ "@dxos/app-graph": "0.8.4-main.548089c",
51
+ "@dxos/blueprints": "0.8.4-main.548089c",
52
+ "@dxos/client-protocol": "0.8.4-main.548089c",
53
+ "@dxos/debug": "0.8.4-main.548089c",
54
+ "@dxos/functions": "0.8.4-main.548089c",
55
+ "@dxos/invariant": "0.8.4-main.548089c",
56
+ "@dxos/echo": "0.8.4-main.548089c",
57
+ "@dxos/live-object": "0.8.4-main.548089c",
58
+ "@dxos/local-storage": "0.8.4-main.548089c",
59
+ "@dxos/keys": "0.8.4-main.548089c",
60
+ "@dxos/log": "0.8.4-main.548089c",
61
+ "@dxos/schema": "0.8.4-main.548089c",
62
+ "@dxos/util": "0.8.4-main.548089c",
63
+ "@dxos/react-hooks": "0.8.4-main.548089c",
64
+ "@dxos/types": "0.8.4-main.548089c"
63
65
  },
64
66
  "devDependencies": {
65
- "@effect-rx/rx-react": "0.42.4",
67
+ "@effect-atom/atom-react": "^0.3.4",
66
68
  "@effect/platform": "0.92.1",
67
69
  "@types/react": "~19.2.2",
68
70
  "effect": "3.18.3",
69
71
  "react": "~19.2.0",
70
72
  "typedoc": "0.28.1",
71
- "@dxos/react-ui": "0.8.4-main.406dc2a",
72
- "@dxos/echo-signals": "0.8.4-main.406dc2a",
73
- "@dxos/random": "0.8.4-main.406dc2a",
74
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.406dc2a",
75
- "@dxos/storybook-utils": "0.8.4-main.406dc2a"
73
+ "@dxos/echo-signals": "0.8.4-main.548089c",
74
+ "@dxos/react-ui": "0.8.4-main.548089c",
75
+ "@dxos/random": "0.8.4-main.548089c",
76
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.548089c",
77
+ "@dxos/react-ui-theme": "0.8.4-main.548089c",
78
+ "@dxos/storybook-utils": "0.8.4-main.548089c"
76
79
  },
77
80
  "peerDependencies": {
78
- "@effect-rx/rx-react": "^0.34.1",
81
+ "@effect-atom/atom-react": "^0.3.4",
79
82
  "@effect/platform": "^0.80.12",
80
83
  "effect": "^3.13.3",
81
84
  "react": "^19.0.0"
@@ -2,9 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import type * as Tool from '@effect/ai/Tool';
6
- import type * as Toolkit from '@effect/ai/Toolkit';
7
- import { type Registry } from '@effect-rx/rx-react';
5
+ import { type Registry } from '@effect-atom/atom-react';
8
6
  import type * as Layer from 'effect/Layer';
9
7
  import type * as Schema from 'effect/Schema';
10
8
  import { type FC, type PropsWithChildren } from 'react';
@@ -12,11 +10,12 @@ import { type FC, type PropsWithChildren } from 'react';
12
10
  import { type AiService } from '@dxos/ai';
13
11
  import type * as AiServiceRouter from '@dxos/ai/AiServiceRouter';
14
12
  import { type BuilderExtensions, type GraphBuilder } from '@dxos/app-graph';
13
+ import { type GenericToolkit } from '@dxos/assistant';
15
14
  import { type Blueprint } from '@dxos/blueprints';
16
15
  import { type Space } from '@dxos/client-protocol';
17
16
  import { type FunctionDefinition } from '@dxos/functions';
18
17
  import { type RootSettingsStore } from '@dxos/local-storage';
19
- import { type AnchoredTo } from '@dxos/schema';
18
+ import { type AnchoredTo } from '@dxos/types';
20
19
 
21
20
  import { type PluginManager, defineCapability } from '../core';
22
21
  import { type AnyIntentResolver, type IntentContext } from '../plugin-intent';
@@ -41,9 +40,13 @@ export namespace Capabilities {
41
40
  /**
42
41
  * @category Capability
43
42
  */
44
- export const RxRegistry = defineCapability<Registry.Registry>('dxos.org/app-framework/capability/rx-registry');
43
+ export const RxRegistry = defineCapability<Registry.Registry>('dxos.org/app-framework/capability/atom-registry');
45
44
 
46
- export type ReactContext = Readonly<{ id: string; dependsOn?: string[]; context: FC<PropsWithChildren> }>;
45
+ export type ReactContext = Readonly<{
46
+ id: string;
47
+ dependsOn?: string[];
48
+ context: FC<PropsWithChildren>;
49
+ }>;
47
50
 
48
51
  /**
49
52
  * @category Capability
@@ -151,25 +154,21 @@ export namespace Capabilities {
151
154
  */
152
155
  export const Settings = defineCapability<Settings>('dxos.org/app-framework/capability/settings');
153
156
 
154
- export type Metadata = Readonly<{ id: string; metadata: Record<string, any> }>;
157
+ export type Metadata = Readonly<{
158
+ id: string;
159
+ metadata: Record<string, any>;
160
+ }>;
155
161
 
156
162
  /**
157
163
  * @category Capability
158
164
  */
159
165
  export const Metadata = defineCapability<Metadata>('dxos.org/app-framework/capability/metadata');
160
166
 
161
- // TODO(dmaretskyi): Consider combining Toolkit and ToolkitHandler for type-safe context.
162
-
163
- /**
164
- * @category Capability
165
- */
166
- export const Toolkit = defineCapability<Toolkit.Any>('dxos.org/app-framework/capability/ai-toolkit');
167
-
168
167
  /**
169
168
  * @category Capability
170
169
  */
171
- export const ToolkitHandler = defineCapability<Layer.Layer<Tool.Handler<any>, never, never>>(
172
- 'dxos.org/app-framework/capability/ai-toolkit-handler',
170
+ export const Toolkit = defineCapability<GenericToolkit.GenericToolkit>(
171
+ 'dxos.org/app-framework/capability/ai-toolkit',
173
172
  );
174
173
 
175
174
  /**
@@ -198,16 +197,16 @@ export namespace Capabilities {
198
197
  'dxos.org/app-framework/capability/functions',
199
198
  );
200
199
 
201
- export type FileUploader = (file: File, space: Space) => Promise<FileInfo | undefined>;
200
+ export type FileUploader = (space: Space, file: File) => Promise<FileInfo | undefined>;
202
201
 
203
202
  /**
204
203
  * @category Capability
205
204
  */
206
205
  export const FileUploader = defineCapability<FileUploader>('dxos.org/app-framework/capability/file-uploader');
207
206
 
208
- type AnchorSort = {
207
+ export type AnchorSort = {
209
208
  key: string;
210
- sort: (anchorA: AnchoredTo, anchorB: AnchoredTo) => number;
209
+ sort: (anchorA: AnchoredTo.AnchoredTo, anchorB: AnchoredTo.AnchoredTo) => number;
211
210
  };
212
211
 
213
212
  /**
@@ -4,14 +4,14 @@
4
4
 
5
5
  import * as Schema from 'effect/Schema';
6
6
 
7
- import { DataType } from '@dxos/schema';
7
+ import { ContentBlock } from '@dxos/types';
8
8
 
9
9
  export namespace CollaborationActions {
10
10
  export class AcceptProposal extends Schema.TaggedClass<AcceptProposal>()('collaboration/accept-proposal', {
11
11
  input: Schema.Struct({
12
12
  subject: Schema.Any,
13
13
  anchor: Schema.String,
14
- proposal: DataType.MessageBlock.Proposal,
14
+ proposal: ContentBlock.Proposal,
15
15
  }),
16
16
  output: Schema.Void,
17
17
  }) {}
@@ -45,6 +45,7 @@ type CoreSurfaceProps<T extends Record<string, any> = Record<string, unknown>> =
45
45
 
46
46
  /**
47
47
  * The data to be rendered by the surface.
48
+ * NOTE: This must be a stable value.
48
49
  */
49
50
  data: T;
50
51
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Registry } from '@effect-rx/rx-react';
5
+ import { Registry } from '@effect-atom/atom-react';
6
6
  import * as Effect from 'effect/Effect';
7
7
  import { describe, expect, it, onTestFinished } from 'vitest';
8
8
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Registry, Rx } from '@effect-rx/rx-react';
5
+ import { Atom, type Registry } from '@effect-atom/atom-react';
6
6
  import * as Effect from 'effect/Effect';
7
7
 
8
8
  import { Trigger } from '@dxos/async';
@@ -41,17 +41,17 @@ export type Capability<T> = {
41
41
  /**
42
42
  * The interface definition of the capability.
43
43
  */
44
- interface: InterfaceDef<T>;
44
+ readonly interface: InterfaceDef<T>;
45
45
 
46
46
  /**
47
47
  * The implementation of the capability.
48
48
  */
49
- implementation: T;
49
+ readonly implementation: T;
50
50
 
51
51
  /**
52
52
  * Called when the capability is deactivated.
53
53
  */
54
- deactivate?: () => MaybePromise<void> | Effect.Effect<void, Error>;
54
+ readonly deactivate?: () => MaybePromise<void> | Effect.Effect<void, Error>;
55
55
  };
56
56
 
57
57
  export type AnyCapability = Capability<any>;
@@ -78,7 +78,11 @@ export const contributes = <I extends InterfaceDef<any>>(
78
78
  implementation: Capability<InterfaceDef.Implementation<I>>['implementation'],
79
79
  deactivate?: Capability<InterfaceDef.Implementation<I>>['deactivate'],
80
80
  ): Capability<I> => {
81
- return { interface: interfaceDef, implementation, deactivate } satisfies Capability<I>;
81
+ return {
82
+ interface: interfaceDef,
83
+ implementation,
84
+ deactivate,
85
+ } satisfies Capability<I>;
82
86
  };
83
87
 
84
88
  type LoadCapability<T, U> = () => Promise<{ default: (props: T) => MaybePromise<Capability<U>> }>;
@@ -105,19 +109,19 @@ export const lazy =
105
109
  export class PluginContext {
106
110
  private readonly _registry: Registry.Registry;
107
111
 
108
- private readonly _capabilityImpls = Rx.family<string, Rx.Writable<CapabilityImpl<unknown>[]>>(() => {
109
- return Rx.make<CapabilityImpl<unknown>[]>([]).pipe(Rx.keepAlive);
112
+ private readonly _capabilityImpls = Atom.family<string, Atom.Writable<CapabilityImpl<unknown>[]>>(() => {
113
+ return Atom.make<CapabilityImpl<unknown>[]>([]).pipe(Atom.keepAlive);
110
114
  });
111
115
 
112
- readonly _capabilities = Rx.family<string, Rx.Rx<unknown[]>>((id: string) => {
113
- return Rx.make((get) => {
116
+ readonly _capabilities = Atom.family<string, Atom.Atom<unknown[]>>((id: string) => {
117
+ return Atom.make((get) => {
114
118
  const current = get(this._capabilityImpls(id));
115
119
  return current.map((c) => c.implementation);
116
120
  });
117
121
  });
118
122
 
119
- readonly _capability = Rx.family<string, Rx.Rx<unknown>>((id: string) => {
120
- return Rx.make((get) => {
123
+ readonly _capability = Atom.family<string, Atom.Atom<unknown>>((id: string) => {
124
+ return Atom.make((get) => {
121
125
  const current = get(this._capabilities(id));
122
126
  invariant(current.length > 0, `No capability found for ${id}`);
123
127
  return current[0];
@@ -189,26 +193,26 @@ export class PluginContext {
189
193
  }
190
194
 
191
195
  /**
192
- * Get the Rx reference to the available capabilities for a given interface.
193
- * Primarily useful for deriving other Rx values based on the capabilities or
196
+ * Get the Atom reference to the available capabilities for a given interface.
197
+ * Primarily useful for deriving other Atom values based on the capabilities or
194
198
  * for subscribing to changes in the capabilities.
195
199
  * @returns An Rx reference to the available capabilities.
196
200
  */
197
- capabilities<T>(interfaceDef: InterfaceDef<T>): Rx.Rx<T[]> {
201
+ capabilities<T>(interfaceDef: InterfaceDef<T>): Atom.Atom<T[]> {
198
202
  // NOTE: This the type-checking for capabilities is done at the time of contribution.
199
- return this._capabilities(interfaceDef.identifier) as Rx.Rx<T[]>;
203
+ return this._capabilities(interfaceDef.identifier) as Atom.Atom<T[]>;
200
204
  }
201
205
 
202
206
  /**
203
- * Get the Rx reference to the available capabilities for a given interface.
204
- * Primarily useful for deriving other Rx values based on the capability or
207
+ * Get the Atom reference to the available capabilities for a given interface.
208
+ * Primarily useful for deriving other Atom values based on the capability or
205
209
  * for subscribing to changes in the capability.
206
210
  * @returns An Rx reference to the available capability.
207
211
  * @throws If no capability is found.
208
212
  */
209
- capability<T>(interfaceDef: InterfaceDef<T>): Rx.Rx<T> {
213
+ capability<T>(interfaceDef: InterfaceDef<T>): Atom.Atom<T> {
210
214
  // NOTE: This the type-checking for capabilities is done at the time of contribution.
211
- return this._capability(interfaceDef.identifier) as Rx.Rx<T>;
215
+ return this._capability(interfaceDef.identifier) as Atom.Atom<T>;
212
216
  }
213
217
 
214
218
  /**
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Registry } from '@effect-rx/rx-react';
5
+ import { Registry } from '@effect-atom/atom-react';
6
6
  import { untracked } from '@preact/signals-core';
7
7
  import * as Array from 'effect/Array';
8
8
  import * as Duration from 'effect/Duration';
@@ -55,7 +55,7 @@ export class PluginManager {
55
55
  readonly context: PluginContext;
56
56
  readonly registry: Registry.Registry;
57
57
 
58
- // TODO(wittjosiah): Replace with Rx.
58
+ // TODO(wittjosiah): Replace with Atom.
59
59
  private readonly _state: Live<PluginManagerState>;
60
60
  private readonly _pluginLoader: PluginManagerOptions['pluginLoader'];
61
61
  private readonly _capabilities = new Map<string, AnyCapability[]>();
@@ -110,6 +110,11 @@ export type PluginMeta = {
110
110
  * A grep-able symbol string which can be resolved to an icon asset by @ch-ui/icons, via @ch-ui/vite-plugin-icons.
111
111
  */
112
112
  icon?: string;
113
+
114
+ /**
115
+ * Icon hue (ChromaticPalette).
116
+ */
117
+ iconHue?: string;
113
118
  };
114
119
 
115
120
  /**
package/src/index.ts CHANGED
@@ -3,8 +3,6 @@
3
3
  //
4
4
 
5
5
  export * from './common';
6
- export * from './components';
7
6
  export * from './core';
8
7
  export * from './plugin-intent';
9
8
  export * from './plugin-settings';
10
- export * from './react';
@@ -30,7 +30,6 @@ const Item = ({
30
30
  variant='ghost'
31
31
  icon='ph--x--regular'
32
32
  label='Remove'
33
- size={5}
34
33
  disabled={disabled}
35
34
  onClick={handleRemove}
36
35
  />
@@ -7,8 +7,8 @@ import React from 'react';
7
7
 
8
8
  import { withTheme } from '@dxos/react-ui/testing';
9
9
 
10
- import { useApp } from '../components';
11
10
  import { IntentPlugin } from '../plugin-intent';
11
+ import { useApp } from '../react';
12
12
 
13
13
  import { DebugPlugin } from './debug';
14
14
  import { GeneratorPlugin, createNumberPlugin } from './generator';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
5
+ import { Atom } from '@effect-atom/atom-react';
6
6
  import * as Function from 'effect/Function';
7
7
  import * as Option from 'effect/Option';
8
8
 
@@ -22,7 +22,7 @@ export default (context: PluginContext) =>
22
22
  createExtension({
23
23
  id: `${meta.id}/action`,
24
24
  actions: (node) =>
25
- Rx.make((get) =>
25
+ Atom.make((get) =>
26
26
  Function.pipe(
27
27
  get(node),
28
28
  Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
@@ -51,7 +51,7 @@ export default (context: PluginContext) =>
51
51
  createExtension({
52
52
  id: `${meta.id}/core`,
53
53
  connector: (node) =>
54
- Rx.make((get) =>
54
+ Atom.make((get) =>
55
55
  Function.pipe(
56
56
  get(node),
57
57
  Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
@@ -75,7 +75,7 @@ export default (context: PluginContext) =>
75
75
  createExtension({
76
76
  id: `${meta.id}/core-plugins`,
77
77
  connector: (node) =>
78
- Rx.make((get) =>
78
+ Atom.make((get) =>
79
79
  Function.pipe(
80
80
  get(node),
81
81
  Option.flatMap((node) => (node.id !== SETTINGS_ID ? Option.none() : Option.some(node))),
@@ -123,7 +123,7 @@ export default (context: PluginContext) =>
123
123
  createExtension({
124
124
  id: `${meta.id}/custom-plugins`,
125
125
  connector: (node) =>
126
- Rx.make((get) =>
126
+ Atom.make((get) =>
127
127
  Function.pipe(
128
128
  get(node),
129
129
  Option.flatMap((node) =>
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Resource } from '@dxos/react-ui';
5
+ import { type Resource } from '../common';
6
6
 
7
7
  import { meta } from './meta';
8
8
 
@@ -6,9 +6,9 @@ import React, { type PropsWithChildren } from 'react';
6
6
 
7
7
  import { Capabilities } from '../common';
8
8
  import { topologicalSort } from '../helpers';
9
- import { useCapabilities } from '../react';
10
9
 
11
10
  import { type UseAppOptions } from './useApp';
11
+ import { useCapabilities } from './useCapabilities';
12
12
  import { LoadingState, useLoading } from './useLoading';
13
13
 
14
14
  export type AppProps = Pick<UseAppOptions, 'placeholder' | 'debounce'> & {
@@ -19,7 +19,7 @@ export const DefaultFallback = ({ error }: { error: Error }) => {
19
19
  }}
20
20
  >
21
21
  {/* TODO(wittjosiah): Link to docs for replacing default. */}
22
- <h1 style={{ margin: '0.5rem 0', fontSize: '1.2rem' }}>[ERROR]: {error.message}</h1>
22
+ <h1 style={{ margin: '0.5rem 0', fontSize: '1.2rem' }}>ERROR: {error.message}</h1>
23
23
  <pre style={{ overflow: 'auto', fontSize: '1rem', whiteSpace: 'pre-wrap', color: '#888888' }}>{error.stack}</pre>
24
24
  </div>
25
25
  );
@@ -3,94 +3,118 @@
3
3
  //
4
4
 
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
- import React, { useCallback, useState } from 'react';
6
+ import React, { useCallback, useEffect, useState } from 'react';
7
7
 
8
8
  import { faker } from '@dxos/random';
9
- import { Button, List, ListItem } from '@dxos/react-ui';
9
+ import { List, ListItem, Toolbar } from '@dxos/react-ui';
10
10
  import { withTheme } from '@dxos/react-ui/testing';
11
+ import { getHashStyles, mx } from '@dxos/react-ui-theme';
11
12
 
12
13
  import { Capabilities, createSurface } from '../common';
13
- import { type PluginManager } from '../core';
14
- import { setupPluginManager } from '../testing';
14
+ import { withPluginManager } from '../testing';
15
15
 
16
- import { PluginManagerProvider, usePluginManager } from './PluginManagerProvider';
16
+ import { usePluginManager } from './PluginManagerProvider';
17
17
  import { Surface, useSurfaces } from './Surface';
18
18
 
19
- const randomColor = (): string => {
20
- const hue = faker.number.int({ min: 0, max: 360 });
21
- const saturation = faker.number.int({ min: 50, max: 90 });
22
- const lightness = faker.number.int({ min: 40, max: 70 });
23
- return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
24
- };
25
-
26
- const Component = () => {
19
+ const DefaultStory = () => {
20
+ const [selected, setSelected] = useState<string | undefined>();
27
21
  const manager = usePluginManager();
28
22
  const surfaces = useSurfaces();
29
- const [picked, setPicked] = useState('test');
30
23
 
31
24
  const handleAdd = useCallback(() => {
32
- const id = `test-${faker.number.int({ min: 0, max: 1_000_000 })}`;
33
- const backgroundColor = randomColor();
25
+ const id = `test-${faker.number.int({ min: 0, max: 1_000 })}`;
26
+ const styles = getHashStyles(id);
34
27
 
35
28
  manager.context.contributeCapability({
36
29
  module: 'test',
37
30
  interface: Capabilities.ReactSurface,
38
31
  implementation: createSurface({
39
32
  id,
40
- role: id,
33
+ role: 'item',
34
+ filter: (data): data is any => (data as any)?.id === id,
41
35
  component: () => (
42
- <div className='flex-1' style={{ backgroundColor }}>
43
- {id}
36
+ <div className={mx('flex justify-center items-center border rounded', styles.surface, styles.border)}>
37
+ <span className={mx('dx-tag font-mono text-lg', styles.text)}>{id}</span>
44
38
  </div>
45
39
  ),
46
40
  }),
47
41
  });
48
42
 
49
- setPicked(id);
43
+ setSelected(id);
50
44
  }, [manager]);
51
45
 
52
- const handlePick = useCallback(() => {
53
- setPicked(faker.helpers.arrayElement(surfaces).id);
46
+ const handleSelect = useCallback(() => {
47
+ setSelected(faker.helpers.arrayElement(surfaces)?.id);
54
48
  }, [surfaces]);
55
49
 
50
+ const handleError = useCallback(() => {
51
+ manager.context.contributeCapability({
52
+ module: 'error',
53
+ interface: Capabilities.ReactSurface,
54
+ implementation: createSurface({
55
+ id: 'error',
56
+ role: 'item',
57
+ filter: (data): data is any => (data as any)?.id === 'error',
58
+ component: () => {
59
+ const [count, setCount] = useState(3);
60
+ useEffect(() => {
61
+ const interval = setInterval(() => {
62
+ setCount((count) => {
63
+ if (count <= 1) {
64
+ clearInterval(interval);
65
+ }
66
+
67
+ return count - 1;
68
+ });
69
+ }, 1_000);
70
+ return () => clearInterval(interval);
71
+ }, []);
72
+
73
+ if (count <= 0) {
74
+ throw new Error('BANG!');
75
+ }
76
+
77
+ return (
78
+ <div className='flex justify-center items-center border border-rose-500 rounded'>
79
+ <span className='font-mono'>Ticking... {count}</span>
80
+ </div>
81
+ );
82
+ },
83
+ }),
84
+ });
85
+
86
+ setSelected('error');
87
+ }, [manager]);
88
+
56
89
  return (
57
- <div className='flex flex-col gap-2'>
58
- <div className='flex gap-2'>
59
- <Button onClick={handleAdd}>Add</Button>
60
- <Button onClick={handlePick}>Pick</Button>
61
- </div>
62
- <div className='flex gap-2'>
63
- <div className='flex-1'>
64
- <List itemSizes='one'>
90
+ <div className='flex flex-col bs-full overflow-hidden'>
91
+ <Toolbar.Root>
92
+ <Toolbar.Button onClick={handleAdd}>Add</Toolbar.Button>
93
+ <Toolbar.Button onClick={handleSelect}>Pick</Toolbar.Button>
94
+ <Toolbar.Button onClick={handleError}>Error</Toolbar.Button>
95
+ </Toolbar.Root>
96
+ <div className='grid grid-cols-2 bs-full gap-4 overflow-hidden'>
97
+ <Surface role='item' data={selected ? { id: selected } : undefined} limit={1} />
98
+ <div className='overflow-y-auto bs-full'>
99
+ <List>
65
100
  {surfaces.map((surface) => (
66
101
  <ListItem.Root key={surface.id} id={surface.id}>
67
- <ListItem.Heading classNames='grow pbs-2'>{surface.id}</ListItem.Heading>
102
+ <ListItem.Heading classNames='flex items-center'>{surface.id}</ListItem.Heading>
68
103
  </ListItem.Root>
69
104
  ))}
70
105
  </List>
71
106
  </div>
72
- <div className='flex-1'>
73
- <Surface role={picked} limit={1} />
74
- </div>
75
107
  </div>
76
108
  </div>
77
109
  );
78
110
  };
79
111
 
80
- const DefaultStory = (props: { manager: PluginManager }) => {
81
- return (
82
- <PluginManagerProvider value={props.manager}>
83
- <Component />
84
- </PluginManagerProvider>
85
- );
86
- };
87
-
88
112
  const meta = {
89
113
  title: 'sdk/app-framework/Surface',
90
114
  render: DefaultStory,
91
- decorators: [withTheme],
92
- args: {
93
- manager: setupPluginManager(),
115
+ decorators: [withTheme, withPluginManager({ capabilities: [] })],
116
+ parameters: {
117
+ layout: 'fullscreen',
94
118
  },
95
119
  } satisfies Meta<typeof DefaultStory>;
96
120