@quadrel-enterprise-ui/framework 20.21.0 → 20.21.1

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.
package/index.d.ts CHANGED
@@ -5855,9 +5855,11 @@ declare class QdNotificationsSnackbarComponent {
5855
5855
  type ValidatorFnWithProps = {
5856
5856
  (control: AbstractControl): ValidationErrors | null;
5857
5857
  maxLength?: number;
5858
+ qdRevalidates?: string;
5858
5859
  };
5859
5860
  declare class QdFormControl<T> extends UntypedFormControl implements AbstractControl {
5860
5861
  private maxLength?;
5862
+ private revalidationPartners;
5861
5863
  private validatorList;
5862
5864
  constructor(formState?: T, validatorOrOpts?: ValidatorFnWithProps | ValidatorFnWithProps[] | FormControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null);
5863
5865
  private getValidatorList;
@@ -5868,6 +5870,7 @@ declare class QdFormControl<T> extends UntypedFormControl implements AbstractCon
5868
5870
  clearValidators(): void;
5869
5871
  hasMaxLength(): boolean;
5870
5872
  getMaxLengthOrUndefined(): number | undefined;
5873
+ getRevalidationPartners(): string[];
5871
5874
  }
5872
5875
 
5873
5876
  /**
@@ -7912,7 +7915,35 @@ declare class QdRadioButtonsComponent implements OnInit, OnChanges, OnDestroy, C
7912
7915
  static ɵcmp: i0.ɵɵComponentDeclaration<QdRadioButtonsComponent, "qd-radio-buttons", never, { "value": { "alias": "value"; "required": false; }; "config": { "alias": "config"; "required": false; }; "formControlName": { "alias": "formControlName"; "required": false; }; "testId": { "alias": "data-test-id"; "required": false; }; }, { "valueChange": "valueChange"; "clickHint": "clickHint"; "clickReadonly": "clickReadonly"; "clickViewonly": "clickViewonly"; }, never, never, false, never>;
7913
7916
  }
7914
7917
 
7918
+ /**
7919
+ * `UntypedFormGroup` that wires cross-field re-validation automatically.
7920
+ *
7921
+ * A validator can declare a sibling dependency via `qdRevalidates` (see `QdValidators.dateRange`).
7922
+ * The group then subscribes to that partner's `valueChanges` and re-validates the dependent control,
7923
+ * so a stale error never lingers when the partner value changes — without the consumer calling
7924
+ * `updateValueAndValidity`. The subscriptions are group-internal (sibling to sibling) and are torn
7925
+ * down and rebuilt whenever a control is added, replaced or removed.
7926
+ *
7927
+ * Re-wiring is triggered by control mutations (`add`/`set`/`removeControl`), not by validator
7928
+ * mutations on an existing control: calling `control.addValidators(...)` after construction updates
7929
+ * the control's partners but does not re-wire the group until the next control mutation.
7930
+ */
7915
7931
  declare class QdFormGroup extends UntypedFormGroup {
7932
+ private revalidationSubscription;
7933
+ constructor(controls: {
7934
+ [key: string]: AbstractControl;
7935
+ }, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null);
7936
+ addControl(name: string, control: AbstractControl, options?: {
7937
+ emitEvent?: boolean;
7938
+ }): void;
7939
+ setControl(name: string, control: AbstractControl, options?: {
7940
+ emitEvent?: boolean;
7941
+ }): void;
7942
+ removeControl(name: string, options?: {
7943
+ emitEvent?: boolean;
7944
+ }): void;
7945
+ private rewireCrossFieldRevalidation;
7946
+ private wireCrossFieldRevalidation;
7916
7947
  }
7917
7948
 
7918
7949
  declare class QdFormBuilder extends UntypedFormBuilder {
@@ -8123,29 +8154,71 @@ declare class QdFilterFormItemsComponent implements OnInit {
8123
8154
  static ɵcmp: i0.ɵɵComponentDeclaration<QdFilterFormItemsComponent, "qd-filter-form-items", never, { "inputFilterValue": { "alias": "inputFilterValue"; "required": false; }; "testId": { "alias": "data-test-id"; "required": false; }; }, { "filterValueChange": "filterValueChange"; }, never, never, false, never>;
8124
8155
  }
8125
8156
 
8157
+ /**
8158
+ * Ready-to-use validators for Quadrel Reactive Forms.
8159
+ *
8160
+ * Use them like Angular's built-in `Validators`, but every validator returns a **translatable
8161
+ * error key** instead of a fixed message, and most accept a custom `errorKey` as the last
8162
+ * argument.
8163
+ *
8164
+ * Empty values pass for most validators — combine with `required()` when a value is mandatory.
8165
+ * The amount-aware validators (`min`, `max`, `minLength`, `maxLength`, `pattern`) also accept
8166
+ * `{ value, unit }` objects and validate the inner `value`.
8167
+ *
8168
+ * #### **Usage**
8169
+ * ```ts
8170
+ * form = new QdFormGroup({
8171
+ * email: new QdFormControl(null, [QdValidators.required(), QdValidators.email()]),
8172
+ * age: new QdFormControl(null, [QdValidators.required(), QdValidators.min(18)])
8173
+ * });
8174
+ * ```
8175
+ */
8126
8176
  declare class QdValidators {
8127
8177
  /**
8128
- * Validates that the value of the form field is at least the specified minimum.
8178
+ * Validates that a numeric value is greater than or equal to a minimum.
8179
+ *
8180
+ * Empty values (`null`/`undefined`) pass — combine with `required` when a value is mandatory.
8181
+ * Also accepts amount objects of the shape `{ value, unit }`; in that case the inner `value`
8182
+ * is validated.
8183
+ *
8184
+ * @param min - The smallest allowed value (inclusive).
8185
+ * @param errorKey - Translation key returned when the value is below the minimum.
8129
8186
  *
8130
8187
  * #### **Usage**
8131
8188
  * ```ts
8132
- * new QdFormControl('', QdValidators.min(3));
8133
- * new QdFormControl('', QdValidators.min(3, 'custom-error'));
8189
+ * new QdFormControl(null, QdValidators.min(3));
8190
+ * new QdFormControl(null, QdValidators.min(3, 'custom-error'));
8134
8191
  * ```
8135
8192
  */
8136
8193
  static min(min: number, errorKey?: string): ValidatorFn;
8137
8194
  /**
8138
- * Validates that the value of the form field does not exceed the specified maximum.
8195
+ * Validates that a numeric value is less than or equal to a maximum.
8196
+ *
8197
+ * Empty values (`null`/`undefined`) pass — combine with `required` when a value is mandatory.
8198
+ * Also accepts amount objects of the shape `{ value, unit }`; in that case the inner `value`
8199
+ * is validated.
8200
+ *
8201
+ * @param max - The largest allowed value (inclusive).
8202
+ * @param errorKey - Translation key returned when the value exceeds the maximum.
8139
8203
  *
8140
8204
  * #### **Usage**
8141
8205
  * ```ts
8142
- * new QdFormControl('', QdValidators.max(10));
8143
- * new QdFormControl('', QdValidators.max(10, 'custom-error'));
8206
+ * new QdFormControl(null, QdValidators.max(10));
8207
+ * new QdFormControl(null, QdValidators.max(10, 'custom-error'));
8144
8208
  * ```
8145
8209
  */
8146
8210
  static max(max: number, errorKey?: string): ValidatorFn;
8147
8211
  /**
8148
- * Ensures that the form field is not empty.
8212
+ * Validates that the field holds a non-empty value.
8213
+ *
8214
+ * Quadrel form components additionally render a required asterisk (`*`) on the field label
8215
+ * whenever this validator is present, so users see at a glance that the field is mandatory.
8216
+ *
8217
+ * Empty means: `null`, `undefined`, an empty string, an empty array, or an object whose
8218
+ * leaf values are all empty (checked recursively — useful for amount objects such as
8219
+ * `{ value, unit }`).
8220
+ *
8221
+ * @param errorKey - Translation key returned when the field is empty.
8149
8222
  *
8150
8223
  * #### **Usage**
8151
8224
  * ```ts
@@ -8156,7 +8229,12 @@ declare class QdValidators {
8156
8229
  static required(errorKey?: string): ValidatorFn;
8157
8230
  private static isEmptyInputValue;
8158
8231
  /**
8159
- * Validates that the form field contains a valid email address.
8232
+ * Validates that the field contains a single, well-formed email address.
8233
+ *
8234
+ * Empty values pass — combine with `required` when an address is mandatory. The whole value
8235
+ * must be the address; surrounding text makes it invalid.
8236
+ *
8237
+ * @param errorKey - Translation key returned when the address is malformed.
8160
8238
  *
8161
8239
  * #### **Usage**
8162
8240
  * ```ts
@@ -8166,7 +8244,14 @@ declare class QdValidators {
8166
8244
  */
8167
8245
  static email(errorKey?: string): ValidatorFn;
8168
8246
  /**
8169
- * Ensures that the form field contains at least the specified number of characters.
8247
+ * Validates that a text value is at least a given number of characters long.
8248
+ *
8249
+ * Empty values (`null`/`undefined`/`''`) pass — combine with `required` when input is
8250
+ * mandatory. Also accepts amount objects of the shape `{ value, unit }`; in that case the
8251
+ * inner `value` is measured.
8252
+ *
8253
+ * @param minLength - The minimum number of characters (inclusive).
8254
+ * @param errorKey - Translation key returned when the value is too short.
8170
8255
  *
8171
8256
  * #### **Usage**
8172
8257
  * ```ts
@@ -8176,7 +8261,15 @@ declare class QdValidators {
8176
8261
  */
8177
8262
  static minLength(minLength: number, errorKey?: string): ValidatorFn;
8178
8263
  /**
8179
- * Ensures that the form field contains no more than the specified number of characters.
8264
+ * Validates that a text value is no longer than a given number of characters.
8265
+ *
8266
+ * Empty values pass — combine with `required` when input is mandatory. Also accepts amount
8267
+ * objects of the shape `{ value, unit }`; in that case the inner `value` is measured. The
8268
+ * configured limit is exposed as `.maxLength` on the returned validator, which `qd-textarea`
8269
+ * reads to show a live character counter (`current / max`).
8270
+ *
8271
+ * @param maxLength - The maximum number of characters (inclusive).
8272
+ * @param errorKey - Translation key returned when the value is too long.
8180
8273
  *
8181
8274
  * #### **Usage**
8182
8275
  * ```ts
@@ -8186,7 +8279,13 @@ declare class QdValidators {
8186
8279
  */
8187
8280
  static maxLength(maxLength: number, errorKey?: string): ValidatorFn;
8188
8281
  /**
8189
- * Ensures that the form field matches a given regular expression pattern.
8282
+ * Validates that a text value matches a regular expression.
8283
+ *
8284
+ * Empty values pass — combine with `required` when input is mandatory. Also accepts amount
8285
+ * objects of the shape `{ value, unit }`; in that case the inner `value` is matched.
8286
+ *
8287
+ * @param pattern - The pattern to match, as a `RegExp` or a string regular expression.
8288
+ * @param errorKey - Translation key returned when the value does not match.
8190
8289
  *
8191
8290
  * #### **Usage**
8192
8291
  * ```ts
@@ -8197,37 +8296,102 @@ declare class QdValidators {
8197
8296
  */
8198
8297
  static pattern(pattern: string | RegExp, errorKey?: string): ValidatorFn;
8199
8298
  /**
8200
- * Ensures that the form field contains a valid date.
8299
+ * Validates that the value is a real, parseable `Date` object.
8300
+ *
8301
+ * Empty values pass — combine with `required` when a date is mandatory. Strings (including
8302
+ * `'Invalid Date'`), numbers and plain objects are rejected. The error carries the locale
8303
+ * date format (`DD.MM.YYYY`) as a `params.format` hint for the message.
8304
+ *
8305
+ * @param errorKey - Translation key returned when the value is not a valid date.
8201
8306
  *
8202
8307
  * #### **Usage**
8203
8308
  * ```ts
8204
- * new QdFormControl('', QdValidators.date());
8309
+ * new QdFormControl(null, QdValidators.date());
8205
8310
  * new QdFormControl(new Date(), QdValidators.date());
8206
8311
  * new QdFormControl(new Date(), QdValidators.date('date-error'));
8207
8312
  * ```
8208
8313
  */
8209
8314
  static date(errorKey?: string): ValidatorFn;
8210
8315
  /**
8211
- * Ensures that the selected date is not within a range of disabled dates.
8316
+ * Validates that a date does not fall inside any of the given disabled ranges.
8317
+ *
8318
+ * Each range may set `from`, `to`, or both; an open end reaches into the far past/future.
8319
+ * Boundaries are **exclusive** — a date exactly on `from` or `to` is still allowed; only
8320
+ * dates strictly between them are rejected. Comparison is day-granular. Empty or invalid
8321
+ * values pass.
8322
+ *
8323
+ * @param disabledDates - Ranges to block, e.g. `[{ from, to }]`.
8324
+ * @param errorKey - Translation key returned when the date lies inside a range.
8212
8325
  *
8213
8326
  * #### **Usage**
8214
8327
  * ```ts
8215
- * new QdFormControl('', QdValidators.disabledDates([{ from: new Date('2025-01-01') }]));
8328
+ * new QdFormControl(null, QdValidators.disabledDates([{ from: new Date('2025-01-01') }]));
8329
+ * new QdFormControl(null, QdValidators.disabledDates([{ from: new Date('2025-01-01'), to: new Date('2025-01-31') }]));
8216
8330
  * ```
8217
8331
  */
8218
8332
  static disabledDates(disabledDates: QdDisabledDates[], errorKey?: string): ValidatorFn;
8219
8333
  private static isDateDisabled;
8220
8334
  /**
8221
- * Ensures that the selected time is not within a range of disabled times.
8335
+ * Validates that a date stays on the correct side of a sibling "range partner" control.
8336
+ *
8337
+ * Put it on both ends of a from/to pair, each pointing at the other. A `'start'` control is
8338
+ * invalid when its date is after the partner; an `'end'` control is invalid when its date is
8339
+ * before the partner. Comparison is day-granular, so equal days are valid.
8340
+ *
8341
+ * The partner value is read live on every run, so the limit is never cached — it stays
8342
+ * correct across form rebuilds, saves and config changes. Empty or invalid own/partner
8343
+ * values, and a missing partner control, all pass.
8344
+ *
8345
+ * Inside a `QdFormGroup` the partner is re-validated automatically when this control changes
8346
+ * (and vice versa), so a stale error never lingers — no manual `updateValueAndValidity` needed.
8347
+ * The validator declares this dependency via `qdRevalidates`, which the group reads.
8348
+ *
8349
+ * The auto-revalidation only applies when both controls are `QdFormControl`s inside a
8350
+ * `QdFormGroup`, and only for validators present at construction or set via the group's
8351
+ * `add`/`set`/`removeControl`. On a native `FormGroup`/`FormControl`, or when the validator is
8352
+ * added later via `control.addValidators(...)`, re-validate the partner manually with
8353
+ * `partner.updateValueAndValidity({ emitEvent: false })` whenever this control changes.
8354
+ *
8355
+ * @param partnerControlName - Name of the sibling control holding the other end of the range.
8356
+ * @param position - `'start'` for the from-control, `'end'` for the to-control.
8357
+ * @param errorKey - Translation key returned when the order is violated.
8358
+ *
8359
+ * #### **Usage**
8360
+ * ```ts
8361
+ * new QdFormGroup({
8362
+ * from: new QdFormControl(null, QdValidators.dateRange('to', 'start')),
8363
+ * to: new QdFormControl(null, QdValidators.dateRange('from', 'end'))
8364
+ * });
8365
+ * ```
8366
+ */
8367
+ static dateRange(partnerControlName: string, position: 'start' | 'end', errorKey?: string): ValidatorFn;
8368
+ private static isValidDate;
8369
+ /**
8370
+ * Validates that the time of a date value does not fall inside any disabled time range.
8371
+ *
8372
+ * Each range may set `from`, `to`, or both, as `HH:mm` strings. Boundaries are **exclusive** —
8373
+ * a time exactly on `from` or `to` is allowed; only times strictly between them are rejected.
8374
+ * Only the time-of-day is considered, not the date. Empty or invalid values pass.
8375
+ *
8376
+ * @param disabledTimes - Ranges to block, e.g. `[{ from: '12:00', to: '13:00' }]`.
8377
+ * @param errorKey - Translation key returned when the time lies inside a range.
8222
8378
  *
8223
8379
  * #### **Usage**
8224
8380
  * ```ts
8225
- * new QdFormControl('', QdValidators.disabledTimes([{ from: '15:00' }]));
8381
+ * new QdFormControl(null, QdValidators.disabledTimes([{ from: '15:00' }]));
8382
+ * new QdFormControl(null, QdValidators.disabledTimes([{ from: '12:00', to: '13:00' }]));
8226
8383
  * ```
8227
8384
  */
8228
8385
  static disabledTimes(disabledTimes: QdDisabledTimes[], errorKey?: string): ValidatorFn;
8229
8386
  /**
8230
- * Ensures that the selected file does not exceed the given maximum size in megabytes.
8387
+ * Validates that a selected file does not exceed a maximum size.
8388
+ *
8389
+ * Operates on a `File` value (e.g. from a file input). Non-file values — including `null` —
8390
+ * pass, so combine with `required` when a file is mandatory. The error carries `params.maxMb`
8391
+ * for the message.
8392
+ *
8393
+ * @param maxMb - The maximum allowed size in megabytes.
8394
+ * @param errorKey - Translation key returned when the file is too large.
8231
8395
  *
8232
8396
  * #### **Usage**
8233
8397
  * ```ts
@@ -8237,7 +8401,15 @@ declare class QdValidators {
8237
8401
  */
8238
8402
  static fileSize(maxMb: number, errorKey?: string): ValidatorFn;
8239
8403
  /**
8240
- * Validates that the file type or file extension matches one of the accepted types.
8404
+ * Validates that a selected file matches one of the accepted types.
8405
+ *
8406
+ * Each accepted entry is either a MIME type (`'application/pdf'`), a MIME wildcard
8407
+ * (`'image/*'`), or a file extension (`'.pdf'`); matching is case-insensitive. Non-file
8408
+ * values — including `null` — pass, so combine with `required` when a file is mandatory. The
8409
+ * error carries `params.accepted` for the message.
8410
+ *
8411
+ * @param accepted - Allowed MIME types, MIME wildcards or extensions.
8412
+ * @param errorKey - Translation key returned when the file type is not accepted.
8241
8413
  *
8242
8414
  * #### **Usage**
8243
8415
  * ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quadrel-enterprise-ui/framework",
3
- "version": "20.21.0",
3
+ "version": "20.21.1",
4
4
  "exports": {
5
5
  "./jest-preset": "./jest-preset.js",
6
6
  "./package.json": {
@@ -99,6 +99,7 @@
99
99
  "i18n.qd.form.error.pattern": "Entspricht nicht dem Muster",
100
100
  "i18n.qd.form.error.date": "Eingabe entspricht nicht DD.MM.JJJJ",
101
101
  "i18n.qd.form.error.disabledDates": "Datum ausserhalb des erlaubten Bereichs",
102
+ "i18n.qd.form.error.dateRange": "Das Datum liegt ausserhalb des gültigen Bereichs.",
102
103
  "i18n.qd.form.error.startDateNotAfterEndDate": "Das Startdatum darf nicht hinter dem Enddatum liegen.",
103
104
  "i18n.qd.form.error.endDateNotBeforeStartDate": "Das Enddatum darf nicht vor dem Startdatum liegen.",
104
105
  "i18n.qd.form.error.disabledTimes": "Zeit ausserhalb des erlaubten Bereichs",
@@ -101,6 +101,7 @@
101
101
  "i18n.qd.form.error.pattern": "Does not match pattern",
102
102
  "i18n.qd.form.error.date": "Input does not correspond to DD.MM.YYYY",
103
103
  "i18n.qd.form.error.disabledDates": "Date outside the permitted range",
104
+ "i18n.qd.form.error.dateRange": "The date is outside the valid range.",
104
105
  "i18n.qd.form.error.startDateNotAfterEndDate": "The start date cannot be later than the end date.",
105
106
  "i18n.qd.form.error.endDateNotBeforeStartDate": "The end date cannot be earlier than the start date.",
106
107
  "i18n.qd.form.error.disabledTimes": "Time outside the permitted range",
@@ -101,6 +101,7 @@
101
101
  "i18n.qd.form.error.pattern": "Ne correspond pas au schéma",
102
102
  "i18n.qd.form.error.date": "La saisie ne correspond pas à JJ.MM.AAAA",
103
103
  "i18n.qd.form.error.disabledDates": "Date en dehors de la plage autorisée",
104
+ "i18n.qd.form.error.dateRange": "La date est en dehors de la plage valide.",
104
105
  "i18n.qd.form.error.startDateNotAfterEndDate": "La date de début ne peut pas être postérieure à la date de fin.",
105
106
  "i18n.qd.form.error.endDateNotBeforeStartDate": "La date de fin ne peut pas être antérieure à la date de début.",
106
107
  "i18n.qd.form.error.disabledTimes": "Temps en dehors de la plage autorisée",
@@ -101,6 +101,7 @@
101
101
  "i18n.qd.form.error.pattern": "Non corrisponde allo schema",
102
102
  "i18n.qd.form.error.date": "L'input non corrisponde a GG.MM.AAAA",
103
103
  "i18n.qd.form.error.disabledDates": "Data fuori dall'intervallo consentito",
104
+ "i18n.qd.form.error.dateRange": "La data è al di fuori dell'intervallo valido.",
104
105
  "i18n.qd.form.error.startDateNotAfterEndDate": "La data di inizio non può essere successiva alla data di fine.",
105
106
  "i18n.qd.form.error.endDateNotBeforeStartDate": "La data di fine non può essere anteriore alla data di inizio.",
106
107
  "i18n.qd.form.error.disabledTimes": "Tempo fuori dall'intervallo consentito",