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