Dropdown.tsx 3.5 KB

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