@liwe3/webcomponents 1.0.0 → 1.0.14

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,372 @@
1
+ class w extends HTMLElement {
2
+ constructor() {
3
+ super(), this.currentDate = /* @__PURE__ */ new Date(), this.selectedDate = null, this.selectedRange = { start: null, end: null }, this.MONTH_NAMES = [
4
+ "January",
5
+ "February",
6
+ "March",
7
+ "April",
8
+ "May",
9
+ "June",
10
+ "July",
11
+ "August",
12
+ "September",
13
+ "October",
14
+ "November",
15
+ "December"
16
+ ], this.DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], this.attachShadow({ mode: "open" }), this.render(), this.attachEventListeners();
17
+ }
18
+ static get observedAttributes() {
19
+ return ["range-mode", "selected-date", "selected-range"];
20
+ }
21
+ attributeChangedCallback(e) {
22
+ e === "range-mode" && (this.selectedDate = null, this.selectedRange = { start: null, end: null }, this.render());
23
+ }
24
+ get rangeMode() {
25
+ return this.hasAttribute("range-mode");
26
+ }
27
+ set rangeMode(e) {
28
+ e ? this.setAttribute("range-mode", "") : this.removeAttribute("range-mode");
29
+ }
30
+ /**
31
+ * Renders the date selector component
32
+ */
33
+ render() {
34
+ const e = this.currentDate.getFullYear(), t = this.currentDate.getMonth();
35
+ this.shadowRoot.innerHTML = `
36
+ <style>
37
+ :host {
38
+ display: block;
39
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
40
+ background: white;
41
+ border: 1px solid #e0e0e0;
42
+ border-radius: 8px;
43
+ padding: 16px;
44
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
45
+ width: 320px;
46
+ }
47
+
48
+ .header {
49
+ display: flex;
50
+ justify-content: space-between;
51
+ align-items: center;
52
+ margin-bottom: 16px;
53
+ }
54
+
55
+ .month-year {
56
+ font-size: 18px;
57
+ font-weight: 600;
58
+ color: #333;
59
+ padding-left: 4px;
60
+ }
61
+
62
+ .nav-buttons {
63
+ display: flex;
64
+ gap: 8px;
65
+ }
66
+
67
+ .nav-btn {
68
+ background: #f5f5f5;
69
+ border: none;
70
+ width: 32px;
71
+ height: 32px;
72
+ border-radius: 4px;
73
+ cursor: pointer;
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ font-size: 14px;
78
+ transition: background-color 0.2s;
79
+ }
80
+
81
+ .nav-btn:hover {
82
+ background: #e0e0e0;
83
+ }
84
+
85
+ .year-selector {
86
+ background: transparent;
87
+ border: none;
88
+ font-size: 18px;
89
+ font-weight: 600;
90
+ color: #333;
91
+ cursor: pointer;
92
+ padding: 4px;
93
+ border-radius: 4px;
94
+ }
95
+
96
+ .year-selector:hover {
97
+ background: #f5f5f5;
98
+ }
99
+
100
+ .calendar-grid {
101
+ display: grid;
102
+ grid-template-columns: repeat(7, 1fr);
103
+ gap: 2px;
104
+ }
105
+
106
+ .day-header {
107
+ text-align: center;
108
+ font-size: 12px;
109
+ font-weight: 600;
110
+ color: #666;
111
+ padding: 8px 4px;
112
+ }
113
+
114
+ .day-cell {
115
+ aspect-ratio: 1;
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ font-size: 14px;
120
+ cursor: pointer;
121
+ border-radius: 4px;
122
+ transition: all 0.2s;
123
+ position: relative;
124
+ }
125
+
126
+ .day-cell:hover {
127
+ background: #f0f0f0;
128
+ }
129
+
130
+ .day-cell.other-month {
131
+ color: #ccc;
132
+ }
133
+
134
+ .day-cell.today {
135
+ background: #e3f2fd;
136
+ font-weight: 600;
137
+ }
138
+
139
+ .day-cell.selected {
140
+ background: #2196f3;
141
+ color: white;
142
+ }
143
+
144
+ .day-cell.range-start {
145
+ background: #2196f3;
146
+ color: white;
147
+ }
148
+
149
+ .day-cell.range-end {
150
+ background: #2196f3;
151
+ color: white;
152
+ }
153
+
154
+ .day-cell.in-range {
155
+ background: #bbdefb;
156
+ color: #1976d2;
157
+ }
158
+
159
+ .day-cell.range-hover {
160
+ background: #e3f2fd;
161
+ }
162
+
163
+ .mode-indicator {
164
+ font-size: 12px;
165
+ color: #666;
166
+ margin-bottom: 8px;
167
+ text-align: center;
168
+ }
169
+ </style>
170
+
171
+ <div class="mode-indicator">
172
+ ${this.rangeMode ? "Select date range" : "Select a date"}
173
+ </div>
174
+
175
+ <div class="header">
176
+ <div class="month-year">
177
+ ${this.MONTH_NAMES[t]}
178
+ <select class="year-selector" id="yearSelector">
179
+ ${this.generateYearOptions(e)}
180
+ </select>
181
+ </div>
182
+ <div class="nav-buttons">
183
+ <button class="nav-btn" id="prevMonth">‹</button>
184
+ <button class="nav-btn" id="nextMonth">›</button>
185
+ </div>
186
+ </div>
187
+
188
+ <div class="calendar-grid">
189
+ ${this.generateCalendarGrid(e, t)}
190
+ </div>
191
+ `, this.attachEventListenersToShadowRoot();
192
+ }
193
+ /**
194
+ * Generates year options for the dropdown (current year ±10 years)
195
+ */
196
+ generateYearOptions(e) {
197
+ const t = e - 10, a = e + 10;
198
+ let s = "";
199
+ for (let r = t; r <= a; r++)
200
+ s += `<option value="${r}" ${r === e ? "selected" : ""}>${r}</option>`;
201
+ return s;
202
+ }
203
+ /**
204
+ * Generates the calendar grid with day headers and day cells
205
+ */
206
+ generateCalendarGrid(e, t) {
207
+ let a = "";
208
+ this.DAY_NAMES.forEach((n) => {
209
+ a += `<div class="day-header">${n}</div>`;
210
+ });
211
+ const s = new Date(e, t, 1), r = new Date(e, t + 1, 0), i = s.getDay(), d = r.getDate(), g = t === 0 ? 11 : t - 1, u = t === 0 ? e - 1 : e, f = new Date(u, g + 1, 0).getDate();
212
+ for (let n = i - 1; n >= 0; n--) {
213
+ const o = f - n;
214
+ a += `<div class="day-cell other-month" data-date="${u}-${(g + 1).toString().padStart(2, "0")}-${o.toString().padStart(2, "0")}">${o}</div>`;
215
+ }
216
+ const h = /* @__PURE__ */ new Date(), p = h.getFullYear() === e && h.getMonth() === t;
217
+ for (let n = 1; n <= d; n++) {
218
+ const o = `${e}-${(t + 1).toString().padStart(2, "0")}-${n.toString().padStart(2, "0")}`, y = p && h.getDate() === n;
219
+ let l = "day-cell";
220
+ y && (l += " today"), this.rangeMode ? this.selectedRange.start && this.dateMatches(o, this.selectedRange.start) ? l += " range-start" : this.selectedRange.end && this.dateMatches(o, this.selectedRange.end) ? l += " range-end" : this.isDateInRange(o) && (l += " in-range") : this.selectedDate && this.dateMatches(o, this.selectedDate) && (l += " selected"), a += `<div class="${l}" data-date="${o}">${n}</div>`;
221
+ }
222
+ const v = Math.ceil((i + d) / 7) * 7 - (i + d), D = t === 11 ? 0 : t + 1, b = t === 11 ? e + 1 : e;
223
+ for (let n = 1; n <= v; n++)
224
+ a += `<div class="day-cell other-month" data-date="${b}-${(D + 1).toString().padStart(2, "0")}-${n.toString().padStart(2, "0")}">${n}</div>`;
225
+ return a;
226
+ }
227
+ /**
228
+ * Checks if two date strings match
229
+ */
230
+ dateMatches(e, t) {
231
+ return e === t;
232
+ }
233
+ /**
234
+ * Checks if a date is within the selected range
235
+ */
236
+ isDateInRange(e) {
237
+ if (!this.selectedRange.start || !this.selectedRange.end) return !1;
238
+ const t = new Date(e), a = new Date(this.selectedRange.start), s = new Date(this.selectedRange.end);
239
+ return t > a && t < s;
240
+ }
241
+ /**
242
+ * Attaches main event listeners (called once during construction)
243
+ */
244
+ attachEventListeners() {
245
+ this.shadowRoot.addEventListener("click", (e) => {
246
+ const t = e.target;
247
+ t.id === "prevMonth" ? this.navigateMonth(-1) : t.id === "nextMonth" ? this.navigateMonth(1) : t.classList.contains("day-cell") && this.handleDayClick(t);
248
+ }), this.shadowRoot.addEventListener("change", (e) => {
249
+ const t = e.target;
250
+ t.id === "yearSelector" && this.navigateToYear(parseInt(t.value));
251
+ }), this.rangeMode && (this.shadowRoot.addEventListener("mouseover", (e) => {
252
+ const t = e.target;
253
+ t.classList.contains("day-cell") && this.selectedRange.start && !this.selectedRange.end && this.updateRangeHover(t.dataset.date);
254
+ }), this.shadowRoot.addEventListener("mouseleave", () => {
255
+ this.clearRangeHover();
256
+ }));
257
+ }
258
+ /**
259
+ * Called after each render to setup any post-render event listeners
260
+ */
261
+ attachEventListenersToShadowRoot() {
262
+ }
263
+ /**
264
+ * Navigates to the previous or next month
265
+ */
266
+ navigateMonth(e) {
267
+ const t = this.currentDate.getFullYear(), s = this.currentDate.getMonth() + e;
268
+ s < 0 ? this.currentDate = new Date(t - 1, 11, 1) : s > 11 ? this.currentDate = new Date(t + 1, 0, 1) : this.currentDate = new Date(t, s, 1), this.render();
269
+ }
270
+ /**
271
+ * Navigates to a specific year
272
+ */
273
+ navigateToYear(e) {
274
+ this.currentDate = new Date(e, this.currentDate.getMonth(), 1), this.render();
275
+ }
276
+ /**
277
+ * Handles click on a day cell
278
+ */
279
+ handleDayClick(e) {
280
+ const t = e.dataset.date;
281
+ this.rangeMode ? this.handleRangeSelection(t) : this.handleSingleSelection(t), this.render();
282
+ }
283
+ /**
284
+ * Handles single date selection
285
+ */
286
+ handleSingleSelection(e) {
287
+ this.selectedDate = e, this.dispatchEvent(new CustomEvent("dateSelected", {
288
+ detail: { date: e },
289
+ bubbles: !0
290
+ }));
291
+ }
292
+ /**
293
+ * Handles range selection
294
+ */
295
+ handleRangeSelection(e) {
296
+ if (!this.selectedRange.start || this.selectedRange.start && this.selectedRange.end)
297
+ this.selectedRange = { start: e, end: null };
298
+ else {
299
+ const t = new Date(this.selectedRange.start);
300
+ new Date(e) < t ? this.selectedRange = { start: e, end: this.selectedRange.start } : this.selectedRange.end = e, this.dispatchEvent(new CustomEvent("rangeSelected", {
301
+ detail: {
302
+ start: this.selectedRange.start,
303
+ end: this.selectedRange.end
304
+ },
305
+ bubbles: !0
306
+ }));
307
+ }
308
+ }
309
+ /**
310
+ * Updates hover effect when selecting a range
311
+ */
312
+ updateRangeHover(e) {
313
+ const t = this.shadowRoot.querySelectorAll(".day-cell:not(.other-month)"), a = new Date(this.selectedRange.start), s = new Date(e);
314
+ t.forEach((r) => {
315
+ const i = r, d = new Date(i.dataset.date);
316
+ i.classList.remove("range-hover"), d > a && d <= s && i.classList.add("range-hover");
317
+ });
318
+ }
319
+ /**
320
+ * Clears the hover effect for range selection
321
+ */
322
+ clearRangeHover() {
323
+ this.shadowRoot.querySelectorAll(".day-cell").forEach((t) => {
324
+ t.classList.remove("range-hover");
325
+ });
326
+ }
327
+ /**
328
+ * Sets the selected date programmatically (single date mode only)
329
+ */
330
+ setDate(e) {
331
+ if (this.rangeMode) return;
332
+ this.selectedDate = e;
333
+ const t = new Date(e);
334
+ this.currentDate = new Date(t.getFullYear(), t.getMonth(), 1), this.render();
335
+ }
336
+ /**
337
+ * Sets the selected range programmatically (range mode only)
338
+ */
339
+ setRange(e, t) {
340
+ if (!this.rangeMode) return;
341
+ this.selectedRange = { start: e, end: t };
342
+ const a = new Date(e);
343
+ this.currentDate = new Date(a.getFullYear(), a.getMonth(), 1), this.render();
344
+ }
345
+ /**
346
+ * Gets the currently selected date
347
+ */
348
+ getSelectedDate() {
349
+ return this.selectedDate;
350
+ }
351
+ /**
352
+ * Gets the currently selected range
353
+ */
354
+ getSelectedRange() {
355
+ return this.selectedRange;
356
+ }
357
+ /**
358
+ * Clears the current selection
359
+ */
360
+ clear() {
361
+ this.selectedDate = null, this.selectedRange = { start: null, end: null }, this.render();
362
+ }
363
+ }
364
+ const R = (c = "liwe3-date-selector") => {
365
+ typeof window < "u" && !window.customElements.get(c) && customElements.define(c, w);
366
+ };
367
+ R();
368
+ export {
369
+ w as DateSelectorElement,
370
+ R as defineDateSelector
371
+ };
372
+ //# sourceMappingURL=DateSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateSelector.js","sources":["../src/DateSelector.ts"],"sourcesContent":["/**\n * DateSelector Web Component\n * A customizable date picker with single date and range selection modes\n */\n\nexport type DateRange = {\n start: string | null;\n end: string | null;\n};\n\nexport class DateSelectorElement extends HTMLElement {\n declare shadowRoot: ShadowRoot;\n private currentDate: Date = new Date();\n private selectedDate: string | null = null;\n private selectedRange: DateRange = { start: null, end: null };\n\n // Month and day names for localization\n private readonly MONTH_NAMES: string[] = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December'\n ];\n\n private readonly DAY_NAMES: string[] = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n this.render();\n this.attachEventListeners();\n }\n\n static get observedAttributes(): string[] {\n return ['range-mode', 'selected-date', 'selected-range'];\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'range-mode') {\n this.selectedDate = null;\n this.selectedRange = { start: null, end: null };\n this.render();\n }\n }\n\n get rangeMode(): boolean {\n return this.hasAttribute('range-mode');\n }\n\n set rangeMode(value: boolean) {\n if (value) {\n this.setAttribute('range-mode', '');\n } else {\n this.removeAttribute('range-mode');\n }\n }\n\n /**\n * Renders the date selector component\n */\n private render(): void {\n const year = this.currentDate.getFullYear();\n const month = this.currentDate.getMonth();\n\n this.shadowRoot.innerHTML = `\n <style>\n :host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n padding: 16px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n width: 320px;\n }\n\n .header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n }\n\n .month-year {\n font-size: 18px;\n font-weight: 600;\n color: #333;\n padding-left: 4px;\n }\n\n .nav-buttons {\n display: flex;\n gap: 8px;\n }\n\n .nav-btn {\n background: #f5f5f5;\n border: none;\n width: 32px;\n height: 32px;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n transition: background-color 0.2s;\n }\n\n .nav-btn:hover {\n background: #e0e0e0;\n }\n\n .year-selector {\n background: transparent;\n border: none;\n font-size: 18px;\n font-weight: 600;\n color: #333;\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n }\n\n .year-selector:hover {\n background: #f5f5f5;\n }\n\n .calendar-grid {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n gap: 2px;\n }\n\n .day-header {\n text-align: center;\n font-size: 12px;\n font-weight: 600;\n color: #666;\n padding: 8px 4px;\n }\n\n .day-cell {\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.2s;\n position: relative;\n }\n\n .day-cell:hover {\n background: #f0f0f0;\n }\n\n .day-cell.other-month {\n color: #ccc;\n }\n\n .day-cell.today {\n background: #e3f2fd;\n font-weight: 600;\n }\n\n .day-cell.selected {\n background: #2196f3;\n color: white;\n }\n\n .day-cell.range-start {\n background: #2196f3;\n color: white;\n }\n\n .day-cell.range-end {\n background: #2196f3;\n color: white;\n }\n\n .day-cell.in-range {\n background: #bbdefb;\n color: #1976d2;\n }\n\n .day-cell.range-hover {\n background: #e3f2fd;\n }\n\n .mode-indicator {\n font-size: 12px;\n color: #666;\n margin-bottom: 8px;\n text-align: center;\n }\n </style>\n\n <div class=\"mode-indicator\">\n ${this.rangeMode ? 'Select date range' : 'Select a date'}\n </div>\n\n <div class=\"header\">\n <div class=\"month-year\">\n ${this.MONTH_NAMES[month]}\n <select class=\"year-selector\" id=\"yearSelector\">\n ${this.generateYearOptions(year)}\n </select>\n </div>\n <div class=\"nav-buttons\">\n <button class=\"nav-btn\" id=\"prevMonth\">‹</button>\n <button class=\"nav-btn\" id=\"nextMonth\">›</button>\n </div>\n </div>\n\n <div class=\"calendar-grid\">\n ${this.generateCalendarGrid(year, month)}\n </div>\n `;\n\n // Reattach event listeners after rendering\n this.attachEventListenersToShadowRoot();\n }\n\n /**\n * Generates year options for the dropdown (current year ±10 years)\n */\n private generateYearOptions(currentYear: number): string {\n const START_YEAR = currentYear - 10;\n const END_YEAR = currentYear + 10;\n let options = '';\n\n for (let year = START_YEAR; year <= END_YEAR; year++) {\n const selected = year === currentYear ? 'selected' : '';\n options += `<option value=\"${year}\" ${selected}>${year}</option>`;\n }\n\n return options;\n }\n\n /**\n * Generates the calendar grid with day headers and day cells\n */\n private generateCalendarGrid(year: number, month: number): string {\n let grid = '';\n\n // Add day headers\n this.DAY_NAMES.forEach(day => {\n grid += `<div class=\"day-header\">${day}</div>`;\n });\n\n // Get first day of month and number of days\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n const firstDayOfWeek = firstDay.getDay();\n const daysInMonth = lastDay.getDate();\n\n // Add previous month's trailing days\n const prevMonth = month === 0 ? 11 : month - 1;\n const prevYear = month === 0 ? year - 1 : year;\n const daysInPrevMonth = new Date(prevYear, prevMonth + 1, 0).getDate();\n\n for (let i = firstDayOfWeek - 1; i >= 0; i--) {\n const day = daysInPrevMonth - i;\n grid += `<div class=\"day-cell other-month\" data-date=\"${prevYear}-${(prevMonth + 1).toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}\">${day}</div>`;\n }\n\n // Add current month days\n const today = new Date();\n const isCurrentMonth = today.getFullYear() === year && today.getMonth() === month;\n\n for (let day = 1; day <= daysInMonth; day++) {\n const dateStr = `${year}-${(month + 1).toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;\n const isToday = isCurrentMonth && today.getDate() === day;\n\n let classes = 'day-cell';\n if (isToday) classes += ' today';\n\n // Add selection classes\n if (this.rangeMode) {\n if (this.selectedRange.start && this.dateMatches(dateStr, this.selectedRange.start)) {\n classes += ' range-start';\n } else if (this.selectedRange.end && this.dateMatches(dateStr, this.selectedRange.end)) {\n classes += ' range-end';\n } else if (this.isDateInRange(dateStr)) {\n classes += ' in-range';\n }\n } else {\n if (this.selectedDate && this.dateMatches(dateStr, this.selectedDate)) {\n classes += ' selected';\n }\n }\n\n grid += `<div class=\"${classes}\" data-date=\"${dateStr}\">${day}</div>`;\n }\n\n // Add next month's leading days\n const totalCells = Math.ceil((firstDayOfWeek + daysInMonth) / 7) * 7;\n const remainingCells = totalCells - (firstDayOfWeek + daysInMonth);\n const nextMonth = month === 11 ? 0 : month + 1;\n const nextYear = month === 11 ? year + 1 : year;\n\n for (let day = 1; day <= remainingCells; day++) {\n grid += `<div class=\"day-cell other-month\" data-date=\"${nextYear}-${(nextMonth + 1).toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}\">${day}</div>`;\n }\n\n return grid;\n }\n\n /**\n * Checks if two date strings match\n */\n private dateMatches(dateStr1: string, dateStr2: string): boolean {\n return dateStr1 === dateStr2;\n }\n\n /**\n * Checks if a date is within the selected range\n */\n private isDateInRange(dateStr: string): boolean {\n if (!this.selectedRange.start || !this.selectedRange.end) return false;\n\n const date = new Date(dateStr);\n const start = new Date(this.selectedRange.start);\n const end = new Date(this.selectedRange.end);\n\n return date > start && date < end;\n }\n\n /**\n * Attaches main event listeners (called once during construction)\n */\n private attachEventListeners(): void {\n // Main event delegation - only attach once\n this.shadowRoot.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n\n if (target.id === 'prevMonth') {\n this.navigateMonth(-1);\n } else if (target.id === 'nextMonth') {\n this.navigateMonth(1);\n } else if (target.classList.contains('day-cell')) {\n this.handleDayClick(target);\n }\n });\n\n this.shadowRoot.addEventListener('change', (e) => {\n const target = e.target as HTMLSelectElement;\n if (target.id === 'yearSelector') {\n this.navigateToYear(parseInt(target.value));\n }\n });\n\n // Add hover effects for range selection\n if (this.rangeMode) {\n this.shadowRoot.addEventListener('mouseover', (e) => {\n const target = e.target as HTMLElement;\n if (target.classList.contains('day-cell') && this.selectedRange.start && !this.selectedRange.end) {\n this.updateRangeHover(target.dataset.date!);\n }\n });\n\n this.shadowRoot.addEventListener('mouseleave', () => {\n this.clearRangeHover();\n });\n }\n }\n\n /**\n * Called after each render to setup any post-render event listeners\n */\n private attachEventListenersToShadowRoot(): void {\n // This method is for any post-render setup if needed\n // Currently empty as we use event delegation\n }\n\n /**\n * Navigates to the previous or next month\n */\n private navigateMonth(direction: number): void {\n const currentYear = this.currentDate.getFullYear();\n const currentMonth = this.currentDate.getMonth();\n const newMonth = currentMonth + direction;\n\n // Handle year transitions properly\n if (newMonth < 0) {\n this.currentDate = new Date(currentYear - 1, 11, 1);\n } else if (newMonth > 11) {\n this.currentDate = new Date(currentYear + 1, 0, 1);\n } else {\n this.currentDate = new Date(currentYear, newMonth, 1);\n }\n\n this.render();\n }\n\n /**\n * Navigates to a specific year\n */\n private navigateToYear(year: number): void {\n this.currentDate = new Date(year, this.currentDate.getMonth(), 1);\n this.render();\n }\n\n /**\n * Handles click on a day cell\n */\n private handleDayClick(dayElement: HTMLElement): void {\n const dateStr = dayElement.dataset.date!;\n\n if (this.rangeMode) {\n this.handleRangeSelection(dateStr);\n } else {\n this.handleSingleSelection(dateStr);\n }\n\n this.render();\n }\n\n /**\n * Handles single date selection\n */\n private handleSingleSelection(dateStr: string): void {\n this.selectedDate = dateStr;\n\n // Dispatch custom event\n this.dispatchEvent(new CustomEvent('dateSelected', {\n detail: { date: dateStr },\n bubbles: true\n }));\n }\n\n /**\n * Handles range selection\n */\n private handleRangeSelection(dateStr: string): void {\n if (!this.selectedRange.start || (this.selectedRange.start && this.selectedRange.end)) {\n // Start new selection\n this.selectedRange = { start: dateStr, end: null };\n } else {\n // Complete the range\n const startDate = new Date(this.selectedRange.start);\n const endDate = new Date(dateStr);\n\n if (endDate < startDate) {\n // Swap if end is before start\n this.selectedRange = { start: dateStr, end: this.selectedRange.start };\n } else {\n this.selectedRange.end = dateStr;\n }\n\n // Dispatch custom event\n this.dispatchEvent(new CustomEvent('rangeSelected', {\n detail: {\n start: this.selectedRange.start,\n end: this.selectedRange.end\n },\n bubbles: true\n }));\n }\n }\n\n /**\n * Updates hover effect when selecting a range\n */\n private updateRangeHover(hoverDate: string): void {\n const dayCells = this.shadowRoot.querySelectorAll('.day-cell:not(.other-month)');\n const startDate = new Date(this.selectedRange.start!);\n const hoverDateObj = new Date(hoverDate);\n\n dayCells.forEach(cell => {\n const cellElement = cell as HTMLElement;\n const cellDate = new Date(cellElement.dataset.date!);\n cellElement.classList.remove('range-hover');\n\n if (cellDate > startDate && cellDate <= hoverDateObj) {\n cellElement.classList.add('range-hover');\n }\n });\n }\n\n /**\n * Clears the hover effect for range selection\n */\n private clearRangeHover(): void {\n const dayCells = this.shadowRoot.querySelectorAll('.day-cell');\n dayCells.forEach(cell => {\n cell.classList.remove('range-hover');\n });\n }\n\n /**\n * Sets the selected date programmatically (single date mode only)\n */\n public setDate(dateStr: string): void {\n if (this.rangeMode) return;\n this.selectedDate = dateStr;\n const date = new Date(dateStr);\n this.currentDate = new Date(date.getFullYear(), date.getMonth(), 1);\n this.render();\n }\n\n /**\n * Sets the selected range programmatically (range mode only)\n */\n public setRange(startDate: string, endDate: string): void {\n if (!this.rangeMode) return;\n this.selectedRange = { start: startDate, end: endDate };\n const date = new Date(startDate);\n this.currentDate = new Date(date.getFullYear(), date.getMonth(), 1);\n this.render();\n }\n\n /**\n * Gets the currently selected date\n */\n public getSelectedDate(): string | null {\n return this.selectedDate;\n }\n\n /**\n * Gets the currently selected range\n */\n public getSelectedRange(): DateRange {\n return this.selectedRange;\n }\n\n /**\n * Clears the current selection\n */\n public clear(): void {\n this.selectedDate = null;\n this.selectedRange = { start: null, end: null };\n this.render();\n }\n}\n\n/**\n * Conditionally defines the custom element if in a browser environment.\n */\nconst defineDateSelector = (tagName: string = 'liwe3-date-selector'): void => {\n if (typeof window !== 'undefined' && !window.customElements.get(tagName)) {\n customElements.define(tagName, DateSelectorElement);\n }\n};\n\n// Auto-register with default tag name\ndefineDateSelector();\n\nexport { defineDateSelector };\n"],"names":["DateSelectorElement","name","value","year","month","currentYear","START_YEAR","END_YEAR","options","grid","day","firstDay","lastDay","firstDayOfWeek","daysInMonth","prevMonth","prevYear","daysInPrevMonth","i","today","isCurrentMonth","dateStr","isToday","classes","remainingCells","nextMonth","nextYear","dateStr1","dateStr2","date","start","end","target","direction","newMonth","dayElement","startDate","hoverDate","dayCells","hoverDateObj","cell","cellElement","cellDate","endDate","defineDateSelector","tagName"],"mappings":"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"}