@dxos/plugin-deck 0.8.4-main.ead640a → 0.8.4-main.effb148878

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 (502) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/neutral/DeckLayout-NBVPPAQP.mjs +278 -0
  4. package/dist/lib/neutral/DeckLayout-NBVPPAQP.mjs.map +7 -0
  5. package/dist/lib/neutral/DeckPlugin.mjs +70 -0
  6. package/dist/lib/neutral/DeckPlugin.mjs.map +7 -0
  7. package/dist/lib/neutral/DeckPlugin.node.mjs +18 -0
  8. package/dist/lib/neutral/DeckPlugin.node.mjs.map +7 -0
  9. package/dist/lib/neutral/DeckPlugin.workerd.mjs +16 -0
  10. package/dist/lib/neutral/DeckPlugin.workerd.mjs.map +7 -0
  11. package/dist/lib/neutral/DeckSettings-W5I57OXM.mjs +27 -0
  12. package/dist/lib/neutral/DeckSettings-W5I57OXM.mjs.map +7 -0
  13. package/dist/lib/neutral/add-toast-H2PK2S3H.mjs +24 -0
  14. package/dist/lib/neutral/add-toast-H2PK2S3H.mjs.map +7 -0
  15. package/dist/lib/neutral/adjust-J6ZPQ5BT.mjs +93 -0
  16. package/dist/lib/neutral/adjust-J6ZPQ5BT.mjs.map +7 -0
  17. package/dist/lib/neutral/app-graph-builder-MRA3OMKO.mjs +129 -0
  18. package/dist/lib/neutral/app-graph-builder-MRA3OMKO.mjs.map +7 -0
  19. package/dist/lib/neutral/capabilities/index.mjs +23 -0
  20. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  21. package/dist/lib/neutral/check-app-scheme-A7FZVNZO.mjs +10 -0
  22. package/dist/lib/neutral/chunk-3WIBNTUT.mjs +35 -0
  23. package/dist/lib/neutral/chunk-3WIBNTUT.mjs.map +7 -0
  24. package/dist/lib/neutral/chunk-FBN443XP.mjs +8 -0
  25. package/dist/lib/neutral/chunk-FBN443XP.mjs.map +7 -0
  26. package/dist/lib/neutral/chunk-FSIEKCMR.mjs +1305 -0
  27. package/dist/lib/neutral/chunk-FSIEKCMR.mjs.map +7 -0
  28. package/dist/lib/neutral/chunk-GBIGQKYW.mjs +112 -0
  29. package/dist/lib/neutral/chunk-GBIGQKYW.mjs.map +7 -0
  30. package/dist/lib/neutral/chunk-GLB73Q6U.mjs +22 -0
  31. package/dist/lib/neutral/chunk-GLB73Q6U.mjs.map +7 -0
  32. package/dist/lib/neutral/chunk-HD44H4CJ.mjs +280 -0
  33. package/dist/lib/neutral/chunk-HD44H4CJ.mjs.map +7 -0
  34. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  35. package/dist/lib/neutral/chunk-VHETZ22W.mjs +101 -0
  36. package/dist/lib/neutral/chunk-VHETZ22W.mjs.map +7 -0
  37. package/dist/lib/neutral/chunk-ZYYOSX5I.mjs +69 -0
  38. package/dist/lib/neutral/chunk-ZYYOSX5I.mjs.map +7 -0
  39. package/dist/lib/neutral/close-IPQTWQXS.mjs +44 -0
  40. package/dist/lib/neutral/close-IPQTWQXS.mjs.map +7 -0
  41. package/dist/lib/neutral/components/index.mjs +126 -0
  42. package/dist/lib/neutral/components/index.mjs.map +7 -0
  43. package/dist/lib/neutral/containers/index.mjs +32 -0
  44. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  45. package/dist/lib/neutral/hooks/index.mjs +159 -0
  46. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  47. package/dist/lib/neutral/index.mjs +38 -0
  48. package/dist/lib/neutral/index.mjs.map +7 -0
  49. package/dist/lib/neutral/meta.json +1 -0
  50. package/dist/lib/neutral/meta.mjs +8 -0
  51. package/dist/lib/neutral/meta.mjs.map +7 -0
  52. package/dist/lib/neutral/open-OAKTKZM2.mjs +149 -0
  53. package/dist/lib/neutral/open-OAKTKZM2.mjs.map +7 -0
  54. package/dist/lib/neutral/operation-handler-266CVMTW.mjs +13 -0
  55. package/dist/lib/neutral/operation-handler-266CVMTW.mjs.map +7 -0
  56. package/dist/lib/neutral/operations/index.mjs +8 -0
  57. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  58. package/dist/lib/neutral/plugin.mjs +16 -0
  59. package/dist/lib/neutral/plugin.mjs.map +7 -0
  60. package/dist/lib/neutral/react-root-WZ6KH27J.mjs +41 -0
  61. package/dist/lib/neutral/react-root-WZ6KH27J.mjs.map +7 -0
  62. package/dist/lib/neutral/react-surface-KAAZDHV3.mjs +34 -0
  63. package/dist/lib/neutral/react-surface-KAAZDHV3.mjs.map +7 -0
  64. package/dist/lib/neutral/revert-workspace-PLY4YQ4X.mjs +21 -0
  65. package/dist/lib/neutral/revert-workspace-PLY4YQ4X.mjs.map +7 -0
  66. package/dist/lib/neutral/scroll-into-view-INJL3YOV.mjs +21 -0
  67. package/dist/lib/neutral/scroll-into-view-INJL3YOV.mjs.map +7 -0
  68. package/dist/lib/neutral/set-CQ6AO7QB.mjs +37 -0
  69. package/dist/lib/neutral/set-CQ6AO7QB.mjs.map +7 -0
  70. package/dist/lib/neutral/set-layout-mode-NBPJRYGC.mjs +85 -0
  71. package/dist/lib/neutral/set-layout-mode-NBPJRYGC.mjs.map +7 -0
  72. package/dist/lib/neutral/settings-EGNYUM4T.mjs +33 -0
  73. package/dist/lib/neutral/settings-EGNYUM4T.mjs.map +7 -0
  74. package/dist/lib/neutral/show-undo-EZH7JPAV.mjs +59 -0
  75. package/dist/lib/neutral/show-undo-EZH7JPAV.mjs.map +7 -0
  76. package/dist/lib/neutral/state-IIDXMQUO.mjs +86 -0
  77. package/dist/lib/neutral/state-IIDXMQUO.mjs.map +7 -0
  78. package/dist/lib/neutral/switch-workspace-UCFFW3B6.mjs +60 -0
  79. package/dist/lib/neutral/switch-workspace-UCFFW3B6.mjs.map +7 -0
  80. package/dist/lib/neutral/translations.mjs +58 -0
  81. package/dist/lib/neutral/translations.mjs.map +7 -0
  82. package/dist/lib/neutral/types/index.mjs +34 -0
  83. package/dist/lib/neutral/types/index.mjs.map +7 -0
  84. package/dist/lib/neutral/update-companion-NCPRS5MP.mjs +32 -0
  85. package/dist/lib/neutral/update-companion-NCPRS5MP.mjs.map +7 -0
  86. package/dist/lib/neutral/update-complementary-4RERA3VA.mjs +28 -0
  87. package/dist/lib/neutral/update-complementary-4RERA3VA.mjs.map +7 -0
  88. package/dist/lib/neutral/update-dialog-GMFMY7KZ.mjs +29 -0
  89. package/dist/lib/neutral/update-dialog-GMFMY7KZ.mjs.map +7 -0
  90. package/dist/lib/neutral/update-plank-size-TO7RMHQM.mjs +26 -0
  91. package/dist/lib/neutral/update-plank-size-TO7RMHQM.mjs.map +7 -0
  92. package/dist/lib/neutral/update-popover-H3KBQQZ4.mjs +33 -0
  93. package/dist/lib/neutral/update-popover-H3KBQQZ4.mjs.map +7 -0
  94. package/dist/lib/neutral/update-sidebar-OM7EGDQR.mjs +25 -0
  95. package/dist/lib/neutral/update-sidebar-OM7EGDQR.mjs.map +7 -0
  96. package/dist/lib/neutral/url-handler-3QTKEM2K.mjs +184 -0
  97. package/dist/lib/neutral/url-handler-3QTKEM2K.mjs.map +7 -0
  98. package/dist/types/src/DeckPlugin.d.ts +3 -1
  99. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  100. package/dist/types/src/DeckPlugin.node.d.ts +4 -0
  101. package/dist/types/src/DeckPlugin.node.d.ts.map +1 -0
  102. package/dist/types/src/DeckPlugin.test.d.ts +2 -0
  103. package/dist/types/src/DeckPlugin.test.d.ts.map +1 -0
  104. package/dist/types/src/DeckPlugin.workerd.d.ts +4 -0
  105. package/dist/types/src/DeckPlugin.workerd.d.ts.map +1 -0
  106. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  107. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  108. package/dist/types/src/capabilities/check-app-scheme.d.ts +17 -2
  109. package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -1
  110. package/dist/types/src/capabilities/index.d.ts +196 -12
  111. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  112. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  113. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  114. package/dist/types/src/capabilities/react-root.d.ts +4 -2
  115. package/dist/types/src/capabilities/react-root.d.ts.map +1 -1
  116. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  117. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  118. package/dist/types/src/capabilities/settings.d.ts +5 -2
  119. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  120. package/dist/types/src/capabilities/state.d.ts +136 -49
  121. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  122. package/dist/types/src/capabilities/tools.d.ts +4 -3
  123. package/dist/types/src/capabilities/tools.d.ts.map +1 -1
  124. package/dist/types/src/capabilities/url-handler.d.ts +3 -2
  125. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -1
  126. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts +4 -4
  127. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts.map +1 -1
  128. package/dist/types/src/components/DeckSettings/DeckSettings.stories.d.ts +62 -0
  129. package/dist/types/src/components/DeckSettings/DeckSettings.stories.d.ts.map +1 -0
  130. package/dist/types/src/components/DeckSettings/index.d.ts +1 -1
  131. package/dist/types/src/components/DeckSettings/index.d.ts.map +1 -1
  132. package/dist/types/src/components/Matrix/Matrix.d.ts +41 -0
  133. package/dist/types/src/components/Matrix/Matrix.d.ts.map +1 -0
  134. package/dist/types/src/components/Matrix/Matrix.stories.d.ts +17 -0
  135. package/dist/types/src/components/Matrix/Matrix.stories.d.ts.map +1 -0
  136. package/dist/types/src/components/Matrix/index.d.ts +3 -0
  137. package/dist/types/src/components/Matrix/index.d.ts.map +1 -0
  138. package/dist/types/src/components/index.d.ts +3 -2
  139. package/dist/types/src/components/index.d.ts.map +1 -1
  140. package/dist/types/src/{components/DeckLayout → containers/Deck}/Banner.d.ts +1 -1
  141. package/dist/types/src/containers/Deck/Banner.d.ts.map +1 -0
  142. package/dist/types/src/containers/Deck/Deck.d.ts +25 -0
  143. package/dist/types/src/containers/Deck/Deck.d.ts.map +1 -0
  144. package/dist/types/src/containers/Deck/Deck.stories.d.ts +62 -0
  145. package/dist/types/src/containers/Deck/Deck.stories.d.ts.map +1 -0
  146. package/dist/types/src/containers/Deck/DeckContent.d.ts +7 -0
  147. package/dist/types/src/containers/Deck/DeckContent.d.ts.map +1 -0
  148. package/dist/types/src/containers/Deck/DeckRoot.d.ts +39 -0
  149. package/dist/types/src/containers/Deck/DeckRoot.d.ts.map +1 -0
  150. package/dist/types/src/containers/Deck/DeckViewport.d.ts +16 -0
  151. package/dist/types/src/containers/Deck/DeckViewport.d.ts.map +1 -0
  152. package/dist/types/src/containers/Deck/StatusBar.d.ts.map +1 -0
  153. package/dist/types/src/containers/Deck/index.d.ts +2 -0
  154. package/dist/types/src/containers/Deck/index.d.ts.map +1 -0
  155. package/dist/types/src/containers/DeckLayout/ActiveNode.d.ts.map +1 -0
  156. package/dist/types/src/containers/DeckLayout/DeckLayout.d.ts.map +1 -0
  157. package/dist/types/src/containers/DeckLayout/DeckLayout.stories.d.ts +64 -0
  158. package/dist/types/src/containers/DeckLayout/DeckLayout.stories.d.ts.map +1 -0
  159. package/dist/types/src/containers/DeckLayout/Dialog.d.ts.map +1 -0
  160. package/dist/types/src/containers/DeckLayout/Fallback.d.ts +2 -0
  161. package/dist/types/src/containers/DeckLayout/Fallback.d.ts.map +1 -0
  162. package/dist/types/src/containers/DeckLayout/Popover.d.ts +5 -0
  163. package/dist/types/src/containers/DeckLayout/Popover.d.ts.map +1 -0
  164. package/dist/types/src/{components → containers}/DeckLayout/Toast.d.ts +3 -3
  165. package/dist/types/src/containers/DeckLayout/Toast.d.ts.map +1 -0
  166. package/dist/types/src/containers/DeckLayout/constants.d.ts.map +1 -0
  167. package/dist/types/src/containers/DeckLayout/index.d.ts +4 -0
  168. package/dist/types/src/containers/DeckLayout/index.d.ts.map +1 -0
  169. package/dist/types/src/containers/Plank/Plank.d.ts +17 -0
  170. package/dist/types/src/containers/Plank/Plank.d.ts.map +1 -0
  171. package/dist/types/src/containers/Plank/Plank.stories.d.ts +62 -0
  172. package/dist/types/src/containers/Plank/Plank.stories.d.ts.map +1 -0
  173. package/dist/types/src/containers/Plank/PlankComponent.d.ts +17 -0
  174. package/dist/types/src/containers/Plank/PlankComponent.d.ts.map +1 -0
  175. package/dist/types/src/containers/Plank/PlankContent.d.ts +10 -0
  176. package/dist/types/src/containers/Plank/PlankContent.d.ts.map +1 -0
  177. package/dist/types/src/{components → containers}/Plank/PlankControls.d.ts +5 -6
  178. package/dist/types/src/containers/Plank/PlankControls.d.ts.map +1 -0
  179. package/dist/types/src/containers/Plank/PlankError.d.ts +15 -0
  180. package/dist/types/src/containers/Plank/PlankError.d.ts.map +1 -0
  181. package/dist/types/src/{components → containers}/Plank/PlankHeading.d.ts +5 -4
  182. package/dist/types/src/containers/Plank/PlankHeading.d.ts.map +1 -0
  183. package/dist/types/src/{components → containers}/Plank/PlankLoading.d.ts.map +1 -1
  184. package/dist/types/src/containers/Plank/PlankRoot.d.ts +37 -0
  185. package/dist/types/src/containers/Plank/PlankRoot.d.ts.map +1 -0
  186. package/dist/types/src/containers/Plank/index.d.ts +4 -0
  187. package/dist/types/src/containers/Plank/index.d.ts.map +1 -0
  188. package/dist/types/src/containers/Sidebar/ComplementarySidebar.d.ts.map +1 -0
  189. package/dist/types/src/containers/Sidebar/Sidebar.d.ts.map +1 -0
  190. package/dist/types/src/{components → containers}/Sidebar/SidebarButton.d.ts +1 -1
  191. package/dist/types/src/containers/Sidebar/SidebarButton.d.ts.map +1 -0
  192. package/dist/types/src/{components → containers}/Sidebar/index.d.ts.map +1 -1
  193. package/dist/types/src/containers/index.d.ts +6 -0
  194. package/dist/types/src/containers/index.d.ts.map +1 -0
  195. package/dist/types/src/hooks/index.d.ts +2 -1
  196. package/dist/types/src/hooks/index.d.ts.map +1 -1
  197. package/dist/types/src/hooks/useBreakpoints.d.ts +1 -1
  198. package/dist/types/src/hooks/useCompanions.d.ts.map +1 -1
  199. package/dist/types/src/hooks/useDeckCompanions.d.ts +4 -4
  200. package/dist/types/src/hooks/useDeckCompanions.d.ts.map +1 -1
  201. package/dist/types/src/hooks/useDeckState.d.ts +17 -0
  202. package/dist/types/src/hooks/useDeckState.d.ts.map +1 -0
  203. package/dist/types/src/hooks/useMainSize.d.ts +2 -2
  204. package/dist/types/src/hooks/useMainSize.d.ts.map +1 -1
  205. package/dist/types/src/hooks/useNodeActionExpander.d.ts +1 -1
  206. package/dist/types/src/hooks/useNodeActionExpander.d.ts.map +1 -1
  207. package/dist/types/src/hooks/useSelectedCompanion.d.ts +13 -0
  208. package/dist/types/src/hooks/useSelectedCompanion.d.ts.map +1 -0
  209. package/dist/types/src/index.d.ts +1 -4
  210. package/dist/types/src/index.d.ts.map +1 -1
  211. package/dist/types/src/layout.d.ts +20 -9
  212. package/dist/types/src/layout.d.ts.map +1 -1
  213. package/dist/types/src/layout.test.d.ts +2 -0
  214. package/dist/types/src/layout.test.d.ts.map +1 -0
  215. package/dist/types/src/meta.d.ts +2 -2
  216. package/dist/types/src/meta.d.ts.map +1 -1
  217. package/dist/types/src/operations/add-toast.d.ts +5 -0
  218. package/dist/types/src/operations/add-toast.d.ts.map +1 -0
  219. package/dist/types/src/operations/adjust.d.ts +5 -0
  220. package/dist/types/src/operations/adjust.d.ts.map +1 -0
  221. package/dist/types/src/operations/close.d.ts +5 -0
  222. package/dist/types/src/operations/close.d.ts.map +1 -0
  223. package/dist/types/src/operations/helpers.d.ts +3 -0
  224. package/dist/types/src/operations/helpers.d.ts.map +1 -0
  225. package/dist/types/src/operations/index.d.ts +3 -0
  226. package/dist/types/src/operations/index.d.ts.map +1 -0
  227. package/dist/types/src/operations/open.d.ts +5 -0
  228. package/dist/types/src/operations/open.d.ts.map +1 -0
  229. package/dist/types/src/operations/revert-workspace.d.ts +5 -0
  230. package/dist/types/src/operations/revert-workspace.d.ts.map +1 -0
  231. package/dist/types/src/operations/scroll-into-view.d.ts +5 -0
  232. package/dist/types/src/operations/scroll-into-view.d.ts.map +1 -0
  233. package/dist/types/src/operations/set-layout-mode.d.ts +9 -0
  234. package/dist/types/src/operations/set-layout-mode.d.ts.map +1 -0
  235. package/dist/types/src/operations/set.d.ts +5 -0
  236. package/dist/types/src/operations/set.d.ts.map +1 -0
  237. package/dist/types/src/operations/show-undo.d.ts +5 -0
  238. package/dist/types/src/operations/show-undo.d.ts.map +1 -0
  239. package/dist/types/src/operations/switch-workspace.d.ts +5 -0
  240. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -0
  241. package/dist/types/src/operations/update-companion.d.ts +5 -0
  242. package/dist/types/src/operations/update-companion.d.ts.map +1 -0
  243. package/dist/types/src/operations/update-complementary.d.ts +5 -0
  244. package/dist/types/src/operations/update-complementary.d.ts.map +1 -0
  245. package/dist/types/src/operations/update-dialog.d.ts +5 -0
  246. package/dist/types/src/operations/update-dialog.d.ts.map +1 -0
  247. package/dist/types/src/operations/update-plank-size.d.ts +5 -0
  248. package/dist/types/src/operations/update-plank-size.d.ts.map +1 -0
  249. package/dist/types/src/operations/update-popover.d.ts +5 -0
  250. package/dist/types/src/operations/update-popover.d.ts.map +1 -0
  251. package/dist/types/src/operations/update-sidebar.d.ts +5 -0
  252. package/dist/types/src/operations/update-sidebar.d.ts.map +1 -0
  253. package/dist/types/src/plugin.d.ts +4 -0
  254. package/dist/types/src/plugin.d.ts.map +1 -0
  255. package/dist/types/src/translations.d.ts +43 -55
  256. package/dist/types/src/translations.d.ts.map +1 -1
  257. package/dist/types/src/types/DeckCapabilities.d.ts +188 -0
  258. package/dist/types/src/types/DeckCapabilities.d.ts.map +1 -0
  259. package/dist/types/src/types/DeckEvents.d.ts +5 -0
  260. package/dist/types/src/types/DeckEvents.d.ts.map +1 -0
  261. package/dist/types/src/types/DeckOperation.d.ts +15 -0
  262. package/dist/types/src/types/DeckOperation.d.ts.map +1 -0
  263. package/dist/types/src/types/Settings.d.ts +10 -0
  264. package/dist/types/src/types/Settings.d.ts.map +1 -0
  265. package/dist/types/src/types/index.d.ts +4 -0
  266. package/dist/types/src/types/index.d.ts.map +1 -1
  267. package/dist/types/src/types/schema.d.ts +64 -64
  268. package/dist/types/src/types/schema.d.ts.map +1 -1
  269. package/dist/types/src/util/index.d.ts +2 -1
  270. package/dist/types/src/util/index.d.ts.map +1 -1
  271. package/dist/types/src/util/layoutAppliesTopbar.d.ts +1 -1
  272. package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -1
  273. package/dist/types/src/util/plank-url-params.d.ts +14 -0
  274. package/dist/types/src/util/plank-url-params.d.ts.map +1 -0
  275. package/dist/types/src/util/plank-url-params.test.d.ts +2 -0
  276. package/dist/types/src/util/plank-url-params.test.d.ts.map +1 -0
  277. package/dist/types/src/util/sanitize-persisted-state.d.ts +19 -0
  278. package/dist/types/src/util/sanitize-persisted-state.d.ts.map +1 -0
  279. package/dist/types/src/util/sanitize-persisted-state.test.d.ts +2 -0
  280. package/dist/types/src/util/sanitize-persisted-state.test.d.ts.map +1 -0
  281. package/dist/types/src/util/set-active.d.ts +19 -4
  282. package/dist/types/src/util/set-active.d.ts.map +1 -1
  283. package/dist/types/src/util/set-active.test.d.ts +2 -0
  284. package/dist/types/src/util/set-active.test.d.ts.map +1 -0
  285. package/dist/types/tsconfig.tsbuildinfo +1 -1
  286. package/package.json +130 -61
  287. package/src/DeckPlugin.node.ts +17 -0
  288. package/src/DeckPlugin.test.ts +27 -0
  289. package/src/DeckPlugin.ts +32 -56
  290. package/src/DeckPlugin.workerd.ts +16 -0
  291. package/src/capabilities/app-graph-builder.ts +111 -127
  292. package/src/capabilities/check-app-scheme.ts +123 -24
  293. package/src/capabilities/index.ts +13 -14
  294. package/src/capabilities/operation-handler.ts +16 -0
  295. package/src/capabilities/react-root.tsx +37 -29
  296. package/src/capabilities/react-surface.tsx +28 -22
  297. package/src/capabilities/settings.ts +29 -20
  298. package/src/capabilities/state.ts +74 -91
  299. package/src/capabilities/tools.ts +57 -50
  300. package/src/capabilities/url-handler.ts +221 -50
  301. package/src/components/DeckSettings/DeckSettings.stories.tsx +37 -0
  302. package/src/components/DeckSettings/DeckSettings.tsx +19 -88
  303. package/src/components/DeckSettings/index.ts +2 -2
  304. package/src/components/Matrix/Matrix.stories.tsx +220 -0
  305. package/src/components/Matrix/Matrix.tsx +205 -0
  306. package/src/components/Matrix/SPEC.md +219 -0
  307. package/src/components/Matrix/index.ts +6 -0
  308. package/src/components/index.ts +6 -3
  309. package/src/containers/Deck/Banner.tsx +41 -0
  310. package/src/containers/Deck/Deck.stories.tsx +81 -0
  311. package/src/containers/Deck/Deck.tsx +21 -0
  312. package/src/containers/Deck/DeckContent.tsx +102 -0
  313. package/src/containers/Deck/DeckRoot.tsx +50 -0
  314. package/src/containers/Deck/DeckViewport.tsx +450 -0
  315. package/src/{components/DeckLayout → containers/Deck}/StatusBar.tsx +4 -4
  316. package/src/containers/Deck/index.ts +5 -0
  317. package/src/{components → containers}/DeckLayout/ActiveNode.tsx +9 -4
  318. package/src/containers/DeckLayout/DeckLayout.stories.tsx +395 -0
  319. package/src/containers/DeckLayout/DeckLayout.tsx +62 -0
  320. package/src/containers/DeckLayout/Dialog.tsx +52 -0
  321. package/src/containers/DeckLayout/Fallback.tsx +24 -0
  322. package/src/containers/DeckLayout/Popover.tsx +162 -0
  323. package/src/{components → containers}/DeckLayout/Toast.tsx +6 -6
  324. package/src/{components → containers}/DeckLayout/constants.ts +1 -0
  325. package/src/{components → containers}/DeckLayout/index.ts +3 -2
  326. package/src/containers/Plank/Plank.stories.tsx +108 -0
  327. package/src/containers/Plank/Plank.tsx +22 -0
  328. package/src/containers/Plank/PlankComponent.tsx +218 -0
  329. package/src/containers/Plank/PlankContent.tsx +45 -0
  330. package/src/{components → containers}/Plank/PlankControls.tsx +43 -36
  331. package/src/containers/Plank/PlankError.tsx +82 -0
  332. package/src/{components → containers}/Plank/PlankHeading.tsx +68 -64
  333. package/src/{components → containers}/Plank/PlankLoading.tsx +1 -1
  334. package/src/containers/Plank/PlankRoot.tsx +49 -0
  335. package/src/{components → containers}/Plank/index.ts +0 -2
  336. package/src/containers/Sidebar/ComplementarySidebar.tsx +192 -0
  337. package/src/containers/Sidebar/Sidebar.tsx +39 -0
  338. package/src/containers/Sidebar/SidebarButton.tsx +100 -0
  339. package/src/containers/index.ts +11 -0
  340. package/src/hooks/index.ts +2 -1
  341. package/src/hooks/useCompanions.ts +3 -3
  342. package/src/hooks/useDeckCompanions.ts +8 -10
  343. package/src/hooks/useDeckState.ts +73 -0
  344. package/src/hooks/useMainSize.ts +2 -2
  345. package/src/hooks/useNodeActionExpander.ts +4 -4
  346. package/src/hooks/useSelectedCompanion.ts +32 -0
  347. package/src/index.ts +1 -4
  348. package/src/layout.test.ts +59 -0
  349. package/src/layout.ts +38 -40
  350. package/src/meta.ts +25 -3
  351. package/src/operations/add-toast.ts +24 -0
  352. package/src/operations/adjust.ts +82 -0
  353. package/src/operations/close.ts +35 -0
  354. package/src/operations/helpers.ts +22 -0
  355. package/src/operations/index.ts +24 -0
  356. package/src/operations/open.ts +186 -0
  357. package/src/operations/revert-workspace.ts +22 -0
  358. package/src/operations/scroll-into-view.ts +24 -0
  359. package/src/operations/set-layout-mode.ts +84 -0
  360. package/src/operations/set.ts +36 -0
  361. package/src/operations/show-undo.ts +47 -0
  362. package/src/operations/switch-workspace.ts +66 -0
  363. package/src/operations/update-companion.ts +35 -0
  364. package/src/operations/update-complementary.ts +33 -0
  365. package/src/operations/update-dialog.ts +34 -0
  366. package/src/operations/update-plank-size.ts +28 -0
  367. package/src/operations/update-popover.ts +36 -0
  368. package/src/operations/update-sidebar.ts +28 -0
  369. package/src/plugin.ts +11 -0
  370. package/src/translations.ts +43 -54
  371. package/src/types/DeckCapabilities.ts +34 -0
  372. package/src/types/DeckEvents.ts +21 -0
  373. package/src/types/DeckOperation.ts +53 -0
  374. package/src/types/Settings.ts +36 -0
  375. package/src/types/index.ts +5 -0
  376. package/src/types/schema.ts +49 -58
  377. package/src/util/index.ts +2 -1
  378. package/src/util/layoutAppliesTopbar.ts +2 -2
  379. package/src/util/plank-url-params.test.ts +85 -0
  380. package/src/util/plank-url-params.ts +36 -0
  381. package/src/util/sanitize-persisted-state.test.ts +79 -0
  382. package/src/util/sanitize-persisted-state.ts +52 -0
  383. package/src/util/set-active.test.ts +106 -0
  384. package/src/util/set-active.ts +50 -30
  385. package/src/vite-env.d.ts +5 -0
  386. package/dist/lib/browser/app-graph-builder-YYP67JHW.mjs +0 -153
  387. package/dist/lib/browser/app-graph-builder-YYP67JHW.mjs.map +0 -7
  388. package/dist/lib/browser/check-app-scheme-GCOL6YDT.mjs +0 -32
  389. package/dist/lib/browser/check-app-scheme-GCOL6YDT.mjs.map +0 -7
  390. package/dist/lib/browser/chunk-7I6H3N4Q.mjs +0 -162
  391. package/dist/lib/browser/chunk-7I6H3N4Q.mjs.map +0 -7
  392. package/dist/lib/browser/chunk-CNTGBCMK.mjs +0 -145
  393. package/dist/lib/browser/chunk-CNTGBCMK.mjs.map +0 -7
  394. package/dist/lib/browser/chunk-HUWUYTOI.mjs +0 -16
  395. package/dist/lib/browser/chunk-HUWUYTOI.mjs.map +0 -7
  396. package/dist/lib/browser/chunk-JQKOS2HB.mjs +0 -1531
  397. package/dist/lib/browser/chunk-JQKOS2HB.mjs.map +0 -7
  398. package/dist/lib/browser/chunk-MHP4GPX5.mjs +0 -11
  399. package/dist/lib/browser/chunk-MHP4GPX5.mjs.map +0 -7
  400. package/dist/lib/browser/chunk-RJP5R7PY.mjs +0 -127
  401. package/dist/lib/browser/chunk-RJP5R7PY.mjs.map +0 -7
  402. package/dist/lib/browser/chunk-VX7MMQOW.mjs +0 -129
  403. package/dist/lib/browser/chunk-VX7MMQOW.mjs.map +0 -7
  404. package/dist/lib/browser/index.mjs +0 -174
  405. package/dist/lib/browser/index.mjs.map +0 -7
  406. package/dist/lib/browser/intent-resolver-7XNOEPVN.mjs +0 -524
  407. package/dist/lib/browser/intent-resolver-7XNOEPVN.mjs.map +0 -7
  408. package/dist/lib/browser/meta.json +0 -1
  409. package/dist/lib/browser/react-root-OJEF7YCH.mjs +0 -43
  410. package/dist/lib/browser/react-root-OJEF7YCH.mjs.map +0 -7
  411. package/dist/lib/browser/react-surface-XN2NJYHO.mjs +0 -40
  412. package/dist/lib/browser/react-surface-XN2NJYHO.mjs.map +0 -7
  413. package/dist/lib/browser/settings-M3KSKRAP.mjs +0 -30
  414. package/dist/lib/browser/settings-M3KSKRAP.mjs.map +0 -7
  415. package/dist/lib/browser/state-6ZSDTF6Q.mjs +0 -12
  416. package/dist/lib/browser/toolkit-L7C3UAEU.mjs +0 -63
  417. package/dist/lib/browser/toolkit-L7C3UAEU.mjs.map +0 -7
  418. package/dist/lib/browser/types/index.mjs +0 -32
  419. package/dist/lib/browser/url-handler-EHTLXZRR.mjs +0 -70
  420. package/dist/lib/browser/url-handler-EHTLXZRR.mjs.map +0 -7
  421. package/dist/types/src/capabilities/capabilities.d.ts +0 -184
  422. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  423. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  424. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  425. package/dist/types/src/capabilities/toolkit.d.ts +0 -6
  426. package/dist/types/src/capabilities/toolkit.d.ts.map +0 -1
  427. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +0 -1
  428. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +0 -1
  429. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts +0 -3
  430. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +0 -1
  431. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +0 -1
  432. package/dist/types/src/components/DeckLayout/DeckLayout.stories.d.ts +0 -74
  433. package/dist/types/src/components/DeckLayout/DeckLayout.stories.d.ts.map +0 -1
  434. package/dist/types/src/components/DeckLayout/DeckMain.d.ts +0 -3
  435. package/dist/types/src/components/DeckLayout/DeckMain.d.ts.map +0 -1
  436. package/dist/types/src/components/DeckLayout/Dialog.d.ts.map +0 -1
  437. package/dist/types/src/components/DeckLayout/Fallback.d.ts +0 -3
  438. package/dist/types/src/components/DeckLayout/Fallback.d.ts.map +0 -1
  439. package/dist/types/src/components/DeckLayout/Popover.d.ts +0 -5
  440. package/dist/types/src/components/DeckLayout/Popover.d.ts.map +0 -1
  441. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +0 -1
  442. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +0 -1
  443. package/dist/types/src/components/DeckLayout/Topbar.d.ts +0 -3
  444. package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +0 -1
  445. package/dist/types/src/components/DeckLayout/constants.d.ts.map +0 -1
  446. package/dist/types/src/components/DeckLayout/index.d.ts +0 -4
  447. package/dist/types/src/components/DeckLayout/index.d.ts.map +0 -1
  448. package/dist/types/src/components/Plank/Plank.d.ts +0 -27
  449. package/dist/types/src/components/Plank/Plank.d.ts.map +0 -1
  450. package/dist/types/src/components/Plank/Plank.stories.d.ts +0 -89
  451. package/dist/types/src/components/Plank/Plank.stories.d.ts.map +0 -1
  452. package/dist/types/src/components/Plank/PlankControls.d.ts.map +0 -1
  453. package/dist/types/src/components/Plank/PlankError.d.ts +0 -13
  454. package/dist/types/src/components/Plank/PlankError.d.ts.map +0 -1
  455. package/dist/types/src/components/Plank/PlankHeading.d.ts.map +0 -1
  456. package/dist/types/src/components/Plank/index.d.ts +0 -6
  457. package/dist/types/src/components/Plank/index.d.ts.map +0 -1
  458. package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +0 -1
  459. package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +0 -1
  460. package/dist/types/src/components/Sidebar/SidebarButton.d.ts.map +0 -1
  461. package/dist/types/src/components/fragments.d.ts +0 -4
  462. package/dist/types/src/components/fragments.d.ts.map +0 -1
  463. package/dist/types/src/events.d.ts +0 -4
  464. package/dist/types/src/events.d.ts.map +0 -1
  465. package/dist/types/src/hooks/useHoistStatusbar.d.ts +0 -3
  466. package/dist/types/src/hooks/useHoistStatusbar.d.ts.map +0 -1
  467. package/dist/types/src/util/overscroll.d.ts +0 -47
  468. package/dist/types/src/util/overscroll.d.ts.map +0 -1
  469. package/src/capabilities/capabilities.ts +0 -14
  470. package/src/capabilities/intent-resolver.ts +0 -472
  471. package/src/capabilities/toolkit.ts +0 -57
  472. package/src/components/DeckLayout/Banner.tsx +0 -39
  473. package/src/components/DeckLayout/ContentEmpty.tsx +0 -31
  474. package/src/components/DeckLayout/DeckLayout.stories.tsx +0 -64
  475. package/src/components/DeckLayout/DeckLayout.tsx +0 -32
  476. package/src/components/DeckLayout/DeckMain.tsx +0 -285
  477. package/src/components/DeckLayout/Dialog.tsx +0 -36
  478. package/src/components/DeckLayout/Fallback.tsx +0 -28
  479. package/src/components/DeckLayout/Popover.tsx +0 -104
  480. package/src/components/DeckLayout/Topbar.tsx +0 -11
  481. package/src/components/Plank/Plank.stories.tsx +0 -54
  482. package/src/components/Plank/Plank.tsx +0 -283
  483. package/src/components/Plank/PlankError.tsx +0 -49
  484. package/src/components/Sidebar/ComplementarySidebar.tsx +0 -194
  485. package/src/components/Sidebar/Sidebar.tsx +0 -42
  486. package/src/components/Sidebar/SidebarButton.tsx +0 -87
  487. package/src/components/fragments.ts +0 -14
  488. package/src/events.ts +0 -11
  489. package/src/hooks/useHoistStatusbar.ts +0 -26
  490. package/src/util/overscroll.ts +0 -69
  491. /package/dist/lib/{browser/state-6ZSDTF6Q.mjs.map → neutral/check-app-scheme-A7FZVNZO.mjs.map} +0 -0
  492. /package/dist/lib/{browser/types/index.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
  493. /package/dist/types/src/{components/DeckLayout → containers/Deck}/StatusBar.d.ts +0 -0
  494. /package/dist/types/src/{components → containers}/DeckLayout/ActiveNode.d.ts +0 -0
  495. /package/dist/types/src/{components → containers}/DeckLayout/DeckLayout.d.ts +0 -0
  496. /package/dist/types/src/{components → containers}/DeckLayout/Dialog.d.ts +0 -0
  497. /package/dist/types/src/{components → containers}/DeckLayout/constants.d.ts +0 -0
  498. /package/dist/types/src/{components → containers}/Plank/PlankLoading.d.ts +0 -0
  499. /package/dist/types/src/{components → containers}/Sidebar/ComplementarySidebar.d.ts +0 -0
  500. /package/dist/types/src/{components → containers}/Sidebar/Sidebar.d.ts +0 -0
  501. /package/dist/types/src/{components → containers}/Sidebar/index.d.ts +0 -0
  502. /package/src/{components → containers}/Sidebar/index.ts +0 -0
@@ -0,0 +1,100 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback } from 'react';
6
+
7
+ import { useOperationInvoker } from '@dxos/app-framework/ui';
8
+ import { LayoutOperation } from '@dxos/app-toolkit';
9
+ import { IconButton, type IconButtonProps, type ThemedClassName, useTranslation } from '@dxos/react-ui';
10
+ import { getLinkedVariant } from '@dxos/react-ui-attention';
11
+
12
+ import { useDeckCompanions, useDeckState } from '#hooks';
13
+ import { meta } from '#meta';
14
+
15
+ export const ToggleSidebarButton = ({
16
+ classNames,
17
+ variant = 'ghost',
18
+ }: ThemedClassName<Pick<IconButtonProps, 'variant'>>) => {
19
+ const { updateState } = useDeckState();
20
+ const { t } = useTranslation(meta.id);
21
+
22
+ const handleClick = useCallback(() => {
23
+ updateState((state) => ({
24
+ ...state,
25
+ sidebarState: state.sidebarState === 'expanded' ? 'collapsed' : 'expanded',
26
+ }));
27
+ }, [updateState]);
28
+
29
+ return (
30
+ <IconButton
31
+ variant={variant}
32
+ icon='ph--sidebar--regular'
33
+ iconOnly
34
+ size={4}
35
+ label={t('open-navigation-sidebar.label')}
36
+ onClick={handleClick}
37
+ classNames={classNames}
38
+ />
39
+ );
40
+ };
41
+
42
+ export const CloseSidebarButton = () => {
43
+ const { updateState } = useDeckState();
44
+ const { t } = useTranslation(meta.id);
45
+
46
+ const handleClick = useCallback(() => {
47
+ updateState((state) => ({ ...state, sidebarState: 'collapsed' }));
48
+ }, [updateState]);
49
+
50
+ return (
51
+ <IconButton
52
+ variant='ghost'
53
+ icon='ph--caret-line-left--regular'
54
+ iconOnly
55
+ size={4}
56
+ label={t('close-navigation-sidebar.button')}
57
+ onClick={handleClick}
58
+ classNames='rounded-none px-1 dx-focus-ring-inset pe-[max(.5rem,env(safe-area-inset-left))]'
59
+ />
60
+ );
61
+ };
62
+
63
+ export const ToggleComplementarySidebarButton = ({
64
+ inR0,
65
+ classNames,
66
+ current,
67
+ }: ThemedClassName<{ inR0?: boolean; current?: string }>) => {
68
+ const { invokePromise } = useOperationInvoker();
69
+ const { state, updateState } = useDeckState();
70
+ const { t } = useTranslation(meta.id);
71
+
72
+ const companions = useDeckCompanions();
73
+ const handleClick = useCallback(() => {
74
+ const nextState = state.complementarySidebarState === 'expanded' ? 'collapsed' : 'expanded';
75
+ updateState((state) => ({ ...state, complementarySidebarState: nextState }));
76
+
77
+ const subject = state.complementarySidebarPanel ?? (companions[0] && getLinkedVariant(companions[0].id));
78
+ if (nextState === 'expanded' && !current && subject) {
79
+ void invokePromise(LayoutOperation.UpdateComplementary, { subject });
80
+ }
81
+ }, [state, updateState, current, companions, invokePromise]);
82
+
83
+ const label = t(
84
+ state.complementarySidebarState === 'expanded'
85
+ ? 'close-complementary-sidebar.label'
86
+ : 'open-complementary-sidebar.label',
87
+ );
88
+
89
+ return (
90
+ <IconButton
91
+ variant='ghost'
92
+ classNames={['[&>svg]:-scale-x-100', classNames]}
93
+ icon='ph--sidebar-simple--regular'
94
+ iconOnly
95
+ label={label}
96
+ tooltipSide={inR0 ? 'left' : undefined}
97
+ onClick={handleClick}
98
+ />
99
+ );
100
+ };
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type ComponentType, lazy } from 'react';
6
+
7
+ export * from './Deck';
8
+ export * from './Plank';
9
+ export * from './Sidebar';
10
+
11
+ export const DeckLayout: ComponentType<any> = lazy(() => import('./DeckLayout'));
@@ -5,6 +5,7 @@
5
5
  export * from './useBreakpoints';
6
6
  export * from './useCompanions';
7
7
  export * from './useDeckCompanions';
8
- export * from './useHoistStatusbar';
8
+ export * from './useDeckState';
9
9
  export * from './useMainSize';
10
10
  export * from './useNodeActionExpander';
11
+ export * from './useSelectedCompanion';
@@ -4,15 +4,15 @@
4
4
 
5
5
  import { useMemo } from 'react';
6
6
 
7
- import { useAppGraph } from '@dxos/app-framework';
7
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
8
8
  import { useConnections } from '@dxos/plugin-graph';
9
9
  import { byPosition } from '@dxos/util';
10
10
 
11
- import { PLANK_COMPANION_TYPE } from '../types';
11
+ import { PLANK_COMPANION_TYPE } from '#types';
12
12
 
13
13
  export const useCompanions = (id?: string) => {
14
14
  const { graph } = useAppGraph();
15
- const nodes = useConnections(graph, id);
15
+ const nodes = useConnections(graph, id, 'child');
16
16
  const companions = nodes.filter((node) => node.type === PLANK_COMPANION_TYPE);
17
17
  return useMemo(() => companions.toSorted((a, b) => byPosition(a.properties, b.properties)), [companions]);
18
18
  };
@@ -2,18 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Label, useAppGraph } from '@dxos/app-framework';
6
- import { type Node, ROOT_ID, useConnections } from '@dxos/plugin-graph';
5
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
6
+ import { Node, type Node as NodeType } from '@dxos/plugin-graph';
7
+ import { useConnections } from '@dxos/plugin-graph';
8
+ import { type Label } from '@dxos/ui-types/translations';
7
9
  import { type Position, byPosition } from '@dxos/util';
8
10
 
9
- import { ATTENDABLE_PATH_SEPARATOR, DECK_COMPANION_TYPE } from '../types';
11
+ import { DECK_COMPANION_TYPE } from '#types';
10
12
 
11
- export const getCompanionId = (id: string) => {
12
- const [_, companionId] = id.split(ATTENDABLE_PATH_SEPARATOR);
13
- return companionId ?? 'never';
14
- };
15
-
16
- export type DeckCompanion = Node<
13
+ export type DeckCompanion = NodeType.Node<
17
14
  any,
18
15
  {
19
16
  label: Label;
@@ -22,12 +19,13 @@ export type DeckCompanion = Node<
22
19
  /** If true, the panel will not be wrapped in a scroll area. */
23
20
  fixed?: boolean;
24
21
  position?: Position;
22
+ joyride?: string;
25
23
  }
26
24
  >;
27
25
 
28
26
  export const useDeckCompanions = (): DeckCompanion[] => {
29
27
  const { graph } = useAppGraph();
30
- const connections = useConnections(graph, ROOT_ID);
28
+ const connections = useConnections(graph, Node.RootId, 'child');
31
29
  const companions = connections.filter((node) => node.type === DECK_COMPANION_TYPE) as DeckCompanion[];
32
30
  return companions.toSorted((a, b) => byPosition(a.properties, b.properties));
33
31
  };
@@ -0,0 +1,73 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useAtomValue } from '@effect-atom/atom-react';
6
+ import { useCallback, useMemo } from 'react';
7
+
8
+ import { Capabilities } from '@dxos/app-framework';
9
+ import { useCapability } from '@dxos/app-framework/ui';
10
+ import { invariant } from '@dxos/invariant';
11
+
12
+ import {
13
+ DeckCapabilities,
14
+ type EphemeralDeckState,
15
+ type DeckPluginState,
16
+ type DeckState,
17
+ type StoredDeckState,
18
+ } from '#types';
19
+
20
+ export type DeckStateHook = {
21
+ /** Combined state value (reactive). Includes both persisted and ephemeral state. */
22
+ state: DeckPluginState;
23
+ /** The active deck, computed from decks[activeDeck]. */
24
+ deck: DeckState;
25
+ /** Update persisted state. */
26
+ updateState: (fn: (current: StoredDeckState) => StoredDeckState) => void;
27
+ /** Update ephemeral state. */
28
+ updateEphemeral: (fn: (current: EphemeralDeckState) => EphemeralDeckState) => void;
29
+ };
30
+
31
+ /**
32
+ * Hook to access the deck plugin state reactively.
33
+ * Returns the combined state, the active deck, and update functions for each atom.
34
+ */
35
+ export const useDeckState = (): DeckStateHook => {
36
+ const registry = useCapability(Capabilities.AtomRegistry);
37
+ const stateAtom = useCapability(DeckCapabilities.State);
38
+ const ephemeralAtom = useCapability(DeckCapabilities.EphemeralState);
39
+ const persistedState = useAtomValue(stateAtom);
40
+ const ephemeralState = useAtomValue(ephemeralAtom);
41
+
42
+ // Compute deck from decks[activeDeck] to ensure it's always current.
43
+ const deck = useMemo(() => {
44
+ const deck = persistedState.decks[persistedState.activeDeck];
45
+ invariant(deck, `Deck not found: ${persistedState.activeDeck}`);
46
+ return deck;
47
+ }, [persistedState.decks, persistedState.activeDeck]);
48
+
49
+ // Combine persisted and ephemeral state into a unified view.
50
+ const state = useMemo(
51
+ (): DeckPluginState => ({
52
+ ...persistedState,
53
+ ...ephemeralState,
54
+ }),
55
+ [persistedState, ephemeralState],
56
+ );
57
+
58
+ const updateState = useCallback(
59
+ (fn: (current: StoredDeckState) => StoredDeckState) => {
60
+ registry.set(stateAtom, fn(registry.get(stateAtom)));
61
+ },
62
+ [registry, stateAtom],
63
+ );
64
+
65
+ const updateEphemeral = useCallback(
66
+ (fn: (current: EphemeralDeckState) => EphemeralDeckState) => {
67
+ registry.set(ephemeralAtom, fn(registry.get(ephemeralAtom)));
68
+ },
69
+ [registry, ephemeralAtom],
70
+ );
71
+
72
+ return useMemo(() => ({ state, deck, updateState, updateEphemeral }), [state, deck, updateState, updateEphemeral]);
73
+ };
@@ -7,7 +7,7 @@ import { useMainContext } from '@dxos/react-ui';
7
7
  export const useMainSize = () => {
8
8
  const { navigationSidebarState, complementarySidebarState } = useMainContext('DeckPluginPlank');
9
9
  return {
10
- 'data-sidebar-inline-start-state': navigationSidebarState,
11
- 'data-sidebar-inline-end-state': complementarySidebarState,
10
+ 'data-sidebar-left-state': navigationSidebarState,
11
+ 'data-sidebar-right-state': complementarySidebarState,
12
12
  };
13
13
  };
@@ -4,14 +4,14 @@
4
4
 
5
5
  import { useEffect } from 'react';
6
6
 
7
- import { type Node, getGraph } from '@dxos/plugin-graph';
7
+ import { Graph, type Node } from '@dxos/plugin-graph';
8
8
 
9
- export const useNodeActionExpander = (node?: Node) => {
9
+ export const useNodeActionExpander = (node?: Node.Node) => {
10
10
  useEffect(() => {
11
11
  if (node) {
12
12
  const frame = requestAnimationFrame(() => {
13
- const graph = getGraph(node);
14
- void graph.expand(node.id);
13
+ const graph = Graph.getGraph(node);
14
+ void Graph.expand(graph, node.id, 'action');
15
15
  });
16
16
  return () => cancelAnimationFrame(frame);
17
17
  }
@@ -0,0 +1,32 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { useMemo } from 'react';
6
+
7
+ import { type Node } from '@dxos/plugin-graph';
8
+ import { getLinkedVariant } from '@dxos/react-ui-attention';
9
+
10
+ /**
11
+ * Resolves which companion to show based on variant preference.
12
+ * Falls back to first available if preferred variant not found.
13
+ */
14
+ export const useSelectedCompanion = (companions: Node.Node[], preferredVariant?: string) => {
15
+ return useMemo(() => {
16
+ if (companions.length === 0) {
17
+ return { companionId: undefined, variant: undefined };
18
+ }
19
+
20
+ // Try to find companion matching the preferred variant.
21
+ if (preferredVariant) {
22
+ const preferred = companions.find((companion) => getLinkedVariant(companion.id) === preferredVariant);
23
+ if (preferred) {
24
+ return { companionId: preferred.id, variant: getLinkedVariant(preferred.id) };
25
+ }
26
+ }
27
+
28
+ // Fallback to first companion.
29
+ const first = companions[0];
30
+ return { companionId: first.id, variant: getLinkedVariant(first.id) };
31
+ }, [companions, preferredVariant]);
32
+ };
package/src/index.ts CHANGED
@@ -2,8 +2,5 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export { DeckCapabilities } from './capabilities';
6
- export { DeckEvents } from './events';
7
- export * from './DeckPlugin';
8
5
  export * from './meta';
9
- export { useCompanions } from './hooks';
6
+ export * from './types';
@@ -0,0 +1,59 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, expect, test } from 'vitest';
6
+
7
+ import { openEntry, openSubjectsOnActiveDeck } from './layout';
8
+
9
+ describe('openEntry', () => {
10
+ test('pushes new id to the end', () => {
11
+ expect(openEntry(['a', 'b'], 'c')).toEqual(['a', 'b', 'c']);
12
+ });
13
+
14
+ test('no-op when id already present', () => {
15
+ expect(openEntry(['a', 'b'], 'a')).toEqual(['a', 'b']);
16
+ });
17
+
18
+ test('replaces by key prefix when key matches', () => {
19
+ expect(openEntry(['foo+1', 'b'], 'foo+2', { key: 'foo' })).toEqual(['foo+2', 'b']);
20
+ });
21
+ });
22
+
23
+ describe('openSubjectsOnActiveDeck', () => {
24
+ test('truncates after pivot then appends one subject', () => {
25
+ expect(openSubjectsOnActiveDeck(['a', 'b', 'c', 'd'], ['e'], { pivotId: 'a' })).toEqual(['a', 'e']);
26
+ });
27
+
28
+ test('appends to end when pivot not in deck', () => {
29
+ expect(openSubjectsOnActiveDeck(['a', 'b'], ['c'], { pivotId: 'missing' })).toEqual(['a', 'b', 'c']);
30
+ });
31
+
32
+ test('without pivotId appends each subject to the end', () => {
33
+ expect(openSubjectsOnActiveDeck(['a'], ['b', 'c'], {})).toEqual(['a', 'b', 'c']);
34
+ });
35
+
36
+ test('with pivot keeps all new subjects after truncate', () => {
37
+ expect(openSubjectsOnActiveDeck(['a', 'b', 'c'], ['x', 'y'], { pivotId: 'a' })).toEqual(['a', 'x', 'y']);
38
+ });
39
+
40
+ test('passes key through to openEntry', () => {
41
+ expect(openSubjectsOnActiveDeck(['foo+1'], ['foo+2'], { key: 'foo' })).toEqual(['foo+2']);
42
+ });
43
+
44
+ test('returns deck unchanged when subject is already open (no pivot)', () => {
45
+ expect(openSubjectsOnActiveDeck(['a', 'b', 'c'], ['b'])).toEqual(['a', 'b', 'c']);
46
+ });
47
+
48
+ test('returns deck unchanged when subject is already open (with pivot)', () => {
49
+ expect(openSubjectsOnActiveDeck(['a', 'b', 'c'], ['c'], { pivotId: 'a' })).toEqual(['a', 'b', 'c']);
50
+ });
51
+
52
+ test('returns deck unchanged when all subjects are already open', () => {
53
+ expect(openSubjectsOnActiveDeck(['a', 'b', 'c'], ['b', 'c'], { pivotId: 'a' })).toEqual(['a', 'b', 'c']);
54
+ });
55
+
56
+ test('truncates after pivot when subject is new even if some are already open', () => {
57
+ expect(openSubjectsOnActiveDeck(['a', 'b', 'c'], ['b', 'd'], { pivotId: 'a' })).toEqual(['a', 'b', 'd']);
58
+ });
59
+ });
package/src/layout.ts CHANGED
@@ -4,38 +4,23 @@
4
4
 
5
5
  import { produce } from 'immer';
6
6
 
7
- import { ATTENDABLE_PATH_SEPARATOR } from '@dxos/react-ui-attention';
8
-
9
- import { type DeckAction, type NewPlankPositioning } from './types';
10
-
11
- export const createEntryId = (entryId: string, variant?: string) =>
12
- variant ? `${entryId}${ATTENDABLE_PATH_SEPARATOR}${variant}` : entryId;
13
-
14
- export const parseEntryId = (entryId: string) => {
15
- const [id, variant] = entryId.split(ATTENDABLE_PATH_SEPARATOR);
16
- return { id, variant };
17
- };
7
+ import { type DeckAction } from '#types';
18
8
 
19
9
  type OpenLayoutEntryOptions = {
20
10
  key?: string;
21
- positioning?: NewPlankPositioning;
22
- pivotId?: string;
23
- variant?: string;
24
11
  };
25
12
 
26
- export const openEntry = (deck: string[], _entryId: string, options?: OpenLayoutEntryOptions): string[] => {
27
- return produce(deck, (draft) => {
28
- const entryId = createEntryId(_entryId, options?.variant);
29
-
30
- // Check that the entry is not already in the part
13
+ /**
14
+ * Mutates a deck list using stack semantics: new items open to the right (`push`).
15
+ * Callers that open from a pivot must truncate the deck first (see deck `open` operation).
16
+ */
17
+ export const openEntry = (deck: readonly string[], entryId: string, options?: OpenLayoutEntryOptions): string[] => {
18
+ return produce([...deck], (draft) => {
31
19
  if (draft.find((id) => id === entryId)) {
32
20
  return;
33
21
  }
34
22
 
35
23
  const key = options?.key;
36
- const plankPositioning = options?.positioning ?? 'start';
37
- const pivotId = options?.pivotId;
38
-
39
24
  if (key) {
40
25
  const index = draft.findIndex((id) => id.split('+')[0] === key);
41
26
  if (index !== -1) {
@@ -44,27 +29,40 @@ export const openEntry = (deck: string[], _entryId: string, options?: OpenLayout
44
29
  }
45
30
  }
46
31
 
47
- if (pivotId) {
48
- const pivotIndex = draft.findIndex((id) => id === pivotId);
49
- if (pivotIndex !== -1) {
50
- if (plankPositioning === 'start') {
51
- draft.splice(pivotIndex, 0, entryId);
52
- } else {
53
- draft.splice(pivotIndex + 1, 0, entryId);
54
- }
55
- return;
56
- }
57
- }
58
-
59
- // If no pivot found or provided, fall back to original behavior
60
- if (plankPositioning === 'start') {
61
- draft.unshift(entryId);
62
- } else {
63
- draft.push(entryId);
64
- }
32
+ draft.push(entryId);
65
33
  });
66
34
  };
67
35
 
36
+ export type OpenSubjectsOnActiveDeckOptions = {
37
+ pivotId?: string;
38
+ key?: string;
39
+ };
40
+
41
+ /**
42
+ * Computes the next multi-mode `active` list for {@link LayoutOperation.Open}.
43
+ * If `pivotId` is present and found, truncates the deck after that id.
44
+ * Applies each subject with {@link openEntry}.
45
+ * If the pivot is missing, appends onto the full `active` list.
46
+ *
47
+ * When all subjects are already present in the active deck, the deck is returned
48
+ * unchanged so that pivot truncation does not discard open planks when navigating
49
+ * to something that is already visible.
50
+ */
51
+ export const openSubjectsOnActiveDeck = (
52
+ active: readonly string[],
53
+ subject: readonly string[],
54
+ options?: OpenSubjectsOnActiveDeckOptions,
55
+ ): string[] => {
56
+ if (subject.length > 0 && subject.every((id) => active.includes(id))) {
57
+ return [...active];
58
+ }
59
+
60
+ const { pivotId, key } = options ?? {};
61
+ const pivotIndex = pivotId ? active.findIndex((id) => id === pivotId) : -1;
62
+ const baseDeck = pivotIndex !== -1 ? active.slice(0, pivotIndex + 1) : [...active];
63
+ return subject.reduce((acc, entryId) => openEntry(acc, entryId, { key }), baseDeck);
64
+ };
65
+
68
66
  export const closeEntry = (deck: string[], entryId: string): string[] => {
69
67
  return produce(deck, (draft) => {
70
68
  const index = draft.findIndex((id) => id === entryId);
package/src/meta.ts CHANGED
@@ -2,10 +2,32 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type PluginMeta } from '@dxos/app-framework';
5
+ import { type Plugin } from '@dxos/app-framework';
6
+ import { trim } from '@dxos/util';
6
7
 
7
- export const meta: PluginMeta = {
8
- id: 'dxos.org/plugin/deck',
8
+ export const meta: Plugin.Meta = {
9
+ id: 'org.dxos.plugin.deck',
9
10
  name: 'Layout',
11
+ author: 'DXOS',
12
+ spec: 'PLUGIN.mdl',
13
+ description: trim`
14
+ The Deck plugin is the core layout engine for DXOS Composer. It manages the multi-plank
15
+ workspace (the "deck"), sidebar panels, dialogs, popovers, and toast notifications, giving
16
+ users a flexible, persistent workspace they can arrange to match their workflow.
17
+
18
+ In multi mode, subjects are opened as resizable "planks" arranged side by side. Users can
19
+ navigate with stack semantics — opening from a pivot truncates planks to the right and
20
+ appends the new one — or switch to solo or fullscreen mode for focused, distraction-free
21
+ viewing.
22
+
23
+ Layout state (active planks, sidebar visibility, plank sizes, companion pane) is persisted
24
+ across sessions via KVS/localStorage. URL routing is handled by the plugin so that any
25
+ workspace configuration can be bookmarked or shared as a deep link.
26
+
27
+ All layout changes are expressed through typed LayoutOperations (Open, Close, SetLayoutMode,
28
+ UpdateSidebar, UpdateDialog, UpdatePopover, etc.) that any plugin in the system can dispatch,
29
+ keeping the layout logic centralised and easy to extend.
30
+ `,
10
31
  icon: 'ph--layout--regular',
32
+ tags: ['system'],
11
33
  };
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities } from '@dxos/app-framework';
8
+ import { LayoutOperation } from '@dxos/app-toolkit';
9
+ import { Operation } from '@dxos/compute';
10
+
11
+ import { DeckCapabilities } from '../types';
12
+
13
+ const handler: Operation.WithHandler<typeof LayoutOperation.AddToast> = LayoutOperation.AddToast.pipe(
14
+ Operation.withHandler(
15
+ Effect.fnUntraced(function* (input) {
16
+ yield* Capabilities.updateAtomValue(DeckCapabilities.EphemeralState, (state) => ({
17
+ ...state,
18
+ toasts: [...state.toasts, input as LayoutOperation.Toast],
19
+ }));
20
+ }),
21
+ ),
22
+ );
23
+
24
+ export default handler;
@@ -0,0 +1,82 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Function from 'effect/Function';
7
+ import * as Option from 'effect/Option';
8
+
9
+ import { Capabilities, Capability } from '@dxos/app-framework';
10
+ import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
11
+ import { Operation } from '@dxos/compute';
12
+ import { AttentionCapabilities } from '@dxos/plugin-attention';
13
+ import { Graph } from '@dxos/plugin-graph';
14
+ import { byPosition } from '@dxos/util';
15
+
16
+ import { incrementPlank } from '../layout';
17
+ import { DeckCapabilities, DeckOperation, PLANK_COMPANION_TYPE } from '../types';
18
+ import { computeActiveUpdates } from '../util';
19
+ import { updateActiveDeck } from './helpers';
20
+
21
+ const handler: Operation.WithHandler<typeof DeckOperation.Adjust> = DeckOperation.Adjust.pipe(
22
+ Operation.withHandler(
23
+ Effect.fnUntraced(function* (input) {
24
+ const _state = yield* Capabilities.getAtomValue(DeckCapabilities.State);
25
+ const deck = yield* DeckCapabilities.getDeck();
26
+ const attention = yield* Capability.get(AttentionCapabilities.Attention);
27
+ const { graph } = yield* Capability.get(AppCapabilities.AppGraph);
28
+
29
+ let soloOperation:
30
+ | { type: 'solo'; entryId: string; mode: string }
31
+ | { type: 'unsolo'; entryId: string }
32
+ | undefined;
33
+
34
+ if (input.type === 'increment-end' || input.type === 'increment-start') {
35
+ const next = incrementPlank(deck.active, input);
36
+ const { deckUpdates } = computeActiveUpdates({ next, deck, attention });
37
+ yield* Capabilities.updateAtomValue(DeckCapabilities.State, (state) => updateActiveDeck(state, deckUpdates));
38
+ }
39
+
40
+ if (input.type.startsWith('solo')) {
41
+ const entryId = input.id;
42
+ if (!deck.solo) {
43
+ soloOperation = { type: 'solo', entryId, mode: input.type };
44
+ } else {
45
+ if (input.type === 'solo--fullscreen') {
46
+ soloOperation = { type: 'solo', entryId, mode: 'solo--fullscreen' };
47
+ } else if (input.type === 'solo') {
48
+ soloOperation = { type: 'unsolo', entryId };
49
+ }
50
+ }
51
+ }
52
+
53
+ if (soloOperation?.type === 'solo') {
54
+ yield* Operation.invoke(LayoutOperation.SetLayoutMode, {
55
+ subject: soloOperation.entryId,
56
+ mode: soloOperation.mode,
57
+ });
58
+ } else if (soloOperation?.type === 'unsolo') {
59
+ yield* Operation.invoke(LayoutOperation.SetLayoutMode, { mode: 'multi' });
60
+ yield* Operation.invoke(LayoutOperation.Open, { subject: [soloOperation.entryId] });
61
+ }
62
+
63
+ if (input.type === 'companion') {
64
+ const companion = Function.pipe(
65
+ Graph.getNode(graph, input.id),
66
+ Option.map((node) =>
67
+ Graph.getConnections(graph, node.id, 'child')
68
+ .filter((n) => n.type === PLANK_COMPANION_TYPE)
69
+ .toSorted((a, b) => byPosition(a.properties, b.properties)),
70
+ ),
71
+ Option.flatMap((companions) => (companions.length > 0 ? Option.some(companions[0]) : Option.none())),
72
+ );
73
+
74
+ if (Option.isSome(companion)) {
75
+ yield* Operation.invoke(LayoutOperation.UpdateCompanion, { subject: companion.value.id });
76
+ }
77
+ }
78
+ }),
79
+ ),
80
+ );
81
+
82
+ export default handler;
@@ -0,0 +1,35 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { LayoutOperation } from '@dxos/app-toolkit';
9
+ import { Operation } from '@dxos/compute';
10
+ import { AttentionCapabilities } from '@dxos/plugin-attention';
11
+
12
+ import { closeEntry } from '../layout';
13
+ import { DeckCapabilities } from '../types';
14
+ import { computeActiveUpdates } from '../util';
15
+ import { updateActiveDeck } from './helpers';
16
+
17
+ const handler: Operation.WithHandler<typeof LayoutOperation.Close> = LayoutOperation.Close.pipe(
18
+ Operation.withHandler(
19
+ Effect.fnUntraced(function* (input) {
20
+ const deck = yield* DeckCapabilities.getDeck();
21
+ const attention = yield* Capability.get(AttentionCapabilities.Attention);
22
+
23
+ const active = deck.solo ? [deck.solo] : deck.active;
24
+ const next = input.subject.reduce((acc, id) => closeEntry(acc, id), active);
25
+ const { deckUpdates, toAttend } = computeActiveUpdates({ next, deck, attention });
26
+ yield* Capabilities.updateAtomValue(DeckCapabilities.State, (state) => updateActiveDeck(state, deckUpdates));
27
+
28
+ if (toAttend) {
29
+ yield* Operation.schedule(LayoutOperation.ScrollIntoView, { subject: toAttend });
30
+ }
31
+ }),
32
+ ),
33
+ );
34
+
35
+ export default handler;