UNPKG

@hashicorp/design-system-components

Version:
603 lines (585 loc) 28.7 kB
import Component from '@glimmer/component'; import { action } from '@ember/object'; import { assert } from '@ember/debug'; import { tracked } from '@glimmer/tracking'; import { guidFor } from '@ember/object/internals'; import { service } from '@ember/service'; import { modifier } from 'ember-modifier'; import HdsAdvancedTableTableModel from './models/table.js'; import { HdsAdvancedTableDensityValues, HdsAdvancedTableVerticalAlignmentValues } from './types.js'; import { precompileTemplate } from '@ember/template-compilation'; import { g, i, n } from 'decorator-transforms/runtime'; import { setComponentTemplate } from '@ember/component'; var TEMPLATE = precompileTemplate("{{!\n Copyright (c) HashiCorp, Inc.\n SPDX-License-Identifier: MPL-2.0\n}}\n\n<div\n class=\"hds-advanced-table__container\n {{(if this.isStickyHeaderPinned \'hds-advanced-table__container--header-is-pinned\')}}\"\n {{did-update this.setupTableModelData @columns @model @sortBy @sortOrder}}\n {{did-update this.updateTableModelColumnOrder @columnOrder}}\n ...attributes\n>\n {{! Caption }}\n <div id={{this._captionId}} class=\"sr-only hds-advanced-table__caption\" aria-live=\"polite\">\n {{@caption}}\n {{this.sortedMessageText}}\n {{this.reorderedMessageText}}\n </div>\n\n {{! Grid }}\n <div\n class={{this.classNames}}\n role=\"grid\"\n aria-describedby={{this._captionId}}\n {{style\n grid-template-columns=this.gridTemplateColumns\n --hds-advanced-table-sticky-column-offset=this.stickyColumnOffset\n max-height=@maxHeight\n }}\n {{this._registerGridElement}}\n {{this._setUpScrollWrapper}}\n >\n {{! Header }}\n <div\n class={{this.theadClassNames}}\n role=\"rowgroup\"\n {{this._setUpThead}}\n {{on \"dragleave\" (fn (mut this._tableModel.reorderHoveredColumn) null)}}\n >\n <Hds::AdvancedTable::Tr\n @selectionScope=\"col\"\n @onClickSortBySelected={{if @selectableColumnKey (fn this._tableModel.setSortBy @selectableColumnKey)}}\n @sortBySelectedOrder={{if (eq this._tableModel.sortBy @selectableColumnKey) this._tableModel.sortOrder}}\n @isSelectable={{this.isSelectable}}\n @onSelectionChange={{this.onSelectionAllChange}}\n @didInsert={{this.didInsertSelectAllCheckbox}}\n @willDestroy={{this.willDestroySelectAllCheckbox}}\n @selectionAriaLabelSuffix=\"all rows\"\n @hasStickyColumn={{this.hasStickyFirstColumn}}\n @isStickyColumnPinned={{this.isStickyColumnPinned}}\n >\n {{#each this._tableModel.orderedColumns as |column|}}\n {{#if column.isSortable}}\n <Hds::AdvancedTable::ThSort\n @column={{column}}\n @sortOrder={{if (eq column.key this._tableModel.sortBy) this._tableModel.sortOrder}}\n @onClickSort={{if column.key (fn this._tableModel.setSortBy column.key)}}\n @align={{column.align}}\n @tooltip={{column.tooltip}}\n @hasReorderableColumns={{@hasReorderableColumns}}\n @hasResizableColumns={{@hasResizableColumns}}\n @hasSelectableRows={{this.isSelectable}}\n @isStickyColumn={{this._isStickyColumn column}}\n @isStickyColumnPinned={{this.isStickyColumnPinned}}\n @tableHeight={{this._tableHeight}}\n @onColumnResize={{@onColumnResize}}\n @onPinFirstColumn={{this._onPinFirstColumn}}\n @onReorderDragEnd={{fn (mut this._tableModel.reorderDraggedColumn) null}}\n @onReorderDragStart={{fn (mut this._tableModel.reorderDraggedColumn)}}\n @onReorderDrop={{this._tableModel.moveColumnToDropTarget}}\n {{this._registerThElement column}}\n >\n {{column.label}}\n </Hds::AdvancedTable::ThSort>\n {{else}}\n <Hds::AdvancedTable::Th\n @align={{column.align}}\n @column={{column}}\n @hasExpandAllButton={{this._tableModel.hasRowsWithChildren}}\n @hasReorderableColumns={{@hasReorderableColumns}}\n @hasResizableColumns={{@hasResizableColumns}}\n @hasSelectableRows={{this.isSelectable}}\n @isExpanded={{this._tableModel.expandState}}\n @isExpandable={{column.isExpandable}}\n @isStickyColumn={{this._isStickyColumn column}}\n @isStickyColumnPinned={{this.isStickyColumnPinned}}\n @tableHeight={{this._tableHeight}}\n @tooltip={{column.tooltip}}\n @onClickToggle={{this._tableModel.toggleAll}}\n @onColumnResize={{@onColumnResize}}\n @onPinFirstColumn={{this._onPinFirstColumn}}\n @onReorderDragEnd={{fn (mut this._tableModel.reorderDraggedColumn) null}}\n @onReorderDragStart={{fn (mut this._tableModel.reorderDraggedColumn)}}\n @onReorderDrop={{this._tableModel.moveColumnToDropTarget}}\n {{this._registerThElement column}}\n >\n {{column.label}}\n </Hds::AdvancedTable::Th>\n {{/if}}\n {{/each}}\n </Hds::AdvancedTable::Tr>\n\n {{#if this.showScrollIndicatorTop}}\n <div class=\"hds-advanced-table__scroll-indicator hds-advanced-table__scroll-indicator-top\" />\n {{/if}}\n </div>\n\n {{! Body }}\n <div class=\"hds-advanced-table__tbody\" role=\"rowgroup\">\n {{! ----------------------------------------------------------------------------------------\n IMPORTANT: we loop on the `model` array and for each record\n we yield the Tr/Td/Th elements _and_ the record itself as `data`\n this means the consumer will *have to* use the `data` key to access it in their template\n -------------------------------------------------------------------------------------------- }}\n {{#each this._tableModel.sortedRows key=this.identityKey as |record index|}}\n {{#if this._tableModel.hasRowsWithChildren}}\n <Hds::AdvancedTable::ExpandableTrGroup\n @record={{record}}\n @rowIndex={{index}}\n @onClickToggle={{record.onClickToggle}}\n as |T|\n >\n {{yield\n (hash\n Tr=(component\n \"hds/advanced-table/tr\"\n isLastRow=(eq this._tableModel.lastVisibleRow.id T.data.id)\n isParentRow=T.isExpandable\n depth=T.depth\n displayRow=T.shouldDisplayChildRows\n data=T.data\n )\n Th=(component\n \"hds/advanced-table/th\"\n depth=T.depth\n isExpandable=T.isExpandable\n isExpanded=T.isExpanded\n newLabel=T.id\n parentId=T.parentId\n scope=\"row\"\n onClickToggle=T.onClickToggle\n )\n Td=(component \"hds/advanced-table/td\" align=@align)\n data=T.data\n isOpen=T.isExpanded\n rowIndex=T.rowIndex\n )\n to=\"body\"\n }}\n </Hds::AdvancedTable::ExpandableTrGroup>\n {{else}}\n {{yield\n (hash\n Tr=(component\n \"hds/advanced-table/tr\"\n selectionScope=\"row\"\n isLastRow=(eq this._tableModel.lastVisibleRow.id record.id)\n isSelectable=this.isSelectable\n onSelectionChange=this.onSelectionRowChange\n didInsert=this.didInsertRowCheckbox\n willDestroy=this.willDestroyRowCheckbox\n selectionAriaLabelSuffix=@selectionAriaLabelSuffix\n hasStickyColumn=this.hasStickyFirstColumn\n isStickyColumnPinned=this.isStickyColumnPinned\n data=record\n )\n Th=(component\n \"hds/advanced-table/th\"\n scope=\"row\"\n isStickyColumn=this.hasStickyFirstColumn\n isStickyColumnPinned=this.isStickyColumnPinned\n )\n Td=(component \"hds/advanced-table/td\" align=@align)\n data=record\n rowIndex=index\n )\n to=\"body\"\n }}\n {{/if}}\n {{/each}}\n </div>\n </div>\n\n {{#if this.showScrollIndicatorLeft}}\n <div\n class=\"hds-advanced-table__scroll-indicator hds-advanced-table__scroll-indicator-left\"\n {{style height=this.scrollIndicatorDimensions.height left=this.scrollIndicatorDimensions.left}}\n />\n {{/if}}\n\n {{#if this.showScrollIndicatorRight}}\n <div\n class=\"hds-advanced-table__scroll-indicator hds-advanced-table__scroll-indicator-right\"\n {{style height=this.scrollIndicatorDimensions.height right=this.scrollIndicatorDimensions.right}}\n />\n {{/if}}\n\n {{#if this.showScrollIndicatorBottom}}\n <div\n class=\"hds-advanced-table__scroll-indicator hds-advanced-table__scroll-indicator-bottom\"\n {{style bottom=this.scrollIndicatorDimensions.bottom width=this.scrollIndicatorDimensions.width}}\n />\n {{/if}}\n</div>"); /** * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ const DENSITIES = Object.values(HdsAdvancedTableDensityValues); const DEFAULT_DENSITY = HdsAdvancedTableDensityValues.Medium; const VALIGNMENTS = Object.values(HdsAdvancedTableVerticalAlignmentValues); const DEFAULT_VALIGN = HdsAdvancedTableVerticalAlignmentValues.Top; const BORDER_WIDTH = 1; const DEFAULT_SCROLL_DIMENSIONS = { bottom: '0px', height: '0px', left: '0px', right: '0px', width: '0px' }; const getScrollIndicatorDimensions = (scrollWrapper, theadElement, hasStickyFirstColumn, hasFirstColumnPxWidth, isStickyColumnPinned) => { const horizontalScrollBarHeight = scrollWrapper.offsetHeight - scrollWrapper.clientHeight; const verticalScrollBarWidth = scrollWrapper.offsetWidth - scrollWrapper.clientWidth; let leftOffset = 0; if (hasStickyFirstColumn) { const stickyColumnHeaders = theadElement.querySelectorAll('.hds-advanced-table__th--is-sticky-column'); stickyColumnHeaders?.forEach(el => { // querySelectorAll returns Elements, which don't have offsetWidth // need to use offsetWidth to account for the cell borders const elAsHTMLElement = el; leftOffset += elAsHTMLElement.offsetWidth; }); // offsets the left: -1px position if there are multiple sticky columns or the first column has a fixed pixel width if (stickyColumnHeaders.length > 1 || hasFirstColumnPxWidth) { leftOffset -= 1; } // offsets the left: -1px position if the sticky column is already pinned when the scroll indicator is calculated if (isStickyColumnPinned) { leftOffset -= 1; } } return { bottom: `${horizontalScrollBarHeight}px`, height: `${scrollWrapper.offsetHeight - horizontalScrollBarHeight}px`, left: `${leftOffset}px`, right: `${verticalScrollBarWidth}px`, width: `${scrollWrapper.offsetWidth - verticalScrollBarWidth}px` }; }; const getStickyColumnLeftOffset = (theadElement, hasRowSelection, isStickyColumnPinned) => { // if there is no select checkbox column, the sticky column is all the way to the left if (!hasRowSelection) return '0px'; const selectableCell = theadElement.querySelector('.hds-advanced-table__th--is-selectable'); let leftOffset = selectableCell?.offsetWidth ?? 0; // if the sticky column is pinned when the offset is calculated, we need to account for the increased width of the border if (isStickyColumnPinned && leftOffset > 0) { leftOffset -= 2; } return `${leftOffset}px`; }; class HdsAdvancedTable extends Component { static { g(this.prototype, "hdsIntl", [service]); } #hdsIntl = (i(this, "hdsIntl"), void 0); static { g(this.prototype, "_selectAllCheckbox", [tracked], function () { return undefined; }); } #_selectAllCheckbox = (i(this, "_selectAllCheckbox"), void 0); static { g(this.prototype, "_isSelectAllCheckboxSelected", [tracked], function () { return undefined; }); } #_isSelectAllCheckboxSelected = (i(this, "_isSelectAllCheckboxSelected"), void 0); static { g(this.prototype, "_tableHeight", [tracked], function () { return 0; }); } #_tableHeight = (i(this, "_tableHeight"), void 0); _selectableRows = []; _captionId = 'caption-' + guidFor(this); _tableModel; _scrollHandler; _resizeObserver; _theadElement; _scrollWrapperElement; static { g(this.prototype, "scrollIndicatorDimensions", [tracked], function () { return DEFAULT_SCROLL_DIMENSIONS; }); } #scrollIndicatorDimensions = (i(this, "scrollIndicatorDimensions"), void 0); static { g(this.prototype, "isStickyColumnPinned", [tracked], function () { return false; }); } #isStickyColumnPinned = (i(this, "isStickyColumnPinned"), void 0); static { g(this.prototype, "isStickyHeaderPinned", [tracked], function () { return false; }); } #isStickyHeaderPinned = (i(this, "isStickyHeaderPinned"), void 0); static { g(this.prototype, "hasPinnedFirstColumn", [tracked], function () { return undefined; }); } #hasPinnedFirstColumn = (i(this, "hasPinnedFirstColumn"), void 0); static { g(this.prototype, "reorderedMessageText", [tracked], function () { return ''; }); } #reorderedMessageText = (i(this, "reorderedMessageText"), void 0); static { g(this.prototype, "showScrollIndicatorLeft", [tracked], function () { return false; }); } #showScrollIndicatorLeft = (i(this, "showScrollIndicatorLeft"), void 0); static { g(this.prototype, "showScrollIndicatorRight", [tracked], function () { return false; }); } #showScrollIndicatorRight = (i(this, "showScrollIndicatorRight"), void 0); static { g(this.prototype, "showScrollIndicatorTop", [tracked], function () { return false; }); } #showScrollIndicatorTop = (i(this, "showScrollIndicatorTop"), void 0); static { g(this.prototype, "showScrollIndicatorBottom", [tracked], function () { return false; }); } #showScrollIndicatorBottom = (i(this, "showScrollIndicatorBottom"), void 0); static { g(this.prototype, "stickyColumnOffset", [tracked], function () { return '0px'; }); } #stickyColumnOffset = (i(this, "stickyColumnOffset"), void 0); constructor(owner, args) { super(owner, args); const { model, columns, columnOrder, childrenKey, hasReorderableColumns, hasResizableColumns, sortBy, sortOrder, hasStickyFirstColumn, onSort } = args; this._tableModel = new HdsAdvancedTableTableModel({ model, columns, columnOrder, childrenKey, hasReorderableColumns, hasResizableColumns, sortBy, sortOrder, onColumnReorder: this._onColumnReorder.bind(this), onSort }); this._runAssertions(); if (hasStickyFirstColumn) { this.hasPinnedFirstColumn = true; } } get identityKey() { // we have to provide a way for the consumer to pass undefined because Ember tries to interpret undefined as missing an arg and therefore falls back to the default if (this.args.identityKey === 'none') { return undefined; } else { return this.args.identityKey ?? '@identity'; } } get childrenKey() { const { childrenKey = 'children' } = this.args; return childrenKey; } get hasStickyFirstColumn() { // The user-controlled `hasPinnedFirstColumn` variable takes precedence over the model's `hasStickyFirstColumn` property. if (this.hasPinnedFirstColumn !== undefined) { return this.hasPinnedFirstColumn; } else if (this.args.hasStickyFirstColumn === false) { return this.args.hasStickyFirstColumn; } return undefined; } get hasScrollIndicator() { if (this.hasStickyFirstColumn) { return true; } return false; } get sortedMessageText() { const { sortedMessageText } = this.args; const { sortBy, sortOrder } = this._tableModel; if (sortedMessageText !== undefined) { return sortedMessageText; } else if (sortBy !== undefined && sortOrder !== undefined) { // we should allow the user to define a custom value here (e.g., for i18n) - tracked with HDS-965 return `Sorted by ${sortBy} ${sortOrder}ending`; } else { return ''; } } get isSelectable() { const { isSelectable = false } = this.args; if (this._tableModel.hasRowsWithChildren) { assert('@isSelectable must not be true if there are nested rows.', !isSelectable); return isSelectable; } return isSelectable; } get isStriped() { const { isStriped = false } = this.args; if (this._tableModel.hasRowsWithChildren) { assert('@isStriped must not be true if there are nested rows.', !isStriped); return isStriped; } return isStriped; } get density() { const { density = DEFAULT_DENSITY } = this.args; assert(`@density for "Hds::Table" must be one of the following: ${DENSITIES.join(', ')}; received: ${density}`, DENSITIES.includes(density)); return density; } get hasStickyHeader() { if (this.args.maxHeight && this.args.hasStickyHeader !== false) { return true; } else if (this.args.hasStickyHeader && !this.args.maxHeight) { assert('Must set @maxHeight to use @hasStickyHeader.', false); } return false; } get valign() { const { valign = DEFAULT_VALIGN } = this.args; assert(`@valign for "Hds::Table" must be one of the following: ${VALIGNMENTS.join(', ')}; received: ${valign}`, VALIGNMENTS.includes(valign)); return valign; } // returns the grid-template-columns CSS attribute for the grid get gridTemplateColumns() { const { isSelectable } = this.args; const { orderedColumns } = this._tableModel; // if there is a select checkbox, the first column has a 'min-content' width to hug the checkbox content let style = isSelectable ? 'min-content ' : ''; for (let i = 0; i < orderedColumns.length; i++) { style += ` ${orderedColumns[i].appliedWidth}`; } return style; } get classNames() { const classes = ['hds-advanced-table']; if (this.isStriped) { classes.push('hds-advanced-table--striped'); } if (this.density) { classes.push(`hds-advanced-table--density-${this.density}`); } if (this.valign) { classes.push(`hds-advanced-table--valign-${this.valign}`); } if (this._tableModel.hasRowsWithChildren) { classes.push(`hds-advanced-table--nested`); } return classes.join(' '); } get theadClassNames() { const classes = ['hds-advanced-table__thead']; if (this.hasStickyHeader) { classes.push('hds-advanced-table__thead--sticky'); } if (this.isStickyHeaderPinned) { classes.push('hds-advanced-table__thead--is-pinned'); } if (this._tableModel.hasResizableColumns) { classes.push('hds-advanced-table__thead--has-resizable-columns'); } return classes.join(' '); } _registerGridElement = modifier(element => { this._tableModel.gridElement = element; }); _registerThElement = modifier((element, [column]) => { if (column === undefined) { return; } column.thElement = element; }); _setUpScrollWrapper = modifier(element => { this._scrollWrapperElement = element; const updateHorizontalScrollIndicators = () => { this.showScrollIndicatorRight = element.clientWidth < element.scrollWidth; }; this._scrollHandler = () => { this._updateScrollIndicators(element); }; element.addEventListener('scroll', this._scrollHandler); const updateMeasurements = () => { this._tableHeight = element.offsetHeight; const hasFirstColumnPxWidth = this._tableModel.columns[0]?.pxWidth !== undefined; this.scrollIndicatorDimensions = getScrollIndicatorDimensions(element, this._theadElement, this.hasStickyFirstColumn ? true : false, hasFirstColumnPxWidth, this.isStickyColumnPinned); if (this.hasStickyFirstColumn) { this.stickyColumnOffset = getStickyColumnLeftOffset(this._theadElement, isSelectable, this.isStickyColumnPinned); } }; const { isSelectable = false } = this.args; this._resizeObserver = new ResizeObserver(entries => { entries.forEach(() => { updateMeasurements(); updateHorizontalScrollIndicators(); }); }); this._resizeObserver.observe(element); updateMeasurements(); // on render check if should show right scroll indicator updateHorizontalScrollIndicators(); // on render check if should show bottom scroll indicator if (element.clientHeight < element.scrollHeight) { this.showScrollIndicatorBottom = true; } return () => { element.removeEventListener('scroll', this._scrollHandler); this._resizeObserver.disconnect(); }; }); _runAssertions() { const { columns, hasReorderableColumns, hasResizableColumns, hasStickyFirstColumn } = this.args; if (this._tableModel.hasRowsWithChildren) { const sortableColumns = columns.filter(column => column.isSortable); const sortableColumnLabels = sortableColumns.map(column => column.label); assert('Cannot have reorderable columns if there are nested rows.', !hasReorderableColumns); assert(`Cannot have sortable columns if there are nested rows. Sortable columns are ${sortableColumnLabels.toString()}`, sortableColumns.length === 0); assert('Cannot have a sticky first column if there are nested rows.', hasStickyFirstColumn === undefined); assert(`Cannot have resizable columns if there are nested rows.`, !hasResizableColumns); } if (hasReorderableColumns) { assert('Cannot have both reorderable columns and a sticky first column.', hasStickyFirstColumn === undefined); } } _setUpThead = modifier(element => { this._theadElement = element; }); _onColumnReorder = ({ column, newOrder, insertedAt }) => { const { reorderedMessageText } = this.args; if (reorderedMessageText !== undefined) { this.reorderedMessageText = reorderedMessageText; } else { const newPosition = insertedAt + 1; const translatedReorderedMessageText = this.hdsIntl.t('hds.advanced-table.reordered-message', { default: `Moved ${column.label} column to position ${newPosition}`, columnLabel: column.label, newPosition }); this.reorderedMessageText = translatedReorderedMessageText; } this.args.onColumnReorder?.({ column, newOrder, insertedAt }); }; onSelectionChangeCallback(checkbox, selectionKey) { const { onSelectionChange } = this.args; if (typeof onSelectionChange !== 'function') return; onSelectionChange({ selectionKey: selectionKey, selectionCheckboxElement: checkbox, selectedRowsKeys: this._selectableRows.reduce((acc, row) => { if (row.checkbox.checked) { acc.push(row.selectionKey); } return acc; }, []), selectableRowsStates: this._selectableRows.reduce((acc, row) => { acc.push({ selectionKey: row.selectionKey, isSelected: row.checkbox.checked }); return acc; }, []) }); } setupTableModelData() { const { columns, model, sortBy, sortOrder } = this.args; this._tableModel.setupData({ columns, model, sortBy, sortOrder }); } static { n(this.prototype, "setupTableModelData", [action]); } updateTableModelColumnOrder() { if (this.args.columnOrder === undefined) { return; } this._tableModel.columnOrder = this.args.columnOrder; } static { n(this.prototype, "updateTableModelColumnOrder", [action]); } onSelectionAllChange() { this._selectableRows.forEach(row => { row.checkbox.checked = this._selectAllCheckbox?.checked ?? false; }); this._isSelectAllCheckboxSelected = this._selectAllCheckbox?.checked ?? false; this.onSelectionChangeCallback(this._selectAllCheckbox, 'all'); } static { n(this.prototype, "onSelectionAllChange", [action]); } onSelectionRowChange(checkbox, selectionKey) { this.setSelectAllState(); this.onSelectionChangeCallback(checkbox, selectionKey); } static { n(this.prototype, "onSelectionRowChange", [action]); } didInsertSelectAllCheckbox(checkbox) { this._selectAllCheckbox = checkbox; } static { n(this.prototype, "didInsertSelectAllCheckbox", [action]); } willDestroySelectAllCheckbox() { this._selectAllCheckbox = undefined; } static { n(this.prototype, "willDestroySelectAllCheckbox", [action]); } didInsertRowCheckbox(checkbox, selectionKey) { if (selectionKey) { this._selectableRows.push({ selectionKey, checkbox }); } this.setSelectAllState(); } static { n(this.prototype, "didInsertRowCheckbox", [action]); } willDestroyRowCheckbox(selectionKey) { this._selectableRows = this._selectableRows.filter(row => row.selectionKey !== selectionKey); this.setSelectAllState(); } static { n(this.prototype, "willDestroyRowCheckbox", [action]); } setSelectAllState() { if (this._selectAllCheckbox) { const selectableRowsCount = this._selectableRows.length; const selectedRowsCount = this._selectableRows.filter(row => row.checkbox.checked).length; this._selectAllCheckbox.checked = selectedRowsCount === selectableRowsCount; this._selectAllCheckbox.indeterminate = selectedRowsCount > 0 && selectedRowsCount < selectableRowsCount; this._isSelectAllCheckboxSelected = this._selectAllCheckbox.checked; } } static { n(this.prototype, "setSelectAllState", [action]); } _updateScrollIndicators(element) { // 6px as a buffer so the shadow doesn't appear over the border radius on the edge of the table const SCROLL_BUFFER = 6; // left scroll indicator and sticky column styles if (element.scrollLeft > SCROLL_BUFFER) { if (this.hasStickyFirstColumn) { this.isStickyColumnPinned = true; } if (!this.showScrollIndicatorLeft) { this.showScrollIndicatorLeft = true; } } else if (element.scrollLeft === 0 && this.showScrollIndicatorLeft) { this.isStickyColumnPinned = false; this.showScrollIndicatorLeft = false; } // the right edge is how far the user can scroll, which is the full width of the table - the visible section of the table (also subtract the buffer) const rightEdge = element.scrollWidth - element.clientWidth - SCROLL_BUFFER; // right scroll indicator if (element.scrollLeft < rightEdge) { this.showScrollIndicatorRight = true; } else { this.showScrollIndicatorRight = false; } // sticky header if (element.scrollTop > 0) { if (this.hasStickyHeader) { this.isStickyHeaderPinned = true; } this.showScrollIndicatorTop = true; } else { if (this.hasStickyHeader) { this.isStickyHeaderPinned = false; } this.showScrollIndicatorTop = false; } // the bottom edge is how far the user can scroll, which is the full height of the table - the visible section of the table (also subtract the buffer) const bottomEdge = element.scrollHeight - element.clientHeight - SCROLL_BUFFER; // bottom scroll indicator if (element.scrollTop < bottomEdge) { this.showScrollIndicatorBottom = true; } else { this.showScrollIndicatorBottom = false; } } _onPinFirstColumn = () => { this.hasPinnedFirstColumn = this.hasPinnedFirstColumn ? false : true; // we need to retrigger the scroll indicator updates if the pinned state is changed when the table is already scrolled this._updateScrollIndicators(this._scrollWrapperElement); }; _isStickyColumn = column => { if (column.isFirst && this.hasStickyFirstColumn !== undefined) { return this.hasStickyFirstColumn; } return undefined; }; } setComponentTemplate(TEMPLATE, HdsAdvancedTable); export { BORDER_WIDTH, DEFAULT_DENSITY, DEFAULT_VALIGN, DENSITIES, VALIGNMENTS, HdsAdvancedTable as default }; //# sourceMappingURL=index.js.map