@eifi1/ui-kit 0.51.7 → 0.52.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 (746) hide show
  1. package/README.md +141 -23
  2. package/dist/account/account-parts.d.ts +10 -8
  3. package/dist/account/account-parts.js +1 -18
  4. package/dist/account/account-parts.js.map +1 -1
  5. package/dist/account/data-export-setting-labels.js +1 -1
  6. package/dist/account/data-export-setting-labels.js.map +1 -1
  7. package/dist/account/delete-account-setting-labels.js +1 -1
  8. package/dist/account/delete-account-setting-labels.js.map +1 -1
  9. package/dist/account/email-change-setting-labels.js +1 -1
  10. package/dist/account/email-change-setting-labels.js.map +1 -1
  11. package/dist/account/passkeys-setting.d.ts +9 -2
  12. package/dist/account/passkeys-setting.js +41 -29
  13. package/dist/account/passkeys-setting.js.map +1 -1
  14. package/dist/account/sessions-setting.d.ts +3 -2
  15. package/dist/account/sessions-setting.js +10 -8
  16. package/dist/account/sessions-setting.js.map +1 -1
  17. package/dist/admin/admin-action-confirm.js +1 -3
  18. package/dist/admin/admin-action-confirm.js.map +1 -1
  19. package/dist/admin/admin-parts.d.ts +6 -3
  20. package/dist/admin/admin-parts.js +6 -21
  21. package/dist/admin/admin-parts.js.map +1 -1
  22. package/dist/admin/mail-test-card-labels.js +1 -1
  23. package/dist/admin/mail-test-card-labels.js.map +1 -1
  24. package/dist/admin/plan-change-labels.d.ts +2 -2
  25. package/dist/admin/plan-change-labels.js +1 -17
  26. package/dist/admin/plan-change-labels.js.map +1 -1
  27. package/dist/admin/plan-change.d.ts +3 -42
  28. package/dist/admin/plan-change.js +1 -1
  29. package/dist/admin/plan-change.js.map +1 -1
  30. package/dist/admin/reviewer-scope-editor.js +3 -3
  31. package/dist/admin/reviewer-scope-editor.js.map +1 -1
  32. package/dist/auth/auth-errors-labels.d.ts +11 -0
  33. package/dist/auth/auth-errors-labels.js +13 -0
  34. package/dist/auth/auth-errors-labels.js.map +1 -0
  35. package/dist/auth/auth-errors.d.ts +7 -23
  36. package/dist/auth/auth-errors.js +2 -15
  37. package/dist/auth/auth-errors.js.map +1 -1
  38. package/dist/auth/complete-name-dialog.js +2 -1
  39. package/dist/auth/complete-name-dialog.js.map +1 -1
  40. package/dist/auth/forgot-password-form-labels.js +1 -1
  41. package/dist/auth/forgot-password-form-labels.js.map +1 -1
  42. package/dist/auth/forgot-password-form.js +7 -2
  43. package/dist/auth/forgot-password-form.js.map +1 -1
  44. package/dist/auth/register-form-labels.js +1 -1
  45. package/dist/auth/register-form-labels.js.map +1 -1
  46. package/dist/auth/reset-password-form-labels.js +1 -1
  47. package/dist/auth/reset-password-form-labels.js.map +1 -1
  48. package/dist/auth/reset-password-form.js +5 -1
  49. package/dist/auth/reset-password-form.js.map +1 -1
  50. package/dist/auth/sign-in-form-labels.js +1 -1
  51. package/dist/auth/sign-in-form-labels.js.map +1 -1
  52. package/dist/auth/status-parts.d.ts +0 -3
  53. package/dist/auth/status-parts.js +0 -4
  54. package/dist/auth/status-parts.js.map +1 -1
  55. package/dist/auth/verify-email-labels.js +1 -1
  56. package/dist/auth/verify-email-labels.js.map +1 -1
  57. package/dist/auth/verify-email.js +7 -2
  58. package/dist/auth/verify-email.js.map +1 -1
  59. package/dist/billing/cancel-subscription.d.ts +20 -8
  60. package/dist/billing/cancel-subscription.js +7 -5
  61. package/dist/billing/cancel-subscription.js.map +1 -1
  62. package/dist/billing/dialog-close.d.ts +29 -0
  63. package/dist/billing/dialog-close.js +8 -0
  64. package/dist/billing/dialog-close.js.map +1 -0
  65. package/dist/billing/plan-card.d.ts +14 -4
  66. package/dist/billing/plan-card.js +15 -8
  67. package/dist/billing/plan-card.js.map +1 -1
  68. package/dist/billing/plan-change-labels.d.ts +42 -0
  69. package/dist/billing/plan-change-labels.js +22 -0
  70. package/dist/billing/plan-change-labels.js.map +1 -0
  71. package/dist/billing/plan-switch.d.ts +19 -7
  72. package/dist/billing/plan-switch.js +8 -4
  73. package/dist/billing/plan-switch.js.map +1 -1
  74. package/dist/chart.d.ts +12 -0
  75. package/dist/chart.js +16 -1
  76. package/dist/chart.js.map +1 -1
  77. package/dist/components/account-chips.d.ts +5 -5
  78. package/dist/components/account-chips.js +11 -13
  79. package/dist/components/account-chips.js.map +1 -1
  80. package/dist/components/alert-banner.d.ts +16 -5
  81. package/dist/components/alert-banner.js +46 -1
  82. package/dist/components/alert-banner.js.map +1 -1
  83. package/dist/components/amount-input.d.ts +13 -0
  84. package/dist/components/amount-input.js +1 -0
  85. package/dist/components/amount-input.js.map +1 -1
  86. package/dist/components/autocomplete.js +57 -65
  87. package/dist/components/autocomplete.js.map +1 -1
  88. package/dist/components/bulk-action-bar.d.ts +12 -2
  89. package/dist/components/bulk-action-bar.js +65 -21
  90. package/dist/components/bulk-action-bar.js.map +1 -1
  91. package/dist/components/button-look.d.ts +5 -5
  92. package/dist/components/button-look.js.map +1 -1
  93. package/dist/components/button.d.ts +2 -2
  94. package/dist/components/button.js.map +1 -1
  95. package/dist/components/chart-edge.d.ts +16 -0
  96. package/dist/components/chart-edge.js +14 -1
  97. package/dist/components/chart-edge.js.map +1 -1
  98. package/dist/components/chart-figure.d.ts +13 -0
  99. package/dist/components/chart-figure.js +15 -0
  100. package/dist/components/chart-figure.js.map +1 -0
  101. package/dist/components/chart-zoom-core.js +1 -4
  102. package/dist/components/chart-zoom-core.js.map +1 -1
  103. package/dist/components/chart.d.ts +8 -1
  104. package/dist/components/chart.js +19 -10
  105. package/dist/components/chart.js.map +1 -1
  106. package/dist/components/combobox-core.d.ts +111 -2
  107. package/dist/components/combobox-core.js +148 -42
  108. package/dist/components/combobox-core.js.map +1 -1
  109. package/dist/components/combobox.d.ts +1 -1
  110. package/dist/components/combobox.js +141 -130
  111. package/dist/components/combobox.js.map +1 -1
  112. package/dist/components/copy-button.d.ts +6 -5
  113. package/dist/components/copy-button.js +5 -3
  114. package/dist/components/copy-button.js.map +1 -1
  115. package/dist/components/country-select.js +2 -2
  116. package/dist/components/country-select.js.map +1 -1
  117. package/dist/components/data-table-column-settings.d.ts +1 -1
  118. package/dist/components/data-table-column-settings.js +33 -7
  119. package/dist/components/data-table-column-settings.js.map +1 -1
  120. package/dist/components/data-table-filters.d.ts +4 -2
  121. package/dist/components/data-table-filters.js +2 -2
  122. package/dist/components/data-table-filters.js.map +1 -1
  123. package/dist/components/data-table-fit.d.ts +6 -4
  124. package/dist/components/data-table-fit.js +4 -1
  125. package/dist/components/data-table-fit.js.map +1 -1
  126. package/dist/components/data-table-groups.d.ts +1 -1
  127. package/dist/components/data-table-groups.js.map +1 -1
  128. package/dist/components/data-table-head.d.ts +1 -1
  129. package/dist/components/data-table-head.js +15 -12
  130. package/dist/components/data-table-head.js.map +1 -1
  131. package/dist/components/data-table-mobile.d.ts +12 -7
  132. package/dist/components/data-table-mobile.js +43 -30
  133. package/dist/components/data-table-mobile.js.map +1 -1
  134. package/dist/components/data-table-pagination.js +11 -6
  135. package/dist/components/data-table-pagination.js.map +1 -1
  136. package/dist/components/data-table-resize.d.ts +1 -1
  137. package/dist/components/data-table-resize.js.map +1 -1
  138. package/dist/components/data-table-row-actions.d.ts +2 -2
  139. package/dist/components/data-table-row-actions.js.map +1 -1
  140. package/dist/components/data-table-row.d.ts +6 -2
  141. package/dist/components/data-table-row.js +17 -10
  142. package/dist/components/data-table-row.js.map +1 -1
  143. package/dist/components/data-table-selection.d.ts +1 -1
  144. package/dist/components/data-table-selection.js.map +1 -1
  145. package/dist/components/data-table-shared.d.ts +10 -2
  146. package/dist/components/data-table-shared.js +18 -0
  147. package/dist/components/data-table-shared.js.map +1 -1
  148. package/dist/components/data-table-sort.d.ts +21 -2
  149. package/dist/components/data-table-sort.js +24 -0
  150. package/dist/components/data-table-sort.js.map +1 -1
  151. package/dist/components/data-table-virtual.d.ts +1 -1
  152. package/dist/components/data-table-virtual.js +18 -6
  153. package/dist/components/data-table-virtual.js.map +1 -1
  154. package/dist/components/data-table.d.ts +13 -4
  155. package/dist/components/data-table.js +139 -36
  156. package/dist/components/data-table.js.map +1 -1
  157. package/dist/components/date-field.d.ts +24 -2
  158. package/dist/components/date-field.js +33 -8
  159. package/dist/components/date-field.js.map +1 -1
  160. package/dist/components/date-picker.d.ts +15 -2
  161. package/dist/components/date-picker.js +55 -26
  162. package/dist/components/date-picker.js.map +1 -1
  163. package/dist/components/date-range-picker.d.ts +47 -20
  164. package/dist/components/date-range-picker.js +23 -7
  165. package/dist/components/date-range-picker.js.map +1 -1
  166. package/dist/components/error-boundary.js +37 -30
  167. package/dist/components/error-boundary.js.map +1 -1
  168. package/dist/components/{ui-labels.d.ts → field-base-labels.d.ts} +0 -2
  169. package/dist/components/{ui-labels.js → field-base-labels.js} +2 -9
  170. package/dist/components/field-base-labels.js.map +1 -0
  171. package/dist/components/field-base.d.ts +4 -3
  172. package/dist/components/field-base.js +3 -3
  173. package/dist/components/field-base.js.map +1 -1
  174. package/dist/components/field-sync-labels.d.ts +1 -0
  175. package/dist/components/field-sync-labels.js.map +1 -1
  176. package/dist/components/field-sync.d.ts +23 -1
  177. package/dist/components/field-sync.js.map +1 -1
  178. package/dist/components/form-actions.js +11 -5
  179. package/dist/components/form-actions.js.map +1 -1
  180. package/dist/components/hover-menu.d.ts +3 -0
  181. package/dist/components/hover-menu.js +5 -3
  182. package/dist/components/hover-menu.js.map +1 -1
  183. package/dist/components/icon-button.js +14 -9
  184. package/dist/components/icon-button.js.map +1 -1
  185. package/dist/components/inline-confirm.d.ts +43 -0
  186. package/dist/components/inline-confirm.js +67 -0
  187. package/dist/components/inline-confirm.js.map +1 -0
  188. package/dist/components/inline-entity-combobox.d.ts +4 -3
  189. package/dist/components/inline-entity-combobox.js +148 -140
  190. package/dist/components/inline-entity-combobox.js.map +1 -1
  191. package/dist/components/input.js +1 -1
  192. package/dist/components/input.js.map +1 -1
  193. package/dist/components/jump-calendar.js +28 -112
  194. package/dist/components/jump-calendar.js.map +1 -1
  195. package/dist/components/legal-page.d.ts +3 -1
  196. package/dist/components/legal-page.js +3 -2
  197. package/dist/components/legal-page.js.map +1 -1
  198. package/dist/components/legal.d.ts +4 -2
  199. package/dist/components/legal.js.map +1 -1
  200. package/dist/components/lightbox.d.ts +2 -2
  201. package/dist/components/lightbox.js +17 -6
  202. package/dist/components/lightbox.js.map +1 -1
  203. package/dist/components/list.d.ts +6 -2
  204. package/dist/components/list.js +3 -2
  205. package/dist/components/list.js.map +1 -1
  206. package/dist/components/measured-grid.d.ts +1 -1
  207. package/dist/components/measured-grid.js +2 -1
  208. package/dist/components/measured-grid.js.map +1 -1
  209. package/dist/components/mini-calendar.js +3 -5
  210. package/dist/components/mini-calendar.js.map +1 -1
  211. package/dist/components/modal.js +3 -1
  212. package/dist/components/modal.js.map +1 -1
  213. package/dist/components/month-grid.d.ts +55 -0
  214. package/dist/components/month-grid.js +148 -0
  215. package/dist/components/month-grid.js.map +1 -0
  216. package/dist/components/month-picker.d.ts +36 -4
  217. package/dist/components/month-picker.js +123 -146
  218. package/dist/components/month-picker.js.map +1 -1
  219. package/dist/components/multi-select.d.ts +2 -2
  220. package/dist/components/multi-select.js +11 -6
  221. package/dist/components/multi-select.js.map +1 -1
  222. package/dist/components/picker-sheet.js +2 -1
  223. package/dist/components/picker-sheet.js.map +1 -1
  224. package/dist/components/pie-chart-labels.d.ts +7 -0
  225. package/dist/components/pie-chart-labels.js +1 -0
  226. package/dist/components/pie-chart-labels.js.map +1 -1
  227. package/dist/components/pie-chart.d.ts +5 -3
  228. package/dist/components/pie-chart.js +7 -22
  229. package/dist/components/pie-chart.js.map +1 -1
  230. package/dist/components/popover.d.ts +3 -0
  231. package/dist/components/popover.js +7 -1
  232. package/dist/components/popover.js.map +1 -1
  233. package/dist/components/row-actions.js +2 -1
  234. package/dist/components/row-actions.js.map +1 -1
  235. package/dist/components/section-nav.d.ts +7 -0
  236. package/dist/components/section-nav.js.map +1 -1
  237. package/dist/components/series-chart-axes.d.ts +3 -3
  238. package/dist/components/series-chart-axes.js.map +1 -1
  239. package/dist/components/series-chart-labels.d.ts +7 -4
  240. package/dist/components/series-chart-labels.js.map +1 -1
  241. package/dist/components/series-chart.d.ts +31 -7
  242. package/dist/components/series-chart.js +72 -29
  243. package/dist/components/series-chart.js.map +1 -1
  244. package/dist/components/share-card.js +3 -3
  245. package/dist/components/share-card.js.map +1 -1
  246. package/dist/components/sign-chip-labels.d.ts +1 -0
  247. package/dist/components/sign-chip-labels.js.map +1 -1
  248. package/dist/components/sign-chip.d.ts +10 -1
  249. package/dist/components/sign-chip.js.map +1 -1
  250. package/dist/components/tabs-labels.d.ts +2 -0
  251. package/dist/components/tabs-labels.js +11 -0
  252. package/dist/components/tabs-labels.js.map +1 -0
  253. package/dist/components/tabs.d.ts +1 -1
  254. package/dist/components/tabs.js +1 -1
  255. package/dist/components/tabs.js.map +1 -1
  256. package/dist/components/toggle-legend.d.ts +2 -2
  257. package/dist/components/toggle-legend.js +6 -6
  258. package/dist/components/toggle-legend.js.map +1 -1
  259. package/dist/components/translation-review-editor.d.ts +4 -2
  260. package/dist/components/translation-review-editor.js +2 -3
  261. package/dist/components/translation-review-editor.js.map +1 -1
  262. package/dist/components/translation-review.d.ts +2 -1
  263. package/dist/components/translation-review.js +2 -2
  264. package/dist/components/translation-review.js.map +1 -1
  265. package/dist/components/treemap-labels.d.ts +26 -0
  266. package/dist/components/treemap-labels.js +10 -0
  267. package/dist/components/treemap-labels.js.map +1 -0
  268. package/dist/components/treemap-layout.d.ts +62 -0
  269. package/dist/components/treemap-layout.js +126 -0
  270. package/dist/components/treemap-layout.js.map +1 -0
  271. package/dist/components/treemap.d.ts +140 -17
  272. package/dist/components/treemap.js +324 -97
  273. package/dist/components/treemap.js.map +1 -1
  274. package/dist/components/use-table-state.d.ts +5 -5
  275. package/dist/components/use-table-state.js +4 -1
  276. package/dist/components/use-table-state.js.map +1 -1
  277. package/dist/data-table.d.ts +6 -2
  278. package/dist/data-table.js +7 -2
  279. package/dist/data-table.js.map +1 -1
  280. package/dist/eslint/index.js +1 -1
  281. package/dist/eslint/role-utilities.d.ts +36 -7
  282. package/dist/eslint/role-utilities.js +42 -9
  283. package/dist/eslint/role-utilities.js.map +1 -1
  284. package/dist/feedback/feedback-dialog.d.ts +25 -16
  285. package/dist/feedback/feedback-dialog.js +6 -2
  286. package/dist/feedback/feedback-dialog.js.map +1 -1
  287. package/dist/feedback/feedback-mutation.d.ts +30 -0
  288. package/dist/feedback/feedback-mutation.js +16 -0
  289. package/dist/feedback/feedback-mutation.js.map +1 -0
  290. package/dist/feedback/feedback-page-link.d.ts +53 -0
  291. package/dist/feedback/feedback-page-link.js +37 -0
  292. package/dist/feedback/feedback-page-link.js.map +1 -0
  293. package/dist/feedback/feedback-public-list.d.ts +12 -3
  294. package/dist/feedback/feedback-public-list.js +2 -1
  295. package/dist/feedback/feedback-public-list.js.map +1 -1
  296. package/dist/feedback/feedback-replies.d.ts +3 -1
  297. package/dist/feedback/feedback-replies.js +5 -4
  298. package/dist/feedback/feedback-replies.js.map +1 -1
  299. package/dist/feedback/feedback-row-detail-labels.js +5 -0
  300. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  301. package/dist/feedback/feedback-row-detail.d.ts +64 -28
  302. package/dist/feedback/feedback-row-detail.js +30 -28
  303. package/dist/feedback/feedback-row-detail.js.map +1 -1
  304. package/dist/feedback/feedback-status-undo.d.ts +30 -11
  305. package/dist/feedback/feedback-status-undo.js +10 -15
  306. package/dist/feedback/feedback-status-undo.js.map +1 -1
  307. package/dist/feedback/feedback-submit-dialog.d.ts +1 -1
  308. package/dist/feedback/feedback-submit-dialog.js +1 -1
  309. package/dist/feedback/feedback-submit-dialog.js.map +1 -1
  310. package/dist/feedback/feedback-submit.js +9 -3
  311. package/dist/feedback/feedback-submit.js.map +1 -1
  312. package/dist/feedback/feedback-swipe.d.ts +1 -1
  313. package/dist/feedback/feedback-swipe.js.map +1 -1
  314. package/dist/feedback/feedback-table.d.ts +21 -9
  315. package/dist/feedback/feedback-table.js +45 -25
  316. package/dist/feedback/feedback-table.js.map +1 -1
  317. package/dist/feedback/feedback-thread-labels.d.ts +2 -2
  318. package/dist/feedback/feedback-thread-labels.js.map +1 -1
  319. package/dist/feedback/feedback-thread.d.ts +24 -23
  320. package/dist/feedback/feedback-thread.js +2 -1
  321. package/dist/feedback/feedback-thread.js.map +1 -1
  322. package/dist/feedback.d.ts +34 -0
  323. package/dist/feedback.js +42 -0
  324. package/dist/feedback.js.map +1 -1
  325. package/dist/hooks/use-focus-trap.d.ts +35 -0
  326. package/dist/hooks/use-focus-trap.js +6 -4
  327. package/dist/hooks/use-focus-trap.js.map +1 -1
  328. package/dist/hooks/use-hotkey.d.ts +5 -2
  329. package/dist/hooks/use-hotkey.js +5 -4
  330. package/dist/hooks/use-hotkey.js.map +1 -1
  331. package/dist/hooks/use-long-press.d.ts +7 -4
  332. package/dist/hooks/use-long-press.js +3 -0
  333. package/dist/hooks/use-long-press.js.map +1 -1
  334. package/dist/hooks/use-media-query.js +12 -4
  335. package/dist/hooks/use-media-query.js.map +1 -1
  336. package/dist/hooks/use-mounted.d.ts +22 -0
  337. package/dist/hooks/use-mounted.js +24 -0
  338. package/dist/hooks/use-mounted.js.map +1 -0
  339. package/dist/hooks/use-overlay-history.js +19 -3
  340. package/dist/hooks/use-overlay-history.js.map +1 -1
  341. package/dist/i18n/defaults.js +4 -5
  342. package/dist/i18n/defaults.js.map +1 -1
  343. package/dist/i18n/german.js +7 -1
  344. package/dist/i18n/german.js.map +1 -1
  345. package/dist/i18n/kit-labels.d.ts +9 -2
  346. package/dist/i18n/kit-labels.js.map +1 -1
  347. package/dist/i18n/locales/en.js +20 -41
  348. package/dist/i18n/locales/en.js.map +3 -3
  349. package/dist/i18n/locales/es.js +7 -1
  350. package/dist/i18n/locales/es.js.map +1 -1
  351. package/dist/i18n/locales/fr.js +20 -10
  352. package/dist/i18n/locales/fr.js.map +1 -1
  353. package/dist/i18n/locales/hu.js +9 -1
  354. package/dist/i18n/locales/hu.js.map +1 -1
  355. package/dist/i18n/locales/it.js +7 -1
  356. package/dist/i18n/locales/it.js.map +1 -1
  357. package/dist/i18n/locales/zh.js +8 -1
  358. package/dist/i18n/locales/zh.js.map +1 -1
  359. package/dist/i18n/review.js +5 -0
  360. package/dist/i18n/review.js.map +1 -1
  361. package/dist/index.d.ts +64 -17
  362. package/dist/index.js +77 -12
  363. package/dist/index.js.map +1 -1
  364. package/dist/landing/routing.d.ts +3 -1
  365. package/dist/landing/routing.js +4 -7
  366. package/dist/landing/routing.js.map +1 -1
  367. package/dist/lib/broadcast.d.ts +17 -0
  368. package/dist/lib/broadcast.js +30 -0
  369. package/dist/lib/broadcast.js.map +1 -0
  370. package/dist/lib/date-format.d.ts +37 -2
  371. package/dist/lib/date-format.js +34 -8
  372. package/dist/lib/date-format.js.map +1 -1
  373. package/dist/lib/day-format.d.ts +46 -0
  374. package/dist/lib/day-format.js +46 -0
  375. package/dist/lib/day-format.js.map +1 -0
  376. package/dist/lib/describe-failure.d.ts +14 -0
  377. package/dist/lib/describe-failure.js +9 -0
  378. package/dist/lib/describe-failure.js.map +1 -0
  379. package/dist/lib/direction.d.ts +16 -0
  380. package/dist/lib/direction.js +9 -1
  381. package/dist/lib/direction.js.map +1 -1
  382. package/dist/lib/focus-left.d.ts +63 -0
  383. package/dist/lib/focus-left.js +67 -0
  384. package/dist/lib/focus-left.js.map +1 -0
  385. package/dist/lib/format.js +5 -14
  386. package/dist/lib/format.js.map +1 -1
  387. package/dist/lib/http-status.d.ts +24 -0
  388. package/dist/lib/http-status.js +14 -0
  389. package/dist/lib/http-status.js.map +1 -0
  390. package/dist/lib/intl-cache.d.ts +14 -0
  391. package/dist/lib/intl-cache.js +15 -0
  392. package/dist/lib/intl-cache.js.map +1 -0
  393. package/dist/lib/isin.d.ts +10 -0
  394. package/dist/lib/isin.js.map +1 -1
  395. package/dist/lib/iso-day.d.ts +11 -0
  396. package/dist/lib/iso-day.js +8 -0
  397. package/dist/lib/iso-day.js.map +1 -0
  398. package/dist/lib/lazy-with-fallback.d.ts +31 -0
  399. package/dist/lib/lazy-with-fallback.js +40 -0
  400. package/dist/lib/lazy-with-fallback.js.map +1 -0
  401. package/dist/lib/path-pattern.d.ts +34 -0
  402. package/dist/lib/path-pattern.js +24 -0
  403. package/dist/lib/path-pattern.js.map +1 -0
  404. package/dist/lib/reduced-motion.d.ts +2 -1
  405. package/dist/lib/reduced-motion.js.map +1 -1
  406. package/dist/lib/round.d.ts +2 -1
  407. package/dist/lib/round.js +2 -1
  408. package/dist/lib/round.js.map +1 -1
  409. package/dist/lib/safe-storage.d.ts +24 -5
  410. package/dist/lib/safe-storage.js +27 -2
  411. package/dist/lib/safe-storage.js.map +1 -1
  412. package/dist/lib/session-refresh.js +1 -1
  413. package/dist/lib/session-refresh.js.map +1 -1
  414. package/dist/lib/share-format.d.ts +13 -0
  415. package/dist/lib/share-format.js +10 -0
  416. package/dist/lib/share-format.js.map +1 -0
  417. package/dist/lib/text-case.d.ts +17 -0
  418. package/dist/lib/text-case.js +8 -0
  419. package/dist/lib/text-case.js.map +1 -0
  420. package/dist/lib/text-match.d.ts +29 -0
  421. package/dist/lib/text-match.js +20 -2
  422. package/dist/lib/text-match.js.map +1 -1
  423. package/dist/lib/thenable.d.ts +13 -0
  424. package/dist/lib/thenable.js +8 -0
  425. package/dist/lib/thenable.js.map +1 -0
  426. package/dist/lib/translation-review.d.ts +7 -2
  427. package/dist/lib/translation-review.js +4 -4
  428. package/dist/lib/translation-review.js.map +1 -1
  429. package/dist/notifications/device-zone-report.js +1 -1
  430. package/dist/notifications/device-zone-report.js.map +1 -1
  431. package/dist/notifications/notification-bell.d.ts +2 -1
  432. package/dist/notifications/notification-bell.js +3 -3
  433. package/dist/notifications/notification-bell.js.map +1 -1
  434. package/dist/notifications/notification-inbox.d.ts +10 -6
  435. package/dist/notifications/notification-inbox.js +26 -48
  436. package/dist/notifications/notification-inbox.js.map +1 -1
  437. package/dist/notifications/notification-parts.d.ts +3 -2
  438. package/dist/notifications/notification-parts.js +1 -3
  439. package/dist/notifications/notification-parts.js.map +1 -1
  440. package/dist/notifications/notification-types-setting.js +1 -1
  441. package/dist/notifications/notification-types-setting.js.map +1 -1
  442. package/dist/notifications/notifications-labels.d.ts +6 -0
  443. package/dist/notifications/notifications-labels.js +1 -0
  444. package/dist/notifications/notifications-labels.js.map +1 -1
  445. package/dist/notifications/push-device-setting.js +1 -1
  446. package/dist/notifications/push-device-setting.js.map +1 -1
  447. package/dist/notifications/push-devices-setting.d.ts +2 -1
  448. package/dist/notifications/push-devices-setting.js +27 -49
  449. package/dist/notifications/push-devices-setting.js.map +1 -1
  450. package/dist/notifications/quiet-hours-setting.d.ts +10 -3
  451. package/dist/notifications/quiet-hours-setting.js +65 -26
  452. package/dist/notifications/quiet-hours-setting.js.map +1 -1
  453. package/dist/notifications/unsubscribe-panel.js +4 -7
  454. package/dist/notifications/unsubscribe-panel.js.map +1 -1
  455. package/dist/notifications/use-push-device.d.ts +39 -1
  456. package/dist/notifications/use-push-device.js +28 -7
  457. package/dist/notifications/use-push-device.js.map +1 -1
  458. package/dist/offline/query-persistence.d.ts +3 -1
  459. package/dist/offline/query-persistence.js +19 -2
  460. package/dist/offline/query-persistence.js.map +1 -1
  461. package/dist/rhf/fields.d.ts +11 -4
  462. package/dist/rhf/fields.js.map +1 -1
  463. package/dist/search/command-palette.js +1 -1
  464. package/dist/search/command-palette.js.map +1 -1
  465. package/dist/search/global-search.js +19 -9
  466. package/dist/search/global-search.js.map +1 -1
  467. package/dist/search/use-command-key.d.ts +12 -1
  468. package/dist/search/use-command-key.js +3 -12
  469. package/dist/search/use-command-key.js.map +1 -1
  470. package/dist/search.d.ts +7 -0
  471. package/dist/search.js +10 -0
  472. package/dist/search.js.map +1 -1
  473. package/dist/settings/use-settings-focus.js +1 -0
  474. package/dist/settings/use-settings-focus.js.map +1 -1
  475. package/dist/shell/account-menu-language.d.ts +21 -5
  476. package/dist/shell/account-menu-language.js +3 -1
  477. package/dist/shell/account-menu-language.js.map +1 -1
  478. package/dist/shell/account-menu-text-size.d.ts +26 -9
  479. package/dist/shell/account-menu-text-size.js +3 -2
  480. package/dist/shell/account-menu-text-size.js.map +1 -1
  481. package/dist/shell/dev-menu.js +5 -18
  482. package/dist/shell/dev-menu.js.map +1 -1
  483. package/dist/shell/role-switcher.d.ts +7 -0
  484. package/dist/shell/role-switcher.js.map +1 -1
  485. package/dist/shell/top-bar-actions.d.ts +1 -1
  486. package/dist/shell/top-bar-actions.js.map +1 -1
  487. package/dist/shell/top-bar-parts-labels.d.ts +0 -2
  488. package/dist/shell/top-bar-parts-labels.js +0 -1
  489. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  490. package/dist/shell.d.ts +27 -8
  491. package/dist/shell.js +28 -7
  492. package/dist/shell.js.map +1 -1
  493. package/dist/sync/engine.d.ts +30 -4
  494. package/dist/sync/engine.js +172 -52
  495. package/dist/sync/engine.js.map +1 -1
  496. package/dist/sync.d.ts +6 -2
  497. package/dist/sync.js +6 -1
  498. package/dist/sync.js.map +1 -1
  499. package/dist/testing/css-variables.js +3 -8
  500. package/dist/testing/css-variables.js.map +1 -1
  501. package/dist/theme/contrast.d.ts +2 -1
  502. package/dist/theme/contrast.js +3 -8
  503. package/dist/theme/contrast.js.map +1 -1
  504. package/dist/theme/palette-store.js +6 -6
  505. package/dist/theme/palette-store.js.map +1 -1
  506. package/dist/theme/text-size.js +3 -8
  507. package/dist/theme/text-size.js.map +1 -1
  508. package/dist/theme/theme-store.js +3 -6
  509. package/dist/theme/theme-store.js.map +1 -1
  510. package/dist/tour/tour-catalogue.d.ts +7 -4
  511. package/dist/tour/tour-catalogue.js +12 -10
  512. package/dist/tour/tour-catalogue.js.map +1 -1
  513. package/dist/tour/tour-dock.d.ts +0 -2
  514. package/dist/tour/tour-dock.js +0 -2
  515. package/dist/tour/tour-dock.js.map +1 -1
  516. package/dist/tour/tour-gates.d.ts +4 -0
  517. package/dist/tour/tour-gates.js +14 -0
  518. package/dist/tour/tour-gates.js.map +1 -1
  519. package/dist/tour/tour-overlay.d.ts +27 -0
  520. package/dist/tour/tour-overlay.js +741 -0
  521. package/dist/tour/tour-overlay.js.map +1 -0
  522. package/dist/tour/tour.d.ts +13 -3
  523. package/dist/tour/tour.js +59 -781
  524. package/dist/tour/tour.js.map +1 -1
  525. package/dist/tour/use-tour-progress.js +1 -1
  526. package/dist/tour/use-tour-progress.js.map +1 -1
  527. package/dist/wizard/stepper-nav.d.ts +5 -1
  528. package/dist/wizard/stepper-nav.js.map +1 -1
  529. package/dist/wizard/types.d.ts +6 -2
  530. package/dist/wizard/types.js.map +1 -1
  531. package/dist/wizard/use-wizard.d.ts +3 -1
  532. package/dist/wizard/use-wizard.js.map +1 -1
  533. package/dist/wizard/validation.d.ts +3 -1
  534. package/dist/wizard/validation.js.map +1 -1
  535. package/package.json +10 -6
  536. package/src/account/account-parts.ts +5 -25
  537. package/src/account/data-export-setting-labels.ts +1 -1
  538. package/src/account/delete-account-setting-labels.ts +1 -1
  539. package/src/account/email-change-setting-labels.ts +1 -1
  540. package/src/account/passkeys-setting.tsx +60 -38
  541. package/src/account/sessions-setting.tsx +18 -12
  542. package/src/admin/admin-action-confirm.tsx +1 -5
  543. package/src/admin/admin-parts.ts +11 -25
  544. package/src/admin/mail-test-card-labels.ts +1 -1
  545. package/src/admin/plan-change-labels.ts +5 -23
  546. package/src/admin/plan-change.tsx +7 -44
  547. package/src/admin/reviewer-scope-editor.tsx +3 -3
  548. package/src/auth/auth-errors-labels.ts +23 -0
  549. package/src/auth/auth-errors.ts +11 -38
  550. package/src/auth/complete-name-dialog.tsx +4 -1
  551. package/src/auth/forgot-password-form-labels.ts +1 -1
  552. package/src/auth/forgot-password-form.tsx +11 -6
  553. package/src/auth/register-form-labels.ts +1 -1
  554. package/src/auth/reset-password-form-labels.ts +1 -1
  555. package/src/auth/reset-password-form.tsx +8 -4
  556. package/src/auth/sign-in-form-labels.ts +1 -1
  557. package/src/auth/status-parts.tsx +0 -6
  558. package/src/auth/verify-email-labels.ts +1 -1
  559. package/src/auth/verify-email.tsx +11 -6
  560. package/src/billing/cancel-subscription.tsx +26 -12
  561. package/src/billing/dialog-close.ts +34 -0
  562. package/src/billing/plan-card.tsx +36 -11
  563. package/src/billing/plan-change-labels.ts +66 -0
  564. package/src/billing/plan-switch.tsx +26 -12
  565. package/src/chart.ts +21 -3
  566. package/src/components/account-chips.tsx +20 -23
  567. package/src/components/alert-banner.tsx +82 -5
  568. package/src/components/amount-input.tsx +18 -7
  569. package/src/components/autocomplete.tsx +64 -70
  570. package/src/components/bulk-action-bar.tsx +70 -2
  571. package/src/components/button-look.ts +5 -5
  572. package/src/components/button.tsx +2 -2
  573. package/src/components/chart-edge.ts +34 -1
  574. package/src/components/chart-figure.tsx +35 -0
  575. package/src/components/chart-zoom-core.tsx +6 -5
  576. package/src/components/chart.tsx +26 -5
  577. package/src/components/combobox-core.tsx +293 -62
  578. package/src/components/combobox.tsx +183 -153
  579. package/src/components/copy-button.tsx +34 -23
  580. package/src/components/country-select.tsx +16 -11
  581. package/src/components/data-table-column-settings.tsx +52 -10
  582. package/src/components/data-table-filters.ts +6 -4
  583. package/src/components/data-table-fit.ts +19 -5
  584. package/src/components/data-table-groups.tsx +1 -1
  585. package/src/components/data-table-head.tsx +32 -22
  586. package/src/components/data-table-mobile.tsx +61 -26
  587. package/src/components/data-table-pagination.tsx +21 -6
  588. package/src/components/data-table-resize.ts +1 -1
  589. package/src/components/data-table-row-actions.tsx +3 -3
  590. package/src/components/data-table-row.tsx +25 -14
  591. package/src/components/data-table-selection.ts +1 -1
  592. package/src/components/data-table-shared.tsx +33 -1
  593. package/src/components/data-table-sort.ts +57 -2
  594. package/src/components/data-table-virtual.ts +32 -8
  595. package/src/components/data-table.tsx +239 -68
  596. package/src/components/date-field.tsx +65 -8
  597. package/src/components/date-picker.tsx +125 -48
  598. package/src/components/date-range-picker.tsx +82 -31
  599. package/src/components/error-boundary.tsx +53 -39
  600. package/src/components/field-base-labels.ts +20 -0
  601. package/src/components/field-base.tsx +13 -7
  602. package/src/components/field-sync-labels.ts +1 -0
  603. package/src/components/field-sync.tsx +23 -1
  604. package/src/components/form-actions.tsx +20 -5
  605. package/src/components/hover-menu.tsx +18 -8
  606. package/src/components/icon-button.tsx +14 -9
  607. package/src/components/inline-confirm.tsx +116 -0
  608. package/src/components/inline-entity-combobox.tsx +197 -153
  609. package/src/components/input.tsx +1 -1
  610. package/src/components/jump-calendar.tsx +30 -146
  611. package/src/components/legal-page.tsx +10 -7
  612. package/src/components/legal.tsx +4 -2
  613. package/src/components/lightbox.tsx +21 -8
  614. package/src/components/list.tsx +10 -4
  615. package/src/components/measured-grid.tsx +8 -4
  616. package/src/components/mini-calendar.tsx +6 -5
  617. package/src/components/modal.tsx +6 -1
  618. package/src/components/month-grid.tsx +229 -0
  619. package/src/components/month-picker.tsx +192 -200
  620. package/src/components/multi-select.tsx +21 -9
  621. package/src/components/picker-sheet.tsx +12 -9
  622. package/src/components/pie-chart-labels.ts +8 -0
  623. package/src/components/pie-chart.tsx +22 -28
  624. package/src/components/popover.tsx +18 -1
  625. package/src/components/row-actions.tsx +2 -1
  626. package/src/components/section-nav.tsx +7 -0
  627. package/src/components/series-chart-axes.ts +3 -3
  628. package/src/components/series-chart-labels.ts +7 -4
  629. package/src/components/series-chart.tsx +178 -69
  630. package/src/components/share-card.tsx +6 -6
  631. package/src/components/sign-chip-labels.ts +1 -0
  632. package/src/components/sign-chip.tsx +10 -1
  633. package/src/components/tabs-labels.ts +13 -0
  634. package/src/components/tabs.tsx +2 -2
  635. package/src/components/toggle-legend.tsx +16 -11
  636. package/src/components/translation-review-editor.tsx +6 -5
  637. package/src/components/translation-review.tsx +4 -3
  638. package/src/components/treemap-labels.ts +39 -0
  639. package/src/components/treemap-layout.ts +210 -0
  640. package/src/components/treemap.tsx +722 -133
  641. package/src/components/use-table-state.ts +12 -9
  642. package/src/data-table.ts +9 -2
  643. package/src/eslint/role-utilities.ts +97 -19
  644. package/src/feedback/feedback-dialog.tsx +30 -19
  645. package/src/feedback/feedback-mutation.ts +41 -0
  646. package/src/feedback/feedback-page-link.ts +90 -0
  647. package/src/feedback/feedback-public-list.tsx +17 -5
  648. package/src/feedback/feedback-replies.tsx +13 -6
  649. package/src/feedback/feedback-row-detail-labels.ts +5 -0
  650. package/src/feedback/feedback-row-detail.tsx +103 -67
  651. package/src/feedback/feedback-status-undo.ts +41 -27
  652. package/src/feedback/feedback-submit-dialog.tsx +2 -2
  653. package/src/feedback/feedback-submit.tsx +21 -7
  654. package/src/feedback/feedback-swipe.tsx +1 -1
  655. package/src/feedback/feedback-table.tsx +86 -38
  656. package/src/feedback/feedback-thread-labels.ts +2 -2
  657. package/src/feedback/feedback-thread.tsx +27 -25
  658. package/src/feedback.ts +42 -0
  659. package/src/hooks/use-focus-trap.ts +8 -24
  660. package/src/hooks/use-hotkey.ts +24 -7
  661. package/src/hooks/use-long-press.ts +16 -2
  662. package/src/hooks/use-media-query.ts +20 -4
  663. package/src/hooks/use-mounted.ts +39 -0
  664. package/src/hooks/use-overlay-history.ts +32 -3
  665. package/src/i18n/defaults.ts +4 -5
  666. package/src/i18n/german.ts +8 -2
  667. package/src/i18n/kit-labels.tsx +9 -2
  668. package/src/i18n/locales/es.ts +8 -2
  669. package/src/i18n/locales/fr.ts +21 -13
  670. package/src/i18n/locales/hu.ts +10 -2
  671. package/src/i18n/locales/it.ts +8 -2
  672. package/src/i18n/locales/zh.ts +9 -2
  673. package/src/i18n/review.ts +5 -0
  674. package/src/index.ts +103 -13
  675. package/src/landing/routing.tsx +14 -10
  676. package/src/lib/broadcast.ts +52 -0
  677. package/src/lib/date-format.ts +89 -13
  678. package/src/lib/day-format.ts +96 -0
  679. package/src/lib/describe-failure.ts +18 -0
  680. package/src/lib/direction.ts +39 -0
  681. package/src/lib/focus-left.ts +156 -0
  682. package/src/lib/format.ts +5 -17
  683. package/src/lib/http-status.ts +38 -0
  684. package/src/lib/intl-cache.ts +25 -0
  685. package/src/lib/isin.ts +10 -0
  686. package/src/lib/iso-day.ts +13 -0
  687. package/src/lib/lazy-with-fallback.ts +82 -0
  688. package/src/lib/path-pattern.ts +55 -0
  689. package/src/lib/reduced-motion.ts +2 -1
  690. package/src/lib/round.ts +7 -2
  691. package/src/lib/safe-storage.ts +48 -6
  692. package/src/lib/session-refresh.ts +1 -1
  693. package/src/lib/share-format.ts +18 -0
  694. package/src/lib/text-case.ts +19 -0
  695. package/src/lib/text-match.ts +57 -2
  696. package/src/lib/thenable.ts +19 -0
  697. package/src/lib/translation-review.ts +13 -5
  698. package/src/notifications/device-zone-report.ts +1 -1
  699. package/src/notifications/notification-bell.tsx +7 -4
  700. package/src/notifications/notification-inbox.tsx +40 -58
  701. package/src/notifications/notification-parts.tsx +3 -4
  702. package/src/notifications/notification-types-setting.tsx +1 -1
  703. package/src/notifications/notifications-labels.ts +7 -0
  704. package/src/notifications/push-device-setting.tsx +1 -1
  705. package/src/notifications/push-devices-setting.tsx +30 -55
  706. package/src/notifications/quiet-hours-setting.tsx +93 -31
  707. package/src/notifications/unsubscribe-panel.tsx +4 -7
  708. package/src/notifications/use-push-device.ts +76 -10
  709. package/src/offline/query-persistence.ts +35 -3
  710. package/src/rhf/fields.tsx +11 -4
  711. package/src/search/command-palette.tsx +2 -4
  712. package/src/search/global-search.tsx +36 -15
  713. package/src/search/use-command-key.ts +13 -12
  714. package/src/search.ts +9 -0
  715. package/src/settings/use-settings-focus.ts +3 -0
  716. package/src/shell/account-menu-language.tsx +27 -5
  717. package/src/shell/account-menu-text-size.tsx +32 -10
  718. package/src/shell/dev-menu.tsx +7 -21
  719. package/src/shell/role-switcher.tsx +7 -0
  720. package/src/shell/top-bar-actions.tsx +1 -1
  721. package/src/shell/top-bar-parts-labels.ts +0 -3
  722. package/src/shell.ts +40 -9
  723. package/src/sync/engine.ts +339 -61
  724. package/src/sync.ts +8 -1
  725. package/src/testing/css-variables.ts +8 -9
  726. package/src/theme/contrast.ts +8 -9
  727. package/src/theme/palette-store.ts +9 -9
  728. package/src/theme/text-size.ts +6 -8
  729. package/src/theme/theme-store.ts +7 -9
  730. package/src/tour/tour-catalogue.tsx +26 -15
  731. package/src/tour/tour-dock.ts +0 -2
  732. package/src/tour/tour-gates.ts +23 -0
  733. package/src/tour/tour-overlay.tsx +1170 -0
  734. package/src/tour/tour.tsx +108 -1202
  735. package/src/tour/use-tour-progress.ts +1 -1
  736. package/src/wizard/stepper-nav.tsx +3 -1
  737. package/src/wizard/types.ts +11 -2
  738. package/src/wizard/use-wizard.ts +2 -1
  739. package/src/wizard/validation.ts +8 -2
  740. package/tokens.css +2 -1
  741. package/dist/components/ui-labels.js.map +0 -1
  742. package/dist/shell/dev-switchers.d.ts +0 -6
  743. package/dist/shell/dev-switchers.js +0 -12
  744. package/dist/shell/dev-switchers.js.map +0 -1
  745. package/src/components/ui-labels.ts +0 -24
  746. package/src/shell/dev-switchers.tsx +0 -18
@@ -1,5 +1,5 @@
1
- import { Fragment, useId, useMemo, useRef, useState } from "react";
2
- import type { ComponentPropsWithoutRef, ReactNode, Ref } from "react";
1
+ import { useId, useMemo, useRef, useState } from "react";
2
+ import type { ComponentPropsWithoutRef, KeyboardEvent, ReactNode, Ref } from "react";
3
3
  import { ChevronDown } from "lucide-react";
4
4
  import { FIELD_BASE, FIELD_FLOATING_PAD, FIELD_INVALID } from "./field-base";
5
5
  import { cn } from "../lib/cn";
@@ -9,9 +9,18 @@ import { isImeEnter } from "../lib/ime";
9
9
  import { isQuietFocus } from "../lib/quiet-focus";
10
10
  import { usePhoneLayout } from "../hooks/use-breakpoint";
11
11
  import { PickerSheet, SHEET_ROW_CLASS } from "./picker-sheet";
12
- import { ComboboxFieldLabel, endHintRowProps, GROUP_HEADING_STICKY, useActiveOptionScroll } from "./combobox-core";
13
- import { useKitLocale } from "../i18n/kit-labels";
14
- import { rankMatch, sameName } from "../lib/text-match";
12
+ import {
13
+ anchoredHeadingClass,
14
+ ComboboxFieldLabel,
15
+ endHintRowProps,
16
+ GroupedOptions,
17
+ groupRuns,
18
+ SHEET_HEADING_CLASS,
19
+ useTypedListStatus,
20
+ type GroupRun,
21
+ } from "./combobox-core";
22
+ import { DEFAULT_COMBOBOX_LABELS, useKitLabels, useKitLocale } from "../i18n/kit-labels";
23
+ import { sameName, searchRanked } from "../lib/text-match";
15
24
  import {
16
25
  EndHintRow,
17
26
  FieldCaption,
@@ -44,7 +53,7 @@ export interface ComboboxProps
44
53
  value: string;
45
54
  onChange: (v: string) => void;
46
55
  /** Suggestion pool (e.g. existing payee names). */
47
- options: string[];
56
+ options: readonly string[];
48
57
  /** The visible label, a `<label for>` above the field: a ReactNode, as on every kit
49
58
  * field (a string until 0.34, refactor audit 2026-10, API-9). Without one, name the
50
59
  * field with `aria-label`. */
@@ -223,6 +232,12 @@ export function Combobox(props: ComboboxProps) {
223
232
  const { open, setOpen, wrapperRef, panelRef } = useDropdown({ backCloses: !isPhone, escapeLayer: false });
224
233
  const primaryOnly = usePrimaryPressOnly();
225
234
  const [active, setActive] = useState(-1);
235
+ // A closed list has no row the keyboard is on, however it closed — the sheet's X,
236
+ // Escape or Back, a press outside — adjusted while rendering. The arrows' row outlived
237
+ // it: the list reopens on the whole pool, so the row the arrows had put on "Migros"
238
+ // showed "Aldi" highlighted, and Enter took it over the typed value (0.52 code review,
239
+ // combobox.tsx). An ArrowDown that opens the list sets both at once, and keeps its row.
240
+ if (!open && active !== -1) setActive(-1);
226
241
  // The lock (see `lockedKeyDown`): a lock arriving while the list is up closes it,
227
242
  // adjusted while rendering so no frame offers a row that can no longer be taken.
228
243
  const lock = useLockReason(commit, disabledReason);
@@ -264,6 +279,9 @@ export function Combobox(props: ComboboxProps) {
264
279
  const query = typing ? value.trim() : "";
265
280
  // Folded as every kit list folds (DUP-5): "zurich" finds Zürich, by the locale's case.
266
281
  const locale = useKitLocale();
282
+ // The live status's words (INP-6): the result count and "No results", as the panel
283
+ // pickers say them.
284
+ const labels = useKitLabels("combobox", DEFAULT_COMBOBOX_LABELS);
267
285
  const matches = useMemo(() => {
268
286
  const seen = new Set<string>();
269
287
  const uniq = options.filter((o) => o && !seen.has(o) && seen.add(o));
@@ -272,13 +290,14 @@ export function Combobox(props: ComboboxProps) {
272
290
  if (!query) {
273
291
  ranked = uniq.slice(0, cap);
274
292
  } else {
275
- // The whole name, then prefix matches, then substring matches — most relevant on
276
- // top (`rankMatch`; a stable sort keeps the pool's order within a rank).
277
- ranked = uniq
278
- .map((o) => ({ o, rank: rankMatch(o, query, { locale }) }))
279
- .filter((x) => x.rank >= 0)
293
+ // Every word of the query somewhere in the name (0.51.4's rule, which this list
294
+ // was said to have and did not: refactor audit 2026-10-30, DUP-4), ranked by the
295
+ // WHOLE query — the whole name, then prefix matches, then substring matches, then
296
+ // the names that hold the words apart (`searchRanked`, each name folded once). A
297
+ // stable sort keeps the pool's order within a rank.
298
+ ranked = searchRanked(uniq, query, (o) => [o], { locale })
280
299
  .sort((a, b) => a.rank - b.rank)
281
- .map((x) => x.o)
300
+ .map((x) => x.row)
282
301
  .slice(0, cap);
283
302
  }
284
303
  if (!groupBy) return ranked;
@@ -296,27 +315,22 @@ export function Combobox(props: ComboboxProps) {
296
315
  }, [options, query, groupBy, maxSuggestions, isPhone, locale]);
297
316
 
298
317
  /**
299
- * Which rows OPEN a group, and with what heading — computed once for both lists.
318
+ * The rows cut into their groups — computed once for both lists, each run a
319
+ * `role="group"` its heading names (INP-8). Without `groupBy`, one bare run.
300
320
  *
301
- * The desktop list had this as `matches[i - 1]`, which is free; the sheet had it as
302
- * `matches[matches.indexOf(o) - 1]`, which is a scan of the list per row and another
303
- * per heading test. That is quadratic in the sheet's own cap of 50, on the branch
304
- * that runs on the slowest hardware we ship to — and it answers the wrong question
305
- * besides: `indexOf` finds the FIRST row with that string, so a duplicated option
306
- * would have compared against a neighbour it is not next to. (`matches` de-duplicates
307
- * today; that is a property of the memo above, not of the row being rendered.)
321
+ * The desktop list had the boundaries as `matches[i - 1]`, which is free; the sheet had
322
+ * them as `matches[matches.indexOf(o) - 1]`, which is a scan of the list per row and
323
+ * another per heading test. That is quadratic in the sheet's own cap of 50, on the
324
+ * branch that runs on the slowest hardware we ship to — and it answers the wrong
325
+ * question besides: `indexOf` finds the FIRST row with that string, so a duplicated
326
+ * option would have compared against a neighbour it is not next to. (`matches`
327
+ * de-duplicates today; that is a property of the memo above, not of the row being
328
+ * rendered.)
308
329
  */
309
- const groupHeadings = useMemo(() => {
310
- if (!groupBy) return null;
311
- const heads = new Map<number, string>();
312
- let prev: string | undefined;
313
- matches.forEach((o, i) => {
314
- const group = groupBy(o);
315
- if (group != null && group !== prev) heads.set(i, group);
316
- prev = group;
317
- });
318
- return heads;
319
- }, [matches, groupBy]);
330
+ const runs = useMemo<GroupRun<string>[]>(
331
+ () => (groupBy ? groupRuns(matches, groupBy) : [{ group: null, start: 0, rows: matches }]),
332
+ [matches, groupBy],
333
+ );
320
334
 
321
335
  const take = (v: string) => {
322
336
  if (locked) return;
@@ -328,18 +342,6 @@ export function Combobox(props: ComboboxProps) {
328
342
  setTyping(false);
329
343
  };
330
344
 
331
- // Offered only when the typed text is genuinely NOT in the pool: an exact match —
332
- // folded as the list matches, so "cafe" is Café ({@link sameName}, DUP-5 in the
333
- // 2026-10-30 refactor audit) — is an existing entry the list is already showing, and a
334
- // second way to pick it would be noise. Compared against `options`, not `matches` —
335
- // `matches` is capped, so a pool of 300 payees would otherwise offer to "add" one
336
- // that exists but fell off the end of the list.
337
- // What the field claims the keyboard is on. Only on a pointer device: the phone
338
- // renders its rows in a {@link PickerSheet} whose own search box owns focus, and a
339
- // field pointing at an id that is not there is worse than one pointing nowhere.
340
- const activeId = !isPhone && active >= 0 && active < matches.length ? optionId(active) : undefined;
341
- useActiveOptionScroll(activeId);
342
-
343
345
  // While locked the field sits in the reason's Tooltip — in a fragment with a hidden
344
346
  // copy of the reason, Button's anatomy; `block` so a full-width field stays full width.
345
347
  const withLock = (box: ReactNode) =>
@@ -351,19 +353,81 @@ export function Combobox(props: ComboboxProps) {
351
353
  box
352
354
  );
353
355
 
356
+ // Offered only when the typed text is genuinely NOT in the pool: an exact match —
357
+ // folded as the list matches, so "cafe" is Café ({@link sameName}, DUP-5 in the
358
+ // 2026-10-30 refactor audit) — is an existing entry the list is already showing, and a
359
+ // second way to pick it would be noise. Compared against `options`, not `matches` —
360
+ // `matches` is capped, so a pool of 300 payees would otherwise offer to "add" one
361
+ // that exists but fell off the end of the list.
354
362
  const typed = value.trim();
355
363
  const createRow =
356
364
  createLabel && typed.length > 0 && !options.some((o) => sameName(o, typed, locale)) ? createLabel(typed) : null;
357
365
 
366
+ // Whether a list shows, the row the keyboard is on — named by the field, or on a phone
367
+ // by the sheet's own search box, which takes the same keys (INP-6, 0.34's BUG-5 for
368
+ // this field) — and the live status: the family's one rule for a typed list.
369
+ const { showing, expanded, activeOption, statusRegion } = useTypedListStatus({
370
+ isPhone,
371
+ open,
372
+ inert,
373
+ rowCount: matches.length,
374
+ extraRow: Boolean(createRow),
375
+ query,
376
+ active: active < matches.length ? active : -1,
377
+ optionId,
378
+ labels,
379
+ });
358
380
  // The list is a layer on the Escape stack while it SHOWS (Wave 2, DUP-1): an Escape
359
381
  // over an empty "open" list is the dialog's, as it always was. On a phone the sheet
360
382
  // is the layer.
361
- const showing = !isPhone && open && !inert && (matches.length > 0 || Boolean(createRow));
362
383
  useDismissLayer(showing, () => {
363
384
  setOpen(false);
364
385
  setActive(-1);
365
386
  });
366
387
 
388
+ /** The list's keys — in the field and, on a phone, in the sheet's search box. Enter
389
+ * with no row highlighted is "I mean what I typed" in both. */
390
+ const listKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
391
+ if (e.key === "ArrowDown") {
392
+ e.preventDefault();
393
+ setOpen(true);
394
+ setActive((i) => Math.min(i + 1, matches.length - 1));
395
+ } else if (e.key === "ArrowUp") {
396
+ e.preventDefault();
397
+ setActive((i) => Math.max(i - 1, 0));
398
+ } else if (e.key === "Enter") {
399
+ // The Enter that confirms an IME composition is the IME's: it picks no row and
400
+ // submits nothing (BUG-9).
401
+ if (isImeEnter(e)) return;
402
+ if (open && active >= 0 && active < matches.length) {
403
+ e.preventDefault();
404
+ take(matches[active]);
405
+ } else {
406
+ // No row highlighted: the typed text is the answer. `preventDefault` only when a
407
+ // caller is taking Enter, so a plain form submit is otherwise left alone.
408
+ if (onSubmit) e.preventDefault();
409
+ setOpen(false);
410
+ onSubmit?.();
411
+ }
412
+ }
413
+ };
414
+
415
+ /** The rows in their runs — each group a `role="group"` its heading names (INP-8) —
416
+ * for the sheet or the anchored list; `row` draws one option, `grouped` when it
417
+ * stands under a heading. `matches` is group-contiguous, so the boundaries are a
418
+ * property of the list rather than of the branch drawing it (see `runs`). */
419
+ const groupedRows = (sheet: boolean, row: (o: string, i: number, grouped: boolean) => ReactNode) => (
420
+ <GroupedOptions
421
+ runs={runs}
422
+ listboxId={listboxId}
423
+ rowKey={(o) => o}
424
+ row={row}
425
+ // The list's first item sits closer to its top edge; the create row comes first
426
+ // when there is one.
427
+ headingClassName={(run) => (sheet ? SHEET_HEADING_CLASS : anchoredHeadingClass(run, !createRow))}
428
+ />
429
+ );
430
+
367
431
  return (
368
432
  // `rest` dresses the outer box — a `data-tour` anchor, a test id. Not the NAME,
369
433
  // description, invalid or required state: those belong on the <input> below,
@@ -400,13 +464,15 @@ export function Combobox(props: ComboboxProps) {
400
464
  // field otherwise (dev#477: a field with neither announces only its text).
401
465
  aria-label={ariaLabel}
402
466
  role="combobox"
403
- aria-expanded={open}
467
+ aria-expanded={expanded}
404
468
  // The list this field is the mouth of. Required by the role, and the half
405
469
  // that was missing: the field said it was expanded and never said what it
406
470
  // had expanded, so a reader had no way from the box to the options
407
471
  // (ESLint's `role-has-required-aria-props`, the audit's §a11y).
408
472
  aria-controls={listboxId}
409
- aria-activedescendant={activeId}
473
+ // Only on a pointer device: on a phone the sheet's own search box holds
474
+ // focus and names the row, and the field behind it says nothing.
475
+ aria-activedescendant={isPhone ? undefined : activeOption}
410
476
  aria-autocomplete="list"
411
477
  aria-invalid={field.isInvalid || undefined}
412
478
  aria-describedby={mergeDescribedBy(field.describedBy, locked && lock.reasonId)}
@@ -430,6 +496,7 @@ export function Combobox(props: ComboboxProps) {
430
496
  if (isQuietFocus(e.currentTarget)) return;
431
497
  setOpen(true);
432
498
  setTyping(false);
499
+ setActive(-1);
433
500
  // The sheet carries its own input, so the field behind it must not also
434
501
  // pull up the keyboard and scroll the page under the dialog.
435
502
  if (isPhone) sheetInputRef.current?.focus();
@@ -442,7 +509,10 @@ export function Combobox(props: ComboboxProps) {
442
509
  onClick={() => {
443
510
  if (locked) return;
444
511
  setOpen(true);
512
+ // The whole pool again, so no row of the typed list is the keyboard's
513
+ // (0.52 code review, combobox.tsx — see `active`).
445
514
  setTyping(false);
515
+ setActive(-1);
446
516
  }}
447
517
  // `inputMode="none"` rather than readOnly: the field must not look
448
518
  // uneditable (FIELD_BASE greys a read-only field since dev#468) and must
@@ -458,29 +528,8 @@ export function Combobox(props: ComboboxProps) {
458
528
  }}
459
529
  onKeyDown={(e) => {
460
530
  if (locked) return lockedKeyDown(e);
461
- if (e.key === "ArrowDown") {
462
- e.preventDefault();
463
- setOpen(true);
464
- setActive((i) => Math.min(i + 1, matches.length - 1));
465
- } else if (e.key === "ArrowUp") {
466
- e.preventDefault();
467
- setActive((i) => Math.max(i - 1, 0));
468
- } else if (e.key === "Enter") {
469
- // The Enter that confirms an IME composition is the IME's: it picks no
470
- // row and submits nothing (BUG-9).
471
- if (isImeEnter(e)) return;
472
- if (open && active >= 0 && active < matches.length) {
473
- e.preventDefault();
474
- take(matches[active]);
475
- } else {
476
- // No row highlighted: the typed text is the answer. `preventDefault`
477
- // only when a caller is taking Enter, so a plain form submit is
478
- // otherwise left alone.
479
- if (onSubmit) e.preventDefault();
480
- setOpen(false);
481
- onSubmit?.();
482
- }
483
- } else if (e.key === "Escape") {
531
+ listKeyDown(e);
532
+ if (e.key === "Escape") {
484
533
  // A list that is SHOWING is the top of the Escape stack, and the key
485
534
  // closes it and stops here: a Modal or FullBleedDialog around the field
486
535
  // otherwise closed with it, form and all (round 0.34 BUG-1). With no
@@ -535,6 +584,8 @@ export function Combobox(props: ComboboxProps) {
535
584
  )}
536
585
  <FieldCaption parts={hintParts} />
537
586
  {field.errorEl}
587
+ {/* The live status — see `useTypedListStatus` for where it goes and why. */}
588
+ {!isPhone && statusRegion}
538
589
  {isPhone && (
539
590
  <PickerSheet
540
591
  open={open && !inert}
@@ -546,11 +597,17 @@ export function Combobox(props: ComboboxProps) {
546
597
  query={value}
547
598
  onQueryChange={(v) => {
548
599
  onChange(v);
600
+ setActive(-1);
549
601
  setTyping(true);
550
602
  }}
551
603
  searchPlaceholder={searchPlaceholder ?? placeholder}
552
604
  inputRef={sheetInputRef}
553
605
  closeLabel={closeLabel}
606
+ // The field's own keys, in the box focus is in while the sheet is up: arrows
607
+ // and Enter there did nothing (INP-6, as BUG-5 gave the panel pickers).
608
+ onSearchKeyDown={listKeyDown}
609
+ listboxId={listboxId}
610
+ activeId={activeOption}
554
611
  >
555
612
  <ul id={listboxId} role="listbox">
556
613
  {createRow && (
@@ -569,37 +626,28 @@ export function Combobox(props: ComboboxProps) {
569
626
  </button>
570
627
  </li>
571
628
  )}
572
- {matches.map((o, i) => {
573
- const group = groupHeadings?.get(i);
574
- return (
575
- <Fragment key={o}>
576
- {group !== undefined && (
577
- <li
578
- role="presentation"
579
- className={cn(
580
- GROUP_HEADING_STICKY,
581
- "px-4 pb-0.5 pt-3 text-caption font-semibold uppercase tracking-wide text-muted",
582
- )}
583
- >
584
- {group}
585
- </li>
629
+ {groupedRows(true, (o, i) => (
630
+ <li role="presentation">
631
+ <button
632
+ type="button"
633
+ id={optionId(i)}
634
+ role="option"
635
+ aria-selected={o === value}
636
+ onClick={() => take(o)}
637
+ className={cn(
638
+ SHEET_ROW_CLASS,
639
+ // The row the sheet's arrows are on.
640
+ i === active && "bg-active",
641
+ optionAdornment && "flex items-center justify-between gap-2",
586
642
  )}
587
- <li role="presentation">
588
- <button
589
- type="button"
590
- role="option"
591
- aria-selected={o === value}
592
- onClick={() => take(o)}
593
- className={cn(SHEET_ROW_CLASS, optionAdornment && "flex items-center justify-between gap-2")}
594
- >
595
- {optionAdornment ? <span className="truncate-until-large">{o}</span> : o}
596
- {optionAdornment?.(o)}
597
- </button>
598
- </li>
599
- </Fragment>
600
- );
601
- })}
643
+ >
644
+ {optionAdornment ? <span className="truncate-until-large">{o}</span> : o}
645
+ {optionAdornment?.(o)}
646
+ </button>
647
+ </li>
648
+ ))}
602
649
  </ul>
650
+ {statusRegion}
603
651
  </PickerSheet>
604
652
  )}
605
653
  {showing && (
@@ -623,62 +671,44 @@ export function Combobox(props: ComboboxProps) {
623
671
  </button>
624
672
  </li>
625
673
  )}
626
- {matches.map((o, i) => {
627
- // Heading at each group boundary only — `matches` is group-contiguous, so
628
- // the boundaries are a property of the list rather than of the branch
629
- // drawing it. See `groupHeadings`.
630
- const group = groupHeadings?.get(i);
631
- return (
632
- <Fragment key={o}>
633
- {group !== undefined && (
634
- <li
635
- role="presentation"
636
- className={cn(
637
- GROUP_HEADING_STICKY,
638
- "px-3 pb-0.5 pt-2 text-caption font-semibold uppercase tracking-wide text-muted first:pt-1",
639
- )}
640
- >
641
- {group}
642
- </li>
674
+ {groupedRows(false, (o, i, grouped) => (
675
+ <li role="presentation">
676
+ <button
677
+ type="button"
678
+ id={optionId(i)}
679
+ role="option"
680
+ // CHOSEN, not highlighted. The row the arrows are on is named by the
681
+ // field's `aria-activedescendant`; saying "selected" for it would tell a
682
+ // reader that the row they are passing over is already the answer.
683
+ aria-selected={o === value}
684
+ // Focus stays in the field — that is what `aria-activedescendant` is
685
+ // for — so the rows are not tab stops.
686
+ tabIndex={-1}
687
+ onMouseDown={(e) => {
688
+ // mousedown (not click) so the blur from the input firing first
689
+ // doesn't close the list before the selection registers.
690
+ e.preventDefault();
691
+ take(o);
692
+ }}
693
+ onMouseEnter={() => setActive(i)}
694
+ className={cn(
695
+ rowClass(i === active),
696
+ // Every row of a group indented under its heading — it was the first
697
+ // row of each group only.
698
+ grouped && "ps-6",
699
+ // A row with a badge is a flex row so the label truncates and the
700
+ // badge keeps its width; without one it stays the plain block the
701
+ // other lists render, so nothing shifts for callers that pass none.
702
+ // From Large up the label wraps instead (`truncate-until-large`,
703
+ // text size §10.17, round 0.34 T1), as the badge-less row does.
704
+ optionAdornment && "flex items-center justify-between gap-2",
643
705
  )}
644
- <li role="presentation">
645
- <button
646
- type="button"
647
- id={optionId(i)}
648
- role="option"
649
- // CHOSEN, not highlighted. The row the arrows are on is named by
650
- // the field's `aria-activedescendant`; saying "selected" for it
651
- // would tell a reader that the row they are passing over is
652
- // already the answer.
653
- aria-selected={o === value}
654
- // Focus stays in the field — that is what
655
- // `aria-activedescendant` is for — so the rows are not tab stops.
656
- tabIndex={-1}
657
- onMouseDown={(e) => {
658
- // mousedown (not click) so the blur from the input firing first
659
- // doesn't close the list before the selection registers.
660
- e.preventDefault();
661
- take(o);
662
- }}
663
- onMouseEnter={() => setActive(i)}
664
- className={cn(
665
- rowClass(i === active),
666
- group != null && "ps-6",
667
- // A row with a badge is a flex row so the label truncates and the
668
- // badge keeps its width; without one it stays the plain block the
669
- // other lists render, so nothing shifts for callers that pass none.
670
- // From Large up the label wraps instead (`truncate-until-large`,
671
- // text size §10.17, round 0.34 T1), as the badge-less row does.
672
- optionAdornment && "flex items-center justify-between gap-2",
673
- )}
674
- >
675
- {optionAdornment ? <span className="truncate-until-large">{o}</span> : o}
676
- {optionAdornment?.(o)}
677
- </button>
678
- </li>
679
- </Fragment>
680
- );
681
- })}
706
+ >
707
+ {optionAdornment ? <span className="truncate-until-large">{o}</span> : o}
708
+ {optionAdornment?.(o)}
709
+ </button>
710
+ </li>
711
+ ))}
682
712
  </SuggestionList>
683
713
  )}
684
714
  </div>
@@ -9,7 +9,6 @@ import { Button } from "./button";
9
9
  import { IconButton } from "./icon-button";
10
10
  import type { ButtonSize, ButtonTone, ButtonVariant } from "./button-look";
11
11
  import type { IconButtonSize, IconButtonTone } from "./icon-button";
12
- import { Tooltip } from "./tooltip";
13
12
  import type { TooltipSide } from "./tooltip";
14
13
  import { DEFAULT_COPY_BUTTON_LABELS } from "./copy-button-labels";
15
14
 
@@ -31,8 +30,9 @@ export interface CopyButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonEle
31
30
  /** What to copy. A function is read at click time — for a value that is expensive
32
31
  * to build (a CSV of the table) or that changes under the button. */
33
32
  text: string | (() => string);
34
- /** `icon` (default): a square icon button whose tooltip states the result.
35
- * `label`: a text button whose words change to the result. */
33
+ /** `icon` (default): a square icon button whose glyph and colour show the result — its
34
+ * words in a bubble, and from Large up beside the glyph, as every labelled IconButton
35
+ * shows them. `label`: a text button whose words change to the result. */
36
36
  variant?: "icon" | "label";
37
37
  /** The idle accessible name — and, in the `label` variant, the visible text:
38
38
  * "Copy IBAN" says WHAT is copied, which a row of three copy icons needs. Default
@@ -82,9 +82,9 @@ const ICONS: Record<CopyState, typeof Copy> = { idle: Copy, copied: Check, faile
82
82
  * failure goes through an ASSERTIVE region and a success through a polite one — the
83
83
  * failure is the news that changes what they do next.
84
84
  *
85
- * The icon variant keeps the SAME accessible name in every state. A button renaming
86
- * itself under the focus is announced inconsistently across readers; the live region
87
- * is the channel that is actually heard.
85
+ * The icon variant keeps the SAME accessible name in every state, and the same words on
86
+ * screen. A button renaming itself under the focus is announced inconsistently across
87
+ * readers; the live region is the channel that is actually heard.
88
88
  */
89
89
  export function CopyButton({
90
90
  text,
@@ -156,25 +156,36 @@ export function CopyButton({
156
156
  );
157
157
  }
158
158
 
159
+ // IconButton names itself (0.52, refactor audit 2026-10-30, DSP-21): `label` is the
160
+ // bubble — and the text beside the glyph at Large, as on every labelled IconButton —
161
+ // and `aria-label` keeps the name steady. A Tooltip of our own round it cloned
162
+ // `aria-describedby` onto the button, which then read "Copy, button, Copy".
163
+ //
164
+ // The idle words, in every state (0.52 code review, deep, charts, finding 8). As the
165
+ // state, "Copied" stood at Large beside the glyph of a button named "Copy IBAN": the pill
166
+ // changed width on every copy, and the words on screen were not in the name a voice
167
+ // user says to press it (WCAG 2.5.3, label in name). The glyph and its colour show the
168
+ // result, and the live regions say it.
159
169
  return (
160
170
  <>
161
- <Tooltip label={stateText} side={tooltipSide} portal={tooltipPortal}>
162
- <IconButton
163
- type="button"
164
- {...rest}
165
- disabled={disabled}
166
- aria-label={idleText}
167
- variant={buttonVariant ?? "ghost"}
168
- size={(size ?? "sm") as IconButtonSize}
169
- tone={tone as IconButtonTone | undefined}
170
- stopPropagation={stopPropagation}
171
- data-state={state}
172
- onClick={() => void onClick()}
173
- className={cn(iconTone, className)}
174
- >
175
- <Icon aria-hidden />
176
- </IconButton>
177
- </Tooltip>
171
+ <IconButton
172
+ type="button"
173
+ {...rest}
174
+ disabled={disabled}
175
+ label={idleText}
176
+ aria-label={idleText}
177
+ tooltipSide={tooltipSide}
178
+ tooltipPortal={tooltipPortal}
179
+ variant={buttonVariant ?? "ghost"}
180
+ size={(size ?? "sm") as IconButtonSize}
181
+ tone={tone as IconButtonTone | undefined}
182
+ stopPropagation={stopPropagation}
183
+ data-state={state}
184
+ onClick={() => void onClick()}
185
+ className={cn(iconTone, className)}
186
+ >
187
+ <Icon aria-hidden />
188
+ </IconButton>
178
189
  {regions}
179
190
  </>
180
191
  );
@@ -3,7 +3,7 @@ import type { ComponentPropsWithoutRef, ReactNode, Ref } from "react";
3
3
  import { X } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
5
5
  import { COUNTRY_CODES, countryName, normalizeCountryCode } from "../lib/countries";
6
- import { rankMatch } from "../lib/text-match";
6
+ import { searchRanked } from "../lib/text-match";
7
7
  import { FieldChevron, FIELD_FLOATING_PAD, FIELD_INVALID, FIELD_TRIGGER, FloatingField } from "./field-base";
8
8
  import {
9
9
  assignRef,
@@ -178,17 +178,22 @@ interface Entry {
178
178
  name: string;
179
179
  }
180
180
 
181
- /** Best rank first; a stable sort, so equal ranks keep the collated (or preferred)
182
- * order they came in. The rank is the kit's one (`rankMatch`, DUP-5 — written here
183
- * first): the code itself (a two-letter query "ch" means Switzerland before it means
184
- * Chad), then the start of the name, then anywhere in it, with accents and case folded
185
- * — "osterreich" finds Österreich, "cote" Côte d'Ivoire. */
181
+ /** Every word of the query in the name, or the whole code (0.51.4's rule: "kinshasa
182
+ * congo" finds Congo - Kinshasa; refactor audit 2026-10-30, DUP-4), best rank first; a
183
+ * stable sort, so equal ranks keep the collated (or preferred) order they came in. The
184
+ * rank is the kit's one, for the WHOLE query (`rankMatch`, DUP-5 — written here first):
185
+ * the code itself (a two-letter query "ch" means Switzerland before it means Chad), then
186
+ * the start of the name, then anywhere in it, then the words apart (`searchRanked`, each
187
+ * name and code folded once), with accents and case folded — "osterreich" finds
188
+ * Österreich, "cote" Côte d'Ivoire.
189
+ *
190
+ * A word is the code or it is not: searched INSIDE the code, as one more text, "w"
191
+ * listed Aruba (AW) and Samoa (WS) and "d" Germany (DE), names with nothing of the
192
+ * query in them (0.52 code review, country-select.tsx). */
186
193
  function search(entries: Entry[], q: string, locale: string): Entry[] {
187
- return entries
188
- .map((e) => ({ e, r: rankMatch(e.name, q, { code: e.code, locale }) }))
189
- .filter((x) => x.r >= 0)
190
- .sort((a, b) => a.r - b.r)
191
- .map((x) => x.e);
194
+ return searchRanked(entries, q, (e) => [e.name], { code: (e) => e.code, locale })
195
+ .sort((a, b) => a.rank - b.rank)
196
+ .map((x) => x.row);
192
197
  }
193
198
 
194
199
  function toOption(e: Entry, flags: boolean, group?: string): ComboOption<string> {