ngx-mat-table-multi-sort 19.0.0 → 19.1.0-pre.2

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/README.md CHANGED
@@ -9,13 +9,44 @@ An Angular library that adds multi-sort capability to the Angular Material table
9
9
  ![npm](https://img.shields.io/npm/v/ngx-mat-table-multi-sort)
10
10
  ![License](https://img.shields.io/github/license/pgerke/ngx-mat-table-multi-sort)
11
11
 
12
- ## License
12
+ ## Features
13
13
 
14
- The project is subject to the MIT license unless otherwise noted. A copy can be found [here](./LICENSE.md).
14
+ - Extend the Angular Material Table to support multiple sorting
15
+ - Supports Angular 18 and 19. Supporting all actively supported Angular versions is planned (see [#5](https://github.com/pgerke/ngx-mat-table-multi-sort/issues/5))
16
+ - Batteries included: The repository contains a demo application that can help you integrate the library with your project
17
+ - 100% covered by automated unit tests and secured by static code analysis
15
18
 
16
- ## Changelog
19
+ ## How to use this library
17
20
 
18
- Please refer to the [changelog](./CHANGELOG.md) document or the [release notes](https://github.com/pgerke/ngx-mat-table-multi-sort/releases) in GitHub.
21
+ **Prerequisite:** You have created an application using a supported version of Angular and Angular Material
22
+
23
+ 1. In your Angular application run `npm install ngx-mat-table-multi-sort` to add the library to your dependencies
24
+ 1. As this library is using Material, add the following to the `head` element of your `index.html`:
25
+
26
+ ```html
27
+ <link
28
+ href="https://fonts.googleapis.com/icon?family=Material+Icons"
29
+ rel="stylesheet" />
30
+ ```
31
+
32
+ Alternatively, you can also add the following to your `angular.json`:
33
+
34
+ ```json
35
+ "styles": [
36
+ ...
37
+ "https://fonts.googleapis.com/icon?family=Material+Icons",
38
+ ...
39
+ ]
40
+ ```
41
+
42
+ 3. In the template, replace the `matSort` directive with the `matMultiSort` directive.
43
+ 1. Also replace the `mat-sort-header` directive with the `mat-multi-sort-header` directive in the column definitions.
44
+ 1. In the component definition use `MatMultiSortTableDataSource<T>` as your datasource type instead of `MatTableDataSource<T>`.
45
+ 1. Also change the type of the sorter from `MatSort` to `MatMultiSortDirective`
46
+ 1. If you are using standalone components, add the `MatMultiSortDirective` and `MatMultiSortHeaderComponent` to your component's imports array. Otherwise add them to the NgModule that declares your component.
47
+ 1. Done! 🎉
48
+
49
+ Enjoy multi-sorting your Angular Material data table!
19
50
 
20
51
  ## Demo
21
52
 
@@ -26,6 +57,33 @@ The demo application is hosted on [GitHub pages](https://pgerke.github.io/ngx-ma
26
57
  1. Start the demo application by running `npm run start:demo`
27
58
  1. When compilation is completed, the application is running on `http://localhost:4200`
28
59
 
60
+ ## License
61
+
62
+ The project is subject to the MIT license unless otherwise noted. A copy can be found [here](./LICENSE.md).
63
+
64
+ ## Changelog
65
+
66
+ Please refer to the [changelog](./CHANGELOG.md) document or the [release notes](https://github.com/pgerke/ngx-mat-table-multi-sort/releases) in GitHub.
67
+
68
+ ## I found a bug, what do I do?
69
+
70
+ We are happy to hear any feedback regarding the library or its implementation, be it critizism, praise or rants. Please create a [GitHub issue](https://github.com/pgerke/ngx-mat-table-multi-sort/issues) if you would like to contact us.
71
+
72
+ We would especially appreciate, if you could report any issues you encounter while using the library. Issues we know about, we can probably fix.
73
+
74
+ If you want to submit a bug report, please check if the issue you have has already been reported. If you want to contribute additional information to the issue, please add it to the existing issue instead of creating another one. Duplicate issues will take time from bugfixing and thus delay a fix.
75
+
76
+ While creating a bug report, please make it easy for us to fix it by giving us all the details you have about the issue. Always include the version of the library and a short concise description of the issue. Besides that, there are a few other pieces of information that help tracking down bugs:
77
+
78
+ - The system environment in which the issue occurred (e.g. node version)
79
+ - Some steps to reproduce the issue, e.g. a code snippet
80
+ - The expected behaviour and how the failed failed to meet that expectation
81
+ - Anything else you think we might need
82
+
83
+ ## I have a feature request, what do I do?
84
+
85
+ Please create a [GitHub issue](https://github.com/pgerke/ngx-mat-table-multi-sort/issues)!
86
+
29
87
  ## Acknowledgements
30
88
 
31
89
  This library was inspired by the work in [ngx-multi-sort-table](https://github.com/Maxl94/ngx-multi-sort-table). While it was created from scratch and is an independent implementation tailored to specific use cases, their ideas and approach provided valuable guidance in its creation. Many thanks for their contributions to the open-source community!
@@ -1,11 +1,22 @@
1
+ import { moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';
1
2
  import * as i0 from '@angular/core';
2
- import { Directive, inject, Component, ViewEncapsulation } from '@angular/core';
3
+ import { signal, Directive, inject, Component, ViewEncapsulation, ANIMATION_MODULE_TYPE, Input } from '@angular/core';
3
4
  import { MatSort, MatSortHeader } from '@angular/material/sort';
4
5
  import { MatTableDataSource } from '@angular/material/table';
5
6
  import { NgIf } from '@angular/common';
7
+ import * as i1 from '@angular/material/chips';
8
+ import { MatChipsModule } from '@angular/material/chips';
9
+ import * as i2 from '@angular/material/icon';
10
+ import { MatIconModule } from '@angular/material/icon';
6
11
 
7
12
  class MatMultiSortDirective extends MatSort {
8
- _sorts = [];
13
+ /**
14
+ * A writable signal that holds an array of Sort objects.
15
+ * This signal is used to manage the sorting state of the table.
16
+ *
17
+ * @readonly
18
+ */
19
+ _sorts = signal([]);
9
20
  /**
10
21
  * Retrieves the sort direction for a given column ID.
11
22
  *
@@ -13,7 +24,7 @@ class MatMultiSortDirective extends MatSort {
13
24
  * @returns The sort direction ('asc', 'desc', or '') for the specified column ID.
14
25
  */
15
26
  getSortDirection(id) {
16
- const sort = this._sorts.find((e) => e.active === id);
27
+ const sort = this._sorts().find((e) => e.active === id);
17
28
  return sort ? sort.direction : "";
18
29
  }
19
30
  /**
@@ -23,7 +34,7 @@ class MatMultiSortDirective extends MatSort {
23
34
  * @returns The sort index of the column, or -1 if the column is not active.
24
35
  */
25
36
  getSortIndex(id) {
26
- return this._sorts.findIndex((e) => e.active === id);
37
+ return this._sorts().findIndex((e) => e.active === id);
27
38
  }
28
39
  sort(sortable) {
29
40
  this.active = sortable.id;
@@ -32,20 +43,67 @@ class MatMultiSortDirective extends MatSort {
32
43
  // If the column is not active, add it to the list of active columns.
33
44
  if (index < 0) {
34
45
  this.direction = sortable.start ? sortable.start : this.start;
35
- this._sorts.push({ active: this.active, direction: this.direction });
46
+ this._sorts().push({ active: this.active, direction: this.direction });
36
47
  }
37
48
  else {
38
49
  // If the column is active, update the direction or remove it if the direction is empty.
39
50
  this.direction = this.getNextSortDirection(sortable);
40
51
  if (!this.direction) {
41
- this._sorts.splice(index, 1);
52
+ this._sorts().splice(index, 1);
42
53
  }
43
54
  else {
44
- this._sorts[index].direction = this.direction;
55
+ this._sorts()[index].direction = this.direction;
45
56
  }
46
57
  }
47
58
  this.sortChange.emit({ active: this.active, direction: this.direction });
48
59
  }
60
+ /**
61
+ * Removes a sort level by its identifier.
62
+ * If the sort level is not found, the method returns without making any changes.
63
+ *
64
+ * @param id - The identifier of the sort level to be removed.
65
+ * @returns void
66
+ */
67
+ removeSortLevel(id) {
68
+ const index = this.getSortIndex(id);
69
+ if (index < 0)
70
+ return;
71
+ this._sorts().splice(index, 1);
72
+ this.sortChange.emit();
73
+ }
74
+ /**
75
+ * Reorders the sort level by moving an item in the sort array from a previous index to a current index.
76
+ * If the previous index is the same as the current index, the function returns without making any changes.
77
+ *
78
+ * @param previousIndex - The index of the item to be moved.
79
+ * @param currentIndex - The index to which the item should be moved.
80
+ */
81
+ reorderSortLevel(previousIndex, currentIndex) {
82
+ if (previousIndex === currentIndex)
83
+ return;
84
+ moveItemInArray(this._sorts(), previousIndex, currentIndex);
85
+ this.sortChange.emit(this._sorts()[currentIndex]);
86
+ }
87
+ /**
88
+ * Toggles the sort direction for the given column ID.
89
+ *
90
+ * @param id - The unique identifier of the column to toggle the sort direction for.
91
+ * @returns void
92
+ */
93
+ toggleSortDirection(id) {
94
+ const index = this.getSortIndex(id);
95
+ if (index < 0)
96
+ return;
97
+ this.active = id;
98
+ // The value of this.direction is used in the getNextSortDirection method. That's why it is necessary for it to be set before the call to getNextSortDirection.
99
+ this.direction = this.getSortDirection(id);
100
+ this.direction = this.getNextSortDirection({
101
+ id: id,
102
+ disableClear: true,
103
+ });
104
+ this._sorts()[index].direction = this.direction;
105
+ this.sortChange.emit({ active: this.active, direction: this.direction });
106
+ }
49
107
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MatMultiSortDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
50
108
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: MatMultiSortDirective, isStandalone: true, selector: "[matMultiSort]", host: { classAttribute: "mat-sort" }, exportAs: ["matMultiSort"], usesInheritance: true, ngImport: i0 });
51
109
  }
@@ -120,10 +178,10 @@ class MatMultiSortTableDataSource extends MatTableDataSource {
120
178
  }
121
179
  sortDataFunction(data) {
122
180
  // Return the data if there is no sort
123
- if (!this.sort?._sorts.length)
181
+ if (!this.sort?._sorts().length)
124
182
  return data;
125
183
  // Sort the data:
126
- return data.sort((a, b) => MultiCriterionSort(a, b, this.sort._sorts));
184
+ return data.sort((a, b) => MultiCriterionSort(a, b, this.sort._sorts()));
127
185
  }
128
186
  }
129
187
 
@@ -166,6 +224,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
166
224
  args: [{ selector: "[mat-multi-sort-header]", exportAs: "matMultiSortHeader", imports: [NgIf], providers: [{ provide: MatSort, useExisting: MatMultiSortDirective }], encapsulation: ViewEncapsulation.None, template: "<!--\n We set the `tabindex` on an element inside the table header, rather than the header itself,\n because of a bug in NVDA where having a `tabindex` on a `th` breaks keyboard navigation in the\n table (see https://github.com/nvaccess/nvda/issues/7718). This allows for the header to both\n be focusable, and have screen readers read out its `aria-sort` state. We prefer this approach\n over having a button with an `aria-label` inside the header, because the button's `aria-label`\n will be read out as the user is navigating the table's cell (see #13012).\n\n The approach is based off of: https://dequeuniversity.com/library/aria/tables/sf-sortable-grid\n-->\n<div\n class=\"mat-sort-header-container mat-focus-indicator\"\n [class.mat-sort-header-sorted]=\"_isSorted()\"\n [class.mat-sort-header-position-before]=\"arrowPosition === 'before'\"\n [class.mat-sort-header-descending]=\"sortDirection === 'desc'\"\n [class.mat-sort-header-ascending]=\"sortDirection === 'asc'\"\n [class.mat-sort-header-recently-cleared-ascending]=\"\n _recentlyCleared() === 'asc'\n \"\n [class.mat-sort-header-recently-cleared-descending]=\"\n _recentlyCleared() === 'desc'\n \"\n [class.mat-sort-header-animations-disabled]=\"\n _animationModule === 'NoopAnimations'\n \"\n [attr.tabindex]=\"_isDisabled() ? null : 0\"\n [attr.role]=\"_isDisabled() ? null : 'button'\">\n <!--\n TODO(crisbeto): this div isn't strictly necessary, but we have to keep it due to a large\n number of screenshot diff failures. It should be removed eventually. Note that the difference\n isn't visible with a shorter header, but once it breaks up into multiple lines, this element\n causes it to be center-aligned, whereas removing it will keep the text to the left.\n -->\n <div class=\"mat-sort-header-content\">\n <ng-content></ng-content>\n </div>\n\n <!-- Disable animations while a current animation is running -->\n @if (_renderArrow()) {\n <div class=\"mat-sort-header-arrow\">\n <svg viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path\n d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\" />\n </svg>\n </div>\n }\n <div *ngIf=\"_isSorted()\" class=\"mat-sort-header-counter\">\n {{ sortIndex + 1 }}\n </div>\n</div>\n", styles: [".mat-sort-header-container{display:flex;cursor:pointer;align-items:center;letter-spacing:normal;outline:0}[mat-sort-header].cdk-keyboard-focused .mat-sort-header-container,[mat-sort-header].cdk-program-focused .mat-sort-header-container{border-bottom:solid 1px currentColor}.mat-sort-header-disabled .mat-sort-header-container{cursor:default}.mat-sort-header-container:before{margin:calc(calc(var(--mat-focus-indicator-border-width, 3px) + 2px) * -1)}.mat-sort-header-content{display:flex;align-items:center}.mat-sort-header-position-before{flex-direction:row-reverse}@keyframes _mat-sort-header-recently-cleared-ascending{0%{transform:translateY(0);opacity:1}to{transform:translateY(-25%);opacity:0}}@keyframes _mat-sort-header-recently-cleared-descending{0%{transform:translateY(0) rotate(180deg);opacity:1}to{transform:translateY(25%) rotate(180deg);opacity:0}}.mat-sort-header-arrow{height:12px;width:12px;position:relative;transition:transform 225ms cubic-bezier(.4,0,.2,1),opacity 225ms cubic-bezier(.4,0,.2,1);opacity:0;overflow:visible;color:var(--mat-sort-arrow-color, var(--mat-sys-on-surface))}.mat-sort-header.cdk-keyboard-focused .mat-sort-header-arrow,.mat-sort-header.cdk-program-focused .mat-sort-header-arrow,.mat-sort-header:hover .mat-sort-header-arrow{opacity:.54}.mat-sort-header .mat-sort-header-sorted .mat-sort-header-arrow{opacity:1}.mat-sort-header-descending .mat-sort-header-arrow{transform:rotate(180deg)}.mat-sort-header-recently-cleared-ascending .mat-sort-header-arrow{transform:translateY(-25%);transition:none;animation:_mat-sort-header-recently-cleared-ascending 225ms cubic-bezier(.4,0,.2,1) forwards}.mat-sort-header-animations-disabled .mat-sort-header-arrow{transition-duration:0ms;animation-duration:0ms}.mat-sort-header-arrow svg{width:24px;height:24px;fill:currentColor;position:absolute;top:50%;left:50%;margin:-12px 0 0 -12px;transform:translateZ(0)}.mat-sort-header-arrow,[dir=rtl] .mat-sort-header-position-before .mat-sort-header-arrow{margin:0 0 0 6px}.mat-sort-header-position-before .mat-sort-header-arrow,[dir=rtl] .mat-sort-header-arrow{margin:0 6px 0 0}.mat-sort-header-counter{color:var(--mat-sort-arrow-color, var(--mat-sys-on-surface))}\n"] }]
167
225
  }] });
168
226
 
227
+ class MatMultiSortControlComponent {
228
+ /**
229
+ * Injects the ANIMATION_MODULE_TYPE token, which indicates the type of animation module being used.
230
+ * This is an optional dependency and may be undefined if the animation module is not provided.
231
+ *
232
+ * @readonly
233
+ * @type {ANIMATION_MODULE_TYPE | undefined}
234
+ */
235
+ _animationModule = inject(ANIMATION_MODULE_TYPE, { optional: true });
236
+ /**
237
+ * Specifies the orientation of the drop list.
238
+ * Can be either "horizontal" or "vertical".
239
+ *
240
+ * @type {DropListOrientation}
241
+ * @default "horizontal"
242
+ */
243
+ orientation = "horizontal";
244
+ /**
245
+ * An optional input property that accepts an instance of `MatMultiSortDirective`.
246
+ * This directive is used to control the sorting behavior of the table.
247
+ */
248
+ sort;
249
+ /**
250
+ * Retrieves the array of Sort objects from the current sort instance.
251
+ * If the sort instance is not defined, it returns an empty array.
252
+ *
253
+ * @returns {Sort[]} An array of Sort objects or an empty array if no sorts are defined.
254
+ */
255
+ get sorts() {
256
+ return this.sort?._sorts() || [];
257
+ }
258
+ /**
259
+ * Handles the click event on a sort chip.
260
+ * Toggles the sort direction for the given sort ID.
261
+ *
262
+ * @param id - The identifier of the sort field to toggle.
263
+ * @returns void
264
+ */
265
+ onChipClick(id) {
266
+ this.sort?.toggleSortDirection(id);
267
+ }
268
+ /**
269
+ * Handles the event when a sort chip is removed.
270
+ *
271
+ * @param id - The identifier of the sort level to be removed.
272
+ * @returns void
273
+ */
274
+ onChipRemoved(id) {
275
+ this.sort?.removeSortLevel(id);
276
+ }
277
+ /**
278
+ * Handles the drop event for drag-and-drop sorting.
279
+ * Reorders the sort levels based on the previous and current indices.
280
+ *
281
+ * @param event - The drag-and-drop event containing the previous and current indices of the sort order.
282
+ */
283
+ onDrop(event) {
284
+ this.sort?.reorderSortLevel(event.previousIndex, event.currentIndex);
285
+ }
286
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MatMultiSortControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
287
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: MatMultiSortControlComponent, isStandalone: true, selector: "mat-multi-sort-control", inputs: { orientation: "orientation", sort: "sort" }, ngImport: i0, template: "<mat-chip-listbox\n cdkDropList\n [cdkDropListOrientation]=\"orientation\"\n (cdkDropListDropped)=\"onDrop($event)\">\n @for (column of sorts; track $index) {\n <mat-chip\n class=\"mat-sort-header\"\n cdkDrag\n (click)=\"onChipClick(column.active)\"\n (removed)=\"onChipRemoved(column.active)\">\n <div\n matChipAvatar\n class=\"mat-sort-header-container mat-sort-header-sorted mat-focus-indicator\"\n [class.mat-sort-header-descending]=\"column.direction === 'desc'\"\n [class.mat-sort-header-ascending]=\"column.direction === 'asc'\"\n [class.mat-sort-header-animations-disabled]=\"\n _animationModule === 'NoopAnimations'\n \">\n <div class=\"mat-sort-header-arrow\">\n <svg viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path\n d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\" />\n </svg>\n </div>\n </div>\n {{ column.active }}\n <button matChipRemove>\n <mat-icon>clear</mat-icon>\n </button>\n </mat-chip>\n }\n</mat-chip-listbox>\n", styles: [".mat-mdc-chip-listbox.mat-mdc-chip-set.cdk-drop-list .cdk-drop-list-dragging{transition:transform .15s cubic-bezier(0,0,.2,1)}.mat-sort-header{transition:background-color .1s cubic-bezier(0,0,.2,1),box-shadow .1s cubic-bezier(0,0,.2,1)}.mat-sort-header.cdk-drag-animating{transition:transform .15s cubic-bezier(0,0,.2,1)}.mat-sort-header:hover{background-color:#ccc;cursor:move}.mat-sort-header:hover:after{opacity:0}.mat-sort-header:focus:after{opacity:0}.mat-sort-header:active{box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-preview{box-sizing:border-box;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;overflow:hidden}.cdk-drag-placeholder{opacity:0}\n"], dependencies: [{ kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i1.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "directive", type: i1.MatChipAvatar, selector: "mat-chip-avatar, [matChipAvatar]" }, { kind: "component", type: i1.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "directive", type: i1.MatChipRemove, selector: "[matChipRemove]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
288
+ }
289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MatMultiSortControlComponent, decorators: [{
290
+ type: Component,
291
+ args: [{ selector: "mat-multi-sort-control", imports: [CdkDropList, CdkDrag, MatChipsModule, MatIconModule], template: "<mat-chip-listbox\n cdkDropList\n [cdkDropListOrientation]=\"orientation\"\n (cdkDropListDropped)=\"onDrop($event)\">\n @for (column of sorts; track $index) {\n <mat-chip\n class=\"mat-sort-header\"\n cdkDrag\n (click)=\"onChipClick(column.active)\"\n (removed)=\"onChipRemoved(column.active)\">\n <div\n matChipAvatar\n class=\"mat-sort-header-container mat-sort-header-sorted mat-focus-indicator\"\n [class.mat-sort-header-descending]=\"column.direction === 'desc'\"\n [class.mat-sort-header-ascending]=\"column.direction === 'asc'\"\n [class.mat-sort-header-animations-disabled]=\"\n _animationModule === 'NoopAnimations'\n \">\n <div class=\"mat-sort-header-arrow\">\n <svg viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path\n d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\" />\n </svg>\n </div>\n </div>\n {{ column.active }}\n <button matChipRemove>\n <mat-icon>clear</mat-icon>\n </button>\n </mat-chip>\n }\n</mat-chip-listbox>\n", styles: [".mat-mdc-chip-listbox.mat-mdc-chip-set.cdk-drop-list .cdk-drop-list-dragging{transition:transform .15s cubic-bezier(0,0,.2,1)}.mat-sort-header{transition:background-color .1s cubic-bezier(0,0,.2,1),box-shadow .1s cubic-bezier(0,0,.2,1)}.mat-sort-header.cdk-drag-animating{transition:transform .15s cubic-bezier(0,0,.2,1)}.mat-sort-header:hover{background-color:#ccc;cursor:move}.mat-sort-header:hover:after{opacity:0}.mat-sort-header:focus:after{opacity:0}.mat-sort-header:active{box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-preview{box-sizing:border-box;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;overflow:hidden}.cdk-drag-placeholder{opacity:0}\n"] }]
292
+ }], propDecorators: { orientation: [{
293
+ type: Input
294
+ }], sort: [{
295
+ type: Input
296
+ }] } });
297
+
169
298
  /*
170
299
  * Public API Surface of lib
171
300
  */
@@ -174,5 +303,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
174
303
  * Generated bundle index. Do not edit.
175
304
  */
176
305
 
177
- export { MatMultiSortDirective, MatMultiSortHeaderComponent, MatMultiSortTableDataSource, MultiCriterionSort };
306
+ export { MatMultiSortControlComponent, MatMultiSortDirective, MatMultiSortHeaderComponent, MatMultiSortTableDataSource, MultiCriterionSort };
178
307
  //# sourceMappingURL=ngx-mat-table-multi-sort.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ngx-mat-table-multi-sort.mjs","sources":["../../../src/lib/mat-multi-sort.directive.ts","../../../src/lib/mat-multi-sort-table-data-source.ts","../../../src/lib/mat-multi-sort-header/mat-multi-sort-header.component.ts","../../../src/lib/mat-multi-sort-header/mat-multi-sort-header.component.html","../../../src/public-api.ts","../../../src/ngx-mat-table-multi-sort.ts"],"sourcesContent":["import { Directive } from \"@angular/core\";\nimport {\n MatSort,\n MatSortable,\n Sort,\n SortDirection,\n} from \"@angular/material/sort\";\n\n@Directive({\n selector: \"[matMultiSort]\",\n exportAs: \"matMultiSort\",\n host: {\n class: \"mat-sort\",\n },\n})\nexport class MatMultiSortDirective extends MatSort {\n readonly _sorts: Sort[] = [];\n\n /**\n * Retrieves the sort direction for a given column ID.\n *\n * @param id - The ID of the column to get the sort direction for.\n * @returns The sort direction ('asc', 'desc', or '') for the specified column ID.\n */\n getSortDirection(id: string): SortDirection {\n const sort = this._sorts.find((e) => e.active === id);\n return sort ? sort.direction : \"\";\n }\n\n /**\n * Gets the sort index of the given column ID.\n *\n * @param id - The ID of the column to get the sort index for.\n * @returns The sort index of the column, or -1 if the column is not active.\n */\n public getSortIndex(id: string): number {\n return this._sorts.findIndex((e) => e.active === id);\n }\n\n override sort(sortable: MatSortable): void {\n this.active = sortable.id;\n this.direction = this.getSortDirection(sortable.id);\n const index = this.getSortIndex(sortable.id);\n\n // If the column is not active, add it to the list of active columns.\n if (index < 0) {\n this.direction = sortable.start ? sortable.start : this.start;\n this._sorts.push({ active: this.active, direction: this.direction });\n } else {\n // If the column is active, update the direction or remove it if the direction is empty.\n this.direction = this.getNextSortDirection(sortable);\n if (!this.direction) {\n this._sorts.splice(index, 1);\n } else {\n this._sorts[index].direction = this.direction;\n }\n }\n\n this.sortChange.emit({ active: this.active, direction: this.direction });\n }\n}\n","import { MatPaginator } from \"@angular/material/paginator\";\nimport { Sort } from \"@angular/material/sort\";\nimport { MatTableDataSource } from \"@angular/material/table\";\nimport { MatMultiSortDirective } from \"./mat-multi-sort.directive\";\n\n/**\n * Sorts two items based on multiple sorting criteria.\n *\n * @description To do this, we iterate over each sort level and compare the values of the active column. If the values are equal, we move to the next sort level. If all sort levels are equal, we return 0.\n *\n * @template T - The type of the items being sorted.\n * @param {T} a - The first item to compare.\n * @param {T} b - The second item to compare.\n * @param {Sort[]} sorts - An array of sorting criteria, where each criterion specifies the property to sort by and the direction of sorting.\n * @returns {number} - A negative number if `a` should come before `b`, a positive number if `a` should come after `b`, or 0 if they are considered equal.\n */\nexport function MultiCriterionSort<T>(a: T, b: T, sorts: Sort[]): number {\n for (const { active, direction } of sorts) {\n const aValue = a[active as keyof T];\n const bValue = b[active as keyof T];\n\n const comparison = compareValues(aValue, bValue);\n\n if (comparison !== 0) {\n return direction === \"desc\" ? -comparison : comparison;\n }\n }\n\n return 0; // If all comparisons are equal, preserve original order\n}\n\nfunction compareValues<T>(aValue: T, bValue: T): number {\n if (aValue == null && bValue != null) return 1;\n if (aValue != null && bValue == null) return -1;\n if (aValue == null && bValue == null) return 0;\n\n if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n return aValue.localeCompare(bValue);\n }\n\n if (aValue > bValue) return 1;\n if (aValue < bValue) return -1;\n return 0;\n}\n\n/**\n * A data source class that extends `MatTableDataSource` to support multi-column sorting.\n *\n * @template T The type of data that the table displays.\n * @template P The type of paginator used, defaults to `MatPaginator`.\n *\n * @extends MatTableDataSource<T, P>\n */\nexport class MatMultiSortTableDataSource<\n T,\n P extends MatPaginator = MatPaginator,\n> extends MatTableDataSource<T, P> {\n override get sort(): MatMultiSortDirective | null {\n return super.sort as MatMultiSortDirective;\n }\n override set sort(sort: MatMultiSortDirective | null) {\n super.sort = sort;\n }\n\n constructor(initialData?: T[]) {\n super(initialData);\n // Set the default sort function\n this.sortData = (data): T[] => this.sortDataFunction(data);\n }\n\n private sortDataFunction(data: T[]): T[] {\n // Return the data if there is no sort\n if (!this.sort?._sorts.length) return data;\n\n // Sort the data:\n return data.sort((a, b) => MultiCriterionSort(a, b, this.sort!._sorts));\n }\n}\n","import { NgIf } from \"@angular/common\";\nimport { Component, inject, OnInit, ViewEncapsulation } from \"@angular/core\";\nimport { MatSort, MatSortHeader, SortDirection } from \"@angular/material/sort\";\nimport { MatMultiSortDirective } from \"../mat-multi-sort.directive\";\n\n@Component({\n selector: \"[mat-multi-sort-header]\", // eslint-disable-line @angular-eslint/component-selector\n exportAs: \"matMultiSortHeader\",\n imports: [NgIf],\n providers: [{ provide: MatSort, useExisting: MatMultiSortDirective }],\n templateUrl: \"./mat-multi-sort-header.component.html\",\n styleUrl: \"./mat-multi-sort-header.component.scss\",\n encapsulation: ViewEncapsulation.None,\n})\nexport class MatMultiSortHeaderComponent\n extends MatSortHeader\n implements OnInit\n{\n override readonly _sort: MatMultiSortDirective = inject(\n MatMultiSortDirective,\n {\n optional: true,\n }\n )!;\n\n /**\n * Retrieves the sort direction for the current column.\n *\n * @returns {SortDirection} The sort direction for the column identified by this.id.\n */\n get sortDirection(): SortDirection {\n return this._sort.getSortDirection(this.id);\n }\n\n /**\n * Gets the sort index for the current column.\n *\n * @returns {number} The index of the sort order for this column.\n */\n get sortIndex(): number {\n return this._sort.getSortIndex(this.id);\n }\n\n override _isSorted(): boolean {\n return this.sortIndex > -1;\n }\n\n override _toggleOnInteraction(): void {\n if (this._isDisabled()) return;\n\n const wasSorted = this._isSorted();\n const prevDirection = this.sortDirection;\n this._sort.sort(this);\n this._recentlyCleared.set(\n wasSorted && !this._isSorted() ? prevDirection : null\n );\n }\n}\n","<!--\n We set the `tabindex` on an element inside the table header, rather than the header itself,\n because of a bug in NVDA where having a `tabindex` on a `th` breaks keyboard navigation in the\n table (see https://github.com/nvaccess/nvda/issues/7718). This allows for the header to both\n be focusable, and have screen readers read out its `aria-sort` state. We prefer this approach\n over having a button with an `aria-label` inside the header, because the button's `aria-label`\n will be read out as the user is navigating the table's cell (see #13012).\n\n The approach is based off of: https://dequeuniversity.com/library/aria/tables/sf-sortable-grid\n-->\n<div\n class=\"mat-sort-header-container mat-focus-indicator\"\n [class.mat-sort-header-sorted]=\"_isSorted()\"\n [class.mat-sort-header-position-before]=\"arrowPosition === 'before'\"\n [class.mat-sort-header-descending]=\"sortDirection === 'desc'\"\n [class.mat-sort-header-ascending]=\"sortDirection === 'asc'\"\n [class.mat-sort-header-recently-cleared-ascending]=\"\n _recentlyCleared() === 'asc'\n \"\n [class.mat-sort-header-recently-cleared-descending]=\"\n _recentlyCleared() === 'desc'\n \"\n [class.mat-sort-header-animations-disabled]=\"\n _animationModule === 'NoopAnimations'\n \"\n [attr.tabindex]=\"_isDisabled() ? null : 0\"\n [attr.role]=\"_isDisabled() ? null : 'button'\">\n <!--\n TODO(crisbeto): this div isn't strictly necessary, but we have to keep it due to a large\n number of screenshot diff failures. It should be removed eventually. Note that the difference\n isn't visible with a shorter header, but once it breaks up into multiple lines, this element\n causes it to be center-aligned, whereas removing it will keep the text to the left.\n -->\n <div class=\"mat-sort-header-content\">\n <ng-content></ng-content>\n </div>\n\n <!-- Disable animations while a current animation is running -->\n @if (_renderArrow()) {\n <div class=\"mat-sort-header-arrow\">\n <svg viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path\n d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\" />\n </svg>\n </div>\n }\n <div *ngIf=\"_isSorted()\" class=\"mat-sort-header-counter\">\n {{ sortIndex + 1 }}\n </div>\n</div>\n","/*\n * Public API Surface of lib\n */\n\nexport * from \"./lib/mat-multi-sort.directive\";\nexport * from \"./lib/mat-multi-sort-table-data-source\";\nexport * from \"./lib/mat-multi-sort-header/mat-multi-sort-header.component\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngx-mat-table-multi-sort.mjs","sources":["../../../src/lib/mat-multi-sort.directive.ts","../../../src/lib/mat-multi-sort-table-data-source.ts","../../../src/lib/mat-multi-sort-header/mat-multi-sort-header.component.ts","../../../src/lib/mat-multi-sort-header/mat-multi-sort-header.component.html","../../../src/lib/mat-multi-sort-control/mat-multi-sort-control.component.ts","../../../src/lib/mat-multi-sort-control/mat-multi-sort-control.component.html","../../../src/public-api.ts","../../../src/ngx-mat-table-multi-sort.ts"],"sourcesContent":["import { moveItemInArray } from \"@angular/cdk/drag-drop\";\nimport { Directive, signal, WritableSignal } from \"@angular/core\";\nimport {\n MatSort,\n MatSortable,\n Sort,\n SortDirection,\n} from \"@angular/material/sort\";\n\n@Directive({\n selector: \"[matMultiSort]\",\n exportAs: \"matMultiSort\",\n host: {\n class: \"mat-sort\",\n },\n})\nexport class MatMultiSortDirective extends MatSort {\n /**\n * A writable signal that holds an array of Sort objects.\n * This signal is used to manage the sorting state of the table.\n *\n * @readonly\n */\n readonly _sorts: WritableSignal<Sort[]> = signal([]);\n\n /**\n * Retrieves the sort direction for a given column ID.\n *\n * @param id - The ID of the column to get the sort direction for.\n * @returns The sort direction ('asc', 'desc', or '') for the specified column ID.\n */\n getSortDirection(id: string): SortDirection {\n const sort = this._sorts().find((e) => e.active === id);\n return sort ? sort.direction : \"\";\n }\n\n /**\n * Gets the sort index of the given column ID.\n *\n * @param id - The ID of the column to get the sort index for.\n * @returns The sort index of the column, or -1 if the column is not active.\n */\n public getSortIndex(id: string): number {\n return this._sorts().findIndex((e) => e.active === id);\n }\n\n override sort(sortable: MatSortable): void {\n this.active = sortable.id;\n this.direction = this.getSortDirection(sortable.id);\n const index = this.getSortIndex(sortable.id);\n\n // If the column is not active, add it to the list of active columns.\n if (index < 0) {\n this.direction = sortable.start ? sortable.start : this.start;\n this._sorts().push({ active: this.active, direction: this.direction });\n } else {\n // If the column is active, update the direction or remove it if the direction is empty.\n this.direction = this.getNextSortDirection(sortable);\n if (!this.direction) {\n this._sorts().splice(index, 1);\n } else {\n this._sorts()[index].direction = this.direction;\n }\n }\n\n this.sortChange.emit({ active: this.active, direction: this.direction });\n }\n\n /**\n * Removes a sort level by its identifier.\n * If the sort level is not found, the method returns without making any changes.\n *\n * @param id - The identifier of the sort level to be removed.\n * @returns void\n */\n removeSortLevel(id: string): void {\n const index = this.getSortIndex(id);\n if (index < 0) return;\n\n this._sorts().splice(index, 1);\n this.sortChange.emit();\n }\n\n /**\n * Reorders the sort level by moving an item in the sort array from a previous index to a current index.\n * If the previous index is the same as the current index, the function returns without making any changes.\n *\n * @param previousIndex - The index of the item to be moved.\n * @param currentIndex - The index to which the item should be moved.\n */\n reorderSortLevel(previousIndex: number, currentIndex: number): void {\n if (previousIndex === currentIndex) return;\n\n moveItemInArray(this._sorts(), previousIndex, currentIndex);\n this.sortChange.emit(this._sorts()[currentIndex]);\n }\n\n /**\n * Toggles the sort direction for the given column ID.\n *\n * @param id - The unique identifier of the column to toggle the sort direction for.\n * @returns void\n */\n toggleSortDirection(id: string): void {\n const index = this.getSortIndex(id);\n if (index < 0) return;\n\n this.active = id;\n // The value of this.direction is used in the getNextSortDirection method. That's why it is necessary for it to be set before the call to getNextSortDirection.\n this.direction = this.getSortDirection(id);\n this.direction = this.getNextSortDirection({\n id: id,\n disableClear: true,\n } as MatSortable);\n this._sorts()[index].direction = this.direction;\n this.sortChange.emit({ active: this.active, direction: this.direction });\n }\n}\n","import { MatPaginator } from \"@angular/material/paginator\";\nimport { Sort } from \"@angular/material/sort\";\nimport { MatTableDataSource } from \"@angular/material/table\";\nimport { MatMultiSortDirective } from \"./mat-multi-sort.directive\";\n\n/**\n * Sorts two items based on multiple sorting criteria.\n *\n * @description To do this, we iterate over each sort level and compare the values of the active column. If the values are equal, we move to the next sort level. If all sort levels are equal, we return 0.\n *\n * @template T - The type of the items being sorted.\n * @param {T} a - The first item to compare.\n * @param {T} b - The second item to compare.\n * @param {Sort[]} sorts - An array of sorting criteria, where each criterion specifies the property to sort by and the direction of sorting.\n * @returns {number} - A negative number if `a` should come before `b`, a positive number if `a` should come after `b`, or 0 if they are considered equal.\n */\nexport function MultiCriterionSort<T>(a: T, b: T, sorts: Sort[]): number {\n for (const { active, direction } of sorts) {\n const aValue = a[active as keyof T];\n const bValue = b[active as keyof T];\n\n const comparison = compareValues(aValue, bValue);\n\n if (comparison !== 0) {\n return direction === \"desc\" ? -comparison : comparison;\n }\n }\n\n return 0; // If all comparisons are equal, preserve original order\n}\n\nfunction compareValues<T>(aValue: T, bValue: T): number {\n if (aValue == null && bValue != null) return 1;\n if (aValue != null && bValue == null) return -1;\n if (aValue == null && bValue == null) return 0;\n\n if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n return aValue.localeCompare(bValue);\n }\n\n if (aValue > bValue) return 1;\n if (aValue < bValue) return -1;\n return 0;\n}\n\n/**\n * A data source class that extends `MatTableDataSource` to support multi-column sorting.\n *\n * @template T The type of data that the table displays.\n * @template P The type of paginator used, defaults to `MatPaginator`.\n *\n * @extends MatTableDataSource<T, P>\n */\nexport class MatMultiSortTableDataSource<\n T,\n P extends MatPaginator = MatPaginator,\n> extends MatTableDataSource<T, P> {\n override get sort(): MatMultiSortDirective | null {\n return super.sort as MatMultiSortDirective;\n }\n override set sort(sort: MatMultiSortDirective | null) {\n super.sort = sort;\n }\n\n constructor(initialData?: T[]) {\n super(initialData);\n // Set the default sort function\n this.sortData = (data): T[] => this.sortDataFunction(data);\n }\n\n private sortDataFunction(data: T[]): T[] {\n // Return the data if there is no sort\n if (!this.sort?._sorts().length) return data;\n\n // Sort the data:\n return data.sort((a, b) => MultiCriterionSort(a, b, this.sort!._sorts()));\n }\n}\n","import { NgIf } from \"@angular/common\";\nimport { Component, inject, OnInit, ViewEncapsulation } from \"@angular/core\";\nimport { MatSort, MatSortHeader, SortDirection } from \"@angular/material/sort\";\nimport { MatMultiSortDirective } from \"../mat-multi-sort.directive\";\n\n@Component({\n selector: \"[mat-multi-sort-header]\", // eslint-disable-line @angular-eslint/component-selector\n exportAs: \"matMultiSortHeader\",\n imports: [NgIf],\n providers: [{ provide: MatSort, useExisting: MatMultiSortDirective }],\n templateUrl: \"./mat-multi-sort-header.component.html\",\n styleUrl: \"./mat-multi-sort-header.component.scss\",\n encapsulation: ViewEncapsulation.None,\n})\nexport class MatMultiSortHeaderComponent\n extends MatSortHeader\n implements OnInit\n{\n override readonly _sort: MatMultiSortDirective = inject(\n MatMultiSortDirective,\n {\n optional: true,\n }\n )!;\n\n /**\n * Retrieves the sort direction for the current column.\n *\n * @returns {SortDirection} The sort direction for the column identified by this.id.\n */\n get sortDirection(): SortDirection {\n return this._sort.getSortDirection(this.id);\n }\n\n /**\n * Gets the sort index for the current column.\n *\n * @returns {number} The index of the sort order for this column.\n */\n get sortIndex(): number {\n return this._sort.getSortIndex(this.id);\n }\n\n override _isSorted(): boolean {\n return this.sortIndex > -1;\n }\n\n override _toggleOnInteraction(): void {\n if (this._isDisabled()) return;\n\n const wasSorted = this._isSorted();\n const prevDirection = this.sortDirection;\n this._sort.sort(this);\n this._recentlyCleared.set(\n wasSorted && !this._isSorted() ? prevDirection : null\n );\n }\n}\n","<!--\n We set the `tabindex` on an element inside the table header, rather than the header itself,\n because of a bug in NVDA where having a `tabindex` on a `th` breaks keyboard navigation in the\n table (see https://github.com/nvaccess/nvda/issues/7718). This allows for the header to both\n be focusable, and have screen readers read out its `aria-sort` state. We prefer this approach\n over having a button with an `aria-label` inside the header, because the button's `aria-label`\n will be read out as the user is navigating the table's cell (see #13012).\n\n The approach is based off of: https://dequeuniversity.com/library/aria/tables/sf-sortable-grid\n-->\n<div\n class=\"mat-sort-header-container mat-focus-indicator\"\n [class.mat-sort-header-sorted]=\"_isSorted()\"\n [class.mat-sort-header-position-before]=\"arrowPosition === 'before'\"\n [class.mat-sort-header-descending]=\"sortDirection === 'desc'\"\n [class.mat-sort-header-ascending]=\"sortDirection === 'asc'\"\n [class.mat-sort-header-recently-cleared-ascending]=\"\n _recentlyCleared() === 'asc'\n \"\n [class.mat-sort-header-recently-cleared-descending]=\"\n _recentlyCleared() === 'desc'\n \"\n [class.mat-sort-header-animations-disabled]=\"\n _animationModule === 'NoopAnimations'\n \"\n [attr.tabindex]=\"_isDisabled() ? null : 0\"\n [attr.role]=\"_isDisabled() ? null : 'button'\">\n <!--\n TODO(crisbeto): this div isn't strictly necessary, but we have to keep it due to a large\n number of screenshot diff failures. It should be removed eventually. Note that the difference\n isn't visible with a shorter header, but once it breaks up into multiple lines, this element\n causes it to be center-aligned, whereas removing it will keep the text to the left.\n -->\n <div class=\"mat-sort-header-content\">\n <ng-content></ng-content>\n </div>\n\n <!-- Disable animations while a current animation is running -->\n @if (_renderArrow()) {\n <div class=\"mat-sort-header-arrow\">\n <svg viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path\n d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\" />\n </svg>\n </div>\n }\n <div *ngIf=\"_isSorted()\" class=\"mat-sort-header-counter\">\n {{ sortIndex + 1 }}\n </div>\n</div>\n","import {\n CdkDrag,\n CdkDragDrop,\n CdkDropList,\n DropListOrientation,\n} from \"@angular/cdk/drag-drop\";\nimport { ANIMATION_MODULE_TYPE, Component, inject, Input } from \"@angular/core\";\nimport { MatChipsModule } from \"@angular/material/chips\";\nimport { MatIconModule } from \"@angular/material/icon\";\nimport { Sort } from \"@angular/material/sort\";\nimport { MatMultiSortDirective } from \"../../public-api\";\n\n@Component({\n selector: \"mat-multi-sort-control\",\n imports: [CdkDropList, CdkDrag, MatChipsModule, MatIconModule],\n templateUrl: \"./mat-multi-sort-control.component.html\",\n styleUrl: \"./mat-multi-sort-control.component.scss\",\n})\nexport class MatMultiSortControlComponent {\n /**\n * Injects the ANIMATION_MODULE_TYPE token, which indicates the type of animation module being used.\n * This is an optional dependency and may be undefined if the animation module is not provided.\n *\n * @readonly\n * @type {ANIMATION_MODULE_TYPE | undefined}\n */\n readonly _animationModule = inject(ANIMATION_MODULE_TYPE, { optional: true });\n\n /**\n * Specifies the orientation of the drop list.\n * Can be either \"horizontal\" or \"vertical\".\n *\n * @type {DropListOrientation}\n * @default \"horizontal\"\n */\n @Input() orientation: DropListOrientation = \"horizontal\";\n\n /**\n * An optional input property that accepts an instance of `MatMultiSortDirective`.\n * This directive is used to control the sorting behavior of the table.\n */\n @Input() sort?: MatMultiSortDirective;\n\n /**\n * Retrieves the array of Sort objects from the current sort instance.\n * If the sort instance is not defined, it returns an empty array.\n *\n * @returns {Sort[]} An array of Sort objects or an empty array if no sorts are defined.\n */\n get sorts(): Sort[] {\n return this.sort?._sorts() || [];\n }\n\n /**\n * Handles the click event on a sort chip.\n * Toggles the sort direction for the given sort ID.\n *\n * @param id - The identifier of the sort field to toggle.\n * @returns void\n */\n onChipClick(id: string): void {\n this.sort?.toggleSortDirection(id);\n }\n\n /**\n * Handles the event when a sort chip is removed.\n *\n * @param id - The identifier of the sort level to be removed.\n * @returns void\n */\n onChipRemoved(id: string): void {\n this.sort?.removeSortLevel(id);\n }\n\n /**\n * Handles the drop event for drag-and-drop sorting.\n * Reorders the sort levels based on the previous and current indices.\n *\n * @param event - The drag-and-drop event containing the previous and current indices of the sort order.\n */\n onDrop(event: CdkDragDrop<Sort[]>): void {\n this.sort?.reorderSortLevel(event.previousIndex, event.currentIndex);\n }\n}\n","<mat-chip-listbox\n cdkDropList\n [cdkDropListOrientation]=\"orientation\"\n (cdkDropListDropped)=\"onDrop($event)\">\n @for (column of sorts; track $index) {\n <mat-chip\n class=\"mat-sort-header\"\n cdkDrag\n (click)=\"onChipClick(column.active)\"\n (removed)=\"onChipRemoved(column.active)\">\n <div\n matChipAvatar\n class=\"mat-sort-header-container mat-sort-header-sorted mat-focus-indicator\"\n [class.mat-sort-header-descending]=\"column.direction === 'desc'\"\n [class.mat-sort-header-ascending]=\"column.direction === 'asc'\"\n [class.mat-sort-header-animations-disabled]=\"\n _animationModule === 'NoopAnimations'\n \">\n <div class=\"mat-sort-header-arrow\">\n <svg viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path\n d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\" />\n </svg>\n </div>\n </div>\n {{ column.active }}\n <button matChipRemove>\n <mat-icon>clear</mat-icon>\n </button>\n </mat-chip>\n }\n</mat-chip-listbox>\n","/*\n * Public API Surface of lib\n */\n\nexport * from \"./lib/mat-multi-sort.directive\";\nexport * from \"./lib/mat-multi-sort-table-data-source\";\nexport * from \"./lib/mat-multi-sort-header/mat-multi-sort-header.component\";\nexport * from \"./lib/mat-multi-sort-control/mat-multi-sort-control.component\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { CdkDragDrop, DropListOrientation } from "@angular/cdk/drag-drop";
2
+ import { Sort } from "@angular/material/sort";
3
+ import { MatMultiSortDirective } from "../../public-api";
4
+ import * as i0 from "@angular/core";
5
+ export declare class MatMultiSortControlComponent {
6
+ /**
7
+ * Injects the ANIMATION_MODULE_TYPE token, which indicates the type of animation module being used.
8
+ * This is an optional dependency and may be undefined if the animation module is not provided.
9
+ *
10
+ * @readonly
11
+ * @type {ANIMATION_MODULE_TYPE | undefined}
12
+ */
13
+ readonly _animationModule: "NoopAnimations" | "BrowserAnimations" | null;
14
+ /**
15
+ * Specifies the orientation of the drop list.
16
+ * Can be either "horizontal" or "vertical".
17
+ *
18
+ * @type {DropListOrientation}
19
+ * @default "horizontal"
20
+ */
21
+ orientation: DropListOrientation;
22
+ /**
23
+ * An optional input property that accepts an instance of `MatMultiSortDirective`.
24
+ * This directive is used to control the sorting behavior of the table.
25
+ */
26
+ sort?: MatMultiSortDirective;
27
+ /**
28
+ * Retrieves the array of Sort objects from the current sort instance.
29
+ * If the sort instance is not defined, it returns an empty array.
30
+ *
31
+ * @returns {Sort[]} An array of Sort objects or an empty array if no sorts are defined.
32
+ */
33
+ get sorts(): Sort[];
34
+ /**
35
+ * Handles the click event on a sort chip.
36
+ * Toggles the sort direction for the given sort ID.
37
+ *
38
+ * @param id - The identifier of the sort field to toggle.
39
+ * @returns void
40
+ */
41
+ onChipClick(id: string): void;
42
+ /**
43
+ * Handles the event when a sort chip is removed.
44
+ *
45
+ * @param id - The identifier of the sort level to be removed.
46
+ * @returns void
47
+ */
48
+ onChipRemoved(id: string): void;
49
+ /**
50
+ * Handles the drop event for drag-and-drop sorting.
51
+ * Reorders the sort levels based on the previous and current indices.
52
+ *
53
+ * @param event - The drag-and-drop event containing the previous and current indices of the sort order.
54
+ */
55
+ onDrop(event: CdkDragDrop<Sort[]>): void;
56
+ static ɵfac: i0.ɵɵFactoryDeclaration<MatMultiSortControlComponent, never>;
57
+ static ɵcmp: i0.ɵɵComponentDeclaration<MatMultiSortControlComponent, "mat-multi-sort-control", never, { "orientation": { "alias": "orientation"; "required": false; }; "sort": { "alias": "sort"; "required": false; }; }, {}, never, never, true, never>;
58
+ }
@@ -1,7 +1,14 @@
1
+ import { WritableSignal } from "@angular/core";
1
2
  import { MatSort, MatSortable, Sort, SortDirection } from "@angular/material/sort";
2
3
  import * as i0 from "@angular/core";
3
4
  export declare class MatMultiSortDirective extends MatSort {
4
- readonly _sorts: Sort[];
5
+ /**
6
+ * A writable signal that holds an array of Sort objects.
7
+ * This signal is used to manage the sorting state of the table.
8
+ *
9
+ * @readonly
10
+ */
11
+ readonly _sorts: WritableSignal<Sort[]>;
5
12
  /**
6
13
  * Retrieves the sort direction for a given column ID.
7
14
  *
@@ -17,6 +24,29 @@ export declare class MatMultiSortDirective extends MatSort {
17
24
  */
18
25
  getSortIndex(id: string): number;
19
26
  sort(sortable: MatSortable): void;
27
+ /**
28
+ * Removes a sort level by its identifier.
29
+ * If the sort level is not found, the method returns without making any changes.
30
+ *
31
+ * @param id - The identifier of the sort level to be removed.
32
+ * @returns void
33
+ */
34
+ removeSortLevel(id: string): void;
35
+ /**
36
+ * Reorders the sort level by moving an item in the sort array from a previous index to a current index.
37
+ * If the previous index is the same as the current index, the function returns without making any changes.
38
+ *
39
+ * @param previousIndex - The index of the item to be moved.
40
+ * @param currentIndex - The index to which the item should be moved.
41
+ */
42
+ reorderSortLevel(previousIndex: number, currentIndex: number): void;
43
+ /**
44
+ * Toggles the sort direction for the given column ID.
45
+ *
46
+ * @param id - The unique identifier of the column to toggle the sort direction for.
47
+ * @returns void
48
+ */
49
+ toggleSortDirection(id: string): void;
20
50
  static ɵfac: i0.ɵɵFactoryDeclaration<MatMultiSortDirective, never>;
21
51
  static ɵdir: i0.ɵɵDirectiveDeclaration<MatMultiSortDirective, "[matMultiSort]", ["matMultiSort"], {}, {}, never, never, true, never>;
22
52
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ngx-mat-table-multi-sort",
3
- "version": "19.0.0",
4
- "preview": false,
3
+ "version": "19.1.0-pre.2",
4
+ "preview": true,
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "email": "info@philipgerke.com",
package/public-api.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./lib/mat-multi-sort.directive";
2
2
  export * from "./lib/mat-multi-sort-table-data-source";
3
3
  export * from "./lib/mat-multi-sort-header/mat-multi-sort-header.component";
4
+ export * from "./lib/mat-multi-sort-control/mat-multi-sort-control.component";