@eifi1/ui-kit 0.21.0 → 0.23.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 (320) hide show
  1. package/README.md +42 -25
  2. package/dist/chart.d.ts +19 -14
  3. package/dist/components/account-chips.d.ts +10 -3
  4. package/dist/components/account-chips.js +5 -2
  5. package/dist/components/account-chips.js.map +1 -1
  6. package/dist/components/account-settings.d.ts +33 -2
  7. package/dist/components/account-settings.js +43 -21
  8. package/dist/components/account-settings.js.map +1 -1
  9. package/dist/components/amount-input.d.ts +53 -14
  10. package/dist/components/amount-input.js +17 -28
  11. package/dist/components/amount-input.js.map +1 -1
  12. package/dist/components/autocomplete.d.ts +29 -0
  13. package/dist/components/autocomplete.js +134 -104
  14. package/dist/components/autocomplete.js.map +1 -1
  15. package/dist/components/button-group.d.ts +19 -14
  16. package/dist/components/calculator.d.ts +19 -14
  17. package/dist/components/checkbox-group.d.ts +104 -0
  18. package/dist/components/checkbox-group.js +111 -0
  19. package/dist/components/checkbox-group.js.map +1 -0
  20. package/dist/components/checkbox.d.ts +19 -0
  21. package/dist/components/checkbox.js +30 -7
  22. package/dist/components/checkbox.js.map +1 -1
  23. package/dist/components/chip.d.ts +18 -0
  24. package/dist/components/chip.js +47 -10
  25. package/dist/components/chip.js.map +1 -1
  26. package/dist/components/column-mapper.d.ts +182 -0
  27. package/dist/components/column-mapper.js +375 -0
  28. package/dist/components/column-mapper.js.map +1 -0
  29. package/dist/components/combobox-core.d.ts +39 -2
  30. package/dist/components/combobox-core.js +29 -6
  31. package/dist/components/combobox-core.js.map +1 -1
  32. package/dist/components/combobox.d.ts +91 -2
  33. package/dist/components/combobox.js +454 -308
  34. package/dist/components/combobox.js.map +1 -1
  35. package/dist/components/confirm-dialog.d.ts +69 -161
  36. package/dist/components/confirm-dialog.js +7 -8
  37. package/dist/components/confirm-dialog.js.map +1 -1
  38. package/dist/components/copy-button.d.ts +16 -11
  39. package/dist/components/country-select.d.ts +167 -0
  40. package/dist/components/country-select.js +293 -0
  41. package/dist/components/country-select.js.map +1 -0
  42. package/dist/components/currency-select.d.ts +17 -1
  43. package/dist/components/currency-select.js +56 -23
  44. package/dist/components/currency-select.js.map +1 -1
  45. package/dist/components/danger-confirm.d.ts +69 -166
  46. package/dist/components/danger-confirm.js +144 -50
  47. package/dist/components/danger-confirm.js.map +1 -1
  48. package/dist/components/data-table-cells.d.ts +1 -2
  49. package/dist/components/data-table-filter-popover.d.ts +1 -2
  50. package/dist/components/data-table-filters.d.ts +1 -2
  51. package/dist/components/data-table-labels.d.ts +4 -97
  52. package/dist/components/data-table-labels.js +9 -1
  53. package/dist/components/data-table-labels.js.map +1 -1
  54. package/dist/components/data-table-pagination.d.ts +3 -1
  55. package/dist/components/data-table.d.ts +1 -2
  56. package/dist/components/data-table.js +98 -3
  57. package/dist/components/data-table.js.map +1 -1
  58. package/dist/components/date-picker.d.ts +66 -5
  59. package/dist/components/date-picker.js +378 -66
  60. package/dist/components/date-picker.js.map +1 -1
  61. package/dist/components/entity-combobox.d.ts +42 -1
  62. package/dist/components/entity-combobox.js +154 -113
  63. package/dist/components/entity-combobox.js.map +1 -1
  64. package/dist/components/facing-pair.d.ts +19 -14
  65. package/dist/components/field-parts.d.ts +224 -0
  66. package/dist/components/field-parts.js +156 -0
  67. package/dist/components/field-parts.js.map +1 -0
  68. package/dist/components/field-strip.d.ts +105 -0
  69. package/dist/components/field-strip.js +46 -0
  70. package/dist/components/field-strip.js.map +1 -0
  71. package/dist/components/file-button.d.ts +19 -14
  72. package/dist/components/file-button.js +13 -3
  73. package/dist/components/file-button.js.map +1 -1
  74. package/dist/components/file-dropzone.d.ts +41 -15
  75. package/dist/components/file-dropzone.js +57 -34
  76. package/dist/components/file-dropzone.js.map +1 -1
  77. package/dist/components/form-actions.d.ts +18 -13
  78. package/dist/components/form-actions.js +69 -5
  79. package/dist/components/form-actions.js.map +1 -1
  80. package/dist/components/iban-input.d.ts +69 -0
  81. package/dist/components/iban-input.js +125 -0
  82. package/dist/components/iban-input.js.map +1 -0
  83. package/dist/components/icon-picker.d.ts +21 -2
  84. package/dist/components/icon-picker.js +19 -4
  85. package/dist/components/icon-picker.js.map +1 -1
  86. package/dist/components/inline-edit-field.d.ts +167 -0
  87. package/dist/components/inline-edit-field.js +293 -0
  88. package/dist/components/inline-edit-field.js.map +1 -0
  89. package/dist/components/language-select.d.ts +130 -0
  90. package/dist/components/language-select.js +18 -0
  91. package/dist/components/language-select.js.map +1 -0
  92. package/dist/components/line-items.d.ts +25 -3
  93. package/dist/components/line-items.js +55 -46
  94. package/dist/components/line-items.js.map +1 -1
  95. package/dist/components/list.d.ts +25 -0
  96. package/dist/components/list.js +16 -5
  97. package/dist/components/list.js.map +1 -1
  98. package/dist/components/money-field.d.ts +32 -14
  99. package/dist/components/money-field.js.map +1 -1
  100. package/dist/components/month-picker.d.ts +52 -4
  101. package/dist/components/month-picker.js +291 -86
  102. package/dist/components/month-picker.js.map +1 -1
  103. package/dist/components/multi-entity-combobox.d.ts +26 -1
  104. package/dist/components/multi-entity-combobox.js +143 -102
  105. package/dist/components/multi-entity-combobox.js.map +1 -1
  106. package/dist/components/multi-select.d.ts +8 -1
  107. package/dist/components/multi-select.js +9 -4
  108. package/dist/components/multi-select.js.map +1 -1
  109. package/dist/components/number-field.d.ts +34 -19
  110. package/dist/components/number-field.js +6 -20
  111. package/dist/components/number-field.js.map +1 -1
  112. package/dist/components/number-input.d.ts +79 -19
  113. package/dist/components/number-input.js +90 -38
  114. package/dist/components/number-input.js.map +1 -1
  115. package/dist/components/numpad-sheet.d.ts +19 -14
  116. package/dist/components/one-time-code-input.d.ts +100 -0
  117. package/dist/components/one-time-code-input.js +137 -0
  118. package/dist/components/one-time-code-input.js.map +1 -0
  119. package/dist/components/phone-input.d.ts +69 -0
  120. package/dist/components/phone-input.js +171 -0
  121. package/dist/components/phone-input.js.map +1 -0
  122. package/dist/components/reauth-dialog.d.ts +2 -2
  123. package/dist/components/reauth-dialog.js +6 -8
  124. package/dist/components/reauth-dialog.js.map +1 -1
  125. package/dist/components/series-chart.d.ts +19 -14
  126. package/dist/components/settings-fields.d.ts +19 -14
  127. package/dist/components/share-card.d.ts +16 -11
  128. package/dist/components/sign-chip.d.ts +66 -0
  129. package/dist/components/sign-chip.js +39 -0
  130. package/dist/components/sign-chip.js.map +1 -0
  131. package/dist/components/swatch-picker.d.ts +43 -2
  132. package/dist/components/swatch-picker.js +80 -32
  133. package/dist/components/swatch-picker.js.map +1 -1
  134. package/dist/components/switch.d.ts +19 -0
  135. package/dist/components/switch.js +24 -6
  136. package/dist/components/switch.js.map +1 -1
  137. package/dist/components/text-link.d.ts +18 -13
  138. package/dist/components/tile-radio.d.ts +88 -13
  139. package/dist/components/tile-radio.js +28 -11
  140. package/dist/components/tile-radio.js.map +1 -1
  141. package/dist/components/time-input.d.ts +24 -15
  142. package/dist/components/time-input.js.map +1 -1
  143. package/dist/components/toggle-group.d.ts +47 -1
  144. package/dist/components/toggle-group.js +110 -69
  145. package/dist/components/toggle-group.js.map +1 -1
  146. package/dist/components/trigger-aria.d.ts +3 -0
  147. package/dist/components/trigger-aria.js +3 -1
  148. package/dist/components/trigger-aria.js.map +1 -1
  149. package/dist/components/ui.d.ts +16 -11
  150. package/dist/components/ui.js +284 -88
  151. package/dist/components/ui.js.map +1 -1
  152. package/dist/components/use-table-state.d.ts +1 -2
  153. package/dist/{data-table-3mi2R3so.d.ts → data-table-labels-B7OdnM0S.d.ts} +140 -3
  154. package/dist/data-table.d.ts +1 -2
  155. package/dist/data-table.js +2 -1
  156. package/dist/data-table.js.map +1 -1
  157. package/dist/feedback/feedback-attachment.d.ts +1 -1
  158. package/dist/feedback/feedback-attachment.js +348 -41
  159. package/dist/feedback/feedback-attachment.js.map +1 -1
  160. package/dist/feedback/feedback-dialog.d.ts +1 -1
  161. package/dist/feedback/feedback-dialog.js.map +1 -1
  162. package/dist/feedback/feedback-inbox.d.ts +3 -2
  163. package/dist/feedback/feedback-inbox.js.map +1 -1
  164. package/dist/feedback/feedback-thread.d.ts +68 -253
  165. package/dist/feedback/feedback-thread.js +46 -10
  166. package/dist/feedback/feedback-thread.js.map +1 -1
  167. package/dist/{kit-labels-D1J2_jyD.d.ts → feedback-BxeQVzwq.d.ts} +1206 -20
  168. package/dist/{feedback-attachment-WFiXJ8We.d.ts → feedback-attachment-fGAzZPf0.d.ts} +178 -11
  169. package/dist/feedback.d.ts +66 -2
  170. package/dist/hooks/use-file-drop.d.ts +19 -14
  171. package/dist/i18n/defaults.d.ts +19 -14
  172. package/dist/i18n/defaults.js +19 -2
  173. package/dist/i18n/defaults.js.map +1 -1
  174. package/dist/i18n/german.d.ts +19 -14
  175. package/dist/i18n/german.js +84 -5
  176. package/dist/i18n/german.js.map +1 -1
  177. package/dist/i18n/kit-labels.d.ts +15 -10
  178. package/dist/i18n/kit-labels.js +8 -2
  179. package/dist/i18n/kit-labels.js.map +1 -1
  180. package/dist/i18n/languages.d.ts +19 -14
  181. package/dist/i18n/locales/de-CH.d.ts +19 -14
  182. package/dist/i18n/locales/en.d.ts +19 -14
  183. package/dist/i18n/locales/en.js +16 -0
  184. package/dist/i18n/locales/en.js.map +1 -1
  185. package/dist/i18n/locales/es.d.ts +19 -14
  186. package/dist/i18n/locales/es.js +83 -5
  187. package/dist/i18n/locales/es.js.map +1 -1
  188. package/dist/i18n/locales/fr.d.ts +19 -14
  189. package/dist/i18n/locales/fr.js +82 -5
  190. package/dist/i18n/locales/fr.js.map +1 -1
  191. package/dist/i18n/locales/hu.d.ts +19 -14
  192. package/dist/i18n/locales/hu.js +85 -5
  193. package/dist/i18n/locales/hu.js.map +1 -1
  194. package/dist/i18n/locales/it.d.ts +19 -14
  195. package/dist/i18n/locales/it.js +84 -5
  196. package/dist/i18n/locales/it.js.map +1 -1
  197. package/dist/i18n/locales/zh.d.ts +19 -14
  198. package/dist/i18n/locales/zh.js +80 -5
  199. package/dist/i18n/locales/zh.js.map +1 -1
  200. package/dist/i18n/review.d.ts +19 -14
  201. package/dist/i18n/review.js +27 -1
  202. package/dist/i18n/review.js.map +1 -1
  203. package/dist/index.d.ts +21 -10
  204. package/dist/index.js +73 -2
  205. package/dist/index.js.map +1 -1
  206. package/dist/lib/column-mapping.d.ts +81 -0
  207. package/dist/lib/column-mapping.js +108 -0
  208. package/dist/lib/column-mapping.js.map +1 -0
  209. package/dist/lib/countries.d.ts +43 -0
  210. package/dist/lib/countries.js +39 -0
  211. package/dist/lib/countries.js.map +1 -0
  212. package/dist/lib/decimal-marks.d.ts +46 -0
  213. package/dist/lib/decimal-marks.js +40 -0
  214. package/dist/lib/decimal-marks.js.map +1 -0
  215. package/dist/lib/iban.d.ts +98 -0
  216. package/dist/lib/iban.js +154 -0
  217. package/dist/lib/iban.js.map +1 -0
  218. package/dist/lib/isin.d.ts +30 -0
  219. package/dist/lib/isin.js +36 -0
  220. package/dist/lib/isin.js.map +1 -0
  221. package/dist/lib/phone.d.ts +69 -0
  222. package/dist/lib/phone.js +121 -0
  223. package/dist/lib/phone.js.map +1 -0
  224. package/dist/lib/table-text.d.ts +109 -1
  225. package/dist/lib/table-text.js +122 -1
  226. package/dist/lib/table-text.js.map +1 -1
  227. package/dist/rhf/fields.d.ts +233 -18
  228. package/dist/rhf/fields.js +456 -3
  229. package/dist/rhf/fields.js.map +1 -1
  230. package/dist/rhf/form.d.ts +19 -14
  231. package/dist/rhf.d.ts +22 -15
  232. package/dist/rhf.js.map +1 -1
  233. package/dist/shell/app-shell.d.ts +18 -13
  234. package/dist/shell/top-bar-brand.d.ts +19 -14
  235. package/dist/shell/topbar-action-menu.d.ts +36 -3
  236. package/dist/shell/topbar-action-menu.js +74 -33
  237. package/dist/shell/topbar-action-menu.js.map +1 -1
  238. package/dist/shell.d.ts +18 -13
  239. package/dist/table-text.d.ts +1 -1
  240. package/dist/tour/tour.js +20 -24
  241. package/dist/tour/tour.js.map +1 -1
  242. package/dist/wizard/stepper-nav.d.ts +49 -16
  243. package/dist/wizard/stepper-nav.js +4 -0
  244. package/dist/wizard/stepper-nav.js.map +1 -1
  245. package/dist/wizard.d.ts +19 -14
  246. package/package.json +1 -1
  247. package/src/components/account-chips.tsx +17 -3
  248. package/src/components/account-settings.tsx +92 -26
  249. package/src/components/amount-input.tsx +68 -56
  250. package/src/components/autocomplete.tsx +198 -114
  251. package/src/components/checkbox-group.tsx +229 -0
  252. package/src/components/checkbox.tsx +72 -8
  253. package/src/components/chip.tsx +80 -10
  254. package/src/components/column-mapper.tsx +666 -0
  255. package/src/components/combobox-core.tsx +82 -9
  256. package/src/components/combobox.tsx +661 -340
  257. package/src/components/confirm-dialog.tsx +12 -8
  258. package/src/components/country-select.tsx +556 -0
  259. package/src/components/currency-select.tsx +109 -33
  260. package/src/components/danger-confirm.tsx +429 -82
  261. package/src/components/data-table-labels.ts +16 -1
  262. package/src/components/data-table.tsx +175 -6
  263. package/src/components/date-picker.tsx +595 -71
  264. package/src/components/entity-combobox.tsx +235 -124
  265. package/src/components/field-parts.tsx +403 -0
  266. package/src/components/field-strip.tsx +149 -0
  267. package/src/components/file-button.tsx +36 -3
  268. package/src/components/file-dropzone.tsx +106 -38
  269. package/src/components/form-actions.tsx +147 -6
  270. package/src/components/iban-input.tsx +231 -0
  271. package/src/components/icon-picker.tsx +47 -6
  272. package/src/components/inline-edit-field.tsx +533 -0
  273. package/src/components/language-select.tsx +78 -0
  274. package/src/components/line-items.tsx +35 -2
  275. package/src/components/list.tsx +55 -6
  276. package/src/components/money-field.tsx +13 -0
  277. package/src/components/month-picker.tsx +400 -63
  278. package/src/components/multi-entity-combobox.tsx +207 -120
  279. package/src/components/multi-select.tsx +80 -58
  280. package/src/components/number-field.tsx +28 -46
  281. package/src/components/number-input.tsx +210 -43
  282. package/src/components/one-time-code-input.tsx +288 -0
  283. package/src/components/phone-input.tsx +299 -0
  284. package/src/components/reauth-dialog.tsx +17 -18
  285. package/src/components/sign-chip.tsx +103 -0
  286. package/src/components/swatch-picker.tsx +143 -31
  287. package/src/components/switch.tsx +58 -7
  288. package/src/components/tile-radio.tsx +145 -29
  289. package/src/components/time-input.tsx +8 -1
  290. package/src/components/toggle-group.tsx +206 -73
  291. package/src/components/trigger-aria.ts +5 -0
  292. package/src/components/ui.tsx +479 -138
  293. package/src/data-table.ts +2 -1
  294. package/src/feedback/feedback-attachment.tsx +597 -46
  295. package/src/feedback/feedback-dialog.tsx +9 -3
  296. package/src/feedback/feedback-inbox.tsx +3 -2
  297. package/src/feedback/feedback-thread.tsx +113 -9
  298. package/src/i18n/defaults.ts +18 -1
  299. package/src/i18n/german.ts +89 -0
  300. package/src/i18n/kit-labels.tsx +82 -2
  301. package/src/i18n/locales/en.ts +36 -4
  302. package/src/i18n/locales/es.ts +87 -0
  303. package/src/i18n/locales/fr.ts +87 -0
  304. package/src/i18n/locales/hu.ts +83 -0
  305. package/src/i18n/locales/it.ts +88 -0
  306. package/src/i18n/locales/zh.ts +76 -0
  307. package/src/i18n/review.ts +26 -0
  308. package/src/index.ts +71 -3
  309. package/src/lib/column-mapping.ts +234 -0
  310. package/src/lib/countries.ts +91 -0
  311. package/src/lib/decimal-marks.ts +99 -0
  312. package/src/lib/iban.ts +171 -0
  313. package/src/lib/isin.ts +62 -0
  314. package/src/lib/phone.ts +211 -0
  315. package/src/lib/table-text.ts +271 -0
  316. package/src/rhf/fields.tsx +860 -9
  317. package/src/rhf.ts +3 -1
  318. package/src/shell/topbar-action-menu.tsx +134 -38
  319. package/src/tour/tour.tsx +66 -28
  320. package/src/wizard/stepper-nav.tsx +35 -1
@@ -1,12 +1,14 @@
1
+ import { l as FeedbackAttachmentLabels, k as FeedbackAttachmentFieldSingleProps, g as FeedbackAttachmentFieldLabels, u as FeedbackDialogTextLabels } from './feedback-attachment-fGAzZPf0.js';
2
+ import { FeedbackNoteAttachment } from './feedback/feedback-inbox.js';
1
3
  import * as react from 'react';
2
- import { AnchorHTMLAttributes, Ref, ReactElement, ButtonHTMLAttributes, ReactNode, SelectHTMLAttributes, ComponentPropsWithoutRef, InputHTMLAttributes, TextareaHTMLAttributes } from 'react';
3
- import { DataTableLabels } from './components/data-table-labels.js';
4
+ import { InputHTMLAttributes, ReactNode, AnchorHTMLAttributes, Ref, ReactElement, ButtonHTMLAttributes, SelectHTMLAttributes, ComponentPropsWithoutRef, TextareaHTMLAttributes } from 'react';
5
+ import { TooltipSide } from './components/tooltip.js';
6
+ import { f as DataTableLabels } from './data-table-labels-B7OdnM0S.js';
4
7
  import { MiniCalendarLabels, WeekDay } from './components/mini-calendar.js';
5
8
  import { CalendarHeatmapLabels } from './components/calendar-heatmap.js';
6
9
  import { PopoverLabels } from './components/popover.js';
7
10
  import { ChipInputLabels } from './components/chip.js';
8
11
  import { FieldSyncLabels } from './components/field-sync.js';
9
- import { TooltipSide } from './components/tooltip.js';
10
12
  import { WizardLabels } from './wizard/types.js';
11
13
  import { TourLabels } from './tour/tour.js';
12
14
  import { CommandPaletteLabels } from './search/command-palette.js';
@@ -19,15 +21,11 @@ import { SparklineLabels } from './components/sparkline.js';
19
21
  import { StatTileLabels } from './components/stat-tile.js';
20
22
  import { SignaturePadLabels } from './components/signature-pad.js';
21
23
  import { PasswordStrengthLabels } from './components/password-strength.js';
22
- import { DangerConfirmLabels } from './components/danger-confirm.js';
23
24
  import { SwatchPickerLabels } from './components/swatch-picker.js';
24
25
  import { IconPickerLabels } from './components/icon-picker.js';
25
26
  import { DialogFrameProps, DialogFrameLabels } from './components/dialog-frame.js';
26
27
  import { MeasuredGridLabels } from './components/measured-grid.js';
27
- import { f as FeedbackAttachmentFieldLabels, q as FeedbackDialogTextLabels } from './feedback-attachment-WFiXJ8We.js';
28
- import { FeedbackThreadLabels, FeedbackComposerLabels } from './feedback/feedback-thread.js';
29
28
  import { AccountSettingsLabels } from './components/account-settings-labels.js';
30
- import { ConfirmDialogLabels } from './components/confirm-dialog.js';
31
29
  import { FloatingPanelLabels } from './components/floating-panel.js';
32
30
  import { BulkActionBarLabels } from './components/bulk-action-bar.js';
33
31
  import { ListLabels } from './components/list.js';
@@ -48,6 +46,13 @@ import { RoleDefinition, AccountStateLabels } from './components/account-chips.j
48
46
  import { ReauthDialogLabels } from './components/reauth-dialog.js';
49
47
  import { ServerWakeLabels } from './components/server-wake.js';
50
48
  import { TranslationReviewLabels } from './components/translation-review-labels.js';
49
+ import { CountrySelectLabels } from './components/country-select.js';
50
+ import { InlineEditLabels } from './components/inline-edit-field.js';
51
+ import { IbanKind } from './lib/iban.js';
52
+ import { PhoneCountry, PhoneCountryCode } from './lib/phone.js';
53
+ import { SignChipLabels } from './components/sign-chip.js';
54
+ import { ColumnMapperLabels } from './components/column-mapper.js';
55
+ import './components/field-parts.js';
51
56
 
52
57
  type ButtonVariant = "primary" | "secondary" | "ghost" | "danger" | "brand" | "link";
53
58
  type ButtonSize = "sm" | "md";
@@ -565,7 +570,6 @@ type FieldChevronProps = Omit<ComponentPropsWithoutRef<"svg">, "children">;
565
570
  * what was picked. */
566
571
  declare function FieldChevron({ className, ...rest }: FieldChevronProps): react.JSX.Element;
567
572
  declare const FLOATING_LABEL_CLASS: string;
568
- declare const FLOATING_LABEL_STATIC: string;
569
573
  /**
570
574
  * The one place that assembles a labelled field: a `relative` wrapper around the
571
575
  * control (`children`) plus a floating label inside the top strip. Pass `staticLabel`
@@ -622,15 +626,6 @@ interface FieldHintProps extends Omit<ComponentPropsWithoutRef<"button">, "child
622
626
  side?: TooltipSide;
623
627
  }
624
628
  declare function FieldHint({ label, side, className, "aria-label": ariaLabel, ...rest }: FieldHintProps): react.JSX.Element;
625
- /**
626
- * The floating label for a custom-dropdown trigger (a `<span>`, since the trigger is a
627
- * button not a labelable input). Same placement as {@link FloatingField}'s static label,
628
- * so every labelled field lines up. Render inside a `relative` wrapper, before the trigger.
629
- */
630
- interface FieldLabelProps extends ComponentPropsWithoutRef<"span"> {
631
- children: ReactNode;
632
- }
633
- declare function FieldLabel({ children, className, ...rest }: FieldLabelProps): react.JSX.Element;
634
629
  interface LabelProps extends ComponentPropsWithoutRef<"label"> {
635
630
  /** Draw the required mark after the text. The mark is `aria-hidden`: what a
636
631
  * screen reader hears is the control's own `required` / `aria-required`, which
@@ -669,6 +664,22 @@ declare const DEFAULT_PASSWORD_REVEAL_LABELS: PasswordRevealLabels;
669
664
  /** Caller's labels over the English defaults — the same shape as
670
665
  * `resolveDataTableLabels`, so a consumer translates every kit string one way. */
671
666
  declare function resolvePasswordRevealLabels(partial?: Partial<PasswordRevealLabels>): PasswordRevealLabels;
667
+ /**
668
+ * What the character counter of {@link Input} and {@link Textarea} (`showCount`) says.
669
+ * The visible "12/80" is digits and a slash and is not translated; these are the words
670
+ * a screen reader gets instead of it.
671
+ */
672
+ interface CharacterCountLabels {
673
+ /** The counter as part of the field's description, read when focus reaches the
674
+ * field: "12 of 80 characters". */
675
+ count: (used: number, max: number) => string;
676
+ /** Said once, politely, on entering the last stretch before the limit: "8
677
+ * characters left". */
678
+ remaining: (left: number) => string;
679
+ /** Said once, politely, on reaching the limit. */
680
+ limitReached: string;
681
+ }
682
+ declare const DEFAULT_CHARACTER_COUNT_LABELS: CharacterCountLabels;
672
683
  interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
673
684
  label?: ReactNode;
674
685
  /** Classes for the `<input>` itself, as distinct from `className`, which
@@ -699,6 +710,30 @@ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
699
710
  * `invalid`, so the field paints as well as announces. `invalid` alone still
700
711
  * covers the case where the message lives elsewhere. See {@link useFieldError}. */
701
712
  error?: ReactNode;
713
+ /**
714
+ * Standing advice for the field (keksdose K4: Input had `error` but no `hint`, so the
715
+ * app built the caption by hand under each field, and half of those never reached a
716
+ * screen reader). The {@link Select} rule, so every field reads alike:
717
+ * - plain TEXT (a string or a number) is a caption UNDER the field, attached with
718
+ * `aria-describedby` — after the caller's own ids, before the error's;
719
+ * - anything else (a {@link FieldHint} "?") rides the label line beside the
720
+ * animated label, as NumberInput's does — or, on a field with no label, sits at the
721
+ * field's end edge outside the box, and `className` then styles that row.
722
+ */
723
+ hint?: ReactNode;
724
+ /**
725
+ * A live "12/80" under the field, with `maxLength` (keksdose K11 — the broadcast,
726
+ * support and handoff-note fields counted by hand). Read with the field as "12 of 80
727
+ * characters", and announced politely only on entering the last stretch and on
728
+ * reaching the limit — never on every keystroke. See {@link CharacterCount}. Ignored
729
+ * without a `maxLength`: a count with no limit is not what this answers. Counts
730
+ * UTF-16 code units, as `maxLength` itself does. Controlled, it counts `value`;
731
+ * uncontrolled, `defaultValue` and then every change event — a value written from
732
+ * outside without one (a form library's `reset`) shows from the next keystroke.
733
+ */
734
+ showCount?: boolean;
735
+ /** The counter's words. See {@link CharacterCountLabels}. */
736
+ countLabels?: Partial<CharacterCountLabels>;
702
737
  /** Names for the password reveal toggle, English by default — it is the one
703
738
  * string this component renders on its own behalf, and a German form was
704
739
  * reading it out in English. See {@link PasswordRevealLabels}. */
@@ -735,6 +770,29 @@ interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "siz
735
770
  * the chevron is positioned against — so it could set a width and nothing
736
771
  * else; this is the way to the element. See {@link Input}'s `inputClassName`. */
737
772
  selectClassName?: string;
773
+ /**
774
+ * Why the choice cannot be changed — {@link Button}'s `disabledReason`, for a select
775
+ * that SAVES on change (a role picker in a members table, a status in a row). keksdose
776
+ * K3: those sat inside a hand-rolled `SaveGuard` that forced a native `disabled`, which
777
+ * took the field out of the tab order so the reason never reached a keyboard.
778
+ *
779
+ * With a reason the select is `aria-disabled` instead — still focusable, still showing
780
+ * its value — its list does not open (pointer and keys are swallowed, Tab and Escape
781
+ * excepted), `onChange` is never called, and the reason is in the kit {@link Tooltip}
782
+ * and on `aria-describedby`. It wears the settled look of a disabled field and drops
783
+ * its chevron, as a disabled Select does (dev#474). It wins over `disabled`.
784
+ *
785
+ * Use it CONTROLLED (`value` + `onChange`): React puts a controlled value back after
786
+ * the swallowed change. A touch platform's own picker may still open; nothing it picks
787
+ * is kept or reported.
788
+ */
789
+ disabledReason?: ReactNode;
790
+ /**
791
+ * This select COMMITS — choosing saves. Under a locked {@link WriteLockProvider} it is
792
+ * locked the `disabledReason` way with the lock's reason (which wins over its own).
793
+ * No provider, or an unlocked one: no effect. Button's `commit`, for keksdose K3.
794
+ */
795
+ commit?: boolean;
738
796
  }
739
797
  declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLSelectElement>>;
740
798
  interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
@@ -743,6 +801,14 @@ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
743
801
  invalid?: boolean;
744
802
  /** See {@link Input}'s `error`. */
745
803
  error?: ReactNode;
804
+ /** See {@link Input}'s `hint` (keksdose K4): text is a caption under the field, a
805
+ * {@link FieldHint} rides the label line (or, unlabelled, the end edge). */
806
+ hint?: ReactNode;
807
+ /** See {@link Input}'s `showCount` (keksdose K11): a live "12/80" under the field,
808
+ * with `maxLength`, announced only near and at the limit. */
809
+ showCount?: boolean;
810
+ /** The counter's words. See {@link CharacterCountLabels}. */
811
+ countLabels?: Partial<CharacterCountLabels>;
746
812
  }
747
813
  declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
748
814
  interface CardProps extends ComponentPropsWithoutRef<"div"> {
@@ -1164,6 +1230,375 @@ interface TabsProps<T extends string> extends Omit<ComponentPropsWithoutRef<"div
1164
1230
  }
1165
1231
  declare function Tabs<T extends string>({ tabs, active, onChange, className, wrap, label, panelId, onRemove, removeOn, onAdd, addLabel, labels, busy, orientation, "aria-label": ariaLabel, ...rest }: TabsProps<T>): react.JSX.Element;
1166
1232
 
1233
+ /**
1234
+ * How typed text is compared with the text it has to repeat — shared by
1235
+ * `DangerConfirm`'s `phraseMatch` and `useConfirm`'s `typedMatch`.
1236
+ *
1237
+ * - `"trim"` ignores spaces around the typed text — a phone keyboard's autocomplete
1238
+ * likes to add one. Case counts: "delete" is not "DELETE".
1239
+ * - `"exact"` compares character for character, spaces included.
1240
+ * - `"caseless"` trims AND ignores case: for an e-mail address, whose domain is
1241
+ * case-insensitive and whose local part every real mail server treats so. Both apps'
1242
+ * "type the account's address" rules (keksdose's `TYPE_EMAIL`, Kurvenschmiede's
1243
+ * `TypedConfirm`) compared `trim().toLowerCase()`, and a capital the user's keyboard
1244
+ * put at the start must not make the right row look like the wrong one.
1245
+ */
1246
+ type TypedMatch = "trim" | "exact" | "caseless";
1247
+ /** Whether `typed` repeats `target` under `mode` — see {@link TypedMatch}. Exported for
1248
+ * a caller that draws its own field (a dialog that also picks a recipient) and wants
1249
+ * the same rule as the kit's. */
1250
+ declare function typedMatches(typed: string, target: string, mode?: TypedMatch): boolean;
1251
+ /**
1252
+ * Busy-while-a-promise-runs, for an action that MAY return one: `run(result, onResolved)`
1253
+ * marks the caller pending until `result` settles, calls `onResolved` if it fulfilled,
1254
+ * and only clears the flag if it rejected — the caller shows why and the user retries.
1255
+ * Nothing runs after unmount. Shared by `DangerConfirm` and `ReauthDialog`, whose
1256
+ * contract is the same: resolve = done, reject = stay put.
1257
+ *
1258
+ * @internal
1259
+ */
1260
+ declare function usePromisePending(): {
1261
+ pending: boolean;
1262
+ run: (result: unknown, onResolved: () => void) => boolean;
1263
+ };
1264
+ /** The one word {@link CurrentPasswordInput} says on its own behalf — the
1265
+ * `dangerConfirm.password` label, shared with DangerConfirm's password field, so an
1266
+ * app translates "Password" once. */
1267
+ type CurrentPasswordInputLabels = Pick<DangerConfirmLabels, "password">;
1268
+ /**
1269
+ * Everything {@link Input} takes except what makes this field what it is: `type` is
1270
+ * always `"password"` and `autoComplete` always `"current-password"`.
1271
+ */
1272
+ interface CurrentPasswordInputProps extends Omit<InputProps, "type" | "autoComplete" | "label"> {
1273
+ /**
1274
+ * The visible label. Default `dangerConfirm.password` ("Password") — unless the field
1275
+ * is named another way (`aria-label` / `aria-labelledby`), which then stays the only
1276
+ * name. Pass the app's own word on a sign-in form ("Password", "Your password"), or
1277
+ * `null` for a field whose `<label htmlFor>` is drawn elsewhere (a form library's
1278
+ * `FormLabel`), which would otherwise be labelled twice.
1279
+ */
1280
+ label?: ReactNode;
1281
+ /** The value as a string — the `(next) => …` shape, so a caller holding it in
1282
+ * `useState` need not unwrap `event.target.value`. Fires alongside `onChange`,
1283
+ * never instead of it, so a form library's `onChange` keeps working. */
1284
+ onValueChange?: (value: string) => void;
1285
+ /**
1286
+ * A check is running (the sign-in request, the re-auth). The field turns `readOnly`,
1287
+ * NOT `disabled`: the field being submitted is usually the focused one (Enter was
1288
+ * pressed in it), and disabling a focused field drops focus to `<body>` — the user
1289
+ * lands nowhere when the "wrong password" answer comes back.
1290
+ */
1291
+ busy?: boolean;
1292
+ /** Per-instance override of `dangerConfirm.password`. */
1293
+ labels?: Partial<CurrentPasswordInputLabels>;
1294
+ }
1295
+ /**
1296
+ * The "prove it is you" field: a password input that a password manager fills with
1297
+ * the CURRENT password and never offers to generate a new one for.
1298
+ *
1299
+ * It is the field of a sign-in form, a re-auth step ({@link ReauthDialog} draws the same
1300
+ * field), and {@link DangerConfirm}'s `requirePassword`. Public since 0.22 for kastlan's
1301
+ * sign-in and re-auth (kastlan 1), which wrote `type="password"` +
1302
+ * `autoComplete="current-password"` by hand — and a sign-in field that forgets the
1303
+ * second half gets the browser's "suggest a strong password" offer on the one form where
1304
+ * a NEW password is never what is wanted. The reverse matters as much: a field that sets
1305
+ * a NEW password (a passphrase, a sign-up) must NOT be this one — keksdose #170 keeps
1306
+ * its passphrase doors on `new-password` / `off` for that reason.
1307
+ *
1308
+ * Everything else is {@link Input}: the reveal toggle, `error` (under the field,
1309
+ * `aria-describedby`, `aria-invalid`), `invalid`, `name`, `id`, `autoFocus`, `required`.
1310
+ * The ref is the `<input>`, so it works with `@eifi1/ui-kit/rhf`'s `FormControl` /
1311
+ * a `register()` spread, and controlled or uncontrolled.
1312
+ *
1313
+ * ```tsx
1314
+ * <CurrentPasswordInput name="password" label={t("password")} error={errors.password?.message}
1315
+ * busy={isSubmitting} {...register("password")} />
1316
+ * ```
1317
+ */
1318
+ declare const CurrentPasswordInput: react.ForwardRefExoticComponent<CurrentPasswordInputProps & react.RefAttributes<HTMLInputElement>>;
1319
+ /** The words {@link TypedConfirmField} says on its own behalf — the `dangerConfirm`
1320
+ * namespace's `phrase` and `phrasePlaceholder`, shared with DangerConfirm's own field,
1321
+ * so the sentence "Type “X” to confirm" is translated once. */
1322
+ type TypedConfirmFieldLabels = Pick<DangerConfirmLabels, "phrase" | "phrasePlaceholder">;
1323
+ interface TypedConfirmFieldProps extends Omit<InputProps, "type" | "value" | "defaultValue" | "label" | "placeholder"> {
1324
+ /** The text to repeat — a word ("DELETE"), a name, an e-mail address. */
1325
+ target: string;
1326
+ /** How the typed text is compared with `target` — {@link TypedMatch}. Default
1327
+ * `"trim"`, as {@link typedMatches}; `"caseless"` for an address or an
1328
+ * acknowledgement word a user may type in any case. */
1329
+ match?: TypedMatch;
1330
+ /** Controlled value. Left out, the field keeps its own (start: `defaultValue`). */
1331
+ value?: string;
1332
+ defaultValue?: string;
1333
+ /** The typed text as a string, on every keystroke. Fires alongside `onChange`. */
1334
+ onValueChange?: (value: string) => void;
1335
+ /**
1336
+ * The typed text started or stopped matching `target` — fired from the keystroke
1337
+ * that flipped it, so an uncontrolled field can still drive the button it guards. A
1338
+ * controlled caller that resets the value itself (on a close) knows the answer
1339
+ * already, and gets no call for that; it can also compute it with {@link typedMatches}.
1340
+ */
1341
+ onMatchedChange?: (matched: boolean) => void;
1342
+ /** The label. Default `dangerConfirm.phrase(target)` — "Type “DELETE” to confirm". */
1343
+ label?: ReactNode;
1344
+ /** Text inside the empty field. Default `dangerConfirm.phrasePlaceholder` (unset).
1345
+ * Given, the label moves ABOVE the field: a floating label occupies the empty
1346
+ * field, which is exactly where a placeholder shows. `""` means none. */
1347
+ placeholder?: string;
1348
+ /** The guarded action is running: the field turns `readOnly` (not `disabled`, which
1349
+ * would drop the focus Enter left in it). */
1350
+ busy?: boolean;
1351
+ labels?: Partial<TypedConfirmFieldLabels>;
1352
+ }
1353
+ /**
1354
+ * The "type this to confirm" field — {@link DangerConfirm}'s `phrase` field and
1355
+ * `useConfirm({ requireTyped })`'s, on its own (keksdose K7).
1356
+ *
1357
+ * keksdose writes it by hand four times: the privacy enrol, upgrade and sweep dialogs
1358
+ * (type the acknowledgement word, then the key doors appear) and the admin's "type the
1359
+ * user's address" (`UserActionConfirm`), each an `Input` plus its own
1360
+ * `trim().toUpperCase()` / `toLowerCase()` comparison. None of those places is an
1361
+ * arm → confirm tile or a modal confirm — what is guarded is a whole form, or the
1362
+ * next step of a dialog — so the field had to stand alone. What it brings over a plain
1363
+ * `Input`: one match rule ({@link typedMatches}, which lower-cases locale-independently
1364
+ * on purpose), the label worded from the target in the app's language, and the
1365
+ * attributes a phone keyboard needs to leave the text alone (no autocomplete, no
1366
+ * auto-capital, no autocorrect, no spellcheck — a keyboard that "corrects" an e-mail
1367
+ * address makes the guard unpassable).
1368
+ *
1369
+ * The field reports whether it matches (`onMatchedChange`, and `data-matched` on the
1370
+ * `<input>` for styling); what the match unlocks is the caller's. The ref is the
1371
+ * `<input>`.
1372
+ *
1373
+ * ```tsx
1374
+ * const [ok, setOk] = useState(false);
1375
+ * <TypedConfirmField target={t("privacy.enroll_ack_word")} match="caseless" onMatchedChange={setOk} />
1376
+ * {ok && <KeyDoorsForm … />}
1377
+ * ```
1378
+ */
1379
+ declare const TypedConfirmField: react.ForwardRefExoticComponent<TypedConfirmFieldProps & react.RefAttributes<HTMLInputElement>>;
1380
+ /**
1381
+ * Every string the tile renders — the `dangerConfirm` namespace of
1382
+ * `<UiKitProvider labels>`, overridable per instance through `labels`. The arm and
1383
+ * confirm buttons are usually worded per action ("Delete budget"), which is what the
1384
+ * `armLabel` / `confirmLabel` props are for; these are the fallbacks.
1385
+ */
1386
+ interface DangerConfirmLabels {
1387
+ /** The button that arms the tile. */
1388
+ arm: string;
1389
+ /** The button that runs the action once the guards are satisfied. */
1390
+ confirm: string;
1391
+ cancel: string;
1392
+ /** The warning above the fields, when no `prompt` is given. */
1393
+ prompt: string;
1394
+ /** Label of the password field (`requirePassword`). */
1395
+ password: string;
1396
+ /** Label of the type-to-confirm field. A FUNCTION of the phrase by default, like
1397
+ * every message that carries a value: where the phrase sits in the sentence moves
1398
+ * with the language. A plain STRING is taken as the finished label — for an app
1399
+ * whose catalogue already words it ("Type DELETE to confirm") and would otherwise
1400
+ * wrap it as `() => label`. */
1401
+ phrase: string | ((phrase: string) => string);
1402
+ /** Placeholder of the type-to-confirm field — a string, or a function of the
1403
+ * phrase (`(p) => p` echoes it). Optional and unset by default: the field keeps its
1404
+ * floating label, as before. Given, the label moves ABOVE the field (a floating
1405
+ * label occupies the empty field, which is exactly where a placeholder shows) and
1406
+ * the placeholder fills the field. An empty string means none. */
1407
+ phrasePlaceholder?: string | ((phrase: string) => string);
1408
+ /** 0.22: the checkbox `requireAcknowledge={true}` shows — "I have read what this does
1409
+ * and want to continue" (keksdose's `admin.users.confirm_ack`). */
1410
+ acknowledge: string;
1411
+ /**
1412
+ * 0.23: why the armed confirm is held while the typed phrase does not match yet — in
1413
+ * the confirm's tooltip and its description (keksdose G4a). A FUNCTION of the phrase
1414
+ * by default ("Type “DELETE” to confirm"), or a finished STRING, as `phrase`.
1415
+ */
1416
+ needsPhrase: string | ((phrase: string) => string);
1417
+ /** 0.23: why the armed confirm is held while the `requireAcknowledge` box is unticked
1418
+ * — "Tick the box to confirm". */
1419
+ needsAcknowledge: string;
1420
+ /** 0.23: why the armed confirm is held while the `requirePassword` field is empty —
1421
+ * "Enter your password to confirm". */
1422
+ needsPassword: string;
1423
+ }
1424
+ /** `satisfies` rather than a type annotation, so `DEFAULT_DANGER_CONFIRM_LABELS.phrase`
1425
+ * stays callable for a caller that composes its own label from it. */
1426
+ declare const DEFAULT_DANGER_CONFIRM_LABELS: {
1427
+ arm: string;
1428
+ confirm: string;
1429
+ cancel: string;
1430
+ prompt: string;
1431
+ password: string;
1432
+ phrase: (phrase: string) => string;
1433
+ acknowledge: string;
1434
+ needsPhrase: (phrase: string) => string;
1435
+ needsAcknowledge: string;
1436
+ needsPassword: string;
1437
+ };
1438
+ /**
1439
+ * What the guards were answered with — the second argument of
1440
+ * {@link DangerConfirmProps.onConfirm} (0.23, keksdose G4b). A key is there only when its
1441
+ * guard was asked for, so the object can go into a request body as it is.
1442
+ */
1443
+ interface DangerConfirmValues {
1444
+ /**
1445
+ * The text typed into the `phrase` field — as the match rule compared it: trimmed
1446
+ * under `phraseMatch` `"trim"` and `"caseless"` (the spaces a phone keyboard adds are
1447
+ * not part of it), exactly as typed under `"exact"`. The case is the user's, even
1448
+ * under `"caseless"`: a server that re-checks applies its own rule to it. Absent
1449
+ * without a `phrase`.
1450
+ */
1451
+ typed?: string;
1452
+ /** The entered password — the same value as the first argument. Absent without
1453
+ * `requirePassword`. */
1454
+ password?: string;
1455
+ /** `true` when the `requireAcknowledge` box was shown — it was ticked, since the
1456
+ * confirm is held until it is. Absent without one. */
1457
+ acknowledged?: true;
1458
+ }
1459
+ /**
1460
+ * One line of {@link DangerConfirmProps.consequences}: what the action will do. A plain
1461
+ * string, or this, for a key of its own and the `severe` mark.
1462
+ */
1463
+ interface DangerConsequence {
1464
+ /** React key — keksdose keys its lines by what they say ("api_tokens", "only_door").
1465
+ * Default: the text when it is a string, else the position. */
1466
+ key?: string;
1467
+ text: ReactNode;
1468
+ /** "There is no way back" — painted in the danger colour rather than the list's
1469
+ * muted one. keksdose reserves it for the one line that loses something for good. */
1470
+ severe?: boolean;
1471
+ }
1472
+ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onChange"> {
1473
+ /**
1474
+ * Runs the action, with the entered password when `requirePassword` is on.
1475
+ *
1476
+ * Return a promise and the tile manages itself: busy until it settles, disarmed
1477
+ * (fields wiped) when it resolves, still armed when it rejects — so the user can
1478
+ * correct a wrong password and retry. The rejection is not swallowed for you to
1479
+ * miss: handle it (and show why) in the caller, as with any mutation.
1480
+ *
1481
+ * 0.23: the second argument is what every guard was answered with — the typed phrase,
1482
+ * the password, the tick ({@link DangerConfirmValues}). keksdose G4b: its admin
1483
+ * actions send the address the admin TYPED, and the server re-checks it against the
1484
+ * account (`assert_confirmed`), so a client that put the wrong row's id in the request
1485
+ * is refused rather than obeyed; the tile kept the text to itself.
1486
+ *
1487
+ * onConfirm={(_password, { typed }) =>
1488
+ * reset.mutateAsync({ id, confirm: { acknowledged: true, confirm_email: typed ?? null } })}
1489
+ *
1490
+ * A second argument rather than one object in place of the password: every
1491
+ * `(password) => …` and `() => …` handler, and a `mutation.mutate` passed as it is,
1492
+ * keeps working unchanged, and a handler that needs one guard's answer names it.
1493
+ */
1494
+ onConfirm: (password: string | undefined, values: DangerConfirmValues) => void | Promise<unknown>;
1495
+ /** Show a password field; confirm is held until it is filled. */
1496
+ requirePassword?: boolean;
1497
+ /**
1498
+ * Show an "I understand" checkbox; confirm is held until it is ticked
1499
+ * (keksdose K7). `true` words it with `labels.acknowledge`; any other node IS the
1500
+ * checkbox's label ("I understand Anna will be signed out everywhere").
1501
+ *
1502
+ * The guard for an action whose risk is MIS-TARGETING less than carelessness:
1503
+ * keksdose's admin password reset asks for a typed address when the account has an
1504
+ * encrypted door to lose, and a tick otherwise (`UserActionConfirm`), and its plan
1505
+ * editor asks for the tick alone (`UserPlanEditor`). Both were hand-built beside this
1506
+ * tile because it had no tick. It combines with `phrase` and `requirePassword`: every
1507
+ * guard given must be satisfied.
1508
+ */
1509
+ requireAcknowledge?: ReactNode;
1510
+ /**
1511
+ * What the action will do, said before it happens — a list under the prompt, shown
1512
+ * once armed (keksdose K7, `UserActionConfirm`'s consequences). Strings, or
1513
+ * {@link DangerConsequence}s for a `severe` line in the danger colour.
1514
+ *
1515
+ * Derive them from the row's own facts rather than reciting the worst case: an admin
1516
+ * who reads the same paragraph on every row stops reading it (keksdose dev#488).
1517
+ */
1518
+ consequences?: readonly (string | DangerConsequence)[];
1519
+ /** Show a "type <phrase> to confirm" field; confirm is held until the field matches
1520
+ * (case-sensitive; surrounding spaces ignored unless `phraseMatch="exact"`). */
1521
+ phrase?: string;
1522
+ /**
1523
+ * How the typed text is compared with `phrase`. `"trim"` (default) ignores spaces
1524
+ * around it — a phone keyboard's autocomplete likes to add one. `"exact"` compares
1525
+ * character for character, spaces included, for an app whose contract is "type
1526
+ * exactly this". `"caseless"` (0.18) also ignores case — for a phrase that is an
1527
+ * e-mail address (keksdose's "type the user's address" admin rule). See
1528
+ * {@link TypedMatch}.
1529
+ */
1530
+ phraseMatch?: TypedMatch;
1531
+ /** The warning above the fields. Defaults to `labels.prompt`. */
1532
+ prompt?: ReactNode;
1533
+ /** `"danger"` (default) for what cannot be undone; `"warning"` for what can, at a
1534
+ * cost (loading demo data over your own). Colours the prompt and the confirm. */
1535
+ tone?: "danger" | "warning";
1536
+ /** Visible text of the arm button; defaults to `labels.arm`. */
1537
+ armLabel?: ReactNode;
1538
+ /** Visible text of the confirm button; defaults to `labels.confirm`. */
1539
+ confirmLabel?: ReactNode;
1540
+ /** The action is running: confirm shows a spinner and nothing can be pressed. For a
1541
+ * caller that tracks the mutation itself (a `useMutation`'s `isPending`); a
1542
+ * promise returned from `onConfirm` does the same on its own. */
1543
+ busy?: boolean;
1544
+ /** The arm button is disabled. */
1545
+ disabled?: boolean;
1546
+ /**
1547
+ * Why the action is not available — a read-only demo, a write lock, a missing
1548
+ * permission. Disables the arm button like `disabled`, and SAYS so: the sentence is
1549
+ * shown under the button and attached to it with `aria-describedby`, and the button
1550
+ * stays focusable (`aria-disabled`) so a keyboard user can land on it and hear why.
1551
+ *
1552
+ * On the ARM button rather than the confirm: arming asks for a password, and asking
1553
+ * for a password for a write that can never land is the worse of the two. A tile that
1554
+ * is ALREADY armed when the reason arrives (controlled `armed`, or a lock that landed
1555
+ * while it was open) keeps its fields but its confirm takes the reason the same way
1556
+ * — focusable, `aria-disabled`, the reason in its tooltip — and Enter does nothing.
1557
+ */
1558
+ lockedReason?: ReactNode;
1559
+ /**
1560
+ * This tile COMMITS — the 0.18 write-lock opt-in that {@link Button} has (keksdose
1561
+ * K3). Under a locked {@link WriteLockProvider} the lock's reason becomes
1562
+ * `lockedReason` (and wins over one of the tile's own), so a page that mounts the
1563
+ * provider no longer threads `lockedReason={lock.locked ? lock.reason : undefined}`
1564
+ * into every tile. No provider, or an unlocked one: no effect.
1565
+ */
1566
+ commit?: boolean;
1567
+ /** Controlled armed state. The parent can then collapse the tile from a mutation's
1568
+ * own `onSuccess` without returning a promise. */
1569
+ armed?: boolean;
1570
+ /** Called with the next armed state — on arm, cancel, and a resolved `onConfirm`. */
1571
+ onArmedChange?: (armed: boolean) => void;
1572
+ /** User-facing strings; see {@link DangerConfirmLabels}. */
1573
+ labels?: Partial<DangerConfirmLabels>;
1574
+ }
1575
+ /**
1576
+ * An "arm → confirm" tile for destructive actions: one button, which expands into a
1577
+ * warning, an optional list of consequences, an optional "I understand" tick, an
1578
+ * optional type-to-confirm field, an optional password field and a confirm that is held
1579
+ * until every guard is satisfied.
1580
+ *
1581
+ * A held confirm SAYS which guard is still open (0.23, keksdose G4a): it is
1582
+ * `aria-disabled` rather than `disabled` — still focusable, so a keyboard user can land
1583
+ * on it — with the reason in the kit {@link Tooltip} and its description ("Type
1584
+ * “DELETE” to confirm", "Tick the box to confirm", "Enter your password to confirm";
1585
+ * `labels.needs*`), the first open guard in the order they are drawn. FormActions'
1586
+ * `submitDisabledReason` does the same for a form's Save. Pressing it, or Enter in a
1587
+ * field, does nothing. A lock's reason wins over a guard's; while the action runs the
1588
+ * confirm is plainly disabled, its spinner saying why.
1589
+ *
1590
+ * Keksdose hand-rolled it three times (load demo data, wipe everything, reset a
1591
+ * budget) and then as `shared/components/danger-confirm.tsx`; the only app-specific
1592
+ * part was its write-lock hook, which is `lockedReason` here.
1593
+ *
1594
+ * The fields are a `<form>`, so Enter confirms once the guards allow it. They are
1595
+ * wiped every time the tile disarms — a password must not sit in a collapsed tile.
1596
+ * Arming moves focus to the first field (or Cancel, when there is none — never to the
1597
+ * destructive button itself), and disarming moves it back to the arm button, so the
1598
+ * keyboard user is never left on an element that just vanished.
1599
+ */
1600
+ declare function DangerConfirm({ onConfirm, requirePassword, requireAcknowledge, consequences, phrase, phraseMatch, prompt, tone, armLabel, confirmLabel, busy: busyProp, disabled, lockedReason: ownLockedReason, commit, armed: armedProp, onArmedChange, labels: labelsProp, className, ...rest }: DangerConfirmProps): react.JSX.Element;
1601
+
1167
1602
  /**
1168
1603
  * A button that opens the file picker — the shape all three apps kept writing by hand
1169
1604
  * as a `<Button>` plus a hidden `<input type="file">` plus a ref between them (seven
@@ -1361,6 +1796,22 @@ interface FileButtonProps extends Omit<UseFilePickerOptions, "disabled">, Omit<B
1361
1796
  * file leaves it as it was. Off by default, so the button's layout is unchanged.
1362
1797
  */
1363
1798
  showFileName?: boolean;
1799
+ /**
1800
+ * Why picking is not available — {@link Button}'s `disabledReason`, with the picker's
1801
+ * half added (keksdose K3): the button is `aria-disabled` but stays focusable, the
1802
+ * reason is in the kit Tooltip and its description, a click opens no picker, and a
1803
+ * `droppable` button takes no drop (the drag is still cancelled, so the browser does
1804
+ * not navigate to the file). Wins over `disabled`, as on Button.
1805
+ */
1806
+ disabledReason?: ReactNode;
1807
+ /**
1808
+ * This pick COMMITS — an upload that starts on pick, an attachment saved at once.
1809
+ * Under a locked {@link WriteLockProvider} it takes the `disabledReason` path with
1810
+ * the lock's reason (which wins over one of its own). No provider, or an unlocked
1811
+ * one: no effect. A picker that only fills a form the user saves later is not a
1812
+ * commit, and is left live — the form's Save carries the lock.
1813
+ */
1814
+ commit?: boolean;
1364
1815
  }
1365
1816
  /**
1366
1817
  * {@link useFilePicker} behind a {@link Button}: `variant` and every other button prop
@@ -1376,6 +1827,471 @@ interface FileButtonProps extends Omit<UseFilePickerOptions, "disabled">, Omit<B
1376
1827
  */
1377
1828
  declare const FileButton: react.ForwardRefExoticComponent<FileButtonProps & react.RefAttributes<HTMLButtonElement>>;
1378
1829
 
1830
+ /**
1831
+ * The conversation under a report: who said what, when, with what attached — and the
1832
+ * box to answer in.
1833
+ *
1834
+ * Both apps had written it by hand. kastlan's feedback page grew a comment list of
1835
+ * bordered boxes with `slate-*` literals (feedback-page.tsx, "keksdose left this
1836
+ * unbuilt"), and keksdose built the same thing a second time for support
1837
+ * (support-thread.tsx) with sides, bubbles and a composer that clears only what it
1838
+ * sent. This is that second one, generalised: the kit owns the look and the
1839
+ * behaviour, the app owns the data, the upload and every word it does not share.
1840
+ *
1841
+ * **Own vs other** is the caller's per message (`own`), not a comparison the kit makes
1842
+ * against a user id: whose message sits at the END side depends on who is reading,
1843
+ * and only the app knows that (keksdose's support thread labelled a member's question
1844
+ * "Du" in the admin panel the first time round, by reading the wrong field).
1845
+ *
1846
+ * **Redaction.** A thread is somebody's words about their own data — exactly what a
1847
+ * host's demo / screen-share mode blurs. Bodies, authors and attachments carry
1848
+ * `data-private` (the attribute `Tooltip redact` and `StatTile sensitive` use) unless
1849
+ * `redact={false}`.
1850
+ *
1851
+ * **RTL.** Sides are logical — `justify-end` is the reading end, and the bubble's
1852
+ * tucked corner is `rounded-ee` / `rounded-es` — and each body is `dir="auto"`, so a
1853
+ * Hebrew reply in an English thread (or the reverse) lays out as its own language.
1854
+ *
1855
+ * **A chat, too** (keksdose G4/G5). keksdose's support chat is the same conversation
1856
+ * read the chat way: status lines between the messages ("Closed automatically",
1857
+ * "Reopened"), a day line where the date changes, clock times under it, Enter to send
1858
+ * and several files uploaded ahead of the send. Each of those is an opt-in here
1859
+ * (`kind: "event"`, `daySeparators`, `timeFormat="clock"`, `sendOn="enter"`,
1860
+ * `attachmentSlot` + `canSend`), so the feedback thread's defaults stay as they were.
1861
+ */
1862
+ /** The `feedbackThread` namespace of `<UiKitProvider labels>`. */
1863
+ interface FeedbackThreadLabels {
1864
+ /** Accessible name of the message list. */
1865
+ thread: string;
1866
+ empty: string;
1867
+ loading: string;
1868
+ /** Author line of an `own` message that has no `author` of its own. */
1869
+ you: string;
1870
+ /** The badge beside a `staff` author. */
1871
+ staff: string;
1872
+ /** Accessible name of a message's attachment list. */
1873
+ attachments: string;
1874
+ }
1875
+ declare const DEFAULT_FEEDBACK_THREAD_LABELS: FeedbackThreadLabels;
1876
+ /** The `feedbackComposer` namespace of `<UiKitProvider labels>`. The attach buttons'
1877
+ * words are `feedbackAttachment`'s, shared with the dialog and the note editor. */
1878
+ interface FeedbackComposerLabels {
1879
+ /** Accessible name of the text box. */
1880
+ field: string;
1881
+ placeholder: string;
1882
+ send: string;
1883
+ /** The shortcut line, given the platform's modifier ("Ctrl" or "⌘"). */
1884
+ sendHint: (modifier: string) => string;
1885
+ /** The shortcut line under `sendOn="enter"` (keksdose G5): Enter sends, so say how a
1886
+ * new line is made. */
1887
+ sendHintEnter: string;
1888
+ }
1889
+ declare const DEFAULT_FEEDBACK_COMPOSER_LABELS: FeedbackComposerLabels;
1890
+ interface FeedbackThreadAttachment {
1891
+ id?: string | number;
1892
+ name: string;
1893
+ /** Where to open it. Left out, the attachment is listed by name only. */
1894
+ url?: string;
1895
+ /** MIME type; an `image/*` with a `url` is shown as a thumbnail. */
1896
+ type?: string;
1897
+ /** Bytes, shown beside a non-image. */
1898
+ size?: number;
1899
+ }
1900
+ interface FeedbackThreadMessage {
1901
+ /** Leave out, or `"message"`. `"event"` is a {@link FeedbackThreadEvent}. */
1902
+ kind?: "message";
1903
+ id: string | number;
1904
+ /** Who wrote it. Left out on an `own` message, it reads "You". */
1905
+ author?: ReactNode;
1906
+ /** A `Date`, an ISO string or epoch ms. */
1907
+ createdAt: Date | string | number;
1908
+ body: string;
1909
+ attachments?: readonly FeedbackThreadAttachment[];
1910
+ /** Written by whoever is reading: sits at the end side, in the brand tint. */
1911
+ own?: boolean;
1912
+ /** Written by the team rather than a user: gets the "Staff" badge. */
1913
+ staff?: boolean;
1914
+ }
1915
+ /**
1916
+ * A line in the thread that nobody wrote — "Closed automatically", "Marked as
1917
+ * resolved", "Reopened" — drawn centred and muted with its time, no author, no side,
1918
+ * no bubble.
1919
+ *
1920
+ * keksdose G4: its support chat interleaves these with the messages, and as a message
1921
+ * they came out as a bubble from nobody at the start side, which reads as the member
1922
+ * having said "resolved". Word it for the READER, as with `own`: the app knows whether
1923
+ * "you reopened it" or "Anna reopened it" is true for the person looking.
1924
+ *
1925
+ * The text is the app's, not somebody's words about their data, so it is NOT tagged
1926
+ * `data-private`; one that names a person can wrap the name in its own
1927
+ * `<span data-private>` (`body` is a node for that reason).
1928
+ */
1929
+ interface FeedbackThreadEvent {
1930
+ kind: "event";
1931
+ id: string | number;
1932
+ /** A `Date`, an ISO string or epoch ms. */
1933
+ createdAt: Date | string | number;
1934
+ body: ReactNode;
1935
+ }
1936
+ /** One row of a {@link FeedbackThread}: a message, or an event line between them. */
1937
+ type FeedbackThreadItem = FeedbackThreadMessage | FeedbackThreadEvent;
1938
+ interface FeedbackThreadProps {
1939
+ /** Oldest first. Event lines ({@link FeedbackThreadEvent}) sit among the messages. */
1940
+ messages: readonly FeedbackThreadItem[];
1941
+ loading?: boolean;
1942
+ /** Replaces the default "No comments yet". */
1943
+ empty?: ReactNode;
1944
+ /**
1945
+ * Draw one attachment yourself — for files behind auth, which a plain `<img src>`
1946
+ * cannot fetch (kastlan's `AuthedImage`), or a lightbox. The default is a thumbnail
1947
+ * link for an image with a `url`, a file link otherwise.
1948
+ */
1949
+ renderAttachment?: (attachment: FeedbackThreadAttachment, message: FeedbackThreadMessage) => ReactNode;
1950
+ /** Tag bodies, authors and attachments `data-private`. Default true. */
1951
+ redact?: boolean;
1952
+ /**
1953
+ * How a row's time reads. `"relative"` (default): "5 minutes ago", a date past six
1954
+ * days — right for a report's comments, read days apart. `"clock"`: the time of day
1955
+ * in the locale ("14:05", "2:05 PM") — the chat look, keksdose G4; pair it with
1956
+ * `daySeparators`, which say which day that clock time is on. Either way the full
1957
+ * date and time is in the Tooltip.
1958
+ */
1959
+ timeFormat?: "relative" | "clock";
1960
+ /**
1961
+ * A centred day line before the first row and wherever the next row is on another
1962
+ * calendar day (the device's zone): "Today", "Yesterday", else the date — keksdose
1963
+ * G4. "Today" / "Yesterday" are `Intl.RelativeTimeFormat`'s own words in the kit
1964
+ * locale, so there is no label to translate. Default false.
1965
+ */
1966
+ daySeparators?: boolean;
1967
+ /** "Now" for the relative times and the day lines — pin it in tests and stories.
1968
+ * Default: the clock. */
1969
+ now?: Date | number;
1970
+ /** Overrides the provider's locale for the times. */
1971
+ locale?: string;
1972
+ labels?: Partial<FeedbackThreadLabels>;
1973
+ className?: string;
1974
+ }
1975
+ declare function FeedbackThread({ messages, loading, empty, renderAttachment, redact, now, locale: localeProp, timeFormat, daySeparators, labels: labelsProp, className, }: FeedbackThreadProps): react.JSX.Element;
1976
+ /** What the composer's attach control takes — {@link FeedbackNoteAttachment} with the
1977
+ * labels optional, since the field reads `feedbackAttachment` from the provider, and
1978
+ * `onError` the field's own (0.23.0): it is handed the refused file and the limit too
1979
+ * (`FeedbackAttachmentErrorInfo`), and a `(kind) => …` handler still fits. */
1980
+ type FeedbackComposerAttachment = Omit<FeedbackNoteAttachment, "labels" | "onError"> & {
1981
+ labels?: Partial<FeedbackAttachmentLabels>;
1982
+ onError?: FeedbackAttachmentFieldSingleProps["onError"];
1983
+ };
1984
+ interface FeedbackComposerProps {
1985
+ /**
1986
+ * Send the comment. Return the promise: the box clears when it RESOLVES, and only of
1987
+ * what was sent — text typed while it was in flight stays. A rejection keeps
1988
+ * everything for a retry (surface the error yourself; the composer stays quiet).
1989
+ *
1990
+ * `attachment` is the built-in field's one picture. Files the host uploaded ahead
1991
+ * (`attachmentSlot`) are the host's state, read by the host here — and `body` may be
1992
+ * `""` when `canSend` let an attachments-only message go.
1993
+ */
1994
+ onSend: (body: string, attachment: File | null) => void | Promise<unknown>;
1995
+ /** The send is in flight: a spinner on the button and no second send. */
1996
+ pending?: boolean;
1997
+ /** Offer one picture with the comment (file, paste or `onCaptureScreenshot`).
1998
+ * `true` for the defaults. Left out, the composer is text only. */
1999
+ attachment?: boolean | FeedbackComposerAttachment;
2000
+ /**
2001
+ * The host's own attach control, in the row with Send where the built-in field sits
2002
+ * (after it, if both are on) — keksdose G5: its support chat uploads up to N files
2003
+ * AHEAD of the send and sends their refs, which one `File` in `onSend` cannot carry.
2004
+ * The slot is the host's picker plus the chips of what is uploaded; the upload, the
2005
+ * refs and clearing them once `onSend` resolves stay with the host. Pair it with
2006
+ * `canSend`.
2007
+ */
2008
+ attachmentSlot?: ReactNode;
2009
+ /**
2010
+ * Whether Send is enabled, over the composer's own rule (some text in the box) —
2011
+ * for state the composer cannot see, i.e. `attachmentSlot`'s (keksdose G5): `true`
2012
+ * with files ready makes an empty draft sendable (`onSend("", null)`), `false` while
2013
+ * an upload is still running holds even a written reply back. Left out, the text
2014
+ * decides. `pending` blocks a send either way, as does a draft past `maxLength`.
2015
+ */
2016
+ canSend?: boolean;
2017
+ /**
2018
+ * Which key sends. `"mod-enter"` (default): Ctrl/⌘+Enter, the report dialog's and
2019
+ * note editor's shortcut, with plain Enter a new line — feedback is written in
2020
+ * paragraphs. `"enter"`: the chat way (keksdose G5) — Enter sends, Shift+Enter is a
2021
+ * new line, Ctrl/⌘+Enter still sends; an Enter that confirms an IME composition
2022
+ * (Japanese, Chinese input) is the IME's, never a send.
2023
+ */
2024
+ sendOn?: "mod-enter" | "enter";
2025
+ /** Rendered INSTEAD of the composer — the thread is closed, or read-only for this
2026
+ * reader. */
2027
+ disabledReason?: ReactNode;
2028
+ rows?: number;
2029
+ /**
2030
+ * The longest draft the box takes, in UTF-16 code units as the browser counts — the
2031
+ * server's limit, so a reply too long for it is cut off while it is typed rather than
2032
+ * refused by a 422 after the press (keksdose G6: its support replies are capped at
2033
+ * 4,000 on the server, and its other text fields already count against that with
2034
+ * Textarea's `maxLength` + `showCount` since 0.22; the reply box, a composer, could
2035
+ * not). The box's own `maxLength`, so typing and pasting stop at it.
2036
+ *
2037
+ * {@link FeedbackComposerHandle.insertText} is not stopped by it — the browser limits
2038
+ * typing, not a script — and a canned reply is not cut mid-sentence to fit. A draft
2039
+ * past the limit therefore holds Send back (whatever `canSend` says, as `pending`
2040
+ * does) until it is trimmed; with `showCount` the counter, red at the limit, says by
2041
+ * how much.
2042
+ */
2043
+ maxLength?: number;
2044
+ /**
2045
+ * A live "12/4000" under the box, with `maxLength` — Textarea's `showCount`, the same
2046
+ * counter (keksdose G6): the count is part of the box's description, read with it on
2047
+ * focus, and a polite live region speaks only on entering the last stretch and at the
2048
+ * limit, never per keystroke. Under `size="sm"` the hidden send hint stays the box's
2049
+ * description too, before the count. Ignored without `maxLength`.
2050
+ */
2051
+ showCount?: boolean;
2052
+ /** The counter's words — the `characterCount` namespace, as on Textarea. */
2053
+ countLabels?: Partial<CharacterCountLabels>;
2054
+ /**
2055
+ * The box's hint, over the `placeholder` label — keksdose F9: an admin answering a
2056
+ * support ticket is asked something else ("Reply to Anna…") than a member adding to
2057
+ * their own report, and one provider-wide label cannot say both.
2058
+ */
2059
+ placeholder?: string;
2060
+ /**
2061
+ * The draft, controlled — for a host that keeps it itself (saves it per ticket,
2062
+ * prefills a template). Left out, the composer keeps its own. Either way a send
2063
+ * that resolves clears only what was sent: controlled, that is an
2064
+ * `onValueChange("")` the host receives like any keystroke, and only if the draft
2065
+ * is still the one that went out.
2066
+ */
2067
+ value?: string;
2068
+ /** Every change to the draft — typing, {@link FeedbackComposerHandle.insertText}, the
2069
+ * clear after a send. Required to change a controlled `value`. */
2070
+ onValueChange?: (value: string) => void;
2071
+ /** {@link FeedbackComposerHandle}: put text into the draft from outside (canned-reply
2072
+ * chips) or focus the box. */
2073
+ ref?: Ref<FeedbackComposerHandle>;
2074
+ labels?: Partial<FeedbackComposerLabels>;
2075
+ className?: string;
2076
+ /**
2077
+ * `"sm"` for a narrow host — keksdose's assistant launcher, a small floating panel
2078
+ * (0.22): a small Send button, and the send hint ("Enter to send, Shift + Enter for a
2079
+ * new line") hidden from view but kept as the box's description, so a keyboard or
2080
+ * screen-reader user still learns the shortcut. Default `"md"`.
2081
+ */
2082
+ size?: "md" | "sm";
2083
+ /**
2084
+ * On the composer's root — the box, or the `disabledReason` line in its place —
2085
+ * with any `data-*` attribute beside it (keksdose K17). keksdose's assistant tour
2086
+ * points at the chat box with `[data-tour="assistant-ask"]`, and a composer that
2087
+ * dropped every attribute it was not told about left the anchor nowhere: the
2088
+ * assistant kept its hand-built box rather than lose the tour step.
2089
+ */
2090
+ id?: string;
2091
+ /** `data-*` attributes for the root, as `id` — a tour anchor, a test id. */
2092
+ [dataAttribute: `data-${string}`]: string | number | boolean | undefined;
2093
+ }
2094
+ /**
2095
+ * What a {@link FeedbackComposer} `ref` holds.
2096
+ *
2097
+ * keksdose F9: the support admin answers the same five questions all day and wants
2098
+ * chips above the box ("Thanks, fixed in the next release") that drop their text in
2099
+ * where the caret is. A controlled `value` alone cannot do that well — the host sees
2100
+ * the string, not the caret, so it could only append — so the composer, which owns
2101
+ * the textarea, does the splice.
2102
+ */
2103
+ interface FeedbackComposerHandle {
2104
+ /**
2105
+ * Insert `text` at the caret, replacing any selection (the caret the box last had:
2106
+ * a click on a chip blurs it, and the selection survives the blur), then focus the
2107
+ * box with the caret after the inserted text so the reply can go on. Nothing is
2108
+ * added around it — put a space or a newline in `text` if the reply needs one. A
2109
+ * no-op while `disabledReason` replaces the box.
2110
+ */
2111
+ insertText: (text: string) => void;
2112
+ focus: () => void;
2113
+ }
2114
+ /**
2115
+ * The answer box under a {@link FeedbackThread}: a textarea, an optional picture,
2116
+ * and Send — Ctrl/⌘+Enter sends, the shortcut the report dialog and the note editor
2117
+ * use, so the habit carries across the feature. Plain Enter is a new line: feedback is
2118
+ * written in paragraphs, unlike a chat — which `sendOn="enter"` is for (keksdose G5).
2119
+ */
2120
+ declare function FeedbackComposer({ onSend, pending, attachment, attachmentSlot, canSend: canSendProp, sendOn, disabledReason, rows, maxLength, showCount, countLabels, placeholder, value, onValueChange, ref, labels: labelsProp, className, id, size, ...rest }: FeedbackComposerProps): react.JSX.Element;
2121
+ /**
2122
+ * {@link FeedbackComposer} under a name that is not about feedback (keksdose K17).
2123
+ *
2124
+ * The component was never feedback-specific: a textarea, an optional picture or a
2125
+ * host's upload slot, Send, `sendOn="enter"` for the chat way. keksdose's assistant
2126
+ * and support chat are chats, not reports, and an import of `FeedbackComposer` there
2127
+ * reads as a mistake to the next person. The same function, not a wrapper, so the
2128
+ * two names cannot drift.
2129
+ */
2130
+ declare const ChatComposer: typeof FeedbackComposer;
2131
+ /** {@link FeedbackComposerProps}, for {@link ChatComposer}. */
2132
+ type ChatComposerProps = FeedbackComposerProps;
2133
+ /** {@link FeedbackComposerHandle}, for {@link ChatComposer}. */
2134
+ type ChatComposerHandle = FeedbackComposerHandle;
2135
+ /** {@link FeedbackComposerLabels}, for {@link ChatComposer} — still the `feedbackComposer`
2136
+ * namespace of the provider. */
2137
+ type ChatComposerLabels = FeedbackComposerLabels;
2138
+
2139
+ /**
2140
+ * The `confirmDialog` namespace of `<UiKitProvider labels>`: the two buttons' fallback
2141
+ * text. A call that knows what it is confirming says so per call (`confirmLabel:
2142
+ * "Delete budget"`), which is what the dialog is for — these are for the rest.
2143
+ */
2144
+ interface ConfirmDialogLabels {
2145
+ confirm: string;
2146
+ cancel: string;
2147
+ /**
2148
+ * 0.18: label of the field a `requireTyped` confirm shows. A FUNCTION of the text to
2149
+ * type by default — where the address sits in the sentence moves with the language —
2150
+ * or a finished STRING. A call's own `typedLabel` wins over it.
2151
+ *
2152
+ * Required, like every key of a namespace: the shipped catalogues
2153
+ * (`@eifi1/ui-kit/i18n/<code>`) translate it, and an app's own full catalogue should
2154
+ * hear about the new string from the compiler rather than show it in English.
2155
+ */
2156
+ typed: string | ((text: string) => string);
2157
+ }
2158
+ /** `satisfies` rather than a type annotation, so `.typed` stays known-callable for a
2159
+ * caller composing its own label from it. */
2160
+ declare const DEFAULT_CONFIRM_DIALOG_LABELS: {
2161
+ confirm: string;
2162
+ cancel: string;
2163
+ typed: (text: string) => string;
2164
+ };
2165
+ type ConfirmTone = "danger" | "warning" | "neutral";
2166
+ interface ConfirmOptions {
2167
+ /** The question, and the dialog's accessible name. */
2168
+ title: ReactNode;
2169
+ /** The smaller line under it — the consequence. Wired to `aria-describedby`. */
2170
+ body?: ReactNode;
2171
+ /** Default: `confirmDialog.confirm` from the provider, else "Confirm". */
2172
+ confirmLabel?: ReactNode;
2173
+ /** Default: `confirmDialog.cancel` from the provider, else "Cancel". */
2174
+ cancelLabel?: ReactNode;
2175
+ /**
2176
+ * `"danger"` for what cannot be undone (a delete): the confirm is the destructive
2177
+ * button and focus starts on CANCEL. `"warning"` and `"neutral"` (default) start on
2178
+ * the confirm. See {@link ConfirmProvider} for why the two differ.
2179
+ */
2180
+ tone?: ConfirmTone;
2181
+ /**
2182
+ * 0.18: make the user TYPE this before confirm is enabled — the target account's
2183
+ * e-mail address, a budget's name. For the action whose risk is not "did you mean
2184
+ * it" but "is this the right row": an admin who deactivates somebody has already
2185
+ * proven who THEY are (they passed the admin gate); typing the address is what
2186
+ * proves they read which account they are on. Both keksdose (`TYPE_EMAIL`) and
2187
+ * Kurvenschmiede (`TypedConfirm`) built this beside `useConfirm` because it had no
2188
+ * field.
2189
+ *
2190
+ * The dialog then shows one text field under the body and focuses it (whatever the
2191
+ * tone: a reflexive Enter cannot confirm a field that does not match yet). Confirm
2192
+ * stays disabled until the text matches; Enter in the field confirms once it does.
2193
+ * The answer is still `true` / `false` — the text matched what you passed, so send
2194
+ * that to the server if it asks for the address too, not the user's spelling.
2195
+ */
2196
+ requireTyped?: string;
2197
+ /** Label of that field. Default: `confirmDialog.typed` — `Type “a@b.c” to confirm`. */
2198
+ typedLabel?: string;
2199
+ /**
2200
+ * How the typed text is compared. Default `"caseless"`: surrounding spaces and case
2201
+ * ignored, the rule both apps applied to an address. `"trim"` keeps case, `"exact"`
2202
+ * keeps spaces too — for a phrase like "DELETE" whose contract is "exactly this".
2203
+ */
2204
+ typedMatch?: TypedMatch;
2205
+ }
2206
+ type ConfirmFn = (options: ConfirmOptions) => Promise<boolean>;
2207
+ /**
2208
+ * `const confirm = useConfirm()` → `if (!(await confirm({ title }))) return`.
2209
+ *
2210
+ * The returned function is STABLE for the life of the provider, so it can sit in an
2211
+ * effect's or a `useCallback`'s dependency list without re-running it.
2212
+ *
2213
+ * Throws outside a {@link ConfirmProvider}, rather than falling back to
2214
+ * `window.confirm`: a silent fallback is exactly the native dialog the three apps are
2215
+ * migrating away from, and it would look like the migration had worked.
2216
+ */
2217
+ declare function useConfirm(): ConfirmFn;
2218
+ interface ConfirmProviderProps {
2219
+ children: ReactNode;
2220
+ }
2221
+ /**
2222
+ * The host for {@link useConfirm}: ONE confirm dialog for the whole app, rendered on
2223
+ * {@link DialogFrame}, answering a promise.
2224
+ *
2225
+ * Asked for by all three apps at once — keksdose has 20+ `window.confirm` calls,
2226
+ * kastlan 7, lenkbank 1. The native dialog cannot be translated past its OK/Cancel
2227
+ * (those are the BROWSER's language, not the app's), cannot say which button is the
2228
+ * destructive one, and on an installed PWA it prints the origin over the question.
2229
+ * A promise is what lets each of those call sites change by one `await`:
2230
+ *
2231
+ * if (!window.confirm(t("budget.delete_confirm"))) return;
2232
+ * // becomes
2233
+ * if (!(await confirm({ title: t("budget.delete_confirm"), tone: "danger" }))) return;
2234
+ *
2235
+ * ## Its own provider, not part of `UiKitProvider`
2236
+ *
2237
+ * `UiKitProvider` renders nothing: it is strings and a locale, it is optional, and it
2238
+ * NESTS (an inner one re-labels one table). A dialog host inside it would mount a host
2239
+ * per nested provider, and a component under the inner one would open a second dialog
2240
+ * layer of its own. So the host is its own component, mounted once — inside the
2241
+ * `UiKitProvider` whose strings it should speak, which is also the order the labels
2242
+ * need.
2243
+ *
2244
+ * ## Focus
2245
+ *
2246
+ * On CANCEL for `tone: "danger"`, on CONFIRM otherwise. A confirm is often answered by
2247
+ * a reflexive Enter — the key that pressed the Delete button in the first place may
2248
+ * still be down — and for an action that cannot be undone that reflex must land on the
2249
+ * harmless answer; `DangerConfirm` makes the same call ("never to the destructive
2250
+ * button itself"). For everything else the confirm is the expected answer and Enter
2251
+ * accepting it is what `window.confirm` taught users, which the migrating call sites'
2252
+ * users already rely on. Focus returns to whatever opened it, through `Modal`'s trap.
2253
+ *
2254
+ * ## Escape, the backdrop, Back and Cancel all answer `false`
2255
+ *
2256
+ * Only the confirm button answers `true`. Anything that merely dismisses is a no.
2257
+ *
2258
+ * ## A second `confirm` while one is open QUEUES
2259
+ *
2260
+ * It is shown when the first is answered, and each call gets its own answer. The
2261
+ * alternative — answering the open one `false` to make room — would answer a question
2262
+ * the user never answered: a background prompt ("your session is about to expire")
2263
+ * would cancel the delete they were reading. `false` has to mean "the user said no".
2264
+ * A double-click cannot queue two of the same: the first click opens the modal
2265
+ * synchronously (a discrete event's update is flushed before the next one), so the
2266
+ * second lands on the open dialog rather than on the button — at worst on its
2267
+ * backdrop, which answers `false`, the safe way to be wrong.
2268
+ *
2269
+ * Unmounting the provider answers everything still pending `false`, so no caller's
2270
+ * `await` hangs forever.
2271
+ *
2272
+ * ## keksdose's synchronous call (transaction-swipe-plan.ts)
2273
+ *
2274
+ * `buildTxSwipeActions` is synchronous, but its `window.confirm` sits inside the
2275
+ * action THUNK (`confirmed(key, run)` returns `() => { if (confirm(…)) run() }`), and a
2276
+ * thunk may be async without its caller knowing. So the plan builder stays
2277
+ * synchronous; it takes the confirm as an argument and the thunk awaits it:
2278
+ *
2279
+ * // mobile-transaction-list.tsx
2280
+ * const confirm = useConfirm();
2281
+ * buildTxSwipeActions({ tx, …, confirm });
2282
+ *
2283
+ * // transaction-swipe-plan.ts
2284
+ * const confirmed = (messageKey: string, run: () => void) => () => {
2285
+ * void confirm({ title: t(messageKey), tone: "danger" }).then((ok) => ok && run());
2286
+ * };
2287
+ *
2288
+ * Its test then passes `confirm: vi.fn(async () => false)` instead of stubbing the
2289
+ * global, and asserts after an `await` (the mutation now runs a microtask later). The
2290
+ * row snaps back when the swipe commits, before the answer — which is right: the
2291
+ * dialog, not the half-swiped row, is where the question now is.
2292
+ */
2293
+ declare function ConfirmProvider({ children }: ConfirmProviderProps): react.JSX.Element;
2294
+
1379
2295
  /** The words a copy button says. The visible three are short on purpose (they
1380
2296
  * replace the button's own text in the `label` variant); the two announcements
1381
2297
  * are the sentences a screen reader hears, since the button's focus never moves. */
@@ -1445,8 +2361,17 @@ declare function CopyButton({ text, variant, label, buttonVariant, size, tone, s
1445
2361
  interface FormActionsLabels {
1446
2362
  save: string;
1447
2363
  cancel: string;
2364
+ /**
2365
+ * The {@link FormActionsProps.submitShortcut} hint beside Save's text, when
2366
+ * {@link FormActionsProps.submitShortcutHint} shows it. `apple` is true on a Mac,
2367
+ * iPhone or iPad, where the key is Cmd: "⌘ Enter" there, "Ctrl+Enter" elsewhere
2368
+ * (a German keyboard says "Strg").
2369
+ */
2370
+ submitShortcut: (apple: boolean) => string;
1448
2371
  }
1449
2372
  declare const DEFAULT_FORM_ACTIONS_LABELS: FormActionsLabels;
2373
+ /** See {@link FormActionsProps.submitShortcut}. */
2374
+ type FormActionsSubmitShortcut = "mod-enter";
1450
2375
  type FormActionsAlign = "start" | "center" | "end" | "between";
1451
2376
  /**
1452
2377
  * Where the row sits:
@@ -1550,6 +2475,27 @@ interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "childr
1550
2475
  /** The save button's variant. Default `brand`; `danger` for a save that destroys
1551
2476
  * (kastlan's `destructive` flag on its own FormActions). */
1552
2477
  submitVariant?: ButtonVariant;
2478
+ /**
2479
+ * The Cancel button's variant. Default `secondary` (the outlined button, as before).
2480
+ * `ghost` for a row where Cancel should step back further than an outline — keksdose
2481
+ * G3: a quiet inline row (a confirm under a table row, a card's own small editor)
2482
+ * whose Cancel was a ghost button before it moved onto FormActions, which drew every
2483
+ * Cancel outlined.
2484
+ */
2485
+ cancelVariant?: ButtonVariant;
2486
+ /**
2487
+ * The size of every button the row draws itself — Save, Cancel and the
2488
+ * `{ label, onClick }` form of {@link destructive}: Button's `size`. Default `md`.
2489
+ * `sm` (12px text, `px-2 py-1`) for a dense row: a confirm inside a table's expansion
2490
+ * row, a toolbar card. keksdose G3: two such rows had small hand-built buttons and lost
2491
+ * them on adopting FormActions, which had no size. At `sm` the spinner and
2492
+ * {@link submitIcon} shrink with the text.
2493
+ *
2494
+ * Your own elements (`children`, an element passed as `destructive`, `start`) are
2495
+ * yours to size — pass them `size="sm"` too. A `size` in {@link submitProps} still
2496
+ * wins for Save, as it always has.
2497
+ */
2498
+ size?: ButtonSize;
1553
2499
  /**
1554
2500
  * A destructive action at the START of the row, apart from Save and Cancel — the
1555
2501
  * "Delete" of an edit dialog. Pass `{ label, onClick }` for the kit's quiet danger
@@ -1606,6 +2552,39 @@ interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "childr
1606
2552
  /** The `id` of the `<form>` the save button submits, when the row is rendered
1607
2553
  * outside it (a dialog's footer slot). */
1608
2554
  form?: string;
2555
+ /**
2556
+ * A keyboard shortcut that presses Save from anywhere in the form. `"mod-enter"`:
2557
+ * Ctrl+Enter, or Cmd+Enter on a Mac — both are accepted everywhere, as keksdose's
2558
+ * editors always have. keksdose K14 (inputs audit 2026-10-02, S5): its transaction
2559
+ * editor, category editor and create card each wrote this as an `onKeyDown` on a
2560
+ * container, re-stating `!pending && !saveDisabled && !lock.locked` every time, and
2561
+ * the one that forgot the lock let the demo's refused save through from the keyboard.
2562
+ *
2563
+ * What it does is what pressing Save does — the same button is clicked, so a form
2564
+ * submits with its validation and its submitter, and `onSubmit` is called in the
2565
+ * `type="button"` mode — and it does NOTHING while Save could not be pressed:
2566
+ * `pending`, `submitDisabled`, or a `commit` under a locked {@link WriteLockProvider}.
2567
+ *
2568
+ * Scoped to the form Save submits (the `form` prop's, else the enclosing `<form>`):
2569
+ * the chord counts only when the focus is inside it, so two editors on one page each
2570
+ * answer for their own fields. Without a form (an `onSubmit` row in a plain container)
2571
+ * the scope is the nearest `role="dialog"`, else the row's parent element — the
2572
+ * container the row ends.
2573
+ *
2574
+ * Listened for on the document, so it runs AFTER every React handler: a field that
2575
+ * takes Ctrl+Enter for itself calls `preventDefault()` or `stopPropagation()` and
2576
+ * the row stays out of it (keksdose live #202 — the create card's Ctrl+Shift+Enter
2577
+ * must create ONE row; the chord here is exactly Ctrl/Cmd+Enter, never with Shift or
2578
+ * Alt). Not during IME composition, and not on a held key's repeats.
2579
+ *
2580
+ * The save button announces it with `aria-keyshortcuts`; {@link submitShortcutHint}
2581
+ * also shows it.
2582
+ */
2583
+ submitShortcut?: FormActionsSubmitShortcut;
2584
+ /** Show the {@link submitShortcut} beside Save's text ("Ctrl+Enter", "⌘ Enter"; the
2585
+ * `form.submitShortcut` label), dimmed. Hidden on a touch-only device, which has no
2586
+ * keyboard to press it on. Default `false`. */
2587
+ submitShortcutHint?: boolean;
1609
2588
  /** Extra actions, placed before Cancel. */
1610
2589
  children?: ReactNode;
1611
2590
  }
@@ -1624,7 +2603,7 @@ interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "childr
1624
2603
  * The spinner is the kit's {@link Spinner}, drawn inside the button with `label={null}`
1625
2604
  * so the button's name stays its text; `aria-busy` is what says it is working.
1626
2605
  */
1627
- declare function FormActions({ onCancel, onSubmit, submitLabel, cancelLabel, pendingLabel, submitIcon: SubmitIcon, submitProps, pending, submitDisabled, submitDisabledReason, commit, submitVariant, destructive, start: startSlot, align, placement: placementProp, stickyWithin, bleed, form, children, className, style, ...rest }: FormActionsProps): react.JSX.Element;
2606
+ declare function FormActions({ onCancel, onSubmit, submitLabel, cancelLabel, pendingLabel, submitIcon: SubmitIcon, submitProps, pending, submitDisabled, submitDisabledReason, commit, submitVariant, cancelVariant, size, destructive, start: startSlot, align, placement: placementProp, stickyWithin, bleed, form, submitShortcut, submitShortcutHint, children, className, style, ...rest }: FormActionsProps): react.JSX.Element;
1628
2607
 
1629
2608
  /**
1630
2609
  * Who holds one record, and the owner's every way of changing that — Kurvenschmiede's
@@ -1806,6 +2785,147 @@ interface ShareDialogProps extends SharePanelProps, Pick<DialogFrameProps, "open
1806
2785
  */
1807
2786
  declare function ShareDialog({ open, onClose, size, className, title, description, ...panel }: ShareDialogProps): react.JSX.Element;
1808
2787
 
2788
+ /** The messages {@link IbanInput} shows under itself, one per {@link IbanProblem}. */
2789
+ interface IbanInputLabels {
2790
+ /** The value does not start with a two-letter country code and two check digits. */
2791
+ format: string;
2792
+ /** The first two letters are no country in the IBAN registry. `code` is those two
2793
+ * letters, as typed (upper case). */
2794
+ country: (code: string) => string;
2795
+ /** The wrong length for the country: `actual` characters typed, `expected` for that
2796
+ * country (spaces not counted in either). */
2797
+ length: (actual: number, expected: number) => string;
2798
+ /** The mod-97 check digits do not match — a mistyped or swapped character. */
2799
+ checksum: string;
2800
+ /** `kind="qr"`: a valid IBAN, but not a QR-IBAN. */
2801
+ qrRequired: string;
2802
+ /** `kind="plain"`: a QR-IBAN, which cannot receive an ordinary transfer. */
2803
+ qrNotAllowed: string;
2804
+ }
2805
+ declare const DEFAULT_IBAN_INPUT_LABELS: IbanInputLabels;
2806
+ interface IbanInputProps extends Omit<InputProps, "type" | "value" | "defaultValue"> {
2807
+ /** The IBAN, compact or not — it is shown in groups of four either way. `""` is
2808
+ * "no IBAN". */
2809
+ value: string;
2810
+ /** The compact, upper-case IBAN (the electronic format, what to store) on every
2811
+ * change — valid or not: a half-typed IBAN is still the field's value. Plain
2812
+ * `onChange` still fires alongside it with the raw event, whose text is the GROUPED
2813
+ * one, so bind this rather than `onChange` to a form. */
2814
+ onValueChange?: (value: string) => void;
2815
+ /** Which IBANs the field accepts. Default `"any"`. `"qr"` / `"plain"`: see
2816
+ * {@link IbanKind} — and why the difference matters, {@link isQrIban}. */
2817
+ kind?: IbanKind;
2818
+ /** The messages, per field. See {@link IbanInputLabels}. */
2819
+ labels?: Partial<IbanInputLabels>;
2820
+ /** The caller's own message, shown INSTEAD of the built-in one while it is set (a
2821
+ * server's "this account is already on file"). `null`, `false` and `""` are no
2822
+ * message, so `touched && errors.iban` can be passed as it is. */
2823
+ error?: ReactNode;
2824
+ }
2825
+ /**
2826
+ * An IBAN field (kastlan, keksdose): typed in any shape, shown in groups of four,
2827
+ * reported compact.
2828
+ *
2829
+ * Both apps had a text field and a regex. What that left out is everything between
2830
+ * the keyboard and the stored value: a pasted "ch09 0000-0000…" stayed lower case
2831
+ * with its hyphens, the grouping that makes 21 characters checkable by eye was
2832
+ * missing, and a wrong IBAN was found out by the bank. Here:
2833
+ *
2834
+ * - **Grouped as you type.** The field shows the paper format ({@link formatIban});
2835
+ * spaces, hyphens and lower case in what is typed or pasted are folded away, and
2836
+ * the caret stays between the same two characters while the groups move around it.
2837
+ * - **Compact out.** `onValueChange` gets the electronic format — upper case, no
2838
+ * spaces — which is the one to store and to compare.
2839
+ * - **Checked, never blocked.** A wrong country, length or checksum shows a message
2840
+ * under the field, through the kit's `error` (so it is the field's
2841
+ * `aria-describedby` and paints it), but every keystroke still lands: a field that
2842
+ * refuses characters cannot be corrected one character at a time. While the field
2843
+ * has focus only what more typing cannot fix is shown; the rest waits for the full
2844
+ * length or for blur. Whether the field is REQUIRED stays the form's rule — an empty
2845
+ * field says nothing.
2846
+ * - **QR-IBAN or not** (kastlan): `kind="qr"` refuses a regular IBAN and
2847
+ * `kind="plain"` refuses a QR-IBAN — a QR-bill can only be paid to a QR-IBAN, and a
2848
+ * QR-IBAN can receive nothing else. See {@link isQrIban}.
2849
+ *
2850
+ * It is {@link Input} underneath, so `label`, `hint`, `error`, `invalid` and the rest
2851
+ * are Input's own and the field reads like every other. A form that must not submit
2852
+ * an invalid IBAN checks {@link isValidIban} / {@link ibanProblem} itself — the field
2853
+ * shows the problem but does not own the submit.
2854
+ */
2855
+ declare const IbanInput: react.ForwardRefExoticComponent<IbanInputProps & react.RefAttributes<HTMLInputElement>>;
2856
+
2857
+ /** The words {@link PhoneInput} renders on its own behalf. */
2858
+ interface PhoneInputLabels {
2859
+ /** The country-code select's accessible name. */
2860
+ countryCode: string;
2861
+ /** The select's last option: a number from a country not listed, typed with its
2862
+ * own "+". */
2863
+ other: string;
2864
+ }
2865
+ declare const DEFAULT_PHONE_INPUT_LABELS: PhoneInputLabels;
2866
+ interface PhoneInputProps extends Omit<InputProps, "type" | "value" | "defaultValue"> {
2867
+ /** The number: E.164 ("+41210000001") for one the field could read, or free text —
2868
+ * a value saved before the field existed is shown exactly as it is. `""` is no
2869
+ * number. */
2870
+ value: string;
2871
+ /** On every change: E.164 when the typed text reads as a number of the selected
2872
+ * country (or carries its own "+"), otherwise the typed text UNCHANGED. Nothing is
2873
+ * refused — see {@link PhoneInput}. Plain `onChange` still fires with the raw event;
2874
+ * bind this one to a form. */
2875
+ onValueChange?: (value: string) => void;
2876
+ /** The country a number typed without "+" belongs to, until the value says
2877
+ * otherwise. Default `"CH"`. */
2878
+ defaultCountry?: PhoneCountry;
2879
+ /** The countries the select offers, in order; "Other" always follows. Default
2880
+ * {@link PHONE_COUNTRIES} (CH, LI, DE, AT, FR, IT). A stored number from a country
2881
+ * left out still shows under its own code. */
2882
+ countries?: readonly PhoneCountryCode[];
2883
+ /** See {@link PhoneInputLabels}. */
2884
+ labels?: Partial<PhoneInputLabels>;
2885
+ /** Classes for the whole field — the select, the input and the lines under them.
2886
+ * `inputClassName` reaches the `<input>`. */
2887
+ className?: string;
2888
+ }
2889
+ /**
2890
+ * A phone number field (kastlan): a country-code select and the number, stored as
2891
+ * E.164 and shown grouped.
2892
+ *
2893
+ * kastlan's contacts kept whatever was typed — "079 …", "+41 (0)79 …", "0041 79 …" —
2894
+ * which nobody could dial from the app or match against the next import. This field
2895
+ * turns all of those into one stored form, "+41210000001", without taking anything
2896
+ * away from the person typing:
2897
+ *
2898
+ * - **A country to type against.** The select (default CH, then LI, DE, AT, FR, IT
2899
+ * and "Other") says which country a number without "+" belongs to; the national
2900
+ * trunk 0 may be typed or left out. Typing a "+" or "00" overrides it, and the
2901
+ * select follows the number ("+49 …" switches it to DE). Changing the select moves
2902
+ * the national number to the new country code.
2903
+ * - **E.164 when it reads, the text when it does not.** A number the rules read is
2904
+ * emitted as E.164; anything else ("ask reception", an extension) is emitted exactly
2905
+ * as typed. Never refused, never an error of its own: a contact's number is often
2906
+ * known only roughly, and a field that will not save "079 … (mornings)" makes
2907
+ * people type it into the notes instead. An app that needs a dialable number
2908
+ * checks {@link isE164} on submit.
2909
+ * - **Existing values untouched.** A free-text value from before is shown exactly as
2910
+ * it is, and normalised only when someone edits it — the field never rewrites a
2911
+ * record just by being opened.
2912
+ * - **Grouped when settled.** While typing the field shows what was typed; on blur a
2913
+ * number it read is regrouped by its country ("21 000 00 01").
2914
+ *
2915
+ * **The limitation** — there is no libphonenumber behind this (≈150 kB of metadata in
2916
+ * every bundle): the six countries have light rules (the trunk 0, a plausible length)
2917
+ * and every other country is any "+" with 8–15 digits. A well-formed number that does
2918
+ * not exist passes, and German and Austrian landlines, whose area codes vary in length,
2919
+ * are grouped only where the split is known (mobile prefixes, the largest cities) and
2920
+ * otherwise shown as one block. See `lib/phone.ts`.
2921
+ *
2922
+ * `label`, `hint`, `error` and `invalid` read as on {@link Input}: the label floats in
2923
+ * the number's box, and a text hint and the error go under the whole row, attached to
2924
+ * the number with `aria-describedby`. The select is named by `labels.countryCode`, and
2925
+ * the pair is a group named by a string `label`.
2926
+ */
2927
+ declare const PhoneInput: react.ForwardRefExoticComponent<PhoneInputProps & react.RefAttributes<HTMLInputElement>>;
2928
+
1809
2929
  /**
1810
2930
  * EVERY string the kit renders, as one typed tree — and an optional provider that
1811
2931
  * hands it to every component at once.
@@ -2032,6 +3152,21 @@ interface UiKitLabels {
2032
3152
  translationReview: TranslationReviewLabels;
2033
3153
  /** 0.19.0: `LegalLinks`' navigation name — the legal pages' shell, for every app. */
2034
3154
  legal: LegalLabels;
3155
+ /** 0.22.0: the screen-reader words of `Input` / `Textarea`'s `showCount` counter. */
3156
+ characterCount: CharacterCountLabels;
3157
+ /** 0.22.0: `CountrySelect`. Its list's "no results" and counts are `combobox`'s. */
3158
+ countrySelect: CountrySelectLabels;
3159
+ /** 0.22.0: `InlineEditField` — keksdose K9. */
3160
+ inlineEdit: InlineEditLabels;
3161
+ /** 0.22.0: `IbanInput`'s messages, one per problem. */
3162
+ ibanInput: IbanInputLabels;
3163
+ /** 0.22.0: `PhoneInput`'s country-code select. */
3164
+ phoneInput: PhoneInputLabels;
3165
+ /** 0.22.0: `SignChip` — the outflow / inflow toggle beside an amount. */
3166
+ signChip: SignChipLabels;
3167
+ /** 0.23.0: `ColumnMapper` / `ColumnRoleTable` — a pasted or dropped table, a role per
3168
+ * column. */
3169
+ columnMapper: ColumnMapperLabels;
2035
3170
  }
2036
3171
  /**
2037
3172
  * A label override, as deep as the labels go: an object of labels (a namespace, or a
@@ -2065,6 +3200,35 @@ declare const DEFAULT_FILE_LABELS: FileLabels;
2065
3200
  /** "12 kB", "3.4 MB" — `Intl`'s unit formatting, so the digits, the decimal mark and
2066
3201
  * the unit's spelling all follow `locale`. */
2067
3202
  declare function formatFileSize(bytes: number, locale?: string): string;
3203
+ /** What a {@link KitDateFormatter} is told about the date it is formatting. */
3204
+ interface KitDateFormatContext {
3205
+ /**
3206
+ * How much of a date the string is: `"day"` — the `iso` is `"YYYY-MM-DD"`; `"month"` —
3207
+ * `"YYYY-MM"` (a `MonthPicker`); `"year"` — `"YYYY"` (`MonthPicker mode="year"`).
3208
+ */
3209
+ unit: "day" | "month" | "year";
3210
+ /** Which kit surface asks: the trigger of a `DatePicker`, of a `DateRangePicker`
3211
+ * (called once per end), of a `MonthPicker`, or a `DateMark`. */
3212
+ source: "datePicker" | "dateRangePicker" | "monthPicker" | "dateMark";
3213
+ /** The locale the kit would have formatted in — the component's `locale` prop, else
3214
+ * the provider's — or `undefined` for the runtime's. */
3215
+ locale: string | undefined;
3216
+ /**
3217
+ * The kit's suggestion: whether this date stands alone where the day of the week
3218
+ * helps — `true` for a `DatePicker`'s trigger and a `DateMark`, `false` for the two
3219
+ * ends of a range (twice the width, in a sentence-like "from – to") and for a month
3220
+ * or a year. keksdose's rule, which this follows: *"A date in a COLUMN carries the
3221
+ * weekday. A date in a SENTENCE does not."* (date-cell.tsx, dev#546). A formatter
3222
+ * is free to ignore it.
3223
+ */
3224
+ weekday: boolean;
3225
+ }
3226
+ /**
3227
+ * The app's ONE answer to "what does a date look like here" — keksdose K12. Returns the
3228
+ * text for an ISO date (see {@link KitDateFormatContext.unit} for the three shapes).
3229
+ * Return `""` to fall back to the kit's own formatting for that date.
3230
+ */
3231
+ type KitDateFormatter = (iso: string, context: KitDateFormatContext) => string;
2068
3232
  /** Where a chart shows the values under the pointer — see `SeriesChartTooltip.placement`. */
2069
3233
  type ChartTooltipPlacement = "cursor" | "above" | "below" | "auto";
2070
3234
  /**
@@ -2127,6 +3291,25 @@ interface UiKitProviderProps {
2127
3291
  * pointer, as before.
2128
3292
  */
2129
3293
  chartTooltipPlacement?: ChartTooltipPlacement;
3294
+ /**
3295
+ * How every kit date below is written, when the component is not told otherwise —
3296
+ * keksdose K12. keksdose has a date-format preference (Settings ▸ date format, feedback
3297
+ * #180) that is not the UI language, and a weekday in the UI language beside digits
3298
+ * in the preference's order (live #246, dev#546): two locales in one string, which
3299
+ * no `locale` + `Intl` options can say. Its `DateField` wraps every `DatePicker` to
3300
+ * pass `formatValue`, and its report range field formats both ends by hand; with this
3301
+ * set once on the provider, those wrappers thin to nothing.
3302
+ *
3303
+ * Used for the trigger text of `DatePicker`, `DateRangePicker` and `MonthPicker`
3304
+ * (month and year mode), and for `DateMark display="date"`. A component's own
3305
+ * `formatValue` or `formatOptions` (`dateStyle` on a DateMark) wins: prop >
3306
+ * provider > the kit's `Intl` default, the order every kit setting resolves in. Left
3307
+ * out (or returning `""`), everything formats exactly as before.
3308
+ *
3309
+ * Keep it stable (`useCallback`, or a module function): it is in the provider's
3310
+ * context value, so a new function every render re-renders every consumer.
3311
+ */
3312
+ formatDate?: KitDateFormatter;
2130
3313
  children: ReactNode;
2131
3314
  }
2132
3315
  /**
@@ -2137,7 +3320,7 @@ interface UiKitProviderProps {
2137
3320
  * it names, so a page can re-label one table's `dataTable.table` without restating
2138
3321
  * the language.
2139
3322
  */
2140
- declare function UiKitProvider({ labels, locale, weekStartsOn, linkComponent, chartTooltipPlacement, children, }: UiKitProviderProps): react.JSX.Element;
3323
+ declare function UiKitProvider({ labels, locale, weekStartsOn, linkComponent, chartTooltipPlacement, formatDate, children, }: UiKitProviderProps): react.JSX.Element;
2141
3324
  /** What the nearest provider says about one namespace — `undefined` outside one.
2142
3325
  * For a component whose own resolver does more than a merge (the data table
2143
3326
  * derives `columnsCount` from `columns`): feed `{ ...overrides, ...props }` to it. */
@@ -2159,6 +3342,9 @@ declare function useKitLink(): KitLinkComponent | undefined;
2159
3342
  declare function useKitWeekStart(): WeekDay | undefined;
2160
3343
  /** The provider's `chartTooltipPlacement`, or `undefined` — a chart's own prop wins. */
2161
3344
  declare function useKitChartTooltipPlacement(): ChartTooltipPlacement | undefined;
3345
+ /** The nearest provider's `formatDate`, or `undefined` — a component's own
3346
+ * `formatValue` / `formatOptions` wins over it. See {@link KitDateFormatter}. */
3347
+ declare function useKitDateFormatter(): KitDateFormatter | undefined;
2162
3348
  /** {@link DEFAULT_FILE_LABELS}, but formatting in the provider's locale. */
2163
3349
  declare function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels;
2164
3350
  /**
@@ -2175,4 +3361,4 @@ declare function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels;
2175
3361
  */
2176
3362
  declare function missingKitLabels(labels: UiKitLabelOverrides | undefined, reference: UiKitLabels): string[];
2177
3363
 
2178
- export { FIELD_BASE as $, type AppShellLabels as A, Button as B, type CalculatorLabels as C, CopyButton as D, type CopyButtonLabels as E, type CopyButtonProps as F, type CurrencyLabels as G, DEFAULT_APP_SHELL_LABELS as H, DEFAULT_CALCULATOR_LABELS as I, DEFAULT_COMBOBOX_LABELS as J, DEFAULT_COMMON_LABELS as K, DEFAULT_COPY_BUTTON_LABELS as L, DEFAULT_CURRENCY_LABELS as M, DEFAULT_DATE_PICKER_LABELS as N, DEFAULT_FILE_LABELS as O, DEFAULT_FILE_PICKER_LABELS as P, DEFAULT_FORM_ACTIONS_LABELS as Q, DEFAULT_MULTI_SELECT_LABELS as R, DEFAULT_PASSWORD_REVEAL_LABELS as S, DEFAULT_PICKER_SHEET_LABELS as T, DEFAULT_SHARE_CARD_LABELS as U, DEFAULT_SWIPEABLE_ROW_LABELS as V, DEFAULT_TABS_LABELS as W, DEFAULT_TOP_BAR_LABELS as X, type DatePickerLabels as Y, EmptyState as Z, type EmptyStateProps as _, type ButtonClassesOptions as a, type SharePendingGrant as a$, FIELD_DISPLAY as a0, FIELD_FLOATING_PAD as a1, FIELD_INVALID as a2, FIELD_TRIGGER as a3, FIELD_WRITABLE_LOOK as a4, FLOATING_INPUT_CLASS as a5, FLOATING_LABEL_CLASS as a6, FLOATING_LABEL_STATIC as a7, FieldChevron as a8, type FieldChevronProps as a9, type IconButtonTone as aA, type IconButtonToneColor as aB, type IconButtonVariant as aC, Input as aD, type InputProps as aE, type KitLinkComponent as aF, type KitLinkProps as aG, Label as aH, type LabelOverride as aI, type LabelProps as aJ, type MultiSelectLabels as aK, PHONE_QUERY as aL, type PasswordRevealLabels as aM, type PickerSheetLabels as aN, type ResponsiveFormActionsPlacement as aO, Select as aP, type SelectProps as aQ, type ShareAddRequest as aR, type ShareCandidate as aS, ShareCard as aT, type ShareCardLabels as aU, type ShareCardProps as aV, ShareDialog as aW, type ShareDialogProps as aX, type ShareGrantee as aY, SharePanel as aZ, type SharePanelProps as a_, FieldHint as aa, type FieldHintProps as ab, FieldLabel as ac, type FieldLabelProps as ad, FileButton as ae, type FileButtonProps as af, type FileLabels as ag, type FilePickerLabels as ah, type FileRejection as ai, type FileRejectionReason as aj, type FileScreenOptions as ak, FloatingField as al, type FloatingFieldProps as am, FormActions as an, type FormActionsAlign as ao, type FormActionsDestructive as ap, type FormActionsLabels as aq, type FormActionsPlacement as ar, type FormActionsProps as as, type FormActionsStickyWithin as at, type FormActionsSubmitProps as au, IconButton as av, type IconButtonGlyphSize as aw, type IconButtonLinkProps as ax, type IconButtonProps as ay, type IconButtonSize as az, type ButtonLinkProps as b, type ShareRole as b0, Spinner as b1, type SpinnerProps as b2, type SwipeableRowLabels as b3, type TabItem as b4, Tabs as b5, type TabsLabels as b6, type TabsProps as b7, Textarea as b8, type TextareaProps as b9, type TopBarLabels as ba, type UiKitLabelOverrides as bb, type UiKitLabels as bc, UiKitProvider as bd, type UiKitProviderProps as be, type UseFilePickerOptions as bf, type UseFilePickerReturn as bg, buttonClasses as bh, formatFileSize as bi, matchesAccept as bj, missingKitLabels as bk, resolvePasswordRevealLabels as bl, useFilePicker as bm, useKitChartTooltipPlacement as bn, useKitFileLabels as bo, useKitLabelOverrides as bp, useKitLabels as bq, useKitLink as br, useKitLocale as bs, useKitWeekStart as bt, type FilePickHandler as bu, formatAccept as bv, judgePick as bw, screenFiles as bx, summariseRejections as by, type ButtonProps as c, type ButtonSize as d, type ButtonTone as e, type ButtonVariant as f, Card as g, CardAction as h, type CardActionProps as i, CardContent as j, type CardContentProps as k, type CardDensity as l, CardDescription as m, type CardDescriptionProps as n, CardFooter as o, type CardFooterProps as p, CardHeader as q, type CardHeaderProps as r, type CardProps as s, CardTitle as t, type CardTitleLevel as u, type CardTitleProps as v, type CardTone as w, type ChartTooltipPlacement as x, type ComboboxLabels as y, type CommonLabels as z };
3364
+ export { DEFAULT_COPY_BUTTON_LABELS as $, type AppShellLabels as A, Button as B, type CalculatorLabels as C, type ChatComposerHandle as D, type ChatComposerLabels as E, type ChatComposerProps as F, type ComboboxLabels as G, type CommonLabels as H, type ConfirmDialogLabels as I, type ConfirmFn as J, type ConfirmOptions as K, ConfirmProvider as L, type ConfirmProviderProps as M, type ConfirmTone as N, CopyButton as O, type CopyButtonLabels as P, type CopyButtonProps as Q, type CurrencyLabels as R, CurrentPasswordInput as S, type CurrentPasswordInputLabels as T, type CurrentPasswordInputProps as U, DEFAULT_APP_SHELL_LABELS as V, DEFAULT_CALCULATOR_LABELS as W, DEFAULT_CHARACTER_COUNT_LABELS as X, DEFAULT_COMBOBOX_LABELS as Y, DEFAULT_COMMON_LABELS as Z, DEFAULT_CONFIRM_DIALOG_LABELS as _, type ButtonClassesOptions as a, type FormActionsProps as a$, DEFAULT_CURRENCY_LABELS as a0, DEFAULT_DANGER_CONFIRM_LABELS as a1, DEFAULT_DATE_PICKER_LABELS as a2, DEFAULT_FEEDBACK_COMPOSER_LABELS as a3, DEFAULT_FEEDBACK_THREAD_LABELS as a4, DEFAULT_FILE_LABELS as a5, DEFAULT_FILE_PICKER_LABELS as a6, DEFAULT_FORM_ACTIONS_LABELS as a7, DEFAULT_IBAN_INPUT_LABELS as a8, DEFAULT_MULTI_SELECT_LABELS as a9, type FeedbackComposerLabels as aA, type FeedbackComposerProps as aB, FeedbackThread as aC, type FeedbackThreadAttachment as aD, type FeedbackThreadEvent as aE, type FeedbackThreadItem as aF, type FeedbackThreadLabels as aG, type FeedbackThreadMessage as aH, type FeedbackThreadProps as aI, FieldChevron as aJ, type FieldChevronProps as aK, FieldHint as aL, type FieldHintProps as aM, FileButton as aN, type FileButtonProps as aO, type FileLabels as aP, type FilePickerLabels as aQ, type FileRejection as aR, type FileRejectionReason as aS, type FileScreenOptions as aT, FloatingField as aU, type FloatingFieldProps as aV, FormActions as aW, type FormActionsAlign as aX, type FormActionsDestructive as aY, type FormActionsLabels as aZ, type FormActionsPlacement as a_, DEFAULT_PASSWORD_REVEAL_LABELS as aa, DEFAULT_PHONE_INPUT_LABELS as ab, DEFAULT_PICKER_SHEET_LABELS as ac, DEFAULT_SHARE_CARD_LABELS as ad, DEFAULT_SWIPEABLE_ROW_LABELS as ae, DEFAULT_TABS_LABELS as af, DEFAULT_TOP_BAR_LABELS as ag, DangerConfirm as ah, type DangerConfirmLabels as ai, type DangerConfirmProps as aj, type DangerConfirmValues as ak, type DangerConsequence as al, type DatePickerLabels as am, EmptyState as an, type EmptyStateProps as ao, FIELD_BASE as ap, FIELD_DISPLAY as aq, FIELD_FLOATING_PAD as ar, FIELD_INVALID as as, FIELD_TRIGGER as at, FIELD_WRITABLE_LOOK as au, FLOATING_INPUT_CLASS as av, FLOATING_LABEL_CLASS as aw, FeedbackComposer as ax, type FeedbackComposerAttachment as ay, type FeedbackComposerHandle as az, type ButtonLinkProps as b, type UseFilePickerOptions as b$, type FormActionsStickyWithin as b0, type FormActionsSubmitProps as b1, type FormActionsSubmitShortcut as b2, IbanInput as b3, type IbanInputLabels as b4, type IbanInputProps as b5, IconButton as b6, type IconButtonGlyphSize as b7, type IconButtonLinkProps as b8, type IconButtonProps as b9, type ShareCardLabels as bA, type ShareCardProps as bB, ShareDialog as bC, type ShareDialogProps as bD, type ShareGrantee as bE, SharePanel as bF, type SharePanelProps as bG, type SharePendingGrant as bH, type ShareRole as bI, Spinner as bJ, type SpinnerProps as bK, type SwipeableRowLabels as bL, type TabItem as bM, Tabs as bN, type TabsLabels as bO, type TabsProps as bP, Textarea as bQ, type TextareaProps as bR, type TopBarLabels as bS, TypedConfirmField as bT, type TypedConfirmFieldLabels as bU, type TypedConfirmFieldProps as bV, type TypedMatch as bW, type UiKitLabelOverrides as bX, type UiKitLabels as bY, UiKitProvider as bZ, type UiKitProviderProps as b_, type IconButtonSize as ba, type IconButtonTone as bb, type IconButtonToneColor as bc, type IconButtonVariant as bd, Input as be, type InputProps as bf, type KitDateFormatContext as bg, type KitDateFormatter as bh, type KitLinkComponent as bi, type KitLinkProps as bj, Label as bk, type LabelOverride as bl, type LabelProps as bm, type MultiSelectLabels as bn, PHONE_QUERY as bo, type PasswordRevealLabels as bp, PhoneInput as bq, type PhoneInputLabels as br, type PhoneInputProps as bs, type PickerSheetLabels as bt, type ResponsiveFormActionsPlacement as bu, Select as bv, type SelectProps as bw, type ShareAddRequest as bx, type ShareCandidate as by, ShareCard as bz, type ButtonProps as c, type UseFilePickerReturn as c0, buttonClasses as c1, formatFileSize as c2, matchesAccept as c3, missingKitLabels as c4, resolvePasswordRevealLabels as c5, typedMatches as c6, useConfirm as c7, useFilePicker as c8, useKitChartTooltipPlacement as c9, useKitDateFormatter as ca, useKitFileLabels as cb, useKitLabelOverrides as cc, useKitLabels as cd, useKitLink as ce, useKitLocale as cf, useKitWeekStart as cg, type FilePickHandler as ch, usePromisePending as ci, formatAccept as cj, judgePick as ck, screenFiles as cl, summariseRejections as cm, type ButtonSize as d, type ButtonTone as e, type ButtonVariant as f, Card as g, CardAction as h, type CardActionProps as i, CardContent as j, type CardContentProps as k, type CardDensity as l, CardDescription as m, type CardDescriptionProps as n, CardFooter as o, type CardFooterProps as p, CardHeader as q, type CardHeaderProps as r, type CardProps as s, CardTitle as t, type CardTitleLevel as u, type CardTitleProps as v, type CardTone as w, type CharacterCountLabels as x, type ChartTooltipPlacement as y, ChatComposer as z };