@dxos/plugin-board 0.8.4-main.9735255 → 0.8.4-main.abd8ff62ef
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/BoardPlugin-MKXIWHZQ.mjs +50 -0
- package/dist/lib/browser/BoardPlugin-MKXIWHZQ.mjs.map +7 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +19 -60
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +29 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +31 -2
- package/dist/lib/browser/types/index.mjs.map +4 -4
- package/dist/lib/node-esm/BoardPlugin-FQMGBWI6.mjs +51 -0
- package/dist/lib/node-esm/BoardPlugin-FQMGBWI6.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +19 -60
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +30 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +31 -2
- package/dist/lib/node-esm/types/index.mjs.map +4 -4
- package/dist/types/src/BoardPlugin.d.ts +1 -0
- package/dist/types/src/BoardPlugin.d.ts.map +1 -1
- package/dist/types/src/BoardPlugin.test.d.ts +2 -0
- package/dist/types/src/BoardPlugin.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +2 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/BoardContainer/BoardContainer.d.ts +6 -0
- package/dist/types/src/containers/BoardContainer/BoardContainer.d.ts.map +1 -0
- package/dist/types/src/containers/BoardContainer/BoardContainer.stories.d.ts +54 -0
- package/dist/types/src/containers/BoardContainer/BoardContainer.stories.d.ts.map +1 -0
- package/dist/types/src/containers/BoardContainer/index.d.ts +2 -0
- package/dist/types/src/containers/BoardContainer/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +3 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +22 -14
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Board.d.ts +3 -3
- package/dist/types/src/types/Board.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +61 -49
- package/src/BoardPlugin.test.ts +27 -0
- package/src/BoardPlugin.tsx +29 -14
- package/src/capabilities/index.ts +3 -1
- package/src/capabilities/react-surface.tsx +31 -0
- package/src/components/index.ts +0 -2
- package/src/{components → containers/BoardContainer}/BoardContainer.stories.tsx +19 -18
- package/src/{components → containers/BoardContainer}/BoardContainer.tsx +72 -39
- package/src/containers/BoardContainer/index.ts +5 -0
- package/src/containers/index.ts +7 -0
- package/src/index.ts +6 -4
- package/src/meta.ts +1 -1
- package/src/translations.ts +12 -11
- package/src/types/Board.ts +7 -3
- package/dist/lib/browser/chunk-2XGWSTZV.mjs +0 -159
- package/dist/lib/browser/chunk-2XGWSTZV.mjs.map +0 -7
- package/dist/lib/browser/chunk-7VKDDGS7.mjs +0 -36
- package/dist/lib/browser/chunk-7VKDDGS7.mjs.map +0 -7
- package/dist/lib/browser/react-surface-BEYXCLXI.mjs +0 -31
- package/dist/lib/browser/react-surface-BEYXCLXI.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JKPYRS2Z.mjs +0 -161
- package/dist/lib/node-esm/chunk-JKPYRS2Z.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UGVRNKWV.mjs +0 -37
- package/dist/lib/node-esm/chunk-UGVRNKWV.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-ZFKFUBJM.mjs +0 -32
- package/dist/lib/node-esm/react-surface-ZFKFUBJM.mjs.map +0 -7
- package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
- package/dist/types/src/components/BoardContainer.d.ts +0 -6
- package/dist/types/src/components/BoardContainer.d.ts.map +0 -1
- package/dist/types/src/components/BoardContainer.stories.d.ts +0 -45
- package/dist/types/src/components/BoardContainer.stories.d.ts.map +0 -1
- package/src/capabilities/react-surface/index.ts +0 -7
- package/src/capabilities/react-surface/react-surface.tsx +0 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-board",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.abd8ff62ef",
|
|
4
4
|
"description": "Surface plugin for card baords",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -12,82 +12,94 @@
|
|
|
12
12
|
"author": "DXOS.org",
|
|
13
13
|
"sideEffects": true,
|
|
14
14
|
"type": "module",
|
|
15
|
+
"imports": {
|
|
16
|
+
"#plugin": "./src/BoardPlugin.tsx",
|
|
17
|
+
"#capabilities": "./src/capabilities/index.ts",
|
|
18
|
+
"#components": "./src/components/index.ts",
|
|
19
|
+
"#containers": "./src/containers/index.ts",
|
|
20
|
+
"#meta": "./src/meta.ts",
|
|
21
|
+
"#translations": "./src/translations.ts",
|
|
22
|
+
"#types": "./src/types/index.ts"
|
|
23
|
+
},
|
|
15
24
|
"exports": {
|
|
16
25
|
".": {
|
|
26
|
+
"source": "./src/index.ts",
|
|
17
27
|
"browser": "./dist/lib/browser/index.mjs",
|
|
18
28
|
"node": "./dist/lib/node-esm/index.mjs",
|
|
19
|
-
"source": "./src/index.ts",
|
|
20
29
|
"types": "./dist/types/src/index.d.ts"
|
|
21
30
|
},
|
|
31
|
+
"./translations": {
|
|
32
|
+
"source": "./src/translations.ts",
|
|
33
|
+
"types": "./dist/types/src/translations.d.ts",
|
|
34
|
+
"browser": "./dist/lib/browser/translations.mjs",
|
|
35
|
+
"node": "./dist/lib/node-esm/translations.mjs"
|
|
36
|
+
},
|
|
22
37
|
"./types": {
|
|
38
|
+
"source": "./src/types/index.ts",
|
|
23
39
|
"browser": "./dist/lib/browser/types/index.mjs",
|
|
24
40
|
"node": "./dist/lib/node-esm/types/index.mjs",
|
|
25
|
-
"source": "./src/types/index.ts",
|
|
26
41
|
"types": "./dist/types/src/types/index.d.ts"
|
|
27
42
|
}
|
|
28
43
|
},
|
|
29
44
|
"types": "dist/types/src/index.d.ts",
|
|
30
|
-
"typesVersions": {
|
|
31
|
-
"*": {
|
|
32
|
-
"types": [
|
|
33
|
-
"dist/types/src/types/index.d.ts"
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
45
|
"files": [
|
|
38
46
|
"dist",
|
|
39
47
|
"src"
|
|
40
48
|
],
|
|
41
49
|
"dependencies": {
|
|
42
|
-
"effect": "
|
|
43
|
-
"@
|
|
44
|
-
"
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/echo-
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/plugin-
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/plugin-
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/react-
|
|
65
|
-
"@dxos/react-ui
|
|
66
|
-
"@dxos/react-ui-
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
50
|
+
"@effect-atom/atom": "^0.5.1",
|
|
51
|
+
"@effect-atom/atom-react": "^0.5.0",
|
|
52
|
+
"effect": "3.20.0",
|
|
53
|
+
"@dxos/app-framework": "0.8.4-main.abd8ff62ef",
|
|
54
|
+
"@dxos/ai": "0.8.4-main.abd8ff62ef",
|
|
55
|
+
"@dxos/assistant": "0.8.4-main.abd8ff62ef",
|
|
56
|
+
"@dxos/async": "0.8.4-main.abd8ff62ef",
|
|
57
|
+
"@dxos/client": "0.8.4-main.abd8ff62ef",
|
|
58
|
+
"@dxos/compute": "0.8.4-main.abd8ff62ef",
|
|
59
|
+
"@dxos/echo": "0.8.4-main.abd8ff62ef",
|
|
60
|
+
"@dxos/echo-atom": "0.8.4-main.abd8ff62ef",
|
|
61
|
+
"@dxos/echo-react": "0.8.4-main.abd8ff62ef",
|
|
62
|
+
"@dxos/invariant": "0.8.4-main.abd8ff62ef",
|
|
63
|
+
"@dxos/effect": "0.8.4-main.abd8ff62ef",
|
|
64
|
+
"@dxos/log": "0.8.4-main.abd8ff62ef",
|
|
65
|
+
"@dxos/plugin-client": "0.8.4-main.abd8ff62ef",
|
|
66
|
+
"@dxos/app-toolkit": "0.8.4-main.abd8ff62ef",
|
|
67
|
+
"@dxos/plugin-markdown": "0.8.4-main.abd8ff62ef",
|
|
68
|
+
"@dxos/plugin-graph": "0.8.4-main.abd8ff62ef",
|
|
69
|
+
"@dxos/plugin-space": "0.8.4-main.abd8ff62ef",
|
|
70
|
+
"@dxos/random": "0.8.4-main.abd8ff62ef",
|
|
71
|
+
"@dxos/plugin-search": "0.8.4-main.abd8ff62ef",
|
|
72
|
+
"@dxos/react-client": "0.8.4-main.abd8ff62ef",
|
|
73
|
+
"@dxos/react-ui": "0.8.4-main.abd8ff62ef",
|
|
74
|
+
"@dxos/react-ui-attention": "0.8.4-main.abd8ff62ef",
|
|
75
|
+
"@dxos/react-ui-form": "0.8.4-main.abd8ff62ef",
|
|
76
|
+
"@dxos/react-ui-board": "0.8.4-main.abd8ff62ef",
|
|
77
|
+
"@dxos/react-ui-mosaic": "0.8.4-main.abd8ff62ef",
|
|
78
|
+
"@dxos/react-ui-stack": "0.8.4-main.abd8ff62ef",
|
|
79
|
+
"@dxos/schema": "0.8.4-main.abd8ff62ef",
|
|
80
|
+
"@dxos/types": "0.8.4-main.abd8ff62ef",
|
|
81
|
+
"@dxos/util": "0.8.4-main.abd8ff62ef"
|
|
70
82
|
},
|
|
71
83
|
"devDependencies": {
|
|
72
84
|
"@types/react": "~19.2.7",
|
|
73
85
|
"@types/react-dom": "~19.2.3",
|
|
74
86
|
"react": "~19.2.3",
|
|
75
87
|
"react-dom": "~19.2.3",
|
|
76
|
-
"vite": "
|
|
77
|
-
"@dxos/plugin-
|
|
78
|
-
"@dxos/plugin-
|
|
79
|
-
"@dxos/plugin-theme": "0.8.4-main.
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/test-utils": "0.8.4-main.
|
|
83
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
88
|
+
"vite": "^8.0.10",
|
|
89
|
+
"@dxos/plugin-preview": "0.8.4-main.abd8ff62ef",
|
|
90
|
+
"@dxos/plugin-testing": "0.8.4-main.abd8ff62ef",
|
|
91
|
+
"@dxos/plugin-theme": "0.8.4-main.abd8ff62ef",
|
|
92
|
+
"@dxos/storybook-utils": "0.8.4-main.abd8ff62ef",
|
|
93
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.abd8ff62ef",
|
|
94
|
+
"@dxos/test-utils": "0.8.4-main.abd8ff62ef",
|
|
95
|
+
"@dxos/ui-theme": "0.8.4-main.abd8ff62ef"
|
|
84
96
|
},
|
|
85
97
|
"peerDependencies": {
|
|
86
|
-
"effect": "3.
|
|
98
|
+
"effect": "3.20.0",
|
|
87
99
|
"react": "~19.2.3",
|
|
88
100
|
"react-dom": "~19.2.3",
|
|
89
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
90
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
101
|
+
"@dxos/react-ui": "0.8.4-main.abd8ff62ef",
|
|
102
|
+
"@dxos/ui-theme": "0.8.4-main.abd8ff62ef"
|
|
91
103
|
},
|
|
92
104
|
"publishConfig": {
|
|
93
105
|
"access": "public"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { ClientPlugin } from '@dxos/plugin-client';
|
|
8
|
+
import { createComposerTestApp } from '@dxos/plugin-testing/harness';
|
|
9
|
+
|
|
10
|
+
import { BoardPlugin } from '#plugin';
|
|
11
|
+
|
|
12
|
+
import { meta } from './meta';
|
|
13
|
+
|
|
14
|
+
const moduleId = (name: string) => `${meta.id}.module.${name}`;
|
|
15
|
+
|
|
16
|
+
describe('BoardPlugin', () => {
|
|
17
|
+
test('modules activate on the expected events', async ({ expect }) => {
|
|
18
|
+
await using harness = await createComposerTestApp({
|
|
19
|
+
plugins: [ClientPlugin({}), BoardPlugin()],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Modules expected to be active after a normal startup.
|
|
23
|
+
expect(harness.manager.getActive()).toEqual(
|
|
24
|
+
expect.arrayContaining([moduleId('metadata'), moduleId('schema'), moduleId('ReactSurface')]),
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
});
|
package/src/BoardPlugin.tsx
CHANGED
|
@@ -3,30 +3,45 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Option from 'effect/Option';
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
+
import { Plugin } from '@dxos/app-framework';
|
|
9
|
+
import { AppPlugin } from '@dxos/app-toolkit';
|
|
10
|
+
import { Operation } from '@dxos/compute';
|
|
11
|
+
import { Annotation } from '@dxos/echo';
|
|
12
|
+
import { SpaceOperation } from '@dxos/plugin-space/operations';
|
|
8
13
|
import { type CreateObject } from '@dxos/plugin-space/types';
|
|
9
|
-
import { translations as boardTranslations } from '@dxos/react-ui-board';
|
|
14
|
+
import { translations as boardTranslations } from '@dxos/react-ui-board/translations';
|
|
10
15
|
|
|
11
|
-
import { ReactSurface } from '
|
|
12
|
-
import { meta } from '
|
|
13
|
-
import { translations } from '
|
|
14
|
-
import { Board } from '
|
|
16
|
+
import { ReactSurface } from '#capabilities';
|
|
17
|
+
import { meta } from '#meta';
|
|
18
|
+
import { translations } from '#translations';
|
|
19
|
+
import { Board } from '#types';
|
|
15
20
|
|
|
16
21
|
export const BoardPlugin = Plugin.define(meta).pipe(
|
|
17
|
-
|
|
18
|
-
Common.Plugin.addMetadataModule({
|
|
22
|
+
AppPlugin.addMetadataModule({
|
|
19
23
|
metadata: {
|
|
20
24
|
id: Board.Board.typename,
|
|
21
25
|
metadata: {
|
|
22
|
-
icon:
|
|
23
|
-
iconHue: '
|
|
24
|
-
createObject: ((props
|
|
25
|
-
|
|
26
|
+
icon: Annotation.IconAnnotation.get(Board.Board).pipe(Option.getOrThrow).icon,
|
|
27
|
+
iconHue: Annotation.IconAnnotation.get(Board.Board).pipe(Option.getOrThrow).hue ?? 'white',
|
|
28
|
+
createObject: ((props, options) =>
|
|
29
|
+
Effect.gen(function* () {
|
|
30
|
+
const object = Board.makeBoard(props);
|
|
31
|
+
return yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
32
|
+
object,
|
|
33
|
+
target: options.target,
|
|
34
|
+
hidden: true,
|
|
35
|
+
targetNodeId: options.targetNodeId,
|
|
36
|
+
});
|
|
37
|
+
})) satisfies CreateObject,
|
|
26
38
|
},
|
|
27
39
|
},
|
|
28
40
|
}),
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
AppPlugin.addSchemaModule({ schema: [Board.Board] }),
|
|
42
|
+
AppPlugin.addSurfaceModule({ activate: ReactSurface }),
|
|
43
|
+
AppPlugin.addTranslationsModule({ translations: [...translations, ...boardTranslations] }),
|
|
31
44
|
Plugin.make,
|
|
32
45
|
);
|
|
46
|
+
|
|
47
|
+
export default BoardPlugin;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
9
|
+
import { Surface } from '@dxos/app-framework/ui';
|
|
10
|
+
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
11
|
+
|
|
12
|
+
import { BoardContainer } from '#containers';
|
|
13
|
+
import { Board } from '#types';
|
|
14
|
+
|
|
15
|
+
export default Capability.makeModule(() =>
|
|
16
|
+
Effect.succeed(
|
|
17
|
+
Capability.contributes(Capabilities.ReactSurface, [
|
|
18
|
+
Surface.create({
|
|
19
|
+
id: 'root',
|
|
20
|
+
// TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.
|
|
21
|
+
filter: AppSurface.oneOf(
|
|
22
|
+
AppSurface.object(AppSurface.Article, Board.Board),
|
|
23
|
+
AppSurface.object(AppSurface.Section, Board.Board),
|
|
24
|
+
),
|
|
25
|
+
component: ({ role, data }) => (
|
|
26
|
+
<BoardContainer role={role} subject={data.subject} attendableId={data.attendableId} />
|
|
27
|
+
),
|
|
28
|
+
}),
|
|
29
|
+
]),
|
|
30
|
+
),
|
|
31
|
+
);
|
package/src/components/index.ts
CHANGED
|
@@ -9,20 +9,21 @@ import React, { useEffect, useState } from 'react';
|
|
|
9
9
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
10
10
|
import { Obj } from '@dxos/echo';
|
|
11
11
|
import { ClientPlugin } from '@dxos/plugin-client';
|
|
12
|
+
import { initializeIdentity } from '@dxos/plugin-client/testing';
|
|
12
13
|
import { PreviewPlugin } from '@dxos/plugin-preview';
|
|
13
14
|
import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
|
|
14
|
-
import {
|
|
15
|
+
import { random } from '@dxos/random';
|
|
15
16
|
import { Filter, Ref, useQuery, useSpaces } from '@dxos/react-client/echo';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
17
|
+
import { translations as stackTranslations } from '@dxos/react-ui-stack/translations';
|
|
18
|
+
import { withLayout } from '@dxos/react-ui/testing';
|
|
18
19
|
import { Organization, Person } from '@dxos/types';
|
|
19
20
|
|
|
20
|
-
import { translations } from '
|
|
21
|
-
import { Board } from '
|
|
21
|
+
import { translations } from '#translations';
|
|
22
|
+
import { Board } from '#types';
|
|
22
23
|
|
|
23
24
|
import { BoardContainer } from './BoardContainer';
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
random.seed(0);
|
|
26
27
|
|
|
27
28
|
const createBoard = () =>
|
|
28
29
|
Obj.make(Board.Board, {
|
|
@@ -36,12 +37,12 @@ const createBoard = () =>
|
|
|
36
37
|
|
|
37
38
|
const createOrg = () =>
|
|
38
39
|
Obj.make(Organization.Organization, {
|
|
39
|
-
name:
|
|
40
|
-
description:
|
|
41
|
-
image:
|
|
42
|
-
website:
|
|
40
|
+
name: random.commerce.productName(),
|
|
41
|
+
description: random.lorem.paragraph(),
|
|
42
|
+
image: random.image.url(),
|
|
43
|
+
website: random.internet.url(),
|
|
43
44
|
// TODO(burdon): Fix.
|
|
44
|
-
// status:
|
|
45
|
+
// status: random.helpers.arrayElement(Organization.StatusOptions).id,
|
|
45
46
|
});
|
|
46
47
|
|
|
47
48
|
const DefaultStory = () => {
|
|
@@ -61,7 +62,7 @@ const DefaultStory = () => {
|
|
|
61
62
|
return null;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
return <BoardContainer role='board' subject={board} />;
|
|
65
|
+
return <BoardContainer role='board' subject={board} attendableId='test' />;
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
//
|
|
@@ -69,10 +70,10 @@ const DefaultStory = () => {
|
|
|
69
70
|
//
|
|
70
71
|
|
|
71
72
|
const meta = {
|
|
72
|
-
title: 'plugins/plugin-board/
|
|
73
|
+
title: 'plugins/plugin-board/containers/BoardContainer',
|
|
73
74
|
render: DefaultStory,
|
|
74
75
|
decorators: [
|
|
75
|
-
|
|
76
|
+
withLayout({ layout: 'fullscreen' }),
|
|
76
77
|
withPluginManager({
|
|
77
78
|
plugins: [
|
|
78
79
|
...corePlugins(),
|
|
@@ -80,18 +81,18 @@ const meta = {
|
|
|
80
81
|
types: [Organization.Organization, Person.Person, Board.Board],
|
|
81
82
|
onClientInitialized: ({ client }) =>
|
|
82
83
|
Effect.gen(function* () {
|
|
83
|
-
yield*
|
|
84
|
+
yield* initializeIdentity(client);
|
|
84
85
|
const space = yield* Effect.promise(() => client.spaces.create());
|
|
85
86
|
yield* Effect.promise(() => space.waitUntilReady());
|
|
86
87
|
const board = space.db.add(createBoard());
|
|
87
88
|
|
|
88
|
-
Obj.
|
|
89
|
+
Obj.update(board, (board) => {
|
|
89
90
|
// Add some sample items
|
|
90
91
|
Array.from({ length: 10 }).map(() => {
|
|
91
92
|
const org = createOrg();
|
|
92
93
|
space.db.add(org);
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
board.items.push(Ref.make(org));
|
|
95
|
+
board.layout.cells[org.id] = {
|
|
95
96
|
x: Math.floor(Math.random() * 5) - 2,
|
|
96
97
|
y: Math.floor(Math.random() * 5) - 2,
|
|
97
98
|
width: 1,
|
|
@@ -2,20 +2,25 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
6
|
+
import * as Atom from '@effect-atom/atom/Atom';
|
|
5
7
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
6
8
|
|
|
7
|
-
import { Surface
|
|
9
|
+
import { Surface } from '@dxos/app-framework/ui';
|
|
10
|
+
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
8
11
|
import { Filter, Obj, Ref } from '@dxos/echo';
|
|
9
|
-
import {
|
|
12
|
+
import { AtomObj } from '@dxos/echo-atom';
|
|
13
|
+
import { useObject } from '@dxos/echo-react';
|
|
10
14
|
import { invariant } from '@dxos/invariant';
|
|
15
|
+
import { Markdown } from '@dxos/plugin-markdown/types';
|
|
11
16
|
import { useQuery } from '@dxos/react-client/echo';
|
|
17
|
+
import { Panel } from '@dxos/react-ui';
|
|
12
18
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
13
19
|
import { Board, type BoardController, type BoardRootProps, type Position } from '@dxos/react-ui-board';
|
|
14
20
|
import { ObjectPicker, type ObjectPickerContentProps } from '@dxos/react-ui-form';
|
|
15
|
-
import { Layout } from '@dxos/react-ui-mosaic';
|
|
16
21
|
import { isNonNullable } from '@dxos/util';
|
|
17
22
|
|
|
18
|
-
import { type Board as BoardType } from '
|
|
23
|
+
import { type Board as BoardType } from '#types';
|
|
19
24
|
|
|
20
25
|
const DEFAULT_POSITION = { x: 0, y: 0 } satisfies Position;
|
|
21
26
|
|
|
@@ -23,18 +28,32 @@ type PickerState = {
|
|
|
23
28
|
position: Position;
|
|
24
29
|
};
|
|
25
30
|
|
|
26
|
-
export type BoardContainerProps =
|
|
31
|
+
export type BoardContainerProps = AppSurface.ObjectArticleProps<BoardType.Board>;
|
|
27
32
|
|
|
28
|
-
export const BoardContainer = ({ role, subject: board }: BoardContainerProps) => {
|
|
29
|
-
const
|
|
33
|
+
export const BoardContainer = ({ role, subject: board, attendableId }: BoardContainerProps) => {
|
|
34
|
+
const { hasAttention } = useAttention(attendableId);
|
|
35
|
+
const db = Obj.getDatabase(board);
|
|
30
36
|
const [boardItems] = useObject(board, 'items');
|
|
31
|
-
const
|
|
37
|
+
const itemsAtom = useMemo(
|
|
38
|
+
() =>
|
|
39
|
+
Atom.make((get) => {
|
|
40
|
+
const result: Obj.Unknown[] = [];
|
|
41
|
+
for (const ref of boardItems ?? []) {
|
|
42
|
+
const obj = get(AtomObj.makeWithReactive(ref));
|
|
43
|
+
if (obj) {
|
|
44
|
+
result.push(obj);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}),
|
|
49
|
+
[boardItems],
|
|
50
|
+
);
|
|
51
|
+
const items = useAtomValue(itemsAtom);
|
|
52
|
+
|
|
53
|
+
const controller = useRef<BoardController>(null);
|
|
32
54
|
const addTriggerRef = useRef<HTMLButtonElement | null>(null);
|
|
33
55
|
const [pickerState, setPickerState] = useState<PickerState | null>(null);
|
|
34
|
-
const attendableId = Obj.getDXN(board).toString();
|
|
35
|
-
const { hasAttention } = useAttention(attendableId);
|
|
36
56
|
|
|
37
|
-
const db = Obj.getDatabase(board);
|
|
38
57
|
// TODO(burdon): Use search.
|
|
39
58
|
const objects = useQuery(db, Filter.everything());
|
|
40
59
|
const options = useMemo<ObjectPickerContentProps['options']>(
|
|
@@ -57,13 +76,22 @@ export const BoardContainer = ({ role, subject: board }: BoardContainerProps) =>
|
|
|
57
76
|
);
|
|
58
77
|
|
|
59
78
|
const handleAdd = useCallback<NonNullable<BoardRootProps['onAdd']>>(
|
|
60
|
-
async (anchor, position
|
|
79
|
+
async (anchor, position) => {
|
|
61
80
|
const db = Obj.getDatabase(board);
|
|
62
81
|
invariant(db);
|
|
82
|
+
// Grid backdrop "+" supplies a position → create a new Markdown document directly.
|
|
83
|
+
// Toolbar "+" omits position → fall back to the picker over existing objects.
|
|
84
|
+
if (position) {
|
|
85
|
+
const doc = db.add(Markdown.make());
|
|
86
|
+
Obj.update(board, (board) => {
|
|
87
|
+
board.items.push(Ref.make(doc));
|
|
88
|
+
board.layout.cells[doc.id.toString()] = position;
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
63
93
|
addTriggerRef.current = anchor;
|
|
64
|
-
setPickerState({
|
|
65
|
-
position,
|
|
66
|
-
});
|
|
94
|
+
setPickerState({ position: DEFAULT_POSITION });
|
|
67
95
|
},
|
|
68
96
|
[board],
|
|
69
97
|
);
|
|
@@ -73,11 +101,11 @@ export const BoardContainer = ({ role, subject: board }: BoardContainerProps) =>
|
|
|
73
101
|
(id) => {
|
|
74
102
|
// TODO(burdon): Impl. DXN.equals and pass in DXN from `id`.
|
|
75
103
|
const idx = board.items.findIndex((ref) => ref.dxn.asEchoDXN()?.echoId === id);
|
|
76
|
-
Obj.
|
|
104
|
+
Obj.update(board, (board) => {
|
|
77
105
|
if (idx !== -1) {
|
|
78
|
-
|
|
106
|
+
board.items.splice(idx, 1);
|
|
79
107
|
}
|
|
80
|
-
delete
|
|
108
|
+
delete board.layout.cells[id];
|
|
81
109
|
});
|
|
82
110
|
},
|
|
83
111
|
[board],
|
|
@@ -86,8 +114,8 @@ export const BoardContainer = ({ role, subject: board }: BoardContainerProps) =>
|
|
|
86
114
|
const handleMove = useCallback<NonNullable<BoardRootProps['onMove']>>(
|
|
87
115
|
(id, position) => {
|
|
88
116
|
const layout = board.layout.cells[id];
|
|
89
|
-
Obj.
|
|
90
|
-
|
|
117
|
+
Obj.update(board, (board) => {
|
|
118
|
+
board.layout.cells[id] = { ...layout, ...position };
|
|
91
119
|
});
|
|
92
120
|
},
|
|
93
121
|
[board],
|
|
@@ -106,11 +134,11 @@ export const BoardContainer = ({ role, subject: board }: BoardContainerProps) =>
|
|
|
106
134
|
}
|
|
107
135
|
|
|
108
136
|
// Create a reference to the selected object and add it to the board.
|
|
109
|
-
Obj.
|
|
110
|
-
|
|
137
|
+
Obj.update(board, (board) => {
|
|
138
|
+
board.items.push(Ref.make(selectedObject));
|
|
111
139
|
|
|
112
140
|
// Set the layout position for the new item.
|
|
113
|
-
|
|
141
|
+
board.layout.cells[selectedObject.id.toString()] = pickerState.position;
|
|
114
142
|
});
|
|
115
143
|
|
|
116
144
|
// Close the picker.
|
|
@@ -127,22 +155,27 @@ export const BoardContainer = ({ role, subject: board }: BoardContainerProps) =>
|
|
|
127
155
|
setPickerState(nextOpen ? { position: DEFAULT_POSITION } : null);
|
|
128
156
|
}}
|
|
129
157
|
>
|
|
130
|
-
<
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
<Panel.Root role={role}>
|
|
159
|
+
<Panel.Toolbar asChild>
|
|
160
|
+
<Board.Toolbar disabled={!hasAttention} />
|
|
161
|
+
</Panel.Toolbar>
|
|
162
|
+
<Panel.Content asChild>
|
|
163
|
+
<Board.Container>
|
|
164
|
+
<Board.Viewport classNames='border-none'>
|
|
165
|
+
<Board.Backdrop />
|
|
166
|
+
<Board.Content>
|
|
167
|
+
{items?.map((item, index) => (
|
|
168
|
+
<Board.Cell item={item} key={index} layout={board.layout?.cells[item.id] ?? { x: 0, y: 0 }}>
|
|
169
|
+
{/* `editable` opts the cell into the in-place editor variant — surfaces that don't recognize the flag fall back to the read-only card. */}
|
|
170
|
+
<Surface.Surface type={AppSurface.Card} data={{ subject: item, editable: true }} limit={1} />
|
|
171
|
+
</Board.Cell>
|
|
172
|
+
))}
|
|
173
|
+
</Board.Content>
|
|
174
|
+
</Board.Viewport>
|
|
175
|
+
</Board.Container>
|
|
176
|
+
</Panel.Content>
|
|
177
|
+
</Panel.Root>
|
|
178
|
+
<ObjectPicker.Content options={options} onSelect={handleSelect} classNames='dx-card-popover-width' />
|
|
146
179
|
<ObjectPicker.VirtualTrigger virtualRef={addTriggerRef} />
|
|
147
180
|
</ObjectPicker.Root>
|
|
148
181
|
</Board.Root>
|
package/src/index.ts
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { Plugin } from '@dxos/app-framework';
|
|
6
|
+
|
|
7
|
+
import { meta } from './meta';
|
|
8
8
|
|
|
9
|
-
export
|
|
9
|
+
export const BoardPlugin = Plugin.lazy(meta, () => import('./BoardPlugin'));
|
|
10
|
+
|
|
11
|
+
export * from './meta';
|
package/src/meta.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type Plugin } from '@dxos/app-framework';
|
|
|
6
6
|
import { trim } from '@dxos/util';
|
|
7
7
|
|
|
8
8
|
export const meta: Plugin.Meta = {
|
|
9
|
-
id: 'dxos.
|
|
9
|
+
id: 'org.dxos.plugin.board',
|
|
10
10
|
name: 'Board',
|
|
11
11
|
description: trim`
|
|
12
12
|
Infinite canvas workspace that combines sticky notes, media, and whiteboarding tools.
|
package/src/translations.ts
CHANGED
|
@@ -4,24 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Resource } from '@dxos/react-ui';
|
|
6
6
|
|
|
7
|
-
import { meta } from '
|
|
8
|
-
import { Board } from '
|
|
7
|
+
import { meta } from '#meta';
|
|
8
|
+
import { Board } from '#types';
|
|
9
9
|
|
|
10
10
|
export const translations = [
|
|
11
11
|
{
|
|
12
12
|
'en-US': {
|
|
13
13
|
[Board.Board.typename]: {
|
|
14
|
-
'typename
|
|
15
|
-
'typename
|
|
16
|
-
'typename
|
|
17
|
-
'typename
|
|
18
|
-
'object
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'object
|
|
14
|
+
'typename.label': 'Board',
|
|
15
|
+
'typename.label_zero': 'Boards',
|
|
16
|
+
'typename.label_one': 'Board',
|
|
17
|
+
'typename.label_other': 'Boards',
|
|
18
|
+
'object-name.placeholder': 'New board',
|
|
19
|
+
'add-object.label': 'Add board',
|
|
20
|
+
'rename-object.label': 'Rename board',
|
|
21
|
+
'delete-object.label': 'Delete board',
|
|
22
|
+
'object-deleted.label': 'Board deleted',
|
|
22
23
|
},
|
|
23
24
|
[meta.id]: {
|
|
24
|
-
'plugin
|
|
25
|
+
'plugin.name': 'Board',
|
|
25
26
|
},
|
|
26
27
|
},
|
|
27
28
|
},
|