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

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