mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-28 13:04:08 +03:00
fix floating point scrollSize browser rounding
This commit is contained in:
@@ -12,7 +12,8 @@ import {
|
||||
removeElements,
|
||||
windowSize,
|
||||
runEach,
|
||||
equalWH,
|
||||
equalBCRWH,
|
||||
getBoundingClientRect,
|
||||
} from 'support';
|
||||
import {
|
||||
classNameEnvironment,
|
||||
@@ -87,14 +88,14 @@ const getRtlScrollBehavior = (parentElm: HTMLElement, childElm: HTMLElement): {
|
||||
|
||||
const getFlexboxGlue = (parentElm: HTMLElement, childElm: HTMLElement): boolean => {
|
||||
addClass(parentElm, classNameEnvironmentFlexboxGlue);
|
||||
const minOffsetsizeParent = offsetSize(parentElm);
|
||||
const minOffsetsize = offsetSize(childElm);
|
||||
const supportsMin = equalWH(minOffsetsize, minOffsetsizeParent);
|
||||
const minOffsetsizeParent = getBoundingClientRect(parentElm);
|
||||
const minOffsetsize = getBoundingClientRect(childElm);
|
||||
const supportsMin = equalBCRWH(minOffsetsize, minOffsetsizeParent, true);
|
||||
|
||||
addClass(parentElm, classNameEnvironmentFlexboxGlueMax);
|
||||
const maxOffsetsizeParent = offsetSize(parentElm);
|
||||
const maxOffsetsize = offsetSize(childElm);
|
||||
const supportsMax = equalWH(maxOffsetsize, maxOffsetsizeParent);
|
||||
const maxOffsetsizeParent = getBoundingClientRect(parentElm);
|
||||
const maxOffsetsize = getBoundingClientRect(childElm);
|
||||
const supportsMax = equalBCRWH(maxOffsetsize, maxOffsetsizeParent, true);
|
||||
|
||||
return supportsMin && supportsMax;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
addClass,
|
||||
removeClass,
|
||||
clientSize,
|
||||
offsetSize,
|
||||
getBoundingClientRect,
|
||||
} from 'support';
|
||||
import { LifecycleHub, Lifecycle } from 'lifecycles/lifecycleHub';
|
||||
import { getEnvironment } from 'environment';
|
||||
@@ -21,6 +23,10 @@ import { classNameViewportScrollbarStyling } from 'classnames';
|
||||
|
||||
const overlaidScrollbarsHideOffset = 42;
|
||||
const overlaidScrollbarsHideBorderStyle = `${overlaidScrollbarsHideOffset}px solid transparent`;
|
||||
interface ContentScrollSizeCacheContext {
|
||||
_viewportSize: WH<number>;
|
||||
_viewportScrollSize: WH<number>;
|
||||
}
|
||||
interface OverflowAmountCacheContext {
|
||||
_contentScrollSize: WH<number>;
|
||||
_viewportSize: WH<number>;
|
||||
@@ -29,26 +35,48 @@ interface OverflowAmountCacheContext {
|
||||
export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle => {
|
||||
const { _structureSetup, _getPaddingStyle } = lifecycleHub;
|
||||
const { _host, _padding, _viewport, _content, _contentArrange } = _structureSetup._targetObj;
|
||||
const { _update: updateContentScrollSizeCache, _current: getCurrentContentScrollSizeCache } = createCache<WH<number>>(
|
||||
() => scrollSize(_content || _viewport),
|
||||
const { _update: updateContentScrollSizeCache, _current: getCurrentContentScrollSizeCache } = createCache<
|
||||
WH<number>,
|
||||
ContentScrollSizeCacheContext
|
||||
>(
|
||||
(ctx) => {
|
||||
const { _viewportSize, _viewportScrollSize } = ctx;
|
||||
const contentViewportScrollSize = scrollSize(_content || _viewport);
|
||||
|
||||
return _content ? fixScrollSizeRounding(contentViewportScrollSize, _viewportSize, _viewportScrollSize) : contentViewportScrollSize;
|
||||
},
|
||||
{ _equal: equalWH }
|
||||
);
|
||||
const { _update: updateOverflowAmountCache, _current: getCurrentOverflowAmountCache } = createCache<XY<number>, OverflowAmountCacheContext>(
|
||||
(ctx) => ({
|
||||
x: Math.max(0, Math.round((ctx._contentScrollSize.w - ctx._viewportSize.w) * 100) / 100),
|
||||
y: Math.max(0, Math.round((ctx._contentScrollSize.h - ctx._viewportSize.h) * 100) / 100),
|
||||
x: Math.max(0, ctx._contentScrollSize.w - ctx._viewportSize.w),
|
||||
y: Math.max(0, ctx._contentScrollSize.h - ctx._viewportSize.h),
|
||||
}),
|
||||
{ _equal: equalXY }
|
||||
);
|
||||
|
||||
const fixScrollSizeRounding = (contentScrollSize: WH<number>, viewportSize: WH<number>, viewportScrollSize: WH<number>): WH<number> => {
|
||||
const equalViewportSizes = viewportSize.w === viewportScrollSize.w || viewportSize.h === viewportScrollSize.h;
|
||||
const contentViewportScrollSizeOverflow = contentScrollSize.w > viewportScrollSize.w || contentScrollSize.h > viewportScrollSize.h;
|
||||
|
||||
if (equalViewportSizes && contentViewportScrollSizeOverflow) {
|
||||
const viewportRect = getBoundingClientRect(_viewport);
|
||||
const viewportOffsetSize = offsetSize(_viewport);
|
||||
|
||||
return {
|
||||
w: contentScrollSize.w - Math.ceil(Math.max(0, viewportRect.width - viewportOffsetSize.w)),
|
||||
h: contentScrollSize.h - Math.ceil(Math.max(0, viewportRect.height - viewportOffsetSize.h)),
|
||||
};
|
||||
}
|
||||
|
||||
return contentScrollSize;
|
||||
};
|
||||
|
||||
const setViewportOverflowStyle = (horizontal: boolean, amount: number, behavior: OverflowBehavior, styleObj: StyleObject) => {
|
||||
const overflowKey = horizontal ? 'overflowX' : 'overflowY';
|
||||
//const scrollMaxKey = horizontal ? 'scrollLeftMax' : 'scrollTopMax';
|
||||
const behaviorIsScroll = behavior === 'scroll';
|
||||
const behaviorIsVisibleScroll = behavior === 'visible-scroll';
|
||||
const hideOverflow = behaviorIsScroll || behavior === 'hidden';
|
||||
//const scrollMax = _viewport[scrollMaxKey];
|
||||
//const scrollMaxOverflow = isNumber(scrollMax) ? scrollMax > 0 : true;
|
||||
const applyStyle = amount > 0 && hideOverflow;
|
||||
|
||||
if (applyStyle) {
|
||||
@@ -156,7 +184,11 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle =
|
||||
const contentClientSize = clientSize(_content || _viewport); // needs to be client Size because applied border for content arrange on content
|
||||
const contentArrangeOffsetSize = clientSize(_contentArrange); // can be offset size aswell
|
||||
|
||||
contentScrollSizeCache = updateContentScrollSizeCache(force);
|
||||
contentScrollSizeCache = updateContentScrollSizeCache(force, {
|
||||
_viewportSize: viewportSize,
|
||||
_viewportScrollSize: viewportScrollSize,
|
||||
});
|
||||
|
||||
const { _value: contentScrollSize } = contentScrollSizeCache;
|
||||
overflowAmuntCache = updateOverflowAmountCache(force, {
|
||||
_contentScrollSize: {
|
||||
@@ -230,8 +262,8 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle =
|
||||
// TODO: Test without content
|
||||
// TODO: Test without padding
|
||||
// TODO: hide host || padding overflow if scroll x or y
|
||||
// TODO: fix false overflow bug (fractal scroll size)
|
||||
// TODO: add trinsic lifecycle
|
||||
// TODO: IE max-width fix not always working
|
||||
// TODO: remove lifecycleHub get set padding if not needed
|
||||
|
||||
style(_viewport, viewportStyle);
|
||||
|
||||
@@ -8,11 +8,18 @@ import { PlainObject } from 'typings';
|
||||
* @param b Object b.
|
||||
* @param props The props which shall be compared.
|
||||
*/
|
||||
export const equal = <T extends PlainObject>(a: T | undefined, b: T | undefined, props: Array<keyof T>): boolean => {
|
||||
export const equal = <T extends PlainObject>(
|
||||
a: T | undefined,
|
||||
b: T | undefined,
|
||||
props: Array<keyof T>,
|
||||
propMutation?: ((value: any) => any) | null | false
|
||||
): boolean => {
|
||||
if (a && b) {
|
||||
let result = true;
|
||||
each(props, (prop) => {
|
||||
if (a[prop] !== b[prop]) {
|
||||
const compareA = propMutation ? propMutation(a[prop]) : a[prop];
|
||||
const compareB = propMutation ? propMutation(b[prop]) : b[prop];
|
||||
if (compareA !== compareB) {
|
||||
result = false;
|
||||
}
|
||||
});
|
||||
@@ -44,3 +51,13 @@ export const equalXY = (a?: XY, b?: XY) => equal<XY>(a, b, ['x', 'y']);
|
||||
* @param b Object b.
|
||||
*/
|
||||
export const equalTRBL = (a?: TRBL, b?: TRBL) => equal<TRBL>(a, b, ['t', 'r', 'b', 'l']);
|
||||
|
||||
/**
|
||||
* Compares two DOM Rects for their equality of their width and height properties
|
||||
* Also returns false if one of the DOM Rects is undefined or null.
|
||||
* @param a DOM Rect a.
|
||||
* @param b DOM Rect b.
|
||||
* @param round Whether the values should be rounded.
|
||||
*/
|
||||
export const equalBCRWH = (a?: DOMRect, b?: DOMRect, round?: boolean) =>
|
||||
equal<DOMRect>(a, b, ['width', 'height'], round && ((value) => Math.round(value)));
|
||||
|
||||
Reference in New Issue
Block a user