@dxos/plugin-deck 0.7.5-feature-compute.4d9d99a → 0.7.5-labs.071a3e2

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 (210) hide show
  1. package/dist/lib/browser/{app-graph-builder-67VRUD5K.mjs → app-graph-builder-CI6ZFMNL.mjs} +57 -31
  2. package/dist/lib/browser/app-graph-builder-CI6ZFMNL.mjs.map +7 -0
  3. package/dist/lib/browser/{check-app-scheme-GEX6W2R5.mjs → check-app-scheme-S3EYUPMF.mjs} +3 -3
  4. package/dist/lib/browser/{check-app-scheme-GEX6W2R5.mjs.map → check-app-scheme-S3EYUPMF.mjs.map} +2 -2
  5. package/dist/lib/browser/chunk-BTDY6SES.mjs +1119 -0
  6. package/dist/lib/browser/chunk-BTDY6SES.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-FZOBKOA2.mjs +24 -0
  8. package/dist/lib/browser/chunk-FZOBKOA2.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-M2L53AIH.mjs +126 -0
  10. package/dist/lib/browser/chunk-M2L53AIH.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-JQJ5UWVB.mjs → chunk-N7TEPFVR.mjs} +3 -2
  12. package/dist/lib/browser/{chunk-JQJ5UWVB.mjs.map → chunk-N7TEPFVR.mjs.map} +3 -3
  13. package/dist/lib/browser/{chunk-5VFDMW5M.mjs → chunk-YQ2GWTDU.mjs} +2 -2
  14. package/dist/lib/browser/chunk-YQ2GWTDU.mjs.map +7 -0
  15. package/dist/lib/browser/index.mjs +36 -76
  16. package/dist/lib/browser/index.mjs.map +4 -4
  17. package/dist/lib/browser/intent-resolver-CSXFDKTC.mjs +494 -0
  18. package/dist/lib/browser/intent-resolver-CSXFDKTC.mjs.map +7 -0
  19. package/dist/lib/browser/meta.json +1 -1
  20. package/dist/lib/browser/{react-root-UL7ZDRVZ.mjs → react-root-HIHLRMCW.mjs} +10 -14
  21. package/dist/lib/browser/react-root-HIHLRMCW.mjs.map +7 -0
  22. package/dist/lib/browser/react-surface-4QVWKQYY.mjs +38 -0
  23. package/dist/lib/browser/react-surface-4QVWKQYY.mjs.map +7 -0
  24. package/dist/lib/browser/{settings-FNWW6WIJ.mjs → settings-WACNLCPB.mjs} +6 -7
  25. package/dist/lib/browser/settings-WACNLCPB.mjs.map +7 -0
  26. package/dist/lib/browser/state-VPOYUKK6.mjs +117 -0
  27. package/dist/lib/browser/state-VPOYUKK6.mjs.map +7 -0
  28. package/dist/lib/browser/tools-5LDJNU56.mjs +51 -0
  29. package/dist/lib/browser/tools-5LDJNU56.mjs.map +7 -0
  30. package/dist/lib/browser/types.mjs +16 -4
  31. package/dist/lib/browser/url-handler-HLF42IHP.mjs +70 -0
  32. package/dist/lib/browser/url-handler-HLF42IHP.mjs.map +7 -0
  33. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  34. package/dist/types/src/capabilities/{layout/app-graph-builder.d.ts → app-graph-builder.d.ts} +22 -22
  35. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  36. package/dist/types/src/capabilities/capabilities.d.ts +132 -3
  37. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  38. package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -0
  39. package/dist/types/src/capabilities/index.d.ts +188 -3
  40. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  41. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  42. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  43. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  44. package/dist/types/src/capabilities/set-active.d.ts +9 -0
  45. package/dist/types/src/capabilities/set-active.d.ts.map +1 -0
  46. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  47. package/dist/types/src/capabilities/state.d.ts +76 -0
  48. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  49. package/dist/types/src/capabilities/tools.d.ts +10 -0
  50. package/dist/types/src/capabilities/tools.d.ts.map +1 -0
  51. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
  52. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
  53. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
  54. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
  55. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +1 -4
  56. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  57. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +1 -1
  58. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +3 -3
  59. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
  60. package/dist/types/src/components/DeckLayout/Plank.d.ts +8 -6
  61. package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
  62. package/dist/types/src/components/DeckLayout/PlankControls.d.ts +2 -2
  63. package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +1 -1
  64. package/dist/types/src/components/DeckLayout/PlankError.d.ts +4 -3
  65. package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
  66. package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
  67. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts +5 -3
  68. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +1 -1
  69. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
  70. package/dist/types/src/components/DeckLayout/Toast.d.ts +2 -2
  71. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  72. package/dist/types/src/components/fragments.d.ts +2 -0
  73. package/dist/types/src/components/fragments.d.ts.map +1 -1
  74. package/dist/types/src/components/index.d.ts +0 -2
  75. package/dist/types/src/components/index.d.ts.map +1 -1
  76. package/dist/types/src/hooks/useMainSize.d.ts +2 -2
  77. package/dist/types/src/layout.d.ts +5 -19
  78. package/dist/types/src/layout.d.ts.map +1 -1
  79. package/dist/types/src/meta.d.ts +1 -0
  80. package/dist/types/src/meta.d.ts.map +1 -1
  81. package/dist/types/src/translations.d.ts +3 -3
  82. package/dist/types/src/types.d.ts +107 -2
  83. package/dist/types/src/types.d.ts.map +1 -1
  84. package/dist/types/src/util/index.d.ts +2 -1
  85. package/dist/types/src/util/index.d.ts.map +1 -1
  86. package/dist/types/src/util/layoutAppliesTopbar.d.ts +2 -0
  87. package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -0
  88. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -1
  89. package/dist/types/tsconfig.tsbuildinfo +1 -1
  90. package/package.json +31 -30
  91. package/src/DeckPlugin.ts +17 -57
  92. package/src/capabilities/{layout/app-graph-builder.ts → app-graph-builder.ts} +36 -28
  93. package/src/capabilities/capabilities.ts +4 -3
  94. package/src/capabilities/{navigation/check-app-scheme.ts → check-app-scheme.ts} +2 -2
  95. package/src/capabilities/index.ts +12 -3
  96. package/src/capabilities/intent-resolver.ts +350 -0
  97. package/src/capabilities/{layout/react-root.tsx → react-root.tsx} +7 -11
  98. package/src/capabilities/react-surface.tsx +31 -0
  99. package/src/capabilities/set-active.ts +43 -0
  100. package/src/capabilities/{settings/settings.ts → settings.ts} +4 -5
  101. package/src/capabilities/state.ts +102 -0
  102. package/src/capabilities/tools.ts +61 -0
  103. package/src/capabilities/url-handler.ts +63 -0
  104. package/src/components/DeckLayout/ActiveNode.tsx +2 -3
  105. package/src/components/DeckLayout/ComplementarySidebar.tsx +120 -69
  106. package/src/components/DeckLayout/ContentEmpty.tsx +7 -10
  107. package/src/components/DeckLayout/DeckLayout.tsx +103 -61
  108. package/src/components/DeckLayout/Fullscreen.tsx +2 -3
  109. package/src/components/DeckLayout/NodePlankHeading.tsx +57 -65
  110. package/src/components/DeckLayout/Plank.tsx +32 -41
  111. package/src/components/DeckLayout/PlankControls.tsx +11 -10
  112. package/src/components/DeckLayout/PlankError.tsx +6 -5
  113. package/src/components/DeckLayout/Sidebar.tsx +17 -20
  114. package/src/components/DeckLayout/SidebarButton.tsx +25 -31
  115. package/src/components/DeckLayout/StatusBar.tsx +5 -11
  116. package/src/components/DeckLayout/Toast.tsx +2 -2
  117. package/src/components/LayoutSettings.tsx +8 -8
  118. package/src/components/fragments.ts +8 -0
  119. package/src/components/index.ts +0 -2
  120. package/src/hooks/useMainSize.ts +3 -3
  121. package/src/layout.ts +43 -212
  122. package/src/meta.ts +1 -0
  123. package/src/translations.ts +8 -8
  124. package/src/types.ts +88 -2
  125. package/src/util/index.ts +2 -1
  126. package/src/util/layoutAppliesTopbar.ts +7 -0
  127. package/src/util/useHoistStatusbar.ts +17 -8
  128. package/dist/lib/browser/app-graph-builder-67VRUD5K.mjs.map +0 -7
  129. package/dist/lib/browser/chunk-2M4PXYNB.mjs +0 -1052
  130. package/dist/lib/browser/chunk-2M4PXYNB.mjs.map +0 -7
  131. package/dist/lib/browser/chunk-2PJNBVCY.mjs +0 -39
  132. package/dist/lib/browser/chunk-2PJNBVCY.mjs.map +0 -7
  133. package/dist/lib/browser/chunk-4C2AFTET.mjs +0 -186
  134. package/dist/lib/browser/chunk-4C2AFTET.mjs.map +0 -7
  135. package/dist/lib/browser/chunk-5VFDMW5M.mjs.map +0 -7
  136. package/dist/lib/browser/chunk-KY5WXIXY.mjs +0 -44
  137. package/dist/lib/browser/chunk-KY5WXIXY.mjs.map +0 -7
  138. package/dist/lib/browser/deck-PLCSKPGL.mjs +0 -26
  139. package/dist/lib/browser/deck-PLCSKPGL.mjs.map +0 -7
  140. package/dist/lib/browser/intent-resolver-FVOQSTBX.mjs +0 -152
  141. package/dist/lib/browser/intent-resolver-FVOQSTBX.mjs.map +0 -7
  142. package/dist/lib/browser/intent-resolver-K7GW4A2I.mjs +0 -249
  143. package/dist/lib/browser/intent-resolver-K7GW4A2I.mjs.map +0 -7
  144. package/dist/lib/browser/location-QHRBQBQN.mjs +0 -35
  145. package/dist/lib/browser/location-QHRBQBQN.mjs.map +0 -7
  146. package/dist/lib/browser/react-context-3BDW7W2N.mjs +0 -32
  147. package/dist/lib/browser/react-context-3BDW7W2N.mjs.map +0 -7
  148. package/dist/lib/browser/react-root-UL7ZDRVZ.mjs.map +0 -7
  149. package/dist/lib/browser/react-surface-VPNOGGNN.mjs +0 -28
  150. package/dist/lib/browser/react-surface-VPNOGGNN.mjs.map +0 -7
  151. package/dist/lib/browser/settings-FNWW6WIJ.mjs.map +0 -7
  152. package/dist/lib/browser/state-7I5BD7SE.mjs +0 -34
  153. package/dist/lib/browser/state-7I5BD7SE.mjs.map +0 -7
  154. package/dist/lib/browser/url-handler-Z5B7LD3N.mjs +0 -76
  155. package/dist/lib/browser/url-handler-Z5B7LD3N.mjs.map +0 -7
  156. package/dist/types/src/capabilities/layout/app-graph-builder.d.ts.map +0 -1
  157. package/dist/types/src/capabilities/layout/deck.d.ts +0 -4
  158. package/dist/types/src/capabilities/layout/deck.d.ts.map +0 -1
  159. package/dist/types/src/capabilities/layout/index.d.ts +0 -229
  160. package/dist/types/src/capabilities/layout/index.d.ts.map +0 -1
  161. package/dist/types/src/capabilities/layout/intent-resolver.d.ts.map +0 -1
  162. package/dist/types/src/capabilities/layout/react-context.d.ts +0 -8
  163. package/dist/types/src/capabilities/layout/react-context.d.ts.map +0 -1
  164. package/dist/types/src/capabilities/layout/react-root.d.ts.map +0 -1
  165. package/dist/types/src/capabilities/layout/state.d.ts +0 -42
  166. package/dist/types/src/capabilities/layout/state.d.ts.map +0 -1
  167. package/dist/types/src/capabilities/navigation/check-app-scheme.d.ts.map +0 -1
  168. package/dist/types/src/capabilities/navigation/index.d.ts +0 -5
  169. package/dist/types/src/capabilities/navigation/index.d.ts.map +0 -1
  170. package/dist/types/src/capabilities/navigation/intent-resolver.d.ts +0 -4
  171. package/dist/types/src/capabilities/navigation/intent-resolver.d.ts.map +0 -1
  172. package/dist/types/src/capabilities/navigation/location.d.ts +0 -4
  173. package/dist/types/src/capabilities/navigation/location.d.ts.map +0 -1
  174. package/dist/types/src/capabilities/navigation/set-location.d.ts +0 -10
  175. package/dist/types/src/capabilities/navigation/set-location.d.ts.map +0 -1
  176. package/dist/types/src/capabilities/navigation/url-handler.d.ts.map +0 -1
  177. package/dist/types/src/capabilities/settings/index.d.ts +0 -3
  178. package/dist/types/src/capabilities/settings/index.d.ts.map +0 -1
  179. package/dist/types/src/capabilities/settings/react-surface.d.ts.map +0 -1
  180. package/dist/types/src/capabilities/settings/settings.d.ts.map +0 -1
  181. package/dist/types/src/components/DeckContext.d.ts +0 -11
  182. package/dist/types/src/components/DeckContext.d.ts.map +0 -1
  183. package/dist/types/src/components/LayoutContext.d.ts +0 -5
  184. package/dist/types/src/components/LayoutContext.d.ts.map +0 -1
  185. package/dist/types/src/layout.test.d.ts +0 -2
  186. package/dist/types/src/layout.test.d.ts.map +0 -1
  187. package/dist/types/src/util/layout-parts.d.ts +0 -7
  188. package/dist/types/src/util/layout-parts.d.ts.map +0 -1
  189. package/src/capabilities/layout/deck.ts +0 -25
  190. package/src/capabilities/layout/index.ts +0 -12
  191. package/src/capabilities/layout/intent-resolver.ts +0 -128
  192. package/src/capabilities/layout/react-context.tsx +0 -26
  193. package/src/capabilities/layout/state.ts +0 -32
  194. package/src/capabilities/navigation/index.ts +0 -10
  195. package/src/capabilities/navigation/intent-resolver.ts +0 -216
  196. package/src/capabilities/navigation/location.ts +0 -28
  197. package/src/capabilities/navigation/set-location.ts +0 -38
  198. package/src/capabilities/navigation/url-handler.ts +0 -67
  199. package/src/capabilities/settings/index.ts +0 -8
  200. package/src/capabilities/settings/react-surface.tsx +0 -23
  201. package/src/components/DeckContext.ts +0 -19
  202. package/src/components/LayoutContext.ts +0 -12
  203. package/src/layout.test.ts +0 -380
  204. package/src/util/layout-parts.ts +0 -12
  205. /package/dist/types/src/capabilities/{navigation/check-app-scheme.d.ts → check-app-scheme.d.ts} +0 -0
  206. /package/dist/types/src/capabilities/{layout/intent-resolver.d.ts → intent-resolver.d.ts} +0 -0
  207. /package/dist/types/src/capabilities/{layout/react-root.d.ts → react-root.d.ts} +0 -0
  208. /package/dist/types/src/capabilities/{settings/react-surface.d.ts → react-surface.d.ts} +0 -0
  209. /package/dist/types/src/capabilities/{settings/settings.d.ts → settings.d.ts} +0 -0
  210. /package/dist/types/src/capabilities/{navigation/url-handler.d.ts → url-handler.d.ts} +0 -0
@@ -0,0 +1,102 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Capabilities, contributes } from '@dxos/app-framework';
6
+ import { invariant } from '@dxos/invariant';
7
+ import { create } from '@dxos/live-object';
8
+ import { LocalStorageStore } from '@dxos/local-storage';
9
+ import { type SidebarState } from '@dxos/react-ui';
10
+
11
+ import { DeckCapabilities } from './capabilities';
12
+ import { DECK_PLUGIN } from '../meta';
13
+ import { getMode, type Deck, type DeckState } from '../types';
14
+
15
+ const boolean = /true|false/;
16
+
17
+ // TODO(thure, 18 Feb 2025): Remove after the next release.
18
+
19
+ const migrateSidebarStateDefaults = {
20
+ [`${DECK_PLUGIN}/complementary-sidebar-state`]: 'expanded',
21
+ [`${DECK_PLUGIN}/sidebar-state`]: 'collapsed',
22
+ };
23
+
24
+ const migrateSidebarState = () => {
25
+ Object.entries(migrateSidebarStateDefaults).forEach(([key, defaultValue]) => {
26
+ if (boolean.test(localStorage.getItem(key) ?? 'never')) {
27
+ localStorage.setItem(key, defaultValue);
28
+ }
29
+ });
30
+ };
31
+
32
+ export default () => {
33
+ migrateSidebarState();
34
+
35
+ const state = new LocalStorageStore<DeckState>(DECK_PLUGIN, {
36
+ sidebarState: 'expanded',
37
+ complementarySidebarState: 'collapsed',
38
+ complementarySidebarPanel: undefined,
39
+ dialogContent: null,
40
+ dialogOpen: false,
41
+ dialogBlockAlign: undefined,
42
+ dialogType: undefined,
43
+ popoverContent: null,
44
+ popoverAnchorId: undefined,
45
+ popoverOpen: false,
46
+ toasts: [],
47
+ currentUndoId: undefined,
48
+ activeDeck: 'default',
49
+ decks: {
50
+ default: {
51
+ initialized: false,
52
+ active: [],
53
+ inactive: [],
54
+ fullscreen: false,
55
+ solo: undefined,
56
+ plankSizing: {},
57
+ },
58
+ },
59
+ get deck() {
60
+ const deck = this.decks[this.activeDeck];
61
+ invariant(deck, `Deck not found: ${this.activeDeck}`);
62
+ return deck;
63
+ },
64
+ previousMode: {},
65
+ scrollIntoView: undefined,
66
+ });
67
+
68
+ state
69
+ .prop({ key: 'sidebarState', type: LocalStorageStore.enum<SidebarState>() })
70
+ .prop({ key: 'complementarySidebarState', type: LocalStorageStore.enum<SidebarState>() })
71
+ .prop({ key: 'decks', type: LocalStorageStore.json<Record<string, Deck>>() })
72
+ .prop({ key: 'activeDeck', type: LocalStorageStore.string() });
73
+
74
+ const layout = create<Capabilities.Layout>({
75
+ get mode() {
76
+ return getMode(state.values.deck);
77
+ },
78
+ get dialogOpen() {
79
+ return state.values.dialogOpen;
80
+ },
81
+ get sidebarOpen() {
82
+ return state.values.sidebarState === 'expanded';
83
+ },
84
+ get complementarySidebarOpen() {
85
+ return state.values.complementarySidebarState === 'expanded';
86
+ },
87
+ get active() {
88
+ return state.values.deck.solo ? [state.values.deck.solo] : state.values.deck.active;
89
+ },
90
+ get inactive() {
91
+ return state.values.deck.inactive;
92
+ },
93
+ get scrollIntoView() {
94
+ return state.values.scrollIntoView;
95
+ },
96
+ });
97
+
98
+ return [
99
+ contributes(DeckCapabilities.DeckState, state.values, () => state.close()),
100
+ contributes(Capabilities.Layout, layout),
101
+ ];
102
+ };
@@ -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
+ ]);
@@ -0,0 +1,63 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Capabilities, contributes, createIntent, LayoutAction, type PluginsContext } from '@dxos/app-framework';
6
+ import { scheduledEffect } from '@dxos/echo-signals/core';
7
+
8
+ import { DeckCapabilities } from './capabilities';
9
+
10
+ // TODO(wittjosiah): Cleanup the url handling. May justify introducing routing capabilities.
11
+ export default async (context: PluginsContext) => {
12
+ const { dispatchPromise: dispatch } = context.requestCapability(Capabilities.IntentDispatcher) ?? {};
13
+ const state = context.requestCapability(DeckCapabilities.MutableDeckState);
14
+
15
+ const handleNavigation = async () => {
16
+ const pathname = window.location.pathname;
17
+ if (pathname === '/reset') {
18
+ state.activeDeck = 'default';
19
+ state.decks = {
20
+ default: {
21
+ initialized: false,
22
+ active: [],
23
+ inactive: [],
24
+ fullscreen: false,
25
+ solo: undefined,
26
+ plankSizing: {},
27
+ },
28
+ };
29
+ window.location.pathname = '/';
30
+ return;
31
+ }
32
+
33
+ const [_, nextDeck, nextSolo] = pathname.split('/');
34
+ if (nextDeck) {
35
+ await dispatch(createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: nextDeck }));
36
+ }
37
+
38
+ if (nextSolo) {
39
+ await dispatch(
40
+ createIntent(LayoutAction.SetLayoutMode, { part: 'mode', subject: nextSolo, options: { mode: 'solo' } }),
41
+ );
42
+ } else {
43
+ await dispatch(createIntent(LayoutAction.SetLayoutMode, { part: 'mode', options: { mode: 'deck' } }));
44
+ }
45
+ };
46
+
47
+ await handleNavigation();
48
+ window.addEventListener('popstate', handleNavigation);
49
+
50
+ const unsubscribe = scheduledEffect(
51
+ () => ({ solo: state.deck.solo, activeDeck: state.activeDeck }),
52
+ ({ solo, activeDeck }) => {
53
+ const path = solo ? `/${activeDeck}/${solo}` : `/${activeDeck}`;
54
+ // TODO(thure): In some browsers, this only preserves the most recent state change, even though this is not `history.replace`…
55
+ history.pushState(null, '', `${path}${window.location.search}`);
56
+ },
57
+ );
58
+
59
+ return contributes(Capabilities.Null, null, () => {
60
+ window.removeEventListener('popstate', handleNavigation);
61
+ unsubscribe();
62
+ });
63
+ };
@@ -4,8 +4,7 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { Surface } from '@dxos/app-framework';
8
- import { useGraph } from '@dxos/plugin-graph';
7
+ import { Surface, useAppGraph } from '@dxos/app-framework';
9
8
  import { useAttended } from '@dxos/react-ui-attention';
10
9
 
11
10
  import { useNode, useNodeActionExpander } from '../../hooks';
@@ -13,7 +12,7 @@ import { useNode, useNodeActionExpander } from '../../hooks';
13
12
  // TODO(burdon): Factor out to effect in plugin set document title.
14
13
  export const ActiveNode = () => {
15
14
  const [id] = useAttended();
16
- const { graph } = useGraph();
15
+ const { graph } = useAppGraph();
17
16
  const activeNode = useNode(graph, id);
18
17
  useNodeActionExpander(activeNode);
19
18
 
@@ -2,23 +2,28 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import React, { useCallback, useEffect, useMemo, useState, type MouseEvent } from 'react';
6
6
 
7
- import { createIntent, NavigationAction, SLUG_PATH_SEPARATOR, Surface, useIntentDispatcher } from '@dxos/app-framework';
8
- import { useGraph } from '@dxos/plugin-graph';
9
- import { Main, ScrollArea, useTranslation, toLocalizedString } from '@dxos/react-ui';
7
+ import {
8
+ createIntent,
9
+ LayoutAction,
10
+ Surface,
11
+ useAppGraph,
12
+ useCapability,
13
+ useIntentDispatcher,
14
+ } from '@dxos/app-framework';
15
+ import { Main, useTranslation, toLocalizedString, IconButton, ScrollArea } from '@dxos/react-ui';
10
16
  import { useAttended } from '@dxos/react-ui-attention';
11
- import { railGridHorizontal, StackContext, StackItem } from '@dxos/react-ui-stack';
12
17
  import { Tabs } from '@dxos/react-ui-tabs';
13
- import { mx } from '@dxos/react-ui-theme';
14
18
 
15
19
  import { PlankContentError } from './PlankError';
16
20
  import { PlankLoading } from './PlankLoading';
17
- import { CloseComplementarySidebarButton } from './SidebarButton';
21
+ import { ToggleComplementarySidebarButton } from './SidebarButton';
22
+ import { DeckCapabilities } from '../../capabilities';
18
23
  import { useNode, useNodeActionExpander } from '../../hooks';
19
24
  import { DECK_PLUGIN } from '../../meta';
20
- import { type Panel } from '../../types';
21
- import { useLayout } from '../LayoutContext';
25
+ import { SLUG_PATH_SEPARATOR, type Panel } from '../../types';
26
+ import { layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
22
27
 
23
28
  export type ComplementarySidebarProps = {
24
29
  panels: Panel[];
@@ -26,16 +31,19 @@ export type ComplementarySidebarProps = {
26
31
  };
27
32
 
28
33
  export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarProps) => {
29
- const { popoverAnchorId } = useLayout();
34
+ const layout = useCapability(DeckCapabilities.MutableDeckState);
30
35
  const attended = useAttended();
31
- const panelIds = useMemo(() => panels.map((p) => p.id), [panels]);
32
- const activePanelId = panelIds.find((p) => p === current) ?? panels[0].id;
36
+ const panelIds = useMemo(() => panels.map((panel) => panel.id), [panels]);
37
+ const activePanelId = panelIds.find((panelId) => panelId === current) ?? panels[0].id;
33
38
  const activeEntryId = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${activePanelId}` : undefined;
34
- const { graph } = useGraph();
39
+ const { graph } = useAppGraph();
35
40
  const node = useNode(graph, activeEntryId);
36
41
  const { t } = useTranslation(DECK_PLUGIN);
37
42
  const { dispatchPromise: dispatch } = useIntentDispatcher();
38
43
  useNodeActionExpander(node);
44
+ const breakpoint = useBreakpoints();
45
+ const topbar = layoutAppliesTopbar(breakpoint);
46
+ const hoistStatusbar = useHoistStatusbar(breakpoint);
39
47
 
40
48
  const [internalValue, setInternalValue] = useState(activePanelId);
41
49
 
@@ -43,70 +51,113 @@ export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarPr
43
51
  setInternalValue(activePanelId);
44
52
  }, [activePanelId]);
45
53
 
46
- const handleValueChange = useCallback(
47
- (nextValue: string) => {
48
- setInternalValue(nextValue);
49
- void dispatch(createIntent(NavigationAction.Open, { activeParts: { complementary: nextValue } }));
54
+ const handleTabClick = useCallback(
55
+ (event: MouseEvent) => {
56
+ const nextValue = event.currentTarget.getAttribute('data-value') as string;
57
+ if (nextValue === activePanelId) {
58
+ layout.complementarySidebarState = layout.complementarySidebarState === 'expanded' ? 'collapsed' : 'expanded';
59
+ } else {
60
+ setInternalValue(nextValue);
61
+ layout.complementarySidebarState = 'expanded';
62
+ void dispatch(createIntent(LayoutAction.UpdateComplementary, { part: 'complementary', subject: nextValue }));
63
+ }
50
64
  },
51
- [dispatch],
65
+ [layout, activePanelId, dispatch],
52
66
  );
53
67
 
54
68
  // TODO(burdon): Scroll area should be controlled by surface.
55
69
  return (
56
- <Main.ComplementarySidebar classNames='lg:block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]'>
57
- <StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
58
- <div role='none' className={mx(railGridHorizontal, 'grid grid-cols-[100%] bs-full')}>
59
- <Tabs.Root
60
- orientation='horizontal'
61
- value={internalValue}
62
- onValueChange={handleValueChange}
63
- attendableId={attended[0]}
64
- classNames='contents'
70
+ <Main.ComplementarySidebar
71
+ classNames={[
72
+ topbar && 'block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]',
73
+ hoistStatusbar && 'block-end-[--statusbar-size]',
74
+ ]}
75
+ >
76
+ <Tabs.Root
77
+ orientation='vertical'
78
+ verticalVariant='stateless'
79
+ value={internalValue}
80
+ attendableId={attended[0]}
81
+ classNames='contents'
82
+ >
83
+ <div
84
+ 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'
86
+ >
87
+ <Tabs.Tablist classNames='grid grid-cols-1 auto-rows-[--rail-action] p-1 gap-1 !overflow-y-auto'>
88
+ {panels.map((panel) => (
89
+ <Tabs.Tab key={panel.id} value={panel.id} asChild>
90
+ <IconButton
91
+ label={toLocalizedString(panel.label, t)}
92
+ icon={panel.icon}
93
+ size={5}
94
+ iconOnly
95
+ tooltipSide='left'
96
+ data-value={panel.id}
97
+ variant={
98
+ activePanelId === panel.id
99
+ ? layout.complementarySidebarState === 'expanded'
100
+ ? 'primary'
101
+ : 'default'
102
+ : 'ghost'
103
+ }
104
+ onClick={handleTabClick}
105
+ />
106
+ </Tabs.Tab>
107
+ ))}
108
+ </Tabs.Tablist>
109
+ {!hoistStatusbar && (
110
+ <div role='none' className='grid grid-cols-1 auto-rows-[--rail-item] p-1 overflow-y-auto'>
111
+ <Surface role='status-bar--r0-footer' limit={1} />
112
+ </div>
113
+ )}
114
+ <div role='none' className='hidden lg:grid grid-cols-1 auto-rows-[--rail-action] p-1'>
115
+ <ToggleComplementarySidebarButton />
116
+ </div>
117
+ </div>
118
+ {panels.map((panel) => (
119
+ <Tabs.Tabpanel
120
+ key={panel.id}
121
+ 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]'
123
+ {...(layout.complementarySidebarState !== 'expanded' && { inert: 'true' })}
65
124
  >
66
- <StackItem.Heading classNames='border-be border-separator grid grid-cols-[1fr_min-content] items-stretch'>
67
- <ScrollArea.Root classNames='flex-1 min-is-0'>
68
- <ScrollArea.Viewport>
69
- <Tabs.Tablist classNames='bs-[--rail-content] is-min items-stretch pis-[max(.5rem,env(safe-area-inset-left))] sm:pis-2'>
70
- {panels.map((panel) => (
71
- <Tabs.Tab key={panel.id} value={panel.id} classNames='!min-bs-0'>
72
- {toLocalizedString(panel.label, t)}
73
- </Tabs.Tab>
74
- ))}
75
- </Tabs.Tablist>
76
- <ScrollArea.Scrollbar orientation='horizontal'>
125
+ {panel.id === activePanelId && node && (
126
+ <>
127
+ <h2 className='flex items-center pli-2 border-separator border-be'>
128
+ {toLocalizedString(panel.label, t)}
129
+ </h2>
130
+ <ScrollArea.Root>
131
+ <ScrollArea.Viewport>
132
+ <Surface
133
+ key={activeEntryId}
134
+ role={`complementary--${activePanelId}`}
135
+ data={{
136
+ id: activeEntryId,
137
+ subject: node.properties.object ?? node.properties.space,
138
+ popoverAnchorId: layout.popoverAnchorId,
139
+ }}
140
+ fallback={PlankContentError}
141
+ placeholder={<PlankLoading />}
142
+ />
143
+ </ScrollArea.Viewport>
144
+ <ScrollArea.Scrollbar orientation='vertical'>
77
145
  <ScrollArea.Thumb />
78
146
  </ScrollArea.Scrollbar>
79
- </ScrollArea.Viewport>
80
- </ScrollArea.Root>
81
- <CloseComplementarySidebarButton />
82
- </StackItem.Heading>
83
- <ScrollArea.Root>
84
- <ScrollArea.Viewport>
85
- {panels.map((panel) => (
86
- <Tabs.Tabpanel key={panel.id} value={panel.id} classNames='pbe-[env(safe-area-inset-bottom)]'>
87
- {panel.id === activePanelId && node && (
88
- <Surface
89
- key={activeEntryId}
90
- role={`complementary--${activePanelId}`}
91
- data={{
92
- id: activeEntryId,
93
- subject: node.properties.object ?? node.properties.space,
94
- popoverAnchorId,
95
- }}
96
- fallback={PlankContentError}
97
- placeholder={<PlankLoading />}
98
- />
99
- )}
100
- </Tabs.Tabpanel>
101
- ))}
102
- <ScrollArea.Scrollbar orientation='vertical'>
103
- <ScrollArea.Thumb />
104
- </ScrollArea.Scrollbar>
105
- </ScrollArea.Viewport>
106
- </ScrollArea.Root>
107
- </Tabs.Root>
108
- </div>
109
- </StackContext.Provider>
147
+ </ScrollArea.Root>
148
+ {!hoistStatusbar && (
149
+ <div
150
+ role='contentinfo'
151
+ className='flex flex-wrap justify-center items-center border-bs border-separator plb-1'
152
+ >
153
+ <Surface role='status-bar--r1-footer' limit={1} />
154
+ </div>
155
+ )}
156
+ </>
157
+ )}
158
+ </Tabs.Tabpanel>
159
+ ))}
160
+ </Tabs.Root>
110
161
  </Main.ComplementarySidebar>
111
162
  );
112
163
  };
@@ -5,25 +5,22 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Surface } from '@dxos/app-framework';
8
- import { mx } from '@dxos/react-ui-theme';
9
8
 
10
9
  import { ToggleSidebarButton } from './SidebarButton';
11
- import { soloInlinePadding } from '../fragments';
10
+ import { layoutAppliesTopbar, useBreakpoints } from '../../util';
11
+ import { fixedSidebarToggleStyles } from '../fragments';
12
12
 
13
13
  export const ContentEmpty = () => {
14
+ const breakpoint = useBreakpoints();
15
+ const topbar = layoutAppliesTopbar(breakpoint);
14
16
  return (
15
17
  <div
16
18
  role='none'
17
- className='min-bs-screen is-dvw sm:is-full p-8 grid grid-rows-[var(--rail-size)_1fr]'
19
+ className='grid place-items-center p-8 relative bg-deck'
18
20
  data-testid='layoutPlugin.firstRunMessage'
19
21
  >
20
- <div role='toolbar' className={mx(soloInlinePadding, 'flex items-stretch')}>
21
- <ToggleSidebarButton />
22
- <span role='none' className='grow' />
23
- </div>
24
- <div role='none' className='grid place-items-center'>
25
- <Surface role='keyshortcuts' />
26
- </div>
22
+ <Surface role='keyshortcuts' />
23
+ {!topbar && <ToggleSidebarButton variant='default' classNames={fixedSidebarToggleStyles} />}
27
24
  </div>
28
25
  );
29
26
  };