collapsePanel.tsx 2.7 KB

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