@k2b/ui 0.22.0 → 0.23.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 (98) hide show
  1. package/dist/browser/content/Calendar.js +1086 -1049
  2. package/dist/browser/content/Calendar.js.map +1 -1
  3. package/dist/browser/content/CalendarDayView.js +1187 -0
  4. package/dist/browser/content/CalendarDayView.js.map +1 -0
  5. package/dist/browser/content/CalendarWeekView.js +1571 -0
  6. package/dist/browser/content/CalendarWeekView.js.map +1 -0
  7. package/dist/browser/content/ChartExplorer.js +174 -82
  8. package/dist/browser/content/ChartExplorer.js.map +1 -1
  9. package/dist/browser/content/ChartFilterControls.js +90 -33
  10. package/dist/browser/content/ChartFilterControls.js.map +1 -1
  11. package/dist/browser/content/DataTable.js +199 -171
  12. package/dist/browser/content/DataTable.js.map +1 -1
  13. package/dist/browser/content/calendar-day-scroll.js +98 -0
  14. package/dist/browser/content/calendar-day-scroll.js.map +1 -0
  15. package/dist/browser/content/calendar-days.js +408 -0
  16. package/dist/browser/content/calendar-days.js.map +1 -0
  17. package/dist/browser/content/calendar-dialogs.js +236 -0
  18. package/dist/browser/content/calendar-dialogs.js.map +1 -0
  19. package/dist/browser/content/calendar-messages.js +210 -2
  20. package/dist/browser/content/calendar-messages.js.map +1 -1
  21. package/dist/browser/content/calendar-pointer.js +15 -3
  22. package/dist/browser/content/calendar-pointer.js.map +1 -1
  23. package/dist/browser/content/calendar-shared.js +328 -0
  24. package/dist/browser/content/calendar-shared.js.map +1 -0
  25. package/dist/browser/content/calendar-time-view.js +1649 -0
  26. package/dist/browser/content/calendar-time-view.js.map +1 -0
  27. package/dist/browser/content/chart-messages.js +10 -0
  28. package/dist/browser/content/chart-messages.js.map +1 -1
  29. package/dist/browser/content/index.js.map +1 -1
  30. package/dist/browser/inputs/Combobox.js +0 -1
  31. package/dist/browser/inputs/Combobox.js.map +1 -1
  32. package/dist/browser/layout/AppWorkspace.js +123 -97
  33. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  34. package/dist/browser/layout/PageTitle.js +4 -1
  35. package/dist/browser/layout/PageTitle.js.map +1 -1
  36. package/dist/browser/layout/app-workspace-controller.js +164 -86
  37. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  38. package/dist/browser/surfaces/StatCell.js +18 -6
  39. package/dist/browser/surfaces/StatCell.js.map +1 -1
  40. package/dist/ssr/content/Calendar.js +524 -335
  41. package/dist/ssr/content/Calendar.js.map +1 -1
  42. package/dist/ssr/content/CalendarDayView.js +800 -0
  43. package/dist/ssr/content/CalendarDayView.js.map +1 -0
  44. package/dist/ssr/content/CalendarWeekView.js +1069 -0
  45. package/dist/ssr/content/CalendarWeekView.js.map +1 -0
  46. package/dist/ssr/content/ChartExplorer.js +93 -34
  47. package/dist/ssr/content/ChartExplorer.js.map +1 -1
  48. package/dist/ssr/content/ChartFilterControls.js +49 -7
  49. package/dist/ssr/content/ChartFilterControls.js.map +1 -1
  50. package/dist/ssr/content/DataTable.js +69 -51
  51. package/dist/ssr/content/DataTable.js.map +1 -1
  52. package/dist/ssr/content/calendar-day-scroll.js +98 -0
  53. package/dist/ssr/content/calendar-day-scroll.js.map +1 -0
  54. package/dist/ssr/content/calendar-days.js +408 -0
  55. package/dist/ssr/content/calendar-days.js.map +1 -0
  56. package/dist/ssr/content/calendar-dialogs.js +159 -0
  57. package/dist/ssr/content/calendar-dialogs.js.map +1 -0
  58. package/dist/ssr/content/calendar-messages.js +210 -2
  59. package/dist/ssr/content/calendar-messages.js.map +1 -1
  60. package/dist/ssr/content/calendar-pointer.js +15 -3
  61. package/dist/ssr/content/calendar-pointer.js.map +1 -1
  62. package/dist/ssr/content/calendar-shared.js +261 -0
  63. package/dist/ssr/content/calendar-shared.js.map +1 -0
  64. package/dist/ssr/content/calendar-time-view.js +1306 -0
  65. package/dist/ssr/content/calendar-time-view.js.map +1 -0
  66. package/dist/ssr/content/chart-messages.js +10 -0
  67. package/dist/ssr/content/chart-messages.js.map +1 -1
  68. package/dist/ssr/content/index.js.map +1 -1
  69. package/dist/ssr/inputs/Combobox.js.map +1 -1
  70. package/dist/ssr/layout/AppWorkspace.js +38 -29
  71. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  72. package/dist/ssr/layout/PageTitle.js +4 -1
  73. package/dist/ssr/layout/PageTitle.js.map +1 -1
  74. package/dist/ssr/layout/app-workspace-controller.js +164 -86
  75. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  76. package/dist/ssr/surfaces/StatCell.js +2 -2
  77. package/dist/ssr/surfaces/StatCell.js.map +1 -1
  78. package/dist/styles.css +1 -1
  79. package/dist/types/content/Calendar.d.ts +91 -0
  80. package/dist/types/content/CalendarDayView.d.ts +7 -0
  81. package/dist/types/content/CalendarWeekView.d.ts +7 -0
  82. package/dist/types/content/ChartExplorer.d.ts +36 -1
  83. package/dist/types/content/ChartFilterControls.d.ts +6 -1
  84. package/dist/types/content/DataTable.d.ts +5 -0
  85. package/dist/types/content/calendar-day-scroll.d.ts +42 -0
  86. package/dist/types/content/calendar-days.d.ts +192 -0
  87. package/dist/types/content/calendar-dialogs.d.ts +22 -0
  88. package/dist/types/content/calendar-messages.d.ts +99 -0
  89. package/dist/types/content/calendar-pointer.d.ts +9 -0
  90. package/dist/types/content/calendar-shared.d.ts +69 -0
  91. package/dist/types/content/calendar-time-view.d.ts +252 -0
  92. package/dist/types/content/chart-messages.d.ts +5 -0
  93. package/dist/types/content/index.d.ts +2 -2
  94. package/dist/types/layout/AppWorkspace.d.ts +25 -3
  95. package/dist/types/layout/PageTitle.d.ts +2 -1
  96. package/dist/types/layout/app-workspace-controller.d.ts +9 -1
  97. package/dist/types/surfaces/StatCell.d.ts +5 -0
  98. package/package.json +1 -1
@@ -0,0 +1,1187 @@
1
+ import { template as _$template } from "solid-js/web";
2
+ import { delegateEvents as _$delegateEvents } from "solid-js/web";
3
+ import { className as _$className } from "solid-js/web";
4
+ import { memo as _$memo } from "solid-js/web";
5
+ import { setStyleProperty as _$setStyleProperty } from "solid-js/web";
6
+ import { addEventListener as _$addEventListener } from "solid-js/web";
7
+ import { effect as _$effect } from "solid-js/web";
8
+ import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
9
+ import { getNextMarker as _$getNextMarker } from "solid-js/web";
10
+ import { getNextElement as _$getNextElement } from "solid-js/web";
11
+ import { insert as _$insert } from "solid-js/web";
12
+ import { createComponent as _$createComponent } from "solid-js/web";
13
+ import { setAttribute as _$setAttribute } from "solid-js/web";
14
+ import { use as _$use } from "solid-js/web";
15
+ var _tmpl$ = /*#__PURE__*/_$template(`<p class=k2b-calendar-days__more>`),
16
+ _tmpl$2 = /*#__PURE__*/_$template(`<div class=k2b-calendar-days data-view=day><div class=k2b-calendar-days__scroll tabindex=-1><div class=k2b-calendar-days__track><!$><!/><!$><!/></div></div><p class=k2b-calendar-sr></p><!$><!/>`),
17
+ _tmpl$3 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__today>`),
18
+ _tmpl$4 = /*#__PURE__*/_$template(`<i class="ti ti-clock"aria-hidden=true>`),
19
+ _tmpl$5 = /*#__PURE__*/_$template(`<span>`),
20
+ _tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-calendar-days__all-day role=group>`),
21
+ _tmpl$7 = /*#__PURE__*/_$template(`<span class=k2b-calendar-night aria-hidden=true>`),
22
+ _tmpl$8 = /*#__PURE__*/_$template(`<button type=button class=k2b-calendar-night__bar aria-expanded=true><i class="ti ti-moon"aria-hidden=true></i><span></span><span class=k2b-calendar-night__action><!$><!/><i class="ti ti-chevron-up"aria-hidden=true>`),
23
+ _tmpl$9 = /*#__PURE__*/_$template(`<div class=k2b-calendar-now aria-hidden=true><span class=k2b-calendar-now__time>`),
24
+ _tmpl$0 = /*#__PURE__*/_$template(`<section class=k2b-calendar-days__day data-calendar-group><header class=k2b-calendar-days__head><h2 class=k2b-calendar-days__title><button type=button class=k2b-calendar-days__title-button><!$><!/><span class=k2b-calendar-days__long></span><span class=k2b-calendar-days__short></span></button></h2><span class=k2b-calendar-days__note><span class=k2b-calendar-days__soon></span><span class=k2b-calendar-days__cheer aria-hidden=true><i class="ti ti-confetti"aria-hidden=true></i><!$><!/></span></span><!$><!/><span class=k2b-calendar-days__summary></span></header><!$><!/><div class=k2b-calendar-days__body><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/>`),
25
+ _tmpl$1 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__badge><!$><!/><!$><!/>`),
26
+ _tmpl$10 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
27
+ _tmpl$11 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__line aria-hidden=true>`),
28
+ _tmpl$12 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__hour aria-hidden=true>`),
29
+ _tmpl$13 = /*#__PURE__*/_$template(`<ul class=k2b-calendar-fold__chips>`),
30
+ _tmpl$14 = /*#__PURE__*/_$template(`<div class=k2b-calendar-fold><button type=button class=k2b-calendar-fold__toggle aria-expanded=false><i class="ti ti-moon"aria-hidden=true></i><span></span><i class="ti ti-chevron-down"aria-hidden=true></i></button><!$><!/>`),
31
+ _tmpl$15 = /*#__PURE__*/_$template(`<li><!$><!/><!$><!/>`),
32
+ _tmpl$16 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__hour data-night=true aria-hidden=true>`),
33
+ _tmpl$17 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__midnight aria-hidden=true>`),
34
+ _tmpl$18 = /*#__PURE__*/_$template(`<span class=k2b-calendar-hover aria-hidden=true>`),
35
+ _tmpl$19 = /*#__PURE__*/_$template(`<section class=k2b-calendar-days__day data-calendar-group data-empty=true><header class=k2b-calendar-days__head><h2 class=k2b-calendar-days__title><span class=k2b-calendar-days__run></span></h2><span class=k2b-calendar-days__note></span><!$><!/><span class=k2b-calendar-days__summary></span></header><button type=button class=k2b-calendar-days__empty data-calendar-unfold><span></span><span class=k2b-calendar-days__empty-action><i class="ti ti-arrows-vertical"aria-hidden=true></i><!$><!/>`),
36
+ _tmpl$20 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__badge-day>`),
37
+ _tmpl$21 = /*#__PURE__*/_$template(`<span class=k2b-calendar-days__badge data-run=true><!$><!/><!$><!/><!$><!/>`);
38
+ import { createComputed, createEffect, createMemo, createSignal, createUniqueId, For, on, onCleanup, onMount, Show, untrack } from "solid-js";
39
+ import { brakedScroll, GESTURE_GAP_MS, SETTLE_RADIUS, settleTarget, stopCrossing, stopIndexAt, wheelPixels } from "./calendar-day-scroll";
40
+ import { addDayKeys, DAY_MINUTES, dayGroups, dayHeightTerms, dayKeyRange, dayMinuteAt, dayY, dayYTerms, markerLanes, readDayGeometry, termsCss } from "./calendar-days";
41
+ import { EventChip, eventHref } from "./calendar-shared";
42
+ import { AllDayChips, createTimeView, dayBands, dayGaps, daySummary, eventAccent, foldedEntries, gapAside, isNearNow, longDay, markerAbove, nightHours, reducedMotion, shortDay, soonNote, TimeBand, TimeCheck, TimeGap, TimeMarker, TimeOverlays, TimeQuickCreate } from "./calendar-time-view";
43
+ const groupId = group => group.kind === "day" ? `d:${group.key}` : `e:${group.keys.join(",")}`;
44
+ const groupFirst = group => group.kind === "day" ? group.key : group.keys[0];
45
+
46
+ /**
47
+ * The day view with `dayHours`: the loaded days one below the other in a single scroll, each with its heading kept on
48
+ * top while it is in view. Runs of empty days fold into one row. The view slows down and settles at each day start,
49
+ * and a line at the top of the heading fills while a day start passes.
50
+ */
51
+ export const CalendarDayView = props => {
52
+ const view = createTimeView(props);
53
+ const [mounted, setMounted] = createSignal(false);
54
+ const [unfolded, setUnfolded] = createSignal(new Set());
55
+ const [topKey, setTopKey] = createSignal(untrack(view.anchorKey));
56
+ const [hover, setHover] = createSignal(null);
57
+ /** Where today's day lies from the view, kept current while scrolling for the Today button's arrow. */
58
+ const [todayPlace, setTodayPlace] = createSignal("");
59
+ let scroller;
60
+ let track;
61
+ const helpId = createUniqueId();
62
+
63
+ // The server and the first render start at the shown day, so the page never flashes the days before it; once
64
+ // mounted the earlier days join above it without moving the view.
65
+ const keys = createMemo(() => {
66
+ const {
67
+ first,
68
+ last
69
+ } = view.range();
70
+ const anchor = view.anchorKey();
71
+ const from = mounted() || anchor < first || anchor > last ? first : anchor;
72
+ return dayKeyRange(from, last);
73
+ });
74
+ // Today and the day the reader opened never fold, so a day opened from the month shows its hours to create in.
75
+ const groups = createMemo(() => dayGroups(keys(), key => view.dayOf(key).empty, new Set([view.nowKey(), view.anchorKey(), ...unfolded()])));
76
+ const unfold = keys => setUnfolded(value => new Set([...value, ...keys]));
77
+ const groupIds = createMemo(() => groups().map(groupId));
78
+ const groupsById = createMemo(() => new Map(groups().map(group => [groupId(group), group])));
79
+
80
+ // Where each group starts in the scroll, measured after every change of the groups and on resize.
81
+ let sections = [];
82
+ let tops = [];
83
+ const measure = () => {
84
+ if (!track) return;
85
+ sections = [...track.querySelectorAll(":scope > [data-calendar-group]")];
86
+ tops = sections.map(section => section.offsetTop);
87
+ };
88
+ const keysOf = section => (section?.dataset.calendarKeys ?? "").split(",").filter(Boolean);
89
+ const sectionOf = key => sections.find(section => keysOf(section).includes(key));
90
+
91
+ /** The group at the top of the view and how far into it the view is, kept across changes above it. */
92
+ let anchor = null;
93
+ /** A day the host moved to before its days loaded; it goes on screen once they arrive. */
94
+ let pendingTarget = null;
95
+ /** The last scroll position the view read, to tell the reader's direction. */
96
+ let lastScrollTop = 0;
97
+ const rememberAnchor = () => {
98
+ if (!scroller || sections.length === 0) return;
99
+ const index = stopIndexAt(tops, scroller.scrollTop);
100
+ const section = sections[index];
101
+ if (section) anchor = {
102
+ key: keysOf(section)[0],
103
+ delta: scroller.scrollTop - tops[index]
104
+ };
105
+ };
106
+ const restoreAnchor = () => {
107
+ if (!scroller || !anchor) return;
108
+ const saved = anchor;
109
+ let index = sections.findIndex(section => keysOf(section).includes(saved.key));
110
+ if (index < 0) index = sections.findIndex(section => keysOf(section)[0] >= saved.key);
111
+ if (index < 0) return;
112
+ const top = tops[index] + Math.min(saved.delta, sections[index].offsetHeight - 1);
113
+ if (Math.abs(scroller.scrollTop - top) > 0.5) scroller.scrollTop = top;
114
+ lastScrollTop = scroller.scrollTop;
115
+ };
116
+
117
+ /** The scroll position of a minute of a day, or of the day's start without a minute. */
118
+ const topFor = (key, minute) => {
119
+ const section = sectionOf(key);
120
+ if (!section) return null;
121
+ const index = sections.indexOf(section);
122
+ const body = section.querySelector("[data-calendar-body]");
123
+ if (minute === undefined || !body) return tops[index];
124
+ const geometry = readDayGeometry(body, view.wake(), body.dataset.expanded === "true");
125
+ return tops[index] + body.offsetTop + dayY(geometry, minute);
126
+ };
127
+
128
+ // Gliding: arrows, Today, and Go to scroll smoothly; the stops and loading wait until the glide arrived.
129
+ let glideTarget = null;
130
+ let glideTimer = 0;
131
+ const glide = top => {
132
+ if (!scroller) return;
133
+ const target = Math.round(Math.max(0, Math.min(top, scroller.scrollHeight - scroller.clientHeight)));
134
+ glideTarget = target;
135
+ window.clearTimeout(glideTimer);
136
+ glideTimer = window.setTimeout(() => {
137
+ glideTarget = null;
138
+ }, 1600);
139
+ // What the view keeps in place from now on is where the glide arrives, not where it started.
140
+ const index = stopIndexAt(tops, target);
141
+ const section = sections[index];
142
+ if (section) anchor = {
143
+ key: keysOf(section)[0],
144
+ delta: target - tops[index]
145
+ };
146
+ scroller.scrollTo({
147
+ top: target,
148
+ behavior: reducedMotion() ? "instant" : "smooth"
149
+ });
150
+ };
151
+
152
+ /** Puts a day on screen: now in the upper third today, else an hour before its first entry, else its start. */
153
+ const positionAt = key => {
154
+ if (!scroller) return;
155
+ measure();
156
+ if (key === view.nowKey()) {
157
+ const top = topFor(key, view.nowMinute());
158
+ // Now in the upper third, but never showing the end of the day before above the day's own heading.
159
+ if (top !== null) scroller.scrollTop = Math.max(topFor(key) ?? 0, top - scroller.clientHeight / 3);
160
+ lastScrollTop = scroller.scrollTop;
161
+ return;
162
+ }
163
+ const model = view.dayOf(key);
164
+ const first = Math.min(...model.bands.map(band => band.start), ...model.markers.map(marker => marker.minute), Number.POSITIVE_INFINITY);
165
+ const start = topFor(key);
166
+ if (start === null) return;
167
+ const entry = Number.isFinite(first) && first > 120 ? topFor(key, first - 60) : null;
168
+ scroller.scrollTop = entry === null ? start : Math.max(start, entry - 44);
169
+ lastScrollTop = scroller.scrollTop;
170
+ };
171
+
172
+ // Input: the wheel brakes at day starts; a resting scroll glides onto a near one.
173
+ let lastInput = "other";
174
+ let fingers = 0;
175
+ let settling = false;
176
+ let restTimer = 0;
177
+ let frame = 0;
178
+ let ready = false;
179
+ let carry = 0;
180
+ let lastWheel = 0;
181
+ const settle = () => {
182
+ if (!scroller || fingers > 0 || settling || glideTarget !== null || view.dragging()) return;
183
+ const target = settleTarget(tops.slice(1), scroller.scrollTop, lastInput === "touch" ? SETTLE_RADIUS.touch : SETTLE_RADIUS.wheel);
184
+ if (target === undefined) return;
185
+ settling = true;
186
+ scroller.scrollTo({
187
+ top: target,
188
+ behavior: reducedMotion() ? "instant" : "smooth"
189
+ });
190
+ window.setTimeout(() => {
191
+ settling = false;
192
+ }, 450);
193
+ };
194
+ const onWheel = event => {
195
+ if (!scroller || event.ctrlKey || Math.abs(event.deltaX) > Math.abs(event.deltaY) || view.dragging()) return;
196
+ const delta = wheelPixels(event.deltaY, event.deltaMode, scroller.clientHeight);
197
+ const top = scroller.scrollTop;
198
+ const max = scroller.scrollHeight - scroller.clientHeight;
199
+ // At the ends the wheel asks for more days instead.
200
+ if (delta > 0 && top >= max - 1 || delta < 0 && top <= 1) {
201
+ loadMore(delta > 0 ? "later" : "earlier");
202
+ return;
203
+ }
204
+ if (event.timeStamp - lastWheel > GESTURE_GAP_MS) carry = 0;
205
+ // A gesture that goes on takes over from a glide onto a day start; the view settles again once it rests.
206
+ settling = false;
207
+ lastWheel = event.timeStamp;
208
+ const next = brakedScroll(tops, top + carry, delta);
209
+ lastInput = "wheel";
210
+ if (next === undefined) {
211
+ carry = 0;
212
+ return;
213
+ }
214
+ event.preventDefault();
215
+ glideTarget = null;
216
+ const bounded = Math.max(0, Math.min(max, next));
217
+ scroller.scrollTop = bounded;
218
+ // Steps too small for a pixel add up instead of vanishing.
219
+ carry = bounded - scroller.scrollTop;
220
+ };
221
+
222
+ // Loading: each end asks once per range, and only after the view settled at its first position.
223
+ let askedEarlier = "";
224
+ let askedLater = "";
225
+ const loadMore = edge => {
226
+ // Days that come in above move the view, so they wait for a glide to arrive; days below move nothing.
227
+ if (!ready || view.dragging() || edge === "earlier" && glideTarget !== null) return;
228
+ const {
229
+ first,
230
+ last
231
+ } = view.range();
232
+ if (edge === "earlier" && props.owner.onLoadEarlier && askedEarlier !== first) {
233
+ askedEarlier = first;
234
+ void props.owner.onLoadEarlier();
235
+ }
236
+ if (edge === "later" && props.owner.onLoadLater && askedLater !== last) {
237
+ askedLater = last;
238
+ void props.owner.onLoadLater();
239
+ }
240
+ };
241
+ let reportTimer = 0;
242
+ let reported = "";
243
+ /** Tells the host the days the reader sees once they changed, after the scroll calmed down. */
244
+ const reportVisible = () => {
245
+ const {
246
+ first,
247
+ last
248
+ } = untrack(visibleKeys);
249
+ if (`${first}/${last}` === reported) return;
250
+ reported = `${first}/${last}`;
251
+ window.clearTimeout(reportTimer);
252
+ reportTimer = window.setTimeout(() => props.owner.onVisibleDateChange?.(view.parseKey(first), view.parseKey(last)), 250);
253
+ };
254
+ const updateChrome = () => {
255
+ if (!scroller) return;
256
+ const top = scroller.scrollTop;
257
+ const index = stopIndexAt(tops, top);
258
+ const key = keysOf(sections[index])[0];
259
+ if (key && key !== untrack(topKey)) setTopKey(key);
260
+ reportVisible();
261
+ for (const [position, section] of sections.entries()) {
262
+ const head = section.firstElementChild;
263
+ if (!head) continue;
264
+ const crossing = position > 0 ? stopCrossing(tops[position], top) : 0;
265
+ if (crossing > 0) head.style.setProperty("--k2b-calendar-cross", String(crossing));else if (head.style.getPropertyValue("--k2b-calendar-cross")) head.style.removeProperty("--k2b-calendar-cross");
266
+ }
267
+ setTodayPlace(placeOfToday());
268
+ // Only the reader's own scrolling asks for more: days that came in above push the view down, and runs of empty
269
+ // days are short, so asking whenever the view is near an end would load one empty week after the other.
270
+ const direction = Math.sign(top - lastScrollTop);
271
+ lastScrollTop = top;
272
+ if (direction > 0 && top + scroller.clientHeight > scroller.scrollHeight - 2 * scroller.clientHeight) loadMore("later");else if (direction < 0 && top < scroller.clientHeight) loadMore("earlier");
273
+ rememberAnchor();
274
+ };
275
+ const onScroll = () => {
276
+ if (!scroller) return;
277
+ if (glideTarget !== null && Math.abs(scroller.scrollTop - glideTarget) < 2) glideTarget = null;
278
+ if (!frame) frame = requestAnimationFrame(() => {
279
+ frame = 0;
280
+ updateChrome();
281
+ });
282
+ window.clearTimeout(restTimer);
283
+ restTimer = window.setTimeout(settle, lastInput === "touch" ? 90 : 160);
284
+ };
285
+ onMount(() => {
286
+ setMounted(true);
287
+ queueMicrotask(() => {
288
+ positionAt(view.anchorKey());
289
+ rememberAnchor();
290
+ ready = true;
291
+ updateChrome();
292
+ });
293
+ const observer = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(() => {
294
+ measure();
295
+ // A glide owns the scroll until it arrives; putting the view back meanwhile would stop it.
296
+ if (glideTarget === null) restoreAnchor();
297
+ });
298
+ if (track) observer?.observe(track);
299
+ onCleanup(() => {
300
+ observer?.disconnect();
301
+ window.clearTimeout(restTimer);
302
+ window.clearTimeout(reportTimer);
303
+ window.clearTimeout(glideTimer);
304
+ if (frame) cancelAnimationFrame(frame);
305
+ });
306
+ });
307
+ // Before new days or an unfolded run change the page, note where the reader is from the page as it stands: the
308
+ // place remembered in the last frame can be a scroll behind on a busy page. A computation runs before any render
309
+ // effect touches the page.
310
+ createComputed(on(() => [groupIds(), view.days()], () => {
311
+ if (!untrack(mounted)) return;
312
+ measure();
313
+ rememberAnchor();
314
+ }, {
315
+ defer: true
316
+ }));
317
+ // New days above or below, a folded night, or an unfolded run: keep what the reader looks at in place.
318
+ createEffect(on(() => [groupIds(), view.days()], () => {
319
+ if (!untrack(mounted)) return;
320
+ measure();
321
+ if (pendingTarget && loaded(pendingTarget)) {
322
+ positionAt(pendingTarget);
323
+ pendingTarget = null;
324
+ rememberAnchor();
325
+ } else restoreAnchor();
326
+ updateChrome();
327
+ }, {
328
+ defer: true
329
+ }));
330
+ // Another date from the host puts that day on screen.
331
+ createEffect(on(view.anchorKey, key => {
332
+ if (!untrack(mounted)) return;
333
+ pendingTarget = loaded(key) ? null : key;
334
+ if (pendingTarget) return;
335
+ if (key === untrack(visibleKeys).first) {
336
+ rememberAnchor();
337
+ return;
338
+ }
339
+ queueMicrotask(() => {
340
+ positionAt(key);
341
+ rememberAnchor();
342
+ updateChrome();
343
+ });
344
+ }, {
345
+ defer: true
346
+ }));
347
+
348
+ /** Whether today's day is above, below, or in the view. */
349
+ const placeOfToday = () => {
350
+ const key = view.nowKey();
351
+ if (!scroller) return "";
352
+ const section = sectionOf(key);
353
+ if (!section) return key < untrack(topKey) ? "up" : "down";
354
+ const index = sections.indexOf(section);
355
+ const top = scroller.scrollTop;
356
+ if (tops[index] + section.offsetHeight < top) return "up";
357
+ if (tops[index] > top + scroller.clientHeight) return "down";
358
+ return "";
359
+ };
360
+ const visibleKeys = () => {
361
+ const first = topKey();
362
+ if (!scroller || sections.length === 0) return {
363
+ first,
364
+ last: first
365
+ };
366
+ const bottom = scroller.scrollTop + scroller.clientHeight;
367
+ const index = stopIndexAt(tops, bottom - 1);
368
+ const keysAtBottom = keysOf(sections[index]);
369
+ return {
370
+ first,
371
+ last: keysAtBottom[keysAtBottom.length - 1] ?? first
372
+ };
373
+ };
374
+ const loaded = key => key >= view.range().first && key <= view.range().last;
375
+ const goTo = key => {
376
+ if (!loaded(key) || !scroller) return false;
377
+ // A day inside a run of empty days opens on its own, so the view goes to that day and not to the run.
378
+ if (untrack(groups).some(group => group.kind === "empty" && group.keys.includes(key))) unfold([key]);
379
+ measure();
380
+ const top = topFor(key);
381
+ if (top === null) return false;
382
+ glide(top);
383
+ return true;
384
+ };
385
+ const handle = {
386
+ visibleKeys,
387
+ step: direction => {
388
+ if (!scroller) return false;
389
+ measure();
390
+ const top = scroller.scrollTop;
391
+ const index = stopIndexAt(tops, top);
392
+ const target = direction > 0 ? tops[index + 1] : top - tops[index] > 8 ? tops[index] : tops[index - 1];
393
+ if (target === undefined) return false;
394
+ glide(target);
395
+ return true;
396
+ },
397
+ goTo,
398
+ today: () => {
399
+ const key = view.nowKey();
400
+ if (!loaded(key) || !scroller) return false;
401
+ measure();
402
+ const top = topFor(key, view.nowMinute());
403
+ if (top === null) return false;
404
+ glide(Math.max(topFor(key) ?? 0, top - scroller.clientHeight / 3));
405
+ return true;
406
+ },
407
+ todayDirection: () => {
408
+ const key = view.nowKey();
409
+ const {
410
+ first,
411
+ last
412
+ } = view.range();
413
+ if (key < first) return "up";
414
+ if (key > last) return "down";
415
+ return todayPlace();
416
+ },
417
+ controller: {
418
+ quickCreate: create => {
419
+ const target = view.createTarget(visibleKeys());
420
+ const body = scroller?.querySelector(`[data-calendar-body="${target.key}"]`);
421
+ view.openQuickCreate(target.key, target.start, target.end, anchorFor(target.key, target.start, target.end) ?? body ?? scroller, create);
422
+ },
423
+ createTarget: () => {
424
+ const target = view.createTarget(visibleKeys());
425
+ return view.rangeOfSelection(target);
426
+ },
427
+ dragIn: (event, item, onDrop) => view.dragIn(event, item, onDrop, scroller)
428
+ }
429
+ };
430
+ /** The place of a slot on screen for the quick create, when it is in view. */
431
+ const anchorFor = (key, start, end) => {
432
+ const body = scroller?.querySelector(`[data-calendar-body="${key}"]`);
433
+ if (!body || !scroller) return null;
434
+ const rect = body.getBoundingClientRect();
435
+ const bounds = scroller.getBoundingClientRect();
436
+ const geometry = readDayGeometry(body, view.wake(), body.dataset.expanded === "true");
437
+ const top = rect.top + dayY(geometry, start);
438
+ const bottom = rect.top + dayY(geometry, end);
439
+ if (bottom < bounds.top + 40 || top > bounds.bottom - 20) return null;
440
+ const left = rect.left + 56;
441
+ const clampedTop = Math.max(bounds.top, top);
442
+ return new DOMRect(left, clampedTop, Math.min(rect.right - left, 320), Math.max(8, Math.min(bottom, bounds.bottom) - clampedTop));
443
+ };
444
+ onMount(() => props.register(handle));
445
+ onCleanup(() => props.register(null));
446
+
447
+ /** Tab into the stream lands on the first stop on screen, not on the first loaded day weeks above. */
448
+ let tabbedAt = -1e9;
449
+ onMount(() => {
450
+ const note = event => {
451
+ if (event.key === "Tab") {
452
+ tabbedAt = performance.now();
453
+ if (scroller) restingTop = scroller.scrollTop;
454
+ }
455
+ };
456
+ window.addEventListener("keydown", note, true);
457
+ onCleanup(() => window.removeEventListener("keydown", note, true));
458
+ });
459
+ let restingTop = 0;
460
+ const onFocusIn = event => {
461
+ if (!scroller) return;
462
+ const from = event.relatedTarget instanceof Node ? event.relatedTarget : null;
463
+ if (performance.now() - tabbedAt > 400 || from && scroller.contains(from)) {
464
+ restingTop = scroller.scrollTop;
465
+ return;
466
+ }
467
+ // Undo the scroll to the focused stop, which some engines make before this runs and some after; a stop on screen
468
+ // keeps the focus.
469
+ if (Math.abs(scroller.scrollTop - restingTop) >= 1) scroller.scrollTop = restingTop;
470
+ const bounds = scroller.getBoundingClientRect();
471
+ const visible = element => {
472
+ const rect = element.getBoundingClientRect();
473
+ return rect.height > 0 && rect.top >= bounds.top - 1 && rect.bottom <= bounds.bottom + 1;
474
+ };
475
+ if (event.target instanceof Element && visible(event.target)) return;
476
+ const stops = [...scroller.querySelectorAll("a[href],button:not([tabindex='-1'])")].filter(visible);
477
+ const back = Boolean(from && scroller.compareDocumentPosition(from) & Node.DOCUMENT_POSITION_FOLLOWING);
478
+ (back ? stops[stops.length - 1] : stops[0])?.focus({
479
+ preventScroll: true
480
+ });
481
+ };
482
+ return (() => {
483
+ var _el$ = _$getNextElement(_tmpl$2),
484
+ _el$2 = _el$.firstChild,
485
+ _el$3 = _el$2.firstChild,
486
+ _el$5 = _el$3.firstChild,
487
+ [_el$6, _co$] = _$getNextMarker(_el$5.nextSibling),
488
+ _el$7 = _el$6.nextSibling,
489
+ [_el$8, _co$2] = _$getNextMarker(_el$7.nextSibling),
490
+ _el$9 = _el$2.nextSibling,
491
+ _el$0 = _el$9.nextSibling,
492
+ [_el$1, _co$3] = _$getNextMarker(_el$0.nextSibling);
493
+ _el$2.$$focusin = onFocusIn;
494
+ _el$2.addEventListener("touchcancel", event => {
495
+ fingers = event.touches.length;
496
+ });
497
+ _el$2.$$touchend = event => {
498
+ fingers = event.touches.length;
499
+ };
500
+ _el$2.$$touchstart = event => {
501
+ fingers = event.touches.length;
502
+ lastInput = "touch";
503
+ glideTarget = null;
504
+ };
505
+ _el$2.addEventListener("wheel", onWheel);
506
+ _el$2.addEventListener("scroll", onScroll);
507
+ var _ref$ = scroller;
508
+ typeof _ref$ === "function" ? _$use(_ref$, _el$2) : scroller = _el$2;
509
+ _$setAttribute(_el$2, "aria-describedby", helpId);
510
+ var _ref$2 = track;
511
+ typeof _ref$2 === "function" ? _$use(_ref$2, _el$3) : track = _el$3;
512
+ _$insert(_el$3, _$createComponent(For, {
513
+ get each() {
514
+ return groupIds();
515
+ },
516
+ children: id => {
517
+ const group = () => groupsById().get(id);
518
+ return _$createComponent(Show, {
519
+ get when() {
520
+ return group();
521
+ },
522
+ children: current => current().kind === "day" ? _$createComponent(DaySection, {
523
+ view: view,
524
+ get dayKey() {
525
+ return groupFirst(current());
526
+ },
527
+ hover: hover,
528
+ setHover: setHover,
529
+ scroller: () => scroller
530
+ }) : _$createComponent(EmptyRun, {
531
+ view: view,
532
+ get keys() {
533
+ return current().keys;
534
+ },
535
+ onUnfold: unfold
536
+ })
537
+ });
538
+ }
539
+ }), _el$6, _co$);
540
+ _$insert(_el$3, _$createComponent(Show, {
541
+ get when() {
542
+ return props.owner.onLoadLater;
543
+ },
544
+ get children() {
545
+ var _el$4 = _$getNextElement(_tmpl$);
546
+ _$insert(_el$4, () => view.messages().calendarMoreDays);
547
+ return _el$4;
548
+ }
549
+ }), _el$8, _co$2);
550
+ _$setAttribute(_el$9, "id", helpId);
551
+ _$insert(_el$9, () => view.messages().calendarDayKeyboardHelp);
552
+ _$insert(_el$, _$createComponent(TimeQuickCreate, {
553
+ view: view
554
+ }), _el$1, _co$3);
555
+ _$effect(() => _$setAttribute(_el$, "data-dragging", view.dragging() || undefined));
556
+ _$runHydrationEvents();
557
+ return _el$;
558
+ })();
559
+ };
560
+ const DaySection = props => {
561
+ const view = props.view;
562
+ const model = createMemo(() => view.dayOf(props.dayKey));
563
+ const expanded = () => view.nightOpen(props.dayKey, model());
564
+ const headingId = createUniqueId();
565
+ const badge = () => view.props.owner.dayBadges?.[props.dayKey];
566
+ const today = () => props.dayKey === view.calendarToday();
567
+ const selectedDay = () => {
568
+ const current = view.selection();
569
+ return Boolean(current && current.key === props.dayKey && current.start === undefined);
570
+ };
571
+ const soon = () => soonNote(view, props.dayKey);
572
+ const wake = () => view.wake();
573
+ const nowMinute = () => props.dayKey === view.nowKey() ? view.nowMinute() : null;
574
+ const bands = createMemo(() => dayBands(view, props.dayKey, expanded()));
575
+ const gaps = createMemo(() => dayGaps(view, props.dayKey));
576
+ const markers = () => model().markers.filter(marker => marker.minute < (expanded() ? DAY_MINUTES : wake()));
577
+ /** Deadlines whose pills would cover each other share the width; keyed by marker, so rows keep their elements. */
578
+ const lanes = createMemo(() => new Map(markerLanes(markers(), wake()).map(entry => [entry.item, entry])));
579
+ const folded = () => expanded() ? [] : foldedEntries(view, props.dayKey);
580
+ const nightLabel = () => view.messages().calendarNight({
581
+ from: shortDay(view, props.dayKey),
582
+ to: shortDay(view, addDayKeys(props.dayKey, 1))
583
+ });
584
+ const foldLabel = () => view.messages().calendarNightHours({
585
+ from: view.clock(wake()).slice(0, 2),
586
+ to: view.clock(DAY_MINUTES).slice(0, 2)
587
+ });
588
+
589
+ // Gaps, bands, and markers in one time order, so Tab runs through the day as it reads. Unchanged rows keep their
590
+ // elements and focus when the clock updates the gaps.
591
+ const timeline = createMemo(previous => [...gaps().map(gap => previous.find(row => row.kind === "gap" && row.gap.start === gap.start && row.gap.end === gap.end && row.gap.past === gap.past) ?? {
592
+ at: gap.start,
593
+ kind: "gap",
594
+ gap
595
+ }), ...bands().map(band => previous.find(row => row.kind === "band" && row.band === band) ?? {
596
+ at: Math.max(0, band.start),
597
+ kind: "band",
598
+ band
599
+ }), ...markers().map(marker => previous.find(row => row.kind === "marker" && row.marker === marker) ?? {
600
+ at: marker.minute,
601
+ kind: "marker",
602
+ marker
603
+ })].sort((left, right) => left.at - right.at), []);
604
+ const isEmptyTarget = target => target instanceof Element && !target.closest("a,button,[data-calendar-event],.k2b-calendar-band,.k2b-calendar-marker,.k2b-calendar-draft,.k2b-calendar-fold");
605
+ const minuteAt = (element, clientY) => {
606
+ const geometry = readDayGeometry(element, wake(), expanded());
607
+ const rect = element.getBoundingClientRect();
608
+ return Math.max(0, Math.min((expanded() ? DAY_MINUTES : wake()) - 15, dayMinuteAt(geometry, clientY - rect.top)));
609
+ };
610
+ let lastPointer = "mouse";
611
+ return (() => {
612
+ var _el$10 = _$getNextElement(_tmpl$0),
613
+ _el$11 = _el$10.firstChild,
614
+ _el$12 = _el$11.firstChild,
615
+ _el$13 = _el$12.firstChild,
616
+ _el$17 = _el$13.firstChild,
617
+ [_el$18, _co$4] = _$getNextMarker(_el$17.nextSibling),
618
+ _el$15 = _el$18.nextSibling,
619
+ _el$16 = _el$15.nextSibling,
620
+ _el$19 = _el$12.nextSibling,
621
+ _el$20 = _el$19.firstChild,
622
+ _el$23 = _el$20.nextSibling,
623
+ _el$24 = _el$23.firstChild,
624
+ _el$25 = _el$24.nextSibling,
625
+ [_el$26, _co$5] = _$getNextMarker(_el$25.nextSibling),
626
+ _el$28 = _el$19.nextSibling,
627
+ [_el$29, _co$6] = _$getNextMarker(_el$28.nextSibling),
628
+ _el$27 = _el$29.nextSibling,
629
+ _el$54 = _el$11.nextSibling,
630
+ [_el$55, _co$12] = _$getNextMarker(_el$54.nextSibling),
631
+ _el$31 = _el$55.nextSibling,
632
+ _el$42 = _el$31.firstChild,
633
+ [_el$43, _co$8] = _$getNextMarker(_el$42.nextSibling),
634
+ _el$44 = _el$43.nextSibling,
635
+ [_el$45, _co$9] = _$getNextMarker(_el$44.nextSibling),
636
+ _el$46 = _el$45.nextSibling,
637
+ [_el$47, _co$0] = _$getNextMarker(_el$46.nextSibling),
638
+ _el$48 = _el$47.nextSibling,
639
+ [_el$49, _co$1] = _$getNextMarker(_el$48.nextSibling),
640
+ _el$50 = _el$49.nextSibling,
641
+ [_el$51, _co$10] = _$getNextMarker(_el$50.nextSibling),
642
+ _el$52 = _el$51.nextSibling,
643
+ [_el$53, _co$11] = _$getNextMarker(_el$52.nextSibling);
644
+ _$setAttribute(_el$10, "aria-labelledby", headingId);
645
+ _$setAttribute(_el$12, "id", headingId);
646
+ _el$13.$$click = () => {
647
+ view.setTouchDraft(null);
648
+ view.setSelection(selectedDay() ? null : {
649
+ key: props.dayKey
650
+ });
651
+ };
652
+ _$insert(_el$13, _$createComponent(Show, {
653
+ get when() {
654
+ return today();
655
+ },
656
+ get children() {
657
+ var _el$14 = _$getNextElement(_tmpl$3);
658
+ _$insert(_el$14, () => view.props.labels.today);
659
+ return _el$14;
660
+ }
661
+ }), _el$18, _co$4);
662
+ _$insert(_el$15, () => longDay(view, props.dayKey));
663
+ _$insert(_el$16, () => shortDay(view, props.dayKey, true));
664
+ _$insert(_el$20, _$createComponent(Show, {
665
+ get when() {
666
+ return soon();
667
+ },
668
+ get children() {
669
+ return [_$getNextElement(_tmpl$4), (() => {
670
+ var _el$22 = _$getNextElement(_tmpl$5);
671
+ _$insert(_el$22, soon);
672
+ return _el$22;
673
+ })()];
674
+ }
675
+ }));
676
+ _$insert(_el$23, () => view.messages().calendarAllDone, _el$26, _co$5);
677
+ _$insert(_el$11, _$createComponent(Show, {
678
+ get when() {
679
+ return badge();
680
+ },
681
+ children: current => (() => {
682
+ var _el$56 = _$getNextElement(_tmpl$1),
683
+ _el$57 = _el$56.firstChild,
684
+ [_el$58, _co$13] = _$getNextMarker(_el$57.nextSibling),
685
+ _el$59 = _el$58.nextSibling,
686
+ [_el$60, _co$14] = _$getNextMarker(_el$59.nextSibling);
687
+ _$insert(_el$56, _$createComponent(Show, {
688
+ get when() {
689
+ return current().icon;
690
+ },
691
+ children: icon => (() => {
692
+ var _el$61 = _$getNextElement(_tmpl$10);
693
+ _$effect(() => _$className(_el$61, `ti ti-${icon()}`));
694
+ return _el$61;
695
+ })()
696
+ }), _el$58, _co$13);
697
+ _$insert(_el$56, () => current().label, _el$60, _co$14);
698
+ return _el$56;
699
+ })()
700
+ }), _el$29, _co$6);
701
+ _$insert(_el$27, () => daySummary(view, props.dayKey));
702
+ _$insert(_el$10, _$createComponent(Show, {
703
+ get when() {
704
+ return model().spans.length > 0;
705
+ },
706
+ get children() {
707
+ var _el$30 = _$getNextElement(_tmpl$6);
708
+ _$insert(_el$30, _$createComponent(AllDayChips, {
709
+ view: view,
710
+ get dayKey() {
711
+ return props.dayKey;
712
+ },
713
+ get spans() {
714
+ return model().spans;
715
+ }
716
+ }));
717
+ _$effect(() => _$setAttribute(_el$30, "aria-label", view.messages().calendarAllDayAndDue));
718
+ return _el$30;
719
+ }
720
+ }), _el$55, _co$12);
721
+ _el$31.addEventListener("pointerleave", () => {
722
+ if (props.hover()?.key === props.dayKey) props.setHover(null);
723
+ });
724
+ _el$31.$$pointermove = event => {
725
+ if (event.pointerType !== "mouse" || view.dragging() || !isEmptyTarget(event.target)) {
726
+ if (props.hover()?.key === props.dayKey) props.setHover(null);
727
+ return;
728
+ }
729
+ const minute = Math.floor(minuteAt(event.currentTarget, event.clientY) / 15) * 15;
730
+ props.setHover({
731
+ key: props.dayKey,
732
+ minute
733
+ });
734
+ };
735
+ _el$31.$$dblclick = event => {
736
+ if (!isEmptyTarget(event.target) || lastPointer !== "mouse") return;
737
+ const minute = Math.floor(minuteAt(event.currentTarget, event.clientY) / 30) * 30;
738
+ view.openQuickCreate(props.dayKey, minute, Math.min(minute + 60, expanded() ? DAY_MINUTES : wake()), event.currentTarget);
739
+ };
740
+ _$addEventListener(_el$31, "click", event => {
741
+ if (!isEmptyTarget(event.target) || !view.canCreate()) return;
742
+ const minute = Math.floor(minuteAt(event.currentTarget, event.clientY) / 30) * 30;
743
+ const end = Math.min(minute + 60, expanded() ? DAY_MINUTES : wake());
744
+ if (lastPointer === "mouse") {
745
+ view.setTouchDraft(null);
746
+ view.setSelection({
747
+ key: props.dayKey,
748
+ start: minute,
749
+ end
750
+ });
751
+ return;
752
+ }
753
+ view.setTouchDraft({
754
+ key: props.dayKey,
755
+ start: minute,
756
+ end
757
+ });
758
+ view.setSelection({
759
+ key: props.dayKey,
760
+ start: minute,
761
+ end
762
+ });
763
+ });
764
+ _el$31.$$touchstart = () => {
765
+ lastPointer = "touch";
766
+ };
767
+ _el$31.$$pointerdown = event => {
768
+ lastPointer = event.pointerType;
769
+ if (event.button !== 0 || !isEmptyTarget(event.target)) return;
770
+ view.startDraw(event, props.dayKey, props.scroller());
771
+ };
772
+ _$use(element => view.registerBody(props.dayKey, element, expanded), _el$31);
773
+ _$insert(_el$31, _$createComponent(For, {
774
+ get each() {
775
+ return Array.from({
776
+ length: wake() / 60 + 1
777
+ }, (_, index) => index * 60);
778
+ },
779
+ children: minute => [(() => {
780
+ var _el$62 = _$getNextElement(_tmpl$11);
781
+ _$effect(_$p => _$setStyleProperty(_el$62, "top", termsCss(dayYTerms(wake(), expanded(), minute))));
782
+ return _el$62;
783
+ })(), (() => {
784
+ var _el$63 = _$getNextElement(_tmpl$12);
785
+ _$insert(_el$63, () => view.clock(minute));
786
+ _$effect(_p$ => {
787
+ var _v$10 = isNearNow(view, props.dayKey, minute) ? "true" : undefined,
788
+ _v$11 = termsCss(dayYTerms(wake(), expanded(), minute));
789
+ _v$10 !== _p$.e && _$setAttribute(_el$63, "data-near-now", _p$.e = _v$10);
790
+ _v$11 !== _p$.t && _$setStyleProperty(_el$63, "top", _p$.t = _v$11);
791
+ return _p$;
792
+ }, {
793
+ e: undefined,
794
+ t: undefined
795
+ });
796
+ return _el$63;
797
+ })()]
798
+ }), _el$43, _co$8);
799
+ _$insert(_el$31, _$createComponent(Show, {
800
+ get when() {
801
+ return expanded();
802
+ },
803
+ get fallback() {
804
+ return (() => {
805
+ var _el$64 = _$getNextElement(_tmpl$14),
806
+ _el$65 = _el$64.firstChild,
807
+ _el$66 = _el$65.firstChild,
808
+ _el$67 = _el$66.nextSibling,
809
+ _el$69 = _el$65.nextSibling,
810
+ [_el$70, _co$15] = _$getNextMarker(_el$69.nextSibling);
811
+ _el$65.$$click = () => view.setNight(props.dayKey, true);
812
+ _$insert(_el$67, foldLabel);
813
+ _$insert(_el$64, _$createComponent(Show, {
814
+ get when() {
815
+ return folded().length > 0;
816
+ },
817
+ get children() {
818
+ var _el$68 = _$getNextElement(_tmpl$13);
819
+ _$insert(_el$68, _$createComponent(For, {
820
+ get each() {
821
+ return folded();
822
+ },
823
+ children: entry => {
824
+ const checked = () => view.checkedOf(entry.event);
825
+ return (() => {
826
+ var _el$71 = _$getNextElement(_tmpl$15),
827
+ _el$72 = _el$71.firstChild,
828
+ [_el$73, _co$16] = _$getNextMarker(_el$72.nextSibling),
829
+ _el$74 = _el$73.nextSibling,
830
+ [_el$75, _co$17] = _$getNextMarker(_el$74.nextSibling);
831
+ _$insert(_el$71, _$createComponent(Show, {
832
+ get when() {
833
+ return checked() !== undefined;
834
+ },
835
+ get children() {
836
+ return _$createComponent(TimeCheck, {
837
+ view: view,
838
+ get event() {
839
+ return entry.event;
840
+ }
841
+ });
842
+ }
843
+ }), _el$73, _co$16);
844
+ _$insert(_el$71, _$createComponent(EventChip, {
845
+ get event() {
846
+ return view.normalized(entry.event, props.dayKey);
847
+ },
848
+ get owner() {
849
+ return view.props.owner;
850
+ },
851
+ get href() {
852
+ return eventHref(view.props.owner, entry.event);
853
+ },
854
+ compact: true,
855
+ timeline: true,
856
+ get leadingTime() {
857
+ return entry.time;
858
+ },
859
+ get checkbox() {
860
+ return checked() !== undefined;
861
+ },
862
+ get onCheck() {
863
+ return view.checkOf(entry.event);
864
+ }
865
+ }), _el$75, _co$17);
866
+ _$effect(_p$ => {
867
+ var _v$14 = checked() !== undefined ? "true" : undefined,
868
+ _v$15 = checked() ? "true" : undefined,
869
+ _v$16 = eventAccent(entry.event);
870
+ _v$14 !== _p$.e && _$setAttribute(_el$71, "data-checkbox", _p$.e = _v$14);
871
+ _v$15 !== _p$.t && _$setAttribute(_el$71, "data-checked", _p$.t = _v$15);
872
+ _v$16 !== _p$.a && _$setStyleProperty(_el$71, "--k2b-calendar-accent", _p$.a = _v$16);
873
+ return _p$;
874
+ }, {
875
+ e: undefined,
876
+ t: undefined,
877
+ a: undefined
878
+ });
879
+ return _el$71;
880
+ })();
881
+ }
882
+ }));
883
+ return _el$68;
884
+ }
885
+ }), _el$70, _co$15);
886
+ _$effect(_p$ => {
887
+ var _v$12 = `calc(${termsCss(dayYTerms(wake(), false, wake()))} + 3px)`,
888
+ _v$13 = view.messages().calendarOpenNight;
889
+ _v$12 !== _p$.e && _$setStyleProperty(_el$64, "top", _p$.e = _v$12);
890
+ _v$13 !== _p$.t && _$setAttribute(_el$65, "aria-label", _p$.t = _v$13);
891
+ return _p$;
892
+ }, {
893
+ e: undefined,
894
+ t: undefined
895
+ });
896
+ _$runHydrationEvents();
897
+ return _el$64;
898
+ })();
899
+ },
900
+ get children() {
901
+ return [(() => {
902
+ var _el$32 = _$getNextElement(_tmpl$7);
903
+ _$effect(_p$ => {
904
+ var _v$ = termsCss(dayYTerms(wake(), true, wake())),
905
+ _v$2 = termsCss(dayHeightTermsNight(wake()));
906
+ _v$ !== _p$.e && _$setStyleProperty(_el$32, "top", _p$.e = _v$);
907
+ _v$2 !== _p$.t && _$setStyleProperty(_el$32, "height", _p$.t = _v$2);
908
+ return _p$;
909
+ }, {
910
+ e: undefined,
911
+ t: undefined
912
+ });
913
+ return _el$32;
914
+ })(), (() => {
915
+ var _el$33 = _$getNextElement(_tmpl$8),
916
+ _el$34 = _el$33.firstChild,
917
+ _el$35 = _el$34.nextSibling,
918
+ _el$36 = _el$35.nextSibling,
919
+ _el$38 = _el$36.firstChild,
920
+ [_el$39, _co$7] = _$getNextMarker(_el$38.nextSibling),
921
+ _el$37 = _el$39.nextSibling;
922
+ _el$33.$$click = () => view.setNight(props.dayKey, false);
923
+ _$insert(_el$35, nightLabel);
924
+ _$insert(_el$36, () => view.messages().calendarFoldNight, _el$39, _co$7);
925
+ _$effect(_$p => _$setStyleProperty(_el$33, "top", termsCss(dayYTerms(wake(), true, wake()))));
926
+ _$runHydrationEvents();
927
+ return _el$33;
928
+ })(), _$createComponent(For, {
929
+ get each() {
930
+ return nightHours(wake());
931
+ },
932
+ children: minute => [(() => {
933
+ var _el$76 = _$getNextElement(_tmpl$11);
934
+ _$effect(_p$ => {
935
+ var _v$17 = view.clock(minute) === "00:00" ? "true" : undefined,
936
+ _v$18 = termsCss(dayYTerms(wake(), true, minute));
937
+ _v$17 !== _p$.e && _$setAttribute(_el$76, "data-midnight", _p$.e = _v$17);
938
+ _v$18 !== _p$.t && _$setStyleProperty(_el$76, "top", _p$.t = _v$18);
939
+ return _p$;
940
+ }, {
941
+ e: undefined,
942
+ t: undefined
943
+ });
944
+ return _el$76;
945
+ })(), (() => {
946
+ var _el$77 = _$getNextElement(_tmpl$16);
947
+ _$insert(_el$77, () => view.clock(minute));
948
+ _$effect(_$p => _$setStyleProperty(_el$77, "top", termsCss(dayYTerms(wake(), true, minute))));
949
+ return _el$77;
950
+ })(), _$createComponent(Show, {
951
+ get when() {
952
+ return view.clock(minute) === "00:00";
953
+ },
954
+ get children() {
955
+ var _el$78 = _$getNextElement(_tmpl$17);
956
+ _$insert(_el$78, () => shortDay(view, addDayKeys(props.dayKey, 1), true));
957
+ _$effect(_$p => _$setStyleProperty(_el$78, "top", termsCss(dayYTerms(wake(), true, minute))));
958
+ return _el$78;
959
+ }
960
+ })]
961
+ })];
962
+ }
963
+ }), _el$45, _co$9);
964
+ _$insert(_el$31, _$createComponent(For, {
965
+ get each() {
966
+ return timeline();
967
+ },
968
+ children: entry => entry.kind === "gap" ? _$createComponent(TimeGap, {
969
+ view: view,
970
+ get gap() {
971
+ return entry.gap;
972
+ },
973
+ get dayKey() {
974
+ return props.dayKey;
975
+ },
976
+ get expanded() {
977
+ return expanded();
978
+ },
979
+ get aside() {
980
+ return gapAside(model(), entry.gap);
981
+ }
982
+ }) : entry.kind === "band" ? _$createComponent(TimeBand, {
983
+ view: view,
984
+ get band() {
985
+ return entry.band;
986
+ },
987
+ get dayKey() {
988
+ return props.dayKey;
989
+ },
990
+ get expanded() {
991
+ return expanded();
992
+ },
993
+ showLocation: true,
994
+ hourPx: 56,
995
+ get scroller() {
996
+ return props.scroller;
997
+ }
998
+ }) : _$createComponent(TimeMarker, {
999
+ view: view,
1000
+ get event() {
1001
+ return entry.marker.item;
1002
+ },
1003
+ get minute() {
1004
+ return entry.marker.minute;
1005
+ },
1006
+ get dayKey() {
1007
+ return props.dayKey;
1008
+ },
1009
+ get expanded() {
1010
+ return expanded();
1011
+ },
1012
+ get above() {
1013
+ return markerAbove(model(), entry.marker.minute);
1014
+ },
1015
+ get lane() {
1016
+ return lanes().get(entry.marker)?.lane ?? 0;
1017
+ },
1018
+ get lanes() {
1019
+ return lanes().get(entry.marker)?.lanes ?? 1;
1020
+ },
1021
+ showTime: true,
1022
+ get scroller() {
1023
+ return props.scroller;
1024
+ }
1025
+ })
1026
+ }), _el$47, _co$0);
1027
+ _$insert(_el$31, _$createComponent(TimeOverlays, {
1028
+ view: view,
1029
+ get dayKey() {
1030
+ return props.dayKey;
1031
+ },
1032
+ get expanded() {
1033
+ return expanded();
1034
+ }
1035
+ }), _el$49, _co$1);
1036
+ _$insert(_el$31, _$createComponent(Show, {
1037
+ get when() {
1038
+ return _$memo(() => props.hover()?.key === props.dayKey)() && props.hover();
1039
+ },
1040
+ children: current => (() => {
1041
+ var _el$79 = _$getNextElement(_tmpl$18);
1042
+ _$insert(_el$79, () => view.clock(current().minute));
1043
+ _$effect(_$p => _$setStyleProperty(_el$79, "top", termsCss(dayYTerms(wake(), expanded(), current().minute))));
1044
+ return _el$79;
1045
+ })()
1046
+ }), _el$51, _co$10);
1047
+ _$insert(_el$31, _$createComponent(Show, {
1048
+ get when() {
1049
+ return _$memo(() => !!(nowMinute() !== null && nowMinute() >= 0))() && nowMinute() < (expanded() ? DAY_MINUTES : wake());
1050
+ },
1051
+ get children() {
1052
+ var _el$40 = _$getNextElement(_tmpl$9),
1053
+ _el$41 = _el$40.firstChild;
1054
+ _$insert(_el$41, () => view.clock(nowMinute()));
1055
+ _$effect(_$p => _$setStyleProperty(_el$40, "top", termsCss(dayYTerms(wake(), expanded(), nowMinute()))));
1056
+ return _el$40;
1057
+ }
1058
+ }), _el$53, _co$11);
1059
+ _$effect(_p$ => {
1060
+ var _v$3 = props.dayKey,
1061
+ _v$4 = today() ? "true" : undefined,
1062
+ _v$5 = props.dayKey < view.nowKey() ? "true" : undefined,
1063
+ _v$6 = selectedDay() ? "true" : undefined,
1064
+ _v$7 = selectedDay() ? "true" : "false",
1065
+ _v$8 = view.cheered() === props.dayKey ? "true" : undefined,
1066
+ _v$9 = props.dayKey,
1067
+ _v$0 = expanded() ? "true" : "false",
1068
+ _v$1 = termsCss(dayHeightTerms(wake(), expanded()));
1069
+ _v$3 !== _p$.e && _$setAttribute(_el$10, "data-calendar-keys", _p$.e = _v$3);
1070
+ _v$4 !== _p$.t && _$setAttribute(_el$10, "data-today", _p$.t = _v$4);
1071
+ _v$5 !== _p$.a && _$setAttribute(_el$10, "data-past", _p$.a = _v$5);
1072
+ _v$6 !== _p$.o && _$setAttribute(_el$10, "data-selected", _p$.o = _v$6);
1073
+ _v$7 !== _p$.i && _$setAttribute(_el$13, "aria-pressed", _p$.i = _v$7);
1074
+ _v$8 !== _p$.n && _$setAttribute(_el$19, "data-cheer", _p$.n = _v$8);
1075
+ _v$9 !== _p$.s && _$setAttribute(_el$31, "data-calendar-body", _p$.s = _v$9);
1076
+ _v$0 !== _p$.h && _$setAttribute(_el$31, "data-expanded", _p$.h = _v$0);
1077
+ _v$1 !== _p$.r && _$setStyleProperty(_el$31, "height", _p$.r = _v$1);
1078
+ return _p$;
1079
+ }, {
1080
+ e: undefined,
1081
+ t: undefined,
1082
+ a: undefined,
1083
+ o: undefined,
1084
+ i: undefined,
1085
+ n: undefined,
1086
+ s: undefined,
1087
+ h: undefined,
1088
+ r: undefined
1089
+ });
1090
+ _$runHydrationEvents();
1091
+ return _el$10;
1092
+ })();
1093
+ };
1094
+ const dayHeightTermsNight = wake => {
1095
+ const total = dayHeightTerms(wake, true);
1096
+ return [0, total[1], total[2], 0];
1097
+ };
1098
+ const EmptyRun = props => {
1099
+ const view = props.view;
1100
+ const headingId = createUniqueId();
1101
+ const first = () => props.keys[0];
1102
+ const last = () => props.keys[props.keys.length - 1];
1103
+ const title = () => props.keys.length === 1 ? longDay(view, first()) : `${shortDay(view, first())} – ${shortDay(view, last(), true)}`;
1104
+ return (() => {
1105
+ var _el$80 = _$getNextElement(_tmpl$19),
1106
+ _el$81 = _el$80.firstChild,
1107
+ _el$82 = _el$81.firstChild,
1108
+ _el$83 = _el$82.firstChild,
1109
+ _el$84 = _el$82.nextSibling,
1110
+ _el$86 = _el$84.nextSibling,
1111
+ [_el$87, _co$18] = _$getNextMarker(_el$86.nextSibling),
1112
+ _el$85 = _el$87.nextSibling,
1113
+ _el$88 = _el$81.nextSibling,
1114
+ _el$89 = _el$88.firstChild,
1115
+ _el$90 = _el$89.nextSibling,
1116
+ _el$91 = _el$90.firstChild,
1117
+ _el$92 = _el$91.nextSibling,
1118
+ [_el$93, _co$19] = _$getNextMarker(_el$92.nextSibling);
1119
+ _$setAttribute(_el$80, "aria-labelledby", headingId);
1120
+ _$setAttribute(_el$82, "id", headingId);
1121
+ _$insert(_el$83, title);
1122
+ _$insert(_el$81, _$createComponent(For, {
1123
+ get each() {
1124
+ return props.keys.filter(key => view.props.owner.dayBadges?.[key]);
1125
+ },
1126
+ children: key => {
1127
+ const badge = view.props.owner.dayBadges[key];
1128
+ return (() => {
1129
+ var _el$94 = _$getNextElement(_tmpl$21),
1130
+ _el$96 = _el$94.firstChild,
1131
+ [_el$97, _co$20] = _$getNextMarker(_el$96.nextSibling),
1132
+ _el$98 = _el$97.nextSibling,
1133
+ [_el$99, _co$21] = _$getNextMarker(_el$98.nextSibling),
1134
+ _el$100 = _el$99.nextSibling,
1135
+ [_el$101, _co$22] = _$getNextMarker(_el$100.nextSibling);
1136
+ _$insert(_el$94, _$createComponent(Show, {
1137
+ get when() {
1138
+ return props.keys.length > 1;
1139
+ },
1140
+ get children() {
1141
+ var _el$95 = _$getNextElement(_tmpl$20);
1142
+ _$insert(_el$95, () => shortDay(view, key).split(/[\s,.]/)[0]);
1143
+ return _el$95;
1144
+ }
1145
+ }), _el$97, _co$20);
1146
+ _$insert(_el$94, _$createComponent(Show, {
1147
+ get when() {
1148
+ return badge.icon;
1149
+ },
1150
+ children: icon => (() => {
1151
+ var _el$102 = _$getNextElement(_tmpl$10);
1152
+ _$effect(() => _$className(_el$102, `ti ti-${icon()}`));
1153
+ return _el$102;
1154
+ })()
1155
+ }), _el$99, _co$21);
1156
+ _$insert(_el$94, () => badge.label, _el$101, _co$22);
1157
+ return _el$94;
1158
+ })();
1159
+ }
1160
+ }), _el$87, _co$18);
1161
+ _$insert(_el$85, (() => {
1162
+ var _c$ = _$memo(() => props.keys.length > 1);
1163
+ return () => _c$() ? view.messages().calendarDayCount({
1164
+ count: props.keys.length
1165
+ }) : "";
1166
+ })());
1167
+ _el$88.$$click = () => props.onUnfold(props.keys);
1168
+ _$insert(_el$89, () => view.messages().calendarNothingPlannedShort);
1169
+ _$insert(_el$90, () => view.messages().calendarUnfoldDays({
1170
+ count: props.keys.length
1171
+ }), _el$93, _co$19);
1172
+ _$effect(_p$ => {
1173
+ var _v$19 = props.keys.join(","),
1174
+ _v$20 = last() < view.nowKey() ? "true" : undefined;
1175
+ _v$19 !== _p$.e && _$setAttribute(_el$80, "data-calendar-keys", _p$.e = _v$19);
1176
+ _v$20 !== _p$.t && _$setAttribute(_el$80, "data-past", _p$.t = _v$20);
1177
+ return _p$;
1178
+ }, {
1179
+ e: undefined,
1180
+ t: undefined
1181
+ });
1182
+ _$runHydrationEvents();
1183
+ return _el$80;
1184
+ })();
1185
+ };
1186
+ _$delegateEvents(["touchstart", "touchend", "focusin", "click", "pointerdown", "dblclick", "pointermove"]);
1187
+ //# sourceMappingURL=CalendarDayView.js.map