@trackunit/react-components 0.1.13 → 0.1.16
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.js +138 -28
- package/package.json +2 -2
- package/src/components/Card/CardFooter.d.ts +5 -1
- package/src/components/Card/CardHeader.d.ts +3 -3
- package/src/components/Sidebar/Sidebar.d.ts +55 -0
- package/src/components/Sidebar/useOverflowItems.d.ts +39 -0
- package/src/components/buttons/shared/ButtonProps.d.ts +4 -0
- package/src/components/index.d.ts +1 -0
package/index.js
CHANGED
|
@@ -99,7 +99,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
99
99
|
* @returns {JSX.Element} Spinner component
|
|
100
100
|
*/
|
|
101
101
|
const Spinner = ({ mode = "light", size = "medium", centered = false, className, containerClassName, dataTestId, }) => {
|
|
102
|
-
return (jsx(Container$
|
|
102
|
+
return (jsx(Container$9, Object.assign({ "$mode": mode, "$centered": centered, className: containerClassName }, { children: jsx(StyledSpinner$1, { "$size": size, "$mode": mode, role: "spinbutton", className: className, "data-testid": dataTestId }) })));
|
|
103
103
|
};
|
|
104
104
|
const getSpinnerStyles = () => ({ $size }) => {
|
|
105
105
|
switch ($size) {
|
|
@@ -117,7 +117,7 @@ const StyledSpinner$1 = tw.span `
|
|
|
117
117
|
${p => (p.$mode === "dark" ? tws `tu-spinner--dark` : null)}
|
|
118
118
|
${getSpinnerStyles()}
|
|
119
119
|
`;
|
|
120
|
-
const Container$
|
|
120
|
+
const Container$9 = tw.div `
|
|
121
121
|
tu-spinner--container
|
|
122
122
|
${p => (p.$centered ? tws `tu-spinner--container-centered` : null)}
|
|
123
123
|
`;
|
|
@@ -226,12 +226,12 @@ const Icon$1 = ({ name, size = "large", className, dataTestId, color, onClick, f
|
|
|
226
226
|
if (!IconComponent) {
|
|
227
227
|
return null;
|
|
228
228
|
}
|
|
229
|
-
return (jsx(React.Suspense, Object.assign({ fallback: jsx(LoadingDot, { className: iconSizeClassName }) }, { children: jsx(Root$
|
|
229
|
+
return (jsx(React.Suspense, Object.assign({ fallback: jsx(LoadingDot, { className: iconSizeClassName }) }, { children: jsx(Root$9, Object.assign({ "$color": color, onClick: onClick, "data-testid": dataTestId, ref: forwardedRef }, { children: jsx(IconComponent, { "data-testid": dataTestId ? `${dataTestId}-${name}` : name, className: `${iconSizeClassName} ${colorClassNames} ${className !== null && className !== void 0 ? className : ""} ${name} aspect-square`, style: fillColor ? Object.assign(Object.assign({}, style), { fill: fillColor }) : Object.assign({}, style) }) })) })));
|
|
230
230
|
};
|
|
231
231
|
const LoadingDot = tw.span `
|
|
232
232
|
tu-loading-dot
|
|
233
233
|
`;
|
|
234
|
-
const Root$
|
|
234
|
+
const Root$9 = tw.span `
|
|
235
235
|
tu-icon
|
|
236
236
|
${({ $color }) => {
|
|
237
237
|
switch ($color) {
|
|
@@ -428,7 +428,7 @@ const Alert = ({ color = "info", title, className, children, primaryAction, seco
|
|
|
428
428
|
ref && ref.current && ref.current.scrollIntoView && ref.current.scrollIntoView();
|
|
429
429
|
}
|
|
430
430
|
}, [ref, autoScroll]);
|
|
431
|
-
return (jsxs(Container$
|
|
431
|
+
return (jsxs(Container$8, Object.assign({ "$color": color, className: className, "data-testid": dataTestId, "$inline": inline, ref: ref, role: "alert" }, { children: [jsx(IconContainer$1, Object.assign({ "$inline": inline }, { children: getIconFromColor() })), jsxs(Content$1, Object.assign({ "$inline": inline }, { children: [jsxs(ContentDetails, { children: [jsx(ContentBody, { children: body }), onClose && !inline ? (jsx(CloseButtonContainer, Object.assign({ "$inline": inline }, { children: jsx(IconButton, { size: "small", variant: "transparent", color: "secondary", onClick: onClose, icon: jsx(Icon$1, { name: "XIcon", size: "small" }), title: "Close Alert", circular: true }) }))) : null] }), (primaryAction || secondaryAction || onClose) && (jsxs(RightAligned, Object.assign({ "$inline": inline }, { children: [secondaryAction && (jsx(Button, Object.assign({ size: "small", variant: "transparent", color: getButtonColor(), onClick: secondaryAction.onClick, loading: secondaryAction === null || secondaryAction === void 0 ? void 0 : secondaryAction.loading }, { children: secondaryAction.label }))), primaryAction && (jsx(Button, Object.assign({ size: "small", color: getButtonColor(), onClick: primaryAction.onClick, loading: primaryAction === null || primaryAction === void 0 ? void 0 : primaryAction.loading }, { children: primaryAction.label }))), onClose && inline ? (jsx(CloseButtonContainer, Object.assign({ "$inline": inline }, { children: jsx(IconButton, { size: "small", variant: "transparent", color: "secondary", onClick: onClose, icon: jsx(Icon$1, { name: "XIcon", size: "small" }), title: "Close Alert", circular: true }) }))) : null] })))] }))] })));
|
|
432
432
|
};
|
|
433
433
|
const CloseButtonContainer = tw.div `
|
|
434
434
|
${p => (p.$inline ? tws `tu-alert__close-button-container--inline` : tws `tu-alert__close-button-container`)}
|
|
@@ -442,7 +442,7 @@ const getBackgroundColor = () => ({ $color }) => {
|
|
|
442
442
|
};
|
|
443
443
|
return colors[$color];
|
|
444
444
|
};
|
|
445
|
-
const Container$
|
|
445
|
+
const Container$8 = tw.div `
|
|
446
446
|
tu-alert
|
|
447
447
|
${p => (p.$inline ? tws `tu-alert--inline` : null)}
|
|
448
448
|
${getBackgroundColor()}
|
|
@@ -655,11 +655,12 @@ const StyledDensityContainer = twx(DensityContainer) `
|
|
|
655
655
|
* @param {CardFooterProps} props - The props for the CardFooter component
|
|
656
656
|
* @returns {JSX.Element} CardFooter component
|
|
657
657
|
*/
|
|
658
|
-
const CardFooter = ({ dataTestId, className, children, density }) => {
|
|
659
|
-
return (jsx(
|
|
658
|
+
const CardFooter = ({ dataTestId, className, children, density, hideSeparator = false }) => {
|
|
659
|
+
return (jsx(Container$7, Object.assign({ dataTestId: dataTestId, className: className, "$hideSeparator": hideSeparator, "$density": density }, { children: jsx(Body, { children: children }) })));
|
|
660
660
|
};
|
|
661
|
-
const
|
|
661
|
+
const Container$7 = twx(DensityContainer) `
|
|
662
662
|
tu-card__footer-density-container
|
|
663
|
+
${p => p.$hideSeparator && tws `tu-card__footer-density-container--borderless`}
|
|
663
664
|
`;
|
|
664
665
|
const Body = tw.div `
|
|
665
666
|
tu-card__footer
|
|
@@ -706,11 +707,12 @@ const StyledHeading = tw.div `
|
|
|
706
707
|
* @param {CardHeaderProps} props - The props for the CardHeader component
|
|
707
708
|
* @returns {JSX.Element} CardHeader component
|
|
708
709
|
*/
|
|
709
|
-
const CardHeader = ({ heading, headingVariant = "primary", subHeading, onClose, dataTestId, className, children, accessories, density, extraClassName, }) => {
|
|
710
|
-
return (jsx(
|
|
710
|
+
const CardHeader = ({ heading, headingVariant = "primary", subHeading, onClose, dataTestId, className, children, accessories, density, extraClassName, hideSeparator = false, }) => {
|
|
711
|
+
return (jsx(Root$8, Object.assign({ dataTestId: dataTestId, className: className, "$hideSeparator": hideSeparator, "$density": density }, { children: jsxs(Container$6, { children: [jsxs("div", Object.assign({ className: extraClassName }, { children: [jsxs(HeadingContainer$1, { children: [jsx(Heading$1, Object.assign({ variant: headingVariant }, { children: heading })), accessories] }), subHeading && (jsx(Heading$1, Object.assign({ subtle: true, variant: "subtitle" }, { children: subHeading }))), children] })), onClose && (jsx(IconButton, { dataTestId: "card-header-close-button", variant: "transparent", color: "secondary", onClick: onClose, icon: jsx(Icon$1, { name: "XIcon", size: "small" }) }))] }) })));
|
|
711
712
|
};
|
|
712
|
-
const
|
|
713
|
-
tu-card__header-density-container
|
|
713
|
+
const Root$8 = twx(DensityContainer) `
|
|
714
|
+
tu-card__header-density-container
|
|
715
|
+
${p => p.$hideSeparator && tws `tu-card__header-density-container--borderless`}
|
|
714
716
|
`;
|
|
715
717
|
const Container$6 = tw.div `
|
|
716
718
|
tu-card__header
|
|
@@ -783,9 +785,9 @@ const ChartContainer = tw.div `
|
|
|
783
785
|
* @returns {JSX.Element} Label component
|
|
784
786
|
*/
|
|
785
787
|
const Label$2 = ({ id, htmlFor, children, className, dataTestId, disabled, isInvalid, }) => {
|
|
786
|
-
return (jsx(Root$
|
|
788
|
+
return (jsx(Root$7, Object.assign({ id: id || "", htmlFor: htmlFor || "", className: className, "data-testid": dataTestId, "$disabled": disabled, "$isInvalid": isInvalid }, { children: children })));
|
|
787
789
|
};
|
|
788
|
-
const Root$
|
|
790
|
+
const Root$7 = tw.label `
|
|
789
791
|
tu-label
|
|
790
792
|
${({ $disabled }) => $disabled && tws `tu-label--disabled`}
|
|
791
793
|
${({ $isInvalid }) => $isInvalid && tws `tu-label--invalid`}
|
|
@@ -1085,7 +1087,7 @@ const TipContainer = tw.text `
|
|
|
1085
1087
|
* @returns {JSX.Element} FormGroup component
|
|
1086
1088
|
*/
|
|
1087
1089
|
const FormGroup = ({ isInvalid, helpText, helpAddon, tip, className, dataTestId, label, children, disabled = false, }) => {
|
|
1088
|
-
return (jsxs(FormGroupRoot, Object.assign({ className: className, "data-testid": dataTestId, "$disabled": disabled }, { children: [jsxs(ContainerBefore, { children: [jsx(
|
|
1090
|
+
return (jsxs(FormGroupRoot, Object.assign({ className: className, "data-testid": dataTestId, "$disabled": disabled }, { children: [jsxs(ContainerBefore, { children: [jsx(FormGroupLabel, Object.assign({ dataTestId: `${dataTestId}-label` }, { children: label })), tip && jsx(Tip, Object.assign({ dataTestId: `${dataTestId}-tip` }, { children: tip }))] }), children, jsxs(ContainerAfter, Object.assign({ "$isInvalid": isInvalid }, { children: [helpText && jsx("span", Object.assign({ "data-testid": `${dataTestId}-helpText` }, { children: helpText })), helpAddon && jsx(HelpAddon, Object.assign({ "data-testid": `${dataTestId}-helpAddon` }, { children: helpAddon }))] }))] })));
|
|
1089
1091
|
};
|
|
1090
1092
|
const FormGroupRoot = tw.label `
|
|
1091
1093
|
tu-form-group
|
|
@@ -1096,6 +1098,9 @@ const FormGroupRoot = tw.label `
|
|
|
1096
1098
|
const ContainerBefore = tw.div `
|
|
1097
1099
|
tu-form-group__container-before
|
|
1098
1100
|
`;
|
|
1101
|
+
const FormGroupLabel = twx(Label$2) `
|
|
1102
|
+
component-formGroup-font
|
|
1103
|
+
`;
|
|
1099
1104
|
const ContainerAfter = tw.div `
|
|
1100
1105
|
tu-form-group__container-after
|
|
1101
1106
|
${({ $isInvalid }) => ($isInvalid ? tws `tu-form-group__container-after--invalid` : null)}
|
|
@@ -1213,7 +1218,7 @@ const Drawer = ({ open, onClose = () => { }, children, disableOverlay = false, p
|
|
|
1213
1218
|
window.removeEventListener("keyup", onKeyPress);
|
|
1214
1219
|
};
|
|
1215
1220
|
}, [open, onClose]);
|
|
1216
|
-
return (jsx(FloatingFocusManager, Object.assign({ context: context }, { children: open ? (jsxs(Root$
|
|
1221
|
+
return (jsx(FloatingFocusManager, Object.assign({ context: context }, { children: open ? (jsxs(Root$6, Object.assign({ id: "drawer" }, { children: [!disableOverlay && jsx(Overlay, { "aria-hidden": open, "$open": open, onClick: onClose, id: "drawer__overlay" }), jsx(StyledCard$1, Object.assign({ "aria-hidden": open, "data-testId": dataTestId, "$open": open, "$position": position, id: "drawer__card", className: className }, { children: children }))] }))) : (
|
|
1217
1222
|
// eslint-disable-next-line react/jsx-no-useless-fragment
|
|
1218
1223
|
jsx(Fragment, {})) })));
|
|
1219
1224
|
};
|
|
@@ -1235,7 +1240,7 @@ const StyledCard$1 = twx(Card) `
|
|
|
1235
1240
|
${({ $open }) => $open && tws `tu-drawer__card--open`}
|
|
1236
1241
|
${({ $position }) => getPositionStyles($position)}
|
|
1237
1242
|
`;
|
|
1238
|
-
const Root$
|
|
1243
|
+
const Root$6 = tw.div `
|
|
1239
1244
|
tu-drawer
|
|
1240
1245
|
`;
|
|
1241
1246
|
const Overlay = tw.div `
|
|
@@ -1346,9 +1351,9 @@ const Ping = tw.span `
|
|
|
1346
1351
|
*/
|
|
1347
1352
|
const LegendItem = ({ className, label, disabled, selected, onClick, color, dataTestId }) => {
|
|
1348
1353
|
const handleOnClick = onClick && !disabled ? () => onClick() : undefined;
|
|
1349
|
-
return (jsxs(Root$
|
|
1354
|
+
return (jsxs(Root$5, Object.assign({ "data-testid": dataTestId, "$disabled": disabled, className: className, "$selected": selected, onClick: handleOnClick }, { children: [jsx(Indicator, { style: { backgroundColor: color }, "$selected": selected }), label && jsx("p", { children: label })] })));
|
|
1350
1355
|
};
|
|
1351
|
-
const Root$
|
|
1356
|
+
const Root$5 = tw.div `
|
|
1352
1357
|
inline-flex
|
|
1353
1358
|
items-center
|
|
1354
1359
|
transition-all
|
|
@@ -1441,11 +1446,11 @@ const MoreMenu = ({ className, dataTestId, dotsDirection = "horizontal", menuPla
|
|
|
1441
1446
|
useClickOutside(actionMenuRef, () => {
|
|
1442
1447
|
setActionMenuIsOpen(false);
|
|
1443
1448
|
});
|
|
1444
|
-
return (jsx(Root$
|
|
1449
|
+
return (jsx(Root$4, Object.assign({ ref: actionMenuRef, className: className, "data-testid": dataTestId }, { children: jsx(Popover, Object.assign({ render: () => children, placement: menuPlacement }, { children: jsx(IconButton, Object.assign({}, iconButtonProps, { icon: jsx(Icon$1, Object.assign({ name: dotsName }, iconProps)), onClick: () => {
|
|
1445
1450
|
setActionMenuIsOpen(!actionMenuIsOpen);
|
|
1446
1451
|
} })) })) })));
|
|
1447
1452
|
};
|
|
1448
|
-
const Root$
|
|
1453
|
+
const Root$4 = tw.div `
|
|
1449
1454
|
tu-more-menu
|
|
1450
1455
|
${({ variant }) => (variant === "primary" ? tws `tu-more-menu--primary` : "")}
|
|
1451
1456
|
`;
|
|
@@ -1619,7 +1624,7 @@ const IconContainer = tw.div `
|
|
|
1619
1624
|
* @returns {JSX.Element} PageHeader component
|
|
1620
1625
|
*/
|
|
1621
1626
|
const PageHeader = ({ className, dataTestId, action, showLoading, description, link, title, tag, backTo, children, }) => {
|
|
1622
|
-
return (jsxs(StyledPageHeader, Object.assign({ className: className, "data-testid": dataTestId }, { children: [jsxs(HeadingAndAccessoriesContainer, Object.assign({ "data-testid": `${dataTestId}-heading-container` }, { children: [jsxs(HeadingContainer, { children: [backTo && (jsx(IconButton, { to: backTo, color: "tertiary", variant: "transparent", size: "small", icon: jsx(Icon$1, { name: "ArrowLeftIcon" }) })), jsx(Heading, Object.assign({ "data-testid": `${dataTestId}-heading` }, { children: title })), description && (jsx(StyledTip, Object.assign({ link: isValidHttpUrl(link) ? link : undefined, dataTestId: `${dataTestId}-tip`, iconProps: { name: "QuestionMarkCircleIcon" }, renderAs: link ? "a" : "span" }, { children: description })))] }), tag && jsx(Tag, Object.assign({ dataTestId: dataTestId }, { children: tag })), showLoading && jsx(Spinner, { dataTestId: `${dataTestId}-spinner`, centered: true }), action] })), jsx(ChildContainer, { children: children })] })));
|
|
1627
|
+
return (jsxs(StyledPageHeader, Object.assign({ className: className, "data-testid": dataTestId }, { children: [jsxs(HeadingAndAccessoriesContainer, Object.assign({ "data-testid": `${dataTestId}-heading-container` }, { children: [jsxs(HeadingContainer, { children: [backTo && (jsx(IconButton, { to: backTo, color: "tertiary", variant: "transparent", size: "small", icon: jsx(Icon$1, { name: "ArrowLeftIcon" }) })), jsx(Heading, Object.assign({ "data-testid": `${dataTestId}-heading` }, { children: title })), description && (jsx(StyledTip, Object.assign({ link: isValidHttpUrl(link) ? link : undefined, dataTestId: `${dataTestId}-tip`, iconProps: { name: "QuestionMarkCircleIcon" }, renderAs: link ? "a" : "span" }, { children: description })))] }), tag && jsx(Tag, Object.assign({ dataTestId: dataTestId }, { children: tag })), showLoading && jsx(Spinner, { dataTestId: `${dataTestId}-spinner`, centered: true }), action] })), jsx(ChildContainer$1, { children: children })] })));
|
|
1623
1628
|
};
|
|
1624
1629
|
function isValidHttpUrl(link) {
|
|
1625
1630
|
if (!link) {
|
|
@@ -1646,7 +1651,7 @@ const HeadingContainer = tw.div `
|
|
|
1646
1651
|
const Heading = tw.h1 `
|
|
1647
1652
|
tu-page-header__heading
|
|
1648
1653
|
`;
|
|
1649
|
-
const ChildContainer = tw.div `
|
|
1654
|
+
const ChildContainer$1 = tw.div `
|
|
1650
1655
|
tu-page-header__child-container
|
|
1651
1656
|
`;
|
|
1652
1657
|
const StyledTip = twx(Tip) `
|
|
@@ -1754,15 +1759,15 @@ const Pagination = ({ gotoPage, previousPage, nextPage, pageCount, pageIndex, ca
|
|
|
1754
1759
|
handlePageChange("manual");
|
|
1755
1760
|
}, [handlePageChange]);
|
|
1756
1761
|
if (loading) {
|
|
1757
|
-
return (jsx(Root$
|
|
1762
|
+
return (jsx(Root$3, Object.assign({ className: className }, { children: jsx(SkeletonLines, { height: 16, width: 150 }) })));
|
|
1758
1763
|
}
|
|
1759
|
-
return (jsxs(Root$
|
|
1764
|
+
return (jsxs(Root$3, Object.assign({ "data-testid": dataTestId, className: className }, { children: [jsx(IconButton, { onClick: () => handlePageChange("prev"), disabled: cursorBase ? false : page !== undefined && page <= 0, "data-testid": "prev-page", icon: jsx(Icon$1, { name: "ChevronLeftIcon", size: "small" }), size: "small", color: "secondary", variant: "transparent" }), !cursorBase && (jsxs(Fragment, { children: [jsx(Text$1, { children: getTranslatedPage() }), jsx(PageInput, { type: "number", min: 1,
|
|
1760
1765
|
// max={amountOfPages}
|
|
1761
1766
|
value: pageInputValue, onFocus: handleOnFocus, onBlur: handleOnBlur, onChange: handleOnChange, onKeyPress: handleOnKeyPress, "data-testid": "page-input" }), jsx(TextStyled, Object.assign({ dataTestId: "page-count" }, { children: pageCount !== null && pageCount !== undefined && getTranslatedCount(pageCount) }))] })), jsx(IconButton, { onClick: () => handlePageChange("next"), disabled: cursorBase
|
|
1762
1767
|
? false
|
|
1763
1768
|
: page !== undefined && pageCount !== undefined && pageCount !== null && page >= pageCount - 1, "data-testid": "next-page", icon: jsx(Icon$1, { name: "ChevronRightIcon", size: "small" }), size: "small", color: "secondary", variant: "transparent" })] })));
|
|
1764
1769
|
};
|
|
1765
|
-
const Root$
|
|
1770
|
+
const Root$3 = tw.div `
|
|
1766
1771
|
tu-pagination
|
|
1767
1772
|
`;
|
|
1768
1773
|
const TextStyled = twx(Text$1) `
|
|
@@ -2451,6 +2456,111 @@ const SelectContainer = tw.div `
|
|
|
2451
2456
|
`;
|
|
2452
2457
|
Select.displayName = "Select";
|
|
2453
2458
|
|
|
2459
|
+
/**
|
|
2460
|
+
* A hook used to detect what children are overflowing a container.
|
|
2461
|
+
*
|
|
2462
|
+
* @param {OverflowItemsOptions} root0 The options for the hook.
|
|
2463
|
+
* @param {OverflowItemsOptions.threshold} root0.threshold The threshold for the intersection observer.
|
|
2464
|
+
* @returns {object} The overflow items and the ref to the container.
|
|
2465
|
+
*/
|
|
2466
|
+
const useOverflowItems = ({ threshold = 1, childUniqueIdentifierAttribute = "id", children, }) => {
|
|
2467
|
+
const [itemOverflowMap, setItemOverflowMap] = useState({});
|
|
2468
|
+
const overflowContainerRef = useRef(null); // TODO: Handle other elements than div
|
|
2469
|
+
const observerRef = useRef(null);
|
|
2470
|
+
const handleIntersection = useCallback(entries => {
|
|
2471
|
+
const updatedEntries = {};
|
|
2472
|
+
entries.forEach(entry => {
|
|
2473
|
+
const targetElementId = entry.target[childUniqueIdentifierAttribute];
|
|
2474
|
+
if (targetElementId) {
|
|
2475
|
+
updatedEntries[targetElementId] = entry.isIntersecting ? false : true;
|
|
2476
|
+
}
|
|
2477
|
+
});
|
|
2478
|
+
setItemOverflowMap(prev => (Object.assign(Object.assign({}, prev), updatedEntries)));
|
|
2479
|
+
}, [childUniqueIdentifierAttribute]);
|
|
2480
|
+
const observe = useCallback(() => {
|
|
2481
|
+
const node = overflowContainerRef.current;
|
|
2482
|
+
if (node && node.children) {
|
|
2483
|
+
const root = overflowContainerRef.current;
|
|
2484
|
+
const options = { root, threshold };
|
|
2485
|
+
const observer = new IntersectionObserver(handleIntersection, options);
|
|
2486
|
+
Array.from(node.children).forEach(child => {
|
|
2487
|
+
observer.observe(child);
|
|
2488
|
+
});
|
|
2489
|
+
observer.observe(node);
|
|
2490
|
+
observerRef.current = observer;
|
|
2491
|
+
}
|
|
2492
|
+
}, [handleIntersection, threshold]);
|
|
2493
|
+
const unobserve = useCallback(() => {
|
|
2494
|
+
const currentObserver = observerRef.current;
|
|
2495
|
+
currentObserver === null || currentObserver === void 0 ? void 0 : currentObserver.disconnect();
|
|
2496
|
+
observerRef.current = null;
|
|
2497
|
+
}, []);
|
|
2498
|
+
const initializeObserver = useCallback(() => {
|
|
2499
|
+
unobserve();
|
|
2500
|
+
observe();
|
|
2501
|
+
}, [observe, unobserve]);
|
|
2502
|
+
useEffect(() => {
|
|
2503
|
+
initializeObserver();
|
|
2504
|
+
return () => {
|
|
2505
|
+
unobserve();
|
|
2506
|
+
};
|
|
2507
|
+
}, [initializeObserver, unobserve, children]);
|
|
2508
|
+
return { overflowContainerRef, itemOverflowMap };
|
|
2509
|
+
};
|
|
2510
|
+
|
|
2511
|
+
/**
|
|
2512
|
+
* The sidebar components is used to render a responsive sidebar.
|
|
2513
|
+
* - The sidebar will be rendered horizontally until a given breakpoint where it will be stacked vertically.
|
|
2514
|
+
* - The sidebar hides items that does not fit in the sidebar and show them in a more menu.
|
|
2515
|
+
* - **_The sidebar is just a wrapper. You are responsible for styling the children._**
|
|
2516
|
+
*
|
|
2517
|
+
* When using this component make sure to add `setupIntersectionObserver();` to your jest.setup.ts file.
|
|
2518
|
+
*
|
|
2519
|
+
* @param {SidebarProps} props - The props for the Sidebar component
|
|
2520
|
+
* @returns {JSX.Element} Sidebar component
|
|
2521
|
+
*/
|
|
2522
|
+
const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", className, dataTestId = "sidebar", moreMenuProps, menuListProps, overflowThreshold, }) => {
|
|
2523
|
+
const { overflowContainerRef, itemOverflowMap } = useOverflowItems({
|
|
2524
|
+
children,
|
|
2525
|
+
childUniqueIdentifierAttribute: "id",
|
|
2526
|
+
threshold: overflowThreshold !== null && overflowThreshold !== void 0 ? overflowThreshold : 0.8,
|
|
2527
|
+
});
|
|
2528
|
+
const overflowItemCount = Object.values(itemOverflowMap).filter(isOverflowing => isOverflowing).length;
|
|
2529
|
+
const itemVisibilityClassName = (id) => {
|
|
2530
|
+
if (itemOverflowMap[id]) {
|
|
2531
|
+
return tws `invisible`;
|
|
2532
|
+
}
|
|
2533
|
+
return tws `visible`;
|
|
2534
|
+
};
|
|
2535
|
+
return (jsxs(Root$2, Object.assign({ className: className, "data-testid": dataTestId }, { children: [jsx(ChildContainer, Object.assign({ "$breakpoint": breakpoint, ref: overflowContainerRef, className: childContainerClassName, "data-testid": `${dataTestId}-child-container` }, { children: React__default.Children.map(children, child => {
|
|
2536
|
+
return React__default.cloneElement(child, {
|
|
2537
|
+
className: `${child.props.className} ${itemVisibilityClassName(child.props.id)}`,
|
|
2538
|
+
});
|
|
2539
|
+
}) })), overflowItemCount > 0 ? (jsx(MoreMenu, Object.assign({ iconButtonProps: {
|
|
2540
|
+
circular: false,
|
|
2541
|
+
variant: "transparent",
|
|
2542
|
+
color: "secondary",
|
|
2543
|
+
}, menuPlacement: "bottom-end" }, moreMenuProps, { className: `${(moreMenuProps === null || moreMenuProps === void 0 ? void 0 : moreMenuProps.className) || ""} !p-0`, dataTestId: `${dataTestId}-more-menu` }, { children: jsx(MenuList, Object.assign({}, menuListProps, { dataTestId: `${dataTestId}-menu-list` }, { children: React__default.Children.map(children, child => {
|
|
2544
|
+
return itemOverflowMap[child.props.id] ? child : null;
|
|
2545
|
+
}) })) }))) : null] })));
|
|
2546
|
+
};
|
|
2547
|
+
const Root$2 = tw.div `
|
|
2548
|
+
tu-sidebar
|
|
2549
|
+
`;
|
|
2550
|
+
const breakpointClasses = {
|
|
2551
|
+
xs: tws `tu-sidebar__child-container--xs`,
|
|
2552
|
+
sm: tws `tu-sidebar__child-container--sm`,
|
|
2553
|
+
md: tws `tu-sidebar__child-container--md`,
|
|
2554
|
+
lg: tws `tu-sidebar__child-container--lg`,
|
|
2555
|
+
xl: tws `tu-sidebar__child-container--xl`,
|
|
2556
|
+
"2xl": tws `tu-sidebar__child-container--2xl`,
|
|
2557
|
+
"3xl": tws `tu-sidebar__child-container--3xl`,
|
|
2558
|
+
};
|
|
2559
|
+
const ChildContainer = tw.div `
|
|
2560
|
+
tu-sidebar__child-container
|
|
2561
|
+
${({ $breakpoint }) => breakpointClasses[$breakpoint]}
|
|
2562
|
+
`;
|
|
2563
|
+
|
|
2454
2564
|
/**
|
|
2455
2565
|
* The TextArea is a base component, and should not be used very often.
|
|
2456
2566
|
* For most cases the TextAreaField is the correct component.
|
|
@@ -2961,4 +3071,4 @@ const Layout = tw.div `
|
|
|
2961
3071
|
tu-layout-TwoColumnLayout
|
|
2962
3072
|
`;
|
|
2963
3073
|
|
|
2964
|
-
export { ActionButton, Alert, Badge, BaseInput, Button, Card, CardBody, CardFooter, CardHeader, Chart, Checkbox, Collapse, ContentGridArea, CopyableText, CreatableSelect, DateField, DateInput, DayPicker, DayPickerPopover, DayRangePicker, DensityContainer, Drawer, ExternalLink, FilterListMapLayout, FormGroup, FullWidthRepeatingLayout, GridArea, Heading$1 as Heading, Icon$1 as Icon, IconButton, Indicator$1 as Indicator, IntrinsicallyResponsiveGrid, Label$2 as Label, LegendItem, MenuItem, MenuList, MinTopFullContentLayout, Modal, ModalBackdrop, MoreMenu, MultiSelectMenuItem, NavGridArea, NumberField, NumberInput, PageHeader, Pagination, PieChart, Popover, PopoverList, PopoverListItem, PopoverTitle, Prompt, ROLE_CARD, RadioGroup, RadioItem, Search, SectionHeader, Select, SelectPrefix, SingleSelectMenuItem, SkeletonLines, Spacer, Spinner, StarButton, Tag, Text$1 as Text, TextArea, TextAreaField, TextField, TextInput, Timeline, TimelineElement, Tip, TitleGridArea, TitleNavContentLayout, Toggle, Tooltip, TwoColumnLayout, ValueBar, docs, getOrderedOptions, getValueBarColorByValue, isMultiValue, useContainerProps, useCustomComponents, useDebounce, useLocalStorage, useModal, usePrompt, useTimeout };
|
|
3074
|
+
export { ActionButton, Alert, Badge, BaseInput, Button, Card, CardBody, CardFooter, CardHeader, Chart, Checkbox, Collapse, ContentGridArea, CopyableText, CreatableSelect, DateField, DateInput, DayPicker, DayPickerPopover, DayRangePicker, DensityContainer, Drawer, ExternalLink, FilterListMapLayout, FormGroup, FullWidthRepeatingLayout, GridArea, Heading$1 as Heading, Icon$1 as Icon, IconButton, Indicator$1 as Indicator, IntrinsicallyResponsiveGrid, Label$2 as Label, LegendItem, MenuItem, MenuList, MinTopFullContentLayout, Modal, ModalBackdrop, MoreMenu, MultiSelectMenuItem, NavGridArea, NumberField, NumberInput, PageHeader, Pagination, PieChart, Popover, PopoverList, PopoverListItem, PopoverTitle, Prompt, ROLE_CARD, RadioGroup, RadioItem, Search, SectionHeader, Select, SelectPrefix, Sidebar, SingleSelectMenuItem, SkeletonLines, Spacer, Spinner, StarButton, Tag, Text$1 as Text, TextArea, TextAreaField, TextField, TextInput, Timeline, TimelineElement, Tip, TitleGridArea, TitleNavContentLayout, Toggle, Tooltip, TwoColumnLayout, ValueBar, docs, getOrderedOptions, getValueBarColorByValue, isMultiValue, useContainerProps, useCustomComponents, useDebounce, useLocalStorage, useModal, usePrompt, useTimeout };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"@trackunit/tailwind-styled-components": "0.0.51",
|
|
10
10
|
"react": "18.2.0",
|
|
11
11
|
"@trackunit/ui-design-tokens": "0.0.53",
|
|
12
|
-
"@trackunit/react-core-contexts-test": "0.1.
|
|
12
|
+
"@trackunit/react-core-contexts-test": "0.1.15",
|
|
13
13
|
"echarts-for-react": "3.0.2",
|
|
14
14
|
"echarts": "5.4.0",
|
|
15
15
|
"uuid": "8.3.2",
|
|
@@ -9,6 +9,10 @@ export interface CardFooterProps extends CommonProps {
|
|
|
9
9
|
* Element to render in the footer
|
|
10
10
|
*/
|
|
11
11
|
children?: React.ReactNode | null;
|
|
12
|
+
/**
|
|
13
|
+
* Wether or not a seperator line should be rendered
|
|
14
|
+
*/
|
|
15
|
+
hideSeparator?: boolean;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* A simple footer intended to use with Cards and Modals.
|
|
@@ -18,4 +22,4 @@ export interface CardFooterProps extends CommonProps {
|
|
|
18
22
|
* @param {CardFooterProps} props - The props for the CardFooter component
|
|
19
23
|
* @returns {JSX.Element} CardFooter component
|
|
20
24
|
*/
|
|
21
|
-
export declare const CardFooter: ({ dataTestId, className, children, density }: CardFooterProps) => JSX.Element;
|
|
25
|
+
export declare const CardFooter: ({ dataTestId, className, children, density, hideSeparator }: CardFooterProps) => JSX.Element;
|
|
@@ -5,7 +5,7 @@ export interface CardHeaderProps extends CommonProps {
|
|
|
5
5
|
/**
|
|
6
6
|
* The text to show in the Cards main heading
|
|
7
7
|
*/
|
|
8
|
-
heading
|
|
8
|
+
heading?: string;
|
|
9
9
|
/**
|
|
10
10
|
* The variant/size of the heading.
|
|
11
11
|
* Same as the `Heading` component.
|
|
@@ -26,7 +26,7 @@ export interface CardHeaderProps extends CommonProps {
|
|
|
26
26
|
/**
|
|
27
27
|
* Wether or not a seperator line should be rendered
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
hideSeparator?: boolean;
|
|
30
30
|
/** Function to call when the close button is clicked */
|
|
31
31
|
onClose?: () => void;
|
|
32
32
|
/**
|
|
@@ -44,4 +44,4 @@ export interface CardHeaderProps extends CommonProps {
|
|
|
44
44
|
* @param {CardHeaderProps} props - The props for the CardHeader component
|
|
45
45
|
* @returns {JSX.Element} CardHeader component
|
|
46
46
|
*/
|
|
47
|
-
export declare const CardHeader: ({ heading, headingVariant, subHeading, onClose, dataTestId, className, children, accessories, density, extraClassName, }: CardHeaderProps) => JSX.Element;
|
|
47
|
+
export declare const CardHeader: ({ heading, headingVariant, subHeading, onClose, dataTestId, className, children, accessories, density, extraClassName, hideSeparator, }: CardHeaderProps) => JSX.Element;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CommonProps } from "../../common/CommonProps";
|
|
3
|
+
import { MenuList, MoreMenu } from "../Menu";
|
|
4
|
+
export interface SidebarItemProps extends CommonProps {
|
|
5
|
+
/**
|
|
6
|
+
* The id prop is used to identify the sidebar item in the dom.
|
|
7
|
+
* This is needed as it is used for the intersection observer to determine which items are visible and which are not.
|
|
8
|
+
*/
|
|
9
|
+
id: string;
|
|
10
|
+
}
|
|
11
|
+
export declare type Breakpoints = "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
|
|
12
|
+
export interface SidebarProps extends CommonProps {
|
|
13
|
+
/**
|
|
14
|
+
* The breakpoint at which the menu will go from Horizontal to vertical stacked
|
|
15
|
+
*
|
|
16
|
+
* @default "lg"
|
|
17
|
+
*/
|
|
18
|
+
breakpoint?: Breakpoints;
|
|
19
|
+
/**
|
|
20
|
+
* The overflowThreshold is used to determine when an item is considered to be overflowing.
|
|
21
|
+
*/
|
|
22
|
+
overflowThreshold?: number;
|
|
23
|
+
/**
|
|
24
|
+
* The child elements of the sidebar.
|
|
25
|
+
* Usually this will be a list of SidebarItems, bottons or links.
|
|
26
|
+
*
|
|
27
|
+
* **For the overflow functionality to take effect use _"min-w-[*]"_ or _"flex-shrink-0"_ on the elements.**
|
|
28
|
+
*/
|
|
29
|
+
children: React.ReactElement<SidebarItemProps>[] | React.ReactElement<SidebarItemProps>;
|
|
30
|
+
/**
|
|
31
|
+
* The childContainerClassName is applied to the element that contains the children.
|
|
32
|
+
* This can be used to change gap or similar styling.
|
|
33
|
+
*/
|
|
34
|
+
childContainerClassName?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Pass custom props to the MoreMenu component used to render overflow items
|
|
37
|
+
*/
|
|
38
|
+
moreMenuProps?: Omit<React.ComponentProps<typeof MoreMenu>, "children">;
|
|
39
|
+
/**
|
|
40
|
+
* Pass custom props to the MenuList component used to render overflow items
|
|
41
|
+
*/
|
|
42
|
+
menuListProps?: Omit<React.ComponentProps<typeof MenuList>, "children">;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The sidebar components is used to render a responsive sidebar.
|
|
46
|
+
* - The sidebar will be rendered horizontally until a given breakpoint where it will be stacked vertically.
|
|
47
|
+
* - The sidebar hides items that does not fit in the sidebar and show them in a more menu.
|
|
48
|
+
* - **_The sidebar is just a wrapper. You are responsible for styling the children._**
|
|
49
|
+
*
|
|
50
|
+
* When using this component make sure to add `setupIntersectionObserver();` to your jest.setup.ts file.
|
|
51
|
+
*
|
|
52
|
+
* @param {SidebarProps} props - The props for the Sidebar component
|
|
53
|
+
* @returns {JSX.Element} Sidebar component
|
|
54
|
+
*/
|
|
55
|
+
export declare const Sidebar: ({ childContainerClassName, children, breakpoint, className, dataTestId, moreMenuProps, menuListProps, overflowThreshold, }: SidebarProps) => JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { HTMLAttributes } from "react";
|
|
2
|
+
import { SidebarItemProps } from "./Sidebar";
|
|
3
|
+
export interface OverflowItemsOptions {
|
|
4
|
+
/**
|
|
5
|
+
* If the child elements of the container are not available at the time of the hook initialization,
|
|
6
|
+
* you can pass the children as a prop, and the hook will initialize the observer when the children are available.
|
|
7
|
+
*/
|
|
8
|
+
children?: React.ReactElement<SidebarItemProps>[] | React.ReactElement<SidebarItemProps>;
|
|
9
|
+
/**
|
|
10
|
+
* The threshold for the intersection observer.
|
|
11
|
+
* Learn more: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer
|
|
12
|
+
*
|
|
13
|
+
* @default 1
|
|
14
|
+
*/
|
|
15
|
+
threshold?: number | number[];
|
|
16
|
+
/**
|
|
17
|
+
* The unique identifier attribute for the child elements.
|
|
18
|
+
* The identifier is the value that will be returned in the visibleItemsIds array.
|
|
19
|
+
*
|
|
20
|
+
* **ATTENTION: The identifier must be a HTMLAttribute that is available in the DOM, you cannot use react key.**
|
|
21
|
+
*
|
|
22
|
+
* @default "id"
|
|
23
|
+
*/
|
|
24
|
+
childUniqueIdentifierAttribute?: keyof HTMLAttributes<HTMLElement> | `data-${string}`;
|
|
25
|
+
}
|
|
26
|
+
export declare type OverflowMap = {
|
|
27
|
+
[key: string]: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A hook used to detect what children are overflowing a container.
|
|
31
|
+
*
|
|
32
|
+
* @param {OverflowItemsOptions} root0 The options for the hook.
|
|
33
|
+
* @param {OverflowItemsOptions.threshold} root0.threshold The threshold for the intersection observer.
|
|
34
|
+
* @returns {object} The overflow items and the ref to the container.
|
|
35
|
+
*/
|
|
36
|
+
export declare const useOverflowItems: ({ threshold, childUniqueIdentifierAttribute, children, }: OverflowItemsOptions) => {
|
|
37
|
+
overflowContainerRef: import("react").MutableRefObject<HTMLDivElement | null>;
|
|
38
|
+
itemOverflowMap: OverflowMap;
|
|
39
|
+
};
|