Next.js template
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SelectField.js 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { ErrorMessage, useField } from 'formik';
  2. import PropTypes from 'prop-types';
  3. import React, { useEffect } from 'react';
  4. import Select, { components, createFilter } from 'react-select';
  5. import { ReactComponent as FilledChevronDown } from '../../../assets/images/svg/filled-chevron-down.svg';
  6. const SelectField = ({
  7. label,
  8. disabled,
  9. options,
  10. link,
  11. defaultSelected = null,
  12. dropdownFullHeight,
  13. selectOption,
  14. ...props
  15. }) => {
  16. const [field, meta, helpers] = useField(props);
  17. const filterConfig = {
  18. ignoreCase: true,
  19. ignoreAccents: true,
  20. trim: true,
  21. matchFrom: 'start',
  22. };
  23. useEffect(() => {
  24. if (defaultSelected) {
  25. helpers.setValue(defaultSelected);
  26. }
  27. }, [defaultSelected]); // eslint-disable-line
  28. const DropdownIndicator = (props) =>
  29. components.DropdownIndicator && (
  30. <components.DropdownIndicator {...props}>
  31. <FilledChevronDown />
  32. </components.DropdownIndicator>
  33. );
  34. function styles() {
  35. let style = 'c-input';
  36. if (meta.error && meta.touched) {
  37. style += ` c-input--error`;
  38. }
  39. if (dropdownFullHeight) {
  40. style += ` c-input--dropdown-full-height`;
  41. }
  42. return style;
  43. }
  44. return (
  45. <div className={styles()}>
  46. {!!label && (
  47. <label className="c-input__label" htmlFor={field.name}>
  48. {label}
  49. </label>
  50. )}
  51. {!!link && <div className="c-input__link">{link}</div>}
  52. <Select
  53. defaultValue={defaultSelected || options[0]}
  54. components={{ DropdownIndicator }}
  55. isSearchable={false}
  56. classNamePrefix="c-select"
  57. options={options}
  58. isDisabled={disabled}
  59. {...field}
  60. {...props}
  61. onBlur={(e) => {
  62. helpers.setTouched(true);
  63. field.onBlur(e);
  64. }}
  65. onChange={(selectedOption) => {
  66. helpers.setValue(selectedOption);
  67. if (props.onChange) {
  68. props.onChange();
  69. }
  70. if (selectOption) {
  71. selectOption(selectedOption);
  72. }
  73. }}
  74. filterOption={createFilter(filterConfig)}
  75. />
  76. <ErrorMessage name={field.name}>
  77. {(errorMessage) => {
  78. if (typeof errorMessage === 'string') {
  79. return <span className="c-input__error">{errorMessage}</span>;
  80. }
  81. return <span className="c-input__error">{errorMessage.value}</span>;
  82. }}
  83. </ErrorMessage>
  84. </div>
  85. );
  86. };
  87. SelectField.propTypes = {
  88. field: PropTypes.shape({
  89. name: PropTypes.string,
  90. }),
  91. form: PropTypes.shape({}),
  92. label: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({})]),
  93. disabled: PropTypes.bool,
  94. options: PropTypes.arrayOf(
  95. PropTypes.shape({
  96. label: PropTypes.string,
  97. value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  98. })
  99. ),
  100. onChange: PropTypes.func,
  101. link: PropTypes.node,
  102. defaultSelected: PropTypes.shape({
  103. label: PropTypes.string,
  104. value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  105. }),
  106. dropdownFullHeight: PropTypes.bool,
  107. selectOption: PropTypes.func,
  108. };
  109. export default SelectField;