@3mo/data-grid
Version:
A data grid web component
117 lines (116 loc) • 4.69 kB
JavaScript
import { Controller } from '@a11d/lit';
import { DataGridColumnComponent } from './index.js';
export class DataGridColumnsController extends Controller {
constructor(host) {
super(host);
this.host = host;
this.detailsColumnWidthInPixels = 0;
this.selectionColumnWidthInPixels = 0;
this.actionsColumnWidthInPixels = 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: '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 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;
});
}
}