index.tsx 3.0 KB

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