@bubo-squared/ui-framework 0.2.19 → 0.2.21

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
@@ -93,10 +93,40 @@ function cn(...inputs) {
93
93
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
94
94
  }
95
95
 
96
+ // src/lib/ripple.ts
97
+ function removeExistingRipples(target) {
98
+ const ripples = target.querySelectorAll(".bubo-ripple");
99
+ ripples.forEach((node) => node.remove());
100
+ }
101
+ function spawnRipple(target, clientX, clientY, options = {}) {
102
+ if (typeof window === "undefined" || typeof document === "undefined") return;
103
+ const rect = target.getBoundingClientRect();
104
+ const x = clientX - rect.left;
105
+ const y = clientY - rect.top;
106
+ const radius = Math.sqrt(rect.width * rect.width + rect.height * rect.height);
107
+ const size = radius * 2;
108
+ removeExistingRipples(target);
109
+ const ripple = document.createElement("span");
110
+ ripple.className = "bubo-ripple";
111
+ ripple.style.width = `${size}px`;
112
+ ripple.style.height = `${size}px`;
113
+ ripple.style.left = `${x - radius}px`;
114
+ ripple.style.top = `${y - radius}px`;
115
+ const durationMs = options.durationMs ?? 500;
116
+ ripple.style.animationDuration = `${durationMs}ms`;
117
+ const cleanup = () => {
118
+ ripple.removeEventListener("animationend", cleanup);
119
+ ripple.remove();
120
+ };
121
+ ripple.addEventListener("animationend", cleanup);
122
+ target.appendChild(ripple);
123
+ window.setTimeout(cleanup, durationMs + 50);
124
+ }
125
+
96
126
  // src/components/Buttons/Button.tsx
97
127
  var import_jsx_runtime2 = require("react/jsx-runtime");
98
128
  var buttonVariants = (0, import_class_variance_authority.cva)(
99
- "inline-flex items-center justify-center whitespace-nowrap rounded-4 transition-colors disabled:pointer-events-none overflow-hidden cursor-pointer",
129
+ "relative inline-flex items-center justify-center whitespace-nowrap rounded-4 transition-colors disabled:pointer-events-none overflow-hidden cursor-pointer",
100
130
  {
101
131
  variants: {
102
132
  variant: {
@@ -121,10 +151,10 @@ var buttonVariants = (0, import_class_variance_authority.cva)(
121
151
  ]
122
152
  },
123
153
  size: {
124
- sm: ["px-2", "py-1", "gap-2", "h-9"],
125
- md: ["px-2", "py-1", "gap-2", "h-10"],
126
- lg: ["px-2.5", "py-1", "gap-2.5", "h-11"],
127
- xl: ["px-3", "py-0.5", "gap-3", "h-12"]
154
+ sm: ["px-3", "py-1", "gap-2", "h-9"],
155
+ md: ["px-4", "py-2", "gap-2", "h-10"],
156
+ lg: ["px-4", "py-2", "gap-2.5", "h-11"],
157
+ xl: ["px-4", "py-2", "gap-3", "h-12"]
128
158
  }
129
159
  },
130
160
  defaultVariants: {
@@ -163,14 +193,23 @@ var Button = React.forwardRef(
163
193
  children,
164
194
  trailingIcon,
165
195
  leadingIcon,
196
+ onPointerDown,
166
197
  ...rest
167
198
  } = props;
168
199
  const Comp = asChild ? import_react_slot.Slot : "button";
200
+ const handlePointerDown = (e) => {
201
+ onPointerDown?.(e);
202
+ if (e.defaultPrevented) return;
203
+ if (rest.disabled) return;
204
+ if (e.button !== 0 || !e.isPrimary) return;
205
+ spawnRipple(e.currentTarget, e.clientX, e.clientY);
206
+ };
169
207
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
170
208
  Comp,
171
209
  {
172
210
  className: cn(buttonVariants({ variant, size, className })),
173
211
  ref,
212
+ onPointerDown: handlePointerDown,
174
213
  ...rest,
175
214
  children: [
176
215
  leadingIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn(buttonIconVariants({ size })), children: leadingIcon }),
@@ -223,7 +262,7 @@ var import_react_slot2 = require("@radix-ui/react-slot");
223
262
  var import_class_variance_authority3 = require("class-variance-authority");
224
263
  var import_jsx_runtime4 = require("react/jsx-runtime");
225
264
  var iconButtonVariants = (0, import_class_variance_authority3.cva)(
226
- "inline-flex items-center justify-center whitespace-nowrap transition-colors disabled:pointer-events-none overflow-hidden p-2 cursor-pointer",
265
+ "relative inline-flex items-center justify-center whitespace-nowrap transition-colors disabled:pointer-events-none overflow-hidden p-2 cursor-pointer",
227
266
  {
228
267
  variants: {
229
268
  variant: {
@@ -269,14 +308,23 @@ var IconButton = React2.forwardRef(
269
308
  asChild = false,
270
309
  icon,
271
310
  round = false,
311
+ onPointerDown,
272
312
  ...rest
273
313
  } = props;
274
314
  const Comp = asChild ? import_react_slot2.Slot : "button";
315
+ const handlePointerDown = (e) => {
316
+ onPointerDown?.(e);
317
+ if (e.defaultPrevented) return;
318
+ if (rest.disabled) return;
319
+ if (e.button !== 0 || !e.isPrimary) return;
320
+ spawnRipple(e.currentTarget, e.clientX, e.clientY);
321
+ };
275
322
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
276
323
  Comp,
277
324
  {
278
325
  className: cn(iconButtonVariants({ variant, size }), round ? "rounded-full" : "rounded-4", className),
279
326
  ref,
327
+ onPointerDown: handlePointerDown,
280
328
  ...rest,
281
329
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "buttonIcon flex items-center justify-center", children: icon })
282
330
  }
@@ -1535,16 +1583,17 @@ var MenuSubContent = DropdownMenuSubContent;
1535
1583
  var MenuSubTrigger = DropdownMenuSubTrigger;
1536
1584
 
1537
1585
  // src/components/Inputs/Checkbox.tsx
1538
- var React20 = require("react");
1586
+ var React20 = __toESM(require("react"), 1);
1539
1587
  var CheckboxPrimitive = __toESM(require("@radix-ui/react-checkbox"), 1);
1540
1588
  var import_icons6 = require("@bubo-squared/icons");
1541
1589
  var import_icons7 = require("@bubo-squared/icons");
1542
1590
  var import_jsx_runtime22 = require("react/jsx-runtime");
1543
- function Checkbox({ label, className, ...props }) {
1591
+ var Checkbox = React20.forwardRef(({ label, className, ...props }, forwardedRef) => {
1544
1592
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "inline-flex items-center gap-(--space-12) cursor-pointer select-none", children: [
1545
1593
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1546
1594
  CheckboxPrimitive.Root,
1547
1595
  {
1596
+ ref: forwardedRef,
1548
1597
  className: cn(
1549
1598
  "group flex h-5 w-5 items-center justify-center rounded-2 border border-(--border-secondary) bg-(--background-neutral) text-primary-inverse",
1550
1599
  "data-[state=checked]:bg-(--background-brand) data-[state=checked]:text-button-white data-[state=checked]:border-none",
@@ -1566,7 +1615,8 @@ function Checkbox({ label, className, ...props }) {
1566
1615
  ),
1567
1616
  label && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "paragraph-md-medium text-primary", children: label })
1568
1617
  ] });
1569
- }
1618
+ });
1619
+ Checkbox.displayName = "Checkbox";
1570
1620
 
1571
1621
  // src/components/Inputs/Autocomplete.tsx
1572
1622
  var React23 = __toESM(require("react"), 1);
@@ -1699,7 +1749,7 @@ var iconWrapperVariants = (0, import_class_variance_authority14.cva)(
1699
1749
  }
1700
1750
  }
1701
1751
  );
1702
- var Autocomplete = (props) => {
1752
+ var Autocomplete = React23.forwardRef((props, forwardedRef) => {
1703
1753
  const {
1704
1754
  label,
1705
1755
  hint,
@@ -1740,6 +1790,18 @@ var Autocomplete = (props) => {
1740
1790
  const [isFocused, setIsFocused] = React23.useState(false);
1741
1791
  const [activeIndex, setActiveIndex] = React23.useState(-1);
1742
1792
  const inputRef = React23.useRef(null);
1793
+ const setInputRef = React23.useCallback(
1794
+ (node) => {
1795
+ inputRef.current = node;
1796
+ if (!forwardedRef) return;
1797
+ if (typeof forwardedRef === "function") {
1798
+ forwardedRef(node);
1799
+ } else {
1800
+ forwardedRef.current = node;
1801
+ }
1802
+ },
1803
+ [forwardedRef]
1804
+ );
1743
1805
  const baseId = React23.useId();
1744
1806
  const inputId = id ?? baseId;
1745
1807
  const listboxId = `${inputId}-listbox`;
@@ -1852,7 +1914,7 @@ var Autocomplete = (props) => {
1852
1914
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1853
1915
  Input,
1854
1916
  {
1855
- ref: inputRef,
1917
+ ref: setInputRef,
1856
1918
  id: inputId,
1857
1919
  type: "text",
1858
1920
  disabled: disabled ?? void 0,
@@ -1927,7 +1989,7 @@ var Autocomplete = (props) => {
1927
1989
  }
1928
1990
  )
1929
1991
  ] }) });
1930
- };
1992
+ });
1931
1993
  Autocomplete.displayName = "Autocomplete";
1932
1994
 
1933
1995
  // src/components/Inputs/Select.tsx
@@ -2010,7 +2072,7 @@ var selectButtonVariants = (0, import_class_variance_authority15.cva)(
2010
2072
  }
2011
2073
  }
2012
2074
  );
2013
- var Select = (props) => {
2075
+ var Select = React24.forwardRef((props, forwardedRef) => {
2014
2076
  const {
2015
2077
  label = "Field Label",
2016
2078
  hint = "This is a hint text to help user.",
@@ -2085,6 +2147,7 @@ var Select = (props) => {
2085
2147
  /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SelectPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
2086
2148
  "button",
2087
2149
  {
2150
+ ref: forwardedRef,
2088
2151
  type: "button",
2089
2152
  "aria-haspopup": "listbox",
2090
2153
  "aria-expanded": isOpen,
@@ -2159,7 +2222,7 @@ var Select = (props) => {
2159
2222
  )
2160
2223
  }
2161
2224
  );
2162
- };
2225
+ });
2163
2226
  Select.displayName = "Select";
2164
2227
 
2165
2228
  // src/components/Inputs/PasswordInput.tsx
@@ -2223,7 +2286,7 @@ var actionButtonVariants = (0, import_class_variance_authority16.cva)(
2223
2286
  }
2224
2287
  }
2225
2288
  );
2226
- var PasswordInput = (props) => {
2289
+ var PasswordInput = React25.forwardRef((props, forwardedRef) => {
2227
2290
  const {
2228
2291
  label,
2229
2292
  hint,
@@ -2247,6 +2310,18 @@ var PasswordInput = (props) => {
2247
2310
  const [isRevealed, setIsRevealed] = React25.useState(false);
2248
2311
  const currentValue = (isControlled ? value : internalValue) ?? "";
2249
2312
  const inputRef = React25.useRef(null);
2313
+ const setInputRef = React25.useCallback(
2314
+ (node) => {
2315
+ inputRef.current = node;
2316
+ if (!forwardedRef) return;
2317
+ if (typeof forwardedRef === "function") {
2318
+ forwardedRef(node);
2319
+ } else {
2320
+ forwardedRef.current = node;
2321
+ }
2322
+ },
2323
+ [forwardedRef]
2324
+ );
2250
2325
  const showLeadingIcon = !!leadingIcon;
2251
2326
  const handleContainerClick = () => {
2252
2327
  if (disabled) return;
@@ -2287,7 +2362,7 @@ var PasswordInput = (props) => {
2287
2362
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2288
2363
  Input,
2289
2364
  {
2290
- ref: inputRef,
2365
+ ref: setInputRef,
2291
2366
  type: isRevealed ? "text" : "password",
2292
2367
  disabled: disabled ?? void 0,
2293
2368
  placeholder,
@@ -2322,7 +2397,7 @@ var PasswordInput = (props) => {
2322
2397
  )
2323
2398
  }
2324
2399
  );
2325
- };
2400
+ });
2326
2401
  PasswordInput.displayName = "PasswordInput";
2327
2402
 
2328
2403
  // src/components/Inputs/PhoneInput.tsx
@@ -2969,19 +3044,20 @@ var FlagComponent = ({ country, countryName }) => {
2969
3044
  var React32 = __toESM(require("react"), 1);
2970
3045
  var RadioGroupPrimitive = __toESM(require("@radix-ui/react-radio-group"), 1);
2971
3046
  var import_jsx_runtime34 = require("react/jsx-runtime");
2972
- var RadioGroup = ({
2973
- label,
2974
- hint,
2975
- hideHint,
2976
- options,
2977
- orientation = "vertical",
2978
- disabled = false,
2979
- value,
2980
- defaultValue,
2981
- onValueChange,
2982
- className,
2983
- ...rootProps
2984
- }) => {
3047
+ var RadioGroup = React32.forwardRef((props, forwardedRef) => {
3048
+ const {
3049
+ label,
3050
+ hint,
3051
+ hideHint,
3052
+ options,
3053
+ orientation = "vertical",
3054
+ disabled = false,
3055
+ value,
3056
+ defaultValue,
3057
+ onValueChange,
3058
+ className,
3059
+ ...rootProps
3060
+ } = props;
2985
3061
  const groupId = React32.useId();
2986
3062
  const hintId = hint ? `${groupId}-hint` : void 0;
2987
3063
  const handleValueChange = (next) => {
@@ -2998,6 +3074,7 @@ var RadioGroup = ({
2998
3074
  children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2999
3075
  RadioGroupPrimitive.Root,
3000
3076
  {
3077
+ ref: forwardedRef,
3001
3078
  ...rootProps,
3002
3079
  value,
3003
3080
  defaultValue,
@@ -3078,7 +3155,8 @@ var RadioGroup = ({
3078
3155
  )
3079
3156
  }
3080
3157
  );
3081
- };
3158
+ });
3159
+ RadioGroup.displayName = "RadioGroup";
3082
3160
 
3083
3161
  // src/components/Inputs/SearchInput.tsx
3084
3162
  var React33 = __toESM(require("react"), 1);
@@ -3114,7 +3192,7 @@ var iconWrapperVariants3 = (0, import_class_variance_authority19.cva)("flex item
3114
3192
  size: "lg"
3115
3193
  }
3116
3194
  });
3117
- var SearchInput = (props) => {
3195
+ var SearchInput = React33.forwardRef((props, forwardedRef) => {
3118
3196
  const {
3119
3197
  placeholder = "Search...",
3120
3198
  size = "lg",
@@ -3126,6 +3204,18 @@ var SearchInput = (props) => {
3126
3204
  ...inputProps
3127
3205
  } = props;
3128
3206
  const inputRef = React33.useRef(null);
3207
+ const setInputRef = React33.useCallback(
3208
+ (node) => {
3209
+ inputRef.current = node;
3210
+ if (!forwardedRef) return;
3211
+ if (typeof forwardedRef === "function") {
3212
+ forwardedRef(node);
3213
+ } else {
3214
+ forwardedRef.current = node;
3215
+ }
3216
+ },
3217
+ [forwardedRef]
3218
+ );
3129
3219
  const handleContainerClick = () => {
3130
3220
  if (disabled) return;
3131
3221
  inputRef.current?.focus();
@@ -3144,7 +3234,7 @@ var SearchInput = (props) => {
3144
3234
  /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3145
3235
  Input,
3146
3236
  {
3147
- ref: inputRef,
3237
+ ref: setInputRef,
3148
3238
  type: "search",
3149
3239
  placeholder,
3150
3240
  disabled: disabled ?? void 0,
@@ -3159,7 +3249,7 @@ var SearchInput = (props) => {
3159
3249
  ]
3160
3250
  }
3161
3251
  ) }) });
3162
- };
3252
+ });
3163
3253
  SearchInput.displayName = "SearchInput";
3164
3254
 
3165
3255
  // src/components/Inputs/Slider.tsx
@@ -3213,10 +3303,11 @@ var Tooltip = (props) => {
3213
3303
  open,
3214
3304
  defaultOpen,
3215
3305
  onOpenChange,
3216
- children
3306
+ children,
3307
+ delayDuration = 200
3217
3308
  } = props;
3218
3309
  const { side, align } = mapPlacementToSideAndAlign(placement);
3219
- const tooltipClasses = "group bg-(--background-tooltip) max-w-[calc(100vw-2rem)] shadow-card-md border-none rounded-4 p-4 [&>span]:scale-200 data-[state=delayed-open]:animate-in data-[state=instant-open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=delayed-open]:fade-in-0 data-[state=instant-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-[state=instant-open]:zoom-in-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";
3310
+ const tooltipClasses = "group bg-(--background-tooltip) max-w-[calc(100vw-2rem)] shadow-card-md border-none rounded-4 py-1.5 px-2.5 [&>span]:scale-200 data-[state=delayed-open]:animate-in data-[state=instant-open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=delayed-open]:fade-in-0 data-[state=instant-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-[state=instant-open]:zoom-in-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";
3220
3311
  const tooltipArrowClasses = "relative fill-(--background-tooltip) transition-[filter,transform] group-data-[side=top]:top-[-2px] group-data-[side=top]:drop-shadow-[0px_1px_1px_color-mix(in_srgb,_var(--color-b-black-10)_66%,_transparent)] group-data-[side=bottom]:drop-shadow-[0px_1px_1px_color-mix(in_srgb,_var(--color-b-black-10)_66%,_transparent)] group-data-[side=left]:drop-shadow-[0px_2px_1px_color-mix(in_srgb,_var(--color-b-black-10)_66%,_transparent)] group-data-[side=right]:drop-shadow-[0px_2px_1px_color-mix(in_srgb,_var(--color-b-black-10)_66%,_transparent)]";
3221
3312
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
3222
3313
  TooltipPrimitive.Root,
@@ -3225,6 +3316,7 @@ var Tooltip = (props) => {
3225
3316
  defaultOpen,
3226
3317
  onOpenChange,
3227
3318
  disableHoverableContent,
3319
+ delayDuration,
3228
3320
  children: [
3229
3321
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(TooltipPrimitive.Trigger, { asChild: true, children }),
3230
3322
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(TooltipPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
@@ -3236,9 +3328,9 @@ var Tooltip = (props) => {
3236
3328
  className: cn(tooltipClasses, className),
3237
3329
  children: [
3238
3330
  showArrow && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(TooltipArrow, { className: tooltipArrowClasses }),
3239
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "grid gap-2", children: [
3331
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "grid", children: [
3240
3332
  (strapline ?? "") !== "" && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "caption text-secondary", children: strapline }),
3241
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h4", { className: "subtitle-medium text-primary", children: title }),
3333
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h4", { className: "paragraph-md text-primary", children: title }),
3242
3334
  (description ?? "") !== "" && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "paragraph-sm text-primary", children: description })
3243
3335
  ] })
3244
3336
  ]
@@ -3260,7 +3352,7 @@ var toArray = (value) => {
3260
3352
  if (value === void 0) return void 0;
3261
3353
  return Array.isArray(value) ? value : [value];
3262
3354
  };
3263
- var Slider = (props) => {
3355
+ var Slider = React35.forwardRef((props, forwardedRef) => {
3264
3356
  const {
3265
3357
  name,
3266
3358
  display = "flat",
@@ -3576,6 +3668,7 @@ var Slider = (props) => {
3576
3668
  {
3577
3669
  className: wrapperBase,
3578
3670
  style: { marginInline: `${thumbRadius}px` },
3671
+ ref: forwardedRef,
3579
3672
  children: [
3580
3673
  name && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
3581
3674
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
@@ -3641,14 +3734,14 @@ var Slider = (props) => {
3641
3734
  ]
3642
3735
  }
3643
3736
  );
3644
- };
3737
+ });
3645
3738
  Slider.displayName = "Slider";
3646
3739
 
3647
3740
  // src/components/Inputs/TextArea.tsx
3648
3741
  var React36 = __toESM(require("react"), 1);
3649
3742
  var import_icons13 = require("@bubo-squared/icons");
3650
3743
  var import_jsx_runtime38 = require("react/jsx-runtime");
3651
- var TextArea = (props) => {
3744
+ var TextArea = React36.forwardRef((props, forwardedRef) => {
3652
3745
  const {
3653
3746
  label,
3654
3747
  hint,
@@ -3677,6 +3770,18 @@ var TextArea = (props) => {
3677
3770
  const showCharacterLimit = type === "character-limit" && typeof effectiveMaxLength === "number";
3678
3771
  const textareaRef = React36.useRef(null);
3679
3772
  const containerRef = React36.useRef(null);
3773
+ const setTextareaRef = React36.useCallback(
3774
+ (node) => {
3775
+ textareaRef.current = node;
3776
+ if (!forwardedRef) return;
3777
+ if (typeof forwardedRef === "function") {
3778
+ forwardedRef(node);
3779
+ } else {
3780
+ forwardedRef.current = node;
3781
+ }
3782
+ },
3783
+ [forwardedRef]
3784
+ );
3680
3785
  const [height, setHeight] = React36.useState(void 0);
3681
3786
  const [width, setWidth] = React36.useState(void 0);
3682
3787
  const minHeight = 80;
@@ -3698,10 +3803,10 @@ var TextArea = (props) => {
3698
3803
  success: "border-(--border-success)",
3699
3804
  error: "border-(--border-error)"
3700
3805
  };
3701
- const statusFocusClass = {
3702
- default: "focus-within:border-(--border-brand) focus-within:hover:border-(--border-brand) focus-within:shadow-[0_0_0_var(--focus-ring-spread)_var(--focus-primary)]",
3703
- success: "focus-within:border-(--border-success) focus-within:hover:border-(--border-success) focus-within:shadow-[0_0_0_var(--focus-ring-spread)_var(--focus-success)]",
3704
- error: "focus-within:border-(--border-error) focus-within:hover:border-(--border-error) focus-within:shadow-[0_0_0_var(--focus-ring-spread)_var(--focus-error)]"
3806
+ const statusShellClass = {
3807
+ default: "input-default",
3808
+ success: "input-success",
3809
+ error: "input-error"
3705
3810
  };
3706
3811
  const counterColorClass = disabled ? "text-primary-disabled" : status === "success" ? "text-(--color-success)" : status === "error" ? "text-(--color-error)" : "text-primary";
3707
3812
  const handleResizePointerDown = (event) => {
@@ -3741,11 +3846,11 @@ var TextArea = (props) => {
3741
3846
  "div",
3742
3847
  {
3743
3848
  className: cn(
3744
- "relative flex w-full rounded-4 border bg-(--background-primary) cursor-text transition-colors",
3745
- "border-(--border-secondary) hover:border-(--border-secondary-hover) hover:bg-(--background-primary-hover)",
3849
+ "relative flex w-full rounded-4 border bg-(--background-primary) cursor-text",
3850
+ "border-(--border-secondary)",
3851
+ statusShellClass[status],
3746
3852
  disabled && "bg-(--background-primary-disabled) border-(--border-secondary-disabled) cursor-default",
3747
3853
  statusBorderClass[status],
3748
- !disabled && statusFocusClass[status],
3749
3854
  className
3750
3855
  ),
3751
3856
  ref: containerRef,
@@ -3761,7 +3866,7 @@ var TextArea = (props) => {
3761
3866
  {
3762
3867
  id: textareaId,
3763
3868
  name,
3764
- ref: textareaRef,
3869
+ ref: setTextareaRef,
3765
3870
  disabled: disabled ?? void 0,
3766
3871
  value: isControlled ? value : currentValue,
3767
3872
  defaultValue: isControlled ? void 0 : defaultValue,
@@ -3812,7 +3917,7 @@ var TextArea = (props) => {
3812
3917
  )
3813
3918
  }
3814
3919
  );
3815
- };
3920
+ });
3816
3921
  TextArea.displayName = "TextArea";
3817
3922
 
3818
3923
  // src/components/Inputs/TextInput.tsx
@@ -3851,7 +3956,7 @@ var iconWrapperVariants4 = (0, import_class_variance_authority20.cva)(
3851
3956
  }
3852
3957
  }
3853
3958
  );
3854
- var TextInput = (props) => {
3959
+ var TextInput = React37.forwardRef((props, forwardedRef) => {
3855
3960
  const {
3856
3961
  label,
3857
3962
  hint,
@@ -3874,6 +3979,18 @@ var TextInput = (props) => {
3874
3979
  );
3875
3980
  const currentValue = (isControlled ? value : internalValue) ?? "";
3876
3981
  const inputRef = React37.useRef(null);
3982
+ const setInputRef = React37.useCallback(
3983
+ (node) => {
3984
+ inputRef.current = node;
3985
+ if (!forwardedRef) return;
3986
+ if (typeof forwardedRef === "function") {
3987
+ forwardedRef(node);
3988
+ } else {
3989
+ forwardedRef.current = node;
3990
+ }
3991
+ },
3992
+ [forwardedRef]
3993
+ );
3877
3994
  const handleContainerClick = () => {
3878
3995
  if (disabled) return;
3879
3996
  inputRef.current?.focus();
@@ -3915,7 +4032,7 @@ var TextInput = (props) => {
3915
4032
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3916
4033
  Input,
3917
4034
  {
3918
- ref: inputRef,
4035
+ ref: setInputRef,
3919
4036
  type: "text",
3920
4037
  disabled: disabled ?? void 0,
3921
4038
  placeholder,
@@ -3944,13 +4061,13 @@ var TextInput = (props) => {
3944
4061
  )
3945
4062
  }
3946
4063
  );
3947
- };
4064
+ });
3948
4065
  TextInput.displayName = "TextInput";
3949
4066
 
3950
4067
  // src/components/Inputs/Toggle.tsx
3951
- var React38 = require("react");
4068
+ var React38 = __toESM(require("react"), 1);
3952
4069
  var import_jsx_runtime40 = require("react/jsx-runtime");
3953
- var Toggle = (props) => {
4070
+ var Toggle = React38.forwardRef((props, forwardedRef) => {
3954
4071
  const { label, className, disabled, ...inputProps } = props;
3955
4072
  return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
3956
4073
  "label",
@@ -3964,6 +4081,7 @@ var Toggle = (props) => {
3964
4081
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3965
4082
  "input",
3966
4083
  {
4084
+ ref: forwardedRef,
3967
4085
  type: "checkbox",
3968
4086
  disabled,
3969
4087
  className: "peer sr-only",
@@ -4035,13 +4153,13 @@ var Toggle = (props) => {
4035
4153
  ]
4036
4154
  }
4037
4155
  );
4038
- };
4156
+ });
4039
4157
  Toggle.displayName = "Toggle";
4040
4158
 
4041
4159
  // src/components/Inputs/WebsiteInput.tsx
4042
- var React39 = require("react");
4160
+ var React39 = __toESM(require("react"), 1);
4043
4161
  var import_jsx_runtime41 = require("react/jsx-runtime");
4044
- var WebsiteInput = (props) => {
4162
+ var WebsiteInput = React39.forwardRef((props, forwardedRef) => {
4045
4163
  const {
4046
4164
  hierarchy = "leading",
4047
4165
  protocolLabel = "http://",
@@ -4088,6 +4206,7 @@ var WebsiteInput = (props) => {
4088
4206
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4089
4207
  TextInput,
4090
4208
  {
4209
+ ref: forwardedRef,
4091
4210
  ...rest,
4092
4211
  size,
4093
4212
  disabled,
@@ -4096,7 +4215,7 @@ var WebsiteInput = (props) => {
4096
4215
  trailingIcon: !isLeading ? trailingAddon : void 0
4097
4216
  }
4098
4217
  );
4099
- };
4218
+ });
4100
4219
  WebsiteInput.displayName = "WebsiteInput";
4101
4220
 
4102
4221
  // src/components/Feedback/Popover.tsx