UNPKG

@freshworks/crayons

Version:
986 lines (984 loc) 63.1 kB
import { attachShadow, createEvent, h, proxyCustomElement } from '@stencil/core/internal/client'; import { T as TranslationController } from './Translation.js'; import { d as defineCustomElement$g } from './avatar.js'; import { d as defineCustomElement$f } from './button.js'; import { d as defineCustomElement$e } from './checkbox.js'; import { d as defineCustomElement$d } from './custom-cell-anchor.js'; import { d as defineCustomElement$c } from './custom-cell-icon.js'; import { d as defineCustomElement$b } from './custom-cell-paragraph.js'; import { d as defineCustomElement$a } from './custom-cell-user.js'; import { d as defineCustomElement$9 } from './drag-container.js'; import { d as defineCustomElement$3, a as defineCustomElement$8 } from './icon.js'; import { d as defineCustomElement$7 } from './input.js'; import { c as createPopper, d as defineCustomElement$6 } from './popover.js'; import { d as defineCustomElement$5 } from './skeleton.js'; import { d as defineCustomElement$4 } from './spinner.js'; import { d as defineCustomElement$2 } from './tooltip.js'; const dataTableCss = ":host{font-family:var(--fw-font-family, -apple-system, blinkmacsystemfont, \"Segoe UI\", roboto, oxygen, ubuntu, cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-box-sizing:border-box;box-sizing:border-box}:host{display:block}div.fw-data-table-container{position:relative;width:100%;height:100%;overflow:visible}div.fw-data-table-container div.fw-data-table-scrollable{position:relative;display:block;width:100%;height:100%;overflow:auto}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table{table-layout:fixed;border-collapse:collapse;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:100%;width:-webkit-max-content;width:-moz-max-content;width:max-content}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead{position:-webkit-sticky;position:sticky;top:0;width:100%;border-radius:4px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead tr th{color:#475867;font-size:12px;line-height:20px;padding:12px 8px;font-weight:600;letter-spacing:0.2px;text-overflow:ellipsis;text-align:left;z-index:1;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:40px;max-width:1000px;background:#f5f7f9;overflow-wrap:anywhere;word-break:break-word;white-space:normal}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead tr th:first-of-type{padding-left:16px;border-radius:4px 0px 0px 0px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead tr th:last-of-type{padding-right:16px;border-radius:0px 4px 0px 0px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead tr th.data-grid-sm{padding:4px 8px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead tr th.data-grid-md{padding:12px 8px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead tr th.data-grid-lg{padding:16px 8px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table thead tr th.hidden{display:none}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody{width:100%;background:#fff}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr{width:100%;border-bottom:1px solid #ebeff3}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr:hover,div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr:focus{background:#f5f7f9}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr.active{background:#e5f2fd}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr:last-child{border-bottom:0px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td{color:#12344d;font-size:14px;line-height:20px;padding:12px 8px;text-overflow:ellipsis;-webkit-box-sizing:border-box;box-sizing:border-box;z-index:0;height:64px;overflow-wrap:anywhere;word-break:break-word;white-space:normal}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.data-grid-checkbox{text-align:center;width:20px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.data-grid-sm{padding:4px 8px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.data-grid-md{padding:12px 8px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.data-grid-lg{padding:16px 8px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td:first-child{padding-left:16px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td:last-child{padding-right:16px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.row-actions{width:1px;white-space:nowrap}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.row-actions fw-button{margin-right:5px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.row-actions fw-tooltip:last-child fw-button{margin-right:0px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr td.hidden{display:none}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr.loading{cursor:not-allowed}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr.loading td{position:relative;opacity:0.65}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody tr.loading td::after{content:\"\";position:absolute;top:0px;left:0px;bottom:0px;right:0px}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table tbody fw-skeleton{display:block;height:10px;padding:4px 0px;-webkit-box-sizing:content-box;box-sizing:content-box}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table.is-selectable td:first-child,div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table.is-selectable th:first-child{text-align:center}div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table.is-selectable td:first-child fw-checkbox,div.fw-data-table-container div.fw-data-table-scrollable table.fw-data-table.is-selectable th:first-child fw-checkbox{display:block;width:16px;height:20px}div.fw-data-table-container div.fw-data-table-scrollable.loading{opacity:0.65}div.fw-data-table-container div.fw-data-table-scrollable.shimmer{overflow:hidden}div.fw-data-table-container .fw-data-table--loading{position:absolute;top:0px;left:0px;width:100%;height:100%}div.fw-data-table-container .table-settings{position:absolute;right:0px;top:0px}div.fw-data-table-container .table-settings .table-settings-container{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:end;align-items:flex-end}div.fw-data-table-container .table-settings .table-settings-container .table-settings-button{width:40px;min-height:44px;background:#fff;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #ebeff3;border-radius:0px 4px 0px 0px;margin:0px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-button:focus,div.fw-data-table-container .table-settings .table-settings-container .table-settings-button:hover{cursor:pointer}div.fw-data-table-container .table-settings .table-settings-container .table-settings-button:disabled{cursor:default;opacity:0.65}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options{z-index:99;width:500px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#fff;border:1px solid #ebeff3;border-radius:4px;-webkit-box-shadow:-15px 20px 40px rgba(0, 0, 0, 0.04);box-shadow:-15px 20px 40px rgba(0, 0, 0, 0.04);padding:22px 0px 0px 0px;display:none;-webkit-animation:appear 0.3s;animation:appear 0.3s}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options.show{display:block}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-header{display:-ms-flexbox;display:flex;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;font-weight:600;-ms-flex-align:end;align-items:flex-end;padding:0px 22px;margin-bottom:16px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-header span.title{-ms-flex-positive:1;flex-grow:1;font-size:16px;line-height:24px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-header button.reset{-ms-flex-positive:0;flex-grow:0;color:#2c5cc5;font-size:14px;font-weight:600;text-decoration:none;line-height:17px;padding-right:4px;margin:0px;background:#fff;border:0px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-header button.reset:focus,div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-header button.reset:hover{cursor:pointer}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content{display:-ms-flexbox;display:flex;width:100%;height:342px;-webkit-box-sizing:border-box;box-sizing:border-box;padding:0px 22px;gap:14px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-left{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-positive:1;flex-grow:1;width:220px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-left .table-settings-content-title{-webkit-box-sizing:border-box;box-sizing:border-box;padding-bottom:5px;padding-left:5px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-left .table-settings-content-search{position:relative;top:-3px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-left .table-settings-content-choose{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-positive:1;flex-grow:1;margin-top:14px;overflow-y:hidden;-webkit-transform:translateX(-3px);transform:translateX(-3px);width:calc(100% + 5px)}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-left .table-settings-content-choose .table-settings-content-checkboxes{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow-y:auto;padding-left:5px;padding-right:5px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-left .table-settings-content-choose .table-settings-content-checkboxes div{margin:5px 0px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-left .table-settings-content-choose .table-settings-content-checkboxes div fw-checkbox{width:100%;overflow-wrap:break-word}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:220px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#ebeff3;border-radius:4px 4px 0px 0px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-title{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px 12px 3px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable{width:100%;-ms-flex-positive:1;flex-grow:1;padding:0px 12px;-webkit-box-sizing:border-box;box-sizing:border-box;overflow-y:auto}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item{display:-ms-flexbox;display:flex;background:#fff;border-radius:4px;-webkit-box-shadow:0px 2px 4px rgba(18, 52, 77, 0.06);box-shadow:0px 2px 4px rgba(18, 52, 77, 0.06);border:1px solid #ebeff3;padding:7px 8px 7px 14px;margin:8px 0px;font-size:14px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-icon,div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-close{width:16px;-ms-flex-positive:0;flex-grow:0;text-align:center}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-icon:focus,div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-icon:hover,div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-close:focus,div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-close:hover{cursor:pointer}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-icon.non-drag:hover,div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-icon.non-drag:focus{cursor:default}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-icon{width:9px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-close{background:#fff;border:0px;padding:0px;margin:0px}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-text{-ms-flex-positive:1;flex-grow:1;color:#12344d;padding:0px 11px;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-text:hover,div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-right .table-settings-content-draggable .table-settings-drag-item .table-settings-drag-item-text:focus{cursor:default}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-content .table-settings-content-title{font-size:14px;line-height:20px;color:#475867;font-weight:600}div.fw-data-table-container .table-settings .table-settings-container .table-settings-options .table-settings-footer{display:-ms-flexbox;display:flex;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;background:#f5f7f9;padding:12px 16px;gap:12px;-ms-flex-pack:end;justify-content:flex-end}@media (prefers-reduced-motion){div.fw-data-table-container .table-settings .table-settings-container .table-settings-options{-webkit-animation:none;animation:none}}div.fw-data-table-container .table-settings .table-settings-overlay{position:fixed;width:100vw;height:100vh;top:0px;left:0px;z-index:95}@-webkit-keyframes appear{from{opacity:0}to{opacity:1}}@keyframes appear{from{opacity:0}to{opacity:1}}"; const PREDEFINED_VARIANTS_META = { anchor: { componentName: 'fw-custom-cell-anchor', isFocusable: true, }, user: { componentName: 'fw-custom-cell-user', isFocusable: false, skipTextAlign: true, }, icon: { componentName: 'fw-custom-cell-icon', isFocusable: false, }, paragraph: { componentName: 'fw-custom-cell-paragraph', isFocusable: true, }, }; const TABLE_POPPER_CONFIG = { strategy: 'fixed', placement: 'bottom-end', modifiers: [ { name: 'offset', options: { offset: [0, 2], }, }, ], }; let localStorage = null; try { if (window.localStorage) { localStorage = window.localStorage; } } catch (error) { console.warn('Cannot save table settings to localStorage'); } let DataTable = class extends HTMLElement { constructor() { super(); this.__registerHost(); attachShadow(this); this.fwSelectionChange = createEvent(this, "fwSelectionChange", 7); this.fwSelectAllChange = createEvent(this, "fwSelectAllChange", 7); /** * Label attribute is not visible on screen. There for accessibility purposes. */ this.label = ''; /** * To enable bulk actions on the table. */ this.rowActions = []; /** * Rows Array of objects to be displayed in the table. */ this.rows = []; /** * Columns Array of objects that provides information regarding the columns in the table. */ this.columns = []; /** * isSelectable Boolean based on which selectable options appears for rows in the table. */ this.isSelectable = false; /** * isAllSelectable Boolean based on which select all option appears in the table header */ this.isAllSelectable = false; /** * showSettings is used to show the settings button on the table. */ this.showSettings = false; /** * autoSaveSettings to enable auto saving of table settings to `localstorage`. * If set to `true`, make sure `id` attribute is also set to the `data-table` */ this.autoSaveSettings = false; /** * To disable table during async operations */ this.isLoading = false; /** * shimmerCount number of shimmer rows to show during initial loading */ this.shimmerCount = 4; /** * orderedColumns Maintains a collection of ordered columns. */ this.orderedColumns = []; /** * selected Array of selected row id. */ this.selected = []; /** * Collection of rows loading */ this.rowsLoading = {}; /** * Temporary setting for table column drag/drop configuration */ this.columnsDragSetting = []; /** * Temporary settings for table column hide/show configuration */ this.columnsHideSetting = []; /** * isSettingsOpen when true shows table settings container. */ this.isSettingsOpen = false; /** * text to search for columns in settings. */ this.settingSearchText = ''; /** * disable column hide options when only one column is visible. */ this.disabledColumnHide = false; /** * show shimmer on set to false after intial table load. */ this.showShimmer = true; /** * width of the columns is auto calculated as table width is lesser than container width. */ this.ifAutoCalculatedWidth = false; /** * Private * To perform actions after a render * WorkAround for stencil wait for next render * https://github.com/ionic-team/stencil/issues/2744 */ this.renderPromiseResolve = null; this.popperInstance = null; this.settingsButton = null; this.settingsUpdateButton = null; this.settingsResetButton = null; this.settingsInput = null; this.settingsDragContainer = null; this.settings = null; this.tableContainer = null; this.selectColumnHeader = null; this.lastColumnHeader = null; } /** * componentWillLoad lifecycle event */ componentWillLoad() { this.columnOrdering(this.columns); if (localStorage && this.autoSaveSettings) { const tableId = this.el.id ? `-${this.el.id}` : ''; const tableSettings = localStorage.getItem(`fw-table${tableId}`); tableSettings && this.setTableSettings(JSON.parse(tableSettings)); } this.rows.length && this.hideShimmer(); } /** * componentDidLoad lifecycle event */ componentDidLoad() { if (this.showSettings) { if (this.settingsButton) { this.settingsButton.style.height = this.el.shadowRoot.querySelector('thead').offsetHeight + 'px'; } this.popperInstance = createPopper(this.settingsButton, this.settings, TABLE_POPPER_CONFIG); } } /** * componentDidRender lifecycle event */ componentDidRender() { if (this.renderPromiseResolve) { this.renderPromiseResolve(); this.renderPromiseResolve = null; } /** * Hack to override table behaviour of expanding columns when total column with lesser than container width. * Idea is to remove the width on the last column so that it occupies the rest of the space. */ if (this.selectColumnHeader) { if (parseInt(window.getComputedStyle(this.selectColumnHeader).width) > 40 && !this.ifAutoCalculatedWidth) { this.ifAutoCalculatedWidth = true; } } } disconnectedCallback() { var _a; (_a = this.popperInstance) === null || _a === void 0 ? void 0 : _a.destroy(); } /** * keyDownHandler * @param event */ keyDownHandler(event) { if (event.key === 'Escape') { this.toggleSettings(false); } else { this.arrowNavigate(event); } } /** * showSettingsHandler * @param showSettings */ showSettingsHandler(showSettings) { if (showSettings) { this.waitForNextRender().then(() => { this.settingsButton.style.height = this.el.shadowRoot.querySelector('thead').offsetHeight + 'px'; if (!this.popperInstance) { this.popperInstance = createPopper(this.settingsButton, this.settings, TABLE_POPPER_CONFIG); } }); } } /** * columnsChangeHandler * @param newColumns recent datatable columns value */ columnsChangeHandler(newColumns) { this.columnOrdering(newColumns); } /** * watchChangeHandler * @param newRows recent datatable columns value */ rowsChangeHandler(newRows) { newRows.length && this.hideShimmer(); } loadingHandler() { if (this.isSettingsOpen) { this.toggleSettings(false); } } /** * Private * selectRow * @param rowId Id of row to select/unselect in the table * @param checked option to select/unselct * @returns currently selected rows */ selectRow(rowId, checked = true) { if (checked) { if (this.selected.indexOf(rowId) < 0) { this.selected = [...this.selected, rowId]; } } else { const selected = this.selected.filter((selected) => selected !== rowId); this.selected = [...selected]; } this.fwSelectionChange.emit({ rowId: rowId, checked: checked, selected: this.selected, }); return this.selected; } /** * selectAllRows method we can use to select/unselect rows in the table * @param checked denotes if we want to check or uncheck the rows */ async selectAllRows(checked = true) { if (checked === true) { const newlySelected = this.rows .filter((row) => !this.selected.includes(row.id)) .map((filteredRow) => { return filteredRow.id; }); this.selected = [...this.selected, ...newlySelected]; } else { this.selected = []; } this.fwSelectAllChange.emit({ checked: checked, selected: this.selected, }); return this.selected; } /** * getSelectedRows * @returns selected rows from the data table */ async getSelectedRows() { return this.rows.filter((row) => this.selected.includes(row.id)); } /** * getSelectedIds * @returns an array of selected row IDs */ async getSelectedIds() { return this.selected; } /** * getTableSettings * @returns columnConfig object */ async getTableSettings() { const columnConfig = {}; this.orderedColumns.map((column) => { if (!columnConfig[column.key]) { columnConfig[column.key] = {}; } columnConfig[column.key].position = column.position; columnConfig[column.key].hide = column.hide || false; columnConfig[column.key].lock = column.lock || false; }); return columnConfig; } /** * setTableSettings * @param columnConfig columnConfig object */ async setTableSettings(columnConfig) { try { let orderedColumns = [...this.orderedColumns]; for (const key in columnConfig) { if (Object.prototype.hasOwnProperty.call(columnConfig, key)) { const config = columnConfig[key]; const modifiedOrderColumn = this.getColumnsState(orderedColumns, key, config); orderedColumns = modifiedOrderColumn; } } this.orderedColumns = [...orderedColumns]; } catch (error) { console.warn('Save table settings was not applied'); } return this.orderedColumns; } /** * loadTable - Method to call when we want to change table loading state * @param state to load table or not * @returns isLoading current state */ async loadTable(state = true) { this.isLoading = state; return this.isLoading; } /** * hideShimmer */ hideShimmer() { if (this.showShimmer) { this.showShimmer = false; } } /** * Private * getColumnsState function to call when updating a column state. * Updating state using this function can help update the UI easily. * @param state current state to modify * @param stateKey key that can help identify what object in state to identify * @param keyValuePairs key value pair to modify the object * @returns modifies state object */ getColumnsState(state, stateKey, keyValuePairs) { const currentElementIndex = state.findIndex((stateElement) => stateElement.key === stateKey); const currentElement = state[currentElementIndex]; const modifiedCurrentElement = Object.assign(Object.assign({}, currentElement), keyValuePairs); const otherElements = state.filter((stateElement) => stateElement.key !== stateKey); const preElements = otherElements.slice(0, currentElementIndex); const postElements = otherElements.slice(currentElementIndex, otherElements.length); if (modifiedCurrentElement.position !== currentElement.position) { for (let index = 0; index < preElements.length; index++) { const preElement = preElements[index]; if (preElement.position >= modifiedCurrentElement.position && preElement.position <= currentElement.position) { preElement.position = preElement.position + 1; } } for (let index = 0; index < postElements.length; index++) { const postElement = postElements[index]; if (postElement.position <= modifiedCurrentElement.position && postElement.position >= currentElement.position) { postElement.position = postElement.position - 1; } } } const newStateOrder = [ ...preElements, modifiedCurrentElement, ...postElements, ].sort((a, b) => a.position - b.position); return newStateOrder; } /** * Private * lockFocusInside lock the focus inside modal overlay */ lockFocusInsideSettings() { const resetFocus = (event) => { event.stopPropagation(); if (event.shiftKey === false && event.key === 'Tab') { this.settingsResetButton.focus(); } }; const updateFocus = (event) => { event.stopPropagation(); if (event.shiftKey === true && event.key === 'Tab') { this.settingsUpdateButton.setFocus(); } }; this.settingsUpdateButton.addEventListener('keydown', resetFocus); this.settingsResetButton.addEventListener('keydown', updateFocus); } /** * Private * toggleSettings * @param isOpen opens/closes the table * @return isOpen current open/close state */ async toggleSettings(isOpen = true) { await this.resetSettings(); this.isSettingsOpen = isOpen; await this.waitForNextRender(); this.popperInstance.update(); if (isOpen) { this.settingsInput.setFocus(); this.lockFocusInsideSettings(); } return isOpen; } /** * resetSettings function to reset the temporary column state in settings using table column state. */ async resetSettings() { this.settingSearchText = ''; this.settingsInput.value = ''; this.columnsDragSetting = []; this.columnsHideSetting = []; const modifiedColumnsDragSettings = this.orderedColumns.map((column) => { const columnInfo = {}; columnInfo.key = column.key; columnInfo.text = column.text; columnInfo.position = column.position; columnInfo.hide = column.hide || false; columnInfo.lock = column.lock; return columnInfo; }); this.columnsDragSetting = modifiedColumnsDragSettings; const modifiedColumnsHideSettings = this.columns.map((column) => { const columnInfo = {}; const orderedColumn = this.orderedColumns.filter((orderedColumn) => orderedColumn.key === column.key)[0]; columnInfo.key = column.key; columnInfo.text = column.text; columnInfo.hide = orderedColumn.hide; columnInfo.lock = orderedColumn.lock; return columnInfo; }); this.columnsHideSetting = modifiedColumnsHideSettings; } /** * applySettings function to apply temporary column state in settings to tables column state */ async applySettings() { this.columnsDragSetting.forEach((currentSetting) => { const newColumnState = this.getColumnsState(this.orderedColumns, currentSetting.key, { hide: currentSetting.hide, position: currentSetting.position, }); this.orderedColumns = [...newColumnState]; }); if (localStorage && this.autoSaveSettings) { try { const tableId = this.el.id ? `-${this.el.id}` : null; if (tableId) { const columnConfig = await this.getTableSettings(); localStorage.setItem(`fw-table${tableId}`, JSON.stringify(columnConfig)); } else { throw new Error("Table must have an 'id' attribute to autosave settings"); } } catch (error) { console.log(error.message); } } this.toggleSettings(false); this.ifAutoCalculatedWidth = false; } /** * arrowNavigation function that helps with table navigation * @param event event that triggers navigation inside table */ arrowNavigate(event) { const currentElement = this.getEventPath(event)[0]; const currentCell = this.closestTableCell(this.getEventPath(event)); if (currentCell) { let cellFocusChange = false; // Switch focus between components inside a cell if (currentElement !== currentCell) { cellFocusChange = this.arrowNavigateCellComponents(event.code, currentElement); } else { cellFocusChange = true; } // Switch focus between cells if (cellFocusChange) { this.arrowNavigateCell(event.code, currentCell); } } } /** * arrowNavigateCellComponents Navigate between components in a cell * @param eventCode code for the keyboard event * @param currentElement current element the focus is on * @returns cellFocusChange boolean tells if this a navigation between cells */ arrowNavigateCellComponents(eventCode, currentElement) { var _a, _b, _c, _d, _e; let cellFocusChange = false; let nextFocusElement = null; switch (eventCode) { case 'ArrowRight': if (currentElement.parentElement.nodeName === 'FW-TOOLTIP') { if (currentElement.parentElement.nextElementSibling) { if ((_a = currentElement.parentElement.nextElementSibling.children[0]) === null || _a === void 0 ? void 0 : _a.getAttribute('tabindex')) { nextFocusElement = currentElement.parentElement.nextElementSibling.children[0]; } } else { cellFocusChange = true; } } else if ((_b = currentElement.nextElementSibling) === null || _b === void 0 ? void 0 : _b.getAttribute('tabIndex')) { nextFocusElement = currentElement.nextElementSibling; } else { cellFocusChange = true; } break; case 'ArrowLeft': if (currentElement.parentElement.nodeName === 'FW-TOOLTIP') { if ((_c = currentElement.parentElement.previousElementSibling) === null || _c === void 0 ? void 0 : _c.getAttribute('tabIndex')) { if ((_d = currentElement.parentElement.previousElementSibling.children[0]) === null || _d === void 0 ? void 0 : _d.getAttribute('tabindex')) { nextFocusElement = currentElement.parentElement.previousElementSibling.children[0]; } } else { cellFocusChange = true; } } else if ((_e = currentElement.previousElementSibling) === null || _e === void 0 ? void 0 : _e.getAttribute('tabIndex')) { nextFocusElement = currentElement.previousElementSibling; } else { cellFocusChange = true; } break; default: cellFocusChange = true; break; } if (nextFocusElement) { nextFocusElement.setAttribute('tabIndex', '0'); nextFocusElement.focus(); } return cellFocusChange; } /** * arrowNavigateCell navigate between table cells * @param eventCode code for the keyboard event * @param currentCell current cell the focus is on */ arrowNavigateCell(eventCode, currentCell) { let currentRowIndex = +currentCell.parentElement.getAttribute('aria-rowIndex'); let currentColIndex = +currentCell.getAttribute('aria-colIndex'); let nextRowIndex; let nextColIndex; let columnLength = this.orderedColumns.length; columnLength = this.isSelectable ? columnLength + 1 : columnLength; columnLength = this.rowActions.length ? columnLength + 1 : columnLength; switch (eventCode) { case 'ArrowDown': nextRowIndex = currentRowIndex + 1; nextColIndex = currentColIndex; break; case 'ArrowUp': nextRowIndex = currentRowIndex - 1; nextColIndex = currentColIndex; break; case 'ArrowRight': { const getNextCellIndex = (currentRowIndex, currentColIndex) => { if (currentColIndex !== columnLength) { nextRowIndex = currentRowIndex; nextColIndex = currentColIndex + 1; } else { nextRowIndex = currentRowIndex + 1; nextColIndex = 1; } return { nextRowIndex, nextColIndex }; }; let currentColumnHidden = false; do { const nextCellIndex = getNextCellIndex(currentRowIndex, currentColIndex); const currentColumn = this.tableContainer.querySelector(`th[aria-colIndex="${nextColIndex}"]`); currentColumnHidden = currentColumn.classList.contains('hidden'); if (currentColumnHidden) { currentRowIndex = nextCellIndex.nextRowIndex; currentColIndex = nextCellIndex.nextColIndex; } else { nextRowIndex = nextCellIndex.nextRowIndex; nextColIndex = nextCellIndex.nextColIndex; } } while (currentColumnHidden); // Loop till next visible column } break; case 'ArrowLeft': { const getPreviousCellIndex = (currentRowIndex, currentColIndex) => { if (currentColIndex !== 1) { nextRowIndex = currentRowIndex; nextColIndex = currentColIndex - 1; } else { nextRowIndex = currentRowIndex - 1; nextColIndex = columnLength; } return { nextRowIndex, nextColIndex }; }; let currentColumnHidden = false; do { const previousCellIndex = getPreviousCellIndex(currentRowIndex, currentColIndex); const currentColumn = this.tableContainer.querySelector(`th[aria-colIndex="${nextColIndex}"]`); currentColumnHidden = currentColumn.classList.contains('hidden'); if (currentColumnHidden) { currentRowIndex = previousCellIndex.nextRowIndex; currentColIndex = previousCellIndex.nextColIndex; } else { nextRowIndex = previousCellIndex.nextRowIndex; nextColIndex = previousCellIndex.nextColIndex; } } while (currentColumnHidden); // Loop till next visible column } break; } const nextCell = this.tableContainer.querySelector(`[aria-rowIndex="${nextRowIndex}"] > [aria-colIndex="${nextColIndex}"]`); if (nextCell) { this.removeFocusCell(currentCell); this.focusCell(nextCell, eventCode); } } /** * get event's path which is an array of the objects * event.path unsupported in safari */ getEventPath(event) { return event.path ? event.path : event.composedPath(); } /** * WorkAround for wait until next render in stenciljs * https://github.com/ionic-team/stencil/issues/2744 */ waitForNextRender() { return new Promise((resolve) => (this.renderPromiseResolve = resolve)); } /** * Function to call when removing the focus of a table cell * @param cell table cell */ removeFocusCell(cell) { cell.setAttribute('tabIndex', '-1'); } /** * Function to call when focusing a table cell * @param cell table cell * @param direction key direction when focus comes into cell */ focusCell(cell, direction = 'ArrowRight') { if (cell.dataset.hasFocusableChild && cell.dataset.hasFocusableChild === 'true') { cell.removeAttribute('tabIndex'); let childElement = null; switch (direction) { case 'ArrowLeft': childElement = cell.children[cell.children.length - 1]; break; default: childElement = cell.children[0]; break; } if (childElement.nodeName === 'FW-TOOLTIP') { childElement = childElement.children[0]; } childElement.setAttribute('tabIndex', '0'); childElement.focus(); } else { cell.setAttribute('tabIndex', '0'); cell.focus(); } } /** * hasFocusableComponent - determines if a cell has focusable component * @param column column information * @returns {boolean} hasFocusableComponent */ hasFocusableComponent(column) { let hasFocusableComponent = false; if (column.hasFocusableComponent) { hasFocusableComponent = true; } else if (column.variant && PREDEFINED_VARIANTS_META[column.variant].isFocusable) { hasFocusableComponent = true; } return hasFocusableComponent; } /** * private * closestTableCell Find the closest table cell from the path of the event * @param eventPath Event path from the emitted event * @returns closest table cell */ closestTableCell(eventPath) { let closestCell; for (let i = 0; i < eventPath.length; i++) { const element = eventPath[i]; if (element.nodeName === 'TD') { closestCell = element; break; } } return closestCell; } /** * columnOrdering Sorting columns based on position to show columns in the right order visually. * @param columns */ columnOrdering(columns) { this.orderedColumns = [...columns].sort((column1, column2) => { let result = 0; if (column1.lock && !column2.lock) { result = -1; } else if (!column1.lock && column2.lock) { result = 1; } else if ((!column1.lock && !column2.lock) || (column1.lock && column2.lock)) { if (column1.position && column2.position) { result = column1.position - column2.position; } else if (column1.position && !column2.position) { result = -1; } else if (!column1.position && column2.position) { result = 1; } } return result; }); // To add correct position to ordered columns array this.orderedColumns.map((column, index) => { column.position = index + 1; }); } /** * performRowAction * @param action action object - has information related to the action to be performed * @param rowData rowData - complete data of the current row */ async performRowAction(action, rowData) { const selectAll = this.el.shadowRoot.querySelector('fw-checkbox#select-all'); if (selectAll && !selectAll.disabled) { selectAll.disabled = true; } this.rowsLoading = Object.assign(Object.assign({}, this.rowsLoading), { [rowData.id]: true }); try { await action.handler(rowData); } catch (error) { console.log(error.message); } delete this.rowsLoading[rowData.id]; this.rowsLoading = Object.assign({}, this.rowsLoading); if (selectAll && Object.keys(this.rowsLoading).length === 0) { selectAll.disabled = false; } } /** * Settings search handler * @param searchText text to search for in columns list */ settingsSearch(searchText) { this.settingSearchText = searchText.toLowerCase(); } /** * Settings checkbox handler * @param columnKey table column key * @param checked value for checked * @param event event that is triggering this action */ async settingsColumnToggle(columnKey, checked, event) { let changePair; if (checked) { let lastCheckedPosition = 1; this.columnsDragSetting.forEach((column, columnIndex) => !column.hide && (lastCheckedPosition = columnIndex + 1)); changePair = { hide: !checked, position: lastCheckedPosition + 1 }; } else { if (this.disabledColumnHide) { if (event) { event.currentTarget.checked = true; } return; } const position = this.columnsDragSetting.length; changePair = { hide: !checked, position: position }; } const newColumnDragState = this.getColumnsState(this.columnsDragSetting, columnKey, changePair); const newColumnHideState = this.getColumnsState(this.columnsHideSetting, columnKey, { hide: !checked }); this.columnsDragSetting = [...newColumnDragState]; this.columnsHideSetting = [...newColumnHideState]; if (event) { if (event.currentTarget.classList.contains('table-settings-drag-item-close') && event.key === 'Enter') { const previousDragItem = event.currentTarget .parentElement.previousSibling; const nextDragItem = event.currentTarget.parentElement .nextSibling; await this.waitForNextRender(); if (previousDragItem || nextDragItem) { const focusItem = (previousDragItem || nextDragItem).querySelector('.table-settings-drag-item-close'); focusItem.focus(); } else { const focusItem = this.tableContainer.querySelector('.table-settings-content-checkboxes div:last-child fw-checkbox'); focusItem.focus(); } } } this.disabledColumnHide = this.columnsHideSetting.filter((column) => !column.hide).length === 1; return this.columnsDragSetting; } /** * settingsColumnDrop * @param columnKey table column key * @param droppedIndex value for position */ async settingsColumnDrop(columnKey, droppedIndex) { const lockedColumnsLength = this.columnsDragSetting.filter((column) => column.lock).length; const newColumnState = this.getColumnsState(this.columnsDragSetting, columnKey, { position: droppedIndex + 1 + lockedColumnsLength, }); this.columnsDragSetting = [...newColumnState]; return newColumnState; } /** * private * @returns {JSX.Element} returns jsx for a webcomponent */ renderWebComponent(componentName, props) { let template; if (window.customElements.get(componentName)) { const WebComponentTag = `${componentName}`; let slotText; if (props.slotText) { slotText = props.slotText; delete props.slotText; } template = h(WebComponentTag, Object.assign({}, props), slotText); } else { template = null; } return template; } /** * private * @returns {JSX.Element} returns jsx for a custom HTML template */ renderCustomTemplate(customTemplate, cellValue) { return customTemplate(h, cellValue); } /** * private * @returns {JSX.Element} returns jsx from a predefined set of components */ renderPredefinedVariant(columnVariant, cellValue) { let template; if (columnVariant === 'anchor') { template = h("fw-custom-cell-anchor", Object.assign({}, cellValue)); } else if (columnVariant === 'user') { template = h("fw-custom-cell-user", Object.assign({}, cellValue)); } else if (columnVariant === 'icon') { template = h("fw-custom-cell-icon", Object.assign({}, cellValue)); } else if (columnVariant === 'paragraph') { template = (h("fw-custom-cell-paragraph", Object.assign({}, cellValue))); } else { template = null; } return template; } /** * private * @returns {JSX.Element} table body cell */ renderTableCell(column, cellValue) { let template; if (column.variant) { template = this.renderPredefinedVariant(column.variant, cellValue); } else if (column.customTemplate) { template = this.renderCustomTemplate(column.customTemplate, cellValue); } else { template = column.formatData ? column.formatData(cellValue) : cellValue; } return template; } /** * private * @returns {JSX.Element} table header row */ renderTableHeader() { var _a; const selectAllChecked = this.rows.length && this.rows.every((row) => this.selected.includes(row.id)); const visibleColumns = this.orderedColumns.filter((column) => !column.hide && column.variant !== 'paragraph'); const lastVisibleColumnKey = (_a = visibleColumns[visibleColumns.length - 1]) === null || _a === void 0 ? void 0 : _a.key; return this.orderedColumns.filter((column) => !column.hide).length ? (h("tr", { role: 'row' }, this.orderedColumns.length && this.isSelectable && (h("th", { ref: (el) => (this.selectColumnHeader = el), key: 'isSelectable', "aria-colindex": 1, style: { width: '40px' } }, this.isAllSelectable && (h("fw-checkbox", { id: 'select-all', value: 'select-all', checked: selectAllChecked, onFwChange: (event) => { var _a, _b; return this.selectAllRows((_b = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.checked); } })))), this.orderedColumns.map((column, columnIndex) => { let textAlign = null; if (column.textAlign && !(column.variant && PREDEFINED_VARIANTS_META[column.variant].skipTextAlign)) { textAlign = column.textAlign; } const headerStyles = Object.assign({}, column.widthProperties && !(column.key === lastVisibleColumnKey && this.ifAutoCalculatedWidth) ? column.widthProperties : {}, textAlign ? { textAlign } : {}); const optionalAttrs = {}; if (column.key === lastVisibleColumnKey) { optionalAttrs.ref = (el) => (this.lastColumnHeader = el); } return (h("th", Object.assign({ role: 'columnheader', key: column.key, "aria-colindex": this.isSelectable ? columnIndex + 2 : columnIndex + 1, class: { hidden: column.hide }, style: headerStyles }, optionalAttrs), column.customHeader ? this.renderCustomTemplate(column.customHeader, column.text) : column.text)); }), this.rowActions.length !== 0 && (h("th", { class: 'row-actions', role: 'columnheader', "aria-colindex": this.isSelectable ? this.orderedColumns.length + 2 : this.orderedColumns.length + 1 }, TranslationController.t('datatable.actions'))))) : null; } /** * private * @returns table body rows */ renderTableBody(