v-calendar-3 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/LICENSE +9 -0
- package/README.md +142 -0
- package/dist/cjs/index.css +1133 -0
- package/dist/cjs/index.js +10699 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/es/index.js +10678 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/style.css +1134 -0
- package/dist/iife/index.js +2 -0
- package/dist/iife/index.js.map +1 -0
- package/dist/mjs/index.mjs +10678 -0
- package/dist/mjs/index.mjs.map +1 -0
- package/dist/mjs/style.css +1134 -0
- package/dist/style.css +1134 -0
- package/dist/types/components/BaseIcon/BaseIcon.vue.d.ts +41 -0
- package/dist/types/components/BaseIcon/icons/IconChevronDown.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/IconChevronLeft.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/IconChevronRight.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/IconClock.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/index.d.ts +4 -0
- package/dist/types/components/BaseSelect/BaseSelect.vue.d.ts +26 -0
- package/dist/types/components/Calendar/Calendar.vue.d.ts +2526 -0
- package/dist/types/components/Calendar/CalendarDay.vue.d.ts +83 -0
- package/dist/types/components/Calendar/CalendarDayPopover.vue.d.ts +3 -0
- package/dist/types/components/Calendar/CalendarHeader.vue.d.ts +13 -0
- package/dist/types/components/Calendar/CalendarNav.vue.d.ts +4 -0
- package/dist/types/components/Calendar/CalendarNavPopover.vue.d.ts +3 -0
- package/dist/types/components/Calendar/CalendarPage.vue.d.ts +3 -0
- package/dist/types/components/Calendar/CalendarPageProvider.vue.d.ts +17 -0
- package/dist/types/components/Calendar/CalendarSlot.vue.d.ts +15 -0
- package/dist/types/components/Calendar/CalendarTitleSelect.vue.d.ts +15 -0
- package/dist/types/components/CalendarGrid/CalendarCell.vue.d.ts +9 -0
- package/dist/types/components/CalendarGrid/CalendarCellPopover.vue.d.ts +209 -0
- package/dist/types/components/CalendarGrid/CalendarDayCell.vue.d.ts +8 -0
- package/dist/types/components/CalendarGrid/CalendarEventDetails.vue.d.ts +15 -0
- package/dist/types/components/CalendarGrid/CalendarEventEdit.vue.d.ts +26 -0
- package/dist/types/components/CalendarGrid/CalendarGrid.vue.d.ts +134 -0
- package/dist/types/components/CalendarGrid/CalendarGridWeek.vue.d.ts +8 -0
- package/dist/types/components/CalendarGrid/CalendarViewSelect.vue.d.ts +3 -0
- package/dist/types/components/CalendarGrid/CalendarWeekCell.vue.d.ts +10 -0
- package/dist/types/components/CalendarGrid/Constraints.d.ts +16 -0
- package/dist/types/components/DatePicker/DatePicker.vue.d.ts +15251 -0
- package/dist/types/components/DatePicker/DatePickerBase.vue.d.ts +3 -0
- package/dist/types/components/DatePicker/DatePickerPopover.vue.d.ts +3 -0
- package/dist/types/components/DatePicker/TimePicker.vue.d.ts +10089 -0
- package/dist/types/components/Popover/Popover.vue.d.ts +72 -0
- package/dist/types/components/Popover/PopoverRow.vue.d.ts +17 -0
- package/dist/types/components/index.d.ts +4 -0
- package/dist/types/index.d.cts +40981 -0
- package/dist/types/index.d.mts +40981 -0
- package/dist/types/index.d.ts +40981 -0
- package/dist/types/use/base.d.ts +67 -0
- package/dist/types/use/calendar.d.ts +2422 -0
- package/dist/types/use/calendarGrid.d.ts +9370 -0
- package/dist/types/use/datePicker.d.ts +20210 -0
- package/dist/types/use/page.d.ts +20 -0
- package/dist/types/use/slots.d.ts +5 -0
- package/dist/types/use/timePicker.d.ts +10089 -0
- package/dist/types/utils/attribute.d.ts +49 -0
- package/dist/types/utils/cache.d.ts +10 -0
- package/dist/types/utils/calendar/event.d.ts +111 -0
- package/dist/types/utils/config/index.d.ts +5 -0
- package/dist/types/utils/date/helpers.d.ts +161 -0
- package/dist/types/utils/date/range.d.ts +74 -0
- package/dist/types/utils/date/repeat.d.ts +34 -0
- package/dist/types/utils/date/rules.d.ts +82 -0
- package/dist/types/utils/defaults/index.d.ts +30 -0
- package/dist/types/utils/defaults/locales.d.ts +9 -0
- package/dist/types/utils/glyph.d.ts +58 -0
- package/dist/types/utils/helpers.d.ts +49 -0
- package/dist/types/utils/locale.d.ts +48 -0
- package/dist/types/utils/page.d.ts +95 -0
- package/dist/types/utils/plugins/index.d.ts +4 -0
- package/dist/types/utils/popovers.d.ts +47 -0
- package/dist/types/utils/theme.d.ts +17 -0
- package/dist/types/utils/touch.d.ts +8 -0
- package/dist/types/utils/useDisplayMode.d.ts +12 -0
- package/dist/types/utils/watchers.d.ts +6 -0
- package/package.json +115 -0
- package/src/components/BaseIcon/BaseIcon.vue +29 -0
- package/src/components/BaseIcon/icons/IconChevronDown.vue +5 -0
- package/src/components/BaseIcon/icons/IconChevronLeft.vue +5 -0
- package/src/components/BaseIcon/icons/IconChevronRight.vue +5 -0
- package/src/components/BaseIcon/icons/IconClock.vue +11 -0
- package/src/components/BaseIcon/icons/index.ts +4 -0
- package/src/components/BaseSelect/BaseSelect.vue +136 -0
- package/src/components/Calendar/Calendar.vue +116 -0
- package/src/components/Calendar/CalendarDay.vue +422 -0
- package/src/components/Calendar/CalendarDayPopover.vue +44 -0
- package/src/components/Calendar/CalendarHeader.vue +203 -0
- package/src/components/Calendar/CalendarNav.vue +325 -0
- package/src/components/Calendar/CalendarNavPopover.vue +24 -0
- package/src/components/Calendar/CalendarPage.vue +140 -0
- package/src/components/Calendar/CalendarPageProvider.vue +15 -0
- package/src/components/Calendar/CalendarSlot.vue +36 -0
- package/src/components/Calendar/CalendarTitleSelect.vue +72 -0
- package/src/components/CalendarGrid/CalendarCell.vue +112 -0
- package/src/components/CalendarGrid/CalendarCellPopover.vue +93 -0
- package/src/components/CalendarGrid/CalendarDayCell.vue +57 -0
- package/src/components/CalendarGrid/CalendarEventDetails.vue +71 -0
- package/src/components/CalendarGrid/CalendarEventEdit.vue +195 -0
- package/src/components/CalendarGrid/CalendarGrid.vue +715 -0
- package/src/components/CalendarGrid/CalendarGridWeek.vue +60 -0
- package/src/components/CalendarGrid/CalendarViewSelect.vue +34 -0
- package/src/components/CalendarGrid/CalendarWeekCell.vue +52 -0
- package/src/components/CalendarGrid/Constraints.ts +40 -0
- package/src/components/DatePicker/DatePicker.vue +27 -0
- package/src/components/DatePicker/DatePickerBase.vue +53 -0
- package/src/components/DatePicker/DatePickerPopover.vue +37 -0
- package/src/components/DatePicker/TimePicker.vue +167 -0
- package/src/components/Popover/Popover.vue +572 -0
- package/src/components/Popover/PopoverRow.vue +94 -0
- package/src/components/index.ts +4 -0
- package/src/index.ts +24 -0
- package/src/styles/index.css +48 -0
- package/src/styles/theme.css +322 -0
- package/src/styles/transitions.css +77 -0
- package/src/use/base.ts +144 -0
- package/src/use/calendar.ts +796 -0
- package/src/use/calendarGrid.ts +954 -0
- package/src/use/datePicker.ts +909 -0
- package/src/use/page.ts +78 -0
- package/src/use/slots.ts +17 -0
- package/src/use/timePicker.ts +194 -0
- package/src/utils/attribute.ts +107 -0
- package/src/utils/cache.ts +30 -0
- package/src/utils/calendar/event.ts +335 -0
- package/src/utils/config/index.ts +11 -0
- package/src/utils/date/helpers.ts +1039 -0
- package/src/utils/date/range.ts +274 -0
- package/src/utils/date/repeat.ts +135 -0
- package/src/utils/date/rules.ts +290 -0
- package/src/utils/defaults/index.ts +77 -0
- package/src/utils/defaults/locales.ts +123 -0
- package/src/utils/defaults/masks.json +15 -0
- package/src/utils/defaults/touch.json +5 -0
- package/src/utils/glyph.ts +305 -0
- package/src/utils/helpers.ts +181 -0
- package/src/utils/locale.ts +275 -0
- package/src/utils/page.ts +608 -0
- package/src/utils/plugins/index.ts +24 -0
- package/src/utils/popovers.ts +216 -0
- package/src/utils/theme.ts +58 -0
- package/src/utils/touch.ts +72 -0
- package/src/utils/useDisplayMode.ts +198 -0
- package/src/utils/watchers.ts +26 -0
|
@@ -0,0 +1,954 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ExtractPropTypes,
|
|
3
|
+
type PropType,
|
|
4
|
+
computed,
|
|
5
|
+
inject,
|
|
6
|
+
nextTick,
|
|
7
|
+
provide,
|
|
8
|
+
ref,
|
|
9
|
+
watch,
|
|
10
|
+
} from 'vue';
|
|
11
|
+
import CalendarCellPopover from '../components/CalendarGrid/CalendarCellPopover.vue';
|
|
12
|
+
import {
|
|
13
|
+
type Event,
|
|
14
|
+
type EventConfig,
|
|
15
|
+
createEvent as _createEvent,
|
|
16
|
+
} from '../utils/calendar/event';
|
|
17
|
+
import { MS_PER_HOUR, roundDate } from '../utils/date/helpers';
|
|
18
|
+
import { DateRange, DateRangeContext } from '../utils/date/range';
|
|
19
|
+
import { on } from '../utils/helpers';
|
|
20
|
+
import type { CalendarDay } from '../utils/page';
|
|
21
|
+
import { propsDef as basePropsDef, createCalendar, emitsDef } from './calendar';
|
|
22
|
+
|
|
23
|
+
type GridState =
|
|
24
|
+
'NORMAL' | 'CREATE_MONITOR' | 'DRAG_MONITOR' | 'RESIZE_MONITOR';
|
|
25
|
+
|
|
26
|
+
export type GridStateEvent =
|
|
27
|
+
| 'GRID_CURSOR_DOWN'
|
|
28
|
+
| 'GRID_CURSOR_DOWN_SHIFT'
|
|
29
|
+
| 'GRID_CURSOR_MOVE'
|
|
30
|
+
| 'GRID_CURSOR_MOVE_SHIFT'
|
|
31
|
+
| 'GRID_CURSOR_UP'
|
|
32
|
+
| 'GRID_CURSOR_UP_SHIFT'
|
|
33
|
+
| 'EVENT_CURSOR_DOWN'
|
|
34
|
+
| 'EVENT_CURSOR_DOWN_SHIFT'
|
|
35
|
+
| 'EVENT_CURSOR_MOVE'
|
|
36
|
+
| 'EVENT_CURSOR_MOVE_SHIFT'
|
|
37
|
+
| 'EVENT_RESIZE_START_CURSOR_DOWN'
|
|
38
|
+
| 'EVENT_RESIZE_START_CURSOR_DOWN_SHIFT'
|
|
39
|
+
| 'EVENT_RESIZE_END_CURSOR_DOWN'
|
|
40
|
+
| 'EVENT_RESIZE_END_CURSOR_DOWN_SHIFT'
|
|
41
|
+
| 'ESCAPE';
|
|
42
|
+
|
|
43
|
+
export interface Point {
|
|
44
|
+
x: number;
|
|
45
|
+
y: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface DragOffset {
|
|
49
|
+
weekdays: number;
|
|
50
|
+
weeks: number;
|
|
51
|
+
ms: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ResizeOffset {
|
|
55
|
+
weekdays: number;
|
|
56
|
+
weeks: number;
|
|
57
|
+
ms: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface DragOriginState {
|
|
61
|
+
position: number;
|
|
62
|
+
date: Date;
|
|
63
|
+
day: CalendarDay;
|
|
64
|
+
event: Event;
|
|
65
|
+
eventSelected: boolean;
|
|
66
|
+
ms: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ResizeOriginState {
|
|
70
|
+
position: number;
|
|
71
|
+
day: CalendarDay;
|
|
72
|
+
event: Event;
|
|
73
|
+
isWeekly: boolean;
|
|
74
|
+
isStart: boolean;
|
|
75
|
+
isNew: boolean;
|
|
76
|
+
ms: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface CreateOriginState {
|
|
80
|
+
position: number;
|
|
81
|
+
date: Date;
|
|
82
|
+
day: CalendarDay;
|
|
83
|
+
isWeekly: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// #region Messages
|
|
87
|
+
|
|
88
|
+
type MessageType =
|
|
89
|
+
| 'event-create-begin'
|
|
90
|
+
| 'event-create-end'
|
|
91
|
+
| 'event-resize-begin'
|
|
92
|
+
| 'event-resize-update'
|
|
93
|
+
| 'event-resize-end'
|
|
94
|
+
| 'event-move-begin'
|
|
95
|
+
| 'event-move-update'
|
|
96
|
+
| 'event-move-end'
|
|
97
|
+
| 'event-remove';
|
|
98
|
+
|
|
99
|
+
class Messages {
|
|
100
|
+
constructor(private emit: Function) {}
|
|
101
|
+
|
|
102
|
+
EventCreateBegin(event: Event) {
|
|
103
|
+
return new CancellableEventMessage(this.emit, 'event-create-begin', event);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
EventCreateEnd(event: Event) {
|
|
107
|
+
return new EventMessage(this.emit, 'event-create-end', event);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
EventResizeBegin(event: Event) {
|
|
111
|
+
return new CancellableEventMessage(this.emit, 'event-resize-begin', event);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
EventResizeUpdate(event: Event, offset: ResizeOffset) {
|
|
115
|
+
return new EventResizeMessage(
|
|
116
|
+
this.emit,
|
|
117
|
+
'event-resize-update',
|
|
118
|
+
event,
|
|
119
|
+
offset,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
EventResizeEnd(event: Event) {
|
|
124
|
+
return new EventMessage(this.emit, 'event-resize-end', event);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
EventMoveBegin(event: Event) {
|
|
128
|
+
return new CancellableEventMessage(this.emit, 'event-move-begin', event);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
EventMoveUpdate(event: Event, offset: DragOffset) {
|
|
132
|
+
return new EventMoveMessage(this.emit, 'event-move-update', event, offset);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
EventMoveEnd(event: Event) {
|
|
136
|
+
return new EventMessage(this.emit, 'event-move-end', event);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
EventRemove(event: Event) {
|
|
140
|
+
return new CancellableEventMessage(this.emit, 'event-remove', event);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
class BaseMessage {
|
|
145
|
+
private emit: Function;
|
|
146
|
+
type: MessageType;
|
|
147
|
+
|
|
148
|
+
constructor(emit: Function, type: MessageType) {
|
|
149
|
+
this.emit = emit;
|
|
150
|
+
this.type = type;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
send() {
|
|
154
|
+
this.emit(this.type, this);
|
|
155
|
+
return this;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async sendAsync() {
|
|
159
|
+
this.emit(this.type, this);
|
|
160
|
+
await nextTick();
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
class EventMessage<T extends Event | EventConfig> extends BaseMessage {
|
|
166
|
+
event: T;
|
|
167
|
+
constructor(emit: Function, type: MessageType, event: T) {
|
|
168
|
+
super(emit, type);
|
|
169
|
+
this.event = event;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
class CancellableEventMessage<
|
|
174
|
+
T extends Event | EventConfig,
|
|
175
|
+
> extends EventMessage<T> {
|
|
176
|
+
cancel = false;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
class EventResizeMessage extends CancellableEventMessage<Event> {
|
|
180
|
+
offset?: ResizeOffset;
|
|
181
|
+
|
|
182
|
+
constructor(
|
|
183
|
+
emit: Function,
|
|
184
|
+
type: MessageType,
|
|
185
|
+
event: Event,
|
|
186
|
+
offset?: ResizeOffset,
|
|
187
|
+
) {
|
|
188
|
+
super(emit, type, event);
|
|
189
|
+
this.offset = offset;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
class EventMoveMessage extends CancellableEventMessage<Event> {
|
|
194
|
+
offset?: DragOffset;
|
|
195
|
+
|
|
196
|
+
constructor(
|
|
197
|
+
emit: Function,
|
|
198
|
+
type: MessageType,
|
|
199
|
+
event: Event,
|
|
200
|
+
offset?: ResizeOffset,
|
|
201
|
+
) {
|
|
202
|
+
super(emit, type, event);
|
|
203
|
+
this.offset = offset;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// #endregion Messages
|
|
208
|
+
|
|
209
|
+
export const emits = [
|
|
210
|
+
...emitsDef,
|
|
211
|
+
'day-header-click',
|
|
212
|
+
'event-create-begin',
|
|
213
|
+
'event-create-end',
|
|
214
|
+
'event-resize-begin',
|
|
215
|
+
'event-resize-update',
|
|
216
|
+
'event-resize-end',
|
|
217
|
+
'event-move-begin',
|
|
218
|
+
'event-move-update',
|
|
219
|
+
'event-move-end',
|
|
220
|
+
'event-remove',
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
const SNAP_MINUTES = 15;
|
|
224
|
+
const PIXELS_PER_HOUR = 50;
|
|
225
|
+
const contextKey = Symbol('__vc_grid_context__');
|
|
226
|
+
|
|
227
|
+
export const propsDef = {
|
|
228
|
+
...basePropsDef,
|
|
229
|
+
events: {
|
|
230
|
+
type: Object as PropType<EventConfig[]>,
|
|
231
|
+
default: () => [],
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export type CalendarGridProps = Readonly<ExtractPropTypes<typeof propsDef>>;
|
|
236
|
+
|
|
237
|
+
export type CalendarGridContext = ReturnType<typeof createCalendarGrid>;
|
|
238
|
+
|
|
239
|
+
type IBoundingRect = Pick<Element, 'getBoundingClientRect' | 'contains'>;
|
|
240
|
+
|
|
241
|
+
export function createCalendarGrid(
|
|
242
|
+
props: CalendarGridProps,
|
|
243
|
+
{ emit, slots }: any,
|
|
244
|
+
) {
|
|
245
|
+
const calendar = createCalendar(props, { emit, slots });
|
|
246
|
+
const cellPopoverRef = ref<typeof CalendarCellPopover>();
|
|
247
|
+
const dailyGridRef = ref<IBoundingRect | null>(null);
|
|
248
|
+
const weeklyGridRef = ref<IBoundingRect | null>(null);
|
|
249
|
+
const activeGridRef = ref<IBoundingRect | null>(null);
|
|
250
|
+
const messages = new Messages(emit);
|
|
251
|
+
|
|
252
|
+
const { view, isDaily, isMonthly, pages, locale, move, onDayFocusin } =
|
|
253
|
+
calendar;
|
|
254
|
+
|
|
255
|
+
const page = computed(() => pages.value[0]);
|
|
256
|
+
const days = computed(() => page.value.viewDays);
|
|
257
|
+
const weeks = computed(() => page.value.viewWeeks);
|
|
258
|
+
const dayColumns = computed(() => {
|
|
259
|
+
if (isDaily.value) return 1;
|
|
260
|
+
return weeks.value[0].days.length;
|
|
261
|
+
});
|
|
262
|
+
const dayRows = computed(() => {
|
|
263
|
+
if (isMonthly.value) return weeks.value.length;
|
|
264
|
+
return 1;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const snapMinutes = ref(SNAP_MINUTES);
|
|
268
|
+
const snapMs = computed(() => snapMinutes.value * 60 * 10000);
|
|
269
|
+
const pixelsPerHour = ref(PIXELS_PER_HOUR);
|
|
270
|
+
|
|
271
|
+
const state = ref<GridState>('NORMAL');
|
|
272
|
+
const fill = ref('light');
|
|
273
|
+
|
|
274
|
+
const eventsMap = ref<Record<any, Event>>({});
|
|
275
|
+
const events = computed(() => Object.values(eventsMap.value));
|
|
276
|
+
const detailEvent = ref<Event | null>(null);
|
|
277
|
+
|
|
278
|
+
const createOrigin = ref<CreateOriginState | null>(null);
|
|
279
|
+
|
|
280
|
+
const resizing = ref(false);
|
|
281
|
+
let resizeOrigin: ResizeOriginState | null = null;
|
|
282
|
+
|
|
283
|
+
const dragging = ref(false);
|
|
284
|
+
let dragOrigin: DragOriginState | null = null;
|
|
285
|
+
|
|
286
|
+
const isTouch = ref(false);
|
|
287
|
+
|
|
288
|
+
const active = computed(() => resizing.value || dragging.value);
|
|
289
|
+
|
|
290
|
+
const selectedEvents = computed(() => events.value.filter(e => e.selected));
|
|
291
|
+
|
|
292
|
+
const selectedEventsCount = computed(() => selectedEvents.value.length);
|
|
293
|
+
|
|
294
|
+
const hasSelectedEvents = computed(() => selectedEventsCount.value > 0);
|
|
295
|
+
|
|
296
|
+
const eventsContext = computed(() => {
|
|
297
|
+
const ctx = new DateRangeContext();
|
|
298
|
+
events.value.forEach(evt => {
|
|
299
|
+
ctx.render(evt, evt.range, days.value);
|
|
300
|
+
});
|
|
301
|
+
return ctx;
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
const gridStyle = computed(() => {
|
|
305
|
+
return {
|
|
306
|
+
height: `${24 * pixelsPerHour.value}px`,
|
|
307
|
+
};
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
function getEventContext() {
|
|
311
|
+
return {
|
|
312
|
+
locale,
|
|
313
|
+
days,
|
|
314
|
+
dayRows,
|
|
315
|
+
dayColumns,
|
|
316
|
+
isDaily,
|
|
317
|
+
isMonthly,
|
|
318
|
+
snapMinutes: snapMinutes.value,
|
|
319
|
+
pixelsPerHour: pixelsPerHour.value,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// #region Event details
|
|
324
|
+
|
|
325
|
+
function showCellPopover(event: Event) {
|
|
326
|
+
setTimeout(() => {
|
|
327
|
+
if (isDaily.value || !cellPopoverRef.value) return;
|
|
328
|
+
cellPopoverRef.value.show(event);
|
|
329
|
+
}, 10);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function updateCellPopover(event: Event) {
|
|
333
|
+
if (!cellPopoverRef.value) return;
|
|
334
|
+
cellPopoverRef.value.update(event);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function hideCellPopover() {
|
|
338
|
+
if (isDaily.value || !cellPopoverRef.value) return;
|
|
339
|
+
cellPopoverRef.value.hide();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function popoverVisible() {
|
|
343
|
+
return !!cellPopoverRef.value && cellPopoverRef.value.isVisible();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// #endregion Cell details
|
|
347
|
+
|
|
348
|
+
// #region Util
|
|
349
|
+
|
|
350
|
+
function createEventFromExisting(config: EventConfig, range?: DateRange) {
|
|
351
|
+
const event = events.value.find(e => e.key === config.key);
|
|
352
|
+
const ctx = getEventContext();
|
|
353
|
+
if (event != null) {
|
|
354
|
+
const { selected } = event;
|
|
355
|
+
return _createEvent(
|
|
356
|
+
{
|
|
357
|
+
...config,
|
|
358
|
+
selected,
|
|
359
|
+
},
|
|
360
|
+
ctx,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
return _createEvent(config, ctx);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function createNewEvent(date: Date, isWeekly: boolean) {
|
|
367
|
+
const event = _createEvent(
|
|
368
|
+
{
|
|
369
|
+
key: Symbol(),
|
|
370
|
+
start: date,
|
|
371
|
+
end: date,
|
|
372
|
+
allDay: isWeekly,
|
|
373
|
+
},
|
|
374
|
+
getEventContext(),
|
|
375
|
+
);
|
|
376
|
+
const msg = messages.EventCreateBegin(event).send();
|
|
377
|
+
if (msg.cancel || !msg.event) return;
|
|
378
|
+
eventsMap.value[event.key] = event;
|
|
379
|
+
return event;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function removeEvent(event: Event) {
|
|
383
|
+
const msg = messages.EventRemove(event).send();
|
|
384
|
+
if (msg.cancel) return;
|
|
385
|
+
delete eventsMap.value[event.key];
|
|
386
|
+
|
|
387
|
+
hideCellPopover();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function getEventsFromProps() {
|
|
391
|
+
return props.events.reduce(
|
|
392
|
+
(map, config) => {
|
|
393
|
+
map[config.key] = map[config.key] || createEventFromExisting(config);
|
|
394
|
+
return map;
|
|
395
|
+
},
|
|
396
|
+
{} as Record<keyof any, Event>,
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function getMsFromPosition(position: number) {
|
|
401
|
+
const hours = Math.max(Math.min(position / pixelsPerHour.value, 24), 0);
|
|
402
|
+
return hours * MS_PER_HOUR;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function getDateFromPosition(
|
|
406
|
+
position: number,
|
|
407
|
+
day: CalendarDay,
|
|
408
|
+
offsetMs = 0,
|
|
409
|
+
snapMs = 0,
|
|
410
|
+
) {
|
|
411
|
+
const startTime = day.startDate.getTime();
|
|
412
|
+
const ms = getMsFromPosition(position);
|
|
413
|
+
const date = roundDate(startTime + ms + offsetMs, snapMs);
|
|
414
|
+
return date;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const getPositionFromMouseEvent = (
|
|
418
|
+
gridEl: IBoundingRect | null,
|
|
419
|
+
event: MouseEvent,
|
|
420
|
+
): Point => {
|
|
421
|
+
if (gridEl == null) return { x: 0, y: 0 };
|
|
422
|
+
const rect = gridEl.getBoundingClientRect();
|
|
423
|
+
const x = event.clientX - rect.left;
|
|
424
|
+
const y = event.clientY - rect.top;
|
|
425
|
+
return { x, y };
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
const getPositionFromTouchEvent = (
|
|
429
|
+
gridEl: IBoundingRect | null,
|
|
430
|
+
event: TouchEvent,
|
|
431
|
+
): Point => {
|
|
432
|
+
if (gridEl == null) return { x: 0, y: 0 };
|
|
433
|
+
const rect = gridEl.getBoundingClientRect();
|
|
434
|
+
const touch = event.targetTouches[0] || event.changedTouches[0];
|
|
435
|
+
const x = touch.clientX - rect.left;
|
|
436
|
+
const y = touch.clientY - rect.top;
|
|
437
|
+
return { x, y };
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const getPositionFromUIEvent = (
|
|
441
|
+
gridEl: IBoundingRect | null,
|
|
442
|
+
event: UIEvent,
|
|
443
|
+
): Point => {
|
|
444
|
+
if (event.type.startsWith('touch'))
|
|
445
|
+
return getPositionFromTouchEvent(gridEl, event as TouchEvent);
|
|
446
|
+
return getPositionFromMouseEvent(gridEl, event as MouseEvent);
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
const getDayFromPosition = (el: IBoundingRect | null, { x, y }: any) => {
|
|
450
|
+
if (el == null) return days.value[0];
|
|
451
|
+
const rect = el.getBoundingClientRect();
|
|
452
|
+
const dayWidth = rect.width / dayColumns.value;
|
|
453
|
+
const dayHeight = rect.height / dayRows.value;
|
|
454
|
+
const xNorm = Math.max(Math.min(x, rect.width), 0);
|
|
455
|
+
const yNorm = Math.max(Math.min(y, rect.height), 0);
|
|
456
|
+
const xIdx = Math.min(Math.floor(xNorm / dayWidth), dayColumns.value - 1);
|
|
457
|
+
const yIdx = Math.min(Math.floor(yNorm / dayHeight), dayRows.value - 1);
|
|
458
|
+
const idx = xIdx + yIdx * dayColumns.value;
|
|
459
|
+
return days.value[idx];
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
// #endregion Util
|
|
463
|
+
|
|
464
|
+
// #region Cell Operations
|
|
465
|
+
|
|
466
|
+
function forSelectedEvents(fn: (event: Event) => void) {
|
|
467
|
+
selectedEvents.value.forEach(e => fn(e));
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function deselectAllEvents() {
|
|
471
|
+
forSelectedEvents(cell => (cell.selected = false));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// #endregion Cell Operations
|
|
475
|
+
|
|
476
|
+
// #region Resizing
|
|
477
|
+
|
|
478
|
+
function startResizingEvents(
|
|
479
|
+
position: number,
|
|
480
|
+
day: CalendarDay,
|
|
481
|
+
event: Event,
|
|
482
|
+
isStart: boolean,
|
|
483
|
+
isNew: boolean,
|
|
484
|
+
) {
|
|
485
|
+
if (active.value) return;
|
|
486
|
+
resizing.value = true;
|
|
487
|
+
event.selected = true;
|
|
488
|
+
const isWeekly = activeGridRef.value === weeklyGridRef.value;
|
|
489
|
+
const ms = getMsFromPosition(position);
|
|
490
|
+
resizeOrigin = {
|
|
491
|
+
position,
|
|
492
|
+
day,
|
|
493
|
+
event,
|
|
494
|
+
isWeekly,
|
|
495
|
+
isStart,
|
|
496
|
+
isNew,
|
|
497
|
+
ms,
|
|
498
|
+
};
|
|
499
|
+
forSelectedEvents(event => {
|
|
500
|
+
const msg = messages.EventResizeBegin(event).send();
|
|
501
|
+
if (msg.cancel) return;
|
|
502
|
+
event.startResize(day, isStart);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function updateResizingEvents(position: number, day: CalendarDay) {
|
|
507
|
+
if (!resizing.value || !resizeOrigin) return;
|
|
508
|
+
const offset: ResizeOffset = { weeks: 0, weekdays: 0, ms: 0 };
|
|
509
|
+
if (resizeOrigin.isWeekly) {
|
|
510
|
+
offset.weeks = day.weekPosition - resizeOrigin.day.weekPosition;
|
|
511
|
+
offset.weekdays = day.weekdayPosition - resizeOrigin.day.weekdayPosition;
|
|
512
|
+
} else {
|
|
513
|
+
offset.ms = getMsFromPosition(position) - resizeOrigin.ms;
|
|
514
|
+
}
|
|
515
|
+
forSelectedEvents(event => {
|
|
516
|
+
const msg = messages.EventResizeUpdate(event, offset).send();
|
|
517
|
+
if (msg.cancel) return;
|
|
518
|
+
event.updateResize(offset);
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function stopResizingEvents() {
|
|
523
|
+
if (!resizing.value || !resizeOrigin) return;
|
|
524
|
+
forSelectedEvents(event => {
|
|
525
|
+
messages.EventResizeEnd(event);
|
|
526
|
+
if (resizeOrigin!.isNew && event === resizeOrigin!.event) {
|
|
527
|
+
messages.EventCreateEnd(event).send();
|
|
528
|
+
showCellPopover(event);
|
|
529
|
+
}
|
|
530
|
+
event.stopResize();
|
|
531
|
+
});
|
|
532
|
+
resizing.value = false;
|
|
533
|
+
resizeOrigin = null;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// #endregion Resizing
|
|
537
|
+
|
|
538
|
+
// #region Dragging
|
|
539
|
+
|
|
540
|
+
function startDraggingEvents(
|
|
541
|
+
position: number,
|
|
542
|
+
day: CalendarDay,
|
|
543
|
+
event: Event,
|
|
544
|
+
) {
|
|
545
|
+
if (active.value) return;
|
|
546
|
+
dragging.value = true;
|
|
547
|
+
const date = getDateFromPosition(position, day, 0, 0);
|
|
548
|
+
const eventSelected = event.selected;
|
|
549
|
+
event.selected = true;
|
|
550
|
+
const ms = getMsFromPosition(position);
|
|
551
|
+
dragOrigin = {
|
|
552
|
+
position,
|
|
553
|
+
date,
|
|
554
|
+
day,
|
|
555
|
+
event,
|
|
556
|
+
eventSelected,
|
|
557
|
+
ms,
|
|
558
|
+
};
|
|
559
|
+
selectedEvents.value.forEach(event => {
|
|
560
|
+
const msg = messages.EventMoveBegin(event).send();
|
|
561
|
+
if (msg.cancel) return;
|
|
562
|
+
event.startDrag(day);
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function updateDraggingEvents(position: number, day: CalendarDay) {
|
|
567
|
+
if (!dragging.value || !dragOrigin) return;
|
|
568
|
+
const offset = {
|
|
569
|
+
weeks: day.weekPosition - dragOrigin.day.weekPosition,
|
|
570
|
+
weekdays: day.weekdayPosition - dragOrigin.day.weekdayPosition,
|
|
571
|
+
ms: getMsFromPosition(position) - dragOrigin.ms,
|
|
572
|
+
};
|
|
573
|
+
forSelectedEvents(event => {
|
|
574
|
+
const msg = messages.EventMoveUpdate(event, offset).send();
|
|
575
|
+
if (msg.cancel) return;
|
|
576
|
+
event.updateDrag(offset);
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function stopDraggingEvents() {
|
|
581
|
+
if (!dragging.value || !dragOrigin) return;
|
|
582
|
+
dragging.value = false;
|
|
583
|
+
dragOrigin = null;
|
|
584
|
+
forSelectedEvents(event => {
|
|
585
|
+
messages.EventMoveEnd(event).send();
|
|
586
|
+
event.stopDrag();
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// #endregion Dragging
|
|
591
|
+
|
|
592
|
+
// #region Watchers
|
|
593
|
+
|
|
594
|
+
function refreshEventsFromProps() {
|
|
595
|
+
eventsMap.value = getEventsFromProps();
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
watch(
|
|
599
|
+
() => props.events,
|
|
600
|
+
() => {
|
|
601
|
+
refreshEventsFromProps();
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
deep: true,
|
|
605
|
+
},
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
watch([view], () => {
|
|
609
|
+
deselectAllEvents();
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
// #endregion Watchers
|
|
613
|
+
|
|
614
|
+
// #region State management
|
|
615
|
+
|
|
616
|
+
function handleNormalEvent(
|
|
617
|
+
gse: GridStateEvent,
|
|
618
|
+
day: CalendarDay,
|
|
619
|
+
position: number,
|
|
620
|
+
evt: Event | undefined,
|
|
621
|
+
) {
|
|
622
|
+
switch (gse) {
|
|
623
|
+
case 'GRID_CURSOR_DOWN':
|
|
624
|
+
case 'GRID_CURSOR_DOWN_SHIFT': {
|
|
625
|
+
createOrigin.value = {
|
|
626
|
+
isWeekly: activeGridRef.value === weeklyGridRef.value,
|
|
627
|
+
date: getDateFromPosition(position, day),
|
|
628
|
+
position,
|
|
629
|
+
day,
|
|
630
|
+
};
|
|
631
|
+
state.value = 'CREATE_MONITOR';
|
|
632
|
+
break;
|
|
633
|
+
}
|
|
634
|
+
case 'EVENT_CURSOR_DOWN': {
|
|
635
|
+
if (!evt) return;
|
|
636
|
+
if (!evt.selected) deselectAllEvents();
|
|
637
|
+
startDraggingEvents(position, day, evt);
|
|
638
|
+
state.value = 'DRAG_MONITOR';
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
case 'EVENT_CURSOR_DOWN_SHIFT': {
|
|
642
|
+
if (!evt) return;
|
|
643
|
+
startDraggingEvents(position, day, evt);
|
|
644
|
+
state.value = 'DRAG_MONITOR';
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
case 'EVENT_RESIZE_START_CURSOR_DOWN': {
|
|
648
|
+
if (!evt) return;
|
|
649
|
+
if (!evt.selected) deselectAllEvents();
|
|
650
|
+
startResizingEvents(position, day, evt, true, false);
|
|
651
|
+
state.value = 'RESIZE_MONITOR';
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
case 'EVENT_RESIZE_START_CURSOR_DOWN_SHIFT': {
|
|
655
|
+
if (!evt) return;
|
|
656
|
+
startResizingEvents(position, day, evt, true, false);
|
|
657
|
+
state.value = 'RESIZE_MONITOR';
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
case 'EVENT_RESIZE_END_CURSOR_DOWN': {
|
|
661
|
+
if (!evt) return;
|
|
662
|
+
if (!evt.selected) deselectAllEvents();
|
|
663
|
+
startResizingEvents(position, day, evt, false, false);
|
|
664
|
+
state.value = 'RESIZE_MONITOR';
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
case 'EVENT_RESIZE_END_CURSOR_DOWN_SHIFT': {
|
|
668
|
+
if (!evt) return;
|
|
669
|
+
startResizingEvents(position, day, evt, false, false);
|
|
670
|
+
state.value = 'RESIZE_MONITOR';
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function handleCreateMonitorEvent(gse: GridStateEvent, day: CalendarDay) {
|
|
677
|
+
if (!createOrigin.value) return;
|
|
678
|
+
|
|
679
|
+
switch (gse) {
|
|
680
|
+
case 'ESCAPE': {
|
|
681
|
+
deselectAllEvents();
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
case 'GRID_CURSOR_UP':
|
|
685
|
+
case 'GRID_CURSOR_UP_SHIFT': {
|
|
686
|
+
deselectAllEvents();
|
|
687
|
+
if (!popoverVisible()) {
|
|
688
|
+
const { position, isWeekly } = createOrigin.value;
|
|
689
|
+
const date = getDateFromPosition(position, day);
|
|
690
|
+
const evt = createNewEvent(date, isWeekly);
|
|
691
|
+
if (evt) {
|
|
692
|
+
evt.selected = true;
|
|
693
|
+
messages.EventCreateEnd(evt).send();
|
|
694
|
+
showCellPopover(evt);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
state.value = 'NORMAL';
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
case 'EVENT_CURSOR_MOVE':
|
|
701
|
+
case 'EVENT_CURSOR_MOVE_SHIFT':
|
|
702
|
+
case 'GRID_CURSOR_MOVE':
|
|
703
|
+
case 'GRID_CURSOR_MOVE_SHIFT': {
|
|
704
|
+
// if (isTouch.value || isMonthly.value) {
|
|
705
|
+
// if (isTouch.value) {
|
|
706
|
+
// state.value = 'NORMAL';
|
|
707
|
+
// return;
|
|
708
|
+
// }
|
|
709
|
+
deselectAllEvents();
|
|
710
|
+
const { position, isWeekly } = createOrigin.value;
|
|
711
|
+
const date = getDateFromPosition(position, day);
|
|
712
|
+
const evt = createNewEvent(date, isWeekly);
|
|
713
|
+
if (evt) {
|
|
714
|
+
startResizingEvents(position, day, evt, false, true);
|
|
715
|
+
updateResizingEvents(position, day);
|
|
716
|
+
state.value = 'RESIZE_MONITOR';
|
|
717
|
+
}
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function handleResizeMonitorEvent(
|
|
724
|
+
event: GridStateEvent,
|
|
725
|
+
position: number,
|
|
726
|
+
day: CalendarDay,
|
|
727
|
+
) {
|
|
728
|
+
if (!resizeOrigin) return;
|
|
729
|
+
switch (event) {
|
|
730
|
+
case 'EVENT_CURSOR_MOVE':
|
|
731
|
+
case 'EVENT_CURSOR_MOVE_SHIFT':
|
|
732
|
+
case 'GRID_CURSOR_MOVE':
|
|
733
|
+
case 'GRID_CURSOR_MOVE_SHIFT': {
|
|
734
|
+
updateResizingEvents(position, day);
|
|
735
|
+
if (!resizeOrigin.isNew) {
|
|
736
|
+
updateCellPopover(resizeOrigin.event);
|
|
737
|
+
}
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
740
|
+
case 'GRID_CURSOR_UP': {
|
|
741
|
+
if (position === resizeOrigin.position) {
|
|
742
|
+
deselectAllEvents();
|
|
743
|
+
resizeOrigin.event.selected = true;
|
|
744
|
+
}
|
|
745
|
+
stopResizingEvents();
|
|
746
|
+
state.value = 'NORMAL';
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
case 'GRID_CURSOR_UP_SHIFT': {
|
|
750
|
+
stopResizingEvents();
|
|
751
|
+
state.value = 'NORMAL';
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function handleDragMonitorEvent(
|
|
758
|
+
event: GridStateEvent,
|
|
759
|
+
day: CalendarDay,
|
|
760
|
+
position: number,
|
|
761
|
+
) {
|
|
762
|
+
if (!dragOrigin) return;
|
|
763
|
+
switch (event) {
|
|
764
|
+
case 'GRID_CURSOR_MOVE':
|
|
765
|
+
case 'GRID_CURSOR_MOVE_SHIFT': {
|
|
766
|
+
updateDraggingEvents(position, day);
|
|
767
|
+
updateCellPopover(dragOrigin.event);
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
case 'GRID_CURSOR_UP': {
|
|
771
|
+
const origin = dragOrigin;
|
|
772
|
+
stopDraggingEvents();
|
|
773
|
+
if (position === origin.position) {
|
|
774
|
+
deselectAllEvents();
|
|
775
|
+
origin.event.selected = true;
|
|
776
|
+
showCellPopover(origin.event);
|
|
777
|
+
}
|
|
778
|
+
state.value = 'NORMAL';
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
case 'GRID_CURSOR_UP_SHIFT': {
|
|
782
|
+
stopDraggingEvents();
|
|
783
|
+
state.value = 'NORMAL';
|
|
784
|
+
break;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function updateState(
|
|
790
|
+
gse: GridStateEvent,
|
|
791
|
+
day: CalendarDay,
|
|
792
|
+
position: number,
|
|
793
|
+
evt: Event | undefined = undefined,
|
|
794
|
+
) {
|
|
795
|
+
switch (state.value) {
|
|
796
|
+
case 'NORMAL': {
|
|
797
|
+
handleNormalEvent(gse, day, position, evt);
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
case 'CREATE_MONITOR': {
|
|
801
|
+
handleCreateMonitorEvent(gse, day);
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
case 'RESIZE_MONITOR': {
|
|
805
|
+
handleResizeMonitorEvent(gse, position, day);
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
case 'DRAG_MONITOR': {
|
|
809
|
+
handleDragMonitorEvent(gse, day, position);
|
|
810
|
+
break;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const setActiveGrid = (event: MouseEvent | TouchEvent) => {
|
|
816
|
+
activeGridRef.value =
|
|
817
|
+
[dailyGridRef, weeklyGridRef].find(
|
|
818
|
+
ref => ref.value && ref.value.contains(event.currentTarget as Node),
|
|
819
|
+
)?.value ?? null;
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
const handleEvent = (
|
|
823
|
+
stateEvent: GridStateEvent,
|
|
824
|
+
event: MouseEvent | TouchEvent | KeyboardEvent,
|
|
825
|
+
evt: Event | undefined = undefined,
|
|
826
|
+
) => {
|
|
827
|
+
if (!activeGridRef.value) return;
|
|
828
|
+
if (event.type.startsWith('touch')) {
|
|
829
|
+
isTouch.value = true;
|
|
830
|
+
} else if (isTouch.value) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const eventName = (
|
|
834
|
+
event.shiftKey ? `${stateEvent}_SHIFT` : stateEvent
|
|
835
|
+
) as GridStateEvent;
|
|
836
|
+
const position = getPositionFromUIEvent(activeGridRef.value, event);
|
|
837
|
+
const day = getDayFromPosition(activeGridRef.value, position);
|
|
838
|
+
updateState(eventName, day, position.y, evt);
|
|
839
|
+
if (stateEvent === 'GRID_CURSOR_DOWN') {
|
|
840
|
+
onDayFocusin(day, null);
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
const startMonitoringGridMove = () => {
|
|
845
|
+
const offMove = on(window, 'mousemove', event => {
|
|
846
|
+
handleEvent('GRID_CURSOR_MOVE', event as MouseEvent);
|
|
847
|
+
});
|
|
848
|
+
const offUp = on(window, 'mouseup', event => {
|
|
849
|
+
handleEvent('GRID_CURSOR_UP', event as MouseEvent);
|
|
850
|
+
offMove();
|
|
851
|
+
offUp();
|
|
852
|
+
});
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
// #endregion State management
|
|
856
|
+
|
|
857
|
+
refreshEventsFromProps();
|
|
858
|
+
|
|
859
|
+
const context = {
|
|
860
|
+
...calendar,
|
|
861
|
+
dailyGridRef,
|
|
862
|
+
weeklyGridRef,
|
|
863
|
+
cellPopoverRef,
|
|
864
|
+
dayColumns,
|
|
865
|
+
dayRows,
|
|
866
|
+
snapMinutes,
|
|
867
|
+
snapMs,
|
|
868
|
+
pixelsPerHour,
|
|
869
|
+
isTouch,
|
|
870
|
+
events,
|
|
871
|
+
eventsMap,
|
|
872
|
+
selectedEvents,
|
|
873
|
+
hasSelectedEvents,
|
|
874
|
+
eventsContext,
|
|
875
|
+
detailEvent,
|
|
876
|
+
resizing,
|
|
877
|
+
dragging,
|
|
878
|
+
gridStyle,
|
|
879
|
+
fill,
|
|
880
|
+
page,
|
|
881
|
+
days,
|
|
882
|
+
weeks,
|
|
883
|
+
// Methods
|
|
884
|
+
removeEvent,
|
|
885
|
+
// Event handlers
|
|
886
|
+
onDayNumberClick(day: CalendarDay) {
|
|
887
|
+
emit('day-header-click', day);
|
|
888
|
+
move(day, { view: 'daily' });
|
|
889
|
+
},
|
|
890
|
+
onGridEscapeKeydown() {
|
|
891
|
+
updateState('ESCAPE', days.value[0], 0);
|
|
892
|
+
},
|
|
893
|
+
// Mouse event handlers
|
|
894
|
+
onGridMouseDown(event: MouseEvent) {
|
|
895
|
+
setActiveGrid(event);
|
|
896
|
+
handleEvent('GRID_CURSOR_DOWN', event);
|
|
897
|
+
startMonitoringGridMove();
|
|
898
|
+
},
|
|
899
|
+
onEventMouseDown(event: MouseEvent, evt: Event) {
|
|
900
|
+
setActiveGrid(event);
|
|
901
|
+
handleEvent('EVENT_CURSOR_DOWN', event, evt);
|
|
902
|
+
},
|
|
903
|
+
onEventResizeStartMouseDown(event: MouseEvent, evt: Event) {
|
|
904
|
+
setActiveGrid(event);
|
|
905
|
+
handleEvent('EVENT_RESIZE_START_CURSOR_DOWN', event, evt);
|
|
906
|
+
},
|
|
907
|
+
onEventResizeEndMouseDown(event: MouseEvent, evt: Event) {
|
|
908
|
+
setActiveGrid(event);
|
|
909
|
+
handleEvent('EVENT_RESIZE_END_CURSOR_DOWN', event, evt);
|
|
910
|
+
},
|
|
911
|
+
// Touch event handlers
|
|
912
|
+
onGridTouchStart(event: TouchEvent) {
|
|
913
|
+
setActiveGrid(event);
|
|
914
|
+
handleEvent('GRID_CURSOR_DOWN', event);
|
|
915
|
+
},
|
|
916
|
+
onGridTouchMove(event: TouchEvent) {
|
|
917
|
+
handleEvent('GRID_CURSOR_MOVE', event);
|
|
918
|
+
},
|
|
919
|
+
onGridTouchEnd(event: TouchEvent) {
|
|
920
|
+
handleEvent('GRID_CURSOR_UP', event);
|
|
921
|
+
},
|
|
922
|
+
onEventTouchStart(event: TouchEvent, evt: Event) {
|
|
923
|
+
setActiveGrid(event);
|
|
924
|
+
handleEvent('EVENT_CURSOR_DOWN', event, evt);
|
|
925
|
+
},
|
|
926
|
+
onEventTouchMove(event: TouchEvent, evt: Event) {
|
|
927
|
+
handleEvent('GRID_CURSOR_MOVE', event, evt);
|
|
928
|
+
},
|
|
929
|
+
onEventTouchEnd(event: TouchEvent, evt: Event) {
|
|
930
|
+
handleEvent('GRID_CURSOR_UP', event, evt);
|
|
931
|
+
},
|
|
932
|
+
onEventResizeStartTouchStart(event: TouchEvent, evt: Event) {
|
|
933
|
+
setActiveGrid(event);
|
|
934
|
+
handleEvent('EVENT_RESIZE_START_CURSOR_DOWN', event, evt);
|
|
935
|
+
},
|
|
936
|
+
onEventResizeEndTouchStart(event: TouchEvent, evt: Event) {
|
|
937
|
+
setActiveGrid(event);
|
|
938
|
+
handleEvent('EVENT_RESIZE_END_CURSOR_DOWN', event, evt);
|
|
939
|
+
},
|
|
940
|
+
};
|
|
941
|
+
provide(contextKey, context);
|
|
942
|
+
|
|
943
|
+
return context;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
export function useCalendarGrid() {
|
|
947
|
+
const context = inject<CalendarGridContext>(contextKey);
|
|
948
|
+
if (!context) {
|
|
949
|
+
throw new Error(
|
|
950
|
+
'Calendar context missing. Please verify this component is nested within a valid context provider.',
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
return context;
|
|
954
|
+
}
|