@dxos/plugin-deck 0.7.5-main.ff8607b → 0.7.5-staging.b81e783

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 (114) hide show
  1. package/dist/lib/browser/{app-graph-builder-CI6ZFMNL.mjs → app-graph-builder-IYHAGFA3.mjs} +6 -2
  2. package/dist/lib/browser/{app-graph-builder-CI6ZFMNL.mjs.map → app-graph-builder-IYHAGFA3.mjs.map} +3 -3
  3. package/dist/lib/browser/{chunk-YQ2GWTDU.mjs → chunk-22AQ5IVX.mjs} +1 -1
  4. package/dist/lib/browser/{chunk-YQ2GWTDU.mjs.map → chunk-22AQ5IVX.mjs.map} +2 -2
  5. package/dist/lib/browser/chunk-AOAWF7JV.mjs +24 -0
  6. package/dist/lib/browser/{chunk-NYZJCVAU.mjs.map → chunk-AOAWF7JV.mjs.map} +3 -3
  7. package/dist/lib/browser/{chunk-M2L53AIH.mjs → chunk-CYE6QZBQ.mjs} +4 -2
  8. package/dist/lib/browser/chunk-CYE6QZBQ.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-WXNLVMK2.mjs → chunk-DIXE74SK.mjs} +95 -117
  10. package/dist/lib/browser/chunk-DIXE74SK.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-KANJBSIX.mjs +97 -0
  12. package/dist/lib/browser/chunk-KANJBSIX.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +18 -5
  14. package/dist/lib/browser/index.mjs.map +3 -3
  15. package/dist/lib/browser/{intent-resolver-CSXFDKTC.mjs → intent-resolver-MWUADUNI.mjs} +42 -48
  16. package/dist/lib/browser/intent-resolver-MWUADUNI.mjs.map +7 -0
  17. package/dist/lib/browser/meta.json +1 -1
  18. package/dist/lib/browser/{react-root-ECDQZYQT.mjs → react-root-XCWQYEOK.mjs} +7 -8
  19. package/dist/lib/browser/react-root-XCWQYEOK.mjs.map +7 -0
  20. package/dist/lib/browser/{react-surface-4WIQZW2S.mjs → react-surface-IU3LLZDI.mjs} +6 -5
  21. package/dist/lib/browser/{react-surface-4WIQZW2S.mjs.map → react-surface-IU3LLZDI.mjs.map} +1 -1
  22. package/dist/lib/browser/{settings-WACNLCPB.mjs → settings-YONG3QB7.mjs} +2 -2
  23. package/dist/lib/browser/{state-VPOYUKK6.mjs → state-MZZL5S2D.mjs} +11 -4
  24. package/dist/lib/browser/state-MZZL5S2D.mjs.map +7 -0
  25. package/dist/lib/browser/tools-5LDJNU56.mjs +51 -0
  26. package/dist/lib/browser/tools-5LDJNU56.mjs.map +7 -0
  27. package/dist/lib/browser/types.mjs +1 -1
  28. package/dist/lib/browser/{url-handler-HLF42IHP.mjs → url-handler-BIEBKATX.mjs} +5 -5
  29. package/dist/lib/browser/{url-handler-HLF42IHP.mjs.map → url-handler-BIEBKATX.mjs.map} +3 -3
  30. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  31. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  32. package/dist/types/src/capabilities/capabilities.d.ts +8 -8
  33. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  34. package/dist/types/src/capabilities/index.d.ts +1 -0
  35. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  36. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  37. package/dist/types/src/capabilities/react-root.d.ts.map +1 -1
  38. package/dist/types/src/capabilities/state.d.ts +4 -1
  39. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  40. package/dist/types/src/capabilities/tools.d.ts +10 -0
  41. package/dist/types/src/capabilities/tools.d.ts.map +1 -0
  42. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts +1 -2
  43. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
  44. package/dist/types/src/components/DeckLayout/Banner.d.ts +1 -2
  45. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -1
  46. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts +1 -4
  47. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
  48. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts +1 -2
  49. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
  50. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +2 -4
  51. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  52. package/dist/types/src/components/DeckLayout/Fallback.d.ts +1 -2
  53. package/dist/types/src/components/DeckLayout/Fallback.d.ts.map +1 -1
  54. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +1 -2
  55. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +1 -1
  56. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +1 -1
  57. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
  58. package/dist/types/src/components/DeckLayout/Plank.d.ts +1 -1
  59. package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
  60. package/dist/types/src/components/DeckLayout/PlankError.d.ts +2 -3
  61. package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
  62. package/dist/types/src/components/DeckLayout/PlankLoading.d.ts +1 -2
  63. package/dist/types/src/components/DeckLayout/PlankLoading.d.ts.map +1 -1
  64. package/dist/types/src/components/DeckLayout/Sidebar.d.ts +1 -2
  65. package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
  66. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts +3 -4
  67. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +1 -1
  68. package/dist/types/src/components/DeckLayout/StatusBar.d.ts +1 -2
  69. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
  70. package/dist/types/src/components/DeckLayout/Toast.d.ts +1 -2
  71. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  72. package/dist/types/src/components/DeckLayout/Topbar.d.ts +1 -2
  73. package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +1 -1
  74. package/dist/types/src/components/LayoutSettings.d.ts +1 -2
  75. package/dist/types/src/components/LayoutSettings.d.ts.map +1 -1
  76. package/dist/types/src/events.d.ts +1 -0
  77. package/dist/types/src/events.d.ts.map +1 -1
  78. package/dist/types/src/hooks/useNode.d.ts.map +1 -1
  79. package/dist/types/src/types.d.ts +5 -1
  80. package/dist/types/src/types.d.ts.map +1 -1
  81. package/dist/types/src/util/index.d.ts +1 -0
  82. package/dist/types/src/util/index.d.ts.map +1 -1
  83. package/dist/types/src/util/set-active.d.ts.map +1 -0
  84. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -1
  85. package/package.json +31 -30
  86. package/src/DeckPlugin.ts +14 -4
  87. package/src/capabilities/app-graph-builder.ts +4 -0
  88. package/src/capabilities/capabilities.ts +3 -6
  89. package/src/capabilities/index.ts +1 -0
  90. package/src/capabilities/intent-resolver.ts +26 -8
  91. package/src/capabilities/react-root.tsx +1 -3
  92. package/src/capabilities/state.ts +6 -1
  93. package/src/capabilities/tools.ts +61 -0
  94. package/src/capabilities/url-handler.ts +3 -3
  95. package/src/components/DeckLayout/ComplementarySidebar.tsx +33 -23
  96. package/src/components/DeckLayout/DeckLayout.tsx +41 -26
  97. package/src/components/DeckLayout/Plank.tsx +4 -3
  98. package/src/components/DeckLayout/PlankControls.tsx +1 -1
  99. package/src/events.ts +1 -0
  100. package/src/hooks/useNode.ts +3 -1
  101. package/src/layout.ts +1 -1
  102. package/src/types.ts +10 -3
  103. package/src/util/index.ts +1 -0
  104. package/src/{capabilities → util}/set-active.ts +4 -0
  105. package/src/util/useHoistStatusbar.ts +4 -8
  106. package/dist/lib/browser/chunk-M2L53AIH.mjs.map +0 -7
  107. package/dist/lib/browser/chunk-NYZJCVAU.mjs +0 -22
  108. package/dist/lib/browser/chunk-WXNLVMK2.mjs.map +0 -7
  109. package/dist/lib/browser/intent-resolver-CSXFDKTC.mjs.map +0 -7
  110. package/dist/lib/browser/react-root-ECDQZYQT.mjs.map +0 -7
  111. package/dist/lib/browser/state-VPOYUKK6.mjs.map +0 -7
  112. package/dist/types/src/capabilities/set-active.d.ts.map +0 -1
  113. /package/dist/lib/browser/{settings-WACNLCPB.mjs.map → settings-YONG3QB7.mjs.map} +0 -0
  114. /package/dist/types/src/{capabilities → util}/set-active.d.ts +0 -0
@@ -1,4 +1,5 @@
1
1
  export * from './overscroll';
2
+ export * from './set-active';
2
3
  export * from './useBreakpoints';
3
4
  export * from './layoutAppliesTopbar';
4
5
  export * from './useHoistStatusbar';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/util/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/util/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set-active.d.ts","sourceRoot":"","sources":["../../../../src/util/set-active.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,SAAS,+BAAgC,gBAAgB,uBA8BrE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useHoistStatusbar.d.ts","sourceRoot":"","sources":["../../../../src/util/useHoistStatusbar.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,iBAAiB,eAAgB,MAAM,YAYnD,CAAC"}
1
+ {"version":3,"file":"useHoistStatusbar.d.ts","sourceRoot":"","sources":["../../../../src/util/useHoistStatusbar.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,iBAAiB,eAAgB,MAAM,YAOnD,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@dxos/plugin-deck",
3
- "version": "0.7.5-main.ff8607b",
3
+ "version": "0.7.5-staging.b81e783",
4
4
  "description": "DXOS Surface plugin for the main application layout.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
7
  "license": "MIT",
8
8
  "author": "DXOS.org",
9
9
  "sideEffects": true,
10
+ "type": "module",
10
11
  "exports": {
11
12
  ".": {
12
13
  "types": "./dist/types/src/index.d.ts",
@@ -32,31 +33,31 @@
32
33
  "dependencies": {
33
34
  "@fluentui/react-tabster": "9.23.3",
34
35
  "@preact/signals-core": "^1.6.0",
35
- "effect": "^3.12.1",
36
+ "effect": "^3.12.3",
36
37
  "immer": "^10.1.1",
37
- "@dxos/app-framework": "0.7.5-main.ff8607b",
38
- "@dxos/async": "0.7.5-main.ff8607b",
39
- "@dxos/echo-schema": "0.7.5-main.ff8607b",
40
- "@dxos/debug": "0.7.5-main.ff8607b",
41
- "@dxos/echo-signals": "0.7.5-main.ff8607b",
42
- "@dxos/invariant": "0.7.5-main.ff8607b",
43
- "@dxos/keyboard": "0.7.5-main.ff8607b",
44
- "@dxos/local-storage": "0.7.5-main.ff8607b",
45
- "@dxos/live-object": "0.7.5-main.ff8607b",
46
- "@dxos/log": "0.7.5-main.ff8607b",
47
- "@dxos/plugin-attention": "0.7.5-main.ff8607b",
48
- "@dxos/plugin-client": "0.7.5-main.ff8607b",
49
- "@dxos/plugin-graph": "0.7.5-main.ff8607b",
50
- "@dxos/plugin-observability": "0.7.5-main.ff8607b",
51
- "@dxos/plugin-theme": "0.7.5-main.ff8607b",
52
- "@dxos/react-client": "0.7.5-main.ff8607b",
53
- "@dxos/react-ui-form": "0.7.5-main.ff8607b",
54
- "@dxos/react-ui-attention": "0.7.5-main.ff8607b",
55
- "@dxos/react-ui-mosaic": "0.7.5-main.ff8607b",
56
- "@dxos/react-ui-stack": "0.7.5-main.ff8607b",
57
- "@dxos/react-ui-tabs": "0.7.5-main.ff8607b",
58
- "@dxos/util": "0.7.5-main.ff8607b",
59
- "@dxos/react-ui-text-tooltip": "0.7.5-main.ff8607b"
38
+ "@dxos/artifact": "0.7.5-staging.b81e783",
39
+ "@dxos/async": "0.7.5-staging.b81e783",
40
+ "@dxos/debug": "0.7.5-staging.b81e783",
41
+ "@dxos/echo-schema": "0.7.5-staging.b81e783",
42
+ "@dxos/invariant": "0.7.5-staging.b81e783",
43
+ "@dxos/echo-signals": "0.7.5-staging.b81e783",
44
+ "@dxos/keyboard": "0.7.5-staging.b81e783",
45
+ "@dxos/live-object": "0.7.5-staging.b81e783",
46
+ "@dxos/plugin-attention": "0.7.5-staging.b81e783",
47
+ "@dxos/local-storage": "0.7.5-staging.b81e783",
48
+ "@dxos/log": "0.7.5-staging.b81e783",
49
+ "@dxos/plugin-client": "0.7.5-staging.b81e783",
50
+ "@dxos/plugin-graph": "0.7.5-staging.b81e783",
51
+ "@dxos/app-framework": "0.7.5-staging.b81e783",
52
+ "@dxos/plugin-observability": "0.7.5-staging.b81e783",
53
+ "@dxos/plugin-theme": "0.7.5-staging.b81e783",
54
+ "@dxos/react-client": "0.7.5-staging.b81e783",
55
+ "@dxos/react-ui-attention": "0.7.5-staging.b81e783",
56
+ "@dxos/react-ui-stack": "0.7.5-staging.b81e783",
57
+ "@dxos/react-ui-tabs": "0.7.5-staging.b81e783",
58
+ "@dxos/react-ui-text-tooltip": "0.7.5-staging.b81e783",
59
+ "@dxos/react-ui-form": "0.7.5-staging.b81e783",
60
+ "@dxos/util": "0.7.5-staging.b81e783"
60
61
  },
61
62
  "devDependencies": {
62
63
  "@phosphor-icons/react": "^2.1.5",
@@ -65,16 +66,16 @@
65
66
  "react": "~18.2.0",
66
67
  "react-dom": "~18.2.0",
67
68
  "vite": "5.4.7",
68
- "@dxos/react-ui-theme": "0.7.5-main.ff8607b",
69
- "@dxos/react-ui": "0.7.5-main.ff8607b",
70
- "@dxos/storybook-utils": "0.7.5-main.ff8607b"
69
+ "@dxos/react-ui": "0.7.5-staging.b81e783",
70
+ "@dxos/storybook-utils": "0.7.5-staging.b81e783",
71
+ "@dxos/react-ui-theme": "0.7.5-staging.b81e783"
71
72
  },
72
73
  "peerDependencies": {
73
74
  "@phosphor-icons/react": "^2.0.5",
74
75
  "react": "~18.2.0",
75
76
  "react-dom": "~18.2.0",
76
- "@dxos/react-ui": "0.7.5-main.ff8607b",
77
- "@dxos/react-ui-theme": "0.7.5-main.ff8607b"
77
+ "@dxos/react-ui-theme": "0.7.5-staging.b81e783",
78
+ "@dxos/react-ui": "0.7.5-staging.b81e783"
78
79
  },
79
80
  "publishConfig": {
80
81
  "access": "public"
package/src/DeckPlugin.ts CHANGED
@@ -10,11 +10,12 @@ import { translations as stackTranslations } from '@dxos/react-ui-stack';
10
10
  import {
11
11
  AppGraphBuilder,
12
12
  CheckAppScheme,
13
+ DeckSettings,
13
14
  DeckState,
14
15
  LayoutIntentResolver,
15
16
  ReactRoot,
16
- DeckSettings,
17
17
  ReactSurface,
18
+ Tools,
18
19
  UrlHandler,
19
20
  } from './capabilities';
20
21
  import { DeckEvents } from './events';
@@ -40,7 +41,10 @@ export const DeckPlugin = () =>
40
41
  }),
41
42
  defineModule({
42
43
  id: `${meta.id}/module/layout`,
43
- activatesOn: oneOf(Events.Startup, Events.SetupAppGraph),
44
+ // TODO(wittjosiah): Does not integrate with settings store.
45
+ // Should this be a different event?
46
+ // Should settings store be renamed to be more generic?
47
+ activatesOn: oneOf(Events.SetupSettings, Events.SetupAppGraph),
44
48
  activatesAfter: [Events.LayoutReady, DeckEvents.StateReady],
45
49
  activate: DeckState,
46
50
  }),
@@ -52,16 +56,17 @@ export const DeckPlugin = () =>
52
56
  defineModule({
53
57
  id: `${meta.id}/module/react-root`,
54
58
  activatesOn: Events.Startup,
59
+ activatesBefore: [DeckEvents.SetupComplementaryPanels],
55
60
  activate: ReactRoot,
56
61
  }),
57
62
  defineModule({
58
63
  id: `${meta.id}/module/react-surface`,
59
- activatesOn: Events.SetupSurfaces,
64
+ activatesOn: Events.SetupReactSurface,
60
65
  activate: ReactSurface,
61
66
  }),
62
67
  defineModule({
63
68
  id: `${meta.id}/module/layout-intent-resolver`,
64
- activatesOn: Events.SetupIntents,
69
+ activatesOn: Events.SetupIntentResolver,
65
70
  activate: LayoutIntentResolver,
66
71
  }),
67
72
  defineModule({
@@ -69,6 +74,11 @@ export const DeckPlugin = () =>
69
74
  activatesOn: Events.SetupAppGraph,
70
75
  activate: AppGraphBuilder,
71
76
  }),
77
+ defineModule({
78
+ id: `${meta.id}/module/tools`,
79
+ activatesOn: Events.SetupArtifactDefinition,
80
+ activate: Tools,
81
+ }),
72
82
  defineModule({
73
83
  id: `${meta.id}/module/url`,
74
84
  activatesOn: allOf(Events.DispatcherReady, DeckEvents.StateReady),
@@ -98,7 +98,11 @@ export default (context: PluginsContext) =>
98
98
  { ns: DECK_PLUGIN },
99
99
  ],
100
100
  icon: 'ph--sidebar--regular',
101
+ keyBinding: {
102
+ macos: 'meta+b',
103
+ },
101
104
  disposition: 'pin-end',
105
+ position: 'hoist',
102
106
  l0Breakpoint: 'lg',
103
107
  },
104
108
  };
@@ -2,17 +2,14 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { defineCapability, type Label } from '@dxos/app-framework';
5
+ import { defineCapability } from '@dxos/app-framework';
6
6
  import { type DeepReadonly } from '@dxos/util';
7
7
 
8
8
  import { DECK_PLUGIN } from '../meta';
9
- import { type DeckState } from '../types';
9
+ import { type DeckState, type Panel } from '../types';
10
10
 
11
11
  export namespace DeckCapabilities {
12
12
  export const DeckState = defineCapability<DeepReadonly<DeckState>>(`${DECK_PLUGIN}/capability/state`);
13
13
  export const MutableDeckState = defineCapability<DeckState>(`${DECK_PLUGIN}/capability/state`);
14
-
15
- export const ComplementaryPanel = defineCapability<{ id: string; label: Label; icon: string }>(
16
- `${DECK_PLUGIN}/capability/complementary-panel`,
17
- );
14
+ export const ComplementaryPanel = defineCapability<Panel>(`${DECK_PLUGIN}/capability/complementary-panel`);
18
15
  }
@@ -11,6 +11,7 @@ export const ReactRoot = lazy(() => import('./react-root'));
11
11
  export const ReactSurface = lazy(() => import('./react-surface'));
12
12
  export const DeckSettings = lazy(() => import('./settings'));
13
13
  export const DeckState = lazy(() => import('./state'));
14
+ export const Tools = lazy(() => import('./tools'));
14
15
  export const UrlHandler = lazy(() => import('./url-handler'));
15
16
 
16
17
  export * from './capabilities';
@@ -20,13 +20,13 @@ import { isReactiveObject } from '@dxos/live-object';
20
20
  import { log } from '@dxos/log';
21
21
  import { AttentionCapabilities } from '@dxos/plugin-attention';
22
22
  import { ObservabilityAction } from '@dxos/plugin-observability/types';
23
- import { nonNullable } from '@dxos/util';
23
+ import { isNonNullable } from '@dxos/util';
24
24
 
25
25
  import { DeckCapabilities } from './capabilities';
26
- import { setActive } from './set-active';
27
26
  import { closeEntry, incrementPlank, openEntry } from '../layout';
28
27
  import { DECK_PLUGIN } from '../meta';
29
28
  import { DeckAction, type LayoutMode, type DeckSettingsProps, isLayoutMode, getMode } from '../types';
29
+ import { setActive } from '../util';
30
30
 
31
31
  export default (context: PluginsContext) =>
32
32
  contributes(Capabilities.IntentResolver, [
@@ -113,6 +113,7 @@ export default (context: PluginsContext) =>
113
113
  layout.popoverOpen = options.state ?? Boolean(subject);
114
114
  layout.popoverContent = subject ? { component: subject, props: options.props } : null;
115
115
  layout.popoverAnchorId = options.anchorId;
116
+ layout.popoverSide = options.side;
116
117
  },
117
118
  }),
118
119
  createResolver({
@@ -149,16 +150,16 @@ export default (context: PluginsContext) =>
149
150
  const current = deck.solo ? [deck.solo] : deck.active;
150
151
  // When un-soloing, the solo entry is added to the deck.
151
152
  const next = (
152
- mode === 'solo' ? [subject ?? deck.solo ?? deck.active[0]] : [...deck.active, deck.solo]
153
- ).filter(nonNullable);
153
+ mode !== 'deck' ? [subject ?? deck.solo ?? deck.active[0]] : [...deck.active, deck.solo]
154
+ ).filter(isNonNullable);
154
155
 
155
156
  const removed = current.filter((id) => !next.includes(id));
156
157
  const closed = Array.from(new Set([...deck.inactive.filter((id) => !next.includes(id)), ...removed]));
157
158
  deck.inactive = closed;
158
159
 
159
- if (mode === 'solo' && next[0]) {
160
+ if (mode !== 'deck' && next[0]) {
160
161
  deck.solo = next[0];
161
- } else if (mode !== 'solo' && deck.solo) {
162
+ } else if (mode === 'deck' && deck.solo) {
162
163
  deck.solo = undefined;
163
164
  deck.initialized = true;
164
165
  }
@@ -193,13 +194,18 @@ export default (context: PluginsContext) =>
193
194
  resolve: ({ subject }) => {
194
195
  const state = context.requestCapability(DeckCapabilities.MutableDeckState);
195
196
  batch(() => {
197
+ // TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.
198
+ // Ideally this should be worked into the data model in a generic way.
199
+ if (!state.activeDeck.startsWith('!')) {
200
+ state.previousDeck = state.activeDeck;
201
+ }
196
202
  state.activeDeck = subject;
197
203
  if (!state.decks[subject]) {
198
204
  state.decks[subject] = { initialized: false, active: [], inactive: [], fullscreen: false, plankSizing: {} };
199
205
  }
200
206
  });
201
207
 
202
- const first = state.decks[state.activeDeck].active[0];
208
+ const first = state.deck.solo ? state.deck.solo : state.deck.active[0];
203
209
  if (first) {
204
210
  return {
205
211
  intents: [createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: first })],
@@ -207,6 +213,17 @@ export default (context: PluginsContext) =>
207
213
  }
208
214
  },
209
215
  }),
216
+ createResolver({
217
+ intent: LayoutAction.UpdateLayout,
218
+ filter: (data): data is S.Schema.Type<typeof LayoutAction.RevertWorkspace.fields.input> =>
219
+ S.is(LayoutAction.RevertWorkspace.fields.input)(data),
220
+ resolve: () => {
221
+ const state = context.requestCapability(DeckCapabilities.MutableDeckState);
222
+ return {
223
+ intents: [createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: state.previousDeck })],
224
+ };
225
+ },
226
+ }),
210
227
  createResolver({
211
228
  intent: LayoutAction.UpdateLayout,
212
229
  filter: (data): data is S.Schema.Type<typeof LayoutAction.Open.fields.input> =>
@@ -267,7 +284,8 @@ export default (context: PluginsContext) =>
267
284
  resolve: ({ subject }) => {
268
285
  const state = context.requestCapability(DeckCapabilities.MutableDeckState);
269
286
  const attention = context.requestCapability(AttentionCapabilities.Attention);
270
- const next = subject.reduce((acc, id) => closeEntry(acc, id), state.deck.active);
287
+ const active = state.deck.solo ? [state.deck.solo] : state.deck.active;
288
+ const next = subject.reduce((acc, id) => closeEntry(acc, id), active);
271
289
  const toAttend = setActive({ next, state, attention });
272
290
  return {
273
291
  intents: toAttend ? [createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: toAttend })] : [],
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React, { useCallback } from 'react';
6
6
 
7
- import { Capabilities, contributes, useCapabilities, useCapability } from '@dxos/app-framework';
7
+ import { Capabilities, contributes, useCapability } from '@dxos/app-framework';
8
8
 
9
9
  import { DeckCapabilities } from './capabilities';
10
10
  import { DeckLayout } from '../components';
@@ -17,7 +17,6 @@ export default () =>
17
17
  root: () => {
18
18
  const layout = useCapability(DeckCapabilities.MutableDeckState);
19
19
  const settings = useCapability(Capabilities.SettingsStore).getStore<DeckSettingsProps>(DECK_PLUGIN)!.value;
20
- const panels = useCapabilities(DeckCapabilities.ComplementaryPanel);
21
20
 
22
21
  const handleDismissToast = useCallback(
23
22
  (id: string) => {
@@ -40,7 +39,6 @@ export default () =>
40
39
  <DeckLayout
41
40
  showHints={settings.showHints}
42
41
  overscroll={settings.overscroll}
43
- panels={panels}
44
42
  onDismissToast={handleDismissToast}
45
43
  />
46
44
  );
@@ -46,6 +46,7 @@ export default () => {
46
46
  toasts: [],
47
47
  currentUndoId: undefined,
48
48
  activeDeck: 'default',
49
+ previousDeck: 'default',
49
50
  decks: {
50
51
  default: {
51
52
  initialized: false,
@@ -69,7 +70,8 @@ export default () => {
69
70
  .prop({ key: 'sidebarState', type: LocalStorageStore.enum<SidebarState>() })
70
71
  .prop({ key: 'complementarySidebarState', type: LocalStorageStore.enum<SidebarState>() })
71
72
  .prop({ key: 'decks', type: LocalStorageStore.json<Record<string, Deck>>() })
72
- .prop({ key: 'activeDeck', type: LocalStorageStore.string() });
73
+ .prop({ key: 'activeDeck', type: LocalStorageStore.string() })
74
+ .prop({ key: 'previousDeck', type: LocalStorageStore.string() });
73
75
 
74
76
  const layout = create<Capabilities.Layout>({
75
77
  get mode() {
@@ -84,6 +86,9 @@ export default () => {
84
86
  get complementarySidebarOpen() {
85
87
  return state.values.complementarySidebarState === 'expanded';
86
88
  },
89
+ get workspace() {
90
+ return state.values.activeDeck;
91
+ },
87
92
  get active() {
88
93
  return state.values.deck.solo ? [state.values.deck.solo] : state.values.deck.active;
89
94
  },
@@ -0,0 +1,61 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import {
6
+ contributes,
7
+ createIntent,
8
+ Capabilities,
9
+ LayoutAction,
10
+ type PromiseIntentDispatcher,
11
+ } from '@dxos/app-framework';
12
+ import { defineTool, ToolResult } from '@dxos/artifact';
13
+ import { S } from '@dxos/echo-schema';
14
+ import { invariant } from '@dxos/invariant';
15
+
16
+ // TODO(burdon): Factor out.
17
+ declare global {
18
+ interface ToolContextExtensions {
19
+ dispatch?: PromiseIntentDispatcher;
20
+ pivotId?: string;
21
+ }
22
+ }
23
+
24
+ export default () =>
25
+ contributes(Capabilities.Tools, [
26
+ defineTool({
27
+ name: 'show',
28
+ // TODO(ZaymonFC): We should update the prompt to teach the LLM the difference between object ids and fully qualified ids.
29
+ description:
30
+ 'Show an item in the app. Use this tool to open an artifact. When supplying IDs to show, they must be fully qualified like space:object.',
31
+ // TODO(wittjosiah): Refactor Layout/Navigation/Deck actions so that they can be used directly.
32
+ schema: S.Struct({
33
+ id: S.String.annotations({
34
+ description: 'The ID of the item to show.',
35
+ }),
36
+ pivotId: S.optional(
37
+ S.String.annotations({
38
+ description: 'The ID of the chat. If provided, the item will be added after the pivot item.',
39
+ }),
40
+ ),
41
+ }),
42
+ execute: async ({ id }, { extensions }) => {
43
+ invariant(extensions?.dispatch, 'No intent dispatcher');
44
+ const { data, error } = await extensions.dispatch(
45
+ createIntent(LayoutAction.Open, {
46
+ subject: [id],
47
+ part: 'main',
48
+ options: {
49
+ pivotId: extensions.pivotId,
50
+ positioning: 'end',
51
+ },
52
+ }),
53
+ );
54
+ if (error) {
55
+ return ToolResult.Error(error.message);
56
+ }
57
+
58
+ return ToolResult.Success(data);
59
+ },
60
+ }),
61
+ ]);
@@ -31,15 +31,15 @@ export default async (context: PluginsContext) => {
31
31
  }
32
32
 
33
33
  const [_, nextDeck, nextSolo] = pathname.split('/');
34
- if (nextDeck) {
34
+ if (nextDeck && nextDeck !== state.activeDeck) {
35
35
  await dispatch(createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: nextDeck }));
36
36
  }
37
37
 
38
- if (nextSolo) {
38
+ if (nextSolo && nextSolo !== state.deck.solo) {
39
39
  await dispatch(
40
40
  createIntent(LayoutAction.SetLayoutMode, { part: 'mode', subject: nextSolo, options: { mode: 'solo' } }),
41
41
  );
42
- } else {
42
+ } else if (!nextSolo && state.deck.solo) {
43
43
  await dispatch(createIntent(LayoutAction.SetLayoutMode, { part: 'mode', options: { mode: 'deck' } }));
44
44
  }
45
45
  };
@@ -9,6 +9,7 @@ import {
9
9
  LayoutAction,
10
10
  Surface,
11
11
  useAppGraph,
12
+ useCapabilities,
12
13
  useCapability,
13
14
  useIntentDispatcher,
14
15
  } from '@dxos/app-framework';
@@ -20,31 +21,34 @@ import { PlankContentError } from './PlankError';
20
21
  import { PlankLoading } from './PlankLoading';
21
22
  import { ToggleComplementarySidebarButton } from './SidebarButton';
22
23
  import { DeckCapabilities } from '../../capabilities';
23
- import { useNode, useNodeActionExpander } from '../../hooks';
24
+ import { useNode } from '../../hooks';
24
25
  import { DECK_PLUGIN } from '../../meta';
25
- import { SLUG_PATH_SEPARATOR, type Panel } from '../../types';
26
26
  import { layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
27
27
 
28
28
  export type ComplementarySidebarProps = {
29
- panels: Panel[];
30
29
  current?: string;
31
30
  };
32
31
 
33
- export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarProps) => {
32
+ export const ComplementarySidebar = ({ current }: ComplementarySidebarProps) => {
33
+ const { t } = useTranslation(DECK_PLUGIN);
34
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
34
35
  const layout = useCapability(DeckCapabilities.MutableDeckState);
35
36
  const attended = useAttended();
36
- const panelIds = useMemo(() => panels.map((p) => p.id), [panels]);
37
- const activePanelId = panelIds.find((p) => p === current) ?? panels[0].id;
38
- const activeEntryId = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${activePanelId}` : undefined;
39
37
  const { graph } = useAppGraph();
40
- const node = useNode(graph, activeEntryId);
41
- const { t } = useTranslation(DECK_PLUGIN);
42
- const { dispatchPromise: dispatch } = useIntentDispatcher();
43
- useNodeActionExpander(node);
38
+ const node = useNode(graph, attended[0]);
44
39
  const breakpoint = useBreakpoints();
45
40
  const topbar = layoutAppliesTopbar(breakpoint);
46
41
  const hoistStatusbar = useHoistStatusbar(breakpoint);
47
42
 
43
+ const panels = useCapabilities(DeckCapabilities.ComplementaryPanel);
44
+ const availablePanels = panels.filter((panel) => {
45
+ if (!node || !panel.filter) {
46
+ return true;
47
+ }
48
+
49
+ return panel.filter(node);
50
+ });
51
+ const activePanelId = availablePanels.find((panel) => panel.id === current)?.id ?? availablePanels[0]?.id;
48
52
  const [internalValue, setInternalValue] = useState(activePanelId);
49
53
 
50
54
  useEffect(() => {
@@ -65,6 +69,17 @@ export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarPr
65
69
  [layout, activePanelId, dispatch],
66
70
  );
67
71
 
72
+ const data = useMemo(
73
+ () =>
74
+ node && {
75
+ id: node.id,
76
+ subject: node.data,
77
+ workspace: layout.activeDeck,
78
+ popoverAnchorId: layout.popoverAnchorId,
79
+ },
80
+ [node, layout.popoverAnchorId],
81
+ );
82
+
68
83
  // TODO(burdon): Scroll area should be controlled by surface.
69
84
  return (
70
85
  <Main.ComplementarySidebar
@@ -82,10 +97,10 @@ export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarPr
82
97
  >
83
98
  <div
84
99
  role='none'
85
- className='absolute z-[1] inset-block-0 inline-end-0 !is-[--r0-size] border-is border-separator grid grid-cols-1 grid-rows-[1fr_min-content] bg-baseSurface contain-layout app-drag'
100
+ className='absolute z-[1] inset-block-0 inline-end-0 !is-[--r0-size] pbs-[env(safe-area-inset-top)] pbe-[env(safe-area-inset-bottom)] border-is border-separator grid grid-cols-1 grid-rows-[1fr_min-content] bg-baseSurface contain-layout app-drag'
86
101
  >
87
102
  <Tabs.Tablist classNames='grid grid-cols-1 auto-rows-[--rail-action] p-1 gap-1 !overflow-y-auto'>
88
- {panels.map((panel) => (
103
+ {availablePanels.map((panel) => (
89
104
  <Tabs.Tab key={panel.id} value={panel.id} asChild>
90
105
  <IconButton
91
106
  label={toLocalizedString(panel.label, t)}
@@ -115,14 +130,14 @@ export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarPr
115
130
  <ToggleComplementarySidebarButton />
116
131
  </div>
117
132
  </div>
118
- {panels.map((panel) => (
133
+ {availablePanels.map((panel) => (
119
134
  <Tabs.Tabpanel
120
135
  key={panel.id}
121
136
  value={panel.id}
122
- classNames='absolute data-[state="inactive"]:-z-[1] inset-block-0 inline-start-0 is-[calc(100%-var(--r0-size))] lg:is-[--r1-size] grid grid-cols-1 grid-rows-[var(--rail-size)_1fr_min-content]'
137
+ classNames='absolute data-[state="inactive"]:-z-[1] inset-block-0 inline-start-0 is-[calc(100%-var(--r0-size))] lg:is-[--r1-size] grid grid-cols-1 grid-rows-[var(--rail-size)_1fr_min-content] pbs-[env(safe-area-inset-top)]'
123
138
  {...(layout.complementarySidebarState !== 'expanded' && { inert: 'true' })}
124
139
  >
125
- {panel.id === activePanelId && node && (
140
+ {panel.id === activePanelId && data && (
126
141
  <>
127
142
  <h2 className='flex items-center pli-2 border-separator border-be'>
128
143
  {toLocalizedString(panel.label, t)}
@@ -130,13 +145,8 @@ export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarPr
130
145
  <ScrollArea.Root>
131
146
  <ScrollArea.Viewport>
132
147
  <Surface
133
- key={activeEntryId}
134
148
  role={`complementary--${activePanelId}`}
135
- data={{
136
- id: activeEntryId,
137
- subject: node.properties.object ?? node.properties.space,
138
- popoverAnchorId: layout.popoverAnchorId,
139
- }}
149
+ data={data}
140
150
  fallback={PlankContentError}
141
151
  placeholder={<PlankLoading />}
142
152
  />
@@ -148,7 +158,7 @@ export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarPr
148
158
  {!hoistStatusbar && (
149
159
  <div
150
160
  role='contentinfo'
151
- className='flex flex-wrap justify-center items-center border-bs border-separator plb-1'
161
+ className='flex flex-wrap justify-center items-center border-bs border-separator pbs-1 pbe-[max(env(safe-area-inset-bottom),0.25rem)]'
152
162
  >
153
163
  <Surface role='status-bar--r1-footer' limit={1} />
154
164
  </div>