@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/README.md +949 -0
- package/dist/en-US.d.ts +36 -0
- package/dist/index.css +843 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +115 -0
- package/dist/index.js +1760 -0
- package/dist/index.js.map +1 -0
- package/dist/index.modern.js +1721 -0
- package/dist/index.modern.js.map +1 -0
- package/dist/locale/en-US.js +38 -0
- package/dist/locale/en-US.js.map +1 -0
- package/dist/locale/en-US.modern.js +38 -0
- package/dist/locale/en-US.modern.js.map +1 -0
- package/dist/locale/zh-CN.js +38 -0
- package/dist/locale/zh-CN.js.map +1 -0
- package/dist/locale/zh-CN.modern.js +38 -0
- package/dist/locale/zh-CN.modern.js.map +1 -0
- package/dist/zh-CN.d.ts +36 -0
- package/package.json +112 -0
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
|