ngxsmk-datepicker 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -24
- package/fesm2022/ngxsmk-datepicker.mjs +265 -61
- package/fesm2022/ngxsmk-datepicker.mjs.map +1 -1
- package/index.d.ts +62 -1
- package/package.json +13 -15
package/README.md
CHANGED
|
@@ -20,15 +20,15 @@ Built with Angular Signals for optimal performance and a clean, declarative API.
|
|
|
20
20
|
|
|
21
21
|
## **✨ Features**
|
|
22
22
|
|
|
23
|
-
* **
|
|
24
|
-
* **
|
|
25
|
-
* **
|
|
26
|
-
* **
|
|
27
|
-
* **
|
|
28
|
-
* **
|
|
29
|
-
* **
|
|
30
|
-
* **
|
|
31
|
-
* **
|
|
23
|
+
* **Date & Time Selection**: Supports `single` date or `range` mode selection, including optional time inputs.
|
|
24
|
+
* **12h/24h Time Support**: Uses internal 24-hour timekeeping but displays a user-friendly **12-hour clock with AM/PM toggle**.
|
|
25
|
+
* **Dynamic Time Intervals**: Configure minute selection steps (e.g., 5, 15, 30 minutes) using the `minuteInterval` input.
|
|
26
|
+
* **Time Restriction**: Time controls are validated against `minDate` to prevent selecting times in the past for the current day.
|
|
27
|
+
* **Predefined Date Ranges**: Offers quick selection of common ranges (e.g., "Last 7 Days").
|
|
28
|
+
* **Advanced Localization (i18n)**: Automatically handles month/weekday names and week start days based on the browser's locale.
|
|
29
|
+
* **Custom Styling**: All component elements are prefixed with `ngxsmk-` and themeable via CSS custom properties.
|
|
30
|
+
* **Rounded Range Borders**: Visually highlights the selected date range with rounded start/end cells.
|
|
31
|
+
* **Flexible Inputs**: Accepts native `Date` objects for initialization.
|
|
32
32
|
|
|
33
33
|
## **🚀 Installation**
|
|
34
34
|
|
|
@@ -40,7 +40,7 @@ Install the package using npm:
|
|
|
40
40
|
|
|
41
41
|
ngxsmk-datepicker is a standalone component, so you can import it directly into your component or module.
|
|
42
42
|
|
|
43
|
-
#### **1
|
|
43
|
+
#### **1. Import the Component**
|
|
44
44
|
|
|
45
45
|
In your component file (e.g., app.component.ts), import NgxsmkDatepickerComponent.
|
|
46
46
|
|
|
@@ -82,7 +82,10 @@ Use the \<ngxsmk-datepicker\> selector in your HTML template.
|
|
|
82
82
|
|
|
83
83
|
<ngxsmk-datepicker
|
|
84
84
|
[mode]="'range'"
|
|
85
|
-
[ranges]="myRanges"
|
|
85
|
+
[ranges]="myRanges"
|
|
86
|
+
[showTime]="true"
|
|
87
|
+
[minuteInterval]="15"
|
|
88
|
+
[minDate]="today"
|
|
86
89
|
[isInvalidDate]="isWeekend"
|
|
87
90
|
[locale]="'en-US'"
|
|
88
91
|
[theme]="'light'"
|
|
@@ -93,22 +96,25 @@ Use the \<ngxsmk-datepicker\> selector in your HTML template.
|
|
|
93
96
|
|
|
94
97
|
### **Inputs**
|
|
95
98
|
|
|
96
|
-
| Property
|
|
97
|
-
|
|
98
|
-
| mode
|
|
99
|
-
| locale
|
|
100
|
-
| theme
|
|
101
|
-
| showRanges
|
|
102
|
-
| minDate
|
|
103
|
-
| maxDate
|
|
104
|
-
| isInvalidDate
|
|
105
|
-
| ranges
|
|
99
|
+
| Property | Type | Default | Description |
|
|
100
|
+
|:--------------------------------------|:-------------------------------------------|:------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
101
|
+
| mode | 'single' | 'range' | 'single' |
|
|
102
|
+
| locale | string | navigator.language | Sets the locale for language and regional formatting (e.g., 'en-US', 'de-DE'). |
|
|
103
|
+
| theme | 'light' | 'dark' | 'light' |
|
|
104
|
+
| showRanges | boolean | true | If true, displays the predefined ranges panel when in 'range' mode. |
|
|
105
|
+
| minDate | DateInput | null | null | The earliest selectable date. Accepts Date, string, moment, or dayjs objects. |
|
|
106
|
+
| maxDate | DateInput | null | null | The latest selectable date. Accepts Date, string, moment, or dayjs objects. |
|
|
107
|
+
| isInvalidDate | (date: Date) \=\> boolean | () \=\> false | A function to programmatically disable specific dates. Returns true if the date should be disabled. |
|
|
108
|
+
| ranges | DateRange | null | null | An object of predefined date ranges. The key is the label, and the value is a \[start, end\] tuple. |
|
|
109
|
+
| minuteInterval | number | 1 | Interval for minute dropdown options (e.g., 5, 15, 30). Used for option generation and initial time rounding. |
|
|
110
|
+
| showTime | boolean | false | Enables the hour/minute/AM/PM selection section. |
|
|
111
|
+
| value | Date \| { start: Date; end: Date } \| null | null | The initial selected date or date range. |
|
|
106
112
|
|
|
107
113
|
### **Outputs**
|
|
108
114
|
|
|
109
|
-
| Event | Payload
|
|
110
|
-
|
|
111
|
-
| valueChange | Date
|
|
115
|
+
| Event | Payload | Description |
|
|
116
|
+
|:------------|:-----------------------------------|:-------------------------------------------------------|
|
|
117
|
+
| valueChange | Date \| { start: Date; end: Date } | Emits the newly selected, time-adjusted date or range. |
|
|
112
118
|
|
|
113
119
|
## **🎨 Theming**
|
|
114
120
|
|
|
@@ -10,21 +10,27 @@ import { FormsModule } from '@angular/forms';
|
|
|
10
10
|
class CustomSelectComponent {
|
|
11
11
|
constructor(elementRef) {
|
|
12
12
|
this.elementRef = elementRef;
|
|
13
|
+
/** The list of available options to display in the dropdown. */
|
|
13
14
|
this.options = [];
|
|
15
|
+
/** Emits the new value when an option is selected. */
|
|
14
16
|
this.valueChange = new EventEmitter();
|
|
15
17
|
this.isOpen = false;
|
|
16
18
|
}
|
|
19
|
+
/** Closes the dropdown when a click occurs outside the component boundary. */
|
|
17
20
|
onDocumentClick(event) {
|
|
18
21
|
if (!this.elementRef.nativeElement.contains(event.target))
|
|
19
22
|
this.isOpen = false;
|
|
20
23
|
}
|
|
24
|
+
/** Gets the display label for the currently selected value. */
|
|
21
25
|
get displayValue() {
|
|
22
26
|
const selectedOption = this.options.find((opt) => opt.value === this.value);
|
|
23
27
|
return selectedOption ? selectedOption.label : '';
|
|
24
28
|
}
|
|
29
|
+
/** Toggles the visibility of the dropdown panel. */
|
|
25
30
|
toggleDropdown() {
|
|
26
31
|
this.isOpen = !this.isOpen;
|
|
27
32
|
}
|
|
33
|
+
/** Handles the selection of a new option. */
|
|
28
34
|
selectOption(option) {
|
|
29
35
|
this.value = option.value;
|
|
30
36
|
this.valueChange.emit(this.value);
|
|
@@ -32,16 +38,16 @@ class CustomSelectComponent {
|
|
|
32
38
|
}
|
|
33
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 }); }
|
|
34
40
|
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: `
|
|
35
|
-
<div class="
|
|
36
|
-
<button type="button" class="select-display">
|
|
41
|
+
<div class="ngxsmk-select-container" (click)="toggleDropdown()">
|
|
42
|
+
<button type="button" class="ngxsmk-select-display">
|
|
37
43
|
<span>{{ displayValue }}</span>
|
|
38
|
-
<svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
44
|
+
<svg class="ngxsmk-arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
39
45
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48"
|
|
40
46
|
d="M112 184l144 144 144-144"/>
|
|
41
47
|
</svg>
|
|
42
48
|
</button>
|
|
43
49
|
@if (isOpen) {
|
|
44
|
-
<div class="options-panel">
|
|
50
|
+
<div class="ngxsmk-options-panel">
|
|
45
51
|
<ul>
|
|
46
52
|
@for (option of options; track option.value) {
|
|
47
53
|
<li [class.selected]="option.value === value" (click)="selectOption(option); $event.stopPropagation()">
|
|
@@ -52,21 +58,21 @@ class CustomSelectComponent {
|
|
|
52
58
|
</div>
|
|
53
59
|
}
|
|
54
60
|
</div>
|
|
55
|
-
`, isInline: true, styles: [":host{position:relative;display:inline-block}.
|
|
61
|
+
`, isInline: true, 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"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
|
|
56
62
|
}
|
|
57
63
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: CustomSelectComponent, decorators: [{
|
|
58
64
|
type: Component,
|
|
59
65
|
args: [{ selector: 'app-custom-select', standalone: true, imports: [CommonModule], template: `
|
|
60
|
-
<div class="
|
|
61
|
-
<button type="button" class="select-display">
|
|
66
|
+
<div class="ngxsmk-select-container" (click)="toggleDropdown()">
|
|
67
|
+
<button type="button" class="ngxsmk-select-display">
|
|
62
68
|
<span>{{ displayValue }}</span>
|
|
63
|
-
<svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
69
|
+
<svg class="ngxsmk-arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
64
70
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48"
|
|
65
71
|
d="M112 184l144 144 144-144"/>
|
|
66
72
|
</svg>
|
|
67
73
|
</button>
|
|
68
74
|
@if (isOpen) {
|
|
69
|
-
<div class="options-panel">
|
|
75
|
+
<div class="ngxsmk-options-panel">
|
|
70
76
|
<ul>
|
|
71
77
|
@for (option of options; track option.value) {
|
|
72
78
|
<li [class.selected]="option.value === value" (click)="selectOption(option); $event.stopPropagation()">
|
|
@@ -77,7 +83,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
77
83
|
</div>
|
|
78
84
|
}
|
|
79
85
|
</div>
|
|
80
|
-
`, styles: [":host{position:relative;display:inline-block}.
|
|
86
|
+
`, 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"] }]
|
|
81
87
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { options: [{
|
|
82
88
|
type: Input
|
|
83
89
|
}], value: [{
|
|
@@ -89,6 +95,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
89
95
|
args: ['document:click', ['$event']]
|
|
90
96
|
}] } });
|
|
91
97
|
class NgxsmkDatepickerComponent {
|
|
98
|
+
/** Sets the locale for language and regional formatting (e.g., 'en-US', 'de-DE'). */
|
|
92
99
|
set locale(value) {
|
|
93
100
|
this._locale = value;
|
|
94
101
|
}
|
|
@@ -98,12 +105,15 @@ class NgxsmkDatepickerComponent {
|
|
|
98
105
|
get isDarkMode() {
|
|
99
106
|
return this.theme === 'dark';
|
|
100
107
|
}
|
|
108
|
+
/** The earliest selectable date. */
|
|
101
109
|
set minDate(value) {
|
|
102
110
|
this._minDate = this._normalizeDate(value);
|
|
103
111
|
}
|
|
112
|
+
/** The latest selectable date. */
|
|
104
113
|
set maxDate(value) {
|
|
105
114
|
this._maxDate = this._normalizeDate(value);
|
|
106
115
|
}
|
|
116
|
+
/** An object of predefined date ranges for quick selection. */
|
|
107
117
|
set ranges(value) {
|
|
108
118
|
if (!value) {
|
|
109
119
|
this._ranges = null;
|
|
@@ -121,12 +131,22 @@ class NgxsmkDatepickerComponent {
|
|
|
121
131
|
}
|
|
122
132
|
constructor(platformId) {
|
|
123
133
|
this.platformId = platformId;
|
|
134
|
+
/** Sets the selection mode: 'single' date or 'range' selection. */
|
|
124
135
|
this.mode = 'single';
|
|
136
|
+
/** A function to programmatically disable specific dates. Returns true if the date should be disabled. */
|
|
125
137
|
this.isInvalidDate = () => false;
|
|
138
|
+
/** If true, displays the predefined ranges panel when in 'range' mode. */
|
|
126
139
|
this.showRanges = true;
|
|
140
|
+
/** If true, displays the time selection controls (hour/minute). */
|
|
141
|
+
this.showTime = false;
|
|
142
|
+
/** Sets the minute selection step/interval (e.g., 5, 15, 30). */
|
|
143
|
+
this.minuteInterval = 1;
|
|
144
|
+
/** The initial selected date or date range. Accepts Date, or { start: Date, end: Date }. */
|
|
127
145
|
this.value = null;
|
|
128
146
|
this._locale = 'en-US';
|
|
147
|
+
/** Controls the visual theme: 'light' or 'dark'. */
|
|
129
148
|
this.theme = 'light';
|
|
149
|
+
/** Emits the newly selected date or date range. */
|
|
130
150
|
this.valueChange = new EventEmitter();
|
|
131
151
|
this._minDate = null;
|
|
132
152
|
this._maxDate = null;
|
|
@@ -143,6 +163,17 @@ class NgxsmkDatepickerComponent {
|
|
|
143
163
|
this.monthOptions = [];
|
|
144
164
|
this.yearOptions = [];
|
|
145
165
|
this.firstDayOfWeek = 0;
|
|
166
|
+
// Time selection state
|
|
167
|
+
this.currentHour = 0; // Internal 24h format (0-23)
|
|
168
|
+
this.currentMinute = 0;
|
|
169
|
+
this.currentDisplayHour = 12; // Display 12h format (1-12)
|
|
170
|
+
this.isPm = false; // Tracks AM/PM status
|
|
171
|
+
this.hourOptions = [];
|
|
172
|
+
this.minuteOptions = [];
|
|
173
|
+
this.ampmOptions = [
|
|
174
|
+
{ label: 'AM', value: false },
|
|
175
|
+
{ label: 'PM', value: true }
|
|
176
|
+
];
|
|
146
177
|
if (isPlatformBrowser(this.platformId)) {
|
|
147
178
|
this._locale = navigator.language;
|
|
148
179
|
}
|
|
@@ -170,6 +201,18 @@ class NgxsmkDatepickerComponent {
|
|
|
170
201
|
ngOnInit() {
|
|
171
202
|
this.today.setHours(0, 0, 0, 0);
|
|
172
203
|
this.generateLocaleData();
|
|
204
|
+
this.generateTimeOptions();
|
|
205
|
+
// Set default time to current time if enabled and no initial value
|
|
206
|
+
if (this.showTime && !this.value) {
|
|
207
|
+
const now = new Date();
|
|
208
|
+
this.currentHour = now.getHours();
|
|
209
|
+
this.currentMinute = Math.floor(now.getMinutes() / this.minuteInterval) * this.minuteInterval;
|
|
210
|
+
if (this.currentMinute === 60) {
|
|
211
|
+
this.currentMinute = 0;
|
|
212
|
+
this.currentHour = (this.currentHour + 1) % 24;
|
|
213
|
+
}
|
|
214
|
+
this.update12HourState(this.currentHour);
|
|
215
|
+
}
|
|
173
216
|
if (this.value) {
|
|
174
217
|
this.initializeValue(this.value);
|
|
175
218
|
}
|
|
@@ -180,11 +223,40 @@ class NgxsmkDatepickerComponent {
|
|
|
180
223
|
this.generateLocaleData();
|
|
181
224
|
this.generateCalendar();
|
|
182
225
|
}
|
|
226
|
+
// Regenerate time options if the interval changes
|
|
227
|
+
if (changes['minuteInterval']) {
|
|
228
|
+
this.generateTimeOptions();
|
|
229
|
+
// Recalculate and round current minute to the new interval
|
|
230
|
+
this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;
|
|
231
|
+
this.onTimeChange();
|
|
232
|
+
}
|
|
183
233
|
if (changes['value'] && changes['value'].currentValue !== changes['value'].previousValue) {
|
|
184
234
|
this.initializeValue(changes['value'].currentValue);
|
|
185
235
|
this.generateCalendar();
|
|
186
236
|
}
|
|
187
237
|
}
|
|
238
|
+
/** Converts the displayed 12h time (currentDisplayHour + isPm) into the 24h internal time (currentHour). */
|
|
239
|
+
get24Hour(displayHour, isPm) {
|
|
240
|
+
if (isPm) {
|
|
241
|
+
return displayHour === 12 ? 12 : displayHour + 12; // 12 PM is 12, 1-11 PM is 13-23
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
return displayHour === 12 ? 0 : displayHour; // 12 AM is 0 (midnight), 1-11 AM is 1-11
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** Updates the display time variables (12h format and AM/PM state) from the 24h internal time. */
|
|
248
|
+
update12HourState(fullHour) {
|
|
249
|
+
this.isPm = fullHour >= 12;
|
|
250
|
+
this.currentDisplayHour = fullHour % 12 || 12; // 0 (midnight) or 12 PM both become 12
|
|
251
|
+
}
|
|
252
|
+
/** Applies the currently selected hour and minute to a given date object. */
|
|
253
|
+
applyCurrentTime(date) {
|
|
254
|
+
// Convert 12h display state back to 24h format
|
|
255
|
+
this.currentHour = this.get24Hour(this.currentDisplayHour, this.isPm);
|
|
256
|
+
date.setHours(this.currentHour, this.currentMinute, 0, 0);
|
|
257
|
+
return date;
|
|
258
|
+
}
|
|
259
|
+
/** Initializes selection state and time controls from the provided input value. */
|
|
188
260
|
initializeValue(value) {
|
|
189
261
|
if (!value) {
|
|
190
262
|
this.selectedDate = null;
|
|
@@ -192,29 +264,51 @@ class NgxsmkDatepickerComponent {
|
|
|
192
264
|
this.endDate = null;
|
|
193
265
|
return;
|
|
194
266
|
}
|
|
267
|
+
let initialDate = null;
|
|
195
268
|
if (this.mode === 'single' && value instanceof Date) {
|
|
196
269
|
this.selectedDate = this._normalizeDate(value);
|
|
197
|
-
|
|
198
|
-
this.currentDate = new Date(this.selectedDate);
|
|
199
|
-
}
|
|
270
|
+
initialDate = this.selectedDate;
|
|
200
271
|
}
|
|
201
272
|
else if (this.mode === 'range' && typeof value === 'object' && 'start' in value && 'end' in value) {
|
|
202
273
|
this.startDate = this._normalizeDate(value.start);
|
|
203
274
|
this.endDate = this._normalizeDate(value.end);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
275
|
+
initialDate = this.startDate;
|
|
276
|
+
}
|
|
277
|
+
if (initialDate) {
|
|
278
|
+
this.currentDate = new Date(initialDate);
|
|
279
|
+
// Set time selectors based on 24h value from initial date
|
|
280
|
+
this.currentHour = initialDate.getHours();
|
|
281
|
+
this.currentMinute = initialDate.getMinutes();
|
|
282
|
+
this.update12HourState(this.currentHour);
|
|
283
|
+
// Round minute to nearest interval, in case the initial value time doesn't match the current interval
|
|
284
|
+
this.currentMinute = Math.floor(this.currentMinute / this.minuteInterval) * this.minuteInterval;
|
|
207
285
|
}
|
|
208
286
|
}
|
|
287
|
+
/** Normalizes a date input to a Date object, keeping time information. */
|
|
209
288
|
_normalizeDate(date) {
|
|
210
289
|
if (!date)
|
|
211
290
|
return null;
|
|
212
291
|
const d = (date instanceof Date) ? new Date(date.getTime()) : new Date(date);
|
|
213
292
|
if (isNaN(d.getTime()))
|
|
214
293
|
return null;
|
|
215
|
-
d.setHours(0, 0, 0, 0);
|
|
216
294
|
return d;
|
|
217
295
|
}
|
|
296
|
+
/** Generates options for the hour and minute selectors based on the interval. */
|
|
297
|
+
generateTimeOptions() {
|
|
298
|
+
// Hours are 1 through 12 for 12h format display
|
|
299
|
+
this.hourOptions = Array.from({ length: 12 }).map((_, i) => ({
|
|
300
|
+
label: (i + 1).toString().padStart(2, '0'),
|
|
301
|
+
value: i + 1, // Values 1 through 12
|
|
302
|
+
}));
|
|
303
|
+
this.minuteOptions = [];
|
|
304
|
+
for (let i = 0; i < 60; i += this.minuteInterval) {
|
|
305
|
+
this.minuteOptions.push({
|
|
306
|
+
label: i.toString().padStart(2, '0'),
|
|
307
|
+
value: i,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/** Generates locale-dependent month and weekday names. */
|
|
218
312
|
generateLocaleData() {
|
|
219
313
|
this.monthOptions = Array.from({ length: 12 }).map((_, i) => ({
|
|
220
314
|
label: new Date(2024, i, 1).toLocaleDateString(this.locale, { month: 'long' }),
|
|
@@ -233,55 +327,101 @@ class NgxsmkDatepickerComponent {
|
|
|
233
327
|
return weekDay;
|
|
234
328
|
});
|
|
235
329
|
}
|
|
330
|
+
/** Populates the internal array of predefined ranges. */
|
|
236
331
|
updateRangesArray() {
|
|
237
332
|
this.rangesArray = this._ranges ? Object.entries(this._ranges).map(([key, value]) => ({ key, value })) : [];
|
|
238
333
|
}
|
|
334
|
+
/** Handles selection of a predefined date range. */
|
|
239
335
|
selectRange(range) {
|
|
240
|
-
this.startDate = range[0];
|
|
241
|
-
this.endDate = range[1];
|
|
242
|
-
|
|
336
|
+
this.startDate = this.applyCurrentTime(range[0]);
|
|
337
|
+
this.endDate = this.applyCurrentTime(range[1]);
|
|
338
|
+
if (this.startDate && this.endDate) {
|
|
339
|
+
/** Type assertion is safe here as both dates are explicitly set */
|
|
340
|
+
this.valueChange.emit({ start: this.startDate, end: this.endDate });
|
|
341
|
+
}
|
|
243
342
|
this.currentDate = new Date(this.startDate);
|
|
343
|
+
this.initializeValue({ start: this.startDate, end: this.endDate }); // Update time selectors
|
|
244
344
|
this.generateCalendar();
|
|
245
345
|
}
|
|
346
|
+
/** Checks if a specific date should be disabled based on minDate, maxDate, or custom function. */
|
|
246
347
|
isDateDisabled(date) {
|
|
247
348
|
if (!date)
|
|
248
349
|
return false;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (this.
|
|
252
|
-
|
|
350
|
+
// Check against minDate/maxDate, ensuring we compare only the date part
|
|
351
|
+
const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
352
|
+
if (this._minDate) {
|
|
353
|
+
const minDateOnly = new Date(this._minDate.getFullYear(), this._minDate.getMonth(), this._minDate.getDate());
|
|
354
|
+
if (dateOnly < minDateOnly)
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
if (this._maxDate) {
|
|
358
|
+
const maxDateOnly = new Date(this._maxDate.getFullYear(), this._maxDate.getMonth(), this._maxDate.getDate());
|
|
359
|
+
if (dateOnly > maxDateOnly)
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
253
362
|
if (this.isInvalidDate(date))
|
|
254
363
|
return true;
|
|
255
364
|
return false;
|
|
256
365
|
}
|
|
366
|
+
/** Updates the time component of the selected date(s) when hour/minute selectors change. */
|
|
367
|
+
onTimeChange() {
|
|
368
|
+
if (this.mode === 'single' && this.selectedDate) {
|
|
369
|
+
this.selectedDate = this.applyCurrentTime(this.selectedDate);
|
|
370
|
+
this.valueChange.emit(this.selectedDate);
|
|
371
|
+
}
|
|
372
|
+
else if (this.mode === 'range' && this.startDate && this.endDate) {
|
|
373
|
+
this.startDate = this.applyCurrentTime(this.startDate);
|
|
374
|
+
this.endDate = this.applyCurrentTime(this.endDate);
|
|
375
|
+
/** Type assertion is safe here as both dates are confirmed */
|
|
376
|
+
this.valueChange.emit({ start: this.startDate, end: this.endDate });
|
|
377
|
+
}
|
|
378
|
+
else if (this.mode === 'range' && this.startDate && !this.endDate) {
|
|
379
|
+
// If range started but not completed, update time on the start date only (no emit)
|
|
380
|
+
this.startDate = this.applyCurrentTime(this.startDate);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/** Handles the click event on a calendar day cell. */
|
|
257
384
|
onDateClick(day) {
|
|
258
385
|
if (!day || this.isDateDisabled(day))
|
|
259
386
|
return;
|
|
260
387
|
if (this.mode === 'single') {
|
|
261
|
-
this.selectedDate = day;
|
|
388
|
+
this.selectedDate = this.applyCurrentTime(day);
|
|
262
389
|
this.valueChange.emit(this.selectedDate);
|
|
263
390
|
}
|
|
264
391
|
else {
|
|
392
|
+
// Range selection logic
|
|
265
393
|
if (!this.startDate || (this.startDate && this.endDate)) {
|
|
266
|
-
this.startDate = day;
|
|
394
|
+
this.startDate = this.applyCurrentTime(day);
|
|
267
395
|
this.endDate = null;
|
|
268
396
|
}
|
|
269
397
|
else if (day >= this.startDate) {
|
|
270
|
-
this.endDate = day;
|
|
398
|
+
this.endDate = this.applyCurrentTime(day);
|
|
399
|
+
/** Type assertion is safe here as both dates are set when ending a range */
|
|
271
400
|
this.valueChange.emit({ start: this.startDate, end: this.endDate });
|
|
272
401
|
}
|
|
273
402
|
else {
|
|
274
|
-
this.startDate = day;
|
|
403
|
+
this.startDate = this.applyCurrentTime(day);
|
|
275
404
|
this.endDate = null;
|
|
276
405
|
}
|
|
277
406
|
this.hoveredDate = null;
|
|
278
407
|
}
|
|
408
|
+
// Update time controls to reflect the time of the newly selected date
|
|
409
|
+
if (this.mode === 'single' && this.selectedDate) {
|
|
410
|
+
this.update12HourState(this.selectedDate.getHours());
|
|
411
|
+
this.currentMinute = this.selectedDate.getMinutes();
|
|
412
|
+
}
|
|
413
|
+
else if (this.mode === 'range' && this.startDate) {
|
|
414
|
+
this.update12HourState(this.startDate.getHours());
|
|
415
|
+
this.currentMinute = this.startDate.getMinutes();
|
|
416
|
+
}
|
|
279
417
|
}
|
|
418
|
+
/** Handles hover events for range preview when only the start date is selected. */
|
|
280
419
|
onDateHover(day) {
|
|
281
420
|
if (this.mode === 'range' && this.startDate && !this.endDate && day) {
|
|
282
421
|
this.hoveredDate = day;
|
|
283
422
|
}
|
|
284
423
|
}
|
|
424
|
+
/** Checks if a date is within the range being previewed (during hover). */
|
|
285
425
|
isPreviewInRange(day) {
|
|
286
426
|
if (this.mode !== 'range' || !this.startDate || this.endDate || !this.hoveredDate || !day)
|
|
287
427
|
return false;
|
|
@@ -290,6 +430,7 @@ class NgxsmkDatepickerComponent {
|
|
|
290
430
|
const time = day.getTime();
|
|
291
431
|
return time > Math.min(start, end) && time < Math.max(start, end);
|
|
292
432
|
}
|
|
433
|
+
/** Generates the calendar grid for the currently active month. */
|
|
293
434
|
generateCalendar() {
|
|
294
435
|
this.daysInMonth = [];
|
|
295
436
|
const year = this.currentDate.getFullYear();
|
|
@@ -308,6 +449,7 @@ class NgxsmkDatepickerComponent {
|
|
|
308
449
|
this.daysInMonth.push(this._normalizeDate(new Date(year, month, i)));
|
|
309
450
|
}
|
|
310
451
|
}
|
|
452
|
+
/** Generates month and year options for dropdowns. */
|
|
311
453
|
generateDropdownOptions() {
|
|
312
454
|
const startYear = this._currentYear - 10;
|
|
313
455
|
const endYear = this._currentYear + 10;
|
|
@@ -316,10 +458,12 @@ class NgxsmkDatepickerComponent {
|
|
|
316
458
|
this.yearOptions.push({ label: `${i}`, value: i });
|
|
317
459
|
}
|
|
318
460
|
}
|
|
461
|
+
/** Moves the calendar view forward or backward by one month. */
|
|
319
462
|
changeMonth(delta) {
|
|
320
463
|
this.currentDate.setMonth(this.currentDate.getMonth() + delta);
|
|
321
464
|
this.generateCalendar();
|
|
322
465
|
}
|
|
466
|
+
/** Utility function to check if two dates represent the same day (ignoring time). */
|
|
323
467
|
isSameDay(d1, d2) {
|
|
324
468
|
if (!d1 || !d2)
|
|
325
469
|
return false;
|
|
@@ -327,19 +471,23 @@ class NgxsmkDatepickerComponent {
|
|
|
327
471
|
d1.getMonth() === d2.getMonth() &&
|
|
328
472
|
d1.getDate() === d2.getDate());
|
|
329
473
|
}
|
|
474
|
+
/** Checks if a date is strictly between the start and end of a selected range (ignoring time). */
|
|
330
475
|
isInRange(d) {
|
|
331
476
|
if (!d || !this.startDate || !this.endDate)
|
|
332
477
|
return false;
|
|
333
|
-
//
|
|
334
|
-
const
|
|
335
|
-
const
|
|
336
|
-
|
|
478
|
+
// Use date-only comparison for highlighting the days
|
|
479
|
+
const dTime = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
|
|
480
|
+
const startDayTime = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate()).getTime();
|
|
481
|
+
const endDayTime = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate()).getTime();
|
|
482
|
+
const startTime = Math.min(startDayTime, endDayTime);
|
|
483
|
+
const endTime = Math.max(startDayTime, endDayTime);
|
|
484
|
+
return dTime > startTime && dTime < endTime;
|
|
337
485
|
}
|
|
338
486
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: NgxsmkDatepickerComponent, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
339
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: NgxsmkDatepickerComponent, isStandalone: true, selector: "ngxsmk-datepicker", inputs: { mode: "mode", isInvalidDate: "isInvalidDate", showRanges: "showRanges", value: "value", locale: "locale", theme: "theme", minDate: "minDate", maxDate: "maxDate", ranges: "ranges" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.dark-theme": "this.isDarkMode" } }, usesOnChanges: true, ngImport: i0, template: `
|
|
340
|
-
<div class="datepicker-container">
|
|
487
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: NgxsmkDatepickerComponent, isStandalone: true, selector: "ngxsmk-datepicker", inputs: { mode: "mode", isInvalidDate: "isInvalidDate", showRanges: "showRanges", showTime: "showTime", minuteInterval: "minuteInterval", value: "value", locale: "locale", theme: "theme", minDate: "minDate", maxDate: "maxDate", ranges: "ranges" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.dark-theme": "this.isDarkMode" } }, usesOnChanges: true, ngImport: i0, template: `
|
|
488
|
+
<div class="ngxsmk-datepicker-container">
|
|
341
489
|
@if (showRanges && rangesArray.length > 0 && mode === 'range') {
|
|
342
|
-
<div class="ranges-container">
|
|
490
|
+
<div class="ngxsmk-ranges-container">
|
|
343
491
|
<ul>
|
|
344
492
|
@for (range of rangesArray; track range.key) {
|
|
345
493
|
<li (click)="selectRange(range.value)">{{ range.key }}</li>
|
|
@@ -347,21 +495,21 @@ class NgxsmkDatepickerComponent {
|
|
|
347
495
|
</ul>
|
|
348
496
|
</div>
|
|
349
497
|
}
|
|
350
|
-
<div class="calendar-container">
|
|
351
|
-
<div class="header">
|
|
352
|
-
<div class="month-year-selects">
|
|
498
|
+
<div class="ngxsmk-calendar-container">
|
|
499
|
+
<div class="ngxsmk-header">
|
|
500
|
+
<div class="ngxsmk-month-year-selects">
|
|
353
501
|
<app-custom-select class="month-select" [options]="monthOptions"
|
|
354
502
|
[(value)]="currentMonth"></app-custom-select>
|
|
355
503
|
<app-custom-select class="year-select" [options]="yearOptions" [(value)]="currentYear"></app-custom-select>
|
|
356
504
|
</div>
|
|
357
|
-
<div class="nav-buttons">
|
|
358
|
-
<button type="button" class="nav-button" (click)="changeMonth(-1)">
|
|
505
|
+
<div class="ngxsmk-nav-buttons">
|
|
506
|
+
<button type="button" class="ngxsmk-nav-button" (click)="changeMonth(-1)">
|
|
359
507
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
360
508
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48"
|
|
361
509
|
d="M328 112L184 256l144 144"/>
|
|
362
510
|
</svg>
|
|
363
511
|
</button>
|
|
364
|
-
<button type="button" class="nav-button" (click)="changeMonth(1)">
|
|
512
|
+
<button type="button" class="ngxsmk-nav-button" (click)="changeMonth(1)">
|
|
365
513
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
366
514
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48"
|
|
367
515
|
d="M184 112l144 144-144 144"/>
|
|
@@ -369,13 +517,13 @@ class NgxsmkDatepickerComponent {
|
|
|
369
517
|
</button>
|
|
370
518
|
</div>
|
|
371
519
|
</div>
|
|
372
|
-
<div class="days-grid-wrapper">
|
|
373
|
-
<div class="days-grid">
|
|
520
|
+
<div class="ngxsmk-days-grid-wrapper">
|
|
521
|
+
<div class="ngxsmk-days-grid">
|
|
374
522
|
@for (day of weekDays; track day) {
|
|
375
|
-
<div class="day-name">{{ day }}</div>
|
|
523
|
+
<div class="ngxsmk-day-name">{{ day }}</div>
|
|
376
524
|
}
|
|
377
525
|
@for (day of daysInMonth; track $index) {
|
|
378
|
-
<div class="day-cell"
|
|
526
|
+
<div class="ngxsmk-day-cell"
|
|
379
527
|
[class.empty]="!day" [class.disabled]="isDateDisabled(day)" [class.today]="isSameDay(day, today)"
|
|
380
528
|
[class.selected]="mode === 'single' && isSameDay(day, selectedDate)"
|
|
381
529
|
[class.start-date]="mode === 'range' && isSameDay(day, startDate)"
|
|
@@ -384,22 +532,48 @@ class NgxsmkDatepickerComponent {
|
|
|
384
532
|
[class.preview-range]="isPreviewInRange(day)"
|
|
385
533
|
(click)="onDateClick(day)" (mouseenter)="onDateHover(day)">
|
|
386
534
|
@if (day) {
|
|
387
|
-
<div class="day-number">{{ day | date : 'd' }}</div>
|
|
535
|
+
<div class="ngxsmk-day-number">{{ day | date : 'd' }}</div>
|
|
388
536
|
}
|
|
389
537
|
</div>
|
|
390
538
|
}
|
|
391
539
|
</div>
|
|
392
540
|
</div>
|
|
541
|
+
|
|
542
|
+
@if (showTime) {
|
|
543
|
+
<div class="ngxsmk-time-selection">
|
|
544
|
+
<span class="ngxsmk-time-label">Time:</span>
|
|
545
|
+
<app-custom-select
|
|
546
|
+
class="hour-select"
|
|
547
|
+
[options]="hourOptions"
|
|
548
|
+
[(value)]="currentDisplayHour"
|
|
549
|
+
(valueChange)="onTimeChange()"
|
|
550
|
+
></app-custom-select>
|
|
551
|
+
<span class="ngxsmk-time-separator">:</span>
|
|
552
|
+
<app-custom-select
|
|
553
|
+
class="minute-select"
|
|
554
|
+
[options]="minuteOptions"
|
|
555
|
+
[(value)]="currentMinute"
|
|
556
|
+
(valueChange)="onTimeChange()"
|
|
557
|
+
></app-custom-select>
|
|
558
|
+
<app-custom-select
|
|
559
|
+
class="ampm-select"
|
|
560
|
+
[options]="ampmOptions"
|
|
561
|
+
[(value)]="isPm"
|
|
562
|
+
(valueChange)="onTimeChange()"
|
|
563
|
+
></app-custom-select>
|
|
564
|
+
</div>
|
|
565
|
+
}
|
|
566
|
+
|
|
393
567
|
</div>
|
|
394
568
|
</div>
|
|
395
|
-
`, isInline: true, styles: [":host{--datepicker-primary-color: #6d28d9;--datepicker-primary-contrast: #ffffff;--datepicker-range-background: #f5f3ff;--datepicker-background: #ffffff;--datepicker-text-color: #222428;--datepicker-subtle-text-color: #9ca3af;--datepicker-border-color: #e9e9e9;--datepicker-hover-background: #f0f0f0}:host(.dark-theme){--datepicker-range-background: rgba(139, 92, 246, .2);--datepicker-background: #1f2937;--datepicker-text-color: #d1d5db;--datepicker-subtle-text-color: #6b7280;--datepicker-border-color: #4b5563;--datepicker-hover-background: #374151}.datepicker-container{display:flex}.calendar-container{width:320px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;border:1px solid var(--datepicker-border-color);border-radius:10px;padding:16px;background:var(--datepicker-background)
|
|
569
|
+
`, isInline: true, styles: [":host{--datepicker-primary-color: #6d28d9;--datepicker-primary-contrast: #ffffff;--datepicker-range-background: #f5f3ff;--datepicker-background: #ffffff;--datepicker-text-color: #222428;--datepicker-subtle-text-color: #9ca3af;--datepicker-border-color: #e9e9e9;--datepicker-hover-background: #f0f0f0}:host(.dark-theme){--datepicker-range-background: rgba(139, 92, 246, .2);--datepicker-background: #1f2937;--datepicker-text-color: #d1d5db;--datepicker-subtle-text-color: #6b7280;--datepicker-border-color: #4b5563;--datepicker-hover-background: #374151}.ngxsmk-datepicker-container{display:flex}.ngxsmk-calendar-container{width:320px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;border:1px solid var(--datepicker-border-color);border-radius:10px;padding:16px;background:var(--datepicker-background)}.ngxsmk-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;position:relative;z-index:2}.ngxsmk-month-year-selects{display:flex;gap:8px}.ngxsmk-month-year-selects app-custom-select.month-select{--custom-select-width: 120px}.ngxsmk-month-year-selects app-custom-select.year-select{--custom-select-width: 90px}.ngxsmk-nav-buttons{display:flex}.ngxsmk-nav-button{background:none;border:none;padding:8px;cursor:pointer;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:var(--datepicker-text-color)}.ngxsmk-nav-button:hover{background-color:var(--datepicker-hover-background)}.ngxsmk-nav-button svg{width:18px;height:18px}.ngxsmk-days-grid-wrapper{position:relative}.ngxsmk-days-grid{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;gap:0}.ngxsmk-day-name{font-weight:600;font-size:.8rem;color:var(--datepicker-subtle-text-color);padding:8px 0}.ngxsmk-day-cell{position:relative;height:38px;display:flex;justify-content:center;align-items:center;cursor:pointer;border-radius:0}.ngxsmk-day-number{width:36px;height:36px;display:flex;justify-content:center;align-items:center;border-radius:50%;color:var(--datepicker-text-color);position:relative;z-index:1}.ngxsmk-day-cell:not(.disabled):hover .ngxsmk-day-number{background-color:var(--datepicker-hover-background);color:var(--datepicker-primary-color)}.ngxsmk-day-cell.start-date .ngxsmk-day-number,.ngxsmk-day-cell.end-date .ngxsmk-day-number,.ngxsmk-day-cell.selected .ngxsmk-day-number{background-color:var(--datepicker-primary-color);color:var(--datepicker-primary-contrast)}.ngxsmk-day-cell.in-range,.ngxsmk-day-cell.start-date,.ngxsmk-day-cell.end-date,.ngxsmk-day-cell.preview-range{background-color:var(--datepicker-range-background)}.ngxsmk-day-cell.start-date{border-top-left-radius:10px;border-bottom-left-radius:10px}.ngxsmk-day-cell.end-date{border-top-right-radius:10px;border-bottom-right-radius:10px}.ngxsmk-day-cell.start-date.end-date{border-radius:50px}.ngxsmk-day-cell.disabled{background-color:transparent!important;color:#4b5563;cursor:not-allowed;pointer-events:none;opacity:.5}.ngxsmk-day-cell.today .ngxsmk-day-number{border:1px solid var(--datepicker-primary-color)}.ngxsmk-ranges-container{width:180px;padding:16px;border-right:1px solid var(--datepicker-border-color);background:var(--datepicker-background)}.ngxsmk-ranges-container ul{list-style:none;padding:0;margin:0}.ngxsmk-ranges-container li{padding:10px;margin-bottom:8px;border-radius:6px;cursor:pointer;color:var(--datepicker-text-color)}.ngxsmk-ranges-container li:hover{background-color:var(--datepicker-hover-background)}.ngxsmk-time-selection{display:flex;align-items:center;justify-content:center;gap:4px;margin-top:16px;padding-top:12px;border-top:1px solid var(--datepicker-border-color)}.ngxsmk-time-label{font-size:.9rem;color:var(--datepicker-subtle-text-color);margin-right:4px}.ngxsmk-time-selection app-custom-select{--custom-select-width: 60px;height:30px}.ngxsmk-time-selection app-custom-select.ampm-select{--custom-select-width: 70px}.ngxsmk-time-separator{font-weight:600;font-size:1.1rem;color:var(--datepicker-text-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CustomSelectComponent, selector: "app-custom-select", inputs: ["options", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }] }); }
|
|
396
570
|
}
|
|
397
571
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: NgxsmkDatepickerComponent, decorators: [{
|
|
398
572
|
type: Component,
|
|
399
573
|
args: [{ selector: 'ngxsmk-datepicker', standalone: true, imports: [CommonModule, FormsModule, CustomSelectComponent], template: `
|
|
400
|
-
<div class="datepicker-container">
|
|
574
|
+
<div class="ngxsmk-datepicker-container">
|
|
401
575
|
@if (showRanges && rangesArray.length > 0 && mode === 'range') {
|
|
402
|
-
<div class="ranges-container">
|
|
576
|
+
<div class="ngxsmk-ranges-container">
|
|
403
577
|
<ul>
|
|
404
578
|
@for (range of rangesArray; track range.key) {
|
|
405
579
|
<li (click)="selectRange(range.value)">{{ range.key }}</li>
|
|
@@ -407,21 +581,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
407
581
|
</ul>
|
|
408
582
|
</div>
|
|
409
583
|
}
|
|
410
|
-
<div class="calendar-container">
|
|
411
|
-
<div class="header">
|
|
412
|
-
<div class="month-year-selects">
|
|
584
|
+
<div class="ngxsmk-calendar-container">
|
|
585
|
+
<div class="ngxsmk-header">
|
|
586
|
+
<div class="ngxsmk-month-year-selects">
|
|
413
587
|
<app-custom-select class="month-select" [options]="monthOptions"
|
|
414
588
|
[(value)]="currentMonth"></app-custom-select>
|
|
415
589
|
<app-custom-select class="year-select" [options]="yearOptions" [(value)]="currentYear"></app-custom-select>
|
|
416
590
|
</div>
|
|
417
|
-
<div class="nav-buttons">
|
|
418
|
-
<button type="button" class="nav-button" (click)="changeMonth(-1)">
|
|
591
|
+
<div class="ngxsmk-nav-buttons">
|
|
592
|
+
<button type="button" class="ngxsmk-nav-button" (click)="changeMonth(-1)">
|
|
419
593
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
420
594
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48"
|
|
421
595
|
d="M328 112L184 256l144 144"/>
|
|
422
596
|
</svg>
|
|
423
597
|
</button>
|
|
424
|
-
<button type="button" class="nav-button" (click)="changeMonth(1)">
|
|
598
|
+
<button type="button" class="ngxsmk-nav-button" (click)="changeMonth(1)">
|
|
425
599
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
426
600
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48"
|
|
427
601
|
d="M184 112l144 144-144 144"/>
|
|
@@ -429,13 +603,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
429
603
|
</button>
|
|
430
604
|
</div>
|
|
431
605
|
</div>
|
|
432
|
-
<div class="days-grid-wrapper">
|
|
433
|
-
<div class="days-grid">
|
|
606
|
+
<div class="ngxsmk-days-grid-wrapper">
|
|
607
|
+
<div class="ngxsmk-days-grid">
|
|
434
608
|
@for (day of weekDays; track day) {
|
|
435
|
-
<div class="day-name">{{ day }}</div>
|
|
609
|
+
<div class="ngxsmk-day-name">{{ day }}</div>
|
|
436
610
|
}
|
|
437
611
|
@for (day of daysInMonth; track $index) {
|
|
438
|
-
<div class="day-cell"
|
|
612
|
+
<div class="ngxsmk-day-cell"
|
|
439
613
|
[class.empty]="!day" [class.disabled]="isDateDisabled(day)" [class.today]="isSameDay(day, today)"
|
|
440
614
|
[class.selected]="mode === 'single' && isSameDay(day, selectedDate)"
|
|
441
615
|
[class.start-date]="mode === 'range' && isSameDay(day, startDate)"
|
|
@@ -444,15 +618,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
444
618
|
[class.preview-range]="isPreviewInRange(day)"
|
|
445
619
|
(click)="onDateClick(day)" (mouseenter)="onDateHover(day)">
|
|
446
620
|
@if (day) {
|
|
447
|
-
<div class="day-number">{{ day | date : 'd' }}</div>
|
|
621
|
+
<div class="ngxsmk-day-number">{{ day | date : 'd' }}</div>
|
|
448
622
|
}
|
|
449
623
|
</div>
|
|
450
624
|
}
|
|
451
625
|
</div>
|
|
452
626
|
</div>
|
|
627
|
+
|
|
628
|
+
@if (showTime) {
|
|
629
|
+
<div class="ngxsmk-time-selection">
|
|
630
|
+
<span class="ngxsmk-time-label">Time:</span>
|
|
631
|
+
<app-custom-select
|
|
632
|
+
class="hour-select"
|
|
633
|
+
[options]="hourOptions"
|
|
634
|
+
[(value)]="currentDisplayHour"
|
|
635
|
+
(valueChange)="onTimeChange()"
|
|
636
|
+
></app-custom-select>
|
|
637
|
+
<span class="ngxsmk-time-separator">:</span>
|
|
638
|
+
<app-custom-select
|
|
639
|
+
class="minute-select"
|
|
640
|
+
[options]="minuteOptions"
|
|
641
|
+
[(value)]="currentMinute"
|
|
642
|
+
(valueChange)="onTimeChange()"
|
|
643
|
+
></app-custom-select>
|
|
644
|
+
<app-custom-select
|
|
645
|
+
class="ampm-select"
|
|
646
|
+
[options]="ampmOptions"
|
|
647
|
+
[(value)]="isPm"
|
|
648
|
+
(valueChange)="onTimeChange()"
|
|
649
|
+
></app-custom-select>
|
|
650
|
+
</div>
|
|
651
|
+
}
|
|
652
|
+
|
|
453
653
|
</div>
|
|
454
654
|
</div>
|
|
455
|
-
`, styles: [":host{--datepicker-primary-color: #6d28d9;--datepicker-primary-contrast: #ffffff;--datepicker-range-background: #f5f3ff;--datepicker-background: #ffffff;--datepicker-text-color: #222428;--datepicker-subtle-text-color: #9ca3af;--datepicker-border-color: #e9e9e9;--datepicker-hover-background: #f0f0f0}:host(.dark-theme){--datepicker-range-background: rgba(139, 92, 246, .2);--datepicker-background: #1f2937;--datepicker-text-color: #d1d5db;--datepicker-subtle-text-color: #6b7280;--datepicker-border-color: #4b5563;--datepicker-hover-background: #374151}.datepicker-container{display:flex}.calendar-container{width:320px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;border:1px solid var(--datepicker-border-color);border-radius:10px;padding:16px;background:var(--datepicker-background)
|
|
655
|
+
`, styles: [":host{--datepicker-primary-color: #6d28d9;--datepicker-primary-contrast: #ffffff;--datepicker-range-background: #f5f3ff;--datepicker-background: #ffffff;--datepicker-text-color: #222428;--datepicker-subtle-text-color: #9ca3af;--datepicker-border-color: #e9e9e9;--datepicker-hover-background: #f0f0f0}:host(.dark-theme){--datepicker-range-background: rgba(139, 92, 246, .2);--datepicker-background: #1f2937;--datepicker-text-color: #d1d5db;--datepicker-subtle-text-color: #6b7280;--datepicker-border-color: #4b5563;--datepicker-hover-background: #374151}.ngxsmk-datepicker-container{display:flex}.ngxsmk-calendar-container{width:320px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;border:1px solid var(--datepicker-border-color);border-radius:10px;padding:16px;background:var(--datepicker-background)}.ngxsmk-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;position:relative;z-index:2}.ngxsmk-month-year-selects{display:flex;gap:8px}.ngxsmk-month-year-selects app-custom-select.month-select{--custom-select-width: 120px}.ngxsmk-month-year-selects app-custom-select.year-select{--custom-select-width: 90px}.ngxsmk-nav-buttons{display:flex}.ngxsmk-nav-button{background:none;border:none;padding:8px;cursor:pointer;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:var(--datepicker-text-color)}.ngxsmk-nav-button:hover{background-color:var(--datepicker-hover-background)}.ngxsmk-nav-button svg{width:18px;height:18px}.ngxsmk-days-grid-wrapper{position:relative}.ngxsmk-days-grid{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;gap:0}.ngxsmk-day-name{font-weight:600;font-size:.8rem;color:var(--datepicker-subtle-text-color);padding:8px 0}.ngxsmk-day-cell{position:relative;height:38px;display:flex;justify-content:center;align-items:center;cursor:pointer;border-radius:0}.ngxsmk-day-number{width:36px;height:36px;display:flex;justify-content:center;align-items:center;border-radius:50%;color:var(--datepicker-text-color);position:relative;z-index:1}.ngxsmk-day-cell:not(.disabled):hover .ngxsmk-day-number{background-color:var(--datepicker-hover-background);color:var(--datepicker-primary-color)}.ngxsmk-day-cell.start-date .ngxsmk-day-number,.ngxsmk-day-cell.end-date .ngxsmk-day-number,.ngxsmk-day-cell.selected .ngxsmk-day-number{background-color:var(--datepicker-primary-color);color:var(--datepicker-primary-contrast)}.ngxsmk-day-cell.in-range,.ngxsmk-day-cell.start-date,.ngxsmk-day-cell.end-date,.ngxsmk-day-cell.preview-range{background-color:var(--datepicker-range-background)}.ngxsmk-day-cell.start-date{border-top-left-radius:10px;border-bottom-left-radius:10px}.ngxsmk-day-cell.end-date{border-top-right-radius:10px;border-bottom-right-radius:10px}.ngxsmk-day-cell.start-date.end-date{border-radius:50px}.ngxsmk-day-cell.disabled{background-color:transparent!important;color:#4b5563;cursor:not-allowed;pointer-events:none;opacity:.5}.ngxsmk-day-cell.today .ngxsmk-day-number{border:1px solid var(--datepicker-primary-color)}.ngxsmk-ranges-container{width:180px;padding:16px;border-right:1px solid var(--datepicker-border-color);background:var(--datepicker-background)}.ngxsmk-ranges-container ul{list-style:none;padding:0;margin:0}.ngxsmk-ranges-container li{padding:10px;margin-bottom:8px;border-radius:6px;cursor:pointer;color:var(--datepicker-text-color)}.ngxsmk-ranges-container li:hover{background-color:var(--datepicker-hover-background)}.ngxsmk-time-selection{display:flex;align-items:center;justify-content:center;gap:4px;margin-top:16px;padding-top:12px;border-top:1px solid var(--datepicker-border-color)}.ngxsmk-time-label{font-size:.9rem;color:var(--datepicker-subtle-text-color);margin-right:4px}.ngxsmk-time-selection app-custom-select{--custom-select-width: 60px;height:30px}.ngxsmk-time-selection app-custom-select.ampm-select{--custom-select-width: 70px}.ngxsmk-time-separator{font-weight:600;font-size:1.1rem;color:var(--datepicker-text-color)}\n"] }]
|
|
456
656
|
}], ctorParameters: () => [{ type: Object, decorators: [{
|
|
457
657
|
type: Inject,
|
|
458
658
|
args: [PLATFORM_ID]
|
|
@@ -462,6 +662,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
462
662
|
type: Input
|
|
463
663
|
}], showRanges: [{
|
|
464
664
|
type: Input
|
|
665
|
+
}], showTime: [{
|
|
666
|
+
type: Input
|
|
667
|
+
}], minuteInterval: [{
|
|
668
|
+
type: Input
|
|
465
669
|
}], value: [{
|
|
466
670
|
type: Input
|
|
467
671
|
}], locale: [{
|
|
@@ -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 Inject,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n PLATFORM_ID,\r\n SimpleChanges,\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=\"custom-select-container\" (click)=\"toggleDropdown()\">\r\n <button type=\"button\" class=\"select-display\">\r\n <span>{{ displayValue }}</span>\r\n <svg class=\"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=\"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 .custom-select-container {\r\n cursor: pointer;\r\n }\r\n\r\n .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 }\r\n\r\n .arrow-icon {\r\n width: 12px;\r\n height: 12px;\r\n margin-left: 8px;\r\n }\r\n\r\n .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: 10;\r\n }\r\n\r\n .options-panel ul {\r\n list-style: none;\r\n padding: 4px;\r\n margin: 0;\r\n }\r\n\r\n .options-panel li {\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n }\r\n\r\n .options-panel li:hover {\r\n background-color: var(--datepicker-hover-background, #f0f0f0);\r\n }\r\n\r\n .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 @Input() options: { label: string; value: any }[] = [];\r\n @Input() value: any;\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 @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 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 toggleDropdown(): void {\r\n this.isOpen = !this.isOpen;\r\n }\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@Component({\r\n selector: 'ngxsmk-datepicker',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule, CustomSelectComponent],\r\n template: `\r\n <div class=\"datepicker-container\">\r\n @if (showRanges && rangesArray.length > 0 && mode === 'range') {\r\n <div class=\"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=\"calendar-container\">\r\n <div class=\"header\">\r\n <div class=\"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=\"nav-buttons\">\r\n <button type=\"button\" class=\"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=\"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=\"days-grid-wrapper\">\r\n <div class=\"days-grid\">\r\n @for (day of weekDays; track day) {\r\n <div class=\"day-name\">{{ day }}</div>\r\n }\r\n @for (day of daysInMonth; track $index) {\r\n <div class=\"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=\"day-number\">{{ day | date : 'd' }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\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 .datepicker-container {\r\n display: flex;\r\n }\r\n\r\n .calendar-container {\r\n width: 320px;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n border: 1px solid var(--datepicker-border-color);\r\n border-radius: 10px;\r\n padding: 16px;\r\n background: var(--datepicker-background);\r\n overflow: hidden;\r\n }\r\n\r\n .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 }\r\n\r\n .month-year-selects {\r\n display: flex;\r\n gap: 8px;\r\n }\r\n\r\n .month-year-selects app-custom-select.month-select {\r\n --custom-select-width: 120px;\r\n }\r\n\r\n .month-year-selects app-custom-select.year-select {\r\n --custom-select-width: 90px;\r\n }\r\n\r\n .nav-buttons {\r\n display: flex;\r\n }\r\n\r\n .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 .nav-button:hover {\r\n background-color: var(--datepicker-hover-background);\r\n }\r\n\r\n .nav-button svg {\r\n width: 18px;\r\n height: 18px;\r\n }\r\n\r\n .days-grid-wrapper {\r\n position: relative;\r\n }\r\n\r\n .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 .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 .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 .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 .day-cell:not(.disabled):hover .day-number {\r\n background-color: var(--datepicker-hover-background);\r\n color: var(--datepicker-primary-color);\r\n }\r\n\r\n .day-cell.start-date .day-number,\r\n .day-cell.end-date .day-number,\r\n .day-cell.selected .day-number {\r\n background-color: var(--datepicker-primary-color);\r\n color: var(--datepicker-primary-contrast);\r\n }\r\n\r\n .day-cell.in-range, .day-cell.start-date, .day-cell.end-date, .day-cell.preview-range {\r\n /* Ensure the light background covers the entire cell for connected look */\r\n background-color: var(--datepicker-range-background);\r\n }\r\n\r\n .day-cell.start-date {\r\n border-top-left-radius: 50px;\r\n border-bottom-left-radius: 50px;\r\n }\r\n\r\n .day-cell.end-date {\r\n border-top-right-radius: 50px;\r\n border-bottom-right-radius: 50px;\r\n }\r\n\r\n .day-cell.start-date.end-date {\r\n border-radius: 50px;\r\n }\r\n\r\n .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 .day-cell.today .day-number {\r\n border: 1px solid var(--datepicker-primary-color);\r\n }\r\n\r\n .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 .ranges-container ul {\r\n list-style: none;\r\n padding: 0;\r\n margin: 0;\r\n }\r\n\r\n .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 .ranges-container li:hover {\r\n background-color: var(--datepicker-hover-background);\r\n }\r\n `],\r\n})\r\nexport class NgxsmkDatepickerComponent implements OnInit, OnChanges {\r\n @Input() mode: 'single' | 'range' = 'single';\r\n @Input() isInvalidDate: (date: Date) => boolean = () => false;\r\n @Input() showRanges: boolean = true;\r\n\r\n @Input() value: Date | { start: Date, end: Date } | null = null;\r\n\r\n private _locale: string = 'en-US';\r\n\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 @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 @Output() valueChange = new EventEmitter<Date | { start: Date; end: Date }>();\r\n\r\n private _minDate: Date | null = null;\r\n\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 @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 @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 constructor(@Inject(PLATFORM_ID) private readonly platformId: Object) {\r\n if (isPlatformBrowser(this.platformId)) {\r\n this._locale = navigator.language;\r\n }\r\n }\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 this.today.setHours(0, 0, 0, 0);\r\n this.generateLocaleData();\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 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 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 if (this.mode === 'single' && value instanceof Date) {\r\n this.selectedDate = this._normalizeDate(value);\r\n if (this.selectedDate) {\r\n this.currentDate = new Date(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\r\n if (this.startDate) {\r\n this.currentDate = new Date(this.startDate);\r\n }\r\n }\r\n }\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 d.setHours(0, 0, 0, 0);\r\n return d;\r\n }\r\n\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 private updateRangesArray(): void {\r\n this.rangesArray = this._ranges ? Object.entries(this._ranges).map(([key, value]) => ({key, value})) : [];\r\n }\r\n\r\n public selectRange(range: [Date, Date]): void {\r\n this.startDate = range[0];\r\n this.endDate = range[1];\r\n this.valueChange.emit({start: this.startDate, end: this.endDate});\r\n this.currentDate = new Date(this.startDate);\r\n this.generateCalendar();\r\n }\r\n\r\n public isDateDisabled(date: Date | null): boolean {\r\n if (!date) return false;\r\n if (this._minDate && date < this._minDate) return true;\r\n if (this._maxDate && date > this._maxDate) return true;\r\n if (this.isInvalidDate(date)) return true;\r\n return false;\r\n }\r\n\r\n public onDateClick(day: Date | null): void {\r\n if (!day || this.isDateDisabled(day)) return;\r\n if (this.mode === 'single') {\r\n this.selectedDate = day;\r\n this.valueChange.emit(this.selectedDate);\r\n } else {\r\n if (!this.startDate || (this.startDate && this.endDate)) {\r\n this.startDate = day;\r\n this.endDate = null;\r\n } else if (day >= this.startDate) {\r\n this.endDate = day;\r\n this.valueChange.emit({start: this.startDate, end: this.endDate});\r\n } else {\r\n this.startDate = day;\r\n this.endDate = null;\r\n }\r\n this.hoveredDate = null;\r\n }\r\n }\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 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 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 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 public changeMonth(delta: number): void {\r\n this.currentDate.setMonth(this.currentDate.getMonth() + delta);\r\n this.generateCalendar();\r\n }\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 public isInRange(d: Date | null): boolean {\r\n if (!d || !this.startDate || !this.endDate) return false;\r\n\r\n // This logic ensures highlighting works correctly regardless of the order the user clicked the dates.\r\n const startTime = Math.min(this.startDate.getTime(), this.endDate.getTime());\r\n const endTime = Math.max(this.startDate.getTime(), this.endDate.getTime());\r\n\r\n return d.getTime() > startTime && d.getTime() < 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":";;;;;;AAiBA;AACA;AACA;MA8Fa,qBAAqB,CAAA;AAMhC,IAAA,WAAA,CAA6B,UAAsB,EAAA;QAAtB,IAAA,CAAA,UAAU,GAAV,UAAU;QAL9B,IAAA,CAAA,OAAO,GAAoC,EAAE;AAE5C,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,YAAY,EAAO;QACxC,IAAA,CAAA,MAAM,GAAG,KAAK;IAGrB;AAGA,IAAA,eAAe,CAAC,KAAiB,EAAA;AAC/B,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAAE,YAAA,IAAI,CAAC,MAAM,GAAG,KAAK;IAChF;AAEA,IAAA,IAAI,YAAY,GAAA;QACd,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC;QAC3E,OAAO,cAAc,GAAG,cAAc,CAAC,KAAK,GAAG,EAAE;IACnD;IAEA,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM;IAC5B;AAEA,IAAA,YAAY,CAAC,MAAqC,EAAA;AAChD,QAAA,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AACjC,QAAA,IAAI,CAAC,MAAM,GAAG,KAAK;IACrB;8GA3BW,qBAAqB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,UAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAArB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,KAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,EAAA,WAAA,EAAA,aAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,gBAAA,EAAA,yBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAzFtB,CAAA;;;;;;;;;;;;;;;;;;;;;AAqBT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,0kCAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAtBS,YAAY,EAAA,CAAA,EAAA,CAAA,CAAA;;2FA0FX,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA7FjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,mBAAmB,cACjB,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,CAAC,EAAA,QAAA,EACb,CAAA;;;;;;;;;;;;;;;;;;;;;AAqBT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,0kCAAA,CAAA,EAAA;+EAqEQ,OAAO,EAAA,CAAA;sBAAf;gBACQ,KAAK,EAAA,CAAA;sBAAb;gBACS,WAAW,EAAA,CAAA;sBAApB;gBAOD,eAAe,EAAA,CAAA;sBADd,YAAY;uBAAC,gBAAgB,EAAE,CAAC,QAAQ,CAAC;;MA0R/B,yBAAyB,CAAA;IASpC,IAAa,MAAM,CAAC,KAAa,EAAA;AAC/B,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;IACtB;AAEA,IAAA,IAAI,MAAM,GAAA;QACR,OAAO,IAAI,CAAC,OAAO;IACrB;AAIA,IAAA,IAAqC,UAAU,GAAA;AAC7C,QAAA,OAAO,IAAI,CAAC,KAAK,KAAK,MAAM;IAC9B;IAMA,IAAa,OAAO,CAAC,KAAuB,EAAA;QAC1C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;IAC5C;IAIA,IAAa,OAAO,CAAC,KAAuB,EAAA;QAC1C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;IAC5C;IAIA,IAAa,MAAM,CAAC,KAAuB,EAAA;QACzC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,IAAI,CAAC,OAAO,GAAG,IAAI;QACrB;aAAO;YACL,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;gBAChE,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzC,IAAI,KAAK,IAAI,GAAG;oBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC;AACzC,gBAAA,OAAO,GAAG;YACZ,CAAC,EAAE,EAAqC,CAAC;QAC3C;QACA,IAAI,CAAC,iBAAiB,EAAE;IAC1B;AAiBA,IAAA,WAAA,CAAkD,UAAkB,EAAA;QAAlB,IAAA,CAAA,UAAU,GAAV,UAAU;QAnEnD,IAAA,CAAA,IAAI,GAAuB,QAAQ;AACnC,QAAA,IAAA,CAAA,aAAa,GAA4B,MAAM,KAAK;QACpD,IAAA,CAAA,UAAU,GAAY,IAAI;QAE1B,IAAA,CAAA,KAAK,GAA6C,IAAI;QAEvD,IAAA,CAAA,OAAO,GAAW,OAAO;QAUxB,IAAA,CAAA,KAAK,GAAqB,OAAO;AAMhC,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,YAAY,EAAqC;QAErE,IAAA,CAAA,QAAQ,GAAgB,IAAI;QAM5B,IAAA,CAAA,QAAQ,GAAgB,IAAI;QAM5B,IAAA,CAAA,OAAO,GAA2C,IAAI;AAgBvD,QAAA,IAAA,CAAA,WAAW,GAAS,IAAI,IAAI,EAAE;QAC9B,IAAA,CAAA,WAAW,GAAoB,EAAE;QACjC,IAAA,CAAA,QAAQ,GAAa,EAAE;AACd,QAAA,IAAA,CAAA,KAAK,GAAS,IAAI,IAAI,EAAE;QACjC,IAAA,CAAA,YAAY,GAAgB,IAAI;QAChC,IAAA,CAAA,SAAS,GAAgB,IAAI;QAC7B,IAAA,CAAA,OAAO,GAAgB,IAAI;QAC3B,IAAA,CAAA,WAAW,GAAgB,IAAI;QAC/B,IAAA,CAAA,WAAW,GAA2C,EAAE;QAGxD,IAAA,CAAA,YAAY,GAAuC,EAAE;QACrD,IAAA,CAAA,WAAW,GAAuC,EAAE;QACnD,IAAA,CAAA,cAAc,GAAW,CAAC;AAGhC,QAAA,IAAI,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACtC,YAAA,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,QAAQ;QACnC;IACF;AAEA,IAAA,IAAI,YAAY,GAAA;QACd,OAAO,IAAI,CAAC,aAAa;IAC3B;IAEA,IAAI,YAAY,CAAC,KAAa,EAAA;AAC5B,QAAA,IAAI,IAAI,CAAC,aAAa,KAAK,KAAK,EAAE;AAChC,YAAA,IAAI,CAAC,aAAa,GAAG,KAAK;AAC1B,YAAA,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC;YAChC,IAAI,CAAC,gBAAgB,EAAE;QACzB;IACF;AAEA,IAAA,IAAI,WAAW,GAAA;QACb,OAAO,IAAI,CAAC,YAAY;IAC1B;IAEA,IAAI,WAAW,CAAC,IAAY,EAAA;AAC1B,QAAA,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE;AAC9B,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;AACxB,YAAA,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC;YAClC,IAAI,CAAC,gBAAgB,EAAE;QACzB;IACF;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,kBAAkB,EAAE;AACzB,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACd,YAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;QAClC;QACA,IAAI,CAAC,gBAAgB,EAAE;IACzB;AAEA,IAAA,WAAW,CAAC,OAAsB,EAAA;AAChC,QAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE;YACrB,IAAI,CAAC,kBAAkB,EAAE;YACzB,IAAI,CAAC,gBAAgB,EAAE;QACzB;AAEA,QAAA,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE;YACxF,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC;YACnD,IAAI,CAAC,gBAAgB,EAAE;QACzB;IACF;AAEQ,IAAA,eAAe,CAAC,KAA+C,EAAA;QACrE,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;AACxB,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,YAAA,IAAI,CAAC,OAAO,GAAG,IAAI;YACnB;QACF;QAEA,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,YAAY,IAAI,EAAE;YACnD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;AAC9C,YAAA,IAAI,IAAI,CAAC,YAAY,EAAE;gBACrB,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;YAChD;QACF;AAAO,aAAA,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE;YACnG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC;YACjD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC;AAE7C,YAAA,IAAI,IAAI,CAAC,SAAS,EAAE;gBAClB,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YAC7C;QACF;IACF;AAEQ,IAAA,cAAc,CAAC,IAAsB,EAAA;AAC3C,QAAA,IAAI,CAAC,IAAI;AAAE,YAAA,OAAO,IAAI;QACtB,MAAM,CAAC,GAAG,CAAC,IAAI,YAAY,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,IAAW,CAAC;AACnF,QAAA,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AAAE,YAAA,OAAO,IAAI;QACnC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtB,QAAA,OAAO,CAAC;IACV;IAEQ,kBAAkB,GAAA;QACxB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,EAAE,EAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM;YAC1D,KAAK,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC;AAC5E,YAAA,KAAK,EAAE,CAAC;AACT,SAAA,CAAC,CAAC;AACH,QAAA,IAAI;YACF,IAAI,CAAC,cAAc,GAAG,CAAE,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAS,CAAC,QAAQ,EAAE,QAAQ,IAAI,CAAC,IAAI,CAAC;QAC3F;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,IAAI,CAAC,cAAc,GAAG,CAAC;QACzB;AACA,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC;AACtD,QAAA,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,CAAC,EAAC,CAAC,CAAC,GAAG,CAAC,MAAK;YAC/C,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAC,OAAO,EAAE,OAAO,EAAC,CAAC;YACjF,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAC9B,YAAA,OAAO,OAAO;AAChB,QAAA,CAAC,CAAC;IACJ;IAEQ,iBAAiB,GAAA;AACvB,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAC,GAAG,EAAE,KAAK,EAAC,CAAC,CAAC,GAAG,EAAE;IAC3G;AAEO,IAAA,WAAW,CAAC,KAAmB,EAAA;AACpC,QAAA,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC;AACzB,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC;AACvB,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,EAAC,CAAC;QACjE,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;QAC3C,IAAI,CAAC,gBAAgB,EAAE;IACzB;AAEO,IAAA,cAAc,CAAC,IAAiB,EAAA;AACrC,QAAA,IAAI,CAAC,IAAI;AAAE,YAAA,OAAO,KAAK;QACvB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,IAAI;QACtD,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,IAAI;AACtD,QAAA,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;AAAE,YAAA,OAAO,IAAI;AACzC,QAAA,OAAO,KAAK;IACd;AAEO,IAAA,WAAW,CAAC,GAAgB,EAAA;QACjC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;YAAE;AACtC,QAAA,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE;AAC1B,YAAA,IAAI,CAAC,YAAY,GAAG,GAAG;YACvB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;QAC1C;aAAO;AACL,YAAA,IAAI,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE;AACvD,gBAAA,IAAI,CAAC,SAAS,GAAG,GAAG;AACpB,gBAAA,IAAI,CAAC,OAAO,GAAG,IAAI;YACrB;AAAO,iBAAA,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE;AAChC,gBAAA,IAAI,CAAC,OAAO,GAAG,GAAG;AAClB,gBAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,EAAC,CAAC;YACnE;iBAAO;AACL,gBAAA,IAAI,CAAC,SAAS,GAAG,GAAG;AACpB,gBAAA,IAAI,CAAC,OAAO,GAAG,IAAI;YACrB;AACA,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;QACzB;IACF;AAEO,IAAA,WAAW,CAAC,GAAgB,EAAA;AACjC,QAAA,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,GAAG,EAAE;AACnE,YAAA,IAAI,CAAC,WAAW,GAAG,GAAG;QACxB;IACF;AAEO,IAAA,gBAAgB,CAAC,GAAgB,EAAA;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,GAAG;AAAE,YAAA,OAAO,KAAK;QACvG,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;AACtC,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE;QAC1B,OAAO,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC;IACnE;IAEO,gBAAgB,GAAA;AACrB,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE;AACzC,QAAA,IAAI,CAAC,aAAa,GAAG,KAAK;AAC1B,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QACxB,IAAI,CAAC,uBAAuB,EAAE;QAC9B,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAChD,QAAA,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;AACnD,QAAA,MAAM,cAAc,GAAG,eAAe,CAAC,MAAM,EAAE;AAC/C,QAAA,MAAM,cAAc,GAAG,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC;AAErE,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,EAAE,CAAC,EAAE,EAAE;AACvC,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAC7B;AACA,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE;YAClD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QACtE;IACF;IAEQ,uBAAuB,GAAA;AAC7B,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,GAAG,EAAE;AACxC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,GAAG,EAAE;AACtC,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE;AACrB,QAAA,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE;AACzC,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,CAAA,EAAG,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAC,CAAC;QAClD;IACF;AAEO,IAAA,WAAW,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC;QAC9D,IAAI,CAAC,gBAAgB,EAAE;IACzB;IAEO,SAAS,CAAC,EAAe,EAAE,EAAe,EAAA;AAC/C,QAAA,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE;AAAE,YAAA,OAAO,KAAK;QAC5B,QACE,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE;AACrC,YAAA,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE;YAC/B,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE;IAEjC;AAEO,IAAA,SAAS,CAAC,CAAc,EAAA;QAC7B,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,KAAK;;QAGxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;AAE1E,QAAA,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,SAAS,IAAI,CAAC,CAAC,OAAO,EAAE,GAAG,OAAO;IACzD;AAjRW,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,yBAAyB,kBAoEhB,WAAW,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AApEpB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,aAAA,EAAA,eAAA,EAAA,UAAA,EAAA,YAAA,EAAA,KAAA,EAAA,OAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,OAAA,EAAA,OAAA,EAAA,SAAA,EAAA,OAAA,EAAA,SAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,OAAA,EAAA,EAAA,WAAA,EAAA,aAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,kBAAA,EAAA,iBAAA,EAAA,EAAA,EAAA,aAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAxP1B,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,kqGAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAzDS,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EA1CxB,qBAAqB,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;2FAmSrB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBA5PrC,SAAS;+BACE,mBAAmB,EAAA,UAAA,EACjB,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,WAAW,EAAE,qBAAqB,CAAC,EAAA,QAAA,EACjD,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,kqGAAA,CAAA,EAAA;;0BAoQY,MAAM;2BAAC,WAAW;yCAnEtB,IAAI,EAAA,CAAA;sBAAZ;gBACQ,aAAa,EAAA,CAAA;sBAArB;gBACQ,UAAU,EAAA,CAAA;sBAAlB;gBAEQ,KAAK,EAAA,CAAA;sBAAb;gBAIY,MAAM,EAAA,CAAA;sBAAlB;gBAQQ,KAAK,EAAA,CAAA;sBAAb;gBAEoC,UAAU,EAAA,CAAA;sBAA9C,WAAW;uBAAC,kBAAkB;gBAIrB,WAAW,EAAA,CAAA;sBAApB;gBAIY,OAAO,EAAA,CAAA;sBAAnB;gBAMY,OAAO,EAAA,CAAA;sBAAnB;gBAMY,MAAM,EAAA,CAAA;sBAAlB;;;AC3bH;;AAEG;;ACFH;;AAEG;;;;"}
|
|
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 Inject,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n PLATFORM_ID,\r\n SimpleChanges,\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 width: 320px;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n border: 1px solid var(--datepicker-border-color);\r\n border-radius: 10px;\r\n padding: 16px;\r\n background: var(--datepicker-background);\r\n /* overflow: hidden; */\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 }\r\n\r\n .ngxsmk-month-year-selects {\r\n display: flex;\r\n gap: 8px;\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 .ngxsmk-day-cell.start-date .ngxsmk-day-number,\r\n .ngxsmk-day-cell.end-date .ngxsmk-day-number,\r\n .ngxsmk-day-cell.selected .ngxsmk-day-number {\r\n background-color: var(--datepicker-primary-color);\r\n color: var(--datepicker-primary-contrast);\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: 10px;\r\n border-bottom-left-radius: 10px;\r\n }\r\n\r\n .ngxsmk-day-cell.end-date {\r\n border-top-right-radius: 10px;\r\n border-bottom-right-radius: 10px;\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 /** 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\r\n constructor(@Inject(PLATFORM_ID) private readonly platformId: Object) {\r\n if (isPlatformBrowser(this.platformId)) {\r\n this._locale = navigator.language;\r\n }\r\n }\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 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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"}
|
package/index.d.ts
CHANGED
|
@@ -3,17 +3,24 @@ import { EventEmitter, ElementRef, OnInit, OnChanges, SimpleChanges } from '@ang
|
|
|
3
3
|
|
|
4
4
|
declare class CustomSelectComponent {
|
|
5
5
|
private readonly elementRef;
|
|
6
|
+
/** The list of available options to display in the dropdown. */
|
|
6
7
|
options: {
|
|
7
8
|
label: string;
|
|
8
9
|
value: any;
|
|
9
10
|
}[];
|
|
11
|
+
/** The currently selected value. */
|
|
10
12
|
value: any;
|
|
13
|
+
/** Emits the new value when an option is selected. */
|
|
11
14
|
valueChange: EventEmitter<any>;
|
|
12
15
|
isOpen: boolean;
|
|
13
16
|
constructor(elementRef: ElementRef);
|
|
17
|
+
/** Closes the dropdown when a click occurs outside the component boundary. */
|
|
14
18
|
onDocumentClick(event: MouseEvent): void;
|
|
19
|
+
/** Gets the display label for the currently selected value. */
|
|
15
20
|
get displayValue(): string;
|
|
21
|
+
/** Toggles the visibility of the dropdown panel. */
|
|
16
22
|
toggleDropdown(): void;
|
|
23
|
+
/** Handles the selection of a new option. */
|
|
17
24
|
selectOption(option: {
|
|
18
25
|
label: string;
|
|
19
26
|
value: any;
|
|
@@ -31,27 +38,41 @@ interface DateRange {
|
|
|
31
38
|
}
|
|
32
39
|
declare class NgxsmkDatepickerComponent implements OnInit, OnChanges {
|
|
33
40
|
private readonly platformId;
|
|
41
|
+
/** Sets the selection mode: 'single' date or 'range' selection. */
|
|
34
42
|
mode: 'single' | 'range';
|
|
43
|
+
/** A function to programmatically disable specific dates. Returns true if the date should be disabled. */
|
|
35
44
|
isInvalidDate: (date: Date) => boolean;
|
|
45
|
+
/** If true, displays the predefined ranges panel when in 'range' mode. */
|
|
36
46
|
showRanges: boolean;
|
|
47
|
+
/** If true, displays the time selection controls (hour/minute). */
|
|
48
|
+
showTime: boolean;
|
|
49
|
+
/** Sets the minute selection step/interval (e.g., 5, 15, 30). */
|
|
50
|
+
minuteInterval: number;
|
|
51
|
+
/** The initial selected date or date range. Accepts Date, or { start: Date, end: Date }. */
|
|
37
52
|
value: Date | {
|
|
38
53
|
start: Date;
|
|
39
54
|
end: Date;
|
|
40
55
|
} | null;
|
|
41
56
|
private _locale;
|
|
57
|
+
/** Sets the locale for language and regional formatting (e.g., 'en-US', 'de-DE'). */
|
|
42
58
|
set locale(value: string);
|
|
43
59
|
get locale(): string;
|
|
60
|
+
/** Controls the visual theme: 'light' or 'dark'. */
|
|
44
61
|
theme: 'light' | 'dark';
|
|
45
62
|
get isDarkMode(): boolean;
|
|
63
|
+
/** Emits the newly selected date or date range. */
|
|
46
64
|
valueChange: EventEmitter<Date | {
|
|
47
65
|
start: Date;
|
|
48
66
|
end: Date;
|
|
49
67
|
}>;
|
|
50
68
|
private _minDate;
|
|
69
|
+
/** The earliest selectable date. */
|
|
51
70
|
set minDate(value: DateInput | null);
|
|
52
71
|
private _maxDate;
|
|
72
|
+
/** The latest selectable date. */
|
|
53
73
|
set maxDate(value: DateInput | null);
|
|
54
74
|
private _ranges;
|
|
75
|
+
/** An object of predefined date ranges for quick selection. */
|
|
55
76
|
set ranges(value: DateRange | null);
|
|
56
77
|
currentDate: Date;
|
|
57
78
|
daysInMonth: (Date | null)[];
|
|
@@ -76,6 +97,22 @@ declare class NgxsmkDatepickerComponent implements OnInit, OnChanges {
|
|
|
76
97
|
value: number;
|
|
77
98
|
}[];
|
|
78
99
|
private firstDayOfWeek;
|
|
100
|
+
currentHour: number;
|
|
101
|
+
currentMinute: number;
|
|
102
|
+
currentDisplayHour: number;
|
|
103
|
+
isPm: boolean;
|
|
104
|
+
hourOptions: {
|
|
105
|
+
label: string;
|
|
106
|
+
value: number;
|
|
107
|
+
}[];
|
|
108
|
+
minuteOptions: {
|
|
109
|
+
label: string;
|
|
110
|
+
value: number;
|
|
111
|
+
}[];
|
|
112
|
+
ampmOptions: {
|
|
113
|
+
label: string;
|
|
114
|
+
value: boolean;
|
|
115
|
+
}[];
|
|
79
116
|
constructor(platformId: Object);
|
|
80
117
|
get currentMonth(): number;
|
|
81
118
|
set currentMonth(month: number);
|
|
@@ -83,22 +120,46 @@ declare class NgxsmkDatepickerComponent implements OnInit, OnChanges {
|
|
|
83
120
|
set currentYear(year: number);
|
|
84
121
|
ngOnInit(): void;
|
|
85
122
|
ngOnChanges(changes: SimpleChanges): void;
|
|
123
|
+
/** Converts the displayed 12h time (currentDisplayHour + isPm) into the 24h internal time (currentHour). */
|
|
124
|
+
private get24Hour;
|
|
125
|
+
/** Updates the display time variables (12h format and AM/PM state) from the 24h internal time. */
|
|
126
|
+
private update12HourState;
|
|
127
|
+
/** Applies the currently selected hour and minute to a given date object. */
|
|
128
|
+
private applyCurrentTime;
|
|
129
|
+
/** Initializes selection state and time controls from the provided input value. */
|
|
86
130
|
private initializeValue;
|
|
131
|
+
/** Normalizes a date input to a Date object, keeping time information. */
|
|
87
132
|
private _normalizeDate;
|
|
133
|
+
/** Generates options for the hour and minute selectors based on the interval. */
|
|
134
|
+
private generateTimeOptions;
|
|
135
|
+
/** Generates locale-dependent month and weekday names. */
|
|
88
136
|
private generateLocaleData;
|
|
137
|
+
/** Populates the internal array of predefined ranges. */
|
|
89
138
|
private updateRangesArray;
|
|
139
|
+
/** Handles selection of a predefined date range. */
|
|
90
140
|
selectRange(range: [Date, Date]): void;
|
|
141
|
+
/** Checks if a specific date should be disabled based on minDate, maxDate, or custom function. */
|
|
91
142
|
isDateDisabled(date: Date | null): boolean;
|
|
143
|
+
/** Updates the time component of the selected date(s) when hour/minute selectors change. */
|
|
144
|
+
onTimeChange(): void;
|
|
145
|
+
/** Handles the click event on a calendar day cell. */
|
|
92
146
|
onDateClick(day: Date | null): void;
|
|
147
|
+
/** Handles hover events for range preview when only the start date is selected. */
|
|
93
148
|
onDateHover(day: Date | null): void;
|
|
149
|
+
/** Checks if a date is within the range being previewed (during hover). */
|
|
94
150
|
isPreviewInRange(day: Date | null): boolean;
|
|
151
|
+
/** Generates the calendar grid for the currently active month. */
|
|
95
152
|
generateCalendar(): void;
|
|
153
|
+
/** Generates month and year options for dropdowns. */
|
|
96
154
|
private generateDropdownOptions;
|
|
155
|
+
/** Moves the calendar view forward or backward by one month. */
|
|
97
156
|
changeMonth(delta: number): void;
|
|
157
|
+
/** Utility function to check if two dates represent the same day (ignoring time). */
|
|
98
158
|
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). */
|
|
99
160
|
isInRange(d: Date | null): boolean;
|
|
100
161
|
static ɵfac: i0.ɵɵFactoryDeclaration<NgxsmkDatepickerComponent, never>;
|
|
101
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<NgxsmkDatepickerComponent, "ngxsmk-datepicker", never, { "mode": { "alias": "mode"; "required": false; }; "isInvalidDate": { "alias": "isInvalidDate"; "required": false; }; "showRanges": { "alias": "showRanges"; "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>;
|
|
162
|
+
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>;
|
|
102
163
|
}
|
|
103
164
|
|
|
104
165
|
export { CustomSelectComponent, NgxsmkDatepickerComponent };
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngxsmk-datepicker",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/common": ">=17.0.0",
|
|
6
|
-
"@angular/core": ">=17.0.0"
|
|
6
|
+
"@angular/core": ">=17.0.0",
|
|
7
|
+
"@angular/forms": ">=17.0.0"
|
|
7
8
|
},
|
|
8
9
|
"dependencies": {
|
|
9
10
|
"tslib": "^2.3.0"
|
|
@@ -14,18 +15,6 @@
|
|
|
14
15
|
"esm2022": "fesm2022/ngxsmk-datepicker.mjs",
|
|
15
16
|
"types": "index.d.ts",
|
|
16
17
|
"typings": "index.d.ts",
|
|
17
|
-
"exports": {
|
|
18
|
-
".": {
|
|
19
|
-
"import": "./fesm2022/ngxsmk-datepicker.mjs",
|
|
20
|
-
"default": "./fesm2022/ngxsmk-datepicker.mjs",
|
|
21
|
-
"require": "./fesm2022/ngxsmk-datepicker.mjs",
|
|
22
|
-
"node": "./fesm2022/ngxsmk-datepicker.mjs",
|
|
23
|
-
"types": "./index.d.ts"
|
|
24
|
-
},
|
|
25
|
-
"./package.json": {
|
|
26
|
-
"default": "./package.json"
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
18
|
"homepage": "https://github.com/toozuuu/ngxsmk-datepicker#readme",
|
|
30
19
|
"repository": {
|
|
31
20
|
"type": "git",
|
|
@@ -52,5 +41,14 @@
|
|
|
52
41
|
"date-selection",
|
|
53
42
|
"i18n",
|
|
54
43
|
"localization"
|
|
55
|
-
]
|
|
44
|
+
],
|
|
45
|
+
"exports": {
|
|
46
|
+
"./package.json": {
|
|
47
|
+
"default": "./package.json"
|
|
48
|
+
},
|
|
49
|
+
".": {
|
|
50
|
+
"types": "./index.d.ts",
|
|
51
|
+
"default": "./fesm2022/ngxsmk-datepicker.mjs"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
56
54
|
}
|