@openzeppelin/ui-components 3.0.1 → 3.1.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/index.cjs CHANGED
@@ -38,7 +38,7 @@ let sonner = require("sonner");
38
38
  let next_themes = require("next-themes");
39
39
 
40
40
  //#region src/version.ts
41
- const VERSION = "3.0.1";
41
+ const VERSION = "3.1.0";
42
42
 
43
43
  //#endregion
44
44
  //#region src/components/ui/accordion.tsx
@@ -2952,6 +2952,312 @@ function AddressField({ id, label, placeholder, helperText, control, name, width
2952
2952
  }
2953
2953
  AddressField.displayName = "AddressField";
2954
2954
 
2955
+ //#endregion
2956
+ //#region src/components/fields/TextAreaField.tsx
2957
+ /**
2958
+ * Multi-line text input field component specifically designed for React Hook Form integration.
2959
+ *
2960
+ * Architecture flow:
2961
+ * 1. Form schemas are generated from contract functions using adapters
2962
+ * 2. TransactionForm renders the overall form structure with React Hook Form
2963
+ * 3. DynamicFormField selects the appropriate field component based on field type
2964
+ * 4. BaseField provides consistent layout and hook form integration
2965
+ * 5. This component handles textarea-specific rendering and validation
2966
+ *
2967
+ * The component includes:
2968
+ * - Integration with React Hook Form
2969
+ * - Resizable multi-line text input
2970
+ * - Character limit support
2971
+ * - Customizable validation through adapter integration
2972
+ * - Automatic error handling and reporting
2973
+ * - Full accessibility support with ARIA attributes
2974
+ * - Keyboard navigation with Escape to clear
2975
+ */
2976
+ function TextAreaField({ id, label, placeholder, helperText, control, name, width = "full", validation, rows = 4, maxLength, validateTextArea, readOnly }) {
2977
+ const isRequired = !!validation?.required;
2978
+ const errorId = `${id}-error`;
2979
+ const descriptionId = `${id}-description`;
2980
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2981
+ className: `flex flex-col gap-2 ${width === "full" ? "w-full" : width === "half" ? "w-1/2" : "w-1/3"}`,
2982
+ children: [label && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Label, {
2983
+ htmlFor: id,
2984
+ children: [
2985
+ label,
2986
+ " ",
2987
+ isRequired && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2988
+ className: "text-destructive",
2989
+ children: "*"
2990
+ })
2991
+ ]
2992
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_hook_form.Controller, {
2993
+ control,
2994
+ name,
2995
+ rules: { validate: (value) => {
2996
+ if (value === void 0 || value === null || value === "") return validation?.required ? "This field is required" : true;
2997
+ if (validateTextArea && value) {
2998
+ const validation$1 = validateTextArea(value);
2999
+ if (validation$1 !== true && typeof validation$1 === "string") return validation$1;
3000
+ }
3001
+ if (maxLength && typeof value === "string" && value.length > maxLength) return `Maximum length is ${maxLength} characters`;
3002
+ return true;
3003
+ } },
3004
+ disabled: readOnly,
3005
+ render: ({ field, fieldState: { error, isTouched } }) => {
3006
+ const hasError = !!error;
3007
+ const shouldShowError = hasError && isTouched;
3008
+ const validationClasses = require_ErrorMessage.getValidationStateClasses(error, isTouched);
3009
+ const accessibilityProps = getAccessibilityProps({
3010
+ id,
3011
+ hasError,
3012
+ isRequired,
3013
+ hasHelperText: !!helperText
3014
+ });
3015
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3016
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Textarea, {
3017
+ ...field,
3018
+ id,
3019
+ placeholder,
3020
+ rows,
3021
+ maxLength,
3022
+ className: validationClasses,
3023
+ value: field.value ?? "",
3024
+ disabled: readOnly,
3025
+ ...accessibilityProps,
3026
+ "aria-describedby": `${helperText ? descriptionId : ""} ${hasError ? errorId : ""}`,
3027
+ onKeyDown: handleEscapeKey((value) => {
3028
+ if (typeof field.onChange === "function") field.onChange(value);
3029
+ }, field.value)
3030
+ }),
3031
+ maxLength && typeof field.value === "string" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3032
+ className: "text-muted-foreground text-right text-xs",
3033
+ children: [
3034
+ field.value.length,
3035
+ "/",
3036
+ maxLength
3037
+ ]
3038
+ }),
3039
+ helperText && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3040
+ id: descriptionId,
3041
+ className: "text-muted-foreground text-sm",
3042
+ children: helperText
3043
+ }),
3044
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ErrorMessage.ErrorMessage, {
3045
+ error,
3046
+ id: errorId,
3047
+ message: shouldShowError ? error?.message : void 0
3048
+ })
3049
+ ] });
3050
+ }
3051
+ })]
3052
+ });
3053
+ }
3054
+ TextAreaField.displayName = "TextAreaField";
3055
+
3056
+ //#endregion
3057
+ //#region src/components/fields/AddressListField/labels.ts
3058
+ /** Default English labels for {@link AddressListField}. */
3059
+ const DEFAULT_ADDRESS_LIST_FIELD_LABELS = {
3060
+ addAddresses: "Add addresses",
3061
+ addAddressCount: (count) => `Add ${count} address${count === 1 ? "" : "es"}`,
3062
+ invalidPrefix: "Invalid:",
3063
+ invalidMore: (extraCount) => `(+${extraCount} more)`,
3064
+ maxItemsReached: (maxItems) => `Maximum of ${maxItems} addresses reached.`,
3065
+ addressesAdded: (count) => `${count} address${count === 1 ? "" : "es"} added`,
3066
+ removeAddress: (index) => `Remove address ${index + 1}`,
3067
+ previewReadyToAdd: (count) => `${count} ready to add`,
3068
+ previewInvalid: (count) => `${count} invalid`,
3069
+ previewAlreadyListed: (count) => `${count} already listed`,
3070
+ previewDuplicateInPaste: (count) => `${count} duplicate in paste`,
3071
+ bulkNothingAdded: "No addresses were added. Check formatting and try again.",
3072
+ bulkAdded: (count) => `Added ${count} address${count === 1 ? "" : "es"}`,
3073
+ bulkInvalidFormats: (count) => `${count} invalid format${count === 1 ? "" : "s"}`,
3074
+ bulkAlreadyListed: (count) => `${count} already listed`,
3075
+ bulkDuplicatesInPaste: (count) => `${count} duplicate${count === 1 ? "" : "s"} in paste`
3076
+ };
3077
+ /** Merges {@link DEFAULT_ADDRESS_LIST_FIELD_LABELS} with optional overrides. */
3078
+ function resolveAddressListFieldLabels(overrides) {
3079
+ return {
3080
+ ...DEFAULT_ADDRESS_LIST_FIELD_LABELS,
3081
+ ...overrides
3082
+ };
3083
+ }
3084
+ /** Builds the inline helper preview shown while the user types in the draft textarea. */
3085
+ function buildAddressListPreviewSummary(classification, labels) {
3086
+ if (!classification) return null;
3087
+ const skipped = classification.invalid.length + classification.alreadyListed.length + classification.duplicatesInInput.length;
3088
+ if (classification.accepted.length === 0 && skipped === 0) return null;
3089
+ const parts = [];
3090
+ if (classification.accepted.length > 0) parts.push(labels.previewReadyToAdd(classification.accepted.length));
3091
+ if (classification.invalid.length > 0) parts.push(labels.previewInvalid(classification.invalid.length));
3092
+ if (classification.alreadyListed.length > 0) parts.push(labels.previewAlreadyListed(classification.alreadyListed.length));
3093
+ if (classification.duplicatesInInput.length > 0) parts.push(labels.previewDuplicateInPaste(classification.duplicatesInInput.length));
3094
+ return parts.join(" · ");
3095
+ }
3096
+ /** Formats post-add feedback after the user commits parsed addresses to the list. */
3097
+ function formatAddressBulkSummary(classification, addedCount, labels) {
3098
+ if (addedCount === 0 && classification.accepted.length === 0) {
3099
+ if (classification.invalid.length + classification.alreadyListed.length + classification.duplicatesInInput.length === 0) return null;
3100
+ return labels.bulkNothingAdded;
3101
+ }
3102
+ const parts = [];
3103
+ if (addedCount > 0) parts.push(labels.bulkAdded(addedCount));
3104
+ if (classification.invalid.length > 0) parts.push(labels.bulkInvalidFormats(classification.invalid.length));
3105
+ if (classification.alreadyListed.length > 0) parts.push(labels.bulkAlreadyListed(classification.alreadyListed.length));
3106
+ if (classification.duplicatesInInput.length > 0) parts.push(labels.bulkDuplicatesInPaste(classification.duplicatesInInput.length));
3107
+ if (parts.length === 0) return null;
3108
+ return parts.join(". ") + ".";
3109
+ }
3110
+
3111
+ //#endregion
3112
+ //#region src/components/fields/AddressListField/AddressListField.tsx
3113
+ /**
3114
+ * Multi-address list field for bulk paste workflows.
3115
+ *
3116
+ * Architecture flow:
3117
+ * 1. App or wizard steps hold the committed address list in local or form state
3118
+ * 2. AddressListField renders a draft textarea plus the committed list rows
3119
+ * 3. Parsing and classification run via `@openzeppelin/ui-utils` helpers
3120
+ * 4. Optional {@link AddressingCapability} validates candidates before add
3121
+ * 5. {@link AddressDisplay} renders each committed row with copy and explorer links
3122
+ *
3123
+ * The component includes:
3124
+ * - Delimiter-aware bulk paste (newlines, commas, semicolons)
3125
+ * - Live preview of accepted, invalid, duplicate, and already-listed candidates
3126
+ * - Optional `maxItems` cap with disabled input at the limit
3127
+ * - Removable list rows with accessible remove buttons
3128
+ * - Caller-controlled copy for placeholders and format hints
3129
+ * - Optional `labels` overrides for built-in button and status strings
3130
+ *
3131
+ * @example
3132
+ * ```tsx
3133
+ * const [addresses, setAddresses] = useState<string[]>([]);
3134
+ *
3135
+ * <AddressListField
3136
+ * value={addresses}
3137
+ * onChange={setAddresses}
3138
+ * placeholder="Paste addresses (one per line or comma-separated)"
3139
+ * formatHint="Each entry is validated before it is added."
3140
+ * addressing={capabilities}
3141
+ * />
3142
+ * ```
3143
+ */
3144
+ function AddressListField({ value, onChange, placeholder, formatHint, addressing, getExplorerUrl, label, helperText, maxItems, disabled = false, maxInvalidPreview = 3, className, labels: labelOverrides }) {
3145
+ const fieldId = (0, react.useId)();
3146
+ const labels = (0, react.useMemo)(() => resolveAddressListFieldLabels(labelOverrides), [labelOverrides]);
3147
+ const atLimit = maxItems != null && value.length >= maxItems;
3148
+ const inputDisabled = disabled || atLimit;
3149
+ const [feedback, setFeedback] = (0, react.useState)(null);
3150
+ const { control, reset, watch } = (0, react_hook_form.useForm)({
3151
+ defaultValues: { input: "" },
3152
+ mode: "onChange"
3153
+ });
3154
+ const rawInput = watch("input");
3155
+ const classification = (0, react.useMemo)(() => {
3156
+ if (!rawInput.trim()) return null;
3157
+ return (0, _openzeppelin_ui_utils.classifyAddressCandidates)((0, _openzeppelin_ui_utils.parseDelimitedAddressInput)(rawInput), value, addressing, maxItems);
3158
+ }, [
3159
+ rawInput,
3160
+ value,
3161
+ addressing,
3162
+ maxItems
3163
+ ]);
3164
+ const previewSummary = (0, react.useMemo)(() => buildAddressListPreviewSummary(classification, labels), [classification, labels]);
3165
+ const inlineHelperText = rawInput.trim() ? previewSummary ?? void 0 : feedback ?? void 0;
3166
+ const handleAdd = (0, react.useCallback)(() => {
3167
+ if (!classification || classification.accepted.length === 0 || atLimit) return;
3168
+ onChange([...value, ...classification.accepted]);
3169
+ reset({ input: "" });
3170
+ setFeedback(formatAddressBulkSummary(classification, classification.accepted.length, labels));
3171
+ }, [
3172
+ classification,
3173
+ atLimit,
3174
+ onChange,
3175
+ value,
3176
+ reset,
3177
+ labels
3178
+ ]);
3179
+ const handleRemove = (0, react.useCallback)((index) => {
3180
+ onChange(value.filter((_, currentIndex) => currentIndex !== index));
3181
+ setFeedback(null);
3182
+ }, [onChange, value]);
3183
+ const acceptedCount = classification?.accepted.length ?? 0;
3184
+ const addButtonLabel = acceptedCount > 0 ? labels.addAddressCount(acceptedCount) : labels.addAddresses;
3185
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3186
+ className: (0, _openzeppelin_ui_utils.cn)("space-y-3", className),
3187
+ children: [
3188
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3189
+ className: "space-y-1",
3190
+ children: [helperText ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3191
+ className: "text-xs text-muted-foreground",
3192
+ children: helperText
3193
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3194
+ className: "text-xs text-muted-foreground",
3195
+ children: formatHint
3196
+ })]
3197
+ }),
3198
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextAreaField, {
3199
+ id: `address-list-field-${fieldId}`,
3200
+ name: "input",
3201
+ label: label ?? "",
3202
+ placeholder,
3203
+ helperText: inlineHelperText,
3204
+ control,
3205
+ rows: 4,
3206
+ validation: { required: false },
3207
+ readOnly: inputDisabled
3208
+ }),
3209
+ classification && classification.invalid.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
3210
+ className: "text-xs text-destructive",
3211
+ children: [
3212
+ labels.invalidPrefix,
3213
+ " ",
3214
+ classification.invalid.slice(0, maxInvalidPreview).join(", "),
3215
+ classification.invalid.length > maxInvalidPreview ? ` ${labels.invalidMore(classification.invalid.length - maxInvalidPreview)}` : ""
3216
+ ]
3217
+ }),
3218
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
3219
+ type: "button",
3220
+ size: "sm",
3221
+ disabled: inputDisabled || acceptedCount === 0,
3222
+ onClick: () => handleAdd(),
3223
+ children: addButtonLabel
3224
+ }),
3225
+ atLimit && maxItems != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3226
+ className: "text-xs text-muted-foreground",
3227
+ children: labels.maxItemsReached(maxItems)
3228
+ }),
3229
+ value.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3230
+ className: "space-y-1",
3231
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3232
+ className: "text-xs text-muted-foreground",
3233
+ children: labels.addressesAdded(value.length)
3234
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3235
+ className: "max-h-44 space-y-1 overflow-y-auto rounded-md border border-border/70 p-1",
3236
+ children: value.map((address, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3237
+ className: "flex items-center justify-between rounded bg-muted p-2",
3238
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddressDisplay, {
3239
+ address,
3240
+ variant: "inline",
3241
+ truncateWhenLabeled: true,
3242
+ showCopyButton: true,
3243
+ explorerUrl: getExplorerUrl?.(address) ?? void 0
3244
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
3245
+ type: "button",
3246
+ variant: "ghost",
3247
+ size: "sm",
3248
+ className: "size-7 shrink-0 p-0 text-muted-foreground hover:text-destructive",
3249
+ onClick: () => handleRemove(index),
3250
+ disabled,
3251
+ "aria-label": labels.removeAddress(index),
3252
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "size-3.5" })
3253
+ })]
3254
+ }, `${address}-${index}`))
3255
+ })]
3256
+ })
3257
+ ]
3258
+ });
3259
+ }
3260
+
2955
3261
  //#endregion
2956
3262
  //#region src/components/fields/address-suggestion/address-suggestion-context.tsx
2957
3263
  /**
@@ -5744,105 +6050,6 @@ function SelectGroupedField({ id, label, placeholder = "Select an option", helpe
5744
6050
  }
5745
6051
  SelectGroupedField.displayName = "SelectGroupedField";
5746
6052
 
5747
- //#endregion
5748
- //#region src/components/fields/TextAreaField.tsx
5749
- /**
5750
- * Multi-line text input field component specifically designed for React Hook Form integration.
5751
- *
5752
- * Architecture flow:
5753
- * 1. Form schemas are generated from contract functions using adapters
5754
- * 2. TransactionForm renders the overall form structure with React Hook Form
5755
- * 3. DynamicFormField selects the appropriate field component based on field type
5756
- * 4. BaseField provides consistent layout and hook form integration
5757
- * 5. This component handles textarea-specific rendering and validation
5758
- *
5759
- * The component includes:
5760
- * - Integration with React Hook Form
5761
- * - Resizable multi-line text input
5762
- * - Character limit support
5763
- * - Customizable validation through adapter integration
5764
- * - Automatic error handling and reporting
5765
- * - Full accessibility support with ARIA attributes
5766
- * - Keyboard navigation with Escape to clear
5767
- */
5768
- function TextAreaField({ id, label, placeholder, helperText, control, name, width = "full", validation, rows = 4, maxLength, validateTextArea }) {
5769
- const isRequired = !!validation?.required;
5770
- const errorId = `${id}-error`;
5771
- const descriptionId = `${id}-description`;
5772
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5773
- className: `flex flex-col gap-2 ${width === "full" ? "w-full" : width === "half" ? "w-1/2" : "w-1/3"}`,
5774
- children: [label && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Label, {
5775
- htmlFor: id,
5776
- children: [
5777
- label,
5778
- " ",
5779
- isRequired && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5780
- className: "text-destructive",
5781
- children: "*"
5782
- })
5783
- ]
5784
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_hook_form.Controller, {
5785
- control,
5786
- name,
5787
- rules: { validate: (value) => {
5788
- if (value === void 0 || value === null || value === "") return validation?.required ? "This field is required" : true;
5789
- if (validateTextArea && value) {
5790
- const validation$1 = validateTextArea(value);
5791
- if (validation$1 !== true && typeof validation$1 === "string") return validation$1;
5792
- }
5793
- if (maxLength && typeof value === "string" && value.length > maxLength) return `Maximum length is ${maxLength} characters`;
5794
- return true;
5795
- } },
5796
- render: ({ field, fieldState: { error, isTouched } }) => {
5797
- const hasError = !!error;
5798
- const shouldShowError = hasError && isTouched;
5799
- const validationClasses = require_ErrorMessage.getValidationStateClasses(error, isTouched);
5800
- const accessibilityProps = getAccessibilityProps({
5801
- id,
5802
- hasError,
5803
- isRequired,
5804
- hasHelperText: !!helperText
5805
- });
5806
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5807
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Textarea, {
5808
- ...field,
5809
- id,
5810
- placeholder,
5811
- rows,
5812
- maxLength,
5813
- className: validationClasses,
5814
- value: field.value ?? "",
5815
- ...accessibilityProps,
5816
- "aria-describedby": `${helperText ? descriptionId : ""} ${hasError ? errorId : ""}`,
5817
- onKeyDown: handleEscapeKey((value) => {
5818
- if (typeof field.onChange === "function") field.onChange(value);
5819
- }, field.value)
5820
- }),
5821
- maxLength && typeof field.value === "string" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5822
- className: "text-muted-foreground text-right text-xs",
5823
- children: [
5824
- field.value.length,
5825
- "/",
5826
- maxLength
5827
- ]
5828
- }),
5829
- helperText && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5830
- id: descriptionId,
5831
- className: "text-muted-foreground text-sm",
5832
- children: helperText
5833
- }),
5834
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ErrorMessage.ErrorMessage, {
5835
- error,
5836
- id: errorId,
5837
- message: shouldShowError ? error?.message : void 0
5838
- })
5839
- ] });
5840
- }
5841
- })]
5842
- });
5843
- }
5844
- TextAreaField.displayName = "TextAreaField";
5845
-
5846
6053
  //#endregion
5847
6054
  //#region src/components/fields/TextField.tsx
5848
6055
  /**
@@ -6441,6 +6648,7 @@ exports.AccordionTrigger = AccordionTrigger;
6441
6648
  exports.AddressDisplay = AddressDisplay;
6442
6649
  exports.AddressField = AddressField;
6443
6650
  exports.AddressLabelProvider = AddressLabelProvider;
6651
+ exports.AddressListField = AddressListField;
6444
6652
  exports.AddressSuggestionProvider = AddressSuggestionProvider;
6445
6653
  exports.Alert = Alert;
6446
6654
  exports.AlertDescription = AlertDescription;
@@ -6462,6 +6670,7 @@ exports.CardFooter = CardFooter;
6462
6670
  exports.CardHeader = CardHeader;
6463
6671
  exports.CardTitle = CardTitle;
6464
6672
  exports.Checkbox = Checkbox;
6673
+ exports.DEFAULT_ADDRESS_LIST_FIELD_LABELS = DEFAULT_ADDRESS_LIST_FIELD_LABELS;
6465
6674
  exports.DateRangePicker = DateRangePicker;
6466
6675
  exports.DateTimeField = DateTimeField;
6467
6676
  exports.Dialog = Dialog;
@@ -6567,10 +6776,12 @@ exports.ViewContractStateButton = ViewContractStateButton;
6567
6776
  exports.WizardLayout = WizardLayout;
6568
6777
  exports.WizardNavigation = WizardNavigation;
6569
6778
  exports.WizardStepper = WizardStepper;
6779
+ exports.buildAddressListPreviewSummary = buildAddressListPreviewSummary;
6570
6780
  exports.buttonVariants = buttonVariants;
6571
6781
  exports.computeChildTouched = computeChildTouched;
6572
6782
  exports.createFocusManager = createFocusManager;
6573
6783
  exports.createValidationResult = require_ErrorMessage.createValidationResult;
6784
+ exports.formatAddressBulkSummary = formatAddressBulkSummary;
6574
6785
  exports.formatValidationError = require_ErrorMessage.formatValidationError;
6575
6786
  exports.getAccessibilityProps = getAccessibilityProps;
6576
6787
  exports.getDescribedById = getDescribedById;
@@ -6584,6 +6795,7 @@ exports.handleToggleKeys = handleToggleKeys;
6584
6795
  exports.handleValidationError = require_ErrorMessage.handleValidationError;
6585
6796
  exports.hasFieldError = require_ErrorMessage.hasFieldError;
6586
6797
  exports.isDuplicateMapKey = require_ErrorMessage.isDuplicateMapKey;
6798
+ exports.resolveAddressListFieldLabels = resolveAddressListFieldLabels;
6587
6799
  exports.useAddressLabel = useAddressLabel;
6588
6800
  exports.useAddressSuggestions = useAddressSuggestions;
6589
6801
  exports.useDuplicateKeyIndexes = useDuplicateKeyIndexes;