spiderly 19.9.2 → 19.9.4

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,7 +1,7 @@
1
1
  import { AfterViewInit, EventEmitter, OnDestroy, OnInit, TemplateRef } from '@angular/core';
2
2
  import { ActivatedRoute, Router } from '@angular/router';
3
3
  import { TranslocoService } from '@jsverse/transloco';
4
- import { SelectItem } from 'primeng/api';
4
+ import { SelectItem, SortMeta } from 'primeng/api';
5
5
  import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
6
6
  import { Table, TableFilterEvent, TableLazyLoadEvent } from 'primeng/table';
7
7
  import { Observable } from 'rxjs';
@@ -78,6 +78,22 @@ export declare class SpiderlyDataTableComponent implements OnInit, AfterViewInit
78
78
  stateKey?: string;
79
79
  /** 'session' persists across refresh only; 'local' persists indefinitely. */
80
80
  stateStorage: 'session' | 'local';
81
+ /**
82
+ * Column field the table sorts by while the user has no sort of their own — applied on
83
+ * first load (persisted state, when present, wins) and re-applied whenever an action
84
+ * would leave the table unsorted (tri-state header click, Clear filters). Shows as a
85
+ * regular header sort arrow. Omit to keep the backend's implicit Id DESC ordering.
86
+ */
87
+ defaultSortField?: string;
88
+ /** Direction for `defaultSortField`: 1 ascending (default), -1 descending. */
89
+ defaultSortOrder: 1 | -1;
90
+ initialMultiSortMeta: SortMeta[] | null;
91
+ /** Columns currently rendered — `cols` minus the hidden ones. Actions columns always render. */
92
+ visibleCols: Column[];
93
+ /** Cached count of visible data columns, so template bindings don't re-derive it per CD cycle. */
94
+ private visibleDataColsCount;
95
+ /** Data columns offered in the column chooser (actions columns are excluded). */
96
+ chooserCols: Column[];
81
97
  resolvedStateKey: string | null;
82
98
  selectedItemIds: number[];
83
99
  getAlreadySelectedItemIds: (additionalIndexes?: any) => number[];
@@ -103,6 +119,69 @@ export declare class SpiderlyDataTableComponent implements OnInit, AfterViewInit
103
119
  ngAfterViewInit(): void;
104
120
  private setupRemovableSort;
105
121
  ngOnInit(): void;
122
+ /**
123
+ * User visibility choices (field → visible), holding only fields the user explicitly
124
+ * toggled away from their declared default — so a page changing a column's declared
125
+ * default later flows through to every user who never touched that column.
126
+ */
127
+ private columnVisibilityOverrides;
128
+ /**
129
+ * Columns revealed by the load-time reconciliation. Kept apart from
130
+ * `columnVisibilityOverrides` so persisting a later unrelated toggle can't promote a
131
+ * transient safety reveal into a durable choice.
132
+ */
133
+ private revealedByConstraint;
134
+ /** A data column shows values for a `field`; anything else (the actions column) always renders. */
135
+ private static isDataColumn;
136
+ /**
137
+ * Storage slot for the visibility overrides. Deliberately ALWAYS localStorage, even when
138
+ * `stateStorage` is 'session': the column layout is a durable preference, while filters
139
+ * are a transient working set — different natural lifetimes.
140
+ */
141
+ private get columnsStateKey();
142
+ /** Actions columns always render; data columns follow reveal/override, then declared default. */
143
+ isColumnVisible(col: Column): boolean;
144
+ private refreshVisibleCols;
145
+ /**
146
+ * Locked columns can't be toggled; the last visible data column can't be hidden — the
147
+ * table must never collapse to just an actions column. Revealing is always allowed.
148
+ */
149
+ canToggleColumn(col: Column): boolean;
150
+ toggleColumn(col: Column, visible: boolean): void;
151
+ /** Restores every column to its declared default and forgets the stored override. */
152
+ resetColumnVisibility(): void;
153
+ /**
154
+ * A hidden column contributes nothing to filtering or sorting: the header is the only
155
+ * filter surface, so a kept constraint would restrict the data invisibly. Reloads (once)
156
+ * only when a constraint was actually cleared — plain hides don't need a server round-trip.
157
+ */
158
+ private clearHiddenColumnConstraints;
159
+ /** Whether filter metadata (single or array) carries a real constraint, not just an empty slot. */
160
+ private static isActiveFilterMeta;
161
+ private persistColumnVisibility;
162
+ private restoreColumnVisibility;
163
+ /** Parses a JSON entry from web storage; missing or corrupted entries read as null. */
164
+ private static readStoredJson;
165
+ /**
166
+ * PrimeNG's persisted table state (filters/sort/pagination), read directly from storage
167
+ * because we need it before PrimeNG's restoreState() runs on the first [value] change.
168
+ */
169
+ private persistedTableState;
170
+ /**
171
+ * Guards the "hidden contributes nothing" invariant against state this component didn't
172
+ * write (older blobs, hand-edited storage): a hidden column the persisted table state
173
+ * still filters or sorts by is revealed rather than constraining the data invisibly.
174
+ * In-memory only — once the constraint is gone, the user's stored choice reapplies.
175
+ */
176
+ private reconcileVisibilityWithPersistedConstraints;
177
+ /**
178
+ * The declared default as PrimeNG sort meta, or null when none is declared — or when its
179
+ * column is hidden ("hidden contributes nothing"): the table then falls back to the
180
+ * backend's implicit Id DESC, exactly as if no default were declared.
181
+ */
182
+ private defaultMultiSortMeta;
183
+ private persistedMultiSortMeta;
184
+ private applyDefaultSortIfUnsorted;
106
185
  lazyLoad(event: TableLazyLoadEvent): void;
107
186
  clientLoad(): void;
108
187
  private clientFilterCount;
@@ -141,7 +220,7 @@ export declare class SpiderlyDataTableComponent implements OnInit, AfterViewInit
141
220
  rowUnselect(id: number): void;
142
221
  getFormArrayControlByIndex(formControlName: string, index: number): SpiderlyFormControl;
143
222
  static ɵfac: i0.ɵɵFactoryDeclaration<SpiderlyDataTableComponent, never>;
144
- static ɵcmp: i0.ɵɵComponentDeclaration<SpiderlyDataTableComponent, "spiderly-data-table", never, { "tableTitle": { "alias": "tableTitle"; "required": false; }; "tableIcon": { "alias": "tableIcon"; "required": false; }; "items": { "alias": "items"; "required": false; }; "rows": { "alias": "rows"; "required": false; }; "cols": { "alias": "cols"; "required": false; }; "showPaginator": { "alias": "showPaginator"; "required": false; }; "showCardWrapper": { "alias": "showCardWrapper"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "idField": { "alias": "idField"; "required": false; }; "getPaginatedListObservableMethod": { "alias": "getPaginatedListObservableMethod"; "required": false; }; "exportListToExcelObservableMethod": { "alias": "exportListToExcelObservableMethod"; "required": false; }; "deleteItemFromTableObservableMethod": { "alias": "deleteItemFromTableObservableMethod"; "required": false; }; "deleteListFromTableObservableMethod": { "alias": "deleteListFromTableObservableMethod"; "required": false; }; "newlySelectedItems": { "alias": "newlySelectedItems"; "required": false; }; "unselectedItems": { "alias": "unselectedItems"; "required": false; }; "selectionMode": { "alias": "selectionMode"; "required": false; }; "selectedLazyLoadObservableMethod": { "alias": "selectedLazyLoadObservableMethod"; "required": false; }; "additionalFilterIdLong": { "alias": "additionalFilterIdLong"; "required": false; }; "showAddButton": { "alias": "showAddButton"; "required": false; }; "showExportToExcelButton": { "alias": "showExportToExcelButton"; "required": false; }; "showReloadTableButton": { "alias": "showReloadTableButton"; "required": false; }; "getFormArrayItems": { "alias": "getFormArrayItems"; "required": false; }; "hasLazyLoad": { "alias": "hasLazyLoad"; "required": false; }; "stateKey": { "alias": "stateKey"; "required": false; }; "stateStorage": { "alias": "stateStorage"; "required": false; }; "getAlreadySelectedItemIds": { "alias": "getAlreadySelectedItemIds"; "required": false; }; "getAlreadySelectedItems": { "alias": "getAlreadySelectedItems"; "required": false; }; "getFormControl": { "alias": "getFormControl"; "required": false; }; "additionalIndexes": { "alias": "additionalIndexes"; "required": false; }; "navigateOnRowClick": { "alias": "navigateOnRowClick"; "required": false; }; "rowNavigationPath": { "alias": "rowNavigationPath"; "required": false; }; }, { "onTotalRecordsChange": "onTotalRecordsChange"; "onLazyLoad": "onLazyLoad"; "onIsAllSelectedChange": "onIsAllSelectedChange"; "onRowSelect": "onRowSelect"; "onRowUnselect": "onRowUnselect"; }, ["actionsTemplate"], never, true, never>;
223
+ static ɵcmp: i0.ɵɵComponentDeclaration<SpiderlyDataTableComponent, "spiderly-data-table", never, { "tableTitle": { "alias": "tableTitle"; "required": false; }; "tableIcon": { "alias": "tableIcon"; "required": false; }; "items": { "alias": "items"; "required": false; }; "rows": { "alias": "rows"; "required": false; }; "cols": { "alias": "cols"; "required": false; }; "showPaginator": { "alias": "showPaginator"; "required": false; }; "showCardWrapper": { "alias": "showCardWrapper"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "idField": { "alias": "idField"; "required": false; }; "getPaginatedListObservableMethod": { "alias": "getPaginatedListObservableMethod"; "required": false; }; "exportListToExcelObservableMethod": { "alias": "exportListToExcelObservableMethod"; "required": false; }; "deleteItemFromTableObservableMethod": { "alias": "deleteItemFromTableObservableMethod"; "required": false; }; "deleteListFromTableObservableMethod": { "alias": "deleteListFromTableObservableMethod"; "required": false; }; "newlySelectedItems": { "alias": "newlySelectedItems"; "required": false; }; "unselectedItems": { "alias": "unselectedItems"; "required": false; }; "selectionMode": { "alias": "selectionMode"; "required": false; }; "selectedLazyLoadObservableMethod": { "alias": "selectedLazyLoadObservableMethod"; "required": false; }; "additionalFilterIdLong": { "alias": "additionalFilterIdLong"; "required": false; }; "showAddButton": { "alias": "showAddButton"; "required": false; }; "showExportToExcelButton": { "alias": "showExportToExcelButton"; "required": false; }; "showReloadTableButton": { "alias": "showReloadTableButton"; "required": false; }; "getFormArrayItems": { "alias": "getFormArrayItems"; "required": false; }; "hasLazyLoad": { "alias": "hasLazyLoad"; "required": false; }; "stateKey": { "alias": "stateKey"; "required": false; }; "stateStorage": { "alias": "stateStorage"; "required": false; }; "defaultSortField": { "alias": "defaultSortField"; "required": false; }; "defaultSortOrder": { "alias": "defaultSortOrder"; "required": false; }; "getAlreadySelectedItemIds": { "alias": "getAlreadySelectedItemIds"; "required": false; }; "getAlreadySelectedItems": { "alias": "getAlreadySelectedItems"; "required": false; }; "getFormControl": { "alias": "getFormControl"; "required": false; }; "additionalIndexes": { "alias": "additionalIndexes"; "required": false; }; "navigateOnRowClick": { "alias": "navigateOnRowClick"; "required": false; }; "rowNavigationPath": { "alias": "rowNavigationPath"; "required": false; }; }, { "onTotalRecordsChange": "onTotalRecordsChange"; "onLazyLoad": "onLazyLoad"; "onIsAllSelectedChange": "onIsAllSelectedChange"; "onRowSelect": "onRowSelect"; "onRowUnselect": "onRowUnselect"; }, ["actionsTemplate"], never, true, never>;
145
224
  }
146
225
  export declare class Action {
147
226
  name?: string;
@@ -181,6 +260,17 @@ export declare class Column<T = any> {
181
260
  showTime?: boolean;
182
261
  decimalPlaces?: number;
183
262
  sortable?: boolean;
263
+ /**
264
+ * Whether the column is initially rendered. Defaults to `true`. Declare `visible: false` for
265
+ * columns that should be available in the column chooser but hidden until the user reveals them.
266
+ */
267
+ visible?: boolean;
268
+ /**
269
+ * Pins the column: it always renders and shows in the chooser as checked and disabled.
270
+ * Use for the row's identifying column (e.g. a product's title) so the table can never
271
+ * lose its anchor.
272
+ */
273
+ lockVisible?: boolean;
184
274
  /**
185
275
  * Fired when this column's cell is clicked. Receives a {@link CellClickEvent} with the row id,
186
276
  * the column field, the full row, the raw and formatted cell value, the clicked `<td>` element
@@ -191,7 +281,7 @@ export declare class Column<T = any> {
191
281
  * Not applied to editable cells — those belong to their inline input.
192
282
  */
193
283
  onCellClick?: (event: CellClickEvent) => void;
194
- constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, onCellClick, }?: {
284
+ constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible, onCellClick, }?: {
195
285
  name?: string;
196
286
  field?: string & keyof T;
197
287
  filterField?: string & keyof T;
@@ -205,6 +295,8 @@ export declare class Column<T = any> {
205
295
  showTime?: boolean;
206
296
  decimalPlaces?: number;
207
297
  sortable?: boolean;
298
+ visible?: boolean;
299
+ lockVisible?: boolean;
208
300
  onCellClick?: (event: CellClickEvent) => void;
209
301
  });
210
302
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spiderly",
3
- "version": "19.9.2",
3
+ "version": "19.9.4",
4
4
  "author": "Filip Trivan",
5
5
  "license": "MIT",
6
6
  "description": "Spiderly Angular Library to use in combination with Spiderly.",
@@ -43,6 +43,32 @@
43
43
  text-decoration: underline;
44
44
  }
45
45
 
46
+ .column-chooser {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: 8px;
50
+ }
51
+ .column-chooser-option {
52
+ display: flex;
53
+ align-items: center;
54
+ gap: 8px;
55
+ cursor: pointer;
56
+ }
57
+ .column-chooser-reset {
58
+ margin-top: 4px;
59
+ padding: 0;
60
+ border: none;
61
+ background: none;
62
+ color: var(--p-primary-color);
63
+ cursor: pointer;
64
+ align-self: flex-start;
65
+ font-size: 0.875rem;
66
+
67
+ &:hover {
68
+ text-decoration: underline;
69
+ }
70
+ }
71
+
46
72
  ::ng-deep {
47
73
  .p-datatable-thead {
48
74
  position: unset !important;