Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix(react-drawer): allow 1px tolerance in scroll-bottom detection so the footer divider hides at >100% zoom",
"packageName": "@fluentui/react-drawer",
"email": "adam.znamenacek@eway-crm.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { DrawerBody } from './DrawerBody';
import { getScrollState } from './useDrawerBody';
import { isConformant } from '../../testing/isConformant';

describe('DrawerBody', () => {
Expand All @@ -21,4 +22,66 @@ describe('DrawerBody', () => {
</div>
`);
});

describe('getScrollState', () => {
it('returns none when content does not overflow', () => {
const state = getScrollState({
scrollTop: 0,
scrollHeight: 100,
clientHeight: 100,
} as HTMLElement);

expect(state).toBe('none');
});

it('returns top when at the start of scrollable content', () => {
const state = getScrollState({
scrollTop: 0,
scrollHeight: 200,
clientHeight: 100,
} as HTMLElement);

expect(state).toBe('top');
});

it('returns middle when between top and bottom', () => {
const state = getScrollState({
scrollTop: 50,
scrollHeight: 200,
clientHeight: 100,
} as HTMLElement);

expect(state).toBe('middle');
});

it('returns bottom when at the end of scrollable content', () => {
const state = getScrollState({
scrollTop: 100,
scrollHeight: 200,
clientHeight: 100,
} as HTMLElement);

expect(state).toBe('bottom');
});

it('returns bottom when within 1px tolerance at the end', () => {
const state = getScrollState({
scrollTop: 89.4,
scrollHeight: 190,
clientHeight: 100,
} as HTMLElement);

expect(state).toBe('bottom');
});

it('returns middle when more than 1px away from the end', () => {
const state = getScrollState({
scrollTop: 88.9,
scrollHeight: 190,
clientHeight: 100,
} as HTMLElement);

expect(state).toBe('middle');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ import type { DrawerScrollState } from '../../shared/DrawerBase.types';
import type { DrawerBodyProps, DrawerBodyState } from './DrawerBody.types';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';

/**
* Treat values within 1px of the scroll height as "bottom" to account for
* fractional scroll measurements caused by browser zoom and display scaling.
*/
const SCROLL_BOTTOM_TOLERANCE = 1;

/**
* Get the current scroll state of the DrawerBody.
*
* @internal
* @param element - HTMLElement to check scroll state of
*/
const getScrollState = ({ scrollTop, scrollHeight, clientHeight }: HTMLElement): DrawerScrollState => {
export const getScrollState = ({ scrollTop, scrollHeight, clientHeight }: HTMLElement): DrawerScrollState => {
if (scrollHeight <= clientHeight) {
return 'none';
}
Expand All @@ -31,7 +37,9 @@ const getScrollState = ({ scrollTop, scrollHeight, clientHeight }: HTMLElement):
return 'top';
}

if (scrollTop + clientHeight === scrollHeight) {
const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);

if (distanceFromBottom <= SCROLL_BOTTOM_TOLERANCE) {
return 'bottom';
}

Expand Down