UNPKG

@hashicorp/design-system-components

Version:
382 lines (370 loc) 11.2 kB
import HdsAdvancedTableRow from './row.js'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking'; import { isEmpty } from '@ember/utils'; import HdsAdvancedTableColumn from './column.js'; import { HdsAdvancedTableThSortOrderValues, HdsAdvancedTableColumnReorderSideValues } from '../types.js'; import { g, i, n } from 'decorator-transforms/runtime'; /** * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ function getVisibleRows(rows) { return rows.reduce((acc, row) => { acc.push(row); if (row.isOpen && row.children) { acc.push(...getVisibleRows(row.children)); } return acc; }, []); } function getChildrenCount(rows) { return rows.reduce((acc, row) => acc + 1 + getChildrenCount(row.children ?? []), 0); } class HdsAdvancedTableTableModel { static { g(this.prototype, "columns", [tracked], function () { return []; }); } #columns = (i(this, "columns"), void 0); static { g(this.prototype, "columnOrder", [tracked], function () { return []; }); } #columnOrder = (i(this, "columnOrder"), void 0); static { g(this.prototype, "reorderDraggedColumn", [tracked], function () { return null; }); } #reorderDraggedColumn = (i(this, "reorderDraggedColumn"), void 0); static { g(this.prototype, "reorderHoveredColumn", [tracked], function () { return null; }); } #reorderHoveredColumn = (i(this, "reorderHoveredColumn"), void 0); static { g(this.prototype, "rows", [tracked], function () { return []; }); } #rows = (i(this, "rows"), void 0); static { g(this.prototype, "sortBy", [tracked], function () { return undefined; }); } #sortBy = (i(this, "sortBy"), void 0); static { g(this.prototype, "sortOrder", [tracked], function () { return HdsAdvancedTableThSortOrderValues.Asc; }); } #sortOrder = (i(this, "sortOrder"), void 0); static { g(this.prototype, "gridElement", [tracked], function () { return undefined; }); } #gridElement = (i(this, "gridElement"), void 0); childrenKey; hasReorderableColumns; hasResizableColumns; onColumnReorder; onSort; constructor(args) { const { model, columns, columnOrder, childrenKey, hasReorderableColumns, hasResizableColumns, sortBy, sortOrder, onColumnReorder, onSort } = args; this.childrenKey = childrenKey; this.hasReorderableColumns = hasReorderableColumns; this.hasResizableColumns = hasResizableColumns; this.onSort = onSort; this.setupData({ model, columns, sortBy, sortOrder }); // set initial column order if (this.hasReorderableColumns) { this.columnOrder = isEmpty(columnOrder) ? this.columns.map(column => column.key) : columnOrder; // ensured non-empty this.onColumnReorder = onColumnReorder; } } get hasColumnBeingDragged() { return this.reorderDraggedColumn !== null; } get reorderDraggedColumnCells() { if (this.reorderDraggedColumn === null) { return []; } const { key } = this.reorderDraggedColumn; return this.flattenedVisibleRows.map(row => { const cell = row.cells.find(cell => cell.columnKey === key); return cell; }); } get orderedColumns() { if (this.hasReorderableColumns) { return this.columnOrder.reduce((acc, key) => { const column = this.columns.find(column => column.key === key); if (column !== undefined) { acc.push(column); } return acc; }, []); } else { return this.columns; } } get sortCriteria() { // get the current column const currentColumn = this.columns.find(column => column.key === this.sortBy); if ( // check if there is a custom sorting function associated with the current `sortBy` column (we assume the column has `isSortable`) currentColumn?.sortingFunction && typeof currentColumn.sortingFunction === 'function') { return currentColumn.sortingFunction; } else { // otherwise fallback to the default format "sortBy:sortOrder" return `${this.sortBy}:${this.sortOrder}`; } } get sortedRows() { const criteria = this.sortCriteria; const rows = this.rows; if (rows.length <= 1 || criteria === undefined) { return rows; } if (typeof criteria === 'function') { // Use custom sort function return [...rows].sort(criteria); } else { // Parse the criteria string format "sortBy:sortOrder" const [sortBy, sortOrder] = criteria.split(':'); if (!sortBy) { return rows; } return [...rows].sort((a, b) => { const valueA = a[sortBy]; const valueB = b[sortBy]; if (valueA < valueB) { return sortOrder === 'asc' ? -1 : 1; } if (valueA > valueB) { return sortOrder === 'asc' ? 1 : -1; } return 0; }); } } get totalRowCount() { return getChildrenCount(this.sortedRows); } get flattenedVisibleRows() { return getVisibleRows(this.sortedRows); } get lastVisibleRow() { return this.flattenedVisibleRows[this.flattenedVisibleRows.length - 1]; } get hasRowsWithChildren() { return this.rows.some(row => row.hasChildren); } get allRowsAreOpen() { return this.flattenedVisibleRows.length === this.totalRowCount; } get expandState() { if (this.allRowsAreOpen) { return true; } else { return false; } } setTransientColumnWidths(options = {}) { const roundValues = options.roundValues ?? false; this.columns.forEach(column => { column.pxTransientWidth = roundValues ? Math.round(column.pxWidth) : column.pxWidth; }); } resetTransientColumnWidths() { this.columns.forEach(column => { column.pxTransientWidth = undefined; }); } getColumnByKey(key) { return this.columns.find(column => column.key === key); } setupData(args) { const { model, columns, sortBy, sortOrder } = args; this.sortBy = sortBy; this.sortOrder = sortOrder ?? HdsAdvancedTableThSortOrderValues.Asc; this.columns = columns.map(column => new HdsAdvancedTableColumn({ column, table: this })); this.rows = model.map(row => { return new HdsAdvancedTableRow({ ...row, childrenKey: this.childrenKey, columns, table: this }); }); } static { n(this.prototype, "setupData", [action]); } restoreColumnWidths() { this.columns.forEach(column => { column.width = column.originalWidth; }); } static { n(this.prototype, "restoreColumnWidths", [action]); } setSortBy(column) { if (this.sortBy === column) { // check to see if the column is already sorted and invert the sort order if so this.sortOrder = this.sortOrder === HdsAdvancedTableThSortOrderValues.Asc ? HdsAdvancedTableThSortOrderValues.Desc : HdsAdvancedTableThSortOrderValues.Asc; } else { // otherwise, set the sort order to ascending this.sortBy = column; this.sortOrder = HdsAdvancedTableThSortOrderValues.Asc; } if (typeof this.onSort === 'function') { this.onSort(this.sortBy, this.sortOrder); } } static { n(this.prototype, "setSortBy", [action]); } openAll() { this.rows.forEach(row => row.openAll()); } static { n(this.prototype, "openAll", [action]); } collapseAll() { this.rows.forEach(row => row.collapseAll()); } static { n(this.prototype, "collapseAll", [action]); } toggleAll() { if (this.allRowsAreOpen) { this.collapseAll(); } else { this.openAll(); } } static { n(this.prototype, "toggleAll", [action]); } stepColumn(column, step) { const { table } = column; const oldIndex = table.orderedColumns.indexOf(column); const newIndex = oldIndex + step; // Check if the new position is within the array bounds. if (newIndex < 0 || newIndex >= table.orderedColumns.length) { return; } const targetColumn = table.orderedColumns[newIndex]; if (targetColumn === undefined) { return; } // Determine the side based on the step direction. const side = step > 0 ? HdsAdvancedTableColumnReorderSideValues.Right : HdsAdvancedTableColumnReorderSideValues.Left; table.moveColumnToTarget(column, targetColumn, side); } static { n(this.prototype, "stepColumn", [action]); } moveColumnToTerminalPosition(column, position) { const firstColumn = this.orderedColumns.find(column => column.isFirst); const { targetColumn, side } = position === 'start' ? { targetColumn: firstColumn, side: HdsAdvancedTableColumnReorderSideValues.Left } : { targetColumn: this.orderedColumns[this.orderedColumns.length - 1], side: HdsAdvancedTableColumnReorderSideValues.Right }; if (targetColumn === undefined) { return; } // Move the column to the target position this.moveColumnToTarget(column, targetColumn, side); } static { n(this.prototype, "moveColumnToTerminalPosition", [action]); } moveColumnToTarget(sourceColumn, targetColumn, side) { const sourceKey = sourceColumn.key; const targetKey = targetColumn.key; const oldIndex = this.columnOrder.indexOf(sourceKey); const newIndex = this.columnOrder.indexOf(targetKey); if (oldIndex !== -1 && newIndex !== -1) { const updated = [...this.columnOrder]; updated.splice(oldIndex, 1); // Remove from old position // Calculate the insertion index based on the side // If dropping to the right of the target, insert after the target // If dropping to the left of the target, insert before the target // Adjust for the shift in indices caused by removing the source column const adjustedIndex = side === HdsAdvancedTableColumnReorderSideValues.Right ? newIndex > oldIndex ? newIndex : newIndex + 1 : newIndex > oldIndex ? newIndex - 1 : newIndex; updated.splice(adjustedIndex, 0, sourceColumn.key); // Insert at new position this.columnOrder = updated; // we need to wait until the reposition has finished requestAnimationFrame(() => { sourceColumn.thElement?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); sourceColumn.isBeingDragged = false; this.onColumnReorder?.({ column: sourceColumn, newOrder: updated, insertedAt: updated.indexOf(sourceColumn.key) }); }); } } static { n(this.prototype, "moveColumnToTarget", [action]); } moveColumnToDropTarget(targetColumn, side) { const sourceColumn = this.reorderDraggedColumn; if (sourceColumn == null || sourceColumn === targetColumn) { return; } this.moveColumnToTarget(sourceColumn, targetColumn, side); } static { n(this.prototype, "moveColumnToDropTarget", [action]); } } export { HdsAdvancedTableTableModel as default }; //# sourceMappingURL=table.js.map