@3mo/data-grid
Version:
A data grid web component
208 lines (199 loc) • 6.72 kB
JavaScript
import { __decorate } from "tslib";
import { component, Component, css, html, property, event, style, live, queryAll } from '@a11d/lit';
import { observeResize } from '@3mo/resize-observer';
import { Localizer } from '@3mo/localization';
import { DataGridSelectability, DataGridSidePanelTab } from './index.js';
Localizer.dictionaries.add('en', {
'Actions for ${count:pluralityNumber} selected entries': [
'Actions for the selected entry',
'Actions for ${count} selected entries',
],
});
Localizer.dictionaries.add('de', {
'Actions for ${count:pluralityNumber} selected entries': [
'Optionen für den ausgewählten Eintrag',
'Optionen für ${count} ausgewählte Einträge',
],
});
let DataGridHeader = class DataGridHeader extends Component {
constructor() {
super(...arguments);
this.overlayOpen = false;
this.handleDataGridDataChange = () => {
this.requestUpdate();
};
this.handleSelectionChange = (e) => {
const previousSelection = this.selection;
const selection = e.detail;
if (previousSelection === 'indeterminate' || selection === false) {
this.dataGrid.deselectAll();
}
else {
this.dataGrid.selectAll();
}
};
}
connected() {
this.dataGrid.dataChange.subscribe(this.handleDataGridDataChange);
}
disconnected() {
this.dataGrid.dataChange.unsubscribe(this.handleDataGridDataChange);
}
updated(...parameters) {
super.updated(...parameters);
this.columnHeaders.forEach(h => h.requestUpdate());
}
static get styles() {
return css `
:host {
--mo-data-grid-header-separator-height: 15px;
--mo-data-grid-header-separator-width: 2px;
display: grid;
grid-template-columns: subgrid;
position: sticky;
grid-column: -1 / 1;
background: var(--mo-data-grid-header-background, var(--mo-data-grid-sticky-part-color));
top: 0;
z-index: 4;
font-size: small;
border-block: var(--mo-data-grid-border);
height: var(--mo-data-grid-header-height);
}
.details, .selection, .actions, .context-menu {
position: sticky;
background: var(--mo-data-grid-sticky-part-color);
z-index: 5;
}
.details {
inset-inline-start: 0px;
}
.selection {
inset-inline-start: 0px;
}
.actions, .context-menu {
cursor: pointer;
inset-inline-end: 0px;
}
.actions {
mo-icon-button {
color: var(--mo-color-accent);
font-size: large;
}
}
.context-menu {
background-color: var(--mo-color-accent);
mo-icon-button {
color: var(--mo-color-on-accent);
font-size: 20px;
}
}
`;
}
get template() {
return html `
${this.detailsExpanderTemplate}
${this.selectionTemplate}
${this.contentTemplate}
${this.fillerTemplate}
${this.actionsTemplate}
`;
}
get detailsExpanderTemplate() {
return this.dataGrid.hasDetails === false ? html.nothing : html `
<mo-flex class='details' justifyContent='center' alignItems='center'
${style({ insetInlineStart: '0px' })}
${this.getResizeObserver('detailsColumnWidthInPixels')}
>
${!this.dataGrid.hasDetails || !this.dataGrid.multipleDetails ? html.nothing : html `
<mo-icon-button dense
icon=${this.dataGrid.allRowDetailsOpen ? 'unfold_less' : 'unfold_more'}
=${() => this.toggleAllDetails()}
></mo-icon-button>
`}
</mo-flex>
`;
}
get selectionTemplate() {
return !this.dataGrid.hasSelection ? html.nothing : html `
<mo-flex class='selection' justifyContent='center' alignItems='center'
${style({ insetInlineStart: this.dataGrid.hasDetails ? '20px' : '0px' })}
${this.getResizeObserver('selectionColumnWidthInPixels')}
>
${this.dataGrid.selectability !== DataGridSelectability.Multiple ? html.nothing : html `
<mo-checkbox .selected=${live(this.selection)} =${this.handleSelectionChange}></mo-checkbox>
`}
</mo-flex>
`;
}
get selection() {
switch (this.dataGrid.selectedData.length) {
case 0:
return false;
case this.dataGrid.dataLength:
return true;
default:
return 'indeterminate';
}
}
get contentTemplate() {
return html `
${this.dataGrid.visibleColumns.map(column => html `
<mo-data-grid-column-header .column=${column}></mo-data-grid-column-header>
`)}
`;
}
get fillerTemplate() {
return html `<span></span>`;
}
get actionsTemplate() {
if (this.dataGrid.hasContextMenu && this.dataGrid.selectedData.length > 1) {
return html `
<mo-flex class='context-menu' alignItems='end' justifyContent='center' ${this.getResizeObserver('actionsColumnWidthInPixels')}>
<mo-popover-container>
<mo-icon-button dense icon='more_vert' title=${t('Actions for ${count:pluralityNumber} selected entries', { count: this.dataGrid.selectedData.length })}></mo-icon-button>
<mo-menu slot='popover'>
${this.dataGrid.contextMenuController.getMenuContentTemplate()}
</mo-menu>
</mo-popover-container>
</mo-flex>
`;
}
if (!this.dataGrid.hasToolbar && !this.dataGrid.sidePanelHidden) {
return html `
<mo-flex class='actions' alignItems='end' justifyContent='center' ${this.getResizeObserver('actionsColumnWidthInPixels')}>
<mo-icon-button dense icon='settings'
=${() => this.dataGrid.navigateToSidePanelTab(this.dataGrid.sidePanelTab ? undefined : DataGridSidePanelTab.Settings)}
></mo-icon-button>
</mo-flex>
`;
}
return html.nothing;
}
getResizeObserver(property) {
// @ts-expect-error Readonly property set here
return observeResize(([entry]) => this.dataGrid.columnsController[property] = entry?.contentRect.width ?? 0);
}
toggleAllDetails() {
this.dataGrid.toggleRowDetails();
this.requestUpdate();
}
};
__decorate([
event()
], DataGridHeader.prototype, "pageChange", void 0);
__decorate([
event()
], DataGridHeader.prototype, "modeSelectionChange", void 0);
__decorate([
property({ type: Object })
], DataGridHeader.prototype, "dataGrid", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], DataGridHeader.prototype, "overlayOpen", void 0);
__decorate([
queryAll('mo-data-grid-column-header')
], DataGridHeader.prototype, "columnHeaders", void 0);
DataGridHeader = __decorate([
component('mo-data-grid-header')
], DataGridHeader);
export { DataGridHeader };