quang 20.1.9 → 20.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,54 +1,512 @@
1
1
  # QuangDateComponent
2
2
 
3
- The `QuangDateComponent` is based on Air Datepicker. It can be fully customized using the input property `datepickerOptions`.
3
+ The `QuangDateComponent` is a comprehensive date and time picker based on [Air Datepicker](https://air-datepicker.com/docs). It provides full customization capabilities, internationalization support, and various display modes including inline calendars and time-only pickers.
4
4
 
5
- ## Features
6
- - Fully customizable datepicker
7
- - Based on Air Datepicker
8
- - Supports date ranges and localization
5
+ ## Supported Features
6
+
7
+ ### Date Selection Modes
8
+ - **Single Date**: Select a single date
9
+ - **Date Range**: Select start and end dates with range highlighting
10
+ - **Inline Calendar**: Display calendar directly in the page without popup
11
+ - **Time Only**: Show only time picker without date selection
12
+
13
+ ### Input Formats
14
+ - **Custom Date Formats**: Configurable display formats using Unicode date patterns
15
+ - **Time Formats**: Separate time format configuration
16
+ - **Invalid Date Handling**: Custom messages for invalid date inputs
17
+ - **Search Input**: Live search with debouncing for date input
18
+
19
+ ### Internationalization
20
+ - **Multi-language Support**: Integrated with QuangTranslationService
21
+ - **Locale Override**: Manual locale setting capability
22
+ - **Browser Language Fallback**: Automatic language detection
23
+
24
+ ### Customization
25
+ - **Icon Support**: Custom calendar icons through content projection
26
+ - **CSS Styling**: Custom classes for calendar and button elements
27
+ - **Position Control**: Configurable popup positioning
28
+ - **Air Datepicker Integration**: Full access to Air Datepicker options
9
29
 
10
30
  ## Inputs
11
31
 
12
- - `datepickerOptions`: `object` — Configuration options for the datepicker. **(Required)**
13
- - `minDate`: `Date | string` — Minimum selectable date.
14
- - `maxDate`: `Date | string` — Maximum selectable date.
15
- - All standard form/label/validation-related inputs inherited from `QuangBaseComponent`:
16
- - `isReadonly`, `componentLabel`, `componentPlaceholder`, `componentTabIndex`, `componentClass`, `errorMap`, `successMessage`, `helpMessage`, `formControl`
32
+ - `datepickerOptions`: `QuangDatepickerOptions | undefined` — Full Air Datepicker configuration object for advanced customization. **Overrides component defaults**
33
+
34
+ - `dateFormat`: `string` — Display format for dates using [Unicode date patterns](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table). Default: `'dd/MM/yyyy'`
35
+ - `timeFormat`: `string` Display format for time using Unicode patterns. Default: `'HH:mm'`
36
+ - `invalidDateMessage`: `string` Message shown when user enters invalid date format
37
+
38
+ - `minDate`: `Date | undefined` — Earliest selectable date
39
+ - `maxDate`: `Date | undefined` — Latest selectable date
40
+ - `minHour`: `number` — Minimum selectable hour (0-23). Default: `0`
41
+ - `maxHour`: `number` — Maximum selectable hour (0-24). Default: `24`
42
+ - `minMinute`: `number` — Minimum selectable minute (0-59). Default: `0`
43
+ - `maxMinute`: `number` — Maximum selectable minute (0-59). Default: `59`
44
+
45
+ - `timepicker`: `boolean` — Enable time selection alongside date. Default: `false`
46
+ - `showOnlyTimepicker`: `boolean` — Show only time picker without date selection. Default: `false`
47
+ - `showInline`: `boolean` — Display calendar inline instead of popup. Default: `false`
48
+ - `rangeSelection`: `boolean` — Enable date range selection mode. Default: `false`
49
+
50
+ - `activeLanguageOverride`: `string | undefined` — Override automatic language detection with specific locale code
51
+
52
+ - `multipleDatesSeparator`: `string` — Separator for displaying date ranges. Default: `' - '`
53
+
54
+ - `calendarClasses`: `string` — Additional CSS classes for the calendar popup
55
+ - `buttonClass`: `string` — Additional CSS classes for the calendar toggle button
56
+
57
+ - `searchTextDebounce`: `number` — Debounce time in milliseconds for search input. Default: `500`
58
+
59
+ All standard inputs inherited from `QuangBaseComponent`:
60
+ - `isReadonly`: `boolean` — Makes the input read-only
61
+ - `componentLabel`: `string` — Label text (supports i18n keys)
62
+ - `componentPlaceholder`: `string` — Placeholder text (supports i18n keys)
63
+ - `componentTabIndex`: `number` — Tab index for accessibility
64
+ - `componentClass`: `string` — Additional CSS classes for the input element
65
+ - `errorMap`: `Record<string, any>` — Validation error messages
66
+ - `successMessage`: `string` — Success message text
67
+ - `helpMessage`: `string` — Help text displayed below the input
68
+ - `formControl`: `FormControl` — Angular reactive form control
17
69
 
18
70
  ## Outputs
19
71
 
20
- - `dateChange`: Emits the selected date when it changes.
72
+ - `dateChange`: `EventEmitter<Date | DateRange | null>` — Emitted when the selected date/range changes
73
+ - Single date mode: Emits `Date | null`
74
+ - Range mode: Emits `DateRange | null` with `{ dateFrom: string | null, dateTo: string | null }`
21
75
  - All standard outputs inherited from `QuangBaseComponent`:
22
- - `componentBlur`
76
+ - `componentBlur`: `EventEmitter<void>` — Emitted when input loses focus
23
77
 
24
78
  ## Usage
79
+
80
+ ### Basic Date Picker
25
81
  ```html
26
82
  <quang-date
83
+ [errorMap]="errors()"
84
+ componentLabel="form.label.birthdate"
85
+ formControlName="birthdate"
86
+ >
87
+ <svg-icon src="assets/icons/svg/calendar.svg" />
88
+ </quang-date>
89
+ ```
90
+
91
+ ### Date Picker with Time Selection
92
+ ```html
93
+ <quang-date
94
+ [errorMap]="errors()"
95
+ [timepicker]="true"
27
96
  [minDate]="minDate"
28
97
  [maxDate]="maxDate"
98
+ componentLabel="form.label.appointment"
99
+ dateFormat="dd/MM/yyyy"
100
+ timeFormat="HH:mm"
101
+ formControlName="appointmentDateTime"
102
+ >
103
+ <img src="assets/icons/svg/calendar.svg" alt="Calendar" />
104
+ </quang-date>
105
+ ```
106
+
107
+ ### Date Range Selection
108
+ ```html
109
+ <quang-date
29
110
  [errorMap]="errors()"
30
- [formControl]="testForm.controls.testInput"
31
- [isReadonly]="isReadonly()"
111
+ [rangeSelection]="true"
112
+ [minDate]="startDate"
113
+ [maxDate]="endDate"
114
+ componentLabel="form.label.dateRange"
115
+ multipleDatesSeparator=" to "
116
+ formControlName="dateRange"
117
+ >
118
+ <i class="fas fa-calendar-alt"></i>
119
+ </quang-date>
120
+ ```
121
+
122
+ ### Time-Only Picker
123
+ ```html
124
+ <quang-date
125
+ [errorMap]="errors()"
126
+ [showOnlyTimepicker]="true"
127
+ [minHour]="9"
128
+ [maxHour]="17"
129
+ [minMinute]="0"
130
+ [maxMinute]="59"
131
+ componentLabel="form.label.meetingTime"
132
+ timeFormat="HH:mm"
133
+ formControlName="meetingTime"
134
+ >
135
+ <svg-icon src="assets/icons/svg/clock.svg" />
136
+ </quang-date>
137
+ ```
138
+
139
+ ### Inline Calendar
140
+ ```html
141
+ <quang-date
142
+ [errorMap]="errors()"
143
+ [showInline]="true"
32
144
  [timepicker]="true"
33
- class="col-6"
145
+ componentLabel="form.label.eventDate"
146
+ formControlName="eventDate"
147
+ calendarClasses="custom-calendar-style"
148
+ />
149
+ ```
150
+
151
+ ### Custom Date Format and Validation
152
+ ```html
153
+ <quang-date
154
+ [errorMap]="errors()"
155
+ [minDate]="minAllowedDate"
156
+ [maxDate]="maxAllowedDate"
157
+ dateFormat="yyyy-MM-dd"
158
+ invalidDateMessage="Please enter a valid date in YYYY-MM-DD format"
159
+ componentLabel="form.label.deadline"
160
+ componentPlaceholder="YYYY-MM-DD"
161
+ formControlName="deadline"
162
+ >
163
+ <svg-icon src="assets/icons/svg/calendar.svg" />
164
+ </quang-date>
165
+ ```
166
+
167
+ ### Advanced Configuration with Air Datepicker Options
168
+ ```html
169
+ <quang-date
170
+ [errorMap]="errors()"
171
+ [datepickerOptions]="customDatepickerOptions"
172
+ componentLabel="form.label.advancedDate"
173
+ formControlName="advancedDate"
174
+ >
175
+ <svg-icon src="assets/icons/svg/calendar.svg" />
176
+ </quang-date>
177
+ ```
178
+
179
+ #### TypeScript Configuration Example
180
+ ```typescript
181
+ customDatepickerOptions: QuangDatepickerOptions = {
182
+ view: 'months',
183
+ minView: 'months',
184
+ dateFormat: 'MM/yyyy',
185
+ autoClose: true,
186
+ position: 'top center',
187
+ offset: 10,
188
+ showOtherMonths: false,
189
+ selectOtherMonths: false,
190
+ moveToOtherMonthsOnSelect: false
191
+ };
192
+ ```
193
+
194
+ ### Localization Example
195
+ ```html
196
+ <!-- Use specific locale -->
197
+ <quang-date
198
+ [errorMap]="errors()"
199
+ activeLanguageOverride="it"
200
+ componentLabel="form.label.dataCompleanno"
201
+ formControlName="dataCompleanno"
202
+ >
203
+ <svg-icon src="assets/icons/svg/calendar.svg" />
204
+ </quang-date>
205
+
206
+ <!-- Use QuangTranslationService automatic detection -->
207
+ <quang-date
208
+ [errorMap]="errors()"
34
209
  componentLabel="form.label.date"
35
- successMessage="form.label.success"
210
+ formControlName="date"
36
211
  >
37
- <img src="./assets/icons/svg/calendar.svg" />
212
+ <svg-icon src="assets/icons/svg/calendar.svg" />
38
213
  </quang-date>
39
214
  ```
40
215
 
41
- ### Note
42
- Remember to add the import:
216
+ ## Installation & Setup
217
+
218
+ ### Required Styles
219
+ Add the global date component styles to your application:
220
+
221
+ **Option 1: In angular.json**
222
+ ```json
223
+ "styles": [
224
+ "node_modules/quang/components/date/global-date.component.scss"
225
+ ]
226
+ ```
227
+
228
+ **Option 2: In your global styles file**
229
+ ```scss
230
+ @import 'quang/components/date/global-date.component.scss';
231
+ ```
232
+
233
+ **Option 3: In vendors folder (recommended)**
234
+ ```scss
235
+ // src/sass/vendors/_date-component.scss
236
+ @import 'node_modules/quang/components/date/global-date.component.scss';
237
+ ```
238
+
239
+ ### Air Datepicker Integration
240
+ The component automatically handles Air Datepicker setup and configuration. Supported locales include:
241
+ - English (en) - Default
242
+ - Italian (it)
243
+ - French (fr)
244
+ - Auto-detection based on browser/QuangTranslationService
245
+
246
+ ## Component Behavior
247
+
248
+ ### Date Format Patterns
249
+ Uses [Unicode Date Field Symbol Table](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table):
250
+
251
+ | Pattern | Description | Example |
252
+ |---------|-------------|---------|
253
+ | `dd/MM/yyyy` | Day/Month/Year | 25/12/2023 |
254
+ | `MM/dd/yyyy` | Month/Day/Year | 12/25/2023 |
255
+ | `yyyy-MM-dd` | ISO Date | 2023-12-25 |
256
+ | `dd MMM yyyy` | Day Month Year | 25 Dec 2023 |
257
+ | `EEEE, dd MMMM yyyy` | Full Date | Monday, 25 December 2023 |
258
+
259
+ ### Time Format Patterns
260
+ | Pattern | Description | Example |
261
+ |---------|-------------|---------|
262
+ | `HH:mm` | 24-hour format | 14:30 |
263
+ | `hh:mm a` | 12-hour format | 02:30 PM |
264
+ | `HH:mm:ss` | With seconds | 14:30:45 |
265
+
266
+ ### Display Modes
267
+
268
+ #### Single Date Mode (Default)
269
+ - Returns: `Date | null`
270
+ - User selects one date
271
+ - Input shows formatted date string
272
+
273
+ #### Range Selection Mode
274
+ - Returns: `DateRange | null` = `{ dateFrom: string | null, dateTo: string | null }`
275
+ - User selects start and end dates
276
+ - Input shows both dates with separator
277
+ - Visual range highlighting in calendar
278
+
279
+ #### Time-Only Mode
280
+ - Returns: `string` in specified time format
281
+ - No date selection available
282
+ - Only time picker controls visible
283
+
284
+ #### Inline Mode
285
+ - Calendar always visible
286
+ - No popup behavior
287
+ - Useful for dashboard widgets or dedicated date selection areas
288
+
289
+ ### Validation Integration
290
+
291
+ #### Built-in Validation
292
+ - **Date Range**: Automatic validation against `minDate`/`maxDate`
293
+ - **Time Range**: Validation against `minHour`/`maxHour`, `minMinute`/`maxMinute`
294
+ - **Format Validation**: Invalid date format detection with custom messages
295
+
296
+ #### Custom Validation
297
+ ```typescript
298
+ // Custom validator example
299
+ dateValidator(control: AbstractControl): ValidationErrors | null {
300
+ const value = control.value;
301
+ if (!value) return null;
302
+
303
+ const selectedDate = new Date(value);
304
+ const today = new Date();
305
+
306
+ if (selectedDate < today) {
307
+ return { pastDate: { message: 'Date cannot be in the past' } };
308
+ }
309
+
310
+ return null;
311
+ }
312
+ ```
313
+
314
+ ### Accessibility Features
315
+
316
+ #### Keyboard Navigation
317
+ - **Tab**: Navigate to/from date input
318
+ - **Enter/Space**: Open calendar when focused on button
319
+ - **Arrow Keys**: Navigate calendar dates
320
+ - **Escape**: Close calendar popup
321
+
322
+ #### Screen Reader Support
323
+ - **ARIA Labels**: Calendar button properly labeled
324
+ - **Date Announcements**: Selected dates announced
325
+ - **Error Messages**: Validation errors announced
326
+ - **Help Text**: Additional guidance provided
43
327
 
44
- `node_modules/quang/components/date/global-date.component.scss`
328
+ #### Focus Management
329
+ - **Focus Trapping**: Keyboard focus contained within open calendar
330
+ - **Focus Return**: Focus returns to trigger element when calendar closes
331
+ - **Visual Indicators**: Clear focus styling
45
332
 
46
- or
333
+ ### Performance Considerations
47
334
 
48
- `quang/components/date/global-date.component.scss`
335
+ #### Debouncing
336
+ - **Search Input**: Configurable debounce for typed date input
337
+ - **Validation**: Debounced validation to prevent excessive API calls
338
+ - **Change Detection**: OnPush strategy for optimal performance
49
339
 
50
- in your global style (suggested "vendors" folder).
340
+ #### Memory Management
341
+ - **Air Datepicker Cleanup**: Automatic instance destruction
342
+ - **Event Listeners**: Proper cleanup on component destruction
343
+ - **Subscription Management**: RxJS subscriptions properly handled
344
+
345
+ ## Best Practices
346
+
347
+ ### Date Format Selection
348
+ - **Use consistent formats**: Stick to one format throughout your application
349
+ - **Consider locale**: Match user's expected date format for their region
350
+ - **ISO format**: Use `yyyy-MM-dd` for data storage and API communication
351
+ - **User-friendly display**: Use localized formats like `dd/MM/yyyy` for UI
352
+
353
+ ### Range Selection Guidelines
354
+ - **Clear separators**: Use intuitive separators like " to " or " - "
355
+ - **Validation**: Always validate that end date is after start date
356
+ - **User feedback**: Provide clear visual indication of selected range
357
+ - **Default behavior**: Consider setting reasonable default ranges
358
+
359
+ ### Time Picker Configuration
360
+ - **Business hours**: Use `minHour`/`maxHour` to limit to relevant times
361
+ - **Step intervals**: Configure minute steps for appointment scheduling
362
+ - **Format consistency**: Match time format with user expectations
363
+
364
+ ### Internationalization
365
+ - **Automatic detection**: Let QuangTranslationService handle locale automatically
366
+ - **Override sparingly**: Only use `activeLanguageOverride` for specific cases
367
+ - **Test multiple locales**: Verify date formats work across all supported languages
368
+
369
+ ### Performance Optimization
370
+ - **Debouncing**: Increase `searchTextDebounce` for slower networks
371
+ - **Inline calendars**: Use sparingly as they're always rendered
372
+ - **Air Datepicker options**: Avoid complex configurations that impact performance
373
+
374
+ ## Troubleshooting
375
+
376
+ ### Common Issues
377
+
378
+ #### Calendar not showing
379
+ - **Check styles**: Ensure global styles are imported
380
+ - **Z-index conflicts**: Calendar popup may be behind other elements
381
+ - **Container overflow**: Parent containers may clip calendar popup
382
+ - **Content projection**: Verify icon/content is projected correctly
383
+
384
+ #### Date format issues
385
+ - **Invalid patterns**: Check Unicode date pattern syntax
386
+ - **Locale mismatch**: Format patterns may not match selected locale
387
+ - **Parsing errors**: Ensure `invalidDateMessage` provides clear guidance
388
+
389
+ #### Validation problems
390
+ - **Min/max dates**: Verify date constraints are properly set
391
+ - **Time constraints**: Check hour/minute ranges are logical
392
+ - **Custom validators**: Ensure proper integration with Angular forms
393
+
394
+ #### Localization not working
395
+ - **QuangTranslationService**: Check service is properly configured
396
+ - **Language fallback**: Browser language detection may fail
397
+ - **Manual override**: Use `activeLanguageOverride` as fallback
398
+
399
+ ### Performance Issues
400
+
401
+ #### Slow calendar opening
402
+ - **Reduce options complexity**: Simplify `datepickerOptions`
403
+ - **Debounce optimization**: Adjust `searchTextDebounce` value
404
+ - **Check for memory leaks**: Ensure proper component cleanup
405
+
406
+ #### Memory usage
407
+ - **Air Datepicker instances**: Component handles cleanup automatically
408
+ - **Event listeners**: Should be cleaned up on destroy
409
+ - **Large date ranges**: Consider pagination for extensive date selections
410
+
411
+ ### Styling Problems
412
+
413
+ #### Button styling
414
+ - **Use `buttonClass`**: Add custom classes via input
415
+ - **Bootstrap conflicts**: Check for conflicting CSS rules
416
+ - **Responsive design**: Test on different screen sizes
417
+
418
+ #### Calendar appearance
419
+ - **Global styles**: Ensure proper SCSS import
420
+ - **Custom themes**: Use `calendarClasses` for theming
421
+ - **Mobile responsiveness**: Test calendar popup on mobile devices
422
+
423
+ ### Integration Issues
424
+
425
+ #### Form validation
426
+ - **Error messages**: Use `errorMap` for custom validation messages
427
+ - **Success states**: Configure `successMessage` for positive feedback
428
+ - **Help text**: Use `helpMessage` for user guidance
429
+
430
+ #### API integration
431
+ - **Date serialization**: Use consistent format for API calls
432
+ - **Time zones**: Handle time zone conversion properly
433
+ - **Range queries**: Format date ranges correctly for backend
434
+
435
+ #### Third-party conflicts
436
+ - **CSS frameworks**: Check for styling conflicts
437
+ - **Date libraries**: Avoid conflicts with other date manipulation libraries
438
+ - **Event handling**: Ensure proper event propagation
439
+
440
+ ## Advanced Configuration
441
+
442
+ ### Custom Air Datepicker Options
443
+ ```typescript
444
+ // Advanced configuration example
445
+ advancedOptions: QuangDatepickerOptions = {
446
+ view: 'years',
447
+ minView: 'months',
448
+ maxView: 'years',
449
+ startDate: new Date(),
450
+ firstDay: 1, // Monday as first day
451
+ weekends: [6, 0], // Saturday, Sunday
452
+ dateFormat: 'dd/MM/yyyy',
453
+ altField: true,
454
+ altFieldDateFormat: 'yyyy-MM-dd',
455
+ showOtherMonths: true,
456
+ selectOtherMonths: true,
457
+ moveToOtherMonthsOnSelect: true,
458
+ showOtherYears: true,
459
+ selectOtherYears: true,
460
+ moveToOtherYearsOnSelect: true,
461
+ minDate: new Date(),
462
+ maxDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // +1 year
463
+ disabledDates: [new Date('2023-12-25')], // Christmas
464
+ position: 'bottom center',
465
+ offset: 12,
466
+ autoClose: true,
467
+ toggleSelected: false
468
+ };
469
+ ```
470
+
471
+ ### Custom Styling
472
+ ```scss
473
+ // Custom calendar styling
474
+ .custom-calendar-style {
475
+ .air-datepicker {
476
+ border: 2px solid #007bff;
477
+ border-radius: 8px;
478
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
479
+
480
+ .air-datepicker-cell.-selected- {
481
+ background: linear-gradient(45deg, #007bff, #0056b3);
482
+ color: white;
483
+ }
484
+
485
+ .air-datepicker-cell.-in-range- {
486
+ background-color: rgba(0, 123, 255, 0.1);
487
+ }
488
+ }
489
+ }
490
+ ```
51
491
 
52
492
  ## Notes
53
493
 
54
494
  This component extends the `QuangBaseComponent` and inherits its features, such as label, error messages, and success messages.
495
+
496
+ ### Air Datepicker Integration
497
+ - **Full API Access**: Use `datepickerOptions` for complete Air Datepicker configuration
498
+ - **Event Handling**: Component manages `onSelect` and `onHide` events automatically
499
+ - **Localization**: Automatic locale configuration with fallback options
500
+ - **Instance Management**: Air Datepicker instances are properly created and destroyed
501
+
502
+ ### Form Integration
503
+ - **Reactive Forms**: Full support for Angular reactive forms
504
+ - **Template-driven Forms**: Compatible with template-driven forms
505
+ - **Validation**: Integrates with Angular validation system
506
+ - **Change Detection**: Optimized with OnPush strategy
507
+
508
+ ### QuangTranslationService Integration
509
+ - **Automatic Language**: Uses active language from translation service
510
+ - **Label Translation**: All labels support i18n keys
511
+ - **Message Translation**: Error and help messages support translation
512
+ - **Locale Matching**: Matches translation service locale with calendar locale