collapsePanel.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import {useState} from 'react';
  2. import {css} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import {IconChevron, IconList} from 'sentry/icons';
  5. import {tct} from 'sentry/locale';
  6. import space from 'sentry/styles/space';
  7. export const COLLAPSE_COUNT = 5;
  8. type ChildRenderProps = {
  9. isExpanded: boolean;
  10. showMoreButton: React.ReactNode;
  11. };
  12. type Props = {
  13. children: (props: ChildRenderProps) => JSX.Element;
  14. items: number;
  15. buttonTitle?: string;
  16. collapseCount?: number;
  17. disableBorder?: boolean;
  18. };
  19. /**
  20. * Used to expand results.
  21. *
  22. * Our collapsible component was not used because we want our
  23. * expand button to be outside the list of children
  24. *
  25. */
  26. function CollapsePanel({
  27. items,
  28. children,
  29. buttonTitle,
  30. collapseCount = COLLAPSE_COUNT,
  31. disableBorder = true,
  32. }: Props) {
  33. const [isExpanded, setIsExpanded] = useState(false);
  34. function expandResults() {
  35. setIsExpanded(true);
  36. }
  37. return children({
  38. isExpanded,
  39. showMoreButton:
  40. isExpanded || items <= collapseCount ? null : (
  41. <ShowMoreButton
  42. items={items}
  43. buttonTitle={buttonTitle}
  44. collapseCount={collapseCount}
  45. disableBorder={disableBorder}
  46. onClick={expandResults}
  47. />
  48. ),
  49. });
  50. }
  51. type ShowMoreButtonProps = {
  52. items: number;
  53. onClick: () => void;
  54. buttonTitle?: string;
  55. collapseCount?: number;
  56. disableBorder?: boolean;
  57. };
  58. function ShowMoreButton({
  59. items,
  60. buttonTitle = 'More',
  61. collapseCount = COLLAPSE_COUNT,
  62. disableBorder = true,
  63. onClick,
  64. }: ShowMoreButtonProps) {
  65. return (
  66. <ShowMore
  67. onClick={onClick}
  68. role="button"
  69. data-test-id="collapse-show-more"
  70. disableBorder={disableBorder}
  71. >
  72. <ShowMoreText>
  73. <StyledIconList color="gray300" />
  74. {tct('Show [count] [buttonTitle]', {count: items - collapseCount, buttonTitle})}
  75. </ShowMoreText>
  76. <IconChevron color="gray300" direction="down" />
  77. </ShowMore>
  78. );
  79. }
  80. export default CollapsePanel;
  81. const ShowMore = styled('div')<{disableBorder: boolean}>`
  82. display: flex;
  83. align-items: center;
  84. padding: ${space(1)} ${space(2)};
  85. font-size: ${p => p.theme.fontSizeMedium};
  86. color: ${p => p.theme.subText};
  87. cursor: pointer;
  88. border-top: 1px solid ${p => p.theme.border};
  89. ${p =>
  90. !p.disableBorder &&
  91. css`
  92. border-left: 1px solid ${p.theme.border};
  93. border-right: 1px solid ${p.theme.border};
  94. border-bottom: 1px solid ${p.theme.border};
  95. border-bottom-left-radius: ${p.theme.borderRadius};
  96. border-bottom-right-radius: ${p.theme.borderRadius};
  97. margin-bottom: ${space(2)};
  98. `}
  99. `;
  100. const StyledIconList = styled(IconList)`
  101. margin-right: ${space(1)};
  102. `;
  103. const ShowMoreText = styled('div')`
  104. display: flex;
  105. align-items: center;
  106. flex-grow: 1;
  107. `;