1 | import React from 'react';
|
2 | import {render} from 'react-dom';
|
3 | import {connect} from 'react-redux';
|
4 | import {createStore} from 'redux';
|
5 | import actions from './actions';
|
6 | import {reducers} from './reducers';
|
7 |
|
8 |
|
9 | const NoItems = () => {
|
10 |
|
11 | return (
|
12 | <div
|
13 | key={null}
|
14 | className="item item-no-results"
|
15 | >No results found</div>
|
16 | );
|
17 | };
|
18 |
|
19 | const Presentation = ({...props}) => {
|
20 | let topBar;
|
21 | const visibleItems = Object.keys(props.visibleItems).map((item) => {
|
22 | return (
|
23 | <div
|
24 | onClick={() => {
|
25 | props.submit({
|
26 | selected: item,
|
27 | selectedItemLabel: props.items[item]
|
28 | });
|
29 | focus();
|
30 | }}
|
31 | key={item}
|
32 | className={
|
33 | (item == props.currentlyHighlighted) ? 'item item-selected' : 'item'
|
34 | }
|
35 | >
|
36 | {props.items[item]}
|
37 | </div>
|
38 | )
|
39 |
|
40 | });
|
41 | const focus = () => {
|
42 | if (topBar)
|
43 | topBar.focus();
|
44 | };
|
45 | return (
|
46 | <div
|
47 | className="select-react-redux-container"
|
48 | ref={(input) => {
|
49 | if (props.initialRender && input) {
|
50 | props.initialRenderFalse();
|
51 | document.addEventListener('click', function (event) {
|
52 | if (!input.contains(event.target)) {
|
53 | props.refresh();
|
54 | }
|
55 | });
|
56 |
|
57 | }
|
58 |
|
59 | }}>
|
60 | <a href="#"
|
61 | tabIndex={props.tabIndex}
|
62 | onClick={props.topBarOnClick}
|
63 | onKeyPress={props.linkOnKeyPress}
|
64 | autoFocus
|
65 | onKeyDown={e => {
|
66 | if (e.key.indexOf('Arrow') == 0) {
|
67 | props.linkOnKeyPress(e)
|
68 | }
|
69 | }}
|
70 | className={props.open ? 'selected selected-open' : 'selected'}
|
71 | ref={function (input) {
|
72 | if (input && props.open) {
|
73 | topBar = input;
|
74 | focus();
|
75 | }
|
76 | }}
|
77 | >
|
78 | <div
|
79 | className={Object.keys(props.items).length == 0 ? 'top-bar top-bar-empty' : 'top-bar'}>
|
80 | { Object.keys(props.items).length == 0 ? 'No options available' :
|
81 | props.selectedItemLabel
|
82 | ? props.selectedItemLabel
|
83 | : 'Please select...'}
|
84 | </div>
|
85 | </a>
|
86 |
|
87 | <div className={props.open ? 'results-container open' : 'results-container' }>
|
88 | <div className="input-container">
|
89 | <input
|
90 | type="text"
|
91 | autoCorrect="off"
|
92 | autoCapitalize="off"
|
93 | spellCheck="false"
|
94 | autoComplete="off"
|
95 | ref={(item) => {
|
96 | if (item && props.open) {
|
97 | item.focus()
|
98 | }
|
99 | }}
|
100 | value={props.visibilityFilter}
|
101 | onKeyPress={(e) => {
|
102 | if (e.key === 'Enter' && props.open) {
|
103 | props.submit({
|
104 | selected: props.currentlyHighlighted,
|
105 | selectedItemLabel: props.items[props.currentlyHighlighted]
|
106 | });
|
107 | focus();
|
108 | }
|
109 | }}
|
110 | onChange={props.inputOnChange}
|
111 | onKeyDown={(e) => {
|
112 | props.inputOnKeyDown(e);
|
113 | if (e.key == 'Escape') {
|
114 | focus();
|
115 | }
|
116 | }}
|
117 | />
|
118 | </div>
|
119 | {visibleItems.length > 0 ? visibleItems : <NoItems/>}
|
120 | </div>
|
121 | </div>
|
122 | );
|
123 | };
|
124 |
|
125 | const Stateless = ({items, selected = null, tabIndex = null, onChange}) => {
|
126 |
|
127 | const store = createStore(reducers);
|
128 |
|
129 | store.dispatch({type: '@@redux/INIT'});
|
130 |
|
131 | window.store = store;
|
132 |
|
133 | store.dispatch({type: actions.SET_ITEMS, payload: items});
|
134 |
|
135 | if (selected) {
|
136 | store.dispatch({
|
137 | type: actions.SET_SELECTED, payload: {
|
138 | selected: selected,
|
139 | selectedItemLabel: items[selected]
|
140 | }
|
141 | });
|
142 | }
|
143 |
|
144 | if (tabIndex) {
|
145 | store.dispatch({type: actions.SET_TABINDEX, payload: tabIndex})
|
146 | }
|
147 |
|
148 | const mapStateToProps = (state = {}) => {
|
149 | return state;
|
150 | };
|
151 |
|
152 | const mapDispatchToProps = (dispatch) => {
|
153 | return {
|
154 | submit: (item) => {
|
155 | if (item.selected) {
|
156 | dispatch({type: actions.SET_SELECTED, payload: item});
|
157 | dispatch({type: actions.SET_OPEN, payload: false});
|
158 | dispatch({type: actions.SET_FILTER, payload: ''});
|
159 | onChange(item.selected);
|
160 | }
|
161 | },
|
162 | linkOnKeyPress: (e) => {
|
163 | if (e.key != 'Escape') {
|
164 | dispatch({type: actions.SET_OPEN, payload: true});
|
165 | dispatch({type: actions.SET_FILTER, payload: ''});
|
166 | }
|
167 | },
|
168 |
|
169 | inputOnChange: (e) => {
|
170 | dispatch({type: actions.SET_FILTER, payload: e.target.value})
|
171 | },
|
172 | inputOnKeyDown: (e) => {
|
173 | if (e.key === 'ArrowDown') {
|
174 | dispatch({type: actions.SET_NEXT_HIGHLIGHTED, payload: false})
|
175 | }
|
176 |
|
177 | if (e.key === 'ArrowUp') {
|
178 | dispatch({type: actions.SET_PREV_HIGHLIGHTED, payload: false})
|
179 | }
|
180 |
|
181 | if (e.key === 'Escape') {
|
182 | dispatch({type: actions.SET_OPEN, payload: false});
|
183 | dispatch({type: actions.SET_FILTER, payload: ''});
|
184 | }
|
185 | },
|
186 | topBarOnClick: () => {
|
187 | dispatch({type: actions.TOGGLE_OPEN});
|
188 | },
|
189 |
|
190 | initialRenderFalse: () => {
|
191 | dispatch({type: actions.SET_INITIAL_RENDER_FALSE});
|
192 | },
|
193 | refresh: () => {
|
194 | dispatch({type: actions.SET_OPEN, payload: false});
|
195 | dispatch({type: actions.SET_FILTER, payload: ''});
|
196 | }
|
197 | }
|
198 | };
|
199 |
|
200 | const SelectWithStore = connect(
|
201 | mapStateToProps,
|
202 | mapDispatchToProps
|
203 | )(Presentation);
|
204 |
|
205 | return (
|
206 | <SelectWithStore store={store}/>
|
207 | )
|
208 | };
|
209 |
|
210 |
|
211 | export class Select extends React.Component {
|
212 | constructor(props) {
|
213 | super(props);
|
214 | }
|
215 |
|
216 |
|
217 | shouldComponentUpdate() {
|
218 | console.log('should component update');
|
219 | return true;
|
220 | }
|
221 |
|
222 | componentWillReceiveProps(nextProps) {
|
223 | console.log('fdf');
|
224 | console.log(nextProps);
|
225 | }
|
226 |
|
227 | render() {
|
228 | return (
|
229 | <Stateless {...this.props} />
|
230 | )
|
231 | }
|
232 | } |
\ | No newline at end of file |