@dxos/app-framework 0.7.5-main.9d2a38b → 0.7.5-main.ff8607b
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/app-graph-builder-F7VZ6LRN.mjs +137 -0
- package/dist/lib/browser/app-graph-builder-F7VZ6LRN.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GNLU3GAU.mjs → chunk-ATRNTMSS.mjs} +623 -819
- package/dist/lib/browser/chunk-ATRNTMSS.mjs.map +7 -0
- package/dist/lib/browser/chunk-LDJ3T4V3.mjs +32 -0
- package/dist/lib/browser/chunk-LDJ3T4V3.mjs.map +7 -0
- package/dist/lib/browser/chunk-WS6SU6HI.mjs +285 -0
- package/dist/lib/browser/chunk-WS6SU6HI.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +57 -74
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs +11 -0
- package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs.map +7 -0
- package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs +38 -0
- package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/store-QU2IKFAI.mjs +19 -0
- package/dist/lib/browser/store-QU2IKFAI.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +10 -3
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/worker.mjs +77 -0
- package/dist/lib/browser/worker.mjs.map +7 -0
- package/dist/lib/node/app-graph-builder-JGBADFF7.cjs +146 -0
- package/dist/lib/node/app-graph-builder-JGBADFF7.cjs.map +7 -0
- package/dist/lib/node/chunk-QLVQ6PND.cjs +58 -0
- package/dist/lib/node/chunk-QLVQ6PND.cjs.map +7 -0
- package/dist/lib/node/chunk-WKC6YMEQ.cjs +1433 -0
- package/dist/lib/node/chunk-WKC6YMEQ.cjs.map +7 -0
- package/dist/lib/node/chunk-WRWRZKZU.cjs +308 -0
- package/dist/lib/node/chunk-WRWRZKZU.cjs.map +7 -0
- package/dist/lib/node/index.cjs +106 -118
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs +32 -0
- package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs.map +7 -0
- package/dist/lib/node/intent-resolver-3TKCXP4S.cjs +45 -0
- package/dist/lib/node/intent-resolver-3TKCXP4S.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/store-4QMUUU2A.cjs +34 -0
- package/dist/lib/node/store-4QMUUU2A.cjs.map +7 -0
- package/dist/lib/node/testing/index.cjs +15 -8
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/lib/node/worker.cjs +99 -0
- package/dist/lib/node/worker.cjs.map +7 -0
- package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs +138 -0
- package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-KPMTPXQI.mjs → chunk-44J2VZBB.mjs} +623 -819
- package/dist/lib/node-esm/chunk-44J2VZBB.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-CNJYZNSL.mjs +34 -0
- package/dist/lib/node-esm/chunk-CNJYZNSL.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HTLXL32I.mjs +286 -0
- package/dist/lib/node-esm/chunk-HTLXL32I.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +57 -74
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs +12 -0
- package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs.map +7 -0
- package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs +39 -0
- package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/store-VWDAYUQY.mjs +20 -0
- package/dist/lib/node-esm/store-VWDAYUQY.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +10 -3
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/worker.mjs +78 -0
- package/dist/lib/node-esm/worker.mjs.map +7 -0
- package/dist/types/src/App.d.ts.map +1 -1
- package/dist/types/src/common/capabilities.d.ts +63 -110
- package/dist/types/src/common/capabilities.d.ts.map +1 -1
- package/dist/types/src/common/events.d.ts +8 -1
- package/dist/types/src/common/events.d.ts.map +1 -1
- package/dist/types/src/common/file.d.ts +1 -1
- package/dist/types/src/common/file.d.ts.map +1 -1
- package/dist/types/src/common/graph.d.ts +2 -2
- package/dist/types/src/common/graph.d.ts.map +1 -1
- package/dist/types/src/common/index.d.ts +0 -1
- package/dist/types/src/common/index.d.ts.map +1 -1
- package/dist/types/src/common/layout.d.ts +204 -121
- package/dist/types/src/common/layout.d.ts.map +1 -1
- package/dist/types/src/common/surface.d.ts +3 -3
- package/dist/types/src/common/surface.d.ts.map +1 -1
- package/dist/types/src/common/translations.d.ts +7 -7
- package/dist/types/src/common/translations.d.ts.map +1 -1
- package/dist/types/src/core/capabilities.d.ts +6 -2
- package/dist/types/src/core/capabilities.d.ts.map +1 -1
- package/dist/types/src/core/manager.d.ts +2 -9
- package/dist/types/src/core/manager.d.ts.map +1 -1
- package/dist/types/src/core/plugin.d.ts +5 -2
- package/dist/types/src/core/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -1
- package/dist/types/src/playground/generator/generator.d.ts +2 -0
- package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
- package/dist/types/src/playground/generator/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -1
- package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/logger/schema.d.ts +1 -1
- package/dist/types/src/playground/logger/schema.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/actions.d.ts +1 -1
- package/dist/types/src/plugin-intent/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/index.d.ts +0 -1
- package/dist/types/src/plugin-intent/index.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +27 -20
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent.d.ts +3 -3
- package/dist/types/src/plugin-intent/intent.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/actions.d.ts +11 -1
- package/dist/types/src/plugin-settings/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts +197 -0
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/intent-resolver.d.ts +4 -0
- package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/store.d.ts +5 -0
- package/dist/types/src/plugin-settings/store.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/translations.d.ts +11 -0
- package/dist/types/src/plugin-settings/translations.d.ts.map +1 -0
- package/dist/types/src/{plugin-intent → react}/IntentContext.d.ts +1 -1
- package/dist/types/src/react/IntentContext.d.ts.map +1 -0
- package/dist/types/src/react/Surface.d.ts.map +1 -1
- package/dist/types/src/react/Surface.stories.d.ts +16 -0
- package/dist/types/src/react/Surface.stories.d.ts.map +1 -0
- package/dist/types/src/react/common.d.ts +12 -0
- package/dist/types/src/react/common.d.ts.map +1 -0
- package/dist/types/src/react/index.d.ts +2 -0
- package/dist/types/src/react/index.d.ts.map +1 -1
- package/dist/types/src/react/useIntentResolver.d.ts +3 -0
- package/dist/types/src/react/useIntentResolver.d.ts.map +1 -0
- package/dist/types/src/testing/withPluginManager.d.ts +1 -1
- package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
- package/dist/types/src/worker.d.ts +4 -0
- package/dist/types/src/worker.d.ts.map +1 -0
- package/package.json +26 -20
- package/project.json +3 -3
- package/src/App.tsx +15 -14
- package/src/common/capabilities.ts +20 -11
- package/src/common/events.ts +10 -1
- package/src/common/file.ts +1 -1
- package/src/common/graph.ts +2 -2
- package/src/common/index.ts +0 -1
- package/src/common/layout.ts +194 -126
- package/src/common/surface.ts +2 -2
- package/src/common/translations.ts +7 -8
- package/src/core/capabilities.ts +16 -7
- package/src/core/manager.test.ts +22 -73
- package/src/core/manager.ts +105 -91
- package/src/core/plugin.ts +6 -3
- package/src/playground/debug/plugin.ts +1 -1
- package/src/playground/generator/Toolbar.tsx +11 -11
- package/src/playground/generator/generator.ts +25 -0
- package/src/playground/generator/plugin.ts +6 -1
- package/src/playground/layout/plugin.ts +1 -1
- package/src/playground/logger/Toolbar.tsx +2 -1
- package/src/playground/logger/plugin.ts +6 -3
- package/src/playground/logger/schema.ts +1 -1
- package/src/plugin-intent/IntentPlugin.tsx +3 -43
- package/src/plugin-intent/actions.ts +1 -1
- package/src/plugin-intent/index.ts +0 -1
- package/src/plugin-intent/intent-dispatcher.test.ts +48 -29
- package/src/plugin-intent/intent-dispatcher.ts +76 -41
- package/src/plugin-intent/intent.ts +5 -5
- package/src/plugin-settings/SettingsPlugin.ts +19 -13
- package/src/plugin-settings/actions.ts +11 -1
- package/src/plugin-settings/app-graph-builder.ts +122 -0
- package/src/plugin-settings/intent-resolver.ts +28 -0
- package/src/plugin-settings/store.ts +20 -0
- package/src/plugin-settings/translations.ts +17 -0
- package/src/{plugin-intent → react}/IntentContext.tsx +2 -2
- package/src/react/Surface.stories.tsx +96 -0
- package/src/react/Surface.tsx +11 -8
- package/src/react/common.ts +12 -0
- package/src/react/index.ts +2 -0
- package/src/react/useIntentResolver.ts +22 -0
- package/src/testing/withPluginManager.tsx +11 -3
- package/src/worker.ts +11 -0
- package/tsconfig.json +3 -3
- package/dist/lib/browser/chunk-GNLU3GAU.mjs.map +0 -7
- package/dist/lib/node/chunk-FBA4BB3J.cjs +0 -1639
- package/dist/lib/node/chunk-FBA4BB3J.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-KPMTPXQI.mjs.map +0 -7
- package/dist/types/src/common/navigation.d.ts +0 -241
- package/dist/types/src/common/navigation.d.ts.map +0 -1
- package/dist/types/src/plugin-intent/IntentContext.d.ts.map +0 -1
- package/src/common/navigation.ts +0 -199
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { S } from '@
|
|
5
|
+
import { Schema as S } from '@effect/schema';
|
|
6
6
|
|
|
7
7
|
export const SETTINGS_PLUGIN = 'dxos.org/plugin/settings';
|
|
8
8
|
export const SETTINGS_ACTION = `${SETTINGS_PLUGIN}/action`;
|
|
9
|
+
export const SETTINGS_ID = 'dxos:settings';
|
|
10
|
+
export const SETTINGS_KEY = 'settings';
|
|
9
11
|
|
|
10
12
|
export namespace SettingsAction {
|
|
11
13
|
export class Open extends S.TaggedClass<Open>()(`${SETTINGS_ACTION}/open`, {
|
|
@@ -14,4 +16,12 @@ export namespace SettingsAction {
|
|
|
14
16
|
}),
|
|
15
17
|
output: S.Void,
|
|
16
18
|
}) {}
|
|
19
|
+
|
|
20
|
+
export class OpenPluginRegistry extends S.TaggedClass<OpenPluginRegistry>()(
|
|
21
|
+
`${SETTINGS_ACTION}/open-plugin-registry`,
|
|
22
|
+
{
|
|
23
|
+
input: S.Void,
|
|
24
|
+
output: S.Void,
|
|
25
|
+
},
|
|
26
|
+
) {}
|
|
17
27
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createExtension, type Node } from '@dxos/app-graph';
|
|
6
|
+
import { type SettingsStore, type SettingsValue } from '@dxos/local-storage';
|
|
7
|
+
import { nonNullable } from '@dxos/util';
|
|
8
|
+
|
|
9
|
+
import { SETTINGS_ID, SETTINGS_KEY, SETTINGS_PLUGIN, SettingsAction } from './actions';
|
|
10
|
+
import { Capabilities } from '../common';
|
|
11
|
+
import { contributes, type PluginMeta, type PluginsContext } from '../core';
|
|
12
|
+
import { createIntent } from '../plugin-intent';
|
|
13
|
+
|
|
14
|
+
export default (context: PluginsContext) =>
|
|
15
|
+
contributes(Capabilities.AppGraphBuilder, [
|
|
16
|
+
createExtension({
|
|
17
|
+
id: `${SETTINGS_PLUGIN}/action`,
|
|
18
|
+
filter: (node): node is Node<null> => node.id === 'root',
|
|
19
|
+
actions: () => [
|
|
20
|
+
{
|
|
21
|
+
id: SETTINGS_PLUGIN,
|
|
22
|
+
data: async () => {
|
|
23
|
+
const { dispatchPromise: dispatch } = context.requestCapability(Capabilities.IntentDispatcher);
|
|
24
|
+
await dispatch(createIntent(SettingsAction.Open));
|
|
25
|
+
},
|
|
26
|
+
properties: {
|
|
27
|
+
label: ['open settings label', { ns: SETTINGS_PLUGIN }],
|
|
28
|
+
icon: 'ph--gear--regular',
|
|
29
|
+
keyBinding: {
|
|
30
|
+
macos: 'meta+,',
|
|
31
|
+
windows: 'alt+,',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
}),
|
|
37
|
+
createExtension({
|
|
38
|
+
id: `${SETTINGS_PLUGIN}/core`,
|
|
39
|
+
filter: (node): node is Node<null> => node.id === 'root',
|
|
40
|
+
connector: () => [
|
|
41
|
+
{
|
|
42
|
+
id: SETTINGS_ID,
|
|
43
|
+
type: SETTINGS_PLUGIN,
|
|
44
|
+
properties: {
|
|
45
|
+
label: ['app settings label', { ns: SETTINGS_PLUGIN }],
|
|
46
|
+
icon: 'ph--gear--regular',
|
|
47
|
+
disposition: 'pin-end',
|
|
48
|
+
position: 'fallback',
|
|
49
|
+
testId: 'treeView.appSettings',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
}),
|
|
54
|
+
createExtension({
|
|
55
|
+
id: `${SETTINGS_PLUGIN}/core-plugins`,
|
|
56
|
+
filter: (node): node is Node<null> => node.id === SETTINGS_ID,
|
|
57
|
+
connector: () => {
|
|
58
|
+
const manager = context.requestCapability(Capabilities.PluginManager);
|
|
59
|
+
const [settingsStore] = context.requestCapabilities(Capabilities.SettingsStore);
|
|
60
|
+
return [
|
|
61
|
+
...manager.plugins
|
|
62
|
+
.filter((plugin) => manager.core.includes(plugin.meta.id))
|
|
63
|
+
.map((plugin): [PluginMeta, SettingsStore<SettingsValue>] | null => {
|
|
64
|
+
const settings = settingsStore?.getStore(plugin.meta.id);
|
|
65
|
+
if (!settings) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return [plugin.meta, settings];
|
|
70
|
+
})
|
|
71
|
+
.filter(nonNullable)
|
|
72
|
+
.map(([meta, settings]) => ({
|
|
73
|
+
id: `${SETTINGS_KEY}:${meta.id.replaceAll('/', ':')}`,
|
|
74
|
+
type: 'category',
|
|
75
|
+
data: settings,
|
|
76
|
+
properties: {
|
|
77
|
+
label: meta.name ?? meta.id,
|
|
78
|
+
icon: meta.icon ?? 'ph--circle--regular',
|
|
79
|
+
},
|
|
80
|
+
})),
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
id: `${SETTINGS_KEY}:custom-plugins`,
|
|
84
|
+
type: 'collection',
|
|
85
|
+
properties: {
|
|
86
|
+
label: ['custom plugins label', { ns: SETTINGS_PLUGIN }],
|
|
87
|
+
icon: 'ph--squares-four--regular',
|
|
88
|
+
role: 'branch',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
createExtension({
|
|
95
|
+
id: `${SETTINGS_PLUGIN}/custom-plugins`,
|
|
96
|
+
filter: (node): node is Node<null> => node.id === `${SETTINGS_KEY}:custom-plugins`,
|
|
97
|
+
connector: () => {
|
|
98
|
+
const manager = context.requestCapability(Capabilities.PluginManager);
|
|
99
|
+
const [settingsStore] = context.requestCapabilities(Capabilities.SettingsStore);
|
|
100
|
+
return manager.plugins
|
|
101
|
+
.filter((plugin) => !manager.core.includes(plugin.meta.id))
|
|
102
|
+
.map((plugin): [PluginMeta, SettingsStore<SettingsValue>] | null => {
|
|
103
|
+
const settings = settingsStore?.getStore(plugin.meta.id);
|
|
104
|
+
if (!settings) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return [plugin.meta, settings];
|
|
109
|
+
})
|
|
110
|
+
.filter(nonNullable)
|
|
111
|
+
.map(([meta, settings]) => ({
|
|
112
|
+
id: `${SETTINGS_KEY}:${meta.id.replaceAll('/', ':')}`,
|
|
113
|
+
type: 'category',
|
|
114
|
+
data: settings,
|
|
115
|
+
properties: {
|
|
116
|
+
label: meta.name ?? meta.id,
|
|
117
|
+
icon: meta.icon ?? 'ph--circle--regular',
|
|
118
|
+
},
|
|
119
|
+
}));
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
]);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { pipe } from 'effect';
|
|
6
|
+
|
|
7
|
+
import { SETTINGS_ID, SETTINGS_KEY, SettingsAction } from './actions';
|
|
8
|
+
import { Capabilities, LayoutAction } from '../common';
|
|
9
|
+
import { contributes } from '../core';
|
|
10
|
+
import { createResolver, createIntent, chain } from '../plugin-intent';
|
|
11
|
+
|
|
12
|
+
export default () =>
|
|
13
|
+
contributes(
|
|
14
|
+
Capabilities.IntentResolver,
|
|
15
|
+
createResolver({
|
|
16
|
+
intent: SettingsAction.Open,
|
|
17
|
+
resolve: ({ plugin }) => {
|
|
18
|
+
return {
|
|
19
|
+
intents: [
|
|
20
|
+
pipe(
|
|
21
|
+
createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: SETTINGS_ID }),
|
|
22
|
+
chain(LayoutAction.Open, { part: 'main', subject: [`${SETTINGS_KEY}:${plugin.replaceAll('/', ':')}`] }),
|
|
23
|
+
),
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { RootSettingsStore } from '@dxos/local-storage';
|
|
6
|
+
|
|
7
|
+
import { Capabilities } from '../common';
|
|
8
|
+
import { contributes, type PluginsContext } from '../core';
|
|
9
|
+
|
|
10
|
+
export default (context: PluginsContext) => {
|
|
11
|
+
// TODO(wittjosiah): This should subscribe to capabilities and create stores for newly added settings objects.
|
|
12
|
+
const allSettings = context.requestCapabilities(Capabilities.Settings);
|
|
13
|
+
const settingsStore = new RootSettingsStore();
|
|
14
|
+
|
|
15
|
+
allSettings.forEach((setting) => {
|
|
16
|
+
settingsStore.createStore(setting as any);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return contributes(Capabilities.SettingsStore, settingsStore);
|
|
20
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { SETTINGS_PLUGIN } from './actions';
|
|
6
|
+
|
|
7
|
+
export default [
|
|
8
|
+
{
|
|
9
|
+
'en-US': {
|
|
10
|
+
[SETTINGS_PLUGIN]: {
|
|
11
|
+
'open settings label': 'Open settings',
|
|
12
|
+
'app settings label': 'Settings',
|
|
13
|
+
'custom plugins label': 'Plugins',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
];
|
|
@@ -7,9 +7,9 @@ import { type Context, createContext, useContext, type Provider, useEffect } fro
|
|
|
7
7
|
import { raise } from '@dxos/debug';
|
|
8
8
|
import { pick } from '@dxos/util';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { usePluginManager } from './PluginManagerProvider';
|
|
11
11
|
import { Capabilities } from '../common';
|
|
12
|
-
import {
|
|
12
|
+
import { type AnyIntentResolver, type IntentContext } from '../plugin-intent';
|
|
13
13
|
|
|
14
14
|
const IntentContext: Context<IntentContext | undefined> = createContext<IntentContext | undefined>(undefined);
|
|
15
15
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxos-theme';
|
|
6
|
+
|
|
7
|
+
import React, { useCallback, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { faker } from '@dxos/random';
|
|
10
|
+
import { Button, List, ListItem } from '@dxos/react-ui';
|
|
11
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
12
|
+
|
|
13
|
+
import { PluginManagerProvider, usePluginManager } from './PluginManagerProvider';
|
|
14
|
+
import { Surface, useSurfaces } from './Surface';
|
|
15
|
+
import { Capabilities, createSurface } from '../common';
|
|
16
|
+
import { type PluginManager } from '../core';
|
|
17
|
+
import { setupPluginManager } from '../testing';
|
|
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 Story = () => {
|
|
27
|
+
const manager = usePluginManager();
|
|
28
|
+
const surfaces = useSurfaces();
|
|
29
|
+
const [picked, setPicked] = useState('test');
|
|
30
|
+
|
|
31
|
+
const handleAdd = useCallback(() => {
|
|
32
|
+
const id = `test-${faker.number.int({ min: 0, max: 1_000_000 })}`;
|
|
33
|
+
const backgroundColor = randomColor();
|
|
34
|
+
|
|
35
|
+
manager.context.contributeCapability({
|
|
36
|
+
module: 'test',
|
|
37
|
+
interface: Capabilities.ReactSurface,
|
|
38
|
+
implementation: createSurface({
|
|
39
|
+
id,
|
|
40
|
+
role: id,
|
|
41
|
+
component: () => (
|
|
42
|
+
<div className='flex-1' style={{ backgroundColor }}>
|
|
43
|
+
{id}
|
|
44
|
+
</div>
|
|
45
|
+
),
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
setPicked(id);
|
|
50
|
+
}, [manager]);
|
|
51
|
+
|
|
52
|
+
const handlePick = useCallback(() => {
|
|
53
|
+
setPicked(faker.helpers.arrayElement(surfaces).id);
|
|
54
|
+
}, [surfaces]);
|
|
55
|
+
|
|
56
|
+
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'>
|
|
65
|
+
{surfaces.map((surface) => (
|
|
66
|
+
<ListItem.Root key={surface.id} id={surface.id}>
|
|
67
|
+
<ListItem.Heading classNames='grow pbs-2'>{surface.id}</ListItem.Heading>
|
|
68
|
+
</ListItem.Root>
|
|
69
|
+
))}
|
|
70
|
+
</List>
|
|
71
|
+
</div>
|
|
72
|
+
<div className='flex-1'>
|
|
73
|
+
<Surface role={picked} limit={1} />
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default {
|
|
81
|
+
title: 'sdk/app-framework/Surface',
|
|
82
|
+
render: ({ manager }: { manager: PluginManager }) => {
|
|
83
|
+
return (
|
|
84
|
+
<PluginManagerProvider value={manager}>
|
|
85
|
+
<Story />
|
|
86
|
+
</PluginManagerProvider>
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
// NOTE: Intentionally not using withPluginManager to try to reduce surface area of the story.
|
|
90
|
+
decorators: [withTheme, withLayout({ tooltips: true })],
|
|
91
|
+
args: {
|
|
92
|
+
manager: setupPluginManager(),
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const Default = {};
|
package/src/react/Surface.tsx
CHANGED
|
@@ -5,14 +5,17 @@
|
|
|
5
5
|
import React, { memo, forwardRef, Suspense, useMemo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { useDefaultValue } from '@dxos/react-hooks';
|
|
8
|
-
import {
|
|
8
|
+
import { byPosition } from '@dxos/util';
|
|
9
9
|
|
|
10
10
|
import { ErrorBoundary } from './ErrorBoundary';
|
|
11
11
|
import { useCapabilities } from './useCapabilities';
|
|
12
12
|
import { Capabilities, type SurfaceDefinition, type SurfaceProps } from '../common';
|
|
13
13
|
import { type PluginsContext } from '../core';
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export const useSurfaces = () => {
|
|
16
19
|
const surfaces = useCapabilities(Capabilities.ReactSurface);
|
|
17
20
|
return useMemo(() => surfaces.flat(), [surfaces]);
|
|
18
21
|
};
|
|
@@ -23,7 +26,7 @@ const findCandidates = (surfaces: SurfaceDefinition[], { role, data }: Pick<Surf
|
|
|
23
26
|
Array.isArray(definition.role) ? definition.role.includes(role) : definition.role === role,
|
|
24
27
|
)
|
|
25
28
|
.filter(({ filter }) => (filter ? filter(data ?? {}) : true))
|
|
26
|
-
.toSorted(
|
|
29
|
+
.toSorted(byPosition);
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
/**
|
|
@@ -49,11 +52,9 @@ export const Surface = memo(
|
|
|
49
52
|
const surfaces = useSurfaces();
|
|
50
53
|
const data = useDefaultValue(_data, () => ({}));
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}, [surfaces, role, data, limit]);
|
|
56
|
-
|
|
55
|
+
// NOTE: Memoizing the candidates makes the surface not re-render based on reactivity within data.
|
|
56
|
+
const definitions = findCandidates(surfaces, { role, data });
|
|
57
|
+
const candidates = limit ? definitions.slice(0, limit) : definitions;
|
|
57
58
|
const nodes = candidates.map(({ component: Component, id }) => (
|
|
58
59
|
<Component ref={forwardedRef} key={id} id={id} role={role} data={data} limit={limit} {...rest} />
|
|
59
60
|
));
|
|
@@ -70,3 +71,5 @@ export const Surface = memo(
|
|
|
70
71
|
},
|
|
71
72
|
),
|
|
72
73
|
);
|
|
74
|
+
|
|
75
|
+
Surface.displayName = 'Surface';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useCapability } from './useCapabilities';
|
|
6
|
+
import { Capabilities } from '../common';
|
|
7
|
+
|
|
8
|
+
export const useIntentDispatcher = () => useCapability(Capabilities.IntentDispatcher);
|
|
9
|
+
|
|
10
|
+
export const useAppGraph = () => useCapability(Capabilities.AppGraph);
|
|
11
|
+
|
|
12
|
+
export const useLayout = () => useCapability(Capabilities.Layout);
|
package/src/react/index.ts
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Capabilities } from '../common';
|
|
8
|
+
import { type AnyIntentResolver } from '../plugin-intent';
|
|
9
|
+
import { usePluginManager } from '../react';
|
|
10
|
+
|
|
11
|
+
export const useIntentResolver = (module: string, resolver: AnyIntentResolver) => {
|
|
12
|
+
const manager = usePluginManager();
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
manager.context.contributeCapability({
|
|
15
|
+
module,
|
|
16
|
+
interface: Capabilities.IntentResolver,
|
|
17
|
+
implementation: resolver,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return () => manager.context.removeCapability(Capabilities.IntentResolver, resolver);
|
|
21
|
+
}, [module, resolver]);
|
|
22
|
+
};
|
|
@@ -12,14 +12,14 @@ import { Capabilities, Events } from '../common';
|
|
|
12
12
|
import { type AnyCapability, contributes, defineModule, definePlugin, PluginManager } from '../core';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* @internal
|
|
16
16
|
*/
|
|
17
|
-
export const
|
|
17
|
+
export const setupPluginManager = ({
|
|
18
18
|
capabilities,
|
|
19
19
|
plugins = [],
|
|
20
20
|
core = plugins.map(({ meta }) => meta.id),
|
|
21
21
|
...options
|
|
22
|
-
}: CreateAppOptions & { capabilities?: AnyCapability[] } = {})
|
|
22
|
+
}: CreateAppOptions & { capabilities?: AnyCapability[] } = {}) => {
|
|
23
23
|
const pluginManager = new PluginManager({
|
|
24
24
|
pluginLoader: () => raise(new Error('Not implemented')),
|
|
25
25
|
plugins: [StoryPlugin(), ...plugins],
|
|
@@ -37,6 +37,14 @@ export const withPluginManager = ({
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
return pluginManager;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Wraps a story with a plugin manager.
|
|
45
|
+
*/
|
|
46
|
+
export const withPluginManager = (options: CreateAppOptions & { capabilities?: AnyCapability[] } = {}): Decorator => {
|
|
47
|
+
const pluginManager = setupPluginManager(options);
|
|
40
48
|
const App = createApp({ pluginManager });
|
|
41
49
|
|
|
42
50
|
return (Story, context) => {
|
package/src/worker.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// Entrypoint for using plugins in workers runtimes (e.g. Cloudflare Workers, etc.)
|
|
6
|
+
// Excludes all frontend code & dependencies (e.g. localStorage, React, etc.)
|
|
7
|
+
|
|
8
|
+
export * from './core';
|
|
9
|
+
// NOTE: Common includes browser capabilities but they are types only.
|
|
10
|
+
export * from './common';
|
|
11
|
+
export * from './plugin-intent';
|
package/tsconfig.json
CHANGED
|
@@ -20,9 +20,6 @@
|
|
|
20
20
|
{
|
|
21
21
|
"path": "../../common/async"
|
|
22
22
|
},
|
|
23
|
-
{
|
|
24
|
-
"path": "../../common/context"
|
|
25
|
-
},
|
|
26
23
|
{
|
|
27
24
|
"path": "../../common/debug"
|
|
28
25
|
},
|
|
@@ -35,6 +32,9 @@
|
|
|
35
32
|
{
|
|
36
33
|
"path": "../../common/log"
|
|
37
34
|
},
|
|
35
|
+
{
|
|
36
|
+
"path": "../../common/random"
|
|
37
|
+
},
|
|
38
38
|
{
|
|
39
39
|
"path": "../../common/storybook-utils"
|
|
40
40
|
},
|