@openzeppelin/ui-components 3.1.0 → 3.2.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 +252 -107
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -46
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +34 -46
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +253 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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.
|
|
41
|
+
const VERSION = "3.2.0";
|
|
42
42
|
|
|
43
43
|
//#endregion
|
|
44
44
|
//#region src/components/ui/accordion.tsx
|
|
@@ -3057,6 +3057,10 @@ TextAreaField.displayName = "TextAreaField";
|
|
|
3057
3057
|
//#region src/components/fields/AddressListField/labels.ts
|
|
3058
3058
|
/** Default English labels for {@link AddressListField}. */
|
|
3059
3059
|
const DEFAULT_ADDRESS_LIST_FIELD_LABELS = {
|
|
3060
|
+
addSingleAddress: "Add",
|
|
3061
|
+
invalidSingleAddress: "Enter a valid address",
|
|
3062
|
+
enableBulkEntry: "Bulk paste",
|
|
3063
|
+
enableSingleEntry: "Single entry",
|
|
3060
3064
|
addAddresses: "Add addresses",
|
|
3061
3065
|
addAddressCount: (count) => `Add ${count} address${count === 1 ? "" : "es"}`,
|
|
3062
3066
|
invalidPrefix: "Invalid:",
|
|
@@ -3109,41 +3113,9 @@ function formatAddressBulkSummary(classification, addedCount, labels) {
|
|
|
3109
3113
|
}
|
|
3110
3114
|
|
|
3111
3115
|
//#endregion
|
|
3112
|
-
//#region src/components/fields/AddressListField/
|
|
3113
|
-
/**
|
|
3114
|
-
|
|
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]);
|
|
3116
|
+
//#region src/components/fields/AddressListField/AddressListBulkEntry.tsx
|
|
3117
|
+
/** Bulk paste entry — info callout, textarea, and add action in a compact stack. */
|
|
3118
|
+
function AddressListBulkEntry({ fieldId, value, onAdd, placeholder, formatHint, addressing, maxItems, disabled = false, maxInvalidPreview = 3, labels, modeToggle }) {
|
|
3147
3119
|
const atLimit = maxItems != null && value.length >= maxItems;
|
|
3148
3120
|
const inputDisabled = disabled || atLimit;
|
|
3149
3121
|
const [feedback, setFeedback] = (0, react.useState)(null);
|
|
@@ -3162,97 +3134,270 @@ function AddressListField({ value, onChange, placeholder, formatHint, addressing
|
|
|
3162
3134
|
maxItems
|
|
3163
3135
|
]);
|
|
3164
3136
|
const previewSummary = (0, react.useMemo)(() => buildAddressListPreviewSummary(classification, labels), [classification, labels]);
|
|
3165
|
-
const
|
|
3137
|
+
const statusMessage = rawInput.trim() ? previewSummary ?? void 0 : feedback ?? void 0;
|
|
3166
3138
|
const handleAdd = (0, react.useCallback)(() => {
|
|
3167
3139
|
if (!classification || classification.accepted.length === 0 || atLimit) return;
|
|
3168
|
-
|
|
3140
|
+
onAdd(classification.accepted);
|
|
3169
3141
|
reset({ input: "" });
|
|
3170
3142
|
setFeedback(formatAddressBulkSummary(classification, classification.accepted.length, labels));
|
|
3171
3143
|
}, [
|
|
3172
3144
|
classification,
|
|
3173
3145
|
atLimit,
|
|
3174
|
-
|
|
3175
|
-
value,
|
|
3146
|
+
onAdd,
|
|
3176
3147
|
reset,
|
|
3177
3148
|
labels
|
|
3178
3149
|
]);
|
|
3179
|
-
const handleRemove = (0, react.useCallback)((index) => {
|
|
3180
|
-
onChange(value.filter((_, currentIndex) => currentIndex !== index));
|
|
3181
|
-
setFeedback(null);
|
|
3182
|
-
}, [onChange, value]);
|
|
3183
3150
|
const acceptedCount = classification?.accepted.length ?? 0;
|
|
3184
3151
|
const addButtonLabel = acceptedCount > 0 ? labels.addAddressCount(acceptedCount) : labels.addAddresses;
|
|
3185
3152
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3186
|
-
className:
|
|
3153
|
+
className: "space-y-3",
|
|
3187
3154
|
children: [
|
|
3188
3155
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3189
|
-
className: "
|
|
3190
|
-
children: [
|
|
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",
|
|
3156
|
+
className: "flex items-start gap-2 rounded-lg border border-border/70 bg-muted/30 px-3 py-2.5",
|
|
3157
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Info, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3158
|
+
className: "text-xs leading-relaxed text-muted-foreground",
|
|
3195
3159
|
children: formatHint
|
|
3196
3160
|
})]
|
|
3197
3161
|
}),
|
|
3198
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3162
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3163
|
+
className: "relative",
|
|
3164
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextAreaField, {
|
|
3165
|
+
id: `address-list-bulk-${fieldId}`,
|
|
3166
|
+
name: "input",
|
|
3167
|
+
label: "",
|
|
3168
|
+
placeholder,
|
|
3169
|
+
helperText: statusMessage,
|
|
3170
|
+
control,
|
|
3171
|
+
rows: 4,
|
|
3172
|
+
validation: { required: false },
|
|
3173
|
+
readOnly: inputDisabled
|
|
3174
|
+
})
|
|
3175
|
+
}), modeToggle ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3176
|
+
className: "flex justify-end pr-2",
|
|
3177
|
+
children: modeToggle
|
|
3178
|
+
}) : null] }),
|
|
3179
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3180
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
3181
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3182
|
+
className: "min-w-0 flex-1",
|
|
3183
|
+
children: [classification && classification.invalid.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
3184
|
+
className: "text-xs text-destructive",
|
|
3185
|
+
children: [
|
|
3186
|
+
labels.invalidPrefix,
|
|
3187
|
+
" ",
|
|
3188
|
+
classification.invalid.slice(0, maxInvalidPreview).join(", "),
|
|
3189
|
+
classification.invalid.length > maxInvalidPreview ? ` ${labels.invalidMore(classification.invalid.length - maxInvalidPreview)}` : ""
|
|
3190
|
+
]
|
|
3191
|
+
}) : null, atLimit && maxItems != null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3192
|
+
className: "text-xs text-muted-foreground",
|
|
3193
|
+
children: labels.maxItemsReached(maxItems)
|
|
3194
|
+
}) : null]
|
|
3195
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
|
|
3196
|
+
type: "button",
|
|
3197
|
+
size: "sm",
|
|
3198
|
+
className: "shrink-0",
|
|
3199
|
+
disabled: inputDisabled || acceptedCount === 0,
|
|
3200
|
+
onClick: () => handleAdd(),
|
|
3201
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "mr-1 size-4" }), addButtonLabel]
|
|
3202
|
+
})]
|
|
3203
|
+
})
|
|
3204
|
+
]
|
|
3205
|
+
});
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
//#endregion
|
|
3209
|
+
//#region src/components/fields/AddressListField/AddressListEntries.tsx
|
|
3210
|
+
/** Renders committed addresses with remove actions. Shared by single and bulk entry modes. */
|
|
3211
|
+
function AddressListEntries({ value, getExplorerUrl, disabled = false, labels, onRemove }) {
|
|
3212
|
+
if (value.length === 0) return null;
|
|
3213
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3214
|
+
className: "space-y-1",
|
|
3215
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3216
|
+
className: "text-xs text-muted-foreground",
|
|
3217
|
+
children: labels.addressesAdded(value.length)
|
|
3218
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3219
|
+
className: "max-h-44 space-y-1 overflow-y-auto rounded-md border border-border/70 p-1",
|
|
3220
|
+
children: value.map((address, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3221
|
+
className: "flex items-center justify-between rounded bg-muted p-2",
|
|
3222
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddressDisplay, {
|
|
3223
|
+
address,
|
|
3224
|
+
variant: "inline",
|
|
3225
|
+
truncateWhenLabeled: true,
|
|
3226
|
+
showCopyButton: true,
|
|
3227
|
+
explorerUrl: getExplorerUrl?.(address) ?? void 0
|
|
3228
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
3229
|
+
type: "button",
|
|
3230
|
+
variant: "ghost",
|
|
3231
|
+
size: "sm",
|
|
3232
|
+
className: "size-7 shrink-0 p-0 text-muted-foreground hover:text-destructive",
|
|
3233
|
+
onClick: () => onRemove(index),
|
|
3234
|
+
disabled,
|
|
3235
|
+
"aria-label": labels.removeAddress(index),
|
|
3236
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "size-3.5" })
|
|
3237
|
+
})]
|
|
3238
|
+
}, `${address}-${index}`))
|
|
3239
|
+
})]
|
|
3240
|
+
});
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
//#endregion
|
|
3244
|
+
//#region src/components/fields/AddressListField/AddressListSingleEntry.tsx
|
|
3245
|
+
/** Single-address entry — inline {@link AddressField} with an Add button (address-book aware). */
|
|
3246
|
+
function AddressListSingleEntry({ fieldId, value, onAdd, placeholder, addressing, maxItems, disabled = false, labels, modeToggle }) {
|
|
3247
|
+
const atLimit = maxItems != null && value.length >= maxItems;
|
|
3248
|
+
const inputDisabled = disabled || atLimit;
|
|
3249
|
+
const { control, reset, getValues, handleSubmit } = (0, react_hook_form.useForm)({
|
|
3250
|
+
defaultValues: { draft: "" },
|
|
3251
|
+
mode: "onChange"
|
|
3252
|
+
});
|
|
3253
|
+
const trimmedDraft = ((0, react_hook_form.useWatch)({
|
|
3254
|
+
control,
|
|
3255
|
+
name: "draft"
|
|
3256
|
+
}) ?? "").trim();
|
|
3257
|
+
const validationState = (0, react.useMemo)(() => {
|
|
3258
|
+
if (!trimmedDraft) return {
|
|
3259
|
+
canAdd: false,
|
|
3260
|
+
showInvalid: false
|
|
3261
|
+
};
|
|
3262
|
+
if (value.includes(trimmedDraft)) return {
|
|
3263
|
+
canAdd: false,
|
|
3264
|
+
showInvalid: false
|
|
3265
|
+
};
|
|
3266
|
+
if (atLimit) return {
|
|
3267
|
+
canAdd: false,
|
|
3268
|
+
showInvalid: false
|
|
3269
|
+
};
|
|
3270
|
+
if (addressing && !addressing.isValidAddress(trimmedDraft)) return {
|
|
3271
|
+
canAdd: false,
|
|
3272
|
+
showInvalid: true
|
|
3273
|
+
};
|
|
3274
|
+
return {
|
|
3275
|
+
canAdd: true,
|
|
3276
|
+
showInvalid: false
|
|
3277
|
+
};
|
|
3278
|
+
}, [
|
|
3279
|
+
trimmedDraft,
|
|
3280
|
+
value,
|
|
3281
|
+
atLimit,
|
|
3282
|
+
addressing
|
|
3283
|
+
]);
|
|
3284
|
+
const submitAdd = (0, react.useCallback)(() => {
|
|
3285
|
+
if (!validationState.canAdd) return;
|
|
3286
|
+
onAdd(getValues("draft").trim());
|
|
3287
|
+
reset({ draft: "" });
|
|
3288
|
+
}, [
|
|
3289
|
+
validationState.canAdd,
|
|
3290
|
+
onAdd,
|
|
3291
|
+
getValues,
|
|
3292
|
+
reset
|
|
3293
|
+
]);
|
|
3294
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3295
|
+
className: "space-y-1",
|
|
3296
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3297
|
+
className: "flex items-start gap-2",
|
|
3298
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3299
|
+
className: "min-w-0 flex-1",
|
|
3300
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddressField, {
|
|
3301
|
+
id: `address-list-single-${fieldId}`,
|
|
3302
|
+
name: "draft",
|
|
3303
|
+
label: "",
|
|
3304
|
+
placeholder,
|
|
3305
|
+
helperText: validationState.showInvalid ? labels.invalidSingleAddress : void 0,
|
|
3306
|
+
control,
|
|
3307
|
+
addressing,
|
|
3308
|
+
validation: { required: false },
|
|
3309
|
+
readOnly: inputDisabled
|
|
3310
|
+
}), modeToggle ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3311
|
+
className: "-mt-px flex justify-end pr-2",
|
|
3312
|
+
children: modeToggle
|
|
3313
|
+
}) : null]
|
|
3314
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
|
|
3219
3315
|
type: "button",
|
|
3220
|
-
|
|
3221
|
-
disabled: inputDisabled ||
|
|
3222
|
-
onClick: ()
|
|
3223
|
-
children:
|
|
3224
|
-
})
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3316
|
+
className: "h-10 shrink-0",
|
|
3317
|
+
disabled: inputDisabled || !validationState.canAdd,
|
|
3318
|
+
onClick: handleSubmit(submitAdd),
|
|
3319
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "mr-1 size-4" }), labels.addSingleAddress]
|
|
3320
|
+
})]
|
|
3321
|
+
}), atLimit && maxItems != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3322
|
+
className: "text-xs text-muted-foreground",
|
|
3323
|
+
children: labels.maxItemsReached(maxItems)
|
|
3324
|
+
})]
|
|
3325
|
+
});
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
//#endregion
|
|
3329
|
+
//#region src/components/fields/AddressListField/AddressListField.tsx
|
|
3330
|
+
/**
|
|
3331
|
+
* Multi-address list field with single-entry default and optional bulk paste.
|
|
3332
|
+
*/
|
|
3333
|
+
function AddressListField({ value, onChange, placeholder, bulkPlaceholder, formatHint, addressing, getExplorerUrl, label, helperText, maxItems, disabled = false, maxInvalidPreview = 3, className, defaultEntryMode = "single", allowModeToggle = true, labels: labelOverrides }) {
|
|
3334
|
+
const fieldId = (0, react.useId)();
|
|
3335
|
+
const labels = (0, react.useMemo)(() => resolveAddressListFieldLabels(labelOverrides), [labelOverrides]);
|
|
3336
|
+
const [entryMode, setEntryMode] = (0, react.useState)(defaultEntryMode);
|
|
3337
|
+
const resolvedBulkPlaceholder = bulkPlaceholder ?? placeholder;
|
|
3338
|
+
const handleRemove = (0, react.useCallback)((index) => {
|
|
3339
|
+
onChange(value.filter((_, currentIndex) => currentIndex !== index));
|
|
3340
|
+
}, [onChange, value]);
|
|
3341
|
+
const handleAddSingle = (0, react.useCallback)((address) => {
|
|
3342
|
+
onChange([...value, address]);
|
|
3343
|
+
}, [onChange, value]);
|
|
3344
|
+
const handleAddBulk = (0, react.useCallback)((addresses) => {
|
|
3345
|
+
onChange([...value, ...addresses]);
|
|
3346
|
+
}, [onChange, value]);
|
|
3347
|
+
const switchToBulk = (0, react.useCallback)(() => setEntryMode("bulk"), []);
|
|
3348
|
+
const switchToSingle = (0, react.useCallback)(() => setEntryMode("single"), []);
|
|
3349
|
+
const toggleClassName = "inline-flex items-center gap-1 rounded-b-md rounded-t-none border border-t-0 border-input bg-muted/40 px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground";
|
|
3350
|
+
const modeToggle = !allowModeToggle ? void 0 : entryMode === "single" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3351
|
+
type: "button",
|
|
3352
|
+
onClick: switchToBulk,
|
|
3353
|
+
className: toggleClassName,
|
|
3354
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ClipboardPaste, { className: "size-3" }), labels.enableBulkEntry]
|
|
3355
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3356
|
+
type: "button",
|
|
3357
|
+
onClick: switchToSingle,
|
|
3358
|
+
className: toggleClassName,
|
|
3359
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PencilLine, { className: "size-3" }), labels.enableSingleEntry]
|
|
3360
|
+
});
|
|
3361
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3362
|
+
className: (0, _openzeppelin_ui_utils.cn)("space-y-3", className),
|
|
3363
|
+
children: [
|
|
3364
|
+
label ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
3365
|
+
className: "text-sm font-medium leading-none",
|
|
3366
|
+
children: label
|
|
3367
|
+
}) : null,
|
|
3368
|
+
helperText && entryMode === "single" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3369
|
+
className: "text-sm leading-relaxed text-muted-foreground",
|
|
3370
|
+
children: helperText
|
|
3371
|
+
}) : null,
|
|
3372
|
+
entryMode === "single" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddressListSingleEntry, {
|
|
3373
|
+
fieldId,
|
|
3374
|
+
value,
|
|
3375
|
+
onAdd: handleAddSingle,
|
|
3376
|
+
placeholder,
|
|
3377
|
+
addressing,
|
|
3378
|
+
maxItems,
|
|
3379
|
+
disabled,
|
|
3380
|
+
labels,
|
|
3381
|
+
modeToggle
|
|
3382
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddressListBulkEntry, {
|
|
3383
|
+
fieldId,
|
|
3384
|
+
value,
|
|
3385
|
+
onAdd: handleAddBulk,
|
|
3386
|
+
placeholder: resolvedBulkPlaceholder,
|
|
3387
|
+
formatHint,
|
|
3388
|
+
addressing,
|
|
3389
|
+
maxItems,
|
|
3390
|
+
disabled,
|
|
3391
|
+
maxInvalidPreview,
|
|
3392
|
+
labels,
|
|
3393
|
+
modeToggle
|
|
3228
3394
|
}),
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
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
|
-
})]
|
|
3395
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddressListEntries, {
|
|
3396
|
+
value,
|
|
3397
|
+
getExplorerUrl,
|
|
3398
|
+
disabled,
|
|
3399
|
+
labels,
|
|
3400
|
+
onRemove: handleRemove
|
|
3256
3401
|
})
|
|
3257
3402
|
]
|
|
3258
3403
|
});
|