@triptease/tt-calendar 6.1.1 → 6.1.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.
@@ -0,0 +1,435 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.Calendar = void 0;
10
+ const lit_1 = require("lit");
11
+ const decorators_js_1 = require("lit/decorators.js");
12
+ const class_map_js_1 = require("lit/directives/class-map.js");
13
+ const unsafe_svg_js_1 = require("lit/directives/unsafe-svg.js");
14
+ const luxon_1 = require("luxon");
15
+ const DateSelectionContext_js_1 = require("./DateSelectionContext.js");
16
+ const icons_1 = require("@triptease/icons");
17
+ const Styles_js_1 = require("./Styles.js");
18
+ const helpers_js_1 = require("./helpers.js");
19
+ class Calendar extends lit_1.LitElement {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.range = false;
23
+ this.focusedDate = this.today;
24
+ this.visible = false;
25
+ this.newWeek = () => new Array(7).fill(null);
26
+ this.handleButtonKeyDown = (event) => {
27
+ if (event.key === 'Enter' || event.key === ' ') {
28
+ event.stopPropagation();
29
+ }
30
+ };
31
+ this.onDayHover = (event) => {
32
+ const day = event.target.dataset.date;
33
+ if (!day)
34
+ return;
35
+ this.focusedDate = luxon_1.DateTime.fromISO(day);
36
+ };
37
+ this.isStartDate = (date) => Boolean(this.isRange() && this.internalRangeValue?.startDate && this.internalRangeValue.startDate.equals(date));
38
+ this.isEndDate = (date) => Boolean(this.isRange() && this.internalRangeValue?.endDate && this.internalRangeValue.endDate.equals(date));
39
+ this.handleClearSelection = () => {
40
+ this.value = { startDate: undefined, endDate: undefined };
41
+ this.dispatchEvent(new DateSelectionContext_js_1.DateRangeSelectionEvent({ startDate: undefined, endDate: undefined }));
42
+ };
43
+ }
44
+ get internalRangeValue() {
45
+ if (this.range && this.value) {
46
+ const startDate = this.value?.startDate
47
+ ? luxon_1.DateTime.fromISO(this.value.startDate)
48
+ : undefined;
49
+ const endDate = this.value?.endDate
50
+ ? luxon_1.DateTime.fromISO(this.value.endDate)
51
+ : undefined;
52
+ return { startDate, endDate };
53
+ }
54
+ return { startDate: undefined, endDate: undefined };
55
+ }
56
+ getRange() {
57
+ if (this.range && this.internalRangeValue.startDate && this.internalRangeValue.endDate) {
58
+ return luxon_1.Interval.fromDateTimes(this.internalRangeValue.startDate, this.internalRangeValue.endDate.plus({ days: 1 }));
59
+ }
60
+ return luxon_1.Interval.invalid('Invalid range');
61
+ }
62
+ updated(changedProperties) {
63
+ if (changedProperties.has('value') && this.value) {
64
+ super.updateComplete.then(() => {
65
+ if (!this.range) {
66
+ const parsedDate = luxon_1.DateTime.fromISO(this.value);
67
+ this.focusedDate = parsedDate.isValid ? parsedDate : this.today;
68
+ }
69
+ else {
70
+ this.focusedDate = this.internalRangeValue?.startDate || this.today;
71
+ }
72
+ });
73
+ }
74
+ super.updated(changedProperties);
75
+ }
76
+ toggleVisibility() {
77
+ if (this.visible) {
78
+ this.visible = false;
79
+ }
80
+ else {
81
+ this.visible = true;
82
+ this.updateComplete.then(() => {
83
+ this.calendarDiv.focus();
84
+ this.calendarDiv.scrollIntoView({
85
+ behavior: 'smooth',
86
+ block: 'nearest',
87
+ });
88
+ });
89
+ if (!this.range) {
90
+ const parsedDate = luxon_1.DateTime.fromISO(this.value ?? this.today);
91
+ this.focusedDate = parsedDate.isValid ? parsedDate : this.today;
92
+ }
93
+ else {
94
+ this.focusedDate = this.value?.startDate
95
+ ? luxon_1.DateTime.fromISO(this.value.startDate)
96
+ : this.today;
97
+ }
98
+ }
99
+ }
100
+ handleKeyDown(event) {
101
+ const currentDate = this.focusedDate;
102
+ switch (event.key) {
103
+ case 'ArrowLeft':
104
+ event.preventDefault();
105
+ this.focusDay(currentDate.minus({ day: 1 }));
106
+ break;
107
+ case 'ArrowRight':
108
+ event.preventDefault();
109
+ this.focusDay(currentDate.plus({ day: 1 }));
110
+ break;
111
+ case 'ArrowUp':
112
+ event.preventDefault();
113
+ this.focusDay(currentDate.minus({ week: 1 }));
114
+ break;
115
+ case 'ArrowDown':
116
+ event.preventDefault();
117
+ this.focusDay(currentDate.plus({ week: 1 }));
118
+ break;
119
+ case 'Home':
120
+ event.preventDefault();
121
+ // Move to first day of week
122
+ this.focusDay(currentDate.startOf('week'));
123
+ break;
124
+ case 'End':
125
+ event.preventDefault();
126
+ // Move to last day of week
127
+ this.focusDay(currentDate.endOf('week'));
128
+ break;
129
+ case 'PageUp':
130
+ event.preventDefault();
131
+ if (event.shiftKey) {
132
+ // Previous year
133
+ this.focusDay(currentDate.minus({ year: 1 }));
134
+ }
135
+ else {
136
+ // Previous month
137
+ this.focusDay(currentDate.minus({ month: 1 }));
138
+ }
139
+ break;
140
+ case 'PageDown':
141
+ event.preventDefault();
142
+ if (event.shiftKey) {
143
+ // Next year
144
+ this.focusDay(currentDate.plus({ year: 1 }));
145
+ }
146
+ else {
147
+ // Next month
148
+ this.focusDay(currentDate.plus({ month: 1 }));
149
+ }
150
+ break;
151
+ case 'Enter':
152
+ case ' ':
153
+ event.preventDefault();
154
+ this.handleDayClick(this.focusedDate);
155
+ return;
156
+ default:
157
+ return;
158
+ }
159
+ event.preventDefault();
160
+ }
161
+ focusDay(date) {
162
+ this.focusedDate = date;
163
+ this.updateComplete.then(() => {
164
+ const dayElement = this.shadowRoot?.querySelector(`.day[data-date="${date.toISO()}"]`);
165
+ if (dayElement) {
166
+ dayElement.focus();
167
+ }
168
+ });
169
+ }
170
+ getDaysInMonth(date) {
171
+ const startOfMonth = date.startOf('month');
172
+ const endOfMonth = date.endOf('month');
173
+ const weeks = [];
174
+ let currentWeek = this.newWeek();
175
+ let currentDay = startOfMonth;
176
+ while (currentDay <= endOfMonth) {
177
+ // Get the day of week (0-6, Sunday=0, Saturday=6)
178
+ const dayOfWeek = currentDay.weekday === 7 ? 0 : currentDay.weekday;
179
+ currentWeek[dayOfWeek] = currentDay;
180
+ const isWeekComplete = dayOfWeek === 6; // Saturday (last day of week)
181
+ const isLastDayOfMonth = currentDay.hasSame(endOfMonth, 'day');
182
+ if (isWeekComplete || isLastDayOfMonth) {
183
+ weeks.push(currentWeek);
184
+ if (!isLastDayOfMonth) {
185
+ currentWeek = this.newWeek();
186
+ }
187
+ }
188
+ currentDay = currentDay.plus({ days: 1 });
189
+ }
190
+ return weeks;
191
+ }
192
+ previousYear() {
193
+ this.focusedDate = this.focusedDate.minus({ year: 1 });
194
+ }
195
+ previousMonth() {
196
+ this.focusedDate = this.focusedDate.minus({ month: 1 });
197
+ }
198
+ nextMonth() {
199
+ this.focusedDate = this.focusedDate.plus({ month: 1 });
200
+ }
201
+ nextYear() {
202
+ this.focusedDate = this.focusedDate.plus({ year: 1 });
203
+ }
204
+ get today() {
205
+ return luxon_1.DateTime.local();
206
+ }
207
+ handleDayClick(day) {
208
+ if (this.isRange()) {
209
+ if (!this.value?.startDate || this.value?.endDate) {
210
+ this.value = { startDate: day.toISODate() };
211
+ this.focusedDate = day;
212
+ return;
213
+ }
214
+ if (!this.value.endDate) {
215
+ this.value = { ...this.value, endDate: day.toISODate() };
216
+ this.focusedDate = day;
217
+ this.dispatchEvent(new DateSelectionContext_js_1.DateRangeSelectionEvent(this.value));
218
+ return;
219
+ }
220
+ }
221
+ if (day.isValid) {
222
+ this.dispatchEvent(new DateSelectionContext_js_1.DateSelectionEvent(day.toISODate()));
223
+ }
224
+ }
225
+ getWeekdayLabels() {
226
+ const monday = luxon_1.DateTime.fromISO('2024-06-02T00:00:00Z').startOf('week'); //Weeks start on Monday in Luxon https://moment.github.io/luxon/api-docs/index.html#datetimestartof
227
+ const sunday = monday.plus({ days: 6 });
228
+ return Array.from({ length: 7 }, (_, i) => {
229
+ const date = sunday.plus({ days: i });
230
+ return date.toLocaleString({ weekday: 'short' });
231
+ });
232
+ }
233
+ isSelected(date) {
234
+ if (date.equals(this.focusedDate))
235
+ return true;
236
+ if (this.isRange() && this.internalRangeValue.startDate) {
237
+ if (!this.internalRangeValue.endDate) {
238
+ const range = luxon_1.Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate.plus({ days: 1 }));
239
+ return range.contains(date);
240
+ }
241
+ const range = this.getRange();
242
+ return range.contains(date);
243
+ }
244
+ return false;
245
+ }
246
+ isInRange(date) {
247
+ if (!this.isRange() || !this.internalRangeValue?.startDate) {
248
+ return false;
249
+ }
250
+ if (!this.internalRangeValue?.endDate) {
251
+ const range = luxon_1.Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate);
252
+ return range.contains(date) && !this.isStartDate(date) && !date.equals(this.focusedDate);
253
+ }
254
+ const range = this.getRange();
255
+ return range.contains(date) && !this.isStartDate(date) && !this.isEndDate(date);
256
+ }
257
+ isRange() {
258
+ return this.range;
259
+ }
260
+ get isSelectingRange() {
261
+ return Boolean(this.isRange() && this.value?.startDate && !this.value?.endDate);
262
+ }
263
+ handleToggle(e) {
264
+ const details = e.target;
265
+ if (details.open) {
266
+ details.scrollIntoView({
267
+ behavior: 'smooth',
268
+ block: 'nearest',
269
+ });
270
+ }
271
+ }
272
+ render() {
273
+ const weeks = this.getDaysInMonth(this.focusedDate);
274
+ const monthYear = this.focusedDate.toLocaleString({
275
+ month: 'long',
276
+ year: 'numeric',
277
+ });
278
+ return (0, lit_1.html) `
279
+ <div class="calendar-panel" @keydown=${this.handleKeyDown} role="application" aria-label="${monthYear}">
280
+ <div class="calendar-header">
281
+ <button
282
+ @click=${this.previousYear}
283
+ @keydown=${this.handleButtonKeyDown}
284
+ aria-label="Previous year"
285
+ class="compact"
286
+ >
287
+ ${(0, unsafe_svg_js_1.unsafeSVG)(icons_1.doubleChevron)}
288
+ </button>
289
+ <button
290
+ @click=${this.previousMonth}
291
+ @keydown="${this.handleButtonKeyDown}"
292
+ aria-label="Previous month"
293
+ class="compact"
294
+ >
295
+ ${(0, unsafe_svg_js_1.unsafeSVG)(icons_1.chevron)}
296
+ </button>
297
+ <h2>${monthYear}</h2>
298
+ <button
299
+ @click=${this.nextMonth}
300
+ @keydown="${this.handleButtonKeyDown}"
301
+ aria-label="Next month"
302
+ class="compact right"
303
+ >
304
+ ${(0, unsafe_svg_js_1.unsafeSVG)(icons_1.chevron)}
305
+ </button>
306
+ <button
307
+ @click=${this.nextYear}
308
+ @keydown=${this.handleButtonKeyDown}
309
+ aria-label="Next year"
310
+ class="compact right"
311
+ >
312
+ ${(0, unsafe_svg_js_1.unsafeSVG)(icons_1.doubleChevron)}
313
+ </button>
314
+ </div>
315
+ <div class="calendar-grid">
316
+ <table
317
+ role="grid"
318
+ aria-labelledby="month-year"
319
+ data-range="${this.range}"
320
+ class="${this.isSelectingRange ? 'selecting' : ''}"
321
+ >
322
+ <thead>
323
+ <tr>
324
+ ${this.getWeekdayLabels().map((label) => (0, lit_1.html) ` <th>${label}</th>`)}
325
+ </tr>
326
+ </thead>
327
+
328
+ <tbody>
329
+ ${weeks.map((week) => (0, lit_1.html) ` <tr>
330
+ ${week.map((day) => {
331
+ if (!day) {
332
+ return (0, lit_1.html) ` <td></td>`;
333
+ }
334
+ const isDisabled = this.dayIsDisabled(day);
335
+ return (0, lit_1.html) ` <td
336
+ class="${(0, class_map_js_1.classMap)({
337
+ day: true,
338
+ 'in-range': this.isInRange(day),
339
+ 'start-date': this.isStartDate(day),
340
+ 'end-date': this.isEndDate(day),
341
+ })}"
342
+ @click=${() => this.handleDayClick(day)}
343
+ role="gridcell"
344
+ data-date="${day.toISODate()}"
345
+ aria-label="${day.toLocaleString({ dateStyle: 'long' })}"
346
+ aria-selected="${this.isSelected(day)}"
347
+ aria-disabled="${isDisabled}"
348
+ tabindex="-1"
349
+ @mouseenter="${this.onDayHover}"
350
+ >
351
+ ${day.day}
352
+ </td>`;
353
+ })}
354
+ </tr>`)}
355
+ </tbody>
356
+ </table>
357
+ </div>
358
+
359
+ <div class="calendar-footer">
360
+ <div class="actions" @keydown="${this.handleButtonKeyDown}">
361
+ ${this.isRange()
362
+ ? (0, lit_1.html) `
363
+ <button @click=${() => this.handleClearSelection()} data-theme="secondary" id="clear-selection">
364
+ Clear selection
365
+ </button>
366
+ `
367
+ : (0, lit_1.html) ` <button @click=${() => this.handleDayClick(this.today)} data-theme="secondary">Today</button> `}
368
+ </div>
369
+ <div>
370
+ <details @keydown=${this.handleButtonKeyDown} @toggle=${this.handleToggle}>
371
+ <summary>${(0, unsafe_svg_js_1.unsafeSVG)(icons_1.keyboard)} Keyboard commands ${(0, unsafe_svg_js_1.unsafeSVG)(icons_1.chevronDown)}</summary>
372
+ <p>Arrow keys: navigate the calendar</p>
373
+ <p>Enter or Space: select the date</p>
374
+ <p>Escape: close the calendar without selecting a date</p>
375
+ <p>Tab: navigate between the calendar and the presets</p>
376
+ <p>Home: move to first day of week</p>
377
+ <p>End: move to last day of week</p>
378
+ <p>Page Up: move to previous month</p>
379
+ <p>Page Down: move to next month</p>
380
+ <p>Shift + Page Up: move to next year</p>
381
+ <p>Shift + Page Down: move to previous year</p>
382
+ </details>
383
+ </div>
384
+ </div>
385
+ </div>
386
+ `;
387
+ }
388
+ dayIsDisabled(day) {
389
+ if (this.maxDate && day > this.maxDate)
390
+ return true;
391
+ if (this.minDate && day < this.minDate)
392
+ return true;
393
+ if (this.range && this.isSelectingRange && this.internalRangeValue?.startDate) {
394
+ if (day < this.internalRangeValue.startDate)
395
+ return true;
396
+ if (this.maxDays && day > this.internalRangeValue.startDate.plus({ days: this.maxDays }))
397
+ return true;
398
+ }
399
+ return false;
400
+ }
401
+ }
402
+ exports.Calendar = Calendar;
403
+ Calendar.styles = Styles_js_1.styles;
404
+ Calendar.shadowRootOptions = {
405
+ ...lit_1.LitElement.shadowRootOptions,
406
+ delegatesFocus: true,
407
+ };
408
+ __decorate([
409
+ (0, decorators_js_1.property)({ type: String })
410
+ ], Calendar.prototype, "value", void 0);
411
+ __decorate([
412
+ (0, decorators_js_1.property)({ type: Boolean })
413
+ ], Calendar.prototype, "range", void 0);
414
+ __decorate([
415
+ (0, decorators_js_1.property)({ attribute: 'max-date', converter: helpers_js_1.dateTimeConverter })
416
+ ], Calendar.prototype, "maxDate", void 0);
417
+ __decorate([
418
+ (0, decorators_js_1.property)({ type: Number, attribute: 'max-days' })
419
+ ], Calendar.prototype, "maxDays", void 0);
420
+ __decorate([
421
+ (0, decorators_js_1.property)({ attribute: 'min-date', converter: helpers_js_1.dateTimeConverter })
422
+ ], Calendar.prototype, "minDate", void 0);
423
+ __decorate([
424
+ (0, decorators_js_1.property)({ type: Number, attribute: 'min-days' })
425
+ ], Calendar.prototype, "minDays", void 0);
426
+ __decorate([
427
+ (0, decorators_js_1.query)('.calendar-panel')
428
+ ], Calendar.prototype, "calendarDiv", void 0);
429
+ __decorate([
430
+ (0, decorators_js_1.state)()
431
+ ], Calendar.prototype, "focusedDate", void 0);
432
+ __decorate([
433
+ (0, decorators_js_1.state)()
434
+ ], Calendar.prototype, "visible", void 0);
435
+ //# sourceMappingURL=TtCalendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TtCalendar.js","sourceRoot":"","sources":["../../../src/TtCalendar.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement, PropertyValues } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { DateTime, Interval } from 'luxon';\nimport { DateRange, DateRangeSelectionEvent, DateSelectionEvent } from './DateSelectionContext.js';\nimport { chevron, chevronDown, doubleChevron, keyboard } from '@triptease/icons';\nimport { styles } from './Styles.js';\nimport { dateTimeConverter } from './helpers.js';\n\ntype WeekdayList = [\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n DateTime | null,\n];\n\ninterface CalendarWithRange {\n value?: DateRange;\n range: true;\n}\n\ninterface InternalDateRange {\n startDate?: DateTime;\n endDate?: DateTime;\n}\n\nexport class Calendar extends LitElement {\n static styles = styles;\n\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n // Start public properties\n\n @property({ type: String })\n public value?: string | DateRange;\n\n @property({ type: Boolean })\n public range = false;\n\n @property({ attribute: 'max-date', converter: dateTimeConverter })\n public maxDate?: DateTime;\n\n @property({ type: Number, attribute: 'max-days' })\n public maxDays?: number;\n\n @property({ attribute: 'min-date', converter: dateTimeConverter })\n public minDate?: DateTime;\n\n @property({ type: Number, attribute: 'min-days' })\n public minDays?: number;\n\n get internalRangeValue(): InternalDateRange {\n if (this.range && this.value) {\n const startDate = (this.value as DateRange)?.startDate\n ? DateTime.fromISO((this.value as DateRange).startDate!)\n : undefined;\n const endDate = (this.value as DateRange)?.endDate\n ? DateTime.fromISO((this.value as DateRange).endDate!)\n : undefined;\n return { startDate, endDate };\n }\n return { startDate: undefined, endDate: undefined };\n }\n\n getRange(): Interval {\n if (this.range && this.internalRangeValue.startDate && this.internalRangeValue.endDate) {\n return Interval.fromDateTimes(\n this.internalRangeValue.startDate,\n this.internalRangeValue.endDate.plus({ days: 1 })\n );\n }\n return Interval.invalid('Invalid range');\n }\n\n public updated(changedProperties: PropertyValues) {\n if (changedProperties.has('value') && this.value) {\n super.updateComplete.then(() => {\n if (!this.range) {\n const parsedDate = DateTime.fromISO(this.value as string);\n this.focusedDate = parsedDate.isValid ? parsedDate : this.today;\n } else {\n this.focusedDate = this.internalRangeValue?.startDate || this.today;\n }\n });\n }\n super.updated(changedProperties);\n }\n\n public toggleVisibility() {\n if (this.visible) {\n this.visible = false;\n } else {\n this.visible = true;\n this.updateComplete.then(() => {\n this.calendarDiv.focus();\n this.calendarDiv.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n });\n });\n if (!this.range) {\n const parsedDate = DateTime.fromISO((this.value as string) ?? this.today);\n this.focusedDate = parsedDate.isValid ? parsedDate : this.today;\n } else {\n this.focusedDate = (this.value as DateRange)?.startDate\n ? DateTime.fromISO((this.value as DateRange).startDate!)\n : this.today;\n }\n }\n }\n\n // end public properties\n\n @query('.calendar-panel')\n private calendarDiv!: HTMLElement;\n\n @state()\n private focusedDate: DateTime = this.today;\n\n @state()\n private visible: boolean = false;\n\n private handleKeyDown(event: KeyboardEvent) {\n const currentDate = this.focusedDate;\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault();\n this.focusDay(currentDate.minus({ day: 1 }));\n break;\n case 'ArrowRight':\n event.preventDefault();\n this.focusDay(currentDate.plus({ day: 1 }));\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.focusDay(currentDate.minus({ week: 1 }));\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.focusDay(currentDate.plus({ week: 1 }));\n break;\n case 'Home':\n event.preventDefault();\n // Move to first day of week\n this.focusDay(currentDate.startOf('week'));\n break;\n case 'End':\n event.preventDefault();\n // Move to last day of week\n this.focusDay(currentDate.endOf('week'));\n break;\n case 'PageUp':\n event.preventDefault();\n if (event.shiftKey) {\n // Previous year\n this.focusDay(currentDate.minus({ year: 1 }));\n } else {\n // Previous month\n this.focusDay(currentDate.minus({ month: 1 }));\n }\n break;\n case 'PageDown':\n event.preventDefault();\n if (event.shiftKey) {\n // Next year\n this.focusDay(currentDate.plus({ year: 1 }));\n } else {\n // Next month\n this.focusDay(currentDate.plus({ month: 1 }));\n }\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n this.handleDayClick(this.focusedDate);\n return;\n\n default:\n return;\n }\n\n event.preventDefault();\n }\n\n private focusDay(date: DateTime) {\n this.focusedDate = date;\n this.updateComplete.then(() => {\n const dayElement = <HTMLElement | undefined>this.shadowRoot?.querySelector(`.day[data-date=\"${date.toISO()}\"]`);\n if (dayElement) {\n dayElement.focus();\n }\n });\n }\n\n private newWeek = () => new Array(7).fill(null) as WeekdayList;\n\n private getDaysInMonth(date: DateTime): WeekdayList[] {\n const startOfMonth = date.startOf('month');\n const endOfMonth = date.endOf('month');\n\n const weeks: WeekdayList[] = [];\n let currentWeek: WeekdayList = this.newWeek();\n\n let currentDay = startOfMonth;\n\n while (currentDay <= endOfMonth) {\n // Get the day of week (0-6, Sunday=0, Saturday=6)\n const dayOfWeek = currentDay.weekday === 7 ? 0 : currentDay.weekday;\n\n currentWeek[dayOfWeek] = currentDay;\n\n const isWeekComplete = dayOfWeek === 6; // Saturday (last day of week)\n const isLastDayOfMonth = currentDay.hasSame(endOfMonth, 'day');\n\n if (isWeekComplete || isLastDayOfMonth) {\n weeks.push(currentWeek);\n\n if (!isLastDayOfMonth) {\n currentWeek = this.newWeek();\n }\n }\n\n currentDay = currentDay.plus({ days: 1 });\n }\n\n return weeks;\n }\n\n private previousYear() {\n this.focusedDate = this.focusedDate.minus({ year: 1 });\n }\n\n private previousMonth() {\n this.focusedDate = this.focusedDate.minus({ month: 1 });\n }\n\n private nextMonth() {\n this.focusedDate = this.focusedDate.plus({ month: 1 });\n }\n\n private nextYear() {\n this.focusedDate = this.focusedDate.plus({ year: 1 });\n }\n\n private get today(): DateTime {\n return DateTime.local();\n }\n\n private handleDayClick(day: DateTime) {\n if (this.isRange()) {\n if (!this.value?.startDate || this.value?.endDate) {\n this.value = { startDate: day.toISODate()! };\n this.focusedDate = day;\n return;\n }\n\n if (!this.value.endDate) {\n this.value = { ...(this.value as DateRange), endDate: day.toISODate()! };\n this.focusedDate = day;\n this.dispatchEvent(new DateRangeSelectionEvent(this.value));\n return;\n }\n }\n\n if (day.isValid) {\n this.dispatchEvent(new DateSelectionEvent(day.toISODate()!));\n }\n }\n\n private handleButtonKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.stopPropagation();\n }\n };\n\n private getWeekdayLabels(): string[] {\n const monday = DateTime.fromISO('2024-06-02T00:00:00Z').startOf('week'); //Weeks start on Monday in Luxon https://moment.github.io/luxon/api-docs/index.html#datetimestartof\n const sunday = monday.plus({ days: 6 });\n return Array.from({ length: 7 }, (_, i) => {\n const date = sunday.plus({ days: i });\n return date.toLocaleString({ weekday: 'short' });\n });\n }\n\n private isSelected(date: DateTime): boolean {\n if (date.equals(this.focusedDate)) return true;\n\n if (this.isRange() && this.internalRangeValue.startDate) {\n if (!this.internalRangeValue.endDate) {\n const range = Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate.plus({ days: 1 }));\n return range.contains(date);\n }\n\n const range = this.getRange();\n return range.contains(date);\n }\n\n return false;\n }\n\n private isInRange(date: DateTime): boolean {\n if (!this.isRange() || !this.internalRangeValue?.startDate) {\n return false;\n }\n\n if (!this.internalRangeValue?.endDate) {\n const range = Interval.fromDateTimes(this.internalRangeValue.startDate, this.focusedDate);\n return range.contains(date) && !this.isStartDate(date) && !date.equals(this.focusedDate);\n }\n\n const range = this.getRange();\n return range.contains(date) && !this.isStartDate(date) && !this.isEndDate(date);\n }\n\n private isRange(): this is CalendarWithRange {\n return this.range;\n }\n\n private get isSelectingRange(): boolean {\n return Boolean(this.isRange() && this.value?.startDate && !this.value?.endDate);\n }\n\n private onDayHover = (event: MouseEvent) => {\n const day = (event.target as HTMLElement).dataset.date;\n if (!day) return;\n\n this.focusedDate = DateTime.fromISO(day);\n };\n\n private isStartDate = (date: DateTime): boolean =>\n Boolean(this.isRange() && this.internalRangeValue?.startDate && this.internalRangeValue.startDate.equals(date));\n\n private isEndDate = (date: DateTime): boolean =>\n Boolean(this.isRange() && this.internalRangeValue?.endDate && this.internalRangeValue.endDate.equals(date));\n\n private handleClearSelection = () => {\n this.value = { startDate: undefined, endDate: undefined };\n this.dispatchEvent(new DateRangeSelectionEvent({ startDate: undefined, endDate: undefined }));\n };\n\n private handleToggle(e: Event) {\n const details = e.target as HTMLDetailsElement;\n if (details.open) {\n details.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n });\n }\n }\n\n render() {\n const weeks = this.getDaysInMonth(this.focusedDate);\n const monthYear = this.focusedDate.toLocaleString({\n month: 'long',\n year: 'numeric',\n });\n\n return html`\n <div class=\"calendar-panel\" @keydown=${this.handleKeyDown} role=\"application\" aria-label=\"${monthYear}\">\n <div class=\"calendar-header\">\n <button\n @click=${this.previousYear}\n @keydown=${this.handleButtonKeyDown}\n aria-label=\"Previous year\"\n class=\"compact\"\n >\n ${unsafeSVG(doubleChevron)}\n </button>\n <button\n @click=${this.previousMonth}\n @keydown=\"${this.handleButtonKeyDown}\"\n aria-label=\"Previous month\"\n class=\"compact\"\n >\n ${unsafeSVG(chevron)}\n </button>\n <h2>${monthYear}</h2>\n <button\n @click=${this.nextMonth}\n @keydown=\"${this.handleButtonKeyDown}\"\n aria-label=\"Next month\"\n class=\"compact right\"\n >\n ${unsafeSVG(chevron)}\n </button>\n <button\n @click=${this.nextYear}\n @keydown=${this.handleButtonKeyDown}\n aria-label=\"Next year\"\n class=\"compact right\"\n >\n ${unsafeSVG(doubleChevron)}\n </button>\n </div>\n <div class=\"calendar-grid\">\n <table\n role=\"grid\"\n aria-labelledby=\"month-year\"\n data-range=\"${this.range}\"\n class=\"${this.isSelectingRange ? 'selecting' : ''}\"\n >\n <thead>\n <tr>\n ${this.getWeekdayLabels().map((label) => html` <th>${label}</th>`)}\n </tr>\n </thead>\n\n <tbody>\n ${weeks.map(\n (week) =>\n html` <tr>\n ${week.map((day) => {\n if (!day) {\n return html` <td></td>`;\n }\n\n const isDisabled = this.dayIsDisabled(day);\n\n return html` <td\n class=\"${classMap({\n day: true,\n 'in-range': this.isInRange(day),\n 'start-date': this.isStartDate(day),\n 'end-date': this.isEndDate(day),\n })}\"\n @click=${() => this.handleDayClick(day)}\n role=\"gridcell\"\n data-date=\"${day.toISODate()}\"\n aria-label=\"${day.toLocaleString({ dateStyle: 'long' })}\"\n aria-selected=\"${this.isSelected(day)}\"\n aria-disabled=\"${isDisabled}\"\n tabindex=\"-1\"\n @mouseenter=\"${this.onDayHover}\"\n >\n ${day.day}\n </td>`;\n })}\n </tr>`\n )}\n </tbody>\n </table>\n </div>\n\n <div class=\"calendar-footer\">\n <div class=\"actions\" @keydown=\"${this.handleButtonKeyDown}\">\n ${this.isRange()\n ? html`\n <button @click=${() => this.handleClearSelection()} data-theme=\"secondary\" id=\"clear-selection\">\n Clear selection\n </button>\n `\n : html` <button @click=${() => this.handleDayClick(this.today)} data-theme=\"secondary\">Today</button> `}\n </div>\n <div>\n <details @keydown=${this.handleButtonKeyDown} @toggle=${this.handleToggle}>\n <summary>${unsafeSVG(keyboard)} Keyboard commands ${unsafeSVG(chevronDown)}</summary>\n <p>Arrow keys: navigate the calendar</p>\n <p>Enter or Space: select the date</p>\n <p>Escape: close the calendar without selecting a date</p>\n <p>Tab: navigate between the calendar and the presets</p>\n <p>Home: move to first day of week</p>\n <p>End: move to last day of week</p>\n <p>Page Up: move to previous month</p>\n <p>Page Down: move to next month</p>\n <p>Shift + Page Up: move to next year</p>\n <p>Shift + Page Down: move to previous year</p>\n </details>\n </div>\n </div>\n </div>\n `;\n }\n\n private dayIsDisabled(day: DateTime) {\n if (this.maxDate && day > this.maxDate) return true;\n\n if (this.minDate && day < this.minDate) return true;\n\n if (this.range && this.isSelectingRange && this.internalRangeValue?.startDate) {\n if (day < this.internalRangeValue.startDate) return true;\n\n if (this.maxDays && day > this.internalRangeValue.startDate.plus({ days: this.maxDays })) return true;\n }\n\n return false;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tt-calendar': Calendar;\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dateTimeConverter = exports.dateConverter = void 0;
4
+ const luxon_1 = require("luxon");
5
+ const dateConverter = (value) => value ? luxon_1.DateTime.fromISO(value).toJSDate() : undefined;
6
+ exports.dateConverter = dateConverter;
7
+ const dateTimeConverter = (value) => value ? luxon_1.DateTime.fromISO(value) : undefined;
8
+ exports.dateTimeConverter = dateTimeConverter;
9
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/helpers.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AAE1B,MAAM,aAAa,GAAG,CAAC,KAAoB,EAAoB,EAAE,CACtE,KAAK,CAAC,CAAC,CAAC,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAD5C,QAAA,aAAa,iBAC+B;AAElD,MAAM,iBAAiB,GAAG,CAAC,KAAoB,EAAwB,EAAE,CAC9E,KAAK,CAAC,CAAC,CAAC,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AADjC,QAAA,iBAAiB,qBACgB","sourcesContent":["import { DateTime } from 'luxon';\n\nexport const dateConverter = (value: string | null): Date | undefined =>\n value ? DateTime.fromISO(value).toJSDate() : undefined;\n\nexport const dateTimeConverter = (value: string | null): DateTime | undefined =>\n value ? DateTime.fromISO(value) : undefined;\n"]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Calendar = void 0;
4
+ var tt_calendar_js_1 = require("./tt-calendar.js");
5
+ Object.defineProperty(exports, "Calendar", { enumerable: true, get: function () { return tt_calendar_js_1.Calendar; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":";;;AAAA,mDAA4C;AAAnC,0GAAA,QAAQ,OAAA","sourcesContent":["export { Calendar } from './tt-calendar.js';\n"]}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Calendar = void 0;
4
+ const TtCalendar_js_1 = require("./TtCalendar.js");
5
+ Object.defineProperty(exports, "Calendar", { enumerable: true, get: function () { return TtCalendar_js_1.Calendar; } });
6
+ if (typeof window !== 'undefined') {
7
+ if (!window.customElements.get('tt-calendar')) {
8
+ window.customElements.define('tt-calendar', TtCalendar_js_1.Calendar);
9
+ }
10
+ }
11
+ //# sourceMappingURL=tt-calendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tt-calendar.js","sourceRoot":"","sources":["../../../src/tt-calendar.ts"],"names":[],"mappings":";;;AAAA,mDAA2C;AAQlC,yFARA,wBAAQ,OAQA;AANjB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9C,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,aAAa,EAAE,wBAAQ,CAAC,CAAC;IACxD,CAAC;AACH,CAAC","sourcesContent":["import { Calendar } from './TtCalendar.js';\n\nif (typeof window !== 'undefined') {\n if (!window.customElements.get('tt-calendar')) {\n window.customElements.define('tt-calendar', Calendar);\n }\n}\n\nexport { Calendar };\n"]}
package/package.json CHANGED
@@ -3,8 +3,12 @@
3
3
  "description": "Webcomponent tt-calendar following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "@triptease",
6
- "version": "6.1.1",
6
+ "version": "6.1.2",
7
7
  "type": "module",
8
+ "files": [
9
+ "dist/esm",
10
+ "dist/cjs"
11
+ ],
8
12
  "main": "dist/esm/src/index.js",
9
13
  "module": "dist/esm/src/index.js",
10
14
  "exports": {
@@ -39,7 +43,7 @@
39
43
  },
40
44
  "dependencies": {
41
45
  "@lit/context": "^1.1.5",
42
- "@triptease/icons": "1.4.0",
46
+ "@triptease/icons": "1.4.1",
43
47
  "@types/luxon": "^3.6.2",
44
48
  "lit": "^3.1.4",
45
49
  "luxon": "^3.6.1"