@arsedizioni/ars-utils 22.5.17 → 22.5.18

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.
@@ -1,3 +1,4 @@
1
+ import * as _angular_forms_signals from '@angular/forms/signals';
1
2
  import * as _angular_core from '@angular/core';
2
3
  import { DestroyRef, ChangeDetectorRef } from '@angular/core';
3
4
  import { ScrollDispatcher } from '@angular/cdk/scrolling';
@@ -315,12 +316,6 @@ declare class ClipperSearchResultManager extends ClipperDocumentManager {
315
316
  protected snapshot: ClipperSearchResult | undefined;
316
317
  protected readonly filterBusy: _angular_core.WritableSignal<boolean>;
317
318
  protected filterParams: ClipperSearchParams;
318
- /**
319
- * Parameters that produced the result set currently on screen, frozen at the moment the query
320
- * was issued. Pagination and sorting page over this copy so that filter pane edits which have
321
- * not been applied yet cannot leak into a page change.
322
- */
323
- protected activeParams: ClipperSearchParams | undefined;
324
319
  protected readonly filterPaneHasBackdrop: _angular_core.WritableSignal<boolean>;
325
320
  protected readonly filterPaneClosed: _angular_core.WritableSignal<boolean>;
326
321
  protected readonly filterPane2HasBackdrop: _angular_core.WritableSignal<boolean>;
@@ -464,32 +459,6 @@ declare class ClipperSearchResultManager extends ClipperDocumentManager {
464
459
  * @param queryChunks - Pipe-separated highlight chunks (e.g. "|1|2|3...").
465
460
  */
466
461
  openDocument(documentId?: string, query?: string, queryChunks?: string): void;
467
- /**
468
- * Freezes the parameters that produced the result set currently on screen. Paging and
469
- * re-sorting must run against this copy, never against `filterParams`, which is bound to the
470
- * filter pane and may hold edits the user has not applied yet.
471
- * @param params - The parameters actually sent to the server for the current result set.
472
- */
473
- protected setActiveParams(params: ClipperSearchParams): void;
474
- /**
475
- * Returns a working copy of the parameters that produced the result set currently on screen.
476
- * @returns A clone of the active parameters, or `undefined` when no search has run yet.
477
- */
478
- protected getActiveParams(): ClipperSearchParams | undefined;
479
- /**
480
- * Builds the parameters needed to load a different page of the result set currently on screen.
481
- * @param pageIndex - The zero-based index of the requested page.
482
- * @returns A clone of the active parameters with the paging offset moved to `pageIndex`, or
483
- * `undefined` when no search has run yet.
484
- */
485
- protected getPageParams(pageIndex: number): ClipperSearchParams | undefined;
486
- /**
487
- * Revives the date properties of a set of search parameters read back from storage, where JSON
488
- * serialisation has turned them into strings.
489
- * @param params - The deserialised parameters, or `undefined` when the stored state predates them.
490
- * @returns The same instance with its date properties converted back to `Date`, or `undefined`.
491
- */
492
- protected reviveParamsDates(params?: ClipperSearchParams): ClipperSearchParams | undefined;
493
462
  /**
494
463
  * Serialises the current component state (paginator, facets, filter params, scroll, sort, data)
495
464
  * to the given storage under the given key, enabling later restoration.
@@ -503,11 +472,57 @@ declare class ClipperSearchResultManager extends ClipperDocumentManager {
503
472
  * @param id - The storage key to read from.
504
473
  * @param storage - The Web Storage instance to use. Defaults to `sessionStorage`.
505
474
  */
475
+ /**
476
+ * Hook invoked just before the component state is serialised by save().
477
+ * Subclasses that keep a separate form model can commit it to filterParams here.
478
+ */
479
+ protected onStateSaving(): void;
480
+ /**
481
+ * Hook invoked after restore() has fully re-hydrated filterParams.
482
+ * Subclasses that keep a separate form model can rebuild it from filterParams here.
483
+ */
484
+ protected onStateRestored(): void;
506
485
  restore(id: string, storage?: Storage): void;
507
486
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ClipperSearchResultManager, never>;
508
487
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ClipperSearchResultManager, "ng-component", never, {}, {}, never, never, true, never>;
509
488
  }
510
489
 
490
+ /**
491
+ * Shape of the browser filter-pane form model. Text fields use '' when empty,
492
+ * numeric/select/date fields use null, list fields use null — never undefined,
493
+ * because signal forms only create child fields for defined values.
494
+ */
495
+ interface BrowserFilterModel {
496
+ modules: NameValueItem<ClipperModule>[] | null;
497
+ tags: NameValueItem<string>[] | null;
498
+ topics: NameValueItem<string>[] | null;
499
+ sectors: NameValueItem<string>[] | null;
500
+ authors: NameValueItem<string>[] | null;
501
+ channels: NameValueItem<any>[] | null;
502
+ number: string;
503
+ year: number | null;
504
+ from: Date | null;
505
+ to: Date | null;
506
+ text: string;
507
+ titleOnly: boolean;
508
+ showNotAbrogatedDocumentsOnly: boolean;
509
+ showCommentedDocumentsOnly: boolean;
510
+ showUnreadDocumentsOnly: boolean;
511
+ sourceNumber: string;
512
+ sourceYear: number | null;
513
+ sourceFrom: Date | null;
514
+ sourceTo: Date | null;
515
+ source: string | null;
516
+ author: string | null;
517
+ type: string | null;
518
+ changedNumber: string;
519
+ changedYear: number | null;
520
+ changedTitle: string;
521
+ modifierNumber: string;
522
+ modifierYear: number | null;
523
+ modifierTitle: string;
524
+ changeReason: number | null;
525
+ }
511
526
  declare class ClipperBrowserComponent extends ClipperSearchResultManager {
512
527
  readonly filterByNumber: _angular_core.Signal<MatInput>;
513
528
  readonly filterByText: _angular_core.Signal<MatInput>;
@@ -599,9 +614,46 @@ declare class ClipperBrowserComponent extends ClipperSearchResultManager {
599
614
  * Falls back to all modules when `selectableModules` is empty or null.
600
615
  */
601
616
  protected readonly filteredModules: _angular_core.Signal<NameValueItem<ClipperModule>[]>;
602
- protected interval: DateInterval;
603
- protected sourceInterval: DateInterval;
604
617
  protected user: ClipperUserInfo | undefined;
618
+ /**
619
+ * Model backing the filter-pane signal form. This is the single source of truth
620
+ * for every filter value bound in the template; `filterParams` only carries the
621
+ * assembled query DTO (see syncParams/loadFilter). Empty values are '' / null /
622
+ * false / null-array — never undefined, so every child field exists.
623
+ */
624
+ protected readonly filterModel: _angular_core.WritableSignal<BrowserFilterModel>;
625
+ /**
626
+ * Signal form for the filter pane. The four year fields accept values from 1750
627
+ * (previously the native min attribute on the inputs).
628
+ */
629
+ protected readonly filterForm: _angular_forms_signals.FieldTree<BrowserFilterModel, string | number, "writable">;
630
+ /** Root signal form for the sort-mode button selector. */
631
+ protected readonly sortForm: _angular_forms_signals.FieldTree<NameValueItem<ClipperSort>, string | number, "writable">;
632
+ /** Debounced stream of keyup events on the interval inputs (shorthand typing support). */
633
+ private readonly intervalKeyup;
634
+ /**
635
+ * Applies a partial update to the filter model.
636
+ * @param patch - The fields to change.
637
+ */
638
+ private patchFilter;
639
+ /**
640
+ * Blocks the space key on the interval inputs; it is reserved as the
641
+ * "copy the other bound" shortcut handled by onIntervalKeyup.
642
+ * @param event - The keydown event from a start or end date input.
643
+ */
644
+ protected onIntervalKeydown(event: KeyboardEvent): void;
645
+ /**
646
+ * Forwards keyup events of the interval inputs to the debounced shorthand parser.
647
+ * @param event - The keyup event from a start or end date input.
648
+ * @param source - `true` when the event comes from the source-publication range.
649
+ * @param end - `true` when the event comes from an end-date input.
650
+ */
651
+ protected onIntervalKeyup(event: KeyboardEvent, source: boolean, end: boolean): void;
652
+ /**
653
+ * Clears one of the two publication ranges.
654
+ * @param source - `true` to clear the source-publication range.
655
+ */
656
+ protected clearInterval(source?: boolean): void;
605
657
  private _viewReady;
606
658
  constructor();
607
659
  /**
@@ -670,8 +722,29 @@ declare class ClipperBrowserComponent extends ClipperSearchResultManager {
670
722
  */
671
723
  protected clearFilter(): void;
672
724
  /**
673
- * Load selected filter
674
- */
725
+ * Copies the filter model into `filterParams`, normalizing empty values back
726
+ * to the undefined-based convention of ClipperSearchParams.
727
+ */
728
+ private syncParams;
729
+ /**
730
+ * Commits the form model to filterParams before the component state is serialised.
731
+ */
732
+ protected onStateSaving(): void;
733
+ /**
734
+ * Rebuilds the form model from filterParams after a state restore.
735
+ * The publication intervals are intentionally not rebuilt from fromDate/toDate,
736
+ * matching the historical behavior where the range inputs were not restored.
737
+ */
738
+ protected onStateRestored(): void;
739
+ /**
740
+ * Builds a DateInterval for the publication range of the current model.
741
+ * @param source - When true, uses the source-publication range instead.
742
+ * @returns The interval, with raw (non-normalized) bounds.
743
+ */
744
+ private modelInterval;
745
+ /**
746
+ * Load selected filter
747
+ */
675
748
  private loadFilter;
676
749
  /**
677
750
  * Apply current filter params
@@ -1258,11 +1331,16 @@ interface SearchFreeTextQueryParams {
1258
1331
  declare class ClipperSearchFreeTextQueryBuilderComponent {
1259
1332
  readonly done: _angular_core.OutputEmitterRef<SearchFreeTextQueryParams>;
1260
1333
  private readonly dialogService;
1261
- protected queryAnd: string;
1262
- protected queryOr: string;
1263
- protected queryNot: string;
1264
- protected queryPhrase: string;
1265
- protected queryStart: string;
1334
+ /** Model backing the signal form: one entry per query operator field. */
1335
+ private readonly model;
1336
+ /** Signal form for the query fields; every field is capped at 200 characters. */
1337
+ protected readonly form: _angular_forms_signals.FieldTree<{
1338
+ queryPhrase: string;
1339
+ queryAnd: string;
1340
+ queryOr: string;
1341
+ queryStart: string;
1342
+ queryNot: string;
1343
+ }, string | number, "writable">;
1266
1344
  /**
1267
1345
  * Resets all query fields to empty strings.
1268
1346
  */
@@ -2,6 +2,7 @@ import * as _angular_core from '@angular/core';
2
2
  import { OnDestroy } from '@angular/core';
3
3
  import { ControlValueAccessor, NgControl } from '@angular/forms';
4
4
  import { NameValueItem, INode } from '@arsedizioni/ars-utils/core';
5
+ import * as _angular_forms_signals from '@angular/forms/signals';
5
6
 
6
7
  declare class ButtonSelectorComponent implements OnDestroy, ControlValueAccessor {
7
8
  ngControl: NgControl;
@@ -196,10 +197,18 @@ declare class ChipsSelectorComponent implements OnDestroy, ControlValueAccessor
196
197
  private propagateTouched;
197
198
  private readonly renderer;
198
199
  private readonly cdr;
199
- /** Currently selected items (may contain multiple entries when `multiple` is `true`). */
200
- protected selection: NameValueItem<any>[];
200
+ /**
201
+ * Currently selected items. Kept loosely typed on purpose: in multi-select mode the
202
+ * bound controls write an array, while in single-select mode mat-select / the chip
203
+ * listbox write a single item; `getSelection()` normalizes both shapes.
204
+ */
205
+ protected readonly selection: _angular_core.WritableSignal<any>;
201
206
  /** The single selected item — used in `button` collapsed-display mode. */
202
- protected singleSelection?: NameValueItem<any>;
207
+ protected readonly singleSelection: _angular_core.WritableSignal<NameValueItem<any>>;
208
+ /** Root signal form bound to the internal mat-select / chip listbox. */
209
+ protected readonly selectionForm: _angular_forms_signals.FieldTree<any, string | number, "writable">;
210
+ /** Root signal form bound to the internal button-selector in `button` collapsed mode. */
211
+ protected readonly singleForm: _angular_forms_signals.FieldTree<NameValueItem<any>, string | number, "writable">;
203
212
  constructor(ngControl: NgControl);
204
213
  ngOnDestroy(): void;
205
214
  /**
@@ -214,7 +223,8 @@ declare class ChipsSelectorComponent implements OnDestroy, ControlValueAccessor
214
223
  */
215
224
  private getSelection;
216
225
  /**
217
- * Schedules a value update after a short delay, giving the template time to sync `ngModel`.
226
+ * Schedules a value update after a short delay, coalescing rapid selection changes
227
+ * before the value is propagated to the outer form.
218
228
  */
219
229
  updateValue(): void;
220
230
  /**
@@ -319,6 +329,8 @@ declare class TreePickerComponent {
319
329
  private _isSelectableNode;
320
330
  /** Current filter text. */
321
331
  protected readonly filterText: _angular_core.WritableSignal<string>;
332
+ /** Root signal form bound to the filter text input. */
333
+ protected readonly filterForm: _angular_forms_signals.FieldTree<string, string | number, "writable">;
322
334
  /** Nodes matching the current filter text, in nodeMap iteration order. */
323
335
  protected readonly filteredItems: _angular_core.WritableSignal<INode[]>;
324
336
  /** Index of the currently highlighted filtered node (-1 = none). */
@@ -1,3 +1,4 @@
1
+ import * as _angular_forms_signals from '@angular/forms/signals';
1
2
  import * as _angular_core from '@angular/core';
2
3
  import { OnDestroy, DoCheck, ElementRef } from '@angular/core';
3
4
  import { ControlValueAccessor, NgControl } from '@angular/forms';
@@ -34,10 +35,12 @@ declare class FileInputComponent implements OnDestroy, DoCheck, MatFormFieldCont
34
35
  private setValue;
35
36
  get value(): FileInfo;
36
37
  get size(): any;
37
- private _required;
38
+ /** Backing signal so the internal form schema reacts to `required` changes. */
39
+ private readonly _required;
38
40
  get required(): boolean;
39
41
  set required(value: boolean);
40
- private _disabled;
42
+ /** Backing signal so the internal form schema reacts to `disabled` changes. */
43
+ private readonly _disabled;
41
44
  get disabled(): boolean;
42
45
  set disabled(value: boolean);
43
46
  get placeholder(): string;
@@ -60,6 +63,16 @@ declare class FileInputComponent implements OnDestroy, DoCheck, MatFormFieldCont
60
63
  readonly changed: _angular_core.OutputEmitterRef<FileInfo>;
61
64
  readonly download: _angular_core.OutputEmitterRef<void>;
62
65
  readonly preview: _angular_core.OutputEmitterRef<void>;
66
+ /** Model backing the internal display form: the (readonly) file-name text. */
67
+ private readonly nameModel;
68
+ /**
69
+ * Internal signal form for the file-name input. It reproduces the previous
70
+ * template-driven validators: `required` follows the `required` input and the
71
+ * size rule mirrors FileSizeValidatorDirective (empty name is left to `required`).
72
+ */
73
+ protected readonly nameForm: _angular_forms_signals.FieldTree<{
74
+ name: string;
75
+ }, string | number, "writable">;
63
76
  private propagateChange;
64
77
  private propagateTouched;
65
78
  constructor(ngControl: NgControl);
@@ -1,3 +1,4 @@
1
+ import * as _angular_forms_signals from '@angular/forms/signals';
1
2
  import * as _angular_core from '@angular/core';
2
3
 
3
4
  /** Constants identifying each filter group slot and text filter channels. */
@@ -90,10 +91,18 @@ declare class FilterBarComponent {
90
91
  readonly text3Length: _angular_core.InputSignal<string>;
91
92
  readonly showTextSearchButton: _angular_core.InputSignal<boolean>;
92
93
  readonly appearance: _angular_core.InputSignal<"fill" | "outline">;
93
- /** Two-way bindable text filter values. */
94
+ /**
95
+ * Text filter values. Empty is represented as '' (never undefined) because the
96
+ * signals back the [formField] bindings; it is normalized to undefined when
97
+ * committed to the CurrentFilter.
98
+ */
94
99
  protected readonly text: _angular_core.WritableSignal<string>;
95
100
  protected readonly text2: _angular_core.WritableSignal<string>;
96
101
  protected readonly text3: _angular_core.WritableSignal<string>;
102
+ /** Signal forms for the three text inputs (max 100 characters each). */
103
+ protected readonly textForm: _angular_forms_signals.FieldTree<string, string | number, "writable">;
104
+ protected readonly text2Form: _angular_forms_signals.FieldTree<string, string | number, "writable">;
105
+ protected readonly text3Form: _angular_forms_signals.FieldTree<string, string | number, "writable">;
97
106
  /** Filter group for slot 1, derived reactively from the `filters` input. */
98
107
  protected readonly flt1: _angular_core.Signal<FilterGroup>;
99
108
  /** Filter group for slot 2, derived reactively from the `filters` input. */
@@ -1,3 +1,4 @@
1
+ import * as _angular_forms_signals from '@angular/forms/signals';
1
2
  import * as _angular_core from '@angular/core';
2
3
  import { MatPaginator, PageEvent } from '@angular/material/paginator';
3
4
  import { ScreenService, SelectableModel } from '@arsedizioni/ars-utils/core';
@@ -12,6 +13,10 @@ declare class SupportNotificationsBrowserComponent {
12
13
  private readonly destroyRef;
13
14
  protected selection: SelectableModel<SupportNotificationInfo, number>;
14
15
  protected searchParams: SupportNotificationsSearchParams;
16
+ /** Current free-text search value, bound to the search input. */
17
+ protected readonly searchText: _angular_core.WritableSignal<string>;
18
+ /** Signal form for the search box (max 200 characters). */
19
+ protected readonly searchForm: _angular_forms_signals.FieldTree<string, string | number, "writable">;
15
20
  protected total: _angular_core.WritableSignal<number>;
16
21
  protected items: _angular_core.WritableSignal<SupportNotificationInfo[]>;
17
22
  constructor();
@@ -2,6 +2,7 @@ import { RawEditorOptions, TinyMCE, Editor } from 'tinymce';
2
2
  import * as _angular_core from '@angular/core';
3
3
  import { OnInit, OnDestroy } from '@angular/core';
4
4
  import { ControlValueAccessor } from '@angular/forms';
5
+ import * as _angular_forms_signals from '@angular/forms/signals';
5
6
 
6
7
  /**
7
8
  * The editor profiles the applications ask for, ready to be handed to
@@ -258,8 +259,13 @@ declare class TinyMceEditorComponent {
258
259
  protected readonly dialogData: _angular_core.WritableSignal<TinyMceEditorDialogData>;
259
260
  /** Whether the editor is in read-only mode. */
260
261
  protected readonly disabled: _angular_core.WritableSignal<boolean>;
261
- /** Current editor content, kept as a plain field for [(ngModel)] two-way binding. */
262
- protected text: string;
262
+ /** Current editor content. */
263
+ protected readonly text: _angular_core.WritableSignal<string>;
264
+ /**
265
+ * Signal form bound to the editor textarea. The disabled state is pushed to the
266
+ * TinymceEditorDirective through the ControlValueAccessor interop.
267
+ */
268
+ protected readonly textForm: _angular_forms_signals.FieldTree<string, string | number, "writable">;
263
269
  /** The profile handed to the editor directive, merged over its defaults. */
264
270
  protected tinymceConfig: RawEditorOptions;
265
271
  constructor();