index.tsx 3.0 KB

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