UNPKG

@3mo/data-grid

Version:
158 lines (157 loc) 6.42 kB
import { Controller } from '@a11d/lit'; import { DataGridColumnComponent } from './index.js'; export class DataGridColumnsController extends Controller { constructor(host) { super(host); this.host = host; this.columnWidths = { reordering: 0, details: 0, selection: 0, actions: 0 }; this._extractedColumns = new Array(); this.initialized = false; } hostUpdate() { this.provideCssColumnsProperties(); } hostUpdated() { if (!this.initialized && !this.host.columns.length) { this.extractColumns(); } this.host.columns.forEach(column => column.dataGrid = this.host); this.initialized = true; } get visibleColumns() { return this.host.columns.filter(c => c.hidden === false); } setColumns(columns) { this.host.columns = columns; this.host.columnsChange.dispatch(columns); this.host.requestUpdate(); } extractColumns() { this._extractedColumns = this.elementExtractedColumns.length > 0 ? this.elementExtractedColumns : this.autoGeneratedColumns; this.host.extractedColumnsUpdated(this._extractedColumns); } get extractedColumns() { return this._extractedColumns; } // The reason for not doing this in the CSS is that we need to trim all the 0px values out of the columns // because the 'grid column gap' renders a gap no matter if the column is 0px or not provideCssColumnsProperties() { const columns = this.columns.map(c => `[${c.name}] ${c.width}`).join(' '); if (this.host.style.getPropertyValue('--mo-data-grid-columns') !== columns) { this.host.style.setProperty('--mo-data-grid-columns', columns); } } get columns() { return [ { name: 'order', width: this.orderColumnWidth }, { name: 'details', width: this.detailsColumnWidth }, { name: 'selection', width: this.selectionColumnWidth }, ...this.dataColumnsWidths.map(width => ({ name: 'data', width })), { name: 'padding', width: '1fr' }, { name: 'actions', width: this.actionsColumnWidth } ].filter(c => c.width !== undefined); } get orderColumnWidth() { return !this.host.reorderabilityController.enabled ? undefined : window.getComputedStyle(this.host).getPropertyValue('--mo-data-grid-column-reorder-width'); } get detailsColumnWidth() { return !this.host.hasDetails ? undefined : window.getComputedStyle(this.host).getPropertyValue('--mo-data-grid-column-details-width'); } get selectionColumnWidth() { return !this.host.hasSelection ? undefined : window.getComputedStyle(this.host).getPropertyValue('--mo-data-grid-column-selection-width'); } get dataColumnsWidths() { return this.visibleColumns .map(c => c.width) .filter((c) => c !== undefined); } get actionsColumnWidth() { return this.host.sidePanelHidden && !this.host.hasContextMenu ? undefined : window.getComputedStyle(this.host).getPropertyValue('--mo-data-grid-column-actions-width'); } get columnsElements() { const slot = this.host.renderRoot?.querySelector('slot[name=column]'); if (!slot) { return []; } const children = [...slot.children]; const assigned = [...slot.assignedElements()]; return [...assigned, ...children] .filter((c) => c instanceof DataGridColumnComponent) .map(c => { c.dataGrid = this.host; return c; }); } get elementExtractedColumns() { return this.columnsElements.map(c => c.column); } get autoGeneratedColumns() { if (!this.host.dataLength) { return []; } const getDefaultColumnElement = (value) => { switch (typeof value) { case 'number': case 'bigint': return 'mo-data-grid-column-number'; case 'boolean': return 'mo-data-grid-column-boolean'; default: return 'mo-data-grid-column-text'; } }; const [sampleData] = this.host.data || []; return Object.keys(sampleData || {}) .filter(key => !key.startsWith('_')) .map(key => { const columnElement = document.createElement(getDefaultColumnElement(KeyPath.get(sampleData, key))); columnElement.heading = key.replace(/([A-Z])/g, ' $1').charAt(0).toUpperCase() + key.replace(/([A-Z])/g, ' $1').slice(1); columnElement.dataSelector = key; columnElement.dataGrid = this.host; const column = columnElement.column; columnElement.remove(); return column; }); } setColumnWidth(column, widthInPixels) { this.columnWidths[column] = widthInPixels; } getStickyColumnInsetInline(column) { if (typeof column !== 'object') { switch (column) { case 'reordering': return '0px'; case 'details': return `${this.columnWidths.reordering}px`; case 'selection': return `${this.columnWidths.reordering + this.columnWidths.details}px`; case 'actions': return 'auto'; } } if (!column.sticky) { return ''; } const columnIndex = this.visibleColumns.indexOf(column); const calculate = (type) => this.visibleColumns .filter((c, i) => c.sticky === type && (type === 'start' ? i < columnIndex : i > columnIndex)) .map(c => c.widthInPixels) .filter(x => x !== undefined) .reduce((a, b) => a + b, 0); const { reordering, selection, details, actions } = this.columnWidths; const start = `${reordering + selection + details + calculate('start')}px`; const end = `${calculate('end') + actions}px`; switch (column.sticky) { case 'start': return `${start} auto`; case 'end': return `auto ${end}`; case 'both': return `${start} ${end}`; default: return ''; } } }