@fundamental-ngx/core 0.63.0-rc.2 → 0.63.0-rc.21

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 (119) hide show
  1. package/fesm2022/fundamental-ngx-core-action-bar.mjs +2 -2
  2. package/fesm2022/fundamental-ngx-core-action-sheet.mjs +2 -2
  3. package/fesm2022/fundamental-ngx-core-action-sheet.mjs.map +1 -1
  4. package/fesm2022/fundamental-ngx-core-avatar-group.mjs +2 -2
  5. package/fesm2022/fundamental-ngx-core-avatar-group.mjs.map +1 -1
  6. package/fesm2022/fundamental-ngx-core-avatar.mjs +2 -2
  7. package/fesm2022/fundamental-ngx-core-bar.mjs +2 -2
  8. package/fesm2022/fundamental-ngx-core-bar.mjs.map +1 -1
  9. package/fesm2022/fundamental-ngx-core-breadcrumb.mjs +2 -2
  10. package/fesm2022/fundamental-ngx-core-busy-indicator.mjs +2 -2
  11. package/fesm2022/fundamental-ngx-core-button.mjs +2 -2
  12. package/fesm2022/fundamental-ngx-core-calendar.mjs +52 -47
  13. package/fesm2022/fundamental-ngx-core-calendar.mjs.map +1 -1
  14. package/fesm2022/fundamental-ngx-core-card.mjs +2 -2
  15. package/fesm2022/fundamental-ngx-core-card.mjs.map +1 -1
  16. package/fesm2022/fundamental-ngx-core-carousel.mjs +2 -2
  17. package/fesm2022/fundamental-ngx-core-checkbox.mjs +2 -2
  18. package/fesm2022/fundamental-ngx-core-combobox.mjs +1 -1
  19. package/fesm2022/fundamental-ngx-core-combobox.mjs.map +1 -1
  20. package/fesm2022/fundamental-ngx-core-date-picker.mjs +7 -6
  21. package/fesm2022/fundamental-ngx-core-date-picker.mjs.map +1 -1
  22. package/fesm2022/fundamental-ngx-core-datetime-picker.mjs +14 -13
  23. package/fesm2022/fundamental-ngx-core-datetime-picker.mjs.map +1 -1
  24. package/fesm2022/fundamental-ngx-core-datetime.mjs +295 -100
  25. package/fesm2022/fundamental-ngx-core-datetime.mjs.map +1 -1
  26. package/fesm2022/fundamental-ngx-core-dialog.mjs +2 -2
  27. package/fesm2022/fundamental-ngx-core-dynamic-page.mjs +2 -2
  28. package/fesm2022/fundamental-ngx-core-dynamic-side-content.mjs +2 -2
  29. package/fesm2022/fundamental-ngx-core-facets.mjs +2 -2
  30. package/fesm2022/fundamental-ngx-core-feed-input.mjs +2 -2
  31. package/fesm2022/fundamental-ngx-core-feed-list-item.mjs +2 -2
  32. package/fesm2022/fundamental-ngx-core-file-uploader.mjs +2 -2
  33. package/fesm2022/fundamental-ngx-core-fixed-card-layout.mjs +2 -2
  34. package/fesm2022/fundamental-ngx-core-flexible-column-layout.mjs +2 -2
  35. package/fesm2022/fundamental-ngx-core-form.mjs +19 -16
  36. package/fesm2022/fundamental-ngx-core-form.mjs.map +1 -1
  37. package/fesm2022/fundamental-ngx-core-generic-tag.mjs +2 -2
  38. package/fesm2022/fundamental-ngx-core-grid-list.mjs +2 -2
  39. package/fesm2022/fundamental-ngx-core-icon.mjs +2 -2
  40. package/fesm2022/fundamental-ngx-core-info-label.mjs +2 -2
  41. package/fesm2022/fundamental-ngx-core-input-group.mjs +2 -2
  42. package/fesm2022/fundamental-ngx-core-layout-grid.mjs +2 -2
  43. package/fesm2022/fundamental-ngx-core-layout-panel.mjs +2 -2
  44. package/fesm2022/fundamental-ngx-core-link.mjs +2 -2
  45. package/fesm2022/fundamental-ngx-core-list.mjs +4 -4
  46. package/fesm2022/fundamental-ngx-core-message-box.mjs +2 -2
  47. package/fesm2022/fundamental-ngx-core-message-page.mjs +2 -2
  48. package/fesm2022/fundamental-ngx-core-message-strip.mjs +2 -2
  49. package/fesm2022/fundamental-ngx-core-message-strip.mjs.map +1 -1
  50. package/fesm2022/fundamental-ngx-core-message-toast.mjs +2 -2
  51. package/fesm2022/fundamental-ngx-core-micro-process-flow.mjs +2 -2
  52. package/fesm2022/fundamental-ngx-core-multi-combobox.mjs +2 -2
  53. package/fesm2022/fundamental-ngx-core-multi-combobox.mjs.map +1 -1
  54. package/fesm2022/fundamental-ngx-core-multi-input.mjs +1 -1
  55. package/fesm2022/fundamental-ngx-core-multi-input.mjs.map +1 -1
  56. package/fesm2022/fundamental-ngx-core-nested-list.mjs +1 -1
  57. package/fesm2022/fundamental-ngx-core-nested-list.mjs.map +1 -1
  58. package/fesm2022/fundamental-ngx-core-notification.mjs +2 -2
  59. package/fesm2022/fundamental-ngx-core-object-attribute.mjs +2 -2
  60. package/fesm2022/fundamental-ngx-core-object-identifier.mjs +2 -2
  61. package/fesm2022/fundamental-ngx-core-object-marker.mjs +2 -2
  62. package/fesm2022/fundamental-ngx-core-object-status.mjs +2 -2
  63. package/fesm2022/fundamental-ngx-core-overflow-layout.mjs +1 -1
  64. package/fesm2022/fundamental-ngx-core-overflow-layout.mjs.map +1 -1
  65. package/fesm2022/fundamental-ngx-core-pagination.mjs +2 -2
  66. package/fesm2022/fundamental-ngx-core-panel.mjs +2 -2
  67. package/fesm2022/fundamental-ngx-core-popover.mjs +110 -6
  68. package/fesm2022/fundamental-ngx-core-popover.mjs.map +1 -1
  69. package/fesm2022/fundamental-ngx-core-product-switch.mjs +3 -3
  70. package/fesm2022/fundamental-ngx-core-product-switch.mjs.map +1 -1
  71. package/fesm2022/fundamental-ngx-core-progress-indicator.mjs +2 -2
  72. package/fesm2022/fundamental-ngx-core-progress-indicator.mjs.map +1 -1
  73. package/fesm2022/fundamental-ngx-core-quick-view.mjs +2 -2
  74. package/fesm2022/fundamental-ngx-core-radio.mjs +2 -2
  75. package/fesm2022/fundamental-ngx-core-rating-indicator.mjs +2 -2
  76. package/fesm2022/fundamental-ngx-core-rating-indicator.mjs.map +1 -1
  77. package/fesm2022/fundamental-ngx-core-resizable-card-layout.mjs +4 -4
  78. package/fesm2022/fundamental-ngx-core-segmented-button.mjs +2 -2
  79. package/fesm2022/fundamental-ngx-core-select.mjs +2 -2
  80. package/fesm2022/fundamental-ngx-core-select.mjs.map +1 -1
  81. package/fesm2022/fundamental-ngx-core-settings.mjs +4 -4
  82. package/fesm2022/fundamental-ngx-core-shellbar.mjs +2 -2
  83. package/fesm2022/fundamental-ngx-core-shellbar.mjs.map +1 -1
  84. package/fesm2022/fundamental-ngx-core-side-navigation.mjs +2 -2
  85. package/fesm2022/fundamental-ngx-core-skeleton.mjs +2 -2
  86. package/fesm2022/fundamental-ngx-core-slider.mjs +2 -2
  87. package/fesm2022/fundamental-ngx-core-slider.mjs.map +1 -1
  88. package/fesm2022/fundamental-ngx-core-split-button.mjs +2 -2
  89. package/fesm2022/fundamental-ngx-core-status-indicator.mjs +2 -2
  90. package/fesm2022/fundamental-ngx-core-step-input.mjs +2 -2
  91. package/fesm2022/fundamental-ngx-core-switch.mjs +2 -2
  92. package/fesm2022/fundamental-ngx-core-table.mjs +4 -4
  93. package/fesm2022/fundamental-ngx-core-tabs.mjs +4 -4
  94. package/fesm2022/fundamental-ngx-core-text.mjs +2 -2
  95. package/fesm2022/fundamental-ngx-core-tile.mjs +2 -2
  96. package/fesm2022/fundamental-ngx-core-time-picker.mjs +8 -17
  97. package/fesm2022/fundamental-ngx-core-time-picker.mjs.map +1 -1
  98. package/fesm2022/fundamental-ngx-core-time.mjs +8 -16
  99. package/fesm2022/fundamental-ngx-core-time.mjs.map +1 -1
  100. package/fesm2022/fundamental-ngx-core-title.mjs +2 -2
  101. package/fesm2022/fundamental-ngx-core-token.mjs +4 -4
  102. package/fesm2022/fundamental-ngx-core-token.mjs.map +1 -1
  103. package/fesm2022/fundamental-ngx-core-toolbar.mjs +2 -2
  104. package/fesm2022/fundamental-ngx-core-toolbar.mjs.map +1 -1
  105. package/fesm2022/fundamental-ngx-core-tree.mjs +2 -2
  106. package/fesm2022/fundamental-ngx-core-upload-collection.mjs +2 -2
  107. package/fesm2022/fundamental-ngx-core-user-menu.mjs +25 -4
  108. package/fesm2022/fundamental-ngx-core-user-menu.mjs.map +1 -1
  109. package/fesm2022/fundamental-ngx-core-vertical-navigation.mjs +4 -4
  110. package/fesm2022/fundamental-ngx-core-wizard.mjs +2 -2
  111. package/package.json +4 -4
  112. package/types/fundamental-ngx-core-calendar.d.ts +5 -12
  113. package/types/fundamental-ngx-core-datetime-picker.d.ts +0 -2
  114. package/types/fundamental-ngx-core-datetime.d.ts +109 -68
  115. package/types/fundamental-ngx-core-form.d.ts +2 -0
  116. package/types/fundamental-ngx-core-popover.d.ts +378 -319
  117. package/types/fundamental-ngx-core-time-picker.d.ts +2 -8
  118. package/types/fundamental-ngx-core-time.d.ts +1 -7
  119. package/types/fundamental-ngx-core-user-menu.d.ts +7 -2
@@ -1,10 +1,8 @@
1
- import { Subject } from 'rxjs';
2
1
  import * as i0 from '@angular/core';
3
- import { InjectionToken, Optional, Inject, Pipe, inject, LOCALE_ID, Injectable, NgModule } from '@angular/core';
2
+ import { signal, InjectionToken, inject, Pipe, LOCALE_ID, Injectable, NgModule } from '@angular/core';
4
3
  import { TranslationResolver, FD_LANGUAGE_SIGNAL } from '@fundamental-ngx/i18n';
5
4
  import { INVALID_DATE_ERROR, range, LETTERS_UNICODE_RANGE } from '@fundamental-ngx/cdk/utils';
6
- import * as i1 from '@angular/cdk/platform';
7
- import { PlatformModule } from '@angular/cdk/platform';
5
+ import { Platform, PlatformModule } from '@angular/cdk/platform';
8
6
 
9
7
  /**
10
8
  * Datetime Adapter is an abstract class that must be implemented by each adapter.
@@ -15,16 +13,15 @@ import { PlatformModule } from '@angular/cdk/platform';
15
13
  class DatetimeAdapter {
16
14
  constructor() {
17
15
  /** @hidden */
18
- this._localeChanges = new Subject();
19
- this.localeChanges = this._localeChanges.asObservable();
16
+ this._locale = signal('', ...(ngDevMode ? [{ debugName: "_locale" }] : []));
17
+ this.locale = this._locale.asReadonly();
20
18
  }
21
19
  /**
22
20
  * Sets the locale used for all dates.
23
21
  * @param locale The new locale.
24
22
  */
25
23
  setLocale(locale) {
26
- this.locale = locale;
27
- this._localeChanges.next();
24
+ this._locale.set(locale);
28
25
  }
29
26
  /**
30
27
  * Set hours, minutes and seconds at once.
@@ -44,12 +41,14 @@ class DatetimeAdapter {
44
41
  * Get Amount of weeks in given month/year
45
42
  * @param year The year of the date
46
43
  * @param month The month of the date
47
- * @param firstDayOfWeek The first day of week. 1 - Sunday, 2 - Monday...
44
+ * @param firstDayOfWeek The first day of week. 1 - Sunday, 2 - Monday, ..., 7 - Saturday
48
45
  * @returns Number of weeks in the given month
49
46
  */
50
47
  getAmountOfWeeks(year, month, firstDayOfWeek) {
51
48
  const firstOfMonth = new Date(year, month - 1, 1);
52
49
  const lastOfMonth = new Date(year, month, 0);
50
+ // firstDayOfWeek is 1-based (1=Sunday, …, 7=Saturday); getDay() is 0-based —
51
+ // `+ 8` normalizes both into the 0–6 mod-7 space.
53
52
  const dayOffset = (firstOfMonth.getDay() - firstDayOfWeek + 8) % 7;
54
53
  const used = dayOffset + lastOfMonth.getDate();
55
54
  return Math.ceil(used / 7);
@@ -77,10 +76,11 @@ class DatetimeAdapter {
77
76
  const DATE_TIME_FORMATS = new InjectionToken('date-formats');
78
77
 
79
78
  class DateFormatPipe {
80
- /** @hidden */
81
- constructor(_dateTimeAdapter, _dateTimeFormats) {
82
- this._dateTimeAdapter = _dateTimeAdapter;
83
- this._dateTimeFormats = _dateTimeFormats;
79
+ constructor() {
80
+ /** @hidden */
81
+ this._dateTimeAdapter = inject(DatetimeAdapter);
82
+ /** @hidden */
83
+ this._dateTimeFormats = inject(DATE_TIME_FORMATS);
84
84
  }
85
85
  /** Format date object */
86
86
  transform(date, noDateMessage = '') {
@@ -91,26 +91,21 @@ class DateFormatPipe {
91
91
  return noDateMessage;
92
92
  }
93
93
  }
94
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFormatPipe, deps: [{ token: DatetimeAdapter }, { token: DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Pipe }); }
94
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
95
95
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DateFormatPipe, isStandalone: true, name: "dateFormat" }); }
96
96
  }
97
97
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFormatPipe, decorators: [{
98
98
  type: Pipe,
99
99
  args: [{
100
- name: 'dateFormat',
101
- standalone: true
100
+ name: 'dateFormat'
102
101
  }]
103
- }], ctorParameters: () => [{ type: DatetimeAdapter }, { type: undefined, decorators: [{
104
- type: Optional
105
- }, {
106
- type: Inject,
107
- args: [DATE_TIME_FORMATS]
108
- }] }] });
102
+ }] });
109
103
  class DateTimeFormatPipe {
110
- /** @hidden */
111
- constructor(_dateTimeAdapter, _dateTimeFormats) {
112
- this._dateTimeAdapter = _dateTimeAdapter;
113
- this._dateTimeFormats = _dateTimeFormats;
104
+ constructor() {
105
+ /** @hidden */
106
+ this._dateTimeAdapter = inject(DatetimeAdapter);
107
+ /** @hidden */
108
+ this._dateTimeFormats = inject(DATE_TIME_FORMATS);
114
109
  }
115
110
  /** Format date object */
116
111
  transform(date, noDateMessage = '') {
@@ -121,25 +116,19 @@ class DateTimeFormatPipe {
121
116
  return noDateMessage;
122
117
  }
123
118
  }
124
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateTimeFormatPipe, deps: [{ token: DatetimeAdapter }, { token: DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Pipe }); }
119
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateTimeFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
125
120
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DateTimeFormatPipe, isStandalone: true, name: "dateTimeFormat" }); }
126
121
  }
127
122
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateTimeFormatPipe, decorators: [{
128
123
  type: Pipe,
129
124
  args: [{
130
- name: 'dateTimeFormat',
131
- standalone: true
125
+ name: 'dateTimeFormat'
132
126
  }]
133
- }], ctorParameters: () => [{ type: DatetimeAdapter }, { type: undefined, decorators: [{
134
- type: Optional
135
- }, {
136
- type: Inject,
137
- args: [DATE_TIME_FORMATS]
138
- }] }] });
127
+ }] });
139
128
  class DateFromNowPipe {
140
- /** @hidden */
141
- constructor(_dateTimeAdapter) {
142
- this._dateTimeAdapter = _dateTimeAdapter;
129
+ constructor() {
130
+ /** @hidden */
131
+ this._dateTimeAdapter = inject(DatetimeAdapter);
143
132
  }
144
133
  /** Format date object */
145
134
  transform(date, noDateMessage = '') {
@@ -156,21 +145,19 @@ class DateFromNowPipe {
156
145
  return '';
157
146
  }
158
147
  }
159
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFromNowPipe, deps: [{ token: DatetimeAdapter }], target: i0.ɵɵFactoryTarget.Pipe }); }
148
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFromNowPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
160
149
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DateFromNowPipe, isStandalone: true, name: "dateFromNow" }); }
161
150
  }
162
151
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFromNowPipe, decorators: [{
163
152
  type: Pipe,
164
153
  args: [{
165
- name: 'dateFromNow',
166
- standalone: true
154
+ name: 'dateFromNow'
167
155
  }]
168
- }], ctorParameters: () => [{ type: DatetimeAdapter }] });
156
+ }] });
169
157
  class DayPeriodFormatPipe {
170
- /** @hidden */
171
- constructor(_dateTimeAdapter, _dateTimeFormats) {
172
- this._dateTimeAdapter = _dateTimeAdapter;
173
- this._dateTimeFormats = _dateTimeFormats;
158
+ constructor() {
159
+ /** @hidden */
160
+ this._dateTimeAdapter = inject(DatetimeAdapter);
174
161
  }
175
162
  /** Format date object for day period */
176
163
  transform(date, customFormat = {}, noDateMessage = '') {
@@ -179,21 +166,15 @@ class DayPeriodFormatPipe {
179
166
  }
180
167
  return this._dateTimeAdapter.format(date, customFormat);
181
168
  }
182
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DayPeriodFormatPipe, deps: [{ token: DatetimeAdapter }, { token: DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Pipe }); }
169
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DayPeriodFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
183
170
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DayPeriodFormatPipe, isStandalone: true, name: "dayPeriodFormat" }); }
184
171
  }
185
172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DayPeriodFormatPipe, decorators: [{
186
173
  type: Pipe,
187
174
  args: [{
188
- name: 'dayPeriodFormat',
189
- standalone: true
175
+ name: 'dayPeriodFormat'
190
176
  }]
191
- }], ctorParameters: () => [{ type: DatetimeAdapter }, { type: undefined, decorators: [{
192
- type: Optional
193
- }, {
194
- type: Inject,
195
- args: [DATE_TIME_FORMATS]
196
- }] }] });
177
+ }] });
197
178
  class TranslateDayPeriodPipe {
198
179
  constructor() {
199
180
  /** @hidden */
@@ -223,7 +204,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
223
204
  type: Pipe,
224
205
  args: [{
225
206
  name: 'translateDayPeriod',
226
- standalone: true,
227
207
  pure: false // required to update the value when the observable is resolved
228
208
  }]
229
209
  }] });
@@ -286,14 +266,14 @@ function convertToDesiredFormat(inputStr) {
286
266
  return inputStr.replace(/\bat\b/i, '').trim();
287
267
  }
288
268
 
289
- /** Adds 0 if number is less then 10 */
290
- function _leftPad(n) {
291
- return n === n % 10 ? `0${n}` : `${n}`;
269
+ /** Pads a number to at least 2 digits. Years are padded to at least 4 digits. */
270
+ function _leftPad(n, minLength = 2) {
271
+ return String(n).padStart(minLength, '0');
292
272
  }
293
- /** Converts date to ISO8601 */
273
+ /** Converts date to ISO 8601 date-time string without timezone designator (`YYYY-MM-DDTHH:mm:ss`). */
294
274
  function toIso8601(fdDate) {
295
275
  return [
296
- [fdDate.year, _leftPad(fdDate.month), _leftPad(fdDate.day)].join('-'),
276
+ [_leftPad(fdDate.year, 4), _leftPad(fdDate.month), _leftPad(fdDate.day)].join('-'),
297
277
  'T',
298
278
  [_leftPad(fdDate.hour), _leftPad(fdDate.minute), _leftPad(fdDate.second)].join(':')
299
279
  ].join('');
@@ -523,11 +503,70 @@ const PM_DAY_PERIOD_DEFAULT = 'PM';
523
503
  */
524
504
  class FdDatetimeAdapter extends DatetimeAdapter {
525
505
  /** @hidden */
526
- constructor(localeId, platform) {
506
+ constructor() {
527
507
  super();
528
- super.setLocale(localeId);
508
+ /** Cached Intl.RelativeTimeFormat instance, invalidated on locale change. */
509
+ this._relativeTimeFormatter = null;
510
+ /** Cached result of _isFormatDayFirst(), invalidated on locale change. */
511
+ this._dayFirstCache = null;
512
+ const localeId = inject(LOCALE_ID, { optional: true });
513
+ const platform = inject(Platform);
514
+ this.setLocale(localeId || 'en-US');
529
515
  this._fixYearsRangeIssue = platform.TRIDENT || platform.EDGE;
530
516
  }
517
+ /** @hidden */
518
+ setLocale(locale) {
519
+ super.setLocale(locale);
520
+ this._relativeTimeFormatter = null;
521
+ this._dayFirstCache = null;
522
+ }
523
+ /** @hidden */
524
+ fromNow(date) {
525
+ if (!this.isValid(date)) {
526
+ return INVALID_DATE_ERROR;
527
+ }
528
+ const now = new Date();
529
+ const target = this._createDateInstanceByFdDate(date);
530
+ const diffMs = target.getTime() - now.getTime();
531
+ const absDiffSec = Math.abs(diffMs / 1000);
532
+ let value;
533
+ let unit;
534
+ if (absDiffSec < 60) {
535
+ value = Math.round(diffMs / 1000);
536
+ unit = 'second';
537
+ }
538
+ else if (absDiffSec < 3600) {
539
+ value = Math.round(diffMs / 60000);
540
+ unit = 'minute';
541
+ }
542
+ else if (absDiffSec < 86400) {
543
+ value = Math.round(diffMs / 3600000);
544
+ unit = 'hour';
545
+ }
546
+ else if (absDiffSec < 2592000) {
547
+ value = Math.round(diffMs / 86400000);
548
+ unit = 'day';
549
+ }
550
+ else if (absDiffSec < 31536000) {
551
+ value = Math.round(diffMs / 2592000000);
552
+ unit = 'month';
553
+ }
554
+ else {
555
+ value = Math.round(diffMs / 31536000000);
556
+ unit = 'year';
557
+ }
558
+ try {
559
+ if (!this._relativeTimeFormatter) {
560
+ this._relativeTimeFormatter = new Intl.RelativeTimeFormat(this.locale(), { numeric: 'auto' });
561
+ }
562
+ return this._relativeTimeFormatter.format(value, unit);
563
+ }
564
+ catch {
565
+ const absValue = Math.abs(value);
566
+ const suffix = value < 0 ? 'ago' : 'from now';
567
+ return `${absValue} ${unit}${absValue !== 1 ? 's' : ''} ${suffix}`;
568
+ }
569
+ }
531
570
  /** Get year */
532
571
  getYear(date) {
533
572
  return date.year;
@@ -567,29 +606,29 @@ class FdDatetimeAdapter extends DatetimeAdapter {
567
606
  }
568
607
  /** Get month names */
569
608
  getMonthNames(style) {
570
- const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { month: style, timeZone: 'utc' });
609
+ const dateTimeFormat = new Intl.DateTimeFormat(this.locale(), { month: style, timeZone: 'utc' });
571
610
  return range(12, (i) => this._stripDirectionalityCharacters(this._format(dateTimeFormat, new Date(2017, i, 1))));
572
611
  }
573
612
  /** Get date names */
574
613
  getDateNames() {
575
- const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { day: 'numeric', timeZone: 'utc' });
614
+ const dateTimeFormat = new Intl.DateTimeFormat(this.locale(), { day: 'numeric', timeZone: 'utc' });
576
615
  return range(31, (i) => this._stripDirectionalityCharacters(this._format(dateTimeFormat, new Date(2017, 0, i + 1))));
577
616
  }
578
617
  /** Get day of week names */
579
618
  getDayOfWeekNames(style) {
580
- const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { weekday: style, timeZone: 'utc' });
619
+ const dateTimeFormat = new Intl.DateTimeFormat(this.locale(), { weekday: style, timeZone: 'utc' });
581
620
  return range(7, (i) => this._stripDirectionalityCharacters(this._format(dateTimeFormat, new Date(2017, 0, i + 1))));
582
621
  }
583
622
  /** Get year name */
584
623
  getYearName(date) {
585
- const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { year: 'numeric', timeZone: 'utc' });
624
+ const dateTimeFormat = new Intl.DateTimeFormat(this.locale(), { year: 'numeric', timeZone: 'utc' });
586
625
  const dateInstance = this._createDateInstanceByFdDate(date);
587
626
  return this._stripDirectionalityCharacters(this._format(dateTimeFormat, dateInstance));
588
627
  }
589
628
  /** Get week name */
590
629
  getWeekName(date) {
591
630
  const weekNumber = this.getWeekNumber(date);
592
- return weekNumber.toLocaleString(this.locale);
631
+ return weekNumber.toLocaleString(this.locale());
593
632
  }
594
633
  /** Get hour names */
595
634
  getHourNames({ meridian, twoDigit }) {
@@ -597,7 +636,7 @@ class FdDatetimeAdapter extends DatetimeAdapter {
597
636
  if (meridian) {
598
637
  hour = hour === 0 || hour === 12 ? 12 : hour % 12;
599
638
  }
600
- return hour.toLocaleString(this.locale, { minimumIntegerDigits: twoDigit ? 2 : 1 });
639
+ return hour.toLocaleString(this.locale(), { minimumIntegerDigits: twoDigit ? 2 : 1 });
601
640
  });
602
641
  }
603
642
  /** Get minute names */
@@ -605,17 +644,17 @@ class FdDatetimeAdapter extends DatetimeAdapter {
605
644
  const length = Math.ceil(60 / minuteStep);
606
645
  return range(length, (index) => {
607
646
  const minute = index * minuteStep;
608
- return minute.toLocaleString(this.locale, { minimumIntegerDigits: twoDigit ? 2 : 1 });
647
+ return minute.toLocaleString(this.locale(), { minimumIntegerDigits: twoDigit ? 2 : 1 });
609
648
  });
610
649
  }
611
650
  /** Get second names */
612
651
  getSecondNames({ twoDigit }) {
613
- return range(60, (second) => second.toLocaleString(this.locale, { minimumIntegerDigits: twoDigit ? 2 : 1 }));
652
+ return range(60, (second) => second.toLocaleString(this.locale(), { minimumIntegerDigits: twoDigit ? 2 : 1 }));
614
653
  }
615
654
  /** Get day period names */
616
655
  getDayPeriodNames() {
617
656
  const DEFAULT_PERIODS = [AM_DAY_PERIOD_DEFAULT, PM_DAY_PERIOD_DEFAULT];
618
- const formatter = new Intl.DateTimeFormat(this.locale, {
657
+ const formatter = new Intl.DateTimeFormat(this.locale(), {
619
658
  hour: 'numeric',
620
659
  minute: 'numeric',
621
660
  hour12: true
@@ -643,20 +682,31 @@ class FdDatetimeAdapter extends DatetimeAdapter {
643
682
  return this._createFdDateFromDateInstance(dateInstance);
644
683
  }
645
684
  /** Set minutes */
646
- setMinutes(date, hours) {
685
+ setMinutes(date, minutes) {
647
686
  const dateInstance = this._createDateInstanceByFdDate(date);
648
- dateInstance.setMinutes(hours);
687
+ dateInstance.setMinutes(minutes);
649
688
  return this._createFdDateFromDateInstance(dateInstance);
650
689
  }
651
690
  /** Set seconds */
652
- setSeconds(date, hours) {
691
+ setSeconds(date, seconds) {
653
692
  const dateInstance = this._createDateInstanceByFdDate(date);
654
- dateInstance.setSeconds(hours);
693
+ dateInstance.setSeconds(seconds);
655
694
  return this._createFdDateFromDateInstance(dateInstance);
656
695
  }
657
696
  /** Get first day of week */
658
697
  getFirstDayOfWeek() {
659
- // can't retrieve this info from Intl object or Date object, default to Sunday.
698
+ try {
699
+ const locale = new Intl.Locale(this.locale());
700
+ const weekInfo = locale.weekInfo ?? locale.getWeekInfo?.();
701
+ if (weekInfo) {
702
+ // Intl.Locale weekInfo uses 1=Monday..7=Sunday
703
+ // Adapter convention is 0=Sunday..6=Saturday
704
+ return weekInfo.firstDay === 7 ? 0 : weekInfo.firstDay;
705
+ }
706
+ }
707
+ catch {
708
+ // Fallback for environments without Intl.Locale.weekInfo
709
+ }
660
710
  return 0;
661
711
  }
662
712
  /** Get number of days in a month */
@@ -703,6 +753,13 @@ class FdDatetimeAdapter extends DatetimeAdapter {
703
753
  parseFormat.hour) {
704
754
  date = this._parseTimeString(value);
705
755
  }
756
+ // Fallback: try locale-aware date parsing when Date.parse() fails
757
+ if (Number.isNaN(date.valueOf()) && typeof value === 'string') {
758
+ const parsed = this._parseDateString(value) ?? this._parseDateTimeString(value);
759
+ if (parsed) {
760
+ date = parsed;
761
+ }
762
+ }
706
763
  return this._createFdDateFromDateInstance(date);
707
764
  }
708
765
  /** Format date object to string */
@@ -744,6 +801,9 @@ class FdDatetimeAdapter extends DatetimeAdapter {
744
801
  }
745
802
  /** Clone a date object */
746
803
  clone(date) {
804
+ if (!date) {
805
+ throw new Error('FdDatetimeAdapter: Cannot clone a null/undefined date.');
806
+ }
747
807
  return new FdDate(date.year, date.month, date.day, date.hour, date.minute, date.second);
748
808
  }
749
809
  /** Check if date object is valid */
@@ -755,6 +815,9 @@ class FdDatetimeAdapter extends DatetimeAdapter {
755
815
  }
756
816
  /** Check if date between given dates */
757
817
  isBetween(dateToCheck, startDate, endDate) {
818
+ if (!dateToCheck || !startDate || !endDate) {
819
+ return false;
820
+ }
758
821
  const date = this._createDateInstanceByFdDate(dateToCheck);
759
822
  const start = this._createDateInstanceByFdDate(startDate);
760
823
  const end = this._createDateInstanceByFdDate(endDate);
@@ -777,7 +840,7 @@ class FdDatetimeAdapter extends DatetimeAdapter {
777
840
  }
778
841
  return this.toIso8601(date1) === this.toIso8601(date2);
779
842
  }
780
- /** Format date object to ISO8601 string */
843
+ /** {@inheritDoc DatetimeAdapter.toIso8601} */
781
844
  toIso8601(fdDate) {
782
845
  return toIso8601(fdDate);
783
846
  }
@@ -837,7 +900,7 @@ class FdDatetimeAdapter extends DatetimeAdapter {
837
900
  }
838
901
  /** Format date using Intl.DateTimeFormat */
839
902
  _formatWithIntl(date, displayFormat) {
840
- const formatter = new Intl.DateTimeFormat(this.locale, displayFormat);
903
+ const formatter = new Intl.DateTimeFormat(this.locale(), displayFormat);
841
904
  const dateInstance = this._createDateInstanceByFdDate(date);
842
905
  return this._stripDirectionalityCharacters(this._format(formatter, dateInstance));
843
906
  }
@@ -888,7 +951,7 @@ class FdDatetimeAdapter extends DatetimeAdapter {
888
951
  * @param hours The hours as a number between 0 - 24
889
952
  * @param minutes The minutes as a number between 0 - 59
890
953
  * @param seconds The seconds as a number between 0 - 59
891
- * @param milliseconds The milliseconds as a number between 0 - 59
954
+ * @param milliseconds The milliseconds as a number between 0 - 999
892
955
  */
893
956
  _createUTCDateInstance(year, month, day, hours = 0, minutes = 0, seconds = 0, milliseconds = 0) {
894
957
  const utcDate = new Date();
@@ -903,34 +966,166 @@ class FdDatetimeAdapter extends DatetimeAdapter {
903
966
  /**
904
967
  * @hidden
905
968
  *
906
- * Since FdDatetimeAdapter can parse only "en-US" locale
907
- * there is no reason to create comprehensive time parse
908
- * that can understand plenty of locales.
909
- *
910
- * @param timeStr Time string to parse (E.g. '10:30 PM')
911
- * @returns date Native date instance
969
+ * Parse a time string into hours, minutes, seconds and apply to today's date.
970
+ * Supports: "14:30", "14:30:45", "10:30 PM", "10:30PM", "14.30" (dot separator).
912
971
  *
972
+ * @param timeStr Time string to parse
973
+ * @returns date Native date instance (Invalid Date if parsing fails)
913
974
  */
914
975
  _parseTimeString(timeStr) {
915
- /**
916
- * Date.parse('10:30 AM') doesn't work so we need do a trick
917
- * and prepend it by a date string.
918
- */
919
- const dateStr = new Intl.DateTimeFormat('en-US').format(new Date());
920
- const dateTimeString = `${dateStr} ${timeStr}`;
921
- return new Date(Date.parse(dateTimeString));
976
+ const match = timeStr.trim().match(/^(\d{1,2})[:.](\d{2})(?:[:.](\d{2}))?\s*([AaPp][Mm])?$/);
977
+ if (!match) {
978
+ return new Date(NaN);
979
+ }
980
+ let hours = parseInt(match[1], 10);
981
+ const minutes = parseInt(match[2], 10);
982
+ const seconds = match[3] ? parseInt(match[3], 10) : 0;
983
+ const period = match[4]?.toUpperCase();
984
+ if (period) {
985
+ // 12-hour format: hours must be 1-12
986
+ if (hours < 1 || hours > 12) {
987
+ return new Date(NaN);
988
+ }
989
+ if (period === 'AM') {
990
+ hours = hours === 12 ? 0 : hours;
991
+ }
992
+ else {
993
+ hours = hours === 12 ? 12 : hours + 12;
994
+ }
995
+ }
996
+ if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) {
997
+ return new Date(NaN);
998
+ }
999
+ const now = new Date();
1000
+ now.setHours(hours, minutes, seconds, 0);
1001
+ return now;
1002
+ }
1003
+ /**
1004
+ * @hidden
1005
+ *
1006
+ * Try to parse a date string with common separators (/, -, .)
1007
+ * using locale awareness for day/month ordering.
1008
+ *
1009
+ * @param value Date string (e.g. "12.03.2026", "03/12/2026", "2026-03-12")
1010
+ * @returns Native Date instance or null if parsing fails
1011
+ */
1012
+ _parseDateString(value) {
1013
+ const match = value.trim().match(/^(\d{1,4})([/\-.])(\d{1,2})\2(\d{1,4})$/);
1014
+ if (!match) {
1015
+ return null;
1016
+ }
1017
+ const g1 = parseInt(match[1], 10);
1018
+ const g2 = parseInt(match[3], 10);
1019
+ const g3 = parseInt(match[4], 10);
1020
+ let year;
1021
+ let month;
1022
+ let day;
1023
+ if (match[1].length === 4) {
1024
+ // YYYY-MM-DD
1025
+ year = g1;
1026
+ month = g2;
1027
+ day = g3;
1028
+ }
1029
+ else if (match[4].length === 4) {
1030
+ // DD/MM/YYYY or MM/DD/YYYY — use locale to disambiguate
1031
+ year = g3;
1032
+ if (this._isFormatDayFirst()) {
1033
+ day = g1;
1034
+ month = g2;
1035
+ }
1036
+ else {
1037
+ month = g1;
1038
+ day = g2;
1039
+ }
1040
+ }
1041
+ else {
1042
+ // Two-digit years are ambiguous — reject
1043
+ return null;
1044
+ }
1045
+ // Validate ranges
1046
+ if (month < 1 || month > 12 || day < 1) {
1047
+ return null;
1048
+ }
1049
+ // Validate day for the given month/year (catches Feb 30, etc.)
1050
+ const maxDay = new Date(year, month, 0).getDate();
1051
+ if (day > maxDay) {
1052
+ return null;
1053
+ }
1054
+ const date = new Date();
1055
+ date.setFullYear(year, month - 1, day);
1056
+ date.setHours(0, 0, 0, 0);
1057
+ return date;
1058
+ }
1059
+ /**
1060
+ * @hidden
1061
+ *
1062
+ * Parse a locale-native datetime string that contains both a date and a time
1063
+ * component (e.g. "20/05/2026 16:33" fr-FR, "20.5.2026, 16:33" de-DE).
1064
+ *
1065
+ * Strategy: split on the first 4-digit year boundary (everything before+including
1066
+ * the year is the date part; everything after the optional ", " separator is the
1067
+ * time part), delegate each half to the existing helpers, then combine.
1068
+ *
1069
+ * @param value Datetime string to parse
1070
+ * @returns Native Date instance or null if parsing fails
1071
+ */
1072
+ _parseDateTimeString(value) {
1073
+ // Match: <date-with-4-digit-year> <optional-comma> <whitespace> <time>
1074
+ // Captures: [1] = date portion, [2] = time portion
1075
+ const m = value.trim().match(/^(.*?\d{4}),?\s+(.+)$/);
1076
+ if (!m) {
1077
+ return null;
1078
+ }
1079
+ const datePart = m[1].trim();
1080
+ const timePart = m[2].trim();
1081
+ const dateOnly = this._parseDateString(datePart);
1082
+ if (!dateOnly) {
1083
+ return null;
1084
+ }
1085
+ const timeParsed = this._parseTimeString(timePart);
1086
+ if (Number.isNaN(timeParsed.valueOf())) {
1087
+ return null;
1088
+ }
1089
+ dateOnly.setHours(timeParsed.getHours(), timeParsed.getMinutes(), timeParsed.getSeconds(), 0);
1090
+ return dateOnly;
1091
+ }
1092
+ /**
1093
+ * @hidden
1094
+ *
1095
+ * Detect whether the current locale formats dates with day before month.
1096
+ * Uses Intl.DateTimeFormat.formatToParts to inspect the locale's ordering.
1097
+ *
1098
+ * @returns true if locale puts day before month (e.g. de-DE, en-GB)
1099
+ */
1100
+ _isFormatDayFirst() {
1101
+ if (this._dayFirstCache !== null) {
1102
+ return this._dayFirstCache;
1103
+ }
1104
+ try {
1105
+ const parts = new Intl.DateTimeFormat(this.locale()).formatToParts(new Date(2020, 0, 2));
1106
+ for (const part of parts) {
1107
+ if (part.type === 'day') {
1108
+ this._dayFirstCache = true;
1109
+ return true;
1110
+ }
1111
+ if (part.type === 'month') {
1112
+ this._dayFirstCache = false;
1113
+ return false;
1114
+ }
1115
+ }
1116
+ }
1117
+ catch {
1118
+ // Fallback: month-first (US convention)
1119
+ }
1120
+ this._dayFirstCache = false;
1121
+ return false;
922
1122
  }
923
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapter, deps: [{ token: LOCALE_ID, optional: true }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Injectable }); }
1123
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
924
1124
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapter }); }
925
1125
  }
926
1126
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapter, decorators: [{
927
1127
  type: Injectable
928
- }], ctorParameters: () => [{ type: undefined, decorators: [{
929
- type: Optional
930
- }, {
931
- type: Inject,
932
- args: [LOCALE_ID]
933
- }] }, { type: i1.Platform }] });
1128
+ }], ctorParameters: () => [] });
934
1129
 
935
1130
  const PIPES = [
936
1131
  DateFormatPipe,