@dxos/plugin-simple-layout 0.8.4-main.3fbcb4aa9b → 0.8.4-main.43cb759274

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 (45) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/neutral/SimpleLayoutPlugin.mjs +1 -1
  3. package/dist/lib/neutral/SimpleLayoutPlugin.mjs.map +3 -3
  4. package/dist/lib/neutral/{app-graph-builder-EYQKLRRP.mjs → app-graph-builder-MSPO34DT.mjs} +2 -2
  5. package/dist/lib/neutral/{app-graph-builder-EYQKLRRP.mjs.map → app-graph-builder-MSPO34DT.mjs.map} +1 -1
  6. package/dist/lib/neutral/capabilities/index.mjs +2 -2
  7. package/dist/lib/neutral/{chunk-AMTEDJHG.mjs → chunk-OK5336TS.mjs} +7 -4
  8. package/dist/lib/neutral/chunk-OK5336TS.mjs.map +7 -0
  9. package/dist/lib/neutral/{chunk-XVUAQHKU.mjs → chunk-QRTV5UNX.mjs} +2 -2
  10. package/dist/lib/neutral/components/index.mjs +17 -12
  11. package/dist/lib/neutral/components/index.mjs.map +3 -3
  12. package/dist/lib/neutral/hooks/index.mjs +1 -1
  13. package/dist/lib/neutral/hooks/index.mjs.map +1 -1
  14. package/dist/lib/neutral/index.mjs +1 -1
  15. package/dist/lib/neutral/meta.json +1 -1
  16. package/dist/lib/neutral/meta.mjs +1 -1
  17. package/dist/lib/neutral/{open-XI2T7D5O.mjs → open-APISM3AA.mjs} +16 -2
  18. package/dist/lib/neutral/open-APISM3AA.mjs.map +7 -0
  19. package/dist/lib/neutral/operations/index.mjs +1 -1
  20. package/dist/lib/neutral/plugin.mjs +2 -2
  21. package/dist/lib/neutral/{react-surface-REZMYKQV.mjs → react-surface-N3PGKIYV.mjs} +4 -4
  22. package/dist/lib/neutral/{react-surface-REZMYKQV.mjs.map → react-surface-N3PGKIYV.mjs.map} +1 -1
  23. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  24. package/dist/types/src/components/SimpleLayout/AppBar.d.ts.map +1 -1
  25. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -1
  26. package/dist/types/src/meta.d.ts +1 -1
  27. package/dist/types/src/meta.d.ts.map +1 -1
  28. package/dist/types/src/operations/open.d.ts.map +1 -1
  29. package/dist/types/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +33 -37
  31. package/src/SimpleLayoutPlugin.ts +1 -1
  32. package/src/capabilities/app-graph-builder.ts +1 -1
  33. package/src/capabilities/react-surface.tsx +3 -3
  34. package/src/components/Home/Home.tsx +3 -3
  35. package/src/components/NavBranch/NavBranch.tsx +3 -3
  36. package/src/components/Popover/Popover.tsx +7 -5
  37. package/src/components/SimpleLayout/AppBar.tsx +44 -41
  38. package/src/components/SimpleLayout/NavBar.tsx +1 -1
  39. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +3 -3
  40. package/src/hooks/actions.ts +1 -1
  41. package/src/meta.ts +6 -4
  42. package/src/operations/open.ts +23 -4
  43. package/dist/lib/neutral/chunk-AMTEDJHG.mjs.map +0 -7
  44. package/dist/lib/neutral/open-XI2T7D5O.mjs.map +0 -7
  45. /package/dist/lib/neutral/{chunk-XVUAQHKU.mjs.map → chunk-QRTV5UNX.mjs.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-simple-layout",
3
- "version": "0.8.4-main.3fbcb4aa9b",
3
+ "version": "0.8.4-main.43cb759274",
4
4
  "description": "Simple layout plugin for minimal UI contexts like popover windows.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/dxos/dxos"
10
10
  },
11
- "license": "MIT",
11
+ "license": "FSL-1.1-Apache-2.0",
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": true,
14
14
  "type": "module",
@@ -77,53 +77,49 @@
77
77
  "src"
78
78
  ],
79
79
  "dependencies": {
80
- "@effect-atom/atom": "^0.5.1",
81
80
  "@effect-atom/atom-react": "^0.5.0",
82
81
  "@radix-ui/react-context": "1.1.1",
83
- "@tauri-apps/plugin-deep-link": "^2.2.0",
84
- "@tauri-apps/plugin-haptics": "^2.3.2",
85
- "@dxos/app-toolkit": "0.8.4-main.3fbcb4aa9b",
86
- "@dxos/app-framework": "0.8.4-main.3fbcb4aa9b",
87
- "@dxos/async": "0.8.4-main.3fbcb4aa9b",
88
- "@dxos/compute": "0.8.4-main.3fbcb4aa9b",
89
- "@dxos/effect": "0.8.4-main.3fbcb4aa9b",
90
- "@dxos/log": "0.8.4-main.3fbcb4aa9b",
91
- "@dxos/context": "0.8.4-main.3fbcb4aa9b",
92
- "@dxos/plugin-client": "0.8.4-main.3fbcb4aa9b",
93
- "@dxos/plugin-graph": "0.8.4-main.3fbcb4aa9b",
94
- "@dxos/react-ui-menu": "0.8.4-main.3fbcb4aa9b",
95
- "@dxos/react-ui-list": "0.8.4-main.3fbcb4aa9b",
96
- "@dxos/react-ui-attention": "0.8.4-main.3fbcb4aa9b",
97
- "@dxos/react-ui-mosaic": "0.8.4-main.3fbcb4aa9b",
98
- "@dxos/react-ui-search": "0.8.4-main.3fbcb4aa9b",
99
- "@dxos/util": "0.8.4-main.3fbcb4aa9b",
100
- "@dxos/schema": "0.8.4-main.3fbcb4aa9b",
101
- "@dxos/echo": "0.8.4-main.3fbcb4aa9b",
102
- "@dxos/react-ui-stack": "0.8.4-main.3fbcb4aa9b"
82
+ "@tauri-apps/plugin-deep-link": "^2.4.9",
83
+ "@dxos/app-framework": "0.8.4-main.43cb759274",
84
+ "@dxos/async": "0.8.4-main.43cb759274",
85
+ "@dxos/compute": "0.8.4-main.43cb759274",
86
+ "@dxos/echo": "0.8.4-main.43cb759274",
87
+ "@dxos/effect": "0.8.4-main.43cb759274",
88
+ "@dxos/keys": "0.8.4-main.43cb759274",
89
+ "@dxos/plugin-client": "0.8.4-main.43cb759274",
90
+ "@dxos/plugin-graph": "0.8.4-main.43cb759274",
91
+ "@dxos/context": "0.8.4-main.43cb759274",
92
+ "@dxos/log": "0.8.4-main.43cb759274",
93
+ "@dxos/react-ui-attention": "0.8.4-main.43cb759274",
94
+ "@dxos/react-ui-menu": "0.8.4-main.43cb759274",
95
+ "@dxos/react-ui-mosaic": "0.8.4-main.43cb759274",
96
+ "@dxos/react-ui-search": "0.8.4-main.43cb759274",
97
+ "@dxos/util": "0.8.4-main.43cb759274",
98
+ "@dxos/app-toolkit": "0.8.4-main.43cb759274"
103
99
  },
104
100
  "devDependencies": {
105
101
  "@types/react": "~19.2.7",
106
102
  "@types/react-dom": "~19.2.3",
107
- "effect": "3.20.0",
103
+ "effect": "3.21.2",
108
104
  "react": "~19.2.3",
109
105
  "react-dom": "~19.2.3",
110
- "vite": "^8.0.10",
111
- "@dxos/plugin-preview": "0.8.4-main.3fbcb4aa9b",
112
- "@dxos/app-graph": "0.8.4-main.3fbcb4aa9b",
113
- "@dxos/plugin-search": "0.8.4-main.3fbcb4aa9b",
114
- "@dxos/plugin-testing": "0.8.4-main.3fbcb4aa9b",
115
- "@dxos/react-ui": "0.8.4-main.3fbcb4aa9b",
116
- "@dxos/schema": "0.8.4-main.3fbcb4aa9b",
117
- "@dxos/plugin-space": "0.8.4-main.3fbcb4aa9b",
118
- "@dxos/storybook-utils": "0.8.4-main.3fbcb4aa9b",
119
- "@dxos/ui-theme": "0.8.4-main.3fbcb4aa9b"
106
+ "vite": "^8.0.14",
107
+ "@dxos/app-graph": "0.8.4-main.43cb759274",
108
+ "@dxos/plugin-preview": "0.8.4-main.43cb759274",
109
+ "@dxos/plugin-search": "0.8.4-main.43cb759274",
110
+ "@dxos/plugin-testing": "0.8.4-main.43cb759274",
111
+ "@dxos/plugin-space": "0.8.4-main.43cb759274",
112
+ "@dxos/react-ui": "0.8.4-main.43cb759274",
113
+ "@dxos/storybook-utils": "0.8.4-main.43cb759274",
114
+ "@dxos/ui-theme": "0.8.4-main.43cb759274",
115
+ "@dxos/schema": "0.8.4-main.43cb759274"
120
116
  },
121
117
  "peerDependencies": {
122
- "effect": "3.20.0",
118
+ "effect": "3.21.2",
123
119
  "react": "~19.2.3",
124
120
  "react-dom": "~19.2.3",
125
- "@dxos/ui-theme": "0.8.4-main.3fbcb4aa9b",
126
- "@dxos/react-ui": "0.8.4-main.3fbcb4aa9b"
121
+ "@dxos/react-ui": "0.8.4-main.43cb759274",
122
+ "@dxos/ui-theme": "0.8.4-main.43cb759274"
127
123
  },
128
124
  "publishConfig": {
129
125
  "access": "public"
@@ -50,7 +50,7 @@ export const SimpleLayoutPlugin = Plugin.define<SimpleLayoutPluginOptions>(meta)
50
50
  }),
51
51
  Plugin.addModule({
52
52
  id: Capability.getModuleTag(UrlHandler),
53
- activatesOn: ActivationEvent.allOf(ActivationEvents.OperationInvokerReady, SimpleLayoutEvents.StateReady),
53
+ activatesOn: ActivationEvent.allOf(ActivationEvents.ProcessManagerReady, SimpleLayoutEvents.StateReady),
54
54
  activate: UrlHandler,
55
55
  }),
56
56
  Plugin.make,
@@ -11,7 +11,7 @@ import { GraphBuilder, NodeMatcher } from '@dxos/plugin-graph';
11
11
  export default Capability.makeModule(
12
12
  Effect.fnUntraced(function* () {
13
13
  const extensions = yield* GraphBuilder.createExtension({
14
- id: 'org.dxos.plugin.simpleLayout.not-found',
14
+ id: 'org.dxos.plugin.simpleLayout.notFound',
15
15
  match: NodeMatcher.whenRoot,
16
16
  connector: () => Effect.succeed([AppNode.makeNotFound()]),
17
17
  });
@@ -30,15 +30,15 @@ export default Capability.makeModule(() =>
30
30
  component: () => <Home />,
31
31
  }),
32
32
  Surface.create({
33
- id: 'not-found',
33
+ id: 'notFound',
34
34
  role: 'article',
35
35
  filter: (data): data is SurfaceData => data.attendableId === NOT_FOUND_PATH,
36
36
  component: () => <NotFoundArticle />,
37
37
  }),
38
38
  Surface.create({
39
- id: 'nav-branch',
39
+ id: 'navBranch',
40
40
  role: 'article',
41
- position: 'fallback',
41
+ position: 'last',
42
42
  filter: (data): data is SurfaceData => {
43
43
  const props = data.properties as Record<string, any>;
44
44
  return ALLOWED_DISPOSITIONS.includes(props?.disposition) || props?.role === 'branch';
@@ -100,11 +100,11 @@ const WorkspaceTile: MosaicStackTileComponent<Node.Node> = (props) => {
100
100
  fullWidth
101
101
  tabIndex={-1} // TODO(burdon): Use Mosaic.Focus.
102
102
  data-selected={isSelected}
103
- classNames={mx('dx-focus-ring', isSelected && 'bg-hover-overlay')}
103
+ classNames={mx('dx-focus-ring', isSelected && 'bg-selected-surface')}
104
104
  onClick={handleSelect}
105
105
  ref={cardRef}
106
106
  >
107
- <Card.Toolbar density='fine'>
107
+ <Card.Header density='md'>
108
108
  <Avatar.Root>
109
109
  <Avatar.Content
110
110
  icon={data.properties.icon}
@@ -117,7 +117,7 @@ const WorkspaceTile: MosaicStackTileComponent<Node.Node> = (props) => {
117
117
  <Avatar.Label classNames='cursor-pointer'>{name}</Avatar.Label>
118
118
  <Icon icon='ph--caret-right--regular' />
119
119
  </Avatar.Root>
120
- </Card.Toolbar>
120
+ </Card.Header>
121
121
  </Card.Root>
122
122
  );
123
123
  };
@@ -102,10 +102,10 @@ const NavBranchTile: MosaicStackTileComponent<Node.Node> = (props) => {
102
102
  fullWidth
103
103
  tabIndex={-1} // TODO(burdon): Use Mosaic.Focus.
104
104
  data-selected={isSelected}
105
- classNames={mx('dx-focus-ring cursor-pointer', isSelected && 'bg-hover-overlay')}
105
+ classNames={mx('dx-focus-ring cursor-pointer', isSelected && 'bg-selected-surface')}
106
106
  onClick={handleSelect}
107
107
  >
108
- <Card.Toolbar>
108
+ <Card.Header>
109
109
  <Avatar.Root>
110
110
  <Avatar.Content
111
111
  hue={data.properties.hue}
@@ -118,7 +118,7 @@ const NavBranchTile: MosaicStackTileComponent<Node.Node> = (props) => {
118
118
  <Avatar.Label>{name}</Avatar.Label>
119
119
  <Icon icon='ph--caret-right--regular' />
120
120
  </Avatar.Root>
121
- </Card.Toolbar>
121
+ </Card.Header>
122
122
  </Card.Root>
123
123
  );
124
124
  };
@@ -84,6 +84,7 @@ export const PopoverContent = () => {
84
84
  [handleClose],
85
85
  );
86
86
 
87
+ /* TODO(thure): Make this a constant and document it. */
87
88
  const collisionBoundaries: HTMLElement[] = useMemo(() => {
88
89
  const closest = state.popoverAnchor?.closest('[data-popover-collision-boundary]') as HTMLElement | null | undefined;
89
90
  return closest ? [closest] : [];
@@ -96,6 +97,7 @@ export const PopoverContent = () => {
96
97
  sticky='always'
97
98
  hideWhenDetached
98
99
  collisionBoundary={collisionBoundaries}
100
+ onOpenAutoFocus={(event) => event.preventDefault()}
99
101
  onInteractOutside={handleInteractOutside}
100
102
  onEscapeKeyDown={handleInteractOutside}
101
103
  >
@@ -105,12 +107,12 @@ export const PopoverContent = () => {
105
107
  )}
106
108
  {state.popoverKind === 'card' && (
107
109
  <Card.Root border={false} classNames='dx-card-popover'>
108
- <Card.Toolbar>
109
- {/* TODO(wittjosiah): Cleaner way to handle no drag handle in toolbar? */}
110
- <span />
110
+ <Card.Header>
111
+ {/* Disabled drag handle keeps the toolbar slot layout consistent with regular cards. */}
112
+ <Card.DragHandle />
111
113
  {state.popoverTitle ? <Card.Title>{toLocalizedString(state.popoverTitle, t)}</Card.Title> : <span />}
112
- <Card.CloseIconButton onClick={handleClose} />
113
- </Card.Toolbar>
114
+ <Card.ActionIconButton action='close' onClick={handleClose} />
115
+ </Card.Header>
114
116
  {state.popoverContent && 'subject' in state.popoverContent && (
115
117
  <Surface.Surface type={AppSurface.Card} data={state.popoverContent} limit={1} />
116
118
  )}
@@ -5,9 +5,10 @@
5
5
  import { type Atom, useAtomValue } from '@effect-atom/atom-react';
6
6
  import React, { Fragment } from 'react';
7
7
 
8
- import { IconButton, Popover, Toolbar, useTranslation } from '@dxos/react-ui';
8
+ import { DensityProvider, IconButton, Popover, Toolbar, useTranslation } from '@dxos/react-ui';
9
+ import { composable, composableProps } from '@dxos/react-ui';
9
10
  import { type ActionExecutor, type ActionGraphProps, Menu, useMenuActions } from '@dxos/react-ui-menu';
10
- import { composable, composableProps, osTranslations } from '@dxos/ui-theme';
11
+ import { osTranslations } from '@dxos/ui-theme';
11
12
 
12
13
  import { meta } from '#meta';
13
14
 
@@ -48,45 +49,47 @@ export const AppBar = composable<HTMLDivElement, AppBarProps>(
48
49
  const AnchorRoot = popoverAnchorId ? Popover.Anchor : Fragment;
49
50
 
50
51
  return (
51
- <Toolbar.Root
52
- {...composableProps(props, {
53
- role: 'banner',
54
- classNames: 'grid grid-cols-[var(--dx-rail-size)_1fr_var(--dx-rail-size)] items-center dx-density-fine',
55
- })}
56
- ref={forwardedRef}
57
- >
58
- {keyboardOpen ? (
59
- <IconButton variant='ghost' icon='ph--x--regular' iconOnly label={t('done.label')} />
60
- ) : showBackButton ? (
61
- <IconButton
62
- variant='ghost'
63
- icon='ph--caret-left--regular'
64
- iconOnly
65
- label={t('back.label')}
66
- onClick={onBack}
67
- />
68
- ) : (
69
- <div />
70
- )}
71
- <h1 className='text-center truncate font-thin uppercase'>{displayTitle}</h1>
72
- {hasActions ? (
73
- <AnchorRoot>
74
- <Menu.Root {...menuActions} caller={meta.id} onAction={onAction}>
75
- <Menu.Trigger asChild>
76
- <IconButton
77
- variant='ghost'
78
- icon='ph--dots-three-vertical--regular'
79
- iconOnly
80
- label={t('actions-menu.label')}
81
- />
82
- </Menu.Trigger>
83
- <Menu.Content />
84
- </Menu.Root>
85
- </AnchorRoot>
86
- ) : (
87
- <span />
88
- )}
89
- </Toolbar.Root>
52
+ <DensityProvider density='md'>
53
+ <Toolbar.Root
54
+ {...composableProps(props, {
55
+ role: 'banner',
56
+ classNames: 'grid grid-cols-[var(--dx-rail-size)_1fr_var(--dx-rail-size)] items-center dx-density-md',
57
+ })}
58
+ ref={forwardedRef}
59
+ >
60
+ {keyboardOpen ? (
61
+ <IconButton variant='ghost' icon='ph--x--regular' iconOnly label={t('done.label')} />
62
+ ) : showBackButton ? (
63
+ <IconButton
64
+ variant='ghost'
65
+ icon='ph--caret-left--regular'
66
+ iconOnly
67
+ label={t('back.label')}
68
+ onClick={onBack}
69
+ />
70
+ ) : (
71
+ <div />
72
+ )}
73
+ <h1 className='text-center truncate font-thin uppercase'>{displayTitle}</h1>
74
+ {hasActions ? (
75
+ <AnchorRoot>
76
+ <Menu.Root {...menuActions} caller={meta.id} onAction={onAction}>
77
+ <Menu.Trigger asChild>
78
+ <IconButton
79
+ variant='ghost'
80
+ icon='ph--dots-three-vertical--regular'
81
+ iconOnly
82
+ label={t('actions-menu.label')}
83
+ />
84
+ </Menu.Trigger>
85
+ <Menu.Content />
86
+ </Menu.Root>
87
+ </AnchorRoot>
88
+ ) : (
89
+ <span />
90
+ )}
91
+ </Toolbar.Root>
92
+ </DensityProvider>
90
93
  );
91
94
  },
92
95
  );
@@ -5,8 +5,8 @@
5
5
  import { type Atom } from '@effect-atom/atom-react';
6
6
  import React from 'react';
7
7
 
8
+ import { composable, composableProps } from '@dxos/react-ui';
8
9
  import { type ActionExecutor, type ActionGraphProps, Menu, useMenuActions } from '@dxos/react-ui-menu';
9
- import { composable, composableProps } from '@dxos/ui-theme';
10
10
 
11
11
  const NAVBAR_NAME = 'SimpleLayout.NavBar';
12
12
 
@@ -9,9 +9,9 @@ import { ActivationEvents, Capability, Plugin } from '@dxos/app-framework';
9
9
  import { withPluginManager } from '@dxos/app-framework/testing';
10
10
  import { AppActivationEvents } from '@dxos/app-toolkit';
11
11
  import { Collection } from '@dxos/echo';
12
- import { ClientPlugin } from '@dxos/plugin-client/plugin';
13
- import { SearchPlugin } from '@dxos/plugin-search/plugin';
14
- import { SpacePlugin } from '@dxos/plugin-space/plugin';
12
+ import { ClientPlugin } from '@dxos/plugin-client/testing';
13
+ import { SearchPlugin } from '@dxos/plugin-search/testing';
14
+ import { SpacePlugin } from '@dxos/plugin-space/testing';
15
15
  import { corePlugins } from '@dxos/plugin-testing';
16
16
  import { translations as searchTranslation } from '@dxos/react-ui-search/translations';
17
17
  import { withLayout } from '@dxos/react-ui/testing';
@@ -59,7 +59,7 @@ export const createCompanionActions = (
59
59
  id: `${idPrefix}-companion-${companion.id}`,
60
60
  type: Node.ActionType,
61
61
  properties: {
62
- icon: companion.properties.icon ?? 'ph--placeholder--regular',
62
+ icon: companion.properties.icon ?? 'ph--circle-dashed--regular',
63
63
  label: companion.properties.label,
64
64
  iconOnly: true,
65
65
  ...(selectedVariant !== undefined && {
package/src/meta.ts CHANGED
@@ -2,16 +2,18 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Plugin } from '@dxos/app-framework';
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { DXN } from '@dxos/keys';
6
7
  import { trim } from '@dxos/util';
7
8
 
8
- export const meta: Plugin.Meta = {
9
- id: 'org.dxos.plugin.simpleLayout',
9
+ export const meta = Plugin.makeMeta({
10
+ key: DXN.make('org.dxos.plugin.simpleLayout'),
10
11
  name: 'Simple Layout',
12
+ author: 'DXOS',
11
13
  description: trim`
12
14
  Minimal layout plugin for simplified UI contexts like popover windows.
13
15
  Provides basic content rendering without sidebars or complex navigation.
14
16
  `,
15
17
  icon: 'ph--layout--regular',
16
18
  tags: ['system'],
17
- };
19
+ });
@@ -1,6 +1,7 @@
1
1
  // Copyright 2025 DXOS.org
2
2
 
3
3
  import * as Effect from 'effect/Effect';
4
+ import * as Option from 'effect/Option';
4
5
 
5
6
  import { Capability } from '@dxos/app-framework';
6
7
  import {
@@ -11,6 +12,8 @@ import {
11
12
  } from '@dxos/app-toolkit';
12
13
  import { Operation } from '@dxos/compute';
13
14
  import { Context } from '@dxos/context';
15
+ import { Database, EID } from '@dxos/echo';
16
+ import { log } from '@dxos/log';
14
17
  import { ClientCapabilities } from '@dxos/plugin-client';
15
18
 
16
19
  import { layoutStateAccess } from './state-access';
@@ -18,6 +21,7 @@ import { layoutStateAccess } from './state-access';
18
21
  const handler: Operation.WithHandler<typeof LayoutOperation.Open> = LayoutOperation.Open.pipe(
19
22
  Operation.withHandler(
20
23
  Effect.fnUntraced(function* (input) {
24
+ log('LayoutOperation.Open handler start');
21
25
  const { graph } = yield* Capability.get(AppCapabilities.AppGraph);
22
26
  const { updateState } = yield* layoutStateAccess;
23
27
  const id = input.subject[0];
@@ -25,12 +29,26 @@ const handler: Operation.WithHandler<typeof LayoutOperation.Open> = LayoutOperat
25
29
  // Validate navigation target, redirecting to 404 if not found.
26
30
  const capabilities = yield* Capability.Service;
27
31
  const pathResolvers = capabilities.getAll(AppCapabilities.NavigationPathResolver);
28
- const checkRemoteExistence = yield* Capability.get(ClientCapabilities.Client).pipe(
29
- Effect.map((client) =>
30
- createEdgeExistenceChecker((spaceId, body) => client.edge.http.execQuery(new Context(), spaceId, body)),
31
- ),
32
+ const client = yield* Capability.get(ClientCapabilities.Client).pipe(
32
33
  Effect.catchAll(() => Effect.succeed(undefined)),
33
34
  );
35
+ // Existence checkers for the resolved EID: local (loadOption) first, then remote (edge).
36
+ const checkLocalExistence = client
37
+ ? (uri: EID.EID) => {
38
+ const spaceId = EID.getSpaceId(uri);
39
+ const space = spaceId ? client.spaces.get(spaceId) : undefined;
40
+ if (!space) {
41
+ return Effect.succeed(false);
42
+ }
43
+ return Database.loadOption(space.db.makeRef(uri)).pipe(
44
+ Effect.map(Option.isSome),
45
+ Effect.catchAll(() => Effect.succeed(false)),
46
+ );
47
+ }
48
+ : undefined;
49
+ const checkRemoteExistence = client
50
+ ? createEdgeExistenceChecker((spaceId, body) => client.edge.http.execQuery(new Context(), spaceId, body))
51
+ : undefined;
34
52
 
35
53
  const validatedId =
36
54
  input.navigation === 'immediate'
@@ -39,6 +57,7 @@ const handler: Operation.WithHandler<typeof LayoutOperation.Open> = LayoutOperat
39
57
  graph,
40
58
  subjectId: id,
41
59
  pathResolvers,
60
+ checkLocalExistence,
42
61
  checkRemoteExistence,
43
62
  });
44
63
 
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Plugin } from '@dxos/app-framework';\nimport { trim } from '@dxos/util';\n\nexport const meta: Plugin.Meta = {\n id: 'org.dxos.plugin.simpleLayout',\n name: 'Simple Layout',\n description: trim`\n Minimal layout plugin for simplified UI contexts like popover windows.\n Provides basic content rendering without sidebars or complex navigation.\n `,\n icon: 'ph--layout--regular',\n tags: ['system'],\n};\n"],
5
- "mappings": ";AAKA,SAASA,YAAY;AAEd,IAAMC,OAAoB;EAC/BC,IAAI;EACJC,MAAM;EACNC,aAAaJ;;;;EAIbK,MAAM;EACNC,MAAM;IAAC;;AACT;",
6
- "names": ["trim", "meta", "id", "name", "description", "icon", "tags"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/operations/open.ts"],
4
- "sourcesContent": ["// Copyright 2025 DXOS.org\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability } from '@dxos/app-framework';\nimport {\n AppCapabilities,\n LayoutOperation,\n createEdgeExistenceChecker,\n validateNavigationTarget,\n} from '@dxos/app-toolkit';\nimport { Operation } from '@dxos/compute';\nimport { Context } from '@dxos/context';\nimport { ClientCapabilities } from '@dxos/plugin-client';\n\nimport { layoutStateAccess } from './state-access';\n\nconst handler: Operation.WithHandler<typeof LayoutOperation.Open> = LayoutOperation.Open.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* (input) {\n const { graph } = yield* Capability.get(AppCapabilities.AppGraph);\n const { updateState } = yield* layoutStateAccess;\n const id = input.subject[0];\n\n // Validate navigation target, redirecting to 404 if not found.\n const capabilities = yield* Capability.Service;\n const pathResolvers = capabilities.getAll(AppCapabilities.NavigationPathResolver);\n const checkRemoteExistence = yield* Capability.get(ClientCapabilities.Client).pipe(\n Effect.map((client) =>\n createEdgeExistenceChecker((spaceId, body) => client.edge.http.execQuery(new Context(), spaceId, body)),\n ),\n Effect.catchAll(() => Effect.succeed(undefined)),\n );\n\n const validatedId =\n input.navigation === 'immediate'\n ? id\n : yield* validateNavigationTarget({\n graph,\n subjectId: id,\n pathResolvers,\n checkRemoteExistence,\n });\n\n updateState((state) => {\n const newHistory = state.active ? [...state.history, state.active] : state.history;\n const trimmedHistory =\n newHistory.length > MAX_HISTORY_LENGTH ? newHistory.slice(-MAX_HISTORY_LENGTH) : newHistory;\n return {\n ...state,\n active: validatedId,\n history: trimmedHistory,\n };\n });\n\n return [validatedId];\n }),\n ),\n);\n\nexport default handler;\n\nconst MAX_HISTORY_LENGTH = 50;\n"],
5
- "mappings": ";;;;;;;AAEA,YAAYA,YAAY;AAExB,SAASC,kBAAkB;AAC3B,SACEC,iBACAC,iBACAC,4BACAC,gCACK;AACP,SAASC,iBAAiB;AAC1B,SAASC,eAAe;AACxB,SAASC,0BAA0B;AAInC,IAAA,eAAoEC;IAI9D,UAAQC,gBAAgB,KAAOC,KAAAA,UAAAA,YAAAA,kBAAAA,WAAAA,OAAAA;AAC/B,QAAMC,EAAAA,MAAKC,IAAMC,OAAQ,WAAE,IAAA,gBAAA,QAAA;AAE3B,QAAA,EAAA,YAAA,IAAA,OAAA;AACA,QAAMC,KAAAA,MAAAA,QAAe,CAAA;AAErB,QAAMC,eAAAA,OAAAA,WAA8BC;AAOpC,QAAMC,gBACJL,aAAMM,OAAe,gBACjBP,sBACOQ;QACLC,uBAAAA,OAAAA,WAAAA,IAAAA,mBAAAA,MAAAA,EAAAA,KAAAA,WAAAA,CAAAA,WAAAA,2BAAAA,CAAAA,SAAAA,SAAAA,OAAAA,KAAAA,KAAAA,UAAAA,IAAAA,QAAAA,QAAAA,EAAAA,YAAAA,YAAAA,GAAAA,cAAAA,GAAAA,GAAAA,CAAAA,GAAAA,SAAAA,IAAAA,CAAAA,CAAAA,GAAAA,gBAAAA,MAAAA,eAAAA,MAAAA,CAAAA,CAAAA;QACAC,cAAWV,MAAAA,eAAAA,cAAAA,KAAAA,OAAAA,yBAAAA;IACXW;IACAP,WAAAA;IACF;IAENN;;cACwCc,CAAAA,UAAMC;UAASD,aAAY,MAAA,SAAA;MAAIA,GAAAA,MAAMC;MAC3E,MAAMC;IAEN,IAAA,MAAO;UACL,iBAAQ,WAAA,SAAA,qBAAA,WAAA,MAAA,CAAA,kBAAA,IAAA;WACRC;MACAF,GAAAA;MACF,QAAA;MACF,SAAA;IAEA;;SAAoB;IACtB;EAIJ;AAEA,CAAA,CAAA,CAAA;;;",
6
- "names": ["Effect", "Capability", "AppCapabilities", "LayoutOperation", "createEdgeExistenceChecker", "validateNavigationTarget", "Operation", "Context", "ClientCapabilities", "LayoutOperation", "updateState", "layoutStateAccess", "id", "input", "subject", "capabilities", "checkRemoteExistence", "Capability", "validatedId", "navigation", "validateNavigationTarget", "graph", "subjectId", "pathResolvers", "state", "history", "trimmedHistory", "active"]
7
- }