ngxsmk-datepicker 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,419 +1,419 @@
1
- # Extension Points and Hooks
2
-
3
- **Last updated:** June 3, 2026 - **Current stable:** v2.3.1
4
-
5
- ngxsmk-datepicker provides comprehensive extension points through the `hooks` input, allowing you to customize rendering, validation, keyboard shortcuts, formatting, and event handling.
6
-
7
- > **📚 For a complete understanding of the plugin architecture, see the [Plugin Architecture Guide](./PLUGIN-ARCHITECTURE.md)** which covers architecture principles, plugin patterns, lifecycle, and advanced use cases.
8
-
9
- ## Overview
10
-
11
- The `hooks` input accepts a `DatepickerHooks` object that implements various hook interfaces:
12
-
13
- - **DayCellRenderHook**: Customize day cell rendering
14
- - **ValidationHook**: Custom validation and range rules
15
- - **KeyboardShortcutHook**: Custom keyboard shortcuts
16
- - **DateFormatHook**: Custom date formatting
17
- - **EventHook**: Event lifecycle hooks
18
-
19
- ## Basic Usage
20
-
21
- ```typescript
22
- import { Component } from '@angular/core';
23
- import { NgxsmkDatepickerComponent, DatepickerHooks } from 'ngxsmk-datepicker';
24
-
25
- @Component({
26
- selector: 'app-custom',
27
- standalone: true,
28
- imports: [NgxsmkDatepickerComponent],
29
- template: `
30
- <ngxsmk-datepicker
31
- [hooks]="myHooks"
32
- mode="single">
33
- </ngxsmk-datepicker>
34
- `
35
- })
36
- export class CustomComponent {
37
- myHooks: DatepickerHooks = {
38
- // Implement hook methods here
39
- };
40
- }
41
- ```
42
-
43
- ## Day Cell Rendering Hooks
44
-
45
- ### Custom CSS Classes
46
-
47
- Add custom CSS classes to day cells:
48
-
49
- ```typescript
50
- myHooks: DatepickerHooks = {
51
- getDayCellClasses: (date, isSelected, isDisabled, isToday, isHoliday) => {
52
- const classes: string[] = [];
53
-
54
- // Add custom class for weekends
55
- if (date.getDay() === 0 || date.getDay() === 6) {
56
- classes.push('weekend-day');
57
- }
58
-
59
- // Add custom class for first of month
60
- if (date.getDate() === 1) {
61
- classes.push('first-of-month');
62
- }
63
-
64
- return classes;
65
- }
66
- };
67
- ```
68
-
69
- ### Custom Tooltips
70
-
71
- Customize tooltip text for day cells:
72
-
73
- ```typescript
74
- myHooks: DatepickerHooks = {
75
- getDayCellTooltip: (date, holidayLabel) => {
76
- if (holidayLabel) {
77
- return `Holiday: ${holidayLabel}`;
78
- }
79
-
80
- // Add custom tooltip for specific dates
81
- if (date.getDate() === 15) {
82
- return 'Mid-month special';
83
- }
84
-
85
- return null; // Use default
86
- }
87
- };
88
- ```
89
-
90
- ### Custom Day Number Formatting
91
-
92
- Format the day number display:
93
-
94
- ```typescript
95
- myHooks: DatepickerHooks = {
96
- formatDayNumber: (date) => {
97
- // Add suffix (1st, 2nd, 3rd, etc.)
98
- const day = date.getDate();
99
- const suffix = day === 1 || day === 21 || day === 31 ? 'st' :
100
- day === 2 || day === 22 ? 'nd' :
101
- day === 3 || day === 23 ? 'rd' : 'th';
102
- return `${day}${suffix}`;
103
- }
104
- };
105
- ```
106
-
107
- ## Validation Hooks
108
-
109
- ### Custom Date Validation
110
-
111
- Add custom validation logic:
112
-
113
- ```typescript
114
- myHooks: DatepickerHooks = {
115
- validateDate: (date, currentValue, mode) => {
116
- // Prevent selecting dates in the past
117
- const today = new Date();
118
- today.setHours(0, 0, 0, 0);
119
- if (date < today) {
120
- return false;
121
- }
122
-
123
- // Prevent selecting more than 5 dates in multiple mode
124
- if (mode === 'multiple' && Array.isArray(currentValue)) {
125
- if (currentValue.length >= 5) {
126
- return false;
127
- }
128
- }
129
-
130
- return true;
131
- }
132
- };
133
- ```
134
-
135
- ### Custom Range Validation
136
-
137
- Validate date ranges:
138
-
139
- ```typescript
140
- myHooks: DatepickerHooks = {
141
- validateRange: (startDate, endDate) => {
142
- // Ensure range is at least 3 days
143
- const diffTime = endDate.getTime() - startDate.getTime();
144
- const diffDays = diffTime / (1000 * 60 * 60 * 24);
145
-
146
- if (diffDays < 3) {
147
- return false; // Range too short
148
- }
149
-
150
- // Ensure range is not more than 30 days
151
- if (diffDays > 30) {
152
- return false; // Range too long
153
- }
154
-
155
- return true;
156
- },
157
-
158
- getValidationError: (date) => {
159
- const today = new Date();
160
- today.setHours(0, 0, 0, 0);
161
- if (date < today) {
162
- return 'Cannot select past dates';
163
- }
164
- return null;
165
- }
166
- };
167
- ```
168
-
169
- ## Keyboard Shortcuts
170
-
171
- ### Custom Keyboard Shortcuts
172
-
173
- Add custom keyboard shortcuts:
174
-
175
- ```typescript
176
- myHooks: DatepickerHooks = {
177
- handleShortcut: (event, context) => {
178
- // Custom shortcut: Ctrl+1 for first day of month
179
- if (event.ctrlKey && event.key === '1') {
180
- const firstDay = new Date(context.currentDate);
181
- firstDay.setDate(1);
182
- // Navigate to first day
183
- return true; // Handled
184
- }
185
-
186
- // Custom shortcut: Ctrl+L for last day of month
187
- if (event.ctrlKey && event.key === 'l') {
188
- const lastDay = new Date(context.currentDate);
189
- lastDay.setMonth(lastDay.getMonth() + 1, 0);
190
- // Navigate to last day
191
- return true; // Handled
192
- }
193
-
194
- return false; // Not handled, use default
195
- }
196
- };
197
- ```
198
-
199
- ### Using customShortcuts Input
200
-
201
- Alternatively, use the `customShortcuts` input for simpler shortcuts:
202
-
203
- ```typescript
204
- import { KeyboardShortcutContext } from 'ngxsmk-datepicker';
205
-
206
- @Component({
207
- // ...
208
- })
209
- export class MyComponent {
210
- shortcuts = {
211
- 'Ctrl+1': (context: KeyboardShortcutContext) => {
212
- // Handle Ctrl+1
213
- return true;
214
- },
215
- 'Ctrl+L': (context: KeyboardShortcutContext) => {
216
- // Handle Ctrl+L
217
- return true;
218
- }
219
- };
220
- }
221
- ```
222
-
223
- ```html
224
- <ngxsmk-datepicker
225
- [customShortcuts]="shortcuts"
226
- mode="single">
227
- </ngxsmk-datepicker>
228
- ```
229
-
230
- ## Date Formatting Hooks
231
-
232
- ### Custom Display Value Formatting
233
-
234
- Format the input display value:
235
-
236
- ```typescript
237
- myHooks: DatepickerHooks = {
238
- formatDisplayValue: (value, mode) => {
239
- if (mode === 'single' && value instanceof Date) {
240
- // Custom format: "Monday, January 15, 2024"
241
- return value.toLocaleDateString('en-US', {
242
- weekday: 'long',
243
- year: 'numeric',
244
- month: 'long',
245
- day: 'numeric'
246
- });
247
- }
248
-
249
- if (mode === 'range' && typeof value === 'object' && 'start' in value) {
250
- const range = value as { start: Date; end: Date };
251
- return `${range.start.toLocaleDateString()} → ${range.end.toLocaleDateString()}`;
252
- }
253
-
254
- return ''; // Use default
255
- },
256
-
257
- formatAriaLabel: (date) => {
258
- // Custom aria-label format
259
- return `Select ${date.toLocaleDateString('en-US', {
260
- weekday: 'long',
261
- month: 'long',
262
- day: 'numeric',
263
- year: 'numeric'
264
- })}`;
265
- }
266
- };
267
- ```
268
-
269
- ## Event Hooks
270
-
271
- ### Lifecycle Events
272
-
273
- Hook into date selection lifecycle:
274
-
275
- ```typescript
276
- myHooks: DatepickerHooks = {
277
- beforeDateSelect: (date, currentValue) => {
278
- // Called before date is selected
279
- // Return false to prevent selection
280
- console.log('About to select:', date);
281
-
282
- // Example: Prevent selection on weekends
283
- const day = date.getDay();
284
- if (day === 0 || day === 6) {
285
- return false; // Prevent selection
286
- }
287
-
288
- return true; // Allow selection
289
- },
290
-
291
- afterDateSelect: (date, newValue) => {
292
- // Called after date is selected
293
- console.log('Date selected:', date);
294
- console.log('New value:', newValue);
295
-
296
- // Perform side effects (API calls, analytics, etc.)
297
- },
298
-
299
- onCalendarOpen: () => {
300
- console.log('Calendar opened');
301
- // Track analytics, etc.
302
- },
303
-
304
- onCalendarClose: () => {
305
- console.log('Calendar closed');
306
- // Cleanup, etc.
307
- }
308
- };
309
- ```
310
-
311
- ## Complete Example
312
-
313
- ```typescript
314
- import { Component } from '@angular/core';
315
- import { NgxsmkDatepickerComponent, DatepickerHooks } from 'ngxsmk-datepicker';
316
-
317
- @Component({
318
- selector: 'app-advanced',
319
- standalone: true,
320
- imports: [NgxsmkDatepickerComponent],
321
- template: `
322
- <ngxsmk-datepicker
323
- [hooks]="advancedHooks"
324
- [customShortcuts]="shortcuts"
325
- mode="range">
326
- </ngxsmk-datepicker>
327
- `
328
- })
329
- export class AdvancedComponent {
330
- advancedHooks: DatepickerHooks = {
331
- // Custom classes
332
- getDayCellClasses: (date, isSelected, isDisabled, isToday, isHoliday) => {
333
- const classes: string[] = [];
334
- if (date.getDay() === 0 || date.getDay() === 6) {
335
- classes.push('weekend');
336
- }
337
- return classes;
338
- },
339
-
340
- // Custom validation
341
- validateRange: (start, end) => {
342
- const days = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24);
343
- return days >= 3 && days <= 30;
344
- },
345
-
346
- // Custom formatting
347
- formatDisplayValue: (value, mode) => {
348
- if (mode === 'range' && typeof value === 'object' && 'start' in value) {
349
- const r = value as { start: Date; end: Date };
350
- return `${r.start.toLocaleDateString()} - ${r.end.toLocaleDateString()}`;
351
- }
352
- return '';
353
- },
354
-
355
- // Event hooks
356
- beforeDateSelect: (date) => {
357
- return date.getDay() !== 0 && date.getDay() !== 6; // No weekends
358
- }
359
- };
360
-
361
- shortcuts = {
362
- 'Ctrl+Home': (context) => {
363
- // Navigate to today
364
- return true;
365
- }
366
- };
367
- }
368
- ```
369
-
370
- ## Built-in Keyboard Shortcuts
371
-
372
- The datepicker includes these built-in shortcuts:
373
-
374
- | Key | Action |
375
- |-----|--------|
376
- | `←` `→` `↑` `↓` | Navigate dates |
377
- | `Page Up` | Previous month |
378
- | `Page Down` | Next month |
379
- | `Shift + Page Up` | Previous year |
380
- | `Shift + Page Down` | Next year |
381
- | `Home` | First day of month |
382
- | `End` | Last day of month |
383
- | `Enter` / `Space` | Select focused date |
384
- | `Escape` | Close calendar |
385
- | `T` | Select today |
386
- | `Y` | Select yesterday |
387
- | `N` | Select tomorrow |
388
- | `W` | Select next week |
389
-
390
- Disable shortcuts:
391
- ```html
392
- <ngxsmk-datepicker
393
- [enableKeyboardShortcuts]="false"
394
- mode="single">
395
- </ngxsmk-datepicker>
396
- ```
397
-
398
- ## Best Practices
399
-
400
- 1. **Performance**: Keep hook functions lightweight and memoize expensive operations
401
- 2. **Accessibility**: Ensure custom formatting maintains accessibility
402
- 3. **Validation**: Provide clear error messages via `getValidationError`
403
- 4. **Consistency**: Use consistent formatting across all hooks
404
- 5. **Testing**: Test hooks thoroughly, especially validation logic
405
-
406
- ## Type Safety
407
-
408
- All hooks are fully typed with TypeScript interfaces. Use the exported types for better IDE support:
409
-
410
- ```typescript
411
- import {
412
- DatepickerHooks,
413
- KeyboardShortcutContext,
414
- KeyboardShortcutHelp
415
- } from 'ngxsmk-datepicker';
416
- ```
417
-
418
-
419
-
1
+ # Extension Points and Hooks
2
+
3
+ **Last updated:** July 2, 2026 - **Current stable:** v2.4.0
4
+
5
+ ngxsmk-datepicker provides comprehensive extension points through the `hooks` input, allowing you to customize rendering, validation, keyboard shortcuts, formatting, and event handling.
6
+
7
+ > **📚 For a complete understanding of the plugin architecture, see the [Plugin Architecture Guide](./PLUGIN-ARCHITECTURE.md)** which covers architecture principles, plugin patterns, lifecycle, and advanced use cases.
8
+
9
+ ## Overview
10
+
11
+ The `hooks` input accepts a `DatepickerHooks` object that implements various hook interfaces:
12
+
13
+ - **DayCellRenderHook**: Customize day cell rendering
14
+ - **ValidationHook**: Custom validation and range rules
15
+ - **KeyboardShortcutHook**: Custom keyboard shortcuts
16
+ - **DateFormatHook**: Custom date formatting
17
+ - **EventHook**: Event lifecycle hooks
18
+
19
+ ## Basic Usage
20
+
21
+ ```typescript
22
+ import { Component } from '@angular/core';
23
+ import { NgxsmkDatepickerComponent, DatepickerHooks } from 'ngxsmk-datepicker';
24
+
25
+ @Component({
26
+ selector: 'app-custom',
27
+ standalone: true,
28
+ imports: [NgxsmkDatepickerComponent],
29
+ template: `
30
+ <ngxsmk-datepicker
31
+ [hooks]="myHooks"
32
+ mode="single">
33
+ </ngxsmk-datepicker>
34
+ `
35
+ })
36
+ export class CustomComponent {
37
+ myHooks: DatepickerHooks = {
38
+ // Implement hook methods here
39
+ };
40
+ }
41
+ ```
42
+
43
+ ## Day Cell Rendering Hooks
44
+
45
+ ### Custom CSS Classes
46
+
47
+ Add custom CSS classes to day cells:
48
+
49
+ ```typescript
50
+ myHooks: DatepickerHooks = {
51
+ getDayCellClasses: (date, isSelected, isDisabled, isToday, isHoliday) => {
52
+ const classes: string[] = [];
53
+
54
+ // Add custom class for weekends
55
+ if (date.getDay() === 0 || date.getDay() === 6) {
56
+ classes.push('weekend-day');
57
+ }
58
+
59
+ // Add custom class for first of month
60
+ if (date.getDate() === 1) {
61
+ classes.push('first-of-month');
62
+ }
63
+
64
+ return classes;
65
+ }
66
+ };
67
+ ```
68
+
69
+ ### Custom Tooltips
70
+
71
+ Customize tooltip text for day cells:
72
+
73
+ ```typescript
74
+ myHooks: DatepickerHooks = {
75
+ getDayCellTooltip: (date, holidayLabel) => {
76
+ if (holidayLabel) {
77
+ return `Holiday: ${holidayLabel}`;
78
+ }
79
+
80
+ // Add custom tooltip for specific dates
81
+ if (date.getDate() === 15) {
82
+ return 'Mid-month special';
83
+ }
84
+
85
+ return null; // Use default
86
+ }
87
+ };
88
+ ```
89
+
90
+ ### Custom Day Number Formatting
91
+
92
+ Format the day number display:
93
+
94
+ ```typescript
95
+ myHooks: DatepickerHooks = {
96
+ formatDayNumber: (date) => {
97
+ // Add suffix (1st, 2nd, 3rd, etc.)
98
+ const day = date.getDate();
99
+ const suffix = day === 1 || day === 21 || day === 31 ? 'st' :
100
+ day === 2 || day === 22 ? 'nd' :
101
+ day === 3 || day === 23 ? 'rd' : 'th';
102
+ return `${day}${suffix}`;
103
+ }
104
+ };
105
+ ```
106
+
107
+ ## Validation Hooks
108
+
109
+ ### Custom Date Validation
110
+
111
+ Add custom validation logic:
112
+
113
+ ```typescript
114
+ myHooks: DatepickerHooks = {
115
+ validateDate: (date, currentValue, mode) => {
116
+ // Prevent selecting dates in the past
117
+ const today = new Date();
118
+ today.setHours(0, 0, 0, 0);
119
+ if (date < today) {
120
+ return false;
121
+ }
122
+
123
+ // Prevent selecting more than 5 dates in multiple mode
124
+ if (mode === 'multiple' && Array.isArray(currentValue)) {
125
+ if (currentValue.length >= 5) {
126
+ return false;
127
+ }
128
+ }
129
+
130
+ return true;
131
+ }
132
+ };
133
+ ```
134
+
135
+ ### Custom Range Validation
136
+
137
+ Validate date ranges:
138
+
139
+ ```typescript
140
+ myHooks: DatepickerHooks = {
141
+ validateRange: (startDate, endDate) => {
142
+ // Ensure range is at least 3 days
143
+ const diffTime = endDate.getTime() - startDate.getTime();
144
+ const diffDays = diffTime / (1000 * 60 * 60 * 24);
145
+
146
+ if (diffDays < 3) {
147
+ return false; // Range too short
148
+ }
149
+
150
+ // Ensure range is not more than 30 days
151
+ if (diffDays > 30) {
152
+ return false; // Range too long
153
+ }
154
+
155
+ return true;
156
+ },
157
+
158
+ getValidationError: (date) => {
159
+ const today = new Date();
160
+ today.setHours(0, 0, 0, 0);
161
+ if (date < today) {
162
+ return 'Cannot select past dates';
163
+ }
164
+ return null;
165
+ }
166
+ };
167
+ ```
168
+
169
+ ## Keyboard Shortcuts
170
+
171
+ ### Custom Keyboard Shortcuts
172
+
173
+ Add custom keyboard shortcuts:
174
+
175
+ ```typescript
176
+ myHooks: DatepickerHooks = {
177
+ handleShortcut: (event, context) => {
178
+ // Custom shortcut: Ctrl+1 for first day of month
179
+ if (event.ctrlKey && event.key === '1') {
180
+ const firstDay = new Date(context.currentDate);
181
+ firstDay.setDate(1);
182
+ // Navigate to first day
183
+ return true; // Handled
184
+ }
185
+
186
+ // Custom shortcut: Ctrl+L for last day of month
187
+ if (event.ctrlKey && event.key === 'l') {
188
+ const lastDay = new Date(context.currentDate);
189
+ lastDay.setMonth(lastDay.getMonth() + 1, 0);
190
+ // Navigate to last day
191
+ return true; // Handled
192
+ }
193
+
194
+ return false; // Not handled, use default
195
+ }
196
+ };
197
+ ```
198
+
199
+ ### Using customShortcuts Input
200
+
201
+ Alternatively, use the `customShortcuts` input for simpler shortcuts:
202
+
203
+ ```typescript
204
+ import { KeyboardShortcutContext } from 'ngxsmk-datepicker';
205
+
206
+ @Component({
207
+ // ...
208
+ })
209
+ export class MyComponent {
210
+ shortcuts = {
211
+ 'Ctrl+1': (context: KeyboardShortcutContext) => {
212
+ // Handle Ctrl+1
213
+ return true;
214
+ },
215
+ 'Ctrl+L': (context: KeyboardShortcutContext) => {
216
+ // Handle Ctrl+L
217
+ return true;
218
+ }
219
+ };
220
+ }
221
+ ```
222
+
223
+ ```html
224
+ <ngxsmk-datepicker
225
+ [customShortcuts]="shortcuts"
226
+ mode="single">
227
+ </ngxsmk-datepicker>
228
+ ```
229
+
230
+ ## Date Formatting Hooks
231
+
232
+ ### Custom Display Value Formatting
233
+
234
+ Format the input display value:
235
+
236
+ ```typescript
237
+ myHooks: DatepickerHooks = {
238
+ formatDisplayValue: (value, mode) => {
239
+ if (mode === 'single' && value instanceof Date) {
240
+ // Custom format: "Monday, January 15, 2024"
241
+ return value.toLocaleDateString('en-US', {
242
+ weekday: 'long',
243
+ year: 'numeric',
244
+ month: 'long',
245
+ day: 'numeric'
246
+ });
247
+ }
248
+
249
+ if (mode === 'range' && typeof value === 'object' && 'start' in value) {
250
+ const range = value as { start: Date; end: Date };
251
+ return `${range.start.toLocaleDateString()} → ${range.end.toLocaleDateString()}`;
252
+ }
253
+
254
+ return ''; // Use default
255
+ },
256
+
257
+ formatAriaLabel: (date) => {
258
+ // Custom aria-label format
259
+ return `Select ${date.toLocaleDateString('en-US', {
260
+ weekday: 'long',
261
+ month: 'long',
262
+ day: 'numeric',
263
+ year: 'numeric'
264
+ })}`;
265
+ }
266
+ };
267
+ ```
268
+
269
+ ## Event Hooks
270
+
271
+ ### Lifecycle Events
272
+
273
+ Hook into date selection lifecycle:
274
+
275
+ ```typescript
276
+ myHooks: DatepickerHooks = {
277
+ beforeDateSelect: (date, currentValue) => {
278
+ // Called before date is selected
279
+ // Return false to prevent selection
280
+ console.log('About to select:', date);
281
+
282
+ // Example: Prevent selection on weekends
283
+ const day = date.getDay();
284
+ if (day === 0 || day === 6) {
285
+ return false; // Prevent selection
286
+ }
287
+
288
+ return true; // Allow selection
289
+ },
290
+
291
+ afterDateSelect: (date, newValue) => {
292
+ // Called after date is selected
293
+ console.log('Date selected:', date);
294
+ console.log('New value:', newValue);
295
+
296
+ // Perform side effects (API calls, analytics, etc.)
297
+ },
298
+
299
+ onCalendarOpen: () => {
300
+ console.log('Calendar opened');
301
+ // Track analytics, etc.
302
+ },
303
+
304
+ onCalendarClose: () => {
305
+ console.log('Calendar closed');
306
+ // Cleanup, etc.
307
+ }
308
+ };
309
+ ```
310
+
311
+ ## Complete Example
312
+
313
+ ```typescript
314
+ import { Component } from '@angular/core';
315
+ import { NgxsmkDatepickerComponent, DatepickerHooks } from 'ngxsmk-datepicker';
316
+
317
+ @Component({
318
+ selector: 'app-advanced',
319
+ standalone: true,
320
+ imports: [NgxsmkDatepickerComponent],
321
+ template: `
322
+ <ngxsmk-datepicker
323
+ [hooks]="advancedHooks"
324
+ [customShortcuts]="shortcuts"
325
+ mode="range">
326
+ </ngxsmk-datepicker>
327
+ `
328
+ })
329
+ export class AdvancedComponent {
330
+ advancedHooks: DatepickerHooks = {
331
+ // Custom classes
332
+ getDayCellClasses: (date, isSelected, isDisabled, isToday, isHoliday) => {
333
+ const classes: string[] = [];
334
+ if (date.getDay() === 0 || date.getDay() === 6) {
335
+ classes.push('weekend');
336
+ }
337
+ return classes;
338
+ },
339
+
340
+ // Custom validation
341
+ validateRange: (start, end) => {
342
+ const days = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24);
343
+ return days >= 3 && days <= 30;
344
+ },
345
+
346
+ // Custom formatting
347
+ formatDisplayValue: (value, mode) => {
348
+ if (mode === 'range' && typeof value === 'object' && 'start' in value) {
349
+ const r = value as { start: Date; end: Date };
350
+ return `${r.start.toLocaleDateString()} - ${r.end.toLocaleDateString()}`;
351
+ }
352
+ return '';
353
+ },
354
+
355
+ // Event hooks
356
+ beforeDateSelect: (date) => {
357
+ return date.getDay() !== 0 && date.getDay() !== 6; // No weekends
358
+ }
359
+ };
360
+
361
+ shortcuts = {
362
+ 'Ctrl+Home': (context) => {
363
+ // Navigate to today
364
+ return true;
365
+ }
366
+ };
367
+ }
368
+ ```
369
+
370
+ ## Built-in Keyboard Shortcuts
371
+
372
+ The datepicker includes these built-in shortcuts:
373
+
374
+ | Key | Action |
375
+ |-----|--------|
376
+ | `←` `→` `↑` `↓` | Navigate dates |
377
+ | `Page Up` | Previous month |
378
+ | `Page Down` | Next month |
379
+ | `Shift + Page Up` | Previous year |
380
+ | `Shift + Page Down` | Next year |
381
+ | `Home` | First day of month |
382
+ | `End` | Last day of month |
383
+ | `Enter` / `Space` | Select focused date |
384
+ | `Escape` | Close calendar |
385
+ | `T` | Select today |
386
+ | `Y` | Select yesterday |
387
+ | `N` | Select tomorrow |
388
+ | `W` | Select next week |
389
+
390
+ Disable shortcuts:
391
+ ```html
392
+ <ngxsmk-datepicker
393
+ [enableKeyboardShortcuts]="false"
394
+ mode="single">
395
+ </ngxsmk-datepicker>
396
+ ```
397
+
398
+ ## Best Practices
399
+
400
+ 1. **Performance**: Keep hook functions lightweight and memoize expensive operations
401
+ 2. **Accessibility**: Ensure custom formatting maintains accessibility
402
+ 3. **Validation**: Provide clear error messages via `getValidationError`
403
+ 4. **Consistency**: Use consistent formatting across all hooks
404
+ 5. **Testing**: Test hooks thoroughly, especially validation logic
405
+
406
+ ## Type Safety
407
+
408
+ All hooks are fully typed with TypeScript interfaces. Use the exported types for better IDE support:
409
+
410
+ ```typescript
411
+ import {
412
+ DatepickerHooks,
413
+ KeyboardShortcutContext,
414
+ KeyboardShortcutHelp
415
+ } from 'ngxsmk-datepicker';
416
+ ```
417
+
418
+
419
+