@arsedizioni/ars-utils 22.5.46 → 22.5.48

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arsedizioni/ars-utils",
3
- "version": "22.5.46",
3
+ "version": "22.5.48",
4
4
  "author": {
5
5
  "email": "software@arsedizioni.it",
6
6
  "name": "Fabio Buscaroli, Alberto Doria"
@@ -257,8 +257,8 @@ declare class TimeValidatorDirective implements Validator {
257
257
  * nor an empty array. Apply `notEmpty` to a text input where non-blank content is required, or
258
258
  * to a multi-value control that must carry at least one entry.
259
259
  *
260
- * A value that is simply absent passes: saying "obbligatorio" is the job of `required`, or of
261
- * `requiredNotEmpty` when both rules belong on the same control.
260
+ * A value that is simply absent passes: saying "obbligatorio" is the job of `required`, which is
261
+ * declared next to this one when both rules belong on the same control.
262
262
  */
263
263
  declare class NotEmptyValidatorDirective implements Validator {
264
264
  /**
@@ -272,37 +272,6 @@ declare class NotEmptyValidatorDirective implements Validator {
272
272
  static ɵdir: i0.ɵɵDirectiveDeclaration<NotEmptyValidatorDirective, "[notEmpty]", never, {}, {}, never, never, true, never>;
273
273
  }
274
274
 
275
- /**
276
- * Directive that validates that a control carries actual content: present AND not blank.
277
- * Apply `requiredNotEmpty` where `required notEmpty` would otherwise be spelled out together.
278
- *
279
- * It raises the very errors those two rules raise — `required` when the value is missing, an
280
- * empty string or an empty array, `notEmpty` when a value is there but made of whitespace alone —
281
- * so existing error messages and `getFieldErrorMessage` keep working untouched, and the user
282
- * still reads "Obbligatorio" rather than the vaguer "Non può essere vuoto".
283
- *
284
- * IMPORTANT, on a Material field: this directive does NOT draw the asterisk. `MatInput` reads its
285
- * own `required` input first and falls back to `hasValidator(Validators.required)`, which no
286
- * directive-provided validator can satisfy — the validators of a template-driven control are
287
- * merged into one composed function before they get there. Keep writing `required` on the
288
- * control next to this one: the two produce the same `{ required: true }` key, so the errors
289
- * merge and nothing is reported twice.
290
- *
291
- * `aria-required` is set here so that assistive technology is told the truth even where the
292
- * `required` attribute is absent.
293
- */
294
- declare class RequiredNotEmptyValidatorDirective implements Validator {
295
- /**
296
- * Validates that the control value is present and carries content.
297
- * @param control - The form control to validate.
298
- * @returns `{ required: true }` when nothing was entered, `{ notEmpty: true }` when the value
299
- * is blank, `null` when the value is acceptable.
300
- */
301
- validate(control: AbstractControl): ValidationErrors | null;
302
- static ɵfac: i0.ɵɵFactoryDeclaration<RequiredNotEmptyValidatorDirective, never>;
303
- static ɵdir: i0.ɵɵDirectiveDeclaration<RequiredNotEmptyValidatorDirective, "[requiredNotEmpty]", never, {}, {}, never, never, true, never>;
304
- }
305
-
306
275
  /**
307
276
  * Options shared by the ARS signal-form validators.
308
277
  *
@@ -370,12 +339,16 @@ declare function password<TPathKind extends PathKind = PathKind.Root>(path: Sche
370
339
  * The signal-form counterpart of `NotEmptyValidatorDirective`, sharing its predicate through
371
340
  * {@link isBlankValue}: a blank string and an empty array are errors, an absent value is not.
372
341
  * That last part is not an oversight — saying "obbligatorio" belongs to `required()`, and a field
373
- * that is merely blank would otherwise raise two errors that mean the same thing. Pair the two,
374
- * or reach for {@link requiredNotEmpty}, when a field must be both present and non-blank.
342
+ * that is merely blank would otherwise raise two errors that mean the same thing. Declare the two
343
+ * together when a field must be both present and non-blank.
375
344
  *
376
345
  * Replaces the `pattern(p.x, /\S/)` workaround: same rule, but the intent is in the name and the
377
346
  * error kind is `notEmpty` rather than `pattern`.
378
347
  *
348
+ * On a multi-value field this rule is the ONLY one that sees an empty selection: Angular's
349
+ * `required()` treats emptiness as `'' | false | null | undefined`, so an empty array walks past
350
+ * it. Give it a message of its own there, because the default one talks about whitespace.
351
+ *
379
352
  * @param path - Path of the field to validate.
380
353
  * @param config - Optional message override.
381
354
  * @returns void
@@ -385,34 +358,6 @@ declare function password<TPathKind extends PathKind = PathKind.Root>(path: Sche
385
358
  * const f = form(this.model, p => { notEmpty(p.tags); }); // at least one tag
386
359
  */
387
360
  declare function notEmpty<TValue extends string | readonly unknown[] | undefined, TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>, config?: ArsValidatorConfig<TValue, TPathKind>): void;
388
- /**
389
- * Requires the value to be both present and made of something: the two rules a mandatory text
390
- * field almost always needs together, declared once.
391
- *
392
- * The signal-form counterpart of `RequiredNotEmptyValidatorDirective`. It raises the errors the
393
- * two rules raise on their own rather than a kind of its own — `required` when nothing was
394
- * entered, `notEmpty` when a value is there but blank — so the message stays as precise as it was
395
- * and nothing downstream needs to learn a new kind.
396
- *
397
- * The presence half is DELEGATED to Angular's own `required()` and is not reimplemented here.
398
- * That call does more than validate: it writes the `REQUIRED` metadata on the field, and that
399
- * metadata is the only thing the Material compatibility layer looks at when it answers
400
- * `hasValidator(Validators.required)` through `field().required()`. A plain `validate()` would
401
- * reject the empty value just the same and silently drop the asterisk from the label.
402
- *
403
- * The empty array is the one case handled here rather than there: Angular's emptiness check is
404
- * `value === '' || value === false || value == null`, so an empty array walks straight past
405
- * `required()`. It is reported with the `required` kind all the same, because for a multi-value
406
- * field "nothing selected" is exactly what the user needs to be told.
407
- *
408
- * @param path - Path of the field to validate.
409
- * @param config - Optional message override, applied to whichever of the two errors is raised,
410
- * and `when` condition, honoured by both halves of the rule.
411
- * @returns void
412
- * @example
413
- * const f = form(this.model, p => { requiredNotEmpty(p.city); });
414
- */
415
- declare function requiredNotEmpty<TValue extends string | readonly unknown[] | undefined, TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>, config?: ArsValidatorConfig<TValue, TPathKind>): void;
416
361
  /**
417
362
  * Requires the value to differ from the value of another field of the same form.
418
363
  *
@@ -613,5 +558,5 @@ declare class SignalsUtils {
613
558
  }[], message?: string): string | undefined;
614
559
  }
615
560
 
616
- export { ARS_VALIDATOR_MESSAGES, EmailsValidatorDirective, EqualsValidatorDirective, FileSizeValidatorDirective, GuidValidatorDirective, MIN_VALID_YEAR, MaxTermsValidatorDirective, NotEmptyValidatorDirective, NotEqualValidatorDirective, NotFutureValidatorDirective, PasswordValidatorDirective, RequiredNotEmptyValidatorDirective, SignalsUtils, SqlDateValidatorDirective, TimeValidatorDirective, UrlValidatorDirective, ValidIfDirective, ValidatorDirective, date, dateRange, emails, equals, fileSize, guid, maxTerms, notEmpty, notEqual, notFuture, otp, password, requiredNotEmpty, sqlDate, time, url, validIf };
561
+ export { ARS_VALIDATOR_MESSAGES, EmailsValidatorDirective, EqualsValidatorDirective, FileSizeValidatorDirective, GuidValidatorDirective, MIN_VALID_YEAR, MaxTermsValidatorDirective, NotEmptyValidatorDirective, NotEqualValidatorDirective, NotFutureValidatorDirective, PasswordValidatorDirective, SignalsUtils, SqlDateValidatorDirective, TimeValidatorDirective, UrlValidatorDirective, ValidIfDirective, ValidatorDirective, date, dateRange, emails, equals, fileSize, guid, maxTerms, notEmpty, notEqual, notFuture, otp, password, sqlDate, time, url, validIf };
617
562
  export type { ArsValidatorConfig };
@@ -1,4 +1,4 @@
1
- import { Searchable, INode, DateInterval, SearchBag, NameValueItem } from '@arsedizioni/ars-utils/core';
1
+ import { Searchable, INode, SearchBag, DateInterval, NameValueItem } from '@arsedizioni/ars-utils/core';
2
2
  import { MatFormFieldAppearance } from '@angular/material/form-field';
3
3
  import * as _angular_core from '@angular/core';
4
4
  import { TemplateRef, InjectionToken, Signal, ElementRef, Renderer2 } from '@angular/core';
@@ -111,6 +111,35 @@ interface SelectDialogData {
111
111
  searchLabel?: string;
112
112
  searchButtonLabel?: string;
113
113
  }
114
+ /**
115
+ * Data of `ListDialogComponent`: the read-only sibling of {@link SelectDialogData}.
116
+ *
117
+ * It carries no `can*` flag on purpose — the dialog shows a searchable list and closes, so there
118
+ * is nothing to enable — and no `mustSelect` / `okCaption` either, because there is no
119
+ * confirmation step to gate.
120
+ */
121
+ interface ListDialogData {
122
+ /** Dialog title, rendered as HTML. */
123
+ title: string;
124
+ /** Optional description shown under the title, rendered as HTML. */
125
+ description?: string;
126
+ /** Optional header shown above the list, rendered as HTML. Hidden while the list is empty. */
127
+ header?: string;
128
+ /** Items to display. */
129
+ items?: SelectableItem[];
130
+ /** Initial search text. */
131
+ filter?: string;
132
+ /** Message shown in place of the list when there is nothing to display. Rendered as HTML. */
133
+ emptyMessage?: string;
134
+ /** Caption of the close button, which is always available. Defaults to `Chiudi`. */
135
+ closeCaption?: string;
136
+ /** Label of the search field. Defaults to `Cerca...`. */
137
+ searchLabel?: string;
138
+ /** Appearance of the search field. Defaults to `outline`. */
139
+ appearance?: MatFormFieldAppearance;
140
+ /** Preferred dialog width, in pixels, for the caller that opens it. */
141
+ width?: number;
142
+ }
114
143
  interface SelectTreeDialogData {
115
144
  title: string;
116
145
  description?: string;
@@ -910,4 +939,4 @@ declare class FlexLayoutModule {
910
939
  }
911
940
 
912
941
  export { ALIAS_FAMILIES, BS5_BREAKPOINTS, CANONICAL_ALIASES, FlexLayoutModule, FxClassDirective, FxFlexAlignDirective, FxFlexDirective, FxFlexFillDirective, FxFlexOffsetDirective, FxFlexOrderDirective, FxGridAreaDirective, FxGridColumnDirective, FxGridDirective, FxLayoutAlignDirective, FxLayoutDirective, FxLayoutGapDirective, FxLayoutWrapDirective, FxShowHideDirective, FxStyleDirective, IfBpDirective, ItemNode, LAYOUT_BREAKPOINTS, LAYOUT_VALUES, MediaObserver, NON_CANONICAL_PRIORITY, PromptDialogType, ResponsiveBaseDirective, SelectableItem, SelectableNode, UIService, applyVisibility, buildAlignStyles, buildFlexStyles, buildLayoutCSS, resolve, resolveAll, resolveFlexInput, resolveNonCanonical, resolveParentFlow, validateBasis, validateLayoutValue, validateWrapValue };
913
- export type { BpValues, BreakpointAlias, CanonicalKey, CredentialsDialogResult, DialogOption, DialogResult, ISelectableItem, ISendToDialog, NcValues, NonCanonicalKey, PromptDateDialogResult, PromptDialogData, PromptDialogResult, PromptOtpDialogResult, PromptTimeDialogData, RecoverPasswordDialogResult, ResetPasswordDialogResult, SelectDialogAppend, SelectDialogData, SelectDialogDelete, SelectDialogEdit, SelectDialogFilter, SelectDialogLookup, SelectDialogResult, SelectFile, SelectFileDialogData, SelectFileOption, SelectPictureFileDialogData, SelectTreeDialogData, SelectTreeDialogResult, SelectableFilter, SendToDialogResult, SendToPopulateData };
942
+ export type { BpValues, BreakpointAlias, CanonicalKey, CredentialsDialogResult, DialogOption, DialogResult, ISelectableItem, ISendToDialog, ListDialogData, NcValues, NonCanonicalKey, PromptDateDialogResult, PromptDialogData, PromptDialogResult, PromptOtpDialogResult, PromptTimeDialogData, RecoverPasswordDialogResult, ResetPasswordDialogResult, SelectDialogAppend, SelectDialogData, SelectDialogDelete, SelectDialogEdit, SelectDialogFilter, SelectDialogLookup, SelectDialogResult, SelectFile, SelectFileDialogData, SelectFileOption, SelectPictureFileDialogData, SelectTreeDialogData, SelectTreeDialogResult, SelectableFilter, SendToDialogResult, SendToPopulateData };
@@ -1,16 +1,62 @@
1
1
  import * as _angular_forms_signals from '@angular/forms/signals';
2
2
  import * as _angular_core from '@angular/core';
3
3
  import { OnDestroy } from '@angular/core';
4
+ import { SearchFilterMetadata } from '@arsedizioni/ars-utils/core';
5
+ import { ListDialogData, SelectableItem, SelectDialogData, SelectDialogResult, SelectDialogEdit, SelectDialogAppend, SelectDialogDelete, SelectDialogLookup, SelectDialogFilter, SelectableFilter, ItemNode, SelectTreeDialogResult, SelectTreeDialogData, ISendToDialog, SendToDialogResult, SendToPopulateData } from '@arsedizioni/ars-utils/ui';
4
6
  import { MatCheckboxChange } from '@angular/material/checkbox';
5
7
  import { MatSelectionList, MatSelectionListChange } from '@angular/material/list';
6
8
  import { MatPaginator, PageEvent } from '@angular/material/paginator';
7
- import { SearchFilterMetadata } from '@arsedizioni/ars-utils/core';
8
- import { SelectDialogData, SelectDialogResult, SelectDialogEdit, SelectableItem, SelectDialogAppend, SelectDialogDelete, SelectDialogLookup, SelectDialogFilter, SelectableFilter, ItemNode, SelectTreeDialogResult, SelectTreeDialogData, ISendToDialog, SendToDialogResult, SendToPopulateData } from '@arsedizioni/ars-utils/ui';
9
9
  import * as rxjs from 'rxjs';
10
10
  import { MatTree } from '@angular/material/tree';
11
11
  import { MatFormFieldAppearance } from '@angular/material/form-field';
12
12
  import { SignalsUtils } from '@arsedizioni/ars-utils/core.validators';
13
13
 
14
+ /**
15
+ * Read-only counterpart of `SelectDialogComponent`: it shows a list of items with a search box
16
+ * and nothing else.
17
+ *
18
+ * Deliberately not a selection: the list is a plain `mat-list`, not a `mat-selection-list`, so
19
+ * there is no selected state to read, no `done` payload and no Ok / Annulla pair — closing is the
20
+ * only way out and it is always available. It carries no add / edit / delete affordance either:
21
+ * a dialog that cannot change anything is the whole point, and a caller that needs commands wants
22
+ * `SelectDialogComponent` instead.
23
+ *
24
+ * Filtering is client-side, through the same `search` pipe the select dialog uses on its local
25
+ * items. There is no server-side lookup: paging a list nobody can act on would buy nothing.
26
+ */
27
+ declare class ListDialogComponent {
28
+ private readonly cdr;
29
+ protected readonly dialogData: _angular_core.WritableSignal<ListDialogData>;
30
+ /** Items currently on screen. Seeded from the dialog data and replaceable through {@link setItems}. */
31
+ protected readonly items: _angular_core.WritableSignal<SelectableItem[]>;
32
+ /** Counters written by the `search` pipe while it filters, read back by the footer. */
33
+ protected filterMetadata: SearchFilterMetadata;
34
+ /** Current search text. */
35
+ protected readonly filterText: _angular_core.WritableSignal<string>;
36
+ /** Root signal form bound to the search input. */
37
+ protected readonly filterForm: _angular_forms_signals.FieldTree<string, string | number, "writable">;
38
+ /**
39
+ * Replaces the items on screen, for a caller that fills the list after opening the dialog or
40
+ * refreshes it while it is open.
41
+ * @param items - The new items to display; an empty array clears the list.
42
+ */
43
+ setItems(items: SelectableItem[]): void;
44
+ /**
45
+ * Sets the search text programmatically.
46
+ * @param text - The new search string to apply.
47
+ */
48
+ setFilter(text: string): void;
49
+ /**
50
+ * Returns the current search text.
51
+ * @returns The active search string.
52
+ */
53
+ getFilter(): string;
54
+ /** Clears the search text, restoring the whole list. */
55
+ protected clearFilter(): void;
56
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ListDialogComponent, never>;
57
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ListDialogComponent, "ng-component", never, {}, {}, never, never, true, never>;
58
+ }
59
+
14
60
  declare class SelectDialogComponent {
15
61
  readonly paginator: _angular_core.Signal<MatPaginator>;
16
62
  readonly selection: _angular_core.Signal<MatSelectionList>;
@@ -345,5 +391,5 @@ declare class SendToDialogComponent implements ISendToDialog {
345
391
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SendToDialogComponent, "ng-component", never, {}, { "done": "done"; "populate": "populate"; }, never, never, true, never>;
346
392
  }
347
393
 
348
- export { SelectDialogComponent, SelectTreeDialogComponent, SendToDialogComponent, TreeDataSource };
394
+ export { ListDialogComponent, SelectDialogComponent, SelectTreeDialogComponent, SendToDialogComponent, TreeDataSource };
349
395
  export type { SelectTreeDialogAppend, SendToDialogData };