@dloizides/ui-forms 1.21.0 → 1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.22.0
4
+
5
+ KEFI-EDITOR-UI-2 "Extract stepper and upload-with-link field to @dloizides/ui-forms", extracted from kefi-web.
6
+
7
+ - 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.
8
+ - 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`.
9
+
3
10
  ## 1.20.0
4
11
 
5
12
  **Horizontal form fields line up (D-ALL-22 "Horizontal form fields are aligned").**
package/dist/index.d.mts CHANGED
@@ -1062,4 +1062,70 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1062
1062
  */
1063
1063
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1064
1064
 
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 };
1065
+ /** One step; `label` is pre-localized and shown on its tab. */
1066
+ interface StepperStep<TKey extends string | number = string> {
1067
+ key: TKey;
1068
+ label: string;
1069
+ }
1070
+ interface StepNeighbours<TKey extends string | number = string> {
1071
+ previous: StepperStep<TKey> | null;
1072
+ next: StepperStep<TKey> | null;
1073
+ }
1074
+ /** The steps either side of `current`; both null when `current` is not a step. */
1075
+ declare function resolveStepNeighbours<TKey extends string | number>(steps: readonly StepperStep<TKey>[], current: TKey): StepNeighbours<TKey>;
1076
+
1077
+ interface StepperTabsProps<TKey extends string | number = string> {
1078
+ steps: readonly StepperStep<TKey>[];
1079
+ current: TKey;
1080
+ onStep: (key: TKey) => void;
1081
+ /** Pre-localized accessibility hint for every tab. */
1082
+ stepHint: string;
1083
+ /** Row testID; each tab is `${testID}-${step.key}`. */
1084
+ testID: string;
1085
+ }
1086
+ /** A row of step tabs sharing the width; each label wraps inside its own tab. */
1087
+ declare const StepperTabs: <TKey extends string | number = string>({ steps, current, onStep, stepHint, testID, }: StepperTabsProps<TKey>) => React.ReactElement;
1088
+
1089
+ interface StepperNavLabels<TKey extends string | number = string> {
1090
+ back: string;
1091
+ backHint: string;
1092
+ /** The next button's label, built from the step it leads to. */
1093
+ next: (step: StepperStep<TKey>) => string;
1094
+ nextHint: string;
1095
+ }
1096
+ interface StepperNavProps<TKey extends string | number = string> {
1097
+ steps: readonly StepperStep<TKey>[];
1098
+ current: TKey;
1099
+ onStep: (key: TKey) => void;
1100
+ labels: StepperNavLabels<TKey>;
1101
+ /** Row testID; the buttons are `${testID}-back` and `${testID}-next`. */
1102
+ testID: string;
1103
+ }
1104
+ /** Back and next under a step: back is disabled on the first step, next is absent on the last. */
1105
+ declare const StepperNav: <TKey extends string | number = string>({ steps, current, onStep, labels, testID, }: StepperNavProps<TKey>) => React.ReactElement;
1106
+
1107
+ /** Every string the field shows; all pre-localized. */
1108
+ interface UploadWithLinkLabels {
1109
+ title: string;
1110
+ help?: string;
1111
+ pasteToggle: string;
1112
+ pasteToggleHint: string;
1113
+ link: string;
1114
+ linkHint: string;
1115
+ linkPlaceholder: string;
1116
+ }
1117
+ interface UploadWithLinkFieldProps {
1118
+ value: string | null | undefined;
1119
+ onChange: (url: string) => void;
1120
+ labels: UploadWithLinkLabels;
1121
+ /** The upload control, e.g. ui-media `ImagePickerButton`; its transport stays with the app. */
1122
+ uploadControl: React.ReactNode;
1123
+ /** The link input; the others are `${testID}-preview` and `${testID}-paste`. */
1124
+ testID: string;
1125
+ disabled?: boolean;
1126
+ previewSize?: number;
1127
+ }
1128
+ /** An image field: preview, an upload control, and a link input revealed on request. */
1129
+ declare const UploadWithLinkField: ({ value, onChange, labels, uploadControl, testID, disabled, previewSize, }: UploadWithLinkFieldProps) => React.ReactElement;
1130
+
1131
+ 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 StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
package/dist/index.d.ts CHANGED
@@ -1062,4 +1062,70 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1062
1062
  */
1063
1063
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1064
1064
 
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 };
1065
+ /** One step; `label` is pre-localized and shown on its tab. */
1066
+ interface StepperStep<TKey extends string | number = string> {
1067
+ key: TKey;
1068
+ label: string;
1069
+ }
1070
+ interface StepNeighbours<TKey extends string | number = string> {
1071
+ previous: StepperStep<TKey> | null;
1072
+ next: StepperStep<TKey> | null;
1073
+ }
1074
+ /** The steps either side of `current`; both null when `current` is not a step. */
1075
+ declare function resolveStepNeighbours<TKey extends string | number>(steps: readonly StepperStep<TKey>[], current: TKey): StepNeighbours<TKey>;
1076
+
1077
+ interface StepperTabsProps<TKey extends string | number = string> {
1078
+ steps: readonly StepperStep<TKey>[];
1079
+ current: TKey;
1080
+ onStep: (key: TKey) => void;
1081
+ /** Pre-localized accessibility hint for every tab. */
1082
+ stepHint: string;
1083
+ /** Row testID; each tab is `${testID}-${step.key}`. */
1084
+ testID: string;
1085
+ }
1086
+ /** A row of step tabs sharing the width; each label wraps inside its own tab. */
1087
+ declare const StepperTabs: <TKey extends string | number = string>({ steps, current, onStep, stepHint, testID, }: StepperTabsProps<TKey>) => React.ReactElement;
1088
+
1089
+ interface StepperNavLabels<TKey extends string | number = string> {
1090
+ back: string;
1091
+ backHint: string;
1092
+ /** The next button's label, built from the step it leads to. */
1093
+ next: (step: StepperStep<TKey>) => string;
1094
+ nextHint: string;
1095
+ }
1096
+ interface StepperNavProps<TKey extends string | number = string> {
1097
+ steps: readonly StepperStep<TKey>[];
1098
+ current: TKey;
1099
+ onStep: (key: TKey) => void;
1100
+ labels: StepperNavLabels<TKey>;
1101
+ /** Row testID; the buttons are `${testID}-back` and `${testID}-next`. */
1102
+ testID: string;
1103
+ }
1104
+ /** Back and next under a step: back is disabled on the first step, next is absent on the last. */
1105
+ declare const StepperNav: <TKey extends string | number = string>({ steps, current, onStep, labels, testID, }: StepperNavProps<TKey>) => React.ReactElement;
1106
+
1107
+ /** Every string the field shows; all pre-localized. */
1108
+ interface UploadWithLinkLabels {
1109
+ title: string;
1110
+ help?: string;
1111
+ pasteToggle: string;
1112
+ pasteToggleHint: string;
1113
+ link: string;
1114
+ linkHint: string;
1115
+ linkPlaceholder: string;
1116
+ }
1117
+ interface UploadWithLinkFieldProps {
1118
+ value: string | null | undefined;
1119
+ onChange: (url: string) => void;
1120
+ labels: UploadWithLinkLabels;
1121
+ /** The upload control, e.g. ui-media `ImagePickerButton`; its transport stays with the app. */
1122
+ uploadControl: React.ReactNode;
1123
+ /** The link input; the others are `${testID}-preview` and `${testID}-paste`. */
1124
+ testID: string;
1125
+ disabled?: boolean;
1126
+ previewSize?: number;
1127
+ }
1128
+ /** An image field: preview, an upload control, and a link input revealed on request. */
1129
+ declare const UploadWithLinkField: ({ value, onChange, labels, uploadControl, testID, disabled, previewSize, }: UploadWithLinkFieldProps) => React.ReactElement;
1130
+
1131
+ 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 StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
package/dist/index.js CHANGED
@@ -1860,6 +1860,192 @@ function toggleGroupSelection(selected, groupKeys, order) {
1860
1860
  });
1861
1861
  return order === void 0 ? merged : order.filter((key) => merged.includes(key));
1862
1862
  }
1863
+ var ROW_GAP = 4;
1864
+ var TAB_PADDING = 4;
1865
+ var INDICATOR_WIDTH = 2;
1866
+ var TAB_FONT_SIZE = 12;
1867
+ var styles10 = reactNative.StyleSheet.create({
1868
+ row: { flexDirection: "row", flexWrap: "nowrap", gap: ROW_GAP },
1869
+ tab: {
1870
+ borderBottomWidth: INDICATOR_WIDTH,
1871
+ flexBasis: 0,
1872
+ flexGrow: 1,
1873
+ flexShrink: 1,
1874
+ justifyContent: "center",
1875
+ minHeight: a11y.MIN_TOUCH_TARGET_PX,
1876
+ minWidth: 0,
1877
+ paddingHorizontal: TAB_PADDING
1878
+ },
1879
+ text: { fontSize: TAB_FONT_SIZE, textAlign: "center" },
1880
+ textSelected: { fontWeight: "700" }
1881
+ });
1882
+ var StepperTab = ({
1883
+ step,
1884
+ selected,
1885
+ hint,
1886
+ onStep,
1887
+ testID
1888
+ }) => {
1889
+ const { theme } = uiFeedback.useUi();
1890
+ const ring = uiButtons.useFocusRing();
1891
+ const indicator = selected ? theme.palette.primary["500"] : theme.colors.border;
1892
+ const webKeyProps = {
1893
+ onKeyDown: (event) => {
1894
+ if (event.key !== " ") return;
1895
+ event.preventDefault?.();
1896
+ onStep(step.key);
1897
+ }
1898
+ };
1899
+ return /* @__PURE__ */ jsxRuntime.jsx(
1900
+ reactNative.Pressable,
1901
+ {
1902
+ accessibilityHint: hint,
1903
+ accessibilityLabel: step.label,
1904
+ accessibilityRole: "tab",
1905
+ accessibilityState: { selected },
1906
+ "aria-selected": selected,
1907
+ style: [styles10.tab, { borderBottomColor: indicator }, ring.ringStyle],
1908
+ testID,
1909
+ onBlur: ring.onBlur,
1910
+ onFocus: ring.onFocus,
1911
+ onPress: () => onStep(step.key),
1912
+ ...webKeyProps,
1913
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.text, { color: theme.colors.text }, selected ? styles10.textSelected : void 0], children: step.label })
1914
+ }
1915
+ );
1916
+ };
1917
+ var StepperTabs = ({
1918
+ steps,
1919
+ current,
1920
+ onStep,
1921
+ stepHint,
1922
+ testID
1923
+ }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { accessibilityRole: "tablist", style: styles10.row, testID, children: steps.map((step) => /* @__PURE__ */ jsxRuntime.jsx(
1924
+ StepperTab,
1925
+ {
1926
+ hint: stepHint,
1927
+ selected: step.key === current,
1928
+ step,
1929
+ testID: `${testID}-${step.key}`,
1930
+ onStep
1931
+ },
1932
+ step.key
1933
+ )) });
1934
+
1935
+ // src/Stepper/stepperModel.ts
1936
+ function resolveStepNeighbours(steps, current) {
1937
+ const index = steps.findIndex((step) => step.key === current);
1938
+ if (index < 0) return { previous: null, next: null };
1939
+ return { previous: steps[index - 1] ?? null, next: steps[index + 1] ?? null };
1940
+ }
1941
+ var ROW_GAP2 = 8;
1942
+ var styles11 = reactNative.StyleSheet.create({
1943
+ cell: { flex: 1, minWidth: 0 },
1944
+ row: { flexDirection: "row", gap: ROW_GAP2 }
1945
+ });
1946
+ var StepperNav = ({
1947
+ steps,
1948
+ current,
1949
+ onStep,
1950
+ labels,
1951
+ testID
1952
+ }) => {
1953
+ const { previous, next } = resolveStepNeighbours(steps, current);
1954
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles11.row, testID, children: [
1955
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles11.cell, children: /* @__PURE__ */ jsxRuntime.jsx(
1956
+ uiButtons.Button,
1957
+ {
1958
+ fullWidth: true,
1959
+ accessibilityHint: labels.backHint,
1960
+ accessibilityLabel: labels.back,
1961
+ autoLoading: false,
1962
+ disabled: previous === null,
1963
+ label: labels.back,
1964
+ testID: `${testID}-back`,
1965
+ variant: "outline",
1966
+ onPress: () => {
1967
+ if (previous !== null) onStep(previous.key);
1968
+ }
1969
+ }
1970
+ ) }),
1971
+ next === null ? null : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles11.cell, children: /* @__PURE__ */ jsxRuntime.jsx(
1972
+ uiButtons.Button,
1973
+ {
1974
+ fullWidth: true,
1975
+ accessibilityHint: labels.nextHint,
1976
+ accessibilityLabel: labels.next(next),
1977
+ autoLoading: false,
1978
+ label: labels.next(next),
1979
+ testID: `${testID}-next`,
1980
+ onPress: () => onStep(next.key)
1981
+ }
1982
+ ) })
1983
+ ] });
1984
+ };
1985
+ var DEFAULT_PREVIEW_PX = 48;
1986
+ var PREVIEW_RADIUS = 8;
1987
+ var GAP = 8;
1988
+ var TITLE_FONT_SIZE = 14;
1989
+ var HELP_FONT_SIZE = 13;
1990
+ var styles12 = reactNative.StyleSheet.create({
1991
+ help: { flex: 1, fontSize: HELP_FONT_SIZE },
1992
+ root: { gap: GAP },
1993
+ tile: { alignItems: "center", flexDirection: "row", gap: GAP },
1994
+ title: { fontSize: TITLE_FONT_SIZE, fontWeight: "700" },
1995
+ toggle: { alignSelf: "flex-start", justifyContent: "center", minHeight: a11y.MIN_TOUCH_TARGET_PX },
1996
+ toggleText: { fontSize: TITLE_FONT_SIZE, fontWeight: "700", textDecorationLine: "underline" }
1997
+ });
1998
+ var UploadWithLinkField = ({
1999
+ value,
2000
+ onChange,
2001
+ labels,
2002
+ uploadControl,
2003
+ testID,
2004
+ disabled = false,
2005
+ previewSize = DEFAULT_PREVIEW_PX
2006
+ }) => {
2007
+ const { theme } = uiFeedback.useUi();
2008
+ const ring = uiButtons.useFocusRing();
2009
+ const url = value ?? "";
2010
+ const [pasting, setPasting] = React2.useState(url !== "");
2011
+ const previewBox = { borderRadius: PREVIEW_RADIUS, height: previewSize, width: previewSize };
2012
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles12.root, children: [
2013
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles12.title, { color: theme.colors.text }], children: labels.title }),
2014
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles12.tile, children: [
2015
+ url === "" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [previewBox, { backgroundColor: theme.colors.border }] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { accessible: false, source: { uri: url }, style: previewBox, testID: `${testID}-preview` }),
2016
+ labels.help === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles12.help, { color: theme.colors.text }], children: labels.help })
2017
+ ] }),
2018
+ uploadControl,
2019
+ /* @__PURE__ */ jsxRuntime.jsx(
2020
+ reactNative.Pressable,
2021
+ {
2022
+ accessibilityHint: labels.pasteToggleHint,
2023
+ accessibilityLabel: labels.pasteToggle,
2024
+ accessibilityRole: "button",
2025
+ accessibilityState: { expanded: pasting },
2026
+ "aria-expanded": pasting,
2027
+ style: [styles12.toggle, ring.ringStyle],
2028
+ testID: `${testID}-paste`,
2029
+ onBlur: ring.onBlur,
2030
+ onFocus: ring.onFocus,
2031
+ onPress: () => setPasting(!pasting),
2032
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles12.toggleText, { color: theme.colors.text }], children: labels.pasteToggle })
2033
+ }
2034
+ ),
2035
+ pasting ? /* @__PURE__ */ jsxRuntime.jsx(
2036
+ FormField,
2037
+ {
2038
+ accessibilityHint: labels.linkHint,
2039
+ editable: !disabled,
2040
+ label: labels.link,
2041
+ placeholder: labels.linkPlaceholder,
2042
+ testID,
2043
+ value: url,
2044
+ onChangeText: onChange
2045
+ }
2046
+ ) : null
2047
+ ] });
2048
+ };
1863
2049
 
1864
2050
  exports.AlignToControl = AlignToControl;
1865
2051
  exports.AnchoredMenu = AnchoredMenu;
@@ -1880,13 +2066,17 @@ exports.FormSwitch = FormSwitch;
1880
2066
  exports.INLINE_FIELD_ROW_MIN_WIDTH = INLINE_FIELD_ROW_MIN_WIDTH;
1881
2067
  exports.InlineFieldRow = InlineFieldRow;
1882
2068
  exports.SelectControl = SelectControl;
2069
+ exports.StepperNav = StepperNav;
2070
+ exports.StepperTabs = StepperTabs;
1883
2071
  exports.ThemedTextInput = ThemedTextInput;
1884
2072
  exports.TypeaheadControl = TypeaheadControl;
2073
+ exports.UploadWithLinkField = UploadWithLinkField;
1885
2074
  exports.controlStyles = controlStyles;
1886
2075
  exports.groupAriaChecked = groupAriaChecked;
1887
2076
  exports.inlineFieldRowLayout = inlineFieldRowLayout;
1888
2077
  exports.isUnmatched = isUnmatched;
1889
2078
  exports.resolveGroupSelection = resolveGroupSelection;
2079
+ exports.resolveStepNeighbours = resolveStepNeighbours;
1890
2080
  exports.suggestOptions = suggestOptions;
1891
2081
  exports.toggleGroupSelection = toggleGroupSelection;
1892
2082
  exports.useRecentValues = useRecentValues;