@kne/react-calendar 1.0.5 → 1.1.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.
- package/README.md +210 -49
- package/dist/en-US.d.ts +6 -3
- package/dist/index.css +919 -100
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +48 -4
- package/dist/index.js +2387 -831
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +2214 -681
- package/dist/index.modern.js.map +1 -1
- package/dist/locale/en-US.js +7 -4
- package/dist/locale/en-US.js.map +1 -1
- package/dist/locale/en-US.modern.js +7 -4
- package/dist/locale/en-US.modern.js.map +1 -1
- package/dist/locale/zh-CN.js +7 -4
- package/dist/locale/zh-CN.js.map +1 -1
- package/dist/locale/zh-CN.modern.js +7 -4
- package/dist/locale/zh-CN.modern.js.map +1 -1
- package/dist/zh-CN.d.ts +6 -3
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ var antd = require('antd');
|
|
|
6
6
|
var reactIntl = require('@kne/react-intl');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var FormInfo = require('@kne/form-info');
|
|
9
|
+
var responsiveUtils = require('@kne/responsive-utils');
|
|
9
10
|
|
|
10
11
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
12
|
|
|
@@ -14,16 +15,6 @@ var customParseFormat__default = /*#__PURE__*/_interopDefaultLegacy(customParseF
|
|
|
14
15
|
var useControlValue__default = /*#__PURE__*/_interopDefaultLegacy(useControlValue);
|
|
15
16
|
var FormInfo__default = /*#__PURE__*/_interopDefaultLegacy(FormInfo);
|
|
16
17
|
|
|
17
|
-
function _extends() {
|
|
18
|
-
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
|
19
|
-
for (var e = 1; e < arguments.length; e++) {
|
|
20
|
-
var t = arguments[e];
|
|
21
|
-
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
|
|
22
|
-
}
|
|
23
|
-
return n;
|
|
24
|
-
}, _extends.apply(null, arguments);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
18
|
const locale$1 = {
|
|
28
19
|
'Header.today': '今天',
|
|
29
20
|
'Header.prevMonth': '上一月',
|
|
@@ -36,16 +27,19 @@ const locale$1 = {
|
|
|
36
27
|
'PanelTitle.dateLabel': '{year}年{monthName}{day}日',
|
|
37
28
|
'PanelTitle.eventCount': '共 {count} 个日程',
|
|
38
29
|
'ViewPanel.empty': '暂无日程',
|
|
39
|
-
'SchedulePanel.selectFreeSlot': '
|
|
40
|
-
'SchedulePanel.newSchedule': '新增日程:{range}',
|
|
30
|
+
'SchedulePanel.selectFreeSlot': '点击或拖拽空白处选择时间',
|
|
41
31
|
'SchedulePanel.cancel': '取消',
|
|
42
32
|
'SchedulePanel.save': '保存',
|
|
43
|
-
'
|
|
44
|
-
'
|
|
33
|
+
'SchedulePanel.newScheduleTitle': '新增日程',
|
|
34
|
+
'SchedulePanel.conflict': '与 {count} 个日程时间冲突',
|
|
45
35
|
'DefaultFormInner.title': '标题',
|
|
46
36
|
'DefaultFormInner.titlePlaceholder': '请输入日程标题',
|
|
47
37
|
'DefaultFormInner.detail': '详情',
|
|
48
38
|
'DefaultFormInner.detailPlaceholder': '请输入日程详情',
|
|
39
|
+
'TimeWindow.hours': '{count} 小时',
|
|
40
|
+
'TimeWindow.minutes': '{count} 分钟',
|
|
41
|
+
'TimeWindow.editable': '允许编辑',
|
|
42
|
+
'TimeWindow.locked': '已锁定',
|
|
49
43
|
'Calendar.month.1': '1月',
|
|
50
44
|
'Calendar.month.2': '2月',
|
|
51
45
|
'Calendar.month.3': '3月',
|
|
@@ -72,16 +66,19 @@ const locale = {
|
|
|
72
66
|
'PanelTitle.dateLabel': '{monthName} {day}, {year}',
|
|
73
67
|
'PanelTitle.eventCount': '{count} events',
|
|
74
68
|
'ViewPanel.empty': 'No events',
|
|
75
|
-
'SchedulePanel.selectFreeSlot': '
|
|
76
|
-
'SchedulePanel.newSchedule': 'New event: {range}',
|
|
69
|
+
'SchedulePanel.selectFreeSlot': 'Click or drag on free time',
|
|
77
70
|
'SchedulePanel.cancel': 'Cancel',
|
|
78
71
|
'SchedulePanel.save': 'Save',
|
|
79
|
-
'
|
|
80
|
-
'
|
|
72
|
+
'SchedulePanel.newScheduleTitle': 'New event',
|
|
73
|
+
'SchedulePanel.conflict': 'Overlaps {count} event(s)',
|
|
81
74
|
'DefaultFormInner.title': 'Title',
|
|
82
75
|
'DefaultFormInner.titlePlaceholder': 'Enter event title',
|
|
83
76
|
'DefaultFormInner.detail': 'Details',
|
|
84
77
|
'DefaultFormInner.detailPlaceholder': 'Enter event details',
|
|
78
|
+
'TimeWindow.hours': '{count} h',
|
|
79
|
+
'TimeWindow.minutes': '{count} min',
|
|
80
|
+
'TimeWindow.editable': 'Editable',
|
|
81
|
+
'TimeWindow.locked': 'Locked',
|
|
85
82
|
'Calendar.month.1': 'Jan',
|
|
86
83
|
'Calendar.month.2': 'Feb',
|
|
87
84
|
'Calendar.month.3': 'Mar',
|
|
@@ -173,23 +170,23 @@ const toDayjs = value => {
|
|
|
173
170
|
};
|
|
174
171
|
const parseDayTime = (date, time) => {
|
|
175
172
|
const day = toDayjs(date) || dayjs__default["default"]();
|
|
176
|
-
const parsed = dayjs__default["default"](day.format(DATE_FORMAT)
|
|
173
|
+
const parsed = dayjs__default["default"](`${day.format(DATE_FORMAT)} ${time}`, `${DATE_FORMAT} ${TIME_FORMAT}`);
|
|
177
174
|
return parsed.isValid() ? parsed : day.startOf('day');
|
|
178
175
|
};
|
|
179
|
-
const formatRange = (start, end) => dayjs__default["default"](start).format(TIME_FORMAT)
|
|
176
|
+
const formatRange = (start, end) => `${dayjs__default["default"](start).format(TIME_FORMAT)} - ${dayjs__default["default"](end).format(TIME_FORMAT)}`;
|
|
180
177
|
const getDefaultFormValues = (defaultFormValues, ctx) => {
|
|
181
178
|
if (typeof defaultFormValues === 'function') {
|
|
182
179
|
return defaultFormValues(ctx);
|
|
183
180
|
}
|
|
184
|
-
return
|
|
181
|
+
return {
|
|
185
182
|
title: '',
|
|
186
|
-
detail: ''
|
|
187
|
-
|
|
183
|
+
detail: '',
|
|
184
|
+
...(defaultFormValues || {})
|
|
185
|
+
};
|
|
188
186
|
};
|
|
189
187
|
const sortEventsByStart = events => [...(events || [])].sort((a, b) => {
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
const bStart = (_toDayjs$valueOf2 = (_toDayjs2 = toDayjs(b.start)) == null ? void 0 : _toDayjs2.valueOf()) != null ? _toDayjs$valueOf2 : 0;
|
|
188
|
+
const aStart = toDayjs(a.start)?.valueOf() ?? 0;
|
|
189
|
+
const bStart = toDayjs(b.start)?.valueOf() ?? 0;
|
|
193
190
|
return aStart - bStart;
|
|
194
191
|
});
|
|
195
192
|
const dedupeEventsById = events => {
|
|
@@ -200,9 +197,11 @@ const dedupeEventsById = events => {
|
|
|
200
197
|
return [...map.values()];
|
|
201
198
|
};
|
|
202
199
|
const useControlledState = _ref => {
|
|
203
|
-
let
|
|
204
|
-
|
|
205
|
-
|
|
200
|
+
let {
|
|
201
|
+
value,
|
|
202
|
+
defaultValue,
|
|
203
|
+
onChange
|
|
204
|
+
} = _ref;
|
|
206
205
|
const props = {};
|
|
207
206
|
if (typeof value !== 'undefined') {
|
|
208
207
|
props.value = value;
|
|
@@ -234,14 +233,15 @@ const getRuleDisabled = (result, defaultReason) => {
|
|
|
234
233
|
}
|
|
235
234
|
return null;
|
|
236
235
|
};
|
|
237
|
-
const checkRule =
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
236
|
+
const checkRule = _ref => {
|
|
237
|
+
let {
|
|
238
|
+
date,
|
|
239
|
+
slot,
|
|
240
|
+
mode,
|
|
241
|
+
disabledDate,
|
|
242
|
+
disabledDateTime,
|
|
243
|
+
availableDateTime
|
|
244
|
+
} = _ref;
|
|
245
245
|
if (disabledDate?.(date.toDate())) {
|
|
246
246
|
return {
|
|
247
247
|
disabled: true
|
|
@@ -272,10 +272,11 @@ const checkRule = ({
|
|
|
272
272
|
const normalizeEvent = event => {
|
|
273
273
|
const start = toDayjs(event.start || event.date);
|
|
274
274
|
const end = toDayjs(event.end || event.start || event.date);
|
|
275
|
-
return
|
|
275
|
+
return {
|
|
276
|
+
...event,
|
|
276
277
|
start,
|
|
277
278
|
end: end && start && !end.isAfter(start) ? start.add(1, 'minute') : end
|
|
278
|
-
}
|
|
279
|
+
};
|
|
279
280
|
};
|
|
280
281
|
const groupEventsByDate = events => {
|
|
281
282
|
return (events || []).reduce((result, event) => {
|
|
@@ -309,19 +310,17 @@ const getOverlappingEvents = (slotStart, slotEnd, sortedEvents) => {
|
|
|
309
310
|
return matched;
|
|
310
311
|
};
|
|
311
312
|
const generateTimeSlots = _ref => {
|
|
312
|
-
let
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
timeUnit =
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
_ref$mode = _ref.mode,
|
|
324
|
-
mode = _ref$mode === void 0 ? 'schedule' : _ref$mode;
|
|
313
|
+
let {
|
|
314
|
+
date,
|
|
315
|
+
events,
|
|
316
|
+
timeUnit = 30,
|
|
317
|
+
dayStart = '09:00',
|
|
318
|
+
dayEnd = '18:00',
|
|
319
|
+
disabledDate,
|
|
320
|
+
disabledDateTime,
|
|
321
|
+
availableDateTime,
|
|
322
|
+
mode = 'schedule'
|
|
323
|
+
} = _ref;
|
|
325
324
|
const selectedDate = toDayjs(date) || dayjs__default["default"]();
|
|
326
325
|
const startAt = parseDayTime(selectedDate, dayStart);
|
|
327
326
|
const endAt = parseDayTime(selectedDate, dayEnd);
|
|
@@ -336,7 +335,7 @@ const generateTimeSlots = _ref => {
|
|
|
336
335
|
const slotEnd = slotStart.add(timeUnit, 'minute');
|
|
337
336
|
const matchedEvents = getOverlappingEvents(slotStart, slotEnd, normalizedEvents);
|
|
338
337
|
const baseSlot = {
|
|
339
|
-
key: slotStart.format(DATE_FORMAT)
|
|
338
|
+
key: `${slotStart.format(DATE_FORMAT)}-${slotStart.format(TIME_FORMAT)}`,
|
|
340
339
|
date: slotStart.format(DATE_FORMAT),
|
|
341
340
|
start: slotStart,
|
|
342
341
|
end: slotEnd
|
|
@@ -349,13 +348,14 @@ const generateTimeSlots = _ref => {
|
|
|
349
348
|
disabledDateTime,
|
|
350
349
|
availableDateTime
|
|
351
350
|
});
|
|
352
|
-
slots.push(
|
|
351
|
+
slots.push({
|
|
352
|
+
...baseSlot,
|
|
353
353
|
start: slotStart.toDate(),
|
|
354
354
|
end: slotEnd.toDate(),
|
|
355
355
|
status: ruleResult ? 'disabled' : matchedEvents.length > 0 ? 'occupied' : 'free',
|
|
356
|
-
disabledReason: ruleResult
|
|
356
|
+
disabledReason: ruleResult?.reason,
|
|
357
357
|
events: matchedEvents
|
|
358
|
-
})
|
|
358
|
+
});
|
|
359
359
|
current = slotEnd;
|
|
360
360
|
}
|
|
361
361
|
return slots;
|
|
@@ -394,13 +394,13 @@ const getMonthPickerItemLabel = (formatMessage, value, monthIndex) => formatMess
|
|
|
394
394
|
monthName: getMonthName(formatMessage, monthIndex)
|
|
395
395
|
});
|
|
396
396
|
|
|
397
|
-
var style$
|
|
397
|
+
var style$5 = {"calendar-header":"kne-react-calendar_X1TYG","calendar-title":"kne-react-calendar_FcQis","calendar-title-part":"kne-react-calendar_LcyYv","header-picker-popover":"kne-react-calendar_T4oWB","picker-panel":"kne-react-calendar_PMS-M","picker-panel-header":"kne-react-calendar_IXQKl","picker-panel-range":"kne-react-calendar_J-Pnh","picker-panel-nav":"kne-react-calendar_Wo74w","picker-panel-nav-icon":"kne-react-calendar_Rwzuj","picker-panel-grid":"kne-react-calendar_rxTOr","picker-cell":"kne-react-calendar_bHuh6","picker-cell-active":"kne-react-calendar_xOfrO","header-actions":"kne-react-calendar_OCJaK","header-today":"kne-react-calendar_SWVUG","header-nav":"kne-react-calendar_BOheC","header-nav-icon":"kne-react-calendar_8IEwS"};
|
|
398
398
|
|
|
399
399
|
const HeaderNavIcon = ({
|
|
400
400
|
direction,
|
|
401
401
|
className
|
|
402
402
|
}) => /*#__PURE__*/jsxRuntime.jsx("svg", {
|
|
403
|
-
className: className || style$
|
|
403
|
+
className: className || style$5['header-nav-icon'],
|
|
404
404
|
viewBox: "0 0 16 16",
|
|
405
405
|
"aria-hidden": true,
|
|
406
406
|
focusable: "false",
|
|
@@ -423,7 +423,7 @@ const PickerPanelNav = ({
|
|
|
423
423
|
children
|
|
424
424
|
}) => /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
425
425
|
type: "button",
|
|
426
|
-
className: style$
|
|
426
|
+
className: style$5['picker-panel-nav'],
|
|
427
427
|
"aria-label": label,
|
|
428
428
|
onClick: onClick,
|
|
429
429
|
children: children
|
|
@@ -441,9 +441,9 @@ const YearPickerPanel = ({
|
|
|
441
441
|
length: YEAR_PAGE_SIZE
|
|
442
442
|
}, (_, index) => pageStart + index), [pageStart]);
|
|
443
443
|
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
444
|
-
className: style$
|
|
444
|
+
className: style$5['picker-panel'],
|
|
445
445
|
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
446
|
-
className: style$
|
|
446
|
+
className: style$5['picker-panel-header'],
|
|
447
447
|
children: [/*#__PURE__*/jsxRuntime.jsx(PickerPanelNav, {
|
|
448
448
|
label: formatMessage({
|
|
449
449
|
id: 'Header.prevYearPage'
|
|
@@ -451,10 +451,10 @@ const YearPickerPanel = ({
|
|
|
451
451
|
onClick: () => onPageStartChange(pageStart - YEAR_PAGE_SIZE),
|
|
452
452
|
children: /*#__PURE__*/jsxRuntime.jsx(HeaderNavIcon, {
|
|
453
453
|
direction: "prev",
|
|
454
|
-
className: style$
|
|
454
|
+
className: style$5['picker-panel-nav-icon']
|
|
455
455
|
})
|
|
456
456
|
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
457
|
-
className: style$
|
|
457
|
+
className: style$5['picker-panel-range'],
|
|
458
458
|
children: [pageStart, "-", pageStart + YEAR_PAGE_SIZE - 1]
|
|
459
459
|
}), /*#__PURE__*/jsxRuntime.jsx(PickerPanelNav, {
|
|
460
460
|
label: formatMessage({
|
|
@@ -463,15 +463,15 @@ const YearPickerPanel = ({
|
|
|
463
463
|
onClick: () => onPageStartChange(pageStart + YEAR_PAGE_SIZE),
|
|
464
464
|
children: /*#__PURE__*/jsxRuntime.jsx(HeaderNavIcon, {
|
|
465
465
|
direction: "next",
|
|
466
|
-
className: style$
|
|
466
|
+
className: style$5['picker-panel-nav-icon']
|
|
467
467
|
})
|
|
468
468
|
})]
|
|
469
469
|
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
470
|
-
className: style$
|
|
470
|
+
className: style$5['picker-panel-grid'],
|
|
471
471
|
children: years.map(year => /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
472
472
|
type: "button",
|
|
473
|
-
className: classNames(style$
|
|
474
|
-
[style$
|
|
473
|
+
className: classNames(style$5['picker-cell'], {
|
|
474
|
+
[style$5['picker-cell-active']]: year === value.year()
|
|
475
475
|
}),
|
|
476
476
|
onClick: () => onSelect(year),
|
|
477
477
|
children: year
|
|
@@ -491,13 +491,13 @@ const MonthPickerPanel = ({
|
|
|
491
491
|
length: 12
|
|
492
492
|
}, (_, index) => index), []);
|
|
493
493
|
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
494
|
-
className: style$
|
|
494
|
+
className: style$5['picker-panel'],
|
|
495
495
|
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
496
|
-
className: style$
|
|
496
|
+
className: style$5['picker-panel-grid'],
|
|
497
497
|
children: months.map(month => /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
498
498
|
type: "button",
|
|
499
|
-
className: classNames(style$
|
|
500
|
-
[style$
|
|
499
|
+
className: classNames(style$5['picker-cell'], {
|
|
500
|
+
[style$5['picker-cell-active']]: month === value.month()
|
|
501
501
|
}),
|
|
502
502
|
onClick: () => onSelect(month),
|
|
503
503
|
children: getMonthPickerItemLabel(formatMessage, value, month)
|
|
@@ -506,23 +506,27 @@ const MonthPickerPanel = ({
|
|
|
506
506
|
});
|
|
507
507
|
};
|
|
508
508
|
|
|
509
|
-
const HeaderNavButton =
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
509
|
+
const HeaderNavButton = _ref => {
|
|
510
|
+
let {
|
|
511
|
+
label,
|
|
512
|
+
onClick,
|
|
513
|
+
children
|
|
514
|
+
} = _ref;
|
|
515
|
+
return /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
516
|
+
type: "button",
|
|
517
|
+
className: style$5['header-nav'],
|
|
518
|
+
"aria-label": label,
|
|
519
|
+
onClick: onClick,
|
|
520
|
+
children: children
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
const Header = _ref2 => {
|
|
524
|
+
let {
|
|
525
|
+
current,
|
|
526
|
+
showTodayButton,
|
|
527
|
+
onCurrentChange,
|
|
528
|
+
onSelectToday
|
|
529
|
+
} = _ref2;
|
|
526
530
|
const {
|
|
527
531
|
formatMessage
|
|
528
532
|
} = reactIntl.useIntl();
|
|
@@ -555,9 +559,9 @@ const Header = ({
|
|
|
555
559
|
setMonthOpen(false);
|
|
556
560
|
};
|
|
557
561
|
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
558
|
-
className: style$
|
|
562
|
+
className: style$5['calendar-header'],
|
|
559
563
|
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
560
|
-
className: style$
|
|
564
|
+
className: style$5['calendar-title'],
|
|
561
565
|
children: [/*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
|
|
562
566
|
open: yearOpen,
|
|
563
567
|
onOpenChange: open => {
|
|
@@ -568,7 +572,7 @@ const Header = ({
|
|
|
568
572
|
},
|
|
569
573
|
trigger: "click",
|
|
570
574
|
placement: "bottomLeft",
|
|
571
|
-
rootClassName: style$
|
|
575
|
+
rootClassName: style$5['header-picker-popover'],
|
|
572
576
|
content: /*#__PURE__*/jsxRuntime.jsx(YearPickerPanel, {
|
|
573
577
|
value: date,
|
|
574
578
|
pageStart: yearPageStart,
|
|
@@ -577,7 +581,7 @@ const Header = ({
|
|
|
577
581
|
}),
|
|
578
582
|
children: /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
579
583
|
type: "button",
|
|
580
|
-
className: style$
|
|
584
|
+
className: style$5['calendar-title-part'],
|
|
581
585
|
children: yearText
|
|
582
586
|
})
|
|
583
587
|
}), /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
|
|
@@ -590,22 +594,22 @@ const Header = ({
|
|
|
590
594
|
},
|
|
591
595
|
trigger: "click",
|
|
592
596
|
placement: "bottomLeft",
|
|
593
|
-
rootClassName: style$
|
|
597
|
+
rootClassName: style$5['header-picker-popover'],
|
|
594
598
|
content: /*#__PURE__*/jsxRuntime.jsx(MonthPickerPanel, {
|
|
595
599
|
value: date,
|
|
596
600
|
onSelect: handleMonthSelect
|
|
597
601
|
}),
|
|
598
602
|
children: /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
599
603
|
type: "button",
|
|
600
|
-
className: style$
|
|
604
|
+
className: style$5['calendar-title-part'],
|
|
601
605
|
children: monthText
|
|
602
606
|
})
|
|
603
607
|
})]
|
|
604
608
|
}), /*#__PURE__*/jsxRuntime.jsxs(antd.Space, {
|
|
605
609
|
size: 4,
|
|
606
|
-
className: style$
|
|
610
|
+
className: style$5['header-actions'],
|
|
607
611
|
children: [showTodayButton ? /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
|
|
608
|
-
className: style$
|
|
612
|
+
className: style$5['header-today'],
|
|
609
613
|
type: "text",
|
|
610
614
|
size: "small",
|
|
611
615
|
onClick: onSelectToday,
|
|
@@ -672,17 +676,18 @@ const useStackedLayout = (ref, stackAt) => {
|
|
|
672
676
|
return stacked;
|
|
673
677
|
};
|
|
674
678
|
|
|
675
|
-
var style$
|
|
679
|
+
var style$4 = {"date-cell":"kne-react-calendar_-a9AL","date-number":"kne-react-calendar_9s0kZ","date-has-events":"kne-react-calendar_-Bh5f","date-selected":"kne-react-calendar_Lpltl","date-muted":"kne-react-calendar_1xgRD","date-disabled":"kne-react-calendar_YTv16"};
|
|
676
680
|
|
|
677
|
-
const DateCell =
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
681
|
+
const DateCell = _ref => {
|
|
682
|
+
let {
|
|
683
|
+
date,
|
|
684
|
+
dayEvents,
|
|
685
|
+
selected,
|
|
686
|
+
currentMonth,
|
|
687
|
+
disabled,
|
|
688
|
+
badgeMaxCount,
|
|
689
|
+
renderDateCell
|
|
690
|
+
} = _ref;
|
|
686
691
|
const count = dayEvents.length;
|
|
687
692
|
const customCell = renderDateCell?.(date.toDate(), {
|
|
688
693
|
events: dayEvents,
|
|
@@ -693,14 +698,14 @@ const DateCell = ({
|
|
|
693
698
|
return customCell;
|
|
694
699
|
}
|
|
695
700
|
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
696
|
-
className: classNames(style$
|
|
697
|
-
[style$
|
|
698
|
-
[style$
|
|
699
|
-
[style$
|
|
700
|
-
[style$
|
|
701
|
+
className: classNames(style$4['date-cell'], {
|
|
702
|
+
[style$4['date-selected']]: selected,
|
|
703
|
+
[style$4['date-muted']]: !currentMonth && !selected,
|
|
704
|
+
[style$4['date-disabled']]: disabled && !selected,
|
|
705
|
+
[style$4['date-has-events']]: count > 0 && !selected
|
|
701
706
|
}),
|
|
702
707
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
703
|
-
className: style$
|
|
708
|
+
className: style$4['date-number'],
|
|
704
709
|
children: date.date()
|
|
705
710
|
}), count ? /*#__PURE__*/jsxRuntime.jsx(antd.Badge, {
|
|
706
711
|
count: count > badgeMaxCount ? `${badgeMaxCount}+` : count,
|
|
@@ -726,7 +731,7 @@ const getEventTagLabel = event => {
|
|
|
726
731
|
return null;
|
|
727
732
|
};
|
|
728
733
|
|
|
729
|
-
var style$
|
|
734
|
+
var style$3 = {"event-list-item":"kne-react-calendar_cGTpY","event-item":"kne-react-calendar_3gmHY","event-item-head":"kne-react-calendar_fa3Mn","event-item-tag":"kne-react-calendar_yALGf","event-item-time":"kne-react-calendar_1L-dA","event-item-title":"kne-react-calendar_ISKyA","event-item-detail":"kne-react-calendar_HzTU2","event-item-clickable":"kne-react-calendar_iiYOC","event-item-disabled":"kne-react-calendar_3sXqE"};
|
|
730
735
|
|
|
731
736
|
const EventItem = ({
|
|
732
737
|
event,
|
|
@@ -758,11 +763,11 @@ const EventItem = ({
|
|
|
758
763
|
};
|
|
759
764
|
const tagLabel = getEventTagLabel(event);
|
|
760
765
|
return /*#__PURE__*/jsxRuntime.jsx(antd.List.Item, {
|
|
761
|
-
className: style$
|
|
766
|
+
className: style$3['event-list-item'],
|
|
762
767
|
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
763
|
-
className: classNames(style$
|
|
764
|
-
[style$
|
|
765
|
-
[style$
|
|
768
|
+
className: classNames(style$3['event-item'], {
|
|
769
|
+
[style$3['event-item-clickable']]: clickable,
|
|
770
|
+
[style$3['event-item-disabled']]: event.disabled
|
|
766
771
|
}),
|
|
767
772
|
role: clickable ? 'button' : undefined,
|
|
768
773
|
tabIndex: clickable ? 0 : undefined,
|
|
@@ -774,27 +779,27 @@ const EventItem = ({
|
|
|
774
779
|
}
|
|
775
780
|
} : undefined,
|
|
776
781
|
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
777
|
-
className: style$
|
|
782
|
+
className: style$3['event-item-head'],
|
|
778
783
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
779
|
-
className: style$
|
|
784
|
+
className: style$3['event-item-title'],
|
|
780
785
|
children: event.title
|
|
781
786
|
}), tagLabel ? /*#__PURE__*/jsxRuntime.jsx(antd.Tag, {
|
|
782
|
-
className: style$
|
|
787
|
+
className: style$3['event-item-tag'],
|
|
783
788
|
color: event.color,
|
|
784
789
|
children: tagLabel
|
|
785
790
|
}) : null]
|
|
786
791
|
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
787
|
-
className: style$
|
|
792
|
+
className: style$3['event-item-time'],
|
|
788
793
|
children: formatRange(event.start, event.end)
|
|
789
794
|
}), event.detail ? /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
790
|
-
className: style$
|
|
795
|
+
className: style$3['event-item-detail'],
|
|
791
796
|
children: event.detail
|
|
792
797
|
}) : null]
|
|
793
798
|
})
|
|
794
799
|
});
|
|
795
800
|
};
|
|
796
801
|
|
|
797
|
-
var panelStyle = {"panel-card":"kne-react-calendar_uQsUE","panel-scroll-body":"kne-react-calendar_ujAl5","panel-scroll-content":"kne-react-calendar_t2e0j","panel-spin":"kne-react-calendar_tLux2","panel-spin-container":"kne-react-calendar_iW4mn","panel-title":"kne-react-calendar_C6NB3","panel-scroll-shadow":"kne-react-calendar_3ecxf","panel-scroll-shadow-visible":"kne-react-calendar_TvxhV","detail-card":"kne-react-calendar_3sEou"};
|
|
802
|
+
var panelStyle = {"panel-card":"kne-react-calendar_uQsUE","panel-scroll-body":"kne-react-calendar_ujAl5","panel-scroll-content":"kne-react-calendar_t2e0j","panel-spin":"kne-react-calendar_tLux2","panel-spin-container":"kne-react-calendar_iW4mn","panel-card-expanded":"kne-react-calendar_OzKbW","panel-scroll-body-expanded":"kne-react-calendar_jmktP","panel-title":"kne-react-calendar_C6NB3","panel-scroll-shadow":"kne-react-calendar_3ecxf","panel-scroll-shadow-visible":"kne-react-calendar_TvxhV","detail-card":"kne-react-calendar_3sEou"};
|
|
798
803
|
|
|
799
804
|
const PanelTitle = ({
|
|
800
805
|
date,
|
|
@@ -846,14 +851,16 @@ const usePanelScrollShadow = (resetKey, scrollRef) => {
|
|
|
846
851
|
};
|
|
847
852
|
};
|
|
848
853
|
|
|
849
|
-
const ViewPanel =
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
854
|
+
const ViewPanel = _ref => {
|
|
855
|
+
let {
|
|
856
|
+
date,
|
|
857
|
+
events,
|
|
858
|
+
loading,
|
|
859
|
+
renderEventItem,
|
|
860
|
+
renderPanelHeader,
|
|
861
|
+
onEventClick,
|
|
862
|
+
scrollable = true
|
|
863
|
+
} = _ref;
|
|
857
864
|
const {
|
|
858
865
|
formatMessage
|
|
859
866
|
} = reactIntl.useIntl();
|
|
@@ -874,7 +881,7 @@ const ViewPanel = ({
|
|
|
874
881
|
date: date,
|
|
875
882
|
count: sortedEvents.length
|
|
876
883
|
}),
|
|
877
|
-
className: panelStyle['panel-card'],
|
|
884
|
+
className: classNames(panelStyle['panel-card'], !scrollable && panelStyle['panel-card-expanded']),
|
|
878
885
|
children: /*#__PURE__*/jsxRuntime.jsx(antd.Spin, {
|
|
879
886
|
spinning: !!loading,
|
|
880
887
|
classNames: {
|
|
@@ -883,11 +890,11 @@ const ViewPanel = ({
|
|
|
883
890
|
},
|
|
884
891
|
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
885
892
|
ref: scrollRef,
|
|
886
|
-
className: panelStyle['panel-scroll-body'],
|
|
887
|
-
onScroll: onScroll,
|
|
888
|
-
children: [/*#__PURE__*/jsxRuntime.jsx(PanelScrollShadow, {
|
|
893
|
+
className: classNames(panelStyle['panel-scroll-body'], !scrollable && panelStyle['panel-scroll-body-expanded']),
|
|
894
|
+
onScroll: scrollable ? onScroll : undefined,
|
|
895
|
+
children: [scrollable ? /*#__PURE__*/jsxRuntime.jsx(PanelScrollShadow, {
|
|
889
896
|
visible: scrolled
|
|
890
|
-
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
897
|
+
}) : null, /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
891
898
|
className: panelStyle['panel-scroll-content'],
|
|
892
899
|
children: sortedEvents.length ? /*#__PURE__*/jsxRuntime.jsx(antd.List, {
|
|
893
900
|
dataSource: sortedEvents,
|
|
@@ -909,448 +916,1468 @@ const ViewPanel = ({
|
|
|
909
916
|
});
|
|
910
917
|
};
|
|
911
918
|
|
|
912
|
-
const
|
|
913
|
-
const
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
const getSlotIndexFromPoint = (container, clientX, clientY) => {
|
|
917
|
-
const slotElements = container?.querySelectorAll?.('[data-slot-index]');
|
|
918
|
-
if (!slotElements?.length) {
|
|
919
|
-
return null;
|
|
919
|
+
const MINUTE_MS$1 = 60 * 1000;
|
|
920
|
+
const toMs = value => {
|
|
921
|
+
if (value === null || typeof value === 'undefined') {
|
|
922
|
+
return NaN;
|
|
920
923
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
924
|
+
if (typeof value === 'number') {
|
|
925
|
+
return value;
|
|
926
|
+
}
|
|
927
|
+
const date = dayjs__default["default"](value);
|
|
928
|
+
return date.isValid() ? date.valueOf() : NaN;
|
|
929
|
+
};
|
|
930
|
+
const snapToStep = (ms, {
|
|
931
|
+
originMs,
|
|
932
|
+
stepMs,
|
|
933
|
+
mode = 'round'
|
|
934
|
+
}) => {
|
|
935
|
+
const fn = mode === 'floor' ? Math.floor : mode === 'ceil' ? Math.ceil : Math.round;
|
|
936
|
+
return originMs + fn((ms - originMs) / stepMs) * stepMs;
|
|
937
|
+
};
|
|
938
|
+
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Clip events to the day window and lay overlapping ones out side by side.
|
|
942
|
+
* Returns `{ event, startMs, endMs, column, columns }` sorted by start.
|
|
943
|
+
*/
|
|
944
|
+
const layoutTimelineEvents = (events, {
|
|
945
|
+
startMs,
|
|
946
|
+
endMs
|
|
947
|
+
}) => {
|
|
948
|
+
const items = (events || []).map(event => {
|
|
949
|
+
const s = Math.max(toMs(event.start), startMs);
|
|
950
|
+
const e = Math.min(toMs(event.end), endMs);
|
|
951
|
+
return {
|
|
952
|
+
event,
|
|
953
|
+
startMs: s,
|
|
954
|
+
endMs: e
|
|
955
|
+
};
|
|
956
|
+
}).filter(item => Number.isFinite(item.startMs) && Number.isFinite(item.endMs) && item.endMs > item.startMs).sort((a, b) => a.startMs - b.startMs || b.endMs - a.endMs);
|
|
957
|
+
let cluster = [];
|
|
958
|
+
let clusterEnd = -Infinity;
|
|
959
|
+
let columnEnds = [];
|
|
960
|
+
const flush = () => {
|
|
961
|
+
cluster.forEach(item => {
|
|
962
|
+
item.columns = columnEnds.length;
|
|
963
|
+
});
|
|
964
|
+
cluster = [];
|
|
965
|
+
columnEnds = [];
|
|
966
|
+
};
|
|
967
|
+
items.forEach(item => {
|
|
968
|
+
if (item.startMs >= clusterEnd) {
|
|
969
|
+
flush();
|
|
970
|
+
clusterEnd = -Infinity;
|
|
928
971
|
}
|
|
929
|
-
|
|
930
|
-
|
|
972
|
+
let column = columnEnds.findIndex(end => end <= item.startMs);
|
|
973
|
+
if (column === -1) {
|
|
974
|
+
column = columnEnds.length;
|
|
975
|
+
columnEnds.push(item.endMs);
|
|
976
|
+
} else {
|
|
977
|
+
columnEnds[column] = item.endMs;
|
|
931
978
|
}
|
|
932
|
-
|
|
933
|
-
|
|
979
|
+
item.column = column;
|
|
980
|
+
cluster.push(item);
|
|
981
|
+
clusterEnd = Math.max(clusterEnd, item.endMs);
|
|
982
|
+
});
|
|
983
|
+
flush();
|
|
984
|
+
return items;
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
/** Merge consecutive disabled slots (same reason) into ranges. */
|
|
988
|
+
const mergeDisabledSlots = slots => {
|
|
989
|
+
const ranges = [];
|
|
990
|
+
(slots || []).forEach(slot => {
|
|
991
|
+
if (slot.status !== 'disabled') {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
const startMs = toMs(slot.start);
|
|
995
|
+
const endMs = toMs(slot.end);
|
|
996
|
+
const last = ranges[ranges.length - 1];
|
|
997
|
+
if (last && last.endMs === startMs && last.reason === slot.disabledReason) {
|
|
998
|
+
last.endMs = endMs;
|
|
999
|
+
return;
|
|
934
1000
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1001
|
+
ranges.push({
|
|
1002
|
+
startMs,
|
|
1003
|
+
endMs,
|
|
1004
|
+
reason: slot.disabledReason
|
|
1005
|
+
});
|
|
1006
|
+
});
|
|
1007
|
+
return ranges;
|
|
1008
|
+
};
|
|
1009
|
+
const toBlockers = ranges => (ranges || []).map(range => ({
|
|
1010
|
+
startMs: toMs(range.startMs ?? range.start),
|
|
1011
|
+
endMs: toMs(range.endMs ?? range.end)
|
|
1012
|
+
})).filter(range => Number.isFinite(range.startMs) && Number.isFinite(range.endMs) && range.endMs > range.startMs).sort((a, b) => a.startMs - b.startMs);
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* The free gap around `ms` between blockers, bounded by the day window.
|
|
1016
|
+
* Returns null when `ms` falls inside a blocker.
|
|
1017
|
+
*/
|
|
1018
|
+
const getFreeGap = (ms, blockers, {
|
|
1019
|
+
startMs,
|
|
1020
|
+
endMs
|
|
1021
|
+
}) => {
|
|
1022
|
+
let gapStart = startMs;
|
|
1023
|
+
let gapEnd = endMs;
|
|
1024
|
+
for (const blocker of blockers || []) {
|
|
1025
|
+
if (blocker.startMs <= ms && ms < blocker.endMs) {
|
|
1026
|
+
return null;
|
|
1027
|
+
}
|
|
1028
|
+
if (blocker.endMs <= ms) {
|
|
1029
|
+
gapStart = Math.max(gapStart, blocker.endMs);
|
|
1030
|
+
} else if (blocker.startMs > ms) {
|
|
1031
|
+
gapEnd = Math.min(gapEnd, blocker.startMs);
|
|
940
1032
|
}
|
|
941
1033
|
}
|
|
942
|
-
|
|
1034
|
+
if (ms < startMs || ms >= endMs || gapEnd <= gapStart) {
|
|
1035
|
+
return null;
|
|
1036
|
+
}
|
|
1037
|
+
return {
|
|
1038
|
+
startMs: gapStart,
|
|
1039
|
+
endMs: gapEnd
|
|
1040
|
+
};
|
|
943
1041
|
};
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1042
|
+
|
|
1043
|
+
/** Range created by pressing at `anchorMs` and dragging to `pointerMs`, kept inside `gap`. */
|
|
1044
|
+
const createSelectionRange = ({
|
|
1045
|
+
anchorMs,
|
|
1046
|
+
pointerMs,
|
|
1047
|
+
gap,
|
|
1048
|
+
originMs,
|
|
1049
|
+
stepMs
|
|
1050
|
+
}) => {
|
|
1051
|
+
const anchorStart = clamp(snapToStep(anchorMs, {
|
|
1052
|
+
originMs,
|
|
1053
|
+
stepMs,
|
|
1054
|
+
mode: 'floor'
|
|
1055
|
+
}), gap.startMs, gap.endMs);
|
|
1056
|
+
const anchorEnd = Math.min(anchorStart + stepMs, gap.endMs);
|
|
1057
|
+
const pointer = clamp(pointerMs, gap.startMs, gap.endMs);
|
|
1058
|
+
if (pointer >= anchorStart) {
|
|
1059
|
+
const end = clamp(snapToStep(pointer, {
|
|
1060
|
+
originMs,
|
|
1061
|
+
stepMs,
|
|
1062
|
+
mode: 'ceil'
|
|
1063
|
+
}), anchorEnd, gap.endMs);
|
|
1064
|
+
return {
|
|
1065
|
+
startMs: anchorStart,
|
|
1066
|
+
endMs: end
|
|
1067
|
+
};
|
|
948
1068
|
}
|
|
1069
|
+
const start = clamp(snapToStep(pointer, {
|
|
1070
|
+
originMs,
|
|
1071
|
+
stepMs,
|
|
1072
|
+
mode: 'floor'
|
|
1073
|
+
}), gap.startMs, anchorStart);
|
|
1074
|
+
return {
|
|
1075
|
+
startMs: start,
|
|
1076
|
+
endMs: anchorEnd
|
|
1077
|
+
};
|
|
949
1078
|
};
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1079
|
+
|
|
1080
|
+
/** Default range for a single click: one `unitMs` block that contains the pointer, fitted into `gap`. */
|
|
1081
|
+
const clickSelectionRange = ({
|
|
1082
|
+
pointerMs,
|
|
1083
|
+
gap,
|
|
1084
|
+
originMs,
|
|
1085
|
+
unitMs
|
|
957
1086
|
}) => {
|
|
958
|
-
const
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
const
|
|
977
|
-
const
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1087
|
+
const duration = Math.min(unitMs, gap.endMs - gap.startMs);
|
|
1088
|
+
const start = clamp(snapToStep(pointerMs, {
|
|
1089
|
+
originMs,
|
|
1090
|
+
stepMs: unitMs,
|
|
1091
|
+
mode: 'floor'
|
|
1092
|
+
}), gap.startMs, gap.endMs - duration);
|
|
1093
|
+
return {
|
|
1094
|
+
startMs: start,
|
|
1095
|
+
endMs: start + duration
|
|
1096
|
+
};
|
|
1097
|
+
};
|
|
1098
|
+
const moveSelectionRange = ({
|
|
1099
|
+
range,
|
|
1100
|
+
deltaMs,
|
|
1101
|
+
gap,
|
|
1102
|
+
originMs,
|
|
1103
|
+
stepMs
|
|
1104
|
+
}) => {
|
|
1105
|
+
const duration = range.endMs - range.startMs;
|
|
1106
|
+
const start = clamp(snapToStep(range.startMs + deltaMs, {
|
|
1107
|
+
originMs,
|
|
1108
|
+
stepMs
|
|
1109
|
+
}), gap.startMs, gap.endMs - duration);
|
|
1110
|
+
return {
|
|
1111
|
+
startMs: start,
|
|
1112
|
+
endMs: start + duration
|
|
1113
|
+
};
|
|
1114
|
+
};
|
|
1115
|
+
const resizeSelectionRange = ({
|
|
1116
|
+
range,
|
|
1117
|
+
edge,
|
|
1118
|
+
pointerMs,
|
|
1119
|
+
gap,
|
|
1120
|
+
originMs,
|
|
1121
|
+
stepMs,
|
|
1122
|
+
minMs = stepMs
|
|
1123
|
+
}) => {
|
|
1124
|
+
const snapped = snapToStep(pointerMs, {
|
|
1125
|
+
originMs,
|
|
1126
|
+
stepMs
|
|
1127
|
+
});
|
|
1128
|
+
if (edge === 'start') {
|
|
1129
|
+
const start = clamp(snapped, gap.startMs, range.endMs - minMs);
|
|
1130
|
+
return {
|
|
1131
|
+
startMs: start,
|
|
1132
|
+
endMs: range.endMs
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
const end = clamp(snapped, range.startMs + minMs, gap.endMs);
|
|
1136
|
+
return {
|
|
1137
|
+
startMs: range.startMs,
|
|
1138
|
+
endMs: end
|
|
1139
|
+
};
|
|
1140
|
+
};
|
|
1141
|
+
const findOverlappingEvents = (range, events) => {
|
|
1142
|
+
if (!range) {
|
|
1143
|
+
return [];
|
|
1144
|
+
}
|
|
1145
|
+
return (events || []).filter(event => toMs(event.start) < range.endMs && toMs(event.end) > range.startMs);
|
|
1146
|
+
};
|
|
1147
|
+
const findOverlappingSlots = (range, slots) => {
|
|
1148
|
+
if (!range) {
|
|
1149
|
+
return [];
|
|
1150
|
+
}
|
|
1151
|
+
return (slots || []).filter(slot => toMs(slot.start) < range.endMs && toMs(slot.end) > range.startMs);
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
dayjs__default["default"].extend(customParseFormat__default["default"]);
|
|
1155
|
+
const DEFAULT_DURATION = 60;
|
|
1156
|
+
const DEFAULT_STEP = 1;
|
|
1157
|
+
const DEFAULT_DEBOUNCE_WAIT = 300;
|
|
1158
|
+
const DEFAULT_SEPARATOR = ' ~ ';
|
|
1159
|
+
const DEFAULT_FORMAT = ['YYYY-MM-DD HH:mm', 'HH:mm'];
|
|
1160
|
+
const DEFAULT_MIN_VISIBLE_SPAN = 360;
|
|
1161
|
+
const MINUTE_MS = 60 * 1000;
|
|
1162
|
+
const HOUR_MS = 60 * MINUTE_MS;
|
|
1163
|
+
const PARSE_FORMATS = ['YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm', 'YYYY-MM-DD'];
|
|
1164
|
+
const parseDateLike = value => {
|
|
1165
|
+
if (value == null || value === '') {
|
|
1166
|
+
return null;
|
|
1167
|
+
}
|
|
1168
|
+
if (dayjs__default["default"].isDayjs(value)) {
|
|
1169
|
+
return value.isValid() ? value : null;
|
|
1170
|
+
}
|
|
1171
|
+
const direct = dayjs__default["default"](value);
|
|
1172
|
+
if (direct.isValid()) {
|
|
1173
|
+
return direct;
|
|
1174
|
+
}
|
|
1175
|
+
if (typeof value === 'string') {
|
|
1176
|
+
const parsed = dayjs__default["default"](value, PARSE_FORMATS, true);
|
|
1177
|
+
return parsed.isValid() ? parsed : null;
|
|
1178
|
+
}
|
|
1179
|
+
return null;
|
|
1180
|
+
};
|
|
1181
|
+
const isEmptyBound = value => value == null || value === '';
|
|
1182
|
+
const defaultDayRange = now => {
|
|
1183
|
+
const day = (parseDateLike(now) || dayjs__default["default"]()).startOf('day');
|
|
1184
|
+
return [day, day.add(1, 'day')];
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* `null` 或 `[null, null]` 表示不限制;单侧为空表示该侧不限制;`undefined` 为当天全天。
|
|
1189
|
+
*/
|
|
1190
|
+
const resolveRange = function (range, now) {
|
|
1191
|
+
if (now === void 0) {
|
|
1192
|
+
now = dayjs__default["default"]();
|
|
1193
|
+
}
|
|
1194
|
+
if (range === null) {
|
|
1195
|
+
return [null, null];
|
|
1196
|
+
}
|
|
1197
|
+
if (!Array.isArray(range)) {
|
|
1198
|
+
return defaultDayRange(now);
|
|
1199
|
+
}
|
|
1200
|
+
const start = isEmptyBound(range[0]) ? null : parseDateLike(range[0]);
|
|
1201
|
+
const end = isEmptyBound(range[1]) ? null : parseDateLike(range[1]);
|
|
1202
|
+
const startInvalid = !isEmptyBound(range[0]) && !start;
|
|
1203
|
+
const endInvalid = !isEmptyBound(range[1]) && !end;
|
|
1204
|
+
if (startInvalid || endInvalid || start && end && !end.isAfter(start)) {
|
|
1205
|
+
return defaultDayRange(now);
|
|
1206
|
+
}
|
|
1207
|
+
return [start, end];
|
|
1208
|
+
};
|
|
1209
|
+
const resolveDuration = (duration, rangeStart, rangeEnd) => {
|
|
1210
|
+
const requested = Number(duration) > 0 ? Number(duration) : DEFAULT_DURATION;
|
|
1211
|
+
if (!rangeStart || !rangeEnd) {
|
|
1212
|
+
return requested;
|
|
1213
|
+
}
|
|
1214
|
+
const rangeMinutes = rangeEnd.diff(rangeStart, 'minute');
|
|
1215
|
+
if (rangeMinutes > 0 && requested > rangeMinutes) {
|
|
1216
|
+
return rangeMinutes;
|
|
1217
|
+
}
|
|
1218
|
+
return requested;
|
|
1219
|
+
};
|
|
1220
|
+
const resolveStep = step => Number(step) > 0 ? Number(step) : DEFAULT_STEP;
|
|
1221
|
+
const resolveVisibleSpan = _ref => {
|
|
1222
|
+
let {
|
|
1223
|
+
visibleSpan,
|
|
1224
|
+
duration,
|
|
1225
|
+
baseDuration = duration,
|
|
1226
|
+
rangeStart,
|
|
1227
|
+
rangeEnd
|
|
1228
|
+
} = _ref;
|
|
1229
|
+
const minimum = duration * 1.5;
|
|
1230
|
+
let span = Number(visibleSpan) > 0 ? Number(visibleSpan) : Math.max(baseDuration * 6, DEFAULT_MIN_VISIBLE_SPAN);
|
|
1231
|
+
if (rangeStart && rangeEnd && !(Number(visibleSpan) > 0)) {
|
|
1232
|
+
span = Math.min(span, rangeEnd.diff(rangeStart, 'minute'));
|
|
1233
|
+
}
|
|
1234
|
+
return Math.max(span, minimum);
|
|
1235
|
+
};
|
|
1236
|
+
const snapMs = function (ms, stepMs, mode) {
|
|
1237
|
+
if (mode === void 0) {
|
|
1238
|
+
mode = 'round';
|
|
1239
|
+
}
|
|
1240
|
+
const anchor = dayjs__default["default"](ms).startOf('day').valueOf();
|
|
1241
|
+
const units = (ms - anchor) / stepMs;
|
|
1242
|
+
const snapped = mode === 'floor' ? Math.floor(units) : mode === 'ceil' ? Math.ceil(units) : Math.round(units);
|
|
1243
|
+
return anchor + snapped * stepMs;
|
|
1244
|
+
};
|
|
1245
|
+
const clampWindowStart = (startInput, _ref2) => {
|
|
1246
|
+
let {
|
|
1247
|
+
rangeStart,
|
|
1248
|
+
rangeEnd,
|
|
1249
|
+
duration,
|
|
1250
|
+
step,
|
|
1251
|
+
snap = true,
|
|
1252
|
+
now
|
|
1253
|
+
} = _ref2;
|
|
1254
|
+
const durationMs = duration * MINUTE_MS;
|
|
1255
|
+
const minMs = rangeStart ? rangeStart.valueOf() : -Infinity;
|
|
1256
|
+
const maxMs = rangeEnd ? rangeEnd.valueOf() - durationMs : Infinity;
|
|
1257
|
+
if (maxMs <= minMs) {
|
|
1258
|
+
return dayjs__default["default"](minMs);
|
|
1259
|
+
}
|
|
1260
|
+
const fallback = rangeStart || parseDateLike(now) || dayjs__default["default"]();
|
|
1261
|
+
const start = parseDateLike(startInput) || fallback;
|
|
1262
|
+
const stepMs = step * MINUTE_MS;
|
|
1263
|
+
let target = snap ? snapMs(start.valueOf(), stepMs) : start.valueOf();
|
|
1264
|
+
if (target > maxMs) {
|
|
1265
|
+
target = snap ? snapMs(maxMs, stepMs, 'floor') : maxMs;
|
|
1266
|
+
}
|
|
1267
|
+
if (target < minMs) {
|
|
1268
|
+
target = snap ? snapMs(minMs, stepMs, 'ceil') : minMs;
|
|
1269
|
+
}
|
|
1270
|
+
return dayjs__default["default"](Math.min(Math.max(target, minMs), maxMs));
|
|
1271
|
+
};
|
|
1272
|
+
const createTimeWindow = function (_temp) {
|
|
1273
|
+
let {
|
|
1274
|
+
start,
|
|
1275
|
+
duration,
|
|
1276
|
+
range,
|
|
1277
|
+
step,
|
|
1278
|
+
now,
|
|
1279
|
+
snap = true
|
|
1280
|
+
} = _temp === void 0 ? {} : _temp;
|
|
1281
|
+
const [rangeStart, rangeEnd] = resolveRange(range, now);
|
|
1282
|
+
const resolvedDuration = resolveDuration(duration, rangeStart, rangeEnd);
|
|
1283
|
+
const resolvedStep = resolveStep(step);
|
|
1284
|
+
const windowStart = clampWindowStart(start == null ? null : start, {
|
|
1285
|
+
rangeStart,
|
|
1286
|
+
rangeEnd,
|
|
1287
|
+
duration: resolvedDuration,
|
|
1288
|
+
step: resolvedStep,
|
|
1289
|
+
snap,
|
|
1290
|
+
now
|
|
1291
|
+
});
|
|
1292
|
+
return {
|
|
1293
|
+
start: windowStart,
|
|
1294
|
+
end: windowStart.add(resolvedDuration, 'minute'),
|
|
1295
|
+
rangeStart,
|
|
1296
|
+
rangeEnd,
|
|
1297
|
+
duration: resolvedDuration,
|
|
1298
|
+
step: resolvedStep
|
|
1299
|
+
};
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
/**
|
|
1303
|
+
* 拖动窗口一侧边界:另一侧保持不动,拖动侧按 step 吸附,并受最短 / 最长时长与范围约束。
|
|
1304
|
+
*/
|
|
1305
|
+
const resizeTimeWindow = _ref3 => {
|
|
1306
|
+
let {
|
|
1307
|
+
edge,
|
|
1308
|
+
pointerMs,
|
|
1309
|
+
startMs,
|
|
1310
|
+
endMs,
|
|
1311
|
+
step,
|
|
1312
|
+
rangeStart,
|
|
1313
|
+
rangeEnd,
|
|
1314
|
+
minDuration,
|
|
1315
|
+
maxDuration
|
|
1316
|
+
} = _ref3;
|
|
1317
|
+
const stepMs = resolveStep(step) * MINUTE_MS;
|
|
1318
|
+
const minMs = (Number(minDuration) > 0 ? Number(minDuration) : resolveStep(step)) * MINUTE_MS;
|
|
1319
|
+
const maxMs = Number(maxDuration) > 0 ? Number(maxDuration) * MINUTE_MS : Infinity;
|
|
1320
|
+
const rangeStartMs = rangeStart ? dayjs__default["default"](rangeStart).valueOf() : -Infinity;
|
|
1321
|
+
const rangeEndMs = rangeEnd ? dayjs__default["default"](rangeEnd).valueOf() : Infinity;
|
|
1322
|
+
if (edge === 'start') {
|
|
1323
|
+
let next = snapMs(pointerMs, stepMs);
|
|
1324
|
+
next = Math.min(next, endMs - minMs);
|
|
1325
|
+
next = Math.max(next, endMs - maxMs, rangeStartMs);
|
|
1326
|
+
return {
|
|
1327
|
+
startMs: next,
|
|
1328
|
+
duration: (endMs - next) / MINUTE_MS
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
let next = snapMs(pointerMs, stepMs);
|
|
1332
|
+
next = Math.max(next, startMs + minMs);
|
|
1333
|
+
next = Math.min(next, startMs + maxMs, rangeEndMs);
|
|
1334
|
+
return {
|
|
1335
|
+
startMs,
|
|
1336
|
+
duration: (next - startMs) / MINUTE_MS
|
|
1337
|
+
};
|
|
1338
|
+
};
|
|
1339
|
+
const toWindowValue = window => [window.start.toDate(), window.end.toDate()];
|
|
1340
|
+
const getViewport = (_ref4, visibleSpanMinutes) => {
|
|
1341
|
+
let {
|
|
1342
|
+
startMs,
|
|
1343
|
+
duration
|
|
1344
|
+
} = _ref4;
|
|
1345
|
+
const spanMs = visibleSpanMinutes * MINUTE_MS;
|
|
1346
|
+
const centerMs = startMs + duration * MINUTE_MS / 2;
|
|
1347
|
+
return {
|
|
1348
|
+
startMs: centerMs - spanMs / 2,
|
|
1349
|
+
endMs: centerMs + spanMs / 2,
|
|
1350
|
+
spanMs
|
|
1351
|
+
};
|
|
1352
|
+
};
|
|
1353
|
+
const wheelDeltaToPx = _ref5 => {
|
|
1354
|
+
let {
|
|
1355
|
+
delta,
|
|
1356
|
+
deltaMode = 0,
|
|
1357
|
+
trackWidth
|
|
1358
|
+
} = _ref5;
|
|
1359
|
+
if (deltaMode === 1) {
|
|
1360
|
+
return delta * 16;
|
|
1361
|
+
}
|
|
1362
|
+
if (deltaMode === 2) {
|
|
1363
|
+
return delta * (trackWidth > 0 ? trackWidth : 1);
|
|
1364
|
+
}
|
|
1365
|
+
return delta;
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
/**
|
|
1369
|
+
* 把滚轮像素累加为整步数:步数与刻度尺比例一致,单次离散滚动至少移动一步。
|
|
1370
|
+
*/
|
|
1371
|
+
const consumeWheelSteps = _ref6 => {
|
|
1372
|
+
let {
|
|
1373
|
+
accumulatedPx,
|
|
1374
|
+
deltaPx,
|
|
1375
|
+
pxPerStep,
|
|
1376
|
+
discrete
|
|
1377
|
+
} = _ref6;
|
|
1378
|
+
const sameDirection = accumulatedPx === 0 || Math.sign(accumulatedPx) === Math.sign(deltaPx);
|
|
1379
|
+
const total = (sameDirection ? accumulatedPx : 0) + deltaPx;
|
|
1380
|
+
const perStep = pxPerStep > 0 ? pxPerStep : 1;
|
|
1381
|
+
let steps = Math.trunc(total / perStep) || 0;
|
|
1382
|
+
let rest = total - steps * perStep;
|
|
1383
|
+
if (steps === 0 && discrete && deltaPx !== 0) {
|
|
1384
|
+
steps = Math.sign(deltaPx);
|
|
1385
|
+
rest = 0;
|
|
1386
|
+
}
|
|
1387
|
+
return {
|
|
1388
|
+
steps,
|
|
1389
|
+
accumulatedPx: rest
|
|
1390
|
+
};
|
|
1391
|
+
};
|
|
1392
|
+
const DEFAULT_INERTIA_TIME_CONSTANT = 325;
|
|
1393
|
+
const VELOCITY_WINDOW_MS = 120;
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* `true` 为默认强度 1,数字为强度倍数,`false` / `0` 关闭。返回滑行衰减时间常数(ms),0 表示关闭。
|
|
1397
|
+
*/
|
|
1398
|
+
const resolveInertia = inertia => {
|
|
1399
|
+
if (inertia === false || inertia == null) {
|
|
1400
|
+
return inertia == null ? DEFAULT_INERTIA_TIME_CONSTANT : 0;
|
|
1401
|
+
}
|
|
1402
|
+
if (inertia === true) {
|
|
1403
|
+
return DEFAULT_INERTIA_TIME_CONSTANT;
|
|
1404
|
+
}
|
|
1405
|
+
const strength = Number(inertia);
|
|
1406
|
+
return strength > 0 ? DEFAULT_INERTIA_TIME_CONSTANT * strength : 0;
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* samples: [{ t, ms }],按时间顺序;返回最近一段内每毫秒移动的时间量。
|
|
1411
|
+
*/
|
|
1412
|
+
const estimateVelocity = (samples, now) => {
|
|
1413
|
+
if (!samples || samples.length < 2) {
|
|
1414
|
+
return 0;
|
|
1415
|
+
}
|
|
1416
|
+
const latest = samples[samples.length - 1];
|
|
1417
|
+
const reference = now == null ? latest.t : now;
|
|
1418
|
+
if (reference - latest.t > VELOCITY_WINDOW_MS / 2) {
|
|
1419
|
+
return 0;
|
|
1420
|
+
}
|
|
1421
|
+
const recent = samples.filter(sample => latest.t - sample.t <= VELOCITY_WINDOW_MS);
|
|
1422
|
+
if (recent.length < 2) {
|
|
1423
|
+
return 0;
|
|
1424
|
+
}
|
|
1425
|
+
const first = recent[0];
|
|
1426
|
+
const elapsed = latest.t - first.t;
|
|
1427
|
+
return elapsed > 0 ? (latest.ms - first.ms) / elapsed : 0;
|
|
1428
|
+
};
|
|
1429
|
+
const timeAtClientX = _ref7 => {
|
|
1430
|
+
let {
|
|
1431
|
+
clientX,
|
|
1432
|
+
rectLeft,
|
|
1433
|
+
rectWidth,
|
|
1434
|
+
rangeStartMs,
|
|
1435
|
+
rangeEndMs,
|
|
1436
|
+
grabOffsetMs = 0
|
|
1437
|
+
} = _ref7;
|
|
1438
|
+
const span = Math.max(rangeEndMs - rangeStartMs, 1);
|
|
1439
|
+
const width = rectWidth > 0 ? rectWidth : 1;
|
|
1440
|
+
const ratio = Math.min(Math.max((clientX - rectLeft) / width, 0), 1);
|
|
1441
|
+
return rangeStartMs + ratio * span - grabOffsetMs;
|
|
1442
|
+
};
|
|
1443
|
+
const formatTimeWindowParts = _ref8 => {
|
|
1444
|
+
let {
|
|
1445
|
+
start,
|
|
1446
|
+
end,
|
|
1447
|
+
format = DEFAULT_FORMAT
|
|
1448
|
+
} = _ref8;
|
|
1449
|
+
const startDate = parseDateLike(start);
|
|
1450
|
+
const endDate = parseDateLike(end);
|
|
1451
|
+
if (!startDate || !endDate || typeof format === 'function') {
|
|
1452
|
+
return null;
|
|
1453
|
+
}
|
|
1454
|
+
const formats = Array.isArray(format) ? format : [format, format];
|
|
1455
|
+
const startText = startDate.format(formats[0] || DEFAULT_FORMAT[0]);
|
|
1456
|
+
let endFormat = formats[1] || formats[0] || DEFAULT_FORMAT[1];
|
|
1457
|
+
const endAtMidnight = endDate.valueOf() === endDate.startOf('day').valueOf();
|
|
1458
|
+
if (format === DEFAULT_FORMAT && !endAtMidnight && !endDate.isSame(startDate, 'day')) {
|
|
1459
|
+
endFormat = 'MM-DD HH:mm';
|
|
1460
|
+
}
|
|
1461
|
+
return [startText, endDate.format(endFormat)];
|
|
1462
|
+
};
|
|
1463
|
+
const formatTimeWindow = _ref9 => {
|
|
1464
|
+
let {
|
|
1465
|
+
start,
|
|
1466
|
+
end,
|
|
1467
|
+
format = DEFAULT_FORMAT,
|
|
1468
|
+
separator = DEFAULT_SEPARATOR
|
|
1469
|
+
} = _ref9;
|
|
1470
|
+
if (typeof format === 'function') {
|
|
1471
|
+
const startDate = parseDateLike(start);
|
|
1472
|
+
const endDate = parseDateLike(end);
|
|
1473
|
+
return startDate && endDate ? format(startDate.toDate(), endDate.toDate()) : '';
|
|
1474
|
+
}
|
|
1475
|
+
const parts = formatTimeWindowParts({
|
|
1476
|
+
start,
|
|
1477
|
+
end,
|
|
1478
|
+
format
|
|
1479
|
+
});
|
|
1480
|
+
return parts ? `${parts[0]}${separator}${parts[1]}` : '';
|
|
1481
|
+
};
|
|
1482
|
+
const LABEL_INTERVALS = [1, 2, 3, 4, 6, 8, 12, 24];
|
|
1483
|
+
const pickLabelEvery = (pxPerHour, minLabelPx) => {
|
|
1484
|
+
if (!(pxPerHour > 0)) {
|
|
1485
|
+
return 3;
|
|
1486
|
+
}
|
|
1487
|
+
return LABEL_INTERVALS.find(every => pxPerHour * every >= minLabelPx) || 24;
|
|
1488
|
+
};
|
|
1489
|
+
const TICK_MINUTES = [1, 2, 5, 10, 15, 30, 60];
|
|
1490
|
+
const MIN_TICK_GAP_PX = 7;
|
|
1491
|
+
const pickTickMinutes = (pxPerHour, labelEvery) => {
|
|
1492
|
+
const fit = TICK_MINUTES.find(minutes => pxPerHour * minutes / 60 >= MIN_TICK_GAP_PX);
|
|
1493
|
+
return fit || labelEvery * 60;
|
|
1494
|
+
};
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* 只生成当前视窗 [viewStart, viewEnd] 内的刻度;`outOfRange` 标出超出可选范围的刻度。
|
|
1498
|
+
*/
|
|
1499
|
+
const buildScaleTicks = function (viewStart, viewEnd, _temp2) {
|
|
1500
|
+
let {
|
|
1501
|
+
trackWidth,
|
|
1502
|
+
rangeStart,
|
|
1503
|
+
rangeEnd,
|
|
1504
|
+
minLabelPx = 52
|
|
1505
|
+
} = _temp2 === void 0 ? {} : _temp2;
|
|
1506
|
+
const viewStartMs = dayjs__default["default"](viewStart).valueOf();
|
|
1507
|
+
const viewEndMs = dayjs__default["default"](viewEnd).valueOf();
|
|
1508
|
+
const span = viewEndMs - viewStartMs;
|
|
1509
|
+
if (span <= 0) {
|
|
1510
|
+
return [];
|
|
1511
|
+
}
|
|
1512
|
+
const pxPerHour = trackWidth > 0 ? trackWidth * HOUR_MS / span : 0;
|
|
1513
|
+
const labelEvery = trackWidth > 0 ? pickLabelEvery(pxPerHour, minLabelPx) : span / HOUR_MS <= 6 ? 1 : 3;
|
|
1514
|
+
const tickMinutes = trackWidth > 0 ? pickTickMinutes(pxPerHour, labelEvery) : 60;
|
|
1515
|
+
const tickMs = tickMinutes * MINUTE_MS;
|
|
1516
|
+
const rangeStartMs = rangeStart ? dayjs__default["default"](rangeStart).valueOf() : -Infinity;
|
|
1517
|
+
const rangeEndMs = rangeEnd ? dayjs__default["default"](rangeEnd).valueOf() : Infinity;
|
|
1518
|
+
const ticks = [];
|
|
1519
|
+
let cursorMs = snapMs(viewStartMs, tickMs, 'ceil');
|
|
1520
|
+
while (cursorMs <= viewEndMs) {
|
|
1521
|
+
const cursor = dayjs__default["default"](cursorMs);
|
|
1522
|
+
const major = cursor.minute() === 0;
|
|
1523
|
+
const midnight = major && cursor.hour() === 0;
|
|
1524
|
+
const minute = cursor.minute();
|
|
1525
|
+
const level = midnight ? 'day' : major ? 'hour' : minute === 30 ? 'half' : minute % 15 === 0 && tickMinutes < 15 ? 'quarter' : 'minute';
|
|
1526
|
+
ticks.push({
|
|
1527
|
+
key: cursorMs,
|
|
1528
|
+
ratio: (cursorMs - viewStartMs) / span,
|
|
1529
|
+
major,
|
|
1530
|
+
level,
|
|
1531
|
+
label: midnight ? cursor.format('MM-DD') : cursor.format('HH:mm'),
|
|
1532
|
+
showLabel: major && cursor.hour() % labelEvery === 0,
|
|
1533
|
+
outOfRange: cursorMs < rangeStartMs || cursorMs > rangeEndMs
|
|
1534
|
+
});
|
|
1535
|
+
cursorMs = snapMs(cursorMs + tickMs, tickMs);
|
|
1536
|
+
}
|
|
1537
|
+
return ticks;
|
|
1538
|
+
};
|
|
1539
|
+
const formatDurationParts = minutes => {
|
|
1540
|
+
const total = Math.max(Math.round(minutes), 0);
|
|
1541
|
+
return {
|
|
1542
|
+
hours: Math.floor(total / 60),
|
|
1543
|
+
minutes: total % 60
|
|
1544
|
+
};
|
|
1545
|
+
};
|
|
1546
|
+
|
|
1547
|
+
var style$2 = {"root":"kne-react-calendar_0I96A","root-large":"kne-react-calendar_eGwaj","root-small":"kne-react-calendar_h50YK","header":"kne-react-calendar_oV0dZ","label":"kne-react-calendar_ES-Jt","separator":"kne-react-calendar_TWzY7","actions":"kne-react-calendar_FiXT7","switch":"kne-react-calendar_uBaQO","switch-on":"kne-react-calendar_c1XaN","duration":"kne-react-calendar_UnlvI","scale":"kne-react-calendar_2q4r3","track":"kne-react-calendar_Psk8T","root-dragging":"kne-react-calendar_lDK6o","ticks":"kne-react-calendar_RAKOV","tick":"kne-react-calendar_0-sBN","tick-minute":"kne-react-calendar_KR68F","tick-quarter":"kne-react-calendar_KG7-G","tick-half":"kne-react-calendar_cxGhs","tick-hour":"kne-react-calendar_eLF-c","tick-day":"kne-react-calendar_bVU--","labels":"kne-react-calendar_ahayU","tick-out":"kne-react-calendar_Crt1q","track-wheel":"kne-react-calendar_6YDSw","cylinder":"kne-react-calendar_zo6Jy","shade":"kne-react-calendar_7IH3i","shade-start":"kne-react-calendar_jm61m","shade-end":"kne-react-calendar_H6JJo","window":"kne-react-calendar_FpwgD","window-resizable":"kne-react-calendar_zx86H","window-fixed":"kne-react-calendar_e3Rls","edge":"kne-react-calendar_XWaYx","edge-start":"kne-react-calendar_Lk0dI","edge-end":"kne-react-calendar_-iQoy","edge-active":"kne-react-calendar_U0aKK","root-resizing":"kne-react-calendar_59sUX","window-compact":"kne-react-calendar_kvOXQ","tick-label":"kne-react-calendar_4LHqw","tick-label-day":"kne-react-calendar_S5S1g","root-locked":"kne-react-calendar_A9Acq"};
|
|
1548
|
+
|
|
1549
|
+
const GRIP_MIN_WIDTH = 28;
|
|
1550
|
+
const CLICK_MOVE_TOLERANCE = 4;
|
|
1551
|
+
const DISCRETE_WHEEL_DELTA = 50;
|
|
1552
|
+
const VISUAL_EASE_MS = 70;
|
|
1553
|
+
const WHEEL_IDLE_MS = 140;
|
|
1554
|
+
const WHEEL_NOTCH_EASE_MS = 90;
|
|
1555
|
+
const WHEEL_INERTIA_SCALE = 0.6;
|
|
1556
|
+
const sameInstant = (left, right) => {
|
|
1557
|
+
const leftDate = parseDateLike(left);
|
|
1558
|
+
const rightDate = parseDateLike(right);
|
|
1559
|
+
if (!leftDate || !rightDate) {
|
|
1560
|
+
return false;
|
|
1561
|
+
}
|
|
1562
|
+
return Math.abs(leftDate.valueOf() - rightDate.valueOf()) < 1000;
|
|
1563
|
+
};
|
|
1564
|
+
const readWindowStart = value => {
|
|
1565
|
+
if (!Array.isArray(value)) {
|
|
1566
|
+
return null;
|
|
1567
|
+
}
|
|
1568
|
+
return parseDateLike(value[0]);
|
|
1569
|
+
};
|
|
1570
|
+
const isDiscreteWheel = (event, deltaPx) => {
|
|
1571
|
+
if (event.deltaMode !== 0) {
|
|
1572
|
+
return true;
|
|
1573
|
+
}
|
|
1574
|
+
const legacy = event.wheelDeltaY || event.wheelDeltaX;
|
|
1575
|
+
if (legacy && Math.abs(legacy) % 120 === 0) {
|
|
1576
|
+
return true;
|
|
1577
|
+
}
|
|
1578
|
+
return Math.abs(deltaPx) >= DISCRETE_WHEEL_DELTA;
|
|
1579
|
+
};
|
|
1580
|
+
const useElementWidth = ref => {
|
|
1581
|
+
const [width, setWidth] = react.useState(0);
|
|
1582
|
+
react.useEffect(() => {
|
|
1583
|
+
const node = ref.current;
|
|
1584
|
+
if (!node) {
|
|
1585
|
+
return undefined;
|
|
988
1586
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
container.scrollTop = scrollTop;
|
|
993
|
-
scrollLockRef.current = null;
|
|
994
|
-
}, []);
|
|
995
|
-
const lockContainerScroll = react.useCallback(() => {
|
|
996
|
-
const container = slotsRef.current;
|
|
997
|
-
if (!container || scrollLockRef.current != null) {
|
|
998
|
-
return;
|
|
1587
|
+
setWidth(node.getBoundingClientRect().width);
|
|
1588
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
1589
|
+
return undefined;
|
|
999
1590
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
const resetGestureState = react.useCallback(() => {
|
|
1005
|
-
clearLongPress();
|
|
1006
|
-
const container = slotsRef.current;
|
|
1007
|
-
const touchState = touchStateRef.current;
|
|
1008
|
-
if (container && touchState?.pointerId != null && container.hasPointerCapture?.(touchState.pointerId)) {
|
|
1009
|
-
try {
|
|
1010
|
-
container.releasePointerCapture(touchState.pointerId);
|
|
1011
|
-
} catch {
|
|
1012
|
-
// Ignore capture release errors on stale pointers.
|
|
1591
|
+
const observer = new ResizeObserver(entries => {
|
|
1592
|
+
const entry = entries[0];
|
|
1593
|
+
if (entry) {
|
|
1594
|
+
setWidth(entry.contentRect.width);
|
|
1013
1595
|
}
|
|
1596
|
+
});
|
|
1597
|
+
observer.observe(node);
|
|
1598
|
+
return () => observer.disconnect();
|
|
1599
|
+
}, [ref]);
|
|
1600
|
+
return width;
|
|
1601
|
+
};
|
|
1602
|
+
const TimeWindowInner = _ref => {
|
|
1603
|
+
let {
|
|
1604
|
+
value,
|
|
1605
|
+
defaultValue,
|
|
1606
|
+
onChange,
|
|
1607
|
+
duration,
|
|
1608
|
+
range,
|
|
1609
|
+
step,
|
|
1610
|
+
visibleSpan,
|
|
1611
|
+
debounceWait = DEFAULT_DEBOUNCE_WAIT,
|
|
1612
|
+
format = DEFAULT_FORMAT,
|
|
1613
|
+
separator = DEFAULT_SEPARATOR,
|
|
1614
|
+
showDuration = true,
|
|
1615
|
+
size = 'default',
|
|
1616
|
+
inertia = true,
|
|
1617
|
+
resizable = true,
|
|
1618
|
+
wheelEffect = true,
|
|
1619
|
+
lockable = false,
|
|
1620
|
+
locked,
|
|
1621
|
+
defaultLocked = false,
|
|
1622
|
+
onLockedChange,
|
|
1623
|
+
minDuration,
|
|
1624
|
+
maxDuration,
|
|
1625
|
+
className,
|
|
1626
|
+
style: styleProp
|
|
1627
|
+
} = _ref;
|
|
1628
|
+
const {
|
|
1629
|
+
formatMessage
|
|
1630
|
+
} = reactIntl.useIntl();
|
|
1631
|
+
const isControlled = typeof value !== 'undefined';
|
|
1632
|
+
const [innerValue, setInnerValue] = react.useState(() => {
|
|
1633
|
+
if (Array.isArray(defaultValue) && readWindowStart(defaultValue)) {
|
|
1634
|
+
return defaultValue;
|
|
1014
1635
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1636
|
+
return toWindowValue(createTimeWindow({
|
|
1637
|
+
duration,
|
|
1638
|
+
range,
|
|
1639
|
+
step
|
|
1640
|
+
}));
|
|
1641
|
+
});
|
|
1642
|
+
const [draftStart, setDraftStart] = react.useState(null);
|
|
1643
|
+
const [draftDuration, setDraftDuration] = react.useState(null);
|
|
1644
|
+
const [dragging, setDragging] = react.useState(false);
|
|
1645
|
+
const [innerLocked, setInnerLocked] = react.useState(defaultLocked);
|
|
1646
|
+
const lockedControlled = typeof locked === 'boolean';
|
|
1647
|
+
const isLocked = lockable && (lockedControlled ? locked : innerLocked);
|
|
1648
|
+
const [resizeView, setResizeView] = react.useState(null);
|
|
1649
|
+
const resizeRef = react.useRef(null);
|
|
1650
|
+
const resizeEdge = resizeView ? resizeView.edge : null;
|
|
1651
|
+
const rootRef = react.useRef(null);
|
|
1652
|
+
const trackRef = react.useRef(null);
|
|
1653
|
+
const dragRef = react.useRef(null);
|
|
1654
|
+
const wheelAccumRef = react.useRef(0);
|
|
1655
|
+
const interactingRef = react.useRef(false);
|
|
1656
|
+
const timerRef = react.useRef(null);
|
|
1657
|
+
const pendingRef = react.useRef(null);
|
|
1658
|
+
const onChangeRef = react.useRef(onChange);
|
|
1659
|
+
const onLockedChangeRef = react.useRef(onLockedChange);
|
|
1660
|
+
const isLockedRef = react.useRef(isLocked);
|
|
1661
|
+
onLockedChangeRef.current = onLockedChange;
|
|
1662
|
+
isLockedRef.current = isLocked;
|
|
1663
|
+
const trackWidth = useElementWidth(trackRef);
|
|
1664
|
+
const committedValue = isControlled ? value : innerValue;
|
|
1665
|
+
const committedStart = readWindowStart(committedValue);
|
|
1666
|
+
const committedMs = committedStart ? committedStart.valueOf() : null;
|
|
1667
|
+
const anchorDay = committedStart ? committedStart.startOf('day').valueOf() : undefined;
|
|
1668
|
+
const draftMs = draftStart ? draftStart.valueOf() : null;
|
|
1669
|
+
const committedEnd = Array.isArray(committedValue) ? parseDateLike(committedValue[1]) : null;
|
|
1670
|
+
const committedEndMs = committedEnd ? committedEnd.valueOf() : null;
|
|
1671
|
+
const committedDuration = committedStart && committedEnd && committedEnd.isAfter(committedStart) ? committedEnd.diff(committedStart, 'minute', true) : null;
|
|
1672
|
+
const activeDuration = draftDuration != null ? draftDuration : committedDuration != null ? committedDuration : duration;
|
|
1673
|
+
const initialDurationRef = react.useRef(committedDuration || DEFAULT_DURATION);
|
|
1674
|
+
const optionsRef = react.useRef(null);
|
|
1675
|
+
onChangeRef.current = onChange;
|
|
1676
|
+
optionsRef.current = {
|
|
1677
|
+
duration: activeDuration,
|
|
1678
|
+
range,
|
|
1679
|
+
step,
|
|
1680
|
+
now: anchorDay
|
|
1681
|
+
};
|
|
1682
|
+
const baseWindow = react.useMemo(() => {
|
|
1683
|
+
const start = draftMs == null ? committedMs : draftMs;
|
|
1684
|
+
return createTimeWindow({
|
|
1685
|
+
start,
|
|
1686
|
+
duration: activeDuration,
|
|
1687
|
+
range,
|
|
1688
|
+
step,
|
|
1689
|
+
now: anchorDay
|
|
1031
1690
|
});
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1691
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1692
|
+
}, [anchorDay, committedMs, draftMs, activeDuration, step, JSON.stringify(range === undefined ? 'default' : range)]);
|
|
1693
|
+
const visibleSpanMinutes = resolveVisibleSpan({
|
|
1694
|
+
visibleSpan,
|
|
1695
|
+
duration: baseWindow.duration,
|
|
1696
|
+
baseDuration: Number(duration) > 0 ? Number(duration) : initialDurationRef.current,
|
|
1697
|
+
rangeStart: baseWindow.rangeStart,
|
|
1698
|
+
rangeEnd: baseWindow.rangeEnd
|
|
1699
|
+
});
|
|
1700
|
+
const baseStartMs = baseWindow.start.valueOf();
|
|
1701
|
+
const rangeStartMs = baseWindow.rangeStart ? baseWindow.rangeStart.valueOf() : null;
|
|
1702
|
+
const rangeEndMs = baseWindow.rangeEnd ? baseWindow.rangeEnd.valueOf() : null;
|
|
1703
|
+
const durationMs = baseWindow.duration * 60 * 1000;
|
|
1704
|
+
const [visualMs, setVisualMs] = react.useState(null);
|
|
1705
|
+
const visualRef = react.useRef(null);
|
|
1706
|
+
const visualTargetRef = react.useRef(null);
|
|
1707
|
+
const frameRef = react.useRef(null);
|
|
1708
|
+
const lastFrameRef = react.useRef(0);
|
|
1709
|
+
const wheelActiveRef = react.useRef(false);
|
|
1710
|
+
const wheelIdleRef = react.useRef(null);
|
|
1711
|
+
const easeRef = react.useRef(VISUAL_EASE_MS);
|
|
1712
|
+
const glidingRef = react.useRef(false);
|
|
1713
|
+
const wheelBaseRef = react.useRef(null);
|
|
1714
|
+
const wheelSamplesRef = react.useRef([]);
|
|
1715
|
+
const wheelDirectionRef = react.useRef(0);
|
|
1716
|
+
const inertiaTau = resolveInertia(inertia);
|
|
1717
|
+
const inertiaRef = react.useRef(inertiaTau);
|
|
1718
|
+
inertiaRef.current = inertiaTau;
|
|
1719
|
+
const clampVisual = ms => {
|
|
1720
|
+
let next = ms;
|
|
1721
|
+
if (rangeEndMs != null) {
|
|
1722
|
+
next = Math.min(next, rangeEndMs - durationMs);
|
|
1041
1723
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
showPopover = true,
|
|
1045
|
-
lockScroll = false
|
|
1046
|
-
} = {}) => {
|
|
1047
|
-
clearDocumentTextSelection();
|
|
1048
|
-
setActivePopoverKey(getPopoverKey(slot));
|
|
1049
|
-
draggingRef.current = true;
|
|
1050
|
-
dragStartIndexRef.current = index;
|
|
1051
|
-
slotsRef.current?.classList.add('schedule-calendar-touch-dragging');
|
|
1052
|
-
if (lockScroll) {
|
|
1053
|
-
lockContainerScroll();
|
|
1054
|
-
}
|
|
1055
|
-
setDragging(true);
|
|
1056
|
-
selectSlots([slot]);
|
|
1057
|
-
if (!showPopover) {
|
|
1058
|
-
suppressTriggerUntilRef.current = Date.now() + 700;
|
|
1059
|
-
setActivePopoverKey(null);
|
|
1060
|
-
}
|
|
1061
|
-
onFreeSlotClick?.(slot);
|
|
1062
|
-
}, [lockContainerScroll, onFreeSlotClick, selectSlots]);
|
|
1063
|
-
const finishSelection = react.useCallback(({
|
|
1064
|
-
fromTouch = false
|
|
1065
|
-
} = {}) => {
|
|
1066
|
-
const hadSelection = selectedSlotsRef.current.length > 0;
|
|
1067
|
-
resetGestureState();
|
|
1068
|
-
if (hadSelection) {
|
|
1069
|
-
if (fromTouch) {
|
|
1070
|
-
suppressTriggerUntilRef.current = Date.now() + 500;
|
|
1071
|
-
}
|
|
1072
|
-
showFormPopoverForSlots(selectedSlotsRef.current);
|
|
1724
|
+
if (rangeStartMs != null) {
|
|
1725
|
+
next = Math.max(next, rangeStartMs);
|
|
1073
1726
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1727
|
+
return next;
|
|
1728
|
+
};
|
|
1729
|
+
const clampVisualRef = react.useRef(clampVisual);
|
|
1730
|
+
clampVisualRef.current = clampVisual;
|
|
1731
|
+
const runFrame = time => {
|
|
1732
|
+
const target = visualTargetRef.current;
|
|
1733
|
+
const current = visualRef.current == null ? target : visualRef.current;
|
|
1734
|
+
const dt = lastFrameRef.current ? Math.min(time - lastFrameRef.current, 64) : 16;
|
|
1735
|
+
lastFrameRef.current = time;
|
|
1736
|
+
const diff = target - current;
|
|
1737
|
+
const settled = Math.abs(diff) < 1000;
|
|
1738
|
+
const next = settled ? target : current + diff * (1 - Math.exp(-dt / easeRef.current));
|
|
1739
|
+
visualRef.current = next;
|
|
1740
|
+
setVisualMs(next);
|
|
1741
|
+
if (glidingRef.current) {
|
|
1742
|
+
moveToRef.current(next);
|
|
1079
1743
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
}, []);
|
|
1086
|
-
const handleMouseDown = react.useCallback((event, slot, index) => {
|
|
1087
|
-
if (shouldIgnoreMouseSelectionEvent()) {
|
|
1744
|
+
if (settled) {
|
|
1745
|
+
frameRef.current = null;
|
|
1746
|
+
lastFrameRef.current = 0;
|
|
1747
|
+
easeRef.current = VISUAL_EASE_MS;
|
|
1748
|
+
glidingRef.current = false;
|
|
1088
1749
|
return;
|
|
1089
1750
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1751
|
+
frameRef.current = requestAnimationFrame(runFrame);
|
|
1752
|
+
};
|
|
1753
|
+
const stopGlide = () => {
|
|
1754
|
+
if (!glidingRef.current) {
|
|
1755
|
+
return false;
|
|
1092
1756
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1757
|
+
glidingRef.current = false;
|
|
1758
|
+
wheelBaseRef.current = null;
|
|
1759
|
+
wheelSamplesRef.current = [];
|
|
1760
|
+
wheelDirectionRef.current = 0;
|
|
1761
|
+
easeRef.current = VISUAL_EASE_MS;
|
|
1762
|
+
if (frameRef.current) {
|
|
1763
|
+
cancelAnimationFrame(frameRef.current);
|
|
1764
|
+
frameRef.current = null;
|
|
1765
|
+
lastFrameRef.current = 0;
|
|
1099
1766
|
}
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1767
|
+
visualTargetRef.current = visualRef.current;
|
|
1768
|
+
return true;
|
|
1769
|
+
};
|
|
1770
|
+
const glideTo = function (ms, easeMs) {
|
|
1771
|
+
if (easeMs === void 0) {
|
|
1772
|
+
easeMs = inertiaTau;
|
|
1105
1773
|
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1774
|
+
const snapped = createTimeWindow({
|
|
1775
|
+
start: ms,
|
|
1776
|
+
...optionsRef.current
|
|
1777
|
+
}).start.valueOf();
|
|
1778
|
+
glidingRef.current = true;
|
|
1779
|
+
easeRef.current = easeMs;
|
|
1780
|
+
setVisualTarget(snapped);
|
|
1781
|
+
};
|
|
1782
|
+
const setVisualTarget = function (ms, _temp) {
|
|
1783
|
+
let {
|
|
1784
|
+
immediate = false
|
|
1785
|
+
} = _temp === void 0 ? {} : _temp;
|
|
1786
|
+
const target = clampVisualRef.current(ms);
|
|
1787
|
+
visualTargetRef.current = target;
|
|
1788
|
+
if (immediate || typeof requestAnimationFrame === 'undefined') {
|
|
1789
|
+
if (frameRef.current) {
|
|
1790
|
+
cancelAnimationFrame(frameRef.current);
|
|
1791
|
+
frameRef.current = null;
|
|
1792
|
+
lastFrameRef.current = 0;
|
|
1793
|
+
}
|
|
1794
|
+
visualRef.current = target;
|
|
1795
|
+
setVisualMs(target);
|
|
1110
1796
|
return;
|
|
1111
1797
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1798
|
+
if (!frameRef.current) {
|
|
1799
|
+
frameRef.current = requestAnimationFrame(runFrame);
|
|
1800
|
+
}
|
|
1801
|
+
};
|
|
1802
|
+
const setVisualTargetRef = react.useRef(setVisualTarget);
|
|
1803
|
+
setVisualTargetRef.current = setVisualTarget;
|
|
1804
|
+
const glideToRef = react.useRef(glideTo);
|
|
1805
|
+
glideToRef.current = glideTo;
|
|
1806
|
+
const stopGlideRef = react.useRef(stopGlide);
|
|
1807
|
+
stopGlideRef.current = stopGlide;
|
|
1808
|
+
react.useEffect(() => () => {
|
|
1809
|
+
if (frameRef.current) {
|
|
1810
|
+
cancelAnimationFrame(frameRef.current);
|
|
1811
|
+
}
|
|
1812
|
+
clearTimeout(wheelIdleRef.current);
|
|
1813
|
+
}, []);
|
|
1814
|
+
react.useEffect(() => {
|
|
1815
|
+
if (dragRef.current || resizeRef.current || wheelActiveRef.current || glidingRef.current) {
|
|
1118
1816
|
return;
|
|
1119
1817
|
}
|
|
1120
|
-
if (
|
|
1121
|
-
|
|
1818
|
+
if (visualRef.current == null) {
|
|
1819
|
+
visualRef.current = baseStartMs;
|
|
1820
|
+
visualTargetRef.current = baseStartMs;
|
|
1122
1821
|
return;
|
|
1123
1822
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1823
|
+
setVisualTargetRef.current(baseStartMs);
|
|
1824
|
+
}, [baseStartMs]);
|
|
1825
|
+
const displayStartMs = resizeView || visualMs == null ? baseStartMs : visualMs;
|
|
1826
|
+
const viewport = resizeView || getViewport({
|
|
1827
|
+
startMs: displayStartMs,
|
|
1828
|
+
duration: baseWindow.duration
|
|
1829
|
+
}, visibleSpanMinutes);
|
|
1830
|
+
const viewRef = react.useRef(null);
|
|
1831
|
+
const baseWindowRef = react.useRef(baseWindow);
|
|
1832
|
+
baseWindowRef.current = baseWindow;
|
|
1833
|
+
viewRef.current = viewport;
|
|
1834
|
+
const ticks = react.useMemo(() => buildScaleTicks(viewport.startMs, viewport.endMs, {
|
|
1835
|
+
trackWidth,
|
|
1836
|
+
rangeStart: rangeStartMs,
|
|
1837
|
+
rangeEnd: rangeEndMs
|
|
1838
|
+
}), [viewport.startMs, viewport.endMs, trackWidth, rangeStartMs, rangeEndMs]);
|
|
1839
|
+
const toPercent = ms => (ms - viewport.startMs) / viewport.spanMs * 100;
|
|
1840
|
+
const width = durationMs / viewport.spanMs * 100;
|
|
1841
|
+
const left = toPercent(displayStartMs);
|
|
1842
|
+
const windowPx = width / 100 * trackWidth;
|
|
1843
|
+
const leftShade = rangeStartMs != null ? Math.min(Math.max(toPercent(rangeStartMs), 0), 100) : 0;
|
|
1844
|
+
const rightShade = rangeEndMs != null ? Math.min(Math.max(100 - toPercent(rangeEndMs), 0), 100) : 0;
|
|
1845
|
+
const label = react.useMemo(() => {
|
|
1846
|
+
if (typeof format === 'function') {
|
|
1847
|
+
return format(baseWindow.start.toDate(), baseWindow.end.toDate());
|
|
1848
|
+
}
|
|
1849
|
+
const [startText, endText] = formatTimeWindowParts({
|
|
1850
|
+
start: baseWindow.start,
|
|
1851
|
+
end: baseWindow.end,
|
|
1852
|
+
format
|
|
1129
1853
|
});
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1854
|
+
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
1855
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
1856
|
+
children: startText
|
|
1857
|
+
}), /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
1858
|
+
className: style$2.separator,
|
|
1859
|
+
children: separator
|
|
1860
|
+
}), /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
1861
|
+
children: endText
|
|
1862
|
+
})]
|
|
1863
|
+
});
|
|
1864
|
+
}, [baseWindow.end, baseWindow.start, format, separator]);
|
|
1865
|
+
const ariaValueText = formatTimeWindow({
|
|
1866
|
+
start: baseWindow.start,
|
|
1867
|
+
end: baseWindow.end,
|
|
1868
|
+
format: typeof format === 'function' ? DEFAULT_FORMAT : format,
|
|
1869
|
+
separator: typeof separator === 'string' ? separator : DEFAULT_SEPARATOR
|
|
1870
|
+
});
|
|
1871
|
+
const durationText = react.useMemo(() => {
|
|
1872
|
+
const {
|
|
1873
|
+
hours,
|
|
1874
|
+
minutes
|
|
1875
|
+
} = formatDurationParts(baseWindow.duration);
|
|
1876
|
+
const parts = [];
|
|
1877
|
+
if (hours) {
|
|
1878
|
+
parts.push(formatMessage({
|
|
1879
|
+
id: 'TimeWindow.hours'
|
|
1880
|
+
}, {
|
|
1881
|
+
count: hours
|
|
1882
|
+
}));
|
|
1883
|
+
}
|
|
1884
|
+
if (minutes || !hours) {
|
|
1885
|
+
parts.push(formatMessage({
|
|
1886
|
+
id: 'TimeWindow.minutes'
|
|
1887
|
+
}, {
|
|
1888
|
+
count: minutes
|
|
1889
|
+
}));
|
|
1890
|
+
}
|
|
1891
|
+
return parts.join(' ');
|
|
1892
|
+
}, [baseWindow.duration, formatMessage]);
|
|
1893
|
+
const clearTimer = () => {
|
|
1894
|
+
if (timerRef.current) {
|
|
1895
|
+
clearTimeout(timerRef.current);
|
|
1896
|
+
timerRef.current = null;
|
|
1897
|
+
}
|
|
1140
1898
|
};
|
|
1899
|
+
react.useEffect(() => clearTimer, []);
|
|
1141
1900
|
react.useEffect(() => {
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
return undefined;
|
|
1901
|
+
if (interactingRef.current || draftMs == null) {
|
|
1902
|
+
return;
|
|
1145
1903
|
}
|
|
1146
|
-
const
|
|
1147
|
-
|
|
1148
|
-
|
|
1904
|
+
const pending = Array.isArray(pendingRef.current) ? pendingRef.current : null;
|
|
1905
|
+
if (pending && sameInstant(committedMs, pending[0]) && sameInstant(committedEndMs, pending[1])) {
|
|
1906
|
+
pendingRef.current = null;
|
|
1907
|
+
setDraftStart(null);
|
|
1908
|
+
setDraftDuration(null);
|
|
1909
|
+
}
|
|
1910
|
+
}, [committedMs, committedEndMs, draftMs]);
|
|
1911
|
+
const publish = nextWindow => {
|
|
1912
|
+
const nextValue = toWindowValue(nextWindow);
|
|
1913
|
+
baseWindowRef.current = nextWindow;
|
|
1914
|
+
pendingRef.current = nextValue;
|
|
1915
|
+
setDraftStart(nextWindow.start);
|
|
1916
|
+
setDraftDuration(nextWindow.duration);
|
|
1917
|
+
clearTimer();
|
|
1918
|
+
timerRef.current = setTimeout(() => {
|
|
1919
|
+
timerRef.current = null;
|
|
1920
|
+
if (!isControlled) {
|
|
1921
|
+
setInnerValue(nextValue);
|
|
1149
1922
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
} catch {
|
|
1153
|
-
// Ignore capture release errors on stale pointers.
|
|
1923
|
+
if (onChangeRef.current) {
|
|
1924
|
+
onChangeRef.current(nextValue);
|
|
1154
1925
|
}
|
|
1926
|
+
}, debounceWait);
|
|
1927
|
+
};
|
|
1928
|
+
const moveTo = startInput => {
|
|
1929
|
+
const current = baseWindowRef.current;
|
|
1930
|
+
const nextWindow = createTimeWindow({
|
|
1931
|
+
start: startInput,
|
|
1932
|
+
...optionsRef.current
|
|
1933
|
+
});
|
|
1934
|
+
if (nextWindow.start.valueOf() === current.start.valueOf()) {
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
publish(nextWindow);
|
|
1938
|
+
};
|
|
1939
|
+
const moveToRef = react.useRef(moveTo);
|
|
1940
|
+
moveToRef.current = moveTo;
|
|
1941
|
+
const durationPropRef = react.useRef(duration);
|
|
1942
|
+
react.useEffect(() => {
|
|
1943
|
+
if (durationPropRef.current === duration) {
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
durationPropRef.current = duration;
|
|
1947
|
+
publish(createTimeWindow({
|
|
1948
|
+
...optionsRef.current,
|
|
1949
|
+
start: baseWindowRef.current.start,
|
|
1950
|
+
duration
|
|
1951
|
+
}));
|
|
1952
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1953
|
+
}, [duration]);
|
|
1954
|
+
const pointerTimeAt = (clientX, view) => {
|
|
1955
|
+
const rect = trackRef.current ? trackRef.current.getBoundingClientRect() : {
|
|
1956
|
+
left: 0,
|
|
1957
|
+
width: 1
|
|
1155
1958
|
};
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1959
|
+
return timeAtClientX({
|
|
1960
|
+
clientX,
|
|
1961
|
+
rectLeft: rect.left,
|
|
1962
|
+
rectWidth: rect.width,
|
|
1963
|
+
rangeStartMs: view.startMs,
|
|
1964
|
+
rangeEndMs: view.endMs
|
|
1965
|
+
});
|
|
1966
|
+
};
|
|
1967
|
+
const startResize = (event, edge) => {
|
|
1968
|
+
const view = viewRef.current;
|
|
1969
|
+
const current = baseWindowRef.current;
|
|
1970
|
+
const edgeMs = edge === 'start' ? current.start.valueOf() : current.end.valueOf();
|
|
1971
|
+
resizeRef.current = {
|
|
1972
|
+
pointerId: event.pointerId,
|
|
1973
|
+
edge,
|
|
1974
|
+
view,
|
|
1975
|
+
grabOffsetMs: pointerTimeAt(event.clientX, view) - edgeMs
|
|
1159
1976
|
};
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1977
|
+
interactingRef.current = true;
|
|
1978
|
+
setResizeView({
|
|
1979
|
+
...view,
|
|
1980
|
+
edge
|
|
1981
|
+
});
|
|
1982
|
+
try {
|
|
1983
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1984
|
+
} catch (error) {
|
|
1985
|
+
// pointer may already be released
|
|
1986
|
+
}
|
|
1987
|
+
};
|
|
1988
|
+
const moveResize = event => {
|
|
1989
|
+
const resize = resizeRef.current;
|
|
1990
|
+
const current = baseWindowRef.current;
|
|
1991
|
+
const next = resizeTimeWindow({
|
|
1992
|
+
edge: resize.edge,
|
|
1993
|
+
pointerMs: pointerTimeAt(event.clientX, resize.view) - resize.grabOffsetMs,
|
|
1994
|
+
startMs: current.start.valueOf(),
|
|
1995
|
+
endMs: current.end.valueOf(),
|
|
1996
|
+
step: current.step,
|
|
1997
|
+
rangeStart: current.rangeStart,
|
|
1998
|
+
rangeEnd: current.rangeEnd,
|
|
1999
|
+
minDuration,
|
|
2000
|
+
maxDuration
|
|
2001
|
+
});
|
|
2002
|
+
if (next.startMs === current.start.valueOf() && next.duration === current.duration) {
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
publish(createTimeWindow({
|
|
2006
|
+
...optionsRef.current,
|
|
2007
|
+
start: next.startMs,
|
|
2008
|
+
duration: next.duration
|
|
2009
|
+
}));
|
|
2010
|
+
};
|
|
2011
|
+
const endResize = () => {
|
|
2012
|
+
const resize = resizeRef.current;
|
|
2013
|
+
resizeRef.current = null;
|
|
2014
|
+
interactingRef.current = false;
|
|
2015
|
+
const current = baseWindowRef.current;
|
|
2016
|
+
const centerMs = resize.view.startMs + resize.view.spanMs / 2;
|
|
2017
|
+
const frozenStart = centerMs - current.duration * 60 * 1000 / 2;
|
|
2018
|
+
visualRef.current = frozenStart;
|
|
2019
|
+
setVisualMs(frozenStart);
|
|
2020
|
+
setResizeView(null);
|
|
2021
|
+
setVisualTargetRef.current(current.start.valueOf());
|
|
2022
|
+
};
|
|
2023
|
+
const onPointerDown = event => {
|
|
2024
|
+
if (event.button != null && event.button !== 0) {
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
const braked = stopGlideRef.current();
|
|
2028
|
+
const edgeNode = resizable && event.target && event.target.closest ? event.target.closest('[data-edge]') : null;
|
|
2029
|
+
if (edgeNode) {
|
|
2030
|
+
startResize(event, edgeNode.getAttribute('data-edge'));
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
dragRef.current = {
|
|
2034
|
+
pointerId: event.pointerId,
|
|
2035
|
+
startX: event.clientX,
|
|
2036
|
+
originMs: visualRef.current == null ? baseWindowRef.current.start.valueOf() : visualRef.current,
|
|
2037
|
+
moved: false,
|
|
2038
|
+
braked,
|
|
2039
|
+
samples: []
|
|
1163
2040
|
};
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
if (
|
|
1174
|
-
|
|
2041
|
+
interactingRef.current = true;
|
|
2042
|
+
try {
|
|
2043
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2044
|
+
} catch (error) {
|
|
2045
|
+
// pointer may already be released
|
|
2046
|
+
}
|
|
2047
|
+
};
|
|
2048
|
+
const onPointerMove = event => {
|
|
2049
|
+
if (resizeRef.current) {
|
|
2050
|
+
if (resizeRef.current.pointerId === event.pointerId) {
|
|
2051
|
+
moveResize(event);
|
|
1175
2052
|
}
|
|
1176
|
-
return
|
|
2053
|
+
return;
|
|
2054
|
+
}
|
|
2055
|
+
const drag = dragRef.current;
|
|
2056
|
+
if (!drag || drag.pointerId !== event.pointerId) {
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
const dx = event.clientX - drag.startX;
|
|
2060
|
+
if (!drag.moved && Math.abs(dx) < CLICK_MOVE_TOLERANCE) {
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
if (!drag.moved) {
|
|
2064
|
+
drag.moved = true;
|
|
2065
|
+
setDragging(true);
|
|
2066
|
+
}
|
|
2067
|
+
const rect = trackRef.current ? trackRef.current.getBoundingClientRect() : {
|
|
2068
|
+
width: 1
|
|
1177
2069
|
};
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
|
|
2070
|
+
const deltaMs = dx / (rect.width || 1) * viewRef.current.spanMs;
|
|
2071
|
+
const rawMs = drag.originMs - deltaMs;
|
|
2072
|
+
drag.samples.push({
|
|
2073
|
+
t: event.timeStamp,
|
|
2074
|
+
ms: rawMs
|
|
2075
|
+
});
|
|
2076
|
+
if (drag.samples.length > 12) {
|
|
2077
|
+
drag.samples.shift();
|
|
2078
|
+
}
|
|
2079
|
+
moveToRef.current(rawMs);
|
|
2080
|
+
setVisualTargetRef.current(rawMs, {
|
|
2081
|
+
immediate: true
|
|
2082
|
+
});
|
|
2083
|
+
};
|
|
2084
|
+
const endDrag = event => {
|
|
2085
|
+
if (resizeRef.current) {
|
|
2086
|
+
if (!event || resizeRef.current.pointerId === event.pointerId) {
|
|
2087
|
+
endResize();
|
|
1181
2088
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
const drag = dragRef.current;
|
|
2092
|
+
if (!drag || event && drag.pointerId !== event.pointerId) {
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
2095
|
+
dragRef.current = null;
|
|
2096
|
+
interactingRef.current = false;
|
|
2097
|
+
setDragging(false);
|
|
2098
|
+
if (drag.moved) {
|
|
2099
|
+
const velocity = inertiaRef.current && event ? estimateVelocity(drag.samples, event.timeStamp) : 0;
|
|
2100
|
+
const projection = velocity * inertiaRef.current;
|
|
2101
|
+
if (Math.abs(projection) >= baseWindowRef.current.step * 60 * 1000) {
|
|
2102
|
+
glideToRef.current(visualRef.current + projection);
|
|
2103
|
+
} else {
|
|
2104
|
+
setVisualTargetRef.current(baseWindowRef.current.start.valueOf());
|
|
1189
2105
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
2106
|
+
}
|
|
2107
|
+
if (!drag.moved && drag.braked) {
|
|
2108
|
+
moveToRef.current(drag.originMs);
|
|
2109
|
+
setVisualTargetRef.current(baseWindowRef.current.start.valueOf());
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
if (!drag.moved && event && event.type === 'pointerup') {
|
|
2113
|
+
const rect = trackRef.current ? trackRef.current.getBoundingClientRect() : {
|
|
2114
|
+
left: 0,
|
|
2115
|
+
width: 1
|
|
2116
|
+
};
|
|
2117
|
+
const view = viewRef.current;
|
|
2118
|
+
const clickedMs = timeAtClientX({
|
|
2119
|
+
clientX: event.clientX,
|
|
2120
|
+
rectLeft: rect.left,
|
|
2121
|
+
rectWidth: rect.width,
|
|
2122
|
+
rangeStartMs: view.startMs,
|
|
2123
|
+
rangeEndMs: view.endMs
|
|
1194
2124
|
});
|
|
2125
|
+
const current = baseWindowRef.current;
|
|
2126
|
+
moveToRef.current(clickedMs - current.duration * 60 * 1000 / 2);
|
|
2127
|
+
}
|
|
2128
|
+
};
|
|
2129
|
+
const onKeyDown = event => {
|
|
2130
|
+
stopGlideRef.current();
|
|
2131
|
+
const current = baseWindowRef.current;
|
|
2132
|
+
const stepMinutes = current.step;
|
|
2133
|
+
const moves = {
|
|
2134
|
+
ArrowLeft: -stepMinutes,
|
|
2135
|
+
ArrowDown: -stepMinutes,
|
|
2136
|
+
ArrowRight: stepMinutes,
|
|
2137
|
+
ArrowUp: stepMinutes,
|
|
2138
|
+
PageDown: -current.duration,
|
|
2139
|
+
PageUp: current.duration
|
|
1195
2140
|
};
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
2141
|
+
if (event.key === 'Home' && current.rangeStart) {
|
|
2142
|
+
event.preventDefault();
|
|
2143
|
+
moveToRef.current(current.rangeStart);
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
if (event.key === 'End' && current.rangeEnd) {
|
|
2147
|
+
event.preventDefault();
|
|
2148
|
+
moveToRef.current(current.rangeEnd);
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
2151
|
+
if (!(event.key in moves)) {
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
event.preventDefault();
|
|
2155
|
+
const minutes = event.shiftKey ? Math.sign(moves[event.key]) * Math.max(60, stepMinutes) : moves[event.key];
|
|
2156
|
+
moveToRef.current(current.start.add(minutes, 'minute'));
|
|
2157
|
+
};
|
|
2158
|
+
react.useEffect(() => {
|
|
2159
|
+
const node = rootRef.current;
|
|
2160
|
+
if (!node) {
|
|
2161
|
+
return undefined;
|
|
2162
|
+
}
|
|
2163
|
+
const onWheel = event => {
|
|
2164
|
+
if (isLockedRef.current) {
|
|
1207
2165
|
return;
|
|
1208
2166
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
pointerId: event.pointerId,
|
|
1212
|
-
x: event.clientX,
|
|
1213
|
-
y: event.clientY,
|
|
1214
|
-
lastX: event.clientX,
|
|
1215
|
-
lastY: event.clientY,
|
|
1216
|
-
slot,
|
|
1217
|
-
index,
|
|
1218
|
-
moved: false,
|
|
1219
|
-
longPressed: false,
|
|
1220
|
-
active: false,
|
|
1221
|
-
selectionTriggered: false
|
|
1222
|
-
};
|
|
1223
|
-
if (!allowMultiSelectRef.current) {
|
|
2167
|
+
const dominant = Math.abs(event.deltaX) > Math.abs(event.deltaY) ? event.deltaX : event.deltaY;
|
|
2168
|
+
if (!dominant) {
|
|
1224
2169
|
return;
|
|
1225
2170
|
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
2171
|
+
event.preventDefault();
|
|
2172
|
+
const current = baseWindowRef.current;
|
|
2173
|
+
const rectWidth = trackRef.current ? trackRef.current.getBoundingClientRect().width : node.clientWidth;
|
|
2174
|
+
const deltaPx = wheelDeltaToPx({
|
|
2175
|
+
delta: dominant,
|
|
2176
|
+
deltaMode: event.deltaMode,
|
|
2177
|
+
trackWidth: rectWidth
|
|
2178
|
+
});
|
|
2179
|
+
const stepMs = current.step * 60 * 1000;
|
|
2180
|
+
const pxPerStep = rectWidth * stepMs / viewRef.current.spanMs;
|
|
2181
|
+
const discrete = isDiscreteWheel(event, deltaPx);
|
|
2182
|
+
const {
|
|
2183
|
+
steps,
|
|
2184
|
+
accumulatedPx
|
|
2185
|
+
} = consumeWheelSteps({
|
|
2186
|
+
accumulatedPx: wheelAccumRef.current,
|
|
2187
|
+
deltaPx,
|
|
2188
|
+
pxPerStep,
|
|
2189
|
+
discrete
|
|
2190
|
+
});
|
|
2191
|
+
wheelAccumRef.current = accumulatedPx;
|
|
2192
|
+
wheelActiveRef.current = true;
|
|
2193
|
+
clearTimeout(wheelIdleRef.current);
|
|
2194
|
+
wheelIdleRef.current = setTimeout(() => {
|
|
2195
|
+
wheelActiveRef.current = false;
|
|
2196
|
+
wheelAccumRef.current = 0;
|
|
2197
|
+
wheelBaseRef.current = null;
|
|
2198
|
+
wheelSamplesRef.current = [];
|
|
2199
|
+
wheelDirectionRef.current = 0;
|
|
2200
|
+
if (!glidingRef.current) {
|
|
2201
|
+
setVisualTargetRef.current(baseWindowRef.current.start.valueOf());
|
|
2202
|
+
}
|
|
2203
|
+
}, WHEEL_IDLE_MS);
|
|
2204
|
+
if (discrete && inertiaRef.current) {
|
|
2205
|
+
if (!steps) {
|
|
1229
2206
|
return;
|
|
1230
2207
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
const touchState = touchStateRef.current;
|
|
1237
|
-
if (!touchState || event.pointerId !== touchState.pointerId) {
|
|
1238
|
-
return;
|
|
1239
|
-
}
|
|
1240
|
-
touchState.lastX = event.clientX;
|
|
1241
|
-
touchState.lastY = event.clientY;
|
|
1242
|
-
if (!touchState.active) {
|
|
1243
|
-
if (shouldCancelPendingGesture(touchState, event.clientX, event.clientY)) {
|
|
1244
|
-
touchState.moved = true;
|
|
1245
|
-
clearPendingTouch();
|
|
2208
|
+
const samples = wheelSamplesRef.current;
|
|
2209
|
+
if (wheelDirectionRef.current !== Math.sign(steps)) {
|
|
2210
|
+
samples.length = 0;
|
|
2211
|
+
wheelBaseRef.current = null;
|
|
2212
|
+
wheelDirectionRef.current = Math.sign(steps);
|
|
1246
2213
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
};
|
|
1257
|
-
const handlePointerUp = event => {
|
|
1258
|
-
const touchState = touchStateRef.current;
|
|
1259
|
-
if (!touchState || event.pointerId !== touchState.pointerId) {
|
|
1260
|
-
return;
|
|
1261
|
-
}
|
|
1262
|
-
releasePointerCapture(event.pointerId);
|
|
1263
|
-
suppressMouseUntilRef.current = Date.now() + 700;
|
|
1264
|
-
if (touchState.active) {
|
|
1265
|
-
event.preventDefault();
|
|
1266
|
-
touchState.selectionTriggered = true;
|
|
1267
|
-
const index = getSlotIndexFromPoint(container, event.clientX, event.clientY);
|
|
1268
|
-
if (index !== null) {
|
|
1269
|
-
handlersRef.current.updateSelectionRange(index);
|
|
1270
|
-
}
|
|
1271
|
-
suppressTriggerUntilRef.current = Date.now() + 500;
|
|
1272
|
-
handlersRef.current.finishSelection({
|
|
1273
|
-
fromTouch: true
|
|
2214
|
+
const from = wheelBaseRef.current == null ? current.start.valueOf() : wheelBaseRef.current;
|
|
2215
|
+
const base = createTimeWindow({
|
|
2216
|
+
start: from + steps * stepMs,
|
|
2217
|
+
...optionsRef.current
|
|
2218
|
+
}).start.valueOf();
|
|
2219
|
+
wheelBaseRef.current = base;
|
|
2220
|
+
samples.push({
|
|
2221
|
+
t: event.timeStamp,
|
|
2222
|
+
ms: base
|
|
1274
2223
|
});
|
|
2224
|
+
if (samples.length > 8) {
|
|
2225
|
+
samples.shift();
|
|
2226
|
+
}
|
|
2227
|
+
const projection = estimateVelocity(samples, event.timeStamp) * inertiaRef.current * WHEEL_INERTIA_SCALE;
|
|
2228
|
+
let target = base + projection;
|
|
2229
|
+
const lastTarget = visualTargetRef.current;
|
|
2230
|
+
if (samples.length > 1 && lastTarget != null && (target - lastTarget) * wheelDirectionRef.current < 0) {
|
|
2231
|
+
target = lastTarget;
|
|
2232
|
+
}
|
|
2233
|
+
glideToRef.current(target, projection ? inertiaRef.current : WHEEL_NOTCH_EASE_MS);
|
|
1275
2234
|
return;
|
|
1276
2235
|
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
const {
|
|
1280
|
-
slot
|
|
1281
|
-
} = touchState;
|
|
1282
|
-
touchStateRef.current = null;
|
|
1283
|
-
if (quickTap) {
|
|
1284
|
-
touchState.selectionTriggered = true;
|
|
1285
|
-
suppressTriggerUntilRef.current = Date.now() + 500;
|
|
1286
|
-
handlersRef.current.selectSlots([slot]);
|
|
1287
|
-
handlersRef.current.showFormPopoverForSlots([slot]);
|
|
1288
|
-
handlersRef.current.onFreeSlotClick?.(slot);
|
|
1289
|
-
return;
|
|
1290
|
-
}
|
|
1291
|
-
handlersRef.current.resetGestureState();
|
|
1292
|
-
};
|
|
1293
|
-
const handleContextMenu = event => {
|
|
1294
|
-
if (touchStateRef.current?.active || draggingRef.current) {
|
|
1295
|
-
event.preventDefault();
|
|
1296
|
-
}
|
|
1297
|
-
};
|
|
1298
|
-
const handleSelectStart = event => {
|
|
1299
|
-
if (!touchStateRef.current?.active && !draggingRef.current) {
|
|
1300
|
-
return;
|
|
1301
|
-
}
|
|
1302
|
-
event.preventDefault();
|
|
1303
|
-
};
|
|
1304
|
-
const handleTouchMove = event => {
|
|
1305
|
-
if (!draggingRef.current && !touchStateRef.current?.active) {
|
|
1306
|
-
return;
|
|
2236
|
+
if (steps) {
|
|
2237
|
+
moveToRef.current(current.start.valueOf() + steps * stepMs);
|
|
1307
2238
|
}
|
|
1308
|
-
|
|
2239
|
+
const residualMs = pxPerStep > 0 ? accumulatedPx / pxPerStep * stepMs : 0;
|
|
2240
|
+
setVisualTargetRef.current(baseWindowRef.current.start.valueOf() + residualMs);
|
|
1309
2241
|
};
|
|
1310
|
-
|
|
1311
|
-
passive: false,
|
|
1312
|
-
capture: true
|
|
1313
|
-
};
|
|
1314
|
-
container.addEventListener('pointerdown', handlePointerDown, {
|
|
1315
|
-
passive: true
|
|
1316
|
-
});
|
|
1317
|
-
container.addEventListener('pointermove', handlePointerMove, {
|
|
1318
|
-
passive: false
|
|
1319
|
-
});
|
|
1320
|
-
container.addEventListener('pointerup', handlePointerUp, {
|
|
1321
|
-
passive: false
|
|
1322
|
-
});
|
|
1323
|
-
container.addEventListener('pointercancel', handlePointerUp, {
|
|
2242
|
+
node.addEventListener('wheel', onWheel, {
|
|
1324
2243
|
passive: false
|
|
1325
2244
|
});
|
|
1326
|
-
|
|
1327
|
-
container.addEventListener('contextmenu', handleContextMenu);
|
|
1328
|
-
container.addEventListener('selectstart', handleSelectStart);
|
|
1329
|
-
return () => {
|
|
1330
|
-
releasePointerCapture(touchStateRef.current?.pointerId);
|
|
1331
|
-
handlersRef.current.clearLongPress();
|
|
1332
|
-
handlersRef.current.resetGestureState();
|
|
1333
|
-
longPressTimerRef.current = null;
|
|
1334
|
-
container.removeEventListener('touchmove', handleTouchMove, touchOptions);
|
|
1335
|
-
};
|
|
2245
|
+
return () => node.removeEventListener('wheel', onWheel);
|
|
1336
2246
|
}, []);
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
handleMouseEnter,
|
|
1349
|
-
handleMouseUp,
|
|
1350
|
-
handleMouseLeave,
|
|
1351
|
-
handlePopoverOpenChange
|
|
2247
|
+
const toggleLocked = () => {
|
|
2248
|
+
const next = !isLockedRef.current;
|
|
2249
|
+
if (next) {
|
|
2250
|
+
stopGlideRef.current();
|
|
2251
|
+
}
|
|
2252
|
+
if (!lockedControlled) {
|
|
2253
|
+
setInnerLocked(next);
|
|
2254
|
+
}
|
|
2255
|
+
if (onLockedChangeRef.current) {
|
|
2256
|
+
onLockedChangeRef.current(next);
|
|
2257
|
+
}
|
|
1352
2258
|
};
|
|
2259
|
+
const labelTicks = ticks.filter(tick => tick.showLabel);
|
|
2260
|
+
const ariaBounds = {};
|
|
2261
|
+
if (rangeStartMs != null) {
|
|
2262
|
+
ariaBounds['aria-valuemin'] = rangeStartMs;
|
|
2263
|
+
}
|
|
2264
|
+
if (rangeEndMs != null) {
|
|
2265
|
+
ariaBounds['aria-valuemax'] = rangeEndMs - durationMs;
|
|
2266
|
+
}
|
|
2267
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2268
|
+
ref: rootRef,
|
|
2269
|
+
className: classNames(style$2.root, style$2[`root-${size}`], className, {
|
|
2270
|
+
[style$2['root-dragging']]: dragging,
|
|
2271
|
+
[style$2['root-resizing']]: !!resizeView,
|
|
2272
|
+
[style$2['root-locked']]: isLocked
|
|
2273
|
+
}),
|
|
2274
|
+
style: styleProp,
|
|
2275
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2276
|
+
className: style$2.header,
|
|
2277
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2278
|
+
className: style$2.label,
|
|
2279
|
+
children: label
|
|
2280
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2281
|
+
className: style$2.actions,
|
|
2282
|
+
children: [lockable ? /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
2283
|
+
type: "button",
|
|
2284
|
+
role: "switch",
|
|
2285
|
+
"aria-checked": !isLocked,
|
|
2286
|
+
"aria-label": formatMessage({
|
|
2287
|
+
id: isLocked ? 'TimeWindow.locked' : 'TimeWindow.editable'
|
|
2288
|
+
}),
|
|
2289
|
+
className: classNames(style$2.switch, {
|
|
2290
|
+
[style$2['switch-on']]: !isLocked
|
|
2291
|
+
}),
|
|
2292
|
+
onClick: toggleLocked,
|
|
2293
|
+
children: /*#__PURE__*/jsxRuntime.jsx("i", {})
|
|
2294
|
+
}) : null, showDuration ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2295
|
+
className: style$2.duration,
|
|
2296
|
+
children: durationText
|
|
2297
|
+
}) : null]
|
|
2298
|
+
})]
|
|
2299
|
+
}), isLocked ? null : /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2300
|
+
className: style$2.scale,
|
|
2301
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2302
|
+
ref: trackRef,
|
|
2303
|
+
className: classNames(style$2.track, {
|
|
2304
|
+
[style$2['track-wheel']]: wheelEffect
|
|
2305
|
+
}),
|
|
2306
|
+
role: "slider",
|
|
2307
|
+
tabIndex: 0,
|
|
2308
|
+
...ariaBounds,
|
|
2309
|
+
"aria-valuenow": baseWindow.start.valueOf(),
|
|
2310
|
+
"aria-valuetext": ariaValueText,
|
|
2311
|
+
onKeyDown: onKeyDown,
|
|
2312
|
+
onPointerDown: onPointerDown,
|
|
2313
|
+
onPointerMove: onPointerMove,
|
|
2314
|
+
onPointerUp: endDrag,
|
|
2315
|
+
onPointerCancel: endDrag,
|
|
2316
|
+
children: [leftShade > 0 ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2317
|
+
className: classNames(style$2.shade, style$2['shade-start']),
|
|
2318
|
+
style: {
|
|
2319
|
+
width: `${leftShade}%`
|
|
2320
|
+
}
|
|
2321
|
+
}) : null, rightShade > 0 ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2322
|
+
className: classNames(style$2.shade, style$2['shade-end']),
|
|
2323
|
+
style: {
|
|
2324
|
+
width: `${rightShade}%`
|
|
2325
|
+
}
|
|
2326
|
+
}) : null, /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2327
|
+
className: style$2.ticks,
|
|
2328
|
+
children: ticks.map(tick => /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2329
|
+
className: classNames(style$2.tick, style$2[`tick-${tick.level}`], {
|
|
2330
|
+
[style$2['tick-out']]: tick.outOfRange
|
|
2331
|
+
}),
|
|
2332
|
+
style: {
|
|
2333
|
+
left: `${tick.ratio * 100}%`
|
|
2334
|
+
}
|
|
2335
|
+
}, tick.key))
|
|
2336
|
+
}), wheelEffect ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2337
|
+
className: style$2.cylinder,
|
|
2338
|
+
"aria-hidden": "true"
|
|
2339
|
+
}) : null, /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2340
|
+
className: classNames(style$2.window, {
|
|
2341
|
+
[style$2['window-compact']]: windowPx < GRIP_MIN_WIDTH,
|
|
2342
|
+
[style$2['window-resizable']]: resizable,
|
|
2343
|
+
[style$2['window-fixed']]: !resizable
|
|
2344
|
+
}),
|
|
2345
|
+
style: {
|
|
2346
|
+
left: `${left}%`,
|
|
2347
|
+
width: `${width}%`
|
|
2348
|
+
},
|
|
2349
|
+
children: resizable ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
2350
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2351
|
+
"data-edge": "start",
|
|
2352
|
+
"aria-hidden": "true",
|
|
2353
|
+
className: classNames(style$2.edge, style$2['edge-start'], {
|
|
2354
|
+
[style$2['edge-active']]: resizeEdge === 'start'
|
|
2355
|
+
})
|
|
2356
|
+
}), /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2357
|
+
"data-edge": "end",
|
|
2358
|
+
"aria-hidden": "true",
|
|
2359
|
+
className: classNames(style$2.edge, style$2['edge-end'], {
|
|
2360
|
+
[style$2['edge-active']]: resizeEdge === 'end'
|
|
2361
|
+
})
|
|
2362
|
+
})]
|
|
2363
|
+
}) : null
|
|
2364
|
+
})]
|
|
2365
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2366
|
+
className: style$2.labels,
|
|
2367
|
+
children: labelTicks.map(tick => /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2368
|
+
className: classNames(style$2['tick-label'], style$2[`tick-label-${tick.level}`], {
|
|
2369
|
+
[style$2['tick-out']]: tick.outOfRange
|
|
2370
|
+
}),
|
|
2371
|
+
style: {
|
|
2372
|
+
left: `${tick.ratio * 100}%`
|
|
2373
|
+
},
|
|
2374
|
+
children: tick.label
|
|
2375
|
+
}, tick.key))
|
|
2376
|
+
})]
|
|
2377
|
+
})]
|
|
2378
|
+
});
|
|
1353
2379
|
};
|
|
2380
|
+
const TimeWindow = withLocale(TimeWindowInner);
|
|
1354
2381
|
|
|
1355
2382
|
const DefaultFormInner = () => {
|
|
1356
2383
|
const {
|
|
@@ -1381,170 +2408,595 @@ const DefaultFormInner = () => {
|
|
|
1381
2408
|
});
|
|
1382
2409
|
};
|
|
1383
2410
|
|
|
1384
|
-
var style$1 = {"slots":"kne-react-calendar_Ftp-V","
|
|
2411
|
+
var style$1 = {"kne-responsive-boundary":"kne-react-calendar_U1upa","kne-responsive-scroll":"kne-react-calendar_vKocI","slots":"kne-react-calendar_Ftp-V","timeline":"kne-react-calendar_EaUED","timeline-axis":"kne-react-calendar_X2W6x","timeline-axis-label":"kne-react-calendar_NvxDW","timeline-grid":"kne-react-calendar_gTav1","timeline-grid-dragging":"kne-react-calendar_4qf3-","timeline-line":"kne-react-calendar_Tp2ES","timeline-line-hour":"kne-react-calendar_M5-iS","timeline-disabled":"kne-react-calendar_-g-DR","timeline-disabled-reason":"kne-react-calendar_3vFqg","timeline-event":"kne-react-calendar_Wd-9L","timeline-event-title":"kne-react-calendar_WKbMK","timeline-event-time":"kne-react-calendar_K98yc","timeline-event-compact":"kne-react-calendar_WrUNC","timeline-event-disabled":"kne-react-calendar_C4d2-","timeline-ghost":"kne-react-calendar_0T5mO","timeline-now":"kne-react-calendar_AzaVv","timeline-popover-anchor":"kne-react-calendar_WtBzl","timeline-selection":"kne-react-calendar_z-uOR","timeline-selection-dragging":"kne-react-calendar_MbeJu","timeline-selection-label":"kne-react-calendar_7nYLD","timeline-selection-compact":"kne-react-calendar_CpsWx","timeline-selection-badge":"kne-react-calendar_NqiWA","timeline-selection-conflict":"kne-react-calendar_XQQ3E","timeline-selection-edge":"kne-react-calendar_s2EvF","timeline-selection-edge-start":"kne-react-calendar_PcIon","timeline-selection-edge-end":"kne-react-calendar_nS8Mr","form-popover":"kne-react-calendar_W-I5J","schedule-popover":"kne-react-calendar_rVLO8","form-popover-title":"kne-react-calendar_mMpFQ","form-sheet":"kne-react-calendar_n-MRC","form-sheet-content":"kne-react-calendar_ZaEkY","form-actions":"kne-react-calendar_4NPv0","form-conflict":"kne-react-calendar_PpU92","form-time-window":"kne-react-calendar_Wd4qh","event-detail":"kne-react-calendar_Dc-t3","event-detail-clickable":"kne-react-calendar_C3waU","event-detail-title":"kne-react-calendar_FkbSR","event-detail-disabled":"kne-react-calendar_UsltM","event-detail-bar":"kne-react-calendar_ZETY4","event-detail-body":"kne-react-calendar_v9RjG","event-detail-time":"kne-react-calendar_NT-kw","event-detail-text":"kne-react-calendar_vOb62","event-detail-tag":"kne-react-calendar_rs8bh"};
|
|
1385
2412
|
|
|
1386
|
-
const
|
|
1387
|
-
|
|
2413
|
+
const EventDetail = ({
|
|
2414
|
+
event,
|
|
1388
2415
|
date,
|
|
1389
2416
|
onEventClick
|
|
1390
|
-
}) =>
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
2417
|
+
}) => {
|
|
2418
|
+
const clickable = !event.disabled && (typeof event.onClick === 'function' || typeof onEventClick === 'function');
|
|
2419
|
+
const handleClick = () => {
|
|
2420
|
+
if (typeof event.onClick === 'function') {
|
|
2421
|
+
event.onClick(event, {
|
|
2422
|
+
date,
|
|
2423
|
+
mode: 'schedule'
|
|
2424
|
+
});
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
onEventClick?.(event, {
|
|
2428
|
+
date,
|
|
2429
|
+
mode: 'schedule'
|
|
2430
|
+
});
|
|
2431
|
+
};
|
|
2432
|
+
const tagLabel = getEventTagLabel(event);
|
|
2433
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2434
|
+
className: classNames(style$1['event-detail'], {
|
|
2435
|
+
[style$1['event-detail-clickable']]: clickable,
|
|
2436
|
+
[style$1['event-detail-disabled']]: event.disabled
|
|
2437
|
+
}),
|
|
2438
|
+
style: event.color ? {
|
|
2439
|
+
'--timeline-event-color': event.color
|
|
2440
|
+
} : undefined,
|
|
2441
|
+
role: clickable ? 'button' : undefined,
|
|
2442
|
+
tabIndex: clickable ? 0 : undefined,
|
|
2443
|
+
onClick: clickable ? handleClick : undefined,
|
|
2444
|
+
onKeyDown: clickable ? keyEvent => {
|
|
2445
|
+
if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
|
|
2446
|
+
keyEvent.preventDefault();
|
|
2447
|
+
handleClick();
|
|
2448
|
+
}
|
|
2449
|
+
} : undefined,
|
|
2450
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2451
|
+
className: style$1['event-detail-bar']
|
|
2452
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2453
|
+
className: style$1['event-detail-body'],
|
|
2454
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2455
|
+
className: style$1['event-detail-title'],
|
|
2456
|
+
children: event.title
|
|
2457
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2458
|
+
className: style$1['event-detail-time'],
|
|
2459
|
+
children: formatRange(event.start, event.end)
|
|
2460
|
+
}), event.detail ? /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2461
|
+
className: style$1['event-detail-text'],
|
|
2462
|
+
children: event.detail
|
|
2463
|
+
}) : null, tagLabel ? /*#__PURE__*/jsxRuntime.jsx(antd.Tag, {
|
|
2464
|
+
className: style$1['event-detail-tag'],
|
|
2465
|
+
color: event.color,
|
|
2466
|
+
children: tagLabel
|
|
2467
|
+
}) : null]
|
|
2468
|
+
})]
|
|
2469
|
+
});
|
|
2470
|
+
};
|
|
1403
2471
|
|
|
1404
|
-
const
|
|
1405
|
-
|
|
2472
|
+
const DRAG_THRESHOLD_PX = 4;
|
|
2473
|
+
const TOUCH_SLOP_PX = 8;
|
|
2474
|
+
const LONG_PRESS_MS = 350;
|
|
2475
|
+
const Timeline = ({
|
|
1406
2476
|
date,
|
|
1407
|
-
|
|
2477
|
+
day,
|
|
2478
|
+
hourHeight,
|
|
2479
|
+
timeUnit,
|
|
2480
|
+
timeStep,
|
|
2481
|
+
eventItems,
|
|
2482
|
+
disabledRanges,
|
|
2483
|
+
blockers,
|
|
2484
|
+
conflicts,
|
|
2485
|
+
allowMultiSelect,
|
|
2486
|
+
selection,
|
|
2487
|
+
dragging,
|
|
1408
2488
|
formPopover,
|
|
1409
2489
|
popoverOpen,
|
|
2490
|
+
popoverPlacement,
|
|
2491
|
+
popoverAnchor,
|
|
1410
2492
|
onPopoverOpenChange,
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
onMouseEnter,
|
|
1415
|
-
onMouseUp,
|
|
1416
|
-
onClick,
|
|
2493
|
+
onSelectionDrag,
|
|
2494
|
+
onSelectionCommit,
|
|
2495
|
+
onFreeSlotClick,
|
|
1417
2496
|
onEventClick,
|
|
1418
|
-
|
|
1419
|
-
renderOccupiedSlot
|
|
2497
|
+
renderEventBlock,
|
|
2498
|
+
renderOccupiedSlot,
|
|
2499
|
+
interactionRef,
|
|
2500
|
+
isMobile
|
|
1420
2501
|
}) => {
|
|
1421
|
-
const
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
const
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
2502
|
+
const gridRef = react.useRef(null);
|
|
2503
|
+
const gestureRef = react.useRef(null);
|
|
2504
|
+
const suppressClickRef = react.useRef(false);
|
|
2505
|
+
const touchCommitRef = react.useRef(0);
|
|
2506
|
+
const [hover, setHover] = react.useState(null);
|
|
2507
|
+
const [activeEventKey, setActiveEventKey] = react.useState(null);
|
|
2508
|
+
const pxPerMs = hourHeight / (60 * MINUTE_MS$1);
|
|
2509
|
+
const height = (day.endMs - day.startMs) * pxPerMs;
|
|
2510
|
+
const unitMs = timeUnit * MINUTE_MS$1;
|
|
2511
|
+
const stepMs = timeStep * MINUTE_MS$1;
|
|
2512
|
+
const latest = react.useRef({});
|
|
2513
|
+
latest.current = {
|
|
2514
|
+
day,
|
|
2515
|
+
blockers,
|
|
2516
|
+
unitMs,
|
|
2517
|
+
stepMs,
|
|
2518
|
+
allowMultiSelect,
|
|
2519
|
+
selection,
|
|
2520
|
+
onSelectionDrag,
|
|
2521
|
+
onSelectionCommit,
|
|
2522
|
+
onFreeSlotClick,
|
|
2523
|
+
pxPerMs
|
|
2524
|
+
};
|
|
2525
|
+
const toY = ms => (ms - day.startMs) * pxPerMs;
|
|
2526
|
+
const lines = react.useMemo(() => {
|
|
2527
|
+
const list = [];
|
|
2528
|
+
for (let ms = day.startMs; ms <= day.endMs; ms += unitMs) {
|
|
2529
|
+
list.push({
|
|
2530
|
+
ms,
|
|
2531
|
+
hour: dayjs__default["default"](ms).minute() === 0
|
|
1449
2532
|
});
|
|
1450
2533
|
}
|
|
1451
|
-
return
|
|
1452
|
-
}
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
2534
|
+
return list;
|
|
2535
|
+
}, [day.endMs, day.startMs, unitMs]);
|
|
2536
|
+
const labels = react.useMemo(() => {
|
|
2537
|
+
const list = [];
|
|
2538
|
+
let cursor = dayjs__default["default"](day.startMs);
|
|
2539
|
+
if (cursor.minute() !== 0) {
|
|
2540
|
+
list.push(day.startMs);
|
|
2541
|
+
cursor = cursor.add(1, 'hour').startOf('hour');
|
|
2542
|
+
}
|
|
2543
|
+
for (; cursor.valueOf() <= day.endMs; cursor = cursor.add(1, 'hour')) {
|
|
2544
|
+
list.push(cursor.valueOf());
|
|
2545
|
+
}
|
|
2546
|
+
if (list[list.length - 1] !== day.endMs) {
|
|
2547
|
+
list.push(day.endMs);
|
|
2548
|
+
}
|
|
2549
|
+
return list;
|
|
2550
|
+
}, [day.endMs, day.startMs]);
|
|
2551
|
+
const [now, setNow] = react.useState(() => Date.now());
|
|
2552
|
+
react.useEffect(() => {
|
|
2553
|
+
const timer = setInterval(() => setNow(Date.now()), 60 * 1000);
|
|
2554
|
+
return () => clearInterval(timer);
|
|
2555
|
+
}, []);
|
|
2556
|
+
const showNow = now >= day.startMs && now <= day.endMs;
|
|
2557
|
+
const msAtClientY = clientY => {
|
|
2558
|
+
const rect = gridRef.current.getBoundingClientRect();
|
|
2559
|
+
const {
|
|
2560
|
+
day: currentDay,
|
|
2561
|
+
pxPerMs: currentPx
|
|
2562
|
+
} = latest.current;
|
|
2563
|
+
return Math.min(Math.max(currentDay.startMs + (clientY - rect.top) / currentPx, currentDay.startMs), currentDay.endMs - 1);
|
|
2564
|
+
};
|
|
2565
|
+
const finishGesture = () => {
|
|
2566
|
+
const gesture = gestureRef.current;
|
|
2567
|
+
if (!gesture) {
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
clearTimeout(gesture.timer);
|
|
2571
|
+
window.removeEventListener('pointermove', gesture.onMove);
|
|
2572
|
+
window.removeEventListener('pointerup', gesture.onUp);
|
|
2573
|
+
window.removeEventListener('pointercancel', gesture.onCancel);
|
|
2574
|
+
gestureRef.current = null;
|
|
2575
|
+
};
|
|
2576
|
+
react.useEffect(() => finishGesture, []);
|
|
2577
|
+
react.useEffect(() => {
|
|
2578
|
+
const grid = gridRef.current;
|
|
2579
|
+
if (!grid) {
|
|
2580
|
+
return undefined;
|
|
2581
|
+
}
|
|
2582
|
+
const preventScroll = event => {
|
|
2583
|
+
if (gestureRef.current?.active) {
|
|
2584
|
+
event.preventDefault();
|
|
2585
|
+
}
|
|
2586
|
+
};
|
|
2587
|
+
const preventGhostClick = event => {
|
|
2588
|
+
if (Date.now() - touchCommitRef.current < 300) {
|
|
2589
|
+
event.preventDefault();
|
|
2590
|
+
}
|
|
2591
|
+
};
|
|
2592
|
+
grid.addEventListener('touchmove', preventScroll, {
|
|
2593
|
+
passive: false
|
|
2594
|
+
});
|
|
2595
|
+
grid.addEventListener('touchend', preventGhostClick, {
|
|
2596
|
+
passive: false
|
|
2597
|
+
});
|
|
2598
|
+
return () => {
|
|
2599
|
+
grid.removeEventListener('touchmove', preventScroll);
|
|
2600
|
+
grid.removeEventListener('touchend', preventGhostClick);
|
|
2601
|
+
};
|
|
2602
|
+
}, []);
|
|
2603
|
+
const handlePointerDown = event => {
|
|
2604
|
+
if (!gridRef.current?.contains(event.target)) {
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
if (interactionRef) {
|
|
2608
|
+
interactionRef.current = Date.now();
|
|
2609
|
+
}
|
|
2610
|
+
if (event.pointerType === 'mouse' && event.button !== 0) {
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
const {
|
|
2614
|
+
day: currentDay,
|
|
2615
|
+
blockers: currentBlockers,
|
|
2616
|
+
selection: currentSelection,
|
|
2617
|
+
allowMultiSelect: multi
|
|
2618
|
+
} = latest.current;
|
|
2619
|
+
const edgeNode = event.target.closest('[data-selection-edge]');
|
|
2620
|
+
const onSelection = event.target.closest('[data-timeline-selection]');
|
|
2621
|
+
const eventNode = event.target.closest('[data-timeline-event]');
|
|
2622
|
+
const pointerMs = msAtClientY(event.clientY);
|
|
2623
|
+
let gesture;
|
|
2624
|
+
if (edgeNode && currentSelection && multi) {
|
|
2625
|
+
gesture = {
|
|
2626
|
+
type: 'resize',
|
|
2627
|
+
edge: edgeNode.dataset.selectionEdge,
|
|
2628
|
+
active: true
|
|
2629
|
+
};
|
|
2630
|
+
} else if (onSelection && currentSelection) {
|
|
2631
|
+
gesture = {
|
|
2632
|
+
type: 'move',
|
|
2633
|
+
active: true
|
|
2634
|
+
};
|
|
2635
|
+
} else {
|
|
2636
|
+
const gap = getFreeGap(pointerMs, currentBlockers, currentDay);
|
|
2637
|
+
if (!gap) {
|
|
2638
|
+
return;
|
|
2639
|
+
}
|
|
2640
|
+
gesture = {
|
|
2641
|
+
type: 'create',
|
|
2642
|
+
gap,
|
|
2643
|
+
active: event.pointerType === 'mouse',
|
|
2644
|
+
onEvent: !!eventNode
|
|
2645
|
+
};
|
|
2646
|
+
}
|
|
2647
|
+
if (gesture.type !== 'create') {
|
|
2648
|
+
const ownGap = getFreeGap(currentSelection.startMs, currentBlockers, currentDay) || currentDay;
|
|
2649
|
+
gesture.gap = ownGap;
|
|
2650
|
+
gesture.range0 = currentSelection;
|
|
2651
|
+
event.preventDefault();
|
|
2652
|
+
}
|
|
2653
|
+
Object.assign(gesture, {
|
|
2654
|
+
pointerId: event.pointerId,
|
|
2655
|
+
pointerType: event.pointerType,
|
|
2656
|
+
startX: event.clientX,
|
|
2657
|
+
startY: event.clientY,
|
|
2658
|
+
startMs: pointerMs,
|
|
2659
|
+
moved: false
|
|
2660
|
+
});
|
|
2661
|
+
setHover(null);
|
|
2662
|
+
gesture.onMove = moveEvent => {
|
|
2663
|
+
if (moveEvent.pointerId !== gesture.pointerId) {
|
|
2664
|
+
return;
|
|
2665
|
+
}
|
|
2666
|
+
const dx = moveEvent.clientX - gesture.startX;
|
|
2667
|
+
const dy = moveEvent.clientY - gesture.startY;
|
|
2668
|
+
if (!gesture.active) {
|
|
2669
|
+
if (Math.hypot(dx, dy) > TOUCH_SLOP_PX) {
|
|
2670
|
+
finishGesture();
|
|
2671
|
+
}
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
if (!gesture.moved && Math.abs(dy) < DRAG_THRESHOLD_PX) {
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
const {
|
|
2678
|
+
stepMs: step,
|
|
2679
|
+
day: d,
|
|
2680
|
+
allowMultiSelect: canResize
|
|
2681
|
+
} = latest.current;
|
|
2682
|
+
const ms = msAtClientY(moveEvent.clientY);
|
|
2683
|
+
let next;
|
|
2684
|
+
if (gesture.type === 'create') {
|
|
2685
|
+
if (!canResize) {
|
|
2686
|
+
return;
|
|
2687
|
+
}
|
|
2688
|
+
next = createSelectionRange({
|
|
2689
|
+
anchorMs: gesture.startMs,
|
|
2690
|
+
pointerMs: ms,
|
|
2691
|
+
gap: gesture.gap,
|
|
2692
|
+
originMs: d.startMs,
|
|
2693
|
+
stepMs: step
|
|
2694
|
+
});
|
|
2695
|
+
} else if (gesture.type === 'move') {
|
|
2696
|
+
next = moveSelectionRange({
|
|
2697
|
+
range: gesture.range0,
|
|
2698
|
+
deltaMs: ms - gesture.startMs,
|
|
2699
|
+
gap: gesture.gap,
|
|
2700
|
+
originMs: d.startMs,
|
|
2701
|
+
stepMs: step
|
|
2702
|
+
});
|
|
2703
|
+
} else {
|
|
2704
|
+
next = resizeSelectionRange({
|
|
2705
|
+
range: gesture.range0,
|
|
2706
|
+
edge: gesture.edge,
|
|
2707
|
+
pointerMs: ms,
|
|
2708
|
+
gap: gesture.gap,
|
|
2709
|
+
originMs: d.startMs,
|
|
2710
|
+
stepMs: step
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
2713
|
+
gesture.moved = true;
|
|
2714
|
+
gesture.range = next;
|
|
2715
|
+
latest.current.onSelectionDrag(next);
|
|
2716
|
+
};
|
|
2717
|
+
gesture.onUp = upEvent => {
|
|
2718
|
+
if (upEvent.pointerId !== gesture.pointerId) {
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2721
|
+
finishGesture();
|
|
2722
|
+
if (gesture.pointerType !== 'mouse') {
|
|
2723
|
+
touchCommitRef.current = Date.now();
|
|
2724
|
+
}
|
|
2725
|
+
const {
|
|
2726
|
+
unitMs: unit,
|
|
2727
|
+
day: d,
|
|
2728
|
+
onSelectionCommit: commit,
|
|
2729
|
+
onFreeSlotClick: onFreeClick
|
|
2730
|
+
} = latest.current;
|
|
2731
|
+
if (gesture.moved) {
|
|
2732
|
+
suppressClickRef.current = true;
|
|
2733
|
+
setTimeout(() => {
|
|
2734
|
+
suppressClickRef.current = false;
|
|
2735
|
+
}, 0);
|
|
2736
|
+
commit(gesture.range);
|
|
2737
|
+
return;
|
|
2738
|
+
}
|
|
2739
|
+
if (gesture.type !== 'create') {
|
|
2740
|
+
commit(gesture.range0);
|
|
2741
|
+
return;
|
|
2742
|
+
}
|
|
2743
|
+
if (gesture.onEvent) {
|
|
2744
|
+
return;
|
|
2745
|
+
}
|
|
2746
|
+
const range = clickSelectionRange({
|
|
2747
|
+
pointerMs: gesture.startMs,
|
|
2748
|
+
gap: gesture.gap,
|
|
2749
|
+
originMs: d.startMs,
|
|
2750
|
+
unitMs: unit
|
|
2751
|
+
});
|
|
2752
|
+
const slotStart = snapToStep(gesture.startMs, {
|
|
2753
|
+
originMs: d.startMs,
|
|
2754
|
+
stepMs: unit,
|
|
2755
|
+
mode: 'floor'
|
|
1464
2756
|
});
|
|
2757
|
+
onFreeClick?.({
|
|
2758
|
+
start: new Date(slotStart),
|
|
2759
|
+
end: new Date(Math.min(slotStart + unit, d.endMs))
|
|
2760
|
+
});
|
|
2761
|
+
commit(range);
|
|
2762
|
+
};
|
|
2763
|
+
gesture.onCancel = cancelEvent => {
|
|
2764
|
+
if (cancelEvent.pointerId !== gesture.pointerId) {
|
|
2765
|
+
return;
|
|
2766
|
+
}
|
|
2767
|
+
const wasMoved = gesture.moved;
|
|
2768
|
+
finishGesture();
|
|
2769
|
+
if (wasMoved) {
|
|
2770
|
+
latest.current.onSelectionCommit(gesture.range);
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
if (!gesture.active) {
|
|
2774
|
+
gesture.timer = setTimeout(() => {
|
|
2775
|
+
gesture.active = true;
|
|
2776
|
+
navigator.vibrate?.(10);
|
|
2777
|
+
const {
|
|
2778
|
+
day: d,
|
|
2779
|
+
unitMs: unit
|
|
2780
|
+
} = latest.current;
|
|
2781
|
+
const range = clickSelectionRange({
|
|
2782
|
+
pointerMs: gesture.startMs,
|
|
2783
|
+
gap: gesture.gap,
|
|
2784
|
+
originMs: d.startMs,
|
|
2785
|
+
unitMs: unit
|
|
2786
|
+
});
|
|
2787
|
+
gesture.moved = true;
|
|
2788
|
+
gesture.range = range;
|
|
2789
|
+
gesture.startMs = range.startMs;
|
|
2790
|
+
latest.current.onSelectionDrag(range);
|
|
2791
|
+
}, LONG_PRESS_MS);
|
|
1465
2792
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
2793
|
+
finishGesture();
|
|
2794
|
+
gestureRef.current = gesture;
|
|
2795
|
+
window.addEventListener('pointermove', gesture.onMove);
|
|
2796
|
+
window.addEventListener('pointerup', gesture.onUp);
|
|
2797
|
+
window.addEventListener('pointercancel', gesture.onCancel);
|
|
2798
|
+
};
|
|
2799
|
+
const handleHover = event => {
|
|
2800
|
+
if (event.pointerType !== 'mouse' || gestureRef.current || !gridRef.current?.contains(event.target)) {
|
|
2801
|
+
return;
|
|
2802
|
+
}
|
|
2803
|
+
if (event.target.closest('[data-timeline-selection]')) {
|
|
2804
|
+
setHover(null);
|
|
2805
|
+
return;
|
|
2806
|
+
}
|
|
2807
|
+
const ms = msAtClientY(event.clientY);
|
|
2808
|
+
const gap = getFreeGap(ms, blockers, day);
|
|
2809
|
+
if (!gap) {
|
|
2810
|
+
setHover(null);
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
const range = clickSelectionRange({
|
|
2814
|
+
pointerMs: ms,
|
|
2815
|
+
gap,
|
|
2816
|
+
originMs: day.startMs,
|
|
2817
|
+
unitMs
|
|
2818
|
+
});
|
|
2819
|
+
setHover(current => current && current.startMs === range.startMs && current.endMs === range.endMs ? current : range);
|
|
2820
|
+
};
|
|
2821
|
+
const renderEventContent = item => {
|
|
2822
|
+
const {
|
|
2823
|
+
event
|
|
2824
|
+
} = item;
|
|
2825
|
+
if (renderEventBlock) {
|
|
2826
|
+
return renderEventBlock(event, {
|
|
2827
|
+
start: new Date(item.startMs),
|
|
2828
|
+
end: new Date(item.endMs)
|
|
1480
2829
|
});
|
|
1481
2830
|
}
|
|
1482
|
-
if (
|
|
1483
|
-
return
|
|
1484
|
-
|
|
1485
|
-
|
|
2831
|
+
if (renderOccupiedSlot) {
|
|
2832
|
+
return renderOccupiedSlot({
|
|
2833
|
+
start: new Date(item.startMs),
|
|
2834
|
+
end: new Date(item.endMs),
|
|
2835
|
+
status: 'occupied',
|
|
2836
|
+
events: [event]
|
|
2837
|
+
}, {
|
|
2838
|
+
events: [event]
|
|
1486
2839
|
});
|
|
1487
2840
|
}
|
|
1488
|
-
return
|
|
2841
|
+
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
2842
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2843
|
+
className: style$1['timeline-event-title'],
|
|
2844
|
+
children: event.title
|
|
2845
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2846
|
+
className: style$1['timeline-event-time'],
|
|
2847
|
+
children: formatRange(event.start, event.end)
|
|
2848
|
+
})]
|
|
2849
|
+
});
|
|
1489
2850
|
};
|
|
1490
|
-
const
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
}),
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
}) : null,
|
|
1505
|
-
className: style$1['
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
})
|
|
1513
|
-
|
|
1514
|
-
|
|
2851
|
+
const selectionBlock = selection ? /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2852
|
+
"data-timeline-selection": "",
|
|
2853
|
+
className: classNames(style$1['timeline-selection'], {
|
|
2854
|
+
[style$1['timeline-selection-dragging']]: dragging,
|
|
2855
|
+
[style$1['timeline-selection-conflict']]: conflicts.length > 0,
|
|
2856
|
+
[style$1['timeline-selection-compact']]: (selection.endMs - selection.startMs) * pxPerMs < 34
|
|
2857
|
+
}),
|
|
2858
|
+
style: {
|
|
2859
|
+
top: toY(selection.startMs),
|
|
2860
|
+
height: Math.max((selection.endMs - selection.startMs) * pxPerMs, 6)
|
|
2861
|
+
},
|
|
2862
|
+
children: [allowMultiSelect ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2863
|
+
"data-selection-edge": "start",
|
|
2864
|
+
className: classNames(style$1['timeline-selection-edge'], style$1['timeline-selection-edge-start'])
|
|
2865
|
+
}) : null, /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2866
|
+
className: style$1['timeline-selection-label'],
|
|
2867
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2868
|
+
children: formatRange(selection.startMs, selection.endMs)
|
|
2869
|
+
}), conflicts.length ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2870
|
+
className: style$1['timeline-selection-badge'],
|
|
2871
|
+
children: conflicts.length
|
|
2872
|
+
}) : null]
|
|
2873
|
+
}), allowMultiSelect ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2874
|
+
"data-selection-edge": "end",
|
|
2875
|
+
className: classNames(style$1['timeline-selection-edge'], style$1['timeline-selection-edge-end'])
|
|
1515
2876
|
}) : null]
|
|
2877
|
+
}) : null;
|
|
2878
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2879
|
+
className: style$1['timeline'],
|
|
2880
|
+
style: {
|
|
2881
|
+
height
|
|
2882
|
+
},
|
|
2883
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2884
|
+
className: style$1['timeline-axis'],
|
|
2885
|
+
"aria-hidden": true,
|
|
2886
|
+
children: labels.map(ms => /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2887
|
+
className: style$1['timeline-axis-label'],
|
|
2888
|
+
style: {
|
|
2889
|
+
top: toY(ms)
|
|
2890
|
+
},
|
|
2891
|
+
children: dayjs__default["default"](ms).format(TIME_FORMAT)
|
|
2892
|
+
}, ms))
|
|
2893
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2894
|
+
ref: gridRef,
|
|
2895
|
+
className: classNames(style$1['timeline-grid'], {
|
|
2896
|
+
[style$1['timeline-grid-dragging']]: dragging
|
|
2897
|
+
}),
|
|
2898
|
+
onPointerDown: handlePointerDown,
|
|
2899
|
+
onPointerMove: handleHover,
|
|
2900
|
+
onPointerLeave: () => setHover(null),
|
|
2901
|
+
onContextMenu: event => {
|
|
2902
|
+
if (gridRef.current?.contains(event.target)) {
|
|
2903
|
+
event.preventDefault();
|
|
2904
|
+
}
|
|
2905
|
+
},
|
|
2906
|
+
onClickCapture: event => {
|
|
2907
|
+
if (suppressClickRef.current && gridRef.current?.contains(event.target)) {
|
|
2908
|
+
suppressClickRef.current = false;
|
|
2909
|
+
event.stopPropagation();
|
|
2910
|
+
}
|
|
2911
|
+
},
|
|
2912
|
+
children: [lines.map(line => /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2913
|
+
className: classNames(style$1['timeline-line'], {
|
|
2914
|
+
[style$1['timeline-line-hour']]: line.hour
|
|
2915
|
+
}),
|
|
2916
|
+
style: {
|
|
2917
|
+
top: toY(line.ms)
|
|
2918
|
+
}
|
|
2919
|
+
}, line.ms)), disabledRanges.map(range => {
|
|
2920
|
+
const block = /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2921
|
+
className: style$1['timeline-disabled'],
|
|
2922
|
+
style: {
|
|
2923
|
+
top: toY(range.startMs),
|
|
2924
|
+
height: (range.endMs - range.startMs) * pxPerMs
|
|
2925
|
+
},
|
|
2926
|
+
children: range.reason && (range.endMs - range.startMs) * pxPerMs >= 22 ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2927
|
+
className: style$1['timeline-disabled-reason'],
|
|
2928
|
+
children: range.reason
|
|
2929
|
+
}) : null
|
|
2930
|
+
}, range.startMs);
|
|
2931
|
+
return range.reason ? /*#__PURE__*/jsxRuntime.jsx(antd.Tooltip, {
|
|
2932
|
+
title: range.reason,
|
|
2933
|
+
children: block
|
|
2934
|
+
}, range.startMs) : block;
|
|
2935
|
+
}), eventItems.map(item => {
|
|
2936
|
+
const key = `${item.event.id}-${item.startMs}`;
|
|
2937
|
+
const blockHeight = (item.endMs - item.startMs) * pxPerMs;
|
|
2938
|
+
return /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
|
|
2939
|
+
arrow: false,
|
|
2940
|
+
trigger: "click",
|
|
2941
|
+
placement: isMobile ? 'bottom' : 'left',
|
|
2942
|
+
rootClassName: style$1['schedule-popover'],
|
|
2943
|
+
open: activeEventKey === key,
|
|
2944
|
+
onOpenChange: open => setActiveEventKey(open ? key : null),
|
|
2945
|
+
content: /*#__PURE__*/jsxRuntime.jsx(EventDetail, {
|
|
2946
|
+
event: item.event,
|
|
2947
|
+
date: date,
|
|
2948
|
+
onEventClick: onEventClick
|
|
2949
|
+
}),
|
|
2950
|
+
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2951
|
+
"data-timeline-event": "",
|
|
2952
|
+
className: classNames(style$1['timeline-event'], {
|
|
2953
|
+
[style$1['timeline-event-disabled']]: item.event.disabled,
|
|
2954
|
+
[style$1['timeline-event-compact']]: blockHeight < 34
|
|
2955
|
+
}),
|
|
2956
|
+
style: {
|
|
2957
|
+
top: toY(item.startMs),
|
|
2958
|
+
height: Math.max(blockHeight - 2, 4),
|
|
2959
|
+
left: `calc(${item.column / item.columns * 100}% + 2px)`,
|
|
2960
|
+
width: `calc(${100 / item.columns}% - 4px)`,
|
|
2961
|
+
...(item.event.color ? {
|
|
2962
|
+
'--timeline-event-color': item.event.color
|
|
2963
|
+
} : null)
|
|
2964
|
+
},
|
|
2965
|
+
children: renderEventContent(item)
|
|
2966
|
+
})
|
|
2967
|
+
}, key);
|
|
2968
|
+
}), hover && !selection ? /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
2969
|
+
className: style$1['timeline-ghost'],
|
|
2970
|
+
style: {
|
|
2971
|
+
top: toY(hover.startMs),
|
|
2972
|
+
height: (hover.endMs - hover.startMs) * pxPerMs
|
|
2973
|
+
},
|
|
2974
|
+
children: ["+ ", dayjs__default["default"](hover.startMs).format(TIME_FORMAT)]
|
|
2975
|
+
}) : null, showNow ? /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2976
|
+
className: style$1['timeline-now'],
|
|
2977
|
+
style: {
|
|
2978
|
+
top: toY(now)
|
|
2979
|
+
}
|
|
2980
|
+
}) : null, selectionBlock, formPopover && popoverAnchor ? /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
|
|
2981
|
+
arrow: false,
|
|
2982
|
+
trigger: "click",
|
|
2983
|
+
placement: popoverPlacement,
|
|
2984
|
+
rootClassName: style$1['schedule-popover'],
|
|
2985
|
+
open: popoverOpen && !dragging,
|
|
2986
|
+
onOpenChange: onPopoverOpenChange,
|
|
2987
|
+
content: formPopover,
|
|
2988
|
+
destroyOnHidden: true,
|
|
2989
|
+
children: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2990
|
+
"aria-hidden": true,
|
|
2991
|
+
className: style$1['timeline-popover-anchor'],
|
|
2992
|
+
style: {
|
|
2993
|
+
top: toY(popoverAnchor.startMs),
|
|
2994
|
+
height: (popoverAnchor.endMs - popoverAnchor.startMs) * pxPerMs
|
|
2995
|
+
}
|
|
2996
|
+
})
|
|
2997
|
+
}) : null]
|
|
2998
|
+
})]
|
|
1516
2999
|
});
|
|
1517
|
-
const slotHandlers = {
|
|
1518
|
-
onContextMenu,
|
|
1519
|
-
onMouseDown,
|
|
1520
|
-
onPointerDown,
|
|
1521
|
-
onMouseEnter,
|
|
1522
|
-
onMouseUp,
|
|
1523
|
-
onClick
|
|
1524
|
-
};
|
|
1525
|
-
const inner = slot.status === 'disabled' ? /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
1526
|
-
type: "button",
|
|
1527
|
-
className: slotClassName,
|
|
1528
|
-
"data-slot-index": slot.index,
|
|
1529
|
-
"data-slot-status": slot.status,
|
|
1530
|
-
disabled: true,
|
|
1531
|
-
onContextMenu: onContextMenu,
|
|
1532
|
-
onMouseDown: onMouseDown,
|
|
1533
|
-
onPointerDown: onPointerDown,
|
|
1534
|
-
onMouseEnter: onMouseEnter,
|
|
1535
|
-
onMouseUp: onMouseUp,
|
|
1536
|
-
onClick: onClick,
|
|
1537
|
-
children: slotChildren
|
|
1538
|
-
}) : /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
1539
|
-
role: "button",
|
|
1540
|
-
tabIndex: 0,
|
|
1541
|
-
className: slotClassName,
|
|
1542
|
-
"data-slot-index": slot.index,
|
|
1543
|
-
"data-slot-status": slot.status,
|
|
1544
|
-
...slotHandlers,
|
|
1545
|
-
children: slotChildren
|
|
1546
|
-
});
|
|
1547
|
-
return wrapWithPopover(inner);
|
|
1548
3000
|
};
|
|
1549
3001
|
|
|
1550
3002
|
function _catch(body, recover) {
|
|
@@ -1558,79 +3010,158 @@ function _catch(body, recover) {
|
|
|
1558
3010
|
}
|
|
1559
3011
|
return result;
|
|
1560
3012
|
}
|
|
1561
|
-
const SchedulePanel =
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
3013
|
+
const SchedulePanel = _ref => {
|
|
3014
|
+
let {
|
|
3015
|
+
date,
|
|
3016
|
+
slots,
|
|
3017
|
+
events: dayEvents,
|
|
3018
|
+
dayStart,
|
|
3019
|
+
dayEnd,
|
|
3020
|
+
timeUnit,
|
|
3021
|
+
timeStep,
|
|
3022
|
+
hourHeight,
|
|
3023
|
+
allowConflict,
|
|
3024
|
+
loading,
|
|
3025
|
+
allowMultiSelect,
|
|
3026
|
+
onSlotRangeChange,
|
|
3027
|
+
onFreeSlotClick,
|
|
3028
|
+
onCreate,
|
|
3029
|
+
formInner,
|
|
3030
|
+
formProps,
|
|
3031
|
+
defaultFormValues,
|
|
3032
|
+
renderEventBlock,
|
|
3033
|
+
renderOccupiedSlot,
|
|
3034
|
+
renderPanelHeader,
|
|
3035
|
+
onEventClick
|
|
3036
|
+
} = _ref;
|
|
1579
3037
|
const {
|
|
1580
3038
|
formatMessage
|
|
1581
3039
|
} = reactIntl.useIntl();
|
|
1582
|
-
const
|
|
3040
|
+
const isMobile = responsiveUtils.useIsMobile();
|
|
3041
|
+
const scrollRef = react.useRef(null);
|
|
3042
|
+
const interactionRef = react.useRef(0);
|
|
3043
|
+
const openedAtRef = react.useRef(0);
|
|
3044
|
+
const [selection, setSelection] = react.useState(null);
|
|
3045
|
+
const [dragging, setDragging] = react.useState(false);
|
|
3046
|
+
const [popoverOpen, setPopoverOpen] = react.useState(false);
|
|
3047
|
+
const [popoverPlacement, setPopoverPlacement] = react.useState('left');
|
|
3048
|
+
const [popoverAnchor, setPopoverAnchor] = react.useState(null);
|
|
3049
|
+
const day = react.useMemo(() => ({
|
|
3050
|
+
startMs: parseDayTime(date, dayStart).valueOf(),
|
|
3051
|
+
endMs: parseDayTime(date, dayEnd).valueOf()
|
|
3052
|
+
}), [date, dayEnd, dayStart]);
|
|
3053
|
+
const events = react.useMemo(() => sortEventsByStart(dayEvents || []), [dayEvents]);
|
|
3054
|
+
const eventItems = react.useMemo(() => layoutTimelineEvents(events, day), [day, events]);
|
|
3055
|
+
const disabledRanges = react.useMemo(() => mergeDisabledSlots(slots), [slots]);
|
|
3056
|
+
const blockers = react.useMemo(() => toBlockers(allowConflict ? disabledRanges : [...disabledRanges, ...eventItems]), [allowConflict, disabledRanges, eventItems]);
|
|
3057
|
+
const conflicts = react.useMemo(() => findOverlappingEvents(selection, eventItems.map(item => item.event)), [eventItems, selection]);
|
|
3058
|
+
const gap = selection && getFreeGap(selection.startMs, blockers, day) || day;
|
|
3059
|
+
const windowRange = react.useMemo(() => [new Date(gap.startMs), new Date(gap.endMs)], [gap.startMs, gap.endMs]);
|
|
1583
3060
|
const panelHeader = renderPanelHeader?.({
|
|
1584
3061
|
date: date.toDate(),
|
|
1585
3062
|
mode: 'schedule',
|
|
1586
3063
|
events
|
|
1587
3064
|
});
|
|
1588
|
-
const {
|
|
1589
|
-
activePopoverKey,
|
|
1590
|
-
dragging,
|
|
1591
|
-
formPopoverKey,
|
|
1592
|
-
selectedAnchorKey,
|
|
1593
|
-
selectedKeys,
|
|
1594
|
-
selectSlots,
|
|
1595
|
-
slotsRef,
|
|
1596
|
-
handleMouseDown,
|
|
1597
|
-
handleMouseEnter,
|
|
1598
|
-
handleMouseUp,
|
|
1599
|
-
handleMouseLeave,
|
|
1600
|
-
handlePopoverOpenChange
|
|
1601
|
-
} = useScheduleSelectionGesture({
|
|
1602
|
-
slots,
|
|
1603
|
-
selectedSlots,
|
|
1604
|
-
setSelectedSlots,
|
|
1605
|
-
allowMultiSelect,
|
|
1606
|
-
onSlotRangeChange,
|
|
1607
|
-
onFreeSlotClick
|
|
1608
|
-
});
|
|
1609
3065
|
const {
|
|
1610
3066
|
scrolled,
|
|
1611
3067
|
onScroll
|
|
1612
|
-
} = usePanelScrollShadow(date.format(DATE_FORMAT),
|
|
1613
|
-
const
|
|
3068
|
+
} = usePanelScrollShadow(date.format(DATE_FORMAT), scrollRef);
|
|
3069
|
+
const getFormContext = range => ({
|
|
1614
3070
|
date: date.toDate(),
|
|
1615
|
-
|
|
3071
|
+
start: range ? new Date(range.startMs) : null,
|
|
3072
|
+
end: range ? new Date(range.endMs) : null,
|
|
3073
|
+
slots: findOverlappingSlots(range, slots),
|
|
3074
|
+
conflicts: findOverlappingEvents(range, eventItems.map(item => item.event))
|
|
3075
|
+
});
|
|
3076
|
+
const emitRange = range => {
|
|
3077
|
+
if (range) {
|
|
3078
|
+
onSlotRangeChange?.(findOverlappingSlots(range, slots), {
|
|
3079
|
+
action: 'select',
|
|
3080
|
+
start: new Date(range.startMs),
|
|
3081
|
+
end: new Date(range.endMs)
|
|
3082
|
+
});
|
|
3083
|
+
} else {
|
|
3084
|
+
onSlotRangeChange?.([], {
|
|
3085
|
+
action: 'clear'
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
3088
|
+
};
|
|
3089
|
+
const clearSelection = () => {
|
|
3090
|
+
setPopoverOpen(false);
|
|
3091
|
+
setPopoverAnchor(null);
|
|
3092
|
+
setDragging(false);
|
|
3093
|
+
if (selection) {
|
|
3094
|
+
setSelection(null);
|
|
3095
|
+
emitRange(null);
|
|
3096
|
+
}
|
|
1616
3097
|
};
|
|
1617
|
-
const
|
|
1618
|
-
|
|
3098
|
+
const commitSelection = range => {
|
|
3099
|
+
setDragging(false);
|
|
3100
|
+
if (!range) {
|
|
3101
|
+
return;
|
|
3102
|
+
}
|
|
3103
|
+
if (!popoverOpen) {
|
|
3104
|
+
const stacked = !!scrollRef.current?.closest('[data-schedule-layout="stacked"]');
|
|
3105
|
+
setPopoverPlacement(stacked ? 'bottom' : 'left');
|
|
3106
|
+
setPopoverAnchor(range);
|
|
3107
|
+
}
|
|
3108
|
+
setSelection(range);
|
|
3109
|
+
openedAtRef.current = Date.now();
|
|
3110
|
+
setPopoverOpen(true);
|
|
3111
|
+
emitRange(range);
|
|
3112
|
+
};
|
|
3113
|
+
const formContext = getFormContext(selection);
|
|
3114
|
+
const formPopover = selection ? /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
3115
|
+
className: classNames(style$1['form-popover'], {
|
|
3116
|
+
[style$1['form-sheet-content']]: isMobile
|
|
3117
|
+
}),
|
|
1619
3118
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
1620
3119
|
className: style$1['form-popover-title'],
|
|
1621
3120
|
children: formatMessage({
|
|
1622
|
-
id: 'SchedulePanel.
|
|
1623
|
-
}, {
|
|
1624
|
-
range: formatRange(selectedSlots[0].start, selectedSlots[selectedSlots.length - 1].end)
|
|
3121
|
+
id: 'SchedulePanel.newScheduleTitle'
|
|
1625
3122
|
})
|
|
1626
|
-
}), /*#__PURE__*/jsxRuntime.
|
|
3123
|
+
}), /*#__PURE__*/jsxRuntime.jsx(TimeWindow, {
|
|
3124
|
+
className: style$1['form-time-window'],
|
|
3125
|
+
size: isMobile ? 'default' : 'small',
|
|
3126
|
+
value: [new Date(selection.startMs), new Date(selection.endMs)],
|
|
3127
|
+
range: windowRange,
|
|
3128
|
+
step: timeStep,
|
|
3129
|
+
minDuration: timeStep,
|
|
3130
|
+
resizable: allowMultiSelect,
|
|
3131
|
+
debounceWait: 120,
|
|
3132
|
+
format: "HH:mm",
|
|
3133
|
+
separator: " - ",
|
|
3134
|
+
onChange: value => {
|
|
3135
|
+
if (!value) {
|
|
3136
|
+
return;
|
|
3137
|
+
}
|
|
3138
|
+
const range = {
|
|
3139
|
+
startMs: value[0].getTime(),
|
|
3140
|
+
endMs: value[1].getTime()
|
|
3141
|
+
};
|
|
3142
|
+
setSelection(range);
|
|
3143
|
+
emitRange(range);
|
|
3144
|
+
}
|
|
3145
|
+
}), conflicts.length ? /*#__PURE__*/jsxRuntime.jsx(antd.Alert, {
|
|
3146
|
+
className: style$1['form-conflict'],
|
|
3147
|
+
type: "warning",
|
|
3148
|
+
showIcon: true,
|
|
3149
|
+
title: `${formatMessage({
|
|
3150
|
+
id: 'SchedulePanel.conflict'
|
|
3151
|
+
}, {
|
|
3152
|
+
count: conflicts.length
|
|
3153
|
+
})}:${conflicts.map(event => event.title).join('、')}`
|
|
3154
|
+
}) : null, /*#__PURE__*/jsxRuntime.jsxs(FormInfo.Form, {
|
|
1627
3155
|
...formProps,
|
|
3156
|
+
...(isMobile ? {
|
|
3157
|
+
size: 'large'
|
|
3158
|
+
} : null),
|
|
1628
3159
|
data: getDefaultFormValues(defaultFormValues, formContext),
|
|
1629
3160
|
onSubmit: function (values) {
|
|
1630
3161
|
try {
|
|
1631
3162
|
const _temp = _catch(function () {
|
|
1632
|
-
return Promise.resolve(onCreate?.(values,
|
|
1633
|
-
|
|
3163
|
+
return Promise.resolve(onCreate?.(values, getFormContext(selection))).then(function () {
|
|
3164
|
+
clearSelection();
|
|
1634
3165
|
});
|
|
1635
3166
|
}, function () {});
|
|
1636
3167
|
return Promise.resolve(_temp && _temp.then ? _temp.then(function () {}) : void 0);
|
|
@@ -1641,7 +3172,7 @@ const SchedulePanel = ({
|
|
|
1641
3172
|
children: [formInner || /*#__PURE__*/jsxRuntime.jsx(DefaultFormInner, {}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
1642
3173
|
className: style$1['form-actions'],
|
|
1643
3174
|
children: [/*#__PURE__*/jsxRuntime.jsx(antd.Button, {
|
|
1644
|
-
onClick:
|
|
3175
|
+
onClick: clearSelection,
|
|
1645
3176
|
children: formatMessage({
|
|
1646
3177
|
id: 'SchedulePanel.cancel'
|
|
1647
3178
|
})
|
|
@@ -1653,7 +3184,7 @@ const SchedulePanel = ({
|
|
|
1653
3184
|
})]
|
|
1654
3185
|
})]
|
|
1655
3186
|
}) : null;
|
|
1656
|
-
return /*#__PURE__*/jsxRuntime.
|
|
3187
|
+
return /*#__PURE__*/jsxRuntime.jsxs(antd.Card, {
|
|
1657
3188
|
bordered: false,
|
|
1658
3189
|
title: panelHeader || /*#__PURE__*/jsxRuntime.jsx(PanelTitle, {
|
|
1659
3190
|
date: date,
|
|
@@ -1662,69 +3193,93 @@ const SchedulePanel = ({
|
|
|
1662
3193
|
})
|
|
1663
3194
|
}),
|
|
1664
3195
|
className: panelStyle['panel-card'],
|
|
1665
|
-
children: /*#__PURE__*/jsxRuntime.jsx(antd.Spin, {
|
|
3196
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(antd.Spin, {
|
|
1666
3197
|
spinning: !!loading,
|
|
1667
3198
|
classNames: {
|
|
1668
3199
|
root: panelStyle['panel-spin'],
|
|
1669
3200
|
container: panelStyle['panel-spin-container']
|
|
1670
3201
|
},
|
|
1671
3202
|
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
1672
|
-
ref:
|
|
1673
|
-
className:
|
|
1674
|
-
[style$1['slots-dragging']]: dragging
|
|
1675
|
-
}),
|
|
3203
|
+
ref: scrollRef,
|
|
3204
|
+
className: style$1['slots'],
|
|
1676
3205
|
onScroll: onScroll,
|
|
1677
|
-
onMouseUp: handleMouseUp,
|
|
1678
|
-
onMouseLeave: handleMouseLeave,
|
|
1679
3206
|
children: [/*#__PURE__*/jsxRuntime.jsx(PanelScrollShadow, {
|
|
1680
3207
|
visible: scrolled
|
|
1681
|
-
}), /*#__PURE__*/jsxRuntime.jsx(
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
3208
|
+
}), /*#__PURE__*/jsxRuntime.jsx(Timeline, {
|
|
3209
|
+
date: date.toDate(),
|
|
3210
|
+
day: day,
|
|
3211
|
+
hourHeight: hourHeight,
|
|
3212
|
+
timeUnit: timeUnit,
|
|
3213
|
+
timeStep: timeStep,
|
|
3214
|
+
eventItems: eventItems,
|
|
3215
|
+
disabledRanges: disabledRanges,
|
|
3216
|
+
blockers: blockers,
|
|
3217
|
+
conflicts: conflicts,
|
|
3218
|
+
allowMultiSelect: allowMultiSelect,
|
|
3219
|
+
selection: selection,
|
|
3220
|
+
dragging: dragging,
|
|
3221
|
+
formPopover: isMobile ? null : formPopover,
|
|
3222
|
+
isMobile: isMobile,
|
|
3223
|
+
popoverOpen: popoverOpen,
|
|
3224
|
+
popoverPlacement: popoverPlacement,
|
|
3225
|
+
popoverAnchor: popoverAnchor,
|
|
3226
|
+
interactionRef: interactionRef,
|
|
3227
|
+
onPopoverOpenChange: open => {
|
|
3228
|
+
if (open) {
|
|
3229
|
+
setPopoverOpen(true);
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
if (Date.now() - interactionRef.current < 400) {
|
|
3233
|
+
return;
|
|
3234
|
+
}
|
|
3235
|
+
clearSelection();
|
|
3236
|
+
},
|
|
3237
|
+
onSelectionDrag: range => {
|
|
3238
|
+
setDragging(true);
|
|
3239
|
+
setSelection(range);
|
|
3240
|
+
},
|
|
3241
|
+
onSelectionCommit: commitSelection,
|
|
3242
|
+
onFreeSlotClick: slot => onFreeSlotClick?.({
|
|
3243
|
+
...slot,
|
|
3244
|
+
key: `${date.format(DATE_FORMAT)}-${slot.start.getTime()}`,
|
|
3245
|
+
date: date.format(DATE_FORMAT),
|
|
3246
|
+
status: 'free',
|
|
3247
|
+
events: []
|
|
3248
|
+
}),
|
|
3249
|
+
onEventClick: onEventClick,
|
|
3250
|
+
renderEventBlock: renderEventBlock,
|
|
3251
|
+
renderOccupiedSlot: renderOccupiedSlot
|
|
1713
3252
|
})]
|
|
1714
3253
|
})
|
|
1715
|
-
})
|
|
3254
|
+
}), isMobile ? /*#__PURE__*/jsxRuntime.jsx(antd.Drawer, {
|
|
3255
|
+
placement: "bottom",
|
|
3256
|
+
size: "auto",
|
|
3257
|
+
closable: false,
|
|
3258
|
+
rootClassName: style$1['form-sheet'],
|
|
3259
|
+
open: !!selection && popoverOpen && !dragging,
|
|
3260
|
+
onClose: () => {
|
|
3261
|
+
if (Date.now() - openedAtRef.current < 500) {
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
3264
|
+
clearSelection();
|
|
3265
|
+
},
|
|
3266
|
+
destroyOnHidden: true,
|
|
3267
|
+
children: formPopover
|
|
3268
|
+
}) : null]
|
|
1716
3269
|
});
|
|
1717
3270
|
};
|
|
1718
3271
|
|
|
1719
|
-
var style = {"schedule-calendar-shell":"kne-react-calendar_csu63","schedule-calendar":"kne-react-calendar_5p1TK","calendar-side":"kne-react-calendar_nd7DK","panel-side":"kne-react-calendar_rWvHE","schedule-calendar-stacked":"kne-react-calendar_zGXr5"};
|
|
3272
|
+
var style = {"kne-responsive-boundary":"kne-react-calendar_gh14z","kne-responsive-scroll":"kne-react-calendar_Kfn6L","schedule-calendar-shell":"kne-react-calendar_csu63","schedule-calendar":"kne-react-calendar_5p1TK","calendar-side":"kne-react-calendar_nd7DK","panel-side":"kne-react-calendar_rWvHE","schedule-calendar-event-list-expanded":"kne-react-calendar_Av0q4","schedule-calendar-stacked":"kne-react-calendar_zGXr5"};
|
|
1720
3273
|
|
|
1721
3274
|
dayjs__default["default"].extend(customParseFormat__default["default"]);
|
|
1722
3275
|
const buildMonthRuleCache = _ref => {
|
|
1723
|
-
let
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
3276
|
+
let {
|
|
3277
|
+
currentDate,
|
|
3278
|
+
mode,
|
|
3279
|
+
disabledDate,
|
|
3280
|
+
disabledDateTime,
|
|
3281
|
+
availableDateTime
|
|
3282
|
+
} = _ref;
|
|
1728
3283
|
const cache = new Map();
|
|
1729
3284
|
const monthStart = currentDate.startOf('month');
|
|
1730
3285
|
const monthEnd = currentDate.endOf('month');
|
|
@@ -1742,62 +3297,54 @@ const buildMonthRuleCache = _ref => {
|
|
|
1742
3297
|
return cache;
|
|
1743
3298
|
};
|
|
1744
3299
|
const ScheduleCalendarInner = props => {
|
|
1745
|
-
const
|
|
1746
|
-
mode =
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
calendarProps = props.calendarProps,
|
|
1781
|
-
panelProps = props.panelProps;
|
|
3300
|
+
const {
|
|
3301
|
+
mode = 'view',
|
|
3302
|
+
events = [],
|
|
3303
|
+
loading,
|
|
3304
|
+
disabledDate,
|
|
3305
|
+
disabledDateTime,
|
|
3306
|
+
availableDateTime,
|
|
3307
|
+
badgeMaxCount = 9,
|
|
3308
|
+
timeUnit = 30,
|
|
3309
|
+
dayStart = '09:00',
|
|
3310
|
+
dayEnd = '18:00',
|
|
3311
|
+
timeStep = 5,
|
|
3312
|
+
hourHeight = 56,
|
|
3313
|
+
allowConflict = false,
|
|
3314
|
+
allowMultiSelect = mode === 'schedule',
|
|
3315
|
+
renderDateCell,
|
|
3316
|
+
renderEventItem,
|
|
3317
|
+
renderEventBlock,
|
|
3318
|
+
renderOccupiedSlot,
|
|
3319
|
+
renderPanelHeader,
|
|
3320
|
+
formInner,
|
|
3321
|
+
formProps,
|
|
3322
|
+
defaultFormValues,
|
|
3323
|
+
onDateChange,
|
|
3324
|
+
onEventClick,
|
|
3325
|
+
onFreeSlotClick,
|
|
3326
|
+
onSlotRangeChange,
|
|
3327
|
+
onCreate,
|
|
3328
|
+
className,
|
|
3329
|
+
style: propsStyle,
|
|
3330
|
+
stackAt = LAYOUT_STACK_BREAKPOINT,
|
|
3331
|
+
eventListScrollable = true,
|
|
3332
|
+
calendarProps,
|
|
3333
|
+
panelProps
|
|
3334
|
+
} = props;
|
|
1782
3335
|
const rootRef = react.useRef(null);
|
|
1783
3336
|
const calendarRef = react.useRef(null);
|
|
1784
3337
|
const stacked = useStackedLayout(rootRef, stackAt);
|
|
1785
|
-
const
|
|
1786
|
-
const
|
|
1787
|
-
|
|
1788
|
-
setValue = _useControlValue[1];
|
|
3338
|
+
const eventListExpanded = mode === 'view' && !eventListScrollable;
|
|
3339
|
+
const stackedLayoutStyle = useStackedPanelLayout(rootRef, calendarRef, stacked && !eventListExpanded);
|
|
3340
|
+
const [value, setValue] = useControlValue__default["default"](props);
|
|
1789
3341
|
const selectedDate = react.useMemo(() => toDayjs(value) || dayjs__default["default"](), [value]);
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
current = _useControlledState[0],
|
|
1796
|
-
setCurrent = _useControlledState[1];
|
|
3342
|
+
const [current, setCurrent] = useControlledState({
|
|
3343
|
+
value: props.current,
|
|
3344
|
+
defaultValue: props.defaultCurrent || selectedDate,
|
|
3345
|
+
onChange: props.onCurrentChange
|
|
3346
|
+
});
|
|
1797
3347
|
const currentDate = react.useMemo(() => toDayjs(current) || selectedDate, [current, selectedDate]);
|
|
1798
|
-
const _useState = react.useState([]),
|
|
1799
|
-
selectedSlots = _useState[0],
|
|
1800
|
-
setSelectedSlots = _useState[1];
|
|
1801
3348
|
const eventGroup = react.useMemo(() => groupEventsByDate(events), [events]);
|
|
1802
3349
|
const selectedEvents = react.useMemo(() => eventGroup[selectedDate.format(DATE_FORMAT)] || [], [eventGroup, selectedDate]);
|
|
1803
3350
|
const ruleContext = react.useMemo(() => ({
|
|
@@ -1806,17 +3353,19 @@ const ScheduleCalendarInner = props => {
|
|
|
1806
3353
|
disabledDateTime,
|
|
1807
3354
|
availableDateTime
|
|
1808
3355
|
}), [availableDateTime, disabledDate, disabledDateTime, mode]);
|
|
1809
|
-
const monthRuleCache = react.useMemo(() => buildMonthRuleCache(
|
|
1810
|
-
currentDate
|
|
1811
|
-
|
|
3356
|
+
const monthRuleCache = react.useMemo(() => buildMonthRuleCache({
|
|
3357
|
+
currentDate,
|
|
3358
|
+
...ruleContext
|
|
3359
|
+
}), [currentDate, ruleContext]);
|
|
1812
3360
|
const getDateRule = react.useCallback(date => {
|
|
1813
3361
|
const cached = monthRuleCache.get(date.format(DATE_FORMAT));
|
|
1814
3362
|
if (cached !== undefined) {
|
|
1815
3363
|
return cached;
|
|
1816
3364
|
}
|
|
1817
|
-
return checkRule(
|
|
1818
|
-
date
|
|
1819
|
-
|
|
3365
|
+
return checkRule({
|
|
3366
|
+
date,
|
|
3367
|
+
...ruleContext
|
|
3368
|
+
});
|
|
1820
3369
|
}, [monthRuleCache, ruleContext]);
|
|
1821
3370
|
const slots = react.useMemo(() => generateTimeSlots({
|
|
1822
3371
|
date: selectedDate,
|
|
@@ -1832,8 +3381,7 @@ const ScheduleCalendarInner = props => {
|
|
|
1832
3381
|
const handleSelectDate = (date, info) => {
|
|
1833
3382
|
const nextDate = date.startOf('day').toDate();
|
|
1834
3383
|
setValue(nextDate, info);
|
|
1835
|
-
onDateChange
|
|
1836
|
-
setSelectedSlots([]);
|
|
3384
|
+
onDateChange?.(nextDate, info);
|
|
1837
3385
|
};
|
|
1838
3386
|
const handleCurrentChange = (date, info) => {
|
|
1839
3387
|
setCurrent(date.startOf('month').toDate(), info);
|
|
@@ -1869,13 +3417,14 @@ const ScheduleCalendarInner = props => {
|
|
|
1869
3417
|
style: propsStyle,
|
|
1870
3418
|
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
1871
3419
|
ref: rootRef,
|
|
1872
|
-
className: classNames(style['schedule-calendar'], stacked && style['schedule-calendar-stacked'], className),
|
|
3420
|
+
className: classNames(style['schedule-calendar'], stacked && style['schedule-calendar-stacked'], eventListExpanded && style['schedule-calendar-event-list-expanded'], className),
|
|
1873
3421
|
"data-schedule-layout": stacked ? 'stacked' : 'row',
|
|
1874
|
-
style: stacked ? stackedLayoutStyle : undefined,
|
|
3422
|
+
style: stacked && !eventListExpanded ? stackedLayoutStyle : undefined,
|
|
1875
3423
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
1876
3424
|
ref: calendarRef,
|
|
1877
3425
|
className: style['calendar-side'],
|
|
1878
|
-
children: /*#__PURE__*/jsxRuntime.jsx(antd.Calendar,
|
|
3426
|
+
children: /*#__PURE__*/jsxRuntime.jsx(antd.Calendar, {
|
|
3427
|
+
...calendarProps,
|
|
1879
3428
|
fullscreen: false,
|
|
1880
3429
|
value: currentDate,
|
|
1881
3430
|
headerRender: () => {
|
|
@@ -1901,36 +3450,42 @@ const ScheduleCalendarInner = props => {
|
|
|
1901
3450
|
onPanelChange: date => handleCurrentChange(date, {
|
|
1902
3451
|
source: 'picker'
|
|
1903
3452
|
})
|
|
1904
|
-
})
|
|
1905
|
-
}), /*#__PURE__*/jsxRuntime.jsx("div",
|
|
1906
|
-
className: style['panel-side']
|
|
1907
|
-
|
|
3453
|
+
})
|
|
3454
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
3455
|
+
className: style['panel-side'],
|
|
3456
|
+
...panelProps,
|
|
1908
3457
|
children: mode === 'schedule' ? /*#__PURE__*/jsxRuntime.jsx(SchedulePanel, {
|
|
1909
3458
|
date: selectedDate,
|
|
1910
3459
|
slots: slots,
|
|
3460
|
+
events: selectedEvents,
|
|
3461
|
+
dayStart: dayStart,
|
|
3462
|
+
dayEnd: dayEnd,
|
|
3463
|
+
timeUnit: timeUnit,
|
|
3464
|
+
timeStep: timeStep,
|
|
3465
|
+
hourHeight: hourHeight,
|
|
3466
|
+
allowConflict: allowConflict,
|
|
1911
3467
|
loading: loading,
|
|
1912
3468
|
allowMultiSelect: allowMultiSelect,
|
|
1913
|
-
selectedSlots: selectedSlots,
|
|
1914
|
-
setSelectedSlots: setSelectedSlots,
|
|
1915
3469
|
onSlotRangeChange: onSlotRangeChange,
|
|
1916
3470
|
onFreeSlotClick: onFreeSlotClick,
|
|
1917
3471
|
onCreate: onCreate,
|
|
1918
3472
|
formInner: formInner,
|
|
1919
3473
|
formProps: formProps,
|
|
1920
3474
|
defaultFormValues: defaultFormValues,
|
|
1921
|
-
|
|
3475
|
+
renderEventBlock: renderEventBlock,
|
|
1922
3476
|
renderOccupiedSlot: renderOccupiedSlot,
|
|
1923
3477
|
renderPanelHeader: renderPanelHeader,
|
|
1924
3478
|
onEventClick: onEventClick
|
|
1925
|
-
}) : /*#__PURE__*/jsxRuntime.jsx(ViewPanel, {
|
|
3479
|
+
}, selectedDate.format(DATE_FORMAT)) : /*#__PURE__*/jsxRuntime.jsx(ViewPanel, {
|
|
1926
3480
|
date: selectedDate,
|
|
1927
3481
|
events: selectedEvents,
|
|
1928
3482
|
loading: loading,
|
|
1929
3483
|
renderEventItem: renderEventItem,
|
|
1930
3484
|
renderPanelHeader: renderPanelHeader,
|
|
1931
|
-
onEventClick: onEventClick
|
|
3485
|
+
onEventClick: onEventClick,
|
|
3486
|
+
scrollable: eventListScrollable
|
|
1932
3487
|
})
|
|
1933
|
-
})
|
|
3488
|
+
})]
|
|
1934
3489
|
})
|
|
1935
3490
|
});
|
|
1936
3491
|
};
|
|
@@ -1938,6 +3493,7 @@ const ScheduleCalendar = withLocale(ScheduleCalendarInner);
|
|
|
1938
3493
|
|
|
1939
3494
|
exports.ReactCalendar = ScheduleCalendar;
|
|
1940
3495
|
exports.ScheduleCalendar = ScheduleCalendar;
|
|
3496
|
+
exports.TimeWindow = TimeWindow;
|
|
1941
3497
|
exports.dedupeEventsById = dedupeEventsById;
|
|
1942
3498
|
exports["default"] = ScheduleCalendar;
|
|
1943
3499
|
exports.generateTimeSlots = generateTimeSlots;
|