kalendly 0.3.0 → 0.3.2
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 +155 -20
- package/dist/core/index.d.mts +16 -2
- package/dist/core/index.d.ts +16 -2
- package/dist/core/index.js +153 -5
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +142 -5
- package/dist/core/index.mjs.map +1 -1
- package/dist/index.d.mts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +297 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +286 -31
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +274 -30
- package/dist/index.umd.js.map +1 -1
- package/dist/styles/calendar.css +33 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -31,12 +31,76 @@ function generateYears(minYear, maxYear) {
|
|
|
31
31
|
const max = maxYear ?? currentYear + 10;
|
|
32
32
|
return Array.from({ length: max - min + 1 }, (_, i) => min + i);
|
|
33
33
|
}
|
|
34
|
-
function
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
function parseHourRanges(value, slotDuration) {
|
|
35
|
+
const parts = value.split(",").map((part) => part.trim()).filter(Boolean);
|
|
36
|
+
if (parts.length === 0) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`<kal-calendar> available-hours is empty. Omit the attribute to allow every hour, or name at least one HH:MM-HH:MM range.`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const ranges = parts.map((part) => {
|
|
42
|
+
const halves = part.split("-");
|
|
43
|
+
if (halves.length !== 2) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`<kal-calendar> available-hours range "${part}" is not HH:MM-HH:MM.`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
const [start, end] = halves.map((half) => parseTimeToMinutes(half.trim()));
|
|
49
|
+
if (start === null || end === null) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`<kal-calendar> available-hours range "${part}" has an unreadable time. Use 24-hour HH:MM.`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (start >= end) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`<kal-calendar> available-hours range "${part}" starts at or after it ends.`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (start % slotDuration !== 0 || end % slotDuration !== 0) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`<kal-calendar> available-hours range "${part}" does not land on a ${slotDuration}-minute slot boundary.`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return [start, end];
|
|
39
65
|
});
|
|
66
|
+
if (mergeIntervals(ranges).length !== ranges.length) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`<kal-calendar> available-hours ranges overlap or touch: "${value}". Write each bookable window once.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return ranges;
|
|
72
|
+
}
|
|
73
|
+
function isDateWithinWindow(date, min, max) {
|
|
74
|
+
const target = normalizeDate(date).getTime();
|
|
75
|
+
if (min && target < normalizeDate(min).getTime()) return false;
|
|
76
|
+
if (max && target > normalizeDate(max).getTime()) return false;
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
function isDayAllowed(date, days) {
|
|
80
|
+
return days === null || days.includes(date.getDay());
|
|
81
|
+
}
|
|
82
|
+
function eventCoversDate(event, date) {
|
|
83
|
+
const start = normalizeDate(new Date(event.date)).getTime();
|
|
84
|
+
const target = normalizeDate(date).getTime();
|
|
85
|
+
if (Number.isNaN(start)) return false;
|
|
86
|
+
if (event.endDate === void 0 || event.endDate === null) {
|
|
87
|
+
return start === target;
|
|
88
|
+
}
|
|
89
|
+
const end = normalizeDate(new Date(event.endDate)).getTime();
|
|
90
|
+
if (Number.isNaN(end)) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`<kal-calendar> event ${event.id} has an unreadable endDate: ${String(event.endDate)}.`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (end < start) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`<kal-calendar> event ${event.id} has an endDate before its date: ${String(event.endDate)} < ${String(event.date)}.`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return target >= start && target <= end;
|
|
101
|
+
}
|
|
102
|
+
function getEventsForDate(events, date) {
|
|
103
|
+
return events.filter((event) => eventCoversDate(event, date));
|
|
40
104
|
}
|
|
41
105
|
function hasEvents(events, date) {
|
|
42
106
|
return getEventsForDate(events, date).length > 0;
|
|
@@ -180,7 +244,67 @@ function safeColor(value) {
|
|
|
180
244
|
const trimmed = String(value).trim();
|
|
181
245
|
return isValidHexColor(trimmed) || /^[a-z]+$/i.test(trimmed) ? trimmed : "#3b82f6";
|
|
182
246
|
}
|
|
183
|
-
|
|
247
|
+
function parseTimeToMinutes(time) {
|
|
248
|
+
if (typeof time !== "string") return null;
|
|
249
|
+
const match = /^(\d{1,2}):(\d{2})$/.exec(time.trim());
|
|
250
|
+
if (!match) return null;
|
|
251
|
+
const hours = Number(match[1]);
|
|
252
|
+
const mins = Number(match[2]);
|
|
253
|
+
if (hours > 24 || mins > 59 || hours === 24 && mins > 0) return null;
|
|
254
|
+
return hours * 60 + mins;
|
|
255
|
+
}
|
|
256
|
+
function formatMinutes(total) {
|
|
257
|
+
const hours = Math.floor(total / 60);
|
|
258
|
+
const mins = total % 60;
|
|
259
|
+
return `${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
|
|
260
|
+
}
|
|
261
|
+
function eventInterval(event, slotDuration, onDay) {
|
|
262
|
+
const day = normalizeDate(onDay).getTime();
|
|
263
|
+
if (Number.isNaN(day)) return null;
|
|
264
|
+
const base = day / 6e4;
|
|
265
|
+
const wholeDay = [base, base + MINUTES_PER_DAY];
|
|
266
|
+
if (event.allDay || !event.startTime) return wholeDay;
|
|
267
|
+
const from = parseTimeToMinutes(event.startTime);
|
|
268
|
+
if (from === null) return wholeDay;
|
|
269
|
+
if (event.endTime === void 0 || event.endTime === null) {
|
|
270
|
+
return [base + from, base + from + slotDuration];
|
|
271
|
+
}
|
|
272
|
+
const to = parseTimeToMinutes(event.endTime);
|
|
273
|
+
if (to === null) return wholeDay;
|
|
274
|
+
return [base + from, base + (to <= from ? to + MINUTES_PER_DAY : to)];
|
|
275
|
+
}
|
|
276
|
+
function mergeIntervals(intervals) {
|
|
277
|
+
const sorted = [...intervals].sort((a, b) => a[0] - b[0]);
|
|
278
|
+
return sorted.reduce((merged, [start, end]) => {
|
|
279
|
+
const last = merged[merged.length - 1];
|
|
280
|
+
if (last && start <= last[1]) last[1] = Math.max(last[1], end);
|
|
281
|
+
else merged.push([start, end]);
|
|
282
|
+
return merged;
|
|
283
|
+
}, []);
|
|
284
|
+
}
|
|
285
|
+
function bookedSlots(events, date, slotDuration = DEFAULT_SLOT_DURATION) {
|
|
286
|
+
const base = normalizeDate(date).getTime() / 6e4;
|
|
287
|
+
const previousDay = new Date(date);
|
|
288
|
+
previousDay.setDate(previousDay.getDate() - 1);
|
|
289
|
+
const intervals = [];
|
|
290
|
+
for (const event of new Set(events)) {
|
|
291
|
+
for (const day of [previousDay, date]) {
|
|
292
|
+
if (!eventCoversDate(event, day)) continue;
|
|
293
|
+
const interval = eventInterval(event, slotDuration, day);
|
|
294
|
+
if (interval) intervals.push(interval);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const merged = mergeIntervals(intervals);
|
|
298
|
+
return Array.from(
|
|
299
|
+
{ length: Math.floor(MINUTES_PER_DAY / slotDuration) },
|
|
300
|
+
(_, index) => {
|
|
301
|
+
const start = base + index * slotDuration;
|
|
302
|
+
const end = start + slotDuration;
|
|
303
|
+
return merged.some(([from, to]) => start < to && end > from);
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
var MONTHS, MONTHS_FULL, DAYS, DEFAULT_CATEGORY_COLORS, HTML_ESCAPES, MINUTES_PER_DAY, DEFAULT_SLOT_DURATION;
|
|
184
308
|
var init_utils = __esm({
|
|
185
309
|
"src/core/utils.ts"() {
|
|
186
310
|
"use strict";
|
|
@@ -236,6 +360,8 @@ var init_utils = __esm({
|
|
|
236
360
|
'"': """,
|
|
237
361
|
"'": "'"
|
|
238
362
|
};
|
|
363
|
+
MINUTES_PER_DAY = 1440;
|
|
364
|
+
DEFAULT_SLOT_DURATION = 60;
|
|
239
365
|
}
|
|
240
366
|
});
|
|
241
367
|
|
|
@@ -649,6 +775,29 @@ var init_CalendarElement = __esm({
|
|
|
649
775
|
}
|
|
650
776
|
return title;
|
|
651
777
|
}
|
|
778
|
+
get slotDuration() {
|
|
779
|
+
const raw = this.getAttribute("slot-duration");
|
|
780
|
+
if (raw === null) return DEFAULT_SLOT_DURATION;
|
|
781
|
+
const minutes = Number(raw);
|
|
782
|
+
if (Number.isInteger(minutes) && minutes > 0 && MINUTES_PER_DAY % minutes === 0) {
|
|
783
|
+
return minutes;
|
|
784
|
+
}
|
|
785
|
+
console.warn(
|
|
786
|
+
`<kal-calendar> slot-duration="${raw}" must be a positive whole number of minutes that divides ${MINUTES_PER_DAY} \u2014 falling back to ${DEFAULT_SLOT_DURATION}.`
|
|
787
|
+
);
|
|
788
|
+
return DEFAULT_SLOT_DURATION;
|
|
789
|
+
}
|
|
790
|
+
warnMissingEndTime(events) {
|
|
791
|
+
for (const event of events) {
|
|
792
|
+
if (!event.startTime || event.endTime) continue;
|
|
793
|
+
const key = String(event.id);
|
|
794
|
+
if (_CalendarElement.warnedMissingEnd.has(key)) continue;
|
|
795
|
+
_CalendarElement.warnedMissingEnd.add(key);
|
|
796
|
+
console.warn(
|
|
797
|
+
`<kal-calendar> event ${key} has startTime but no endTime \u2014 occupying one ${this.slotDuration}-minute slot. Send an endTime to say how long it runs.`
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
652
801
|
get monthCount() {
|
|
653
802
|
const requested = Number(this.getAttribute("months") ?? 1);
|
|
654
803
|
if (!Number.isInteger(requested) || requested < 1) return 1;
|
|
@@ -662,6 +811,41 @@ var init_CalendarElement = __esm({
|
|
|
662
811
|
const val = this.getAttribute("max-year");
|
|
663
812
|
return val ? parseInt(val, 10) : (/* @__PURE__ */ new Date()).getFullYear() + 10;
|
|
664
813
|
}
|
|
814
|
+
boundaryDate(attr) {
|
|
815
|
+
const val = this.getAttribute(attr);
|
|
816
|
+
if (!val) return null;
|
|
817
|
+
const parsed = new Date(val);
|
|
818
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
819
|
+
throw new Error(
|
|
820
|
+
`<kal-calendar> ${attr} is unreadable: "${val}". Use a value Date can parse, the same as initial-date.`
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
return parsed;
|
|
824
|
+
}
|
|
825
|
+
get availableDays() {
|
|
826
|
+
const val = this.getAttribute("available-days");
|
|
827
|
+
if (val === null) return null;
|
|
828
|
+
const parts = val.split(",").map((part) => part.trim()).filter(Boolean);
|
|
829
|
+
if (parts.length === 0) {
|
|
830
|
+
throw new Error(
|
|
831
|
+
`<kal-calendar> available-days is empty. Omit the attribute to allow every day, or name at least one weekday.`
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
return parts.map((part) => {
|
|
835
|
+
const day = Number(part);
|
|
836
|
+
if (!Number.isInteger(day) || day < 0 || day > 6) {
|
|
837
|
+
throw new Error(
|
|
838
|
+
`<kal-calendar> available-days must list integers 0-6, 0 = Sunday. Got "${part}".`
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
return day;
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
get availableHours() {
|
|
845
|
+
const val = this.getAttribute("available-hours");
|
|
846
|
+
if (val === null) return null;
|
|
847
|
+
return parseHourRanges(val, this.slotDuration);
|
|
848
|
+
}
|
|
665
849
|
initEngine() {
|
|
666
850
|
const initialDateAttr = this.getAttribute("initial-date");
|
|
667
851
|
const initialDate = initialDateAttr ? new Date(initialDateAttr) : void 0;
|
|
@@ -780,8 +964,26 @@ var init_CalendarElement = __esm({
|
|
|
780
964
|
if (declared.size === 0) return "open";
|
|
781
965
|
return this.knownBuckets.find((bucket) => declared.has(bucket));
|
|
782
966
|
}
|
|
967
|
+
assertHorizonOrdered() {
|
|
968
|
+
const min = this.boundaryDate("min-date");
|
|
969
|
+
const max = this.boundaryDate("max-date");
|
|
970
|
+
if (min && max && min.getTime() > max.getTime()) {
|
|
971
|
+
throw new Error(
|
|
972
|
+
`<kal-calendar> min-date is after max-date: "${this.getAttribute("min-date")}" > "${this.getAttribute("max-date")}".`
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
// Whether the vendor offers this day at all, before any event is considered.
|
|
977
|
+
isDateOffered(date) {
|
|
978
|
+
return isDateWithinWindow(
|
|
979
|
+
date,
|
|
980
|
+
this.boundaryDate("min-date"),
|
|
981
|
+
this.boundaryDate("max-date")
|
|
982
|
+
) && isDayAllowed(date, this.availableDays);
|
|
983
|
+
}
|
|
783
984
|
isDateSelectable(date) {
|
|
784
985
|
if (!this.engine) return false;
|
|
986
|
+
if (!this.isDateOffered(date)) return false;
|
|
785
987
|
if (this._selectableStatuses) {
|
|
786
988
|
return this._selectableStatuses.includes(this.resolveBucket(date));
|
|
787
989
|
}
|
|
@@ -801,6 +1003,11 @@ var init_CalendarElement = __esm({
|
|
|
801
1003
|
this.assertStatusesDeclared();
|
|
802
1004
|
this.assertStatusesKnown();
|
|
803
1005
|
}
|
|
1006
|
+
this.boundaryDate("min-date");
|
|
1007
|
+
this.boundaryDate("max-date");
|
|
1008
|
+
void this.availableDays;
|
|
1009
|
+
void this.availableHours;
|
|
1010
|
+
this.assertHorizonOrdered();
|
|
804
1011
|
const today = /* @__PURE__ */ new Date();
|
|
805
1012
|
const todayMonth = today.getMonth();
|
|
806
1013
|
const todayYear = today.getFullYear();
|
|
@@ -844,7 +1051,7 @@ var init_CalendarElement = __esm({
|
|
|
844
1051
|
return `
|
|
845
1052
|
<div class="event-card" style="border-left-color: ${borderColor}">
|
|
846
1053
|
<div class="event-header">
|
|
847
|
-
|
|
1054
|
+
${event.name ? `<div class="event-title">${escapeHtml(event.name)}</div>` : ""}
|
|
848
1055
|
<div class="event-badges">
|
|
849
1056
|
${event.category ? `<span class="badge category category-${slugifyToken(event.category)}">${escapeHtml(getCategoryLabel(event.category))}</span>` : ""}
|
|
850
1057
|
${event.priority ? `<span class="badge priority priority-${slugifyToken(event.priority)}">${escapeHtml(getPriorityLabel(event.priority))}</span>` : ""}
|
|
@@ -910,42 +1117,45 @@ var init_CalendarElement = __esm({
|
|
|
910
1117
|
const defaultRenderNoEvents = () => '<div class="no-events-message">No events scheduled for this day.</div>';
|
|
911
1118
|
const renderEvent = this._renderEvent || defaultRenderEvent;
|
|
912
1119
|
const renderNoEvents = this._renderNoEvents || defaultRenderNoEvents;
|
|
913
|
-
const renderTimeGrid = (
|
|
914
|
-
const
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
const startTime =
|
|
928
|
-
const endTime =
|
|
929
|
-
const
|
|
930
|
-
const inTimeRange = !
|
|
1120
|
+
const renderTimeGrid = (date) => {
|
|
1121
|
+
const slotDuration = this.slotDuration;
|
|
1122
|
+
const previousDay = new Date(date);
|
|
1123
|
+
previousDay.setDate(previousDay.getDate() - 1);
|
|
1124
|
+
const events = [
|
|
1125
|
+
...this.engine.getEventsForDate(previousDay),
|
|
1126
|
+
...this.engine.getEventsForDate(date)
|
|
1127
|
+
];
|
|
1128
|
+
this.warnMissingEndTime(events);
|
|
1129
|
+
const booked = bookedSlots(events, date, slotDuration);
|
|
1130
|
+
const hours = this.availableHours;
|
|
1131
|
+
const slots = booked.map((isBooked, index) => {
|
|
1132
|
+
const slotStart = index * slotDuration;
|
|
1133
|
+
const slotEnd = slotStart + slotDuration;
|
|
1134
|
+
const startTime = formatMinutes(slotStart);
|
|
1135
|
+
const endTime = formatMinutes(slotEnd);
|
|
1136
|
+
const offered = hours === null || hours.some(([from, to]) => slotStart >= from && slotEnd <= to);
|
|
1137
|
+
const inTimeRange = offered && !isBooked && selectable && this._timeRangeStart !== null && this._timeRangeEnd !== null && isSameDay2(this._timeRangeDate, date) && startTime >= this._timeRangeStart && endTime <= this._timeRangeEnd;
|
|
931
1138
|
const isRangeStart = inTimeRange && startTime === this._timeRangeStart;
|
|
932
1139
|
const isRangeEnd = inTimeRange && endTime === this._timeRangeEnd;
|
|
933
1140
|
const isInRange = inTimeRange && !isRangeStart && !isRangeEnd;
|
|
934
1141
|
const slotClasses = [
|
|
935
1142
|
"time-grid-slot",
|
|
936
|
-
|
|
1143
|
+
offered ? "" : "time-grid-slot-out-of-range",
|
|
1144
|
+
isBooked ? "time-grid-slot-blocked" : "time-grid-slot-open",
|
|
937
1145
|
isRangeStart ? "time-grid-slot-range-start" : "",
|
|
938
1146
|
isRangeEnd ? "time-grid-slot-range-end" : "",
|
|
939
1147
|
isInRange ? "time-grid-slot-in-range" : ""
|
|
940
1148
|
].filter(Boolean).join(" ");
|
|
941
|
-
const slotAttrs =
|
|
1149
|
+
const slotAttrs = `${offered ? 'data-action="select-slot" ' : ""}data-start-time="${startTime}" data-end-time="${endTime}" data-date="${date.toISOString()}" data-booked="${isBooked}"`;
|
|
1150
|
+
const status = !offered ? "Closed" : isBooked ? "Booked" : "Available";
|
|
942
1151
|
return `
|
|
943
1152
|
<div class="${slotClasses}" ${slotAttrs}>
|
|
944
1153
|
<span class="time-grid-label">${startTime}</span>
|
|
945
|
-
<span class="time-grid-status">${
|
|
1154
|
+
<span class="time-grid-status">${status}</span>
|
|
946
1155
|
</div>`;
|
|
947
1156
|
});
|
|
948
|
-
|
|
1157
|
+
const gridClasses = selectable ? "time-grid time-grid-selectable" : "time-grid";
|
|
1158
|
+
return `<div class="${gridClasses}">${slots.join("")}</div>`;
|
|
949
1159
|
};
|
|
950
1160
|
const multiMonth = viewModel.panes.length > 1;
|
|
951
1161
|
const renderPane = (pane) => `
|
|
@@ -970,6 +1180,12 @@ var init_CalendarElement = __esm({
|
|
|
970
1180
|
${week.map((calendarDate, dayIndex) => {
|
|
971
1181
|
const classes = getCellClasses(calendarDate);
|
|
972
1182
|
const cellAttrs = [];
|
|
1183
|
+
if (viewModel.selectedDate && isSameDay2(
|
|
1184
|
+
calendarDate.date,
|
|
1185
|
+
viewModel.selectedDate
|
|
1186
|
+
)) {
|
|
1187
|
+
classes.push("calendar-cell-selected");
|
|
1188
|
+
}
|
|
973
1189
|
if (availabilityMode && calendarDate.isCurrentMonth) {
|
|
974
1190
|
const bucket = this.resolveBucket(
|
|
975
1191
|
calendarDate.date
|
|
@@ -1003,12 +1219,18 @@ var init_CalendarElement = __esm({
|
|
|
1003
1219
|
}
|
|
1004
1220
|
}
|
|
1005
1221
|
const dateString = calendarDate.date.toISOString();
|
|
1222
|
+
const offered = this.isDateOffered(
|
|
1223
|
+
calendarDate.date
|
|
1224
|
+
);
|
|
1225
|
+
if (!offered) {
|
|
1226
|
+
classes.push("calendar-cell-out-of-range");
|
|
1227
|
+
}
|
|
1006
1228
|
return `
|
|
1007
1229
|
<td
|
|
1008
1230
|
class="${classes.join(" ")}"
|
|
1009
1231
|
data-date="${dateString}"
|
|
1010
1232
|
data-day-index="${dayIndex}"
|
|
1011
|
-
data-clickable="true"
|
|
1233
|
+
${offered ? 'data-clickable="true"' : ""}
|
|
1012
1234
|
${cellAttrs.join(" ")}
|
|
1013
1235
|
>
|
|
1014
1236
|
${calendarDate.date.getDate()}
|
|
@@ -1122,7 +1344,7 @@ var init_CalendarElement = __esm({
|
|
|
1122
1344
|
` : ""}
|
|
1123
1345
|
|
|
1124
1346
|
<div class="events-container">
|
|
1125
|
-
${availabilityMode === "time" ? renderTimeGrid(viewModel.
|
|
1347
|
+
${availabilityMode === "time" ? renderTimeGrid(viewModel.selectedDate) : viewModel.tasks.length > 0 ? viewModel.tasks.map((event) => renderEvent(event)).join("") : renderNoEvents()}
|
|
1126
1348
|
</div>
|
|
1127
1349
|
</div>
|
|
1128
1350
|
` : ""}
|
|
@@ -1283,6 +1505,20 @@ var init_CalendarElement = __esm({
|
|
|
1283
1505
|
const slotStart = actionEl.dataset.startTime;
|
|
1284
1506
|
const slotEnd = actionEl.dataset.endTime;
|
|
1285
1507
|
const slotDate = new Date(actionEl.dataset.date);
|
|
1508
|
+
const slotBooked = actionEl.dataset.booked === "true";
|
|
1509
|
+
this.dispatchEvent(
|
|
1510
|
+
new CustomEvent("cal-slot-select", {
|
|
1511
|
+
bubbles: true,
|
|
1512
|
+
composed: true,
|
|
1513
|
+
detail: {
|
|
1514
|
+
date: slotDate,
|
|
1515
|
+
startTime: slotStart,
|
|
1516
|
+
endTime: slotEnd,
|
|
1517
|
+
booked: slotBooked
|
|
1518
|
+
}
|
|
1519
|
+
})
|
|
1520
|
+
);
|
|
1521
|
+
if (slotBooked || !this.hasAttribute("selectable")) break;
|
|
1286
1522
|
if (this._timeRangeComplete) {
|
|
1287
1523
|
this._timeRangeDate = slotDate;
|
|
1288
1524
|
this._timeRangeStart = slotStart;
|
|
@@ -1420,9 +1656,14 @@ var init_CalendarElement = __esm({
|
|
|
1420
1656
|
"initial-date",
|
|
1421
1657
|
"min-year",
|
|
1422
1658
|
"max-year",
|
|
1659
|
+
"min-date",
|
|
1660
|
+
"max-date",
|
|
1661
|
+
"available-days",
|
|
1662
|
+
"available-hours",
|
|
1423
1663
|
"week-starts-on",
|
|
1424
1664
|
"heading",
|
|
1425
1665
|
"months",
|
|
1666
|
+
"slot-duration",
|
|
1426
1667
|
"title",
|
|
1427
1668
|
"use-short-month-names",
|
|
1428
1669
|
"availability-mode",
|
|
@@ -1440,6 +1681,8 @@ var init_CalendarElement = __esm({
|
|
|
1440
1681
|
borderColor: "--calendar-border-color",
|
|
1441
1682
|
todayOutline: "--calendar-today-outline",
|
|
1442
1683
|
selectedBg: "--calendar-selected-bg",
|
|
1684
|
+
outOfRangeBg: "--calendar-out-of-range-bg",
|
|
1685
|
+
outOfRangeFg: "--calendar-out-of-range-fg",
|
|
1443
1686
|
headerBg: "--calendar-header-bg",
|
|
1444
1687
|
popupBg: "--calendar-popup-bg",
|
|
1445
1688
|
pickerBg: "--calendar-picker-bg",
|
|
@@ -1474,6 +1717,7 @@ var init_CalendarElement = __esm({
|
|
|
1474
1717
|
badgeTentativeBg: "--calendar-badge-tentative-bg",
|
|
1475
1718
|
badgeTentativeText: "--calendar-badge-tentative-text"
|
|
1476
1719
|
};
|
|
1720
|
+
_CalendarElement.warnedMissingEnd = /* @__PURE__ */ new Set();
|
|
1477
1721
|
_CalendarElement.BUILT_IN_BUCKETS = ["blocked", "conditional", "open"];
|
|
1478
1722
|
_CalendarElement.titleDeprecationWarned = false;
|
|
1479
1723
|
CalendarElement = _CalendarElement;
|
|
@@ -1495,12 +1739,18 @@ export {
|
|
|
1495
1739
|
CalendarEngine,
|
|
1496
1740
|
DAYS,
|
|
1497
1741
|
DEFAULT_CATEGORY_COLORS,
|
|
1742
|
+
DEFAULT_SLOT_DURATION,
|
|
1743
|
+
MINUTES_PER_DAY,
|
|
1498
1744
|
MONTHS,
|
|
1499
1745
|
MONTHS_FULL,
|
|
1746
|
+
bookedSlots,
|
|
1500
1747
|
defineCalendarElement,
|
|
1501
1748
|
escapeHtml,
|
|
1749
|
+
eventCoversDate,
|
|
1750
|
+
eventInterval,
|
|
1502
1751
|
formatAttendees,
|
|
1503
1752
|
formatDateForDisplay,
|
|
1753
|
+
formatMinutes,
|
|
1504
1754
|
formatTimeRange,
|
|
1505
1755
|
generateCalendarDates,
|
|
1506
1756
|
generateYears,
|
|
@@ -1510,11 +1760,16 @@ export {
|
|
|
1510
1760
|
getEventsForDate,
|
|
1511
1761
|
getMonthYearText,
|
|
1512
1762
|
hasEvents,
|
|
1763
|
+
isDateWithinWindow,
|
|
1764
|
+
isDayAllowed,
|
|
1513
1765
|
isSameDay,
|
|
1514
1766
|
isToday,
|
|
1515
1767
|
isValidHexColor,
|
|
1516
1768
|
mergeCategoryColors,
|
|
1769
|
+
mergeIntervals,
|
|
1517
1770
|
normalizeDate,
|
|
1771
|
+
parseHourRanges,
|
|
1772
|
+
parseTimeToMinutes,
|
|
1518
1773
|
safeColor,
|
|
1519
1774
|
safeUrl,
|
|
1520
1775
|
slugifyToken,
|