@akcelik/strct 3.0.0 → 3.1.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.
@@ -10830,7 +10830,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
10830
10830
  args: [{ selector: '[strctDatagridActionBar]' }]
10831
10831
  }] });
10832
10832
  /**
10833
- * Interactive data table: sortable columns, row selection, expandable detail
10833
+ * Interactive data table: sortable columns, row selection (Shift-click a row
10834
+ * checkbox to carry its new state across a whole block), expandable detail
10834
10835
  * rows, a batch action bar and built-in paging.
10835
10836
  * <strct-datagrid [columns]="cols" [rows]="data" selectable expandable [pageSize]="10">
10836
10837
  * <button strct-button strctDatagridActions size="sm">Migrate</button>
@@ -11602,12 +11603,18 @@ class StrctDatagrid {
11602
11603
  somePageSelected = computed(() => !this.allPageSelected() &&
11603
11604
  this.selectionRows().some((r) => this.selected().has(this.idOf(r))), /* @ts-ignore */
11604
11605
  ...(ngDevMode ? [{ debugName: "somePageSelected" }] : /* istanbul ignore next */ []));
11605
- /** Resolve a row's stable identity (defaults to the row object itself). */
11606
+ /** Resolve a row's stable identity: its `rowId` value, or the row object
11607
+ * itself when there is no `rowId` or it resolves to null/undefined. */
11606
11608
  idOf(row) {
11607
11609
  const id = this.rowId();
11608
11610
  if (id == null)
11609
11611
  return row;
11610
- return typeof id === 'function' ? id(row) : row[id];
11612
+ const resolved = typeof id === 'function' ? id(row) : row[id];
11613
+ // An unresolvable id must not collapse rows onto one another: a Set holds
11614
+ // `undefined` once, so every row missing the field would share one
11615
+ // identity — select one, select them all. `??`, not `||`: 0 and '' are
11616
+ // legitimate ids.
11617
+ return resolved ?? row;
11611
11618
  }
11612
11619
  rowKey(row) {
11613
11620
  return this.idOf(row);
@@ -11904,15 +11911,49 @@ class StrctDatagrid {
11904
11911
  }
11905
11912
  this.expandedRows.set(next);
11906
11913
  }
11914
+ /** The row a Shift-click measures its range from: the last one toggled on
11915
+ * its own. A range leaves it where it is, so successive Shift-clicks
11916
+ * re-project from the same origin instead of walking the anchor along. */
11917
+ rangeAnchor = null;
11918
+ /** Set by the row checkbox's click, consumed by the `toggleRow` that the
11919
+ * same interaction fires immediately after. */
11920
+ rangeIntent = false;
11921
+ noteRangeIntent(event) {
11922
+ this.rangeIntent = event.shiftKey;
11923
+ }
11924
+ /**
11925
+ * Toggle one row. Shift-clicking a row checkbox instead applies the clicked
11926
+ * box's new state across every row between the anchor and this one — so a
11927
+ * Shift-click selects a block, and Shift-clicking a checked box clears one.
11928
+ */
11907
11929
  toggleRow(row) {
11908
11930
  const id = this.idOf(row);
11931
+ const select = !this.selected().has(id);
11909
11932
  const next = new Set(this.selected());
11910
- if (next.has(id)) {
11911
- next.delete(id);
11933
+ const ranged = this.rangeIntent;
11934
+ this.rangeIntent = false;
11935
+ if (ranged && this.rangeAnchor !== null) {
11936
+ const rows = this.selectionRows();
11937
+ const from = rows.findIndex((r) => this.idOf(r) === this.rangeAnchor);
11938
+ const to = rows.findIndex((r) => this.idOf(r) === id);
11939
+ // A vanished anchor (paged away, filtered out) degrades to a plain toggle.
11940
+ if (from !== -1 && to !== -1) {
11941
+ for (let i = Math.min(from, to); i <= Math.max(from, to); i++) {
11942
+ const rid = this.idOf(rows[i]);
11943
+ if (select)
11944
+ next.add(rid);
11945
+ else
11946
+ next.delete(rid);
11947
+ }
11948
+ this.commitSelection(next);
11949
+ return;
11950
+ }
11912
11951
  }
11913
- else {
11952
+ if (select)
11914
11953
  next.add(id);
11915
- }
11954
+ else
11955
+ next.delete(id);
11956
+ this.rangeAnchor = id;
11916
11957
  this.commitSelection(next);
11917
11958
  }
11918
11959
  toggleAll() {
@@ -11924,9 +11965,11 @@ class StrctDatagrid {
11924
11965
  else {
11925
11966
  rows.forEach((r) => next.add(this.idOf(r)));
11926
11967
  }
11968
+ this.rangeAnchor = null;
11927
11969
  this.commitSelection(next);
11928
11970
  }
11929
11971
  clearSelection() {
11972
+ this.rangeAnchor = null;
11930
11973
  this.commitSelection(new Set());
11931
11974
  }
11932
11975
  /** Last known row object per selected id — selections made on one page stay
@@ -12238,9 +12281,12 @@ class StrctDatagrid {
12238
12281
  [class.strct-dg__cell--sticky]="stickyActive()"
12239
12282
  [style.insetInlineStart.px]="utilLeft('sel')"
12240
12283
  >
12284
+ <!-- click fires (and bubbles) before the input's change,
12285
+ so the modifier is recorded by the time toggleRow runs. -->
12241
12286
  <strct-checkbox
12242
12287
  [ariaLabel]="selectRowLabel(row)"
12243
12288
  [checked]="isSelected(row)"
12289
+ (click)="noteRangeIntent($event)"
12244
12290
  (checkedChange)="toggleRow(row)"
12245
12291
  />
12246
12292
  </td>
@@ -12724,9 +12770,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
12724
12770
  [class.strct-dg__cell--sticky]="stickyActive()"
12725
12771
  [style.insetInlineStart.px]="utilLeft('sel')"
12726
12772
  >
12773
+ <!-- click fires (and bubbles) before the input's change,
12774
+ so the modifier is recorded by the time toggleRow runs. -->
12727
12775
  <strct-checkbox
12728
12776
  [ariaLabel]="selectRowLabel(row)"
12729
12777
  [checked]="isSelected(row)"
12778
+ (click)="noteRangeIntent($event)"
12730
12779
  (checkedChange)="toggleRow(row)"
12731
12780
  />
12732
12781
  </td>