mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-24 17:50:37 +03:00
improve sizeobserver with passive listeners, fix raf and setT code, move part of enviroment code to plugin
This commit is contained in:
@@ -11,7 +11,6 @@ import {
|
|||||||
XY,
|
XY,
|
||||||
removeAttr,
|
removeAttr,
|
||||||
removeElements,
|
removeElements,
|
||||||
windowSize,
|
|
||||||
equalBCRWH,
|
equalBCRWH,
|
||||||
getBoundingClientRect,
|
getBoundingClientRect,
|
||||||
assignDeep,
|
assignDeep,
|
||||||
@@ -30,6 +29,7 @@ import {
|
|||||||
import { Options, defaultOptions } from 'options';
|
import { Options, defaultOptions } from 'options';
|
||||||
import { PartialOptions } from 'typings';
|
import { PartialOptions } from 'typings';
|
||||||
import { InitializationStrategy } from 'initialization';
|
import { InitializationStrategy } from 'initialization';
|
||||||
|
import { getPlugins, ScrollbarsHidingPluginInstance, scrollbarsHidingPluginName } from 'plugins';
|
||||||
|
|
||||||
type EnvironmentEventMap = {
|
type EnvironmentEventMap = {
|
||||||
_: [];
|
_: [];
|
||||||
@@ -52,18 +52,12 @@ export interface InternalEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let environmentInstance: InternalEnvironment;
|
let environmentInstance: InternalEnvironment;
|
||||||
const { abs, round } = Math;
|
|
||||||
|
|
||||||
const diffBiggerThanOne = (valOne: number, valTwo: number): boolean => {
|
|
||||||
const absValOne = abs(valOne);
|
|
||||||
const absValTwo = abs(valTwo);
|
|
||||||
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getNativeScrollbarSize = (
|
const getNativeScrollbarSize = (
|
||||||
body: HTMLElement,
|
body: HTMLElement,
|
||||||
measureElm: HTMLElement,
|
measureElm: HTMLElement,
|
||||||
measureElmChild: HTMLElement
|
measureElmChild: HTMLElement,
|
||||||
|
clear?: boolean
|
||||||
): XY => {
|
): XY => {
|
||||||
appendChildren(body, measureElm);
|
appendChildren(body, measureElm);
|
||||||
|
|
||||||
@@ -71,6 +65,8 @@ const getNativeScrollbarSize = (
|
|||||||
const oSize = offsetSize(measureElm);
|
const oSize = offsetSize(measureElm);
|
||||||
const fSize = fractionalSize(measureElmChild);
|
const fSize = fractionalSize(measureElmChild);
|
||||||
|
|
||||||
|
clear && removeElements(measureElm);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: oSize.h - cSize.h + fSize.h,
|
x: oSize.h - cSize.h + fSize.h,
|
||||||
y: oSize.w - cSize.w + fSize.w,
|
y: oSize.w - cSize.w + fSize.w,
|
||||||
@@ -137,26 +133,19 @@ const getFlexboxGlue = (parentElm: HTMLElement, childElm: HTMLElement): boolean
|
|||||||
return supportsMin && supportsMax;
|
return supportsMin && supportsMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getWindowDPR = (): number => {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
// @ts-ignore
|
|
||||||
const dDPI = window.screen.deviceXDPI || 0;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
// @ts-ignore
|
|
||||||
const sDPI = window.screen.logicalXDPI || 1;
|
|
||||||
return window.devicePixelRatio || dDPI / sDPI;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createEnvironment = (): InternalEnvironment => {
|
const createEnvironment = (): InternalEnvironment => {
|
||||||
const { body } = document;
|
const { body } = document;
|
||||||
const envDOM = createDOM(`<div class="${classNameEnvironment}"><div></div></div>`);
|
const envDOM = createDOM(`<div class="${classNameEnvironment}"><div></div></div>`);
|
||||||
const envElm = envDOM[0] as HTMLElement;
|
const envElm = envDOM[0] as HTMLElement;
|
||||||
const envChildElm = envElm.firstChild as HTMLElement;
|
const envChildElm = envElm.firstChild as HTMLElement;
|
||||||
const [addEvent, , triggerEvent] = createEventListenerHub<EnvironmentEventMap>();
|
const [addEvent, , triggerEvent] = createEventListenerHub<EnvironmentEventMap>();
|
||||||
const [updateNativeScrollbarSizeCache, getNativeScrollbarSizeCache] = createCache({
|
const [updateNativeScrollbarSizeCache, getNativeScrollbarSizeCache] = createCache(
|
||||||
_initialValue: getNativeScrollbarSize(body, envElm, envChildElm),
|
{
|
||||||
_equal: equalXY,
|
_initialValue: getNativeScrollbarSize(body, envElm, envChildElm),
|
||||||
});
|
_equal: equalXY,
|
||||||
|
},
|
||||||
|
getNativeScrollbarSize.bind(0, body, envElm, envChildElm, true)
|
||||||
|
);
|
||||||
const [nativeScrollbarsSize] = getNativeScrollbarSizeCache();
|
const [nativeScrollbarsSize] = getNativeScrollbarSizeCache();
|
||||||
const nativeScrollbarsHiding = getNativeScrollbarsHiding(envElm);
|
const nativeScrollbarsHiding = getNativeScrollbarsHiding(envElm);
|
||||||
const nativeScrollbarsOverlaid = {
|
const nativeScrollbarsOverlaid = {
|
||||||
@@ -197,47 +186,14 @@ const createEnvironment = (): InternalEnvironment => {
|
|||||||
removeElements(envElm);
|
removeElements(envElm);
|
||||||
|
|
||||||
if (!nativeScrollbarsHiding && (!nativeScrollbarsOverlaid.x || !nativeScrollbarsOverlaid.y)) {
|
if (!nativeScrollbarsHiding && (!nativeScrollbarsOverlaid.x || !nativeScrollbarsOverlaid.y)) {
|
||||||
let size = windowSize();
|
let resizeFn: undefined | ReturnType<ScrollbarsHidingPluginInstance['_envWindowZoom']>;
|
||||||
let dpr = getWindowDPR();
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
const sizeNew = windowSize();
|
const scrollbarsHidingPlugin = getPlugins()[scrollbarsHidingPluginName] as
|
||||||
const deltaSize = {
|
| ScrollbarsHidingPluginInstance
|
||||||
w: sizeNew.w - size.w,
|
| undefined;
|
||||||
h: sizeNew.h - size.h,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (deltaSize.w === 0 && deltaSize.h === 0) return;
|
resizeFn = resizeFn || (scrollbarsHidingPlugin && scrollbarsHidingPlugin._envWindowZoom());
|
||||||
|
resizeFn && resizeFn(env, updateNativeScrollbarSizeCache, triggerEvent.bind(0, '_'));
|
||||||
const deltaAbsSize = {
|
|
||||||
w: abs(deltaSize.w),
|
|
||||||
h: abs(deltaSize.h),
|
|
||||||
};
|
|
||||||
const deltaAbsRatio = {
|
|
||||||
w: abs(round(sizeNew.w / (size.w / 100.0))),
|
|
||||||
h: abs(round(sizeNew.h / (size.h / 100.0))),
|
|
||||||
};
|
|
||||||
const dprNew = getWindowDPR();
|
|
||||||
const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
|
|
||||||
const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
|
|
||||||
const dprChanged = dprNew !== dpr && dpr > 0;
|
|
||||||
const isZoom = deltaIsBigger && difference && dprChanged;
|
|
||||||
|
|
||||||
if (isZoom) {
|
|
||||||
const [scrollbarSize, scrollbarSizeChanged] = updateNativeScrollbarSizeCache(
|
|
||||||
getNativeScrollbarSize(body, envElm, envChildElm)
|
|
||||||
);
|
|
||||||
|
|
||||||
assignDeep(environmentInstance._nativeScrollbarsSize, scrollbarSize); // keep the object same!
|
|
||||||
removeElements(envElm);
|
|
||||||
|
|
||||||
if (scrollbarSizeChanged) {
|
|
||||||
triggerEvent('_');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size = sizeNew;
|
|
||||||
dpr = dprNew;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
prependChildren,
|
prependChildren,
|
||||||
removeElements,
|
removeElements,
|
||||||
on,
|
on,
|
||||||
stopAndPrevent,
|
|
||||||
addClass,
|
addClass,
|
||||||
push,
|
push,
|
||||||
ResizeObserverConstructor,
|
ResizeObserverConstructor,
|
||||||
@@ -18,6 +17,7 @@ import {
|
|||||||
isBoolean,
|
isBoolean,
|
||||||
removeClass,
|
removeClass,
|
||||||
isObject,
|
isObject,
|
||||||
|
stopPropagation,
|
||||||
} from 'support';
|
} from 'support';
|
||||||
import { getEnvironment } from 'environment';
|
import { getEnvironment } from 'environment';
|
||||||
import {
|
import {
|
||||||
@@ -190,7 +190,7 @@ export const createSizeObserver = (
|
|||||||
onSizeChangedCallbackProxy(directionIsRTLCacheValues);
|
onSizeChangedCallbackProxy(directionIsRTLCacheValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
stopAndPrevent(event);
|
stopPropagation(event);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ const pluginRegistry: Record<string, PluginInstance> = {};
|
|||||||
|
|
||||||
export const getPlugins = () => assignDeep({}, pluginRegistry);
|
export const getPlugins = () => assignDeep({}, pluginRegistry);
|
||||||
|
|
||||||
export const addPlugin = (addedPlugin: Plugin | Plugin[]) =>
|
export const addPlugin = (addedPlugin: Plugin | Plugin[]) => {
|
||||||
each((isArray(addedPlugin) ? addedPlugin : [addedPlugin]) as Plugin[], (plugin) => {
|
each((isArray(addedPlugin) ? addedPlugin : [addedPlugin]) as Plugin[], (plugin) => {
|
||||||
each(keys(plugin), (pluginName) => {
|
each(keys(plugin), (pluginName) => {
|
||||||
pluginRegistry[pluginName] = plugin[pluginName];
|
pluginRegistry[pluginName] = plugin[pluginName];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|||||||
+83
-8
@@ -1,5 +1,17 @@
|
|||||||
import { keys, attr, WH, style, addClass, removeClass, noop, each } from 'support';
|
import {
|
||||||
import { getEnvironment } from 'environment';
|
keys,
|
||||||
|
attr,
|
||||||
|
WH,
|
||||||
|
style,
|
||||||
|
addClass,
|
||||||
|
removeClass,
|
||||||
|
noop,
|
||||||
|
each,
|
||||||
|
assignDeep,
|
||||||
|
windowSize,
|
||||||
|
UpdateCache,
|
||||||
|
XY,
|
||||||
|
} from 'support';
|
||||||
import { classNameViewportArrange } from 'classnames';
|
import { classNameViewportArrange } from 'classnames';
|
||||||
import type { StyleObject } from 'typings';
|
import type { StyleObject } from 'typings';
|
||||||
import type { StructureSetupState } from 'setups/structureSetup';
|
import type { StructureSetupState } from 'setups/structureSetup';
|
||||||
@@ -8,6 +20,7 @@ import type {
|
|||||||
GetViewportOverflowState,
|
GetViewportOverflowState,
|
||||||
HideNativeScrollbars,
|
HideNativeScrollbars,
|
||||||
} from 'setups/structureSetup/updateSegments/overflowUpdateSegment';
|
} from 'setups/structureSetup/updateSegments/overflowUpdateSegment';
|
||||||
|
import type { InternalEnvironment } from 'environment';
|
||||||
import type { Plugin } from 'plugins';
|
import type { Plugin } from 'plugins';
|
||||||
|
|
||||||
export type ArrangeViewport = (
|
export type ArrangeViewport = (
|
||||||
@@ -29,29 +42,51 @@ export type UndoArrangeViewport = (
|
|||||||
) => UndoViewportArrangeResult;
|
) => UndoViewportArrangeResult;
|
||||||
|
|
||||||
export type ScrollbarsHidingPluginInstance = {
|
export type ScrollbarsHidingPluginInstance = {
|
||||||
_createUniqueViewportArrangeElement(): HTMLStyleElement | false;
|
_createUniqueViewportArrangeElement(env: InternalEnvironment): HTMLStyleElement | false;
|
||||||
_overflowUpdateSegment(
|
_overflowUpdateSegment(
|
||||||
doViewportArrange: boolean,
|
doViewportArrange: boolean,
|
||||||
|
flexboxGlue: boolean,
|
||||||
viewport: HTMLElement,
|
viewport: HTMLElement,
|
||||||
viewportArrange: HTMLStyleElement | false | null | undefined,
|
viewportArrange: HTMLStyleElement | false | null | undefined,
|
||||||
getState: () => StructureSetupState,
|
getState: () => StructureSetupState,
|
||||||
getViewportOverflowState: GetViewportOverflowState,
|
getViewportOverflowState: GetViewportOverflowState,
|
||||||
hideNativeScrollbars: HideNativeScrollbars
|
hideNativeScrollbars: HideNativeScrollbars
|
||||||
): [ArrangeViewport, UndoArrangeViewport];
|
): [ArrangeViewport, UndoArrangeViewport];
|
||||||
|
_envWindowZoom(): (
|
||||||
|
envInstance: InternalEnvironment,
|
||||||
|
updateNativeScrollbarSizeCache: UpdateCache<XY<number>>,
|
||||||
|
triggerEvent: () => void
|
||||||
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
let contentArrangeCounter = 0;
|
let contentArrangeCounter = 0;
|
||||||
|
const { round, abs } = Math;
|
||||||
|
const getWindowDPR = (): number => {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
// @ts-ignore
|
||||||
|
const dDPI = window.screen.deviceXDPI || 0;
|
||||||
|
// eslint-disable-next-line
|
||||||
|
// @ts-ignore
|
||||||
|
const sDPI = window.screen.logicalXDPI || 1;
|
||||||
|
return window.devicePixelRatio || dDPI / sDPI;
|
||||||
|
};
|
||||||
|
|
||||||
|
const diffBiggerThanOne = (valOne: number, valTwo: number): boolean => {
|
||||||
|
const absValOne = abs(valOne);
|
||||||
|
const absValTwo = abs(valTwo);
|
||||||
|
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
|
||||||
|
};
|
||||||
|
|
||||||
export const scrollbarsHidingPluginName = '__osScrollbarsHidingPlugin';
|
export const scrollbarsHidingPluginName = '__osScrollbarsHidingPlugin';
|
||||||
|
|
||||||
export const scrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> = {
|
export const scrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> = {
|
||||||
[scrollbarsHidingPluginName]: {
|
[scrollbarsHidingPluginName]: {
|
||||||
_createUniqueViewportArrangeElement: () => {
|
_createUniqueViewportArrangeElement: (env: InternalEnvironment) => {
|
||||||
const {
|
const {
|
||||||
_nativeScrollbarsHiding: _nativeScrollbarStyling,
|
_nativeScrollbarsHiding: _nativeScrollbarStyling,
|
||||||
_nativeScrollbarsOverlaid: _nativeScrollbarIsOverlaid,
|
_nativeScrollbarsOverlaid: _nativeScrollbarIsOverlaid,
|
||||||
_cssCustomProperties,
|
_cssCustomProperties,
|
||||||
} = getEnvironment();
|
} = env;
|
||||||
const create =
|
const create =
|
||||||
!_cssCustomProperties &&
|
!_cssCustomProperties &&
|
||||||
!_nativeScrollbarStyling &&
|
!_nativeScrollbarStyling &&
|
||||||
@@ -67,14 +102,13 @@ export const scrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> = {
|
|||||||
},
|
},
|
||||||
_overflowUpdateSegment: (
|
_overflowUpdateSegment: (
|
||||||
doViewportArrange,
|
doViewportArrange,
|
||||||
|
flexboxGlue,
|
||||||
viewport,
|
viewport,
|
||||||
viewportArrange,
|
viewportArrange,
|
||||||
getState,
|
getState,
|
||||||
getViewportOverflowState,
|
getViewportOverflowState,
|
||||||
hideNativeScrollbars
|
hideNativeScrollbars
|
||||||
) => {
|
) => {
|
||||||
const { _flexboxGlue } = getEnvironment();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the styles of the viewport arrange element.
|
* Sets the styles of the viewport arrange element.
|
||||||
* @param viewportOverflowState The viewport overflow state according to which the scrollbars shall be hidden.
|
* @param viewportOverflowState The viewport overflow state according to which the scrollbars shall be hidden.
|
||||||
@@ -182,7 +216,7 @@ export const scrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> = {
|
|||||||
|
|
||||||
removeClass(viewport, classNameViewportArrange);
|
removeClass(viewport, classNameViewportArrange);
|
||||||
|
|
||||||
if (!_flexboxGlue) {
|
if (!flexboxGlue) {
|
||||||
finalPaddingStyle.height = '';
|
finalPaddingStyle.height = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,5 +241,46 @@ export const scrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> = {
|
|||||||
|
|
||||||
return [arrangeViewport, undoViewportArrange];
|
return [arrangeViewport, undoViewportArrange];
|
||||||
},
|
},
|
||||||
|
_envWindowZoom: () => {
|
||||||
|
let size = windowSize();
|
||||||
|
let dpr = getWindowDPR();
|
||||||
|
|
||||||
|
return (envInstance, updateNativeScrollbarSizeCache, triggerEvent) => {
|
||||||
|
const sizeNew = windowSize();
|
||||||
|
const deltaSize = {
|
||||||
|
w: sizeNew.w - size.w,
|
||||||
|
h: sizeNew.h - size.h,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (deltaSize.w === 0 && deltaSize.h === 0) return;
|
||||||
|
|
||||||
|
const deltaAbsSize = {
|
||||||
|
w: abs(deltaSize.w),
|
||||||
|
h: abs(deltaSize.h),
|
||||||
|
};
|
||||||
|
const deltaAbsRatio = {
|
||||||
|
w: abs(round(sizeNew.w / (size.w / 100.0))),
|
||||||
|
h: abs(round(sizeNew.h / (size.h / 100.0))),
|
||||||
|
};
|
||||||
|
const dprNew = getWindowDPR();
|
||||||
|
const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
|
||||||
|
const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
|
||||||
|
const dprChanged = dprNew !== dpr && dpr > 0;
|
||||||
|
const isZoom = deltaIsBigger && difference && dprChanged;
|
||||||
|
|
||||||
|
if (isZoom) {
|
||||||
|
const [scrollbarSize, scrollbarSizeChanged] = updateNativeScrollbarSizeCache();
|
||||||
|
|
||||||
|
assignDeep(envInstance._nativeScrollbarsSize, scrollbarSize); // keep the object same!
|
||||||
|
|
||||||
|
if (scrollbarSizeChanged) {
|
||||||
|
triggerEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeNew;
|
||||||
|
dpr = dprNew;
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import {
|
|||||||
scrollLeft,
|
scrollLeft,
|
||||||
scrollTop,
|
scrollTop,
|
||||||
on,
|
on,
|
||||||
stopAndPrevent,
|
|
||||||
addClass,
|
addClass,
|
||||||
equalWH,
|
equalWH,
|
||||||
push,
|
push,
|
||||||
cAF,
|
cAF,
|
||||||
rAF,
|
rAF,
|
||||||
|
stopPropagation,
|
||||||
} from 'support';
|
} from 'support';
|
||||||
import {
|
import {
|
||||||
classNameSizeObserverListenerScroll,
|
classNameSizeObserverListenerScroll,
|
||||||
@@ -68,7 +68,7 @@ export const sizeObserverPlugin: Plugin<SizeObserverPluginInstance> = {
|
|||||||
isDirty = !scrollEvent || !equalWH(currSize, cacheSize);
|
isDirty = !scrollEvent || !equalWH(currSize, cacheSize);
|
||||||
|
|
||||||
if (scrollEvent) {
|
if (scrollEvent) {
|
||||||
stopAndPrevent(scrollEvent);
|
stopPropagation(scrollEvent);
|
||||||
|
|
||||||
if (isDirty && !rAFId) {
|
if (isDirty && !rAFId) {
|
||||||
cAF!(rAFId);
|
cAF!(rAFId);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
removeClass,
|
removeClass,
|
||||||
removeElements,
|
removeElements,
|
||||||
runEachAndClear,
|
runEachAndClear,
|
||||||
|
setT,
|
||||||
stopPropagation,
|
stopPropagation,
|
||||||
} from 'support';
|
} from 'support';
|
||||||
import {
|
import {
|
||||||
@@ -143,7 +144,7 @@ export const createScrollbarsSetupElements = (
|
|||||||
appendChildren(evaluatedScrollbarSlot, horizontalScrollbars[0]._scrollbar);
|
appendChildren(evaluatedScrollbarSlot, horizontalScrollbars[0]._scrollbar);
|
||||||
appendChildren(evaluatedScrollbarSlot, verticalScrollbars[0]._scrollbar);
|
appendChildren(evaluatedScrollbarSlot, verticalScrollbars[0]._scrollbar);
|
||||||
|
|
||||||
setTimeout(() => {
|
setT(() => {
|
||||||
addRemoveClassHorizontal(classNamesScrollbarTransitionless);
|
addRemoveClassHorizontal(classNamesScrollbarTransitionless);
|
||||||
addRemoveClassVertical(classNamesScrollbarTransitionless);
|
addRemoveClassVertical(classNamesScrollbarTransitionless);
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { rAF, cAF, isFunction, on, runEachAndClear } from 'support';
|
import { rAF, cAF, isFunction, on, runEachAndClear, setT, clearT } from 'support';
|
||||||
import { createState, createOptionCheck } from 'setups/setups';
|
import { createState, createOptionCheck } from 'setups/setups';
|
||||||
import {
|
import {
|
||||||
createScrollbarsSetupElements,
|
createScrollbarsSetupElements,
|
||||||
@@ -29,15 +29,15 @@ export interface ScrollbarsSetupStaticState {
|
|||||||
|
|
||||||
const createSelfCancelTimeout = (timeout?: number | (() => number)) => {
|
const createSelfCancelTimeout = (timeout?: number | (() => number)) => {
|
||||||
let id: number;
|
let id: number;
|
||||||
const setT = timeout ? (setTimeout as (...args: any[]) => number) : rAF!;
|
const setTFn = timeout ? setT : rAF!;
|
||||||
const clearT = timeout ? clearTimeout : cAF!;
|
const clearTFn = timeout ? clearT : cAF!;
|
||||||
return [
|
return [
|
||||||
(callback: () => any) => {
|
(callback: () => any) => {
|
||||||
clearT(id);
|
clearTFn(id);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
id = setT(callback, isFunction(timeout) ? timeout() : timeout);
|
id = setTFn(callback, isFunction(timeout) ? timeout() : timeout);
|
||||||
},
|
},
|
||||||
() => clearT(id),
|
() => clearTFn(id),
|
||||||
] as [timeout: (callback: () => any) => void, clear: () => void];
|
] as [timeout: (callback: () => any) => void, clear: () => void];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ const addDataAttrHost = (elm: HTMLElement, value: string) => {
|
|||||||
export const createStructureSetupElements = (
|
export const createStructureSetupElements = (
|
||||||
target: InitializationTarget
|
target: InitializationTarget
|
||||||
): StructureSetupElements => {
|
): StructureSetupElements => {
|
||||||
const { _getInitializationStrategy, _nativeScrollbarsHiding } = getEnvironment();
|
const env = getEnvironment();
|
||||||
|
const { _getInitializationStrategy, _nativeScrollbarsHiding } = env;
|
||||||
const scrollbarsHidingPlugin = getPlugins()[scrollbarsHidingPluginName] as
|
const scrollbarsHidingPlugin = getPlugins()[scrollbarsHidingPluginName] as
|
||||||
| ScrollbarsHidingPluginInstance
|
| ScrollbarsHidingPluginInstance
|
||||||
| undefined;
|
| undefined;
|
||||||
@@ -156,7 +157,7 @@ export const createStructureSetupElements = (
|
|||||||
!viewportIsTarget &&
|
!viewportIsTarget &&
|
||||||
!_nativeScrollbarsHiding &&
|
!_nativeScrollbarsHiding &&
|
||||||
createUniqueViewportArrangeElement &&
|
createUniqueViewportArrangeElement &&
|
||||||
createUniqueViewportArrangeElement(),
|
createUniqueViewportArrangeElement(env),
|
||||||
_windowElm: wnd,
|
_windowElm: wnd,
|
||||||
_documentElm: ownerDocument,
|
_documentElm: ownerDocument,
|
||||||
_htmlElm: parent(bodyElm) as HTMLHtmlElement,
|
_htmlElm: parent(bodyElm) as HTMLHtmlElement,
|
||||||
|
|||||||
+1
@@ -308,6 +308,7 @@ export const createOverflowUpdateSegment: CreateStructureUpdateSegment = (
|
|||||||
const [arrangeViewport, undoViewportArrange] = scrollbarsHidingPlugin
|
const [arrangeViewport, undoViewportArrange] = scrollbarsHidingPlugin
|
||||||
? scrollbarsHidingPlugin._overflowUpdateSegment(
|
? scrollbarsHidingPlugin._overflowUpdateSegment(
|
||||||
doViewportArrange,
|
doViewportArrange,
|
||||||
|
_flexboxGlue,
|
||||||
_viewport,
|
_viewport,
|
||||||
_viewportArrange,
|
_viewportArrange,
|
||||||
getState,
|
getState,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { jsAPI } from 'support/compatibility/vendors';
|
import { jsAPI } from 'support/compatibility/vendors';
|
||||||
|
|
||||||
export const MutationObserverConstructor = jsAPI<typeof MutationObserver>('MutationObserver');
|
export const MutationObserverConstructor = jsAPI<typeof MutationObserver>('MutationObserver');
|
||||||
export const IntersectionObserverConstructor = jsAPI<typeof IntersectionObserver>(
|
export const IntersectionObserverConstructor =
|
||||||
'IntersectionObserver'
|
jsAPI<typeof IntersectionObserver>('IntersectionObserver');
|
||||||
);
|
|
||||||
export const ResizeObserverConstructor = jsAPI<typeof ResizeObserver>('ResizeObserver');
|
export const ResizeObserverConstructor = jsAPI<typeof ResizeObserver>('ResizeObserver');
|
||||||
export const cAF = jsAPI<typeof cancelAnimationFrame>('cancelAnimationFrame');
|
export const cAF = jsAPI<typeof cancelAnimationFrame>('cancelAnimationFrame');
|
||||||
export const rAF = jsAPI<typeof requestAnimationFrame>('requestAnimationFrame');
|
export const rAF = jsAPI<typeof requestAnimationFrame>('requestAnimationFrame');
|
||||||
|
export const setT = window.setTimeout as (handler: TimerHandler, timeout?: number) => number;
|
||||||
|
export const clearT = window.clearTimeout as (id?: number) => void;
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import { isNumber, isFunction } from 'support/utils/types';
|
import { isNumber, isFunction } from 'support/utils/types';
|
||||||
import { from } from 'support/utils/array';
|
import { from } from 'support/utils/array';
|
||||||
import { rAF, cAF } from 'support/compatibility/apis';
|
import { rAF, cAF, setT, clearT } from 'support/compatibility/apis';
|
||||||
|
|
||||||
const clearTimeouts = (id: number | undefined) => {
|
|
||||||
id && clearTimeout(id);
|
|
||||||
id && cAF!(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
type DebounceTiming = number | false | null | undefined;
|
type DebounceTiming = number | false | null | undefined;
|
||||||
|
|
||||||
@@ -44,17 +39,17 @@ export const debounce = <FunctionToDebounce extends (...args: any) => any>(
|
|||||||
functionToDebounce: FunctionToDebounce,
|
functionToDebounce: FunctionToDebounce,
|
||||||
options?: DebounceOptions<FunctionToDebounce>
|
options?: DebounceOptions<FunctionToDebounce>
|
||||||
): Debounced<FunctionToDebounce> => {
|
): Debounced<FunctionToDebounce> => {
|
||||||
let timeoutId: number | undefined;
|
|
||||||
let maxTimeoutId: number | undefined;
|
let maxTimeoutId: number | undefined;
|
||||||
let prevArguments: Parameters<FunctionToDebounce> | null | undefined;
|
let prevArguments: Parameters<FunctionToDebounce> | null | undefined;
|
||||||
let latestArguments: Parameters<FunctionToDebounce> | null | undefined;
|
let latestArguments: Parameters<FunctionToDebounce> | null | undefined;
|
||||||
|
let clear: () => void = noop;
|
||||||
const { _timeout, _maxDelay, _mergeParams } = options || {};
|
const { _timeout, _maxDelay, _mergeParams } = options || {};
|
||||||
const setT = setTimeout as (...args: any[]) => number;
|
|
||||||
|
|
||||||
const invokeFunctionToDebounce = function (args: IArguments) {
|
const invokeFunctionToDebounce = function (args: IArguments) {
|
||||||
clearTimeouts(timeoutId);
|
clear();
|
||||||
clearTimeouts(maxTimeoutId);
|
clearT(maxTimeoutId);
|
||||||
maxTimeoutId = timeoutId = prevArguments = undefined;
|
maxTimeoutId = prevArguments = undefined;
|
||||||
|
clear = noop;
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
functionToDebounce.apply(this, args);
|
functionToDebounce.apply(this, args);
|
||||||
@@ -67,7 +62,7 @@ export const debounce = <FunctionToDebounce extends (...args: any) => any>(
|
|||||||
|
|
||||||
const flush = () => {
|
const flush = () => {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (timeoutId) {
|
if (clear !== noop) {
|
||||||
invokeFunctionToDebounce(mergeParms(latestArguments!) || latestArguments!);
|
invokeFunctionToDebounce(mergeParms(latestArguments!) || latestArguments!);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -82,6 +77,7 @@ export const debounce = <FunctionToDebounce extends (...args: any) => any>(
|
|||||||
const finalMaxWait = isFunction(_maxDelay) ? _maxDelay() : _maxDelay;
|
const finalMaxWait = isFunction(_maxDelay) ? _maxDelay() : _maxDelay;
|
||||||
const hasMaxWait = isNumber(finalMaxWait) && finalMaxWait >= 0;
|
const hasMaxWait = isNumber(finalMaxWait) && finalMaxWait >= 0;
|
||||||
const setTimeoutFn = finalTimeout > 0 ? setT : rAF!;
|
const setTimeoutFn = finalTimeout > 0 ? setT : rAF!;
|
||||||
|
const clearTimeoutFn = finalTimeout > 0 ? clearT : cAF!;
|
||||||
const mergeParamsResult = mergeParms(args);
|
const mergeParamsResult = mergeParms(args);
|
||||||
const invokedArgs = mergeParamsResult || args;
|
const invokedArgs = mergeParamsResult || args;
|
||||||
const boundInvoke = invokeFunctionToDebounce.bind(0, invokedArgs);
|
const boundInvoke = invokeFunctionToDebounce.bind(0, invokedArgs);
|
||||||
@@ -90,9 +86,10 @@ export const debounce = <FunctionToDebounce extends (...args: any) => any>(
|
|||||||
// invokeFunctionToDebounce(prevArguments || args);
|
// invokeFunctionToDebounce(prevArguments || args);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
clearTimeouts(timeoutId);
|
clear();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
timeoutId = setTimeoutFn(boundInvoke, finalTimeout as number) as number;
|
const timeoutId = setTimeoutFn(boundInvoke, finalTimeout);
|
||||||
|
clear = () => clearTimeoutFn(timeoutId);
|
||||||
|
|
||||||
if (hasMaxWait && !maxTimeoutId) {
|
if (hasMaxWait && !maxTimeoutId) {
|
||||||
maxTimeoutId = setT(flush, finalMaxWait as number);
|
maxTimeoutId = setT(flush, finalMaxWait as number);
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
import { noop, debounce } from 'support/utils/function';
|
import { noop, debounce } from 'support/utils/function';
|
||||||
import { rAF } from 'support/compatibility/apis';
|
import { rAF, setT } from 'support/compatibility/apis';
|
||||||
|
|
||||||
jest.mock('support/compatibility/apis', () => {
|
jest.mock('support/compatibility/apis', () => {
|
||||||
const originalModule = jest.requireActual('support/compatibility/apis');
|
const originalModule = jest.requireActual('support/compatibility/apis');
|
||||||
return {
|
return {
|
||||||
...originalModule,
|
...originalModule,
|
||||||
rAF: jest.fn().mockImplementation((...args) => originalModule.rAF(...args)),
|
rAF: jest.fn().mockImplementation((...args) => originalModule.rAF(...args)),
|
||||||
|
setT: jest.fn().mockImplementation((...args) => originalModule.setT(...args)),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockSetTimeout = () => {
|
|
||||||
const original = window.setTimeout;
|
|
||||||
// @ts-ignore
|
|
||||||
const setT = (window.setTimeout = jest.fn((...args) => original(...args)));
|
|
||||||
return [
|
|
||||||
setT,
|
|
||||||
() => {
|
|
||||||
window.setTimeout = original;
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-return-await
|
// eslint-disable-next-line no-return-await
|
||||||
const timeout = async (timeout = 100) => await new Promise((r) => setTimeout(r, timeout));
|
const timeout = async (timeout = 100) => await new Promise((r) => setTimeout(r, timeout));
|
||||||
|
|
||||||
@@ -34,7 +23,6 @@ describe('function', () => {
|
|||||||
describe('timeout', () => {
|
describe('timeout', () => {
|
||||||
test('without timeout', () => {
|
test('without timeout', () => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const [setT, unmockSetTimeout] = mockSetTimeout();
|
|
||||||
const debouncedFn = debounce(() => {
|
const debouncedFn = debounce(() => {
|
||||||
i += 1;
|
i += 1;
|
||||||
});
|
});
|
||||||
@@ -44,12 +32,10 @@ describe('function', () => {
|
|||||||
expect(rAF).not.toHaveBeenCalled();
|
expect(rAF).not.toHaveBeenCalled();
|
||||||
expect(setT).not.toHaveBeenCalled();
|
expect(setT).not.toHaveBeenCalled();
|
||||||
expect(i).toBe(1);
|
expect(i).toBe(1);
|
||||||
unmockSetTimeout();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('with timeout 0', async () => {
|
test('with timeout 0', async () => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const [setT, unmockSetTimeout] = mockSetTimeout();
|
|
||||||
const debouncedFn = debounce(
|
const debouncedFn = debounce(
|
||||||
() => {
|
() => {
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -67,12 +53,10 @@ describe('function', () => {
|
|||||||
await timeout();
|
await timeout();
|
||||||
|
|
||||||
expect(i).toBe(1);
|
expect(i).toBe(1);
|
||||||
unmockSetTimeout();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('with timeout > 0', async () => {
|
test('with timeout > 0', async () => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const [setT, unmockSetTimeout] = mockSetTimeout();
|
|
||||||
const debouncedFn = debounce(
|
const debouncedFn = debounce(
|
||||||
() => {
|
() => {
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -89,8 +73,6 @@ describe('function', () => {
|
|||||||
expect(i).toBe(0);
|
expect(i).toBe(0);
|
||||||
await timeout();
|
await timeout();
|
||||||
expect(i).toBe(1);
|
expect(i).toBe(1);
|
||||||
|
|
||||||
unmockSetTimeout();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('with timeout > 0 and multiple calls', async () => {
|
test('with timeout > 0 and multiple calls', async () => {
|
||||||
|
|||||||
+1
@@ -30,6 +30,7 @@ if (!window.ResizeObserver) {
|
|||||||
addPlugin(sizeObserverPlugin);
|
addPlugin(sizeObserverPlugin);
|
||||||
}
|
}
|
||||||
if (!OverlayScrollbars.env().scrollbarsHiding) {
|
if (!OverlayScrollbars.env().scrollbarsHiding) {
|
||||||
|
console.log('added');
|
||||||
addPlugin(scrollbarsHidingPlugin);
|
addPlugin(scrollbarsHidingPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,8 +104,6 @@ body {
|
|||||||
background: blue;
|
background: blue;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
height: 10000px;
|
|
||||||
width: 10000px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.percent {
|
.percent {
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export {};
|
|
||||||
Reference in New Issue
Block a user