Select.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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">{props.children}</CustomScrollbar>
  58. </components.MenuList>
  59. );
  60. };
  61. export class Select extends PureComponent<CommonProps & SelectProps> {
  62. static defaultProps = {
  63. width: null,
  64. className: '',
  65. isDisabled: false,
  66. isSearchable: true,
  67. isClearable: false,
  68. isMulti: false,
  69. openMenuOnFocus: false,
  70. autoFocus: false,
  71. isLoading: false,
  72. backspaceRemovesValue: true,
  73. maxMenuHeight: 300,
  74. };
  75. render() {
  76. const {
  77. defaultValue,
  78. getOptionLabel,
  79. getOptionValue,
  80. onChange,
  81. options,
  82. placeholder,
  83. width,
  84. value,
  85. className,
  86. isDisabled,
  87. isLoading,
  88. isSearchable,
  89. isClearable,
  90. backspaceRemovesValue,
  91. isMulti,
  92. autoFocus,
  93. openMenuOnFocus,
  94. onBlur,
  95. maxMenuHeight,
  96. noOptionsMessage,
  97. } = this.props;
  98. let widthClass = '';
  99. if (width) {
  100. widthClass = 'width-' + width;
  101. }
  102. const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
  103. return (
  104. <ReactSelect
  105. classNamePrefix="gf-form-select-box"
  106. className={selectClassNames}
  107. components={{
  108. Option: SelectOption,
  109. SingleValue,
  110. IndicatorsContainer,
  111. MenuList,
  112. Group: SelectOptionGroup,
  113. }}
  114. defaultValue={defaultValue}
  115. value={value}
  116. getOptionLabel={getOptionLabel}
  117. getOptionValue={getOptionValue}
  118. menuShouldScrollIntoView={false}
  119. isSearchable={isSearchable}
  120. onChange={onChange}
  121. options={options}
  122. placeholder={placeholder || 'Choose'}
  123. styles={resetSelectStyles()}
  124. isDisabled={isDisabled}
  125. isLoading={isLoading}
  126. isClearable={isClearable}
  127. autoFocus={autoFocus}
  128. onBlur={onBlur}
  129. openMenuOnFocus={openMenuOnFocus}
  130. maxMenuHeight={maxMenuHeight}
  131. noOptionsMessage={noOptionsMessage}
  132. isMulti={isMulti}
  133. backspaceRemovesValue={backspaceRemovesValue}
  134. />
  135. );
  136. }
  137. }
  138. export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
  139. static defaultProps = {
  140. width: null,
  141. className: '',
  142. components: {},
  143. loadingMessage: () => 'Loading...',
  144. isDisabled: false,
  145. isClearable: false,
  146. isMulti: false,
  147. isSearchable: true,
  148. backspaceRemovesValue: true,
  149. autoFocus: false,
  150. openMenuOnFocus: false,
  151. maxMenuHeight: 300,
  152. };
  153. render() {
  154. const {
  155. defaultValue,
  156. getOptionLabel,
  157. getOptionValue,
  158. onChange,
  159. placeholder,
  160. width,
  161. value,
  162. className,
  163. loadOptions,
  164. defaultOptions,
  165. isLoading,
  166. loadingMessage,
  167. noOptionsMessage,
  168. isDisabled,
  169. isSearchable,
  170. isClearable,
  171. backspaceRemovesValue,
  172. autoFocus,
  173. onBlur,
  174. openMenuOnFocus,
  175. maxMenuHeight,
  176. isMulti,
  177. } = this.props;
  178. let widthClass = '';
  179. if (width) {
  180. widthClass = 'width-' + width;
  181. }
  182. const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
  183. return (
  184. <ReactAsyncSelect
  185. classNamePrefix="gf-form-select-box"
  186. className={selectClassNames}
  187. components={{
  188. Option: SelectOption,
  189. SingleValue,
  190. IndicatorsContainer,
  191. NoOptionsMessage,
  192. }}
  193. defaultValue={defaultValue}
  194. value={value}
  195. getOptionLabel={getOptionLabel}
  196. getOptionValue={getOptionValue}
  197. menuShouldScrollIntoView={false}
  198. onChange={onChange}
  199. loadOptions={loadOptions}
  200. isLoading={isLoading}
  201. defaultOptions={defaultOptions}
  202. placeholder={placeholder || 'Choose'}
  203. styles={resetSelectStyles()}
  204. loadingMessage={loadingMessage}
  205. noOptionsMessage={noOptionsMessage}
  206. isDisabled={isDisabled}
  207. isSearchable={isSearchable}
  208. isClearable={isClearable}
  209. autoFocus={autoFocus}
  210. onBlur={onBlur}
  211. openMenuOnFocus={openMenuOnFocus}
  212. maxMenuHeight={maxMenuHeight}
  213. isMulti={isMulti}
  214. backspaceRemovesValue={backspaceRemovesValue}
  215. />
  216. );
  217. }
  218. }
  219. export default Select;