]>
Commit | Line | Data |
---|---|---|
3ab3a128 | 1 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | |
02de449a | 3 | import ReactDom from 'react-dom'; |
4 | import classnames from 'classnames'; | |
5 | ||
6 | const scrollTo = (element, to, duration) => { | |
0b9ef41f | 7 | const requestAnimationFrame = window.requestAnimationFrame || |
8 | function requestAnimationFrameTimeout() { | |
9 | return setTimeout(arguments[0], 10); | |
10 | }; | |
02de449a | 11 | // jump to target if duration zero |
12 | if (duration <= 0) { | |
13 | element.scrollTop = to; | |
14 | return; | |
15 | } | |
16 | const difference = to - element.scrollTop; | |
17 | const perTick = difference / duration * 10; | |
18 | ||
0b9ef41f | 19 | requestAnimationFrame(() => { |
02de449a | 20 | element.scrollTop = element.scrollTop + perTick; |
21 | if (element.scrollTop === to) return; | |
22 | scrollTo(element, to, duration - 10); | |
0b9ef41f | 23 | }); |
02de449a | 24 | }; |
25 | ||
3ab3a128 | 26 | class Select extends Component { |
27 | static propTypes = { | |
02de449a | 28 | prefixCls: PropTypes.string, |
29 | options: PropTypes.array, | |
30 | selectedIndex: PropTypes.number, | |
31 | type: PropTypes.string, | |
32 | onSelect: PropTypes.func, | |
182e9fcc | 33 | onMouseEnter: PropTypes.func, |
3ab3a128 | 34 | }; |
02de449a | 35 | |
3ab3a128 | 36 | state = { |
37 | active: false, | |
38 | }; | |
d093074a | 39 | |
02de449a | 40 | componentDidMount() { |
41 | // jump to selected option | |
42 | this.scrollToSelected(0); | |
3ab3a128 | 43 | } |
02de449a | 44 | |
1cd769a6 | 45 | componentDidUpdate(prevProps) { |
02de449a | 46 | // smooth scroll to selected option |
1cd769a6 | 47 | if (prevProps.selectedIndex !== this.props.selectedIndex) { |
48 | this.scrollToSelected(120); | |
49 | } | |
3ab3a128 | 50 | } |
02de449a | 51 | |
3ab3a128 | 52 | onSelect = (value) => { |
02de449a | 53 | const { onSelect, type } = this.props; |
02de449a | 54 | onSelect(type, value); |
3ab3a128 | 55 | } |
02de449a | 56 | |
57 | getOptions() { | |
8133e8cf | 58 | const { options, selectedIndex, prefixCls } = this.props; |
02de449a | 59 | return options.map((item, index) => { |
8133e8cf | 60 | const cls = classnames({ |
518b852e M |
61 | [`${prefixCls}-select-option-selected`]: selectedIndex === index, |
62 | [`${prefixCls}-select-option-disabled`]: item.disabled, | |
8133e8cf | 63 | }); |
518b852e M |
64 | let onclick = null; |
65 | if (!item.disabled) { | |
95699887 | 66 | onclick = this.onSelect.bind(this, item.value); |
518b852e | 67 | } |
4984ed85 | 68 | return (<li |
69 | className={cls} | |
70 | key={index} | |
71 | onClick={onclick} | |
72 | disabled={item.disabled} | |
73 | > | |
74 | {item.value} | |
75 | </li>); | |
02de449a | 76 | }); |
3ab3a128 | 77 | } |
02de449a | 78 | |
79 | scrollToSelected(duration) { | |
80 | // move to selected item | |
81 | const select = ReactDom.findDOMNode(this); | |
ed31dbba | 82 | const list = ReactDom.findDOMNode(this.list); |
cb5a445c | 83 | if (!list) { |
84 | return; | |
85 | } | |
5fcf22e0 | 86 | let index = this.props.selectedIndex; |
02de449a | 87 | if (index < 0) { |
88 | index = 0; | |
89 | } | |
90 | const topOption = list.children[index]; | |
428cfa8d | 91 | const to = topOption.offsetTop; |
85d09ad3 | 92 | scrollTo(select, to, duration); |
3ab3a128 | 93 | } |
02de449a | 94 | |
3ab3a128 | 95 | handleMouseEnter = (e) => { |
d093074a | 96 | this.setState({ active: true }); |
97 | this.props.onMouseEnter(e); | |
3ab3a128 | 98 | } |
d093074a | 99 | |
3ab3a128 | 100 | handleMouseLeave = () => { |
d093074a | 101 | this.setState({ active: false }); |
3ab3a128 | 102 | } |
d093074a | 103 | |
ed31dbba WZ |
104 | saveList = (node) => { |
105 | this.list = node; | |
106 | } | |
107 | ||
02de449a | 108 | render() { |
109 | if (this.props.options.length === 0) { | |
110 | return null; | |
111 | } | |
112 | ||
113 | const { prefixCls } = this.props; | |
d093074a | 114 | const cls = classnames({ |
115 | [`${prefixCls}-select`]: 1, | |
116 | [`${prefixCls}-select-active`]: this.state.active, | |
117 | }); | |
02de449a | 118 | |
119 | return ( | |
4984ed85 | 120 | <div |
d093074a | 121 | className={cls} |
122 | onMouseEnter={this.handleMouseEnter} | |
123 | onMouseLeave={this.handleMouseLeave} | |
4984ed85 | 124 | > |
ed31dbba | 125 | <ul ref={this.saveList}>{this.getOptions()}</ul> |
02de449a | 126 | </div> |
127 | ); | |
3ab3a128 | 128 | } |
129 | } | |
02de449a | 130 | |
131 | export default Select; |