@ni/nimble-components 18.5.7 → 18.5.8

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.
Files changed (45) hide show
  1. package/dist/all-components-bundle.js +290 -35
  2. package/dist/all-components-bundle.js.map +1 -1
  3. package/dist/all-components-bundle.min.js +883 -843
  4. package/dist/all-components-bundle.min.js.map +1 -1
  5. package/dist/esm/table/components/cell/index.d.ts +1 -1
  6. package/dist/esm/table/components/cell/index.js.map +1 -1
  7. package/dist/esm/table/components/cell/template.d.ts +1 -1
  8. package/dist/esm/table/components/header/index.d.ts +6 -0
  9. package/dist/esm/table/components/header/index.js +32 -0
  10. package/dist/esm/table/components/header/index.js.map +1 -1
  11. package/dist/esm/table/components/header/styles.js +5 -0
  12. package/dist/esm/table/components/header/styles.js.map +1 -1
  13. package/dist/esm/table/components/header/template.js +15 -2
  14. package/dist/esm/table/components/header/template.js.map +1 -1
  15. package/dist/esm/table/components/row/index.d.ts +5 -1
  16. package/dist/esm/table/components/row/index.js.map +1 -1
  17. package/dist/esm/table/components/row/template.d.ts +1 -1
  18. package/dist/esm/table/index.d.ts +13 -2
  19. package/dist/esm/table/index.js +62 -30
  20. package/dist/esm/table/index.js.map +1 -1
  21. package/dist/esm/table/models/sort-operations.d.ts +7 -0
  22. package/dist/esm/table/models/sort-operations.js +36 -0
  23. package/dist/esm/table/models/sort-operations.js.map +1 -0
  24. package/dist/esm/table/models/table-validator.d.ts +2 -0
  25. package/dist/esm/table/models/table-validator.js +14 -1
  26. package/dist/esm/table/models/table-validator.js.map +1 -1
  27. package/dist/esm/table/template.js +6 -1
  28. package/dist/esm/table/template.js.map +1 -1
  29. package/dist/esm/table/types.d.ts +10 -17
  30. package/dist/esm/table/types.js +8 -1
  31. package/dist/esm/table/types.js.map +1 -1
  32. package/dist/esm/table-column/base/index.d.ts +23 -1
  33. package/dist/esm/table-column/base/index.js +25 -3
  34. package/dist/esm/table-column/base/index.js.map +1 -1
  35. package/dist/esm/table-column/base/types.d.ts +26 -0
  36. package/dist/esm/table-column/base/types.js +15 -0
  37. package/dist/esm/table-column/base/types.js.map +1 -0
  38. package/dist/esm/table-column/text/index.d.ts +7 -1
  39. package/dist/esm/table-column/text/index.js +4 -1
  40. package/dist/esm/table-column/text/index.js.map +1 -1
  41. package/dist/esm/table-column/text/template.d.ts +1 -1
  42. package/package.json +1 -1
  43. package/dist/esm/table/models/table-validator.spec.d.ts +0 -1
  44. package/dist/esm/table/models/table-validator.spec.js +0 -276
  45. package/dist/esm/table/models/table-validator.spec.js.map +0 -1
@@ -26886,13 +26886,123 @@
26886
26886
  });
26887
26887
  }
26888
26888
 
26889
+ function getSortedRowModel() {
26890
+ return table => memo$1(() => [table.getState().sorting, table.getPreSortedRowModel()], (sorting, rowModel) => {
26891
+ if (!rowModel.rows.length || !(sorting != null && sorting.length)) {
26892
+ return rowModel;
26893
+ }
26894
+ const sortingState = table.getState().sorting;
26895
+ const sortedFlatRows = [];
26896
+
26897
+ // Filter out sortings that correspond to non existing columns
26898
+ const availableSorting = sortingState.filter(sort => {
26899
+ var _table$getColumn;
26900
+ return (_table$getColumn = table.getColumn(sort.id)) == null ? void 0 : _table$getColumn.getCanSort();
26901
+ });
26902
+ const columnInfoById = {};
26903
+ availableSorting.forEach(sortEntry => {
26904
+ const column = table.getColumn(sortEntry.id);
26905
+ if (!column) return;
26906
+ columnInfoById[sortEntry.id] = {
26907
+ sortUndefined: column.columnDef.sortUndefined,
26908
+ invertSorting: column.columnDef.invertSorting,
26909
+ sortingFn: column.getSortingFn()
26910
+ };
26911
+ });
26912
+ const sortData = rows => {
26913
+ // This will also perform a stable sorting using the row index
26914
+ // if needed.
26915
+ const sortedData = [...rows];
26916
+ sortedData.sort((rowA, rowB) => {
26917
+ for (let i = 0; i < availableSorting.length; i += 1) {
26918
+ var _sortEntry$desc;
26919
+ const sortEntry = availableSorting[i];
26920
+ const columnInfo = columnInfoById[sortEntry.id];
26921
+ const isDesc = (_sortEntry$desc = sortEntry == null ? void 0 : sortEntry.desc) != null ? _sortEntry$desc : false;
26922
+ if (columnInfo.sortUndefined) {
26923
+ const aValue = rowA.getValue(sortEntry.id);
26924
+ const bValue = rowB.getValue(sortEntry.id);
26925
+ const aUndefined = typeof aValue === 'undefined';
26926
+ const bUndefined = typeof bValue === 'undefined';
26927
+ if (aUndefined || bUndefined) {
26928
+ return aUndefined && bUndefined ? 0 : aUndefined ? columnInfo.sortUndefined : -columnInfo.sortUndefined;
26929
+ }
26930
+ }
26931
+
26932
+ // This function should always return in ascending order
26933
+ let sortInt = columnInfo.sortingFn(rowA, rowB, sortEntry.id);
26934
+ if (sortInt !== 0) {
26935
+ if (isDesc) {
26936
+ sortInt *= -1;
26937
+ }
26938
+ if (columnInfo.invertSorting) {
26939
+ sortInt *= -1;
26940
+ }
26941
+ return sortInt;
26942
+ }
26943
+ }
26944
+ return rowA.index - rowB.index;
26945
+ });
26946
+
26947
+ // If there are sub-rows, sort them
26948
+ sortedData.forEach(row => {
26949
+ var _row$subRows;
26950
+ sortedFlatRows.push(row);
26951
+ if ((_row$subRows = row.subRows) != null && _row$subRows.length) {
26952
+ row.subRows = sortData(row.subRows);
26953
+ }
26954
+ });
26955
+ return sortedData;
26956
+ };
26957
+ return {
26958
+ rows: sortData(rowModel.rows),
26959
+ flatRows: sortedFlatRows,
26960
+ rowsById: rowModel.rowsById
26961
+ };
26962
+ }, {
26963
+ key: 'getSortedRowModel',
26964
+ debug: () => {
26965
+ var _table$options$debugA;
26966
+ return (_table$options$debugA = table.options.debugAll) != null ? _table$options$debugA : table.options.debugTable;
26967
+ },
26968
+ onChange: () => {
26969
+ table._autoResetPageIndex();
26970
+ }
26971
+ });
26972
+ }
26973
+
26974
+ /**
26975
+ * The possible directions a table column can be sorted in.
26976
+ */
26977
+ const TableColumnSortDirection = {
26978
+ none: undefined,
26979
+ ascending: 'ascending',
26980
+ descending: 'descending'
26981
+ };
26982
+
26983
+ /**
26984
+ * The possible operations to use when sorting a table column.
26985
+ */
26986
+ const TableColumnSortOperation = {
26987
+ /**
26988
+ * Performs a sort using `===`, `<`, and `>` operators
26989
+ */
26990
+ basic: 'basic',
26991
+ /**
26992
+ * Performs a locale-aware case-sensitive string sort on the columns.
26993
+ * Only use this sort operation if the field is of type `string | undefined | null`.
26994
+ */
26995
+ localeAwareCaseSensitive: 'localeAwareCaseSensitive'
26996
+ };
26997
+
26889
26998
  /**
26890
26999
  * The base class for table columns
26891
27000
  */
26892
27001
  class TableColumn extends FoundationElement {
26893
27002
  constructor() {
26894
- super(...arguments);
27003
+ super();
26895
27004
  this.columnHidden = false;
27005
+ this.sortDirection = TableColumnSortDirection.none;
26896
27006
  /**
26897
27007
  * @internal
26898
27008
  *
@@ -26900,13 +27010,20 @@
26900
27010
  * This array is parallel with the field names specified by `cellRecordFieldNames`.
26901
27011
  */
26902
27012
  this.dataRecordFieldNames = [];
27013
+ /**
27014
+ * @internal
27015
+ *
27016
+ * The operation to use when sorting the table by this column.
27017
+ */
27018
+ this.sortOperation = TableColumnSortOperation.basic;
27019
+ this.internalUniqueId = uniqueId('table-column-slot');
26903
27020
  }
26904
27021
  /**
26905
27022
  * @internal
26906
27023
  */
26907
27024
  connectedCallback() {
26908
27025
  super.connectedCallback();
26909
- this.setAttribute('slot', uniqueId('table-column-slot'));
27026
+ this.setAttribute('slot', this.internalUniqueId);
26910
27027
  }
26911
27028
  }
26912
27029
  __decorate$1([
@@ -26921,12 +27038,24 @@
26921
27038
  __decorate$1([
26922
27039
  attr({ attribute: 'column-hidden', mode: 'boolean' })
26923
27040
  ], TableColumn.prototype, "columnHidden", void 0);
27041
+ __decorate$1([
27042
+ attr({ attribute: 'sort-index', converter: nullableNumberConverter })
27043
+ ], TableColumn.prototype, "sortIndex", void 0);
27044
+ __decorate$1([
27045
+ attr({ attribute: 'sort-direction' })
27046
+ ], TableColumn.prototype, "sortDirection", void 0);
26924
27047
  __decorate$1([
26925
27048
  observable
26926
27049
  ], TableColumn.prototype, "dataRecordFieldNames", void 0);
26927
27050
  __decorate$1([
26928
27051
  observable
26929
27052
  ], TableColumn.prototype, "columnConfig", void 0);
27053
+ __decorate$1([
27054
+ observable
27055
+ ], TableColumn.prototype, "operandDataRecordFieldName", void 0);
27056
+ __decorate$1([
27057
+ observable
27058
+ ], TableColumn.prototype, "sortOperation", void 0);
26930
27059
 
26931
27060
  /**
26932
27061
  * Helper class for the nimble-table to validate that the table's configuration
@@ -26939,6 +27068,7 @@
26939
27068
  this.invalidRecordId = false;
26940
27069
  this.duplicateColumnId = false;
26941
27070
  this.missingColumnId = false;
27071
+ this.duplicateSortIndex = false;
26942
27072
  }
26943
27073
  getValidity() {
26944
27074
  return {
@@ -26946,7 +27076,8 @@
26946
27076
  missingRecordId: this.missingRecordId,
26947
27077
  invalidRecordId: this.invalidRecordId,
26948
27078
  duplicateColumnId: this.duplicateColumnId,
26949
- missingColumnId: this.missingColumnId
27079
+ missingColumnId: this.missingColumnId,
27080
+ duplicateSortIndex: this.duplicateSortIndex
26950
27081
  };
26951
27082
  }
26952
27083
  isValid() {
@@ -27000,6 +27131,17 @@
27000
27131
  }
27001
27132
  return !this.missingColumnId && !this.duplicateColumnId;
27002
27133
  }
27134
+ validateColumnSortIndices(sortIndices) {
27135
+ this.duplicateSortIndex = false;
27136
+ const sortIndexSet = new Set();
27137
+ for (const sortIndex of sortIndices) {
27138
+ if (sortIndexSet.has(sortIndex)) {
27139
+ this.duplicateSortIndex = true;
27140
+ }
27141
+ sortIndexSet.add(sortIndex);
27142
+ }
27143
+ return !this.duplicateSortIndex;
27144
+ }
27003
27145
  }
27004
27146
 
27005
27147
  const styles$d = css `
@@ -27100,12 +27242,26 @@
27100
27242
  ${iconColor.cssCustomProperty}: ${tableHeaderFontColor};
27101
27243
  text-transform: uppercase;
27102
27244
  }
27245
+
27246
+ .sort-indicator {
27247
+ padding: 0px calc(${standardPadding} / 2);
27248
+ width: ${standardPadding};
27249
+ }
27103
27250
  `;
27104
27251
 
27105
27252
  // prettier-ignore
27106
27253
  const template$7 = html `
27107
- <template role="columnheader">
27254
+ <template role="columnheader" aria-sort="${x => x.ariaSort}">
27108
27255
  <slot></slot>
27256
+
27257
+ <span class="sort-indicator" aria-hidden="true">
27258
+ ${when(x => x.sortDirection === TableColumnSortDirection.ascending, html `
27259
+ <${DesignSystem.tagFor(IconArrowUp)}></${DesignSystem.tagFor(IconArrowUp)}>
27260
+ `)}
27261
+ ${when(x => x.sortDirection === TableColumnSortDirection.descending, html `
27262
+ <${DesignSystem.tagFor(IconArrowDown)}></${DesignSystem.tagFor(IconArrowDown)}>
27263
+ `)}
27264
+ </span>
27109
27265
  </template>
27110
27266
  `;
27111
27267
 
@@ -27114,7 +27270,36 @@
27114
27270
  * @internal
27115
27271
  */
27116
27272
  class TableHeader extends FoundationElement {
27273
+ constructor() {
27274
+ super(...arguments);
27275
+ this.sortDirection = TableColumnSortDirection.none;
27276
+ this.firstSortedColumn = false;
27277
+ }
27278
+ sortDirectionChanged(_prev, _next) {
27279
+ this.updateAriaSort();
27280
+ }
27281
+ firstSortedColumnChanged(_prev, _next) {
27282
+ this.updateAriaSort();
27283
+ }
27284
+ updateAriaSort() {
27285
+ if (!this.firstSortedColumn
27286
+ || this.sortDirection === TableColumnSortDirection.none) {
27287
+ this.ariaSort = null;
27288
+ }
27289
+ else if (this.sortDirection === TableColumnSortDirection.ascending) {
27290
+ this.ariaSort = 'ascending';
27291
+ }
27292
+ else {
27293
+ this.ariaSort = 'descending';
27294
+ }
27295
+ }
27117
27296
  }
27297
+ __decorate$1([
27298
+ attr({ attribute: 'sort-direction' })
27299
+ ], TableHeader.prototype, "sortDirection", void 0);
27300
+ __decorate$1([
27301
+ attr({ attribute: 'first-sorted-column', mode: 'boolean' })
27302
+ ], TableHeader.prototype, "firstSortedColumn", void 0);
27118
27303
  const nimbleTableHeader = TableHeader.compose({
27119
27304
  baseName: 'table-header',
27120
27305
  template: template$7,
@@ -27374,7 +27559,11 @@
27374
27559
  <div class="header-row" role="row">
27375
27560
  ${repeat(x => x.columns, html `
27376
27561
  ${when(x => !x.columnHidden, html `
27377
- <${DesignSystem.tagFor(TableHeader)} class="header">
27562
+ <${DesignSystem.tagFor(TableHeader)}
27563
+ class="header"
27564
+ sort-direction="${x => (typeof x.sortIndex === 'number' ? x.sortDirection : TableColumnSortDirection.none)}"
27565
+ ?first-sorted-column="${(x, c) => x === c.parent.firstSortedColumn}"
27566
+ >
27378
27567
  <slot name="${x => x.slot}"></slot>
27379
27568
  </${DesignSystem.tagFor(TableHeader)}>
27380
27569
  `)}
@@ -28130,6 +28319,40 @@
28130
28319
  observable
28131
28320
  ], Virtualizer.prototype, "rowContainerYOffset", void 0);
28132
28321
 
28322
+ /**
28323
+ * Returns the sorting function for TanStack to use based on the specified
28324
+ * TableColumnSortOperation
28325
+ */
28326
+ function getTanStackSortingFunction(sortOperation) {
28327
+ switch (sortOperation) {
28328
+ case TableColumnSortOperation.basic:
28329
+ return sortingFns.basic;
28330
+ case TableColumnSortOperation.localeAwareCaseSensitive:
28331
+ return localeAwareCaseSensitiveSortFunction;
28332
+ default:
28333
+ return sortingFns.basic;
28334
+ }
28335
+ }
28336
+ /**
28337
+ * A function to perform locale-aware and case-senstitive sorting of two rows from
28338
+ * TanStack for a given column. The function sorts `undefined` followed by `null`
28339
+ * before all defined strings.
28340
+ */
28341
+ function localeAwareCaseSensitiveSortFunction(rowA, rowB, columnId) {
28342
+ const valueA = rowA.getValue(columnId);
28343
+ const valueB = rowB.getValue(columnId);
28344
+ if (typeof valueA === 'string' && typeof valueB === 'string') {
28345
+ return valueA.localeCompare(valueB);
28346
+ }
28347
+ if (valueA === valueB) {
28348
+ return 0;
28349
+ }
28350
+ if (valueA === undefined || (valueA === null && valueB !== undefined)) {
28351
+ return -1;
28352
+ }
28353
+ return 1;
28354
+ }
28355
+
28133
28356
  /**
28134
28357
  * A nimble-styled table.
28135
28358
  */
@@ -28158,25 +28381,14 @@
28158
28381
  this.canRenderRows = true;
28159
28382
  this.tableValidator = new TableValidator();
28160
28383
  this.columnNotifiers = [];
28161
- this.update = (state) => {
28162
- this.table.setOptions(prev => ({
28163
- ...prev,
28164
- ...this.options,
28165
- state,
28166
- onStateChange: (updater) => {
28167
- const updatedState = typeof updater === 'function'
28168
- ? updater(state)
28169
- : updater;
28170
- this.update(updatedState);
28171
- }
28172
- }));
28173
- };
28174
28384
  this.options = {
28175
28385
  data: [],
28176
28386
  onStateChange: (_) => { },
28177
28387
  getCoreRowModel: getCoreRowModel(),
28388
+ getSortedRowModel: getSortedRowModel(),
28178
28389
  columns: [],
28179
28390
  state: {},
28391
+ enableSorting: true,
28180
28392
  renderFallbackValue: null,
28181
28393
  autoResetAll: false
28182
28394
  };
@@ -28187,7 +28399,6 @@
28187
28399
  return this.tableValidator.getValidity();
28188
28400
  }
28189
28401
  setData(newData) {
28190
- this.generateTanStackColumns(newData);
28191
28402
  this.setTableData(newData);
28192
28403
  }
28193
28404
  connectedCallback() {
@@ -28215,6 +28426,14 @@
28215
28426
  if (args === 'columnId') {
28216
28427
  this.validateColumnIds();
28217
28428
  }
28429
+ else if (args === 'operandDataRecordFieldName'
28430
+ || args === 'sortOperation') {
28431
+ this.generateTanStackColumns();
28432
+ }
28433
+ else if (args === 'sortIndex' || args === 'sortDirection') {
28434
+ this.validateColumnSortIndices();
28435
+ this.setSortState();
28436
+ }
28218
28437
  }
28219
28438
  }
28220
28439
  onRowActionMenuBeforeToggle(event) {
@@ -28237,6 +28456,8 @@
28237
28456
  return;
28238
28457
  }
28239
28458
  this.validateAndObserveColumns();
28459
+ this.generateTanStackColumns();
28460
+ this.setSortState();
28240
28461
  const slots = new Set();
28241
28462
  for (const column of this.columns) {
28242
28463
  if (column.actionMenuSlot) {
@@ -28259,11 +28480,20 @@
28259
28480
  this.columnNotifiers.push(notifier);
28260
28481
  }
28261
28482
  this.validateColumnIds();
28483
+ this.validateColumnSortIndices();
28262
28484
  }
28263
28485
  validateColumnIds() {
28264
28486
  this.tableValidator.validateColumnIds(this.columns.map(x => x.columnId));
28265
28487
  this.canRenderRows = this.checkValidity();
28266
28488
  }
28489
+ validateColumnSortIndices() {
28490
+ this.tableValidator.validateColumnSortIndices(this.getColumnsParticipatingInSorting().map(x => x.sortIndex));
28491
+ this.canRenderRows = this.checkValidity();
28492
+ }
28493
+ getColumnsParticipatingInSorting() {
28494
+ return this.columns.filter(x => x.sortDirection !== TableColumnSortDirection.none
28495
+ && typeof x.sortIndex === 'number');
28496
+ }
28267
28497
  async updateColumnsFromChildItems() {
28268
28498
  const definedElements = this.childItems.map(async (item) => (item.matches(':not(:defined)')
28269
28499
  ? customElements.whenDefined(item.localName)
@@ -28297,27 +28527,47 @@
28297
28527
  this.virtualizer.dataChanged();
28298
28528
  }
28299
28529
  updateTableOptions(updatedOptions) {
28300
- this.options = { ...this.options, ...updatedOptions };
28301
- this.update(this.table.initialState);
28530
+ this.options = {
28531
+ ...this.options,
28532
+ ...updatedOptions,
28533
+ state: { ...this.options.state, ...updatedOptions.state }
28534
+ };
28535
+ this.table.setOptions(this.options);
28302
28536
  this.refreshRows();
28303
28537
  }
28304
- // Generate columns for TanStack that correspond to all the keys in TData because all operations,
28305
- // such as grouping and sorting, will be performed on the data's records, not the values rendered within a cell.
28306
- generateTanStackColumns(data) {
28307
- if (data.length === 0) {
28308
- return;
28309
- }
28310
- const firstItem = data[0];
28311
- const keys = Object.keys(firstItem);
28312
- const generatedColumns = keys.map(key => {
28538
+ setSortState() {
28539
+ const sortedColumns = this.getColumnsParticipatingInSorting().sort((x, y) => x.sortIndex - y.sortIndex);
28540
+ this.firstSortedColumn = sortedColumns.length
28541
+ ? sortedColumns[0]
28542
+ : undefined;
28543
+ const tanStackSortingState = sortedColumns.map(column => {
28544
+ return {
28545
+ id: column.internalUniqueId,
28546
+ desc: column.sortDirection
28547
+ === TableColumnSortDirection.descending
28548
+ };
28549
+ });
28550
+ this.updateTableOptions({
28551
+ state: {
28552
+ sorting: tanStackSortingState
28553
+ }
28554
+ });
28555
+ }
28556
+ generateTanStackColumns() {
28557
+ const generatedColumns = this.columns.map(column => {
28313
28558
  const columnDef = {
28314
- id: key,
28315
- accessorKey: key,
28316
- header: key
28559
+ id: column.internalUniqueId,
28560
+ accessorKey: column.operandDataRecordFieldName,
28561
+ sortingFn: getTanStackSortingFunction(column.sortOperation)
28317
28562
  };
28318
28563
  return columnDef;
28319
28564
  });
28320
- this.updateTableOptions({ columns: generatedColumns });
28565
+ this.updateTableOptions({
28566
+ // Force TanStack to detect a data update because a columns's accessor is
28567
+ // referenced when creating a new row model.
28568
+ data: [...this.table.options.data],
28569
+ columns: generatedColumns
28570
+ });
28321
28571
  }
28322
28572
  }
28323
28573
  __decorate$1([
@@ -28341,6 +28591,9 @@
28341
28591
  __decorate$1([
28342
28592
  observable
28343
28593
  ], Table.prototype, "canRenderRows", void 0);
28594
+ __decorate$1([
28595
+ observable
28596
+ ], Table.prototype, "firstSortedColumn", void 0);
28344
28597
  const nimbleTable = Table.compose({
28345
28598
  baseName: 'table',
28346
28599
  template: template$4,
@@ -28389,13 +28642,15 @@
28389
28642
  */
28390
28643
  class TableColumnText extends TableColumn {
28391
28644
  constructor() {
28392
- super(...arguments);
28645
+ super();
28393
28646
  this.cellRecordFieldNames = ['value'];
28394
28647
  this.cellStyles = cellStyles;
28395
28648
  this.cellTemplate = cellTemplate;
28649
+ this.sortOperation = TableColumnSortOperation.localeAwareCaseSensitive;
28396
28650
  }
28397
28651
  fieldNameChanged() {
28398
28652
  this.dataRecordFieldNames = [this.fieldName];
28653
+ this.operandDataRecordFieldName = this.fieldName;
28399
28654
  }
28400
28655
  placeholderChanged() {
28401
28656
  this.columnConfig = { placeholder: this.placeholder ?? '' };