From 7048d40837168737f75bdc570f69765c3f10c3ea Mon Sep 17 00:00:00 2001 From: Andrei Zhaleznichenka Date: Sun, 17 Sep 2023 18:12:27 +0200 Subject: [PATCH] add tests --- .../__tests__/resizable-columns.test.tsx | 19 ++++++- src/table/resizer/dom-helper.ts | 52 +++---------------- src/table/resizer/index.tsx | 52 +++++++++++-------- 3 files changed, 54 insertions(+), 69 deletions(-) diff --git a/src/table/__tests__/resizable-columns.test.tsx b/src/table/__tests__/resizable-columns.test.tsx index d2fbd79500..26d653a476 100644 --- a/src/table/__tests__/resizable-columns.test.tsx +++ b/src/table/__tests__/resizable-columns.test.tsx @@ -295,12 +295,14 @@ test('should not trigger if the previous and the current widths are the same', ( }); describe('resize with keyboard', () => { + let mockWidth = 150; + const originalBoundingClientRect = HTMLElement.prototype.getBoundingClientRect; beforeEach(() => { HTMLElement.prototype.getBoundingClientRect = function () { const rect = originalBoundingClientRect.apply(this); if (this.tagName === 'TH') { - rect.width = 150; + rect.width = mockWidth; } return rect; }; @@ -310,7 +312,7 @@ describe('resize with keyboard', () => { HTMLElement.prototype.getBoundingClientRect = originalBoundingClientRect; }); - test('resizes columns with keyboard to the lect', async () => { + test('resizes columns with keyboard', async () => { const onChange = jest.fn(); const { wrapper } = renderTable( onChange(event.detail)} />); const columnResizerWrapper = wrapper.findColumnResizer(1)!; @@ -330,6 +332,19 @@ describe('resize with keyboard', () => { expect(onChange).toHaveBeenCalledWith({ widths: [150 + 10, 300] }); }); }); + + test('cannot resize below minsize', () => { + mockWidth = 80; + const onChange = jest.fn(); + const { wrapper } = renderTable(
onChange(event.detail)} />); + const columnResizerWrapper = wrapper.findColumnResizer(1)!; + + columnResizerWrapper.focus(); + columnResizerWrapper.keydown(KeyCode.left); + + expect(onChange).toHaveBeenCalledTimes(0); + expect(columnResizerWrapper.getElement()!).toHaveAttribute('aria-valuenow', '80'); + }); }); describe('column header content', () => { diff --git a/src/table/resizer/dom-helper.ts b/src/table/resizer/dom-helper.ts index 6f99015516..6f722b3943 100644 --- a/src/table/resizer/dom-helper.ts +++ b/src/table/resizer/dom-helper.ts @@ -44,55 +44,19 @@ export class ResizerDomHelper { } } - get header(): null | HTMLElement { - return this._header; + get header(): HTMLElement { + return this._header!; } - get headerWidth(): number { - return this._header?.getBoundingClientRect().width ?? 0; + get table(): HTMLElement { + return this._table!; } - get headerLeft(): number { - return this._header?.getBoundingClientRect().left ?? 0; + get tracker(): HTMLElement { + return this._tracker!; } - get headerRight(): number { - return this._header?.getBoundingClientRect().right ?? 0; + get scrollParent(): HTMLElement { + return this._scrollParent!; } - - get leftEdge(): number { - return this._scrollParent?.getBoundingClientRect().left ?? 0; - } - - get rightEdge(): number { - return this._scrollParent?.getBoundingClientRect().right ?? 0; - } - - incrementScroll = (value: number) => { - if (this._scrollParent) { - this._scrollParent.scrollLeft += value; - } - }; - - updateTrackerPosition = (newOffset: number) => { - if (this._table && this._header && this._tracker) { - const { left: scrollParentLeft } = this._table.getBoundingClientRect(); - this._tracker.style.top = this._header.getBoundingClientRect().height + 'px'; - // minus one pixel to offset the cell border - this._tracker.style.left = newOffset - scrollParentLeft - 1 + 'px'; - } - }; - - setResizeActiveStyle = () => { - document.body.classList.add(styles['resize-active']); - }; - - setResizerWithFocusStyle = () => { - document.body.classList.add(styles['resize-active-with-focus']); - }; - - removeStyles = () => { - document.body.classList.remove(styles['resize-active']); - document.body.classList.remove(styles['resize-active-with-focus']); - }; } diff --git a/src/table/resizer/index.tsx b/src/table/resizer/index.tsx index 19de1d544e..087483be13 100644 --- a/src/table/resizer/index.tsx +++ b/src/table/resizer/index.tsx @@ -41,14 +41,21 @@ export function Resizer({ const [headerCellWidth, setHeaderCellWidth] = useState(0); // Read header width after mounting for it to be available in the element's ARIA label before it gets focused. - useEffect(() => setHeaderCellWidth(resizerDom.current.headerWidth), []); + useEffect(() => setHeaderCellWidth(resizerDom.current.header.getBoundingClientRect().width), []); const handlers = useMemo(() => { + const updateTrackerPosition = (newOffset: number) => { + const { left: scrollParentLeft } = resizerDom.current.table.getBoundingClientRect(); + resizerDom.current.tracker.style.top = resizerDom.current.header.getBoundingClientRect().height + 'px'; + // minus one pixel to offset the cell border + resizerDom.current.tracker.style.left = newOffset - scrollParentLeft - 1 + 'px'; + }; + const updateColumnWidth = (newWidth: number) => { - const right = resizerDom.current.headerRight; - const width = resizerDom.current.headerWidth; + const right = resizerDom.current.header.getBoundingClientRect().right; + const width = resizerDom.current.header.getBoundingClientRect().width; const updatedWidth = newWidth < minWidth ? minWidth : newWidth; - resizerDom.current.updateTrackerPosition(right + updatedWidth - width); + updateTrackerPosition(right + updatedWidth - width); if (newWidth >= minWidth) { setHeaderCellWidth(newWidth); } @@ -57,8 +64,8 @@ export function Resizer({ }; const resizeColumn = (offset: number) => { - if (offset > resizerDom.current.leftEdge) { - const newWidth = offset - resizerDom.current.headerLeft; + if (offset > resizerDom.current.scrollParent.getBoundingClientRect().left) { + const newWidth = offset - resizerDom.current.header.getBoundingClientRect().left; // callbacks must be the last calls in the handler, because they may cause an extra update updateColumnWidth(newWidth); } @@ -67,14 +74,14 @@ export function Resizer({ const onAutoGrow = () => { autoGrowTimeout.current = setTimeout(onAutoGrow, AUTO_GROW_INTERVAL); // callbacks must be the last calls in the handler, because they may cause an extra update - updateColumnWidth(resizerDom.current.headerWidth + AUTO_GROW_INCREMENT); - resizerDom.current.incrementScroll(AUTO_GROW_INCREMENT); + updateColumnWidth(resizerDom.current.header.getBoundingClientRect().width + AUTO_GROW_INCREMENT); + resizerDom.current.scrollParent.scrollLeft += AUTO_GROW_INCREMENT; }; const onMouseMove = (event: MouseEvent) => { clearTimeout(autoGrowTimeout.current); const offset = event.pageX; - if (offset > resizerDom.current.rightEdge) { + if (offset > resizerDom.current.scrollParent.getBoundingClientRect().right) { autoGrowTimeout.current = setTimeout(onAutoGrow, AUTO_GROW_START_TIME); } else { resizeColumn(offset); @@ -91,45 +98,44 @@ export function Resizer({ const onKeyDown = (event: KeyboardEvent) => { if (event.keyCode === KeyCode.left) { event.preventDefault(); - updateColumnWidth(resizerDom.current.headerWidth - 10); + updateColumnWidth(resizerDom.current.header.getBoundingClientRect().width - 10); setTimeout(() => onWidthUpdateCommit(), 0); } if (event.keyCode === KeyCode.right) { event.preventDefault(); - updateColumnWidth(resizerDom.current.headerWidth + 10); + updateColumnWidth(resizerDom.current.header.getBoundingClientRect().width + 10); setTimeout(() => onWidthUpdateCommit(), 0); } }; - return { updateColumnWidth, onMouseMove, onMouseUp, onKeyDown }; + return { updateTrackerPosition, updateColumnWidth, onMouseMove, onMouseUp, onKeyDown }; }, [minWidth, onWidthUpdate, onWidthUpdateCommit]); useEffect(() => { - const headerElement = resizerDom.current.header; - - if ((!isDragging && !resizerHasFocus) || !handlers || !headerElement) { + if ((!isDragging && !resizerHasFocus) || !handlers) { return; } - resizerDom.current.updateTrackerPosition(resizerDom.current.headerRight); + handlers.updateTrackerPosition(resizerDom.current.header.getBoundingClientRect().right); if (isDragging) { - resizerDom.current.setResizeActiveStyle(); + document.body.classList.add(styles['resize-active']); document.addEventListener('mousemove', handlers.onMouseMove); document.addEventListener('mouseup', handlers.onMouseUp); } if (resizerHasFocus) { - resizerDom.current.setResizeActiveStyle(); - resizerDom.current.setResizerWithFocusStyle(); - headerElement.addEventListener('keydown', handlers.onKeyDown); + document.body.classList.add(styles['resize-active']); + document.body.classList.add(styles['resize-active-with-focus']); + resizerDom.current.header.addEventListener('keydown', handlers.onKeyDown); } return () => { clearTimeout(autoGrowTimeout.current); - resizerDom.current.removeStyles(); + document.body.classList.remove(styles['resize-active']); + document.body.classList.remove(styles['resize-active-with-focus']); document.removeEventListener('mousemove', handlers.onMouseMove); document.removeEventListener('mouseup', handlers.onMouseUp); - headerElement.removeEventListener('keydown', handlers.onKeyDown); + resizerDom.current.header.removeEventListener('keydown', handlers.onKeyDown); }; }, [isDragging, onWidthUpdateCommit, resizerHasFocus, handlers]); @@ -165,7 +171,7 @@ export function Resizer({ setIsDragging(false); }} onFocus={() => { - setHeaderCellWidth(resizerDom.current.headerWidth); + setHeaderCellWidth(resizerDom.current.header.getBoundingClientRect().width); setResizerHasFocus(true); }} onBlur={() => {