Skip to content

Commit

Permalink
feat: Add the option to find scrollTop of element bottom
Browse files Browse the repository at this point in the history
  • Loading branch information
guidobouman committed Apr 26, 2018
1 parent 0d76124 commit 08e2ed7
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 18 deletions.
7 changes: 5 additions & 2 deletions src/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ function getContainerRect(container) {
left: 0,
bottom: window.innerHeight,
right: window.innerWidth,
height: window.innerHeight,
width: window.innerWidth,
} : container.getBoundingClientRect();
}

export function getTargetScrollTop(container, element) {
export function getTargetScrollTop(container, element, toBottom = false) {
const containerRect = getContainerRect(container);
const elementRect = element.getBoundingClientRect();
const scrollOffset = elementRect.top - containerRect.top;
return scrollOffset + getScrollingElement(container).scrollTop;
const offsetCorrection = toBottom ? elementRect.height - containerRect.height : 0;
return scrollOffset + offsetCorrection + getScrollingElement(container).scrollTop;
}

export function getElementsInContainerViewport(container, elementList) {
Expand Down
112 changes: 96 additions & 16 deletions src/utilities.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,48 +42,128 @@ describe('getScrolllingElement', () => {
});

describe('getTargetScrollTop', () => {
function getElements(scrollTop, containerTop, targetTop) {
function getElements(scrollTop, containerDimensions, targetDimensions) {
const container = document.createElement('div');
container.scrollTop = scrollTop;
container.getBoundingClientRect = () => ({
top: containerTop,
...containerDimensions,
height: containerDimensions.bottom - containerDimensions.top,
});

const target = document.createElement('div');
target.getBoundingClientRect = () => ({
top: targetTop,
...targetDimensions,
height: targetDimensions.bottom - targetDimensions.top,
});

return [container, target];
}

test('calculates scrollTop for target element', () => {
expect(getTargetScrollTop(...getElements(0, 0, 0))).toEqual(0);
expect(getTargetScrollTop(...getElements(100, 0, -100))).toEqual(0);
expect(getTargetScrollTop(...getElements(100, 0, 0))).toEqual(100);
expect(getTargetScrollTop(...getElements(0, 0, 100))).toEqual(100);
expect(getTargetScrollTop(...getElements(100, 0, 100))).toEqual(200);
expect(getTargetScrollTop(...getElements(100, 100, 100))).toEqual(100);
expect(getTargetScrollTop(...getElements(0, { top: 0 }, { top: 0 }))).toEqual(0);
expect(getTargetScrollTop(...getElements(100, { top: 0 }, { top: -100 }))).toEqual(0);
expect(getTargetScrollTop(...getElements(100, { top: 0 }, { top: 0 }))).toEqual(100);
expect(getTargetScrollTop(...getElements(0, { top: 0 }, { top: 100 }))).toEqual(100);
expect(getTargetScrollTop(...getElements(100, { top: 0 }, { top: 100 }))).toEqual(200);
expect(getTargetScrollTop(...getElements(100, { top: 100 }, { top: 100 }))).toEqual(100);
});

function getBodyElements(scrollTop, targetTop) {
test('calculates scrollTop for target element bottom', () => {
expect(getTargetScrollTop(...getElements(0, {
top: 0,
bottom: 300,
}, {
top: 0,
bottom: 300,
}), true)).toEqual(0);

expect(getTargetScrollTop(...getElements(100, {
top: 0,
bottom: 300,
}, {
top: -100,
bottom: 200,
}), true)).toEqual(0);

expect(getTargetScrollTop(...getElements(100, {
top: 0,
bottom: 300,
}, {
top: 0,
bottom: 300,
}), true)).toEqual(100);

expect(getTargetScrollTop(...getElements(0, {
top: 0,
bottom: 300,
}, {
top: 100,
bottom: 400,
}), true)).toEqual(100);

expect(getTargetScrollTop(...getElements(100, {
top: 0,
bottom: 300,
}, {
top: 100,
bottom: 400,
}), true)).toEqual(200);

expect(getTargetScrollTop(...getElements(100, {
top: 100,
bottom: 400,
}, {
top: 100,
bottom: 400,
}), true)).toEqual(100);
});

function getBodyElements(scrollTop, targetDimensions) {
const container = document.body;
getScrollingElement(document.body).scrollTop = scrollTop;

const target = document.createElement('div');
target.getBoundingClientRect = () => ({
top: targetTop,
...targetDimensions,
height: targetDimensions.bottom - targetDimensions.top,
});

return [container, target];
}

test('calculates scrollTop for target element in body', () => {
expect(getTargetScrollTop(...getBodyElements(0, 0))).toEqual(0);
expect(getTargetScrollTop(...getBodyElements(100, -100))).toEqual(0);
expect(getTargetScrollTop(...getBodyElements(100, 0))).toEqual(100);
expect(getTargetScrollTop(...getBodyElements(0, 100))).toEqual(100);
expect(getTargetScrollTop(...getBodyElements(100, 100))).toEqual(200);
expect(getTargetScrollTop(...getBodyElements(0, { top: 0 }))).toEqual(0);
expect(getTargetScrollTop(...getBodyElements(100, { top: -100 }))).toEqual(0);
expect(getTargetScrollTop(...getBodyElements(100, { top: 0 }))).toEqual(100);
expect(getTargetScrollTop(...getBodyElements(0, { top: 100 }))).toEqual(100);
expect(getTargetScrollTop(...getBodyElements(100, { top: 100 }))).toEqual(200);
});

test('calculates scrollTop for target element bottom in body', () => {
expect(getTargetScrollTop(...getBodyElements(0, {
top: 0,
bottom: SCREEN_HEIGHT,
}), true)).toEqual(0);

expect(getTargetScrollTop(...getBodyElements(100, {
top: -100,
bottom: SCREEN_HEIGHT - 100,
}), true)).toEqual(0);

expect(getTargetScrollTop(...getBodyElements(100, {
top: 0,
bottom: SCREEN_HEIGHT,
}), true)).toEqual(100);

expect(getTargetScrollTop(...getBodyElements(0, {
top: 100,
bottom: SCREEN_HEIGHT + 100,
}), true)).toEqual(100);

expect(getTargetScrollTop(...getBodyElements(100, {
top: 100,
bottom: SCREEN_HEIGHT + 100,
}), true)).toEqual(200);
});
});

Expand Down

0 comments on commit 08e2ed7

Please sign in to comment.