@anglr/datetime 9.0.2 → 9.0.3-beta.20260518114213

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.
Files changed (48) hide show
  1. package/.claude/skills/angular-developer/SKILL.md +130 -0
  2. package/.claude/skills/angular-developer/references/angular-animations.md +160 -0
  3. package/.claude/skills/angular-developer/references/angular-aria.md +410 -0
  4. package/.claude/skills/angular-developer/references/cli.md +86 -0
  5. package/.claude/skills/angular-developer/references/component-harnesses.md +59 -0
  6. package/.claude/skills/angular-developer/references/component-styling.md +91 -0
  7. package/.claude/skills/angular-developer/references/components.md +117 -0
  8. package/.claude/skills/angular-developer/references/creating-services.md +97 -0
  9. package/.claude/skills/angular-developer/references/data-resolvers.md +69 -0
  10. package/.claude/skills/angular-developer/references/define-routes.md +67 -0
  11. package/.claude/skills/angular-developer/references/defining-providers.md +72 -0
  12. package/.claude/skills/angular-developer/references/di-fundamentals.md +120 -0
  13. package/.claude/skills/angular-developer/references/e2e-testing.md +66 -0
  14. package/.claude/skills/angular-developer/references/effects.md +83 -0
  15. package/.claude/skills/angular-developer/references/hierarchical-injectors.md +43 -0
  16. package/.claude/skills/angular-developer/references/host-elements.md +80 -0
  17. package/.claude/skills/angular-developer/references/injection-context.md +63 -0
  18. package/.claude/skills/angular-developer/references/inputs.md +101 -0
  19. package/.claude/skills/angular-developer/references/linked-signal.md +59 -0
  20. package/.claude/skills/angular-developer/references/loading-strategies.md +61 -0
  21. package/.claude/skills/angular-developer/references/mcp.md +106 -0
  22. package/.claude/skills/angular-developer/references/migrations.md +30 -0
  23. package/.claude/skills/angular-developer/references/navigate-to-routes.md +69 -0
  24. package/.claude/skills/angular-developer/references/outputs.md +86 -0
  25. package/.claude/skills/angular-developer/references/reactive-forms.md +122 -0
  26. package/.claude/skills/angular-developer/references/rendering-strategies.md +44 -0
  27. package/.claude/skills/angular-developer/references/resource.md +77 -0
  28. package/.claude/skills/angular-developer/references/route-animations.md +56 -0
  29. package/.claude/skills/angular-developer/references/route-guards.md +52 -0
  30. package/.claude/skills/angular-developer/references/router-lifecycle.md +45 -0
  31. package/.claude/skills/angular-developer/references/router-testing.md +87 -0
  32. package/.claude/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
  33. package/.claude/skills/angular-developer/references/signal-forms.md +897 -0
  34. package/.claude/skills/angular-developer/references/signals-overview.md +94 -0
  35. package/.claude/skills/angular-developer/references/tailwind-css.md +69 -0
  36. package/.claude/skills/angular-developer/references/template-driven-forms.md +114 -0
  37. package/.claude/skills/angular-developer/references/testing-fundamentals.md +66 -0
  38. package/.github/instructions/typescript/code-conventions.md +8 -0
  39. package/.github/instructions/typescript/comments.md +41 -0
  40. package/.github/instructions/typescript/formatting.md +43 -0
  41. package/.github/instructions/typescript/naming-conventions.md +7 -0
  42. package/.github/instructions/typescript.instructions.md +26 -0
  43. package/changelog.md +6 -0
  44. package/es2022/src/services/dateValueProvider/dateValueProvider.service.js +1 -1
  45. package/es2022/src/services/dateValueProvider/dateValueProvider.service.js.map +1 -1
  46. package/package.json +1 -1
  47. package/readme.md +1453 -4
  48. package/version.bak +1 -1
package/readme.md CHANGED
@@ -1,11 +1,1460 @@
1
1
  [![npm version](https://badge.fury.io/js/%40anglr%2Fdatetime.svg)](https://badge.fury.io/js/%40anglr%2Fdatetime)
2
2
  [![Build status](https://ci.appveyor.com/api/projects/status/4ieg9q7sgfgbpboj?svg=true)](https://ci.appveyor.com/project/kukjevov/ng-datetime)
3
3
 
4
- # Angular Datetime
4
+ # @anglr/datetime
5
+
6
+ > Angular library for datetime input, manipulation, validation, formatting, and calendar/picker UI components with pluggable date adapters (date-fns, Moment.js, or any other implementing `DateApiObject`).
5
7
 
6
8
  - [API](https://ressurectit.github.io/#/content/api/ng-datetime/datetime)
7
- - [API Moment](https://ressurectit.github.io/#/content/api/ng-datetime-date-fns/datetime-date-fns)
8
- - [API Date FNS](https://ressurectit.github.io/#/content/api/ng-datetime-moment/datetime-moment)
9
+ - [API Date FNS](https://ressurectit.github.io/#/content/api/ng-datetime-date-fns/datetime-date-fns)
10
+ - [API Moment](https://ressurectit.github.io/#/content/api/ng-datetime-moment/datetime-moment)
9
11
  - [Samples](https://ressurectit.github.io/#/content/datetime#samples)
10
12
 
11
- Library that contains components and directives used for datetime manipulation.
13
+ ---
14
+
15
+ ## Table of Contents
16
+
17
+ - [Why Use This Library?](#why-use-this-library)
18
+ - [Installation](#installation)
19
+ - [Architecture Overview](#architecture-overview)
20
+ - [Date Adapters](#date-adapters)
21
+ - [Modules](#modules)
22
+ - [Directives](#directives)
23
+ - [Pipes](#pipes)
24
+ - [Services](#services)
25
+ - [Validators](#validators)
26
+ - [Calendar](#calendar)
27
+ - [Date/Time Picker](#datetime-picker)
28
+ - [Theming & Styles](#theming--styles)
29
+ - [Usage Examples](#usage-examples)
30
+ - [Samples](#samples)
31
+ - [Advanced Usage](#advanced-usage)
32
+
33
+ ---
34
+
35
+ ## Why Use This Library?
36
+
37
+ - **Adapter-based architecture** — swap between `date-fns` and `Moment.js` (or your custom implementation) without changing your templates or component code.
38
+ - **Standalone directives** — tree-shakable, composable, use only what you need.
39
+ - **Rich keyboard handling** — arrow key navigation between date parts, increment/decrement with constraints, auto-selection of date segments.
40
+ - **Built-in validation** — min/max/format validators with Angular Reactive and Template-driven forms integration.
41
+ - **Flexible pickers** — configurable day/month/year/time pickers with positioning, CSS classes, and behavioral options.
42
+ - **Calendar component** — full month calendar with event support, custom day templates, and aspect ratio control.
43
+ - **Pipes for display** — format, convert, and compare dates directly in templates.
44
+ - **i18n-ready** — locale support via date-fns locales or Moment locale system.
45
+ - **Relative date parsing** — support for expressions like `+5d`, `-2M`, `+1y`.
46
+
47
+ ---
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ npm install @anglr/datetime
53
+ ```
54
+
55
+ Choose your date adapter:
56
+
57
+ ```bash
58
+ # date-fns (recommended)
59
+ npm install date-fns
60
+
61
+ # or Moment.js
62
+ npm install moment
63
+ ```
64
+
65
+ **Peer dependencies:**
66
+
67
+ - `@angular/core` >= 19.1.0
68
+ - `@angular/forms` >= 19.1.0
69
+ - `@angular/common` >= 19.1.0
70
+ - `@angular/animations` >= 19.1.0
71
+ - `@anglr/common` >= 22.0.0
72
+ - `@jscrpt/common` >= 7.0.0
73
+ - `rxjs` >= 7.5.7
74
+
75
+ ---
76
+
77
+ ## Architecture Overview
78
+
79
+ ```
80
+ ┌─────────────────────────────────────────────────┐
81
+ │ Your Application │
82
+ ├──────────────────┬──────────────────────────────┤
83
+ │ Directives │ Pipes / Validators │
84
+ │ (date inputs, │ (dateFormat, isAfter, │
85
+ │ pickers, etc.) │ datetimeMin, etc.) │
86
+ ├──────────────────┴──────────────────────────────┤
87
+ │ Core Services │
88
+ │ (DateApi, DatePositionParser, │
89
+ │ DateTimeRelativeParser, DateValueProvider) │
90
+ ├─────────────────────────────────────────────────┤
91
+ │ Adapter Layer (DI tokens) │
92
+ │ ┌──────────────────┐ ┌────────────────────┐ │
93
+ │ │ date-fns adapter │ │ Moment.js adapter │ │
94
+ │ │ DateFnsDateApi │ │ MomentDateApi │ │
95
+ │ └──────────────────┘ └────────────────────┘ │
96
+ └─────────────────────────────────────────────────┘
97
+ ```
98
+
99
+ The library uses Angular dependency injection tokens (`DATE_API`, `FORMAT_PROVIDER`, `DATE_API_OBJECT_TYPE`) allowing you to plug in any adapter at the application root.
100
+
101
+ ---
102
+
103
+ ## Date Adapters
104
+
105
+ ### date-fns Adapter
106
+
107
+ Import path: `@anglr/datetime/date-fns`
108
+
109
+ ```typescript
110
+ import {DATE_API} from '@anglr/datetime';
111
+ import {DateFnsDateApi, DateFnsLocale, DATE_FNS_DATE_API_OBJECT_TYPE, DATE_FNS_FORMAT_PROVIDER, DATE_FNS_LOCALE} from '@anglr/datetime/date-fns';
112
+ import {sk} from 'date-fns/locale';
113
+
114
+ export const appProviders =
115
+ [
116
+ {
117
+ provide: DATE_API,
118
+ useClass: DateFnsDateApi,
119
+ },
120
+ DATE_FNS_FORMAT_PROVIDER,
121
+ DATE_FNS_DATE_API_OBJECT_TYPE,
122
+ {
123
+ provide: DATE_FNS_LOCALE,
124
+ useValue: <DateFnsLocale>
125
+ {
126
+ locale: sk,
127
+ },
128
+ },
129
+ ];
130
+ ```
131
+
132
+ Default format tokens provided by `DATE_FNS_FORMAT_PROVIDER`:
133
+
134
+ | Token | Format |
135
+ |-------|--------|
136
+ | `date` | `'P'` (locale-aware) |
137
+ | `dateTime` | `'Pp'` |
138
+ | `time` | `'p'` |
139
+ | `year` | `'yyyy'` |
140
+ | `month` | `'MM'` |
141
+ | `day` | `'dd'` |
142
+ | `hour` | `'HH'` |
143
+ | `minute` | `'mm'` |
144
+ | `second` | `'ss'` |
145
+
146
+ ### Moment.js Adapter
147
+
148
+ Import path: `@anglr/datetime/moment`
149
+
150
+ ```typescript
151
+ import {DATE_API} from '@anglr/datetime';
152
+ import {MomentDateApi, MOMENT_FORMAT_PROVIDER, MOMENT_DATE_API_OBJECT_TYPE} from '@anglr/datetime/moment';
153
+
154
+ export const appProviders =
155
+ [
156
+ {
157
+ provide: DATE_API,
158
+ useClass: MomentDateApi,
159
+ },
160
+ MOMENT_FORMAT_PROVIDER,
161
+ MOMENT_DATE_API_OBJECT_TYPE,
162
+ ];
163
+ ```
164
+
165
+ ### Custom Format Provider
166
+
167
+ Override the default format tokens:
168
+
169
+ ```typescript
170
+ import {FORMAT_PROVIDER, FormatProvider} from '@anglr/datetime';
171
+
172
+ {
173
+ provide: FORMAT_PROVIDER,
174
+ useFactory: () =>
175
+ {
176
+ return <FormatProvider>{
177
+ date: 'd.M.y',
178
+ dateTime: 'd.M.y HH:mm',
179
+ time: 'HH:mm',
180
+ year: 'yyyy',
181
+ month: 'MM',
182
+ week: 'ww',
183
+ day: 'DD',
184
+ hour: 'HH',
185
+ minute: 'mm',
186
+ second: 'ss',
187
+ dayName: 'dddd',
188
+ dayNameShort: 'dd',
189
+ monthName: 'MMMM',
190
+ monthNameShort: 'MMM',
191
+ };
192
+ },
193
+ }
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Modules
199
+
200
+ | Module | Description |
201
+ |--------|-------------|
202
+ | `DateTimeModule` | Core directives: `DateTimeDirective`, `DateTimeInputDirective`, `DateTimeControlValueAccessorDirective`, validators |
203
+ | `DateTimePickerModule` | `DateTimePickerComponent`, `DateTimePickerDirective` |
204
+ | `MonthCalendarModule` | `MonthCalendarComponent`, `CalendarDayTemplateDirective` |
205
+ | `DatePipesModule` | `dateFormat`, `dateConvert`, `isAfter`, `isBefore` pipes |
206
+
207
+ ---
208
+
209
+ ## Directives
210
+
211
+ ### Composite (ready-to-use) Directives
212
+
213
+ These combine multiple internal directives for common use cases:
214
+
215
+ | Directive | Selector | Description |
216
+ |-----------|----------|-------------|
217
+ | `DatePickerInputDirective` | `input[dateTime][datePickerInput]` | Full date picker with advanced keyboard handler |
218
+ | `DateTimePickerInputDirective` | `input[dateTime][dateTimePickerInput]` | Full date + time picker with advanced keyboard handler |
219
+ | `SimpleDatePickerInputDirective` | `input[dateTime][simpleDatePickerInput]` | Date picker with simple keyboard handler |
220
+ | `SimpleDateTimePickerInputDirective` | `input[dateTime][simpleDateTimePickerInput]` | Date + time picker with simple keyboard handler |
221
+ | `ButtonDateTimeInputDirective` | `button[dateTime][dateTimeInput]` | Date/time input rendered as button/link |
222
+
223
+ ### Behavior Directives
224
+
225
+ | Directive | Selector | Description |
226
+ |-----------|----------|-------------|
227
+ | `WithNowDirective` | `[dateTime][withNow]` | Sets value to current date/time on focus (if empty) |
228
+ | `WithTodayDirective` | `[dateTime][withToday]` | Sets value to start of today on focus (if empty) |
229
+ | `WithTimeDirective` | `[dateTime][withPicker][withTime]` | Adds time picker component and switches format to `'dateTime'` |
230
+
231
+ ### Core Directives
232
+
233
+ | Directive | Selector | Description |
234
+ |-----------|----------|-------------|
235
+ | `DateTimeDirective` | `[dateTime]` | Shared data holder (format, restrictions, validation config) |
236
+ | `DateTimeInputDirective` | `input[dateTime][dateTimeInput]` | Text input with value parsing |
237
+ | `DateTimeInputHandlerDirective` | `[dateTime][withHandler]` | Advanced keyboard navigation (arrow keys navigate date parts) |
238
+ | `SimpleDateTimeInputHandlerDirective` | `[dateTime][withSimpleHandler]` | Simple keyboard (arrows: ±day/±week, Ctrl+Space: open picker) |
239
+ | `DateTimePickerDirective` | `[dateTime][withPicker]` | Controls picker component visibility and positioning |
240
+ | `DateTimeControlValueAccessorDirective` | `[dateTime][valueFormat]` | Angular ControlValueAccessor integration |
241
+ | `DateTimeValidatorDirective` | — | Validates date is valid format |
242
+ | `DateTimeMinValidatorDirective` | — | Validates date >= min |
243
+ | `DateTimeMaxValidatorDirective` | — | Validates date <= max |
244
+
245
+ ### Keyboard Handlers
246
+
247
+ **`DateTimeInputHandlerDirective` (Advanced):**
248
+ - Left/Right arrows: Navigate between date segments (year → month → day → hour → minute)
249
+ - Up/Down arrows: Increment/decrement current segment with min/max constraints
250
+ - Typed characters: Replace selected segment with validation
251
+ - Click/select: Auto-select current date part
252
+
253
+ **`SimpleDateTimeInputHandlerDirective` (Simple):**
254
+ - Left/Right arrows: ±1 day
255
+ - Up/Down arrows: ±1 week
256
+ - Escape: Close picker
257
+ - Ctrl+Space: Open picker
258
+
259
+ ---
260
+
261
+ ## Pipes
262
+
263
+ | Pipe | Syntax | Description |
264
+ |------|--------|-------------|
265
+ | `dateFormat` | `{{ value \| dateFormat }}` | Format with default `'date'` format |
266
+ | `dateFormat` | `{{ value \| dateFormat: 'dateTime' }}` | Format with FormatProvider key |
267
+ | `dateFormat` | `{{ value \| dateFormat: 'yyyy-MM-dd' : true }}` | Format with custom format string |
268
+ | `dateConvert` | `{{ value \| dateConvert }}` | Convert to DateApiObject wrapper |
269
+ | `dateConvert` | `{{ value \| dateConvert: 'yyyy-MM-dd' }}` | Convert with parse format |
270
+ | `isAfter` | `{{ date1 \| isAfter: date2 }}` | Test if date1 is after date2 |
271
+ | `isBefore` | `{{ date1 \| isBefore: date2 }}` | Test if date1 is before date2 |
272
+
273
+ ---
274
+
275
+ ## Services
276
+
277
+ ### DateApi\<TDate\>
278
+
279
+ Core abstraction for date manipulation. Injected via `DATE_API` token.
280
+
281
+ ```typescript
282
+ import {Component, inject} from '@angular/core';
283
+ import {DATE_API, DateApi} from '@anglr/datetime';
284
+
285
+ @Component(
286
+ {
287
+ /* ... */
288
+ })
289
+ export class ExampleComponent
290
+ {
291
+ private readonly dateApi: DateApi<Date> = inject<DateApi<Date>>(DATE_API);
292
+
293
+ example(): void
294
+ {
295
+ // Create date object
296
+ const today = this.dateApi.now();
297
+
298
+ // Parse value
299
+ const date = this.dateApi.getValue('2024-01-15', 'yyyy-MM-dd');
300
+
301
+ // Fluent API
302
+ const formatted = this.dateApi.now()
303
+ .addDays(5)
304
+ .startOfDay()
305
+ .format('yyyy-MM-dd');
306
+
307
+ // Comparisons
308
+ const isAfter = date.isAfter(today.value);
309
+ const isSame = date.isSameMonth(today.value);
310
+ }
311
+ }
312
+ ```
313
+
314
+ ### DateApiObject\<TDate\> (Fluent Wrapper)
315
+
316
+ Wraps a date value with chainable methods:
317
+
318
+ ```typescript
319
+ const result = dateApi.getValue('2024-03-15', 'yyyy-MM-dd')
320
+ .startOfMonth() // → 2024-03-01
321
+ .addMonths(2) // → 2024-05-01
322
+ .endOfMonth() // → 2024-05-31
323
+ .format('d.M.yyyy'); // → "31.5.2024"
324
+
325
+ // Getters/Setters
326
+ const year = obj.year(); // get: 2024
327
+ obj.year(2025); // set: 2025
328
+ obj.month(0); // January (0-based)
329
+ obj.dayOfMonth(15);
330
+
331
+ // Period helpers
332
+ obj.startOfDecade();
333
+ obj.endOfYear();
334
+ obj.startOfWeek();
335
+
336
+ // Clone and reset
337
+ const copy = obj.clone();
338
+ obj.resetOriginal(); // revert to initial value
339
+ obj.updateOriginal(); // lock current as new original
340
+ ```
341
+
342
+ ### DatePositionParserService
343
+
344
+ Parses cursor position within a date string format:
345
+
346
+ ```typescript
347
+ import {Component, inject} from '@angular/core';
348
+ import {DatePositionParserService} from '@anglr/datetime';
349
+
350
+ @Component(
351
+ {
352
+ /* ... */
353
+ })
354
+ export class ExampleComponent
355
+ {
356
+ private readonly positionParser: DatePositionParserService = inject(DatePositionParserService);
357
+
358
+ example(): void
359
+ {
360
+ const parser = this.positionParser.createParser('dd.MM.yyyy');
361
+ const result = parser.parse('15.03.2024', 4);
362
+ // result: { positionFrom: 3, positionTo: 5, part: 'month' }
363
+
364
+ parser.next('15.03.2024', 1);
365
+ // moves cursor to month segment
366
+ }
367
+ }
368
+ ```
369
+
370
+ ### DateTimeRelativeParser\<TDate\>
371
+
372
+ Parses relative date expressions:
373
+
374
+ ```typescript
375
+ import {Component, inject} from '@angular/core';
376
+ import {DateTimeRelativeParser} from '@anglr/datetime';
377
+
378
+ @Component(
379
+ {
380
+ /* ... */
381
+ })
382
+ export class ExampleComponent
383
+ {
384
+ private readonly relativeParser: DateTimeRelativeParser = inject(DateTimeRelativeParser);
385
+
386
+ example(): void
387
+ {
388
+ // Syntax: [+-]\d+[yMwdhm]
389
+ const result1 = this.relativeParser.parse('+5d'); // today + 5 days
390
+ const result2 = this.relativeParser.parse('-2M'); // today - 2 months
391
+ const result3 = this.relativeParser.parse('+1y'); // today + 1 year
392
+ }
393
+ }
394
+ ```
395
+
396
+ Supported suffixes: `y` (years), `M` (months), `w` (weeks), `d` (days), `h`/`H` (hours), `m` (minutes).
397
+
398
+ ### DateValueProvider\<TDate\>
399
+
400
+ Converts single date values to date ranges based on format granularity:
401
+
402
+ ```typescript
403
+ import {Component, inject} from '@angular/core';
404
+ import {DateValueProvider} from '@anglr/datetime';
405
+
406
+ @Component(
407
+ {
408
+ /* ... */
409
+ })
410
+ export class ExampleComponent
411
+ {
412
+ private readonly valueProvider: DateValueProvider = inject(DateValueProvider);
413
+
414
+ example(dateObj: unknown): void
415
+ {
416
+ // For day format: returns startOfDay → endOfDay
417
+ const range = this.valueProvider.getValue(dateObj, 'date');
418
+ // range.from → 2024-03-15 00:00:00
419
+ // range.to → 2024-03-15 23:59:59
420
+ }
421
+ }
422
+ ```
423
+
424
+ ---
425
+
426
+ ## Validators
427
+
428
+ ### Template-Driven Forms
429
+
430
+ ```html
431
+ <input dateTime simpleDatePickerInput
432
+ [minDateTime]="minDate"
433
+ [maxDateTime]="maxDate">
434
+ ```
435
+
436
+ ### Reactive Forms (Programmatic)
437
+
438
+ ```typescript
439
+ import {Component, inject} from '@angular/core';
440
+ import {FormControl} from '@angular/forms';
441
+ import {DATE_API, DateApi, datetimeValidator, datetimeMinValidator, datetimeMaxValidator, DateTimeValueFormat} from '@anglr/datetime';
442
+
443
+ @Component(
444
+ {
445
+ /* ... */
446
+ })
447
+ export class ValidatorExampleComponent
448
+ {
449
+ private readonly dateApi: DateApi<Date> = inject<DateApi<Date>>(DATE_API);
450
+
451
+ public readonly dateControl: FormControl = new FormControl('2024-01-15', [
452
+ datetimeValidator(this.dateApi, DateTimeValueFormat.FormattedString, 'yyyy-MM-dd'),
453
+ datetimeMinValidator(this.dateApi, '2024-01-01', DateTimeValueFormat.FormattedString, 'yyyy-MM-dd'),
454
+ datetimeMaxValidator(this.dateApi, '2024-12-31', DateTimeValueFormat.FormattedString, 'yyyy-MM-dd'),
455
+ ]);
456
+ }
457
+ ```
458
+
459
+ ### Model-Based Validation (Decorator)
460
+
461
+ ```typescript
462
+ import {DateTime, DateTimeValueFormat} from '@anglr/datetime';
463
+
464
+ class MyModel
465
+ {
466
+ @DateTime()
467
+ public dateField: string;
468
+
469
+ @DateTime(DateTimeValueFormat.DataString, 'yyyy-MM-dd', 'yyyy-MM-dd')
470
+ public startDate: string;
471
+ }
472
+ ```
473
+
474
+ ### Value Format Options
475
+
476
+ | Format | Description |
477
+ |--------|-------------|
478
+ | `DateTimeValueFormat.DateInstance` | Native JS Date object |
479
+ | `DateTimeValueFormat.UnixTimestamp` | Seconds since epoch |
480
+ | `DateTimeValueFormat.Timestamp` | Milliseconds since epoch |
481
+ | `DateTimeValueFormat.FormattedString` | Display format string |
482
+ | `DateTimeValueFormat.DataString` | Data-specific format string |
483
+ | `DateTimeValueFormat.RangeOfDateInstances` | Period with `from` / `to` |
484
+
485
+ ---
486
+
487
+ ## Calendar
488
+
489
+ The `MonthCalendarComponent` displays a full month calendar with event support.
490
+
491
+ ```typescript
492
+ import {ChangeDetectionStrategy, Component} from '@angular/core';
493
+ import {CalendarDayAspectRatio, EventData, MonthCalendarDayFormat, MonthCalendarModule} from '@anglr/datetime';
494
+
495
+ @Component(
496
+ {
497
+ template: `
498
+ <month-calendar [display]="currentMonth"
499
+ [events]="events"
500
+ [showWeekNumber]="true"
501
+ [dayAspectRatio]="CalendarDayAspectRatio.FourToThree"
502
+ [weekDayName]="MonthCalendarDayFormat.Short">
503
+ <ng-template calendarDayTemplate let-day>
504
+ <div class="day-number">{{ day.day }}</div>
505
+ @for (event of day.events; track event) {
506
+ <div class="event" [class.all-day]="event.allDay">
507
+ {{ $any(event.data).title }}
508
+ </div>
509
+ }
510
+ </ng-template>
511
+ </month-calendar>
512
+ `,
513
+ imports:
514
+ [
515
+ MonthCalendarModule,
516
+ ],
517
+ changeDetection: ChangeDetectionStrategy.OnPush,
518
+ })
519
+ export class CalendarPageComponent
520
+ {
521
+ protected readonly CalendarDayAspectRatio: typeof CalendarDayAspectRatio = CalendarDayAspectRatio;
522
+ protected readonly MonthCalendarDayFormat: typeof MonthCalendarDayFormat = MonthCalendarDayFormat;
523
+
524
+ public currentMonth: Date = new Date();
525
+ public events: EventData<Date, MyEvent>[] =
526
+ [
527
+ {data: {title: 'Meeting'}, dateFrom: new Date(2024, 2, 15), dateTo: new Date(2024, 2, 15)},
528
+ {data: {title: 'Conference'}, dateFrom: new Date(2024, 2, 20), dateTo: new Date(2024, 2, 22)},
529
+ ];
530
+ }
531
+ ```
532
+
533
+ ### Calendar Day Aspect Ratios
534
+
535
+ | Enum | Ratio | Value |
536
+ |------|-------|-------|
537
+ | `OneToOne` | 1:1 | 100 |
538
+ | `ThreeToTwo` | 3:2 | 66.66 |
539
+ | `FourToThree` | 4:3 | 75 |
540
+ | `SixteenToTen` | 16:10 | 62.5 |
541
+ | `SixteenToNine` | 16:9 | 56.25 |
542
+
543
+ ---
544
+
545
+ ## Date/Time Picker
546
+
547
+ ### Picker Components
548
+
549
+ | Component | Description |
550
+ |-----------|-------------|
551
+ | `DayPickerComponent` | Day grid for selecting a date within a month |
552
+ | `MonthPickerComponent` | Month grid for selecting a month within a year |
553
+ | `YearPickerComponent` | Year grid for selecting a year within a decade |
554
+ | `RollerTimePickerComponent` | Scrollable time picker (hours, minutes) |
555
+
556
+ ### Picker Options
557
+
558
+ ```typescript
559
+ import {DateTimePickerDirective, DateTimePickerDirectiveOptions} from '@anglr/datetime';
560
+
561
+ // In template:
562
+ // <input dateTime simpleDatePickerInput [withPickerOptions]="pickerOptions">
563
+
564
+ pickerOptions: DateTimePickerDirectiveOptions =
565
+ {
566
+ closeOnValueSelect: true,
567
+ closeOnBlur: true,
568
+ showOnFocus: true,
569
+ disabled: false,
570
+ absolute: true,
571
+ pickerCssClass: 'my-custom-picker',
572
+ };
573
+ ```
574
+
575
+ ### Custom Picker Periods
576
+
577
+ ```typescript
578
+ import {Directive} from '@angular/core';
579
+ import {DateTimeDirective, DateTimePickerDirective, DateTimeValueFormat, MonthPickerComponent, YearPickerComponent} from '@anglr/datetime';
580
+
581
+ @Directive(
582
+ {
583
+ /* ... */
584
+ })
585
+ export class CustomPickerDirective<TDate = unknown>
586
+ {
587
+ constructor(picker: DateTimePickerDirective<TDate>,
588
+ dateTime: DateTimeDirective<TDate>)
589
+ {
590
+ picker.pickerOptions =
591
+ {
592
+ defaultPeriod: 'month',
593
+ periodsDefinition:
594
+ {
595
+ 'month': MonthPickerComponent,
596
+ 'year': YearPickerComponent,
597
+ },
598
+ };
599
+ dateTime.customFormat = 'yyyy-MM';
600
+ dateTime.valueFormat = DateTimeValueFormat.FormattedString;
601
+ }
602
+ }
603
+ ```
604
+
605
+ ---
606
+
607
+ ## Theming & Styles
608
+
609
+ Import styles via SCSS:
610
+
611
+ ```scss
612
+ // All styles
613
+ @use '@anglr/datetime/styles';
614
+
615
+ // Individual themes
616
+ @use '@anglr/datetime/styles/themes/light';
617
+ @use '@anglr/datetime/styles/themes/dark';
618
+ ```
619
+
620
+ Available themes: `light`, `dark`.
621
+
622
+ SCSS architecture:
623
+ - `styles/core/_mixins.scss` — Reusable mixins
624
+ - `styles/core/_theme.scss` — Theme variable definitions
625
+ - `styles/core/_functions.scss` — SCSS helper functions
626
+ - `styles/components/_date-time-picker.scss` — Picker component styles
627
+ - `styles/components/_month-calendar.scss` — Calendar component styles
628
+
629
+ ---
630
+
631
+ ## Usage Examples
632
+
633
+ ### Basic Date Picker Input
634
+
635
+ ```typescript
636
+ import {ChangeDetectionStrategy, Component} from '@angular/core';
637
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
638
+ import {DateTimeModule, WithTodayDirective, SimpleDatePickerInputDirective} from '@anglr/datetime';
639
+
640
+ @Component(
641
+ {
642
+ selector: 'my-form',
643
+ template: `
644
+ <input dateTime simpleDatePickerInput withToday
645
+ class="form-control"
646
+ [formControl]="dateControl">
647
+ `,
648
+ imports:
649
+ [
650
+ DateTimeModule,
651
+ WithTodayDirective,
652
+ ReactiveFormsModule,
653
+ SimpleDatePickerInputDirective,
654
+ ],
655
+ changeDetection: ChangeDetectionStrategy.OnPush,
656
+ })
657
+ export class MyFormComponent
658
+ {
659
+ public readonly dateControl: FormControl = new FormControl('');
660
+ }
661
+ ```
662
+
663
+ ### Date + Time Picker
664
+
665
+ ```typescript
666
+ import {ChangeDetectionStrategy, Component} from '@angular/core';
667
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
668
+ import {DateTimeModule, WithNowDirective, SimpleDateTimePickerInputDirective} from '@anglr/datetime';
669
+
670
+ @Component(
671
+ {
672
+ template: `
673
+ <input dateTime simpleDateTimePickerInput withNow
674
+ class="form-control"
675
+ [formControl]="dateTimeControl">
676
+ `,
677
+ imports:
678
+ [
679
+ DateTimeModule,
680
+ WithNowDirective,
681
+ ReactiveFormsModule,
682
+ SimpleDateTimePickerInputDirective,
683
+ ],
684
+ changeDetection: ChangeDetectionStrategy.OnPush,
685
+ })
686
+ export class DateTimeFormComponent
687
+ {
688
+ public readonly dateTimeControl: FormControl = new FormControl('');
689
+ }
690
+ ```
691
+
692
+ ### Advanced Keyboard-Navigable Date Input
693
+
694
+ ```typescript
695
+ import {ChangeDetectionStrategy, Component} from '@angular/core';
696
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
697
+ import {DateTimeModule, DateTimePickerModule, DatePickerInputDirective} from '@anglr/datetime';
698
+
699
+ @Component(
700
+ {
701
+ template: `
702
+ <input dateTime datePickerInput
703
+ class="form-control"
704
+ [formControl]="dateControl"
705
+ [minDateTime]="minDate"
706
+ [maxDateTime]="maxDate">
707
+ `,
708
+ imports:
709
+ [
710
+ DateTimeModule,
711
+ ReactiveFormsModule,
712
+ DateTimePickerModule,
713
+ DatePickerInputDirective,
714
+ ],
715
+ changeDetection: ChangeDetectionStrategy.OnPush,
716
+ })
717
+ export class AdvancedDateComponent
718
+ {
719
+ public readonly dateControl: FormControl = new FormControl('');
720
+ public minDate: string = '2024-01-01';
721
+ public maxDate: string = '2024-12-31';
722
+ }
723
+ ```
724
+
725
+ ### Display Dates with Pipes
726
+
727
+ ```typescript
728
+ import {ChangeDetectionStrategy, Component} from '@angular/core';
729
+ import {DatePipesModule} from '@anglr/datetime';
730
+
731
+ @Component(
732
+ {
733
+ template: `
734
+ <!-- Default date format -->
735
+ <span>{{ createdAt | dateFormat }}</span>
736
+
737
+ <!-- Date + time -->
738
+ <span>{{ updatedAt | dateFormat: 'dateTime' }}</span>
739
+
740
+ <!-- Custom format -->
741
+ <span>{{ birthday | dateFormat: 'dd. MMMM yyyy' : true }}</span>
742
+
743
+ <!-- Comparison -->
744
+ @if (endDate | isBefore: today) {
745
+ <span class="expired">Expired</span>
746
+ }
747
+ `,
748
+ imports:
749
+ [
750
+ DatePipesModule,
751
+ ],
752
+ changeDetection: ChangeDetectionStrategy.OnPush,
753
+ })
754
+ export class DisplayComponent
755
+ {
756
+ public createdAt: string = '2024-03-15T10:30:00Z';
757
+ public updatedAt: Date = new Date();
758
+ public birthday: Date = new Date(1990, 5, 15);
759
+ public endDate: Date = new Date(2024, 0, 1);
760
+ public today: Date = new Date();
761
+ }
762
+ ```
763
+
764
+ ### Creating a Custom Picker Directive (hostDirectives pattern)
765
+
766
+ ```typescript
767
+ import {Directive} from '@angular/core';
768
+ import {
769
+ DateTimeDirective,
770
+ DateTimeValueFormat,
771
+ DateTimeInputDirective,
772
+ DateTimePickerDirective,
773
+ SimpleDateTimeInputHandlerDirective,
774
+ } from '@anglr/datetime';
775
+
776
+ @Directive(
777
+ {
778
+ selector: 'input[dateTime][dayPicker]',
779
+ hostDirectives:
780
+ [
781
+ DateTimeInputDirective,
782
+ DateTimePickerDirective,
783
+ SimpleDateTimeInputHandlerDirective,
784
+ {
785
+ directive: DateTimeDirective,
786
+ inputs: ['minDateTime', 'maxDateTime', 'valueFormat', 'format', 'customFormat', 'dataFormat'],
787
+ },
788
+ ],
789
+ })
790
+ export class DayPickerDirective<TDate = unknown>
791
+ {
792
+ constructor(dateTime: DateTimeDirective<TDate>)
793
+ {
794
+ dateTime.valueFormat = DateTimeValueFormat.DataString;
795
+ dateTime.dataFormat = 'yyyy-MM-dd';
796
+ }
797
+ }
798
+ ```
799
+
800
+ Usage in template:
801
+
802
+ ```html
803
+ <input dateTime dayPicker class="form-control" [formControl]="myControl">
804
+ ```
805
+
806
+ ### Month-Only Picker Directive
807
+
808
+ ```typescript
809
+ import {Directive} from '@angular/core';
810
+ import {
811
+ DateTimeDirective,
812
+ DateTimeValueFormat,
813
+ MonthPickerComponent,
814
+ YearPickerComponent,
815
+ DateTimeInputDirective,
816
+ DateTimePickerDirective,
817
+ DateTimeInputHandlerDirective,
818
+ } from '@anglr/datetime';
819
+
820
+ @Directive(
821
+ {
822
+ selector: 'input[dateTime][monthPicker]',
823
+ hostDirectives:
824
+ [
825
+ DateTimeInputDirective,
826
+ DateTimePickerDirective,
827
+ DateTimeInputHandlerDirective,
828
+ {
829
+ directive: DateTimeDirective,
830
+ inputs: ['minDateTime', 'maxDateTime'],
831
+ },
832
+ ],
833
+ })
834
+ export class MonthPickerDirective<TDate = unknown>
835
+ {
836
+ constructor(picker: DateTimePickerDirective<TDate>,
837
+ dateTime: DateTimeDirective<TDate>)
838
+ {
839
+ picker.pickerOptions =
840
+ {
841
+ defaultPeriod: 'month',
842
+ periodsDefinition:
843
+ {
844
+ 'month': MonthPickerComponent,
845
+ 'year': YearPickerComponent,
846
+ },
847
+ };
848
+ dateTime.customFormat = 'yyyy-MM';
849
+ dateTime.valueFormat = DateTimeValueFormat.FormattedString;
850
+ }
851
+ }
852
+ ```
853
+
854
+ ### Day + Time Picker with DataString Output
855
+
856
+ ```typescript
857
+ import {Directive} from '@angular/core';
858
+ import {
859
+ DateTimeDirective,
860
+ DateTimeValueFormat,
861
+ WithTimeDirective,
862
+ DateTimeInputDirective,
863
+ DateTimePickerDirective,
864
+ SimpleDateTimeInputHandlerDirective,
865
+ } from '@anglr/datetime';
866
+
867
+ @Directive(
868
+ {
869
+ selector: 'input[dateTime][dayTimePicker]',
870
+ hostDirectives:
871
+ [
872
+ WithTimeDirective,
873
+ DateTimeInputDirective,
874
+ DateTimePickerDirective,
875
+ SimpleDateTimeInputHandlerDirective,
876
+ {
877
+ directive: DateTimeDirective,
878
+ inputs: ['minDateTime', 'maxDateTime', 'valueFormat', 'format', 'customFormat', 'dataFormat'],
879
+ },
880
+ ],
881
+ })
882
+ export class DayTimePickerDirective<TDate = unknown>
883
+ {
884
+ constructor(dateTime: DateTimeDirective<TDate>)
885
+ {
886
+ dateTime.valueFormat = DateTimeValueFormat.DataString;
887
+ dateTime.dataFormat = "yyyy-MM-dd'T'HH:mm:ss";
888
+ }
889
+ }
890
+ ```
891
+
892
+ ### Extending DateApiObject with Custom Methods
893
+
894
+ ```typescript
895
+ import {DateApiObject} from '@anglr/datetime';
896
+ import {DateFnsDateApiObject} from '@anglr/datetime/date-fns';
897
+ import {differenceInMonths, differenceInYears, differenceInSeconds} from 'date-fns';
898
+
899
+ export class DateApiExtension extends DateFnsDateApiObject
900
+ {
901
+ public override clone(): DateApiObject<Date>
902
+ {
903
+ return new DateApiExtension(new Date(this._value), null, this._localeSvc);
904
+ }
905
+
906
+ public override cloneOriginal(): DateApiObject<Date>
907
+ {
908
+ return new DateApiExtension(new Date(this._originalValue), null, this._localeSvc);
909
+ }
910
+
911
+ public diffMonths(date: Date): number
912
+ {
913
+ return differenceInMonths(this._value, date);
914
+ }
915
+
916
+ public diffYears(date: Date): number
917
+ {
918
+ return differenceInYears(this._value, date);
919
+ }
920
+
921
+ public diffSeconds(date: Date): number
922
+ {
923
+ return differenceInSeconds(this._value, date);
924
+ }
925
+ }
926
+ ```
927
+
928
+ Register the extension globally:
929
+
930
+ ```typescript
931
+ import {DATE_API_OBJECT_TYPE} from '@anglr/datetime';
932
+
933
+ {
934
+ provide: DATE_API_OBJECT_TYPE,
935
+ useValue: DateApiExtension,
936
+ }
937
+ ```
938
+
939
+ ### Feature Module Pattern
940
+
941
+ ```typescript
942
+ import {NgModule} from '@angular/core';
943
+ import {ReactiveFormsModule} from '@angular/forms';
944
+ import {
945
+ DateTimeModule,
946
+ WithNowDirective,
947
+ WithTimeDirective,
948
+ WithTodayDirective,
949
+ DateTimePickerModule,
950
+ DatePickerInputDirective,
951
+ DateTimePickerInputDirective,
952
+ DateTimeInputHandlerDirective,
953
+ SimpleDatePickerInputDirective,
954
+ SimpleDateTimePickerInputDirective,
955
+ SimpleDateTimeInputHandlerDirective,
956
+ } from '@anglr/datetime';
957
+
958
+ @NgModule(
959
+ {
960
+ imports:
961
+ [
962
+ WithNowDirective,
963
+ WithTimeDirective,
964
+ WithTodayDirective,
965
+ DatePickerInputDirective,
966
+ DateTimePickerInputDirective,
967
+ DateTimeInputHandlerDirective,
968
+ SimpleDatePickerInputDirective,
969
+ SimpleDateTimePickerInputDirective,
970
+ SimpleDateTimeInputHandlerDirective,
971
+ ],
972
+ exports:
973
+ [
974
+ DateTimeModule,
975
+ WithNowDirective,
976
+ WithTimeDirective,
977
+ WithTodayDirective,
978
+ ReactiveFormsModule,
979
+ DateTimePickerModule,
980
+ DatePickerInputDirective,
981
+ DateTimePickerInputDirective,
982
+ DateTimeInputHandlerDirective,
983
+ SimpleDatePickerInputDirective,
984
+ SimpleDateTimePickerInputDirective,
985
+ SimpleDateTimeInputHandlerDirective,
986
+ ],
987
+ })
988
+ export class FormsFeatureModule
989
+ {
990
+ }
991
+ ```
992
+
993
+ ### Display Feature Module with Pipes
994
+
995
+ ```typescript
996
+ import {NgModule} from '@angular/core';
997
+ import {CommonModule} from '@angular/common';
998
+ import {DatePipesModule} from '@anglr/datetime';
999
+
1000
+ @NgModule(
1001
+ {
1002
+ exports:
1003
+ [
1004
+ CommonModule,
1005
+ DatePipesModule,
1006
+ ],
1007
+ })
1008
+ export class DisplayingFeatureModule
1009
+ {
1010
+ }
1011
+ ```
1012
+
1013
+ ---
1014
+
1015
+ ## Samples
1016
+
1017
+ These samples demonstrate the building-block approach using individual directives. Live demos are available at [Samples](https://ressurectit.github.io/#/content/datetime#samples).
1018
+
1019
+ ### Basic DateTime Input
1020
+
1021
+ A minimal date input using `dateTime` and `dateTimeInput` directives with a reactive form control.
1022
+
1023
+ ```typescript
1024
+ import {Component, ChangeDetectionStrategy} from '@angular/core';
1025
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
1026
+ import {JsonPipe} from '@angular/common';
1027
+ import {DatePipesModule, DateTimeModule} from '@anglr/datetime';
1028
+
1029
+ @Component(
1030
+ {
1031
+ selector: 'basic-sample',
1032
+ templateUrl: 'basicSample.component.html',
1033
+ imports:
1034
+ [
1035
+ ReactiveFormsModule,
1036
+ DatePipesModule,
1037
+ DateTimeModule,
1038
+ JsonPipe,
1039
+ ],
1040
+ changeDetection: ChangeDetectionStrategy.OnPush,
1041
+ })
1042
+ export class BasicSampleComponent
1043
+ {
1044
+ protected datetimeControl: FormControl<unknown> = new FormControl(null);
1045
+ }
1046
+ ```
1047
+
1048
+ ```html
1049
+ <div class="flex-row margin-bottom-extra-small">
1050
+ <div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
1051
+ <div class="flex-1">Date value: {{datetimeControl.value | dateFormat}}</div>
1052
+ </div>
1053
+
1054
+ <input class="form-control" dateTime dateTimeInput [formControl]="datetimeControl">
1055
+ ```
1056
+
1057
+ ### Basic DateTime Picker
1058
+
1059
+ Adds a date picker popup by applying the `withPicker` directive.
1060
+
1061
+ ```typescript
1062
+ import {Component, ChangeDetectionStrategy} from '@angular/core';
1063
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
1064
+ import {JsonPipe} from '@angular/common';
1065
+ import {DatePipesModule, DateTimeModule, DateTimePickerModule} from '@anglr/datetime';
1066
+
1067
+ @Component(
1068
+ {
1069
+ selector: 'basic-picker-sample',
1070
+ templateUrl: 'basicPickerSample.component.html',
1071
+ imports:
1072
+ [
1073
+ DateTimePickerModule,
1074
+ ReactiveFormsModule,
1075
+ DatePipesModule,
1076
+ DateTimeModule,
1077
+ JsonPipe,
1078
+ ],
1079
+ changeDetection: ChangeDetectionStrategy.OnPush,
1080
+ })
1081
+ export class BasicPickerSampleComponent
1082
+ {
1083
+ protected datetimeControl: FormControl<unknown> = new FormControl(null);
1084
+ }
1085
+ ```
1086
+
1087
+ ```html
1088
+ <div class="flex-row margin-bottom-extra-small">
1089
+ <div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
1090
+ <div class="flex-1">Date value: {{datetimeControl.value | dateFormat}}</div>
1091
+ </div>
1092
+
1093
+ <input class="form-control" dateTime dateTimeInput withPicker [formControl]="datetimeControl">
1094
+ ```
1095
+
1096
+ ### DateTime with Time
1097
+
1098
+ Enables time selection alongside date by adding the `withTime` directive.
1099
+
1100
+ ```typescript
1101
+ import {Component, ChangeDetectionStrategy} from '@angular/core';
1102
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
1103
+ import {JsonPipe} from '@angular/common';
1104
+ import {DatePipesModule, DateTimeModule, DateTimePickerModule, WithTimeDirective} from '@anglr/datetime';
1105
+
1106
+ @Component(
1107
+ {
1108
+ selector: 'with-time-sample',
1109
+ templateUrl: 'withTimeSample.component.html',
1110
+ imports:
1111
+ [
1112
+ DateTimePickerModule,
1113
+ WithTimeDirective,
1114
+ ReactiveFormsModule,
1115
+ DatePipesModule,
1116
+ DateTimeModule,
1117
+ JsonPipe,
1118
+ ],
1119
+ changeDetection: ChangeDetectionStrategy.OnPush,
1120
+ })
1121
+ export class WithTimeSampleComponent
1122
+ {
1123
+ protected datetimeControl: FormControl<unknown> = new FormControl(null);
1124
+ }
1125
+ ```
1126
+
1127
+ ```html
1128
+ <div class="flex-row margin-bottom-extra-small">
1129
+ <div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
1130
+ <div class="flex-1">Date value: {{datetimeControl.value | dateFormat: 'dateTime'}}</div>
1131
+ </div>
1132
+
1133
+ <input class="form-control" dateTime dateTimeInput withPicker withTime [formControl]="datetimeControl">
1134
+ ```
1135
+
1136
+ ### Today vs Now
1137
+
1138
+ Compares `withToday` (sets value to start of day) and `withNow` (sets value to current date/time) when the input is focused while empty.
1139
+
1140
+ ```typescript
1141
+ import {Component, ChangeDetectionStrategy} from '@angular/core';
1142
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
1143
+ import {JsonPipe} from '@angular/common';
1144
+ import {DatePipesModule, DateTimeModule, DateTimePickerModule, WithNowDirective, WithTimeDirective, WithTodayDirective} from '@anglr/datetime';
1145
+
1146
+ @Component(
1147
+ {
1148
+ selector: 'today-vs-now-sample',
1149
+ templateUrl: 'todayVsNowSample.component.html',
1150
+ imports:
1151
+ [
1152
+ WithTimeDirective,
1153
+ WithTodayDirective,
1154
+ DateTimePickerModule,
1155
+ ReactiveFormsModule,
1156
+ WithNowDirective,
1157
+ DatePipesModule,
1158
+ DateTimeModule,
1159
+ JsonPipe,
1160
+ ],
1161
+ changeDetection: ChangeDetectionStrategy.OnPush,
1162
+ })
1163
+ export class TodayVsNowSampleComponent
1164
+ {
1165
+ protected datetimeControl: FormControl<unknown> = new FormControl(null);
1166
+ protected datetimeControl2: FormControl<unknown> = new FormControl(null);
1167
+ }
1168
+ ```
1169
+
1170
+ ```html
1171
+ <div class="flex-row column-gap-small margin-bottom-extra-small">
1172
+ <div class="flex-1">
1173
+ <div>Raw value: {{datetimeControl.value | json}}</div>
1174
+ <div>Date value: {{datetimeControl.value | dateFormat: 'dateTime'}}</div>
1175
+ </div>
1176
+
1177
+ <div class="flex-1">
1178
+ <div>Raw value: {{datetimeControl2.value | json}}</div>
1179
+ <div>Date value: {{datetimeControl2.value | dateFormat: 'dateTime'}}</div>
1180
+ </div>
1181
+ </div>
1182
+
1183
+ <div class="flex-row column-gap-small">
1184
+ <div class="form-group flex-1">
1185
+ <label class="control-label">today</label>
1186
+ <input class="form-control" dateTime dateTimeInput withPicker withTime withToday [formControl]="datetimeControl">
1187
+ </div>
1188
+
1189
+ <div class="form-group flex-1">
1190
+ <label class="control-label">now</label>
1191
+ <input class="form-control" dateTime dateTimeInput withPicker withTime withNow [formControl]="datetimeControl2">
1192
+ </div>
1193
+ </div>
1194
+ ```
1195
+
1196
+ ### Input Handlers
1197
+
1198
+ Demonstrates the difference between `withSimpleHandler` (simple arrow key navigation: ±1 day/±1 week) and `withHandler` (advanced segment-based keyboard navigation).
1199
+
1200
+ ```typescript
1201
+ import {Component, ChangeDetectionStrategy} from '@angular/core';
1202
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
1203
+ import {JsonPipe} from '@angular/common';
1204
+ import {DatePipesModule, DateTimeInputHandlerDirective, DateTimeModule, DateTimePickerModule, SimpleDateTimeInputHandlerDirective} from '@anglr/datetime';
1205
+
1206
+ @Component(
1207
+ {
1208
+ selector: 'handlers-sample',
1209
+ templateUrl: 'handlersSample.component.html',
1210
+ imports:
1211
+ [
1212
+ SimpleDateTimeInputHandlerDirective,
1213
+ DateTimeInputHandlerDirective,
1214
+ DateTimePickerModule,
1215
+ ReactiveFormsModule,
1216
+ DatePipesModule,
1217
+ DateTimeModule,
1218
+ JsonPipe,
1219
+ ],
1220
+ changeDetection: ChangeDetectionStrategy.OnPush,
1221
+ })
1222
+ export class HandlersSampleComponent
1223
+ {
1224
+ protected datetimeControl: FormControl<unknown> = new FormControl(null);
1225
+ protected datetimeControl2: FormControl<unknown> = new FormControl(null);
1226
+ }
1227
+ ```
1228
+
1229
+ ```html
1230
+ <div class="flex-row column-gap-small margin-bottom-extra-small">
1231
+ <div class="flex-1">
1232
+ <div>Raw value: {{datetimeControl.value | json}}</div>
1233
+ <div>Date value: {{datetimeControl.value | dateFormat}}</div>
1234
+ </div>
1235
+
1236
+ <div class="flex-1">
1237
+ <div>Raw value: {{datetimeControl2.value | json}}</div>
1238
+ <div>Date value: {{datetimeControl2.value | dateFormat}}</div>
1239
+ </div>
1240
+ </div>
1241
+
1242
+ <div class="flex-row column-gap-small">
1243
+ <div class="form-group flex-1">
1244
+ <label class="control-label">simple handler</label>
1245
+ <input class="form-control" dateTime dateTimeInput withPicker withSimpleHandler [formControl]="datetimeControl">
1246
+ </div>
1247
+
1248
+ <div class="form-group flex-1">
1249
+ <label class="control-label">handler</label>
1250
+ <input class="form-control" dateTime dateTimeInput withPicker withHandler [formControl]="datetimeControl2">
1251
+ </div>
1252
+ </div>
1253
+ ```
1254
+
1255
+ ### Different Data Types
1256
+
1257
+ Shows how to use different `valueFormat` options to control the output type of the form control value.
1258
+
1259
+ ```typescript
1260
+ import {Component, ChangeDetectionStrategy} from '@angular/core';
1261
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
1262
+ import {JsonPipe} from '@angular/common';
1263
+ import {DatePipesModule, DateTimeModule, DateTimePickerModule} from '@anglr/datetime';
1264
+
1265
+ @Component(
1266
+ {
1267
+ selector: 'data-types-sample',
1268
+ templateUrl: 'dataTypesSample.component.html',
1269
+ imports:
1270
+ [
1271
+ DateTimePickerModule,
1272
+ ReactiveFormsModule,
1273
+ DatePipesModule,
1274
+ DateTimeModule,
1275
+ JsonPipe,
1276
+ ],
1277
+ changeDetection: ChangeDetectionStrategy.OnPush,
1278
+ })
1279
+ export class DataTypesSampleComponent
1280
+ {
1281
+ protected datetimeControl: FormControl<unknown> = new FormControl(null);
1282
+ protected timestampControl: FormControl<number|null> = new FormControl(null);
1283
+ protected stringControl: FormControl<string|null> = new FormControl(null);
1284
+ protected customStringControl: FormControl<string|null> = new FormControl(null);
1285
+ }
1286
+ ```
1287
+
1288
+ ```html
1289
+ <div class="flex-row column-gap-medium margin-bottom-extra-small">
1290
+ <div class="flex-1">
1291
+ <div>Raw value: {{datetimeControl.value | json}}</div>
1292
+ <div>Date value: {{datetimeControl.value | dateFormat}}</div>
1293
+ </div>
1294
+
1295
+ <div class="flex-1">
1296
+ <div>Raw value: {{timestampControl.value | json}}</div>
1297
+ <div>Date value: {{timestampControl.value | dateFormat}}</div>
1298
+ </div>
1299
+
1300
+ <div class="flex-1">
1301
+ <div>Raw value: {{stringControl.value | json}}</div>
1302
+ <div>Date value: {{stringControl.value | dateFormat: 'date' : 'yyyyMMdd'}}</div>
1303
+ </div>
1304
+
1305
+ <div class="flex-1">
1306
+ <div>Raw value: {{customStringControl.value | json}}</div>
1307
+ <div>Date value: {{customStringControl.value | dateFormat: 'date' : 'yyyy-MM-dd'}}</div>
1308
+ </div>
1309
+ </div>
1310
+
1311
+ <div class="flex-row column-gap-medium">
1312
+ <div class="form-group flex-1">
1313
+ <label class="control-label">type DateInstance</label>
1314
+ <input class="form-control" dateTime dateTimeInput withPicker [formControl]="datetimeControl" valueFormat="DateInstance">
1315
+ </div>
1316
+
1317
+ <div class="form-group flex-1">
1318
+ <label class="control-label">type UnixTimestamp</label>
1319
+ <input class="form-control" dateTime dateTimeInput withPicker [formControl]="timestampControl" valueFormat="Timestamp">
1320
+ </div>
1321
+
1322
+ <div class="form-group flex-1">
1323
+ <label class="control-label">type FormattedString</label>
1324
+ <input class="form-control" dateTime dateTimeInput withPicker [formControl]="stringControl" valueFormat="FormattedString" customFormat="yyyyMMdd">
1325
+ </div>
1326
+
1327
+ <div class="form-group flex-1">
1328
+ <label class="control-label">type DataString</label>
1329
+ <input class="form-control" dateTime dateTimeInput withPicker [formControl]="customStringControl" valueFormat="DataString" dataFormat="yyyy-MM-dd">
1330
+ </div>
1331
+ </div>
1332
+ ```
1333
+
1334
+ ### Customized Picker
1335
+
1336
+ Customizes the picker to show only month/year periods with a custom date format.
1337
+
1338
+ ```typescript
1339
+ import {Component, ChangeDetectionStrategy} from '@angular/core';
1340
+ import {FormControl, ReactiveFormsModule} from '@angular/forms';
1341
+ import {JsonPipe} from '@angular/common';
1342
+ import {DatePipesModule, DateTimeModule, DateTimePickerModule, DateTimePickerOptions, MonthPickerComponent, YearPickerComponent} from '@anglr/datetime';
1343
+
1344
+ @Component(
1345
+ {
1346
+ selector: 'customized-picker-sample',
1347
+ templateUrl: 'customizedPickerSample.component.html',
1348
+ imports:
1349
+ [
1350
+ DateTimePickerModule,
1351
+ ReactiveFormsModule,
1352
+ DatePipesModule,
1353
+ DateTimeModule,
1354
+ JsonPipe,
1355
+ ],
1356
+ changeDetection: ChangeDetectionStrategy.OnPush,
1357
+ })
1358
+ export class CustomizedPickerSampleComponent
1359
+ {
1360
+ protected datetimeControl: FormControl<unknown> = new FormControl(null);
1361
+ protected pickerOptions: Partial<DateTimePickerOptions<unknown>>;
1362
+
1363
+ constructor()
1364
+ {
1365
+ this.pickerOptions =
1366
+ {
1367
+ periodsDefinition:
1368
+ {
1369
+ month: MonthPickerComponent,
1370
+ year: YearPickerComponent,
1371
+ },
1372
+ defaultPeriod: 'month',
1373
+ };
1374
+ }
1375
+ }
1376
+ ```
1377
+
1378
+ ```html
1379
+ <div class="flex-row margin-bottom-extra-small">
1380
+ <div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
1381
+ <div class="flex-1">Date value: {{datetimeControl.value | dateFormat: 'date': 'yyyyMM'}}</div>
1382
+ </div>
1383
+
1384
+ <input class="form-control" dateTime dateTimeInput withPicker [formControl]="datetimeControl" [pickerOptions]="pickerOptions" valueFormat="FormattedString" customFormat="yyyyMM">
1385
+ ```
1386
+
1387
+ ---
1388
+
1389
+ ## Advanced Usage
1390
+
1391
+ ### Relative Date Input
1392
+
1393
+ Users can type relative expressions in inputs configured with `DateTimeRelativeParser`:
1394
+
1395
+ | Expression | Result |
1396
+ |------------|--------|
1397
+ | `+5d` | Today + 5 days |
1398
+ | `-2M` | Today - 2 months |
1399
+ | `+1y` | Today + 1 year |
1400
+ | `-3w` | Today - 3 weeks |
1401
+ | `+2h` | Now + 2 hours |
1402
+ | `-30m` | Now - 30 minutes |
1403
+
1404
+ ### DateTimeValue Interface (Ranges)
1405
+
1406
+ ```typescript
1407
+ import {DateTimeValue} from '@anglr/datetime';
1408
+
1409
+ // Represents a date range
1410
+ const period: DateTimeValue<Date> =
1411
+ {
1412
+ from: new Date(2024, 0, 1),
1413
+ to: new Date(2024, 11, 31),
1414
+ };
1415
+ ```
1416
+
1417
+ ### Using DateApi in Services
1418
+
1419
+ ```typescript
1420
+ import {inject, Injectable} from '@angular/core';
1421
+ import {DATE_API, DateApi} from '@anglr/datetime';
1422
+
1423
+ @Injectable(
1424
+ {
1425
+ providedIn: 'root',
1426
+ })
1427
+ export class MyDateService
1428
+ {
1429
+ private readonly dateApi: DateApi<Date> = inject<DateApi<Date>>(DATE_API);
1430
+
1431
+ public isExpired(dateStr: string): boolean
1432
+ {
1433
+ const date = this.dateApi.getValue(dateStr, 'yyyy-MM-dd');
1434
+ const now = this.dateApi.now();
1435
+
1436
+ return date.isBefore(now.value);
1437
+ }
1438
+
1439
+ public getMonthRange(date: Date): {from: string; to: string}
1440
+ {
1441
+ const obj = this.dateApi.getValue(date);
1442
+
1443
+ return {
1444
+ from: obj.clone().startOfMonth().format('yyyy-MM-dd'),
1445
+ to: obj.clone().endOfMonth().format('yyyy-MM-dd'),
1446
+ };
1447
+ }
1448
+
1449
+ public formatForDisplay(date: Date): string
1450
+ {
1451
+ return this.dateApi.getValue(date).format('d.M.yyyy HH:mm');
1452
+ }
1453
+ }
1454
+ ```
1455
+
1456
+ ---
1457
+
1458
+ ## License
1459
+
1460
+ [MIT](LICENSE)