@dxos/app-framework 0.7.4 → 0.7.5-labs.5f04cf6
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.
- package/dist/lib/browser/chunk-22MGDQXD.mjs +1621 -0
- package/dist/lib/browser/chunk-22MGDQXD.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +136 -527
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +67 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/lib/node/chunk-7PNEFY2G.cjs +1665 -0
- package/dist/lib/node/chunk-7PNEFY2G.cjs.map +7 -0
- package/dist/lib/node/index.cjs +141 -551
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +91 -0
- package/dist/lib/node/testing/index.cjs.map +7 -0
- package/dist/lib/node-esm/chunk-ZFOOPWBG.mjs +1623 -0
- package/dist/lib/node-esm/chunk-ZFOOPWBG.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +136 -527
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +68 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/App.d.ts +22 -13
- package/dist/types/src/App.d.ts.map +1 -1
- package/dist/types/src/common/capabilities.d.ts +343 -0
- package/dist/types/src/common/capabilities.d.ts.map +1 -0
- package/dist/types/src/common/events.d.ts +41 -0
- package/dist/types/src/common/events.d.ts.map +1 -0
- package/dist/types/src/common/file.d.ts +14 -0
- package/dist/types/src/common/file.d.ts.map +1 -0
- package/dist/types/src/common/graph.d.ts +21 -0
- package/dist/types/src/common/graph.d.ts.map +1 -0
- package/dist/types/src/{plugins/common → common}/index.d.ts +3 -1
- package/dist/types/src/common/index.d.ts.map +1 -0
- package/dist/types/src/common/layout.d.ts +165 -0
- package/dist/types/src/common/layout.d.ts.map +1 -0
- package/dist/types/src/{plugins/common → common}/navigation.d.ts +77 -32
- package/dist/types/src/common/navigation.d.ts.map +1 -0
- package/dist/types/src/common/surface.d.ts +68 -0
- package/dist/types/src/common/surface.d.ts.map +1 -0
- package/dist/types/src/{plugins/common → common}/translations.d.ts +0 -11
- package/dist/types/src/common/translations.d.ts.map +1 -0
- package/dist/types/src/core/capabilities.d.ts +90 -0
- package/dist/types/src/core/capabilities.d.ts.map +1 -0
- package/dist/types/src/core/capabilities.test.d.ts +2 -0
- package/dist/types/src/core/capabilities.test.d.ts.map +1 -0
- package/dist/types/src/core/events.d.ts +58 -0
- package/dist/types/src/core/events.d.ts.map +1 -0
- package/dist/types/src/core/index.d.ts +5 -0
- package/dist/types/src/core/index.d.ts.map +1 -0
- package/dist/types/src/core/manager.d.ts +126 -0
- package/dist/types/src/core/manager.d.ts.map +1 -0
- package/dist/types/src/core/manager.test.d.ts +2 -0
- package/dist/types/src/core/manager.test.d.ts.map +1 -0
- package/dist/types/src/core/plugin.d.ts +94 -0
- package/dist/types/src/core/plugin.d.ts.map +1 -0
- package/dist/types/src/helpers.d.ts +10 -0
- package/dist/types/src/helpers.d.ts.map +1 -0
- package/dist/types/src/helpers.test.d.ts +2 -0
- package/dist/types/src/helpers.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +5 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/playground/debug/Debug.d.ts +6 -0
- package/dist/types/src/playground/debug/Debug.d.ts.map +1 -0
- package/dist/types/src/playground/debug/index.d.ts +2 -0
- package/dist/types/src/playground/debug/index.d.ts.map +1 -0
- package/dist/types/src/playground/debug/plugin.d.ts +2 -0
- package/dist/types/src/playground/debug/plugin.d.ts.map +1 -0
- package/dist/types/src/playground/generator/Main.d.ts +6 -0
- package/dist/types/src/playground/generator/Main.d.ts.map +1 -0
- package/dist/types/src/playground/generator/Toolbar.d.ts +6 -0
- package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -0
- package/dist/types/src/playground/generator/generator.d.ts +5 -0
- package/dist/types/src/playground/generator/generator.d.ts.map +1 -0
- package/dist/types/src/playground/generator/index.d.ts +3 -0
- package/dist/types/src/playground/generator/index.d.ts.map +1 -0
- package/dist/types/src/playground/generator/plugin.d.ts +2 -0
- package/dist/types/src/playground/generator/plugin.d.ts.map +1 -0
- package/dist/types/src/playground/layout/Layout.d.ts +8 -0
- package/dist/types/src/playground/layout/Layout.d.ts.map +1 -0
- package/dist/types/src/playground/layout/index.d.ts +2 -0
- package/dist/types/src/playground/layout/index.d.ts.map +1 -0
- package/dist/types/src/playground/layout/plugin.d.ts +2 -0
- package/dist/types/src/playground/layout/plugin.d.ts.map +1 -0
- package/dist/types/src/playground/logger/Toolbar.d.ts +6 -0
- package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -0
- package/dist/types/src/playground/logger/index.d.ts +2 -0
- package/dist/types/src/playground/logger/index.d.ts.map +1 -0
- package/dist/types/src/playground/logger/plugin.d.ts +2 -0
- package/dist/types/src/playground/logger/plugin.d.ts.map +1 -0
- package/dist/types/src/playground/logger/schema.d.ts +13 -0
- package/dist/types/src/playground/logger/schema.d.ts.map +1 -0
- package/dist/types/src/playground/playground.stories.d.ts +10 -0
- package/dist/types/src/playground/playground.stories.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/IntentContext.d.ts +8 -0
- package/dist/types/src/plugin-intent/IntentContext.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/IntentPlugin.d.ts +2 -0
- package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/actions.d.ts +23 -0
- package/dist/types/src/plugin-intent/actions.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/errors.d.ts +16 -0
- package/dist/types/src/plugin-intent/errors.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/index.d.ts +6 -0
- package/dist/types/src/plugin-intent/index.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +106 -0
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/intent-dispatcher.test.d.ts +2 -0
- package/dist/types/src/plugin-intent/intent-dispatcher.test.d.ts.map +1 -0
- package/dist/types/src/plugin-intent/intent.d.ts +68 -0
- package/dist/types/src/plugin-intent/intent.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/SettingsPlugin.d.ts +2 -0
- package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/actions.d.ts +17 -0
- package/dist/types/src/plugin-settings/actions.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/index.d.ts +3 -0
- package/dist/types/src/plugin-settings/index.d.ts.map +1 -0
- package/dist/types/src/react/ErrorBoundary.d.ts.map +1 -0
- package/dist/types/src/react/PluginManagerProvider.d.ts +10 -0
- package/dist/types/src/react/PluginManagerProvider.d.ts.map +1 -0
- package/dist/types/src/react/Surface.d.ts +12 -0
- package/dist/types/src/react/Surface.d.ts.map +1 -0
- package/dist/types/src/react/index.d.ts +5 -0
- package/dist/types/src/react/index.d.ts.map +1 -0
- package/dist/types/src/react/useCapabilities.d.ts +13 -0
- package/dist/types/src/react/useCapabilities.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/withPluginManager.d.ts +10 -0
- package/dist/types/src/testing/withPluginManager.d.ts.map +1 -0
- package/dist/types/src/testing/withPluginManager.stories.d.ts +5 -0
- package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +31 -14
- package/project.json +2 -1
- package/src/App.tsx +138 -34
- package/src/common/capabilities.ts +88 -0
- package/src/common/events.ts +63 -0
- package/src/common/file.ts +22 -0
- package/src/common/graph.ts +30 -0
- package/src/{plugins/common → common}/index.ts +3 -1
- package/src/common/layout.ts +157 -0
- package/src/{plugins/common → common}/navigation.ts +69 -50
- package/src/common/surface.ts +81 -0
- package/src/common/translations.ts +18 -0
- package/src/core/capabilities.test.ts +116 -0
- package/src/core/capabilities.ts +213 -0
- package/src/core/events.ts +58 -0
- package/src/core/index.ts +8 -0
- package/src/core/manager.test.ts +567 -0
- package/src/core/manager.ts +497 -0
- package/src/core/plugin.ts +128 -0
- package/src/helpers.test.ts +97 -0
- package/src/helpers.ts +45 -0
- package/src/index.ts +6 -3
- package/src/playground/debug/Debug.tsx +39 -0
- package/src/playground/debug/index.ts +5 -0
- package/src/playground/debug/plugin.ts +17 -0
- package/src/playground/generator/Main.tsx +71 -0
- package/src/playground/generator/Toolbar.tsx +46 -0
- package/src/playground/generator/generator.ts +23 -0
- package/src/playground/generator/index.ts +6 -0
- package/src/playground/generator/plugin.ts +18 -0
- package/src/playground/layout/Layout.tsx +33 -0
- package/src/playground/layout/index.ts +5 -0
- package/src/playground/layout/plugin.ts +17 -0
- package/src/playground/logger/Toolbar.tsx +28 -0
- package/src/playground/logger/index.ts +5 -0
- package/src/playground/logger/plugin.ts +33 -0
- package/src/playground/logger/schema.ts +12 -0
- package/src/playground/playground.stories.tsx +34 -0
- package/src/plugin-intent/IntentContext.tsx +34 -0
- package/src/plugin-intent/IntentPlugin.tsx +60 -0
- package/src/plugin-intent/actions.ts +22 -0
- package/src/plugin-intent/errors.ts +39 -0
- package/src/plugin-intent/index.ts +9 -0
- package/src/plugin-intent/intent-dispatcher.test.ts +280 -0
- package/src/plugin-intent/intent-dispatcher.ts +269 -0
- package/src/plugin-intent/intent.ts +146 -0
- package/src/plugin-settings/SettingsPlugin.ts +29 -0
- package/src/plugin-settings/actions.ts +17 -0
- package/src/plugin-settings/index.ts +6 -0
- package/src/react/PluginManagerProvider.ts +22 -0
- package/src/react/Surface.tsx +72 -0
- package/src/react/index.ts +8 -0
- package/src/react/useCapabilities.ts +40 -0
- package/src/testing/index.ts +5 -0
- package/src/testing/withPluginManager.stories.tsx +47 -0
- package/src/testing/withPluginManager.tsx +67 -0
- package/tsconfig.json +54 -2
- package/dist/lib/browser/chunk-3E7RY3CE.mjs +0 -72
- package/dist/lib/browser/chunk-3E7RY3CE.mjs.map +0 -7
- package/dist/lib/browser/chunk-653Y45CL.mjs +0 -41
- package/dist/lib/browser/chunk-653Y45CL.mjs.map +0 -7
- package/dist/lib/browser/chunk-FRXJ25VI.mjs +0 -214
- package/dist/lib/browser/chunk-FRXJ25VI.mjs.map +0 -7
- package/dist/lib/browser/chunk-YXM35XRE.mjs +0 -213
- package/dist/lib/browser/chunk-YXM35XRE.mjs.map +0 -7
- package/dist/lib/browser/plugin-intent-LU4KL2RO.mjs +0 -22
- package/dist/lib/browser/plugin-intent-LU4KL2RO.mjs.map +0 -7
- package/dist/lib/browser/plugin-settings-OM3G2QFY.mjs +0 -11
- package/dist/lib/browser/plugin-settings-OM3G2QFY.mjs.map +0 -7
- package/dist/lib/browser/plugin-surface-LECZMKSQ.mjs +0 -24
- package/dist/lib/browser/plugin-surface-LECZMKSQ.mjs.map +0 -7
- package/dist/lib/node/chunk-JZ2JVKRY.cjs +0 -58
- package/dist/lib/node/chunk-JZ2JVKRY.cjs.map +0 -7
- package/dist/lib/node/chunk-QBM42OQ6.cjs +0 -97
- package/dist/lib/node/chunk-QBM42OQ6.cjs.map +0 -7
- package/dist/lib/node/chunk-QSVP5HOW.cjs +0 -238
- package/dist/lib/node/chunk-QSVP5HOW.cjs.map +0 -7
- package/dist/lib/node/chunk-SOVLKUWI.cjs +0 -236
- package/dist/lib/node/chunk-SOVLKUWI.cjs.map +0 -7
- package/dist/lib/node/plugin-intent-FVFR2LKB.cjs +0 -43
- package/dist/lib/node/plugin-intent-FVFR2LKB.cjs.map +0 -7
- package/dist/lib/node/plugin-settings-OZ6IKAE5.cjs +0 -32
- package/dist/lib/node/plugin-settings-OZ6IKAE5.cjs.map +0 -7
- package/dist/lib/node/plugin-surface-YWDRXQTD.cjs +0 -45
- package/dist/lib/node/plugin-surface-YWDRXQTD.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-2R4GVK7O.mjs +0 -215
- package/dist/lib/node-esm/chunk-2R4GVK7O.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-EYCTSFEJ.mjs +0 -74
- package/dist/lib/node-esm/chunk-EYCTSFEJ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YFMFQBB4.mjs +0 -214
- package/dist/lib/node-esm/chunk-YFMFQBB4.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YNU7FTGJ.mjs +0 -43
- package/dist/lib/node-esm/chunk-YNU7FTGJ.mjs.map +0 -7
- package/dist/lib/node-esm/plugin-intent-V7ER24Y6.mjs +0 -23
- package/dist/lib/node-esm/plugin-intent-V7ER24Y6.mjs.map +0 -7
- package/dist/lib/node-esm/plugin-settings-37UVWF2V.mjs +0 -12
- package/dist/lib/node-esm/plugin-settings-37UVWF2V.mjs.map +0 -7
- package/dist/lib/node-esm/plugin-surface-TEU42XQN.mjs +0 -25
- package/dist/lib/node-esm/plugin-surface-TEU42XQN.mjs.map +0 -7
- package/dist/types/src/plugins/common/file.d.ts +0 -22
- package/dist/types/src/plugins/common/file.d.ts.map +0 -1
- package/dist/types/src/plugins/common/graph.d.ts +0 -51
- package/dist/types/src/plugins/common/graph.d.ts.map +0 -1
- package/dist/types/src/plugins/common/index.d.ts.map +0 -1
- package/dist/types/src/plugins/common/layout.d.ts +0 -202
- package/dist/types/src/plugins/common/layout.d.ts.map +0 -1
- package/dist/types/src/plugins/common/metadata.d.ts +0 -16
- package/dist/types/src/plugins/common/metadata.d.ts.map +0 -1
- package/dist/types/src/plugins/common/navigation.d.ts.map +0 -1
- package/dist/types/src/plugins/common/translations.d.ts.map +0 -1
- package/dist/types/src/plugins/helpers.d.ts +0 -41
- package/dist/types/src/plugins/helpers.d.ts.map +0 -1
- package/dist/types/src/plugins/index.d.ts +0 -7
- package/dist/types/src/plugins/index.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-host/HostPlugin.d.ts +0 -21
- package/dist/types/src/plugins/plugin-host/HostPlugin.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-host/PluginContainer.d.ts +0 -14
- package/dist/types/src/plugins/plugin-host/PluginContainer.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-host/PluginContext.d.ts +0 -47
- package/dist/types/src/plugins/plugin-host/PluginContext.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-host/index.d.ts +0 -4
- package/dist/types/src/plugins/plugin-host/index.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-host/plugin.d.ts +0 -98
- package/dist/types/src/plugins/plugin-host/plugin.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-host/plugin.test.d.ts +0 -35
- package/dist/types/src/plugins/plugin-host/plugin.test.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-intent/IntentContext.d.ts +0 -21
- package/dist/types/src/plugins/plugin-intent/IntentContext.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-intent/IntentPlugin.d.ts +0 -8
- package/dist/types/src/plugins/plugin-intent/IntentPlugin.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-intent/helpers.d.ts +0 -6
- package/dist/types/src/plugins/plugin-intent/helpers.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-intent/index.d.ts +0 -6
- package/dist/types/src/plugins/plugin-intent/index.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-intent/intent.d.ts +0 -81
- package/dist/types/src/plugins/plugin-intent/intent.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-intent/meta.d.ts +0 -5
- package/dist/types/src/plugins/plugin-intent/meta.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-intent/provides.d.ts +0 -20
- package/dist/types/src/plugins/plugin-intent/provides.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-settings/SettingsPlugin.d.ts +0 -4
- package/dist/types/src/plugins/plugin-settings/SettingsPlugin.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-settings/index.d.ts +0 -4
- package/dist/types/src/plugins/plugin-settings/index.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-settings/meta.d.ts +0 -5
- package/dist/types/src/plugins/plugin-settings/meta.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-settings/provides.d.ts +0 -13
- package/dist/types/src/plugins/plugin-settings/provides.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/ErrorBoundary.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/Surface.d.ts +0 -62
- package/dist/types/src/plugins/plugin-surface/Surface.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/SurfacePlugin.d.ts +0 -7
- package/dist/types/src/plugins/plugin-surface/SurfacePlugin.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/SurfaceRootContext.d.ts +0 -39
- package/dist/types/src/plugins/plugin-surface/SurfaceRootContext.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/helpers.d.ts +0 -21
- package/dist/types/src/plugins/plugin-surface/helpers.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/index.d.ts +0 -8
- package/dist/types/src/plugins/plugin-surface/index.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/meta.d.ts +0 -5
- package/dist/types/src/plugins/plugin-surface/meta.d.ts.map +0 -1
- package/dist/types/src/plugins/plugin-surface/provides.d.ts +0 -16
- package/dist/types/src/plugins/plugin-surface/provides.d.ts.map +0 -1
- package/src/plugins/common/file.ts +0 -36
- package/src/plugins/common/graph.ts +0 -70
- package/src/plugins/common/layout.ts +0 -155
- package/src/plugins/common/metadata.ts +0 -29
- package/src/plugins/common/translations.ts +0 -36
- package/src/plugins/helpers.ts +0 -92
- package/src/plugins/index.ts +0 -11
- package/src/plugins/plugin-host/HostPlugin.tsx +0 -96
- package/src/plugins/plugin-host/PluginContainer.tsx +0 -120
- package/src/plugins/plugin-host/PluginContext.tsx +0 -79
- package/src/plugins/plugin-host/index.ts +0 -8
- package/src/plugins/plugin-host/plugin.test.ts +0 -158
- package/src/plugins/plugin-host/plugin.ts +0 -126
- package/src/plugins/plugin-intent/IntentContext.tsx +0 -49
- package/src/plugins/plugin-intent/IntentPlugin.tsx +0 -151
- package/src/plugins/plugin-intent/helpers.ts +0 -11
- package/src/plugins/plugin-intent/index.ts +0 -12
- package/src/plugins/plugin-intent/intent.ts +0 -101
- package/src/plugins/plugin-intent/meta.ts +0 -9
- package/src/plugins/plugin-intent/provides.ts +0 -38
- package/src/plugins/plugin-settings/SettingsPlugin.tsx +0 -22
- package/src/plugins/plugin-settings/index.ts +0 -9
- package/src/plugins/plugin-settings/meta.ts +0 -9
- package/src/plugins/plugin-settings/provides.ts +0 -29
- package/src/plugins/plugin-surface/Surface.tsx +0 -195
- package/src/plugins/plugin-surface/SurfacePlugin.tsx +0 -33
- package/src/plugins/plugin-surface/SurfaceRootContext.tsx +0 -60
- package/src/plugins/plugin-surface/helpers.ts +0 -22
- package/src/plugins/plugin-surface/index.ts +0 -14
- package/src/plugins/plugin-surface/meta.ts +0 -9
- package/src/plugins/plugin-surface/provides.ts +0 -26
- /package/dist/types/src/{plugins/plugin-surface → react}/ErrorBoundary.d.ts +0 -0
- /package/src/{plugins/plugin-surface → react}/ErrorBoundary.tsx +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { topologicalSort } from './helpers';
|
|
8
|
+
|
|
9
|
+
describe('topologicalSort', () => {
|
|
10
|
+
it('should handle empty array', () => {
|
|
11
|
+
const result = topologicalSort([]);
|
|
12
|
+
expect(result).toEqual([]);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should handle single node with no dependencies', () => {
|
|
16
|
+
const nodes = [{ id: 'A', dependsOn: [], data: 1 }];
|
|
17
|
+
const result = topologicalSort(nodes);
|
|
18
|
+
expect(result).toEqual(nodes);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should sort simple linear dependencies', () => {
|
|
22
|
+
const nodes = [
|
|
23
|
+
{ id: 'A', dependsOn: ['B'], data: 1 },
|
|
24
|
+
{ id: 'B', dependsOn: ['C'], data: 2 },
|
|
25
|
+
{ id: 'C', data: 3 },
|
|
26
|
+
];
|
|
27
|
+
const result = topologicalSort(nodes);
|
|
28
|
+
|
|
29
|
+
expect(result.map((n) => n.id)).toEqual(['C', 'B', 'A']);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should handle multiple dependencies', () => {
|
|
33
|
+
const nodes = [
|
|
34
|
+
{ id: 'A', dependsOn: ['B', 'C'], data: 1 },
|
|
35
|
+
{ id: 'B', dependsOn: ['D'], data: 2 },
|
|
36
|
+
{ id: 'C', dependsOn: ['D'], data: 3 },
|
|
37
|
+
{ id: 'D', data: 4 },
|
|
38
|
+
];
|
|
39
|
+
const result = topologicalSort(nodes);
|
|
40
|
+
|
|
41
|
+
const resultIds = result.map((n) => n.id);
|
|
42
|
+
expect(resultIds[0]).toBe('D'); // D must be first.
|
|
43
|
+
expect(resultIds[3]).toBe('A'); // A must be last.
|
|
44
|
+
// B and C can be in either order.
|
|
45
|
+
expect(resultIds.slice(1, 3)).toContain('B');
|
|
46
|
+
expect(resultIds.slice(1, 3)).toContain('C');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should throw on circular dependencies', () => {
|
|
50
|
+
const nodes = [
|
|
51
|
+
{ id: 'A', dependsOn: ['B'], data: 1 },
|
|
52
|
+
{ id: 'B', dependsOn: ['A'], data: 2 },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
expect(() => topologicalSort(nodes)).toThrow(/Circular dependency detected/);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should throw on missing dependencies', () => {
|
|
59
|
+
const nodes = [
|
|
60
|
+
{ id: 'A', dependsOn: ['B'], data: 1 },
|
|
61
|
+
{ id: 'B', dependsOn: ['C'], data: 2 },
|
|
62
|
+
// C is missing.
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
expect(() => topologicalSort(nodes)).toThrow(/Node C not found/);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should maintain data integrity', () => {
|
|
69
|
+
const nodes = [
|
|
70
|
+
{ id: 'A', dependsOn: ['B'], data: { value: 1 } },
|
|
71
|
+
{ id: 'B', data: { value: 2 } },
|
|
72
|
+
];
|
|
73
|
+
const result = topologicalSort(nodes);
|
|
74
|
+
|
|
75
|
+
expect(result[0].data).toEqual({ value: 2 });
|
|
76
|
+
expect(result[1].data).toEqual({ value: 1 });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should handle complex dependency graph', () => {
|
|
80
|
+
const nodes = [
|
|
81
|
+
{ id: 'A', dependsOn: ['B', 'C'], data: 1 },
|
|
82
|
+
{ id: 'B', dependsOn: ['D'], data: 2 },
|
|
83
|
+
{ id: 'C', dependsOn: ['D', 'E'], data: 3 },
|
|
84
|
+
{ id: 'D', dependsOn: ['F'], data: 4 },
|
|
85
|
+
{ id: 'E', dependsOn: ['F'], data: 5 },
|
|
86
|
+
{ id: 'F', data: 6 },
|
|
87
|
+
];
|
|
88
|
+
const result = topologicalSort(nodes);
|
|
89
|
+
const resultIds = result.map((n) => n.id);
|
|
90
|
+
|
|
91
|
+
// Verify order constraints.
|
|
92
|
+
expect(resultIds[0]).toBe('F'); // F must be first.
|
|
93
|
+
expect(resultIds[resultIds.length - 1]).toBe('A'); // A must be last.
|
|
94
|
+
expect(resultIds.indexOf('D')).toBeLessThan(resultIds.indexOf('B'));
|
|
95
|
+
expect(resultIds.indexOf('E')).toBeLessThan(resultIds.indexOf('C'));
|
|
96
|
+
});
|
|
97
|
+
});
|
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
type DependencyNode = {
|
|
6
|
+
id: string;
|
|
7
|
+
dependsOn?: string[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Topologically sorts a list of nodes based on their dependencies.
|
|
12
|
+
*/
|
|
13
|
+
// TODO(wittjosiah): Factor out?
|
|
14
|
+
export const topologicalSort = <T extends DependencyNode>(nodes: T[]): T[] => {
|
|
15
|
+
const getDependencies = (nodeId: string, seen = new Set<string>(), path = new Set<string>()): string[] => {
|
|
16
|
+
if (path.has(nodeId)) {
|
|
17
|
+
throw new Error(`Circular dependency detected involving ${nodeId}`);
|
|
18
|
+
}
|
|
19
|
+
if (seen.has(nodeId)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const node = nodes.find((n) => n.id === nodeId);
|
|
24
|
+
if (!node) {
|
|
25
|
+
throw new Error(`Node ${nodeId} not found but is listed as a dependency`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const newPath = new Set([...path, nodeId]);
|
|
29
|
+
const newSeen = new Set([...seen, nodeId]);
|
|
30
|
+
|
|
31
|
+
const dependsOn = node.dependsOn ?? [];
|
|
32
|
+
return [...dependsOn.flatMap((depId) => getDependencies(depId, newSeen, newPath)), nodeId];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Get all unique dependencies.
|
|
36
|
+
const allDependencies = nodes
|
|
37
|
+
.map((node) => node.id)
|
|
38
|
+
.flatMap((id) => getDependencies(id))
|
|
39
|
+
.filter((id, index, self) => self.indexOf(id) === index);
|
|
40
|
+
|
|
41
|
+
// Map back to original nodes
|
|
42
|
+
return allDependencies
|
|
43
|
+
.map((id) => nodes.find((node) => node.id === id))
|
|
44
|
+
.filter((node): node is T => node !== undefined);
|
|
45
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export * from './plugins';
|
|
6
|
-
|
|
7
5
|
export * from './App';
|
|
6
|
+
export * from './common';
|
|
7
|
+
export * from './core';
|
|
8
|
+
export * from './plugin-intent';
|
|
9
|
+
export * from './plugin-settings';
|
|
10
|
+
export * from './react';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
8
|
+
|
|
9
|
+
import { Capabilities, createSurface } from '../../common';
|
|
10
|
+
import { contributes } from '../../core';
|
|
11
|
+
import { usePluginManager } from '../../react';
|
|
12
|
+
|
|
13
|
+
export const Debug = () => {
|
|
14
|
+
const manager = usePluginManager();
|
|
15
|
+
|
|
16
|
+
const object = {
|
|
17
|
+
core: manager.core,
|
|
18
|
+
enabled: manager.enabled,
|
|
19
|
+
active: manager.active,
|
|
20
|
+
pendingReset: manager.pendingReset,
|
|
21
|
+
eventsFired: manager.eventsFired,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<SyntaxHighlighter language='json' classNames='flex w-full text-xs opacity-75 rounded'>
|
|
26
|
+
{JSON.stringify(object, undefined, 2)}
|
|
27
|
+
</SyntaxHighlighter>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default () =>
|
|
32
|
+
contributes(
|
|
33
|
+
Capabilities.ReactSurface,
|
|
34
|
+
createSurface({
|
|
35
|
+
id: 'dxos.org/test/debug/main',
|
|
36
|
+
role: 'secondary',
|
|
37
|
+
component: Debug,
|
|
38
|
+
}),
|
|
39
|
+
);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Events } from '../../common';
|
|
6
|
+
import { defineModule, definePlugin, lazy } from '../../core';
|
|
7
|
+
|
|
8
|
+
const Debug = lazy(() => import('./Debug'));
|
|
9
|
+
|
|
10
|
+
export const DebugPlugin = () =>
|
|
11
|
+
definePlugin({ id: 'dxos.org/test/debug' }, [
|
|
12
|
+
defineModule({
|
|
13
|
+
id: 'dxos.org/test/debug/main',
|
|
14
|
+
activatesOn: Events.Startup,
|
|
15
|
+
activate: () => Debug(),
|
|
16
|
+
}),
|
|
17
|
+
]);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useCallback } from 'react';
|
|
6
|
+
|
|
7
|
+
import { IconButton, List, ListItem } from '@dxos/react-ui';
|
|
8
|
+
|
|
9
|
+
import { Capabilities } from '../../common';
|
|
10
|
+
import { contributes } from '../../core';
|
|
11
|
+
import { usePluginManager } from '../../react';
|
|
12
|
+
|
|
13
|
+
const Item = ({
|
|
14
|
+
id,
|
|
15
|
+
disabled,
|
|
16
|
+
onRemove,
|
|
17
|
+
}: {
|
|
18
|
+
id: string;
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
onRemove: (id: string) => Promise<void>;
|
|
21
|
+
}) => {
|
|
22
|
+
const handleRemove = useCallback(() => onRemove(id), [onRemove]);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<ListItem.Root key={id} id={id}>
|
|
26
|
+
<ListItem.Heading classNames='grow pbs-2'>{id}</ListItem.Heading>
|
|
27
|
+
<ListItem.Endcap>
|
|
28
|
+
<IconButton
|
|
29
|
+
iconOnly
|
|
30
|
+
variant='ghost'
|
|
31
|
+
icon='ph--x--regular'
|
|
32
|
+
label='Remove'
|
|
33
|
+
size={5}
|
|
34
|
+
disabled={disabled}
|
|
35
|
+
onClick={handleRemove}
|
|
36
|
+
/>
|
|
37
|
+
</ListItem.Endcap>
|
|
38
|
+
</ListItem.Root>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Main = () => {
|
|
43
|
+
const manager = usePluginManager();
|
|
44
|
+
|
|
45
|
+
const handleRemove = useCallback(
|
|
46
|
+
async (id: string) => {
|
|
47
|
+
await manager.remove(id);
|
|
48
|
+
},
|
|
49
|
+
[manager],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<List itemSizes='one'>
|
|
54
|
+
{manager.plugins.map((plugin) => (
|
|
55
|
+
<Item
|
|
56
|
+
key={plugin.meta.id}
|
|
57
|
+
id={plugin.meta.id}
|
|
58
|
+
disabled={manager.core.includes(plugin.meta.id)}
|
|
59
|
+
onRemove={handleRemove}
|
|
60
|
+
/>
|
|
61
|
+
))}
|
|
62
|
+
</List>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default () =>
|
|
67
|
+
contributes(Capabilities.ReactSurface, {
|
|
68
|
+
id: 'dxos.org/test/generator/main',
|
|
69
|
+
role: 'primary',
|
|
70
|
+
component: Main,
|
|
71
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useCallback } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Button } from '@dxos/react-ui';
|
|
8
|
+
|
|
9
|
+
import { CountEvent, createPluginId, Number } from './generator';
|
|
10
|
+
import { Capabilities } from '../../common';
|
|
11
|
+
import { contributes } from '../../core';
|
|
12
|
+
import { usePluginManager } from '../../react';
|
|
13
|
+
|
|
14
|
+
export const Toolbar = () => {
|
|
15
|
+
const manager = usePluginManager();
|
|
16
|
+
|
|
17
|
+
const handleAdd = useCallback(async () => {
|
|
18
|
+
const id = createPluginId(Math.random().toString(16).substring(2, 8));
|
|
19
|
+
await manager.add(id);
|
|
20
|
+
}, [manager]);
|
|
21
|
+
|
|
22
|
+
const handleCount = useCallback(async () => {
|
|
23
|
+
if (manager.pendingReset.includes(CountEvent.id)) {
|
|
24
|
+
await manager.reset(CountEvent);
|
|
25
|
+
} else {
|
|
26
|
+
await manager.activate(CountEvent);
|
|
27
|
+
}
|
|
28
|
+
}, [manager]);
|
|
29
|
+
|
|
30
|
+
const count = manager.context.requestCapabilities(Number).reduce((acc, curr) => acc + curr, 0);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<Button onClick={handleAdd}>Add</Button>
|
|
35
|
+
<Button onClick={handleCount}>Count</Button>
|
|
36
|
+
<div className='flex items-center'>Count: {count}</div>
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default () =>
|
|
42
|
+
contributes(Capabilities.ReactSurface, {
|
|
43
|
+
id: 'dxos.org/test/generator/toolbar',
|
|
44
|
+
role: 'toolbar',
|
|
45
|
+
component: Toolbar,
|
|
46
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { contributes, defineEvent, defineCapability, defineModule, definePlugin } from '../../core';
|
|
6
|
+
|
|
7
|
+
export const Number = defineCapability<number>('dxos.org/test/generator/number');
|
|
8
|
+
|
|
9
|
+
export const CountEvent = defineEvent('dxos.org/test/generator/count');
|
|
10
|
+
|
|
11
|
+
export const createPluginId = (id: string) => `dxos.org/test/generator/${id}`;
|
|
12
|
+
|
|
13
|
+
export const createNumberPlugin = (id: string) => {
|
|
14
|
+
const number = Math.floor(Math.random() * 100);
|
|
15
|
+
|
|
16
|
+
return definePlugin({ id }, [
|
|
17
|
+
defineModule({
|
|
18
|
+
id: `${id}/main`,
|
|
19
|
+
activatesOn: CountEvent,
|
|
20
|
+
activate: () => contributes(Number, number),
|
|
21
|
+
}),
|
|
22
|
+
]);
|
|
23
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Events } from '../../common';
|
|
6
|
+
import { defineModule, definePlugin, lazy } from '../../core';
|
|
7
|
+
|
|
8
|
+
const Main = lazy(() => import('./Main'));
|
|
9
|
+
const Toolbar = lazy(() => import('./Toolbar'));
|
|
10
|
+
|
|
11
|
+
export const GeneratorPlugin = () =>
|
|
12
|
+
definePlugin({ id: 'dxos.org/test/generator' }, [
|
|
13
|
+
defineModule({
|
|
14
|
+
id: 'dxos.org/test/generator/main',
|
|
15
|
+
activatesOn: Events.Startup,
|
|
16
|
+
activate: async () => [await Main(), await Toolbar()],
|
|
17
|
+
}),
|
|
18
|
+
]);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { Capabilities } from '../../common';
|
|
8
|
+
import { contributes } from '../../core';
|
|
9
|
+
import { Surface } from '../../react';
|
|
10
|
+
|
|
11
|
+
export const Layout = () => {
|
|
12
|
+
return (
|
|
13
|
+
<div className='flex flex-col gap-2'>
|
|
14
|
+
<div className='flex gap-2'>
|
|
15
|
+
<Surface role='toolbar' />
|
|
16
|
+
</div>
|
|
17
|
+
<div className='flex gap-2'>
|
|
18
|
+
<div className='flex-1'>
|
|
19
|
+
<Surface role='primary' limit={1} />
|
|
20
|
+
</div>
|
|
21
|
+
<div className='flex-1'>
|
|
22
|
+
<Surface role='secondary' limit={1} />
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default () =>
|
|
30
|
+
contributes(Capabilities.ReactRoot, {
|
|
31
|
+
id: 'dxos.org/test/layout/root',
|
|
32
|
+
root: Layout,
|
|
33
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Events } from '../../common';
|
|
6
|
+
import { definePlugin, lazy, defineModule } from '../../core';
|
|
7
|
+
|
|
8
|
+
const Layout = lazy(() => import('./Layout'));
|
|
9
|
+
|
|
10
|
+
export const LayoutPlugin = () =>
|
|
11
|
+
definePlugin({ id: 'dxos.org/test/layout' }, [
|
|
12
|
+
defineModule({
|
|
13
|
+
id: 'dxos.org/test/layout/root',
|
|
14
|
+
activatesOn: Events.Startup,
|
|
15
|
+
activate: () => Layout(),
|
|
16
|
+
}),
|
|
17
|
+
]);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useCallback } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Button } from '@dxos/react-ui';
|
|
8
|
+
|
|
9
|
+
import { Log } from './schema';
|
|
10
|
+
import { Capabilities, createSurface } from '../../common';
|
|
11
|
+
import { contributes } from '../../core';
|
|
12
|
+
import { createIntent, useIntentDispatcher } from '../../plugin-intent';
|
|
13
|
+
|
|
14
|
+
export const Logger = () => {
|
|
15
|
+
const { dispatchPromise } = useIntentDispatcher();
|
|
16
|
+
const handleClick = useCallback(() => dispatchPromise(createIntent(Log, { message: 'Hello, world!' })), []);
|
|
17
|
+
return <Button onClick={handleClick}>Log</Button>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default () =>
|
|
21
|
+
contributes(
|
|
22
|
+
Capabilities.ReactSurface,
|
|
23
|
+
createSurface({
|
|
24
|
+
id: 'dxos.org/test/logger/action',
|
|
25
|
+
role: 'toolbar',
|
|
26
|
+
component: Logger,
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { log } from '@dxos/log';
|
|
6
|
+
|
|
7
|
+
import { Log } from './schema';
|
|
8
|
+
import { Capabilities, Events } from '../../common';
|
|
9
|
+
import { contributes, defineModule, lazy, definePlugin } from '../../core';
|
|
10
|
+
import { createResolver } from '../../plugin-intent';
|
|
11
|
+
|
|
12
|
+
const Toolbar = lazy(() => import('./Toolbar'));
|
|
13
|
+
|
|
14
|
+
export const LoggerPlugin = () =>
|
|
15
|
+
definePlugin({ id: 'dxos.org/test/logger' }, [
|
|
16
|
+
defineModule({
|
|
17
|
+
id: 'dxos.org/test/logger/intents',
|
|
18
|
+
activatesOn: Events.SetupIntents,
|
|
19
|
+
activate: () => [
|
|
20
|
+
contributes(
|
|
21
|
+
Capabilities.IntentResolver,
|
|
22
|
+
createResolver(Log, ({ message }) => {
|
|
23
|
+
log.info(message);
|
|
24
|
+
}),
|
|
25
|
+
),
|
|
26
|
+
],
|
|
27
|
+
}),
|
|
28
|
+
defineModule({
|
|
29
|
+
id: 'dxos.org/test/logger/surfaces',
|
|
30
|
+
activatesOn: Events.Startup,
|
|
31
|
+
activate: () => Toolbar(),
|
|
32
|
+
}),
|
|
33
|
+
]);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxos-theme';
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
10
|
+
|
|
11
|
+
import { DebugPlugin } from './debug';
|
|
12
|
+
import { createNumberPlugin, GeneratorPlugin } from './generator';
|
|
13
|
+
import { LayoutPlugin } from './layout';
|
|
14
|
+
import { LoggerPlugin } from './logger';
|
|
15
|
+
import { createApp } from '../App';
|
|
16
|
+
import { IntentPlugin } from '../plugin-intent';
|
|
17
|
+
|
|
18
|
+
const plugins = [IntentPlugin(), LayoutPlugin(), DebugPlugin(), LoggerPlugin(), GeneratorPlugin()];
|
|
19
|
+
|
|
20
|
+
const Story = createApp({
|
|
21
|
+
pluginLoader: (id) => createNumberPlugin(id),
|
|
22
|
+
plugins,
|
|
23
|
+
core: plugins.map((plugin) => plugin.meta.id),
|
|
24
|
+
// Having a non-empty placeholder makes it clear if it's taking a while to load.
|
|
25
|
+
placeholder: <div>Loading...</div>,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const Playground = {};
|
|
29
|
+
|
|
30
|
+
export default {
|
|
31
|
+
title: 'sdk/app-framework/playground',
|
|
32
|
+
render: Story,
|
|
33
|
+
decorators: [withTheme, withLayout({ tooltips: true })],
|
|
34
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Context, createContext, useContext, type Provider, useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
import { raise } from '@dxos/debug';
|
|
8
|
+
import { pick } from '@dxos/util';
|
|
9
|
+
|
|
10
|
+
import { type AnyIntentResolver, type IntentContext } from './intent-dispatcher';
|
|
11
|
+
import { Capabilities } from '../common';
|
|
12
|
+
import { usePluginManager } from '../react';
|
|
13
|
+
|
|
14
|
+
const IntentContext: Context<IntentContext | undefined> = createContext<IntentContext | undefined>(undefined);
|
|
15
|
+
|
|
16
|
+
export const useIntentDispatcher = (): Pick<IntentContext, 'dispatch' | 'dispatchPromise'> => {
|
|
17
|
+
const context = useContext(IntentContext) ?? raise(new Error('IntentContext not found'));
|
|
18
|
+
return pick(context, ['dispatch', 'dispatchPromise']);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const useIntentResolver = (module: string, resolver: AnyIntentResolver) => {
|
|
22
|
+
const manager = usePluginManager();
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
manager.context.contributeCapability({
|
|
25
|
+
module,
|
|
26
|
+
interface: Capabilities.IntentResolver,
|
|
27
|
+
implementation: resolver,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return () => manager.context.removeCapability(Capabilities.IntentResolver, resolver);
|
|
31
|
+
}, [module, resolver]);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const IntentProvider: Provider<IntentContext | undefined> = IntentContext.Provider;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Effect } from 'effect';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { create } from '@dxos/live-object';
|
|
9
|
+
|
|
10
|
+
import { IntentProvider } from './IntentContext';
|
|
11
|
+
import { INTENT_PLUGIN } from './actions';
|
|
12
|
+
import { type AnyIntentResolver, createDispatcher, type IntentContext } from './intent-dispatcher';
|
|
13
|
+
import { Capabilities, Events } from '../common';
|
|
14
|
+
import { contributes, defineModule, definePlugin } from '../core';
|
|
15
|
+
|
|
16
|
+
const defaultEffect = () => Effect.fail(new Error('Intent runtime not ready'));
|
|
17
|
+
const defaultPromise = () => Effect.runPromise(defaultEffect());
|
|
18
|
+
|
|
19
|
+
export const IntentPlugin = () =>
|
|
20
|
+
definePlugin({ id: INTENT_PLUGIN }, [
|
|
21
|
+
defineModule({
|
|
22
|
+
id: `${INTENT_PLUGIN}/module/dispatcher`,
|
|
23
|
+
// TODO(wittjosiah): This will mean that startup needs to be reset when intents are added or removed.
|
|
24
|
+
// This is fine for now because it's how it worked prior to capabilities api anyways.
|
|
25
|
+
// In the future, the intent dispatcher should be able to be reset without resetting the entire app.
|
|
26
|
+
activatesOn: Events.Startup,
|
|
27
|
+
activatesBefore: [Events.SetupIntents],
|
|
28
|
+
activatesAfter: [Events.DispatcherReady],
|
|
29
|
+
activate: (context) => {
|
|
30
|
+
const state = create<IntentContext>({
|
|
31
|
+
dispatch: defaultEffect,
|
|
32
|
+
dispatchPromise: defaultPromise,
|
|
33
|
+
undo: defaultEffect,
|
|
34
|
+
undoPromise: defaultPromise,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// TODO(wittjosiah): Make getResolver callback async and allow resolvers to be requested on demand.
|
|
38
|
+
const { dispatch, dispatchPromise, undo, undoPromise } = createDispatcher((module) =>
|
|
39
|
+
context
|
|
40
|
+
.requestCapabilities(Capabilities.IntentResolver, (c, moduleId): c is AnyIntentResolver => {
|
|
41
|
+
return module ? moduleId === module : true;
|
|
42
|
+
})
|
|
43
|
+
.flat(),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
state.dispatch = dispatch;
|
|
47
|
+
state.dispatchPromise = dispatchPromise;
|
|
48
|
+
state.undo = undo;
|
|
49
|
+
state.undoPromise = undoPromise;
|
|
50
|
+
|
|
51
|
+
return [
|
|
52
|
+
contributes(Capabilities.IntentDispatcher, state),
|
|
53
|
+
contributes(Capabilities.ReactContext, {
|
|
54
|
+
id: INTENT_PLUGIN,
|
|
55
|
+
context: ({ children }) => <IntentProvider value={state}>{children}</IntentProvider>,
|
|
56
|
+
}),
|
|
57
|
+
];
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
]);
|