@openzeppelin/ui-components 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -7,6 +7,8 @@ let react = require("react");
7
7
  react = require_ErrorMessage.__toESM(react);
8
8
  let _openzeppelin_ui_utils = require("@openzeppelin/ui-utils");
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
+ let _radix_ui_react_tooltip = require("@radix-ui/react-tooltip");
11
+ _radix_ui_react_tooltip = require_ErrorMessage.__toESM(_radix_ui_react_tooltip);
10
12
  let _radix_ui_react_slot = require("@radix-ui/react-slot");
11
13
  let react_day_picker = require("react-day-picker");
12
14
  let _radix_ui_react_checkbox = require("@radix-ui/react-checkbox");
@@ -31,8 +33,6 @@ let _radix_ui_react_collapsible = require("@radix-ui/react-collapsible");
31
33
  _radix_ui_react_collapsible = require_ErrorMessage.__toESM(_radix_ui_react_collapsible);
32
34
  let _radix_ui_react_tabs = require("@radix-ui/react-tabs");
33
35
  _radix_ui_react_tabs = require_ErrorMessage.__toESM(_radix_ui_react_tabs);
34
- let _radix_ui_react_tooltip = require("@radix-ui/react-tooltip");
35
- _radix_ui_react_tooltip = require_ErrorMessage.__toESM(_radix_ui_react_tooltip);
36
36
  let _openzeppelin_ui_types = require("@openzeppelin/ui-types");
37
37
  let sonner = require("sonner");
38
38
  let next_themes = require("next-themes");
@@ -114,6 +114,19 @@ const AccordionContent = react.forwardRef(({ className, children, variant: varia
114
114
  });
115
115
  AccordionContent.displayName = "AccordionContent";
116
116
 
117
+ //#endregion
118
+ //#region src/components/ui/tooltip.tsx
119
+ const TooltipProvider = _radix_ui_react_tooltip.Provider;
120
+ const Tooltip = _radix_ui_react_tooltip.Root;
121
+ const TooltipTrigger = _radix_ui_react_tooltip.Trigger;
122
+ const TooltipContent = react.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_tooltip.Portal, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_tooltip.Content, {
123
+ ref,
124
+ sideOffset,
125
+ className: (0, _openzeppelin_ui_utils.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),
126
+ ...props
127
+ }) }));
128
+ TooltipContent.displayName = _radix_ui_react_tooltip.Content.displayName;
129
+
117
130
  //#endregion
118
131
  //#region src/components/ui/address-display/context.ts
119
132
  /**
@@ -126,8 +139,20 @@ const AddressLabelContext = (0, react.createContext)(null);
126
139
  //#endregion
127
140
  //#region src/components/ui/address-display/address-display.tsx
128
141
  /**
142
+ * True when the primary input can hover (e.g. desktop with mouse).
143
+ * Touch-first phones typically report false. SSR assumes hover-capable.
144
+ */
145
+ function usePrefersHover() {
146
+ return react.useSyncExternalStore(react.useCallback((onStoreChange) => {
147
+ if (typeof window === "undefined" || typeof window.matchMedia === "undefined") return () => {};
148
+ const mq = window.matchMedia("(hover: hover)");
149
+ mq.addEventListener("change", onStoreChange);
150
+ return () => mq.removeEventListener("change", onStoreChange);
151
+ }, []), () => typeof window !== "undefined" && typeof window.matchMedia !== "undefined" ? window.matchMedia("(hover: hover)").matches : true, () => true);
152
+ }
153
+ /**
129
154
  * Displays a blockchain address with optional truncation, copy button,
130
- * explorer link, and human-readable label.
155
+ * explorer link, tooltip, and human-readable label.
131
156
  *
132
157
  * Labels are resolved in priority order:
133
158
  * 1. Explicit `label` prop
@@ -152,11 +177,22 @@ const AddressLabelContext = (0, react.createContext)(null);
152
177
  *
153
178
  * // Suppress label resolution for a specific instance
154
179
  * <AddressDisplay address="0x742d35Cc..." disableLabel />
180
+ *
181
+ * // Reveal full address on hover (still truncated when idle)
182
+ * <AddressDisplay address="0x742d35Cc..." untruncateOnHover />
183
+ *
184
+ * // Tooltip with full address on hover + copy icon on hover
185
+ * <AddressDisplay address="0x742d35Cc..." showTooltip showCopyButton showCopyButtonOnHover />
186
+ *
187
+ * // Inline variant (no chip background) — useful inside wallet bars
188
+ * <AddressDisplay address="0x742d35Cc..." variant="inline" showTooltip showCopyButton />
155
189
  * ```
156
190
  */
157
- function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4, showCopyButton = false, showCopyButtonOnHover = false, explorerUrl, label: labelProp, onLabelEdit: onLabelEditProp, networkId, disableLabel = false, className, ...props }) {
191
+ 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 }) {
158
192
  const [copied, setCopied] = react.useState(false);
193
+ const [isHovered, setIsHovered] = react.useState(false);
159
194
  const copyTimeoutRef = react.useRef(null);
195
+ const prefersHover = usePrefersHover();
160
196
  const resolver = react.useContext(AddressLabelContext);
161
197
  const resolvedLabel = disableLabel ? void 0 : labelProp ?? resolver?.resolveLabel(address, networkId);
162
198
  const contextEditHandler = react.useCallback(() => {
@@ -167,7 +203,25 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
167
203
  networkId
168
204
  ]);
169
205
  const editHandler = disableLabel ? void 0 : onLabelEditProp ?? (resolver?.onEditLabel ? contextEditHandler : void 0);
170
- const displayAddress = truncate ? (0, _openzeppelin_ui_utils.truncateMiddle)(address, startChars, endChars) : address;
206
+ const canUntruncate = untruncateOnHover && truncate && !showTooltip;
207
+ const showFullAddress = !truncate || canUntruncate && isHovered;
208
+ const displayAddress = showFullAddress ? address : (0, _openzeppelin_ui_utils.truncateMiddle)(address, startChars, endChars);
209
+ const addressTextClassName = (0, _openzeppelin_ui_utils.cn)(!showFullAddress && "truncate", (showFullAddress || !truncate) && "break-all");
210
+ const expandInteractionClassName = canUntruncate && !prefersHover ? "cursor-pointer" : void 0;
211
+ const handlePointerEnter = (e) => {
212
+ if (canUntruncate && prefersHover) setIsHovered(true);
213
+ onPointerEnter?.(e);
214
+ onMouseEnter?.(e);
215
+ };
216
+ const handlePointerLeave = (e) => {
217
+ if (canUntruncate && prefersHover) setIsHovered(false);
218
+ onPointerLeave?.(e);
219
+ onMouseLeave?.(e);
220
+ };
221
+ const handleUntruncateClick = (e) => {
222
+ if (canUntruncate && !prefersHover) setIsHovered((open) => !open);
223
+ onClick?.(e);
224
+ };
171
225
  const handleCopy = (e) => {
172
226
  e.stopPropagation();
173
227
  navigator.clipboard.writeText(address);
@@ -183,6 +237,7 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
183
237
  if (copyTimeoutRef.current) window.clearTimeout(copyTimeoutRef.current);
184
238
  };
185
239
  }, []);
240
+ const isChip = variant === "chip";
186
241
  const actionButtons = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
187
242
  showCopyButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
188
243
  type: "button",
@@ -195,6 +250,9 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
195
250
  href: explorerUrl,
196
251
  target: "_blank",
197
252
  rel: "noopener noreferrer",
253
+ onClick: (e) => {
254
+ e.stopPropagation();
255
+ },
198
256
  className: "ml-1.5 shrink-0 text-slate-500 transition-colors hover:text-slate-700",
199
257
  "aria-label": "View in explorer",
200
258
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ExternalLink, { className: "h-3.5 w-3.5" })
@@ -210,28 +268,48 @@ function AddressDisplay({ address, truncate = true, startChars = 6, endChars = 4
210
268
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Pencil, { className: "h-3.5 w-3.5" })
211
269
  })
212
270
  ] });
213
- if (resolvedLabel) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
214
- className: (0, _openzeppelin_ui_utils.cn)("group inline-flex max-w-full flex-col rounded-md bg-slate-100 px-2 py-1", "text-xs text-slate-700", className),
271
+ const shouldShowTooltip = showTooltip && truncate;
272
+ const wrapWithTooltip = (content) => {
273
+ if (!shouldShowTooltip) return content;
274
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipProvider, {
275
+ delayDuration: 300,
276
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Tooltip, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTrigger, {
277
+ asChild: true,
278
+ children: content
279
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipContent, {
280
+ className: "font-mono text-xs",
281
+ children: address
282
+ })] })
283
+ });
284
+ };
285
+ if (resolvedLabel) return wrapWithTooltip(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
286
+ className: (0, _openzeppelin_ui_utils.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),
287
+ onPointerEnter: handlePointerEnter,
288
+ onPointerLeave: handlePointerLeave,
289
+ onClick: handleUntruncateClick,
215
290
  ...props,
216
291
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
217
292
  className: "truncate font-sans font-medium text-slate-900 leading-snug",
218
293
  children: resolvedLabel
219
294
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
220
- className: "flex items-center font-mono text-[10px] text-slate-400 leading-snug",
295
+ className: "flex min-w-0 items-center font-mono text-[10px] text-slate-400 leading-snug",
221
296
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
222
- className: (0, _openzeppelin_ui_utils.cn)("truncate", truncate ? "" : "break-all"),
297
+ className: addressTextClassName,
223
298
  children: displayAddress
224
299
  }), actionButtons]
225
300
  })]
226
- });
227
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
228
- className: (0, _openzeppelin_ui_utils.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),
301
+ }));
302
+ return wrapWithTooltip(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
303
+ className: (0, _openzeppelin_ui_utils.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),
304
+ onPointerEnter: handlePointerEnter,
305
+ onPointerLeave: handlePointerLeave,
306
+ onClick: handleUntruncateClick,
229
307
  ...props,
230
308
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
231
- className: (0, _openzeppelin_ui_utils.cn)("truncate", truncate ? "" : "break-all"),
309
+ className: addressTextClassName,
232
310
  children: displayAddress
233
311
  }), actionButtons]
234
- });
312
+ }));
235
313
  }
236
314
 
237
315
  //#endregion
@@ -1605,12 +1683,12 @@ SelectSeparator.displayName = _radix_ui_react_select.Separator.displayName;
1605
1683
  * Can render as a button or anchor element depending on whether href is provided.
1606
1684
  */
1607
1685
  function SidebarButton({ icon, children, onClick, size = "default", badge, disabled = false, isSelected = false, href, target, rel, className }) {
1608
- const commonClass = (0, _openzeppelin_ui_utils.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);
1686
+ const commonClass = (0, _openzeppelin_ui_utils.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);
1609
1687
  const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1610
1688
  className: "flex items-center gap-2",
1611
1689
  children: [icon, children]
1612
1690
  }), badge && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1613
- className: "text-xs px-2 py-1 bg-muted text-muted-foreground rounded-full font-medium",
1691
+ className: "text-xs px-2 py-0.5 bg-muted text-muted-foreground rounded-full font-medium",
1614
1692
  children: badge
1615
1693
  })] });
1616
1694
  if (href) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
@@ -1808,19 +1886,6 @@ const Textarea = react.forwardRef(({ className, ...props }, ref) => {
1808
1886
  });
1809
1887
  Textarea.displayName = "Textarea";
1810
1888
 
1811
- //#endregion
1812
- //#region src/components/ui/tooltip.tsx
1813
- const TooltipProvider = _radix_ui_react_tooltip.Provider;
1814
- const Tooltip = _radix_ui_react_tooltip.Root;
1815
- const TooltipTrigger = _radix_ui_react_tooltip.Trigger;
1816
- const TooltipContent = react.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_tooltip.Content, {
1817
- ref,
1818
- sideOffset,
1819
- className: (0, _openzeppelin_ui_utils.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),
1820
- ...props
1821
- }));
1822
- TooltipContent.displayName = _radix_ui_react_tooltip.Content.displayName;
1823
-
1824
1889
  //#endregion
1825
1890
  //#region src/components/ui/view-contract-state-button.tsx
1826
1891
  /**
@@ -1855,6 +1920,546 @@ function ViewContractStateButton({ contractAddress, onToggle }) {
1855
1920
  });
1856
1921
  }
1857
1922
 
1923
+ //#endregion
1924
+ //#region src/components/ui/wizard/WizardStepper.tsx
1925
+ function resolveState(step, index, currentStepIndex, furthestStepIndex) {
1926
+ if (step.status === "completed" || step.status === "skipped") return "completed";
1927
+ if (index === currentStepIndex) return "current";
1928
+ if (step.isInvalid && (index < currentStepIndex || index <= furthestStepIndex)) return "invalid";
1929
+ if (index < currentStepIndex) return "completed";
1930
+ if (index <= furthestStepIndex) return "visited";
1931
+ return "upcoming";
1932
+ }
1933
+ function canClick(state, freeNavigation = false) {
1934
+ if (freeNavigation) return true;
1935
+ return state !== "upcoming";
1936
+ }
1937
+ function StepCircle({ state, index }) {
1938
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1939
+ className: (0, _openzeppelin_ui_utils.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"),
1940
+ children: state === "completed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, { className: "size-3.5" }) : state === "visited" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Pencil, { className: "size-3" }) : state === "invalid" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.AlertCircle, { className: "size-3.5" }) : index + 1
1941
+ });
1942
+ }
1943
+ function StepLabel({ title, state, isSkipped }) {
1944
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1945
+ className: "min-w-0 flex-1",
1946
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1947
+ className: (0, _openzeppelin_ui_utils.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"),
1948
+ children: title
1949
+ }), isSkipped && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1950
+ className: "mt-0.5 block text-[11px] text-zinc-400",
1951
+ children: "Skipped"
1952
+ })]
1953
+ });
1954
+ }
1955
+ function VerticalStepper({ steps, currentStepIndex, furthestStepIndex = currentStepIndex, onStepClick, freeNavigation, className }) {
1956
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
1957
+ "aria-label": "Wizard steps",
1958
+ className: (0, _openzeppelin_ui_utils.cn)("rounded-2xl border border-zinc-200 bg-white p-6", className),
1959
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1960
+ className: "flex flex-col gap-1",
1961
+ children: steps.map((step, index) => {
1962
+ const state = resolveState(step, index, currentStepIndex, furthestStepIndex);
1963
+ const clickable = canClick(state, freeNavigation) && !!onStepClick;
1964
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1965
+ type: "button",
1966
+ onClick: () => clickable && onStepClick?.(index),
1967
+ disabled: !clickable,
1968
+ className: (0, _openzeppelin_ui_utils.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"),
1969
+ "aria-current": state === "current" ? "step" : void 0,
1970
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCircle, {
1971
+ state,
1972
+ index
1973
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, {
1974
+ title: step.title,
1975
+ state,
1976
+ isSkipped: step.status === "skipped"
1977
+ })]
1978
+ }, step.id);
1979
+ })
1980
+ })
1981
+ });
1982
+ }
1983
+ function HorizontalStepper({ steps, currentStepIndex, furthestStepIndex = currentStepIndex, onStepClick, freeNavigation, className }) {
1984
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
1985
+ "aria-label": "Wizard steps",
1986
+ className: (0, _openzeppelin_ui_utils.cn)("rounded-2xl border border-zinc-200 bg-white p-6", className),
1987
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1988
+ className: "flex w-full items-center",
1989
+ children: steps.map((step, index) => {
1990
+ const state = resolveState(step, index, currentStepIndex, furthestStepIndex);
1991
+ const clickable = canClick(state, freeNavigation) && !!onStepClick;
1992
+ const isLast = index === steps.length - 1;
1993
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.default.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1994
+ type: "button",
1995
+ onClick: () => clickable && onStepClick?.(index),
1996
+ disabled: !clickable,
1997
+ className: (0, _openzeppelin_ui_utils.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"),
1998
+ "aria-current": state === "current" ? "step" : void 0,
1999
+ "aria-label": `Step ${index + 1}: ${step.title}`,
2000
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCircle, {
2001
+ state,
2002
+ index
2003
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2004
+ className: "hidden sm:block",
2005
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, {
2006
+ title: step.title,
2007
+ state,
2008
+ isSkipped: step.status === "skipped"
2009
+ })
2010
+ })]
2011
+ }), !isLast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: (0, _openzeppelin_ui_utils.cn)("mx-1 h-px flex-1 transition-colors sm:mx-2", index < currentStepIndex ? "bg-blue-600" : "bg-zinc-200") })] }, step.id);
2012
+ })
2013
+ })
2014
+ });
2015
+ }
2016
+ /**
2017
+ * A stepper component for navigating through a series of steps.
2018
+ *
2019
+ * @param props - The props for the WizardStepper component.
2020
+ * @returns A React node representing the stepper component.
2021
+ */
2022
+ function WizardStepper(props) {
2023
+ const { variant = "horizontal", ...rest } = props;
2024
+ return variant === "vertical" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VerticalStepper, {
2025
+ ...rest,
2026
+ variant
2027
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HorizontalStepper, {
2028
+ ...rest,
2029
+ variant
2030
+ });
2031
+ }
2032
+
2033
+ //#endregion
2034
+ //#region src/components/ui/wizard/WizardNavigation.tsx
2035
+ /**
2036
+ * A navigation component for the wizard.
2037
+ *
2038
+ * @param props - The props for the WizardNavigation component.
2039
+ * @returns A React node representing the navigation component.
2040
+ */
2041
+ function WizardNavigation({ isFirstStep, isLastStep, canProceed = true, onPrevious, onNext, onCancel, extraActions, nextLabel = "Next", lastStepLabel = "Finish", className }) {
2042
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2043
+ className: (0, _openzeppelin_ui_utils.cn)("flex items-center justify-between", className),
2044
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2045
+ className: "flex gap-2",
2046
+ children: [onCancel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
2047
+ type: "button",
2048
+ variant: "outline",
2049
+ onClick: onCancel,
2050
+ className: "gap-2",
2051
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "size-4" }), "Cancel"]
2052
+ }), !isFirstStep && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
2053
+ type: "button",
2054
+ variant: "outline",
2055
+ onClick: onPrevious,
2056
+ className: "gap-2",
2057
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronLeft, { className: "size-4" }), "Previous"]
2058
+ })]
2059
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2060
+ className: "flex gap-2",
2061
+ children: [extraActions, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
2062
+ type: "button",
2063
+ onClick: onNext,
2064
+ disabled: !canProceed,
2065
+ className: "gap-2",
2066
+ children: [isLastStep ? lastStepLabel : nextLabel, !isLastStep && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, { className: "size-4" })]
2067
+ })]
2068
+ })]
2069
+ });
2070
+ }
2071
+
2072
+ //#endregion
2073
+ //#region src/components/ui/wizard/hooks.ts
2074
+ /**
2075
+ * Clamp a step index into the valid range for the current wizard.
2076
+ */
2077
+ function getSafeStepIndex(stepCount, currentStepIndex) {
2078
+ if (stepCount === 0) return 0;
2079
+ return Math.max(0, Math.min(currentStepIndex, stepCount - 1));
2080
+ }
2081
+ /**
2082
+ * Track the highest step reached unless a controlled value is provided.
2083
+ */
2084
+ function useFurthestStepIndex(currentStepIndex, controlledFurthestStepIndex) {
2085
+ const [internalFurthestStepIndex, setInternalFurthestStepIndex] = (0, react.useState)(currentStepIndex);
2086
+ (0, react.useEffect)(() => {
2087
+ setInternalFurthestStepIndex((prev) => Math.max(prev, currentStepIndex));
2088
+ }, [currentStepIndex]);
2089
+ return controlledFurthestStepIndex ?? internalFurthestStepIndex;
2090
+ }
2091
+ /**
2092
+ * Keep the scrollable wizard's active and visited step state in sync with scrolling and clicks.
2093
+ */
2094
+ function useScrollableWizardStepTracking({ steps, currentStepIndex, onStepChange, scrollRef, sectionId, scrollPadding = SCROLL_PADDING_PX }) {
2095
+ const safeIndex = getSafeStepIndex(steps.length, currentStepIndex);
2096
+ const initialIndexRef = (0, react.useRef)(safeIndex);
2097
+ const rafRef = (0, react.useRef)(null);
2098
+ const manualSelectionIndexRef = (0, react.useRef)(null);
2099
+ const stepsRef = (0, react.useRef)(steps);
2100
+ const sectionIdRef = (0, react.useRef)(sectionId);
2101
+ const onStepChangeRef = (0, react.useRef)(onStepChange);
2102
+ const scrollPaddingRef = (0, react.useRef)(scrollPadding);
2103
+ (0, react.useEffect)(() => {
2104
+ stepsRef.current = steps;
2105
+ sectionIdRef.current = sectionId;
2106
+ onStepChangeRef.current = onStepChange;
2107
+ scrollPaddingRef.current = scrollPadding;
2108
+ });
2109
+ const [activeIndex, setActiveIndex] = (0, react.useState)(initialIndexRef.current);
2110
+ const activeIndexRef = (0, react.useRef)(initialIndexRef.current);
2111
+ const [furthestStepIndex, setFurthestStepIndex] = (0, react.useState)(initialIndexRef.current);
2112
+ const isMountedRef = (0, react.useRef)(false);
2113
+ const clearManualSelection = (0, react.useCallback)(() => {
2114
+ manualSelectionIndexRef.current = null;
2115
+ }, []);
2116
+ (0, react.useEffect)(() => {
2117
+ const container = scrollRef.current;
2118
+ if (!container) return;
2119
+ const ownerDocument = container.ownerDocument;
2120
+ isMountedRef.current = false;
2121
+ let didCompleteInitialRaf = false;
2122
+ const releaseManualSelectionOnUserScroll = () => {
2123
+ clearManualSelection();
2124
+ };
2125
+ const handleKeyDown = (event) => {
2126
+ if (isScrollableNavigationKey(event)) clearManualSelection();
2127
+ };
2128
+ const handleScroll = () => {
2129
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2130
+ rafRef.current = requestAnimationFrame(() => {
2131
+ const currentSteps = stepsRef.current;
2132
+ const currentSectionId = sectionIdRef.current;
2133
+ const currentOnStepChange = onStepChangeRef.current;
2134
+ if (currentSteps.length === 0) return;
2135
+ const manualSelectionIndex = manualSelectionIndexRef.current;
2136
+ const naturalState = resolveScrollableActiveIndex(container, currentSteps, currentSectionId);
2137
+ const naturalActiveIndex = naturalState.activeIndex;
2138
+ const newActiveIndex = manualSelectionIndex ?? naturalActiveIndex;
2139
+ const shouldCommitFurthestStepIndex = manualSelectionIndex !== null ? true : naturalState.commitFurthestStepIndex;
2140
+ if (activeIndexRef.current !== newActiveIndex) {
2141
+ activeIndexRef.current = newActiveIndex;
2142
+ setActiveIndex(newActiveIndex);
2143
+ if (isMountedRef.current) {
2144
+ lastEmittedIndexRef.current = newActiveIndex;
2145
+ currentOnStepChange(newActiveIndex);
2146
+ }
2147
+ } else setActiveIndex(newActiveIndex);
2148
+ if (shouldCommitFurthestStepIndex) setFurthestStepIndex((prev) => Math.max(prev, newActiveIndex));
2149
+ rafRef.current = null;
2150
+ if (!didCompleteInitialRaf) {
2151
+ didCompleteInitialRaf = true;
2152
+ isMountedRef.current = true;
2153
+ }
2154
+ });
2155
+ };
2156
+ container.addEventListener("wheel", releaseManualSelectionOnUserScroll, { passive: true });
2157
+ container.addEventListener("touchmove", releaseManualSelectionOnUserScroll, { passive: true });
2158
+ container.addEventListener("pointerdown", releaseManualSelectionOnUserScroll);
2159
+ ownerDocument.addEventListener("keydown", handleKeyDown);
2160
+ container.addEventListener("scroll", handleScroll, { passive: true });
2161
+ handleScroll();
2162
+ return () => {
2163
+ isMountedRef.current = false;
2164
+ container.removeEventListener("wheel", releaseManualSelectionOnUserScroll);
2165
+ container.removeEventListener("touchmove", releaseManualSelectionOnUserScroll);
2166
+ container.removeEventListener("pointerdown", releaseManualSelectionOnUserScroll);
2167
+ ownerDocument.removeEventListener("keydown", handleKeyDown);
2168
+ container.removeEventListener("scroll", handleScroll);
2169
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2170
+ };
2171
+ }, [clearManualSelection, scrollRef]);
2172
+ const lastEmittedIndexRef = (0, react.useRef)(safeIndex);
2173
+ (0, react.useEffect)(() => {
2174
+ const newSafeIndex = getSafeStepIndex(stepsRef.current.length, currentStepIndex);
2175
+ if (newSafeIndex === lastEmittedIndexRef.current) return;
2176
+ lastEmittedIndexRef.current = newSafeIndex;
2177
+ activeIndexRef.current = newSafeIndex;
2178
+ setActiveIndex(newSafeIndex);
2179
+ setFurthestStepIndex((prev) => Math.max(prev, newSafeIndex));
2180
+ const step = stepsRef.current[newSafeIndex];
2181
+ if (!step) return;
2182
+ const sectionElement = scrollRef.current?.querySelector(`#${CSS.escape(sectionIdRef.current(step.id))}`);
2183
+ if (scrollRef.current && sectionElement) scrollSectionIntoView(scrollRef.current, sectionElement, scrollPaddingRef.current);
2184
+ }, [currentStepIndex, scrollRef]);
2185
+ return {
2186
+ activeIndex,
2187
+ furthestStepIndex,
2188
+ scrollToSection: (0, react.useCallback)((index) => {
2189
+ const step = stepsRef.current[index];
2190
+ if (!step) return;
2191
+ manualSelectionIndexRef.current = index;
2192
+ activeIndexRef.current = index;
2193
+ lastEmittedIndexRef.current = index;
2194
+ setActiveIndex(index);
2195
+ setFurthestStepIndex((prev) => Math.max(prev, index));
2196
+ onStepChangeRef.current(index);
2197
+ const container = scrollRef.current;
2198
+ const sectionElement = container?.querySelector(`#${CSS.escape(sectionIdRef.current(step.id))}`);
2199
+ if (container && sectionElement) scrollSectionIntoView(container, sectionElement, scrollPaddingRef.current);
2200
+ }, [scrollRef])
2201
+ };
2202
+ }
2203
+ function resolveScrollableActiveIndex(container, steps, sectionId) {
2204
+ if (steps.length === 0) return {
2205
+ activeIndex: 0,
2206
+ commitFurthestStepIndex: false
2207
+ };
2208
+ const containerRect = container.getBoundingClientRect();
2209
+ const anchorY = containerRect.top + Math.min(containerRect.height * .35, 220);
2210
+ const isScrollable = container.scrollHeight > container.clientHeight + 1;
2211
+ const isAtBottom = isScrollable && container.scrollTop + container.clientHeight >= container.scrollHeight - 1;
2212
+ const isNearBottom = isScrollable && container.scrollTop + container.clientHeight >= container.scrollHeight - 4;
2213
+ if (isAtBottom) return {
2214
+ activeIndex: steps.length - 1,
2215
+ commitFurthestStepIndex: false
2216
+ };
2217
+ let activeIndex = 0;
2218
+ let highestScore = Number.NEGATIVE_INFINITY;
2219
+ for (let i = 0; i < steps.length; i++) {
2220
+ const sectionMetrics = getSectionMetrics(container, steps[i].id, sectionId, containerRect);
2221
+ if (!sectionMetrics) continue;
2222
+ const score = scoreScrollableStep({
2223
+ stepIndex: i,
2224
+ stepCount: steps.length,
2225
+ containerRect,
2226
+ anchorY,
2227
+ isNearBottom,
2228
+ ...sectionMetrics
2229
+ });
2230
+ if (score >= highestScore) {
2231
+ highestScore = score;
2232
+ activeIndex = i;
2233
+ }
2234
+ }
2235
+ return {
2236
+ activeIndex,
2237
+ commitFurthestStepIndex: true
2238
+ };
2239
+ }
2240
+ const SCROLL_PADDING_PX = 32;
2241
+ function getSectionElement(container, stepId, sectionId) {
2242
+ return container.querySelector(`#${CSS.escape(sectionId(stepId))}`);
2243
+ }
2244
+ function scrollSectionIntoView(container, sectionElement, padding) {
2245
+ const elementTop = sectionElement.getBoundingClientRect().top;
2246
+ const containerTop = container.getBoundingClientRect().top;
2247
+ const targetScrollTop = container.scrollTop + (elementTop - containerTop) - padding;
2248
+ container.scrollTo({
2249
+ top: targetScrollTop,
2250
+ behavior: "smooth"
2251
+ });
2252
+ }
2253
+ function getSectionMetrics(container, stepId, sectionId, containerRect) {
2254
+ const sectionElement = getSectionElement(container, stepId, sectionId);
2255
+ if (!sectionElement) return null;
2256
+ const sectionRect = sectionElement.getBoundingClientRect();
2257
+ return {
2258
+ sectionRect,
2259
+ visibleHeight: getVisibleHeight(containerRect, sectionRect)
2260
+ };
2261
+ }
2262
+ function getVisibleHeight(containerRect, sectionRect) {
2263
+ return Math.max(0, Math.min(sectionRect.bottom, containerRect.bottom) - Math.max(sectionRect.top, containerRect.top));
2264
+ }
2265
+ function scoreScrollableStep({ stepIndex, stepCount, containerRect, sectionRect, visibleHeight, anchorY, isNearBottom }) {
2266
+ const isVisible = visibleHeight > 0;
2267
+ const focusBandTop = containerRect.top + Math.min(containerRect.height * .2, 140);
2268
+ const focusBandBottom = containerRect.top + Math.min(containerRect.height * .55, 360);
2269
+ const focusBandOverlap = getBandOverlapHeight(sectionRect, focusBandTop, focusBandBottom);
2270
+ const distanceToFocusBand = focusBandOverlap > 0 ? 0 : Math.min(Math.abs(sectionRect.top - focusBandBottom), Math.abs(sectionRect.bottom - focusBandTop));
2271
+ const lastStepProminent = stepIndex === stepCount - 1 && visibleHeight >= Math.min(sectionRect.height, containerRect.height) * .25 && sectionRect.top <= containerRect.top + containerRect.height * .65;
2272
+ let score = isVisible ? visibleHeight : Number.NEGATIVE_INFINITY;
2273
+ if (focusBandOverlap > 0) score += 12e3 + focusBandOverlap * 25;
2274
+ if (sectionRect.top <= anchorY) score += 250;
2275
+ score += Math.max(0, 1e3 - distanceToFocusBand);
2276
+ if (isNearBottom && lastStepProminent && isVisible) score += 15e3;
2277
+ return score;
2278
+ }
2279
+ function getBandOverlapHeight(sectionRect, bandTop, bandBottom) {
2280
+ return Math.max(0, Math.min(sectionRect.bottom, bandBottom) - Math.max(sectionRect.top, bandTop));
2281
+ }
2282
+ function isScrollableNavigationKey(event) {
2283
+ if (event.metaKey || event.ctrlKey || event.altKey) return false;
2284
+ return [
2285
+ "ArrowDown",
2286
+ "ArrowUp",
2287
+ "PageDown",
2288
+ "PageUp",
2289
+ "Home",
2290
+ "End",
2291
+ " "
2292
+ ].includes(event.key);
2293
+ }
2294
+
2295
+ //#endregion
2296
+ //#region src/components/ui/wizard/WizardLayout.tsx
2297
+ function PagedLayout({ steps, currentStepIndex, furthestStepIndex: furthestStepIndexProp, onStepChange, onComplete, onCancel, navActions, header, variant, className }) {
2298
+ const safeIndex = getSafeStepIndex(steps.length, currentStepIndex);
2299
+ const resolvedFurthestStepIndex = useFurthestStepIndex(safeIndex, furthestStepIndexProp);
2300
+ if (steps.length === 0) return null;
2301
+ const isFirstStep = safeIndex === 0;
2302
+ const isLastStep = safeIndex === steps.length - 1;
2303
+ const currentStep = steps[safeIndex];
2304
+ const canProceed = currentStep?.isValid !== false;
2305
+ const handleNext = () => {
2306
+ if (isLastStep) {
2307
+ onComplete?.();
2308
+ return;
2309
+ }
2310
+ onStepChange(safeIndex + 1);
2311
+ };
2312
+ const handlePrevious = () => {
2313
+ if (!isFirstStep) onStepChange(safeIndex - 1);
2314
+ };
2315
+ const stepDefs = toStepDefs(steps, safeIndex);
2316
+ const footer = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2317
+ className: "shrink-0 border-t border-border bg-background px-8 py-4",
2318
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2319
+ className: "mx-auto max-w-5xl",
2320
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WizardNavigation, {
2321
+ isFirstStep,
2322
+ isLastStep,
2323
+ canProceed,
2324
+ onPrevious: handlePrevious,
2325
+ onNext: handleNext,
2326
+ onCancel,
2327
+ extraActions: navActions
2328
+ })
2329
+ })
2330
+ });
2331
+ if (variant === "vertical") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2332
+ className: (0, _openzeppelin_ui_utils.cn)("flex h-full gap-6", className),
2333
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2334
+ className: "w-[220px] shrink-0 py-6 pl-6",
2335
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WizardStepper, {
2336
+ variant: "vertical",
2337
+ steps: stepDefs,
2338
+ currentStepIndex: safeIndex,
2339
+ furthestStepIndex: resolvedFurthestStepIndex,
2340
+ onStepClick: onStepChange,
2341
+ className: "h-full"
2342
+ })
2343
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2344
+ className: "flex min-w-0 flex-1 flex-col overflow-hidden",
2345
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2346
+ className: "flex-1 overflow-y-auto p-8",
2347
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2348
+ className: "mx-auto max-w-5xl",
2349
+ children: [header, currentStep?.component]
2350
+ })
2351
+ }), footer]
2352
+ })]
2353
+ });
2354
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2355
+ className: (0, _openzeppelin_ui_utils.cn)("flex h-full flex-col", className),
2356
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2357
+ className: "shrink-0 p-6 pb-0",
2358
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WizardStepper, {
2359
+ variant: "horizontal",
2360
+ steps: stepDefs,
2361
+ currentStepIndex: safeIndex,
2362
+ furthestStepIndex: resolvedFurthestStepIndex,
2363
+ onStepClick: onStepChange
2364
+ })
2365
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2366
+ className: "flex min-w-0 flex-1 flex-col overflow-hidden",
2367
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2368
+ className: "flex-1 overflow-y-auto p-8",
2369
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2370
+ className: "mx-auto max-w-5xl",
2371
+ children: [header, currentStep?.component]
2372
+ })
2373
+ }), footer]
2374
+ })]
2375
+ });
2376
+ }
2377
+ function ScrollableLayout({ steps, currentStepIndex, onStepChange, header, onComplete, scrollPadding, className }) {
2378
+ const instanceId = (0, react.useId)();
2379
+ const scrollRef = (0, react.useRef)(null);
2380
+ const sectionId = (0, react.useCallback)((stepId) => `wizard-section-${instanceId}-${stepId}`, [instanceId]);
2381
+ const { activeIndex, furthestStepIndex, scrollToSection } = useScrollableWizardStepTracking({
2382
+ steps,
2383
+ currentStepIndex,
2384
+ onStepChange,
2385
+ scrollRef,
2386
+ sectionId,
2387
+ scrollPadding
2388
+ });
2389
+ if (steps.length === 0) return null;
2390
+ const stepDefs = toStepDefs(steps, activeIndex);
2391
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2392
+ className: (0, _openzeppelin_ui_utils.cn)("flex h-full gap-6", className),
2393
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2394
+ className: "w-[220px] shrink-0 py-6 pl-6",
2395
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WizardStepper, {
2396
+ variant: "vertical",
2397
+ steps: stepDefs,
2398
+ currentStepIndex: activeIndex,
2399
+ furthestStepIndex,
2400
+ onStepClick: scrollToSection,
2401
+ freeNavigation: true,
2402
+ className: "h-full"
2403
+ })
2404
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2405
+ ref: scrollRef,
2406
+ className: "flex min-w-0 flex-1 flex-col overflow-y-auto p-8",
2407
+ children: [
2408
+ header,
2409
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2410
+ className: "space-y-12",
2411
+ children: steps.map((step) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
2412
+ id: sectionId(step.id),
2413
+ children: step.component
2414
+ }, step.id))
2415
+ }),
2416
+ onComplete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2417
+ className: "flex justify-end pt-8",
2418
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
2419
+ type: "button",
2420
+ onClick: onComplete,
2421
+ children: "Finish"
2422
+ })
2423
+ })
2424
+ ]
2425
+ })]
2426
+ });
2427
+ }
2428
+ function toStepDefs(steps, currentStepIndex) {
2429
+ return steps.map((s, i) => {
2430
+ const isInvalid = s.isInvalid ?? s.isValid === false;
2431
+ const status = s.status ?? (i < currentStepIndex && !isInvalid ? "completed" : "pending");
2432
+ return {
2433
+ id: s.id,
2434
+ title: s.title,
2435
+ status,
2436
+ isInvalid
2437
+ };
2438
+ });
2439
+ }
2440
+ /**
2441
+ * A layout component for the wizard.
2442
+ *
2443
+ * @param props - The props for the WizardLayout component.
2444
+ * @returns A React node representing the layout component.
2445
+ */
2446
+ function WizardLayout(props) {
2447
+ const { variant = "horizontal", ...rest } = props;
2448
+ if (variant === "scrollable") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollableLayout, {
2449
+ steps: rest.steps,
2450
+ currentStepIndex: rest.currentStepIndex,
2451
+ onStepChange: rest.onStepChange,
2452
+ header: rest.header,
2453
+ onComplete: rest.onComplete,
2454
+ scrollPadding: rest.scrollPadding,
2455
+ className: rest.className
2456
+ });
2457
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PagedLayout, {
2458
+ ...rest,
2459
+ variant
2460
+ });
2461
+ }
2462
+
1858
2463
  //#endregion
1859
2464
  //#region src/components/fields/address-suggestion/context.ts
1860
2465
  /**
@@ -5860,6 +6465,9 @@ exports.TooltipProvider = TooltipProvider;
5860
6465
  exports.TooltipTrigger = TooltipTrigger;
5861
6466
  exports.UrlField = UrlField;
5862
6467
  exports.ViewContractStateButton = ViewContractStateButton;
6468
+ exports.WizardLayout = WizardLayout;
6469
+ exports.WizardNavigation = WizardNavigation;
6470
+ exports.WizardStepper = WizardStepper;
5863
6471
  exports.buttonVariants = buttonVariants;
5864
6472
  exports.computeChildTouched = computeChildTouched;
5865
6473
  exports.createFocusManager = createFocusManager;