@openzeppelin/ui-components 1.2.1 → 1.4.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,7 +1,7 @@
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
6
  import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
7
7
  import { cn, getDefaultValueForType, getInvalidUrlMessage, getServiceDisplayName, isValidUrl, truncateMiddle, validateBytesSimple } from "@openzeppelin/ui-utils";
@@ -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]
152
222
  });
153
223
  }
154
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
274
+ });
275
+ }
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", {
@@ -606,6 +770,134 @@ const DropdownMenuShortcut = ({ className, ...props }) => {
606
770
  };
607
771
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
608
772
 
773
+ //#endregion
774
+ //#region src/components/ui/ecosystem-dropdown.tsx
775
+ /** Simple dropdown selector for choosing a blockchain ecosystem. */
776
+ function EcosystemDropdown({ options, value, onValueChange, getEcosystemIcon, disabled = false, className, placeholder = "Select blockchain...", "aria-labelledby": ariaLabelledby }) {
777
+ const [open, setOpen] = React$1.useState(false);
778
+ const selectedOption = options.find((o) => o.value === value);
779
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
780
+ open,
781
+ onOpenChange: setOpen,
782
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
783
+ asChild: true,
784
+ children: /* @__PURE__ */ jsxs(Button, {
785
+ variant: "outline",
786
+ role: "combobox",
787
+ "aria-expanded": open,
788
+ "aria-labelledby": ariaLabelledby,
789
+ disabled,
790
+ className: cn("w-full justify-between", className),
791
+ children: [/* @__PURE__ */ jsx("span", {
792
+ className: "flex items-center gap-2 truncate",
793
+ children: selectedOption ? /* @__PURE__ */ jsxs(Fragment, { children: [getEcosystemIcon?.(selectedOption.value), /* @__PURE__ */ jsx("span", {
794
+ className: "truncate",
795
+ children: selectedOption.label
796
+ })] }) : /* @__PURE__ */ jsx("span", {
797
+ className: "text-muted-foreground",
798
+ children: placeholder
799
+ })
800
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
801
+ })
802
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
803
+ className: "w-[--radix-dropdown-menu-trigger-width] min-w-[200px]",
804
+ align: "start",
805
+ children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
806
+ disabled: !option.enabled,
807
+ onSelect: () => {
808
+ onValueChange(option.value);
809
+ setOpen(false);
810
+ },
811
+ className: "gap-2",
812
+ children: [
813
+ getEcosystemIcon?.(option.value),
814
+ /* @__PURE__ */ jsx("span", {
815
+ className: "flex-1 truncate",
816
+ children: option.label
817
+ }),
818
+ !option.enabled && option.disabledLabel && /* @__PURE__ */ jsx("span", {
819
+ className: "shrink-0 text-xs text-muted-foreground",
820
+ children: option.disabledLabel
821
+ }),
822
+ value === option.value && /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 shrink-0 opacity-100" })
823
+ ]
824
+ }, option.value))
825
+ })]
826
+ });
827
+ }
828
+
829
+ //#endregion
830
+ //#region src/components/icons/MidnightIcon.tsx
831
+ /**
832
+ * MidnightIcon - SVG icon for the Midnight blockchain
833
+ * Inline SVG to ensure it renders correctly when this package is consumed as a library
834
+ */
835
+ function MidnightIcon({ size = 16, className = "", variant: _variant }) {
836
+ return /* @__PURE__ */ jsxs("svg", {
837
+ xmlns: "http://www.w3.org/2000/svg",
838
+ viewBox: "0 0 789.37 789.37",
839
+ width: size,
840
+ height: size,
841
+ className,
842
+ "aria-hidden": "true",
843
+ children: [
844
+ /* @__PURE__ */ jsx("path", {
845
+ d: "m394.69,0C176.71,0,0,176.71,0,394.69s176.71,394.69,394.69,394.69,394.69-176.71,394.69-394.69S612.67,0,394.69,0Zm0,716.6c-177.5,0-321.91-144.41-321.91-321.91S217.18,72.78,394.69,72.78s321.91,144.41,321.91,321.91-144.41,321.91-321.91,321.91Z",
846
+ fill: "currentColor"
847
+ }),
848
+ /* @__PURE__ */ jsx("rect", {
849
+ x: "357.64",
850
+ y: "357.64",
851
+ width: "74.09",
852
+ height: "74.09",
853
+ fill: "currentColor"
854
+ }),
855
+ /* @__PURE__ */ jsx("rect", {
856
+ x: "357.64",
857
+ y: "240.66",
858
+ width: "74.09",
859
+ height: "74.09",
860
+ fill: "currentColor"
861
+ }),
862
+ /* @__PURE__ */ jsx("rect", {
863
+ x: "357.64",
864
+ y: "123.69",
865
+ width: "74.09",
866
+ height: "74.09",
867
+ fill: "currentColor"
868
+ })
869
+ ]
870
+ });
871
+ }
872
+
873
+ //#endregion
874
+ //#region src/components/ui/ecosystem-icon.tsx
875
+ /** Displays the appropriate icon for a blockchain ecosystem. */
876
+ function EcosystemIcon({ ecosystem, fallbackLabel, className, size = 16, variant = "branded" }) {
877
+ if (ecosystem.id === "midnight") return /* @__PURE__ */ jsx(MidnightIcon, {
878
+ size,
879
+ variant,
880
+ className: cn("shrink-0", className)
881
+ });
882
+ if (ecosystem.iconComponent) return /* @__PURE__ */ jsx(ecosystem.iconComponent, {
883
+ size,
884
+ variant,
885
+ className: cn("shrink-0", className)
886
+ });
887
+ const initial = (fallbackLabel ?? ecosystem.id).charAt(0).toUpperCase();
888
+ return /* @__PURE__ */ jsx("div", {
889
+ className: cn("bg-muted text-muted-foreground shrink-0 rounded-full flex items-center justify-center font-medium", className),
890
+ style: {
891
+ width: size,
892
+ height: size,
893
+ fontSize: size * .5
894
+ },
895
+ role: "img",
896
+ "aria-label": fallbackLabel ?? ecosystem.id,
897
+ children: initial
898
+ });
899
+ }
900
+
609
901
  //#endregion
610
902
  //#region src/components/ui/empty-state.tsx
611
903
  /**
@@ -931,50 +1223,6 @@ const LoadingButton = React$1.forwardRef(({ className, loading = false, children
931
1223
  });
932
1224
  LoadingButton.displayName = "LoadingButton";
933
1225
 
934
- //#endregion
935
- //#region src/components/icons/MidnightIcon.tsx
936
- /**
937
- * MidnightIcon - SVG icon for the Midnight blockchain
938
- * Inline SVG to ensure it renders correctly when this package is consumed as a library
939
- */
940
- function MidnightIcon({ size = 16, className = "", variant: _variant }) {
941
- return /* @__PURE__ */ jsxs("svg", {
942
- xmlns: "http://www.w3.org/2000/svg",
943
- viewBox: "0 0 789.37 789.37",
944
- width: size,
945
- height: size,
946
- className,
947
- "aria-hidden": "true",
948
- children: [
949
- /* @__PURE__ */ jsx("path", {
950
- d: "m394.69,0C176.71,0,0,176.71,0,394.69s176.71,394.69,394.69,394.69,394.69-176.71,394.69-394.69S612.67,0,394.69,0Zm0,716.6c-177.5,0-321.91-144.41-321.91-321.91S217.18,72.78,394.69,72.78s321.91,144.41,321.91,321.91-144.41,321.91-321.91,321.91Z",
951
- fill: "currentColor"
952
- }),
953
- /* @__PURE__ */ jsx("rect", {
954
- x: "357.64",
955
- y: "357.64",
956
- width: "74.09",
957
- height: "74.09",
958
- fill: "currentColor"
959
- }),
960
- /* @__PURE__ */ jsx("rect", {
961
- x: "357.64",
962
- y: "240.66",
963
- width: "74.09",
964
- height: "74.09",
965
- fill: "currentColor"
966
- }),
967
- /* @__PURE__ */ jsx("rect", {
968
- x: "357.64",
969
- y: "123.69",
970
- width: "74.09",
971
- height: "74.09",
972
- fill: "currentColor"
973
- })
974
- ]
975
- });
976
- }
977
-
978
1226
  //#endregion
979
1227
  //#region src/components/ui/network-icon.tsx
980
1228
  /** Displays the appropriate icon for a blockchain network. */
@@ -1001,10 +1249,15 @@ function NetworkIcon({ network, className, size = 16, variant = "branded" }) {
1001
1249
 
1002
1250
  //#endregion
1003
1251
  //#region src/components/ui/network-selector.tsx
1004
- /** Searchable dropdown selector for blockchain networks with optional grouping. */
1005
- 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 }) {
1006
1254
  const [open, setOpen] = React$1.useState(false);
1007
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;
1008
1261
  const filteredNetworks = React$1.useMemo(() => {
1009
1262
  if (!searchQuery) return networks;
1010
1263
  if (filterNetwork) return networks.filter((n) => filterNetwork(n, searchQuery));
@@ -1028,34 +1281,79 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1028
1281
  groupByEcosystem,
1029
1282
  getEcosystem
1030
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;
1031
1313
  return /* @__PURE__ */ jsxs(DropdownMenu, {
1032
1314
  open,
1033
1315
  onOpenChange: setOpen,
1034
1316
  children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
1035
1317
  asChild: true,
1036
- children: /* @__PURE__ */ jsxs(Button, {
1037
- variant: "outline",
1038
- role: "combobox",
1039
- "aria-expanded": open,
1040
- className: cn("w-full justify-between", className),
1041
- children: [/* @__PURE__ */ jsx("span", {
1042
- className: "flex items-center gap-2 truncate",
1043
- children: selectedNetwork ? /* @__PURE__ */ jsxs(Fragment, { children: [
1044
- getNetworkIcon?.(selectedNetwork),
1045
- /* @__PURE__ */ jsx("span", {
1046
- className: "truncate",
1047
- children: getNetworkLabel(selectedNetwork)
1048
- }),
1049
- getNetworkType && /* @__PURE__ */ jsx("span", {
1050
- className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase text-muted-foreground",
1051
- 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
1052
1353
  })
1053
- ] }) : /* @__PURE__ */ jsx("span", {
1054
- className: "text-muted-foreground",
1055
- children: placeholder
1056
- })
1057
- }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
1058
- })
1354
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
1355
+ });
1356
+ })()
1059
1357
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
1060
1358
  className: "w-[--radix-dropdown-menu-trigger-width] min-w-[240px] p-0",
1061
1359
  align: "start",
@@ -1071,9 +1369,19 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1071
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",
1072
1370
  "aria-label": "Search networks"
1073
1371
  })]
1074
- }), /* @__PURE__ */ jsx("div", {
1372
+ }), /* @__PURE__ */ jsxs("div", {
1075
1373
  className: "max-h-[300px] overflow-y-auto p-1",
1076
- 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", {
1077
1385
  className: "py-6 text-center text-sm text-muted-foreground",
1078
1386
  children: "No network found."
1079
1387
  }) : Object.entries(groupedNetworks).map(([group, groupNetworks], index) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [
@@ -1082,12 +1390,16 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1082
1390
  children: group
1083
1391
  }),
1084
1392
  /* @__PURE__ */ jsx(DropdownMenuGroup, { children: groupNetworks.map((network) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
1085
- onSelect: () => {
1086
- onSelectNetwork(network);
1087
- setOpen(false);
1393
+ onSelect: (e) => {
1394
+ if (isMultiple) e.preventDefault();
1395
+ handleSelect(network);
1088
1396
  },
1089
1397
  className: "gap-2",
1090
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,
1091
1403
  getNetworkIcon?.(network),
1092
1404
  /* @__PURE__ */ jsxs("div", {
1093
1405
  className: "flex flex-1 items-center gap-2 min-w-0",
@@ -1099,11 +1411,11 @@ function NetworkSelector({ networks, selectedNetwork, onSelectNetwork, getNetwor
1099
1411
  children: getNetworkType(network)
1100
1412
  })]
1101
1413
  }),
1102
- 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" })
1103
1415
  ]
1104
1416
  }, getNetworkId(network))) }),
1105
1417
  index < Object.keys(groupedNetworks).length - 1 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {})
1106
- ] }, group))
1418
+ ] }, group))]
1107
1419
  })]
1108
1420
  })]
1109
1421
  });
@@ -1136,6 +1448,32 @@ function NetworkStatusBadge({ network, className }) {
1136
1448
  });
1137
1449
  }
1138
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
+
1139
1477
  //#endregion
1140
1478
  //#region src/components/ui/progress.tsx
1141
1479
  const Progress = React$1.forwardRef(({ className, value, ...props }, ref) => /* @__PURE__ */ jsx(ProgressPrimitive.Root, {
@@ -1505,6 +1843,15 @@ function ViewContractStateButton({ contractAddress, onToggle }) {
1505
1843
  });
1506
1844
  }
1507
1845
 
1846
+ //#endregion
1847
+ //#region src/components/fields/address-suggestion/context.ts
1848
+ /**
1849
+ * @internal Shared context instance consumed by both AddressField and
1850
+ * AddressSuggestionProvider. Kept in its own file so component files export
1851
+ * only components (required by React Fast Refresh).
1852
+ */
1853
+ const AddressSuggestionContext = createContext(null);
1854
+
1508
1855
  //#endregion
1509
1856
  //#region src/components/fields/utils/accessibility.ts
1510
1857
  /**
@@ -1696,6 +2043,8 @@ function getWidthClasses(width) {
1696
2043
 
1697
2044
  //#endregion
1698
2045
  //#region src/components/fields/AddressField.tsx
2046
+ const DEBOUNCE_MS = 200;
2047
+ const MAX_SUGGESTIONS = 5;
1699
2048
  /**
1700
2049
  * Address input field component specifically designed for blockchain addresses via React Hook Form integration.
1701
2050
  *
@@ -1713,11 +2062,82 @@ function getWidthClasses(width) {
1713
2062
  * - Chain-agnostic design (validation handled by adapters)
1714
2063
  * - Full accessibility support with ARIA attributes
1715
2064
  * - Keyboard navigation
2065
+ *
2066
+ * Autocomplete suggestions can be provided in two ways:
2067
+ *
2068
+ * 1. **Context-based (zero-config)**: Mount an `AddressSuggestionProvider` in the
2069
+ * component tree. Every `AddressField` below it automatically resolves suggestions.
2070
+ *
2071
+ * 2. **Prop-based (explicit)**: Pass `suggestions` directly. This overrides context.
2072
+ * Pass `suggestions={false}` to opt out when a provider is mounted.
2073
+ *
2074
+ * The suggestion dropdown includes built-in debouncing, keyboard navigation (Arrow keys,
2075
+ * Enter, Escape), click-outside dismissal, and ARIA listbox semantics.
1716
2076
  */
1717
- function AddressField({ id, label, placeholder, helperText, control, name, width = "full", validation, adapter, readOnly }) {
2077
+ function AddressField({ id, label, placeholder, helperText, control, name, width = "full", validation, adapter, readOnly, suggestions: suggestionsProp, onSuggestionSelect }) {
1718
2078
  const isRequired = !!validation?.required;
1719
2079
  const errorId = `${id}-error`;
1720
2080
  const descriptionId = `${id}-description`;
2081
+ const contextResolver = useContext(AddressSuggestionContext);
2082
+ const containerRef = useRef(null);
2083
+ const lastSetValueRef = useRef("");
2084
+ const [inputValue, setInputValue] = useState("");
2085
+ const [debouncedQuery, setDebouncedQuery] = useState("");
2086
+ const [showSuggestions, setShowSuggestions] = useState(false);
2087
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
2088
+ const watchedFieldValue = useWatch({
2089
+ control,
2090
+ name
2091
+ });
2092
+ useEffect(() => {
2093
+ const currentFieldValue = watchedFieldValue ?? "";
2094
+ if (currentFieldValue !== lastSetValueRef.current) {
2095
+ lastSetValueRef.current = currentFieldValue;
2096
+ setInputValue(currentFieldValue);
2097
+ }
2098
+ }, [watchedFieldValue]);
2099
+ useEffect(() => {
2100
+ if (!inputValue.trim()) {
2101
+ setDebouncedQuery("");
2102
+ return;
2103
+ }
2104
+ const timer = setTimeout(() => setDebouncedQuery(inputValue), DEBOUNCE_MS);
2105
+ return () => clearTimeout(timer);
2106
+ }, [inputValue]);
2107
+ const suggestionsDisabled = suggestionsProp === false;
2108
+ const resolvedSuggestions = useMemo(() => {
2109
+ if (suggestionsDisabled) return [];
2110
+ if (Array.isArray(suggestionsProp)) return suggestionsProp;
2111
+ if (!contextResolver || !debouncedQuery.trim()) return [];
2112
+ return contextResolver.resolveSuggestions(debouncedQuery).slice(0, MAX_SUGGESTIONS);
2113
+ }, [
2114
+ suggestionsDisabled,
2115
+ suggestionsProp,
2116
+ contextResolver,
2117
+ debouncedQuery
2118
+ ]);
2119
+ const hasSuggestions = showSuggestions && resolvedSuggestions.length > 0;
2120
+ useEffect(() => {
2121
+ let active = true;
2122
+ const handleClickOutside = (e) => {
2123
+ if (active && containerRef.current && !containerRef.current.contains(e.target)) setShowSuggestions(false);
2124
+ };
2125
+ document.addEventListener("mousedown", handleClickOutside);
2126
+ return () => {
2127
+ active = false;
2128
+ document.removeEventListener("mousedown", handleClickOutside);
2129
+ };
2130
+ }, []);
2131
+ const handleSuggestionKeyDown = useCallback((e) => {
2132
+ if (!hasSuggestions) return;
2133
+ if (e.key === "ArrowDown") {
2134
+ e.preventDefault();
2135
+ setHighlightedIndex((prev) => prev < resolvedSuggestions.length - 1 ? prev + 1 : 0);
2136
+ } else if (e.key === "ArrowUp") {
2137
+ e.preventDefault();
2138
+ setHighlightedIndex((prev) => prev > 0 ? prev - 1 : resolvedSuggestions.length - 1);
2139
+ }
2140
+ }, [hasSuggestions, resolvedSuggestions.length]);
1721
2141
  return /* @__PURE__ */ jsxs("div", {
1722
2142
  className: `flex flex-col gap-2 ${width === "full" ? "w-full" : width === "half" ? "w-1/2" : "w-1/3"}`,
1723
2143
  children: [label && /* @__PURE__ */ jsxs(Label, {
@@ -1751,9 +2171,32 @@ function AddressField({ id, label, placeholder, helperText, control, name, width
1751
2171
  const handleInputChange = (e) => {
1752
2172
  const value = e.target.value;
1753
2173
  field.onChange(value);
2174
+ lastSetValueRef.current = value;
2175
+ setInputValue(value);
2176
+ setShowSuggestions(value.length > 0);
2177
+ setHighlightedIndex(-1);
2178
+ };
2179
+ const applySuggestion = (suggestion) => {
2180
+ field.onChange(suggestion.value);
2181
+ onSuggestionSelect?.(suggestion);
2182
+ lastSetValueRef.current = suggestion.value;
2183
+ setInputValue(suggestion.value);
2184
+ setShowSuggestions(false);
2185
+ setHighlightedIndex(-1);
1754
2186
  };
1755
2187
  const handleKeyDown = (e) => {
1756
- if (e.key === "Escape") handleEscapeKey(field.onChange, field.value)(e);
2188
+ if (hasSuggestions && e.key === "Enter" && highlightedIndex >= 0) {
2189
+ e.preventDefault();
2190
+ applySuggestion(resolvedSuggestions[highlightedIndex]);
2191
+ return;
2192
+ }
2193
+ if (e.key === "Escape") {
2194
+ if (hasSuggestions) {
2195
+ setShowSuggestions(false);
2196
+ return;
2197
+ }
2198
+ handleEscapeKey(field.onChange, field.value)(e);
2199
+ }
1757
2200
  };
1758
2201
  const accessibilityProps = getAccessibilityProps({
1759
2202
  id,
@@ -1762,18 +2205,50 @@ function AddressField({ id, label, placeholder, helperText, control, name, width
1762
2205
  hasHelperText: !!helperText
1763
2206
  });
1764
2207
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1765
- /* @__PURE__ */ jsx(Input, {
1766
- ...field,
1767
- id,
1768
- placeholder: placeholder || "0x...",
1769
- className: validationClasses,
1770
- onChange: handleInputChange,
1771
- onKeyDown: handleKeyDown,
1772
- "data-slot": "input",
1773
- value: field.value ?? "",
1774
- ...accessibilityProps,
1775
- "aria-describedby": `${helperText ? descriptionId : ""} ${hasError ? errorId : ""}`,
1776
- disabled: readOnly
2208
+ /* @__PURE__ */ jsxs("div", {
2209
+ ref: containerRef,
2210
+ className: "relative",
2211
+ onKeyDown: handleSuggestionKeyDown,
2212
+ children: [/* @__PURE__ */ jsx(Input, {
2213
+ ...field,
2214
+ id,
2215
+ placeholder: placeholder || "0x...",
2216
+ className: validationClasses,
2217
+ onChange: handleInputChange,
2218
+ onKeyDown: handleKeyDown,
2219
+ "data-slot": "input",
2220
+ value: field.value ?? "",
2221
+ ...accessibilityProps,
2222
+ "aria-describedby": `${helperText ? descriptionId : ""} ${hasError ? errorId : ""}`,
2223
+ "aria-expanded": hasSuggestions,
2224
+ "aria-autocomplete": suggestionsDisabled ? void 0 : "list",
2225
+ "aria-controls": hasSuggestions ? `${id}-suggestions` : void 0,
2226
+ "aria-activedescendant": hasSuggestions && highlightedIndex >= 0 ? `${id}-suggestion-${highlightedIndex}` : void 0,
2227
+ disabled: readOnly
2228
+ }), hasSuggestions && /* @__PURE__ */ jsx("div", {
2229
+ id: `${id}-suggestions`,
2230
+ className: cn("absolute z-50 mt-1 w-full rounded-md border border-border bg-popover shadow-md", "max-h-48 overflow-auto"),
2231
+ role: "listbox",
2232
+ children: resolvedSuggestions.map((s, i) => /* @__PURE__ */ jsxs("button", {
2233
+ id: `${id}-suggestion-${i}`,
2234
+ type: "button",
2235
+ role: "option",
2236
+ "aria-selected": i === highlightedIndex,
2237
+ className: cn("flex w-full flex-col px-3 py-2 text-left text-sm", "hover:bg-accent", i === highlightedIndex && "bg-accent"),
2238
+ onMouseDown: (e) => {
2239
+ e.preventDefault();
2240
+ applySuggestion(s);
2241
+ },
2242
+ onMouseEnter: () => setHighlightedIndex(i),
2243
+ children: [/* @__PURE__ */ jsx("span", {
2244
+ className: "font-medium",
2245
+ children: s.label
2246
+ }), /* @__PURE__ */ jsx("span", {
2247
+ className: "truncate font-mono text-xs text-muted-foreground",
2248
+ children: s.value
2249
+ })]
2250
+ }, `${s.value}-${s.description ?? i}`))
2251
+ })]
1777
2252
  }),
1778
2253
  helperText && /* @__PURE__ */ jsx("div", {
1779
2254
  id: descriptionId,
@@ -1792,6 +2267,90 @@ function AddressField({ id, label, placeholder, helperText, control, name, width
1792
2267
  }
1793
2268
  AddressField.displayName = "AddressField";
1794
2269
 
2270
+ //#endregion
2271
+ //#region src/components/fields/address-suggestion/address-suggestion-context.tsx
2272
+ /**
2273
+ * Address Suggestion Context
2274
+ *
2275
+ * Provides a React context for resolving address autocomplete suggestions.
2276
+ * When an `AddressSuggestionProvider` is mounted, every `AddressField`
2277
+ * in the subtree automatically renders a suggestion dropdown as the user types.
2278
+ *
2279
+ * @example
2280
+ * ```tsx
2281
+ * import { AddressSuggestionProvider } from '@openzeppelin/ui-components';
2282
+ * import { useAliasSuggestionResolver } from '@openzeppelin/ui-storage';
2283
+ *
2284
+ * function App() {
2285
+ * const resolver = useAliasSuggestionResolver(db);
2286
+ * return (
2287
+ * <AddressSuggestionProvider {...resolver}>
2288
+ * <MyApp />
2289
+ * </AddressSuggestionProvider>
2290
+ * );
2291
+ * }
2292
+ * ```
2293
+ */
2294
+ /**
2295
+ * Provides address suggestion resolution to all `AddressField` instances in the
2296
+ * subtree. Wrap your application (or a subsection) with this provider and
2297
+ * supply a `resolveSuggestions` function.
2298
+ *
2299
+ * @param props - Resolver function and children
2300
+ *
2301
+ * @example
2302
+ * ```tsx
2303
+ * <AddressSuggestionProvider
2304
+ * resolveSuggestions={(query, networkId) => filterAliases(query, networkId)}
2305
+ * >
2306
+ * <App />
2307
+ * </AddressSuggestionProvider>
2308
+ * ```
2309
+ */
2310
+ function AddressSuggestionProvider({ children, resolveSuggestions }) {
2311
+ const value = React$1.useMemo(() => ({ resolveSuggestions }), [resolveSuggestions]);
2312
+ return /* @__PURE__ */ jsx(AddressSuggestionContext.Provider, {
2313
+ value,
2314
+ children
2315
+ });
2316
+ }
2317
+
2318
+ //#endregion
2319
+ //#region src/components/fields/address-suggestion/useAddressSuggestions.ts
2320
+ /**
2321
+ * Convenience hook that resolves suggestions for a query string using the
2322
+ * nearest `AddressSuggestionProvider`. Returns an empty array when no provider
2323
+ * is mounted or when the query is empty.
2324
+ *
2325
+ * @param query - Current input value to match against
2326
+ * @param networkId - Optional network identifier for scoping results
2327
+ * @returns Object containing the resolved suggestions array
2328
+ *
2329
+ * @example
2330
+ * ```tsx
2331
+ * function MyField({ query }: { query: string }) {
2332
+ * const { suggestions } = useAddressSuggestions(query, 'ethereum-mainnet');
2333
+ * return (
2334
+ * <ul>
2335
+ * {suggestions.map(s => <li key={s.value}>{s.label}</li>)}
2336
+ * </ul>
2337
+ * );
2338
+ * }
2339
+ * ```
2340
+ */
2341
+ /** Resolves address suggestions from the nearest `AddressSuggestionProvider`. */
2342
+ function useAddressSuggestions(query, networkId) {
2343
+ const resolver = React$1.useContext(AddressSuggestionContext);
2344
+ return { suggestions: React$1.useMemo(() => {
2345
+ if (!resolver || !query.trim()) return [];
2346
+ return resolver.resolveSuggestions(query, networkId);
2347
+ }, [
2348
+ resolver,
2349
+ query,
2350
+ networkId
2351
+ ]) };
2352
+ }
2353
+
1795
2354
  //#endregion
1796
2355
  //#region src/components/fields/AmountField.tsx
1797
2356
  /**
@@ -5161,5 +5720,5 @@ const Toaster = ({ ...props }) => {
5161
5720
  };
5162
5721
 
5163
5722
  //#endregion
5164
- 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, 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 };
5723
+ 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, 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 };
5165
5724
  //# sourceMappingURL=index.mjs.map