@ascentgl/ads-ui 21.83.0 → 21.84.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.
|
@@ -5676,13 +5676,23 @@ class AdsDatetimepickerComponent extends AbstractInputComponent {
|
|
|
5676
5676
|
/** @ignore */
|
|
5677
5677
|
onChanged(event) {
|
|
5678
5678
|
const value = event === null ? null : typeof event == 'string' ? event : event.value;
|
|
5679
|
+
const inputHasContent = !!this.input?.nativeElement.value;
|
|
5679
5680
|
/**
|
|
5680
5681
|
* sync valueControl errors with displayControl errors
|
|
5681
5682
|
* NOTE: this is needed for "invalid format" errors that are calculated for displayControl
|
|
5682
5683
|
* by MatDatetimepicker component
|
|
5683
5684
|
*/
|
|
5684
|
-
|
|
5685
|
+
if (inputHasContent && this.displayControl.errors) {
|
|
5686
|
+
// Input has content — propagate displayControl errors (including matDatepickerParse)
|
|
5687
|
+
this.valueControl.setErrors(this.displayControl.errors);
|
|
5688
|
+
}
|
|
5685
5689
|
this.onDisplayedValueChange(value ? new Date(value) : null);
|
|
5690
|
+
// Re-validate valueControl so its own validators (e.g. required) run,
|
|
5691
|
+
// clearing any stale errors set via setErrors above.
|
|
5692
|
+
this.valueControl.updateValueAndValidity({ emitEvent: false });
|
|
5693
|
+
// Directly call syncState because statusChanges may not fire if
|
|
5694
|
+
// the status hasn't changed (e.g., was already INVALID).
|
|
5695
|
+
this.syncState(this.valueControl.status);
|
|
5686
5696
|
}
|
|
5687
5697
|
onViewChanged(view) {
|
|
5688
5698
|
this.templateFormatter.run(view);
|
|
@@ -5776,8 +5786,24 @@ class AdsDatetimepickerComponent extends AbstractInputComponent {
|
|
|
5776
5786
|
}
|
|
5777
5787
|
syncState(status) {
|
|
5778
5788
|
if (status === 'INVALID') {
|
|
5779
|
-
this.
|
|
5780
|
-
this.
|
|
5789
|
+
const errors = { ...this.valueControl.errors };
|
|
5790
|
+
const inputHasContent = !!this.input?.nativeElement.value;
|
|
5791
|
+
// When the input has visible content but the control value is null,
|
|
5792
|
+
// the user typed a partial/invalid date. Show format error instead
|
|
5793
|
+
// of "required", since the field is not actually empty from the user's perspective.
|
|
5794
|
+
if (inputHasContent && !this.displayControl.value) {
|
|
5795
|
+
// Prefer existing parse error from displayControl, otherwise create one.
|
|
5796
|
+
const existingParseError = this.displayControl.errors?.matDatepickerParse;
|
|
5797
|
+
errors['matDatepickerParse'] = existingParseError ?? { text: this.input?.nativeElement.value };
|
|
5798
|
+
}
|
|
5799
|
+
// When the input is empty, make sure stale parse errors are not carried over
|
|
5800
|
+
// from valueControl (which may have received them via setErrors in onChanged).
|
|
5801
|
+
if (!inputHasContent) {
|
|
5802
|
+
delete errors['matDatepickerParse'];
|
|
5803
|
+
}
|
|
5804
|
+
// Angular treats an empty object as "has errors" (truthy), so normalize to null.
|
|
5805
|
+
const finalErrors = Object.keys(errors).length > 0 ? errors : null;
|
|
5806
|
+
this.displayControl.setErrors(finalErrors);
|
|
5781
5807
|
}
|
|
5782
5808
|
else {
|
|
5783
5809
|
// Clear errors correctly (Angular expects null, not [])
|
|
@@ -5830,6 +5856,12 @@ class AdsDatetimepickerComponent extends AbstractInputComponent {
|
|
|
5830
5856
|
syncEmptyValues() {
|
|
5831
5857
|
if (this.valueControl.value)
|
|
5832
5858
|
return false;
|
|
5859
|
+
// When the input has user-typed content that failed parsing (e.g., partial date '03/10/202'),
|
|
5860
|
+
// displayControl is already null (set by mat-datetimepicker's _cvaOnChange(null)).
|
|
5861
|
+
// Don't clear the display — the user's text should stay so the format error is visible.
|
|
5862
|
+
// But when displayControl still holds a value (e.g., external form reset), allow clearing.
|
|
5863
|
+
if (this.input?.nativeElement.value && !this.displayControl.value)
|
|
5864
|
+
return true;
|
|
5833
5865
|
this.setControlValue(this.displayControl, this.valueControl.value, false);
|
|
5834
5866
|
return true;
|
|
5835
5867
|
}
|
|
@@ -6018,6 +6050,8 @@ class AdsDatepickerComponent extends AdsDatetimepickerComponent {
|
|
|
6018
6050
|
};
|
|
6019
6051
|
/** @ignore - Previous raw input value for tracking changes */
|
|
6020
6052
|
this.previousRawValue = '';
|
|
6053
|
+
/** @ignore - Tracks whether the input was modified by the custom keydown handler */
|
|
6054
|
+
this.inputModifiedByKeyHandler = false;
|
|
6021
6055
|
/** @ignore */
|
|
6022
6056
|
this.elementRef = inject(ElementRef);
|
|
6023
6057
|
}
|
|
@@ -6048,6 +6082,18 @@ class AdsDatepickerComponent extends AdsDatetimepickerComponent {
|
|
|
6048
6082
|
});
|
|
6049
6083
|
this.intersectionObserver.observe(this.elementRef.nativeElement);
|
|
6050
6084
|
}
|
|
6085
|
+
/** @ignore - Override to dispatch change event on blur when input was modified programmatically */
|
|
6086
|
+
touchControls() {
|
|
6087
|
+
// Mark controls as touched BEFORE dispatching the change event.
|
|
6088
|
+
// onChanged → syncState → super.syncState() checks valueControl.untouched
|
|
6089
|
+
// and clears displayControl if it's touched+invalid — so valueControl must
|
|
6090
|
+
// be touched first to prevent the user's partial input from being wiped.
|
|
6091
|
+
super.touchControls();
|
|
6092
|
+
if (this.inputModifiedByKeyHandler && this.input) {
|
|
6093
|
+
this.inputModifiedByKeyHandler = false;
|
|
6094
|
+
this.input.nativeElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
6095
|
+
}
|
|
6096
|
+
}
|
|
6051
6097
|
/** @ignore */
|
|
6052
6098
|
applyCustomFormat() {
|
|
6053
6099
|
this.customDisplayFormatOverride = {};
|
|
@@ -6180,6 +6226,8 @@ class AdsDatepickerComponent extends AdsDatetimepickerComponent {
|
|
|
6180
6226
|
newCursorPos++;
|
|
6181
6227
|
}
|
|
6182
6228
|
input.setSelectionRange(newCursorPos, newCursorPos);
|
|
6229
|
+
// Mark that the input was modified programmatically
|
|
6230
|
+
this.inputModifiedByKeyHandler = true;
|
|
6183
6231
|
// Trigger change detection
|
|
6184
6232
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
6185
6233
|
}
|
|
@@ -6198,6 +6246,8 @@ class AdsDatepickerComponent extends AdsDatetimepickerComponent {
|
|
|
6198
6246
|
// Adjust cursor position
|
|
6199
6247
|
const newCursorPos = Math.min(cursorPos, formatted.length);
|
|
6200
6248
|
input.setSelectionRange(newCursorPos, newCursorPos);
|
|
6249
|
+
// Mark that the input was modified programmatically
|
|
6250
|
+
this.inputModifiedByKeyHandler = true;
|
|
6201
6251
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
6202
6252
|
}
|
|
6203
6253
|
/** @ignore - Format digits with slashes (MM/DD/YYYY) */
|