]>
Commit | Line | Data |
---|---|---|
1 | import React, {PropTypes} from 'react'; | |
2 | import ReactDOM from 'react-dom'; | |
3 | import Trigger from 'rc-trigger'; | |
4 | import {createChainedFunction} from 'rc-util'; | |
5 | import placements from './util/placements'; | |
6 | import CommonMixin from './mixin/CommonMixin'; | |
7 | ||
8 | function noop() { | |
9 | } | |
10 | ||
11 | function refFn(field, component) { | |
12 | this[field] = component; | |
13 | } | |
14 | ||
15 | const Picker = React.createClass({ | |
16 | propTypes: { | |
17 | prefixCls: PropTypes.string, | |
18 | panel: PropTypes.element, | |
19 | children: PropTypes.func, | |
20 | disabled: PropTypes.bool, | |
21 | value: PropTypes.object, | |
22 | open: PropTypes.bool, | |
23 | align: PropTypes.object, | |
24 | placement: PropTypes.any, | |
25 | transitionName: PropTypes.string, | |
26 | onChange: PropTypes.func, | |
27 | onOpen: PropTypes.func, | |
28 | onClose: PropTypes.func, | |
29 | }, | |
30 | ||
31 | mixins: [CommonMixin], | |
32 | ||
33 | getDefaultProps() { | |
34 | return { | |
35 | open: false, | |
36 | align: {}, | |
37 | placement: 'bottomLeft', | |
38 | onChange: noop, | |
39 | onOpen: noop, | |
40 | onClose: noop, | |
41 | }; | |
42 | }, | |
43 | ||
44 | getInitialState() { | |
45 | this.savePanelRef = refFn.bind(this, 'panelInstance'); | |
46 | const { open, value } = this.props; | |
47 | return { open, value }; | |
48 | }, | |
49 | ||
50 | componentWillReceiveProps(nextProps) { | |
51 | const { value, open } = nextProps; | |
52 | if (value !== undefined) { | |
53 | this.setState({value}); | |
54 | } | |
55 | if (open !== undefined) { | |
56 | this.setState({open}); | |
57 | } | |
58 | }, | |
59 | ||
60 | onPanelChange(value) { | |
61 | const props = this.props; | |
62 | this.setState({ | |
63 | value: value, | |
64 | }); | |
65 | props.onChange(value); | |
66 | }, | |
67 | ||
68 | onPanelClear() { | |
69 | this.setOpen(false, this.focus); | |
70 | }, | |
71 | ||
72 | onVisibleChange(open) { | |
73 | this.setOpen(open, () => { | |
74 | if (open) { | |
75 | ReactDOM.findDOMNode(this.panelInstance).focus(); | |
76 | } | |
77 | }); | |
78 | }, | |
79 | ||
80 | getPanelElement() { | |
81 | const panel = this.props.panel; | |
82 | const extraProps = { | |
83 | ref: this.savePanelRef, | |
84 | defaultValue: this.state.value || panel.props.defaultValue, | |
85 | onChange: createChainedFunction(panel.props.onChange, this.onPanelChange), | |
86 | onClear: createChainedFunction(panel.props.onClear, this.onPanelClear), | |
87 | }; | |
88 | ||
89 | return React.cloneElement(panel, extraProps); | |
90 | }, | |
91 | ||
92 | setOpen(open, callback) { | |
93 | const {onOpen, onClose} = this.props; | |
94 | if (this.state.open !== open) { | |
95 | this.setState({ | |
96 | open: open, | |
97 | }, callback); | |
98 | const event = { | |
99 | open: open, | |
100 | }; | |
101 | if (open) { | |
102 | onOpen(event); | |
103 | } else { | |
104 | onClose(event); | |
105 | } | |
106 | } | |
107 | }, | |
108 | ||
109 | focus() { | |
110 | if (!this.state.open) { | |
111 | ReactDOM.findDOMNode(this).focus(); | |
112 | } | |
113 | }, | |
114 | ||
115 | render() { | |
116 | const state = this.state; | |
117 | const props = this.props; | |
118 | const { prefixCls, placement, align, disabled, transitionName, children } = props; | |
119 | return ( | |
120 | <Trigger | |
121 | prefixCls={prefixCls} | |
122 | popup={this.getPanelElement()} | |
123 | popupAlign={align} | |
124 | builtinPlacements={placements} | |
125 | popupPlacement={placement} | |
126 | action={disabled ? [] : ['click']} | |
127 | destroyPopupOnHide | |
128 | popupTransitionName={transitionName} | |
129 | popupVisible={state.open} | |
130 | onPopupVisibleChange={this.onVisibleChange} | |
131 | > | |
132 | <span className={`${prefixCls}-picker`}> | |
133 | {children(state, props)} | |
134 | </span> | |
135 | </Trigger> | |
136 | ); | |
137 | }, | |
138 | }); | |
139 | ||
140 | export default Picker; |