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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-ui-basics",
3
- "version": "0.0.180",
3
+ "version": "0.0.182",
4
4
  "description": "",
5
5
  "module": "index.js",
6
6
  "_main": "index.cjs.js",
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, removeEventListener, WINDOW, orNoop } from '../Tools.js';
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;
@@ -45,8 +45,10 @@ class Droppable extends PureComponent {
45
45
  _state[allow] && allow,
46
46
  )}
47
47
  onDragOver={e => {
48
- preventDefault(e);
49
- stopPropagation(e);
48
+ if (_state[allow]) {
49
+ preventDefault(e);
50
+ stopPropagation(e);
51
+ }
50
52
  }}
51
53
  ref={ref('element', that)}>
52
54
  {_props[ReactConstants[4]]}
@@ -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: (date: string) => Date
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 date = props.value || new Date();
60
+ const value = props.value;
58
61
  this.state = {
59
- focused: false,
60
- value: date,
61
- text: props.formatter(date),
62
- selectedMonth: DateTools.dateOf(date).resetTime().set(1, DateTools.TimeUnit.DAY),
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: this.props.value,
70
- selectedMonth: DateTools.dateOf(this.props.value).resetTime().set(1, DateTools.TimeUnit.DAY),
71
- text: this.props.formatter(this.props.value)
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
- <TextField id={'value'} value={text}
114
- autoComplete="off"
115
- onFocus={() => this.setState({focused: true})}
116
- onChange={e => {
117
- const text = e.target.value;
118
- try {
119
- const date = parser(text);
120
- if (date instanceof Date && !Number.isNaN(date.getTime())) {
121
- if (date && value.getTime() !== date.getTime())
122
- this.onChange(date);
123
- }
124
- this.setState({text})
125
- } catch (ignored) {
126
- }
127
- }}
128
- onKeyDown={e => {
129
- if ((e.keyCode === 27/*esc*/ || e.keyCode === 13/*enter*/) && focused) {
130
- e.preventDefault();
131
- this.setState({text: formatter(value), focused: false});
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>