@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 +312 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +126 -8
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +120 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +310 -103
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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
|
|
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;
|