ngxsmk-datepicker 1.1.7 → 1.1.8

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, HostListener, Output, Input, Component, inject, PLATFORM_ID, HostBinding } from '@angular/core';
2
+ import { inject, ElementRef, EventEmitter, HostListener, Output, Input, Component, PLATFORM_ID, HostBinding } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, isPlatformBrowser } from '@angular/common';
5
5
  import { FormsModule } from '@angular/forms';
@@ -7,36 +7,54 @@ import { FormsModule } from '@angular/forms';
7
7
  // #####################################################################
8
8
  // ## Reusable Custom Select Component
9
9
  // #####################################################################
10
+ /**
11
+ * @title Custom Select Component
12
+ * @description A standalone component implementing a custom styled dropdown selector.
13
+ * It handles options display, value tracking, and document click-away logic for closing.
14
+ *
15
+ * @selector app-custom-select
16
+ * @export
17
+ */
10
18
  class CustomSelectComponent {
11
- constructor(elementRef) {
12
- this.elementRef = elementRef;
19
+ constructor() {
20
+ /** The ElementRef injected via `inject()` for DOM manipulation and click detection. */
21
+ this.elementRef = inject(ElementRef);
13
22
  /** The list of available options to display in the dropdown. */
14
23
  this.options = [];
15
24
  /** Emits the new value when an option is selected. */
16
25
  this.valueChange = new EventEmitter();
17
26
  this.isOpen = false;
18
27
  }
19
- /** Closes the dropdown when a click occurs outside the component boundary. */
28
+ /**
29
+ * Closes the dropdown when a click event occurs outside the component's native element.
30
+ * @param event The mouse event triggered on the document.
31
+ */
20
32
  onDocumentClick(event) {
21
33
  if (!this.elementRef.nativeElement.contains(event.target))
22
34
  this.isOpen = false;
23
35
  }
24
- /** Gets the display label for the currently selected value. */
36
+ /**
37
+ * Retrieves the display label corresponding to the currently selected value.
38
+ * @returns The label string or an empty string if no option is selected.
39
+ */
25
40
  get displayValue() {
26
41
  const selectedOption = this.options.find((opt) => opt.value === this.value);
27
42
  return selectedOption ? selectedOption.label : '';
28
43
  }
29
- /** Toggles the visibility of the dropdown panel. */
44
+ /** Toggles the visibility state of the options dropdown panel. */
30
45
  toggleDropdown() {
31
46
  this.isOpen = !this.isOpen;
32
47
  }
33
- /** Handles the selection of a new option. */
48
+ /**
49
+ * Handles the selection of a new option, updating the value and closing the dropdown.
50
+ * @param option The selected option object containing label and value.
51
+ */
34
52
  selectOption(option) {
35
53
  this.value = option.value;
36
54
  this.valueChange.emit(this.value);
37
55
  this.isOpen = false;
38
56
  }
39
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CustomSelectComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
57
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CustomSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
40
58
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: CustomSelectComponent, isStandalone: true, selector: "app-custom-select", inputs: { options: "options", value: "value" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, ngImport: i0, template: `
41
59
  <div class="ngxsmk-select-container" (click)="toggleDropdown()">
42
60
  <button type="button" class="ngxsmk-select-display">
@@ -84,7 +102,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
84
102
  }
85
103
  </div>
86
104
  `, styles: [":host{position:relative;display:inline-block}.ngxsmk-select-container{cursor:pointer}.ngxsmk-select-display{display:flex;align-items:center;justify-content:space-between;width:var(--custom-select-width, 115px);background:var(--datepicker-background, #fff);border:1px solid var(--datepicker-border-color, #ccc);color:var(--datepicker-text-color, #333);border-radius:4px;padding:4px 8px;font-size:14px;text-align:left;height:30px}.ngxsmk-arrow-icon{width:12px;height:12px;margin-left:8px}.ngxsmk-options-panel{position:absolute;top:110%;left:0;width:100%;background:var(--datepicker-background, #fff);border:1px solid var(--datepicker-border-color, #ccc);color:var(--datepicker-text-color, #333);border-radius:4px;box-shadow:0 4px 8px #0000001a;max-height:200px;overflow-y:auto;z-index:9999}.ngxsmk-options-panel ul{list-style:none;padding:4px;margin:0}.ngxsmk-options-panel li{padding:8px 12px;border-radius:4px;cursor:pointer}.ngxsmk-options-panel li:hover{background-color:var(--datepicker-hover-background, #f0f0f0)}.ngxsmk-options-panel li.selected{background-color:var(--datepicker-primary-color, #3880ff);color:var(--datepicker-primary-contrast, #fff)}\n"] }]
87
- }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { options: [{
105
+ }], ctorParameters: () => [], propDecorators: { options: [{
88
106
  type: Input
89
107
  }], value: [{
90
108
  type: Input
@@ -94,6 +112,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
94
112
  type: HostListener,
95
113
  args: ['document:click', ['$event']]
96
114
  }] } });
115
+ /**
116
+ * @title Ngxsmk Datepicker Component
117
+ * @description A fully featured, standalone datepicker component supporting single date selection,
118
+ * date range selection, time selection, custom date ranges, and theme toggling.
119
+ *
120
+ * @selector ngxsmk-datepicker
121
+ * @implements OnInit, OnChanges
122
+ * @export
123
+ */
97
124
  class NgxsmkDatepickerComponent {
98
125
  /** Sets the locale for language and regional formatting (e.g., 'en-US', 'de-DE'). */
99
126
  set locale(value) {
@@ -102,6 +129,7 @@ class NgxsmkDatepickerComponent {
102
129
  get locale() {
103
130
  return this._locale;
104
131
  }
132
+ /** Binds the dark-theme class to the host element when theme is 'dark'. */
105
133
  get isDarkMode() {
106
134
  return this.theme === 'dark';
107
135
  }
@@ -129,9 +157,8 @@ class NgxsmkDatepickerComponent {
129
157
  }
130
158
  this.updateRangesArray();
131
159
  }
132
- // ⭐️ FIX: Constructor is now empty (or contains only non-injection code)
133
160
  constructor() {
134
- // ⭐️ FIX: Inject PLATFORM_ID as a field initializer. This is a valid injection context.
161
+ /** Platform ID injected via `inject()` for Server-Side Rendering (SSR) checks. */
135
162
  this.platformId = inject(PLATFORM_ID);
136
163
  /** Sets the selection mode: 'single' date or 'range' selection. */
137
164
  this.mode = 'single';
@@ -177,9 +204,11 @@ class NgxsmkDatepickerComponent {
177
204
  { label: 'PM', value: true }
178
205
  ];
179
206
  }
207
+ /** Retrieves the currently displayed calendar month index. */
180
208
  get currentMonth() {
181
209
  return this._currentMonth;
182
210
  }
211
+ /** Sets the month index and regenerates the calendar grid. */
183
212
  set currentMonth(month) {
184
213
  if (this._currentMonth !== month) {
185
214
  this._currentMonth = month;
@@ -187,9 +216,11 @@ class NgxsmkDatepickerComponent {
187
216
  this.generateCalendar();
188
217
  }
189
218
  }
219
+ /** Retrieves the currently displayed calendar year. */
190
220
  get currentYear() {
191
221
  return this._currentYear;
192
222
  }
223
+ /** Sets the year and regenerates the calendar grid. */
193
224
  set currentYear(year) {
194
225
  if (this._currentYear !== year) {
195
226
  this._currentYear = year;
@@ -197,8 +228,8 @@ class NgxsmkDatepickerComponent {
197
228
  this.generateCalendar();
198
229
  }
199
230
  }
231
+ /** Initializes the component, performs platform checks, and sets up date/time states. */
200
232
  ngOnInit() {
201
- // ⭐️ FIX: PLATFORM_ID check moved to ngOnInit where it's safe to use the injected value.
202
233
  if (isPlatformBrowser(this.platformId)) {
203
234
  this._locale = navigator.language;
204
235
  }
@@ -221,15 +252,14 @@ class NgxsmkDatepickerComponent {
221
252
  }
222
253
  this.generateCalendar();
223
254
  }
255
+ /** Handles input changes, particularly for `locale`, `minuteInterval`, and `value`. */
224
256
  ngOnChanges(changes) {
225
257
  if (changes['locale']) {
226
258
  this.generateLocaleData();
227
259
  this.generateCalendar();
228
260
  }
229
- // Regenerate time options if the interval changes
230
261
  if (changes['minuteInterval']) {
231
262
  this.generateTimeOptions();
232
- // Recalculate and round current minute to the new interval
233
263
  this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;
234
264
  this.onTimeChange();
235
265
  }
@@ -238,28 +268,42 @@ class NgxsmkDatepickerComponent {
238
268
  this.generateCalendar();
239
269
  }
240
270
  }
241
- /** Converts the displayed 12h time (currentDisplayHour + isPm) into the 24h internal time (currentHour). */
271
+ /**
272
+ * Converts the displayed 12-hour time (displayHour + isPm) into the 24-hour internal time.
273
+ * @param displayHour The 12-hour display hour (1-12).
274
+ * @param isPm Whether the time is PM (true) or AM (false).
275
+ * @returns The 24-hour time (0-23).
276
+ */
242
277
  get24Hour(displayHour, isPm) {
243
278
  if (isPm) {
244
- return displayHour === 12 ? 12 : displayHour + 12; // 12 PM is 12, 1-11 PM is 13-23
279
+ return displayHour === 12 ? 12 : displayHour + 12;
245
280
  }
246
281
  else {
247
- return displayHour === 12 ? 0 : displayHour; // 12 AM is 0 (midnight), 1-11 AM is 1-11
282
+ return displayHour === 12 ? 0 : displayHour;
248
283
  }
249
284
  }
250
- /** Updates the display time variables (12h format and AM/PM state) from the 24h internal time. */
285
+ /**
286
+ * Updates the display time variables (12h format and AM/PM state) from the 24h internal time.
287
+ * @param fullHour The 24-hour time (0-23).
288
+ */
251
289
  update12HourState(fullHour) {
252
290
  this.isPm = fullHour >= 12;
253
- this.currentDisplayHour = fullHour % 12 || 12; // 0 (midnight) or 12 PM both become 12
291
+ this.currentDisplayHour = fullHour % 12 || 12;
254
292
  }
255
- /** Applies the currently selected hour and minute to a given date object. */
293
+ /**
294
+ * Applies the currently selected hour and minute to a given date object.
295
+ * @param date The date object to modify.
296
+ * @returns The modified date object.
297
+ */
256
298
  applyCurrentTime(date) {
257
- // Convert 12h display state back to 24h format
258
299
  this.currentHour = this.get24Hour(this.currentDisplayHour, this.isPm);
259
300
  date.setHours(this.currentHour, this.currentMinute, 0, 0);
260
301
  return date;
261
302
  }
262
- /** Initializes selection state and time controls from the provided input value. */
303
+ /**
304
+ * Initializes selection state and time controls from the provided input value.
305
+ * @param value The input date or date range.
306
+ */
263
307
  initializeValue(value) {
264
308
  if (!value) {
265
309
  this.selectedDate = null;
@@ -279,15 +323,17 @@ class NgxsmkDatepickerComponent {
279
323
  }
280
324
  if (initialDate) {
281
325
  this.currentDate = new Date(initialDate);
282
- // Set time selectors based on 24h value from initial date
283
326
  this.currentHour = initialDate.getHours();
284
327
  this.currentMinute = initialDate.getMinutes();
285
328
  this.update12HourState(this.currentHour);
286
- // Round minute to nearest interval, in case the initial value time doesn't match the current interval
287
329
  this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;
288
330
  }
289
331
  }
290
- /** Normalizes a date input to a Date object, keeping time information. */
332
+ /**
333
+ * Normalizes a date input to a Date object, handling various types.
334
+ * @param date The input date type.
335
+ * @returns A valid Date object or null.
336
+ */
291
337
  _normalizeDate(date) {
292
338
  if (!date)
293
339
  return null;
@@ -298,10 +344,9 @@ class NgxsmkDatepickerComponent {
298
344
  }
299
345
  /** Generates options for the hour and minute selectors based on the interval. */
300
346
  generateTimeOptions() {
301
- // Hours are 1 through 12 for 12h format display
302
347
  this.hourOptions = Array.from({ length: 12 }).map((_, i) => ({
303
348
  label: (i + 1).toString().padStart(2, '0'),
304
- value: i + 1, // Values 1 through 12
349
+ value: i + 1,
305
350
  }));
306
351
  this.minuteOptions = [];
307
352
  for (let i = 0; i < 60; i += this.minuteInterval) {
@@ -311,7 +356,7 @@ class NgxsmkDatepickerComponent {
311
356
  });
312
357
  }
313
358
  }
314
- /** Generates locale-dependent month and weekday names. */
359
+ /** Generates locale-dependent month and weekday names for display. */
315
360
  generateLocaleData() {
316
361
  this.monthOptions = Array.from({ length: 12 }).map((_, i) => ({
317
362
  label: new Date(2024, i, 1).toLocaleDateString(this.locale, { month: 'long' }),
@@ -330,27 +375,32 @@ class NgxsmkDatepickerComponent {
330
375
  return weekDay;
331
376
  });
332
377
  }
333
- /** Populates the internal array of predefined ranges. */
378
+ /** Populates the internal array of predefined ranges from the input object. */
334
379
  updateRangesArray() {
335
380
  this.rangesArray = this._ranges ? Object.entries(this._ranges).map(([key, value]) => ({ key, value })) : [];
336
381
  }
337
- /** Handles selection of a predefined date range. */
382
+ /**
383
+ * Handles selection of a predefined date range, updates the view, and emits the new range.
384
+ * @param range The selected date range [start, end].
385
+ */
338
386
  selectRange(range) {
339
387
  this.startDate = this.applyCurrentTime(range[0]);
340
388
  this.endDate = this.applyCurrentTime(range[1]);
341
389
  if (this.startDate && this.endDate) {
342
- /** Type assertion is safe here as both dates are explicitly set */
343
390
  this.valueChange.emit({ start: this.startDate, end: this.endDate });
344
391
  }
345
392
  this.currentDate = new Date(this.startDate);
346
- this.initializeValue({ start: this.startDate, end: this.endDate }); // Update time selectors
393
+ this.initializeValue({ start: this.startDate, end: this.endDate });
347
394
  this.generateCalendar();
348
395
  }
349
- /** Checks if a specific date should be disabled based on minDate, maxDate, or custom function. */
396
+ /**
397
+ * Checks if a specific date should be disabled based on minDate, maxDate, or custom function.
398
+ * @param date The date to check.
399
+ * @returns True if the date is disabled, false otherwise.
400
+ */
350
401
  isDateDisabled(date) {
351
402
  if (!date)
352
403
  return false;
353
- // Check against minDate/maxDate, ensuring we compare only the date part
354
404
  const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());
355
405
  if (this._minDate) {
356
406
  const minDateOnly = new Date(this._minDate.getFullYear(), this._minDate.getMonth(), this._minDate.getDate());
@@ -366,7 +416,7 @@ class NgxsmkDatepickerComponent {
366
416
  return true;
367
417
  return false;
368
418
  }
369
- /** Updates the time component of the selected date(s) when hour/minute selectors change. */
419
+ /** Updates the time component of the selected date(s) when hour/minute selectors change and emits the new value. */
370
420
  onTimeChange() {
371
421
  if (this.mode === 'single' && this.selectedDate) {
372
422
  this.selectedDate = this.applyCurrentTime(this.selectedDate);
@@ -375,15 +425,16 @@ class NgxsmkDatepickerComponent {
375
425
  else if (this.mode === 'range' && this.startDate && this.endDate) {
376
426
  this.startDate = this.applyCurrentTime(this.startDate);
377
427
  this.endDate = this.applyCurrentTime(this.endDate);
378
- /** Type assertion is safe here as both dates are confirmed */
379
428
  this.valueChange.emit({ start: this.startDate, end: this.endDate });
380
429
  }
381
430
  else if (this.mode === 'range' && this.startDate && !this.endDate) {
382
- // If range started but not completed, update time on the start date only (no emit)
383
431
  this.startDate = this.applyCurrentTime(this.startDate);
384
432
  }
385
433
  }
386
- /** Handles the click event on a calendar day cell. */
434
+ /**
435
+ * Handles the click event on a calendar day cell to manage single or range selection.
436
+ * @param day The date clicked.
437
+ */
387
438
  onDateClick(day) {
388
439
  if (!day || this.isDateDisabled(day))
389
440
  return;
@@ -392,14 +443,12 @@ class NgxsmkDatepickerComponent {
392
443
  this.valueChange.emit(this.selectedDate);
393
444
  }
394
445
  else {
395
- // Range selection logic
396
446
  if (!this.startDate || (this.startDate && this.endDate)) {
397
447
  this.startDate = this.applyCurrentTime(day);
398
448
  this.endDate = null;
399
449
  }
400
450
  else if (day >= this.startDate) {
401
451
  this.endDate = this.applyCurrentTime(day);
402
- /** Type assertion is safe here as both dates are set when ending a range */
403
452
  this.valueChange.emit({ start: this.startDate, end: this.endDate });
404
453
  }
405
454
  else {
@@ -409,22 +458,26 @@ class NgxsmkDatepickerComponent {
409
458
  this.hoveredDate = null;
410
459
  }
411
460
  // Update time controls to reflect the time of the newly selected date
412
- if (this.mode === 'single' && this.selectedDate) {
413
- this.update12HourState(this.selectedDate.getHours());
414
- this.currentMinute = this.selectedDate.getMinutes();
415
- }
416
- else if (this.mode === 'range' && this.startDate) {
417
- this.update12HourState(this.startDate.getHours());
418
- this.currentMinute = this.startDate.getMinutes();
461
+ const selectedTimeRef = this.mode === 'single' ? this.selectedDate : this.startDate;
462
+ if (selectedTimeRef) {
463
+ this.update12HourState(selectedTimeRef.getHours());
464
+ this.currentMinute = selectedTimeRef.getMinutes();
419
465
  }
420
466
  }
421
- /** Handles hover events for range preview when only the start date is selected. */
467
+ /**
468
+ * Updates the hovered date for range preview during selection.
469
+ * @param day The date being hovered over.
470
+ */
422
471
  onDateHover(day) {
423
472
  if (this.mode === 'range' && this.startDate && !this.endDate && day) {
424
473
  this.hoveredDate = day;
425
474
  }
426
475
  }
427
- /** Checks if a date is within the range being previewed (during hover). */
476
+ /**
477
+ * Checks if a date is within the range being previewed (during hover).
478
+ * @param day The date to check.
479
+ * @returns True if the date is in the preview range.
480
+ */
428
481
  isPreviewInRange(day) {
429
482
  if (this.mode !== 'range' || !this.startDate || this.endDate || !this.hoveredDate || !day)
430
483
  return false;
@@ -433,7 +486,7 @@ class NgxsmkDatepickerComponent {
433
486
  const time = day.getTime();
434
487
  return time > Math.min(start, end) && time < Math.max(start, end);
435
488
  }
436
- /** Generates the calendar grid for the currently active month. */
489
+ /** Generates the calendar grid (days and empty cells) for the currently active month. */
437
490
  generateCalendar() {
438
491
  this.daysInMonth = [];
439
492
  const year = this.currentDate.getFullYear();
@@ -452,7 +505,7 @@ class NgxsmkDatepickerComponent {
452
505
  this.daysInMonth.push(this._normalizeDate(new Date(year, month, i)));
453
506
  }
454
507
  }
455
- /** Generates month and year options for dropdowns. */
508
+ /** Generates month and year options for the dropdown selectors. */
456
509
  generateDropdownOptions() {
457
510
  const startYear = this._currentYear - 10;
458
511
  const endYear = this._currentYear + 10;
@@ -461,12 +514,20 @@ class NgxsmkDatepickerComponent {
461
514
  this.yearOptions.push({ label: `${i}`, value: i });
462
515
  }
463
516
  }
464
- /** Moves the calendar view forward or backward by one month. */
517
+ /**
518
+ * Moves the calendar view forward or backward by one month.
519
+ * @param delta -1 for previous month, 1 for next month.
520
+ */
465
521
  changeMonth(delta) {
466
522
  this.currentDate.setMonth(this.currentDate.getMonth() + delta);
467
523
  this.generateCalendar();
468
524
  }
469
- /** Utility function to check if two dates represent the same day (ignoring time). */
525
+ /**
526
+ * Utility function to check if two dates represent the same day (ignoring time).
527
+ * @param d1 The first date.
528
+ * @param d2 The second date.
529
+ * @returns True if they are the same day.
530
+ */
470
531
  isSameDay(d1, d2) {
471
532
  if (!d1 || !d2)
472
533
  return false;
@@ -474,11 +535,14 @@ class NgxsmkDatepickerComponent {
474
535
  d1.getMonth() === d2.getMonth() &&
475
536
  d1.getDate() === d2.getDate());
476
537
  }
477
- /** Checks if a date is strictly between the start and end of a selected range (ignoring time). */
538
+ /**
539
+ * Checks if a date is strictly between the start and end of a selected range (ignoring time).
540
+ * @param d The date to check.
541
+ * @returns True if the date is in the selected range.
542
+ */
478
543
  isInRange(d) {
479
544
  if (!d || !this.startDate || !this.endDate)
480
545
  return false;
481
- // Use date-only comparison for highlighting the days
482
546
  const dTime = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
483
547
  const startDayTime = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate()).getTime();
484
548
  const endDayTime = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate()).getTime();
@@ -1 +1 @@
1
- {"version":3,"file":"ngxsmk-datepicker.mjs","sources":["../../../projects/ngxsmk-datepicker/src/lib/ngxsmk-datepicker.ts","../../../projects/ngxsmk-datepicker/src/public-api.ts","../../../projects/ngxsmk-datepicker/src/ngxsmk-datepicker.ts"],"sourcesContent":["import {\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n HostBinding,\r\n HostListener,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n SimpleChanges,\r\n PLATFORM_ID,\r\n inject, // 👈 New: Import the inject function\r\n} from '@angular/core';\r\nimport {CommonModule, isPlatformBrowser} from '@angular/common';\r\nimport {FormsModule} from '@angular/forms';\r\n\r\n// #####################################################################\r\n// ## Reusable Custom Select Component\r\n// #####################################################################\r\n@Component({\r\n selector: 'app-custom-select',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"ngxsmk-select-container\" (click)=\"toggleDropdown()\">\r\n <button type=\"button\" class=\"ngxsmk-select-display\">\r\n <span>{{ displayValue }}</span>\r\n <svg class=\"ngxsmk-arrow-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"48\"\r\n d=\"M112 184l144 144 144-144\"/>\r\n </svg>\r\n </button>\r\n @if (isOpen) {\r\n <div class=\"ngxsmk-options-panel\">\r\n <ul>\r\n @for (option of options; track option.value) {\r\n <li [class.selected]=\"option.value === value\" (click)=\"selectOption(option); $event.stopPropagation()\">\r\n {{ option.label }}\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n position: relative;\r\n display: inline-block;\r\n }\r\n\r\n .ngxsmk-select-container {\r\n cursor: pointer;\r\n }\r\n\r\n .ngxsmk-select-display {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: var(--custom-select-width, 115px);\r\n background: var(--datepicker-background, #fff);\r\n border: 1px solid var(--datepicker-border-color, #ccc);\r\n color: var(--datepicker-text-color, #333);\r\n border-radius: 4px;\r\n padding: 4px 8px;\r\n font-size: 14px;\r\n text-align: left;\r\n height: 30px;\r\n }\r\n\r\n .ngxsmk-arrow-icon {\r\n width: 12px;\r\n height: 12px;\r\n margin-left: 8px;\r\n }\r\n\r\n .ngxsmk-options-panel {\r\n position: absolute;\r\n top: 110%; /* Relative to the host element's height */\r\n left: 0;\r\n width: 100%;\r\n background: var(--datepicker-background, #fff);\r\n border: 1px solid var(--datepicker-border-color, #ccc);\r\n color: var(--datepicker-text-color, #333);\r\n border-radius: 4px;\r\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\r\n max-height: 200px;\r\n overflow-y: auto;\r\n z-index: 9999; /* Highest Z-index for visibility */\r\n }\r\n\r\n .ngxsmk-options-panel ul {\r\n list-style: none;\r\n padding: 4px;\r\n margin: 0;\r\n }\r\n\r\n .ngxsmk-options-panel li {\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n }\r\n\r\n .ngxsmk-options-panel li:hover {\r\n background-color: var(--datepicker-hover-background, #f0f0f0);\r\n }\r\n\r\n .ngxsmk-options-panel li.selected {\r\n background-color: var(--datepicker-primary-color, #3880ff);\r\n color: var(--datepicker-primary-contrast, #fff);\r\n }\r\n `],\r\n})\r\nexport class CustomSelectComponent {\r\n /** The list of available options to display in the dropdown. */\r\n @Input() options: { label: string; value: any }[] = [];\r\n /** The currently selected value. */\r\n @Input() value: any;\r\n /** Emits the new value when an option is selected. */\r\n @Output() valueChange = new EventEmitter<any>();\r\n public isOpen = false;\r\n\r\n constructor(private readonly elementRef: ElementRef) {\r\n }\r\n\r\n /** Closes the dropdown when a click occurs outside the component boundary. */\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: MouseEvent): void {\r\n if (!this.elementRef.nativeElement.contains(event.target)) this.isOpen = false;\r\n }\r\n\r\n /** Gets the display label for the currently selected value. */\r\n get displayValue(): string {\r\n const selectedOption = this.options.find((opt) => opt.value === this.value);\r\n return selectedOption ? selectedOption.label : '';\r\n }\r\n\r\n /** Toggles the visibility of the dropdown panel. */\r\n toggleDropdown(): void {\r\n this.isOpen = !this.isOpen;\r\n }\r\n\r\n /** Handles the selection of a new option. */\r\n selectOption(option: { label: string; value: any }): void {\r\n this.value = option.value;\r\n this.valueChange.emit(this.value);\r\n this.isOpen = false;\r\n }\r\n}\r\n\r\n// #####################################################################\r\n// ## Datepicker Component\r\n// #####################################################################\r\nexport type DateInput = Date | string | { toDate: () => Date; _isAMomentObject?: boolean; $d?: Date };\r\n\r\nexport interface DateRange {\r\n [key: string]: [DateInput, DateInput];\r\n}\r\n\r\n@Component({\r\n selector: 'ngxsmk-datepicker',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule, CustomSelectComponent],\r\n template: `\r\n <div class=\"ngxsmk-datepicker-container\">\r\n @if (showRanges && rangesArray.length > 0 && mode === 'range') {\r\n <div class=\"ngxsmk-ranges-container\">\r\n <ul>\r\n @for (range of rangesArray; track range.key) {\r\n <li (click)=\"selectRange(range.value)\">{{ range.key }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n <div class=\"ngxsmk-calendar-container\">\r\n <div class=\"ngxsmk-header\">\r\n <div class=\"ngxsmk-month-year-selects\">\r\n <app-custom-select class=\"month-select\" [options]=\"monthOptions\"\r\n [(value)]=\"currentMonth\"></app-custom-select>\r\n <app-custom-select class=\"year-select\" [options]=\"yearOptions\" [(value)]=\"currentYear\"></app-custom-select>\r\n </div>\r\n <div class=\"ngxsmk-nav-buttons\">\r\n <button type=\"button\" class=\"ngxsmk-nav-button\" (click)=\"changeMonth(-1)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"48\"\r\n d=\"M328 112L184 256l144 144\"/>\r\n </svg>\r\n </button>\r\n <button type=\"button\" class=\"ngxsmk-nav-button\" (click)=\"changeMonth(1)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"48\"\r\n d=\"M184 112l144 144-144 144\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"ngxsmk-days-grid-wrapper\">\r\n <div class=\"ngxsmk-days-grid\">\r\n @for (day of weekDays; track day) {\r\n <div class=\"ngxsmk-day-name\">{{ day }}</div>\r\n }\r\n @for (day of daysInMonth; track $index) {\r\n <div class=\"ngxsmk-day-cell\"\r\n [class.empty]=\"!day\" [class.disabled]=\"isDateDisabled(day)\" [class.today]=\"isSameDay(day, today)\"\r\n [class.selected]=\"mode === 'single' && isSameDay(day, selectedDate)\"\r\n [class.start-date]=\"mode === 'range' && isSameDay(day, startDate)\"\r\n [class.end-date]=\"mode === 'range' && isSameDay(day, endDate)\"\r\n [class.in-range]=\"mode === 'range' && isInRange(day)\"\r\n [class.preview-range]=\"isPreviewInRange(day)\"\r\n (click)=\"onDateClick(day)\" (mouseenter)=\"onDateHover(day)\">\r\n @if (day) {\r\n <div class=\"ngxsmk-day-number\">{{ day | date : 'd' }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (showTime) {\r\n <div class=\"ngxsmk-time-selection\">\r\n <span class=\"ngxsmk-time-label\">Time:</span>\r\n <app-custom-select\r\n class=\"hour-select\"\r\n [options]=\"hourOptions\"\r\n [(value)]=\"currentDisplayHour\"\r\n (valueChange)=\"onTimeChange()\"\r\n ></app-custom-select>\r\n <span class=\"ngxsmk-time-separator\">:</span>\r\n <app-custom-select\r\n class=\"minute-select\"\r\n [options]=\"minuteOptions\"\r\n [(value)]=\"currentMinute\"\r\n (valueChange)=\"onTimeChange()\"\r\n ></app-custom-select>\r\n <app-custom-select\r\n class=\"ampm-select\"\r\n [options]=\"ampmOptions\"\r\n [(value)]=\"isPm\"\r\n (valueChange)=\"onTimeChange()\"\r\n ></app-custom-select>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --datepicker-primary-color: #6d28d9;\r\n --datepicker-primary-contrast: #ffffff;\r\n --datepicker-range-background: #f5f3ff;\r\n --datepicker-background: #ffffff;\r\n --datepicker-text-color: #222428;\r\n --datepicker-subtle-text-color: #9ca3af;\r\n --datepicker-border-color: #e9e9e9;\r\n --datepicker-hover-background: #f0f0f0;\r\n }\r\n\r\n :host(.dark-theme) {\r\n --datepicker-range-background: rgba(139, 92, 246, 0.2);\r\n --datepicker-background: #1f2937;\r\n --datepicker-text-color: #d1d5db;\r\n --datepicker-subtle-text-color: #6b7280;\r\n --datepicker-border-color: #4b5563;\r\n --datepicker-hover-background: #374151;\r\n }\r\n\r\n .ngxsmk-datepicker-container {\r\n display: flex;\r\n }\r\n\r\n .ngxsmk-calendar-container {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n border-radius: 10px;\r\n padding: 16px;\r\n background: var(--datepicker-background);\r\n }\r\n\r\n .ngxsmk-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n margin-bottom: 12px;\r\n position: relative;\r\n z-index: 2;\r\n gap: 5px;\r\n }\r\n\r\n .ngxsmk-month-year-selects {\r\n display: flex;\r\n gap: 5px;\r\n }\r\n\r\n .ngxsmk-month-year-selects app-custom-select.month-select {\r\n --custom-select-width: 120px;\r\n }\r\n\r\n .ngxsmk-month-year-selects app-custom-select.year-select {\r\n --custom-select-width: 90px;\r\n }\r\n\r\n .ngxsmk-nav-buttons {\r\n display: flex;\r\n }\r\n\r\n .ngxsmk-nav-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n cursor: pointer;\r\n border-radius: 50%;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: var(--datepicker-text-color);\r\n }\r\n\r\n .ngxsmk-nav-button:hover {\r\n background-color: var(--datepicker-hover-background);\r\n }\r\n\r\n .ngxsmk-nav-button svg {\r\n width: 18px;\r\n height: 18px;\r\n }\r\n\r\n .ngxsmk-days-grid-wrapper {\r\n position: relative;\r\n }\r\n\r\n .ngxsmk-days-grid {\r\n display: grid;\r\n grid-template-columns: repeat(7, 1fr);\r\n text-align: center;\r\n gap: 0;\r\n }\r\n\r\n .ngxsmk-day-name {\r\n font-weight: 600;\r\n font-size: 0.8rem;\r\n color: var(--datepicker-subtle-text-color);\r\n padding: 8px 0;\r\n }\r\n\r\n .ngxsmk-day-cell {\r\n position: relative;\r\n height: 38px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n cursor: pointer;\r\n border-radius: 0;\r\n }\r\n\r\n .ngxsmk-day-number {\r\n width: 36px;\r\n height: 36px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n border-radius: 50%;\r\n color: var(--datepicker-text-color);\r\n position: relative;\r\n z-index: 1;\r\n }\r\n\r\n .ngxsmk-day-cell:not(.disabled):hover .ngxsmk-day-number {\r\n background-color: var(--datepicker-hover-background);\r\n color: var(--datepicker-primary-color);\r\n }\r\n\r\n /* --- Range Highlight --- */\r\n .ngxsmk-day-cell.in-range,\r\n .ngxsmk-day-cell.start-date,\r\n .ngxsmk-day-cell.end-date,\r\n .ngxsmk-day-cell.preview-range {\r\n background-color: var(--datepicker-range-background);\r\n }\r\n\r\n /* Apply radius to the edge cells */\r\n .ngxsmk-day-cell.start-date {\r\n border-top-left-radius: 100%;\r\n border-bottom-left-radius: 100%;\r\n }\r\n\r\n .ngxsmk-day-cell.end-date {\r\n border-top-right-radius: 100%;\r\n border-bottom-right-radius: 100%;\r\n }\r\n\r\n .ngxsmk-day-cell.start-date.end-date {\r\n border-radius: 50px;\r\n }\r\n /* --- End Range Highlight --- */\r\n\r\n .ngxsmk-day-cell.disabled {\r\n background-color: transparent !important;\r\n color: #4b5563;\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n opacity: 0.5;\r\n }\r\n\r\n .ngxsmk-day-cell.today .ngxsmk-day-number {\r\n border: 1px solid var(--datepicker-primary-color);\r\n }\r\n\r\n .ngxsmk-ranges-container {\r\n width: 180px;\r\n padding: 16px;\r\n border-right: 1px solid var(--datepicker-border-color);\r\n background: var(--datepicker-background);\r\n }\r\n\r\n .ngxsmk-ranges-container ul {\r\n list-style: none;\r\n padding: 0;\r\n margin: 0;\r\n }\r\n\r\n .ngxsmk-ranges-container li {\r\n padding: 10px;\r\n margin-bottom: 8px;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n color: var(--datepicker-text-color);\r\n }\r\n\r\n .ngxsmk-ranges-container li:hover {\r\n background-color: var(--datepicker-hover-background);\r\n }\r\n\r\n .ngxsmk-time-selection {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n margin-top: 16px;\r\n padding-top: 12px;\r\n border-top: 1px solid var(--datepicker-border-color);\r\n }\r\n\r\n .ngxsmk-time-label {\r\n font-size: 0.9rem;\r\n color: var(--datepicker-subtle-text-color);\r\n margin-right: 4px;\r\n }\r\n\r\n .ngxsmk-time-selection app-custom-select {\r\n --custom-select-width: 60px;\r\n height: 30px;\r\n }\r\n\r\n .ngxsmk-time-selection app-custom-select.ampm-select {\r\n --custom-select-width: 70px;\r\n }\r\n\r\n .ngxsmk-time-separator {\r\n font-weight: 600;\r\n font-size: 1.1rem;\r\n color: var(--datepicker-text-color);\r\n }\r\n `],\r\n})\r\nexport class NgxsmkDatepickerComponent implements OnInit, OnChanges {\r\n\r\n // ⭐️ FIX: Inject PLATFORM_ID as a field initializer. This is a valid injection context.\r\n private readonly platformId = inject(PLATFORM_ID);\r\n\r\n /** Sets the selection mode: 'single' date or 'range' selection. */\r\n @Input() mode: 'single' | 'range' = 'single';\r\n /** A function to programmatically disable specific dates. Returns true if the date should be disabled. */\r\n @Input() isInvalidDate: (date: Date) => boolean = () => false;\r\n /** If true, displays the predefined ranges panel when in 'range' mode. */\r\n @Input() showRanges: boolean = true;\r\n /** If true, displays the time selection controls (hour/minute). */\r\n @Input() showTime: boolean = false;\r\n /** Sets the minute selection step/interval (e.g., 5, 15, 30). */\r\n @Input() minuteInterval: number = 1;\r\n\r\n /** The initial selected date or date range. Accepts Date, or { start: Date, end: Date }. */\r\n @Input() value: Date | { start: Date, end: Date } | null = null;\r\n\r\n private _locale: string = 'en-US';\r\n\r\n /** Sets the locale for language and regional formatting (e.g., 'en-US', 'de-DE'). */\r\n @Input() set locale(value: string) {\r\n this._locale = value;\r\n }\r\n\r\n get locale(): string {\r\n return this._locale;\r\n }\r\n\r\n /** Controls the visual theme: 'light' or 'dark'. */\r\n @Input() theme: 'light' | 'dark' = 'light';\r\n\r\n @HostBinding('class.dark-theme') get isDarkMode() {\r\n return this.theme === 'dark';\r\n }\r\n\r\n /** Emits the newly selected date or date range. */\r\n @Output() valueChange = new EventEmitter<Date | { start: Date; end: Date }>();\r\n\r\n private _minDate: Date | null = null;\r\n\r\n /** The earliest selectable date. */\r\n @Input() set minDate(value: DateInput | null) {\r\n this._minDate = this._normalizeDate(value);\r\n }\r\n\r\n private _maxDate: Date | null = null;\r\n\r\n /** The latest selectable date. */\r\n @Input() set maxDate(value: DateInput | null) {\r\n this._maxDate = this._normalizeDate(value);\r\n }\r\n\r\n private _ranges: { [key: string]: [Date, Date] } | null = null;\r\n\r\n /** An object of predefined date ranges for quick selection. */\r\n @Input() set ranges(value: DateRange | null) {\r\n if (!value) {\r\n this._ranges = null;\r\n } else {\r\n this._ranges = Object.entries(value).reduce((acc, [key, dates]) => {\r\n const start = this._normalizeDate(dates[0]);\r\n const end = this._normalizeDate(dates[1]);\r\n if (start && end) acc[key] = [start, end];\r\n return acc;\r\n }, {} as { [key: string]: [Date, Date] });\r\n }\r\n this.updateRangesArray();\r\n }\r\n\r\n public currentDate: Date = new Date();\r\n public daysInMonth: (Date | null)[] = [];\r\n public weekDays: string[] = [];\r\n public readonly today: Date = new Date();\r\n public selectedDate: Date | null = null;\r\n public startDate: Date | null = null;\r\n public endDate: Date | null = null;\r\n public hoveredDate: Date | null = null;\r\n public rangesArray: { key: string; value: [Date, Date] }[] = [];\r\n private _currentMonth!: number;\r\n private _currentYear!: number;\r\n public monthOptions: { label: string; value: number }[] = [];\r\n public yearOptions: { label: string; value: number }[] = [];\r\n private firstDayOfWeek: number = 0;\r\n\r\n // Time selection state\r\n public currentHour: number = 0; // Internal 24h format (0-23)\r\n public currentMinute: number = 0;\r\n public currentDisplayHour: number = 12; // Display 12h format (1-12)\r\n public isPm: boolean = false; // Tracks AM/PM status\r\n\r\n public hourOptions: { label: string; value: number }[] = [];\r\n public minuteOptions: { label: string; value: number }[] = [];\r\n public ampmOptions: { label: string; value: boolean }[] = [\r\n { label: 'AM', value: false },\r\n { label: 'PM', value: true }\r\n ];\r\n\r\n // ⭐️ FIX: Constructor is now empty (or contains only non-injection code)\r\n constructor() {}\r\n\r\n get currentMonth(): number {\r\n return this._currentMonth;\r\n }\r\n\r\n set currentMonth(month: number) {\r\n if (this._currentMonth !== month) {\r\n this._currentMonth = month;\r\n this.currentDate.setMonth(month);\r\n this.generateCalendar();\r\n }\r\n }\r\n\r\n get currentYear(): number {\r\n return this._currentYear;\r\n }\r\n\r\n set currentYear(year: number) {\r\n if (this._currentYear !== year) {\r\n this._currentYear = year;\r\n this.currentDate.setFullYear(year);\r\n this.generateCalendar();\r\n }\r\n }\r\n\r\n ngOnInit(): void {\r\n // ⭐️ FIX: PLATFORM_ID check moved to ngOnInit where it's safe to use the injected value.\r\n if (isPlatformBrowser(this.platformId)) {\r\n this._locale = navigator.language;\r\n }\r\n\r\n this.today.setHours(0, 0, 0, 0);\r\n this.generateLocaleData();\r\n this.generateTimeOptions();\r\n\r\n // Set default time to current time if enabled and no initial value\r\n if (this.showTime && !this.value) {\r\n const now = new Date();\r\n\r\n this.currentHour = now.getHours();\r\n this.currentMinute = Math.floor(now.getMinutes() / this.minuteInterval) * this.minuteInterval;\r\n\r\n if (this.currentMinute === 60) {\r\n this.currentMinute = 0;\r\n this.currentHour = (this.currentHour + 1) % 24;\r\n }\r\n\r\n this.update12HourState(this.currentHour);\r\n }\r\n\r\n if (this.value) {\r\n this.initializeValue(this.value);\r\n }\r\n this.generateCalendar();\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['locale']) {\r\n this.generateLocaleData();\r\n this.generateCalendar();\r\n }\r\n\r\n // Regenerate time options if the interval changes\r\n if (changes['minuteInterval']) {\r\n this.generateTimeOptions();\r\n // Recalculate and round current minute to the new interval\r\n this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;\r\n this.onTimeChange();\r\n }\r\n\r\n if (changes['value'] && changes['value'].currentValue !== changes['value'].previousValue) {\r\n this.initializeValue(changes['value'].currentValue);\r\n this.generateCalendar();\r\n }\r\n }\r\n\r\n /** Converts the displayed 12h time (currentDisplayHour + isPm) into the 24h internal time (currentHour). */\r\n private get24Hour(displayHour: number, isPm: boolean): number {\r\n if (isPm) {\r\n return displayHour === 12 ? 12 : displayHour + 12; // 12 PM is 12, 1-11 PM is 13-23\r\n } else {\r\n return displayHour === 12 ? 0 : displayHour; // 12 AM is 0 (midnight), 1-11 AM is 1-11\r\n }\r\n }\r\n\r\n /** Updates the display time variables (12h format and AM/PM state) from the 24h internal time. */\r\n private update12HourState(fullHour: number): void {\r\n this.isPm = fullHour >= 12;\r\n this.currentDisplayHour = fullHour % 12 || 12; // 0 (midnight) or 12 PM both become 12\r\n }\r\n\r\n /** Applies the currently selected hour and minute to a given date object. */\r\n private applyCurrentTime(date: Date): Date {\r\n // Convert 12h display state back to 24h format\r\n this.currentHour = this.get24Hour(this.currentDisplayHour, this.isPm);\r\n date.setHours(this.currentHour, this.currentMinute, 0, 0);\r\n return date;\r\n }\r\n\r\n /** Initializes selection state and time controls from the provided input value. */\r\n private initializeValue(value: Date | { start: Date, end: Date } | null): void {\r\n if (!value) {\r\n this.selectedDate = null;\r\n this.startDate = null;\r\n this.endDate = null;\r\n return;\r\n }\r\n\r\n let initialDate: Date | null = null;\r\n\r\n if (this.mode === 'single' && value instanceof Date) {\r\n this.selectedDate = this._normalizeDate(value);\r\n initialDate = this.selectedDate;\r\n\r\n } else if (this.mode === 'range' && typeof value === 'object' && 'start' in value && 'end' in value) {\r\n this.startDate = this._normalizeDate(value.start);\r\n this.endDate = this._normalizeDate(value.end);\r\n initialDate = this.startDate;\r\n }\r\n\r\n if (initialDate) {\r\n this.currentDate = new Date(initialDate);\r\n\r\n // Set time selectors based on 24h value from initial date\r\n this.currentHour = initialDate.getHours();\r\n this.currentMinute = initialDate.getMinutes();\r\n\r\n this.update12HourState(this.currentHour);\r\n\r\n // Round minute to nearest interval, in case the initial value time doesn't match the current interval\r\n this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;\r\n }\r\n }\r\n\r\n /** Normalizes a date input to a Date object, keeping time information. */\r\n private _normalizeDate(date: DateInput | null): Date | null {\r\n if (!date) return null;\r\n const d = (date instanceof Date) ? new Date(date.getTime()) : new Date(date as any);\r\n if (isNaN(d.getTime())) return null;\r\n return d;\r\n }\r\n\r\n /** Generates options for the hour and minute selectors based on the interval. */\r\n private generateTimeOptions(): void {\r\n // Hours are 1 through 12 for 12h format display\r\n this.hourOptions = Array.from({ length: 12 }).map((_, i) => ({\r\n label: (i + 1).toString().padStart(2, '0'),\r\n value: i + 1, // Values 1 through 12\r\n }));\r\n\r\n this.minuteOptions = [];\r\n for (let i = 0; i < 60; i += this.minuteInterval) {\r\n this.minuteOptions.push({\r\n label: i.toString().padStart(2, '0'),\r\n value: i,\r\n });\r\n }\r\n }\r\n\r\n /** Generates locale-dependent month and weekday names. */\r\n private generateLocaleData(): void {\r\n this.monthOptions = Array.from({length: 12}).map((_, i) => ({\r\n label: new Date(2024, i, 1).toLocaleDateString(this.locale, {month: 'long'}),\r\n value: i,\r\n }));\r\n try {\r\n this.firstDayOfWeek = ((new Intl.Locale(this.locale) as any).weekInfo?.firstDay || 0) % 7;\r\n } catch (e) {\r\n this.firstDayOfWeek = 0;\r\n }\r\n const day = new Date(2024, 0, 7 + this.firstDayOfWeek);\r\n this.weekDays = Array.from({length: 7}).map(() => {\r\n const weekDay = new Date(day).toLocaleDateString(this.locale, {weekday: 'short'});\r\n day.setDate(day.getDate() + 1);\r\n return weekDay;\r\n });\r\n }\r\n\r\n /** Populates the internal array of predefined ranges. */\r\n private updateRangesArray(): void {\r\n this.rangesArray = this._ranges ? Object.entries(this._ranges).map(([key, value]) => ({key, value})) : [];\r\n }\r\n\r\n /** Handles selection of a predefined date range. */\r\n public selectRange(range: [Date, Date]): void {\r\n this.startDate = this.applyCurrentTime(range[0]);\r\n this.endDate = this.applyCurrentTime(range[1]);\r\n\r\n if (this.startDate && this.endDate) {\r\n /** Type assertion is safe here as both dates are explicitly set */\r\n this.valueChange.emit({start: this.startDate as Date, end: this.endDate as Date});\r\n }\r\n\r\n this.currentDate = new Date(this.startDate);\r\n this.initializeValue({start: this.startDate, end: this.endDate}); // Update time selectors\r\n this.generateCalendar();\r\n }\r\n\r\n /** Checks if a specific date should be disabled based on minDate, maxDate, or custom function. */\r\n public isDateDisabled(date: Date | null): boolean {\r\n if (!date) return false;\r\n // Check against minDate/maxDate, ensuring we compare only the date part\r\n const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());\r\n\r\n if (this._minDate) {\r\n const minDateOnly = new Date(this._minDate.getFullYear(), this._minDate.getMonth(), this._minDate.getDate());\r\n if (dateOnly < minDateOnly) return true;\r\n }\r\n if (this._maxDate) {\r\n const maxDateOnly = new Date(this._maxDate.getFullYear(), this._maxDate.getMonth(), this._maxDate.getDate());\r\n if (dateOnly > maxDateOnly) return true;\r\n }\r\n\r\n if (this.isInvalidDate(date)) return true;\r\n return false;\r\n }\r\n\r\n /** Updates the time component of the selected date(s) when hour/minute selectors change. */\r\n public onTimeChange(): void {\r\n if (this.mode === 'single' && this.selectedDate) {\r\n this.selectedDate = this.applyCurrentTime(this.selectedDate);\r\n this.valueChange.emit(this.selectedDate);\r\n\r\n } else if (this.mode === 'range' && this.startDate && this.endDate) {\r\n\r\n this.startDate = this.applyCurrentTime(this.startDate);\r\n this.endDate = this.applyCurrentTime(this.endDate);\r\n\r\n /** Type assertion is safe here as both dates are confirmed */\r\n this.valueChange.emit({start: this.startDate as Date, end: this.endDate as Date});\r\n\r\n } else if (this.mode === 'range' && this.startDate && !this.endDate) {\r\n // If range started but not completed, update time on the start date only (no emit)\r\n this.startDate = this.applyCurrentTime(this.startDate);\r\n }\r\n }\r\n\r\n /** Handles the click event on a calendar day cell. */\r\n public onDateClick(day: Date | null): void {\r\n if (!day || this.isDateDisabled(day)) return;\r\n\r\n if (this.mode === 'single') {\r\n this.selectedDate = this.applyCurrentTime(day);\r\n this.valueChange.emit(this.selectedDate);\r\n\r\n } else {\r\n // Range selection logic\r\n if (!this.startDate || (this.startDate && this.endDate)) {\r\n this.startDate = this.applyCurrentTime(day);\r\n this.endDate = null;\r\n } else if (day >= this.startDate) {\r\n this.endDate = this.applyCurrentTime(day);\r\n /** Type assertion is safe here as both dates are set when ending a range */\r\n this.valueChange.emit({start: this.startDate as Date, end: this.endDate as Date});\r\n } else {\r\n this.startDate = this.applyCurrentTime(day);\r\n this.endDate = null;\r\n }\r\n this.hoveredDate = null;\r\n }\r\n\r\n // Update time controls to reflect the time of the newly selected date\r\n if (this.mode === 'single' && this.selectedDate) {\r\n this.update12HourState(this.selectedDate.getHours());\r\n this.currentMinute = this.selectedDate.getMinutes();\r\n } else if (this.mode === 'range' && this.startDate) {\r\n this.update12HourState(this.startDate.getHours());\r\n this.currentMinute = this.startDate.getMinutes();\r\n }\r\n }\r\n\r\n /** Handles hover events for range preview when only the start date is selected. */\r\n public onDateHover(day: Date | null): void {\r\n if (this.mode === 'range' && this.startDate && !this.endDate && day) {\r\n this.hoveredDate = day;\r\n }\r\n }\r\n\r\n /** Checks if a date is within the range being previewed (during hover). */\r\n public isPreviewInRange(day: Date | null): boolean {\r\n if (this.mode !== 'range' || !this.startDate || this.endDate || !this.hoveredDate || !day) return false;\r\n const start = this.startDate.getTime();\r\n const end = this.hoveredDate.getTime();\r\n const time = day.getTime();\r\n return time > Math.min(start, end) && time < Math.max(start, end);\r\n }\r\n\r\n /** Generates the calendar grid for the currently active month. */\r\n public generateCalendar(): void {\r\n this.daysInMonth = [];\r\n const year = this.currentDate.getFullYear();\r\n const month = this.currentDate.getMonth();\r\n this._currentMonth = month;\r\n this._currentYear = year;\r\n this.generateDropdownOptions();\r\n const firstDayOfMonth = new Date(year, month, 1);\r\n const lastDayOfMonth = new Date(year, month + 1, 0);\r\n const startDayOfWeek = firstDayOfMonth.getDay();\r\n const emptyCellCount = (startDayOfWeek - this.firstDayOfWeek + 7) % 7;\r\n\r\n for (let i = 0; i < emptyCellCount; i++) {\r\n this.daysInMonth.push(null);\r\n }\r\n for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {\r\n this.daysInMonth.push(this._normalizeDate(new Date(year, month, i)));\r\n }\r\n }\r\n\r\n /** Generates month and year options for dropdowns. */\r\n private generateDropdownOptions(): void {\r\n const startYear = this._currentYear - 10;\r\n const endYear = this._currentYear + 10;\r\n this.yearOptions = [];\r\n for (let i = startYear; i <= endYear; i++) {\r\n this.yearOptions.push({label: `${i}`, value: i});\r\n }\r\n }\r\n\r\n /** Moves the calendar view forward or backward by one month. */\r\n public changeMonth(delta: number): void {\r\n this.currentDate.setMonth(this.currentDate.getMonth() + delta);\r\n this.generateCalendar();\r\n }\r\n\r\n /** Utility function to check if two dates represent the same day (ignoring time). */\r\n public isSameDay(d1: Date | null, d2: Date | null): boolean {\r\n if (!d1 || !d2) return false;\r\n return (\r\n d1.getFullYear() === d2.getFullYear() &&\r\n d1.getMonth() === d2.getMonth() &&\r\n d1.getDate() === d2.getDate()\r\n );\r\n }\r\n\r\n /** Checks if a date is strictly between the start and end of a selected range (ignoring time). */\r\n public isInRange(d: Date | null): boolean {\r\n if (!d || !this.startDate || !this.endDate) return false;\r\n\r\n // Use date-only comparison for highlighting the days\r\n const dTime = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\r\n const startDayTime = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate()).getTime();\r\n const endDayTime = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate()).getTime();\r\n\r\n const startTime = Math.min(startDayTime, endDayTime);\r\n const endTime = Math.max(startDayTime, endDayTime);\r\n\r\n return dTime > startTime && dTime < endTime;\r\n }\r\n}\r\n","/*\r\n * Public API Surface of ngxsmk-datepicker\r\n */\r\n\r\nexport * from './lib/ngxsmk-datepicker';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngxsmk-datepicker.mjs","sources":["../../../projects/ngxsmk-datepicker/src/lib/ngxsmk-datepicker.ts","../../../projects/ngxsmk-datepicker/src/public-api.ts","../../../projects/ngxsmk-datepicker/src/ngxsmk-datepicker.ts"],"sourcesContent":["import {\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n HostBinding,\r\n HostListener,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n SimpleChanges,\r\n PLATFORM_ID,\r\n inject,\r\n} from '@angular/core';\r\nimport { CommonModule, isPlatformBrowser } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\n\r\n// #####################################################################\r\n// ## Reusable Custom Select Component\r\n// #####################################################################\r\n/**\r\n * @title Custom Select Component\r\n * @description A standalone component implementing a custom styled dropdown selector.\r\n * It handles options display, value tracking, and document click-away logic for closing.\r\n *\r\n * @selector app-custom-select\r\n * @export\r\n */\r\n@Component({\r\n selector: 'app-custom-select',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"ngxsmk-select-container\" (click)=\"toggleDropdown()\">\r\n <button type=\"button\" class=\"ngxsmk-select-display\">\r\n <span>{{ displayValue }}</span>\r\n <svg class=\"ngxsmk-arrow-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"48\"\r\n d=\"M112 184l144 144 144-144\"/>\r\n </svg>\r\n </button>\r\n @if (isOpen) {\r\n <div class=\"ngxsmk-options-panel\">\r\n <ul>\r\n @for (option of options; track option.value) {\r\n <li [class.selected]=\"option.value === value\" (click)=\"selectOption(option); $event.stopPropagation()\">\r\n {{ option.label }}\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n position: relative;\r\n display: inline-block;\r\n }\r\n\r\n .ngxsmk-select-container {\r\n cursor: pointer;\r\n }\r\n\r\n .ngxsmk-select-display {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: var(--custom-select-width, 115px);\r\n background: var(--datepicker-background, #fff);\r\n border: 1px solid var(--datepicker-border-color, #ccc);\r\n color: var(--datepicker-text-color, #333);\r\n border-radius: 4px;\r\n padding: 4px 8px;\r\n font-size: 14px;\r\n text-align: left;\r\n height: 30px;\r\n }\r\n\r\n .ngxsmk-arrow-icon {\r\n width: 12px;\r\n height: 12px;\r\n margin-left: 8px;\r\n }\r\n\r\n .ngxsmk-options-panel {\r\n position: absolute;\r\n top: 110%;\r\n left: 0;\r\n width: 100%;\r\n background: var(--datepicker-background, #fff);\r\n border: 1px solid var(--datepicker-border-color, #ccc);\r\n color: var(--datepicker-text-color, #333);\r\n border-radius: 4px;\r\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\r\n max-height: 200px;\r\n overflow-y: auto;\r\n z-index: 9999;\r\n }\r\n\r\n .ngxsmk-options-panel ul {\r\n list-style: none;\r\n padding: 4px;\r\n margin: 0;\r\n }\r\n\r\n .ngxsmk-options-panel li {\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n }\r\n\r\n .ngxsmk-options-panel li:hover {\r\n background-color: var(--datepicker-hover-background, #f0f0f0);\r\n }\r\n\r\n .ngxsmk-options-panel li.selected {\r\n background-color: var(--datepicker-primary-color, #3880ff);\r\n color: var(--datepicker-primary-contrast, #fff);\r\n }\r\n `],\r\n})\r\nexport class CustomSelectComponent {\r\n /** The ElementRef injected via `inject()` for DOM manipulation and click detection. */\r\n private readonly elementRef: ElementRef = inject(ElementRef);\r\n\r\n /** The list of available options to display in the dropdown. */\r\n @Input() options: { label: string; value: any }[] = [];\r\n /** The currently selected value. */\r\n @Input() value: any;\r\n /** Emits the new value when an option is selected. */\r\n @Output() valueChange = new EventEmitter<any>();\r\n public isOpen = false;\r\n\r\n constructor() {}\r\n\r\n /**\r\n * Closes the dropdown when a click event occurs outside the component's native element.\r\n * @param event The mouse event triggered on the document.\r\n */\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: MouseEvent): void {\r\n if (!this.elementRef.nativeElement.contains(event.target)) this.isOpen = false;\r\n }\r\n\r\n /**\r\n * Retrieves the display label corresponding to the currently selected value.\r\n * @returns The label string or an empty string if no option is selected.\r\n */\r\n get displayValue(): string {\r\n const selectedOption = this.options.find((opt) => opt.value === this.value);\r\n return selectedOption ? selectedOption.label : '';\r\n }\r\n\r\n /** Toggles the visibility state of the options dropdown panel. */\r\n toggleDropdown(): void {\r\n this.isOpen = !this.isOpen;\r\n }\r\n\r\n /**\r\n * Handles the selection of a new option, updating the value and closing the dropdown.\r\n * @param option The selected option object containing label and value.\r\n */\r\n selectOption(option: { label: string; value: any }): void {\r\n this.value = option.value;\r\n this.valueChange.emit(this.value);\r\n this.isOpen = false;\r\n }\r\n}\r\n\r\n// #####################################################################\r\n// ## Datepicker Component\r\n// #####################################################################\r\nexport type DateInput = Date | string | { toDate: () => Date; _isAMomentObject?: boolean; $d?: Date };\r\n\r\nexport interface DateRange {\r\n [key: string]: [DateInput, DateInput];\r\n}\r\n\r\n/**\r\n * @title Ngxsmk Datepicker Component\r\n * @description A fully featured, standalone datepicker component supporting single date selection,\r\n * date range selection, time selection, custom date ranges, and theme toggling.\r\n *\r\n * @selector ngxsmk-datepicker\r\n * @implements OnInit, OnChanges\r\n * @export\r\n */\r\n@Component({\r\n selector: 'ngxsmk-datepicker',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule, CustomSelectComponent],\r\n template: `\r\n <div class=\"ngxsmk-datepicker-container\">\r\n @if (showRanges && rangesArray.length > 0 && mode === 'range') {\r\n <div class=\"ngxsmk-ranges-container\">\r\n <ul>\r\n @for (range of rangesArray; track range.key) {\r\n <li (click)=\"selectRange(range.value)\">{{ range.key }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n <div class=\"ngxsmk-calendar-container\">\r\n <div class=\"ngxsmk-header\">\r\n <div class=\"ngxsmk-month-year-selects\">\r\n <app-custom-select class=\"month-select\" [options]=\"monthOptions\"\r\n [(value)]=\"currentMonth\"></app-custom-select>\r\n <app-custom-select class=\"year-select\" [options]=\"yearOptions\" [(value)]=\"currentYear\"></app-custom-select>\r\n </div>\r\n <div class=\"ngxsmk-nav-buttons\">\r\n <button type=\"button\" class=\"ngxsmk-nav-button\" (click)=\"changeMonth(-1)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"48\"\r\n d=\"M328 112L184 256l144 144\"/>\r\n </svg>\r\n </button>\r\n <button type=\"button\" class=\"ngxsmk-nav-button\" (click)=\"changeMonth(1)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"48\"\r\n d=\"M184 112l144 144-144 144\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"ngxsmk-days-grid-wrapper\">\r\n <div class=\"ngxsmk-days-grid\">\r\n @for (day of weekDays; track day) {\r\n <div class=\"ngxsmk-day-name\">{{ day }}</div>\r\n }\r\n @for (day of daysInMonth; track $index) {\r\n <div class=\"ngxsmk-day-cell\"\r\n [class.empty]=\"!day\" [class.disabled]=\"isDateDisabled(day)\" [class.today]=\"isSameDay(day, today)\"\r\n [class.selected]=\"mode === 'single' && isSameDay(day, selectedDate)\"\r\n [class.start-date]=\"mode === 'range' && isSameDay(day, startDate)\"\r\n [class.end-date]=\"mode === 'range' && isSameDay(day, endDate)\"\r\n [class.in-range]=\"mode === 'range' && isInRange(day)\"\r\n [class.preview-range]=\"isPreviewInRange(day)\"\r\n (click)=\"onDateClick(day)\" (mouseenter)=\"onDateHover(day)\">\r\n @if (day) {\r\n <div class=\"ngxsmk-day-number\">{{ day | date : 'd' }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (showTime) {\r\n <div class=\"ngxsmk-time-selection\">\r\n <span class=\"ngxsmk-time-label\">Time:</span>\r\n <app-custom-select\r\n class=\"hour-select\"\r\n [options]=\"hourOptions\"\r\n [(value)]=\"currentDisplayHour\"\r\n (valueChange)=\"onTimeChange()\"\r\n ></app-custom-select>\r\n <span class=\"ngxsmk-time-separator\">:</span>\r\n <app-custom-select\r\n class=\"minute-select\"\r\n [options]=\"minuteOptions\"\r\n [(value)]=\"currentMinute\"\r\n (valueChange)=\"onTimeChange()\"\r\n ></app-custom-select>\r\n <app-custom-select\r\n class=\"ampm-select\"\r\n [options]=\"ampmOptions\"\r\n [(value)]=\"isPm\"\r\n (valueChange)=\"onTimeChange()\"\r\n ></app-custom-select>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --datepicker-primary-color: #6d28d9;\r\n --datepicker-primary-contrast: #ffffff;\r\n --datepicker-range-background: #f5f3ff;\r\n --datepicker-background: #ffffff;\r\n --datepicker-text-color: #222428;\r\n --datepicker-subtle-text-color: #9ca3af;\r\n --datepicker-border-color: #e9e9e9;\r\n --datepicker-hover-background: #f0f0f0;\r\n }\r\n\r\n :host(.dark-theme) {\r\n --datepicker-range-background: rgba(139, 92, 246, 0.2);\r\n --datepicker-background: #1f2937;\r\n --datepicker-text-color: #d1d5db;\r\n --datepicker-subtle-text-color: #6b7280;\r\n --datepicker-border-color: #4b5563;\r\n --datepicker-hover-background: #374151;\r\n }\r\n\r\n .ngxsmk-datepicker-container {\r\n display: flex;\r\n }\r\n\r\n .ngxsmk-calendar-container {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n border-radius: 10px;\r\n padding: 16px;\r\n background: var(--datepicker-background);\r\n }\r\n\r\n .ngxsmk-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n margin-bottom: 12px;\r\n position: relative;\r\n z-index: 2;\r\n gap: 5px;\r\n }\r\n\r\n .ngxsmk-month-year-selects {\r\n display: flex;\r\n gap: 5px;\r\n }\r\n\r\n .ngxsmk-month-year-selects app-custom-select.month-select {\r\n --custom-select-width: 120px;\r\n }\r\n\r\n .ngxsmk-month-year-selects app-custom-select.year-select {\r\n --custom-select-width: 90px;\r\n }\r\n\r\n .ngxsmk-nav-buttons {\r\n display: flex;\r\n }\r\n\r\n .ngxsmk-nav-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n cursor: pointer;\r\n border-radius: 50%;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: var(--datepicker-text-color);\r\n }\r\n\r\n .ngxsmk-nav-button:hover {\r\n background-color: var(--datepicker-hover-background);\r\n }\r\n\r\n .ngxsmk-nav-button svg {\r\n width: 18px;\r\n height: 18px;\r\n }\r\n\r\n .ngxsmk-days-grid-wrapper {\r\n position: relative;\r\n }\r\n\r\n .ngxsmk-days-grid {\r\n display: grid;\r\n grid-template-columns: repeat(7, 1fr);\r\n text-align: center;\r\n gap: 0;\r\n }\r\n\r\n .ngxsmk-day-name {\r\n font-weight: 600;\r\n font-size: 0.8rem;\r\n color: var(--datepicker-subtle-text-color);\r\n padding: 8px 0;\r\n }\r\n\r\n .ngxsmk-day-cell {\r\n position: relative;\r\n height: 38px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n cursor: pointer;\r\n border-radius: 0;\r\n }\r\n\r\n .ngxsmk-day-number {\r\n width: 36px;\r\n height: 36px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n border-radius: 50%;\r\n color: var(--datepicker-text-color);\r\n position: relative;\r\n z-index: 1;\r\n }\r\n\r\n .ngxsmk-day-cell:not(.disabled):hover .ngxsmk-day-number {\r\n background-color: var(--datepicker-hover-background);\r\n color: var(--datepicker-primary-color);\r\n }\r\n\r\n /* --- Range Highlight --- */\r\n .ngxsmk-day-cell.in-range,\r\n .ngxsmk-day-cell.start-date,\r\n .ngxsmk-day-cell.end-date,\r\n .ngxsmk-day-cell.preview-range {\r\n background-color: var(--datepicker-range-background);\r\n }\r\n\r\n /* Apply radius to the edge cells */\r\n .ngxsmk-day-cell.start-date {\r\n border-top-left-radius: 100%;\r\n border-bottom-left-radius: 100%;\r\n }\r\n\r\n .ngxsmk-day-cell.end-date {\r\n border-top-right-radius: 100%;\r\n border-bottom-right-radius: 100%;\r\n }\r\n\r\n .ngxsmk-day-cell.start-date.end-date {\r\n border-radius: 50px;\r\n }\r\n /* --- End Range Highlight --- */\r\n\r\n .ngxsmk-day-cell.disabled {\r\n background-color: transparent !important;\r\n color: #4b5563;\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n opacity: 0.5;\r\n }\r\n\r\n .ngxsmk-day-cell.today .ngxsmk-day-number {\r\n border: 1px solid var(--datepicker-primary-color);\r\n }\r\n\r\n .ngxsmk-ranges-container {\r\n width: 180px;\r\n padding: 16px;\r\n border-right: 1px solid var(--datepicker-border-color);\r\n background: var(--datepicker-background);\r\n }\r\n\r\n .ngxsmk-ranges-container ul {\r\n list-style: none;\r\n padding: 0;\r\n margin: 0;\r\n }\r\n\r\n .ngxsmk-ranges-container li {\r\n padding: 10px;\r\n margin-bottom: 8px;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n color: var(--datepicker-text-color);\r\n }\r\n\r\n .ngxsmk-ranges-container li:hover {\r\n background-color: var(--datepicker-hover-background);\r\n }\r\n\r\n .ngxsmk-time-selection {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n margin-top: 16px;\r\n padding-top: 12px;\r\n border-top: 1px solid var(--datepicker-border-color);\r\n }\r\n\r\n .ngxsmk-time-label {\r\n font-size: 0.9rem;\r\n color: var(--datepicker-subtle-text-color);\r\n margin-right: 4px;\r\n }\r\n\r\n .ngxsmk-time-selection app-custom-select {\r\n --custom-select-width: 60px;\r\n height: 30px;\r\n }\r\n\r\n .ngxsmk-time-selection app-custom-select.ampm-select {\r\n --custom-select-width: 70px;\r\n }\r\n\r\n .ngxsmk-time-separator {\r\n font-weight: 600;\r\n font-size: 1.1rem;\r\n color: var(--datepicker-text-color);\r\n }\r\n `],\r\n})\r\nexport class NgxsmkDatepickerComponent implements OnInit, OnChanges {\r\n\r\n /** Platform ID injected via `inject()` for Server-Side Rendering (SSR) checks. */\r\n private readonly platformId = inject(PLATFORM_ID);\r\n\r\n /** Sets the selection mode: 'single' date or 'range' selection. */\r\n @Input() mode: 'single' | 'range' = 'single';\r\n /** A function to programmatically disable specific dates. Returns true if the date should be disabled. */\r\n @Input() isInvalidDate: (date: Date) => boolean = () => false;\r\n /** If true, displays the predefined ranges panel when in 'range' mode. */\r\n @Input() showRanges: boolean = true;\r\n /** If true, displays the time selection controls (hour/minute). */\r\n @Input() showTime: boolean = false;\r\n /** Sets the minute selection step/interval (e.g., 5, 15, 30). */\r\n @Input() minuteInterval: number = 1;\r\n\r\n /** The initial selected date or date range. Accepts Date, or { start: Date, end: Date }. */\r\n @Input() value: Date | { start: Date, end: Date } | null = null;\r\n\r\n private _locale: string = 'en-US';\r\n\r\n /** Sets the locale for language and regional formatting (e.g., 'en-US', 'de-DE'). */\r\n @Input() set locale(value: string) {\r\n this._locale = value;\r\n }\r\n\r\n get locale(): string {\r\n return this._locale;\r\n }\r\n\r\n /** Controls the visual theme: 'light' or 'dark'. */\r\n @Input() theme: 'light' | 'dark' = 'light';\r\n\r\n /** Binds the dark-theme class to the host element when theme is 'dark'. */\r\n @HostBinding('class.dark-theme') get isDarkMode() {\r\n return this.theme === 'dark';\r\n }\r\n\r\n /** Emits the newly selected date or date range. */\r\n @Output() valueChange = new EventEmitter<Date | { start: Date; end: Date }>();\r\n\r\n private _minDate: Date | null = null;\r\n\r\n /** The earliest selectable date. */\r\n @Input() set minDate(value: DateInput | null) {\r\n this._minDate = this._normalizeDate(value);\r\n }\r\n\r\n private _maxDate: Date | null = null;\r\n\r\n /** The latest selectable date. */\r\n @Input() set maxDate(value: DateInput | null) {\r\n this._maxDate = this._normalizeDate(value);\r\n }\r\n\r\n private _ranges: { [key: string]: [Date, Date] } | null = null;\r\n\r\n /** An object of predefined date ranges for quick selection. */\r\n @Input() set ranges(value: DateRange | null) {\r\n if (!value) {\r\n this._ranges = null;\r\n } else {\r\n this._ranges = Object.entries(value).reduce((acc, [key, dates]) => {\r\n const start = this._normalizeDate(dates[0]);\r\n const end = this._normalizeDate(dates[1]);\r\n if (start && end) acc[key] = [start, end];\r\n return acc;\r\n }, {} as { [key: string]: [Date, Date] });\r\n }\r\n this.updateRangesArray();\r\n }\r\n\r\n public currentDate: Date = new Date();\r\n public daysInMonth: (Date | null)[] = [];\r\n public weekDays: string[] = [];\r\n public readonly today: Date = new Date();\r\n public selectedDate: Date | null = null;\r\n public startDate: Date | null = null;\r\n public endDate: Date | null = null;\r\n public hoveredDate: Date | null = null;\r\n public rangesArray: { key: string; value: [Date, Date] }[] = [];\r\n private _currentMonth!: number;\r\n private _currentYear!: number;\r\n public monthOptions: { label: string; value: number }[] = [];\r\n public yearOptions: { label: string; value: number }[] = [];\r\n private firstDayOfWeek: number = 0;\r\n\r\n // Time selection state\r\n public currentHour: number = 0; // Internal 24h format (0-23)\r\n public currentMinute: number = 0;\r\n public currentDisplayHour: number = 12; // Display 12h format (1-12)\r\n public isPm: boolean = false; // Tracks AM/PM status\r\n\r\n public hourOptions: { label: string; value: number }[] = [];\r\n public minuteOptions: { label: string; value: number }[] = [];\r\n public ampmOptions: { label: string; value: boolean }[] = [\r\n { label: 'AM', value: false },\r\n { label: 'PM', value: true }\r\n ];\r\n\r\n constructor() {}\r\n\r\n /** Retrieves the currently displayed calendar month index. */\r\n get currentMonth(): number {\r\n return this._currentMonth;\r\n }\r\n\r\n /** Sets the month index and regenerates the calendar grid. */\r\n set currentMonth(month: number) {\r\n if (this._currentMonth !== month) {\r\n this._currentMonth = month;\r\n this.currentDate.setMonth(month);\r\n this.generateCalendar();\r\n }\r\n }\r\n\r\n /** Retrieves the currently displayed calendar year. */\r\n get currentYear(): number {\r\n return this._currentYear;\r\n }\r\n\r\n /** Sets the year and regenerates the calendar grid. */\r\n set currentYear(year: number) {\r\n if (this._currentYear !== year) {\r\n this._currentYear = year;\r\n this.currentDate.setFullYear(year);\r\n this.generateCalendar();\r\n }\r\n }\r\n\r\n /** Initializes the component, performs platform checks, and sets up date/time states. */\r\n ngOnInit(): void {\r\n if (isPlatformBrowser(this.platformId)) {\r\n this._locale = navigator.language;\r\n }\r\n\r\n this.today.setHours(0, 0, 0, 0);\r\n this.generateLocaleData();\r\n this.generateTimeOptions();\r\n\r\n // Set default time to current time if enabled and no initial value\r\n if (this.showTime && !this.value) {\r\n const now = new Date();\r\n\r\n this.currentHour = now.getHours();\r\n this.currentMinute = Math.floor(now.getMinutes() / this.minuteInterval) * this.minuteInterval;\r\n\r\n if (this.currentMinute === 60) {\r\n this.currentMinute = 0;\r\n this.currentHour = (this.currentHour + 1) % 24;\r\n }\r\n\r\n this.update12HourState(this.currentHour);\r\n }\r\n\r\n if (this.value) {\r\n this.initializeValue(this.value);\r\n }\r\n this.generateCalendar();\r\n }\r\n\r\n /** Handles input changes, particularly for `locale`, `minuteInterval`, and `value`. */\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['locale']) {\r\n this.generateLocaleData();\r\n this.generateCalendar();\r\n }\r\n\r\n if (changes['minuteInterval']) {\r\n this.generateTimeOptions();\r\n this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;\r\n this.onTimeChange();\r\n }\r\n\r\n if (changes['value'] && changes['value'].currentValue !== changes['value'].previousValue) {\r\n this.initializeValue(changes['value'].currentValue);\r\n this.generateCalendar();\r\n }\r\n }\r\n\r\n /**\r\n * Converts the displayed 12-hour time (displayHour + isPm) into the 24-hour internal time.\r\n * @param displayHour The 12-hour display hour (1-12).\r\n * @param isPm Whether the time is PM (true) or AM (false).\r\n * @returns The 24-hour time (0-23).\r\n */\r\n private get24Hour(displayHour: number, isPm: boolean): number {\r\n if (isPm) {\r\n return displayHour === 12 ? 12 : displayHour + 12;\r\n } else {\r\n return displayHour === 12 ? 0 : displayHour;\r\n }\r\n }\r\n\r\n /**\r\n * Updates the display time variables (12h format and AM/PM state) from the 24h internal time.\r\n * @param fullHour The 24-hour time (0-23).\r\n */\r\n private update12HourState(fullHour: number): void {\r\n this.isPm = fullHour >= 12;\r\n this.currentDisplayHour = fullHour % 12 || 12;\r\n }\r\n\r\n /**\r\n * Applies the currently selected hour and minute to a given date object.\r\n * @param date The date object to modify.\r\n * @returns The modified date object.\r\n */\r\n private applyCurrentTime(date: Date): Date {\r\n this.currentHour = this.get24Hour(this.currentDisplayHour, this.isPm);\r\n date.setHours(this.currentHour, this.currentMinute, 0, 0);\r\n return date;\r\n }\r\n\r\n /**\r\n * Initializes selection state and time controls from the provided input value.\r\n * @param value The input date or date range.\r\n */\r\n private initializeValue(value: Date | { start: Date, end: Date } | null): void {\r\n if (!value) {\r\n this.selectedDate = null;\r\n this.startDate = null;\r\n this.endDate = null;\r\n return;\r\n }\r\n\r\n let initialDate: Date | null = null;\r\n\r\n if (this.mode === 'single' && value instanceof Date) {\r\n this.selectedDate = this._normalizeDate(value);\r\n initialDate = this.selectedDate;\r\n\r\n } else if (this.mode === 'range' && typeof value === 'object' && 'start' in value && 'end' in value) {\r\n this.startDate = this._normalizeDate(value.start);\r\n this.endDate = this._normalizeDate(value.end);\r\n initialDate = this.startDate;\r\n }\r\n\r\n if (initialDate) {\r\n this.currentDate = new Date(initialDate);\r\n\r\n this.currentHour = initialDate.getHours();\r\n this.currentMinute = initialDate.getMinutes();\r\n\r\n this.update12HourState(this.currentHour);\r\n this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;\r\n }\r\n }\r\n\r\n /**\r\n * Normalizes a date input to a Date object, handling various types.\r\n * @param date The input date type.\r\n * @returns A valid Date object or null.\r\n */\r\n private _normalizeDate(date: DateInput | null): Date | null {\r\n if (!date) return null;\r\n const d = (date instanceof Date) ? new Date(date.getTime()) : new Date(date as any);\r\n if (isNaN(d.getTime())) return null;\r\n return d;\r\n }\r\n\r\n /** Generates options for the hour and minute selectors based on the interval. */\r\n private generateTimeOptions(): void {\r\n this.hourOptions = Array.from({ length: 12 }).map((_, i) => ({\r\n label: (i + 1).toString().padStart(2, '0'),\r\n value: i + 1,\r\n }));\r\n\r\n this.minuteOptions = [];\r\n for (let i = 0; i < 60; i += this.minuteInterval) {\r\n this.minuteOptions.push({\r\n label: i.toString().padStart(2, '0'),\r\n value: i,\r\n });\r\n }\r\n }\r\n\r\n /** Generates locale-dependent month and weekday names for display. */\r\n private generateLocaleData(): void {\r\n this.monthOptions = Array.from({length: 12}).map((_, i) => ({\r\n label: new Date(2024, i, 1).toLocaleDateString(this.locale, {month: 'long'}),\r\n value: i,\r\n }));\r\n try {\r\n this.firstDayOfWeek = ((new Intl.Locale(this.locale) as any).weekInfo?.firstDay || 0) % 7;\r\n } catch (e) {\r\n this.firstDayOfWeek = 0;\r\n }\r\n const day = new Date(2024, 0, 7 + this.firstDayOfWeek);\r\n this.weekDays = Array.from({length: 7}).map(() => {\r\n const weekDay = new Date(day).toLocaleDateString(this.locale, {weekday: 'short'});\r\n day.setDate(day.getDate() + 1);\r\n return weekDay;\r\n });\r\n }\r\n\r\n /** Populates the internal array of predefined ranges from the input object. */\r\n private updateRangesArray(): void {\r\n this.rangesArray = this._ranges ? Object.entries(this._ranges).map(([key, value]) => ({key, value})) : [];\r\n }\r\n\r\n /**\r\n * Handles selection of a predefined date range, updates the view, and emits the new range.\r\n * @param range The selected date range [start, end].\r\n */\r\n public selectRange(range: [Date, Date]): void {\r\n this.startDate = this.applyCurrentTime(range[0]);\r\n this.endDate = this.applyCurrentTime(range[1]);\r\n\r\n if (this.startDate && this.endDate) {\r\n this.valueChange.emit({start: this.startDate as Date, end: this.endDate as Date});\r\n }\r\n\r\n this.currentDate = new Date(this.startDate);\r\n this.initializeValue({start: this.startDate, end: this.endDate});\r\n this.generateCalendar();\r\n }\r\n\r\n /**\r\n * Checks if a specific date should be disabled based on minDate, maxDate, or custom function.\r\n * @param date The date to check.\r\n * @returns True if the date is disabled, false otherwise.\r\n */\r\n public isDateDisabled(date: Date | null): boolean {\r\n if (!date) return false;\r\n const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());\r\n\r\n if (this._minDate) {\r\n const minDateOnly = new Date(this._minDate.getFullYear(), this._minDate.getMonth(), this._minDate.getDate());\r\n if (dateOnly < minDateOnly) return true;\r\n }\r\n if (this._maxDate) {\r\n const maxDateOnly = new Date(this._maxDate.getFullYear(), this._maxDate.getMonth(), this._maxDate.getDate());\r\n if (dateOnly > maxDateOnly) return true;\r\n }\r\n\r\n if (this.isInvalidDate(date)) return true;\r\n return false;\r\n }\r\n\r\n /** Updates the time component of the selected date(s) when hour/minute selectors change and emits the new value. */\r\n public onTimeChange(): void {\r\n if (this.mode === 'single' && this.selectedDate) {\r\n this.selectedDate = this.applyCurrentTime(this.selectedDate);\r\n this.valueChange.emit(this.selectedDate);\r\n\r\n } else if (this.mode === 'range' && this.startDate && this.endDate) {\r\n this.startDate = this.applyCurrentTime(this.startDate);\r\n this.endDate = this.applyCurrentTime(this.endDate);\r\n this.valueChange.emit({start: this.startDate as Date, end: this.endDate as Date});\r\n\r\n } else if (this.mode === 'range' && this.startDate && !this.endDate) {\r\n this.startDate = this.applyCurrentTime(this.startDate);\r\n }\r\n }\r\n\r\n /**\r\n * Handles the click event on a calendar day cell to manage single or range selection.\r\n * @param day The date clicked.\r\n */\r\n public onDateClick(day: Date | null): void {\r\n if (!day || this.isDateDisabled(day)) return;\r\n\r\n if (this.mode === 'single') {\r\n this.selectedDate = this.applyCurrentTime(day);\r\n this.valueChange.emit(this.selectedDate);\r\n\r\n } else {\r\n if (!this.startDate || (this.startDate && this.endDate)) {\r\n this.startDate = this.applyCurrentTime(day);\r\n this.endDate = null;\r\n } else if (day >= this.startDate) {\r\n this.endDate = this.applyCurrentTime(day);\r\n this.valueChange.emit({start: this.startDate as Date, end: this.endDate as Date});\r\n } else {\r\n this.startDate = this.applyCurrentTime(day);\r\n this.endDate = null;\r\n }\r\n this.hoveredDate = null;\r\n }\r\n\r\n // Update time controls to reflect the time of the newly selected date\r\n const selectedTimeRef = this.mode === 'single' ? this.selectedDate : this.startDate;\r\n if (selectedTimeRef) {\r\n this.update12HourState(selectedTimeRef.getHours());\r\n this.currentMinute = selectedTimeRef.getMinutes();\r\n }\r\n }\r\n\r\n /**\r\n * Updates the hovered date for range preview during selection.\r\n * @param day The date being hovered over.\r\n */\r\n public onDateHover(day: Date | null): void {\r\n if (this.mode === 'range' && this.startDate && !this.endDate && day) {\r\n this.hoveredDate = day;\r\n }\r\n }\r\n\r\n /**\r\n * Checks if a date is within the range being previewed (during hover).\r\n * @param day The date to check.\r\n * @returns True if the date is in the preview range.\r\n */\r\n public isPreviewInRange(day: Date | null): boolean {\r\n if (this.mode !== 'range' || !this.startDate || this.endDate || !this.hoveredDate || !day) return false;\r\n const start = this.startDate.getTime();\r\n const end = this.hoveredDate.getTime();\r\n const time = day.getTime();\r\n return time > Math.min(start, end) && time < Math.max(start, end);\r\n }\r\n\r\n /** Generates the calendar grid (days and empty cells) for the currently active month. */\r\n public generateCalendar(): void {\r\n this.daysInMonth = [];\r\n const year = this.currentDate.getFullYear();\r\n const month = this.currentDate.getMonth();\r\n this._currentMonth = month;\r\n this._currentYear = year;\r\n this.generateDropdownOptions();\r\n const firstDayOfMonth = new Date(year, month, 1);\r\n const lastDayOfMonth = new Date(year, month + 1, 0);\r\n const startDayOfWeek = firstDayOfMonth.getDay();\r\n const emptyCellCount = (startDayOfWeek - this.firstDayOfWeek + 7) % 7;\r\n\r\n for (let i = 0; i < emptyCellCount; i++) {\r\n this.daysInMonth.push(null);\r\n }\r\n for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {\r\n this.daysInMonth.push(this._normalizeDate(new Date(year, month, i)));\r\n }\r\n }\r\n\r\n /** Generates month and year options for the dropdown selectors. */\r\n private generateDropdownOptions(): void {\r\n const startYear = this._currentYear - 10;\r\n const endYear = this._currentYear + 10;\r\n this.yearOptions = [];\r\n for (let i = startYear; i <= endYear; i++) {\r\n this.yearOptions.push({label: `${i}`, value: i});\r\n }\r\n }\r\n\r\n /**\r\n * Moves the calendar view forward or backward by one month.\r\n * @param delta -1 for previous month, 1 for next month.\r\n */\r\n public changeMonth(delta: number): void {\r\n this.currentDate.setMonth(this.currentDate.getMonth() + delta);\r\n this.generateCalendar();\r\n }\r\n\r\n /**\r\n * Utility function to check if two dates represent the same day (ignoring time).\r\n * @param d1 The first date.\r\n * @param d2 The second date.\r\n * @returns True if they are the same day.\r\n */\r\n public isSameDay(d1: Date | null, d2: Date | null): boolean {\r\n if (!d1 || !d2) return false;\r\n return (\r\n d1.getFullYear() === d2.getFullYear() &&\r\n d1.getMonth() === d2.getMonth() &&\r\n d1.getDate() === d2.getDate()\r\n );\r\n }\r\n\r\n /**\r\n * Checks if a date is strictly between the start and end of a selected range (ignoring time).\r\n * @param d The date to check.\r\n * @returns True if the date is in the selected range.\r\n */\r\n public isInRange(d: Date | null): boolean {\r\n if (!d || !this.startDate || !this.endDate) return false;\r\n\r\n const dTime = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\r\n const startDayTime = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate()).getTime();\r\n const endDayTime = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate()).getTime();\r\n\r\n const startTime = Math.min(startDayTime, endDayTime);\r\n const endTime = Math.max(startDayTime, endDayTime);\r\n\r\n return dTime > startTime && dTime < endTime;\r\n }\r\n}\r\n","/*\r\n * Public API Surface of ngxsmk-datepicker\r\n */\r\n\r\nexport * from './lib/ngxsmk-datepicker';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts CHANGED
@@ -1,7 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, ElementRef, OnInit, OnChanges, SimpleChanges } from '@angular/core';
2
+ import { EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';
3
3
 
4
+ /**
5
+ * @title Custom Select Component
6
+ * @description A standalone component implementing a custom styled dropdown selector.
7
+ * It handles options display, value tracking, and document click-away logic for closing.
8
+ *
9
+ * @selector app-custom-select
10
+ * @export
11
+ */
4
12
  declare class CustomSelectComponent {
13
+ /** The ElementRef injected via `inject()` for DOM manipulation and click detection. */
5
14
  private readonly elementRef;
6
15
  /** The list of available options to display in the dropdown. */
7
16
  options: {
@@ -13,14 +22,23 @@ declare class CustomSelectComponent {
13
22
  /** Emits the new value when an option is selected. */
14
23
  valueChange: EventEmitter<any>;
15
24
  isOpen: boolean;
16
- constructor(elementRef: ElementRef);
17
- /** Closes the dropdown when a click occurs outside the component boundary. */
25
+ constructor();
26
+ /**
27
+ * Closes the dropdown when a click event occurs outside the component's native element.
28
+ * @param event The mouse event triggered on the document.
29
+ */
18
30
  onDocumentClick(event: MouseEvent): void;
19
- /** Gets the display label for the currently selected value. */
31
+ /**
32
+ * Retrieves the display label corresponding to the currently selected value.
33
+ * @returns The label string or an empty string if no option is selected.
34
+ */
20
35
  get displayValue(): string;
21
- /** Toggles the visibility of the dropdown panel. */
36
+ /** Toggles the visibility state of the options dropdown panel. */
22
37
  toggleDropdown(): void;
23
- /** Handles the selection of a new option. */
38
+ /**
39
+ * Handles the selection of a new option, updating the value and closing the dropdown.
40
+ * @param option The selected option object containing label and value.
41
+ */
24
42
  selectOption(option: {
25
43
  label: string;
26
44
  value: any;
@@ -36,7 +54,17 @@ type DateInput = Date | string | {
36
54
  interface DateRange {
37
55
  [key: string]: [DateInput, DateInput];
38
56
  }
57
+ /**
58
+ * @title Ngxsmk Datepicker Component
59
+ * @description A fully featured, standalone datepicker component supporting single date selection,
60
+ * date range selection, time selection, custom date ranges, and theme toggling.
61
+ *
62
+ * @selector ngxsmk-datepicker
63
+ * @implements OnInit, OnChanges
64
+ * @export
65
+ */
39
66
  declare class NgxsmkDatepickerComponent implements OnInit, OnChanges {
67
+ /** Platform ID injected via `inject()` for Server-Side Rendering (SSR) checks. */
40
68
  private readonly platformId;
41
69
  /** Sets the selection mode: 'single' date or 'range' selection. */
42
70
  mode: 'single' | 'range';
@@ -59,6 +87,7 @@ declare class NgxsmkDatepickerComponent implements OnInit, OnChanges {
59
87
  get locale(): string;
60
88
  /** Controls the visual theme: 'light' or 'dark'. */
61
89
  theme: 'light' | 'dark';
90
+ /** Binds the dark-theme class to the host element when theme is 'dark'. */
62
91
  get isDarkMode(): boolean;
63
92
  /** Emits the newly selected date or date range. */
64
93
  valueChange: EventEmitter<Date | {
@@ -114,49 +143,103 @@ declare class NgxsmkDatepickerComponent implements OnInit, OnChanges {
114
143
  value: boolean;
115
144
  }[];
116
145
  constructor();
146
+ /** Retrieves the currently displayed calendar month index. */
117
147
  get currentMonth(): number;
148
+ /** Sets the month index and regenerates the calendar grid. */
118
149
  set currentMonth(month: number);
150
+ /** Retrieves the currently displayed calendar year. */
119
151
  get currentYear(): number;
152
+ /** Sets the year and regenerates the calendar grid. */
120
153
  set currentYear(year: number);
154
+ /** Initializes the component, performs platform checks, and sets up date/time states. */
121
155
  ngOnInit(): void;
156
+ /** Handles input changes, particularly for `locale`, `minuteInterval`, and `value`. */
122
157
  ngOnChanges(changes: SimpleChanges): void;
123
- /** Converts the displayed 12h time (currentDisplayHour + isPm) into the 24h internal time (currentHour). */
158
+ /**
159
+ * Converts the displayed 12-hour time (displayHour + isPm) into the 24-hour internal time.
160
+ * @param displayHour The 12-hour display hour (1-12).
161
+ * @param isPm Whether the time is PM (true) or AM (false).
162
+ * @returns The 24-hour time (0-23).
163
+ */
124
164
  private get24Hour;
125
- /** Updates the display time variables (12h format and AM/PM state) from the 24h internal time. */
165
+ /**
166
+ * Updates the display time variables (12h format and AM/PM state) from the 24h internal time.
167
+ * @param fullHour The 24-hour time (0-23).
168
+ */
126
169
  private update12HourState;
127
- /** Applies the currently selected hour and minute to a given date object. */
170
+ /**
171
+ * Applies the currently selected hour and minute to a given date object.
172
+ * @param date The date object to modify.
173
+ * @returns The modified date object.
174
+ */
128
175
  private applyCurrentTime;
129
- /** Initializes selection state and time controls from the provided input value. */
176
+ /**
177
+ * Initializes selection state and time controls from the provided input value.
178
+ * @param value The input date or date range.
179
+ */
130
180
  private initializeValue;
131
- /** Normalizes a date input to a Date object, keeping time information. */
181
+ /**
182
+ * Normalizes a date input to a Date object, handling various types.
183
+ * @param date The input date type.
184
+ * @returns A valid Date object or null.
185
+ */
132
186
  private _normalizeDate;
133
187
  /** Generates options for the hour and minute selectors based on the interval. */
134
188
  private generateTimeOptions;
135
- /** Generates locale-dependent month and weekday names. */
189
+ /** Generates locale-dependent month and weekday names for display. */
136
190
  private generateLocaleData;
137
- /** Populates the internal array of predefined ranges. */
191
+ /** Populates the internal array of predefined ranges from the input object. */
138
192
  private updateRangesArray;
139
- /** Handles selection of a predefined date range. */
193
+ /**
194
+ * Handles selection of a predefined date range, updates the view, and emits the new range.
195
+ * @param range The selected date range [start, end].
196
+ */
140
197
  selectRange(range: [Date, Date]): void;
141
- /** Checks if a specific date should be disabled based on minDate, maxDate, or custom function. */
198
+ /**
199
+ * Checks if a specific date should be disabled based on minDate, maxDate, or custom function.
200
+ * @param date The date to check.
201
+ * @returns True if the date is disabled, false otherwise.
202
+ */
142
203
  isDateDisabled(date: Date | null): boolean;
143
- /** Updates the time component of the selected date(s) when hour/minute selectors change. */
204
+ /** Updates the time component of the selected date(s) when hour/minute selectors change and emits the new value. */
144
205
  onTimeChange(): void;
145
- /** Handles the click event on a calendar day cell. */
206
+ /**
207
+ * Handles the click event on a calendar day cell to manage single or range selection.
208
+ * @param day The date clicked.
209
+ */
146
210
  onDateClick(day: Date | null): void;
147
- /** Handles hover events for range preview when only the start date is selected. */
211
+ /**
212
+ * Updates the hovered date for range preview during selection.
213
+ * @param day The date being hovered over.
214
+ */
148
215
  onDateHover(day: Date | null): void;
149
- /** Checks if a date is within the range being previewed (during hover). */
216
+ /**
217
+ * Checks if a date is within the range being previewed (during hover).
218
+ * @param day The date to check.
219
+ * @returns True if the date is in the preview range.
220
+ */
150
221
  isPreviewInRange(day: Date | null): boolean;
151
- /** Generates the calendar grid for the currently active month. */
222
+ /** Generates the calendar grid (days and empty cells) for the currently active month. */
152
223
  generateCalendar(): void;
153
- /** Generates month and year options for dropdowns. */
224
+ /** Generates month and year options for the dropdown selectors. */
154
225
  private generateDropdownOptions;
155
- /** Moves the calendar view forward or backward by one month. */
226
+ /**
227
+ * Moves the calendar view forward or backward by one month.
228
+ * @param delta -1 for previous month, 1 for next month.
229
+ */
156
230
  changeMonth(delta: number): void;
157
- /** Utility function to check if two dates represent the same day (ignoring time). */
231
+ /**
232
+ * Utility function to check if two dates represent the same day (ignoring time).
233
+ * @param d1 The first date.
234
+ * @param d2 The second date.
235
+ * @returns True if they are the same day.
236
+ */
158
237
  isSameDay(d1: Date | null, d2: Date | null): boolean;
159
- /** Checks if a date is strictly between the start and end of a selected range (ignoring time). */
238
+ /**
239
+ * Checks if a date is strictly between the start and end of a selected range (ignoring time).
240
+ * @param d The date to check.
241
+ * @returns True if the date is in the selected range.
242
+ */
160
243
  isInRange(d: Date | null): boolean;
161
244
  static ɵfac: i0.ɵɵFactoryDeclaration<NgxsmkDatepickerComponent, never>;
162
245
  static ɵcmp: i0.ɵɵComponentDeclaration<NgxsmkDatepickerComponent, "ngxsmk-datepicker", never, { "mode": { "alias": "mode"; "required": false; }; "isInvalidDate": { "alias": "isInvalidDate"; "required": false; }; "showRanges": { "alias": "showRanges"; "required": false; }; "showTime": { "alias": "showTime"; "required": false; }; "minuteInterval": { "alias": "minuteInterval"; "required": false; }; "value": { "alias": "value"; "required": false; }; "locale": { "alias": "locale"; "required": false; }; "theme": { "alias": "theme"; "required": false; }; "minDate": { "alias": "minDate"; "required": false; }; "maxDate": { "alias": "maxDate"; "required": false; }; "ranges": { "alias": "ranges"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngxsmk-datepicker",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=17.0.0",
6
6
  "@angular/core": ">=17.0.0",