Select.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Libraries
  2. import classNames from 'classnames';
  3. import React, { PureComponent } from 'react';
  4. // Ignoring because I couldn't get @types/react-select work wih Torkel's fork
  5. // @ts-ignore
  6. import { default as ReactSelect } from '@torkelo/react-select';
  7. // @ts-ignore
  8. import { default as ReactAsyncSelect } from '@torkelo/react-select/lib/Async';
  9. // @ts-ignore
  10. import { components } from '@torkelo/react-select';
  11. // Components
  12. import { SelectOption, SingleValue } from './SelectOption';
  13. import SelectOptionGroup from './SelectOptionGroup';
  14. import IndicatorsContainer from './IndicatorsContainer';
  15. import NoOptionsMessage from './NoOptionsMessage';
  16. import resetSelectStyles from './resetSelectStyles';
  17. import { CustomScrollbar } from '..';
  18. export interface SelectOptionItem {
  19. label?: string;
  20. value?: any;
  21. imgUrl?: string;
  22. description?: string;
  23. [key: string]: any;
  24. }
  25. interface CommonProps {
  26. defaultValue?: any;
  27. getOptionLabel?: (item: SelectOptionItem) => string;
  28. getOptionValue?: (item: SelectOptionItem) => string;
  29. onChange: (item: SelectOptionItem) => {} | void;
  30. placeholder?: string;
  31. width?: number;
  32. value?: SelectOptionItem;
  33. className?: string;
  34. isDisabled?: boolean;
  35. isSearchable?: boolean;
  36. isClearable?: boolean;
  37. autoFocus?: boolean;
  38. openMenuOnFocus?: boolean;
  39. onBlur?: () => void;
  40. maxMenuHeight?: number;
  41. isLoading: boolean;
  42. noOptionsMessage?: () => string;
  43. isMulti?: boolean;
  44. backspaceRemovesValue: boolean;
  45. }
  46. interface SelectProps {
  47. options: SelectOptionItem[];
  48. }
  49. interface AsyncProps {
  50. defaultOptions: boolean;
  51. loadOptions: (query: string) => Promise<SelectOptionItem[]>;
  52. loadingMessage?: () => string;
  53. }
  54. export const MenuList = (props: any) => {
  55. return (
  56. <components.MenuList {...props}>
  57. <CustomScrollbar autoHide={false} autoHeightMax="inherit">
  58. {props.children}
  59. </CustomScrollbar>
  60. </components.MenuList>
  61. );
  62. };
  63. export class Select extends PureComponent<CommonProps & SelectProps> {
  64. static defaultProps = {
  65. width: null,
  66. className: '',
  67. isDisabled: false,
  68. isSearchable: true,
  69. isClearable: false,
  70. isMulti: false,
  71. openMenuOnFocus: false,
  72. autoFocus: false,
  73. isLoading: false,
  74. backspaceRemovesValue: true,
  75. maxMenuHeight: 300,
  76. };
  77. render() {
  78. const {
  79. defaultValue,
  80. getOptionLabel,
  81. getOptionValue,
  82. onChange,
  83. options,
  84. placeholder,
  85. width,
  86. value,
  87. className,
  88. isDisabled,
  89. isLoading,
  90. isSearchable,
  91. isClearable,
  92. backspaceRemovesValue,
  93. isMulti,
  94. autoFocus,
  95. openMenuOnFocus,
  96. onBlur,
  97. maxMenuHeight,
  98. noOptionsMessage,
  99. } = this.props;
  100. let widthClass = '';
  101. if (width) {
  102. widthClass = 'width-' + width;
  103. }
  104. const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
  105. return (
  106. <ReactSelect
  107. classNamePrefix="gf-form-select-box"
  108. className={selectClassNames}
  109. components={{
  110. Option: SelectOption,
  111. SingleValue,
  112. IndicatorsContainer,
  113. MenuList,
  114. Group: SelectOptionGroup,
  115. }}
  116. defaultValue={defaultValue}
  117. value={value}
  118. getOptionLabel={getOptionLabel}
  119. getOptionValue={getOptionValue}
  120. menuShouldScrollIntoView={false}
  121. isSearchable={isSearchable}
  122. onChange={onChange}
  123. options={options}
  124. placeholder={placeholder || 'Choose'}
  125. styles={resetSelectStyles()}
  126. isDisabled={isDisabled}
  127. isLoading={isLoading}
  128. isClearable={isClearable}
  129. autoFocus={autoFocus}
  130. onBlur={onBlur}
  131. openMenuOnFocus={openMenuOnFocus}
  132. maxMenuHeight={maxMenuHeight}
  133. noOptionsMessage={noOptionsMessage}
  134. isMulti={isMulti}
  135. backspaceRemovesValue={backspaceRemovesValue}
  136. />
  137. );
  138. }
  139. }
  140. export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
  141. static defaultProps = {
  142. width: null,
  143. className: '',
  144. components: {},
  145. loadingMessage: () => 'Loading...',
  146. isDisabled: false,
  147. isClearable: false,
  148. isMulti: false,
  149. isSearchable: true,
  150. backspaceRemovesValue: true,
  151. autoFocus: false,
  152. openMenuOnFocus: false,
  153. maxMenuHeight: 300,
  154. };
  155. render() {
  156. const {
  157. defaultValue,
  158. getOptionLabel,
  159. getOptionValue,
  160. onChange,
  161. placeholder,
  162. width,
  163. value,
  164. className,
  165. loadOptions,
  166. defaultOptions,
  167. isLoading,
  168. loadingMessage,
  169. noOptionsMessage,
  170. isDisabled,
  171. isSearchable,
  172. isClearable,
  173. backspaceRemovesValue,
  174. autoFocus,
  175. onBlur,
  176. openMenuOnFocus,
  177. maxMenuHeight,
  178. isMulti,
  179. } = this.props;
  180. let widthClass = '';
  181. if (width) {
  182. widthClass = 'width-' + width;
  183. }
  184. const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
  185. return (
  186. <ReactAsyncSelect
  187. classNamePrefix="gf-form-select-box"
  188. className={selectClassNames}
  189. components={{
  190. Option: SelectOption,
  191. SingleValue,
  192. IndicatorsContainer,
  193. NoOptionsMessage,
  194. }}
  195. defaultValue={defaultValue}
  196. value={value}
  197. getOptionLabel={getOptionLabel}
  198. getOptionValue={getOptionValue}
  199. menuShouldScrollIntoView={false}
  200. onChange={onChange}
  201. loadOptions={loadOptions}
  202. isLoading={isLoading}
  203. defaultOptions={defaultOptions}
  204. placeholder={placeholder || 'Choose'}
  205. styles={resetSelectStyles()}
  206. loadingMessage={loadingMessage}
  207. noOptionsMessage={noOptionsMessage}
  208. isDisabled={isDisabled}
  209. isSearchable={isSearchable}
  210. isClearable={isClearable}
  211. autoFocus={autoFocus}
  212. onBlur={onBlur}
  213. openMenuOnFocus={openMenuOnFocus}
  214. maxMenuHeight={maxMenuHeight}
  215. isMulti={isMulti}
  216. backspaceRemovesValue={backspaceRemovesValue}
  217. />
  218. );
  219. }
  220. }
  221. export default Select;