@dloizides/ui-forms 1.20.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 +7 -0
- package/dist/index.d.mts +67 -1
- package/dist/index.d.ts +67 -1
- package/dist/index.js +219 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +218 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
@@ -1437,12 +1437,18 @@ var FormSwitch = ({
|
|
|
1437
1437
|
)
|
|
1438
1438
|
);
|
|
1439
1439
|
};
|
|
1440
|
+
|
|
1441
|
+
// src/FormCheckbox/checkboxColors.ts
|
|
1442
|
+
var checkboxBoxColors = (colors, brand, checked) => checked ? { backgroundColor: brand, borderColor: brand } : { backgroundColor: "transparent", borderColor: colors.textSecondary };
|
|
1440
1443
|
var ACTIVATION_KEYS = ["Enter", " ", "Spacebar"];
|
|
1441
1444
|
var HINT_FONT_SIZE2 = 12;
|
|
1442
1445
|
var BOX_SIZE = 20;
|
|
1443
1446
|
var BOX_RADIUS = 5;
|
|
1444
1447
|
var CHECK_FONT_SIZE = 14;
|
|
1445
1448
|
var DISABLED_OPACITY = 0.5;
|
|
1449
|
+
var FOCUS_RING_WIDTH = 2;
|
|
1450
|
+
var WEB_NO_DEFAULT_OUTLINE = { outlineStyle: "none" };
|
|
1451
|
+
var FOCUS_RING_INSET = -6;
|
|
1446
1452
|
var styles9 = reactNative.StyleSheet.create({
|
|
1447
1453
|
container: {
|
|
1448
1454
|
flexDirection: "row",
|
|
@@ -1467,6 +1473,15 @@ var styles9 = reactNative.StyleSheet.create({
|
|
|
1467
1473
|
// Nudge the box to sit on the label's first text line.
|
|
1468
1474
|
marginTop: 1
|
|
1469
1475
|
},
|
|
1476
|
+
focusRing: {
|
|
1477
|
+
position: "absolute",
|
|
1478
|
+
top: FOCUS_RING_INSET,
|
|
1479
|
+
left: FOCUS_RING_INSET,
|
|
1480
|
+
right: FOCUS_RING_INSET,
|
|
1481
|
+
bottom: FOCUS_RING_INSET,
|
|
1482
|
+
borderWidth: FOCUS_RING_WIDTH,
|
|
1483
|
+
borderRadius: BOX_RADIUS - FOCUS_RING_INSET
|
|
1484
|
+
},
|
|
1470
1485
|
check: {
|
|
1471
1486
|
fontSize: CHECK_FONT_SIZE,
|
|
1472
1487
|
fontWeight: "700",
|
|
@@ -1502,13 +1517,15 @@ var FormCheckbox = ({
|
|
|
1502
1517
|
const hintText = typeof hint === "string" && hint !== "" ? hint : description;
|
|
1503
1518
|
const hasHint = typeof hintText === "string" && hintText !== "";
|
|
1504
1519
|
const { hintId } = useFieldIds();
|
|
1520
|
+
const [focused, setFocused] = React2__default.default.useState(false);
|
|
1505
1521
|
const themeStyles = React2__default.default.useMemo(() => {
|
|
1506
|
-
const boxOn =
|
|
1507
|
-
const boxOff =
|
|
1522
|
+
const boxOn = checkboxBoxColors(colors, brand, true);
|
|
1523
|
+
const boxOff = checkboxBoxColors(colors, brand, false);
|
|
1524
|
+
const ring = { borderColor: brand };
|
|
1508
1525
|
const labelStyle = { color: colors.text };
|
|
1509
1526
|
const hintStyle = { color: colors.textSecondary };
|
|
1510
|
-
return { boxOn, boxOff, label: labelStyle, hint: hintStyle };
|
|
1511
|
-
}, [brand, colors
|
|
1527
|
+
return { boxOn, boxOff, ring, label: labelStyle, hint: hintStyle };
|
|
1528
|
+
}, [brand, colors]);
|
|
1512
1529
|
const toggle = () => {
|
|
1513
1530
|
const next = !value;
|
|
1514
1531
|
if (onValueChange) onValueChange(next);
|
|
@@ -1532,18 +1549,24 @@ var FormCheckbox = ({
|
|
|
1532
1549
|
"aria-checked": value,
|
|
1533
1550
|
"aria-describedby": hasHint ? hintId : void 0,
|
|
1534
1551
|
disabled,
|
|
1552
|
+
onBlur: () => setFocused(false),
|
|
1553
|
+
onFocus: () => setFocused(true),
|
|
1535
1554
|
onPress: toggle,
|
|
1536
1555
|
role: "checkbox",
|
|
1537
1556
|
style: [
|
|
1538
1557
|
styles9.container,
|
|
1539
1558
|
hasHint ? null : styles9.centered,
|
|
1540
1559
|
containerStyle,
|
|
1541
|
-
disabled ? { opacity: DISABLED_OPACITY } : null
|
|
1560
|
+
disabled ? { opacity: DISABLED_OPACITY } : null,
|
|
1561
|
+
reactNative.Platform.OS === "web" ? WEB_NO_DEFAULT_OUTLINE : null
|
|
1542
1562
|
],
|
|
1543
1563
|
testID,
|
|
1544
1564
|
...keyboardProps,
|
|
1545
1565
|
children: [
|
|
1546
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1566
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles9.box, value ? themeStyles.boxOn : themeStyles.boxOff], testID: `${testID}-box`, children: [
|
|
1567
|
+
focused ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { pointerEvents: "none", style: [styles9.focusRing, themeStyles.ring], testID: `${testID}-focus-ring` }) : null,
|
|
1568
|
+
value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null
|
|
1569
|
+
] }),
|
|
1547
1570
|
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.textColumn, children: [
|
|
1548
1571
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.label, themeStyles.label], children: label }),
|
|
1549
1572
|
hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles9.hint, themeStyles.hint], children: hintText }) : null
|
|
@@ -1837,6 +1860,192 @@ function toggleGroupSelection(selected, groupKeys, order) {
|
|
|
1837
1860
|
});
|
|
1838
1861
|
return order === void 0 ? merged : order.filter((key) => merged.includes(key));
|
|
1839
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
|
+
};
|
|
1840
2049
|
|
|
1841
2050
|
exports.AlignToControl = AlignToControl;
|
|
1842
2051
|
exports.AnchoredMenu = AnchoredMenu;
|
|
@@ -1857,13 +2066,17 @@ exports.FormSwitch = FormSwitch;
|
|
|
1857
2066
|
exports.INLINE_FIELD_ROW_MIN_WIDTH = INLINE_FIELD_ROW_MIN_WIDTH;
|
|
1858
2067
|
exports.InlineFieldRow = InlineFieldRow;
|
|
1859
2068
|
exports.SelectControl = SelectControl;
|
|
2069
|
+
exports.StepperNav = StepperNav;
|
|
2070
|
+
exports.StepperTabs = StepperTabs;
|
|
1860
2071
|
exports.ThemedTextInput = ThemedTextInput;
|
|
1861
2072
|
exports.TypeaheadControl = TypeaheadControl;
|
|
2073
|
+
exports.UploadWithLinkField = UploadWithLinkField;
|
|
1862
2074
|
exports.controlStyles = controlStyles;
|
|
1863
2075
|
exports.groupAriaChecked = groupAriaChecked;
|
|
1864
2076
|
exports.inlineFieldRowLayout = inlineFieldRowLayout;
|
|
1865
2077
|
exports.isUnmatched = isUnmatched;
|
|
1866
2078
|
exports.resolveGroupSelection = resolveGroupSelection;
|
|
2079
|
+
exports.resolveStepNeighbours = resolveStepNeighbours;
|
|
1867
2080
|
exports.suggestOptions = suggestOptions;
|
|
1868
2081
|
exports.toggleGroupSelection = toggleGroupSelection;
|
|
1869
2082
|
exports.useRecentValues = useRecentValues;
|