@dxos/plugin-deck 0.9.0 → 0.9.1-staging.ee54ba693a

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 (314) hide show
  1. package/PLUGIN.mdl +3 -1
  2. package/dist/lib/neutral/{DeckLayout-DEURA3KR.mjs → DeckLayout-B3RUUV5P.mjs} +36 -22
  3. package/dist/lib/neutral/DeckLayout-B3RUUV5P.mjs.map +7 -0
  4. package/dist/lib/neutral/DeckPlugin.mjs +4 -8
  5. package/dist/lib/neutral/DeckPlugin.mjs.map +4 -4
  6. package/dist/lib/neutral/DeckSettings-Z7GMB7XJ.mjs +32 -0
  7. package/dist/lib/neutral/DeckSettings-Z7GMB7XJ.mjs.map +7 -0
  8. package/dist/lib/neutral/{add-toast-TNB6DXWU.mjs → add-toast-BHNEH5UY.mjs} +2 -2
  9. package/dist/lib/neutral/{adjust-HNU5CCRO.mjs → adjust-MJB6UMRQ.mjs} +16 -10
  10. package/dist/lib/neutral/adjust-MJB6UMRQ.mjs.map +7 -0
  11. package/dist/lib/neutral/{app-graph-builder-HMLT627T.mjs → app-graph-builder-2F7P4IFQ.mjs} +8 -7
  12. package/dist/lib/neutral/app-graph-builder-2F7P4IFQ.mjs.map +7 -0
  13. package/dist/lib/neutral/capabilities/index.mjs +8 -8
  14. package/dist/lib/neutral/{check-app-scheme-INSOF72J.mjs → check-app-scheme-HSAORHHX.mjs} +2 -2
  15. package/dist/lib/neutral/chunk-FKGYHBUB.mjs +8 -0
  16. package/dist/lib/neutral/{chunk-BS4EOYMK.mjs → chunk-ICOJ4GMB.mjs} +37 -19
  17. package/dist/lib/neutral/chunk-ICOJ4GMB.mjs.map +7 -0
  18. package/dist/lib/neutral/chunk-KY7LMF4D.mjs +46 -0
  19. package/dist/lib/neutral/chunk-KY7LMF4D.mjs.map +7 -0
  20. package/dist/lib/neutral/{chunk-324PPIZB.mjs → chunk-KZFJ4PBT.mjs} +4 -4
  21. package/dist/lib/neutral/chunk-KZFJ4PBT.mjs.map +7 -0
  22. package/dist/lib/neutral/{chunk-GBIGQKYW.mjs → chunk-PP32NEVY.mjs} +4 -4
  23. package/dist/lib/neutral/chunk-PP32NEVY.mjs.map +7 -0
  24. package/dist/lib/neutral/chunk-SONATB35.mjs +20 -0
  25. package/dist/lib/neutral/chunk-SONATB35.mjs.map +7 -0
  26. package/dist/lib/neutral/chunk-Z2B5RSVI.mjs +1096 -0
  27. package/dist/lib/neutral/chunk-Z2B5RSVI.mjs.map +7 -0
  28. package/dist/lib/neutral/{close-ASKR22A6.mjs → close-2YGB5IIP.mjs} +4 -3
  29. package/dist/lib/neutral/{close-ASKR22A6.mjs.map → close-2YGB5IIP.mjs.map} +1 -1
  30. package/dist/lib/neutral/components/index.mjs +201 -16
  31. package/dist/lib/neutral/components/index.mjs.map +4 -4
  32. package/dist/lib/neutral/containers/index.mjs +6 -11
  33. package/dist/lib/neutral/containers/index.mjs.map +3 -3
  34. package/dist/lib/neutral/hooks/index.mjs +101 -17
  35. package/dist/lib/neutral/hooks/index.mjs.map +4 -4
  36. package/dist/lib/neutral/index.mjs +18 -2
  37. package/dist/lib/neutral/meta.json +1 -1
  38. package/dist/lib/neutral/meta.mjs +1 -1
  39. package/dist/lib/neutral/{notification-tracker-P36322BH.mjs → notification-tracker-Y5CRTWJM.mjs} +12 -10
  40. package/dist/lib/neutral/notification-tracker-Y5CRTWJM.mjs.map +7 -0
  41. package/dist/lib/neutral/{open-5OYNO3RT.mjs → open-P6XQ56M7.mjs} +8 -7
  42. package/dist/lib/neutral/open-P6XQ56M7.mjs.map +7 -0
  43. package/dist/lib/neutral/operations/index.mjs +1 -1
  44. package/dist/lib/neutral/plugin.mjs +2 -2
  45. package/dist/lib/neutral/{react-root-HH5DEUOG.mjs → react-root-E6TAFHX6.mjs} +2 -2
  46. package/dist/lib/neutral/react-root-E6TAFHX6.mjs.map +7 -0
  47. package/dist/lib/neutral/{react-surface-3UVVCK3O.mjs → react-surface-H63FXUK3.mjs} +5 -6
  48. package/dist/lib/neutral/react-surface-H63FXUK3.mjs.map +7 -0
  49. package/dist/lib/neutral/{revert-workspace-B2QLT2C4.mjs → revert-workspace-RXWP2TEE.mjs} +2 -2
  50. package/dist/lib/neutral/{scroll-into-view-B52C3PJO.mjs → scroll-into-view-HFV5EGYZ.mjs} +2 -2
  51. package/dist/lib/neutral/{set-PA35ONXO.mjs → set-HOOVB7E4.mjs} +4 -3
  52. package/dist/lib/neutral/{set-PA35ONXO.mjs.map → set-HOOVB7E4.mjs.map} +1 -1
  53. package/dist/lib/neutral/{set-layout-mode-RPCCPQRB.mjs → set-layout-mode-XAGSZZGB.mjs} +2 -2
  54. package/dist/lib/neutral/{settings-EGNYUM4T.mjs → settings-6CDQEB6B.mjs} +3 -3
  55. package/dist/lib/neutral/settings-6CDQEB6B.mjs.map +7 -0
  56. package/dist/lib/neutral/{state-IIDXMQUO.mjs → state-F4X5GPGZ.mjs} +4 -3
  57. package/dist/lib/neutral/state-F4X5GPGZ.mjs.map +7 -0
  58. package/dist/lib/neutral/{switch-workspace-LZF4KZXH.mjs → switch-workspace-PA7N6EUX.mjs} +4 -4
  59. package/dist/lib/neutral/switch-workspace-PA7N6EUX.mjs.map +7 -0
  60. package/dist/lib/neutral/translations.mjs +3 -3
  61. package/dist/lib/neutral/translations.mjs.map +3 -3
  62. package/dist/lib/neutral/types/index.mjs +11 -1
  63. package/dist/lib/neutral/{update-companion-YUCZZVGY.mjs → update-companion-6A2SKQAI.mjs} +14 -6
  64. package/dist/lib/neutral/update-companion-6A2SKQAI.mjs.map +7 -0
  65. package/dist/lib/neutral/{update-complementary-7FZNB55J.mjs → update-complementary-K55I5EV5.mjs} +2 -2
  66. package/dist/lib/neutral/{update-dialog-FNQTSSAP.mjs → update-dialog-Z3GEXMVV.mjs} +2 -2
  67. package/dist/lib/neutral/{update-plank-size-3YW4NXEY.mjs → update-plank-size-BTESVV7N.mjs} +2 -2
  68. package/dist/lib/neutral/{update-popover-G2VUD7E6.mjs → update-popover-QEVDSZSH.mjs} +2 -2
  69. package/dist/lib/neutral/{update-sidebar-KRHPUHUB.mjs → update-sidebar-VSRCN47U.mjs} +2 -2
  70. package/dist/lib/neutral/{url-handler-A6HLW4RB.mjs → url-handler-ERZXXEYR.mjs} +11 -10
  71. package/dist/lib/neutral/url-handler-ERZXXEYR.mjs.map +7 -0
  72. package/dist/types/dx.config.d.ts +28 -0
  73. package/dist/types/dx.config.d.ts.map +1 -0
  74. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  75. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -2
  76. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  77. package/dist/types/src/capabilities/index.d.ts +8 -196
  78. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  79. package/dist/types/src/capabilities/notification-tracker.d.ts +1 -1
  80. package/dist/types/src/capabilities/notification-tracker.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/react-root.d.ts +1 -5
  82. package/dist/types/src/capabilities/react-root.d.ts.map +1 -1
  83. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  84. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  85. package/dist/types/src/capabilities/settings.d.ts +1 -3
  86. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  87. package/dist/types/src/capabilities/state.d.ts +1 -187
  88. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  89. package/dist/types/src/capabilities/tools.d.ts +1 -1
  90. package/dist/types/src/capabilities/url-handler.d.ts +1 -1
  91. package/dist/types/src/components/Companion/Companion.d.ts +17 -0
  92. package/dist/types/src/components/Companion/Companion.d.ts.map +1 -0
  93. package/dist/types/src/components/Companion/index.d.ts +2 -0
  94. package/dist/types/src/components/Companion/index.d.ts.map +1 -0
  95. package/dist/types/src/components/Matrix/Matrix.d.ts +1 -1
  96. package/dist/types/src/components/Matrix/Matrix.d.ts.map +1 -1
  97. package/dist/types/src/components/Matrix/Matrix.stories.d.ts +2 -2
  98. package/dist/types/src/components/Matrix/Matrix.stories.d.ts.map +1 -1
  99. package/dist/types/src/components/Matrix/index.d.ts +1 -1
  100. package/dist/types/src/components/Matrix/index.d.ts.map +1 -1
  101. package/dist/types/src/components/Pane/Pane.d.ts +45 -0
  102. package/dist/types/src/components/Pane/Pane.d.ts.map +1 -0
  103. package/dist/types/src/components/Pane/Pane.stories.d.ts +7 -0
  104. package/dist/types/src/components/Pane/Pane.stories.d.ts.map +1 -0
  105. package/dist/types/src/components/Pane/index.d.ts +2 -0
  106. package/dist/types/src/components/Pane/index.d.ts.map +1 -0
  107. package/dist/types/src/components/Plank/Plank.d.ts +74 -0
  108. package/dist/types/src/components/Plank/Plank.d.ts.map +1 -0
  109. package/dist/types/src/components/Plank/Plank.stories.d.ts +6 -0
  110. package/dist/types/src/components/Plank/Plank.stories.d.ts.map +1 -0
  111. package/dist/types/src/components/Plank/index.d.ts +2 -0
  112. package/dist/types/src/components/Plank/index.d.ts.map +1 -0
  113. package/dist/types/src/components/index.d.ts +3 -2
  114. package/dist/types/src/components/index.d.ts.map +1 -1
  115. package/dist/types/src/containers/Deck/Banner.d.ts.map +1 -1
  116. package/dist/types/src/containers/Deck/Deck.d.ts +1 -1
  117. package/dist/types/src/containers/Deck/Deck.d.ts.map +1 -1
  118. package/dist/types/src/containers/Deck/Deck.stories.d.ts +2 -2
  119. package/dist/types/src/containers/Deck/DeckPlank.d.ts +21 -0
  120. package/dist/types/src/containers/Deck/DeckPlank.d.ts.map +1 -0
  121. package/dist/types/src/containers/Deck/DeckViewport.d.ts +3 -1
  122. package/dist/types/src/containers/Deck/DeckViewport.d.ts.map +1 -1
  123. package/dist/types/src/containers/{Plank → Deck}/PlankControls.d.ts +3 -10
  124. package/dist/types/src/containers/Deck/PlankControls.d.ts.map +1 -0
  125. package/dist/types/src/containers/Deck/PlankFallback.d.ts +6 -0
  126. package/dist/types/src/containers/Deck/PlankFallback.d.ts.map +1 -0
  127. package/dist/types/src/containers/Deck/StatusBar.d.ts.map +1 -1
  128. package/dist/types/src/containers/Deck/useDeckPlank.d.ts +49 -0
  129. package/dist/types/src/containers/Deck/useDeckPlank.d.ts.map +1 -0
  130. package/dist/types/src/containers/DeckLayout/DeckLayout.stories.d.ts +2 -2
  131. package/dist/types/src/containers/DeckLayout/DeckLayout.stories.d.ts.map +1 -1
  132. package/dist/types/src/containers/DeckLayout/Popover.d.ts.map +1 -1
  133. package/dist/types/src/{components → containers}/DeckSettings/DeckSettings.d.ts +1 -1
  134. package/dist/types/src/containers/DeckSettings/DeckSettings.d.ts.map +1 -0
  135. package/dist/types/src/{components → containers}/DeckSettings/DeckSettings.stories.d.ts +2 -2
  136. package/dist/types/src/{components → containers}/DeckSettings/DeckSettings.stories.d.ts.map +1 -1
  137. package/dist/types/src/containers/DeckSettings/index.d.ts.map +1 -0
  138. package/dist/types/src/containers/Sidebar/ComplementarySidebar.d.ts.map +1 -1
  139. package/dist/types/src/containers/index.d.ts +1 -1
  140. package/dist/types/src/containers/index.d.ts.map +1 -1
  141. package/dist/types/src/hooks/index.d.ts +2 -0
  142. package/dist/types/src/hooks/index.d.ts.map +1 -1
  143. package/dist/types/src/hooks/useCompanionSplit.d.ts +28 -0
  144. package/dist/types/src/hooks/useCompanionSplit.d.ts.map +1 -0
  145. package/dist/types/src/hooks/useCompanions.d.ts +11 -7
  146. package/dist/types/src/hooks/useCompanions.d.ts.map +1 -1
  147. package/dist/types/src/hooks/useDeckCompanions.d.ts +2 -2
  148. package/dist/types/src/hooks/useDeckCompanions.d.ts.map +1 -1
  149. package/dist/types/src/hooks/useDeckState.d.ts +1 -1
  150. package/dist/types/src/hooks/useDeckState.d.ts.map +1 -1
  151. package/dist/types/src/hooks/useSelectedCompanionVariant.d.ts +6 -0
  152. package/dist/types/src/hooks/useSelectedCompanionVariant.d.ts.map +1 -0
  153. package/dist/types/src/index.d.ts +1 -0
  154. package/dist/types/src/index.d.ts.map +1 -1
  155. package/dist/types/src/meta.d.ts +32 -2
  156. package/dist/types/src/meta.d.ts.map +1 -1
  157. package/dist/types/src/operations/adjust.d.ts.map +1 -1
  158. package/dist/types/src/operations/open.d.ts.map +1 -1
  159. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -1
  160. package/dist/types/src/operations/update-companion.d.ts.map +1 -1
  161. package/dist/types/src/translations.d.ts +2 -2
  162. package/dist/types/src/translations.d.ts.map +1 -1
  163. package/dist/types/src/types/DeckCapabilities.d.ts +4 -4
  164. package/dist/types/src/types/DeckCapabilities.d.ts.map +1 -1
  165. package/dist/types/src/types/DeckOperation.d.ts +2 -2
  166. package/dist/types/src/types/DeckOperation.d.ts.map +1 -1
  167. package/dist/types/src/types/index.d.ts +1 -0
  168. package/dist/types/src/types/index.d.ts.map +1 -1
  169. package/dist/types/src/types/schema.d.ts +11 -9
  170. package/dist/types/src/types/schema.d.ts.map +1 -1
  171. package/dist/types/src/types/surface.d.ts +12 -0
  172. package/dist/types/src/types/surface.d.ts.map +1 -0
  173. package/dist/types/src/util/companion-view-state.d.ts +16 -0
  174. package/dist/types/src/util/companion-view-state.d.ts.map +1 -0
  175. package/dist/types/src/util/index.d.ts +1 -0
  176. package/dist/types/src/util/index.d.ts.map +1 -1
  177. package/dist/types/src/util/plank-url-params.d.ts +2 -0
  178. package/dist/types/src/util/plank-url-params.d.ts.map +1 -1
  179. package/dist/types/tsconfig.tsbuildinfo +1 -1
  180. package/dx.config.ts +35 -0
  181. package/package.json +50 -48
  182. package/src/DeckPlugin.test.ts +1 -1
  183. package/src/DeckPlugin.ts +2 -3
  184. package/src/capabilities/app-graph-builder.ts +7 -6
  185. package/src/capabilities/check-app-scheme.ts +3 -3
  186. package/src/capabilities/notification-tracker.ts +11 -9
  187. package/src/capabilities/react-root.tsx +1 -1
  188. package/src/capabilities/react-surface.tsx +4 -5
  189. package/src/capabilities/settings.ts +2 -2
  190. package/src/capabilities/state.ts +1 -1
  191. package/src/capabilities/url-handler.ts +7 -15
  192. package/src/components/Companion/Companion.tsx +91 -0
  193. package/src/components/Companion/index.ts +5 -0
  194. package/src/components/Matrix/Matrix.stories.tsx +15 -27
  195. package/src/components/Matrix/Matrix.tsx +3 -3
  196. package/src/components/Matrix/SPEC.md +1 -1
  197. package/src/components/Matrix/index.ts +1 -1
  198. package/src/components/Pane/Pane.stories.tsx +92 -0
  199. package/src/components/Pane/Pane.tsx +178 -0
  200. package/src/components/Pane/index.ts +5 -0
  201. package/src/components/Plank/Plank.stories.tsx +103 -0
  202. package/src/components/Plank/Plank.tsx +149 -0
  203. package/src/components/Plank/index.ts +5 -0
  204. package/src/components/index.ts +3 -4
  205. package/src/containers/Deck/Banner.tsx +5 -4
  206. package/src/containers/Deck/Deck.tsx +3 -3
  207. package/src/containers/Deck/DeckPlank.tsx +187 -0
  208. package/src/containers/Deck/DeckViewport.tsx +118 -246
  209. package/src/containers/{Plank → Deck}/PlankControls.tsx +21 -19
  210. package/src/containers/Deck/PlankFallback.tsx +42 -0
  211. package/src/containers/Deck/StatusBar.tsx +4 -2
  212. package/src/containers/Deck/useDeckPlank.ts +219 -0
  213. package/src/containers/DeckLayout/DeckLayout.stories.tsx +44 -60
  214. package/src/containers/DeckLayout/Dialog.tsx +1 -1
  215. package/src/containers/DeckLayout/Fallback.tsx +1 -1
  216. package/src/containers/DeckLayout/Popover.tsx +37 -20
  217. package/src/containers/DeckLayout/Toast.tsx +1 -1
  218. package/src/{components → containers}/DeckSettings/DeckSettings.stories.tsx +1 -1
  219. package/src/containers/DeckSettings/DeckSettings.tsx +42 -0
  220. package/src/containers/Sidebar/ComplementarySidebar.tsx +8 -7
  221. package/src/containers/Sidebar/Sidebar.tsx +1 -1
  222. package/src/containers/Sidebar/SidebarButton.tsx +3 -3
  223. package/src/containers/index.ts +1 -1
  224. package/src/hooks/index.ts +2 -0
  225. package/src/hooks/useCompanionSplit.ts +78 -0
  226. package/src/hooks/useCompanions.ts +39 -7
  227. package/src/hooks/useDeckCompanions.ts +3 -3
  228. package/src/hooks/useDeckState.ts +1 -1
  229. package/src/hooks/useSelectedCompanionVariant.ts +14 -0
  230. package/src/index.ts +7 -0
  231. package/src/meta.ts +2 -27
  232. package/src/operations/adjust.ts +23 -12
  233. package/src/operations/open.ts +12 -10
  234. package/src/operations/switch-workspace.ts +2 -2
  235. package/src/operations/update-companion.ts +10 -6
  236. package/src/translations.ts +3 -3
  237. package/src/types/DeckCapabilities.ts +6 -4
  238. package/src/types/DeckEvents.ts +1 -1
  239. package/src/types/DeckOperation.ts +3 -2
  240. package/src/types/index.ts +1 -0
  241. package/src/types/schema.ts +21 -16
  242. package/src/types/surface.ts +28 -0
  243. package/src/util/companion-view-state.ts +28 -0
  244. package/src/util/index.ts +1 -0
  245. package/src/util/plank-url-params.test.ts +5 -0
  246. package/src/util/plank-url-params.ts +5 -3
  247. package/src/util/sanitize-persisted-state.test.ts +1 -1
  248. package/src/util/set-active.test.ts +1 -1
  249. package/dist/lib/neutral/DeckLayout-DEURA3KR.mjs.map +0 -7
  250. package/dist/lib/neutral/DeckSettings-W5I57OXM.mjs +0 -27
  251. package/dist/lib/neutral/DeckSettings-W5I57OXM.mjs.map +0 -7
  252. package/dist/lib/neutral/adjust-HNU5CCRO.mjs.map +0 -7
  253. package/dist/lib/neutral/app-graph-builder-HMLT627T.mjs.map +0 -7
  254. package/dist/lib/neutral/chunk-324PPIZB.mjs.map +0 -7
  255. package/dist/lib/neutral/chunk-BS4EOYMK.mjs.map +0 -7
  256. package/dist/lib/neutral/chunk-GBIGQKYW.mjs.map +0 -7
  257. package/dist/lib/neutral/chunk-PYEY5SEC.mjs +0 -37
  258. package/dist/lib/neutral/chunk-PYEY5SEC.mjs.map +0 -7
  259. package/dist/lib/neutral/chunk-Q4W6B4IB.mjs +0 -8
  260. package/dist/lib/neutral/chunk-WAXJPQJI.mjs +0 -1306
  261. package/dist/lib/neutral/chunk-WAXJPQJI.mjs.map +0 -7
  262. package/dist/lib/neutral/notification-tracker-P36322BH.mjs.map +0 -7
  263. package/dist/lib/neutral/open-5OYNO3RT.mjs.map +0 -7
  264. package/dist/lib/neutral/react-root-HH5DEUOG.mjs.map +0 -7
  265. package/dist/lib/neutral/react-surface-3UVVCK3O.mjs.map +0 -7
  266. package/dist/lib/neutral/settings-EGNYUM4T.mjs.map +0 -7
  267. package/dist/lib/neutral/state-IIDXMQUO.mjs.map +0 -7
  268. package/dist/lib/neutral/switch-workspace-LZF4KZXH.mjs.map +0 -7
  269. package/dist/lib/neutral/update-companion-YUCZZVGY.mjs.map +0 -7
  270. package/dist/lib/neutral/url-handler-A6HLW4RB.mjs.map +0 -7
  271. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts.map +0 -1
  272. package/dist/types/src/components/DeckSettings/index.d.ts.map +0 -1
  273. package/dist/types/src/containers/Plank/Plank.d.ts +0 -17
  274. package/dist/types/src/containers/Plank/Plank.d.ts.map +0 -1
  275. package/dist/types/src/containers/Plank/Plank.stories.d.ts +0 -67
  276. package/dist/types/src/containers/Plank/Plank.stories.d.ts.map +0 -1
  277. package/dist/types/src/containers/Plank/PlankComponent.d.ts +0 -17
  278. package/dist/types/src/containers/Plank/PlankComponent.d.ts.map +0 -1
  279. package/dist/types/src/containers/Plank/PlankContent.d.ts +0 -10
  280. package/dist/types/src/containers/Plank/PlankContent.d.ts.map +0 -1
  281. package/dist/types/src/containers/Plank/PlankControls.d.ts.map +0 -1
  282. package/dist/types/src/containers/Plank/PlankError.d.ts +0 -15
  283. package/dist/types/src/containers/Plank/PlankError.d.ts.map +0 -1
  284. package/dist/types/src/containers/Plank/PlankHeading.d.ts +0 -22
  285. package/dist/types/src/containers/Plank/PlankHeading.d.ts.map +0 -1
  286. package/dist/types/src/containers/Plank/PlankLoading.d.ts +0 -3
  287. package/dist/types/src/containers/Plank/PlankLoading.d.ts.map +0 -1
  288. package/dist/types/src/containers/Plank/PlankRoot.d.ts +0 -37
  289. package/dist/types/src/containers/Plank/PlankRoot.d.ts.map +0 -1
  290. package/dist/types/src/containers/Plank/index.d.ts +0 -4
  291. package/dist/types/src/containers/Plank/index.d.ts.map +0 -1
  292. package/src/components/DeckSettings/DeckSettings.tsx +0 -34
  293. package/src/containers/Plank/Plank.stories.tsx +0 -108
  294. package/src/containers/Plank/Plank.tsx +0 -22
  295. package/src/containers/Plank/PlankComponent.tsx +0 -223
  296. package/src/containers/Plank/PlankContent.tsx +0 -45
  297. package/src/containers/Plank/PlankError.tsx +0 -82
  298. package/src/containers/Plank/PlankHeading.tsx +0 -237
  299. package/src/containers/Plank/PlankLoading.tsx +0 -10
  300. package/src/containers/Plank/PlankRoot.tsx +0 -49
  301. package/src/containers/Plank/index.ts +0 -7
  302. /package/dist/lib/neutral/{add-toast-TNB6DXWU.mjs.map → add-toast-BHNEH5UY.mjs.map} +0 -0
  303. /package/dist/lib/neutral/{check-app-scheme-INSOF72J.mjs.map → check-app-scheme-HSAORHHX.mjs.map} +0 -0
  304. /package/dist/lib/neutral/{chunk-Q4W6B4IB.mjs.map → chunk-FKGYHBUB.mjs.map} +0 -0
  305. /package/dist/lib/neutral/{revert-workspace-B2QLT2C4.mjs.map → revert-workspace-RXWP2TEE.mjs.map} +0 -0
  306. /package/dist/lib/neutral/{scroll-into-view-B52C3PJO.mjs.map → scroll-into-view-HFV5EGYZ.mjs.map} +0 -0
  307. /package/dist/lib/neutral/{set-layout-mode-RPCCPQRB.mjs.map → set-layout-mode-XAGSZZGB.mjs.map} +0 -0
  308. /package/dist/lib/neutral/{update-complementary-7FZNB55J.mjs.map → update-complementary-K55I5EV5.mjs.map} +0 -0
  309. /package/dist/lib/neutral/{update-dialog-FNQTSSAP.mjs.map → update-dialog-Z3GEXMVV.mjs.map} +0 -0
  310. /package/dist/lib/neutral/{update-plank-size-3YW4NXEY.mjs.map → update-plank-size-BTESVV7N.mjs.map} +0 -0
  311. /package/dist/lib/neutral/{update-popover-G2VUD7E6.mjs.map → update-popover-QEVDSZSH.mjs.map} +0 -0
  312. /package/dist/lib/neutral/{update-sidebar-KRHPUHUB.mjs.map → update-sidebar-VSRCN47U.mjs.map} +0 -0
  313. /package/dist/types/src/{components → containers}/DeckSettings/index.d.ts +0 -0
  314. /package/src/{components → containers}/DeckSettings/index.ts +0 -0
@@ -2,43 +2,36 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- import React, {
6
- Fragment,
7
- memo,
8
- type PropsWithChildren,
9
- type UIEvent,
10
- useCallback,
11
- useEffect,
12
- useMemo,
13
- useRef,
14
- } from 'react';
5
+ import React, { type PropsWithChildren, useCallback, useEffect, useRef } from 'react';
15
6
 
16
7
  import { Surface, useOperationInvoker } from '@dxos/app-framework/ui';
17
8
  import { LayoutOperation } from '@dxos/app-toolkit';
18
- import { useAppGraph } from '@dxos/app-toolkit/ui';
19
9
  import { addEventListener } from '@dxos/async';
20
10
  import { invariant } from '@dxos/invariant';
21
- import { useNode } from '@dxos/plugin-graph';
22
- import { IconButton, Main, type MainContentProps, useOnTransition, useTranslation } from '@dxos/react-ui';
23
- import { mainPaddingTransitions } from '@dxos/react-ui';
24
- import { DEFAULT_HORIZONTAL_SIZE, Stack, StackContext } from '@dxos/react-ui-stack';
11
+ import { IconButton, Main, type MainContentProps, ScrollArea, useOnTransition, useTranslation } from '@dxos/react-ui';
12
+ import { mainIntrinsicSize, mainPaddingTransitions } from '@dxos/react-ui';
13
+ import { Mosaic, type MosaicStackTileComponent, type MosaicTileProps } from '@dxos/react-ui-mosaic';
25
14
  import { hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/ui-theme';
26
15
 
27
- import { useBreakpoints, useCompanions, useDeckState, useSelectedCompanion } from '#hooks';
16
+ import { useBreakpoints, useDeckState } from '#hooks';
28
17
  import { meta } from '#meta';
29
- import { DeckOperation } from '#types';
30
- import { getMode } from '#types';
18
+ import { DeckOperation, Keyshortcuts, getMode } from '#types';
31
19
 
32
20
  import { layoutAppliesTopbar } from '../../util';
33
- import { Plank, PlankRootProps, type PlankComponentProps } from '../Plank';
34
21
  import {
35
22
  ToggleComplementarySidebarButton as NaturalToggleComplementarySidebarButton,
36
23
  ToggleSidebarButton as NaturalToggleSidebarButton,
37
24
  } from '../Sidebar';
25
+ import { DeckPlank } from './DeckPlank';
38
26
  import { useDeckContext } from './DeckRoot';
39
27
 
40
28
  const DECK_VIEWPORT_NAME = 'DeckViewport';
41
29
 
30
+ // Multi-mode plank extents (rem); each plank persists its own width via `plankSizing`.
31
+ const DEFAULT_PLANK_SIZE = 50;
32
+ const MIN_PLANK_SIZE = 20;
33
+ const MAX_PLANK_SIZE = 120;
34
+
42
35
  //
43
36
  // DeckViewport
44
37
  //
@@ -46,11 +39,10 @@ const DECK_VIEWPORT_NAME = 'DeckViewport';
46
39
  export type DeckViewportProps = PropsWithChildren;
47
40
 
48
41
  /**
49
- * Deck viewport that renders the main content area and sets CSS variables for plank sizing.
42
+ * Deck viewport that renders the main content area and sets CSS variables for sidebar widths.
50
43
  */
51
44
  export const DeckViewport = ({ children }: DeckViewportProps) => {
52
45
  const {
53
- deck: { active, plankSizing },
54
46
  state: { sidebarState, complementarySidebarState },
55
47
  settings,
56
48
  layoutMode,
@@ -82,8 +74,6 @@ export const DeckViewport = ({ children }: DeckViewportProps) => {
82
74
  : complementarySidebarState === 'collapsed'
83
75
  ? 'var(--dx-rail-size)'
84
76
  : '0',
85
- '--main-content-first-width': `${plankSizing[active[0] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
86
- '--main-content-last-width': `${plankSizing[active[(active.length ?? 1) - 1] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
87
77
  } as MainContentProps['style']
88
78
  }
89
79
  >
@@ -105,7 +95,7 @@ export const DeckContentEmpty = () => {
105
95
  const topbar = layoutAppliesTopbar(breakpoint, layoutMode);
106
96
  return (
107
97
  <div className='grid place-items-center p-8 relative bg-deck-surface' data-testid='layoutPlugin.firstRunMessage'>
108
- <Surface.Surface role='keyshortcuts' />
98
+ <Surface.Surface type={Keyshortcuts} />
109
99
  {!topbar && <ToggleSidebarButton />}
110
100
  </div>
111
101
  );
@@ -120,8 +110,7 @@ export const DeckContentEmpty = () => {
120
110
  */
121
111
  export const DeckSoloMode = () => {
122
112
  const { deck, settings, layoutMode, onLayoutChange } = useDeckContext('DeckSoloMode');
123
- const { companionOpen, companionVariant, fullscreen, solo } = deck;
124
- const effectiveCompanionVariant = fullscreen ? undefined : companionOpen ? companionVariant : undefined;
113
+ const { companionOpen, fullscreen, solo } = deck;
125
114
  const breakpoint = useBreakpoints();
126
115
  const topbar = layoutAppliesTopbar(breakpoint, layoutMode);
127
116
  invariant(solo);
@@ -147,21 +136,14 @@ export const DeckSoloMode = () => {
147
136
  <div className='relative overflow-hidden bg-deck-surface'>
148
137
  <DeckSidebarToggles topbar={topbar} fullscreen={fullscreen} />
149
138
  {fullscreen && <ExitFullscreenButton onExit={() => onLayoutChange({ mode: 'solo--fullscreen' })} />}
150
- <StackContext.Provider
151
- value={{
152
- orientation: 'horizontal',
153
- size: 'contain',
154
- rail: true,
155
- }}
156
- >
157
- <PlankContainer
158
- id={solo}
159
- part='solo'
160
- layoutMode={layoutMode}
161
- companionVariant={effectiveCompanionVariant}
162
- settings={settings}
163
- />
164
- </StackContext.Provider>
139
+ <DeckPlank
140
+ id={solo}
141
+ part='solo'
142
+ layoutMode={layoutMode}
143
+ companionShown={!fullscreen && companionOpen}
144
+ settings={settings}
145
+ classNames={mx('absolute inset-0', mainIntrinsicSize)}
146
+ />
165
147
  </div>
166
148
  );
167
149
  };
@@ -170,25 +152,65 @@ export const DeckSoloMode = () => {
170
152
  // DeckMultiMode
171
153
  //
172
154
 
155
+ const getPlankId = (id: string) => id;
156
+
173
157
  /**
174
- * Multi-plank horizontal scrolling layout.
158
+ * Tile wrapping a {@link DeckPlank} in a resizable {@link Mosaic.Tile}; the committed width persists via
159
+ * `plankSizing`. Reads the deck context directly since the Mosaic stack renders tiles by id.
160
+ */
161
+ const DeckPlankTile: MosaicStackTileComponent<string> = (props) => {
162
+ const id = props.data;
163
+ const { deck, settings, layoutMode } = useDeckContext('DeckPlankTile');
164
+ const { invokePromise } = useOperationInvoker();
165
+
166
+ const handleSizeChange = useCallback<NonNullable<MosaicTileProps['onSizeChange']>>(
167
+ (size) => {
168
+ if (typeof size === 'number') {
169
+ void invokePromise(DeckOperation.UpdatePlankSize, { id, size: Math.round(size) });
170
+ }
171
+ },
172
+ [invokePromise, id],
173
+ );
174
+
175
+ return (
176
+ <Mosaic.Tile
177
+ {...props}
178
+ classNames='relative h-full'
179
+ size={deck.plankSizing[id] ?? DEFAULT_PLANK_SIZE}
180
+ minSize={MIN_PLANK_SIZE}
181
+ maxSize={MAX_PLANK_SIZE}
182
+ onSizeChange={handleSizeChange}
183
+ >
184
+ <DeckPlank
185
+ id={id}
186
+ part='multi'
187
+ layoutMode={layoutMode}
188
+ active={deck.active}
189
+ companionShown={deck.companionOpen}
190
+ settings={settings}
191
+ classNames='size-full'
192
+ />
193
+ <Mosaic.ResizeHandle />
194
+ </Mosaic.Tile>
195
+ );
196
+ };
197
+
198
+ /**
199
+ * Multi-plank horizontal scrolling layout. Planks are resizable {@link Mosaic.Tile}s in a horizontal
200
+ * {@link Mosaic.Stack}; the scroll position is preserved across solo↔multi transitions and the
201
+ * just-navigated plank is scrolled into view.
175
202
  */
176
203
  export const DeckMultiMode = () => {
177
- const {
178
- deck: { active, companionVariant, fullscreen },
179
- settings,
180
- layoutMode,
181
- } = useDeckContext('DeckMultiMode');
182
- /** In multi mode the companion column is always shown when the last plank has companions (not gated by `companionOpen`). */
183
- const effectiveCompanionVariant = companionVariant;
184
- const lastPlankId = active[active.length - 1];
185
- const lastPlankCompanions = useCompanions(lastPlankId);
204
+ const { deck, layoutMode } = useDeckContext('DeckMultiMode');
205
+ const { active, fullscreen } = deck;
206
+ const { state } = useDeckState();
207
+ const { invokePromise } = useOperationInvoker();
186
208
  const breakpoint = useBreakpoints();
187
209
  const topbar = layoutAppliesTopbar(breakpoint, layoutMode);
188
- const deckRef = useRef<HTMLDivElement>(null);
210
+ const viewportRef = useRef<HTMLDivElement>(null);
189
211
 
190
- /** Clear scroll restoration state if the window is resized. */
191
- const scrollLeftRef = useRef<number>(null);
212
+ // Preserve horizontal scroll position across solo↔multi transitions; a window resize invalidates it.
213
+ const scrollLeftRef = useRef<number | null>(null);
192
214
  useEffect(
193
215
  () =>
194
216
  addEventListener(window, 'resize', () => {
@@ -196,67 +218,58 @@ export const DeckMultiMode = () => {
196
218
  }),
197
219
  [],
198
220
  );
199
-
200
221
  const restoreScroll = useCallback(() => {
201
- if (deckRef.current && scrollLeftRef.current != null) {
202
- deckRef.current.scrollLeft = scrollLeftRef.current;
222
+ if (viewportRef.current && scrollLeftRef.current != null) {
223
+ viewportRef.current.scrollLeft = scrollLeftRef.current;
203
224
  }
204
225
  }, []);
205
-
206
226
  useOnTransition(layoutMode, (mode) => mode !== 'multi', 'multi', restoreScroll);
207
-
208
- /** Save scroll position as the user scrolls. */
209
- const handleScroll = useCallback((event: UIEvent) => {
210
- if (event.currentTarget === event.target) {
211
- scrollLeftRef.current = (event.target as HTMLDivElement).scrollLeft;
227
+ // Save scroll position as the user scrolls (ScrollArea.Viewport does not forward `onScroll`).
228
+ useEffect(() => {
229
+ const viewport = viewportRef.current;
230
+ if (!viewport) {
231
+ return;
212
232
  }
233
+ return addEventListener(viewport, 'scroll', () => {
234
+ scrollLeftRef.current = viewport.scrollLeft;
235
+ });
213
236
  }, []);
214
237
 
215
- // Create order map.
216
- // In multi mode only the last plank hosts the companion pane, so only that plank adds the extra column.
217
- const { order, itemsCount } = useMemo(() => {
218
- const lastHasCompanions = lastPlankCompanions.length > 0;
219
- return active.reduce(
220
- (acc: { order: Record<string, number>; itemsCount: number }, entryId, index) => {
221
- const isLastPlank = index === active.length - 1;
222
- acc.order[entryId] = acc.itemsCount + 1;
223
- acc.itemsCount += lastHasCompanions && isLastPlank ? 3 : 2;
224
- return acc;
225
- },
226
- { order: {}, itemsCount: 0 },
227
- );
228
- }, [active, lastPlankCompanions.length]);
238
+ // Scroll the just-navigated plank into view, then clear the one-shot flag.
239
+ useEffect(() => {
240
+ const id = state.scrollIntoView;
241
+ const viewport = viewportRef.current;
242
+ if (!id || !viewport) {
243
+ return;
244
+ }
245
+
246
+ const tile = viewport.querySelector<HTMLElement>(`[data-object-id="${CSS.escape(id)}"]`);
247
+ if (tile) {
248
+ const offset = tile.getBoundingClientRect().left - viewport.getBoundingClientRect().left + viewport.scrollLeft;
249
+ viewport.scrollTo({ left: offset, behavior: 'smooth' });
250
+ }
251
+ void invokePromise(LayoutOperation.ScrollIntoView, { subject: undefined });
252
+ }, [state.scrollIntoView, invokePromise]);
229
253
 
230
254
  return (
231
255
  <div className='relative bg-deck-surface overflow-hidden'>
232
256
  <DeckSidebarToggles topbar={topbar} fullscreen={fullscreen} />
233
- <Stack
234
- classNames={[
235
- 'absolute h-[calc(100%-2*var(--main-spacing))] w-full inset-y-(--main-spacing) -inset-w-px',
236
- mainPaddingTransitions,
237
- ]}
238
- orientation='horizontal'
239
- size='contain'
240
- itemsCount={itemsCount - 1}
241
- onScroll={handleScroll}
242
- ref={deckRef}
243
- >
244
- {active.map((entryId) => (
245
- <Fragment key={entryId}>
246
- {/* TODO(burdon): Setting for separator. */}
247
- <PlankSeparator hidden order={order[entryId] - 1} encapsulate={!!settings?.encapsulatedPlanks} />
248
- <PlankContainer
249
- id={entryId}
250
- part='multi'
251
- active={active}
252
- order={order[entryId]}
253
- layoutMode={layoutMode}
254
- companionVariant={effectiveCompanionVariant}
255
- settings={settings}
256
- />
257
- </Fragment>
258
- ))}
259
- </Stack>
257
+ <Mosaic.Root>
258
+ <Mosaic.Container orientation='horizontal' classNames={['absolute inset-0', mainPaddingTransitions]}>
259
+ <ScrollArea.Root orientation='horizontal' classNames='size-full'>
260
+ <ScrollArea.Viewport ref={viewportRef}>
261
+ <Mosaic.Stack
262
+ orientation='horizontal'
263
+ classNames='h-full gap-(--main-spacing) px-(--main-spacing)'
264
+ getId={getPlankId}
265
+ items={active}
266
+ Tile={DeckPlankTile}
267
+ draggable={false}
268
+ />
269
+ </ScrollArea.Viewport>
270
+ </ScrollArea.Root>
271
+ </Mosaic.Container>
272
+ </Mosaic.Root>
260
273
  </div>
261
274
  );
262
275
  };
@@ -273,7 +286,7 @@ const ToggleComplementarySidebarButton = () => (
273
286
  );
274
287
 
275
288
  const ExitFullscreenButton = ({ onExit }: { onExit: () => void }) => {
276
- const { t } = useTranslation(meta.id);
289
+ const { t } = useTranslation(meta.profile.key);
277
290
  return (
278
291
  <div
279
292
  className={mx(
@@ -307,144 +320,3 @@ const DeckSidebarToggles = ({ topbar, fullscreen }: { topbar: boolean; fullscree
307
320
  </>
308
321
  );
309
322
  };
310
-
311
- //
312
- // PlankSeparator
313
- //
314
-
315
- const PlankSeparator = ({ order, hidden, encapsulate }: { order: number; hidden?: boolean; encapsulate?: boolean }) =>
316
- order > 0 && (
317
- <span
318
- role='separator'
319
- className={mx('row-span-2 bg-deck-surface', hidden && 'hidden', encapsulate ? 'w-0' : 'w-4')}
320
- style={{ gridColumn: order }}
321
- />
322
- );
323
-
324
- //
325
- // PlankContainer
326
- //
327
-
328
- type PlankContainerProps = Pick<PlankRootProps, 'layoutMode' | 'part' | 'settings'> &
329
- Pick<PlankComponentProps, 'id'> &
330
- Partial<Pick<PlankComponentProps, 'path' | 'order' | 'active'>> & {
331
- companionVariant?: string;
332
- };
333
-
334
- /**
335
- * Connected Plank that calls hooks and renders the radix-style Plank tree.
336
- * This is the bridge between DeckViewport (which knows about framework hooks) and
337
- * the pure Plank components (which receive everything via context).
338
- */
339
- const PlankContainer = memo(
340
- ({ id, layoutMode, part, order, settings, companionVariant, active, ...props }: PlankContainerProps) => {
341
- const { graph } = useAppGraph();
342
- const { invokePromise } = useOperationInvoker();
343
- const { state, deck } = useDeckState();
344
- const node = useNode(graph, id);
345
- const companions = useCompanions(id);
346
- const isLastPlankInMulti =
347
- layoutMode === 'multi' && active && active.length > 0 && active[active.length - 1] === id;
348
- const variantForThisPlank =
349
- layoutMode === 'multi' ? (isLastPlankInMulti ? companionVariant : undefined) : companionVariant;
350
- const { companionId } = useSelectedCompanion(companions, variantForThisPlank);
351
- const resolvedCompanionId =
352
- layoutMode === 'multi' && isLastPlankInMulti && companions.length > 0
353
- ? companionId
354
- : variantForThisPlank
355
- ? companionId
356
- : undefined;
357
- const currentCompanion = companions.find(({ id }) => id === resolvedCompanionId);
358
- const hasCompanion = !!(resolvedCompanionId && currentCompanion);
359
-
360
- const handleAdjust = useCallback(
361
- (plankId: string, type: DeckOperation.PartAdjustment) => {
362
- if (type === 'close') {
363
- if (part === 'complementary') {
364
- return invokePromise(LayoutOperation.UpdateComplementary, { state: 'collapsed' });
365
- } else if (active) {
366
- // Close the plank and everything to the right (stack pop).
367
- const index = active.indexOf(plankId);
368
- const toClose = index !== -1 ? active.slice(index) : [plankId];
369
- return invokePromise(LayoutOperation.Close, { subject: toClose });
370
- } else {
371
- return invokePromise(LayoutOperation.Close, { subject: [plankId] });
372
- }
373
- } else {
374
- return invokePromise(DeckOperation.Adjust, { type, id: plankId });
375
- }
376
- },
377
- [invokePromise, part, active],
378
- );
379
-
380
- const handleResize = useCallback(
381
- (plankId: string, size: number) => invokePromise(DeckOperation.UpdatePlankSize, { id: plankId, size }),
382
- [invokePromise],
383
- );
384
-
385
- const handleScrollIntoView = useCallback(
386
- (subject?: string) => invokePromise(LayoutOperation.ScrollIntoView, { subject }),
387
- [invokePromise],
388
- );
389
-
390
- const handleUpdateCompanion = useCallback(
391
- (companion: string | null) => invokePromise(LayoutOperation.UpdateCompanion, { subject: companion }),
392
- [invokePromise],
393
- );
394
-
395
- return (
396
- <Plank.Root
397
- graph={graph}
398
- layoutMode={layoutMode}
399
- part={part}
400
- settings={settings}
401
- popoverAnchorId={state.popoverAnchorId}
402
- scrollIntoView={state.scrollIntoView}
403
- plankSizing={deck.plankSizing}
404
- onAdjust={handleAdjust}
405
- onResize={handleResize}
406
- onScrollIntoView={handleScrollIntoView}
407
- onUpdateCompanion={handleUpdateCompanion}
408
- >
409
- <Plank.Content solo={part === 'solo'} companion={hasCompanion} encapsulate={!!settings?.encapsulatedPlanks}>
410
- <Plank.Component
411
- {...props}
412
- active={active}
413
- id={id}
414
- node={node}
415
- companioned={hasCompanion ? 'primary' : undefined}
416
- companions={hasCompanion ? [] : companions}
417
- order={order}
418
- {...(part === 'solo'
419
- ? {
420
- part: 'solo-primary',
421
- }
422
- : {
423
- part,
424
- })}
425
- />
426
- {hasCompanion && (
427
- <Plank.Component
428
- {...props}
429
- active={active}
430
- id={resolvedCompanionId}
431
- node={currentCompanion}
432
- companions={companions}
433
- companioned='companion'
434
- primary={node}
435
- {...(part === 'solo'
436
- ? {
437
- order,
438
- part: 'solo-companion',
439
- }
440
- : {
441
- order: (order ?? 0) + 1,
442
- part,
443
- })}
444
- />
445
- )}
446
- </Plank.Content>
447
- </Plank.Root>
448
- );
449
- },
450
- );
@@ -9,18 +9,11 @@ import { LayoutOperation } from '@dxos/app-toolkit';
9
9
  import { ButtonGroup, type ButtonGroupProps, type ButtonProps, IconButton, useTranslation } from '@dxos/react-ui';
10
10
 
11
11
  import { meta } from '#meta';
12
- import { type DeckAction, type LayoutMode } from '#types';
12
+ import { type DeckOperation, type LayoutMode } from '#types';
13
13
 
14
- export type PlankControlHandler = (event: DeckAction.PartAdjustment) => void;
14
+ import { type PlankCapabilities } from './useDeckPlank';
15
15
 
16
- export type PlankCapabilities = {
17
- incrementStart?: boolean;
18
- incrementEnd?: boolean;
19
- deck?: boolean;
20
- solo?: boolean;
21
- fullscreen?: boolean;
22
- companion?: boolean;
23
- };
16
+ export type PlankControlHandler = (event: DeckOperation.PartAdjustment) => void;
24
17
 
25
18
  //
26
19
  // Controls
@@ -34,7 +27,7 @@ export type PlankCompanionControlsProps = {
34
27
 
35
28
  export const PlankCompanionControls = forwardRef<HTMLDivElement, PlankCompanionControlsProps>(
36
29
  ({ primary }, forwardedRef) => {
37
- const { t } = useTranslation(meta.id);
30
+ const { t } = useTranslation(meta.profile.key);
38
31
  const { invokePromise } = useOperationInvoker();
39
32
  const handleCloseCompanion = useCallback(() => {
40
33
  return invokePromise(LayoutOperation.UpdateCompanion, { subject: null });
@@ -78,7 +71,7 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
78
71
  { children, classNames, variant = 'default', capabilities, layoutMode, pin, close = false, onClick, ...props },
79
72
  forwardedRef,
80
73
  ) => {
81
- const { t } = useTranslation(meta.id);
74
+ const { t } = useTranslation(meta.profile.key);
82
75
  const buttonClassNames =
83
76
  variant === 'hide-disabled' ? `disabled:hidden ${plankControlSpacing}` : plankControlSpacing;
84
77
 
@@ -166,13 +159,22 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
166
159
  )}
167
160
 
168
161
  {capabilities.companion && (
169
- <PlankControl
170
- label={t('open-companion.label')}
171
- classNames={buttonClassNames}
172
- data-testid='plankHeading.companion'
173
- icon='ph--square-split-horizontal--regular'
174
- onClick={() => onClick?.('companion')}
175
- />
162
+ <ButtonGroup>
163
+ <PlankControl
164
+ label={t('open-companion.label')}
165
+ classNames={buttonClassNames}
166
+ data-testid='plankHeading.companion'
167
+ icon='ph--square-split-horizontal--regular'
168
+ onClick={() => onClick?.('companion')}
169
+ />
170
+ <PlankControl
171
+ label={t('open-companion-vertical.label')}
172
+ classNames={buttonClassNames}
173
+ data-testid='plankHeading.companion-vertical'
174
+ icon='ph--square-split-vertical--regular'
175
+ onClick={() => onClick?.('companion-vertical')}
176
+ />
177
+ </ButtonGroup>
176
178
  )}
177
179
  {children}
178
180
  </ButtonGroup>
@@ -0,0 +1,42 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React, { useEffect } from 'react';
6
+
7
+ import { log } from '@dxos/log';
8
+ import { ErrorFallback, type ErrorFallbackProps, useTranslation } from '@dxos/react-ui';
9
+ import { descriptionMessage, mx } from '@dxos/ui-theme';
10
+
11
+ import { meta } from '#meta';
12
+
13
+ // TODO(burdon): Show skeleton: https://github.com/dxos/dxos/issues/8259
14
+ export const PlankLoading = () => <div className='grid place-items-center dx-attention-surface' />;
15
+
16
+ /** User-facing error fallback for a plank's content Surface. */
17
+ export const PlankErrorFallback = ({ error }: ErrorFallbackProps) => {
18
+ const { t } = useTranslation(meta.profile.key);
19
+
20
+ useEffect(() => {
21
+ if (error) {
22
+ log.error('plank error', { error });
23
+ }
24
+ }, [error]);
25
+
26
+ if (process.env.NODE_ENV === 'development') {
27
+ return <ErrorFallback title='Plank Error' error={error} />;
28
+ }
29
+
30
+ // Show only a generic message to end users; raw error details stay in logs / the dev fallback above.
31
+ return (
32
+ <div
33
+ role='alert'
34
+ data-testid='plank-content-error'
35
+ className='dx-attention-surface overflow-y-auto p-8 grid place-items-center'
36
+ >
37
+ <div className='flex flex-col items-center gap-2'>
38
+ <p className={mx(descriptionMessage, 'break-all rounded-md p-4')}>{t('error-fallback.message')}</p>
39
+ </div>
40
+ </div>
41
+ );
42
+ };
@@ -7,6 +7,8 @@ import React from 'react';
7
7
  import { Surface } from '@dxos/app-framework/ui';
8
8
  import { useLandmarkMover } from '@dxos/react-ui';
9
9
 
10
+ import { Hints, StatusBar as StatusBarRole } from '#types';
11
+
10
12
  export const StatusBar = ({ showHints }: { showHints?: boolean }) => {
11
13
  const mover = useLandmarkMover(undefined, '3');
12
14
  return (
@@ -15,8 +17,8 @@ export const StatusBar = ({ showHints }: { showHints?: boolean }) => {
15
17
  className='fixed bottom-0 inset-x-0 h-(--dx-statusbar-size) border-y border-separator z-[2] flex text-description'
16
18
  {...mover}
17
19
  >
18
- {showHints && <Surface.Surface role='hints' limit={1} />}
19
- <Surface.Surface role='status-bar' limit={1} />
20
+ {showHints && <Surface.Surface type={Hints} limit={1} />}
21
+ <Surface.Surface type={StatusBarRole} limit={1} />
20
22
  </div>
21
23
  );
22
24
  };