@dxos/plugin-masonry 0.8.4-main.fcc0d83b33 → 0.8.4-staging.60fe92afc8

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 (79) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +328 -0
  3. package/README.md +1 -1
  4. package/dist/lib/neutral/MasonryContainer-7CXOATRR.mjs +96 -0
  5. package/dist/lib/neutral/MasonryContainer-7CXOATRR.mjs.map +7 -0
  6. package/dist/lib/neutral/MasonryPlugin.mjs +38 -0
  7. package/dist/lib/neutral/MasonryPlugin.mjs.map +7 -0
  8. package/dist/lib/neutral/capabilities/index.mjs +11 -0
  9. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  10. package/dist/lib/{browser/types/index.mjs → neutral/chunk-CNXGZZNQ.mjs} +12 -14
  11. package/dist/lib/neutral/chunk-CNXGZZNQ.mjs.map +7 -0
  12. package/dist/lib/neutral/chunk-IJ2FIXSI.mjs +32 -0
  13. package/dist/lib/neutral/chunk-IJ2FIXSI.mjs.map +7 -0
  14. package/dist/lib/neutral/components/index.mjs +1 -0
  15. package/dist/lib/neutral/containers/index.mjs +9 -0
  16. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  17. package/dist/lib/neutral/create-object-WRCYV4HT.mjs +39 -0
  18. package/dist/lib/neutral/create-object-WRCYV4HT.mjs.map +7 -0
  19. package/dist/lib/neutral/index.mjs +14 -0
  20. package/dist/lib/neutral/index.mjs.map +7 -0
  21. package/dist/lib/neutral/meta.json +1 -0
  22. package/dist/lib/neutral/meta.mjs +8 -0
  23. package/dist/lib/neutral/meta.mjs.map +7 -0
  24. package/dist/lib/neutral/plugin.mjs +12 -0
  25. package/dist/lib/neutral/plugin.mjs.map +7 -0
  26. package/dist/lib/neutral/react-surface-7CZHE3XA.mjs +35 -0
  27. package/dist/lib/neutral/react-surface-7CZHE3XA.mjs.map +7 -0
  28. package/dist/lib/neutral/types/index.mjs +10 -0
  29. package/dist/lib/neutral/types/index.mjs.map +7 -0
  30. package/dist/types/src/MasonryPlugin.d.ts +1 -0
  31. package/dist/types/src/MasonryPlugin.d.ts.map +1 -1
  32. package/dist/types/src/MasonryPlugin.test.d.ts +2 -0
  33. package/dist/types/src/MasonryPlugin.test.d.ts.map +1 -0
  34. package/dist/types/src/capabilities/create-object.d.ts +11 -0
  35. package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
  36. package/dist/types/src/capabilities/index.d.ts +6 -0
  37. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  38. package/dist/types/src/containers/MasonryContainer/MasonryContainer.d.ts +1 -2
  39. package/dist/types/src/containers/MasonryContainer/MasonryContainer.d.ts.map +1 -1
  40. package/dist/types/src/index.d.ts +1 -1
  41. package/dist/types/src/index.d.ts.map +1 -1
  42. package/dist/types/src/meta.d.ts +1 -1
  43. package/dist/types/src/meta.d.ts.map +1 -1
  44. package/dist/types/src/plugin.d.ts +3 -0
  45. package/dist/types/src/plugin.d.ts.map +1 -0
  46. package/dist/types/src/types/Masonry.d.ts +5 -5
  47. package/dist/types/src/types/Masonry.d.ts.map +1 -1
  48. package/dist/types/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +74 -49
  50. package/src/MasonryPlugin.test.ts +26 -0
  51. package/src/MasonryPlugin.tsx +11 -33
  52. package/src/capabilities/create-object.ts +36 -0
  53. package/src/capabilities/index.ts +1 -0
  54. package/src/capabilities/react-surface.tsx +1 -2
  55. package/src/containers/MasonryContainer/MasonryContainer.stories.tsx +5 -5
  56. package/src/containers/MasonryContainer/MasonryContainer.tsx +28 -37
  57. package/src/index.ts +1 -2
  58. package/src/meta.ts +19 -7
  59. package/src/plugin.ts +9 -0
  60. package/src/types/Masonry.ts +12 -13
  61. package/src/types/MasonryAction.ts +1 -1
  62. package/src/vite-env.d.ts +10 -0
  63. package/dist/lib/browser/index.mjs +0 -71
  64. package/dist/lib/browser/index.mjs.map +0 -7
  65. package/dist/lib/browser/meta.json +0 -1
  66. package/dist/lib/browser/types/index.mjs.map +0 -7
  67. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  68. package/dist/lib/node-esm/index.mjs +0 -72
  69. package/dist/lib/node-esm/index.mjs.map +0 -7
  70. package/dist/lib/node-esm/meta.json +0 -1
  71. package/dist/lib/node-esm/translations.mjs +0 -31
  72. package/dist/lib/node-esm/translations.mjs.map +0 -7
  73. package/dist/lib/node-esm/types/index.mjs +0 -69
  74. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  75. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
  76. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs.map +0 -0
  77. /package/dist/lib/{node-esm/chunk-HSLMI22Q.mjs.map → neutral/components/index.mjs.map} +0 -0
  78. /package/dist/lib/{browser → neutral}/translations.mjs +0 -0
  79. /package/dist/lib/{browser → neutral}/translations.mjs.map +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-masonry",
3
- "version": "0.8.4-main.fcc0d83b33",
3
+ "version": "0.8.4-staging.60fe92afc8",
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": "MIT",
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": "./src/capabilities/index.ts",
17
- "#components": "./src/components/index.ts",
18
- "#containers": "./src/containers/index.ts",
19
- "#meta": "./src/meta.ts",
20
- "#translations": "./src/translations.ts",
21
- "#types": "./src/types/index.ts"
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
+ }
22
51
  },
23
52
  "exports": {
24
53
  ".": {
25
54
  "source": "./src/index.ts",
26
55
  "types": "./dist/types/src/index.d.ts",
27
- "browser": "./dist/lib/browser/index.mjs",
28
- "node": "./dist/lib/node-esm/index.mjs"
56
+ "default": "./dist/lib/neutral/index.mjs"
57
+ },
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"
29
63
  },
30
64
  "./translations": {
31
65
  "source": "./src/translations.ts",
32
66
  "types": "./dist/types/src/translations.d.ts",
33
- "browser": "./dist/lib/browser/translations.mjs",
34
- "node": "./dist/lib/node-esm/translations.mjs"
35
- },
36
- "./types": {
37
- "source": "./src/types/index.ts",
38
- "types": "./dist/types/src/types/index.d.ts",
39
- "browser": "./dist/lib/browser/types/index.mjs",
40
- "node": "./dist/lib/node-esm/types/index.mjs"
67
+ "default": "./dist/lib/neutral/translations.mjs"
41
68
  }
42
69
  },
43
70
  "types": "dist/types/src/index.d.ts",
44
71
  "files": [
45
72
  "dist",
46
- "src"
73
+ "src",
74
+ "PLUGIN.mdl"
47
75
  ],
48
76
  "dependencies": {
49
- "@dxos/compute": "0.8.4-main.fcc0d83b33",
50
- "@dxos/app-framework": "0.8.4-main.fcc0d83b33",
51
- "@dxos/app-toolkit": "0.8.4-main.fcc0d83b33",
52
- "@dxos/echo": "0.8.4-main.fcc0d83b33",
53
- "@dxos/plugin-client": "0.8.4-main.fcc0d83b33",
54
- "@dxos/effect": "0.8.4-main.fcc0d83b33",
55
- "@dxos/plugin-search": "0.8.4-main.fcc0d83b33",
56
- "@dxos/plugin-space": "0.8.4-main.fcc0d83b33",
57
- "@dxos/react-client": "0.8.4-main.fcc0d83b33",
58
- "@dxos/react-ui-form": "0.8.4-main.fcc0d83b33",
59
- "@dxos/react-ui": "0.8.4-main.fcc0d83b33",
60
- "@dxos/react-ui-masonry": "0.8.4-main.fcc0d83b33",
61
- "@dxos/react-ui-mosaic": "0.8.4-main.fcc0d83b33",
62
- "@dxos/react-ui-menu": "0.8.4-main.fcc0d83b33",
63
- "@dxos/react-ui-search": "0.8.4-main.fcc0d83b33",
64
- "@dxos/react-ui-stack": "0.8.4-main.fcc0d83b33",
65
- "@dxos/schema": "0.8.4-main.fcc0d83b33",
66
- "@dxos/types": "0.8.4-main.fcc0d83b33",
67
- "@dxos/util": "0.8.4-main.fcc0d83b33"
77
+ "@dxos/app-toolkit": "0.8.4-staging.60fe92afc8",
78
+ "@dxos/app-framework": "0.8.4-staging.60fe92afc8",
79
+ "@dxos/compute": "0.8.4-staging.60fe92afc8",
80
+ "@dxos/keys": "0.8.4-staging.60fe92afc8",
81
+ "@dxos/effect": "0.8.4-staging.60fe92afc8",
82
+ "@dxos/echo": "0.8.4-staging.60fe92afc8",
83
+ "@dxos/plugin-client": "0.8.4-staging.60fe92afc8",
84
+ "@dxos/react-client": "0.8.4-staging.60fe92afc8",
85
+ "@dxos/plugin-space": "0.8.4-staging.60fe92afc8",
86
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8",
87
+ "@dxos/react-ui-menu": "0.8.4-staging.60fe92afc8",
88
+ "@dxos/react-ui-search": "0.8.4-staging.60fe92afc8",
89
+ "@dxos/react-ui-masonry": "0.8.4-staging.60fe92afc8",
90
+ "@dxos/types": "0.8.4-staging.60fe92afc8",
91
+ "@dxos/schema": "0.8.4-staging.60fe92afc8",
92
+ "@dxos/util": "0.8.4-staging.60fe92afc8"
68
93
  },
69
94
  "devDependencies": {
70
95
  "@types/react": "~19.2.7",
71
96
  "@types/react-dom": "~19.2.3",
72
- "effect": "3.20.0",
97
+ "effect": "3.21.3",
73
98
  "react": "~19.2.3",
74
99
  "react-dom": "~19.2.3",
75
- "vite": "^8.0.10",
76
- "@dxos/plugin-preview": "0.8.4-main.fcc0d83b33",
77
- "@dxos/plugin-testing": "0.8.4-main.fcc0d83b33",
78
- "@dxos/random": "0.8.4-main.fcc0d83b33",
79
- "@dxos/plugin-theme": "0.8.4-main.fcc0d83b33",
80
- "@dxos/storybook-utils": "0.8.4-main.fcc0d83b33",
81
- "@dxos/ui-theme": "0.8.4-main.fcc0d83b33"
100
+ "vite": "^8.0.16",
101
+ "@dxos/plugin-preview": "0.8.4-staging.60fe92afc8",
102
+ "@dxos/plugin-testing": "0.8.4-staging.60fe92afc8",
103
+ "@dxos/storybook-utils": "0.8.4-staging.60fe92afc8",
104
+ "@dxos/plugin-theme": "0.8.4-staging.60fe92afc8",
105
+ "@dxos/ui-theme": "0.8.4-staging.60fe92afc8",
106
+ "@dxos/random": "0.8.4-staging.60fe92afc8"
82
107
  },
83
108
  "peerDependencies": {
84
- "effect": "3.20.0",
109
+ "effect": "3.21.3",
85
110
  "react": "~19.2.3",
86
111
  "react-dom": "~19.2.3",
87
- "@dxos/react-ui": "0.8.4-main.fcc0d83b33",
88
- "@dxos/ui-theme": "0.8.4-main.fcc0d83b33"
112
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8",
113
+ "@dxos/ui-theme": "0.8.4-staging.60fe92afc8"
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
+ });
@@ -2,48 +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 { Operation } from '@dxos/compute';
11
- import { Annotation, Type } from '@dxos/echo';
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
10
  import { translations } from '#translations';
19
- import { Masonry, MasonryAction } from '#types';
11
+ import { Masonry } from '#types';
12
+
13
+ // eslint-disable-next-line import/no-relative-packages
14
+ import pluginSpec from '../PLUGIN.mdl?raw';
20
15
 
21
16
  export const MasonryPlugin = Plugin.define(meta).pipe(
22
- AppPlugin.addMetadataModule({
23
- metadata: {
24
- id: Type.getTypename(Masonry.Masonry),
25
- metadata: {
26
- icon: Annotation.IconAnnotation.get(Masonry.Masonry).pipe(Option.getOrThrow).icon,
27
- iconHue: Annotation.IconAnnotation.get(Masonry.Masonry).pipe(Option.getOrThrow).hue ?? 'white',
28
- inputSchema: MasonryAction.MasonryProps,
29
- createObject: ((props, options) =>
30
- Effect.gen(function* () {
31
- const object = yield* Effect.promise(async () => {
32
- const { view } = await ViewModel.makeFromDatabase({ db: options.db, typename: props.typename });
33
- return Masonry.make({ name: props.name, view });
34
- });
35
- return yield* Operation.invoke(SpaceOperation.AddObject, {
36
- object,
37
- target: options.target,
38
- hidden: true,
39
- targetNodeId: options.targetNodeId,
40
- });
41
- })) satisfies CreateObject,
42
- },
43
- },
44
- }),
17
+ AppPlugin.addCreateObjectModule({ activate: CreateObject }),
45
18
  AppPlugin.addSchemaModule({ schema: [Masonry.Masonry] }),
46
19
  AppPlugin.addSurfaceModule({ activate: ReactSurface }),
47
20
  AppPlugin.addTranslationsModule({ translations }),
21
+ AppPlugin.addPluginAssetModule({
22
+ asset: { pluginId: meta.id, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
23
+ }),
48
24
  Plugin.make,
49
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
+ );
@@ -4,4 +4,5 @@
4
4
 
5
5
  import { Capability } from '@dxos/app-framework';
6
6
 
7
+ export const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));
7
8
  export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -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 { Filter, useObject, useQuery, useSpaces } from '@dxos/react-client/echo';
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.typename,
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 { Annotation, Filter, Obj, Query, type Ref, Type } from '@dxos/echo';
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, getTypenameFromQuery } from '@dxos/schema';
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 typename = view?.query ? getTypenameFromQuery(view.query.ast) : undefined;
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<Schema.Schema.AnyNoContext>();
37
+ const [cardSchema, setCardSchema] = useState<Type.AnyEntity>();
42
38
 
43
39
  useEffect(() => {
44
- const staticSchema = schemas.flat().find((schema) => Type.getTypename(schema) === typename);
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 (!staticSchema && typename && db) {
49
- const query = db.schemaRegistry.query({ typename });
50
- const unsubscribe = query.subscribe(
51
- () => {
52
- const [schema] = query.results;
53
- if (schema) {
54
- setCardSchema(schema);
55
- }
56
- },
57
- { fire: true },
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
- }, [schemas, typename, db]);
56
+ setCardSchema(undefined);
57
+ }, [schemas, typeUri, db]);
62
58
 
63
- const query = useMemo(() => {
64
- const baseFilter = cardSchema ? Filter.type(cardSchema) : Filter.nothing();
65
- return tag ? Query.select(baseFilter).select(Filter.tag(tag)) : Query.select(baseFilter);
66
- }, [cardSchema, tag]);
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(
@@ -99,26 +96,20 @@ export const MasonryContainer = ({
99
96
 
100
97
  const Item = ({ data }: { data: any }) => {
101
98
  const objectMenuItems = useObjectMenuItems(data);
102
- const icon = Function.pipe(
103
- Obj.getSchema(data),
104
- Option.fromNullable,
105
- Option.flatMap(Annotation.IconAnnotation.get),
106
- Option.map(({ icon }) => icon),
107
- Option.getOrElse(() => 'ph--placeholder--regular'),
108
- );
99
+ const icon = Obj.getIcon(data)?.icon ?? 'ph--circle-dashed--regular';
109
100
 
110
101
  return (
111
102
  <Menu.Root>
112
103
  <Card.Root>
113
- <Card.Toolbar>
104
+ <Card.Header>
114
105
  <Card.Icon icon={icon} />
115
- <Card.Title>{Obj.getLabel(data)}</Card.Title>
106
+ <Card.Title>{Obj.getLabel(data, { fallback: 'typename' })}</Card.Title>
116
107
  {/* TODO(wittjosiah): Reconcile with Card.Menu. */}
117
108
  <Menu.Trigger asChild disabled={!objectMenuItems?.length}>
118
109
  <Toolbar.IconButton iconOnly variant='ghost' icon='ph--dots-three-vertical--regular' label='Actions' />
119
110
  </Menu.Trigger>
120
111
  <Menu.Content items={objectMenuItems} />
121
- </Card.Toolbar>
112
+ </Card.Header>
122
113
  <Surface.Surface
123
114
  type={AppSurface.Card}
124
115
  limit={1}
package/src/index.ts CHANGED
@@ -3,5 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './meta';
6
-
7
- export * from './MasonryPlugin';
6
+ export * from './types';
package/src/meta.ts CHANGED
@@ -2,18 +2,30 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Plugin } from '@dxos/app-framework';
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: Plugin.Meta = {
9
- id: 'org.dxos.plugin.masonry',
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
- Responsive grid layout that displays query results in an adaptive masonry pattern.
13
- Visualize collections of cards, images, or mixed content that automatically adjusts to available screen space.
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: 'green',
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
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Plugin } from '@dxos/app-framework';
6
+
7
+ import { meta } from './meta';
8
+
9
+ export const MasonryPlugin = Plugin.lazy(meta, () => import('#plugin'));
@@ -4,12 +4,15 @@
4
4
 
5
5
  import * as Schema from 'effect/Schema';
6
6
 
7
- import { Annotation, Obj, Ref, Type } from '@dxos/echo';
8
- import { View } from '@dxos/echo';
9
- import { FormInputAnnotation, LabelAnnotation } from '@dxos/echo/internal';
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
- export const Masonry = Schema.Struct({
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
29
  ViewAnnotation.set(['view']),
31
- Annotation.IconAnnotation.set({
32
- icon: 'ph--wall--regular',
33
- hue: 'green',
34
- }),
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
- export interface Masonry extends Schema.Schema.Type<typeof Masonry> {}
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/types';
7
+ import { TypeInputOptionsAnnotation } from '@dxos/plugin-space';
8
8
 
9
9
  export const MasonryProps = Schema.Struct({
10
10
  name: Schema.optional(Schema.String),
@@ -0,0 +1,10 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ //
4
+ // Copyright 2026 DXOS.org
5
+ //
6
+
7
+ declare module '*.mdl?raw' {
8
+ const content: string;
9
+ export default content;
10
+ }
@@ -1,71 +0,0 @@
1
- import "./chunk-J5LGTIGS.mjs";
2
-
3
- // src/meta.ts
4
- import { trim } from "@dxos/util";
5
- var meta = {
6
- id: "org.dxos.plugin.masonry",
7
- name: "Masonry",
8
- description: trim`
9
- Responsive grid layout that displays query results in an adaptive masonry pattern.
10
- Visualize collections of cards, images, or mixed content that automatically adjusts to available screen space.
11
- `,
12
- icon: "ph--wall--regular",
13
- iconHue: "green",
14
- source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-masonry",
15
- screenshots: []
16
- };
17
-
18
- // src/MasonryPlugin.tsx
19
- import * as Effect from "effect/Effect";
20
- import * as Option from "effect/Option";
21
- import { Plugin } from "@dxos/app-framework";
22
- import { AppPlugin } from "@dxos/app-toolkit";
23
- import { Operation } from "@dxos/compute";
24
- import { Annotation, Type } from "@dxos/echo";
25
- import { SpaceOperation } from "@dxos/plugin-space/operations";
26
- import { ViewModel } from "@dxos/schema";
27
- import { ReactSurface } from "#capabilities";
28
- import { meta as meta2 } from "#meta";
29
- import { translations } from "#translations";
30
- import { Masonry, MasonryAction } from "#types";
31
- var MasonryPlugin = Plugin.define(meta2).pipe(AppPlugin.addMetadataModule({
32
- metadata: {
33
- id: Type.getTypename(Masonry.Masonry),
34
- metadata: {
35
- icon: Annotation.IconAnnotation.get(Masonry.Masonry).pipe(Option.getOrThrow).icon,
36
- iconHue: Annotation.IconAnnotation.get(Masonry.Masonry).pipe(Option.getOrThrow).hue ?? "white",
37
- inputSchema: MasonryAction.MasonryProps,
38
- createObject: (props, options) => Effect.gen(function* () {
39
- const object = yield* Effect.promise(async () => {
40
- const { view } = await ViewModel.makeFromDatabase({
41
- db: options.db,
42
- typename: props.typename
43
- });
44
- return Masonry.make({
45
- name: props.name,
46
- view
47
- });
48
- });
49
- return yield* Operation.invoke(SpaceOperation.AddObject, {
50
- object,
51
- target: options.target,
52
- hidden: true,
53
- targetNodeId: options.targetNodeId
54
- });
55
- })
56
- }
57
- }
58
- }), AppPlugin.addSchemaModule({
59
- schema: [
60
- Masonry.Masonry
61
- ]
62
- }), AppPlugin.addSurfaceModule({
63
- activate: ReactSurface
64
- }), AppPlugin.addTranslationsModule({
65
- translations
66
- }), Plugin.make);
67
- export {
68
- MasonryPlugin,
69
- meta
70
- };
71
- //# sourceMappingURL=index.mjs.map