index.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import React, { useState, useEffect, useRef } from 'react';
  2. import { SelectOptionType } from '../../constants/type';
  3. import Icon from '../Icon';
  4. import Divider from '../Divider';
  5. import {
  6. Wrapper,
  7. Selected,
  8. Content,
  9. InputContent,
  10. OptionWrapper,
  11. Option,
  12. } from './styled';
  13. type Props = {
  14. onChange?: (item: SelectOptionType) => void;
  15. options: SelectOptionType[];
  16. defaultValue?: React.ReactNode;
  17. isDivide?: boolean;
  18. width?: string;
  19. useInput?: boolean;
  20. style?: {};
  21. };
  22. const SelectBox: React.FunctionComponent<Props> = ({
  23. onChange,
  24. options,
  25. defaultValue,
  26. isDivide = false,
  27. width = 'auto',
  28. useInput = false,
  29. style,
  30. }: Props) => {
  31. const selectRef = useRef<HTMLDivElement>(null);
  32. const optionRef = useRef<HTMLDivElement>(null);
  33. const [isCollapse, setCollapse] = useState(true);
  34. const [value, setValue] = useState(defaultValue);
  35. const handleClick = (): void => {
  36. setCollapse(!isCollapse);
  37. };
  38. const handleSelect = (index: number): void => {
  39. setValue(options[index].content);
  40. if (onChange) {
  41. onChange(options[index]);
  42. }
  43. };
  44. const handleBlur = (): void => {
  45. setCollapse(true);
  46. };
  47. const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
  48. setValue(e.target.value || 0);
  49. };
  50. const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {
  51. if (e.keyCode === 13 && onChange && value) {
  52. const param = {
  53. key: '',
  54. content: '',
  55. value: parseInt(value as string, 10),
  56. };
  57. onChange(param);
  58. setCollapse(true);
  59. }
  60. };
  61. useEffect(() => {
  62. if (defaultValue) {
  63. setValue(defaultValue);
  64. } else {
  65. setValue(options[0].content);
  66. }
  67. }, [defaultValue]);
  68. useEffect(() => {
  69. if (!isCollapse && selectRef.current) {
  70. const position = selectRef.current.getBoundingClientRect();
  71. if (optionRef.current) {
  72. optionRef.current.style.top = `${selectRef.current.clientHeight + position.top}px`;
  73. optionRef.current.style.left = `${position.left}px`;
  74. }
  75. }
  76. });
  77. return (
  78. <Wrapper width={width} style={style}>
  79. <Selected
  80. ref={selectRef}
  81. onMouseDown={handleClick}
  82. onBlur={handleBlur}
  83. tabIndex={0}
  84. data-testid="selected"
  85. >
  86. {
  87. useInput && (typeof value === 'string' || typeof value === 'number') ? (
  88. <InputContent
  89. value={value}
  90. onChange={handleChange}
  91. onKeyDown={handleKeyDown}
  92. />
  93. ) : (
  94. <Content>
  95. {value}
  96. </Content>
  97. )
  98. }
  99. {isDivide ? <Divider /> : null}
  100. <Icon glyph="down-arrow" />
  101. </Selected>
  102. {
  103. !isCollapse ? (
  104. <OptionWrapper ref={optionRef} data-testid="option-list">
  105. {
  106. options.map((option: SelectOptionType, index: number) => (
  107. <Option
  108. key={option.key}
  109. onMouseDown={(): void => { handleSelect(index); }}
  110. >
  111. {option.content}
  112. </Option>
  113. ))
  114. }
  115. </OptionWrapper>
  116. ) : null
  117. }
  118. </Wrapper>
  119. );
  120. };
  121. export default SelectBox;