@k2b/ui 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/browser/actions/Dropdown.js +67 -52
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/GestureMenu.js +3 -3
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/actions/SpotlightSearch.js +13 -6
- package/dist/browser/actions/SpotlightSearch.js.map +1 -1
- package/dist/browser/actions/Toolbar.js +75 -1
- package/dist/browser/actions/Toolbar.js.map +1 -1
- package/dist/browser/content/Calendar.js +1570 -923
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/CalendarDayView.js +2 -2
- package/dist/browser/content/CalendarDayView.js.map +1 -1
- package/dist/browser/content/CalendarWeekView.js +29 -7
- package/dist/browser/content/CalendarWeekView.js.map +1 -1
- package/dist/browser/content/DataTable.js +45 -35
- package/dist/browser/content/DataTable.js.map +1 -1
- package/dist/browser/content/Kbd.js +51 -0
- package/dist/browser/content/Kbd.js.map +1 -0
- package/dist/browser/content/LabelChip.js +38 -0
- package/dist/browser/content/LabelChip.js.map +1 -0
- package/dist/browser/content/MarkdownView.js +2 -1
- package/dist/browser/content/MarkdownView.js.map +1 -1
- package/dist/browser/content/Steps.js +34 -0
- package/dist/browser/content/Steps.js.map +1 -0
- package/dist/browser/content/VirtualFeed.js +33 -1
- package/dist/browser/content/VirtualFeed.js.map +1 -1
- package/dist/browser/content/calendar-day-scroll.js +17 -4
- package/dist/browser/content/calendar-day-scroll.js.map +1 -1
- package/dist/browser/content/calendar-dialogs.js +32 -60
- package/dist/browser/content/calendar-dialogs.js.map +1 -1
- package/dist/browser/content/calendar-month-scroll.js +80 -0
- package/dist/browser/content/calendar-month-scroll.js.map +1 -0
- package/dist/browser/content/calendar-time-view.js +9 -4
- package/dist/browser/content/calendar-time-view.js.map +1 -1
- package/dist/browser/content/index.js +4 -1
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/content/markdown-info-blocks.js +33 -5
- package/dist/browser/content/markdown-info-blocks.js.map +1 -1
- package/dist/browser/feedback/prompts.js +17 -3
- package/dist/browser/feedback/prompts.js.map +1 -1
- package/dist/browser/intl/index.js +1 -0
- package/dist/browser/intl/index.js.map +1 -1
- package/dist/browser/intl/shortcut-messages.js +77 -0
- package/dist/browser/intl/shortcut-messages.js.map +1 -0
- package/dist/browser/intl/shortcut.js +123 -0
- package/dist/browser/intl/shortcut.js.map +1 -0
- package/dist/browser/layout/AppWorkspace.js +345 -325
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/Navigation.js +18 -3
- package/dist/browser/layout/Navigation.js.map +1 -1
- package/dist/browser/layout/PageTitle.js +14 -0
- package/dist/browser/layout/PageTitle.js.map +1 -1
- package/dist/browser/layout/SidebarSwitcher.js +505 -0
- package/dist/browser/layout/SidebarSwitcher.js.map +1 -0
- package/dist/browser/layout/TableOfContents.js +115 -0
- package/dist/browser/layout/TableOfContents.js.map +1 -0
- package/dist/browser/layout/app-workspace-controller.js +15 -48
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/index.js +2 -0
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/layout/navigation-model.js +1 -0
- package/dist/browser/layout/navigation-model.js.map +1 -1
- package/dist/browser/layout/table-of-contents-messages.js +19 -0
- package/dist/browser/layout/table-of-contents-messages.js.map +1 -0
- package/dist/browser/surfaces/LinkCard.js +40 -24
- package/dist/browser/surfaces/LinkCard.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +11 -5
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/GestureMenu.js +3 -3
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/actions/SpotlightSearch.js +9 -3
- package/dist/ssr/actions/SpotlightSearch.js.map +1 -1
- package/dist/ssr/actions/Toolbar.js +67 -1
- package/dist/ssr/actions/Toolbar.js.map +1 -1
- package/dist/ssr/content/Calendar.js +895 -321
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/CalendarDayView.js +2 -2
- package/dist/ssr/content/CalendarDayView.js.map +1 -1
- package/dist/ssr/content/CalendarWeekView.js +28 -7
- package/dist/ssr/content/CalendarWeekView.js.map +1 -1
- package/dist/ssr/content/DataTable.js +21 -17
- package/dist/ssr/content/DataTable.js.map +1 -1
- package/dist/ssr/content/Kbd.js +38 -0
- package/dist/ssr/content/Kbd.js.map +1 -0
- package/dist/ssr/content/LabelChip.js +21 -0
- package/dist/ssr/content/LabelChip.js.map +1 -0
- package/dist/ssr/content/MarkdownView.js +2 -1
- package/dist/ssr/content/MarkdownView.js.map +1 -1
- package/dist/ssr/content/Steps.js +14 -0
- package/dist/ssr/content/Steps.js.map +1 -0
- package/dist/ssr/content/VirtualFeed.js +33 -1
- package/dist/ssr/content/VirtualFeed.js.map +1 -1
- package/dist/ssr/content/calendar-day-scroll.js +17 -4
- package/dist/ssr/content/calendar-day-scroll.js.map +1 -1
- package/dist/ssr/content/calendar-dialogs.js +12 -32
- package/dist/ssr/content/calendar-dialogs.js.map +1 -1
- package/dist/ssr/content/calendar-month-scroll.js +80 -0
- package/dist/ssr/content/calendar-month-scroll.js.map +1 -0
- package/dist/ssr/content/calendar-time-view.js +8 -3
- package/dist/ssr/content/calendar-time-view.js.map +1 -1
- package/dist/ssr/content/index.js +4 -1
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/content/markdown-info-blocks.js +33 -5
- package/dist/ssr/content/markdown-info-blocks.js.map +1 -1
- package/dist/ssr/feedback/prompts.js +17 -3
- package/dist/ssr/feedback/prompts.js.map +1 -1
- package/dist/ssr/intl/index.js +1 -0
- package/dist/ssr/intl/index.js.map +1 -1
- package/dist/ssr/intl/shortcut-messages.js +77 -0
- package/dist/ssr/intl/shortcut-messages.js.map +1 -0
- package/dist/ssr/intl/shortcut.js +123 -0
- package/dist/ssr/intl/shortcut.js.map +1 -0
- package/dist/ssr/layout/AppWorkspace.js +67 -59
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/Navigation.js +12 -2
- package/dist/ssr/layout/Navigation.js.map +1 -1
- package/dist/ssr/layout/PageTitle.js +14 -0
- package/dist/ssr/layout/PageTitle.js.map +1 -1
- package/dist/ssr/layout/SidebarSwitcher.js +271 -0
- package/dist/ssr/layout/SidebarSwitcher.js.map +1 -0
- package/dist/ssr/layout/TableOfContents.js +79 -0
- package/dist/ssr/layout/TableOfContents.js.map +1 -0
- package/dist/ssr/layout/app-workspace-controller.js +15 -48
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/index.js +2 -0
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/layout/navigation-model.js +1 -0
- package/dist/ssr/layout/navigation-model.js.map +1 -1
- package/dist/ssr/layout/table-of-contents-messages.js +19 -0
- package/dist/ssr/layout/table-of-contents-messages.js.map +1 -0
- package/dist/ssr/surfaces/LinkCard.js +26 -10
- package/dist/ssr/surfaces/LinkCard.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Dropdown.d.ts +12 -0
- package/dist/types/actions/SpotlightSearch.d.ts +2 -0
- package/dist/types/content/Calendar.d.ts +20 -7
- package/dist/types/content/CalendarWeekView.d.ts +1 -1
- package/dist/types/content/DataTable.d.ts +9 -0
- package/dist/types/content/Kbd.d.ts +16 -0
- package/dist/types/content/LabelChip.d.ts +12 -0
- package/dist/types/content/MarkdownView.d.ts +2 -1
- package/dist/types/content/Steps.d.ts +12 -0
- package/dist/types/content/VirtualFeed.d.ts +8 -0
- package/dist/types/content/calendar-day-scroll.d.ts +9 -4
- package/dist/types/content/calendar-dialogs.d.ts +0 -2
- package/dist/types/content/calendar-month-scroll.d.ts +25 -0
- package/dist/types/content/index.d.ts +7 -1
- package/dist/types/content/markdown-info-blocks.d.ts +21 -4
- package/dist/types/feedback/prompts.d.ts +8 -2
- package/dist/types/intl/index.d.ts +2 -0
- package/dist/types/intl/shortcut-messages.d.ts +35 -0
- package/dist/types/intl/shortcut.d.ts +29 -0
- package/dist/types/layout/AppWorkspace.d.ts +5 -1
- package/dist/types/layout/SidebarSwitcher.d.ts +65 -0
- package/dist/types/layout/TableOfContents.d.ts +24 -0
- package/dist/types/layout/index.d.ts +3 -0
- package/dist/types/layout/navigation-model.d.ts +4 -0
- package/dist/types/layout/table-of-contents-messages.d.ts +4 -0
- package/dist/types/surfaces/LinkCard.d.ts +3 -0
- package/package.json +4 -4
|
@@ -27,47 +27,49 @@ var _tmpl$ = ["<div role=\"radiogroup\"", " aria-orientation=\"horizontal\" clas
|
|
|
27
27
|
_tmpl$16 = ["<span class=\"k2b-calendar-month__day-number\"", ">", "</span>"],
|
|
28
28
|
_tmpl$17 = ["<span class=\"k2b-calendar-month__badge\">", "", "</span>"],
|
|
29
29
|
_tmpl$18 = ["<span class=\"k2b-calendar-dot\"", " style=\"", "\"></span>"],
|
|
30
|
-
_tmpl$19 = ["<div class=\"k2b-calendar-
|
|
31
|
-
_tmpl$20 = ["<div class=\"k2b-calendar-
|
|
32
|
-
_tmpl$21 = ["<
|
|
33
|
-
_tmpl$22 = ["<
|
|
34
|
-
_tmpl$23 = ["<div class=\"k2b-calendar-
|
|
35
|
-
_tmpl$24 = ["<
|
|
36
|
-
_tmpl$25 = ["<
|
|
37
|
-
_tmpl$26 = ["<div class=\"k2b-calendar-
|
|
38
|
-
_tmpl$27 = ["<div class=\"k2b-calendar-
|
|
39
|
-
_tmpl$28 = ["<
|
|
40
|
-
_tmpl$29 = "<
|
|
41
|
-
_tmpl$30 = ["<
|
|
42
|
-
_tmpl$31 =
|
|
43
|
-
_tmpl$32 = ["<
|
|
44
|
-
_tmpl$33 = "<
|
|
45
|
-
_tmpl$34 = ["<
|
|
46
|
-
_tmpl$35 =
|
|
47
|
-
_tmpl$36 = ["<div class=\"k2b-calendar-
|
|
48
|
-
_tmpl$37 = ["<
|
|
49
|
-
_tmpl$38 = ["<
|
|
50
|
-
_tmpl$39 = ["<
|
|
51
|
-
_tmpl$40 = ["<
|
|
52
|
-
_tmpl$41 = ["<div class=\"k2b-calendar-time-
|
|
53
|
-
_tmpl$42 = ["<div class=\"k2b-calendar-time-
|
|
54
|
-
_tmpl$43 = ["<div class=\"k2b-calendar-
|
|
55
|
-
_tmpl$44 = ["<div class=\"k2b-calendar-
|
|
56
|
-
_tmpl$45 = ["<
|
|
57
|
-
_tmpl$46 = ["<div class=\"k2b-calendar-
|
|
58
|
-
_tmpl$47 = ["<button type=\"button\" class=\"k2b-calendar-time-
|
|
59
|
-
_tmpl$48 = ["<div class=\"k2b-calendar-time-
|
|
60
|
-
_tmpl$49 = ["<
|
|
61
|
-
_tmpl$50 = ["<div class=\"k2b-calendar-
|
|
62
|
-
_tmpl$51 = ["<
|
|
63
|
-
_tmpl$52 = ["<div class=\"k2b-calendar-
|
|
64
|
-
_tmpl$53 = ["<
|
|
65
|
-
_tmpl$54 = ["<div class=\"k2b-calendar-mobile-
|
|
66
|
-
_tmpl$55 = ["<div class=\"k2b-calendar-
|
|
67
|
-
_tmpl$56 = ["<
|
|
30
|
+
_tmpl$19 = ["<div class=\"k2b-calendar-month__week-number\" role=\"rowheader\">", "</div>"],
|
|
31
|
+
_tmpl$20 = ["<div class=\"k2b-calendar-month__week\" role=\"row\"", " style=\"", "\"", ">", "", "</div>"],
|
|
32
|
+
_tmpl$21 = ["<button type=\"button\" class=\"k2b-calendar-month__week-link\" tabindex=\"-1\"", ">", "</button>"],
|
|
33
|
+
_tmpl$22 = ["<button type=\"button\" class=\"k2b-calendar-month__more\" tabindex=\"-1\" style=\"", "\"", " aria-haspopup=\"dialog\"", "><span class=\"k2b-calendar-month__more-long\">", "</span><span class=\"k2b-calendar-month__more-short\">+", "</span></button>"],
|
|
34
|
+
_tmpl$23 = ["<div class=\"k2b-calendar-month__day\" role=\"gridcell\"", "><div class=\"k2b-calendar-month__day-header\"><span class=\"k2b-calendar-month__day-number\"", ">", "</span>", "</div><div class=\"k2b-calendar-month__lanes\">", "", "", "</div></div>"],
|
|
35
|
+
_tmpl$24 = ["<div class=\"k2b-calendar-month__segment\" style=\"", "\">", "</div>"],
|
|
36
|
+
_tmpl$25 = ["<div class=\"k2b-calendar-month__weekday\" role=\"columnheader\">", "</div>"],
|
|
37
|
+
_tmpl$26 = ["<div class=\"k2b-calendar-month__weekdays\" role=\"row\"", ">", "", "</div>"],
|
|
38
|
+
_tmpl$27 = ["<div class=\"k2b-calendar-month__weekday\" role=\"columnheader\"", ">", "</div>"],
|
|
39
|
+
_tmpl$28 = ["<div class=\"k2b-calendar-month\" role=\"grid\"", " aria-multiselectable=\"true\" data-lanes=\"true\" style=\"", "\">", "", "</div>"],
|
|
40
|
+
_tmpl$29 = ["<div class=\"k2b-calendar-month-viewport\"><div class=\"k2b-calendar-month\" role=\"grid\"", " aria-multiselectable=\"true\" data-lanes=\"true\" data-continuous=\"true\"", " style=\"", "\">", "<div class=\"k2b-calendar-month__track\" role=\"rowgroup\" style=\"", "\">", "</div></div><div class=\"k2b-calendar-month__scroll-label\" aria-hidden=\"true\"", ">", "</div></div>"],
|
|
41
|
+
_tmpl$30 = ["<ul class=\"k2b-calendar-day-list__events\">", "</ul>"],
|
|
42
|
+
_tmpl$31 = "<i class=\"ti ti-plus\" aria-hidden=\"true\"></i>",
|
|
43
|
+
_tmpl$32 = ["<div class=\"k2b-calendar-day-list\"><div class=\"k2b-calendar-day-list__title\">", "</div>", "<div class=\"k2b-calendar-day-list__actions\">", "", "</div></div>"],
|
|
44
|
+
_tmpl$33 = ["<p class=\"k2b-calendar-day-list__empty\">", "</p>"],
|
|
45
|
+
_tmpl$34 = ["<li>", "</li>"],
|
|
46
|
+
_tmpl$35 = "<i class=\"ti ti-zoom-in\" aria-hidden=\"true\"></i>",
|
|
47
|
+
_tmpl$36 = ["<div class=\"k2b-calendar-popover\" popover=\"auto\" role=\"dialog\"", ">", "</div>"],
|
|
48
|
+
_tmpl$37 = ["<div class=\"k2b-calendar-time-grid__all-day\" style=\"", "\"><div class=\"k2b-calendar-time-grid__all-day-label\">", "</div>", "</div>"],
|
|
49
|
+
_tmpl$38 = ["<div class=\"k2b-calendar-time-grid\"", "><div class=\"k2b-calendar-time-grid__days\" style=\"", "\"><div class=\"k2b-calendar-time-grid__corner\"></div>", "</div>", "<div class=\"k2b-calendar-time-grid__scroll k2b-detail-trail\"><div class=\"k2b-calendar-time-grid__grid\" style=\"", "\"><div class=\"k2b-calendar-time-grid__gutter\" style=\"", "\">", "</div>", "</div></div></div>"],
|
|
50
|
+
_tmpl$39 = ["<span class=\"k2b-calendar-time-grid__day-label\"", ">", "</span>"],
|
|
51
|
+
_tmpl$40 = ["<span class=\"k2b-calendar-time-grid__badge\">", "", "</span>"],
|
|
52
|
+
_tmpl$41 = ["<div class=\"k2b-calendar-time-grid__all-day-events\">", "", "</div>"],
|
|
53
|
+
_tmpl$42 = ["<div class=\"k2b-calendar-time-grid__hour\"", ">", ":00</div>"],
|
|
54
|
+
_tmpl$43 = ["<div class=\"k2b-calendar-time-grid__now\" style=\"", "\"></div>"],
|
|
55
|
+
_tmpl$44 = ["<div class=\"k2b-calendar-time-grid__column\" style=\"", "\">", "", "", "", "", "</div>"],
|
|
56
|
+
_tmpl$45 = ["<div class=\"k2b-calendar-preview__title\">", "</div>"],
|
|
57
|
+
_tmpl$46 = ["<div class=\"k2b-calendar-preview k2b-calendar-preview--timed\"", " style=\"", "\"><div class=\"k2b-calendar-preview__content\">", "<div class=\"k2b-calendar-preview__label\">", " - ", "</div></div></div>"],
|
|
58
|
+
_tmpl$47 = ["<button type=\"button\"", " draggable=\"false\" class=\"k2b-calendar-time-grid__resize\"><span class=\"k2b-calendar-time-grid__resize-icon\" aria-hidden=\"true\"></span></button>"],
|
|
59
|
+
_tmpl$48 = ["<div class=\"k2b-calendar-time-grid__event-position\" style=\"", "\"><div class=\"k2b-calendar-time-grid__event-frame\">", "", "</div></div>"],
|
|
60
|
+
_tmpl$49 = ["<button type=\"button\" class=\"k2b-calendar-time-grid__overflow\" style=\"", "\"", "><span class=\"k2b-calendar-time-grid__overflow-count\">+", "</span></button>"],
|
|
61
|
+
_tmpl$50 = ["<div class=\"k2b-calendar-time-grid__overflow-menu\" style=\"", "\"><div class=\"k2b-calendar-time-grid__overflow-title\">", " - ", "</div>", "</div>"],
|
|
62
|
+
_tmpl$51 = ["<div class=\"k2b-calendar-year\">", "</div>"],
|
|
63
|
+
_tmpl$52 = ["<div class=\"k2b-calendar-year__month\"><div class=\"k2b-calendar-year__title\">", "</div><div class=\"k2b-calendar-year__grid\">", "</div></div>"],
|
|
64
|
+
_tmpl$53 = ["<span class=\"k2b-calendar-year__indicator\"", " style=\"", "\"></span>"],
|
|
65
|
+
_tmpl$54 = ["<div class=\"k2b-calendar-mobile-month__events\">", "</div>"],
|
|
66
|
+
_tmpl$55 = ["<div class=\"k2b-calendar-mobile-month\">", "<div class=\"k2b-calendar-mobile-month__agenda\"><div class=\"k2b-calendar-mobile-month__title\">", "</div>", "</div></div>"],
|
|
67
|
+
_tmpl$56 = ["<div class=\"k2b-calendar-mobile-month__empty\">", "</div>"],
|
|
68
|
+
_tmpl$57 = ["<div class=\"k2b-calendar-body\">", "</div>"],
|
|
69
|
+
_tmpl$58 = ["<section class=\"", "\"", ">", "", "</section>"];
|
|
68
70
|
import { Link } from "@k2b/ssr/nav";
|
|
69
71
|
import { dates as calendar } from "@k2b/stdlib";
|
|
70
|
-
import { createEffect, createMemo, createSignal, For, mergeProps, on, onCleanup, onMount, Show, untrack } from "solid-js";
|
|
72
|
+
import { createComputed, createEffect, createMemo, createSignal, For, mergeProps, on, onCleanup, onMount, Show, untrack } from "solid-js";
|
|
71
73
|
import { Button } from "../actions/Button";
|
|
72
74
|
import { GestureMenu } from "../actions/GestureMenu";
|
|
73
75
|
import SegmentedControl from "../actions/SegmentedControl";
|
|
@@ -75,13 +77,15 @@ import { useDateConfigLocale } from "../intl/locale";
|
|
|
75
77
|
import { useUiMessages } from "../intl/messages";
|
|
76
78
|
import { CalendarDayView } from "./CalendarDayView";
|
|
77
79
|
import { CalendarWeekView } from "./CalendarWeekView";
|
|
80
|
+
import { addDayKeys } from "./calendar-days";
|
|
78
81
|
import { openCalendarGoTo, openCalendarShortcuts } from "./calendar-dialogs";
|
|
79
82
|
import { layoutCalendarIntervals } from "./calendar-event-layout";
|
|
80
83
|
import { useCalendarMessages } from "./calendar-messages";
|
|
81
84
|
import { fitMonthWeek, layoutMonthWeek, monthLaneCapacity } from "./calendar-month-layout";
|
|
85
|
+
import { MONTH_ROW_BLOCK, MONTH_ROWS_IN_VIEW, monthFocusRow, monthOfWeek, monthRenderWindow, monthRevealTop, monthRowOf, monthTodayDirection, monthVisibleRows, monthWeekKeys } from "./calendar-month-scroll";
|
|
82
86
|
import { calendarDayIndexAtPoint, calendarMinuteAtPoint, startCalendarPointerSession } from "./calendar-pointer";
|
|
83
87
|
import { EventChip, eventHref, followCalendarHref, formatTime, ownerDateConfig, parseDate, placeCalendarPopover, textWidth, validDate } from "./calendar-shared";
|
|
84
|
-
import { compactGermanDate } from "./calendar-time-view";
|
|
88
|
+
import { compactGermanDate, reducedMotion } from "./calendar-time-view";
|
|
85
89
|
|
|
86
90
|
/** The days a host loaded events for, from the first day `from` up to `to`, both `YYYY-MM-DD` or dates. */
|
|
87
91
|
|
|
@@ -413,11 +417,13 @@ const CalendarHeader = props => {
|
|
|
413
417
|
const calendarMessages = useCalendarMessages();
|
|
414
418
|
const dateConfig = () => ownerDateConfig(props.owner);
|
|
415
419
|
const timeView = () => props.nav.timeView();
|
|
420
|
+
const monthView = () => props.nav.monthView();
|
|
421
|
+
const scrollingView = () => timeView() ?? monthView();
|
|
416
422
|
const parseKey = key => calendar.parseCalendarDate(key, dateConfig());
|
|
417
423
|
/** The date the header pages from: the first day a day or week view shows, else the date. */
|
|
418
424
|
const base = () => {
|
|
419
425
|
const shown = timeView()?.visibleKeys().first;
|
|
420
|
-
return shown ? parseKey(shown) : props.date;
|
|
426
|
+
return shown ? parseKey(shown) : monthView()?.stepFrom() ?? props.date;
|
|
421
427
|
};
|
|
422
428
|
const previous = () => adjacentCalendarDate(base(), props.view, -1, dateConfig());
|
|
423
429
|
const next = () => adjacentCalendarDate(base(), props.view, 1, dateConfig());
|
|
@@ -451,7 +457,7 @@ const CalendarHeader = props => {
|
|
|
451
457
|
timeZone: dateConfig().timeZone
|
|
452
458
|
});
|
|
453
459
|
if (props.view === "week") return `${formatDay(calendar.startOfWeek(props.date, dateConfig()), dateConfig())} - ${formatDay(calendar.addDays(calendar.startOfWeek(props.date, dateConfig()), 6, dateConfig()), dateConfig())}`;
|
|
454
|
-
return formatMonth(props.date, dateConfig());
|
|
460
|
+
return formatMonth(monthView()?.focusMonth() ?? props.date, dateConfig());
|
|
455
461
|
};
|
|
456
462
|
/**
|
|
457
463
|
* The titles this view can show around the current date: the months of the year, the weeks of the month and across
|
|
@@ -515,37 +521,52 @@ const CalendarHeader = props => {
|
|
|
515
521
|
const href = props.owner.getViewHref?.(view);
|
|
516
522
|
if (href) window.location.href = href;
|
|
517
523
|
};
|
|
524
|
+
/**
|
|
525
|
+
* A previous or next button. Its element stays while its target changes, such as with each step through the months,
|
|
526
|
+
* so a repeated click or Enter lands on the same button and keeps its focus.
|
|
527
|
+
*/
|
|
518
528
|
const navButton = (date, icon, label, direction) => {
|
|
519
|
-
const href = props.owner.getDateHref?.(date, props.view);
|
|
520
|
-
const step = () =>
|
|
521
|
-
const title = props.nav.commands().length > 0 ? `${label} (${direction > 0 ? "J" : "K"})` : label;
|
|
522
|
-
|
|
529
|
+
const href = () => props.owner.getDateHref?.(date(), props.view);
|
|
530
|
+
const step = () => scrollingView()?.step(direction) ?? false;
|
|
531
|
+
const title = () => props.nav.commands().length > 0 ? `${label} (${direction > 0 ? "J" : "K"})` : label;
|
|
532
|
+
const link = target => _$createComponent(CalendarNavigationLink, {
|
|
523
533
|
get owner() {
|
|
524
534
|
return props.owner;
|
|
525
535
|
},
|
|
526
|
-
href
|
|
536
|
+
get href() {
|
|
537
|
+
return target();
|
|
538
|
+
},
|
|
527
539
|
intercept: step,
|
|
528
|
-
anchorProps
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
540
|
+
get anchorProps() {
|
|
541
|
+
return {
|
|
542
|
+
"aria-label": label,
|
|
543
|
+
title: title(),
|
|
544
|
+
class: "k2b-calendar-header__nav-button"
|
|
545
|
+
};
|
|
532
546
|
},
|
|
533
547
|
get children() {
|
|
534
548
|
return _$ssr(_tmpl$2, `ti ${_$escape(icon, true)}`);
|
|
535
549
|
}
|
|
536
|
-
})
|
|
537
|
-
|
|
538
|
-
|
|
550
|
+
});
|
|
551
|
+
return _$createComponent(Show, {
|
|
552
|
+
get when() {
|
|
553
|
+
return Boolean((props.owner.onNavigateHref || props.owner.onNavigate) && href());
|
|
539
554
|
},
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
555
|
+
get fallback() {
|
|
556
|
+
return _$createComponent(Show, {
|
|
557
|
+
get when() {
|
|
558
|
+
return props.owner.onDateChange;
|
|
559
|
+
},
|
|
560
|
+
get fallback() {
|
|
561
|
+
return link(() => href() ?? "#");
|
|
562
|
+
},
|
|
563
|
+
get children() {
|
|
564
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("aria-label", _$escape(label, true), false) + _$ssrAttribute("title", _$escape(title(), true), false), `ti ${_$escape(icon, true)}`);
|
|
565
|
+
}
|
|
566
|
+
});
|
|
546
567
|
},
|
|
547
568
|
get children() {
|
|
548
|
-
return
|
|
569
|
+
return link(() => href() ?? "#");
|
|
549
570
|
}
|
|
550
571
|
});
|
|
551
572
|
};
|
|
@@ -553,7 +574,7 @@ const CalendarHeader = props => {
|
|
|
553
574
|
* In the day and week views that scroll through their days, Today points where today lies, or shows a calm dot while
|
|
554
575
|
* it is on screen; the icon keeps its place either way. The other views name their period in the title.
|
|
555
576
|
*/
|
|
556
|
-
const direction = () => timeMode() ? (
|
|
577
|
+
const direction = () => timeMode() || monthView() ? (scrollingView()?.todayDirection() ?? todayDirectionOf(String(props.view), props.date, dateConfig())) || "here" : undefined;
|
|
557
578
|
/** One arrow that the stylesheet turns toward today, or the dot while today shows. */
|
|
558
579
|
const todayIcon = () => _$createComponent(Show, {
|
|
559
580
|
get when() {
|
|
@@ -574,7 +595,7 @@ const CalendarHeader = props => {
|
|
|
574
595
|
const todayButton = () => {
|
|
575
596
|
const today = calendar.today(dateConfig());
|
|
576
597
|
const href = props.owner.getDateHref?.(today, props.view);
|
|
577
|
-
const intercept = () =>
|
|
598
|
+
const intercept = () => scrollingView()?.today() ?? false;
|
|
578
599
|
const title = () => props.nav.commands().length > 0 ? `${props.labels.today} (H)` : undefined;
|
|
579
600
|
const label = [todayIcon(), _$ssr(_tmpl$6, _$escape(props.labels.today))];
|
|
580
601
|
return (props.owner.onNavigateHref || props.owner.onNavigate) && href ? _$createComponent(CalendarNavigationLink, {
|
|
@@ -641,7 +662,7 @@ const CalendarHeader = props => {
|
|
|
641
662
|
value: "year",
|
|
642
663
|
label: props.labels.year
|
|
643
664
|
}].filter(option => !props.owner.views || props.owner.views.includes(option.value)), ...(props.owner.customViews ?? [])]);
|
|
644
|
-
return _$ssr(_tmpl$0, _$escape(navButton(previous
|
|
665
|
+
return _$ssr(_tmpl$0, _$escape(navButton(previous, "ti-chevron-left", props.labels.previous, -1)), _$escape(navButton(next, "ti-chevron-right", props.labels.next, 1)), _$escape(title()), _$escape(_$createComponent(For, {
|
|
645
666
|
get each() {
|
|
646
667
|
return titleWidths();
|
|
647
668
|
},
|
|
@@ -950,7 +971,7 @@ const MonthPickerView = props => {
|
|
|
950
971
|
|
|
951
972
|
/** One entry of the month grid: its whole range, and the days it covers as `YYYY-MM-DD` keys. */
|
|
952
973
|
|
|
953
|
-
/** What the calendar's controller
|
|
974
|
+
/** What the calendar's controller and header ask of the month view; the rest serves the month that scrolls. */
|
|
954
975
|
|
|
955
976
|
/** Lane height and gap of the month entries, in rem; the stylesheet reads both from the grid's custom properties. */
|
|
956
977
|
const MONTH_LANE_REM = 1.25;
|
|
@@ -1010,9 +1031,13 @@ const PRINTABLE_KEY = /^.$/u;
|
|
|
1010
1031
|
const MonthView = props => {
|
|
1011
1032
|
const calendarMessages = useCalendarMessages();
|
|
1012
1033
|
const dateConfig = createMemo(() => ownerDateConfig(props.owner));
|
|
1034
|
+
const continuous = createMemo(() => Boolean(props.owner.range));
|
|
1035
|
+
const [mounted, setMounted] = createSignal(false);
|
|
1036
|
+
const hostMonthKey = () => calendar.formatDateKey(calendar.startOfMonth(props.date, dateConfig()), dateConfig());
|
|
1037
|
+
const [focusMonthKey, setFocusMonthKey] = createSignal(untrack(hostMonthKey));
|
|
1013
1038
|
// The shown month and its grid change only with the month, so a refresh of the same month keeps every cell and its
|
|
1014
1039
|
// focus.
|
|
1015
|
-
const month = createMemo(() => zonedYearMonth(props.date, dateConfig()), undefined, {
|
|
1040
|
+
const month = createMemo(() => zonedYearMonth(continuous() ? calendar.parseCalendarDate(focusMonthKey(), dateConfig()) : props.date, dateConfig()), undefined, {
|
|
1016
1041
|
equals: (previous, next) => previous.year === next.year && previous.month === next.month
|
|
1017
1042
|
});
|
|
1018
1043
|
const weeks = createMemo(() => calendar.getMonthGrid(month().year, month().month, dateConfig()).map(week => week.map(day => ({
|
|
@@ -1024,17 +1049,12 @@ const MonthView = props => {
|
|
|
1024
1049
|
const weekdays = createMemo(() => calendar.weekdays(dateConfig()));
|
|
1025
1050
|
const todayKey = createMemo(() => calendar.formatDateKey(props.now, dateConfig()));
|
|
1026
1051
|
const items = createMemo(() => monthItems(props.events));
|
|
1027
|
-
const weekLayouts = createMemo(() => weeks().map(week => layoutMonthWeek(week.map(entry => entry.key), items().map(item => ({
|
|
1028
|
-
item,
|
|
1029
|
-
firstKey: item.firstKey,
|
|
1030
|
-
lastKey: item.lastKey,
|
|
1031
|
-
bar: item.bar
|
|
1032
|
-
})))));
|
|
1033
1052
|
const [capacities, setCapacities] = createSignal([]);
|
|
1034
1053
|
const [cellWidth, setCellWidth] = createSignal(0);
|
|
1035
1054
|
const [barFont, setBarFont] = createSignal("");
|
|
1036
1055
|
const [anchorKey, setAnchorKey] = createSignal(null);
|
|
1037
1056
|
const [focusKey, setFocusKey] = createSignal(null);
|
|
1057
|
+
const [focusedCellKey, setFocusedCellKey] = createSignal(null);
|
|
1038
1058
|
const [popover, setPopover] = createSignal(null);
|
|
1039
1059
|
/** Whether the quick create holds the focus; until then the grid keeps it. */
|
|
1040
1060
|
const [createActive, setCreateActive] = createSignal(false);
|
|
@@ -1060,13 +1080,479 @@ const MonthView = props => {
|
|
|
1060
1080
|
end: calendar.addDays(parseKey(range.last), 1, dateConfig()),
|
|
1061
1081
|
allDay: true
|
|
1062
1082
|
});
|
|
1063
|
-
const
|
|
1083
|
+
const hostKey = () => calendar.formatDateKey(props.date, dateConfig());
|
|
1084
|
+
const loadedRange = createMemo(() => {
|
|
1085
|
+
const range = props.owner.range;
|
|
1086
|
+
const keyOf = value => calendar.formatDateKey(parseDate(value, dateConfig()), dateConfig());
|
|
1087
|
+
return range ? {
|
|
1088
|
+
first: keyOf(range.from),
|
|
1089
|
+
to: keyOf(range.to)
|
|
1090
|
+
} : {
|
|
1091
|
+
first: hostMonthKey(),
|
|
1092
|
+
to: hostMonthKey()
|
|
1093
|
+
};
|
|
1094
|
+
});
|
|
1095
|
+
const loadedWeeks = createMemo(() => monthWeekKeys(loadedRange().first, loadedRange().to, dateConfig().firstDayOfWeek ?? 1));
|
|
1096
|
+
const loaded = key => key >= loadedRange().first && key < loadedRange().to;
|
|
1097
|
+
// The first paint starts at the month's first week. Mount adds the earlier weeks and positions synchronously.
|
|
1098
|
+
const trackWeeks = createMemo(() => {
|
|
1099
|
+
const all = loadedWeeks();
|
|
1100
|
+
const anchor = monthRowOf(all, hostMonthKey());
|
|
1101
|
+
return mounted() || anchor === undefined ? all : all.slice(anchor);
|
|
1102
|
+
});
|
|
1103
|
+
const [scrollTop, setScrollTop] = createSignal(0);
|
|
1104
|
+
const [rowHeight, setRowHeight] = createSignal(80);
|
|
1105
|
+
const [viewHeight, setViewHeight] = createSignal(400);
|
|
1106
|
+
const [labelShown, setLabelShown] = createSignal(false);
|
|
1107
|
+
const [pulseKey, setPulseKey] = createSignal("");
|
|
1108
|
+
let scroller;
|
|
1109
|
+
let weekdayElement;
|
|
1110
|
+
let ready = false;
|
|
1111
|
+
let positioned = false;
|
|
1112
|
+
let silentTop = null;
|
|
1113
|
+
let frame = 0;
|
|
1114
|
+
let labelTimer = 0;
|
|
1115
|
+
let reportTimer = 0;
|
|
1116
|
+
let queueTimer = 0;
|
|
1117
|
+
let glideTimer = 0;
|
|
1118
|
+
let arrivalTimer = 0;
|
|
1119
|
+
let pulseTimer = 0;
|
|
1120
|
+
/** The month that quick repeated steps head for; the next step and the arrows' links go on from it. */
|
|
1121
|
+
const [queuedMonth, setQueuedMonth] = createSignal(null);
|
|
1122
|
+
let pendingTarget = null;
|
|
1123
|
+
let pendingOrigin = null;
|
|
1124
|
+
let glideTarget = null;
|
|
1125
|
+
let pulseOnArrival = false;
|
|
1126
|
+
let reported = "";
|
|
1127
|
+
let reportedFocus = "";
|
|
1128
|
+
let askedEarlier = "";
|
|
1129
|
+
let askedLater = "";
|
|
1130
|
+
let exhaustedEarlier = "";
|
|
1131
|
+
let exhaustedLater = "";
|
|
1132
|
+
const scrollFocusDay = createMemo(() => {
|
|
1133
|
+
const first = focusMonthKey();
|
|
1134
|
+
const range = selection();
|
|
1135
|
+
const selected = range && range.last >= first ? range.first > first ? range.first : first : null;
|
|
1136
|
+
if (selected?.slice(0, 7) === first.slice(0, 7)) return selected;
|
|
1137
|
+
if (hostKey().slice(0, 7) === first.slice(0, 7)) return hostKey();
|
|
1138
|
+
return todayKey().slice(0, 7) === first.slice(0, 7) ? todayKey() : first;
|
|
1139
|
+
});
|
|
1140
|
+
const visibleRange = createMemo(() => {
|
|
1141
|
+
const weeks = trackWeeks();
|
|
1142
|
+
const rows = monthVisibleRows(scrollTop(), viewHeight(), rowHeight(), weeks.length);
|
|
1143
|
+
const first = weeks[rows.first] ?? focusMonthKey();
|
|
1144
|
+
return {
|
|
1145
|
+
first,
|
|
1146
|
+
last: addDayKeys(weeks[Math.max(rows.first, rows.end - 1)] ?? first, 6)
|
|
1147
|
+
};
|
|
1148
|
+
});
|
|
1149
|
+
const renderWindow = createMemo(() => mounted() ? monthRenderWindow(scrollTop(), viewHeight(), rowHeight(), trackWeeks().length) : {
|
|
1150
|
+
first: 0,
|
|
1151
|
+
end: Math.min(trackWeeks().length, MONTH_ROW_BLOCK * 2)
|
|
1152
|
+
}, undefined, {
|
|
1153
|
+
equals: (left, right) => left.first === right.first && left.end === right.end
|
|
1154
|
+
});
|
|
1155
|
+
/** The window's weeks, and those of the focused day, the selection's moving end, and an open popover's day. */
|
|
1156
|
+
const renderedWeeks = createMemo(() => {
|
|
1157
|
+
const weeks = trackWeeks();
|
|
1158
|
+
const window = renderWindow();
|
|
1159
|
+
const keys = new Set(weeks.slice(window.first, window.end));
|
|
1160
|
+
for (const key of [focusKey(), focusedCellKey(), popover()?.anchor.dataset.calendarDayKey]) {
|
|
1161
|
+
const row = key ? monthRowOf(weeks, key) : undefined;
|
|
1162
|
+
if (row !== undefined) keys.add(weeks[row]);
|
|
1163
|
+
}
|
|
1164
|
+
return [...keys].sort();
|
|
1165
|
+
});
|
|
1166
|
+
// Rows keep their elements, but the list moves a kept row when the window passes it, and a browser drops the focus
|
|
1167
|
+
// from an element that moves. The focused element takes it back once the rows are in place.
|
|
1168
|
+
let refocus = null;
|
|
1169
|
+
createComputed(on(renderedWeeks, () => {
|
|
1170
|
+
const active = typeof document === "undefined" ? null : document.activeElement;
|
|
1171
|
+
refocus = active && scroller?.contains(active) ? active : null;
|
|
1172
|
+
}, {
|
|
1173
|
+
defer: true
|
|
1174
|
+
}));
|
|
1175
|
+
createEffect(on(renderedWeeks, () => {
|
|
1176
|
+
const element = refocus;
|
|
1177
|
+
refocus = null;
|
|
1178
|
+
if (element instanceof HTMLElement && element.isConnected && document.activeElement !== element) element.focus({
|
|
1179
|
+
preventScroll: true
|
|
1180
|
+
});
|
|
1181
|
+
}, {
|
|
1182
|
+
defer: true
|
|
1183
|
+
}));
|
|
1184
|
+
const placeOfToday = () => {
|
|
1185
|
+
const weeks = trackWeeks();
|
|
1186
|
+
const row = monthRowOf(weeks, todayKey());
|
|
1187
|
+
return row === undefined ? todayKey() < (weeks[0] ?? focusMonthKey()) ? "up" : "down" : monthTodayDirection(row, scrollTop(), viewHeight(), rowHeight());
|
|
1188
|
+
};
|
|
1189
|
+
const measureScroll = () => {
|
|
1190
|
+
if (!scroller) return;
|
|
1191
|
+
const row = scroller.querySelector(".k2b-calendar-month__week");
|
|
1192
|
+
const height = row?.getBoundingClientRect().height;
|
|
1193
|
+
if (height && height > 0) setRowHeight(height);
|
|
1194
|
+
setViewHeight(Math.max(0, scroller.clientHeight - (weekdayElement?.getBoundingClientRect().height ?? 0)));
|
|
1195
|
+
};
|
|
1196
|
+
const loadMore = edge => {
|
|
1197
|
+
if (!ready) return;
|
|
1198
|
+
const range = loadedRange();
|
|
1199
|
+
const asked = edge === "earlier" ? range.first : range.to;
|
|
1200
|
+
const loader = edge === "earlier" ? props.owner.onLoadEarlier : props.owner.onLoadLater;
|
|
1201
|
+
if (!loader || (edge === "earlier" ? askedEarlier === asked || exhaustedEarlier === asked : askedLater === asked || exhaustedLater === asked)) return;
|
|
1202
|
+
if (edge === "earlier") askedEarlier = asked;else askedLater = asked;
|
|
1203
|
+
const result = loader();
|
|
1204
|
+
if (result !== null && (typeof result === "object" || typeof result === "function") && "then" in result && typeof result.then === "function") {
|
|
1205
|
+
const settled = () => {
|
|
1206
|
+
if (!ready || (edge === "earlier" ? loadedRange().first : loadedRange().to) !== asked) return;
|
|
1207
|
+
if (edge === "earlier") exhaustedEarlier = asked;else exhaustedLater = asked;
|
|
1208
|
+
const target = pendingOrigin === (edge === "earlier" ? -1 : 1) ? pendingTarget : null;
|
|
1209
|
+
if (target) {
|
|
1210
|
+
pendingTarget = null;
|
|
1211
|
+
pendingOrigin = null;
|
|
1212
|
+
setQueuedMonth(null);
|
|
1213
|
+
window.clearTimeout(queueTimer);
|
|
1214
|
+
}
|
|
1215
|
+
if (edge === "later" && glideTarget?.expires === Number.POSITIVE_INFINITY) {
|
|
1216
|
+
glideTarget = null;
|
|
1217
|
+
pulseOnArrival = false;
|
|
1218
|
+
setQueuedMonth(null);
|
|
1219
|
+
for (const timer of [queueTimer, glideTimer, arrivalTimer]) window.clearTimeout(timer);
|
|
1220
|
+
readScroll();
|
|
1221
|
+
}
|
|
1222
|
+
if (target) props.goToDate?.(parseKey(target));
|
|
1223
|
+
};
|
|
1224
|
+
void Promise.resolve(result).then(settled, settled);
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
/** Asks for more weeks near either end; weeks inserted above a running glide would move its way, so it waits. */
|
|
1228
|
+
const loadNearEdges = () => {
|
|
1229
|
+
if (!scroller) return;
|
|
1230
|
+
if (!glideTarget && scroller.scrollTop < MONTH_ROWS_IN_VIEW * rowHeight()) loadMore("earlier");
|
|
1231
|
+
if (scroller.scrollTop + viewHeight() > (trackWeeks().length - MONTH_ROWS_IN_VIEW * 2) * rowHeight()) loadMore("later");
|
|
1232
|
+
};
|
|
1233
|
+
const reportVisible = () => {
|
|
1234
|
+
if (!ready) return;
|
|
1235
|
+
const {
|
|
1236
|
+
first,
|
|
1237
|
+
last
|
|
1238
|
+
} = untrack(visibleRange);
|
|
1239
|
+
const focus = untrack(scrollFocusDay);
|
|
1240
|
+
const value = `${first}/${last}/${focus}`;
|
|
1241
|
+
if (reported === value) return;
|
|
1242
|
+
reported = value;
|
|
1243
|
+
window.clearTimeout(reportTimer);
|
|
1244
|
+
reportTimer = window.setTimeout(() => {
|
|
1245
|
+
reportedFocus = focus;
|
|
1246
|
+
props.owner.onVisibleDateChange?.(parseKey(first), parseKey(last), parseKey(focus));
|
|
1247
|
+
}, 250);
|
|
1248
|
+
};
|
|
1249
|
+
const keepLabel = () => {
|
|
1250
|
+
window.clearTimeout(labelTimer);
|
|
1251
|
+
labelTimer = window.setTimeout(() => setLabelShown(false), 650);
|
|
1252
|
+
};
|
|
1253
|
+
const readScroll = (showLabel = true) => {
|
|
1254
|
+
if (!scroller) return;
|
|
1255
|
+
const top = scroller.scrollTop;
|
|
1256
|
+
setScrollTop(top);
|
|
1257
|
+
const weeks = trackWeeks();
|
|
1258
|
+
const week = weeks[monthFocusRow(top, viewHeight(), rowHeight(), weeks.length)];
|
|
1259
|
+
if (week) {
|
|
1260
|
+
const next = monthOfWeek(week);
|
|
1261
|
+
if (next !== untrack(focusMonthKey)) {
|
|
1262
|
+
setFocusMonthKey(next);
|
|
1263
|
+
if (showLabel && ready) {
|
|
1264
|
+
setLabelShown(true);
|
|
1265
|
+
keepLabel();
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
reportVisible();
|
|
1270
|
+
};
|
|
1271
|
+
const pulseToday = () => {
|
|
1272
|
+
if (reducedMotion()) return;
|
|
1273
|
+
setPulseKey(todayKey());
|
|
1274
|
+
window.clearTimeout(pulseTimer);
|
|
1275
|
+
pulseTimer = window.setTimeout(() => setPulseKey(""), 1000);
|
|
1276
|
+
};
|
|
1277
|
+
const finishGlide = () => {
|
|
1278
|
+
if (!scroller) return;
|
|
1279
|
+
const target = glideTarget;
|
|
1280
|
+
const row = target ? monthRowOf(trackWeeks(), target.week) : undefined;
|
|
1281
|
+
// A clamped glide may still be waiting for more weeks below; scrollend is not arrival then.
|
|
1282
|
+
if (target && row !== undefined && Math.abs(scroller.scrollTop - (row * rowHeight() + target.offset)) > 1) return;
|
|
1283
|
+
glideTarget = null;
|
|
1284
|
+
if (pendingOrigin !== -1 && pendingOrigin !== 1) {
|
|
1285
|
+
setQueuedMonth(null);
|
|
1286
|
+
window.clearTimeout(queueTimer);
|
|
1287
|
+
}
|
|
1288
|
+
window.clearTimeout(glideTimer);
|
|
1289
|
+
window.clearTimeout(arrivalTimer);
|
|
1290
|
+
readScroll();
|
|
1291
|
+
// A glide that lands near an end asks for the next weeks there, as the reader's own scrolling does.
|
|
1292
|
+
if (target) loadNearEdges();
|
|
1293
|
+
if (pulseOnArrival) {
|
|
1294
|
+
pulseOnArrival = false;
|
|
1295
|
+
pulseToday();
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
const cancelGlide = () => {
|
|
1299
|
+
if (!scroller) return;
|
|
1300
|
+
if (pendingOrigin === -1 || pendingOrigin === 1) {
|
|
1301
|
+
pendingTarget = null;
|
|
1302
|
+
pendingOrigin = null;
|
|
1303
|
+
setQueuedMonth(null);
|
|
1304
|
+
window.clearTimeout(queueTimer);
|
|
1305
|
+
}
|
|
1306
|
+
if (!glideTarget) return;
|
|
1307
|
+
// A reader's wheel or touch takes over from navigation, including any target waiting for more weeks.
|
|
1308
|
+
glideTarget = null;
|
|
1309
|
+
pulseOnArrival = false;
|
|
1310
|
+
setQueuedMonth(null);
|
|
1311
|
+
for (const timer of [queueTimer, glideTimer, arrivalTimer]) window.clearTimeout(timer);
|
|
1312
|
+
scroller.scrollTo({
|
|
1313
|
+
top: scroller.scrollTop,
|
|
1314
|
+
behavior: "instant"
|
|
1315
|
+
});
|
|
1316
|
+
};
|
|
1317
|
+
const issueGlide = (top, smooth) => {
|
|
1318
|
+
if (!scroller) return;
|
|
1319
|
+
const maximum = Math.max(0, scroller.scrollHeight - scroller.clientHeight);
|
|
1320
|
+
const target = Math.max(0, Math.min(top, maximum));
|
|
1321
|
+
if (smooth && !reducedMotion() && Math.abs(target - scroller.scrollTop) > viewHeight() * 3) {
|
|
1322
|
+
scroller.scrollTop = target - Math.sign(target - scroller.scrollTop) * viewHeight();
|
|
1323
|
+
readScroll();
|
|
1324
|
+
}
|
|
1325
|
+
scroller.scrollTo({
|
|
1326
|
+
top: target,
|
|
1327
|
+
behavior: smooth && !reducedMotion() ? "smooth" : "instant"
|
|
1328
|
+
});
|
|
1329
|
+
if (top > maximum + 1) loadMore("later");
|
|
1330
|
+
if (!smooth || reducedMotion()) {
|
|
1331
|
+
readScroll();
|
|
1332
|
+
finishGlide();
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
const glide = (top, smooth = true) => {
|
|
1336
|
+
if (!scroller) return;
|
|
1337
|
+
const row = Math.max(0, Math.min(trackWeeks().length - 1, Math.floor(top / rowHeight())));
|
|
1338
|
+
const week = trackWeeks()[row];
|
|
1339
|
+
if (!week) return;
|
|
1340
|
+
// A target past the loaded weeks waits for them however long they take; the reader's own scrolling ends the wait.
|
|
1341
|
+
const waiting = top > scroller.scrollHeight - scroller.clientHeight + 1;
|
|
1342
|
+
glideTarget = {
|
|
1343
|
+
week,
|
|
1344
|
+
offset: top - row * rowHeight(),
|
|
1345
|
+
expires: waiting ? Number.POSITIVE_INFINITY : performance.now() + 1600
|
|
1346
|
+
};
|
|
1347
|
+
window.clearTimeout(glideTimer);
|
|
1348
|
+
window.clearTimeout(arrivalTimer);
|
|
1349
|
+
if (!waiting) glideTimer = window.setTimeout(() => {
|
|
1350
|
+
glideTarget = null;
|
|
1351
|
+
pulseOnArrival = false;
|
|
1352
|
+
}, 1600);
|
|
1353
|
+
arrivalTimer = window.setTimeout(finishGlide, 900);
|
|
1354
|
+
issueGlide(top, smooth);
|
|
1355
|
+
};
|
|
1356
|
+
const positionMonth = (key, smooth = true, reveal = false) => {
|
|
1357
|
+
if (!continuous() || !loaded(key) || !scroller) return false;
|
|
1358
|
+
const weeks = trackWeeks();
|
|
1359
|
+
const first = monthRowOf(weeks, `${key.slice(0, 7)}-01`);
|
|
1360
|
+
const row = monthRowOf(weeks, key);
|
|
1361
|
+
if (first === undefined || row === undefined) return false;
|
|
1362
|
+
const top = first * rowHeight();
|
|
1363
|
+
glide(reveal ? monthRevealTop(row, top, viewHeight(), rowHeight()) ?? top : top, smooth);
|
|
1364
|
+
return true;
|
|
1365
|
+
};
|
|
1366
|
+
const goToMonth = key => positionMonth(key, true, true);
|
|
1367
|
+
const stepMonth = direction => {
|
|
1368
|
+
if (!continuous() || !scroller) return false;
|
|
1369
|
+
const target = calendar.formatDateKey(calendar.addMonths(parseKey(queuedMonth() ?? focusMonthKey()), direction, dateConfig()), dateConfig());
|
|
1370
|
+
if (loaded(target)) {
|
|
1371
|
+
pendingTarget = null;
|
|
1372
|
+
pendingOrigin = null;
|
|
1373
|
+
if (!positionMonth(target)) return false;
|
|
1374
|
+
} else {
|
|
1375
|
+
// A month past the loaded weeks asks for them and waits; an end the host has reached goes through its navigation.
|
|
1376
|
+
const range = loadedRange();
|
|
1377
|
+
const later = direction === 1;
|
|
1378
|
+
const edge = later ? range.to : range.first;
|
|
1379
|
+
if (!(later ? props.owner.onLoadLater : props.owner.onLoadEarlier) || (later ? exhaustedLater : exhaustedEarlier) === edge) return false;
|
|
1380
|
+
pendingTarget = target;
|
|
1381
|
+
pendingOrigin = direction;
|
|
1382
|
+
loadMore(later ? "later" : "earlier");
|
|
1383
|
+
}
|
|
1384
|
+
// Instant positioning may finish during positionMonth; queue afterwards so rapid clicks still accumulate.
|
|
1385
|
+
setQueuedMonth(target);
|
|
1386
|
+
window.clearTimeout(queueTimer);
|
|
1387
|
+
// A glide that waits for more weeks keeps its month queued until it arrives or the reader scrolls.
|
|
1388
|
+
queueTimer = window.setTimeout(() => {
|
|
1389
|
+
if (pendingOrigin !== -1 && pendingOrigin !== 1 && glideTarget?.expires !== Number.POSITIVE_INFINITY) setQueuedMonth(null);
|
|
1390
|
+
}, 1200);
|
|
1391
|
+
return true;
|
|
1392
|
+
};
|
|
1393
|
+
const goToday = () => {
|
|
1394
|
+
if (!continuous() || !loaded(todayKey()) || !scroller) return false;
|
|
1395
|
+
pulseOnArrival = !reducedMotion();
|
|
1396
|
+
if (positionMonth(todayKey(), true, true)) return true;
|
|
1397
|
+
pulseOnArrival = false;
|
|
1398
|
+
return false;
|
|
1399
|
+
};
|
|
1400
|
+
const revealDay = key => {
|
|
1401
|
+
const row = monthRowOf(trackWeeks(), key);
|
|
1402
|
+
if (row === undefined || !scroller) return;
|
|
1403
|
+
const top = monthRevealTop(row, scroller.scrollTop, viewHeight(), rowHeight());
|
|
1404
|
+
if (top !== undefined) glide(top);
|
|
1405
|
+
};
|
|
1406
|
+
const onScroll = () => {
|
|
1407
|
+
if (!ready || !scroller) return;
|
|
1408
|
+
// Initial positioning and range rebasing are not the reader asking for more weeks.
|
|
1409
|
+
if (silentTop !== null && Math.abs(scroller.scrollTop - silentTop) < 1) return;
|
|
1410
|
+
silentTop = null;
|
|
1411
|
+
if (untrack(labelShown)) keepLabel();
|
|
1412
|
+
if (!frame) frame = requestAnimationFrame(() => {
|
|
1413
|
+
frame = 0;
|
|
1414
|
+
readScroll();
|
|
1415
|
+
if (!scroller) return;
|
|
1416
|
+
loadNearEdges();
|
|
1417
|
+
});
|
|
1418
|
+
};
|
|
1419
|
+
// Capture the old track before render effects change its height, then restore the same week and pixel below.
|
|
1420
|
+
let previousWeeks = [];
|
|
1421
|
+
let savedAnchor = null;
|
|
1422
|
+
createComputed(on(loadedWeeks, weeks => {
|
|
1423
|
+
if (!untrack(mounted) || !scroller) return;
|
|
1424
|
+
const top = scroller.scrollTop;
|
|
1425
|
+
const row = Math.floor(top / untrack(rowHeight));
|
|
1426
|
+
const week = previousWeeks[row];
|
|
1427
|
+
savedAnchor = week ? {
|
|
1428
|
+
week,
|
|
1429
|
+
delta: top - row * untrack(rowHeight)
|
|
1430
|
+
} : null;
|
|
1431
|
+
const next = week ? monthRowOf(weeks, week) : undefined;
|
|
1432
|
+
// Move the render window before DOM updates, so even a larger rebase retains the visible rows' elements.
|
|
1433
|
+
if (next !== undefined && savedAnchor) setScrollTop(next * untrack(rowHeight) + savedAnchor.delta);
|
|
1434
|
+
}, {
|
|
1435
|
+
defer: true
|
|
1436
|
+
}));
|
|
1437
|
+
createEffect(on(loadedWeeks, () => {
|
|
1438
|
+
if (!untrack(mounted) || !scroller) return;
|
|
1439
|
+
measureScroll();
|
|
1440
|
+
previousWeeks = untrack(trackWeeks);
|
|
1441
|
+
const row = savedAnchor ? monthRowOf(previousWeeks, savedAnchor.week) : undefined;
|
|
1442
|
+
const top = row !== undefined && savedAnchor ? row * untrack(rowHeight) + savedAnchor.delta : scroller.scrollTop;
|
|
1443
|
+
// Weeks added below move nothing, and writing the same position would stop a glide on its way.
|
|
1444
|
+
const moved = Math.abs(scroller.scrollTop - top) >= 1;
|
|
1445
|
+
if (moved) scroller.scrollTop = top;
|
|
1446
|
+
if (pendingTarget && loaded(pendingTarget)) {
|
|
1447
|
+
const key = pendingTarget;
|
|
1448
|
+
pendingTarget = null;
|
|
1449
|
+
pendingOrigin = null;
|
|
1450
|
+
positioned = positionMonth(key, positioned) || positioned;
|
|
1451
|
+
if (pendingKey === key) {
|
|
1452
|
+
pendingKey = null;
|
|
1453
|
+
select(key);
|
|
1454
|
+
queueMicrotask(() => focusCell(key));
|
|
1455
|
+
}
|
|
1456
|
+
} else {
|
|
1457
|
+
if (pendingTarget && (pendingOrigin === -1 || pendingOrigin === 1)) loadMore(pendingOrigin === -1 ? "earlier" : "later");
|
|
1458
|
+
// A glide goes on after the weeks above moved it, and one that waited at the end goes on into the new weeks.
|
|
1459
|
+
if (glideTarget && performance.now() < glideTarget.expires && (moved || glideTarget.expires === Number.POSITIVE_INFINITY)) {
|
|
1460
|
+
const target = monthRowOf(previousWeeks, glideTarget.week);
|
|
1461
|
+
if (target !== undefined) issueGlide(target * untrack(rowHeight) + glideTarget.offset, true);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
savedAnchor = null;
|
|
1465
|
+
silentTop = scroller.scrollTop;
|
|
1466
|
+
readScroll(false);
|
|
1467
|
+
}, {
|
|
1468
|
+
defer: true
|
|
1469
|
+
}));
|
|
1470
|
+
createEffect(on(hostKey, key => {
|
|
1471
|
+
if (!continuous() || !untrack(mounted) || !scroller) return;
|
|
1472
|
+
if (key === reportedFocus) {
|
|
1473
|
+
if (pendingOrigin === "host") {
|
|
1474
|
+
pendingTarget = null;
|
|
1475
|
+
pendingOrigin = null;
|
|
1476
|
+
}
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
pendingTarget = loaded(key) ? null : key;
|
|
1480
|
+
pendingOrigin = pendingTarget ? "host" : null;
|
|
1481
|
+
if (pendingTarget) return;
|
|
1482
|
+
const visible = untrack(visibleRange);
|
|
1483
|
+
if (key.slice(0, 7) !== untrack(focusMonthKey).slice(0, 7) || key < visible.first || key > visible.last) positionMonth(key);
|
|
1484
|
+
if (pendingKey === key) {
|
|
1485
|
+
pendingKey = null;
|
|
1486
|
+
select(key);
|
|
1487
|
+
queueMicrotask(() => focusCell(key));
|
|
1488
|
+
}
|
|
1489
|
+
}, {
|
|
1490
|
+
defer: true
|
|
1491
|
+
}));
|
|
1492
|
+
createEffect(on(scrollFocusDay, () => {
|
|
1493
|
+
if (continuous()) reportVisible();
|
|
1494
|
+
}, {
|
|
1495
|
+
defer: true
|
|
1496
|
+
}));
|
|
1497
|
+
// The scrolling starts once the grid is on the page, also when a host passes `range` only later.
|
|
1498
|
+
createEffect(on(continuous, active => {
|
|
1499
|
+
if (!active || !scroller) return;
|
|
1500
|
+
setMounted(true);
|
|
1501
|
+
measureScroll();
|
|
1502
|
+
previousWeeks = trackWeeks();
|
|
1503
|
+
const row = monthRowOf(previousWeeks, hostMonthKey());
|
|
1504
|
+
if (row !== undefined && loaded(hostKey())) scroller.scrollTop = row * rowHeight();
|
|
1505
|
+
// Too few weeks below the month, such as the days of another view while the month's own load, cannot put its
|
|
1506
|
+
// first week on top yet; the month goes there once its weeks arrive.
|
|
1507
|
+
positioned = row !== undefined && Math.abs(scroller.scrollTop - row * rowHeight()) < 1;
|
|
1508
|
+
if (!positioned) {
|
|
1509
|
+
pendingTarget = hostKey();
|
|
1510
|
+
pendingOrigin = "mount";
|
|
1511
|
+
}
|
|
1512
|
+
readScroll(false);
|
|
1513
|
+
silentTop = scroller.scrollTop;
|
|
1514
|
+
ready = true;
|
|
1515
|
+
reportVisible();
|
|
1516
|
+
scroller.addEventListener("scrollend", finishGlide);
|
|
1517
|
+
const resize = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(() => {
|
|
1518
|
+
if (!scroller) return;
|
|
1519
|
+
const height = untrack(rowHeight);
|
|
1520
|
+
const position = scroller.scrollTop / height;
|
|
1521
|
+
measureScroll();
|
|
1522
|
+
if (height !== untrack(rowHeight)) {
|
|
1523
|
+
scroller.scrollTop = position * untrack(rowHeight);
|
|
1524
|
+
if (glideTarget) {
|
|
1525
|
+
const target = monthRowOf(untrack(trackWeeks), glideTarget.week);
|
|
1526
|
+
if (target !== undefined) issueGlide(target * untrack(rowHeight) + glideTarget.offset, true);
|
|
1527
|
+
}
|
|
1528
|
+
silentTop = scroller.scrollTop;
|
|
1529
|
+
}
|
|
1530
|
+
readScroll(false);
|
|
1531
|
+
});
|
|
1532
|
+
resize?.observe(scroller);
|
|
1533
|
+
const element = scroller;
|
|
1534
|
+
onCleanup(() => {
|
|
1535
|
+
resize?.disconnect();
|
|
1536
|
+
element.removeEventListener("scrollend", finishGlide);
|
|
1537
|
+
for (const timer of [labelTimer, reportTimer, queueTimer, glideTimer, arrivalTimer, pulseTimer]) window.clearTimeout(timer);
|
|
1538
|
+
if (frame) cancelAnimationFrame(frame);
|
|
1539
|
+
frame = 0;
|
|
1540
|
+
ready = false;
|
|
1541
|
+
setMounted(false);
|
|
1542
|
+
});
|
|
1543
|
+
}));
|
|
1544
|
+
const visibleKeys = createMemo(() => continuous() ? renderedWeeks().flatMap(key => Array.from({
|
|
1545
|
+
length: 7
|
|
1546
|
+
}, (_, day) => addDayKeys(key, day))) : weeks().flatMap(week => week.map(entry => entry.key)));
|
|
1064
1547
|
const rovingKey = createMemo(() => {
|
|
1065
1548
|
const keys = visibleKeys();
|
|
1066
|
-
const focus = focusKey();
|
|
1549
|
+
const focus = focusKey() ?? (continuous() ? focusedCellKey() : null);
|
|
1067
1550
|
if (focus && keys.includes(focus)) return focus;
|
|
1068
|
-
if (keys.includes(todayKey())) return todayKey();
|
|
1069
|
-
|
|
1551
|
+
if (keys.includes(todayKey()) && (!continuous() || todayKey() >= visibleRange().first && todayKey() <= visibleRange().last)) return todayKey();
|
|
1552
|
+
const first = calendar.formatDateKey(zonedMonthDate(month().year, month().month, dateConfig()), dateConfig());
|
|
1553
|
+
if (!continuous() || keys.includes(first)) return first;
|
|
1554
|
+
const visible = visibleRange();
|
|
1555
|
+
return keys.find(key => key.slice(0, 7) === first.slice(0, 7) && key >= visible.first && key <= visible.last) ?? keys.find(key => key >= visible.first && key <= visible.last) ?? keys[0] ?? first;
|
|
1070
1556
|
});
|
|
1071
1557
|
const dropRange = createMemo(() => {
|
|
1072
1558
|
const preview = movePreview();
|
|
@@ -1091,8 +1577,7 @@ const MonthView = props => {
|
|
|
1091
1577
|
setAnchorKey(anchor);
|
|
1092
1578
|
setFocusKey(focus);
|
|
1093
1579
|
};
|
|
1094
|
-
//
|
|
1095
|
-
// goes with the view, so switching to another view reports that nothing is selected.
|
|
1580
|
+
// Selection survives scrolling; only paging starts a month without it. Switching views clears the host's selection.
|
|
1096
1581
|
createEffect(on(selection, range => props.owner.onSelectionChange?.(range ? rangeOf(range) : null), {
|
|
1097
1582
|
defer: true
|
|
1098
1583
|
}));
|
|
@@ -1101,6 +1586,7 @@ const MonthView = props => {
|
|
|
1101
1586
|
});
|
|
1102
1587
|
createEffect(on(selection, range => props.onFocusDay?.(range ? parseKey(range.first) : null)));
|
|
1103
1588
|
createEffect(on(month, () => {
|
|
1589
|
+
if (continuous()) return;
|
|
1104
1590
|
setPopover(null);
|
|
1105
1591
|
const key = pendingKey;
|
|
1106
1592
|
pendingKey = null;
|
|
@@ -1191,6 +1677,8 @@ const MonthView = props => {
|
|
|
1191
1677
|
const focusCell = key => cells.get(key)?.focus({
|
|
1192
1678
|
preventScroll: true
|
|
1193
1679
|
});
|
|
1680
|
+
/** Whether the focus is in the popover, or fell to the page as it hid: only then does a close return it. */
|
|
1681
|
+
const focusInPopover = () => popoverElement?.contains(document.activeElement) || document.activeElement === document.body;
|
|
1194
1682
|
const closePopover = (restoreFocus = true) => {
|
|
1195
1683
|
if (!popover()) return;
|
|
1196
1684
|
setPopover(null);
|
|
@@ -1222,6 +1710,11 @@ const MonthView = props => {
|
|
|
1222
1710
|
popoverFocusable()?.focus();
|
|
1223
1711
|
return true;
|
|
1224
1712
|
};
|
|
1713
|
+
/**
|
|
1714
|
+
* The day to create on without a selection. The month that scrolls takes the day it stands for, today or the 1st of
|
|
1715
|
+
* the month in focus, never a day the keyboard last visited in another month.
|
|
1716
|
+
*/
|
|
1717
|
+
const unselectedKey = () => continuous() ? scrollFocusDay() : rovingKey();
|
|
1225
1718
|
/** Enter, a double-click, and N create on the selection, with the quick create or the host's own create action. */
|
|
1226
1719
|
const createOnSelection = () => {
|
|
1227
1720
|
const range = selection();
|
|
@@ -1234,8 +1727,8 @@ const MonthView = props => {
|
|
|
1234
1727
|
onMount(() => props.register?.({
|
|
1235
1728
|
quickCreate: create => {
|
|
1236
1729
|
const range = selection() ?? {
|
|
1237
|
-
first:
|
|
1238
|
-
last:
|
|
1730
|
+
first: unselectedKey(),
|
|
1731
|
+
last: unselectedKey()
|
|
1239
1732
|
};
|
|
1240
1733
|
select(range.first, range.last);
|
|
1241
1734
|
if (!openCreate(range, {
|
|
@@ -1244,10 +1737,18 @@ const MonthView = props => {
|
|
|
1244
1737
|
})) props.owner.onSlotActivate?.(rangeOf(range));
|
|
1245
1738
|
},
|
|
1246
1739
|
createTarget: () => rangeOf(selection() ?? {
|
|
1247
|
-
first:
|
|
1248
|
-
last:
|
|
1740
|
+
first: unselectedKey(),
|
|
1741
|
+
last: unselectedKey()
|
|
1249
1742
|
}),
|
|
1250
|
-
typing: () => popover()?.kind === "create" && !createActive()
|
|
1743
|
+
typing: () => popover()?.kind === "create" && !createActive(),
|
|
1744
|
+
continuous,
|
|
1745
|
+
focusMonth: () => parseKey(focusMonthKey()),
|
|
1746
|
+
stepFrom: () => parseKey(queuedMonth() ?? focusMonthKey()),
|
|
1747
|
+
focusDay: () => parseKey(scrollFocusDay()),
|
|
1748
|
+
step: stepMonth,
|
|
1749
|
+
goTo: goToMonth,
|
|
1750
|
+
today: goToday,
|
|
1751
|
+
todayDirection: placeOfToday
|
|
1251
1752
|
}));
|
|
1252
1753
|
onCleanup(() => props.register?.(null));
|
|
1253
1754
|
const openDayList = key => {
|
|
@@ -1282,12 +1783,15 @@ const MonthView = props => {
|
|
|
1282
1783
|
}
|
|
1283
1784
|
};
|
|
1284
1785
|
const moveFocus = (key, extend) => {
|
|
1285
|
-
if (!visibleKeys().includes(key)) {
|
|
1786
|
+
if (continuous() ? !loaded(key) : !visibleKeys().includes(key)) {
|
|
1286
1787
|
pageTo(key);
|
|
1287
1788
|
return;
|
|
1288
1789
|
}
|
|
1289
1790
|
if (extend) select(anchorKey() ?? focusKey() ?? key, key);else select(key);
|
|
1290
|
-
|
|
1791
|
+
if (continuous()) {
|
|
1792
|
+
revealDay(key);
|
|
1793
|
+
queueMicrotask(() => focusCell(key));
|
|
1794
|
+
} else focusCell(key);
|
|
1291
1795
|
followSelection();
|
|
1292
1796
|
};
|
|
1293
1797
|
const onCellKeyDown = (event, key) => {
|
|
@@ -1316,7 +1820,12 @@ const MonthView = props => {
|
|
|
1316
1820
|
}
|
|
1317
1821
|
if (event.key === "PageUp" || event.key === "PageDown") {
|
|
1318
1822
|
event.preventDefault();
|
|
1319
|
-
|
|
1823
|
+
const target = calendar.formatDateKey(addMonthsClamped(day, event.key === "PageUp" ? -1 : 1, dateConfig()), dateConfig());
|
|
1824
|
+
if (continuous() && loaded(target)) {
|
|
1825
|
+
moveFocus(target, event.shiftKey);
|
|
1826
|
+
// The month's first week goes on top, unless the day lies in a sixth week that would then stay out of view.
|
|
1827
|
+
goToMonth(target);
|
|
1828
|
+
} else pageTo(target);
|
|
1320
1829
|
return;
|
|
1321
1830
|
}
|
|
1322
1831
|
if (event.key === "Enter" || (event.key === "n" || event.key === "N") && !event.shiftKey) {
|
|
@@ -1386,6 +1895,9 @@ const MonthView = props => {
|
|
|
1386
1895
|
cancelInteraction?.();
|
|
1387
1896
|
cancelInteraction = startCalendarPointerSession({
|
|
1388
1897
|
event,
|
|
1898
|
+
scrollContainer: continuous() ? scroller : undefined,
|
|
1899
|
+
// A drag along the last row on screen selects its days; the view scrolls once the pointer came from inside.
|
|
1900
|
+
armAutoScroll: true,
|
|
1389
1901
|
resolve: (clientX, clientY) => dayKeyAtPoint(clientX, clientY),
|
|
1390
1902
|
onActivate: () => {
|
|
1391
1903
|
suppressClickUntil = performance.now() + 400;
|
|
@@ -1394,6 +1906,8 @@ const MonthView = props => {
|
|
|
1394
1906
|
},
|
|
1395
1907
|
onPreview: current => select(key, current),
|
|
1396
1908
|
onCommit: current => {
|
|
1909
|
+
// The click that ends a long drag, such as one that scrolled the view, must not select the pressed day again.
|
|
1910
|
+
suppressClickUntil = performance.now() + 400;
|
|
1397
1911
|
select(key, current);
|
|
1398
1912
|
focusCell(current);
|
|
1399
1913
|
const range = orderedSelection(key, current);
|
|
@@ -1413,8 +1927,8 @@ const MonthView = props => {
|
|
|
1413
1927
|
const menuItems = createMemo(() => {
|
|
1414
1928
|
if (!hasMenu()) return [];
|
|
1415
1929
|
const range = selection() ?? {
|
|
1416
|
-
first:
|
|
1417
|
-
last:
|
|
1930
|
+
first: unselectedKey(),
|
|
1931
|
+
last: unselectedKey()
|
|
1418
1932
|
};
|
|
1419
1933
|
const own = props.owner.selectionMenu?.(rangeOf(range), {
|
|
1420
1934
|
quickCreate: create => {
|
|
@@ -1464,6 +1978,8 @@ const MonthView = props => {
|
|
|
1464
1978
|
cancelInteraction?.();
|
|
1465
1979
|
cancelInteraction = startCalendarPointerSession({
|
|
1466
1980
|
event: pointerEvent,
|
|
1981
|
+
scrollContainer: continuous() ? scroller : undefined,
|
|
1982
|
+
armAutoScroll: true,
|
|
1467
1983
|
resolve: (clientX, clientY) => {
|
|
1468
1984
|
const key = dayKeyAtPoint(clientX, clientY);
|
|
1469
1985
|
if (!key) return null;
|
|
@@ -1483,6 +1999,9 @@ const MonthView = props => {
|
|
|
1483
1999
|
},
|
|
1484
2000
|
onPreview: setMovePreview,
|
|
1485
2001
|
onCommit: next => {
|
|
2002
|
+
// The click that ends a long move, such as one that scrolled the view, must not open the entry.
|
|
2003
|
+
markDragged();
|
|
2004
|
+
suppressClickUntil = performance.now() + 400;
|
|
1486
2005
|
clearMove();
|
|
1487
2006
|
if (eventTimeChanged(event, next)) props.owner.onEventDrop?.(event, next);
|
|
1488
2007
|
},
|
|
@@ -1570,235 +2089,264 @@ const MonthView = props => {
|
|
|
1570
2089
|
if (linkedItem() === item.key) setLinkedItem("");
|
|
1571
2090
|
}
|
|
1572
2091
|
});
|
|
1573
|
-
const
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
get children() {
|
|
1601
|
-
return _$ssr(_tmpl$22, _$escape(_$createComponent(Show, {
|
|
1602
|
-
get when() {
|
|
1603
|
-
return weekHref();
|
|
1604
|
-
},
|
|
1605
|
-
get fallback() {
|
|
1606
|
-
return _$createComponent(Show, {
|
|
1607
|
-
get when() {
|
|
1608
|
-
return canOpenView("week");
|
|
1609
|
-
},
|
|
1610
|
-
get fallback() {
|
|
1611
|
-
return weekNumber();
|
|
1612
|
-
},
|
|
1613
|
-
get children() {
|
|
1614
|
-
return _$ssr(_tmpl$24, _$ssrAttribute("title", _$escape(calendarMessages().calendarOpenWeekNumber({
|
|
1615
|
-
week: weekNumber()
|
|
1616
|
-
}), true), false) + _$ssrAttribute("aria-label", _$escape(calendarMessages().calendarOpenWeekNumber({
|
|
1617
|
-
week: weekNumber()
|
|
1618
|
-
}), true), false), _$escape(weekNumber()));
|
|
1619
|
-
}
|
|
1620
|
-
});
|
|
1621
|
-
},
|
|
1622
|
-
children: href => _$createComponent(CalendarNavigationLink, {
|
|
1623
|
-
get owner() {
|
|
1624
|
-
return props.owner;
|
|
1625
|
-
},
|
|
1626
|
-
get href() {
|
|
1627
|
-
return href();
|
|
2092
|
+
const weekRow = (week, weekIndex) => {
|
|
2093
|
+
const layout = createMemo(() => layoutMonthWeek(week().map(entry => entry.key), items().map(item => ({
|
|
2094
|
+
item,
|
|
2095
|
+
firstKey: item.firstKey,
|
|
2096
|
+
lastKey: item.lastKey,
|
|
2097
|
+
bar: item.bar
|
|
2098
|
+
}))));
|
|
2099
|
+
// The continuous rows are all as high as the first, so they share its measured capacity.
|
|
2100
|
+
const capacity = () => capacities()[continuous() ? 0 : weekIndex()] ?? MONTH_DEFAULT_LANES;
|
|
2101
|
+
const fit = createMemo(() => fitMonthWeek(layout(), capacity()));
|
|
2102
|
+
const weekHref = () => viewHref(week()[0].key, "week");
|
|
2103
|
+
const weekNumber = () => zonedWeekNumber(week()[0].day, dateConfig());
|
|
2104
|
+
return _$ssr(_tmpl$20, _$ssrAttribute("data-week-key", continuous() ? _$escape(week()[0]?.key, true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-rowindex", continuous() ? _$escape(weekIndex(), true) + 2 : _$escape(undefined, true), false), _$ssrStyle(continuous() ? {
|
|
2105
|
+
"--k2b-calendar-week-index": String(weekIndex())
|
|
2106
|
+
} : undefined), _$ssrAttribute("data-week-numbers", props.owner.withWeekNumbers ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
|
|
2107
|
+
get when() {
|
|
2108
|
+
return props.owner.withWeekNumbers;
|
|
2109
|
+
},
|
|
2110
|
+
get children() {
|
|
2111
|
+
return _$ssr(_tmpl$19, _$escape(_$createComponent(Show, {
|
|
2112
|
+
get when() {
|
|
2113
|
+
return weekHref();
|
|
2114
|
+
},
|
|
2115
|
+
get fallback() {
|
|
2116
|
+
return _$createComponent(Show, {
|
|
2117
|
+
get when() {
|
|
2118
|
+
return canOpenView("week");
|
|
1628
2119
|
},
|
|
1629
|
-
get
|
|
1630
|
-
return
|
|
1631
|
-
class: "k2b-calendar-month__week-link",
|
|
1632
|
-
tabIndex: -1,
|
|
1633
|
-
title: calendarMessages().calendarOpenWeekNumber({
|
|
1634
|
-
week: weekNumber()
|
|
1635
|
-
}),
|
|
1636
|
-
"aria-label": calendarMessages().calendarOpenWeekNumber({
|
|
1637
|
-
week: weekNumber()
|
|
1638
|
-
})
|
|
1639
|
-
};
|
|
2120
|
+
get fallback() {
|
|
2121
|
+
return weekNumber();
|
|
1640
2122
|
},
|
|
1641
2123
|
get children() {
|
|
1642
|
-
return
|
|
2124
|
+
return _$ssr(_tmpl$21, _$ssrAttribute("title", _$escape(calendarMessages().calendarOpenWeekNumber({
|
|
2125
|
+
week: weekNumber()
|
|
2126
|
+
}), true), false) + _$ssrAttribute("aria-label", _$escape(calendarMessages().calendarOpenWeekNumber({
|
|
2127
|
+
week: weekNumber()
|
|
2128
|
+
}), true), false), _$escape(weekNumber()));
|
|
1643
2129
|
}
|
|
1644
|
-
})
|
|
1645
|
-
}
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
children: ({
|
|
1650
|
-
day,
|
|
1651
|
-
key
|
|
1652
|
-
}, column) => {
|
|
1653
|
-
const dayBadge = props.owner.dayBadges?.[key];
|
|
1654
|
-
const sameMonth = calendar.isSameMonth(day, props.date, dateConfig());
|
|
1655
|
-
const label = dayLabel(day);
|
|
1656
|
-
const bars = createMemo(() => fit().bars.filter(bar => bar.startColumn === column()));
|
|
1657
|
-
const cell = () => fit().cells[column()] ?? {
|
|
1658
|
-
top: 0,
|
|
1659
|
-
shown: [],
|
|
1660
|
-
hidden: 0
|
|
1661
|
-
};
|
|
1662
|
-
return _$ssr(_tmpl$26, _$ssrAttribute("tabindex", rovingKey() === key ? 0 : -1, false) + _$ssrAttribute("aria-label", _$escape(label, true), false) + _$ssrAttribute("aria-selected", within(selection(), key) ? "true" : "false", false) + _$ssrAttribute("aria-current", key === todayKey() ? "date" : _$escape(undefined, true), false) + _$ssrAttribute("data-calendar-day-key", _$escape(key, true), false) + _$ssrAttribute("data-outside", !sameMonth ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-weekend", column() > 4 ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-past", key < todayKey() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-selected", _$escape(selectionPart(key), true), false) + _$ssrAttribute("data-drop-preview", within(dropRange(), key) ? "true" : _$escape(undefined, true), false), _$ssrAttribute("data-today", key === todayKey() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-outside", !sameMonth ? "true" : _$escape(undefined, true), false), _$escape(calendar.formatDayNumber(day, dateConfig())), _$escape(_$createComponent(Show, {
|
|
1663
|
-
when: dayBadge,
|
|
1664
|
-
children: badge => _$ssr(_tmpl$17, _$escape(_$createComponent(Show, {
|
|
1665
|
-
get when() {
|
|
1666
|
-
return badge().icon;
|
|
1667
|
-
},
|
|
1668
|
-
children: icon => _$ssr(_tmpl$2, `k2b-calendar-month__badge-icon ti ti-${_$escape(icon(), true)}`)
|
|
1669
|
-
})), _$escape(badge().label))
|
|
1670
|
-
})), _$escape(_$createComponent(For, {
|
|
1671
|
-
get each() {
|
|
1672
|
-
return bars();
|
|
2130
|
+
});
|
|
2131
|
+
},
|
|
2132
|
+
children: href => _$createComponent(CalendarNavigationLink, {
|
|
2133
|
+
get owner() {
|
|
2134
|
+
return props.owner;
|
|
1673
2135
|
},
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
2136
|
+
get href() {
|
|
2137
|
+
return href();
|
|
2138
|
+
},
|
|
2139
|
+
get anchorProps() {
|
|
2140
|
+
return {
|
|
2141
|
+
class: "k2b-calendar-month__week-link",
|
|
2142
|
+
tabIndex: -1,
|
|
2143
|
+
title: calendarMessages().calendarOpenWeekNumber({
|
|
2144
|
+
week: weekNumber()
|
|
2145
|
+
}),
|
|
2146
|
+
"aria-label": calendarMessages().calendarOpenWeekNumber({
|
|
2147
|
+
week: weekNumber()
|
|
2148
|
+
})
|
|
1685
2149
|
};
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
return {
|
|
1690
|
-
"--k2b-calendar-span": String(span),
|
|
1691
|
-
"--k2b-calendar-row": String(bar.lane)
|
|
1692
|
-
};
|
|
1693
|
-
},
|
|
1694
|
-
"data-bar": "true",
|
|
1695
|
-
get ["data-linked"]() {
|
|
1696
|
-
return linkedItem() === bar.item.key && bar.item.firstKey !== bar.item.lastKey ? "true" : undefined;
|
|
1697
|
-
},
|
|
1698
|
-
get ["data-continues-before"]() {
|
|
1699
|
-
return bar.continuesBefore ? "true" : undefined;
|
|
1700
|
-
},
|
|
1701
|
-
get ["data-continues-after"]() {
|
|
1702
|
-
return bar.continuesAfter ? "true" : undefined;
|
|
1703
|
-
}
|
|
1704
|
-
}, () => linkProps(bar.item)), _$escape(_$createComponent(EventChip, {
|
|
1705
|
-
get event() {
|
|
1706
|
-
return bar.item.event;
|
|
1707
|
-
},
|
|
1708
|
-
get owner() {
|
|
1709
|
-
return props.owner;
|
|
1710
|
-
},
|
|
1711
|
-
get href() {
|
|
1712
|
-
return eventHref(props.owner, bar.item.event);
|
|
1713
|
-
},
|
|
1714
|
-
get label() {
|
|
1715
|
-
return itemLabel(bar.item);
|
|
1716
|
-
},
|
|
1717
|
-
compact: true,
|
|
1718
|
-
bar: true,
|
|
1719
|
-
get continuesBefore() {
|
|
1720
|
-
return bar.continuesBefore;
|
|
1721
|
-
},
|
|
1722
|
-
get continuesAfter() {
|
|
1723
|
-
return bar.continuesAfter;
|
|
1724
|
-
},
|
|
1725
|
-
get hintStart() {
|
|
1726
|
-
return startHint();
|
|
1727
|
-
},
|
|
1728
|
-
get hintEnd() {
|
|
1729
|
-
return endHint();
|
|
1730
|
-
},
|
|
1731
|
-
get moving() {
|
|
1732
|
-
return movingEventId() === bar.item.event.id;
|
|
1733
|
-
},
|
|
1734
|
-
get onMovePointerDown() {
|
|
1735
|
-
return props.owner.onEventDrop ? (pointerEvent, markDragged) => startMove(pointerEvent, bar.item, markDragged) : undefined;
|
|
1736
|
-
}
|
|
1737
|
-
})), false);
|
|
2150
|
+
},
|
|
2151
|
+
get children() {
|
|
2152
|
+
return weekNumber();
|
|
1738
2153
|
}
|
|
1739
|
-
})
|
|
1740
|
-
|
|
1741
|
-
|
|
2154
|
+
})
|
|
2155
|
+
})));
|
|
2156
|
+
}
|
|
2157
|
+
})), _$escape(_$createComponent(For, {
|
|
2158
|
+
get each() {
|
|
2159
|
+
return week();
|
|
2160
|
+
},
|
|
2161
|
+
children: ({
|
|
2162
|
+
day,
|
|
2163
|
+
key
|
|
2164
|
+
}, column) => {
|
|
2165
|
+
const dayBadge = props.owner.dayBadges?.[key];
|
|
2166
|
+
const sameMonth = () => calendar.isSameMonth(day, continuous() ? parseKey(focusMonthKey()) : props.date, dateConfig());
|
|
2167
|
+
const label = dayLabel(day);
|
|
2168
|
+
const bars = createMemo(() => fit().bars.filter(bar => bar.startColumn === column()));
|
|
2169
|
+
const cell = () => fit().cells[column()] ?? {
|
|
2170
|
+
top: 0,
|
|
2171
|
+
shown: [],
|
|
2172
|
+
hidden: 0
|
|
2173
|
+
};
|
|
2174
|
+
return _$ssr(_tmpl$23, _$ssrAttribute("tabindex", rovingKey() === key ? 0 : -1, false) + _$ssrAttribute("aria-label", _$escape(label, true), false) + _$ssrAttribute("aria-selected", within(selection(), key) ? "true" : "false", false) + _$ssrAttribute("aria-current", key === todayKey() ? "date" : _$escape(undefined, true), false) + _$ssrAttribute("data-calendar-day-key", _$escape(key, true), false) + _$ssrAttribute("data-outside", !sameMonth() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-month-first", continuous() && key.endsWith("-01") ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-month-top", continuous() && Number(key.slice(8)) <= 7 ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-weekend", column() > 4 ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-past", key < todayKey() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-selected", _$escape(selectionPart(key), true), false) + _$ssrAttribute("data-drop-preview", within(dropRange(), key) ? "true" : _$escape(undefined, true), false), _$ssrAttribute("data-pulse", continuous() && pulseKey() === key ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-today", key === todayKey() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-outside", !sameMonth() ? "true" : _$escape(undefined, true), false), continuous() && key.endsWith("-01") ? _$escape(shortDayLabel(key).replace(/\.$/, "")) : _$escape(calendar.formatDayNumber(day, dateConfig())), _$escape(_$createComponent(Show, {
|
|
2175
|
+
when: dayBadge,
|
|
2176
|
+
children: badge => _$ssr(_tmpl$17, _$escape(_$createComponent(Show, {
|
|
2177
|
+
get when() {
|
|
2178
|
+
return badge().icon;
|
|
1742
2179
|
},
|
|
1743
|
-
children:
|
|
2180
|
+
children: icon => _$ssr(_tmpl$2, `k2b-calendar-month__badge-icon ti ti-${_$escape(icon(), true)}`)
|
|
2181
|
+
})), _$escape(badge().label))
|
|
2182
|
+
})), _$escape(_$createComponent(For, {
|
|
2183
|
+
get each() {
|
|
2184
|
+
return bars();
|
|
2185
|
+
},
|
|
2186
|
+
children: bar => {
|
|
2187
|
+
const span = bar.endColumn - bar.startColumn + 1;
|
|
2188
|
+
const startHint = () => {
|
|
2189
|
+
if (!bar.continuesBefore) return undefined;
|
|
2190
|
+
const hint = calendarMessages().calendarContinuesFrom(hintDate(bar.item.firstKey));
|
|
2191
|
+
return hintFits(bar.item.event.title, hint, span) ? hint : undefined;
|
|
2192
|
+
};
|
|
2193
|
+
const endHint = () => {
|
|
2194
|
+
if (!bar.continuesAfter) return undefined;
|
|
2195
|
+
const hint = calendarMessages().calendarContinuesUntil(hintDate(bar.item.lastKey));
|
|
2196
|
+
return hintFits(`${bar.item.event.title}${startHint() ?? ""}`, hint, span) ? hint : undefined;
|
|
2197
|
+
};
|
|
2198
|
+
return _$ssrElement("div", _$mergeProps({
|
|
2199
|
+
"class": "k2b-calendar-month__segment",
|
|
2200
|
+
get style() {
|
|
2201
|
+
return {
|
|
2202
|
+
"--k2b-calendar-span": String(span),
|
|
2203
|
+
"--k2b-calendar-row": String(bar.lane)
|
|
2204
|
+
};
|
|
2205
|
+
},
|
|
2206
|
+
"data-bar": "true",
|
|
2207
|
+
get ["data-linked"]() {
|
|
2208
|
+
return linkedItem() === bar.item.key && bar.item.firstKey !== bar.item.lastKey ? "true" : undefined;
|
|
2209
|
+
},
|
|
2210
|
+
get ["data-continues-before"]() {
|
|
2211
|
+
return bar.continuesBefore ? "true" : undefined;
|
|
2212
|
+
},
|
|
2213
|
+
get ["data-continues-after"]() {
|
|
2214
|
+
return bar.continuesAfter ? "true" : undefined;
|
|
2215
|
+
}
|
|
2216
|
+
}, () => linkProps(bar.item)), _$escape(_$createComponent(EventChip, {
|
|
1744
2217
|
get event() {
|
|
1745
|
-
return item.event;
|
|
2218
|
+
return bar.item.event;
|
|
1746
2219
|
},
|
|
1747
2220
|
get owner() {
|
|
1748
2221
|
return props.owner;
|
|
1749
2222
|
},
|
|
1750
2223
|
get href() {
|
|
1751
|
-
return eventHref(props.owner, item.event);
|
|
2224
|
+
return eventHref(props.owner, bar.item.event);
|
|
2225
|
+
},
|
|
2226
|
+
get label() {
|
|
2227
|
+
return itemLabel(bar.item);
|
|
1752
2228
|
},
|
|
1753
2229
|
compact: true,
|
|
1754
|
-
|
|
1755
|
-
|
|
2230
|
+
bar: true,
|
|
2231
|
+
get continuesBefore() {
|
|
2232
|
+
return bar.continuesBefore;
|
|
2233
|
+
},
|
|
2234
|
+
get continuesAfter() {
|
|
2235
|
+
return bar.continuesAfter;
|
|
2236
|
+
},
|
|
2237
|
+
get hintStart() {
|
|
2238
|
+
return startHint();
|
|
2239
|
+
},
|
|
2240
|
+
get hintEnd() {
|
|
2241
|
+
return endHint();
|
|
1756
2242
|
},
|
|
1757
2243
|
get moving() {
|
|
1758
|
-
return movingEventId() === item.event.id;
|
|
2244
|
+
return movingEventId() === bar.item.event.id;
|
|
1759
2245
|
},
|
|
1760
2246
|
get onMovePointerDown() {
|
|
1761
|
-
return props.owner.onEventDrop ? (pointerEvent, markDragged) => startMove(pointerEvent, item, markDragged) : undefined;
|
|
2247
|
+
return props.owner.onEventDrop ? (pointerEvent, markDragged) => startMove(pointerEvent, bar.item, markDragged) : undefined;
|
|
1762
2248
|
}
|
|
1763
|
-
})))
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1766
|
-
|
|
2249
|
+
})), false);
|
|
2250
|
+
}
|
|
2251
|
+
})), _$escape(_$createComponent(For, {
|
|
2252
|
+
get each() {
|
|
2253
|
+
return cell().shown;
|
|
2254
|
+
},
|
|
2255
|
+
children: (item, index) => _$ssr(_tmpl$24, _$ssrStyleProperty("--k2b-calendar-span:", "1") + _$ssrStyleProperty(";--k2b-calendar-row:", _$escape(String(cell().top + index()), true)), _$escape(_$createComponent(EventChip, {
|
|
2256
|
+
get event() {
|
|
2257
|
+
return item.event;
|
|
1767
2258
|
},
|
|
1768
|
-
get
|
|
1769
|
-
return
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
2259
|
+
get owner() {
|
|
2260
|
+
return props.owner;
|
|
2261
|
+
},
|
|
2262
|
+
get href() {
|
|
2263
|
+
return eventHref(props.owner, item.event);
|
|
2264
|
+
},
|
|
2265
|
+
compact: true,
|
|
2266
|
+
get leadingTime() {
|
|
2267
|
+
return leadingTime(item);
|
|
2268
|
+
},
|
|
2269
|
+
get moving() {
|
|
2270
|
+
return movingEventId() === item.event.id;
|
|
2271
|
+
},
|
|
2272
|
+
get onMovePointerDown() {
|
|
2273
|
+
return props.owner.onEventDrop ? (pointerEvent, markDragged) => startMove(pointerEvent, item, markDragged) : undefined;
|
|
1778
2274
|
}
|
|
1779
|
-
})))
|
|
1780
|
-
}
|
|
1781
|
-
|
|
2275
|
+
})))
|
|
2276
|
+
})), _$escape(_$createComponent(Show, {
|
|
2277
|
+
get when() {
|
|
2278
|
+
return cell().hidden > 0;
|
|
2279
|
+
},
|
|
2280
|
+
get children() {
|
|
2281
|
+
return _$ssr(_tmpl$22, _$ssrStyleProperty("--k2b-calendar-row:", _$escape(String(cell().top + cell().shown.length), true)), _$ssrAttribute("aria-label", _$escape(calendarMessages().calendarMoreEventsOn({
|
|
2282
|
+
count: cell().hidden,
|
|
2283
|
+
label
|
|
2284
|
+
}), true), false), _$ssrAttribute("aria-expanded", (() => {
|
|
2285
|
+
const current = popover();
|
|
2286
|
+
return current?.kind === "day" && _$escape(current.dayKey, true) === _$escape(key, true);
|
|
2287
|
+
})(), false), _$escape(calendarMessages().calendarMoreEvents({
|
|
2288
|
+
count: cell().hidden
|
|
2289
|
+
})), _$escape(cell().hidden));
|
|
2290
|
+
}
|
|
2291
|
+
})));
|
|
2292
|
+
}
|
|
2293
|
+
})));
|
|
2294
|
+
};
|
|
2295
|
+
const weekdayRow = () => _$ssr(_tmpl$26, _$ssrAttribute("data-week-numbers", props.owner.withWeekNumbers ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
|
|
2296
|
+
get when() {
|
|
2297
|
+
return props.owner.withWeekNumbers;
|
|
2298
|
+
},
|
|
2299
|
+
get children() {
|
|
2300
|
+
return _$ssr(_tmpl$25, _$escape(calendarMessages().weekShort));
|
|
1782
2301
|
}
|
|
2302
|
+
})), _$escape(_$createComponent(For, {
|
|
2303
|
+
get each() {
|
|
2304
|
+
return weekdays();
|
|
2305
|
+
},
|
|
2306
|
+
children: (day, index) => _$ssr(_tmpl$27, _$ssrAttribute("data-weekend", index() > 4 ? "true" : _$escape(undefined, true), false), _$escape(day))
|
|
2307
|
+
})));
|
|
2308
|
+
const grid = () => _$ssr(_tmpl$28, _$ssrAttribute("aria-label", _$escape(formatMonth(props.date, dateConfig()), true), false), _$ssrStyleProperty("grid-template-rows:", `auto repeat(${_$escape(weeks().length, true)}, minmax(5rem, 1fr))`) + _$ssrStyleProperty(";--k2b-calendar-lane:", "1.25rem") + _$ssrStyleProperty(";--k2b-calendar-lane-gap:", "0.125rem"), _$escape(weekdayRow()), _$escape(_$createComponent(For, {
|
|
2309
|
+
get each() {
|
|
2310
|
+
return weeks();
|
|
2311
|
+
},
|
|
2312
|
+
children: (week, index) => weekRow(() => week, index)
|
|
1783
2313
|
})));
|
|
2314
|
+
const continuousRow = key => {
|
|
2315
|
+
const days = createMemo(() => Array.from({
|
|
2316
|
+
length: 7
|
|
2317
|
+
}, (_, offset) => {
|
|
2318
|
+
const dayKey = addDayKeys(key, offset);
|
|
2319
|
+
return {
|
|
2320
|
+
day: parseKey(dayKey),
|
|
2321
|
+
key: dayKey
|
|
2322
|
+
};
|
|
2323
|
+
}));
|
|
2324
|
+
return weekRow(days, () => monthRowOf(trackWeeks(), key) ?? 0);
|
|
2325
|
+
};
|
|
2326
|
+
const continuousGrid = () => _$ssr(_tmpl$29, _$ssrAttribute("aria-label", _$escape(formatMonth(parseKey(focusMonthKey()), dateConfig()), true), false), _$ssrAttribute("aria-rowcount", _$escape(trackWeeks().length, true) + 1, false), _$ssrStyleProperty("--k2b-calendar-lane:", "1.25rem") + _$ssrStyleProperty(";--k2b-calendar-lane-gap:", "0.125rem"), _$escape(weekdayRow()), _$ssrStyleProperty("--k2b-calendar-weeks:", _$escape(String(trackWeeks().length), true)), _$escape(_$createComponent(For, {
|
|
2327
|
+
get each() {
|
|
2328
|
+
return renderedWeeks();
|
|
2329
|
+
},
|
|
2330
|
+
children: continuousRow
|
|
2331
|
+
})), _$ssrAttribute("data-show", labelShown() ? "true" : "false", false), _$escape(formatMonth(parseKey(focusMonthKey()), dateConfig())));
|
|
1784
2332
|
const dayList = dayKey => {
|
|
1785
2333
|
const day = parseKey(dayKey);
|
|
1786
2334
|
const href = viewHref(dayKey, "day");
|
|
1787
2335
|
// Read where it renders, so a refresh while the list is open updates it as it does the grid.
|
|
1788
2336
|
const entries = () => dayEntries(dayKey);
|
|
1789
|
-
return _$ssr(_tmpl$
|
|
2337
|
+
return _$ssr(_tmpl$32, _$escape(dayLabel(day)), _$escape(_$createComponent(Show, {
|
|
1790
2338
|
get when() {
|
|
1791
2339
|
return entries().length > 0;
|
|
1792
2340
|
},
|
|
1793
2341
|
get fallback() {
|
|
1794
|
-
return _$ssr(_tmpl$
|
|
2342
|
+
return _$ssr(_tmpl$33, _$escape(calendarMessages().calendarNothingPlanned));
|
|
1795
2343
|
},
|
|
1796
2344
|
get children() {
|
|
1797
|
-
return _$ssr(_tmpl$
|
|
2345
|
+
return _$ssr(_tmpl$30, _$escape(_$createComponent(For, {
|
|
1798
2346
|
get each() {
|
|
1799
2347
|
return entries();
|
|
1800
2348
|
},
|
|
1801
|
-
children: item => _$ssr(_tmpl$
|
|
2349
|
+
children: item => _$ssr(_tmpl$34, _$escape(_$createComponent(EventChip, {
|
|
1802
2350
|
get event() {
|
|
1803
2351
|
return item.event;
|
|
1804
2352
|
},
|
|
@@ -1835,7 +2383,7 @@ const MonthView = props => {
|
|
|
1835
2383
|
size: "sm",
|
|
1836
2384
|
onClick: () => openView(dayKey, "day"),
|
|
1837
2385
|
get children() {
|
|
1838
|
-
return [_$ssr(_tmpl$
|
|
2386
|
+
return [_$ssr(_tmpl$35), calendarMessages().calendarOpenDay];
|
|
1839
2387
|
}
|
|
1840
2388
|
});
|
|
1841
2389
|
}
|
|
@@ -1854,7 +2402,7 @@ const MonthView = props => {
|
|
|
1854
2402
|
"data-size": "sm"
|
|
1855
2403
|
},
|
|
1856
2404
|
get children() {
|
|
1857
|
-
return [_$ssr(_tmpl$
|
|
2405
|
+
return [_$ssr(_tmpl$35), calendarMessages().calendarOpenDay];
|
|
1858
2406
|
}
|
|
1859
2407
|
})
|
|
1860
2408
|
})), _$escape(_$createComponent(Show, {
|
|
@@ -1876,18 +2424,19 @@ const MonthView = props => {
|
|
|
1876
2424
|
});
|
|
1877
2425
|
},
|
|
1878
2426
|
get children() {
|
|
1879
|
-
return [_$ssr(_tmpl$
|
|
2427
|
+
return [_$ssr(_tmpl$31), calendarMessages().calendarNewEvent];
|
|
1880
2428
|
}
|
|
1881
2429
|
});
|
|
1882
2430
|
}
|
|
1883
2431
|
})));
|
|
1884
2432
|
};
|
|
2433
|
+
const viewGrid = () => continuous() ? continuousGrid() : grid();
|
|
1885
2434
|
return [_$createComponent(Show, {
|
|
1886
2435
|
get when() {
|
|
1887
2436
|
return hasMenu();
|
|
1888
2437
|
},
|
|
1889
2438
|
get fallback() {
|
|
1890
|
-
return
|
|
2439
|
+
return viewGrid();
|
|
1891
2440
|
},
|
|
1892
2441
|
get children() {
|
|
1893
2442
|
return _$createComponent(GestureMenu, {
|
|
@@ -1901,11 +2450,11 @@ const MonthView = props => {
|
|
|
1901
2450
|
onOpen: onMenuOpen,
|
|
1902
2451
|
"class": "k2b-calendar-month-menu",
|
|
1903
2452
|
get children() {
|
|
1904
|
-
return
|
|
2453
|
+
return viewGrid();
|
|
1905
2454
|
}
|
|
1906
2455
|
});
|
|
1907
2456
|
}
|
|
1908
|
-
}), _$ssr(_tmpl$
|
|
2457
|
+
}), _$ssr(_tmpl$36, _$ssrAttribute("aria-label", (() => {
|
|
1909
2458
|
const current = popover();
|
|
1910
2459
|
if (current?.kind === "day") return dayLabel(parseKey(current.dayKey));
|
|
1911
2460
|
return _$escape(calendarMessages().calendarQuickCreate, true);
|
|
@@ -1917,7 +2466,7 @@ const MonthView = props => {
|
|
|
1917
2466
|
children: value => value.kind === "create" ? props.owner.renderQuickCreate?.(rangeOf(value.range), {
|
|
1918
2467
|
create: value.create,
|
|
1919
2468
|
close: () => {
|
|
1920
|
-
if (popover() === value) closePopover();
|
|
2469
|
+
if (popover() === value) closePopover(focusInPopover());
|
|
1921
2470
|
}
|
|
1922
2471
|
}) : dayList(value.dayKey)
|
|
1923
2472
|
})))];
|
|
@@ -1938,6 +2487,8 @@ const TimeGridView = props => {
|
|
|
1938
2487
|
let scrollContainer;
|
|
1939
2488
|
let timeGrid;
|
|
1940
2489
|
let timeGutter;
|
|
2490
|
+
let daysRow;
|
|
2491
|
+
let allDayRow;
|
|
1941
2492
|
let defaultHourMarker;
|
|
1942
2493
|
let cancelInteraction;
|
|
1943
2494
|
let suppressSlotClickUntil = 0;
|
|
@@ -1968,7 +2519,10 @@ const TimeGridView = props => {
|
|
|
1968
2519
|
if (!timeGrid || !timeGutter) return null;
|
|
1969
2520
|
const gridRect = timeGrid.getBoundingClientRect();
|
|
1970
2521
|
const gutterRect = timeGutter.getBoundingClientRect();
|
|
1971
|
-
|
|
2522
|
+
// The gutter stays in view while the days scroll sideways under it, so the days start one gutter after the grid.
|
|
2523
|
+
if (clientX < gutterRect.right) return null;
|
|
2524
|
+
const daysLeft = gridRect.left + gutterRect.width;
|
|
2525
|
+
const dayIndex = calendarDayIndexAtPoint(clientX, daysLeft, gridRect.right - daysLeft, props.days.length);
|
|
1972
2526
|
if (dayIndex === null) return null;
|
|
1973
2527
|
const minute = Math.min(gridEndHour() * 60 + 45, calendarMinuteAtPoint(clientY, gridRect.top, gridRect.height, gridStartHour(), gridEndHour()));
|
|
1974
2528
|
return zonedMinuteSlot(props.days[dayIndex], minute, dateConfig());
|
|
@@ -2094,12 +2648,28 @@ const TimeGridView = props => {
|
|
|
2094
2648
|
}
|
|
2095
2649
|
return [...groups.values()];
|
|
2096
2650
|
};
|
|
2097
|
-
// 12 rem per lane. The 40 rem grid is wider
|
|
2098
|
-
// three or more make the day scroll, and one lane fits beside a tablet drawer.
|
|
2099
|
-
const
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2651
|
+
// A week shares 36 rem between its days; a single day takes 12 rem per overlapping lane. The 40 rem grid is wider
|
|
2652
|
+
// than one or two lanes, so only three or more make the day scroll, and one lane fits beside a tablet drawer.
|
|
2653
|
+
const columnTemplate = createMemo(() => {
|
|
2654
|
+
let dayMin = "var(--k2b-calendar-day-min)";
|
|
2655
|
+
if (isDayView()) {
|
|
2656
|
+
const day = props.days[0];
|
|
2657
|
+
const layouts = timedEventLayouts(eventsByDay().get(calendar.formatDateKey(day, dateConfig()))?.timed ?? []);
|
|
2658
|
+
dayMin = `${Math.max(1, ...layouts.map(layout => layout.lanes)) * 12}rem`;
|
|
2659
|
+
}
|
|
2660
|
+
return `4rem repeat(${props.days.length}, minmax(${dayMin}, 1fr))`;
|
|
2661
|
+
});
|
|
2662
|
+
// The hours scroll sideways themselves; the day and all-day rows follow, also when focus scrolls one of them.
|
|
2663
|
+
// A row's scroll event from our own write arrives a frame late; echoing it back would undo a smooth scroll or fling.
|
|
2664
|
+
const followed = new WeakMap();
|
|
2665
|
+
const followColumns = source => {
|
|
2666
|
+
if (followed.get(source) === source.scrollLeft) return;
|
|
2667
|
+
followed.delete(source);
|
|
2668
|
+
for (const row of [scrollContainer, daysRow, allDayRow]) {
|
|
2669
|
+
if (!row || row === source || row.scrollLeft === source.scrollLeft) continue;
|
|
2670
|
+
row.scrollLeft = source.scrollLeft;
|
|
2671
|
+
followed.set(row, row.scrollLeft);
|
|
2672
|
+
}
|
|
2103
2673
|
};
|
|
2104
2674
|
const laneStyle = layoutItem => {
|
|
2105
2675
|
if (isDayView()) {
|
|
@@ -2135,7 +2705,7 @@ const TimeGridView = props => {
|
|
|
2135
2705
|
});
|
|
2136
2706
|
});
|
|
2137
2707
|
});
|
|
2138
|
-
return _$ssr(_tmpl$
|
|
2708
|
+
return _$ssr(_tmpl$38, _$ssrAttribute("data-view", isDayView() ? "day" : "week", false), _$ssrStyleProperty("grid-template-columns:", _$escape(columnTemplate(), true)), _$escape(_$createComponent(For, {
|
|
2139
2709
|
get each() {
|
|
2140
2710
|
return props.days;
|
|
2141
2711
|
},
|
|
@@ -2153,9 +2723,9 @@ const TimeGridView = props => {
|
|
|
2153
2723
|
class: "k2b-calendar-time-grid__day"
|
|
2154
2724
|
},
|
|
2155
2725
|
get children() {
|
|
2156
|
-
return [_$ssr(_tmpl$
|
|
2726
|
+
return [_$ssr(_tmpl$39, _$ssrAttribute("data-today", today() ? "true" : _$escape(undefined, true), false), _$escape(formatDay(day, dateConfig()))), _$createComponent(Show, {
|
|
2157
2727
|
when: dayBadge,
|
|
2158
|
-
children: badge => _$ssr(_tmpl$
|
|
2728
|
+
children: badge => _$ssr(_tmpl$40, _$escape(_$createComponent(Show, {
|
|
2159
2729
|
get when() {
|
|
2160
2730
|
return badge().icon;
|
|
2161
2731
|
},
|
|
@@ -2170,7 +2740,7 @@ const TimeGridView = props => {
|
|
|
2170
2740
|
return !props.owner.hideAllDay;
|
|
2171
2741
|
},
|
|
2172
2742
|
get children() {
|
|
2173
|
-
return _$ssr(_tmpl$
|
|
2743
|
+
return _$ssr(_tmpl$37, _$ssrStyleProperty("grid-template-columns:", _$escape(columnTemplate(), true)) + _$ssrStyleProperty(";max-height:", `${_$escape(props.owner.allDayMaxHeightRem ?? 7, true)}rem`), _$escape(props.labels.allDay), _$escape(_$createComponent(For, {
|
|
2174
2744
|
get each() {
|
|
2175
2745
|
return props.days;
|
|
2176
2746
|
},
|
|
@@ -2194,7 +2764,7 @@ const TimeGridView = props => {
|
|
|
2194
2764
|
end: calendar.addDays(start, 1, dateConfig()),
|
|
2195
2765
|
allDay: true
|
|
2196
2766
|
};
|
|
2197
|
-
}, () => performance.now() < suppressSlotClickUntil)), _$ssr(_tmpl$
|
|
2767
|
+
}, () => performance.now() < suppressSlotClickUntil)), _$ssr(_tmpl$41, _$escape(_$createComponent(For, {
|
|
2198
2768
|
each: previewAllDay,
|
|
2199
2769
|
children: event => _$ssr(_tmpl$14, _$escape(event.title))
|
|
2200
2770
|
})), _$escape(_$createComponent(For, {
|
|
@@ -2221,11 +2791,11 @@ const TimeGridView = props => {
|
|
|
2221
2791
|
}
|
|
2222
2792
|
})));
|
|
2223
2793
|
}
|
|
2224
|
-
})), _$ssrStyleProperty("grid-template-columns:",
|
|
2794
|
+
})), _$ssrStyleProperty("grid-template-columns:", _$escape(columnTemplate(), true)), _$ssrStyleProperty("grid-template-rows:", `repeat(${_$escape(hours().length, true)}, minmax(4rem, 1fr))`), _$escape(_$createComponent(For, {
|
|
2225
2795
|
get each() {
|
|
2226
2796
|
return hours();
|
|
2227
2797
|
},
|
|
2228
|
-
children: hour => _$ssr(_tmpl$
|
|
2798
|
+
children: hour => _$ssr(_tmpl$42, _$ssrAttribute("data-outside-business", hour < businessStartHour() || hour > businessEndHour() ? "true" : _$escape(undefined, true), false), _$escape(`${hour}`.padStart(2, "0")))
|
|
2229
2799
|
})), _$escape(_$createComponent(For, {
|
|
2230
2800
|
get each() {
|
|
2231
2801
|
return props.days;
|
|
@@ -2233,12 +2803,12 @@ const TimeGridView = props => {
|
|
|
2233
2803
|
children: day => {
|
|
2234
2804
|
const dayKey = calendar.formatDateKey(day, dateConfig());
|
|
2235
2805
|
const layouts = createMemo(() => timedEventLayouts(eventsByDay().get(dayKey)?.timed ?? []));
|
|
2236
|
-
return _$ssr(_tmpl$
|
|
2806
|
+
return _$ssr(_tmpl$44, _$ssrStyleProperty("grid-template-rows:", `repeat(${_$escape(hours().length, true)}, minmax(4rem, 1fr))`), _$escape(_$createComponent(Show, {
|
|
2237
2807
|
get when() {
|
|
2238
2808
|
return currentTimeLine(day) !== null;
|
|
2239
2809
|
},
|
|
2240
2810
|
get children() {
|
|
2241
|
-
return _$ssr(_tmpl$
|
|
2811
|
+
return _$ssr(_tmpl$43, _$ssrStyleProperty("top:", `${_$escape(currentTimeLine(day) ?? 0, true)}%`));
|
|
2242
2812
|
}
|
|
2243
2813
|
})), _$escape(_$createComponent(For, {
|
|
2244
2814
|
get each() {
|
|
@@ -2267,12 +2837,12 @@ const TimeGridView = props => {
|
|
|
2267
2837
|
children: event => {
|
|
2268
2838
|
const layout = eventLayout(event);
|
|
2269
2839
|
const short = event.endDate.getTime() - event.startDate.getTime() < 60 * 60_000;
|
|
2270
|
-
return _$ssr(_tmpl$
|
|
2840
|
+
return _$ssr(_tmpl$46, _$ssrAttribute("data-short", short ? "true" : _$escape(undefined, true), false), _$ssrStyleProperty("top:", `${_$escape(layout.top, true)}%`) + _$ssrStyleProperty(";height:", `${_$escape(layout.height, true)}%`), _$escape(_$createComponent(Show, {
|
|
2271
2841
|
get when() {
|
|
2272
2842
|
return event.title;
|
|
2273
2843
|
},
|
|
2274
2844
|
get children() {
|
|
2275
|
-
return _$ssr(_tmpl$
|
|
2845
|
+
return _$ssr(_tmpl$45, _$escape(event.title));
|
|
2276
2846
|
}
|
|
2277
2847
|
})), _$escape(formatTime(event.startDate, dateConfig())), _$escape(formatTime(event.endDate, dateConfig())));
|
|
2278
2848
|
}
|
|
@@ -2318,7 +2888,7 @@ const TimeGridView = props => {
|
|
|
2318
2888
|
onCancel: clearInteraction
|
|
2319
2889
|
});
|
|
2320
2890
|
};
|
|
2321
|
-
return _$ssr(_tmpl$
|
|
2891
|
+
return _$ssr(_tmpl$48, _$ssrStyleProperty("top:", `${_$escape(layout.top, true)}%`) + _$ssrStyleProperty(";height:", `${_$escape(layout.height, true)}%`) + _$ssrStyleProperty(";left:", _$escape(position.left, true)) + _$ssrStyleProperty(";width:", _$escape(position.width, true)) + _$ssrStyleProperty(";z-index:", _$escape(String(20 + layoutItem.lane), true)), _$escape(_$createComponent(EventChip, {
|
|
2322
2892
|
event: event,
|
|
2323
2893
|
get owner() {
|
|
2324
2894
|
return props.owner;
|
|
@@ -2338,7 +2908,7 @@ const TimeGridView = props => {
|
|
|
2338
2908
|
return props.owner.onEventResize;
|
|
2339
2909
|
},
|
|
2340
2910
|
get children() {
|
|
2341
|
-
return _$ssr(_tmpl$
|
|
2911
|
+
return _$ssr(_tmpl$47, _$ssrAttribute("aria-label", _$escape(calendarMessages().resizeEvent, true), false));
|
|
2342
2912
|
}
|
|
2343
2913
|
})));
|
|
2344
2914
|
}
|
|
@@ -2350,14 +2920,14 @@ const TimeGridView = props => {
|
|
|
2350
2920
|
const layout = timeRangeLayout(overflow.groupStartDate, overflow.groupEndDate);
|
|
2351
2921
|
const key = `${dayKey}-${overflow.groupId}`;
|
|
2352
2922
|
const hiddenTitle = () => overflow.hiddenEvents.map(event => `${formatTime(event.startDate, dateConfig())} ${event.title}`).join("\n");
|
|
2353
|
-
return [_$ssr(_tmpl$
|
|
2923
|
+
return [_$ssr(_tmpl$49, _$ssrStyleProperty("top:", `${_$escape(layout.top, true)}%`) + _$ssrStyleProperty(";height:", `${_$escape(layout.height, true)}%`), _$ssrAttribute("title", _$escape(hiddenTitle(), true), false) + _$ssrAttribute("aria-label", _$escape(calendarMessages().hiddenOverlappingEvents({
|
|
2354
2924
|
count: overflow.hiddenEvents.length
|
|
2355
2925
|
}), true), false), _$escape(overflow.hiddenEvents.length)), _$createComponent(Show, {
|
|
2356
2926
|
get when() {
|
|
2357
2927
|
return expandedOverflow() === key;
|
|
2358
2928
|
},
|
|
2359
2929
|
get children() {
|
|
2360
|
-
return _$ssr(_tmpl$
|
|
2930
|
+
return _$ssr(_tmpl$50, _$ssrStyleProperty("top:", `${_$escape(layout.top, true)}%`), _$escape(formatTime(overflow.groupStartDate, dateConfig())), _$escape(formatTime(overflow.groupEndDate, dateConfig())), _$escape(_$createComponent(For, {
|
|
2361
2931
|
get each() {
|
|
2362
2932
|
return overflow.hiddenEvents;
|
|
2363
2933
|
},
|
|
@@ -2416,11 +2986,11 @@ const YearView = props => {
|
|
|
2416
2986
|
};
|
|
2417
2987
|
});
|
|
2418
2988
|
});
|
|
2419
|
-
return _$ssr(_tmpl$
|
|
2989
|
+
return _$ssr(_tmpl$51, _$escape(_$createComponent(For, {
|
|
2420
2990
|
get each() {
|
|
2421
2991
|
return months();
|
|
2422
2992
|
},
|
|
2423
|
-
children: month => _$ssr(_tmpl$
|
|
2993
|
+
children: month => _$ssr(_tmpl$52, _$escape(month.label), _$escape(_$createComponent(For, {
|
|
2424
2994
|
get each() {
|
|
2425
2995
|
return month.days;
|
|
2426
2996
|
},
|
|
@@ -2443,7 +3013,7 @@ const YearView = props => {
|
|
|
2443
3013
|
get when() {
|
|
2444
3014
|
return day.events[0];
|
|
2445
3015
|
},
|
|
2446
|
-
children: event => _$ssr(_tmpl$
|
|
3016
|
+
children: event => _$ssr(_tmpl$53, _$ssrAttribute("data-color", event().colorHex ? _$escape(undefined, true) : _$escape(event().color ?? "blue", true), false) + _$ssrAttribute("data-today", day.isToday ? "true" : _$escape(undefined, true), false), _$ssrStyle(event().colorHex ? {
|
|
2447
3017
|
"background-color": day.isToday ? "white" : event().colorHex
|
|
2448
3018
|
} : undefined))
|
|
2449
3019
|
})];
|
|
@@ -2456,7 +3026,7 @@ const MobileMonthView = props => {
|
|
|
2456
3026
|
const dateConfig = createMemo(() => ownerDateConfig(props.owner));
|
|
2457
3027
|
const selectedDateKey = createMemo(() => calendar.formatDateKey(props.selectedDate, dateConfig()));
|
|
2458
3028
|
const selectedEvents = createMemo(() => props.events.filter(event => event.dayKey === selectedDateKey()));
|
|
2459
|
-
return _$ssr(_tmpl$
|
|
3029
|
+
return _$ssr(_tmpl$55, _$escape(_$createComponent(MonthPickerView, {
|
|
2460
3030
|
get owner() {
|
|
2461
3031
|
return {
|
|
2462
3032
|
...props.owner,
|
|
@@ -2486,10 +3056,10 @@ const MobileMonthView = props => {
|
|
|
2486
3056
|
return selectedEvents().length > 0;
|
|
2487
3057
|
},
|
|
2488
3058
|
get fallback() {
|
|
2489
|
-
return _$ssr(_tmpl$
|
|
3059
|
+
return _$ssr(_tmpl$56, _$escape(props.labels.noEvents));
|
|
2490
3060
|
},
|
|
2491
3061
|
get children() {
|
|
2492
|
-
return _$ssr(_tmpl$
|
|
3062
|
+
return _$ssr(_tmpl$54, _$escape(_$createComponent(For, {
|
|
2493
3063
|
get each() {
|
|
2494
3064
|
return selectedEvents();
|
|
2495
3065
|
},
|
|
@@ -2506,7 +3076,7 @@ const MobileMonthView = props => {
|
|
|
2506
3076
|
}
|
|
2507
3077
|
})));
|
|
2508
3078
|
};
|
|
2509
|
-
const CalendarBody = props => _$ssr(_tmpl$
|
|
3079
|
+
const CalendarBody = props => _$ssr(_tmpl$57, _$escape(props.children));
|
|
2510
3080
|
const CalendarRoot = props => {
|
|
2511
3081
|
const messages = useUiMessages();
|
|
2512
3082
|
const calendarMessages = useCalendarMessages();
|
|
@@ -2560,24 +3130,26 @@ const CalendarRoot = props => {
|
|
|
2560
3130
|
// The day and week views with `dayHours` scroll through their days; the header and the commands ask them first.
|
|
2561
3131
|
const [timeView, setTimeView] = createSignal(null);
|
|
2562
3132
|
const [monthCreate, setMonthCreate] = createSignal(null);
|
|
3133
|
+
const monthView = () => monthCreate()?.continuous() ? monthCreate() : null;
|
|
3134
|
+
const scrollingView = () => timeView() ?? monthView();
|
|
2563
3135
|
const timeMode = () => Boolean(props.dayHours) && (view() === "day" || view() === "week");
|
|
2564
3136
|
const parseKey = key => calendar.parseCalendarDate(key, dateConfig());
|
|
2565
3137
|
/** The first shown day of a day or week view, or the selected day of the month view, for the other views. */
|
|
2566
3138
|
const shownDay = () => {
|
|
2567
3139
|
const first = timeView()?.visibleKeys().first;
|
|
2568
3140
|
if (first) return parseKey(first);
|
|
2569
|
-
return view() === "month" ? focusDay() : null;
|
|
3141
|
+
return view() === "month" ? focusDay() ?? monthView()?.focusDay() ?? null : null;
|
|
2570
3142
|
};
|
|
2571
3143
|
const go = (target, nextView) => {
|
|
2572
3144
|
const href = props.getDateHref?.(target, nextView);
|
|
2573
3145
|
if (href) followCalendarHref(owner, href);else openViewAt(props, target, nextView);
|
|
2574
3146
|
};
|
|
2575
3147
|
const step = direction => {
|
|
2576
|
-
if (
|
|
2577
|
-
go(adjacentCalendarDate(shownDay() ?? date(), view(), direction, dateConfig()), view());
|
|
3148
|
+
if (scrollingView()?.step(direction)) return;
|
|
3149
|
+
go(adjacentCalendarDate(monthView()?.stepFrom() ?? shownDay() ?? date(), view(), direction, dateConfig()), view());
|
|
2578
3150
|
};
|
|
2579
3151
|
const goToday = () => {
|
|
2580
|
-
if (
|
|
3152
|
+
if (scrollingView()?.today()) return;
|
|
2581
3153
|
go(calendar.today(dateConfig()), view());
|
|
2582
3154
|
};
|
|
2583
3155
|
const goView = nextView => {
|
|
@@ -2590,7 +3162,7 @@ const CalendarRoot = props => {
|
|
|
2590
3162
|
if (href) followCalendarHref(owner, href);else props.onViewChange?.(nextView);
|
|
2591
3163
|
};
|
|
2592
3164
|
const goToKey = key => {
|
|
2593
|
-
if (
|
|
3165
|
+
if (scrollingView()?.goTo(key)) return;
|
|
2594
3166
|
go(parseKey(key), view());
|
|
2595
3167
|
};
|
|
2596
3168
|
const openGoTo = () => void openCalendarGoTo({
|
|
@@ -2685,6 +3257,7 @@ const CalendarRoot = props => {
|
|
|
2685
3257
|
});
|
|
2686
3258
|
const headerNav = {
|
|
2687
3259
|
timeView,
|
|
3260
|
+
monthView,
|
|
2688
3261
|
commands: () => props.onCommandsChange ? allCommands() : [],
|
|
2689
3262
|
// The arrow keys page like J and K, so the list names them beside those keys.
|
|
2690
3263
|
openShortcuts: () => void openCalendarShortcuts(allCommands(), calendarMessages(), custom() ? {} : {
|
|
@@ -2730,7 +3303,7 @@ const CalendarRoot = props => {
|
|
|
2730
3303
|
},
|
|
2731
3304
|
register: setTimeView
|
|
2732
3305
|
});
|
|
2733
|
-
return _$ssr(_tmpl$
|
|
3306
|
+
return _$ssr(_tmpl$58, `k2b-content-calendar ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("aria-busy", props.navigationPending ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(CalendarHeader, {
|
|
2734
3307
|
get date() {
|
|
2735
3308
|
return date();
|
|
2736
3309
|
},
|
|
@@ -2742,7 +3315,7 @@ const CalendarRoot = props => {
|
|
|
2742
3315
|
},
|
|
2743
3316
|
owner: owner,
|
|
2744
3317
|
get focusDay() {
|
|
2745
|
-
return _$memo(() => view() === "month"
|
|
3318
|
+
return _$memo(() => !!(view() === "month" || timeView()))() ? shownDay() : null;
|
|
2746
3319
|
},
|
|
2747
3320
|
nav: headerNav
|
|
2748
3321
|
})), _$escape(_$createComponent(Show, {
|
|
@@ -2779,6 +3352,7 @@ const CalendarRoot = props => {
|
|
|
2779
3352
|
return mergedLabels();
|
|
2780
3353
|
},
|
|
2781
3354
|
onFocusDay: setFocusDay,
|
|
3355
|
+
goToDate: date => go(date, view()),
|
|
2782
3356
|
register: setMonthCreate
|
|
2783
3357
|
});
|
|
2784
3358
|
}
|