@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
@@ -8,16 +8,16 @@ import React, { useCallback, useMemo, useRef, useState } from 'react';
8
8
  import { Capabilities, Capability, Plugin } from '@dxos/app-framework';
9
9
  import { withPluginManager } from '@dxos/app-framework/testing';
10
10
  import { Surface } from '@dxos/app-framework/ui';
11
- import { Graph } from '@dxos/app-graph';
12
11
  import { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';
12
+ import { AppSurface } from '@dxos/app-toolkit/ui';
13
13
  import { Obj } from '@dxos/echo';
14
+ import { type Node } from '@dxos/plugin-graph';
14
15
  import { corePlugins } from '@dxos/plugin-testing';
15
16
  import { random } from '@dxos/random';
16
17
  import { Focus, Panel, Toolbar } from '@dxos/react-ui';
17
18
  import { useAttentionAttributes } from '@dxos/react-ui-attention';
18
19
  import { withAttention } from '@dxos/react-ui-attention/testing';
19
- import { type MosaicTileProps, Mosaic } from '@dxos/react-ui-mosaic';
20
- import { StackContext } from '@dxos/react-ui-stack';
20
+ import { Mosaic, type MosaicTileProps } from '@dxos/react-ui-mosaic';
21
21
  import { Syntax } from '@dxos/react-ui-syntax-highlighter';
22
22
  import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
23
23
  import { Text } from '@dxos/schema';
@@ -27,7 +27,7 @@ import { DeckState, OperationHandler } from '#capabilities';
27
27
  import { meta as pluginMeta } from '#meta';
28
28
  import { translations } from '#translations';
29
29
 
30
- import { Plank } from '../../containers/Plank';
30
+ import { Plank } from '../Plank';
31
31
  import { Matrix, type MatrixController, type MatrixRootProps } from './Matrix';
32
32
 
33
33
  random.seed(123);
@@ -74,29 +74,17 @@ const StoryTile = (props: MosaicTileProps<Obj.Any>) => {
74
74
  };
75
75
 
76
76
  /**
77
- * Tile that wraps a Plank for content rendering.
77
+ * Tile that renders a node-bound Plank (sigil/title + content Surface).
78
78
  */
79
79
  const PlankTile = (props: MosaicTileProps<Obj.Any>) => {
80
- const graph = useMemo(() => Graph.make(), []);
80
+ const node = useMemo<Node.Node>(
81
+ () => ({ id: props.data.id, type: 'test', data: props.data, properties: { label: Obj.getLabel(props.data) } }),
82
+ [props.data],
83
+ );
81
84
  return (
82
- <StackContext.Provider value={{ orientation: 'horizontal', size: 'contain', rail: true }}>
83
- <Plank.Root layoutMode='multi' part='multi' graph={graph}>
84
- <Mosaic.Tile {...props} asChild>
85
- <Plank.Content solo={false} companion={false} encapsulate={false}>
86
- <Plank.Component
87
- id={props.data.id}
88
- part='multi'
89
- node={{
90
- id: props.data.id,
91
- data: props.data,
92
- type: 'test',
93
- properties: {},
94
- }}
95
- />
96
- </Plank.Content>
97
- </Mosaic.Tile>
98
- </Plank.Root>
99
- </StackContext.Provider>
85
+ <Mosaic.Tile {...props} classNames='w-full md:w-[50rem] shrink-0'>
86
+ <Plank node={node} />
87
+ </Mosaic.Tile>
100
88
  );
101
89
  };
102
90
 
@@ -104,7 +92,7 @@ const TestExtension = Capability.contributes(
104
92
  Capabilities.ReactSurface,
105
93
  Surface.create({
106
94
  id: 'storyArticle',
107
- role: 'article',
95
+ filter: Surface.makeFilter(AppSurface.Article),
108
96
  component: ({ data: { subject } }) => {
109
97
  if (!subject) {
110
98
  return <Loading />;
@@ -123,9 +111,9 @@ const TestExtension = Capability.contributes(
123
111
  }),
124
112
  );
125
113
 
126
- type DefaultStoryProps = Pick<MatrixRootProps, 'Tile'>;
114
+ type StoryArgs = Pick<MatrixRootProps, 'Tile'>;
127
115
 
128
- const DefaultStory = ({ Tile }: DefaultStoryProps) => {
116
+ const DefaultStory = ({ Tile }: StoryArgs) => {
129
117
  const items = useMemo(
130
118
  () => [
131
119
  Organization.make({ name: random.company.name() }),
@@ -4,13 +4,13 @@
4
4
 
5
5
  import { useFocusFinders } from '@fluentui/react-tabster';
6
6
  import { createContext } from '@radix-ui/react-context';
7
- import React, { forwardRef, type PropsWithChildren, useCallback, useEffect, useImperativeHandle, useRef } from 'react';
7
+ import React, { type PropsWithChildren, forwardRef, useCallback, useEffect, useImperativeHandle, useRef } from 'react';
8
8
 
9
9
  import { Obj } from '@dxos/echo';
10
10
  import { ScrollArea } from '@dxos/react-ui';
11
11
  import { composable, composableProps } from '@dxos/react-ui';
12
12
  import { useAttended } from '@dxos/react-ui-attention';
13
- import { type MosaicStackTileComponent, Mosaic } from '@dxos/react-ui-mosaic';
13
+ import { Mosaic, type MosaicStackTileComponent } from '@dxos/react-ui-mosaic';
14
14
  import { type ComposableProps } from '@dxos/ui-types';
15
15
 
16
16
  //
@@ -202,4 +202,4 @@ export const Matrix = {
202
202
  Viewport: MatrixViewport,
203
203
  };
204
204
 
205
- export type { MatrixController, MatrixRootProps, MatrixContentProps, MatrixViewportProps };
205
+ export type { MatrixContentProps, MatrixController, MatrixRootProps, MatrixViewportProps };
@@ -98,7 +98,7 @@ IDs with a `~` prefix on the last segment (e.g., `root/obj/~settings`) mark the
98
98
  - **DeckMain** ensures attention is initialized:
99
99
  - On first render, focuses the first plank's button if nothing is attended.
100
100
  - On mobile breakpoint: reads the currently attended ID to determine which plank to show in solo mode.
101
- - **Keyboard** — `plugin-attention` syncs `Keyboard.singleton.setCurrentContext(id)` with the attended ID, so keyboard shortcuts apply to the attended plank.
101
+ - **Keyboard** — `plugin-attention` syncs `Keyboard.singleton.setCurrentContext(\`root/${id}\`)` with the attended ID, so keyboard shortcuts apply to the attended plank while inheriting root-level bindings.
102
102
 
103
103
  ### Attention vs Focus vs Matrix.current
104
104
 
@@ -3,4 +3,4 @@
3
3
  //
4
4
 
5
5
  export { Matrix } from './Matrix';
6
- export type { MatrixController, MatrixRootProps, MatrixContentProps, MatrixViewportProps } from './Matrix';
6
+ export type { MatrixContentProps, MatrixController, MatrixRootProps, MatrixViewportProps } from './Matrix';
@@ -0,0 +1,92 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { useState } from 'react';
7
+
8
+ import { Icon, IconButton } from '@dxos/react-ui';
9
+ import { useAttentionAttributes } from '@dxos/react-ui-attention';
10
+ import { withAttention } from '@dxos/react-ui-attention/testing';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
+
13
+ import { Pane, type PaneTab } from './Pane';
14
+
15
+ const TABS: PaneTab[] = [
16
+ { id: 'notes', icon: 'ph--note--regular', label: 'Notes' },
17
+ { id: 'chat', icon: 'ph--chat--regular', label: 'Chat' },
18
+ { id: 'links', icon: 'ph--link--regular', label: 'Links' },
19
+ ];
20
+
21
+ // A self-contained main Pane that is its own attendable region (focusing it sets attention, which the
22
+ // sigil and title reflect via the accent color).
23
+ const MainPane = ({ id, label }: { id: string; label: string }) => {
24
+ const attentionAttrs = useAttentionAttributes(id);
25
+ return (
26
+ <Pane.Root tabIndex={0} classNames='flex-1' {...attentionAttrs}>
27
+ <Pane.Toolbar>
28
+ <Pane.Sigil attendableId={id}>
29
+ <Icon icon='ph--circle-dashed--regular' />
30
+ </Pane.Sigil>
31
+ <Pane.Title attendableId={id}>{label}</Pane.Title>
32
+ <IconButton iconOnly variant='ghost' icon='ph--arrows-out--regular' label='Fullscreen' />
33
+ <IconButton iconOnly variant='ghost' icon='ph--x--regular' label='Close' />
34
+ </Pane.Toolbar>
35
+ <Pane.Content classNames='grid place-items-center text-description'>
36
+ <span>{label} content</span>
37
+ </Pane.Content>
38
+ </Pane.Root>
39
+ );
40
+ };
41
+
42
+ // A presentational preview of the solo split: a main Pane beside a companion Pane (tabs + close).
43
+ const SplitStory = () => {
44
+ const [tab, setTab] = useState('notes');
45
+ const activeTab = TABS.find((entry) => entry.id === tab);
46
+ return (
47
+ <div className='w-full grid grid-cols-2 px-3 gap-3 bg-deck-surface'>
48
+ <MainPane id='plank-main' label='Main plank' />
49
+ <Pane.Root>
50
+ <Pane.Toolbar>
51
+ <Pane.Tabs tabs={TABS} value={tab} onValueChange={setTab} attendableId='plank-main' related />
52
+ <IconButton iconOnly variant='ghost' icon='ph--x--regular' label='Close companion' />
53
+ </Pane.Toolbar>
54
+ <Pane.Content classNames='grid place-items-center text-description'>
55
+ <span className='flex items-center gap-1'>
56
+ {activeTab && <Icon icon={activeTab.icon} />}
57
+ {tab}
58
+ </span>
59
+ </Pane.Content>
60
+ </Pane.Root>
61
+ </div>
62
+ );
63
+ };
64
+
65
+ // Two main planks side by side; click either to move attention — only the attended plank's sigil and
66
+ // title take the accent color.
67
+ const TwoPanesStory = () => (
68
+ <div className='w-full flex h-full px-3 gap-3 bg-deck-surface'>
69
+ <MainPane id='plank-a' label='Pane A' />
70
+ <MainPane id='plank-b' label='Pane B' />
71
+ </div>
72
+ );
73
+
74
+ const meta: Meta = {
75
+ title: 'plugins/plugin-deck/components/Pane',
76
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
77
+ parameters: { layout: 'fullscreen' },
78
+ };
79
+
80
+ export default meta;
81
+
82
+ type Story = StoryObj;
83
+
84
+ export const Default: Story = {
85
+ render: () => <SplitStory />,
86
+ decorators: [withAttention('plank-main')],
87
+ };
88
+
89
+ export const Attention: Story = {
90
+ render: () => <TwoPanesStory />,
91
+ decorators: [withAttention('plank-a')],
92
+ };
@@ -0,0 +1,178 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Slot } from '@radix-ui/react-slot';
6
+ import React, { type ComponentPropsWithRef, forwardRef } from 'react';
7
+
8
+ import { AttentionSigilButton } from '@dxos/app-toolkit/ui';
9
+ import { DensityProvider, IconButton, type ThemedClassName, composableProps, slottable } from '@dxos/react-ui';
10
+ import { type AttendableId, type Related, useAttention } from '@dxos/react-ui-attention';
11
+ import { iconSize, mx } from '@dxos/ui-theme';
12
+ import type { Merge } from '@dxos/util';
13
+
14
+ //
15
+ // Pane
16
+ //
17
+ // A presentational, radix-style component for a single deck pane: a toolbar rail above a content body.
18
+ // A plank always has a toolbar, so it implements that layout directly rather than wrapping the
19
+ // generalized `Panel`. A companion pane is just a Pane whose toolbar holds `Pane.Tabs` instead of a
20
+ // sigil/title. Intentionally free of app-framework concepts (capabilities, operations, Surface) —
21
+ // containers compose the sigil, controls, tabs and content surface into the slots.
22
+ //
23
+
24
+ //
25
+ // Root
26
+ //
27
+
28
+ // Root accepts arbitrary div attributes (the container wires tabIndex, data-* and key handlers), so it
29
+ // is a plain forwarding div rather than the narrowly-typed `slottable` used by the toolbar/content slots.
30
+ type PaneRootProps = ThemedClassName<ComponentPropsWithRef<'div'>>;
31
+
32
+ const PaneRoot = forwardRef<HTMLDivElement, PaneRootProps>(({ children, ...props }, forwardedRef) => (
33
+ <div
34
+ {...composableProps(props, {
35
+ role: 'article',
36
+ classNames:
37
+ 'dx-container flex flex-col dx-attention-surface relative dx-focus-ring-inset-over-all dx-density-lg min-w-0',
38
+ })}
39
+ ref={forwardedRef}
40
+ >
41
+ {children}
42
+ </div>
43
+ ));
44
+
45
+ PaneRoot.displayName = 'Pane.Root';
46
+
47
+ //
48
+ // Toolbar
49
+ //
50
+
51
+ const PaneToolbar = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
52
+ const Comp = asChild ? Slot : 'div';
53
+ return (
54
+ <Comp
55
+ {...composableProps(props, {
56
+ style: iconSize(5),
57
+ classNames: 'flex items-center gap-1 px-1 shrink-0 h-(--dx-rail-content) bg-header-surface',
58
+ })}
59
+ ref={forwardedRef}
60
+ >
61
+ <DensityProvider density='lg'>{children}</DensityProvider>
62
+ </Comp>
63
+ );
64
+ });
65
+
66
+ PaneToolbar.displayName = 'Pane.Toolbar';
67
+
68
+ //
69
+ // Content
70
+ //
71
+
72
+ const PaneContent = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
73
+ const Comp = asChild ? Slot : 'div';
74
+ return (
75
+ <Comp {...composableProps(props, { classNames: 'flex-1 min-h-0' })} ref={forwardedRef}>
76
+ {children}
77
+ </Comp>
78
+ );
79
+ });
80
+
81
+ PaneContent.displayName = 'Pane.Content';
82
+
83
+ //
84
+ // Title
85
+ //
86
+
87
+ type PaneTitleProps = ThemedClassName<ComponentPropsWithRef<'h1'>> & AttendableId & Related;
88
+
89
+ /** Attention-aware plank title; colors to the accent when the plank (or a related companion) is attended. */
90
+ const PaneTitle = forwardRef<HTMLHeadingElement, PaneTitleProps>(
91
+ ({ attendableId, related, classNames, ...props }, forwardedRef) => {
92
+ const { hasAttention, isAncestor, isRelated } = useAttention(attendableId);
93
+ return (
94
+ <h1
95
+ {...props}
96
+ data-attention={((related && isRelated) || hasAttention || isAncestor).toString()}
97
+ className={mx(
98
+ 'px-1 min-w-0 w-0 grow truncate font-medium text-base-fg data-[attention=true]:text-accent-text self-center',
99
+ classNames,
100
+ )}
101
+ ref={forwardedRef}
102
+ />
103
+ );
104
+ },
105
+ );
106
+
107
+ PaneTitle.displayName = 'Pane.Title';
108
+
109
+ //
110
+ // Tabs
111
+ //
112
+
113
+ export type PaneTab = {
114
+ id: string;
115
+ icon: string;
116
+ /** Already-localized label. */
117
+ label: string;
118
+ };
119
+
120
+ type PaneTabsProps = Merge<
121
+ ThemedClassName<{
122
+ tabs: ReadonlyArray<PaneTab>;
123
+ value?: string;
124
+ onValueChange?: (id: string) => void;
125
+ /** Collapse inactive tabs to icon-only once the tab count exceeds this. */
126
+ maxTabs?: number;
127
+ }>,
128
+ AttendableId,
129
+ Related
130
+ >;
131
+
132
+ /** Full-height tab strip for a companion plank's toolbar; selects among available companions. */
133
+ const PaneTabs = forwardRef<HTMLDivElement, PaneTabsProps>(
134
+ ({ tabs, value, onValueChange, maxTabs = 5, attendableId, related, classNames }, forwardedRef) => {
135
+ // The active tab only reads as primary when the plank (shared with its companion) is attended.
136
+ const { hasAttention, isAncestor, isRelated } = useAttention(attendableId);
137
+ const attended = (related && isRelated) || hasAttention || isAncestor;
138
+ return (
139
+ <div
140
+ role='tablist'
141
+ className={mx('flex-1 min-w-0 overflow-x-auto scrollbar-none flex items-center gap-1', classNames)}
142
+ ref={forwardedRef}
143
+ >
144
+ {tabs.map(({ id, icon, label }) => (
145
+ <IconButton
146
+ key={id}
147
+ role='tab'
148
+ aria-selected={value === id}
149
+ tabIndex={value === id ? 0 : -1}
150
+ data-id={id}
151
+ icon={icon}
152
+ iconOnly={tabs.length > maxTabs && value !== id}
153
+ label={label}
154
+ variant={value === id && attended ? 'primary' : 'ghost'}
155
+ onClick={() => onValueChange?.(id)}
156
+ />
157
+ ))}
158
+ </div>
159
+ );
160
+ },
161
+ );
162
+
163
+ PaneTabs.displayName = 'Pane.Tabs';
164
+
165
+ //
166
+ // Pane
167
+ //
168
+
169
+ export const Pane = {
170
+ Root: PaneRoot,
171
+ Toolbar: PaneToolbar,
172
+ Sigil: AttentionSigilButton,
173
+ Title: PaneTitle,
174
+ Tabs: PaneTabs,
175
+ Content: PaneContent,
176
+ };
177
+
178
+ export type { PaneRootProps, PaneTabsProps, PaneTitleProps };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './Pane';
@@ -0,0 +1,103 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { useMemo } from 'react';
7
+
8
+ import { Capabilities, Capability, Plugin } from '@dxos/app-framework';
9
+ import { withPluginManager } from '@dxos/app-framework/testing';
10
+ import { Surface } from '@dxos/app-framework/ui';
11
+ import { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';
12
+ import { AppSurface } from '@dxos/app-toolkit/ui';
13
+ import { Obj } from '@dxos/echo';
14
+ import { type Node } from '@dxos/plugin-graph';
15
+ import { corePlugins } from '@dxos/plugin-testing';
16
+ import { random } from '@dxos/random';
17
+ import { withAttention } from '@dxos/react-ui-attention/testing';
18
+ import { Syntax } from '@dxos/react-ui-syntax-highlighter';
19
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
20
+ import { Organization, Person } from '@dxos/types';
21
+
22
+ import { DeckState, OperationHandler } from '#capabilities';
23
+ import { meta as pluginMeta } from '#meta';
24
+ import { translations } from '#translations';
25
+
26
+ import { Plank } from './Plank';
27
+
28
+ random.seed(99);
29
+
30
+ const TestPlugin = Plugin.define(pluginMeta).pipe(
31
+ Plugin.addModule({
32
+ id: Capability.getModuleTag(DeckState),
33
+ activatesOn: AppActivationEvents.AppGraphReady,
34
+ activate: () => DeckState(),
35
+ }),
36
+ AppPlugin.addOperationHandlerModule({
37
+ activate: OperationHandler,
38
+ }),
39
+ Plugin.make,
40
+ );
41
+
42
+ const TestExtension = Capability.contributes(
43
+ Capabilities.ReactSurface,
44
+ Surface.create({
45
+ id: 'storyArticle',
46
+ filter: Surface.makeFilter(AppSurface.Article),
47
+ component: ({ data: { subject } }) =>
48
+ subject ? (
49
+ <Syntax.Root data={subject}>
50
+ <Syntax.Content>
51
+ <Syntax.Viewport>
52
+ <Syntax.Code />
53
+ </Syntax.Viewport>
54
+ </Syntax.Content>
55
+ </Syntax.Root>
56
+ ) : (
57
+ <Loading />
58
+ ),
59
+ }),
60
+ );
61
+
62
+ // A border makes each plank's bounds obvious against the deck surface.
63
+ const PLANK_CLASSNAMES = 'border border-separator';
64
+
65
+ const useNode = (data: Obj.Any, icon: string): Node.Node =>
66
+ useMemo(
67
+ () => ({ id: data.id, type: 'test', data, properties: { label: Obj.getLabel(data) ?? 'Untitled', icon } }),
68
+ [data, icon],
69
+ );
70
+
71
+ // Two planks side by side; focus either to move attention (sigil/title take the accent color).
72
+ const DefaultStory = () => {
73
+ const [organization, person] = useMemo(
74
+ () => [Organization.make({ name: random.company.name() }), Person.make({ fullName: random.person.fullName() })],
75
+ [],
76
+ );
77
+ const organizationNode = useNode(organization, 'ph--building-office--regular');
78
+ const personNode = useNode(person, 'ph--user--regular');
79
+
80
+ return (
81
+ <div className='flex h-full gap-3 p-3 bg-deck-surface'>
82
+ <Plank node={organizationNode} classNames={PLANK_CLASSNAMES} />
83
+ <Plank node={personNode} classNames={PLANK_CLASSNAMES} />
84
+ </div>
85
+ );
86
+ };
87
+
88
+ const meta: Meta = {
89
+ title: 'plugins/plugin-deck/components/Plank',
90
+ decorators: [
91
+ withPluginManager({ plugins: [...corePlugins(), TestPlugin()], capabilities: [TestExtension] }),
92
+ withAttention(),
93
+ withTheme(),
94
+ withLayout({ layout: 'fullscreen' }),
95
+ ],
96
+ parameters: { layout: 'fullscreen', translations },
97
+ };
98
+
99
+ export default meta;
100
+
101
+ type Story = StoryObj;
102
+
103
+ export const Default: Story = { render: () => <DefaultStory /> };
@@ -0,0 +1,149 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React, {
6
+ type ComponentProps,
7
+ Fragment,
8
+ type KeyboardEventHandler,
9
+ type ReactNode,
10
+ forwardRef,
11
+ useMemo,
12
+ } from 'react';
13
+
14
+ import { Surface } from '@dxos/app-framework/ui';
15
+ import { AppSurface, AttentionSigil, type AttentionSigilAction } from '@dxos/app-toolkit/ui';
16
+ import { type Node } from '@dxos/plugin-graph';
17
+ import { Icon, Popover, type ThemedClassName, toLocalizedString, useTranslation } from '@dxos/react-ui';
18
+ import { useAttentionAttributes } from '@dxos/react-ui-attention';
19
+
20
+ import { meta } from '#meta';
21
+
22
+ import { Pane } from '../Pane';
23
+
24
+ type SurfaceProps = ComponentProps<typeof Surface.Surface>;
25
+
26
+ export type PlankProps = ThemedClassName<{
27
+ node: Node.Node;
28
+ /** Attendable id; defaults to the node id. */
29
+ attendableId?: string;
30
+ /** Grouped sigil menu actions; when present the sigil opens a menu, otherwise it is a plain button. */
31
+ actions?: AttentionSigilAction[][];
32
+ onAction?: (action: AttentionSigilAction) => void;
33
+ /** Toolbar controls rendered after the title (e.g. close/solo/fullscreen). */
34
+ controls?: ReactNode;
35
+ /** Toolbar content rendered between the title and the controls (e.g. a NavbarEnd surface). */
36
+ navbarEnd?: ReactNode;
37
+ /** Sigil-menu footer content (e.g. a MenuFooter surface). */
38
+ sigilFooter?: ReactNode;
39
+ /** Highlight the title/sigil when a related (companion) region is attended. */
40
+ related?: boolean;
41
+ /** Render the title in a muted style (e.g. while the subject is loading). */
42
+ pending?: boolean;
43
+ /** When it matches `${meta.key}:${node.id}`, anchors a popover to the sigil. */
44
+ popoverAnchorId?: string;
45
+ /** Extra Article surface data merged over the computed defaults (e.g. companionTo/variant/path). */
46
+ articleData?: Partial<AppSurface.ArticleData>;
47
+ /** Error fallback for the content surface. */
48
+ fallback?: SurfaceProps['fallback'];
49
+ /** Loading placeholder for the content surface. */
50
+ placeholder?: SurfaceProps['placeholder'];
51
+ /** Render only the content surface, omitting the toolbar (e.g. fullscreen). */
52
+ headless?: boolean;
53
+ // TODO(burdon): Why is this required?
54
+ onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
55
+ }>;
56
+
57
+ /**
58
+ * A higher-level deck pane bound to a graph {@link Node}: renders the node's sigil, title and content
59
+ * Surface inside a {@link Pane}, and makes itself the node's attendable region. Toolbar controls
60
+ * (close/solo/etc.) and framework surfaces (NavbarEnd/MenuFooter) are supplied by the container via
61
+ * slots so this component stays free of capabilities/operations.
62
+ */
63
+ export const Plank = forwardRef<HTMLDivElement, PlankProps>(
64
+ (
65
+ {
66
+ classNames,
67
+ node,
68
+ attendableId = node.id,
69
+ actions,
70
+ onAction,
71
+ controls,
72
+ navbarEnd,
73
+ sigilFooter,
74
+ related,
75
+ pending,
76
+ popoverAnchorId,
77
+ articleData,
78
+ fallback,
79
+ placeholder,
80
+ headless,
81
+ onKeyDown,
82
+ },
83
+ forwardedRef,
84
+ ) => {
85
+ const { t } = useTranslation(meta.profile.key);
86
+ const attentionAttrs = useAttentionAttributes(attendableId);
87
+ const icon = node.properties?.icon ?? 'ph--circle-dashed--regular';
88
+ const label = toLocalizedString(node.properties?.label ?? '', t);
89
+ const data = useMemo<AppSurface.ArticleData>(
90
+ () => ({ attendableId, subject: node.data, properties: node.properties, popoverAnchorId, ...articleData }),
91
+ [attendableId, node.data, node.properties, popoverAnchorId, articleData],
92
+ );
93
+
94
+ // Anchor the sigil's popover only when this plank's menu is the active popover target.
95
+ const ActionRoot = popoverAnchorId === `${meta.profile.key}:${node.id}` ? Popover.Anchor : Fragment;
96
+
97
+ return (
98
+ <Pane.Root
99
+ ref={forwardedRef}
100
+ classNames={classNames}
101
+ tabIndex={0}
102
+ onKeyDown={onKeyDown}
103
+ {...attentionAttrs}
104
+ data-testid='deck.plank'
105
+ >
106
+ {!headless && (
107
+ <Pane.Toolbar>
108
+ <ActionRoot>
109
+ {actions && actions.length > 0 ? (
110
+ <AttentionSigil
111
+ icon={icon}
112
+ related={related}
113
+ attendableId={attendableId}
114
+ actions={actions}
115
+ onAction={onAction}
116
+ triggerLabel={label}
117
+ >
118
+ {sigilFooter}
119
+ </AttentionSigil>
120
+ ) : (
121
+ <Pane.Sigil attendableId={attendableId}>
122
+ <span className='sr-only'>{label}</span>
123
+ <Icon icon={icon} />
124
+ </Pane.Sigil>
125
+ )}
126
+ </ActionRoot>
127
+ <Pane.Title attendableId={attendableId} related={related} classNames={pending && 'text-description'}>
128
+ {label}
129
+ </Pane.Title>
130
+ {navbarEnd}
131
+ {controls}
132
+ </Pane.Toolbar>
133
+ )}
134
+ <Pane.Content>
135
+ <Surface.Surface
136
+ key={node.id}
137
+ type={AppSurface.Article}
138
+ data={data}
139
+ limit={1}
140
+ fallback={fallback}
141
+ placeholder={placeholder}
142
+ />
143
+ </Pane.Content>
144
+ </Pane.Root>
145
+ );
146
+ },
147
+ );
148
+
149
+ Plank.displayName = 'Plank';
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './Plank';
@@ -2,8 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type ComponentType, lazy } from 'react';
6
-
7
- export const DeckSettings: ComponentType<any> = lazy(() => import('./DeckSettings'));
8
-
5
+ export { Companion, type CompanionProps } from './Companion';
9
6
  export { Matrix } from './Matrix';
7
+ export { Pane, type PaneTab } from './Pane';
8
+ export { Plank, type PlankProps } from './Plank';