@dxos/plugin-preview 0.8.3 → 0.8.4-main.03d5cd7b56

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 (135) hide show
  1. package/dist/lib/neutral/PreviewPlugin.mjs +9 -0
  2. package/dist/lib/neutral/PreviewPlugin.mjs.map +7 -0
  3. package/dist/lib/neutral/PreviewPlugin.node.mjs +17 -0
  4. package/dist/lib/neutral/PreviewPlugin.node.mjs.map +7 -0
  5. package/dist/lib/neutral/capabilities/index.mjs +9 -0
  6. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  7. package/dist/lib/neutral/chunk-3SWUVHXJ.mjs +28 -0
  8. package/dist/lib/neutral/chunk-3SWUVHXJ.mjs.map +7 -0
  9. package/dist/lib/neutral/chunk-52UEVZSF.mjs +17 -0
  10. package/dist/lib/neutral/chunk-52UEVZSF.mjs.map +7 -0
  11. package/dist/lib/neutral/index.mjs +7 -0
  12. package/dist/lib/neutral/index.mjs.map +7 -0
  13. package/dist/lib/neutral/meta.json +1 -0
  14. package/dist/lib/neutral/meta.mjs +7 -0
  15. package/dist/lib/neutral/meta.mjs.map +7 -0
  16. package/dist/lib/neutral/plugin.mjs +11 -0
  17. package/dist/lib/neutral/plugin.mjs.map +7 -0
  18. package/dist/lib/neutral/preview-popover-MPPEMUIA.mjs +78 -0
  19. package/dist/lib/neutral/preview-popover-MPPEMUIA.mjs.map +7 -0
  20. package/dist/lib/neutral/react-surface-YFFJXXPQ.mjs +348 -0
  21. package/dist/lib/neutral/react-surface-YFFJXXPQ.mjs.map +7 -0
  22. package/dist/lib/neutral/testing.mjs +7 -0
  23. package/dist/lib/neutral/testing.mjs.map +7 -0
  24. package/dist/lib/neutral/translations.mjs +21 -0
  25. package/dist/lib/neutral/translations.mjs.map +7 -0
  26. package/dist/types/src/PreviewPlugin.d.ts +3 -1
  27. package/dist/types/src/PreviewPlugin.d.ts.map +1 -1
  28. package/dist/types/src/PreviewPlugin.node.d.ts +4 -0
  29. package/dist/types/src/PreviewPlugin.node.d.ts.map +1 -0
  30. package/dist/types/src/PreviewPlugin.test.d.ts +2 -0
  31. package/dist/types/src/PreviewPlugin.test.d.ts.map +1 -0
  32. package/dist/types/src/capabilities/index.d.ts +3 -2
  33. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  34. package/dist/types/src/capabilities/preview-popover.d.ts +3 -2
  35. package/dist/types/src/capabilities/preview-popover.d.ts.map +1 -1
  36. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  37. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  38. package/dist/types/src/cards/ExpandoCard.d.ts +4 -0
  39. package/dist/types/src/cards/ExpandoCard.d.ts.map +1 -0
  40. package/dist/types/src/cards/FormCard.d.ts +7 -0
  41. package/dist/types/src/cards/FormCard.d.ts.map +1 -0
  42. package/dist/types/src/cards/JsonCard.d.ts +5 -0
  43. package/dist/types/src/cards/JsonCard.d.ts.map +1 -0
  44. package/dist/types/src/cards/OrganizationCard.d.ts +5 -0
  45. package/dist/types/src/cards/OrganizationCard.d.ts.map +1 -0
  46. package/dist/types/src/cards/PersonCard.d.ts +5 -0
  47. package/dist/types/src/cards/PersonCard.d.ts.map +1 -0
  48. package/dist/types/src/cards/ProjectCard.d.ts +5 -0
  49. package/dist/types/src/cards/ProjectCard.d.ts.map +1 -0
  50. package/dist/types/src/cards/TaskCard.d.ts +5 -0
  51. package/dist/types/src/cards/TaskCard.d.ts.map +1 -0
  52. package/dist/types/src/cards/index.d.ts +8 -0
  53. package/dist/types/src/cards/index.d.ts.map +1 -0
  54. package/dist/types/src/index.d.ts +0 -2
  55. package/dist/types/src/index.d.ts.map +1 -1
  56. package/dist/types/src/meta.d.ts +2 -3
  57. package/dist/types/src/meta.d.ts.map +1 -1
  58. package/dist/types/src/plugin.d.ts +3 -0
  59. package/dist/types/src/plugin.d.ts.map +1 -0
  60. package/dist/types/src/stories/Card.stories.d.ts +38 -0
  61. package/dist/types/src/stories/Card.stories.d.ts.map +1 -0
  62. package/dist/types/src/stories/testing.d.ts +21 -0
  63. package/dist/types/src/stories/testing.d.ts.map +1 -0
  64. package/dist/types/src/testing.d.ts +2 -0
  65. package/dist/types/src/testing.d.ts.map +1 -0
  66. package/dist/types/src/translations.d.ts +11 -6
  67. package/dist/types/src/translations.d.ts.map +1 -1
  68. package/dist/types/tsconfig.tsbuildinfo +1 -1
  69. package/package.json +88 -34
  70. package/src/PreviewPlugin.node.ts +16 -0
  71. package/src/PreviewPlugin.test.ts +25 -0
  72. package/src/PreviewPlugin.tsx +19 -29
  73. package/src/capabilities/index.ts +3 -3
  74. package/src/capabilities/preview-popover.ts +71 -49
  75. package/src/capabilities/react-surface.tsx +108 -120
  76. package/src/cards/ExpandoCard.tsx +76 -0
  77. package/src/cards/FormCard.tsx +48 -0
  78. package/src/cards/JsonCard.tsx +19 -0
  79. package/src/cards/OrganizationCard.tsx +29 -0
  80. package/src/cards/PersonCard.tsx +65 -0
  81. package/src/cards/ProjectCard.tsx +22 -0
  82. package/src/cards/TaskCard.tsx +44 -0
  83. package/src/cards/index.ts +11 -0
  84. package/src/index.ts +0 -3
  85. package/src/meta.ts +8 -5
  86. package/src/plugin.ts +9 -0
  87. package/src/stories/Card.stories.tsx +121 -0
  88. package/src/stories/testing.tsx +101 -0
  89. package/src/testing.ts +7 -0
  90. package/src/translations.ts +13 -5
  91. package/dist/lib/browser/chunk-LFAK2TMG.mjs +0 -14
  92. package/dist/lib/browser/chunk-LFAK2TMG.mjs.map +0 -7
  93. package/dist/lib/browser/index.mjs +0 -60
  94. package/dist/lib/browser/index.mjs.map +0 -7
  95. package/dist/lib/browser/meta.json +0 -1
  96. package/dist/lib/browser/preview-popover-NRFVC4QQ.mjs +0 -69
  97. package/dist/lib/browser/preview-popover-NRFVC4QQ.mjs.map +0 -7
  98. package/dist/lib/browser/react-surface-J2R6Q33B.mjs +0 -272
  99. package/dist/lib/browser/react-surface-J2R6Q33B.mjs.map +0 -7
  100. package/dist/lib/node/chunk-XGHMBEIV.cjs +0 -37
  101. package/dist/lib/node/chunk-XGHMBEIV.cjs.map +0 -7
  102. package/dist/lib/node/index.cjs +0 -85
  103. package/dist/lib/node/index.cjs.map +0 -7
  104. package/dist/lib/node/meta.json +0 -1
  105. package/dist/lib/node/preview-popover-HIXRYF6L.cjs +0 -88
  106. package/dist/lib/node/preview-popover-HIXRYF6L.cjs.map +0 -7
  107. package/dist/lib/node/react-surface-ZSNNAKBG.cjs +0 -290
  108. package/dist/lib/node/react-surface-ZSNNAKBG.cjs.map +0 -7
  109. package/dist/lib/node-esm/chunk-7BPXNL44.mjs +0 -16
  110. package/dist/lib/node-esm/chunk-7BPXNL44.mjs.map +0 -7
  111. package/dist/lib/node-esm/index.mjs +0 -61
  112. package/dist/lib/node-esm/index.mjs.map +0 -7
  113. package/dist/lib/node-esm/meta.json +0 -1
  114. package/dist/lib/node-esm/preview-popover-HBGSL64N.mjs +0 -71
  115. package/dist/lib/node-esm/preview-popover-HBGSL64N.mjs.map +0 -7
  116. package/dist/lib/node-esm/react-surface-UKEVHG5K.mjs +0 -273
  117. package/dist/lib/node-esm/react-surface-UKEVHG5K.mjs.map +0 -7
  118. package/dist/types/src/Preview.stories.d.ts +0 -127
  119. package/dist/types/src/Preview.stories.d.ts.map +0 -1
  120. package/dist/types/src/components/ContactCard.d.ts +0 -7
  121. package/dist/types/src/components/ContactCard.d.ts.map +0 -1
  122. package/dist/types/src/components/OrganizationCard.d.ts +0 -5
  123. package/dist/types/src/components/OrganizationCard.d.ts.map +0 -1
  124. package/dist/types/src/components/ProjectCard.d.ts +0 -5
  125. package/dist/types/src/components/ProjectCard.d.ts.map +0 -1
  126. package/dist/types/src/components/index.d.ts +0 -4
  127. package/dist/types/src/components/index.d.ts.map +0 -1
  128. package/dist/types/src/types.d.ts +0 -6
  129. package/dist/types/src/types.d.ts.map +0 -1
  130. package/src/Preview.stories.tsx +0 -147
  131. package/src/components/ContactCard.tsx +0 -70
  132. package/src/components/OrganizationCard.tsx +0 -41
  133. package/src/components/ProjectCard.tsx +0 -20
  134. package/src/components/index.ts +0 -7
  135. package/src/types.ts +0 -11
package/package.json CHANGED
@@ -1,61 +1,115 @@
1
1
  {
2
2
  "name": "@dxos/plugin-preview",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-main.03d5cd7b56",
4
4
  "description": "Preview plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
13
  "sideEffects": true,
10
14
  "type": "module",
15
+ "imports": {
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
+ "#meta": {
22
+ "source": "./src/meta.ts",
23
+ "types": "./dist/types/src/meta.d.ts",
24
+ "default": "./dist/lib/neutral/meta.mjs"
25
+ },
26
+ "#plugin": {
27
+ "source": {
28
+ "node": "./src/PreviewPlugin.node.ts",
29
+ "default": "./src/PreviewPlugin.tsx"
30
+ },
31
+ "types": "./dist/types/src/PreviewPlugin.d.ts",
32
+ "node": "./dist/lib/neutral/PreviewPlugin.node.mjs",
33
+ "default": "./dist/lib/neutral/PreviewPlugin.mjs"
34
+ },
35
+ "#translations": {
36
+ "source": "./src/translations.ts",
37
+ "types": "./dist/types/src/translations.d.ts",
38
+ "default": "./dist/lib/neutral/translations.mjs"
39
+ }
40
+ },
11
41
  "exports": {
12
42
  ".": {
43
+ "source": "./src/index.ts",
13
44
  "types": "./dist/types/src/index.d.ts",
14
- "browser": "./dist/lib/browser/index.mjs"
45
+ "default": "./dist/lib/neutral/index.mjs"
46
+ },
47
+ "./plugin": {
48
+ "source": "./src/plugin.ts",
49
+ "types": "./dist/types/src/plugin.d.ts",
50
+ "default": "./dist/lib/neutral/plugin.mjs"
51
+ },
52
+ "./testing": {
53
+ "source": "./src/testing.ts",
54
+ "types": "./dist/types/src/testing.d.ts",
55
+ "default": "./dist/lib/neutral/testing.mjs"
56
+ },
57
+ "./translations": {
58
+ "source": "./src/translations.ts",
59
+ "types": "./dist/types/src/translations.d.ts",
60
+ "default": "./dist/lib/neutral/translations.mjs"
15
61
  }
16
62
  },
17
63
  "types": "dist/types/src/index.d.ts",
18
- "typesVersions": {
19
- "*": {}
20
- },
21
64
  "files": [
22
65
  "dist",
23
66
  "src"
24
67
  ],
25
68
  "dependencies": {
26
- "@preact-signals/safe-react": "^0.9.0",
27
- "effect": "3.14.21",
28
- "@dxos/app-framework": "0.8.3",
29
- "@dxos/async": "0.8.3",
30
- "@dxos/echo": "0.8.3",
31
- "@dxos/echo-schema": "0.8.3",
32
- "@dxos/lit-ui": "0.8.3",
33
- "@dxos/plugin-client": "0.8.3",
34
- "@dxos/client": "0.8.3",
35
- "@dxos/log": "0.8.3",
36
- "@dxos/keys": "0.8.3",
37
- "@dxos/react-client": "0.8.3",
38
- "@dxos/react-ui": "0.8.3",
39
- "@dxos/react-ui-editor": "0.8.3",
40
- "@dxos/react-ui-stack": "0.8.3",
41
- "@dxos/react-ui-form": "0.8.3",
42
- "@dxos/react-ui-table": "0.8.3",
43
- "@dxos/react-ui-theme": "0.8.3",
44
- "@dxos/util": "0.8.3",
45
- "@dxos/schema": "0.8.3"
69
+ "@effect-atom/atom-react": "^0.5.0",
70
+ "@dxos/app-toolkit": "0.8.4-main.03d5cd7b56",
71
+ "@dxos/app-graph": "0.8.4-main.03d5cd7b56",
72
+ "@dxos/client": "0.8.4-main.03d5cd7b56",
73
+ "@dxos/echo": "0.8.4-main.03d5cd7b56",
74
+ "@dxos/async": "0.8.4-main.03d5cd7b56",
75
+ "@dxos/effect": "0.8.4-main.03d5cd7b56",
76
+ "@dxos/log": "0.8.4-main.03d5cd7b56",
77
+ "@dxos/keys": "0.8.4-main.03d5cd7b56",
78
+ "@dxos/lit-ui": "0.8.4-main.03d5cd7b56",
79
+ "@dxos/operation": "0.8.4-main.03d5cd7b56",
80
+ "@dxos/plugin-attention": "0.8.4-main.03d5cd7b56",
81
+ "@dxos/plugin-client": "0.8.4-main.03d5cd7b56",
82
+ "@dxos/react-ui": "0.8.4-main.03d5cd7b56",
83
+ "@dxos/plugin-deck": "0.8.4-main.03d5cd7b56",
84
+ "@dxos/react-client": "0.8.4-main.03d5cd7b56",
85
+ "@dxos/react-ui-menu": "0.8.4-main.03d5cd7b56",
86
+ "@dxos/react-ui-form": "0.8.4-main.03d5cd7b56",
87
+ "@dxos/react-ui-editor": "0.8.4-main.03d5cd7b56",
88
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.03d5cd7b56",
89
+ "@dxos/react-ui-mosaic": "0.8.4-main.03d5cd7b56",
90
+ "@dxos/app-framework": "0.8.4-main.03d5cd7b56",
91
+ "@dxos/react-ui-table": "0.8.4-main.03d5cd7b56",
92
+ "@dxos/schema": "0.8.4-main.03d5cd7b56",
93
+ "@dxos/types": "0.8.4-main.03d5cd7b56",
94
+ "@dxos/ui-theme": "0.8.4-main.03d5cd7b56",
95
+ "@dxos/ui-editor": "0.8.4-main.03d5cd7b56",
96
+ "@dxos/util": "0.8.4-main.03d5cd7b56"
46
97
  },
47
98
  "devDependencies": {
48
- "effect": "3.14.21",
49
- "react": "~18.2.0",
50
- "react-dom": "~18.2.0",
51
- "vite": "5.4.7",
52
- "@dxos/random": "0.8.3",
53
- "@dxos/storybook-utils": "0.8.3"
99
+ "effect": "3.20.0",
100
+ "react": "~19.2.3",
101
+ "react-dom": "~19.2.3",
102
+ "vite": "^8.0.10",
103
+ "@dxos/echo-db": "0.8.4-main.03d5cd7b56",
104
+ "@dxos/plugin-testing": "0.8.4-main.03d5cd7b56",
105
+ "@dxos/random": "0.8.4-main.03d5cd7b56",
106
+ "@dxos/react-ui-components": "0.8.4-main.03d5cd7b56",
107
+ "@dxos/storybook-utils": "0.8.4-main.03d5cd7b56"
54
108
  },
55
109
  "peerDependencies": {
56
- "effect": "^3.13.3",
57
- "react": "~18.2.0",
58
- "react-dom": "~18.2.0"
110
+ "effect": "3.20.0",
111
+ "react": "~19.2.3",
112
+ "react-dom": "~19.2.3"
59
113
  },
60
114
  "publishConfig": {
61
115
  "access": "public"
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { AppPlugin } from '@dxos/app-toolkit';
7
+ import { Organization, Person } from '@dxos/types';
8
+
9
+ import { meta } from '#meta';
10
+
11
+ export const PreviewPlugin = Plugin.define(meta).pipe(
12
+ AppPlugin.addSchemaModule({ schema: [Person.Person, Organization.Organization] }),
13
+ Plugin.make,
14
+ );
15
+
16
+ export default PreviewPlugin;
@@ -0,0 +1,25 @@
1
+ //
2
+ // Copyright 2026 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 { PreviewPlugin } from '#plugin';
11
+
12
+ import { meta } from './meta';
13
+
14
+ const moduleId = (name: string) => `${meta.id}.module.${name}`;
15
+
16
+ describe('PreviewPlugin', () => {
17
+ test('modules activate on the expected events', { timeout: 10_000 }, async ({ expect }) => {
18
+ await using harness = await createComposerTestApp({
19
+ plugins: [ClientPlugin({}), PreviewPlugin()],
20
+ });
21
+
22
+ // After autoStart: schema auto-cascades from ClientPlugin.
23
+ expect(harness.manager.getActive()).toContain(moduleId('schema'));
24
+ });
25
+ });
@@ -2,34 +2,24 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, Events, contributes, defineModule, definePlugin } from '@dxos/app-framework';
6
- import { ClientCapabilities, ClientEvents } from '@dxos/plugin-client';
7
- import { DataType } from '@dxos/schema';
5
+ import { ActivationEvents, Plugin } from '@dxos/app-framework';
6
+ import { AppPlugin } from '@dxos/app-toolkit';
7
+ import { Organization, Person } from '@dxos/types';
8
8
 
9
- import { PreviewPopover, ReactSurface } from './capabilities';
10
- import { meta } from './meta';
11
- import translations from './translations';
9
+ import { PreviewPopover, ReactSurface } from '#capabilities';
10
+ import { meta } from '#meta';
11
+ import { translations } from '#translations';
12
12
 
13
- export const PreviewPlugin = () =>
14
- definePlugin(meta, [
15
- defineModule({
16
- id: `${meta.id}/module/translations`,
17
- activatesOn: Events.SetupTranslations,
18
- activate: () => contributes(Capabilities.Translations, translations),
19
- }),
20
- defineModule({
21
- id: `${meta.id}/module/schema`,
22
- activatesOn: ClientEvents.SetupSchema,
23
- activate: () => [contributes(ClientCapabilities.Schema, [DataType.Person, DataType.Organization])],
24
- }),
25
- defineModule({
26
- id: `${meta.id}/module/preview-popover`,
27
- activatesOn: Events.Startup,
28
- activate: PreviewPopover,
29
- }),
30
- defineModule({
31
- id: `${meta.id}/module/react-surface`,
32
- activatesOn: Events.SetupReactSurface,
33
- activate: ReactSurface,
34
- }),
35
- ]);
13
+ export const PreviewPlugin = Plugin.define(meta).pipe(
14
+ AppPlugin.addSchemaModule({ schema: [Person.Person, Organization.Organization] }),
15
+ AppPlugin.addSurfaceModule({ activate: ReactSurface }),
16
+ AppPlugin.addTranslationsModule({ translations }),
17
+ Plugin.addModule({
18
+ id: 'preview-popover',
19
+ activatesOn: ActivationEvents.Startup,
20
+ activate: PreviewPopover,
21
+ }),
22
+ Plugin.make,
23
+ );
24
+
25
+ export default PreviewPlugin;
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { lazy } from '@dxos/app-framework';
5
+ import { Capability } from '@dxos/app-framework';
6
6
 
7
- export const PreviewPopover = lazy(() => import('./preview-popover'));
8
- export const ReactSurface = lazy(() => import('./react-surface'));
7
+ export const PreviewPopover = Capability.lazy('PreviewPopover', () => import('./preview-popover'));
8
+ export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -2,73 +2,95 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, LayoutAction, contributes, createIntent, type PluginContext } from '@dxos/app-framework';
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { AppCapabilities, LayoutOperation, getPersonalSpace, getSpaceIdFromPath } from '@dxos/app-toolkit';
6
9
  import { addEventListener } from '@dxos/async';
7
- import { type Client, resolveRef } from '@dxos/client';
8
- import { parseId, type Space } from '@dxos/client/echo';
10
+ import { type Client } from '@dxos/client';
11
+ import { type Space } from '@dxos/client/echo';
12
+ import { Obj } from '@dxos/echo';
9
13
  import { DXN } from '@dxos/keys';
10
- import { type DxRefTagActivate } from '@dxos/lit-ui';
11
14
  import { log } from '@dxos/log';
12
15
  import { ClientCapabilities } from '@dxos/plugin-client';
13
- import { type PreviewLinkRef, type PreviewLinkTarget } from '@dxos/react-ui-editor';
16
+ import { DX_ANCHOR_ACTIVATE, type DxAnchorActivate } from '@dxos/react-ui';
17
+ import { type PreviewLinkRef, type PreviewLinkTarget } from '@dxos/ui-editor';
14
18
 
15
19
  const customEventOptions = { capture: true, passive: false };
16
20
 
17
21
  const handlePreviewLookup = async (
18
22
  client: Client,
19
23
  defaultSpace: Space,
20
- { ref, label }: PreviewLinkRef,
24
+ { dxn, label }: PreviewLinkRef,
21
25
  ): Promise<PreviewLinkTarget | null> => {
22
26
  try {
23
- const dxn = DXN.parse(ref);
24
- if (!dxn) {
25
- return null;
26
- }
27
-
28
- const object = await resolveRef(client, dxn, defaultSpace);
27
+ const object = await defaultSpace.db.makeRef(DXN.parse(dxn)).load();
29
28
  return { label, object };
30
- } catch (err) {
29
+ } catch {
31
30
  return null;
32
31
  }
33
32
  };
34
33
 
35
- export default (context: PluginContext) => {
36
- // TODO(wittjosiah): Factor out lookup handlers to other plugins to make not ECHO-specific.
37
- const handleDxRefTagActivate = async ({ refId, label, trigger }: DxRefTagActivate) => {
38
- const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
39
- const client = context.getCapability(ClientCapabilities.Client);
40
- const [layout] = context.getCapabilities(Capabilities.Layout);
41
- const { spaceId } = parseId(layout.workspace);
42
- const space = (spaceId && client.spaces.get(spaceId)) ?? client.spaces.default;
43
- const result = await handlePreviewLookup(client, space, { ref: refId, label });
44
- if (!result) {
45
- return;
46
- }
34
+ export default Capability.makeModule(
35
+ Effect.fnUntraced(function* () {
36
+ // Get context for lazy capability access in callbacks.
37
+ const capabilities = yield* Capability.Service;
38
+
39
+ // TODO(wittjosiah): Factor out lookup handlers to other plugins to make not ECHO-specific.
40
+ const handleAnchorActivate = async ({
41
+ dxn,
42
+ label,
43
+ trigger,
44
+ kind = 'card',
45
+ title: titleProp,
46
+ side,
47
+ props,
48
+ }: DxAnchorActivate) => {
49
+ const { invokePromise } = capabilities.get(Capabilities.OperationInvoker);
50
+ const client = capabilities.get(ClientCapabilities.Client);
51
+ const registry = capabilities.get(Capabilities.AtomRegistry);
52
+ // Layout is optional: in standalone harnesses (Storybook, tests) no plugin contributes
53
+ // `AppCapabilities.Layout`, and `getAll` returns an empty array. Reading `registry.get(undefined)`
54
+ // would crash inside Atom's identity check (`'~atom/Serializable' in undefined`). When layout
55
+ // isn't available, fall through to the personal-space default.
56
+ const [layoutAtom] = capabilities.getAll(AppCapabilities.Layout);
57
+ const spaceId = layoutAtom && getSpaceIdFromPath(registry.get(layoutAtom).workspace);
58
+ const space = (spaceId && client.spaces.get(spaceId)) ?? getPersonalSpace(client);
59
+ if (!space) {
60
+ return;
61
+ }
62
+ const result = await handlePreviewLookup(client, space, { dxn, label });
63
+ if (!result) {
64
+ return;
65
+ }
47
66
 
48
- await dispatch(
49
- createIntent(LayoutAction.UpdatePopover, {
50
- part: 'popover',
67
+ const title = titleProp ?? Obj.getLabel(result.object);
68
+
69
+ await invokePromise(LayoutOperation.UpdatePopover, {
70
+ subjectRef: dxn,
51
71
  subject: result.object,
52
- options: {
53
- state: true,
54
- variant: 'virtual',
55
- anchor: trigger,
56
- },
57
- }),
58
- );
59
- };
72
+ state: true,
73
+ variant: 'virtual',
74
+ anchor: trigger,
75
+ ...(kind && { kind }),
76
+ ...(title && { title }),
77
+ ...(side && { side }),
78
+ ...(props && { props }),
79
+ });
80
+ };
60
81
 
61
- let cleanup: () => void;
62
- if (document.defaultView) {
63
- cleanup = addEventListener(
64
- document.defaultView,
65
- 'dx-ref-tag-activate' as any,
66
- handleDxRefTagActivate,
67
- customEventOptions,
68
- );
69
- } else {
70
- log.warn('No default view found');
71
- }
82
+ let cleanup: () => void;
83
+ if (document.defaultView) {
84
+ cleanup = addEventListener(
85
+ document.defaultView,
86
+ DX_ANCHOR_ACTIVATE as any,
87
+ handleAnchorActivate,
88
+ customEventOptions,
89
+ );
90
+ } else {
91
+ log.warn('no default view found');
92
+ }
72
93
 
73
- return contributes(Capabilities.Null, null, () => cleanup());
74
- };
94
+ return Capability.contributes(Capabilities.Null, null, () => Effect.sync(() => cleanup?.()));
95
+ }),
96
+ );
@@ -2,129 +2,117 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback } from 'react';
5
+ import * as Effect from 'effect/Effect';
6
+ import React from 'react';
6
7
 
7
- import {
8
- Capabilities,
9
- LayoutAction,
10
- Surface,
11
- contributes,
12
- createIntent,
13
- createSurface,
14
- useIntentDispatcher,
15
- } from '@dxos/app-framework';
16
- import { fullyQualifiedId, getSchema, getSpace } from '@dxos/client/echo';
17
- import { Obj, Filter } from '@dxos/echo';
18
- import { type JsonPath, setValue } from '@dxos/echo-schema';
19
- import { useTranslation } from '@dxos/react-ui';
20
- import { Form } from '@dxos/react-ui-form';
21
- import { Card } from '@dxos/react-ui-stack';
22
- import { TableType } from '@dxos/react-ui-table';
23
- import { descriptionMessage, mx } from '@dxos/react-ui-theme';
24
- import { DataType } from '@dxos/schema';
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
11
+ import { Obj } from '@dxos/echo';
12
+ import { Card } from '@dxos/react-ui';
13
+ import { Expando, type ProjectionModel } from '@dxos/schema';
14
+ import { Organization, Person, Pipeline, Task } from '@dxos/types';
25
15
 
26
- import { ContactCard, OrganizationCard, ProjectCard } from '../components';
27
- import { PREVIEW_PLUGIN } from '../meta';
16
+ import { ExpandoCard, FormCard, JsonCard, OrganizationCard, PersonCard, ProjectCard, TaskCard } from '../cards';
28
17
 
29
- export default () =>
30
- contributes(Capabilities.ReactSurface, [
31
- //
32
- // Specific schema types.
33
- //
34
- createSurface({
35
- id: `${PREVIEW_PLUGIN}/schema-popover--contact`,
36
- role: ['popover', 'card--kanban', 'card--document', 'card'],
37
- filter: (data): data is { subject: DataType.Person } => Obj.instanceOf(DataType.Person, data.subject),
38
- component: ({ data, role }) => {
39
- const { dispatchPromise: dispatch } = useIntentDispatcher();
40
- const handleOrgClick = useCallback(
41
- async (org: DataType.Organization) => {
42
- const space = getSpace(org);
43
- const tablesQuery = await space?.db.query(Filter.type(TableType)).run();
44
- const currentSpaceOrgTable = tablesQuery?.objects.find((table) => {
45
- return table.view?.target?.query?.typename === DataType.Organization.typename;
46
- });
47
- await dispatch(
48
- createIntent(LayoutAction.UpdatePopover, {
49
- part: 'popover',
50
- options: {
51
- state: false,
52
- anchorId: '',
53
- },
54
- }),
55
- );
56
- if (currentSpaceOrgTable) {
57
- return dispatch(
58
- createIntent(LayoutAction.Open, {
59
- part: 'main',
60
- subject: [fullyQualifiedId(currentSpaceOrgTable)],
61
- options: { workspace: space?.id },
62
- }),
63
- );
64
- }
65
- },
66
- [dispatch],
67
- );
68
- return (
69
- <ContactCard role={role} subject={data.subject} onOrgClick={handleOrgClick}>
70
- {role === 'popover' && <Surface role='related' data={data} />}
71
- </ContactCard>
72
- );
73
- },
74
- }),
75
- createSurface({
76
- id: `${PREVIEW_PLUGIN}/schema-popover--organization`,
77
- role: ['popover', 'card--kanban', 'card--document', 'card'],
78
- filter: (data): data is { subject: DataType.Organization } => Obj.instanceOf(DataType.Organization, data.subject),
79
- component: ({ data, role }) => (
80
- <OrganizationCard role={role} subject={data.subject}>
81
- {role === 'popover' && <Surface role='related' data={data} />}
82
- </OrganizationCard>
83
- ),
84
- }),
85
- createSurface({
86
- id: `${PREVIEW_PLUGIN}/schema-popover--project`,
87
- role: ['popover', 'card--kanban', 'card--document', 'card'],
88
- filter: (data): data is { subject: DataType.Project } => Obj.instanceOf(DataType.Project, data.subject),
89
- component: ({ data, role }) => <ProjectCard subject={data.subject} role={role} />,
90
- }),
18
+ export default Capability.makeModule(() =>
19
+ Effect.succeed(
20
+ Capability.contributes(Capabilities.ReactSurface, [
21
+ //
22
+ // Specific schema types.
23
+ // TODO(burdon): Create helpers and factor out.
24
+ //
91
25
 
92
- //
93
- // Fallback for any object.
94
- //
95
- createSurface({
96
- id: `${PREVIEW_PLUGIN}/fallback-popover`,
97
- role: ['popover', 'card--kanban', 'card--document', 'card'],
98
- position: 'fallback',
99
- filter: (data): data is { subject: Obj.Any } => Obj.isObject(data.subject),
100
- component: ({ data, role }) => {
101
- const schema = getSchema(data.subject);
102
- const { t } = useTranslation(PREVIEW_PLUGIN);
103
- if (!schema) {
104
- // TODO(burdon): Use Alert.
105
- return <p className={mx(descriptionMessage)}>{t('unable to create preview message')}</p>;
106
- }
26
+ Surface.create<{ subject: Person.Person }>({
27
+ id: 'schema-popover--contact',
28
+ position: 'hoist',
29
+ filter: AppSurface.object(AppSurface.Card, Person.Person),
30
+ component: ({ data, role }) => {
31
+ return (
32
+ <>
33
+ <PersonCard role={role} subject={data.subject} />
34
+ <Surface.Surface type={AppSurface.Related} data={data} limit={1} />
35
+ </>
36
+ );
37
+ },
38
+ }),
39
+ Surface.create({
40
+ id: 'schema-popover--organization',
41
+ position: 'hoist',
42
+ filter: AppSurface.object(AppSurface.Card, Organization.Organization),
43
+ component: ({ data, role }) => {
44
+ return (
45
+ <>
46
+ <OrganizationCard role={role} subject={data.subject} />
47
+ <Surface.Surface type={AppSurface.Related} data={data} limit={1} />
48
+ </>
49
+ );
50
+ },
51
+ }),
52
+ Surface.create({
53
+ id: 'schema-popover--project',
54
+ position: 'hoist',
55
+ filter: AppSurface.object(AppSurface.Card, Pipeline.Pipeline),
56
+ component: ({ data, role }) => {
57
+ return <ProjectCard role={role} subject={data.subject} />;
58
+ },
59
+ }),
60
+ Surface.create({
61
+ id: 'schema-popover--task',
62
+ position: 'hoist',
63
+ filter: AppSurface.object(AppSurface.Card, Task.Task),
64
+ component: ({ data, role }) => {
65
+ return <TaskCard role={role} subject={data.subject} />;
66
+ },
67
+ }),
68
+ Surface.create<AppSurface.ObjectCardData<Expando.Expando>>({
69
+ id: 'schema-popover--expando',
70
+ filter: AppSurface.object(AppSurface.Card, Expando.Expando),
71
+ component: ({ data, role }) => {
72
+ return <ExpandoCard role={role} subject={data.subject} ignorePaths={data.ignorePaths} />;
73
+ },
74
+ }),
107
75
 
108
- const handleSave = useCallback((values: any, { changed }: { changed: Record<string, boolean> }) => {
109
- const changedPaths = Object.keys(changed).filter((path) => changed[path]);
110
- for (const path of changedPaths) {
111
- const value = values[path];
112
- setValue(data.subject, path as JsonPath, value);
113
- }
114
- }, []);
76
+ //
77
+ // Fallback for any object.
78
+ //
115
79
 
116
- return (
117
- <Card.Container role={role}>
118
- <Form
119
- schema={schema}
120
- values={data.subject}
121
- readonly={role === 'popover'}
122
- onSave={handleSave}
123
- autoSave
124
- {...(role === 'card--kanban' && { outerSpacing: 'blockStart-0' })}
125
- />
126
- </Card.Container>
127
- );
128
- },
129
- }),
130
- ]);
80
+ Surface.create({
81
+ id: 'fallback-popover',
82
+ role: 'card--content',
83
+ position: 'fallback',
84
+ filter: (data): data is { subject: Obj.Unknown; projection?: ProjectionModel } => Obj.isObject(data.subject),
85
+ component: ({ data, role }) => {
86
+ return <FormCard role={role} subject={data.subject} projection={data.projection} />;
87
+ },
88
+ }),
89
+
90
+ Surface.create({
91
+ id: 'fallback-json',
92
+ role: 'card--content',
93
+ position: 'fallback',
94
+ filter: (data): data is Record<string, unknown> => true,
95
+ component: ({ data }) => {
96
+ return <JsonCard data={data} />;
97
+ },
98
+ }),
99
+
100
+ Surface.create({
101
+ id: 'section',
102
+ position: 'fallback',
103
+ filter: AppSurface.subject(AppSurface.Section, Obj.isObject),
104
+ component: ({ data }) => {
105
+ return (
106
+ <div className='flex w-full justify-center'>
107
+ <div className='py-2 dx-card-min-width dx-card-max-width'>
108
+ <Card.Root>
109
+ <Surface.Surface type={AppSurface.Card} data={data} limit={1} />
110
+ </Card.Root>
111
+ </div>
112
+ </div>
113
+ );
114
+ },
115
+ }),
116
+ ]),
117
+ ),
118
+ );