@akcelik/strct 5.8.0 → 5.9.0

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.
@@ -14493,7 +14493,7 @@ class StrctDatagrid {
14493
14493
  const sortRows = (rs) => {
14494
14494
  const c = [...rs];
14495
14495
  if (key)
14496
- c.sort((a, b) => sign * this.compare(a[key], b[key]));
14496
+ c.sort((a, b) => this.compareRows(a, b, key, sign));
14497
14497
  return c;
14498
14498
  };
14499
14499
  const filtering = this.activeFilters().length > 0 || this.quickTerm() !== '';
@@ -14527,7 +14527,7 @@ class StrctDatagrid {
14527
14527
  if (!key)
14528
14528
  return data;
14529
14529
  const sign = dir === 'asc' ? 1 : -1;
14530
- return data.sort((a, b) => sign * this.compare(a[key], b[key]));
14530
+ return data.sort((a, b) => this.compareRows(a, b, key, sign));
14531
14531
  }, /* @ts-ignore */
14532
14532
  ...(ngDevMode ? [{ debugName: "sorted" }] : /* istanbul ignore next */ []));
14533
14533
  paged = computed(() => {
@@ -14942,6 +14942,12 @@ class StrctDatagrid {
14942
14942
  this.lazyLoad.emit(state);
14943
14943
  });
14944
14944
  });
14945
+ // The columns' own `hidden` flags, read once they exist — a required input
14946
+ // is not available in the constructor.
14947
+ effect(() => {
14948
+ const cols = this.columns();
14949
+ untracked(() => this.applyDeclaredHidden(cols));
14950
+ });
14945
14951
  // Restore persisted column preferences once, before the first render.
14946
14952
  const persisted = this.readPersistedState();
14947
14953
  if (persisted)
@@ -14961,7 +14967,10 @@ class StrctDatagrid {
14961
14967
  const widths = Object.fromEntries(this.columnWidths());
14962
14968
  const hidden = [...this.hiddenColumns()];
14963
14969
  const order = this.columnOrder() ?? undefined;
14964
- const st = { widths, hidden, order };
14970
+ // A list an operator sorted by Host CPU opened sorted by name again, and
14971
+ // a lazy one asked the server for the wrong order first.
14972
+ const { key: sortKey, dir: sortDir } = this.sort();
14973
+ const st = { widths, hidden, order, sortKey, sortDir };
14965
14974
  const key = JSON.stringify(st);
14966
14975
  untracked(() => {
14967
14976
  if (key === this.lastStateKey)
@@ -14994,8 +15003,31 @@ class StrctDatagrid {
14994
15003
  }
14995
15004
  applyColumnState(st) {
14996
15005
  this.columnWidths.set(new Map(Object.entries(st.widths ?? {}).map(([k, v]) => [k, Number(v)])));
15006
+ if (st.hidden)
15007
+ this.hiddenDecidedByState = true;
14997
15008
  this.hiddenColumns.set(new Set(st.hidden ?? []));
14998
15009
  this.columnOrder.set(st.order?.length ? [...st.order] : null);
15010
+ if (st.sortKey !== undefined)
15011
+ this.sort.set({ key: st.sortKey, dir: st.sortDir ?? 'asc' });
15012
+ }
15013
+ /** Whether a persisted or bound state has already decided what is hidden. */
15014
+ hiddenDecidedByState = false;
15015
+ /** Whether the columns' own `hidden` flags have been read (once). */
15016
+ declaredHiddenApplied = false;
15017
+ /**
15018
+ * Columns the consumer declared hidden — the default for a column no state
15019
+ * mentions. A list that shows five of twenty columns says so on the columns,
15020
+ * rather than seeding `columnState` and reaching into the library's storage
15021
+ * key to keep from overriding what the operator chose.
15022
+ */
15023
+ applyDeclaredHidden(cols) {
15024
+ if (this.declaredHiddenApplied || this.hiddenDecidedByState)
15025
+ return;
15026
+ this.declaredHiddenApplied = true;
15027
+ const declared = cols.filter((c) => c.hidden).map((c) => c.key);
15028
+ if (!declared.length)
15029
+ return;
15030
+ this.hiddenColumns.update((set) => new Set([...set, ...declared]));
14999
15031
  }
15000
15032
  /**
15001
15033
  * The grid as CSV: header labels + every non-hidden column, all rows in the
@@ -15003,17 +15035,32 @@ class StrctDatagrid {
15003
15035
  */
15004
15036
  toCSV() {
15005
15037
  const hidden = this.hiddenColumns();
15006
- const cols = this.columns().filter((c) => !hidden.has(c.key));
15038
+ // The user's order, as the xlsx export already used: the same grid wrote
15039
+ // its columns two different ways.
15040
+ const cols = this.orderedColumns().filter((c) => !hidden.has(c.key));
15007
15041
  const esc = (v) => {
15008
- const s = v == null ? '' : String(v);
15042
+ let s = v == null ? '' : String(v);
15043
+ // A cell that opens with one of these is a formula to a spreadsheet, so
15044
+ // a VM named "=HYPERLINK(…)" ran when the export was opened. A leading
15045
+ // apostrophe is the spreadsheet's own "this is text".
15046
+ if (/^[=+\-@\t\r]/.test(s))
15047
+ s = `'${s}`;
15009
15048
  return /[",\n;]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
15010
15049
  };
15011
15050
  const data = this.lazy() ? this.rows() : this.sorted();
15012
15051
  return [
15013
15052
  cols.map((c) => esc(c.label)).join(','),
15014
- ...data.map((r) => cols.map((c) => esc(r[c.key])).join(',')),
15053
+ ...data.map((r) => cols.map((c) => esc(this.exportValueOf(r, c))).join(',')),
15015
15054
  ].join('\n');
15016
15055
  }
15056
+ /**
15057
+ * What an export writes for a cell: what the column says, else the stored
15058
+ * value. A templated cell shows "2 h 15 m" and stored 8100; without this the
15059
+ * export carries the seconds, an enum code or a bare `true`.
15060
+ */
15061
+ exportValueOf(row, col) {
15062
+ return col.exportValue ? col.exportValue(row) : row[col.key];
15063
+ }
15017
15064
  /**
15018
15065
  * The grid as a real .xlsx workbook (dependency-free SpreadsheetML):
15019
15066
  * header labels + every non-hidden column in the current order, all rows in
@@ -15023,7 +15070,7 @@ class StrctDatagrid {
15023
15070
  const hidden = this.hiddenColumns();
15024
15071
  const cols = this.orderedColumns().filter((c) => !hidden.has(c.key));
15025
15072
  const data = this.lazy() ? this.rows() : this.sorted();
15026
- return buildXlsx(cols.map((c) => c.label), data.map((r) => cols.map((c) => r[c.key])));
15073
+ return buildXlsx(cols.map((c) => c.label), data.map((r) => cols.map((c) => this.exportValueOf(r, c))));
15027
15074
  }
15028
15075
  /** Download the grid as an .xlsx file. */
15029
15076
  downloadXLSX(filename = 'datagrid.xlsx') {
@@ -15273,9 +15320,39 @@ class StrctDatagrid {
15273
15320
  .filter((r) => !!r);
15274
15321
  this.selectionChange.emit([...fresh, ...offData]);
15275
15322
  }
15323
+ /**
15324
+ * One row's sort key for a column: what the column says to sort by, else the
15325
+ * stored value. A cell that shows "1.5 TB" sorts as text without this, which
15326
+ * puts it before "900 GB"; a date written by toLocaleString sorts across
15327
+ * days and AM/PM by its characters.
15328
+ */
15329
+ sortKeyOf(row, col, key) {
15330
+ return col?.sortValue ? col.sortValue(row) : row[key];
15331
+ }
15332
+ /** The column a key belongs to — the comparator and the sort key need it. */
15333
+ columnOf(key) {
15334
+ return this.columns().find((c) => c.key === key);
15335
+ }
15336
+ /** Compare two rows by a column, honouring its comparator and nulls-last. */
15337
+ compareRows(a, b, key, sign) {
15338
+ const col = this.columnOf(key);
15339
+ if (col?.comparator)
15340
+ return sign * col.comparator(a, b);
15341
+ const av = this.sortKeyOf(a, col, key);
15342
+ const bv = this.sortKeyOf(b, col, key);
15343
+ // An unread value is neither the smallest nor the largest: it is not an
15344
+ // answer at all, so it goes last whichever way the column is sorted.
15345
+ const aEmpty = av == null || av === '';
15346
+ const bEmpty = bv == null || bv === '';
15347
+ if (aEmpty || bEmpty)
15348
+ return aEmpty && bEmpty ? 0 : aEmpty ? 1 : -1;
15349
+ return sign * this.compare(av, bv);
15350
+ }
15276
15351
  compare(a, b) {
15277
15352
  if (typeof a === 'number' && typeof b === 'number')
15278
15353
  return a - b;
15354
+ if (a instanceof Date && b instanceof Date)
15355
+ return a.getTime() - b.getTime();
15279
15356
  return String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true });
15280
15357
  }
15281
15358
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });