@dxos/plugin-board 0.8.4-main.2e9d522 → 0.8.4-main.548089c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/chunk-6IYOP7JD.mjs +64 -0
- package/dist/lib/browser/chunk-6IYOP7JD.mjs.map +7 -0
- package/dist/lib/browser/chunk-UDI6JPP5.mjs +143 -0
- package/dist/lib/browser/chunk-UDI6JPP5.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +53 -49
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-TDOZP647.mjs → intent-resolver-MGJCQT3N.mjs} +7 -7
- package/dist/lib/browser/{intent-resolver-TDOZP647.mjs.map → intent-resolver-MGJCQT3N.mjs.map} +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-surface-PBKZGBFJ.mjs +30 -0
- package/dist/lib/browser/react-surface-PBKZGBFJ.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +3 -3
- package/dist/lib/node-esm/chunk-LJPQ2ELJ.mjs +145 -0
- package/dist/lib/node-esm/chunk-LJPQ2ELJ.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-WFLKZNL3.mjs +65 -0
- package/dist/lib/node-esm/chunk-WFLKZNL3.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +53 -49
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-IHQWKJNT.mjs → intent-resolver-TV2AARM7.mjs} +7 -7
- package/dist/lib/node-esm/{intent-resolver-IHQWKJNT.mjs.map → intent-resolver-TV2AARM7.mjs.map} +1 -1
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/react-surface-NELFNJ6M.mjs +31 -0
- package/dist/lib/node-esm/react-surface-NELFNJ6M.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +3 -3
- package/dist/types/src/BoardPlugin.d.ts +1 -1
- package/dist/types/src/BoardPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/BoardContainer.d.ts +2 -2
- package/dist/types/src/components/BoardContainer.d.ts.map +1 -1
- package/dist/types/src/components/BoardContainer.stories.d.ts +42 -5
- package/dist/types/src/components/BoardContainer.stories.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/types/Board.d.ts +88 -0
- package/dist/types/src/types/Board.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +45 -42
- package/src/BoardPlugin.tsx +42 -43
- package/src/capabilities/react-surface.tsx +1 -1
- package/src/components/BoardContainer.stories.tsx +33 -50
- package/src/components/BoardContainer.tsx +95 -53
- package/src/index.ts +2 -0
- package/src/meta.ts +6 -2
- package/src/types/Board.ts +47 -0
- package/src/types/index.ts +1 -1
- package/dist/lib/browser/chunk-TDV6SJ64.mjs +0 -46
- package/dist/lib/browser/chunk-TDV6SJ64.mjs.map +0 -7
- package/dist/lib/browser/react-surface-XFSXU2JJ.mjs +0 -143
- package/dist/lib/browser/react-surface-XFSXU2JJ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-K6CHLZYU.mjs +0 -48
- package/dist/lib/node-esm/chunk-K6CHLZYU.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-ZHPQBZWO.mjs +0 -144
- package/dist/lib/node-esm/react-surface-ZHPQBZWO.mjs.map +0 -7
- package/dist/types/src/types/schema.d.ts +0 -65
- package/dist/types/src/types/schema.d.ts.map +0 -1
- package/src/types/schema.ts +0 -45
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.548089c",
|
|
4
4
|
"description": "Surface plugin for card baords",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -10,11 +10,13 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
+
"source": "./src/index.ts",
|
|
13
14
|
"types": "./dist/types/src/index.d.ts",
|
|
14
15
|
"browser": "./dist/lib/browser/index.mjs",
|
|
15
16
|
"node": "./dist/lib/node-esm/index.mjs"
|
|
16
17
|
},
|
|
17
18
|
"./types": {
|
|
19
|
+
"source": "./src/types/index.ts",
|
|
18
20
|
"types": "./dist/types/src/types/index.d.ts",
|
|
19
21
|
"browser": "./dist/lib/browser/types/index.mjs",
|
|
20
22
|
"node": "./dist/lib/node-esm/types/index.mjs"
|
|
@@ -34,52 +36,53 @@
|
|
|
34
36
|
],
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"@preact-signals/safe-react": "^0.9.0",
|
|
37
|
-
"@preact/signals-core": "^1.
|
|
38
|
-
"@preact/signals-react": "^3.
|
|
39
|
-
"effect": "3.
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/assistant": "0.8.4-main.
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/client": "0.8.4-main.
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/echo
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/invariant": "0.8.4-main.
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/plugin-
|
|
51
|
-
"@dxos/plugin-search": "0.8.4-main.
|
|
52
|
-
"@dxos/plugin-space": "0.8.4-main.
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/react-ui-
|
|
58
|
-
"@dxos/react-ui-form": "0.8.4-main.
|
|
59
|
-
"@dxos/react-ui-stack": "0.8.4-main.
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/
|
|
39
|
+
"@preact/signals-core": "^1.12.1",
|
|
40
|
+
"@preact/signals-react": "^3.3.0",
|
|
41
|
+
"effect": "3.18.3",
|
|
42
|
+
"@dxos/ai": "0.8.4-main.548089c",
|
|
43
|
+
"@dxos/assistant": "0.8.4-main.548089c",
|
|
44
|
+
"@dxos/app-framework": "0.8.4-main.548089c",
|
|
45
|
+
"@dxos/async": "0.8.4-main.548089c",
|
|
46
|
+
"@dxos/client": "0.8.4-main.548089c",
|
|
47
|
+
"@dxos/blueprints": "0.8.4-main.548089c",
|
|
48
|
+
"@dxos/echo": "0.8.4-main.548089c",
|
|
49
|
+
"@dxos/log": "0.8.4-main.548089c",
|
|
50
|
+
"@dxos/invariant": "0.8.4-main.548089c",
|
|
51
|
+
"@dxos/plugin-graph": "0.8.4-main.548089c",
|
|
52
|
+
"@dxos/plugin-client": "0.8.4-main.548089c",
|
|
53
|
+
"@dxos/plugin-search": "0.8.4-main.548089c",
|
|
54
|
+
"@dxos/plugin-space": "0.8.4-main.548089c",
|
|
55
|
+
"@dxos/react-client": "0.8.4-main.548089c",
|
|
56
|
+
"@dxos/random": "0.8.4-main.548089c",
|
|
57
|
+
"@dxos/effect": "0.8.4-main.548089c",
|
|
58
|
+
"@dxos/react-ui": "0.8.4-main.548089c",
|
|
59
|
+
"@dxos/react-ui-attention": "0.8.4-main.548089c",
|
|
60
|
+
"@dxos/react-ui-form": "0.8.4-main.548089c",
|
|
61
|
+
"@dxos/react-ui-stack": "0.8.4-main.548089c",
|
|
62
|
+
"@dxos/types": "0.8.4-main.548089c",
|
|
63
|
+
"@dxos/schema": "0.8.4-main.548089c",
|
|
64
|
+
"@dxos/util": "0.8.4-main.548089c",
|
|
65
|
+
"@dxos/react-ui-board": "0.8.4-main.548089c"
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
65
|
-
"@types/react": "~
|
|
66
|
-
"@types/react-dom": "~
|
|
67
|
-
"react": "~
|
|
68
|
-
"react-dom": "~
|
|
69
|
-
"vite": "
|
|
70
|
-
"@dxos/plugin-preview": "0.8.4-main.
|
|
71
|
-
"@dxos/plugin-theme": "0.8.4-main.
|
|
72
|
-
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
68
|
+
"@types/react": "~19.2.2",
|
|
69
|
+
"@types/react-dom": "~19.2.2",
|
|
70
|
+
"react": "~19.2.0",
|
|
71
|
+
"react-dom": "~19.2.0",
|
|
72
|
+
"vite": "7.1.9",
|
|
73
|
+
"@dxos/plugin-preview": "0.8.4-main.548089c",
|
|
74
|
+
"@dxos/plugin-theme": "0.8.4-main.548089c",
|
|
75
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.548089c",
|
|
76
|
+
"@dxos/test-utils": "0.8.4-main.548089c",
|
|
77
|
+
"@dxos/react-ui-theme": "0.8.4-main.548089c",
|
|
78
|
+
"@dxos/storybook-utils": "0.8.4-main.548089c"
|
|
76
79
|
},
|
|
77
80
|
"peerDependencies": {
|
|
78
81
|
"effect": "^3.13.3",
|
|
79
|
-
"react": "
|
|
80
|
-
"react-dom": "
|
|
81
|
-
"@dxos/react-ui
|
|
82
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
82
|
+
"react": "^19.0.0",
|
|
83
|
+
"react-dom": "^19.0.0",
|
|
84
|
+
"@dxos/react-ui": "0.8.4-main.548089c",
|
|
85
|
+
"@dxos/react-ui-theme": "0.8.4-main.548089c"
|
|
83
86
|
},
|
|
84
87
|
"publishConfig": {
|
|
85
88
|
"access": "public"
|
package/src/BoardPlugin.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Capabilities, contributes, createIntent, defineModule, definePlugin
|
|
5
|
+
import { Capabilities, Events, contributes, createIntent, defineModule, definePlugin } from '@dxos/app-framework';
|
|
6
6
|
import { ClientEvents } from '@dxos/plugin-client';
|
|
7
7
|
import { SpaceCapabilities } from '@dxos/plugin-space';
|
|
8
8
|
import { defineObjectForm } from '@dxos/plugin-space/types';
|
|
@@ -13,46 +13,45 @@ import { meta } from './meta';
|
|
|
13
13
|
import { translations } from './translations';
|
|
14
14
|
import { Board } from './types';
|
|
15
15
|
|
|
16
|
-
export const BoardPlugin = () =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
export const BoardPlugin = definePlugin(meta, () => [
|
|
17
|
+
defineModule({
|
|
18
|
+
id: `${meta.id}/module/translations`,
|
|
19
|
+
activatesOn: Events.SetupTranslations,
|
|
20
|
+
activate: () => contributes(Capabilities.Translations, [...translations, ...boardTranslations]),
|
|
21
|
+
}),
|
|
22
|
+
defineModule({
|
|
23
|
+
id: `${meta.id}/module/metadata`,
|
|
24
|
+
activatesOn: Events.SetupMetadata,
|
|
25
|
+
activate: () =>
|
|
26
|
+
// TODO(burdon): "Metadata" here seems non-descriptive; is this specifically for the type? ObjectMetadata?
|
|
27
|
+
contributes(Capabilities.Metadata, {
|
|
28
|
+
id: Board.Board.typename,
|
|
29
|
+
metadata: {
|
|
30
|
+
icon: 'ph--squares-four--regular',
|
|
31
|
+
iconHue: 'green',
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
}),
|
|
35
|
+
defineModule({
|
|
36
|
+
id: `${meta.id}/module/object-form`,
|
|
37
|
+
activatesOn: ClientEvents.SetupSchema,
|
|
38
|
+
activate: () =>
|
|
39
|
+
contributes(
|
|
40
|
+
SpaceCapabilities.ObjectForm,
|
|
41
|
+
defineObjectForm({
|
|
42
|
+
objectSchema: Board.Board,
|
|
43
|
+
getIntent: () => createIntent(Board.Create),
|
|
33
44
|
}),
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
defineModule({
|
|
48
|
-
id: `${meta.id}/module/react-surface`,
|
|
49
|
-
activatesOn: Events.SetupReactSurface,
|
|
50
|
-
activate: ReactSurface,
|
|
51
|
-
}),
|
|
52
|
-
defineModule({
|
|
53
|
-
id: `${meta.id}/module/intent-resolver`,
|
|
54
|
-
activatesOn: Events.SetupIntentResolver,
|
|
55
|
-
activate: IntentResolver,
|
|
56
|
-
}),
|
|
57
|
-
]);
|
|
58
|
-
};
|
|
45
|
+
),
|
|
46
|
+
}),
|
|
47
|
+
defineModule({
|
|
48
|
+
id: `${meta.id}/module/react-surface`,
|
|
49
|
+
activatesOn: Events.SetupReactSurface,
|
|
50
|
+
activate: ReactSurface,
|
|
51
|
+
}),
|
|
52
|
+
defineModule({
|
|
53
|
+
id: `${meta.id}/module/intent-resolver`,
|
|
54
|
+
activatesOn: Events.SetupIntentResolver,
|
|
55
|
+
activate: IntentResolver,
|
|
56
|
+
}),
|
|
57
|
+
]);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { Capabilities, type PluginContext, contributes, createSurface } from '@dxos/app-framework';
|
|
8
8
|
import { Obj } from '@dxos/echo';
|
|
9
9
|
|
|
10
10
|
import { BoardContainer } from '../components';
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
6
|
-
|
|
7
|
-
import { type StoryObj, type Meta } from '@storybook/react-vite';
|
|
5
|
+
import { type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React, { useEffect, useState } from 'react';
|
|
9
7
|
|
|
10
8
|
import { IntentPlugin, SettingsPlugin } from '@dxos/app-framework';
|
|
@@ -16,26 +14,21 @@ import { SpacePlugin } from '@dxos/plugin-space';
|
|
|
16
14
|
import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
|
|
17
15
|
import { ThemePlugin } from '@dxos/plugin-theme';
|
|
18
16
|
import { faker } from '@dxos/random';
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
17
|
+
import { Filter, Ref, useQuery, useSpaces } from '@dxos/react-client/echo';
|
|
18
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
21
19
|
import { translations as stackTranslations } from '@dxos/react-ui-stack';
|
|
22
20
|
import { defaultTx } from '@dxos/react-ui-theme';
|
|
23
|
-
import {
|
|
24
|
-
import { withLayout } from '@dxos/storybook-utils';
|
|
21
|
+
import { Organization, Person } from '@dxos/types';
|
|
25
22
|
|
|
26
|
-
import { BoardContainer } from './BoardContainer';
|
|
27
23
|
import { translations } from '../translations';
|
|
28
24
|
import { Board } from '../types';
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
import { BoardContainer } from './BoardContainer';
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
// Initialization utilities
|
|
34
|
-
//
|
|
28
|
+
faker.seed(0);
|
|
35
29
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const board = Obj.make(Board.Board, {
|
|
30
|
+
const createBoard = () =>
|
|
31
|
+
Obj.make(Board.Board, {
|
|
39
32
|
name: 'Test Board',
|
|
40
33
|
items: [],
|
|
41
34
|
layout: {
|
|
@@ -44,25 +37,17 @@ const initializeBoard = async ({ space, client }: { space: Space; client: Client
|
|
|
44
37
|
},
|
|
45
38
|
});
|
|
46
39
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
//
|
|
51
|
-
// Story components
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
const rollOrg = () =>
|
|
55
|
-
({
|
|
40
|
+
const createOrg = () =>
|
|
41
|
+
Obj.make(Organization.Organization, {
|
|
56
42
|
name: faker.commerce.productName(),
|
|
57
43
|
description: faker.lorem.paragraph(),
|
|
58
44
|
image: faker.image.url(),
|
|
59
45
|
website: faker.internet.url(),
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
})
|
|
46
|
+
// TODO(burdon): Fix.
|
|
47
|
+
// status: faker.helpers.arrayElement(Organization.StatusOptions).id,
|
|
48
|
+
});
|
|
63
49
|
|
|
64
|
-
const
|
|
65
|
-
const _client = useClient();
|
|
50
|
+
const DefaultStory = () => {
|
|
66
51
|
const spaces = useSpaces();
|
|
67
52
|
const space = spaces[spaces.length - 1];
|
|
68
53
|
const boards = useQuery(space, Filter.type(Board.Board));
|
|
@@ -82,37 +67,28 @@ const StorybookBoard = () => {
|
|
|
82
67
|
return <BoardContainer role='board' board={board} />;
|
|
83
68
|
};
|
|
84
69
|
|
|
85
|
-
type StoryProps = {};
|
|
86
|
-
|
|
87
70
|
//
|
|
88
71
|
// Story definitions
|
|
89
72
|
//
|
|
90
73
|
|
|
91
|
-
const meta
|
|
74
|
+
const meta = {
|
|
92
75
|
title: 'plugins/plugin-board/Board',
|
|
93
|
-
|
|
94
|
-
render: () => <StorybookBoard />,
|
|
95
|
-
parameters: { translations: [...translations, ...stackTranslations] },
|
|
76
|
+
render: DefaultStory,
|
|
96
77
|
decorators: [
|
|
97
|
-
|
|
78
|
+
withTheme,
|
|
98
79
|
withPluginManager({
|
|
99
80
|
plugins: [
|
|
100
|
-
ThemePlugin({ tx: defaultTx }),
|
|
101
81
|
ClientPlugin({
|
|
102
|
-
types: [
|
|
103
|
-
onClientInitialized: async (
|
|
82
|
+
types: [Organization.Organization, Person.Person, Board.Board],
|
|
83
|
+
onClientInitialized: async ({ client }) => {
|
|
104
84
|
await client.halo.createIdentity();
|
|
105
85
|
const space = await client.spaces.create();
|
|
106
86
|
await space.waitUntilReady();
|
|
107
|
-
const
|
|
108
|
-
space,
|
|
109
|
-
client,
|
|
110
|
-
});
|
|
111
|
-
space.db.add(board);
|
|
87
|
+
const board = space.db.add(createBoard());
|
|
112
88
|
|
|
113
89
|
// Add some sample items
|
|
114
|
-
Array.from({ length: 10 }).map((
|
|
115
|
-
const org =
|
|
90
|
+
Array.from({ length: 10 }).map(() => {
|
|
91
|
+
const org = createOrg();
|
|
116
92
|
space.db.add(org);
|
|
117
93
|
board.items.push(Ref.make(org));
|
|
118
94
|
board.layout.cells[org.id] = {
|
|
@@ -125,18 +101,25 @@ const meta: Meta<StoryProps> = {
|
|
|
125
101
|
});
|
|
126
102
|
},
|
|
127
103
|
}),
|
|
128
|
-
|
|
129
|
-
PreviewPlugin(),
|
|
130
|
-
SpacePlugin(),
|
|
104
|
+
SpacePlugin({}),
|
|
131
105
|
IntentPlugin(),
|
|
132
106
|
SettingsPlugin(),
|
|
107
|
+
|
|
108
|
+
// UI
|
|
109
|
+
ThemePlugin({ tx: defaultTx }),
|
|
110
|
+
PreviewPlugin(),
|
|
111
|
+
StorybookLayoutPlugin({}),
|
|
133
112
|
],
|
|
134
113
|
}),
|
|
135
114
|
],
|
|
115
|
+
parameters: {
|
|
116
|
+
layout: 'fullscreen',
|
|
117
|
+
translations: [...translations, ...stackTranslations],
|
|
118
|
+
},
|
|
136
119
|
};
|
|
137
120
|
|
|
138
121
|
export default meta;
|
|
139
122
|
|
|
140
|
-
type Story = StoryObj<
|
|
123
|
+
type Story = StoryObj<typeof meta>;
|
|
141
124
|
|
|
142
125
|
export const Default: Story = {};
|
|
@@ -2,62 +2,72 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
5
|
+
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
7
6
|
|
|
8
|
-
import {
|
|
7
|
+
import { Surface } from '@dxos/app-framework/react';
|
|
9
8
|
import { getSpace } from '@dxos/client/echo';
|
|
10
|
-
import {
|
|
9
|
+
import { Filter, Obj, Ref } from '@dxos/echo';
|
|
11
10
|
import { invariant } from '@dxos/invariant';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
11
|
+
import { useQuery } from '@dxos/react-client/echo';
|
|
12
|
+
import { useSignalsMemo } from '@dxos/react-ui';
|
|
13
|
+
import { useAttention } from '@dxos/react-ui-attention';
|
|
14
|
+
import { Board, type BoardController, type BoardRootProps, type Position } from '@dxos/react-ui-board';
|
|
15
|
+
import { ObjectPicker, type ObjectPickerContentProps } from '@dxos/react-ui-form';
|
|
14
16
|
import { StackItem } from '@dxos/react-ui-stack';
|
|
15
17
|
import { isNonNullable } from '@dxos/util';
|
|
16
18
|
|
|
17
|
-
// TODO(thure): There is debate about having to rename either the type or the React component. A best practice should be chosen and either Board or Kanban (or both) should be refactored to apply it.
|
|
18
19
|
import { type Board as BoardType } from '../types';
|
|
19
20
|
|
|
21
|
+
const DEFAULT_POSITION = { x: 0, y: 0 } satisfies Position;
|
|
22
|
+
|
|
23
|
+
type PickerState = {
|
|
24
|
+
position: Position;
|
|
25
|
+
};
|
|
26
|
+
|
|
20
27
|
export type BoardContainerProps = {
|
|
21
|
-
role
|
|
28
|
+
role?: string;
|
|
22
29
|
board: BoardType.Board;
|
|
23
30
|
};
|
|
24
31
|
|
|
25
|
-
export const BoardContainer = ({
|
|
26
|
-
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
32
|
+
export const BoardContainer = ({ board }: BoardContainerProps) => {
|
|
27
33
|
const controller = useRef<BoardController>(null);
|
|
34
|
+
const items = useSignalsMemo(() => board.items.map((ref) => ref.target).filter(isNonNullable), [board]);
|
|
35
|
+
const addTriggerRef = useRef<HTMLButtonElement | null>(null);
|
|
36
|
+
const [pickerState, setPickerState] = useState<PickerState | null>(null);
|
|
37
|
+
const attendableId = Obj.getDXN(board).toString();
|
|
38
|
+
const { hasAttention } = useAttention(attendableId);
|
|
28
39
|
|
|
29
|
-
// TODO(burdon):
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// TODO(burdon): Use search.
|
|
41
|
+
const objects = useQuery(getSpace(board), Filter.everything());
|
|
42
|
+
const options = useMemo<ObjectPickerContentProps['options']>(
|
|
43
|
+
() =>
|
|
44
|
+
objects
|
|
45
|
+
.filter((obj) => obj.id !== board.id)
|
|
46
|
+
.map((obj) => {
|
|
47
|
+
const label = Obj.getLabel(obj);
|
|
48
|
+
if (label) {
|
|
49
|
+
return {
|
|
50
|
+
id: obj.id,
|
|
51
|
+
label,
|
|
52
|
+
hue: 'neutral' as const,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
.filter(isNonNullable)
|
|
57
|
+
.sort(({ label: a }, { label: b }) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase())),
|
|
58
|
+
[objects],
|
|
59
|
+
);
|
|
43
60
|
|
|
44
61
|
const handleAdd = useCallback<NonNullable<BoardRootProps['onAdd']>>(
|
|
45
|
-
async (position =
|
|
62
|
+
async (anchor, position = DEFAULT_POSITION) => {
|
|
46
63
|
const space = getSpace(board);
|
|
47
64
|
invariant(space);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
onCreateObject: (object: Obj.Any) => {
|
|
53
|
-
board.items.push(Ref.make(object));
|
|
54
|
-
board.layout.cells[object.id] = { ...position, width: 1, height: 1 };
|
|
55
|
-
controller.current?.center(position);
|
|
56
|
-
},
|
|
57
|
-
}),
|
|
58
|
-
);
|
|
65
|
+
addTriggerRef.current = anchor;
|
|
66
|
+
setPickerState({
|
|
67
|
+
position,
|
|
68
|
+
});
|
|
59
69
|
},
|
|
60
|
-
[board
|
|
70
|
+
[board],
|
|
61
71
|
);
|
|
62
72
|
|
|
63
73
|
// TODO(burdon): Use intents so can be undone.
|
|
@@ -69,7 +79,6 @@ export const BoardContainer = ({ role, board }: BoardContainerProps) => {
|
|
|
69
79
|
board.items.splice(idx, 1);
|
|
70
80
|
}
|
|
71
81
|
delete board.layout.cells[id];
|
|
72
|
-
setItems((items) => items.filter((item) => item.id !== id));
|
|
73
82
|
},
|
|
74
83
|
[board],
|
|
75
84
|
);
|
|
@@ -82,23 +91,56 @@ export const BoardContainer = ({ role, board }: BoardContainerProps) => {
|
|
|
82
91
|
[board],
|
|
83
92
|
);
|
|
84
93
|
|
|
94
|
+
const handleSelect = useCallback<NonNullable<ObjectPickerContentProps['onSelect']>>(
|
|
95
|
+
(id) => {
|
|
96
|
+
if (!pickerState) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Find the selected object by id from the space.
|
|
101
|
+
const selectedObject = objects.find((obj) => obj.id === id);
|
|
102
|
+
if (!selectedObject) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Create a reference to the selected object and add it to the board.
|
|
107
|
+
board.items.push(Ref.make(selectedObject));
|
|
108
|
+
|
|
109
|
+
// Set the layout position for the new item.
|
|
110
|
+
board.layout.cells[selectedObject.id.toString()] = pickerState.position;
|
|
111
|
+
|
|
112
|
+
// Close the picker.
|
|
113
|
+
setPickerState(null);
|
|
114
|
+
},
|
|
115
|
+
[pickerState, objects, board],
|
|
116
|
+
);
|
|
117
|
+
|
|
85
118
|
return (
|
|
86
119
|
<Board.Root ref={controller} layout={board.layout} onAdd={handleAdd} onDelete={handleDelete} onMove={handleMove}>
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
<ObjectPicker.Root
|
|
121
|
+
open={!!pickerState}
|
|
122
|
+
onOpenChange={(nextOpen: boolean) => {
|
|
123
|
+
setPickerState(nextOpen ? { position: DEFAULT_POSITION } : null);
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
<StackItem.Content toolbar>
|
|
127
|
+
<Board.Toolbar disabled={!hasAttention} />
|
|
128
|
+
<Board.Container>
|
|
129
|
+
<Board.Viewport classNames='border-none'>
|
|
130
|
+
<Board.Backdrop />
|
|
131
|
+
<Board.Content>
|
|
132
|
+
{items?.map((item, index) => (
|
|
133
|
+
<Board.Cell item={item} key={index} layout={board.layout?.cells[item.id] ?? { x: 0, y: 0 }}>
|
|
134
|
+
<Surface role='card--extrinsic' data={{ subject: item }} limit={1} />
|
|
135
|
+
</Board.Cell>
|
|
136
|
+
))}
|
|
137
|
+
</Board.Content>
|
|
138
|
+
</Board.Viewport>
|
|
139
|
+
</Board.Container>
|
|
140
|
+
</StackItem.Content>
|
|
141
|
+
<ObjectPicker.Content options={options} onSelect={handleSelect} classNames='popover-card-width' />
|
|
142
|
+
<ObjectPicker.VirtualTrigger virtualRef={addTriggerRef} />
|
|
143
|
+
</ObjectPicker.Root>
|
|
102
144
|
</Board.Root>
|
|
103
145
|
);
|
|
104
146
|
};
|
package/src/index.ts
CHANGED
package/src/meta.ts
CHANGED
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type PluginMeta } from '@dxos/app-framework';
|
|
6
|
+
import { trim } from '@dxos/util';
|
|
6
7
|
|
|
7
8
|
export const meta: PluginMeta = {
|
|
8
9
|
id: 'dxos.org/plugin/board',
|
|
9
10
|
name: 'Board',
|
|
10
|
-
description:
|
|
11
|
-
|
|
11
|
+
description: trim`
|
|
12
|
+
Infinite canvas workspace that combines sticky notes, media, and whiteboarding tools.
|
|
13
|
+
Arrange and connect ideas freely in a visual space perfect for brainstorming and creative collaboration.
|
|
14
|
+
`,
|
|
12
15
|
icon: 'ph--squares-four--regular',
|
|
16
|
+
iconHue: 'green',
|
|
13
17
|
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-board',
|
|
14
18
|
screenshots: [],
|
|
15
19
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
|
+
|
|
7
|
+
import { Obj, Type } from '@dxos/echo';
|
|
8
|
+
import { FormAnnotation, LabelAnnotation } from '@dxos/echo/internal';
|
|
9
|
+
import { BoardLayout, defaultLayout } from '@dxos/react-ui-board';
|
|
10
|
+
|
|
11
|
+
import { meta } from '../meta';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Board and layout.
|
|
15
|
+
*/
|
|
16
|
+
export const Board = Schema.Struct({
|
|
17
|
+
name: Schema.String.pipe(Schema.optional),
|
|
18
|
+
items: Type.Ref(Type.Expando).pipe(Schema.Array, Schema.mutable, FormAnnotation.set(false)),
|
|
19
|
+
layout: BoardLayout.pipe(Schema.mutable, FormAnnotation.set(false)),
|
|
20
|
+
}).pipe(
|
|
21
|
+
Type.Obj({
|
|
22
|
+
typename: 'dxos.org/type/Board',
|
|
23
|
+
version: '0.1.0',
|
|
24
|
+
}),
|
|
25
|
+
LabelAnnotation.set(['name']),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export interface Board extends Schema.Schema.Type<typeof Board> {}
|
|
29
|
+
|
|
30
|
+
export const makeBoard = (props: Partial<Obj.MakeProps<typeof Board>> = {}) =>
|
|
31
|
+
Obj.make(Board, {
|
|
32
|
+
items: [],
|
|
33
|
+
layout: defaultLayout,
|
|
34
|
+
...props,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create board.
|
|
39
|
+
*/
|
|
40
|
+
export class Create extends Schema.TaggedClass<Create>()(`${meta.id}/action/create`, {
|
|
41
|
+
input: Schema.Struct({
|
|
42
|
+
name: Schema.optional(Schema.String),
|
|
43
|
+
}),
|
|
44
|
+
output: Schema.Struct({
|
|
45
|
+
object: Board,
|
|
46
|
+
}),
|
|
47
|
+
}) {}
|
package/src/types/index.ts
CHANGED