import { LitElement, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { classMap } from 'lit-html/directives/class-map.js';
// Import required components and icons
import '@kyndryl-design-system/shidoka-foundation/components/button';
import '@kyndryl-design-system/shidoka-foundation/components/icon';
import '../checkbox/checkbox';
import './index';
import styles from './data-table.scss';
type ColumnDefinition = {
sortable?: boolean;
sortFn?: Function;
field: string;
align?: string;
headerName: string;
valueGetter?: Function;
width?: string;
maxWidth?: string;
ellipsis?: boolean;
cellRenderer?: (data: { row: any; column: ColumnDefinition }) => any;
};
/**
* DEPRECATED. `kyn-data-table` Web Component.
* This component provides a table with sorting, pagination, and selection capabilities.
* It is designed to be used with the `kyn-table-toolbar` and `kyn-table-container` components.
* @fires on-selected-rows-changed - Dispatched when the selected rows change.
* @fires on-sort-changed - Dispatched when the sort order changes.
* @fires on-page-changed - Dispatched when the page number or page size changes.
*/
@customElement('data-table')
export class DataTable extends LitElement {
static override styles = [styles];
/**
* rows: Array of objects representing each row in the data table.
*/
@property({ type: Array })
rows: any[] = [];
/**
* columns: Array of objects defining column properties such as
* field name, sorting function, etc.
*/
@property({ type: Array })
columns: ColumnDefinition[] = [];
/**
* checkboxSelection: Boolean indicating whether rows should be
* selectable using checkboxes.
*/
@property({ type: Boolean })
checkboxSelection = false;
/**
* striped: Boolean indicating whether rows should have alternate
* coloring.
*/
@property({ type: Boolean })
striped = false;
/**
* selectedRows: Set of row ids that are currently selected.
*/
@property({ type: Set })
selectedRows = new Set();
/**
* selectAll: Boolean indicating whether all rows are currently
* selected.
* @ignore
*/
@state()
selectAll = false;
/**
* stickyHeader: Boolean indicating whether the table header
* should be sticky.
*/
@property({ type: Boolean })
stickyHeader = false;
/**
* dense: Boolean indicating whether the table should be displayed
* in dense mode.
*/
@property({ type: Boolean })
dense = false;
/**
* paginationModel: Object holding pagination information such as
* current page, page size, etc.
*/
@property({ type: Object })
paginationModel = {
count: 0,
pageSize: 5,
pageNumber: 0,
pageSizeOptions: [5, 10],
};
/** Option to hide the items range display. */
@property({ type: Boolean })
hideItemsRange = false;
/** Option to hide the page size dropdown. */
@property({ type: Boolean })
hidePageSizeDropdown = false;
/** Option to hide the navigation buttons. */
@property({ type: Boolean })
hideNavigationButtons = false;
/** Determines if the table layout is fixed (true) or auto (false). */
@property({ type: Boolean })
fixedLayout = false;
/**
* headerCheckboxIndeterminate: Boolean indicating whether the header
* checkbox is in an indeterminate state.
* @ignore
*/
@state()
headerCheckboxIndeterminate = false;
/**
* headerCheckboxChecked: Boolean indicating whether the header checkbox is
* checked.
* @ignore
*/
@state()
headerCheckboxChecked = false;
/**
* Updates the state of the header checkbox based on the number of
* selected rows.
*/
updateHeaderCheckbox() {
if (this.selectedRows.size === 0) {
this.headerCheckboxIndeterminate = false;
this.headerCheckboxChecked = false;
} else if (this.selectedRows.size === this.rows.length) {
this.headerCheckboxIndeterminate = false;
this.headerCheckboxChecked = true;
this.selectAll = true;
} else {
this.headerCheckboxIndeterminate = true;
this.headerCheckboxChecked = false;
this.selectAll = false;
}
}
/**
* Handles the change of selection state for a specific row.
*/
handleRowSelectionChange(rowId: number, isChecked: boolean) {
const newSet = new Set(this.selectedRows);
if (isChecked) {
newSet.add(rowId);
} else {
newSet.delete(rowId);
}
this.selectedRows = newSet;
this.updateHeaderCheckbox();
// Emit the custom event with the updated selectedRows
this.dispatchEvent(
new CustomEvent('on-selected-rows-changed', {
detail: { selectedRows: Array.from(this.selectedRows) },
bubbles: true,
composed: true,
})
);
}
/**
* Toggles the selection state of all rows in the table.
*/
toggleSelectionAll() {
this.selectAll = !this.selectAll;
if (this.selectAll) {
// If selecting all, add all row ids to the selectedRows set
this.rows.forEach((row) => this.selectedRows.add(row.id));
} else {
// If deselecting all, clear the selectedRows set
this.selectedRows.clear();
}
this.updateHeaderCheckbox();
this.requestUpdate();
this.dispatchEvent(
new CustomEvent('on-selected-rows-changed', {
detail: { selectedRows: Array.from(this.selectedRows) },
bubbles: true,
composed: true,
})
);
}
/**
* Handles the change of page size in pagination.
*/
onPageSizeChange(event: CustomEvent) {
this.paginationModel.pageSize = event.detail.value;
this.dispatchEvent(
new CustomEvent('on-page-changed', {
detail: { pageSize: event.detail.value, pageNumber: 1 },
bubbles: true,
composed: true,
})
);
}
/**
* Handles the change of page number in pagination.
*/
onPageNumberChange(event: CustomEvent) {
this.paginationModel.pageNumber = event.detail.value;
const pageSize = this.paginationModel.pageSize;
this.dispatchEvent(
new CustomEvent('on-page-changed', {
detail: { pageNumber: event.detail.value, pageSize },
bubbles: true,
composed: true,
})
);
}
override render() {
const { count, pageSize, pageNumber, pageSizeOptions } =
this.paginationModel;
this.selectedRows = new Set(this.selectedRows || []);
this.updateHeaderCheckbox();
return html`
${this.checkboxSelection
? html` Select All Items
`
: null}
${this.columns.map(
({ sortable, sortFn, field, align, headerName }) =>
html`${headerName}`
)}
${this.rows.map(
(row) => html`
{
if (this.checkboxSelection) {
this.handleRowSelectionChange(
row.id,
!this.selectedRows.has(row.id)
);
}
}}
>
${this.checkboxSelection
? html`
{
this.handleRowSelectionChange(
row.id,
e.detail.checked
);
}}
>${row.id}
`
: null}
${this.columns.map(
(column) => html`
${column.cellRenderer
? column.cellRenderer({ row, column })
: column.valueGetter
? column.valueGetter({ row })
: row[column.field]}
`
)}
`
)}
${this.paginationModel?.count > 0
? html` `
: null}
`;
}
}
// Define the custom element in the global namespace
declare global {
interface HTMLElementTagNameMap {
'data-table': DataTable;
}
}