@endora-commerce/admin-shell 0.107.0 → 0.109.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 (396) hide show
  1. package/README.md +1 -1
  2. package/dist/AdminRoot.js +1 -1
  3. package/dist/AdminRoot.js.map +1 -1
  4. package/dist/App.d.ts.map +1 -1
  5. package/dist/App.js +2 -6
  6. package/dist/App.js.map +1 -1
  7. package/dist/components/AdminFeedback.d.ts +21 -0
  8. package/dist/components/AdminFeedback.d.ts.map +1 -0
  9. package/dist/components/AdminFeedback.js +109 -0
  10. package/dist/components/AdminFeedback.js.map +1 -0
  11. package/dist/components/AppShell.d.ts.map +1 -1
  12. package/dist/components/AppShell.js +179 -143
  13. package/dist/components/AppShell.js.map +1 -1
  14. package/dist/components/FederatedSignIn.d.ts.map +1 -1
  15. package/dist/components/FederatedSignIn.js +1 -2
  16. package/dist/components/FederatedSignIn.js.map +1 -1
  17. package/dist/components/IdleLogout.js +1 -1
  18. package/dist/components/IdleLogout.js.map +1 -1
  19. package/dist/components/ImpersonationBanner.d.ts.map +1 -1
  20. package/dist/components/ImpersonationBanner.js +2 -3
  21. package/dist/components/ImpersonationBanner.js.map +1 -1
  22. package/dist/components/LanguagePicker.d.ts.map +1 -1
  23. package/dist/components/LanguagePicker.js +2 -5
  24. package/dist/components/LanguagePicker.js.map +1 -1
  25. package/dist/components/LoginPage.d.ts.map +1 -1
  26. package/dist/components/LoginPage.js +2 -6
  27. package/dist/components/LoginPage.js.map +1 -1
  28. package/dist/components/RoleRequiredNotice.js +2 -2
  29. package/dist/components/RoleRequiredNotice.js.map +1 -1
  30. package/dist/components/SpeechToTextButton.js +1 -1
  31. package/dist/components/SpeechToTextButton.js.map +1 -1
  32. package/dist/components/VersionBadge.js +2 -2
  33. package/dist/components/VersionBadge.js.map +1 -1
  34. package/dist/components/notifications/NotificationBell.d.ts.map +1 -1
  35. package/dist/components/notifications/NotificationBell.js +1 -2
  36. package/dist/components/notifications/NotificationBell.js.map +1 -1
  37. package/dist/components/notifications/notification-text.d.ts +1 -1
  38. package/dist/components/notifications/notification-text.d.ts.map +1 -1
  39. package/dist/components/notifications/notification-text.js +1 -2
  40. package/dist/components/notifications/notification-text.js.map +1 -1
  41. package/dist/components/notifications/useAdminNotifications.js +1 -1
  42. package/dist/components/notifications/useAdminNotifications.js.map +1 -1
  43. package/dist/components/prompt-actions/PromptModePanel.js +2 -2
  44. package/dist/components/prompt-actions/PromptModePanel.js.map +1 -1
  45. package/dist/components/prompt-actions/PromptPlanPreview.js +2 -2
  46. package/dist/components/prompt-actions/PromptPlanPreview.js.map +1 -1
  47. package/dist/components/sidebar/PinToggleButton.d.ts +21 -0
  48. package/dist/components/sidebar/PinToggleButton.d.ts.map +1 -0
  49. package/dist/components/sidebar/PinToggleButton.js +19 -0
  50. package/dist/components/sidebar/PinToggleButton.js.map +1 -0
  51. package/dist/components/sidebar/PinnedSection.d.ts +37 -0
  52. package/dist/components/sidebar/PinnedSection.d.ts.map +1 -0
  53. package/dist/components/sidebar/PinnedSection.js +70 -0
  54. package/dist/components/sidebar/PinnedSection.js.map +1 -0
  55. package/dist/components/sidebar/PreferencesSaveNotice.d.ts +10 -0
  56. package/dist/components/sidebar/PreferencesSaveNotice.d.ts.map +1 -0
  57. package/dist/components/sidebar/PreferencesSaveNotice.js +17 -0
  58. package/dist/components/sidebar/PreferencesSaveNotice.js.map +1 -0
  59. package/dist/components/sidebar/nav-types.d.ts +59 -0
  60. package/dist/components/sidebar/nav-types.d.ts.map +1 -0
  61. package/dist/components/sidebar/nav-types.js +2 -0
  62. package/dist/components/sidebar/nav-types.js.map +1 -0
  63. package/dist/components/sidebar/use-pin-actions.d.ts +14 -0
  64. package/dist/components/sidebar/use-pin-actions.d.ts.map +1 -0
  65. package/dist/components/sidebar/use-pin-actions.js +22 -0
  66. package/dist/components/sidebar/use-pin-actions.js.map +1 -0
  67. package/dist/index.d.ts +2 -2
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +1 -1
  70. package/dist/index.js.map +1 -1
  71. package/dist/lib/admin-actions/api.js +1 -1
  72. package/dist/lib/admin-actions/api.js.map +1 -1
  73. package/dist/lib/admin-actions/useAdminActions.d.ts +2 -1
  74. package/dist/lib/admin-actions/useAdminActions.d.ts.map +1 -1
  75. package/dist/lib/admin-actions/useAdminActions.js +5 -14
  76. package/dist/lib/admin-actions/useAdminActions.js.map +1 -1
  77. package/dist/lib/admin-feedback/api.d.ts +8 -0
  78. package/dist/lib/admin-feedback/api.d.ts.map +1 -0
  79. package/dist/lib/admin-feedback/api.js +10 -0
  80. package/dist/lib/admin-feedback/api.js.map +1 -0
  81. package/dist/lib/federated-sign-in/api.js +1 -1
  82. package/dist/lib/federated-sign-in/api.js.map +1 -1
  83. package/dist/lib/global-search/api.js +1 -1
  84. package/dist/lib/global-search/api.js.map +1 -1
  85. package/dist/lib/palette-match.d.ts +26 -0
  86. package/dist/lib/palette-match.d.ts.map +1 -0
  87. package/dist/lib/palette-match.js +36 -0
  88. package/dist/lib/palette-match.js.map +1 -0
  89. package/dist/lib/pinned-entries.d.ts +49 -0
  90. package/dist/lib/pinned-entries.d.ts.map +1 -0
  91. package/dist/lib/pinned-entries.js +58 -0
  92. package/dist/lib/pinned-entries.js.map +1 -0
  93. package/dist/lib/platform-info/api.js +1 -1
  94. package/dist/lib/platform-info/api.js.map +1 -1
  95. package/dist/lib/prompt-actions/api.js +1 -1
  96. package/dist/lib/prompt-actions/api.js.map +1 -1
  97. package/dist/lib/prompt-actions/usePromptRequest.js +1 -1
  98. package/dist/lib/prompt-actions/usePromptRequest.js.map +1 -1
  99. package/dist/modules/home/HomePage.d.ts.map +1 -1
  100. package/dist/modules/home/HomePage.js +2 -4
  101. package/dist/modules/home/HomePage.js.map +1 -1
  102. package/dist/modules/home/RecentActivityCard.d.ts.map +1 -1
  103. package/dist/modules/home/RecentActivityCard.js +1 -2
  104. package/dist/modules/home/RecentActivityCard.js.map +1 -1
  105. package/dist/modules/home/activity-render.js +1 -1
  106. package/dist/modules/home/activity-render.js.map +1 -1
  107. package/dist/modules/home/useRecentActivity.js +1 -1
  108. package/dist/modules/home/useRecentActivity.js.map +1 -1
  109. package/dist/modules/platform/ApiDescriptionPage.d.ts.map +1 -1
  110. package/dist/modules/platform/ApiDescriptionPage.js +3 -6
  111. package/dist/modules/platform/ApiDescriptionPage.js.map +1 -1
  112. package/dist/modules/platform/ModuleActivationControl.d.ts.map +1 -1
  113. package/dist/modules/platform/ModuleActivationControl.js +2 -3
  114. package/dist/modules/platform/ModuleActivationControl.js.map +1 -1
  115. package/dist/modules/platform/ModulesPage.d.ts.map +1 -1
  116. package/dist/modules/platform/ModulesPage.js +3 -9
  117. package/dist/modules/platform/ModulesPage.js.map +1 -1
  118. package/dist/modules/platform/RecentActivityVisibilityControl.js +2 -2
  119. package/dist/modules/platform/RecentActivityVisibilityControl.js.map +1 -1
  120. package/dist/modules/platform/api-description.d.ts.map +1 -1
  121. package/dist/modules/platform/api-description.js +1 -2
  122. package/dist/modules/platform/api-description.js.map +1 -1
  123. package/dist/modules/platform/api.js +1 -1
  124. package/dist/modules/platform/api.js.map +1 -1
  125. package/dist/modules/profile/ProfilePage.d.ts.map +1 -1
  126. package/dist/modules/profile/ProfilePage.js +2 -5
  127. package/dist/modules/profile/ProfilePage.js.map +1 -1
  128. package/package.json +11 -8
  129. package/dist/components/FileDropzone.d.ts +0 -17
  130. package/dist/components/FileDropzone.d.ts.map +0 -1
  131. package/dist/components/FileDropzone.js +0 -17
  132. package/dist/components/FileDropzone.js.map +0 -1
  133. package/dist/components/PaginationFooter.d.ts +0 -18
  134. package/dist/components/PaginationFooter.d.ts.map +0 -1
  135. package/dist/components/PaginationFooter.js +0 -17
  136. package/dist/components/PaginationFooter.js.map +0 -1
  137. package/dist/components/ResponsiveTable.d.ts +0 -18
  138. package/dist/components/ResponsiveTable.d.ts.map +0 -1
  139. package/dist/components/ResponsiveTable.js +0 -17
  140. package/dist/components/ResponsiveTable.js.map +0 -1
  141. package/dist/components/RowActionMenu.d.ts +0 -18
  142. package/dist/components/RowActionMenu.d.ts.map +0 -1
  143. package/dist/components/RowActionMenu.js +0 -17
  144. package/dist/components/RowActionMenu.js.map +0 -1
  145. package/dist/components/StickyFormActions.d.ts +0 -18
  146. package/dist/components/StickyFormActions.d.ts.map +0 -1
  147. package/dist/components/StickyFormActions.js +0 -17
  148. package/dist/components/StickyFormActions.js.map +0 -1
  149. package/dist/components/TouchReorderButtons.d.ts +0 -18
  150. package/dist/components/TouchReorderButtons.d.ts.map +0 -1
  151. package/dist/components/TouchReorderButtons.js +0 -17
  152. package/dist/components/TouchReorderButtons.js.map +0 -1
  153. package/dist/components/admin-user-picker/AdminUserPicker.d.ts +0 -18
  154. package/dist/components/admin-user-picker/AdminUserPicker.d.ts.map +0 -1
  155. package/dist/components/admin-user-picker/AdminUserPicker.js +0 -17
  156. package/dist/components/admin-user-picker/AdminUserPicker.js.map +0 -1
  157. package/dist/components/asset-picker/AssetFieldPicker.d.ts +0 -21
  158. package/dist/components/asset-picker/AssetFieldPicker.d.ts.map +0 -1
  159. package/dist/components/asset-picker/AssetFieldPicker.js +0 -20
  160. package/dist/components/asset-picker/AssetFieldPicker.js.map +0 -1
  161. package/dist/components/category-picker/CategorySelect.d.ts +0 -18
  162. package/dist/components/category-picker/CategorySelect.d.ts.map +0 -1
  163. package/dist/components/category-picker/CategorySelect.js +0 -17
  164. package/dist/components/category-picker/CategorySelect.js.map +0 -1
  165. package/dist/components/category-tree-picker/CategoryTreePicker.d.ts +0 -18
  166. package/dist/components/category-tree-picker/CategoryTreePicker.d.ts.map +0 -1
  167. package/dist/components/category-tree-picker/CategoryTreePicker.js +0 -17
  168. package/dist/components/category-tree-picker/CategoryTreePicker.js.map +0 -1
  169. package/dist/components/category-tree-picker/category-tree-utils.d.ts +0 -18
  170. package/dist/components/category-tree-picker/category-tree-utils.d.ts.map +0 -1
  171. package/dist/components/category-tree-picker/category-tree-utils.js +0 -17
  172. package/dist/components/category-tree-picker/category-tree-utils.js.map +0 -1
  173. package/dist/components/category-tree-picker/index.d.ts +0 -18
  174. package/dist/components/category-tree-picker/index.d.ts.map +0 -1
  175. package/dist/components/category-tree-picker/index.js +0 -17
  176. package/dist/components/category-tree-picker/index.js.map +0 -1
  177. package/dist/components/charts/echart.d.ts +0 -18
  178. package/dist/components/charts/echart.d.ts.map +0 -1
  179. package/dist/components/charts/echart.js +0 -17
  180. package/dist/components/charts/echart.js.map +0 -1
  181. package/dist/components/cms-picker/CmsBlockPicker.d.ts +0 -19
  182. package/dist/components/cms-picker/CmsBlockPicker.d.ts.map +0 -1
  183. package/dist/components/cms-picker/CmsBlockPicker.js +0 -18
  184. package/dist/components/cms-picker/CmsBlockPicker.js.map +0 -1
  185. package/dist/components/cms-picker/CmsPagePicker.d.ts +0 -19
  186. package/dist/components/cms-picker/CmsPagePicker.d.ts.map +0 -1
  187. package/dist/components/cms-picker/CmsPagePicker.js +0 -18
  188. package/dist/components/cms-picker/CmsPagePicker.js.map +0 -1
  189. package/dist/components/country-select/index.d.ts +0 -18
  190. package/dist/components/country-select/index.d.ts.map +0 -1
  191. package/dist/components/country-select/index.js +0 -17
  192. package/dist/components/country-select/index.js.map +0 -1
  193. package/dist/components/customer-group-picker/CustomerGroupPicker.d.ts +0 -18
  194. package/dist/components/customer-group-picker/CustomerGroupPicker.d.ts.map +0 -1
  195. package/dist/components/customer-group-picker/CustomerGroupPicker.js +0 -17
  196. package/dist/components/customer-group-picker/CustomerGroupPicker.js.map +0 -1
  197. package/dist/components/customer-picker/CustomerPicker.d.ts +0 -18
  198. package/dist/components/customer-picker/CustomerPicker.d.ts.map +0 -1
  199. package/dist/components/customer-picker/CustomerPicker.js +0 -17
  200. package/dist/components/customer-picker/CustomerPicker.js.map +0 -1
  201. package/dist/components/hooks/useFocusTrap.d.ts +0 -17
  202. package/dist/components/hooks/useFocusTrap.d.ts.map +0 -1
  203. package/dist/components/hooks/useFocusTrap.js +0 -17
  204. package/dist/components/hooks/useFocusTrap.js.map +0 -1
  205. package/dist/components/hooks/useViewportTier.d.ts +0 -18
  206. package/dist/components/hooks/useViewportTier.d.ts.map +0 -1
  207. package/dist/components/hooks/useViewportTier.js +0 -17
  208. package/dist/components/hooks/useViewportTier.js.map +0 -1
  209. package/dist/components/organization-picker/OrganizationPicker.d.ts +0 -19
  210. package/dist/components/organization-picker/OrganizationPicker.d.ts.map +0 -1
  211. package/dist/components/organization-picker/OrganizationPicker.js +0 -18
  212. package/dist/components/organization-picker/OrganizationPicker.js.map +0 -1
  213. package/dist/components/organization-picker/OrganizationPickerMulti.d.ts +0 -19
  214. package/dist/components/organization-picker/OrganizationPickerMulti.d.ts.map +0 -1
  215. package/dist/components/organization-picker/OrganizationPickerMulti.js +0 -18
  216. package/dist/components/organization-picker/OrganizationPickerMulti.js.map +0 -1
  217. package/dist/components/organization-picker/OrganizationStatusBadge.d.ts +0 -19
  218. package/dist/components/organization-picker/OrganizationStatusBadge.d.ts.map +0 -1
  219. package/dist/components/organization-picker/OrganizationStatusBadge.js +0 -18
  220. package/dist/components/organization-picker/OrganizationStatusBadge.js.map +0 -1
  221. package/dist/components/organization-picker/index.d.ts +0 -19
  222. package/dist/components/organization-picker/index.d.ts.map +0 -1
  223. package/dist/components/organization-picker/index.js +0 -18
  224. package/dist/components/organization-picker/index.js.map +0 -1
  225. package/dist/components/organization-picker/useOrganizationsQuery.d.ts +0 -19
  226. package/dist/components/organization-picker/useOrganizationsQuery.d.ts.map +0 -1
  227. package/dist/components/organization-picker/useOrganizationsQuery.js +0 -18
  228. package/dist/components/organization-picker/useOrganizationsQuery.js.map +0 -1
  229. package/dist/components/payment-method-availability/MethodAvailabilityCell.d.ts +0 -17
  230. package/dist/components/payment-method-availability/MethodAvailabilityCell.d.ts.map +0 -1
  231. package/dist/components/payment-method-availability/MethodAvailabilityCell.js +0 -17
  232. package/dist/components/payment-method-availability/MethodAvailabilityCell.js.map +0 -1
  233. package/dist/components/reorder/ReorderAnnouncer.d.ts +0 -18
  234. package/dist/components/reorder/ReorderAnnouncer.d.ts.map +0 -1
  235. package/dist/components/reorder/ReorderAnnouncer.js +0 -17
  236. package/dist/components/reorder/ReorderAnnouncer.js.map +0 -1
  237. package/dist/components/reorder/useReorderList.d.ts +0 -18
  238. package/dist/components/reorder/useReorderList.d.ts.map +0 -1
  239. package/dist/components/reorder/useReorderList.js +0 -17
  240. package/dist/components/reorder/useReorderList.js.map +0 -1
  241. package/dist/components/rule-builder/RuleBuilder.d.ts +0 -18
  242. package/dist/components/rule-builder/RuleBuilder.d.ts.map +0 -1
  243. package/dist/components/rule-builder/RuleBuilder.js +0 -17
  244. package/dist/components/rule-builder/RuleBuilder.js.map +0 -1
  245. package/dist/components/sales-channel-picker/SalesChannelPicker.d.ts +0 -19
  246. package/dist/components/sales-channel-picker/SalesChannelPicker.d.ts.map +0 -1
  247. package/dist/components/sales-channel-picker/SalesChannelPicker.js +0 -18
  248. package/dist/components/sales-channel-picker/SalesChannelPicker.js.map +0 -1
  249. package/dist/components/scope-notice/ScopeNotice.d.ts +0 -18
  250. package/dist/components/scope-notice/ScopeNotice.d.ts.map +0 -1
  251. package/dist/components/scope-notice/ScopeNotice.js +0 -17
  252. package/dist/components/scope-notice/ScopeNotice.js.map +0 -1
  253. package/dist/components/ui/alert.d.ts +0 -18
  254. package/dist/components/ui/alert.d.ts.map +0 -1
  255. package/dist/components/ui/alert.js +0 -17
  256. package/dist/components/ui/alert.js.map +0 -1
  257. package/dist/components/ui/badge.d.ts +0 -18
  258. package/dist/components/ui/badge.d.ts.map +0 -1
  259. package/dist/components/ui/badge.js +0 -17
  260. package/dist/components/ui/badge.js.map +0 -1
  261. package/dist/components/ui/button.d.ts +0 -18
  262. package/dist/components/ui/button.d.ts.map +0 -1
  263. package/dist/components/ui/button.js +0 -17
  264. package/dist/components/ui/button.js.map +0 -1
  265. package/dist/components/ui/card.d.ts +0 -17
  266. package/dist/components/ui/card.d.ts.map +0 -1
  267. package/dist/components/ui/card.js +0 -17
  268. package/dist/components/ui/card.js.map +0 -1
  269. package/dist/components/ui/checkbox.d.ts +0 -17
  270. package/dist/components/ui/checkbox.d.ts.map +0 -1
  271. package/dist/components/ui/checkbox.js +0 -17
  272. package/dist/components/ui/checkbox.js.map +0 -1
  273. package/dist/components/ui/color-picker.d.ts +0 -17
  274. package/dist/components/ui/color-picker.d.ts.map +0 -1
  275. package/dist/components/ui/color-picker.js +0 -17
  276. package/dist/components/ui/color-picker.js.map +0 -1
  277. package/dist/components/ui/combobox.d.ts +0 -18
  278. package/dist/components/ui/combobox.d.ts.map +0 -1
  279. package/dist/components/ui/combobox.js +0 -17
  280. package/dist/components/ui/combobox.js.map +0 -1
  281. package/dist/components/ui/input.d.ts +0 -17
  282. package/dist/components/ui/input.d.ts.map +0 -1
  283. package/dist/components/ui/input.js +0 -17
  284. package/dist/components/ui/input.js.map +0 -1
  285. package/dist/components/ui/label.d.ts +0 -17
  286. package/dist/components/ui/label.d.ts.map +0 -1
  287. package/dist/components/ui/label.js +0 -17
  288. package/dist/components/ui/label.js.map +0 -1
  289. package/dist/components/ui/multi-select.d.ts +0 -18
  290. package/dist/components/ui/multi-select.d.ts.map +0 -1
  291. package/dist/components/ui/multi-select.js +0 -17
  292. package/dist/components/ui/multi-select.js.map +0 -1
  293. package/dist/components/ui/page-header.d.ts +0 -18
  294. package/dist/components/ui/page-header.d.ts.map +0 -1
  295. package/dist/components/ui/page-header.js +0 -17
  296. package/dist/components/ui/page-header.js.map +0 -1
  297. package/dist/components/ui/route-tabs.d.ts +0 -18
  298. package/dist/components/ui/route-tabs.d.ts.map +0 -1
  299. package/dist/components/ui/route-tabs.js +0 -17
  300. package/dist/components/ui/route-tabs.js.map +0 -1
  301. package/dist/components/ui/save-button-group.d.ts +0 -18
  302. package/dist/components/ui/save-button-group.d.ts.map +0 -1
  303. package/dist/components/ui/save-button-group.js +0 -17
  304. package/dist/components/ui/save-button-group.js.map +0 -1
  305. package/dist/components/ui/select.d.ts +0 -17
  306. package/dist/components/ui/select.d.ts.map +0 -1
  307. package/dist/components/ui/select.js +0 -17
  308. package/dist/components/ui/select.js.map +0 -1
  309. package/dist/components/ui/separator.d.ts +0 -17
  310. package/dist/components/ui/separator.d.ts.map +0 -1
  311. package/dist/components/ui/separator.js +0 -17
  312. package/dist/components/ui/separator.js.map +0 -1
  313. package/dist/components/ui/table.d.ts +0 -17
  314. package/dist/components/ui/table.d.ts.map +0 -1
  315. package/dist/components/ui/table.js +0 -17
  316. package/dist/components/ui/table.js.map +0 -1
  317. package/dist/components/ui/textarea.d.ts +0 -17
  318. package/dist/components/ui/textarea.d.ts.map +0 -1
  319. package/dist/components/ui/textarea.js +0 -17
  320. package/dist/components/ui/textarea.js.map +0 -1
  321. package/dist/i18n/TranslationProvider.d.ts +0 -18
  322. package/dist/i18n/TranslationProvider.d.ts.map +0 -1
  323. package/dist/i18n/TranslationProvider.js +0 -17
  324. package/dist/i18n/TranslationProvider.js.map +0 -1
  325. package/dist/i18n/app-language-context.d.ts +0 -18
  326. package/dist/i18n/app-language-context.d.ts.map +0 -1
  327. package/dist/i18n/app-language-context.js +0 -17
  328. package/dist/i18n/app-language-context.js.map +0 -1
  329. package/dist/i18n/interpolate.d.ts +0 -17
  330. package/dist/i18n/interpolate.d.ts.map +0 -1
  331. package/dist/i18n/interpolate.js +0 -17
  332. package/dist/i18n/interpolate.js.map +0 -1
  333. package/dist/i18n/language-storage.d.ts +0 -17
  334. package/dist/i18n/language-storage.d.ts.map +0 -1
  335. package/dist/i18n/language-storage.js +0 -17
  336. package/dist/i18n/language-storage.js.map +0 -1
  337. package/dist/i18n/resolver.d.ts +0 -18
  338. package/dist/i18n/resolver.d.ts.map +0 -1
  339. package/dist/i18n/resolver.js +0 -17
  340. package/dist/i18n/resolver.js.map +0 -1
  341. package/dist/i18n/types.d.ts +0 -17
  342. package/dist/i18n/types.d.ts.map +0 -1
  343. package/dist/i18n/types.js +0 -2
  344. package/dist/i18n/types.js.map +0 -1
  345. package/dist/i18n/useTranslation.d.ts +0 -17
  346. package/dist/i18n/useTranslation.d.ts.map +0 -1
  347. package/dist/i18n/useTranslation.js +0 -17
  348. package/dist/i18n/useTranslation.js.map +0 -1
  349. package/dist/lib/admin-actions/icon-map.d.ts +0 -17
  350. package/dist/lib/admin-actions/icon-map.d.ts.map +0 -1
  351. package/dist/lib/admin-actions/icon-map.js +0 -17
  352. package/dist/lib/admin-actions/icon-map.js.map +0 -1
  353. package/dist/lib/api-client.d.ts +0 -17
  354. package/dist/lib/api-client.d.ts.map +0 -1
  355. package/dist/lib/api-client.js +0 -17
  356. package/dist/lib/api-client.js.map +0 -1
  357. package/dist/lib/auth.d.ts +0 -18
  358. package/dist/lib/auth.d.ts.map +0 -1
  359. package/dist/lib/auth.js +0 -17
  360. package/dist/lib/auth.js.map +0 -1
  361. package/dist/lib/format.d.ts +0 -17
  362. package/dist/lib/format.d.ts.map +0 -1
  363. package/dist/lib/format.js +0 -17
  364. package/dist/lib/format.js.map +0 -1
  365. package/dist/lib/module-presence/index.d.ts +0 -19
  366. package/dist/lib/module-presence/index.d.ts.map +0 -1
  367. package/dist/lib/module-presence/index.js +0 -18
  368. package/dist/lib/module-presence/index.js.map +0 -1
  369. package/dist/lib/money.d.ts +0 -17
  370. package/dist/lib/money.d.ts.map +0 -1
  371. package/dist/lib/money.js +0 -17
  372. package/dist/lib/money.js.map +0 -1
  373. package/dist/lib/surface-visibility.d.ts +0 -15
  374. package/dist/lib/surface-visibility.d.ts.map +0 -1
  375. package/dist/lib/surface-visibility.js +0 -14
  376. package/dist/lib/surface-visibility.js.map +0 -1
  377. package/dist/lib/text-normalization.d.ts +0 -17
  378. package/dist/lib/text-normalization.d.ts.map +0 -1
  379. package/dist/lib/text-normalization.js +0 -17
  380. package/dist/lib/text-normalization.js.map +0 -1
  381. package/dist/lib/use-page-size-preference.d.ts +0 -16
  382. package/dist/lib/use-page-size-preference.d.ts.map +0 -1
  383. package/dist/lib/use-page-size-preference.js +0 -15
  384. package/dist/lib/use-page-size-preference.js.map +0 -1
  385. package/dist/lib/use-unsaved-changes-prompt.d.ts +0 -17
  386. package/dist/lib/use-unsaved-changes-prompt.d.ts.map +0 -1
  387. package/dist/lib/use-unsaved-changes-prompt.js +0 -17
  388. package/dist/lib/use-unsaved-changes-prompt.js.map +0 -1
  389. package/dist/lib/utils.d.ts +0 -17
  390. package/dist/lib/utils.d.ts.map +0 -1
  391. package/dist/lib/utils.js +0 -17
  392. package/dist/lib/utils.js.map +0 -1
  393. package/dist/lib/uuid.d.ts +0 -17
  394. package/dist/lib/uuid.d.ts.map +0 -1
  395. package/dist/lib/uuid.js +0 -17
  396. package/dist/lib/uuid.js.map +0 -1
@@ -1,30 +1,30 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import { useFocusTrap } from './hooks/useFocusTrap.js';
2
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
3
+ import { useFocusTrap, useViewportTier } from '@endora-commerce/admin-kit/components';
4
4
  import { BrandLogo } from './BrandLogo.js';
5
5
  import { VersionBadge } from './VersionBadge.js';
6
+ import { AdminFeedback } from './AdminFeedback.js';
6
7
  import { NavLink, Outlet, useLocation, useNavigate } from 'react-router-dom';
7
- import { BookOpen, Boxes, ChevronDown, ChevronRight, HelpCircle, Home as HomeIcon, Menu, LayoutDashboard, LogOut, PanelLeftClose, PanelLeftOpen, Search, Sparkles, } from 'lucide-react';
8
- import { useAuth } from '../lib/auth.js';
9
- import { cn } from '../lib/utils.js';
10
- import { useTranslation } from '../i18n/useTranslation.js';
11
- import { useTranslationContext } from '../i18n/TranslationProvider.js';
8
+ import { BookOpen, Boxes, ChevronDown, ChevronRight, HelpCircle, Home as HomeIcon, Menu, LayoutDashboard, LogOut, PanelLeftClose, PanelLeftOpen, Pin, PinOff, Search, Sparkles, } from 'lucide-react';
9
+ import { useAuth, cn, useModulePresence, useSurfaceVisibility, resolveIcon, useAdminPreference, } from '@endora-commerce/admin-kit/lib';
10
+ import { useTranslation, useTranslationContext } from '@endora-commerce/admin-kit/i18n';
12
11
  import { registryNavFor, useAdminRegistry, } from '../lib/module-registry/index.js';
13
12
  import { LanguagePicker } from './LanguagePicker.js';
14
13
  import { RoleRequiredNotice } from './RoleRequiredNotice.js';
15
- import { useViewportTier } from './hooks/useViewportTier.js';
16
14
  import { NotificationBell } from './notifications/index.js';
17
15
  import { useAdminActions } from '../lib/admin-actions/useAdminActions.js';
18
- import { normalize } from '../lib/text-normalization.js';
19
- import { useModulePresence } from '../lib/module-presence/index.js';
16
+ import { matchesSearchTerms, searchTerms } from '../lib/palette-match.js';
20
17
  import { usePlatformVersion } from '../lib/platform-info/usePlatformVersion.js';
21
- import { useSurfaceVisibility, } from '../lib/surface-visibility.js';
22
- import { resolveIcon } from '../lib/admin-actions/icon-map.js';
23
18
  import { getPromptCapability, listUnseenPromptRequests } from '../lib/prompt-actions/api.js';
24
19
  import { PromptModePanel } from './prompt-actions/PromptModePanel.js';
25
20
  import { useGlobalSearch } from '../lib/global-search/useGlobalSearch.js';
26
- import { Badge } from './ui/badge.js';
21
+ import { Badge } from '@endora-commerce/admin-kit/ui';
27
22
  import { SpeechToTextButton } from './SpeechToTextButton.js';
23
+ import { PinnedSection } from './sidebar/PinnedSection.js';
24
+ import { PinToggleButton } from './sidebar/PinToggleButton.js';
25
+ import { PreferencesSaveNotice } from './sidebar/PreferencesSaveNotice.js';
26
+ import { usePinActions } from './sidebar/use-pin-actions.js';
27
+ import { reorderVisiblePins, resolvePinsFrom, visibleDestinations, } from '../lib/pinned-entries.js';
28
28
  /* Design-aligned navigation. The "Home" + "Orders" cluster sits above
29
29
  * the first labelled group exactly as the prototype shows. */
30
30
  const NAV = [
@@ -73,6 +73,16 @@ const NAV = [
73
73
  labelKey: 'appShell.section.crm',
74
74
  items: [],
75
75
  },
76
+ {
77
+ // The "Projects & tasks" group (`specs/163-projects-and-tasks/` research
78
+ // R-16). It holds no host-declared row: every entry is the `projects` or
79
+ // the `tasks` module's contribution, each gated by its own module's
80
+ // permission, so the heading shows only Tasks entries while `projects` is
81
+ // off and disappears when both modules are.
82
+ key: 'work',
83
+ labelKey: 'appShell.section.work',
84
+ items: [],
85
+ },
76
86
  {
77
87
  key: 'catalog',
78
88
  labelKey: 'appShell.section.catalog',
@@ -318,61 +328,6 @@ const NAV = [
318
328
  ],
319
329
  },
320
330
  ];
321
- const STORAGE_KEY = 'b2b-admin.nav.collapsed-groups';
322
- const RAIL_STORAGE_KEY = 'b2b-admin.nav.rail-mode';
323
- /**
324
- * Rail (icon-only) mode persistence. The whole sidebar shrinks to a
325
- * 64px-wide column showing just icons; section labels disappear and
326
- * each section becomes a single icon (the first item's icon). Hovering
327
- * or clicking the icon reveals a popover with the section's items.
328
- */
329
- function loadRailMode() {
330
- if (typeof window === 'undefined')
331
- return false;
332
- try {
333
- return window.localStorage.getItem(RAIL_STORAGE_KEY) === '1';
334
- }
335
- catch {
336
- return false;
337
- }
338
- }
339
- function persistRailMode(value) {
340
- if (typeof window === 'undefined')
341
- return;
342
- try {
343
- window.localStorage.setItem(RAIL_STORAGE_KEY, value ? '1' : '0');
344
- }
345
- catch {
346
- /* ignore */
347
- }
348
- }
349
- function loadCollapsed() {
350
- if (typeof window === 'undefined')
351
- return new Set();
352
- try {
353
- const raw = window.localStorage.getItem(STORAGE_KEY);
354
- if (!raw)
355
- return new Set();
356
- const parsed = JSON.parse(raw);
357
- if (Array.isArray(parsed)) {
358
- return new Set(parsed.filter((v) => typeof v === 'string'));
359
- }
360
- }
361
- catch {
362
- /* ignore */
363
- }
364
- return new Set();
365
- }
366
- function persistCollapsed(value) {
367
- if (typeof window === 'undefined')
368
- return;
369
- try {
370
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(Array.from(value)));
371
- }
372
- catch {
373
- /* ignore */
374
- }
375
- }
376
331
  const CRUMB_DICT = [
377
332
  { test: /^\/$/, build: () => [{ labelKey: 'appShell.nav.home', href: null }] },
378
333
  // Six hand-written `/catalog*` trails stood here until feature 091's Phase 4
@@ -672,13 +627,19 @@ function buildCrumbs(pathname, composedNav) {
672
627
  * does type `zamówienia`; folding only the query breaks the one who does not.
673
628
  * (Postel's Law — accept what was typed and normalise it.)
674
629
  *
675
- * `needle` must already be normalised; the caller folds the query once per
676
- * keystroke rather than once per row. `normalize` trims, so a query with a
630
+ * **Per word, across the row** — every word of the query must occur in some
631
+ * field, not the whole query in one. The rule itself is `lib/palette-match.ts`,
632
+ * shared with the Actions group for the same reason as the fold: a multi-word
633
+ * query such as `kanał sprzedaży` used to need one field carrying those words
634
+ * contiguously, so it missed `Kanały sprzedaży`.
635
+ *
636
+ * `terms` must already be folded by `searchTerms`; the caller does that once
637
+ * per keystroke rather than once per row. `normalize` trims, so a query with a
677
638
  * leading space matches what the operator meant rather than nothing at all
678
639
  * (issue #236).
679
640
  */
680
- function matchesQuery(needle, ...haystacks) {
681
- return haystacks.some((haystack) => normalize(haystack).includes(needle));
641
+ function matchesQuery(terms, ...haystacks) {
642
+ return matchesSearchTerms(terms, haystacks);
682
643
  }
683
644
  /**
684
645
  * The static Navigate group.
@@ -878,8 +839,12 @@ function useNavLabel() {
878
839
  const { t } = useTranslationContext();
879
840
  return useCallback((item) => t(item.labelScope ?? 'core', item.labelKey), [t]);
880
841
  }
842
+ /** The sentence the pin and unpin live regions say, in the admin's language (FR-005). */
843
+ function pinAnnouncementText(t, outcome, label) {
844
+ return t(outcome === 'pinned' ? 'appShell.pinned.announce.pinned' : 'appShell.pinned.announce.unpinned', { label });
845
+ }
881
846
  export function AppShell() {
882
- const { me, logout, hasPermission } = useAuth();
847
+ const { me, logout } = useAuth();
883
848
  // The host's nav with every installed module's contributed entry folded in.
884
849
  const composedNav = useComposedNav();
885
850
  // Feature 073 — the effective enabled-set. A module that is off contributes
@@ -889,22 +854,26 @@ export function AppShell() {
889
854
  const isVisible = useSurfaceVisibility();
890
855
  const navigate = useNavigate();
891
856
  const location = useLocation();
892
- const [collapsed, setCollapsed] = useState(() => loadCollapsed());
893
- const [railMode, setRailMode] = useState(() => loadRailMode());
857
+ // Feature 164 — folded groups and rail mode are the admin's, kept on the
858
+ // server and present in the first render (FR-013, FR-016). A stored group key
859
+ // this release does not render folds nothing and is kept in the next write
860
+ // (FR-015).
861
+ const [collapsedGroups, setCollapsedGroups] = useAdminPreference('sidebarCollapsedGroups');
862
+ const collapsed = useMemo(() => new Set(collapsedGroups), [collapsedGroups]);
863
+ const [storedRailMode, setStoredRailMode] = useAdminPreference('sidebarRailMode');
894
864
  const platformVersion = usePlatformVersion();
865
+ const feedbackOffered = isModulePresent('admin_feedback');
895
866
  const [paletteOpen, setPaletteOpen] = useState(false);
896
867
  const [navDrawerOpen, setNavDrawerOpen] = useState(false);
897
868
  const sidebarRef = useRef(null);
898
869
  const viewportTier = useViewportTier();
899
870
  const isMobile = viewportTier === 'mobile';
900
871
  useFocusTrap(sidebarRef, isMobile && navDrawerOpen);
872
+ // Rail mode has no effect on the mobile tier, whatever is stored (FR-013).
873
+ const railMode = storedRailMode && !isMobile;
901
874
  const toggleRailMode = useCallback(() => {
902
- setRailMode((prev) => {
903
- const next = !prev;
904
- persistRailMode(next);
905
- return next;
906
- });
907
- }, []);
875
+ setStoredRailMode(!storedRailMode);
876
+ }, [storedRailMode, setStoredRailMode]);
908
877
  const t = useTranslation('core');
909
878
  // The brand link's tooltip. With a release known it is the full sentence in
910
879
  // either mode: collapsed, the badge has no room and this is the only place
@@ -923,19 +892,27 @@ export function AppShell() {
923
892
  // The raw, scope-taking resolver, for the breadcrumb: a crumb a module
924
893
  // contributed resolves its label in that module's own namespace.
925
894
  const { t: tScoped } = useTranslationContext();
895
+ // Feature 164 — the sidebar's visible destinations, built once with the same
896
+ // predicate the sections render with and read by both the Pinned section and
897
+ // the palette's pin control (research R-7, R-15): a pin is the original
898
+ // entry's own object, so it cannot show a surface its original would not.
899
+ const pinTargets = useMemo(() => visibleDestinations(composedNav, isVisible), [composedNav, isVisible]);
900
+ const { pins, isPinned, toggle: togglePin, setPins } = usePinActions();
901
+ const resolvedPins = useMemo(() => resolvePinsFrom(pins, pinTargets), [pins, pinTargets]);
902
+ // One polite region for every pin and unpin in the sidebar (FR-005), mounted
903
+ // empty and outside the sidebar, which the closed drawer hides from AT.
904
+ const [pinAnnouncement, setPinAnnouncement] = useState('');
905
+ const togglePinOf = useCallback((item) => {
906
+ const outcome = togglePin(item.to);
907
+ setPinAnnouncement(pinAnnouncementText(t, outcome, navLabel(item)));
908
+ }, [togglePin, t, navLabel]);
926
909
  const fullName = me ? `${me.adminUser.firstName} ${me.adminUser.lastName}`.trim() : '';
927
910
  const role = me?.role?.name ?? 'Admin';
928
911
  const toggleSection = useCallback((key) => {
929
- setCollapsed((prev) => {
930
- const next = new Set(prev);
931
- if (next.has(key))
932
- next.delete(key);
933
- else
934
- next.add(key);
935
- persistCollapsed(next);
936
- return next;
937
- });
938
- }, []);
912
+ setCollapsedGroups(collapsedGroups.includes(key)
913
+ ? collapsedGroups.filter((group) => group !== key)
914
+ : [...collapsedGroups, key]);
915
+ }, [collapsedGroups, setCollapsedGroups]);
939
916
  // ⌘K opens the palette anywhere in the admin; ⌘B toggles the
940
917
  // sidebar rail (matches the shadcn / VS Code shortcut convention).
941
918
  useEffect(() => {
@@ -964,59 +941,70 @@ export function AppShell() {
964
941
  }, [location.pathname]);
965
942
  const crumbs = useMemo(() => buildCrumbs(location.pathname, composedNav), [location.pathname, composedNav]);
966
943
  const isCmsRoute = location.pathname.startsWith('/cms');
967
- return (_jsxs("div", { className: cn('b2b-app-layout', isMobile ? null : railMode ? 'b2b-app-layout--rail' : 'b2b-app-layout--expanded'), children: [isMobile && navDrawerOpen ? (_jsx("button", { type: "button", className: "b2b-nav-drawer-backdrop", "aria-label": t('appShell.mobileMenu.close'), onClick: () => setNavDrawerOpen(false) })) : null, _jsxs("aside", { ref: sidebarRef, className: cn('b2b-sidebar', railMode && !isMobile && 'b2b-sidebar--rail', isMobile && navDrawerOpen && 'b2b-sidebar--drawer-open'), "aria-hidden": isMobile && !navDrawerOpen ? true : undefined, role: "navigation", "aria-label": t('appShell.mobileMenu.title'), children: [_jsxs(NavLink, { to: "/", end: true, className: "b2b-sidebar__brand", style: { textDecoration: 'none', color: 'inherit', cursor: 'pointer' }, "aria-label": t('appShell.brand.dashboardLink'), title: brandTooltip, children: [_jsx("span", { className: "b2b-sidebar__brand-logo", children: _jsx(BrandLogo, { label: t('appShell.brand.text') }) }), _jsxs("span", { className: "b2b-sidebar__brand-text", children: [t('appShell.brand.textPrimary'), ' ', _jsx("span", { className: "b2b-sidebar__brand-text-accent", children: t('appShell.brand.textAccent') })] })] }), platformVersion !== null ? (_jsx("div", { className: "b2b-sidebar__version", children: _jsx(VersionBadge, { version: platformVersion }) })) : null, _jsx("div", { className: "b2b-sidebar__search", children: railMode ? (_jsx("button", { type: "button", className: "b2b-sidebar__search-rail", onClick: () => setPaletteOpen(true), title: t('appShell.search.openPalette'), "aria-label": t('appShell.search.openPalette'), children: _jsx(Search, { size: 16 }) })) : (_jsxs(_Fragment, { children: [_jsx(Search, { size: 14, className: "b2b-sidebar__search-icon" }), _jsx("input", { className: "b2b-sidebar__search-input", placeholder: t('appShell.search.placeholder'), readOnly: true, onClick: () => setPaletteOpen(true), onFocus: () => setPaletteOpen(true) }), _jsx("span", { className: "b2b-sidebar__search-kbd", children: t('appShell.search.shortcutSymbol') })] })) }), _jsx("nav", { className: "b2b-sidebar__nav", children: composedNav.map((section) => {
968
- const isOpen = !collapsed.has(section.key);
969
- // Permission-gate every entry, then presence-gate it (feature 073 /
970
- // FR-031). Sections with no remaining visible items fold away
971
- // entirely, which is what makes a whole domain disappear when every
972
- // module in it is off — the same behaviour restricted admins have
973
- // always had.
974
- //
975
- // Issue #230 — the predicate is `isSurfaceVisible`, shared with the
976
- // command palette and the dashboard quick actions. The palette used
977
- // to run a second, weaker copy of it; a shared helper is what stops
978
- // the three from disagreeing again.
979
- const visibleItems = section.items.filter(isVisible);
980
- if (visibleItems.length === 0)
981
- return null;
982
- // Feature 019 / 021 — section labels go through useTranslation('core').
983
- // The empty-labelKey "main" cluster keeps no label; every other
984
- // group resolves its declared `labelKey`. Polish strings live
985
- // in packages/modules/_i18n/i18n/pl.json under the same key.
986
- const translatedLabel = section.labelKey ? t(section.labelKey) : '';
987
- // In rail mode the section reduces to one icon (the first
988
- // visible item's icon). Hover or click reveals a popover
989
- // listing every visible item in the section.
990
- if (railMode) {
991
- return (_jsx(RailSection, { section: section, visibleItems: visibleItems, translatedLabel: translatedLabel }, section.key));
992
- }
993
- return (_jsxs("div", { className: cn('b2b-sidebar__group', !isOpen && section.labelKey && 'b2b-sidebar__group--collapsed'), children: [section.labelKey ? (_jsxs("button", { type: "button", className: "b2b-sidebar__group-label", onClick: () => toggleSection(section.key), children: [_jsx(ChevronDown, { size: 11 }), _jsx("span", { children: translatedLabel })] })) : null, _jsx("div", { className: "b2b-sidebar__items", children: visibleItems.map((item) => {
994
- const Icon = item.icon;
995
- // Force exact-match (`end`) when another item in the same
996
- // section nests under this item's path. Without this, a
997
- // parent route like `/inventory` lights up alongside its
998
- // children (`/inventory/low-stock`, `/inventory/import`,
999
- // …) because NavLink's default match is prefix-based.
1000
- // The home link (`/`) is the canonical example and is
1001
- // covered by the same rule (every other item starts with
1002
- // `/`).
1003
- const hasNestedSibling = section.items.some((other) => other !== item &&
1004
- other.to.startsWith(item.to === '/' ? '/' : `${item.to}/`));
1005
- return (_jsxs(NavLink, { to: item.to, end: item.to === '/' || hasNestedSibling, className: ({ isActive }) => cn('b2b-nav-item', isActive && 'is-active'), children: [_jsx(Icon, { size: 16 }), _jsx("span", { style: { flex: 1 }, children: navLabel(item) })] }, item.to));
1006
- }) })] }, section.key));
1007
- }) }), me ? (_jsxs("div", { className: "b2b-sidebar__foot", children: [_jsxs(NavLink, { to: "/profile", className: "b2b-sidebar__foot-identity", title: railMode
944
+ return (_jsxs("div", { className: cn('b2b-app-layout', isMobile ? null : railMode ? 'b2b-app-layout--rail' : 'b2b-app-layout--expanded'), children: [isMobile && navDrawerOpen ? (_jsx("button", { type: "button", className: "b2b-nav-drawer-backdrop", "aria-label": t('appShell.mobileMenu.close'), onClick: () => setNavDrawerOpen(false) })) : null, _jsxs("aside", { ref: sidebarRef, className: cn('b2b-sidebar', railMode && 'b2b-sidebar--rail', isMobile && navDrawerOpen && 'b2b-sidebar--drawer-open'), "aria-hidden": isMobile && !navDrawerOpen ? true : undefined, role: "navigation", "aria-label": t('appShell.mobileMenu.title'), children: [_jsxs(NavLink, { to: "/", end: true, className: "b2b-sidebar__brand", style: { textDecoration: 'none', color: 'inherit', cursor: 'pointer' }, "aria-label": t('appShell.brand.dashboardLink'), title: brandTooltip, children: [_jsx("span", { className: "b2b-sidebar__brand-logo", children: _jsx(BrandLogo, { label: t('appShell.brand.text') }) }), _jsxs("span", { className: "b2b-sidebar__brand-text", children: [t('appShell.brand.textPrimary'), ' ', _jsx("span", { className: "b2b-sidebar__brand-text-accent", children: t('appShell.brand.textAccent') })] })] }), platformVersion !== null || feedbackOffered ? (_jsxs("div", { className: "b2b-sidebar__version", children: [platformVersion !== null ? _jsx(VersionBadge, { version: platformVersion }) : null, feedbackOffered && !railMode ? _jsx(AdminFeedback, { rail: false }) : null] })) : null, feedbackOffered && railMode ? (_jsx("div", { className: "b2b-sidebar__feedback-rail-row", children: _jsx(AdminFeedback, { rail: true }) })) : null, _jsx("div", { className: "b2b-sidebar__search", children: railMode ? (_jsx("button", { type: "button", className: "b2b-sidebar__search-rail", onClick: () => setPaletteOpen(true), title: t('appShell.search.openPalette'), "aria-label": t('appShell.search.openPalette'), children: _jsx(Search, { size: 16 }) })) : (_jsxs(_Fragment, { children: [_jsx(Search, { size: 14, className: "b2b-sidebar__search-icon" }), _jsx("input", { className: "b2b-sidebar__search-input", placeholder: t('appShell.search.placeholder'), readOnly: true, onClick: () => setPaletteOpen(true), onFocus: () => setPaletteOpen(true) }), _jsx("span", { className: "b2b-sidebar__search-kbd", children: t('appShell.search.shortcutSymbol') })] })) }), _jsxs("nav", { className: "b2b-sidebar__nav", children: [railMode ? (resolvedPins.length > 0 ? (_jsx(RailSection, { section: {
945
+ key: 'pinned',
946
+ labelKey: 'appShell.pinned.heading',
947
+ items: resolvedPins.map((pin) => pin.item),
948
+ }, visibleItems: resolvedPins.map((pin) => pin.item), translatedLabel: t('appShell.pinned.heading'), pinned: {
949
+ icon: Pin,
950
+ endOf: (item) => resolvedPins.find((pin) => pin.item === item)?.end ?? false,
951
+ onUnpin: togglePinOf,
952
+ } }, "pinned")) : null) : (_jsx(PinnedSection, { pins: resolvedPins, sections: composedNav, collapsed: collapsed.has('pinned'), onToggleCollapsed: toggleSection, onUnpin: (pin) => togglePinOf(pin.item), onReorder: (visibleOrder) => setPins(reorderVisiblePins(pins, visibleOrder)), navLabel: navLabel, touch: isMobile })), composedNav.map((section) => {
953
+ const isOpen = !collapsed.has(section.key);
954
+ // Permission-gate every entry, then presence-gate it (feature 073 /
955
+ // FR-031). Sections with no remaining visible items fold away
956
+ // entirely, which is what makes a whole domain disappear when every
957
+ // module in it is off — the same behaviour restricted admins have
958
+ // always had.
959
+ //
960
+ // Issue #230 — the predicate is `isSurfaceVisible`, shared with the
961
+ // command palette and the dashboard quick actions. The palette used
962
+ // to run a second, weaker copy of it; a shared helper is what stops
963
+ // the three from disagreeing again.
964
+ const visibleItems = section.items.filter(isVisible);
965
+ if (visibleItems.length === 0)
966
+ return null;
967
+ // Feature 019 / 021 — section labels go through useTranslation('core').
968
+ // The empty-labelKey "main" cluster keeps no label; every other
969
+ // group resolves its declared `labelKey`. Polish strings live
970
+ // in packages/modules/_i18n/i18n/pl.json under the same key.
971
+ const translatedLabel = section.labelKey ? t(section.labelKey) : '';
972
+ // In rail mode the section reduces to one icon (the first
973
+ // visible item's icon). Hover or click reveals a popover
974
+ // listing every visible item in the section.
975
+ if (railMode) {
976
+ return (_jsx(RailSection, { section: section, visibleItems: visibleItems, translatedLabel: translatedLabel }, section.key));
977
+ }
978
+ return (_jsxs("div", { className: cn('b2b-sidebar__group', !isOpen && section.labelKey && 'b2b-sidebar__group--collapsed'), children: [section.labelKey ? (_jsxs("button", { type: "button", className: "b2b-sidebar__group-label", onClick: () => toggleSection(section.key), children: [_jsx(ChevronDown, { size: 11 }), _jsx("span", { children: translatedLabel })] })) : null, _jsx("div", { className: "b2b-sidebar__items", children: visibleItems.map((item) => {
979
+ const Icon = item.icon;
980
+ // Force exact-match (`end`) when another item in the same
981
+ // section nests under this item's path. Without this, a
982
+ // parent route like `/inventory` lights up alongside its
983
+ // children (`/inventory/low-stock`, `/inventory/import`,
984
+ // …) because NavLink's default match is prefix-based.
985
+ // The home link (`/`) is the canonical example and is
986
+ // covered by the same rule (every other item starts with
987
+ // `/`).
988
+ const hasNestedSibling = section.items.some((other) => other !== item &&
989
+ other.to.startsWith(item.to === '/' ? '/' : `${item.to}/`));
990
+ const label = navLabel(item);
991
+ // Feature 164 — the pin control is the row's second Tab
992
+ // stop, after the link and never inside it (FR-004).
993
+ return (_jsxs("div", { className: "b2b-nav-row", children: [_jsxs(NavLink, { to: item.to, end: item.to === '/' || hasNestedSibling, className: ({ isActive }) => cn('b2b-nav-item', isActive && 'is-active'), children: [_jsx(Icon, { size: 16 }), _jsx("span", { style: { flex: 1 }, children: label })] }), _jsx(PinToggleButton, { label: label, pinned: isPinned(item.to), touch: isMobile, onToggle: () => togglePinOf(item) })] }, item.to));
994
+ }) })] }, section.key));
995
+ })] }), me ? (_jsxs("div", { className: "b2b-sidebar__foot", children: [_jsxs(NavLink, { to: "/profile", className: "b2b-sidebar__foot-identity", title: railMode
1008
996
  ? `${fullName || me.adminUser.email} — ${t('appShell.profileMenu.profile')}`
1009
997
  : t('appShell.profileMenu.profile'), "aria-label": t('appShell.profileMenu.profile'), children: [_jsx("div", { className: "b2b-avatar", children: (fullName || me.adminUser.email).slice(0, 2).toUpperCase() }), _jsxs("div", { className: "meta", children: [_jsx("div", { className: "name", children: fullName || me.adminUser.email }), _jsx("div", { className: "role", children: role })] })] }), _jsx("button", { type: "button", className: "icon-btn", title: t('appShell.profileMenu.signOut'), "aria-label": t('appShell.profileMenu.signOut'), onClick: () => void logout(), children: _jsx(LogOut, { size: 14 }) })] })) : null, !isMobile ? (_jsxs("button", { type: "button", className: "b2b-sidebar__rail-toggle", onClick: toggleRailMode, title: railMode
1010
998
  ? (t('appShell.sidebarToggle.expand') || 'Expand sidebar (⌘B)')
1011
999
  : (t('appShell.sidebarToggle.collapse') || 'Collapse sidebar (⌘B)'), "aria-label": railMode
1012
1000
  ? (t('appShell.sidebarToggle.expand') || 'Expand sidebar')
1013
- : (t('appShell.sidebarToggle.collapse') || 'Collapse sidebar'), "aria-pressed": railMode, children: [railMode ? _jsx(PanelLeftOpen, { size: 14 }) : _jsx(PanelLeftClose, { size: 14 }), !railMode ? (_jsx("span", { className: "b2b-sidebar__rail-toggle-label", children: t('appShell.sidebarToggle.collapse') || 'Collapse' })) : null] })) : null] }), _jsxs("div", { style: { minWidth: 0, display: 'flex', flexDirection: 'column' }, children: [_jsxs("div", { className: "b2b-topbar", children: [isMobile ? (_jsx("button", { type: "button", className: "b2b-topbar__menu-btn", "aria-label": t('appShell.mobileMenu.open'), "aria-expanded": navDrawerOpen, onClick: () => setNavDrawerOpen((open) => !open), children: _jsx(Menu, { size: 20 }) })) : null, _jsx("div", { className: isCmsRoute ? 'b2b-topbar__crumbs-inner b2b-page b2b-page--wide' : 'b2b-topbar__crumbs', children: crumbs.map((c, i) => (_jsxs("span", { style: { display: 'inline-flex', alignItems: 'center', gap: 6 }, children: [i > 0 ? _jsx(ChevronRight, { size: 12, className: "crumb-sep" }) : null, c.href ? (_jsx(NavLink, { to: c.href, className: "crumb-link", style: { color: 'inherit', textDecoration: 'none' }, children: c.labelKey !== undefined ? tScoped(c.labelScope ?? 'core', c.labelKey) : c.literal })) : (_jsx("span", { className: "crumb-cur", children: c.labelKey !== undefined ? tScoped(c.labelScope ?? 'core', c.labelKey) : c.literal }))] }, i))) }), _jsxs("div", { className: "b2b-topbar__actions", children: [_jsx("button", { type: "button", className: "b2b-topbar__icon-btn", title: t('appShell.search.openPalette'), "aria-label": t('appShell.search.openPalette'), onClick: () => setPaletteOpen(true), children: _jsx(Search, { size: 16 }) }), isModulePresent('admin_notifications') && hasPermission('admin:read') ? (_jsx(NotificationBell, {})) : null, _jsx("button", { type: "button", className: "b2b-topbar__icon-btn b2b-topbar__hide-mobile", title: t('appShell.topbar.help'), "aria-label": t('appShell.topbar.help'), children: _jsx(HelpCircle, { size: 16 }) }), _jsx("div", { style: { width: 1, height: 22, background: 'var(--border-color)', margin: '0 4px' } }), _jsx(LanguagePicker, {}), me ? (_jsx(NavLink, { to: "/profile", className: "b2b-avatar", title: `${fullName || me.adminUser.email} — ${t('appShell.profileMenu.profile')}`, "aria-label": t('appShell.profileMenu.profile'), style: { textDecoration: 'none', cursor: 'pointer' }, children: (fullName || me.adminUser.email).slice(0, 2).toUpperCase() })) : null] })] }), _jsxs("main", { className: "b2b-main", style: { flex: 1, overflow: 'auto' }, children: [_jsx("div", { className: "b2b-impersonation-slot", "data-impersonation-banner": true }), me !== null && me.role === null ? _jsx(RoleRequiredNotice, {}) : null, _jsx(Outlet, {})] })] }), _jsx(CommandPalette, { open: paletteOpen, onClose: () => setPaletteOpen(false), onNavigate: (to) => {
1001
+ : (t('appShell.sidebarToggle.collapse') || 'Collapse sidebar'), "aria-pressed": railMode, children: [railMode ? _jsx(PanelLeftOpen, { size: 14 }) : _jsx(PanelLeftClose, { size: 14 }), !railMode ? (_jsx("span", { className: "b2b-sidebar__rail-toggle-label", children: t('appShell.sidebarToggle.collapse') || 'Collapse' })) : null] })) : null] }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", "data-testid": "sidebar-pin-status", children: pinAnnouncement }), _jsxs("div", { style: { minWidth: 0, display: 'flex', flexDirection: 'column' }, children: [_jsxs("div", { className: "b2b-topbar", children: [isMobile ? (_jsx("button", { type: "button", className: "b2b-topbar__menu-btn", "aria-label": t('appShell.mobileMenu.open'), "aria-expanded": navDrawerOpen, onClick: () => setNavDrawerOpen((open) => !open), children: _jsx(Menu, { size: 20 }) })) : null, _jsx("div", { className: isCmsRoute ? 'b2b-topbar__crumbs-inner b2b-page b2b-page--wide' : 'b2b-topbar__crumbs', children: crumbs.map((c, i) => (_jsxs("span", { style: { display: 'inline-flex', alignItems: 'center', gap: 6 }, children: [i > 0 ? _jsx(ChevronRight, { size: 12, className: "crumb-sep" }) : null, c.href ? (_jsx(NavLink, { to: c.href, className: "crumb-link", style: { color: 'inherit', textDecoration: 'none' }, children: c.labelKey !== undefined ? tScoped(c.labelScope ?? 'core', c.labelKey) : c.literal })) : (_jsx("span", { className: "crumb-cur", children: c.labelKey !== undefined ? tScoped(c.labelScope ?? 'core', c.labelKey) : c.literal }))] }, i))) }), _jsxs("div", { className: "b2b-topbar__actions", children: [_jsx("button", { type: "button", className: "b2b-topbar__icon-btn", title: t('appShell.search.openPalette'), "aria-label": t('appShell.search.openPalette'), onClick: () => setPaletteOpen(true), children: _jsx(Search, { size: 16 }) }), isModulePresent('admin_notifications') ? (_jsx(NotificationBell, {})) : null, _jsx("button", { type: "button", className: "b2b-topbar__icon-btn b2b-topbar__hide-mobile", title: t('appShell.topbar.help'), "aria-label": t('appShell.topbar.help'), children: _jsx(HelpCircle, { size: 16 }) }), _jsx("div", { style: { width: 1, height: 22, background: 'var(--border-color)', margin: '0 4px' } }), _jsx(LanguagePicker, {}), me ? (_jsx(NavLink, { to: "/profile", className: "b2b-avatar", title: `${fullName || me.adminUser.email} — ${t('appShell.profileMenu.profile')}`, "aria-label": t('appShell.profileMenu.profile'), style: { textDecoration: 'none', cursor: 'pointer' }, children: (fullName || me.adminUser.email).slice(0, 2).toUpperCase() })) : null] })] }), _jsx(PreferencesSaveNotice, {}), _jsxs("main", { className: "b2b-main", style: { flex: 1, overflow: 'auto' }, children: [_jsx("div", { className: "b2b-impersonation-slot", "data-impersonation-banner": true }), me !== null && me.role === null ? _jsx(RoleRequiredNotice, {}) : null, _jsx(Outlet, {})] })] }), _jsx(CommandPalette, { pinTargets: pinTargets, open: paletteOpen, onClose: () => setPaletteOpen(false), onNavigate: (to) => {
1014
1002
  navigate(to);
1015
1003
  setPaletteOpen(false);
1016
1004
  } })] }));
1017
1005
  }
1018
1006
  function RailSection(props) {
1019
- const { section, visibleItems, translatedLabel } = props;
1007
+ const { section, visibleItems, translatedLabel, pinned } = props;
1020
1008
  const navLabel = useNavLabel();
1021
1009
  const [hover, setHover] = useState(false);
1022
1010
  const [sticky, setSticky] = useState(false);
@@ -1059,11 +1047,11 @@ function RailSection(props) {
1059
1047
  const railSource = visibleItems[0] ?? section.items[0];
1060
1048
  if (!railSource)
1061
1049
  return null;
1062
- const RailIcon = railSource.icon;
1050
+ const RailIcon = pinned?.icon ?? railSource.icon;
1063
1051
  const headerLabel = translatedLabel || (visibleItems[0] ? navLabel(visibleItems[0]) : '');
1064
1052
  // Single-item section: render a plain link with no popover. The
1065
1053
  // hover area is the link itself; tooltip carries the label.
1066
- if (visibleItems.length === 1) {
1054
+ if (visibleItems.length === 1 && pinned === undefined) {
1067
1055
  const only = visibleItems[0];
1068
1056
  const Icon = only.icon;
1069
1057
  const onlyLabel = navLabel(only);
@@ -1072,7 +1060,14 @@ function RailSection(props) {
1072
1060
  return (_jsxs("div", { ref: wrapperRef, className: "b2b-sidebar__rail-row", onMouseEnter: () => {
1073
1061
  cancelClose();
1074
1062
  setHover(true);
1075
- }, onMouseLeave: scheduleClose, children: [_jsx("button", { type: "button", className: cn('b2b-nav-item b2b-nav-item--rail', sectionActive && 'is-active', open && 'is-open'), onClick: () => setSticky((prev) => !prev), "aria-haspopup": "menu", "aria-expanded": open, "aria-label": headerLabel, title: headerLabel, children: _jsx(RailIcon, { size: 18 }) }), open ? (_jsxs("div", { className: "b2b-sidebar__rail-popover", role: "menu", children: [headerLabel ? (_jsx("div", { className: "b2b-sidebar__rail-popover-header", children: headerLabel })) : null, visibleItems.map((item) => {
1063
+ }, onMouseLeave: scheduleClose, children: [_jsx("button", { type: "button", className: cn('b2b-nav-item b2b-nav-item--rail', sectionActive && 'is-active', open && 'is-open'), onClick: () => setSticky((prev) => !prev), ...(pinned === undefined ? { 'aria-haspopup': 'menu' } : {}), "aria-expanded": open, "aria-label": headerLabel, title: headerLabel, children: _jsx(RailIcon, { size: 18 }) }), open && pinned !== undefined ? (_jsxs("div", { className: "b2b-sidebar__rail-popover", children: [headerLabel ? (_jsx("div", { className: "b2b-sidebar__rail-popover-header", children: headerLabel })) : null, visibleItems.map((item) => {
1064
+ const Icon = item.icon;
1065
+ const label = navLabel(item);
1066
+ return (_jsxs("div", { className: "b2b-sidebar__rail-popover-row", children: [_jsxs(NavLink, { to: item.to, end: pinned.endOf(item), className: ({ isActive }) => cn('b2b-sidebar__rail-popover-item', isActive && 'is-active'), onClick: () => {
1067
+ setSticky(false);
1068
+ setHover(false);
1069
+ }, children: [_jsx(Icon, { size: 14 }), _jsx("span", { children: label })] }), _jsx(PinToggleButton, { label: label, pinned: true, onToggle: () => pinned.onUnpin(item) })] }, item.to));
1070
+ })] })) : open ? (_jsxs("div", { className: "b2b-sidebar__rail-popover", role: "menu", children: [headerLabel ? (_jsx("div", { className: "b2b-sidebar__rail-popover-header", children: headerLabel })) : null, visibleItems.map((item) => {
1076
1071
  const Icon = item.icon;
1077
1072
  const hasNestedSibling = visibleItems.some((other) => other !== item &&
1078
1073
  other.to.startsWith(item.to === '/' ? '/' : `${item.to}/`));
@@ -1082,6 +1077,8 @@ function RailSection(props) {
1082
1077
  }, children: [_jsx(Icon, { size: 14 }), _jsx("span", { children: navLabel(item) })] }, item.to));
1083
1078
  })] })) : null] }));
1084
1079
  }
1080
+ /** The `Alt+Enter` chord as the platform writes it (FR-027, research R-16). */
1081
+ const ALT_ENTER_GLYPH = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform) ? '⌥↵' : 'Alt+↵';
1085
1082
  /** Sentinel route for the assistant entry row — switches the palette mode
1086
1083
  * instead of navigating (feature 043; module_actions are navigation-only). */
1087
1084
  const PROMPT_MODE_SENTINEL = '__prompt_actions_mode__';
@@ -1104,8 +1101,14 @@ export function resetPromptCapabilityCacheForTesting() {
1104
1101
  promptCapabilityCache = null;
1105
1102
  }
1106
1103
  function CommandPalette(props) {
1107
- const { open, onClose, onNavigate } = props;
1104
+ const { open, onClose, onNavigate, pinTargets } = props;
1108
1105
  const t = useTranslation('core');
1106
+ const navLabel = useNavLabel();
1107
+ const { isPinned, toggle: togglePin } = usePinActions();
1108
+ // The palette is `aria-modal`, so assistive technology ignores the sidebar's
1109
+ // region while it is open: it announces in its own (research R-16).
1110
+ const [pinAnnouncement, setPinAnnouncement] = useState('');
1111
+ const instructionsId = useId();
1109
1112
  const tp = useTranslation('prompt_actions');
1110
1113
  const { hasPermission } = useAuth();
1111
1114
  const isVisible = useSurfaceVisibility();
@@ -1249,7 +1252,7 @@ function CommandPalette(props) {
1249
1252
  if (!query.trim())
1250
1253
  return [...assistantItems, ...navigateItems, ...actionItems];
1251
1254
  // Folded once here, then compared against every row — see `matchesQuery`.
1252
- const q = normalize(query);
1255
+ const q = searchTerms(query);
1253
1256
  const filteredAssistant = assistantItems.filter((i) => matchesQuery(q, i.label, i.sub, i.keywords));
1254
1257
  // Navigate group: filter against the *translated* label + sub plus
1255
1258
  // the raw keywords list so a Polish user can search in Polish and
@@ -1261,6 +1264,17 @@ function CommandPalette(props) {
1261
1264
  // eslint-disable-next-line react-hooks/exhaustive-deps
1262
1265
  }, [query, actionItems, assistantItems, navigateItems, recordItems]);
1263
1266
  const items = useMemo(() => (seeAllItem ? [...itemsBeforeSeeAll, seeAllItem] : itemsBeforeSeeAll), [itemsBeforeSeeAll, seeAllItem]);
1267
+ // FR-027 — a row is pinnable when its destination **is** a visible sidebar
1268
+ // entry's. The assistant sentinel and "see all" (a path with a query) never
1269
+ // match a destination, so they never carry the control.
1270
+ const pinTargetOf = useCallback((it) => it.to === PROMPT_MODE_SENTINEL ? undefined : pinTargets.get(it.to), [pinTargets]);
1271
+ const togglePinOf = useCallback((to) => {
1272
+ const target = pinTargets.get(to);
1273
+ if (!target)
1274
+ return;
1275
+ const outcome = togglePin(to);
1276
+ setPinAnnouncement(pinAnnouncementText(t, outcome, navLabel(target.item)));
1277
+ }, [pinTargets, togglePin, t, navLabel]);
1264
1278
  // Activating the assistant row switches the palette body instead of
1265
1279
  // navigating (feature 043); everything else keeps the navigation path.
1266
1280
  const activate = useCallback((to) => {
@@ -1290,6 +1304,7 @@ function CommandPalette(props) {
1290
1304
  }, [query, open]);
1291
1305
  useEffect(() => {
1292
1306
  if (!open) {
1307
+ setPinAnnouncement('');
1293
1308
  setQuery('');
1294
1309
  setMode('search');
1295
1310
  setInitialRequest(undefined);
@@ -1321,6 +1336,14 @@ function CommandPalette(props) {
1321
1336
  e.preventDefault();
1322
1337
  setCursor((c) => Math.max(0, c - 1));
1323
1338
  }
1339
+ else if (e.key === 'Enter' && e.altKey) {
1340
+ // Feature 164, FR-027 — `Alt+Enter` (⌥↵) pins or unpins the highlighted
1341
+ // row and never navigates; focus stays in the input.
1342
+ e.preventDefault();
1343
+ const it = items[cursor];
1344
+ if (it && pinTargetOf(it))
1345
+ togglePinOf(it.to);
1346
+ }
1324
1347
  else if (e.key === 'Enter') {
1325
1348
  e.preventDefault();
1326
1349
  const it = items[cursor];
@@ -1333,7 +1356,7 @@ function CommandPalette(props) {
1333
1356
  };
1334
1357
  window.addEventListener('keydown', onKey);
1335
1358
  return () => window.removeEventListener('keydown', onKey);
1336
- }, [open, mode, items, cursor, onClose, activate]);
1359
+ }, [open, mode, items, cursor, onClose, activate, pinTargetOf, togglePinOf]);
1337
1360
  if (!open)
1338
1361
  return null;
1339
1362
  if (mode === 'prompt') {
@@ -1356,14 +1379,27 @@ function CommandPalette(props) {
1356
1379
  const Icon = it.icon;
1357
1380
  const label = resolveLabel(it);
1358
1381
  const sub = resolveSub(it);
1359
- return (_jsxs("div", { className: cn('b2b-palette__item', i === cursor && 'is-cur'), onMouseEnter: () => setCursor(i), onClick: () => activate(it.to), children: [_jsx(Icon, { size: 16, "aria-hidden": "true" }), _jsxs("div", { style: { minWidth: 0, flex: 1 }, children: [_jsx("div", { children: label }), sub ? _jsx("div", { style: { fontSize: 11, color: 'var(--fg-muted)' }, children: sub }) : null] }), it.badge ? _jsx(Badge, { variant: "secondary", children: it.badge }) : null, _jsx("span", { className: "meta", children: i === cursor ? _jsx("span", { className: "b2b-kbd-sm", children: "\u21B5" }) : null })] }, `${it.group}-${it.groupKey ?? ''}-${it.to}-${i}`));
1382
+ const pinTarget = pinTargetOf(it);
1383
+ const pinned = pinTarget !== undefined && isPinned(it.to);
1384
+ const pinName = pinTarget === undefined
1385
+ ? ''
1386
+ : t(pinned ? 'appShell.pinned.unpin' : 'appShell.pinned.pin', {
1387
+ label: navLabel(pinTarget.item),
1388
+ });
1389
+ return (_jsxs("div", { className: cn('b2b-palette__item', i === cursor && 'is-cur'), onMouseEnter: () => setCursor(i), onClick: () => activate(it.to), children: [_jsx(Icon, { size: 16, "aria-hidden": "true" }), _jsxs("div", { style: { minWidth: 0, flex: 1 }, children: [_jsx("div", { children: label }), sub ? _jsx("div", { style: { fontSize: 11, color: 'var(--fg-muted)' }, children: sub }) : null] }), it.badge ? _jsx(Badge, { variant: "secondary", children: it.badge }) : null, pinTarget !== undefined && i === cursor ? (_jsxs("span", { className: "b2b-palette__pin-hint", children: [_jsx("span", { className: "b2b-kbd-sm", children: ALT_ENTER_GLYPH }), t(pinned ? 'appShell.palette.pin.hintUnpin' : 'appShell.palette.pin.hintPin')] })) : null, pinTarget !== undefined ? (_jsx("button", { type: "button", tabIndex: -1, className: "b2b-palette__pin", "aria-pressed": pinned, "aria-keyshortcuts": "Alt+Enter", "aria-label": pinName, title: pinName,
1390
+ // Focus stays in the search input; the row's own activation (open
1391
+ // the destination) must not fire.
1392
+ onMouseDown: (event) => event.preventDefault(), onClick: (event) => {
1393
+ event.stopPropagation();
1394
+ togglePinOf(it.to);
1395
+ }, children: pinned ? _jsx(PinOff, { size: 14, "aria-hidden": "true" }) : _jsx(Pin, { size: 14, "aria-hidden": "true" }) })) : null, _jsx("span", { className: "meta", children: i === cursor ? _jsx("span", { className: "b2b-kbd-sm", children: "\u21B5" }) : null })] }, `${it.group}-${it.groupKey ?? ''}-${it.to}-${i}`));
1360
1396
  };
1361
1397
  let lastGroup = '';
1362
1398
  let recordIndex = firstRecordIndex;
1363
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "b2b-scrim", onClick: onClose }), _jsxs("div", { className: "b2b-palette", role: "dialog", "aria-modal": "true", children: [_jsxs("div", { className: "b2b-palette__input", children: [_jsx(Search, { size: 18, style: { color: 'var(--fg-muted)' } }), _jsx("input", { ref: inputRef, placeholder: t('appShell.search.commandPalettePlaceholder'), value: query, onChange: (e) => handleQueryChange(e.target.value) }), _jsx(SpeechToTextButton, { startTitle: t('appShell.search.voiceInput'), stopTitle: t('appShell.search.voiceInputStop'), onTranscript: (text) => {
1399
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "b2b-scrim", onClick: onClose }), _jsxs("div", { className: "b2b-palette", role: "dialog", "aria-modal": "true", children: [_jsxs("div", { className: "b2b-palette__input", children: [_jsx(Search, { size: 18, style: { color: 'var(--fg-muted)' } }), _jsx("input", { ref: inputRef, placeholder: t('appShell.search.commandPalettePlaceholder'), "aria-describedby": instructionsId, value: query, onChange: (e) => handleQueryChange(e.target.value) }), _jsx(SpeechToTextButton, { startTitle: t('appShell.search.voiceInput'), stopTitle: t('appShell.search.voiceInputStop'), onTranscript: (text) => {
1364
1400
  setQuery((q) => (q ? `${q} ${text}` : text));
1365
1401
  inputRef.current?.focus();
1366
- } }), _jsx("span", { className: "b2b-kbd-sm", children: "esc" })] }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", "data-testid": "palette-records-status", children: showRecords && records.state === 'ready'
1402
+ } }), _jsx("span", { className: "b2b-kbd-sm", children: "esc" }), _jsx("span", { id: instructionsId, className: "sr-only", children: t('appShell.palette.pin.instructions') })] }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", "data-testid": "palette-pin-status", children: pinAnnouncement }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", "data-testid": "palette-records-status", children: showRecords && records.state === 'ready'
1367
1403
  ? t('appShell.palette.records.announce', { count: recordCount })
1368
1404
  : '' }), _jsxs("div", { className: "b2b-palette__list", "aria-busy": recordsLoading, children: [unseen.length > 0 ? (_jsxs("div", { "data-testid": "prompt-unseen-notice", className: "b2b-palette__item", style: { cursor: 'pointer' }, onClick: () => {
1369
1405
  setInitialRequest(unseen[0]);