@dxos/plugin-deck 0.7.5-labs.a279d8c → 0.7.5-labs.a8b535d

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 (236) hide show
  1. package/dist/lib/browser/{app-graph-builder-67VRUD5K.mjs → app-graph-builder-IYHAGFA3.mjs} +61 -31
  2. package/dist/lib/browser/app-graph-builder-IYHAGFA3.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-5VFDMW5M.mjs → chunk-22AQ5IVX.mjs} +2 -2
  6. package/dist/lib/browser/chunk-22AQ5IVX.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-FT33W5CI.mjs +128 -0
  8. package/dist/lib/browser/chunk-FT33W5CI.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-G2X3ZDCE.mjs +24 -0
  10. package/dist/lib/browser/chunk-G2X3ZDCE.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/{chunk-JQJ5UWVB.mjs → chunk-N7TEPFVR.mjs} +3 -2
  14. package/dist/lib/browser/{chunk-JQJ5UWVB.mjs.map → chunk-N7TEPFVR.mjs.map} +3 -3
  15. package/dist/lib/browser/chunk-O4RFYYQ6.mjs +1114 -0
  16. package/dist/lib/browser/chunk-O4RFYYQ6.mjs.map +7 -0
  17. package/dist/lib/browser/index.mjs +45 -84
  18. package/dist/lib/browser/index.mjs.map +4 -4
  19. package/dist/lib/browser/intent-resolver-ZD67BRUI.mjs +488 -0
  20. package/dist/lib/browser/intent-resolver-ZD67BRUI.mjs.map +7 -0
  21. package/dist/lib/browser/meta.json +1 -1
  22. package/dist/lib/browser/{react-root-AWYSGU4Q.mjs → react-root-6ILKHD5J.mjs} +12 -17
  23. package/dist/lib/browser/react-root-6ILKHD5J.mjs.map +7 -0
  24. package/dist/lib/browser/react-surface-O75FKXAI.mjs +39 -0
  25. package/dist/lib/browser/react-surface-O75FKXAI.mjs.map +7 -0
  26. package/dist/lib/browser/{settings-FNWW6WIJ.mjs → settings-H35U6NHE.mjs} +6 -7
  27. package/dist/lib/browser/settings-H35U6NHE.mjs.map +7 -0
  28. package/dist/lib/browser/state-U4SHOPJW.mjs +129 -0
  29. package/dist/lib/browser/state-U4SHOPJW.mjs.map +7 -0
  30. package/dist/lib/browser/{tools-4XY7KFQF.mjs → tools-64LXGLYR.mjs} +24 -11
  31. package/dist/lib/browser/tools-64LXGLYR.mjs.map +7 -0
  32. package/dist/lib/browser/types.mjs +16 -4
  33. package/dist/lib/browser/url-handler-MVHTKUYA.mjs +72 -0
  34. package/dist/lib/browser/url-handler-MVHTKUYA.mjs.map +7 -0
  35. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  36. package/dist/types/src/capabilities/app-graph-builder.d.ts +181 -0
  37. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  38. package/dist/types/src/capabilities/capabilities.d.ts +137 -8
  39. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  40. package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -0
  41. package/dist/types/src/capabilities/index.d.ts +188 -3
  42. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  43. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  44. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  45. package/dist/types/src/capabilities/react-surface.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 +79 -0
  48. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  49. package/dist/types/src/capabilities/{navigation/tools.d.ts → tools.d.ts} +1 -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 +1 -2
  53. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
  54. package/dist/types/src/components/DeckLayout/Banner.d.ts +1 -2
  55. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -1
  56. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts +1 -4
  57. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
  58. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts +1 -2
  59. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
  60. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +2 -7
  61. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  62. package/dist/types/src/components/DeckLayout/Fallback.d.ts +1 -2
  63. package/dist/types/src/components/DeckLayout/Fallback.d.ts.map +1 -1
  64. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +1 -2
  65. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +1 -1
  66. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +3 -3
  67. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
  68. package/dist/types/src/components/DeckLayout/Plank.d.ts +8 -6
  69. package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
  70. package/dist/types/src/components/DeckLayout/PlankControls.d.ts +2 -2
  71. package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +1 -1
  72. package/dist/types/src/components/DeckLayout/PlankError.d.ts +6 -6
  73. package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
  74. package/dist/types/src/components/DeckLayout/PlankLoading.d.ts +1 -2
  75. package/dist/types/src/components/DeckLayout/PlankLoading.d.ts.map +1 -1
  76. package/dist/types/src/components/DeckLayout/Sidebar.d.ts +1 -2
  77. package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
  78. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts +6 -5
  79. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +1 -1
  80. package/dist/types/src/components/DeckLayout/StatusBar.d.ts +1 -2
  81. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
  82. package/dist/types/src/components/DeckLayout/Toast.d.ts +2 -3
  83. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  84. package/dist/types/src/components/DeckLayout/Topbar.d.ts +1 -2
  85. package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +1 -1
  86. package/dist/types/src/components/LayoutSettings.d.ts +1 -2
  87. package/dist/types/src/components/LayoutSettings.d.ts.map +1 -1
  88. package/dist/types/src/components/fragments.d.ts +2 -0
  89. package/dist/types/src/components/fragments.d.ts.map +1 -1
  90. package/dist/types/src/components/index.d.ts +0 -2
  91. package/dist/types/src/components/index.d.ts.map +1 -1
  92. package/dist/types/src/events.d.ts +1 -0
  93. package/dist/types/src/events.d.ts.map +1 -1
  94. package/dist/types/src/hooks/useMainSize.d.ts +2 -2
  95. package/dist/types/src/hooks/useNode.d.ts.map +1 -1
  96. package/dist/types/src/layout.d.ts +5 -19
  97. package/dist/types/src/layout.d.ts.map +1 -1
  98. package/dist/types/src/meta.d.ts +1 -0
  99. package/dist/types/src/meta.d.ts.map +1 -1
  100. package/dist/types/src/translations.d.ts +3 -3
  101. package/dist/types/src/types.d.ts +117 -2
  102. package/dist/types/src/types.d.ts.map +1 -1
  103. package/dist/types/src/util/index.d.ts +3 -1
  104. package/dist/types/src/util/index.d.ts.map +1 -1
  105. package/dist/types/src/util/layoutAppliesTopbar.d.ts +2 -0
  106. package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -0
  107. package/dist/types/src/util/set-active.d.ts +9 -0
  108. package/dist/types/src/util/set-active.d.ts.map +1 -0
  109. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -1
  110. package/dist/types/tsconfig.tsbuildinfo +1 -1
  111. package/package.json +31 -31
  112. package/src/DeckPlugin.ts +23 -65
  113. package/src/capabilities/{layout/app-graph-builder.ts → app-graph-builder.ts} +40 -28
  114. package/src/capabilities/capabilities.ts +5 -7
  115. package/src/capabilities/{navigation/check-app-scheme.ts → check-app-scheme.ts} +2 -2
  116. package/src/capabilities/index.ts +12 -3
  117. package/src/capabilities/intent-resolver.ts +368 -0
  118. package/src/capabilities/{layout/react-root.tsx → react-root.tsx} +8 -14
  119. package/src/capabilities/react-surface.tsx +31 -0
  120. package/src/capabilities/{settings/settings.ts → settings.ts} +4 -5
  121. package/src/capabilities/state.ts +108 -0
  122. package/src/capabilities/{navigation/tools.ts → tools.ts} +18 -9
  123. package/src/capabilities/url-handler.ts +65 -0
  124. package/src/components/DeckLayout/ActiveNode.tsx +2 -3
  125. package/src/components/DeckLayout/ComplementarySidebar.tsx +185 -77
  126. package/src/components/DeckLayout/ContentEmpty.tsx +7 -10
  127. package/src/components/DeckLayout/DeckLayout.tsx +141 -84
  128. package/src/components/DeckLayout/Fullscreen.tsx +2 -3
  129. package/src/components/DeckLayout/NodePlankHeading.tsx +57 -65
  130. package/src/components/DeckLayout/Plank.tsx +33 -41
  131. package/src/components/DeckLayout/PlankControls.tsx +12 -11
  132. package/src/components/DeckLayout/PlankError.tsx +6 -5
  133. package/src/components/DeckLayout/Sidebar.tsx +17 -20
  134. package/src/components/DeckLayout/SidebarButton.tsx +25 -31
  135. package/src/components/DeckLayout/StatusBar.tsx +5 -11
  136. package/src/components/DeckLayout/Toast.tsx +2 -2
  137. package/src/components/LayoutSettings.tsx +8 -8
  138. package/src/components/fragments.ts +8 -0
  139. package/src/components/index.ts +0 -2
  140. package/src/events.ts +1 -0
  141. package/src/hooks/useMainSize.ts +3 -3
  142. package/src/hooks/useNode.ts +3 -1
  143. package/src/layout.ts +43 -212
  144. package/src/meta.ts +1 -0
  145. package/src/translations.ts +8 -8
  146. package/src/types.ts +103 -4
  147. package/src/util/index.ts +3 -1
  148. package/src/util/layoutAppliesTopbar.ts +7 -0
  149. package/src/util/set-active.ts +47 -0
  150. package/src/util/useHoistStatusbar.ts +13 -8
  151. package/dist/lib/browser/app-graph-builder-67VRUD5K.mjs.map +0 -7
  152. package/dist/lib/browser/chunk-2PJNBVCY.mjs +0 -39
  153. package/dist/lib/browser/chunk-2PJNBVCY.mjs.map +0 -7
  154. package/dist/lib/browser/chunk-4C2AFTET.mjs +0 -186
  155. package/dist/lib/browser/chunk-4C2AFTET.mjs.map +0 -7
  156. package/dist/lib/browser/chunk-5VFDMW5M.mjs.map +0 -7
  157. package/dist/lib/browser/chunk-KY5WXIXY.mjs +0 -44
  158. package/dist/lib/browser/chunk-KY5WXIXY.mjs.map +0 -7
  159. package/dist/lib/browser/chunk-WUMAJGVA.mjs +0 -1052
  160. package/dist/lib/browser/chunk-WUMAJGVA.mjs.map +0 -7
  161. package/dist/lib/browser/deck-PLCSKPGL.mjs +0 -26
  162. package/dist/lib/browser/deck-PLCSKPGL.mjs.map +0 -7
  163. package/dist/lib/browser/intent-resolver-FVOQSTBX.mjs +0 -152
  164. package/dist/lib/browser/intent-resolver-FVOQSTBX.mjs.map +0 -7
  165. package/dist/lib/browser/intent-resolver-K7GW4A2I.mjs +0 -249
  166. package/dist/lib/browser/intent-resolver-K7GW4A2I.mjs.map +0 -7
  167. package/dist/lib/browser/location-AIO6V3MK.mjs +0 -35
  168. package/dist/lib/browser/location-AIO6V3MK.mjs.map +0 -7
  169. package/dist/lib/browser/react-context-G6PDXUI5.mjs +0 -32
  170. package/dist/lib/browser/react-context-G6PDXUI5.mjs.map +0 -7
  171. package/dist/lib/browser/react-root-AWYSGU4Q.mjs.map +0 -7
  172. package/dist/lib/browser/react-surface-CLUABFNX.mjs +0 -28
  173. package/dist/lib/browser/react-surface-CLUABFNX.mjs.map +0 -7
  174. package/dist/lib/browser/settings-FNWW6WIJ.mjs.map +0 -7
  175. package/dist/lib/browser/state-7I5BD7SE.mjs +0 -34
  176. package/dist/lib/browser/state-7I5BD7SE.mjs.map +0 -7
  177. package/dist/lib/browser/tools-4XY7KFQF.mjs.map +0 -7
  178. package/dist/lib/browser/url-handler-JRAQRY73.mjs +0 -76
  179. package/dist/lib/browser/url-handler-JRAQRY73.mjs.map +0 -7
  180. package/dist/types/src/capabilities/layout/app-graph-builder.d.ts +0 -181
  181. package/dist/types/src/capabilities/layout/app-graph-builder.d.ts.map +0 -1
  182. package/dist/types/src/capabilities/layout/deck.d.ts +0 -4
  183. package/dist/types/src/capabilities/layout/deck.d.ts.map +0 -1
  184. package/dist/types/src/capabilities/layout/index.d.ts +0 -229
  185. package/dist/types/src/capabilities/layout/index.d.ts.map +0 -1
  186. package/dist/types/src/capabilities/layout/intent-resolver.d.ts.map +0 -1
  187. package/dist/types/src/capabilities/layout/react-context.d.ts +0 -8
  188. package/dist/types/src/capabilities/layout/react-context.d.ts.map +0 -1
  189. package/dist/types/src/capabilities/layout/react-root.d.ts.map +0 -1
  190. package/dist/types/src/capabilities/layout/state.d.ts +0 -42
  191. package/dist/types/src/capabilities/layout/state.d.ts.map +0 -1
  192. package/dist/types/src/capabilities/navigation/check-app-scheme.d.ts.map +0 -1
  193. package/dist/types/src/capabilities/navigation/index.d.ts +0 -6
  194. package/dist/types/src/capabilities/navigation/index.d.ts.map +0 -1
  195. package/dist/types/src/capabilities/navigation/intent-resolver.d.ts +0 -4
  196. package/dist/types/src/capabilities/navigation/intent-resolver.d.ts.map +0 -1
  197. package/dist/types/src/capabilities/navigation/location.d.ts +0 -4
  198. package/dist/types/src/capabilities/navigation/location.d.ts.map +0 -1
  199. package/dist/types/src/capabilities/navigation/set-location.d.ts +0 -10
  200. package/dist/types/src/capabilities/navigation/set-location.d.ts.map +0 -1
  201. package/dist/types/src/capabilities/navigation/tools.d.ts.map +0 -1
  202. package/dist/types/src/capabilities/navigation/url-handler.d.ts.map +0 -1
  203. package/dist/types/src/capabilities/settings/index.d.ts +0 -3
  204. package/dist/types/src/capabilities/settings/index.d.ts.map +0 -1
  205. package/dist/types/src/capabilities/settings/react-surface.d.ts.map +0 -1
  206. package/dist/types/src/capabilities/settings/settings.d.ts.map +0 -1
  207. package/dist/types/src/components/DeckContext.d.ts +0 -11
  208. package/dist/types/src/components/DeckContext.d.ts.map +0 -1
  209. package/dist/types/src/components/LayoutContext.d.ts +0 -5
  210. package/dist/types/src/components/LayoutContext.d.ts.map +0 -1
  211. package/dist/types/src/layout.test.d.ts +0 -2
  212. package/dist/types/src/layout.test.d.ts.map +0 -1
  213. package/dist/types/src/util/layout-parts.d.ts +0 -7
  214. package/dist/types/src/util/layout-parts.d.ts.map +0 -1
  215. package/src/capabilities/layout/deck.ts +0 -25
  216. package/src/capabilities/layout/index.ts +0 -12
  217. package/src/capabilities/layout/intent-resolver.ts +0 -128
  218. package/src/capabilities/layout/react-context.tsx +0 -26
  219. package/src/capabilities/layout/state.ts +0 -32
  220. package/src/capabilities/navigation/index.ts +0 -11
  221. package/src/capabilities/navigation/intent-resolver.ts +0 -216
  222. package/src/capabilities/navigation/location.ts +0 -28
  223. package/src/capabilities/navigation/set-location.ts +0 -38
  224. package/src/capabilities/navigation/url-handler.ts +0 -67
  225. package/src/capabilities/settings/index.ts +0 -8
  226. package/src/capabilities/settings/react-surface.tsx +0 -23
  227. package/src/components/DeckContext.ts +0 -19
  228. package/src/components/LayoutContext.ts +0 -12
  229. package/src/layout.test.ts +0 -380
  230. package/src/util/layout-parts.ts +0 -12
  231. /package/dist/types/src/capabilities/{navigation/check-app-scheme.d.ts → check-app-scheme.d.ts} +0 -0
  232. /package/dist/types/src/capabilities/{layout/intent-resolver.d.ts → intent-resolver.d.ts} +0 -0
  233. /package/dist/types/src/capabilities/{layout/react-root.d.ts → react-root.d.ts} +0 -0
  234. /package/dist/types/src/capabilities/{settings/react-surface.d.ts → react-surface.d.ts} +0 -0
  235. /package/dist/types/src/capabilities/{settings/settings.d.ts → settings.d.ts} +0 -0
  236. /package/dist/types/src/capabilities/{navigation/url-handler.d.ts → url-handler.d.ts} +0 -0
@@ -0,0 +1,65 @@
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 && nextDeck !== state.activeDeck) {
35
+ await dispatch(createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: nextDeck }));
36
+ }
37
+
38
+ if (nextSolo && nextSolo !== state.deck.solo) {
39
+ await dispatch(
40
+ createIntent(LayoutAction.SetLayoutMode, { part: 'mode', subject: nextSolo, options: { mode: 'solo' } }),
41
+ );
42
+ } else if (!nextSolo && state.deck.solo) {
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
+ if (window.location.pathname !== path) {
55
+ // TODO(thure): In some browsers, this only preserves the most recent state change, even though this is not `history.replace`…
56
+ history.pushState(null, '', `${path}${window.location.search}`);
57
+ }
58
+ },
59
+ );
60
+
61
+ return contributes(Capabilities.Null, null, () => {
62
+ window.removeEventListener('popstate', handleNavigation);
63
+ unsubscribe();
64
+ });
65
+ };
@@ -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,111 +2,219 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import React, {
6
+ type PropsWithChildren,
7
+ useCallback,
8
+ useEffect,
9
+ useMemo,
10
+ useState,
11
+ type MouseEvent,
12
+ Fragment,
13
+ } from 'react';
6
14
 
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';
15
+ import {
16
+ createIntent,
17
+ LayoutAction,
18
+ Surface,
19
+ useAppGraph,
20
+ useCapabilities,
21
+ useCapability,
22
+ useIntentDispatcher,
23
+ } from '@dxos/app-framework';
24
+ import { Main, useTranslation, toLocalizedString, IconButton, ScrollArea as NaturalScrollArea } from '@dxos/react-ui';
10
25
  import { useAttended } from '@dxos/react-ui-attention';
11
- import { railGridHorizontal, StackContext, StackItem } from '@dxos/react-ui-stack';
12
26
  import { Tabs } from '@dxos/react-ui-tabs';
13
- import { mx } from '@dxos/react-ui-theme';
27
+ import { byPosition } from '@dxos/util';
14
28
 
15
29
  import { PlankContentError } from './PlankError';
16
30
  import { PlankLoading } from './PlankLoading';
17
- import { CloseComplementarySidebarButton } from './SidebarButton';
18
- import { useNode, useNodeActionExpander } from '../../hooks';
31
+ import { ToggleComplementarySidebarButton } from './SidebarButton';
32
+ import { DeckCapabilities } from '../../capabilities';
33
+ import { useNode } from '../../hooks';
19
34
  import { DECK_PLUGIN } from '../../meta';
20
35
  import { type Panel } from '../../types';
21
- import { useLayout } from '../LayoutContext';
36
+ import { layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
22
37
 
23
38
  export type ComplementarySidebarProps = {
24
- panels: Panel[];
25
39
  current?: string;
26
40
  };
27
41
 
28
- export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarProps) => {
29
- const { popoverAnchorId } = useLayout();
30
- const attended = useAttended();
31
- const panelIds = useMemo(() => panels.map((p) => p.id), [panels]);
32
- const activePanelId = panelIds.find((p) => p === current) ?? panels[0].id;
33
- const activeEntryId = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${activePanelId}` : undefined;
34
- const { graph } = useGraph();
35
- const node = useNode(graph, activeEntryId);
42
+ export const ComplementarySidebar = ({ current }: ComplementarySidebarProps) => {
36
43
  const { t } = useTranslation(DECK_PLUGIN);
37
44
  const { dispatchPromise: dispatch } = useIntentDispatcher();
38
- useNodeActionExpander(node);
45
+ const layout = useCapability(DeckCapabilities.MutableDeckState);
46
+ const attended = useAttended();
47
+ const { graph } = useAppGraph();
48
+ const node = useNode(graph, attended[0]);
49
+ const breakpoint = useBreakpoints();
50
+ const topbar = layoutAppliesTopbar(breakpoint);
51
+ const hoistStatusbar = useHoistStatusbar(breakpoint);
52
+
53
+ const panels = useCapabilities(DeckCapabilities.ComplementaryPanel);
54
+ const availablePanels = panels
55
+ .filter((panel) => {
56
+ if (!node || !panel.filter) {
57
+ return true;
58
+ }
39
59
 
60
+ return panel.filter(node);
61
+ })
62
+ .toSorted(byPosition);
63
+ const activePanelId = availablePanels.find((panel) => panel.id === current)?.id ?? availablePanels[0]?.id;
40
64
  const [internalValue, setInternalValue] = useState(activePanelId);
41
65
 
42
66
  useEffect(() => {
43
67
  setInternalValue(activePanelId);
44
68
  }, [activePanelId]);
45
69
 
46
- const handleValueChange = useCallback(
47
- (nextValue: string) => {
48
- setInternalValue(nextValue);
49
- void dispatch(createIntent(NavigationAction.Open, { activeParts: { complementary: nextValue } }));
70
+ const handleTabClick = useCallback(
71
+ (event: MouseEvent) => {
72
+ const nextValue = event.currentTarget.getAttribute('data-value') as string;
73
+ if (nextValue === activePanelId) {
74
+ layout.complementarySidebarState = layout.complementarySidebarState === 'expanded' ? 'collapsed' : 'expanded';
75
+ } else {
76
+ setInternalValue(nextValue);
77
+ layout.complementarySidebarState = 'expanded';
78
+ void dispatch(createIntent(LayoutAction.UpdateComplementary, { part: 'complementary', subject: nextValue }));
79
+ }
50
80
  },
51
- [dispatch],
81
+ [layout, activePanelId, dispatch],
82
+ );
83
+
84
+ const data = useMemo(
85
+ () =>
86
+ node && {
87
+ id: node.id,
88
+ subject: node.data,
89
+ workspace: layout.activeDeck,
90
+ popoverAnchorId: layout.popoverAnchorId,
91
+ },
92
+ [node, layout.popoverAnchorId],
52
93
  );
53
94
 
54
95
  // TODO(burdon): Scroll area should be controlled by surface.
55
96
  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'
65
- >
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'>
77
- <ScrollArea.Thumb />
78
- </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>
97
+ <Main.ComplementarySidebar
98
+ classNames={[
99
+ topbar && 'block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]',
100
+ hoistStatusbar && 'block-end-[--statusbar-size]',
101
+ ]}
102
+ >
103
+ <Tabs.Root
104
+ orientation='vertical'
105
+ verticalVariant='stateless'
106
+ value={internalValue}
107
+ attendableId={attended[0]}
108
+ classNames='contents'
109
+ >
110
+ <div
111
+ role='none'
112
+ 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'
113
+ >
114
+ <Tabs.Tablist classNames='grid grid-cols-1 auto-rows-[--rail-action] p-1 gap-1 !overflow-y-auto'>
115
+ {availablePanels.map((panel) => (
116
+ <Tabs.Tab key={panel.id} value={panel.id} asChild>
117
+ <IconButton
118
+ label={toLocalizedString(panel.label, t)}
119
+ icon={panel.icon}
120
+ size={5}
121
+ iconOnly
122
+ tooltipSide='left'
123
+ data-value={panel.id}
124
+ variant={
125
+ activePanelId === panel.id
126
+ ? layout.complementarySidebarState === 'expanded'
127
+ ? 'primary'
128
+ : 'default'
129
+ : 'ghost'
130
+ }
131
+ onClick={handleTabClick}
132
+ />
133
+ </Tabs.Tab>
134
+ ))}
135
+ </Tabs.Tablist>
136
+ {!hoistStatusbar && (
137
+ <div role='none' className='grid grid-cols-1 auto-rows-[--rail-item] p-1 overflow-y-auto'>
138
+ <Surface role='status-bar--r0-footer' limit={1} />
139
+ </div>
140
+ )}
141
+ <div role='none' className='hidden lg:grid grid-cols-1 auto-rows-[--rail-action] p-1'>
142
+ <ToggleComplementarySidebarButton />
143
+ </div>
108
144
  </div>
109
- </StackContext.Provider>
145
+ {availablePanels.map((panel) => (
146
+ <Tabs.Tabpanel
147
+ key={panel.id}
148
+ value={panel.id}
149
+ 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)]'
150
+ {...(layout.complementarySidebarState !== 'expanded' && { inert: 'true' })}
151
+ >
152
+ <ComplementarySidebarPanel
153
+ panel={panel}
154
+ activePanelId={activePanelId}
155
+ data={data}
156
+ hoistStatusbar={hoistStatusbar}
157
+ />
158
+ </Tabs.Tabpanel>
159
+ ))}
160
+ </Tabs.Root>
110
161
  </Main.ComplementarySidebar>
111
162
  );
112
163
  };
164
+
165
+ type ComplementarySidebarPanelProps = {
166
+ panel: Panel;
167
+ activePanelId: string;
168
+ data?: {
169
+ id: string;
170
+ subject: any;
171
+ workspace: string;
172
+ popoverAnchorId?: string;
173
+ };
174
+ hoistStatusbar: boolean;
175
+ };
176
+
177
+ const ScrollArea = ({ children }: PropsWithChildren) => {
178
+ return (
179
+ <NaturalScrollArea.Root>
180
+ <NaturalScrollArea.Viewport>{children}</NaturalScrollArea.Viewport>
181
+ <NaturalScrollArea.Scrollbar orientation='vertical'>
182
+ <NaturalScrollArea.Thumb />
183
+ </NaturalScrollArea.Scrollbar>
184
+ </NaturalScrollArea.Root>
185
+ );
186
+ };
187
+
188
+ const ComplementarySidebarPanel = ({ panel, activePanelId, data, hoistStatusbar }: ComplementarySidebarPanelProps) => {
189
+ const { t } = useTranslation(DECK_PLUGIN);
190
+
191
+ if (panel.id !== activePanelId || !data) {
192
+ return null;
193
+ }
194
+
195
+ const Wrapper = panel.fixed ? Fragment : ScrollArea;
196
+
197
+ return (
198
+ <>
199
+ <h2 className='flex items-center pli-2 border-separator border-be font-medium'>
200
+ {toLocalizedString(panel.label, t)}
201
+ </h2>
202
+ <Wrapper>
203
+ <Surface
204
+ role={`complementary--${activePanelId}`}
205
+ data={data}
206
+ fallback={PlankContentError}
207
+ placeholder={<PlankLoading />}
208
+ />
209
+ </Wrapper>
210
+ {!hoistStatusbar && (
211
+ <div
212
+ role='contentinfo'
213
+ className='flex flex-wrap justify-center items-center border-bs border-separator pbs-1 pbe-[max(env(safe-area-inset-bottom),0.25rem)]'
214
+ >
215
+ <Surface role='status-bar--r1-footer' limit={1} />
216
+ </div>
217
+ )}
218
+ </>
219
+ );
220
+ };
@@ -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] lg:grid-rows-1'
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, 'bs-[--rail-action] flex items-stretch lg:hidden')}>
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
  };