@eifi1/ui-kit 0.22.0 → 0.24.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 (208) hide show
  1. package/README.md +42 -25
  2. package/dist/chart.d.ts +8 -7
  3. package/dist/components/amount-input.d.ts +34 -7
  4. package/dist/components/amount-input.js +14 -10
  5. package/dist/components/amount-input.js.map +1 -1
  6. package/dist/components/autocomplete.d.ts +26 -0
  7. package/dist/components/autocomplete.js +164 -137
  8. package/dist/components/autocomplete.js.map +1 -1
  9. package/dist/components/button-group.d.ts +8 -7
  10. package/dist/components/calculator.d.ts +8 -7
  11. package/dist/components/column-mapper.d.ts +235 -0
  12. package/dist/components/column-mapper.js +411 -0
  13. package/dist/components/column-mapper.js.map +1 -0
  14. package/dist/components/combobox-core.d.ts +39 -2
  15. package/dist/components/combobox-core.js +29 -6
  16. package/dist/components/combobox-core.js.map +1 -1
  17. package/dist/components/combobox.d.ts +113 -3
  18. package/dist/components/combobox.js +456 -313
  19. package/dist/components/combobox.js.map +1 -1
  20. package/dist/components/confirm-dialog.d.ts +8 -7
  21. package/dist/components/confirm-dialog.js +7 -8
  22. package/dist/components/confirm-dialog.js.map +1 -1
  23. package/dist/components/copy-button.d.ts +5 -4
  24. package/dist/components/country-select.d.ts +50 -7
  25. package/dist/components/country-select.js +65 -9
  26. package/dist/components/country-select.js.map +1 -1
  27. package/dist/components/danger-confirm.d.ts +8 -7
  28. package/dist/components/danger-confirm.js +64 -7
  29. package/dist/components/danger-confirm.js.map +1 -1
  30. package/dist/components/date-picker.d.ts +41 -0
  31. package/dist/components/date-picker.js +269 -8
  32. package/dist/components/date-picker.js.map +1 -1
  33. package/dist/components/entity-combobox.d.ts +48 -2
  34. package/dist/components/entity-combobox.js +159 -114
  35. package/dist/components/entity-combobox.js.map +1 -1
  36. package/dist/components/facing-pair.d.ts +8 -7
  37. package/dist/components/field-parts.d.ts +116 -6
  38. package/dist/components/field-parts.js +84 -0
  39. package/dist/components/field-parts.js.map +1 -1
  40. package/dist/components/field-strip.d.ts +105 -0
  41. package/dist/components/field-strip.js +46 -0
  42. package/dist/components/field-strip.js.map +1 -0
  43. package/dist/components/file-button.d.ts +8 -7
  44. package/dist/components/file-dropzone.d.ts +8 -7
  45. package/dist/components/form-actions.d.ts +8 -7
  46. package/dist/components/form-actions.js +23 -3
  47. package/dist/components/form-actions.js.map +1 -1
  48. package/dist/components/iban-input.d.ts +8 -7
  49. package/dist/components/icon-picker.d.ts +10 -1
  50. package/dist/components/icon-picker.js +12 -4
  51. package/dist/components/icon-picker.js.map +1 -1
  52. package/dist/components/language-select.d.ts +8 -7
  53. package/dist/components/money-field.d.ts +11 -7
  54. package/dist/components/money-field.js.map +1 -1
  55. package/dist/components/month-picker.js +2 -1
  56. package/dist/components/month-picker.js.map +1 -1
  57. package/dist/components/multi-entity-combobox.d.ts +31 -2
  58. package/dist/components/multi-entity-combobox.js +152 -103
  59. package/dist/components/multi-entity-combobox.js.map +1 -1
  60. package/dist/components/number-field.d.ts +8 -7
  61. package/dist/components/number-input.d.ts +8 -7
  62. package/dist/components/numpad-sheet.d.ts +8 -7
  63. package/dist/components/phone-input.d.ts +8 -7
  64. package/dist/components/reauth-dialog.d.ts +2 -2
  65. package/dist/components/reauth-dialog.js +6 -8
  66. package/dist/components/reauth-dialog.js.map +1 -1
  67. package/dist/components/series-chart.d.ts +8 -7
  68. package/dist/components/settings-fields.d.ts +8 -7
  69. package/dist/components/share-card.d.ts +8 -7
  70. package/dist/components/swatch-picker.d.ts +17 -1
  71. package/dist/components/swatch-picker.js +10 -4
  72. package/dist/components/swatch-picker.js.map +1 -1
  73. package/dist/components/text-link.d.ts +8 -7
  74. package/dist/components/tile-radio.d.ts +20 -0
  75. package/dist/components/tile-radio.js +25 -8
  76. package/dist/components/tile-radio.js.map +1 -1
  77. package/dist/components/time-input.d.ts +8 -7
  78. package/dist/components/toggle-group.js +2 -2
  79. package/dist/components/toggle-group.js.map +1 -1
  80. package/dist/components/trigger-aria.d.ts +3 -0
  81. package/dist/components/trigger-aria.js +3 -1
  82. package/dist/components/trigger-aria.js.map +1 -1
  83. package/dist/components/ui.d.ts +5 -4
  84. package/dist/components/ui.js +60 -28
  85. package/dist/components/ui.js.map +1 -1
  86. package/dist/feedback/feedback-attachment.d.ts +66 -1
  87. package/dist/feedback/feedback-attachment.js +185 -65
  88. package/dist/feedback/feedback-attachment.js.map +1 -1
  89. package/dist/feedback/feedback-dialog.d.ts +66 -1
  90. package/dist/feedback/feedback-dialog.js.map +1 -1
  91. package/dist/feedback/feedback-inbox.d.ts +67 -252
  92. package/dist/feedback/feedback-inbox.js.map +1 -1
  93. package/dist/feedback/feedback-thread.d.ts +66 -287
  94. package/dist/feedback/feedback-thread.js +16 -3
  95. package/dist/feedback/feedback-thread.js.map +1 -1
  96. package/dist/{kit-labels-R8mIAc9N.d.ts → feedback-DOwPu-Il.d.ts} +1273 -30
  97. package/dist/feedback.d.ts +65 -3
  98. package/dist/hooks/use-file-drop.d.ts +8 -7
  99. package/dist/i18n/defaults.d.ts +8 -7
  100. package/dist/i18n/defaults.js +3 -1
  101. package/dist/i18n/defaults.js.map +1 -1
  102. package/dist/i18n/german.d.ts +8 -7
  103. package/dist/i18n/german.js +36 -2
  104. package/dist/i18n/german.js.map +1 -1
  105. package/dist/i18n/kit-labels.d.ts +5 -4
  106. package/dist/i18n/kit-labels.js.map +1 -1
  107. package/dist/i18n/languages.d.ts +8 -7
  108. package/dist/i18n/locales/de-CH.d.ts +8 -7
  109. package/dist/i18n/locales/en.d.ts +8 -7
  110. package/dist/i18n/locales/en.js +7 -0
  111. package/dist/i18n/locales/en.js.map +1 -1
  112. package/dist/i18n/locales/es.d.ts +8 -7
  113. package/dist/i18n/locales/es.js +37 -2
  114. package/dist/i18n/locales/es.js.map +1 -1
  115. package/dist/i18n/locales/fr.d.ts +8 -7
  116. package/dist/i18n/locales/fr.js +36 -2
  117. package/dist/i18n/locales/fr.js.map +1 -1
  118. package/dist/i18n/locales/hu.d.ts +8 -7
  119. package/dist/i18n/locales/hu.js +38 -2
  120. package/dist/i18n/locales/hu.js.map +1 -1
  121. package/dist/i18n/locales/it.d.ts +8 -7
  122. package/dist/i18n/locales/it.js +37 -2
  123. package/dist/i18n/locales/it.js.map +1 -1
  124. package/dist/i18n/locales/zh.d.ts +8 -7
  125. package/dist/i18n/locales/zh.js +34 -2
  126. package/dist/i18n/locales/zh.js.map +1 -1
  127. package/dist/i18n/review.d.ts +8 -7
  128. package/dist/i18n/review.js +20 -1
  129. package/dist/i18n/review.js.map +1 -1
  130. package/dist/index.d.ts +6 -4
  131. package/dist/index.js +16 -0
  132. package/dist/index.js.map +1 -1
  133. package/dist/lib/column-mapping.d.ts +81 -0
  134. package/dist/lib/column-mapping.js +108 -0
  135. package/dist/lib/column-mapping.js.map +1 -0
  136. package/dist/lib/strip-fade.d.ts +2 -2
  137. package/dist/lib/strip-fade.js.map +1 -1
  138. package/dist/lib/table-text.d.ts +109 -1
  139. package/dist/lib/table-text.js +122 -1
  140. package/dist/lib/table-text.js.map +1 -1
  141. package/dist/rhf/fields.d.ts +142 -13
  142. package/dist/rhf/fields.js +185 -3
  143. package/dist/rhf/fields.js.map +1 -1
  144. package/dist/rhf/form.d.ts +8 -7
  145. package/dist/rhf.d.ts +9 -8
  146. package/dist/rhf.js.map +1 -1
  147. package/dist/shell/app-shell.d.ts +8 -7
  148. package/dist/shell/top-bar-brand.d.ts +8 -7
  149. package/dist/shell/topbar-action-menu.d.ts +36 -3
  150. package/dist/shell/topbar-action-menu.js +74 -33
  151. package/dist/shell/topbar-action-menu.js.map +1 -1
  152. package/dist/shell.d.ts +8 -7
  153. package/dist/table-text.d.ts +1 -1
  154. package/dist/wizard/stepper-nav.d.ts +38 -9
  155. package/dist/wizard/stepper-nav.js +4 -0
  156. package/dist/wizard/stepper-nav.js.map +1 -1
  157. package/dist/wizard.d.ts +8 -7
  158. package/package.json +1 -1
  159. package/src/components/amount-input.tsx +50 -14
  160. package/src/components/autocomplete.tsx +188 -116
  161. package/src/components/column-mapper.tsx +768 -0
  162. package/src/components/combobox-core.tsx +82 -9
  163. package/src/components/combobox.tsx +655 -335
  164. package/src/components/confirm-dialog.tsx +12 -8
  165. package/src/components/country-select.tsx +135 -22
  166. package/src/components/danger-confirm.tsx +274 -24
  167. package/src/components/date-picker.tsx +423 -10
  168. package/src/components/entity-combobox.tsx +243 -129
  169. package/src/components/field-parts.tsx +224 -5
  170. package/src/components/field-strip.tsx +149 -0
  171. package/src/components/form-actions.tsx +52 -5
  172. package/src/components/icon-picker.tsx +23 -4
  173. package/src/components/money-field.tsx +3 -0
  174. package/src/components/month-picker.tsx +2 -1
  175. package/src/components/multi-entity-combobox.tsx +221 -121
  176. package/src/components/reauth-dialog.tsx +17 -18
  177. package/src/components/swatch-picker.tsx +29 -5
  178. package/src/components/tile-radio.tsx +74 -13
  179. package/src/components/toggle-group.tsx +2 -2
  180. package/src/components/trigger-aria.ts +5 -0
  181. package/src/components/ui.tsx +114 -33
  182. package/src/feedback/feedback-attachment.tsx +372 -72
  183. package/src/feedback/feedback-dialog.tsx +7 -3
  184. package/src/feedback/feedback-inbox.tsx +3 -2
  185. package/src/feedback/feedback-thread.tsx +112 -9
  186. package/src/i18n/defaults.ts +2 -0
  187. package/src/i18n/german.ts +42 -0
  188. package/src/i18n/kit-labels.tsx +4 -0
  189. package/src/i18n/locales/en.ts +27 -5
  190. package/src/i18n/locales/es.ts +41 -0
  191. package/src/i18n/locales/fr.ts +42 -0
  192. package/src/i18n/locales/hu.ts +37 -0
  193. package/src/i18n/locales/it.ts +41 -0
  194. package/src/i18n/locales/zh.ts +32 -0
  195. package/src/i18n/review.ts +19 -0
  196. package/src/index.ts +18 -0
  197. package/src/lib/column-mapping.ts +234 -0
  198. package/src/lib/strip-fade.ts +2 -2
  199. package/src/lib/table-text.ts +271 -0
  200. package/src/rhf/fields.tsx +421 -6
  201. package/src/rhf.ts +2 -1
  202. package/src/shell/topbar-action-menu.tsx +134 -38
  203. package/src/wizard/stepper-nav.tsx +35 -1
  204. package/dist/components/field-anatomy.d.ts +0 -95
  205. package/dist/components/field-anatomy.js +0 -84
  206. package/dist/components/field-anatomy.js.map +0 -1
  207. package/dist/feedback-attachment-NhUm7Zga.d.ts +0 -367
  208. package/src/components/field-anatomy.tsx +0 -190
@@ -1,12 +1,12 @@
1
1
  import * as react from 'react';
2
- import { InputHTMLAttributes, ReactNode, AnchorHTMLAttributes, Ref, ReactElement, ButtonHTMLAttributes, SelectHTMLAttributes, ComponentPropsWithoutRef, TextareaHTMLAttributes } from 'react';
2
+ import { InputHTMLAttributes, ReactNode, AnchorHTMLAttributes, Ref, ReactElement, ButtonHTMLAttributes, SelectHTMLAttributes, ComponentPropsWithoutRef, TextareaHTMLAttributes, RefObject } from 'react';
3
+ import { TooltipSide } from './components/tooltip.js';
3
4
  import { f as DataTableLabels } from './data-table-labels-B7OdnM0S.js';
4
5
  import { MiniCalendarLabels, WeekDay } from './components/mini-calendar.js';
5
6
  import { CalendarHeatmapLabels } from './components/calendar-heatmap.js';
6
7
  import { PopoverLabels } from './components/popover.js';
7
8
  import { ChipInputLabels } from './components/chip.js';
8
9
  import { FieldSyncLabels } from './components/field-sync.js';
9
- import { TooltipSide } from './components/tooltip.js';
10
10
  import { WizardLabels } from './wizard/types.js';
11
11
  import { TourLabels } from './tour/tour.js';
12
12
  import { CommandPaletteLabels } from './search/command-palette.js';
@@ -23,15 +23,13 @@ import { SwatchPickerLabels } from './components/swatch-picker.js';
23
23
  import { IconPickerLabels } from './components/icon-picker.js';
24
24
  import { DialogFrameProps, DialogFrameLabels } from './components/dialog-frame.js';
25
25
  import { MeasuredGridLabels } from './components/measured-grid.js';
26
- import { f as FeedbackAttachmentFieldLabels, t as FeedbackDialogTextLabels } from './feedback-attachment-NhUm7Zga.js';
27
- import { FeedbackThreadLabels, FeedbackComposerLabels } from './feedback/feedback-thread.js';
26
+ import { LucideIcon } from 'lucide-react';
28
27
  import { AccountSettingsLabels } from './components/account-settings-labels.js';
29
28
  import { FloatingPanelLabels } from './components/floating-panel.js';
30
29
  import { BulkActionBarLabels } from './components/bulk-action-bar.js';
31
30
  import { ListLabels } from './components/list.js';
32
31
  import { BreadcrumbsLabels } from './components/breadcrumbs.js';
33
32
  import { ToastLabels } from './components/toast.js';
34
- import { LucideIcon } from 'lucide-react';
35
33
  import { DescriptionListLabels } from './components/description-list.js';
36
34
  import { LineItemsLabels } from './components/line-items.js';
37
35
  import { ProgressBarLabels } from './components/progress-bar.js';
@@ -51,6 +49,8 @@ import { InlineEditLabels } from './components/inline-edit-field.js';
51
49
  import { IbanKind } from './lib/iban.js';
52
50
  import { PhoneCountry, PhoneCountryCode } from './lib/phone.js';
53
51
  import { SignChipLabels } from './components/sign-chip.js';
52
+ import { ColumnMapperLabels } from './components/column-mapper.js';
53
+ import './components/field-parts.js';
54
54
 
55
55
  type ButtonVariant = "primary" | "secondary" | "ghost" | "danger" | "brand" | "link";
56
56
  type ButtonSize = "sm" | "md";
@@ -568,7 +568,6 @@ type FieldChevronProps = Omit<ComponentPropsWithoutRef<"svg">, "children">;
568
568
  * what was picked. */
569
569
  declare function FieldChevron({ className, ...rest }: FieldChevronProps): react.JSX.Element;
570
570
  declare const FLOATING_LABEL_CLASS: string;
571
- declare const FLOATING_LABEL_STATIC: string;
572
571
  /**
573
572
  * The one place that assembles a labelled field: a `relative` wrapper around the
574
573
  * control (`children`) plus a floating label inside the top strip. Pass `staticLabel`
@@ -625,15 +624,6 @@ interface FieldHintProps extends Omit<ComponentPropsWithoutRef<"button">, "child
625
624
  side?: TooltipSide;
626
625
  }
627
626
  declare function FieldHint({ label, side, className, "aria-label": ariaLabel, ...rest }: FieldHintProps): react.JSX.Element;
628
- /**
629
- * The floating label for a custom-dropdown trigger (a `<span>`, since the trigger is a
630
- * button not a labelable input). Same placement as {@link FloatingField}'s static label,
631
- * so every labelled field lines up. Render inside a `relative` wrapper, before the trigger.
632
- */
633
- interface FieldLabelProps extends ComponentPropsWithoutRef<"span"> {
634
- children: ReactNode;
635
- }
636
- declare function FieldLabel({ children, className, ...rest }: FieldLabelProps): react.JSX.Element;
637
627
  interface LabelProps extends ComponentPropsWithoutRef<"label"> {
638
628
  /** Draw the required mark after the text. The mark is `aria-hidden`: what a
639
629
  * screen reader hears is the control's own `required` / `aria-required`, which
@@ -1416,6 +1406,18 @@ interface DangerConfirmLabels {
1416
1406
  /** 0.22: the checkbox `requireAcknowledge={true}` shows — "I have read what this does
1417
1407
  * and want to continue" (keksdose's `admin.users.confirm_ack`). */
1418
1408
  acknowledge: string;
1409
+ /**
1410
+ * 0.23: why the armed confirm is held while the typed phrase does not match yet — in
1411
+ * the confirm's tooltip and its description (keksdose G4a). A FUNCTION of the phrase
1412
+ * by default ("Type “DELETE” to confirm"), or a finished STRING, as `phrase`.
1413
+ */
1414
+ needsPhrase: string | ((phrase: string) => string);
1415
+ /** 0.23: why the armed confirm is held while the `requireAcknowledge` box is unticked
1416
+ * — "Tick the box to confirm". */
1417
+ needsAcknowledge: string;
1418
+ /** 0.23: why the armed confirm is held while the `requirePassword` field is empty —
1419
+ * "Enter your password to confirm". */
1420
+ needsPassword: string;
1419
1421
  }
1420
1422
  /** `satisfies` rather than a type annotation, so `DEFAULT_DANGER_CONFIRM_LABELS.phrase`
1421
1423
  * stays callable for a caller that composes its own label from it. */
@@ -1427,7 +1429,31 @@ declare const DEFAULT_DANGER_CONFIRM_LABELS: {
1427
1429
  password: string;
1428
1430
  phrase: (phrase: string) => string;
1429
1431
  acknowledge: string;
1432
+ needsPhrase: (phrase: string) => string;
1433
+ needsAcknowledge: string;
1434
+ needsPassword: string;
1430
1435
  };
1436
+ /**
1437
+ * What the guards were answered with — the second argument of
1438
+ * {@link DangerConfirmProps.onConfirm} (0.23, keksdose G4b). A key is there only when its
1439
+ * guard was asked for, so the object can go into a request body as it is.
1440
+ */
1441
+ interface DangerConfirmValues {
1442
+ /**
1443
+ * The text typed into the `phrase` field — as the match rule compared it: trimmed
1444
+ * under `phraseMatch` `"trim"` and `"caseless"` (the spaces a phone keyboard adds are
1445
+ * not part of it), exactly as typed under `"exact"`. The case is the user's, even
1446
+ * under `"caseless"`: a server that re-checks applies its own rule to it. Absent
1447
+ * without a `phrase`.
1448
+ */
1449
+ typed?: string;
1450
+ /** The entered password — the same value as the first argument. Absent without
1451
+ * `requirePassword`. */
1452
+ password?: string;
1453
+ /** `true` when the `requireAcknowledge` box was shown — it was ticked, since the
1454
+ * confirm is held until it is. Absent without one. */
1455
+ acknowledged?: true;
1456
+ }
1431
1457
  /**
1432
1458
  * One line of {@link DangerConfirmProps.consequences}: what the action will do. A plain
1433
1459
  * string, or this, for a key of its own and the `severe` mark.
@@ -1449,12 +1475,25 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
1449
1475
  * (fields wiped) when it resolves, still armed when it rejects — so the user can
1450
1476
  * correct a wrong password and retry. The rejection is not swallowed for you to
1451
1477
  * miss: handle it (and show why) in the caller, as with any mutation.
1478
+ *
1479
+ * 0.23: the second argument is what every guard was answered with — the typed phrase,
1480
+ * the password, the tick ({@link DangerConfirmValues}). keksdose G4b: its admin
1481
+ * actions send the address the admin TYPED, and the server re-checks it against the
1482
+ * account (`assert_confirmed`), so a client that put the wrong row's id in the request
1483
+ * is refused rather than obeyed; the tile kept the text to itself.
1484
+ *
1485
+ * onConfirm={(_password, { typed }) =>
1486
+ * reset.mutateAsync({ id, confirm: { acknowledged: true, confirm_email: typed ?? null } })}
1487
+ *
1488
+ * A second argument rather than one object in place of the password: every
1489
+ * `(password) => …` and `() => …` handler, and a `mutation.mutate` passed as it is,
1490
+ * keeps working unchanged, and a handler that needs one guard's answer names it.
1452
1491
  */
1453
- onConfirm: (password?: string) => void | Promise<unknown>;
1454
- /** Show a password field; confirm stays disabled until it is filled. */
1492
+ onConfirm: (password: string | undefined, values: DangerConfirmValues) => void | Promise<unknown>;
1493
+ /** Show a password field; confirm is held until it is filled. */
1455
1494
  requirePassword?: boolean;
1456
1495
  /**
1457
- * Show an "I understand" checkbox; confirm stays disabled until it is ticked
1496
+ * Show an "I understand" checkbox; confirm is held until it is ticked
1458
1497
  * (keksdose K7). `true` words it with `labels.acknowledge`; any other node IS the
1459
1498
  * checkbox's label ("I understand Anna will be signed out everywhere").
1460
1499
  *
@@ -1475,8 +1514,8 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
1475
1514
  * who reads the same paragraph on every row stops reading it (keksdose dev#488).
1476
1515
  */
1477
1516
  consequences?: readonly (string | DangerConsequence)[];
1478
- /** Show a "type <phrase> to confirm" field; confirm stays disabled until the field
1479
- * matches (case-sensitive; surrounding spaces ignored unless `phraseMatch="exact"`). */
1517
+ /** Show a "type <phrase> to confirm" field; confirm is held until the field matches
1518
+ * (case-sensitive; surrounding spaces ignored unless `phraseMatch="exact"`). */
1480
1519
  phrase?: string;
1481
1520
  /**
1482
1521
  * How the typed text is compared with `phrase`. `"trim"` (default) ignores spaces
@@ -1490,15 +1529,99 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
1490
1529
  /** The warning above the fields. Defaults to `labels.prompt`. */
1491
1530
  prompt?: ReactNode;
1492
1531
  /** `"danger"` (default) for what cannot be undone; `"warning"` for what can, at a
1493
- * cost (loading demo data over your own). Colours the prompt and the confirm. */
1532
+ * cost (loading demo data over your own). Colours the prompt, and picks the arm
1533
+ * button's variant and — unless {@link DangerConfirmProps.confirmVariant} is
1534
+ * given — the confirm's. */
1494
1535
  tone?: "danger" | "warning";
1536
+ /**
1537
+ * The confirm button's variant, apart from `tone` (0.24, keksdose). Default: what
1538
+ * `tone` picks, as before — `"danger"` for `"danger"`, `"primary"` for `"warning"`.
1539
+ *
1540
+ * `tone` says how bad the outcome is; this says how loud the last press is, and the two
1541
+ * need not agree. keksdose's `UserActionConfirm` (an admin resets somebody else's
1542
+ * password) asks an AMBER question — what it guards against is mis-targeting, not data
1543
+ * loss, so the danger colour stays its one `severe` consequence's — and ends in a RED
1544
+ * Go, as its hand-built panel did before it moved onto this tile in 0.23; with only
1545
+ * `tone`, the amber question made Go the neutral primary fill. `tone="warning"
1546
+ * confirmVariant="danger"` is that panel again.
1547
+ */
1548
+ confirmVariant?: ButtonVariant;
1549
+ /**
1550
+ * Hold the armed confirm for a reason of the CALLER's own (0.24, keksdose) — the
1551
+ * tile's counterpart of FormActions' `submitDisabledReason`. While it has content the
1552
+ * confirm is held exactly as by the built-in guards: `aria-disabled` but focusable,
1553
+ * the reason in the kit {@link Tooltip} and its description, a press — or Enter in a
1554
+ * field — does nothing. Nothing else changes: the arm button stays usable, and no
1555
+ * line is printed under the buttons.
1556
+ *
1557
+ * keksdose's `UserPlanEditor` ("move this account onto another plan") must not confirm
1558
+ * the plan the account already holds — the request would only write FREE → FREE into
1559
+ * the audit trail. With no guard of its own to give, it passed "Pick a different plan"
1560
+ * as `lockedReason`, which is a LOCK: documented as "the action is not available",
1561
+ * spelled out under the buttons as well as in the tooltip, and meant for a write the
1562
+ * user cannot make land. A guard the user lifts by changing a field is this prop.
1563
+ *
1564
+ * Which reason the held confirm names: a write lock's first (`lockedReason`, `commit`
1565
+ * — nothing in the tile lifts it), then this one, then the built-in guards in the
1566
+ * order they are drawn (the tick, the phrase, the password). This one before the
1567
+ * built-ins because it is usually about a field in
1568
+ * {@link DangerConfirmProps.children}, which is drawn ABOVE them — the rule since 0.23
1569
+ * is "the first open guard in the order the user meets it" — and because it is about
1570
+ * WHAT is being confirmed (which plan), which has to be settled before acknowledging
1571
+ * it means anything. It is also the order keksdose's plan editor had, its
1572
+ * `lockedReason` winning over the tick.
1573
+ */
1574
+ confirmDisabledReason?: ReactNode;
1575
+ /**
1576
+ * Fields of the caller's own, drawn INSIDE the armed tile (0.24, keksdose): after the
1577
+ * prompt and the consequences, before the tick, the typed phrase and the password —
1578
+ * the order is "what this does, what to do it with, then prove you mean it". Nothing
1579
+ * is drawn for them while the tile is disarmed, and nothing at all without them, so a
1580
+ * tile without children is laid out exactly as before.
1581
+ *
1582
+ * keksdose's `UserPlanEditor` asks WHICH plan before it asks for the tick; with no
1583
+ * place inside the tile for the picker, the `Select` sat above it, and the tile's
1584
+ * prompt — the panel's title by rights — became the "FREE → PRO" line under the
1585
+ * picker. With the picker here, the prompt is the title again.
1586
+ *
1587
+ * The fields are the caller's: their values are not wiped on disarm (an uncontrolled
1588
+ * field starts over anyway — the slot unmounts), not passed to `onConfirm`, and a
1589
+ * guard on them is {@link DangerConfirmProps.confirmDisabledReason}. Arming moves
1590
+ * focus to their first form field (an input, a select, a combobox, a radio…), else to
1591
+ * the tile's own first field as before; Tab then goes on through the tick, the phrase
1592
+ * and the password to Cancel and the confirm. They sit inside the tile's `<form>`:
1593
+ * Enter in a text field confirms once every guard allows, and a {@link Button} among
1594
+ * them needs `type="button"` — without one it SUBMITS the form, as a native button
1595
+ * does.
1596
+ */
1597
+ children?: ReactNode;
1495
1598
  /** Visible text of the arm button; defaults to `labels.arm`. */
1496
1599
  armLabel?: ReactNode;
1497
1600
  /** Visible text of the confirm button; defaults to `labels.confirm`. */
1498
1601
  confirmLabel?: ReactNode;
1499
- /** The action is running: confirm shows a spinner and nothing can be pressed. For a
1500
- * caller that tracks the mutation itself (a `useMutation`'s `isPending`); a
1501
- * promise returned from `onConfirm` does the same on its own. */
1602
+ /**
1603
+ * The action is running: confirm shows a spinner and nothing can be pressed — Cancel
1604
+ * included. For a caller that tracks the mutation itself (a `useMutation`'s
1605
+ * `isPending`); a promise returned from `onConfirm` does the same on its own.
1606
+ *
1607
+ * Cancel stays disabled ON PURPOSE, unlike FormActions' (keksdose asked in 0.24 why the
1608
+ * two differ). Once the request has left, nothing on the client can call it back —
1609
+ * not even an `AbortSignal`, which only stops the waiting, not the server — so a usable
1610
+ * Cancel could only collapse the tile while the action went on: "Cancel" pressed, and
1611
+ * the account reset anyway. Every way of settling what comes back is wrong somewhere: a
1612
+ * resolve after the Cancel did what the user called off; a reject finds the fields
1613
+ * wiped (a collapsed tile holds no password), so the 0.23 "stay armed and retry" is
1614
+ * gone; and re-arming while the first request runs is either a busy tile with empty
1615
+ * fields or — if the busy state went with the Cancel — a second destructive request
1616
+ * beside the first. FormActions' Cancel leaves an editor whose save is the user's own
1617
+ * edit landing, and a form can be edited again; the tile's action is the one that
1618
+ * cannot be undone, so it says nothing it cannot keep and waits — the wait is one
1619
+ * request long.
1620
+ *
1621
+ * When the action settles still armed (it failed) and the press on the confirm had
1622
+ * dropped the focus — a natively disabled button loses it — focus comes back to the
1623
+ * confirm, so a keyboard user can retry or Shift+Tab to the field to correct (0.24).
1624
+ */
1502
1625
  busy?: boolean;
1503
1626
  /** The arm button is disabled. */
1504
1627
  disabled?: boolean;
@@ -1533,9 +1656,21 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
1533
1656
  }
1534
1657
  /**
1535
1658
  * An "arm → confirm" tile for destructive actions: one button, which expands into a
1536
- * warning, an optional list of consequences, an optional "I understand" tick, an
1537
- * optional type-to-confirm field, an optional password field and a confirm that stays
1538
- * disabled until every guard is satisfied.
1659
+ * warning, an optional list of consequences, optional fields of the caller's own
1660
+ * (`children`, 0.24), an optional "I understand" tick, an optional type-to-confirm
1661
+ * field, an optional password field and a confirm that is held until every guard is
1662
+ * satisfied — the built-in ones, and the caller's `confirmDisabledReason` (0.24).
1663
+ *
1664
+ * A held confirm SAYS which guard is still open (0.23, keksdose G4a): it is
1665
+ * `aria-disabled` rather than `disabled` — still focusable, so a keyboard user can land
1666
+ * on it — with the reason in the kit {@link Tooltip} and its description ("Type
1667
+ * “DELETE” to confirm", "Tick the box to confirm", "Enter your password to confirm";
1668
+ * `labels.needs*`), the first open guard in the order they are drawn. FormActions'
1669
+ * `submitDisabledReason` does the same for a form's Save. Pressing it, or Enter in a
1670
+ * field, does nothing. A lock's reason wins over a guard's, the caller's guard over the
1671
+ * built-in ones; while the action runs the confirm is plainly disabled, its spinner
1672
+ * saying why — and so is Cancel, which cannot call back a request that has left (see
1673
+ * `busy`).
1539
1674
  *
1540
1675
  * Keksdose hand-rolled it three times (load demo data, wipe everything, reset a
1541
1676
  * budget) and then as `shared/components/danger-confirm.tsx`; the only app-specific
@@ -1547,7 +1682,7 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
1547
1682
  * destructive button itself), and disarming moves it back to the arm button, so the
1548
1683
  * keyboard user is never left on an element that just vanished.
1549
1684
  */
1550
- 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;
1685
+ declare function DangerConfirm({ onConfirm, requirePassword, requireAcknowledge, consequences, phrase, phraseMatch, prompt, tone, confirmVariant, confirmDisabledReason, children, armLabel, confirmLabel, busy: busyProp, disabled, lockedReason: ownLockedReason, commit, armed: armedProp, onArmedChange, labels: labelsProp, className, ...rest }: DangerConfirmProps): react.JSX.Element;
1551
1686
 
1552
1687
  /**
1553
1688
  * A button that opens the file picker — the shape all three apps kept writing by hand
@@ -1777,6 +1912,1090 @@ interface FileButtonProps extends Omit<UseFilePickerOptions, "disabled">, Omit<B
1777
1912
  */
1778
1913
  declare const FileButton: react.ForwardRefExoticComponent<FileButtonProps & react.RefAttributes<HTMLButtonElement>>;
1779
1914
 
1915
+ interface FeedbackCategoryOption {
1916
+ value: string;
1917
+ label: string;
1918
+ }
1919
+ interface FeedbackAttachmentLabels {
1920
+ /** The heading over the field. Optional: a note editor puts the buttons
1921
+ * straight under its textarea, where a second heading is noise. */
1922
+ attachment?: string;
1923
+ attachmentAdd: string;
1924
+ /** Label for the "capture screenshot" button. Optional — falls back to the provider's
1925
+ * `feedbackAttachment.attachmentCapture`, then English. */
1926
+ attachmentCapture?: string;
1927
+ /** The line under the attachment buttons saying a screenshot can be pasted
1928
+ * straight in. Optional — falls back to the provider's `feedbackAttachment`, then English. */
1929
+ attachmentPaste?: string;
1930
+ attachmentRemove: string;
1931
+ /** `multiple` mode (0.15.5): the chip list's accessible name — and, in
1932
+ * `<FeedbackDialog attachments="multiple">`, the heading over it (0.16.0). Optional,
1933
+ * as are the keys below — they fall back to the provider's `feedbackAttachment`,
1934
+ * then English. */
1935
+ attachmentList?: string;
1936
+ /** `multiple` mode (0.16.0): the screenshot slot's chip title, in place of its file name. */
1937
+ attachmentScreenshot?: string;
1938
+ /** `multiple` mode: one chip's remove button, given the file's name. */
1939
+ attachmentRemoveFile?: (name: string) => string;
1940
+ /** `multiple` mode: the line shown once `max` files are attached. */
1941
+ attachmentLimit?: (max: number) => string;
1942
+ /** `refs` mode (0.22.0): the second line of a chip whose upload is still running. */
1943
+ attachmentUploading?: string;
1944
+ }
1945
+ interface FeedbackDialogLabels extends FeedbackAttachmentLabels {
1946
+ title: string;
1947
+ category: string;
1948
+ subject: string;
1949
+ body: string;
1950
+ attachment: string;
1951
+ submitHint: string;
1952
+ cancel: string;
1953
+ save: string;
1954
+ /** @deprecated since 0.16.0 — use `attachmentList`, the one key for the heading and
1955
+ * the chip list it names. Still honoured: set, it wins over the provider's
1956
+ * `attachmentList` (but not over an `attachmentList` passed beside it). */
1957
+ attachments?: string;
1958
+ }
1959
+ /**
1960
+ * The dialog's own strings — the `feedbackDialog` namespace of `<UiKitProvider
1961
+ * labels>` (0.12.0). The attachment keys are not repeated here: they are the
1962
+ * `feedbackAttachment` namespace's, which the field inside already reads.
1963
+ *
1964
+ * Before, every key was required at the call site, so each app restated ten strings
1965
+ * wherever it mounted the dialog (kastlan feedback-button.tsx built the object inline).
1966
+ */
1967
+ interface FeedbackDialogTextLabels {
1968
+ title: string;
1969
+ category: string;
1970
+ subject: string;
1971
+ body: string;
1972
+ /** The body's label when `requireBody={false}`: "What happened? (optional)".
1973
+ * Optional, so a complete `UiKitLabels` typed before 0.14.2 still compiles. */
1974
+ bodyOptional?: string;
1975
+ /** The heading over the attachment buttons. */
1976
+ attachment: string;
1977
+ /** The line beside the buttons naming the shortcut. */
1978
+ submitHint: string;
1979
+ cancel: string;
1980
+ save: string;
1981
+ /** @deprecated since 0.16.0 — use `feedbackAttachment.attachmentList`. It and this
1982
+ * key were two names for one heading ("Attachments" over the chips that list names
1983
+ * "Attachments"), and a catalogue that translated one left the other English. Still
1984
+ * honoured when set: it wins over `feedbackAttachment.attachmentList`. */
1985
+ attachments?: string;
1986
+ }
1987
+ declare const DEFAULT_FEEDBACK_DIALOG_LABELS: FeedbackDialogTextLabels;
1988
+ interface FeedbackSubmission {
1989
+ title: string;
1990
+ body: string;
1991
+ category: string;
1992
+ attachment: File | null;
1993
+ }
1994
+ /**
1995
+ * What `onSubmit` gets under `attachments="multiple"` (0.15.5): the screenshot and
1996
+ * the picked/pasted files apart, because an app files them differently — keksdose
1997
+ * attaches the screenshot to the report and the photos as its evidence list. No
1998
+ * `attachment`: there is no one file it could name.
1999
+ */
2000
+ interface FeedbackMultipleSubmission {
2001
+ title: string;
2002
+ body: string;
2003
+ category: string;
2004
+ /** What `onCaptureScreenshot` returned, or `null` — at most one. */
2005
+ screenshot: File | null;
2006
+ /** Picked and pasted files, in the order they were added; at most `maxAttachments`. */
2007
+ attachments: File[];
2008
+ }
2009
+ interface FeedbackDialogBaseProps {
2010
+ open: boolean;
2011
+ onClose: () => void;
2012
+ categories: FeedbackCategoryOption[];
2013
+ category: string;
2014
+ onCategoryChange: (value: string) => void;
2015
+ /** Prop > `<UiKitProvider labels={{ feedbackDialog, feedbackAttachment }}>` >
2016
+ * English. Optional since 0.12.0; a whole `FeedbackDialogLabels` still fits. */
2017
+ labels?: Partial<FeedbackDialogLabels>;
2018
+ submitting?: boolean;
2019
+ contextSlot?: ReactNode;
2020
+ attachmentAccept?: string[];
2021
+ maxAttachmentBytes?: number;
2022
+ /**
2023
+ * Optional: capture a screenshot of the underlying app view and return it as a
2024
+ * File. When provided, a "Capture screenshot" button is shown next to "Add
2025
+ * attachment"; the returned file is fed through the same validation + preview.
2026
+ */
2027
+ onCaptureScreenshot?: () => Promise<File | null>;
2028
+ /**
2029
+ * `false`: a report with only a subject can be sent, and the body's label says it is
2030
+ * optional (`bodyOptional`, unless `labels.body` is passed). Default `true`, the
2031
+ * dialog's behaviour until 0.14.2 (keksdose K1: its backend takes title-only reports).
2032
+ */
2033
+ requireBody?: boolean;
2034
+ }
2035
+ /** One attachment — a screenshot, a picked or a pasted image; a second replaces
2036
+ * nothing, it has to wait for the first to be removed. The default. */
2037
+ interface FeedbackDialogSingleProps extends FeedbackDialogBaseProps {
2038
+ attachments?: "single";
2039
+ onSubmit: (data: FeedbackSubmission) => void | Promise<void>;
2040
+ /** `info` (0.23.0) names the refused file and the limit — see
2041
+ * {@link FeedbackAttachmentErrorInfo}. */
2042
+ onAttachmentError?: (kind: "type" | "size", info: FeedbackAttachmentErrorInfo) => void;
2043
+ /** Multiple mode only — refused here rather than silently ignored. */
2044
+ maxAttachments?: never;
2045
+ }
2046
+ /**
2047
+ * One screenshot plus up to `maxAttachments` picked or pasted files (0.15.5, keksdose
2048
+ * dev#578: "pasted two photos, the second overwrote the first"). The capture button is
2049
+ * offered while there is no screenshot yet; the add button while there is room.
2050
+ */
2051
+ interface FeedbackDialogMultipleProps extends FeedbackDialogBaseProps {
2052
+ attachments: "multiple";
2053
+ /** Default `DEFAULT_MAX_ATTACHMENTS` (5). The screenshot does not count. */
2054
+ maxAttachments?: number;
2055
+ onSubmit: (data: FeedbackMultipleSubmission) => void | Promise<void>;
2056
+ /** `"count"`: more files arrived at once than there was room for; the surplus was
2057
+ * dropped. `info` (0.23.0) names the refused file(s) and the limit. */
2058
+ onAttachmentError?: (kind: FeedbackAttachmentError, info: FeedbackAttachmentErrorInfo) => void;
2059
+ }
2060
+ type FeedbackDialogProps = FeedbackDialogSingleProps | FeedbackDialogMultipleProps;
2061
+ /**
2062
+ * The generic feedback form dialog: category + subject + body + an optional image
2063
+ * attachment, with Ctrl/Cmd+Enter to submit. Domain-free — the app supplies the
2064
+ * category options, labels and an `onSubmit` that talks to its own backend, plus
2065
+ * an optional `contextSlot` for app-specific context (user, current URL, …).
2066
+ *
2067
+ * **A screenshot can be pasted straight in.** Ctrl/Cmd+V anywhere in the dialog
2068
+ * takes an image off the clipboard and makes it the attachment, through the same
2069
+ * validation and the same preview as the file picker. It is the gesture the two
2070
+ * ways in did not cover: `onCaptureScreenshot` snapshots the *whole* app view,
2071
+ * and the file picker needs a file — so somebody who wanted to show one panel,
2072
+ * or one region of one, had to save a crop to disk first and then find it again
2073
+ * (Steering Design feedback #39). The clipboard is where a region snip already
2074
+ * is on every platform.
2075
+ *
2076
+ * **`attachments="multiple"`** (0.15.5) takes several: every paste and pick adds a
2077
+ * chip, and `onSubmit` gets `{ screenshot, attachments }` ({@link
2078
+ * FeedbackMultipleSubmission}) instead of `attachment`. Opt-in, so a caller typed
2079
+ * against the one-file submission keeps compiling and behaving as before.
2080
+ */
2081
+ declare function FeedbackDialog(props: FeedbackDialogProps): react.JSX.Element | null;
2082
+
2083
+ declare const DEFAULT_ATTACHMENT_ACCEPT: string[];
2084
+ declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
2085
+ /** How many files `<FeedbackAttachmentField multiple>` takes when `max` is not given
2086
+ * (0.15.5). Five photos of one problem is already a lot to look through; a report
2087
+ * that needs more is a conversation, which the thread is for. */
2088
+ declare const DEFAULT_MAX_ATTACHMENTS = 5;
2089
+ /**
2090
+ * The field's own strings — the `feedbackAttachment` namespace of `<UiKitProvider
2091
+ * labels>`. The keys are {@link FeedbackAttachmentLabels}' own, so the `labels` prop
2092
+ * (and a whole `FeedbackDialogLabels` handed down by the dialog) merges over them
2093
+ * one to one. The optional heading, `attachment`, stays a prop: a note editor puts
2094
+ * the buttons straight under its textarea and wants none.
2095
+ *
2096
+ * Before 0.7.0 the two optional keys fell back to hard-coded English, so a German app
2097
+ * that relied on its provider got "Capture screenshot" under a German form.
2098
+ *
2099
+ * The three keys added in 0.15.5 for `multiple` mode are optional, so a complete
2100
+ * `UiKitLabels` typed before it still compiles; they fall back to English. So is
2101
+ * `attachmentScreenshot` (0.16.0).
2102
+ */
2103
+ interface FeedbackAttachmentFieldLabels {
2104
+ attachmentAdd: string;
2105
+ attachmentCapture: string;
2106
+ attachmentPaste: string;
2107
+ attachmentRemove: string;
2108
+ /** `multiple` mode: the accessible name of the list of chosen files — and, since
2109
+ * 0.16.0, the heading `<FeedbackDialog attachments="multiple">` puts over it. */
2110
+ attachmentList?: string;
2111
+ /** `multiple` mode (0.16.0): what the screenshot slot's chip is called — "Screenshot"
2112
+ * rather than the capture's file name ("screenshot.webp"), which says nothing a
2113
+ * reporter chose. The file name stays as the chip's second line. */
2114
+ attachmentScreenshot?: string;
2115
+ /** `multiple` mode: one chip's remove button — "Remove photo.jpg". Named per file,
2116
+ * because five buttons all called "Remove attachment" say nothing about which. */
2117
+ attachmentRemoveFile?: (name: string) => string;
2118
+ /** `multiple` mode: the line shown in place of the add buttons once `max` is reached. */
2119
+ attachmentLimit?: (max: number) => string;
2120
+ /** `refs` mode (0.22.0, keksdose K16): the second line of a chip whose upload is still
2121
+ * running, where an uploaded one shows its size — "Uploading…". Optional, like the
2122
+ * keys above, so a `UiKitLabels` typed before it still compiles. */
2123
+ attachmentUploading?: string;
2124
+ /** `refs` mode (0.23.0, keksdose G5a): {@link FeedbackAttachmentErrorInfo.message} for
2125
+ * an `"upload"` refusal — "“huge.png” could not be uploaded". The other refusals'
2126
+ * sentences are the `filePicker` namespace's, shared with FileButton. Optional, like
2127
+ * the keys above. */
2128
+ attachmentUploadFailed?: (name: string) => string;
2129
+ }
2130
+ declare const DEFAULT_FEEDBACK_ATTACHMENT_LABELS: FeedbackAttachmentFieldLabels;
2131
+ /** Why a file was turned away. `"count"` only ever comes from `multiple` (and `refs`)
2132
+ * mode: more files arrived at once than `max` left room for, and the surplus was
2133
+ * dropped. */
2134
+ type FeedbackAttachmentError = "type" | "size" | "count";
2135
+ /** `refs` mode's reasons: {@link FeedbackAttachmentError}, or `"upload"` — `onUpload`
2136
+ * rejected, and what it rejected with is `onError`'s second argument. A type of its
2137
+ * own so a host's exhaustive switch over the File modes' reasons stays exhaustive. */
2138
+ type FeedbackAttachmentRefsError = FeedbackAttachmentError | "upload";
2139
+ /**
2140
+ * What `onError` knows about a refusal beyond its kind (0.23.0, keksdose G5a): the file
2141
+ * it was about, the limit that refused it, and a sentence that says both.
2142
+ *
2143
+ * keksdose's support chat toasted "File too large" with no name — the field's `onError`
2144
+ * carried a kind and nothing else, so a refusal could not say WHICH of three pasted
2145
+ * screenshots went, nor what the ceiling was, and its own `AttachmentPicker` (a
2146
+ * FileButton, whose `onReject` hands over `{ file, message }`) said more than the kit's
2147
+ * field would have. This is that, for every mode.
2148
+ *
2149
+ * It arrives as an EXTRA argument, after the ones `onError` already had, so a handler
2150
+ * written for 0.22 — `(kind) => …`, or `refs` mode's `(kind, error) => …` — compiles
2151
+ * and behaves as before:
2152
+ *
2153
+ * - single and `multiple`: `onError(kind, info)`;
2154
+ * - `refs`: `onError(kind, error, info)` — the second place is `onUpload`'s rejection
2155
+ * since 0.22 (`undefined` for the other kinds, as it always was), so the info comes
2156
+ * third rather than changing what a 0.22 handler reads there. It also carries that
2157
+ * `error`, so one helper `(kind, info) => …` serves all three modes.
2158
+ *
2159
+ * An object rather than more positional arguments because what a host reaches for
2160
+ * differs by kind — the bytes for `"size"`, `max` for `"count"`, the server's answer for
2161
+ * `"upload"` — and a field added later must not shift anyone's arguments.
2162
+ */
2163
+ interface FeedbackAttachmentErrorInfo {
2164
+ /** The file refused — under the name the field would have given it (a pasted image
2165
+ * is already "pasted.png"). For `"count"`, the first of the surplus; for
2166
+ * `"upload"`, the file whose upload failed. */
2167
+ file: File;
2168
+ /** `"count"`: every file of the surplus (several can arrive in one pick). Otherwise
2169
+ * `[file]`. */
2170
+ files: File[];
2171
+ /**
2172
+ * One translated sentence naming the file and the limit — the ones FileButton's
2173
+ * `onReject` hands over, from the same `filePicker` namespace: "“huge.png” is larger
2174
+ * than 10 MB", "Only image/png, image/jpeg files", "“c.png” was not added: at most 5
2175
+ * files" (several at once: "3 files were not added"). `"upload"`: the field's own
2176
+ * `attachmentUploadFailed`, "“huge.png” could not be uploaded" — a host with a better
2177
+ * sentence from the server's answer uses `error`. Ready for a toast as it is.
2178
+ */
2179
+ message: string;
2180
+ /** The field's `maxBytes` — the ceiling a `"size"` refusal went over, in bytes. */
2181
+ maxBytes: number;
2182
+ /** The field's `accept` — the types a `"type"` refusal was not among. */
2183
+ accept: string[];
2184
+ /** The field's `max` — the ceiling a `"count"` refusal hit. Absent in single mode,
2185
+ * which holds one file by definition. */
2186
+ max?: number;
2187
+ /** `"upload"` only: what `onUpload` rejected with — `onError`'s second argument. */
2188
+ error?: unknown;
2189
+ }
2190
+ /**
2191
+ * One uploaded attachment in `refs` mode: what the host's upload answered with. `key`
2192
+ * identifies it (a storage key, an upload id) and is what a remove goes by; `name` is
2193
+ * what the chip says. `size` (bytes) and `type` (mime) are optional — given, the chip
2194
+ * shows the size and an image icon or a file icon accordingly.
2195
+ */
2196
+ interface FeedbackAttachmentRef {
2197
+ key: string;
2198
+ name: string;
2199
+ size?: number;
2200
+ type?: string;
2201
+ }
2202
+ interface FeedbackAttachmentFieldBaseProps {
2203
+ /** Prop > `<UiKitProvider labels={{ feedbackAttachment }}>` > English. Optional
2204
+ * since 0.7.0; `attachment` (the heading) is only ever read from here. */
2205
+ labels?: Partial<FeedbackAttachmentLabels> & Pick<Partial<FeedbackAttachmentFieldLabels>, "attachmentUploading" | "attachmentUploadFailed">;
2206
+ accept?: string[];
2207
+ maxBytes?: number;
2208
+ /**
2209
+ * Take no files for now (0.23.0, keksdose G5b): the add and capture buttons, the
2210
+ * hidden file input and every chip's remove button are natively disabled, and a paste
2211
+ * is let through untouched. The chips stay as they are — what is about to be sent
2212
+ * stays readable.
2213
+ *
2214
+ * For the moment a send is in flight. keksdose's support picker is `disabled` while
2215
+ * the message goes out, because the message carries the attachments AS THEY WERE at
2216
+ * the press: a chip removed mid-send has gone with it all the same, and one added
2217
+ * mid-send looks as if it had. The field has no drop target; the paste is its drop.
2218
+ *
2219
+ * This is a pause, not a lock that explains itself — for that, `refs` mode (the mode
2220
+ * that commits) takes `commit` and `disabledReason`.
2221
+ */
2222
+ disabled?: boolean;
2223
+ /** Snapshot the app view behind this and return it as a File. A "Capture
2224
+ * screenshot" button appears only when it is given. */
2225
+ onCaptureScreenshot?: () => Promise<File | null>;
2226
+ /** Listen for the paste on `document` rather than on this field's own
2227
+ * subtree. For a modal, which owns the whole page while it is up. */
2228
+ documentPaste?: boolean;
2229
+ /** Listen for the paste within this element's subtree rather than this
2230
+ * field's own — for a field standing *beside* the text box a paste is made
2231
+ * in, whose common parent is where the event bubbles to. Ignored when
2232
+ * `documentPaste` is set. */
2233
+ pasteFrom?: RefObject<HTMLElement | null>;
2234
+ /**
2235
+ * The add and capture buttons' look (0.24.0, keksdose) — Button's own `variant`.
2236
+ * Default `"secondary"`, the look they always had.
2237
+ *
2238
+ * keksdose's support chat puts this field in ChatComposer's `attachmentSlot`, in the
2239
+ * row with Send, where its own picker had been a `ghost` / `sm` FileButton: two
2240
+ * bordered full-size buttons under a chat box read as a second form, and the field
2241
+ * gave no way to say otherwise. Every mode, wherever the buttons appear; the chips'
2242
+ * remove buttons keep their size.
2243
+ */
2244
+ buttonVariant?: ButtonVariant;
2245
+ /** The add and capture buttons' size — Button's own `size`, with `buttonVariant`.
2246
+ * Default `"md"`. `"sm"` draws their icons at 14px, as a small button's are. */
2247
+ buttonSize?: ButtonSize;
2248
+ className?: string;
2249
+ }
2250
+ /** One file: choosing a second means removing the first. The field's only mode until 0.15.5. */
2251
+ interface FeedbackAttachmentFieldSingleProps extends FeedbackAttachmentFieldBaseProps {
2252
+ multiple?: false;
2253
+ refs?: false;
2254
+ value: File | null;
2255
+ onChange: (file: File | null) => void;
2256
+ /** A file was refused. `info` (0.23.0) names it and the limit — see
2257
+ * {@link FeedbackAttachmentErrorInfo}. */
2258
+ onError?: (kind: "type" | "size", info: FeedbackAttachmentErrorInfo) => void;
2259
+ max?: never;
2260
+ screenshot?: never;
2261
+ onScreenshotChange?: never;
2262
+ commit?: never;
2263
+ disabledReason?: never;
2264
+ }
2265
+ /**
2266
+ * Several files (0.15.5, keksdose dev#578: "pasted two photos, the second overwrote
2267
+ * the first"). Every way in ADDS — a pick of several files, a paste, a capture — up to
2268
+ * `max`, and each file is a removable chip.
2269
+ */
2270
+ interface FeedbackAttachmentFieldMultipleProps extends FeedbackAttachmentFieldBaseProps {
2271
+ multiple: true;
2272
+ refs?: false;
2273
+ value: File[];
2274
+ onChange: (files: File[]) => void;
2275
+ /** How many files `value` may hold. Default {@link DEFAULT_MAX_ATTACHMENTS} (5). The
2276
+ * add buttons and the paste hint are offered only while there is room. */
2277
+ max?: number;
2278
+ /** Per file: a rejected one is reported and the others are still added. `"count"` is
2279
+ * once per pick, with the whole surplus in `info.files`. `info` (0.23.0): see
2280
+ * {@link FeedbackAttachmentErrorInfo}. */
2281
+ onError?: (kind: FeedbackAttachmentError, info: FeedbackAttachmentErrorInfo) => void;
2282
+ /**
2283
+ * A separate slot for THE screenshot, outside `value` and `max`. Given
2284
+ * `onScreenshotChange`, what `onCaptureScreenshot` returns lands here instead of in
2285
+ * `value`, shown as the first chip, and the capture button is offered only while the
2286
+ * slot is empty — a second snapshot of the same view is not more evidence. This is
2287
+ * how `<FeedbackDialog attachments="multiple">` keeps the screenshot apart from the
2288
+ * photos; a form built from the parts can do the same.
2289
+ */
2290
+ screenshot?: File | null;
2291
+ onScreenshotChange?: (file: File | null) => void;
2292
+ commit?: never;
2293
+ disabledReason?: never;
2294
+ }
2295
+ /**
2296
+ * Uploaded on pick (0.22.0, keksdose K16). keksdose's support chat uploads each file
2297
+ * the moment it is chosen and sends the message with the REFS the uploads answered —
2298
+ * a 10 MB screenshot is refused while the reporter is still typing, not when they
2299
+ * press Send — so its `AttachmentPicker` could not use this field, whose value is
2300
+ * `File`s held until the form is submitted. Here the value is
2301
+ * {@link FeedbackAttachmentRef}s: every way in (pick, paste, capture) validates the
2302
+ * file as the other modes do, then hands it to `onUpload` and shows a chip with a
2303
+ * spinner until it answers; the ref it resolves to joins `value` through `onChange`.
2304
+ * A rejection drops the chip and reports `onError("upload", error)`. A chip is removed
2305
+ * BY KEY: `onChange` gets the list without it, and `onRemove` the key, for a host that
2306
+ * deletes the upload on the server too.
2307
+ *
2308
+ * Uploads still running count against `max`, so five picks in quick succession cannot
2309
+ * overshoot it; they are not in `value` until they land, so a send that reads `value`
2310
+ * sends only what has arrived — hold Send back while {@link onUploadingChange} says
2311
+ * an upload is running. Several files upload side by side and join in the order they
2312
+ * finish. The File modes are unchanged.
2313
+ */
2314
+ interface FeedbackAttachmentFieldRefsProps extends FeedbackAttachmentFieldBaseProps {
2315
+ refs: true;
2316
+ multiple?: never;
2317
+ value: FeedbackAttachmentRef[];
2318
+ onChange: (refs: FeedbackAttachmentRef[]) => void;
2319
+ /** Upload one file; resolve to its ref, or reject to refuse it. Called once per
2320
+ * accepted file, the moment it is chosen. */
2321
+ onUpload: (file: File) => Promise<FeedbackAttachmentRef>;
2322
+ /** A chip was removed — after `onChange` — with its ref's key. */
2323
+ onRemove?: (key: string) => void;
2324
+ /** Whether any upload is running: `true` when the first starts, `false` when the
2325
+ * last settles — for the host's Send, which should wait. */
2326
+ onUploadingChange?: (uploading: boolean) => void;
2327
+ /** How many refs `value` may hold, uploads in flight included. Default
2328
+ * {@link DEFAULT_MAX_ATTACHMENTS} (5). */
2329
+ max?: number;
2330
+ /** Per file. `"upload"` carries what `onUpload` rejected with as `error` (`undefined`
2331
+ * for the other kinds). `info` (0.23.0) comes third so a 0.22 handler's `error` is
2332
+ * still the second argument — see {@link FeedbackAttachmentErrorInfo}. */
2333
+ onError?: (kind: FeedbackAttachmentRefsError, error: unknown, info: FeedbackAttachmentErrorInfo) => void;
2334
+ /**
2335
+ * This field COMMITS (0.23.0): each file is uploaded the moment it is chosen, and a
2336
+ * remove may delete the upload (`onRemove`) — a save, unlike the File modes, which
2337
+ * only stage a file for a form sent later (and so stay open under a lock, like every
2338
+ * field). Under a locked {@link WriteLockProvider} it takes the `disabledReason` path
2339
+ * with the lock's reason, which wins over one of its own. No provider, or an unlocked
2340
+ * one: no effect.
2341
+ */
2342
+ commit?: boolean;
2343
+ /**
2344
+ * Why no file can be added or removed — the write lock's sentence, a quota, a thread
2345
+ * closed to replies. Unlike `disabled`, it SAYS so, the kit's commit-control way: the
2346
+ * buttons (add, capture, every chip's remove) stay focusable, `aria-disabled`, with
2347
+ * the reason in the kit Tooltip and their description; no pick, paste or remove gets
2348
+ * through; and the reason stands where the paste hint was, for a phone that never
2349
+ * hovers. The chips stay readable.
2350
+ */
2351
+ disabledReason?: ReactNode;
2352
+ screenshot?: never;
2353
+ onScreenshotChange?: never;
2354
+ }
2355
+ type FeedbackAttachmentFieldProps = FeedbackAttachmentFieldSingleProps | FeedbackAttachmentFieldMultipleProps | FeedbackAttachmentFieldRefsProps;
2356
+ /**
2357
+ * Picking one picture: the file dialog, a capture of the app view, or a paste.
2358
+ * With `multiple`, picking several (see {@link FeedbackAttachmentFieldMultipleProps}).
2359
+ *
2360
+ * Lifted out of {@link FeedbackDialog} so the *reply* half of the feature can
2361
+ * have it too (Steering Design feedback #128). A report is a conversation — it
2362
+ * is filed, it is answered, and the reporter sends it back saying that is not
2363
+ * what they meant — and the screenshot showing what they mean is taken at
2364
+ * whichever of those points they looked. Only the first of them had a way to
2365
+ * attach one, so everything after it had to be described in words.
2366
+ *
2367
+ * **Three ways in, and they are three because no one of them covers the others.**
2368
+ * The file dialog needs a file on disk; `onCaptureScreenshot` snapshots the
2369
+ * *whole* app view; and the clipboard is where a region snip already is on every
2370
+ * platform (Steering Design feedback #39). Somebody who wanted to show one panel
2371
+ * had to save a crop and then find it again.
2372
+ *
2373
+ * `documentPaste` and `pasteFrom` decide where the paste is listened for, and
2374
+ * it is a real choice rather than a flag with a default. A modal traps focus,
2375
+ * so while it is up every paste in the page is meant for it — including one
2376
+ * made with nothing in particular focused, which never reaches a React
2377
+ * `onPaste` on a child: that is `documentPaste`. An editor **inline on a
2378
+ * page** is not that: the page around it has its own fields, so it listens
2379
+ * within its own subtree and a paste elsewhere stays where it was aimed. But
2380
+ * "its own subtree" has to include the text box the paste is actually made in,
2381
+ * and that box is this field's *sibling*, not its child — a paste in it bubbles
2382
+ * to their common parent and never through here. `pasteFrom` is that parent
2383
+ * (Steering Design feedback #140): the element whose subtree is listened to,
2384
+ * handed in by whoever renders both the box and this field side by side.
2385
+ */
2386
+ declare function FeedbackAttachmentField(props: FeedbackAttachmentFieldProps): react.JSX.Element;
2387
+ /** What a pasted image is called once it is an attachment.
2388
+ *
2389
+ * The extension is read off the mime type rather than assumed to be `.png`:
2390
+ * Safari puts TIFF on the clipboard and a file called `pasted.png` that is not
2391
+ * a PNG is one the receiving end opens wrong. */
2392
+ declare function pastedName(type: string): string;
2393
+
2394
+ /**
2395
+ * The feedback **inbox**, as the parts two apps were each writing separately.
2396
+ *
2397
+ * `feedback-dialog.tsx` next door is the other half — the form somebody files a
2398
+ * report with — and the split between them is the same one: this owns the
2399
+ * *vocabulary*, the *policy* about how a report moves, and the *look*; the app
2400
+ * owns the data, the API and every string.
2401
+ *
2402
+ * It exists because both apps had grown their own copy. Keksdose's is the one
2403
+ * this is lifted from, comments and all, because it is the one that had been
2404
+ * argued with users for a year — the glyph per status, the two sizes of the
2405
+ * status control, what a row offers from where it currently stands. Steering
2406
+ * Design's was thinner in every one of those places and read as a different
2407
+ * product for no reason anyone chose.
2408
+ *
2409
+ * **What is deliberately NOT here.** The two apps store a report differently and
2410
+ * are meant to: one keeps the reporter's context in a JSON column and the
2411
+ * screenshot in an object store, the other keeps a `page_path` and the bytes in
2412
+ * the row. So there is no `Feedback` type in this file and nothing here takes
2413
+ * one. Every component takes the values it draws, and the detail panel is a
2414
+ * *shell* the app fills — which is what lets each keep the shape that suits it
2415
+ * without either of them inventing a second look for a status pill.
2416
+ */
2417
+ /** The seven states a report can be in.
2418
+ *
2419
+ * Shared value for value across both apps on purpose: it is what lets one habit,
2420
+ * and one agent prompt, work on either repo. Four are a chain and three sit off
2421
+ * it — see {@link visibleFeedbackStatuses} for what that buys. */
2422
+ type FeedbackStatus = "OPEN" | "IN_PROGRESS" | "IN_EVALUATION" | "NEEDS_LIVE_TEST" | "POSTPONED" | "DONE" | "WONT_DO";
2423
+ /** What a report is about. `CRASH` is filed by an error boundary and never
2424
+ * chosen, which is exactly why it is loud below and absent from every picker. */
2425
+ type FeedbackCategory = "CRASH" | "BUG" | "IDEA" | "QUESTION" | "OTHER";
2426
+ /**
2427
+ * A glyph and a tone per status.
2428
+ *
2429
+ * Colour alone is not a label — two of these sit a hue apart, and a consumer who
2430
+ * moves `--brand` can park it beside any of the others — so every status carries
2431
+ * its own shape as well. Declaration order is chain order, and
2432
+ * {@link FEEDBACK_STATUS_ORDER} is derived from it rather than restated, because
2433
+ * a restated list cannot be checked for exhaustiveness: an eighth status would
2434
+ * break the build here and leave a literal seven long.
2435
+ */
2436
+ declare const FEEDBACK_STATUS_META: Record<FeedbackStatus, {
2437
+ icon: LucideIcon;
2438
+ activeBg: string;
2439
+ activeText: string;
2440
+ }>;
2441
+ /** Chain order, then the three off it. The order a picker offers, and the rank a
2442
+ * status column sorts by — so a list sorted by status reads as a queue rather
2443
+ * than as an alphabet. */
2444
+ declare const FEEDBACK_STATUS_ORDER: FeedbackStatus[];
2445
+ /** The next status along the chain, or null at the end (or off it, as `WONT_DO`
2446
+ * is). What a swipe-to-advance gesture commits. */
2447
+ declare function nextFeedbackStatus(current: FeedbackStatus): FeedbackStatus | null;
2448
+ /**
2449
+ * The steps that make sense from where a row currently stands.
2450
+ *
2451
+ * For the compact control in a table cell: it is a glanceable triage affordance,
2452
+ * and a row of seven icons in a cell is noise. One step forward, one step back
2453
+ * (so an item can be sent back for rework), and any of the three off-chain
2454
+ * verdicts — which is what makes those usable as verdicts at all.
2455
+ *
2456
+ * The two parking states are not dead ends: each offers the step that resumes
2457
+ * work and the ones that close it, but deliberately **not each other** —
2458
+ * "postponed" and "waiting on a deploy" are different answers to different
2459
+ * questions, and a row moving between them directly is a re-triage, which starts
2460
+ * by picking the work back up.
2461
+ */
2462
+ declare function visibleFeedbackStatuses(current: FeedbackStatus): FeedbackStatus[];
2463
+ /**
2464
+ * Every status, in chain order — what an EXPANDED row offers.
2465
+ *
2466
+ * {@link visibleFeedbackStatuses} narrows the choice to the steps that make
2467
+ * sense from where a row is, which is right for a table cell. Once the row is
2468
+ * open in front of you, that same narrowing turns every non-adjacent move into a
2469
+ * walk: OPEN to DONE meant three round trips, and WONT_DO could not be left at
2470
+ * all except through a rework note.
2471
+ *
2472
+ * Takes a `current` it does not use, so the two policies read as one pair at the
2473
+ * call sites and a future rule ("terminal rows still cannot jump to X") has a
2474
+ * place to live.
2475
+ */
2476
+ declare function selectableFeedbackStatuses(_current: FeedbackStatus): FeedbackStatus[];
2477
+ /**
2478
+ * Per-category badge treatment, the counterpart to the status meta above.
2479
+ *
2480
+ * A category cell that is one grey pill holding the raw enum makes a CRASH —
2481
+ * filed automatically, by somebody staring at a broken page right now — read
2482
+ * exactly like a QUESTION, and sit unnoticed in the queue. `--danger` plus its own
2483
+ * glyph is what makes that impossible; the hand-filed categories stay
2484
+ * deliberately quiet so that the loud one means something.
2485
+ *
2486
+ * Declaration order is triage order, CRASH first.
2487
+ */
2488
+ declare const FEEDBACK_CATEGORY_META: Record<FeedbackCategory, {
2489
+ icon: LucideIcon;
2490
+ badgeBg: string;
2491
+ badgeText: string;
2492
+ }>;
2493
+ /** Triage order, CRASH first — also a category column's sort key and the option
2494
+ * order in its filter. Sorting by the raw enum is alphabetical, which parks
2495
+ * CRASH between BUG and IDEA. */
2496
+ declare const FEEDBACK_CATEGORY_ORDER: FeedbackCategory[];
2497
+ /** A category's rank for a column sort. Anything this build has never heard of —
2498
+ * an older client against a newer API — sorts LAST rather than to `indexOf`'s
2499
+ * −1, which would rank it above CRASH. */
2500
+ declare function feedbackCategoryRank(category: FeedbackCategory): number;
2501
+ /**
2502
+ * The category as a badge.
2503
+ *
2504
+ * Falls back to OTHER's treatment for a category this build has never heard of,
2505
+ * so an older client against a newer API degrades to a readable neutral pill
2506
+ * instead of throwing on `meta.icon` — a crash report must not be able to cause
2507
+ * one. The *label* is the caller's, and for the same reason it needs the same
2508
+ * guard: pass what OTHER is called if you cannot name the value you were given.
2509
+ */
2510
+ declare function FeedbackCategoryBadge({ category, label, compact, className, }: {
2511
+ category: FeedbackCategory;
2512
+ label: ReactNode;
2513
+ compact?: boolean;
2514
+ className?: string;
2515
+ }): react.JSX.Element;
2516
+ /** Where a report stands, as a badge — for the places that only *report* the
2517
+ * status rather than offering to change it. */
2518
+ declare function FeedbackStatusBadge({ status, label, className, }: {
2519
+ status: FeedbackStatus;
2520
+ label: ReactNode;
2521
+ className?: string;
2522
+ }): react.JSX.Element;
2523
+ /**
2524
+ * A row of statuses to switch a report to — either a table column's icon row or
2525
+ * an expanded panel's labelled pills.
2526
+ *
2527
+ * One component for both, because everything except the class strings is the
2528
+ * same decision: which one is current, and when the buttons are disabled. Two
2529
+ * copies had already drifted — only the icon variant carried `aria-label` and
2530
+ * `aria-pressed`, so the pill row was unlabelled for a screen reader.
2531
+ *
2532
+ * WHICH statuses to offer is the caller's, not this component's:
2533
+ * {@link visibleFeedbackStatuses} for a compact column,
2534
+ * {@link selectableFeedbackStatuses} for an expanded row. Passing the list keeps
2535
+ * that policy readable at the two call sites instead of hiding it behind
2536
+ * `variant`.
2537
+ */
2538
+ declare function FeedbackStatusTransitions({ status, statuses, canEdit, onPick, variant, label, className, }: {
2539
+ status: FeedbackStatus;
2540
+ statuses: FeedbackStatus[];
2541
+ canEdit: boolean;
2542
+ onPick: (status: FeedbackStatus) => void;
2543
+ variant: "icon" | "pill";
2544
+ /** What each status is called, translated by the app. */
2545
+ label: (status: FeedbackStatus) => string;
2546
+ className?: string;
2547
+ }): react.JSX.Element;
2548
+ /**
2549
+ * A textarea and its two buttons — for an outcome, for a note sent back with a
2550
+ * report, for a body being corrected.
2551
+ *
2552
+ * One component because all three are the same gesture: a draft that is not
2553
+ * committed until it is saved. Ctrl/⌘+Enter submits, which is the same shortcut
2554
+ * the compose dialog next door uses, so the habit carries across the feature.
2555
+ *
2556
+ * ## `initial` seeds the draft; it does not own it (changed 2026-09-22)
2557
+ *
2558
+ * This used to re-seed from `initial` in an effect, and that effect threw away
2559
+ * whatever was in the box — **and the picture attached to it** — every time the
2560
+ * prop arrived with a different value. `initial` is normally the saved note, so
2561
+ * the list refreshing under the editor, or the owner re-deriving the same string,
2562
+ * was enough: a triager halfway through a reply, with a screenshot picked out,
2563
+ * lost both and got the saved text back with no way to undo it.
2564
+ *
2565
+ * A draft belongs to the thing being edited, so switching to a different note is a
2566
+ * different editor — say so with a `key`:
2567
+ *
2568
+ * ```tsx
2569
+ * <FeedbackNoteEditor key={note.id} initial={note.body} … />
2570
+ * ```
2571
+ *
2572
+ * Where the id is not in hand at the call site, pass {@link resetKey} instead and
2573
+ * the editor re-seeds when THAT changes. Either way the decision is the caller's,
2574
+ * which is the point: the editor cannot tell a new subject from a new render.
2575
+ */
2576
+ declare function FeedbackNoteEditor({ initial, pending, onSave, onCancel, saveLabel, cancelLabel, placeholder, rows, attachment, resetKey, }: {
2577
+ initial: string;
2578
+ pending: boolean;
2579
+ onSave: (value: string, attachment?: File | null) => void;
2580
+ onCancel: () => void;
2581
+ saveLabel: ReactNode;
2582
+ cancelLabel: ReactNode;
2583
+ /** A line above the field saying what to write, not an in-field placeholder:
2584
+ * a hint that disappears the moment somebody starts typing is a hint that is
2585
+ * gone exactly when it is being followed. */
2586
+ placeholder?: ReactNode;
2587
+ rows?: number;
2588
+ /** Offer a picture with the note (Steering Design feedback #128). Omitted,
2589
+ * the editor is exactly the text box it always was — which is what the
2590
+ * *outcome* editor beside it wants, since an outcome is the answer rather
2591
+ * than the evidence. */
2592
+ attachment?: FeedbackNoteAttachment;
2593
+ /** Change this to say "the editor is now editing something ELSE", and the draft
2594
+ * and its attachment are dropped and re-seeded from `initial`. For call sites
2595
+ * that cannot put a `key` on the editor (see the note above). Leave it out and
2596
+ * the draft is never thrown away behind the user's back. */
2597
+ resetKey?: string | number;
2598
+ }): react.JSX.Element;
2599
+ /** What {@link FeedbackNoteEditor} needs in order to offer a picture with the
2600
+ * note: the same four things {@link FeedbackAttachmentField} takes, so the
2601
+ * reply path is held to the app's own limits rather than to the defaults. */
2602
+ interface FeedbackNoteAttachment {
2603
+ labels: FeedbackAttachmentLabels;
2604
+ accept?: string[];
2605
+ maxBytes?: number;
2606
+ /** `info` (0.23.0) names the refused file and the limit. */
2607
+ onError?: (kind: "type" | "size", info: FeedbackAttachmentErrorInfo) => void;
2608
+ onCaptureScreenshot?: () => Promise<File | null>;
2609
+ }
2610
+ /**
2611
+ * One labelled block of an opened report.
2612
+ *
2613
+ * The detail panel is a stack of these, and it is a stack rather than a
2614
+ * component with fixed fields on purpose: the two apps keep a report's context
2615
+ * and its screenshot in genuinely different places, and a shell that insisted on
2616
+ * both would force one of them to invent a shape it does not have. What is
2617
+ * shared is what a section *looks* like — and that is all that made the two
2618
+ * panels read as different products.
2619
+ */
2620
+ declare function FeedbackDetailSection({ title, action, children, }: {
2621
+ title: ReactNode;
2622
+ /** Something on the title's own line — an edit button, a resolved-at date. */
2623
+ action?: ReactNode;
2624
+ children: ReactNode;
2625
+ }): react.JSX.Element;
2626
+ /** The stack a detail panel is. Here so the spacing between sections is decided
2627
+ * once rather than by whichever app was written second. */
2628
+ declare function FeedbackDetail({ children }: {
2629
+ children: ReactNode;
2630
+ }): react.JSX.Element;
2631
+ /** Prose inside a section — a body, an outcome, a note.
2632
+ *
2633
+ * `whitespace-pre-wrap` is the whole component: a report is written in
2634
+ * paragraphs, and a note appended to it later is separated by blank lines that
2635
+ * carry the entire "this arrived after the answer" reading. */
2636
+ declare function FeedbackProse({ children, empty }: {
2637
+ children?: string;
2638
+ empty?: ReactNode;
2639
+ }): react.JSX.Element;
2640
+
2641
+ /**
2642
+ * The conversation under a report: who said what, when, with what attached — and the
2643
+ * box to answer in.
2644
+ *
2645
+ * Both apps had written it by hand. kastlan's feedback page grew a comment list of
2646
+ * bordered boxes with `slate-*` literals (feedback-page.tsx, "keksdose left this
2647
+ * unbuilt"), and keksdose built the same thing a second time for support
2648
+ * (support-thread.tsx) with sides, bubbles and a composer that clears only what it
2649
+ * sent. This is that second one, generalised: the kit owns the look and the
2650
+ * behaviour, the app owns the data, the upload and every word it does not share.
2651
+ *
2652
+ * **Own vs other** is the caller's per message (`own`), not a comparison the kit makes
2653
+ * against a user id: whose message sits at the END side depends on who is reading,
2654
+ * and only the app knows that (keksdose's support thread labelled a member's question
2655
+ * "Du" in the admin panel the first time round, by reading the wrong field).
2656
+ *
2657
+ * **Redaction.** A thread is somebody's words about their own data — exactly what a
2658
+ * host's demo / screen-share mode blurs. Bodies, authors and attachments carry
2659
+ * `data-private` (the attribute `Tooltip redact` and `StatTile sensitive` use) unless
2660
+ * `redact={false}`.
2661
+ *
2662
+ * **RTL.** Sides are logical — `justify-end` is the reading end, and the bubble's
2663
+ * tucked corner is `rounded-ee` / `rounded-es` — and each body is `dir="auto"`, so a
2664
+ * Hebrew reply in an English thread (or the reverse) lays out as its own language.
2665
+ *
2666
+ * **A chat, too** (keksdose G4/G5). keksdose's support chat is the same conversation
2667
+ * read the chat way: status lines between the messages ("Closed automatically",
2668
+ * "Reopened"), a day line where the date changes, clock times under it, Enter to send
2669
+ * and several files uploaded ahead of the send. Each of those is an opt-in here
2670
+ * (`kind: "event"`, `daySeparators`, `timeFormat="clock"`, `sendOn="enter"`,
2671
+ * `attachmentSlot` + `canSend`), so the feedback thread's defaults stay as they were.
2672
+ */
2673
+ /** The `feedbackThread` namespace of `<UiKitProvider labels>`. */
2674
+ interface FeedbackThreadLabels {
2675
+ /** Accessible name of the message list. */
2676
+ thread: string;
2677
+ empty: string;
2678
+ loading: string;
2679
+ /** Author line of an `own` message that has no `author` of its own. */
2680
+ you: string;
2681
+ /** The badge beside a `staff` author. */
2682
+ staff: string;
2683
+ /** Accessible name of a message's attachment list. */
2684
+ attachments: string;
2685
+ }
2686
+ declare const DEFAULT_FEEDBACK_THREAD_LABELS: FeedbackThreadLabels;
2687
+ /** The `feedbackComposer` namespace of `<UiKitProvider labels>`. The attach buttons'
2688
+ * words are `feedbackAttachment`'s, shared with the dialog and the note editor. */
2689
+ interface FeedbackComposerLabels {
2690
+ /** Accessible name of the text box. */
2691
+ field: string;
2692
+ placeholder: string;
2693
+ send: string;
2694
+ /** The shortcut line, given the platform's modifier ("Ctrl" or "⌘"). */
2695
+ sendHint: (modifier: string) => string;
2696
+ /** The shortcut line under `sendOn="enter"` (keksdose G5): Enter sends, so say how a
2697
+ * new line is made. */
2698
+ sendHintEnter: string;
2699
+ }
2700
+ declare const DEFAULT_FEEDBACK_COMPOSER_LABELS: FeedbackComposerLabels;
2701
+ interface FeedbackThreadAttachment {
2702
+ id?: string | number;
2703
+ name: string;
2704
+ /** Where to open it. Left out, the attachment is listed by name only. */
2705
+ url?: string;
2706
+ /** MIME type; an `image/*` with a `url` is shown as a thumbnail. */
2707
+ type?: string;
2708
+ /** Bytes, shown beside a non-image. */
2709
+ size?: number;
2710
+ }
2711
+ interface FeedbackThreadMessage {
2712
+ /** Leave out, or `"message"`. `"event"` is a {@link FeedbackThreadEvent}. */
2713
+ kind?: "message";
2714
+ id: string | number;
2715
+ /** Who wrote it. Left out on an `own` message, it reads "You". */
2716
+ author?: ReactNode;
2717
+ /** A `Date`, an ISO string or epoch ms. */
2718
+ createdAt: Date | string | number;
2719
+ body: string;
2720
+ attachments?: readonly FeedbackThreadAttachment[];
2721
+ /** Written by whoever is reading: sits at the end side, in the brand tint. */
2722
+ own?: boolean;
2723
+ /** Written by the team rather than a user: gets the "Staff" badge. */
2724
+ staff?: boolean;
2725
+ }
2726
+ /**
2727
+ * A line in the thread that nobody wrote — "Closed automatically", "Marked as
2728
+ * resolved", "Reopened" — drawn centred and muted with its time, no author, no side,
2729
+ * no bubble.
2730
+ *
2731
+ * keksdose G4: its support chat interleaves these with the messages, and as a message
2732
+ * they came out as a bubble from nobody at the start side, which reads as the member
2733
+ * having said "resolved". Word it for the READER, as with `own`: the app knows whether
2734
+ * "you reopened it" or "Anna reopened it" is true for the person looking.
2735
+ *
2736
+ * The text is the app's, not somebody's words about their data, so it is NOT tagged
2737
+ * `data-private`; one that names a person can wrap the name in its own
2738
+ * `<span data-private>` (`body` is a node for that reason).
2739
+ */
2740
+ interface FeedbackThreadEvent {
2741
+ kind: "event";
2742
+ id: string | number;
2743
+ /** A `Date`, an ISO string or epoch ms. */
2744
+ createdAt: Date | string | number;
2745
+ body: ReactNode;
2746
+ }
2747
+ /** One row of a {@link FeedbackThread}: a message, or an event line between them. */
2748
+ type FeedbackThreadItem = FeedbackThreadMessage | FeedbackThreadEvent;
2749
+ interface FeedbackThreadProps {
2750
+ /** Oldest first. Event lines ({@link FeedbackThreadEvent}) sit among the messages. */
2751
+ messages: readonly FeedbackThreadItem[];
2752
+ loading?: boolean;
2753
+ /** Replaces the default "No comments yet". */
2754
+ empty?: ReactNode;
2755
+ /**
2756
+ * Draw one attachment yourself — for files behind auth, which a plain `<img src>`
2757
+ * cannot fetch (kastlan's `AuthedImage`), or a lightbox. The default is a thumbnail
2758
+ * link for an image with a `url`, a file link otherwise.
2759
+ */
2760
+ renderAttachment?: (attachment: FeedbackThreadAttachment, message: FeedbackThreadMessage) => ReactNode;
2761
+ /** Tag bodies, authors and attachments `data-private`. Default true. */
2762
+ redact?: boolean;
2763
+ /**
2764
+ * How a row's time reads. `"relative"` (default): "5 minutes ago", a date past six
2765
+ * days — right for a report's comments, read days apart. `"clock"`: the time of day
2766
+ * in the locale ("14:05", "2:05 PM") — the chat look, keksdose G4; pair it with
2767
+ * `daySeparators`, which say which day that clock time is on. Either way the full
2768
+ * date and time is in the Tooltip.
2769
+ */
2770
+ timeFormat?: "relative" | "clock";
2771
+ /**
2772
+ * A centred day line before the first row and wherever the next row is on another
2773
+ * calendar day (the device's zone): "Today", "Yesterday", else the date — keksdose
2774
+ * G4. "Today" / "Yesterday" are `Intl.RelativeTimeFormat`'s own words in the kit
2775
+ * locale, so there is no label to translate. Default false.
2776
+ */
2777
+ daySeparators?: boolean;
2778
+ /** "Now" for the relative times and the day lines — pin it in tests and stories.
2779
+ * Default: the clock. */
2780
+ now?: Date | number;
2781
+ /** Overrides the provider's locale for the times. */
2782
+ locale?: string;
2783
+ labels?: Partial<FeedbackThreadLabels>;
2784
+ className?: string;
2785
+ }
2786
+ declare function FeedbackThread({ messages, loading, empty, renderAttachment, redact, now, locale: localeProp, timeFormat, daySeparators, labels: labelsProp, className, }: FeedbackThreadProps): react.JSX.Element;
2787
+ /** What the composer's attach control takes — {@link FeedbackNoteAttachment} with the
2788
+ * labels optional, since the field reads `feedbackAttachment` from the provider, and
2789
+ * `onError` the field's own (0.23.0): it is handed the refused file and the limit too
2790
+ * (`FeedbackAttachmentErrorInfo`), and a `(kind) => …` handler still fits. Since
2791
+ * 0.24.0 also the field's `buttonVariant` / `buttonSize`, for a composer whose row
2792
+ * wants smaller or quieter attach buttons than the bordered `md` default. */
2793
+ type FeedbackComposerAttachment = Omit<FeedbackNoteAttachment, "labels" | "onError"> & {
2794
+ labels?: Partial<FeedbackAttachmentLabels>;
2795
+ onError?: FeedbackAttachmentFieldSingleProps["onError"];
2796
+ } & Pick<FeedbackAttachmentFieldSingleProps, "buttonVariant" | "buttonSize">;
2797
+ /**
2798
+ * What a render-prop {@link FeedbackComposerProps.attachmentSlot} is handed (0.24.0,
2799
+ * keksdose).
2800
+ *
2801
+ * keksdose's support chat put `<FeedbackAttachmentField refs>` in the slot and a
2802
+ * screenshot pasted into the reply box never reached it: the box is the field's
2803
+ * sibling, so the paste bubbles to their common parent — the composer's root — and the
2804
+ * field hears it only through `pasteFrom`, which needs that root. The composer kept it
2805
+ * to itself, so keksdose wrapped the whole composer in a ref'd `<div>` of its own just
2806
+ * to have an element to hand over.
2807
+ */
2808
+ interface FeedbackComposerSlotContext {
2809
+ /**
2810
+ * The composer's root, round the text box and this slot — the field's `pasteFrom`,
2811
+ * as it is: `pasteFrom={slot.root}`.
2812
+ *
2813
+ * A ref, not the element, because `pasteFrom` is one: the field reads `.current` in
2814
+ * an effect, and the slot renders INSIDE this root, so the two are committed together
2815
+ * and React attaches the root before any effect of the slot's runs — the first paste
2816
+ * after the first paint already lands. The element itself would be `null` on the
2817
+ * first render (it does not exist yet) and could only arrive by a second render
2818
+ * through state; the ref is the same object every render, so the field's listener is
2819
+ * added once and never re-added.
2820
+ *
2821
+ * With the built-in `attachment` on as well, it listens on this root too: hand the
2822
+ * root to one field only, or an image pasted once is attached twice.
2823
+ */
2824
+ root: RefObject<HTMLElement | null>;
2825
+ /** The composer's `pending` — a send is in flight. For the field's `disabled`
2826
+ * (keksdose G5b): the message carries the attachments as they were at the press. */
2827
+ pending: boolean;
2828
+ }
2829
+ interface FeedbackComposerProps {
2830
+ /**
2831
+ * Send the comment. Return the promise: the box clears when it RESOLVES, and only of
2832
+ * what was sent — text typed while it was in flight stays. A rejection keeps
2833
+ * everything for a retry (surface the error yourself; the composer stays quiet).
2834
+ *
2835
+ * `attachment` is the built-in field's one picture. Files the host uploaded ahead
2836
+ * (`attachmentSlot`) are the host's state, read by the host here — and `body` may be
2837
+ * `""` when `canSend` let an attachments-only message go.
2838
+ */
2839
+ onSend: (body: string, attachment: File | null) => void | Promise<unknown>;
2840
+ /** The send is in flight: a spinner on the button and no second send. */
2841
+ pending?: boolean;
2842
+ /** Offer one picture with the comment (file, paste or `onCaptureScreenshot`).
2843
+ * `true` for the defaults. Left out, the composer is text only. */
2844
+ attachment?: boolean | FeedbackComposerAttachment;
2845
+ /**
2846
+ * The host's own attach control, in the row with Send where the built-in field sits
2847
+ * (after it, if both are on) — keksdose G5: its support chat uploads up to N files
2848
+ * AHEAD of the send and sends their refs, which one `File` in `onSend` cannot carry.
2849
+ * The slot is the host's picker plus the chips of what is uploaded; the upload, the
2850
+ * refs and clearing them once `onSend` resolves stay with the host. Pair it with
2851
+ * `canSend`.
2852
+ *
2853
+ * A node, or (0.24.0) a function of {@link FeedbackComposerSlotContext} that returns
2854
+ * one — for a field that wants the composer's root as its `pasteFrom`, so a
2855
+ * screenshot pasted into the box reaches it, and `pending` for its `disabled`:
2856
+ *
2857
+ * ```tsx
2858
+ * attachmentSlot={({ root, pending }) => (
2859
+ * <FeedbackAttachmentField refs pasteFrom={root} disabled={pending} … />
2860
+ * )}
2861
+ * ```
2862
+ *
2863
+ * Called once per render of the composer, and not at all while `disabledReason`
2864
+ * stands in for it.
2865
+ */
2866
+ attachmentSlot?: ReactNode | ((slot: FeedbackComposerSlotContext) => ReactNode);
2867
+ /**
2868
+ * Whether Send is enabled, over the composer's own rule (some text in the box) —
2869
+ * for state the composer cannot see, i.e. `attachmentSlot`'s (keksdose G5): `true`
2870
+ * with files ready makes an empty draft sendable (`onSend("", null)`), `false` while
2871
+ * an upload is still running holds even a written reply back. Left out, the text
2872
+ * decides. `pending` blocks a send either way, as does a draft past `maxLength`.
2873
+ */
2874
+ canSend?: boolean;
2875
+ /**
2876
+ * Which key sends. `"mod-enter"` (default): Ctrl/⌘+Enter, the report dialog's and
2877
+ * note editor's shortcut, with plain Enter a new line — feedback is written in
2878
+ * paragraphs. `"enter"`: the chat way (keksdose G5) — Enter sends, Shift+Enter is a
2879
+ * new line, Ctrl/⌘+Enter still sends; an Enter that confirms an IME composition
2880
+ * (Japanese, Chinese input) is the IME's, never a send.
2881
+ */
2882
+ sendOn?: "mod-enter" | "enter";
2883
+ /** Rendered INSTEAD of the composer — the thread is closed, or read-only for this
2884
+ * reader. */
2885
+ disabledReason?: ReactNode;
2886
+ rows?: number;
2887
+ /**
2888
+ * The longest draft the box takes, in UTF-16 code units as the browser counts — the
2889
+ * server's limit, so a reply too long for it is cut off while it is typed rather than
2890
+ * refused by a 422 after the press (keksdose G6: its support replies are capped at
2891
+ * 4,000 on the server, and its other text fields already count against that with
2892
+ * Textarea's `maxLength` + `showCount` since 0.22; the reply box, a composer, could
2893
+ * not). The box's own `maxLength`, so typing and pasting stop at it.
2894
+ *
2895
+ * {@link FeedbackComposerHandle.insertText} is not stopped by it — the browser limits
2896
+ * typing, not a script — and a canned reply is not cut mid-sentence to fit. A draft
2897
+ * past the limit therefore holds Send back (whatever `canSend` says, as `pending`
2898
+ * does) until it is trimmed; with `showCount` the counter, red at the limit, says by
2899
+ * how much.
2900
+ */
2901
+ maxLength?: number;
2902
+ /**
2903
+ * A live "12/4000" under the box, with `maxLength` — Textarea's `showCount`, the same
2904
+ * counter (keksdose G6): the count is part of the box's description, read with it on
2905
+ * focus, and a polite live region speaks only on entering the last stretch and at the
2906
+ * limit, never per keystroke. Under `size="sm"` the hidden send hint stays the box's
2907
+ * description too, before the count. Ignored without `maxLength`.
2908
+ */
2909
+ showCount?: boolean;
2910
+ /** The counter's words — the `characterCount` namespace, as on Textarea. */
2911
+ countLabels?: Partial<CharacterCountLabels>;
2912
+ /**
2913
+ * The box's hint, over the `placeholder` label — keksdose F9: an admin answering a
2914
+ * support ticket is asked something else ("Reply to Anna…") than a member adding to
2915
+ * their own report, and one provider-wide label cannot say both.
2916
+ */
2917
+ placeholder?: string;
2918
+ /**
2919
+ * The draft, controlled — for a host that keeps it itself (saves it per ticket,
2920
+ * prefills a template). Left out, the composer keeps its own. Either way a send
2921
+ * that resolves clears only what was sent: controlled, that is an
2922
+ * `onValueChange("")` the host receives like any keystroke, and only if the draft
2923
+ * is still the one that went out.
2924
+ */
2925
+ value?: string;
2926
+ /** Every change to the draft — typing, {@link FeedbackComposerHandle.insertText}, the
2927
+ * clear after a send. Required to change a controlled `value`. */
2928
+ onValueChange?: (value: string) => void;
2929
+ /** {@link FeedbackComposerHandle}: put text into the draft from outside (canned-reply
2930
+ * chips) or focus the box. */
2931
+ ref?: Ref<FeedbackComposerHandle>;
2932
+ labels?: Partial<FeedbackComposerLabels>;
2933
+ className?: string;
2934
+ /**
2935
+ * `"sm"` for a narrow host — keksdose's assistant launcher, a small floating panel
2936
+ * (0.22): a small Send button, and the send hint ("Enter to send, Shift + Enter for a
2937
+ * new line") hidden from view but kept as the box's description, so a keyboard or
2938
+ * screen-reader user still learns the shortcut. Default `"md"`.
2939
+ */
2940
+ size?: "md" | "sm";
2941
+ /**
2942
+ * On the composer's root — the box, or the `disabledReason` line in its place —
2943
+ * with any `data-*` attribute beside it (keksdose K17). keksdose's assistant tour
2944
+ * points at the chat box with `[data-tour="assistant-ask"]`, and a composer that
2945
+ * dropped every attribute it was not told about left the anchor nowhere: the
2946
+ * assistant kept its hand-built box rather than lose the tour step.
2947
+ */
2948
+ id?: string;
2949
+ /** `data-*` attributes for the root, as `id` — a tour anchor, a test id. */
2950
+ [dataAttribute: `data-${string}`]: string | number | boolean | undefined;
2951
+ }
2952
+ /**
2953
+ * What a {@link FeedbackComposer} `ref` holds.
2954
+ *
2955
+ * keksdose F9: the support admin answers the same five questions all day and wants
2956
+ * chips above the box ("Thanks, fixed in the next release") that drop their text in
2957
+ * where the caret is. A controlled `value` alone cannot do that well — the host sees
2958
+ * the string, not the caret, so it could only append — so the composer, which owns
2959
+ * the textarea, does the splice.
2960
+ */
2961
+ interface FeedbackComposerHandle {
2962
+ /**
2963
+ * Insert `text` at the caret, replacing any selection (the caret the box last had:
2964
+ * a click on a chip blurs it, and the selection survives the blur), then focus the
2965
+ * box with the caret after the inserted text so the reply can go on. Nothing is
2966
+ * added around it — put a space or a newline in `text` if the reply needs one. A
2967
+ * no-op while `disabledReason` replaces the box.
2968
+ */
2969
+ insertText: (text: string) => void;
2970
+ focus: () => void;
2971
+ }
2972
+ /**
2973
+ * The answer box under a {@link FeedbackThread}: a textarea, an optional picture,
2974
+ * and Send — Ctrl/⌘+Enter sends, the shortcut the report dialog and the note editor
2975
+ * use, so the habit carries across the feature. Plain Enter is a new line: feedback is
2976
+ * written in paragraphs, unlike a chat — which `sendOn="enter"` is for (keksdose G5).
2977
+ */
2978
+ 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;
2979
+ /**
2980
+ * {@link FeedbackComposer} under a name that is not about feedback (keksdose K17).
2981
+ *
2982
+ * The component was never feedback-specific: a textarea, an optional picture or a
2983
+ * host's upload slot, Send, `sendOn="enter"` for the chat way. keksdose's assistant
2984
+ * and support chat are chats, not reports, and an import of `FeedbackComposer` there
2985
+ * reads as a mistake to the next person. The same function, not a wrapper, so the
2986
+ * two names cannot drift.
2987
+ */
2988
+ declare const ChatComposer: typeof FeedbackComposer;
2989
+ /** {@link FeedbackComposerProps}, for {@link ChatComposer}. */
2990
+ type ChatComposerProps = FeedbackComposerProps;
2991
+ /** {@link FeedbackComposerHandle}, for {@link ChatComposer}. */
2992
+ type ChatComposerHandle = FeedbackComposerHandle;
2993
+ /** {@link FeedbackComposerLabels}, for {@link ChatComposer} — still the `feedbackComposer`
2994
+ * namespace of the provider. */
2995
+ type ChatComposerLabels = FeedbackComposerLabels;
2996
+ /** {@link FeedbackComposerSlotContext}, for {@link ChatComposer}'s `attachmentSlot`. */
2997
+ type ChatComposerSlotContext = FeedbackComposerSlotContext;
2998
+
1780
2999
  /**
1781
3000
  * The `confirmDialog` namespace of `<UiKitProvider labels>`: the two buttons' fallback
1782
3001
  * text. A call that knows what it is confirming says so per call (`confirmLabel:
@@ -2116,6 +3335,27 @@ interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "childr
2116
3335
  /** The save button's variant. Default `brand`; `danger` for a save that destroys
2117
3336
  * (kastlan's `destructive` flag on its own FormActions). */
2118
3337
  submitVariant?: ButtonVariant;
3338
+ /**
3339
+ * The Cancel button's variant. Default `secondary` (the outlined button, as before).
3340
+ * `ghost` for a row where Cancel should step back further than an outline — keksdose
3341
+ * G3: a quiet inline row (a confirm under a table row, a card's own small editor)
3342
+ * whose Cancel was a ghost button before it moved onto FormActions, which drew every
3343
+ * Cancel outlined.
3344
+ */
3345
+ cancelVariant?: ButtonVariant;
3346
+ /**
3347
+ * The size of every button the row draws itself — Save, Cancel and the
3348
+ * `{ label, onClick }` form of {@link destructive}: Button's `size`. Default `md`.
3349
+ * `sm` (12px text, `px-2 py-1`) for a dense row: a confirm inside a table's expansion
3350
+ * row, a toolbar card. keksdose G3: two such rows had small hand-built buttons and lost
3351
+ * them on adopting FormActions, which had no size. At `sm` the spinner and
3352
+ * {@link submitIcon} shrink with the text.
3353
+ *
3354
+ * Your own elements (`children`, an element passed as `destructive`, `start`) are
3355
+ * yours to size — pass them `size="sm"` too. A `size` in {@link submitProps} still
3356
+ * wins for Save, as it always has.
3357
+ */
3358
+ size?: ButtonSize;
2119
3359
  /**
2120
3360
  * A destructive action at the START of the row, apart from Save and Cancel — the
2121
3361
  * "Delete" of an edit dialog. Pass `{ label, onClick }` for the kit's quiet danger
@@ -2223,7 +3463,7 @@ interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "childr
2223
3463
  * The spinner is the kit's {@link Spinner}, drawn inside the button with `label={null}`
2224
3464
  * so the button's name stays its text; `aria-busy` is what says it is working.
2225
3465
  */
2226
- 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, submitShortcut, submitShortcutHint, children, className, style, ...rest }: FormActionsProps): react.JSX.Element;
3466
+ 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;
2227
3467
 
2228
3468
  /**
2229
3469
  * Who holds one record, and the owner's every way of changing that — Kurvenschmiede's
@@ -2784,6 +4024,9 @@ interface UiKitLabels {
2784
4024
  phoneInput: PhoneInputLabels;
2785
4025
  /** 0.22.0: `SignChip` — the outflow / inflow toggle beside an amount. */
2786
4026
  signChip: SignChipLabels;
4027
+ /** 0.23.0: `ColumnMapper` / `ColumnRoleTable` — a pasted or dropped table, a role per
4028
+ * column. */
4029
+ columnMapper: ColumnMapperLabels;
2787
4030
  }
2788
4031
  /**
2789
4032
  * A label override, as deep as the labels go: an object of labels (a namespace, or a
@@ -2978,4 +4221,4 @@ declare function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels;
2978
4221
  */
2979
4222
  declare function missingKitLabels(labels: UiKitLabelOverrides | undefined, reference: UiKitLabels): string[];
2980
4223
 
2981
- export { DEFAULT_FILE_LABELS as $, type AppShellLabels as A, Button as B, type CalculatorLabels as C, type CommonLabels as D, type ConfirmDialogLabels as E, type ConfirmFn as F, type ConfirmOptions as G, ConfirmProvider as H, type ConfirmProviderProps as I, type ConfirmTone as J, CopyButton as K, type CopyButtonLabels as L, type CopyButtonProps as M, type CurrencyLabels as N, CurrentPasswordInput as O, type CurrentPasswordInputLabels as P, type CurrentPasswordInputProps as Q, DEFAULT_APP_SHELL_LABELS as R, DEFAULT_CALCULATOR_LABELS as S, DEFAULT_CHARACTER_COUNT_LABELS as T, DEFAULT_COMBOBOX_LABELS as U, DEFAULT_COMMON_LABELS as V, DEFAULT_CONFIRM_DIALOG_LABELS as W, DEFAULT_COPY_BUTTON_LABELS as X, DEFAULT_CURRENCY_LABELS as Y, DEFAULT_DANGER_CONFIRM_LABELS as Z, DEFAULT_DATE_PICKER_LABELS as _, type ButtonClassesOptions as a, type InputProps as a$, DEFAULT_FILE_PICKER_LABELS as a0, DEFAULT_FORM_ACTIONS_LABELS as a1, DEFAULT_IBAN_INPUT_LABELS as a2, DEFAULT_MULTI_SELECT_LABELS as a3, DEFAULT_PASSWORD_REVEAL_LABELS as a4, DEFAULT_PHONE_INPUT_LABELS as a5, DEFAULT_PICKER_SHEET_LABELS as a6, DEFAULT_SHARE_CARD_LABELS as a7, DEFAULT_SWIPEABLE_ROW_LABELS as a8, DEFAULT_TABS_LABELS as a9, type FilePickerLabels as aA, type FileRejection as aB, type FileRejectionReason as aC, type FileScreenOptions as aD, FloatingField as aE, type FloatingFieldProps as aF, FormActions as aG, type FormActionsAlign as aH, type FormActionsDestructive as aI, type FormActionsLabels as aJ, type FormActionsPlacement as aK, type FormActionsProps as aL, type FormActionsStickyWithin as aM, type FormActionsSubmitProps as aN, type FormActionsSubmitShortcut as aO, IbanInput as aP, type IbanInputLabels as aQ, type IbanInputProps as aR, IconButton as aS, type IconButtonGlyphSize as aT, type IconButtonLinkProps as aU, type IconButtonProps as aV, type IconButtonSize as aW, type IconButtonTone as aX, type IconButtonToneColor as aY, type IconButtonVariant as aZ, Input as a_, DEFAULT_TOP_BAR_LABELS as aa, DangerConfirm as ab, type DangerConfirmLabels as ac, type DangerConfirmProps as ad, type DangerConsequence as ae, type DatePickerLabels as af, EmptyState as ag, type EmptyStateProps as ah, FIELD_BASE as ai, FIELD_DISPLAY as aj, FIELD_FLOATING_PAD as ak, FIELD_INVALID as al, FIELD_TRIGGER as am, FIELD_WRITABLE_LOOK as an, FLOATING_INPUT_CLASS as ao, FLOATING_LABEL_CLASS as ap, FLOATING_LABEL_STATIC as aq, FieldChevron as ar, type FieldChevronProps as as, FieldHint as at, type FieldHintProps as au, FieldLabel as av, type FieldLabelProps as aw, FileButton as ax, type FileButtonProps as ay, type FileLabels as az, type ButtonLinkProps as b, useKitLocale as b$, type KitDateFormatContext as b0, type KitDateFormatter as b1, type KitLinkComponent as b2, type KitLinkProps as b3, Label as b4, type LabelOverride as b5, type LabelProps as b6, type MultiSelectLabels as b7, PHONE_QUERY as b8, type PasswordRevealLabels as b9, Textarea as bA, type TextareaProps as bB, type TopBarLabels as bC, TypedConfirmField as bD, type TypedConfirmFieldLabels as bE, type TypedConfirmFieldProps as bF, type TypedMatch as bG, type UiKitLabelOverrides as bH, type UiKitLabels as bI, UiKitProvider as bJ, type UiKitProviderProps as bK, type UseFilePickerOptions as bL, type UseFilePickerReturn as bM, buttonClasses as bN, formatFileSize as bO, matchesAccept as bP, missingKitLabels as bQ, resolvePasswordRevealLabels as bR, typedMatches as bS, useConfirm as bT, useFilePicker as bU, useKitChartTooltipPlacement as bV, useKitDateFormatter as bW, useKitFileLabels as bX, useKitLabelOverrides as bY, useKitLabels as bZ, useKitLink as b_, PhoneInput as ba, type PhoneInputLabels as bb, type PhoneInputProps as bc, type PickerSheetLabels as bd, type ResponsiveFormActionsPlacement as be, Select as bf, type SelectProps as bg, type ShareAddRequest as bh, type ShareCandidate as bi, ShareCard as bj, type ShareCardLabels as bk, type ShareCardProps as bl, ShareDialog as bm, type ShareDialogProps as bn, type ShareGrantee as bo, SharePanel as bp, type SharePanelProps as bq, type SharePendingGrant as br, type ShareRole as bs, Spinner as bt, type SpinnerProps as bu, type SwipeableRowLabels as bv, type TabItem as bw, Tabs as bx, type TabsLabels as by, type TabsProps as bz, type ButtonProps as c, useKitWeekStart as c0, type FilePickHandler as c1, usePromisePending as c2, formatAccept as c3, judgePick as c4, screenFiles as c5, summariseRejections as c6, 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, type ComboboxLabels as z };
4224
+ export { DEFAULT_COMMON_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 ChatComposerSlotContext as G, type ComboboxLabels as H, type CommonLabels as I, type ConfirmDialogLabels as J, type ConfirmFn as K, type ConfirmOptions as L, ConfirmProvider as M, type ConfirmProviderProps as N, type ConfirmTone as O, CopyButton as P, type CopyButtonLabels as Q, type CopyButtonProps as R, type CurrencyLabels as S, CurrentPasswordInput as T, type CurrentPasswordInputLabels as U, type CurrentPasswordInputProps as V, DEFAULT_APP_SHELL_LABELS as W, DEFAULT_ATTACHMENT_ACCEPT as X, DEFAULT_CALCULATOR_LABELS as Y, DEFAULT_CHARACTER_COUNT_LABELS as Z, DEFAULT_COMBOBOX_LABELS as _, type ButtonClassesOptions as a, FeedbackDetail as a$, DEFAULT_CONFIRM_DIALOG_LABELS as a0, DEFAULT_COPY_BUTTON_LABELS as a1, DEFAULT_CURRENCY_LABELS as a2, DEFAULT_DANGER_CONFIRM_LABELS as a3, DEFAULT_DATE_PICKER_LABELS as a4, DEFAULT_FEEDBACK_ATTACHMENT_LABELS as a5, DEFAULT_FEEDBACK_COMPOSER_LABELS as a6, DEFAULT_FEEDBACK_DIALOG_LABELS as a7, DEFAULT_FEEDBACK_THREAD_LABELS as a8, DEFAULT_FILE_LABELS as a9, FIELD_DISPLAY as aA, FIELD_FLOATING_PAD as aB, FIELD_INVALID as aC, FIELD_TRIGGER as aD, FIELD_WRITABLE_LOOK as aE, FLOATING_INPUT_CLASS as aF, FLOATING_LABEL_CLASS as aG, type FeedbackAttachmentError as aH, type FeedbackAttachmentErrorInfo as aI, FeedbackAttachmentField as aJ, type FeedbackAttachmentFieldLabels as aK, type FeedbackAttachmentFieldMultipleProps as aL, type FeedbackAttachmentFieldProps as aM, type FeedbackAttachmentFieldRefsProps as aN, type FeedbackAttachmentFieldSingleProps as aO, type FeedbackAttachmentLabels as aP, type FeedbackAttachmentRef as aQ, type FeedbackAttachmentRefsError as aR, type FeedbackCategory as aS, FeedbackCategoryBadge as aT, type FeedbackCategoryOption as aU, FeedbackComposer as aV, type FeedbackComposerAttachment as aW, type FeedbackComposerHandle as aX, type FeedbackComposerLabels as aY, type FeedbackComposerProps as aZ, type FeedbackComposerSlotContext as a_, DEFAULT_FILE_PICKER_LABELS as aa, DEFAULT_FORM_ACTIONS_LABELS as ab, DEFAULT_IBAN_INPUT_LABELS as ac, DEFAULT_MAX_ATTACHMENTS as ad, DEFAULT_MAX_ATTACHMENT_BYTES as ae, DEFAULT_MULTI_SELECT_LABELS as af, DEFAULT_PASSWORD_REVEAL_LABELS as ag, DEFAULT_PHONE_INPUT_LABELS as ah, DEFAULT_PICKER_SHEET_LABELS as ai, DEFAULT_SHARE_CARD_LABELS as aj, DEFAULT_SWIPEABLE_ROW_LABELS as ak, DEFAULT_TABS_LABELS as al, DEFAULT_TOP_BAR_LABELS as am, DangerConfirm as an, type DangerConfirmLabels as ao, type DangerConfirmProps as ap, type DangerConfirmValues as aq, type DangerConsequence as ar, type DatePickerLabels as as, EmptyState as at, type EmptyStateProps as au, FEEDBACK_CATEGORY_META as av, FEEDBACK_CATEGORY_ORDER as aw, FEEDBACK_STATUS_META as ax, FEEDBACK_STATUS_ORDER as ay, FIELD_BASE as az, type ButtonLinkProps as b, type LabelProps as b$, FeedbackDetailSection as b0, FeedbackDialog as b1, type FeedbackDialogLabels as b2, type FeedbackDialogMultipleProps as b3, type FeedbackDialogProps as b4, type FeedbackDialogSingleProps as b5, type FeedbackDialogTextLabels as b6, type FeedbackMultipleSubmission as b7, type FeedbackNoteAttachment as b8, FeedbackNoteEditor as b9, type FormActionsAlign as bA, type FormActionsDestructive as bB, type FormActionsLabels as bC, type FormActionsPlacement as bD, type FormActionsProps as bE, type FormActionsStickyWithin as bF, type FormActionsSubmitProps as bG, type FormActionsSubmitShortcut as bH, IbanInput as bI, type IbanInputLabels as bJ, type IbanInputProps as bK, IconButton as bL, type IconButtonGlyphSize as bM, type IconButtonLinkProps as bN, type IconButtonProps as bO, type IconButtonSize as bP, type IconButtonTone as bQ, type IconButtonToneColor as bR, type IconButtonVariant as bS, Input as bT, type InputProps as bU, type KitDateFormatContext as bV, type KitDateFormatter as bW, type KitLinkComponent as bX, type KitLinkProps as bY, Label as bZ, type LabelOverride as b_, FeedbackProse as ba, type FeedbackStatus as bb, FeedbackStatusBadge as bc, FeedbackStatusTransitions as bd, type FeedbackSubmission as be, FeedbackThread as bf, type FeedbackThreadAttachment as bg, type FeedbackThreadEvent as bh, type FeedbackThreadItem as bi, type FeedbackThreadLabels as bj, type FeedbackThreadMessage as bk, type FeedbackThreadProps as bl, FieldChevron as bm, type FieldChevronProps as bn, FieldHint as bo, type FieldHintProps as bp, FileButton as bq, type FileButtonProps as br, type FileLabels as bs, type FilePickerLabels as bt, type FileRejection as bu, type FileRejectionReason as bv, type FileScreenOptions as bw, FloatingField as bx, type FloatingFieldProps as by, FormActions as bz, type ButtonProps as c, type FilePickHandler as c$, type MultiSelectLabels as c0, PHONE_QUERY as c1, type PasswordRevealLabels as c2, PhoneInput as c3, type PhoneInputLabels as c4, type PhoneInputProps as c5, type PickerSheetLabels as c6, type ResponsiveFormActionsPlacement as c7, Select as c8, type SelectProps as c9, type UiKitLabelOverrides as cA, type UiKitLabels as cB, UiKitProvider as cC, type UiKitProviderProps as cD, type UseFilePickerOptions as cE, type UseFilePickerReturn as cF, buttonClasses as cG, feedbackCategoryRank as cH, formatFileSize as cI, matchesAccept as cJ, missingKitLabels as cK, nextFeedbackStatus as cL, pastedName as cM, resolvePasswordRevealLabels as cN, selectableFeedbackStatuses as cO, typedMatches as cP, useConfirm as cQ, useFilePicker as cR, useKitChartTooltipPlacement as cS, useKitDateFormatter as cT, useKitFileLabels as cU, useKitLabelOverrides as cV, useKitLabels as cW, useKitLink as cX, useKitLocale as cY, useKitWeekStart as cZ, visibleFeedbackStatuses as c_, type ShareAddRequest as ca, type ShareCandidate as cb, ShareCard as cc, type ShareCardLabels as cd, type ShareCardProps as ce, ShareDialog as cf, type ShareDialogProps as cg, type ShareGrantee as ch, SharePanel as ci, type SharePanelProps as cj, type SharePendingGrant as ck, type ShareRole as cl, Spinner as cm, type SpinnerProps as cn, type SwipeableRowLabels as co, type TabItem as cp, Tabs as cq, type TabsLabels as cr, type TabsProps as cs, Textarea as ct, type TextareaProps as cu, type TopBarLabels as cv, TypedConfirmField as cw, type TypedConfirmFieldLabels as cx, type TypedConfirmFieldProps as cy, type TypedMatch as cz, type ButtonSize as d, usePromisePending as d0, formatAccept as d1, judgePick as d2, screenFiles as d3, summariseRejections as d4, 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 };