@arsedizioni/ars-utils 22.0.43 → 22.0.47

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.
@@ -198,7 +198,9 @@ class DateFnsAdapter extends DateAdapter {
198
198
  if (typeof value === 'string' && value.length > 0) {
199
199
  const iso8601Date = parseISO(value);
200
200
  if (this.isValid(iso8601Date)) {
201
- return new TZDate(iso8601Date, 'Europe/Rome');
201
+ const t = new TZDate(iso8601Date, 'Europe/Rome');
202
+ t.setHours(12, 0, 0, 0);
203
+ return t;
202
204
  }
203
205
  const formats = Array.isArray(parseFormat) ? parseFormat : [parseFormat];
204
206
  if (!formats.length) {
@@ -209,13 +211,17 @@ class DateFnsAdapter extends DateAdapter {
209
211
  locale: this.locale
210
212
  });
211
213
  if (this.isValid(fromFormat)) {
212
- return new TZDate(fromFormat, 'Europe/Rome');
214
+ const t = new TZDate(fromFormat, 'Europe/Rome');
215
+ t.setHours(12, 0, 0, 0);
216
+ return t;
213
217
  }
214
218
  }
215
219
  return this.invalid();
216
220
  }
217
221
  else if (typeof value === 'number') {
218
- return new Date(value);
222
+ const t = new TZDate(new Date(value), 'Europe/Rome');
223
+ t.setHours(12, 0, 0, 0);
224
+ return t;
219
225
  }
220
226
  else if (value instanceof Date) {
221
227
  return this.clone(value);
@@ -2162,6 +2168,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
2162
2168
  * The host control is re-validated whenever the OTHER control's value changes:
2163
2169
  * without this, typing a new password AFTER the confirmation field was filled
2164
2170
  * left the form incorrectly valid (the classic password/confirm bug).
2171
+ *
2172
+ * IMPORTANT (reciprocal-binding safety): the re-validation triggered from the
2173
+ * other control's `valueChanges` runs with `{ emitEvent: false }`. Calling
2174
+ * Angular's `onValidatorChange` instead would re-emit valueChanges, so a
2175
+ * reciprocal setup (A [equals]=B and B [equals]=A) would overflow the stack.
2165
2176
  */
2166
2177
  class EqualsValidatorDirective {
2167
2178
  constructor() {
@@ -2169,21 +2180,18 @@ class EqualsValidatorDirective {
2169
2180
  this.equals = input(undefined, /* @ts-ignore */
2170
2181
  ...(ngDevMode ? [{ debugName: "equals" }] : /* istanbul ignore next */ []));
2171
2182
  // Re-subscribe whenever the [equals] binding points to a different control,
2172
- // and trigger host re-validation on every change of the other control.
2183
+ // and re-validate the host on every change of the other control.
2173
2184
  effect(() => {
2174
2185
  const other = this.equals();
2175
2186
  this.subscription?.unsubscribe();
2176
- this.subscription = other?.valueChanges.subscribe(() => this.onValidatorChange?.());
2187
+ this.subscription = other?.valueChanges.subscribe(() =>
2188
+ // emitEvent:false breaks the reciprocal valueChanges loop (see class doc).
2189
+ this.hostControl?.updateValueAndValidity({ emitEvent: false }));
2190
+ // Re-validate the host when the bound control itself is swapped.
2191
+ this.hostControl?.updateValueAndValidity({ emitEvent: false });
2177
2192
  });
2178
2193
  inject(DestroyRef).onDestroy(() => this.subscription?.unsubscribe());
2179
2194
  }
2180
- /**
2181
- * Registers the callback Angular invokes to re-run this validator.
2182
- * @param fn - The revalidation callback provided by the forms API.
2183
- */
2184
- registerOnValidatorChange(fn) {
2185
- this.onValidatorChange = fn;
2186
- }
2187
2195
  /**
2188
2196
  * Validates that the host control value equals the bound control's value.
2189
2197
  * Returns `null` (valid) when no control is bound.
@@ -2191,6 +2199,7 @@ class EqualsValidatorDirective {
2191
2199
  * @returns `null` when valid, `{ equals: ... }` otherwise.
2192
2200
  */
2193
2201
  validate(control) {
2202
+ this.hostControl = control;
2194
2203
  const eq = this.equals();
2195
2204
  if (!eq)
2196
2205
  return null;
@@ -2405,6 +2414,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
2405
2414
  *
2406
2415
  * The host control is re-validated whenever the OTHER control's value changes,
2407
2416
  * so editing either field keeps both error states consistent.
2417
+ *
2418
+ * IMPORTANT (reciprocal-binding safety): the re-validation triggered from the
2419
+ * other control's `valueChanges` is run with `{ emitEvent: false }`. Using
2420
+ * Angular's `onValidatorChange` here instead would call `host.updateValueAndValidity()`
2421
+ * WITH events, so a reciprocal setup (A [notEqual]=B and B [notEqual]=A) would
2422
+ * ping-pong valueChanges between the two controls and overflow the stack.
2408
2423
  */
2409
2424
  class NotEqualValidatorDirective {
2410
2425
  constructor() {
@@ -2414,17 +2429,15 @@ class NotEqualValidatorDirective {
2414
2429
  effect(() => {
2415
2430
  const other = this.notEqual();
2416
2431
  this.subscription?.unsubscribe();
2417
- this.subscription = other?.valueChanges.subscribe(() => this.onValidatorChange?.());
2432
+ this.subscription = other?.valueChanges.subscribe(() =>
2433
+ // Re-validate the host WITHOUT emitting valueChanges, otherwise a
2434
+ // reciprocal binding would loop forever (see class doc).
2435
+ this.hostControl?.updateValueAndValidity({ emitEvent: false }));
2436
+ // Re-validate the host when the bound control itself is swapped.
2437
+ this.hostControl?.updateValueAndValidity({ emitEvent: false });
2418
2438
  });
2419
2439
  inject(DestroyRef).onDestroy(() => this.subscription?.unsubscribe());
2420
2440
  }
2421
- /**
2422
- * Registers the callback Angular invokes to re-run this validator.
2423
- * @param fn - The revalidation callback provided by the forms API.
2424
- */
2425
- registerOnValidatorChange(fn) {
2426
- this.onValidatorChange = fn;
2427
- }
2428
2441
  /**
2429
2442
  * Validates that the host control value is not equal to the bound control's value.
2430
2443
  * Also clears the `notequal` error on the other control when the host becomes valid.
@@ -2433,6 +2446,7 @@ class NotEqualValidatorDirective {
2433
2446
  * @returns `null` when valid, `{ notequal: true }` otherwise.
2434
2447
  */
2435
2448
  validate(control) {
2449
+ this.hostControl = control;
2436
2450
  const notEqual = this.notEqual();
2437
2451
  if (!notEqual)
2438
2452
  return null;
@@ -2443,7 +2457,9 @@ class NotEqualValidatorDirective {
2443
2457
  }
2444
2458
  else if (notEqual.hasError('notequal')) {
2445
2459
  const { notequal: _removed, ...rest } = notEqual.errors ?? {};
2446
- notEqual.setErrors(Object.keys(rest).length > 0 ? rest : null);
2460
+ // emitEvent:false on both: clearing the partner's error must not feed
2461
+ // back through valueChanges/statusChanges into this validator.
2462
+ notEqual.setErrors(Object.keys(rest).length > 0 ? rest : null, { emitEvent: false });
2447
2463
  notEqual.updateValueAndValidity({ onlySelf: true, emitEvent: false });
2448
2464
  notEqual.markAsTouched();
2449
2465
  notEqual.markAsDirty();