@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.
- package/LICENSE +201 -0
- package/README.md +310 -0
- package/dist/cjs/chrome/BackofficeAwesomebar.cjs +95 -0
- package/dist/cjs/chrome/BackofficeAwesomebar.native.js +106 -0
- package/dist/cjs/chrome/BackofficeAwesomebar.native.js.map +1 -0
- package/dist/cjs/chrome/CommandPalette.cjs +453 -0
- package/dist/cjs/chrome/CommandPalette.native.js +505 -0
- package/dist/cjs/chrome/CommandPalette.native.js.map +1 -0
- package/dist/cjs/chrome/HelpMenu.cjs +131 -0
- package/dist/cjs/chrome/HelpMenu.native.js +145 -0
- package/dist/cjs/chrome/HelpMenu.native.js.map +1 -0
- package/dist/cjs/chrome/NotificationsButton.cjs +112 -0
- package/dist/cjs/chrome/NotificationsButton.native.js +115 -0
- package/dist/cjs/chrome/NotificationsButton.native.js.map +1 -0
- package/dist/cjs/chrome/UserMenu.cjs +158 -0
- package/dist/cjs/chrome/UserMenu.native.js +186 -0
- package/dist/cjs/chrome/UserMenu.native.js.map +1 -0
- package/dist/cjs/chrome/awesomebar-data.cjs +173 -0
- package/dist/cjs/chrome/awesomebar-data.native.js +233 -0
- package/dist/cjs/chrome/awesomebar-data.native.js.map +1 -0
- package/dist/cjs/chrome/command-palette-model.cjs +208 -0
- package/dist/cjs/chrome/command-palette-model.native.js +301 -0
- package/dist/cjs/chrome/command-palette-model.native.js.map +1 -0
- package/dist/cjs/chrome/help-about-dialog.cjs +136 -0
- package/dist/cjs/chrome/help-about-dialog.native.js +146 -0
- package/dist/cjs/chrome/help-about-dialog.native.js.map +1 -0
- package/dist/cjs/chrome/help-shortcuts-dialog.cjs +155 -0
- package/dist/cjs/chrome/help-shortcuts-dialog.native.js +168 -0
- package/dist/cjs/chrome/help-shortcuts-dialog.native.js.map +1 -0
- package/dist/cjs/chrome/notifications-data.cjs +190 -0
- package/dist/cjs/chrome/notifications-data.native.js +271 -0
- package/dist/cjs/chrome/notifications-data.native.js.map +1 -0
- package/dist/cjs/chrome/notifications-panel.cjs +171 -0
- package/dist/cjs/chrome/notifications-panel.native.js +189 -0
- package/dist/cjs/chrome/notifications-panel.native.js.map +1 -0
- package/dist/cjs/chrome/notifications-utils.cjs +43 -0
- package/dist/cjs/chrome/notifications-utils.native.js +46 -0
- package/dist/cjs/chrome/notifications-utils.native.js.map +1 -0
- package/dist/cjs/chrome/shortcuts.cjs +58 -0
- package/dist/cjs/chrome/shortcuts.native.js +72 -0
- package/dist/cjs/chrome/shortcuts.native.js.map +1 -0
- package/dist/cjs/chrome/user-session.cjs +100 -0
- package/dist/cjs/chrome/user-session.native.js +120 -0
- package/dist/cjs/chrome/user-session.native.js.map +1 -0
- package/dist/cjs/config/BackofficeProvider.cjs +164 -0
- package/dist/cjs/config/BackofficeProvider.native.js +217 -0
- package/dist/cjs/config/BackofficeProvider.native.js.map +1 -0
- package/dist/cjs/config/capabilities.cjs +123 -0
- package/dist/cjs/config/capabilities.native.js +155 -0
- package/dist/cjs/config/capabilities.native.js.map +1 -0
- package/dist/cjs/config/events.cjs +18 -0
- package/dist/cjs/config/events.native.js +21 -0
- package/dist/cjs/config/events.native.js.map +1 -0
- package/dist/cjs/config/slots.cjs +18 -0
- package/dist/cjs/config/slots.native.js +21 -0
- package/dist/cjs/config/slots.native.js.map +1 -0
- package/dist/cjs/i18n/en.cjs +101 -0
- package/dist/cjs/i18n/en.native.js +104 -0
- package/dist/cjs/i18n/en.native.js.map +1 -0
- package/dist/cjs/i18n/index.cjs +77 -0
- package/dist/cjs/i18n/index.native.js +102 -0
- package/dist/cjs/i18n/index.native.js.map +1 -0
- package/dist/cjs/index.cjs +109 -0
- package/dist/cjs/index.native.js +112 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/cjs/navigation/navigator.cjs +144 -0
- package/dist/cjs/navigation/navigator.native.js +307 -0
- package/dist/cjs/navigation/navigator.native.js.map +1 -0
- package/dist/cjs/navigation/paths.cjs +103 -0
- package/dist/cjs/navigation/paths.native.js +143 -0
- package/dist/cjs/navigation/paths.native.js.map +1 -0
- package/dist/cjs/oneAdapter/index.cjs +53 -0
- package/dist/cjs/oneAdapter/index.native.js +64 -0
- package/dist/cjs/oneAdapter/index.native.js.map +1 -0
- package/dist/cjs/shared/useFrappeApp.cjs +56 -0
- package/dist/cjs/shared/useFrappeApp.native.js +60 -0
- package/dist/cjs/shared/useFrappeApp.native.js.map +1 -0
- package/dist/cjs/shell/BackofficeShell.cjs +194 -0
- package/dist/cjs/shell/BackofficeShell.native.js +223 -0
- package/dist/cjs/shell/BackofficeShell.native.js.map +1 -0
- package/dist/cjs/shell/WorkspaceSidebar.cjs +115 -0
- package/dist/cjs/shell/WorkspaceSidebar.native.js +143 -0
- package/dist/cjs/shell/WorkspaceSidebar.native.js.map +1 -0
- package/dist/cjs/shell/useWorkspaces.cjs +131 -0
- package/dist/cjs/shell/useWorkspaces.native.js +173 -0
- package/dist/cjs/shell/useWorkspaces.native.js.map +1 -0
- package/dist/cjs/shell/workspaceIcons.cjs +64 -0
- package/dist/cjs/shell/workspaceIcons.native.js +67 -0
- package/dist/cjs/shell/workspaceIcons.native.js.map +1 -0
- package/dist/esm/chrome/BackofficeAwesomebar.mjs +70 -0
- package/dist/esm/chrome/BackofficeAwesomebar.mjs.map +1 -0
- package/dist/esm/chrome/BackofficeAwesomebar.native.js +78 -0
- package/dist/esm/chrome/BackofficeAwesomebar.native.js.map +1 -0
- package/dist/esm/chrome/CommandPalette.mjs +428 -0
- package/dist/esm/chrome/CommandPalette.mjs.map +1 -0
- package/dist/esm/chrome/CommandPalette.native.js +477 -0
- package/dist/esm/chrome/CommandPalette.native.js.map +1 -0
- package/dist/esm/chrome/HelpMenu.mjs +106 -0
- package/dist/esm/chrome/HelpMenu.mjs.map +1 -0
- package/dist/esm/chrome/HelpMenu.native.js +117 -0
- package/dist/esm/chrome/HelpMenu.native.js.map +1 -0
- package/dist/esm/chrome/NotificationsButton.mjs +87 -0
- package/dist/esm/chrome/NotificationsButton.mjs.map +1 -0
- package/dist/esm/chrome/NotificationsButton.native.js +87 -0
- package/dist/esm/chrome/NotificationsButton.native.js.map +1 -0
- package/dist/esm/chrome/UserMenu.mjs +133 -0
- package/dist/esm/chrome/UserMenu.mjs.map +1 -0
- package/dist/esm/chrome/UserMenu.native.js +147 -0
- package/dist/esm/chrome/UserMenu.native.js.map +1 -0
- package/dist/esm/chrome/awesomebar-data.mjs +144 -0
- package/dist/esm/chrome/awesomebar-data.mjs.map +1 -0
- package/dist/esm/chrome/awesomebar-data.native.js +190 -0
- package/dist/esm/chrome/awesomebar-data.native.js.map +1 -0
- package/dist/esm/chrome/command-palette-model.mjs +183 -0
- package/dist/esm/chrome/command-palette-model.mjs.map +1 -0
- package/dist/esm/chrome/command-palette-model.native.js +273 -0
- package/dist/esm/chrome/command-palette-model.native.js.map +1 -0
- package/dist/esm/chrome/help-about-dialog.mjs +111 -0
- package/dist/esm/chrome/help-about-dialog.mjs.map +1 -0
- package/dist/esm/chrome/help-about-dialog.native.js +118 -0
- package/dist/esm/chrome/help-about-dialog.native.js.map +1 -0
- package/dist/esm/chrome/help-shortcuts-dialog.mjs +130 -0
- package/dist/esm/chrome/help-shortcuts-dialog.mjs.map +1 -0
- package/dist/esm/chrome/help-shortcuts-dialog.native.js +140 -0
- package/dist/esm/chrome/help-shortcuts-dialog.native.js.map +1 -0
- package/dist/esm/chrome/notifications-data.mjs +165 -0
- package/dist/esm/chrome/notifications-data.mjs.map +1 -0
- package/dist/esm/chrome/notifications-data.native.js +232 -0
- package/dist/esm/chrome/notifications-data.native.js.map +1 -0
- package/dist/esm/chrome/notifications-panel.mjs +146 -0
- package/dist/esm/chrome/notifications-panel.mjs.map +1 -0
- package/dist/esm/chrome/notifications-panel.native.js +161 -0
- package/dist/esm/chrome/notifications-panel.native.js.map +1 -0
- package/dist/esm/chrome/notifications-utils.mjs +17 -0
- package/dist/esm/chrome/notifications-utils.mjs.map +1 -0
- package/dist/esm/chrome/notifications-utils.native.js +17 -0
- package/dist/esm/chrome/notifications-utils.native.js.map +1 -0
- package/dist/esm/chrome/shortcuts.mjs +33 -0
- package/dist/esm/chrome/shortcuts.mjs.map +1 -0
- package/dist/esm/chrome/shortcuts.native.js +44 -0
- package/dist/esm/chrome/shortcuts.native.js.map +1 -0
- package/dist/esm/chrome/user-session.mjs +73 -0
- package/dist/esm/chrome/user-session.mjs.map +1 -0
- package/dist/esm/chrome/user-session.native.js +79 -0
- package/dist/esm/chrome/user-session.native.js.map +1 -0
- package/dist/esm/config/BackofficeProvider.mjs +132 -0
- package/dist/esm/config/BackofficeProvider.mjs.map +1 -0
- package/dist/esm/config/BackofficeProvider.native.js +171 -0
- package/dist/esm/config/BackofficeProvider.native.js.map +1 -0
- package/dist/esm/config/capabilities.mjs +97 -0
- package/dist/esm/config/capabilities.mjs.map +1 -0
- package/dist/esm/config/capabilities.native.js +126 -0
- package/dist/esm/config/capabilities.native.js.map +1 -0
- package/dist/esm/config/events.mjs +2 -0
- package/dist/esm/config/events.mjs.map +1 -0
- package/dist/esm/config/events.native.js +2 -0
- package/dist/esm/config/events.native.js.map +1 -0
- package/dist/esm/config/slots.mjs +2 -0
- package/dist/esm/config/slots.mjs.map +1 -0
- package/dist/esm/config/slots.native.js +2 -0
- package/dist/esm/config/slots.native.js.map +1 -0
- package/dist/esm/i18n/en.mjs +76 -0
- package/dist/esm/i18n/en.mjs.map +1 -0
- package/dist/esm/i18n/en.native.js +76 -0
- package/dist/esm/i18n/en.native.js.map +1 -0
- package/dist/esm/i18n/index.mjs +40 -0
- package/dist/esm/i18n/index.mjs.map +1 -0
- package/dist/esm/i18n/index.native.js +62 -0
- package/dist/esm/i18n/index.native.js.map +1 -0
- package/dist/esm/index.mjs +26 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +26 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/navigation/navigator.mjs +115 -0
- package/dist/esm/navigation/navigator.mjs.map +1 -0
- package/dist/esm/navigation/navigator.native.js +275 -0
- package/dist/esm/navigation/navigator.native.js.map +1 -0
- package/dist/esm/navigation/paths.mjs +66 -0
- package/dist/esm/navigation/paths.mjs.map +1 -0
- package/dist/esm/navigation/paths.native.js +103 -0
- package/dist/esm/navigation/paths.native.js.map +1 -0
- package/dist/esm/oneAdapter/index.mjs +28 -0
- package/dist/esm/oneAdapter/index.mjs.map +1 -0
- package/dist/esm/oneAdapter/index.native.js +36 -0
- package/dist/esm/oneAdapter/index.native.js.map +1 -0
- package/dist/esm/shared/useFrappeApp.mjs +31 -0
- package/dist/esm/shared/useFrappeApp.mjs.map +1 -0
- package/dist/esm/shared/useFrappeApp.native.js +32 -0
- package/dist/esm/shared/useFrappeApp.native.js.map +1 -0
- package/dist/esm/shell/BackofficeShell.mjs +169 -0
- package/dist/esm/shell/BackofficeShell.mjs.map +1 -0
- package/dist/esm/shell/BackofficeShell.native.js +195 -0
- package/dist/esm/shell/BackofficeShell.native.js.map +1 -0
- package/dist/esm/shell/WorkspaceSidebar.mjs +89 -0
- package/dist/esm/shell/WorkspaceSidebar.mjs.map +1 -0
- package/dist/esm/shell/WorkspaceSidebar.native.js +114 -0
- package/dist/esm/shell/WorkspaceSidebar.native.js.map +1 -0
- package/dist/esm/shell/useWorkspaces.mjs +104 -0
- package/dist/esm/shell/useWorkspaces.mjs.map +1 -0
- package/dist/esm/shell/useWorkspaces.native.js +143 -0
- package/dist/esm/shell/useWorkspaces.native.js.map +1 -0
- package/dist/esm/shell/workspaceIcons.mjs +39 -0
- package/dist/esm/shell/workspaceIcons.mjs.map +1 -0
- package/dist/esm/shell/workspaceIcons.native.js +39 -0
- package/dist/esm/shell/workspaceIcons.native.js.map +1 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.mjs +70 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.mjs.map +1 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.native.js +106 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.native.js.map +1 -0
- package/dist/jsx/chrome/CommandPalette.mjs +428 -0
- package/dist/jsx/chrome/CommandPalette.mjs.map +1 -0
- package/dist/jsx/chrome/CommandPalette.native.js +505 -0
- package/dist/jsx/chrome/CommandPalette.native.js.map +1 -0
- package/dist/jsx/chrome/HelpMenu.mjs +106 -0
- package/dist/jsx/chrome/HelpMenu.mjs.map +1 -0
- package/dist/jsx/chrome/HelpMenu.native.js +145 -0
- package/dist/jsx/chrome/HelpMenu.native.js.map +1 -0
- package/dist/jsx/chrome/NotificationsButton.mjs +87 -0
- package/dist/jsx/chrome/NotificationsButton.mjs.map +1 -0
- package/dist/jsx/chrome/NotificationsButton.native.js +115 -0
- package/dist/jsx/chrome/NotificationsButton.native.js.map +1 -0
- package/dist/jsx/chrome/UserMenu.mjs +133 -0
- package/dist/jsx/chrome/UserMenu.mjs.map +1 -0
- package/dist/jsx/chrome/UserMenu.native.js +186 -0
- package/dist/jsx/chrome/UserMenu.native.js.map +1 -0
- package/dist/jsx/chrome/awesomebar-data.mjs +144 -0
- package/dist/jsx/chrome/awesomebar-data.mjs.map +1 -0
- package/dist/jsx/chrome/awesomebar-data.native.js +233 -0
- package/dist/jsx/chrome/awesomebar-data.native.js.map +1 -0
- package/dist/jsx/chrome/command-palette-model.mjs +183 -0
- package/dist/jsx/chrome/command-palette-model.mjs.map +1 -0
- package/dist/jsx/chrome/command-palette-model.native.js +301 -0
- package/dist/jsx/chrome/command-palette-model.native.js.map +1 -0
- package/dist/jsx/chrome/help-about-dialog.mjs +111 -0
- package/dist/jsx/chrome/help-about-dialog.mjs.map +1 -0
- package/dist/jsx/chrome/help-about-dialog.native.js +146 -0
- package/dist/jsx/chrome/help-about-dialog.native.js.map +1 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.mjs +130 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.mjs.map +1 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.native.js +168 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.native.js.map +1 -0
- package/dist/jsx/chrome/notifications-data.mjs +165 -0
- package/dist/jsx/chrome/notifications-data.mjs.map +1 -0
- package/dist/jsx/chrome/notifications-data.native.js +271 -0
- package/dist/jsx/chrome/notifications-data.native.js.map +1 -0
- package/dist/jsx/chrome/notifications-panel.mjs +146 -0
- package/dist/jsx/chrome/notifications-panel.mjs.map +1 -0
- package/dist/jsx/chrome/notifications-panel.native.js +189 -0
- package/dist/jsx/chrome/notifications-panel.native.js.map +1 -0
- package/dist/jsx/chrome/notifications-utils.mjs +17 -0
- package/dist/jsx/chrome/notifications-utils.mjs.map +1 -0
- package/dist/jsx/chrome/notifications-utils.native.js +46 -0
- package/dist/jsx/chrome/notifications-utils.native.js.map +1 -0
- package/dist/jsx/chrome/shortcuts.mjs +33 -0
- package/dist/jsx/chrome/shortcuts.mjs.map +1 -0
- package/dist/jsx/chrome/shortcuts.native.js +72 -0
- package/dist/jsx/chrome/shortcuts.native.js.map +1 -0
- package/dist/jsx/chrome/user-session.mjs +73 -0
- package/dist/jsx/chrome/user-session.mjs.map +1 -0
- package/dist/jsx/chrome/user-session.native.js +120 -0
- package/dist/jsx/chrome/user-session.native.js.map +1 -0
- package/dist/jsx/config/BackofficeProvider.mjs +132 -0
- package/dist/jsx/config/BackofficeProvider.mjs.map +1 -0
- package/dist/jsx/config/BackofficeProvider.native.js +217 -0
- package/dist/jsx/config/BackofficeProvider.native.js.map +1 -0
- package/dist/jsx/config/capabilities.mjs +97 -0
- package/dist/jsx/config/capabilities.mjs.map +1 -0
- package/dist/jsx/config/capabilities.native.js +155 -0
- package/dist/jsx/config/capabilities.native.js.map +1 -0
- package/dist/jsx/config/events.mjs +2 -0
- package/dist/jsx/config/events.mjs.map +1 -0
- package/dist/jsx/config/events.native.js +21 -0
- package/dist/jsx/config/events.native.js.map +1 -0
- package/dist/jsx/config/slots.mjs +2 -0
- package/dist/jsx/config/slots.mjs.map +1 -0
- package/dist/jsx/config/slots.native.js +21 -0
- package/dist/jsx/config/slots.native.js.map +1 -0
- package/dist/jsx/i18n/en.mjs +76 -0
- package/dist/jsx/i18n/en.mjs.map +1 -0
- package/dist/jsx/i18n/en.native.js +104 -0
- package/dist/jsx/i18n/en.native.js.map +1 -0
- package/dist/jsx/i18n/index.mjs +40 -0
- package/dist/jsx/i18n/index.mjs.map +1 -0
- package/dist/jsx/i18n/index.native.js +102 -0
- package/dist/jsx/i18n/index.native.js.map +1 -0
- package/dist/jsx/index.js +26 -0
- package/dist/jsx/index.js.map +1 -0
- package/dist/jsx/index.mjs +26 -0
- package/dist/jsx/index.mjs.map +1 -0
- package/dist/jsx/index.native.js +112 -0
- package/dist/jsx/index.native.js.map +1 -0
- package/dist/jsx/navigation/navigator.mjs +115 -0
- package/dist/jsx/navigation/navigator.mjs.map +1 -0
- package/dist/jsx/navigation/navigator.native.js +307 -0
- package/dist/jsx/navigation/navigator.native.js.map +1 -0
- package/dist/jsx/navigation/paths.mjs +66 -0
- package/dist/jsx/navigation/paths.mjs.map +1 -0
- package/dist/jsx/navigation/paths.native.js +143 -0
- package/dist/jsx/navigation/paths.native.js.map +1 -0
- package/dist/jsx/oneAdapter/index.mjs +28 -0
- package/dist/jsx/oneAdapter/index.mjs.map +1 -0
- package/dist/jsx/oneAdapter/index.native.js +64 -0
- package/dist/jsx/oneAdapter/index.native.js.map +1 -0
- package/dist/jsx/shared/useFrappeApp.mjs +31 -0
- package/dist/jsx/shared/useFrappeApp.mjs.map +1 -0
- package/dist/jsx/shared/useFrappeApp.native.js +60 -0
- package/dist/jsx/shared/useFrappeApp.native.js.map +1 -0
- package/dist/jsx/shell/BackofficeShell.mjs +169 -0
- package/dist/jsx/shell/BackofficeShell.mjs.map +1 -0
- package/dist/jsx/shell/BackofficeShell.native.js +223 -0
- package/dist/jsx/shell/BackofficeShell.native.js.map +1 -0
- package/dist/jsx/shell/WorkspaceSidebar.mjs +89 -0
- package/dist/jsx/shell/WorkspaceSidebar.mjs.map +1 -0
- package/dist/jsx/shell/WorkspaceSidebar.native.js +143 -0
- package/dist/jsx/shell/WorkspaceSidebar.native.js.map +1 -0
- package/dist/jsx/shell/useWorkspaces.mjs +104 -0
- package/dist/jsx/shell/useWorkspaces.mjs.map +1 -0
- package/dist/jsx/shell/useWorkspaces.native.js +173 -0
- package/dist/jsx/shell/useWorkspaces.native.js.map +1 -0
- package/dist/jsx/shell/workspaceIcons.mjs +39 -0
- package/dist/jsx/shell/workspaceIcons.mjs.map +1 -0
- package/dist/jsx/shell/workspaceIcons.native.js +67 -0
- package/dist/jsx/shell/workspaceIcons.native.js.map +1 -0
- package/package.json +123 -0
- package/src/chrome/BackofficeAwesomebar.tsx +89 -0
- package/src/chrome/CommandPalette.spec.tsx +252 -0
- package/src/chrome/CommandPalette.tsx +520 -0
- package/src/chrome/HelpMenu.tsx +119 -0
- package/src/chrome/NotificationsButton.tsx +87 -0
- package/src/chrome/UserMenu.tsx +173 -0
- package/src/chrome/awesomebar-data.tsx +252 -0
- package/src/chrome/command-palette-model.ts +291 -0
- package/src/chrome/help-about-dialog.tsx +130 -0
- package/src/chrome/help-shortcuts-dialog.tsx +144 -0
- package/src/chrome/notifications-data.tsx +287 -0
- package/src/chrome/notifications-panel.tsx +175 -0
- package/src/chrome/notifications-utils.tsx +44 -0
- package/src/chrome/shortcuts.ts +53 -0
- package/src/chrome/user-session.tsx +116 -0
- package/src/config/BackofficeProvider.spec.tsx +126 -0
- package/src/config/BackofficeProvider.tsx +315 -0
- package/src/config/capabilities.ts +172 -0
- package/src/config/events.ts +19 -0
- package/src/config/slots.ts +28 -0
- package/src/i18n/en.ts +83 -0
- package/src/i18n/index.ts +69 -0
- package/src/index.ts +150 -0
- package/src/navigation/navigator.spec.ts +106 -0
- package/src/navigation/navigator.ts +209 -0
- package/src/navigation/paths.ts +146 -0
- package/src/oneAdapter/index.tsx +61 -0
- package/src/shared/useFrappeApp.ts +39 -0
- package/src/shell/BackofficeShell.tsx +222 -0
- package/src/shell/WorkspaceSidebar.tsx +119 -0
- package/src/shell/useWorkspaces.ts +202 -0
- package/src/shell/workspaceIcons.ts +76 -0
- package/types/chrome/BackofficeAwesomebar.d.ts +12 -0
- package/types/chrome/BackofficeAwesomebar.d.ts.map +1 -0
- package/types/chrome/CommandPalette.d.ts +6 -0
- package/types/chrome/CommandPalette.d.ts.map +1 -0
- package/types/chrome/HelpMenu.d.ts +2 -0
- package/types/chrome/HelpMenu.d.ts.map +1 -0
- package/types/chrome/NotificationsButton.d.ts +2 -0
- package/types/chrome/NotificationsButton.d.ts.map +1 -0
- package/types/chrome/UserMenu.d.ts +6 -0
- package/types/chrome/UserMenu.d.ts.map +1 -0
- package/types/chrome/awesomebar-data.d.ts +52 -0
- package/types/chrome/awesomebar-data.d.ts.map +1 -0
- package/types/chrome/command-palette-model.d.ts +47 -0
- package/types/chrome/command-palette-model.d.ts.map +1 -0
- package/types/chrome/help-about-dialog.d.ts +12 -0
- package/types/chrome/help-about-dialog.d.ts.map +1 -0
- package/types/chrome/help-shortcuts-dialog.d.ts +6 -0
- package/types/chrome/help-shortcuts-dialog.d.ts.map +1 -0
- package/types/chrome/notifications-data.d.ts +34 -0
- package/types/chrome/notifications-data.d.ts.map +1 -0
- package/types/chrome/notifications-panel.d.ts +11 -0
- package/types/chrome/notifications-panel.d.ts.map +1 -0
- package/types/chrome/notifications-utils.d.ts +21 -0
- package/types/chrome/notifications-utils.d.ts.map +1 -0
- package/types/chrome/shortcuts.d.ts +6 -0
- package/types/chrome/shortcuts.d.ts.map +1 -0
- package/types/chrome/user-session.d.ts +19 -0
- package/types/chrome/user-session.d.ts.map +1 -0
- package/types/config/BackofficeProvider.d.ts +128 -0
- package/types/config/BackofficeProvider.d.ts.map +1 -0
- package/types/config/capabilities.d.ts +109 -0
- package/types/config/capabilities.d.ts.map +1 -0
- package/types/config/events.d.ts +39 -0
- package/types/config/events.d.ts.map +1 -0
- package/types/config/slots.d.ts +32 -0
- package/types/config/slots.d.ts.map +1 -0
- package/types/i18n/en.d.ts +83 -0
- package/types/i18n/en.d.ts.map +1 -0
- package/types/i18n/index.d.ts +27 -0
- package/types/i18n/index.d.ts.map +1 -0
- package/types/index.d.ts +55 -0
- package/types/index.d.ts.map +1 -0
- package/types/navigation/navigator.d.ts +98 -0
- package/types/navigation/navigator.d.ts.map +1 -0
- package/types/navigation/paths.d.ts +60 -0
- package/types/navigation/paths.d.ts.map +1 -0
- package/types/oneAdapter/index.d.ts +8 -0
- package/types/oneAdapter/index.d.ts.map +1 -0
- package/types/shared/useFrappeApp.d.ts +10 -0
- package/types/shared/useFrappeApp.d.ts.map +1 -0
- package/types/shell/BackofficeShell.d.ts +10 -0
- package/types/shell/BackofficeShell.d.ts.map +1 -0
- package/types/shell/WorkspaceSidebar.d.ts +9 -0
- package/types/shell/WorkspaceSidebar.d.ts.map +1 -0
- package/types/shell/useWorkspaces.d.ts +43 -0
- package/types/shell/useWorkspaces.d.ts.map +1 -0
- package/types/shell/workspaceIcons.d.ts +9 -0
- package/types/shell/workspaceIcons.d.ts.map +1 -0
package/src/i18n/en.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled English resources for the "backoffice" i18n namespace.
|
|
3
|
+
*
|
|
4
|
+
* Keys mirror the surface structure (shell/sidebar/awesomebar/notifications/
|
|
5
|
+
* userMenu/help). Host apps override by registering their own bundle:
|
|
6
|
+
*
|
|
7
|
+
* i18next.addResourceBundle("en", "backoffice", { shell: { title: "Admin" } }, true, true);
|
|
8
|
+
*/
|
|
9
|
+
export const en = {
|
|
10
|
+
shell: {
|
|
11
|
+
title: "Backoffice",
|
|
12
|
+
home: "Home",
|
|
13
|
+
toggleSidebar: "Toggle sidebar",
|
|
14
|
+
},
|
|
15
|
+
sidebar: {
|
|
16
|
+
private: "Private",
|
|
17
|
+
public: "Public",
|
|
18
|
+
loading: "Loading workspaces",
|
|
19
|
+
},
|
|
20
|
+
awesomebar: {
|
|
21
|
+
triggerLabel: "Search",
|
|
22
|
+
placeholder: "Search or type a command…",
|
|
23
|
+
label: "Search or type a command",
|
|
24
|
+
results: "Search results",
|
|
25
|
+
recents: "Recents",
|
|
26
|
+
actions: "Actions",
|
|
27
|
+
navigation: "Navigation",
|
|
28
|
+
documents: "Documents",
|
|
29
|
+
listCommand: "{{doctype}} List",
|
|
30
|
+
newCommand: "New {{doctype}}",
|
|
31
|
+
reportCommand: "{{doctype}} Report",
|
|
32
|
+
kanbanCommand: "{{doctype}} Kanban",
|
|
33
|
+
workspaceBadge: "Workspace",
|
|
34
|
+
doctypeBadge: "DocType",
|
|
35
|
+
searching: "Searching…",
|
|
36
|
+
noResults: "No results for “{{query}}”",
|
|
37
|
+
empty: "Type to search…",
|
|
38
|
+
hintNavigate: "navigate",
|
|
39
|
+
hintOpen: "open",
|
|
40
|
+
hintClose: "close",
|
|
41
|
+
},
|
|
42
|
+
notifications: {
|
|
43
|
+
title: "Notifications",
|
|
44
|
+
untitled: "Notification",
|
|
45
|
+
markAllRead: "Mark all as read",
|
|
46
|
+
settingsUnavailable: "Notification settings (not available yet)",
|
|
47
|
+
emptyTitle: "No new notifications",
|
|
48
|
+
emptyDescription: "Mentions, assignments, and shares will show up here.",
|
|
49
|
+
},
|
|
50
|
+
userMenu: {
|
|
51
|
+
label: "User menu",
|
|
52
|
+
sessionUnavailable: "Session not loaded",
|
|
53
|
+
myProfile: "My Profile",
|
|
54
|
+
mySettings: "My Settings",
|
|
55
|
+
sessionDefaults: "Session Defaults",
|
|
56
|
+
sessionDefaultsGap: "Not implemented yet",
|
|
57
|
+
reload: "Reload",
|
|
58
|
+
toggleTheme: "Toggle Theme",
|
|
59
|
+
themeUnavailable: "Theme switching is unavailable on this platform",
|
|
60
|
+
viewWebsite: "View Website",
|
|
61
|
+
exitToSite: "← multiplatform.one",
|
|
62
|
+
logOut: "Log Out",
|
|
63
|
+
},
|
|
64
|
+
help: {
|
|
65
|
+
label: "Help",
|
|
66
|
+
documentation: "Documentation",
|
|
67
|
+
userForum: "User Forum",
|
|
68
|
+
reportIssue: "Report an Issue",
|
|
69
|
+
keyboardShortcuts: "Keyboard Shortcuts",
|
|
70
|
+
about: "About",
|
|
71
|
+
aboutTitle: "About",
|
|
72
|
+
aboutTagline:
|
|
73
|
+
"Backoffice is the multiplatform.one recreation of the Frappe Desk — one codebase across web, mobile, and desktop.",
|
|
74
|
+
installedApps: "Installed Apps",
|
|
75
|
+
versionsUnavailable: "Version information is unavailable.",
|
|
76
|
+
close: "Close",
|
|
77
|
+
shortcutsTitle: "Keyboard Shortcuts",
|
|
78
|
+
shortcutsIntro: "Shortcuts available across the backoffice (web).",
|
|
79
|
+
shortcutFocusSearch: "Open the command palette",
|
|
80
|
+
shortcutSaveForm: "Save the open document",
|
|
81
|
+
shortcutCloseOverlays: "Close dialogs and menus",
|
|
82
|
+
},
|
|
83
|
+
} as const;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backoffice i18n — the package ships its own translations under the
|
|
3
|
+
* "backoffice" namespace (English bundled; more languages can join the
|
|
4
|
+
* BUNDLED_RESOURCES map) and registers them into the ambient i18next
|
|
5
|
+
* instance, following @multiplatform.one/i18n conventions:
|
|
6
|
+
*
|
|
7
|
+
* - registration is additive: `addResourceBundle(lng, ns, …, deep=true,
|
|
8
|
+
* overwrite=false)`, so anything the HOST already registered for the
|
|
9
|
+
* namespace wins, and a Frappe i18n backend (partialBundledLanguages)
|
|
10
|
+
* can still supplement over the bundle.
|
|
11
|
+
* - every t() call in the package also carries an inline English default,
|
|
12
|
+
* so a missing bundle degrades to English instead of raw keys.
|
|
13
|
+
*
|
|
14
|
+
* When no i18next instance was initialized at all (a host app that does not
|
|
15
|
+
* use i18n), the provider initializes a minimal English-only instance so
|
|
16
|
+
* react-i18next binds a working `t`.
|
|
17
|
+
*/
|
|
18
|
+
import i18next, { type i18n as I18nInstance } from "i18next";
|
|
19
|
+
import { initReactI18next } from "react-i18next";
|
|
20
|
+
import { en } from "./en";
|
|
21
|
+
|
|
22
|
+
export const BACKOFFICE_I18N_NAMESPACE = "backoffice";
|
|
23
|
+
|
|
24
|
+
const BUNDLED_RESOURCES: Record<string, object> = { en };
|
|
25
|
+
|
|
26
|
+
const registeredInstances = new WeakSet<I18nInstance>();
|
|
27
|
+
|
|
28
|
+
function addBundles(instance: I18nInstance): void {
|
|
29
|
+
for (const [lng, resources] of Object.entries(BUNDLED_RESOURCES)) {
|
|
30
|
+
// deep merge, never overwrite — host-registered keys take precedence.
|
|
31
|
+
instance.addResourceBundle(lng, BACKOFFICE_I18N_NAMESPACE, resources, true, false);
|
|
32
|
+
}
|
|
33
|
+
// Satisfy backends that lazy-load namespaces (react-i18next readiness).
|
|
34
|
+
void instance.loadNamespaces(BACKOFFICE_I18N_NAMESPACE).catch(() => {});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Idempotently register the bundled backoffice translations on `instance`
|
|
39
|
+
* (the global i18next singleton by default). Safe to call before the host
|
|
40
|
+
* initializes i18next — registration is deferred to the `initialized` event.
|
|
41
|
+
* Called automatically by BackofficeProvider.
|
|
42
|
+
*/
|
|
43
|
+
export function registerBackofficeTranslations(instance: I18nInstance = i18next): void {
|
|
44
|
+
if (registeredInstances.has(instance)) return;
|
|
45
|
+
registeredInstances.add(instance);
|
|
46
|
+
|
|
47
|
+
if (instance.isInitialized) {
|
|
48
|
+
addBundles(instance);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
instance.on("initialized", () => addBundles(instance));
|
|
53
|
+
|
|
54
|
+
// No host i18n at all: bring up a minimal instance so t() works. Guarded
|
|
55
|
+
// against a host init that is merely in flight.
|
|
56
|
+
const initializing = (instance as { isInitializing?: boolean }).isInitializing;
|
|
57
|
+
if (!initializing && !instance.isInitialized) {
|
|
58
|
+
void instance.use(initReactI18next).init({
|
|
59
|
+
lng: "en",
|
|
60
|
+
fallbackLng: "en",
|
|
61
|
+
defaultNS: BACKOFFICE_I18N_NAMESPACE,
|
|
62
|
+
ns: [BACKOFFICE_I18N_NAMESPACE],
|
|
63
|
+
resources: {},
|
|
64
|
+
interpolation: { escapeValue: false },
|
|
65
|
+
returnNull: false,
|
|
66
|
+
returnEmptyString: false,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @multiplatform.one/backoffice — embeddable Frappe desk recreation.
|
|
3
|
+
*
|
|
4
|
+
* Mount BackofficeProvider (frappe connection + navigation adapter +
|
|
5
|
+
* capability flags) around the surfaces you want; BackofficeShell is the
|
|
6
|
+
* full desk chrome. See README.md for the embedding story.
|
|
7
|
+
*
|
|
8
|
+
* The one-router adapter lives on the `./one-adapter` subpath so this entry
|
|
9
|
+
* stays router-free.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Provider + config
|
|
13
|
+
export {
|
|
14
|
+
BackofficeProvider,
|
|
15
|
+
useBackofficeCapabilities,
|
|
16
|
+
useBackofficeConfig,
|
|
17
|
+
useBackofficeLocation,
|
|
18
|
+
useBackofficeNavigator,
|
|
19
|
+
useBackofficePaths,
|
|
20
|
+
useBackofficeSlots,
|
|
21
|
+
useIsDoctypeAllowed,
|
|
22
|
+
} from "./config/BackofficeProvider";
|
|
23
|
+
export type {
|
|
24
|
+
BackofficeAction,
|
|
25
|
+
BackofficeActionContext,
|
|
26
|
+
BackofficeActions,
|
|
27
|
+
BackofficeAppearance,
|
|
28
|
+
BackofficeConfig,
|
|
29
|
+
BackofficeFrappeConfig,
|
|
30
|
+
BackofficeProviderProps,
|
|
31
|
+
} from "./config/BackofficeProvider";
|
|
32
|
+
export { isDoctypeAllowed, resolveCapabilities } from "./config/capabilities";
|
|
33
|
+
export type {
|
|
34
|
+
BackofficeCapabilities,
|
|
35
|
+
BackofficeDoctypeScope,
|
|
36
|
+
CapabilityInput,
|
|
37
|
+
ResolvedBackofficeCapabilities,
|
|
38
|
+
ResolvedCapability,
|
|
39
|
+
ResolvedExitToSite,
|
|
40
|
+
} from "./config/capabilities";
|
|
41
|
+
export type { BackofficeEvent, BackofficeEventHandler } from "./config/events";
|
|
42
|
+
export type { BackofficeSlots } from "./config/slots";
|
|
43
|
+
|
|
44
|
+
// Navigation seam
|
|
45
|
+
export {
|
|
46
|
+
ControlledNavigator,
|
|
47
|
+
MemoryNavigator,
|
|
48
|
+
createMemoryNavigator,
|
|
49
|
+
createNoopNavigator,
|
|
50
|
+
parseBackofficeHref,
|
|
51
|
+
} from "./navigation/navigator";
|
|
52
|
+
export type {
|
|
53
|
+
BackofficeLocation,
|
|
54
|
+
BackofficeNavigator,
|
|
55
|
+
BackofficeParams,
|
|
56
|
+
ControlledNavigatorHandlers,
|
|
57
|
+
} from "./navigation/navigator";
|
|
58
|
+
export {
|
|
59
|
+
BACKOFFICE_BASE,
|
|
60
|
+
BACKOFFICE_VIEWS,
|
|
61
|
+
createBackofficePaths,
|
|
62
|
+
formPath,
|
|
63
|
+
homePath,
|
|
64
|
+
isBackofficeView,
|
|
65
|
+
listPath,
|
|
66
|
+
newDocPath,
|
|
67
|
+
parseDocDefaults,
|
|
68
|
+
slugToDisplayName,
|
|
69
|
+
toSlug,
|
|
70
|
+
viewPath,
|
|
71
|
+
workspacePath,
|
|
72
|
+
} from "./navigation/paths";
|
|
73
|
+
export type {
|
|
74
|
+
BackofficePath,
|
|
75
|
+
BackofficePaths,
|
|
76
|
+
BackofficeSubPath,
|
|
77
|
+
BackofficeView,
|
|
78
|
+
} from "./navigation/paths";
|
|
79
|
+
|
|
80
|
+
// i18n
|
|
81
|
+
export { BACKOFFICE_I18N_NAMESPACE, registerBackofficeTranslations } from "./i18n";
|
|
82
|
+
|
|
83
|
+
// Shell
|
|
84
|
+
export { BackofficeShell } from "./shell/BackofficeShell";
|
|
85
|
+
export type { BackofficeShellProps } from "./shell/BackofficeShell";
|
|
86
|
+
export { WORKSPACE_SIDEBAR_WIDTH, WorkspaceSidebar } from "./shell/WorkspaceSidebar";
|
|
87
|
+
export type { WorkspaceSidebarProps } from "./shell/WorkspaceSidebar";
|
|
88
|
+
export { useDefaultWorkspace, useSessionUser, useWorkspaces } from "./shell/useWorkspaces";
|
|
89
|
+
export type { WorkspaceDoc, WorkspacesResult } from "./shell/useWorkspaces";
|
|
90
|
+
export { workspaceIcon } from "./shell/workspaceIcons";
|
|
91
|
+
|
|
92
|
+
// Chrome
|
|
93
|
+
export { BackofficeAwesomebar } from "./chrome/BackofficeAwesomebar";
|
|
94
|
+
export type {
|
|
95
|
+
BackofficeAwesomebarHandle,
|
|
96
|
+
BackofficeAwesomebarProps,
|
|
97
|
+
} from "./chrome/BackofficeAwesomebar";
|
|
98
|
+
export { CommandPalette } from "./chrome/CommandPalette";
|
|
99
|
+
export type { CommandPaletteProps } from "./chrome/CommandPalette";
|
|
100
|
+
export { useCommandPaletteModel } from "./chrome/command-palette-model";
|
|
101
|
+
export type {
|
|
102
|
+
CommandPaletteItem,
|
|
103
|
+
CommandPaletteModel,
|
|
104
|
+
CommandPaletteSection,
|
|
105
|
+
CommandPaletteSectionId,
|
|
106
|
+
UseCommandPaletteModelOptions,
|
|
107
|
+
} from "./chrome/command-palette-model";
|
|
108
|
+
export {
|
|
109
|
+
rankNameMatches,
|
|
110
|
+
readRecentItems,
|
|
111
|
+
toContentSnippet,
|
|
112
|
+
useAwesomebarCatalog,
|
|
113
|
+
useGlobalSearch,
|
|
114
|
+
} from "./chrome/awesomebar-data";
|
|
115
|
+
export type {
|
|
116
|
+
AwesomebarCatalog,
|
|
117
|
+
AwesomebarCatalogState,
|
|
118
|
+
AwesomebarWorkspace,
|
|
119
|
+
GlobalSearchHit,
|
|
120
|
+
GlobalSearchState,
|
|
121
|
+
RecentItem,
|
|
122
|
+
} from "./chrome/awesomebar-data";
|
|
123
|
+
export { NotificationsButton } from "./chrome/NotificationsButton";
|
|
124
|
+
export { NotificationsPanel } from "./chrome/notifications-panel";
|
|
125
|
+
export type { NotificationsPanelProps } from "./chrome/notifications-panel";
|
|
126
|
+
export { useNotifications } from "./chrome/notifications-data";
|
|
127
|
+
export type {
|
|
128
|
+
NotificationItem,
|
|
129
|
+
NotificationLogDoc,
|
|
130
|
+
UseNotificationsResult,
|
|
131
|
+
} from "./chrome/notifications-data";
|
|
132
|
+
export { parseFrappeTimestamp, stripHtmlToText } from "./chrome/notifications-utils";
|
|
133
|
+
export { HelpMenu } from "./chrome/HelpMenu";
|
|
134
|
+
export { HelpAboutDialog } from "./chrome/help-about-dialog";
|
|
135
|
+
export type { FrappeAppVersion, HelpAboutDialogProps } from "./chrome/help-about-dialog";
|
|
136
|
+
export { HelpShortcutsDialog } from "./chrome/help-shortcuts-dialog";
|
|
137
|
+
export type { HelpShortcutsDialogProps } from "./chrome/help-shortcuts-dialog";
|
|
138
|
+
export { UserMenu } from "./chrome/UserMenu";
|
|
139
|
+
export type { UserMenuProps } from "./chrome/UserMenu";
|
|
140
|
+
export {
|
|
141
|
+
clearSessionUserCache,
|
|
142
|
+
resolveUserImageUrl,
|
|
143
|
+
useSessionUserInfo,
|
|
144
|
+
} from "./chrome/user-session";
|
|
145
|
+
export type { SessionUserInfo } from "./chrome/user-session";
|
|
146
|
+
export { useBackofficeShortcuts } from "./chrome/shortcuts";
|
|
147
|
+
export type { BackofficeShortcutHandlers } from "./chrome/shortcuts";
|
|
148
|
+
|
|
149
|
+
// Shared
|
|
150
|
+
export { useFrappeApp } from "./shared/useFrappeApp";
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ControlledNavigator, createMemoryNavigator, parseBackofficeHref } from "./navigator";
|
|
3
|
+
|
|
4
|
+
describe("parseBackofficeHref", () => {
|
|
5
|
+
it("splits path and query params", () => {
|
|
6
|
+
const location = parseBackofficeHref("/backoffice/todo?f=abc&x=1");
|
|
7
|
+
expect(location.path).toBe("/backoffice/todo");
|
|
8
|
+
expect(location.params).toEqual({ f: "abc", x: "1" });
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("collects repeated keys into arrays", () => {
|
|
12
|
+
const location = parseBackofficeHref("/backoffice?tag=a&tag=b");
|
|
13
|
+
expect(location.params).toEqual({ tag: ["a", "b"] });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("decodes percent-encoded params", () => {
|
|
17
|
+
const location = parseBackofficeHref(
|
|
18
|
+
"/backoffice/sales-order?d=%7B%22status%22%3A%22Open%22%7D",
|
|
19
|
+
);
|
|
20
|
+
expect(location.params.d).toBe('{"status":"Open"}');
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("MemoryNavigator (navigator contract)", () => {
|
|
25
|
+
it("starts on the initial path", () => {
|
|
26
|
+
const navigator = createMemoryNavigator("/backoffice");
|
|
27
|
+
expect(navigator.getLocation()).toEqual({ path: "/backoffice", params: {} });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("navigate pushes entries and notifies subscribers", () => {
|
|
31
|
+
const navigator = createMemoryNavigator("/backoffice");
|
|
32
|
+
const listener = vi.fn();
|
|
33
|
+
navigator.subscribe(listener);
|
|
34
|
+
|
|
35
|
+
navigator.navigate("/backoffice/todo?f=x");
|
|
36
|
+
|
|
37
|
+
expect(listener).toHaveBeenCalledTimes(1);
|
|
38
|
+
expect(navigator.getLocation()).toEqual({ path: "/backoffice/todo", params: { f: "x" } });
|
|
39
|
+
expect(navigator.entries).toHaveLength(2);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("replace swaps the top entry without growing the stack", () => {
|
|
43
|
+
const navigator = createMemoryNavigator("/backoffice");
|
|
44
|
+
navigator.navigate("/backoffice/todo");
|
|
45
|
+
navigator.replace("/backoffice/note");
|
|
46
|
+
|
|
47
|
+
expect(navigator.entries).toHaveLength(2);
|
|
48
|
+
expect(navigator.getLocation().path).toBe("/backoffice/note");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("back pops to the previous entry and is a no-op at the root", () => {
|
|
52
|
+
const navigator = createMemoryNavigator("/backoffice");
|
|
53
|
+
navigator.navigate("/backoffice/todo");
|
|
54
|
+
navigator.back();
|
|
55
|
+
expect(navigator.getLocation().path).toBe("/backoffice");
|
|
56
|
+
|
|
57
|
+
navigator.back();
|
|
58
|
+
expect(navigator.getLocation().path).toBe("/backoffice");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("getLocation identity is stable until the location changes", () => {
|
|
62
|
+
const navigator = createMemoryNavigator("/backoffice");
|
|
63
|
+
const first = navigator.getLocation();
|
|
64
|
+
expect(navigator.getLocation()).toBe(first);
|
|
65
|
+
navigator.navigate("/backoffice/todo");
|
|
66
|
+
expect(navigator.getLocation()).not.toBe(first);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("unsubscribe stops notifications", () => {
|
|
70
|
+
const navigator = createMemoryNavigator("/backoffice");
|
|
71
|
+
const listener = vi.fn();
|
|
72
|
+
const unsubscribe = navigator.subscribe(listener);
|
|
73
|
+
unsubscribe();
|
|
74
|
+
navigator.navigate("/backoffice/todo");
|
|
75
|
+
expect(listener).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("ControlledNavigator (bridge contract)", () => {
|
|
80
|
+
it("forwards navigation to the host handlers", () => {
|
|
81
|
+
const handlers = { navigate: vi.fn(), replace: vi.fn(), back: vi.fn() };
|
|
82
|
+
const navigator = new ControlledNavigator(handlers, { path: "/backoffice", params: {} });
|
|
83
|
+
|
|
84
|
+
navigator.navigate("/backoffice/todo");
|
|
85
|
+
navigator.replace("/backoffice/note");
|
|
86
|
+
navigator.back();
|
|
87
|
+
|
|
88
|
+
expect(handlers.navigate).toHaveBeenCalledWith("/backoffice/todo");
|
|
89
|
+
expect(handlers.replace).toHaveBeenCalledWith("/backoffice/note");
|
|
90
|
+
expect(handlers.back).toHaveBeenCalledTimes(1);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("mirrors host location through setLocation and notifies", () => {
|
|
94
|
+
const navigator = new ControlledNavigator(
|
|
95
|
+
{ navigate: () => {}, replace: () => {}, back: () => {} },
|
|
96
|
+
{ path: "/backoffice", params: {} },
|
|
97
|
+
);
|
|
98
|
+
const listener = vi.fn();
|
|
99
|
+
navigator.subscribe(listener);
|
|
100
|
+
|
|
101
|
+
navigator.setLocation({ path: "/backoffice/todo", params: { f: "x" } });
|
|
102
|
+
|
|
103
|
+
expect(listener).toHaveBeenCalledTimes(1);
|
|
104
|
+
expect(navigator.getLocation().path).toBe("/backoffice/todo");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backoffice navigation seam.
|
|
3
|
+
*
|
|
4
|
+
* The backoffice never imports a router. Every surface navigates through a
|
|
5
|
+
* host-supplied {@link BackofficeNavigator} — a deliberately minimal contract
|
|
6
|
+
* (push/replace/back + a subscribable location) that any routing runtime can
|
|
7
|
+
* satisfy in a few lines:
|
|
8
|
+
*
|
|
9
|
+
* - One router → `useOneNavigator()` from
|
|
10
|
+
* `@multiplatform.one/backoffice/one-adapter`
|
|
11
|
+
* - tests/storybook → {@link createMemoryNavigator}
|
|
12
|
+
* - custom hosts → {@link ControlledNavigator} (bridge callbacks in,
|
|
13
|
+
* mirror location back with `setLocation`)
|
|
14
|
+
*
|
|
15
|
+
* This is intentionally lighter than the stack-navigation seam in
|
|
16
|
+
* `@multiplatform.one/router/seam`: that module OWNS a navigation stack
|
|
17
|
+
* (route manifest + host stack adapter) for targets with no router at all,
|
|
18
|
+
* while this contract EMBEDS into whatever router the host app already runs.
|
|
19
|
+
* A seam-backed host can still implement this interface over its
|
|
20
|
+
* StackNavigator (push/replace/back map 1:1, location from `useNavState`).
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export type BackofficeParams = Record<string, string | string[] | undefined>;
|
|
24
|
+
|
|
25
|
+
export interface BackofficeLocation {
|
|
26
|
+
/** Current pathname (no query string), e.g. `"/backoffice/todo"`. */
|
|
27
|
+
path: string;
|
|
28
|
+
/** Dynamic route segments merged with query params (One router semantics). */
|
|
29
|
+
params: BackofficeParams;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface BackofficeNavigator {
|
|
33
|
+
/** Push a new history entry. */
|
|
34
|
+
navigate(path: string): void;
|
|
35
|
+
/** Replace the current history entry. */
|
|
36
|
+
replace(path: string): void;
|
|
37
|
+
/** Go back one entry. */
|
|
38
|
+
back(): void;
|
|
39
|
+
/** Snapshot of the current location (stable identity until it changes). */
|
|
40
|
+
getLocation(): BackofficeLocation;
|
|
41
|
+
/** Subscribe to location changes. Returns an unsubscribe function. */
|
|
42
|
+
subscribe(listener: () => void): () => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Minimal query parser (repeated keys become arrays). Deliberately not
|
|
47
|
+
* URLSearchParams so this module has zero polyfill-order dependency — same
|
|
48
|
+
* trade the router seam makes for GJS entries.
|
|
49
|
+
*/
|
|
50
|
+
function parseQuery(query: string | undefined): BackofficeParams {
|
|
51
|
+
const params: BackofficeParams = {};
|
|
52
|
+
if (!query) return params;
|
|
53
|
+
for (const pair of query.split("&")) {
|
|
54
|
+
if (!pair) continue;
|
|
55
|
+
const eq = pair.indexOf("=");
|
|
56
|
+
const rawKey = eq === -1 ? pair : pair.slice(0, eq);
|
|
57
|
+
const rawValue = eq === -1 ? "" : pair.slice(eq + 1);
|
|
58
|
+
let key = rawKey;
|
|
59
|
+
let value = rawValue;
|
|
60
|
+
try {
|
|
61
|
+
key = decodeURIComponent(rawKey);
|
|
62
|
+
value = decodeURIComponent(rawValue);
|
|
63
|
+
} catch {
|
|
64
|
+
// malformed escape — keep the raw pair
|
|
65
|
+
}
|
|
66
|
+
const prev = params[key];
|
|
67
|
+
if (prev === undefined) params[key] = value;
|
|
68
|
+
else if (Array.isArray(prev)) prev.push(value);
|
|
69
|
+
else params[key] = [prev, value];
|
|
70
|
+
}
|
|
71
|
+
return params;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Split an href into a {@link BackofficeLocation} (query → params). */
|
|
75
|
+
export function parseBackofficeHref(href: string): BackofficeLocation {
|
|
76
|
+
const queryIndex = href.indexOf("?");
|
|
77
|
+
const path = queryIndex === -1 ? href : href.slice(0, queryIndex);
|
|
78
|
+
const query = queryIndex === -1 ? undefined : href.slice(queryIndex + 1);
|
|
79
|
+
return { path: path || "/", params: parseQuery(query) };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type Listener = () => void;
|
|
83
|
+
|
|
84
|
+
abstract class SubscribableNavigator implements BackofficeNavigator {
|
|
85
|
+
protected listeners = new Set<Listener>();
|
|
86
|
+
protected location: BackofficeLocation;
|
|
87
|
+
|
|
88
|
+
constructor(initialLocation: BackofficeLocation) {
|
|
89
|
+
this.location = initialLocation;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
abstract navigate(path: string): void;
|
|
93
|
+
abstract replace(path: string): void;
|
|
94
|
+
abstract back(): void;
|
|
95
|
+
|
|
96
|
+
getLocation = (): BackofficeLocation => this.location;
|
|
97
|
+
|
|
98
|
+
subscribe = (listener: Listener): (() => void) => {
|
|
99
|
+
this.listeners.add(listener);
|
|
100
|
+
return () => this.listeners.delete(listener);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
protected setLocationInternal(next: BackofficeLocation): void {
|
|
104
|
+
if (next.path === this.location.path && next.params === this.location.params) return;
|
|
105
|
+
this.location = next;
|
|
106
|
+
for (const listener of this.listeners) listener();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* In-memory navigator — a self-contained history stack for tests, stories,
|
|
112
|
+
* and hosts with no routing runtime (e.g. a modal embedding of a single
|
|
113
|
+
* backoffice surface).
|
|
114
|
+
*/
|
|
115
|
+
export class MemoryNavigator extends SubscribableNavigator {
|
|
116
|
+
private stack: BackofficeLocation[];
|
|
117
|
+
|
|
118
|
+
constructor(initialPath = "/backoffice") {
|
|
119
|
+
const initial = parseBackofficeHref(initialPath);
|
|
120
|
+
super(initial);
|
|
121
|
+
this.stack = [initial];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** History entries, oldest first (test introspection). */
|
|
125
|
+
get entries(): readonly BackofficeLocation[] {
|
|
126
|
+
return this.stack;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
navigate = (path: string): void => {
|
|
130
|
+
const next = parseBackofficeHref(path);
|
|
131
|
+
this.stack.push(next);
|
|
132
|
+
this.setLocationInternal(next);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
replace = (path: string): void => {
|
|
136
|
+
const next = parseBackofficeHref(path);
|
|
137
|
+
this.stack[this.stack.length - 1] = next;
|
|
138
|
+
this.setLocationInternal(next);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
back = (): void => {
|
|
142
|
+
if (this.stack.length <= 1) return;
|
|
143
|
+
this.stack.pop();
|
|
144
|
+
const top = this.stack[this.stack.length - 1];
|
|
145
|
+
if (top) this.setLocationInternal(top);
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function createMemoryNavigator(initialPath = "/backoffice"): MemoryNavigator {
|
|
150
|
+
return new MemoryNavigator(initialPath);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface ControlledNavigatorHandlers {
|
|
154
|
+
navigate(path: string): void;
|
|
155
|
+
replace(path: string): void;
|
|
156
|
+
back(): void;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Bridge navigator for adapters over an external router: navigation calls
|
|
161
|
+
* forward to the host handlers, and the host mirrors its location back via
|
|
162
|
+
* {@link ControlledNavigator.setLocation}. The one-adapter is ~20 lines over
|
|
163
|
+
* this class; a react-router or seam adapter looks the same.
|
|
164
|
+
*/
|
|
165
|
+
export class ControlledNavigator extends SubscribableNavigator {
|
|
166
|
+
private handlers: ControlledNavigatorHandlers;
|
|
167
|
+
|
|
168
|
+
constructor(handlers: ControlledNavigatorHandlers, initialLocation?: BackofficeLocation) {
|
|
169
|
+
super(initialLocation ?? { path: "/", params: {} });
|
|
170
|
+
this.handlers = handlers;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Swap the forwarding callbacks (adapters keep them fresh per render). */
|
|
174
|
+
setHandlers(handlers: ControlledNavigatorHandlers): void {
|
|
175
|
+
this.handlers = handlers;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Mirror the host router's current location into the navigator. */
|
|
179
|
+
setLocation(next: BackofficeLocation): void {
|
|
180
|
+
this.setLocationInternal(next);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
navigate = (path: string): void => {
|
|
184
|
+
this.handlers.navigate(path);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
replace = (path: string): void => {
|
|
188
|
+
this.handlers.replace(path);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
back = (): void => {
|
|
192
|
+
this.handlers.back();
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Inert navigator — the default-context fallback so package surfaces render
|
|
198
|
+
* (and stories mount) without a BackofficeProvider. Navigation is a no-op.
|
|
199
|
+
*/
|
|
200
|
+
export function createNoopNavigator(initialPath = "/backoffice"): BackofficeNavigator {
|
|
201
|
+
const location = parseBackofficeHref(initialPath);
|
|
202
|
+
return {
|
|
203
|
+
navigate: () => {},
|
|
204
|
+
replace: () => {},
|
|
205
|
+
back: () => {},
|
|
206
|
+
getLocation: () => location,
|
|
207
|
+
subscribe: () => () => {},
|
|
208
|
+
};
|
|
209
|
+
}
|