@dxos/plugin-masonry 0.8.4-main.fcfe5033a5 → 0.9.0
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/LICENSE +102 -5
- package/PLUGIN.mdl +328 -0
- package/README.md +1 -1
- package/dist/lib/neutral/MasonryContainer-7CXOATRR.mjs +96 -0
- package/dist/lib/neutral/MasonryContainer-7CXOATRR.mjs.map +7 -0
- package/dist/lib/neutral/MasonryPlugin.mjs +38 -0
- package/dist/lib/neutral/MasonryPlugin.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +11 -0
- package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
- package/dist/lib/{browser/types/index.mjs → neutral/chunk-CNXGZZNQ.mjs} +15 -15
- package/dist/lib/neutral/chunk-CNXGZZNQ.mjs.map +7 -0
- package/dist/lib/neutral/chunk-IJ2FIXSI.mjs +32 -0
- package/dist/lib/neutral/chunk-IJ2FIXSI.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +1 -0
- package/dist/lib/neutral/containers/index.mjs +9 -0
- package/dist/lib/neutral/containers/index.mjs.map +7 -0
- package/dist/lib/neutral/create-object-WRCYV4HT.mjs +39 -0
- package/dist/lib/neutral/create-object-WRCYV4HT.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +14 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/meta.mjs +8 -0
- package/dist/lib/neutral/meta.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +12 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/react-surface-7CZHE3XA.mjs +35 -0
- package/dist/lib/neutral/react-surface-7CZHE3XA.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +30 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/lib/neutral/types/index.mjs +10 -0
- package/dist/lib/neutral/types/index.mjs.map +7 -0
- package/dist/types/src/MasonryPlugin.d.ts +1 -0
- package/dist/types/src/MasonryPlugin.d.ts.map +1 -1
- package/dist/types/src/MasonryPlugin.test.d.ts +2 -0
- package/dist/types/src/MasonryPlugin.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +11 -0
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +6 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/containers/MasonryContainer/MasonryContainer.d.ts +1 -2
- package/dist/types/src/containers/MasonryContainer/MasonryContainer.d.ts.map +1 -1
- package/dist/types/src/containers/MasonryContainer/MasonryContainer.stories.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/plugin.d.ts +3 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +10 -10
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Masonry.d.ts +6 -6
- package/dist/types/src/types/Masonry.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +77 -52
- package/src/MasonryPlugin.test.ts +26 -0
- package/src/MasonryPlugin.tsx +11 -34
- package/src/capabilities/create-object.ts +36 -0
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/react-surface.tsx +1 -2
- package/src/containers/MasonryContainer/MasonryContainer.stories.tsx +5 -5
- package/src/containers/MasonryContainer/MasonryContainer.tsx +31 -38
- package/src/index.ts +1 -2
- package/src/meta.ts +19 -7
- package/src/plugin.ts +9 -0
- package/src/types/Masonry.ts +13 -14
- package/src/types/MasonryAction.ts +1 -1
- package/src/vite-env.d.ts +10 -0
- package/dist/lib/browser/index.mjs +0 -97
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/types/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/index.mjs +0 -98
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/types/index.mjs +0 -67
- package/dist/lib/node-esm/types/index.mjs.map +0 -7
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs.map +0 -0
- /package/dist/lib/{node-esm/chunk-HSLMI22Q.mjs.map → neutral/components/index.mjs.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-masonry",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Masonry DXOS Surface plugin",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -8,84 +8,109 @@
|
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/dxos/dxos"
|
|
10
10
|
},
|
|
11
|
-
"license": "
|
|
11
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
12
12
|
"author": "DXOS.org",
|
|
13
13
|
"sideEffects": true,
|
|
14
14
|
"type": "module",
|
|
15
15
|
"imports": {
|
|
16
|
-
"#capabilities":
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
"#capabilities": {
|
|
17
|
+
"source": "./src/capabilities/index.ts",
|
|
18
|
+
"types": "./dist/types/src/capabilities/index.d.ts",
|
|
19
|
+
"default": "./dist/lib/neutral/capabilities/index.mjs"
|
|
20
|
+
},
|
|
21
|
+
"#components": {
|
|
22
|
+
"source": "./src/components/index.ts",
|
|
23
|
+
"types": "./dist/types/src/components/index.d.ts",
|
|
24
|
+
"default": "./dist/lib/neutral/components/index.mjs"
|
|
25
|
+
},
|
|
26
|
+
"#containers": {
|
|
27
|
+
"source": "./src/containers/index.ts",
|
|
28
|
+
"types": "./dist/types/src/containers/index.d.ts",
|
|
29
|
+
"default": "./dist/lib/neutral/containers/index.mjs"
|
|
30
|
+
},
|
|
31
|
+
"#meta": {
|
|
32
|
+
"source": "./src/meta.ts",
|
|
33
|
+
"types": "./dist/types/src/meta.d.ts",
|
|
34
|
+
"default": "./dist/lib/neutral/meta.mjs"
|
|
35
|
+
},
|
|
36
|
+
"#plugin": {
|
|
37
|
+
"source": "./src/MasonryPlugin.tsx",
|
|
38
|
+
"types": "./dist/types/src/MasonryPlugin.d.ts",
|
|
39
|
+
"default": "./dist/lib/neutral/MasonryPlugin.mjs"
|
|
40
|
+
},
|
|
41
|
+
"#translations": {
|
|
42
|
+
"source": "./src/translations.ts",
|
|
43
|
+
"types": "./dist/types/src/translations.d.ts",
|
|
44
|
+
"default": "./dist/lib/neutral/translations.mjs"
|
|
45
|
+
},
|
|
46
|
+
"#types": {
|
|
47
|
+
"source": "./src/types/index.ts",
|
|
48
|
+
"types": "./dist/types/src/types/index.d.ts",
|
|
49
|
+
"default": "./dist/lib/neutral/types/index.mjs"
|
|
50
|
+
}
|
|
21
51
|
},
|
|
22
52
|
"exports": {
|
|
23
53
|
".": {
|
|
24
54
|
"source": "./src/index.ts",
|
|
25
55
|
"types": "./dist/types/src/index.d.ts",
|
|
26
|
-
"
|
|
27
|
-
"node": "./dist/lib/node-esm/index.mjs"
|
|
56
|
+
"default": "./dist/lib/neutral/index.mjs"
|
|
28
57
|
},
|
|
29
|
-
"./
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
58
|
+
"./assets/PLUGIN.mdl": "./PLUGIN.mdl",
|
|
59
|
+
"./plugin": {
|
|
60
|
+
"source": "./src/plugin.ts",
|
|
61
|
+
"types": "./dist/types/src/plugin.d.ts",
|
|
62
|
+
"default": "./dist/lib/neutral/plugin.mjs"
|
|
63
|
+
},
|
|
64
|
+
"./translations": {
|
|
65
|
+
"source": "./src/translations.ts",
|
|
66
|
+
"types": "./dist/types/src/translations.d.ts",
|
|
67
|
+
"default": "./dist/lib/neutral/translations.mjs"
|
|
34
68
|
}
|
|
35
69
|
},
|
|
36
70
|
"types": "dist/types/src/index.d.ts",
|
|
37
|
-
"typesVersions": {
|
|
38
|
-
"*": {
|
|
39
|
-
"types": [
|
|
40
|
-
"dist/types/src/types/index.d.ts"
|
|
41
|
-
]
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
71
|
"files": [
|
|
45
72
|
"dist",
|
|
46
|
-
"src"
|
|
73
|
+
"src",
|
|
74
|
+
"PLUGIN.mdl"
|
|
47
75
|
],
|
|
48
76
|
"dependencies": {
|
|
49
|
-
"@dxos/app-framework": "0.
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/echo": "0.
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/plugin-
|
|
56
|
-
"@dxos/react-
|
|
57
|
-
"@dxos/react-
|
|
58
|
-
"@dxos/react-ui
|
|
59
|
-
"@dxos/react-ui-
|
|
60
|
-
"@dxos/react-ui-
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/schema": "0.
|
|
65
|
-
"@dxos/effect": "0.8.4-main.fcfe5033a5",
|
|
66
|
-
"@dxos/types": "0.8.4-main.fcfe5033a5",
|
|
67
|
-
"@dxos/util": "0.8.4-main.fcfe5033a5"
|
|
77
|
+
"@dxos/app-framework": "0.9.0",
|
|
78
|
+
"@dxos/compute": "0.9.0",
|
|
79
|
+
"@dxos/echo": "0.9.0",
|
|
80
|
+
"@dxos/keys": "0.9.0",
|
|
81
|
+
"@dxos/app-toolkit": "0.9.0",
|
|
82
|
+
"@dxos/effect": "0.9.0",
|
|
83
|
+
"@dxos/plugin-client": "0.9.0",
|
|
84
|
+
"@dxos/react-client": "0.9.0",
|
|
85
|
+
"@dxos/react-ui-masonry": "0.9.0",
|
|
86
|
+
"@dxos/react-ui": "0.9.0",
|
|
87
|
+
"@dxos/react-ui-search": "0.9.0",
|
|
88
|
+
"@dxos/react-ui-menu": "0.9.0",
|
|
89
|
+
"@dxos/plugin-space": "0.9.0",
|
|
90
|
+
"@dxos/util": "0.9.0",
|
|
91
|
+
"@dxos/types": "0.9.0",
|
|
92
|
+
"@dxos/schema": "0.9.0"
|
|
68
93
|
},
|
|
69
94
|
"devDependencies": {
|
|
70
95
|
"@types/react": "~19.2.7",
|
|
71
96
|
"@types/react-dom": "~19.2.3",
|
|
72
|
-
"effect": "3.
|
|
97
|
+
"effect": "3.21.3",
|
|
73
98
|
"react": "~19.2.3",
|
|
74
99
|
"react-dom": "~19.2.3",
|
|
75
|
-
"vite": "^
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/plugin-
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/plugin-
|
|
80
|
-
"@dxos/storybook-utils": "0.
|
|
81
|
-
"@dxos/ui-theme": "0.
|
|
100
|
+
"vite": "^8.0.16",
|
|
101
|
+
"@dxos/random": "0.9.0",
|
|
102
|
+
"@dxos/plugin-preview": "0.9.0",
|
|
103
|
+
"@dxos/plugin-testing": "0.9.0",
|
|
104
|
+
"@dxos/plugin-theme": "0.9.0",
|
|
105
|
+
"@dxos/storybook-utils": "0.9.0",
|
|
106
|
+
"@dxos/ui-theme": "0.9.0"
|
|
82
107
|
},
|
|
83
108
|
"peerDependencies": {
|
|
84
|
-
"effect": "3.
|
|
109
|
+
"effect": "3.21.3",
|
|
85
110
|
"react": "~19.2.3",
|
|
86
111
|
"react-dom": "~19.2.3",
|
|
87
|
-
"@dxos/react-ui": "0.
|
|
88
|
-
"@dxos/ui-theme": "0.
|
|
112
|
+
"@dxos/react-ui": "0.9.0",
|
|
113
|
+
"@dxos/ui-theme": "0.9.0"
|
|
89
114
|
},
|
|
90
115
|
"publishConfig": {
|
|
91
116
|
"access": "public"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { ClientPlugin } from '@dxos/plugin-client/plugin';
|
|
8
|
+
import { createComposerTestApp } from '@dxos/plugin-testing/harness';
|
|
9
|
+
|
|
10
|
+
import { MasonryPlugin } from '#plugin';
|
|
11
|
+
|
|
12
|
+
import { meta } from './meta';
|
|
13
|
+
|
|
14
|
+
const moduleId = (name: string) => `${meta.id}.module.${name}`;
|
|
15
|
+
|
|
16
|
+
describe('MasonryPlugin', () => {
|
|
17
|
+
test('modules activate on the expected events', async ({ expect }) => {
|
|
18
|
+
await using harness = await createComposerTestApp({
|
|
19
|
+
plugins: [ClientPlugin({}), MasonryPlugin()],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
expect(harness.manager.getActive()).toEqual(
|
|
23
|
+
expect.arrayContaining([moduleId('CreateObject'), moduleId('schema'), moduleId('ReactSurface')]),
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
});
|
package/src/MasonryPlugin.tsx
CHANGED
|
@@ -2,49 +2,26 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import * as Effect from 'effect/Effect';
|
|
6
|
-
import * as Option from 'effect/Option';
|
|
7
|
-
|
|
8
5
|
import { Plugin } from '@dxos/app-framework';
|
|
9
6
|
import { AppPlugin } from '@dxos/app-toolkit';
|
|
10
|
-
import { Annotation, Type } from '@dxos/echo';
|
|
11
|
-
import { Operation } from '@dxos/operation';
|
|
12
|
-
import { SpaceOperation } from '@dxos/plugin-space/operations';
|
|
13
|
-
import { type CreateObject } from '@dxos/plugin-space/types';
|
|
14
|
-
import { ViewModel } from '@dxos/schema';
|
|
15
7
|
|
|
16
|
-
import { ReactSurface } from '#capabilities';
|
|
8
|
+
import { CreateObject, ReactSurface } from '#capabilities';
|
|
17
9
|
import { meta } from '#meta';
|
|
18
|
-
import {
|
|
10
|
+
import { translations } from '#translations';
|
|
11
|
+
import { Masonry } from '#types';
|
|
19
12
|
|
|
20
|
-
|
|
13
|
+
// eslint-disable-next-line import/no-relative-packages
|
|
14
|
+
import pluginSpec from '../PLUGIN.mdl?raw';
|
|
21
15
|
|
|
22
16
|
export const MasonryPlugin = Plugin.define(meta).pipe(
|
|
23
|
-
AppPlugin.
|
|
24
|
-
metadata: {
|
|
25
|
-
id: Type.getTypename(Masonry.Masonry),
|
|
26
|
-
metadata: {
|
|
27
|
-
icon: Annotation.IconAnnotation.get(Masonry.Masonry).pipe(Option.getOrThrow).icon,
|
|
28
|
-
iconHue: Annotation.IconAnnotation.get(Masonry.Masonry).pipe(Option.getOrThrow).hue ?? 'white',
|
|
29
|
-
inputSchema: MasonryAction.MasonryProps,
|
|
30
|
-
createObject: ((props, options) =>
|
|
31
|
-
Effect.gen(function* () {
|
|
32
|
-
const object = yield* Effect.promise(async () => {
|
|
33
|
-
const { view } = await ViewModel.makeFromDatabase({ db: options.db, typename: props.typename });
|
|
34
|
-
return Masonry.make({ name: props.name, view });
|
|
35
|
-
});
|
|
36
|
-
return yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
37
|
-
object,
|
|
38
|
-
target: options.target,
|
|
39
|
-
hidden: true,
|
|
40
|
-
targetNodeId: options.targetNodeId,
|
|
41
|
-
});
|
|
42
|
-
})) satisfies CreateObject,
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
}),
|
|
17
|
+
AppPlugin.addCreateObjectModule({ activate: CreateObject }),
|
|
46
18
|
AppPlugin.addSchemaModule({ schema: [Masonry.Masonry] }),
|
|
47
19
|
AppPlugin.addSurfaceModule({ activate: ReactSurface }),
|
|
48
20
|
AppPlugin.addTranslationsModule({ translations }),
|
|
21
|
+
AppPlugin.addPluginAssetModule({
|
|
22
|
+
asset: { pluginId: meta.id, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
|
|
23
|
+
}),
|
|
49
24
|
Plugin.make,
|
|
50
25
|
);
|
|
26
|
+
|
|
27
|
+
export default MasonryPlugin;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { Capability } from '@dxos/app-framework';
|
|
8
|
+
import { Operation } from '@dxos/compute';
|
|
9
|
+
import { Type } from '@dxos/echo';
|
|
10
|
+
import { SpaceOperation } from '@dxos/plugin-space';
|
|
11
|
+
import { SpaceCapabilities } from '@dxos/plugin-space';
|
|
12
|
+
import { ViewModel } from '@dxos/schema';
|
|
13
|
+
|
|
14
|
+
import { Masonry, MasonryAction } from '#types';
|
|
15
|
+
|
|
16
|
+
export default Capability.makeModule(
|
|
17
|
+
Effect.fnUntraced(function* () {
|
|
18
|
+
return Capability.contributes(SpaceCapabilities.CreateObjectEntry, {
|
|
19
|
+
id: Type.getTypename(Masonry.Masonry),
|
|
20
|
+
inputSchema: MasonryAction.MasonryProps,
|
|
21
|
+
createObject: (props, options) =>
|
|
22
|
+
Effect.gen(function* () {
|
|
23
|
+
const object = yield* Effect.promise(async () => {
|
|
24
|
+
const { view } = await ViewModel.makeFromDatabase({ db: options.db, typename: props.typename });
|
|
25
|
+
return Masonry.make({ name: props.name, view });
|
|
26
|
+
});
|
|
27
|
+
return yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
28
|
+
object,
|
|
29
|
+
target: options.target,
|
|
30
|
+
hidden: true,
|
|
31
|
+
targetNodeId: options.targetNodeId,
|
|
32
|
+
});
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
@@ -8,8 +8,7 @@ import React from 'react';
|
|
|
8
8
|
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
9
9
|
import { Surface } from '@dxos/app-framework/ui';
|
|
10
10
|
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
11
|
-
import { Obj } from '@dxos/echo';
|
|
12
|
-
import { View } from '@dxos/echo';
|
|
11
|
+
import { Obj, View } from '@dxos/echo';
|
|
13
12
|
|
|
14
13
|
import { MasonryContainer } from '#containers';
|
|
15
14
|
import { Masonry } from '#types';
|
|
@@ -7,13 +7,13 @@ import * as Effect from 'effect/Effect';
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
9
9
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
10
|
-
import { View } from '@dxos/echo';
|
|
11
|
-
import { ClientPlugin } from '@dxos/plugin-client';
|
|
10
|
+
import { Filter, Type, View } from '@dxos/echo';
|
|
11
|
+
import { ClientPlugin } from '@dxos/plugin-client/testing';
|
|
12
12
|
import { initializeIdentity } from '@dxos/plugin-client/testing';
|
|
13
|
-
import { PreviewPlugin } from '@dxos/plugin-preview';
|
|
13
|
+
import { PreviewPlugin } from '@dxos/plugin-preview/testing';
|
|
14
14
|
import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
|
|
15
15
|
import { random } from '@dxos/random';
|
|
16
|
-
import {
|
|
16
|
+
import { useObject, useQuery, useSpaces } from '@dxos/react-client/echo';
|
|
17
17
|
import { ViewModel } from '@dxos/schema';
|
|
18
18
|
import { createObjectFactory } from '@dxos/schema/testing';
|
|
19
19
|
import { Organization } from '@dxos/types';
|
|
@@ -52,7 +52,7 @@ const meta = {
|
|
|
52
52
|
const { view } = yield* Effect.promise(() =>
|
|
53
53
|
ViewModel.makeFromDatabase({
|
|
54
54
|
db: space.db,
|
|
55
|
-
typename: Organization.Organization
|
|
55
|
+
typename: Type.getTypename(Organization.Organization),
|
|
56
56
|
}),
|
|
57
57
|
);
|
|
58
58
|
const masonry = Masonry.make({ view });
|
|
@@ -2,22 +2,18 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import * as Function from 'effect/Function';
|
|
6
|
-
import * as Option from 'effect/Option';
|
|
7
|
-
import type * as Schema from 'effect/Schema';
|
|
8
5
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
9
6
|
|
|
10
7
|
import { Surface, useCapabilities } from '@dxos/app-framework/ui';
|
|
11
8
|
import { AppCapabilities } from '@dxos/app-toolkit';
|
|
12
|
-
import { AppSurface, useObjectMenuItems } from '@dxos/app-toolkit/ui';
|
|
13
|
-
import {
|
|
14
|
-
import { type View } from '@dxos/echo';
|
|
9
|
+
import { AppSurface, useObjectMenuItems, useSchemaFilter } from '@dxos/app-toolkit/ui';
|
|
10
|
+
import { Filter, Obj, Query, type Ref, Type, type View } from '@dxos/echo';
|
|
15
11
|
import { useObject, useQuery } from '@dxos/react-client/echo';
|
|
16
12
|
import { Card, Panel, Toolbar } from '@dxos/react-ui';
|
|
17
13
|
import { Masonry as MasonryComponent } from '@dxos/react-ui-masonry';
|
|
18
14
|
import { Menu } from '@dxos/react-ui-menu';
|
|
19
15
|
import { SearchList, useSearchListResults } from '@dxos/react-ui-search';
|
|
20
|
-
import { getTagFromQuery,
|
|
16
|
+
import { getTagFromQuery, getTypeURIFromQuery } from '@dxos/schema';
|
|
21
17
|
import { isNonNullable } from '@dxos/util';
|
|
22
18
|
|
|
23
19
|
export type MasonryContainerProps = {
|
|
@@ -35,35 +31,36 @@ export const MasonryContainer = ({
|
|
|
35
31
|
const [view] = useObject(viewOrRef);
|
|
36
32
|
const schemas = useCapabilities(AppCapabilities.Schema);
|
|
37
33
|
const db = view && Obj.getDatabase(view);
|
|
38
|
-
const
|
|
34
|
+
const typeUri = view?.query ? getTypeURIFromQuery(view.query.ast) : undefined;
|
|
39
35
|
const tag = view?.query ? getTagFromQuery(view.query.ast) : undefined;
|
|
40
36
|
|
|
41
|
-
const [cardSchema, setCardSchema] = useState<
|
|
37
|
+
const [cardSchema, setCardSchema] = useState<Type.AnyEntity>();
|
|
42
38
|
|
|
43
39
|
useEffect(() => {
|
|
44
|
-
const staticSchema = schemas.flat().find((schema) => Type.
|
|
40
|
+
const staticSchema = schemas.flat().find((schema) => Type.getURI(schema) === typeUri);
|
|
45
41
|
if (staticSchema) {
|
|
46
42
|
setCardSchema(() => staticSchema);
|
|
43
|
+
return;
|
|
47
44
|
}
|
|
48
|
-
if (
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
59
|
-
return unsubscribe;
|
|
45
|
+
if (typeUri && db) {
|
|
46
|
+
const findInRegistry = () =>
|
|
47
|
+
db.graph.registry
|
|
48
|
+
.list()
|
|
49
|
+
.filter(Type.isType)
|
|
50
|
+
.find((t) => Type.getURI(t) === typeUri);
|
|
51
|
+
setCardSchema(() => findInRegistry());
|
|
52
|
+
return db.graph.registry.changed.on(() => {
|
|
53
|
+
setCardSchema(() => findInRegistry());
|
|
54
|
+
});
|
|
60
55
|
}
|
|
61
|
-
|
|
56
|
+
setCardSchema(undefined);
|
|
57
|
+
}, [schemas, typeUri, db]);
|
|
62
58
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
const baseFilter = useSchemaFilter(cardSchema);
|
|
60
|
+
const query = useMemo(
|
|
61
|
+
() => (tag ? Query.select(baseFilter).select(Filter.tag(tag)) : Query.select(baseFilter)),
|
|
62
|
+
[baseFilter, tag],
|
|
63
|
+
);
|
|
67
64
|
const objects = useQuery(db, query);
|
|
68
65
|
|
|
69
66
|
const sortedObjects = useMemo(
|
|
@@ -87,7 +84,9 @@ export const MasonryContainer = ({
|
|
|
87
84
|
</Toolbar.Root>
|
|
88
85
|
</Panel.Toolbar>
|
|
89
86
|
<Panel.Content>
|
|
90
|
-
<MasonryComponent.Content
|
|
87
|
+
<MasonryComponent.Content>
|
|
88
|
+
<MasonryComponent.Viewport items={results} getId={(data: any) => data?.id} />
|
|
89
|
+
</MasonryComponent.Content>
|
|
91
90
|
</Panel.Content>
|
|
92
91
|
</Panel.Root>
|
|
93
92
|
</SearchList.Root>
|
|
@@ -97,26 +96,20 @@ export const MasonryContainer = ({
|
|
|
97
96
|
|
|
98
97
|
const Item = ({ data }: { data: any }) => {
|
|
99
98
|
const objectMenuItems = useObjectMenuItems(data);
|
|
100
|
-
const icon =
|
|
101
|
-
Obj.getSchema(data),
|
|
102
|
-
Option.fromNullable,
|
|
103
|
-
Option.flatMap(Annotation.IconAnnotation.get),
|
|
104
|
-
Option.map(({ icon }) => icon),
|
|
105
|
-
Option.getOrElse(() => 'ph--placeholder--regular'),
|
|
106
|
-
);
|
|
99
|
+
const icon = Obj.getIcon(data)?.icon ?? 'ph--circle-dashed--regular';
|
|
107
100
|
|
|
108
101
|
return (
|
|
109
102
|
<Menu.Root>
|
|
110
103
|
<Card.Root>
|
|
111
|
-
<Card.
|
|
104
|
+
<Card.Header>
|
|
112
105
|
<Card.Icon icon={icon} />
|
|
113
|
-
<Card.Title>{Obj.getLabel(data)}</Card.Title>
|
|
106
|
+
<Card.Title>{Obj.getLabel(data, { fallback: 'typename' })}</Card.Title>
|
|
114
107
|
{/* TODO(wittjosiah): Reconcile with Card.Menu. */}
|
|
115
108
|
<Menu.Trigger asChild disabled={!objectMenuItems?.length}>
|
|
116
109
|
<Toolbar.IconButton iconOnly variant='ghost' icon='ph--dots-three-vertical--regular' label='Actions' />
|
|
117
110
|
</Menu.Trigger>
|
|
118
111
|
<Menu.Content items={objectMenuItems} />
|
|
119
|
-
</Card.
|
|
112
|
+
</Card.Header>
|
|
120
113
|
<Surface.Surface
|
|
121
114
|
type={AppSurface.Card}
|
|
122
115
|
limit={1}
|
package/src/index.ts
CHANGED
package/src/meta.ts
CHANGED
|
@@ -2,18 +2,30 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Plugin } from '@dxos/app-framework';
|
|
6
|
+
import { DXN } from '@dxos/keys';
|
|
6
7
|
import { trim } from '@dxos/util';
|
|
7
8
|
|
|
8
|
-
export const meta
|
|
9
|
-
|
|
9
|
+
export const meta = Plugin.makeMeta({
|
|
10
|
+
key: DXN.make('org.dxos.plugin.masonry'),
|
|
10
11
|
name: 'Masonry',
|
|
12
|
+
author: 'DXOS',
|
|
11
13
|
description: trim`
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
Masonry renders a live, query-driven collection as a responsive column-balanced card grid.
|
|
15
|
+
|
|
16
|
+
A Masonry object wraps an ECHO View that defines which objects to show and in what order.
|
|
17
|
+
As objects are added or removed — by any peer — the grid reflows automatically, keeping cards
|
|
18
|
+
balanced across columns without manual arrangement.
|
|
19
|
+
|
|
20
|
+
Each card delegates its body to a Surface slot, so other plugins can supply rich, type-specific
|
|
21
|
+
content while Masonry handles layout, search, and context menus.
|
|
22
|
+
|
|
23
|
+
A built-in search bar filters cards client-side by label without modifying the underlying query,
|
|
24
|
+
making it easy to explore large collections without leaving the view.
|
|
14
25
|
`,
|
|
15
26
|
icon: 'ph--wall--regular',
|
|
16
|
-
iconHue: '
|
|
27
|
+
iconHue: 'teal',
|
|
17
28
|
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-masonry',
|
|
29
|
+
spec: 'PLUGIN.mdl',
|
|
18
30
|
screenshots: [],
|
|
19
|
-
};
|
|
31
|
+
});
|
package/src/plugin.ts
ADDED
package/src/types/Masonry.ts
CHANGED
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import
|
|
7
|
+
// QueryAST is referenced indirectly through `Type.InstanceType<typeof MasonrySchema>`
|
|
8
|
+
// (Ref.Ref(View.View) → View.View → QueryAST.Query) in the emitted .d.ts; the
|
|
9
|
+
// namespace import keeps the inferred types portable.
|
|
10
|
+
// eslint-disable-next-line unused-imports/no-unused-imports
|
|
11
|
+
import { DXN, Annotation, Obj, QueryAST, Ref, Type, View } from '@dxos/echo';
|
|
12
|
+
import { FormInputAnnotation, LabelAnnotation } from '@dxos/echo/Annotation';
|
|
10
13
|
import { ViewAnnotation } from '@dxos/schema';
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
const MasonrySchema = Schema.Struct({
|
|
13
16
|
name: Schema.String.pipe(Schema.optional),
|
|
14
17
|
|
|
15
18
|
view: Ref.Ref(View.View).pipe(FormInputAnnotation.set(false)),
|
|
@@ -22,19 +25,15 @@ export const Masonry = Schema.Struct({
|
|
|
22
25
|
).pipe(FormInputAnnotation.set(false), Schema.optional),
|
|
23
26
|
// TODO(wittjosiah): Consider Masonry supporting not being just a view but referencing arbitrary data directly.
|
|
24
27
|
}).pipe(
|
|
25
|
-
Type.object({
|
|
26
|
-
typename: 'org.dxos.type.masonry',
|
|
27
|
-
version: '0.1.0',
|
|
28
|
-
}),
|
|
29
28
|
LabelAnnotation.set(['name']),
|
|
30
|
-
ViewAnnotation.set(
|
|
31
|
-
Annotation.IconAnnotation.set({
|
|
32
|
-
|
|
33
|
-
hue: 'green',
|
|
34
|
-
}),
|
|
29
|
+
ViewAnnotation.set(['view']),
|
|
30
|
+
Annotation.IconAnnotation.set({ icon: 'ph--wall--regular', hue: 'green' }),
|
|
31
|
+
Type.makeObject(DXN.make('org.dxos.type.masonry', '0.1.0')),
|
|
35
32
|
);
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
// TODO(wittjosiah): Try to clean up this type inference.
|
|
35
|
+
export interface Masonry extends Type.InstanceType<typeof MasonrySchema> {}
|
|
36
|
+
export const Masonry: Type.Obj<Masonry> = MasonrySchema as any;
|
|
38
37
|
|
|
39
38
|
type MakeProps = Omit<Partial<Obj.MakeProps<typeof Masonry>>, 'view'> & {
|
|
40
39
|
view: View.View;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
-
import { TypeInputOptionsAnnotation } from '@dxos/plugin-space
|
|
7
|
+
import { TypeInputOptionsAnnotation } from '@dxos/plugin-space';
|
|
8
8
|
|
|
9
9
|
export const MasonryProps = Schema.Struct({
|
|
10
10
|
name: Schema.optional(Schema.String),
|