ngwr 10.0.0 → 10.2.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 (238) hide show
  1. package/README.md +9 -8
  2. package/action-sheet/styles/_index.scss +6 -1
  3. package/alert/styles/_index.scss +7 -3
  4. package/badge/styles/_index.scss +1 -1
  5. package/badge/styles/_tag.scss +2 -2
  6. package/border-glow/styles/_index.scss +5 -0
  7. package/breadcrumbs/styles/_index.scss +1 -1
  8. package/button/styles/_index.scss +6 -6
  9. package/calendar/styles/_index.scss +9 -1
  10. package/circular-text/styles/_index.scss +6 -1
  11. package/density/styles/_index.scss +3 -1
  12. package/dialog/styles/_index.scss +1 -2
  13. package/drag-drop/styles/_index.scss +20 -7
  14. package/event-calendar/styles/_index.scss +284 -0
  15. package/falling-text/styles/_index.scss +5 -0
  16. package/fesm2022/ngwr-alert.mjs +8 -3
  17. package/fesm2022/ngwr-alert.mjs.map +1 -1
  18. package/fesm2022/ngwr-back-top.mjs +6 -4
  19. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  20. package/fesm2022/ngwr-border-glow.mjs +12 -9
  21. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  22. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  23. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  24. package/fesm2022/ngwr-calendar.mjs +5 -3
  25. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  26. package/fesm2022/ngwr-card.mjs +2 -2
  27. package/fesm2022/ngwr-card.mjs.map +1 -1
  28. package/fesm2022/ngwr-carousel.mjs +17 -4
  29. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  30. package/fesm2022/ngwr-cascader.mjs +31 -4
  31. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  32. package/fesm2022/ngwr-checkbox.mjs +12 -3
  33. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  34. package/fesm2022/ngwr-circular-text.mjs +2 -2
  35. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  36. package/fesm2022/ngwr-command-palette.mjs +7 -3
  37. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  38. package/fesm2022/ngwr-counter.mjs +9 -1
  39. package/fesm2022/ngwr-counter.mjs.map +1 -1
  40. package/fesm2022/ngwr-date-picker.mjs +23 -6
  41. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  42. package/fesm2022/ngwr-descriptions.mjs +5 -4
  43. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  44. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  45. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  46. package/fesm2022/ngwr-dropdown.mjs +4 -0
  47. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  48. package/fesm2022/ngwr-event-calendar.mjs +723 -0
  49. package/fesm2022/ngwr-event-calendar.mjs.map +1 -0
  50. package/fesm2022/ngwr-falling-text.mjs +2 -2
  51. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  52. package/fesm2022/ngwr-file-upload.mjs +2 -2
  53. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  54. package/fesm2022/ngwr-form.mjs +258 -42
  55. package/fesm2022/ngwr-form.mjs.map +1 -1
  56. package/fesm2022/ngwr-fuzzy-text.mjs +15 -1
  57. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  58. package/fesm2022/ngwr-gauge.mjs +8 -3
  59. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  60. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  61. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  62. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  63. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  64. package/fesm2022/ngwr-i18n-en.mjs +73 -5
  65. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  66. package/fesm2022/ngwr-i18n-ru.mjs +73 -5
  67. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  68. package/fesm2022/ngwr-i18n.mjs +20 -2
  69. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  70. package/fesm2022/ngwr-icon.mjs +5 -0
  71. package/fesm2022/ngwr-icon.mjs.map +1 -1
  72. package/fesm2022/ngwr-input-number.mjs +19 -3
  73. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  74. package/fesm2022/ngwr-input.mjs +48 -6
  75. package/fesm2022/ngwr-input.mjs.map +1 -1
  76. package/fesm2022/ngwr-knob.mjs +8 -3
  77. package/fesm2022/ngwr-knob.mjs.map +1 -1
  78. package/fesm2022/ngwr-lightbox.mjs +32 -3
  79. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  80. package/fesm2022/ngwr-line-chart.mjs +3 -3
  81. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  82. package/fesm2022/ngwr-list.mjs +2 -2
  83. package/fesm2022/ngwr-list.mjs.map +1 -1
  84. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  85. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  86. package/fesm2022/ngwr-marquee.mjs +2 -2
  87. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  88. package/fesm2022/ngwr-media.mjs +3 -0
  89. package/fesm2022/ngwr-media.mjs.map +1 -1
  90. package/fesm2022/ngwr-meter-group.mjs +14 -3
  91. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  92. package/fesm2022/ngwr-page-header.mjs +2 -2
  93. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  94. package/fesm2022/ngwr-pagination.mjs +1 -1
  95. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  96. package/fesm2022/ngwr-progress.mjs +8 -2
  97. package/fesm2022/ngwr-progress.mjs.map +1 -1
  98. package/fesm2022/ngwr-qr.mjs.map +1 -1
  99. package/fesm2022/ngwr-rating.mjs +6 -4
  100. package/fesm2022/ngwr-rating.mjs.map +1 -1
  101. package/fesm2022/ngwr-result.mjs +19 -12
  102. package/fesm2022/ngwr-result.mjs.map +1 -1
  103. package/fesm2022/ngwr-segmented.mjs +2 -2
  104. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  105. package/fesm2022/ngwr-select.mjs +28 -8
  106. package/fesm2022/ngwr-select.mjs.map +1 -1
  107. package/fesm2022/ngwr-shiny-text.mjs +4 -6
  108. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  109. package/fesm2022/ngwr-speed-dial.mjs +11 -3
  110. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  111. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  112. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  113. package/fesm2022/ngwr-squircle.mjs +1 -1
  114. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  115. package/fesm2022/ngwr-star-border.mjs +2 -2
  116. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  117. package/fesm2022/ngwr-switch.mjs +10 -3
  118. package/fesm2022/ngwr-switch.mjs.map +1 -1
  119. package/fesm2022/ngwr-table.mjs +233 -19
  120. package/fesm2022/ngwr-table.mjs.map +1 -1
  121. package/fesm2022/ngwr-tabs.mjs +21 -4
  122. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  123. package/fesm2022/ngwr-textarea.mjs +20 -4
  124. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  125. package/fesm2022/ngwr-tilt-card.mjs +2 -2
  126. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  127. package/fesm2022/ngwr-toolbar.mjs +2 -2
  128. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  129. package/fesm2022/ngwr-tour.mjs +264 -0
  130. package/fesm2022/ngwr-tour.mjs.map +1 -0
  131. package/fesm2022/ngwr-transfer.mjs +184 -0
  132. package/fesm2022/ngwr-transfer.mjs.map +1 -0
  133. package/fesm2022/ngwr-tree.mjs +23 -6
  134. package/fesm2022/ngwr-tree.mjs.map +1 -1
  135. package/fesm2022/ngwr-typewriter.mjs +2 -2
  136. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  137. package/fesm2022/ngwr-validators.mjs +118 -2
  138. package/fesm2022/ngwr-validators.mjs.map +1 -1
  139. package/fesm2022/ngwr-version.mjs +2 -2
  140. package/fesm2022/ngwr-version.mjs.map +1 -1
  141. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  142. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  143. package/fesm2022/ngwr-waves.mjs +2 -2
  144. package/fesm2022/ngwr-waves.mjs.map +1 -1
  145. package/form/styles/_index.scss +8 -4
  146. package/glitch-text/styles/_index.scss +5 -0
  147. package/gradient-text/styles/_index.scss +5 -0
  148. package/i18n/en.json +74 -6
  149. package/i18n/ru.json +74 -6
  150. package/icon/styles/_index.scss +5 -0
  151. package/keyboard/styles/_index.scss +5 -0
  152. package/llms-full.txt +123 -62
  153. package/llms.txt +29 -8
  154. package/loading-bar/styles/_index.scss +5 -0
  155. package/marquee/styles/_index.scss +7 -2
  156. package/overlay/styles/_index.scss +5 -0
  157. package/package.json +13 -1
  158. package/popover/styles/_index.scss +48 -12
  159. package/pull-to-refresh/styles/_index.scss +5 -0
  160. package/result/styles/_index.scss +3 -3
  161. package/schematics/icon-set/index.js +80 -34
  162. package/schematics/icon-set/schema.json +8 -3
  163. package/schematics/ng-add/index.js +5 -2
  164. package/schematics/page/templates.js +17 -21
  165. package/schematics/provider/index.js +31 -13
  166. package/schematics/provider/schema.json +40 -24
  167. package/schematics/use/index.js +5 -1
  168. package/schematics/use/schema.json +8 -3
  169. package/schematics/use/symbol-map.json +6 -177
  170. package/segmented/styles/_index.scss +1 -1
  171. package/select/styles/_index.scss +7 -3
  172. package/shiny-text/styles/_index.scss +5 -0
  173. package/sidebar/styles/_index.scss +3 -3
  174. package/speed-dial/styles/_index.scss +12 -1
  175. package/spotlight-card/styles/_index.scss +5 -0
  176. package/squircle/styles/_index.scss +5 -0
  177. package/star-border/styles/_index.scss +5 -0
  178. package/statistic/styles/_index.scss +2 -2
  179. package/stepper/styles/_index.scss +3 -3
  180. package/styles/_animations.scss +6 -0
  181. package/styles.scss +3 -0
  182. package/table/styles/_index.scss +100 -2
  183. package/tabs/styles/_index.scss +1 -1
  184. package/theme/styles/_colors.scss +65 -2
  185. package/theme/styles/_dark.scss +18 -6
  186. package/theme/styles/_focus.scss +2 -8
  187. package/tilt-card/styles/_index.scss +5 -0
  188. package/toast/styles/_index.scss +6 -3
  189. package/tour/styles/_index.scss +63 -0
  190. package/transfer/styles/_index.scss +105 -0
  191. package/types/ngwr-alert.d.ts +4 -1
  192. package/types/ngwr-avatar.d.ts +1 -1
  193. package/types/ngwr-back-top.d.ts +3 -2
  194. package/types/ngwr-badge.d.ts +1 -1
  195. package/types/ngwr-border-glow.d.ts +0 -1
  196. package/types/ngwr-carousel.d.ts +10 -1
  197. package/types/ngwr-cascader.d.ts +12 -1
  198. package/types/ngwr-checkbox.d.ts +9 -1
  199. package/types/ngwr-command-palette.d.ts +4 -1
  200. package/types/ngwr-date-picker.d.ts +9 -1
  201. package/types/ngwr-density.d.ts +1 -1
  202. package/types/ngwr-divider.d.ts +1 -1
  203. package/types/ngwr-event-calendar.d.ts +358 -0
  204. package/types/ngwr-form.d.ts +177 -20
  205. package/types/ngwr-fuzzy-text.d.ts +8 -0
  206. package/types/ngwr-gauge.d.ts +4 -1
  207. package/types/ngwr-i18n.d.ts +15 -0
  208. package/types/ngwr-input-number.d.ts +8 -1
  209. package/types/ngwr-input.d.ts +50 -20
  210. package/types/ngwr-knob.d.ts +4 -1
  211. package/types/ngwr-lightbox.d.ts +7 -1
  212. package/types/ngwr-line-chart.d.ts +1 -1
  213. package/types/ngwr-media.d.ts +1 -1
  214. package/types/ngwr-meter-group.d.ts +9 -1
  215. package/types/ngwr-page-header.d.ts +2 -2
  216. package/types/ngwr-pagination.d.ts +1 -1
  217. package/types/ngwr-progress.d.ts +4 -1
  218. package/types/ngwr-rating.d.ts +3 -2
  219. package/types/ngwr-result.d.ts +12 -6
  220. package/types/ngwr-segmented.d.ts +6 -0
  221. package/types/ngwr-select.d.ts +13 -7
  222. package/types/ngwr-shiny-text.d.ts +2 -4
  223. package/types/ngwr-speed-dial.d.ts +7 -1
  224. package/types/ngwr-squircle.d.ts +1 -1
  225. package/types/ngwr-switch.d.ts +7 -1
  226. package/types/ngwr-table.d.ts +126 -6
  227. package/types/ngwr-tabs.d.ts +1 -4
  228. package/types/ngwr-textarea.d.ts +8 -1
  229. package/types/ngwr-toolbar.d.ts +2 -2
  230. package/types/ngwr-tour.d.ts +132 -0
  231. package/types/ngwr-transfer.d.ts +118 -0
  232. package/types/ngwr-tree.d.ts +10 -2
  233. package/types/ngwr-validators.d.ts +62 -2
  234. package/types/ngwr-version.d.ts +2 -2
  235. package/typewriter/styles/_index.scss +5 -0
  236. package/typography/styles/_index.scss +5 -5
  237. package/virtual-scroll/styles/_index.scss +6 -1
  238. package/waves/styles/_index.scss +5 -0
@@ -0,0 +1,723 @@
1
+ import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
+ import { NgTemplateOutlet } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, TemplateRef, Directive, input, model, output, DOCUMENT, contentChild, signal, computed, ViewEncapsulation, Component } from '@angular/core';
5
+ import { WrButton, WrButtonGroup } from 'ngwr/button';
6
+ import { WrDateAdapter } from 'ngwr/date-adapter';
7
+ import { readI18nText, useI18nFormatter, useI18nText } from 'ngwr/i18n';
8
+ import { numAttr } from 'ngwr/utils';
9
+
10
+ /**
11
+ * @license
12
+ *
13
+ * Use of this source code is governed by an MIT-style license that can be
14
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
15
+ */
16
+ /**
17
+ * Replace the chip's contents. The event is the implicit context; the chip
18
+ * itself — its button, its position and its drag handling — stays with the
19
+ * calendar, so a custom template cannot break the geometry.
20
+ *
21
+ * @example
22
+ * ```html
23
+ * <wr-event-calendar [events]="events">
24
+ * <ng-template wrCalendarEvent let-event>
25
+ * <strong>{{ event.title }}</strong> — {{ event.data.room }}
26
+ * </ng-template>
27
+ * </wr-event-calendar>
28
+ * ```
29
+ */
30
+ class WrCalendarEventTemplate {
31
+ template = inject(TemplateRef);
32
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrCalendarEventTemplate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
33
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: WrCalendarEventTemplate, isStandalone: true, selector: "ng-template[wrCalendarEvent]", ngImport: i0 });
34
+ }
35
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrCalendarEventTemplate, decorators: [{
36
+ type: Directive,
37
+ args: [{
38
+ selector: 'ng-template[wrCalendarEvent]',
39
+ }]
40
+ }] });
41
+
42
+ /**
43
+ * @license
44
+ *
45
+ * Use of this source code is governed by an MIT-style license that can be
46
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
47
+ */
48
+ const MINUTES_PER_DAY = 24 * 60;
49
+ const DAYS_PER_WEEK = 7;
50
+ const MONTH_ROWS = 6;
51
+ /**
52
+ * Month / week / day event calendar with drag to move and resize.
53
+ *
54
+ * `events` is an INPUT, never mutated: a drag emits `eventChange` describing
55
+ * where the event would land and stops there. Apply it to your own state and
56
+ * the calendar re-renders — so an unhandled output is a cancelled drag, an
57
+ * optimistic update is one `set`, and a rejected server write needs no rollback
58
+ * path inside the component.
59
+ *
60
+ * Every chip lives inside the `role="gridcell"` where it starts and reaches out
61
+ * with `calc()` widths or percentage heights. That is what keeps the ARIA grid
62
+ * valid — an events layer floating over the grid would leave rows owning
63
+ * something other than cells — and it means no pixel measurement anywhere.
64
+ *
65
+ * **Keyboard.** The grid is one tab stop with a roving cursor: arrows move by
66
+ * day (left / right) and by week or slot (up / down), `Home` / `End` jump to
67
+ * the ends of the row, `Enter` on an empty cell emits `slotClick`, and `Enter`
68
+ * on a cell holding events focuses the first chip (`Escape` returns). On a
69
+ * focused chip, `Alt` + arrows move the event — the keyboard equivalent of the
70
+ * drag, emitting the same `eventChange`.
71
+ *
72
+ * Date math and formatting go through {@link WrDateAdapter}; register one with
73
+ * `provideWrDateAdapter(...)` at bootstrap.
74
+ *
75
+ * @example
76
+ * ```html
77
+ * <wr-event-calendar
78
+ * editable
79
+ * [events]="events()"
80
+ * [(view)]="view"
81
+ * [(date)]="anchor"
82
+ * (eventChange)="apply($event)"
83
+ * (slotClick)="compose($event)"
84
+ * />
85
+ * ```
86
+ *
87
+ * @see https://ngwr.dev/reference/components/event-calendar
88
+ */
89
+ class WrEventCalendar {
90
+ /** Everything to render. Never mutated — see `eventChange`. */
91
+ events = input([], /* @ts-ignore */
92
+ ...(ngDevMode ? [{ debugName: "events" }] : /* istanbul ignore next */ []));
93
+ /** Which span is shown. Two-way bindable. @default 'month' */
94
+ view = model('month', /* @ts-ignore */
95
+ ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
96
+ /** Any date inside the shown span. Two-way bindable. */
97
+ date = model(new Date(), /* @ts-ignore */
98
+ ...(ngDevMode ? [{ debugName: "date" }] : /* istanbul ignore next */ []));
99
+ /** Which buttons the view switcher offers. Empty hides it. */
100
+ views = input(['month', 'week', 'day'], /* @ts-ignore */
101
+ ...(ngDevMode ? [{ debugName: "views" }] : /* istanbul ignore next */ []));
102
+ /** Allow dragging chips to move and resize them. @default false */
103
+ editable = input(false, { ...(ngDevMode ? { debugName: "editable" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
104
+ /** Minutes per row in the time views — also the drag snap. @default 30 */
105
+ slotMinutes = input(30, { ...(ngDevMode ? { debugName: "slotMinutes" } : /* istanbul ignore next */ {}), transform: numAttr(30) });
106
+ /** First hour the time views show. @default 0 */
107
+ dayStartHour = input(0, { ...(ngDevMode ? { debugName: "dayStartHour" } : /* istanbul ignore next */ {}), transform: numAttr(0) });
108
+ /** First hour they do NOT show, exclusive. @default 24 */
109
+ dayEndHour = input(24, { ...(ngDevMode ? { debugName: "dayEndHour" } : /* istanbul ignore next */ {}), transform: numAttr(24) });
110
+ /** Lanes a month cell shows before collapsing the rest into “+N more”. @default 3 */
111
+ maxLanes = input(3, { ...(ngDevMode ? { debugName: "maxLanes" } : /* istanbul ignore next */ {}), transform: numAttr(3) });
112
+ /** Hide the built-in header — supply your own navigation instead. @default false */
113
+ hideHeader = input(false, { ...(ngDevMode ? { debugName: "hideHeader" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
114
+ /** A chip was activated. */
115
+ eventClick = output();
116
+ /** Empty space was activated — the slot the user pointed at. */
117
+ slotClick = output();
118
+ /** A drag or an `Alt` + arrow finished. Apply it yourself; nothing moves until you do. */
119
+ eventChange = output();
120
+ adapter = inject(WrDateAdapter);
121
+ document = inject(DOCUMENT);
122
+ chipTpl = contentChild(WrCalendarEventTemplate, /* @ts-ignore */
123
+ ...(ngDevMode ? [{ debugName: "chipTpl" }] : /* istanbul ignore next */ []));
124
+ todayLabel = readI18nText('eventCalendar.today', 'Today');
125
+ previousLabel = readI18nText('eventCalendar.previous', 'Previous');
126
+ nextLabel = readI18nText('eventCalendar.next', 'Next');
127
+ allDayLabel = readI18nText('eventCalendar.allDay', 'All day');
128
+ timeLabel = readI18nText('eventCalendar.time', 'Time');
129
+ moreLabel = useI18nFormatter('eventCalendar.more', '+{{count}} more');
130
+ viewLabels = {
131
+ month: readI18nText('eventCalendar.month', 'Month'),
132
+ week: readI18nText('eventCalendar.week', 'Week'),
133
+ day: readI18nText('eventCalendar.day', 'Day'),
134
+ };
135
+ /** Accessible name of the grid; overridable for a page with several. */
136
+ ariaLabel = input(null, /* @ts-ignore */
137
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
138
+ resolvedAriaLabel = useI18nText(this.ariaLabel, 'eventCalendar.label', 'Calendar');
139
+ /**
140
+ * `[day, minutes]` of the roving cursor — `minutes === -1` means a month cell
141
+ * or the all-day band. Raw, so it survives a view switch; read
142
+ * {@link cursorCell}, which clamps it to what the current view actually has.
143
+ */
144
+ cursor = signal([0, -1], /* @ts-ignore */
145
+ ...(ngDevMode ? [{ debugName: "cursor" }] : /* istanbul ignore next */ []));
146
+ /**
147
+ * The cursor as the current view can honour it. Exactly one cell may carry
148
+ * `tabindex="0"`, so a stale coordinate — the 09:30 row after switching to
149
+ * month, day 34 after switching to week — must fall back to a real cell
150
+ * rather than leave the grid with no tab stop at all.
151
+ */
152
+ cursorCell = computed(() => {
153
+ const [day, minutes] = this.cursor();
154
+ const columns = Math.max(1, this.days().length);
155
+ const clamped = Math.min(columns - 1, Math.max(0, day));
156
+ if (this.view() === 'month')
157
+ return [clamped, -1];
158
+ if (minutes === -1 && this.hasAllDay())
159
+ return [clamped, -1];
160
+ const rows = this.rows();
161
+ const known = rows.some(row => row.minutes === minutes);
162
+ return [clamped, known ? minutes : (rows[0]?.minutes ?? 0)];
163
+ }, /* @ts-ignore */
164
+ ...(ngDevMode ? [{ debugName: "cursorCell" }] : /* istanbul ignore next */ []));
165
+ /** Non-null only while a pointer is down on a chip. @internal */
166
+ drag = signal(null, /* @ts-ignore */
167
+ ...(ngDevMode ? [{ debugName: "drag" }] : /* istanbul ignore next */ []));
168
+ dragging = computed(() => this.drag()?.event.id ?? null, /* @ts-ignore */
169
+ ...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
170
+ chipTemplate = computed(() => this.chipTpl()?.template ?? null, /* @ts-ignore */
171
+ ...(ngDevMode ? [{ debugName: "chipTemplate" }] : /* istanbul ignore next */ []));
172
+ classes = computed(() => {
173
+ const parts = ['wr-event-calendar', `wr-event-calendar--${this.view()}`];
174
+ if (this.editable())
175
+ parts.push('wr-event-calendar--editable');
176
+ if (this.drag())
177
+ parts.push('wr-event-calendar--dragging');
178
+ return parts.join(' ');
179
+ }, /* @ts-ignore */
180
+ ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
181
+ // ---------------------------------------------------------------- ranges
182
+ /** Inclusive-exclusive window the current view covers. */
183
+ range = computed(() => {
184
+ const anchor = this.startOfDay(this.date());
185
+ switch (this.view()) {
186
+ case 'day':
187
+ return [anchor, this.adapter.addDays(anchor, 1)];
188
+ case 'week': {
189
+ const start = this.startOfWeek(anchor);
190
+ return [start, this.adapter.addDays(start, DAYS_PER_WEEK)];
191
+ }
192
+ default: {
193
+ const first = this.adapter.createDate(this.adapter.getYear(anchor), this.adapter.getMonth(anchor), 1);
194
+ const start = this.startOfWeek(first);
195
+ return [start, this.adapter.addDays(start, MONTH_ROWS * DAYS_PER_WEEK)];
196
+ }
197
+ }
198
+ }, /* @ts-ignore */
199
+ ...(ngDevMode ? [{ debugName: "range" }] : /* istanbul ignore next */ []));
200
+ /** Every day the view shows, left to right. */
201
+ days = computed(() => {
202
+ const [start, end] = this.range();
203
+ const count = Math.round((end.getTime() - start.getTime()) / (MINUTES_PER_DAY * 60_000));
204
+ return Array.from({ length: count }, (_, i) => this.adapter.addDays(start, i));
205
+ }, /* @ts-ignore */
206
+ ...(ngDevMode ? [{ debugName: "days" }] : /* istanbul ignore next */ []));
207
+ /** Only what overlaps the window — everything downstream works off this. */
208
+ visible = computed(() => {
209
+ const [start, end] = this.range();
210
+ return [...this.events()]
211
+ .filter(e => e.end.getTime() > start.getTime() && e.start.getTime() < end.getTime())
212
+ .sort((a, b) => {
213
+ const byStart = a.start.getTime() - b.start.getTime();
214
+ // Ties go to the longer event, so a week-long band claims its lane
215
+ // before the one-day events sitting alongside it.
216
+ return byStart !== 0 ? byStart : b.end.getTime() - a.end.getTime();
217
+ });
218
+ }, /* @ts-ignore */
219
+ ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
220
+ title = computed(() => {
221
+ const anchor = this.date();
222
+ const months = this.adapter.getMonthNames('long');
223
+ switch (this.view()) {
224
+ case 'day':
225
+ return this.adapter.format(anchor, 'longDate');
226
+ case 'week': {
227
+ const [start] = this.range();
228
+ const last = this.adapter.addDays(start, DAYS_PER_WEEK - 1);
229
+ return `${this.adapter.format(start, 'mediumDate')} – ${this.adapter.format(last, 'mediumDate')}`;
230
+ }
231
+ default:
232
+ return `${months[this.adapter.getMonth(anchor)]} ${this.adapter.getYear(anchor)}`;
233
+ }
234
+ }, /* @ts-ignore */
235
+ ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
236
+ weekdayNames = computed(() => {
237
+ const names = this.adapter.getDayOfWeekNames('short');
238
+ const first = this.adapter.getFirstDayOfWeek();
239
+ return Array.from({ length: DAYS_PER_WEEK }, (_, i) => names[(first + i) % DAYS_PER_WEEK]);
240
+ }, /* @ts-ignore */
241
+ ...(ngDevMode ? [{ debugName: "weekdayNames" }] : /* istanbul ignore next */ []));
242
+ switcher = computed(() => this.views().map(view => ({ view, label: this.viewLabels[view] })), /* @ts-ignore */
243
+ ...(ngDevMode ? [{ debugName: "switcher" }] : /* istanbul ignore next */ []));
244
+ // ----------------------------------------------------------- month model
245
+ weeks = computed(() => {
246
+ const days = this.days();
247
+ const events = this.visible();
248
+ const weeks = [];
249
+ const month = this.adapter.getMonth(this.date());
250
+ for (let w = 0; w * DAYS_PER_WEEK < days.length; w++) {
251
+ const row = days.slice(w * DAYS_PER_WEEK, (w + 1) * DAYS_PER_WEEK);
252
+ const { chips, hidden } = this.bandLayout(events, row, this.maxLanes());
253
+ weeks.push({
254
+ key: this.iso(row[0]),
255
+ days: row.map((date, col) => ({
256
+ date,
257
+ key: this.iso(date),
258
+ day: String(this.adapter.getDate(date)),
259
+ label: this.adapter.format(date, 'longDate'),
260
+ inMonth: this.adapter.getMonth(date) === month,
261
+ isToday: this.adapter.isSameDay(date, this.adapter.today()),
262
+ bands: chips.filter(chip => chip.column === col),
263
+ hidden: hidden[col],
264
+ })),
265
+ });
266
+ }
267
+ return weeks;
268
+ }, /* @ts-ignore */
269
+ ...(ngDevMode ? [{ debugName: "weeks" }] : /* istanbul ignore next */ []));
270
+ // ------------------------------------------------------------ time model
271
+ columns = computed(() => {
272
+ const weekdays = this.adapter.getDayOfWeekNames('short');
273
+ return this.days().map(date => ({
274
+ key: this.iso(date),
275
+ date,
276
+ weekday: weekdays[this.adapter.getDayOfWeek(date)],
277
+ day: String(this.adapter.getDate(date)),
278
+ label: this.adapter.format(date, 'longDate'),
279
+ isToday: this.adapter.isSameDay(date, this.adapter.today()),
280
+ }));
281
+ }, /* @ts-ignore */
282
+ ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
283
+ /** The all-day band above the time grid — same layout as a month week. */
284
+ allDayBands = computed(() => {
285
+ const days = this.days();
286
+ const events = this.visible().filter(e => e.allDay === true || this.spansWholeDay(e));
287
+ return this.bandLayout(events, days, Number.POSITIVE_INFINITY).chips;
288
+ }, /* @ts-ignore */
289
+ ...(ngDevMode ? [{ debugName: "allDayBands" }] : /* istanbul ignore next */ []));
290
+ allDayCells = computed(() => {
291
+ const days = this.days();
292
+ const chips = this.allDayBands();
293
+ return days.map((date, col) => ({
294
+ key: this.iso(date),
295
+ date,
296
+ label: `${this.allDayLabel} — ${this.adapter.format(date, 'longDate')}`,
297
+ bands: chips.filter(chip => chip.column === col),
298
+ }));
299
+ }, /* @ts-ignore */
300
+ ...(ngDevMode ? [{ debugName: "allDayCells" }] : /* istanbul ignore next */ []));
301
+ hasAllDay = computed(() => this.allDayBands().length > 0, /* @ts-ignore */
302
+ ...(ngDevMode ? [{ debugName: "hasAllDay" }] : /* istanbul ignore next */ []));
303
+ rows = computed(() => {
304
+ const slot = Math.max(5, this.slotMinutes());
305
+ const from = Math.max(0, Math.min(23, this.dayStartHour())) * 60;
306
+ const to = Math.max(from + slot, Math.min(24, this.dayEndHour()) * 60);
307
+ const days = this.days();
308
+ const placed = this.timeLayout(days, slot);
309
+ const rows = [];
310
+ for (let minutes = from; minutes < to; minutes += slot) {
311
+ rows.push({
312
+ key: String(minutes),
313
+ minutes,
314
+ major: minutes % 60 === 0,
315
+ label: minutes % 60 === 0 ? this.clock(minutes) : '',
316
+ cells: days.map((date, col) => ({
317
+ key: `${this.iso(date)}:${minutes}`,
318
+ date,
319
+ label: `${this.clock(minutes)} — ${this.adapter.format(date, 'longDate')}`,
320
+ chips: placed[col].filter(chip => chip.slotMinutes === minutes).map(chip => chip.chip),
321
+ })),
322
+ });
323
+ }
324
+ return rows;
325
+ }, /* @ts-ignore */
326
+ ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
327
+ // ------------------------------------------------------------------ nav
328
+ step(direction) {
329
+ const anchor = this.date();
330
+ switch (this.view()) {
331
+ case 'day':
332
+ this.date.set(this.adapter.addDays(anchor, direction));
333
+ break;
334
+ case 'week':
335
+ this.date.set(this.adapter.addDays(anchor, direction * DAYS_PER_WEEK));
336
+ break;
337
+ default:
338
+ this.date.set(this.adapter.addMonths(anchor, direction));
339
+ }
340
+ }
341
+ goToday() {
342
+ this.date.set(this.adapter.today());
343
+ }
344
+ setView(view) {
345
+ this.view.set(view);
346
+ }
347
+ /** “+N more” opens that day — the overflow is only ever a month-view problem. */
348
+ openDay(date) {
349
+ this.date.set(date);
350
+ this.view.set('day');
351
+ }
352
+ // -------------------------------------------------------------- pointer
353
+ onChipPointerDown(event, chipEvent, kind) {
354
+ if (!this.canDrag(chipEvent) || event.button !== 0)
355
+ return;
356
+ const cell = this.cellUnder(event.clientX, event.clientY);
357
+ if (!cell)
358
+ return;
359
+ // The chip must stop swallowing hit-tests, or `elementFromPoint` reports
360
+ // the chip itself for the whole drag and the target never changes.
361
+ try {
362
+ event.target.setPointerCapture?.(event.pointerId);
363
+ }
364
+ catch {
365
+ // Capture is an optimisation — it keeps the release on this element even
366
+ // when the pointer leaves it. A pointer that is already gone throws here,
367
+ // and losing capture is not a reason to lose the drag.
368
+ }
369
+ event.preventDefault();
370
+ event.stopPropagation();
371
+ this.drag.set({
372
+ event: chipEvent,
373
+ kind,
374
+ originDate: cell.date,
375
+ originMinutes: cell.minutes,
376
+ pointerId: event.pointerId,
377
+ });
378
+ }
379
+ onPointerUp(event) {
380
+ const state = this.drag();
381
+ this.drag.set(null);
382
+ if (state?.pointerId !== event.pointerId)
383
+ return;
384
+ const cell = this.cellUnder(event.clientX, event.clientY);
385
+ if (!cell)
386
+ return;
387
+ const dayDelta = this.daysBetween(state.originDate, cell.date);
388
+ const minuteDelta = cell.minutes < 0 || state.originMinutes < 0 ? 0 : cell.minutes - state.originMinutes;
389
+ if (dayDelta === 0 && minuteDelta === 0)
390
+ return;
391
+ const { event: source, kind } = state;
392
+ if (kind === 'resize') {
393
+ const end = this.shift(source.end, dayDelta, minuteDelta);
394
+ // A resize that would end at or before the start is a no-op, not an
395
+ // inverted event.
396
+ if (end.getTime() <= source.start.getTime())
397
+ return;
398
+ this.eventChange.emit({ event: source, start: source.start, end, kind });
399
+ return;
400
+ }
401
+ this.eventChange.emit({
402
+ event: source,
403
+ start: this.shift(source.start, dayDelta, minuteDelta),
404
+ end: this.shift(source.end, dayDelta, minuteDelta),
405
+ kind,
406
+ });
407
+ }
408
+ onChipClick(event) {
409
+ this.eventClick.emit(event);
410
+ }
411
+ onCellClick(date, minutes) {
412
+ this.slotClick.emit(this.slotAt(date, minutes));
413
+ }
414
+ // ------------------------------------------------------------- keyboard
415
+ onChipKeyDown(event, chipEvent) {
416
+ if (event.key === 'Escape') {
417
+ this.focusCell(event);
418
+ return;
419
+ }
420
+ if (!event.altKey || !this.canDrag(chipEvent))
421
+ return;
422
+ const slot = Math.max(5, this.slotMinutes());
423
+ const inTime = this.view() !== 'month';
424
+ let days = 0;
425
+ let minutes = 0;
426
+ switch (event.key) {
427
+ case 'ArrowLeft':
428
+ days = -1;
429
+ break;
430
+ case 'ArrowRight':
431
+ days = 1;
432
+ break;
433
+ case 'ArrowUp':
434
+ if (inTime)
435
+ minutes = -slot;
436
+ else
437
+ days = -DAYS_PER_WEEK;
438
+ break;
439
+ case 'ArrowDown':
440
+ if (inTime)
441
+ minutes = slot;
442
+ else
443
+ days = DAYS_PER_WEEK;
444
+ break;
445
+ default:
446
+ return;
447
+ }
448
+ event.preventDefault();
449
+ this.eventChange.emit({
450
+ event: chipEvent,
451
+ start: this.shift(chipEvent.start, days, minutes),
452
+ end: this.shift(chipEvent.end, days, minutes),
453
+ kind: 'move',
454
+ });
455
+ }
456
+ onGridKeyDown(event) {
457
+ // Handled per cell, not on the grid: the element carrying the keyboard
458
+ // should be the one that actually holds focus. Chips sit inside cells and
459
+ // own their keys, so let anything originating in one bubble straight past.
460
+ if (event.target !== event.currentTarget)
461
+ return;
462
+ const [day, minutes] = this.cursorCell();
463
+ const columns = this.days().length;
464
+ const rows = this.rows();
465
+ const inTime = this.view() !== 'month';
466
+ let next;
467
+ switch (event.key) {
468
+ case 'ArrowLeft':
469
+ next = [Math.max(0, day - 1), minutes];
470
+ break;
471
+ case 'ArrowRight':
472
+ next = [Math.min(columns - 1, day + 1), minutes];
473
+ break;
474
+ case 'ArrowUp':
475
+ next = inTime ? [day, this.stepRow(minutes, -1, rows)] : [Math.max(0, day - DAYS_PER_WEEK), minutes];
476
+ break;
477
+ case 'ArrowDown':
478
+ next = inTime
479
+ ? [day, this.stepRow(minutes, 1, rows)]
480
+ : [day + DAYS_PER_WEEK < columns ? day + DAYS_PER_WEEK : day, minutes];
481
+ break;
482
+ case 'Home':
483
+ next = [day - (day % DAYS_PER_WEEK), minutes];
484
+ break;
485
+ case 'End':
486
+ next = [Math.min(columns - 1, day - (day % DAYS_PER_WEEK) + DAYS_PER_WEEK - 1), minutes];
487
+ break;
488
+ case 'Enter':
489
+ case ' ': {
490
+ event.preventDefault();
491
+ const cell = event.target;
492
+ const chip = cell.querySelector('.wr-event-calendar__chip');
493
+ if (chip)
494
+ chip.focus();
495
+ else
496
+ this.onCellClick(this.days()[day], minutes);
497
+ return;
498
+ }
499
+ default:
500
+ return;
501
+ }
502
+ event.preventDefault();
503
+ this.cursor.set(next);
504
+ this.focusCursor(event.currentTarget);
505
+ }
506
+ isCursor(day, minutes) {
507
+ const [d, m] = this.cursorCell();
508
+ return d === day && m === minutes;
509
+ }
510
+ // --------------------------------------------------------------- layout
511
+ /**
512
+ * Greedy lane packing for day-spanning chips. Sorted by start then by length,
513
+ * each segment takes the first lane its columns are free in — the classic
514
+ * interval-graph colouring, and the reason a long event keeps one lane across
515
+ * the whole week instead of stair-stepping.
516
+ *
517
+ * `limit` caps the visible lanes; anything past it is reported per column so
518
+ * the cell can say how much it is hiding.
519
+ */
520
+ bandLayout(events, days, limit) {
521
+ const first = days[0];
522
+ const last = this.adapter.addDays(days[days.length - 1], 1);
523
+ const lanes = [];
524
+ const chips = [];
525
+ const hidden = days.map(() => 0);
526
+ for (const event of events) {
527
+ if (event.end.getTime() <= first.getTime() || event.start.getTime() >= last.getTime())
528
+ continue;
529
+ const from = Math.max(0, this.daysBetween(first, this.startOfDay(event.start)));
530
+ // An exclusive end landing exactly on midnight belongs to the previous
531
+ // day — otherwise every all-day event paints one column too wide.
532
+ const endDay = this.startOfDay(new Date(event.end.getTime() - 1));
533
+ const to = Math.min(days.length - 1, this.daysBetween(first, endDay));
534
+ if (to < from)
535
+ continue;
536
+ let lane = lanes.findIndex(taken => taken.every(col => col < from || col > to));
537
+ if (lane === -1) {
538
+ lane = lanes.length;
539
+ lanes.push([]);
540
+ }
541
+ for (let col = from; col <= to; col++)
542
+ lanes[lane].push(col);
543
+ if (lane >= limit) {
544
+ for (let col = from; col <= to; col++)
545
+ hidden[col]++;
546
+ continue;
547
+ }
548
+ chips.push({
549
+ key: `${String(event.id)}:${from}`,
550
+ event,
551
+ column: from,
552
+ span: to - from + 1,
553
+ lane,
554
+ continuesBefore: event.start.getTime() < first.getTime(),
555
+ continuesAfter: event.end.getTime() > last.getTime(),
556
+ });
557
+ }
558
+ return { chips, hidden };
559
+ }
560
+ /**
561
+ * Column layout inside one day: events that overlap in time share the width.
562
+ * Clusters are built by a running high-water mark — a new cluster starts the
563
+ * moment an event begins after everything before it has ended.
564
+ */
565
+ timeLayout(days, slot) {
566
+ const from = Math.max(0, Math.min(23, this.dayStartHour())) * 60;
567
+ const to = Math.max(from + slot, Math.min(24, this.dayEndHour()) * 60);
568
+ const timed = this.visible().filter(e => !e.allDay && !this.spansWholeDay(e));
569
+ return days.map(day => {
570
+ const dayStart = this.startOfDay(day);
571
+ const windowStart = dayStart.getTime() + from * 60_000;
572
+ const windowEnd = dayStart.getTime() + to * 60_000;
573
+ const onDay = timed
574
+ .filter(e => e.end.getTime() > windowStart && e.start.getTime() < windowEnd)
575
+ .map(event => ({
576
+ event,
577
+ from: Math.max(windowStart, event.start.getTime()),
578
+ to: Math.min(windowEnd, event.end.getTime()),
579
+ }))
580
+ .sort((a, b) => {
581
+ const byStart = a.from - b.from;
582
+ return byStart !== 0 ? byStart : b.to - a.to;
583
+ });
584
+ const out = [];
585
+ let cluster = [];
586
+ let highWater = -1;
587
+ const flush = () => {
588
+ for (const [index, item] of cluster.entries()) {
589
+ const minutes = Math.floor((item.from - dayStart.getTime()) / 60_000);
590
+ const slotStart = from + Math.floor((minutes - from) / slot) * slot;
591
+ const length = (item.to - item.from) / 60_000;
592
+ out.push({
593
+ slotMinutes: slotStart,
594
+ chip: {
595
+ key: `${String(item.event.id)}:${minutes}`,
596
+ event: item.event,
597
+ top: ((minutes - slotStart) / slot) * 100,
598
+ height: (length / slot) * 100,
599
+ left: (index / cluster.length) * 100,
600
+ width: (1 / cluster.length) * 100,
601
+ continuesBefore: item.event.start.getTime() < windowStart,
602
+ continuesAfter: item.event.end.getTime() > windowEnd,
603
+ },
604
+ });
605
+ }
606
+ cluster = [];
607
+ };
608
+ for (const item of onDay) {
609
+ if (cluster.length > 0 && item.from >= highWater)
610
+ flush();
611
+ cluster.push(item);
612
+ highWater = Math.max(highWater, item.to);
613
+ }
614
+ flush();
615
+ return out;
616
+ });
617
+ }
618
+ // --------------------------------------------------------------- chrome
619
+ chipLabel(event) {
620
+ const time = event.allDay ? this.allDayLabel : this.adapter.format(event.start, 'time');
621
+ return `${event.title}, ${time}`;
622
+ }
623
+ chipTime(event) {
624
+ return event.allDay ? this.allDayLabel : this.adapter.format(event.start, 'time');
625
+ }
626
+ canDrag(event) {
627
+ return this.editable() && event.editable !== false;
628
+ }
629
+ // --------------------------------------------------------------- helpers
630
+ slotAt(date, minutes) {
631
+ if (minutes < 0) {
632
+ const start = this.startOfDay(date);
633
+ return { start, end: this.adapter.addDays(start, 1), allDay: true };
634
+ }
635
+ const start = new Date(this.startOfDay(date).getTime() + minutes * 60_000);
636
+ return { start, end: new Date(start.getTime() + Math.max(5, this.slotMinutes()) * 60_000), allDay: false };
637
+ }
638
+ /** The `[data-cell]` under the pointer, or `null` outside the grid. */
639
+ cellUnder(x, y) {
640
+ const el = this.document.elementFromPoint(x, y)?.closest('[data-cell-date]');
641
+ if (!el)
642
+ return null;
643
+ // Epoch millis rather than a formatted date: `new Date('2026-08-08')` is
644
+ // parsed as UTC and lands on the previous day west of Greenwich.
645
+ const stamp = Number(el.dataset['cellDate']);
646
+ if (!Number.isFinite(stamp))
647
+ return null;
648
+ return { date: new Date(stamp), minutes: Number(el.dataset['cellMinutes'] ?? -1) };
649
+ }
650
+ /** Value of a cell's `data-cell-date`. @internal */
651
+ stamp(date) {
652
+ return this.startOfDay(date).getTime();
653
+ }
654
+ focusCursor(from) {
655
+ const [day, minutes] = this.cursorCell();
656
+ from.closest('[role="grid"]')?.querySelector(`[data-cell-index="${day}:${minutes}"]`)?.focus();
657
+ }
658
+ focusCell(event) {
659
+ event.preventDefault();
660
+ event.target.closest('[data-cell-date]')?.focus();
661
+ }
662
+ /**
663
+ * Move one time row, treating the all-day band as the row above the first —
664
+ * otherwise the band is mouse-only, which is the kind of gap that makes a
665
+ * keyboard user give up on the whole grid.
666
+ */
667
+ stepRow(minutes, direction, rows) {
668
+ if (minutes === -1)
669
+ return direction === 1 ? (rows[0]?.minutes ?? -1) : -1;
670
+ const index = rows.findIndex(row => row.minutes === minutes);
671
+ if (index === -1)
672
+ return rows[0]?.minutes ?? -1;
673
+ if (index === 0 && direction === -1)
674
+ return this.hasAllDay() ? -1 : minutes;
675
+ return rows[Math.min(rows.length - 1, index + direction)].minutes;
676
+ }
677
+ shift(date, days, minutes) {
678
+ return new Date(this.adapter.addDays(date, days).getTime() + minutes * 60_000);
679
+ }
680
+ startOfDay(date) {
681
+ return this.adapter.setTime(date, 0, 0, 0);
682
+ }
683
+ startOfWeek(date) {
684
+ const first = this.adapter.getFirstDayOfWeek();
685
+ const offset = (this.adapter.getDayOfWeek(date) - first + DAYS_PER_WEEK) % DAYS_PER_WEEK;
686
+ return this.startOfDay(this.adapter.addDays(date, -offset));
687
+ }
688
+ /** Whole days apart — computed on the day floor, so DST cannot round it off. */
689
+ daysBetween(from, to) {
690
+ const a = this.startOfDay(from);
691
+ const b = this.startOfDay(to);
692
+ return Math.round((b.getTime() - a.getTime()) / (MINUTES_PER_DAY * 60_000));
693
+ }
694
+ spansWholeDay(event) {
695
+ return event.end.getTime() - event.start.getTime() >= MINUTES_PER_DAY * 60_000;
696
+ }
697
+ clock(minutes) {
698
+ const date = this.adapter.setTime(this.adapter.today(), Math.floor(minutes / 60), minutes % 60, 0);
699
+ return this.adapter.format(date, 'time');
700
+ }
701
+ iso(date) {
702
+ return `${this.adapter.getYear(date)}-${this.adapter.getMonth(date) + 1}-${this.adapter.getDate(date)}`;
703
+ }
704
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrEventCalendar, deps: [], target: i0.ɵɵFactoryTarget.Component });
705
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrEventCalendar, isStandalone: true, selector: "wr-event-calendar", inputs: { events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, date: { classPropertyName: "date", publicName: "date", isSignal: true, isRequired: false, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, slotMinutes: { classPropertyName: "slotMinutes", publicName: "slotMinutes", isSignal: true, isRequired: false, transformFunction: null }, dayStartHour: { classPropertyName: "dayStartHour", publicName: "dayStartHour", isSignal: true, isRequired: false, transformFunction: null }, dayEndHour: { classPropertyName: "dayEndHour", publicName: "dayEndHour", isSignal: true, isRequired: false, transformFunction: null }, maxLanes: { classPropertyName: "maxLanes", publicName: "maxLanes", isSignal: true, isRequired: false, transformFunction: null }, hideHeader: { classPropertyName: "hideHeader", publicName: "hideHeader", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { view: "viewChange", date: "dateChange", eventClick: "eventClick", slotClick: "slotClick", eventChange: "eventChange" }, host: { listeners: { "pointerup": "onPointerUp($event)", "pointercancel": "drag.set(null)" }, properties: { "class": "classes()" } }, queries: [{ propertyName: "chipTpl", first: true, predicate: WrCalendarEventTemplate, descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n Two grids, one rule: a chip always lives inside the `role=\"gridcell\"` where it\n STARTS, and reaches out from there \u2014 `calc()` widths for day-spanning bands,\n percentage heights for timed chips. A floating events layer would read better\n in the template and would leave `role=\"row\"` owning something other than\n cells, which is exactly what the axe gate rejects.\n-->\n@if (!hideHeader()) {\n <div class=\"wr-event-calendar__header\">\n <div class=\"wr-event-calendar__nav\">\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-event-calendar__step\"\n [attr.aria-label]=\"previousLabel\"\n (click)=\"step(-1)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <button wr-btn type=\"button\" size=\"sm\" outlined (click)=\"goToday()\">{{ todayLabel }}</button>\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-event-calendar__step\"\n [attr.aria-label]=\"nextLabel\"\n (click)=\"step(1)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n </div>\n\n <h2 class=\"wr-event-calendar__title\">{{ title() }}</h2>\n\n @if (switcher().length > 1) {\n <wr-btn-group>\n @for (item of switcher(); track item.view) {\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n [outlined]=\"view() !== item.view\"\n [color]=\"view() === item.view ? 'primary' : null\"\n [attr.aria-pressed]=\"view() === item.view\"\n (click)=\"setView(item.view)\"\n >\n {{ item.label }}\n </button>\n }\n </wr-btn-group>\n }\n </div>\n}\n\n@if (view() === 'month') {\n <div\n role=\"grid\"\n class=\"wr-event-calendar__grid wr-event-calendar__grid--month\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n >\n <div role=\"row\" class=\"wr-event-calendar__row\">\n @for (name of weekdayNames(); track $index) {\n <div role=\"columnheader\" class=\"wr-event-calendar__weekday\">{{ name }}</div>\n }\n </div>\n\n @for (week of weeks(); track week.key; let w = $index) {\n <div role=\"row\" class=\"wr-event-calendar__row\">\n @for (cell of week.days; track cell.key; let c = $index) {\n @let index = w * 7 + c;\n <div\n role=\"gridcell\"\n class=\"wr-event-calendar__cell wr-event-calendar__cell--day\"\n [class.wr-event-calendar__cell--muted]=\"!cell.inMonth\"\n [class.wr-event-calendar__cell--today]=\"cell.isToday\"\n [attr.aria-label]=\"cell.label\"\n [attr.tabindex]=\"isCursor(index, -1) ? 0 : -1\"\n [attr.data-cell-date]=\"stamp(cell.date)\"\n [attr.data-cell-minutes]=\"-1\"\n [attr.data-cell-index]=\"`${index}:-1`\"\n (click)=\"onCellClick(cell.date, -1)\"\n (keydown)=\"onGridKeyDown($event)\"\n >\n <span class=\"wr-event-calendar__daynum\" aria-hidden=\"true\">{{ cell.day }}</span>\n\n @for (chip of cell.bands; track chip.key) {\n <ng-container\n [ngTemplateOutlet]=\"band\"\n [ngTemplateOutletContext]=\"{ $implicit: chip, offset: '1.75rem' }\"\n />\n }\n\n @if (cell.hidden > 0) {\n <button\n type=\"button\"\n class=\"wr-event-calendar__more\"\n [style.--wr-event-calendar-lane]=\"maxLanes()\"\n (click)=\"openDay(cell.date); $event.stopPropagation()\"\n >\n {{ moreLabel({ count: cell.hidden }) }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n} @else {\n <div\n role=\"grid\"\n class=\"wr-event-calendar__grid wr-event-calendar__grid--time\"\n [style.--wr-event-calendar-cols]=\"columns().length\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n >\n <div role=\"row\" class=\"wr-event-calendar__row\">\n <div role=\"columnheader\" class=\"wr-event-calendar__gutter\" [attr.aria-label]=\"timeLabel\"></div>\n @for (column of columns(); track column.key) {\n <div\n role=\"columnheader\"\n class=\"wr-event-calendar__colhead\"\n [class.wr-event-calendar__colhead--today]=\"column.isToday\"\n >\n <span class=\"wr-event-calendar__colhead-weekday\">{{ column.weekday }}</span>\n <span class=\"wr-event-calendar__colhead-day\">{{ column.day }}</span>\n </div>\n }\n </div>\n\n @if (hasAllDay()) {\n <div role=\"row\" class=\"wr-event-calendar__row wr-event-calendar__row--allday\">\n <div role=\"rowheader\" class=\"wr-event-calendar__gutter\">{{ allDayLabel }}</div>\n @for (cell of allDayCells(); track cell.key; let c = $index) {\n <div\n role=\"gridcell\"\n class=\"wr-event-calendar__cell wr-event-calendar__cell--allday\"\n [attr.aria-label]=\"cell.label\"\n [attr.tabindex]=\"isCursor(c, -1) ? 0 : -1\"\n [attr.data-cell-date]=\"stamp(cell.date)\"\n [attr.data-cell-minutes]=\"-1\"\n [attr.data-cell-index]=\"`${c}:-1`\"\n (click)=\"onCellClick(cell.date, -1)\"\n (keydown)=\"onGridKeyDown($event)\"\n >\n @for (chip of cell.bands; track chip.key) {\n <ng-container [ngTemplateOutlet]=\"band\" [ngTemplateOutletContext]=\"{ $implicit: chip, offset: '0rem' }\" />\n }\n </div>\n }\n </div>\n }\n\n @for (row of rows(); track row.key) {\n <div role=\"row\" class=\"wr-event-calendar__row\" [class.wr-event-calendar__row--major]=\"row.major\">\n <div role=\"rowheader\" class=\"wr-event-calendar__gutter\">{{ row.label }}</div>\n @for (cell of row.cells; track cell.key; let c = $index) {\n <div\n role=\"gridcell\"\n class=\"wr-event-calendar__cell wr-event-calendar__cell--slot\"\n [class.wr-event-calendar__cell--major]=\"row.major\"\n [attr.aria-label]=\"cell.label\"\n [attr.tabindex]=\"isCursor(c, row.minutes) ? 0 : -1\"\n [attr.data-cell-date]=\"stamp(cell.date)\"\n [attr.data-cell-minutes]=\"row.minutes\"\n [attr.data-cell-index]=\"`${c}:${row.minutes}`\"\n (click)=\"onCellClick(cell.date, row.minutes)\"\n (keydown)=\"onGridKeyDown($event)\"\n >\n @for (chip of cell.chips; track chip.key) {\n <button\n type=\"button\"\n class=\"wr-event-calendar__chip wr-event-calendar__chip--time\"\n [class.wr-event-calendar__chip--dragging]=\"dragging() === chip.event.id\"\n [class.wr-event-calendar__chip--continues-before]=\"chip.continuesBefore\"\n [class.wr-event-calendar__chip--continues-after]=\"chip.continuesAfter\"\n [style.--wr-event-calendar-color]=\"`var(--wr-color-${chip.event.color ?? 'primary'})`\"\n [style.top.%]=\"chip.top\"\n [style.height.%]=\"chip.height\"\n [style.left.%]=\"chip.left\"\n [style.width.%]=\"chip.width\"\n [attr.aria-label]=\"chipLabel(chip.event)\"\n (click)=\"onChipClick(chip.event); $event.stopPropagation()\"\n (keydown)=\"onChipKeyDown($event, chip.event)\"\n (pointerdown)=\"onChipPointerDown($event, chip.event, 'move')\"\n >\n <span class=\"wr-event-calendar__chip-time\" aria-hidden=\"true\">{{ chipTime(chip.event) }}</span>\n @if (chipTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"{ $implicit: chip.event }\" />\n } @else {\n <span class=\"wr-event-calendar__chip-title\" aria-hidden=\"true\">{{ chip.event.title }}</span>\n }\n\n @if (canDrag(chip.event) && !chip.continuesAfter) {\n <!--\n A grab area, not a control: the same resize is on the keyboard\n as `Alt` + arrows on the chip itself, so exposing a second\n focusable thing here would add a tab stop that leads nowhere.\n -->\n <span\n class=\"wr-event-calendar__resize\"\n aria-hidden=\"true\"\n (pointerdown)=\"onChipPointerDown($event, chip.event, 'resize')\"\n ></span>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n\n<!-- One chip shape for both day-spanning cases: month cells and the all-day band. -->\n<ng-template #band let-chip let-offset=\"offset\">\n <button\n type=\"button\"\n class=\"wr-event-calendar__chip wr-event-calendar__chip--band\"\n [class.wr-event-calendar__chip--dragging]=\"dragging() === chip.event.id\"\n [class.wr-event-calendar__chip--continues-before]=\"chip.continuesBefore\"\n [class.wr-event-calendar__chip--continues-after]=\"chip.continuesAfter\"\n [style.--wr-event-calendar-color]=\"`var(--wr-color-${chip.event.color ?? 'primary'})`\"\n [style.--wr-event-calendar-span]=\"chip.span\"\n [style.--wr-event-calendar-lane]=\"chip.lane\"\n [style.--wr-event-calendar-offset]=\"offset\"\n [attr.aria-label]=\"chipLabel(chip.event)\"\n (click)=\"onChipClick(chip.event); $event.stopPropagation()\"\n (keydown)=\"onChipKeyDown($event, chip.event)\"\n (pointerdown)=\"onChipPointerDown($event, chip.event, 'move')\"\n >\n @if (chipTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"{ $implicit: chip.event }\" />\n } @else {\n <span class=\"wr-event-calendar__chip-title\" aria-hidden=\"true\">{{ chip.event.title }}</span>\n }\n </button>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: WrButton, selector: "wr-btn, button[wr-btn], a[wr-btn]", inputs: ["color", "size", "shape", "icon", "iconPosition", "disabled", "outlined", "block", "loading", "isDisabledWhenLoading"] }, { kind: "component", type: WrButtonGroup, selector: "wr-btn-group", inputs: ["shape"] }], encapsulation: i0.ViewEncapsulation.None });
706
+ }
707
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrEventCalendar, decorators: [{
708
+ type: Component,
709
+ args: [{ selector: 'wr-event-calendar', encapsulation: ViewEncapsulation.None, host: {
710
+ '[class]': 'classes()',
711
+ // A drag has to end wherever the pointer is released, including outside the
712
+ // chip it started on — so the host owns the release, not the chip.
713
+ '(pointerup)': 'onPointerUp($event)',
714
+ '(pointercancel)': 'drag.set(null)',
715
+ }, imports: [NgTemplateOutlet, WrButton, WrButtonGroup], template: "<!--\n Two grids, one rule: a chip always lives inside the `role=\"gridcell\"` where it\n STARTS, and reaches out from there \u2014 `calc()` widths for day-spanning bands,\n percentage heights for timed chips. A floating events layer would read better\n in the template and would leave `role=\"row\"` owning something other than\n cells, which is exactly what the axe gate rejects.\n-->\n@if (!hideHeader()) {\n <div class=\"wr-event-calendar__header\">\n <div class=\"wr-event-calendar__nav\">\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-event-calendar__step\"\n [attr.aria-label]=\"previousLabel\"\n (click)=\"step(-1)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <button wr-btn type=\"button\" size=\"sm\" outlined (click)=\"goToday()\">{{ todayLabel }}</button>\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-event-calendar__step\"\n [attr.aria-label]=\"nextLabel\"\n (click)=\"step(1)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n </div>\n\n <h2 class=\"wr-event-calendar__title\">{{ title() }}</h2>\n\n @if (switcher().length > 1) {\n <wr-btn-group>\n @for (item of switcher(); track item.view) {\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n [outlined]=\"view() !== item.view\"\n [color]=\"view() === item.view ? 'primary' : null\"\n [attr.aria-pressed]=\"view() === item.view\"\n (click)=\"setView(item.view)\"\n >\n {{ item.label }}\n </button>\n }\n </wr-btn-group>\n }\n </div>\n}\n\n@if (view() === 'month') {\n <div\n role=\"grid\"\n class=\"wr-event-calendar__grid wr-event-calendar__grid--month\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n >\n <div role=\"row\" class=\"wr-event-calendar__row\">\n @for (name of weekdayNames(); track $index) {\n <div role=\"columnheader\" class=\"wr-event-calendar__weekday\">{{ name }}</div>\n }\n </div>\n\n @for (week of weeks(); track week.key; let w = $index) {\n <div role=\"row\" class=\"wr-event-calendar__row\">\n @for (cell of week.days; track cell.key; let c = $index) {\n @let index = w * 7 + c;\n <div\n role=\"gridcell\"\n class=\"wr-event-calendar__cell wr-event-calendar__cell--day\"\n [class.wr-event-calendar__cell--muted]=\"!cell.inMonth\"\n [class.wr-event-calendar__cell--today]=\"cell.isToday\"\n [attr.aria-label]=\"cell.label\"\n [attr.tabindex]=\"isCursor(index, -1) ? 0 : -1\"\n [attr.data-cell-date]=\"stamp(cell.date)\"\n [attr.data-cell-minutes]=\"-1\"\n [attr.data-cell-index]=\"`${index}:-1`\"\n (click)=\"onCellClick(cell.date, -1)\"\n (keydown)=\"onGridKeyDown($event)\"\n >\n <span class=\"wr-event-calendar__daynum\" aria-hidden=\"true\">{{ cell.day }}</span>\n\n @for (chip of cell.bands; track chip.key) {\n <ng-container\n [ngTemplateOutlet]=\"band\"\n [ngTemplateOutletContext]=\"{ $implicit: chip, offset: '1.75rem' }\"\n />\n }\n\n @if (cell.hidden > 0) {\n <button\n type=\"button\"\n class=\"wr-event-calendar__more\"\n [style.--wr-event-calendar-lane]=\"maxLanes()\"\n (click)=\"openDay(cell.date); $event.stopPropagation()\"\n >\n {{ moreLabel({ count: cell.hidden }) }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n} @else {\n <div\n role=\"grid\"\n class=\"wr-event-calendar__grid wr-event-calendar__grid--time\"\n [style.--wr-event-calendar-cols]=\"columns().length\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n >\n <div role=\"row\" class=\"wr-event-calendar__row\">\n <div role=\"columnheader\" class=\"wr-event-calendar__gutter\" [attr.aria-label]=\"timeLabel\"></div>\n @for (column of columns(); track column.key) {\n <div\n role=\"columnheader\"\n class=\"wr-event-calendar__colhead\"\n [class.wr-event-calendar__colhead--today]=\"column.isToday\"\n >\n <span class=\"wr-event-calendar__colhead-weekday\">{{ column.weekday }}</span>\n <span class=\"wr-event-calendar__colhead-day\">{{ column.day }}</span>\n </div>\n }\n </div>\n\n @if (hasAllDay()) {\n <div role=\"row\" class=\"wr-event-calendar__row wr-event-calendar__row--allday\">\n <div role=\"rowheader\" class=\"wr-event-calendar__gutter\">{{ allDayLabel }}</div>\n @for (cell of allDayCells(); track cell.key; let c = $index) {\n <div\n role=\"gridcell\"\n class=\"wr-event-calendar__cell wr-event-calendar__cell--allday\"\n [attr.aria-label]=\"cell.label\"\n [attr.tabindex]=\"isCursor(c, -1) ? 0 : -1\"\n [attr.data-cell-date]=\"stamp(cell.date)\"\n [attr.data-cell-minutes]=\"-1\"\n [attr.data-cell-index]=\"`${c}:-1`\"\n (click)=\"onCellClick(cell.date, -1)\"\n (keydown)=\"onGridKeyDown($event)\"\n >\n @for (chip of cell.bands; track chip.key) {\n <ng-container [ngTemplateOutlet]=\"band\" [ngTemplateOutletContext]=\"{ $implicit: chip, offset: '0rem' }\" />\n }\n </div>\n }\n </div>\n }\n\n @for (row of rows(); track row.key) {\n <div role=\"row\" class=\"wr-event-calendar__row\" [class.wr-event-calendar__row--major]=\"row.major\">\n <div role=\"rowheader\" class=\"wr-event-calendar__gutter\">{{ row.label }}</div>\n @for (cell of row.cells; track cell.key; let c = $index) {\n <div\n role=\"gridcell\"\n class=\"wr-event-calendar__cell wr-event-calendar__cell--slot\"\n [class.wr-event-calendar__cell--major]=\"row.major\"\n [attr.aria-label]=\"cell.label\"\n [attr.tabindex]=\"isCursor(c, row.minutes) ? 0 : -1\"\n [attr.data-cell-date]=\"stamp(cell.date)\"\n [attr.data-cell-minutes]=\"row.minutes\"\n [attr.data-cell-index]=\"`${c}:${row.minutes}`\"\n (click)=\"onCellClick(cell.date, row.minutes)\"\n (keydown)=\"onGridKeyDown($event)\"\n >\n @for (chip of cell.chips; track chip.key) {\n <button\n type=\"button\"\n class=\"wr-event-calendar__chip wr-event-calendar__chip--time\"\n [class.wr-event-calendar__chip--dragging]=\"dragging() === chip.event.id\"\n [class.wr-event-calendar__chip--continues-before]=\"chip.continuesBefore\"\n [class.wr-event-calendar__chip--continues-after]=\"chip.continuesAfter\"\n [style.--wr-event-calendar-color]=\"`var(--wr-color-${chip.event.color ?? 'primary'})`\"\n [style.top.%]=\"chip.top\"\n [style.height.%]=\"chip.height\"\n [style.left.%]=\"chip.left\"\n [style.width.%]=\"chip.width\"\n [attr.aria-label]=\"chipLabel(chip.event)\"\n (click)=\"onChipClick(chip.event); $event.stopPropagation()\"\n (keydown)=\"onChipKeyDown($event, chip.event)\"\n (pointerdown)=\"onChipPointerDown($event, chip.event, 'move')\"\n >\n <span class=\"wr-event-calendar__chip-time\" aria-hidden=\"true\">{{ chipTime(chip.event) }}</span>\n @if (chipTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"{ $implicit: chip.event }\" />\n } @else {\n <span class=\"wr-event-calendar__chip-title\" aria-hidden=\"true\">{{ chip.event.title }}</span>\n }\n\n @if (canDrag(chip.event) && !chip.continuesAfter) {\n <!--\n A grab area, not a control: the same resize is on the keyboard\n as `Alt` + arrows on the chip itself, so exposing a second\n focusable thing here would add a tab stop that leads nowhere.\n -->\n <span\n class=\"wr-event-calendar__resize\"\n aria-hidden=\"true\"\n (pointerdown)=\"onChipPointerDown($event, chip.event, 'resize')\"\n ></span>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n\n<!-- One chip shape for both day-spanning cases: month cells and the all-day band. -->\n<ng-template #band let-chip let-offset=\"offset\">\n <button\n type=\"button\"\n class=\"wr-event-calendar__chip wr-event-calendar__chip--band\"\n [class.wr-event-calendar__chip--dragging]=\"dragging() === chip.event.id\"\n [class.wr-event-calendar__chip--continues-before]=\"chip.continuesBefore\"\n [class.wr-event-calendar__chip--continues-after]=\"chip.continuesAfter\"\n [style.--wr-event-calendar-color]=\"`var(--wr-color-${chip.event.color ?? 'primary'})`\"\n [style.--wr-event-calendar-span]=\"chip.span\"\n [style.--wr-event-calendar-lane]=\"chip.lane\"\n [style.--wr-event-calendar-offset]=\"offset\"\n [attr.aria-label]=\"chipLabel(chip.event)\"\n (click)=\"onChipClick(chip.event); $event.stopPropagation()\"\n (keydown)=\"onChipKeyDown($event, chip.event)\"\n (pointerdown)=\"onChipPointerDown($event, chip.event, 'move')\"\n >\n @if (chipTemplate(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"{ $implicit: chip.event }\" />\n } @else {\n <span class=\"wr-event-calendar__chip-title\" aria-hidden=\"true\">{{ chip.event.title }}</span>\n }\n </button>\n</ng-template>\n" }]
716
+ }], propDecorators: { events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }, { type: i0.Output, args: ["viewChange"] }], date: [{ type: i0.Input, args: [{ isSignal: true, alias: "date", required: false }] }, { type: i0.Output, args: ["dateChange"] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], slotMinutes: [{ type: i0.Input, args: [{ isSignal: true, alias: "slotMinutes", required: false }] }], dayStartHour: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayStartHour", required: false }] }], dayEndHour: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayEndHour", required: false }] }], maxLanes: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLanes", required: false }] }], hideHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideHeader", required: false }] }], eventClick: [{ type: i0.Output, args: ["eventClick"] }], slotClick: [{ type: i0.Output, args: ["slotClick"] }], eventChange: [{ type: i0.Output, args: ["eventChange"] }], chipTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => WrCalendarEventTemplate), { isSignal: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
717
+
718
+ /**
719
+ * Generated bundle index. Do not edit.
720
+ */
721
+
722
+ export { WrCalendarEventTemplate, WrEventCalendar };
723
+ //# sourceMappingURL=ngwr-event-calendar.mjs.map