Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pan-kot committed Sep 17, 2023
1 parent 3e90b26 commit 7048d40
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 69 deletions.
19 changes: 17 additions & 2 deletions src/table/__tests__/resizable-columns.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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(<Table {...defaultProps} onColumnWidthsChange={event => onChange(event.detail)} />);
const columnResizerWrapper = wrapper.findColumnResizer(1)!;
Expand All @@ -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(<Table {...defaultProps} onColumnWidthsChange={event => 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', () => {
Expand Down
52 changes: 8 additions & 44 deletions src/table/resizer/dom-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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']);
};
}
52 changes: 29 additions & 23 deletions src/table/resizer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
Expand All @@ -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]);

Expand Down Expand Up @@ -165,7 +171,7 @@ export function Resizer({
setIsDragging(false);

Check warning on line 171 in src/table/resizer/index.tsx

View check run for this annotation

Codecov / codecov/patch

src/table/resizer/index.tsx#L171

Added line #L171 was not covered by tests
}}
onFocus={() => {
setHeaderCellWidth(resizerDom.current.headerWidth);
setHeaderCellWidth(resizerDom.current.header.getBoundingClientRect().width);
setResizerHasFocus(true);
}}
onBlur={() => {
Expand Down

0 comments on commit 7048d40

Please sign in to comment.