@ngxsmk/cdk 1.3.2 → 3.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.
Files changed (199) hide show
  1. package/README.md +1 -1
  2. package/cva-base/cva-base.d.ts +34 -0
  3. package/cva-base/cva-base.d.ts.map +1 -0
  4. package/cva-base/index.d.ts +2 -0
  5. package/cva-base/index.d.ts.map +1 -0
  6. package/cva-base/ngxsmk-cdk-cva-base.d.ts.map +1 -0
  7. package/esm2022/cva-base/cva-base.mjs +45 -0
  8. package/esm2022/cva-base/index.mjs +2 -0
  9. package/esm2022/cva-base/ngxsmk-cdk-cva-base.mjs +5 -0
  10. package/esm2022/input-group/index.mjs +3 -0
  11. package/esm2022/input-group/input-group-engine.mjs +219 -0
  12. package/esm2022/input-group/models/index.mjs +2 -0
  13. package/esm2022/input-group/models/input-group.model.mjs +2 -0
  14. package/esm2022/input-group/ngxsmk-cdk-input-group.mjs +5 -0
  15. package/esm2022/listbox-keyboard/index.mjs +2 -0
  16. package/esm2022/listbox-keyboard/listbox-keyboard.mjs +145 -0
  17. package/esm2022/listbox-keyboard/ngxsmk-cdk-listbox-keyboard.mjs +5 -0
  18. package/esm2022/public-api.mjs +10 -1
  19. package/esm2022/roving-focus/index.mjs +2 -0
  20. package/esm2022/roving-focus/ngxsmk-cdk-roving-focus.mjs +5 -0
  21. package/esm2022/roving-focus/roving-focus.mjs +176 -0
  22. package/esm2022/scheduler/index.mjs +5 -0
  23. package/esm2022/scheduler/models/date-range.mjs +2 -0
  24. package/esm2022/scheduler/models/event.model.mjs +2 -0
  25. package/esm2022/scheduler/models/index.mjs +6 -0
  26. package/esm2022/scheduler/models/resource.model.mjs +5 -0
  27. package/esm2022/scheduler/models/selection.model.mjs +7 -0
  28. package/esm2022/scheduler/models/view.model.mjs +7 -0
  29. package/esm2022/scheduler/ngxsmk-cdk-scheduler.mjs +5 -0
  30. package/esm2022/scheduler/plugin/drag-plugin.mjs +82 -0
  31. package/esm2022/scheduler/plugin/index.mjs +8 -0
  32. package/esm2022/scheduler/plugin/keyboard-plugin.mjs +150 -0
  33. package/esm2022/scheduler/plugin/plugin-host.mjs +48 -0
  34. package/esm2022/scheduler/plugin/plugin.types.mjs +2 -0
  35. package/esm2022/scheduler/plugin/resize-plugin.mjs +74 -0
  36. package/esm2022/scheduler/plugin/selection-plugin.mjs +84 -0
  37. package/esm2022/scheduler/plugin/tooltip-plugin.mjs +103 -0
  38. package/esm2022/scheduler/scheduler-engine.mjs +316 -0
  39. package/esm2022/scheduler/utils/date-utils.mjs +131 -0
  40. package/esm2022/scheduler/utils/index.mjs +3 -0
  41. package/esm2022/scheduler/utils/snap.mjs +24 -0
  42. package/esm2022/scroll-lock/scroll-lock.mjs +22 -5
  43. package/esm2022/skip-link/index.mjs +2 -0
  44. package/esm2022/skip-link/ngxsmk-cdk-skip-link.mjs +5 -0
  45. package/esm2022/skip-link/skip-link.mjs +33 -0
  46. package/esm2022/spreadsheet/index.mjs +5 -0
  47. package/esm2022/spreadsheet/models/cell.model.mjs +2 -0
  48. package/esm2022/spreadsheet/models/column.model.mjs +2 -0
  49. package/esm2022/spreadsheet/models/filter.model.mjs +2 -0
  50. package/esm2022/spreadsheet/models/formula.model.mjs +2 -0
  51. package/esm2022/spreadsheet/models/index.mjs +8 -0
  52. package/esm2022/spreadsheet/models/row.model.mjs +2 -0
  53. package/esm2022/spreadsheet/models/selection.model.mjs +2 -0
  54. package/esm2022/spreadsheet/models/sort.model.mjs +2 -0
  55. package/esm2022/spreadsheet/ngxsmk-cdk-spreadsheet.mjs +5 -0
  56. package/esm2022/spreadsheet/plugin/clipboard-plugin.mjs +171 -0
  57. package/esm2022/spreadsheet/plugin/filter-plugin.mjs +87 -0
  58. package/esm2022/spreadsheet/plugin/formula-plugin.mjs +456 -0
  59. package/esm2022/spreadsheet/plugin/index.mjs +10 -0
  60. package/esm2022/spreadsheet/plugin/plugin-host.mjs +188 -0
  61. package/esm2022/spreadsheet/plugin/plugin.types.mjs +2 -0
  62. package/esm2022/spreadsheet/plugin/selection-plugin.mjs +114 -0
  63. package/esm2022/spreadsheet/plugin/sort-plugin.mjs +63 -0
  64. package/esm2022/spreadsheet/plugin/undo-plugin.mjs +138 -0
  65. package/esm2022/spreadsheet/plugin/validation-plugin.mjs +71 -0
  66. package/esm2022/spreadsheet/spreadsheet-engine.mjs +547 -0
  67. package/esm2022/spreadsheet/utils/cell-utils.mjs +129 -0
  68. package/esm2022/spreadsheet/utils/index.mjs +2 -0
  69. package/fesm2022/ngxsmk-cdk-cva-base.mjs +52 -0
  70. package/fesm2022/ngxsmk-cdk-cva-base.mjs.map +1 -0
  71. package/fesm2022/ngxsmk-cdk-input-group.mjs +226 -0
  72. package/fesm2022/ngxsmk-cdk-input-group.mjs.map +1 -0
  73. package/fesm2022/ngxsmk-cdk-listbox-keyboard.mjs +152 -0
  74. package/fesm2022/ngxsmk-cdk-listbox-keyboard.mjs.map +1 -0
  75. package/fesm2022/ngxsmk-cdk-roving-focus.mjs +183 -0
  76. package/fesm2022/ngxsmk-cdk-roving-focus.mjs.map +1 -0
  77. package/fesm2022/ngxsmk-cdk-scheduler.mjs +1035 -0
  78. package/fesm2022/ngxsmk-cdk-scheduler.mjs.map +1 -0
  79. package/fesm2022/ngxsmk-cdk-scroll-lock.mjs +21 -4
  80. package/fesm2022/ngxsmk-cdk-scroll-lock.mjs.map +1 -1
  81. package/fesm2022/ngxsmk-cdk-skip-link.mjs +40 -0
  82. package/fesm2022/ngxsmk-cdk-skip-link.mjs.map +1 -0
  83. package/fesm2022/ngxsmk-cdk-spreadsheet.mjs +1969 -0
  84. package/fesm2022/ngxsmk-cdk-spreadsheet.mjs.map +1 -0
  85. package/fesm2022/ngxsmk-cdk.mjs +5 -0
  86. package/fesm2022/ngxsmk-cdk.mjs.map +1 -1
  87. package/input-group/index.d.ts +3 -0
  88. package/input-group/index.d.ts.map +1 -0
  89. package/input-group/input-group-engine.d.ts +88 -0
  90. package/input-group/input-group-engine.d.ts.map +1 -0
  91. package/input-group/models/index.d.ts +2 -0
  92. package/input-group/models/index.d.ts.map +1 -0
  93. package/input-group/models/input-group.model.d.ts +114 -0
  94. package/input-group/models/input-group.model.d.ts.map +1 -0
  95. package/input-group/ngxsmk-cdk-input-group.d.ts.map +1 -0
  96. package/listbox-keyboard/index.d.ts +2 -0
  97. package/listbox-keyboard/index.d.ts.map +1 -0
  98. package/listbox-keyboard/listbox-keyboard.d.ts +60 -0
  99. package/listbox-keyboard/listbox-keyboard.d.ts.map +1 -0
  100. package/listbox-keyboard/ngxsmk-cdk-listbox-keyboard.d.ts.map +1 -0
  101. package/package.json +59 -17
  102. package/public-api.d.ts +8 -0
  103. package/public-api.d.ts.map +1 -1
  104. package/roving-focus/index.d.ts +2 -0
  105. package/roving-focus/index.d.ts.map +1 -0
  106. package/roving-focus/ngxsmk-cdk-roving-focus.d.ts.map +1 -0
  107. package/roving-focus/roving-focus.d.ts +61 -0
  108. package/roving-focus/roving-focus.d.ts.map +1 -0
  109. package/scheduler/index.d.ts +5 -0
  110. package/scheduler/index.d.ts.map +1 -0
  111. package/scheduler/models/date-range.d.ts +6 -0
  112. package/scheduler/models/date-range.d.ts.map +1 -0
  113. package/scheduler/models/event.model.d.ts +50 -0
  114. package/scheduler/models/event.model.d.ts.map +1 -0
  115. package/scheduler/models/index.d.ts +6 -0
  116. package/scheduler/models/index.d.ts.map +1 -0
  117. package/scheduler/models/resource.model.d.ts +16 -0
  118. package/scheduler/models/resource.model.d.ts.map +1 -0
  119. package/scheduler/models/selection.model.d.ts +12 -0
  120. package/scheduler/models/selection.model.d.ts.map +1 -0
  121. package/scheduler/models/view.model.d.ts +21 -0
  122. package/scheduler/models/view.model.d.ts.map +1 -0
  123. package/scheduler/ngxsmk-cdk-scheduler.d.ts.map +1 -0
  124. package/scheduler/plugin/drag-plugin.d.ts +28 -0
  125. package/scheduler/plugin/drag-plugin.d.ts.map +1 -0
  126. package/scheduler/plugin/index.d.ts +8 -0
  127. package/scheduler/plugin/index.d.ts.map +1 -0
  128. package/scheduler/plugin/keyboard-plugin.d.ts +24 -0
  129. package/scheduler/plugin/keyboard-plugin.d.ts.map +1 -0
  130. package/scheduler/plugin/plugin-host.d.ts +16 -0
  131. package/scheduler/plugin/plugin-host.d.ts.map +1 -0
  132. package/scheduler/plugin/plugin.types.d.ts +9 -0
  133. package/scheduler/plugin/plugin.types.d.ts.map +1 -0
  134. package/scheduler/plugin/resize-plugin.d.ts +26 -0
  135. package/scheduler/plugin/resize-plugin.d.ts.map +1 -0
  136. package/scheduler/plugin/selection-plugin.d.ts +40 -0
  137. package/scheduler/plugin/selection-plugin.d.ts.map +1 -0
  138. package/scheduler/plugin/tooltip-plugin.d.ts +41 -0
  139. package/scheduler/plugin/tooltip-plugin.d.ts.map +1 -0
  140. package/scheduler/scheduler-engine.d.ts +95 -0
  141. package/scheduler/scheduler-engine.d.ts.map +1 -0
  142. package/scheduler/utils/date-utils.d.ts +26 -0
  143. package/scheduler/utils/date-utils.d.ts.map +1 -0
  144. package/scheduler/utils/index.d.ts +3 -0
  145. package/scheduler/utils/index.d.ts.map +1 -0
  146. package/scheduler/utils/snap.d.ts +7 -0
  147. package/scheduler/utils/snap.d.ts.map +1 -0
  148. package/scroll-lock/scroll-lock.d.ts +2 -0
  149. package/scroll-lock/scroll-lock.d.ts.map +1 -1
  150. package/skip-link/index.d.ts +2 -0
  151. package/skip-link/index.d.ts.map +1 -0
  152. package/skip-link/ngxsmk-cdk-skip-link.d.ts.map +1 -0
  153. package/skip-link/skip-link.d.ts +18 -0
  154. package/skip-link/skip-link.d.ts.map +1 -0
  155. package/spreadsheet/index.d.ts +5 -0
  156. package/spreadsheet/index.d.ts.map +1 -0
  157. package/spreadsheet/models/cell.model.d.ts +44 -0
  158. package/spreadsheet/models/cell.model.d.ts.map +1 -0
  159. package/spreadsheet/models/column.model.d.ts +77 -0
  160. package/spreadsheet/models/column.model.d.ts.map +1 -0
  161. package/spreadsheet/models/filter.model.d.ts +15 -0
  162. package/spreadsheet/models/filter.model.d.ts.map +1 -0
  163. package/spreadsheet/models/formula.model.d.ts +65 -0
  164. package/spreadsheet/models/formula.model.d.ts.map +1 -0
  165. package/spreadsheet/models/index.d.ts +8 -0
  166. package/spreadsheet/models/index.d.ts.map +1 -0
  167. package/spreadsheet/models/row.model.d.ts +33 -0
  168. package/spreadsheet/models/row.model.d.ts.map +1 -0
  169. package/spreadsheet/models/selection.model.d.ts +18 -0
  170. package/spreadsheet/models/selection.model.d.ts.map +1 -0
  171. package/spreadsheet/models/sort.model.d.ts +14 -0
  172. package/spreadsheet/models/sort.model.d.ts.map +1 -0
  173. package/spreadsheet/ngxsmk-cdk-spreadsheet.d.ts.map +1 -0
  174. package/spreadsheet/plugin/clipboard-plugin.d.ts +24 -0
  175. package/spreadsheet/plugin/clipboard-plugin.d.ts.map +1 -0
  176. package/spreadsheet/plugin/filter-plugin.d.ts +21 -0
  177. package/spreadsheet/plugin/filter-plugin.d.ts.map +1 -0
  178. package/spreadsheet/plugin/formula-plugin.d.ts +39 -0
  179. package/spreadsheet/plugin/formula-plugin.d.ts.map +1 -0
  180. package/spreadsheet/plugin/index.d.ts +10 -0
  181. package/spreadsheet/plugin/index.d.ts.map +1 -0
  182. package/spreadsheet/plugin/plugin-host.d.ts +66 -0
  183. package/spreadsheet/plugin/plugin-host.d.ts.map +1 -0
  184. package/spreadsheet/plugin/plugin.types.d.ts +58 -0
  185. package/spreadsheet/plugin/plugin.types.d.ts.map +1 -0
  186. package/spreadsheet/plugin/selection-plugin.d.ts +28 -0
  187. package/spreadsheet/plugin/selection-plugin.d.ts.map +1 -0
  188. package/spreadsheet/plugin/sort-plugin.d.ts +18 -0
  189. package/spreadsheet/plugin/sort-plugin.d.ts.map +1 -0
  190. package/spreadsheet/plugin/undo-plugin.d.ts +40 -0
  191. package/spreadsheet/plugin/undo-plugin.d.ts.map +1 -0
  192. package/spreadsheet/plugin/validation-plugin.d.ts +29 -0
  193. package/spreadsheet/plugin/validation-plugin.d.ts.map +1 -0
  194. package/spreadsheet/spreadsheet-engine.d.ts +194 -0
  195. package/spreadsheet/spreadsheet-engine.d.ts.map +1 -0
  196. package/spreadsheet/utils/cell-utils.d.ts +26 -0
  197. package/spreadsheet/utils/cell-utils.d.ts.map +1 -0
  198. package/spreadsheet/utils/index.d.ts +2 -0
  199. package/spreadsheet/utils/index.d.ts.map +1 -0
@@ -0,0 +1,1035 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, computed, Injectable } from '@angular/core';
3
+
4
+ function startOfDay(date) {
5
+ const d = new Date(date);
6
+ d.setHours(0, 0, 0, 0);
7
+ return d;
8
+ }
9
+ function startOfWeek(date, firstDayOfWeek) {
10
+ const d = startOfDay(date);
11
+ const day = d.getDay();
12
+ const diff = (day - firstDayOfWeek + 7) % 7;
13
+ d.setDate(d.getDate() - diff);
14
+ return d;
15
+ }
16
+ function endOfWeek(date, firstDayOfWeek) {
17
+ const start = startOfWeek(date, firstDayOfWeek);
18
+ const end = new Date(start);
19
+ end.setDate(end.getDate() + 7);
20
+ end.setMilliseconds(-1);
21
+ return end;
22
+ }
23
+ function startOfMonth(date) {
24
+ const d = new Date(date.getFullYear(), date.getMonth(), 1);
25
+ d.setHours(0, 0, 0, 0);
26
+ return d;
27
+ }
28
+ function endOfMonth(date) {
29
+ const d = new Date(date.getFullYear(), date.getMonth() + 1, 0);
30
+ d.setHours(23, 59, 59, 999);
31
+ return d;
32
+ }
33
+ function addDays(date, days) {
34
+ const d = new Date(date);
35
+ d.setDate(d.getDate() + days);
36
+ return d;
37
+ }
38
+ function addMinutes(date, minutes) {
39
+ return new Date(date.getTime() + minutes * 60_000);
40
+ }
41
+ function addWeeks(date, weeks) {
42
+ return addDays(date, weeks * 7);
43
+ }
44
+ function diffMinutes(start, end) {
45
+ return (end.getTime() - start.getTime()) / 60_000;
46
+ }
47
+ function diffDays(start, end) {
48
+ const s = startOfDay(start);
49
+ const e = startOfDay(end);
50
+ return Math.round((e.getTime() - s.getTime()) / 86_400_000);
51
+ }
52
+ function isSameDay(a, b) {
53
+ return (a.getFullYear() === b.getFullYear() &&
54
+ a.getMonth() === b.getMonth() &&
55
+ a.getDate() === b.getDate());
56
+ }
57
+ function isSameWeek(a, b, firstDayOfWeek) {
58
+ return isSameDay(startOfWeek(a, firstDayOfWeek), startOfWeek(b, firstDayOfWeek));
59
+ }
60
+ function isToday(date) {
61
+ return isSameDay(date, new Date());
62
+ }
63
+ function isWeekend(date) {
64
+ const day = date.getDay();
65
+ return day === 0 || day === 6;
66
+ }
67
+ function isPast(date) {
68
+ return date.getTime() < Date.now();
69
+ }
70
+ function dateRangeOverlaps(aStart, aEnd, bStart, bEnd) {
71
+ return aStart.getTime() < bEnd.getTime() && aEnd.getTime() > bStart.getTime();
72
+ }
73
+ function clampDate(date, min, max) {
74
+ const t = date.getTime();
75
+ if (t < min.getTime())
76
+ return new Date(min);
77
+ if (t > max.getTime())
78
+ return new Date(max);
79
+ return new Date(date);
80
+ }
81
+ function getHoursInRange(start, end) {
82
+ const hours = [];
83
+ const d = new Date(start);
84
+ while (d < end) {
85
+ hours.push(d.getHours());
86
+ d.setHours(d.getHours() + 1, 0, 0, 0);
87
+ }
88
+ return hours;
89
+ }
90
+ function formatHour(h, locale = 'en-US') {
91
+ const d = new Date();
92
+ d.setHours(h, 0, 0, 0);
93
+ return d.toLocaleTimeString(locale, { hour: 'numeric', minute: undefined });
94
+ }
95
+ function formatDateRange(start, end, locale = 'en-US') {
96
+ const opts = { month: 'short', day: 'numeric' };
97
+ const yearOpts = { month: 'short', day: 'numeric', year: 'numeric' };
98
+ const sameYear = start.getFullYear() === end.getFullYear();
99
+ const fmt = new Intl.DateTimeFormat(locale, sameYear ? opts : yearOpts);
100
+ return `${fmt.format(start)} – ${fmt.format(end)}${sameYear ? `, ${start.getFullYear()}` : ''}`;
101
+ }
102
+ function getWeekDates(date, firstDayOfWeek) {
103
+ const start = startOfWeek(date, firstDayOfWeek);
104
+ return Array.from({ length: 7 }, (_, i) => addDays(start, i));
105
+ }
106
+ function getWorkWeekDates(date, firstDayOfWeek) {
107
+ const weekDates = getWeekDates(date, firstDayOfWeek);
108
+ return weekDates.filter((d) => !isWeekend(d));
109
+ }
110
+ function getMonthGrid(date, firstDayOfWeek) {
111
+ const monthStart = startOfMonth(date);
112
+ const gridStart = startOfWeek(monthStart, firstDayOfWeek);
113
+ const gridEnd = addDays(gridStart, 42);
114
+ const weeks = [];
115
+ let current = new Date(gridStart);
116
+ while (current < gridEnd) {
117
+ weeks.push(Array.from({ length: 7 }, (_, i) => addDays(current, i)));
118
+ current = addDays(current, 7);
119
+ }
120
+ return weeks;
121
+ }
122
+ function getDayNames(locale = 'en-US', format = 'short') {
123
+ return Array.from({ length: 7 }, (_, i) => {
124
+ const d = new Date(2026, 0, 4 + i);
125
+ return d.toLocaleDateString(locale, { weekday: format });
126
+ });
127
+ }
128
+ function getMonthNames(locale = 'en-US', format = 'long') {
129
+ return Array.from({ length: 12 }, (_, i) => {
130
+ const d = new Date(2026, i, 1);
131
+ return d.toLocaleDateString(locale, { month: format });
132
+ });
133
+ }
134
+
135
+ const HOUR_HEIGHT_MAP = {
136
+ compact: 48,
137
+ comfortable: 60,
138
+ dense: 36,
139
+ };
140
+ function computeRange(type, date, firstDayOfWeek) {
141
+ switch (type) {
142
+ case 'timeGridDay':
143
+ case 'dayGridDay':
144
+ case 'agenda':
145
+ return { start: startOfDay(date), end: addDays(startOfDay(date), 1) };
146
+ case 'timeGridWeek':
147
+ case 'dayGridWeek':
148
+ return { start: startOfWeek(date, firstDayOfWeek), end: endOfWeek(date, firstDayOfWeek) };
149
+ case 'timeGridWorkWeek': {
150
+ const weekStart = startOfWeek(date, firstDayOfWeek);
151
+ return { start: addDays(weekStart, 1), end: addDays(weekStart, 5) };
152
+ }
153
+ case 'timeGrid3Day':
154
+ return { start: startOfDay(date), end: addDays(startOfDay(date), 3) };
155
+ case 'dayGridMonth':
156
+ return { start: startOfMonth(date), end: endOfMonth(date) };
157
+ case 'timeline':
158
+ return { start: startOfWeek(date, firstDayOfWeek), end: endOfWeek(date, firstDayOfWeek) };
159
+ default:
160
+ return { start: startOfWeek(date, firstDayOfWeek), end: endOfWeek(date, firstDayOfWeek) };
161
+ }
162
+ }
163
+ class SchedulerEngine {
164
+ constructor(config = {}) {
165
+ this.now = signal(new Date());
166
+ this._config = config;
167
+ const firstDay = config.firstDayOfWeek ?? 1;
168
+ const date = config.date ?? new Date();
169
+ const view = config.defaultView ?? 'timeGridWeek';
170
+ const range = computeRange(view, date, firstDay);
171
+ this._lifecycle = {
172
+ beforeRender: signal(() => true),
173
+ afterRender: signal(() => {
174
+ /* noop */
175
+ }),
176
+ beforeCreate: signal(() => true),
177
+ afterCreate: signal(() => {
178
+ /* noop */
179
+ }),
180
+ beforeUpdate: signal(() => true),
181
+ afterUpdate: signal(() => {
182
+ /* noop */
183
+ }),
184
+ beforeDelete: signal(() => true),
185
+ afterDelete: signal(() => {
186
+ /* noop */
187
+ }),
188
+ beforeDrag: signal(() => true),
189
+ afterDrag: signal(() => {
190
+ /* noop */
191
+ }),
192
+ beforeResize: signal(() => true),
193
+ afterResize: signal(() => {
194
+ /* noop */
195
+ }),
196
+ };
197
+ this.events = signal(config.initialEvents ?? []);
198
+ this.resources = signal(config.initialResources ?? []);
199
+ this.plugins = signal(config.plugins ?? []);
200
+ this.viewState = signal({
201
+ type: view,
202
+ date: new Date(date),
203
+ rangeStart: range.start,
204
+ rangeEnd: range.end,
205
+ slotDuration: config.slotDuration ?? 30,
206
+ snapDuration: config.snapDuration ?? 15,
207
+ visibleHours: config.visibleHours ?? [0, 24],
208
+ firstDayOfWeek: firstDay,
209
+ locale: config.locale ?? 'en-US',
210
+ rtl: config.rtl ?? false,
211
+ density: config.density ?? 'comfortable',
212
+ showAllDay: config.showAllDay ?? true,
213
+ showWeekends: config.showWeekends ?? true,
214
+ showCurrentTime: config.showCurrentTime ?? true,
215
+ });
216
+ this.selection = signal({
217
+ selectedEventIds: new Set(),
218
+ selectedRange: null,
219
+ multiSelect: false,
220
+ focusedCell: null,
221
+ });
222
+ this.hourHeight = computed(() => HOUR_HEIGHT_MAP[this.viewState().density] ?? 60);
223
+ this.visibleEvents = computed(() => {
224
+ const vs = this.viewState();
225
+ const events = this.events();
226
+ return events.filter((e) => !e.allDay && dateRangeOverlaps(e.start, e.end, vs.rangeStart, vs.rangeEnd));
227
+ });
228
+ this.allDayEvents = computed(() => {
229
+ const vs = this.viewState();
230
+ const events = this.events();
231
+ return events.filter((e) => e.allDay && dateRangeOverlaps(e.start, e.end, vs.rangeStart, vs.rangeEnd));
232
+ });
233
+ this.timedEvents = computed(() => this.visibleEvents());
234
+ this.weekDates = computed(() => {
235
+ const vs = this.viewState();
236
+ const start = vs.rangeStart;
237
+ const dates = [];
238
+ let current = new Date(start);
239
+ while (current < vs.rangeEnd) {
240
+ dates.push(new Date(current));
241
+ current = addDays(current, 1);
242
+ }
243
+ return dates;
244
+ });
245
+ this.dayNames = computed(() => {
246
+ const locale = this.viewState().locale;
247
+ return Array.from({ length: 7 }, (_, i) => {
248
+ const d = startOfWeek(new Date(), this.viewState().firstDayOfWeek);
249
+ d.setDate(d.getDate() + i);
250
+ return d.toLocaleDateString(locale, { weekday: 'short' });
251
+ });
252
+ });
253
+ this.weekLabel = computed(() => {
254
+ const vs = this.viewState();
255
+ return (vs.rangeStart.toLocaleDateString(vs.locale, {
256
+ month: 'short',
257
+ day: 'numeric',
258
+ }) +
259
+ ' – ' +
260
+ vs.rangeEnd.toLocaleDateString(vs.locale, {
261
+ month: 'short',
262
+ day: 'numeric',
263
+ year: 'numeric',
264
+ }));
265
+ });
266
+ }
267
+ get lifecycle() {
268
+ return this._lifecycle;
269
+ }
270
+ // ── Navigation ──
271
+ next() {
272
+ const vs = this.viewState();
273
+ const date = addDays(vs.date, this._viewSpan(vs.type));
274
+ this._navigateTo(date);
275
+ }
276
+ previous() {
277
+ const vs = this.viewState();
278
+ const date = addDays(vs.date, -this._viewSpan(vs.type));
279
+ this._navigateTo(date);
280
+ }
281
+ today() {
282
+ this._navigateTo(new Date());
283
+ }
284
+ goto(date) {
285
+ this._navigateTo(date);
286
+ }
287
+ setView(type, date) {
288
+ const vs = this.viewState();
289
+ const refDate = date ?? vs.date;
290
+ const range = computeRange(type, refDate, vs.firstDayOfWeek);
291
+ this.viewState.update((s) => ({
292
+ ...s,
293
+ type,
294
+ date: new Date(refDate),
295
+ rangeStart: range.start,
296
+ rangeEnd: range.end,
297
+ }));
298
+ }
299
+ // ── Event Mutations ──
300
+ addEvent(event) {
301
+ if (!this._runHook(this._lifecycle.beforeCreate, event))
302
+ return;
303
+ this.events.update((evts) => [...evts, event]);
304
+ this._lifecycle.afterCreate()(event);
305
+ }
306
+ updateEvent(id, patch) {
307
+ const existing = this.events().find((e) => e.id === id);
308
+ if (!existing)
309
+ return;
310
+ const updated = { ...existing, ...patch };
311
+ if (!this._runHook(this._lifecycle.beforeUpdate, updated))
312
+ return;
313
+ this.events.update((evts) => evts.map((e) => (e.id === id ? updated : e)));
314
+ this._lifecycle.afterUpdate()(updated);
315
+ }
316
+ removeEvent(id) {
317
+ const existing = this.events().find((e) => e.id === id);
318
+ if (!existing)
319
+ return;
320
+ if (!this._runHook(this._lifecycle.beforeDelete, existing))
321
+ return;
322
+ this.events.update((evts) => evts.filter((e) => e.id !== id));
323
+ this._lifecycle.afterDelete()(existing);
324
+ }
325
+ moveEvent(id, newStart, newEnd, resourceId) {
326
+ const existing = this.events().find((e) => e.id === id);
327
+ if (!existing)
328
+ return;
329
+ const move = {
330
+ event: existing,
331
+ from: existing.start,
332
+ to: newStart,
333
+ newStart,
334
+ newEnd,
335
+ resourceId,
336
+ };
337
+ if (!this._runHook(this._lifecycle.beforeDrag, existing))
338
+ return;
339
+ this.events.update((evts) => evts.map((e) => e.id === id
340
+ ? { ...e, start: newStart, end: newEnd, resourceId: resourceId ?? e.resourceId }
341
+ : e));
342
+ this._lifecycle.afterDrag()(move);
343
+ }
344
+ resizeEvent(id, newEnd) {
345
+ const existing = this.events().find((e) => e.id === id);
346
+ if (!existing)
347
+ return;
348
+ const resize = {
349
+ event: existing,
350
+ oldEnd: existing.end,
351
+ newEnd,
352
+ };
353
+ if (!this._runHook(this._lifecycle.beforeResize, existing))
354
+ return;
355
+ this.events.update((evts) => evts.map((e) => (e.id === id ? { ...e, end: newEnd } : e)));
356
+ this._lifecycle.afterResize()(resize);
357
+ }
358
+ // ── Selection ──
359
+ selectEvent(id, multi = false) {
360
+ this.selection.update((s) => {
361
+ const ids = new Set(multi ? s.selectedEventIds : []);
362
+ if (ids.has(id)) {
363
+ ids.delete(id);
364
+ }
365
+ else {
366
+ ids.add(id);
367
+ }
368
+ return { ...s, selectedEventIds: ids };
369
+ });
370
+ }
371
+ selectRange(start, end, resourceId) {
372
+ this.selection.update((s) => ({
373
+ ...s,
374
+ selectedRange: { start, end, resourceId },
375
+ }));
376
+ }
377
+ clearSelection() {
378
+ this.selection.update((s) => ({
379
+ ...s,
380
+ selectedEventIds: new Set(),
381
+ selectedRange: null,
382
+ }));
383
+ }
384
+ isEventSelected(id) {
385
+ return this.selection().selectedEventIds.has(id);
386
+ }
387
+ // ── Queries ──
388
+ eventsForDay(day) {
389
+ return this.visibleEvents().filter((e) => isSameDay(e.start, day));
390
+ }
391
+ allDayEventsForDay(day) {
392
+ return this.allDayEvents().filter((e) => e.start.getTime() <= day.getTime() + 86_400_000 && e.end.getTime() >= day.getTime());
393
+ }
394
+ getEventsInRange(start, end) {
395
+ return this.events().filter((e) => dateRangeOverlaps(e.start, e.end, start, end));
396
+ }
397
+ eventTop(event) {
398
+ const hh = this.hourHeight();
399
+ return ((event.start.getHours() * 60 + event.start.getMinutes()) / 60) * hh;
400
+ }
401
+ eventHeight(event) {
402
+ const hh = this.hourHeight();
403
+ const durationMin = diffMinutes(event.start, event.end);
404
+ return Math.max((durationMin / 60) * hh, 18);
405
+ }
406
+ currentTimeY() {
407
+ const hh = this.hourHeight();
408
+ const now = this.now();
409
+ return ((now.getHours() * 60 + now.getMinutes()) / 60) * hh;
410
+ }
411
+ // ── Private ──
412
+ _navigateTo(date) {
413
+ const vs = this.viewState();
414
+ const range = computeRange(vs.type, date, vs.firstDayOfWeek);
415
+ this.viewState.update((s) => ({
416
+ ...s,
417
+ date: new Date(date),
418
+ rangeStart: range.start,
419
+ rangeEnd: range.end,
420
+ }));
421
+ }
422
+ _viewSpan(type) {
423
+ switch (type) {
424
+ case 'timeGridDay':
425
+ case 'dayGridDay':
426
+ case 'agenda':
427
+ return 1;
428
+ case 'timeGrid3Day':
429
+ return 3;
430
+ case 'timeGridWorkWeek':
431
+ case 'timeGridWeek':
432
+ case 'dayGridWeek':
433
+ return 7;
434
+ case 'dayGridMonth':
435
+ return 30;
436
+ case 'timeline':
437
+ return 7;
438
+ default:
439
+ return 7;
440
+ }
441
+ }
442
+ _runHook(hook, arg) {
443
+ const fn = hook();
444
+ const result = fn(arg);
445
+ return result === false ? false : true;
446
+ }
447
+ }
448
+
449
+ const DEFAULT_WORKING_HOURS = {
450
+ days: [1, 2, 3, 4, 5],
451
+ ranges: [[480, 1020]],
452
+ };
453
+
454
+ function isTimeGridView(view) {
455
+ return view.startsWith('timeGrid');
456
+ }
457
+ function isDayGridView(view) {
458
+ return view.startsWith('dayGrid');
459
+ }
460
+
461
+ const DEFAULT_SELECTION = {
462
+ selectedEventIds: new Set(),
463
+ selectedRange: null,
464
+ multiSelect: false,
465
+ focusedCell: null,
466
+ };
467
+
468
+ class PluginHost {
469
+ constructor() {
470
+ this._plugins = new Map();
471
+ this._engine = null;
472
+ }
473
+ register(engine, plugins) {
474
+ this._engine = engine;
475
+ const sorted = [...plugins].sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
476
+ for (const plugin of sorted) {
477
+ if (this._plugins.has(plugin.name))
478
+ continue;
479
+ this._plugins.set(plugin.name, plugin);
480
+ plugin.onInit?.(engine);
481
+ }
482
+ }
483
+ unregister(name) {
484
+ const plugin = this._plugins.get(name);
485
+ if (plugin) {
486
+ plugin.onDestroy?.();
487
+ this._plugins.delete(name);
488
+ }
489
+ }
490
+ notifyRender() {
491
+ for (const plugin of this._plugins.values()) {
492
+ plugin.onRender?.();
493
+ }
494
+ }
495
+ destroy() {
496
+ for (const plugin of this._plugins.values()) {
497
+ plugin.onDestroy?.();
498
+ }
499
+ this._plugins.clear();
500
+ }
501
+ has(name) {
502
+ return this._plugins.has(name);
503
+ }
504
+ get(name) {
505
+ return this._plugins.get(name);
506
+ }
507
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: PluginHost, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
508
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: PluginHost }); }
509
+ }
510
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: PluginHost, decorators: [{
511
+ type: Injectable
512
+ }] });
513
+
514
+ class DragPlugin {
515
+ constructor(options = {}) {
516
+ this.name = 'drag';
517
+ this.priority = 10;
518
+ this._dragging = null;
519
+ this._options = options;
520
+ }
521
+ onInit(engine) {
522
+ this._engine = engine;
523
+ }
524
+ onDestroy() {
525
+ this._dragging = null;
526
+ }
527
+ startDrag(eventId, pointerY, dayEl, day) {
528
+ const event = this._engine.events().find((e) => e.id === eventId);
529
+ if (!event || event.draggable === false)
530
+ return false;
531
+ if (this._options.onDragStart && !this._options.onDragStart(event))
532
+ return false;
533
+ const scrollTop = dayEl.closest('.ngxsmk-sch__scroll')?.scrollTop ?? 0;
534
+ const colTop = dayEl.getBoundingClientRect().top;
535
+ const eventTop = this._engine.eventTop(event);
536
+ const offsetY = pointerY - colTop - eventTop + scrollTop;
537
+ this._dragging = {
538
+ eventId,
539
+ offsetY,
540
+ startTop: eventTop,
541
+ originDay: day,
542
+ };
543
+ return true;
544
+ }
545
+ moveDrag(pointerY, dayEl, day) {
546
+ if (!this._dragging)
547
+ return null;
548
+ const hh = this._engine.hourHeight();
549
+ const scrollTop = dayEl.closest('.ngxsmk-sch__scroll')?.scrollTop ?? 0;
550
+ const colTop = dayEl.getBoundingClientRect().top;
551
+ const rawY = pointerY - colTop + scrollTop - this._dragging.offsetY;
552
+ const snap = this._options.snapDuration ?? this._engine.viewState().snapDuration;
553
+ const snapPx = (snap / 60) * hh;
554
+ const top = Math.max(0, Math.round(rawY / snapPx) * snapPx);
555
+ return { top, day };
556
+ }
557
+ endDrag(top, day) {
558
+ if (!this._dragging)
559
+ return null;
560
+ const event = this._engine.events().find((e) => e.id === this._dragging.eventId);
561
+ if (!event) {
562
+ this._dragging = null;
563
+ return null;
564
+ }
565
+ const hh = this._engine.hourHeight();
566
+ const minutes = (top / hh) * 60;
567
+ const durationMs = event.end.getTime() - event.start.getTime();
568
+ const newStart = new Date(day);
569
+ newStart.setHours(0, 0, 0, 0);
570
+ newStart.setMinutes(minutes);
571
+ const newEnd = new Date(newStart.getTime() + durationMs);
572
+ const move = {
573
+ event,
574
+ from: event.start,
575
+ to: day,
576
+ newStart,
577
+ newEnd,
578
+ resourceId: event.resourceId,
579
+ };
580
+ this._engine.moveEvent(event.id, newStart, newEnd);
581
+ this._options.onDragEnd?.(move);
582
+ this._dragging = null;
583
+ return move;
584
+ }
585
+ cancelDrag() {
586
+ this._dragging = null;
587
+ }
588
+ get dragging() {
589
+ return this._dragging !== null;
590
+ }
591
+ get draggingEventId() {
592
+ return this._dragging?.eventId ?? null;
593
+ }
594
+ }
595
+
596
+ class ResizePlugin {
597
+ constructor(options = {}) {
598
+ this.name = 'resize';
599
+ this.priority = 11;
600
+ this._resizing = null;
601
+ this._options = options;
602
+ }
603
+ onInit(engine) {
604
+ this._engine = engine;
605
+ }
606
+ onDestroy() {
607
+ this._resizing = null;
608
+ }
609
+ startResize(eventId) {
610
+ const event = this._engine.events().find((e) => e.id === eventId);
611
+ if (!event || event.resizable === false)
612
+ return false;
613
+ if (this._options.onResizeStart && !this._options.onResizeStart(event))
614
+ return false;
615
+ this._resizing = { eventId, originEnd: new Date(event.end) };
616
+ return true;
617
+ }
618
+ moveResize(pointerY, dayEl) {
619
+ if (!this._resizing)
620
+ return null;
621
+ const event = this._engine.events().find((e) => e.id === this._resizing.eventId);
622
+ if (!event)
623
+ return null;
624
+ const hh = this._engine.hourHeight();
625
+ const scrollTop = dayEl.closest('.ngxsmk-sch__scroll')?.scrollTop ?? 0;
626
+ const colTop = dayEl.getBoundingClientRect().top;
627
+ const rawY = pointerY - colTop + scrollTop;
628
+ const snap = this._options.snapDuration ?? this._engine.viewState().snapDuration;
629
+ const snapPx = (snap / 60) * hh;
630
+ const y = Math.max(this._engine.eventTop(event) + snapPx, Math.round(rawY / snapPx) * snapPx);
631
+ const minutes = (y / hh) * 60;
632
+ const newEnd = new Date(event.start);
633
+ newEnd.setHours(0, 0, 0, 0);
634
+ newEnd.setMinutes(minutes);
635
+ const minDur = this._options.minDuration ?? 15;
636
+ if (newEnd.getTime() - event.start.getTime() < minDur * 60_000) {
637
+ newEnd.setTime(event.start.getTime() + minDur * 60_000);
638
+ }
639
+ return newEnd;
640
+ }
641
+ endResize() {
642
+ if (!this._resizing)
643
+ return null;
644
+ const event = this._engine.events().find((e) => e.id === this._resizing.eventId);
645
+ if (!event) {
646
+ this._resizing = null;
647
+ return null;
648
+ }
649
+ const resize = {
650
+ event,
651
+ oldEnd: this._resizing.originEnd,
652
+ newEnd: event.end,
653
+ };
654
+ this._engine.resizeEvent(event.id, event.end);
655
+ this._options.onResizeEnd?.(resize);
656
+ this._resizing = null;
657
+ return resize;
658
+ }
659
+ cancelResize() {
660
+ this._resizing = null;
661
+ }
662
+ get resizing() {
663
+ return this._resizing !== null;
664
+ }
665
+ get resizingEventId() {
666
+ return this._resizing?.eventId ?? null;
667
+ }
668
+ }
669
+
670
+ class SelectionPlugin {
671
+ constructor(options = {}) {
672
+ this.name = 'selection';
673
+ this.priority = 5;
674
+ this._rangeSelecting = false;
675
+ this._rangeStart = null;
676
+ this._options = options;
677
+ }
678
+ onInit(engine) {
679
+ this._engine = engine;
680
+ if (this._options.multiSelect) {
681
+ this._engine.selection.update((s) => ({ ...s, multiSelect: true }));
682
+ }
683
+ }
684
+ onDestroy() {
685
+ this._rangeSelecting = false;
686
+ this._rangeStart = null;
687
+ }
688
+ toggleEvent(eventId, modifierKey = false) {
689
+ const multi = this._options.multiSelect && modifierKey;
690
+ this._engine.selectEvent(eventId, multi);
691
+ const selectedIds = this._engine.selection().selectedEventIds;
692
+ const selectedEvents = this._engine.events().filter((e) => selectedIds.has(e.id));
693
+ if (selectedIds.has(eventId)) {
694
+ this._options.onSelect?.(selectedEvents);
695
+ }
696
+ else {
697
+ this._options.onDeselect?.(selectedEvents);
698
+ }
699
+ }
700
+ selectOnly(eventId) {
701
+ this._engine.clearSelection();
702
+ this._engine.selectEvent(eventId);
703
+ const event = this._engine.events().find((e) => e.id === eventId);
704
+ if (event)
705
+ this._options.onSelect?.([event]);
706
+ }
707
+ selectRange(start, end) {
708
+ this._engine.selectRange(start, end);
709
+ this._options.onRangeSelect?.(start, end);
710
+ }
711
+ startRangeSelect(date) {
712
+ this._rangeSelecting = true;
713
+ this._rangeStart = date;
714
+ }
715
+ updateRangeSelect(date) {
716
+ if (!this._rangeSelecting || !this._rangeStart)
717
+ return;
718
+ const s = this._rangeStart < date ? this._rangeStart : date;
719
+ const e = this._rangeStart < date ? date : this._rangeStart;
720
+ this._engine.selectRange(s, e);
721
+ }
722
+ endRangeSelect() {
723
+ if (!this._rangeSelecting || !this._rangeStart)
724
+ return null;
725
+ const range = this._engine.selection().selectedRange;
726
+ this._rangeSelecting = false;
727
+ this._rangeStart = null;
728
+ return range;
729
+ }
730
+ selectAll() {
731
+ const all = this._engine.events();
732
+ this._engine.selection.update((s) => ({
733
+ ...s,
734
+ selectedEventIds: new Set(all.map((e) => e.id)),
735
+ }));
736
+ }
737
+ clearSelection() {
738
+ this._engine.clearSelection();
739
+ }
740
+ get selectedIds() {
741
+ return this._engine.selection().selectedEventIds;
742
+ }
743
+ get selectedCount() {
744
+ return this._engine.selection().selectedEventIds.size;
745
+ }
746
+ get hasSelection() {
747
+ return this._engine.selection().selectedEventIds.size > 0;
748
+ }
749
+ get isRangeSelecting() {
750
+ return this._rangeSelecting;
751
+ }
752
+ }
753
+
754
+ function createDefaultTooltipState() {
755
+ return {
756
+ visible: false,
757
+ event: null,
758
+ x: 0,
759
+ y: 0,
760
+ placement: 'top',
761
+ content: '',
762
+ };
763
+ }
764
+ class TooltipPlugin {
765
+ constructor(options = {}) {
766
+ this.name = 'tooltip';
767
+ this.priority = 50;
768
+ this._timeout = null;
769
+ this._state = createDefaultTooltipState();
770
+ this._listeners = [];
771
+ this._options = {
772
+ delay: options.delay ?? 400,
773
+ showArrow: options.showArrow ?? true,
774
+ placement: options.placement ?? 'top',
775
+ maxWidth: options.maxWidth ?? 280,
776
+ onShow: options.onShow ?? (() => true),
777
+ onHide: options.onHide ??
778
+ (() => {
779
+ /* noop */
780
+ }),
781
+ content: options.content ?? defaultContent,
782
+ };
783
+ }
784
+ onInit(engine) {
785
+ this._engine = engine;
786
+ }
787
+ onDestroy() {
788
+ this.hide();
789
+ this._clearTimeout();
790
+ for (const unlisten of this._listeners)
791
+ unlisten();
792
+ this._listeners = [];
793
+ }
794
+ show(event, targetEl) {
795
+ this._clearTimeout();
796
+ this._timeout = setTimeout(() => {
797
+ if (this._options.onShow(event) === false)
798
+ return;
799
+ const rect = targetEl.getBoundingClientRect();
800
+ const pos = this._computePosition(rect);
801
+ this._state = {
802
+ visible: true,
803
+ event,
804
+ x: pos.x,
805
+ y: pos.y,
806
+ placement: pos.placement,
807
+ content: this._options.content(event),
808
+ };
809
+ }, this._options.delay);
810
+ }
811
+ hide() {
812
+ this._clearTimeout();
813
+ if (this._state.event) {
814
+ this._options.onHide(this._state.event);
815
+ }
816
+ this._state = createDefaultTooltipState();
817
+ }
818
+ updatePosition(targetEl) {
819
+ if (!this._state.visible || !this._state.event)
820
+ return;
821
+ const rect = targetEl.getBoundingClientRect();
822
+ const pos = this._computePosition(rect);
823
+ this._state = { ...this._state, x: pos.x, y: pos.y, placement: pos.placement };
824
+ }
825
+ get state() {
826
+ return this._state;
827
+ }
828
+ get isVisible() {
829
+ return this._state.visible;
830
+ }
831
+ _computePosition(rect) {
832
+ const placement = this._options.placement;
833
+ const offset = 8;
834
+ switch (placement) {
835
+ case 'top':
836
+ return { x: rect.left + rect.width / 2, y: rect.top - offset, placement };
837
+ case 'bottom':
838
+ return { x: rect.left + rect.width / 2, y: rect.bottom + offset, placement };
839
+ case 'left':
840
+ return { x: rect.left - offset, y: rect.top + rect.height / 2, placement };
841
+ case 'right':
842
+ return { x: rect.right + offset, y: rect.top + rect.height / 2, placement };
843
+ }
844
+ }
845
+ _clearTimeout() {
846
+ if (this._timeout) {
847
+ clearTimeout(this._timeout);
848
+ this._timeout = null;
849
+ }
850
+ }
851
+ }
852
+ function defaultContent(event) {
853
+ const time = `${event.start.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} – ${event.end.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`;
854
+ return `${event.title}\n${time}`;
855
+ }
856
+
857
+ class KeyboardPlugin {
858
+ constructor(options = {}) {
859
+ this.name = 'keyboard';
860
+ this.priority = 20;
861
+ this._handler = null;
862
+ this._options = options;
863
+ }
864
+ onInit(engine) {
865
+ this._engine = engine;
866
+ if (typeof document !== 'undefined') {
867
+ this._handler = (e) => this._onKeyDown(e);
868
+ document.addEventListener('keydown', this._handler);
869
+ }
870
+ }
871
+ onDestroy() {
872
+ if (this._handler) {
873
+ document.removeEventListener('keydown', this._handler);
874
+ this._handler = null;
875
+ }
876
+ }
877
+ _onKeyDown(e) {
878
+ const target = e.target;
879
+ if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)
880
+ return;
881
+ switch (e.key) {
882
+ case 'ArrowRight':
883
+ e.preventDefault();
884
+ this._moveFocus(1);
885
+ break;
886
+ case 'ArrowLeft':
887
+ e.preventDefault();
888
+ this._moveFocus(-1);
889
+ break;
890
+ case 'ArrowUp':
891
+ e.preventDefault();
892
+ this._moveFocusTime(-30);
893
+ break;
894
+ case 'ArrowDown':
895
+ e.preventDefault();
896
+ this._moveFocusTime(30);
897
+ break;
898
+ case 'Enter':
899
+ case ' ':
900
+ e.preventDefault();
901
+ this._activateFocused();
902
+ break;
903
+ case 'Delete':
904
+ case 'Backspace':
905
+ e.preventDefault();
906
+ this._deleteSelected();
907
+ break;
908
+ case 'Escape':
909
+ e.preventDefault();
910
+ this._deselect();
911
+ this._options.onKeyAction?.('escape');
912
+ break;
913
+ case 'a':
914
+ if (e.ctrlKey || e.metaKey) {
915
+ e.preventDefault();
916
+ this._selectAll();
917
+ }
918
+ break;
919
+ case 't':
920
+ if (!e.ctrlKey && !e.metaKey && !e.altKey) {
921
+ e.preventDefault();
922
+ this._goToday();
923
+ }
924
+ break;
925
+ }
926
+ }
927
+ _moveFocus(deltaDays) {
928
+ const sel = this._engine.selection();
929
+ const focused = sel.focusedCell;
930
+ if (focused) {
931
+ const newDate = addDays(focused.date, deltaDays);
932
+ this._engine.selection.update((s) => ({
933
+ ...s,
934
+ focusedCell: { date: newDate, resourceId: focused.resourceId },
935
+ }));
936
+ }
937
+ else {
938
+ const vs = this._engine.viewState();
939
+ this._engine.selection.update((s) => ({
940
+ ...s,
941
+ focusedCell: { date: vs.date },
942
+ }));
943
+ }
944
+ this._options.onKeyAction?.('moveFocus');
945
+ }
946
+ _moveFocusTime(deltaMinutes) {
947
+ const sel = this._engine.selection();
948
+ const focused = sel.focusedCell;
949
+ if (focused) {
950
+ const newDate = addMinutes(focused.date, deltaMinutes);
951
+ this._engine.selection.update((s) => ({
952
+ ...s,
953
+ focusedCell: { date: newDate, resourceId: focused.resourceId },
954
+ }));
955
+ }
956
+ else {
957
+ this._moveFocus(0);
958
+ }
959
+ this._options.onKeyAction?.('moveFocusTime');
960
+ }
961
+ _activateFocused() {
962
+ const sel = this._engine.selection();
963
+ const ids = sel.selectedEventIds;
964
+ if (ids.size === 1) {
965
+ const eventId = Array.from(ids)[0];
966
+ const event = this._engine.events().find((e) => e.id === eventId);
967
+ if (event)
968
+ this._options.onKeyAction?.('activate');
969
+ }
970
+ else {
971
+ const focused = sel.focusedCell;
972
+ if (focused) {
973
+ const dayEvents = this._engine.eventsForDay(focused.date);
974
+ if (dayEvents.length > 0) {
975
+ this._engine.selectEvent(dayEvents[0].id);
976
+ }
977
+ }
978
+ }
979
+ }
980
+ _deleteSelected() {
981
+ if (this._options.onKeyAction?.('delete') === false)
982
+ return;
983
+ const ids = this._engine.selection().selectedEventIds;
984
+ for (const id of ids) {
985
+ this._engine.removeEvent(id);
986
+ }
987
+ this._engine.clearSelection();
988
+ }
989
+ _deselect() {
990
+ this._engine.clearSelection();
991
+ }
992
+ _selectAll() {
993
+ const events = this._engine.events();
994
+ this._engine.selection.update((s) => ({
995
+ ...s,
996
+ selectedEventIds: new Set(events.map((e) => e.id)),
997
+ }));
998
+ this._options.onKeyAction?.('selectAll');
999
+ }
1000
+ _goToday() {
1001
+ this._engine.today();
1002
+ this._options.onKeyAction?.('today');
1003
+ }
1004
+ }
1005
+
1006
+ function snapToSlot(value, snapDuration) {
1007
+ return Math.round(value / snapDuration) * snapDuration;
1008
+ }
1009
+ function snapDateToSlot(date, snapDuration) {
1010
+ const ms = date.getTime();
1011
+ const snapMs = snapDuration * 60_000;
1012
+ return new Date(Math.round(ms / snapMs) * snapMs);
1013
+ }
1014
+ function minutesToPixels(minutes, hourHeight) {
1015
+ return (minutes / 60) * hourHeight;
1016
+ }
1017
+ function pixelsToMinutes(pixels, hourHeight) {
1018
+ return (pixels / hourHeight) * 60;
1019
+ }
1020
+ function timeToMinutes(date) {
1021
+ return date.getHours() * 60 + date.getMinutes();
1022
+ }
1023
+ function minutesToTime(baseDate, minutes) {
1024
+ const d = new Date(baseDate);
1025
+ d.setHours(0, 0, 0, 0);
1026
+ d.setMinutes(minutes);
1027
+ return d;
1028
+ }
1029
+
1030
+ /**
1031
+ * Generated bundle index. Do not edit.
1032
+ */
1033
+
1034
+ export { DEFAULT_SELECTION, DEFAULT_WORKING_HOURS, DragPlugin, KeyboardPlugin, PluginHost, ResizePlugin, SchedulerEngine, SelectionPlugin, TooltipPlugin, addDays, addMinutes, addWeeks, clampDate, createDefaultTooltipState, dateRangeOverlaps, diffDays, diffMinutes, endOfMonth, endOfWeek, formatDateRange, formatHour, getDayNames, getHoursInRange, getMonthGrid, getMonthNames, getWeekDates, getWorkWeekDates, isDayGridView, isPast, isSameDay, isSameWeek, isTimeGridView, isToday, isWeekend, minutesToPixels, minutesToTime, pixelsToMinutes, snapDateToSlot, snapToSlot, startOfDay, startOfMonth, startOfWeek, timeToMinutes };
1035
+ //# sourceMappingURL=ngxsmk-cdk-scheduler.mjs.map