UNPKG

@digital-realty/grid

Version:

A free, flexible and high-quality Web Component for showing large amounts of tabular data

154 lines (132 loc) 5.46 kB
/** * @license * Copyright (c) 2016 - 2025 Vaadin Ltd. * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ */ import { addListener } from '@vaadin/component-base/src/gestures.js'; /** * @polymerMixin */ export const ColumnResizingMixin = (superClass) => class ColumnResizingMixin extends superClass { /** @protected */ async ready() { super.ready(); const scroller = this.$.scroller; addListener(scroller, 'track', this._onHeaderTrack.bind(this)); window.addEventListener('resize', this._onBreakPointResize.bind(this)); // Disallow scrolling while resizing scroller.addEventListener('touchmove', (e) => scroller.hasAttribute('column-resizing') && e.preventDefault()); // Disable contextmenu on any resize separator. scroller.addEventListener( 'contextmenu', (e) => e.target.getAttribute('part') === 'resize-handle' && e.preventDefault(), ); // Disable native cell focus when resizing scroller.addEventListener( 'mousedown', (e) => e.target.getAttribute('part') === 'resize-handle' && e.preventDefault(), ); // run once to set the initial responsive column widths setTimeout(() => { this._onBreakPointResize(); }, 0); } /** @private */ _onBreakPointResize(e) { this.$.scroller.toggleAttribute('column-resizing', true); const windowWidth = window.innerWidth; const columns = this.getElementsByTagName('vaadin-grid-column'); const responsiveColumns = Array.from(columns).filter((column) => column.responsive); responsiveColumns.forEach((column) => { const size = column.responsive.findLast(([width]) => parseInt(width) <= windowWidth); if (size) { column.width = size[1]; } else { column.width = column.minWidth; } column.flexGrow = 0; }); this.$.scroller.toggleAttribute('column-resizing', false); this._resizeHandler(); } /** @private */ _onHeaderTrack(e) { const handle = e.target; if (handle.getAttribute('part') === 'resize-handle') { const cell = handle.parentElement; let column = cell._column; this.$.scroller.toggleAttribute('column-resizing', true); // Get the target column to resize while (column.localName === 'vaadin-grid-column-group') { column = column._childColumns .slice(0) .sort((a, b) => a._order - b._order) .filter((column) => !column.hidden) .pop(); } const isRTL = this.__isRTL; const eventX = e.detail.x; const columnRowCells = Array.from(this.$.header.querySelectorAll('[part~="row"]:last-child [part~="cell"]')); const targetCell = columnRowCells.find((cell) => cell._column === column); // Resize the target column if (targetCell.offsetWidth) { const style = getComputedStyle(targetCell._content); const minWidth = (parseInt(column.minWidth) || 10) + parseInt(style.paddingLeft) + parseInt(style.paddingRight) + parseInt(style.borderLeftWidth) + parseInt(style.borderRightWidth) + parseInt(style.marginLeft) + parseInt(style.marginRight); let maxWidth; const cellWidth = targetCell.offsetWidth; const cellRect = targetCell.getBoundingClientRect(); // For cells frozen to end, resize handle is flipped horizontally. if (targetCell.hasAttribute('frozen-to-end')) { maxWidth = cellWidth + (isRTL ? eventX - cellRect.right : cellRect.left - eventX); } else { maxWidth = cellWidth + (isRTL ? cellRect.left - eventX : eventX - cellRect.right); } column.width = `${Math.max(minWidth, maxWidth)}px`; column.flexGrow = 0; } // Fix width and flex-grow for all preceding columns columnRowCells .sort((a, b) => a._column._order - b._column._order) .forEach((cell, index, array) => { if (index < array.indexOf(targetCell)) { cell._column.width = `${cell.offsetWidth}px`; cell._column.flexGrow = 0; } }); const cellFrozenToEnd = this._frozenToEndCells[0]; // When handle moves below the cell frozen to end, scroll into view. if (cellFrozenToEnd && this.$.table.scrollWidth > this.$.table.offsetWidth) { const frozenRect = cellFrozenToEnd.getBoundingClientRect(); const offset = eventX - (isRTL ? frozenRect.right : frozenRect.left); if ((isRTL && offset <= 0) || (!isRTL && offset >= 0)) { this.$.table.scrollLeft += offset; } } if (e.detail.state === 'end') { this.$.scroller.toggleAttribute('column-resizing', false); this.dispatchEvent( new CustomEvent('column-resize', { detail: { resizedColumn: column }, }), ); } // Notify resize this._resizeHandler(); } } /** * Fired when a column in the grid is resized by the user. * * @event column-resize * @param {Object} detail * @param {Object} detail.resizedColumn the column that was resized */ };