@dxos/plugin-preview 0.8.4-main.70d3990 → 0.8.4-main.74a063c4e0

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 (80) hide show
  1. package/dist/lib/browser/index.mjs +40 -45
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +41 -45
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/PreviewPlugin.d.ts +2 -1
  8. package/dist/types/src/PreviewPlugin.d.ts.map +1 -1
  9. package/dist/types/src/capabilities/index.d.ts +3 -2
  10. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  11. package/dist/types/src/capabilities/preview-popover.d.ts +3 -2
  12. package/dist/types/src/capabilities/preview-popover.d.ts.map +1 -1
  13. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  14. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  15. package/dist/types/src/cards/FormCard.d.ts +7 -0
  16. package/dist/types/src/cards/FormCard.d.ts.map +1 -0
  17. package/dist/types/src/cards/JsonCard.d.ts +5 -0
  18. package/dist/types/src/cards/JsonCard.d.ts.map +1 -0
  19. package/dist/types/src/cards/OrganizationCard.d.ts +2 -2
  20. package/dist/types/src/cards/OrganizationCard.d.ts.map +1 -1
  21. package/dist/types/src/cards/PersonCard.d.ts +2 -2
  22. package/dist/types/src/cards/PersonCard.d.ts.map +1 -1
  23. package/dist/types/src/cards/ProjectCard.d.ts +3 -3
  24. package/dist/types/src/cards/ProjectCard.d.ts.map +1 -1
  25. package/dist/types/src/cards/TaskCard.d.ts +2 -2
  26. package/dist/types/src/cards/TaskCard.d.ts.map +1 -1
  27. package/dist/types/src/cards/index.d.ts +2 -0
  28. package/dist/types/src/cards/index.d.ts.map +1 -1
  29. package/dist/types/src/index.d.ts +0 -1
  30. package/dist/types/src/index.d.ts.map +1 -1
  31. package/dist/types/src/meta.d.ts +2 -2
  32. package/dist/types/src/meta.d.ts.map +1 -1
  33. package/dist/types/src/stories/Card.stories.d.ts +20 -13
  34. package/dist/types/src/stories/Card.stories.d.ts.map +1 -1
  35. package/dist/types/src/stories/testing.d.ts +13 -12
  36. package/dist/types/src/stories/testing.d.ts.map +1 -1
  37. package/dist/types/src/translations.d.ts +8 -8
  38. package/dist/types/src/translations.d.ts.map +1 -1
  39. package/dist/types/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +49 -35
  41. package/src/PreviewPlugin.tsx +14 -24
  42. package/src/capabilities/index.ts +3 -3
  43. package/src/capabilities/preview-popover.ts +66 -42
  44. package/src/capabilities/react-surface.tsx +101 -142
  45. package/src/cards/FormCard.tsx +48 -0
  46. package/src/cards/JsonCard.tsx +16 -0
  47. package/src/cards/OrganizationCard.tsx +11 -16
  48. package/src/cards/PersonCard.tsx +51 -49
  49. package/src/cards/ProjectCard.tsx +9 -11
  50. package/src/cards/TaskCard.tsx +24 -26
  51. package/src/cards/index.ts +2 -0
  52. package/src/index.ts +0 -1
  53. package/src/meta.ts +3 -3
  54. package/src/stories/Card.stories.tsx +69 -24
  55. package/src/stories/testing.tsx +55 -78
  56. package/src/translations.ts +8 -8
  57. package/dist/lib/browser/chunk-CEWM5LJG.mjs +0 -17
  58. package/dist/lib/browser/chunk-CEWM5LJG.mjs.map +0 -7
  59. package/dist/lib/browser/preview-popover-4QZ2WDE6.mjs +0 -65
  60. package/dist/lib/browser/preview-popover-4QZ2WDE6.mjs.map +0 -7
  61. package/dist/lib/browser/react-surface-X4KEMECS.mjs +0 -498
  62. package/dist/lib/browser/react-surface-X4KEMECS.mjs.map +0 -7
  63. package/dist/lib/node-esm/chunk-Q5MUNELK.mjs +0 -19
  64. package/dist/lib/node-esm/chunk-Q5MUNELK.mjs.map +0 -7
  65. package/dist/lib/node-esm/preview-popover-FJ2ARIGS.mjs +0 -67
  66. package/dist/lib/node-esm/preview-popover-FJ2ARIGS.mjs.map +0 -7
  67. package/dist/lib/node-esm/react-surface-DR3UAH6F.mjs +0 -499
  68. package/dist/lib/node-esm/react-surface-DR3UAH6F.mjs.map +0 -7
  69. package/dist/types/src/components/CardComponents.d.ts +0 -16
  70. package/dist/types/src/components/CardComponents.d.ts.map +0 -1
  71. package/dist/types/src/components/CardSubjectMenu.d.ts +0 -8
  72. package/dist/types/src/components/CardSubjectMenu.d.ts.map +0 -1
  73. package/dist/types/src/components/index.d.ts +0 -3
  74. package/dist/types/src/components/index.d.ts.map +0 -1
  75. package/dist/types/src/types.d.ts +0 -12
  76. package/dist/types/src/types.d.ts.map +0 -1
  77. package/src/components/CardComponents.tsx +0 -67
  78. package/src/components/CardSubjectMenu.tsx +0 -103
  79. package/src/components/index.ts +0 -6
  80. package/src/types.ts +0 -25
package/package.json CHANGED
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "name": "@dxos/plugin-preview",
3
- "version": "0.8.4-main.70d3990",
3
+ "version": "0.8.4-main.74a063c4e0",
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": "./src/capabilities/index.ts",
17
+ "#meta": "./src/meta.ts"
18
+ },
11
19
  "exports": {
12
20
  ".": {
13
21
  "source": "./src/index.ts",
@@ -24,44 +32,50 @@
24
32
  "src"
25
33
  ],
26
34
  "dependencies": {
27
- "@effect-atom/atom-react": "^0.3.4",
28
- "@preact-signals/safe-react": "^0.9.0",
29
- "@dxos/app-framework": "0.8.4-main.70d3990",
30
- "@dxos/app-graph": "0.8.4-main.70d3990",
31
- "@dxos/async": "0.8.4-main.70d3990",
32
- "@dxos/client": "0.8.4-main.70d3990",
33
- "@dxos/keys": "0.8.4-main.70d3990",
34
- "@dxos/echo": "0.8.4-main.70d3990",
35
- "@dxos/lit-ui": "0.8.4-main.70d3990",
36
- "@dxos/log": "0.8.4-main.70d3990",
37
- "@dxos/plugin-client": "0.8.4-main.70d3990",
38
- "@dxos/plugin-deck": "0.8.4-main.70d3990",
39
- "@dxos/plugin-attention": "0.8.4-main.70d3990",
40
- "@dxos/react-client": "0.8.4-main.70d3990",
41
- "@dxos/react-ui": "0.8.4-main.70d3990",
42
- "@dxos/react-ui-editor": "0.8.4-main.70d3990",
43
- "@dxos/plugin-space": "0.8.4-main.70d3990",
44
- "@dxos/react-ui-form": "0.8.4-main.70d3990",
45
- "@dxos/react-ui-stack": "0.8.4-main.70d3990",
46
- "@dxos/react-ui-theme": "0.8.4-main.70d3990",
47
- "@dxos/react-ui-table": "0.8.4-main.70d3990",
48
- "@dxos/schema": "0.8.4-main.70d3990",
49
- "@dxos/types": "0.8.4-main.70d3990",
50
- "@dxos/react-ui-menu": "0.8.4-main.70d3990",
51
- "@dxos/util": "0.8.4-main.70d3990"
35
+ "@effect-atom/atom-react": "^0.5.0",
36
+ "@dxos/app-framework": "0.8.4-main.74a063c4e0",
37
+ "@dxos/app-toolkit": "0.8.4-main.74a063c4e0",
38
+ "@dxos/app-graph": "0.8.4-main.74a063c4e0",
39
+ "@dxos/async": "0.8.4-main.74a063c4e0",
40
+ "@dxos/client": "0.8.4-main.74a063c4e0",
41
+ "@dxos/effect": "0.8.4-main.74a063c4e0",
42
+ "@dxos/echo": "0.8.4-main.74a063c4e0",
43
+ "@dxos/keys": "0.8.4-main.74a063c4e0",
44
+ "@dxos/lit-ui": "0.8.4-main.74a063c4e0",
45
+ "@dxos/log": "0.8.4-main.74a063c4e0",
46
+ "@dxos/operation": "0.8.4-main.74a063c4e0",
47
+ "@dxos/plugin-attention": "0.8.4-main.74a063c4e0",
48
+ "@dxos/plugin-client": "0.8.4-main.74a063c4e0",
49
+ "@dxos/plugin-deck": "0.8.4-main.74a063c4e0",
50
+ "@dxos/react-client": "0.8.4-main.74a063c4e0",
51
+ "@dxos/react-ui": "0.8.4-main.74a063c4e0",
52
+ "@dxos/react-ui-editor": "0.8.4-main.74a063c4e0",
53
+ "@dxos/react-ui-form": "0.8.4-main.74a063c4e0",
54
+ "@dxos/react-ui-mosaic": "0.8.4-main.74a063c4e0",
55
+ "@dxos/react-ui-menu": "0.8.4-main.74a063c4e0",
56
+ "@dxos/react-ui-table": "0.8.4-main.74a063c4e0",
57
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.74a063c4e0",
58
+ "@dxos/schema": "0.8.4-main.74a063c4e0",
59
+ "@dxos/types": "0.8.4-main.74a063c4e0",
60
+ "@dxos/ui-editor": "0.8.4-main.74a063c4e0",
61
+ "@dxos/ui-theme": "0.8.4-main.74a063c4e0",
62
+ "@dxos/util": "0.8.4-main.74a063c4e0"
52
63
  },
53
64
  "devDependencies": {
54
- "effect": "3.18.3",
55
- "react": "~19.2.0",
56
- "react-dom": "~19.2.0",
57
- "vite": "7.1.9",
58
- "@dxos/random": "0.8.4-main.70d3990",
59
- "@dxos/storybook-utils": "0.8.4-main.70d3990"
65
+ "effect": "3.20.0",
66
+ "react": "~19.2.3",
67
+ "react-dom": "~19.2.3",
68
+ "vite": "^7.1.11",
69
+ "@dxos/echo-db": "0.8.4-main.74a063c4e0",
70
+ "@dxos/plugin-testing": "0.8.4-main.74a063c4e0",
71
+ "@dxos/random": "0.8.4-main.74a063c4e0",
72
+ "@dxos/react-ui-components": "0.8.4-main.74a063c4e0",
73
+ "@dxos/storybook-utils": "0.8.4-main.74a063c4e0"
60
74
  },
61
75
  "peerDependencies": {
62
- "effect": "^3.13.3",
63
- "react": "^19.0.0",
64
- "react-dom": "^19.0.0"
76
+ "effect": "3.20.0",
77
+ "react": "~19.2.3",
78
+ "react-dom": "~19.2.3"
65
79
  },
66
80
  "publishConfig": {
67
81
  "access": "public"
@@ -2,33 +2,23 @@
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';
5
+ import { ActivationEvents, Plugin } from '@dxos/app-framework';
6
+ import { AppPlugin } from '@dxos/app-toolkit';
7
7
  import { Organization, Person } from '@dxos/types';
8
8
 
9
- import { PreviewPopover, ReactSurface } from './capabilities';
10
- import { meta } from './meta';
9
+ import { PreviewPopover, ReactSurface } from '#capabilities';
10
+ import { meta } from '#meta';
11
+
11
12
  import { translations } from './translations';
12
13
 
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,
14
+ export const PreviewPlugin = Plugin.define(meta).pipe(
15
+ AppPlugin.addSchemaModule({ schema: [Person.Person, Organization.Organization], id: 'schema' }),
16
+ AppPlugin.addSurfaceModule({ activate: ReactSurface }),
17
+ AppPlugin.addTranslationsModule({ translations }),
18
+ Plugin.addModule({
19
+ id: 'preview-popover',
20
+ activatesOn: ActivationEvents.Startup,
27
21
  activate: PreviewPopover,
28
22
  }),
29
- defineModule({
30
- id: `${meta.id}/module/react-surface`,
31
- activatesOn: Events.SetupReactSurface,
32
- activate: ReactSurface,
33
- }),
34
- ]);
23
+ Plugin.make,
24
+ );
@@ -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,68 +2,92 @@
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
10
  import { type Client } from '@dxos/client';
8
- import { type Space, parseId } from '@dxos/client/echo';
11
+ import { type Space } from '@dxos/client/echo';
12
+ import { Obj } from '@dxos/echo';
9
13
  import { DXN } from '@dxos/keys';
10
14
  import { log } from '@dxos/log';
11
- import { ClientCapabilities } from '@dxos/plugin-client';
15
+ import { ClientCapabilities } from '@dxos/plugin-client/types';
12
16
  import { DX_ANCHOR_ACTIVATE, type DxAnchorActivate } from '@dxos/react-ui';
13
- import { type PreviewLinkRef, type PreviewLinkTarget } from '@dxos/react-ui-editor';
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 object = await defaultSpace.db.makeRef(DXN.parse(ref)).load();
27
+ const object = await defaultSpace.db.makeRef(DXN.parse(dxn)).load();
24
28
  return { label, object };
25
29
  } catch {
26
30
  return null;
27
31
  }
28
32
  };
29
33
 
30
- export default (context: PluginContext) => {
31
- // TODO(wittjosiah): Factor out lookup handlers to other plugins to make not ECHO-specific.
32
- const handleAnchorActivate = async ({ refId, label, trigger }: DxAnchorActivate) => {
33
- const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
34
- const client = context.getCapability(ClientCapabilities.Client);
35
- const [layout] = context.getCapabilities(Capabilities.Layout);
36
- const { spaceId } = parseId(layout.workspace);
37
- const space = (spaceId && client.spaces.get(spaceId)) ?? client.spaces.default;
38
- const result = await handlePreviewLookup(client, space, { ref: refId, label });
39
- if (!result) {
40
- return;
41
- }
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
+ const [layoutAtom] = capabilities.getAll(AppCapabilities.Layout);
53
+ const layout = registry.get(layoutAtom);
54
+ const spaceId = getSpaceIdFromPath(layout.workspace);
55
+ const space = (spaceId && client.spaces.get(spaceId)) ?? getPersonalSpace(client);
56
+ if (!space) {
57
+ return;
58
+ }
59
+ const result = await handlePreviewLookup(client, space, { dxn, label });
60
+ if (!result) {
61
+ return;
62
+ }
63
+
64
+ const title = titleProp ?? Obj.getLabel(result.object);
42
65
 
43
- await dispatch(
44
- createIntent(LayoutAction.UpdatePopover, {
45
- part: 'popover',
66
+ await invokePromise(LayoutOperation.UpdatePopover, {
67
+ subjectRef: dxn,
46
68
  subject: result.object,
47
- options: {
48
- state: true,
49
- variant: 'virtual',
50
- anchor: trigger,
51
- },
52
- }),
53
- );
54
- };
69
+ state: true,
70
+ variant: 'virtual',
71
+ anchor: trigger,
72
+ ...(kind && { kind }),
73
+ ...(title && { title }),
74
+ ...(side && { side }),
75
+ ...(props && { props }),
76
+ });
77
+ };
55
78
 
56
- let cleanup: () => void;
57
- if (document.defaultView) {
58
- cleanup = addEventListener(
59
- document.defaultView,
60
- DX_ANCHOR_ACTIVATE as any,
61
- handleAnchorActivate,
62
- customEventOptions,
63
- );
64
- } else {
65
- log.warn('No default view found');
66
- }
79
+ let cleanup: () => void;
80
+ if (document.defaultView) {
81
+ cleanup = addEventListener(
82
+ document.defaultView,
83
+ DX_ANCHOR_ACTIVATE as any,
84
+ handleAnchorActivate,
85
+ customEventOptions,
86
+ );
87
+ } else {
88
+ log.warn('no default view found');
89
+ }
67
90
 
68
- return contributes(Capabilities.Null, null, () => cleanup());
69
- };
91
+ return Capability.contributes(Capabilities.Null, null, () => Effect.sync(() => cleanup?.()));
92
+ }),
93
+ );
@@ -2,156 +2,115 @@
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 { Capabilities, LayoutAction, contributes, createIntent, createSurface } from '@dxos/app-framework';
8
- import { Surface, SurfaceCardRole, useIntentDispatcher } from '@dxos/app-framework/react';
9
- import { getSpace } from '@dxos/client/echo';
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
10
11
  import { Obj } from '@dxos/echo';
11
- import { type JsonPath, setValue } from '@dxos/echo/internal';
12
- import { useActiveSpace } from '@dxos/plugin-space';
13
- import { useTranslation } from '@dxos/react-ui';
14
- import { Form } from '@dxos/react-ui-form';
15
- import { Card } from '@dxos/react-ui-stack';
16
- import { descriptionMessage, mx } from '@dxos/react-ui-theme';
12
+ import { Card } from '@dxos/react-ui';
17
13
  import { type ProjectionModel } from '@dxos/schema';
18
- import { Organization, Person, Project, Task } from '@dxos/types';
14
+ import { Organization, Person, Pipeline, Task } from '@dxos/types';
19
15
 
20
- import { OrganizationCard, PersonCard, ProjectCard, TaskCard } from '../cards';
21
- import { meta } from '../meta';
22
- import { type CardPreviewProps } from '../types';
16
+ import { FormCard, JsonCard, OrganizationCard, PersonCard, ProjectCard, TaskCard } from '../cards';
23
17
 
24
- export default () =>
25
- contributes(Capabilities.ReactSurface, [
26
- //
27
- // Specific schema types.
28
- // TODO(burdon): Create helpers and factor out.
29
- //
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
+ //
30
25
 
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),
36
- component: ({ data, role }) => {
37
- const { dispatchPromise: dispatch } = useIntentDispatcher();
38
- const space = getSpace(data.subject);
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],
52
- );
26
+ Surface.create<{ subject: Person.Person }>({
27
+ id: 'schema-popover--contact',
28
+ role: 'card--content',
29
+ position: 'hoist',
30
+ filter: AppSurface.objectCard(Person.Person),
31
+ component: ({ data, role }) => {
32
+ return (
33
+ <>
34
+ <PersonCard role={role} subject={data.subject} />
35
+ <Surface.Surface role='related' data={data} limit={1} />
36
+ </>
37
+ );
38
+ },
39
+ }),
40
+ Surface.create({
41
+ id: 'schema-popover--organization',
42
+ role: 'card--content',
43
+ position: 'hoist',
44
+ filter: AppSurface.objectCard(Organization.Organization),
45
+ component: ({ data, role }) => {
46
+ return (
47
+ <>
48
+ <OrganizationCard role={role} subject={data.subject} />
49
+ <Surface.Surface role='related' data={data} limit={1} />
50
+ </>
51
+ );
52
+ },
53
+ }),
54
+ Surface.create({
55
+ id: 'schema-popover--project',
56
+ role: 'card--content',
57
+ position: 'hoist',
58
+ filter: AppSurface.objectCard(Pipeline.Pipeline),
59
+ component: ({ data, role }) => {
60
+ return <ProjectCard role={role} subject={data.subject} />;
61
+ },
62
+ }),
63
+ Surface.create({
64
+ id: 'schema-popover--task',
65
+ role: 'card--content',
66
+ position: 'hoist',
67
+ filter: AppSurface.objectCard(Task.Task),
68
+ component: ({ data, role }) => {
69
+ return <TaskCard role={role} subject={data.subject} />;
70
+ },
71
+ }),
53
72
 
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>
63
- );
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();
73
- return (
74
- <OrganizationCard role={role as SurfaceCardRole} subject={data.subject} activeSpace={activeSpace}>
75
- {role === 'card--popover' && <Surface role='related' data={data} />}
76
- </OrganizationCard>
77
- );
78
- },
79
- }),
80
- createSurface({
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
- },
88
- }),
89
- createSurface({
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
- },
96
- }),
73
+ //
74
+ // Fallback for any object.
75
+ //
97
76
 
98
- //
99
- // Fallback for any object.
100
- //
77
+ Surface.create({
78
+ id: 'fallback-popover',
79
+ role: 'card--content',
80
+ position: 'fallback',
81
+ filter: (data): data is { subject: Obj.Unknown; projection?: ProjectionModel } => Obj.isObject(data.subject),
82
+ component: ({ data, role }) => {
83
+ return <FormCard role={role} subject={data.subject} projection={data.projection} />;
84
+ },
85
+ }),
101
86
 
102
- createSurface({
103
- id: `${meta.id}/fallback-popover`,
104
- role: SurfaceCardRole.literals as any,
105
- position: 'fallback',
106
- filter: (data): data is { subject: Obj.Any; projection?: ProjectionModel } => Obj.isObject(data.subject),
107
- component: ({ data, role }) => {
108
- const schema = Obj.getSchema(data.subject);
109
- const { t } = useTranslation(meta.id);
110
- if (!schema) {
111
- // TODO(burdon): Use Alert.
112
- return <p className={mx(descriptionMessage)}>{t('unable to create preview message')}</p>;
113
- }
87
+ Surface.create({
88
+ id: 'fallback-json',
89
+ role: 'card--content',
90
+ position: 'fallback',
91
+ filter: (data): data is Record<string, unknown> => true,
92
+ component: ({ data }) => {
93
+ return <JsonCard data={data} />;
94
+ },
95
+ }),
114
96
 
115
- const handleSave = useCallback((values: any, { changed }: { changed: Record<string, boolean> }) => {
116
- const changedPaths = Object.keys(changed).filter((path) => changed[path]);
117
- for (const path of changedPaths) {
118
- const value = values[path];
119
- setValue(data.subject, path as JsonPath, value);
120
- }
121
- }, []);
122
-
123
- return (
124
- <Card.SurfaceRoot role={role}>
125
- <Form
126
- id={data.subject.id}
127
- schema={schema}
128
- projection={data.projection}
129
- values={data.subject}
130
- readonly={role === 'card--popover' ? 'static' : false}
131
- onSave={handleSave}
132
- autoSave
133
- {...(role === 'card--intrinsic' && {
134
- outerSpacing: 'blockStart-0',
135
- })}
136
- />
137
- </Card.SurfaceRoot>
138
- );
139
- },
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} />
97
+ Surface.create({
98
+ id: 'section',
99
+ role: ['section'],
100
+ position: 'fallback',
101
+ filter: AppSurface.anyObjectSection(),
102
+ component: ({ data }) => {
103
+ return (
104
+ <div role='none' className='flex w-full justify-center'>
105
+ <div role='none' className='pt-2 pb-2 dx-card-min-width dx-card-max-width'>
106
+ <Card.Root>
107
+ <Surface.Surface role='card--content' data={data} limit={1} />
108
+ </Card.Root>
109
+ </div>
152
110
  </div>
153
- </div>
154
- );
155
- },
156
- }),
157
- ]);
111
+ );
112
+ },
113
+ }),
114
+ ]),
115
+ ),
116
+ );
@@ -0,0 +1,48 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { type AppSurface } from '@dxos/app-toolkit/ui';
8
+ import { Obj } from '@dxos/echo';
9
+ import { type JsonPath, splitJsonPath } from '@dxos/effect';
10
+ import { Card, useTranslation } from '@dxos/react-ui';
11
+ import { Form, omitId } from '@dxos/react-ui-form';
12
+ import { type ProjectionModel } from '@dxos/schema';
13
+ import { descriptionMessage, mx } from '@dxos/ui-theme';
14
+
15
+ import { meta } from '#meta';
16
+
17
+ export const FormCard = ({ subject, projection }: AppSurface.ObjectCardProps & { projection?: ProjectionModel }) => {
18
+ const { t } = useTranslation(meta.id);
19
+ const echoSchema = Obj.getSchema(subject);
20
+ const schema = useMemo(() => echoSchema && omitId(echoSchema), [echoSchema]);
21
+
22
+ const handleSave = useCallback((values: any, { changed }: { changed: Record<string, boolean> }) => {
23
+ const paths = Object.keys(changed).filter((path) => changed[path]);
24
+ Obj.change(subject, () => {
25
+ for (const path of paths) {
26
+ const value = values[path];
27
+ const parts = splitJsonPath(path as JsonPath);
28
+ Obj.setValue(subject, parts, value);
29
+ }
30
+ });
31
+ }, []);
32
+
33
+ if (!schema) {
34
+ return <p className={mx(descriptionMessage)}>{t('unable-to-create-preview.message')}</p>;
35
+ }
36
+
37
+ return (
38
+ <Card.Content>
39
+ <Form.Root schema={schema} projection={projection} values={subject} autoSave onSave={handleSave}>
40
+ <Form.Viewport>
41
+ <Form.Content>
42
+ <Form.FieldSet />
43
+ </Form.Content>
44
+ </Form.Viewport>
45
+ </Form.Root>
46
+ </Card.Content>
47
+ );
48
+ };
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { Card } from '@dxos/react-ui';
8
+ import { Json } from '@dxos/react-ui-syntax-highlighter';
9
+
10
+ export const JsonCard = ({ data }: { data: unknown }) => {
11
+ return (
12
+ <Card.Content>
13
+ <Json.Data data={data} />
14
+ </Card.Content>
15
+ );
16
+ };