Dropdown.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import React, { useState } from "react";
  2. import styled from "styled-components";
  3. type Option = {
  4. value: unknown;
  5. label: string;
  6. };
  7. type DropdownProps = {
  8. options: Array<Option>;
  9. selectedOption: Option;
  10. onSelect?: (selectedOption: Option) => unknown;
  11. selectLabel?: (currentLabel: string) => void;
  12. selectValue?: (currentValue: any) => void;
  13. };
  14. const Dropdown: React.FunctionComponent<DropdownProps> = ({
  15. options,
  16. selectedOption,
  17. selectLabel,
  18. selectValue,
  19. onSelect,
  20. }) => {
  21. const [isDropdownExpanded, setIsDropdownExpanded] = useState(false);
  22. const handleSelectOption = (option: Option) => {
  23. if (selectedOption.label === option.label) {
  24. return;
  25. }
  26. onSelect(option);
  27. typeof selectLabel === "function" && selectLabel(option.label);
  28. typeof selectValue === "function" && selectValue(option.value);
  29. };
  30. const renderDropdown = () => {
  31. if (isDropdownExpanded) {
  32. return (
  33. <>
  34. <DropdownOverlay onClick={() => setIsDropdownExpanded(false)} />
  35. <OptionWrapper
  36. dropdownWidth="230px"
  37. dropdownMaxHeight="200px"
  38. onClick={() => setIsDropdownExpanded(false)}
  39. >
  40. {renderOptionList()}
  41. </OptionWrapper>
  42. </>
  43. );
  44. }
  45. };
  46. const renderOptionList = () => {
  47. return options.map((option, i, originalArray) => {
  48. return (
  49. <Option
  50. key={i}
  51. selected={option.label === selectedOption.label}
  52. onClick={() => handleSelectOption(option)}
  53. lastItem={i === originalArray.length - 1}
  54. >
  55. {option.label}
  56. </Option>
  57. );
  58. });
  59. };
  60. return (
  61. <DropdownSelector
  62. onClick={() => setIsDropdownExpanded(!isDropdownExpanded)}
  63. >
  64. <DropdownLabel>{selectedOption?.label}</DropdownLabel>
  65. <i className="material-icons">arrow_drop_down</i>
  66. {renderDropdown()}
  67. </DropdownSelector>
  68. );
  69. };
  70. export default Dropdown;
  71. const DropdownSelector = styled.div`
  72. font-size: 13px;
  73. font-weight: 500;
  74. position: relative;
  75. color: #ffffff;
  76. display: flex;
  77. align-items: center;
  78. cursor: pointer;
  79. border-radius: 5px;
  80. :hover {
  81. > i {
  82. background: #ffffff22;
  83. }
  84. }
  85. > i {
  86. border-radius: 20px;
  87. font-size: 20px;
  88. margin-left: 10px;
  89. }
  90. `;
  91. const DropdownLabel = styled.div`
  92. white-space: nowrap;
  93. text-overflow: ellipsis;
  94. overflow: hidden;
  95. max-width: 200px;
  96. `;
  97. const DropdownOverlay = styled.div`
  98. position: fixed;
  99. width: 100%;
  100. height: 100%;
  101. z-index: 10;
  102. left: 0px;
  103. top: 0px;
  104. cursor: default;
  105. `;
  106. const OptionWrapper = styled.div`
  107. position: absolute;
  108. left: 0;
  109. top: calc(100% + 10px);
  110. background: #26282f;
  111. width: ${(props: { dropdownWidth: string; dropdownMaxHeight: string }) =>
  112. props.dropdownWidth};
  113. max-height: ${(props: { dropdownWidth: string; dropdownMaxHeight: string }) =>
  114. props.dropdownMaxHeight || "300px"};
  115. border-radius: 3px;
  116. z-index: 999;
  117. overflow-y: auto;
  118. margin-bottom: 20px;
  119. box-shadow: 0px 4px 10px 0px #00000088;
  120. `;
  121. const Option = styled.div`
  122. width: 100%;
  123. border-top: 1px solid #00000000;
  124. border-bottom: 1px solid
  125. ${(props: { selected: boolean; lastItem: boolean }) =>
  126. props.lastItem ? "#ffffff00" : "#ffffff15"};
  127. height: 37px;
  128. font-size: 13px;
  129. padding-top: 9px;
  130. align-items: center;
  131. padding-left: 15px;
  132. cursor: pointer;
  133. padding-right: 10px;
  134. white-space: nowrap;
  135. overflow: hidden;
  136. text-overflow: ellipsis;
  137. background: ${(props: { selected: boolean; lastItem: boolean }) =>
  138. props.selected ? "#ffffff11" : ""};
  139. :hover {
  140. background: #ffffff22;
  141. }
  142. `;