@dxos/plugin-board 0.8.4-main.2e9d522 → 0.8.4-main.406dc2a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/lib/browser/chunk-RHMZXTJ7.mjs +129 -0
  2. package/dist/lib/browser/chunk-RHMZXTJ7.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-Z6L4ZVCB.mjs +59 -0
  4. package/dist/lib/browser/chunk-Z6L4ZVCB.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +52 -49
  6. package/dist/lib/browser/index.mjs.map +3 -3
  7. package/dist/lib/browser/{intent-resolver-TDOZP647.mjs → intent-resolver-H6OF7V77.mjs} +7 -7
  8. package/dist/lib/browser/{intent-resolver-TDOZP647.mjs.map → intent-resolver-H6OF7V77.mjs.map} +1 -1
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/react-surface-37LEVBKY.mjs +30 -0
  11. package/dist/lib/browser/react-surface-37LEVBKY.mjs.map +7 -0
  12. package/dist/lib/browser/types/index.mjs +3 -3
  13. package/dist/lib/node-esm/chunk-AWLY252W.mjs +60 -0
  14. package/dist/lib/node-esm/chunk-AWLY252W.mjs.map +7 -0
  15. package/dist/lib/node-esm/chunk-XZA5WICX.mjs +131 -0
  16. package/dist/lib/node-esm/chunk-XZA5WICX.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +52 -49
  18. package/dist/lib/node-esm/index.mjs.map +3 -3
  19. package/dist/lib/node-esm/{intent-resolver-IHQWKJNT.mjs → intent-resolver-L534P6FM.mjs} +7 -7
  20. package/dist/lib/node-esm/{intent-resolver-IHQWKJNT.mjs.map → intent-resolver-L534P6FM.mjs.map} +1 -1
  21. package/dist/lib/node-esm/meta.json +1 -1
  22. package/dist/lib/node-esm/react-surface-GVHSH2W2.mjs +31 -0
  23. package/dist/lib/node-esm/react-surface-GVHSH2W2.mjs.map +7 -0
  24. package/dist/lib/node-esm/types/index.mjs +3 -3
  25. package/dist/types/src/BoardPlugin.d.ts +1 -1
  26. package/dist/types/src/BoardPlugin.d.ts.map +1 -1
  27. package/dist/types/src/capabilities/index.d.ts +1 -1
  28. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  29. package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
  30. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  31. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  32. package/dist/types/src/components/BoardContainer.d.ts +2 -2
  33. package/dist/types/src/components/BoardContainer.d.ts.map +1 -1
  34. package/dist/types/src/components/BoardContainer.stories.d.ts +42 -5
  35. package/dist/types/src/components/BoardContainer.stories.d.ts.map +1 -1
  36. package/dist/types/src/index.d.ts +2 -0
  37. package/dist/types/src/index.d.ts.map +1 -1
  38. package/dist/types/src/types/Board.d.ts +88 -0
  39. package/dist/types/src/types/Board.d.ts.map +1 -0
  40. package/dist/types/src/types/index.d.ts +1 -1
  41. package/dist/types/src/types/index.d.ts.map +1 -1
  42. package/dist/types/tsconfig.tsbuildinfo +1 -1
  43. package/package.json +43 -42
  44. package/src/BoardPlugin.tsx +41 -43
  45. package/src/capabilities/react-surface.tsx +1 -1
  46. package/src/components/BoardContainer.stories.tsx +31 -48
  47. package/src/components/BoardContainer.tsx +86 -54
  48. package/src/index.ts +2 -0
  49. package/src/types/Board.ts +47 -0
  50. package/src/types/index.ts +1 -1
  51. package/dist/lib/browser/chunk-TDV6SJ64.mjs +0 -46
  52. package/dist/lib/browser/chunk-TDV6SJ64.mjs.map +0 -7
  53. package/dist/lib/browser/react-surface-XFSXU2JJ.mjs +0 -143
  54. package/dist/lib/browser/react-surface-XFSXU2JJ.mjs.map +0 -7
  55. package/dist/lib/node-esm/chunk-K6CHLZYU.mjs +0 -48
  56. package/dist/lib/node-esm/chunk-K6CHLZYU.mjs.map +0 -7
  57. package/dist/lib/node-esm/react-surface-ZHPQBZWO.mjs +0 -144
  58. package/dist/lib/node-esm/react-surface-ZHPQBZWO.mjs.map +0 -7
  59. package/dist/types/src/types/schema.d.ts +0 -65
  60. package/dist/types/src/types/schema.d.ts.map +0 -1
  61. 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.2e9d522",
3
+ "version": "0.8.4-main.406dc2a",
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,51 @@
34
36
  ],
35
37
  "dependencies": {
36
38
  "@preact-signals/safe-react": "^0.9.0",
37
- "@preact/signals-core": "^1.9.0",
38
- "@preact/signals-react": "^3.2.0",
39
- "effect": "3.17.0",
40
- "@dxos/app-framework": "0.8.4-main.2e9d522",
41
- "@dxos/assistant": "0.8.4-main.2e9d522",
42
- "@dxos/async": "0.8.4-main.2e9d522",
43
- "@dxos/blueprints": "0.8.4-main.2e9d522",
44
- "@dxos/client": "0.8.4-main.2e9d522",
45
- "@dxos/echo": "0.8.4-main.2e9d522",
46
- "@dxos/echo-schema": "0.8.4-main.2e9d522",
47
- "@dxos/effect": "0.8.4-main.2e9d522",
48
- "@dxos/invariant": "0.8.4-main.2e9d522",
49
- "@dxos/log": "0.8.4-main.2e9d522",
50
- "@dxos/plugin-graph": "0.8.4-main.2e9d522",
51
- "@dxos/plugin-search": "0.8.4-main.2e9d522",
52
- "@dxos/plugin-space": "0.8.4-main.2e9d522",
53
- "@dxos/random": "0.8.4-main.2e9d522",
54
- "@dxos/react-client": "0.8.4-main.2e9d522",
55
- "@dxos/react-ui": "0.8.4-main.2e9d522",
56
- "@dxos/plugin-client": "0.8.4-main.2e9d522",
57
- "@dxos/react-ui-board": "0.8.4-main.2e9d522",
58
- "@dxos/react-ui-form": "0.8.4-main.2e9d522",
59
- "@dxos/react-ui-stack": "0.8.4-main.2e9d522",
60
- "@dxos/schema": "0.8.4-main.2e9d522",
61
- "@dxos/util": "0.8.4-main.2e9d522",
62
- "@dxos/ai": "0.8.4-main.2e9d522"
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.406dc2a",
43
+ "@dxos/assistant": "0.8.4-main.406dc2a",
44
+ "@dxos/app-framework": "0.8.4-main.406dc2a",
45
+ "@dxos/client": "0.8.4-main.406dc2a",
46
+ "@dxos/echo": "0.8.4-main.406dc2a",
47
+ "@dxos/async": "0.8.4-main.406dc2a",
48
+ "@dxos/blueprints": "0.8.4-main.406dc2a",
49
+ "@dxos/effect": "0.8.4-main.406dc2a",
50
+ "@dxos/invariant": "0.8.4-main.406dc2a",
51
+ "@dxos/plugin-client": "0.8.4-main.406dc2a",
52
+ "@dxos/log": "0.8.4-main.406dc2a",
53
+ "@dxos/plugin-search": "0.8.4-main.406dc2a",
54
+ "@dxos/plugin-space": "0.8.4-main.406dc2a",
55
+ "@dxos/random": "0.8.4-main.406dc2a",
56
+ "@dxos/react-client": "0.8.4-main.406dc2a",
57
+ "@dxos/plugin-graph": "0.8.4-main.406dc2a",
58
+ "@dxos/react-ui": "0.8.4-main.406dc2a",
59
+ "@dxos/react-ui-board": "0.8.4-main.406dc2a",
60
+ "@dxos/react-ui-stack": "0.8.4-main.406dc2a",
61
+ "@dxos/schema": "0.8.4-main.406dc2a",
62
+ "@dxos/react-ui-form": "0.8.4-main.406dc2a",
63
+ "@dxos/util": "0.8.4-main.406dc2a"
63
64
  },
64
65
  "devDependencies": {
65
- "@types/react": "~18.2.0",
66
- "@types/react-dom": "~18.2.0",
67
- "react": "~18.2.0",
68
- "react-dom": "~18.2.0",
69
- "vite": "5.4.7",
70
- "@dxos/plugin-preview": "0.8.4-main.2e9d522",
71
- "@dxos/plugin-theme": "0.8.4-main.2e9d522",
72
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.2e9d522",
73
- "@dxos/react-ui-theme": "0.8.4-main.2e9d522",
74
- "@dxos/storybook-utils": "0.8.4-main.2e9d522",
75
- "@dxos/test-utils": "0.8.4-main.2e9d522"
66
+ "@types/react": "~19.2.2",
67
+ "@types/react-dom": "~19.2.1",
68
+ "react": "~19.2.0",
69
+ "react-dom": "~19.2.0",
70
+ "vite": "7.1.9",
71
+ "@dxos/plugin-preview": "0.8.4-main.406dc2a",
72
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.406dc2a",
73
+ "@dxos/react-ui-theme": "0.8.4-main.406dc2a",
74
+ "@dxos/plugin-theme": "0.8.4-main.406dc2a",
75
+ "@dxos/storybook-utils": "0.8.4-main.406dc2a",
76
+ "@dxos/test-utils": "0.8.4-main.406dc2a"
76
77
  },
77
78
  "peerDependencies": {
78
79
  "effect": "^3.13.3",
79
- "react": "~18.2.0",
80
- "react-dom": "~18.2.0",
81
- "@dxos/react-ui-theme": "0.8.4-main.2e9d522",
82
- "@dxos/react-ui": "0.8.4-main.2e9d522"
80
+ "react": "^19.0.0",
81
+ "react-dom": "^19.0.0",
82
+ "@dxos/react-ui": "0.8.4-main.406dc2a",
83
+ "@dxos/react-ui-theme": "0.8.4-main.406dc2a"
83
84
  },
84
85
  "publishConfig": {
85
86
  "access": "public"
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, contributes, createIntent, defineModule, definePlugin, Events } from '@dxos/app-framework';
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,44 @@ import { meta } from './meta';
13
13
  import { translations } from './translations';
14
14
  import { Board } from './types';
15
15
 
16
- export const BoardPlugin = () => {
17
- return definePlugin(meta, [
18
- defineModule({
19
- id: `${meta.id}/module/translations`,
20
- activatesOn: Events.SetupTranslations,
21
- activate: () => contributes(Capabilities.Translations, [...translations, ...boardTranslations]),
22
- }),
23
- defineModule({
24
- id: `${meta.id}/module/metadata`,
25
- activatesOn: Events.SetupMetadata,
26
- activate: () =>
27
- // TODO(burdon): "Metadata" here seems non-descriptive; is this specifically for the type? ObjectMetadata?
28
- contributes(Capabilities.Metadata, {
29
- id: Board.Board.typename,
30
- metadata: {
31
- icon: 'ph--squares-four--regular',
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
+ },
32
+ }),
33
+ }),
34
+ defineModule({
35
+ id: `${meta.id}/module/object-form`,
36
+ activatesOn: ClientEvents.SetupSchema,
37
+ activate: () =>
38
+ contributes(
39
+ SpaceCapabilities.ObjectForm,
40
+ defineObjectForm({
41
+ objectSchema: Board.Board,
42
+ getIntent: () => createIntent(Board.Create),
33
43
  }),
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),
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
- };
44
+ ),
45
+ }),
46
+ defineModule({
47
+ id: `${meta.id}/module/react-surface`,
48
+ activatesOn: Events.SetupReactSurface,
49
+ activate: ReactSurface,
50
+ }),
51
+ defineModule({
52
+ id: `${meta.id}/module/intent-resolver`,
53
+ activatesOn: Events.SetupIntentResolver,
54
+ activate: IntentResolver,
55
+ }),
56
+ ]);
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { contributes, Capabilities, type PluginContext, createSurface } from '@dxos/app-framework';
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 '@dxos-theme';
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 { type Client, useClient } from '@dxos/react-client';
20
- import { Filter, useSpaces, useQuery, Ref, type Space } from '@dxos/react-client/echo';
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
21
  import { DataType } from '@dxos/schema';
24
- import { withLayout } from '@dxos/storybook-utils';
25
22
 
26
- import { BoardContainer } from './BoardContainer';
27
23
  import { translations } from '../translations';
28
24
  import { Board } from '../types';
29
25
 
30
- faker.seed(0);
26
+ import { BoardContainer } from './BoardContainer';
31
27
 
32
- //
33
- // Initialization utilities
34
- //
28
+ faker.seed(0);
35
29
 
36
- const initializeBoard = async ({ space, client }: { space: Space; client: Client }) => {
37
- // Create a new board
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
- return { board };
48
- };
49
-
50
- //
51
- // Story components
52
- //
53
-
54
- const rollOrg = () =>
55
- ({
40
+ const createOrg = () =>
41
+ Obj.make(DataType.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
- status: faker.helpers.arrayElement(DataType.OrganizationStatusOptions).id,
61
- // TODO(thure): Why is this so difficult to type?
62
- }) as unknown as DataType.Organization;
46
+ // TODO(burdon): Fix.
47
+ // status: faker.helpers.arrayElement(DataType.OrganizationStatusOptions).id,
48
+ });
63
49
 
64
- const StorybookBoard = () => {
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: Meta<StoryProps> = {
74
+ const meta = {
92
75
  title: 'plugins/plugin-board/Board',
93
- component: StorybookBoard,
94
- render: () => <StorybookBoard />,
95
- parameters: { translations: [...translations, ...stackTranslations] },
76
+ render: DefaultStory,
96
77
  decorators: [
97
- withLayout({ fullscreen: true }),
78
+ withTheme,
98
79
  withPluginManager({
99
80
  plugins: [
100
- ThemePlugin({ tx: defaultTx }),
101
81
  ClientPlugin({
102
82
  types: [DataType.Organization, DataType.Person, Board.Board],
103
- onClientInitialized: async (_, client) => {
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 { board } = await initializeBoard({
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((_, index) => {
115
- const org = Obj.make(DataType.Organization, rollOrg());
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
- StorybookLayoutPlugin(),
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<StoryProps>;
123
+ type Story = StoryObj<typeof meta>;
141
124
 
142
125
  export const Default: Story = {};
@@ -2,62 +2,80 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { effect } from '@preact/signals-react';
6
- import React, { useCallback, useEffect, useRef, useState } from 'react';
5
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
7
6
 
8
- import { createIntent, Surface, useIntentDispatcher } from '@dxos/app-framework';
9
- import { getSpace } from '@dxos/client/echo';
10
- import { type Obj, Ref, type Type } from '@dxos/echo';
7
+ import { Surface } from '@dxos/app-framework';
8
+ import { Filter, Ref, getSpace } from '@dxos/client/echo';
11
9
  import { invariant } from '@dxos/invariant';
12
- import { SpaceAction } from '@dxos/plugin-space/types';
13
- import { Board, type BoardController, type BoardRootProps } from '@dxos/react-ui-board';
10
+ import { useQuery } from '@dxos/react-client/echo';
11
+ import { useSignalsMemo } from '@dxos/react-ui';
12
+ import { Board, type BoardController, type BoardRootProps, type Position } from '@dxos/react-ui-board';
13
+ import { ObjectPicker } from '@dxos/react-ui-form';
14
14
  import { StackItem } from '@dxos/react-ui-stack';
15
15
  import { isNonNullable } from '@dxos/util';
16
16
 
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
17
  import { type Board as BoardType } from '../types';
19
18
 
20
19
  export type BoardContainerProps = {
21
- role: string;
20
+ role?: string;
22
21
  board: BoardType.Board;
23
22
  };
24
23
 
25
- export const BoardContainer = ({ role, board }: BoardContainerProps) => {
26
- const { dispatchPromise: dispatch } = useIntentDispatcher();
27
- const controller = useRef<BoardController>(null);
24
+ const DEFAULT_POSITION = { x: 0, y: 0 } satisfies Position;
28
25
 
29
- // TODO(burdon): Create effect utility for reactive arrays.
30
- const [items, setItems] = useState<Type.Expando[]>([]);
31
- useEffect(() => {
32
- let t: NodeJS.Timeout;
33
- effect(() => {
34
- const refs = [...board.items];
35
- t = setTimeout(async () => {
36
- const items = await Ref.Array.loadAll(refs);
37
- setItems(items.filter(isNonNullable));
38
- });
39
- });
26
+ type PickerState = {
27
+ position: Position;
28
+ };
29
+
30
+ export const BoardContainer = ({ board }: BoardContainerProps) => {
31
+ const controller = useRef<BoardController>(null);
32
+ const items = useSignalsMemo(() => board.items.map((ref) => ref.target).filter(isNonNullable), [board]);
33
+ const addTriggerRef = useRef<HTMLButtonElement | null>(null);
34
+ const [pickerState, setPickerState] = useState<PickerState | null>(null);
40
35
 
41
- return () => clearTimeout(t);
42
- }, [board.items]);
36
+ // Memoize options for ObjectPicker containing all ECHO objects in the same space as the Board.
37
+ const allObjects = useQuery(getSpace(board), Filter.everything());
38
+ const options = useMemo(
39
+ () =>
40
+ allObjects.map((obj) => ({
41
+ id: obj.id,
42
+ label: obj.name || obj.title || obj.id,
43
+ hue: 'neutral' as const,
44
+ })),
45
+ [allObjects],
46
+ );
43
47
 
44
48
  const handleAdd = useCallback<NonNullable<BoardRootProps['onAdd']>>(
45
- async (position = { x: 0, y: 0 }) => {
49
+ async (anchor, position = DEFAULT_POSITION) => {
46
50
  const space = getSpace(board);
47
51
  invariant(space);
48
- await dispatch(
49
- createIntent(SpaceAction.OpenCreateObject, {
50
- target: space,
51
- navigable: false,
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
- );
52
+ addTriggerRef.current = anchor;
53
+ setPickerState({
54
+ position,
55
+ });
56
+ },
57
+ [board],
58
+ );
59
+
60
+ const handleSelect = useCallback(
61
+ (id: string) => {
62
+ if (!pickerState) return;
63
+
64
+ // Find the selected object by id from the space.
65
+ const selectedObject = allObjects.find((obj) => obj.id === id);
66
+ if (!selectedObject) return;
67
+
68
+ // Create a reference to the selected object and add it to the board.
69
+ const ref = Ref.make(selectedObject);
70
+ board.items.push(ref);
71
+
72
+ // Set the layout position for the new item.
73
+ board.layout.cells[selectedObject.id.toString()] = pickerState.position;
74
+
75
+ // Close the picker.
76
+ setPickerState(null);
59
77
  },
60
- [board, controller, dispatch],
78
+ [pickerState, allObjects, board],
61
79
  );
62
80
 
63
81
  // TODO(burdon): Use intents so can be undone.
@@ -69,7 +87,6 @@ export const BoardContainer = ({ role, board }: BoardContainerProps) => {
69
87
  board.items.splice(idx, 1);
70
88
  }
71
89
  delete board.layout.cells[id];
72
- setItems((items) => items.filter((item) => item.id !== id));
73
90
  },
74
91
  [board],
75
92
  );
@@ -84,21 +101,36 @@ export const BoardContainer = ({ role, board }: BoardContainerProps) => {
84
101
 
85
102
  return (
86
103
  <Board.Root ref={controller} layout={board.layout} onAdd={handleAdd} onDelete={handleDelete} onMove={handleMove}>
87
- <StackItem.Content toolbar>
88
- <Board.Controls />
89
- <Board.Container>
90
- <Board.Viewport classNames='border-none'>
91
- <Board.Backdrop />
92
- <Board.Content>
93
- {items?.map((item, index) => (
94
- <Board.Cell item={item} key={index} layout={board.layout?.cells[item.id] ?? { x: 0, y: 0 }}>
95
- <Surface role='card--extrinsic' data={{ subject: item }} limit={1} />
96
- </Board.Cell>
97
- ))}
98
- </Board.Content>
99
- </Board.Viewport>
100
- </Board.Container>
101
- </StackItem.Content>
104
+ <ObjectPicker.Root
105
+ open={!!pickerState}
106
+ onOpenChange={(nextOpen: boolean) => {
107
+ setPickerState(
108
+ nextOpen
109
+ ? {
110
+ position: DEFAULT_POSITION,
111
+ }
112
+ : null,
113
+ );
114
+ }}
115
+ >
116
+ <StackItem.Content toolbar>
117
+ <Board.Toolbar />
118
+ <Board.Container>
119
+ <Board.Viewport classNames='border-none'>
120
+ <Board.Backdrop />
121
+ <Board.Content>
122
+ {items?.map((item, index) => (
123
+ <Board.Cell item={item} key={index} layout={board.layout?.cells[item.id] ?? { x: 0, y: 0 }}>
124
+ <Surface role='card--extrinsic' data={{ subject: item }} limit={1} />
125
+ </Board.Cell>
126
+ ))}
127
+ </Board.Content>
128
+ </Board.Viewport>
129
+ </Board.Container>
130
+ </StackItem.Content>
131
+ <ObjectPicker.Content options={options} onSelect={handleSelect} classNames='popover-card-width' />
132
+ <ObjectPicker.VirtualTrigger virtualRef={addTriggerRef} />
133
+ </ObjectPicker.Root>
102
134
  </Board.Root>
103
135
  );
104
136
  };
package/src/index.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ export * from './components';
5
6
  export * from './meta';
7
+ export * from './types';
6
8
 
7
9
  export * from './BoardPlugin';
@@ -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 { 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.optional(Schema.String),
18
+ items: Schema.mutable(Schema.Array(Type.Ref(Type.Expando))),
19
+ layout: Schema.mutable(BoardLayout),
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
+ }) {}
@@ -2,4 +2,4 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './schema';
5
+ export * as Board from './Board';
@@ -1,46 +0,0 @@
1
- // src/types/schema.ts
2
- import { Schema } from "effect";
3
- import { Type } from "@dxos/echo";
4
- import { LabelAnnotation } from "@dxos/echo-schema";
5
- import { BoardLayout } from "@dxos/react-ui-board";
6
-
7
- // src/meta.ts
8
- var meta = {
9
- id: "dxos.org/plugin/board",
10
- name: "Board",
11
- description: "A spatial, infinite canvas app combining notes, media, and whiteboarding in a tactile, visual interface.",
12
- icon: "ph--squares-four--regular",
13
- source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-board",
14
- screenshots: []
15
- };
16
-
17
- // src/types/schema.ts
18
- (function(Board2) {
19
- Board2.Board = Schema.Struct({
20
- name: Schema.optional(Schema.String),
21
- items: Schema.mutable(Schema.Array(Type.Ref(Type.Expando))),
22
- layout: Schema.mutable(BoardLayout)
23
- }).pipe(Type.Obj({
24
- typename: "dxos.org/type/Board",
25
- version: "0.1.0"
26
- }), LabelAnnotation.set([
27
- "name"
28
- ]));
29
- class Create extends Schema.TaggedClass()(`${meta.id}/action/create`, {
30
- input: Schema.Struct({
31
- name: Schema.optional(Schema.String)
32
- }),
33
- output: Schema.Struct({
34
- object: Board2.Board
35
- })
36
- }) {
37
- }
38
- Board2.Create = Create;
39
- })(Board || (Board = {}));
40
- var Board;
41
-
42
- export {
43
- meta,
44
- Board
45
- };
46
- //# sourceMappingURL=chunk-TDV6SJ64.mjs.map