@endora-commerce/admin-shell 0.108.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 (392) hide show
  1. package/dist/AdminRoot.js +1 -1
  2. package/dist/AdminRoot.js.map +1 -1
  3. package/dist/App.d.ts.map +1 -1
  4. package/dist/App.js +2 -6
  5. package/dist/App.js.map +1 -1
  6. package/dist/components/AdminFeedback.d.ts.map +1 -1
  7. package/dist/components/AdminFeedback.js +3 -9
  8. package/dist/components/AdminFeedback.js.map +1 -1
  9. package/dist/components/AppShell.d.ts.map +1 -1
  10. package/dist/components/AppShell.js +177 -143
  11. package/dist/components/AppShell.js.map +1 -1
  12. package/dist/components/FederatedSignIn.d.ts.map +1 -1
  13. package/dist/components/FederatedSignIn.js +1 -2
  14. package/dist/components/FederatedSignIn.js.map +1 -1
  15. package/dist/components/IdleLogout.js +1 -1
  16. package/dist/components/IdleLogout.js.map +1 -1
  17. package/dist/components/ImpersonationBanner.d.ts.map +1 -1
  18. package/dist/components/ImpersonationBanner.js +2 -3
  19. package/dist/components/ImpersonationBanner.js.map +1 -1
  20. package/dist/components/LanguagePicker.d.ts.map +1 -1
  21. package/dist/components/LanguagePicker.js +2 -5
  22. package/dist/components/LanguagePicker.js.map +1 -1
  23. package/dist/components/LoginPage.d.ts.map +1 -1
  24. package/dist/components/LoginPage.js +2 -6
  25. package/dist/components/LoginPage.js.map +1 -1
  26. package/dist/components/RoleRequiredNotice.js +2 -2
  27. package/dist/components/RoleRequiredNotice.js.map +1 -1
  28. package/dist/components/SpeechToTextButton.js +1 -1
  29. package/dist/components/SpeechToTextButton.js.map +1 -1
  30. package/dist/components/VersionBadge.js +2 -2
  31. package/dist/components/VersionBadge.js.map +1 -1
  32. package/dist/components/notifications/NotificationBell.d.ts.map +1 -1
  33. package/dist/components/notifications/NotificationBell.js +1 -2
  34. package/dist/components/notifications/NotificationBell.js.map +1 -1
  35. package/dist/components/notifications/notification-text.d.ts +1 -1
  36. package/dist/components/notifications/notification-text.d.ts.map +1 -1
  37. package/dist/components/notifications/notification-text.js +1 -2
  38. package/dist/components/notifications/notification-text.js.map +1 -1
  39. package/dist/components/notifications/useAdminNotifications.js +1 -1
  40. package/dist/components/notifications/useAdminNotifications.js.map +1 -1
  41. package/dist/components/prompt-actions/PromptModePanel.js +2 -2
  42. package/dist/components/prompt-actions/PromptModePanel.js.map +1 -1
  43. package/dist/components/prompt-actions/PromptPlanPreview.js +2 -2
  44. package/dist/components/prompt-actions/PromptPlanPreview.js.map +1 -1
  45. package/dist/components/sidebar/PinToggleButton.d.ts +21 -0
  46. package/dist/components/sidebar/PinToggleButton.d.ts.map +1 -0
  47. package/dist/components/sidebar/PinToggleButton.js +19 -0
  48. package/dist/components/sidebar/PinToggleButton.js.map +1 -0
  49. package/dist/components/sidebar/PinnedSection.d.ts +37 -0
  50. package/dist/components/sidebar/PinnedSection.d.ts.map +1 -0
  51. package/dist/components/sidebar/PinnedSection.js +70 -0
  52. package/dist/components/sidebar/PinnedSection.js.map +1 -0
  53. package/dist/components/sidebar/PreferencesSaveNotice.d.ts +10 -0
  54. package/dist/components/sidebar/PreferencesSaveNotice.d.ts.map +1 -0
  55. package/dist/components/sidebar/PreferencesSaveNotice.js +17 -0
  56. package/dist/components/sidebar/PreferencesSaveNotice.js.map +1 -0
  57. package/dist/components/sidebar/nav-types.d.ts +59 -0
  58. package/dist/components/sidebar/nav-types.d.ts.map +1 -0
  59. package/dist/components/sidebar/nav-types.js +2 -0
  60. package/dist/components/sidebar/nav-types.js.map +1 -0
  61. package/dist/components/sidebar/use-pin-actions.d.ts +14 -0
  62. package/dist/components/sidebar/use-pin-actions.d.ts.map +1 -0
  63. package/dist/components/sidebar/use-pin-actions.js +22 -0
  64. package/dist/components/sidebar/use-pin-actions.js.map +1 -0
  65. package/dist/index.d.ts +2 -2
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +1 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/lib/admin-actions/api.js +1 -1
  70. package/dist/lib/admin-actions/api.js.map +1 -1
  71. package/dist/lib/admin-actions/useAdminActions.d.ts +2 -1
  72. package/dist/lib/admin-actions/useAdminActions.d.ts.map +1 -1
  73. package/dist/lib/admin-actions/useAdminActions.js +5 -14
  74. package/dist/lib/admin-actions/useAdminActions.js.map +1 -1
  75. package/dist/lib/admin-feedback/api.js +1 -1
  76. package/dist/lib/admin-feedback/api.js.map +1 -1
  77. package/dist/lib/federated-sign-in/api.js +1 -1
  78. package/dist/lib/federated-sign-in/api.js.map +1 -1
  79. package/dist/lib/global-search/api.js +1 -1
  80. package/dist/lib/global-search/api.js.map +1 -1
  81. package/dist/lib/palette-match.d.ts +26 -0
  82. package/dist/lib/palette-match.d.ts.map +1 -0
  83. package/dist/lib/palette-match.js +36 -0
  84. package/dist/lib/palette-match.js.map +1 -0
  85. package/dist/lib/pinned-entries.d.ts +49 -0
  86. package/dist/lib/pinned-entries.d.ts.map +1 -0
  87. package/dist/lib/pinned-entries.js +58 -0
  88. package/dist/lib/pinned-entries.js.map +1 -0
  89. package/dist/lib/platform-info/api.js +1 -1
  90. package/dist/lib/platform-info/api.js.map +1 -1
  91. package/dist/lib/prompt-actions/api.js +1 -1
  92. package/dist/lib/prompt-actions/api.js.map +1 -1
  93. package/dist/lib/prompt-actions/usePromptRequest.js +1 -1
  94. package/dist/lib/prompt-actions/usePromptRequest.js.map +1 -1
  95. package/dist/modules/home/HomePage.d.ts.map +1 -1
  96. package/dist/modules/home/HomePage.js +2 -4
  97. package/dist/modules/home/HomePage.js.map +1 -1
  98. package/dist/modules/home/RecentActivityCard.d.ts.map +1 -1
  99. package/dist/modules/home/RecentActivityCard.js +1 -2
  100. package/dist/modules/home/RecentActivityCard.js.map +1 -1
  101. package/dist/modules/home/activity-render.js +1 -1
  102. package/dist/modules/home/activity-render.js.map +1 -1
  103. package/dist/modules/home/useRecentActivity.js +1 -1
  104. package/dist/modules/home/useRecentActivity.js.map +1 -1
  105. package/dist/modules/platform/ApiDescriptionPage.d.ts.map +1 -1
  106. package/dist/modules/platform/ApiDescriptionPage.js +3 -6
  107. package/dist/modules/platform/ApiDescriptionPage.js.map +1 -1
  108. package/dist/modules/platform/ModuleActivationControl.d.ts.map +1 -1
  109. package/dist/modules/platform/ModuleActivationControl.js +2 -3
  110. package/dist/modules/platform/ModuleActivationControl.js.map +1 -1
  111. package/dist/modules/platform/ModulesPage.d.ts.map +1 -1
  112. package/dist/modules/platform/ModulesPage.js +3 -9
  113. package/dist/modules/platform/ModulesPage.js.map +1 -1
  114. package/dist/modules/platform/RecentActivityVisibilityControl.js +2 -2
  115. package/dist/modules/platform/RecentActivityVisibilityControl.js.map +1 -1
  116. package/dist/modules/platform/api-description.d.ts.map +1 -1
  117. package/dist/modules/platform/api-description.js +1 -2
  118. package/dist/modules/platform/api-description.js.map +1 -1
  119. package/dist/modules/platform/api.js +1 -1
  120. package/dist/modules/platform/api.js.map +1 -1
  121. package/dist/modules/profile/ProfilePage.d.ts.map +1 -1
  122. package/dist/modules/profile/ProfilePage.js +2 -5
  123. package/dist/modules/profile/ProfilePage.js.map +1 -1
  124. package/package.json +9 -6
  125. package/dist/components/FileDropzone.d.ts +0 -17
  126. package/dist/components/FileDropzone.d.ts.map +0 -1
  127. package/dist/components/FileDropzone.js +0 -17
  128. package/dist/components/FileDropzone.js.map +0 -1
  129. package/dist/components/PaginationFooter.d.ts +0 -18
  130. package/dist/components/PaginationFooter.d.ts.map +0 -1
  131. package/dist/components/PaginationFooter.js +0 -17
  132. package/dist/components/PaginationFooter.js.map +0 -1
  133. package/dist/components/ResponsiveTable.d.ts +0 -18
  134. package/dist/components/ResponsiveTable.d.ts.map +0 -1
  135. package/dist/components/ResponsiveTable.js +0 -17
  136. package/dist/components/ResponsiveTable.js.map +0 -1
  137. package/dist/components/RowActionMenu.d.ts +0 -18
  138. package/dist/components/RowActionMenu.d.ts.map +0 -1
  139. package/dist/components/RowActionMenu.js +0 -17
  140. package/dist/components/RowActionMenu.js.map +0 -1
  141. package/dist/components/StickyFormActions.d.ts +0 -18
  142. package/dist/components/StickyFormActions.d.ts.map +0 -1
  143. package/dist/components/StickyFormActions.js +0 -17
  144. package/dist/components/StickyFormActions.js.map +0 -1
  145. package/dist/components/TouchReorderButtons.d.ts +0 -18
  146. package/dist/components/TouchReorderButtons.d.ts.map +0 -1
  147. package/dist/components/TouchReorderButtons.js +0 -17
  148. package/dist/components/TouchReorderButtons.js.map +0 -1
  149. package/dist/components/admin-user-picker/AdminUserPicker.d.ts +0 -18
  150. package/dist/components/admin-user-picker/AdminUserPicker.d.ts.map +0 -1
  151. package/dist/components/admin-user-picker/AdminUserPicker.js +0 -17
  152. package/dist/components/admin-user-picker/AdminUserPicker.js.map +0 -1
  153. package/dist/components/asset-picker/AssetFieldPicker.d.ts +0 -21
  154. package/dist/components/asset-picker/AssetFieldPicker.d.ts.map +0 -1
  155. package/dist/components/asset-picker/AssetFieldPicker.js +0 -20
  156. package/dist/components/asset-picker/AssetFieldPicker.js.map +0 -1
  157. package/dist/components/category-picker/CategorySelect.d.ts +0 -18
  158. package/dist/components/category-picker/CategorySelect.d.ts.map +0 -1
  159. package/dist/components/category-picker/CategorySelect.js +0 -17
  160. package/dist/components/category-picker/CategorySelect.js.map +0 -1
  161. package/dist/components/category-tree-picker/CategoryTreePicker.d.ts +0 -18
  162. package/dist/components/category-tree-picker/CategoryTreePicker.d.ts.map +0 -1
  163. package/dist/components/category-tree-picker/CategoryTreePicker.js +0 -17
  164. package/dist/components/category-tree-picker/CategoryTreePicker.js.map +0 -1
  165. package/dist/components/category-tree-picker/category-tree-utils.d.ts +0 -18
  166. package/dist/components/category-tree-picker/category-tree-utils.d.ts.map +0 -1
  167. package/dist/components/category-tree-picker/category-tree-utils.js +0 -17
  168. package/dist/components/category-tree-picker/category-tree-utils.js.map +0 -1
  169. package/dist/components/category-tree-picker/index.d.ts +0 -18
  170. package/dist/components/category-tree-picker/index.d.ts.map +0 -1
  171. package/dist/components/category-tree-picker/index.js +0 -17
  172. package/dist/components/category-tree-picker/index.js.map +0 -1
  173. package/dist/components/charts/echart.d.ts +0 -18
  174. package/dist/components/charts/echart.d.ts.map +0 -1
  175. package/dist/components/charts/echart.js +0 -17
  176. package/dist/components/charts/echart.js.map +0 -1
  177. package/dist/components/cms-picker/CmsBlockPicker.d.ts +0 -19
  178. package/dist/components/cms-picker/CmsBlockPicker.d.ts.map +0 -1
  179. package/dist/components/cms-picker/CmsBlockPicker.js +0 -18
  180. package/dist/components/cms-picker/CmsBlockPicker.js.map +0 -1
  181. package/dist/components/cms-picker/CmsPagePicker.d.ts +0 -19
  182. package/dist/components/cms-picker/CmsPagePicker.d.ts.map +0 -1
  183. package/dist/components/cms-picker/CmsPagePicker.js +0 -18
  184. package/dist/components/cms-picker/CmsPagePicker.js.map +0 -1
  185. package/dist/components/country-select/index.d.ts +0 -18
  186. package/dist/components/country-select/index.d.ts.map +0 -1
  187. package/dist/components/country-select/index.js +0 -17
  188. package/dist/components/country-select/index.js.map +0 -1
  189. package/dist/components/customer-group-picker/CustomerGroupPicker.d.ts +0 -18
  190. package/dist/components/customer-group-picker/CustomerGroupPicker.d.ts.map +0 -1
  191. package/dist/components/customer-group-picker/CustomerGroupPicker.js +0 -17
  192. package/dist/components/customer-group-picker/CustomerGroupPicker.js.map +0 -1
  193. package/dist/components/customer-picker/CustomerPicker.d.ts +0 -18
  194. package/dist/components/customer-picker/CustomerPicker.d.ts.map +0 -1
  195. package/dist/components/customer-picker/CustomerPicker.js +0 -17
  196. package/dist/components/customer-picker/CustomerPicker.js.map +0 -1
  197. package/dist/components/hooks/useFocusTrap.d.ts +0 -17
  198. package/dist/components/hooks/useFocusTrap.d.ts.map +0 -1
  199. package/dist/components/hooks/useFocusTrap.js +0 -17
  200. package/dist/components/hooks/useFocusTrap.js.map +0 -1
  201. package/dist/components/hooks/useViewportTier.d.ts +0 -18
  202. package/dist/components/hooks/useViewportTier.d.ts.map +0 -1
  203. package/dist/components/hooks/useViewportTier.js +0 -17
  204. package/dist/components/hooks/useViewportTier.js.map +0 -1
  205. package/dist/components/organization-picker/OrganizationPicker.d.ts +0 -19
  206. package/dist/components/organization-picker/OrganizationPicker.d.ts.map +0 -1
  207. package/dist/components/organization-picker/OrganizationPicker.js +0 -18
  208. package/dist/components/organization-picker/OrganizationPicker.js.map +0 -1
  209. package/dist/components/organization-picker/OrganizationPickerMulti.d.ts +0 -19
  210. package/dist/components/organization-picker/OrganizationPickerMulti.d.ts.map +0 -1
  211. package/dist/components/organization-picker/OrganizationPickerMulti.js +0 -18
  212. package/dist/components/organization-picker/OrganizationPickerMulti.js.map +0 -1
  213. package/dist/components/organization-picker/OrganizationStatusBadge.d.ts +0 -19
  214. package/dist/components/organization-picker/OrganizationStatusBadge.d.ts.map +0 -1
  215. package/dist/components/organization-picker/OrganizationStatusBadge.js +0 -18
  216. package/dist/components/organization-picker/OrganizationStatusBadge.js.map +0 -1
  217. package/dist/components/organization-picker/index.d.ts +0 -19
  218. package/dist/components/organization-picker/index.d.ts.map +0 -1
  219. package/dist/components/organization-picker/index.js +0 -18
  220. package/dist/components/organization-picker/index.js.map +0 -1
  221. package/dist/components/organization-picker/useOrganizationsQuery.d.ts +0 -19
  222. package/dist/components/organization-picker/useOrganizationsQuery.d.ts.map +0 -1
  223. package/dist/components/organization-picker/useOrganizationsQuery.js +0 -18
  224. package/dist/components/organization-picker/useOrganizationsQuery.js.map +0 -1
  225. package/dist/components/payment-method-availability/MethodAvailabilityCell.d.ts +0 -17
  226. package/dist/components/payment-method-availability/MethodAvailabilityCell.d.ts.map +0 -1
  227. package/dist/components/payment-method-availability/MethodAvailabilityCell.js +0 -17
  228. package/dist/components/payment-method-availability/MethodAvailabilityCell.js.map +0 -1
  229. package/dist/components/reorder/ReorderAnnouncer.d.ts +0 -18
  230. package/dist/components/reorder/ReorderAnnouncer.d.ts.map +0 -1
  231. package/dist/components/reorder/ReorderAnnouncer.js +0 -17
  232. package/dist/components/reorder/ReorderAnnouncer.js.map +0 -1
  233. package/dist/components/reorder/useReorderList.d.ts +0 -18
  234. package/dist/components/reorder/useReorderList.d.ts.map +0 -1
  235. package/dist/components/reorder/useReorderList.js +0 -17
  236. package/dist/components/reorder/useReorderList.js.map +0 -1
  237. package/dist/components/rule-builder/RuleBuilder.d.ts +0 -18
  238. package/dist/components/rule-builder/RuleBuilder.d.ts.map +0 -1
  239. package/dist/components/rule-builder/RuleBuilder.js +0 -17
  240. package/dist/components/rule-builder/RuleBuilder.js.map +0 -1
  241. package/dist/components/sales-channel-picker/SalesChannelPicker.d.ts +0 -19
  242. package/dist/components/sales-channel-picker/SalesChannelPicker.d.ts.map +0 -1
  243. package/dist/components/sales-channel-picker/SalesChannelPicker.js +0 -18
  244. package/dist/components/sales-channel-picker/SalesChannelPicker.js.map +0 -1
  245. package/dist/components/scope-notice/ScopeNotice.d.ts +0 -18
  246. package/dist/components/scope-notice/ScopeNotice.d.ts.map +0 -1
  247. package/dist/components/scope-notice/ScopeNotice.js +0 -17
  248. package/dist/components/scope-notice/ScopeNotice.js.map +0 -1
  249. package/dist/components/ui/alert.d.ts +0 -18
  250. package/dist/components/ui/alert.d.ts.map +0 -1
  251. package/dist/components/ui/alert.js +0 -17
  252. package/dist/components/ui/alert.js.map +0 -1
  253. package/dist/components/ui/badge.d.ts +0 -18
  254. package/dist/components/ui/badge.d.ts.map +0 -1
  255. package/dist/components/ui/badge.js +0 -17
  256. package/dist/components/ui/badge.js.map +0 -1
  257. package/dist/components/ui/button.d.ts +0 -18
  258. package/dist/components/ui/button.d.ts.map +0 -1
  259. package/dist/components/ui/button.js +0 -17
  260. package/dist/components/ui/button.js.map +0 -1
  261. package/dist/components/ui/card.d.ts +0 -17
  262. package/dist/components/ui/card.d.ts.map +0 -1
  263. package/dist/components/ui/card.js +0 -17
  264. package/dist/components/ui/card.js.map +0 -1
  265. package/dist/components/ui/checkbox.d.ts +0 -17
  266. package/dist/components/ui/checkbox.d.ts.map +0 -1
  267. package/dist/components/ui/checkbox.js +0 -17
  268. package/dist/components/ui/checkbox.js.map +0 -1
  269. package/dist/components/ui/color-picker.d.ts +0 -17
  270. package/dist/components/ui/color-picker.d.ts.map +0 -1
  271. package/dist/components/ui/color-picker.js +0 -17
  272. package/dist/components/ui/color-picker.js.map +0 -1
  273. package/dist/components/ui/combobox.d.ts +0 -18
  274. package/dist/components/ui/combobox.d.ts.map +0 -1
  275. package/dist/components/ui/combobox.js +0 -17
  276. package/dist/components/ui/combobox.js.map +0 -1
  277. package/dist/components/ui/input.d.ts +0 -17
  278. package/dist/components/ui/input.d.ts.map +0 -1
  279. package/dist/components/ui/input.js +0 -17
  280. package/dist/components/ui/input.js.map +0 -1
  281. package/dist/components/ui/label.d.ts +0 -17
  282. package/dist/components/ui/label.d.ts.map +0 -1
  283. package/dist/components/ui/label.js +0 -17
  284. package/dist/components/ui/label.js.map +0 -1
  285. package/dist/components/ui/multi-select.d.ts +0 -18
  286. package/dist/components/ui/multi-select.d.ts.map +0 -1
  287. package/dist/components/ui/multi-select.js +0 -17
  288. package/dist/components/ui/multi-select.js.map +0 -1
  289. package/dist/components/ui/page-header.d.ts +0 -18
  290. package/dist/components/ui/page-header.d.ts.map +0 -1
  291. package/dist/components/ui/page-header.js +0 -17
  292. package/dist/components/ui/page-header.js.map +0 -1
  293. package/dist/components/ui/route-tabs.d.ts +0 -18
  294. package/dist/components/ui/route-tabs.d.ts.map +0 -1
  295. package/dist/components/ui/route-tabs.js +0 -17
  296. package/dist/components/ui/route-tabs.js.map +0 -1
  297. package/dist/components/ui/save-button-group.d.ts +0 -18
  298. package/dist/components/ui/save-button-group.d.ts.map +0 -1
  299. package/dist/components/ui/save-button-group.js +0 -17
  300. package/dist/components/ui/save-button-group.js.map +0 -1
  301. package/dist/components/ui/select.d.ts +0 -17
  302. package/dist/components/ui/select.d.ts.map +0 -1
  303. package/dist/components/ui/select.js +0 -17
  304. package/dist/components/ui/select.js.map +0 -1
  305. package/dist/components/ui/separator.d.ts +0 -17
  306. package/dist/components/ui/separator.d.ts.map +0 -1
  307. package/dist/components/ui/separator.js +0 -17
  308. package/dist/components/ui/separator.js.map +0 -1
  309. package/dist/components/ui/table.d.ts +0 -17
  310. package/dist/components/ui/table.d.ts.map +0 -1
  311. package/dist/components/ui/table.js +0 -17
  312. package/dist/components/ui/table.js.map +0 -1
  313. package/dist/components/ui/textarea.d.ts +0 -17
  314. package/dist/components/ui/textarea.d.ts.map +0 -1
  315. package/dist/components/ui/textarea.js +0 -17
  316. package/dist/components/ui/textarea.js.map +0 -1
  317. package/dist/i18n/TranslationProvider.d.ts +0 -18
  318. package/dist/i18n/TranslationProvider.d.ts.map +0 -1
  319. package/dist/i18n/TranslationProvider.js +0 -17
  320. package/dist/i18n/TranslationProvider.js.map +0 -1
  321. package/dist/i18n/app-language-context.d.ts +0 -18
  322. package/dist/i18n/app-language-context.d.ts.map +0 -1
  323. package/dist/i18n/app-language-context.js +0 -17
  324. package/dist/i18n/app-language-context.js.map +0 -1
  325. package/dist/i18n/interpolate.d.ts +0 -17
  326. package/dist/i18n/interpolate.d.ts.map +0 -1
  327. package/dist/i18n/interpolate.js +0 -17
  328. package/dist/i18n/interpolate.js.map +0 -1
  329. package/dist/i18n/language-storage.d.ts +0 -17
  330. package/dist/i18n/language-storage.d.ts.map +0 -1
  331. package/dist/i18n/language-storage.js +0 -17
  332. package/dist/i18n/language-storage.js.map +0 -1
  333. package/dist/i18n/resolver.d.ts +0 -18
  334. package/dist/i18n/resolver.d.ts.map +0 -1
  335. package/dist/i18n/resolver.js +0 -17
  336. package/dist/i18n/resolver.js.map +0 -1
  337. package/dist/i18n/types.d.ts +0 -17
  338. package/dist/i18n/types.d.ts.map +0 -1
  339. package/dist/i18n/types.js +0 -2
  340. package/dist/i18n/types.js.map +0 -1
  341. package/dist/i18n/useTranslation.d.ts +0 -17
  342. package/dist/i18n/useTranslation.d.ts.map +0 -1
  343. package/dist/i18n/useTranslation.js +0 -17
  344. package/dist/i18n/useTranslation.js.map +0 -1
  345. package/dist/lib/admin-actions/icon-map.d.ts +0 -17
  346. package/dist/lib/admin-actions/icon-map.d.ts.map +0 -1
  347. package/dist/lib/admin-actions/icon-map.js +0 -17
  348. package/dist/lib/admin-actions/icon-map.js.map +0 -1
  349. package/dist/lib/api-client.d.ts +0 -17
  350. package/dist/lib/api-client.d.ts.map +0 -1
  351. package/dist/lib/api-client.js +0 -17
  352. package/dist/lib/api-client.js.map +0 -1
  353. package/dist/lib/auth.d.ts +0 -18
  354. package/dist/lib/auth.d.ts.map +0 -1
  355. package/dist/lib/auth.js +0 -17
  356. package/dist/lib/auth.js.map +0 -1
  357. package/dist/lib/format.d.ts +0 -17
  358. package/dist/lib/format.d.ts.map +0 -1
  359. package/dist/lib/format.js +0 -17
  360. package/dist/lib/format.js.map +0 -1
  361. package/dist/lib/module-presence/index.d.ts +0 -19
  362. package/dist/lib/module-presence/index.d.ts.map +0 -1
  363. package/dist/lib/module-presence/index.js +0 -18
  364. package/dist/lib/module-presence/index.js.map +0 -1
  365. package/dist/lib/money.d.ts +0 -17
  366. package/dist/lib/money.d.ts.map +0 -1
  367. package/dist/lib/money.js +0 -17
  368. package/dist/lib/money.js.map +0 -1
  369. package/dist/lib/surface-visibility.d.ts +0 -15
  370. package/dist/lib/surface-visibility.d.ts.map +0 -1
  371. package/dist/lib/surface-visibility.js +0 -14
  372. package/dist/lib/surface-visibility.js.map +0 -1
  373. package/dist/lib/text-normalization.d.ts +0 -17
  374. package/dist/lib/text-normalization.d.ts.map +0 -1
  375. package/dist/lib/text-normalization.js +0 -17
  376. package/dist/lib/text-normalization.js.map +0 -1
  377. package/dist/lib/use-page-size-preference.d.ts +0 -16
  378. package/dist/lib/use-page-size-preference.d.ts.map +0 -1
  379. package/dist/lib/use-page-size-preference.js +0 -15
  380. package/dist/lib/use-page-size-preference.js.map +0 -1
  381. package/dist/lib/use-unsaved-changes-prompt.d.ts +0 -17
  382. package/dist/lib/use-unsaved-changes-prompt.d.ts.map +0 -1
  383. package/dist/lib/use-unsaved-changes-prompt.js +0 -17
  384. package/dist/lib/use-unsaved-changes-prompt.js.map +0 -1
  385. package/dist/lib/utils.d.ts +0 -17
  386. package/dist/lib/utils.d.ts.map +0 -1
  387. package/dist/lib/utils.js +0 -17
  388. package/dist/lib/utils.js.map +0 -1
  389. package/dist/lib/uuid.d.ts +0 -17
  390. package/dist/lib/uuid.d.ts.map +0 -1
  391. package/dist/lib/uuid.js +0 -17
  392. package/dist/lib/uuid.js.map +0 -1
@@ -1,31 +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
6
  import { AdminFeedback } from './AdminFeedback.js';
7
7
  import { NavLink, Outlet, useLocation, useNavigate } from 'react-router-dom';
8
- import { BookOpen, Boxes, ChevronDown, ChevronRight, HelpCircle, Home as HomeIcon, Menu, LayoutDashboard, LogOut, PanelLeftClose, PanelLeftOpen, Search, Sparkles, } from 'lucide-react';
9
- import { useAuth } from '../lib/auth.js';
10
- import { cn } from '../lib/utils.js';
11
- import { useTranslation } from '../i18n/useTranslation.js';
12
- 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';
13
11
  import { registryNavFor, useAdminRegistry, } from '../lib/module-registry/index.js';
14
12
  import { LanguagePicker } from './LanguagePicker.js';
15
13
  import { RoleRequiredNotice } from './RoleRequiredNotice.js';
16
- import { useViewportTier } from './hooks/useViewportTier.js';
17
14
  import { NotificationBell } from './notifications/index.js';
18
15
  import { useAdminActions } from '../lib/admin-actions/useAdminActions.js';
19
- import { normalize } from '../lib/text-normalization.js';
20
- import { useModulePresence } from '../lib/module-presence/index.js';
16
+ import { matchesSearchTerms, searchTerms } from '../lib/palette-match.js';
21
17
  import { usePlatformVersion } from '../lib/platform-info/usePlatformVersion.js';
22
- import { useSurfaceVisibility, } from '../lib/surface-visibility.js';
23
- import { resolveIcon } from '../lib/admin-actions/icon-map.js';
24
18
  import { getPromptCapability, listUnseenPromptRequests } from '../lib/prompt-actions/api.js';
25
19
  import { PromptModePanel } from './prompt-actions/PromptModePanel.js';
26
20
  import { useGlobalSearch } from '../lib/global-search/useGlobalSearch.js';
27
- import { Badge } from './ui/badge.js';
21
+ import { Badge } from '@endora-commerce/admin-kit/ui';
28
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';
29
28
  /* Design-aligned navigation. The "Home" + "Orders" cluster sits above
30
29
  * the first labelled group exactly as the prototype shows. */
31
30
  const NAV = [
@@ -74,6 +73,16 @@ const NAV = [
74
73
  labelKey: 'appShell.section.crm',
75
74
  items: [],
76
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
+ },
77
86
  {
78
87
  key: 'catalog',
79
88
  labelKey: 'appShell.section.catalog',
@@ -319,61 +328,6 @@ const NAV = [
319
328
  ],
320
329
  },
321
330
  ];
322
- const STORAGE_KEY = 'b2b-admin.nav.collapsed-groups';
323
- const RAIL_STORAGE_KEY = 'b2b-admin.nav.rail-mode';
324
- /**
325
- * Rail (icon-only) mode persistence. The whole sidebar shrinks to a
326
- * 64px-wide column showing just icons; section labels disappear and
327
- * each section becomes a single icon (the first item's icon). Hovering
328
- * or clicking the icon reveals a popover with the section's items.
329
- */
330
- function loadRailMode() {
331
- if (typeof window === 'undefined')
332
- return false;
333
- try {
334
- return window.localStorage.getItem(RAIL_STORAGE_KEY) === '1';
335
- }
336
- catch {
337
- return false;
338
- }
339
- }
340
- function persistRailMode(value) {
341
- if (typeof window === 'undefined')
342
- return;
343
- try {
344
- window.localStorage.setItem(RAIL_STORAGE_KEY, value ? '1' : '0');
345
- }
346
- catch {
347
- /* ignore */
348
- }
349
- }
350
- function loadCollapsed() {
351
- if (typeof window === 'undefined')
352
- return new Set();
353
- try {
354
- const raw = window.localStorage.getItem(STORAGE_KEY);
355
- if (!raw)
356
- return new Set();
357
- const parsed = JSON.parse(raw);
358
- if (Array.isArray(parsed)) {
359
- return new Set(parsed.filter((v) => typeof v === 'string'));
360
- }
361
- }
362
- catch {
363
- /* ignore */
364
- }
365
- return new Set();
366
- }
367
- function persistCollapsed(value) {
368
- if (typeof window === 'undefined')
369
- return;
370
- try {
371
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(Array.from(value)));
372
- }
373
- catch {
374
- /* ignore */
375
- }
376
- }
377
331
  const CRUMB_DICT = [
378
332
  { test: /^\/$/, build: () => [{ labelKey: 'appShell.nav.home', href: null }] },
379
333
  // Six hand-written `/catalog*` trails stood here until feature 091's Phase 4
@@ -673,13 +627,19 @@ function buildCrumbs(pathname, composedNav) {
673
627
  * does type `zamówienia`; folding only the query breaks the one who does not.
674
628
  * (Postel's Law — accept what was typed and normalise it.)
675
629
  *
676
- * `needle` must already be normalised; the caller folds the query once per
677
- * 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
678
638
  * leading space matches what the operator meant rather than nothing at all
679
639
  * (issue #236).
680
640
  */
681
- function matchesQuery(needle, ...haystacks) {
682
- return haystacks.some((haystack) => normalize(haystack).includes(needle));
641
+ function matchesQuery(terms, ...haystacks) {
642
+ return matchesSearchTerms(terms, haystacks);
683
643
  }
684
644
  /**
685
645
  * The static Navigate group.
@@ -879,8 +839,12 @@ function useNavLabel() {
879
839
  const { t } = useTranslationContext();
880
840
  return useCallback((item) => t(item.labelScope ?? 'core', item.labelKey), [t]);
881
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
+ }
882
846
  export function AppShell() {
883
- const { me, logout, hasPermission } = useAuth();
847
+ const { me, logout } = useAuth();
884
848
  // The host's nav with every installed module's contributed entry folded in.
885
849
  const composedNav = useComposedNav();
886
850
  // Feature 073 — the effective enabled-set. A module that is off contributes
@@ -890,8 +854,13 @@ export function AppShell() {
890
854
  const isVisible = useSurfaceVisibility();
891
855
  const navigate = useNavigate();
892
856
  const location = useLocation();
893
- const [collapsed, setCollapsed] = useState(() => loadCollapsed());
894
- 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');
895
864
  const platformVersion = usePlatformVersion();
896
865
  const feedbackOffered = isModulePresent('admin_feedback');
897
866
  const [paletteOpen, setPaletteOpen] = useState(false);
@@ -900,13 +869,11 @@ export function AppShell() {
900
869
  const viewportTier = useViewportTier();
901
870
  const isMobile = viewportTier === 'mobile';
902
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;
903
874
  const toggleRailMode = useCallback(() => {
904
- setRailMode((prev) => {
905
- const next = !prev;
906
- persistRailMode(next);
907
- return next;
908
- });
909
- }, []);
875
+ setStoredRailMode(!storedRailMode);
876
+ }, [storedRailMode, setStoredRailMode]);
910
877
  const t = useTranslation('core');
911
878
  // The brand link's tooltip. With a release known it is the full sentence in
912
879
  // either mode: collapsed, the badge has no room and this is the only place
@@ -925,19 +892,27 @@ export function AppShell() {
925
892
  // The raw, scope-taking resolver, for the breadcrumb: a crumb a module
926
893
  // contributed resolves its label in that module's own namespace.
927
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]);
928
909
  const fullName = me ? `${me.adminUser.firstName} ${me.adminUser.lastName}`.trim() : '';
929
910
  const role = me?.role?.name ?? 'Admin';
930
911
  const toggleSection = useCallback((key) => {
931
- setCollapsed((prev) => {
932
- const next = new Set(prev);
933
- if (next.has(key))
934
- next.delete(key);
935
- else
936
- next.add(key);
937
- persistCollapsed(next);
938
- return next;
939
- });
940
- }, []);
912
+ setCollapsedGroups(collapsedGroups.includes(key)
913
+ ? collapsedGroups.filter((group) => group !== key)
914
+ : [...collapsedGroups, key]);
915
+ }, [collapsedGroups, setCollapsedGroups]);
941
916
  // ⌘K opens the palette anywhere in the admin; ⌘B toggles the
942
917
  // sidebar rail (matches the shadcn / VS Code shortcut convention).
943
918
  useEffect(() => {
@@ -966,59 +941,70 @@ export function AppShell() {
966
941
  }, [location.pathname]);
967
942
  const crumbs = useMemo(() => buildCrumbs(location.pathname, composedNav), [location.pathname, composedNav]);
968
943
  const isCmsRoute = location.pathname.startsWith('/cms');
969
- 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 || feedbackOffered ? (_jsxs("div", { className: "b2b-sidebar__version", children: [platformVersion !== null ? _jsx(VersionBadge, { version: platformVersion }) : null, feedbackOffered && !(railMode && !isMobile) ? _jsx(AdminFeedback, { rail: false }) : null] })) : null, feedbackOffered && railMode && !isMobile ? (_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') })] })) }), _jsx("nav", { className: "b2b-sidebar__nav", children: composedNav.map((section) => {
970
- const isOpen = !collapsed.has(section.key);
971
- // Permission-gate every entry, then presence-gate it (feature 073 /
972
- // FR-031). Sections with no remaining visible items fold away
973
- // entirely, which is what makes a whole domain disappear when every
974
- // module in it is off — the same behaviour restricted admins have
975
- // always had.
976
- //
977
- // Issue #230 — the predicate is `isSurfaceVisible`, shared with the
978
- // command palette and the dashboard quick actions. The palette used
979
- // to run a second, weaker copy of it; a shared helper is what stops
980
- // the three from disagreeing again.
981
- const visibleItems = section.items.filter(isVisible);
982
- if (visibleItems.length === 0)
983
- return null;
984
- // Feature 019 / 021 — section labels go through useTranslation('core').
985
- // The empty-labelKey "main" cluster keeps no label; every other
986
- // group resolves its declared `labelKey`. Polish strings live
987
- // in packages/modules/_i18n/i18n/pl.json under the same key.
988
- const translatedLabel = section.labelKey ? t(section.labelKey) : '';
989
- // In rail mode the section reduces to one icon (the first
990
- // visible item's icon). Hover or click reveals a popover
991
- // listing every visible item in the section.
992
- if (railMode) {
993
- return (_jsx(RailSection, { section: section, visibleItems: visibleItems, translatedLabel: translatedLabel }, section.key));
994
- }
995
- 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) => {
996
- const Icon = item.icon;
997
- // Force exact-match (`end`) when another item in the same
998
- // section nests under this item's path. Without this, a
999
- // parent route like `/inventory` lights up alongside its
1000
- // children (`/inventory/low-stock`, `/inventory/import`,
1001
- // …) because NavLink's default match is prefix-based.
1002
- // The home link (`/`) is the canonical example and is
1003
- // covered by the same rule (every other item starts with
1004
- // `/`).
1005
- const hasNestedSibling = section.items.some((other) => other !== item &&
1006
- other.to.startsWith(item.to === '/' ? '/' : `${item.to}/`));
1007
- 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));
1008
- }) })] }, section.key));
1009
- }) }), 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
1010
996
  ? `${fullName || me.adminUser.email} — ${t('appShell.profileMenu.profile')}`
1011
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
1012
998
  ? (t('appShell.sidebarToggle.expand') || 'Expand sidebar (⌘B)')
1013
999
  : (t('appShell.sidebarToggle.collapse') || 'Collapse sidebar (⌘B)'), "aria-label": railMode
1014
1000
  ? (t('appShell.sidebarToggle.expand') || 'Expand sidebar')
1015
- : (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) => {
1016
1002
  navigate(to);
1017
1003
  setPaletteOpen(false);
1018
1004
  } })] }));
1019
1005
  }
1020
1006
  function RailSection(props) {
1021
- const { section, visibleItems, translatedLabel } = props;
1007
+ const { section, visibleItems, translatedLabel, pinned } = props;
1022
1008
  const navLabel = useNavLabel();
1023
1009
  const [hover, setHover] = useState(false);
1024
1010
  const [sticky, setSticky] = useState(false);
@@ -1061,11 +1047,11 @@ function RailSection(props) {
1061
1047
  const railSource = visibleItems[0] ?? section.items[0];
1062
1048
  if (!railSource)
1063
1049
  return null;
1064
- const RailIcon = railSource.icon;
1050
+ const RailIcon = pinned?.icon ?? railSource.icon;
1065
1051
  const headerLabel = translatedLabel || (visibleItems[0] ? navLabel(visibleItems[0]) : '');
1066
1052
  // Single-item section: render a plain link with no popover. The
1067
1053
  // hover area is the link itself; tooltip carries the label.
1068
- if (visibleItems.length === 1) {
1054
+ if (visibleItems.length === 1 && pinned === undefined) {
1069
1055
  const only = visibleItems[0];
1070
1056
  const Icon = only.icon;
1071
1057
  const onlyLabel = navLabel(only);
@@ -1074,7 +1060,14 @@ function RailSection(props) {
1074
1060
  return (_jsxs("div", { ref: wrapperRef, className: "b2b-sidebar__rail-row", onMouseEnter: () => {
1075
1061
  cancelClose();
1076
1062
  setHover(true);
1077
- }, 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) => {
1078
1071
  const Icon = item.icon;
1079
1072
  const hasNestedSibling = visibleItems.some((other) => other !== item &&
1080
1073
  other.to.startsWith(item.to === '/' ? '/' : `${item.to}/`));
@@ -1084,6 +1077,8 @@ function RailSection(props) {
1084
1077
  }, children: [_jsx(Icon, { size: 14 }), _jsx("span", { children: navLabel(item) })] }, item.to));
1085
1078
  })] })) : null] }));
1086
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+↵';
1087
1082
  /** Sentinel route for the assistant entry row — switches the palette mode
1088
1083
  * instead of navigating (feature 043; module_actions are navigation-only). */
1089
1084
  const PROMPT_MODE_SENTINEL = '__prompt_actions_mode__';
@@ -1106,8 +1101,14 @@ export function resetPromptCapabilityCacheForTesting() {
1106
1101
  promptCapabilityCache = null;
1107
1102
  }
1108
1103
  function CommandPalette(props) {
1109
- const { open, onClose, onNavigate } = props;
1104
+ const { open, onClose, onNavigate, pinTargets } = props;
1110
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();
1111
1112
  const tp = useTranslation('prompt_actions');
1112
1113
  const { hasPermission } = useAuth();
1113
1114
  const isVisible = useSurfaceVisibility();
@@ -1251,7 +1252,7 @@ function CommandPalette(props) {
1251
1252
  if (!query.trim())
1252
1253
  return [...assistantItems, ...navigateItems, ...actionItems];
1253
1254
  // Folded once here, then compared against every row — see `matchesQuery`.
1254
- const q = normalize(query);
1255
+ const q = searchTerms(query);
1255
1256
  const filteredAssistant = assistantItems.filter((i) => matchesQuery(q, i.label, i.sub, i.keywords));
1256
1257
  // Navigate group: filter against the *translated* label + sub plus
1257
1258
  // the raw keywords list so a Polish user can search in Polish and
@@ -1263,6 +1264,17 @@ function CommandPalette(props) {
1263
1264
  // eslint-disable-next-line react-hooks/exhaustive-deps
1264
1265
  }, [query, actionItems, assistantItems, navigateItems, recordItems]);
1265
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]);
1266
1278
  // Activating the assistant row switches the palette body instead of
1267
1279
  // navigating (feature 043); everything else keeps the navigation path.
1268
1280
  const activate = useCallback((to) => {
@@ -1292,6 +1304,7 @@ function CommandPalette(props) {
1292
1304
  }, [query, open]);
1293
1305
  useEffect(() => {
1294
1306
  if (!open) {
1307
+ setPinAnnouncement('');
1295
1308
  setQuery('');
1296
1309
  setMode('search');
1297
1310
  setInitialRequest(undefined);
@@ -1323,6 +1336,14 @@ function CommandPalette(props) {
1323
1336
  e.preventDefault();
1324
1337
  setCursor((c) => Math.max(0, c - 1));
1325
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
+ }
1326
1347
  else if (e.key === 'Enter') {
1327
1348
  e.preventDefault();
1328
1349
  const it = items[cursor];
@@ -1335,7 +1356,7 @@ function CommandPalette(props) {
1335
1356
  };
1336
1357
  window.addEventListener('keydown', onKey);
1337
1358
  return () => window.removeEventListener('keydown', onKey);
1338
- }, [open, mode, items, cursor, onClose, activate]);
1359
+ }, [open, mode, items, cursor, onClose, activate, pinTargetOf, togglePinOf]);
1339
1360
  if (!open)
1340
1361
  return null;
1341
1362
  if (mode === 'prompt') {
@@ -1358,14 +1379,27 @@ function CommandPalette(props) {
1358
1379
  const Icon = it.icon;
1359
1380
  const label = resolveLabel(it);
1360
1381
  const sub = resolveSub(it);
1361
- 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}`));
1362
1396
  };
1363
1397
  let lastGroup = '';
1364
1398
  let recordIndex = firstRecordIndex;
1365
- 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) => {
1366
1400
  setQuery((q) => (q ? `${q} ${text}` : text));
1367
1401
  inputRef.current?.focus();
1368
- } }), _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'
1369
1403
  ? t('appShell.palette.records.announce', { count: recordCount })
1370
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: () => {
1371
1405
  setInitialRequest(unseen[0]);