igniteui-webcomponents 7.1.3 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/components/banner/banner.d.ts +53 -17
  3. package/components/banner/banner.js +5 -0
  4. package/components/banner/banner.js.map +1 -1
  5. package/components/button/button-base.d.ts +80 -26
  6. package/components/button/button-base.js +64 -23
  7. package/components/button/button-base.js.map +1 -1
  8. package/components/button/button.d.ts +12 -3
  9. package/components/button/button.js +1 -1
  10. package/components/button/button.js.map +1 -1
  11. package/components/button/icon-button.d.ts +25 -9
  12. package/components/button/icon-button.js +2 -2
  13. package/components/button/icon-button.js.map +1 -1
  14. package/components/button-group/themes/shared/button/button.common.css.js +1 -1
  15. package/components/button-group/themes/shared/button/button.common.css.js.map +1 -1
  16. package/components/button-group/themes/shared/button/button.indigo.css.js +1 -1
  17. package/components/button-group/themes/shared/button/button.indigo.css.js.map +1 -1
  18. package/components/calendar/base.d.ts +5 -4
  19. package/components/calendar/base.js +3 -2
  20. package/components/calendar/base.js.map +1 -1
  21. package/components/calendar/calendar.js +17 -13
  22. package/components/calendar/calendar.js.map +1 -1
  23. package/components/calendar/days-view/days-view.d.ts +1 -0
  24. package/components/calendar/days-view/days-view.js +7 -4
  25. package/components/calendar/days-view/days-view.js.map +1 -1
  26. package/components/calendar/helpers.d.ts +1 -1
  27. package/components/calendar/helpers.js.map +1 -1
  28. package/components/chat/chat-message.js +8 -8
  29. package/components/chat/chat-message.js.map +1 -1
  30. package/components/chat/chat-state.d.ts +3 -1
  31. package/components/chat/chat-state.js +3 -2
  32. package/components/chat/chat-state.js.map +1 -1
  33. package/components/chat/chat.d.ts +5 -1
  34. package/components/chat/chat.js +14 -4
  35. package/components/chat/chat.js.map +1 -1
  36. package/components/checkbox/checkbox.js +1 -0
  37. package/components/checkbox/checkbox.js.map +1 -1
  38. package/components/checkbox/switch.js +1 -0
  39. package/components/checkbox/switch.js.map +1 -1
  40. package/components/combo/combo.d.ts +1 -0
  41. package/components/combo/combo.js +7 -0
  42. package/components/combo/combo.js.map +1 -1
  43. package/components/combo/controllers/navigation.js +3 -0
  44. package/components/combo/controllers/navigation.js.map +1 -1
  45. package/components/common/controllers/command.d.ts +62 -0
  46. package/components/common/controllers/command.js +25 -0
  47. package/components/common/controllers/command.js.map +1 -0
  48. package/components/common/controllers/id-resolver.d.ts +31 -0
  49. package/components/common/controllers/id-resolver.js +136 -0
  50. package/components/common/controllers/id-resolver.js.map +1 -0
  51. package/components/common/i18n/EN/calendar.resources.d.ts +16 -14
  52. package/components/common/i18n/EN/calendar.resources.js +1 -1
  53. package/components/common/i18n/EN/calendar.resources.js.map +1 -1
  54. package/components/common/i18n/EN/chat.resources.d.ts +10 -8
  55. package/components/common/i18n/EN/chat.resources.js.map +1 -1
  56. package/components/common/i18n/EN/date-picker.resources.d.ts +8 -0
  57. package/components/common/i18n/EN/date-picker.resources.js +8 -0
  58. package/components/common/i18n/EN/date-picker.resources.js.map +1 -0
  59. package/components/common/i18n/EN/date-range-picker.resources.d.ts +9 -7
  60. package/components/common/i18n/EN/date-range-picker.resources.js +1 -1
  61. package/components/common/i18n/EN/date-range-picker.resources.js.map +1 -1
  62. package/components/common/i18n/i18n-controller.d.ts +14 -11
  63. package/components/common/i18n/i18n-controller.js +33 -41
  64. package/components/common/i18n/i18n-controller.js.map +1 -1
  65. package/components/common/i18n/utils.d.ts +8 -2
  66. package/components/common/i18n/utils.js +52 -44
  67. package/components/common/i18n/utils.js.map +1 -1
  68. package/components/common/mixins/alert.d.ts +47 -9
  69. package/components/common/mixins/alert.js +55 -12
  70. package/components/common/mixins/alert.js.map +1 -1
  71. package/components/common/mixins/forms/associated.js +11 -0
  72. package/components/common/mixins/forms/associated.js.map +1 -1
  73. package/components/common/mixins/forms/form-transformers.d.ts +1 -1
  74. package/components/common/mixins/forms/form-transformers.js.map +1 -1
  75. package/components/common/mixins/forms/types.d.ts +5 -0
  76. package/components/common/mixins/forms/types.js.map +1 -1
  77. package/components/common/mixins/mask-behavior.d.ts +73 -0
  78. package/components/common/mixins/mask-behavior.js +159 -0
  79. package/components/common/mixins/mask-behavior.js.map +1 -0
  80. package/components/common/templates/input-shell.d.ts +24 -0
  81. package/components/common/templates/input-shell.js +43 -0
  82. package/components/common/templates/input-shell.js.map +1 -0
  83. package/components/common/templates/masked-input.d.ts +39 -0
  84. package/components/common/templates/masked-input.js +37 -0
  85. package/components/common/templates/masked-input.js.map +1 -0
  86. package/components/common/util.d.ts +11 -0
  87. package/components/common/util.js +20 -0
  88. package/components/common/util.js.map +1 -1
  89. package/components/date-picker/date-picker.d.ts +6 -4
  90. package/components/date-picker/date-picker.js +16 -5
  91. package/components/date-picker/date-picker.js.map +1 -1
  92. package/components/date-range-picker/date-range-input.d.ts +60 -0
  93. package/components/date-range-picker/date-range-input.js +251 -0
  94. package/components/date-range-picker/date-range-input.js.map +1 -0
  95. package/components/date-range-picker/date-range-mask-parser.d.ts +106 -0
  96. package/components/date-range-picker/date-range-mask-parser.js +121 -0
  97. package/components/date-range-picker/date-range-mask-parser.js.map +1 -0
  98. package/components/date-range-picker/date-range-picker.d.ts +17 -11
  99. package/components/date-range-picker/date-range-picker.js +89 -61
  100. package/components/date-range-picker/date-range-picker.js.map +1 -1
  101. package/components/date-range-picker/predefined-ranges-area.d.ts +4 -4
  102. package/components/date-range-picker/predefined-ranges-area.js +8 -4
  103. package/components/date-range-picker/predefined-ranges-area.js.map +1 -1
  104. package/components/date-range-picker/validators.d.ts +5 -19
  105. package/components/date-range-picker/validators.js +20 -16
  106. package/components/date-range-picker/validators.js.map +1 -1
  107. package/components/date-time-input/date-time-input.base.d.ts +155 -0
  108. package/components/date-time-input/date-time-input.base.js +275 -0
  109. package/components/date-time-input/date-time-input.base.js.map +1 -0
  110. package/components/date-time-input/date-time-input.d.ts +33 -122
  111. package/components/date-time-input/date-time-input.js +45 -258
  112. package/components/date-time-input/date-time-input.js.map +1 -1
  113. package/components/date-time-input/datetime-mask-parser.d.ts +11 -1
  114. package/components/date-time-input/datetime-mask-parser.js +5 -5
  115. package/components/date-time-input/datetime-mask-parser.js.map +1 -1
  116. package/components/dialog/dialog.d.ts +88 -31
  117. package/components/dialog/dialog.js +29 -31
  118. package/components/dialog/dialog.js.map +1 -1
  119. package/components/file-input/file-input.d.ts +1 -1
  120. package/components/input/input-base.d.ts +2 -10
  121. package/components/input/input-base.js +11 -57
  122. package/components/input/input-base.js.map +1 -1
  123. package/components/input/input.d.ts +1 -1
  124. package/components/input/input.js +1 -0
  125. package/components/input/input.js.map +1 -1
  126. package/components/input/themes/dark/input.shared.css.d.ts +1 -0
  127. package/components/input/themes/dark/input.shared.css.js +3 -0
  128. package/components/input/themes/dark/input.shared.css.js.map +1 -0
  129. package/components/input/themes/light/input.shared.css.js +1 -1
  130. package/components/input/themes/light/input.shared.css.js.map +1 -1
  131. package/components/input/themes/shared/input.common.css.js +1 -1
  132. package/components/input/themes/shared/input.common.css.js.map +1 -1
  133. package/components/input/themes/shared/input.material.css.js +1 -1
  134. package/components/input/themes/shared/input.material.css.js.map +1 -1
  135. package/components/input/themes/themes.js +4 -3
  136. package/components/input/themes/themes.js.map +1 -1
  137. package/components/mask-input/mask-input.d.ts +9 -4
  138. package/components/mask-input/mask-input.js +30 -36
  139. package/components/mask-input/mask-input.js.map +1 -1
  140. package/components/nav-drawer/nav-drawer.d.ts +93 -17
  141. package/components/nav-drawer/nav-drawer.js +148 -21
  142. package/components/nav-drawer/nav-drawer.js.map +1 -1
  143. package/components/nav-drawer/themes/container.base.css.js +1 -1
  144. package/components/nav-drawer/themes/container.base.css.js.map +1 -1
  145. package/components/nav-drawer/themes/shared/container/nav-drawer.common.css.js +1 -1
  146. package/components/nav-drawer/themes/shared/container/nav-drawer.common.css.js.map +1 -1
  147. package/components/nav-drawer/themes/shared/container/nav-drawer.fluent.css.js +1 -1
  148. package/components/nav-drawer/themes/shared/container/nav-drawer.fluent.css.js.map +1 -1
  149. package/components/nav-drawer/themes/shared/container/nav-drawer.indigo.css.js +1 -1
  150. package/components/nav-drawer/themes/shared/container/nav-drawer.indigo.css.js.map +1 -1
  151. package/components/radio/radio.js +1 -0
  152. package/components/radio/radio.js.map +1 -1
  153. package/components/snackbar/snackbar.d.ts +9 -5
  154. package/components/snackbar/snackbar.js +6 -8
  155. package/components/snackbar/snackbar.js.map +1 -1
  156. package/components/snackbar/themes/snackbar.base.css.js +1 -1
  157. package/components/snackbar/themes/snackbar.base.css.js.map +1 -1
  158. package/components/stepper/step.d.ts +1 -1
  159. package/components/stepper/step.js +4 -4
  160. package/components/stepper/step.js.map +1 -1
  161. package/components/toast/themes/toast.base.css.js +1 -1
  162. package/components/toast/themes/toast.base.css.js.map +1 -1
  163. package/components/toast/toast.d.ts +9 -2
  164. package/components/toast/toast.js +0 -2
  165. package/components/toast/toast.js.map +1 -1
  166. package/components/types.d.ts +4 -0
  167. package/components/types.js.map +1 -1
  168. package/custom-elements.json +34882 -28909
  169. package/igniteui-webcomponents.css-data.json +1 -1
  170. package/igniteui-webcomponents.html-data.json +1 -1
  171. package/index.d.ts +5 -2
  172. package/index.js +1 -1
  173. package/index.js.map +1 -1
  174. package/package.json +3 -3
  175. package/skills/igniteui-wc-choose-components/SKILL.md +3 -6
  176. package/skills/igniteui-wc-generate-from-image-design/references/component-mapping.md +4 -2
  177. package/web-types.json +2 -2
  178. package/components/mask-input/mask-input-base.d.ts +0 -51
  179. package/components/mask-input/mask-input-base.js +0 -146
  180. package/components/mask-input/mask-input-base.js.map +0 -1
@@ -0,0 +1,251 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { property } from 'lit/decorators.js';
8
+ import { addThemingController } from '../../theming/theming-controller.js';
9
+ import { CalendarDay } from '../calendar/model.js';
10
+ import { registerComponent } from '../common/definitions/register.js';
11
+ import { formatDisplayDate } from '../common/i18n/i18n-controller.js';
12
+ import { FormValueDateRangeTransformers } from '../common/mixins/forms/form-transformers.js';
13
+ import { createFormValueState } from '../common/mixins/forms/form-value.js';
14
+ import { equal } from '../common/util.js';
15
+ import { DatePartType, } from '../date-time-input/date-part.js';
16
+ import { IgcDateTimeInputBaseComponent, } from '../date-time-input/date-time-input.base.js';
17
+ import { DateParts } from '../date-time-input/datetime-mask-parser.js';
18
+ import { styles } from '../input/themes/input.base.css.js';
19
+ import { styles as shared } from '../input/themes/shared/input.common.css.js';
20
+ import { all } from '../input/themes/themes.js';
21
+ import { DateRangeMaskParser, DateRangePosition, } from './date-range-mask-parser.js';
22
+ export default class IgcDateRangeInputComponent extends IgcDateTimeInputBaseComponent {
23
+ constructor() {
24
+ super(...arguments);
25
+ this._formValue = createFormValueState(this, {
26
+ initialValue: { start: null, end: null },
27
+ transformers: FormValueDateRangeTransformers,
28
+ });
29
+ this._themes = addThemingController(this, all);
30
+ this._parser = new DateRangeMaskParser();
31
+ this._oldValue = null;
32
+ }
33
+ static { this.tagName = 'igc-date-range-input'; }
34
+ static { this.styles = [styles, shared]; }
35
+ static register() {
36
+ registerComponent(IgcDateRangeInputComponent);
37
+ }
38
+ get _datePartDeltas() {
39
+ return {
40
+ date: 1,
41
+ month: 1,
42
+ year: 1,
43
+ };
44
+ }
45
+ set value(value) {
46
+ this._formValue.setValueAndFormState(value);
47
+ this._updateMaskDisplay();
48
+ }
49
+ get value() {
50
+ return this._formValue.value;
51
+ }
52
+ connectedCallback() {
53
+ super.connectedCallback();
54
+ this._initializeDefaultMask();
55
+ this._updateMaskDisplay();
56
+ }
57
+ async _handleFocus() {
58
+ this._focused = true;
59
+ if (this.readOnly) {
60
+ return;
61
+ }
62
+ this._oldValue = this.value;
63
+ if (!this.value || (!this.value.start && !this.value.end)) {
64
+ this._maskedValue = this._parser.emptyMask;
65
+ await this.updateComplete;
66
+ this.select();
67
+ }
68
+ else if (this.displayFormat !== this.inputFormat) {
69
+ this._updateMaskDisplay();
70
+ }
71
+ }
72
+ _handleBlur() {
73
+ const isSameValue = equal(this._oldValue, this.value);
74
+ this._focused = false;
75
+ if (!(this._isMaskComplete() || this._isEmptyMask)) {
76
+ const parsed = this._parser.parseDateRange(this._maskedValue);
77
+ if (parsed && (parsed.start || parsed.end)) {
78
+ this.value = parsed;
79
+ }
80
+ else {
81
+ this.value = null;
82
+ this._maskedValue = '';
83
+ }
84
+ }
85
+ else {
86
+ this._updateMaskDisplay();
87
+ }
88
+ if (!(this.readOnly || isSameValue)) {
89
+ this.emitEvent('igcChange', { detail: this.value });
90
+ }
91
+ super._handleBlur();
92
+ }
93
+ _setCurrentDateTime() {
94
+ const today = CalendarDay.today.native;
95
+ this.value = { start: today, end: today };
96
+ this._emitInputEvent();
97
+ }
98
+ _calculatePartNavigationPosition(inputValue, direction) {
99
+ const cursorPos = this._maskSelection.start;
100
+ const rangeParts = this._parser.rangeParts;
101
+ const currentPart = rangeParts.find((p) => p.type !== DateParts.Literal &&
102
+ cursorPos >= p.start &&
103
+ cursorPos <= p.end);
104
+ const isStartOrEndPart = currentPart &&
105
+ (currentPart.position === DateRangePosition.Start ||
106
+ currentPart.position === DateRangePosition.End);
107
+ if (direction === 0) {
108
+ if (isStartOrEndPart && cursorPos !== currentPart.start) {
109
+ return currentPart.start;
110
+ }
111
+ const prevPart = [...rangeParts]
112
+ .reverse()
113
+ .find((p) => p.type !== DateParts.Literal && p.end < cursorPos);
114
+ return prevPart?.start ?? 0;
115
+ }
116
+ if (isStartOrEndPart && cursorPos !== currentPart.end) {
117
+ return currentPart.end;
118
+ }
119
+ const nextPart = rangeParts.find((p) => p.type !== DateParts.Literal && p.start > cursorPos);
120
+ return nextPart?.end ?? inputValue.length;
121
+ }
122
+ _updateMaskDisplay() {
123
+ if (this._focused) {
124
+ if (this.value?.start || this.value?.end) {
125
+ this._maskedValue = this._buildMaskedValue();
126
+ }
127
+ else if (!this._maskedValue) {
128
+ this._maskedValue = this._parser.emptyMask;
129
+ }
130
+ return;
131
+ }
132
+ this._maskedValue = this._buildDisplayValue();
133
+ }
134
+ _performStep(datePart, delta, isDecrement) {
135
+ if (!this.value?.start && !this.value?.end) {
136
+ const today = CalendarDay.today.native;
137
+ this.value = { start: today, end: today };
138
+ const { start, end } = this._inputSelection;
139
+ this.updateComplete.then(() => this._input?.setSelectionRange(start, end));
140
+ return;
141
+ }
142
+ super._performStep(datePart, delta, isDecrement);
143
+ }
144
+ _commitSpunValue(value) {
145
+ this.value = value;
146
+ }
147
+ _buildDisplayValue() {
148
+ if (!this.value?.start && !this.value?.end) {
149
+ return '';
150
+ }
151
+ const { start, end } = this.value;
152
+ const startStr = start
153
+ ? formatDisplayDate(start, this.locale, this.displayFormat)
154
+ : '';
155
+ const endStr = end
156
+ ? formatDisplayDate(end, this.locale, this.displayFormat)
157
+ : '';
158
+ return startStr && endStr
159
+ ? `${startStr}${this._parser.separator}${endStr}`
160
+ : startStr || endStr;
161
+ }
162
+ _calculateSpunValue(datePart, delta, isDecrement) {
163
+ const range = datePart;
164
+ const part = this._parser.getPartByTypeAndPosition(range.part, range.position);
165
+ const today = CalendarDay.today.native;
166
+ const defaultValue = { start: today, end: today };
167
+ if (!part) {
168
+ return this.value || defaultValue;
169
+ }
170
+ const effectiveDelta = delta ?? this._datePartDeltas[range.part] ?? 1;
171
+ const spinAmount = effectiveDelta * (isDecrement ? -1 : 1);
172
+ const amPmValue = part.type === DatePartType.AmPm
173
+ ? this._maskedValue.substring(part.start, part.end)
174
+ : undefined;
175
+ return this._parser.spinDateRangePart(part, spinAmount, this.value, this.spinLoop, amPmValue);
176
+ }
177
+ _getDatePartAtCursor() {
178
+ const cursorPos = this._inputSelection.start;
179
+ let part = this._parser.getDateRangePartForCursor(cursorPos);
180
+ if (part?.type === DatePartType.Literal) {
181
+ const nextPart = this._parser.rangeParts.find((p) => p.start >= cursorPos && p.type !== DatePartType.Literal);
182
+ if (nextPart) {
183
+ part = nextPart;
184
+ }
185
+ else {
186
+ part = this._parser.rangeParts.findLast((p) => p.end <= cursorPos && p.type !== DatePartType.Literal);
187
+ }
188
+ }
189
+ if (part && part.type !== DatePartType.Literal) {
190
+ return {
191
+ part: part.type,
192
+ position: part.position,
193
+ };
194
+ }
195
+ return undefined;
196
+ }
197
+ _getDefaultDatePart() {
198
+ const firstPart = this._parser.getFirstDatePartForPosition(DateRangePosition.Start);
199
+ if (firstPart) {
200
+ return {
201
+ part: firstPart.type,
202
+ position: DateRangePosition.Start,
203
+ };
204
+ }
205
+ return undefined;
206
+ }
207
+ _buildMaskedValue() {
208
+ return this._parser.formatDateRange(this.value);
209
+ }
210
+ _applyMask(string) {
211
+ const previous = this._parser.mask;
212
+ this._parser.mask = string;
213
+ this._defaultMask = string;
214
+ this._parser.prompt = this.prompt;
215
+ if (!this.placeholder || previous === this.placeholder) {
216
+ this.placeholder = this._parser.mask;
217
+ }
218
+ }
219
+ _syncValueFromMask() {
220
+ if (!this._isMaskComplete()) {
221
+ this.value = null;
222
+ return;
223
+ }
224
+ const parsed = this._parser.parseDateRange(this._maskedValue);
225
+ this.value = parsed?.start || parsed?.end ? parsed : null;
226
+ }
227
+ stepUp(datePart, delta) {
228
+ super.stepUp(datePart, delta);
229
+ }
230
+ stepDown(datePart, delta) {
231
+ super.stepDown(datePart, delta);
232
+ }
233
+ clear() {
234
+ this._maskedValue = '';
235
+ this.value = null;
236
+ }
237
+ hasDateParts() {
238
+ return this._parser.rangeParts.some((p) => p.type === DatePartType.Date ||
239
+ p.type === DatePartType.Month ||
240
+ p.type === DatePartType.Year);
241
+ }
242
+ hasTimeParts() {
243
+ return this._parser.rangeParts.some((p) => p.type === DatePartType.Hours ||
244
+ p.type === DatePartType.Minutes ||
245
+ p.type === DatePartType.Seconds);
246
+ }
247
+ }
248
+ __decorate([
249
+ property({ attribute: false })
250
+ ], IgcDateRangeInputComponent.prototype, "value", null);
251
+ //# sourceMappingURL=date-range-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range-input.js","sourceRoot":"","sources":["../../../src/components/date-range-picker/date-range-input.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\nimport { addThemingController } from '../../theming/theming-controller.js';\nimport { CalendarDay } from '../calendar/model.js';\nimport { registerComponent } from '../common/definitions/register.js';\nimport { formatDisplayDate } from '../common/i18n/i18n-controller.js';\nimport { FormValueDateRangeTransformers } from '../common/mixins/forms/form-transformers.js';\nimport { createFormValueState } from '../common/mixins/forms/form-value.js';\nimport { equal } from '../common/util.js';\nimport {\n type DatePart,\n type DatePartDeltas,\n DatePartType,\n} from '../date-time-input/date-part.js';\nimport {\n IgcDateTimeInputBaseComponent,\n type IgcDateTimeInputComponentEventMap,\n} from '../date-time-input/date-time-input.base.js';\nimport { DateParts } from '../date-time-input/datetime-mask-parser.js';\nimport { styles } from '../input/themes/input.base.css.js';\nimport { styles as shared } from '../input/themes/shared/input.common.css.js';\nimport { all } from '../input/themes/themes.js';\nimport type { DateRangeValue } from '../types.js';\nimport {\n DateRangeMaskParser,\n type DateRangePart,\n DateRangePosition,\n} from './date-range-mask-parser.js';\n\nexport interface IgcDateRangeInputEventMap extends Omit<\n IgcDateTimeInputComponentEventMap,\n 'igcChange'\n> {\n igcChange: CustomEvent<DateRangeValue | null>;\n}\n\nexport default class IgcDateRangeInputComponent extends IgcDateTimeInputBaseComponent {\n public static readonly tagName = 'igc-date-range-input';\n public static styles = [styles, shared];\n\n /* blazorSuppress */\n public static register() {\n registerComponent(IgcDateRangeInputComponent);\n }\n\n //#region Private state and properties\n\n protected override readonly _formValue = createFormValueState(this, {\n initialValue: { start: null, end: null },\n transformers: FormValueDateRangeTransformers,\n });\n\n protected override readonly _themes = addThemingController(this, all);\n protected override readonly _parser = new DateRangeMaskParser();\n\n protected override get _datePartDeltas(): DatePartDeltas {\n return {\n date: 1,\n month: 1,\n year: 1,\n };\n }\n\n protected _oldValue: DateRangeValue | null = null;\n\n // #endregion\n\n // #region Public attributes and properties\n\n /* @tsTwoWayProperty(true, \"igcChange\", \"detail\", false, true) */\n /**\n * The value of the date range input.\n * @attr\n */\n @property({ attribute: false })\n public set value(value: DateRangeValue | null) {\n this._formValue.setValueAndFormState(value);\n this._updateMaskDisplay();\n }\n\n public get value(): DateRangeValue | null {\n return this._formValue.value;\n }\n\n // #endregion\n\n // #region Lifecycle Hooks\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this._initializeDefaultMask();\n this._updateMaskDisplay();\n }\n\n // #endregion\n\n // #region Event Handlers Overrides\n\n protected override async _handleFocus(): Promise<void> {\n this._focused = true;\n\n if (this.readOnly) {\n return;\n }\n\n this._oldValue = this.value;\n\n if (!this.value || (!this.value.start && !this.value.end)) {\n this._maskedValue = this._parser.emptyMask;\n await this.updateComplete;\n this.select();\n } else if (this.displayFormat !== this.inputFormat) {\n this._updateMaskDisplay();\n }\n }\n\n protected override _handleBlur(): void {\n const isSameValue = equal(this._oldValue, this.value);\n\n this._focused = false;\n\n if (!(this._isMaskComplete() || this._isEmptyMask)) {\n const parsed = this._parser.parseDateRange(this._maskedValue);\n\n if (parsed && (parsed.start || parsed.end)) {\n this.value = parsed;\n } else {\n this.value = null;\n this._maskedValue = '';\n }\n } else {\n this._updateMaskDisplay();\n }\n\n if (!(this.readOnly || isSameValue)) {\n this.emitEvent('igcChange', { detail: this.value });\n }\n\n super._handleBlur();\n }\n\n // #endregion\n\n // #region Keybindings overrides\n\n protected override _setCurrentDateTime(): void {\n const today = CalendarDay.today.native;\n this.value = { start: today, end: today };\n this._emitInputEvent();\n }\n\n protected override _calculatePartNavigationPosition(\n inputValue: string,\n direction: number\n ): number {\n const cursorPos = this._maskSelection.start;\n const rangeParts = this._parser.rangeParts;\n\n const currentPart = rangeParts.find(\n (p) =>\n p.type !== DateParts.Literal &&\n cursorPos >= p.start &&\n cursorPos <= p.end\n );\n\n const isStartOrEndPart =\n currentPart &&\n (currentPart.position === DateRangePosition.Start ||\n currentPart.position === DateRangePosition.End);\n\n if (direction === 0) {\n // Backward: if inside a start/end part, move to its start; else, move to previous part's start\n if (isStartOrEndPart && cursorPos !== currentPart.start) {\n return currentPart.start;\n }\n const prevPart = [...rangeParts]\n .reverse()\n .find((p) => p.type !== DateParts.Literal && p.end < cursorPos);\n return prevPart?.start ?? 0;\n }\n\n // Forward: if inside a start/end part, move to its end; else, move to next part's end\n if (isStartOrEndPart && cursorPos !== currentPart.end) {\n return currentPart.end;\n }\n const nextPart = rangeParts.find(\n (p) => p.type !== DateParts.Literal && p.start > cursorPos\n );\n return nextPart?.end ?? inputValue.length;\n }\n\n // #endregion\n\n // #region Internal API Overrides\n\n protected override _updateMaskDisplay(): void {\n if (this._focused) {\n // Only reset mask from value when value is non-null (i.e. after spinning or programmatic set).\n // When value is null the user is mid-typing — leave _maskedValue unchanged.\n if (this.value?.start || this.value?.end) {\n this._maskedValue = this._buildMaskedValue();\n } else if (!this._maskedValue) {\n this._maskedValue = this._parser.emptyMask;\n }\n return;\n }\n\n this._maskedValue = this._buildDisplayValue();\n }\n\n protected override _performStep(\n datePart: unknown,\n delta: number | undefined,\n isDecrement: boolean\n ): void {\n // If no value exists, set to today's date first\n if (!this.value?.start && !this.value?.end) {\n const today = CalendarDay.today.native;\n this.value = { start: today, end: today };\n const { start, end } = this._inputSelection;\n this.updateComplete.then(() =>\n this._input?.setSelectionRange(start, end)\n );\n return;\n }\n\n super._performStep(datePart, delta, isDecrement);\n }\n\n protected override _commitSpunValue(value: unknown): void {\n this.value = value as DateRangeValue;\n }\n\n protected override _buildDisplayValue(): string {\n if (!this.value?.start && !this.value?.end) {\n return '';\n }\n\n const { start, end } = this.value;\n const startStr = start\n ? formatDisplayDate(start, this.locale, this.displayFormat)\n : '';\n const endStr = end\n ? formatDisplayDate(end, this.locale, this.displayFormat)\n : '';\n return startStr && endStr\n ? `${startStr}${this._parser.separator}${endStr}`\n : startStr || endStr;\n }\n\n protected override _calculateSpunValue(\n datePart: unknown,\n delta: number | undefined,\n isDecrement: boolean\n ): DateRangeValue {\n const range = datePart as DateRangePart;\n const part = this._parser.getPartByTypeAndPosition(\n range.part as DatePartType,\n range.position\n );\n\n const today = CalendarDay.today.native;\n const defaultValue = { start: today, end: today };\n\n if (!part) {\n return this.value || defaultValue;\n }\n\n const effectiveDelta =\n delta ?? this._datePartDeltas[range.part as keyof DatePartDeltas] ?? 1;\n const spinAmount = effectiveDelta * (isDecrement ? -1 : 1);\n\n // For AM/PM spinning, extract the current AM/PM value from the mask\n const amPmValue =\n part.type === DatePartType.AmPm\n ? this._maskedValue.substring(part.start, part.end)\n : undefined;\n\n return this._parser.spinDateRangePart(\n part,\n spinAmount,\n this.value,\n this.spinLoop,\n amPmValue\n );\n }\n\n /**\n * Gets the date range part at the current cursor position.\n * If the cursor is at a literal, finds the nearest non-literal part.\n * Returns undefined if no valid part is found.\n */\n protected override _getDatePartAtCursor(): DateRangePart | undefined {\n const cursorPos = this._inputSelection.start;\n let part = this._parser.getDateRangePartForCursor(cursorPos);\n\n // If cursor is at a literal, find the nearest non-literal part\n if (part?.type === DatePartType.Literal) {\n const nextPart = this._parser.rangeParts.find(\n (p) => p.start >= cursorPos && p.type !== DatePartType.Literal\n );\n if (nextPart) {\n part = nextPart;\n } else {\n part = this._parser.rangeParts.findLast(\n (p) => p.end <= cursorPos && p.type !== DatePartType.Literal\n );\n }\n }\n\n if (part && part.type !== DatePartType.Literal) {\n return {\n part: part.type as DatePart,\n position: part.position,\n };\n }\n\n return undefined;\n }\n\n /**\n * Gets the default date range part to target when the input is not focused.\n * Returns the first date part at the start position.\n */\n protected override _getDefaultDatePart(): DateRangePart | undefined {\n const firstPart = this._parser.getFirstDatePartForPosition(\n DateRangePosition.Start\n );\n if (firstPart) {\n return {\n part: firstPart.type as DatePart,\n position: DateRangePosition.Start,\n };\n }\n\n return undefined;\n }\n\n protected override _buildMaskedValue(): string {\n return this._parser.formatDateRange(this.value);\n }\n\n protected override _applyMask(string: string): void {\n const previous = this._parser.mask;\n\n this._parser.mask = string;\n this._defaultMask = string;\n this._parser.prompt = this.prompt;\n\n // Update placeholder if not set or if it matches the previous format\n if (!this.placeholder || previous === this.placeholder) {\n this.placeholder = this._parser.mask;\n }\n }\n\n protected override _syncValueFromMask(): void {\n if (!this._isMaskComplete()) {\n this.value = null;\n return;\n }\n\n const parsed = this._parser.parseDateRange(this._maskedValue);\n this.value = parsed?.start || parsed?.end ? parsed : null;\n }\n\n // #region Public API Overrides\n\n /** Increments a date/time portion. */\n public override stepUp(datePart?: DateRangePart, delta?: number): void {\n super.stepUp(datePart, delta);\n }\n\n /** Decrements a date/time portion. */\n public override stepDown(datePart?: DateRangePart, delta?: number): void {\n super.stepDown(datePart, delta);\n }\n\n /** Clears the input element of user input. */\n public override clear(): void {\n this._maskedValue = '';\n this.value = null;\n }\n\n public override hasDateParts(): boolean {\n return this._parser.rangeParts.some(\n (p) =>\n p.type === DatePartType.Date ||\n p.type === DatePartType.Month ||\n p.type === DatePartType.Year\n );\n }\n\n public override hasTimeParts(): boolean {\n return this._parser.rangeParts.some(\n (p) =>\n p.type === DatePartType.Hours ||\n p.type === DatePartType.Minutes ||\n p.type === DatePartType.Seconds\n );\n }\n\n // #endregion\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'igc-date-range-input': IgcDateRangeInputComponent;\n }\n}\n"]}
@@ -0,0 +1,106 @@
1
+ import { type DatePart, DatePartType, type IDatePart } from '../date-time-input/date-part.js';
2
+ import { type DateTimeMaskOptions } from '../date-time-input/datetime-mask-parser.js';
3
+ import { MaskParser } from '../mask-input/mask-parser.js';
4
+ import type { DateRangeValue } from '../types.js';
5
+ export interface DateRangePart {
6
+ part: DatePart;
7
+ position: DateRangePosition;
8
+ }
9
+ /** Position of a date part within the date range */
10
+ export declare enum DateRangePosition {
11
+ Start = "start",
12
+ End = "end",
13
+ Separator = "separator"
14
+ }
15
+ /** Extended date part with range position information */
16
+ export interface IDateRangePart extends IDatePart {
17
+ position: DateRangePosition;
18
+ }
19
+ /** Options for the DateRangeMaskParser */
20
+ export interface DateRangeMaskOptions extends DateTimeMaskOptions {
21
+ /** Separator (defaults to ' - ') */
22
+ separator?: string;
23
+ }
24
+ /**
25
+ * A specialized mask parser for date range input fields.
26
+ * Uses composition with two DateTimeMaskParser instances to handle start and end dates.
27
+ *
28
+ * Accepts a single date format (e.g., 'MM/dd/yyyy') which creates two parsers
29
+ * internally, one for the start date and one for the end date.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const parser = new DateRangeMaskParser({ format: 'MM/dd/yyyy' });
34
+ * parser.parseDateRange('12/25/2023 - 12/31/2023'); // Returns DateRangeValue
35
+ * parser.formatDateRange({ start: date1, end: date2 }); // Returns formatted string
36
+ * ```
37
+ */
38
+ export declare class DateRangeMaskParser extends MaskParser {
39
+ private _startParser;
40
+ private _endParser;
41
+ /** Cached date range parts with position information */
42
+ private _rangeParts;
43
+ /** The separator between start and end dates */
44
+ private _separator;
45
+ /** Start position of the separator in the mask */
46
+ private _separatorStart;
47
+ /** End position of the separator in the mask */
48
+ private _separatorEnd;
49
+ /**
50
+ * Gets the parsed date range parts with position information.
51
+ */
52
+ get rangeParts(): ReadonlyArray<IDateRangePart>;
53
+ /**
54
+ * Gets the separator string used between start and end dates.
55
+ */
56
+ get separator(): string;
57
+ constructor(options?: DateRangeMaskOptions);
58
+ /**
59
+ * Overrides base class to convert date format to mask format
60
+ * before parsing literals. This ensures date format characters
61
+ * (M, d, y, etc.) are properly converted to mask characters (0, L).
62
+ */
63
+ protected _parseMaskLiterals(): void;
64
+ /**
65
+ * Builds the range parts array by combining parts from start and end parsers
66
+ * and adding position information.
67
+ */
68
+ private _buildRangeParts;
69
+ /**
70
+ * Sets a new date format and updates both parsers.
71
+ */
72
+ set mask(value: string);
73
+ get mask(): string;
74
+ /**
75
+ * Parses a masked string into a DateRangeValue using the two internal parsers.
76
+ * Returns null if the string cannot be parsed.
77
+ */
78
+ parseDateRange(masked: string): DateRangeValue | null;
79
+ /**
80
+ * Formats a DateRangeValue into a masked string using the two internal parsers.
81
+ */
82
+ formatDateRange(range: DateRangeValue | null): string;
83
+ /**
84
+ * Gets the date range part at a cursor position.
85
+ * Uses exclusive end for precise character targeting.
86
+ */
87
+ getDateRangePartAtPosition(position: number): IDateRangePart | undefined;
88
+ /**
89
+ * Gets the date range part for cursor (inclusive end).
90
+ * Handles the edge case where cursor is at the end of the last part.
91
+ */
92
+ getDateRangePartForCursor(position: number): IDateRangePart | undefined;
93
+ /**
94
+ * Gets a specific part type for a position.
95
+ */
96
+ getPartByTypeAndPosition(type: DatePartType, position: DateRangePosition): IDateRangePart | undefined;
97
+ /**
98
+ * Gets the first non-literal date part for a position.
99
+ */
100
+ getFirstDatePartForPosition(position: DateRangePosition): IDateRangePart | undefined;
101
+ /**
102
+ * Spins a date part within the range (for stepUp/stepDown functionality).
103
+ * Delegates to the underlying date part's spin method.
104
+ */
105
+ spinDateRangePart(part: IDateRangePart, delta: number, currentValue: DateRangeValue | null, spinLoop: boolean, amPmValue?: string): DateRangeValue;
106
+ }
@@ -0,0 +1,121 @@
1
+ import { DatePartType, } from '../date-time-input/date-part.js';
2
+ import { DateTimeMaskParser, DEFAULT_DATETIME_FORMAT, } from '../date-time-input/datetime-mask-parser.js';
3
+ import { MaskParser } from '../mask-input/mask-parser.js';
4
+ export var DateRangePosition;
5
+ (function (DateRangePosition) {
6
+ DateRangePosition["Start"] = "start";
7
+ DateRangePosition["End"] = "end";
8
+ DateRangePosition["Separator"] = "separator";
9
+ })(DateRangePosition || (DateRangePosition = {}));
10
+ const DEFAULT_SEPARATOR = ' - ';
11
+ export class DateRangeMaskParser extends MaskParser {
12
+ get rangeParts() {
13
+ return this._rangeParts;
14
+ }
15
+ get separator() {
16
+ return this._separator;
17
+ }
18
+ constructor(options) {
19
+ const format = options?.format || DEFAULT_DATETIME_FORMAT;
20
+ const separator = options?.separator || DEFAULT_SEPARATOR;
21
+ const promptCharacter = options?.promptCharacter;
22
+ const rangeFormat = `${format}${separator}${format}`;
23
+ super(options?.promptCharacter
24
+ ? { format: rangeFormat, promptCharacter: options.promptCharacter }
25
+ : { format: rangeFormat });
26
+ this._rangeParts = [];
27
+ this._startParser = new DateTimeMaskParser({ format, promptCharacter });
28
+ this._endParser = new DateTimeMaskParser({ format, promptCharacter });
29
+ this._separator = separator;
30
+ this._separatorStart = this._startParser.mask.length;
31
+ this._separatorEnd = this._separatorStart + separator.length;
32
+ this._buildRangeParts();
33
+ }
34
+ _parseMaskLiterals() {
35
+ const dateFormat = this._options.format;
36
+ const maskFormat = DateTimeMaskParser.convertDateFormatToMaskFormat(dateFormat);
37
+ const originalFormat = this._options.format;
38
+ this._options.format = maskFormat;
39
+ super._parseMaskLiterals();
40
+ this._options.format = originalFormat;
41
+ }
42
+ _buildRangeParts() {
43
+ const startParts = this._startParser.dateParts.map((part) => ({
44
+ ...part,
45
+ position: DateRangePosition.Start,
46
+ getValue: part.getValue.bind(part),
47
+ validate: part.validate.bind(part),
48
+ spin: part.spin.bind(part),
49
+ }));
50
+ const endParts = this._endParser.dateParts.map((part) => ({
51
+ ...part,
52
+ start: part.start + this._separatorEnd,
53
+ end: part.end + this._separatorEnd,
54
+ position: DateRangePosition.End,
55
+ getValue: part.getValue.bind(part),
56
+ validate: part.validate.bind(part),
57
+ spin: part.spin.bind(part),
58
+ }));
59
+ this._rangeParts = [...startParts, ...endParts];
60
+ }
61
+ set mask(value) {
62
+ this._startParser.mask = value;
63
+ this._endParser.mask = value;
64
+ this._separatorStart = this._startParser.mask.length;
65
+ this._separatorEnd = this._separatorStart + this._separator.length;
66
+ const rangeFormat = `${value}${this._separator}${value}`;
67
+ super.mask = rangeFormat;
68
+ this._buildRangeParts();
69
+ }
70
+ get mask() {
71
+ return super.mask;
72
+ }
73
+ parseDateRange(masked) {
74
+ if (!masked || masked === this.emptyMask) {
75
+ return null;
76
+ }
77
+ const startString = masked.substring(0, this._separatorStart);
78
+ const endString = masked.substring(this._separatorEnd);
79
+ const start = this._startParser.parseDate(startString);
80
+ const end = this._endParser.parseDate(endString);
81
+ return { start, end };
82
+ }
83
+ formatDateRange(range) {
84
+ const startString = range?.start
85
+ ? this._startParser.formatDate(range.start)
86
+ : this._startParser.emptyMask;
87
+ const endString = range?.end
88
+ ? this._endParser.formatDate(range.end)
89
+ : this._endParser.emptyMask;
90
+ return startString + this._separator + endString;
91
+ }
92
+ getDateRangePartAtPosition(position) {
93
+ return this._rangeParts.find((part) => position >= part.start && position < part.end);
94
+ }
95
+ getDateRangePartForCursor(position) {
96
+ return this._rangeParts.find((part) => position >= part.start && position <= part.end);
97
+ }
98
+ getPartByTypeAndPosition(type, position) {
99
+ return this._rangeParts.find((p) => p.type === type && p.position === position);
100
+ }
101
+ getFirstDatePartForPosition(position) {
102
+ return this._rangeParts.find((p) => p.position === position && p.type !== DatePartType.Literal);
103
+ }
104
+ spinDateRangePart(part, delta, currentValue, spinLoop, amPmValue) {
105
+ const value = currentValue || { start: null, end: null };
106
+ const targetDate = part.position === DateRangePosition.Start ? value.start : value.end;
107
+ const dateToSpin = targetDate || new Date();
108
+ const newDate = new Date(dateToSpin.getTime());
109
+ const spinOptions = {
110
+ date: newDate,
111
+ spinLoop,
112
+ originalDate: dateToSpin,
113
+ amPmValue,
114
+ };
115
+ part.spin(delta, spinOptions);
116
+ return part.position === DateRangePosition.Start
117
+ ? { ...value, start: newDate }
118
+ : { ...value, end: newDate };
119
+ }
120
+ }
121
+ //# sourceMappingURL=date-range-mask-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range-mask-parser.js","sourceRoot":"","sources":["../../../src/components/date-range-picker/date-range-mask-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type DatePart,\n DatePartType,\n type IDatePart,\n type SpinOptions,\n} from '../date-time-input/date-part.js';\nimport {\n type DateTimeMaskOptions,\n DateTimeMaskParser,\n DEFAULT_DATETIME_FORMAT,\n} from '../date-time-input/datetime-mask-parser.js';\nimport { MaskParser } from '../mask-input/mask-parser.js';\nimport type { DateRangeValue } from '../types.js';\n\n//#region Types and Enums\n\nexport interface DateRangePart {\n part: DatePart;\n position: DateRangePosition;\n}\n\n/** Position of a date part within the date range */\nexport enum DateRangePosition {\n Start = 'start',\n End = 'end',\n Separator = 'separator',\n}\n\n/** Extended date part with range position information */\nexport interface IDateRangePart extends IDatePart {\n position: DateRangePosition;\n}\n\n/** Options for the DateRangeMaskParser */\nexport interface DateRangeMaskOptions extends DateTimeMaskOptions {\n /** Separator (defaults to ' - ') */\n separator?: string;\n}\n\n//#endregion\n\n//#region Constants\n\n/** Default separator between start and end dates */\nconst DEFAULT_SEPARATOR = ' - ';\n\n//#endregion\n\n/**\n * A specialized mask parser for date range input fields.\n * Uses composition with two DateTimeMaskParser instances to handle start and end dates.\n *\n * Accepts a single date format (e.g., 'MM/dd/yyyy') which creates two parsers\n * internally, one for the start date and one for the end date.\n *\n * @example\n * ```ts\n * const parser = new DateRangeMaskParser({ format: 'MM/dd/yyyy' });\n * parser.parseDateRange('12/25/2023 - 12/31/2023'); // Returns DateRangeValue\n * parser.formatDateRange({ start: date1, end: date2 }); // Returns formatted string\n * ```\n */\nexport class DateRangeMaskParser extends MaskParser {\n private _startParser: DateTimeMaskParser;\n private _endParser: DateTimeMaskParser;\n\n /** Cached date range parts with position information */\n private _rangeParts: IDateRangePart[] = [];\n\n /** The separator between start and end dates */\n private _separator: string;\n\n /** Start position of the separator in the mask */\n private _separatorStart: number;\n\n /** End position of the separator in the mask */\n private _separatorEnd: number;\n\n /**\n * Gets the parsed date range parts with position information.\n */\n public get rangeParts(): ReadonlyArray<IDateRangePart> {\n return this._rangeParts;\n }\n\n /**\n * Gets the separator string used between start and end dates.\n */\n public get separator(): string {\n return this._separator;\n }\n\n constructor(options?: DateRangeMaskOptions) {\n const format = options?.format || DEFAULT_DATETIME_FORMAT;\n const separator = options?.separator || DEFAULT_SEPARATOR;\n const promptCharacter = options?.promptCharacter;\n\n // Build the combined range format for the parent MaskParser\n const rangeFormat = `${format}${separator}${format}`;\n\n super(\n options?.promptCharacter\n ? { format: rangeFormat, promptCharacter: options.promptCharacter }\n : { format: rangeFormat }\n );\n\n // Create two parsers for start and end dates\n this._startParser = new DateTimeMaskParser({ format, promptCharacter });\n this._endParser = new DateTimeMaskParser({ format, promptCharacter });\n this._separator = separator;\n\n this._separatorStart = this._startParser.mask.length;\n this._separatorEnd = this._separatorStart + separator.length;\n\n this._buildRangeParts();\n }\n\n //#region Mask Format Conversion\n\n /**\n * Overrides base class to convert date format to mask format\n * before parsing literals. This ensures date format characters\n * (M, d, y, etc.) are properly converted to mask characters (0, L).\n */\n protected override _parseMaskLiterals(): void {\n // Convert the range format to mask format\n // e.g., \"M/d/yyyy - M/d/yyyy\" → \"0/0/0000 - 0/0/0000\"\n const dateFormat = this._options.format;\n const maskFormat =\n DateTimeMaskParser.convertDateFormatToMaskFormat(dateFormat);\n\n // Temporarily set the converted format for base class parsing\n const originalFormat = this._options.format;\n this._options.format = maskFormat;\n\n super._parseMaskLiterals();\n\n // Restore the original date format\n this._options.format = originalFormat;\n }\n\n //#endregion\n\n /**\n * Builds the range parts array by combining parts from start and end parsers\n * and adding position information.\n */\n private _buildRangeParts(): void {\n const startParts = this._startParser.dateParts.map(\n (part): IDateRangePart => ({\n ...part,\n position: DateRangePosition.Start,\n getValue: part.getValue.bind(part),\n validate: part.validate.bind(part),\n spin: part.spin.bind(part),\n })\n );\n\n const endParts = this._endParser.dateParts.map(\n (part): IDateRangePart => ({\n ...part,\n // Adjust positions for end date (offset by separator)\n start: part.start + this._separatorEnd,\n end: part.end + this._separatorEnd,\n position: DateRangePosition.End,\n getValue: part.getValue.bind(part),\n validate: part.validate.bind(part),\n spin: part.spin.bind(part),\n })\n );\n\n this._rangeParts = [...startParts, ...endParts];\n }\n\n /**\n * Sets a new date format and updates both parsers.\n */\n public override set mask(value: string) {\n this._startParser.mask = value;\n this._endParser.mask = value;\n\n this._separatorStart = this._startParser.mask.length;\n this._separatorEnd = this._separatorStart + this._separator.length;\n\n const rangeFormat = `${value}${this._separator}${value}`;\n super.mask = rangeFormat;\n\n this._buildRangeParts();\n }\n\n public override get mask(): string {\n return super.mask;\n }\n\n //#region Date Range Parsing\n\n /**\n * Parses a masked string into a DateRangeValue using the two internal parsers.\n * Returns null if the string cannot be parsed.\n */\n public parseDateRange(masked: string): DateRangeValue | null {\n if (!masked || masked === this.emptyMask) {\n return null;\n }\n\n const startString = masked.substring(0, this._separatorStart);\n const endString = masked.substring(this._separatorEnd);\n\n const start = this._startParser.parseDate(startString);\n const end = this._endParser.parseDate(endString);\n\n return { start, end };\n }\n\n //#endregion\n\n //#region Date Range Formatting\n\n /**\n * Formats a DateRangeValue into a masked string using the two internal parsers.\n */\n public formatDateRange(range: DateRangeValue | null): string {\n const startString = range?.start\n ? this._startParser.formatDate(range.start)\n : this._startParser.emptyMask;\n\n const endString = range?.end\n ? this._endParser.formatDate(range.end)\n : this._endParser.emptyMask;\n\n return startString + this._separator + endString;\n }\n\n //#endregion\n\n //#region Part Queries\n\n /**\n * Gets the date range part at a cursor position.\n * Uses exclusive end for precise character targeting.\n */\n public getDateRangePartAtPosition(\n position: number\n ): IDateRangePart | undefined {\n return this._rangeParts.find(\n (part) => position >= part.start && position < part.end\n );\n }\n\n /**\n * Gets the date range part for cursor (inclusive end).\n * Handles the edge case where cursor is at the end of the last part.\n */\n public getDateRangePartForCursor(\n position: number\n ): IDateRangePart | undefined {\n return this._rangeParts.find(\n (part) => position >= part.start && position <= part.end\n );\n }\n\n /**\n * Gets a specific part type for a position.\n */\n public getPartByTypeAndPosition(\n type: DatePartType,\n position: DateRangePosition\n ): IDateRangePart | undefined {\n return this._rangeParts.find(\n (p) => p.type === type && p.position === position\n );\n }\n\n /**\n * Gets the first non-literal date part for a position.\n */\n public getFirstDatePartForPosition(\n position: DateRangePosition\n ): IDateRangePart | undefined {\n return this._rangeParts.find(\n (p) => p.position === position && p.type !== DatePartType.Literal\n );\n }\n\n //#endregion\n\n //#region Spinning Support\n\n /**\n * Spins a date part within the range (for stepUp/stepDown functionality).\n * Delegates to the underlying date part's spin method.\n */\n public spinDateRangePart(\n part: IDateRangePart,\n delta: number,\n currentValue: DateRangeValue | null,\n spinLoop: boolean,\n amPmValue?: string\n ): DateRangeValue {\n const value = currentValue || { start: null, end: null };\n\n const targetDate =\n part.position === DateRangePosition.Start ? value.start : value.end;\n\n // If no date exists, create one with today's date\n const dateToSpin = targetDate || new Date();\n\n // Create a new date instance to spin\n const newDate = new Date(dateToSpin.getTime());\n\n // Spin using the part's built-in spin method\n const spinOptions: SpinOptions = {\n date: newDate,\n spinLoop,\n originalDate: dateToSpin,\n amPmValue,\n };\n\n part.spin(delta, spinOptions);\n\n return part.position === DateRangePosition.Start\n ? { ...value, start: newDate }\n : { ...value, end: newDate };\n }\n\n //#endregion\n}\n"]}