@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.
- package/README.md +42 -25
- package/dist/chart.d.ts +8 -7
- package/dist/components/amount-input.d.ts +34 -7
- package/dist/components/amount-input.js +14 -10
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +26 -0
- package/dist/components/autocomplete.js +164 -137
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-group.d.ts +8 -7
- package/dist/components/calculator.d.ts +8 -7
- package/dist/components/column-mapper.d.ts +235 -0
- package/dist/components/column-mapper.js +411 -0
- package/dist/components/column-mapper.js.map +1 -0
- package/dist/components/combobox-core.d.ts +39 -2
- package/dist/components/combobox-core.js +29 -6
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +113 -3
- package/dist/components/combobox.js +456 -313
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +8 -7
- package/dist/components/confirm-dialog.js +7 -8
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/copy-button.d.ts +5 -4
- package/dist/components/country-select.d.ts +50 -7
- package/dist/components/country-select.js +65 -9
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +8 -7
- package/dist/components/danger-confirm.js +64 -7
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/date-picker.d.ts +41 -0
- package/dist/components/date-picker.js +269 -8
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +48 -2
- package/dist/components/entity-combobox.js +159 -114
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +8 -7
- package/dist/components/field-parts.d.ts +116 -6
- package/dist/components/field-parts.js +84 -0
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/field-strip.d.ts +105 -0
- package/dist/components/field-strip.js +46 -0
- package/dist/components/field-strip.js.map +1 -0
- package/dist/components/file-button.d.ts +8 -7
- package/dist/components/file-dropzone.d.ts +8 -7
- package/dist/components/form-actions.d.ts +8 -7
- package/dist/components/form-actions.js +23 -3
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/iban-input.d.ts +8 -7
- package/dist/components/icon-picker.d.ts +10 -1
- package/dist/components/icon-picker.js +12 -4
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/language-select.d.ts +8 -7
- package/dist/components/money-field.d.ts +11 -7
- package/dist/components/money-field.js.map +1 -1
- package/dist/components/month-picker.js +2 -1
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +31 -2
- package/dist/components/multi-entity-combobox.js +152 -103
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/number-field.d.ts +8 -7
- package/dist/components/number-input.d.ts +8 -7
- package/dist/components/numpad-sheet.d.ts +8 -7
- package/dist/components/phone-input.d.ts +8 -7
- package/dist/components/reauth-dialog.d.ts +2 -2
- package/dist/components/reauth-dialog.js +6 -8
- package/dist/components/reauth-dialog.js.map +1 -1
- package/dist/components/series-chart.d.ts +8 -7
- package/dist/components/settings-fields.d.ts +8 -7
- package/dist/components/share-card.d.ts +8 -7
- package/dist/components/swatch-picker.d.ts +17 -1
- package/dist/components/swatch-picker.js +10 -4
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/text-link.d.ts +8 -7
- package/dist/components/tile-radio.d.ts +20 -0
- package/dist/components/tile-radio.js +25 -8
- package/dist/components/tile-radio.js.map +1 -1
- package/dist/components/time-input.d.ts +8 -7
- package/dist/components/toggle-group.js +2 -2
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/trigger-aria.d.ts +3 -0
- package/dist/components/trigger-aria.js +3 -1
- package/dist/components/trigger-aria.js.map +1 -1
- package/dist/components/ui.d.ts +5 -4
- package/dist/components/ui.js +60 -28
- package/dist/components/ui.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +66 -1
- package/dist/feedback/feedback-attachment.js +185 -65
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +66 -1
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +67 -252
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +66 -287
- package/dist/feedback/feedback-thread.js +16 -3
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/{kit-labels-R8mIAc9N.d.ts → feedback-DOwPu-Il.d.ts} +1273 -30
- package/dist/feedback.d.ts +65 -3
- package/dist/hooks/use-file-drop.d.ts +8 -7
- package/dist/i18n/defaults.d.ts +8 -7
- package/dist/i18n/defaults.js +3 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +8 -7
- package/dist/i18n/german.js +36 -2
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +5 -4
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +8 -7
- package/dist/i18n/locales/de-CH.d.ts +8 -7
- package/dist/i18n/locales/en.d.ts +8 -7
- package/dist/i18n/locales/en.js +7 -0
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +8 -7
- package/dist/i18n/locales/es.js +37 -2
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +8 -7
- package/dist/i18n/locales/fr.js +36 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +8 -7
- package/dist/i18n/locales/hu.js +38 -2
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +8 -7
- package/dist/i18n/locales/it.js +37 -2
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +8 -7
- package/dist/i18n/locales/zh.js +34 -2
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.d.ts +8 -7
- package/dist/i18n/review.js +20 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/column-mapping.d.ts +81 -0
- package/dist/lib/column-mapping.js +108 -0
- package/dist/lib/column-mapping.js.map +1 -0
- package/dist/lib/strip-fade.d.ts +2 -2
- package/dist/lib/strip-fade.js.map +1 -1
- package/dist/lib/table-text.d.ts +109 -1
- package/dist/lib/table-text.js +122 -1
- package/dist/lib/table-text.js.map +1 -1
- package/dist/rhf/fields.d.ts +142 -13
- package/dist/rhf/fields.js +185 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/rhf/form.d.ts +8 -7
- package/dist/rhf.d.ts +9 -8
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +8 -7
- package/dist/shell/top-bar-brand.d.ts +8 -7
- package/dist/shell/topbar-action-menu.d.ts +36 -3
- package/dist/shell/topbar-action-menu.js +74 -33
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +8 -7
- package/dist/table-text.d.ts +1 -1
- package/dist/wizard/stepper-nav.d.ts +38 -9
- package/dist/wizard/stepper-nav.js +4 -0
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard.d.ts +8 -7
- package/package.json +1 -1
- package/src/components/amount-input.tsx +50 -14
- package/src/components/autocomplete.tsx +188 -116
- package/src/components/column-mapper.tsx +768 -0
- package/src/components/combobox-core.tsx +82 -9
- package/src/components/combobox.tsx +655 -335
- package/src/components/confirm-dialog.tsx +12 -8
- package/src/components/country-select.tsx +135 -22
- package/src/components/danger-confirm.tsx +274 -24
- package/src/components/date-picker.tsx +423 -10
- package/src/components/entity-combobox.tsx +243 -129
- package/src/components/field-parts.tsx +224 -5
- package/src/components/field-strip.tsx +149 -0
- package/src/components/form-actions.tsx +52 -5
- package/src/components/icon-picker.tsx +23 -4
- package/src/components/money-field.tsx +3 -0
- package/src/components/month-picker.tsx +2 -1
- package/src/components/multi-entity-combobox.tsx +221 -121
- package/src/components/reauth-dialog.tsx +17 -18
- package/src/components/swatch-picker.tsx +29 -5
- package/src/components/tile-radio.tsx +74 -13
- package/src/components/toggle-group.tsx +2 -2
- package/src/components/trigger-aria.ts +5 -0
- package/src/components/ui.tsx +114 -33
- package/src/feedback/feedback-attachment.tsx +372 -72
- package/src/feedback/feedback-dialog.tsx +7 -3
- package/src/feedback/feedback-inbox.tsx +3 -2
- package/src/feedback/feedback-thread.tsx +112 -9
- package/src/i18n/defaults.ts +2 -0
- package/src/i18n/german.ts +42 -0
- package/src/i18n/kit-labels.tsx +4 -0
- package/src/i18n/locales/en.ts +27 -5
- package/src/i18n/locales/es.ts +41 -0
- package/src/i18n/locales/fr.ts +42 -0
- package/src/i18n/locales/hu.ts +37 -0
- package/src/i18n/locales/it.ts +41 -0
- package/src/i18n/locales/zh.ts +32 -0
- package/src/i18n/review.ts +19 -0
- package/src/index.ts +18 -0
- package/src/lib/column-mapping.ts +234 -0
- package/src/lib/strip-fade.ts +2 -2
- package/src/lib/table-text.ts +271 -0
- package/src/rhf/fields.tsx +421 -6
- package/src/rhf.ts +2 -1
- package/src/shell/topbar-action-menu.tsx +134 -38
- package/src/wizard/stepper-nav.tsx +35 -1
- package/dist/components/field-anatomy.d.ts +0 -95
- package/dist/components/field-anatomy.js +0 -84
- package/dist/components/field-anatomy.js.map +0 -1
- package/dist/feedback-attachment-NhUm7Zga.d.ts +0 -367
- 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 {
|
|
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
|
|
1454
|
-
/** Show a password field; confirm
|
|
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
|
|
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
|
|
1479
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
1500
|
-
*
|
|
1501
|
-
*
|
|
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,
|
|
1537
|
-
*
|
|
1538
|
-
*
|
|
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 {
|
|
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 };
|