@seafile/seafile-calendar 0.1.2 → 1.0.0-alpha.0

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.
@@ -0,0 +1,206 @@
1
+ import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
2
+ import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
3
+ import _inherits from 'babel-runtime/helpers/inherits';
4
+ import React from 'react';
5
+ import ReactDOM from 'react-dom';
6
+ import PropTypes from 'prop-types';
7
+ import { polyfill } from 'react-lifecycles-compat';
8
+ import dayjs from 'dayjs';
9
+
10
+ var customParseFormat = require('dayjs/plugin/customParseFormat');
11
+ dayjs.extend(customParseFormat);
12
+
13
+ function formatTime(value, format) {
14
+ if (!value) return '';
15
+ var fmt = Array.isArray(format) ? format[0] : format || 'HH:mm';
16
+ return value.format(fmt);
17
+ }
18
+
19
+ // Convert a loose numeric/time string into HH:mm
20
+ // Rules (similar spirit to DateInput.initializeStr):
21
+ // - Strip non-digits
22
+ // - If len <= 2 => treat as hour
23
+ // - If len > 2 => last two digits are minutes; preceding are hours
24
+ // - Clamp hours to [0,23], minutes to [0,59]
25
+ // - Return formatted HH:mm or '' when input is empty
26
+ function initializeTime(str) {
27
+ if (typeof str !== 'string') return '';
28
+ var digits = str.replace(/\D/g, '');
29
+ if (!digits.length) return '';
30
+
31
+ var hDigits = '';
32
+ var mDigits = '';
33
+ if (digits.length <= 2) {
34
+ hDigits = digits;
35
+ } else {
36
+ hDigits = digits.slice(0, digits.length - 2);
37
+ mDigits = digits.slice(-2);
38
+ }
39
+
40
+ var hour = parseInt(hDigits || '0', 10);
41
+ var minute = parseInt(mDigits || '0', 10);
42
+ if (Number.isNaN(hour)) hour = 0;
43
+ if (Number.isNaN(minute)) minute = 0;
44
+
45
+ if (hour > 23) hour = 23;
46
+ if (minute > 59) minute = 59;
47
+
48
+ var HH = String(hour).padStart(2, '0');
49
+ var mm = String(minute).padStart(2, '0');
50
+ return HH + ':' + mm;
51
+ }
52
+
53
+ var timeInputInstance = void 0;
54
+ var cachedSelectionStart = void 0;
55
+ var cachedSelectionEnd = void 0;
56
+
57
+ var TimeInput = function (_React$Component) {
58
+ _inherits(TimeInput, _React$Component);
59
+
60
+ function TimeInput(props) {
61
+ _classCallCheck(this, TimeInput);
62
+
63
+ var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
64
+
65
+ _this.onInputChange = function (event) {
66
+ var str = event.target.value;
67
+ var timeStr = initializeTime(str);
68
+
69
+ if (!str || !timeStr) {
70
+ _this.setState({ str: str, isInputEmpty: true });
71
+ return;
72
+ }
73
+
74
+ if (_this.state.isInputEmpty) {
75
+ _this.setState({ isInputEmpty: false });
76
+ }
77
+
78
+ var base = _this.props.selectedValue || _this.props.value || dayjs();
79
+ var parsed = dayjs(timeStr, 'HH:mm');
80
+ var next = base.clone().hour(parsed.hour()).minute(parsed.minute());
81
+
82
+ _this.setState({ str: str });
83
+ if (_this.props.onChange) {
84
+ _this.props.onChange(next);
85
+ }
86
+ };
87
+
88
+ _this.onKeyDown = function (event) {
89
+ if (event.key === 'Enter' && _this.props.onSelect) {
90
+ var timeStr = initializeTime(_this.state.str);
91
+ if (!timeStr) return;
92
+ var base = _this.props.selectedValue || _this.props.value || dayjs();
93
+ var parsed = dayjs(timeStr, 'HH:mm');
94
+ var next = base.clone().hour(parsed.hour()).minute(parsed.minute());
95
+ _this.props.onSelect(next);
96
+ event.preventDefault();
97
+ }
98
+ };
99
+
100
+ _this.onFocus = function () {
101
+ _this.setState({ hasFocus: true });
102
+ };
103
+
104
+ _this.onBlur = function () {
105
+ var base = _this.props.showFromSelected ? _this.props.selectedValue || null : null;
106
+ _this.setState({
107
+ hasFocus: false,
108
+ str: base ? formatTime(base, _this.props.format) : ''
109
+ });
110
+ };
111
+
112
+ _this.saveRef = function (node) {
113
+ timeInputInstance = node;
114
+ };
115
+
116
+ _this.getRootDOMNode = function () {
117
+ return ReactDOM.findDOMNode(_this);
118
+ };
119
+
120
+ _this.state = {
121
+ str: '',
122
+ hasFocus: false,
123
+ isInputEmpty: true
124
+ };
125
+ return _this;
126
+ }
127
+
128
+ TimeInput.prototype.componentDidUpdate = function componentDidUpdate() {
129
+ if (timeInputInstance && this.state.hasFocus && !(cachedSelectionStart === 0 && cachedSelectionEnd === 0)) {
130
+ timeInputInstance.setSelectionRange(cachedSelectionStart, cachedSelectionEnd);
131
+ }
132
+ };
133
+
134
+ TimeInput.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, state) {
135
+ var newState = null;
136
+ if (timeInputInstance) {
137
+ cachedSelectionStart = timeInputInstance.selectionStart;
138
+ cachedSelectionEnd = timeInputInstance.selectionEnd;
139
+ }
140
+
141
+ if (!state.hasFocus) {
142
+ if (nextProps.showFromSelected && nextProps.selectedValue) {
143
+ newState = { str: formatTime(nextProps.selectedValue, nextProps.format) };
144
+ } else {
145
+ newState = { str: '' };
146
+ }
147
+ }
148
+ return newState;
149
+ };
150
+
151
+ TimeInput.getInstance = function getInstance() {
152
+ return timeInputInstance;
153
+ };
154
+
155
+ TimeInput.prototype.render = function render() {
156
+ var _props = this.props,
157
+ prefixCls = _props.prefixCls,
158
+ placeholder = _props.placeholder,
159
+ inputMode = _props.inputMode,
160
+ disabled = _props.disabled,
161
+ className = _props.className;
162
+
163
+ var inputCls = className || prefixCls + '-time-input ' + prefixCls + '-text-input';
164
+ return React.createElement(
165
+ 'div',
166
+ { className: prefixCls + '-time-input-outer' },
167
+ React.createElement('input', {
168
+ ref: this.saveRef,
169
+ className: inputCls,
170
+ value: this.state.str,
171
+ disabled: disabled,
172
+ placeholder: placeholder,
173
+ onChange: this.onInputChange,
174
+ onKeyDown: this.onKeyDown,
175
+ onFocus: this.onFocus,
176
+ onBlur: this.onBlur,
177
+ inputMode: inputMode
178
+ })
179
+ );
180
+ };
181
+
182
+ return TimeInput;
183
+ }(React.Component);
184
+
185
+ TimeInput.propTypes = {
186
+ prefixCls: PropTypes.string,
187
+ value: PropTypes.object,
188
+ selectedValue: PropTypes.object,
189
+ onChange: PropTypes.func,
190
+ onSelect: PropTypes.func,
191
+ placeholder: PropTypes.string,
192
+ inputMode: PropTypes.string,
193
+ format: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
194
+ disabled: PropTypes.bool,
195
+ className: PropTypes.string,
196
+ showFromSelected: PropTypes.bool
197
+ };
198
+ TimeInput.defaultProps = {
199
+ format: 'HH:mm',
200
+ placeholder: 'HH:mm'
201
+ };
202
+
203
+
204
+ polyfill(TimeInput);
205
+
206
+ export default TimeInput;
package/lib/Calendar.js CHANGED
@@ -64,6 +64,10 @@ var _DateInput = require('./date/DateInput');
64
64
 
65
65
  var _DateInput2 = _interopRequireDefault(_DateInput);
66
66
 
67
+ var _TimeInput = require('./time/TimeInput');
68
+
69
+ var _TimeInput2 = _interopRequireDefault(_TimeInput);
70
+
67
71
  var _util = require('./util');
68
72
 
69
73
  var _toTime = require('./util/toTime');
@@ -109,7 +113,8 @@ var Calendar = function (_React$Component) {
109
113
  mode: _this.props.mode || 'date',
110
114
  value: getMomentObjectIfValid(props.value) || getMomentObjectIfValid(props.defaultValue) || (0, _dayjs2['default'])(),
111
115
  selectedValue: props.selectedValue || props.defaultSelectedValue,
112
- currentStatus: _util.CALENDAR_STATUS.SPECIFIC_TIME
116
+ currentStatus: _util.CALENDAR_STATUS.SPECIFIC_TIME,
117
+ hasExplicitTime: false
113
118
  };
114
119
  return _this;
115
120
  }
@@ -140,6 +145,8 @@ var Calendar = function (_React$Component) {
140
145
  };
141
146
 
142
147
  Calendar.prototype.render = function render() {
148
+ var _this2 = this;
149
+
143
150
  var props = this.props,
144
151
  state = this.state;
145
152
  var locale = props.locale,
@@ -182,7 +189,9 @@ var Calendar = function (_React$Component) {
182
189
 
183
190
  timePickerEle = _react2['default'].cloneElement(timePicker, timePickerProps);
184
191
  }
185
- var calendarInputPlaceholder = dateInputPlaceholder || (Array.isArray(this.getFormat()) ? this.getFormat()[0] : this.getFormat());
192
+
193
+ var baseFormat = Array.isArray(this.getFormat()) ? this.getFormat()[0] : this.getFormat();
194
+ var headerDatePlaceholder = baseFormat.replace(/\s*HH:mm(?::ss)?\s*/, '').trim() || 'YYYY-MM-DD';
186
195
  var inputFormat = Array.isArray(this.getFormat()) ? this.getFormat() : [this.getFormat()];
187
196
 
188
197
  var dateInputElement = props.showDateInput ? _react2['default'].createElement(_DateInput2['default'], {
@@ -190,8 +199,8 @@ var Calendar = function (_React$Component) {
190
199
  key: 'date-input',
191
200
  value: value,
192
201
  locale: locale,
193
- placeholder: calendarInputPlaceholder,
194
- showClear: true,
202
+ placeholder: headerDatePlaceholder,
203
+ showClear: false,
195
204
  disabledTime: disabledTime,
196
205
  disabledDate: disabledDate,
197
206
  onClear: this.onClear,
@@ -203,6 +212,17 @@ var Calendar = function (_React$Component) {
203
212
  inputMode: inputMode
204
213
  }) : null;
205
214
 
215
+ var timeInputTopElement = _react2['default'].createElement(_TimeInput2['default'], {
216
+ key: 'time-input-top',
217
+ prefixCls: prefixCls,
218
+ value: value,
219
+ selectedValue: selectedValue,
220
+ showFromSelected: this.state.hasExplicitTime,
221
+ onChange: this.onTimeInputChange,
222
+ onSelect: this.onTimeInputSelect,
223
+ inputMode: 'numeric'
224
+ });
225
+
206
226
  var children = [];
207
227
  if (props.renderSidebar) {
208
228
  children.push(props.renderSidebar());
@@ -210,7 +230,24 @@ var Calendar = function (_React$Component) {
210
230
  children.push(_react2['default'].createElement(
211
231
  'div',
212
232
  { className: prefixCls + '-panel', key: 'panel' },
213
- dateInputElement,
233
+ _react2['default'].createElement(
234
+ 'div',
235
+ { className: prefixCls + '-inputs' },
236
+ _react2['default'].createElement(
237
+ 'div',
238
+ { className: prefixCls + '-date-input-col' },
239
+ _react2['default'].createElement(
240
+ 'div',
241
+ { className: prefixCls + '-date-input' },
242
+ dateInputElement
243
+ )
244
+ ),
245
+ _react2['default'].createElement(
246
+ 'div',
247
+ { className: prefixCls + '-time-input-col' },
248
+ timeInputTopElement
249
+ )
250
+ ),
214
251
  _react2['default'].createElement(
215
252
  'div',
216
253
  { className: prefixCls + '-date-panel-container' },
@@ -254,39 +291,45 @@ var Calendar = function (_React$Component) {
254
291
  firstDayOfWeek: firstDayOfWeek,
255
292
  currentStatus: currentStatus
256
293
  })
257
- ),
258
- _react2['default'].createElement(_CalendarFooter2['default'], {
259
- showOk: props.showOk,
260
- mode: mode,
261
- renderFooter: props.renderFooter,
262
- locale: locale,
263
- prefixCls: prefixCls,
264
- showToday: props.showToday,
265
- disabledTime: disabledTime,
266
- showTimePicker: showTimePicker,
267
- showDateInput: props.showDateInput,
268
- timePicker: timePicker,
269
- selectedValue: selectedValue,
270
- value: value,
271
- disabledDate: disabledDate,
272
- okDisabled: props.showOk !== false && (!selectedValue || !this.isAllowedDate(selectedValue)),
273
- onOk: this.onOk,
274
- onSelect: this.onSelect,
275
- onToday: this.onToday,
276
- onOpenTimePicker: this.openTimePicker,
277
- onCloseTimePicker: this.closeTimePicker
278
- })
294
+ )
279
295
  ),
280
296
  showHourAndMinute && _react2['default'].createElement(_CalendarRightPanel2['default'], {
281
297
  prefixCls: prefixCls,
282
298
  value: value,
299
+ selectedValue: selectedValue,
283
300
  locale: locale,
284
- onSelect: this.onDateTableSelect,
301
+ onSelect: function onSelect(v) {
302
+ if (!_this2.state.hasExplicitTime) {
303
+ _this2.setState({ hasExplicitTime: true });
304
+ }
305
+ _this2.onDateTableSelect(v);
306
+ },
285
307
  onClickRightPanelTime: onClickRightPanelTime,
286
308
  defaultMinutesTime: this.props.defaultMinutesTime,
287
309
  format: inputFormat
288
310
  })
289
- )
311
+ ),
312
+ _react2['default'].createElement(_CalendarFooter2['default'], {
313
+ showOk: props.showOk,
314
+ mode: mode,
315
+ renderFooter: props.renderFooter,
316
+ locale: locale,
317
+ prefixCls: prefixCls,
318
+ showToday: props.showToday,
319
+ disabledTime: disabledTime,
320
+ showTimePicker: showTimePicker,
321
+ showDateInput: props.showDateInput,
322
+ timePicker: timePicker,
323
+ selectedValue: selectedValue,
324
+ value: value,
325
+ disabledDate: disabledDate,
326
+ okDisabled: props.showOk !== false && (!selectedValue || !this.isAllowedDate(selectedValue)),
327
+ onOk: this.onOk,
328
+ onSelect: this.onSelect,
329
+ onToday: this.onToday,
330
+ onOpenTimePicker: this.openTimePicker,
331
+ onCloseTimePicker: this.closeTimePicker
332
+ })
290
333
  ));
291
334
 
292
335
  return this.renderRoot({
@@ -347,14 +390,14 @@ Calendar.defaultProps = (0, _extends3['default'])({}, _CalendarMixin.calendarMix
347
390
  });
348
391
 
349
392
  var _initialiseProps = function _initialiseProps() {
350
- var _this2 = this;
393
+ var _this3 = this;
351
394
 
352
395
  this.onPanelChange = function (value, mode) {
353
- var props = _this2.props,
354
- state = _this2.state;
396
+ var props = _this3.props,
397
+ state = _this3.state;
355
398
 
356
399
  if (!('mode' in props)) {
357
- _this2.setState({ mode: mode });
400
+ _this3.setState({ mode: mode });
358
401
  }
359
402
  props.onPanelChange(value || state.value, mode);
360
403
  };
@@ -366,109 +409,109 @@ var _initialiseProps = function _initialiseProps() {
366
409
  var keyCode = event.keyCode;
367
410
  // mac
368
411
  var ctrlKey = event.ctrlKey || event.metaKey;
369
- var disabledDate = _this2.props.disabledDate;
370
- var value = _this2.state.value;
412
+ var disabledDate = _this3.props.disabledDate;
413
+ var value = _this3.state.value;
371
414
 
372
415
  switch (keyCode) {
373
416
  case _KeyCode2['default'].DOWN:
374
- _this2.goTime(1, 'weeks');
417
+ _this3.goTime(1, 'weeks');
375
418
  event.preventDefault();
376
419
  return 1;
377
420
  case _KeyCode2['default'].UP:
378
- _this2.goTime(-1, 'weeks');
421
+ _this3.goTime(-1, 'weeks');
379
422
  event.preventDefault();
380
423
  return 1;
381
424
  case _KeyCode2['default'].LEFT:
382
425
  if (ctrlKey) {
383
- _this2.goTime(-1, 'years');
426
+ _this3.goTime(-1, 'years');
384
427
  } else {
385
- _this2.goTime(-1, 'days');
428
+ _this3.goTime(-1, 'days');
386
429
  }
387
430
  event.preventDefault();
388
431
  return 1;
389
432
  case _KeyCode2['default'].RIGHT:
390
433
  if (ctrlKey) {
391
- _this2.goTime(1, 'years');
434
+ _this3.goTime(1, 'years');
392
435
  } else {
393
- _this2.goTime(1, 'days');
436
+ _this3.goTime(1, 'days');
394
437
  }
395
438
  event.preventDefault();
396
439
  return 1;
397
440
  case _KeyCode2['default'].HOME:
398
- _this2.setValue((0, _toTime.goStartMonth)(_this2.state.value));
441
+ _this3.setValue((0, _toTime.goStartMonth)(_this3.state.value));
399
442
  event.preventDefault();
400
443
  return 1;
401
444
  case _KeyCode2['default'].END:
402
- _this2.setValue((0, _toTime.goEndMonth)(_this2.state.value));
445
+ _this3.setValue((0, _toTime.goEndMonth)(_this3.state.value));
403
446
  event.preventDefault();
404
447
  return 1;
405
448
  case _KeyCode2['default'].PAGE_DOWN:
406
- _this2.goTime(1, 'month');
449
+ _this3.goTime(1, 'month');
407
450
  event.preventDefault();
408
451
  return 1;
409
452
  case _KeyCode2['default'].PAGE_UP:
410
- _this2.goTime(-1, 'month');
453
+ _this3.goTime(-1, 'month');
411
454
  event.preventDefault();
412
455
  return 1;
413
456
  case _KeyCode2['default'].ENTER:
414
457
  if (!disabledDate || !disabledDate(value)) {
415
- _this2.onSelect(value, {
458
+ _this3.onSelect(value, {
416
459
  source: 'keyboard'
417
460
  });
418
461
  }
419
462
  event.preventDefault();
420
463
  return 1;
421
464
  default:
422
- _this2.props.onKeyDown(event);
465
+ _this3.props.onKeyDown(event);
423
466
  return 1;
424
467
  }
425
468
  };
426
469
 
427
470
  this.onClear = function () {
428
- _this2.onSelect(null);
429
- _this2.props.onClear();
430
- _this2.setState({ currentStatus: _util.CALENDAR_STATUS.CURRENT_TIME });
471
+ _this3.onSelect(null);
472
+ _this3.props.onClear();
473
+ _this3.setState({ currentStatus: _util.CALENDAR_STATUS.CURRENT_TIME, hasExplicitTime: false });
431
474
  };
432
475
 
433
476
  this.onOk = function () {
434
- var selectedValue = _this2.state.selectedValue;
477
+ var selectedValue = _this3.state.selectedValue;
435
478
 
436
- if (_this2.isAllowedDate(selectedValue)) {
437
- _this2.props.onOk(selectedValue);
479
+ if (_this3.isAllowedDate(selectedValue)) {
480
+ _this3.props.onOk(selectedValue);
438
481
  }
439
482
  };
440
483
 
441
484
  this.onDateInputChange = function (value) {
442
- _this2.onSelect(value, {
485
+ _this3.onSelect(value, {
443
486
  source: 'dateInput'
444
487
  });
445
488
  };
446
489
 
447
490
  this.onDateInputSelect = function (value) {
448
- _this2.onSelect(value, {
491
+ _this3.onSelect(value, {
449
492
  source: 'dateInputSelect'
450
493
  });
451
494
  };
452
495
 
453
496
  this.onDateTableSelect = function (value) {
454
- var timePicker = _this2.props.timePicker;
455
- var selectedValue = _this2.state.selectedValue;
497
+ var timePicker = _this3.props.timePicker;
498
+ var selectedValue = _this3.state.selectedValue;
456
499
 
457
- _this2.setState({ currentStatus: _util.CALENDAR_STATUS.SPECIFIC_TIME });
500
+ _this3.setState({ currentStatus: _util.CALENDAR_STATUS.SPECIFIC_TIME });
458
501
  if (!selectedValue && timePicker) {
459
502
  var timePickerDefaultValue = timePicker.props.defaultValue;
460
503
  if (timePickerDefaultValue) {
461
504
  (0, _util.syncTime)(timePickerDefaultValue, value);
462
505
  }
463
506
  }
464
- _this2.onSelect(value);
507
+ _this3.onSelect(value);
465
508
  };
466
509
 
467
510
  this.onToday = function () {
468
- var value = _this2.state.value;
511
+ var value = _this3.state.value;
469
512
 
470
513
  var now = (0, _util.getTodayTime)(value);
471
- _this2.onSelect(now, {
514
+ _this3.onSelect(now, {
472
515
  source: 'todayButton'
473
516
  });
474
517
  };
@@ -476,33 +519,48 @@ var _initialiseProps = function _initialiseProps() {
476
519
  this.onBlur = function (event) {
477
520
  setTimeout(function () {
478
521
  var dateInput = _DateInput2['default'].getInstance();
479
- var rootInstance = _this2.rootInstance;
522
+ var timeInput = _TimeInput2['default'].getInstance && _TimeInput2['default'].getInstance();
523
+ var rootInstance = _this3.rootInstance;
480
524
 
481
- if (!rootInstance || rootInstance.contains(document.activeElement) || dateInput && dateInput.contains(document.activeElement)) {
525
+ if (!rootInstance || rootInstance.contains(document.activeElement) || dateInput && dateInput.contains(document.activeElement) || timeInput && timeInput.contains && timeInput.contains(document.activeElement)) {
482
526
  // focused element is still part of Calendar
483
527
  return;
484
528
  }
485
529
 
486
- if (_this2.props.onBlur) {
487
- _this2.props.onBlur(event);
530
+ if (_this3.props.onBlur) {
531
+ _this3.props.onBlur(event);
488
532
  }
489
533
  }, 0);
490
534
  };
491
535
 
536
+ this.onTimeInputChange = function (value) {
537
+ if (!_this3.state.hasExplicitTime) {
538
+ _this3.setState({ hasExplicitTime: true });
539
+ }
540
+ _this3.onSelect(value, { source: 'timeInputChange' });
541
+ };
542
+
543
+ this.onTimeInputSelect = function (value) {
544
+ if (!_this3.state.hasExplicitTime) {
545
+ _this3.setState({ hasExplicitTime: true });
546
+ }
547
+ _this3.onSelect(value, { source: 'timeInputSelect' });
548
+ };
549
+
492
550
  this.getRootDOMNode = function () {
493
- return _reactDom2['default'].findDOMNode(_this2);
551
+ return _reactDom2['default'].findDOMNode(_this3);
494
552
  };
495
553
 
496
554
  this.openTimePicker = function () {
497
- _this2.onPanelChange(null, 'time');
555
+ _this3.onPanelChange(null, 'time');
498
556
  };
499
557
 
500
558
  this.closeTimePicker = function () {
501
- _this2.onPanelChange(null, 'date');
559
+ _this3.onPanelChange(null, 'date');
502
560
  };
503
561
 
504
562
  this.goTime = function (direction, unit) {
505
- _this2.setValue((0, _toTime.goTime)(_this2.state.value, direction, unit));
563
+ _this3.setValue((0, _toTime.goTime)(_this3.state.value, direction, unit));
506
564
  };
507
565
  };
508
566