diff options
author | 崖鹰 <zhao.wuz@alipay.com> | 2015-11-13 11:33:48 +0800 |
---|---|---|
committer | 崖鹰 <zhao.wuz@alipay.com> | 2015-11-13 11:33:48 +0800 |
commit | 02de449a0474765a4796fa607e7e3922252f574f (patch) | |
tree | dc37faf2f610343112ea1fc3707ad188092bd031 /src/Picker.jsx | |
parent | 1f336fabc9135ac971e53d9c2ae407db69b8f096 (diff) | |
download | time-picker-02de449a0474765a4796fa607e7e3922252f574f.tar.gz time-picker-02de449a0474765a4796fa607e7e3922252f574f.tar.zst time-picker-02de449a0474765a4796fa607e7e3922252f574f.zip |
release 0.1.0
Diffstat (limited to 'src/Picker.jsx')
-rw-r--r-- | src/Picker.jsx | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/Picker.jsx b/src/Picker.jsx new file mode 100644 index 0000000..f15434a --- /dev/null +++ b/src/Picker.jsx | |||
@@ -0,0 +1,158 @@ | |||
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 | componentWillMount() { | ||
51 | document.addEventListener('click', this.handleDocumentClick, false); | ||
52 | }, | ||
53 | |||
54 | componentWillReceiveProps(nextProps) { | ||
55 | const { value, open } = nextProps; | ||
56 | if (value !== undefined) { | ||
57 | this.setState({value}); | ||
58 | } | ||
59 | if (open !== undefined) { | ||
60 | this.setState({open}); | ||
61 | } | ||
62 | }, | ||
63 | |||
64 | componentWillUnmount() { | ||
65 | document.removeEventListener('click', this.handleDocumentClick, false); | ||
66 | }, | ||
67 | |||
68 | onPanelChange(value) { | ||
69 | const props = this.props; | ||
70 | this.setState({ | ||
71 | value: value, | ||
72 | }); | ||
73 | props.onChange(value); | ||
74 | }, | ||
75 | |||
76 | onPanelClear() { | ||
77 | this.setOpen(false, this.focus); | ||
78 | }, | ||
79 | |||
80 | onVisibleChange(open) { | ||
81 | this.setOpen(open, () => { | ||
82 | if (open) { | ||
83 | ReactDOM.findDOMNode(this.panelInstance).focus(); | ||
84 | } | ||
85 | }); | ||
86 | }, | ||
87 | |||
88 | getPanelElement() { | ||
89 | const panel = this.props.panel; | ||
90 | const extraProps = { | ||
91 | ref: this.savePanelRef, | ||
92 | defaultValue: this.state.value || panel.props.defaultValue, | ||
93 | onChange: createChainedFunction(panel.props.onChange, this.onPanelChange), | ||
94 | onClear: createChainedFunction(panel.props.onClear, this.onPanelClear), | ||
95 | }; | ||
96 | |||
97 | return React.cloneElement(panel, extraProps); | ||
98 | }, | ||
99 | |||
100 | setOpen(open, callback) { | ||
101 | const {onOpen, onClose} = this.props; | ||
102 | if (this.state.open !== open) { | ||
103 | this.setState({ | ||
104 | open: open, | ||
105 | }, callback); | ||
106 | const event = { | ||
107 | open: open, | ||
108 | }; | ||
109 | if (open) { | ||
110 | onOpen(event); | ||
111 | } else { | ||
112 | onClose(event); | ||
113 | } | ||
114 | } | ||
115 | }, | ||
116 | |||
117 | handleDocumentClick(event) { | ||
118 | // hide popup when click outside | ||
119 | if (this.state.open && ReactDOM.findDOMNode(this.panelInstance).contains(event.target)) { | ||
120 | return; | ||
121 | } | ||
122 | this.setState({ | ||
123 | open: false, | ||
124 | }); | ||
125 | }, | ||
126 | |||
127 | focus() { | ||
128 | if (!this.state.open) { | ||
129 | ReactDOM.findDOMNode(this).focus(); | ||
130 | } | ||
131 | }, | ||
132 | |||
133 | render() { | ||
134 | const state = this.state; | ||
135 | const props = this.props; | ||
136 | const { prefixCls, placement, align, disabled, transitionName, children } = props; | ||
137 | return ( | ||
138 | <Trigger | ||
139 | prefixCls={prefixCls} | ||
140 | popup={this.getPanelElement()} | ||
141 | popupAlign={align} | ||
142 | builtinPlacements={placements} | ||
143 | popupPlacement={placement} | ||
144 | action={disabled ? [] : ['click']} | ||
145 | destroyPopupOnHide | ||
146 | popupTransitionName={transitionName} | ||
147 | popupVisible={state.open} | ||
148 | onPopupVisibleChange={this.onVisibleChange} | ||
149 | > | ||
150 | <span className={`${prefixCls}-picker`}> | ||
151 | {children(state, props)} | ||
152 | </span> | ||
153 | </Trigger> | ||
154 | ); | ||
155 | }, | ||
156 | }); | ||
157 | |||
158 | export default Picker; | ||