@kne/react-calendar 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1760 @@
1
+ var react = require('react');
2
+ var dayjs = require('dayjs');
3
+ var customParseFormat = require('dayjs/plugin/customParseFormat');
4
+ var useControlValue = require('@kne/use-control-value');
5
+ var antd = require('antd');
6
+ var reactIntl = require('@kne/react-intl');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+ var FormInfo = require('@kne/form-info');
9
+
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
+
12
+ var dayjs__default = /*#__PURE__*/_interopDefaultLegacy(dayjs);
13
+ var customParseFormat__default = /*#__PURE__*/_interopDefaultLegacy(customParseFormat);
14
+ var useControlValue__default = /*#__PURE__*/_interopDefaultLegacy(useControlValue);
15
+ var FormInfo__default = /*#__PURE__*/_interopDefaultLegacy(FormInfo);
16
+
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
+ const locale$1 = {
28
+ 'Header.today': '今天',
29
+ 'Header.prevMonth': '上一月',
30
+ 'Header.nextMonth': '下一月',
31
+ 'Header.prevYearPage': '上一组年份',
32
+ 'Header.nextYearPage': '下一组年份',
33
+ 'Header.yearLabel': '{year}年',
34
+ 'Header.monthLabel': '{monthName}',
35
+ 'Header.monthPickerItem': '{monthName}',
36
+ 'PanelTitle.dateLabel': '{year}年{monthName}{day}日',
37
+ 'PanelTitle.eventCount': '共 {count} 个日程',
38
+ 'ViewPanel.empty': '暂无日程',
39
+ 'SchedulePanel.selectFreeSlot': '选择空闲时间段',
40
+ 'SchedulePanel.newSchedule': '新增日程:{range}',
41
+ 'SchedulePanel.cancel': '取消',
42
+ 'SchedulePanel.save': '保存',
43
+ 'SlotItem.disabled': '不可选',
44
+ 'SlotItem.occupied': '已占用',
45
+ 'DefaultFormInner.title': '标题',
46
+ 'DefaultFormInner.titlePlaceholder': '请输入日程标题',
47
+ 'DefaultFormInner.detail': '详情',
48
+ 'DefaultFormInner.detailPlaceholder': '请输入日程详情',
49
+ 'Calendar.month.1': '1月',
50
+ 'Calendar.month.2': '2月',
51
+ 'Calendar.month.3': '3月',
52
+ 'Calendar.month.4': '4月',
53
+ 'Calendar.month.5': '5月',
54
+ 'Calendar.month.6': '6月',
55
+ 'Calendar.month.7': '7月',
56
+ 'Calendar.month.8': '8月',
57
+ 'Calendar.month.9': '9月',
58
+ 'Calendar.month.10': '10月',
59
+ 'Calendar.month.11': '11月',
60
+ 'Calendar.month.12': '12月'
61
+ };
62
+
63
+ const locale = {
64
+ 'Header.today': 'Today',
65
+ 'Header.prevMonth': 'Previous month',
66
+ 'Header.nextMonth': 'Next month',
67
+ 'Header.prevYearPage': 'Previous years',
68
+ 'Header.nextYearPage': 'Next years',
69
+ 'Header.yearLabel': '{year}',
70
+ 'Header.monthLabel': '{monthName}',
71
+ 'Header.monthPickerItem': '{monthName}',
72
+ 'PanelTitle.dateLabel': '{monthName} {day}, {year}',
73
+ 'PanelTitle.eventCount': '{count} events',
74
+ 'ViewPanel.empty': 'No events',
75
+ 'SchedulePanel.selectFreeSlot': 'Select an available time slot',
76
+ 'SchedulePanel.newSchedule': 'New event: {range}',
77
+ 'SchedulePanel.cancel': 'Cancel',
78
+ 'SchedulePanel.save': 'Save',
79
+ 'SlotItem.disabled': 'Unavailable',
80
+ 'SlotItem.occupied': 'Occupied',
81
+ 'DefaultFormInner.title': 'Title',
82
+ 'DefaultFormInner.titlePlaceholder': 'Enter event title',
83
+ 'DefaultFormInner.detail': 'Details',
84
+ 'DefaultFormInner.detailPlaceholder': 'Enter event details',
85
+ 'Calendar.month.1': 'Jan',
86
+ 'Calendar.month.2': 'Feb',
87
+ 'Calendar.month.3': 'Mar',
88
+ 'Calendar.month.4': 'Apr',
89
+ 'Calendar.month.5': 'May',
90
+ 'Calendar.month.6': 'Jun',
91
+ 'Calendar.month.7': 'Jul',
92
+ 'Calendar.month.8': 'Aug',
93
+ 'Calendar.month.9': 'Sep',
94
+ 'Calendar.month.10': 'Oct',
95
+ 'Calendar.month.11': 'Nov',
96
+ 'Calendar.month.12': 'Dec'
97
+ };
98
+
99
+ const withLocale = reactIntl.createWithIntlProvider({
100
+ defaultLocale: 'zh-CN',
101
+ messages: {
102
+ 'zh-CN': locale$1,
103
+ 'en-US': locale
104
+ },
105
+ namespace: 'react-calendar'
106
+ });
107
+
108
+ const DATE_FORMAT = 'YYYY-MM-DD';
109
+ const TIME_FORMAT = 'HH:mm';
110
+ /** Stack panels vertically when container width is below this value (px). */
111
+ const LAYOUT_STACK_BREAKPOINT = 560;
112
+ /** Minimum panel viewport height in stacked layout (px), aligned with root min-height. */
113
+ const LAYOUT_MIN_HEIGHT = 560;
114
+
115
+ const measureHeight = node => {
116
+ if (!node) {
117
+ return 0;
118
+ }
119
+ return Math.ceil(node.getBoundingClientRect().height);
120
+ };
121
+ const useStackedPanelLayout = (rootRef, calendarRef, stacked) => {
122
+ const [layoutStyle, setLayoutStyle] = react.useState(undefined);
123
+ react.useLayoutEffect(() => {
124
+ if (!stacked) {
125
+ setLayoutStyle(undefined);
126
+ return undefined;
127
+ }
128
+ const root = rootRef.current;
129
+ const calendar = calendarRef.current;
130
+ if (!root || !calendar) {
131
+ return undefined;
132
+ }
133
+ const update = () => {
134
+ const calendarHeight = measureHeight(calendar);
135
+ const panelViewportHeight = Math.max(calendarHeight, LAYOUT_MIN_HEIGHT);
136
+ const totalHeight = calendarHeight + panelViewportHeight;
137
+ setLayoutStyle({
138
+ height: totalHeight,
139
+ '--schedule-panel-top': `${calendarHeight}px`,
140
+ '--schedule-panel-height': `${panelViewportHeight}px`
141
+ });
142
+ };
143
+ update();
144
+ if (typeof ResizeObserver === 'undefined') {
145
+ window.addEventListener('resize', update);
146
+ return () => window.removeEventListener('resize', update);
147
+ }
148
+ const observer = new ResizeObserver(update);
149
+ observer.observe(calendar);
150
+ observer.observe(root);
151
+ return () => observer.disconnect();
152
+ }, [calendarRef, rootRef, stacked]);
153
+ return layoutStyle;
154
+ };
155
+
156
+ const classNames = function () {
157
+ return [].slice.call(arguments).flatMap(item => {
158
+ if (!item) {
159
+ return [];
160
+ }
161
+ if (typeof item === 'string') {
162
+ return [item];
163
+ }
164
+ return Object.keys(item).filter(key => item[key]);
165
+ }).join(' ');
166
+ };
167
+ const toDayjs = value => {
168
+ if (!value) {
169
+ return null;
170
+ }
171
+ const date = dayjs__default["default"](value);
172
+ return date.isValid() ? date : null;
173
+ };
174
+ const parseDayTime = (date, time) => {
175
+ const day = toDayjs(date) || dayjs__default["default"]();
176
+ const parsed = dayjs__default["default"](day.format(DATE_FORMAT) + " " + time, DATE_FORMAT + " " + TIME_FORMAT);
177
+ return parsed.isValid() ? parsed : day.startOf('day');
178
+ };
179
+ const formatRange = (start, end) => dayjs__default["default"](start).format(TIME_FORMAT) + " - " + dayjs__default["default"](end).format(TIME_FORMAT);
180
+ const getDefaultFormValues = (defaultFormValues, ctx) => {
181
+ if (typeof defaultFormValues === 'function') {
182
+ return defaultFormValues(ctx);
183
+ }
184
+ return _extends({
185
+ title: '',
186
+ detail: ''
187
+ }, defaultFormValues || {});
188
+ };
189
+ const sortEventsByStart = events => [...(events || [])].sort((a, b) => {
190
+ var _toDayjs$valueOf, _toDayjs, _toDayjs$valueOf2, _toDayjs2;
191
+ const aStart = (_toDayjs$valueOf = (_toDayjs = toDayjs(a.start)) == null ? void 0 : _toDayjs.valueOf()) != null ? _toDayjs$valueOf : 0;
192
+ const bStart = (_toDayjs$valueOf2 = (_toDayjs2 = toDayjs(b.start)) == null ? void 0 : _toDayjs2.valueOf()) != null ? _toDayjs$valueOf2 : 0;
193
+ return aStart - bStart;
194
+ });
195
+ const dedupeEventsById = events => {
196
+ const map = new Map();
197
+ (events || []).forEach(event => {
198
+ map.set(event.id, event);
199
+ });
200
+ return [...map.values()];
201
+ };
202
+ const useControlledState = _ref => {
203
+ let value = _ref.value,
204
+ defaultValue = _ref.defaultValue,
205
+ onChange = _ref.onChange;
206
+ const props = {};
207
+ if (typeof value !== 'undefined') {
208
+ props.value = value;
209
+ }
210
+ if (typeof defaultValue !== 'undefined') {
211
+ props.defaultValue = defaultValue;
212
+ }
213
+ if (onChange) {
214
+ props.onChange = onChange;
215
+ }
216
+ return useControlValue__default["default"](props);
217
+ };
218
+
219
+ const getRuleDisabled = (result, defaultReason) => {
220
+ if (!result) {
221
+ return null;
222
+ }
223
+ if (typeof result === 'boolean') {
224
+ return result ? {
225
+ disabled: true,
226
+ reason: defaultReason
227
+ } : null;
228
+ }
229
+ if (result.disabled) {
230
+ return {
231
+ disabled: true,
232
+ reason: result.reason || defaultReason
233
+ };
234
+ }
235
+ return null;
236
+ };
237
+ const checkRule = ({
238
+ date,
239
+ slot,
240
+ mode,
241
+ disabledDate,
242
+ disabledDateTime,
243
+ availableDateTime
244
+ }) => {
245
+ if (disabledDate?.(date.toDate())) {
246
+ return {
247
+ disabled: true
248
+ };
249
+ }
250
+ const ctx = {
251
+ date: date.toDate(),
252
+ mode,
253
+ ...(slot ? {
254
+ slot: {
255
+ start: slot.start.toDate(),
256
+ end: slot.end.toDate()
257
+ }
258
+ } : {})
259
+ };
260
+ const disabledResult = getRuleDisabled(disabledDateTime?.(ctx));
261
+ if (disabledResult) {
262
+ return disabledResult;
263
+ }
264
+ if (availableDateTime && !availableDateTime(ctx)) {
265
+ return {
266
+ disabled: true
267
+ };
268
+ }
269
+ return null;
270
+ };
271
+
272
+ const normalizeEvent = event => {
273
+ const start = toDayjs(event.start || event.date);
274
+ const end = toDayjs(event.end || event.start || event.date);
275
+ return _extends({}, event, {
276
+ start,
277
+ end: end && start && !end.isAfter(start) ? start.add(1, 'minute') : end
278
+ });
279
+ };
280
+ const groupEventsByDate = events => {
281
+ return (events || []).reduce((result, event) => {
282
+ const normalized = normalizeEvent(event);
283
+ if (!normalized.start || !normalized.end) {
284
+ return result;
285
+ }
286
+ const startOfDay = normalized.start.startOf('day');
287
+ const endOfDay = normalized.end.startOf('day');
288
+ let current = startOfDay;
289
+ while (current.isBefore(endOfDay) || current.isSame(endOfDay, 'day')) {
290
+ const key = current.format(DATE_FORMAT);
291
+ result[key] = result[key] || [];
292
+ result[key].push(normalized);
293
+ current = current.add(1, 'day');
294
+ }
295
+ return result;
296
+ }, {});
297
+ };
298
+ const getOverlappingEvents = (slotStart, slotEnd, sortedEvents) => {
299
+ const matched = [];
300
+ for (const event of sortedEvents) {
301
+ if (!event.end.isAfter(slotStart)) {
302
+ continue;
303
+ }
304
+ if (!event.start.isBefore(slotEnd)) {
305
+ break;
306
+ }
307
+ matched.push(event);
308
+ }
309
+ return matched;
310
+ };
311
+ const generateTimeSlots = _ref => {
312
+ let date = _ref.date,
313
+ events = _ref.events,
314
+ _ref$timeUnit = _ref.timeUnit,
315
+ timeUnit = _ref$timeUnit === void 0 ? 30 : _ref$timeUnit,
316
+ _ref$dayStart = _ref.dayStart,
317
+ dayStart = _ref$dayStart === void 0 ? '09:00' : _ref$dayStart,
318
+ _ref$dayEnd = _ref.dayEnd,
319
+ dayEnd = _ref$dayEnd === void 0 ? '18:00' : _ref$dayEnd,
320
+ disabledDate = _ref.disabledDate,
321
+ disabledDateTime = _ref.disabledDateTime,
322
+ availableDateTime = _ref.availableDateTime,
323
+ _ref$mode = _ref.mode,
324
+ mode = _ref$mode === void 0 ? 'schedule' : _ref$mode;
325
+ const selectedDate = toDayjs(date) || dayjs__default["default"]();
326
+ const startAt = parseDayTime(selectedDate, dayStart);
327
+ const endAt = parseDayTime(selectedDate, dayEnd);
328
+ if (!startAt.isBefore(endAt)) {
329
+ return [];
330
+ }
331
+ const normalizedEvents = (events || []).map(normalizeEvent).filter(event => event.start && event.end).sort((a, b) => a.start.valueOf() - b.start.valueOf());
332
+ const slots = [];
333
+ let current = startAt;
334
+ while (current.isBefore(endAt)) {
335
+ const slotStart = current;
336
+ const slotEnd = slotStart.add(timeUnit, 'minute');
337
+ const matchedEvents = getOverlappingEvents(slotStart, slotEnd, normalizedEvents);
338
+ const baseSlot = {
339
+ key: slotStart.format(DATE_FORMAT) + "-" + slotStart.format(TIME_FORMAT),
340
+ date: slotStart.format(DATE_FORMAT),
341
+ start: slotStart,
342
+ end: slotEnd
343
+ };
344
+ const ruleResult = checkRule({
345
+ date: selectedDate,
346
+ slot: baseSlot,
347
+ mode,
348
+ disabledDate,
349
+ disabledDateTime,
350
+ availableDateTime
351
+ });
352
+ slots.push(_extends({}, baseSlot, {
353
+ start: slotStart.toDate(),
354
+ end: slotEnd.toDate(),
355
+ status: ruleResult ? 'disabled' : matchedEvents.length > 0 ? 'occupied' : 'free',
356
+ disabledReason: ruleResult == null ? void 0 : ruleResult.reason,
357
+ events: matchedEvents
358
+ }));
359
+ current = slotEnd;
360
+ }
361
+ return slots;
362
+ };
363
+
364
+ const toDay = value => toDayjs(value) || dayjs__default["default"]();
365
+ const getMonthName = (formatMessage, monthIndex) => formatMessage({
366
+ id: `Calendar.month.${monthIndex + 1}`
367
+ });
368
+ const getPanelDateLabel = (formatMessage, date) => {
369
+ const d = toDay(date);
370
+ const monthIndex = d.month();
371
+ return formatMessage({
372
+ id: 'PanelTitle.dateLabel'
373
+ }, {
374
+ year: d.year(),
375
+ month: monthIndex + 1,
376
+ day: d.date(),
377
+ monthName: getMonthName(formatMessage, monthIndex)
378
+ });
379
+ };
380
+ const getHeaderMonthLabel = (formatMessage, date) => {
381
+ const d = toDay(date);
382
+ const monthIndex = d.month();
383
+ return formatMessage({
384
+ id: 'Header.monthLabel'
385
+ }, {
386
+ month: monthIndex + 1,
387
+ monthName: getMonthName(formatMessage, monthIndex)
388
+ });
389
+ };
390
+ const getMonthPickerItemLabel = (formatMessage, value, monthIndex) => formatMessage({
391
+ id: 'Header.monthPickerItem'
392
+ }, {
393
+ month: monthIndex + 1,
394
+ monthName: getMonthName(formatMessage, monthIndex)
395
+ });
396
+
397
+ var style$4 = {"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
+
399
+ const HeaderNavIcon = ({
400
+ direction,
401
+ className
402
+ }) => /*#__PURE__*/jsxRuntime.jsx("svg", {
403
+ className: className || style$4['header-nav-icon'],
404
+ viewBox: "0 0 16 16",
405
+ "aria-hidden": true,
406
+ focusable: "false",
407
+ children: /*#__PURE__*/jsxRuntime.jsx("path", {
408
+ d: direction === 'prev' ? 'M10 4 L6 8 L10 12' : 'M6 4 L10 8 L6 12',
409
+ fill: "none",
410
+ stroke: "currentColor",
411
+ strokeWidth: "1.8",
412
+ strokeLinecap: "round",
413
+ strokeLinejoin: "round"
414
+ })
415
+ });
416
+
417
+ const YEAR_PAGE_SIZE = 12;
418
+ const getYearPageStart = year => Math.floor(year / YEAR_PAGE_SIZE) * YEAR_PAGE_SIZE;
419
+
420
+ const PickerPanelNav = ({
421
+ label,
422
+ onClick,
423
+ children
424
+ }) => /*#__PURE__*/jsxRuntime.jsx("button", {
425
+ type: "button",
426
+ className: style$4['picker-panel-nav'],
427
+ "aria-label": label,
428
+ onClick: onClick,
429
+ children: children
430
+ });
431
+ const YearPickerPanel = ({
432
+ value,
433
+ pageStart,
434
+ onPageStartChange,
435
+ onSelect
436
+ }) => {
437
+ const {
438
+ formatMessage
439
+ } = reactIntl.useIntl();
440
+ const years = react.useMemo(() => Array.from({
441
+ length: YEAR_PAGE_SIZE
442
+ }, (_, index) => pageStart + index), [pageStart]);
443
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
444
+ className: style$4['picker-panel'],
445
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
446
+ className: style$4['picker-panel-header'],
447
+ children: [/*#__PURE__*/jsxRuntime.jsx(PickerPanelNav, {
448
+ label: formatMessage({
449
+ id: 'Header.prevYearPage'
450
+ }),
451
+ onClick: () => onPageStartChange(pageStart - YEAR_PAGE_SIZE),
452
+ children: /*#__PURE__*/jsxRuntime.jsx(HeaderNavIcon, {
453
+ direction: "prev",
454
+ className: style$4['picker-panel-nav-icon']
455
+ })
456
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
457
+ className: style$4['picker-panel-range'],
458
+ children: [pageStart, "-", pageStart + YEAR_PAGE_SIZE - 1]
459
+ }), /*#__PURE__*/jsxRuntime.jsx(PickerPanelNav, {
460
+ label: formatMessage({
461
+ id: 'Header.nextYearPage'
462
+ }),
463
+ onClick: () => onPageStartChange(pageStart + YEAR_PAGE_SIZE),
464
+ children: /*#__PURE__*/jsxRuntime.jsx(HeaderNavIcon, {
465
+ direction: "next",
466
+ className: style$4['picker-panel-nav-icon']
467
+ })
468
+ })]
469
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
470
+ className: style$4['picker-panel-grid'],
471
+ children: years.map(year => /*#__PURE__*/jsxRuntime.jsx("button", {
472
+ type: "button",
473
+ className: classNames(style$4['picker-cell'], {
474
+ [style$4['picker-cell-active']]: year === value.year()
475
+ }),
476
+ onClick: () => onSelect(year),
477
+ children: year
478
+ }, year))
479
+ })]
480
+ });
481
+ };
482
+
483
+ const MonthPickerPanel = ({
484
+ value,
485
+ onSelect
486
+ }) => {
487
+ const {
488
+ formatMessage
489
+ } = reactIntl.useIntl();
490
+ const months = react.useMemo(() => Array.from({
491
+ length: 12
492
+ }, (_, index) => index), []);
493
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
494
+ className: style$4['picker-panel'],
495
+ children: /*#__PURE__*/jsxRuntime.jsx("div", {
496
+ className: style$4['picker-panel-grid'],
497
+ children: months.map(month => /*#__PURE__*/jsxRuntime.jsx("button", {
498
+ type: "button",
499
+ className: classNames(style$4['picker-cell'], {
500
+ [style$4['picker-cell-active']]: month === value.month()
501
+ }),
502
+ onClick: () => onSelect(month),
503
+ children: getMonthPickerItemLabel(formatMessage, value, month)
504
+ }, month))
505
+ })
506
+ });
507
+ };
508
+
509
+ const HeaderNavButton = ({
510
+ label,
511
+ onClick,
512
+ children
513
+ }) => /*#__PURE__*/jsxRuntime.jsx("button", {
514
+ type: "button",
515
+ className: style$4['header-nav'],
516
+ "aria-label": label,
517
+ onClick: onClick,
518
+ children: children
519
+ });
520
+ const Header = ({
521
+ current,
522
+ showTodayButton,
523
+ onCurrentChange,
524
+ onSelectToday
525
+ }) => {
526
+ const {
527
+ formatMessage
528
+ } = reactIntl.useIntl();
529
+ const date = toDayjs(current) || dayjs__default["default"]();
530
+ const [yearOpen, setYearOpen] = react.useState(false);
531
+ const [monthOpen, setMonthOpen] = react.useState(false);
532
+ const [yearPageStart, setYearPageStart] = react.useState(() => getYearPageStart(date.year()));
533
+ const currentYear = date.year();
534
+ const yearText = formatMessage({
535
+ id: 'Header.yearLabel'
536
+ }, {
537
+ year: date.year()
538
+ });
539
+ const monthText = getHeaderMonthLabel(formatMessage, date);
540
+ react.useEffect(() => {
541
+ if (yearOpen) {
542
+ setYearPageStart(getYearPageStart(currentYear));
543
+ }
544
+ }, [yearOpen, currentYear]);
545
+ const handleYearSelect = year => {
546
+ onCurrentChange(date.year(year), {
547
+ source: 'picker'
548
+ });
549
+ setYearOpen(false);
550
+ };
551
+ const handleMonthSelect = month => {
552
+ onCurrentChange(date.month(month), {
553
+ source: 'picker'
554
+ });
555
+ setMonthOpen(false);
556
+ };
557
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
558
+ className: style$4['calendar-header'],
559
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
560
+ className: style$4['calendar-title'],
561
+ children: [/*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
562
+ open: yearOpen,
563
+ onOpenChange: open => {
564
+ setYearOpen(open);
565
+ if (open) {
566
+ setMonthOpen(false);
567
+ }
568
+ },
569
+ trigger: "click",
570
+ placement: "bottomLeft",
571
+ rootClassName: style$4['header-picker-popover'],
572
+ content: /*#__PURE__*/jsxRuntime.jsx(YearPickerPanel, {
573
+ value: date,
574
+ pageStart: yearPageStart,
575
+ onPageStartChange: setYearPageStart,
576
+ onSelect: handleYearSelect
577
+ }),
578
+ children: /*#__PURE__*/jsxRuntime.jsx("button", {
579
+ type: "button",
580
+ className: style$4['calendar-title-part'],
581
+ children: yearText
582
+ })
583
+ }), /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
584
+ open: monthOpen,
585
+ onOpenChange: open => {
586
+ setMonthOpen(open);
587
+ if (open) {
588
+ setYearOpen(false);
589
+ }
590
+ },
591
+ trigger: "click",
592
+ placement: "bottomLeft",
593
+ rootClassName: style$4['header-picker-popover'],
594
+ content: /*#__PURE__*/jsxRuntime.jsx(MonthPickerPanel, {
595
+ value: date,
596
+ onSelect: handleMonthSelect
597
+ }),
598
+ children: /*#__PURE__*/jsxRuntime.jsx("button", {
599
+ type: "button",
600
+ className: style$4['calendar-title-part'],
601
+ children: monthText
602
+ })
603
+ })]
604
+ }), /*#__PURE__*/jsxRuntime.jsxs(antd.Space, {
605
+ size: 4,
606
+ className: style$4['header-actions'],
607
+ children: [showTodayButton ? /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
608
+ className: style$4['header-today'],
609
+ type: "text",
610
+ size: "small",
611
+ onClick: onSelectToday,
612
+ children: formatMessage({
613
+ id: 'Header.today'
614
+ })
615
+ }) : null, /*#__PURE__*/jsxRuntime.jsx(HeaderNavButton, {
616
+ label: formatMessage({
617
+ id: 'Header.prevMonth'
618
+ }),
619
+ onClick: () => onCurrentChange(date.subtract(1, 'month'), {
620
+ source: 'prevMonth'
621
+ }),
622
+ children: /*#__PURE__*/jsxRuntime.jsx(HeaderNavIcon, {
623
+ direction: "prev"
624
+ })
625
+ }), /*#__PURE__*/jsxRuntime.jsx(HeaderNavButton, {
626
+ label: formatMessage({
627
+ id: 'Header.nextMonth'
628
+ }),
629
+ onClick: () => onCurrentChange(date.add(1, 'month'), {
630
+ source: 'nextMonth'
631
+ }),
632
+ children: /*#__PURE__*/jsxRuntime.jsx(HeaderNavIcon, {
633
+ direction: "next"
634
+ })
635
+ })]
636
+ })]
637
+ });
638
+ };
639
+
640
+ const readWidth = node => {
641
+ if (!node) {
642
+ return 0;
643
+ }
644
+ return node.getBoundingClientRect().width;
645
+ };
646
+ const useStackedLayout = (ref, stackAt) => {
647
+ const [stacked, setStacked] = react.useState(false);
648
+ react.useLayoutEffect(() => {
649
+ const node = ref.current;
650
+ if (!node) {
651
+ return;
652
+ }
653
+ setStacked(readWidth(node) < stackAt);
654
+ }, [ref, stackAt]);
655
+ react.useEffect(() => {
656
+ const node = ref.current;
657
+ if (!node) {
658
+ return undefined;
659
+ }
660
+ const update = () => {
661
+ setStacked(readWidth(node) < stackAt);
662
+ };
663
+ update();
664
+ if (typeof ResizeObserver === 'undefined') {
665
+ window.addEventListener('resize', update);
666
+ return () => window.removeEventListener('resize', update);
667
+ }
668
+ const observer = new ResizeObserver(() => update());
669
+ observer.observe(node);
670
+ return () => observer.disconnect();
671
+ }, [ref, stackAt]);
672
+ return stacked;
673
+ };
674
+
675
+ var style$3 = {"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
+
677
+ const DateCell = ({
678
+ date,
679
+ dayEvents,
680
+ selected,
681
+ currentMonth,
682
+ disabled,
683
+ badgeMaxCount,
684
+ renderDateCell
685
+ }) => {
686
+ const count = dayEvents.length;
687
+ const customCell = renderDateCell?.(date.toDate(), {
688
+ events: dayEvents,
689
+ selected,
690
+ currentMonth
691
+ });
692
+ if (customCell) {
693
+ return customCell;
694
+ }
695
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
696
+ className: classNames(style$3['date-cell'], {
697
+ [style$3['date-selected']]: selected,
698
+ [style$3['date-muted']]: !currentMonth && !selected,
699
+ [style$3['date-disabled']]: disabled && !selected,
700
+ [style$3['date-has-events']]: count > 0 && !selected
701
+ }),
702
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
703
+ className: style$3['date-number'],
704
+ children: date.date()
705
+ }), count ? /*#__PURE__*/jsxRuntime.jsx(antd.Badge, {
706
+ count: count > badgeMaxCount ? `${badgeMaxCount}+` : count,
707
+ size: "small"
708
+ }) : null]
709
+ });
710
+ };
711
+
712
+ const getEventTagLabel = event => {
713
+ if (!event.raw || typeof event.raw !== 'object') {
714
+ return null;
715
+ }
716
+ const {
717
+ label,
718
+ type
719
+ } = event.raw;
720
+ if (typeof label === 'string' && label) {
721
+ return label;
722
+ }
723
+ if (typeof type === 'string' && type) {
724
+ return type;
725
+ }
726
+ return null;
727
+ };
728
+
729
+ var style$2 = {"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
+
731
+ const EventItem = ({
732
+ event,
733
+ date,
734
+ mode,
735
+ renderEventItem,
736
+ onEventClick
737
+ }) => {
738
+ if (renderEventItem) {
739
+ return renderEventItem(event, {
740
+ date,
741
+ mode,
742
+ onEventClick
743
+ });
744
+ }
745
+ const clickable = !event.disabled && (typeof event.onClick === 'function' || typeof onEventClick === 'function');
746
+ const handleClick = () => {
747
+ if (typeof event.onClick === 'function') {
748
+ event.onClick(event, {
749
+ date,
750
+ mode
751
+ });
752
+ return;
753
+ }
754
+ onEventClick?.(event, {
755
+ date,
756
+ mode
757
+ });
758
+ };
759
+ const tagLabel = getEventTagLabel(event);
760
+ return /*#__PURE__*/jsxRuntime.jsx(antd.List.Item, {
761
+ className: style$2['event-list-item'],
762
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
763
+ className: classNames(style$2['event-item'], {
764
+ [style$2['event-item-clickable']]: clickable,
765
+ [style$2['event-item-disabled']]: event.disabled
766
+ }),
767
+ role: clickable ? 'button' : undefined,
768
+ tabIndex: clickable ? 0 : undefined,
769
+ onClick: clickable ? handleClick : undefined,
770
+ onKeyDown: clickable ? eventKey => {
771
+ if (eventKey.key === 'Enter' || eventKey.key === ' ') {
772
+ eventKey.preventDefault();
773
+ handleClick();
774
+ }
775
+ } : undefined,
776
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
777
+ className: style$2['event-item-head'],
778
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
779
+ className: style$2['event-item-title'],
780
+ children: event.title
781
+ }), tagLabel ? /*#__PURE__*/jsxRuntime.jsx(antd.Tag, {
782
+ className: style$2['event-item-tag'],
783
+ color: event.color,
784
+ children: tagLabel
785
+ }) : null]
786
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
787
+ className: style$2['event-item-time'],
788
+ children: formatRange(event.start, event.end)
789
+ }), event.detail ? /*#__PURE__*/jsxRuntime.jsx("div", {
790
+ className: style$2['event-item-detail'],
791
+ children: event.detail
792
+ }) : null]
793
+ })
794
+ });
795
+ };
796
+
797
+ var panelStyle = {"panel-card":"kne-react-calendar_uQsUE","panel-scroll-body":"kne-react-calendar_ujAl5","panel-scroll-content":"kne-react-calendar_t2e0j","panel-spin":"kne-react-calendar_tLux2","panel-spin-container":"kne-react-calendar_iW4mn","panel-title":"kne-react-calendar_C6NB3","panel-scroll-shadow":"kne-react-calendar_3ecxf","panel-scroll-shadow-visible":"kne-react-calendar_TvxhV","detail-card":"kne-react-calendar_3sEou"};
798
+
799
+ const PanelTitle = ({
800
+ date,
801
+ subtitle,
802
+ count
803
+ }) => {
804
+ const {
805
+ formatMessage
806
+ } = reactIntl.useIntl();
807
+ const dateText = getPanelDateLabel(formatMessage, date);
808
+ const countText = typeof count === 'number' ? formatMessage({
809
+ id: 'PanelTitle.eventCount'
810
+ }, {
811
+ count
812
+ }) : null;
813
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
814
+ className: panelStyle['panel-title'],
815
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
816
+ children: dateText
817
+ }), subtitle || countText ? /*#__PURE__*/jsxRuntime.jsx("span", {
818
+ children: subtitle || countText
819
+ }) : null]
820
+ });
821
+ };
822
+
823
+ const PanelScrollShadow = ({
824
+ visible
825
+ }) => /*#__PURE__*/jsxRuntime.jsx("div", {
826
+ className: classNames(panelStyle['panel-scroll-shadow'], {
827
+ [panelStyle['panel-scroll-shadow-visible']]: visible
828
+ }),
829
+ "aria-hidden": true
830
+ });
831
+
832
+ const usePanelScrollShadow = (resetKey, scrollRef) => {
833
+ const [scrolled, setScrolled] = react.useState(false);
834
+ react.useEffect(() => {
835
+ if (scrollRef?.current) {
836
+ scrollRef.current.scrollTop = 0;
837
+ }
838
+ setScrolled(false);
839
+ }, [resetKey, scrollRef]);
840
+ const onScroll = react.useCallback(event => {
841
+ setScrolled(event.currentTarget.scrollTop > 0);
842
+ }, []);
843
+ return {
844
+ scrolled,
845
+ onScroll
846
+ };
847
+ };
848
+
849
+ const ViewPanel = ({
850
+ date,
851
+ events,
852
+ loading,
853
+ renderEventItem,
854
+ renderPanelHeader,
855
+ onEventClick
856
+ }) => {
857
+ const {
858
+ formatMessage
859
+ } = reactIntl.useIntl();
860
+ const sortedEvents = react.useMemo(() => sortEventsByStart(events), [events]);
861
+ const panelHeader = renderPanelHeader?.({
862
+ date: date.toDate(),
863
+ mode: 'view',
864
+ events: sortedEvents
865
+ });
866
+ const scrollRef = react.useRef(null);
867
+ const {
868
+ scrolled,
869
+ onScroll
870
+ } = usePanelScrollShadow(date.format(DATE_FORMAT), scrollRef);
871
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Card, {
872
+ bordered: false,
873
+ title: panelHeader || /*#__PURE__*/jsxRuntime.jsx(PanelTitle, {
874
+ date: date,
875
+ count: sortedEvents.length
876
+ }),
877
+ className: panelStyle['panel-card'],
878
+ children: /*#__PURE__*/jsxRuntime.jsx(antd.Spin, {
879
+ spinning: !!loading,
880
+ classNames: {
881
+ root: panelStyle['panel-spin'],
882
+ container: panelStyle['panel-spin-container']
883
+ },
884
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
885
+ ref: scrollRef,
886
+ className: panelStyle['panel-scroll-body'],
887
+ onScroll: onScroll,
888
+ children: [/*#__PURE__*/jsxRuntime.jsx(PanelScrollShadow, {
889
+ visible: scrolled
890
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
891
+ className: panelStyle['panel-scroll-content'],
892
+ children: sortedEvents.length ? /*#__PURE__*/jsxRuntime.jsx(antd.List, {
893
+ dataSource: sortedEvents,
894
+ renderItem: event => /*#__PURE__*/jsxRuntime.jsx(EventItem, {
895
+ event: event,
896
+ date: date.toDate(),
897
+ mode: "view",
898
+ renderEventItem: renderEventItem,
899
+ onEventClick: onEventClick
900
+ })
901
+ }) : /*#__PURE__*/jsxRuntime.jsx(antd.Empty, {
902
+ description: formatMessage({
903
+ id: 'ViewPanel.empty'
904
+ })
905
+ })
906
+ })]
907
+ })
908
+ })
909
+ });
910
+ };
911
+
912
+ const LONG_PRESS_DELAY = 360;
913
+ const MOVE_THRESHOLD = 18;
914
+ const getPopoverKey = slot => slot ? `form:${slot.key}` : null;
915
+ const getSlotElementFromTouch = (container, touch) => {
916
+ const element = document.elementFromPoint(touch.clientX, touch.clientY);
917
+ const slotElement = element?.closest?.('[data-slot-index]');
918
+ if (!slotElement || !container?.contains(slotElement)) {
919
+ return null;
920
+ }
921
+ return slotElement;
922
+ };
923
+ const getTouchPoint = event => event.changedTouches?.[0] || event.touches?.[0];
924
+ const useScheduleSelectionGesture = ({
925
+ slots,
926
+ selectedSlots,
927
+ setSelectedSlots,
928
+ allowMultiSelect,
929
+ onSlotRangeChange,
930
+ onFreeSlotClick
931
+ }) => {
932
+ const [dragging, setDragging] = react.useState(false);
933
+ const [activePopoverKey, setActivePopoverKey] = react.useState(null);
934
+ const slotsRef = react.useRef(null);
935
+ const draggingRef = react.useRef(false);
936
+ const dragStartIndexRef = react.useRef(null);
937
+ const longPressTimerRef = react.useRef(null);
938
+ const touchStateRef = react.useRef(null);
939
+ const slotsDataRef = react.useRef(slots);
940
+ const selectedSlotsRef = react.useRef(selectedSlots);
941
+ const suppressTriggerUntilRef = react.useRef(0);
942
+ slotsDataRef.current = slots;
943
+ selectedSlotsRef.current = selectedSlots;
944
+ const selectedKeys = react.useMemo(() => new Set(selectedSlots.map(slot => slot.key)), [selectedSlots]);
945
+ const selectedAnchorKey = selectedSlots[selectedSlots.length - 1]?.key;
946
+ const formPopoverKey = selectedAnchorKey ? `form:${selectedAnchorKey}` : null;
947
+ const clearLongPress = react.useCallback(() => {
948
+ if (longPressTimerRef.current) {
949
+ window.clearTimeout(longPressTimerRef.current);
950
+ longPressTimerRef.current = null;
951
+ }
952
+ }, []);
953
+ const selectSlots = react.useCallback(nextSlots => {
954
+ selectedSlotsRef.current = nextSlots;
955
+ if (!nextSlots.length) {
956
+ setActivePopoverKey(null);
957
+ }
958
+ setSelectedSlots(nextSlots);
959
+ onSlotRangeChange?.(nextSlots, {
960
+ action: nextSlots.length ? 'select' : 'clear'
961
+ });
962
+ }, [onSlotRangeChange, setSelectedSlots]);
963
+ const getSelectableRange = react.useCallback((startIndex, endIndex) => {
964
+ const [start, end] = [Math.min(startIndex, endIndex), Math.max(startIndex, endIndex)];
965
+ return slotsDataRef.current.slice(start, end + 1).filter(slot => slot.status === 'free');
966
+ }, []);
967
+ const showFormPopoverForSlots = react.useCallback(slotsList => {
968
+ const anchorSlot = slotsList[slotsList.length - 1];
969
+ if (anchorSlot) {
970
+ setActivePopoverKey(getPopoverKey(anchorSlot));
971
+ }
972
+ }, []);
973
+ const startSlotSelection = react.useCallback((slot, index, {
974
+ showPopover = true
975
+ } = {}) => {
976
+ setActivePopoverKey(getPopoverKey(slot));
977
+ draggingRef.current = true;
978
+ dragStartIndexRef.current = index;
979
+ slotsRef.current?.classList.add('schedule-calendar-touch-dragging');
980
+ setDragging(true);
981
+ selectSlots([slot]);
982
+ if (!showPopover) {
983
+ suppressTriggerUntilRef.current = Date.now() + 700;
984
+ setActivePopoverKey(null);
985
+ }
986
+ onFreeSlotClick?.(slot);
987
+ }, [onFreeSlotClick, selectSlots]);
988
+ const finishSelection = react.useCallback(({
989
+ fromTouch = false
990
+ } = {}) => {
991
+ clearLongPress();
992
+ draggingRef.current = false;
993
+ dragStartIndexRef.current = null;
994
+ slotsRef.current?.classList.remove('schedule-calendar-touch-dragging');
995
+ setDragging(false);
996
+ if (selectedSlotsRef.current.length) {
997
+ if (fromTouch) {
998
+ suppressTriggerUntilRef.current = Date.now() + 500;
999
+ }
1000
+ showFormPopoverForSlots(selectedSlotsRef.current);
1001
+ }
1002
+ }, [clearLongPress, showFormPopoverForSlots]);
1003
+ const updateSelectionRange = react.useCallback(index => {
1004
+ const startIndex = dragStartIndexRef.current;
1005
+ if (startIndex === null || !allowMultiSelect) {
1006
+ return;
1007
+ }
1008
+ const nextSlots = getSelectableRange(startIndex, index);
1009
+ selectSlots(nextSlots);
1010
+ }, [allowMultiSelect, getSelectableRange, selectSlots]);
1011
+ const handleMouseDown = react.useCallback((event, slot, index) => {
1012
+ if (slot.status !== 'free') {
1013
+ return;
1014
+ }
1015
+ event.preventDefault();
1016
+ startSlotSelection(slot, index);
1017
+ }, [startSlotSelection]);
1018
+ const handleMouseEnter = react.useCallback(index => {
1019
+ if (!draggingRef.current) {
1020
+ return;
1021
+ }
1022
+ updateSelectionRange(index);
1023
+ }, [updateSelectionRange]);
1024
+ const handlePopoverOpenChange = react.useCallback((open, currentPopoverKey, {
1025
+ isForm = false
1026
+ } = {}) => {
1027
+ if (Date.now() < suppressTriggerUntilRef.current) {
1028
+ return;
1029
+ }
1030
+ if (!open && isForm) {
1031
+ selectSlots([]);
1032
+ return;
1033
+ }
1034
+ setActivePopoverKey(prevKey => {
1035
+ if (open) {
1036
+ return currentPopoverKey;
1037
+ }
1038
+ return prevKey === currentPopoverKey ? null : prevKey;
1039
+ });
1040
+ }, [selectSlots]);
1041
+ react.useEffect(() => {
1042
+ const container = slotsRef.current;
1043
+ if (!container) {
1044
+ return undefined;
1045
+ }
1046
+ const clearTouchState = () => {
1047
+ clearLongPress();
1048
+ if (!draggingRef.current) {
1049
+ slotsRef.current?.classList.remove('schedule-calendar-touch-dragging');
1050
+ }
1051
+ touchStateRef.current = null;
1052
+ };
1053
+ const handleTouchStart = event => {
1054
+ if (event.touches.length !== 1) {
1055
+ return;
1056
+ }
1057
+ const touch = event.touches[0];
1058
+ const slotElement = getSlotElementFromTouch(container, touch);
1059
+ if (!slotElement) {
1060
+ return;
1061
+ }
1062
+ const index = Number(slotElement.getAttribute('data-slot-index'));
1063
+ const slot = slotsDataRef.current[index];
1064
+ if (Number.isNaN(index) || slot?.status !== 'free') {
1065
+ return;
1066
+ }
1067
+ clearTouchState();
1068
+ touchStateRef.current = {
1069
+ identifier: touch.identifier,
1070
+ x: touch.clientX,
1071
+ y: touch.clientY,
1072
+ slot,
1073
+ index,
1074
+ moved: false,
1075
+ longPressed: false,
1076
+ active: false
1077
+ };
1078
+ longPressTimerRef.current = window.setTimeout(() => {
1079
+ const touchState = touchStateRef.current;
1080
+ if (!touchState) {
1081
+ return;
1082
+ }
1083
+ touchState.longPressed = true;
1084
+ touchState.active = true;
1085
+ slotsRef.current?.classList.add('schedule-calendar-touch-dragging');
1086
+ startSlotSelection(slot, index, {
1087
+ showPopover: false
1088
+ });
1089
+ longPressTimerRef.current = null;
1090
+ }, LONG_PRESS_DELAY);
1091
+ };
1092
+ const handleTouchMove = event => {
1093
+ const touchState = touchStateRef.current;
1094
+ if (!touchState) {
1095
+ return;
1096
+ }
1097
+ const touch = Array.from(event.touches).find(item => item.identifier === touchState.identifier) || event.touches[0];
1098
+ if (!touch) {
1099
+ return;
1100
+ }
1101
+ if (!touchState.active) {
1102
+ const moveX = Math.abs(touch.clientX - touchState.x);
1103
+ const moveY = Math.abs(touch.clientY - touchState.y);
1104
+ if (moveX > MOVE_THRESHOLD || moveY > MOVE_THRESHOLD) {
1105
+ touchState.moved = true;
1106
+ clearTouchState();
1107
+ }
1108
+ return;
1109
+ }
1110
+ event.preventDefault();
1111
+ const slotElement = getSlotElementFromTouch(container, touch);
1112
+ if (!slotElement) {
1113
+ return;
1114
+ }
1115
+ const index = Number(slotElement.getAttribute('data-slot-index'));
1116
+ if (!Number.isNaN(index)) {
1117
+ updateSelectionRange(index);
1118
+ }
1119
+ };
1120
+ const handleTouchEnd = event => {
1121
+ const touchState = touchStateRef.current;
1122
+ if (!touchState) {
1123
+ return;
1124
+ }
1125
+ const touch = Array.from(event.changedTouches || []).find(item => item.identifier === touchState.identifier) || getTouchPoint(event);
1126
+ if (!touch) {
1127
+ clearTouchState();
1128
+ return;
1129
+ }
1130
+ if (touchState.active) {
1131
+ event.preventDefault();
1132
+ suppressTriggerUntilRef.current = Date.now() + 500;
1133
+ finishSelection({
1134
+ fromTouch: true
1135
+ });
1136
+ touchStateRef.current = null;
1137
+ return;
1138
+ }
1139
+ const quickTap = !touchState.longPressed && !touchState.moved;
1140
+ clearTouchState();
1141
+ if (quickTap) {
1142
+ suppressTriggerUntilRef.current = Date.now() + 500;
1143
+ selectSlots([touchState.slot]);
1144
+ showFormPopoverForSlots([touchState.slot]);
1145
+ onFreeSlotClick?.(touchState.slot);
1146
+ }
1147
+ };
1148
+ const handleContextMenu = event => {
1149
+ if (touchStateRef.current || draggingRef.current) {
1150
+ event.preventDefault();
1151
+ }
1152
+ };
1153
+ container.addEventListener('touchstart', handleTouchStart, {
1154
+ passive: true
1155
+ });
1156
+ container.addEventListener('touchmove', handleTouchMove, {
1157
+ passive: false
1158
+ });
1159
+ container.addEventListener('touchend', handleTouchEnd, {
1160
+ passive: false
1161
+ });
1162
+ container.addEventListener('touchcancel', handleTouchEnd, {
1163
+ passive: false
1164
+ });
1165
+ container.addEventListener('contextmenu', handleContextMenu);
1166
+ return () => {
1167
+ clearTouchState();
1168
+ container.removeEventListener('touchstart', handleTouchStart);
1169
+ container.removeEventListener('touchmove', handleTouchMove);
1170
+ container.removeEventListener('touchend', handleTouchEnd);
1171
+ container.removeEventListener('touchcancel', handleTouchEnd);
1172
+ container.removeEventListener('contextmenu', handleContextMenu);
1173
+ };
1174
+ }, [clearLongPress, finishSelection, onFreeSlotClick, selectSlots, showFormPopoverForSlots, startSlotSelection, updateSelectionRange]);
1175
+ return {
1176
+ activePopoverKey,
1177
+ dragging,
1178
+ formPopoverKey,
1179
+ selectedAnchorKey,
1180
+ selectedKeys,
1181
+ setActivePopoverKey,
1182
+ selectSlots,
1183
+ slotsRef,
1184
+ finishSelection,
1185
+ handleMouseDown,
1186
+ handleMouseEnter,
1187
+ handlePopoverOpenChange
1188
+ };
1189
+ };
1190
+
1191
+ const DefaultFormInner = () => {
1192
+ const {
1193
+ formatMessage
1194
+ } = reactIntl.useIntl();
1195
+ return /*#__PURE__*/jsxRuntime.jsx(FormInfo__default["default"], {
1196
+ column: 1,
1197
+ list: [/*#__PURE__*/jsxRuntime.jsx(FormInfo.Input, {
1198
+ name: "title",
1199
+ label: formatMessage({
1200
+ id: 'DefaultFormInner.title'
1201
+ }),
1202
+ rule: "REQ",
1203
+ placeholder: formatMessage({
1204
+ id: 'DefaultFormInner.titlePlaceholder'
1205
+ }),
1206
+ block: true
1207
+ }), /*#__PURE__*/jsxRuntime.jsx(FormInfo.TextArea, {
1208
+ name: "detail",
1209
+ label: formatMessage({
1210
+ id: 'DefaultFormInner.detail'
1211
+ }),
1212
+ placeholder: formatMessage({
1213
+ id: 'DefaultFormInner.detailPlaceholder'
1214
+ }),
1215
+ block: true
1216
+ })]
1217
+ });
1218
+ };
1219
+
1220
+ var style$1 = {"slots":"kne-react-calendar_Ftp-V","slots-content":"kne-react-calendar_ArIB7","slots-dragging":"kne-react-calendar_zOHks","slot-item":"kne-react-calendar_fkkFH","slot-dot":"kne-react-calendar_XjojI","slot-time":"kne-react-calendar_343hW","slot-title":"kne-react-calendar_mkuiI","slot-free":"kne-react-calendar_7kzzQ","slot-occupied":"kne-react-calendar_gdNm7","slot-disabled":"kne-react-calendar_2LDxX","slot-selected":"kne-react-calendar_TYAi6","slot-tag":"kne-react-calendar_-xuUf","form-popover":"kne-react-calendar_W-I5J","schedule-popover":"kne-react-calendar_rVLO8","form-popover-title":"kne-react-calendar_mMpFQ","slot-popover-content":"kne-react-calendar_xYptY","slot-popover-title":"kne-react-calendar_oagF-","form-actions":"kne-react-calendar_4NPv0"};
1221
+
1222
+ const SlotEvents = ({
1223
+ slot,
1224
+ date,
1225
+ onEventClick
1226
+ }) => /*#__PURE__*/jsxRuntime.jsx("div", {
1227
+ className: style$1['slot-popover-content'],
1228
+ children: /*#__PURE__*/jsxRuntime.jsx(antd.List, {
1229
+ size: "small",
1230
+ dataSource: slot.events,
1231
+ renderItem: event => /*#__PURE__*/jsxRuntime.jsx(EventItem, {
1232
+ event: event,
1233
+ date: date,
1234
+ mode: "schedule",
1235
+ onEventClick: onEventClick
1236
+ })
1237
+ })
1238
+ });
1239
+
1240
+ const SlotItem = ({
1241
+ slot,
1242
+ date,
1243
+ selected,
1244
+ formPopover,
1245
+ popoverOpen,
1246
+ onPopoverOpenChange,
1247
+ onContextMenu,
1248
+ onMouseDown,
1249
+ onPointerDown,
1250
+ onMouseEnter,
1251
+ onMouseUp,
1252
+ onClick,
1253
+ onEventClick,
1254
+ renderTimeSlot,
1255
+ renderOccupiedSlot
1256
+ }) => {
1257
+ const {
1258
+ formatMessage
1259
+ } = reactIntl.useIntl();
1260
+ const content = renderTimeSlot?.(slot, {
1261
+ selected
1262
+ });
1263
+ if (content) {
1264
+ const customNode = /*#__PURE__*/jsxRuntime.jsx("div", {
1265
+ "data-slot-index": slot.index,
1266
+ onContextMenu: onContextMenu,
1267
+ onMouseDown: onMouseDown,
1268
+ onPointerDown: onPointerDown,
1269
+ onMouseEnter: onMouseEnter,
1270
+ onMouseUp: onMouseUp,
1271
+ onClick: onClick,
1272
+ children: content
1273
+ });
1274
+ if (formPopover) {
1275
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
1276
+ rootClassName: style$1['schedule-popover'],
1277
+ open: popoverOpen,
1278
+ onOpenChange: onPopoverOpenChange,
1279
+ content: formPopover,
1280
+ trigger: "click",
1281
+ placement: "bottom",
1282
+ autoAdjustOverflow: true,
1283
+ children: customNode
1284
+ });
1285
+ }
1286
+ return customNode;
1287
+ }
1288
+ const wrapWithPopover = node => {
1289
+ if (formPopover) {
1290
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
1291
+ rootClassName: style$1['schedule-popover'],
1292
+ open: popoverOpen,
1293
+ onOpenChange: onPopoverOpenChange,
1294
+ content: formPopover,
1295
+ trigger: "click",
1296
+ placement: "bottom",
1297
+ autoAdjustOverflow: true,
1298
+ children: node
1299
+ });
1300
+ }
1301
+ if (slot.status === 'occupied') {
1302
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
1303
+ rootClassName: style$1['schedule-popover'],
1304
+ open: popoverOpen,
1305
+ onOpenChange: onPopoverOpenChange,
1306
+ content: /*#__PURE__*/jsxRuntime.jsx(SlotEvents, {
1307
+ slot: slot,
1308
+ date: date,
1309
+ onEventClick: onEventClick
1310
+ }),
1311
+ trigger: "click",
1312
+ placement: "bottom",
1313
+ autoAdjustOverflow: true,
1314
+ children: node
1315
+ });
1316
+ }
1317
+ if (slot.disabledReason) {
1318
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Tooltip, {
1319
+ title: slot.disabledReason,
1320
+ children: node
1321
+ });
1322
+ }
1323
+ return node;
1324
+ };
1325
+ const inner = /*#__PURE__*/jsxRuntime.jsxs("button", {
1326
+ type: "button",
1327
+ className: classNames(style$1['slot-item'], style$1[`slot-${slot.status}`], {
1328
+ [style$1['slot-selected']]: selected
1329
+ }),
1330
+ "data-slot-index": slot.index,
1331
+ disabled: slot.status === 'disabled',
1332
+ onContextMenu: onContextMenu,
1333
+ onMouseDown: onMouseDown,
1334
+ onPointerDown: onPointerDown,
1335
+ onMouseEnter: onMouseEnter,
1336
+ onMouseUp: onMouseUp,
1337
+ onClick: onClick,
1338
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
1339
+ className: style$1['slot-dot']
1340
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
1341
+ className: style$1['slot-time'],
1342
+ children: formatRange(slot.start, slot.end)
1343
+ }), slot.status === 'disabled' ? /*#__PURE__*/jsxRuntime.jsx(antd.Tag, {
1344
+ className: style$1['slot-tag'],
1345
+ children: formatMessage({
1346
+ id: 'SlotItem.disabled'
1347
+ })
1348
+ }) : null, slot.status === 'occupied' ? /*#__PURE__*/jsxRuntime.jsx(antd.Tag, {
1349
+ className: style$1['slot-tag'],
1350
+ color: "red",
1351
+ children: formatMessage({
1352
+ id: 'SlotItem.occupied'
1353
+ })
1354
+ }) : null, slot.status === 'occupied' && renderOccupiedSlot ? renderOccupiedSlot(slot, {
1355
+ events: slot.events
1356
+ }) : null, slot.status === 'occupied' && !renderOccupiedSlot ? /*#__PURE__*/jsxRuntime.jsx("span", {
1357
+ className: style$1['slot-title'],
1358
+ children: slot.events.map(event => event.title).join('、')
1359
+ }) : null]
1360
+ });
1361
+ return wrapWithPopover(inner);
1362
+ };
1363
+
1364
+ function _catch(body, recover) {
1365
+ try {
1366
+ var result = body();
1367
+ } catch (e) {
1368
+ return recover(e);
1369
+ }
1370
+ if (result && result.then) {
1371
+ return result.then(void 0, recover);
1372
+ }
1373
+ return result;
1374
+ }
1375
+ const SchedulePanel = ({
1376
+ date,
1377
+ slots,
1378
+ loading,
1379
+ allowMultiSelect,
1380
+ selectedSlots,
1381
+ setSelectedSlots,
1382
+ onSlotRangeChange,
1383
+ onFreeSlotClick,
1384
+ onCreate,
1385
+ formInner,
1386
+ formProps,
1387
+ defaultFormValues,
1388
+ renderTimeSlot,
1389
+ renderOccupiedSlot,
1390
+ renderPanelHeader,
1391
+ onEventClick
1392
+ }) => {
1393
+ const {
1394
+ formatMessage
1395
+ } = reactIntl.useIntl();
1396
+ const events = react.useMemo(() => sortEventsByStart(dedupeEventsById(slots.flatMap(slot => slot.events || []))), [slots]);
1397
+ const panelHeader = renderPanelHeader?.({
1398
+ date: date.toDate(),
1399
+ mode: 'schedule',
1400
+ events
1401
+ });
1402
+ const {
1403
+ activePopoverKey,
1404
+ dragging,
1405
+ formPopoverKey,
1406
+ selectedAnchorKey,
1407
+ selectedKeys,
1408
+ selectSlots,
1409
+ slotsRef,
1410
+ finishSelection,
1411
+ handleMouseDown,
1412
+ handleMouseEnter,
1413
+ handlePopoverOpenChange
1414
+ } = useScheduleSelectionGesture({
1415
+ slots,
1416
+ selectedSlots,
1417
+ setSelectedSlots,
1418
+ allowMultiSelect,
1419
+ onSlotRangeChange,
1420
+ onFreeSlotClick
1421
+ });
1422
+ const {
1423
+ scrolled,
1424
+ onScroll
1425
+ } = usePanelScrollShadow(date.format(DATE_FORMAT), slotsRef);
1426
+ const formContext = {
1427
+ date: date.toDate(),
1428
+ slots: selectedSlots
1429
+ };
1430
+ const formPopover = selectedSlots.length && !dragging ? /*#__PURE__*/jsxRuntime.jsxs("div", {
1431
+ className: style$1['form-popover'],
1432
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
1433
+ className: style$1['form-popover-title'],
1434
+ children: formatMessage({
1435
+ id: 'SchedulePanel.newSchedule'
1436
+ }, {
1437
+ range: formatRange(selectedSlots[0].start, selectedSlots[selectedSlots.length - 1].end)
1438
+ })
1439
+ }), /*#__PURE__*/jsxRuntime.jsxs(FormInfo.Form, {
1440
+ ...formProps,
1441
+ data: getDefaultFormValues(defaultFormValues, formContext),
1442
+ onSubmit: function (values) {
1443
+ try {
1444
+ const _temp = _catch(function () {
1445
+ return Promise.resolve(onCreate?.(values, formContext)).then(function () {
1446
+ selectSlots([]);
1447
+ });
1448
+ }, function () {});
1449
+ return Promise.resolve(_temp && _temp.then ? _temp.then(function () {}) : void 0);
1450
+ } catch (e) {
1451
+ return Promise.reject(e);
1452
+ }
1453
+ },
1454
+ children: [formInner || /*#__PURE__*/jsxRuntime.jsx(DefaultFormInner, {}), /*#__PURE__*/jsxRuntime.jsxs("div", {
1455
+ className: style$1['form-actions'],
1456
+ children: [/*#__PURE__*/jsxRuntime.jsx(antd.Button, {
1457
+ onClick: () => selectSlots([]),
1458
+ children: formatMessage({
1459
+ id: 'SchedulePanel.cancel'
1460
+ })
1461
+ }), /*#__PURE__*/jsxRuntime.jsx(FormInfo.SubmitButton, {
1462
+ children: formatMessage({
1463
+ id: 'SchedulePanel.save'
1464
+ })
1465
+ })]
1466
+ })]
1467
+ })]
1468
+ }) : null;
1469
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Card, {
1470
+ bordered: false,
1471
+ title: panelHeader || /*#__PURE__*/jsxRuntime.jsx(PanelTitle, {
1472
+ date: date,
1473
+ subtitle: formatMessage({
1474
+ id: 'SchedulePanel.selectFreeSlot'
1475
+ })
1476
+ }),
1477
+ className: panelStyle['panel-card'],
1478
+ children: /*#__PURE__*/jsxRuntime.jsx(antd.Spin, {
1479
+ spinning: !!loading,
1480
+ classNames: {
1481
+ root: panelStyle['panel-spin'],
1482
+ container: panelStyle['panel-spin-container']
1483
+ },
1484
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
1485
+ ref: slotsRef,
1486
+ className: classNames(style$1['slots'], {
1487
+ [style$1['slots-dragging']]: dragging
1488
+ }),
1489
+ onScroll: onScroll,
1490
+ onMouseUp: () => finishSelection(),
1491
+ onMouseLeave: () => finishSelection(),
1492
+ children: [/*#__PURE__*/jsxRuntime.jsx(PanelScrollShadow, {
1493
+ visible: scrolled
1494
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
1495
+ className: style$1['slots-content'],
1496
+ children: slots.map((slot, index) => {
1497
+ const slotWithIndex = {
1498
+ ...slot,
1499
+ index
1500
+ };
1501
+ const occupiedPopoverKey = `occupied:${slot.key}`;
1502
+ const currentPopoverKey = slot.key === selectedAnchorKey && formPopover ? formPopoverKey : slot.status === 'occupied' ? occupiedPopoverKey : null;
1503
+ return /*#__PURE__*/jsxRuntime.jsx(SlotItem, {
1504
+ slot: slotWithIndex,
1505
+ date: date.toDate(),
1506
+ selected: selectedKeys.has(slot.key),
1507
+ formPopover: slot.key === selectedAnchorKey ? formPopover : null,
1508
+ popoverOpen: !!currentPopoverKey && activePopoverKey === currentPopoverKey,
1509
+ onPopoverOpenChange: open => handlePopoverOpenChange(open, currentPopoverKey, {
1510
+ isForm: currentPopoverKey === formPopoverKey
1511
+ }),
1512
+ renderTimeSlot: renderTimeSlot,
1513
+ renderOccupiedSlot: renderOccupiedSlot,
1514
+ onEventClick: onEventClick,
1515
+ onContextMenu: event => {
1516
+ if (slot.status === 'free') {
1517
+ event.preventDefault();
1518
+ }
1519
+ },
1520
+ onMouseDown: event => handleMouseDown(event, slot, index),
1521
+ onMouseEnter: () => handleMouseEnter(index),
1522
+ onMouseUp: () => finishSelection(),
1523
+ onClick: undefined
1524
+ }, slot.key);
1525
+ })
1526
+ })]
1527
+ })
1528
+ })
1529
+ });
1530
+ };
1531
+
1532
+ var style = {"schedule-calendar-shell":"kne-react-calendar_csu63","schedule-calendar":"kne-react-calendar_5p1TK","calendar-side":"kne-react-calendar_nd7DK","panel-side":"kne-react-calendar_rWvHE","schedule-calendar-stacked":"kne-react-calendar_zGXr5"};
1533
+
1534
+ dayjs__default["default"].extend(customParseFormat__default["default"]);
1535
+ const buildMonthRuleCache = _ref => {
1536
+ let currentDate = _ref.currentDate,
1537
+ mode = _ref.mode,
1538
+ disabledDate = _ref.disabledDate,
1539
+ disabledDateTime = _ref.disabledDateTime,
1540
+ availableDateTime = _ref.availableDateTime;
1541
+ const cache = new Map();
1542
+ const monthStart = currentDate.startOf('month');
1543
+ const monthEnd = currentDate.endOf('month');
1544
+ let cursor = monthStart;
1545
+ while (cursor.isBefore(monthEnd) || cursor.isSame(monthEnd, 'day')) {
1546
+ cache.set(cursor.format(DATE_FORMAT), checkRule({
1547
+ date: cursor,
1548
+ mode,
1549
+ disabledDate,
1550
+ disabledDateTime,
1551
+ availableDateTime
1552
+ }));
1553
+ cursor = cursor.add(1, 'day');
1554
+ }
1555
+ return cache;
1556
+ };
1557
+ const ScheduleCalendarInner = props => {
1558
+ const _props$mode = props.mode,
1559
+ mode = _props$mode === void 0 ? 'view' : _props$mode,
1560
+ _props$events = props.events,
1561
+ events = _props$events === void 0 ? [] : _props$events,
1562
+ loading = props.loading,
1563
+ disabledDate = props.disabledDate,
1564
+ disabledDateTime = props.disabledDateTime,
1565
+ availableDateTime = props.availableDateTime,
1566
+ _props$badgeMaxCount = props.badgeMaxCount,
1567
+ badgeMaxCount = _props$badgeMaxCount === void 0 ? 9 : _props$badgeMaxCount,
1568
+ _props$timeUnit = props.timeUnit,
1569
+ timeUnit = _props$timeUnit === void 0 ? 30 : _props$timeUnit,
1570
+ _props$dayStart = props.dayStart,
1571
+ dayStart = _props$dayStart === void 0 ? '09:00' : _props$dayStart,
1572
+ _props$dayEnd = props.dayEnd,
1573
+ dayEnd = _props$dayEnd === void 0 ? '18:00' : _props$dayEnd,
1574
+ _props$allowMultiSele = props.allowMultiSelect,
1575
+ allowMultiSelect = _props$allowMultiSele === void 0 ? mode === 'schedule' : _props$allowMultiSele,
1576
+ renderDateCell = props.renderDateCell,
1577
+ renderEventItem = props.renderEventItem,
1578
+ renderTimeSlot = props.renderTimeSlot,
1579
+ renderOccupiedSlot = props.renderOccupiedSlot,
1580
+ renderPanelHeader = props.renderPanelHeader,
1581
+ formInner = props.formInner,
1582
+ formProps = props.formProps,
1583
+ defaultFormValues = props.defaultFormValues,
1584
+ onDateChange = props.onDateChange,
1585
+ onEventClick = props.onEventClick,
1586
+ onFreeSlotClick = props.onFreeSlotClick,
1587
+ onSlotRangeChange = props.onSlotRangeChange,
1588
+ onCreate = props.onCreate,
1589
+ className = props.className,
1590
+ propsStyle = props.style,
1591
+ _props$stackAt = props.stackAt,
1592
+ stackAt = _props$stackAt === void 0 ? LAYOUT_STACK_BREAKPOINT : _props$stackAt,
1593
+ calendarProps = props.calendarProps,
1594
+ panelProps = props.panelProps;
1595
+ const rootRef = react.useRef(null);
1596
+ const calendarRef = react.useRef(null);
1597
+ const stacked = useStackedLayout(rootRef, stackAt);
1598
+ const stackedLayoutStyle = useStackedPanelLayout(rootRef, calendarRef, stacked);
1599
+ const _useControlValue = useControlValue__default["default"](props),
1600
+ value = _useControlValue[0],
1601
+ setValue = _useControlValue[1];
1602
+ const selectedDate = react.useMemo(() => toDayjs(value) || dayjs__default["default"](), [value]);
1603
+ const _useControlledState = useControlledState({
1604
+ value: props.current,
1605
+ defaultValue: props.defaultCurrent || selectedDate,
1606
+ onChange: props.onCurrentChange
1607
+ }),
1608
+ current = _useControlledState[0],
1609
+ setCurrent = _useControlledState[1];
1610
+ const currentDate = react.useMemo(() => toDayjs(current) || selectedDate, [current, selectedDate]);
1611
+ const _useState = react.useState([]),
1612
+ selectedSlots = _useState[0],
1613
+ setSelectedSlots = _useState[1];
1614
+ const eventGroup = react.useMemo(() => groupEventsByDate(events), [events]);
1615
+ const selectedEvents = react.useMemo(() => eventGroup[selectedDate.format(DATE_FORMAT)] || [], [eventGroup, selectedDate]);
1616
+ const ruleContext = react.useMemo(() => ({
1617
+ mode,
1618
+ disabledDate,
1619
+ disabledDateTime,
1620
+ availableDateTime
1621
+ }), [availableDateTime, disabledDate, disabledDateTime, mode]);
1622
+ const monthRuleCache = react.useMemo(() => buildMonthRuleCache(_extends({
1623
+ currentDate
1624
+ }, ruleContext)), [currentDate, ruleContext]);
1625
+ const getDateRule = react.useCallback(date => {
1626
+ const cached = monthRuleCache.get(date.format(DATE_FORMAT));
1627
+ if (cached !== undefined) {
1628
+ return cached;
1629
+ }
1630
+ return checkRule(_extends({
1631
+ date
1632
+ }, ruleContext));
1633
+ }, [monthRuleCache, ruleContext]);
1634
+ const slots = react.useMemo(() => generateTimeSlots({
1635
+ date: selectedDate,
1636
+ events: selectedEvents,
1637
+ timeUnit,
1638
+ dayStart,
1639
+ dayEnd,
1640
+ disabledDate,
1641
+ disabledDateTime,
1642
+ availableDateTime,
1643
+ mode
1644
+ }), [availableDateTime, dayEnd, dayStart, disabledDate, disabledDateTime, mode, selectedDate, selectedEvents, timeUnit]);
1645
+ const handleSelectDate = (date, info) => {
1646
+ const nextDate = date.startOf('day').toDate();
1647
+ setValue(nextDate, info);
1648
+ onDateChange == null || onDateChange(nextDate, info);
1649
+ setSelectedSlots([]);
1650
+ };
1651
+ const handleCurrentChange = (date, info) => {
1652
+ setCurrent(date.startOf('month').toDate(), info);
1653
+ };
1654
+ const handleGoToday = () => {
1655
+ const today = dayjs__default["default"]().startOf('day');
1656
+ if (getDateRule(today)) {
1657
+ return;
1658
+ }
1659
+ handleSelectDate(today, {
1660
+ source: 'today'
1661
+ });
1662
+ handleCurrentChange(today, {
1663
+ source: 'today'
1664
+ });
1665
+ };
1666
+ const fullCellRender = date => {
1667
+ const key = date.format(DATE_FORMAT);
1668
+ const dayEvents = eventGroup[key] || [];
1669
+ const disabled = !!getDateRule(date);
1670
+ return /*#__PURE__*/jsxRuntime.jsx(DateCell, {
1671
+ date: date,
1672
+ dayEvents: dayEvents,
1673
+ selected: date.isSame(selectedDate, 'day'),
1674
+ currentMonth: date.isSame(currentDate, 'month'),
1675
+ disabled: disabled,
1676
+ badgeMaxCount: badgeMaxCount,
1677
+ renderDateCell: renderDateCell
1678
+ });
1679
+ };
1680
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
1681
+ className: style['schedule-calendar-shell'],
1682
+ style: propsStyle,
1683
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
1684
+ ref: rootRef,
1685
+ className: classNames(style['schedule-calendar'], stacked && style['schedule-calendar-stacked'], className),
1686
+ "data-schedule-layout": stacked ? 'stacked' : 'row',
1687
+ style: stacked ? stackedLayoutStyle : undefined,
1688
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
1689
+ ref: calendarRef,
1690
+ className: style['calendar-side'],
1691
+ children: /*#__PURE__*/jsxRuntime.jsx(antd.Calendar, _extends({}, calendarProps, {
1692
+ fullscreen: false,
1693
+ value: currentDate,
1694
+ headerRender: () => {
1695
+ const today = dayjs__default["default"]().startOf('day');
1696
+ const todayDisabled = !!getDateRule(today);
1697
+ return /*#__PURE__*/jsxRuntime.jsx(Header, {
1698
+ current: currentDate,
1699
+ showTodayButton: !todayDisabled && (!selectedDate.isSame(today, 'day') || !currentDate.isSame(today, 'month')),
1700
+ onCurrentChange: handleCurrentChange,
1701
+ onSelectToday: handleGoToday
1702
+ });
1703
+ },
1704
+ fullCellRender: fullCellRender,
1705
+ disabledDate: date => !!getDateRule(date),
1706
+ onSelect: date => {
1707
+ if (getDateRule(date)) {
1708
+ return;
1709
+ }
1710
+ handleSelectDate(date, {
1711
+ source: 'date'
1712
+ });
1713
+ },
1714
+ onPanelChange: date => handleCurrentChange(date, {
1715
+ source: 'picker'
1716
+ })
1717
+ }))
1718
+ }), /*#__PURE__*/jsxRuntime.jsx("div", _extends({
1719
+ className: style['panel-side']
1720
+ }, panelProps, {
1721
+ children: mode === 'schedule' ? /*#__PURE__*/jsxRuntime.jsx(SchedulePanel, {
1722
+ date: selectedDate,
1723
+ slots: slots,
1724
+ loading: loading,
1725
+ allowMultiSelect: allowMultiSelect,
1726
+ selectedSlots: selectedSlots,
1727
+ setSelectedSlots: setSelectedSlots,
1728
+ onSlotRangeChange: onSlotRangeChange,
1729
+ onFreeSlotClick: onFreeSlotClick,
1730
+ onCreate: onCreate,
1731
+ formInner: formInner,
1732
+ formProps: formProps,
1733
+ defaultFormValues: defaultFormValues,
1734
+ renderTimeSlot: renderTimeSlot,
1735
+ renderOccupiedSlot: renderOccupiedSlot,
1736
+ renderPanelHeader: renderPanelHeader,
1737
+ onEventClick: onEventClick
1738
+ }) : /*#__PURE__*/jsxRuntime.jsx(ViewPanel, {
1739
+ date: selectedDate,
1740
+ events: selectedEvents,
1741
+ loading: loading,
1742
+ renderEventItem: renderEventItem,
1743
+ renderPanelHeader: renderPanelHeader,
1744
+ onEventClick: onEventClick
1745
+ })
1746
+ }))]
1747
+ })
1748
+ });
1749
+ };
1750
+ const ScheduleCalendar = withLocale(ScheduleCalendarInner);
1751
+
1752
+ exports.ReactCalendar = ScheduleCalendar;
1753
+ exports.ScheduleCalendar = ScheduleCalendar;
1754
+ exports.dedupeEventsById = dedupeEventsById;
1755
+ exports["default"] = ScheduleCalendar;
1756
+ exports.generateTimeSlots = generateTimeSlots;
1757
+ exports.groupEventsByDate = groupEventsByDate;
1758
+ exports.normalizeEvent = normalizeEvent;
1759
+ exports.sortEventsByStart = sortEventsByStart;
1760
+ //# sourceMappingURL=index.js.map