@dxos/plugin-preview 0.8.4-main.fd6878d → 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 (129) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/neutral/PreviewPlugin.mjs +9 -0
  3. package/dist/lib/neutral/PreviewPlugin.mjs.map +7 -0
  4. package/dist/lib/neutral/PreviewPlugin.node.mjs +17 -0
  5. package/dist/lib/neutral/PreviewPlugin.node.mjs.map +7 -0
  6. package/dist/lib/neutral/PreviewPlugin.workerd.mjs +17 -0
  7. package/dist/lib/neutral/PreviewPlugin.workerd.mjs.map +7 -0
  8. package/dist/lib/neutral/capabilities/index.mjs +9 -0
  9. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  10. package/dist/lib/neutral/chunk-3SWUVHXJ.mjs +28 -0
  11. package/dist/lib/neutral/chunk-3SWUVHXJ.mjs.map +7 -0
  12. package/dist/lib/neutral/chunk-QOM5APM7.mjs +23 -0
  13. package/dist/lib/neutral/chunk-QOM5APM7.mjs.map +7 -0
  14. package/dist/lib/neutral/index.mjs +7 -0
  15. package/dist/lib/neutral/index.mjs.map +7 -0
  16. package/dist/lib/neutral/meta.json +1 -0
  17. package/dist/lib/neutral/meta.mjs +7 -0
  18. package/dist/lib/neutral/meta.mjs.map +7 -0
  19. package/dist/lib/neutral/plugin.mjs +11 -0
  20. package/dist/lib/neutral/plugin.mjs.map +7 -0
  21. package/dist/lib/neutral/preview-popover-FLMYMFCH.mjs +94 -0
  22. package/dist/lib/neutral/preview-popover-FLMYMFCH.mjs.map +7 -0
  23. package/dist/lib/neutral/react-surface-FE7E2JP7.mjs +418 -0
  24. package/dist/lib/neutral/react-surface-FE7E2JP7.mjs.map +7 -0
  25. package/dist/lib/neutral/testing.mjs +7 -0
  26. package/dist/lib/neutral/testing.mjs.map +7 -0
  27. package/dist/lib/neutral/translations.mjs +21 -0
  28. package/dist/lib/neutral/translations.mjs.map +7 -0
  29. package/dist/types/src/PreviewPlugin.d.ts +3 -1
  30. package/dist/types/src/PreviewPlugin.d.ts.map +1 -1
  31. package/dist/types/src/PreviewPlugin.node.d.ts +4 -0
  32. package/dist/types/src/PreviewPlugin.node.d.ts.map +1 -0
  33. package/dist/types/src/PreviewPlugin.test.d.ts +2 -0
  34. package/dist/types/src/PreviewPlugin.test.d.ts.map +1 -0
  35. package/dist/types/src/PreviewPlugin.workerd.d.ts +4 -0
  36. package/dist/types/src/PreviewPlugin.workerd.d.ts.map +1 -0
  37. package/dist/types/src/capabilities/index.d.ts +3 -2
  38. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  39. package/dist/types/src/capabilities/preview-popover.d.ts +3 -2
  40. package/dist/types/src/capabilities/preview-popover.d.ts.map +1 -1
  41. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  42. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  43. package/dist/types/src/cards/ExpandoCard.d.ts +4 -0
  44. package/dist/types/src/cards/ExpandoCard.d.ts.map +1 -0
  45. package/dist/types/src/cards/FormCard.d.ts +17 -0
  46. package/dist/types/src/cards/FormCard.d.ts.map +1 -0
  47. package/dist/types/src/cards/JsonCard.d.ts +5 -0
  48. package/dist/types/src/cards/JsonCard.d.ts.map +1 -0
  49. package/dist/types/src/cards/OrganizationCard.d.ts +5 -0
  50. package/dist/types/src/cards/OrganizationCard.d.ts.map +1 -0
  51. package/dist/types/src/cards/PersonCard.d.ts +5 -0
  52. package/dist/types/src/cards/PersonCard.d.ts.map +1 -0
  53. package/dist/types/src/cards/ProjectCard.d.ts +5 -0
  54. package/dist/types/src/cards/ProjectCard.d.ts.map +1 -0
  55. package/dist/types/src/cards/TaskCard.d.ts +5 -0
  56. package/dist/types/src/cards/TaskCard.d.ts.map +1 -0
  57. package/dist/types/src/cards/index.d.ts +8 -0
  58. package/dist/types/src/cards/index.d.ts.map +1 -0
  59. package/dist/types/src/index.d.ts +0 -2
  60. package/dist/types/src/index.d.ts.map +1 -1
  61. package/dist/types/src/meta.d.ts +2 -3
  62. package/dist/types/src/meta.d.ts.map +1 -1
  63. package/dist/types/src/plugin.d.ts +3 -0
  64. package/dist/types/src/plugin.d.ts.map +1 -0
  65. package/dist/types/src/stories/Card.stories.d.ts +54 -46
  66. package/dist/types/src/stories/Card.stories.d.ts.map +1 -1
  67. package/dist/types/src/stories/testing.d.ts +53 -13
  68. package/dist/types/src/stories/testing.d.ts.map +1 -1
  69. package/dist/types/src/testing.d.ts +2 -0
  70. package/dist/types/src/testing.d.ts.map +1 -0
  71. package/dist/types/src/translations.d.ts +8 -3
  72. package/dist/types/src/translations.d.ts.map +1 -1
  73. package/dist/types/tsconfig.tsbuildinfo +1 -1
  74. package/package.json +80 -36
  75. package/src/PreviewPlugin.node.ts +16 -0
  76. package/src/PreviewPlugin.test.ts +25 -0
  77. package/src/PreviewPlugin.tsx +19 -29
  78. package/src/PreviewPlugin.workerd.ts +16 -0
  79. package/src/capabilities/index.ts +3 -3
  80. package/src/capabilities/preview-popover.ts +96 -49
  81. package/src/capabilities/react-surface.tsx +139 -150
  82. package/src/cards/ExpandoCard.tsx +76 -0
  83. package/src/cards/FormCard.tsx +125 -0
  84. package/src/cards/JsonCard.tsx +19 -0
  85. package/src/cards/OrganizationCard.tsx +29 -0
  86. package/src/cards/PersonCard.tsx +65 -0
  87. package/src/cards/ProjectCard.tsx +22 -0
  88. package/src/cards/TaskCard.tsx +45 -0
  89. package/src/cards/index.ts +11 -0
  90. package/src/index.ts +0 -3
  91. package/src/meta.ts +12 -6
  92. package/src/plugin.ts +9 -0
  93. package/src/stories/Card.stories.tsx +152 -28
  94. package/src/stories/testing.tsx +119 -69
  95. package/src/testing.ts +7 -0
  96. package/src/translations.ts +8 -2
  97. package/dist/lib/browser/chunk-Z73ENKLE.mjs +0 -14
  98. package/dist/lib/browser/chunk-Z73ENKLE.mjs.map +0 -7
  99. package/dist/lib/browser/index.mjs +0 -60
  100. package/dist/lib/browser/index.mjs.map +0 -7
  101. package/dist/lib/browser/meta.json +0 -1
  102. package/dist/lib/browser/preview-popover-MAIBTJKJ.mjs +0 -69
  103. package/dist/lib/browser/preview-popover-MAIBTJKJ.mjs.map +0 -7
  104. package/dist/lib/browser/react-surface-SC522FSX.mjs +0 -303
  105. package/dist/lib/browser/react-surface-SC522FSX.mjs.map +0 -7
  106. package/dist/lib/node-esm/chunk-2ORSL4GJ.mjs +0 -16
  107. package/dist/lib/node-esm/chunk-2ORSL4GJ.mjs.map +0 -7
  108. package/dist/lib/node-esm/index.mjs +0 -61
  109. package/dist/lib/node-esm/index.mjs.map +0 -7
  110. package/dist/lib/node-esm/meta.json +0 -1
  111. package/dist/lib/node-esm/preview-popover-LZGHYW23.mjs +0 -71
  112. package/dist/lib/node-esm/preview-popover-LZGHYW23.mjs.map +0 -7
  113. package/dist/lib/node-esm/react-surface-PDXF35OF.mjs +0 -304
  114. package/dist/lib/node-esm/react-surface-PDXF35OF.mjs.map +0 -7
  115. package/dist/types/src/components/ContactCard.d.ts +0 -7
  116. package/dist/types/src/components/ContactCard.d.ts.map +0 -1
  117. package/dist/types/src/components/OrganizationCard.d.ts +0 -5
  118. package/dist/types/src/components/OrganizationCard.d.ts.map +0 -1
  119. package/dist/types/src/components/ProjectCard.d.ts +0 -5
  120. package/dist/types/src/components/ProjectCard.d.ts.map +0 -1
  121. package/dist/types/src/components/index.d.ts +0 -4
  122. package/dist/types/src/components/index.d.ts.map +0 -1
  123. package/dist/types/src/types.d.ts +0 -7
  124. package/dist/types/src/types.d.ts.map +0 -1
  125. package/src/components/ContactCard.tsx +0 -72
  126. package/src/components/OrganizationCard.tsx +0 -41
  127. package/src/components/ProjectCard.tsx +0 -20
  128. package/src/components/index.ts +0 -7
  129. package/src/types.ts +0 -11
package/package.json CHANGED
@@ -1,63 +1,107 @@
1
1
  {
2
2
  "name": "@dxos/plugin-preview",
3
- "version": "0.8.4-main.fd6878d",
3
+ "version": "0.8.4-staging.60fe92afc8",
4
4
  "description": "Preview plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
- "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
11
+ "license": "FSL-1.1-Apache-2.0",
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
+ "workerd": "./src/PreviewPlugin.workerd.ts",
29
+ "node": "./src/PreviewPlugin.node.ts",
30
+ "default": "./src/PreviewPlugin.tsx"
31
+ },
32
+ "types": "./dist/types/src/PreviewPlugin.d.ts",
33
+ "workerd": "./dist/lib/neutral/PreviewPlugin.workerd.mjs",
34
+ "node": "./dist/lib/neutral/PreviewPlugin.node.mjs",
35
+ "default": "./dist/lib/neutral/PreviewPlugin.mjs"
36
+ },
37
+ "#translations": {
38
+ "source": "./src/translations.ts",
39
+ "types": "./dist/types/src/translations.d.ts",
40
+ "default": "./dist/lib/neutral/translations.mjs"
41
+ }
42
+ },
11
43
  "exports": {
12
44
  ".": {
13
45
  "source": "./src/index.ts",
14
46
  "types": "./dist/types/src/index.d.ts",
15
- "browser": "./dist/lib/browser/index.mjs"
47
+ "default": "./dist/lib/neutral/index.mjs"
48
+ },
49
+ "./plugin": {
50
+ "source": "./src/plugin.ts",
51
+ "types": "./dist/types/src/plugin.d.ts",
52
+ "default": "./dist/lib/neutral/plugin.mjs"
53
+ },
54
+ "./testing": {
55
+ "source": "./src/testing.ts",
56
+ "types": "./dist/types/src/testing.d.ts",
57
+ "default": "./dist/lib/neutral/testing.mjs"
58
+ },
59
+ "./translations": {
60
+ "source": "./src/translations.ts",
61
+ "types": "./dist/types/src/translations.d.ts",
62
+ "default": "./dist/lib/neutral/translations.mjs"
16
63
  }
17
64
  },
18
65
  "types": "dist/types/src/index.d.ts",
19
- "typesVersions": {
20
- "*": {}
21
- },
22
66
  "files": [
23
67
  "dist",
24
68
  "src"
25
69
  ],
26
70
  "dependencies": {
27
- "@preact-signals/safe-react": "^0.9.0",
28
- "@dxos/app-framework": "0.8.4-main.fd6878d",
29
- "@dxos/async": "0.8.4-main.fd6878d",
30
- "@dxos/echo": "0.8.4-main.fd6878d",
31
- "@dxos/client": "0.8.4-main.fd6878d",
32
- "@dxos/keys": "0.8.4-main.fd6878d",
33
- "@dxos/lit-ui": "0.8.4-main.fd6878d",
34
- "@dxos/echo-schema": "0.8.4-main.fd6878d",
35
- "@dxos/log": "0.8.4-main.fd6878d",
36
- "@dxos/plugin-attention": "0.8.4-main.fd6878d",
37
- "@dxos/plugin-client": "0.8.4-main.fd6878d",
38
- "@dxos/plugin-deck": "0.8.4-main.fd6878d",
39
- "@dxos/react-ui": "0.8.4-main.fd6878d",
40
- "@dxos/react-client": "0.8.4-main.fd6878d",
41
- "@dxos/react-ui-editor": "0.8.4-main.fd6878d",
42
- "@dxos/react-ui-form": "0.8.4-main.fd6878d",
43
- "@dxos/react-ui-stack": "0.8.4-main.fd6878d",
44
- "@dxos/react-ui-table": "0.8.4-main.fd6878d",
45
- "@dxos/react-ui-theme": "0.8.4-main.fd6878d",
46
- "@dxos/schema": "0.8.4-main.fd6878d",
47
- "@dxos/util": "0.8.4-main.fd6878d"
71
+ "@dxos/app-framework": "0.8.4-staging.60fe92afc8",
72
+ "@dxos/app-toolkit": "0.8.4-staging.60fe92afc8",
73
+ "@dxos/async": "0.8.4-staging.60fe92afc8",
74
+ "@dxos/client": "0.8.4-staging.60fe92afc8",
75
+ "@dxos/echo-react": "0.8.4-staging.60fe92afc8",
76
+ "@dxos/echo": "0.8.4-staging.60fe92afc8",
77
+ "@dxos/effect": "0.8.4-staging.60fe92afc8",
78
+ "@dxos/keys": "0.8.4-staging.60fe92afc8",
79
+ "@dxos/log": "0.8.4-staging.60fe92afc8",
80
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8",
81
+ "@dxos/plugin-client": "0.8.4-staging.60fe92afc8",
82
+ "@dxos/react-ui-form": "0.8.4-staging.60fe92afc8",
83
+ "@dxos/react-ui-mosaic": "0.8.4-staging.60fe92afc8",
84
+ "@dxos/schema": "0.8.4-staging.60fe92afc8",
85
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-staging.60fe92afc8",
86
+ "@dxos/ui-editor": "0.8.4-staging.60fe92afc8",
87
+ "@dxos/types": "0.8.4-staging.60fe92afc8",
88
+ "@dxos/util": "0.8.4-staging.60fe92afc8"
48
89
  },
49
90
  "devDependencies": {
50
- "effect": "3.17.7",
51
- "react": "~18.2.0",
52
- "react-dom": "~18.2.0",
53
- "vite": "5.4.7",
54
- "@dxos/storybook-utils": "0.8.4-main.fd6878d",
55
- "@dxos/random": "0.8.4-main.fd6878d"
91
+ "effect": "3.21.3",
92
+ "react": "~19.2.3",
93
+ "react-dom": "~19.2.3",
94
+ "vite": "^8.0.16",
95
+ "@dxos/echo-react": "0.8.4-staging.60fe92afc8",
96
+ "@dxos/plugin-testing": "0.8.4-staging.60fe92afc8",
97
+ "@dxos/random": "0.8.4-staging.60fe92afc8",
98
+ "@dxos/storybook-utils": "0.8.4-staging.60fe92afc8",
99
+ "@dxos/react-ui-components": "0.8.4-staging.60fe92afc8"
56
100
  },
57
101
  "peerDependencies": {
58
- "effect": "^3.13.3",
59
- "react": "~18.2.0",
60
- "react-dom": "~18.2.0"
102
+ "effect": "3.21.3",
103
+ "react": "~19.2.3",
104
+ "react-dom": "~19.2.3"
61
105
  },
62
106
  "publishConfig": {
63
107
  "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;
@@ -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;
@@ -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,120 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, LayoutAction, type PluginContext, contributes, createIntent } 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 { type Space, parseId } from '@dxos/client/echo';
9
- import { DXN } from '@dxos/keys';
10
- import { type DxRefTagActivate } from '@dxos/lit-ui';
10
+ import { type Client } from '@dxos/client';
11
+ import { type Space } from '@dxos/client/echo';
12
+ import { Obj } from '@dxos/echo';
13
+ import { EID } from '@dxos/keys';
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(EID.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;
47
38
 
48
- await dispatch(
49
- createIntent(LayoutAction.UpdatePopover, {
50
- part: 'popover',
51
- subject: result.object,
52
- options: {
53
- state: true,
39
+ // TODO(wittjosiah): Factor out lookup handlers to other plugins to make not ECHO-specific.
40
+ // Monotonic activation token: each invocation captures its own sequence; only the
41
+ // most recent activation is allowed to commit popover state. Prevents a slow
42
+ // open (async lookup) from clobbering a later close that fires while it's in flight.
43
+ let activationSequence = 0;
44
+ const handleAnchorActivate = async ({
45
+ dxn,
46
+ label,
47
+ trigger,
48
+ kind = 'card',
49
+ title: titleProp,
50
+ side,
51
+ props,
52
+ state,
53
+ }: DxAnchorActivate) => {
54
+ const sequence = ++activationSequence;
55
+ const { invokePromise } = capabilities.get(Capabilities.OperationInvoker);
56
+
57
+ // Explicit close: callers pass `state: false` on pointer-leave to dismiss
58
+ // the popover. Operation schema requires anchor + kind, so use placeholders;
59
+ // they're overwritten in ephemeral state but only `state` is read by the UI.
60
+ if (state === false) {
61
+ await invokePromise(LayoutOperation.UpdatePopover, {
54
62
  variant: 'virtual',
55
63
  anchor: trigger,
56
- },
57
- }),
58
- );
59
- };
64
+ kind: 'base',
65
+ state: false,
66
+ });
67
+ return;
68
+ }
60
69
 
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
- }
70
+ const client = capabilities.get(ClientCapabilities.Client);
71
+ const registry = capabilities.get(Capabilities.AtomRegistry);
72
+ // Layout is optional: in standalone harnesses (Storybook, tests) no plugin contributes
73
+ // `AppCapabilities.Layout`, and `getAll` returns an empty array. Reading `registry.get(undefined)`
74
+ // would crash inside Atom's identity check (`'~atom/Serializable' in undefined`). When layout
75
+ // isn't available, fall through to the personal-space default.
76
+ const [layoutAtom] = capabilities.getAll(AppCapabilities.Layout);
77
+ const spaceId = layoutAtom && getSpaceIdFromPath(registry.get(layoutAtom).workspace);
78
+ const space = (spaceId && client.spaces.get(spaceId)) ?? getPersonalSpace(client);
79
+ if (!space) {
80
+ return;
81
+ }
82
+ const result = await handlePreviewLookup(client, space, { dxn, label });
83
+ if (!result) {
84
+ return;
85
+ }
86
+ // A newer activation (open or close) arrived while the lookup was in flight; bail
87
+ // out so we don't clobber the latest state.
88
+ if (sequence !== activationSequence) {
89
+ return;
90
+ }
72
91
 
73
- return contributes(Capabilities.Null, null, () => cleanup());
74
- };
92
+ const title = titleProp ?? Obj.getLabel(result.object, { fallback: 'typename' });
93
+
94
+ await invokePromise(LayoutOperation.UpdatePopover, {
95
+ subjectRef: dxn,
96
+ subject: result.object,
97
+ state: true,
98
+ variant: 'virtual',
99
+ anchor: trigger,
100
+ ...(kind && { kind }),
101
+ ...(title && { title }),
102
+ ...(side && { side }),
103
+ ...(props && { props }),
104
+ });
105
+ };
106
+
107
+ let cleanup: () => void;
108
+ if (document.defaultView) {
109
+ cleanup = addEventListener(
110
+ document.defaultView,
111
+ DX_ANCHOR_ACTIVATE as any,
112
+ handleAnchorActivate,
113
+ customEventOptions,
114
+ );
115
+ } else {
116
+ log.warn('no default view found');
117
+ }
118
+
119
+ return Capability.contributes(Capabilities.Null, null, () => Effect.sync(() => cleanup?.()));
120
+ }),
121
+ );