@eifi1/ui-kit 0.21.0 → 0.22.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/dist/chart.d.ts +10 -8
- package/dist/components/account-chips.d.ts +10 -3
- package/dist/components/account-chips.js +5 -2
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/account-settings.d.ts +33 -2
- package/dist/components/account-settings.js +43 -21
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +27 -8
- package/dist/components/amount-input.js +15 -28
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +8 -0
- package/dist/components/autocomplete.js +9 -4
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-group.d.ts +10 -8
- package/dist/components/calculator.d.ts +10 -8
- package/dist/components/checkbox-group.d.ts +104 -0
- package/dist/components/checkbox-group.js +111 -0
- package/dist/components/checkbox-group.js.map +1 -0
- package/dist/components/checkbox.d.ts +19 -0
- package/dist/components/checkbox.js +30 -7
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/chip.d.ts +18 -0
- package/dist/components/chip.js +47 -10
- package/dist/components/chip.js.map +1 -1
- package/dist/components/combobox.d.ts +13 -2
- package/dist/components/combobox.js +17 -8
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +66 -161
- package/dist/components/copy-button.d.ts +10 -8
- package/dist/components/country-select.d.ts +124 -0
- package/dist/components/country-select.js +237 -0
- package/dist/components/country-select.js.map +1 -0
- package/dist/components/currency-select.d.ts +17 -1
- package/dist/components/currency-select.js +56 -23
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +66 -166
- package/dist/components/danger-confirm.js +133 -49
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +1 -2
- package/dist/components/data-table-filter-popover.d.ts +1 -2
- package/dist/components/data-table-filters.d.ts +1 -2
- package/dist/components/data-table-labels.d.ts +4 -97
- package/dist/components/data-table-labels.js +9 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table-pagination.d.ts +3 -1
- package/dist/components/data-table.d.ts +1 -2
- package/dist/components/data-table.js +98 -3
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +25 -5
- package/dist/components/date-picker.js +110 -59
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +8 -1
- package/dist/components/entity-combobox.js +9 -4
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +10 -8
- package/dist/components/field-anatomy.d.ts +95 -0
- package/dist/components/field-anatomy.js +84 -0
- package/dist/components/field-anatomy.js.map +1 -0
- package/dist/components/field-parts.d.ts +114 -0
- package/dist/components/field-parts.js +72 -0
- package/dist/components/field-parts.js.map +1 -0
- package/dist/components/file-button.d.ts +10 -8
- package/dist/components/file-button.js +13 -3
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +32 -9
- package/dist/components/file-dropzone.js +57 -34
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/form-actions.d.ts +10 -8
- package/dist/components/form-actions.js +61 -3
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/iban-input.d.ts +66 -0
- package/dist/components/iban-input.js +125 -0
- package/dist/components/iban-input.js.map +1 -0
- package/dist/components/icon-picker.d.ts +12 -2
- package/dist/components/icon-picker.js +9 -2
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/inline-edit-field.d.ts +167 -0
- package/dist/components/inline-edit-field.js +293 -0
- package/dist/components/inline-edit-field.js.map +1 -0
- package/dist/components/language-select.d.ts +127 -0
- package/dist/components/language-select.js +18 -0
- package/dist/components/language-select.js.map +1 -0
- package/dist/components/line-items.d.ts +25 -3
- package/dist/components/line-items.js +55 -46
- package/dist/components/line-items.js.map +1 -1
- package/dist/components/list.d.ts +25 -0
- package/dist/components/list.js +16 -5
- package/dist/components/list.js.map +1 -1
- package/dist/components/money-field.d.ts +20 -8
- package/dist/components/money-field.js.map +1 -1
- package/dist/components/month-picker.d.ts +52 -4
- package/dist/components/month-picker.js +290 -86
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-select.d.ts +8 -1
- package/dist/components/multi-select.js +9 -4
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +25 -13
- package/dist/components/number-field.js +6 -20
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +70 -13
- package/dist/components/number-input.js +90 -38
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +10 -8
- package/dist/components/one-time-code-input.d.ts +100 -0
- package/dist/components/one-time-code-input.js +137 -0
- package/dist/components/one-time-code-input.js.map +1 -0
- package/dist/components/phone-input.d.ts +66 -0
- package/dist/components/phone-input.js +171 -0
- package/dist/components/phone-input.js.map +1 -0
- package/dist/components/series-chart.d.ts +10 -8
- package/dist/components/settings-fields.d.ts +10 -8
- package/dist/components/share-card.d.ts +8 -6
- package/dist/components/sign-chip.d.ts +66 -0
- package/dist/components/sign-chip.js +39 -0
- package/dist/components/sign-chip.js.map +1 -0
- package/dist/components/swatch-picker.d.ts +27 -2
- package/dist/components/swatch-picker.js +73 -31
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/switch.d.ts +19 -0
- package/dist/components/switch.js +24 -6
- package/dist/components/switch.js.map +1 -1
- package/dist/components/text-link.d.ts +10 -8
- package/dist/components/tile-radio.d.ts +68 -13
- package/dist/components/tile-radio.js +3 -3
- package/dist/components/tile-radio.js.map +1 -1
- package/dist/components/time-input.d.ts +15 -9
- package/dist/components/time-input.js.map +1 -1
- package/dist/components/toggle-group.d.ts +47 -1
- package/dist/components/toggle-group.js +110 -69
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/ui.d.ts +10 -8
- package/dist/components/ui.js +280 -78
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -2
- package/dist/{data-table-3mi2R3so.d.ts → data-table-labels-B7OdnM0S.d.ts} +140 -3
- package/dist/data-table.d.ts +1 -2
- package/dist/data-table.js +2 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +1 -1
- package/dist/feedback/feedback-attachment.js +210 -3
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +1 -1
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +1 -1
- package/dist/feedback/feedback-thread.d.ts +37 -3
- package/dist/feedback/feedback-thread.js +38 -9
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/{feedback-attachment-WFiXJ8We.d.ts → feedback-attachment-NhUm7Zga.d.ts} +70 -5
- package/dist/feedback.d.ts +2 -2
- package/dist/hooks/use-file-drop.d.ts +10 -8
- package/dist/i18n/defaults.d.ts +10 -8
- package/dist/i18n/defaults.js +17 -2
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +10 -8
- package/dist/i18n/german.js +50 -5
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +10 -8
- package/dist/i18n/kit-labels.js +8 -2
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +10 -8
- package/dist/i18n/locales/de-CH.d.ts +10 -8
- package/dist/i18n/locales/en.d.ts +10 -8
- package/dist/i18n/locales/en.js +9 -0
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +10 -8
- package/dist/i18n/locales/es.js +48 -5
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +10 -8
- package/dist/i18n/locales/fr.js +48 -5
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +10 -8
- package/dist/i18n/locales/hu.js +49 -5
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +10 -8
- package/dist/i18n/locales/it.js +49 -5
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +10 -8
- package/dist/i18n/locales/zh.js +48 -5
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.d.ts +10 -8
- package/dist/i18n/review.js +8 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +17 -10
- package/dist/index.js +57 -2
- package/dist/index.js.map +1 -1
- package/dist/{kit-labels-D1J2_jyD.d.ts → kit-labels-R8mIAc9N.d.ts} +811 -8
- package/dist/lib/countries.d.ts +43 -0
- package/dist/lib/countries.js +39 -0
- package/dist/lib/countries.js.map +1 -0
- package/dist/lib/decimal-marks.d.ts +46 -0
- package/dist/lib/decimal-marks.js +40 -0
- package/dist/lib/decimal-marks.js.map +1 -0
- package/dist/lib/iban.d.ts +98 -0
- package/dist/lib/iban.js +154 -0
- package/dist/lib/iban.js.map +1 -0
- package/dist/lib/isin.d.ts +30 -0
- package/dist/lib/isin.js +36 -0
- package/dist/lib/isin.js.map +1 -0
- package/dist/lib/phone.d.ts +69 -0
- package/dist/lib/phone.js +121 -0
- package/dist/lib/phone.js.map +1 -0
- package/dist/rhf/fields.d.ts +148 -11
- package/dist/rhf/fields.js +332 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/rhf/form.d.ts +10 -8
- package/dist/rhf.d.ts +13 -9
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +10 -8
- package/dist/shell/top-bar-brand.d.ts +10 -8
- package/dist/shell.d.ts +10 -8
- package/dist/tour/tour.js +20 -24
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +10 -8
- package/dist/wizard.d.ts +10 -8
- package/package.json +1 -1
- package/src/components/account-chips.tsx +17 -3
- package/src/components/account-settings.tsx +92 -26
- package/src/components/amount-input.tsx +49 -56
- package/src/components/autocomplete.tsx +133 -110
- package/src/components/checkbox-group.tsx +229 -0
- package/src/components/checkbox.tsx +72 -8
- package/src/components/chip.tsx +80 -10
- package/src/components/combobox.tsx +292 -253
- package/src/components/country-select.tsx +443 -0
- package/src/components/currency-select.tsx +109 -33
- package/src/components/danger-confirm.tsx +345 -77
- package/src/components/data-table-labels.ts +16 -1
- package/src/components/data-table.tsx +175 -6
- package/src/components/date-picker.tsx +173 -62
- package/src/components/entity-combobox.tsx +107 -87
- package/src/components/field-anatomy.tsx +190 -0
- package/src/components/field-parts.tsx +184 -0
- package/src/components/file-button.tsx +36 -3
- package/src/components/file-dropzone.tsx +106 -38
- package/src/components/form-actions.tsx +115 -2
- package/src/components/iban-input.tsx +231 -0
- package/src/components/icon-picker.tsx +26 -4
- package/src/components/inline-edit-field.tsx +533 -0
- package/src/components/language-select.tsx +78 -0
- package/src/components/line-items.tsx +35 -2
- package/src/components/list.tsx +55 -6
- package/src/components/money-field.tsx +10 -0
- package/src/components/month-picker.tsx +399 -63
- package/src/components/multi-select.tsx +80 -58
- package/src/components/number-field.tsx +28 -46
- package/src/components/number-input.tsx +210 -43
- package/src/components/one-time-code-input.tsx +288 -0
- package/src/components/phone-input.tsx +299 -0
- package/src/components/sign-chip.tsx +103 -0
- package/src/components/swatch-picker.tsx +118 -30
- package/src/components/switch.tsx +58 -7
- package/src/components/tile-radio.tsx +71 -16
- package/src/components/time-input.tsx +8 -1
- package/src/components/toggle-group.tsx +206 -73
- package/src/components/ui.tsx +472 -105
- package/src/data-table.ts +2 -1
- package/src/feedback/feedback-attachment.tsx +313 -9
- package/src/feedback/feedback-dialog.tsx +2 -0
- package/src/feedback/feedback-thread.tsx +66 -5
- package/src/i18n/defaults.ts +16 -1
- package/src/i18n/german.ts +47 -0
- package/src/i18n/kit-labels.tsx +78 -2
- package/src/i18n/locales/en.ts +10 -0
- package/src/i18n/locales/es.ts +46 -0
- package/src/i18n/locales/fr.ts +45 -0
- package/src/i18n/locales/hu.ts +46 -0
- package/src/i18n/locales/it.ts +47 -0
- package/src/i18n/locales/zh.ts +44 -0
- package/src/i18n/review.ts +7 -0
- package/src/index.ts +53 -3
- package/src/lib/countries.ts +91 -0
- package/src/lib/decimal-marks.ts +99 -0
- package/src/lib/iban.ts +171 -0
- package/src/lib/isin.ts +62 -0
- package/src/lib/phone.ts +211 -0
- package/src/rhf/fields.tsx +606 -9
- package/src/rhf.ts +2 -1
- package/src/tour/tour.tsx +66 -28
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { AnchorHTMLAttributes, Ref, ReactElement, ButtonHTMLAttributes,
|
|
3
|
-
import { DataTableLabels } from './
|
|
2
|
+
import { InputHTMLAttributes, ReactNode, AnchorHTMLAttributes, Ref, ReactElement, ButtonHTMLAttributes, SelectHTMLAttributes, ComponentPropsWithoutRef, TextareaHTMLAttributes } from 'react';
|
|
3
|
+
import { f as DataTableLabels } from './data-table-labels-B7OdnM0S.js';
|
|
4
4
|
import { MiniCalendarLabels, WeekDay } from './components/mini-calendar.js';
|
|
5
5
|
import { CalendarHeatmapLabels } from './components/calendar-heatmap.js';
|
|
6
6
|
import { PopoverLabels } from './components/popover.js';
|
|
@@ -19,15 +19,13 @@ import { SparklineLabels } from './components/sparkline.js';
|
|
|
19
19
|
import { StatTileLabels } from './components/stat-tile.js';
|
|
20
20
|
import { SignaturePadLabels } from './components/signature-pad.js';
|
|
21
21
|
import { PasswordStrengthLabels } from './components/password-strength.js';
|
|
22
|
-
import { DangerConfirmLabels } from './components/danger-confirm.js';
|
|
23
22
|
import { SwatchPickerLabels } from './components/swatch-picker.js';
|
|
24
23
|
import { IconPickerLabels } from './components/icon-picker.js';
|
|
25
24
|
import { DialogFrameProps, DialogFrameLabels } from './components/dialog-frame.js';
|
|
26
25
|
import { MeasuredGridLabels } from './components/measured-grid.js';
|
|
27
|
-
import { f as FeedbackAttachmentFieldLabels,
|
|
26
|
+
import { f as FeedbackAttachmentFieldLabels, t as FeedbackDialogTextLabels } from './feedback-attachment-NhUm7Zga.js';
|
|
28
27
|
import { FeedbackThreadLabels, FeedbackComposerLabels } from './feedback/feedback-thread.js';
|
|
29
28
|
import { AccountSettingsLabels } from './components/account-settings-labels.js';
|
|
30
|
-
import { ConfirmDialogLabels } from './components/confirm-dialog.js';
|
|
31
29
|
import { FloatingPanelLabels } from './components/floating-panel.js';
|
|
32
30
|
import { BulkActionBarLabels } from './components/bulk-action-bar.js';
|
|
33
31
|
import { ListLabels } from './components/list.js';
|
|
@@ -48,6 +46,11 @@ import { RoleDefinition, AccountStateLabels } from './components/account-chips.j
|
|
|
48
46
|
import { ReauthDialogLabels } from './components/reauth-dialog.js';
|
|
49
47
|
import { ServerWakeLabels } from './components/server-wake.js';
|
|
50
48
|
import { TranslationReviewLabels } from './components/translation-review-labels.js';
|
|
49
|
+
import { CountrySelectLabels } from './components/country-select.js';
|
|
50
|
+
import { InlineEditLabels } from './components/inline-edit-field.js';
|
|
51
|
+
import { IbanKind } from './lib/iban.js';
|
|
52
|
+
import { PhoneCountry, PhoneCountryCode } from './lib/phone.js';
|
|
53
|
+
import { SignChipLabels } from './components/sign-chip.js';
|
|
51
54
|
|
|
52
55
|
type ButtonVariant = "primary" | "secondary" | "ghost" | "danger" | "brand" | "link";
|
|
53
56
|
type ButtonSize = "sm" | "md";
|
|
@@ -669,6 +672,22 @@ declare const DEFAULT_PASSWORD_REVEAL_LABELS: PasswordRevealLabels;
|
|
|
669
672
|
/** Caller's labels over the English defaults — the same shape as
|
|
670
673
|
* `resolveDataTableLabels`, so a consumer translates every kit string one way. */
|
|
671
674
|
declare function resolvePasswordRevealLabels(partial?: Partial<PasswordRevealLabels>): PasswordRevealLabels;
|
|
675
|
+
/**
|
|
676
|
+
* What the character counter of {@link Input} and {@link Textarea} (`showCount`) says.
|
|
677
|
+
* The visible "12/80" is digits and a slash and is not translated; these are the words
|
|
678
|
+
* a screen reader gets instead of it.
|
|
679
|
+
*/
|
|
680
|
+
interface CharacterCountLabels {
|
|
681
|
+
/** The counter as part of the field's description, read when focus reaches the
|
|
682
|
+
* field: "12 of 80 characters". */
|
|
683
|
+
count: (used: number, max: number) => string;
|
|
684
|
+
/** Said once, politely, on entering the last stretch before the limit: "8
|
|
685
|
+
* characters left". */
|
|
686
|
+
remaining: (left: number) => string;
|
|
687
|
+
/** Said once, politely, on reaching the limit. */
|
|
688
|
+
limitReached: string;
|
|
689
|
+
}
|
|
690
|
+
declare const DEFAULT_CHARACTER_COUNT_LABELS: CharacterCountLabels;
|
|
672
691
|
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
673
692
|
label?: ReactNode;
|
|
674
693
|
/** Classes for the `<input>` itself, as distinct from `className`, which
|
|
@@ -699,6 +718,30 @@ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
|
699
718
|
* `invalid`, so the field paints as well as announces. `invalid` alone still
|
|
700
719
|
* covers the case where the message lives elsewhere. See {@link useFieldError}. */
|
|
701
720
|
error?: ReactNode;
|
|
721
|
+
/**
|
|
722
|
+
* Standing advice for the field (keksdose K4: Input had `error` but no `hint`, so the
|
|
723
|
+
* app built the caption by hand under each field, and half of those never reached a
|
|
724
|
+
* screen reader). The {@link Select} rule, so every field reads alike:
|
|
725
|
+
* - plain TEXT (a string or a number) is a caption UNDER the field, attached with
|
|
726
|
+
* `aria-describedby` — after the caller's own ids, before the error's;
|
|
727
|
+
* - anything else (a {@link FieldHint} "?") rides the label line beside the
|
|
728
|
+
* animated label, as NumberInput's does — or, on a field with no label, sits at the
|
|
729
|
+
* field's end edge outside the box, and `className` then styles that row.
|
|
730
|
+
*/
|
|
731
|
+
hint?: ReactNode;
|
|
732
|
+
/**
|
|
733
|
+
* A live "12/80" under the field, with `maxLength` (keksdose K11 — the broadcast,
|
|
734
|
+
* support and handoff-note fields counted by hand). Read with the field as "12 of 80
|
|
735
|
+
* characters", and announced politely only on entering the last stretch and on
|
|
736
|
+
* reaching the limit — never on every keystroke. See {@link CharacterCount}. Ignored
|
|
737
|
+
* without a `maxLength`: a count with no limit is not what this answers. Counts
|
|
738
|
+
* UTF-16 code units, as `maxLength` itself does. Controlled, it counts `value`;
|
|
739
|
+
* uncontrolled, `defaultValue` and then every change event — a value written from
|
|
740
|
+
* outside without one (a form library's `reset`) shows from the next keystroke.
|
|
741
|
+
*/
|
|
742
|
+
showCount?: boolean;
|
|
743
|
+
/** The counter's words. See {@link CharacterCountLabels}. */
|
|
744
|
+
countLabels?: Partial<CharacterCountLabels>;
|
|
702
745
|
/** Names for the password reveal toggle, English by default — it is the one
|
|
703
746
|
* string this component renders on its own behalf, and a German form was
|
|
704
747
|
* reading it out in English. See {@link PasswordRevealLabels}. */
|
|
@@ -735,6 +778,29 @@ interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "siz
|
|
|
735
778
|
* the chevron is positioned against — so it could set a width and nothing
|
|
736
779
|
* else; this is the way to the element. See {@link Input}'s `inputClassName`. */
|
|
737
780
|
selectClassName?: string;
|
|
781
|
+
/**
|
|
782
|
+
* Why the choice cannot be changed — {@link Button}'s `disabledReason`, for a select
|
|
783
|
+
* that SAVES on change (a role picker in a members table, a status in a row). keksdose
|
|
784
|
+
* K3: those sat inside a hand-rolled `SaveGuard` that forced a native `disabled`, which
|
|
785
|
+
* took the field out of the tab order so the reason never reached a keyboard.
|
|
786
|
+
*
|
|
787
|
+
* With a reason the select is `aria-disabled` instead — still focusable, still showing
|
|
788
|
+
* its value — its list does not open (pointer and keys are swallowed, Tab and Escape
|
|
789
|
+
* excepted), `onChange` is never called, and the reason is in the kit {@link Tooltip}
|
|
790
|
+
* and on `aria-describedby`. It wears the settled look of a disabled field and drops
|
|
791
|
+
* its chevron, as a disabled Select does (dev#474). It wins over `disabled`.
|
|
792
|
+
*
|
|
793
|
+
* Use it CONTROLLED (`value` + `onChange`): React puts a controlled value back after
|
|
794
|
+
* the swallowed change. A touch platform's own picker may still open; nothing it picks
|
|
795
|
+
* is kept or reported.
|
|
796
|
+
*/
|
|
797
|
+
disabledReason?: ReactNode;
|
|
798
|
+
/**
|
|
799
|
+
* This select COMMITS — choosing saves. Under a locked {@link WriteLockProvider} it is
|
|
800
|
+
* locked the `disabledReason` way with the lock's reason (which wins over its own).
|
|
801
|
+
* No provider, or an unlocked one: no effect. Button's `commit`, for keksdose K3.
|
|
802
|
+
*/
|
|
803
|
+
commit?: boolean;
|
|
738
804
|
}
|
|
739
805
|
declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLSelectElement>>;
|
|
740
806
|
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
@@ -743,6 +809,14 @@ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
|
743
809
|
invalid?: boolean;
|
|
744
810
|
/** See {@link Input}'s `error`. */
|
|
745
811
|
error?: ReactNode;
|
|
812
|
+
/** See {@link Input}'s `hint` (keksdose K4): text is a caption under the field, a
|
|
813
|
+
* {@link FieldHint} rides the label line (or, unlabelled, the end edge). */
|
|
814
|
+
hint?: ReactNode;
|
|
815
|
+
/** See {@link Input}'s `showCount` (keksdose K11): a live "12/80" under the field,
|
|
816
|
+
* with `maxLength`, announced only near and at the limit. */
|
|
817
|
+
showCount?: boolean;
|
|
818
|
+
/** The counter's words. See {@link CharacterCountLabels}. */
|
|
819
|
+
countLabels?: Partial<CharacterCountLabels>;
|
|
746
820
|
}
|
|
747
821
|
declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
|
|
748
822
|
interface CardProps extends ComponentPropsWithoutRef<"div"> {
|
|
@@ -1164,6 +1238,317 @@ interface TabsProps<T extends string> extends Omit<ComponentPropsWithoutRef<"div
|
|
|
1164
1238
|
}
|
|
1165
1239
|
declare function Tabs<T extends string>({ tabs, active, onChange, className, wrap, label, panelId, onRemove, removeOn, onAdd, addLabel, labels, busy, orientation, "aria-label": ariaLabel, ...rest }: TabsProps<T>): react.JSX.Element;
|
|
1166
1240
|
|
|
1241
|
+
/**
|
|
1242
|
+
* How typed text is compared with the text it has to repeat — shared by
|
|
1243
|
+
* `DangerConfirm`'s `phraseMatch` and `useConfirm`'s `typedMatch`.
|
|
1244
|
+
*
|
|
1245
|
+
* - `"trim"` ignores spaces around the typed text — a phone keyboard's autocomplete
|
|
1246
|
+
* likes to add one. Case counts: "delete" is not "DELETE".
|
|
1247
|
+
* - `"exact"` compares character for character, spaces included.
|
|
1248
|
+
* - `"caseless"` trims AND ignores case: for an e-mail address, whose domain is
|
|
1249
|
+
* case-insensitive and whose local part every real mail server treats so. Both apps'
|
|
1250
|
+
* "type the account's address" rules (keksdose's `TYPE_EMAIL`, Kurvenschmiede's
|
|
1251
|
+
* `TypedConfirm`) compared `trim().toLowerCase()`, and a capital the user's keyboard
|
|
1252
|
+
* put at the start must not make the right row look like the wrong one.
|
|
1253
|
+
*/
|
|
1254
|
+
type TypedMatch = "trim" | "exact" | "caseless";
|
|
1255
|
+
/** Whether `typed` repeats `target` under `mode` — see {@link TypedMatch}. Exported for
|
|
1256
|
+
* a caller that draws its own field (a dialog that also picks a recipient) and wants
|
|
1257
|
+
* the same rule as the kit's. */
|
|
1258
|
+
declare function typedMatches(typed: string, target: string, mode?: TypedMatch): boolean;
|
|
1259
|
+
/**
|
|
1260
|
+
* Busy-while-a-promise-runs, for an action that MAY return one: `run(result, onResolved)`
|
|
1261
|
+
* marks the caller pending until `result` settles, calls `onResolved` if it fulfilled,
|
|
1262
|
+
* and only clears the flag if it rejected — the caller shows why and the user retries.
|
|
1263
|
+
* Nothing runs after unmount. Shared by `DangerConfirm` and `ReauthDialog`, whose
|
|
1264
|
+
* contract is the same: resolve = done, reject = stay put.
|
|
1265
|
+
*
|
|
1266
|
+
* @internal
|
|
1267
|
+
*/
|
|
1268
|
+
declare function usePromisePending(): {
|
|
1269
|
+
pending: boolean;
|
|
1270
|
+
run: (result: unknown, onResolved: () => void) => boolean;
|
|
1271
|
+
};
|
|
1272
|
+
/** The one word {@link CurrentPasswordInput} says on its own behalf — the
|
|
1273
|
+
* `dangerConfirm.password` label, shared with DangerConfirm's password field, so an
|
|
1274
|
+
* app translates "Password" once. */
|
|
1275
|
+
type CurrentPasswordInputLabels = Pick<DangerConfirmLabels, "password">;
|
|
1276
|
+
/**
|
|
1277
|
+
* Everything {@link Input} takes except what makes this field what it is: `type` is
|
|
1278
|
+
* always `"password"` and `autoComplete` always `"current-password"`.
|
|
1279
|
+
*/
|
|
1280
|
+
interface CurrentPasswordInputProps extends Omit<InputProps, "type" | "autoComplete" | "label"> {
|
|
1281
|
+
/**
|
|
1282
|
+
* The visible label. Default `dangerConfirm.password` ("Password") — unless the field
|
|
1283
|
+
* is named another way (`aria-label` / `aria-labelledby`), which then stays the only
|
|
1284
|
+
* name. Pass the app's own word on a sign-in form ("Password", "Your password"), or
|
|
1285
|
+
* `null` for a field whose `<label htmlFor>` is drawn elsewhere (a form library's
|
|
1286
|
+
* `FormLabel`), which would otherwise be labelled twice.
|
|
1287
|
+
*/
|
|
1288
|
+
label?: ReactNode;
|
|
1289
|
+
/** The value as a string — the `(next) => …` shape, so a caller holding it in
|
|
1290
|
+
* `useState` need not unwrap `event.target.value`. Fires alongside `onChange`,
|
|
1291
|
+
* never instead of it, so a form library's `onChange` keeps working. */
|
|
1292
|
+
onValueChange?: (value: string) => void;
|
|
1293
|
+
/**
|
|
1294
|
+
* A check is running (the sign-in request, the re-auth). The field turns `readOnly`,
|
|
1295
|
+
* NOT `disabled`: the field being submitted is usually the focused one (Enter was
|
|
1296
|
+
* pressed in it), and disabling a focused field drops focus to `<body>` — the user
|
|
1297
|
+
* lands nowhere when the "wrong password" answer comes back.
|
|
1298
|
+
*/
|
|
1299
|
+
busy?: boolean;
|
|
1300
|
+
/** Per-instance override of `dangerConfirm.password`. */
|
|
1301
|
+
labels?: Partial<CurrentPasswordInputLabels>;
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* The "prove it is you" field: a password input that a password manager fills with
|
|
1305
|
+
* the CURRENT password and never offers to generate a new one for.
|
|
1306
|
+
*
|
|
1307
|
+
* It is the field of a sign-in form, a re-auth step ({@link ReauthDialog} draws the same
|
|
1308
|
+
* field), and {@link DangerConfirm}'s `requirePassword`. Public since 0.22 for kastlan's
|
|
1309
|
+
* sign-in and re-auth (kastlan 1), which wrote `type="password"` +
|
|
1310
|
+
* `autoComplete="current-password"` by hand — and a sign-in field that forgets the
|
|
1311
|
+
* second half gets the browser's "suggest a strong password" offer on the one form where
|
|
1312
|
+
* a NEW password is never what is wanted. The reverse matters as much: a field that sets
|
|
1313
|
+
* a NEW password (a passphrase, a sign-up) must NOT be this one — keksdose #170 keeps
|
|
1314
|
+
* its passphrase doors on `new-password` / `off` for that reason.
|
|
1315
|
+
*
|
|
1316
|
+
* Everything else is {@link Input}: the reveal toggle, `error` (under the field,
|
|
1317
|
+
* `aria-describedby`, `aria-invalid`), `invalid`, `name`, `id`, `autoFocus`, `required`.
|
|
1318
|
+
* The ref is the `<input>`, so it works with `@eifi1/ui-kit/rhf`'s `FormControl` /
|
|
1319
|
+
* a `register()` spread, and controlled or uncontrolled.
|
|
1320
|
+
*
|
|
1321
|
+
* ```tsx
|
|
1322
|
+
* <CurrentPasswordInput name="password" label={t("password")} error={errors.password?.message}
|
|
1323
|
+
* busy={isSubmitting} {...register("password")} />
|
|
1324
|
+
* ```
|
|
1325
|
+
*/
|
|
1326
|
+
declare const CurrentPasswordInput: react.ForwardRefExoticComponent<CurrentPasswordInputProps & react.RefAttributes<HTMLInputElement>>;
|
|
1327
|
+
/** The words {@link TypedConfirmField} says on its own behalf — the `dangerConfirm`
|
|
1328
|
+
* namespace's `phrase` and `phrasePlaceholder`, shared with DangerConfirm's own field,
|
|
1329
|
+
* so the sentence "Type “X” to confirm" is translated once. */
|
|
1330
|
+
type TypedConfirmFieldLabels = Pick<DangerConfirmLabels, "phrase" | "phrasePlaceholder">;
|
|
1331
|
+
interface TypedConfirmFieldProps extends Omit<InputProps, "type" | "value" | "defaultValue" | "label" | "placeholder"> {
|
|
1332
|
+
/** The text to repeat — a word ("DELETE"), a name, an e-mail address. */
|
|
1333
|
+
target: string;
|
|
1334
|
+
/** How the typed text is compared with `target` — {@link TypedMatch}. Default
|
|
1335
|
+
* `"trim"`, as {@link typedMatches}; `"caseless"` for an address or an
|
|
1336
|
+
* acknowledgement word a user may type in any case. */
|
|
1337
|
+
match?: TypedMatch;
|
|
1338
|
+
/** Controlled value. Left out, the field keeps its own (start: `defaultValue`). */
|
|
1339
|
+
value?: string;
|
|
1340
|
+
defaultValue?: string;
|
|
1341
|
+
/** The typed text as a string, on every keystroke. Fires alongside `onChange`. */
|
|
1342
|
+
onValueChange?: (value: string) => void;
|
|
1343
|
+
/**
|
|
1344
|
+
* The typed text started or stopped matching `target` — fired from the keystroke
|
|
1345
|
+
* that flipped it, so an uncontrolled field can still drive the button it guards. A
|
|
1346
|
+
* controlled caller that resets the value itself (on a close) knows the answer
|
|
1347
|
+
* already, and gets no call for that; it can also compute it with {@link typedMatches}.
|
|
1348
|
+
*/
|
|
1349
|
+
onMatchedChange?: (matched: boolean) => void;
|
|
1350
|
+
/** The label. Default `dangerConfirm.phrase(target)` — "Type “DELETE” to confirm". */
|
|
1351
|
+
label?: ReactNode;
|
|
1352
|
+
/** Text inside the empty field. Default `dangerConfirm.phrasePlaceholder` (unset).
|
|
1353
|
+
* Given, the label moves ABOVE the field: a floating label occupies the empty
|
|
1354
|
+
* field, which is exactly where a placeholder shows. `""` means none. */
|
|
1355
|
+
placeholder?: string;
|
|
1356
|
+
/** The guarded action is running: the field turns `readOnly` (not `disabled`, which
|
|
1357
|
+
* would drop the focus Enter left in it). */
|
|
1358
|
+
busy?: boolean;
|
|
1359
|
+
labels?: Partial<TypedConfirmFieldLabels>;
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* The "type this to confirm" field — {@link DangerConfirm}'s `phrase` field and
|
|
1363
|
+
* `useConfirm({ requireTyped })`'s, on its own (keksdose K7).
|
|
1364
|
+
*
|
|
1365
|
+
* keksdose writes it by hand four times: the privacy enrol, upgrade and sweep dialogs
|
|
1366
|
+
* (type the acknowledgement word, then the key doors appear) and the admin's "type the
|
|
1367
|
+
* user's address" (`UserActionConfirm`), each an `Input` plus its own
|
|
1368
|
+
* `trim().toUpperCase()` / `toLowerCase()` comparison. None of those places is an
|
|
1369
|
+
* arm → confirm tile or a modal confirm — what is guarded is a whole form, or the
|
|
1370
|
+
* next step of a dialog — so the field had to stand alone. What it brings over a plain
|
|
1371
|
+
* `Input`: one match rule ({@link typedMatches}, which lower-cases locale-independently
|
|
1372
|
+
* on purpose), the label worded from the target in the app's language, and the
|
|
1373
|
+
* attributes a phone keyboard needs to leave the text alone (no autocomplete, no
|
|
1374
|
+
* auto-capital, no autocorrect, no spellcheck — a keyboard that "corrects" an e-mail
|
|
1375
|
+
* address makes the guard unpassable).
|
|
1376
|
+
*
|
|
1377
|
+
* The field reports whether it matches (`onMatchedChange`, and `data-matched` on the
|
|
1378
|
+
* `<input>` for styling); what the match unlocks is the caller's. The ref is the
|
|
1379
|
+
* `<input>`.
|
|
1380
|
+
*
|
|
1381
|
+
* ```tsx
|
|
1382
|
+
* const [ok, setOk] = useState(false);
|
|
1383
|
+
* <TypedConfirmField target={t("privacy.enroll_ack_word")} match="caseless" onMatchedChange={setOk} />
|
|
1384
|
+
* {ok && <KeyDoorsForm … />}
|
|
1385
|
+
* ```
|
|
1386
|
+
*/
|
|
1387
|
+
declare const TypedConfirmField: react.ForwardRefExoticComponent<TypedConfirmFieldProps & react.RefAttributes<HTMLInputElement>>;
|
|
1388
|
+
/**
|
|
1389
|
+
* Every string the tile renders — the `dangerConfirm` namespace of
|
|
1390
|
+
* `<UiKitProvider labels>`, overridable per instance through `labels`. The arm and
|
|
1391
|
+
* confirm buttons are usually worded per action ("Delete budget"), which is what the
|
|
1392
|
+
* `armLabel` / `confirmLabel` props are for; these are the fallbacks.
|
|
1393
|
+
*/
|
|
1394
|
+
interface DangerConfirmLabels {
|
|
1395
|
+
/** The button that arms the tile. */
|
|
1396
|
+
arm: string;
|
|
1397
|
+
/** The button that runs the action once the guards are satisfied. */
|
|
1398
|
+
confirm: string;
|
|
1399
|
+
cancel: string;
|
|
1400
|
+
/** The warning above the fields, when no `prompt` is given. */
|
|
1401
|
+
prompt: string;
|
|
1402
|
+
/** Label of the password field (`requirePassword`). */
|
|
1403
|
+
password: string;
|
|
1404
|
+
/** Label of the type-to-confirm field. A FUNCTION of the phrase by default, like
|
|
1405
|
+
* every message that carries a value: where the phrase sits in the sentence moves
|
|
1406
|
+
* with the language. A plain STRING is taken as the finished label — for an app
|
|
1407
|
+
* whose catalogue already words it ("Type DELETE to confirm") and would otherwise
|
|
1408
|
+
* wrap it as `() => label`. */
|
|
1409
|
+
phrase: string | ((phrase: string) => string);
|
|
1410
|
+
/** Placeholder of the type-to-confirm field — a string, or a function of the
|
|
1411
|
+
* phrase (`(p) => p` echoes it). Optional and unset by default: the field keeps its
|
|
1412
|
+
* floating label, as before. Given, the label moves ABOVE the field (a floating
|
|
1413
|
+
* label occupies the empty field, which is exactly where a placeholder shows) and
|
|
1414
|
+
* the placeholder fills the field. An empty string means none. */
|
|
1415
|
+
phrasePlaceholder?: string | ((phrase: string) => string);
|
|
1416
|
+
/** 0.22: the checkbox `requireAcknowledge={true}` shows — "I have read what this does
|
|
1417
|
+
* and want to continue" (keksdose's `admin.users.confirm_ack`). */
|
|
1418
|
+
acknowledge: string;
|
|
1419
|
+
}
|
|
1420
|
+
/** `satisfies` rather than a type annotation, so `DEFAULT_DANGER_CONFIRM_LABELS.phrase`
|
|
1421
|
+
* stays callable for a caller that composes its own label from it. */
|
|
1422
|
+
declare const DEFAULT_DANGER_CONFIRM_LABELS: {
|
|
1423
|
+
arm: string;
|
|
1424
|
+
confirm: string;
|
|
1425
|
+
cancel: string;
|
|
1426
|
+
prompt: string;
|
|
1427
|
+
password: string;
|
|
1428
|
+
phrase: (phrase: string) => string;
|
|
1429
|
+
acknowledge: string;
|
|
1430
|
+
};
|
|
1431
|
+
/**
|
|
1432
|
+
* One line of {@link DangerConfirmProps.consequences}: what the action will do. A plain
|
|
1433
|
+
* string, or this, for a key of its own and the `severe` mark.
|
|
1434
|
+
*/
|
|
1435
|
+
interface DangerConsequence {
|
|
1436
|
+
/** React key — keksdose keys its lines by what they say ("api_tokens", "only_door").
|
|
1437
|
+
* Default: the text when it is a string, else the position. */
|
|
1438
|
+
key?: string;
|
|
1439
|
+
text: ReactNode;
|
|
1440
|
+
/** "There is no way back" — painted in the danger colour rather than the list's
|
|
1441
|
+
* muted one. keksdose reserves it for the one line that loses something for good. */
|
|
1442
|
+
severe?: boolean;
|
|
1443
|
+
}
|
|
1444
|
+
interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onChange"> {
|
|
1445
|
+
/**
|
|
1446
|
+
* Runs the action, with the entered password when `requirePassword` is on.
|
|
1447
|
+
*
|
|
1448
|
+
* Return a promise and the tile manages itself: busy until it settles, disarmed
|
|
1449
|
+
* (fields wiped) when it resolves, still armed when it rejects — so the user can
|
|
1450
|
+
* correct a wrong password and retry. The rejection is not swallowed for you to
|
|
1451
|
+
* miss: handle it (and show why) in the caller, as with any mutation.
|
|
1452
|
+
*/
|
|
1453
|
+
onConfirm: (password?: string) => void | Promise<unknown>;
|
|
1454
|
+
/** Show a password field; confirm stays disabled until it is filled. */
|
|
1455
|
+
requirePassword?: boolean;
|
|
1456
|
+
/**
|
|
1457
|
+
* Show an "I understand" checkbox; confirm stays disabled until it is ticked
|
|
1458
|
+
* (keksdose K7). `true` words it with `labels.acknowledge`; any other node IS the
|
|
1459
|
+
* checkbox's label ("I understand Anna will be signed out everywhere").
|
|
1460
|
+
*
|
|
1461
|
+
* The guard for an action whose risk is MIS-TARGETING less than carelessness:
|
|
1462
|
+
* keksdose's admin password reset asks for a typed address when the account has an
|
|
1463
|
+
* encrypted door to lose, and a tick otherwise (`UserActionConfirm`), and its plan
|
|
1464
|
+
* editor asks for the tick alone (`UserPlanEditor`). Both were hand-built beside this
|
|
1465
|
+
* tile because it had no tick. It combines with `phrase` and `requirePassword`: every
|
|
1466
|
+
* guard given must be satisfied.
|
|
1467
|
+
*/
|
|
1468
|
+
requireAcknowledge?: ReactNode;
|
|
1469
|
+
/**
|
|
1470
|
+
* What the action will do, said before it happens — a list under the prompt, shown
|
|
1471
|
+
* once armed (keksdose K7, `UserActionConfirm`'s consequences). Strings, or
|
|
1472
|
+
* {@link DangerConsequence}s for a `severe` line in the danger colour.
|
|
1473
|
+
*
|
|
1474
|
+
* Derive them from the row's own facts rather than reciting the worst case: an admin
|
|
1475
|
+
* who reads the same paragraph on every row stops reading it (keksdose dev#488).
|
|
1476
|
+
*/
|
|
1477
|
+
consequences?: readonly (string | DangerConsequence)[];
|
|
1478
|
+
/** Show a "type <phrase> to confirm" field; confirm stays disabled until the field
|
|
1479
|
+
* matches (case-sensitive; surrounding spaces ignored unless `phraseMatch="exact"`). */
|
|
1480
|
+
phrase?: string;
|
|
1481
|
+
/**
|
|
1482
|
+
* How the typed text is compared with `phrase`. `"trim"` (default) ignores spaces
|
|
1483
|
+
* around it — a phone keyboard's autocomplete likes to add one. `"exact"` compares
|
|
1484
|
+
* character for character, spaces included, for an app whose contract is "type
|
|
1485
|
+
* exactly this". `"caseless"` (0.18) also ignores case — for a phrase that is an
|
|
1486
|
+
* e-mail address (keksdose's "type the user's address" admin rule). See
|
|
1487
|
+
* {@link TypedMatch}.
|
|
1488
|
+
*/
|
|
1489
|
+
phraseMatch?: TypedMatch;
|
|
1490
|
+
/** The warning above the fields. Defaults to `labels.prompt`. */
|
|
1491
|
+
prompt?: ReactNode;
|
|
1492
|
+
/** `"danger"` (default) for what cannot be undone; `"warning"` for what can, at a
|
|
1493
|
+
* cost (loading demo data over your own). Colours the prompt and the confirm. */
|
|
1494
|
+
tone?: "danger" | "warning";
|
|
1495
|
+
/** Visible text of the arm button; defaults to `labels.arm`. */
|
|
1496
|
+
armLabel?: ReactNode;
|
|
1497
|
+
/** Visible text of the confirm button; defaults to `labels.confirm`. */
|
|
1498
|
+
confirmLabel?: ReactNode;
|
|
1499
|
+
/** The action is running: confirm shows a spinner and nothing can be pressed. For a
|
|
1500
|
+
* caller that tracks the mutation itself (a `useMutation`'s `isPending`); a
|
|
1501
|
+
* promise returned from `onConfirm` does the same on its own. */
|
|
1502
|
+
busy?: boolean;
|
|
1503
|
+
/** The arm button is disabled. */
|
|
1504
|
+
disabled?: boolean;
|
|
1505
|
+
/**
|
|
1506
|
+
* Why the action is not available — a read-only demo, a write lock, a missing
|
|
1507
|
+
* permission. Disables the arm button like `disabled`, and SAYS so: the sentence is
|
|
1508
|
+
* shown under the button and attached to it with `aria-describedby`, and the button
|
|
1509
|
+
* stays focusable (`aria-disabled`) so a keyboard user can land on it and hear why.
|
|
1510
|
+
*
|
|
1511
|
+
* On the ARM button rather than the confirm: arming asks for a password, and asking
|
|
1512
|
+
* for a password for a write that can never land is the worse of the two. A tile that
|
|
1513
|
+
* is ALREADY armed when the reason arrives (controlled `armed`, or a lock that landed
|
|
1514
|
+
* while it was open) keeps its fields but its confirm takes the reason the same way
|
|
1515
|
+
* — focusable, `aria-disabled`, the reason in its tooltip — and Enter does nothing.
|
|
1516
|
+
*/
|
|
1517
|
+
lockedReason?: ReactNode;
|
|
1518
|
+
/**
|
|
1519
|
+
* This tile COMMITS — the 0.18 write-lock opt-in that {@link Button} has (keksdose
|
|
1520
|
+
* K3). Under a locked {@link WriteLockProvider} the lock's reason becomes
|
|
1521
|
+
* `lockedReason` (and wins over one of the tile's own), so a page that mounts the
|
|
1522
|
+
* provider no longer threads `lockedReason={lock.locked ? lock.reason : undefined}`
|
|
1523
|
+
* into every tile. No provider, or an unlocked one: no effect.
|
|
1524
|
+
*/
|
|
1525
|
+
commit?: boolean;
|
|
1526
|
+
/** Controlled armed state. The parent can then collapse the tile from a mutation's
|
|
1527
|
+
* own `onSuccess` without returning a promise. */
|
|
1528
|
+
armed?: boolean;
|
|
1529
|
+
/** Called with the next armed state — on arm, cancel, and a resolved `onConfirm`. */
|
|
1530
|
+
onArmedChange?: (armed: boolean) => void;
|
|
1531
|
+
/** User-facing strings; see {@link DangerConfirmLabels}. */
|
|
1532
|
+
labels?: Partial<DangerConfirmLabels>;
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* An "arm → confirm" tile for destructive actions: one button, which expands into a
|
|
1536
|
+
* warning, an optional list of consequences, an optional "I understand" tick, an
|
|
1537
|
+
* optional type-to-confirm field, an optional password field and a confirm that stays
|
|
1538
|
+
* disabled until every guard is satisfied.
|
|
1539
|
+
*
|
|
1540
|
+
* Keksdose hand-rolled it three times (load demo data, wipe everything, reset a
|
|
1541
|
+
* budget) and then as `shared/components/danger-confirm.tsx`; the only app-specific
|
|
1542
|
+
* part was its write-lock hook, which is `lockedReason` here.
|
|
1543
|
+
*
|
|
1544
|
+
* The fields are a `<form>`, so Enter confirms once the guards allow it. They are
|
|
1545
|
+
* wiped every time the tile disarms — a password must not sit in a collapsed tile.
|
|
1546
|
+
* Arming moves focus to the first field (or Cancel, when there is none — never to the
|
|
1547
|
+
* destructive button itself), and disarming moves it back to the arm button, so the
|
|
1548
|
+
* keyboard user is never left on an element that just vanished.
|
|
1549
|
+
*/
|
|
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;
|
|
1551
|
+
|
|
1167
1552
|
/**
|
|
1168
1553
|
* A button that opens the file picker — the shape all three apps kept writing by hand
|
|
1169
1554
|
* as a `<Button>` plus a hidden `<input type="file">` plus a ref between them (seven
|
|
@@ -1361,6 +1746,22 @@ interface FileButtonProps extends Omit<UseFilePickerOptions, "disabled">, Omit<B
|
|
|
1361
1746
|
* file leaves it as it was. Off by default, so the button's layout is unchanged.
|
|
1362
1747
|
*/
|
|
1363
1748
|
showFileName?: boolean;
|
|
1749
|
+
/**
|
|
1750
|
+
* Why picking is not available — {@link Button}'s `disabledReason`, with the picker's
|
|
1751
|
+
* half added (keksdose K3): the button is `aria-disabled` but stays focusable, the
|
|
1752
|
+
* reason is in the kit Tooltip and its description, a click opens no picker, and a
|
|
1753
|
+
* `droppable` button takes no drop (the drag is still cancelled, so the browser does
|
|
1754
|
+
* not navigate to the file). Wins over `disabled`, as on Button.
|
|
1755
|
+
*/
|
|
1756
|
+
disabledReason?: ReactNode;
|
|
1757
|
+
/**
|
|
1758
|
+
* This pick COMMITS — an upload that starts on pick, an attachment saved at once.
|
|
1759
|
+
* Under a locked {@link WriteLockProvider} it takes the `disabledReason` path with
|
|
1760
|
+
* the lock's reason (which wins over one of its own). No provider, or an unlocked
|
|
1761
|
+
* one: no effect. A picker that only fills a form the user saves later is not a
|
|
1762
|
+
* commit, and is left live — the form's Save carries the lock.
|
|
1763
|
+
*/
|
|
1764
|
+
commit?: boolean;
|
|
1364
1765
|
}
|
|
1365
1766
|
/**
|
|
1366
1767
|
* {@link useFilePicker} behind a {@link Button}: `variant` and every other button prop
|
|
@@ -1376,6 +1777,162 @@ interface FileButtonProps extends Omit<UseFilePickerOptions, "disabled">, Omit<B
|
|
|
1376
1777
|
*/
|
|
1377
1778
|
declare const FileButton: react.ForwardRefExoticComponent<FileButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
1378
1779
|
|
|
1780
|
+
/**
|
|
1781
|
+
* The `confirmDialog` namespace of `<UiKitProvider labels>`: the two buttons' fallback
|
|
1782
|
+
* text. A call that knows what it is confirming says so per call (`confirmLabel:
|
|
1783
|
+
* "Delete budget"`), which is what the dialog is for — these are for the rest.
|
|
1784
|
+
*/
|
|
1785
|
+
interface ConfirmDialogLabels {
|
|
1786
|
+
confirm: string;
|
|
1787
|
+
cancel: string;
|
|
1788
|
+
/**
|
|
1789
|
+
* 0.18: label of the field a `requireTyped` confirm shows. A FUNCTION of the text to
|
|
1790
|
+
* type by default — where the address sits in the sentence moves with the language —
|
|
1791
|
+
* or a finished STRING. A call's own `typedLabel` wins over it.
|
|
1792
|
+
*
|
|
1793
|
+
* Required, like every key of a namespace: the shipped catalogues
|
|
1794
|
+
* (`@eifi1/ui-kit/i18n/<code>`) translate it, and an app's own full catalogue should
|
|
1795
|
+
* hear about the new string from the compiler rather than show it in English.
|
|
1796
|
+
*/
|
|
1797
|
+
typed: string | ((text: string) => string);
|
|
1798
|
+
}
|
|
1799
|
+
/** `satisfies` rather than a type annotation, so `.typed` stays known-callable for a
|
|
1800
|
+
* caller composing its own label from it. */
|
|
1801
|
+
declare const DEFAULT_CONFIRM_DIALOG_LABELS: {
|
|
1802
|
+
confirm: string;
|
|
1803
|
+
cancel: string;
|
|
1804
|
+
typed: (text: string) => string;
|
|
1805
|
+
};
|
|
1806
|
+
type ConfirmTone = "danger" | "warning" | "neutral";
|
|
1807
|
+
interface ConfirmOptions {
|
|
1808
|
+
/** The question, and the dialog's accessible name. */
|
|
1809
|
+
title: ReactNode;
|
|
1810
|
+
/** The smaller line under it — the consequence. Wired to `aria-describedby`. */
|
|
1811
|
+
body?: ReactNode;
|
|
1812
|
+
/** Default: `confirmDialog.confirm` from the provider, else "Confirm". */
|
|
1813
|
+
confirmLabel?: ReactNode;
|
|
1814
|
+
/** Default: `confirmDialog.cancel` from the provider, else "Cancel". */
|
|
1815
|
+
cancelLabel?: ReactNode;
|
|
1816
|
+
/**
|
|
1817
|
+
* `"danger"` for what cannot be undone (a delete): the confirm is the destructive
|
|
1818
|
+
* button and focus starts on CANCEL. `"warning"` and `"neutral"` (default) start on
|
|
1819
|
+
* the confirm. See {@link ConfirmProvider} for why the two differ.
|
|
1820
|
+
*/
|
|
1821
|
+
tone?: ConfirmTone;
|
|
1822
|
+
/**
|
|
1823
|
+
* 0.18: make the user TYPE this before confirm is enabled — the target account's
|
|
1824
|
+
* e-mail address, a budget's name. For the action whose risk is not "did you mean
|
|
1825
|
+
* it" but "is this the right row": an admin who deactivates somebody has already
|
|
1826
|
+
* proven who THEY are (they passed the admin gate); typing the address is what
|
|
1827
|
+
* proves they read which account they are on. Both keksdose (`TYPE_EMAIL`) and
|
|
1828
|
+
* Kurvenschmiede (`TypedConfirm`) built this beside `useConfirm` because it had no
|
|
1829
|
+
* field.
|
|
1830
|
+
*
|
|
1831
|
+
* The dialog then shows one text field under the body and focuses it (whatever the
|
|
1832
|
+
* tone: a reflexive Enter cannot confirm a field that does not match yet). Confirm
|
|
1833
|
+
* stays disabled until the text matches; Enter in the field confirms once it does.
|
|
1834
|
+
* The answer is still `true` / `false` — the text matched what you passed, so send
|
|
1835
|
+
* that to the server if it asks for the address too, not the user's spelling.
|
|
1836
|
+
*/
|
|
1837
|
+
requireTyped?: string;
|
|
1838
|
+
/** Label of that field. Default: `confirmDialog.typed` — `Type “a@b.c” to confirm`. */
|
|
1839
|
+
typedLabel?: string;
|
|
1840
|
+
/**
|
|
1841
|
+
* How the typed text is compared. Default `"caseless"`: surrounding spaces and case
|
|
1842
|
+
* ignored, the rule both apps applied to an address. `"trim"` keeps case, `"exact"`
|
|
1843
|
+
* keeps spaces too — for a phrase like "DELETE" whose contract is "exactly this".
|
|
1844
|
+
*/
|
|
1845
|
+
typedMatch?: TypedMatch;
|
|
1846
|
+
}
|
|
1847
|
+
type ConfirmFn = (options: ConfirmOptions) => Promise<boolean>;
|
|
1848
|
+
/**
|
|
1849
|
+
* `const confirm = useConfirm()` → `if (!(await confirm({ title }))) return`.
|
|
1850
|
+
*
|
|
1851
|
+
* The returned function is STABLE for the life of the provider, so it can sit in an
|
|
1852
|
+
* effect's or a `useCallback`'s dependency list without re-running it.
|
|
1853
|
+
*
|
|
1854
|
+
* Throws outside a {@link ConfirmProvider}, rather than falling back to
|
|
1855
|
+
* `window.confirm`: a silent fallback is exactly the native dialog the three apps are
|
|
1856
|
+
* migrating away from, and it would look like the migration had worked.
|
|
1857
|
+
*/
|
|
1858
|
+
declare function useConfirm(): ConfirmFn;
|
|
1859
|
+
interface ConfirmProviderProps {
|
|
1860
|
+
children: ReactNode;
|
|
1861
|
+
}
|
|
1862
|
+
/**
|
|
1863
|
+
* The host for {@link useConfirm}: ONE confirm dialog for the whole app, rendered on
|
|
1864
|
+
* {@link DialogFrame}, answering a promise.
|
|
1865
|
+
*
|
|
1866
|
+
* Asked for by all three apps at once — keksdose has 20+ `window.confirm` calls,
|
|
1867
|
+
* kastlan 7, lenkbank 1. The native dialog cannot be translated past its OK/Cancel
|
|
1868
|
+
* (those are the BROWSER's language, not the app's), cannot say which button is the
|
|
1869
|
+
* destructive one, and on an installed PWA it prints the origin over the question.
|
|
1870
|
+
* A promise is what lets each of those call sites change by one `await`:
|
|
1871
|
+
*
|
|
1872
|
+
* if (!window.confirm(t("budget.delete_confirm"))) return;
|
|
1873
|
+
* // becomes
|
|
1874
|
+
* if (!(await confirm({ title: t("budget.delete_confirm"), tone: "danger" }))) return;
|
|
1875
|
+
*
|
|
1876
|
+
* ## Its own provider, not part of `UiKitProvider`
|
|
1877
|
+
*
|
|
1878
|
+
* `UiKitProvider` renders nothing: it is strings and a locale, it is optional, and it
|
|
1879
|
+
* NESTS (an inner one re-labels one table). A dialog host inside it would mount a host
|
|
1880
|
+
* per nested provider, and a component under the inner one would open a second dialog
|
|
1881
|
+
* layer of its own. So the host is its own component, mounted once — inside the
|
|
1882
|
+
* `UiKitProvider` whose strings it should speak, which is also the order the labels
|
|
1883
|
+
* need.
|
|
1884
|
+
*
|
|
1885
|
+
* ## Focus
|
|
1886
|
+
*
|
|
1887
|
+
* On CANCEL for `tone: "danger"`, on CONFIRM otherwise. A confirm is often answered by
|
|
1888
|
+
* a reflexive Enter — the key that pressed the Delete button in the first place may
|
|
1889
|
+
* still be down — and for an action that cannot be undone that reflex must land on the
|
|
1890
|
+
* harmless answer; `DangerConfirm` makes the same call ("never to the destructive
|
|
1891
|
+
* button itself"). For everything else the confirm is the expected answer and Enter
|
|
1892
|
+
* accepting it is what `window.confirm` taught users, which the migrating call sites'
|
|
1893
|
+
* users already rely on. Focus returns to whatever opened it, through `Modal`'s trap.
|
|
1894
|
+
*
|
|
1895
|
+
* ## Escape, the backdrop, Back and Cancel all answer `false`
|
|
1896
|
+
*
|
|
1897
|
+
* Only the confirm button answers `true`. Anything that merely dismisses is a no.
|
|
1898
|
+
*
|
|
1899
|
+
* ## A second `confirm` while one is open QUEUES
|
|
1900
|
+
*
|
|
1901
|
+
* It is shown when the first is answered, and each call gets its own answer. The
|
|
1902
|
+
* alternative — answering the open one `false` to make room — would answer a question
|
|
1903
|
+
* the user never answered: a background prompt ("your session is about to expire")
|
|
1904
|
+
* would cancel the delete they were reading. `false` has to mean "the user said no".
|
|
1905
|
+
* A double-click cannot queue two of the same: the first click opens the modal
|
|
1906
|
+
* synchronously (a discrete event's update is flushed before the next one), so the
|
|
1907
|
+
* second lands on the open dialog rather than on the button — at worst on its
|
|
1908
|
+
* backdrop, which answers `false`, the safe way to be wrong.
|
|
1909
|
+
*
|
|
1910
|
+
* Unmounting the provider answers everything still pending `false`, so no caller's
|
|
1911
|
+
* `await` hangs forever.
|
|
1912
|
+
*
|
|
1913
|
+
* ## keksdose's synchronous call (transaction-swipe-plan.ts)
|
|
1914
|
+
*
|
|
1915
|
+
* `buildTxSwipeActions` is synchronous, but its `window.confirm` sits inside the
|
|
1916
|
+
* action THUNK (`confirmed(key, run)` returns `() => { if (confirm(…)) run() }`), and a
|
|
1917
|
+
* thunk may be async without its caller knowing. So the plan builder stays
|
|
1918
|
+
* synchronous; it takes the confirm as an argument and the thunk awaits it:
|
|
1919
|
+
*
|
|
1920
|
+
* // mobile-transaction-list.tsx
|
|
1921
|
+
* const confirm = useConfirm();
|
|
1922
|
+
* buildTxSwipeActions({ tx, …, confirm });
|
|
1923
|
+
*
|
|
1924
|
+
* // transaction-swipe-plan.ts
|
|
1925
|
+
* const confirmed = (messageKey: string, run: () => void) => () => {
|
|
1926
|
+
* void confirm({ title: t(messageKey), tone: "danger" }).then((ok) => ok && run());
|
|
1927
|
+
* };
|
|
1928
|
+
*
|
|
1929
|
+
* Its test then passes `confirm: vi.fn(async () => false)` instead of stubbing the
|
|
1930
|
+
* global, and asserts after an `await` (the mutation now runs a microtask later). The
|
|
1931
|
+
* row snaps back when the swipe commits, before the answer — which is right: the
|
|
1932
|
+
* dialog, not the half-swiped row, is where the question now is.
|
|
1933
|
+
*/
|
|
1934
|
+
declare function ConfirmProvider({ children }: ConfirmProviderProps): react.JSX.Element;
|
|
1935
|
+
|
|
1379
1936
|
/** The words a copy button says. The visible three are short on purpose (they
|
|
1380
1937
|
* replace the button's own text in the `label` variant); the two announcements
|
|
1381
1938
|
* are the sentences a screen reader hears, since the button's focus never moves. */
|
|
@@ -1445,8 +2002,17 @@ declare function CopyButton({ text, variant, label, buttonVariant, size, tone, s
|
|
|
1445
2002
|
interface FormActionsLabels {
|
|
1446
2003
|
save: string;
|
|
1447
2004
|
cancel: string;
|
|
2005
|
+
/**
|
|
2006
|
+
* The {@link FormActionsProps.submitShortcut} hint beside Save's text, when
|
|
2007
|
+
* {@link FormActionsProps.submitShortcutHint} shows it. `apple` is true on a Mac,
|
|
2008
|
+
* iPhone or iPad, where the key is Cmd: "⌘ Enter" there, "Ctrl+Enter" elsewhere
|
|
2009
|
+
* (a German keyboard says "Strg").
|
|
2010
|
+
*/
|
|
2011
|
+
submitShortcut: (apple: boolean) => string;
|
|
1448
2012
|
}
|
|
1449
2013
|
declare const DEFAULT_FORM_ACTIONS_LABELS: FormActionsLabels;
|
|
2014
|
+
/** See {@link FormActionsProps.submitShortcut}. */
|
|
2015
|
+
type FormActionsSubmitShortcut = "mod-enter";
|
|
1450
2016
|
type FormActionsAlign = "start" | "center" | "end" | "between";
|
|
1451
2017
|
/**
|
|
1452
2018
|
* Where the row sits:
|
|
@@ -1606,6 +2172,39 @@ interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "childr
|
|
|
1606
2172
|
/** The `id` of the `<form>` the save button submits, when the row is rendered
|
|
1607
2173
|
* outside it (a dialog's footer slot). */
|
|
1608
2174
|
form?: string;
|
|
2175
|
+
/**
|
|
2176
|
+
* A keyboard shortcut that presses Save from anywhere in the form. `"mod-enter"`:
|
|
2177
|
+
* Ctrl+Enter, or Cmd+Enter on a Mac — both are accepted everywhere, as keksdose's
|
|
2178
|
+
* editors always have. keksdose K14 (inputs audit 2026-10-02, S5): its transaction
|
|
2179
|
+
* editor, category editor and create card each wrote this as an `onKeyDown` on a
|
|
2180
|
+
* container, re-stating `!pending && !saveDisabled && !lock.locked` every time, and
|
|
2181
|
+
* the one that forgot the lock let the demo's refused save through from the keyboard.
|
|
2182
|
+
*
|
|
2183
|
+
* What it does is what pressing Save does — the same button is clicked, so a form
|
|
2184
|
+
* submits with its validation and its submitter, and `onSubmit` is called in the
|
|
2185
|
+
* `type="button"` mode — and it does NOTHING while Save could not be pressed:
|
|
2186
|
+
* `pending`, `submitDisabled`, or a `commit` under a locked {@link WriteLockProvider}.
|
|
2187
|
+
*
|
|
2188
|
+
* Scoped to the form Save submits (the `form` prop's, else the enclosing `<form>`):
|
|
2189
|
+
* the chord counts only when the focus is inside it, so two editors on one page each
|
|
2190
|
+
* answer for their own fields. Without a form (an `onSubmit` row in a plain container)
|
|
2191
|
+
* the scope is the nearest `role="dialog"`, else the row's parent element — the
|
|
2192
|
+
* container the row ends.
|
|
2193
|
+
*
|
|
2194
|
+
* Listened for on the document, so it runs AFTER every React handler: a field that
|
|
2195
|
+
* takes Ctrl+Enter for itself calls `preventDefault()` or `stopPropagation()` and
|
|
2196
|
+
* the row stays out of it (keksdose live #202 — the create card's Ctrl+Shift+Enter
|
|
2197
|
+
* must create ONE row; the chord here is exactly Ctrl/Cmd+Enter, never with Shift or
|
|
2198
|
+
* Alt). Not during IME composition, and not on a held key's repeats.
|
|
2199
|
+
*
|
|
2200
|
+
* The save button announces it with `aria-keyshortcuts`; {@link submitShortcutHint}
|
|
2201
|
+
* also shows it.
|
|
2202
|
+
*/
|
|
2203
|
+
submitShortcut?: FormActionsSubmitShortcut;
|
|
2204
|
+
/** Show the {@link submitShortcut} beside Save's text ("Ctrl+Enter", "⌘ Enter"; the
|
|
2205
|
+
* `form.submitShortcut` label), dimmed. Hidden on a touch-only device, which has no
|
|
2206
|
+
* keyboard to press it on. Default `false`. */
|
|
2207
|
+
submitShortcutHint?: boolean;
|
|
1609
2208
|
/** Extra actions, placed before Cancel. */
|
|
1610
2209
|
children?: ReactNode;
|
|
1611
2210
|
}
|
|
@@ -1624,7 +2223,7 @@ interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "childr
|
|
|
1624
2223
|
* The spinner is the kit's {@link Spinner}, drawn inside the button with `label={null}`
|
|
1625
2224
|
* so the button's name stays its text; `aria-busy` is what says it is working.
|
|
1626
2225
|
*/
|
|
1627
|
-
declare function FormActions({ onCancel, onSubmit, submitLabel, cancelLabel, pendingLabel, submitIcon: SubmitIcon, submitProps, pending, submitDisabled, submitDisabledReason, commit, submitVariant, destructive, start: startSlot, align, placement: placementProp, stickyWithin, bleed, form, children, className, style, ...rest }: FormActionsProps): react.JSX.Element;
|
|
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;
|
|
1628
2227
|
|
|
1629
2228
|
/**
|
|
1630
2229
|
* Who holds one record, and the owner's every way of changing that — Kurvenschmiede's
|
|
@@ -1806,6 +2405,147 @@ interface ShareDialogProps extends SharePanelProps, Pick<DialogFrameProps, "open
|
|
|
1806
2405
|
*/
|
|
1807
2406
|
declare function ShareDialog({ open, onClose, size, className, title, description, ...panel }: ShareDialogProps): react.JSX.Element;
|
|
1808
2407
|
|
|
2408
|
+
/** The messages {@link IbanInput} shows under itself, one per {@link IbanProblem}. */
|
|
2409
|
+
interface IbanInputLabels {
|
|
2410
|
+
/** The value does not start with a two-letter country code and two check digits. */
|
|
2411
|
+
format: string;
|
|
2412
|
+
/** The first two letters are no country in the IBAN registry. `code` is those two
|
|
2413
|
+
* letters, as typed (upper case). */
|
|
2414
|
+
country: (code: string) => string;
|
|
2415
|
+
/** The wrong length for the country: `actual` characters typed, `expected` for that
|
|
2416
|
+
* country (spaces not counted in either). */
|
|
2417
|
+
length: (actual: number, expected: number) => string;
|
|
2418
|
+
/** The mod-97 check digits do not match — a mistyped or swapped character. */
|
|
2419
|
+
checksum: string;
|
|
2420
|
+
/** `kind="qr"`: a valid IBAN, but not a QR-IBAN. */
|
|
2421
|
+
qrRequired: string;
|
|
2422
|
+
/** `kind="plain"`: a QR-IBAN, which cannot receive an ordinary transfer. */
|
|
2423
|
+
qrNotAllowed: string;
|
|
2424
|
+
}
|
|
2425
|
+
declare const DEFAULT_IBAN_INPUT_LABELS: IbanInputLabels;
|
|
2426
|
+
interface IbanInputProps extends Omit<InputProps, "type" | "value" | "defaultValue"> {
|
|
2427
|
+
/** The IBAN, compact or not — it is shown in groups of four either way. `""` is
|
|
2428
|
+
* "no IBAN". */
|
|
2429
|
+
value: string;
|
|
2430
|
+
/** The compact, upper-case IBAN (the electronic format, what to store) on every
|
|
2431
|
+
* change — valid or not: a half-typed IBAN is still the field's value. Plain
|
|
2432
|
+
* `onChange` still fires alongside it with the raw event, whose text is the GROUPED
|
|
2433
|
+
* one, so bind this rather than `onChange` to a form. */
|
|
2434
|
+
onValueChange?: (value: string) => void;
|
|
2435
|
+
/** Which IBANs the field accepts. Default `"any"`. `"qr"` / `"plain"`: see
|
|
2436
|
+
* {@link IbanKind} — and why the difference matters, {@link isQrIban}. */
|
|
2437
|
+
kind?: IbanKind;
|
|
2438
|
+
/** The messages, per field. See {@link IbanInputLabels}. */
|
|
2439
|
+
labels?: Partial<IbanInputLabels>;
|
|
2440
|
+
/** The caller's own message, shown INSTEAD of the built-in one while it is set (a
|
|
2441
|
+
* server's "this account is already on file"). `null`, `false` and `""` are no
|
|
2442
|
+
* message, so `touched && errors.iban` can be passed as it is. */
|
|
2443
|
+
error?: ReactNode;
|
|
2444
|
+
}
|
|
2445
|
+
/**
|
|
2446
|
+
* An IBAN field (kastlan, keksdose): typed in any shape, shown in groups of four,
|
|
2447
|
+
* reported compact.
|
|
2448
|
+
*
|
|
2449
|
+
* Both apps had a text field and a regex. What that left out is everything between
|
|
2450
|
+
* the keyboard and the stored value: a pasted "ch09 0000-0000…" stayed lower case
|
|
2451
|
+
* with its hyphens, the grouping that makes 21 characters checkable by eye was
|
|
2452
|
+
* missing, and a wrong IBAN was found out by the bank. Here:
|
|
2453
|
+
*
|
|
2454
|
+
* - **Grouped as you type.** The field shows the paper format ({@link formatIban});
|
|
2455
|
+
* spaces, hyphens and lower case in what is typed or pasted are folded away, and
|
|
2456
|
+
* the caret stays between the same two characters while the groups move around it.
|
|
2457
|
+
* - **Compact out.** `onValueChange` gets the electronic format — upper case, no
|
|
2458
|
+
* spaces — which is the one to store and to compare.
|
|
2459
|
+
* - **Checked, never blocked.** A wrong country, length or checksum shows a message
|
|
2460
|
+
* under the field, through the kit's `error` (so it is the field's
|
|
2461
|
+
* `aria-describedby` and paints it), but every keystroke still lands: a field that
|
|
2462
|
+
* refuses characters cannot be corrected one character at a time. While the field
|
|
2463
|
+
* has focus only what more typing cannot fix is shown; the rest waits for the full
|
|
2464
|
+
* length or for blur. Whether the field is REQUIRED stays the form's rule — an empty
|
|
2465
|
+
* field says nothing.
|
|
2466
|
+
* - **QR-IBAN or not** (kastlan): `kind="qr"` refuses a regular IBAN and
|
|
2467
|
+
* `kind="plain"` refuses a QR-IBAN — a QR-bill can only be paid to a QR-IBAN, and a
|
|
2468
|
+
* QR-IBAN can receive nothing else. See {@link isQrIban}.
|
|
2469
|
+
*
|
|
2470
|
+
* It is {@link Input} underneath, so `label`, `hint`, `error`, `invalid` and the rest
|
|
2471
|
+
* are Input's own and the field reads like every other. A form that must not submit
|
|
2472
|
+
* an invalid IBAN checks {@link isValidIban} / {@link ibanProblem} itself — the field
|
|
2473
|
+
* shows the problem but does not own the submit.
|
|
2474
|
+
*/
|
|
2475
|
+
declare const IbanInput: react.ForwardRefExoticComponent<IbanInputProps & react.RefAttributes<HTMLInputElement>>;
|
|
2476
|
+
|
|
2477
|
+
/** The words {@link PhoneInput} renders on its own behalf. */
|
|
2478
|
+
interface PhoneInputLabels {
|
|
2479
|
+
/** The country-code select's accessible name. */
|
|
2480
|
+
countryCode: string;
|
|
2481
|
+
/** The select's last option: a number from a country not listed, typed with its
|
|
2482
|
+
* own "+". */
|
|
2483
|
+
other: string;
|
|
2484
|
+
}
|
|
2485
|
+
declare const DEFAULT_PHONE_INPUT_LABELS: PhoneInputLabels;
|
|
2486
|
+
interface PhoneInputProps extends Omit<InputProps, "type" | "value" | "defaultValue"> {
|
|
2487
|
+
/** The number: E.164 ("+41210000001") for one the field could read, or free text —
|
|
2488
|
+
* a value saved before the field existed is shown exactly as it is. `""` is no
|
|
2489
|
+
* number. */
|
|
2490
|
+
value: string;
|
|
2491
|
+
/** On every change: E.164 when the typed text reads as a number of the selected
|
|
2492
|
+
* country (or carries its own "+"), otherwise the typed text UNCHANGED. Nothing is
|
|
2493
|
+
* refused — see {@link PhoneInput}. Plain `onChange` still fires with the raw event;
|
|
2494
|
+
* bind this one to a form. */
|
|
2495
|
+
onValueChange?: (value: string) => void;
|
|
2496
|
+
/** The country a number typed without "+" belongs to, until the value says
|
|
2497
|
+
* otherwise. Default `"CH"`. */
|
|
2498
|
+
defaultCountry?: PhoneCountry;
|
|
2499
|
+
/** The countries the select offers, in order; "Other" always follows. Default
|
|
2500
|
+
* {@link PHONE_COUNTRIES} (CH, LI, DE, AT, FR, IT). A stored number from a country
|
|
2501
|
+
* left out still shows under its own code. */
|
|
2502
|
+
countries?: readonly PhoneCountryCode[];
|
|
2503
|
+
/** See {@link PhoneInputLabels}. */
|
|
2504
|
+
labels?: Partial<PhoneInputLabels>;
|
|
2505
|
+
/** Classes for the whole field — the select, the input and the lines under them.
|
|
2506
|
+
* `inputClassName` reaches the `<input>`. */
|
|
2507
|
+
className?: string;
|
|
2508
|
+
}
|
|
2509
|
+
/**
|
|
2510
|
+
* A phone number field (kastlan): a country-code select and the number, stored as
|
|
2511
|
+
* E.164 and shown grouped.
|
|
2512
|
+
*
|
|
2513
|
+
* kastlan's contacts kept whatever was typed — "079 …", "+41 (0)79 …", "0041 79 …" —
|
|
2514
|
+
* which nobody could dial from the app or match against the next import. This field
|
|
2515
|
+
* turns all of those into one stored form, "+41210000001", without taking anything
|
|
2516
|
+
* away from the person typing:
|
|
2517
|
+
*
|
|
2518
|
+
* - **A country to type against.** The select (default CH, then LI, DE, AT, FR, IT
|
|
2519
|
+
* and "Other") says which country a number without "+" belongs to; the national
|
|
2520
|
+
* trunk 0 may be typed or left out. Typing a "+" or "00" overrides it, and the
|
|
2521
|
+
* select follows the number ("+49 …" switches it to DE). Changing the select moves
|
|
2522
|
+
* the national number to the new country code.
|
|
2523
|
+
* - **E.164 when it reads, the text when it does not.** A number the rules read is
|
|
2524
|
+
* emitted as E.164; anything else ("ask reception", an extension) is emitted exactly
|
|
2525
|
+
* as typed. Never refused, never an error of its own: a contact's number is often
|
|
2526
|
+
* known only roughly, and a field that will not save "079 … (mornings)" makes
|
|
2527
|
+
* people type it into the notes instead. An app that needs a dialable number
|
|
2528
|
+
* checks {@link isE164} on submit.
|
|
2529
|
+
* - **Existing values untouched.** A free-text value from before is shown exactly as
|
|
2530
|
+
* it is, and normalised only when someone edits it — the field never rewrites a
|
|
2531
|
+
* record just by being opened.
|
|
2532
|
+
* - **Grouped when settled.** While typing the field shows what was typed; on blur a
|
|
2533
|
+
* number it read is regrouped by its country ("21 000 00 01").
|
|
2534
|
+
*
|
|
2535
|
+
* **The limitation** — there is no libphonenumber behind this (≈150 kB of metadata in
|
|
2536
|
+
* every bundle): the six countries have light rules (the trunk 0, a plausible length)
|
|
2537
|
+
* and every other country is any "+" with 8–15 digits. A well-formed number that does
|
|
2538
|
+
* not exist passes, and German and Austrian landlines, whose area codes vary in length,
|
|
2539
|
+
* are grouped only where the split is known (mobile prefixes, the largest cities) and
|
|
2540
|
+
* otherwise shown as one block. See `lib/phone.ts`.
|
|
2541
|
+
*
|
|
2542
|
+
* `label`, `hint`, `error` and `invalid` read as on {@link Input}: the label floats in
|
|
2543
|
+
* the number's box, and a text hint and the error go under the whole row, attached to
|
|
2544
|
+
* the number with `aria-describedby`. The select is named by `labels.countryCode`, and
|
|
2545
|
+
* the pair is a group named by a string `label`.
|
|
2546
|
+
*/
|
|
2547
|
+
declare const PhoneInput: react.ForwardRefExoticComponent<PhoneInputProps & react.RefAttributes<HTMLInputElement>>;
|
|
2548
|
+
|
|
1809
2549
|
/**
|
|
1810
2550
|
* EVERY string the kit renders, as one typed tree — and an optional provider that
|
|
1811
2551
|
* hands it to every component at once.
|
|
@@ -2032,6 +2772,18 @@ interface UiKitLabels {
|
|
|
2032
2772
|
translationReview: TranslationReviewLabels;
|
|
2033
2773
|
/** 0.19.0: `LegalLinks`' navigation name — the legal pages' shell, for every app. */
|
|
2034
2774
|
legal: LegalLabels;
|
|
2775
|
+
/** 0.22.0: the screen-reader words of `Input` / `Textarea`'s `showCount` counter. */
|
|
2776
|
+
characterCount: CharacterCountLabels;
|
|
2777
|
+
/** 0.22.0: `CountrySelect`. Its list's "no results" and counts are `combobox`'s. */
|
|
2778
|
+
countrySelect: CountrySelectLabels;
|
|
2779
|
+
/** 0.22.0: `InlineEditField` — keksdose K9. */
|
|
2780
|
+
inlineEdit: InlineEditLabels;
|
|
2781
|
+
/** 0.22.0: `IbanInput`'s messages, one per problem. */
|
|
2782
|
+
ibanInput: IbanInputLabels;
|
|
2783
|
+
/** 0.22.0: `PhoneInput`'s country-code select. */
|
|
2784
|
+
phoneInput: PhoneInputLabels;
|
|
2785
|
+
/** 0.22.0: `SignChip` — the outflow / inflow toggle beside an amount. */
|
|
2786
|
+
signChip: SignChipLabels;
|
|
2035
2787
|
}
|
|
2036
2788
|
/**
|
|
2037
2789
|
* A label override, as deep as the labels go: an object of labels (a namespace, or a
|
|
@@ -2065,6 +2817,35 @@ declare const DEFAULT_FILE_LABELS: FileLabels;
|
|
|
2065
2817
|
/** "12 kB", "3.4 MB" — `Intl`'s unit formatting, so the digits, the decimal mark and
|
|
2066
2818
|
* the unit's spelling all follow `locale`. */
|
|
2067
2819
|
declare function formatFileSize(bytes: number, locale?: string): string;
|
|
2820
|
+
/** What a {@link KitDateFormatter} is told about the date it is formatting. */
|
|
2821
|
+
interface KitDateFormatContext {
|
|
2822
|
+
/**
|
|
2823
|
+
* How much of a date the string is: `"day"` — the `iso` is `"YYYY-MM-DD"`; `"month"` —
|
|
2824
|
+
* `"YYYY-MM"` (a `MonthPicker`); `"year"` — `"YYYY"` (`MonthPicker mode="year"`).
|
|
2825
|
+
*/
|
|
2826
|
+
unit: "day" | "month" | "year";
|
|
2827
|
+
/** Which kit surface asks: the trigger of a `DatePicker`, of a `DateRangePicker`
|
|
2828
|
+
* (called once per end), of a `MonthPicker`, or a `DateMark`. */
|
|
2829
|
+
source: "datePicker" | "dateRangePicker" | "monthPicker" | "dateMark";
|
|
2830
|
+
/** The locale the kit would have formatted in — the component's `locale` prop, else
|
|
2831
|
+
* the provider's — or `undefined` for the runtime's. */
|
|
2832
|
+
locale: string | undefined;
|
|
2833
|
+
/**
|
|
2834
|
+
* The kit's suggestion: whether this date stands alone where the day of the week
|
|
2835
|
+
* helps — `true` for a `DatePicker`'s trigger and a `DateMark`, `false` for the two
|
|
2836
|
+
* ends of a range (twice the width, in a sentence-like "from – to") and for a month
|
|
2837
|
+
* or a year. keksdose's rule, which this follows: *"A date in a COLUMN carries the
|
|
2838
|
+
* weekday. A date in a SENTENCE does not."* (date-cell.tsx, dev#546). A formatter
|
|
2839
|
+
* is free to ignore it.
|
|
2840
|
+
*/
|
|
2841
|
+
weekday: boolean;
|
|
2842
|
+
}
|
|
2843
|
+
/**
|
|
2844
|
+
* The app's ONE answer to "what does a date look like here" — keksdose K12. Returns the
|
|
2845
|
+
* text for an ISO date (see {@link KitDateFormatContext.unit} for the three shapes).
|
|
2846
|
+
* Return `""` to fall back to the kit's own formatting for that date.
|
|
2847
|
+
*/
|
|
2848
|
+
type KitDateFormatter = (iso: string, context: KitDateFormatContext) => string;
|
|
2068
2849
|
/** Where a chart shows the values under the pointer — see `SeriesChartTooltip.placement`. */
|
|
2069
2850
|
type ChartTooltipPlacement = "cursor" | "above" | "below" | "auto";
|
|
2070
2851
|
/**
|
|
@@ -2127,6 +2908,25 @@ interface UiKitProviderProps {
|
|
|
2127
2908
|
* pointer, as before.
|
|
2128
2909
|
*/
|
|
2129
2910
|
chartTooltipPlacement?: ChartTooltipPlacement;
|
|
2911
|
+
/**
|
|
2912
|
+
* How every kit date below is written, when the component is not told otherwise —
|
|
2913
|
+
* keksdose K12. keksdose has a date-format preference (Settings ▸ date format, feedback
|
|
2914
|
+
* #180) that is not the UI language, and a weekday in the UI language beside digits
|
|
2915
|
+
* in the preference's order (live #246, dev#546): two locales in one string, which
|
|
2916
|
+
* no `locale` + `Intl` options can say. Its `DateField` wraps every `DatePicker` to
|
|
2917
|
+
* pass `formatValue`, and its report range field formats both ends by hand; with this
|
|
2918
|
+
* set once on the provider, those wrappers thin to nothing.
|
|
2919
|
+
*
|
|
2920
|
+
* Used for the trigger text of `DatePicker`, `DateRangePicker` and `MonthPicker`
|
|
2921
|
+
* (month and year mode), and for `DateMark display="date"`. A component's own
|
|
2922
|
+
* `formatValue` or `formatOptions` (`dateStyle` on a DateMark) wins: prop >
|
|
2923
|
+
* provider > the kit's `Intl` default, the order every kit setting resolves in. Left
|
|
2924
|
+
* out (or returning `""`), everything formats exactly as before.
|
|
2925
|
+
*
|
|
2926
|
+
* Keep it stable (`useCallback`, or a module function): it is in the provider's
|
|
2927
|
+
* context value, so a new function every render re-renders every consumer.
|
|
2928
|
+
*/
|
|
2929
|
+
formatDate?: KitDateFormatter;
|
|
2130
2930
|
children: ReactNode;
|
|
2131
2931
|
}
|
|
2132
2932
|
/**
|
|
@@ -2137,7 +2937,7 @@ interface UiKitProviderProps {
|
|
|
2137
2937
|
* it names, so a page can re-label one table's `dataTable.table` without restating
|
|
2138
2938
|
* the language.
|
|
2139
2939
|
*/
|
|
2140
|
-
declare function UiKitProvider({ labels, locale, weekStartsOn, linkComponent, chartTooltipPlacement, children, }: UiKitProviderProps): react.JSX.Element;
|
|
2940
|
+
declare function UiKitProvider({ labels, locale, weekStartsOn, linkComponent, chartTooltipPlacement, formatDate, children, }: UiKitProviderProps): react.JSX.Element;
|
|
2141
2941
|
/** What the nearest provider says about one namespace — `undefined` outside one.
|
|
2142
2942
|
* For a component whose own resolver does more than a merge (the data table
|
|
2143
2943
|
* derives `columnsCount` from `columns`): feed `{ ...overrides, ...props }` to it. */
|
|
@@ -2159,6 +2959,9 @@ declare function useKitLink(): KitLinkComponent | undefined;
|
|
|
2159
2959
|
declare function useKitWeekStart(): WeekDay | undefined;
|
|
2160
2960
|
/** The provider's `chartTooltipPlacement`, or `undefined` — a chart's own prop wins. */
|
|
2161
2961
|
declare function useKitChartTooltipPlacement(): ChartTooltipPlacement | undefined;
|
|
2962
|
+
/** The nearest provider's `formatDate`, or `undefined` — a component's own
|
|
2963
|
+
* `formatValue` / `formatOptions` wins over it. See {@link KitDateFormatter}. */
|
|
2964
|
+
declare function useKitDateFormatter(): KitDateFormatter | undefined;
|
|
2162
2965
|
/** {@link DEFAULT_FILE_LABELS}, but formatting in the provider's locale. */
|
|
2163
2966
|
declare function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels;
|
|
2164
2967
|
/**
|
|
@@ -2175,4 +2978,4 @@ declare function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels;
|
|
|
2175
2978
|
*/
|
|
2176
2979
|
declare function missingKitLabels(labels: UiKitLabelOverrides | undefined, reference: UiKitLabels): string[];
|
|
2177
2980
|
|
|
2178
|
-
export {
|
|
2981
|
+
export { DEFAULT_FILE_LABELS as $, type AppShellLabels as A, Button as B, type CalculatorLabels as C, type CommonLabels as D, type ConfirmDialogLabels as E, type ConfirmFn as F, type ConfirmOptions as G, ConfirmProvider as H, type ConfirmProviderProps as I, type ConfirmTone as J, CopyButton as K, type CopyButtonLabels as L, type CopyButtonProps as M, type CurrencyLabels as N, CurrentPasswordInput as O, type CurrentPasswordInputLabels as P, type CurrentPasswordInputProps as Q, DEFAULT_APP_SHELL_LABELS as R, DEFAULT_CALCULATOR_LABELS as S, DEFAULT_CHARACTER_COUNT_LABELS as T, DEFAULT_COMBOBOX_LABELS as U, DEFAULT_COMMON_LABELS as V, DEFAULT_CONFIRM_DIALOG_LABELS as W, DEFAULT_COPY_BUTTON_LABELS as X, DEFAULT_CURRENCY_LABELS as Y, DEFAULT_DANGER_CONFIRM_LABELS as Z, DEFAULT_DATE_PICKER_LABELS as _, type ButtonClassesOptions as a, type InputProps as a$, DEFAULT_FILE_PICKER_LABELS as a0, DEFAULT_FORM_ACTIONS_LABELS as a1, DEFAULT_IBAN_INPUT_LABELS as a2, DEFAULT_MULTI_SELECT_LABELS as a3, DEFAULT_PASSWORD_REVEAL_LABELS as a4, DEFAULT_PHONE_INPUT_LABELS as a5, DEFAULT_PICKER_SHEET_LABELS as a6, DEFAULT_SHARE_CARD_LABELS as a7, DEFAULT_SWIPEABLE_ROW_LABELS as a8, DEFAULT_TABS_LABELS as a9, type FilePickerLabels as aA, type FileRejection as aB, type FileRejectionReason as aC, type FileScreenOptions as aD, FloatingField as aE, type FloatingFieldProps as aF, FormActions as aG, type FormActionsAlign as aH, type FormActionsDestructive as aI, type FormActionsLabels as aJ, type FormActionsPlacement as aK, type FormActionsProps as aL, type FormActionsStickyWithin as aM, type FormActionsSubmitProps as aN, type FormActionsSubmitShortcut as aO, IbanInput as aP, type IbanInputLabels as aQ, type IbanInputProps as aR, IconButton as aS, type IconButtonGlyphSize as aT, type IconButtonLinkProps as aU, type IconButtonProps as aV, type IconButtonSize as aW, type IconButtonTone as aX, type IconButtonToneColor as aY, type IconButtonVariant as aZ, Input as a_, DEFAULT_TOP_BAR_LABELS as aa, DangerConfirm as ab, type DangerConfirmLabels as ac, type DangerConfirmProps as ad, type DangerConsequence as ae, type DatePickerLabels as af, EmptyState as ag, type EmptyStateProps as ah, FIELD_BASE as ai, FIELD_DISPLAY as aj, FIELD_FLOATING_PAD as ak, FIELD_INVALID as al, FIELD_TRIGGER as am, FIELD_WRITABLE_LOOK as an, FLOATING_INPUT_CLASS as ao, FLOATING_LABEL_CLASS as ap, FLOATING_LABEL_STATIC as aq, FieldChevron as ar, type FieldChevronProps as as, FieldHint as at, type FieldHintProps as au, FieldLabel as av, type FieldLabelProps as aw, FileButton as ax, type FileButtonProps as ay, type FileLabels as az, type ButtonLinkProps as b, useKitLocale as b$, type KitDateFormatContext as b0, type KitDateFormatter as b1, type KitLinkComponent as b2, type KitLinkProps as b3, Label as b4, type LabelOverride as b5, type LabelProps as b6, type MultiSelectLabels as b7, PHONE_QUERY as b8, type PasswordRevealLabels as b9, Textarea as bA, type TextareaProps as bB, type TopBarLabels as bC, TypedConfirmField as bD, type TypedConfirmFieldLabels as bE, type TypedConfirmFieldProps as bF, type TypedMatch as bG, type UiKitLabelOverrides as bH, type UiKitLabels as bI, UiKitProvider as bJ, type UiKitProviderProps as bK, type UseFilePickerOptions as bL, type UseFilePickerReturn as bM, buttonClasses as bN, formatFileSize as bO, matchesAccept as bP, missingKitLabels as bQ, resolvePasswordRevealLabels as bR, typedMatches as bS, useConfirm as bT, useFilePicker as bU, useKitChartTooltipPlacement as bV, useKitDateFormatter as bW, useKitFileLabels as bX, useKitLabelOverrides as bY, useKitLabels as bZ, useKitLink as b_, PhoneInput as ba, type PhoneInputLabels as bb, type PhoneInputProps as bc, type PickerSheetLabels as bd, type ResponsiveFormActionsPlacement as be, Select as bf, type SelectProps as bg, type ShareAddRequest as bh, type ShareCandidate as bi, ShareCard as bj, type ShareCardLabels as bk, type ShareCardProps as bl, ShareDialog as bm, type ShareDialogProps as bn, type ShareGrantee as bo, SharePanel as bp, type SharePanelProps as bq, type SharePendingGrant as br, type ShareRole as bs, Spinner as bt, type SpinnerProps as bu, type SwipeableRowLabels as bv, type TabItem as bw, Tabs as bx, type TabsLabels as by, type TabsProps as bz, type ButtonProps as c, useKitWeekStart as c0, type FilePickHandler as c1, usePromisePending as c2, formatAccept as c3, judgePick as c4, screenFiles as c5, summariseRejections as c6, type ButtonSize as d, type ButtonTone as e, type ButtonVariant as f, Card as g, CardAction as h, type CardActionProps as i, CardContent as j, type CardContentProps as k, type CardDensity as l, CardDescription as m, type CardDescriptionProps as n, CardFooter as o, type CardFooterProps as p, CardHeader as q, type CardHeaderProps as r, type CardProps as s, CardTitle as t, type CardTitleLevel as u, type CardTitleProps as v, type CardTone as w, type CharacterCountLabels as x, type ChartTooltipPlacement as y, type ComboboxLabels as z };
|