@eifi1/ui-kit 0.34.0 → 0.36.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 (446) hide show
  1. package/README.md +115 -41
  2. package/dist/admin/role-select.d.ts +3 -2
  3. package/dist/admin/role-select.js +2 -0
  4. package/dist/admin/role-select.js.map +1 -1
  5. package/dist/billing/billing-banner.d.ts +5 -2
  6. package/dist/billing/billing-banner.js.map +1 -1
  7. package/dist/billing/plan-limit-notice.d.ts +5 -2
  8. package/dist/billing/plan-limit-notice.js.map +1 -1
  9. package/dist/chart.js.map +1 -1
  10. package/dist/components/amount-input.d.ts +2 -5
  11. package/dist/components/amount-input.js +2 -2
  12. package/dist/components/amount-input.js.map +1 -1
  13. package/dist/components/autocomplete.d.ts +2 -2
  14. package/dist/components/autocomplete.js +2 -1
  15. package/dist/components/autocomplete.js.map +1 -1
  16. package/dist/components/button-look.d.ts +1 -1
  17. package/dist/components/button-look.js +9 -4
  18. package/dist/components/button-look.js.map +1 -1
  19. package/dist/components/calculator.d.ts +1 -4
  20. package/dist/components/calculator.js +1 -3
  21. package/dist/components/calculator.js.map +1 -1
  22. package/dist/components/chart-zoom.d.ts +0 -37
  23. package/dist/components/chart-zoom.js +1 -28
  24. package/dist/components/chart-zoom.js.map +1 -1
  25. package/dist/components/checkbox-group.d.ts +5 -2
  26. package/dist/components/checkbox-group.js +15 -4
  27. package/dist/components/checkbox-group.js.map +1 -1
  28. package/dist/components/chip-input.d.ts +0 -4
  29. package/dist/components/chip-input.js +1 -5
  30. package/dist/components/chip-input.js.map +1 -1
  31. package/dist/components/column-mapper.d.ts +5 -3
  32. package/dist/components/column-mapper.js +2 -0
  33. package/dist/components/column-mapper.js.map +1 -1
  34. package/dist/components/combobox.d.ts +3 -3
  35. package/dist/components/combobox.js +2 -1
  36. package/dist/components/combobox.js.map +1 -1
  37. package/dist/components/copy-button.d.ts +5 -1
  38. package/dist/components/copy-button.js.map +1 -1
  39. package/dist/components/country-select.d.ts +3 -3
  40. package/dist/components/country-select.js +3 -0
  41. package/dist/components/country-select.js.map +1 -1
  42. package/dist/components/currency-option-list.d.ts +3 -8
  43. package/dist/components/currency-option-list.js +1 -29
  44. package/dist/components/currency-option-list.js.map +1 -1
  45. package/dist/components/currency-select.d.ts +3 -2
  46. package/dist/components/currency-select.js +10 -1
  47. package/dist/components/currency-select.js.map +1 -1
  48. package/dist/components/danger-confirm.d.ts +3 -3
  49. package/dist/components/danger-confirm.js.map +1 -1
  50. package/dist/components/data-table-filter-popover.d.ts +1 -1
  51. package/dist/components/data-table-filter-popover.js +1 -1
  52. package/dist/components/data-table-filter-popover.js.map +1 -1
  53. package/dist/components/data-table-labels.d.ts +1 -42
  54. package/dist/components/data-table-labels.js +2 -31
  55. package/dist/components/data-table-labels.js.map +1 -1
  56. package/dist/components/data-table-shared.d.ts +17 -1
  57. package/dist/components/data-table-shared.js +22 -0
  58. package/dist/components/data-table-shared.js.map +1 -1
  59. package/dist/components/data-table.d.ts +12 -2
  60. package/dist/components/data-table.js +18 -14
  61. package/dist/components/data-table.js.map +1 -1
  62. package/dist/components/date-field.d.ts +2 -1
  63. package/dist/components/date-field.js.map +1 -1
  64. package/dist/components/date-picker.js +3 -0
  65. package/dist/components/date-picker.js.map +1 -1
  66. package/dist/components/date-range-picker.js +3 -0
  67. package/dist/components/date-range-picker.js.map +1 -1
  68. package/dist/components/dialog-frame.d.ts +3 -1
  69. package/dist/components/dialog-frame.js.map +1 -1
  70. package/dist/components/dropdown.d.ts +18 -15
  71. package/dist/components/dropdown.js +11 -3
  72. package/dist/components/dropdown.js.map +1 -1
  73. package/dist/components/entity-combobox.d.ts +3 -3
  74. package/dist/components/entity-combobox.js +2 -1
  75. package/dist/components/entity-combobox.js.map +1 -1
  76. package/dist/components/field-base.d.ts +0 -5
  77. package/dist/components/field-base.js +0 -5
  78. package/dist/components/field-base.js.map +1 -1
  79. package/dist/components/field-parts.d.ts +69 -22
  80. package/dist/components/field-parts.js +33 -19
  81. package/dist/components/field-parts.js.map +1 -1
  82. package/dist/components/field-strip.d.ts +9 -23
  83. package/dist/components/field-strip.js +26 -23
  84. package/dist/components/field-strip.js.map +1 -1
  85. package/dist/components/field-sync.d.ts +0 -4
  86. package/dist/components/field-sync.js +0 -4
  87. package/dist/components/field-sync.js.map +1 -1
  88. package/dist/components/field.d.ts +7 -6
  89. package/dist/components/field.js +24 -15
  90. package/dist/components/field.js.map +1 -1
  91. package/dist/components/full-bleed-dialog.js +2 -2
  92. package/dist/components/full-bleed-dialog.js.map +1 -1
  93. package/dist/components/help-popover.d.ts +9 -7
  94. package/dist/components/help-popover.js.map +1 -1
  95. package/dist/components/hover-menu.d.ts +6 -13
  96. package/dist/components/hover-menu.js +3 -3
  97. package/dist/components/hover-menu.js.map +1 -1
  98. package/dist/components/icon-picker.d.ts +3 -2
  99. package/dist/components/icon-picker.js +3 -0
  100. package/dist/components/icon-picker.js.map +1 -1
  101. package/dist/components/inline-entity-combobox.d.ts +3 -3
  102. package/dist/components/inline-entity-combobox.js +2 -1
  103. package/dist/components/inline-entity-combobox.js.map +1 -1
  104. package/dist/components/input.d.ts +2 -2
  105. package/dist/components/input.js +2 -1
  106. package/dist/components/input.js.map +1 -1
  107. package/dist/components/modal.d.ts +9 -1
  108. package/dist/components/modal.js +7 -4
  109. package/dist/components/modal.js.map +1 -1
  110. package/dist/components/month-picker.d.ts +2 -1
  111. package/dist/components/month-picker.js +8 -1
  112. package/dist/components/month-picker.js.map +1 -1
  113. package/dist/components/multi-entity-combobox.d.ts +2 -2
  114. package/dist/components/multi-entity-combobox.js +2 -1
  115. package/dist/components/multi-entity-combobox.js.map +1 -1
  116. package/dist/components/multi-select.d.ts +7 -18
  117. package/dist/components/multi-select.js +8 -10
  118. package/dist/components/multi-select.js.map +1 -1
  119. package/dist/components/number-input.d.ts +2 -5
  120. package/dist/components/number-input.js +2 -4
  121. package/dist/components/number-input.js.map +1 -1
  122. package/dist/components/numeric-field.d.ts +5 -2
  123. package/dist/components/numeric-field.js +4 -1
  124. package/dist/components/numeric-field.js.map +1 -1
  125. package/dist/components/one-time-code-input.d.ts +2 -1
  126. package/dist/components/one-time-code-input.js +2 -1
  127. package/dist/components/one-time-code-input.js.map +1 -1
  128. package/dist/components/phone-input.d.ts +1 -1
  129. package/dist/components/phone-input.js +4 -0
  130. package/dist/components/phone-input.js.map +1 -1
  131. package/dist/components/popover.js +3 -3
  132. package/dist/components/popover.js.map +1 -1
  133. package/dist/components/select.d.ts +4 -3
  134. package/dist/components/select.js +2 -1
  135. package/dist/components/select.js.map +1 -1
  136. package/dist/components/series-chart.js.map +1 -1
  137. package/dist/components/server-wake.d.ts +0 -6
  138. package/dist/components/server-wake.js.map +1 -1
  139. package/dist/components/settings-fields.d.ts +4 -2
  140. package/dist/components/settings-fields.js.map +1 -1
  141. package/dist/components/slider.d.ts +3 -2
  142. package/dist/components/slider.js +7 -1
  143. package/dist/components/slider.js.map +1 -1
  144. package/dist/components/stat-tile.d.ts +8 -2
  145. package/dist/components/stat-tile.js +2 -11
  146. package/dist/components/stat-tile.js.map +1 -1
  147. package/dist/components/swatch-picker.d.ts +3 -2
  148. package/dist/components/swatch-picker.js +3 -0
  149. package/dist/components/swatch-picker.js.map +1 -1
  150. package/dist/components/swipeable-row.d.ts +2 -17
  151. package/dist/components/swipeable-row.js +11 -16
  152. package/dist/components/swipeable-row.js.map +1 -1
  153. package/dist/components/text-link.js +3 -1
  154. package/dist/components/text-link.js.map +1 -1
  155. package/dist/components/textarea.d.ts +2 -1
  156. package/dist/components/textarea.js +9 -3
  157. package/dist/components/textarea.js.map +1 -1
  158. package/dist/components/toggle-group.d.ts +2 -2
  159. package/dist/components/toggle-group.js +7 -3
  160. package/dist/components/toggle-group.js.map +1 -1
  161. package/dist/components/tooltip.d.ts +9 -1
  162. package/dist/components/tooltip.js +20 -5
  163. package/dist/components/tooltip.js.map +1 -1
  164. package/dist/components/translation-review.d.ts +10 -2
  165. package/dist/components/translation-review.js +11 -3
  166. package/dist/components/translation-review.js.map +1 -1
  167. package/dist/components/use-table-state.d.ts +31 -3
  168. package/dist/components/use-table-state.js +53 -8
  169. package/dist/components/use-table-state.js.map +1 -1
  170. package/dist/components/user-avatar.d.ts +2 -2
  171. package/dist/components/user-avatar.js.map +1 -1
  172. package/dist/components/wizard-stepper.d.ts +1 -4
  173. package/dist/components/wizard-stepper.js +2 -3
  174. package/dist/components/wizard-stepper.js.map +1 -1
  175. package/dist/currencies.d.ts +23 -0
  176. package/dist/currencies.js +38 -0
  177. package/dist/currencies.js.map +1 -0
  178. package/dist/demo/demo-banner.d.ts +7 -2
  179. package/dist/demo/demo-banner.js.map +1 -1
  180. package/dist/eslint/index.d.ts +83 -0
  181. package/dist/eslint/index.js +69 -0
  182. package/dist/eslint/index.js.map +1 -0
  183. package/dist/eslint/role-utilities.d.ts +48 -0
  184. package/dist/eslint/role-utilities.generated.d.ts +2 -0
  185. package/dist/eslint/role-utilities.generated.js +143 -0
  186. package/dist/eslint/role-utilities.generated.js.map +1 -0
  187. package/dist/eslint/role-utilities.js +43 -0
  188. package/dist/eslint/role-utilities.js.map +1 -0
  189. package/dist/feedback/feedback-menu.d.ts +2 -2
  190. package/dist/feedback/feedback-menu.js.map +1 -1
  191. package/dist/feedback/feedback-thread.d.ts +3 -8
  192. package/dist/feedback/feedback-thread.js +0 -2
  193. package/dist/feedback/feedback-thread.js.map +1 -1
  194. package/dist/hooks/use-dismiss.d.ts +16 -3
  195. package/dist/hooks/use-dismiss.js +14 -2
  196. package/dist/hooks/use-dismiss.js.map +1 -1
  197. package/dist/i18n/defaults.js +5 -1
  198. package/dist/i18n/defaults.js.map +1 -1
  199. package/dist/i18n/german.js +97 -1
  200. package/dist/i18n/german.js.map +1 -1
  201. package/dist/i18n/kit-labels.d.ts +29 -4
  202. package/dist/i18n/kit-labels.js +21 -1
  203. package/dist/i18n/kit-labels.js.map +1 -1
  204. package/dist/i18n/locales/en.js +104 -3
  205. package/dist/i18n/locales/en.js.map +3 -3
  206. package/dist/i18n/locales/es.js +95 -1
  207. package/dist/i18n/locales/es.js.map +1 -1
  208. package/dist/i18n/locales/fr.js +99 -3
  209. package/dist/i18n/locales/fr.js.map +1 -1
  210. package/dist/i18n/locales/hu.js +95 -1
  211. package/dist/i18n/locales/hu.js.map +1 -1
  212. package/dist/i18n/locales/it.js +99 -3
  213. package/dist/i18n/locales/it.js.map +1 -1
  214. package/dist/i18n/locales/zh.js +95 -1
  215. package/dist/i18n/locales/zh.js.map +1 -1
  216. package/dist/i18n/review.js +13 -0
  217. package/dist/i18n/review.js.map +1 -1
  218. package/dist/i18n/shared-labels.js +3 -1
  219. package/dist/i18n/shared-labels.js.map +1 -1
  220. package/dist/index.d.ts +23 -1
  221. package/dist/index.js +40 -2
  222. package/dist/index.js.map +1 -1
  223. package/dist/lib/device-settings.d.ts +72 -0
  224. package/dist/lib/device-settings.js +64 -0
  225. package/dist/lib/device-settings.js.map +1 -0
  226. package/dist/lib/plain-text.d.ts +11 -0
  227. package/dist/lib/plain-text.js +16 -0
  228. package/dist/lib/plain-text.js.map +1 -0
  229. package/dist/lib/refs.d.ts +13 -0
  230. package/dist/lib/refs.js +15 -0
  231. package/dist/lib/refs.js.map +1 -0
  232. package/dist/lib/safe-storage.d.ts +6 -0
  233. package/dist/lib/safe-storage.js +11 -0
  234. package/dist/lib/safe-storage.js.map +1 -1
  235. package/dist/notifications/notification-parts.d.ts +39 -0
  236. package/dist/notifications/notification-parts.js +47 -0
  237. package/dist/notifications/notification-parts.js.map +1 -0
  238. package/dist/notifications/notification-types-setting.d.ts +62 -0
  239. package/dist/notifications/notification-types-setting.js +192 -0
  240. package/dist/notifications/notification-types-setting.js.map +1 -0
  241. package/dist/notifications/notification-types.d.ts +75 -0
  242. package/dist/notifications/notification-types.js +2 -0
  243. package/dist/notifications/notification-types.js.map +1 -0
  244. package/dist/notifications/notifications-labels.d.ts +131 -0
  245. package/dist/notifications/notifications-labels.js +83 -0
  246. package/dist/notifications/notifications-labels.js.map +1 -0
  247. package/dist/notifications/push-device-setting.d.ts +37 -0
  248. package/dist/notifications/push-device-setting.js +164 -0
  249. package/dist/notifications/push-device-setting.js.map +1 -0
  250. package/dist/notifications/push-devices-setting.d.ts +44 -0
  251. package/dist/notifications/push-devices-setting.js +203 -0
  252. package/dist/notifications/push-devices-setting.js.map +1 -0
  253. package/dist/notifications/quiet-hours-setting.d.ts +47 -0
  254. package/dist/notifications/quiet-hours-setting.js +131 -0
  255. package/dist/notifications/quiet-hours-setting.js.map +1 -0
  256. package/dist/notifications/time-zone-select.d.ts +50 -0
  257. package/dist/notifications/time-zone-select.js +76 -0
  258. package/dist/notifications/time-zone-select.js.map +1 -0
  259. package/dist/notifications/unsubscribe-panel.d.ts +53 -0
  260. package/dist/notifications/unsubscribe-panel.js +139 -0
  261. package/dist/notifications/unsubscribe-panel.js.map +1 -0
  262. package/dist/notifications/use-push-device.d.ts +122 -0
  263. package/dist/notifications/use-push-device.js +230 -0
  264. package/dist/notifications/use-push-device.js.map +1 -0
  265. package/dist/rhf/fields.d.ts +36 -29
  266. package/dist/rhf/fields.js +51 -22
  267. package/dist/rhf/fields.js.map +1 -1
  268. package/dist/rhf/form-core.d.ts +5 -4
  269. package/dist/rhf/form-core.js.map +1 -1
  270. package/dist/rhf/form.d.ts +7 -36
  271. package/dist/rhf/form.js +1 -16
  272. package/dist/rhf/form.js.map +1 -1
  273. package/dist/rhf/line-items.d.ts +1 -1
  274. package/dist/rhf/line-items.js.map +1 -1
  275. package/dist/rhf/use-rhf-wizard-step.js.map +1 -1
  276. package/dist/rhf.js.map +1 -1
  277. package/dist/settings/device-reset-setting-labels.d.ts +3 -0
  278. package/dist/settings/device-reset-setting-labels.js +15 -0
  279. package/dist/settings/device-reset-setting-labels.js.map +1 -0
  280. package/dist/settings/device-reset-setting.d.ts +58 -0
  281. package/dist/settings/device-reset-setting.js +51 -0
  282. package/dist/settings/device-reset-setting.js.map +1 -0
  283. package/dist/shell/app-shell.js +5 -0
  284. package/dist/shell/app-shell.js.map +1 -1
  285. package/dist/shell/option-switcher-menu.d.ts +5 -17
  286. package/dist/shell/option-switcher-menu.js +1 -3
  287. package/dist/shell/option-switcher-menu.js.map +1 -1
  288. package/dist/shell/role-switcher.d.ts +1 -4
  289. package/dist/shell/role-switcher.js +2 -3
  290. package/dist/shell/role-switcher.js.map +1 -1
  291. package/dist/shell/topbar-action-menu.d.ts +7 -19
  292. package/dist/shell/topbar-action-menu.js +1 -3
  293. package/dist/shell/topbar-action-menu.js.map +1 -1
  294. package/dist/shell/topbar-controls.d.ts +3 -12
  295. package/dist/shell/topbar-controls.js +6 -9
  296. package/dist/shell/topbar-controls.js.map +1 -1
  297. package/dist/testing/index.d.ts +1 -1
  298. package/dist/testing/index.js +2 -0
  299. package/dist/testing/index.js.map +1 -1
  300. package/dist/testing/viewport.d.ts +25 -2
  301. package/dist/testing/viewport.js +61 -10
  302. package/dist/testing/viewport.js.map +1 -1
  303. package/dist/theme/contrast-tokens.d.ts +42 -4
  304. package/dist/theme/contrast-tokens.js +56 -9
  305. package/dist/theme/contrast-tokens.js.map +1 -1
  306. package/dist/theme/contrast.d.ts +4 -2
  307. package/dist/theme/contrast.js +13 -0
  308. package/dist/theme/contrast.js.map +1 -1
  309. package/dist/theme/palette-derive.d.ts +15 -1
  310. package/dist/theme/palette-derive.js +37 -8
  311. package/dist/theme/palette-derive.js.map +1 -1
  312. package/dist/theme/palette-presets.d.ts +2 -8
  313. package/dist/theme/palette-presets.js +5 -284
  314. package/dist/theme/palette-presets.js.map +1 -1
  315. package/dist/theme/palette-store.js +6 -0
  316. package/dist/theme/palette-store.js.map +1 -1
  317. package/dist/theme/text-size.js +6 -0
  318. package/dist/theme/text-size.js.map +1 -1
  319. package/dist/theme/theme-store.js +6 -0
  320. package/dist/theme/theme-store.js.map +1 -1
  321. package/dist/wizard/types.d.ts +0 -5
  322. package/dist/wizard/types.js +1 -5
  323. package/dist/wizard/types.js.map +1 -1
  324. package/package.json +9 -1
  325. package/src/admin/role-select.tsx +4 -1
  326. package/src/billing/billing-banner.tsx +5 -2
  327. package/src/billing/plan-limit-notice.tsx +5 -2
  328. package/src/chart.ts +5 -3
  329. package/src/components/amount-input.tsx +4 -7
  330. package/src/components/autocomplete.tsx +5 -2
  331. package/src/components/button-look.ts +15 -5
  332. package/src/components/calculator.tsx +2 -7
  333. package/src/components/chart-zoom.tsx +4 -47
  334. package/src/components/checkbox-group.tsx +22 -4
  335. package/src/components/chip-input.tsx +0 -7
  336. package/src/components/column-mapper.tsx +6 -2
  337. package/src/components/combobox.tsx +6 -3
  338. package/src/components/copy-button.tsx +5 -1
  339. package/src/components/country-select.tsx +6 -1
  340. package/src/components/currency-option-list.tsx +8 -42
  341. package/src/components/currency-select.tsx +12 -3
  342. package/src/components/danger-confirm.tsx +3 -3
  343. package/src/components/data-table-filter-popover.tsx +2 -1
  344. package/src/components/data-table-labels.ts +2 -84
  345. package/src/components/data-table-shared.tsx +55 -2
  346. package/src/components/data-table.tsx +29 -17
  347. package/src/components/date-field.tsx +2 -2
  348. package/src/components/date-picker.tsx +3 -0
  349. package/src/components/date-range-picker.tsx +3 -0
  350. package/src/components/dialog-frame.tsx +3 -1
  351. package/src/components/dropdown.tsx +42 -18
  352. package/src/components/entity-combobox.tsx +6 -3
  353. package/src/components/field-base.tsx +0 -11
  354. package/src/components/field-parts.tsx +112 -38
  355. package/src/components/field-strip.tsx +12 -27
  356. package/src/components/field-sync.tsx +0 -7
  357. package/src/components/field.tsx +32 -19
  358. package/src/components/full-bleed-dialog.tsx +4 -3
  359. package/src/components/help-popover.tsx +9 -7
  360. package/src/components/hover-menu.tsx +12 -16
  361. package/src/components/icon-picker.tsx +8 -3
  362. package/src/components/inline-entity-combobox.tsx +6 -3
  363. package/src/components/input.tsx +4 -2
  364. package/src/components/modal.tsx +20 -4
  365. package/src/components/month-picker.tsx +10 -3
  366. package/src/components/multi-entity-combobox.tsx +5 -2
  367. package/src/components/multi-select.tsx +19 -31
  368. package/src/components/number-input.tsx +5 -10
  369. package/src/components/numeric-field.ts +10 -2
  370. package/src/components/one-time-code-input.tsx +5 -3
  371. package/src/components/phone-input.tsx +4 -0
  372. package/src/components/popover.tsx +8 -4
  373. package/src/components/select.tsx +6 -3
  374. package/src/components/series-chart.tsx +1 -1
  375. package/src/components/server-wake.tsx +0 -6
  376. package/src/components/settings-fields.tsx +4 -2
  377. package/src/components/slider.tsx +10 -3
  378. package/src/components/stat-tile.tsx +11 -20
  379. package/src/components/swatch-picker.tsx +9 -4
  380. package/src/components/swipeable-row.tsx +15 -37
  381. package/src/components/text-link.tsx +3 -1
  382. package/src/components/textarea.tsx +11 -4
  383. package/src/components/toggle-group.tsx +21 -5
  384. package/src/components/tooltip.tsx +37 -6
  385. package/src/components/translation-review.tsx +25 -7
  386. package/src/components/use-table-state.ts +91 -10
  387. package/src/components/user-avatar.tsx +2 -2
  388. package/src/components/wizard-stepper.tsx +2 -6
  389. package/src/currencies.ts +70 -0
  390. package/src/demo/demo-banner.tsx +7 -2
  391. package/src/eslint/index.ts +161 -0
  392. package/src/eslint/role-utilities.generated.ts +146 -0
  393. package/src/eslint/role-utilities.ts +99 -0
  394. package/src/feedback/feedback-menu.tsx +2 -2
  395. package/src/feedback/feedback-thread.tsx +3 -8
  396. package/src/hooks/use-dismiss.ts +39 -4
  397. package/src/i18n/defaults.ts +4 -0
  398. package/src/i18n/german.ts +113 -0
  399. package/src/i18n/kit-labels.tsx +66 -6
  400. package/src/i18n/locales/en.ts +6 -0
  401. package/src/i18n/locales/es.ts +106 -0
  402. package/src/i18n/locales/fr.ts +109 -2
  403. package/src/i18n/locales/hu.ts +104 -0
  404. package/src/i18n/locales/it.ts +108 -2
  405. package/src/i18n/locales/zh.ts +96 -0
  406. package/src/i18n/review.ts +13 -0
  407. package/src/i18n/shared-labels.ts +2 -0
  408. package/src/index.ts +53 -1
  409. package/src/lib/device-settings.ts +146 -0
  410. package/src/lib/plain-text.ts +22 -0
  411. package/src/lib/refs.ts +22 -0
  412. package/src/lib/safe-storage.ts +16 -0
  413. package/src/notifications/notification-parts.tsx +83 -0
  414. package/src/notifications/notification-types-setting.tsx +309 -0
  415. package/src/notifications/notification-types.ts +80 -0
  416. package/src/notifications/notifications-labels.ts +238 -0
  417. package/src/notifications/push-device-setting.tsx +224 -0
  418. package/src/notifications/push-devices-setting.tsx +306 -0
  419. package/src/notifications/quiet-hours-setting.tsx +185 -0
  420. package/src/notifications/time-zone-select.tsx +126 -0
  421. package/src/notifications/unsubscribe-panel.tsx +203 -0
  422. package/src/notifications/use-push-device.ts +392 -0
  423. package/src/rhf/fields.tsx +87 -39
  424. package/src/rhf/form-core.tsx +5 -4
  425. package/src/rhf/form.tsx +7 -43
  426. package/src/rhf/line-items.tsx +1 -1
  427. package/src/rhf/use-rhf-wizard-step.ts +4 -4
  428. package/src/rhf.ts +3 -2
  429. package/src/settings/device-reset-setting-labels.ts +20 -0
  430. package/src/settings/device-reset-setting.tsx +119 -0
  431. package/src/shell/app-shell.tsx +8 -0
  432. package/src/shell/option-switcher-menu.tsx +5 -22
  433. package/src/shell/role-switcher.tsx +2 -6
  434. package/src/shell/topbar-action-menu.tsx +7 -24
  435. package/src/shell/topbar-controls.tsx +6 -18
  436. package/src/testing/index.ts +3 -1
  437. package/src/testing/viewport.ts +125 -19
  438. package/src/theme/contrast-tokens.ts +106 -12
  439. package/src/theme/contrast.ts +30 -4
  440. package/src/theme/palette-derive.ts +68 -7
  441. package/src/theme/palette-presets.ts +16 -299
  442. package/src/theme/palette-store.ts +12 -0
  443. package/src/theme/text-size.ts +8 -0
  444. package/src/theme/theme-store.ts +10 -0
  445. package/src/wizard/types.ts +0 -8
  446. package/tokens.css +38 -4
@@ -6,7 +6,6 @@
6
6
  // A type-only import: erased at build time, so this module stays free of the table
7
7
  // itself (and of react-router), which `i18n/defaults` relies on.
8
8
  import type { DataTableSortLabels } from "./data-table";
9
- import type { LabelOverride } from "../i18n/kit-labels";
10
9
 
11
10
  /** The phone sort control's four keys (`sortBy`, `sortDefault`, `sortAscending`,
12
11
  * `sortDescending`, 0.22.0) are {@link DataTableSortLabels}', declared beside the
@@ -89,7 +88,7 @@ export interface DataTableLabels extends DataTableSortLabels {
89
88
  * A column's filter button and panel: "Filter Amount", and "Filter Amount (active)"
90
89
  * while the column is filtered (round 0.34 Wave 2, BUG-7c). Every column's used to be
91
90
  * "Filter" alike, and "filtered" was a colour. An app that translated only `filter`
92
- * gets `"<filter>: <column>"` from it — see {@link resolveDataTableLabels}.
91
+ * gets `"<filter>: <column>"` from it: DataTable derives the one from the other.
93
92
  */
94
93
  filterColumn: (column: string, active: boolean) => string;
95
94
 
@@ -171,90 +170,9 @@ export const DEFAULT_DATA_TABLE_LABELS: DataTableLabels = {
171
170
  // The phone sort control (0.22.0). The same words as `DEFAULT_DATA_TABLE_SORT_LABELS`
172
171
  // in data-table.tsx, written out rather than spread in: importing that VALUE here
173
172
  // would make data-table.tsx and this module import each other (data-table.tsx reads
174
- // its resolver from here), and would pull the whole table into `i18n/defaults`.
173
+ // these defaults from here), and would pull the whole table into `i18n/defaults`.
175
174
  sortBy: "Sort by",
176
175
  sortDefault: "Default order",
177
176
  sortAscending: "Ascending",
178
177
  sortDescending: "Descending",
179
178
  };
180
-
181
- /**
182
- * Merge caller overrides onto the English defaults (presets merged too, key by key, as
183
- * the provider merges them — so the parameter is a {@link LabelOverride}).
184
- *
185
- * The parameter is lenient on purpose — a table with no labels at all still
186
- * renders — but that is also how a translated app ends up half English and never
187
- * hears about it: lenkbank ships nineteen of these keys in English in a German UI
188
- * today, because every one of them is backfilled silently. The kit will not start
189
- * throwing over it (three apps depend on the lenient merge), so
190
- * {@link missingDataTableLabels} is the other half: it answers which keys fell back,
191
- * and an app asserts on that in its OWN test, where the answer is actionable.
192
- *
193
- * @deprecated 0.34 — pass `labels` to DataTable, or the provider's `dataTable`, which this
194
- * merge serves; removed in 0.35 from the public surface, where DataTable keeps it as its
195
- * own (refactor audit 2026-10, API-6a). One app test calls it.
196
- */
197
- export function resolveDataTableLabels(partial?: LabelOverride<DataTableLabels>): DataTableLabels {
198
- if (!partial) return DEFAULT_DATA_TABLE_LABELS;
199
- // An `undefined` preset is skipped, as the provider skips it, rather than blanking one.
200
- const presets = { ...DEFAULT_DATA_TABLE_LABELS.presets };
201
- for (const [key, text] of Object.entries(partial.presets ?? {})) if (text !== undefined) presets[key] = text;
202
- const merged: DataTableLabels = { ...DEFAULT_DATA_TABLE_LABELS, ...partial, presets };
203
- // `columnsCount` was split out of `columns` + a template literal. Consumers have
204
- // been translating `columns` since 0.1, and backfilling the English default over
205
- // that would hand them "Columns (4/9)" back for having translated the key that
206
- // existed at the time — the same silent-English failure the audit records against
207
- // this file. So the count is derived from the RESOLVED `columns` unless the caller
208
- // states the whole sentence, which is the escape hatch for a language where the
209
- // parenthetical does not fit.
210
- if (partial.columns !== undefined && partial.columnsCount === undefined) {
211
- merged.columnsCount = (visible, total) => `${merged.columns} (${visible}/${total})`;
212
- }
213
- // The same for `filterColumn` (0.34), from a translated `filter`: the app's own word
214
- // with the column, rather than English for having translated the key that existed.
215
- if (partial.filter !== undefined && partial.filterColumn === undefined) {
216
- merged.filterColumn = (column) => `${merged.filter}: ${column}`;
217
- }
218
- return merged;
219
- }
220
-
221
- /**
222
- * The label keys `labels` does not supply, and which therefore come back English
223
- * from {@link resolveDataTableLabels}.
224
- *
225
- * For a consumer's own test:
226
- *
227
- * ```ts
228
- * expect(missingDataTableLabels(de.dataTable)).toEqual([]);
229
- * ```
230
- *
231
- * which fails the day the kit adds a key — which is the point. Adding a label is
232
- * additive here and a silent regression in a translated app, and nothing else in
233
- * either repository can tell the two apart.
234
- *
235
- * Preset labels are reported one at a time (`presets.yesterday`), because `presets`
236
- * is a `Record` merged key by key: answering `"presets"` would say nothing about
237
- * which of the eleven are still English.
238
- *
239
- * @deprecated 0.34 — `missingKitLabels(labels, DEFAULT_UI_KIT_LABELS)`, which checks every
240
- * namespace, the table's among them, and which all three apps' tests already call;
241
- * removed in 0.35 (refactor audit 2026-10, API-6a).
242
- */
243
- export function missingDataTableLabels(labels?: Partial<DataTableLabels>): string[] {
244
- const missing: string[] = [];
245
- for (const key of Object.keys(DEFAULT_DATA_TABLE_LABELS) as Array<keyof DataTableLabels>) {
246
- if (key === "presets") continue;
247
- if (labels?.[key] !== undefined) continue;
248
- // `columnsCount` is DERIVED from a translated `columns` by the resolver above,
249
- // so a caller who set that one is not leaking English here. Reporting it would
250
- // send them to translate a key they have already covered, and an `toEqual([])`
251
- // assertion built on this would never go green.
252
- if (key === "columnsCount" && labels?.columns !== undefined) continue;
253
- if (key === "filterColumn" && labels?.filter !== undefined) continue;
254
- missing.push(key);
255
- }
256
- for (const preset of Object.keys(DEFAULT_DATA_TABLE_LABELS.presets)) {
257
- if (labels?.presets?.[preset] === undefined) missing.push(`presets.${preset}`);
258
- }
259
- return missing;
260
- }
@@ -1,13 +1,16 @@
1
1
  import type { CSSProperties, ReactNode } from "react";
2
2
  import { ROW_ACTIONS_KEY } from "./data-table-row-actions";
3
- import type { DataTableLabels } from "./data-table-labels";
3
+ import { DEFAULT_DATA_TABLE_LABELS, type DataTableLabels } from "./data-table-labels";
4
4
  import type { DataTableCellProps, DataTableColumn, DataTableHeadProps } from "./data-table";
5
+ import type { LabelOverride } from "../i18n/kit-labels";
5
6
 
6
7
  // What DataTable shares with its header (data-table-head.tsx), its column panel and its
7
8
  // phone layout (data-table-mobile.tsx): the cell-attribute and alignment rules, a
8
9
  // column's plain-text name, and the row link. Moved out of data-table.tsx unchanged
9
10
  // (refactor audit 2026-10, MOD-3), into a module of their own so none of those has to
10
- // import data-table.tsx at run time — which imports them.
11
+ // import data-table.tsx at run time — which imports them. Since 0.35 also the table's
12
+ // label resolver, which DataTable and its FilterPopover share and the barrel no longer
13
+ // exports (round 0.35 R1).
11
14
 
12
15
  /**
13
16
  * Split a caller's cell attributes into what may reach the element and what the kit
@@ -80,6 +83,56 @@ export function columnLabel<T>(col: DataTableColumn<T>, labels?: DataTableLabels
80
83
  return col.headerText ?? (typeof col.header === "string" ? col.header : col.key);
81
84
  }
82
85
 
86
+ /**
87
+ * The table's labels: caller overrides merged onto the English defaults (presets merged
88
+ * too, key by key, as the provider merges them — so the parameter is a
89
+ * {@link LabelOverride}).
90
+ *
91
+ * DataTable's own, and FilterPopover's: public until 0.35, when it left the barrel for
92
+ * DataTable's `labels` and the provider's `dataTable`, which it serves (round 0.35 R1,
93
+ * refactor audit 2026-10 API-6a). It stays a resolver rather than `useKitLabels` for the
94
+ * two keys it derives (`columnsCount`, `filterColumn`), which a plain merge would not.
95
+ *
96
+ * Lenient on purpose — a table with no labels at all still renders — so a translated app
97
+ * finds out what fell back to English from `missingKitLabels(labels,
98
+ * DEFAULT_UI_KIT_LABELS)` in its own test, where the answer is actionable.
99
+ */
100
+ export function resolveDataTableLabels(
101
+ ...layers: (LabelOverride<DataTableLabels> | undefined)[]
102
+ ): DataTableLabels {
103
+ if (!layers.some(Boolean)) return DEFAULT_DATA_TABLE_LABELS;
104
+ // The layers in order, the provider's then the prop's, later winning key by key. An
105
+ // `undefined` key is skipped, as `useKitLabels` skips it, rather than blanking the word
106
+ // under it: DataTable spread `{ ...provider, ...prop }`, so `labels={{ autoSize:
107
+ // undefined }}` blanked the provider's word and the English one (round 0.35). `presets`
108
+ // is a record and is merged the same way, so renaming one keeps the other ten.
109
+ const partial: Partial<Omit<DataTableLabels, "presets">> = {};
110
+ const presets = { ...DEFAULT_DATA_TABLE_LABELS.presets };
111
+ for (const layer of layers) {
112
+ for (const [key, value] of Object.entries(layer ?? {})) {
113
+ if (value === undefined) continue;
114
+ if (key !== "presets") Object.assign(partial, { [key]: value });
115
+ else for (const [preset, text] of Object.entries(value)) if (text !== undefined) presets[preset] = text;
116
+ }
117
+ }
118
+ const merged: DataTableLabels = { ...DEFAULT_DATA_TABLE_LABELS, ...partial, presets };
119
+ // `columnsCount` was split out of `columns` + a template literal. Consumers have
120
+ // been translating `columns` since 0.1, and backfilling the English default over
121
+ // that would hand them "Columns (4/9)" back for having translated the key that
122
+ // existed at the time. So the count is derived from the RESOLVED `columns` unless the
123
+ // caller states the whole sentence, which is the escape hatch for a language where
124
+ // the parenthetical does not fit.
125
+ if (partial.columns !== undefined && partial.columnsCount === undefined) {
126
+ merged.columnsCount = (visible, total) => `${merged.columns} (${visible}/${total})`;
127
+ }
128
+ // The same for `filterColumn` (0.34), from a translated `filter`: the app's own word
129
+ // with the column, rather than English for having translated the key that existed.
130
+ if (partial.filter !== undefined && partial.filterColumn === undefined) {
131
+ merged.filterColumn = (column) => `${merged.filter}: ${column}`;
132
+ }
133
+ return merged;
134
+ }
135
+
83
136
  /**
84
137
  * Whether a click that reached `row`'s handler did not start in the row's own DOM.
85
138
  *
@@ -5,7 +5,15 @@ import { Spinner } from "./spinner";
5
5
  import { ROW_ACTIONS_KEY, useRowActionColumn } from "./data-table-row-actions";
6
6
  import { useColumnResize } from "./data-table-resize";
7
7
  import { useRangeSelection } from "./data-table-selection";
8
- import { RowLink, cleanAttrs, columnLabel, fromOutside, logicalAlign, splitCellProps } from "./data-table-shared";
8
+ import {
9
+ RowLink,
10
+ cleanAttrs,
11
+ columnLabel,
12
+ fromOutside,
13
+ logicalAlign,
14
+ resolveDataTableLabels,
15
+ splitCellProps,
16
+ } from "./data-table-shared";
9
17
  import { MobileFilters, MobileRow, MobileSort, StackedFields } from "./data-table-mobile";
10
18
  import { DataTableHead } from "./data-table-head";
11
19
  import { ColumnSettingsPanel } from "./data-table-column-settings";
@@ -20,7 +28,7 @@ import type { SwipeAction } from "./swipeable-row";
20
28
  import { FullBleedDialog } from "./full-bleed-dialog";
21
29
  import { usePhoneLayout } from "../hooks/use-breakpoint";
22
30
  import { useAnnounce } from "../hooks/use-announce";
23
- import { DEFAULT_DATA_TABLE_LABELS, resolveDataTableLabels, type DataTableLabels } from "./data-table-labels";
31
+ import { DEFAULT_DATA_TABLE_LABELS, type DataTableLabels } from "./data-table-labels";
24
32
  import { useKitLabelOverrides, useKitLocale, useKitTableStorageKeyPrefix, type LabelOverride } from "../i18n/kit-labels";
25
33
  import { useEdgeFade } from "../lib/strip-fade";
26
34
  import { dirOf, type Direction } from "../lib/direction";
@@ -294,6 +302,16 @@ export interface DataTableProps<T> {
294
302
  onFiltersChange?: (next: FilterState) => void;
295
303
  sorts?: SortState[];
296
304
  onSortsChange?: (next: SortState[]) => void;
305
+ /**
306
+ * Controlled page size, as `sorts` above: the table pages by it and hands its pager's
307
+ * choice to `onPageSizeChange` (`Infinity` is "All"). For tables that page ALIKE —
308
+ * `TranslationReviewPanel`'s groups share one page size as they share one sort
309
+ * (0.35). Left out, the table keeps its own, from `defaultPageSize`, the URL and
310
+ * `storageKey`. A change of value sends a client-side table back to page 1. In
311
+ * `serverPagination` mode the page size is `serverPagination.pageSize`.
312
+ */
313
+ pageSize?: number;
314
+ onPageSizeChange?: (pageSize: number) => void;
297
315
  /**
298
316
  * Opt-in multi-row selection (desktop table only). When provided, a leading
299
317
  * checkbox column is rendered with a select-all box in the header; the owner
@@ -556,7 +574,7 @@ export interface DataTableProps<T> {
556
574
  * On a phone it heads the summary card, which is also named by it.
557
575
  *
558
576
  * There is no built-in default word: a new kit label key is a silent English string
559
- * in every translated app (see `missingDataTableLabels`), and the caller has the
577
+ * in every translated app (see `missingKitLabels`), and the caller has the
560
578
  * word in its own catalogue already. Without it the row is unlabelled on screen —
561
579
  * pass one.
562
580
  */
@@ -728,6 +746,8 @@ export function DataTable<T>({
728
746
  onFiltersChange,
729
747
  sorts: sortsProp,
730
748
  onSortsChange,
749
+ pageSize: pageSizeProp,
750
+ onPageSizeChange,
731
751
  selection,
732
752
  labels: labelsProp,
733
753
  locale: localeProp,
@@ -775,19 +795,7 @@ export function DataTable<T>({
775
795
  // prop to, `TranslationReviewPanel`'s among them.
776
796
  const providerStorageKeyPrefix = useKitTableStorageKeyPrefix();
777
797
  const storageKeyPrefix = storageKeyPrefixProp ?? providerStorageKeyPrefix ?? DEFAULT_PERSIST_PREFIX;
778
- const labels = useMemo(
779
- () =>
780
- resolveDataTableLabels(
781
- labelOverrides || labelsProp
782
- ? {
783
- ...labelOverrides,
784
- ...labelsProp,
785
- presets: { ...labelOverrides?.presets, ...labelsProp?.presets },
786
- }
787
- : undefined,
788
- ),
789
- [labelOverrides, labelsProp],
790
- );
798
+ const labels = useMemo(() => resolveDataTableLabels(labelOverrides, labelsProp), [labelOverrides, labelsProp]);
791
799
  const locale = useKitLocale(localeProp);
792
800
 
793
801
  // ---- Row actions ---- (data-table-row-actions.tsx)
@@ -830,6 +838,8 @@ export function DataTable<T>({
830
838
  defaultPageSize,
831
839
  sortsProp,
832
840
  filtersProp,
841
+ // Ignored in `serverPagination` mode, where the owner's is the page size.
842
+ pageSizeProp: isServer ? undefined : pageSizeProp,
833
843
  });
834
844
 
835
845
  // With the controls that change them switched off, persisted widths and hidden
@@ -1841,7 +1851,9 @@ export function DataTable<T>({
1841
1851
  isServer
1842
1852
  ? serverPagination!.onPageSizeChange
1843
1853
  : (n) => {
1844
- setPageSize(n);
1854
+ // To the owner when it holds the page size, as `commitSorts` does.
1855
+ if (onPageSizeChange) onPageSizeChange(n);
1856
+ else setPageSize(n);
1845
1857
  setPage(0);
1846
1858
  }
1847
1859
  }
@@ -19,7 +19,7 @@ import {
19
19
  import { splitTriggerAria } from "./trigger-aria";
20
20
  import type { TriggerAria } from "./trigger-aria";
21
21
  import { FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from "./field-base";
22
- import { assignRef, FieldLabelLine, LABEL_ABOVE_BOX } from "./field-parts";
22
+ import { assignRef, FieldLabelLine, LABEL_ABOVE_BOX, type FieldHelpProps } from "./field-parts";
23
23
  import { FullBleedDialog } from "./full-bleed-dialog";
24
24
  import type { RemLength } from "../hooks/use-breakpoint";
25
25
  import type { MiniCalendarProps } from "./mini-calendar";
@@ -34,7 +34,7 @@ import { Popover } from "./popover";
34
34
  * `FormEvent`, while both pickers answer with ISO date strings. Each declares its own
35
35
  * (date-picker.tsx, date-range-picker.tsx).
36
36
  */
37
- export interface DatePickerBaseProps extends Omit<ComponentPropsWithoutRef<"div">, "onChange"> {
37
+ export interface DatePickerBaseProps extends Omit<ComponentPropsWithoutRef<"div">, "onChange">, FieldHelpProps {
38
38
  /** BCP 47 tag for the trigger's date and the calendar. Falls back to
39
39
  * `<UiKitProvider locale>`, then to the runtime's default. */
40
40
  locale?: string;
@@ -170,6 +170,7 @@ export function DatePicker(props: DatePickerProps) {
170
170
  disabled,
171
171
  invalid,
172
172
  hint,
173
+ help,
173
174
  error,
174
175
  // Named so it reaches the field (and so its trigger) when a step/today row is the
175
176
  // root and takes the rest of the caller's props.
@@ -185,6 +186,8 @@ export function DatePicker(props: DatePickerProps) {
185
186
  // (the element a screen reader is on) after any description of the caller's own.
186
187
  const messages = useFieldMessages({
187
188
  hint,
189
+ help,
190
+ name: label ?? rest["aria-label"],
188
191
  error,
189
192
  invalid,
190
193
  describedBy: rest["aria-describedby"],
@@ -394,6 +394,7 @@ export function DateRangePicker(props: DateRangePickerProps) {
394
394
  disabled,
395
395
  invalid,
396
396
  hint,
397
+ help,
397
398
  error,
398
399
  // The trigger's (API-3).
399
400
  ref,
@@ -404,6 +405,8 @@ export function DateRangePicker(props: DateRangePickerProps) {
404
405
  const render = useTriggerFormat("dateRangePicker", locale, formatOptions, formatValue);
405
406
  const messages = useFieldMessages({
406
407
  hint,
408
+ help,
409
+ name: label ?? rest["aria-label"],
407
410
  error,
408
411
  invalid,
409
412
  describedBy: rest["aria-describedby"],
@@ -23,7 +23,9 @@ export { DEFAULT_DIALOG_FRAME_LABELS };
23
23
  * (`children` is the body here, not the whole panel) and `title`, which is the dialog's
24
24
  * HEADING and a ReactNode rather than the browser's tooltip string — the collision
25
25
  * `PickerSheet` met first. Everything else, `size`, `draggable`, `fullBleed`,
26
- * `onKeyDown`, a `data-tour` anchor, still reaches the `Modal`.
26
+ * `onKeyDown`, a `data-tour` anchor, still reaches the `Modal` — and since 0.35 `ref`
27
+ * (round 0.35 R4): the panel, the `role="dialog"` element the frame's header, body and
28
+ * actions sit in.
27
29
  */
28
30
  export interface DialogFrameProps extends Omit<ModalProps, "labelledBy" | "children" | "title"> {
29
31
  /** The heading, and therefore the dialog's accessible name (`aria-labelledby`). */
@@ -11,6 +11,7 @@ import { createPortal } from "react-dom";
11
11
  import { Search } from "lucide-react";
12
12
  import { anchoredInline, useAnchoredPanel } from "../hooks/use-anchored-panel";
13
13
  import { runOwnKeyDown, takeEscape, useDismissLayer, useOutsideClick } from "../hooks/use-dismiss";
14
+ import type { DismissLayer } from "../hooks/use-dismiss";
14
15
  import { useOverlayHistory } from "../hooks/use-overlay-history";
15
16
  import { cn } from "../lib/cn";
16
17
  import { FIELD_TOUCH_TEXT } from "./field-base";
@@ -18,6 +19,12 @@ import { mergeRefs } from "./field-parts";
18
19
  import { FOCUS_RING } from "./focus-ring";
19
20
  import { useAnchorDir } from "./use-anchor-dir";
20
21
 
22
+ /** Each list's Escape layer, filed under the refs {@link useDropdown} and
23
+ * {@link useDropdownSearch} hand out (`panelRef`, `inputRef`), for the panel and the
24
+ * search box those refs are passed to — see "The caller's own handler" on
25
+ * {@link useDropdown} (round 0.35 R2). Weak: a list's refs go with its component. */
26
+ const listLayers = new WeakMap<object, DismissLayer>();
27
+
21
28
  /**
22
29
  * Open state + close-on-outside-click for a custom dropdown — the two input-shaped
23
30
  * comboboxes, and an app's own panel. (MultiSelect, CurrencySelect, GroupedPicker and
@@ -88,6 +95,16 @@ import { useAnchorDir } from "./use-anchor-dir";
88
95
  * and stop it there — so a caller passes nothing new, AmountInput's currency chip
89
96
  * included.
90
97
  *
98
+ * ## The caller's own handler (round 0.35 R2)
99
+ *
100
+ * A caller's `onKeyDown` on {@link DropdownPanel} or {@link DropdownSearchHeader} hears
101
+ * Escape only while this list is the layer on top — the rule the dialogs got first. A
102
+ * tooltip over a row takes that press first, and the next one is the handler's, whose
103
+ * `preventDefault()` still keeps the list. The two find the list's layer through the
104
+ * refs this hook hands out — the panel through `panelRef`, the search box through
105
+ * {@link useDropdownSearch}'s `inputRef` — so a caller passes nothing new. One handed
106
+ * neither (an un-anchored panel may leave `panelRef` off) hears every key, as before.
107
+ *
91
108
  * `escapeLayer: false` is for a caller that registers its own layer: the editable
92
109
  * comboboxes, whose list can be "open" with nothing in it to show — an Escape there
93
110
  * belongs to the dialog.
@@ -129,7 +146,11 @@ export function useDropdown<T extends HTMLElement = HTMLDivElement>({
129
146
  }, []);
130
147
  useOutsideClick([wrapperRef, panelRef], close, open && !panelIsSheet);
131
148
  // See "Escape inside a dialog" above.
132
- useDismissLayer(open && escapeLayer, closeToTrigger);
149
+ const layer = useDismissLayer(open && escapeLayer, closeToTrigger);
150
+ // Filed under `panelRef` for the panel's own handler — "The caller's own handler" above.
151
+ useEffect(() => {
152
+ listLayers.set(panelRef, layer);
153
+ }, [panelRef, layer]);
133
154
  // Same close path Escape and an outside click take, so a list dismissed by Back
134
155
  // cannot end up in a different state from one dismissed any other way.
135
156
  useOverlayHistory(open && backCloses, close);
@@ -145,6 +166,12 @@ export function useDropdownSearch<T extends HTMLElement = HTMLDivElement>() {
145
166
  useDropdown<T>();
146
167
  const [query, setQuery] = useState("");
147
168
  const inputRef = useRef<HTMLInputElement>(null);
169
+ // The list's layer again, under `inputRef` for the search box's handler (round 0.35
170
+ // R2). `useDropdown`'s effect, which runs first, has filed it under `panelRef`.
171
+ useEffect(() => {
172
+ const layer = listLayers.get(panelRef);
173
+ if (layer) listLayers.set(inputRef, layer);
174
+ }, [panelRef]);
148
175
  useEffect(() => {
149
176
  if (open) {
150
177
  // eslint-disable-next-line react-hooks/set-state-in-effect -- reset the query on open
@@ -237,7 +264,9 @@ export function DropdownSearchHeader({
237
264
  value={query}
238
265
  onChange={(e) => onQueryChange(e.target.value)}
239
266
  onKeyDown={(e) => {
240
- runOwnKeyDown(e, onKeyDown);
267
+ // The caller's handler hears Escape only while the list is on top (round 0.35
268
+ // R2) — the layer filed under `inputRef`, when {@link useDropdownSearch} made it.
269
+ runOwnKeyDown(e, onKeyDown, listLayers.get(inputRef));
241
270
  // Focus is in this box while the list is up, so this is where Escape lands
242
271
  // first — see "Escape inside a dialog" on {@link useDropdown}.
243
272
  takeEscape(e);
@@ -271,30 +300,23 @@ export interface DropdownPanelProps extends ComponentPropsWithoutRef<"div"> {
271
300
  anchorRef?: RefObject<HTMLElement | null>;
272
301
  /** {@link useDropdown}'s `panelRef`, so an outside-click sees this as inside. Escape
273
302
  * anywhere in the panel, on a row as in the search box, closes the list rather than
274
- * a dialog around it. */
303
+ * a dialog around it. It is also how the panel finds the list's Escape layer, for
304
+ * its `onKeyDown` (round 0.35 R2: see "The caller's own handler" there). */
275
305
  panelRef?: RefObject<HTMLDivElement | null>;
276
306
  /** Panel width in px, for the anchored form (the CSS `w-*` cannot be measured). */
277
307
  width?: number;
278
- /** Which of the panel's edges lines up with the trigger's, room permitting.
279
- * `start`/`end` follow the trigger's reading direction — `end` is the right edge
280
- * in a left-to-right form and the left one in a right-to-left form — and are what
281
- * the kit's own pickers pass; `left`/`right` are physical and deprecated
282
- * ({@link PhysicalAlign}). Default `end`, which is the old `right` in a
283
- * left-to-right page. */
284
- align?: "start" | "end" | PhysicalAlign;
308
+ /** Which of the panel's edges lines up with the trigger's, room permitting, by the
309
+ * trigger's reading direction — `end` is the right edge in a left-to-right form and
310
+ * the left one in a right-to-left form. Default `end`. The physical `left` / `right`
311
+ * went in 0.35 (round 0.35 R1, refactor audit 2026-10, API-6e): `right` is `end` in a
312
+ * left-to-right page, `left` is `start`. */
313
+ align?: "start" | "end";
285
314
  children: ReactNode;
286
315
  /** The panel, where the rest of the props go (0.34, API-2, refactor audit 2026-10) —
287
316
  * merged with `panelRef`, so the outside-click still sees it. */
288
317
  ref?: Ref<HTMLDivElement>;
289
318
  }
290
319
 
291
- /**
292
- * @deprecated 0.34 — `"start"` / `"end"`, which follow the reading direction: `"right"`
293
- * is `"end"` in a left-to-right page, the default; removed in 0.35 (refactor audit
294
- * 2026-10, API-6e). The physical edges DropdownPanel's `align` still takes.
295
- */
296
- type PhysicalAlign = "left" | "right";
297
-
298
320
  /**
299
321
  * The floating popover surface for the searchable dropdowns: bordered/shadowed
300
322
  * panel, an optional `header` slot (search box, plus any actions), and a
@@ -344,7 +366,9 @@ export function DropdownPanel({
344
366
  // A row the keyboard reached by Tab holds focus too, and its Escape has to close the
345
367
  // list as the search box's does (BUG-1). The caller's handler first, as everywhere.
346
368
  const handleKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {
347
- runOwnKeyDown(e, onKeyDown);
369
+ // It hears Escape only while the list is on top, a tooltip over a row taking the
370
+ // press first (round 0.35 R2) — the layer filed under `panelRef`, when handed one.
371
+ runOwnKeyDown(e, onKeyDown, panelRef && listLayers.get(panelRef));
348
372
  takeEscape(e);
349
373
  };
350
374
  const body = (
@@ -25,6 +25,7 @@ import {
25
25
  useFieldHint,
26
26
  useLockReason,
27
27
  type DisabledReasonDisplay,
28
+ type FieldHelpProps,
28
29
  } from "./field-parts";
29
30
  import { useCommitReason, type CommitScope } from "./write-lock";
30
31
 
@@ -33,7 +34,8 @@ export type { ComboClearValue, ComboOption } from "./combobox-core";
33
34
  /** `onChange` is the kit's — "a selection was made", carrying values — rather
34
35
  * than the div's form event, so the DOM's spelling of it is omitted. */
35
36
  export interface EntityComboboxProps<V extends string | number, C extends ComboClearValue = null>
36
- extends Omit<ComponentPropsWithoutRef<"div">, "onChange"> {
37
+ extends Omit<ComponentPropsWithoutRef<"div">, "onChange">,
38
+ FieldHelpProps {
37
39
  /** Selected id; `null`, `undefined` or `clearValue` when nothing is selected. */
38
40
  value: V | C | null | undefined;
39
41
  /** Selecting an option emits its value; the clear button emits `clearValue`. */
@@ -73,7 +75,7 @@ export interface EntityComboboxProps<V extends string | number, C extends ComboC
73
75
  * so it is the one control here that MUST be in the reader's language. */
74
76
  closeLabel?: string;
75
77
  /** The phone sheet's heading (and, as a string, its accessible name) for a picker
76
- * whose label is drawn by someone else — a form's `FormLabel`; `RhfCombobox`
78
+ * whose label is drawn by someone else — a bound field's label; `RhfCombobox`
77
79
  * hands its label over here (0.24). Default: `label`, then `placeholder`. */
78
80
  sheetTitle?: ReactNode;
79
81
  disabled?: boolean;
@@ -182,6 +184,7 @@ export function EntityCombobox<V extends string | number, C extends ComboClearVa
182
184
  invalid,
183
185
  error,
184
186
  hint,
187
+ help,
185
188
  filter,
186
189
  minChars,
187
190
  debounceMs,
@@ -206,7 +209,7 @@ export function EntityCombobox<V extends string | number, C extends ComboClearVa
206
209
  minChars,
207
210
  debounceMs,
208
211
  });
209
- const hintParts = useFieldHint(hint, ariaDescribedBy);
212
+ const hintParts = useFieldHint(hint, ariaDescribedBy, { help, name: label ?? ariaLabel });
210
213
  const field = useFieldError(error, invalid, hintParts.describedBy, ariaInvalid);
211
214
  // The props are the per-instance overrides, the provider the app-wide ones; a
212
215
  // prop left `undefined` falls through to the provider rather than masking it.
@@ -457,17 +457,6 @@ export interface PasswordRevealLabels {
457
457
  // Defined in ./ui-labels, which holds no component code (0.34, KS U8).
458
458
  export { DEFAULT_PASSWORD_REVEAL_LABELS };
459
459
 
460
- /** @deprecated 0.34 — `useKitLabels("passwordReveal", DEFAULT_PASSWORD_REVEAL_LABELS, labels)`,
461
- * which the provider reaches too, or Input's own `passwordLabels`; removed in 0.35
462
- * (refactor audit 2026-10, API-6a). A merge from before the provider, which no kit
463
- * component calls. */
464
- export function resolvePasswordRevealLabels(
465
- partial?: Partial<PasswordRevealLabels>,
466
- ): PasswordRevealLabels {
467
- if (!partial) return DEFAULT_PASSWORD_REVEAL_LABELS;
468
- return { ...DEFAULT_PASSWORD_REVEAL_LABELS, ...partial };
469
- }
470
-
471
460
  /**
472
461
  * What the character counter of {@link Input} and {@link Textarea} (`showCount`) says.
473
462
  * The visible "12/80" is digits and a slash and is not translated; these are the words