@trackunit/react-components 1.17.17 → 1.17.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.
Files changed (60) hide show
  1. package/index.cjs.js +182 -170
  2. package/index.esm.js +183 -171
  3. package/package.json +5 -5
  4. package/src/common/Refable.d.ts +5 -0
  5. package/src/components/Alert/Alert.d.ts +3 -2
  6. package/src/components/Badge/Badge.d.ts +3 -2
  7. package/src/components/Breadcrumb/Breadcrumb.d.ts +1 -1
  8. package/src/components/Breadcrumb/utils/types.d.ts +2 -1
  9. package/src/components/Card/Card.d.ts +7 -3
  10. package/src/components/Card/CardBody.d.ts +3 -2
  11. package/src/components/Card/CardFooter.d.ts +3 -2
  12. package/src/components/Card/CardHeader.d.ts +3 -2
  13. package/src/components/Collapse/Collapse.d.ts +3 -2
  14. package/src/components/CopyableText/CopyableText.d.ts +3 -2
  15. package/src/components/DetailsList/DetailsList.d.ts +4 -2
  16. package/src/components/EmptyState/EmptyState.d.ts +2 -1
  17. package/src/components/EmptyValue/EmptyValue.d.ts +2 -1
  18. package/src/components/ExternalLink/ExternalLink.d.ts +3 -2
  19. package/src/components/Heading/Heading.d.ts +3 -2
  20. package/src/components/HorizontalOverflowScroller/HorizontalOverflowScroller.d.ts +4 -2
  21. package/src/components/Icon/Icon.d.ts +4 -9
  22. package/src/components/Indicator/Indicator.d.ts +3 -2
  23. package/src/components/KPI/KPI.d.ts +3 -2
  24. package/src/components/KPI/KPISkeleton.d.ts +3 -2
  25. package/src/components/KPICard/KPICard.d.ts +3 -2
  26. package/src/components/KPICard/KPICardSkeleton.d.ts +3 -2
  27. package/src/components/KPICard/components/TrendIndicator/TrendIndicator.d.ts +3 -2
  28. package/src/components/KPICard/components/TrendIndicators.d.ts +3 -2
  29. package/src/components/Menu/MenuItem/MenuItem.d.ts +3 -2
  30. package/src/components/Menu/MenuList/MenuList.d.ts +3 -2
  31. package/src/components/Menu/MoreMenu/MoreMenu.d.ts +3 -2
  32. package/src/components/Notice/Notice.d.ts +3 -2
  33. package/src/components/Page/Page.d.ts +3 -2
  34. package/src/components/Page/PageContent.d.ts +3 -2
  35. package/src/components/PageHeader/PageHeader.d.ts +1 -1
  36. package/src/components/PageHeader/components/PageHeaderKpiMetrics.d.ts +4 -2
  37. package/src/components/PageHeader/components/PageHeaderTitle.d.ts +4 -2
  38. package/src/components/PageHeader/types.d.ts +2 -1
  39. package/src/components/Pagination/Pagination.d.ts +3 -2
  40. package/src/components/Polygon/Polygon.d.ts +3 -2
  41. package/src/components/Popover/PopoverTitle.d.ts +3 -2
  42. package/src/components/PreferenceCard/PreferenceCard.d.ts +3 -2
  43. package/src/components/PreferenceCard/PreferenceCardSkeleton.d.ts +3 -2
  44. package/src/components/SectionHeader/SectionHeader.d.ts +3 -2
  45. package/src/components/Sidebar/Sidebar.d.ts +3 -2
  46. package/src/components/Skeleton/SkeletonBlock/SkeletonBlock.d.ts +2 -1
  47. package/src/components/Skeleton/SkeletonLabel/SkeletonLabel.d.ts +2 -1
  48. package/src/components/SkeletonLines/SkeletonLines.d.ts +4 -3
  49. package/src/components/Spacer/Spacer.d.ts +3 -2
  50. package/src/components/Spinner/Spinner.d.ts +3 -2
  51. package/src/components/Tabs/Tab.d.ts +3 -2
  52. package/src/components/Tabs/TabContent.d.ts +3 -2
  53. package/src/components/Tabs/TabList.d.ts +3 -2
  54. package/src/components/Tabs/Tabs.d.ts +3 -2
  55. package/src/components/ToggleGroup/ToggleGroup.d.ts +3 -2
  56. package/src/components/Tooltip/Tooltip.d.ts +1 -1
  57. package/src/components/ValueBar/ValueBar.d.ts +3 -2
  58. package/src/components/ZStack/ZStack.d.ts +3 -2
  59. package/src/components/buttons/StarButton/StarButton.d.ts +3 -2
  60. package/src/index.d.ts +1 -0
package/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
2
  import { objectKeys, uuidv4, parseTailwindArbitraryValue, objectEntries, nonNullable, objectValues, filterByMultiple } from '@trackunit/shared-utils';
3
- import { useRef, useMemo, useEffect, useState, useLayoutEffect, useCallback, createElement, forwardRef, Fragment, memo, useId, useReducer, Children, isValidElement, cloneElement, createContext, useContext } from 'react';
3
+ import { useRef, useMemo, useEffect, useState, useLayoutEffect, useCallback, createElement, Fragment, memo, forwardRef, useId, useReducer, Children, isValidElement, cloneElement, createContext, useContext } from 'react';
4
4
  import { rentalStatusPalette, sitesPalette, utilizationPalette, activityPalette, criticalityPalette, generalPalette, intentPalette, themeScreenSizeAsNumber, themeContainerSize, color } from '@trackunit/ui-design-tokens';
5
5
  import { iconNames } from '@trackunit/ui-icons';
6
6
  import IconSpriteMicro from '@trackunit/ui-icons/icons-sprite-micro.svg';
@@ -125,7 +125,7 @@ const isSafari = () => {
125
125
  * @param {IconProps} props - The props for the Icon component
126
126
  * @returns {ReactElement} Icon component
127
127
  */
128
- const Icon = ({ name, size = "medium", className, "data-testid": dataTestId, color = undefined, onClick, type = size === "large" ? "outline" : "solid", style, forwardedRef, ariaLabel, fontSize = false, ariaLabelledBy, ariaDescribedBy, ariaHidden, }) => {
128
+ const Icon = ({ name, size = "medium", className, "data-testid": dataTestId, color = undefined, onClick, type = size === "large" ? "outline" : "solid", style, ref, ariaLabel, fontSize = false, ariaLabelledBy, ariaDescribedBy, ariaHidden, }) => {
129
129
  const useTagRef = useRef(null);
130
130
  const ICON_CONTAINER_ID = uuidv4();
131
131
  const correctIconType = useMemo(() => {
@@ -160,7 +160,7 @@ const Icon = ({ name, size = "medium", className, "data-testid": dataTestId, col
160
160
  useTagRef.current.setAttribute("href", href[correctIconType]);
161
161
  }
162
162
  }, [correctIconType, href]);
163
- return (jsx("span", { "aria-describedby": ariaDescribedBy, "aria-hidden": ariaHidden, "aria-label": ariaLabel ? ariaLabel : titleCase(iconName), "aria-labelledby": ariaLabelledBy, className: cvaIcon({ color, size, fontSize, className }), "data-testid": dataTestId, id: ICON_CONTAINER_ID, onClick: onClick, ref: forwardedRef, children: jsx("svg", { "aria-labelledby": ICON_CONTAINER_ID, "data-testid": dataTestId ? `${dataTestId}-${iconName}` : iconName, role: "img", style: style, viewBox: correctViewBox, children: jsx("use", { href: href[correctIconType], ref: useTagRef }) }) }));
163
+ return (jsx("span", { "aria-describedby": ariaDescribedBy, "aria-hidden": ariaHidden, "aria-label": ariaLabel ? ariaLabel : titleCase(iconName), "aria-labelledby": ariaLabelledBy, className: cvaIcon({ color, size, fontSize, className }), "data-testid": dataTestId, id: ICON_CONTAINER_ID, onClick: onClick, ref: ref, children: jsx("svg", { "aria-labelledby": ICON_CONTAINER_ID, "data-testid": dataTestId ? `${dataTestId}-${iconName}` : iconName, role: "img", style: style, viewBox: correctViewBox, children: jsx("use", { href: href[correctIconType], ref: useTagRef }) }) }));
164
164
  };
165
165
 
166
166
  /**
@@ -381,6 +381,70 @@ const useIsTextWrapping = (options = {}) => {
381
381
  return useMemo(() => ({ ref, isTextWrapping }), [isTextWrapping]);
382
382
  };
383
383
 
384
+ // This hook is _heavily_ inspired by floating-ui's useMergeRefs
385
+ /**
386
+ * Merges an array of refs into a single memoized callback ref or `null`.
387
+ * Useful when you need to attach multiple refs to the same element,
388
+ * such as when composing multiple hooks that each need a ref.
389
+ *
390
+ * @template TInstance - The type of the element instance
391
+ * @param {ReadonlyArray<MergeableRef<TInstance> | undefined>} refs - Array of refs to merge (can be RefObjects, RefCallbacks, or undefined)
392
+ * @returns {null | RefCallback<TInstance>} A single ref callback that will update all provided refs, or null if all refs are null
393
+ * @example
394
+ * ```tsx
395
+ * const { ref: measureRef } = useMeasure();
396
+ * const { ref: scrollRef } = useScrollDetection();
397
+ * const mergedRef = useMergeRefs([measureRef, scrollRef]);
398
+ *
399
+ * return <div ref={mergedRef}>Content</div>;
400
+ * ```
401
+ */
402
+ function useMergeRefs(refs) {
403
+ const cleanupRef = useRef(undefined);
404
+ const refsRef = useRef(refs);
405
+ useEffect(() => {
406
+ refsRef.current = refs;
407
+ }, [refs]);
408
+ const refEffect = useCallback((instance) => {
409
+ const cleanups = refsRef.current.map(ref => {
410
+ if (ref === null || ref === undefined) {
411
+ return;
412
+ }
413
+ if (typeof ref === "function") {
414
+ const refCallback = ref;
415
+ const refCleanup = refCallback(instance);
416
+ return typeof refCleanup === "function"
417
+ ? refCleanup
418
+ : () => {
419
+ refCallback(null);
420
+ };
421
+ }
422
+ ref.current = instance;
423
+ return () => {
424
+ ref.current = null;
425
+ };
426
+ });
427
+ return () => {
428
+ cleanups.forEach(refCleanup => refCleanup?.());
429
+ };
430
+ }, []);
431
+ return useMemo(() => {
432
+ // eslint-disable-next-line react-hooks/refs
433
+ if (refsRef.current.every(ref => ref === null)) {
434
+ return null;
435
+ }
436
+ return (value) => {
437
+ if (cleanupRef.current) {
438
+ cleanupRef.current();
439
+ cleanupRef.current = undefined;
440
+ }
441
+ if (value !== null) {
442
+ cleanupRef.current = refEffect(value);
443
+ }
444
+ };
445
+ }, [refEffect]);
446
+ }
447
+
384
448
  const cvaText = cvaMerge(["text-black", "m-0", "relative", "text-sm", "font-normal"], {
385
449
  variants: {
386
450
  align: {
@@ -516,8 +580,8 @@ const cvaSpinnerLabel = cvaMerge(["self-center", "text-center", "text-current"])
516
580
  * @param {SpinnerProps} props - The props for the Spinner component
517
581
  * @returns {ReactElement} Spinner component
518
582
  */
519
- const Spinner = ({ mode = "light", size = "medium", centering = "centered", className, containerClassName, "data-testid": dataTestId = "spinner", label, }) => {
520
- return (jsx("div", { className: cvaSpinnerContainer({ centering, className: containerClassName }), children: jsxs("div", { className: cvaSpinnerContainerInner(), children: [jsx("div", { className: cvaSpinner({ size, mode, className }), "data-testid": dataTestId, role: "spinbutton" }), label ? jsx("span", { className: cvaSpinnerLabel(), children: label }) : null] }) }));
583
+ const Spinner = ({ mode = "light", size = "medium", centering = "centered", className, containerClassName, "data-testid": dataTestId = "spinner", label, ref, }) => {
584
+ return (jsx("div", { className: cvaSpinnerContainer({ centering, className: containerClassName }), ref: ref, children: jsxs("div", { className: cvaSpinnerContainerInner(), children: [jsx("div", { className: cvaSpinner({ size, mode, className }), "data-testid": dataTestId, role: "spinbutton" }), label ? jsx("span", { className: cvaSpinnerLabel(), children: label }) : null] }) }));
521
585
  };
522
586
 
523
587
  const cvaButton = cvaMerge([
@@ -1052,16 +1116,19 @@ const cvaAlertIconContainer = cvaMerge(["shrink-0", "grid", "w-min", "flex"], {
1052
1116
  * @param {AlertProps} props - The props for the Alert component
1053
1117
  * @returns {ReactElement} Alert component
1054
1118
  */
1055
- const Alert = ({ color = "info", title, className, children, primaryAction, secondaryAction, onClickClose, "data-testid": dataTestId, autoScroll = false, actionsInline = false, }) => {
1056
- const ref = useRef(null);
1119
+ const Alert = ({ color = "info", title, className, children, primaryAction, secondaryAction, onClickClose, "data-testid": dataTestId, autoScroll = false, actionsInline = false, ref, }) => {
1120
+ const scrollRef = useRef(null);
1121
+ const mergedRef = useMergeRefs([scrollRef, ref]);
1057
1122
  const { isTextWrapping, ref: titleRef } = useIsTextWrapping();
1058
1123
  useEffect(() => {
1059
1124
  if (autoScroll) {
1060
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1061
- ref.current?.scrollIntoView?.();
1125
+ const element = scrollRef.current;
1126
+ if (element && typeof element.scrollIntoView === "function") {
1127
+ element.scrollIntoView();
1128
+ }
1062
1129
  }
1063
- }, [ref, autoScroll]);
1064
- return (jsxs("div", { className: cvaAlert({ color, actionsInline, className }), "data-testid": dataTestId, ref: ref, role: "alert", children: [jsxs("div", { className: cvaAlertContentContainer({
1130
+ }, [autoScroll]);
1131
+ return (jsxs("div", { className: cvaAlert({ color, actionsInline, className }), "data-testid": dataTestId, ref: mergedRef, role: "alert", children: [jsxs("div", { className: cvaAlertContentContainer({
1065
1132
  inline: !isTextWrapping && (children === null || children === undefined),
1066
1133
  actionsInline,
1067
1134
  }), children: [jsx("div", { className: cvaAlertIconContainer({
@@ -1176,7 +1243,7 @@ const cvaBadge = cvaMerge([
1176
1243
  * @param {BadgeProps} props - The props for the Badge component
1177
1244
  * @returns {ReactElement} Badge component
1178
1245
  */
1179
- const Badge = ({ color = "primary", size = "default", compact = false, className, count, max, hideZero = false, "data-testid": dataTestId, }) => {
1246
+ const Badge = ({ color = "primary", size = "default", compact = false, className, count, max, hideZero = false, "data-testid": dataTestId, ref, }) => {
1180
1247
  if (hideZero && count === 0) {
1181
1248
  return null;
1182
1249
  }
@@ -1186,7 +1253,7 @@ const Badge = ({ color = "primary", size = "default", compact = false, className
1186
1253
  : count
1187
1254
  : count;
1188
1255
  const isSingleChar = displayedCount?.toString().length === 1;
1189
- return (jsx("span", { className: cvaBadge({ color, size, className, compact, isSingleChar }), "data-testid": dataTestId, children: compact ? null : displayedCount }));
1256
+ return (jsx("span", { className: cvaBadge({ color, size, className, compact, isSingleChar }), "data-testid": dataTestId, ref: ref, children: compact ? null : displayedCount }));
1190
1257
  };
1191
1258
 
1192
1259
  /**
@@ -1390,9 +1457,9 @@ const useBreadcrumbItemsToRender = (breadcrumbItems) => {
1390
1457
  * @param {BreadcrumbProps} props - The props for the Breadcrumb component
1391
1458
  * @returns {ReactElement} Breadcrumb component
1392
1459
  */
1393
- const Breadcrumb = ({ className, "data-testid": dataTestId, breadcrumbItems, onClickBack, }) => {
1460
+ const Breadcrumb = ({ className, "data-testid": dataTestId, breadcrumbItems, onClickBack, ref, }) => {
1394
1461
  const breadCrumbItemsToJSX = useBreadcrumbItemsToRender(breadcrumbItems);
1395
- return (jsxs("div", { className: cvaBreadcrumb({ className }), "data-testid": dataTestId, children: [jsx(IconButton, { "data-testid": `backButton-${dataTestId}`, icon: jsx(Icon, { name: "ArrowLeft", size: "small" }), onClick: onClickBack, size: "small", variant: "ghost-neutral" }), jsx("div", { children: jsx(BreadcrumbContainer, { breadcrumbItems: breadCrumbItemsToJSX, "data-testid": dataTestId }) })] }));
1462
+ return (jsxs("div", { className: cvaBreadcrumb({ className }), "data-testid": dataTestId, ref: ref, children: [jsx(IconButton, { "data-testid": `backButton-${dataTestId}`, icon: jsx(Icon, { name: "ArrowLeft", size: "small" }), onClick: onClickBack, size: "small", variant: "ghost-neutral" }), jsx("div", { children: jsx(BreadcrumbContainer, { breadcrumbItems: breadCrumbItemsToJSX, "data-testid": dataTestId }) })] }));
1396
1463
  };
1397
1464
  /**
1398
1465
  * BreadcrumbContainer is a helper component that renders the breadcrumb items based on the screen size.
@@ -1416,8 +1483,8 @@ const BreadcrumbContainer = ({ "data-testid": dataTestId, breadcrumbItems, }) =>
1416
1483
  * @param {StarButtonProps} props - The props for the StarButton component
1417
1484
  * @returns {ReactElement} StarButton component
1418
1485
  */
1419
- const StarButton = ({ starred, onClick }) => {
1420
- return (jsx("div", { "data-test-id": "starred-filter", onClick: onClick, children: jsx(Icon, { color: starred ? "primary" : "neutral", name: "Star", size: "medium" }) }));
1486
+ const StarButton = ({ starred, onClick, ref }) => {
1487
+ return (jsx("div", { "data-test-id": "starred-filter", onClick: onClick, ref: ref, children: jsx(Icon, { color: starred ? "primary" : "neutral", name: "Star", size: "medium" }) }));
1421
1488
  };
1422
1489
 
1423
1490
  const cvaCard = cvaMerge([
@@ -1554,9 +1621,10 @@ const ROLE_CARD = "region";
1554
1621
  * @param {CardProps} props - The props for the Card component
1555
1622
  * @returns {ReactElement} Card component
1556
1623
  */
1557
- const Card = forwardRef(function Card({ children, onClick, fullHeight = false, onMouseEnter, onMouseLeave, className, "data-testid": dataTestId, ...rest }, ref) {
1624
+ const Card = ({ children, onClick, fullHeight = false, onMouseEnter, onMouseLeave, className, "data-testid": dataTestId, ref, ...rest }) => {
1558
1625
  return (jsx("div", { className: cvaCard({ fullHeight, clickable: Boolean(onClick), className }), "data-card": true, "data-testid": dataTestId, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ref: ref, role: ROLE_CARD, ...rest, children: children }));
1559
- });
1626
+ };
1627
+ Card.displayName = "Card";
1560
1628
 
1561
1629
  /**
1562
1630
  * The CardBody component should be used to inform the user of important information.
@@ -1566,13 +1634,13 @@ const Card = forwardRef(function Card({ children, onClick, fullHeight = false, o
1566
1634
  * @param {CardBodyProps} props - The props for the CardBody component
1567
1635
  * @returns {ReactElement} CardBody component
1568
1636
  */
1569
- const CardBody = ({ children, "data-testid": dataTestId, className, direction = "column", gap = "default", padding = "default", id, }) => {
1637
+ const CardBody = ({ children, "data-testid": dataTestId, className, direction = "column", gap = "default", padding = "default", id, ref, }) => {
1570
1638
  return (jsx("div", { className: cvaCardBodyContainer({
1571
1639
  gap,
1572
1640
  padding,
1573
1641
  className,
1574
1642
  direction,
1575
- }), "data-card-body": true, "data-testid": dataTestId, id: id, children: children }));
1643
+ }), "data-card-body": true, "data-testid": dataTestId, id: id, ref: ref, children: children }));
1576
1644
  };
1577
1645
 
1578
1646
  /**
@@ -1583,12 +1651,12 @@ const CardBody = ({ children, "data-testid": dataTestId, className, direction =
1583
1651
  * @param {CardFooterProps} props - The props for the CardFooter component
1584
1652
  * @returns {ReactElement} CardFooter component
1585
1653
  */
1586
- const CardFooter = ({ "data-testid": dataTestId, className, children, padding = "default", hideSeparator = false, }) => {
1654
+ const CardFooter = ({ "data-testid": dataTestId, className, children, padding = "default", hideSeparator = false, ref, }) => {
1587
1655
  return (jsx("div", { className: cvaCardFooterContainerRoot({
1588
1656
  border: hideSeparator ? "borderless" : "default",
1589
1657
  padding,
1590
1658
  className,
1591
- }), "data-card-footer": true, "data-testid": dataTestId, children: jsx("div", { className: cvaCardFooterContainer(), children: children }) }));
1659
+ }), "data-card-footer": true, "data-testid": dataTestId, ref: ref, children: jsx("div", { className: cvaCardFooterContainer(), children: children }) }));
1592
1660
  };
1593
1661
 
1594
1662
  const cvaHeading = cvaMerge(["m-0", "leading-normal", "text-black"], {
@@ -1628,7 +1696,7 @@ const cvaHeading = cvaMerge(["m-0", "leading-normal", "text-black"], {
1628
1696
  * @param {HeadingProps} props - The props for the Heading component
1629
1697
  * @returns {ReactElement} Heading component
1630
1698
  */
1631
- const Heading = ({ variant = "primary", inverted = false, subtle = false, className, "data-testid": dataTestId, ...rest }) => {
1699
+ const Heading = ({ variant = "primary", inverted = false, subtle = false, className, "data-testid": dataTestId, ref, ...rest }) => {
1632
1700
  const semanticType = {
1633
1701
  primary: "h1",
1634
1702
  secondary: "h2",
@@ -1637,6 +1705,7 @@ const Heading = ({ variant = "primary", inverted = false, subtle = false, classN
1637
1705
  };
1638
1706
  return createElement(semanticType[variant], {
1639
1707
  ...rest,
1708
+ ref,
1640
1709
  className: cvaHeading({ subtle, inverted, size: variant, className }),
1641
1710
  "data-testid": dataTestId,
1642
1711
  });
@@ -1648,12 +1717,12 @@ const Heading = ({ variant = "primary", inverted = false, subtle = false, classN
1648
1717
  * @param {CardHeaderProps} props - The props for the CardHeader component
1649
1718
  * @returns {ReactElement} CardHeader component
1650
1719
  */
1651
- const CardHeader = ({ heading, headingVariant = "secondary", subHeading, onClickClose, "data-testid": dataTestId, className, children, accessories, actions, padding = "default", hideSeparator = false, }) => {
1720
+ const CardHeader = ({ heading, headingVariant = "secondary", subHeading, onClickClose, "data-testid": dataTestId, className, children, accessories, actions, padding = "default", hideSeparator = false, ref, }) => {
1652
1721
  return (jsx("div", { className: cvaCardHeaderContainer({
1653
1722
  border: hideSeparator ? "borderless" : "default",
1654
1723
  padding,
1655
1724
  className,
1656
- }), "data-card-header": true, "data-testid": dataTestId, children: jsxs("div", { className: cvaCardHeader(), children: [jsxs("div", { children: [jsxs("div", { className: cvaCardHeaderHeadingContainer(), children: [jsx(Heading, { className: "self-center", variant: headingVariant, children: heading }), accessories] }), subHeading !== null && subHeading !== undefined ? (jsx(Heading, { subtle: true, variant: "subtitle", children: subHeading })) : null, children] }), jsxs("div", { className: "flex place-items-center gap-x-2 gap-y-1", children: [actions, onClickClose ? (jsx(IconButton, { className: "!h-min", "data-testid": "card-header-close-button", icon: jsx(Icon, { name: "XMark", size: "small" }), onClick: onClickClose, variant: "ghost-neutral" })) : null] })] }) }));
1725
+ }), "data-card-header": true, "data-testid": dataTestId, ref: ref, children: jsxs("div", { className: cvaCardHeader(), children: [jsxs("div", { children: [jsxs("div", { className: cvaCardHeaderHeadingContainer(), children: [jsx(Heading, { className: "self-center", variant: headingVariant, children: heading }), accessories] }), subHeading !== null && subHeading !== undefined ? (jsx(Heading, { subtle: true, variant: "subtitle", children: subHeading })) : null, children] }), jsxs("div", { className: "flex place-items-center gap-x-2 gap-y-1", children: [actions, onClickClose ? (jsx(IconButton, { className: "!h-min", "data-testid": "card-header-close-button", icon: jsx(Icon, { name: "XMark", size: "small" }), onClick: onClickClose, variant: "ghost-neutral" })) : null] })] }) }));
1657
1726
  };
1658
1727
 
1659
1728
  const cvaClickable = cvaMerge([
@@ -1924,7 +1993,7 @@ const cvaChevronIcon = cvaMerge(["transition-transform"], {
1924
1993
  * @param {CollapseProps} props - The props for the Collapse component
1925
1994
  * @returns {ReactElement} Collapse component
1926
1995
  */
1927
- const Collapse = ({ id, variant = "primary", initialExpanded = false, onToggle, label, children, className, headerClassName, headerAddon, "data-testid": dataTestId, animate = true, extraPadding = true, }) => {
1996
+ const Collapse = ({ id, variant = "primary", initialExpanded = false, onToggle, label, children, className, headerClassName, headerAddon, "data-testid": dataTestId, animate = true, extraPadding = true, ref, }) => {
1928
1997
  const LABEL_ID = uuidv4();
1929
1998
  const [expanded, setExpanded] = useState(initialExpanded);
1930
1999
  const handleClick = useCallback((e) => {
@@ -1933,7 +2002,7 @@ const Collapse = ({ id, variant = "primary", initialExpanded = false, onToggle,
1933
2002
  }
1934
2003
  setExpanded(!expanded);
1935
2004
  }, [expanded, onToggle]);
1936
- return (jsxs("div", { className: cvaCollapse({ variant: variant, className }), "data-testid": dataTestId, children: [jsx("div", { "aria-controls": id, "aria-expanded": expanded, className: cvaCollapseHeader({ expanded, variant, extraPadding, className: headerClassName }), onClick: handleClick, role: "button", children: jsxs("div", { className: cvaCollapseLabelContainer({ variant }), children: [jsx(Text, { className: cvaCollapseLabel({ variant }), id: LABEL_ID, size: variant === "secondary" ? "small" : "medium", type: "span", weight: "bold", children: label }), jsxs("div", { className: "flex items-center gap-2", children: [headerAddon !== null && headerAddon !== undefined && variant !== "secondary" ? headerAddon : null, jsx(Icon, { ariaLabelledBy: LABEL_ID, className: cvaChevronIcon({ expanded }), name: "ChevronUp", size: variant === "secondary" ? "small" : "medium" })] })] }) }), jsx(Collapsible, { expanded: expanded, extraPadding: extraPadding, id: id, variant: variant, children: expanded || animate ? children : null })] }));
2005
+ return (jsxs("div", { className: cvaCollapse({ variant: variant, className }), "data-testid": dataTestId, ref: ref, children: [jsx("div", { "aria-controls": id, "aria-expanded": expanded, className: cvaCollapseHeader({ expanded, variant, extraPadding, className: headerClassName }), onClick: handleClick, role: "button", children: jsxs("div", { className: cvaCollapseLabelContainer({ variant }), children: [jsx(Text, { className: cvaCollapseLabel({ variant }), id: LABEL_ID, size: variant === "secondary" ? "small" : "medium", type: "span", weight: "bold", children: label }), jsxs("div", { className: "flex items-center gap-2", children: [headerAddon !== null && headerAddon !== undefined && variant !== "secondary" ? headerAddon : null, jsx(Icon, { ariaLabelledBy: LABEL_ID, className: cvaChevronIcon({ expanded }), name: "ChevronUp", size: variant === "secondary" ? "small" : "medium" })] })] }) }), jsx(Collapsible, { expanded: expanded, extraPadding: extraPadding, id: id, variant: variant, children: expanded || animate ? children : null })] }));
1937
2006
  };
1938
2007
  const Collapsible = ({ children, expanded, id, variant, extraPadding }) => {
1939
2008
  const { geometry, ref } = useMeasure();
@@ -2065,7 +2134,7 @@ const cvaCopyableText = cvaMerge([
2065
2134
  * @param {CopyableTextProps} props - The props for the CopyableText component
2066
2135
  * @returns {ReactElement} CopyableText component
2067
2136
  */
2068
- const CopyableText = ({ text, alternativeText, "data-testid": dataTestId, className, }) => {
2137
+ const CopyableText = ({ text, alternativeText, "data-testid": dataTestId, className, ref, }) => {
2069
2138
  const value = alternativeText ?? text ?? "";
2070
2139
  const [animating, setAnimating] = useState(false);
2071
2140
  const [, copyToClipboard] = useCopyToClipboard();
@@ -2073,7 +2142,7 @@ const CopyableText = ({ text, alternativeText, "data-testid": dataTestId, classN
2073
2142
  void copyToClipboard(value);
2074
2143
  setAnimating(true);
2075
2144
  };
2076
- return (jsx("span", { className: cvaCopyableText({ animating, className }), "data-testid": dataTestId, onAnimationEnd: () => setAnimating(false), onClick: handleOnClick, title: value, children: text }));
2145
+ return (jsx("span", { className: cvaCopyableText({ animating, className }), "data-testid": dataTestId, onAnimationEnd: () => setAnimating(false), onClick: handleOnClick, ref: ref, title: value, children: text }));
2077
2146
  };
2078
2147
 
2079
2148
  const cvaDetailsList = cvaMerge(["flex", "w-full", "min-w-0", "items-center", "truncate", "text-xs", "text-neutral-600", "font-medium", "pt-0"], {
@@ -2095,10 +2164,11 @@ const cvaDetailsListItem = cvaMerge(["last:truncate"]);
2095
2164
  * @param {string[]} props.details - Values to render.
2096
2165
  * @param {string} [props.className] - Optional CSS class for customization.
2097
2166
  * @param {boolean} [props.hasLink=false] - Whether the parent component contains a link.
2167
+ * @param [props.ref] - Ref forwarded to the root element.
2098
2168
  * @returns {ReactElement} The details list element.
2099
2169
  */
2100
- const DetailsList = ({ details, className, hasLink = false }) => {
2101
- return (jsx("div", { className: cvaDetailsList({ className, hasLink }), children: details.map((value, index, array) => (jsxs(Fragment, { children: [jsx("span", { className: cvaDetailsListItem({ className }), children: value }), index < array.length - 1 && (jsx("div", { className: "mx-0.5 flex items-center", children: jsx(Icon, { className: "w-4 text-neutral-300", color: "neutral", name: "Slash", size: "small" }) }))] }, index))) }));
2170
+ const DetailsList = ({ details, className, hasLink = false, ref }) => {
2171
+ return (jsx("div", { className: cvaDetailsList({ className, hasLink }), ref: ref, children: details.map((value, index, array) => (jsxs(Fragment, { children: [jsx("span", { className: cvaDetailsListItem({ className }), children: value }), index < array.length - 1 && (jsx("div", { className: "mx-0.5 flex items-center", children: jsx(Icon, { className: "w-4 text-neutral-300", color: "neutral", name: "Slash", size: "small" }) }))] }, index))) }));
2102
2172
  };
2103
2173
 
2104
2174
  const VALID_SIZE_KEYS = [
@@ -2240,10 +2310,10 @@ const cvaSkeleton = cvaMerge([
2240
2310
  * For shape-based elements (images, badges, buttons), use SkeletonBlock component instead.
2241
2311
  */
2242
2312
  const SkeletonLabel = memo((props) => {
2243
- const { width = "100%", textSize = "text-base", flexibleWidth = true, className, "data-testid": dataTestId, children, } = props;
2313
+ const { width = "100%", textSize = "text-base", flexibleWidth = true, className, "data-testid": dataTestId, children, ref, } = props;
2244
2314
  const widthValue = typeof width === "number" ? `${width}px` : width;
2245
2315
  const heightValue = getHeightValue(textSize);
2246
- return (jsx("div", { "aria-label": "Loading", className: cvaSkeleton({ textSize, className }), "data-testid": dataTestId, role: "status", style: {
2316
+ return (jsx("div", { "aria-label": "Loading", className: cvaSkeleton({ textSize, className }), "data-testid": dataTestId, ref: ref, role: "status", style: {
2247
2317
  width: flexibleWidth ? "100%" : widthValue,
2248
2318
  maxWidth: flexibleWidth ? widthValue : undefined,
2249
2319
  height: heightValue,
@@ -2433,8 +2503,8 @@ const cvaExternalLink = cvaMerge(["underline", "decoration-[1.5px]", "underline-
2433
2503
  * @param {ExternalLinkProps} props - The props for the external link component
2434
2504
  * @returns {ReactElement} External Link component
2435
2505
  */
2436
- const ExternalLink = ({ rel = "noreferrer", target = "_blank", href, className, children = href, title = href, "data-testid": dataTestId, onClick, color = "primary", }) => {
2437
- return (jsx("a", { className: cvaExternalLink({ className, color }), "data-testid": dataTestId, href: href, onClick: onClick, rel: rel, target: target, title: title, children: children }));
2506
+ const ExternalLink = ({ rel = "noreferrer", target = "_blank", href, className, children = href, title = href, "data-testid": dataTestId, onClick, color = "primary", ref, }) => {
2507
+ return (jsx("a", { className: cvaExternalLink({ className, color }), "data-testid": dataTestId, href: href, onClick: onClick, ref: ref, rel: rel, target: target, title: title, children: children }));
2438
2508
  };
2439
2509
 
2440
2510
  // =============================================================================
@@ -3238,70 +3308,6 @@ const Highlight = ({ className, "data-testid": dataTestId, children, size = "sma
3238
3308
  };
3239
3309
  Highlight.displayName = "Highlight";
3240
3310
 
3241
- // This hook is _heavily_ inspired by floating-ui's useMergeRefs
3242
- /**
3243
- * Merges an array of refs into a single memoized callback ref or `null`.
3244
- * Useful when you need to attach multiple refs to the same element,
3245
- * such as when composing multiple hooks that each need a ref.
3246
- *
3247
- * @template TInstance - The type of the element instance
3248
- * @param {ReadonlyArray<MergeableRef<TInstance> | undefined>} refs - Array of refs to merge (can be RefObjects, RefCallbacks, or undefined)
3249
- * @returns {null | RefCallback<TInstance>} A single ref callback that will update all provided refs, or null if all refs are null
3250
- * @example
3251
- * ```tsx
3252
- * const { ref: measureRef } = useMeasure();
3253
- * const { ref: scrollRef } = useScrollDetection();
3254
- * const mergedRef = useMergeRefs([measureRef, scrollRef]);
3255
- *
3256
- * return <div ref={mergedRef}>Content</div>;
3257
- * ```
3258
- */
3259
- function useMergeRefs(refs) {
3260
- const cleanupRef = useRef(undefined);
3261
- const refsRef = useRef(refs);
3262
- useEffect(() => {
3263
- refsRef.current = refs;
3264
- }, [refs]);
3265
- const refEffect = useCallback((instance) => {
3266
- const cleanups = refsRef.current.map(ref => {
3267
- if (ref === null || ref === undefined) {
3268
- return;
3269
- }
3270
- if (typeof ref === "function") {
3271
- const refCallback = ref;
3272
- const refCleanup = refCallback(instance);
3273
- return typeof refCleanup === "function"
3274
- ? refCleanup
3275
- : () => {
3276
- refCallback(null);
3277
- };
3278
- }
3279
- ref.current = instance;
3280
- return () => {
3281
- ref.current = null;
3282
- };
3283
- });
3284
- return () => {
3285
- cleanups.forEach(refCleanup => refCleanup?.());
3286
- };
3287
- }, []);
3288
- return useMemo(() => {
3289
- // eslint-disable-next-line react-hooks/refs
3290
- if (refsRef.current.every(ref => ref === null)) {
3291
- return null;
3292
- }
3293
- return (value) => {
3294
- if (cleanupRef.current) {
3295
- cleanupRef.current();
3296
- cleanupRef.current = undefined;
3297
- }
3298
- if (value !== null) {
3299
- cleanupRef.current = refEffect(value);
3300
- }
3301
- };
3302
- }, [refEffect]);
3303
- }
3304
-
3305
3311
  /**
3306
3312
  * The useDebounce hook works like useState, but adds a delay where previous values will be ignored.
3307
3313
  *
@@ -3563,8 +3569,8 @@ const cvaZStackItem = cvaMerge(["col-start-1", "col-end-1", "row-start-1", "row-
3563
3569
  * @param { ZStackProps} props - The props for the ZStack component
3564
3570
  * @returns {Element} ZStack component
3565
3571
  */
3566
- const ZStack = ({ children, className, "data-testid": dataTestId }) => {
3567
- return (jsx("div", { className: cvaZStackContainer({ className }), "data-testid": dataTestId, children: Children.map(children, (child, index) => {
3572
+ const ZStack = ({ children, className, "data-testid": dataTestId, ref }) => {
3573
+ return (jsx("div", { className: cvaZStackContainer({ className }), "data-testid": dataTestId, ref: ref, children: Children.map(children, (child, index) => {
3568
3574
  if (!isValidElement(child)) {
3569
3575
  return child;
3570
3576
  }
@@ -3635,9 +3641,10 @@ const OverflowIndicator = ({ className, "data-testid": dataTestId, direction, on
3635
3641
  * @param props.className - Optional CSS class name for styling
3636
3642
  * @param props."data-testid" - Optional test ID for testing purposes
3637
3643
  * @param props.onScrollStateChange - Optional callback fired when scroll state changes
3644
+ * @param [props.ref] - Ref forwarded to the root element
3638
3645
  * @returns {ReactElement} A horizontal overflow scroller component with visual indicators
3639
3646
  */
3640
- const HorizontalOverflowScroller = ({ className, "data-testid": dataTestId, children, onScrollStateChange, }) => {
3647
+ const HorizontalOverflowScroller = ({ className, "data-testid": dataTestId, children, onScrollStateChange, ref, }) => {
3641
3648
  const childrenArray = Children.toArray(children);
3642
3649
  const { geometry: containerGeometry, ref: measureRef, element } = useMeasure();
3643
3650
  const { ref: scrollRef, isScrollable, isAtBeginning, isAtEnd, } = useScrollDetection({
@@ -3650,7 +3657,7 @@ const HorizontalOverflowScroller = ({ className, "data-testid": dataTestId, chil
3650
3657
  })
3651
3658
  : undefined,
3652
3659
  });
3653
- const mergedRef = useMergeRefs([measureRef, scrollRef]);
3660
+ const mergedRef = useMergeRefs([measureRef, scrollRef, ref]);
3654
3661
  const handleScrollLeft = () => {
3655
3662
  if (!element || containerGeometry?.width === undefined)
3656
3663
  return;
@@ -4316,8 +4323,8 @@ const cvaIndicatorIconBackground = cvaMerge(["rounded-full", "items-center", "ju
4316
4323
  * @param {IndicatorProps} props - The props for the Indicator component
4317
4324
  * @returns {ReactElement} Indicator component
4318
4325
  */
4319
- const Indicator = ({ "data-testid": dataTestId, icon, label, color = "unknown", withBackground = true, withLabel = true, ping = false, size = "medium", weight = "normal", className, ...rest }) => {
4320
- return (jsx(Tooltip, { asChild: false, className: className, disabled: withLabel, label: label, placement: "bottom", children: jsxs("div", { "aria-label": label, className: cvaIndicator(), "data-testid": dataTestId, ...rest, children: [jsxs("div", { className: cvaIndicatorIconBackground({ color, background: withBackground ? "visible" : "hidden" }), "data-testid": dataTestId ? `${dataTestId}-background` : "indicator-background", children: [ping ? (jsx("div", { className: cvaIndicatorPing({ color }), "data-testid": dataTestId ? `${dataTestId}-ping` : "indicator-ping" })) : null, icon] }), label && withLabel ? (jsx("div", { className: cvaIndicatorLabel({ size, weight, background: withBackground ? "visible" : "hidden" }), "data-testid": dataTestId ? `${dataTestId}-label` : undefined, children: label })) : null] }) }));
4326
+ const Indicator = ({ "data-testid": dataTestId, icon, label, color = "unknown", withBackground = true, withLabel = true, ping = false, size = "medium", weight = "normal", className, ref, ...rest }) => {
4327
+ return (jsx(Tooltip, { asChild: false, className: className, disabled: withLabel, label: label, placement: "bottom", children: jsxs("div", { "aria-label": label, className: cvaIndicator(), "data-testid": dataTestId, ref: ref, ...rest, children: [jsxs("div", { className: cvaIndicatorIconBackground({ color, background: withBackground ? "visible" : "hidden" }), "data-testid": dataTestId ? `${dataTestId}-background` : "indicator-background", children: [ping ? (jsx("div", { className: cvaIndicatorPing({ color }), "data-testid": dataTestId ? `${dataTestId}-ping` : "indicator-ping" })) : null, icon] }), label && withLabel ? (jsx("div", { className: cvaIndicatorLabel({ size, weight, background: withBackground ? "visible" : "hidden" }), "data-testid": dataTestId ? `${dataTestId}-label` : undefined, children: label })) : null] }) }));
4321
4328
  };
4322
4329
 
4323
4330
  /**
@@ -4449,20 +4456,20 @@ const cvaKPITrendPercentage = cvaMerge([""], {
4449
4456
  * @param {KPIProps} props - The props for the KPI component
4450
4457
  * @returns {ReactElement} KPI component
4451
4458
  */
4452
- const KPI = ({ title, value, unit, className, "data-testid": dataTestId, tooltipLabel, variant = "default", style, ...rest }) => {
4459
+ const KPI = ({ title, value, unit, className, "data-testid": dataTestId, tooltipLabel, variant = "default", style, ref, ...rest }) => {
4453
4460
  const isSmallVariant = variant === "small";
4454
- return (jsx(Tooltip, { asChild: false, className: "min-w-8 shrink-0", "data-testid": dataTestId ? `${dataTestId}-tooltip` : undefined, disabled: tooltipLabel === undefined || tooltipLabel === "", label: tooltipLabel, placement: "bottom", children: jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsx(Text, { className: twMerge("truncate", "whitespace-nowrap"), "data-testid": dataTestId ? `${dataTestId}-title` : undefined, size: isSmallVariant ? "small" : "medium", subtle: true, weight: isSmallVariant ? "normal" : "bold", children: title }), jsx("div", { className: twMerge("truncate", "whitespace-nowrap"), children: jsxs(Text, { className: "truncate whitespace-nowrap text-lg font-medium", "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: isSmallVariant ? "small" : "large", type: "div", weight: isSmallVariant ? "bold" : "thick", children: [value, " ", unit] }) })] }) }));
4461
+ return (jsx(Tooltip, { asChild: false, className: "min-w-8 shrink-0", "data-testid": dataTestId ? `${dataTestId}-tooltip` : undefined, disabled: tooltipLabel === undefined || tooltipLabel === "", label: tooltipLabel, placement: "bottom", children: jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, ref: ref, style: style, ...rest, children: [jsx(Text, { className: twMerge("truncate", "whitespace-nowrap"), "data-testid": dataTestId ? `${dataTestId}-title` : undefined, size: isSmallVariant ? "small" : "medium", subtle: true, weight: isSmallVariant ? "normal" : "bold", children: title }), jsx("div", { className: twMerge("truncate", "whitespace-nowrap"), children: jsxs(Text, { className: "truncate whitespace-nowrap text-lg font-medium", "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: isSmallVariant ? "small" : "large", type: "div", weight: isSmallVariant ? "bold" : "thick", children: [value, " ", unit] }) })] }) }));
4455
4462
  };
4456
4463
 
4457
4464
  /**
4458
4465
  * Skeleton loading indicator that mimics the KPI component structure.
4459
4466
  * Uses the same layout, spacing, and visual hierarchy as KPI.
4460
4467
  */
4461
- const KPISkeleton = ({ variant = "default", className, "data-testid": dataTestId, style, ...rest }) => {
4468
+ const KPISkeleton = ({ variant = "default", className, "data-testid": dataTestId, style, ref, ...rest }) => {
4462
4469
  const isSmallVariant = variant === "small";
4463
4470
  // Generate stable random widths once and never change them
4464
4471
  const [titleWidth, valueWidth] = useRandomCSSLengths({ count: 2, min: 60, max: 100 });
4465
- return (jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsx("div", { className: twMerge("flex", "items-center", "flex-row", isSmallVariant ? "h-4" : "h-5"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-title-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-sm", width: titleWidth }) }), jsx("div", { className: twMerge("truncate", "whitespace-nowrap", "flex h-7 flex-row items-center"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-lg", width: valueWidth }) })] }));
4472
+ return (jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, ref: ref, style: style, ...rest, children: [jsx("div", { className: twMerge("flex", "items-center", "flex-row", isSmallVariant ? "h-4" : "h-5"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-title-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-sm", width: titleWidth }) }), jsx("div", { className: twMerge("truncate", "whitespace-nowrap", "flex h-7 flex-row items-center"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-lg", width: valueWidth }) })] }));
4466
4473
  };
4467
4474
 
4468
4475
  /**
@@ -4471,8 +4478,8 @@ const KPISkeleton = ({ variant = "default", className, "data-testid": dataTestId
4471
4478
  * @param {TrendIndicatorProps} props - The props for the TrendIndicator component
4472
4479
  * @returns {ReactElement} TrendIndicator component
4473
4480
  */
4474
- const TrendIndicator = ({ value, trend, label, icon = undefined, color = undefined, "data-testid": dataTestId, className, }) => {
4475
- return (jsxs("div", { className: twMerge("flex flex-row items-center gap-1", className), "data-testid": dataTestId, children: [value !== undefined ? (jsx(Text, { "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: "small", weight: "normal", children: value })) : null, jsxs("div", { className: "flex items-center", children: [icon ? (jsx(Icon, { color: color, "data-testid": dataTestId ? `${dataTestId}-icon` : undefined, name: icon, size: "small" })) : null, jsx(Text, { className: cvaKPITrendPercentage({ color }), "data-testid": dataTestId ? `${dataTestId}-trend` : undefined, size: "small", weight: "bold", children: trend })] }), jsx(Text, { "data-testid": dataTestId ? `${dataTestId}-label` : undefined, size: "small", weight: "normal", children: label })] }));
4481
+ const TrendIndicator = ({ value, trend, label, icon = undefined, color = undefined, "data-testid": dataTestId, className, ref, }) => {
4482
+ return (jsxs("div", { className: twMerge("flex flex-row items-center gap-1", className), "data-testid": dataTestId, ref: ref, children: [value !== undefined ? (jsx(Text, { "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: "small", weight: "normal", children: value })) : null, jsxs("div", { className: "flex items-center", children: [icon ? (jsx(Icon, { color: color, "data-testid": dataTestId ? `${dataTestId}-icon` : undefined, name: icon, size: "small" })) : null, jsx(Text, { className: cvaKPITrendPercentage({ color }), "data-testid": dataTestId ? `${dataTestId}-trend` : undefined, size: "small", weight: "bold", children: trend })] }), jsx(Text, { "data-testid": dataTestId ? `${dataTestId}-label` : undefined, size: "small", weight: "normal", children: label })] }));
4476
4483
  };
4477
4484
 
4478
4485
  /**
@@ -4481,8 +4488,8 @@ const TrendIndicator = ({ value, trend, label, icon = undefined, color = undefin
4481
4488
  * @param {TrendIndicatorsProps} props - The props for the TrendIndicators component
4482
4489
  * @returns {ReactElement} TrendIndicators component
4483
4490
  */
4484
- const TrendIndicators = ({ trends, "data-testid": dataTestId, className, }) => {
4485
- return (jsx("span", { className: twMerge("flex flex-row items-center gap-1", className), "data-testid": dataTestId, children: trends.map((trend, index) => (jsx(TrendIndicator, { "data-testid": dataTestId ? `${dataTestId}-trend-indicator-${index}` : undefined, ...trend }, index))) }));
4491
+ const TrendIndicators = ({ trends, "data-testid": dataTestId, className, ref, }) => {
4492
+ return (jsx("span", { className: twMerge("flex flex-row items-center gap-1", className), "data-testid": dataTestId, ref: ref, children: trends.map((trend, index) => (jsx(TrendIndicator, { "data-testid": dataTestId ? `${dataTestId}-trend-indicator-${index}` : undefined, ...trend }, index))) }));
4486
4493
  };
4487
4494
 
4488
4495
  const cvaValueBar = cvaMerge([
@@ -4591,11 +4598,11 @@ const getValueBarColorByValue = (value, min, max, levelColors) => {
4591
4598
  * @param {ValueBarProps} props - The props for the ValueBar component
4592
4599
  * @returns {ReactElement} ValueBar component
4593
4600
  */
4594
- const ValueBar = ({ value, min = 0, max = 100, unit, size = "small", levelColors, valueColor, showValue = false, className, "data-testid": dataTestId, zeroScoreAllowed = false, }) => {
4601
+ const ValueBar = ({ value, min = 0, max = 100, unit, size = "small", levelColors, valueColor, showValue = false, className, "data-testid": dataTestId, zeroScoreAllowed = false, ref, }) => {
4595
4602
  const score = getScore(value, min, max, zeroScoreAllowed);
4596
4603
  const barFillColor = levelColors ? getFillColor(score, levelColors) : getDefaultFillColor(score);
4597
4604
  const valueText = `${Number(value.toFixed(1))}${nonNullable(unit) ? unit : ""}`;
4598
- return (jsxs("span", { className: "relative flex items-center gap-2", "data-testid": dataTestId, children: [jsx("progress", { "aria-label": valueText, className: cvaValueBar({ className, size }), max: 100, style: { color: barFillColor }, value: score * 100 }), showValue && (size === "small" || size === "large") ? (jsx(Text, { className: cvaValueBarText({ size }), "data-testid": dataTestId ? `${dataTestId}-value` : undefined, children: jsx("span", { style: valueColor ? { color: valueColor } : undefined, children: valueText }) })) : null] }));
4605
+ return (jsxs("span", { className: "relative flex items-center gap-2", "data-testid": dataTestId, ref: ref, children: [jsx("progress", { "aria-label": valueText, className: cvaValueBar({ className, size }), max: 100, style: { color: barFillColor }, value: score * 100 }), showValue && (size === "small" || size === "large") ? (jsx(Text, { className: cvaValueBarText({ size }), "data-testid": dataTestId ? `${dataTestId}-value` : undefined, children: jsx("span", { style: valueColor ? { color: valueColor } : undefined, children: valueText }) })) : null] }));
4599
4606
  };
4600
4607
 
4601
4608
  const cvaKPICard = cvaMerge([
@@ -4684,13 +4691,13 @@ const cvaKPIIconContainer = cvaMerge(["flex", "items-center", "justify-center",
4684
4691
  * @param {KPICardProps} props - The props for the KPICard component
4685
4692
  * @returns {ReactElement} KPICard component
4686
4693
  */
4687
- const KPICard = ({ isActive = false, onClick, className, "data-testid": dataTestId, children, iconName = undefined, iconColor = "info", notice, valueBar, trends, unit, ...rest }) => {
4694
+ const KPICard = ({ isActive = false, onClick, className, "data-testid": dataTestId, children, iconName = undefined, iconColor = "info", notice, valueBar, trends, unit, ref, ...rest }) => {
4688
4695
  const isClickable = Boolean(onClick !== undefined);
4689
4696
  return (jsx(Card, { className: cvaKPICard({
4690
4697
  isClickable,
4691
4698
  isActive,
4692
4699
  className,
4693
- }), "data-testid": dataTestId ? dataTestId : undefined, onClick: onClick, children: jsxs(CardBody, { className: cvaKPICardBody(), gap: "none", padding: "none", children: [jsxs("div", { className: cvaKPICardHeader(), children: [jsx(KPI, { ...rest, className: "p-0", "data-testid": dataTestId ? `${dataTestId}-kpi` : undefined, unit: unit }), iconName ? (jsx("div", { className: cvaKPIIconContainer({ iconColor }), children: jsx(Icon, { name: iconName, size: "small", type: "solid" }) })) : null] }), trends !== undefined && trends.length > 0 ? (jsx(TrendIndicators, { "data-testid": dataTestId ? `${dataTestId}-trend-indicators` : undefined, trends: trends })) : null, valueBar !== undefined ? (jsx(ValueBar, { className: "h-2", "data-testid": dataTestId ? `${dataTestId}-value-bar` : undefined, ...valueBar })) : null, notice !== undefined ? (
4700
+ }), "data-testid": dataTestId ? dataTestId : undefined, onClick: onClick, ref: ref, children: jsxs(CardBody, { className: cvaKPICardBody(), gap: "none", padding: "none", children: [jsxs("div", { className: cvaKPICardHeader(), children: [jsx(KPI, { ...rest, className: "p-0", "data-testid": dataTestId ? `${dataTestId}-kpi` : undefined, unit: unit }), iconName ? (jsx("div", { className: cvaKPIIconContainer({ iconColor }), children: jsx(Icon, { name: iconName, size: "small", type: "solid" }) })) : null] }), trends !== undefined && trends.length > 0 ? (jsx(TrendIndicators, { "data-testid": dataTestId ? `${dataTestId}-trend-indicators` : undefined, trends: trends })) : null, valueBar !== undefined ? (jsx(ValueBar, { className: "h-2", "data-testid": dataTestId ? `${dataTestId}-value-bar` : undefined, ...valueBar })) : null, notice !== undefined ? (
4694
4701
  // NOTE: Can't use Notice component here due to the non-flexible text styling options
4695
4702
  jsxs("div", { className: "flex items-center gap-1 truncate", "data-testid": dataTestId ? `${dataTestId}-notice` : undefined, children: [notice.iconName ? (jsx(Icon, { color: notice.iconColor, "data-testid": dataTestId ? `${dataTestId}-notice-icon` : undefined, name: notice.iconName, size: "small" })) : null, jsx(Text, { className: "truncate text-neutral-900", "data-testid": dataTestId ? `${dataTestId}-notice-label` : undefined, size: "small", children: notice.label })] })) : null, children] }) }));
4696
4703
  };
@@ -4705,10 +4712,10 @@ const KPICard = ({ isActive = false, onClick, className, "data-testid": dataTest
4705
4712
  * For multiple text lines, use SkeletonLines component instead.
4706
4713
  */
4707
4714
  const SkeletonBlock = memo((props) => {
4708
- const { width = "100%", height = 16, flexibleWidth = false, className, "data-testid": dataTestId, children } = props;
4715
+ const { width = "100%", height = 16, flexibleWidth = false, className, "data-testid": dataTestId, children, ref, } = props;
4709
4716
  const widthValue = typeof width === "number" ? `${width}px` : width;
4710
4717
  const heightValue = typeof height === "number" ? `${height}px` : height;
4711
- return (jsx("div", { "aria-label": "Loading", className: cvaSkeleton({ className }), "data-testid": dataTestId, role: "status", style: {
4718
+ return (jsx("div", { "aria-label": "Loading", className: cvaSkeleton({ className }), "data-testid": dataTestId, ref: ref, role: "status", style: {
4712
4719
  width: flexibleWidth ? "100%" : widthValue,
4713
4720
  maxWidth: flexibleWidth ? widthValue : undefined,
4714
4721
  height: heightValue,
@@ -4720,8 +4727,8 @@ SkeletonBlock.displayName = "SkeletonBlock";
4720
4727
  * Skeleton loading indicator that mimics the KPICard component structure.
4721
4728
  * Uses the same layout, spacing, and visual hierarchy as KPICard.
4722
4729
  */
4723
- const KPICardSkeleton = ({ hasIcon = false, hasTrends = false, hasValueBar = false, hasNotice = false, children, className, "data-testid": dataTestId, style, ...rest }) => {
4724
- return (jsx(Card, { className: cvaKPICard({ className }), "data-testid": dataTestId, style: style, ...rest, children: jsxs(CardBody, { className: cvaKPICardBody(), gap: "none", padding: "none", children: [jsxs("div", { className: cvaKPICardHeader(), children: [jsx(KPISkeleton, { className: "p-0", "data-testid": dataTestId ? `${dataTestId}-kpi` : undefined }), hasIcon ? (jsx(SkeletonBlock, { "data-testid": dataTestId ? `${dataTestId}-icon-loading` : undefined, height: 28, width: 28 })) : null] }), hasTrends ? (jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-trend-indicator-loading` : undefined, textSize: "text-xs", width: "100%" })) : null, hasValueBar ? (jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-bar-loading` : undefined, textSize: "text-xs", width: "100%" })) : null, hasNotice ? (jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-notice-loading` : undefined, textSize: "text-xs", width: "100%" })) : null, children] }) }));
4730
+ const KPICardSkeleton = ({ hasIcon = false, hasTrends = false, hasValueBar = false, hasNotice = false, children, className, "data-testid": dataTestId, style, ref, ...rest }) => {
4731
+ return (jsx(Card, { className: cvaKPICard({ className }), "data-testid": dataTestId, ref: ref, style: style, ...rest, children: jsxs(CardBody, { className: cvaKPICardBody(), gap: "none", padding: "none", children: [jsxs("div", { className: cvaKPICardHeader(), children: [jsx(KPISkeleton, { className: "p-0", "data-testid": dataTestId ? `${dataTestId}-kpi` : undefined }), hasIcon ? (jsx(SkeletonBlock, { "data-testid": dataTestId ? `${dataTestId}-icon-loading` : undefined, height: 28, width: 28 })) : null] }), hasTrends ? (jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-trend-indicator-loading` : undefined, textSize: "text-xs", width: "100%" })) : null, hasValueBar ? (jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-bar-loading` : undefined, textSize: "text-xs", width: "100%" })) : null, hasNotice ? (jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-notice-loading` : undefined, textSize: "text-xs", width: "100%" })) : null, children] }) }));
4725
4732
  };
4726
4733
 
4727
4734
  const cvaListContainer = cvaMerge(["overflow-y-auto", "overflow-x-hidden", "h-full"], {
@@ -5523,7 +5530,7 @@ const cvaMenuItemSuffix = cvaMerge(["text-neutral-400", "text-sm", "flex", "item
5523
5530
  * @param {MenuItemProps} props - The props for the MenuItem component
5524
5531
  * @returns {ReactElement} MenuItem component
5525
5532
  */
5526
- const MenuItem = ({ className, "data-testid": dataTestId, label, children, selected = false, focused = false, prefix, suffix, disabled = false, onClick, stopPropagation = true, id, tabIndex, optionLabelDescription, optionPrefix, fieldSize = "medium", variant = "primary", }) => {
5533
+ const MenuItem = ({ className, "data-testid": dataTestId, label, children, selected = false, focused = false, prefix, suffix, disabled = false, onClick, stopPropagation = true, id, tabIndex, optionLabelDescription, optionPrefix, fieldSize = "medium", variant = "primary", ref, }) => {
5527
5534
  /* Handle tab navigation */
5528
5535
  const handleKeyDown = (e) => {
5529
5536
  if (e.key === "Enter" && onClick !== undefined && disabled !== true) {
@@ -5546,7 +5553,7 @@ const MenuItem = ({ className, "data-testid": dataTestId, label, children, selec
5546
5553
  e.stopPropagation();
5547
5554
  }
5548
5555
  onClick?.(e);
5549
- }, onKeyDown: handleKeyDown, role: "menuitem", tabIndex: disabled ? -1 : (tabIndex ?? 0), children: [prefix !== null && prefix !== undefined ? (jsx("div", { className: cvaMenuItemPrefix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-prefix` : "menu-item-prefix", children: prefix })) : null, children !== null && children !== undefined && typeof children !== "string" ? (children) : (jsxs("div", { className: cvaMenuItemLabel({ variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-label` : "menu-item-label", children: [optionPrefix !== null && optionPrefix !== undefined ? optionPrefix : null, children ?? label, optionLabelDescription !== undefined && optionLabelDescription !== "" ? (jsxs("span", { className: "ml-1 text-neutral-400", children: ["(", optionLabelDescription, ")"] })) : null] })), suffix !== null && suffix !== undefined ? (jsx("div", { className: cvaMenuItemSuffix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-suffix` : "menu-item-suffix", children: suffix })) : null] }));
5556
+ }, onKeyDown: handleKeyDown, ref: ref, role: "menuitem", tabIndex: disabled ? -1 : (tabIndex ?? 0), children: [prefix !== null && prefix !== undefined ? (jsx("div", { className: cvaMenuItemPrefix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-prefix` : "menu-item-prefix", children: prefix })) : null, children !== null && children !== undefined && typeof children !== "string" ? (children) : (jsxs("div", { className: cvaMenuItemLabel({ variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-label` : "menu-item-label", children: [optionPrefix !== null && optionPrefix !== undefined ? optionPrefix : null, children ?? label, optionLabelDescription !== undefined && optionLabelDescription !== "" ? (jsxs("span", { className: "ml-1 text-neutral-400", children: ["(", optionLabelDescription, ")"] })) : null] })), suffix !== null && suffix !== undefined ? (jsx("div", { className: cvaMenuItemSuffix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-suffix` : "menu-item-suffix", children: suffix })) : null] }));
5550
5557
  };
5551
5558
 
5552
5559
  /**
@@ -5605,7 +5612,7 @@ const MenuItem = ({ className, "data-testid": dataTestId, label, children, selec
5605
5612
  * @param {MenuListProps} props - The props for the MenuList component
5606
5613
  * @returns {ReactElement} MenuList component
5607
5614
  */
5608
- const MenuList = ({ "data-testid": dataTestId, className, children, isMulti = false, selectedItems: controlledSelectedItems, onSelectionChange, ...args }) => {
5615
+ const MenuList = ({ "data-testid": dataTestId, className, children, isMulti = false, selectedItems: controlledSelectedItems, onSelectionChange, ref, ...args }) => {
5609
5616
  const childrenArr = Children.toArray(children);
5610
5617
  const [internalSelectedItems, setInternalSelectedItems] = useState(controlledSelectedItems ?? []);
5611
5618
  const selectedItems = controlledSelectedItems ?? internalSelectedItems;
@@ -5622,7 +5629,7 @@ const MenuList = ({ "data-testid": dataTestId, className, children, isMulti = fa
5622
5629
  setInternalSelectedItems(newSelectedItems);
5623
5630
  }
5624
5631
  }, [isMulti, selectedItems, onSelectionChange]);
5625
- return (jsx("div", { className: cvaMenu({ className, limitWidth: true }), "data-testid": dataTestId ? `${dataTestId}-menu-list` : "menu-list", onClick: args.onClick, role: "list", tabIndex: 0, children: jsx("div", { className: cvaMenuList(), children: childrenArr.map((menuItem, index) => {
5632
+ return (jsx("div", { className: cvaMenu({ className, limitWidth: true }), "data-testid": dataTestId ? `${dataTestId}-menu-list` : "menu-list", onClick: args.onClick, ref: ref, role: "list", tabIndex: 0, children: jsx("div", { className: cvaMenuList(), children: childrenArr.map((menuItem, index) => {
5626
5633
  if (isValidElement(menuItem)) {
5627
5634
  const isSelected = (selectedItems.includes(menuItem.props.id ?? `${index}`) || menuItem.props.selected) ?? false;
5628
5635
  return cloneElement(menuItem, {
@@ -5662,9 +5669,10 @@ const MoreMenu = ({ className, "data-testid": dataTestId, popoverProps, iconProp
5662
5669
  size: "medium",
5663
5670
  square: true,
5664
5671
  variant: "secondary",
5665
- }, customButton, customPortalId, children, }) => {
5672
+ }, customButton, customPortalId, children, ref, }) => {
5666
5673
  const actionMenuRef = useRef(null);
5667
- return (jsx("div", { className: cvaMoreMenu({ className }), "data-testid": dataTestId ? dataTestId : undefined, ref: actionMenuRef, children: jsxs(Popover, { placement: "bottom-end", ...popoverProps, children: [jsx(PopoverTrigger, { children: customButton ?? (jsx(IconButton, { "data-testid": "more-menu-icon", ...iconButtonProps, icon: jsx(Icon, { name: "EllipsisHorizontal", ...iconProps }) })) }), jsx(PopoverContent, { portalId: customPortalId, children: close => (typeof children === "function" ? children(close) : children) })] }) }));
5674
+ const mergedRef = useMergeRefs([actionMenuRef, ref]);
5675
+ return (jsx("div", { className: cvaMoreMenu({ className }), "data-testid": dataTestId ? dataTestId : undefined, ref: mergedRef, children: jsxs(Popover, { placement: "bottom-end", ...popoverProps, children: [jsx(PopoverTrigger, { children: customButton ?? (jsx(IconButton, { "data-testid": "more-menu-icon", ...iconButtonProps, icon: jsx(Icon, { name: "EllipsisHorizontal", ...iconProps }) })) }), jsx(PopoverContent, { portalId: customPortalId, children: close => (typeof children === "function" ? children(close) : children) })] }) }));
5668
5676
  };
5669
5677
 
5670
5678
  const cvaNotice = cvaMerge(["flex", "items-center", "gap-1"]);
@@ -5712,8 +5720,8 @@ const cvaNoticeIcon = cvaMerge(["rounded-full", "items-center", "justify-center"
5712
5720
  * @param {NoticeProps} props - The props for the Notice component
5713
5721
  * @returns {ReactElement} Notice component
5714
5722
  */
5715
- const Notice = ({ "data-testid": dataTestId, iconName = undefined, iconSize = "medium", iconColor = undefined, label, color = "neutral", withLabel = true, className, tooltipLabel = label, withTooltip = false, size = "medium", ...rest }) => {
5716
- return (jsx(Tooltip, { asChild: false, className: className, disabled: withTooltip === false, label: tooltipLabel, placement: "bottom", children: jsxs("div", { "aria-label": label, className: cvaNotice(), "data-testid": dataTestId, ...rest, children: [nonNullable(iconName) ? (jsx("div", { className: cvaNoticeIcon({ color: iconColor || color }), "data-testid": dataTestId ? `${dataTestId}-icon` : "notice-icon", children: jsx(Icon, { name: iconName, size: iconSize }) })) : null, label && withLabel ? (jsx("div", { className: cvaNoticeLabel({ color, size }), "data-testid": dataTestId ? `${dataTestId}-label` : "notice-label", children: label })) : null] }) }));
5723
+ const Notice = ({ "data-testid": dataTestId, iconName = undefined, iconSize = "medium", iconColor = undefined, label, color = "neutral", withLabel = true, className, tooltipLabel = label, withTooltip = false, size = "medium", ref, ...rest }) => {
5724
+ return (jsx(Tooltip, { asChild: false, className: className, disabled: withTooltip === false, label: tooltipLabel, placement: "bottom", children: jsxs("div", { "aria-label": label, className: cvaNotice(), "data-testid": dataTestId, ref: ref, ...rest, children: [nonNullable(iconName) ? (jsx("div", { className: cvaNoticeIcon({ color: iconColor || color }), "data-testid": dataTestId ? `${dataTestId}-icon` : "notice-icon", children: jsx(Icon, { name: iconName, size: iconSize }) })) : null, label && withLabel ? (jsx("div", { className: cvaNoticeLabel({ color, size }), "data-testid": dataTestId ? `${dataTestId}-label` : "notice-label", children: label })) : null] }) }));
5717
5725
  };
5718
5726
 
5719
5727
  const cvaPage = cvaMerge(["grid", "h-full"], {
@@ -5745,8 +5753,8 @@ const cvaPageContent = cvaMerge(["overflow-auto", "page-content", "grid", "gap-r
5745
5753
  /**
5746
5754
  * Renders the page component. Adds padding and layout to the page.
5747
5755
  */
5748
- const Page = ({ layout, className, children, "data-testid": dataTestId }) => {
5749
- return (jsx("div", { className: cvaPage({ className, layout }), "data-testid": dataTestId ? dataTestId : "page", children: children }));
5756
+ const Page = ({ layout, className, children, "data-testid": dataTestId, ref }) => {
5757
+ return (jsx("div", { className: cvaPage({ className, layout }), "data-testid": dataTestId ? dataTestId : "page", ref: ref, children: children }));
5750
5758
  };
5751
5759
 
5752
5760
  /**
@@ -5756,8 +5764,8 @@ const Page = ({ layout, className, children, "data-testid": dataTestId }) => {
5756
5764
  * @param {PageContentProps} props - The component props.
5757
5765
  * @returns {ReactNode} - The rendered component.
5758
5766
  */
5759
- const PageContent = ({ className, children, "data-testid": dataTestId, layout, }) => {
5760
- return (jsx("div", { className: cvaPageContent({ className, layout }), "data-testid": dataTestId ? dataTestId : "page-content", children: children }));
5767
+ const PageContent = ({ className, children, "data-testid": dataTestId, layout, ref, }) => {
5768
+ return (jsx("div", { className: cvaPageContent({ className, layout }), "data-testid": dataTestId ? dataTestId : "page-content", ref: ref, children: children }));
5761
5769
  };
5762
5770
 
5763
5771
  /**
@@ -5865,7 +5873,7 @@ cvaMerge([
5865
5873
  * <SkeletonLines variant="preset" preset="title-paragraph" />
5866
5874
  */
5867
5875
  const SkeletonLines = memo((props) => {
5868
- const { className, "data-testid": dataTestId } = props;
5876
+ const { className, "data-testid": dataTestId, ref } = props;
5869
5877
  // Generate line configs based on variant
5870
5878
  let lineConfigs;
5871
5879
  if (props.variant === "preset") {
@@ -5886,7 +5894,7 @@ const SkeletonLines = memo((props) => {
5886
5894
  }));
5887
5895
  }
5888
5896
  const lineCount = lineConfigs.length;
5889
- return (jsx("div", { "aria-label": `Loading ${lineCount} ${lineCount === 1 ? "item" : "items"}`, className: cvaSkeletonContainer({ className }), "data-testid": dataTestId, "data-variant": props.variant, role: "status", ...(props.variant === "preset" && { "data-preset": props.preset }), children: lineConfigs.map((config, index) => (jsx(SkeletonLabel, { className: config.className, "data-testid": dataTestId ? `${dataTestId}-${index}` : undefined, flexibleWidth: config.flexibleWidth ?? true, textSize: config.textSize ?? "text-base", width: config.width ?? "100%" }, index))) }));
5897
+ return (jsx("div", { "aria-label": `Loading ${lineCount} ${lineCount === 1 ? "item" : "items"}`, className: cvaSkeletonContainer({ className }), "data-testid": dataTestId, "data-variant": props.variant, ref: ref, role: "status", ...(props.variant === "preset" && { "data-preset": props.preset }), children: lineConfigs.map((config, index) => (jsx(SkeletonLabel, { className: config.className, "data-testid": dataTestId ? `${dataTestId}-${index}` : undefined, flexibleWidth: config.flexibleWidth ?? true, textSize: config.textSize ?? "text-base", width: config.width ?? "100%" }, index))) }));
5890
5898
  });
5891
5899
  SkeletonLines.displayName = "SkeletonLines";
5892
5900
 
@@ -5899,16 +5907,17 @@ const LoadingContent = () => (jsx("div", { className: "flex flex-row items-cente
5899
5907
  *
5900
5908
  * @param {object} props - The props for the PageHeaderKpiMetrics component
5901
5909
  * @param {Array<PageHeaderKpiMetricsType>} props.kpiMetrics - The KPI metrics to render
5910
+ * @param [props.ref] - Ref forwarded to the root element
5902
5911
  * @returns {ReactElement} PageHeaderKpiMetrics component
5903
5912
  */
5904
- const PageHeaderKpiMetrics = ({ kpiMetrics }) => {
5905
- return (jsx("div", { className: "hidden items-center gap-4 md:flex", children: kpiMetrics
5913
+ const PageHeaderKpiMetrics = ({ kpiMetrics, ref, }) => {
5914
+ return (jsx("div", { className: "hidden items-center gap-4 md:flex", ref: ref, children: kpiMetrics
5906
5915
  .filter(kpi => kpi.hidden === false || kpi.hidden === undefined)
5907
5916
  .map((kpi, index) => {
5908
5917
  if (kpi.loading === true) {
5909
5918
  return jsx(LoadingContent, {}, `${kpi}-${index}`);
5910
5919
  }
5911
- return (jsxs("div", { className: "flex flex-col text-nowrap text-left", children: [jsx("span", { className: "text-xs text-neutral-500", children: kpi.header }), jsxs("div", { className: "flex flex-row items-center gap-1", children: [jsx("span", { className: "text-lg font-medium text-neutral-900", children: kpi.value }), kpi.unit ? jsx("span", { className: "text-xs text-neutral-900", children: kpi.unit }) : null] })] }, `${kpi}-${index}`));
5920
+ return (jsxs("div", { className: "text-nowrap flex flex-col text-left", children: [jsx("span", { className: "text-xs text-neutral-500", children: kpi.header }), jsxs("div", { className: "flex flex-row items-center gap-1", children: [jsx("span", { className: "text-lg font-medium text-neutral-900", children: kpi.value }), kpi.unit ? jsx("span", { className: "text-xs text-neutral-900", children: kpi.unit }) : null] })] }, `${kpi}-${index}`));
5912
5921
  }) }));
5913
5922
  };
5914
5923
 
@@ -6044,11 +6053,12 @@ const cvaPageHeaderHeading = cvaMerge(["text-neutral-900", "text-xl", "font-semi
6044
6053
  * @param {string} props.title - The title of the page header
6045
6054
  * @param {string} props.className - The class name of the page header title
6046
6055
  * @param {string} [props."data-testid"] - The data test id of the page header title
6056
+ * @param [props.ref] - Ref forwarded to the root element
6047
6057
  * @returns {ReactElement} PageHeaderTitle component
6048
6058
  */
6049
- const PageHeaderTitle = ({ title, "data-testid": dataTestId, className, }) => {
6059
+ const PageHeaderTitle = ({ title, "data-testid": dataTestId, className, ref: forwardedRef, }) => {
6050
6060
  const { ref, isTextTruncated } = useIsTextTruncated();
6051
- return (jsx("div", { className: "flex flex-row items-center", children: jsx(Tooltip, { asChild: false, className: "grid min-w-16", disabled: !isTextTruncated, label: title, placement: "top", children: jsx("h1", { className: cvaPageHeaderHeading({ className }), "data-testid": dataTestId ? `${dataTestId}-heading` : undefined, ref: ref, children: title }) }) }));
6061
+ return (jsx("div", { className: "flex flex-row items-center", ref: forwardedRef, children: jsx(Tooltip, { asChild: false, className: "min-w-16 grid", disabled: !isTextTruncated, label: title, placement: "top", children: jsx("h1", { className: cvaPageHeaderHeading({ className }), "data-testid": dataTestId ? `${dataTestId}-heading` : undefined, ref: ref, children: title }) }) }));
6052
6062
  };
6053
6063
 
6054
6064
  /**
@@ -6100,7 +6110,7 @@ const PageHeaderTitle = ({ title, "data-testid": dataTestId, className, }) => {
6100
6110
  * @param {PageHeaderProps} props - The props for the PageHeader component
6101
6111
  * @returns {ReactElement} PageHeader component
6102
6112
  */
6103
- const PageHeader = ({ className, "data-testid": dataTestId, showLoading = false, description, title, tagLabel, backTo, tagColor, tabsList, descriptionIcon = "QuestionMarkCircle", tagTooltipLabel, ...discriminatedProps }) => {
6113
+ const PageHeader = ({ className, "data-testid": dataTestId, showLoading = false, description, title, tagLabel, backTo, tagColor, tabsList, descriptionIcon = "QuestionMarkCircle", tagTooltipLabel, ref, ...discriminatedProps }) => {
6104
6114
  const tagRenderer = useMemo(() => {
6105
6115
  if (tagLabel === undefined || tagLabel === "" || showLoading) {
6106
6116
  return null;
@@ -6111,7 +6121,7 @@ const PageHeader = ({ className, "data-testid": dataTestId, showLoading = false,
6111
6121
  return (jsxs("div", { className: cvaPageHeaderContainer({
6112
6122
  className,
6113
6123
  withBorder: tabsList === undefined,
6114
- }), "data-testid": dataTestId, children: [jsxs("div", { className: cvaPageHeader(), children: [backTo ? (jsx(Link, { to: backTo, children: jsx(Button, { className: "mr-4 bg-black/5 hover:bg-black/10", prefix: jsx(Icon, { name: "ArrowLeft", size: "small" }), size: "small", square: true, variant: "ghost-neutral" }) })) : undefined, typeof title === "string" ? jsx(PageHeaderTitle, { "data-testid": dataTestId, title: title }) : title, tagRenderer || (description !== null && description !== undefined) ? (jsxs("div", { className: "mx-2 flex items-center gap-2", children: [description !== null && description !== undefined && !showLoading ? (jsx(Tooltip, { asChild: false, "data-testid": dataTestId ? `${dataTestId}-description-tooltip` : undefined, iconProps: {
6124
+ }), "data-testid": dataTestId, ref: ref, children: [jsxs("div", { className: cvaPageHeader(), children: [backTo ? (jsx(Link, { to: backTo, children: jsx(Button, { className: "mr-4 bg-black/5 hover:bg-black/10", prefix: jsx(Icon, { name: "ArrowLeft", size: "small" }), size: "small", square: true, variant: "ghost-neutral" }) })) : undefined, typeof title === "string" ? jsx(PageHeaderTitle, { "data-testid": dataTestId, title: title }) : title, tagRenderer || (description !== null && description !== undefined) ? (jsxs("div", { className: "mx-2 flex items-center gap-2", children: [description !== null && description !== undefined && !showLoading ? (jsx(Tooltip, { asChild: false, "data-testid": dataTestId ? `${dataTestId}-description-tooltip` : undefined, iconProps: {
6115
6125
  name: descriptionIcon,
6116
6126
  "data-testid": "page-header-description-icon",
6117
6127
  }, label: description, placement: "bottom" })) : undefined, tagRenderer] })) : null, jsxs("div", { className: "ml-auto flex gap-2", children: [discriminatedProps.accessoryType === "kpi-metrics" ? (jsx(PageHeaderKpiMetrics, { kpiMetrics: discriminatedProps.kpiMetrics })) : null, discriminatedProps.accessoryType === "actions" ? (Array.isArray(discriminatedProps.secondaryActions) ? (jsx(PageHeaderSecondaryActions, { actions: discriminatedProps.secondaryActions, groupActions: discriminatedProps.groupSecondaryActions ?? false, hasPrimaryAction: !!discriminatedProps.primaryAction })) : discriminatedProps.secondaryActions !== null && discriminatedProps.secondaryActions !== undefined ? (discriminatedProps.secondaryActions) : null) : null, discriminatedProps.accessoryType === "actions" &&
@@ -6130,7 +6140,7 @@ const cvaPaginationText = cvaMerge("whitespace-nowrap");
6130
6140
  * @param {PaginationProps} props - The props for the Pagination component
6131
6141
  * @returns {ReactElement} Pagination component
6132
6142
  */
6133
- const Pagination = ({ previousPage, nextPage, canPreviousPage = false, canNextPage = false, pageCount, pageIndex, loading = false, className, "data-testid": dataTestId, getTranslatedCount, onPageChange, cursorBase = false, }) => {
6143
+ const Pagination = ({ previousPage, nextPage, canPreviousPage = false, canNextPage = false, pageCount, pageIndex, loading = false, className, "data-testid": dataTestId, getTranslatedCount, onPageChange, cursorBase = false, ref, }) => {
6134
6144
  const [page, setPage] = useState(pageIndex);
6135
6145
  const [currentPage, setCurrentPage] = useState(String(pageIndex !== undefined ? pageIndex + 1 : 1));
6136
6146
  if (!loading && pageCount === undefined) {
@@ -6173,9 +6183,9 @@ const Pagination = ({ previousPage, nextPage, canPreviousPage = false, canNextPa
6173
6183
  onPageChange?.({ from, to, description });
6174
6184
  }, [page, onPageChange, previousPage, nextPage]);
6175
6185
  if (loading) {
6176
- return (jsx("div", { className: cvaPagination({ className }), children: jsx(SkeletonLabel, { textSize: "text-sm", width: 150 }) }));
6186
+ return (jsx("div", { className: cvaPagination({ className }), ref: ref, children: jsx(SkeletonLabel, { textSize: "text-sm", width: 150 }) }));
6177
6187
  }
6178
- return (jsxs("div", { className: cvaPagination({ className }), "data-testid": dataTestId, children: [jsx(IconButton, { "data-testid": "prev-page", disabled: cursorBase ? !canPreviousPage || false : page !== undefined && page <= 0, icon: jsx(Icon, { name: "ChevronLeft", size: "small" }), onClick: () => handlePageChange("prev"), size: "small", variant: "ghost-neutral" }), !cursorBase && (jsxs(Fragment$1, { children: [jsx("div", { className: cvaPaginationText(), "data-testid": "current-page", children: currentPage }), jsx("div", { className: cvaPaginationText(), "data-testid": "page-count", children: pageCount !== null && pageCount !== undefined && getTranslatedCount ? getTranslatedCount(pageCount) : null })] })), jsx(IconButton, { "data-testid": "next-page", disabled: cursorBase
6188
+ return (jsxs("div", { className: cvaPagination({ className }), "data-testid": dataTestId, ref: ref, children: [jsx(IconButton, { "data-testid": "prev-page", disabled: cursorBase ? !canPreviousPage || false : page !== undefined && page <= 0, icon: jsx(Icon, { name: "ChevronLeft", size: "small" }), onClick: () => handlePageChange("prev"), size: "small", variant: "ghost-neutral" }), !cursorBase && (jsxs(Fragment$1, { children: [jsx("div", { className: cvaPaginationText(), "data-testid": "current-page", children: currentPage }), jsx("div", { className: cvaPaginationText(), "data-testid": "page-count", children: pageCount !== null && pageCount !== undefined && getTranslatedCount ? getTranslatedCount(pageCount) : null })] })), jsx(IconButton, { "data-testid": "next-page", disabled: cursorBase
6179
6189
  ? !canNextPage || false
6180
6190
  : page !== undefined && pageCount !== undefined && pageCount !== null && page >= pageCount - 1, icon: jsx(Icon, { name: "ChevronRight", size: "small" }), onClick: () => handlePageChange("next"), size: "small", variant: "ghost-neutral" })] }));
6181
6191
  };
@@ -6187,7 +6197,7 @@ const STROKE_WIDTH_THRESHOLD = 32;
6187
6197
  * @param { PolygonProps} props - The props for the Polygon component
6188
6198
  * @returns {ReactElement} Polygon component
6189
6199
  */
6190
- const Polygon = ({ points, size, color = "black", opaque = true, className, "data-testid": dataTestId, }) => {
6200
+ const Polygon = ({ points, size, color = "black", opaque = true, className, "data-testid": dataTestId, ref, }) => {
6191
6201
  // Calculate the bounds of the points
6192
6202
  const minX = Math.min(...points.map(coord => coord[0]));
6193
6203
  const maxX = Math.max(...points.map(coord => coord[0]));
@@ -6204,7 +6214,7 @@ const Polygon = ({ points, size, color = "black", opaque = true, className, "dat
6204
6214
  size: sizeToNormalizeAgainst,
6205
6215
  })}`)
6206
6216
  .join(" ");
6207
- return (jsx("svg", { className: className, "data-testid": dataTestId, height: size, style: { width: `${size}px`, height: `${size}px` }, viewBox: `0 0 ${size} ${size}`, width: size, xmlns: "http://www.w3.org/2000/svg", children: jsx("polygon", { points: normalizedPoints, style: {
6217
+ return (jsx("svg", { className: className, "data-testid": dataTestId, height: size, ref: ref, style: { width: `${size}px`, height: `${size}px` }, viewBox: `0 0 ${size} ${size}`, width: size, xmlns: "http://www.w3.org/2000/svg", children: jsx("polygon", { points: normalizedPoints, style: {
6208
6218
  fill: color,
6209
6219
  fillOpacity: opaque ? 0.2 : undefined,
6210
6220
  stroke: color,
@@ -6220,8 +6230,8 @@ const normalize = ({ value, min, max, size }) => ((value - min) / (max - min)) *
6220
6230
  * @param {PopoverTitleProps} props - The props for the PopoverTitle component
6221
6231
  * @returns {ReactElement} PopoverTitle component
6222
6232
  */
6223
- const PopoverTitle = ({ children, action, divider = false, className, "data-testid": dataTestId, }) => {
6224
- return (jsxs("div", { className: cvaPopoverTitleContainer({ divider, className }), "data-testid": dataTestId, children: [jsx(Text, { className: cvaPopoverTitleText(), size: "small", subtle: true, type: "div", uppercase: true, weight: "bold", children: children }), action] }));
6233
+ const PopoverTitle = ({ children, action, divider = false, className, "data-testid": dataTestId, ref, }) => {
6234
+ return (jsxs("div", { className: cvaPopoverTitleContainer({ divider, className }), "data-testid": dataTestId, ref: ref, children: [jsx(Text, { className: cvaPopoverTitleText(), size: "small", subtle: true, type: "div", uppercase: true, weight: "bold", children: children }), action] }));
6225
6235
  };
6226
6236
 
6227
6237
  const cvaPreferenceCard = cvaMerge([
@@ -6363,8 +6373,9 @@ const preferenceCardGrid = createGrid()
6363
6373
  * with various states and visual treatments.
6364
6374
  * It is recommended to be primarily used as an input component, as it supports checkboxes, radio buttons and toggles.
6365
6375
  */
6366
- const PreferenceCard = ({ title, description, icon, input, titleTag, cardTag, disabled = false, className, "data-testid": dataTestId, children, }) => {
6367
- const { ref, geometry } = useMeasure();
6376
+ const PreferenceCard = ({ title, description, icon, input, titleTag, cardTag, disabled = false, className, "data-testid": dataTestId, children, ref: forwardedRef, }) => {
6377
+ const { ref: measureRef, geometry } = useMeasure();
6378
+ const ref = useMergeRefs([measureRef, forwardedRef]);
6368
6379
  const gridAreas = useGridAreas(preferenceCardGrid);
6369
6380
  return (jsxs("div", { className: cvaPreferenceCard({
6370
6381
  disabled,
@@ -6413,7 +6424,7 @@ const getRandomWidth = (min, max) => {
6413
6424
  * Skeleton loading indicator that mimics the PreferenceCard component structure.
6414
6425
  * Uses the same grid layout, spacing, and visual hierarchy as PreferenceCard.
6415
6426
  */
6416
- const PreferenceCardSkeleton = ({ hasIcon = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasIcon, hasTitleTag = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasTitleTag, hasCardTag = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasCardTag, hasInput = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasInput, }) => {
6427
+ const PreferenceCardSkeleton = ({ hasIcon = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasIcon, hasTitleTag = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasTitleTag, hasCardTag = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasCardTag, hasInput = DEFAULT_SKELETON_PREFERENCE_CARD_PROPS.hasInput, ref, }) => {
6417
6428
  const gridAreas = useGridAreas(preferenceCardGrid);
6418
6429
  // Generate stable random widths once and never change them
6419
6430
  const lineWidths = useMemo(() => {
@@ -6422,7 +6433,7 @@ const PreferenceCardSkeleton = ({ hasIcon = DEFAULT_SKELETON_PREFERENCE_CARD_PRO
6422
6433
  description: getRandomWidth(160, 240),
6423
6434
  };
6424
6435
  }, []);
6425
- return (jsxs("div", { className: cvaPreferenceCard(), children: [hasInput ? (jsx("div", { className: cvaInputContainer({ itemPlacement: "center" }), children: jsx(SkeletonBlock, { height: 20, width: 20 }) })) : null, jsx("div", { className: cvaContentWrapper(), children: jsx(GridAreas, { ...gridAreas, className: cvaContentContainer({ itemPlacement: "center" }), children: slots => (jsxs(Fragment$1, { children: [hasIcon ? (jsx("div", { ...slots.icon, children: jsx(SkeletonBlock, { className: cvaIconBackground({ disabled: false }), height: 32, width: 32 }) })) : null, jsxs("div", { ...slots.information, className: "min-w-0 flex-1", children: [jsx("div", { className: "grid min-w-0 grid-cols-[1fr_auto] items-center gap-2", children: jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [jsx(SkeletonLabel, { textSize: "text-sm", width: lineWidths.title }), hasTitleTag ? jsx(TagSkeleton, { size: "small" }) : null] }) }), jsx(SkeletonLabel, { textSize: "text-xs", width: lineWidths.description })] }), hasCardTag ? (jsx("div", { ...slots.cardTag, className: "justify-self-end", children: jsx(TagSkeleton, { size: "medium" }) })) : null] })) }) })] }));
6436
+ return (jsxs("div", { className: cvaPreferenceCard(), ref: ref, children: [hasInput ? (jsx("div", { className: cvaInputContainer({ itemPlacement: "center" }), children: jsx(SkeletonBlock, { height: 20, width: 20 }) })) : null, jsx("div", { className: cvaContentWrapper(), children: jsx(GridAreas, { ...gridAreas, className: cvaContentContainer({ itemPlacement: "center" }), children: slots => (jsxs(Fragment$1, { children: [hasIcon ? (jsx("div", { ...slots.icon, children: jsx(SkeletonBlock, { className: cvaIconBackground({ disabled: false }), height: 32, width: 32 }) })) : null, jsxs("div", { ...slots.information, className: "min-w-0 flex-1", children: [jsx("div", { className: "grid min-w-0 grid-cols-[1fr_auto] items-center gap-2", children: jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [jsx(SkeletonLabel, { textSize: "text-sm", width: lineWidths.title }), hasTitleTag ? jsx(TagSkeleton, { size: "small" }) : null] }) }), jsx(SkeletonLabel, { textSize: "text-xs", width: lineWidths.description })] }), hasCardTag ? (jsx("div", { ...slots.cardTag, className: "justify-self-end", children: jsx(TagSkeleton, { size: "medium" }) })) : null] })) }) })] }));
6426
6437
  };
6427
6438
  /**
6428
6439
  * Simple tag skeleton for use within PreferenceCardSkeleton.
@@ -6510,8 +6521,8 @@ const cvaSpacer = cvaMerge([], {
6510
6521
  * @param {SpacerProps} props - The props for the Spacer component
6511
6522
  * @returns {ReactElement} Spacer component
6512
6523
  */
6513
- const Spacer = ({ size = "medium", border = false, "data-testid": dataTestId, className, }) => {
6514
- return jsx("div", { className: cvaSpacer({ className, border, size }), "data-testid": dataTestId });
6524
+ const Spacer = ({ size = "medium", border = false, "data-testid": dataTestId, className, ref, }) => {
6525
+ return jsx("div", { className: cvaSpacer({ className, border, size }), "data-testid": dataTestId, ref: ref });
6515
6526
  };
6516
6527
 
6517
6528
  /**
@@ -6520,8 +6531,8 @@ const Spacer = ({ size = "medium", border = false, "data-testid": dataTestId, cl
6520
6531
  * @param {SectionHeaderProps} props - The props for the section header component
6521
6532
  * @returns {ReactElement} SectionHeader component
6522
6533
  */
6523
- const SectionHeader = ({ title, subtitle, "data-testid": dataTestId, addons, }) => {
6524
- return (jsxs("div", { className: "flex flex-col", children: [jsx(HelmetProvider, { children: jsx(Helmet, { title: title }) }), jsxs("div", { className: "mb-2 flex flex-row gap-2", children: [jsxs("div", { className: "flex grow flex-col gap-2", children: [jsx(Heading, { "data-testid": dataTestId, variant: "secondary", children: title }), subtitle ? (jsx(Heading, { subtle: true, variant: "subtitle", children: subtitle })) : null] }), addons !== null && addons !== undefined ? jsx("div", { className: "flex gap-2", children: addons }) : null] }), jsx(Spacer, { size: "small" })] }));
6534
+ const SectionHeader = ({ title, subtitle, "data-testid": dataTestId, addons, ref, }) => {
6535
+ return (jsxs("div", { className: "flex flex-col", ref: ref, children: [jsx(HelmetProvider, { children: jsx(Helmet, { title: title }) }), jsxs("div", { className: "mb-2 flex flex-row gap-2", children: [jsxs("div", { className: "flex grow flex-col gap-2", children: [jsx(Heading, { "data-testid": dataTestId, variant: "secondary", children: title }), subtitle ? (jsx(Heading, { subtle: true, variant: "subtitle", children: subtitle })) : null] }), addons !== null && addons !== undefined ? jsx("div", { className: "flex gap-2", children: addons }) : null] }), jsx(Spacer, { size: "small" })] }));
6525
6536
  };
6526
6537
 
6527
6538
  const cvaSidebar = cvaMerge(["apply", "grid", "grid-cols-fr-min", "items-center"]);
@@ -6624,7 +6635,7 @@ const useOverflowItems = ({ threshold = 1, childUniqueIdentifierAttribute = "id"
6624
6635
  * @param {SidebarProps} props - The props for the Sidebar component
6625
6636
  * @returns {ReactElement} Sidebar component
6626
6637
  */
6627
- const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", className, "data-testid": dataTestId = "sidebar", moreMenuProps, menuListProps, overflowThreshold, }) => {
6638
+ const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", className, "data-testid": dataTestId = "sidebar", moreMenuProps, menuListProps, overflowThreshold, ref, }) => {
6628
6639
  const { overflowContainerRef, itemOverflowMap } = useOverflowItems({
6629
6640
  children,
6630
6641
  childUniqueIdentifierAttribute: "id",
@@ -6637,7 +6648,7 @@ const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", classNa
6637
6648
  }
6638
6649
  return "visible";
6639
6650
  };
6640
- return (jsxs("div", { className: cvaSidebar({ className }), "data-testid": dataTestId, children: [jsx("div", { className: cvaSidebarChildContainer({ breakpoint, className: childContainerClassName }), "data-testid": `${dataTestId}-child-container`, ref: overflowContainerRef, children: Children.map(children, child => {
6651
+ return (jsxs("div", { className: cvaSidebar({ className }), "data-testid": dataTestId, ref: ref, children: [jsx("div", { className: cvaSidebarChildContainer({ breakpoint, className: childContainerClassName }), "data-testid": `${dataTestId}-child-container`, ref: overflowContainerRef, children: Children.map(children, child => {
6641
6652
  return cloneElement(child, {
6642
6653
  className: twMerge(child.props.className, itemVisibilityClassName(child.props.id)),
6643
6654
  });
@@ -6707,13 +6718,13 @@ const cvaTab = cvaMerge([
6707
6718
  * Wrapper for radix tab component.
6708
6719
  * We add a custom implementation of the asChild prop to make it easy to make the child element look like other tabs.
6709
6720
  */
6710
- const Tab = ({ value, isFullWidth = false, iconName = undefined, "data-testid": dataTestId, className, children, suffix, asChild = false, appendTabStylesToChildIfAsChild = true, ...rest }) => {
6721
+ const Tab = ({ value, isFullWidth = false, iconName = undefined, "data-testid": dataTestId, className, children, suffix, asChild = false, appendTabStylesToChildIfAsChild = true, ref, ...rest }) => {
6711
6722
  const renderContent = () => (jsxs(Fragment$1, { children: [iconName !== undefined ? jsx(Icon, { name: iconName, size: "small" }) : null, isValidElement(children) ? children.props.children : children, suffix] }));
6712
6723
  const commonProps = {
6713
6724
  className: appendTabStylesToChildIfAsChild ? cvaTab({ className, isFullWidth }) : className,
6714
6725
  ...rest,
6715
6726
  };
6716
- return (jsx(Trigger, { asChild: true, value: value, children: asChild && typeof children !== "string" ? (cloneElement(children, {
6727
+ return (jsx(Trigger, { asChild: true, ref: ref, value: value, children: asChild && typeof children !== "string" ? (cloneElement(children, {
6717
6728
  ...commonProps,
6718
6729
  children: renderContent(),
6719
6730
  })) : (jsx("button", { ...commonProps, "data-testid": dataTestId, children: renderContent() })) }));
@@ -6722,15 +6733,16 @@ const Tab = ({ value, isFullWidth = false, iconName = undefined, "data-testid":
6722
6733
  /**
6723
6734
  * Wrapper for radix tab content component.
6724
6735
  */
6725
- const TabContent = ({ className, "data-testid": dataTestId, children, ...rest }) => {
6726
- return (jsx(Content, { className: cvaTabContent({ className }), "data-testid": dataTestId ? `${dataTestId}-content` : undefined, ...rest, children: children }));
6736
+ const TabContent = ({ className, "data-testid": dataTestId, children, ref, ...rest }) => {
6737
+ return (jsx(Content, { className: cvaTabContent({ className }), "data-testid": dataTestId ? `${dataTestId}-content` : undefined, ref: ref, ...rest, children: children }));
6727
6738
  };
6728
6739
 
6729
6740
  /**
6730
6741
  * Wrapper for radix tab list component.
6731
6742
  */
6732
- const TabList = ({ className, "data-testid": dataTestId, children, autoScrollToActive = true, ...rest }) => {
6743
+ const TabList = ({ className, "data-testid": dataTestId, children, autoScrollToActive = true, ref, ...rest }) => {
6733
6744
  const listRef = useRef(null);
6745
+ const mergedRef = useMergeRefs([listRef, ref]);
6734
6746
  useEffect(() => {
6735
6747
  const element = listRef.current;
6736
6748
  if (!element) {
@@ -6769,7 +6781,7 @@ const TabList = ({ className, "data-testid": dataTestId, children, autoScrollToA
6769
6781
  });
6770
6782
  }
6771
6783
  }, [autoScrollToActive]);
6772
- return (jsx(List$1, { className: cvaTabList({ className }), "data-testid": dataTestId, ref: listRef, ...rest, children: children }));
6784
+ return (jsx(List$1, { className: cvaTabList({ className }), "data-testid": dataTestId, ref: mergedRef, ...rest, children: children }));
6773
6785
  };
6774
6786
 
6775
6787
  /**
@@ -6808,8 +6820,8 @@ const TabList = ({ className, "data-testid": dataTestId, children, autoScrollToA
6808
6820
  * );
6809
6821
  * ```
6810
6822
  */
6811
- const Tabs = ({ children, forceRender, className, "data-testid": dataTestId, fullWidth, ...rest }) => {
6812
- return (jsx(Root, { className: cvaTabsRoot({ className }), "data-testid": dataTestId, ...rest, children: children }));
6823
+ const Tabs = ({ children, forceRender, className, "data-testid": dataTestId, fullWidth, ref, ...rest }) => {
6824
+ return (jsx(Root, { className: cvaTabsRoot({ className }), "data-testid": dataTestId, ref: ref, ...rest, children: children }));
6813
6825
  };
6814
6826
 
6815
6827
  const cvaToggleGroup = cvaMerge(["inline-flex", "p-0.5", "bg-neutral-200", "rounded-md", "gap-1", "relative"]);
@@ -6932,7 +6944,7 @@ const cvaToggleItemContent = cvaMerge([], {
6932
6944
  * @param {ToggleGroupProps} props - The props for the ToggleGroup component
6933
6945
  * @returns {ReactElement} ToggleGroup component
6934
6946
  */
6935
- const ToggleGroup = ({ list, selected, setSelected, onChange, disabled = false, size = "medium", isIconOnly = false, className, "data-testid": dataTestId, }) => {
6947
+ const ToggleGroup = ({ list, selected, setSelected, onChange, disabled = false, size = "medium", isIconOnly = false, className, "data-testid": dataTestId, ref, }) => {
6936
6948
  const [isMounted, setIsMounted] = useState(false);
6937
6949
  const [slidingLeft, setSlidingLeft] = useState(0);
6938
6950
  const [slidingWidth, setSlidingWidth] = useState(0);
@@ -6948,12 +6960,12 @@ const ToggleGroup = ({ list, selected, setSelected, onChange, disabled = false,
6948
6960
  const containerPadding = 2; // p-0.5 = 2px
6949
6961
  const gap = 4;
6950
6962
  const left = containerPadding +
6951
- buttonRefs.current.slice(0, validIndex).reduce((sum, ref) => sum + (ref?.offsetWidth ?? 0) + gap, 0);
6963
+ buttonRefs.current.slice(0, validIndex).reduce((sum, btnRef) => sum + (btnRef?.offsetWidth ?? 0) + gap, 0);
6952
6964
  const width = buttonRefs.current[validIndex]?.offsetWidth ?? 0;
6953
6965
  setSlidingLeft(left);
6954
6966
  setSlidingWidth(width);
6955
6967
  }, [validIndex]);
6956
- return (jsx("div", { className: twMerge(cvaToggleGroup({ className }), cvaToggleGroupWithSlidingBackground({ isMounted })), "data-testid": dataTestId, style:
6968
+ return (jsx("div", { className: twMerge(cvaToggleGroup({ className }), cvaToggleGroupWithSlidingBackground({ isMounted })), "data-testid": dataTestId, ref: ref, style:
6957
6969
  // eslint-disable-next-line local-rules/no-typescript-assertion
6958
6970
  {
6959
6971
  "--sliding-left": `${slidingLeft}px`,