@trackunit/react-components 1.17.17 → 1.17.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +182 -170
- package/index.esm.js +183 -171
- package/package.json +5 -5
- package/src/common/Refable.d.ts +5 -0
- package/src/components/Alert/Alert.d.ts +3 -2
- package/src/components/Badge/Badge.d.ts +3 -2
- package/src/components/Breadcrumb/Breadcrumb.d.ts +1 -1
- package/src/components/Breadcrumb/utils/types.d.ts +2 -1
- package/src/components/Card/Card.d.ts +7 -3
- package/src/components/Card/CardBody.d.ts +3 -2
- package/src/components/Card/CardFooter.d.ts +3 -2
- package/src/components/Card/CardHeader.d.ts +3 -2
- package/src/components/Collapse/Collapse.d.ts +3 -2
- package/src/components/CopyableText/CopyableText.d.ts +3 -2
- package/src/components/DetailsList/DetailsList.d.ts +4 -2
- package/src/components/EmptyState/EmptyState.d.ts +2 -1
- package/src/components/EmptyValue/EmptyValue.d.ts +2 -1
- package/src/components/ExternalLink/ExternalLink.d.ts +3 -2
- package/src/components/Heading/Heading.d.ts +3 -2
- package/src/components/HorizontalOverflowScroller/HorizontalOverflowScroller.d.ts +4 -2
- package/src/components/Icon/Icon.d.ts +4 -9
- package/src/components/Indicator/Indicator.d.ts +3 -2
- package/src/components/KPI/KPI.d.ts +3 -2
- package/src/components/KPI/KPISkeleton.d.ts +3 -2
- package/src/components/KPICard/KPICard.d.ts +3 -2
- package/src/components/KPICard/KPICardSkeleton.d.ts +3 -2
- package/src/components/KPICard/components/TrendIndicator/TrendIndicator.d.ts +3 -2
- package/src/components/KPICard/components/TrendIndicators.d.ts +3 -2
- package/src/components/Menu/MenuItem/MenuItem.d.ts +3 -2
- package/src/components/Menu/MenuList/MenuList.d.ts +3 -2
- package/src/components/Menu/MoreMenu/MoreMenu.d.ts +3 -2
- package/src/components/Notice/Notice.d.ts +3 -2
- package/src/components/Page/Page.d.ts +3 -2
- package/src/components/Page/PageContent.d.ts +3 -2
- package/src/components/PageHeader/PageHeader.d.ts +1 -1
- package/src/components/PageHeader/components/PageHeaderKpiMetrics.d.ts +4 -2
- package/src/components/PageHeader/components/PageHeaderTitle.d.ts +4 -2
- package/src/components/PageHeader/types.d.ts +2 -1
- package/src/components/Pagination/Pagination.d.ts +3 -2
- package/src/components/Polygon/Polygon.d.ts +3 -2
- package/src/components/Popover/PopoverTitle.d.ts +3 -2
- package/src/components/PreferenceCard/PreferenceCard.d.ts +3 -2
- package/src/components/PreferenceCard/PreferenceCardSkeleton.d.ts +3 -2
- package/src/components/SectionHeader/SectionHeader.d.ts +3 -2
- package/src/components/Sidebar/Sidebar.d.ts +3 -2
- package/src/components/Skeleton/SkeletonBlock/SkeletonBlock.d.ts +2 -1
- package/src/components/Skeleton/SkeletonLabel/SkeletonLabel.d.ts +2 -1
- package/src/components/SkeletonLines/SkeletonLines.d.ts +4 -3
- package/src/components/Spacer/Spacer.d.ts +3 -2
- package/src/components/Spinner/Spinner.d.ts +3 -2
- package/src/components/Tabs/Tab.d.ts +3 -2
- package/src/components/Tabs/TabContent.d.ts +3 -2
- package/src/components/Tabs/TabList.d.ts +3 -2
- package/src/components/Tabs/Tabs.d.ts +3 -2
- package/src/components/ToggleGroup/ToggleGroup.d.ts +3 -2
- package/src/components/Tooltip/Tooltip.d.ts +1 -1
- package/src/components/ValueBar/ValueBar.d.ts +3 -2
- package/src/components/ZStack/ZStack.d.ts +3 -2
- package/src/components/buttons/StarButton/StarButton.d.ts +3 -2
- 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,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1061
|
-
|
|
1125
|
+
const element = scrollRef.current;
|
|
1126
|
+
if (element && typeof element.scrollIntoView === "function") {
|
|
1127
|
+
element.scrollIntoView();
|
|
1128
|
+
}
|
|
1062
1129
|
}
|
|
1063
|
-
}, [
|
|
1064
|
-
return (jsxs("div", { className: cvaAlert({ color, actionsInline, className }), "data-testid": dataTestId, ref:
|
|
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 =
|
|
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
|
-
|
|
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-
|
|
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: "
|
|
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:
|
|
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,
|
|
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`,
|