@eifi1/ui-kit 0.23.0 → 0.24.1
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 +6 -6
- package/dist/chart.d.ts +2 -4
- package/dist/components/amount-input.d.ts +16 -9
- package/dist/components/amount-input.js +13 -11
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +5 -0
- package/dist/components/autocomplete.js +39 -37
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-group.d.ts +2 -4
- package/dist/components/calculator.d.ts +2 -4
- package/dist/components/column-mapper.d.ts +62 -9
- package/dist/components/column-mapper.js +85 -49
- package/dist/components/column-mapper.js.map +1 -1
- package/dist/components/combobox.d.ts +33 -1
- package/dist/components/combobox.js +8 -2
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +2 -4
- package/dist/components/copy-button.d.ts +2 -4
- package/dist/components/danger-confirm.d.ts +2 -4
- package/dist/components/danger-confirm.js +52 -5
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +13 -1
- package/dist/components/entity-combobox.js +13 -4
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +2 -4
- package/dist/components/file-button.d.ts +2 -4
- package/dist/components/file-dropzone.d.ts +2 -4
- package/dist/components/form-actions.d.ts +1 -3
- package/dist/components/form-actions.js +15 -1
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/iban-input.d.ts +2 -4
- package/dist/components/language-select.d.ts +2 -4
- package/dist/components/money-field.d.ts +2 -4
- package/dist/components/multi-entity-combobox.d.ts +5 -1
- package/dist/components/multi-entity-combobox.js +11 -3
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/number-field.d.ts +2 -4
- package/dist/components/number-input.d.ts +2 -4
- package/dist/components/numpad-sheet.d.ts +2 -4
- package/dist/components/phone-input.d.ts +2 -4
- package/dist/components/series-chart.d.ts +2 -4
- package/dist/components/settings-fields.d.ts +2 -4
- package/dist/components/share-card.d.ts +1 -3
- package/dist/components/text-link.d.ts +1 -3
- package/dist/components/time-input.d.ts +2 -4
- package/dist/components/ui.d.ts +2 -4
- package/dist/components/ui.js +55 -17
- package/dist/components/ui.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +66 -1
- package/dist/feedback/feedback-attachment.js +32 -12
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +66 -1
- package/dist/feedback/feedback-inbox.d.ts +67 -253
- package/dist/feedback/feedback-thread.d.ts +1 -3
- package/dist/feedback/feedback-thread.js +8 -2
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/{feedback-BxeQVzwq.d.ts → feedback-DOwPu-Il.d.ts} +878 -18
- package/dist/feedback.d.ts +2 -4
- package/dist/hooks/use-file-drop.d.ts +2 -4
- package/dist/i18n/defaults.d.ts +2 -4
- package/dist/i18n/german.d.ts +2 -4
- package/dist/i18n/kit-labels.d.ts +1 -3
- package/dist/i18n/languages.d.ts +2 -4
- package/dist/i18n/locales/de-CH.d.ts +2 -4
- package/dist/i18n/locales/en.d.ts +2 -4
- package/dist/i18n/locales/es.d.ts +2 -4
- package/dist/i18n/locales/fr.d.ts +2 -4
- package/dist/i18n/locales/hu.d.ts +2 -4
- package/dist/i18n/locales/it.d.ts +2 -4
- package/dist/i18n/locales/zh.d.ts +2 -4
- package/dist/i18n/review.d.ts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/lib/strip-fade.d.ts +2 -2
- package/dist/lib/strip-fade.js.map +1 -1
- package/dist/rhf/fields.d.ts +59 -8
- package/dist/rhf/fields.js +61 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/rhf/form.d.ts +2 -4
- package/dist/rhf.d.ts +3 -5
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +1 -3
- package/dist/shell/top-bar-brand.d.ts +2 -4
- package/dist/shell.d.ts +1 -3
- package/dist/wizard/stepper-nav.d.ts +2 -4
- package/dist/wizard.d.ts +2 -4
- package/package.json +2 -2
- package/src/components/amount-input.tsx +37 -20
- package/src/components/autocomplete.tsx +16 -5
- package/src/components/column-mapper.tsx +181 -79
- package/src/components/combobox.tsx +41 -3
- package/src/components/danger-confirm.tsx +193 -22
- package/src/components/entity-combobox.tsx +28 -5
- package/src/components/form-actions.tsx +20 -1
- package/src/components/multi-entity-combobox.tsx +16 -3
- package/src/components/ui.tsx +107 -0
- package/src/feedback/feedback-attachment.tsx +65 -12
- package/src/feedback/feedback-thread.tsx +66 -6
- package/src/lib/strip-fade.ts +2 -2
- package/src/rhf/fields.tsx +167 -6
- package/src/rhf.ts +1 -1
- package/dist/feedback-attachment-fGAzZPf0.d.ts +0 -469
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { l as FeedbackAttachmentLabels, k as FeedbackAttachmentFieldSingleProps, g as FeedbackAttachmentFieldLabels, u as FeedbackDialogTextLabels } from './feedback-attachment-fGAzZPf0.js';
|
|
2
|
-
import { FeedbackNoteAttachment } from './feedback/feedback-inbox.js';
|
|
3
1
|
import * as react from 'react';
|
|
4
|
-
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';
|
|
5
3
|
import { TooltipSide } from './components/tooltip.js';
|
|
6
4
|
import { f as DataTableLabels } from './data-table-labels-B7OdnM0S.js';
|
|
7
5
|
import { MiniCalendarLabels, WeekDay } from './components/mini-calendar.js';
|
|
@@ -25,13 +23,13 @@ import { SwatchPickerLabels } from './components/swatch-picker.js';
|
|
|
25
23
|
import { IconPickerLabels } from './components/icon-picker.js';
|
|
26
24
|
import { DialogFrameProps, DialogFrameLabels } from './components/dialog-frame.js';
|
|
27
25
|
import { MeasuredGridLabels } from './components/measured-grid.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';
|
|
@@ -1531,15 +1529,99 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
|
|
|
1531
1529
|
/** The warning above the fields. Defaults to `labels.prompt`. */
|
|
1532
1530
|
prompt?: ReactNode;
|
|
1533
1531
|
/** `"danger"` (default) for what cannot be undone; `"warning"` for what can, at a
|
|
1534
|
-
* cost (loading demo data over your own). Colours the prompt and the
|
|
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. */
|
|
1535
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;
|
|
1536
1598
|
/** Visible text of the arm button; defaults to `labels.arm`. */
|
|
1537
1599
|
armLabel?: ReactNode;
|
|
1538
1600
|
/** Visible text of the confirm button; defaults to `labels.confirm`. */
|
|
1539
1601
|
confirmLabel?: ReactNode;
|
|
1540
|
-
/**
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
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
|
+
*/
|
|
1543
1625
|
busy?: boolean;
|
|
1544
1626
|
/** The arm button is disabled. */
|
|
1545
1627
|
disabled?: boolean;
|
|
@@ -1574,9 +1656,10 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
|
|
|
1574
1656
|
}
|
|
1575
1657
|
/**
|
|
1576
1658
|
* An "arm → confirm" tile for destructive actions: one button, which expands into a
|
|
1577
|
-
* warning, an optional list of consequences,
|
|
1578
|
-
*
|
|
1579
|
-
* until every guard is
|
|
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).
|
|
1580
1663
|
*
|
|
1581
1664
|
* A held confirm SAYS which guard is still open (0.23, keksdose G4a): it is
|
|
1582
1665
|
* `aria-disabled` rather than `disabled` — still focusable, so a keyboard user can land
|
|
@@ -1584,8 +1667,10 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
|
|
|
1584
1667
|
* “DELETE” to confirm", "Tick the box to confirm", "Enter your password to confirm";
|
|
1585
1668
|
* `labels.needs*`), the first open guard in the order they are drawn. FormActions'
|
|
1586
1669
|
* `submitDisabledReason` does the same for a form's Save. Pressing it, or Enter in a
|
|
1587
|
-
* field, does nothing. A lock's reason wins over a guard's
|
|
1588
|
-
* confirm is plainly disabled, its spinner
|
|
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`).
|
|
1589
1674
|
*
|
|
1590
1675
|
* Keksdose hand-rolled it three times (load demo data, wipe everything, reset a
|
|
1591
1676
|
* budget) and then as `shared/components/danger-confirm.tsx`; the only app-specific
|
|
@@ -1597,7 +1682,7 @@ interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onCh
|
|
|
1597
1682
|
* destructive button itself), and disarming moves it back to the arm button, so the
|
|
1598
1683
|
* keyboard user is never left on an element that just vanished.
|
|
1599
1684
|
*/
|
|
1600
|
-
declare function DangerConfirm({ onConfirm, requirePassword, requireAcknowledge, consequences, phrase, phraseMatch, prompt, tone, armLabel, confirmLabel, busy: busyProp, disabled, lockedReason: ownLockedReason, commit, armed: armedProp, onArmedChange, labels: labelsProp, className, ...rest }: DangerConfirmProps): react.JSX.Element;
|
|
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;
|
|
1601
1686
|
|
|
1602
1687
|
/**
|
|
1603
1688
|
* A button that opens the file picker — the shape all three apps kept writing by hand
|
|
@@ -1827,6 +1912,732 @@ interface FileButtonProps extends Omit<UseFilePickerOptions, "disabled">, Omit<B
|
|
|
1827
1912
|
*/
|
|
1828
1913
|
declare const FileButton: react.ForwardRefExoticComponent<FileButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
1829
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
|
+
|
|
1830
2641
|
/**
|
|
1831
2642
|
* The conversation under a report: who said what, when, with what attached — and the
|
|
1832
2643
|
* box to answer in.
|
|
@@ -1976,11 +2787,45 @@ declare function FeedbackThread({ messages, loading, empty, renderAttachment, re
|
|
|
1976
2787
|
/** What the composer's attach control takes — {@link FeedbackNoteAttachment} with the
|
|
1977
2788
|
* labels optional, since the field reads `feedbackAttachment` from the provider, and
|
|
1978
2789
|
* `onError` the field's own (0.23.0): it is handed the refused file and the limit too
|
|
1979
|
-
* (`FeedbackAttachmentErrorInfo`), and a `(kind) => …` handler still fits.
|
|
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. */
|
|
1980
2793
|
type FeedbackComposerAttachment = Omit<FeedbackNoteAttachment, "labels" | "onError"> & {
|
|
1981
2794
|
labels?: Partial<FeedbackAttachmentLabels>;
|
|
1982
2795
|
onError?: FeedbackAttachmentFieldSingleProps["onError"];
|
|
1983
|
-
}
|
|
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
|
+
}
|
|
1984
2829
|
interface FeedbackComposerProps {
|
|
1985
2830
|
/**
|
|
1986
2831
|
* Send the comment. Return the promise: the box clears when it RESOLVES, and only of
|
|
@@ -2004,8 +2849,21 @@ interface FeedbackComposerProps {
|
|
|
2004
2849
|
* The slot is the host's picker plus the chips of what is uploaded; the upload, the
|
|
2005
2850
|
* refs and clearing them once `onSend` resolves stay with the host. Pair it with
|
|
2006
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.
|
|
2007
2865
|
*/
|
|
2008
|
-
attachmentSlot?: ReactNode;
|
|
2866
|
+
attachmentSlot?: ReactNode | ((slot: FeedbackComposerSlotContext) => ReactNode);
|
|
2009
2867
|
/**
|
|
2010
2868
|
* Whether Send is enabled, over the composer's own rule (some text in the box) —
|
|
2011
2869
|
* for state the composer cannot see, i.e. `attachmentSlot`'s (keksdose G5): `true`
|
|
@@ -2135,6 +2993,8 @@ type ChatComposerHandle = FeedbackComposerHandle;
|
|
|
2135
2993
|
/** {@link FeedbackComposerLabels}, for {@link ChatComposer} — still the `feedbackComposer`
|
|
2136
2994
|
* namespace of the provider. */
|
|
2137
2995
|
type ChatComposerLabels = FeedbackComposerLabels;
|
|
2996
|
+
/** {@link FeedbackComposerSlotContext}, for {@link ChatComposer}'s `attachmentSlot`. */
|
|
2997
|
+
type ChatComposerSlotContext = FeedbackComposerSlotContext;
|
|
2138
2998
|
|
|
2139
2999
|
/**
|
|
2140
3000
|
* The `confirmDialog` namespace of `<UiKitProvider labels>`: the two buttons' fallback
|
|
@@ -3361,4 +4221,4 @@ declare function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels;
|
|
|
3361
4221
|
*/
|
|
3362
4222
|
declare function missingKitLabels(labels: UiKitLabelOverrides | undefined, reference: UiKitLabels): string[];
|
|
3363
4223
|
|
|
3364
|
-
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 };
|