@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.js CHANGED
@@ -11,10 +11,40 @@ function cn(...inputs) {
11
11
  return twMerge(clsx(inputs));
12
12
  }
13
13
 
14
+ // src/lib/ripple.ts
15
+ function removeExistingRipples(target) {
16
+ const ripples = target.querySelectorAll(".bubo-ripple");
17
+ ripples.forEach((node) => node.remove());
18
+ }
19
+ function spawnRipple(target, clientX, clientY, options = {}) {
20
+ if (typeof window === "undefined" || typeof document === "undefined") return;
21
+ const rect = target.getBoundingClientRect();
22
+ const x = clientX - rect.left;
23
+ const y = clientY - rect.top;
24
+ const radius = Math.sqrt(rect.width * rect.width + rect.height * rect.height);
25
+ const size = radius * 2;
26
+ removeExistingRipples(target);
27
+ const ripple = document.createElement("span");
28
+ ripple.className = "bubo-ripple";
29
+ ripple.style.width = `${size}px`;
30
+ ripple.style.height = `${size}px`;
31
+ ripple.style.left = `${x - radius}px`;
32
+ ripple.style.top = `${y - radius}px`;
33
+ const durationMs = options.durationMs ?? 500;
34
+ ripple.style.animationDuration = `${durationMs}ms`;
35
+ const cleanup = () => {
36
+ ripple.removeEventListener("animationend", cleanup);
37
+ ripple.remove();
38
+ };
39
+ ripple.addEventListener("animationend", cleanup);
40
+ target.appendChild(ripple);
41
+ window.setTimeout(cleanup, durationMs + 50);
42
+ }
43
+
14
44
  // src/components/Buttons/Button.tsx
15
45
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
16
46
  var buttonVariants = cva(
17
- "inline-flex items-center justify-center whitespace-nowrap rounded-4 transition-colors disabled:pointer-events-none overflow-hidden cursor-pointer",
47
+ "relative inline-flex items-center justify-center whitespace-nowrap rounded-4 transition-colors disabled:pointer-events-none overflow-hidden cursor-pointer",
18
48
  {
19
49
  variants: {
20
50
  variant: {
@@ -39,10 +69,10 @@ var buttonVariants = cva(
39
69
  ]
40
70
  },
41
71
  size: {
42
- sm: ["px-2", "py-1", "gap-2", "h-9"],
43
- md: ["px-2", "py-1", "gap-2", "h-10"],
44
- lg: ["px-2.5", "py-1", "gap-2.5", "h-11"],
45
- xl: ["px-3", "py-0.5", "gap-3", "h-12"]
72
+ sm: ["px-3", "py-1", "gap-2", "h-9"],
73
+ md: ["px-4", "py-2", "gap-2", "h-10"],
74
+ lg: ["px-4", "py-2", "gap-2.5", "h-11"],
75
+ xl: ["px-4", "py-2", "gap-3", "h-12"]
46
76
  }
47
77
  },
48
78
  defaultVariants: {
@@ -81,14 +111,23 @@ var Button = React.forwardRef(
81
111
  children,
82
112
  trailingIcon,
83
113
  leadingIcon,
114
+ onPointerDown,
84
115
  ...rest
85
116
  } = props;
86
117
  const Comp = asChild ? Slot : "button";
118
+ const handlePointerDown = (e) => {
119
+ onPointerDown?.(e);
120
+ if (e.defaultPrevented) return;
121
+ if (rest.disabled) return;
122
+ if (e.button !== 0 || !e.isPrimary) return;
123
+ spawnRipple(e.currentTarget, e.clientX, e.clientY);
124
+ };
87
125
  return /* @__PURE__ */ jsxs(
88
126
  Comp,
89
127
  {
90
128
  className: cn(buttonVariants({ variant, size, className })),
91
129
  ref,
130
+ onPointerDown: handlePointerDown,
92
131
  ...rest,
93
132
  children: [
94
133
  leadingIcon && /* @__PURE__ */ jsx2("div", { className: cn(buttonIconVariants({ size })), children: leadingIcon }),
@@ -141,7 +180,7 @@ import { Slot as Slot2 } from "@radix-ui/react-slot";
141
180
  import { cva as cva3 } from "class-variance-authority";
142
181
  import { jsx as jsx4 } from "react/jsx-runtime";
143
182
  var iconButtonVariants = cva3(
144
- "inline-flex items-center justify-center whitespace-nowrap transition-colors disabled:pointer-events-none overflow-hidden p-2 cursor-pointer",
183
+ "relative inline-flex items-center justify-center whitespace-nowrap transition-colors disabled:pointer-events-none overflow-hidden p-2 cursor-pointer",
145
184
  {
146
185
  variants: {
147
186
  variant: {
@@ -187,14 +226,23 @@ var IconButton = React2.forwardRef(
187
226
  asChild = false,
188
227
  icon,
189
228
  round = false,
229
+ onPointerDown,
190
230
  ...rest
191
231
  } = props;
192
232
  const Comp = asChild ? Slot2 : "button";
233
+ const handlePointerDown = (e) => {
234
+ onPointerDown?.(e);
235
+ if (e.defaultPrevented) return;
236
+ if (rest.disabled) return;
237
+ if (e.button !== 0 || !e.isPrimary) return;
238
+ spawnRipple(e.currentTarget, e.clientX, e.clientY);
239
+ };
193
240
  return /* @__PURE__ */ jsx4(
194
241
  Comp,
195
242
  {
196
243
  className: cn(iconButtonVariants({ variant, size }), round ? "rounded-full" : "rounded-4", className),
197
244
  ref,
245
+ onPointerDown: handlePointerDown,
198
246
  ...rest,
199
247
  children: /* @__PURE__ */ jsx4("div", { className: "buttonIcon flex items-center justify-center", children: icon })
200
248
  }
@@ -1459,16 +1507,17 @@ var MenuSubContent = DropdownMenuSubContent;
1459
1507
  var MenuSubTrigger = DropdownMenuSubTrigger;
1460
1508
 
1461
1509
  // src/components/Inputs/Checkbox.tsx
1462
- import "react";
1510
+ import * as React20 from "react";
1463
1511
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
1464
1512
  import { CheckIcon as CheckIcon2 } from "@bubo-squared/icons";
1465
1513
  import { MinusIcon } from "@bubo-squared/icons";
1466
1514
  import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1467
- function Checkbox({ label, className, ...props }) {
1515
+ var Checkbox = React20.forwardRef(({ label, className, ...props }, forwardedRef) => {
1468
1516
  return /* @__PURE__ */ jsxs14("label", { className: "inline-flex items-center gap-(--space-12) cursor-pointer select-none", children: [
1469
1517
  /* @__PURE__ */ jsx22(
1470
1518
  CheckboxPrimitive.Root,
1471
1519
  {
1520
+ ref: forwardedRef,
1472
1521
  className: cn(
1473
1522
  "group flex h-5 w-5 items-center justify-center rounded-2 border border-(--border-secondary) bg-(--background-neutral) text-primary-inverse",
1474
1523
  "data-[state=checked]:bg-(--background-brand) data-[state=checked]:text-button-white data-[state=checked]:border-none",
@@ -1490,7 +1539,8 @@ function Checkbox({ label, className, ...props }) {
1490
1539
  ),
1491
1540
  label && /* @__PURE__ */ jsx22("span", { className: "paragraph-md-medium text-primary", children: label })
1492
1541
  ] });
1493
- }
1542
+ });
1543
+ Checkbox.displayName = "Checkbox";
1494
1544
 
1495
1545
  // src/components/Inputs/Autocomplete.tsx
1496
1546
  import * as React23 from "react";
@@ -1623,7 +1673,7 @@ var iconWrapperVariants = cva14(
1623
1673
  }
1624
1674
  }
1625
1675
  );
1626
- var Autocomplete = (props) => {
1676
+ var Autocomplete = React23.forwardRef((props, forwardedRef) => {
1627
1677
  const {
1628
1678
  label,
1629
1679
  hint,
@@ -1664,6 +1714,18 @@ var Autocomplete = (props) => {
1664
1714
  const [isFocused, setIsFocused] = React23.useState(false);
1665
1715
  const [activeIndex, setActiveIndex] = React23.useState(-1);
1666
1716
  const inputRef = React23.useRef(null);
1717
+ const setInputRef = React23.useCallback(
1718
+ (node) => {
1719
+ inputRef.current = node;
1720
+ if (!forwardedRef) return;
1721
+ if (typeof forwardedRef === "function") {
1722
+ forwardedRef(node);
1723
+ } else {
1724
+ forwardedRef.current = node;
1725
+ }
1726
+ },
1727
+ [forwardedRef]
1728
+ );
1667
1729
  const baseId = React23.useId();
1668
1730
  const inputId = id ?? baseId;
1669
1731
  const listboxId = `${inputId}-listbox`;
@@ -1776,7 +1838,7 @@ var Autocomplete = (props) => {
1776
1838
  /* @__PURE__ */ jsx25(
1777
1839
  Input,
1778
1840
  {
1779
- ref: inputRef,
1841
+ ref: setInputRef,
1780
1842
  id: inputId,
1781
1843
  type: "text",
1782
1844
  disabled: disabled ?? void 0,
@@ -1851,7 +1913,7 @@ var Autocomplete = (props) => {
1851
1913
  }
1852
1914
  )
1853
1915
  ] }) });
1854
- };
1916
+ });
1855
1917
  Autocomplete.displayName = "Autocomplete";
1856
1918
 
1857
1919
  // src/components/Inputs/Select.tsx
@@ -1934,7 +1996,7 @@ var selectButtonVariants = cva15(
1934
1996
  }
1935
1997
  }
1936
1998
  );
1937
- var Select = (props) => {
1999
+ var Select = React24.forwardRef((props, forwardedRef) => {
1938
2000
  const {
1939
2001
  label = "Field Label",
1940
2002
  hint = "This is a hint text to help user.",
@@ -2009,6 +2071,7 @@ var Select = (props) => {
2009
2071
  /* @__PURE__ */ jsx26(SelectPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs16(
2010
2072
  "button",
2011
2073
  {
2074
+ ref: forwardedRef,
2012
2075
  type: "button",
2013
2076
  "aria-haspopup": "listbox",
2014
2077
  "aria-expanded": isOpen,
@@ -2083,7 +2146,7 @@ var Select = (props) => {
2083
2146
  )
2084
2147
  }
2085
2148
  );
2086
- };
2149
+ });
2087
2150
  Select.displayName = "Select";
2088
2151
 
2089
2152
  // src/components/Inputs/PasswordInput.tsx
@@ -2147,7 +2210,7 @@ var actionButtonVariants = cva16(
2147
2210
  }
2148
2211
  }
2149
2212
  );
2150
- var PasswordInput = (props) => {
2213
+ var PasswordInput = React25.forwardRef((props, forwardedRef) => {
2151
2214
  const {
2152
2215
  label,
2153
2216
  hint,
@@ -2171,6 +2234,18 @@ var PasswordInput = (props) => {
2171
2234
  const [isRevealed, setIsRevealed] = React25.useState(false);
2172
2235
  const currentValue = (isControlled ? value : internalValue) ?? "";
2173
2236
  const inputRef = React25.useRef(null);
2237
+ const setInputRef = React25.useCallback(
2238
+ (node) => {
2239
+ inputRef.current = node;
2240
+ if (!forwardedRef) return;
2241
+ if (typeof forwardedRef === "function") {
2242
+ forwardedRef(node);
2243
+ } else {
2244
+ forwardedRef.current = node;
2245
+ }
2246
+ },
2247
+ [forwardedRef]
2248
+ );
2174
2249
  const showLeadingIcon = !!leadingIcon;
2175
2250
  const handleContainerClick = () => {
2176
2251
  if (disabled) return;
@@ -2211,7 +2286,7 @@ var PasswordInput = (props) => {
2211
2286
  /* @__PURE__ */ jsx27(
2212
2287
  Input,
2213
2288
  {
2214
- ref: inputRef,
2289
+ ref: setInputRef,
2215
2290
  type: isRevealed ? "text" : "password",
2216
2291
  disabled: disabled ?? void 0,
2217
2292
  placeholder,
@@ -2246,7 +2321,7 @@ var PasswordInput = (props) => {
2246
2321
  )
2247
2322
  }
2248
2323
  );
2249
- };
2324
+ });
2250
2325
  PasswordInput.displayName = "PasswordInput";
2251
2326
 
2252
2327
  // src/components/Inputs/PhoneInput.tsx
@@ -2317,7 +2392,7 @@ import "react";
2317
2392
  import * as DialogPrimitive from "@radix-ui/react-dialog";
2318
2393
 
2319
2394
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/createLucideIcon.js
2320
- import { forwardRef as forwardRef15, createElement as createElement2 } from "react";
2395
+ import { forwardRef as forwardRef19, createElement as createElement2 } from "react";
2321
2396
 
2322
2397
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/shared/src/utils.js
2323
2398
  var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
@@ -2341,7 +2416,7 @@ var hasA11yProp = (props) => {
2341
2416
  };
2342
2417
 
2343
2418
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/Icon.js
2344
- import { forwardRef as forwardRef14, createElement } from "react";
2419
+ import { forwardRef as forwardRef18, createElement } from "react";
2345
2420
 
2346
2421
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/defaultAttributes.js
2347
2422
  var defaultAttributes = {
@@ -2357,7 +2432,7 @@ var defaultAttributes = {
2357
2432
  };
2358
2433
 
2359
2434
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/Icon.js
2360
- var Icon2 = forwardRef14(
2435
+ var Icon2 = forwardRef18(
2361
2436
  ({
2362
2437
  color = "currentColor",
2363
2438
  size = 24,
@@ -2389,7 +2464,7 @@ var Icon2 = forwardRef14(
2389
2464
 
2390
2465
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/createLucideIcon.js
2391
2466
  var createLucideIcon = (iconName, iconNode) => {
2392
- const Component = forwardRef15(
2467
+ const Component = forwardRef19(
2393
2468
  ({ className, ...props }, ref) => createElement2(Icon2, {
2394
2469
  ref,
2395
2470
  iconNode,
@@ -2893,19 +2968,20 @@ var FlagComponent = ({ country, countryName }) => {
2893
2968
  import * as React32 from "react";
2894
2969
  import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
2895
2970
  import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
2896
- var RadioGroup = ({
2897
- label,
2898
- hint,
2899
- hideHint,
2900
- options,
2901
- orientation = "vertical",
2902
- disabled = false,
2903
- value,
2904
- defaultValue,
2905
- onValueChange,
2906
- className,
2907
- ...rootProps
2908
- }) => {
2971
+ var RadioGroup = React32.forwardRef((props, forwardedRef) => {
2972
+ const {
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
+ } = props;
2909
2985
  const groupId = React32.useId();
2910
2986
  const hintId = hint ? `${groupId}-hint` : void 0;
2911
2987
  const handleValueChange = (next) => {
@@ -2922,6 +2998,7 @@ var RadioGroup = ({
2922
2998
  children: /* @__PURE__ */ jsx34(
2923
2999
  RadioGroupPrimitive.Root,
2924
3000
  {
3001
+ ref: forwardedRef,
2925
3002
  ...rootProps,
2926
3003
  value,
2927
3004
  defaultValue,
@@ -3002,7 +3079,8 @@ var RadioGroup = ({
3002
3079
  )
3003
3080
  }
3004
3081
  );
3005
- };
3082
+ });
3083
+ RadioGroup.displayName = "RadioGroup";
3006
3084
 
3007
3085
  // src/components/Inputs/SearchInput.tsx
3008
3086
  import * as React33 from "react";
@@ -3038,7 +3116,7 @@ var iconWrapperVariants3 = cva19("flex items-center justify-center shrink-0 text
3038
3116
  size: "lg"
3039
3117
  }
3040
3118
  });
3041
- var SearchInput = (props) => {
3119
+ var SearchInput = React33.forwardRef((props, forwardedRef) => {
3042
3120
  const {
3043
3121
  placeholder = "Search...",
3044
3122
  size = "lg",
@@ -3050,6 +3128,18 @@ var SearchInput = (props) => {
3050
3128
  ...inputProps
3051
3129
  } = props;
3052
3130
  const inputRef = React33.useRef(null);
3131
+ const setInputRef = React33.useCallback(
3132
+ (node) => {
3133
+ inputRef.current = node;
3134
+ if (!forwardedRef) return;
3135
+ if (typeof forwardedRef === "function") {
3136
+ forwardedRef(node);
3137
+ } else {
3138
+ forwardedRef.current = node;
3139
+ }
3140
+ },
3141
+ [forwardedRef]
3142
+ );
3053
3143
  const handleContainerClick = () => {
3054
3144
  if (disabled) return;
3055
3145
  inputRef.current?.focus();
@@ -3068,7 +3158,7 @@ var SearchInput = (props) => {
3068
3158
  /* @__PURE__ */ jsx35(
3069
3159
  Input,
3070
3160
  {
3071
- ref: inputRef,
3161
+ ref: setInputRef,
3072
3162
  type: "search",
3073
3163
  placeholder,
3074
3164
  disabled: disabled ?? void 0,
@@ -3083,7 +3173,7 @@ var SearchInput = (props) => {
3083
3173
  ]
3084
3174
  }
3085
3175
  ) }) });
3086
- };
3176
+ });
3087
3177
  SearchInput.displayName = "SearchInput";
3088
3178
 
3089
3179
  // src/components/Inputs/Slider.tsx
@@ -3137,10 +3227,11 @@ var Tooltip = (props) => {
3137
3227
  open,
3138
3228
  defaultOpen,
3139
3229
  onOpenChange,
3140
- children
3230
+ children,
3231
+ delayDuration = 200
3141
3232
  } = props;
3142
3233
  const { side, align } = mapPlacementToSideAndAlign(placement);
3143
- 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";
3234
+ 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";
3144
3235
  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)]";
3145
3236
  return /* @__PURE__ */ jsxs24(
3146
3237
  TooltipPrimitive.Root,
@@ -3149,6 +3240,7 @@ var Tooltip = (props) => {
3149
3240
  defaultOpen,
3150
3241
  onOpenChange,
3151
3242
  disableHoverableContent,
3243
+ delayDuration,
3152
3244
  children: [
3153
3245
  /* @__PURE__ */ jsx36(TooltipPrimitive.Trigger, { asChild: true, children }),
3154
3246
  /* @__PURE__ */ jsx36(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs24(
@@ -3160,9 +3252,9 @@ var Tooltip = (props) => {
3160
3252
  className: cn(tooltipClasses, className),
3161
3253
  children: [
3162
3254
  showArrow && /* @__PURE__ */ jsx36(TooltipArrow, { className: tooltipArrowClasses }),
3163
- /* @__PURE__ */ jsxs24("div", { className: "grid gap-2", children: [
3255
+ /* @__PURE__ */ jsxs24("div", { className: "grid", children: [
3164
3256
  (strapline ?? "") !== "" && /* @__PURE__ */ jsx36("span", { className: "caption text-secondary", children: strapline }),
3165
- /* @__PURE__ */ jsx36("h4", { className: "subtitle-medium text-primary", children: title }),
3257
+ /* @__PURE__ */ jsx36("h4", { className: "paragraph-md text-primary", children: title }),
3166
3258
  (description ?? "") !== "" && /* @__PURE__ */ jsx36("p", { className: "paragraph-sm text-primary", children: description })
3167
3259
  ] })
3168
3260
  ]
@@ -3184,7 +3276,7 @@ var toArray = (value) => {
3184
3276
  if (value === void 0) return void 0;
3185
3277
  return Array.isArray(value) ? value : [value];
3186
3278
  };
3187
- var Slider = (props) => {
3279
+ var Slider = React35.forwardRef((props, forwardedRef) => {
3188
3280
  const {
3189
3281
  name,
3190
3282
  display = "flat",
@@ -3500,6 +3592,7 @@ var Slider = (props) => {
3500
3592
  {
3501
3593
  className: wrapperBase,
3502
3594
  style: { marginInline: `${thumbRadius}px` },
3595
+ ref: forwardedRef,
3503
3596
  children: [
3504
3597
  name && /* @__PURE__ */ jsxs25(Fragment2, { children: [
3505
3598
  /* @__PURE__ */ jsx37(
@@ -3565,14 +3658,14 @@ var Slider = (props) => {
3565
3658
  ]
3566
3659
  }
3567
3660
  );
3568
- };
3661
+ });
3569
3662
  Slider.displayName = "Slider";
3570
3663
 
3571
3664
  // src/components/Inputs/TextArea.tsx
3572
3665
  import * as React36 from "react";
3573
3666
  import { MaximizeIcon } from "@bubo-squared/icons";
3574
3667
  import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
3575
- var TextArea = (props) => {
3668
+ var TextArea = React36.forwardRef((props, forwardedRef) => {
3576
3669
  const {
3577
3670
  label,
3578
3671
  hint,
@@ -3601,6 +3694,18 @@ var TextArea = (props) => {
3601
3694
  const showCharacterLimit = type === "character-limit" && typeof effectiveMaxLength === "number";
3602
3695
  const textareaRef = React36.useRef(null);
3603
3696
  const containerRef = React36.useRef(null);
3697
+ const setTextareaRef = React36.useCallback(
3698
+ (node) => {
3699
+ textareaRef.current = node;
3700
+ if (!forwardedRef) return;
3701
+ if (typeof forwardedRef === "function") {
3702
+ forwardedRef(node);
3703
+ } else {
3704
+ forwardedRef.current = node;
3705
+ }
3706
+ },
3707
+ [forwardedRef]
3708
+ );
3604
3709
  const [height, setHeight] = React36.useState(void 0);
3605
3710
  const [width, setWidth] = React36.useState(void 0);
3606
3711
  const minHeight = 80;
@@ -3622,10 +3727,10 @@ var TextArea = (props) => {
3622
3727
  success: "border-(--border-success)",
3623
3728
  error: "border-(--border-error)"
3624
3729
  };
3625
- const statusFocusClass = {
3626
- 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)]",
3627
- 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)]",
3628
- 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)]"
3730
+ const statusShellClass = {
3731
+ default: "input-default",
3732
+ success: "input-success",
3733
+ error: "input-error"
3629
3734
  };
3630
3735
  const counterColorClass = disabled ? "text-primary-disabled" : status === "success" ? "text-(--color-success)" : status === "error" ? "text-(--color-error)" : "text-primary";
3631
3736
  const handleResizePointerDown = (event) => {
@@ -3665,11 +3770,11 @@ var TextArea = (props) => {
3665
3770
  "div",
3666
3771
  {
3667
3772
  className: cn(
3668
- "relative flex w-full rounded-4 border bg-(--background-primary) cursor-text transition-colors",
3669
- "border-(--border-secondary) hover:border-(--border-secondary-hover) hover:bg-(--background-primary-hover)",
3773
+ "relative flex w-full rounded-4 border bg-(--background-primary) cursor-text",
3774
+ "border-(--border-secondary)",
3775
+ statusShellClass[status],
3670
3776
  disabled && "bg-(--background-primary-disabled) border-(--border-secondary-disabled) cursor-default",
3671
3777
  statusBorderClass[status],
3672
- !disabled && statusFocusClass[status],
3673
3778
  className
3674
3779
  ),
3675
3780
  ref: containerRef,
@@ -3685,7 +3790,7 @@ var TextArea = (props) => {
3685
3790
  {
3686
3791
  id: textareaId,
3687
3792
  name,
3688
- ref: textareaRef,
3793
+ ref: setTextareaRef,
3689
3794
  disabled: disabled ?? void 0,
3690
3795
  value: isControlled ? value : currentValue,
3691
3796
  defaultValue: isControlled ? void 0 : defaultValue,
@@ -3736,7 +3841,7 @@ var TextArea = (props) => {
3736
3841
  )
3737
3842
  }
3738
3843
  );
3739
- };
3844
+ });
3740
3845
  TextArea.displayName = "TextArea";
3741
3846
 
3742
3847
  // src/components/Inputs/TextInput.tsx
@@ -3775,7 +3880,7 @@ var iconWrapperVariants4 = cva20(
3775
3880
  }
3776
3881
  }
3777
3882
  );
3778
- var TextInput = (props) => {
3883
+ var TextInput = React37.forwardRef((props, forwardedRef) => {
3779
3884
  const {
3780
3885
  label,
3781
3886
  hint,
@@ -3798,6 +3903,18 @@ var TextInput = (props) => {
3798
3903
  );
3799
3904
  const currentValue = (isControlled ? value : internalValue) ?? "";
3800
3905
  const inputRef = React37.useRef(null);
3906
+ const setInputRef = React37.useCallback(
3907
+ (node) => {
3908
+ inputRef.current = node;
3909
+ if (!forwardedRef) return;
3910
+ if (typeof forwardedRef === "function") {
3911
+ forwardedRef(node);
3912
+ } else {
3913
+ forwardedRef.current = node;
3914
+ }
3915
+ },
3916
+ [forwardedRef]
3917
+ );
3801
3918
  const handleContainerClick = () => {
3802
3919
  if (disabled) return;
3803
3920
  inputRef.current?.focus();
@@ -3839,7 +3956,7 @@ var TextInput = (props) => {
3839
3956
  /* @__PURE__ */ jsx39(
3840
3957
  Input,
3841
3958
  {
3842
- ref: inputRef,
3959
+ ref: setInputRef,
3843
3960
  type: "text",
3844
3961
  disabled: disabled ?? void 0,
3845
3962
  placeholder,
@@ -3868,13 +3985,13 @@ var TextInput = (props) => {
3868
3985
  )
3869
3986
  }
3870
3987
  );
3871
- };
3988
+ });
3872
3989
  TextInput.displayName = "TextInput";
3873
3990
 
3874
3991
  // src/components/Inputs/Toggle.tsx
3875
- import "react";
3992
+ import * as React38 from "react";
3876
3993
  import { jsx as jsx40, jsxs as jsxs28 } from "react/jsx-runtime";
3877
- var Toggle = (props) => {
3994
+ var Toggle = React38.forwardRef((props, forwardedRef) => {
3878
3995
  const { label, className, disabled, ...inputProps } = props;
3879
3996
  return /* @__PURE__ */ jsxs28(
3880
3997
  "label",
@@ -3888,6 +4005,7 @@ var Toggle = (props) => {
3888
4005
  /* @__PURE__ */ jsx40(
3889
4006
  "input",
3890
4007
  {
4008
+ ref: forwardedRef,
3891
4009
  type: "checkbox",
3892
4010
  disabled,
3893
4011
  className: "peer sr-only",
@@ -3959,13 +4077,13 @@ var Toggle = (props) => {
3959
4077
  ]
3960
4078
  }
3961
4079
  );
3962
- };
4080
+ });
3963
4081
  Toggle.displayName = "Toggle";
3964
4082
 
3965
4083
  // src/components/Inputs/WebsiteInput.tsx
3966
- import "react";
4084
+ import * as React39 from "react";
3967
4085
  import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
3968
- var WebsiteInput = (props) => {
4086
+ var WebsiteInput = React39.forwardRef((props, forwardedRef) => {
3969
4087
  const {
3970
4088
  hierarchy = "leading",
3971
4089
  protocolLabel = "http://",
@@ -4012,6 +4130,7 @@ var WebsiteInput = (props) => {
4012
4130
  return /* @__PURE__ */ jsx41(
4013
4131
  TextInput,
4014
4132
  {
4133
+ ref: forwardedRef,
4015
4134
  ...rest,
4016
4135
  size,
4017
4136
  disabled,
@@ -4020,7 +4139,7 @@ var WebsiteInput = (props) => {
4020
4139
  trailingIcon: !isLeading ? trailingAddon : void 0
4021
4140
  }
4022
4141
  );
4023
- };
4142
+ });
4024
4143
  WebsiteInput.displayName = "WebsiteInput";
4025
4144
 
4026
4145
  // src/components/Feedback/Popover.tsx