@dxos/plugin-preview 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe

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 (86) hide show
  1. package/dist/lib/browser/chunk-CEWM5LJG.mjs +17 -0
  2. package/dist/lib/browser/chunk-CEWM5LJG.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +11 -10
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/{preview-popover-HC6LHWXZ.mjs → preview-popover-IAPAEKZL.mjs} +7 -6
  7. package/dist/lib/browser/preview-popover-IAPAEKZL.mjs.map +7 -0
  8. package/dist/lib/browser/react-surface-LRMZKOJS.mjs +498 -0
  9. package/dist/lib/browser/react-surface-LRMZKOJS.mjs.map +7 -0
  10. package/dist/lib/node-esm/chunk-Q5MUNELK.mjs +19 -0
  11. package/dist/lib/node-esm/chunk-Q5MUNELK.mjs.map +7 -0
  12. package/dist/lib/node-esm/index.mjs +11 -10
  13. package/dist/lib/node-esm/index.mjs.map +3 -3
  14. package/dist/lib/node-esm/meta.json +1 -1
  15. package/dist/lib/node-esm/{preview-popover-ROGTBCTT.mjs → preview-popover-CH2LDYWM.mjs} +7 -6
  16. package/dist/lib/node-esm/preview-popover-CH2LDYWM.mjs.map +7 -0
  17. package/dist/lib/node-esm/react-surface-65UVGBIZ.mjs +499 -0
  18. package/dist/lib/node-esm/react-surface-65UVGBIZ.mjs.map +7 -0
  19. package/dist/types/src/PreviewPlugin.d.ts +1 -1
  20. package/dist/types/src/PreviewPlugin.d.ts.map +1 -1
  21. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  22. package/dist/types/src/cards/OrganizationCard.d.ts +5 -0
  23. package/dist/types/src/cards/OrganizationCard.d.ts.map +1 -0
  24. package/dist/types/src/cards/PersonCard.d.ts +5 -0
  25. package/dist/types/src/cards/PersonCard.d.ts.map +1 -0
  26. package/dist/types/src/cards/ProjectCard.d.ts +5 -0
  27. package/dist/types/src/cards/ProjectCard.d.ts.map +1 -0
  28. package/dist/types/src/cards/TaskCard.d.ts +5 -0
  29. package/dist/types/src/cards/TaskCard.d.ts.map +1 -0
  30. package/dist/types/src/cards/index.d.ts +5 -0
  31. package/dist/types/src/cards/index.d.ts.map +1 -0
  32. package/dist/types/src/components/CardComponents.d.ts +16 -0
  33. package/dist/types/src/components/CardComponents.d.ts.map +1 -0
  34. package/dist/types/src/components/CardSubjectMenu.d.ts +3 -5
  35. package/dist/types/src/components/CardSubjectMenu.d.ts.map +1 -1
  36. package/dist/types/src/components/index.d.ts +2 -3
  37. package/dist/types/src/components/index.d.ts.map +1 -1
  38. package/dist/types/src/meta.d.ts +0 -1
  39. package/dist/types/src/meta.d.ts.map +1 -1
  40. package/dist/types/src/stories/Card.stories.d.ts +3 -1
  41. package/dist/types/src/stories/Card.stories.d.ts.map +1 -1
  42. package/dist/types/src/stories/testing.d.ts +4 -3
  43. package/dist/types/src/stories/testing.d.ts.map +1 -1
  44. package/dist/types/src/translations.d.ts +3 -0
  45. package/dist/types/src/translations.d.ts.map +1 -1
  46. package/dist/types/src/types.d.ts +10 -5
  47. package/dist/types/src/types.d.ts.map +1 -1
  48. package/dist/types/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +33 -32
  50. package/src/PreviewPlugin.tsx +23 -24
  51. package/src/capabilities/preview-popover.ts +5 -5
  52. package/src/capabilities/react-surface.tsx +89 -96
  53. package/src/cards/OrganizationCard.tsx +34 -0
  54. package/src/cards/PersonCard.tsx +63 -0
  55. package/src/cards/ProjectCard.tsx +24 -0
  56. package/src/{components → cards}/TaskCard.tsx +10 -10
  57. package/src/cards/index.ts +8 -0
  58. package/src/components/CardComponents.tsx +67 -0
  59. package/src/components/CardSubjectMenu.tsx +73 -26
  60. package/src/components/index.ts +2 -3
  61. package/src/meta.ts +6 -3
  62. package/src/stories/Card.stories.tsx +11 -8
  63. package/src/stories/testing.tsx +21 -21
  64. package/src/translations.ts +3 -0
  65. package/src/types.ts +23 -5
  66. package/dist/lib/browser/chunk-Z73ENKLE.mjs +0 -14
  67. package/dist/lib/browser/chunk-Z73ENKLE.mjs.map +0 -7
  68. package/dist/lib/browser/preview-popover-HC6LHWXZ.mjs.map +0 -7
  69. package/dist/lib/browser/react-surface-JGO43GLE.mjs +0 -381
  70. package/dist/lib/browser/react-surface-JGO43GLE.mjs.map +0 -7
  71. package/dist/lib/node-esm/chunk-2ORSL4GJ.mjs +0 -16
  72. package/dist/lib/node-esm/chunk-2ORSL4GJ.mjs.map +0 -7
  73. package/dist/lib/node-esm/preview-popover-ROGTBCTT.mjs.map +0 -7
  74. package/dist/lib/node-esm/react-surface-Q7F36L3Z.mjs +0 -382
  75. package/dist/lib/node-esm/react-surface-Q7F36L3Z.mjs.map +0 -7
  76. package/dist/types/src/components/ContactCard.d.ts +0 -7
  77. package/dist/types/src/components/ContactCard.d.ts.map +0 -1
  78. package/dist/types/src/components/OrganizationCard.d.ts +0 -5
  79. package/dist/types/src/components/OrganizationCard.d.ts.map +0 -1
  80. package/dist/types/src/components/ProjectCard.d.ts +0 -5
  81. package/dist/types/src/components/ProjectCard.d.ts.map +0 -1
  82. package/dist/types/src/components/TaskCard.d.ts +0 -5
  83. package/dist/types/src/components/TaskCard.d.ts.map +0 -1
  84. package/src/components/ContactCard.tsx +0 -76
  85. package/src/components/OrganizationCard.tsx +0 -44
  86. package/src/components/ProjectCard.tsx +0 -28
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-preview",
3
- "version": "0.8.4-main.dedc0f3",
3
+ "version": "0.8.4-main.e8ec1fe",
4
4
  "description": "Preview plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -24,43 +24,44 @@
24
24
  "src"
25
25
  ],
26
26
  "dependencies": {
27
- "@effect-rx/rx-react": "0.38.0",
27
+ "@effect-atom/atom-react": "^0.3.4",
28
28
  "@preact-signals/safe-react": "^0.9.0",
29
- "@dxos/app-framework": "0.8.4-main.dedc0f3",
30
- "@dxos/app-graph": "0.8.4-main.dedc0f3",
31
- "@dxos/async": "0.8.4-main.dedc0f3",
32
- "@dxos/client": "0.8.4-main.dedc0f3",
33
- "@dxos/echo": "0.8.4-main.dedc0f3",
34
- "@dxos/echo-schema": "0.8.4-main.dedc0f3",
35
- "@dxos/keys": "0.8.4-main.dedc0f3",
36
- "@dxos/log": "0.8.4-main.dedc0f3",
37
- "@dxos/plugin-client": "0.8.4-main.dedc0f3",
38
- "@dxos/plugin-attention": "0.8.4-main.dedc0f3",
39
- "@dxos/plugin-deck": "0.8.4-main.dedc0f3",
40
- "@dxos/react-client": "0.8.4-main.dedc0f3",
41
- "@dxos/react-ui": "0.8.4-main.dedc0f3",
42
- "@dxos/lit-ui": "0.8.4-main.dedc0f3",
43
- "@dxos/react-ui-editor": "0.8.4-main.dedc0f3",
44
- "@dxos/react-ui-form": "0.8.4-main.dedc0f3",
45
- "@dxos/react-ui-menu": "0.8.4-main.dedc0f3",
46
- "@dxos/react-ui-stack": "0.8.4-main.dedc0f3",
47
- "@dxos/react-ui-table": "0.8.4-main.dedc0f3",
48
- "@dxos/react-ui-theme": "0.8.4-main.dedc0f3",
49
- "@dxos/schema": "0.8.4-main.dedc0f3",
50
- "@dxos/util": "0.8.4-main.dedc0f3"
29
+ "@dxos/async": "0.8.4-main.e8ec1fe",
30
+ "@dxos/app-framework": "0.8.4-main.e8ec1fe",
31
+ "@dxos/echo": "0.8.4-main.e8ec1fe",
32
+ "@dxos/keys": "0.8.4-main.e8ec1fe",
33
+ "@dxos/lit-ui": "0.8.4-main.e8ec1fe",
34
+ "@dxos/client": "0.8.4-main.e8ec1fe",
35
+ "@dxos/log": "0.8.4-main.e8ec1fe",
36
+ "@dxos/app-graph": "0.8.4-main.e8ec1fe",
37
+ "@dxos/plugin-deck": "0.8.4-main.e8ec1fe",
38
+ "@dxos/plugin-space": "0.8.4-main.e8ec1fe",
39
+ "@dxos/plugin-client": "0.8.4-main.e8ec1fe",
40
+ "@dxos/react-client": "0.8.4-main.e8ec1fe",
41
+ "@dxos/react-ui": "0.8.4-main.e8ec1fe",
42
+ "@dxos/react-ui-editor": "0.8.4-main.e8ec1fe",
43
+ "@dxos/react-ui-form": "0.8.4-main.e8ec1fe",
44
+ "@dxos/react-ui-menu": "0.8.4-main.e8ec1fe",
45
+ "@dxos/plugin-attention": "0.8.4-main.e8ec1fe",
46
+ "@dxos/react-ui-stack": "0.8.4-main.e8ec1fe",
47
+ "@dxos/react-ui-table": "0.8.4-main.e8ec1fe",
48
+ "@dxos/schema": "0.8.4-main.e8ec1fe",
49
+ "@dxos/types": "0.8.4-main.e8ec1fe",
50
+ "@dxos/util": "0.8.4-main.e8ec1fe",
51
+ "@dxos/react-ui-theme": "0.8.4-main.e8ec1fe"
51
52
  },
52
53
  "devDependencies": {
53
- "effect": "3.17.7",
54
- "react": "~18.2.0",
55
- "react-dom": "~18.2.0",
56
- "vite": "7.1.1",
57
- "@dxos/random": "0.8.4-main.dedc0f3",
58
- "@dxos/storybook-utils": "0.8.4-main.dedc0f3"
54
+ "effect": "3.18.3",
55
+ "react": "~19.2.0",
56
+ "react-dom": "~19.2.0",
57
+ "vite": "7.1.9",
58
+ "@dxos/storybook-utils": "0.8.4-main.e8ec1fe",
59
+ "@dxos/random": "0.8.4-main.e8ec1fe"
59
60
  },
60
61
  "peerDependencies": {
61
62
  "effect": "^3.13.3",
62
- "react": "~18.2.0",
63
- "react-dom": "~18.2.0"
63
+ "react": "^19.0.0",
64
+ "react-dom": "^19.0.0"
64
65
  },
65
66
  "publishConfig": {
66
67
  "access": "public"
@@ -4,32 +4,31 @@
4
4
 
5
5
  import { Capabilities, Events, contributes, defineModule, definePlugin } from '@dxos/app-framework';
6
6
  import { ClientCapabilities, ClientEvents } from '@dxos/plugin-client';
7
- import { DataType } from '@dxos/schema';
7
+ import { Organization, Person } from '@dxos/types';
8
8
 
9
9
  import { PreviewPopover, ReactSurface } from './capabilities';
10
10
  import { meta } from './meta';
11
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 = definePlugin(meta, () => [
14
+ defineModule({
15
+ id: `${meta.id}/module/translations`,
16
+ activatesOn: Events.SetupTranslations,
17
+ activate: () => contributes(Capabilities.Translations, translations),
18
+ }),
19
+ defineModule({
20
+ id: `${meta.id}/module/schema`,
21
+ activatesOn: ClientEvents.SetupSchema,
22
+ activate: () => [contributes(ClientCapabilities.Schema, [Person.Person, Organization.Organization])],
23
+ }),
24
+ defineModule({
25
+ id: `${meta.id}/module/preview-popover`,
26
+ activatesOn: Events.Startup,
27
+ activate: PreviewPopover,
28
+ }),
29
+ defineModule({
30
+ id: `${meta.id}/module/react-surface`,
31
+ activatesOn: Events.SetupReactSurface,
32
+ activate: ReactSurface,
33
+ }),
34
+ ]);
@@ -7,9 +7,9 @@ import { addEventListener } from '@dxos/async';
7
7
  import { type Client } from '@dxos/client';
8
8
  import { type Space, parseId } from '@dxos/client/echo';
9
9
  import { DXN } from '@dxos/keys';
10
- import { type DxAnchorActivate } from '@dxos/lit-ui';
11
10
  import { log } from '@dxos/log';
12
11
  import { ClientCapabilities } from '@dxos/plugin-client';
12
+ import { DX_ANCHOR_ACTIVATE, type DxAnchorActivate } from '@dxos/react-ui';
13
13
  import { type PreviewLinkRef, type PreviewLinkTarget } from '@dxos/react-ui-editor';
14
14
 
15
15
  const customEventOptions = { capture: true, passive: false };
@@ -22,14 +22,14 @@ const handlePreviewLookup = async (
22
22
  try {
23
23
  const object = await defaultSpace.db.ref(DXN.parse(ref)).load();
24
24
  return { label, object };
25
- } catch (err) {
25
+ } catch {
26
26
  return null;
27
27
  }
28
28
  };
29
29
 
30
30
  export default (context: PluginContext) => {
31
31
  // TODO(wittjosiah): Factor out lookup handlers to other plugins to make not ECHO-specific.
32
- const handleDxAnchorActivate = async ({ refId, label, trigger }: DxAnchorActivate) => {
32
+ const handleAnchorActivate = async ({ refId, label, trigger }: DxAnchorActivate) => {
33
33
  const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
34
34
  const client = context.getCapability(ClientCapabilities.Client);
35
35
  const [layout] = context.getCapabilities(Capabilities.Layout);
@@ -57,8 +57,8 @@ export default (context: PluginContext) => {
57
57
  if (document.defaultView) {
58
58
  cleanup = addEventListener(
59
59
  document.defaultView,
60
- 'dx-anchor-activate' as any,
61
- handleDxAnchorActivate,
60
+ DX_ANCHOR_ACTIVATE as any,
61
+ handleAnchorActivate,
62
62
  customEventOptions,
63
63
  );
64
64
  } else {
@@ -2,137 +2,111 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Effect } from 'effect';
6
5
  import React, { useCallback } from 'react';
7
6
 
8
- import {
9
- Capabilities,
10
- LayoutAction,
11
- Surface,
12
- contributes,
13
- createIntent,
14
- createSurface,
15
- useIntentDispatcher,
16
- } from '@dxos/app-framework';
17
- import { fullyQualifiedId, getSchema, getSpace } from '@dxos/client/echo';
18
- import { Filter, Obj } from '@dxos/echo';
19
- import { type JsonPath, setValue } from '@dxos/echo-schema';
20
- import { AttentionAction } from '@dxos/plugin-attention/types';
21
- import { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';
22
- import { useQuery, useSpace } from '@dxos/react-client/echo';
7
+ import { Capabilities, LayoutAction, contributes, createIntent, createSurface } from '@dxos/app-framework';
8
+ import { Surface, SurfaceCardRole, useIntentDispatcher } from '@dxos/app-framework/react';
9
+ import { getSchema, getSpace } from '@dxos/client/echo';
10
+ import { Obj } from '@dxos/echo';
11
+ import { type JsonPath, setValue } from '@dxos/echo/internal';
12
+ import { useActiveSpace } from '@dxos/plugin-space';
23
13
  import { useTranslation } from '@dxos/react-ui';
24
14
  import { Form } from '@dxos/react-ui-form';
25
15
  import { Card } from '@dxos/react-ui-stack';
26
- import { Table } from '@dxos/react-ui-table/types';
27
16
  import { descriptionMessage, mx } from '@dxos/react-ui-theme';
28
- import { DataType, type ProjectionModel, typenameFromQuery } from '@dxos/schema';
17
+ import { type ProjectionModel } from '@dxos/schema';
18
+ import { Organization, Person, Project, Task } from '@dxos/types';
29
19
 
30
- import { ContactCard, OrganizationCard, ProjectCard } from '../components';
31
- import { PREVIEW_PLUGIN } from '../meta';
20
+ import { OrganizationCard, PersonCard, ProjectCard, TaskCard } from '../cards';
21
+ import { meta } from '../meta';
22
+ import { type CardPreviewProps } from '../types';
32
23
 
33
24
  export default () =>
34
25
  contributes(Capabilities.ReactSurface, [
35
26
  //
36
27
  // Specific schema types.
28
+ // TODO(burdon): Create helpers and factor out.
37
29
  //
38
- createSurface({
39
- id: `${PREVIEW_PLUGIN}/schema-popover--contact`,
40
- role: ['card--popover', 'card--intrinsic', 'card--transclusion', 'card--extrinsic', 'card'],
41
- filter: (data): data is { subject: DataType.Person } => Obj.instanceOf(DataType.Person, data.subject),
30
+
31
+ // TODO(burdon): Infer Role type.
32
+ createSurface<{ subject: Person.Person }>({
33
+ id: `${meta.id}/schema-popover--contact`,
34
+ role: SurfaceCardRole.literals as any,
35
+ filter: (data): data is { subject: Person.Person } => Obj.instanceOf(Person.Person, data.subject),
42
36
  component: ({ data, role }) => {
43
- const { dispatch } = useIntentDispatcher();
37
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
44
38
  const space = getSpace(data.subject);
45
- const defaultSpace = useSpace();
46
-
47
- const currentSpaceOrgs = useQuery(space, Filter.type(DataType.Organization));
48
- const currentSpaceViews = useQuery(space, Filter.type(DataType.View));
49
- const defaultSpaceViews = useQuery(defaultSpace, Filter.type(DataType.View));
50
- const currentSpaceOrgTable = currentSpaceViews.find(
51
- (view) =>
52
- typenameFromQuery(view.query) === DataType.Organization.typename &&
53
- Obj.instanceOf(Table.Table, view.presentation.target),
54
- );
55
- const defaultSpaceOrgTable = defaultSpaceViews.find(
56
- (view) =>
57
- typenameFromQuery(view.query) === DataType.Organization.typename &&
58
- Obj.instanceOf(Table.Table, view.presentation.target),
39
+ const activeSpace = useActiveSpace(); // TODO(burdon): Disambiguate with space?
40
+ const handleSelect = useCallback<NonNullable<CardPreviewProps['onSelect']>>(
41
+ (object) =>
42
+ dispatch(
43
+ createIntent(LayoutAction.Open, {
44
+ part: 'main',
45
+ subject: [Obj.getDXN(object).toString()],
46
+ options: {
47
+ workspace: space?.id,
48
+ },
49
+ }),
50
+ ),
51
+ [dispatch],
59
52
  );
60
53
 
61
- // TODO(wittjosiah): Generalized way of handling related objects navigation.
62
- const handleOrgClick = useCallback(
63
- (org: DataType.Organization) =>
64
- Effect.gen(function* () {
65
- const view = currentSpaceOrgs.includes(org) ? currentSpaceOrgTable : defaultSpaceOrgTable;
66
- yield* dispatch(
67
- createIntent(LayoutAction.UpdatePopover, {
68
- part: 'popover',
69
- options: {
70
- state: false,
71
- anchorId: '',
72
- },
73
- }),
74
- );
75
- if (view) {
76
- const id = fullyQualifiedId(view);
77
- yield* dispatch(
78
- createIntent(LayoutAction.Open, {
79
- part: 'main',
80
- subject: [id],
81
- options: { workspace: space?.id },
82
- }),
83
- );
84
- yield* dispatch(
85
- createIntent(DeckAction.ChangeCompanion, {
86
- primary: id,
87
- companion: [id, 'selected-objects'].join(ATTENDABLE_PATH_SEPARATOR),
88
- }),
89
- );
90
- yield* dispatch(
91
- createIntent(AttentionAction.Select, {
92
- contextId: id,
93
- selection: { mode: 'multi', ids: [org.id] },
94
- }),
95
- );
96
- }
97
- }).pipe(Effect.runPromise),
98
- [dispatch, currentSpaceOrgs, currentSpaceOrgTable, defaultSpaceOrgTable],
54
+ return (
55
+ <PersonCard
56
+ role={role as SurfaceCardRole}
57
+ subject={data.subject}
58
+ activeSpace={activeSpace}
59
+ onSelect={handleSelect}
60
+ >
61
+ {role === 'card--popover' && <Surface role='related' data={data} />}
62
+ </PersonCard>
99
63
  );
100
-
64
+ },
65
+ }),
66
+ createSurface({
67
+ id: `${meta.id}/schema-popover--organization`,
68
+ role: SurfaceCardRole.literals as any,
69
+ filter: (data): data is { subject: Organization.Organization } =>
70
+ Obj.instanceOf(Organization.Organization, data.subject),
71
+ component: ({ data, role }) => {
72
+ const activeSpace = useActiveSpace();
101
73
  return (
102
- <ContactCard role={role} subject={data.subject} onOrgClick={handleOrgClick}>
74
+ <OrganizationCard role={role as SurfaceCardRole} subject={data.subject} activeSpace={activeSpace}>
103
75
  {role === 'card--popover' && <Surface role='related' data={data} />}
104
- </ContactCard>
76
+ </OrganizationCard>
105
77
  );
106
78
  },
107
79
  }),
108
80
  createSurface({
109
- id: `${PREVIEW_PLUGIN}/schema-popover--organization`,
110
- role: ['card--popover', 'card--intrinsic', 'card--transclusion', 'card--extrinsic', 'card'],
111
- filter: (data): data is { subject: DataType.Organization } => Obj.instanceOf(DataType.Organization, data.subject),
112
- component: ({ data, role }) => (
113
- <OrganizationCard role={role} subject={data.subject}>
114
- {role === 'card--popover' && <Surface role='related' data={data} />}
115
- </OrganizationCard>
116
- ),
81
+ id: `${meta.id}/schema-popover--project`,
82
+ role: SurfaceCardRole.literals as any,
83
+ filter: (data): data is { subject: Project.Project } => Obj.instanceOf(Project.Project, data.subject),
84
+ component: ({ data, role }) => {
85
+ const activeSpace = useActiveSpace();
86
+ return <ProjectCard subject={data.subject} role={role as SurfaceCardRole} activeSpace={activeSpace} />;
87
+ },
117
88
  }),
118
89
  createSurface({
119
- id: `${PREVIEW_PLUGIN}/schema-popover--project`,
120
- role: ['card--popover', 'card--intrinsic', 'card--transclusion', 'card--extrinsic', 'card'],
121
- filter: (data): data is { subject: DataType.Project } => Obj.instanceOf(DataType.Project, data.subject),
122
- component: ({ data, role }) => <ProjectCard subject={data.subject} role={role} />,
90
+ id: `${meta.id}/schema-popover--task`,
91
+ role: SurfaceCardRole.literals as any,
92
+ filter: (data): data is { subject: Task.Task } => Obj.instanceOf(Task.Task, data.subject),
93
+ component: ({ data, role }) => {
94
+ return <TaskCard subject={data.subject} role={role as SurfaceCardRole} />;
95
+ },
123
96
  }),
124
97
 
125
98
  //
126
99
  // Fallback for any object.
127
100
  //
101
+
128
102
  createSurface({
129
- id: `${PREVIEW_PLUGIN}/fallback-popover`,
130
- role: ['card--popover', 'card--intrinsic', 'card--transclusion', 'card--extrinsic', 'card'],
103
+ id: `${meta.id}/fallback-popover`,
104
+ role: SurfaceCardRole.literals as any,
131
105
  position: 'fallback',
132
106
  filter: (data): data is { subject: Obj.Any; projection?: ProjectionModel } => Obj.isObject(data.subject),
133
107
  component: ({ data, role }) => {
134
108
  const schema = getSchema(data.subject);
135
- const { t } = useTranslation(PREVIEW_PLUGIN);
109
+ const { t } = useTranslation(meta.id);
136
110
  if (!schema) {
137
111
  // TODO(burdon): Use Alert.
138
112
  return <p className={mx(descriptionMessage)}>{t('unable to create preview message')}</p>;
@@ -149,16 +123,35 @@ export default () =>
149
123
  return (
150
124
  <Card.SurfaceRoot role={role}>
151
125
  <Form
126
+ id={data.subject.id}
152
127
  schema={schema}
153
128
  projection={data.projection}
154
129
  values={data.subject}
155
130
  readonly={role === 'card--popover' ? 'static' : false}
156
131
  onSave={handleSave}
157
132
  autoSave
158
- {...(role === 'card--intrinsic' && { outerSpacing: 'blockStart-0' })}
133
+ {...(role === 'card--intrinsic' && {
134
+ outerSpacing: 'blockStart-0',
135
+ })}
159
136
  />
160
137
  </Card.SurfaceRoot>
161
138
  );
162
139
  },
163
140
  }),
141
+
142
+ createSurface({
143
+ id: `${meta.id}/section`,
144
+ role: ['section'],
145
+ position: 'fallback',
146
+ filter: (data): data is { subject: Obj.Any } => Obj.isObject(data.subject),
147
+ component: ({ data }) => {
148
+ return (
149
+ <div role='none' className='flex is-full justify-center'>
150
+ <div role='none' className='pbs-2 pbe-2 card-min-width card-max-width'>
151
+ <Surface role='card' data={data} limit={1} />
152
+ </div>
153
+ </div>
154
+ );
155
+ },
156
+ }),
164
157
  ]);
@@ -0,0 +1,34 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { Card } from '@dxos/react-ui-stack';
8
+ import { type Organization } from '@dxos/types';
9
+
10
+ import { CardHeader, CardLink } from '../components';
11
+ import { type CardPreviewProps } from '../types';
12
+
13
+ export const OrganizationCard = ({
14
+ children,
15
+ subject,
16
+ role,
17
+ activeSpace,
18
+ }: CardPreviewProps<Organization.Organization>) => {
19
+ const { name, image, description, website } = subject;
20
+
21
+ return (
22
+ <Card.SurfaceRoot id={subject.id} role={role}>
23
+ <Card.Poster
24
+ alt={name ?? ''}
25
+ {...(image ? { image } : { icon: 'ph--building-office--regular' })}
26
+ classNames={!image && 'opacity-50'}
27
+ />
28
+ <CardHeader label={name} subject={subject} activeSpace={activeSpace} />
29
+ {description && <Card.Text classNames='line-clamp-2'>{description}</Card.Text>}
30
+ {website && <CardLink label={website} href={website} />}
31
+ {children}
32
+ </Card.SurfaceRoot>
33
+ );
34
+ };
@@ -0,0 +1,63 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { Fragment } from 'react';
6
+
7
+ import { Avatar, Icon } from '@dxos/react-ui';
8
+ import { Card, cardHeading, cardText } from '@dxos/react-ui-stack';
9
+ import { mx } from '@dxos/react-ui-theme';
10
+ import { type Person } from '@dxos/types';
11
+
12
+ import { CardRow, CardSubjectMenu, gridRow } from '../components';
13
+ import { type CardPreviewProps } from '../types';
14
+
15
+ export const PersonCard = ({ children, role, subject, activeSpace, onSelect }: CardPreviewProps<Person.Person>) => {
16
+ const { fullName, image, organization: { target: organization } = {}, emails = [] } = subject;
17
+
18
+ return (
19
+ <Card.SurfaceRoot id={subject.id} role={role}>
20
+ <Avatar.Root>
21
+ <Card.Text role='group' classNames={mx('grid gap-2 grid-cols-[1fr_min-content]')}>
22
+ <div role='none' className={mx(gridRow, 'grid-rows-2')}>
23
+ {activeSpace ? <CardSubjectMenu subject={subject} activeSpace={activeSpace} /> : <div />}
24
+ <Avatar.Label asChild>
25
+ <h2 className={mx(cardHeading, 'grow truncate')}>{fullName}</h2>
26
+ </Avatar.Label>
27
+ </div>
28
+ <Avatar.Content
29
+ imgSrc={image}
30
+ icon='ph--user--regular'
31
+ size={16}
32
+ classNames={['text-subdued', !image && 'opacity-50']}
33
+ hue='neutral'
34
+ variant='square'
35
+ />
36
+ </Card.Text>
37
+ </Avatar.Root>
38
+ {organization?.name && (
39
+ <CardRow
40
+ icon='ph--buildings--regular'
41
+ label={organization.name}
42
+ onClick={onSelect ? () => onSelect(organization) : undefined}
43
+ />
44
+ )}
45
+ {emails.length > 0 && (
46
+ <dl className={mx(cardText, gridRow, '[&_dt]:text-subdued [&_dt]:pbs-0.5 [&_dd]:min-is-0')}>
47
+ {emails.map(({ label, value }) => (
48
+ <Fragment key={value}>
49
+ <dt>
50
+ <span className='sr-only'>{label}</span>
51
+ <Icon icon='ph--at--regular' size={5} />
52
+ </dt>
53
+ <dd key={value} className='col-span-2 break-words'>
54
+ {value}
55
+ </dd>
56
+ </Fragment>
57
+ ))}
58
+ </dl>
59
+ )}
60
+ {children}
61
+ </Card.SurfaceRoot>
62
+ );
63
+ };
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { Obj } from '@dxos/echo';
8
+ import { Card } from '@dxos/react-ui-stack';
9
+ import { type Project } from '@dxos/types';
10
+
11
+ import { CardHeader } from '../components';
12
+ import { type CardPreviewProps } from '../types';
13
+
14
+ export const ProjectCard = ({ subject, role, activeSpace }: CardPreviewProps<Project.Project>) => {
15
+ const { name, image, description } = subject;
16
+
17
+ return (
18
+ <Card.SurfaceRoot id={subject.id} role={role}>
19
+ {image && <Card.Poster image={image} alt={Obj.getLabel(subject) ?? ''} aspect='auto' />}
20
+ <CardHeader label={name} subject={subject} activeSpace={activeSpace} />
21
+ {description && <Card.Text classNames='line-clamp-2'>{description}</Card.Text>}
22
+ </Card.SurfaceRoot>
23
+ );
24
+ };
@@ -2,21 +2,20 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { SchemaAST } from 'effect';
5
+ import * as SchemaAST from 'effect/SchemaAST';
6
6
  import React from 'react';
7
7
 
8
- import { type PropertyMetaAnnotation, PropertyMetaAnnotationId } from '@dxos/echo-schema';
8
+ import { type PropertyMetaAnnotation, PropertyMetaAnnotationId } from '@dxos/echo/internal';
9
9
  import { Card, cardNoSpacing, cardSpacing } from '@dxos/react-ui-stack';
10
10
  import { mx } from '@dxos/react-ui-theme';
11
- import { DataType } from '@dxos/schema';
11
+ import { Task } from '@dxos/types';
12
12
 
13
- import { type PreviewProps } from '../types';
14
-
15
- import { CardSubjectMenu } from './CardSubjectMenu';
13
+ import { CardSubjectMenu } from '../components';
14
+ import { type CardPreviewProps } from '../types';
16
15
 
17
16
  // TODO(thure): Should this move upstream as a helper? Is there an easier way to get options?
18
17
  const getActiveStatusOption = (status?: string) => {
19
- const properties = SchemaAST.getPropertySignatures(DataType.Task.ast);
18
+ const properties = SchemaAST.getPropertySignatures(Task.Task.ast);
20
19
  const statusProperty = properties.find((p) => p.name === 'status');
21
20
  const statusMeta = SchemaAST.getAnnotation<PropertyMetaAnnotation>(PropertyMetaAnnotationId)(
22
21
  // TODO(thure): Typescript asserts `.type` doesn’t have `.types`, but in runtime it does.
@@ -27,11 +26,12 @@ const getActiveStatusOption = (status?: string) => {
27
26
  return options.find(({ id }) => id === status);
28
27
  };
29
28
 
30
- export const TaskCard = ({ subject, role }: PreviewProps<DataType.Task>) => {
29
+ export const TaskCard = ({ subject, role, activeSpace }: CardPreviewProps<Task.Task>) => {
31
30
  const { title, status } = subject;
32
31
  const statusOption = getActiveStatusOption(status);
32
+
33
33
  return (
34
- <Card.SurfaceRoot role={role}>
34
+ <Card.SurfaceRoot id={subject.id} role={role}>
35
35
  <div role='none' className={mx('flex items-center gap-2', cardSpacing)}>
36
36
  <Card.Heading classNames={[cardNoSpacing, 'min-is-0 flex-1 truncate']}>{title}</Card.Heading>
37
37
  {statusOption && (
@@ -39,7 +39,7 @@ export const TaskCard = ({ subject, role }: PreviewProps<DataType.Task>) => {
39
39
  {statusOption.title}
40
40
  </span>
41
41
  )}
42
- <CardSubjectMenu subject={subject} />
42
+ <CardSubjectMenu subject={subject} activeSpace={activeSpace} />
43
43
  </div>
44
44
  </Card.SurfaceRoot>
45
45
  );
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './OrganizationCard';
6
+ export * from './PersonCard';
7
+ export * from './ProjectCard';
8
+ export * from './TaskCard';