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; } }