react-ui-basics 0.0.180 → 0.0.182
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DNDContainer.d.ts +17 -0
- package/DNDContainer.js +237 -250
- package/DNDContainer.js.map +1 -1
- package/DNDDroppable.js +4 -2
- package/DNDDroppable.js.map +1 -1
- package/DatePicker.d.ts +4 -1
- package/DatePicker.js +24 -14
- package/DatePicker.js.map +1 -1
- package/ImageGallery.js +1 -1
- package/bundle.css +984 -984
- package/package.json +1 -1
- package/router/Route.js +1 -1
- package/src/DNDContainer.tsx +315 -0
- package/src/DNDDroppable.js +4 -2
- package/src/DatePicker.tsx +49 -34
- package/src/DNDContainer.js +0 -263
package/package.json
CHANGED
package/router/Route.js
CHANGED
|
@@ -6,7 +6,7 @@ import {extends as __extends} from "./../_virtual/_rollupPluginBabelHelpers";
|
|
|
6
6
|
import {inherits as __inherits} from "./../_virtual/_rollupPluginBabelHelpers";
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
|
-
import { setOf, allPropsExcept, isDifferent, addEventListener,
|
|
9
|
+
import { setOf, allPropsExcept, isDifferent, addEventListener, WINDOW, removeEventListener, orNoop } from '../Tools.js';
|
|
10
10
|
import { stateGSs, componentDidUpdate, render, componentDidMount, componentWillUnmount, propsGetter, setState, PureComponent } from '../ReactConstants.js';
|
|
11
11
|
|
|
12
12
|
var historyEvents = ['popstate', 'pushState', 'replaceState'];
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import React, {Component} from 'react';
|
|
2
|
+
import ReactCreateElement from './ReactCreateElement';
|
|
3
|
+
import './DNDContainer.css'
|
|
4
|
+
import {
|
|
5
|
+
classNames,
|
|
6
|
+
NOOP,
|
|
7
|
+
orNoop,
|
|
8
|
+
preventDefault,
|
|
9
|
+
DOCUMENT,
|
|
10
|
+
WINDOW,
|
|
11
|
+
addEventListener,
|
|
12
|
+
removeEventListener,
|
|
13
|
+
setTimeout,
|
|
14
|
+
clearTimeout,
|
|
15
|
+
requestAnimationFrame,
|
|
16
|
+
stopPropagation,
|
|
17
|
+
createRef,
|
|
18
|
+
UNDEFINED
|
|
19
|
+
} from "./Tools";
|
|
20
|
+
import {propsGetter, render, componentDidMount} from "./ReactConstants";
|
|
21
|
+
|
|
22
|
+
const clearSelection = () => {
|
|
23
|
+
const getSelection = WINDOW.getSelection;
|
|
24
|
+
if (getSelection) {
|
|
25
|
+
if (getSelection().empty) { // Chrome
|
|
26
|
+
getSelection().empty();
|
|
27
|
+
} else if (getSelection().removeAllRanges) { // Firefox
|
|
28
|
+
getSelection().removeAllRanges();
|
|
29
|
+
}
|
|
30
|
+
} else if (DOCUMENT.selection) { // IE?
|
|
31
|
+
DOCUMENT.selection.empty();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export interface DNDContainerProps {
|
|
36
|
+
provideDraggableInitializer: (f) => void,
|
|
37
|
+
provideDroppableInitializer: (f) => void,
|
|
38
|
+
className?: string,
|
|
39
|
+
children?
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface DNDContainerState {
|
|
43
|
+
draggable: any
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class DNDContainer extends Component<DNDContainerProps, DNDContainerState> {
|
|
47
|
+
|
|
48
|
+
constructor(properties) {
|
|
49
|
+
super(properties);
|
|
50
|
+
const that = this;
|
|
51
|
+
that.state = {
|
|
52
|
+
draggable: null,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const props = propsGetter(that);
|
|
56
|
+
const containerRef = createRef()
|
|
57
|
+
|
|
58
|
+
let draggable;
|
|
59
|
+
let data;
|
|
60
|
+
let scrollOffsetX;
|
|
61
|
+
let scrollOffsetY;
|
|
62
|
+
|
|
63
|
+
const droppables = [];
|
|
64
|
+
let positionListener: (e: MouseEvent) => void;
|
|
65
|
+
positionListener = NOOP
|
|
66
|
+
|
|
67
|
+
that[render] = () => {
|
|
68
|
+
const {children, className} = props();
|
|
69
|
+
const {draggable} = that.state;
|
|
70
|
+
return <div className={classNames('DNDContainer', className)} ref={containerRef}>
|
|
71
|
+
{children}
|
|
72
|
+
<div className="overlay">{draggable}</div>
|
|
73
|
+
</div>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
const onDrag = (e) => {
|
|
78
|
+
if (!draggable)
|
|
79
|
+
return;
|
|
80
|
+
|
|
81
|
+
positionListener(e);
|
|
82
|
+
// that[droppables].forEach(it => it.isHover(e, draggable))
|
|
83
|
+
};
|
|
84
|
+
const onDragStart = (e) => {
|
|
85
|
+
e.stopPropagation && stopPropagation(e)
|
|
86
|
+
droppables.forEach(it => it.onDragStart(e, draggable))
|
|
87
|
+
};
|
|
88
|
+
const onDragEnd = () => {
|
|
89
|
+
const d = draggable;
|
|
90
|
+
if (!d) return
|
|
91
|
+
|
|
92
|
+
if (d.element) {
|
|
93
|
+
let style = d.element.style;
|
|
94
|
+
style.position = '';
|
|
95
|
+
style.pointerEvents = '';
|
|
96
|
+
style.width = ``;
|
|
97
|
+
style.height = ``;
|
|
98
|
+
style.opacity = '';
|
|
99
|
+
}
|
|
100
|
+
d.setState({dragged: false});
|
|
101
|
+
|
|
102
|
+
that.setState({draggable: null});
|
|
103
|
+
|
|
104
|
+
droppables.forEach(it => {
|
|
105
|
+
it.onDragEnd();
|
|
106
|
+
orNoop(it.props.onDragEnd)(d)
|
|
107
|
+
});
|
|
108
|
+
data = null;
|
|
109
|
+
draggable = null;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const draggableInitializer = (item) => {
|
|
113
|
+
const handle = item.props.handle;
|
|
114
|
+
const draggableElement = (handle && item.element.childNodes[0]) || item.element;
|
|
115
|
+
draggableElement.draggable = true;
|
|
116
|
+
|
|
117
|
+
const dragStartListener = (e) => {
|
|
118
|
+
clearSelection();
|
|
119
|
+
const container = containerRef();
|
|
120
|
+
data = item.props.data;
|
|
121
|
+
draggable = item;
|
|
122
|
+
scrollOffsetX = e.pageX - e.clientX;
|
|
123
|
+
scrollOffsetY = e.pageY - e.clientY;
|
|
124
|
+
const dataTransfer = e.dataTransfer;
|
|
125
|
+
const itemOffset = item.element.getBoundingClientRect();
|
|
126
|
+
|
|
127
|
+
item.width = itemOffset.width;
|
|
128
|
+
item.height = itemOffset.height;
|
|
129
|
+
|
|
130
|
+
let clone = orNoop(item.props.copy)((it) => {
|
|
131
|
+
let style = it.element.style;
|
|
132
|
+
|
|
133
|
+
const offsetLeft = totalOffsetLeft(container) + (e.clientX - itemOffset.left);
|
|
134
|
+
const offsetTop = totalOffsetTop(container) + (e.clientY - itemOffset.top);
|
|
135
|
+
positionListener = (orNoop(it.createPositionListener)(e, style, itemOffset, container) || ((e) => {
|
|
136
|
+
if (e.pageX === 0)
|
|
137
|
+
return;
|
|
138
|
+
|
|
139
|
+
style.transform = 'translate(' + (e.pageX - offsetLeft) + 'px, ' + (e.pageY - offsetTop) + 'px)';
|
|
140
|
+
})) as (e: MouseEvent) => void;
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
requestAnimationFrame(() => {
|
|
144
|
+
if (dataTransfer && !dataTransfer.setDragImage) {
|
|
145
|
+
style.opacity = '0'; // hide dragged element in ie and edge
|
|
146
|
+
}
|
|
147
|
+
if (it.initDraggedStyles)
|
|
148
|
+
it.initDraggedStyles(style, itemOffset);
|
|
149
|
+
else {
|
|
150
|
+
style.position = 'absolute';
|
|
151
|
+
style.pointerEvents = 'none';
|
|
152
|
+
style.opacity = '1';
|
|
153
|
+
style.top = '0px';
|
|
154
|
+
style.left = '0px';
|
|
155
|
+
style.width = itemOffset.width + 'px';
|
|
156
|
+
style.height = itemOffset.height + 'px';
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
onDrag(e);
|
|
160
|
+
it.setState({dragged: true});
|
|
161
|
+
});
|
|
162
|
+
return it;
|
|
163
|
+
}, 'copy', item);
|
|
164
|
+
|
|
165
|
+
dataTransfer && dataTransfer.setData && dataTransfer.setData('text', ''); // required by firefox
|
|
166
|
+
dataTransfer && (dataTransfer.dropEffect = "move");
|
|
167
|
+
if (clone) {
|
|
168
|
+
if (dataTransfer && dataTransfer.setDragImage) {
|
|
169
|
+
clone !== item && that.setState({draggable: clone});
|
|
170
|
+
const img = document.createElement('img');
|
|
171
|
+
img.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
|
172
|
+
dataTransfer.setDragImage(img, 0, 0);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
onDragStart(e);
|
|
176
|
+
setTimeout(() => item.setState({placeholder: true}), 1)
|
|
177
|
+
};
|
|
178
|
+
addListener(draggableElement, item, 'dragend', (e) => {
|
|
179
|
+
if (item.state.placeholder)
|
|
180
|
+
item.setState({placeholder: false}, item.forceUpdate);
|
|
181
|
+
onDragEnd()
|
|
182
|
+
});
|
|
183
|
+
addListener(draggableElement, item, 'dragstart', dragStartListener);
|
|
184
|
+
|
|
185
|
+
let longTouch;
|
|
186
|
+
let dragStarted = false;
|
|
187
|
+
let dragged = false;
|
|
188
|
+
addListener(draggableElement, item, 'touchstart', e => {
|
|
189
|
+
if (e.touches.length > 1)
|
|
190
|
+
return;
|
|
191
|
+
|
|
192
|
+
stopPropagation(e)
|
|
193
|
+
preventDefault(e)
|
|
194
|
+
dragged = dragStarted = false;
|
|
195
|
+
const touch = e.targetTouches[0];
|
|
196
|
+
longTouch = setTimeout(() => longTouch && (dragStarted = true) && (longTouch = dragStartListener(touch)), !handle ? 500 : 0)
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
addListener(draggableElement, item, 'touchmove', e => {
|
|
200
|
+
if (longTouch) {
|
|
201
|
+
longTouch = clearTimeout(longTouch);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!dragStarted)
|
|
205
|
+
return;
|
|
206
|
+
|
|
207
|
+
if (e.touches.length > 1)
|
|
208
|
+
return;
|
|
209
|
+
|
|
210
|
+
preventDefault(e);
|
|
211
|
+
dragged = true;
|
|
212
|
+
const touch = e.targetTouches[0];
|
|
213
|
+
positionListener(touch);
|
|
214
|
+
droppables.forEach(it => it.isHover(touch, item))
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
addListener(draggableElement, item, 'touchend', e => {
|
|
218
|
+
longTouch = clearTimeout(longTouch);
|
|
219
|
+
if (!dragged)
|
|
220
|
+
return;
|
|
221
|
+
|
|
222
|
+
item.setState({placeholder: false}, item.forceUpdate);
|
|
223
|
+
if (e.touches.length > 0)
|
|
224
|
+
return;
|
|
225
|
+
|
|
226
|
+
droppables.forEach(it => it.dropIfHover());
|
|
227
|
+
onDragEnd();
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const droppableInitializer = (item) => {
|
|
232
|
+
droppables.push(item);
|
|
233
|
+
|
|
234
|
+
addEventListener(item.element, 'drop', (e) => {
|
|
235
|
+
if (item.state.allow) {
|
|
236
|
+
preventDefault(e);
|
|
237
|
+
stopPropagation(e)
|
|
238
|
+
data && orNoop(item.props.onDrop)(data);
|
|
239
|
+
}
|
|
240
|
+
}, false);
|
|
241
|
+
addEventListener(item.element, 'dragenter', (e) => {
|
|
242
|
+
if (item.state.allow) {
|
|
243
|
+
preventDefault(e);
|
|
244
|
+
item.isHover(e, draggable, true)
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
addEventListener(item.element, 'dragleave', (e) => {
|
|
248
|
+
if (item.state.allow) {
|
|
249
|
+
preventDefault(e);
|
|
250
|
+
item.isHover(e, draggable, false)
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
item.onDragStart = (e, draggable) => {
|
|
255
|
+
item.bounds = item.element.getBoundingClientRect();
|
|
256
|
+
let allow = (orNoop(item.props.onDragStart)(e, data));
|
|
257
|
+
if (allow === UNDEFINED)
|
|
258
|
+
allow = true
|
|
259
|
+
item.setState({allow});
|
|
260
|
+
};
|
|
261
|
+
item.isHover = (e, draggable, hover) => {
|
|
262
|
+
const bounds = item.bounds;
|
|
263
|
+
if (!bounds)
|
|
264
|
+
return;
|
|
265
|
+
|
|
266
|
+
if (hover === UNDEFINED) {
|
|
267
|
+
let y = e.pageY - scrollOffsetY;
|
|
268
|
+
let x = e.pageX - scrollOffsetX;
|
|
269
|
+
hover = bounds.left <= x && bounds.right >= x && bounds.top <= y && bounds.bottom >= y;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
hover && orNoop(item.props.onHover)(e, draggable);
|
|
273
|
+
|
|
274
|
+
if (hover)
|
|
275
|
+
!item.state.hover && item.setState({hover}, item.forceUpdate);
|
|
276
|
+
else
|
|
277
|
+
item.state.hover && item.setState({hover}, item.forceUpdate);
|
|
278
|
+
};
|
|
279
|
+
item.dropIfHover = () => {
|
|
280
|
+
data && item.state.hover && orNoop(item.props.onDrop)(data);
|
|
281
|
+
};
|
|
282
|
+
item.onDragEnd = () => {
|
|
283
|
+
orNoop(orNoop(draggable)['onDragEnd'])();
|
|
284
|
+
item.setState({allow: false, hover: false});
|
|
285
|
+
};
|
|
286
|
+
item.onUnmount = () => droppables.splice(droppables.indexOf(item), 1);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
that[componentDidMount] = () => {
|
|
290
|
+
const {
|
|
291
|
+
provideDraggableInitializer,
|
|
292
|
+
provideDroppableInitializer,
|
|
293
|
+
} = props();
|
|
294
|
+
|
|
295
|
+
orNoop(provideDraggableInitializer)(draggableInitializer);
|
|
296
|
+
orNoop(provideDroppableInitializer)(droppableInitializer);
|
|
297
|
+
addEventListener(containerRef(), 'dragover', onDrag, {capture: true, passive: true})
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export const removeListener = (el, item, type) => item[type] && removeEventListener(el, type, item[type]);
|
|
303
|
+
export const addListener = (el, item, type, listener) => {
|
|
304
|
+
removeListener(el, item, type);
|
|
305
|
+
addEventListener(el, type, item[type] = listener);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const totalOffsetTop = (el) => {
|
|
309
|
+
return el.getBoundingClientRect().top + (WINDOW.pageYOffset || DOCUMENT.documentElement.scrollTop);
|
|
310
|
+
};
|
|
311
|
+
const totalOffsetLeft = (el) => {
|
|
312
|
+
return el.getBoundingClientRect().left + (WINDOW.pageXOffset || DOCUMENT.documentElement.scrollLeft);
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
export default DNDContainer;
|
package/src/DNDDroppable.js
CHANGED
|
@@ -45,8 +45,10 @@ class Droppable extends PureComponent {
|
|
|
45
45
|
_state[allow] && allow,
|
|
46
46
|
)}
|
|
47
47
|
onDragOver={e => {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
if (_state[allow]) {
|
|
49
|
+
preventDefault(e);
|
|
50
|
+
stopPropagation(e);
|
|
51
|
+
}
|
|
50
52
|
}}
|
|
51
53
|
ref={ref('element', that)}>
|
|
52
54
|
{_props[ReactConstants[4]]}
|
package/src/DatePicker.tsx
CHANGED
|
@@ -32,10 +32,13 @@ const DayRenderer = ({day, selected, minDate, onClick}: {
|
|
|
32
32
|
export interface DatePickerProps {
|
|
33
33
|
id?: number | string
|
|
34
34
|
name?: string
|
|
35
|
+
open?: boolean
|
|
36
|
+
onClose?: () => void
|
|
37
|
+
renderInput?: () => JSX.Element
|
|
35
38
|
value: Date
|
|
36
39
|
minDate?: Date
|
|
37
40
|
formatter: (date: Date) => string
|
|
38
|
-
parser: (
|
|
41
|
+
parser: (input: string) => Date
|
|
39
42
|
onChange: (e) => void
|
|
40
43
|
dayOfWeekToString: (day: number) => string | JSX.Element
|
|
41
44
|
monthToString: (day: number) => string | JSX.Element
|
|
@@ -54,28 +57,36 @@ class DatePicker extends React.Component<DatePickerProps, DatePickerState> {
|
|
|
54
57
|
|
|
55
58
|
constructor(props: DatePickerProps) {
|
|
56
59
|
super(props);
|
|
57
|
-
const
|
|
60
|
+
const value = props.value;
|
|
58
61
|
this.state = {
|
|
59
|
-
focused:
|
|
60
|
-
value
|
|
61
|
-
text: props.formatter(
|
|
62
|
-
selectedMonth: DateTools.dateOf(
|
|
62
|
+
focused: !!props.open,
|
|
63
|
+
value,
|
|
64
|
+
text: props.formatter(value),
|
|
65
|
+
selectedMonth: DateTools.dateOf(value || new Date()).resetTime().set(1, DateTools.TimeUnit.DAY),
|
|
63
66
|
};
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
67
|
-
if (this.props.value !== prevProps.value)
|
|
70
|
+
if (this.props.value !== prevProps.value) {
|
|
71
|
+
const value = this.props.value
|
|
68
72
|
this.setState({
|
|
69
|
-
value
|
|
70
|
-
selectedMonth: DateTools.dateOf(
|
|
71
|
-
text: this.props.formatter(
|
|
73
|
+
value,
|
|
74
|
+
selectedMonth: DateTools.dateOf(value || new Date()).resetTime().set(1, DateTools.TimeUnit.DAY),
|
|
75
|
+
text: this.props.formatter(value)
|
|
72
76
|
})
|
|
77
|
+
}
|
|
78
|
+
if (this.props.open !== prevProps.open) {
|
|
79
|
+
const open = !!this.props.open
|
|
80
|
+
this.setState({
|
|
81
|
+
focused: open
|
|
82
|
+
}, !open ? this.props.onClose : null)
|
|
83
|
+
}
|
|
73
84
|
};
|
|
74
85
|
|
|
75
86
|
componentDidMount() {
|
|
76
87
|
document.addEventListener('mousedown', this.listener = (e) => {
|
|
77
88
|
if (this.state.focused && !this.el.contains(e.target))
|
|
78
|
-
this.setState({focused: false});
|
|
89
|
+
this.setState({focused: false}, this.props.onClose);
|
|
79
90
|
})
|
|
80
91
|
};
|
|
81
92
|
|
|
@@ -90,6 +101,9 @@ class DatePicker extends React.Component<DatePickerProps, DatePickerState> {
|
|
|
90
101
|
if (!DateTools.equals(this.state.value, nextState.value))
|
|
91
102
|
return true;
|
|
92
103
|
|
|
104
|
+
if (this.props.open !== nextProps.open)
|
|
105
|
+
return true;
|
|
106
|
+
|
|
93
107
|
if (this.state.text !== nextState.text)
|
|
94
108
|
return true;
|
|
95
109
|
|
|
@@ -106,32 +120,33 @@ class DatePicker extends React.Component<DatePickerProps, DatePickerState> {
|
|
|
106
120
|
};
|
|
107
121
|
|
|
108
122
|
render() {
|
|
109
|
-
const {minDate, formatter, parser, dayOfWeekToString, monthToString} = this.props;
|
|
123
|
+
const {minDate, formatter, parser, dayOfWeekToString, monthToString, renderInput} = this.props;
|
|
110
124
|
const {value, text, focused, selectedMonth} = this.state;
|
|
111
125
|
|
|
112
126
|
return <div className={`DatePicker`} ref={el => this.el = el}>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
127
|
+
{!!renderInput && renderInput()}
|
|
128
|
+
{!renderInput && <TextField id={'value'} value={text}
|
|
129
|
+
autoComplete="off"
|
|
130
|
+
onFocus={() => this.setState({focused: true})}
|
|
131
|
+
onChange={e => {
|
|
132
|
+
const text = e.target.value;
|
|
133
|
+
try {
|
|
134
|
+
const date = parser(text);
|
|
135
|
+
if (date && date instanceof Date && !Number.isNaN(date.getTime())) {
|
|
136
|
+
if (!value || !DateTools.equals(value, date))
|
|
137
|
+
this.onChange(date);
|
|
138
|
+
}
|
|
139
|
+
this.setState({text})
|
|
140
|
+
} catch (ignored) {
|
|
141
|
+
}
|
|
142
|
+
}}
|
|
143
|
+
onKeyDown={e => {
|
|
144
|
+
if ((e.keyCode === 27/*esc*/ || e.keyCode === 13/*enter*/) && focused) {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
this.setState({text: formatter(value), focused: false});
|
|
147
|
+
}
|
|
148
|
+
}}
|
|
149
|
+
/>}
|
|
135
150
|
<div className={`calendar ${focused && 'focused'}`}>
|
|
136
151
|
<div className={'row monthSelect'}>
|
|
137
152
|
<span>
|