@dxos/plugin-deck 0.8.4-main.fffef41 → 0.9.0

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 (504) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +541 -0
  3. package/README.md +1 -1
  4. package/dist/lib/neutral/DeckLayout-DEURA3KR.mjs +291 -0
  5. package/dist/lib/neutral/DeckLayout-DEURA3KR.mjs.map +7 -0
  6. package/dist/lib/neutral/DeckPlugin.mjs +87 -0
  7. package/dist/lib/neutral/DeckPlugin.mjs.map +7 -0
  8. package/dist/lib/neutral/DeckPlugin.node.mjs +18 -0
  9. package/dist/lib/neutral/DeckPlugin.node.mjs.map +7 -0
  10. package/dist/lib/neutral/DeckPlugin.workerd.mjs +16 -0
  11. package/dist/lib/neutral/DeckPlugin.workerd.mjs.map +7 -0
  12. package/dist/lib/neutral/DeckSettings-W5I57OXM.mjs +27 -0
  13. package/dist/lib/neutral/DeckSettings-W5I57OXM.mjs.map +7 -0
  14. package/dist/lib/neutral/add-toast-TNB6DXWU.mjs +24 -0
  15. package/dist/lib/neutral/add-toast-TNB6DXWU.mjs.map +7 -0
  16. package/dist/lib/neutral/adjust-HNU5CCRO.mjs +93 -0
  17. package/dist/lib/neutral/adjust-HNU5CCRO.mjs.map +7 -0
  18. package/dist/lib/neutral/app-graph-builder-HMLT627T.mjs +129 -0
  19. package/dist/lib/neutral/app-graph-builder-HMLT627T.mjs.map +7 -0
  20. package/dist/lib/neutral/capabilities/index.mjs +25 -0
  21. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  22. package/dist/lib/neutral/check-app-scheme-INSOF72J.mjs +10 -0
  23. package/dist/lib/neutral/chunk-324PPIZB.mjs +101 -0
  24. package/dist/lib/neutral/chunk-324PPIZB.mjs.map +7 -0
  25. package/dist/lib/neutral/chunk-BS4EOYMK.mjs +282 -0
  26. package/dist/lib/neutral/chunk-BS4EOYMK.mjs.map +7 -0
  27. package/dist/lib/neutral/chunk-GBIGQKYW.mjs +112 -0
  28. package/dist/lib/neutral/chunk-GBIGQKYW.mjs.map +7 -0
  29. package/dist/lib/neutral/chunk-GLB73Q6U.mjs +22 -0
  30. package/dist/lib/neutral/chunk-GLB73Q6U.mjs.map +7 -0
  31. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  32. package/dist/lib/neutral/chunk-PYEY5SEC.mjs +37 -0
  33. package/dist/lib/neutral/chunk-PYEY5SEC.mjs.map +7 -0
  34. package/dist/lib/neutral/chunk-Q4W6B4IB.mjs +8 -0
  35. package/dist/lib/neutral/chunk-Q4W6B4IB.mjs.map +7 -0
  36. package/dist/lib/neutral/chunk-WAXJPQJI.mjs +1306 -0
  37. package/dist/lib/neutral/chunk-WAXJPQJI.mjs.map +7 -0
  38. package/dist/lib/neutral/chunk-ZYYOSX5I.mjs +69 -0
  39. package/dist/lib/neutral/chunk-ZYYOSX5I.mjs.map +7 -0
  40. package/dist/lib/neutral/close-ASKR22A6.mjs +44 -0
  41. package/dist/lib/neutral/close-ASKR22A6.mjs.map +7 -0
  42. package/dist/lib/neutral/components/index.mjs +126 -0
  43. package/dist/lib/neutral/components/index.mjs.map +7 -0
  44. package/dist/lib/neutral/containers/index.mjs +32 -0
  45. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  46. package/dist/lib/neutral/hooks/index.mjs +159 -0
  47. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  48. package/dist/lib/neutral/index.mjs +38 -0
  49. package/dist/lib/neutral/index.mjs.map +7 -0
  50. package/dist/lib/neutral/meta.json +1 -0
  51. package/dist/lib/neutral/meta.mjs +8 -0
  52. package/dist/lib/neutral/meta.mjs.map +7 -0
  53. package/dist/lib/neutral/notification-tracker-P36322BH.mjs +182 -0
  54. package/dist/lib/neutral/notification-tracker-P36322BH.mjs.map +7 -0
  55. package/dist/lib/neutral/open-5OYNO3RT.mjs +159 -0
  56. package/dist/lib/neutral/open-5OYNO3RT.mjs.map +7 -0
  57. package/dist/lib/neutral/operation-handler-266CVMTW.mjs +13 -0
  58. package/dist/lib/neutral/operation-handler-266CVMTW.mjs.map +7 -0
  59. package/dist/lib/neutral/operations/index.mjs +8 -0
  60. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  61. package/dist/lib/neutral/plugin.mjs +16 -0
  62. package/dist/lib/neutral/plugin.mjs.map +7 -0
  63. package/dist/lib/neutral/react-root-HH5DEUOG.mjs +44 -0
  64. package/dist/lib/neutral/react-root-HH5DEUOG.mjs.map +7 -0
  65. package/dist/lib/neutral/react-surface-3UVVCK3O.mjs +34 -0
  66. package/dist/lib/neutral/react-surface-3UVVCK3O.mjs.map +7 -0
  67. package/dist/lib/neutral/revert-workspace-B2QLT2C4.mjs +21 -0
  68. package/dist/lib/neutral/revert-workspace-B2QLT2C4.mjs.map +7 -0
  69. package/dist/lib/neutral/scroll-into-view-B52C3PJO.mjs +21 -0
  70. package/dist/lib/neutral/scroll-into-view-B52C3PJO.mjs.map +7 -0
  71. package/dist/lib/neutral/set-PA35ONXO.mjs +37 -0
  72. package/dist/lib/neutral/set-PA35ONXO.mjs.map +7 -0
  73. package/dist/lib/neutral/set-layout-mode-RPCCPQRB.mjs +85 -0
  74. package/dist/lib/neutral/set-layout-mode-RPCCPQRB.mjs.map +7 -0
  75. package/dist/lib/neutral/settings-EGNYUM4T.mjs +33 -0
  76. package/dist/lib/neutral/settings-EGNYUM4T.mjs.map +7 -0
  77. package/dist/lib/neutral/state-IIDXMQUO.mjs +86 -0
  78. package/dist/lib/neutral/state-IIDXMQUO.mjs.map +7 -0
  79. package/dist/lib/neutral/switch-workspace-LZF4KZXH.mjs +60 -0
  80. package/dist/lib/neutral/switch-workspace-LZF4KZXH.mjs.map +7 -0
  81. package/dist/lib/neutral/translations.mjs +63 -0
  82. package/dist/lib/neutral/translations.mjs.map +7 -0
  83. package/dist/lib/neutral/types/index.mjs +34 -0
  84. package/dist/lib/neutral/types/index.mjs.map +7 -0
  85. package/dist/lib/neutral/update-companion-YUCZZVGY.mjs +32 -0
  86. package/dist/lib/neutral/update-companion-YUCZZVGY.mjs.map +7 -0
  87. package/dist/lib/neutral/update-complementary-7FZNB55J.mjs +28 -0
  88. package/dist/lib/neutral/update-complementary-7FZNB55J.mjs.map +7 -0
  89. package/dist/lib/neutral/update-dialog-FNQTSSAP.mjs +29 -0
  90. package/dist/lib/neutral/update-dialog-FNQTSSAP.mjs.map +7 -0
  91. package/dist/lib/neutral/update-plank-size-3YW4NXEY.mjs +26 -0
  92. package/dist/lib/neutral/update-plank-size-3YW4NXEY.mjs.map +7 -0
  93. package/dist/lib/neutral/update-popover-G2VUD7E6.mjs +33 -0
  94. package/dist/lib/neutral/update-popover-G2VUD7E6.mjs.map +7 -0
  95. package/dist/lib/neutral/update-sidebar-KRHPUHUB.mjs +25 -0
  96. package/dist/lib/neutral/update-sidebar-KRHPUHUB.mjs.map +7 -0
  97. package/dist/lib/neutral/url-handler-A6HLW4RB.mjs +229 -0
  98. package/dist/lib/neutral/url-handler-A6HLW4RB.mjs.map +7 -0
  99. package/dist/types/src/DeckPlugin.d.ts +3 -1
  100. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  101. package/dist/types/src/DeckPlugin.node.d.ts +4 -0
  102. package/dist/types/src/DeckPlugin.node.d.ts.map +1 -0
  103. package/dist/types/src/DeckPlugin.test.d.ts +2 -0
  104. package/dist/types/src/DeckPlugin.test.d.ts.map +1 -0
  105. package/dist/types/src/DeckPlugin.workerd.d.ts +4 -0
  106. package/dist/types/src/DeckPlugin.workerd.d.ts.map +1 -0
  107. package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
  108. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  109. package/dist/types/src/capabilities/check-app-scheme.d.ts +17 -2
  110. package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -1
  111. package/dist/types/src/capabilities/index.d.ts +197 -12
  112. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  113. package/dist/types/src/capabilities/notification-tracker.d.ts +13 -0
  114. package/dist/types/src/capabilities/notification-tracker.d.ts.map +1 -0
  115. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  116. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  117. package/dist/types/src/capabilities/react-root.d.ts +4 -2
  118. package/dist/types/src/capabilities/react-root.d.ts.map +1 -1
  119. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  120. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  121. package/dist/types/src/capabilities/settings.d.ts +5 -2
  122. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  123. package/dist/types/src/capabilities/state.d.ts +141 -54
  124. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  125. package/dist/types/src/capabilities/tools.d.ts +4 -3
  126. package/dist/types/src/capabilities/tools.d.ts.map +1 -1
  127. package/dist/types/src/capabilities/url-handler.d.ts +3 -2
  128. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -1
  129. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts +4 -4
  130. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts.map +1 -1
  131. package/dist/types/src/components/DeckSettings/DeckSettings.stories.d.ts +67 -0
  132. package/dist/types/src/components/DeckSettings/DeckSettings.stories.d.ts.map +1 -0
  133. package/dist/types/src/components/DeckSettings/index.d.ts +1 -1
  134. package/dist/types/src/components/DeckSettings/index.d.ts.map +1 -1
  135. package/dist/types/src/components/Matrix/Matrix.d.ts +41 -0
  136. package/dist/types/src/components/Matrix/Matrix.d.ts.map +1 -0
  137. package/dist/types/src/components/Matrix/Matrix.stories.d.ts +17 -0
  138. package/dist/types/src/components/Matrix/Matrix.stories.d.ts.map +1 -0
  139. package/dist/types/src/components/Matrix/index.d.ts +3 -0
  140. package/dist/types/src/components/Matrix/index.d.ts.map +1 -0
  141. package/dist/types/src/components/index.d.ts +3 -2
  142. package/dist/types/src/components/index.d.ts.map +1 -1
  143. package/dist/types/src/{components/DeckLayout → containers/Deck}/Banner.d.ts +1 -1
  144. package/dist/types/src/containers/Deck/Banner.d.ts.map +1 -0
  145. package/dist/types/src/containers/Deck/Deck.d.ts +25 -0
  146. package/dist/types/src/containers/Deck/Deck.d.ts.map +1 -0
  147. package/dist/types/src/containers/Deck/Deck.stories.d.ts +67 -0
  148. package/dist/types/src/containers/Deck/Deck.stories.d.ts.map +1 -0
  149. package/dist/types/src/containers/Deck/DeckContent.d.ts +7 -0
  150. package/dist/types/src/containers/Deck/DeckContent.d.ts.map +1 -0
  151. package/dist/types/src/containers/Deck/DeckRoot.d.ts +39 -0
  152. package/dist/types/src/containers/Deck/DeckRoot.d.ts.map +1 -0
  153. package/dist/types/src/containers/Deck/DeckViewport.d.ts +16 -0
  154. package/dist/types/src/containers/Deck/DeckViewport.d.ts.map +1 -0
  155. package/dist/types/src/containers/Deck/StatusBar.d.ts.map +1 -0
  156. package/dist/types/src/containers/Deck/index.d.ts +2 -0
  157. package/dist/types/src/containers/Deck/index.d.ts.map +1 -0
  158. package/dist/types/src/containers/DeckLayout/ActiveNode.d.ts.map +1 -0
  159. package/dist/types/src/containers/DeckLayout/DeckLayout.d.ts.map +1 -0
  160. package/dist/types/src/containers/DeckLayout/DeckLayout.stories.d.ts +69 -0
  161. package/dist/types/src/containers/DeckLayout/DeckLayout.stories.d.ts.map +1 -0
  162. package/dist/types/src/containers/DeckLayout/Dialog.d.ts.map +1 -0
  163. package/dist/types/src/containers/DeckLayout/Fallback.d.ts +2 -0
  164. package/dist/types/src/containers/DeckLayout/Fallback.d.ts.map +1 -0
  165. package/dist/types/src/containers/DeckLayout/Popover.d.ts +5 -0
  166. package/dist/types/src/containers/DeckLayout/Popover.d.ts.map +1 -0
  167. package/dist/types/src/{components → containers}/DeckLayout/Toast.d.ts +3 -3
  168. package/dist/types/src/containers/DeckLayout/Toast.d.ts.map +1 -0
  169. package/dist/types/src/containers/DeckLayout/constants.d.ts.map +1 -0
  170. package/dist/types/src/containers/DeckLayout/index.d.ts +4 -0
  171. package/dist/types/src/containers/DeckLayout/index.d.ts.map +1 -0
  172. package/dist/types/src/containers/Plank/Plank.d.ts +17 -0
  173. package/dist/types/src/containers/Plank/Plank.d.ts.map +1 -0
  174. package/dist/types/src/containers/Plank/Plank.stories.d.ts +67 -0
  175. package/dist/types/src/containers/Plank/Plank.stories.d.ts.map +1 -0
  176. package/dist/types/src/containers/Plank/PlankComponent.d.ts +17 -0
  177. package/dist/types/src/containers/Plank/PlankComponent.d.ts.map +1 -0
  178. package/dist/types/src/containers/Plank/PlankContent.d.ts +10 -0
  179. package/dist/types/src/containers/Plank/PlankContent.d.ts.map +1 -0
  180. package/dist/types/src/{components → containers}/Plank/PlankControls.d.ts +5 -6
  181. package/dist/types/src/containers/Plank/PlankControls.d.ts.map +1 -0
  182. package/dist/types/src/containers/Plank/PlankError.d.ts +15 -0
  183. package/dist/types/src/containers/Plank/PlankError.d.ts.map +1 -0
  184. package/dist/types/src/{components → containers}/Plank/PlankHeading.d.ts +5 -4
  185. package/dist/types/src/containers/Plank/PlankHeading.d.ts.map +1 -0
  186. package/dist/types/src/{components → containers}/Plank/PlankLoading.d.ts.map +1 -1
  187. package/dist/types/src/containers/Plank/PlankRoot.d.ts +37 -0
  188. package/dist/types/src/containers/Plank/PlankRoot.d.ts.map +1 -0
  189. package/dist/types/src/containers/Plank/index.d.ts +4 -0
  190. package/dist/types/src/containers/Plank/index.d.ts.map +1 -0
  191. package/dist/types/src/containers/Sidebar/ComplementarySidebar.d.ts.map +1 -0
  192. package/dist/types/src/containers/Sidebar/Sidebar.d.ts.map +1 -0
  193. package/dist/types/src/{components → containers}/Sidebar/SidebarButton.d.ts +1 -1
  194. package/dist/types/src/containers/Sidebar/SidebarButton.d.ts.map +1 -0
  195. package/dist/types/src/{components → containers}/Sidebar/index.d.ts.map +1 -1
  196. package/dist/types/src/containers/index.d.ts +6 -0
  197. package/dist/types/src/containers/index.d.ts.map +1 -0
  198. package/dist/types/src/hooks/index.d.ts +2 -1
  199. package/dist/types/src/hooks/index.d.ts.map +1 -1
  200. package/dist/types/src/hooks/useBreakpoints.d.ts +1 -1
  201. package/dist/types/src/hooks/useCompanions.d.ts.map +1 -1
  202. package/dist/types/src/hooks/useDeckCompanions.d.ts +4 -4
  203. package/dist/types/src/hooks/useDeckCompanions.d.ts.map +1 -1
  204. package/dist/types/src/hooks/useDeckState.d.ts +17 -0
  205. package/dist/types/src/hooks/useDeckState.d.ts.map +1 -0
  206. package/dist/types/src/hooks/useMainSize.d.ts +2 -2
  207. package/dist/types/src/hooks/useMainSize.d.ts.map +1 -1
  208. package/dist/types/src/hooks/useNodeActionExpander.d.ts +1 -1
  209. package/dist/types/src/hooks/useNodeActionExpander.d.ts.map +1 -1
  210. package/dist/types/src/hooks/useSelectedCompanion.d.ts +13 -0
  211. package/dist/types/src/hooks/useSelectedCompanion.d.ts.map +1 -0
  212. package/dist/types/src/index.d.ts +1 -4
  213. package/dist/types/src/index.d.ts.map +1 -1
  214. package/dist/types/src/layout.d.ts +20 -9
  215. package/dist/types/src/layout.d.ts.map +1 -1
  216. package/dist/types/src/layout.test.d.ts +2 -0
  217. package/dist/types/src/layout.test.d.ts.map +1 -0
  218. package/dist/types/src/meta.d.ts +2 -2
  219. package/dist/types/src/meta.d.ts.map +1 -1
  220. package/dist/types/src/operations/add-toast.d.ts +5 -0
  221. package/dist/types/src/operations/add-toast.d.ts.map +1 -0
  222. package/dist/types/src/operations/adjust.d.ts +5 -0
  223. package/dist/types/src/operations/adjust.d.ts.map +1 -0
  224. package/dist/types/src/operations/close.d.ts +5 -0
  225. package/dist/types/src/operations/close.d.ts.map +1 -0
  226. package/dist/types/src/operations/helpers.d.ts +3 -0
  227. package/dist/types/src/operations/helpers.d.ts.map +1 -0
  228. package/dist/types/src/operations/index.d.ts +3 -0
  229. package/dist/types/src/operations/index.d.ts.map +1 -0
  230. package/dist/types/src/operations/open.d.ts +5 -0
  231. package/dist/types/src/operations/open.d.ts.map +1 -0
  232. package/dist/types/src/operations/revert-workspace.d.ts +5 -0
  233. package/dist/types/src/operations/revert-workspace.d.ts.map +1 -0
  234. package/dist/types/src/operations/scroll-into-view.d.ts +5 -0
  235. package/dist/types/src/operations/scroll-into-view.d.ts.map +1 -0
  236. package/dist/types/src/operations/set-layout-mode.d.ts +9 -0
  237. package/dist/types/src/operations/set-layout-mode.d.ts.map +1 -0
  238. package/dist/types/src/operations/set.d.ts +5 -0
  239. package/dist/types/src/operations/set.d.ts.map +1 -0
  240. package/dist/types/src/operations/switch-workspace.d.ts +5 -0
  241. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -0
  242. package/dist/types/src/operations/update-companion.d.ts +5 -0
  243. package/dist/types/src/operations/update-companion.d.ts.map +1 -0
  244. package/dist/types/src/operations/update-complementary.d.ts +5 -0
  245. package/dist/types/src/operations/update-complementary.d.ts.map +1 -0
  246. package/dist/types/src/operations/update-dialog.d.ts +5 -0
  247. package/dist/types/src/operations/update-dialog.d.ts.map +1 -0
  248. package/dist/types/src/operations/update-plank-size.d.ts +5 -0
  249. package/dist/types/src/operations/update-plank-size.d.ts.map +1 -0
  250. package/dist/types/src/operations/update-popover.d.ts +5 -0
  251. package/dist/types/src/operations/update-popover.d.ts.map +1 -0
  252. package/dist/types/src/operations/update-sidebar.d.ts +5 -0
  253. package/dist/types/src/operations/update-sidebar.d.ts.map +1 -0
  254. package/dist/types/src/plugin.d.ts +4 -0
  255. package/dist/types/src/plugin.d.ts.map +1 -0
  256. package/dist/types/src/translations.d.ts +48 -55
  257. package/dist/types/src/translations.d.ts.map +1 -1
  258. package/dist/types/src/types/DeckCapabilities.d.ts +188 -0
  259. package/dist/types/src/types/DeckCapabilities.d.ts.map +1 -0
  260. package/dist/types/src/types/DeckEvents.d.ts +5 -0
  261. package/dist/types/src/types/DeckEvents.d.ts.map +1 -0
  262. package/dist/types/src/types/DeckOperation.d.ts +15 -0
  263. package/dist/types/src/types/DeckOperation.d.ts.map +1 -0
  264. package/dist/types/src/types/Settings.d.ts +10 -0
  265. package/dist/types/src/types/Settings.d.ts.map +1 -0
  266. package/dist/types/src/types/index.d.ts +4 -0
  267. package/dist/types/src/types/index.d.ts.map +1 -1
  268. package/dist/types/src/types/schema.d.ts +69 -69
  269. package/dist/types/src/types/schema.d.ts.map +1 -1
  270. package/dist/types/src/util/index.d.ts +2 -1
  271. package/dist/types/src/util/index.d.ts.map +1 -1
  272. package/dist/types/src/util/layoutAppliesTopbar.d.ts +1 -1
  273. package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -1
  274. package/dist/types/src/util/plank-url-params.d.ts +14 -0
  275. package/dist/types/src/util/plank-url-params.d.ts.map +1 -0
  276. package/dist/types/src/util/plank-url-params.test.d.ts +2 -0
  277. package/dist/types/src/util/plank-url-params.test.d.ts.map +1 -0
  278. package/dist/types/src/util/sanitize-persisted-state.d.ts +19 -0
  279. package/dist/types/src/util/sanitize-persisted-state.d.ts.map +1 -0
  280. package/dist/types/src/util/sanitize-persisted-state.test.d.ts +2 -0
  281. package/dist/types/src/util/sanitize-persisted-state.test.d.ts.map +1 -0
  282. package/dist/types/src/util/set-active.d.ts +19 -4
  283. package/dist/types/src/util/set-active.d.ts.map +1 -1
  284. package/dist/types/src/util/set-active.test.d.ts +2 -0
  285. package/dist/types/src/util/set-active.test.d.ts.map +1 -0
  286. package/dist/types/tsconfig.tsbuildinfo +1 -1
  287. package/package.json +126 -62
  288. package/src/DeckPlugin.node.ts +17 -0
  289. package/src/DeckPlugin.test.ts +27 -0
  290. package/src/DeckPlugin.ts +43 -56
  291. package/src/DeckPlugin.workerd.ts +16 -0
  292. package/src/capabilities/app-graph-builder.ts +111 -127
  293. package/src/capabilities/check-app-scheme.ts +123 -24
  294. package/src/capabilities/index.ts +14 -14
  295. package/src/capabilities/notification-tracker.ts +170 -0
  296. package/src/capabilities/operation-handler.ts +16 -0
  297. package/src/capabilities/react-root.tsx +40 -28
  298. package/src/capabilities/react-surface.tsx +28 -22
  299. package/src/capabilities/settings.ts +29 -20
  300. package/src/capabilities/state.ts +74 -96
  301. package/src/capabilities/tools.ts +57 -50
  302. package/src/capabilities/url-handler.ts +290 -48
  303. package/src/components/DeckSettings/DeckSettings.stories.tsx +37 -0
  304. package/src/components/DeckSettings/DeckSettings.tsx +19 -88
  305. package/src/components/DeckSettings/index.ts +2 -2
  306. package/src/components/Matrix/Matrix.stories.tsx +220 -0
  307. package/src/components/Matrix/Matrix.tsx +205 -0
  308. package/src/components/Matrix/SPEC.md +219 -0
  309. package/src/components/Matrix/index.ts +6 -0
  310. package/src/components/index.ts +6 -3
  311. package/src/containers/Deck/Banner.tsx +41 -0
  312. package/src/containers/Deck/Deck.stories.tsx +81 -0
  313. package/src/containers/Deck/Deck.tsx +21 -0
  314. package/src/containers/Deck/DeckContent.tsx +102 -0
  315. package/src/containers/Deck/DeckRoot.tsx +50 -0
  316. package/src/containers/Deck/DeckViewport.tsx +450 -0
  317. package/src/{components/DeckLayout → containers/Deck}/StatusBar.tsx +4 -4
  318. package/src/containers/Deck/index.ts +5 -0
  319. package/src/{components → containers}/DeckLayout/ActiveNode.tsx +9 -4
  320. package/src/containers/DeckLayout/DeckLayout.stories.tsx +395 -0
  321. package/src/containers/DeckLayout/DeckLayout.tsx +62 -0
  322. package/src/containers/DeckLayout/Dialog.tsx +52 -0
  323. package/src/containers/DeckLayout/Fallback.tsx +24 -0
  324. package/src/containers/DeckLayout/Popover.tsx +166 -0
  325. package/src/containers/DeckLayout/Toast.tsx +76 -0
  326. package/src/{components → containers}/DeckLayout/constants.ts +1 -0
  327. package/src/{components → containers}/DeckLayout/index.ts +3 -2
  328. package/src/containers/Plank/Plank.stories.tsx +108 -0
  329. package/src/containers/Plank/Plank.tsx +22 -0
  330. package/src/containers/Plank/PlankComponent.tsx +223 -0
  331. package/src/containers/Plank/PlankContent.tsx +45 -0
  332. package/src/{components → containers}/Plank/PlankControls.tsx +43 -37
  333. package/src/containers/Plank/PlankError.tsx +82 -0
  334. package/src/{components → containers}/Plank/PlankHeading.tsx +67 -64
  335. package/src/{components → containers}/Plank/PlankLoading.tsx +1 -1
  336. package/src/containers/Plank/PlankRoot.tsx +49 -0
  337. package/src/{components → containers}/Plank/index.ts +0 -2
  338. package/src/containers/Sidebar/ComplementarySidebar.tsx +189 -0
  339. package/src/containers/Sidebar/Sidebar.tsx +39 -0
  340. package/src/containers/Sidebar/SidebarButton.tsx +100 -0
  341. package/src/containers/index.ts +11 -0
  342. package/src/hooks/index.ts +2 -1
  343. package/src/hooks/useCompanions.ts +3 -3
  344. package/src/hooks/useDeckCompanions.ts +8 -11
  345. package/src/hooks/useDeckState.ts +73 -0
  346. package/src/hooks/useMainSize.ts +2 -2
  347. package/src/hooks/useNodeActionExpander.ts +4 -4
  348. package/src/hooks/useSelectedCompanion.ts +32 -0
  349. package/src/index.ts +1 -4
  350. package/src/layout.test.ts +59 -0
  351. package/src/layout.ts +38 -40
  352. package/src/meta.ts +24 -6
  353. package/src/operations/add-toast.ts +24 -0
  354. package/src/operations/adjust.ts +82 -0
  355. package/src/operations/close.ts +35 -0
  356. package/src/operations/helpers.ts +22 -0
  357. package/src/operations/index.ts +23 -0
  358. package/src/operations/open.ts +201 -0
  359. package/src/operations/revert-workspace.ts +22 -0
  360. package/src/operations/scroll-into-view.ts +24 -0
  361. package/src/operations/set-layout-mode.ts +84 -0
  362. package/src/operations/set.ts +36 -0
  363. package/src/operations/switch-workspace.ts +66 -0
  364. package/src/operations/update-companion.ts +35 -0
  365. package/src/operations/update-complementary.ts +33 -0
  366. package/src/operations/update-dialog.ts +34 -0
  367. package/src/operations/update-plank-size.ts +28 -0
  368. package/src/operations/update-popover.ts +36 -0
  369. package/src/operations/update-sidebar.ts +28 -0
  370. package/src/plugin.ts +11 -0
  371. package/src/translations.ts +48 -54
  372. package/src/types/DeckCapabilities.ts +34 -0
  373. package/src/types/DeckEvents.ts +21 -0
  374. package/src/types/DeckOperation.ts +56 -0
  375. package/src/types/Settings.ts +36 -0
  376. package/src/types/index.ts +5 -0
  377. package/src/types/schema.ts +49 -58
  378. package/src/util/index.ts +2 -1
  379. package/src/util/layoutAppliesTopbar.ts +2 -2
  380. package/src/util/plank-url-params.test.ts +85 -0
  381. package/src/util/plank-url-params.ts +36 -0
  382. package/src/util/sanitize-persisted-state.test.ts +79 -0
  383. package/src/util/sanitize-persisted-state.ts +52 -0
  384. package/src/util/set-active.test.ts +106 -0
  385. package/src/util/set-active.ts +50 -30
  386. package/src/vite-env.d.ts +10 -0
  387. package/dist/lib/browser/app-graph-builder-D74NTOMK.mjs +0 -128
  388. package/dist/lib/browser/app-graph-builder-D74NTOMK.mjs.map +0 -7
  389. package/dist/lib/browser/check-app-scheme-HIEVFAAX.mjs +0 -32
  390. package/dist/lib/browser/check-app-scheme-HIEVFAAX.mjs.map +0 -7
  391. package/dist/lib/browser/chunk-5KMJPIQC.mjs +0 -16
  392. package/dist/lib/browser/chunk-5KMJPIQC.mjs.map +0 -7
  393. package/dist/lib/browser/chunk-CNTGBCMK.mjs +0 -145
  394. package/dist/lib/browser/chunk-CNTGBCMK.mjs.map +0 -7
  395. package/dist/lib/browser/chunk-F3VCCHVL.mjs +0 -162
  396. package/dist/lib/browser/chunk-F3VCCHVL.mjs.map +0 -7
  397. package/dist/lib/browser/chunk-QKCGZ45E.mjs +0 -128
  398. package/dist/lib/browser/chunk-QKCGZ45E.mjs.map +0 -7
  399. package/dist/lib/browser/chunk-UXLU6CMW.mjs +0 -16
  400. package/dist/lib/browser/chunk-UXLU6CMW.mjs.map +0 -7
  401. package/dist/lib/browser/chunk-VBYJ664A.mjs +0 -132
  402. package/dist/lib/browser/chunk-VBYJ664A.mjs.map +0 -7
  403. package/dist/lib/browser/chunk-VUJ6UNIJ.mjs +0 -1553
  404. package/dist/lib/browser/chunk-VUJ6UNIJ.mjs.map +0 -7
  405. package/dist/lib/browser/index.mjs +0 -174
  406. package/dist/lib/browser/index.mjs.map +0 -7
  407. package/dist/lib/browser/intent-resolver-UA4YQGAC.mjs +0 -524
  408. package/dist/lib/browser/intent-resolver-UA4YQGAC.mjs.map +0 -7
  409. package/dist/lib/browser/meta.json +0 -1
  410. package/dist/lib/browser/react-root-JAMHKYWN.mjs +0 -44
  411. package/dist/lib/browser/react-root-JAMHKYWN.mjs.map +0 -7
  412. package/dist/lib/browser/react-surface-6LW337ZT.mjs +0 -40
  413. package/dist/lib/browser/react-surface-6LW337ZT.mjs.map +0 -7
  414. package/dist/lib/browser/settings-SDPTOCCM.mjs +0 -30
  415. package/dist/lib/browser/settings-SDPTOCCM.mjs.map +0 -7
  416. package/dist/lib/browser/state-7IFAGZQO.mjs +0 -12
  417. package/dist/lib/browser/toolkit-L5CFXJCF.mjs +0 -52
  418. package/dist/lib/browser/toolkit-L5CFXJCF.mjs.map +0 -7
  419. package/dist/lib/browser/types/index.mjs +0 -32
  420. package/dist/lib/browser/url-handler-QEYGYE2H.mjs +0 -70
  421. package/dist/lib/browser/url-handler-QEYGYE2H.mjs.map +0 -7
  422. package/dist/types/src/capabilities/capabilities.d.ts +0 -184
  423. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  424. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  425. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  426. package/dist/types/src/capabilities/toolkit.d.ts +0 -25
  427. package/dist/types/src/capabilities/toolkit.d.ts.map +0 -1
  428. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +0 -1
  429. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +0 -1
  430. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts +0 -3
  431. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +0 -1
  432. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +0 -1
  433. package/dist/types/src/components/DeckLayout/DeckLayout.stories.d.ts +0 -74
  434. package/dist/types/src/components/DeckLayout/DeckLayout.stories.d.ts.map +0 -1
  435. package/dist/types/src/components/DeckLayout/DeckMain.d.ts +0 -3
  436. package/dist/types/src/components/DeckLayout/DeckMain.d.ts.map +0 -1
  437. package/dist/types/src/components/DeckLayout/Dialog.d.ts.map +0 -1
  438. package/dist/types/src/components/DeckLayout/Fallback.d.ts +0 -3
  439. package/dist/types/src/components/DeckLayout/Fallback.d.ts.map +0 -1
  440. package/dist/types/src/components/DeckLayout/Popover.d.ts +0 -5
  441. package/dist/types/src/components/DeckLayout/Popover.d.ts.map +0 -1
  442. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +0 -1
  443. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +0 -1
  444. package/dist/types/src/components/DeckLayout/Topbar.d.ts +0 -3
  445. package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +0 -1
  446. package/dist/types/src/components/DeckLayout/constants.d.ts.map +0 -1
  447. package/dist/types/src/components/DeckLayout/index.d.ts +0 -4
  448. package/dist/types/src/components/DeckLayout/index.d.ts.map +0 -1
  449. package/dist/types/src/components/Plank/Plank.d.ts +0 -27
  450. package/dist/types/src/components/Plank/Plank.d.ts.map +0 -1
  451. package/dist/types/src/components/Plank/Plank.stories.d.ts +0 -89
  452. package/dist/types/src/components/Plank/Plank.stories.d.ts.map +0 -1
  453. package/dist/types/src/components/Plank/PlankControls.d.ts.map +0 -1
  454. package/dist/types/src/components/Plank/PlankError.d.ts +0 -13
  455. package/dist/types/src/components/Plank/PlankError.d.ts.map +0 -1
  456. package/dist/types/src/components/Plank/PlankHeading.d.ts.map +0 -1
  457. package/dist/types/src/components/Plank/index.d.ts +0 -6
  458. package/dist/types/src/components/Plank/index.d.ts.map +0 -1
  459. package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +0 -1
  460. package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +0 -1
  461. package/dist/types/src/components/Sidebar/SidebarButton.d.ts.map +0 -1
  462. package/dist/types/src/components/fragments.d.ts +0 -4
  463. package/dist/types/src/components/fragments.d.ts.map +0 -1
  464. package/dist/types/src/events.d.ts +0 -4
  465. package/dist/types/src/events.d.ts.map +0 -1
  466. package/dist/types/src/hooks/useHoistStatusbar.d.ts +0 -3
  467. package/dist/types/src/hooks/useHoistStatusbar.d.ts.map +0 -1
  468. package/dist/types/src/util/overscroll.d.ts +0 -47
  469. package/dist/types/src/util/overscroll.d.ts.map +0 -1
  470. package/src/capabilities/capabilities.ts +0 -14
  471. package/src/capabilities/intent-resolver.ts +0 -471
  472. package/src/capabilities/toolkit.ts +0 -66
  473. package/src/components/DeckLayout/Banner.tsx +0 -39
  474. package/src/components/DeckLayout/ContentEmpty.tsx +0 -31
  475. package/src/components/DeckLayout/DeckLayout.stories.tsx +0 -63
  476. package/src/components/DeckLayout/DeckLayout.tsx +0 -32
  477. package/src/components/DeckLayout/DeckMain.tsx +0 -281
  478. package/src/components/DeckLayout/Dialog.tsx +0 -36
  479. package/src/components/DeckLayout/Fallback.tsx +0 -28
  480. package/src/components/DeckLayout/Popover.tsx +0 -95
  481. package/src/components/DeckLayout/Toast.tsx +0 -86
  482. package/src/components/DeckLayout/Topbar.tsx +0 -11
  483. package/src/components/Plank/Plank.stories.tsx +0 -54
  484. package/src/components/Plank/Plank.tsx +0 -299
  485. package/src/components/Plank/PlankError.tsx +0 -49
  486. package/src/components/Sidebar/ComplementarySidebar.tsx +0 -214
  487. package/src/components/Sidebar/Sidebar.tsx +0 -42
  488. package/src/components/Sidebar/SidebarButton.tsx +0 -88
  489. package/src/components/fragments.ts +0 -14
  490. package/src/events.ts +0 -11
  491. package/src/hooks/useHoistStatusbar.ts +0 -27
  492. package/src/util/overscroll.ts +0 -69
  493. /package/dist/lib/{browser/state-7IFAGZQO.mjs.map → neutral/check-app-scheme-INSOF72J.mjs.map} +0 -0
  494. /package/dist/lib/{browser/types/index.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
  495. /package/dist/types/src/{components/DeckLayout → containers/Deck}/StatusBar.d.ts +0 -0
  496. /package/dist/types/src/{components → containers}/DeckLayout/ActiveNode.d.ts +0 -0
  497. /package/dist/types/src/{components → containers}/DeckLayout/DeckLayout.d.ts +0 -0
  498. /package/dist/types/src/{components → containers}/DeckLayout/Dialog.d.ts +0 -0
  499. /package/dist/types/src/{components → containers}/DeckLayout/constants.d.ts +0 -0
  500. /package/dist/types/src/{components → containers}/Plank/PlankLoading.d.ts +0 -0
  501. /package/dist/types/src/{components → containers}/Sidebar/ComplementarySidebar.d.ts +0 -0
  502. /package/dist/types/src/{components → containers}/Sidebar/Sidebar.d.ts +0 -0
  503. /package/dist/types/src/{components → containers}/Sidebar/index.d.ts +0 -0
  504. /package/src/{components → containers}/Sidebar/index.ts +0 -0
@@ -2,142 +2,126 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Atom } from '@effect-atom/atom-react';
6
- import * as Function from 'effect/Function';
7
- import * as Option from 'effect/Option';
5
+ import * as Effect from 'effect/Effect';
8
6
 
9
- import { Capabilities, LayoutAction, type PluginContext, contributes, createIntent } from '@dxos/app-framework';
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { AppCapabilities, AppNode, LayoutOperation } from '@dxos/app-toolkit';
9
+ import { Operation } from '@dxos/compute';
10
10
  import { AttentionCapabilities } from '@dxos/plugin-attention';
11
- import { ROOT_ID, atomFromSignal, createExtension } from '@dxos/plugin-graph';
11
+ import { GraphBuilder, NodeMatcher } from '@dxos/plugin-graph';
12
12
 
13
- import { meta } from '../meta';
13
+ import { meta } from '#meta';
14
+ import { DeckCapabilities } from '#types';
14
15
 
15
- import { DeckCapabilities } from './capabilities';
16
+ export default Capability.makeModule(
17
+ Effect.fnUntraced(function* () {
18
+ const extensions = yield* Effect.all([
19
+ GraphBuilder.createExtension({
20
+ id: 'notFound',
21
+ match: NodeMatcher.whenRoot,
22
+ connector: () => Effect.succeed([AppNode.makeNotFound()]),
23
+ }),
16
24
 
17
- export default (context: PluginContext) =>
18
- contributes(
19
- Capabilities.AppGraphBuilder,
20
- createExtension({
21
- id: meta.id,
22
- actions: (node) =>
23
- Atom.make((get) =>
24
- Function.pipe(
25
- get(node),
26
- Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
27
- Option.map(() => {
28
- const state = context.getCapability(DeckCapabilities.MutableDeckState);
25
+ GraphBuilder.createExtension({
26
+ id: 'root',
27
+ match: NodeMatcher.whenRoot,
28
+ actions: (_node, get) =>
29
+ Effect.gen(function* () {
30
+ // NOTE(Zan): This is currently disabled.
31
+ // TODO(Zan): Fullscreen needs to know the active node and provide that to the layout part.
32
+ // const _fullscreen = {
33
+ // id: `${LayoutAction.UpdateLayout._tag}/fullscreen`,
34
+ // data: async () => {
35
+ // const { dispatchPromise: dispatch } = context.get(Capabilities.IntentDispatcher);
36
+ // await dispatch(
37
+ // createIntent(LayoutAction.SetLayoutMode, { part: 'mode', options: { mode: 'fullscreen' } }),
38
+ // );
39
+ // },
40
+ // properties: {
41
+ // label: ['toggle-fullscreen.label', { ns: meta.id }],
42
+ // icon: 'ph--arrows-out--regular',
43
+ // keyBinding: {
44
+ // macos: 'ctrl+meta+f',
45
+ // windows: 'shift+ctrl+f',
46
+ // },
47
+ // },
48
+ // };
29
49
 
30
- // NOTE(Zan): This is currently disabled.
31
- // TODO(Zan): Fullscreen needs to know the active node and provide that to the layout part.
32
- // const _fullscreen = {
33
- // id: `${LayoutAction.UpdateLayout._tag}/fullscreen`,
34
- // data: async () => {
35
- // const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
36
- // await dispatch(
37
- // createIntent(LayoutAction.SetLayoutMode, { part: 'mode', options: { mode: 'fullscreen' } }),
38
- // );
39
- // },
40
- // properties: {
41
- // label: ['toggle fullscreen label', { ns: meta.id }],
42
- // icon: 'ph--arrows-out--regular',
43
- // keyBinding: {
44
- // macos: 'ctrl+meta+f',
45
- // windows: 'shift+ctrl+f',
46
- // },
47
- // },
48
- // };
50
+ const closeCurrent = {
51
+ id: `${LayoutOperation.Close.meta.key}.current`,
52
+ data: Effect.fnUntraced(function* () {
53
+ const attention = yield* Capability.get(AttentionCapabilities.Attention);
54
+ const attended = attention.getCurrent().at(-1);
55
+ if (attended) {
56
+ yield* Operation.invoke(LayoutOperation.Close, { subject: [attended] });
57
+ }
58
+ }),
59
+ properties: {
60
+ label: ['close-current.label', { ns: meta.id }],
61
+ icon: 'ph--x--regular',
62
+ },
63
+ };
49
64
 
50
- const closeCurrent = {
51
- id: `${LayoutAction.Close._tag}/current`,
52
- data: async () => {
53
- const attention = context.getCapability(AttentionCapabilities.Attention);
54
- const attended = attention.current.at(-1);
55
- if (attended) {
56
- const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
57
- await dispatch(
58
- createIntent(LayoutAction.Close, {
59
- part: 'main',
60
- subject: [attended],
61
- options: { state: false },
62
- }),
63
- );
64
- }
65
- },
66
- properties: {
67
- label: ['close current label', { ns: meta.id }],
68
- icon: 'ph--x--regular',
69
- },
70
- };
65
+ const closeOthers = {
66
+ id: `${LayoutOperation.Close.meta.key}.others`,
67
+ data: Effect.fnUntraced(function* () {
68
+ const attention = yield* Capability.get(AttentionCapabilities.Attention);
69
+ const deck = yield* DeckCapabilities.getDeck();
70
+ const attended = attention.getCurrent().at(-1);
71
+ const ids = deck.active.filter((id: string) => id !== attended) ?? [];
72
+ yield* Operation.invoke(LayoutOperation.Close, { subject: ids });
73
+ }),
74
+ properties: {
75
+ label: ['close-others.label', { ns: meta.id }],
76
+ icon: 'ph--x-square--regular',
77
+ },
78
+ };
71
79
 
72
- const closeOthers = {
73
- id: `${LayoutAction.Close._tag}/others`,
74
- data: async () => {
75
- const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
76
- const attention = context.getCapability(AttentionCapabilities.Attention);
77
- const attended = attention.current.at(-1);
78
- const ids = state.deck.active.filter((id) => id !== attended) ?? [];
79
- await dispatch(
80
- createIntent(LayoutAction.Close, { part: 'main', subject: ids, options: { state: false } }),
81
- );
82
- },
83
- properties: {
84
- label: ['close others label', { ns: meta.id }],
85
- icon: 'ph--x-square--regular',
86
- },
87
- };
80
+ const closeAll = {
81
+ id: `${LayoutOperation.Close.meta.key}.all`,
82
+ data: Effect.fnUntraced(function* () {
83
+ const deck = yield* DeckCapabilities.getDeck();
84
+ yield* Operation.invoke(LayoutOperation.Close, { subject: deck.active });
85
+ }),
86
+ properties: {
87
+ label: ['close-all.label', { ns: meta.id }],
88
+ icon: 'ph--x-circle--regular',
89
+ },
90
+ };
88
91
 
89
- const closeAll = {
90
- id: `${LayoutAction.Close._tag}/all`,
91
- data: async () => {
92
- const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
93
- await dispatch(
94
- createIntent(LayoutAction.Close, {
95
- part: 'main',
96
- subject: state.deck.active,
97
- options: { state: false },
98
- }),
99
- );
100
- },
101
- properties: {
102
- label: ['close all label', { ns: meta.id }],
103
- icon: 'ph--x-circle--regular',
104
- },
105
- };
92
+ const state = get(yield* Capability.get(DeckCapabilities.State));
93
+ const deck = state.decks[state.activeDeck];
106
94
 
107
- const toggleSidebar = {
108
- id: `${LayoutAction.UpdateSidebar._tag}/nav`,
109
- data: async () => {
110
- state.sidebarState = state.sidebarState === 'expanded' ? 'collapsed' : 'expanded';
95
+ const toggleSidebar = {
96
+ id: `${LayoutOperation.UpdateSidebar.meta.key}.nav`,
97
+ data: Effect.fnUntraced(function* () {
98
+ yield* Capabilities.updateAtomValue(DeckCapabilities.State, (s) => ({
99
+ ...s,
100
+ sidebarState: s.sidebarState === 'expanded' ? ('collapsed' as const) : ('expanded' as const),
101
+ }));
102
+ }),
103
+ properties: {
104
+ label: [
105
+ state.sidebarState === 'expanded'
106
+ ? 'collapse-navigation-sidebar.label'
107
+ : 'open-navigation-sidebar.label',
108
+ { ns: meta.id },
109
+ ],
110
+ icon: 'ph--sidebar--regular',
111
+ keyBinding: {
112
+ macos: "meta+'",
111
113
  },
112
- properties: {
113
- label: [
114
- get(
115
- atomFromSignal(() =>
116
- state.sidebarState === 'expanded'
117
- ? 'collapse navigation sidebar label'
118
- : 'open navigation sidebar label',
119
- ),
120
- ),
121
- { ns: meta.id },
122
- ],
123
- icon: 'ph--sidebar--regular',
124
- keyBinding: {
125
- macos: "meta+'",
126
- },
127
- disposition: 'pin-end',
128
- position: 'hoist',
129
- l0Breakpoint: 'lg',
130
- },
131
- };
114
+ disposition: 'pin-end',
115
+ position: 'last',
116
+ l0Breakpoint: 'lg',
117
+ },
118
+ };
119
+
120
+ return !deck?.solo ? [closeCurrent, closeOthers, closeAll, toggleSidebar] : [toggleSidebar];
121
+ }),
122
+ }),
123
+ ]);
132
124
 
133
- return get(
134
- atomFromSignal(() =>
135
- !state.deck.solo ? [closeCurrent, closeOthers, closeAll, toggleSidebar] : [toggleSidebar],
136
- ),
137
- );
138
- }),
139
- Option.getOrElse(() => []),
140
- ),
141
- ),
142
- }),
143
- );
125
+ return Capability.contributes(AppCapabilities.AppGraphBuilder, extensions.flat());
126
+ }),
127
+ );
@@ -2,39 +2,138 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, type PluginContext, contributes } from '@dxos/app-framework';
5
+ import * as Effect from 'effect/Effect';
6
6
 
7
- import { meta } from '../meta';
8
- import { type DeckSettingsProps } from '../types';
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { APP_SCHEME, AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
9
+ import { EffectEx } from '@dxos/effect';
10
+ import { isTauri } from '@dxos/util';
9
11
 
10
- const isSocket = !!(globalThis as any).__args;
12
+ import { DeckCapabilities } from '#types';
11
13
 
12
- // TODO(mjamesderocher): Can we get this directly from Socket?
13
- const appScheme = 'composer://';
14
+ /** Identifier for the native redirect dialog surface (defined in welcome plugin). */
15
+ const NATIVE_REDIRECT_DIALOG = 'org.dxos.plugin.welcome.component.native-redirect-dialog';
14
16
 
15
- // TODO(mjamesderocher): Factor out as part of NavigationPlugin.
16
- const checkAppScheme = (url: string) => {
17
- const iframe = document.createElement('iframe');
18
- iframe.style.display = 'none';
19
- document.body.appendChild(iframe);
17
+ const SCHEME_TIMEOUT_MS = 500;
20
18
 
21
- iframe.src = url + window.location.pathname.replace(/^\/+/, '') + window.location.search;
19
+ const isSafari = (): boolean => {
20
+ const ua = navigator.userAgent;
21
+ return ua.includes('Safari') && !ua.includes('Chrome') && !ua.includes('Chromium');
22
+ };
23
+
24
+ /** Check if the current page URL can be converted to a valid custom scheme URL. */
25
+ const canRedirectToScheme = (): boolean => {
26
+ try {
27
+ const schemeUrl = APP_SCHEME + window.location.pathname.replace(/^\/+/, '') + window.location.search;
28
+ new URL(schemeUrl);
29
+ return true;
30
+ } catch {
31
+ return false;
32
+ }
33
+ };
34
+
35
+ /**
36
+ * Try to open the native app via custom scheme.
37
+ * Resolves `true` if the app opened (page lost focus), `false` if it didn't within the timeout.
38
+ */
39
+ const tryOpenNativeApp = (): Promise<boolean> => {
40
+ return new Promise((resolve) => {
41
+ let resolved = false;
42
+
43
+ const onBlur = () => {
44
+ if (!resolved) {
45
+ resolved = true;
46
+ cleanup();
47
+ resolve(true);
48
+ }
49
+ };
50
+
51
+ const cleanup = () => {
52
+ window.removeEventListener('blur', onBlur);
53
+ document.removeEventListener('visibilitychange', onVisibilityChange);
54
+ };
22
55
 
23
- const timer = setTimeout(() => {
24
- document.body.removeChild(iframe);
25
- }, 3000);
56
+ const onVisibilityChange = () => {
57
+ if (document.hidden) {
58
+ onBlur();
59
+ }
60
+ };
26
61
 
27
- window.addEventListener('pagehide', (event) => {
28
- clearTimeout(timer);
29
- document.body.removeChild(iframe);
62
+ window.addEventListener('blur', onBlur);
63
+ document.addEventListener('visibilitychange', onVisibilityChange);
64
+
65
+ // Try the scheme via hidden iframe.
66
+ const schemeUrl = APP_SCHEME + window.location.pathname.replace(/^\/+/, '') + window.location.search;
67
+ const iframe = document.createElement('iframe');
68
+ iframe.style.display = 'none';
69
+ iframe.src = schemeUrl;
70
+ document.body.appendChild(iframe);
71
+ setTimeout(() => iframe.remove(), 3000);
72
+
73
+ // If no blur within timeout, the app isn't running.
74
+ setTimeout(() => {
75
+ if (!resolved) {
76
+ resolved = true;
77
+ cleanup();
78
+ resolve(false);
79
+ }
80
+ }, SCHEME_TIMEOUT_MS);
30
81
  });
31
82
  };
32
83
 
33
- export default async (context: PluginContext) => {
34
- const settings = context.getCapability(Capabilities.SettingsStore).getStore<DeckSettingsProps>(meta.id)?.value;
35
- if (!isSocket && settings?.enableNativeRedirect) {
36
- checkAppScheme(appScheme);
37
- }
84
+ /** Dispatch all NavigationHandler contributions with the current page URL. */
85
+ const dispatchNavigationHandlers = Effect.fn(function* () {
86
+ const url = new URL(window.location.href);
87
+ const handlers = yield* Capability.getAll(AppCapabilities.NavigationHandler);
88
+ yield* Effect.all(
89
+ handlers.map((handler) => handler(url)),
90
+ { concurrency: 'unbounded' },
91
+ );
92
+ });
38
93
 
39
- return contributes(Capabilities.Null, null);
94
+ /**
95
+ * Checks whether the native redirect setting is enabled and the redirect should be attempted.
96
+ * Exported for the URL handler to decide whether to defer NavigationHandler dispatch.
97
+ */
98
+ export const shouldDeferNavigationHandlers = (): boolean => {
99
+ return !isTauri() && !isSafari() && !import.meta.env.DEV && canRedirectToScheme();
40
100
  };
101
+
102
+ /**
103
+ * When running in a web browser (not Tauri) with native redirect enabled,
104
+ * tries to open the native app via custom scheme. Defers NavigationHandlers
105
+ * to prevent the web app from consuming one-time tokens before the native app.
106
+ *
107
+ * If the app opens: shows dialog with "Open here" callback that dispatches handlers.
108
+ * If the app doesn't open: dispatches handlers immediately.
109
+ * In Safari: universal links handle this natively, so the check is skipped.
110
+ */
111
+ export default Capability.makeModule(
112
+ Effect.fnUntraced(function* () {
113
+ const capabilities = yield* Capability.Service;
114
+ const { invoke } = yield* Capability.get(Capabilities.OperationInvoker);
115
+ const settings = yield* Capabilities.getAtomValue(DeckCapabilities.Settings);
116
+
117
+ if (!settings?.enableNativeRedirect || !shouldDeferNavigationHandlers()) {
118
+ return;
119
+ }
120
+
121
+ const appOpened = yield* Effect.promise(() => tryOpenNativeApp());
122
+ if (appOpened) {
123
+ const onOpenHere = () =>
124
+ Effect.gen(function* () {
125
+ yield* dispatchNavigationHandlers();
126
+ yield* invoke(LayoutOperation.UpdateDialog, { state: false });
127
+ }).pipe(Effect.provideService(Capability.Service, capabilities), EffectEx.runAndForwardErrors);
128
+
129
+ yield* invoke(LayoutOperation.UpdateDialog, {
130
+ subject: NATIVE_REDIRECT_DIALOG,
131
+ type: 'alert',
132
+ overlayClasses: 'dark bg-neutral-950!',
133
+ props: { onOpenHere },
134
+ });
135
+ } else {
136
+ yield* dispatchNavigationHandlers();
137
+ }
138
+ }),
139
+ );
@@ -2,18 +2,18 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { lazy } from '@dxos/app-framework';
5
+ import { Capability } from '@dxos/app-framework';
6
+ import { OperationHandlerSet } from '@dxos/compute';
6
7
 
7
- export const AppGraphBuilder = lazy(() => import('./app-graph-builder'));
8
- export const CheckAppScheme = lazy(() => import('./check-app-scheme'));
9
- export const DeckSettings = lazy(() => import('./settings'));
10
- export const DeckState = lazy(() => import('./state'));
11
- export const LayoutIntentResolver = lazy(() => import('./intent-resolver'));
12
- export const ReactRoot = lazy(() => import('./react-root'));
13
- export const ReactSurface = lazy(() => import('./react-surface'));
14
- // export const Tools = lazy(() => import('./tools'));
15
- export const Toolkit = lazy(() => import('./toolkit'));
16
- export const UrlHandler = lazy(() => import('./url-handler'));
17
-
18
- export * from './capabilities';
19
- export * from './state';
8
+ export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
9
+ export const CheckAppScheme = Capability.lazy('CheckAppScheme', () => import('./check-app-scheme'));
10
+ export const NotificationTracker = Capability.lazy('NotificationTracker', () => import('./notification-tracker'));
11
+ export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
12
+ 'OperationHandler',
13
+ () => import('./operation-handler'),
14
+ );
15
+ export const ReactRoot = Capability.lazy('ReactRoot', () => import('./react-root'));
16
+ export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
17
+ export const DeckSettings = Capability.lazy('DeckSettings', () => import('./settings'));
18
+ export const DeckState = Capability.lazy('DeckState', () => import('./state'));
19
+ export const UrlHandler = Capability.lazy('UrlHandler', () => import('./url-handler'));
@@ -0,0 +1,170 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Fiber from 'effect/Fiber';
7
+ import * as Stream from 'effect/Stream';
8
+
9
+ import { Capabilities, Capability, type PluginManager } from '@dxos/app-framework';
10
+ import { type LayoutOperation, SettingsOperation } from '@dxos/app-toolkit';
11
+ import { Process } from '@dxos/compute';
12
+
13
+ import { meta } from '#meta';
14
+ import { DeckCapabilities } from '#types';
15
+
16
+ const NOTIFY_TOAST_DURATION = 5_000;
17
+ const ERROR_TOAST_DURATION = 10_000;
18
+ const UNDO_TOAST_DURATION = 10_000;
19
+
20
+ /**
21
+ * The single producer of toasts driven by operation invocations:
22
+ * - Per-invoke notifications ride the process monitor: each invocation spawns a process carrying the
23
+ * caller's `notify` config on its params; this tracker watches process state transitions and toasts
24
+ * on start / success / failure.
25
+ * - Undo toasts come from the history tracker's `undoable` stream (it owns the undo registry lookup);
26
+ * the toast action triggers `historyTracker.undoPromise()`.
27
+ */
28
+ export default Capability.makeModule(
29
+ Effect.fnUntraced(function* () {
30
+ const capabilities = yield* Capability.Service;
31
+ const registry = yield* Capability.get(Capabilities.AtomRegistry);
32
+ const ephemeralAtom = yield* Capability.get(DeckCapabilities.EphemeralState);
33
+ const monitor = yield* Capability.get(Capabilities.ProcessMonitor);
34
+ const manager = yield* Capability.get(Capabilities.PluginManager);
35
+ const invoker = yield* Capability.get(Capabilities.OperationInvoker);
36
+
37
+ const addToast = (toast: LayoutOperation.Toast) => {
38
+ const state = registry.get(ephemeralAtom);
39
+ registry.set(ephemeralAtom, { ...state, toasts: [...state.toasts, toast] });
40
+ };
41
+
42
+ //
43
+ // Notifications — driven by the process monitor.
44
+ //
45
+
46
+ // Tracks the last-seen state per process so we only toast on transitions.
47
+ const lastState = new Map<Process.ID, Process.State>();
48
+
49
+ const handleProcesses = (processes: readonly Process.Info[]) => {
50
+ const seen = new Set<Process.ID>();
51
+ for (const process of processes) {
52
+ seen.add(process.pid);
53
+ const previous = lastState.get(process.pid);
54
+ lastState.set(process.pid, process.state);
55
+ if (previous === process.state) {
56
+ continue;
57
+ }
58
+
59
+ const notify = process.params.notify;
60
+ if (!notify) {
61
+ continue;
62
+ }
63
+
64
+ // Transition into RUNNING (the first snapshot may be a pre-RUNNING state like IDLE/HYBERNATING).
65
+ if (previous !== Process.State.RUNNING && process.state === Process.State.RUNNING && notify.start) {
66
+ addToast({ id: `notify-start-${process.pid}`, title: notify.start, duration: NOTIFY_TOAST_DURATION });
67
+ } else if (process.state === Process.State.SUCCEEDED && notify.success) {
68
+ addToast({ id: `notify-success-${process.pid}`, title: notify.success, duration: NOTIFY_TOAST_DURATION });
69
+ } else if (process.state === Process.State.FAILED && notify.error) {
70
+ addToast({
71
+ id: `notify-error-${process.pid}`,
72
+ title: notify.error,
73
+ ...(process.error ? { description: process.error } : {}),
74
+ icon: 'ph--warning--regular',
75
+ duration: ERROR_TOAST_DURATION,
76
+ });
77
+ }
78
+ }
79
+
80
+ // Drop bookkeeping for processes that have left the tree.
81
+ for (const pid of lastState.keys()) {
82
+ if (!seen.has(pid)) {
83
+ lastState.delete(pid);
84
+ }
85
+ }
86
+ };
87
+
88
+ const unsubscribeMonitor = registry.subscribe(monitor.processTreeAtom, handleProcesses);
89
+
90
+ //
91
+ // Plugin failures — show one toast when any plugin fails to activate, with a link to the registry.
92
+ //
93
+
94
+ let hasShownFailureToast = false;
95
+
96
+ const handleFailures = (failures: readonly PluginManager.PluginFailure[]) => {
97
+ if (failures.length === 0) {
98
+ hasShownFailureToast = false;
99
+ return;
100
+ }
101
+ if (hasShownFailureToast) {
102
+ return;
103
+ }
104
+ hasShownFailureToast = true;
105
+ // Replace any stale plugin-failure toast so at most one is ever visible.
106
+ const toast: LayoutOperation.Toast = {
107
+ id: 'plugin-failure',
108
+ title: ['plugin-failure.title', { ns: meta.id }],
109
+ description: ['plugin-failure.description', { ns: meta.id }],
110
+ icon: 'ph--warning--regular',
111
+ duration: ERROR_TOAST_DURATION,
112
+ actionLabel: ['plugin-failure-action.label', { ns: meta.id }],
113
+ actionAlt: ['plugin-failure-action.alt', { ns: meta.id }],
114
+ onAction: () => void invoker.invokePromise(SettingsOperation.OpenPluginRegistry),
115
+ };
116
+ const state = registry.get(ephemeralAtom);
117
+ registry.set(ephemeralAtom, {
118
+ ...state,
119
+ toasts: [...state.toasts.filter((t) => t.id !== 'plugin-failure'), toast],
120
+ });
121
+ };
122
+
123
+ const unsubscribeFailures = registry.subscribe(manager.failed, handleFailures);
124
+
125
+ //
126
+ // Undo — driven by the history tracker's `undoable` stream (it owns the registry lookup).
127
+ //
128
+
129
+ const showUndoToast = (message: LayoutOperation.Toast['title'], onUndo: () => void) => {
130
+ const undoId = `notify-undo-${crypto.randomUUID()}`;
131
+ const state = registry.get(ephemeralAtom);
132
+ // Replace the previous undo toast (only the most recent action can be undone).
133
+ const toasts = state.currentUndoId
134
+ ? state.toasts.filter((toast) => toast.id !== state.currentUndoId)
135
+ : state.toasts;
136
+ const toast: LayoutOperation.Toast = {
137
+ id: undoId,
138
+ title: message ?? ['undo-available.label', { ns: meta.id }],
139
+ duration: UNDO_TOAST_DURATION,
140
+ actionLabel: ['undo-action.label', { ns: meta.id }],
141
+ actionAlt: ['undo-action.alt', { ns: meta.id }],
142
+ closeLabel: ['undo-close.label', { ns: meta.id }],
143
+ onAction: onUndo,
144
+ };
145
+ registry.set(ephemeralAtom, { ...state, currentUndoId: undoId, toasts: [...toasts, toast] });
146
+ };
147
+
148
+ // The history tracker is contributed on ProcessManagerReady, possibly after this module activates;
149
+ // `waitFor` resolves it once available, then we observe its undoable stream.
150
+ const undoFiber = Effect.runFork(
151
+ Effect.gen(function* () {
152
+ const historyTracker = yield* Capability.waitFor(Capabilities.HistoryTracker);
153
+ yield* Stream.fromPubSub(historyTracker.undoable).pipe(
154
+ Stream.runForEach((event) =>
155
+ Effect.sync(() => showUndoToast(event.message, () => void historyTracker.undoPromise())),
156
+ ),
157
+ );
158
+ }).pipe(Effect.provideService(Capability.Service, capabilities)),
159
+ );
160
+
161
+ // Track all subscriptions so they are torn down when the module deactivates.
162
+ return Capability.contributes(Capabilities.Null, null, () =>
163
+ Effect.gen(function* () {
164
+ unsubscribeMonitor();
165
+ unsubscribeFailures();
166
+ yield* Fiber.interrupt(undoFiber);
167
+ }),
168
+ );
169
+ }),
170
+ );
@@ -0,0 +1,16 @@
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 type { OperationHandlerSet } from '@dxos/compute';
9
+
10
+ import { DeckOperationHandlerSet } from '#operations';
11
+
12
+ export default Capability.makeModule<OperationHandlerSet.OperationHandlerSet>(
13
+ Effect.fnUntraced(function* () {
14
+ return Capability.contributes(Capabilities.OperationHandler, DeckOperationHandlerSet);
15
+ }),
16
+ );