collapsible.tsx 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import {Children, Fragment, useState} from 'react';
  2. import {Button} from 'sentry/components/button';
  3. import {t, tn} from 'sentry/locale';
  4. type CollapseButtonRenderProps = {
  5. onCollapse: () => void;
  6. };
  7. type ExpandButtonRenderProps = {
  8. numberOfHiddenItems: number;
  9. onExpand: () => void;
  10. };
  11. type Props = {
  12. children: React.ReactNode;
  13. collapseButton?: (props: CollapseButtonRenderProps) => React.ReactNode;
  14. expandButton?: (props: ExpandButtonRenderProps) => React.ReactNode;
  15. maxVisibleItems?: number;
  16. };
  17. /**
  18. * This component is used to show first X items and collapse the rest
  19. */
  20. function Collapsible({
  21. collapseButton,
  22. expandButton,
  23. maxVisibleItems = 5,
  24. children,
  25. }: Props) {
  26. const [isCollapsed, setCollapsed] = useState(true);
  27. const handleCollapseToggle = () => setCollapsed(!isCollapsed);
  28. const items = Children.toArray(children);
  29. const canCollapse = items.length > maxVisibleItems;
  30. if (!canCollapse) {
  31. return <Fragment>{children}</Fragment>;
  32. }
  33. const visibleItems = isCollapsed ? items.slice(0, maxVisibleItems) : items;
  34. const numberOfHiddenItems = items.length - visibleItems.length;
  35. const showDefault =
  36. (numberOfHiddenItems > 0 && !expandButton) ||
  37. (numberOfHiddenItems === 0 && !collapseButton);
  38. return (
  39. <Fragment>
  40. {visibleItems}
  41. {showDefault && (
  42. <Button priority="link" onClick={handleCollapseToggle}>
  43. {isCollapsed
  44. ? tn('Show %s hidden item', 'Show %s hidden items', numberOfHiddenItems)
  45. : t('Collapse')}
  46. </Button>
  47. )}
  48. {numberOfHiddenItems > 0 &&
  49. expandButton?.({onExpand: handleCollapseToggle, numberOfHiddenItems})}
  50. {numberOfHiddenItems === 0 && collapseButton?.({onCollapse: handleCollapseToggle})}
  51. </Fragment>
  52. );
  53. }
  54. export default Collapsible;