@openzeppelin/ui-components 1.3.0 → 1.5.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.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { a as getValidationStateClasses, c as isDuplicateMapKey, d as INTEGER_HTML_PATTERN, f as INTEGER_INPUT_PATTERN, i as getErrorMessage, l as validateField, n as createValidationResult, o as handleValidationError, p as INTEGER_PATTERN, r as formatValidationError, s as hasFieldError, t as ErrorMessage, u as validateMapEntries } from "./ErrorMessage-BqOEJm84.mjs";
2
2
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
3
3
  import { cva } from "class-variance-authority";
4
- import { AlertCircle, Calendar as Calendar$1, Check, CheckCircle, CheckCircle2, CheckIcon, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Circle, CloudOff, Copy, DollarSign, ExternalLink as ExternalLink$1, ExternalLinkIcon, Eye, EyeOff, File, FileText, GripVertical, Hash, Info, Loader2, Menu, Network, Plus, Search, Settings, Timer, Upload, X } from "lucide-react";
4
+ import { AlertCircle, Calendar as Calendar$1, Check, CheckCircle, CheckCircle2, CheckIcon, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Circle, CloudOff, Copy, DollarSign, ExternalLink as ExternalLink$1, ExternalLinkIcon, Eye, EyeOff, File, FileText, GripVertical, Hash, Info, Loader2, Menu, MoreHorizontal, Network, Pencil, Plus, Search, Settings, Timer, Upload, X } from "lucide-react";
5
5
  import * as React$1 from "react";
6
- import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
6
+ import React, { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
7
7
  import { cn, getDefaultValueForType, getInvalidUrlMessage, getServiceDisplayName, isValidUrl, truncateMiddle, validateBytesSimple } from "@openzeppelin/ui-utils";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Slot, Slottable } from "@radix-ui/react-slot";
@@ -103,11 +103,58 @@ const AccordionContent = React$1.forwardRef(({ className, children, variant: var
103
103
  AccordionContent.displayName = "AccordionContent";
104
104
 
105
105
  //#endregion
106
- //#region src/components/ui/address-display.tsx
107
- /** Displays a blockchain address with optional truncation, copy button, and explorer link. */
108
- function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4, showCopyButton = false, showCopyButtonOnHover = false, explorerUrl, className, ...props }) {
106
+ //#region src/components/ui/address-display/context.ts
107
+ /**
108
+ * @internal Shared context instance consumed by both AddressDisplay and
109
+ * AddressLabelProvider. Kept in its own file so component files export
110
+ * only components (required by React Fast Refresh).
111
+ */
112
+ const AddressLabelContext = createContext(null);
113
+
114
+ //#endregion
115
+ //#region src/components/ui/address-display/address-display.tsx
116
+ /**
117
+ * Displays a blockchain address with optional truncation, copy button,
118
+ * explorer link, and human-readable label.
119
+ *
120
+ * Labels are resolved in priority order:
121
+ * 1. Explicit `label` prop
122
+ * 2. `AddressLabelContext` resolver (via `AddressLabelProvider`)
123
+ * 3. No label (renders address only, identical to previous behavior)
124
+ *
125
+ * Pass `disableLabel` to suppress context-based resolution (e.g. when the
126
+ * surrounding UI already shows a name, such as a contract selector).
127
+ *
128
+ * @example
129
+ * ```tsx
130
+ * // Basic usage (unchanged)
131
+ * <AddressDisplay address="0x742d35Cc..." showCopyButton />
132
+ *
133
+ * // Explicit label
134
+ * <AddressDisplay address="0x742d35Cc..." label="Treasury" />
135
+ *
136
+ * // Auto-resolved via context (no changes needed at call site)
137
+ * <AddressLabelProvider resolveLabel={myResolver}>
138
+ * <AddressDisplay address="0x742d35Cc..." />
139
+ * </AddressLabelProvider>
140
+ *
141
+ * // Suppress label resolution for a specific instance
142
+ * <AddressDisplay address="0x742d35Cc..." disableLabel />
143
+ * ```
144
+ */
145
+ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4, showCopyButton = false, showCopyButtonOnHover = false, explorerUrl, label: labelProp, onLabelEdit: onLabelEditProp, networkId, disableLabel = false, className, ...props }) {
109
146
  const [copied, setCopied] = React$1.useState(false);
110
147
  const copyTimeoutRef = React$1.useRef(null);
148
+ const resolver = React$1.useContext(AddressLabelContext);
149
+ const resolvedLabel = disableLabel ? void 0 : labelProp ?? resolver?.resolveLabel(address, networkId);
150
+ const contextEditHandler = React$1.useCallback(() => {
151
+ resolver?.onEditLabel?.(address, networkId);
152
+ }, [
153
+ resolver,
154
+ address,
155
+ networkId
156
+ ]);
157
+ const editHandler = disableLabel ? void 0 : onLabelEditProp ?? (resolver?.onEditLabel ? contextEditHandler : void 0);
111
158
  const displayAddress = truncate ? truncateMiddle(address, startChars, endChars) : address;
112
159
  const handleCopy = (e) => {
113
160
  e.stopPropagation();
@@ -124,11 +171,7 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
124
171
  if (copyTimeoutRef.current) window.clearTimeout(copyTimeoutRef.current);
125
172
  };
126
173
  }, []);
127
- const addressContent = /* @__PURE__ */ jsxs(Fragment, { children: [
128
- /* @__PURE__ */ jsx("span", {
129
- className: cn("truncate", truncate ? "" : "break-all"),
130
- children: displayAddress
131
- }),
174
+ const actionButtons = /* @__PURE__ */ jsxs(Fragment, { children: [
132
175
  showCopyButton && /* @__PURE__ */ jsx("button", {
133
176
  type: "button",
134
177
  onClick: handleCopy,
@@ -143,15 +186,136 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
143
186
  className: "ml-1.5 shrink-0 text-slate-500 transition-colors hover:text-slate-700",
144
187
  "aria-label": "View in explorer",
145
188
  children: /* @__PURE__ */ jsx(ExternalLink$1, { className: "h-3.5 w-3.5" })
189
+ }),
190
+ editHandler && /* @__PURE__ */ jsx("button", {
191
+ type: "button",
192
+ onClick: (e) => {
193
+ e.stopPropagation();
194
+ editHandler();
195
+ },
196
+ className: "ml-0 w-0 shrink-0 overflow-hidden text-slate-500 opacity-0 transition-all duration-150 hover:text-slate-700 group-hover:ml-1.5 group-hover:w-3.5 group-hover:opacity-100 focus:ml-1.5 focus:w-3.5 focus:opacity-100",
197
+ "aria-label": "Edit label",
198
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
146
199
  })
147
200
  ] });
148
- return /* @__PURE__ */ jsx("div", {
201
+ if (resolvedLabel) return /* @__PURE__ */ jsxs("div", {
202
+ className: cn("group inline-flex max-w-full flex-col rounded-md bg-slate-100 px-2 py-1", "text-xs text-slate-700", className),
203
+ ...props,
204
+ children: [/* @__PURE__ */ jsx("span", {
205
+ className: "truncate font-sans font-medium text-slate-900 leading-snug",
206
+ children: resolvedLabel
207
+ }), /* @__PURE__ */ jsxs("div", {
208
+ className: "flex items-center font-mono text-[10px] text-slate-400 leading-snug",
209
+ children: [/* @__PURE__ */ jsx("span", {
210
+ className: cn("truncate", truncate ? "" : "break-all"),
211
+ children: displayAddress
212
+ }), actionButtons]
213
+ })]
214
+ });
215
+ return /* @__PURE__ */ jsxs("div", {
149
216
  className: cn("group inline-flex max-w-full items-center rounded-md bg-slate-100 px-2 py-1", "text-xs font-mono text-slate-700", className),
150
217
  ...props,
151
- children: addressContent
218
+ children: [/* @__PURE__ */ jsx("span", {
219
+ className: cn("truncate", truncate ? "" : "break-all"),
220
+ children: displayAddress
221
+ }), actionButtons]
222
+ });
223
+ }
224
+
225
+ //#endregion
226
+ //#region src/components/ui/address-display/address-label-context.tsx
227
+ /**
228
+ * Address Label Context
229
+ *
230
+ * Provides a React context for resolving human-readable labels for blockchain
231
+ * addresses. When an `AddressLabelProvider` is mounted, every `AddressDisplay`
232
+ * in the subtree automatically resolves and renders labels without any
233
+ * call-site changes.
234
+ *
235
+ * @example
236
+ * ```tsx
237
+ * import { AddressLabelProvider } from '@openzeppelin/ui-components';
238
+ *
239
+ * function App() {
240
+ * const resolver = useAliasLabelResolver(db);
241
+ * return (
242
+ * <AddressLabelProvider {...resolver}>
243
+ * <MyApp />
244
+ * </AddressLabelProvider>
245
+ * );
246
+ * }
247
+ * ```
248
+ */
249
+ /**
250
+ * Provides address label resolution to all `AddressDisplay` instances in the
251
+ * subtree. Wrap your application (or a subsection) with this provider and
252
+ * supply a `resolveLabel` function.
253
+ *
254
+ * @param props - Resolver functions and children
255
+ *
256
+ * @example
257
+ * ```tsx
258
+ * <AddressLabelProvider
259
+ * resolveLabel={(addr) => addressBook.get(addr)}
260
+ * onEditLabel={(addr) => openEditor(addr)}
261
+ * >
262
+ * <App />
263
+ * </AddressLabelProvider>
264
+ * ```
265
+ */
266
+ function AddressLabelProvider({ children, resolveLabel, onEditLabel }) {
267
+ const value = React$1.useMemo(() => ({
268
+ resolveLabel,
269
+ onEditLabel
270
+ }), [resolveLabel, onEditLabel]);
271
+ return /* @__PURE__ */ jsx(AddressLabelContext.Provider, {
272
+ value,
273
+ children
152
274
  });
153
275
  }
154
276
 
277
+ //#endregion
278
+ //#region src/components/ui/address-display/use-address-label.ts
279
+ /**
280
+ * Convenience hook for resolving an address label from the nearest
281
+ * `AddressLabelProvider`.
282
+ *
283
+ * Kept in its own file so that `address-label-context.tsx` exports only
284
+ * components (required by React Fast Refresh).
285
+ */
286
+ /**
287
+ * Convenience hook that resolves a label for a specific address using the
288
+ * nearest `AddressLabelProvider`. Returns `undefined` values when no provider
289
+ * is mounted.
290
+ *
291
+ * @param address - The blockchain address to resolve
292
+ * @param networkId - Optional network identifier for network-specific aliases
293
+ * @returns Resolved label and edit handler for the address
294
+ *
295
+ * @example
296
+ * ```tsx
297
+ * function MyAddress({ address }: { address: string }) {
298
+ * const { label, onEdit } = useAddressLabel(address, 'ethereum-mainnet');
299
+ * return <span>{label ?? address}</span>;
300
+ * }
301
+ * ```
302
+ */
303
+ function useAddressLabel(address, networkId) {
304
+ const resolver = React$1.useContext(AddressLabelContext);
305
+ const label = resolver?.resolveLabel(address, networkId);
306
+ const onEdit = React$1.useCallback(() => {
307
+ resolver?.onEditLabel?.(address, networkId);
308
+ }, [
309
+ resolver,
310
+ address,
311
+ networkId
312
+ ]);
313
+ return {
314
+ label,
315
+ onEdit: resolver?.onEditLabel ? onEdit : void 0
316
+ };
317
+ }
318
+
155
319
  //#endregion
156
320
  //#region src/components/ui/alert.tsx
157
321
  const alertVariants = cva("relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", {
@@ -1085,10 +1249,15 @@ function NetworkIcon({ network, className, size = 16, variant = "branded" }) {
1085
1249
 
1086
1250
  //#endregion
1087
1251
  //#region src/components/ui/network-selector.tsx
1088
- /** Searchable dropdown selector for blockchain networks with optional grouping. */
1089
- function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetworkLabel, getNetworkIcon, getNetworkType, getNetworkId, groupByEcosystem = false, getEcosystem, filterNetwork, className, placeholder = "Select Network" }) {
1252
+ /** Searchable dropdown selector for blockchain networks with optional grouping and multi-select. */
1253
+ function NetworkSelector({ networks, getNetworkLabel, getNetworkIcon, getNetworkType, getNetworkId, groupByEcosystem = false, getEcosystem, filterNetwork, className, placeholder = "Select Network", ...modeProps }) {
1090
1254
  const [open, setOpen] = React$1.useState(false);
1091
1255
  const [searchQuery, setSearchQuery] = React$1.useState("");
1256
+ const isMultiple = modeProps.multiple === true;
1257
+ const selectedNetworkIds = isMultiple ? modeProps.selectedNetworkIds : void 0;
1258
+ const onSelectionChange = isMultiple ? modeProps.onSelectionChange : void 0;
1259
+ const selectedNetwork = !isMultiple ? modeProps.selectedNetwork : void 0;
1260
+ const onSelectNetwork = !isMultiple ? modeProps.onSelectNetwork : void 0;
1092
1261
  const filteredNetworks = React$1.useMemo(() => {
1093
1262
  if (!searchQuery) return networks;
1094
1263
  if (filterNetwork) return networks.filter((n) => filterNetwork(n, searchQuery));
@@ -1112,34 +1281,79 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1112
1281
  groupByEcosystem,
1113
1282
  getEcosystem
1114
1283
  ]);
1284
+ const isSelected = React$1.useCallback((network) => {
1285
+ if (isMultiple && selectedNetworkIds) return selectedNetworkIds.includes(getNetworkId(network));
1286
+ return selectedNetwork ? getNetworkId(selectedNetwork) === getNetworkId(network) : false;
1287
+ }, [
1288
+ isMultiple,
1289
+ selectedNetworkIds,
1290
+ selectedNetwork,
1291
+ getNetworkId
1292
+ ]);
1293
+ const handleSelect = React$1.useCallback((network) => {
1294
+ if (isMultiple && selectedNetworkIds && onSelectionChange) {
1295
+ const id = getNetworkId(network);
1296
+ onSelectionChange(selectedNetworkIds.includes(id) ? selectedNetworkIds.filter((x) => x !== id) : [...selectedNetworkIds, id]);
1297
+ } else if (onSelectNetwork) {
1298
+ onSelectNetwork(network);
1299
+ setOpen(false);
1300
+ }
1301
+ }, [
1302
+ isMultiple,
1303
+ selectedNetworkIds,
1304
+ onSelectionChange,
1305
+ onSelectNetwork,
1306
+ getNetworkId
1307
+ ]);
1308
+ const handleClearAll = React$1.useCallback(() => {
1309
+ if (isMultiple && onSelectionChange) onSelectionChange([]);
1310
+ }, [isMultiple, onSelectionChange]);
1311
+ const selectedCount = selectedNetworkIds?.length ?? 0;
1312
+ const renderTrigger = isMultiple ? modeProps.renderTrigger : void 0;
1115
1313
  return /* @__PURE__ */ jsxs(DropdownMenu, {
1116
1314
  open,
1117
1315
  onOpenChange: setOpen,
1118
1316
  children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
1119
1317
  asChild: true,
1120
- children: /* @__PURE__ */ jsxs(Button, {
1121
- variant: "outline",
1122
- role: "combobox",
1123
- "aria-expanded": open,
1124
- className: cn("w-full justify-between", className),
1125
- children: [/* @__PURE__ */ jsx("span", {
1126
- className: "flex items-center gap-2 truncate",
1127
- children: selectedNetwork ? /* @__PURE__ */ jsxs(Fragment, { children: [
1128
- getNetworkIcon?.(selectedNetwork),
1129
- /* @__PURE__ */ jsx("span", {
1130
- className: "truncate",
1131
- children: getNetworkLabel(selectedNetwork)
1132
- }),
1133
- getNetworkType && /* @__PURE__ */ jsx("span", {
1134
- className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase text-muted-foreground",
1135
- children: getNetworkType(selectedNetwork)
1318
+ children: (() => {
1319
+ if (isMultiple && renderTrigger) return renderTrigger({
1320
+ selectedCount,
1321
+ open
1322
+ });
1323
+ if (isMultiple) return /* @__PURE__ */ jsxs(Button, {
1324
+ variant: "outline",
1325
+ role: "combobox",
1326
+ "aria-expanded": open,
1327
+ className: cn("w-full justify-between", className),
1328
+ children: [/* @__PURE__ */ jsx("span", {
1329
+ className: "truncate text-muted-foreground",
1330
+ children: selectedCount > 0 ? `${selectedCount} network${selectedCount > 1 ? "s" : ""} selected` : placeholder
1331
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
1332
+ });
1333
+ return /* @__PURE__ */ jsxs(Button, {
1334
+ variant: "outline",
1335
+ role: "combobox",
1336
+ "aria-expanded": open,
1337
+ className: cn("w-full justify-between", className),
1338
+ children: [/* @__PURE__ */ jsx("span", {
1339
+ className: "flex items-center gap-2 truncate",
1340
+ children: selectedNetwork ? /* @__PURE__ */ jsxs(Fragment, { children: [
1341
+ getNetworkIcon?.(selectedNetwork),
1342
+ /* @__PURE__ */ jsx("span", {
1343
+ className: "truncate",
1344
+ children: getNetworkLabel(selectedNetwork)
1345
+ }),
1346
+ getNetworkType && /* @__PURE__ */ jsx("span", {
1347
+ className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase text-muted-foreground",
1348
+ children: getNetworkType(selectedNetwork)
1349
+ })
1350
+ ] }) : /* @__PURE__ */ jsx("span", {
1351
+ className: "text-muted-foreground",
1352
+ children: placeholder
1136
1353
  })
1137
- ] }) : /* @__PURE__ */ jsx("span", {
1138
- className: "text-muted-foreground",
1139
- children: placeholder
1140
- })
1141
- }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
1142
- })
1354
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
1355
+ });
1356
+ })()
1143
1357
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
1144
1358
  className: "w-[--radix-dropdown-menu-trigger-width] min-w-[240px] p-0",
1145
1359
  align: "start",
@@ -1155,9 +1369,19 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1155
1369
  className: "h-9 w-full border-0 bg-transparent p-0 placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0",
1156
1370
  "aria-label": "Search networks"
1157
1371
  })]
1158
- }), /* @__PURE__ */ jsx("div", {
1372
+ }), /* @__PURE__ */ jsxs("div", {
1159
1373
  className: "max-h-[300px] overflow-y-auto p-1",
1160
- children: Object.entries(groupedNetworks).length === 0 ? /* @__PURE__ */ jsx("div", {
1374
+ children: [isMultiple && selectedCount > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
1375
+ className: "flex items-center justify-between px-2 py-1.5",
1376
+ children: [/* @__PURE__ */ jsxs("span", {
1377
+ className: "text-xs font-medium text-muted-foreground",
1378
+ children: [selectedCount, " selected"]
1379
+ }), /* @__PURE__ */ jsx("button", {
1380
+ onClick: handleClearAll,
1381
+ className: "text-xs text-muted-foreground hover:text-foreground",
1382
+ children: "Clear all"
1383
+ })]
1384
+ }), /* @__PURE__ */ jsx(DropdownMenuSeparator, {})] }), Object.entries(groupedNetworks).length === 0 ? /* @__PURE__ */ jsx("div", {
1161
1385
  className: "py-6 text-center text-sm text-muted-foreground",
1162
1386
  children: "No network found."
1163
1387
  }) : Object.entries(groupedNetworks).map(([group, groupNetworks], index) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [
@@ -1166,12 +1390,16 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1166
1390
  children: group
1167
1391
  }),
1168
1392
  /* @__PURE__ */ jsx(DropdownMenuGroup, { children: groupNetworks.map((network) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
1169
- onSelect: () => {
1170
- onSelectNetwork(network);
1171
- setOpen(false);
1393
+ onSelect: (e) => {
1394
+ if (isMultiple) e.preventDefault();
1395
+ handleSelect(network);
1172
1396
  },
1173
1397
  className: "gap-2",
1174
1398
  children: [
1399
+ isMultiple ? /* @__PURE__ */ jsx("div", {
1400
+ className: "flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border border-primary",
1401
+ children: isSelected(network) && /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" })
1402
+ }) : null,
1175
1403
  getNetworkIcon?.(network),
1176
1404
  /* @__PURE__ */ jsxs("div", {
1177
1405
  className: "flex flex-1 items-center gap-2 min-w-0",
@@ -1183,11 +1411,11 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1183
1411
  children: getNetworkType(network)
1184
1412
  })]
1185
1413
  }),
1186
- selectedNetwork && getNetworkId(selectedNetwork) === getNetworkId(network) && /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 opacity-100" })
1414
+ !isMultiple && isSelected(network) && /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 opacity-100" })
1187
1415
  ]
1188
1416
  }, getNetworkId(network))) }),
1189
1417
  index < Object.keys(groupedNetworks).length - 1 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {})
1190
- ] }, group))
1418
+ ] }, group))]
1191
1419
  })]
1192
1420
  })]
1193
1421
  });
@@ -1220,6 +1448,32 @@ function NetworkStatusBadge({ network, className }) {
1220
1448
  });
1221
1449
  }
1222
1450
 
1451
+ //#endregion
1452
+ //#region src/components/ui/overflow-menu.tsx
1453
+ /** Compact "..." dropdown menu for secondary actions. */
1454
+ function OverflowMenu({ items, align = "end", className, "aria-label": ariaLabel = "More actions" }) {
1455
+ if (items.length === 0) return null;
1456
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
1457
+ asChild: true,
1458
+ children: /* @__PURE__ */ jsx(Button, {
1459
+ variant: "ghost",
1460
+ size: "icon",
1461
+ className: cn("h-8 w-8", className),
1462
+ "aria-label": ariaLabel,
1463
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-4 w-4" })
1464
+ })
1465
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
1466
+ align,
1467
+ className: "min-w-[140px]",
1468
+ children: items.map((item, index) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [item.destructive && index > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}), /* @__PURE__ */ jsxs(DropdownMenuItem, {
1469
+ onClick: item.onSelect,
1470
+ disabled: item.disabled,
1471
+ className: cn(item.destructive && "text-destructive focus:text-destructive"),
1472
+ children: [item.icon, item.label]
1473
+ })] }, item.id))
1474
+ })] });
1475
+ }
1476
+
1223
1477
  //#endregion
1224
1478
  //#region src/components/ui/progress.tsx
1225
1479
  const Progress = React$1.forwardRef(({ className, value, ...props }, ref) => /* @__PURE__ */ jsx(ProgressPrimitive.Root, {
@@ -1339,12 +1593,12 @@ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
1339
1593
  * Can render as a button or anchor element depending on whether href is provided.
1340
1594
  */
1341
1595
  function SidebarButton({ icon, children, onClick, size = "default", badge, disabled = false, isSelected = false, href, target, rel, className }) {
1342
- const commonClass = cn("group relative flex items-center gap-2 px-3 py-2.5 rounded-lg font-semibold text-sm transition-colors", badge ? "justify-between" : "justify-start", disabled ? "text-gray-400 cursor-not-allowed" : isSelected ? "text-[#111928] bg-neutral-100" : "text-gray-600 hover:text-gray-700 cursor-pointer hover:before:content-[\"\"] hover:before:absolute hover:before:inset-x-0 hover:before:top-1 hover:before:bottom-1 hover:before:bg-muted/80 hover:before:rounded-lg hover:before:-z-10", size === "small" ? "h-10" : "h-11", className);
1596
+ const commonClass = cn("group relative flex flex-wrap items-center gap-x-2 gap-y-0.5 px-3 py-2 rounded-lg font-semibold text-sm transition-colors", badge ? "justify-between" : "justify-start", disabled ? "text-gray-400 cursor-not-allowed" : isSelected ? "text-[#111928] bg-neutral-100" : "text-gray-600 hover:text-gray-700 cursor-pointer hover:before:content-[\"\"] hover:before:absolute hover:before:inset-x-0 hover:before:top-1 hover:before:bottom-1 hover:before:bg-muted/80 hover:before:rounded-lg hover:before:-z-10", size === "small" ? "min-h-10" : "min-h-11", className);
1343
1597
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
1344
1598
  className: "flex items-center gap-2",
1345
1599
  children: [icon, children]
1346
1600
  }), badge && /* @__PURE__ */ jsx("span", {
1347
- className: "text-xs px-2 py-1 bg-muted text-muted-foreground rounded-full font-medium",
1601
+ className: "text-xs px-2 py-0.5 bg-muted text-muted-foreground rounded-full font-medium",
1348
1602
  children: badge
1349
1603
  })] });
1350
1604
  if (href) return /* @__PURE__ */ jsx("a", {
@@ -1589,6 +1843,555 @@ function ViewContractStateButton({ contractAddress, onToggle }) {
1589
1843
  });
1590
1844
  }
1591
1845
 
1846
+ //#endregion
1847
+ //#region src/components/ui/wizard/WizardStepper.tsx
1848
+ function resolveState(step, index, currentStepIndex, furthestStepIndex) {
1849
+ if (step.status === "completed" || step.status === "skipped") return "completed";
1850
+ if (index === currentStepIndex) return "current";
1851
+ if (step.isInvalid && (index < currentStepIndex || index <= furthestStepIndex)) return "invalid";
1852
+ if (index < currentStepIndex) return "completed";
1853
+ if (index <= furthestStepIndex) return "visited";
1854
+ return "upcoming";
1855
+ }
1856
+ function canClick(state, freeNavigation = false) {
1857
+ if (freeNavigation) return true;
1858
+ return state !== "upcoming";
1859
+ }
1860
+ function StepCircle({ state, index }) {
1861
+ return /* @__PURE__ */ jsx("span", {
1862
+ className: cn("flex size-6 shrink-0 items-center justify-center rounded-full text-xs font-semibold transition-all", state === "completed" && "bg-blue-600 text-white", state === "current" && "bg-blue-600 text-white ring-2 ring-blue-200", state === "visited" && "bg-blue-100 text-blue-600 ring-1 ring-blue-300", state === "invalid" && "bg-red-100 text-red-600 ring-1 ring-red-300", state === "upcoming" && "bg-zinc-100 text-zinc-400"),
1863
+ children: state === "completed" ? /* @__PURE__ */ jsx(Check, { className: "size-3.5" }) : state === "visited" ? /* @__PURE__ */ jsx(Pencil, { className: "size-3" }) : state === "invalid" ? /* @__PURE__ */ jsx(AlertCircle, { className: "size-3.5" }) : index + 1
1864
+ });
1865
+ }
1866
+ function StepLabel({ title, state, isSkipped }) {
1867
+ return /* @__PURE__ */ jsxs("div", {
1868
+ className: "min-w-0 flex-1",
1869
+ children: [/* @__PURE__ */ jsx("span", {
1870
+ className: cn("text-sm font-medium transition-colors", state === "current" && "text-blue-700", state === "completed" && "text-zinc-700", state === "visited" && "text-blue-600", state === "invalid" && "text-red-600", state === "upcoming" && "text-zinc-400"),
1871
+ children: title
1872
+ }), isSkipped && /* @__PURE__ */ jsx("span", {
1873
+ className: "mt-0.5 block text-[11px] text-zinc-400",
1874
+ children: "Skipped"
1875
+ })]
1876
+ });
1877
+ }
1878
+ function VerticalStepper({ steps, currentStepIndex, furthestStepIndex = currentStepIndex, onStepClick, freeNavigation, className }) {
1879
+ return /* @__PURE__ */ jsx("nav", {
1880
+ "aria-label": "Wizard steps",
1881
+ className: cn("rounded-2xl border border-zinc-200 bg-white p-6", className),
1882
+ children: /* @__PURE__ */ jsx("div", {
1883
+ className: "flex flex-col gap-1",
1884
+ children: steps.map((step, index) => {
1885
+ const state = resolveState(step, index, currentStepIndex, furthestStepIndex);
1886
+ const clickable = canClick(state, freeNavigation) && !!onStepClick;
1887
+ return /* @__PURE__ */ jsxs("button", {
1888
+ type: "button",
1889
+ onClick: () => clickable && onStepClick?.(index),
1890
+ disabled: !clickable,
1891
+ className: cn("flex items-center gap-3 rounded-xl border border-transparent px-3 py-3 text-left transition-all duration-150", clickable ? "cursor-pointer" : "cursor-not-allowed opacity-50", state === "current" && "border-blue-200 bg-blue-50", state === "completed" && "bg-white hover:bg-gray-50", state === "visited" && "bg-white hover:bg-blue-50/50", state === "invalid" && "border-red-200 bg-red-50 hover:bg-red-100/60", state === "upcoming" && "bg-white"),
1892
+ "aria-current": state === "current" ? "step" : void 0,
1893
+ children: [/* @__PURE__ */ jsx(StepCircle, {
1894
+ state,
1895
+ index
1896
+ }), /* @__PURE__ */ jsx(StepLabel, {
1897
+ title: step.title,
1898
+ state,
1899
+ isSkipped: step.status === "skipped"
1900
+ })]
1901
+ }, step.id);
1902
+ })
1903
+ })
1904
+ });
1905
+ }
1906
+ function HorizontalStepper({ steps, currentStepIndex, furthestStepIndex = currentStepIndex, onStepClick, freeNavigation, className }) {
1907
+ return /* @__PURE__ */ jsx("nav", {
1908
+ "aria-label": "Wizard steps",
1909
+ className: cn("rounded-2xl border border-zinc-200 bg-white p-6", className),
1910
+ children: /* @__PURE__ */ jsx("div", {
1911
+ className: "flex w-full items-center",
1912
+ children: steps.map((step, index) => {
1913
+ const state = resolveState(step, index, currentStepIndex, furthestStepIndex);
1914
+ const clickable = canClick(state, freeNavigation) && !!onStepClick;
1915
+ const isLast = index === steps.length - 1;
1916
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsxs("button", {
1917
+ type: "button",
1918
+ onClick: () => clickable && onStepClick?.(index),
1919
+ disabled: !clickable,
1920
+ className: cn("flex items-center gap-2 rounded-xl border border-transparent px-3 py-2 text-left transition-all duration-150", clickable ? "cursor-pointer" : "cursor-not-allowed opacity-50", state === "current" && "border-blue-200 bg-blue-50", state === "completed" && "bg-white hover:bg-gray-50", state === "visited" && "bg-white hover:bg-blue-50/50", state === "invalid" && "border-red-200 bg-red-50 hover:bg-red-100/60", state === "upcoming" && "bg-white"),
1921
+ "aria-current": state === "current" ? "step" : void 0,
1922
+ "aria-label": `Step ${index + 1}: ${step.title}`,
1923
+ children: [/* @__PURE__ */ jsx(StepCircle, {
1924
+ state,
1925
+ index
1926
+ }), /* @__PURE__ */ jsx("div", {
1927
+ className: "hidden sm:block",
1928
+ children: /* @__PURE__ */ jsx(StepLabel, {
1929
+ title: step.title,
1930
+ state,
1931
+ isSkipped: step.status === "skipped"
1932
+ })
1933
+ })]
1934
+ }), !isLast && /* @__PURE__ */ jsx("div", { className: cn("mx-1 h-px flex-1 transition-colors sm:mx-2", index < currentStepIndex ? "bg-blue-600" : "bg-zinc-200") })] }, step.id);
1935
+ })
1936
+ })
1937
+ });
1938
+ }
1939
+ /**
1940
+ * A stepper component for navigating through a series of steps.
1941
+ *
1942
+ * @param props - The props for the WizardStepper component.
1943
+ * @returns A React node representing the stepper component.
1944
+ */
1945
+ function WizardStepper(props) {
1946
+ const { variant = "horizontal", ...rest } = props;
1947
+ return variant === "vertical" ? /* @__PURE__ */ jsx(VerticalStepper, {
1948
+ ...rest,
1949
+ variant
1950
+ }) : /* @__PURE__ */ jsx(HorizontalStepper, {
1951
+ ...rest,
1952
+ variant
1953
+ });
1954
+ }
1955
+
1956
+ //#endregion
1957
+ //#region src/components/ui/wizard/WizardNavigation.tsx
1958
+ /**
1959
+ * A navigation component for the wizard.
1960
+ *
1961
+ * @param props - The props for the WizardNavigation component.
1962
+ * @returns A React node representing the navigation component.
1963
+ */
1964
+ function WizardNavigation({ isFirstStep, isLastStep, canProceed = true, onPrevious, onNext, onCancel, extraActions, nextLabel = "Next", lastStepLabel = "Finish", className }) {
1965
+ return /* @__PURE__ */ jsxs("div", {
1966
+ className: cn("flex items-center justify-between", className),
1967
+ children: [/* @__PURE__ */ jsxs("div", {
1968
+ className: "flex gap-2",
1969
+ children: [onCancel && /* @__PURE__ */ jsxs(Button, {
1970
+ type: "button",
1971
+ variant: "outline",
1972
+ onClick: onCancel,
1973
+ className: "gap-2",
1974
+ children: [/* @__PURE__ */ jsx(X, { className: "size-4" }), "Cancel"]
1975
+ }), !isFirstStep && /* @__PURE__ */ jsxs(Button, {
1976
+ type: "button",
1977
+ variant: "outline",
1978
+ onClick: onPrevious,
1979
+ className: "gap-2",
1980
+ children: [/* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }), "Previous"]
1981
+ })]
1982
+ }), /* @__PURE__ */ jsxs("div", {
1983
+ className: "flex gap-2",
1984
+ children: [extraActions, /* @__PURE__ */ jsxs(Button, {
1985
+ type: "button",
1986
+ onClick: onNext,
1987
+ disabled: !canProceed,
1988
+ className: "gap-2",
1989
+ children: [isLastStep ? lastStepLabel : nextLabel, !isLastStep && /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })]
1990
+ })]
1991
+ })]
1992
+ });
1993
+ }
1994
+
1995
+ //#endregion
1996
+ //#region src/components/ui/wizard/hooks.ts
1997
+ /**
1998
+ * Clamp a step index into the valid range for the current wizard.
1999
+ */
2000
+ function getSafeStepIndex(stepCount, currentStepIndex) {
2001
+ if (stepCount === 0) return 0;
2002
+ return Math.max(0, Math.min(currentStepIndex, stepCount - 1));
2003
+ }
2004
+ /**
2005
+ * Track the highest step reached unless a controlled value is provided.
2006
+ */
2007
+ function useFurthestStepIndex(currentStepIndex, controlledFurthestStepIndex) {
2008
+ const [internalFurthestStepIndex, setInternalFurthestStepIndex] = useState(currentStepIndex);
2009
+ useEffect(() => {
2010
+ setInternalFurthestStepIndex((prev) => Math.max(prev, currentStepIndex));
2011
+ }, [currentStepIndex]);
2012
+ return controlledFurthestStepIndex ?? internalFurthestStepIndex;
2013
+ }
2014
+ /**
2015
+ * Keep the scrollable wizard's active and visited step state in sync with scrolling and clicks.
2016
+ */
2017
+ function useScrollableWizardStepTracking({ steps, currentStepIndex, onStepChange, scrollRef, sectionId, scrollPadding = SCROLL_PADDING_PX }) {
2018
+ const safeIndex = getSafeStepIndex(steps.length, currentStepIndex);
2019
+ const initialIndexRef = useRef(safeIndex);
2020
+ const rafRef = useRef(null);
2021
+ const manualSelectionIndexRef = useRef(null);
2022
+ const stepsRef = useRef(steps);
2023
+ const sectionIdRef = useRef(sectionId);
2024
+ const onStepChangeRef = useRef(onStepChange);
2025
+ const scrollPaddingRef = useRef(scrollPadding);
2026
+ useEffect(() => {
2027
+ stepsRef.current = steps;
2028
+ sectionIdRef.current = sectionId;
2029
+ onStepChangeRef.current = onStepChange;
2030
+ scrollPaddingRef.current = scrollPadding;
2031
+ });
2032
+ const [activeIndex, setActiveIndex] = useState(initialIndexRef.current);
2033
+ const activeIndexRef = useRef(initialIndexRef.current);
2034
+ const [furthestStepIndex, setFurthestStepIndex] = useState(initialIndexRef.current);
2035
+ const isMountedRef = useRef(false);
2036
+ const clearManualSelection = useCallback(() => {
2037
+ manualSelectionIndexRef.current = null;
2038
+ }, []);
2039
+ useEffect(() => {
2040
+ const container = scrollRef.current;
2041
+ if (!container) return;
2042
+ const ownerDocument = container.ownerDocument;
2043
+ isMountedRef.current = false;
2044
+ let didCompleteInitialRaf = false;
2045
+ const releaseManualSelectionOnUserScroll = () => {
2046
+ clearManualSelection();
2047
+ };
2048
+ const handleKeyDown = (event) => {
2049
+ if (isScrollableNavigationKey(event)) clearManualSelection();
2050
+ };
2051
+ const handleScroll = () => {
2052
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2053
+ rafRef.current = requestAnimationFrame(() => {
2054
+ const currentSteps = stepsRef.current;
2055
+ const currentSectionId = sectionIdRef.current;
2056
+ const currentOnStepChange = onStepChangeRef.current;
2057
+ if (currentSteps.length === 0) return;
2058
+ const manualSelectionIndex = manualSelectionIndexRef.current;
2059
+ const naturalState = resolveScrollableActiveIndex(container, currentSteps, currentSectionId);
2060
+ const naturalActiveIndex = naturalState.activeIndex;
2061
+ const newActiveIndex = manualSelectionIndex ?? naturalActiveIndex;
2062
+ const shouldCommitFurthestStepIndex = manualSelectionIndex !== null ? true : naturalState.commitFurthestStepIndex;
2063
+ if (activeIndexRef.current !== newActiveIndex) {
2064
+ activeIndexRef.current = newActiveIndex;
2065
+ setActiveIndex(newActiveIndex);
2066
+ if (isMountedRef.current) {
2067
+ lastEmittedIndexRef.current = newActiveIndex;
2068
+ currentOnStepChange(newActiveIndex);
2069
+ }
2070
+ } else setActiveIndex(newActiveIndex);
2071
+ if (shouldCommitFurthestStepIndex) setFurthestStepIndex((prev) => Math.max(prev, newActiveIndex));
2072
+ rafRef.current = null;
2073
+ if (!didCompleteInitialRaf) {
2074
+ didCompleteInitialRaf = true;
2075
+ isMountedRef.current = true;
2076
+ }
2077
+ });
2078
+ };
2079
+ container.addEventListener("wheel", releaseManualSelectionOnUserScroll, { passive: true });
2080
+ container.addEventListener("touchmove", releaseManualSelectionOnUserScroll, { passive: true });
2081
+ container.addEventListener("pointerdown", releaseManualSelectionOnUserScroll);
2082
+ ownerDocument.addEventListener("keydown", handleKeyDown);
2083
+ container.addEventListener("scroll", handleScroll, { passive: true });
2084
+ handleScroll();
2085
+ return () => {
2086
+ isMountedRef.current = false;
2087
+ container.removeEventListener("wheel", releaseManualSelectionOnUserScroll);
2088
+ container.removeEventListener("touchmove", releaseManualSelectionOnUserScroll);
2089
+ container.removeEventListener("pointerdown", releaseManualSelectionOnUserScroll);
2090
+ ownerDocument.removeEventListener("keydown", handleKeyDown);
2091
+ container.removeEventListener("scroll", handleScroll);
2092
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2093
+ };
2094
+ }, [clearManualSelection, scrollRef]);
2095
+ const lastEmittedIndexRef = useRef(safeIndex);
2096
+ useEffect(() => {
2097
+ const newSafeIndex = getSafeStepIndex(stepsRef.current.length, currentStepIndex);
2098
+ if (newSafeIndex === lastEmittedIndexRef.current) return;
2099
+ lastEmittedIndexRef.current = newSafeIndex;
2100
+ activeIndexRef.current = newSafeIndex;
2101
+ setActiveIndex(newSafeIndex);
2102
+ setFurthestStepIndex((prev) => Math.max(prev, newSafeIndex));
2103
+ const step = stepsRef.current[newSafeIndex];
2104
+ if (!step) return;
2105
+ const sectionElement = scrollRef.current?.querySelector(`#${CSS.escape(sectionIdRef.current(step.id))}`);
2106
+ if (scrollRef.current && sectionElement) scrollSectionIntoView(scrollRef.current, sectionElement, scrollPaddingRef.current);
2107
+ }, [currentStepIndex, scrollRef]);
2108
+ return {
2109
+ activeIndex,
2110
+ furthestStepIndex,
2111
+ scrollToSection: useCallback((index) => {
2112
+ const step = stepsRef.current[index];
2113
+ if (!step) return;
2114
+ manualSelectionIndexRef.current = index;
2115
+ activeIndexRef.current = index;
2116
+ lastEmittedIndexRef.current = index;
2117
+ setActiveIndex(index);
2118
+ setFurthestStepIndex((prev) => Math.max(prev, index));
2119
+ onStepChangeRef.current(index);
2120
+ const container = scrollRef.current;
2121
+ const sectionElement = container?.querySelector(`#${CSS.escape(sectionIdRef.current(step.id))}`);
2122
+ if (container && sectionElement) scrollSectionIntoView(container, sectionElement, scrollPaddingRef.current);
2123
+ }, [scrollRef])
2124
+ };
2125
+ }
2126
+ function resolveScrollableActiveIndex(container, steps, sectionId) {
2127
+ if (steps.length === 0) return {
2128
+ activeIndex: 0,
2129
+ commitFurthestStepIndex: false
2130
+ };
2131
+ const containerRect = container.getBoundingClientRect();
2132
+ const anchorY = containerRect.top + Math.min(containerRect.height * .35, 220);
2133
+ const isScrollable = container.scrollHeight > container.clientHeight + 1;
2134
+ const isAtBottom = isScrollable && container.scrollTop + container.clientHeight >= container.scrollHeight - 1;
2135
+ const isNearBottom = isScrollable && container.scrollTop + container.clientHeight >= container.scrollHeight - 4;
2136
+ if (isAtBottom) return {
2137
+ activeIndex: steps.length - 1,
2138
+ commitFurthestStepIndex: false
2139
+ };
2140
+ let activeIndex = 0;
2141
+ let highestScore = Number.NEGATIVE_INFINITY;
2142
+ for (let i = 0; i < steps.length; i++) {
2143
+ const sectionMetrics = getSectionMetrics(container, steps[i].id, sectionId, containerRect);
2144
+ if (!sectionMetrics) continue;
2145
+ const score = scoreScrollableStep({
2146
+ stepIndex: i,
2147
+ stepCount: steps.length,
2148
+ containerRect,
2149
+ anchorY,
2150
+ isNearBottom,
2151
+ ...sectionMetrics
2152
+ });
2153
+ if (score >= highestScore) {
2154
+ highestScore = score;
2155
+ activeIndex = i;
2156
+ }
2157
+ }
2158
+ return {
2159
+ activeIndex,
2160
+ commitFurthestStepIndex: true
2161
+ };
2162
+ }
2163
+ const SCROLL_PADDING_PX = 32;
2164
+ function getSectionElement(container, stepId, sectionId) {
2165
+ return container.querySelector(`#${CSS.escape(sectionId(stepId))}`);
2166
+ }
2167
+ function scrollSectionIntoView(container, sectionElement, padding) {
2168
+ const elementTop = sectionElement.getBoundingClientRect().top;
2169
+ const containerTop = container.getBoundingClientRect().top;
2170
+ const targetScrollTop = container.scrollTop + (elementTop - containerTop) - padding;
2171
+ container.scrollTo({
2172
+ top: targetScrollTop,
2173
+ behavior: "smooth"
2174
+ });
2175
+ }
2176
+ function getSectionMetrics(container, stepId, sectionId, containerRect) {
2177
+ const sectionElement = getSectionElement(container, stepId, sectionId);
2178
+ if (!sectionElement) return null;
2179
+ const sectionRect = sectionElement.getBoundingClientRect();
2180
+ return {
2181
+ sectionRect,
2182
+ visibleHeight: getVisibleHeight(containerRect, sectionRect)
2183
+ };
2184
+ }
2185
+ function getVisibleHeight(containerRect, sectionRect) {
2186
+ return Math.max(0, Math.min(sectionRect.bottom, containerRect.bottom) - Math.max(sectionRect.top, containerRect.top));
2187
+ }
2188
+ function scoreScrollableStep({ stepIndex, stepCount, containerRect, sectionRect, visibleHeight, anchorY, isNearBottom }) {
2189
+ const isVisible = visibleHeight > 0;
2190
+ const focusBandTop = containerRect.top + Math.min(containerRect.height * .2, 140);
2191
+ const focusBandBottom = containerRect.top + Math.min(containerRect.height * .55, 360);
2192
+ const focusBandOverlap = getBandOverlapHeight(sectionRect, focusBandTop, focusBandBottom);
2193
+ const distanceToFocusBand = focusBandOverlap > 0 ? 0 : Math.min(Math.abs(sectionRect.top - focusBandBottom), Math.abs(sectionRect.bottom - focusBandTop));
2194
+ const lastStepProminent = stepIndex === stepCount - 1 && visibleHeight >= Math.min(sectionRect.height, containerRect.height) * .25 && sectionRect.top <= containerRect.top + containerRect.height * .65;
2195
+ let score = isVisible ? visibleHeight : Number.NEGATIVE_INFINITY;
2196
+ if (focusBandOverlap > 0) score += 12e3 + focusBandOverlap * 25;
2197
+ if (sectionRect.top <= anchorY) score += 250;
2198
+ score += Math.max(0, 1e3 - distanceToFocusBand);
2199
+ if (isNearBottom && lastStepProminent && isVisible) score += 15e3;
2200
+ return score;
2201
+ }
2202
+ function getBandOverlapHeight(sectionRect, bandTop, bandBottom) {
2203
+ return Math.max(0, Math.min(sectionRect.bottom, bandBottom) - Math.max(sectionRect.top, bandTop));
2204
+ }
2205
+ function isScrollableNavigationKey(event) {
2206
+ if (event.metaKey || event.ctrlKey || event.altKey) return false;
2207
+ return [
2208
+ "ArrowDown",
2209
+ "ArrowUp",
2210
+ "PageDown",
2211
+ "PageUp",
2212
+ "Home",
2213
+ "End",
2214
+ " "
2215
+ ].includes(event.key);
2216
+ }
2217
+
2218
+ //#endregion
2219
+ //#region src/components/ui/wizard/WizardLayout.tsx
2220
+ function PagedLayout({ steps, currentStepIndex, furthestStepIndex: furthestStepIndexProp, onStepChange, onComplete, onCancel, navActions, header, variant, className }) {
2221
+ const safeIndex = getSafeStepIndex(steps.length, currentStepIndex);
2222
+ const resolvedFurthestStepIndex = useFurthestStepIndex(safeIndex, furthestStepIndexProp);
2223
+ if (steps.length === 0) return null;
2224
+ const isFirstStep = safeIndex === 0;
2225
+ const isLastStep = safeIndex === steps.length - 1;
2226
+ const currentStep = steps[safeIndex];
2227
+ const canProceed = currentStep?.isValid !== false;
2228
+ const handleNext = () => {
2229
+ if (isLastStep) {
2230
+ onComplete?.();
2231
+ return;
2232
+ }
2233
+ onStepChange(safeIndex + 1);
2234
+ };
2235
+ const handlePrevious = () => {
2236
+ if (!isFirstStep) onStepChange(safeIndex - 1);
2237
+ };
2238
+ const stepDefs = toStepDefs(steps, safeIndex);
2239
+ const footer = /* @__PURE__ */ jsx("div", {
2240
+ className: "shrink-0 border-t border-border bg-background px-8 py-4",
2241
+ children: /* @__PURE__ */ jsx("div", {
2242
+ className: "mx-auto max-w-5xl",
2243
+ children: /* @__PURE__ */ jsx(WizardNavigation, {
2244
+ isFirstStep,
2245
+ isLastStep,
2246
+ canProceed,
2247
+ onPrevious: handlePrevious,
2248
+ onNext: handleNext,
2249
+ onCancel,
2250
+ extraActions: navActions
2251
+ })
2252
+ })
2253
+ });
2254
+ if (variant === "vertical") return /* @__PURE__ */ jsxs("div", {
2255
+ className: cn("flex h-full gap-6", className),
2256
+ children: [/* @__PURE__ */ jsx("div", {
2257
+ className: "w-[220px] shrink-0 py-6 pl-6",
2258
+ children: /* @__PURE__ */ jsx(WizardStepper, {
2259
+ variant: "vertical",
2260
+ steps: stepDefs,
2261
+ currentStepIndex: safeIndex,
2262
+ furthestStepIndex: resolvedFurthestStepIndex,
2263
+ onStepClick: onStepChange,
2264
+ className: "h-full"
2265
+ })
2266
+ }), /* @__PURE__ */ jsxs("div", {
2267
+ className: "flex min-w-0 flex-1 flex-col overflow-hidden",
2268
+ children: [/* @__PURE__ */ jsx("div", {
2269
+ className: "flex-1 overflow-y-auto p-8",
2270
+ children: /* @__PURE__ */ jsxs("div", {
2271
+ className: "mx-auto max-w-5xl",
2272
+ children: [header, currentStep?.component]
2273
+ })
2274
+ }), footer]
2275
+ })]
2276
+ });
2277
+ return /* @__PURE__ */ jsxs("div", {
2278
+ className: cn("flex h-full flex-col", className),
2279
+ children: [/* @__PURE__ */ jsx("div", {
2280
+ className: "shrink-0 p-6 pb-0",
2281
+ children: /* @__PURE__ */ jsx(WizardStepper, {
2282
+ variant: "horizontal",
2283
+ steps: stepDefs,
2284
+ currentStepIndex: safeIndex,
2285
+ furthestStepIndex: resolvedFurthestStepIndex,
2286
+ onStepClick: onStepChange
2287
+ })
2288
+ }), /* @__PURE__ */ jsxs("div", {
2289
+ className: "flex min-w-0 flex-1 flex-col overflow-hidden",
2290
+ children: [/* @__PURE__ */ jsx("div", {
2291
+ className: "flex-1 overflow-y-auto p-8",
2292
+ children: /* @__PURE__ */ jsxs("div", {
2293
+ className: "mx-auto max-w-5xl",
2294
+ children: [header, currentStep?.component]
2295
+ })
2296
+ }), footer]
2297
+ })]
2298
+ });
2299
+ }
2300
+ function ScrollableLayout({ steps, currentStepIndex, onStepChange, header, onComplete, scrollPadding, className }) {
2301
+ const instanceId = useId();
2302
+ const scrollRef = useRef(null);
2303
+ const sectionId = useCallback((stepId) => `wizard-section-${instanceId}-${stepId}`, [instanceId]);
2304
+ const { activeIndex, furthestStepIndex, scrollToSection } = useScrollableWizardStepTracking({
2305
+ steps,
2306
+ currentStepIndex,
2307
+ onStepChange,
2308
+ scrollRef,
2309
+ sectionId,
2310
+ scrollPadding
2311
+ });
2312
+ if (steps.length === 0) return null;
2313
+ const stepDefs = toStepDefs(steps, activeIndex);
2314
+ return /* @__PURE__ */ jsxs("div", {
2315
+ className: cn("flex h-full gap-6", className),
2316
+ children: [/* @__PURE__ */ jsx("div", {
2317
+ className: "w-[220px] shrink-0 py-6 pl-6",
2318
+ children: /* @__PURE__ */ jsx(WizardStepper, {
2319
+ variant: "vertical",
2320
+ steps: stepDefs,
2321
+ currentStepIndex: activeIndex,
2322
+ furthestStepIndex,
2323
+ onStepClick: scrollToSection,
2324
+ freeNavigation: true,
2325
+ className: "h-full"
2326
+ })
2327
+ }), /* @__PURE__ */ jsxs("div", {
2328
+ ref: scrollRef,
2329
+ className: "flex min-w-0 flex-1 flex-col overflow-y-auto p-8",
2330
+ children: [
2331
+ header,
2332
+ /* @__PURE__ */ jsx("div", {
2333
+ className: "space-y-12",
2334
+ children: steps.map((step) => /* @__PURE__ */ jsx("section", {
2335
+ id: sectionId(step.id),
2336
+ children: step.component
2337
+ }, step.id))
2338
+ }),
2339
+ onComplete && /* @__PURE__ */ jsx("div", {
2340
+ className: "flex justify-end pt-8",
2341
+ children: /* @__PURE__ */ jsx(Button, {
2342
+ type: "button",
2343
+ onClick: onComplete,
2344
+ children: "Finish"
2345
+ })
2346
+ })
2347
+ ]
2348
+ })]
2349
+ });
2350
+ }
2351
+ function toStepDefs(steps, currentStepIndex) {
2352
+ return steps.map((s, i) => {
2353
+ const isInvalid = s.isInvalid ?? s.isValid === false;
2354
+ const status = s.status ?? (i < currentStepIndex && !isInvalid ? "completed" : "pending");
2355
+ return {
2356
+ id: s.id,
2357
+ title: s.title,
2358
+ status,
2359
+ isInvalid
2360
+ };
2361
+ });
2362
+ }
2363
+ /**
2364
+ * A layout component for the wizard.
2365
+ *
2366
+ * @param props - The props for the WizardLayout component.
2367
+ * @returns A React node representing the layout component.
2368
+ */
2369
+ function WizardLayout(props) {
2370
+ const { variant = "horizontal", ...rest } = props;
2371
+ if (variant === "scrollable") return /* @__PURE__ */ jsx(ScrollableLayout, {
2372
+ steps: rest.steps,
2373
+ currentStepIndex: rest.currentStepIndex,
2374
+ onStepChange: rest.onStepChange,
2375
+ header: rest.header,
2376
+ onComplete: rest.onComplete,
2377
+ scrollPadding: rest.scrollPadding,
2378
+ className: rest.className
2379
+ });
2380
+ return /* @__PURE__ */ jsx(PagedLayout, {
2381
+ ...rest,
2382
+ variant
2383
+ });
2384
+ }
2385
+
2386
+ //#endregion
2387
+ //#region src/components/fields/address-suggestion/context.ts
2388
+ /**
2389
+ * @internal Shared context instance consumed by both AddressField and
2390
+ * AddressSuggestionProvider. Kept in its own file so component files export
2391
+ * only components (required by React Fast Refresh).
2392
+ */
2393
+ const AddressSuggestionContext = createContext(null);
2394
+
1592
2395
  //#endregion
1593
2396
  //#region src/components/fields/utils/accessibility.ts
1594
2397
  /**
@@ -1780,6 +2583,8 @@ function getWidthClasses(width) {
1780
2583
 
1781
2584
  //#endregion
1782
2585
  //#region src/components/fields/AddressField.tsx
2586
+ const DEBOUNCE_MS = 200;
2587
+ const MAX_SUGGESTIONS = 5;
1783
2588
  /**
1784
2589
  * Address input field component specifically designed for blockchain addresses via React Hook Form integration.
1785
2590
  *
@@ -1797,11 +2602,82 @@ function getWidthClasses(width) {
1797
2602
  * - Chain-agnostic design (validation handled by adapters)
1798
2603
  * - Full accessibility support with ARIA attributes
1799
2604
  * - Keyboard navigation
2605
+ *
2606
+ * Autocomplete suggestions can be provided in two ways:
2607
+ *
2608
+ * 1. **Context-based (zero-config)**: Mount an `AddressSuggestionProvider` in the
2609
+ * component tree. Every `AddressField` below it automatically resolves suggestions.
2610
+ *
2611
+ * 2. **Prop-based (explicit)**: Pass `suggestions` directly. This overrides context.
2612
+ * Pass `suggestions={false}` to opt out when a provider is mounted.
2613
+ *
2614
+ * The suggestion dropdown includes built-in debouncing, keyboard navigation (Arrow keys,
2615
+ * Enter, Escape), click-outside dismissal, and ARIA listbox semantics.
1800
2616
  */
1801
- function AddressField({ id, label, placeholder, helperText, control, name, width = "full", validation, adapter, readOnly }) {
2617
+ function AddressField({ id, label, placeholder, helperText, control, name, width = "full", validation, adapter, readOnly, suggestions: suggestionsProp, onSuggestionSelect }) {
1802
2618
  const isRequired = !!validation?.required;
1803
2619
  const errorId = `${id}-error`;
1804
2620
  const descriptionId = `${id}-description`;
2621
+ const contextResolver = useContext(AddressSuggestionContext);
2622
+ const containerRef = useRef(null);
2623
+ const lastSetValueRef = useRef("");
2624
+ const [inputValue, setInputValue] = useState("");
2625
+ const [debouncedQuery, setDebouncedQuery] = useState("");
2626
+ const [showSuggestions, setShowSuggestions] = useState(false);
2627
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
2628
+ const watchedFieldValue = useWatch({
2629
+ control,
2630
+ name
2631
+ });
2632
+ useEffect(() => {
2633
+ const currentFieldValue = watchedFieldValue ?? "";
2634
+ if (currentFieldValue !== lastSetValueRef.current) {
2635
+ lastSetValueRef.current = currentFieldValue;
2636
+ setInputValue(currentFieldValue);
2637
+ }
2638
+ }, [watchedFieldValue]);
2639
+ useEffect(() => {
2640
+ if (!inputValue.trim()) {
2641
+ setDebouncedQuery("");
2642
+ return;
2643
+ }
2644
+ const timer = setTimeout(() => setDebouncedQuery(inputValue), DEBOUNCE_MS);
2645
+ return () => clearTimeout(timer);
2646
+ }, [inputValue]);
2647
+ const suggestionsDisabled = suggestionsProp === false;
2648
+ const resolvedSuggestions = useMemo(() => {
2649
+ if (suggestionsDisabled) return [];
2650
+ if (Array.isArray(suggestionsProp)) return suggestionsProp;
2651
+ if (!contextResolver || !debouncedQuery.trim()) return [];
2652
+ return contextResolver.resolveSuggestions(debouncedQuery).slice(0, MAX_SUGGESTIONS);
2653
+ }, [
2654
+ suggestionsDisabled,
2655
+ suggestionsProp,
2656
+ contextResolver,
2657
+ debouncedQuery
2658
+ ]);
2659
+ const hasSuggestions = showSuggestions && resolvedSuggestions.length > 0;
2660
+ useEffect(() => {
2661
+ let active = true;
2662
+ const handleClickOutside = (e) => {
2663
+ if (active && containerRef.current && !containerRef.current.contains(e.target)) setShowSuggestions(false);
2664
+ };
2665
+ document.addEventListener("mousedown", handleClickOutside);
2666
+ return () => {
2667
+ active = false;
2668
+ document.removeEventListener("mousedown", handleClickOutside);
2669
+ };
2670
+ }, []);
2671
+ const handleSuggestionKeyDown = useCallback((e) => {
2672
+ if (!hasSuggestions) return;
2673
+ if (e.key === "ArrowDown") {
2674
+ e.preventDefault();
2675
+ setHighlightedIndex((prev) => prev < resolvedSuggestions.length - 1 ? prev + 1 : 0);
2676
+ } else if (e.key === "ArrowUp") {
2677
+ e.preventDefault();
2678
+ setHighlightedIndex((prev) => prev > 0 ? prev - 1 : resolvedSuggestions.length - 1);
2679
+ }
2680
+ }, [hasSuggestions, resolvedSuggestions.length]);
1805
2681
  return /* @__PURE__ */ jsxs("div", {
1806
2682
  className: `flex flex-col gap-2 ${width === "full" ? "w-full" : width === "half" ? "w-1/2" : "w-1/3"}`,
1807
2683
  children: [label && /* @__PURE__ */ jsxs(Label, {
@@ -1835,9 +2711,32 @@ function AddressField({ id, label, placeholder, helperText, control, name, width
1835
2711
  const handleInputChange = (e) => {
1836
2712
  const value = e.target.value;
1837
2713
  field.onChange(value);
2714
+ lastSetValueRef.current = value;
2715
+ setInputValue(value);
2716
+ setShowSuggestions(value.length > 0);
2717
+ setHighlightedIndex(-1);
2718
+ };
2719
+ const applySuggestion = (suggestion) => {
2720
+ field.onChange(suggestion.value);
2721
+ onSuggestionSelect?.(suggestion);
2722
+ lastSetValueRef.current = suggestion.value;
2723
+ setInputValue(suggestion.value);
2724
+ setShowSuggestions(false);
2725
+ setHighlightedIndex(-1);
1838
2726
  };
1839
2727
  const handleKeyDown = (e) => {
1840
- if (e.key === "Escape") handleEscapeKey(field.onChange, field.value)(e);
2728
+ if (hasSuggestions && e.key === "Enter" && highlightedIndex >= 0) {
2729
+ e.preventDefault();
2730
+ applySuggestion(resolvedSuggestions[highlightedIndex]);
2731
+ return;
2732
+ }
2733
+ if (e.key === "Escape") {
2734
+ if (hasSuggestions) {
2735
+ setShowSuggestions(false);
2736
+ return;
2737
+ }
2738
+ handleEscapeKey(field.onChange, field.value)(e);
2739
+ }
1841
2740
  };
1842
2741
  const accessibilityProps = getAccessibilityProps({
1843
2742
  id,
@@ -1846,18 +2745,50 @@ function AddressField({ id, label, placeholder, helperText, control, name, width
1846
2745
  hasHelperText: !!helperText
1847
2746
  });
1848
2747
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1849
- /* @__PURE__ */ jsx(Input, {
1850
- ...field,
1851
- id,
1852
- placeholder: placeholder || "0x...",
1853
- className: validationClasses,
1854
- onChange: handleInputChange,
1855
- onKeyDown: handleKeyDown,
1856
- "data-slot": "input",
1857
- value: field.value ?? "",
1858
- ...accessibilityProps,
1859
- "aria-describedby": `${helperText ? descriptionId : ""} ${hasError ? errorId : ""}`,
1860
- disabled: readOnly
2748
+ /* @__PURE__ */ jsxs("div", {
2749
+ ref: containerRef,
2750
+ className: "relative",
2751
+ onKeyDown: handleSuggestionKeyDown,
2752
+ children: [/* @__PURE__ */ jsx(Input, {
2753
+ ...field,
2754
+ id,
2755
+ placeholder: placeholder || "0x...",
2756
+ className: validationClasses,
2757
+ onChange: handleInputChange,
2758
+ onKeyDown: handleKeyDown,
2759
+ "data-slot": "input",
2760
+ value: field.value ?? "",
2761
+ ...accessibilityProps,
2762
+ "aria-describedby": `${helperText ? descriptionId : ""} ${hasError ? errorId : ""}`,
2763
+ "aria-expanded": hasSuggestions,
2764
+ "aria-autocomplete": suggestionsDisabled ? void 0 : "list",
2765
+ "aria-controls": hasSuggestions ? `${id}-suggestions` : void 0,
2766
+ "aria-activedescendant": hasSuggestions && highlightedIndex >= 0 ? `${id}-suggestion-${highlightedIndex}` : void 0,
2767
+ disabled: readOnly
2768
+ }), hasSuggestions && /* @__PURE__ */ jsx("div", {
2769
+ id: `${id}-suggestions`,
2770
+ className: cn("absolute z-50 mt-1 w-full rounded-md border border-border bg-popover shadow-md", "max-h-48 overflow-auto"),
2771
+ role: "listbox",
2772
+ children: resolvedSuggestions.map((s, i) => /* @__PURE__ */ jsxs("button", {
2773
+ id: `${id}-suggestion-${i}`,
2774
+ type: "button",
2775
+ role: "option",
2776
+ "aria-selected": i === highlightedIndex,
2777
+ className: cn("flex w-full flex-col px-3 py-2 text-left text-sm", "hover:bg-accent", i === highlightedIndex && "bg-accent"),
2778
+ onMouseDown: (e) => {
2779
+ e.preventDefault();
2780
+ applySuggestion(s);
2781
+ },
2782
+ onMouseEnter: () => setHighlightedIndex(i),
2783
+ children: [/* @__PURE__ */ jsx("span", {
2784
+ className: "font-medium",
2785
+ children: s.label
2786
+ }), /* @__PURE__ */ jsx("span", {
2787
+ className: "truncate font-mono text-xs text-muted-foreground",
2788
+ children: s.value
2789
+ })]
2790
+ }, `${s.value}-${s.description ?? i}`))
2791
+ })]
1861
2792
  }),
1862
2793
  helperText && /* @__PURE__ */ jsx("div", {
1863
2794
  id: descriptionId,
@@ -1876,6 +2807,90 @@ function AddressField({ id, label, placeholder, helperText, control, name, width
1876
2807
  }
1877
2808
  AddressField.displayName = "AddressField";
1878
2809
 
2810
+ //#endregion
2811
+ //#region src/components/fields/address-suggestion/address-suggestion-context.tsx
2812
+ /**
2813
+ * Address Suggestion Context
2814
+ *
2815
+ * Provides a React context for resolving address autocomplete suggestions.
2816
+ * When an `AddressSuggestionProvider` is mounted, every `AddressField`
2817
+ * in the subtree automatically renders a suggestion dropdown as the user types.
2818
+ *
2819
+ * @example
2820
+ * ```tsx
2821
+ * import { AddressSuggestionProvider } from '@openzeppelin/ui-components';
2822
+ * import { useAliasSuggestionResolver } from '@openzeppelin/ui-storage';
2823
+ *
2824
+ * function App() {
2825
+ * const resolver = useAliasSuggestionResolver(db);
2826
+ * return (
2827
+ * <AddressSuggestionProvider {...resolver}>
2828
+ * <MyApp />
2829
+ * </AddressSuggestionProvider>
2830
+ * );
2831
+ * }
2832
+ * ```
2833
+ */
2834
+ /**
2835
+ * Provides address suggestion resolution to all `AddressField` instances in the
2836
+ * subtree. Wrap your application (or a subsection) with this provider and
2837
+ * supply a `resolveSuggestions` function.
2838
+ *
2839
+ * @param props - Resolver function and children
2840
+ *
2841
+ * @example
2842
+ * ```tsx
2843
+ * <AddressSuggestionProvider
2844
+ * resolveSuggestions={(query, networkId) => filterAliases(query, networkId)}
2845
+ * >
2846
+ * <App />
2847
+ * </AddressSuggestionProvider>
2848
+ * ```
2849
+ */
2850
+ function AddressSuggestionProvider({ children, resolveSuggestions }) {
2851
+ const value = React$1.useMemo(() => ({ resolveSuggestions }), [resolveSuggestions]);
2852
+ return /* @__PURE__ */ jsx(AddressSuggestionContext.Provider, {
2853
+ value,
2854
+ children
2855
+ });
2856
+ }
2857
+
2858
+ //#endregion
2859
+ //#region src/components/fields/address-suggestion/useAddressSuggestions.ts
2860
+ /**
2861
+ * Convenience hook that resolves suggestions for a query string using the
2862
+ * nearest `AddressSuggestionProvider`. Returns an empty array when no provider
2863
+ * is mounted or when the query is empty.
2864
+ *
2865
+ * @param query - Current input value to match against
2866
+ * @param networkId - Optional network identifier for scoping results
2867
+ * @returns Object containing the resolved suggestions array
2868
+ *
2869
+ * @example
2870
+ * ```tsx
2871
+ * function MyField({ query }: { query: string }) {
2872
+ * const { suggestions } = useAddressSuggestions(query, 'ethereum-mainnet');
2873
+ * return (
2874
+ * <ul>
2875
+ * {suggestions.map(s => <li key={s.value}>{s.label}</li>)}
2876
+ * </ul>
2877
+ * );
2878
+ * }
2879
+ * ```
2880
+ */
2881
+ /** Resolves address suggestions from the nearest `AddressSuggestionProvider`. */
2882
+ function useAddressSuggestions(query, networkId) {
2883
+ const resolver = React$1.useContext(AddressSuggestionContext);
2884
+ return { suggestions: React$1.useMemo(() => {
2885
+ if (!resolver || !query.trim()) return [];
2886
+ return resolver.resolveSuggestions(query, networkId);
2887
+ }, [
2888
+ resolver,
2889
+ query,
2890
+ networkId
2891
+ ]) };
2892
+ }
2893
+
1879
2894
  //#endregion
1880
2895
  //#region src/components/fields/AmountField.tsx
1881
2896
  /**
@@ -5245,5 +6260,5 @@ const Toaster = ({ ...props }) => {
5245
6260
  };
5246
6261
 
5247
6262
  //#endregion
5248
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AddressDisplay, AddressField, Alert, AlertDescription, AlertTitle, AmountField, ArrayField, ArrayObjectField, Banner, BaseField, BigIntField, BooleanField, Button, BytesField, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, DateRangePicker, DateTimeField, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EcosystemDropdown, EcosystemIcon, EmptyState, EnumField, ErrorMessage, ExternalLink, FileUploadField, Footer, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Header, INTEGER_HTML_PATTERN, INTEGER_INPUT_PATTERN, INTEGER_PATTERN, Input, Label, LoadingButton, MapEntryRow, MapField, MidnightIcon, NetworkErrorNotificationProvider, NetworkIcon, NetworkSelector, NetworkServiceErrorBanner, NetworkStatusBadge, NumberField, ObjectField, PasswordField, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioField, RadioGroup, RadioGroupItem, RelayerDetailsCard, Select, SelectContent, SelectField, SelectGroup, SelectGroupedField, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SidebarButton, SidebarGroup, SidebarLayout, SidebarSection, Tabs, TabsContent, TabsList, TabsTrigger, TextAreaField, TextField, Textarea, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UrlField, ViewContractStateButton, buttonVariants, computeChildTouched, createFocusManager, createValidationResult, formatValidationError, getAccessibilityProps, getDescribedById, getErrorMessage, getValidationStateClasses, getWidthClasses, handleEscapeKey, handleKeyboardEvent, handleNumericKeys, handleToggleKeys, handleValidationError, hasFieldError, isDuplicateMapKey, useDuplicateKeyIndexes, useMapFieldSync, useNetworkErrorAwareAdapter, useNetworkErrorReporter, useNetworkErrors, validateField, validateMapEntries, validateMapStructure };
6263
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AddressDisplay, AddressField, AddressLabelProvider, AddressSuggestionProvider, Alert, AlertDescription, AlertTitle, AmountField, ArrayField, ArrayObjectField, Banner, BaseField, BigIntField, BooleanField, Button, BytesField, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, DateRangePicker, DateTimeField, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EcosystemDropdown, EcosystemIcon, EmptyState, EnumField, ErrorMessage, ExternalLink, FileUploadField, Footer, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Header, INTEGER_HTML_PATTERN, INTEGER_INPUT_PATTERN, INTEGER_PATTERN, Input, Label, LoadingButton, MapEntryRow, MapField, MidnightIcon, NetworkErrorNotificationProvider, NetworkIcon, NetworkSelector, NetworkServiceErrorBanner, NetworkStatusBadge, NumberField, ObjectField, OverflowMenu, PasswordField, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioField, RadioGroup, RadioGroupItem, RelayerDetailsCard, Select, SelectContent, SelectField, SelectGroup, SelectGroupedField, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SidebarButton, SidebarGroup, SidebarLayout, SidebarSection, Tabs, TabsContent, TabsList, TabsTrigger, TextAreaField, TextField, Textarea, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UrlField, ViewContractStateButton, WizardLayout, WizardNavigation, WizardStepper, buttonVariants, computeChildTouched, createFocusManager, createValidationResult, formatValidationError, getAccessibilityProps, getDescribedById, getErrorMessage, getValidationStateClasses, getWidthClasses, handleEscapeKey, handleKeyboardEvent, handleNumericKeys, handleToggleKeys, handleValidationError, hasFieldError, isDuplicateMapKey, useAddressLabel, useAddressSuggestions, useDuplicateKeyIndexes, useMapFieldSync, useNetworkErrorAwareAdapter, useNetworkErrorReporter, useNetworkErrors, validateField, validateMapEntries, validateMapStructure };
5249
6264
  //# sourceMappingURL=index.mjs.map