@openzeppelin/ui-components 1.5.0 → 1.7.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
@@ -6,6 +6,7 @@ import * as React$1 from "react";
6
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
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
9
10
  import { Slot, Slottable } from "@radix-ui/react-slot";
10
11
  import { DayPicker } from "react-day-picker";
11
12
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
@@ -20,11 +21,14 @@ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
20
21
  import * as SelectPrimitive from "@radix-ui/react-select";
21
22
  import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
22
23
  import * as TabsPrimitive from "@radix-ui/react-tabs";
23
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
24
24
  import { isMapEntryArray } from "@openzeppelin/ui-types";
25
25
  import { Toaster as Toaster$1, toast } from "sonner";
26
26
  import { useTheme } from "next-themes";
27
27
 
28
+ //#region src/version.ts
29
+ const VERSION = "1.7.0";
30
+
31
+ //#endregion
28
32
  //#region src/components/ui/accordion.tsx
29
33
  const accordionItemVariants = cva("", {
30
34
  variants: { variant: {
@@ -102,6 +106,19 @@ const AccordionContent = React$1.forwardRef(({ className, children, variant: var
102
106
  });
103
107
  AccordionContent.displayName = "AccordionContent";
104
108
 
109
+ //#endregion
110
+ //#region src/components/ui/tooltip.tsx
111
+ const TooltipProvider = TooltipPrimitive.Provider;
112
+ const Tooltip = TooltipPrimitive.Root;
113
+ const TooltipTrigger = TooltipPrimitive.Trigger;
114
+ const TooltipContent = React$1.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Content, {
115
+ ref,
116
+ sideOffset,
117
+ className: cn("bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md px-3 py-1.5 text-xs", className),
118
+ ...props
119
+ }) }));
120
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
121
+
105
122
  //#endregion
106
123
  //#region src/components/ui/address-display/context.ts
107
124
  /**
@@ -114,8 +131,20 @@ const AddressLabelContext = createContext(null);
114
131
  //#endregion
115
132
  //#region src/components/ui/address-display/address-display.tsx
116
133
  /**
134
+ * True when the primary input can hover (e.g. desktop with mouse).
135
+ * Touch-first phones typically report false. SSR assumes hover-capable.
136
+ */
137
+ function usePrefersHover() {
138
+ return React$1.useSyncExternalStore(React$1.useCallback((onStoreChange) => {
139
+ if (typeof window === "undefined" || typeof window.matchMedia === "undefined") return () => {};
140
+ const mq = window.matchMedia("(hover: hover)");
141
+ mq.addEventListener("change", onStoreChange);
142
+ return () => mq.removeEventListener("change", onStoreChange);
143
+ }, []), () => typeof window !== "undefined" && typeof window.matchMedia !== "undefined" ? window.matchMedia("(hover: hover)").matches : true, () => true);
144
+ }
145
+ /**
117
146
  * Displays a blockchain address with optional truncation, copy button,
118
- * explorer link, and human-readable label.
147
+ * explorer link, tooltip, and human-readable label.
119
148
  *
120
149
  * Labels are resolved in priority order:
121
150
  * 1. Explicit `label` prop
@@ -140,11 +169,22 @@ const AddressLabelContext = createContext(null);
140
169
  *
141
170
  * // Suppress label resolution for a specific instance
142
171
  * <AddressDisplay address="0x742d35Cc..." disableLabel />
172
+ *
173
+ * // Reveal full address on hover (still truncated when idle)
174
+ * <AddressDisplay address="0x742d35Cc..." untruncateOnHover />
175
+ *
176
+ * // Tooltip with full address on hover + copy icon on hover
177
+ * <AddressDisplay address="0x742d35Cc..." showTooltip showCopyButton showCopyButtonOnHover />
178
+ *
179
+ * // Inline variant (no chip background) — useful inside wallet bars
180
+ * <AddressDisplay address="0x742d35Cc..." variant="inline" showTooltip showCopyButton />
143
181
  * ```
144
182
  */
145
- function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4, showCopyButton = false, showCopyButtonOnHover = false, explorerUrl, label: labelProp, onLabelEdit: onLabelEditProp, networkId, disableLabel = false, className, ...props }) {
183
+ function AddressDisplay({ address, truncate = true, untruncateOnHover = false, startChars = 6, endChars = 4, showCopyButton = false, showCopyButtonOnHover = false, explorerUrl, label: labelProp, onLabelEdit: onLabelEditProp, networkId, disableLabel = false, showTooltip = false, variant = "chip", className, onPointerEnter, onPointerLeave, onMouseEnter, onMouseLeave, onClick, ...props }) {
146
184
  const [copied, setCopied] = React$1.useState(false);
185
+ const [isHovered, setIsHovered] = React$1.useState(false);
147
186
  const copyTimeoutRef = React$1.useRef(null);
187
+ const prefersHover = usePrefersHover();
148
188
  const resolver = React$1.useContext(AddressLabelContext);
149
189
  const resolvedLabel = disableLabel ? void 0 : labelProp ?? resolver?.resolveLabel(address, networkId);
150
190
  const contextEditHandler = React$1.useCallback(() => {
@@ -155,7 +195,25 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
155
195
  networkId
156
196
  ]);
157
197
  const editHandler = disableLabel ? void 0 : onLabelEditProp ?? (resolver?.onEditLabel ? contextEditHandler : void 0);
158
- const displayAddress = truncate ? truncateMiddle(address, startChars, endChars) : address;
198
+ const canUntruncate = untruncateOnHover && truncate && !showTooltip;
199
+ const showFullAddress = !truncate || canUntruncate && isHovered;
200
+ const displayAddress = showFullAddress ? address : truncateMiddle(address, startChars, endChars);
201
+ const addressTextClassName = cn(!showFullAddress && "truncate", (showFullAddress || !truncate) && "break-all");
202
+ const expandInteractionClassName = canUntruncate && !prefersHover ? "cursor-pointer" : void 0;
203
+ const handlePointerEnter = (e) => {
204
+ if (canUntruncate && prefersHover) setIsHovered(true);
205
+ onPointerEnter?.(e);
206
+ onMouseEnter?.(e);
207
+ };
208
+ const handlePointerLeave = (e) => {
209
+ if (canUntruncate && prefersHover) setIsHovered(false);
210
+ onPointerLeave?.(e);
211
+ onMouseLeave?.(e);
212
+ };
213
+ const handleUntruncateClick = (e) => {
214
+ if (canUntruncate && !prefersHover) setIsHovered((open) => !open);
215
+ onClick?.(e);
216
+ };
159
217
  const handleCopy = (e) => {
160
218
  e.stopPropagation();
161
219
  navigator.clipboard.writeText(address);
@@ -171,6 +229,7 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
171
229
  if (copyTimeoutRef.current) window.clearTimeout(copyTimeoutRef.current);
172
230
  };
173
231
  }, []);
232
+ const isChip = variant === "chip";
174
233
  const actionButtons = /* @__PURE__ */ jsxs(Fragment, { children: [
175
234
  showCopyButton && /* @__PURE__ */ jsx("button", {
176
235
  type: "button",
@@ -183,6 +242,9 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
183
242
  href: explorerUrl,
184
243
  target: "_blank",
185
244
  rel: "noopener noreferrer",
245
+ onClick: (e) => {
246
+ e.stopPropagation();
247
+ },
186
248
  className: "ml-1.5 shrink-0 text-slate-500 transition-colors hover:text-slate-700",
187
249
  "aria-label": "View in explorer",
188
250
  children: /* @__PURE__ */ jsx(ExternalLink$1, { className: "h-3.5 w-3.5" })
@@ -198,28 +260,48 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
198
260
  children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
199
261
  })
200
262
  ] });
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),
263
+ const shouldShowTooltip = showTooltip && truncate;
264
+ const wrapWithTooltip = (content) => {
265
+ if (!shouldShowTooltip) return content;
266
+ return /* @__PURE__ */ jsx(TooltipProvider, {
267
+ delayDuration: 300,
268
+ children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
269
+ asChild: true,
270
+ children: content
271
+ }), /* @__PURE__ */ jsx(TooltipContent, {
272
+ className: "font-mono text-xs",
273
+ children: address
274
+ })] })
275
+ });
276
+ };
277
+ if (resolvedLabel) return wrapWithTooltip(/* @__PURE__ */ jsxs("div", {
278
+ className: cn("group inline-flex max-w-full min-w-0 flex-col", isChip && "rounded-md bg-slate-100 px-2 py-1", "text-xs text-slate-700", expandInteractionClassName, className),
279
+ onPointerEnter: handlePointerEnter,
280
+ onPointerLeave: handlePointerLeave,
281
+ onClick: handleUntruncateClick,
203
282
  ...props,
204
283
  children: [/* @__PURE__ */ jsx("span", {
205
284
  className: "truncate font-sans font-medium text-slate-900 leading-snug",
206
285
  children: resolvedLabel
207
286
  }), /* @__PURE__ */ jsxs("div", {
208
- className: "flex items-center font-mono text-[10px] text-slate-400 leading-snug",
287
+ className: "flex min-w-0 items-center font-mono text-[10px] text-slate-400 leading-snug",
209
288
  children: [/* @__PURE__ */ jsx("span", {
210
- className: cn("truncate", truncate ? "" : "break-all"),
289
+ className: addressTextClassName,
211
290
  children: displayAddress
212
291
  }), actionButtons]
213
292
  })]
214
- });
215
- return /* @__PURE__ */ jsxs("div", {
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),
293
+ }));
294
+ return wrapWithTooltip(/* @__PURE__ */ jsxs("div", {
295
+ className: cn("group inline-flex max-w-full min-w-0 items-center", isChip && "rounded-md bg-slate-100 px-2 py-1", "text-xs font-mono text-slate-700", expandInteractionClassName, className),
296
+ onPointerEnter: handlePointerEnter,
297
+ onPointerLeave: handlePointerLeave,
298
+ onClick: handleUntruncateClick,
217
299
  ...props,
218
300
  children: [/* @__PURE__ */ jsx("span", {
219
- className: cn("truncate", truncate ? "" : "break-all"),
301
+ className: addressTextClassName,
220
302
  children: displayAddress
221
303
  }), actionButtons]
222
- });
304
+ }));
223
305
  }
224
306
 
225
307
  //#endregion
@@ -1796,19 +1878,6 @@ const Textarea = React$1.forwardRef(({ className, ...props }, ref) => {
1796
1878
  });
1797
1879
  Textarea.displayName = "Textarea";
1798
1880
 
1799
- //#endregion
1800
- //#region src/components/ui/tooltip.tsx
1801
- const TooltipProvider = TooltipPrimitive.Provider;
1802
- const Tooltip = TooltipPrimitive.Root;
1803
- const TooltipTrigger = TooltipPrimitive.Trigger;
1804
- const TooltipContent = React$1.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Content, {
1805
- ref,
1806
- sideOffset,
1807
- className: cn("bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md px-3 py-1.5 text-xs", className),
1808
- ...props
1809
- }));
1810
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
1811
-
1812
1881
  //#endregion
1813
1882
  //#region src/components/ui/view-contract-state-button.tsx
1814
1883
  /**
@@ -6260,5 +6329,5 @@ const Toaster = ({ ...props }) => {
6260
6329
  };
6261
6330
 
6262
6331
  //#endregion
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 };
6332
+ 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, VERSION, 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 };
6264
6333
  //# sourceMappingURL=index.mjs.map