@lilydesignsystem/angular-data-grid 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,14 @@ import { DataGrid, type DataGridColumn } from "@lilydesignsystem/angular-data-gr
20
20
  selector: "app-users",
21
21
  standalone: true,
22
22
  imports: [DataGrid],
23
- template: `<lily-data-grid label="Users" [columns]="columns" [rows]="rows" selectionMode="multiple" [(selected)]="selected" [labels]="labels" />`,
23
+ template: `<lily-data-grid
24
+ label="Users"
25
+ [columns]="columns"
26
+ [rows]="rows"
27
+ selectionMode="multiple"
28
+ [(selected)]="selected"
29
+ [labels]="labels"
30
+ />`,
24
31
  })
25
32
  export class UsersComponent {
26
33
  columns: DataGridColumn[] = [
@@ -33,20 +40,24 @@ export class UsersComponent {
33
40
  { name: "Bob", email: "bob@example.com", role: "Editor" },
34
41
  ];
35
42
  selected: string[] = [];
36
- labels = { search: "Search users", selectAll: "Select all rows", selectRow: (name: string) => `Select ${name}` };
43
+ labels = {
44
+ search: "Search users",
45
+ selectAll: "Select all rows",
46
+ selectRow: (name: string) => `Select ${name}`,
47
+ };
37
48
  }
38
49
  ```
39
50
 
40
51
  ## What is Angular-specific
41
52
 
42
- | Svelte | Angular |
43
- | --- | --- |
44
- | `selected`, `filter`, `sort`, `columnOrder`, `page` (bindable) | `model()`s: `[(selected)]`, `[(filter)]`, `[(sort)]`, `[(columnOrder)]`, `[(page)]` |
45
- | `onCellEdit`, `onFilesSelected`, `onFileRemove`, `onRowActivate`, `onExport` | the outputs `cellEdit`, `filesSelected`, `fileRemove`, `rowActivate`, `exportFile`, and the `exportHandler` input (return `false` to stop the save). An output cannot be tested for a listener, so Enter / a click activates a row only when `[activateRows]="true"` |
46
- | `empty`, `footer`, column `cell`, `headerCell`, `avatar`, `personEditor` snippets | `TemplateRef`s: the `empty` and `footer` inputs, and the column's `cell`, `headerCell`, `avatar`, `personEditor` (the context is `$implicit`) |
47
- | rest props on the root | the root `<div class="data-grid">` is inside the `<lily-data-grid>` host; put extra attributes on the host, and `className` on the root |
48
- | `rowAttrs`, column `cellAttrs` | the same inputs, applied through the `lilyDataGridAttrs` directive |
49
- | `class` | `className` |
53
+ | Svelte | Angular |
54
+ | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55
+ | `selected`, `filter`, `sort`, `columnOrder`, `page` (bindable) | `model()`s: `[(selected)]`, `[(filter)]`, `[(sort)]`, `[(columnOrder)]`, `[(page)]` |
56
+ | `onCellEdit`, `onFilesSelected`, `onFileRemove`, `onRowActivate`, `onExport` | the outputs `cellEdit`, `filesSelected`, `fileRemove`, `rowActivate`, `exportFile`, and the `exportHandler` input (return `false` to stop the save). An output cannot be tested for a listener, so Enter / a click activates a row only when `[activateRows]="true"` |
57
+ | `empty`, `footer`, column `cell`, `headerCell`, `avatar`, `personEditor` snippets | `TemplateRef`s: the `empty` and `footer` inputs, and the column's `cell`, `headerCell`, `avatar`, `personEditor` (the context is `$implicit`) |
58
+ | rest props on the root | the root `<div class="data-grid">` is inside the `<lily-data-grid>` host; put extra attributes on the host, and `className` on the root |
59
+ | `rowAttrs`, column `cellAttrs` | the same inputs, applied through the `lilyDataGridAttrs` directive |
60
+ | `class` | `className` |
50
61
 
51
62
  Everything else — columns, labels, `rowId`, `selectionMode`, `pageSize`, `storageKey`, `mode`,
52
63
  the keyboard model, the cell types, editing, export and virtualization — is as in the Svelte
@@ -86,7 +97,7 @@ Requires `@lilydesignsystem/angular-headless`.
86
97
  - **Field-specific search.** `filterField` (a `model()`, `onFilterFieldChange`) limits the text filter to one column; `labels.searchField` (the select's name) with `labels.searchAllFields` (its first option) shows the select, listing the filterable columns. Without a field the whole row is searched.
87
98
  - **`movableColumns`** makes every column movable (Alt+Arrow on the header, or drag), unless a column's `movable` is `false`.
88
99
  - **Right-to-left.** The horizontal arrows are visual, so in a right-to-left layout (the nearest `dir`, else the computed direction) ArrowLeft goes to the next cell and ArrowRight to the previous, and Alt+Arrow moves a column the way the arrow points. Vertical keys, Home, End and the page keys do not change. The pure `isRtl` / `logicalKey` are exported.
89
- - **Labels.** `DataGridLabels` is the one bundle of every string. What each feature needs is listed in `CONTROL_LABELS` (labels that *name a control*) and `ANNOUNCEMENT_LABELS` (live-region messages), and `requiredLabels(features)` / `missingLabels(features, labels)` compute it, so an app can assert in a test that its bundle for a locale is complete. In development the grid logs once, naming the labels its features call for that `labels` leaves out (`warnMissingLabels={false}` silences it; it never logs in production). Lily has no English fallback: a missing label is a control with no name or an announcement never made. `sortAnnouncement` receives the ARIA token (`ascending`, `descending`, `none`), which the bundle turns into its own words.
100
+ - **Labels.** `DataGridLabels` is the one bundle of every string. What each feature needs is listed in `CONTROL_LABELS` (labels that _name a control_) and `ANNOUNCEMENT_LABELS` (live-region messages), and `requiredLabels(features)` / `missingLabels(features, labels)` compute it, so an app can assert in a test that its bundle for a locale is complete. In development the grid logs once, naming the labels its features call for that `labels` leaves out (`warnMissingLabels={false}` silences it; it never logs in production). Lily has no English fallback: a missing label is a control with no name or an announcement never made. `sortAnnouncement` receives the ARIA token (`ascending`, `descending`, `none`), which the bundle turns into its own words.
90
101
  - **Row attributes.** `rowAttrs(row)` returns attributes spread onto each body row — the way to put test ids (`data-testid`), data attributes and other hooks on rows (`rowAttrs={(row) => ({ "data-testid": `row-${row.id}` })}`); `rowClass` does the same for classes, and a column's `cellAttrs` / `cellClass` for cells.
91
102
 
92
103
  ## Pager landmark (0.10.0)
@@ -884,7 +884,7 @@ var DataGridAttrs = class DataGridAttrs {
884
884
  static {
885
885
  this.ɵfac = i0.ɵɵngDeclareFactory({
886
886
  minVersion: "12.0.0",
887
- version: "22.2.3",
887
+ version: "22.2.4",
888
888
  ngImport: i0,
889
889
  type: DataGridAttrs,
890
890
  deps: [],
@@ -894,7 +894,7 @@ var DataGridAttrs = class DataGridAttrs {
894
894
  static {
895
895
  this.ɵdir = i0.ɵɵngDeclareDirective({
896
896
  minVersion: "17.1.0",
897
- version: "22.2.3",
897
+ version: "22.2.4",
898
898
  type: DataGridAttrs,
899
899
  isStandalone: true,
900
900
  selector: "[lilyDataGridAttrs]",
@@ -911,7 +911,7 @@ var DataGridAttrs = class DataGridAttrs {
911
911
  };
912
912
  i0.ɵɵngDeclareClassMetadata({
913
913
  minVersion: "12.0.0",
914
- version: "22.2.3",
914
+ version: "22.2.4",
915
915
  ngImport: i0,
916
916
  type: DataGridAttrs,
917
917
  decorators: [{
@@ -954,6 +954,11 @@ var DataGrid = class DataGrid {
954
954
  isMovable(column) {
955
955
  return column.movable ?? this.movableColumns();
956
956
  }
957
+ footerAggregate(columnId, kind) {
958
+ const column = this.resolvedColumns().find((c) => c.id === columnId);
959
+ if (!column) return void 0;
960
+ return aggregateValues(kind, this.sortedEntries().map((e) => defaultAccessor(column, e.row)));
961
+ }
957
962
  constructor() {
958
963
  this.label = input.required(...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
959
964
  this.caption = input(void 0, ...ngDevMode ? [{ debugName: "caption" }] : /* istanbul ignore next */ []);
@@ -1155,7 +1160,9 @@ var DataGrid = class DataGrid {
1155
1160
  this.someSelected = computed(() => !this.allSelected() && this.sortedEntries().some((e) => this.selectedSet().has(e.id)), ...ngDevMode ? [{ debugName: "someSelected" }] : /* istanbul ignore next */ []);
1156
1161
  this.footerContext = computed(() => ({
1157
1162
  columns: this.visibleColumns(),
1158
- rows: this.pageEntries().map((e) => e.row)
1163
+ rows: this.pageEntries().map((e) => e.row),
1164
+ allRows: this.sortedEntries().map((e) => e.row),
1165
+ aggregate: (columnId, kind) => this.footerAggregate(columnId, kind)
1159
1166
  }), ...ngDevMode ? [{ debugName: "footerContext" }] : /* istanbul ignore next */ []);
1160
1167
  this.exportColumns = computed(() => this.visibleColumns().filter((c) => c.exportable !== false), ...ngDevMode ? [{ debugName: "exportColumns" }] : /* istanbul ignore next */ []);
1161
1168
  this.exportEntries = computed(() => this.exportScope() === "selected" ? this.sortedEntries().filter((e) => this.selectedSet().has(e.id)) : this.sortedEntries(), ...ngDevMode ? [{ debugName: "exportEntries" }] : /* istanbul ignore next */ []);
@@ -1231,7 +1238,8 @@ var DataGrid = class DataGrid {
1231
1238
  const snapshot = {
1232
1239
  columnWidths: this.columnWidths(),
1233
1240
  hiddenColumnIds: [...this.hiddenColumnIds()],
1234
- sort: this.sort()
1241
+ sort: this.sort(),
1242
+ columnOrder: this.columnOrder()
1235
1243
  };
1236
1244
  if (!key || typeof localStorage === "undefined") return;
1237
1245
  try {
@@ -1343,6 +1351,12 @@ var DataGrid = class DataGrid {
1343
1351
  const width = this.widthFor(column);
1344
1352
  if (width) parts.push(`width:${width}px`);
1345
1353
  if (column.align) parts.push(`text-align:${column.align}`);
1354
+ if (column.pinned) {
1355
+ const visible = this.visibleColumns();
1356
+ const i = visible.findIndex((c) => c.id === column.id);
1357
+ const widths = (column.pinned === "start" ? visible.slice(0, i) : visible.slice(i + 1)).filter((c) => c.pinned === column.pinned).map((c) => this.widthFor(c));
1358
+ if (widths.every((w) => w !== void 0)) parts.push(`--data-grid-pinned-offset:${widths.reduce((a, w) => a + (w ?? 0), 0)}px`);
1359
+ }
1346
1360
  return parts.length > 0 ? parts.join(";") : null;
1347
1361
  }
1348
1362
  setWidth(column, width) {
@@ -1886,6 +1900,7 @@ var DataGrid = class DataGrid {
1886
1900
  if (saved.columnWidths) this.columnWidths.set(saved.columnWidths);
1887
1901
  if (saved.hiddenColumnIds) this.hiddenColumnIds.set(new Set(saved.hiddenColumnIds));
1888
1902
  if (saved.sort) this.sort.set(saved.sort);
1903
+ if (Array.isArray(saved.columnOrder)) this.columnOrder.set(saved.columnOrder);
1889
1904
  }
1890
1905
  } catch {}
1891
1906
  }
@@ -1930,7 +1945,7 @@ var DataGrid = class DataGrid {
1930
1945
  static {
1931
1946
  this.ɵfac = i0.ɵɵngDeclareFactory({
1932
1947
  minVersion: "12.0.0",
1933
- version: "22.2.3",
1948
+ version: "22.2.4",
1934
1949
  ngImport: i0,
1935
1950
  type: DataGrid,
1936
1951
  deps: [],
@@ -1940,7 +1955,7 @@ var DataGrid = class DataGrid {
1940
1955
  static {
1941
1956
  this.ɵcmp = i0.ɵɵngDeclareComponent({
1942
1957
  minVersion: "17.0.0",
1943
- version: "22.2.3",
1958
+ version: "22.2.4",
1944
1959
  type: DataGrid,
1945
1960
  isStandalone: true,
1946
1961
  selector: "lily-data-grid",
@@ -2768,7 +2783,7 @@ var DataGrid = class DataGrid {
2768
2783
  };
2769
2784
  i0.ɵɵngDeclareClassMetadata({
2770
2785
  minVersion: "12.0.0",
2771
- version: "22.2.3",
2786
+ version: "22.2.4",
2772
2787
  ngImport: i0,
2773
2788
  type: DataGrid,
2774
2789
  decorators: [{