@bubo-squared/ui-framework 0.2.20 → 0.2.22

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
@@ -69,10 +69,10 @@ var buttonVariants = cva(
69
69
  ]
70
70
  },
71
71
  size: {
72
- sm: ["px-2", "py-1", "gap-2", "h-9"],
73
- md: ["px-2", "py-1", "gap-2", "h-10"],
74
- lg: ["px-2.5", "py-1", "gap-2.5", "h-11"],
75
- 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"]
76
76
  }
77
77
  },
78
78
  defaultVariants: {
@@ -692,13 +692,14 @@ var Badge = React9.forwardRef(
692
692
  ...rest
693
693
  } = props;
694
694
  const Comp = asChild ? Slot5 : "div";
695
+ const hasValue = typeof value === "string" ? value.trim() !== "" : value != null;
695
696
  return /* @__PURE__ */ jsx11(
696
697
  Comp,
697
698
  {
698
699
  ref,
699
700
  className: cn(badgeVariants({ size, variant }), className),
700
701
  ...rest,
701
- children: value ? /* @__PURE__ */ jsxs6(Fragment, { children: [
702
+ children: hasValue ? /* @__PURE__ */ jsxs6(Fragment, { children: [
702
703
  /* @__PURE__ */ jsx11("span", { className: "font-normal", children: label }),
703
704
  /* @__PURE__ */ jsx11("span", { className: "font-normal", children: ":" }),
704
705
  /* @__PURE__ */ jsx11("span", { className: "font-medium", children: value })
@@ -879,7 +880,7 @@ var Divider = (props) => {
879
880
  className: _className,
880
881
  ...divProps
881
882
  } = props;
882
- const textLabel = label ? label : "OR";
883
+ const textLabel = label ?? "OR";
883
884
  return /* @__PURE__ */ jsxs8(
884
885
  "div",
885
886
  {
@@ -1027,13 +1028,15 @@ var Field = (props) => {
1027
1028
  className,
1028
1029
  children
1029
1030
  } = props;
1031
+ const hasLabel = label != null;
1032
+ const hasHint = hint != null;
1030
1033
  const fieldId = React14.useId();
1031
- const labelId = label ? `${fieldId}-label` : void 0;
1032
- const hintId = hint ? `${fieldId}-hint` : void 0;
1034
+ const labelId = hasLabel ? `${fieldId}-label` : void 0;
1035
+ const hintId = hasHint ? `${fieldId}-hint` : void 0;
1033
1036
  const hintColorClass = disabled ? "text-primary-disabled" : status === "success" ? "text-(--color-success)" : status === "error" ? "text-(--color-error)" : "text-(--color-secondary)";
1034
1037
  const labelColorClass = disabled ? "text-primary-disabled" : "text-primary";
1035
1038
  return /* @__PURE__ */ jsxs9("div", { className: cn(fieldBase, className), children: [
1036
- label && /* @__PURE__ */ jsxs9("div", { className: "flex w-full items-center justify-between", children: [
1039
+ hasLabel && /* @__PURE__ */ jsxs9("div", { className: "flex w-full items-center justify-between", children: [
1037
1040
  /* @__PURE__ */ jsx16("label", { id: labelId, className: cn("paragraph-sm", labelColorClass), children: label }),
1038
1041
  labelRight
1039
1042
  ] }),
@@ -1041,9 +1044,9 @@ var Field = (props) => {
1041
1044
  !hideHint && /* @__PURE__ */ jsx16(
1042
1045
  "p",
1043
1046
  {
1044
- id: hint ? hintId : void 0,
1045
- className: cn("caption", hint ? hintColorClass : "invisible"),
1046
- children: hint || "\xA0"
1047
+ id: hasHint ? hintId : void 0,
1048
+ className: cn("caption", hasHint ? hintColorClass : "invisible"),
1049
+ children: hasHint ? hint : "\xA0"
1047
1050
  }
1048
1051
  )
1049
1052
  ] });
@@ -1063,6 +1066,7 @@ var Progress = React15.forwardRef(
1063
1066
  value,
1064
1067
  label,
1065
1068
  hint,
1069
+ ariaLabel,
1066
1070
  showProgressLabel = true,
1067
1071
  hideHint,
1068
1072
  size = "lg",
@@ -1073,12 +1077,13 @@ var Progress = React15.forwardRef(
1073
1077
  } = props;
1074
1078
  const clamped = Number.isFinite(value) ? Math.min(100, Math.max(0, value)) : 0;
1075
1079
  const percentageLabel = `${Math.round(clamped)}%`;
1080
+ const resolvedAriaLabel = ariaLabel ?? (typeof label === "string" ? label : void 0);
1076
1081
  const barHeightClasses = sizeToBarClasses[size];
1077
1082
  return /* @__PURE__ */ jsx17(
1078
1083
  Field,
1079
1084
  {
1080
1085
  label,
1081
- labelRight: showProgressLabel && label ? /* @__PURE__ */ jsx17("span", { className: "footnote text-(--color-secondary)", children: percentageLabel }) : void 0,
1086
+ labelRight: showProgressLabel && label != null ? /* @__PURE__ */ jsx17("span", { className: "footnote text-(--color-secondary)", children: percentageLabel }) : void 0,
1082
1087
  hint,
1083
1088
  hideHint,
1084
1089
  status,
@@ -1092,7 +1097,7 @@ var Progress = React15.forwardRef(
1092
1097
  "aria-valuenow": clamped,
1093
1098
  "aria-valuemin": 0,
1094
1099
  "aria-valuemax": 100,
1095
- "aria-label": label,
1100
+ "aria-label": resolvedAriaLabel,
1096
1101
  ...rest,
1097
1102
  children: /* @__PURE__ */ jsx17(
1098
1103
  "div",
@@ -1199,7 +1204,7 @@ import { Slot as Slot6 } from "@radix-ui/react-slot";
1199
1204
  import { cva as cva11 } from "class-variance-authority";
1200
1205
  import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
1201
1206
  var tagVariants = cva11(
1202
- "inline-flex flex-row items-center justify-center rounded-6 gap-2 px-3 overflow-hidden border-1 border-(--border-secondary) bg-(--background-neutral) hover:border-(--border-secondary-hover) focus:border-(--border-brand) focus-ring-primary ",
1207
+ "inline-flex flex-row items-center justify-center rounded-6 gap-2 px-3 overflow-hidden border-1 border-(--border-secondary) bg-(--background-neutral) focus:border-(--border-brand) focus-ring-primary ",
1203
1208
  {
1204
1209
  variants: {
1205
1210
  size: {
@@ -1225,6 +1230,7 @@ var Tag = React17.forwardRef(
1225
1230
  value,
1226
1231
  ...rest
1227
1232
  } = props;
1233
+ const hasValue = typeof value === "string" ? value.trim() !== "" : value != null;
1228
1234
  const Comp = asChild ? Slot6 : "div";
1229
1235
  const leading = props.leadingIcon && React17.isValidElement(props.leadingIcon) ? React17.cloneElement(props.leadingIcon, { disabled, ...props.leadingIcon.props }) : null;
1230
1236
  const trailing = props.trailingIcon && React17.isValidElement(props.trailingIcon) ? React17.cloneElement(props.trailingIcon, { disabled, ...props.trailingIcon.props }) : null;
@@ -1236,7 +1242,7 @@ var Tag = React17.forwardRef(
1236
1242
  ...rest,
1237
1243
  children: [
1238
1244
  leading && /* @__PURE__ */ jsx19("div", { className: iconClasses, children: leading }),
1239
- value ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-row gap-1 items-center", children: [
1245
+ hasValue ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-row gap-1 items-center", children: [
1240
1246
  /* @__PURE__ */ jsx19("span", { className: "text-primary paragraph-lg mb-0! cursor-default font-normal", children: label }),
1241
1247
  /* @__PURE__ */ jsx19("span", { className: "text-primary paragraph-lg mb-0! cursor-default font-normal", children: ":" }),
1242
1248
  /* @__PURE__ */ jsx19("span", { className: "text-primary paragraph-lg-medium mb-0! cursor-default font-medium", children: value })
@@ -1507,16 +1513,17 @@ var MenuSubContent = DropdownMenuSubContent;
1507
1513
  var MenuSubTrigger = DropdownMenuSubTrigger;
1508
1514
 
1509
1515
  // src/components/Inputs/Checkbox.tsx
1510
- import "react";
1516
+ import * as React20 from "react";
1511
1517
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
1512
1518
  import { CheckIcon as CheckIcon2 } from "@bubo-squared/icons";
1513
1519
  import { MinusIcon } from "@bubo-squared/icons";
1514
1520
  import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1515
- function Checkbox({ label, className, ...props }) {
1521
+ var Checkbox = React20.forwardRef(({ label, className, ...props }, forwardedRef) => {
1516
1522
  return /* @__PURE__ */ jsxs14("label", { className: "inline-flex items-center gap-(--space-12) cursor-pointer select-none", children: [
1517
1523
  /* @__PURE__ */ jsx22(
1518
1524
  CheckboxPrimitive.Root,
1519
1525
  {
1526
+ ref: forwardedRef,
1520
1527
  className: cn(
1521
1528
  "group flex h-5 w-5 items-center justify-center rounded-2 border border-(--border-secondary) bg-(--background-neutral) text-primary-inverse",
1522
1529
  "data-[state=checked]:bg-(--background-brand) data-[state=checked]:text-button-white data-[state=checked]:border-none",
@@ -1538,7 +1545,8 @@ function Checkbox({ label, className, ...props }) {
1538
1545
  ),
1539
1546
  label && /* @__PURE__ */ jsx22("span", { className: "paragraph-md-medium text-primary", children: label })
1540
1547
  ] });
1541
- }
1548
+ });
1549
+ Checkbox.displayName = "Checkbox";
1542
1550
 
1543
1551
  // src/components/Inputs/Autocomplete.tsx
1544
1552
  import * as React23 from "react";
@@ -1671,7 +1679,7 @@ var iconWrapperVariants = cva14(
1671
1679
  }
1672
1680
  }
1673
1681
  );
1674
- var Autocomplete = (props) => {
1682
+ var Autocomplete = React23.forwardRef((props, forwardedRef) => {
1675
1683
  const {
1676
1684
  label,
1677
1685
  hint,
@@ -1692,6 +1700,7 @@ var Autocomplete = (props) => {
1692
1700
  inputValue,
1693
1701
  defaultInputValue,
1694
1702
  onInputChange,
1703
+ freeSolo = false,
1695
1704
  dropdownClassName,
1696
1705
  listboxClassName,
1697
1706
  placeholder = "Search\u2026",
@@ -1712,6 +1721,18 @@ var Autocomplete = (props) => {
1712
1721
  const [isFocused, setIsFocused] = React23.useState(false);
1713
1722
  const [activeIndex, setActiveIndex] = React23.useState(-1);
1714
1723
  const inputRef = React23.useRef(null);
1724
+ const setInputRef = React23.useCallback(
1725
+ (node) => {
1726
+ inputRef.current = node;
1727
+ if (!forwardedRef) return;
1728
+ if (typeof forwardedRef === "function") {
1729
+ forwardedRef(node);
1730
+ } else {
1731
+ forwardedRef.current = node;
1732
+ }
1733
+ },
1734
+ [forwardedRef]
1735
+ );
1715
1736
  const baseId = React23.useId();
1716
1737
  const inputId = id ?? baseId;
1717
1738
  const listboxId = `${inputId}-listbox`;
@@ -1730,6 +1751,12 @@ var Autocomplete = (props) => {
1730
1751
  }
1731
1752
  onInputChange?.(next);
1732
1753
  };
1754
+ const commitTypedValue = (next) => {
1755
+ if (!isValueControlled) {
1756
+ setInternalValue(next);
1757
+ }
1758
+ onChange?.(next);
1759
+ };
1733
1760
  const commitValue = (next) => {
1734
1761
  if (!isValueControlled) {
1735
1762
  setInternalValue(next);
@@ -1746,6 +1773,9 @@ var Autocomplete = (props) => {
1746
1773
  const next = event.target.value;
1747
1774
  setInputText(next);
1748
1775
  setActiveIndex(-1);
1776
+ if (freeSolo) {
1777
+ commitTypedValue(next);
1778
+ }
1749
1779
  };
1750
1780
  const handleFocus = (event) => {
1751
1781
  setIsFocused(true);
@@ -1754,6 +1784,12 @@ var Autocomplete = (props) => {
1754
1784
  const handleBlur = (event) => {
1755
1785
  setIsFocused(false);
1756
1786
  setActiveIndex(-1);
1787
+ if (freeSolo) {
1788
+ const trimmed = currentInput.trim();
1789
+ if (trimmed.length > 0 && currentInput !== currentValue) {
1790
+ commitTypedValue(currentInput);
1791
+ }
1792
+ }
1757
1793
  onBlur?.(event);
1758
1794
  };
1759
1795
  const handleKeyDown = (event) => {
@@ -1787,6 +1823,17 @@ var Autocomplete = (props) => {
1787
1823
  event.preventDefault();
1788
1824
  commitValue(options[activeIndex]);
1789
1825
  setIsFocused(false);
1826
+ break;
1827
+ }
1828
+ if (freeSolo) {
1829
+ const trimmed = currentInput.trim();
1830
+ if (trimmed.length > 0) {
1831
+ event.preventDefault();
1832
+ if (currentInput !== currentValue) {
1833
+ commitTypedValue(currentInput);
1834
+ }
1835
+ setIsFocused(false);
1836
+ }
1790
1837
  }
1791
1838
  break;
1792
1839
  }
@@ -1824,7 +1871,7 @@ var Autocomplete = (props) => {
1824
1871
  /* @__PURE__ */ jsx25(
1825
1872
  Input,
1826
1873
  {
1827
- ref: inputRef,
1874
+ ref: setInputRef,
1828
1875
  id: inputId,
1829
1876
  type: "text",
1830
1877
  disabled: disabled ?? void 0,
@@ -1899,7 +1946,7 @@ var Autocomplete = (props) => {
1899
1946
  }
1900
1947
  )
1901
1948
  ] }) });
1902
- };
1949
+ });
1903
1950
  Autocomplete.displayName = "Autocomplete";
1904
1951
 
1905
1952
  // src/components/Inputs/Select.tsx
@@ -1982,7 +2029,7 @@ var selectButtonVariants = cva15(
1982
2029
  }
1983
2030
  }
1984
2031
  );
1985
- var Select = (props) => {
2032
+ var Select = React24.forwardRef((props, forwardedRef) => {
1986
2033
  const {
1987
2034
  label = "Field Label",
1988
2035
  hint = "This is a hint text to help user.",
@@ -2057,6 +2104,7 @@ var Select = (props) => {
2057
2104
  /* @__PURE__ */ jsx26(SelectPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs16(
2058
2105
  "button",
2059
2106
  {
2107
+ ref: forwardedRef,
2060
2108
  type: "button",
2061
2109
  "aria-haspopup": "listbox",
2062
2110
  "aria-expanded": isOpen,
@@ -2131,7 +2179,7 @@ var Select = (props) => {
2131
2179
  )
2132
2180
  }
2133
2181
  );
2134
- };
2182
+ });
2135
2183
  Select.displayName = "Select";
2136
2184
 
2137
2185
  // src/components/Inputs/PasswordInput.tsx
@@ -2195,7 +2243,7 @@ var actionButtonVariants = cva16(
2195
2243
  }
2196
2244
  }
2197
2245
  );
2198
- var PasswordInput = (props) => {
2246
+ var PasswordInput = React25.forwardRef((props, forwardedRef) => {
2199
2247
  const {
2200
2248
  label,
2201
2249
  hint,
@@ -2219,6 +2267,18 @@ var PasswordInput = (props) => {
2219
2267
  const [isRevealed, setIsRevealed] = React25.useState(false);
2220
2268
  const currentValue = (isControlled ? value : internalValue) ?? "";
2221
2269
  const inputRef = React25.useRef(null);
2270
+ const setInputRef = React25.useCallback(
2271
+ (node) => {
2272
+ inputRef.current = node;
2273
+ if (!forwardedRef) return;
2274
+ if (typeof forwardedRef === "function") {
2275
+ forwardedRef(node);
2276
+ } else {
2277
+ forwardedRef.current = node;
2278
+ }
2279
+ },
2280
+ [forwardedRef]
2281
+ );
2222
2282
  const showLeadingIcon = !!leadingIcon;
2223
2283
  const handleContainerClick = () => {
2224
2284
  if (disabled) return;
@@ -2259,7 +2319,7 @@ var PasswordInput = (props) => {
2259
2319
  /* @__PURE__ */ jsx27(
2260
2320
  Input,
2261
2321
  {
2262
- ref: inputRef,
2322
+ ref: setInputRef,
2263
2323
  type: isRevealed ? "text" : "password",
2264
2324
  disabled: disabled ?? void 0,
2265
2325
  placeholder,
@@ -2294,7 +2354,7 @@ var PasswordInput = (props) => {
2294
2354
  )
2295
2355
  }
2296
2356
  );
2297
- };
2357
+ });
2298
2358
  PasswordInput.displayName = "PasswordInput";
2299
2359
 
2300
2360
  // src/components/Inputs/PhoneInput.tsx
@@ -2365,7 +2425,7 @@ import "react";
2365
2425
  import * as DialogPrimitive from "@radix-ui/react-dialog";
2366
2426
 
2367
2427
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/createLucideIcon.js
2368
- import { forwardRef as forwardRef15, createElement as createElement2 } from "react";
2428
+ import { forwardRef as forwardRef19, createElement as createElement2 } from "react";
2369
2429
 
2370
2430
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/shared/src/utils.js
2371
2431
  var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
@@ -2389,7 +2449,7 @@ var hasA11yProp = (props) => {
2389
2449
  };
2390
2450
 
2391
2451
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/Icon.js
2392
- import { forwardRef as forwardRef14, createElement } from "react";
2452
+ import { forwardRef as forwardRef18, createElement } from "react";
2393
2453
 
2394
2454
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/defaultAttributes.js
2395
2455
  var defaultAttributes = {
@@ -2405,7 +2465,7 @@ var defaultAttributes = {
2405
2465
  };
2406
2466
 
2407
2467
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/Icon.js
2408
- var Icon2 = forwardRef14(
2468
+ var Icon2 = forwardRef18(
2409
2469
  ({
2410
2470
  color = "currentColor",
2411
2471
  size = 24,
@@ -2437,7 +2497,7 @@ var Icon2 = forwardRef14(
2437
2497
 
2438
2498
  // ../../node_modules/.pnpm/lucide-react@0.555.0_react@19.2.3/node_modules/lucide-react/dist/esm/createLucideIcon.js
2439
2499
  var createLucideIcon = (iconName, iconNode) => {
2440
- const Component = forwardRef15(
2500
+ const Component = forwardRef19(
2441
2501
  ({ className, ...props }, ref) => createElement2(Icon2, {
2442
2502
  ref,
2443
2503
  iconNode,
@@ -2941,19 +3001,20 @@ var FlagComponent = ({ country, countryName }) => {
2941
3001
  import * as React32 from "react";
2942
3002
  import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
2943
3003
  import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
2944
- var RadioGroup = ({
2945
- label,
2946
- hint,
2947
- hideHint,
2948
- options,
2949
- orientation = "vertical",
2950
- disabled = false,
2951
- value,
2952
- defaultValue,
2953
- onValueChange,
2954
- className,
2955
- ...rootProps
2956
- }) => {
3004
+ var RadioGroup = React32.forwardRef((props, forwardedRef) => {
3005
+ const {
3006
+ label,
3007
+ hint,
3008
+ hideHint,
3009
+ options,
3010
+ orientation = "vertical",
3011
+ disabled = false,
3012
+ value,
3013
+ defaultValue,
3014
+ onValueChange,
3015
+ className,
3016
+ ...rootProps
3017
+ } = props;
2957
3018
  const groupId = React32.useId();
2958
3019
  const hintId = hint ? `${groupId}-hint` : void 0;
2959
3020
  const handleValueChange = (next) => {
@@ -2970,6 +3031,7 @@ var RadioGroup = ({
2970
3031
  children: /* @__PURE__ */ jsx34(
2971
3032
  RadioGroupPrimitive.Root,
2972
3033
  {
3034
+ ref: forwardedRef,
2973
3035
  ...rootProps,
2974
3036
  value,
2975
3037
  defaultValue,
@@ -3050,7 +3112,8 @@ var RadioGroup = ({
3050
3112
  )
3051
3113
  }
3052
3114
  );
3053
- };
3115
+ });
3116
+ RadioGroup.displayName = "RadioGroup";
3054
3117
 
3055
3118
  // src/components/Inputs/SearchInput.tsx
3056
3119
  import * as React33 from "react";
@@ -3086,7 +3149,7 @@ var iconWrapperVariants3 = cva19("flex items-center justify-center shrink-0 text
3086
3149
  size: "lg"
3087
3150
  }
3088
3151
  });
3089
- var SearchInput = (props) => {
3152
+ var SearchInput = React33.forwardRef((props, forwardedRef) => {
3090
3153
  const {
3091
3154
  placeholder = "Search...",
3092
3155
  size = "lg",
@@ -3098,6 +3161,18 @@ var SearchInput = (props) => {
3098
3161
  ...inputProps
3099
3162
  } = props;
3100
3163
  const inputRef = React33.useRef(null);
3164
+ const setInputRef = React33.useCallback(
3165
+ (node) => {
3166
+ inputRef.current = node;
3167
+ if (!forwardedRef) return;
3168
+ if (typeof forwardedRef === "function") {
3169
+ forwardedRef(node);
3170
+ } else {
3171
+ forwardedRef.current = node;
3172
+ }
3173
+ },
3174
+ [forwardedRef]
3175
+ );
3101
3176
  const handleContainerClick = () => {
3102
3177
  if (disabled) return;
3103
3178
  inputRef.current?.focus();
@@ -3116,7 +3191,7 @@ var SearchInput = (props) => {
3116
3191
  /* @__PURE__ */ jsx35(
3117
3192
  Input,
3118
3193
  {
3119
- ref: inputRef,
3194
+ ref: setInputRef,
3120
3195
  type: "search",
3121
3196
  placeholder,
3122
3197
  disabled: disabled ?? void 0,
@@ -3131,7 +3206,7 @@ var SearchInput = (props) => {
3131
3206
  ]
3132
3207
  }
3133
3208
  ) }) });
3134
- };
3209
+ });
3135
3210
  SearchInput.displayName = "SearchInput";
3136
3211
 
3137
3212
  // src/components/Inputs/Slider.tsx
@@ -3188,6 +3263,8 @@ var Tooltip = (props) => {
3188
3263
  children,
3189
3264
  delayDuration = 200
3190
3265
  } = props;
3266
+ const hasStrapline = typeof strapline === "string" ? strapline.trim() !== "" : strapline != null;
3267
+ const hasDescription = typeof description === "string" ? description.trim() !== "" : description != null;
3191
3268
  const { side, align } = mapPlacementToSideAndAlign(placement);
3192
3269
  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";
3193
3270
  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)]";
@@ -3211,9 +3288,9 @@ var Tooltip = (props) => {
3211
3288
  children: [
3212
3289
  showArrow && /* @__PURE__ */ jsx36(TooltipArrow, { className: tooltipArrowClasses }),
3213
3290
  /* @__PURE__ */ jsxs24("div", { className: "grid", children: [
3214
- (strapline ?? "") !== "" && /* @__PURE__ */ jsx36("span", { className: "caption text-secondary", children: strapline }),
3291
+ hasStrapline && /* @__PURE__ */ jsx36("span", { className: "caption text-secondary", children: strapline }),
3215
3292
  /* @__PURE__ */ jsx36("h4", { className: "paragraph-md text-primary", children: title }),
3216
- (description ?? "") !== "" && /* @__PURE__ */ jsx36("p", { className: "paragraph-sm text-primary", children: description })
3293
+ hasDescription && /* @__PURE__ */ jsx36("p", { className: "paragraph-sm text-primary", children: description })
3217
3294
  ] })
3218
3295
  ]
3219
3296
  }
@@ -3234,7 +3311,7 @@ var toArray = (value) => {
3234
3311
  if (value === void 0) return void 0;
3235
3312
  return Array.isArray(value) ? value : [value];
3236
3313
  };
3237
- var Slider = (props) => {
3314
+ var Slider = React35.forwardRef((props, forwardedRef) => {
3238
3315
  const {
3239
3316
  name,
3240
3317
  display = "flat",
@@ -3550,6 +3627,7 @@ var Slider = (props) => {
3550
3627
  {
3551
3628
  className: wrapperBase,
3552
3629
  style: { marginInline: `${thumbRadius}px` },
3630
+ ref: forwardedRef,
3553
3631
  children: [
3554
3632
  name && /* @__PURE__ */ jsxs25(Fragment2, { children: [
3555
3633
  /* @__PURE__ */ jsx37(
@@ -3615,14 +3693,14 @@ var Slider = (props) => {
3615
3693
  ]
3616
3694
  }
3617
3695
  );
3618
- };
3696
+ });
3619
3697
  Slider.displayName = "Slider";
3620
3698
 
3621
3699
  // src/components/Inputs/TextArea.tsx
3622
3700
  import * as React36 from "react";
3623
3701
  import { MaximizeIcon } from "@bubo-squared/icons";
3624
3702
  import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
3625
- var TextArea = (props) => {
3703
+ var TextArea = React36.forwardRef((props, forwardedRef) => {
3626
3704
  const {
3627
3705
  label,
3628
3706
  hint,
@@ -3651,6 +3729,18 @@ var TextArea = (props) => {
3651
3729
  const showCharacterLimit = type === "character-limit" && typeof effectiveMaxLength === "number";
3652
3730
  const textareaRef = React36.useRef(null);
3653
3731
  const containerRef = React36.useRef(null);
3732
+ const setTextareaRef = React36.useCallback(
3733
+ (node) => {
3734
+ textareaRef.current = node;
3735
+ if (!forwardedRef) return;
3736
+ if (typeof forwardedRef === "function") {
3737
+ forwardedRef(node);
3738
+ } else {
3739
+ forwardedRef.current = node;
3740
+ }
3741
+ },
3742
+ [forwardedRef]
3743
+ );
3654
3744
  const [height, setHeight] = React36.useState(void 0);
3655
3745
  const [width, setWidth] = React36.useState(void 0);
3656
3746
  const minHeight = 80;
@@ -3735,7 +3825,7 @@ var TextArea = (props) => {
3735
3825
  {
3736
3826
  id: textareaId,
3737
3827
  name,
3738
- ref: textareaRef,
3828
+ ref: setTextareaRef,
3739
3829
  disabled: disabled ?? void 0,
3740
3830
  value: isControlled ? value : currentValue,
3741
3831
  defaultValue: isControlled ? void 0 : defaultValue,
@@ -3786,7 +3876,7 @@ var TextArea = (props) => {
3786
3876
  )
3787
3877
  }
3788
3878
  );
3789
- };
3879
+ });
3790
3880
  TextArea.displayName = "TextArea";
3791
3881
 
3792
3882
  // src/components/Inputs/TextInput.tsx
@@ -3825,7 +3915,7 @@ var iconWrapperVariants4 = cva20(
3825
3915
  }
3826
3916
  }
3827
3917
  );
3828
- var TextInput = (props) => {
3918
+ var TextInput = React37.forwardRef((props, forwardedRef) => {
3829
3919
  const {
3830
3920
  label,
3831
3921
  hint,
@@ -3848,6 +3938,18 @@ var TextInput = (props) => {
3848
3938
  );
3849
3939
  const currentValue = (isControlled ? value : internalValue) ?? "";
3850
3940
  const inputRef = React37.useRef(null);
3941
+ const setInputRef = React37.useCallback(
3942
+ (node) => {
3943
+ inputRef.current = node;
3944
+ if (!forwardedRef) return;
3945
+ if (typeof forwardedRef === "function") {
3946
+ forwardedRef(node);
3947
+ } else {
3948
+ forwardedRef.current = node;
3949
+ }
3950
+ },
3951
+ [forwardedRef]
3952
+ );
3851
3953
  const handleContainerClick = () => {
3852
3954
  if (disabled) return;
3853
3955
  inputRef.current?.focus();
@@ -3889,7 +3991,7 @@ var TextInput = (props) => {
3889
3991
  /* @__PURE__ */ jsx39(
3890
3992
  Input,
3891
3993
  {
3892
- ref: inputRef,
3994
+ ref: setInputRef,
3893
3995
  type: "text",
3894
3996
  disabled: disabled ?? void 0,
3895
3997
  placeholder,
@@ -3918,13 +4020,13 @@ var TextInput = (props) => {
3918
4020
  )
3919
4021
  }
3920
4022
  );
3921
- };
4023
+ });
3922
4024
  TextInput.displayName = "TextInput";
3923
4025
 
3924
4026
  // src/components/Inputs/Toggle.tsx
3925
- import "react";
4027
+ import * as React38 from "react";
3926
4028
  import { jsx as jsx40, jsxs as jsxs28 } from "react/jsx-runtime";
3927
- var Toggle = (props) => {
4029
+ var Toggle = React38.forwardRef((props, forwardedRef) => {
3928
4030
  const { label, className, disabled, ...inputProps } = props;
3929
4031
  return /* @__PURE__ */ jsxs28(
3930
4032
  "label",
@@ -3938,6 +4040,7 @@ var Toggle = (props) => {
3938
4040
  /* @__PURE__ */ jsx40(
3939
4041
  "input",
3940
4042
  {
4043
+ ref: forwardedRef,
3941
4044
  type: "checkbox",
3942
4045
  disabled,
3943
4046
  className: "peer sr-only",
@@ -4009,13 +4112,13 @@ var Toggle = (props) => {
4009
4112
  ]
4010
4113
  }
4011
4114
  );
4012
- };
4115
+ });
4013
4116
  Toggle.displayName = "Toggle";
4014
4117
 
4015
4118
  // src/components/Inputs/WebsiteInput.tsx
4016
- import "react";
4119
+ import * as React39 from "react";
4017
4120
  import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
4018
- var WebsiteInput = (props) => {
4121
+ var WebsiteInput = React39.forwardRef((props, forwardedRef) => {
4019
4122
  const {
4020
4123
  hierarchy = "leading",
4021
4124
  protocolLabel = "http://",
@@ -4062,6 +4165,7 @@ var WebsiteInput = (props) => {
4062
4165
  return /* @__PURE__ */ jsx41(
4063
4166
  TextInput,
4064
4167
  {
4168
+ ref: forwardedRef,
4065
4169
  ...rest,
4066
4170
  size,
4067
4171
  disabled,
@@ -4070,7 +4174,7 @@ var WebsiteInput = (props) => {
4070
4174
  trailingIcon: !isLeading ? trailingAddon : void 0
4071
4175
  }
4072
4176
  );
4073
- };
4177
+ });
4074
4178
  WebsiteInput.displayName = "WebsiteInput";
4075
4179
 
4076
4180
  // src/components/Feedback/Popover.tsx
@@ -4093,6 +4197,8 @@ var Popover2 = (props) => {
4093
4197
  offset = 10,
4094
4198
  children
4095
4199
  } = props;
4200
+ const hasStrapline = typeof strapline === "string" ? strapline.trim() !== "" : strapline != null;
4201
+ const hasDescription = typeof description === "string" ? description.trim() !== "" : description != null;
4096
4202
  const [open, setOpen] = React40.useState(false);
4097
4203
  const handleCancel = () => {
4098
4204
  onCancel?.();
@@ -4148,9 +4254,9 @@ var Popover2 = (props) => {
4148
4254
  showArrow && /* @__PURE__ */ jsx42(PopoverArrow, { className: popoverArrowClasses }),
4149
4255
  /* @__PURE__ */ jsxs30("div", { className: "grid gap-4", children: [
4150
4256
  /* @__PURE__ */ jsxs30("div", { className: "space-y-2", children: [
4151
- /* @__PURE__ */ jsx42("span", { className: "caption text-secondary", children: strapline }),
4257
+ hasStrapline && /* @__PURE__ */ jsx42("span", { className: "caption text-secondary", children: strapline }),
4152
4258
  /* @__PURE__ */ jsx42("h4", { className: "subtitle-medium text-primary", children: title }),
4153
- /* @__PURE__ */ jsx42("p", { className: "paragraph-sm text-primary", children: description })
4259
+ hasDescription && /* @__PURE__ */ jsx42("p", { className: "paragraph-sm text-primary", children: description })
4154
4260
  ] }),
4155
4261
  /* @__PURE__ */ jsxs30("div", { className: "flex justify-start items-center gap-4 flex-wrap", children: [
4156
4262
  /* @__PURE__ */ jsx42(Button, { size: "sm", variant: "secondary", onClick: handleCancel, children: cancelText || "Cancel" }),