@dloizides/ui-forms 1.21.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.23.0
4
+
5
+ BEAD-3 "Report form: searchable pattern field and shared form feedback".
6
+
7
+ - `TypeaheadControl` takes `search` instead of `options` for async results: `load(query, signal)`, `onPick(option | null)`, loading, empty and error text, 250 ms debounce, stale responses ignored, editing after a pick clears it.
8
+ - `TypeaheadControl` is a WAI-ARIA combobox in both modes: Down, Up, Enter, Esc, `aria-activedescendant`, a ref to its input. Its rows change role from `menuitem` to `option`; testIDs are unchanged.
9
+ - `ControlOption` gains an optional `detail`, shown under the title on a phone and beside it from 768 px.
10
+ - `AnchoredMenu` fits its height above the on-screen keyboard through `visualViewport`; new `listbox` prop for listbox roles and a status line.
11
+ - New `FormStatusLine` and `useFocusFirstInvalid`.
12
+
13
+ ## 1.22.0
14
+
15
+ KEFI-EDITOR-UI-2 "Extract stepper and upload-with-link field to @dloizides/ui-forms", extracted from kefi-web.
16
+
17
+ - New `StepperTabs`, `StepperNav` and pure `resolveStepNeighbours`: step tabs sharing the row width, back and next under the step. Generic over the step key; every string is a prop.
18
+ - New `UploadWithLinkField`: preview, an upload control slot and a link input revealed on request. The slot keeps ui-forms free of ui-media; pass `ImagePickerButton`.
19
+
3
20
  ## 1.20.0
4
21
 
5
22
  **Horizontal form fields line up (D-ALL-22 "Horizontal form fields are aligned").**
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { RefObject } from 'react';
2
2
  import { StyleProp, TextStyle, ViewStyle, TextInputProps, TextInput, View } from 'react-native';
3
3
 
4
4
  /**
@@ -701,6 +701,7 @@ declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, desc
701
701
  interface ControlOption {
702
702
  readonly label: string;
703
703
  readonly value: string;
704
+ readonly detail?: string;
704
705
  }
705
706
  /** The inclusive from/to value of a date-range control (each an ISO `YYYY-MM-DD` string, or ''). */
706
707
  interface DateRangeValue {
@@ -761,6 +762,22 @@ interface SelectControlProps {
761
762
  }
762
763
  declare function SelectControl({ options, value, onChange, placeholder, accessibilityLabel, accessibilityHint, labelledById, optionHint, style, testID, }: SelectControlProps): React.ReactElement;
763
764
 
765
+ interface FieldControlWiring {
766
+ id?: string;
767
+ describedById?: string;
768
+ }
769
+ interface TypeaheadSearch {
770
+ load: (query: string, signal: AbortSignal) => Promise<readonly ControlOption[]>;
771
+ onPick: (option: ControlOption | null) => void;
772
+ loadingText: string;
773
+ emptyText: string;
774
+ errorText: string;
775
+ debounceMs?: number;
776
+ maxResults?: number;
777
+ scrollMarginTop?: number;
778
+ inputTestID?: string;
779
+ }
780
+
764
781
  /**
765
782
  * `TypeaheadControl` — a search-as-you-type combobox (aml-v2's CountryPicker, generalized). A
766
783
  * text input plus a floating {@link AnchoredMenu} of ranked suggestions ({@link suggestOptions});
@@ -779,8 +796,7 @@ declare function SelectControl({ options, value, onChange, placeholder, accessib
779
796
  declare const DEFAULT_TYPEAHEAD_MIN_CHARS = 1;
780
797
  /** Default cap on rendered suggestions. */
781
798
  declare const DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS = 8;
782
- interface TypeaheadControlProps {
783
- options: readonly ControlOption[];
799
+ interface TypeaheadCommonProps {
784
800
  /** The raw text in the box — NOT necessarily an option value. */
785
801
  value: string;
786
802
  onChange: (value: string) => void;
@@ -796,14 +812,19 @@ interface TypeaheadControlProps {
796
812
  error?: string;
797
813
  /** Minimum characters before suggestions surface. Default 1. */
798
814
  minChars?: number;
799
- /** Cap on rendered suggestions. Default 8. */
800
- maxSuggestions?: number;
801
815
  /** Merged LAST onto the anchor wrapper. */
802
816
  style?: StyleProp<ViewStyle>;
803
817
  /** Input is `${testID}-input`, menu `${testID}-menu`, error `${testID}-error`. */
804
818
  testID: string;
805
819
  }
806
- declare function TypeaheadControl({ options, value, onChange, onSubmit, placeholder, accessibilityLabel, accessibilityHint, optionHint, error, minChars, maxSuggestions, style, testID, }: TypeaheadControlProps): React.ReactElement;
820
+ interface TypeaheadControlProps extends TypeaheadCommonProps {
821
+ options: readonly ControlOption[];
822
+ maxSuggestions?: number;
823
+ }
824
+ interface TypeaheadSearchProps extends TypeaheadCommonProps {
825
+ search: TypeaheadSearch;
826
+ }
827
+ declare const TypeaheadControl: React.ForwardRefExoticComponent<((TypeaheadControlProps | TypeaheadSearchProps) & FieldControlWiring) & React.RefAttributes<TextInput>>;
807
828
 
808
829
  /**
809
830
  * `DateRangeControl` — an inclusive from/to pair (aml cases `from`/`to`, kefi audit `from`/`to`).
@@ -861,10 +882,15 @@ declare function DateRangeControl({ value, onChange, onSubmit, fromLabel, toLabe
861
882
  /** The four theme colours the menu paints with — passed in, so the menu stays theme-flat. */
862
883
  interface AnchoredMenuColors {
863
884
  text: string;
885
+ textSecondary?: string;
864
886
  border: string;
865
887
  surface: string;
866
888
  brand: string;
867
889
  }
890
+ interface AnchoredMenuListbox {
891
+ highlightedValue: string;
892
+ statusText?: string;
893
+ }
868
894
  interface AnchoredMenuProps {
869
895
  options: readonly ControlOption[];
870
896
  /** The currently-selected value, highlighted in the list ('' = none). */
@@ -897,8 +923,9 @@ interface AnchoredMenuProps {
897
923
  * only for the rare case that genuinely wants the menu clipped to its container.
898
924
  */
899
925
  usePortal?: boolean;
926
+ listbox?: AnchoredMenuListbox;
900
927
  }
901
- declare function AnchoredMenu({ options, selectedValue, onSelect, onDismiss, colors, optionHint, accessibilityLabel, testID, anchorRef, usePortal, }: AnchoredMenuProps): React.ReactElement;
928
+ declare function AnchoredMenu({ options, selectedValue, onSelect, onDismiss, colors, optionHint, accessibilityLabel, testID, anchorRef, usePortal, listbox, }: AnchoredMenuProps): React.ReactElement;
902
929
 
903
930
  declare const controlStyles: {
904
931
  /**
@@ -1062,4 +1089,85 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1062
1089
  */
1063
1090
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1064
1091
 
1065
- export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
1092
+ /** One step; `label` is pre-localized and shown on its tab. */
1093
+ interface StepperStep<TKey extends string | number = string> {
1094
+ key: TKey;
1095
+ label: string;
1096
+ }
1097
+ interface StepNeighbours<TKey extends string | number = string> {
1098
+ previous: StepperStep<TKey> | null;
1099
+ next: StepperStep<TKey> | null;
1100
+ }
1101
+ /** The steps either side of `current`; both null when `current` is not a step. */
1102
+ declare function resolveStepNeighbours<TKey extends string | number>(steps: readonly StepperStep<TKey>[], current: TKey): StepNeighbours<TKey>;
1103
+
1104
+ interface StepperTabsProps<TKey extends string | number = string> {
1105
+ steps: readonly StepperStep<TKey>[];
1106
+ current: TKey;
1107
+ onStep: (key: TKey) => void;
1108
+ /** Pre-localized accessibility hint for every tab. */
1109
+ stepHint: string;
1110
+ /** Row testID; each tab is `${testID}-${step.key}`. */
1111
+ testID: string;
1112
+ }
1113
+ /** A row of step tabs sharing the width; each label wraps inside its own tab. */
1114
+ declare const StepperTabs: <TKey extends string | number = string>({ steps, current, onStep, stepHint, testID, }: StepperTabsProps<TKey>) => React.ReactElement;
1115
+
1116
+ interface StepperNavLabels<TKey extends string | number = string> {
1117
+ back: string;
1118
+ backHint: string;
1119
+ /** The next button's label, built from the step it leads to. */
1120
+ next: (step: StepperStep<TKey>) => string;
1121
+ nextHint: string;
1122
+ }
1123
+ interface StepperNavProps<TKey extends string | number = string> {
1124
+ steps: readonly StepperStep<TKey>[];
1125
+ current: TKey;
1126
+ onStep: (key: TKey) => void;
1127
+ labels: StepperNavLabels<TKey>;
1128
+ /** Row testID; the buttons are `${testID}-back` and `${testID}-next`. */
1129
+ testID: string;
1130
+ }
1131
+ /** Back and next under a step: back is disabled on the first step, next is absent on the last. */
1132
+ declare const StepperNav: <TKey extends string | number = string>({ steps, current, onStep, labels, testID, }: StepperNavProps<TKey>) => React.ReactElement;
1133
+
1134
+ interface FormStatusLineProps {
1135
+ message: string | null | undefined;
1136
+ testID: string;
1137
+ style?: StyleProp<TextStyle>;
1138
+ }
1139
+ /** A form's result message, announced as an alert; renders nothing until there is one. */
1140
+ declare function FormStatusLine({ message, testID, style }: FormStatusLineProps): React.ReactElement | null;
1141
+
1142
+ interface Focusable {
1143
+ focus: () => void;
1144
+ }
1145
+ type FocusableRefs<Field extends string> = Readonly<Record<Field, RefObject<Focusable | null>>>;
1146
+ /** Returns a stable function that focuses the first listed field that is on screen. */
1147
+ declare function useFocusFirstInvalid<Field extends string>(refs: FocusableRefs<Field>): (invalid: readonly Field[]) => void;
1148
+
1149
+ /** Every string the field shows; all pre-localized. */
1150
+ interface UploadWithLinkLabels {
1151
+ title: string;
1152
+ help?: string;
1153
+ pasteToggle: string;
1154
+ pasteToggleHint: string;
1155
+ link: string;
1156
+ linkHint: string;
1157
+ linkPlaceholder: string;
1158
+ }
1159
+ interface UploadWithLinkFieldProps {
1160
+ value: string | null | undefined;
1161
+ onChange: (url: string) => void;
1162
+ labels: UploadWithLinkLabels;
1163
+ /** The upload control, e.g. ui-media `ImagePickerButton`; its transport stays with the app. */
1164
+ uploadControl: React.ReactNode;
1165
+ /** The link input; the others are `${testID}-preview` and `${testID}-paste`. */
1166
+ testID: string;
1167
+ disabled?: boolean;
1168
+ previewSize?: number;
1169
+ }
1170
+ /** An image field: preview, an upload control, and a link input revealed on request. */
1171
+ declare const UploadWithLinkField: ({ value, onChange, labels, uploadControl, testID, disabled, previewSize, }: UploadWithLinkFieldProps) => React.ReactElement;
1172
+
1173
+ export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuListbox, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, type Focusable, type FocusableRefs, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormStatusLine, type FormStatusLineProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type TypeaheadSearch, type TypeaheadSearchProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useFocusFirstInvalid, useRecentValues, useThemedInput };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { RefObject } from 'react';
2
2
  import { StyleProp, TextStyle, ViewStyle, TextInputProps, TextInput, View } from 'react-native';
3
3
 
4
4
  /**
@@ -701,6 +701,7 @@ declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, desc
701
701
  interface ControlOption {
702
702
  readonly label: string;
703
703
  readonly value: string;
704
+ readonly detail?: string;
704
705
  }
705
706
  /** The inclusive from/to value of a date-range control (each an ISO `YYYY-MM-DD` string, or ''). */
706
707
  interface DateRangeValue {
@@ -761,6 +762,22 @@ interface SelectControlProps {
761
762
  }
762
763
  declare function SelectControl({ options, value, onChange, placeholder, accessibilityLabel, accessibilityHint, labelledById, optionHint, style, testID, }: SelectControlProps): React.ReactElement;
763
764
 
765
+ interface FieldControlWiring {
766
+ id?: string;
767
+ describedById?: string;
768
+ }
769
+ interface TypeaheadSearch {
770
+ load: (query: string, signal: AbortSignal) => Promise<readonly ControlOption[]>;
771
+ onPick: (option: ControlOption | null) => void;
772
+ loadingText: string;
773
+ emptyText: string;
774
+ errorText: string;
775
+ debounceMs?: number;
776
+ maxResults?: number;
777
+ scrollMarginTop?: number;
778
+ inputTestID?: string;
779
+ }
780
+
764
781
  /**
765
782
  * `TypeaheadControl` — a search-as-you-type combobox (aml-v2's CountryPicker, generalized). A
766
783
  * text input plus a floating {@link AnchoredMenu} of ranked suggestions ({@link suggestOptions});
@@ -779,8 +796,7 @@ declare function SelectControl({ options, value, onChange, placeholder, accessib
779
796
  declare const DEFAULT_TYPEAHEAD_MIN_CHARS = 1;
780
797
  /** Default cap on rendered suggestions. */
781
798
  declare const DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS = 8;
782
- interface TypeaheadControlProps {
783
- options: readonly ControlOption[];
799
+ interface TypeaheadCommonProps {
784
800
  /** The raw text in the box — NOT necessarily an option value. */
785
801
  value: string;
786
802
  onChange: (value: string) => void;
@@ -796,14 +812,19 @@ interface TypeaheadControlProps {
796
812
  error?: string;
797
813
  /** Minimum characters before suggestions surface. Default 1. */
798
814
  minChars?: number;
799
- /** Cap on rendered suggestions. Default 8. */
800
- maxSuggestions?: number;
801
815
  /** Merged LAST onto the anchor wrapper. */
802
816
  style?: StyleProp<ViewStyle>;
803
817
  /** Input is `${testID}-input`, menu `${testID}-menu`, error `${testID}-error`. */
804
818
  testID: string;
805
819
  }
806
- declare function TypeaheadControl({ options, value, onChange, onSubmit, placeholder, accessibilityLabel, accessibilityHint, optionHint, error, minChars, maxSuggestions, style, testID, }: TypeaheadControlProps): React.ReactElement;
820
+ interface TypeaheadControlProps extends TypeaheadCommonProps {
821
+ options: readonly ControlOption[];
822
+ maxSuggestions?: number;
823
+ }
824
+ interface TypeaheadSearchProps extends TypeaheadCommonProps {
825
+ search: TypeaheadSearch;
826
+ }
827
+ declare const TypeaheadControl: React.ForwardRefExoticComponent<((TypeaheadControlProps | TypeaheadSearchProps) & FieldControlWiring) & React.RefAttributes<TextInput>>;
807
828
 
808
829
  /**
809
830
  * `DateRangeControl` — an inclusive from/to pair (aml cases `from`/`to`, kefi audit `from`/`to`).
@@ -861,10 +882,15 @@ declare function DateRangeControl({ value, onChange, onSubmit, fromLabel, toLabe
861
882
  /** The four theme colours the menu paints with — passed in, so the menu stays theme-flat. */
862
883
  interface AnchoredMenuColors {
863
884
  text: string;
885
+ textSecondary?: string;
864
886
  border: string;
865
887
  surface: string;
866
888
  brand: string;
867
889
  }
890
+ interface AnchoredMenuListbox {
891
+ highlightedValue: string;
892
+ statusText?: string;
893
+ }
868
894
  interface AnchoredMenuProps {
869
895
  options: readonly ControlOption[];
870
896
  /** The currently-selected value, highlighted in the list ('' = none). */
@@ -897,8 +923,9 @@ interface AnchoredMenuProps {
897
923
  * only for the rare case that genuinely wants the menu clipped to its container.
898
924
  */
899
925
  usePortal?: boolean;
926
+ listbox?: AnchoredMenuListbox;
900
927
  }
901
- declare function AnchoredMenu({ options, selectedValue, onSelect, onDismiss, colors, optionHint, accessibilityLabel, testID, anchorRef, usePortal, }: AnchoredMenuProps): React.ReactElement;
928
+ declare function AnchoredMenu({ options, selectedValue, onSelect, onDismiss, colors, optionHint, accessibilityLabel, testID, anchorRef, usePortal, listbox, }: AnchoredMenuProps): React.ReactElement;
902
929
 
903
930
  declare const controlStyles: {
904
931
  /**
@@ -1062,4 +1089,85 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1062
1089
  */
1063
1090
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1064
1091
 
1065
- export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
1092
+ /** One step; `label` is pre-localized and shown on its tab. */
1093
+ interface StepperStep<TKey extends string | number = string> {
1094
+ key: TKey;
1095
+ label: string;
1096
+ }
1097
+ interface StepNeighbours<TKey extends string | number = string> {
1098
+ previous: StepperStep<TKey> | null;
1099
+ next: StepperStep<TKey> | null;
1100
+ }
1101
+ /** The steps either side of `current`; both null when `current` is not a step. */
1102
+ declare function resolveStepNeighbours<TKey extends string | number>(steps: readonly StepperStep<TKey>[], current: TKey): StepNeighbours<TKey>;
1103
+
1104
+ interface StepperTabsProps<TKey extends string | number = string> {
1105
+ steps: readonly StepperStep<TKey>[];
1106
+ current: TKey;
1107
+ onStep: (key: TKey) => void;
1108
+ /** Pre-localized accessibility hint for every tab. */
1109
+ stepHint: string;
1110
+ /** Row testID; each tab is `${testID}-${step.key}`. */
1111
+ testID: string;
1112
+ }
1113
+ /** A row of step tabs sharing the width; each label wraps inside its own tab. */
1114
+ declare const StepperTabs: <TKey extends string | number = string>({ steps, current, onStep, stepHint, testID, }: StepperTabsProps<TKey>) => React.ReactElement;
1115
+
1116
+ interface StepperNavLabels<TKey extends string | number = string> {
1117
+ back: string;
1118
+ backHint: string;
1119
+ /** The next button's label, built from the step it leads to. */
1120
+ next: (step: StepperStep<TKey>) => string;
1121
+ nextHint: string;
1122
+ }
1123
+ interface StepperNavProps<TKey extends string | number = string> {
1124
+ steps: readonly StepperStep<TKey>[];
1125
+ current: TKey;
1126
+ onStep: (key: TKey) => void;
1127
+ labels: StepperNavLabels<TKey>;
1128
+ /** Row testID; the buttons are `${testID}-back` and `${testID}-next`. */
1129
+ testID: string;
1130
+ }
1131
+ /** Back and next under a step: back is disabled on the first step, next is absent on the last. */
1132
+ declare const StepperNav: <TKey extends string | number = string>({ steps, current, onStep, labels, testID, }: StepperNavProps<TKey>) => React.ReactElement;
1133
+
1134
+ interface FormStatusLineProps {
1135
+ message: string | null | undefined;
1136
+ testID: string;
1137
+ style?: StyleProp<TextStyle>;
1138
+ }
1139
+ /** A form's result message, announced as an alert; renders nothing until there is one. */
1140
+ declare function FormStatusLine({ message, testID, style }: FormStatusLineProps): React.ReactElement | null;
1141
+
1142
+ interface Focusable {
1143
+ focus: () => void;
1144
+ }
1145
+ type FocusableRefs<Field extends string> = Readonly<Record<Field, RefObject<Focusable | null>>>;
1146
+ /** Returns a stable function that focuses the first listed field that is on screen. */
1147
+ declare function useFocusFirstInvalid<Field extends string>(refs: FocusableRefs<Field>): (invalid: readonly Field[]) => void;
1148
+
1149
+ /** Every string the field shows; all pre-localized. */
1150
+ interface UploadWithLinkLabels {
1151
+ title: string;
1152
+ help?: string;
1153
+ pasteToggle: string;
1154
+ pasteToggleHint: string;
1155
+ link: string;
1156
+ linkHint: string;
1157
+ linkPlaceholder: string;
1158
+ }
1159
+ interface UploadWithLinkFieldProps {
1160
+ value: string | null | undefined;
1161
+ onChange: (url: string) => void;
1162
+ labels: UploadWithLinkLabels;
1163
+ /** The upload control, e.g. ui-media `ImagePickerButton`; its transport stays with the app. */
1164
+ uploadControl: React.ReactNode;
1165
+ /** The link input; the others are `${testID}-preview` and `${testID}-paste`. */
1166
+ testID: string;
1167
+ disabled?: boolean;
1168
+ previewSize?: number;
1169
+ }
1170
+ /** An image field: preview, an upload control, and a link input revealed on request. */
1171
+ declare const UploadWithLinkField: ({ value, onChange, labels, uploadControl, testID, disabled, previewSize, }: UploadWithLinkFieldProps) => React.ReactElement;
1172
+
1173
+ export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuListbox, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, type Focusable, type FocusableRefs, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormStatusLine, type FormStatusLineProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type TypeaheadSearch, type TypeaheadSearchProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useFocusFirstInvalid, useRecentValues, useThemedInput };