@multiplatform.one/backoffice 6.3.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 (414) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +310 -0
  3. package/dist/cjs/chrome/BackofficeAwesomebar.cjs +95 -0
  4. package/dist/cjs/chrome/BackofficeAwesomebar.native.js +106 -0
  5. package/dist/cjs/chrome/BackofficeAwesomebar.native.js.map +1 -0
  6. package/dist/cjs/chrome/CommandPalette.cjs +453 -0
  7. package/dist/cjs/chrome/CommandPalette.native.js +505 -0
  8. package/dist/cjs/chrome/CommandPalette.native.js.map +1 -0
  9. package/dist/cjs/chrome/HelpMenu.cjs +131 -0
  10. package/dist/cjs/chrome/HelpMenu.native.js +145 -0
  11. package/dist/cjs/chrome/HelpMenu.native.js.map +1 -0
  12. package/dist/cjs/chrome/NotificationsButton.cjs +112 -0
  13. package/dist/cjs/chrome/NotificationsButton.native.js +115 -0
  14. package/dist/cjs/chrome/NotificationsButton.native.js.map +1 -0
  15. package/dist/cjs/chrome/UserMenu.cjs +158 -0
  16. package/dist/cjs/chrome/UserMenu.native.js +186 -0
  17. package/dist/cjs/chrome/UserMenu.native.js.map +1 -0
  18. package/dist/cjs/chrome/awesomebar-data.cjs +173 -0
  19. package/dist/cjs/chrome/awesomebar-data.native.js +233 -0
  20. package/dist/cjs/chrome/awesomebar-data.native.js.map +1 -0
  21. package/dist/cjs/chrome/command-palette-model.cjs +208 -0
  22. package/dist/cjs/chrome/command-palette-model.native.js +301 -0
  23. package/dist/cjs/chrome/command-palette-model.native.js.map +1 -0
  24. package/dist/cjs/chrome/help-about-dialog.cjs +136 -0
  25. package/dist/cjs/chrome/help-about-dialog.native.js +146 -0
  26. package/dist/cjs/chrome/help-about-dialog.native.js.map +1 -0
  27. package/dist/cjs/chrome/help-shortcuts-dialog.cjs +155 -0
  28. package/dist/cjs/chrome/help-shortcuts-dialog.native.js +168 -0
  29. package/dist/cjs/chrome/help-shortcuts-dialog.native.js.map +1 -0
  30. package/dist/cjs/chrome/notifications-data.cjs +190 -0
  31. package/dist/cjs/chrome/notifications-data.native.js +271 -0
  32. package/dist/cjs/chrome/notifications-data.native.js.map +1 -0
  33. package/dist/cjs/chrome/notifications-panel.cjs +171 -0
  34. package/dist/cjs/chrome/notifications-panel.native.js +189 -0
  35. package/dist/cjs/chrome/notifications-panel.native.js.map +1 -0
  36. package/dist/cjs/chrome/notifications-utils.cjs +43 -0
  37. package/dist/cjs/chrome/notifications-utils.native.js +46 -0
  38. package/dist/cjs/chrome/notifications-utils.native.js.map +1 -0
  39. package/dist/cjs/chrome/shortcuts.cjs +58 -0
  40. package/dist/cjs/chrome/shortcuts.native.js +72 -0
  41. package/dist/cjs/chrome/shortcuts.native.js.map +1 -0
  42. package/dist/cjs/chrome/user-session.cjs +100 -0
  43. package/dist/cjs/chrome/user-session.native.js +120 -0
  44. package/dist/cjs/chrome/user-session.native.js.map +1 -0
  45. package/dist/cjs/config/BackofficeProvider.cjs +164 -0
  46. package/dist/cjs/config/BackofficeProvider.native.js +217 -0
  47. package/dist/cjs/config/BackofficeProvider.native.js.map +1 -0
  48. package/dist/cjs/config/capabilities.cjs +123 -0
  49. package/dist/cjs/config/capabilities.native.js +155 -0
  50. package/dist/cjs/config/capabilities.native.js.map +1 -0
  51. package/dist/cjs/config/events.cjs +18 -0
  52. package/dist/cjs/config/events.native.js +21 -0
  53. package/dist/cjs/config/events.native.js.map +1 -0
  54. package/dist/cjs/config/slots.cjs +18 -0
  55. package/dist/cjs/config/slots.native.js +21 -0
  56. package/dist/cjs/config/slots.native.js.map +1 -0
  57. package/dist/cjs/i18n/en.cjs +101 -0
  58. package/dist/cjs/i18n/en.native.js +104 -0
  59. package/dist/cjs/i18n/en.native.js.map +1 -0
  60. package/dist/cjs/i18n/index.cjs +77 -0
  61. package/dist/cjs/i18n/index.native.js +102 -0
  62. package/dist/cjs/i18n/index.native.js.map +1 -0
  63. package/dist/cjs/index.cjs +109 -0
  64. package/dist/cjs/index.native.js +112 -0
  65. package/dist/cjs/index.native.js.map +1 -0
  66. package/dist/cjs/navigation/navigator.cjs +144 -0
  67. package/dist/cjs/navigation/navigator.native.js +307 -0
  68. package/dist/cjs/navigation/navigator.native.js.map +1 -0
  69. package/dist/cjs/navigation/paths.cjs +103 -0
  70. package/dist/cjs/navigation/paths.native.js +143 -0
  71. package/dist/cjs/navigation/paths.native.js.map +1 -0
  72. package/dist/cjs/oneAdapter/index.cjs +53 -0
  73. package/dist/cjs/oneAdapter/index.native.js +64 -0
  74. package/dist/cjs/oneAdapter/index.native.js.map +1 -0
  75. package/dist/cjs/shared/useFrappeApp.cjs +56 -0
  76. package/dist/cjs/shared/useFrappeApp.native.js +60 -0
  77. package/dist/cjs/shared/useFrappeApp.native.js.map +1 -0
  78. package/dist/cjs/shell/BackofficeShell.cjs +194 -0
  79. package/dist/cjs/shell/BackofficeShell.native.js +223 -0
  80. package/dist/cjs/shell/BackofficeShell.native.js.map +1 -0
  81. package/dist/cjs/shell/WorkspaceSidebar.cjs +115 -0
  82. package/dist/cjs/shell/WorkspaceSidebar.native.js +143 -0
  83. package/dist/cjs/shell/WorkspaceSidebar.native.js.map +1 -0
  84. package/dist/cjs/shell/useWorkspaces.cjs +131 -0
  85. package/dist/cjs/shell/useWorkspaces.native.js +173 -0
  86. package/dist/cjs/shell/useWorkspaces.native.js.map +1 -0
  87. package/dist/cjs/shell/workspaceIcons.cjs +64 -0
  88. package/dist/cjs/shell/workspaceIcons.native.js +67 -0
  89. package/dist/cjs/shell/workspaceIcons.native.js.map +1 -0
  90. package/dist/esm/chrome/BackofficeAwesomebar.mjs +70 -0
  91. package/dist/esm/chrome/BackofficeAwesomebar.mjs.map +1 -0
  92. package/dist/esm/chrome/BackofficeAwesomebar.native.js +78 -0
  93. package/dist/esm/chrome/BackofficeAwesomebar.native.js.map +1 -0
  94. package/dist/esm/chrome/CommandPalette.mjs +428 -0
  95. package/dist/esm/chrome/CommandPalette.mjs.map +1 -0
  96. package/dist/esm/chrome/CommandPalette.native.js +477 -0
  97. package/dist/esm/chrome/CommandPalette.native.js.map +1 -0
  98. package/dist/esm/chrome/HelpMenu.mjs +106 -0
  99. package/dist/esm/chrome/HelpMenu.mjs.map +1 -0
  100. package/dist/esm/chrome/HelpMenu.native.js +117 -0
  101. package/dist/esm/chrome/HelpMenu.native.js.map +1 -0
  102. package/dist/esm/chrome/NotificationsButton.mjs +87 -0
  103. package/dist/esm/chrome/NotificationsButton.mjs.map +1 -0
  104. package/dist/esm/chrome/NotificationsButton.native.js +87 -0
  105. package/dist/esm/chrome/NotificationsButton.native.js.map +1 -0
  106. package/dist/esm/chrome/UserMenu.mjs +133 -0
  107. package/dist/esm/chrome/UserMenu.mjs.map +1 -0
  108. package/dist/esm/chrome/UserMenu.native.js +147 -0
  109. package/dist/esm/chrome/UserMenu.native.js.map +1 -0
  110. package/dist/esm/chrome/awesomebar-data.mjs +144 -0
  111. package/dist/esm/chrome/awesomebar-data.mjs.map +1 -0
  112. package/dist/esm/chrome/awesomebar-data.native.js +190 -0
  113. package/dist/esm/chrome/awesomebar-data.native.js.map +1 -0
  114. package/dist/esm/chrome/command-palette-model.mjs +183 -0
  115. package/dist/esm/chrome/command-palette-model.mjs.map +1 -0
  116. package/dist/esm/chrome/command-palette-model.native.js +273 -0
  117. package/dist/esm/chrome/command-palette-model.native.js.map +1 -0
  118. package/dist/esm/chrome/help-about-dialog.mjs +111 -0
  119. package/dist/esm/chrome/help-about-dialog.mjs.map +1 -0
  120. package/dist/esm/chrome/help-about-dialog.native.js +118 -0
  121. package/dist/esm/chrome/help-about-dialog.native.js.map +1 -0
  122. package/dist/esm/chrome/help-shortcuts-dialog.mjs +130 -0
  123. package/dist/esm/chrome/help-shortcuts-dialog.mjs.map +1 -0
  124. package/dist/esm/chrome/help-shortcuts-dialog.native.js +140 -0
  125. package/dist/esm/chrome/help-shortcuts-dialog.native.js.map +1 -0
  126. package/dist/esm/chrome/notifications-data.mjs +165 -0
  127. package/dist/esm/chrome/notifications-data.mjs.map +1 -0
  128. package/dist/esm/chrome/notifications-data.native.js +232 -0
  129. package/dist/esm/chrome/notifications-data.native.js.map +1 -0
  130. package/dist/esm/chrome/notifications-panel.mjs +146 -0
  131. package/dist/esm/chrome/notifications-panel.mjs.map +1 -0
  132. package/dist/esm/chrome/notifications-panel.native.js +161 -0
  133. package/dist/esm/chrome/notifications-panel.native.js.map +1 -0
  134. package/dist/esm/chrome/notifications-utils.mjs +17 -0
  135. package/dist/esm/chrome/notifications-utils.mjs.map +1 -0
  136. package/dist/esm/chrome/notifications-utils.native.js +17 -0
  137. package/dist/esm/chrome/notifications-utils.native.js.map +1 -0
  138. package/dist/esm/chrome/shortcuts.mjs +33 -0
  139. package/dist/esm/chrome/shortcuts.mjs.map +1 -0
  140. package/dist/esm/chrome/shortcuts.native.js +44 -0
  141. package/dist/esm/chrome/shortcuts.native.js.map +1 -0
  142. package/dist/esm/chrome/user-session.mjs +73 -0
  143. package/dist/esm/chrome/user-session.mjs.map +1 -0
  144. package/dist/esm/chrome/user-session.native.js +79 -0
  145. package/dist/esm/chrome/user-session.native.js.map +1 -0
  146. package/dist/esm/config/BackofficeProvider.mjs +132 -0
  147. package/dist/esm/config/BackofficeProvider.mjs.map +1 -0
  148. package/dist/esm/config/BackofficeProvider.native.js +171 -0
  149. package/dist/esm/config/BackofficeProvider.native.js.map +1 -0
  150. package/dist/esm/config/capabilities.mjs +97 -0
  151. package/dist/esm/config/capabilities.mjs.map +1 -0
  152. package/dist/esm/config/capabilities.native.js +126 -0
  153. package/dist/esm/config/capabilities.native.js.map +1 -0
  154. package/dist/esm/config/events.mjs +2 -0
  155. package/dist/esm/config/events.mjs.map +1 -0
  156. package/dist/esm/config/events.native.js +2 -0
  157. package/dist/esm/config/events.native.js.map +1 -0
  158. package/dist/esm/config/slots.mjs +2 -0
  159. package/dist/esm/config/slots.mjs.map +1 -0
  160. package/dist/esm/config/slots.native.js +2 -0
  161. package/dist/esm/config/slots.native.js.map +1 -0
  162. package/dist/esm/i18n/en.mjs +76 -0
  163. package/dist/esm/i18n/en.mjs.map +1 -0
  164. package/dist/esm/i18n/en.native.js +76 -0
  165. package/dist/esm/i18n/en.native.js.map +1 -0
  166. package/dist/esm/i18n/index.mjs +40 -0
  167. package/dist/esm/i18n/index.mjs.map +1 -0
  168. package/dist/esm/i18n/index.native.js +62 -0
  169. package/dist/esm/i18n/index.native.js.map +1 -0
  170. package/dist/esm/index.mjs +26 -0
  171. package/dist/esm/index.mjs.map +1 -0
  172. package/dist/esm/index.native.js +26 -0
  173. package/dist/esm/index.native.js.map +1 -0
  174. package/dist/esm/navigation/navigator.mjs +115 -0
  175. package/dist/esm/navigation/navigator.mjs.map +1 -0
  176. package/dist/esm/navigation/navigator.native.js +275 -0
  177. package/dist/esm/navigation/navigator.native.js.map +1 -0
  178. package/dist/esm/navigation/paths.mjs +66 -0
  179. package/dist/esm/navigation/paths.mjs.map +1 -0
  180. package/dist/esm/navigation/paths.native.js +103 -0
  181. package/dist/esm/navigation/paths.native.js.map +1 -0
  182. package/dist/esm/oneAdapter/index.mjs +28 -0
  183. package/dist/esm/oneAdapter/index.mjs.map +1 -0
  184. package/dist/esm/oneAdapter/index.native.js +36 -0
  185. package/dist/esm/oneAdapter/index.native.js.map +1 -0
  186. package/dist/esm/shared/useFrappeApp.mjs +31 -0
  187. package/dist/esm/shared/useFrappeApp.mjs.map +1 -0
  188. package/dist/esm/shared/useFrappeApp.native.js +32 -0
  189. package/dist/esm/shared/useFrappeApp.native.js.map +1 -0
  190. package/dist/esm/shell/BackofficeShell.mjs +169 -0
  191. package/dist/esm/shell/BackofficeShell.mjs.map +1 -0
  192. package/dist/esm/shell/BackofficeShell.native.js +195 -0
  193. package/dist/esm/shell/BackofficeShell.native.js.map +1 -0
  194. package/dist/esm/shell/WorkspaceSidebar.mjs +89 -0
  195. package/dist/esm/shell/WorkspaceSidebar.mjs.map +1 -0
  196. package/dist/esm/shell/WorkspaceSidebar.native.js +114 -0
  197. package/dist/esm/shell/WorkspaceSidebar.native.js.map +1 -0
  198. package/dist/esm/shell/useWorkspaces.mjs +104 -0
  199. package/dist/esm/shell/useWorkspaces.mjs.map +1 -0
  200. package/dist/esm/shell/useWorkspaces.native.js +143 -0
  201. package/dist/esm/shell/useWorkspaces.native.js.map +1 -0
  202. package/dist/esm/shell/workspaceIcons.mjs +39 -0
  203. package/dist/esm/shell/workspaceIcons.mjs.map +1 -0
  204. package/dist/esm/shell/workspaceIcons.native.js +39 -0
  205. package/dist/esm/shell/workspaceIcons.native.js.map +1 -0
  206. package/dist/jsx/chrome/BackofficeAwesomebar.mjs +70 -0
  207. package/dist/jsx/chrome/BackofficeAwesomebar.mjs.map +1 -0
  208. package/dist/jsx/chrome/BackofficeAwesomebar.native.js +106 -0
  209. package/dist/jsx/chrome/BackofficeAwesomebar.native.js.map +1 -0
  210. package/dist/jsx/chrome/CommandPalette.mjs +428 -0
  211. package/dist/jsx/chrome/CommandPalette.mjs.map +1 -0
  212. package/dist/jsx/chrome/CommandPalette.native.js +505 -0
  213. package/dist/jsx/chrome/CommandPalette.native.js.map +1 -0
  214. package/dist/jsx/chrome/HelpMenu.mjs +106 -0
  215. package/dist/jsx/chrome/HelpMenu.mjs.map +1 -0
  216. package/dist/jsx/chrome/HelpMenu.native.js +145 -0
  217. package/dist/jsx/chrome/HelpMenu.native.js.map +1 -0
  218. package/dist/jsx/chrome/NotificationsButton.mjs +87 -0
  219. package/dist/jsx/chrome/NotificationsButton.mjs.map +1 -0
  220. package/dist/jsx/chrome/NotificationsButton.native.js +115 -0
  221. package/dist/jsx/chrome/NotificationsButton.native.js.map +1 -0
  222. package/dist/jsx/chrome/UserMenu.mjs +133 -0
  223. package/dist/jsx/chrome/UserMenu.mjs.map +1 -0
  224. package/dist/jsx/chrome/UserMenu.native.js +186 -0
  225. package/dist/jsx/chrome/UserMenu.native.js.map +1 -0
  226. package/dist/jsx/chrome/awesomebar-data.mjs +144 -0
  227. package/dist/jsx/chrome/awesomebar-data.mjs.map +1 -0
  228. package/dist/jsx/chrome/awesomebar-data.native.js +233 -0
  229. package/dist/jsx/chrome/awesomebar-data.native.js.map +1 -0
  230. package/dist/jsx/chrome/command-palette-model.mjs +183 -0
  231. package/dist/jsx/chrome/command-palette-model.mjs.map +1 -0
  232. package/dist/jsx/chrome/command-palette-model.native.js +301 -0
  233. package/dist/jsx/chrome/command-palette-model.native.js.map +1 -0
  234. package/dist/jsx/chrome/help-about-dialog.mjs +111 -0
  235. package/dist/jsx/chrome/help-about-dialog.mjs.map +1 -0
  236. package/dist/jsx/chrome/help-about-dialog.native.js +146 -0
  237. package/dist/jsx/chrome/help-about-dialog.native.js.map +1 -0
  238. package/dist/jsx/chrome/help-shortcuts-dialog.mjs +130 -0
  239. package/dist/jsx/chrome/help-shortcuts-dialog.mjs.map +1 -0
  240. package/dist/jsx/chrome/help-shortcuts-dialog.native.js +168 -0
  241. package/dist/jsx/chrome/help-shortcuts-dialog.native.js.map +1 -0
  242. package/dist/jsx/chrome/notifications-data.mjs +165 -0
  243. package/dist/jsx/chrome/notifications-data.mjs.map +1 -0
  244. package/dist/jsx/chrome/notifications-data.native.js +271 -0
  245. package/dist/jsx/chrome/notifications-data.native.js.map +1 -0
  246. package/dist/jsx/chrome/notifications-panel.mjs +146 -0
  247. package/dist/jsx/chrome/notifications-panel.mjs.map +1 -0
  248. package/dist/jsx/chrome/notifications-panel.native.js +189 -0
  249. package/dist/jsx/chrome/notifications-panel.native.js.map +1 -0
  250. package/dist/jsx/chrome/notifications-utils.mjs +17 -0
  251. package/dist/jsx/chrome/notifications-utils.mjs.map +1 -0
  252. package/dist/jsx/chrome/notifications-utils.native.js +46 -0
  253. package/dist/jsx/chrome/notifications-utils.native.js.map +1 -0
  254. package/dist/jsx/chrome/shortcuts.mjs +33 -0
  255. package/dist/jsx/chrome/shortcuts.mjs.map +1 -0
  256. package/dist/jsx/chrome/shortcuts.native.js +72 -0
  257. package/dist/jsx/chrome/shortcuts.native.js.map +1 -0
  258. package/dist/jsx/chrome/user-session.mjs +73 -0
  259. package/dist/jsx/chrome/user-session.mjs.map +1 -0
  260. package/dist/jsx/chrome/user-session.native.js +120 -0
  261. package/dist/jsx/chrome/user-session.native.js.map +1 -0
  262. package/dist/jsx/config/BackofficeProvider.mjs +132 -0
  263. package/dist/jsx/config/BackofficeProvider.mjs.map +1 -0
  264. package/dist/jsx/config/BackofficeProvider.native.js +217 -0
  265. package/dist/jsx/config/BackofficeProvider.native.js.map +1 -0
  266. package/dist/jsx/config/capabilities.mjs +97 -0
  267. package/dist/jsx/config/capabilities.mjs.map +1 -0
  268. package/dist/jsx/config/capabilities.native.js +155 -0
  269. package/dist/jsx/config/capabilities.native.js.map +1 -0
  270. package/dist/jsx/config/events.mjs +2 -0
  271. package/dist/jsx/config/events.mjs.map +1 -0
  272. package/dist/jsx/config/events.native.js +21 -0
  273. package/dist/jsx/config/events.native.js.map +1 -0
  274. package/dist/jsx/config/slots.mjs +2 -0
  275. package/dist/jsx/config/slots.mjs.map +1 -0
  276. package/dist/jsx/config/slots.native.js +21 -0
  277. package/dist/jsx/config/slots.native.js.map +1 -0
  278. package/dist/jsx/i18n/en.mjs +76 -0
  279. package/dist/jsx/i18n/en.mjs.map +1 -0
  280. package/dist/jsx/i18n/en.native.js +104 -0
  281. package/dist/jsx/i18n/en.native.js.map +1 -0
  282. package/dist/jsx/i18n/index.mjs +40 -0
  283. package/dist/jsx/i18n/index.mjs.map +1 -0
  284. package/dist/jsx/i18n/index.native.js +102 -0
  285. package/dist/jsx/i18n/index.native.js.map +1 -0
  286. package/dist/jsx/index.js +26 -0
  287. package/dist/jsx/index.js.map +1 -0
  288. package/dist/jsx/index.mjs +26 -0
  289. package/dist/jsx/index.mjs.map +1 -0
  290. package/dist/jsx/index.native.js +112 -0
  291. package/dist/jsx/index.native.js.map +1 -0
  292. package/dist/jsx/navigation/navigator.mjs +115 -0
  293. package/dist/jsx/navigation/navigator.mjs.map +1 -0
  294. package/dist/jsx/navigation/navigator.native.js +307 -0
  295. package/dist/jsx/navigation/navigator.native.js.map +1 -0
  296. package/dist/jsx/navigation/paths.mjs +66 -0
  297. package/dist/jsx/navigation/paths.mjs.map +1 -0
  298. package/dist/jsx/navigation/paths.native.js +143 -0
  299. package/dist/jsx/navigation/paths.native.js.map +1 -0
  300. package/dist/jsx/oneAdapter/index.mjs +28 -0
  301. package/dist/jsx/oneAdapter/index.mjs.map +1 -0
  302. package/dist/jsx/oneAdapter/index.native.js +64 -0
  303. package/dist/jsx/oneAdapter/index.native.js.map +1 -0
  304. package/dist/jsx/shared/useFrappeApp.mjs +31 -0
  305. package/dist/jsx/shared/useFrappeApp.mjs.map +1 -0
  306. package/dist/jsx/shared/useFrappeApp.native.js +60 -0
  307. package/dist/jsx/shared/useFrappeApp.native.js.map +1 -0
  308. package/dist/jsx/shell/BackofficeShell.mjs +169 -0
  309. package/dist/jsx/shell/BackofficeShell.mjs.map +1 -0
  310. package/dist/jsx/shell/BackofficeShell.native.js +223 -0
  311. package/dist/jsx/shell/BackofficeShell.native.js.map +1 -0
  312. package/dist/jsx/shell/WorkspaceSidebar.mjs +89 -0
  313. package/dist/jsx/shell/WorkspaceSidebar.mjs.map +1 -0
  314. package/dist/jsx/shell/WorkspaceSidebar.native.js +143 -0
  315. package/dist/jsx/shell/WorkspaceSidebar.native.js.map +1 -0
  316. package/dist/jsx/shell/useWorkspaces.mjs +104 -0
  317. package/dist/jsx/shell/useWorkspaces.mjs.map +1 -0
  318. package/dist/jsx/shell/useWorkspaces.native.js +173 -0
  319. package/dist/jsx/shell/useWorkspaces.native.js.map +1 -0
  320. package/dist/jsx/shell/workspaceIcons.mjs +39 -0
  321. package/dist/jsx/shell/workspaceIcons.mjs.map +1 -0
  322. package/dist/jsx/shell/workspaceIcons.native.js +67 -0
  323. package/dist/jsx/shell/workspaceIcons.native.js.map +1 -0
  324. package/package.json +123 -0
  325. package/src/chrome/BackofficeAwesomebar.tsx +89 -0
  326. package/src/chrome/CommandPalette.spec.tsx +252 -0
  327. package/src/chrome/CommandPalette.tsx +520 -0
  328. package/src/chrome/HelpMenu.tsx +119 -0
  329. package/src/chrome/NotificationsButton.tsx +87 -0
  330. package/src/chrome/UserMenu.tsx +173 -0
  331. package/src/chrome/awesomebar-data.tsx +252 -0
  332. package/src/chrome/command-palette-model.ts +291 -0
  333. package/src/chrome/help-about-dialog.tsx +130 -0
  334. package/src/chrome/help-shortcuts-dialog.tsx +144 -0
  335. package/src/chrome/notifications-data.tsx +287 -0
  336. package/src/chrome/notifications-panel.tsx +175 -0
  337. package/src/chrome/notifications-utils.tsx +44 -0
  338. package/src/chrome/shortcuts.ts +53 -0
  339. package/src/chrome/user-session.tsx +116 -0
  340. package/src/config/BackofficeProvider.spec.tsx +126 -0
  341. package/src/config/BackofficeProvider.tsx +315 -0
  342. package/src/config/capabilities.ts +172 -0
  343. package/src/config/events.ts +19 -0
  344. package/src/config/slots.ts +28 -0
  345. package/src/i18n/en.ts +83 -0
  346. package/src/i18n/index.ts +69 -0
  347. package/src/index.ts +150 -0
  348. package/src/navigation/navigator.spec.ts +106 -0
  349. package/src/navigation/navigator.ts +209 -0
  350. package/src/navigation/paths.ts +146 -0
  351. package/src/oneAdapter/index.tsx +61 -0
  352. package/src/shared/useFrappeApp.ts +39 -0
  353. package/src/shell/BackofficeShell.tsx +222 -0
  354. package/src/shell/WorkspaceSidebar.tsx +119 -0
  355. package/src/shell/useWorkspaces.ts +202 -0
  356. package/src/shell/workspaceIcons.ts +76 -0
  357. package/types/chrome/BackofficeAwesomebar.d.ts +12 -0
  358. package/types/chrome/BackofficeAwesomebar.d.ts.map +1 -0
  359. package/types/chrome/CommandPalette.d.ts +6 -0
  360. package/types/chrome/CommandPalette.d.ts.map +1 -0
  361. package/types/chrome/HelpMenu.d.ts +2 -0
  362. package/types/chrome/HelpMenu.d.ts.map +1 -0
  363. package/types/chrome/NotificationsButton.d.ts +2 -0
  364. package/types/chrome/NotificationsButton.d.ts.map +1 -0
  365. package/types/chrome/UserMenu.d.ts +6 -0
  366. package/types/chrome/UserMenu.d.ts.map +1 -0
  367. package/types/chrome/awesomebar-data.d.ts +52 -0
  368. package/types/chrome/awesomebar-data.d.ts.map +1 -0
  369. package/types/chrome/command-palette-model.d.ts +47 -0
  370. package/types/chrome/command-palette-model.d.ts.map +1 -0
  371. package/types/chrome/help-about-dialog.d.ts +12 -0
  372. package/types/chrome/help-about-dialog.d.ts.map +1 -0
  373. package/types/chrome/help-shortcuts-dialog.d.ts +6 -0
  374. package/types/chrome/help-shortcuts-dialog.d.ts.map +1 -0
  375. package/types/chrome/notifications-data.d.ts +34 -0
  376. package/types/chrome/notifications-data.d.ts.map +1 -0
  377. package/types/chrome/notifications-panel.d.ts +11 -0
  378. package/types/chrome/notifications-panel.d.ts.map +1 -0
  379. package/types/chrome/notifications-utils.d.ts +21 -0
  380. package/types/chrome/notifications-utils.d.ts.map +1 -0
  381. package/types/chrome/shortcuts.d.ts +6 -0
  382. package/types/chrome/shortcuts.d.ts.map +1 -0
  383. package/types/chrome/user-session.d.ts +19 -0
  384. package/types/chrome/user-session.d.ts.map +1 -0
  385. package/types/config/BackofficeProvider.d.ts +128 -0
  386. package/types/config/BackofficeProvider.d.ts.map +1 -0
  387. package/types/config/capabilities.d.ts +109 -0
  388. package/types/config/capabilities.d.ts.map +1 -0
  389. package/types/config/events.d.ts +39 -0
  390. package/types/config/events.d.ts.map +1 -0
  391. package/types/config/slots.d.ts +32 -0
  392. package/types/config/slots.d.ts.map +1 -0
  393. package/types/i18n/en.d.ts +83 -0
  394. package/types/i18n/en.d.ts.map +1 -0
  395. package/types/i18n/index.d.ts +27 -0
  396. package/types/i18n/index.d.ts.map +1 -0
  397. package/types/index.d.ts +55 -0
  398. package/types/index.d.ts.map +1 -0
  399. package/types/navigation/navigator.d.ts +98 -0
  400. package/types/navigation/navigator.d.ts.map +1 -0
  401. package/types/navigation/paths.d.ts +60 -0
  402. package/types/navigation/paths.d.ts.map +1 -0
  403. package/types/oneAdapter/index.d.ts +8 -0
  404. package/types/oneAdapter/index.d.ts.map +1 -0
  405. package/types/shared/useFrappeApp.d.ts +10 -0
  406. package/types/shared/useFrappeApp.d.ts.map +1 -0
  407. package/types/shell/BackofficeShell.d.ts +10 -0
  408. package/types/shell/BackofficeShell.d.ts.map +1 -0
  409. package/types/shell/WorkspaceSidebar.d.ts +9 -0
  410. package/types/shell/WorkspaceSidebar.d.ts.map +1 -0
  411. package/types/shell/useWorkspaces.d.ts +43 -0
  412. package/types/shell/useWorkspaces.d.ts.map +1 -0
  413. package/types/shell/workspaceIcons.d.ts +9 -0
  414. package/types/shell/workspaceIcons.d.ts.map +1 -0
@@ -0,0 +1,520 @@
1
+ // Command palette (MOD-01) — the backoffice's global search / command
2
+ // surface. One section model (useCommandPaletteModel) rendered through two
3
+ // containers:
4
+ // ≥sm web → centered modal overlay (~640px, top-anchored ~15vh) via the
5
+ // house Dialog surface (LC-06 overlay anatomy, LC-24 transitions)
6
+ // <sm/native → full-height SheetModal (same mechanics as the list tools
7
+ // sheet and the native search sheet)
8
+ //
9
+ // Keyboard-first: the search input is the single tab stop (D-23); ArrowUp/
10
+ // ArrowDown move one roving highlight across sections, Enter opens, Escape
11
+ // closes and returns focus to the pre-open element (D-22). The highlight
12
+ // renders on the accent channel (LC-05). COMMIT-class dismissal (LC-21):
13
+ // picking a row commits and closes; otherwise only backdrop click / Escape
14
+ // dismiss.
15
+ import {
16
+ Dialog,
17
+ DialogContent,
18
+ ScrollView,
19
+ SheetModal,
20
+ SizableText,
21
+ Spinner,
22
+ Text,
23
+ XStack,
24
+ YStack,
25
+ isWeb,
26
+ } from "@multiplatform.one/components";
27
+ import { SearchInput } from "@multiplatform.one/forms";
28
+ import { addToRecent } from "@multiplatform.one/frappe-ui";
29
+ import { useLayoutSizeClass, useReadableTextOn, useResolvedKnobs } from "@multiplatform.one/theme";
30
+ import type { ComponentProps, RefObject } from "react";
31
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
32
+ import { useTranslation } from "react-i18next";
33
+ import { useBackofficeNavigator } from "../config/BackofficeProvider";
34
+ import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
35
+ import {
36
+ useCommandPaletteModel,
37
+ type CommandPaletteItem,
38
+ type CommandPaletteModel,
39
+ } from "./command-palette-model";
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Constants
43
+ // ---------------------------------------------------------------------------
44
+
45
+ const PANEL_WIDTH = 640;
46
+ const RESULTS_MAX_HEIGHT = 400;
47
+ /** Minimum press target for result rows (house 44px floor). */
48
+ const ROW_MIN_HEIGHT = 44;
49
+ const LISTBOX_ID = "backoffice-command-palette-listbox";
50
+
51
+ const optionId = (index: number) => `backoffice-command-palette-option-${index}`;
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // Component
55
+ // ---------------------------------------------------------------------------
56
+
57
+ export interface CommandPaletteProps {
58
+ open: boolean;
59
+ onOpenChange: (open: boolean) => void;
60
+ }
61
+
62
+ export function CommandPalette({ open, onOpenChange }: CommandPaletteProps) {
63
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
64
+ const navigator = useBackofficeNavigator();
65
+ const { knobProps } = useResolvedKnobs();
66
+ const isCompact = useLayoutSizeClass() === "compact";
67
+ const asSheet = !isWeb || isCompact;
68
+
69
+ const [query, setQuery] = useState("");
70
+ const [debouncedQuery, setDebouncedQuery] = useState("");
71
+ const [highlight, setHighlight] = useState(0);
72
+
73
+ const model = useCommandPaletteModel({ query, debouncedQuery, open });
74
+ const { items } = model;
75
+
76
+ const rootRef = useRef<unknown>(null);
77
+ const itemNodesRef = useRef<Array<unknown>>([]);
78
+
79
+ // ── D-22 FOCUS-RETURN: render-phase capture on the opening render (before
80
+ // the overlay mounts and moves focus), restore on close. ─────────────────
81
+ const restoreFocusRef = useRef<HTMLElement | null>(null);
82
+ const wasOpenRef = useRef(false);
83
+ if (open && !wasOpenRef.current && isWeb && typeof document !== "undefined") {
84
+ restoreFocusRef.current =
85
+ document.activeElement instanceof HTMLElement ? document.activeElement : null;
86
+ }
87
+ wasOpenRef.current = open;
88
+
89
+ const close = useCallback(() => {
90
+ setQuery("");
91
+ setDebouncedQuery("");
92
+ setHighlight(0);
93
+ onOpenChange(false);
94
+ }, [onOpenChange]);
95
+
96
+ const handleOpenChange = useCallback(
97
+ (nextOpen: boolean) => {
98
+ if (!nextOpen) close();
99
+ else onOpenChange(true);
100
+ },
101
+ [close, onOpenChange],
102
+ );
103
+
104
+ useEffect(() => {
105
+ if (open || !isWeb || typeof document === "undefined") return;
106
+ // Runs on close (and unmount-after-close): put focus back where it was.
107
+ const target = restoreFocusRef.current;
108
+ restoreFocusRef.current = null;
109
+ if (target?.isConnected) target.focus();
110
+ }, [open]);
111
+
112
+ // Focus the palette input on open (fallback behind the Dialog focus scope;
113
+ // the sheet has no scope of its own on web).
114
+ useEffect(() => {
115
+ if (!open || !isWeb || typeof document === "undefined") return;
116
+ const timer = setTimeout(() => {
117
+ const root = rootRef.current as HTMLElement | null;
118
+ root?.querySelector("input")?.focus();
119
+ }, 0);
120
+ return () => clearTimeout(timer);
121
+ }, [open]);
122
+
123
+ // Keep the highlight on a real row as results stream in/out.
124
+ useEffect(() => {
125
+ setHighlight((current) => (current < items.length ? current : 0));
126
+ }, [items]);
127
+
128
+ // Keep the keyboard-highlighted row scrolled into view (web).
129
+ useEffect(() => {
130
+ if (!isWeb) return;
131
+ const node = itemNodesRef.current[highlight] as HTMLElement | undefined | null;
132
+ node?.scrollIntoView?.({ block: "nearest" });
133
+ }, [highlight]);
134
+
135
+ const activate = useCallback(
136
+ (item: CommandPaletteItem | undefined) => {
137
+ if (!item) return;
138
+ navigator.navigate(item.path);
139
+ addToRecent({ label: item.label, path: item.path });
140
+ close();
141
+ },
142
+ [navigator, close],
143
+ );
144
+
145
+ // ── Input key handling (roving highlight, commit, dismiss) ───────────────
146
+ const handleKeyDown = useCallback(
147
+ (event: { key?: string; nativeEvent?: { key?: string }; preventDefault?: () => void }) => {
148
+ const key = event.key ?? event.nativeEvent?.key;
149
+ if (key === "ArrowDown") {
150
+ event.preventDefault?.();
151
+ setHighlight((current) => (items.length ? (current + 1) % items.length : 0));
152
+ } else if (key === "ArrowUp") {
153
+ event.preventDefault?.();
154
+ setHighlight((current) => (items.length ? (current - 1 + items.length) % items.length : 0));
155
+ } else if (key === "Enter") {
156
+ event.preventDefault?.();
157
+ activate(items[highlight] ?? items[0]);
158
+ } else if (key === "Escape") {
159
+ event.preventDefault?.();
160
+ close();
161
+ } else if (key === "Tab") {
162
+ // D-23 ONE-TAB-STOP: the input is the palette's only tab stop.
163
+ event.preventDefault?.();
164
+ }
165
+ },
166
+ [items, highlight, activate, close],
167
+ );
168
+
169
+ // Sheet mode leaves Escape dismissal to the consumer (LC-21) — cover the
170
+ // case where focus is outside the input (list-tools-sheet precedent).
171
+ useEffect(() => {
172
+ if (!asSheet || !isWeb || typeof document === "undefined" || !open) return;
173
+ const onKeyDown = (event: KeyboardEvent) => {
174
+ if (event.key === "Escape") close();
175
+ };
176
+ document.addEventListener("keydown", onKeyDown);
177
+ return () => document.removeEventListener("keydown", onKeyDown);
178
+ }, [asSheet, open, close]);
179
+
180
+ const handleChange = useCallback((text: string) => {
181
+ setQuery(text);
182
+ setHighlight(0);
183
+ }, []);
184
+
185
+ const handleSearch = useCallback((text: string) => {
186
+ setDebouncedQuery(text.trim());
187
+ }, []);
188
+
189
+ const handleClear = useCallback(() => {
190
+ setDebouncedQuery("");
191
+ setHighlight(0);
192
+ }, []);
193
+
194
+ const activeOptionId = items[highlight] ? optionId(highlight) : undefined;
195
+
196
+ const inputProps = useMemo(
197
+ () =>
198
+ ({
199
+ onKeyDown: handleKeyDown,
200
+ onSubmitEditing: () => activate(items[highlight] ?? items[0]),
201
+ role: "combobox",
202
+ "aria-expanded": true,
203
+ "aria-haspopup": "listbox",
204
+ "aria-controls": LISTBOX_ID,
205
+ "aria-activedescendant": activeOptionId,
206
+ }) as ComponentProps<typeof SearchInput>["inputProps"],
207
+ [handleKeyDown, activate, items, highlight, activeOptionId],
208
+ );
209
+
210
+ const searchInput = (
211
+ <SearchInput
212
+ value={query}
213
+ onChange={handleChange}
214
+ onSearch={handleSearch}
215
+ onClear={handleClear}
216
+ debounceMs={300}
217
+ size="$3"
218
+ placeholder={t("awesomebar.placeholder", "Search or type a command…")}
219
+ aria-label={t("awesomebar.label", "Search or type a command")}
220
+ inputProps={inputProps}
221
+ />
222
+ );
223
+
224
+ const results = (
225
+ <PaletteResults
226
+ model={model}
227
+ highlight={highlight}
228
+ onHighlight={setHighlight}
229
+ onActivate={activate}
230
+ itemNodesRef={itemNodesRef}
231
+ />
232
+ );
233
+
234
+ // ── <sm / native: full-height sheet (native search sheet pattern) ────────
235
+ if (asSheet) {
236
+ return (
237
+ <SheetModal
238
+ open={open}
239
+ onOpenChange={handleOpenChange}
240
+ snapPoint={92}
241
+ scrollable
242
+ header={
243
+ <YStack
244
+ ref={rootRef as never}
245
+ paddingBottom="$2"
246
+ data-testid="backoffice-command-palette"
247
+ >
248
+ {searchInput}
249
+ </YStack>
250
+ }
251
+ >
252
+ <YStack
253
+ id={LISTBOX_ID}
254
+ role={"listbox" as "list"}
255
+ aria-label={t("awesomebar.results", "Search results")}
256
+ paddingBottom="$4"
257
+ data-dismiss-class="commit"
258
+ >
259
+ {results}
260
+ </YStack>
261
+ </SheetModal>
262
+ );
263
+ }
264
+
265
+ // ── ≥sm web: centered top-anchored modal overlay ─────────────────────────
266
+ const topOffset = typeof window !== "undefined" ? Math.round(window.innerHeight * 0.15) : 120;
267
+
268
+ return (
269
+ <Dialog modal open={open} onOpenChange={handleOpenChange}>
270
+ <Dialog.Portal justifyContent="flex-start" alignItems="center" paddingTop={topOffset}>
271
+ <Dialog.Overlay
272
+ key="overlay"
273
+ backgroundColor="$shadow6"
274
+ transition={knobProps.transition}
275
+ enterStyle={{ opacity: 0 }}
276
+ exitStyle={{ opacity: 0 }}
277
+ />
278
+ <DialogContent
279
+ key="content"
280
+ ref={rootRef as never}
281
+ width={PANEL_WIDTH}
282
+ maxWidth="92%"
283
+ // SP-EDGE: the container owns only its border — the input band,
284
+ // rows, and footer own their insets, so row highlights run edge
285
+ // to edge and overflow hidden clips them to the radius.
286
+ padding={0}
287
+ gap={0}
288
+ overflow="hidden"
289
+ aria-label={t("awesomebar.label", "Search or type a command")}
290
+ data-dismiss-class="commit"
291
+ data-testid="backoffice-command-palette"
292
+ >
293
+ <YStack padding="$2.5" borderBottomWidth={1} borderBottomColor="$borderColor">
294
+ {searchInput}
295
+ </YStack>
296
+ <ScrollView maxHeight={RESULTS_MAX_HEIGHT}>
297
+ <YStack
298
+ id={LISTBOX_ID}
299
+ role={"listbox" as "list"}
300
+ aria-label={t("awesomebar.results", "Search results")}
301
+ paddingVertical="$1.5"
302
+ >
303
+ {results}
304
+ </YStack>
305
+ </ScrollView>
306
+ <PaletteFooter />
307
+ </DialogContent>
308
+ </Dialog.Portal>
309
+ </Dialog>
310
+ );
311
+ }
312
+
313
+ // ---------------------------------------------------------------------------
314
+ // Shared section list (one renderer for both containers)
315
+ // ---------------------------------------------------------------------------
316
+
317
+ interface PaletteResultsProps {
318
+ model: CommandPaletteModel;
319
+ highlight: number;
320
+ onHighlight: (index: number) => void;
321
+ onActivate: (item: CommandPaletteItem) => void;
322
+ itemNodesRef: RefObject<Array<unknown>>;
323
+ }
324
+
325
+ function PaletteResults({
326
+ model,
327
+ highlight,
328
+ onHighlight,
329
+ onActivate,
330
+ itemNodesRef,
331
+ }: PaletteResultsProps) {
332
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
333
+ const { knobProps } = useResolvedKnobs();
334
+ // LC-05: the roving highlight rides the accent channel with a
335
+ // luminance-computed readable foreground (Sidebar active-row precedent).
336
+ const onAccent = useReadableTextOn("$accentBackground");
337
+ const { sections, searching, hasQuery, noResults } = model;
338
+
339
+ let flatIndex = -1;
340
+
341
+ return (
342
+ <>
343
+ {sections.map((section) => (
344
+ <YStack key={section.id} data-testid={`backoffice-palette-section-${section.id}`}>
345
+ <Text
346
+ fontSize="$1"
347
+ color="$color10"
348
+ textTransform="uppercase"
349
+ letterSpacing={0.5}
350
+ paddingHorizontal="$3"
351
+ paddingTop="$2.5"
352
+ paddingBottom="$1.5"
353
+ {...knobProps.body}
354
+ >
355
+ {section.label}
356
+ </Text>
357
+ {section.items.map((item) => {
358
+ flatIndex += 1;
359
+ const index = flatIndex;
360
+ const highlighted = index === highlight;
361
+ const Icon = item.icon;
362
+ return (
363
+ <XStack
364
+ key={item.id}
365
+ id={optionId(index)}
366
+ ref={
367
+ ((node: unknown) => {
368
+ itemNodesRef.current[index] = node;
369
+ }) as never
370
+ }
371
+ role={"option" as "listitem"}
372
+ aria-selected={highlighted}
373
+ alignItems="center"
374
+ gap="$2.5"
375
+ paddingHorizontal="$3"
376
+ paddingVertical="$2"
377
+ minHeight={ROW_MIN_HEIGHT}
378
+ cursor="pointer"
379
+ backgroundColor={highlighted ? "$accentBackground" : "transparent"}
380
+ hoverStyle={{
381
+ backgroundColor: highlighted ? "$accentBackground" : "$color3",
382
+ }}
383
+ pressStyle={{ backgroundColor: "$accentBackground" }}
384
+ onPress={() => onActivate(item)}
385
+ onMouseEnter={() => onHighlight(index)}
386
+ >
387
+ {/* LC-08: one uniform leading media slot */}
388
+ <XStack width={20} justifyContent="center" flexShrink={0}>
389
+ <Icon size={16} color={highlighted && onAccent ? onAccent : undefined} />
390
+ </XStack>
391
+ <YStack flex={1} minWidth={0}>
392
+ <Text
393
+ numberOfLines={1}
394
+ fontSize="$3"
395
+ color={highlighted && onAccent ? onAccent : "$color12"}
396
+ {...knobProps.body}
397
+ >
398
+ {item.label}
399
+ </Text>
400
+ {item.description ? (
401
+ <Text
402
+ numberOfLines={1}
403
+ fontSize="$2"
404
+ color={highlighted && onAccent ? onAccent : "$color10"}
405
+ opacity={highlighted ? 0.8 : 1}
406
+ {...knobProps.body}
407
+ >
408
+ {item.description}
409
+ </Text>
410
+ ) : null}
411
+ </YStack>
412
+ {item.badge ? (
413
+ <XStack
414
+ borderWidth={1}
415
+ borderColor={highlighted && onAccent ? onAccent : "$borderColor"}
416
+ borderRadius="$2"
417
+ paddingHorizontal="$1.5"
418
+ paddingVertical={2}
419
+ flexShrink={0}
420
+ opacity={highlighted ? 0.9 : 1}
421
+ >
422
+ <Text
423
+ fontSize="$1"
424
+ color={highlighted && onAccent ? onAccent : "$color10"}
425
+ {...knobProps.body}
426
+ >
427
+ {item.badge}
428
+ </Text>
429
+ </XStack>
430
+ ) : null}
431
+ </XStack>
432
+ );
433
+ })}
434
+ </YStack>
435
+ ))}
436
+
437
+ {hasQuery && searching && (
438
+ <XStack alignItems="center" gap="$2.5" paddingHorizontal="$3" paddingVertical="$2">
439
+ <Spinner size="small" color="$color10" />
440
+ <Text fontSize="$2" color="$color10" {...knobProps.body}>
441
+ {t("awesomebar.searching", "Searching…")}
442
+ </Text>
443
+ </XStack>
444
+ )}
445
+
446
+ {noResults && (
447
+ <XStack paddingHorizontal="$3" paddingVertical="$3">
448
+ <Text fontSize="$2" color="$color10" {...knobProps.body}>
449
+ {t("awesomebar.noResults", {
450
+ defaultValue: "No results for “{{query}}”",
451
+ query: model.query,
452
+ })}
453
+ </Text>
454
+ </XStack>
455
+ )}
456
+
457
+ {!hasQuery && sections.length === 0 && (
458
+ <XStack paddingHorizontal="$3" paddingVertical="$3">
459
+ <Text fontSize="$2" color="$color10" {...knobProps.body}>
460
+ {t("awesomebar.empty", "Type to search…")}
461
+ </Text>
462
+ </XStack>
463
+ )}
464
+ </>
465
+ );
466
+ }
467
+
468
+ // ---------------------------------------------------------------------------
469
+ // Footer hint bar (overlay container only — keyboard hints, DG discoverable)
470
+ // ---------------------------------------------------------------------------
471
+
472
+ function KeyCap({ label }: { label: string }) {
473
+ return (
474
+ <XStack
475
+ borderWidth={1}
476
+ borderColor="$borderColor"
477
+ backgroundColor="$color2"
478
+ borderRadius="$2"
479
+ paddingHorizontal="$1.5"
480
+ justifyContent="center"
481
+ >
482
+ <SizableText size="$1" fontWeight="600" color="$color11">
483
+ {label}
484
+ </SizableText>
485
+ </XStack>
486
+ );
487
+ }
488
+
489
+ function PaletteFooter() {
490
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
491
+ return (
492
+ <XStack
493
+ alignItems="center"
494
+ gap="$3"
495
+ paddingHorizontal="$3"
496
+ paddingVertical="$2"
497
+ borderTopWidth={1}
498
+ borderTopColor="$borderColor"
499
+ >
500
+ <XStack alignItems="center" gap="$1.5">
501
+ <KeyCap label="↑↓" />
502
+ <SizableText size="$1" color="$color10">
503
+ {t("awesomebar.hintNavigate", "navigate")}
504
+ </SizableText>
505
+ </XStack>
506
+ <XStack alignItems="center" gap="$1.5">
507
+ <KeyCap label="↵" />
508
+ <SizableText size="$1" color="$color10">
509
+ {t("awesomebar.hintOpen", "open")}
510
+ </SizableText>
511
+ </XStack>
512
+ <XStack alignItems="center" gap="$1.5">
513
+ <KeyCap label="esc" />
514
+ <SizableText size="$1" color="$color10">
515
+ {t("awesomebar.hintClose", "close")}
516
+ </SizableText>
517
+ </XStack>
518
+ </XStack>
519
+ );
520
+ }
@@ -0,0 +1,119 @@
1
+ // Navbar help dropdown (docs, keyboard shortcuts dialog, about; desk parity).
2
+ //
3
+ // Desk parity items: Documentation, User Forum, Report an Issue (external,
4
+ // via the platform-split openUrl — web new tab / native Linking / GNOME Gio),
5
+ // Keyboard Shortcuts and About (dialogs, all platforms). Dialogs are mounted
6
+ // as siblings of the popover so they survive the menu closing.
7
+ import { Button, Popover, PopoverContent, Separator, YStack } from "@multiplatform.one/components";
8
+ import { openUrl } from "@multiplatform.one/platform";
9
+ import {
10
+ BookOpenIcon,
11
+ BugIcon,
12
+ ChatsCircleIcon,
13
+ InfoIcon,
14
+ KeyboardIcon,
15
+ QuestionIcon,
16
+ } from "@phosphor-icons/react";
17
+ import { useState, type ComponentProps } from "react";
18
+ import { useTranslation } from "react-i18next";
19
+ import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
20
+ import { HelpAboutDialog } from "./help-about-dialog";
21
+ import { HelpShortcutsDialog } from "./help-shortcuts-dialog";
22
+
23
+ const DOCUMENTATION_URL = "https://docs.frappe.io";
24
+ const USER_FORUM_URL = "https://discuss.frappe.io";
25
+ const REPORT_ISSUE_URL = "https://github.com/frappe/frappe/issues";
26
+
27
+ interface HelpMenuItemProps {
28
+ icon: ComponentProps<typeof Button>["icon"];
29
+ label: string;
30
+ onPress: () => void;
31
+ testID: string;
32
+ }
33
+
34
+ function HelpMenuItem({ icon, label, onPress, testID }: HelpMenuItemProps) {
35
+ return (
36
+ <Button
37
+ chromeless
38
+ size="$3"
39
+ icon={icon}
40
+ justifyContent="flex-start"
41
+ width="100%"
42
+ onPress={onPress}
43
+ data-testid={testID}
44
+ >
45
+ {label}
46
+ </Button>
47
+ );
48
+ }
49
+
50
+ export function HelpMenu() {
51
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
52
+ const [menuOpen, setMenuOpen] = useState(false);
53
+ const [aboutOpen, setAboutOpen] = useState(false);
54
+ const [shortcutsOpen, setShortcutsOpen] = useState(false);
55
+
56
+ const openLink = (url: string) => {
57
+ setMenuOpen(false);
58
+ openUrl(url, "_blank");
59
+ };
60
+
61
+ const openDialog = (setOpen: (open: boolean) => void) => {
62
+ setMenuOpen(false);
63
+ setOpen(true);
64
+ };
65
+
66
+ return (
67
+ <>
68
+ <Popover open={menuOpen} onOpenChange={setMenuOpen} placement="bottom-end" stayInFrame>
69
+ <Popover.Trigger asChild>
70
+ <Button
71
+ chromeless
72
+ circular
73
+ size="$3"
74
+ icon={QuestionIcon}
75
+ aria-label={t("help.label", "Help")}
76
+ data-testid="backoffice-help-trigger"
77
+ />
78
+ </Popover.Trigger>
79
+ <PopoverContent padding="$2" data-testid="backoffice-help-menu">
80
+ <YStack minWidth={220}>
81
+ <HelpMenuItem
82
+ icon={BookOpenIcon}
83
+ label={t("help.documentation", "Documentation")}
84
+ onPress={() => openLink(DOCUMENTATION_URL)}
85
+ testID="backoffice-help-documentation"
86
+ />
87
+ <HelpMenuItem
88
+ icon={ChatsCircleIcon}
89
+ label={t("help.userForum", "User Forum")}
90
+ onPress={() => openLink(USER_FORUM_URL)}
91
+ testID="backoffice-help-forum"
92
+ />
93
+ <HelpMenuItem
94
+ icon={BugIcon}
95
+ label={t("help.reportIssue", "Report an Issue")}
96
+ onPress={() => openLink(REPORT_ISSUE_URL)}
97
+ testID="backoffice-help-report-issue"
98
+ />
99
+ <Separator marginVertical="$1" />
100
+ <HelpMenuItem
101
+ icon={KeyboardIcon}
102
+ label={t("help.keyboardShortcuts", "Keyboard Shortcuts")}
103
+ onPress={() => openDialog(setShortcutsOpen)}
104
+ testID="backoffice-help-shortcuts"
105
+ />
106
+ <HelpMenuItem
107
+ icon={InfoIcon}
108
+ label={t("help.about", "About")}
109
+ onPress={() => openDialog(setAboutOpen)}
110
+ testID="backoffice-help-about"
111
+ />
112
+ </YStack>
113
+ </PopoverContent>
114
+ </Popover>
115
+ <HelpShortcutsDialog open={shortcutsOpen} onOpenChange={setShortcutsOpen} />
116
+ <HelpAboutDialog open={aboutOpen} onOpenChange={setAboutOpen} />
117
+ </>
118
+ );
119
+ }