mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-25 19:44:06 +03:00
add drag scrolling & improve code
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import type { StructureSetupState } from 'setups';
|
||||
|
||||
const { min, max } = Math;
|
||||
export const getScrollbarHandleLengthRatio = (
|
||||
structureSetupState: StructureSetupState,
|
||||
isHorizontal?: boolean
|
||||
) => {
|
||||
const { _overflowAmount, _overflowEdge } = structureSetupState;
|
||||
const axis = isHorizontal ? 'x' : 'y';
|
||||
const viewportSize = _overflowEdge[axis];
|
||||
const overflowAmount = _overflowAmount[axis];
|
||||
return max(0, min(1, viewportSize / (viewportSize + overflowAmount)));
|
||||
};
|
||||
export const getScrollbarHandleOffsetRatio = (
|
||||
structureSetupState: StructureSetupState,
|
||||
scrollOffsetElement: HTMLElement,
|
||||
isHorizontal?: boolean
|
||||
) => {
|
||||
const axis = isHorizontal ? 'x' : 'y';
|
||||
const scrollLeftTop = isHorizontal ? 'Left' : 'Top';
|
||||
const lengthRatio = getScrollbarHandleLengthRatio(structureSetupState, isHorizontal);
|
||||
const scrollPosition = scrollOffsetElement[`scroll${scrollLeftTop}`] as number;
|
||||
const scrollPositionMax = Math.floor(structureSetupState._overflowAmount[axis]);
|
||||
const scrollPercent = min(1, scrollPosition / scrollPositionMax);
|
||||
|
||||
return (1 / lengthRatio) * (1 - lengthRatio) * scrollPercent;
|
||||
};
|
||||
@@ -3,15 +3,13 @@ import {
|
||||
appendChildren,
|
||||
createDiv,
|
||||
each,
|
||||
isBoolean,
|
||||
isEmptyArray,
|
||||
noop,
|
||||
on,
|
||||
push,
|
||||
removeClass,
|
||||
removeElements,
|
||||
runEachAndClear,
|
||||
setT,
|
||||
stopPropagation,
|
||||
style,
|
||||
} from 'support';
|
||||
import {
|
||||
@@ -20,18 +18,18 @@ import {
|
||||
classNameScrollbarVertical,
|
||||
classNameScrollbarTrack,
|
||||
classNameScrollbarHandle,
|
||||
classNamesScrollbarInteraction,
|
||||
classNamesScrollbarTransitionless,
|
||||
} from 'classnames';
|
||||
import { getEnvironment } from 'environment';
|
||||
import { dynamicInitializationElement as generalDynamicInitializationElement } from 'initialization';
|
||||
import type { InitializationTarget } from 'initialization';
|
||||
import type { StructureSetupElementsObj } from 'setups/structureSetup/structureSetup.elements';
|
||||
import type { ScrollbarsSetupEvents } from 'setups/scrollbarsSetup/scrollbarsSetup.events';
|
||||
import type {
|
||||
ScrollbarsInitialization,
|
||||
ScrollbarsDynamicInitializationElement,
|
||||
} from 'setups/scrollbarsSetup/scrollbarsSetup.initialization';
|
||||
import { StyleObject } from 'typings';
|
||||
import type { StyleObject } from 'typings';
|
||||
|
||||
export interface ScrollbarStructure {
|
||||
_scrollbar: HTMLElement;
|
||||
@@ -42,24 +40,19 @@ export interface ScrollbarStructure {
|
||||
export interface ScrollbarsSetupElement {
|
||||
_scrollbarStructures: ScrollbarStructure[];
|
||||
_clone: () => ScrollbarStructure;
|
||||
_addRemoveClass: (
|
||||
classNames: string | false | null | undefined,
|
||||
add?: boolean,
|
||||
elm?: (scrollbarStructure: ScrollbarStructure) => HTMLElement | false | null | undefined
|
||||
) => void;
|
||||
_handleStyle: (
|
||||
elmStyle: (
|
||||
scrollbarStructure: ScrollbarStructure
|
||||
) => [HTMLElement | false | null | undefined, StyleObject]
|
||||
) => void;
|
||||
// _removeClass: (classNames: string) => void;
|
||||
/*
|
||||
_addEventListener: () => void;
|
||||
_removeEventListener: () => void;
|
||||
*/
|
||||
}
|
||||
|
||||
export interface ScrollbarsSetupElementsObj {
|
||||
_scrollbarsAddRemoveClass: (
|
||||
classNames: string | false | null | undefined,
|
||||
add?: boolean,
|
||||
isHorizontal?: boolean
|
||||
) => void;
|
||||
_horizontal: ScrollbarsSetupElement;
|
||||
_vertical: ScrollbarsSetupElement;
|
||||
}
|
||||
@@ -70,23 +63,15 @@ export type ScrollbarsSetupElements = [
|
||||
destroy: () => void
|
||||
];
|
||||
|
||||
const interactionStartEventNames = 'touchstart mouseenter';
|
||||
const interactionEndEventNames = 'touchend touchcancel mouseleave';
|
||||
const stopRootClickPropagation = (scrollbar: HTMLElement, documentElm: Document) =>
|
||||
on(
|
||||
scrollbar,
|
||||
'mousedown',
|
||||
on.bind(0, documentElm, 'click', stopPropagation, { _once: true, _capture: true }),
|
||||
{ _capture: true }
|
||||
);
|
||||
|
||||
export const createScrollbarsSetupElements = (
|
||||
target: InitializationTarget,
|
||||
structureSetupElements: StructureSetupElementsObj
|
||||
structureSetupElements: StructureSetupElementsObj,
|
||||
scrollbarsSetupEvents: ScrollbarsSetupEvents
|
||||
): ScrollbarsSetupElements => {
|
||||
const { _getDefaultInitialization } = getEnvironment();
|
||||
const { scrollbarsSlot: defaultScrollbarsSlot } = _getDefaultInitialization();
|
||||
const { _documentElm, _target, _host, _viewport, _targetIsElm } = structureSetupElements;
|
||||
const { _documentElm, _target, _host, _viewport, _targetIsElm, _scrollOffsetElement } =
|
||||
structureSetupElements;
|
||||
const { scrollbarsSlot } = (_targetIsElm ? {} : target) as ScrollbarsInitialization;
|
||||
const evaluatedScrollbarSlot =
|
||||
generalDynamicInitializationElement<ScrollbarsDynamicInitializationElement>(
|
||||
@@ -95,15 +80,14 @@ export const createScrollbarsSetupElements = (
|
||||
defaultScrollbarsSlot,
|
||||
scrollbarsSlot
|
||||
);
|
||||
const scrollbarsAddRemoveClass = (
|
||||
const scrollbarStructureAddRemoveClass = (
|
||||
scrollbarStructures: ScrollbarStructure[],
|
||||
classNames: string | false | null | undefined,
|
||||
add?: boolean,
|
||||
elm?: (scrollbarStructure: ScrollbarStructure) => HTMLElement | false | null | undefined
|
||||
add?: boolean
|
||||
) => {
|
||||
const action = add ? addClass : removeClass;
|
||||
each(scrollbarStructures, (scrollbarStructure) => {
|
||||
action((elm || noop)(scrollbarStructure) || scrollbarStructure._scrollbar, classNames);
|
||||
action(scrollbarStructure._scrollbar, classNames);
|
||||
});
|
||||
};
|
||||
const scrollbarsHandleStyle = (
|
||||
@@ -121,13 +105,22 @@ export const createScrollbarsSetupElements = (
|
||||
const horizontalScrollbars: ScrollbarStructure[] = [];
|
||||
const verticalScrollbars: ScrollbarStructure[] = [];
|
||||
|
||||
const addRemoveClassHorizontal = scrollbarsAddRemoveClass.bind(0, horizontalScrollbars);
|
||||
const addRemoveClassVertical = scrollbarsAddRemoveClass.bind(0, verticalScrollbars);
|
||||
const generateScrollbarDOM = (horizontal?: boolean): ScrollbarStructure => {
|
||||
const scrollbarClassName = horizontal
|
||||
const scrollbarsAddRemoveClass = (
|
||||
className: string | false | null | undefined,
|
||||
add?: boolean,
|
||||
onlyHorizontal?: boolean
|
||||
) => {
|
||||
const singleAxis = isBoolean(onlyHorizontal);
|
||||
const runHorizontal = singleAxis ? onlyHorizontal : true;
|
||||
const runVertical = singleAxis ? !onlyHorizontal : true;
|
||||
runHorizontal && scrollbarStructureAddRemoveClass(horizontalScrollbars, className, add);
|
||||
runVertical && scrollbarStructureAddRemoveClass(verticalScrollbars, className, add);
|
||||
};
|
||||
const generateScrollbarDOM = (isHorizontal?: boolean): ScrollbarStructure => {
|
||||
const scrollbarClassName = isHorizontal
|
||||
? classNameScrollbarHorizontal
|
||||
: classNameScrollbarVertical;
|
||||
const arrToPush = horizontal ? horizontalScrollbars : verticalScrollbars;
|
||||
const arrToPush = isHorizontal ? horizontalScrollbars : verticalScrollbars;
|
||||
const transitionlessClass = isEmptyArray(arrToPush) ? classNamesScrollbarTransitionless : '';
|
||||
const scrollbar = createDiv(
|
||||
`${classNameScrollbar} ${scrollbarClassName} ${transitionlessClass}`
|
||||
@@ -146,15 +139,13 @@ export const createScrollbarsSetupElements = (
|
||||
push(arrToPush, result);
|
||||
push(destroyFns, [
|
||||
removeElements.bind(0, scrollbar),
|
||||
on(scrollbar, interactionStartEventNames, () => {
|
||||
addRemoveClassHorizontal(classNamesScrollbarInteraction, true);
|
||||
addRemoveClassVertical(classNamesScrollbarInteraction, true);
|
||||
}),
|
||||
on(scrollbar, interactionEndEventNames, () => {
|
||||
addRemoveClassHorizontal(classNamesScrollbarInteraction);
|
||||
addRemoveClassVertical(classNamesScrollbarInteraction);
|
||||
}),
|
||||
stopRootClickPropagation(scrollbar, _documentElm),
|
||||
scrollbarsSetupEvents(
|
||||
result,
|
||||
scrollbarsAddRemoveClass,
|
||||
_documentElm,
|
||||
_scrollOffsetElement,
|
||||
isHorizontal
|
||||
),
|
||||
]);
|
||||
|
||||
return result;
|
||||
@@ -166,8 +157,7 @@ export const createScrollbarsSetupElements = (
|
||||
appendChildren(evaluatedScrollbarSlot, verticalScrollbars[0]._scrollbar);
|
||||
|
||||
setT(() => {
|
||||
addRemoveClassHorizontal(classNamesScrollbarTransitionless);
|
||||
addRemoveClassVertical(classNamesScrollbarTransitionless);
|
||||
scrollbarsAddRemoveClass(classNamesScrollbarTransitionless);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
@@ -176,16 +166,15 @@ export const createScrollbarsSetupElements = (
|
||||
|
||||
return [
|
||||
{
|
||||
_scrollbarsAddRemoveClass: scrollbarsAddRemoveClass,
|
||||
_horizontal: {
|
||||
_scrollbarStructures: horizontalScrollbars,
|
||||
_clone: generateHorizontalScrollbarStructure,
|
||||
_addRemoveClass: addRemoveClassHorizontal,
|
||||
_handleStyle: scrollbarsHandleStyle.bind(0, horizontalScrollbars),
|
||||
},
|
||||
_vertical: {
|
||||
_scrollbarStructures: verticalScrollbars,
|
||||
_clone: generateVerticalScrollbarStructure,
|
||||
_addRemoveClass: addRemoveClassVertical,
|
||||
_handleStyle: scrollbarsHandleStyle.bind(0, verticalScrollbars),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
getBoundingClientRect,
|
||||
offsetSize,
|
||||
on,
|
||||
preventDefault,
|
||||
runEachAndClear,
|
||||
stopPropagation,
|
||||
XY,
|
||||
} from 'support';
|
||||
import { classNamesScrollbarInteraction } from 'classnames';
|
||||
import { getScrollbarHandleOffsetRatio } from 'setups/scrollbarsSetup/scrollbarsSetup.calculations';
|
||||
import type { StructureSetupState } from 'setups';
|
||||
import type {
|
||||
ScrollbarsSetupElementsObj,
|
||||
ScrollbarStructure,
|
||||
} from 'setups/scrollbarsSetup/scrollbarsSetup.elements';
|
||||
|
||||
export type ScrollbarsSetupEvents = (
|
||||
scrollbarStructure: ScrollbarStructure,
|
||||
scrollbarsAddRemoveClass: ScrollbarsSetupElementsObj['_scrollbarsAddRemoveClass'],
|
||||
documentElm: Document,
|
||||
scrollOffsetElm: HTMLElement,
|
||||
isHorizontal?: boolean
|
||||
) => () => void;
|
||||
|
||||
const getPageOffset = (event: PointerEvent): XY<number> => ({
|
||||
x: event.pageX,
|
||||
y: event.pageY,
|
||||
});
|
||||
const getInvertedScale = (element: HTMLElement): XY<number> => {
|
||||
const { width, height } = getBoundingClientRect(element);
|
||||
const { w, h } = offsetSize(element);
|
||||
return {
|
||||
x: 1 / (Math.round(width) / w) || 1,
|
||||
y: 1 / (Math.round(height) / h) || 1,
|
||||
};
|
||||
};
|
||||
const createRootClickStopPropagationEvents = (scrollbar: HTMLElement, documentElm: Document) =>
|
||||
on(
|
||||
scrollbar,
|
||||
'mousedown',
|
||||
on.bind(0, documentElm, 'click', stopPropagation, { _once: true, _capture: true }),
|
||||
{ _capture: true }
|
||||
);
|
||||
const createDragScrollingEvents = (
|
||||
doc: Document,
|
||||
scrollbarHandle: HTMLElement,
|
||||
scrollOffsetElement: HTMLElement,
|
||||
structureSetupState: () => StructureSetupState,
|
||||
isHorizontal?: boolean
|
||||
) => {
|
||||
const scrollOffsetKey = `scroll${isHorizontal ? 'Left' : 'Top'}`;
|
||||
const xyKey = `${isHorizontal ? 'x' : 'y'}`;
|
||||
const createOnPointerMoveHandler =
|
||||
(mouseDownScroll: number, mouseDownPageOffset: number, mouseDownInvertedScale: number) =>
|
||||
(event: PointerEvent) => {
|
||||
const movement = (getPageOffset(event)[xyKey] - mouseDownPageOffset) * mouseDownInvertedScale;
|
||||
const handleLengthRatio =
|
||||
1 / getScrollbarHandleOffsetRatio(structureSetupState(), scrollOffsetElement, isHorizontal);
|
||||
scrollOffsetElement[scrollOffsetKey] = mouseDownScroll + movement * handleLengthRatio;
|
||||
// if (_isRTL && isHorizontal && !_rtlScrollBehavior.i) scrollDelta *= -1;
|
||||
};
|
||||
|
||||
return on(scrollbarHandle, 'pointerdown', (pointerDownEvent: PointerEvent) => {
|
||||
const { button, isPrimary, pointerId } = pointerDownEvent;
|
||||
|
||||
if (button === 0 && isPrimary) {
|
||||
const mouseDownScroll = scrollOffsetElement[scrollOffsetKey] || 0;
|
||||
const mouseDownPageOffset = getPageOffset(pointerDownEvent)[xyKey];
|
||||
const mouseDownInvertedScale = getInvertedScale(scrollOffsetElement)[xyKey];
|
||||
const offSelectStart = on(doc, 'selectstart', (event: Event) => preventDefault(event), {
|
||||
_passive: false,
|
||||
});
|
||||
const offPointerMove = on(
|
||||
scrollbarHandle,
|
||||
'pointermove',
|
||||
createOnPointerMoveHandler(mouseDownScroll, mouseDownPageOffset, mouseDownInvertedScale)
|
||||
);
|
||||
|
||||
on(
|
||||
scrollbarHandle,
|
||||
'pointerup',
|
||||
(pointerUpEvent: PointerEvent) => {
|
||||
offSelectStart();
|
||||
offPointerMove();
|
||||
scrollbarHandle.releasePointerCapture(pointerUpEvent.pointerId);
|
||||
},
|
||||
{ _once: true }
|
||||
);
|
||||
scrollbarHandle.setPointerCapture(pointerId);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const createScrollbarsSetupEvents =
|
||||
(structureSetupState: () => StructureSetupState): ScrollbarsSetupEvents =>
|
||||
(scrollbarStructure, scrollbarsAddRemoveClass, documentElm, scrollOffsetElm, isHorizontal) => {
|
||||
const { _scrollbar, _handle } = scrollbarStructure;
|
||||
|
||||
return runEachAndClear.bind(0, [
|
||||
on(_scrollbar, 'pointerenter', () => {
|
||||
scrollbarsAddRemoveClass(classNamesScrollbarInteraction, true);
|
||||
}),
|
||||
on(_scrollbar, 'pointerleave pointercancel', () => {
|
||||
scrollbarsAddRemoveClass(classNamesScrollbarInteraction);
|
||||
}),
|
||||
createRootClickStopPropagationEvents(_scrollbar, documentElm),
|
||||
createDragScrollingEvents(
|
||||
documentElm,
|
||||
_handle,
|
||||
scrollOffsetElm,
|
||||
structureSetupState,
|
||||
isHorizontal
|
||||
),
|
||||
]);
|
||||
};
|
||||
@@ -11,6 +11,11 @@ import {
|
||||
scrollTop,
|
||||
} from 'support';
|
||||
import { createState, createOptionCheck } from 'setups/setups';
|
||||
import {
|
||||
getScrollbarHandleLengthRatio,
|
||||
getScrollbarHandleOffsetRatio,
|
||||
} from 'setups/scrollbarsSetup/scrollbarsSetup.calculations';
|
||||
import { createScrollbarsSetupEvents } from 'setups/scrollbarsSetup/scrollbarsSetup.events';
|
||||
import {
|
||||
createScrollbarsSetupElements,
|
||||
ScrollbarsSetupElement,
|
||||
@@ -40,7 +45,6 @@ export interface ScrollbarsSetupStaticState {
|
||||
_appendElements: () => void;
|
||||
}
|
||||
|
||||
const { min } = Math;
|
||||
const createSelfCancelTimeout = (timeout?: number | (() => number)) => {
|
||||
let id: number;
|
||||
const setTFn = timeout ? setT : rAF!;
|
||||
@@ -55,17 +59,6 @@ const createSelfCancelTimeout = (timeout?: number | (() => number)) => {
|
||||
] as [timeout: (callback: () => any) => void, clear: () => void];
|
||||
};
|
||||
|
||||
const getScrollbarHandleRatio = (
|
||||
structureSetupState: StructureSetupState,
|
||||
isHorizontal?: boolean
|
||||
) => {
|
||||
const { _overflowAmount, _overflowEdge } = structureSetupState;
|
||||
const axis = isHorizontal ? 'x' : 'y';
|
||||
const viewportSize = _overflowEdge[axis];
|
||||
const overflowAmount = _overflowAmount[axis];
|
||||
return min(1, viewportSize / (viewportSize + overflowAmount));
|
||||
};
|
||||
|
||||
const refreshScrollbarHandleLength = (
|
||||
setStyleFn: ScrollbarsSetupElement['_handleStyle'],
|
||||
structureSetupState: StructureSetupState,
|
||||
@@ -75,7 +68,7 @@ const refreshScrollbarHandleLength = (
|
||||
structure._handle,
|
||||
{
|
||||
[isHorizontal ? 'width' : 'height']: `${(
|
||||
getScrollbarHandleRatio(structureSetupState, isHorizontal) * 100
|
||||
getScrollbarHandleLengthRatio(structureSetupState, isHorizontal) * 100
|
||||
).toFixed(3)}%`,
|
||||
},
|
||||
]);
|
||||
@@ -83,28 +76,23 @@ const refreshScrollbarHandleLength = (
|
||||
const refreshScrollbarHandleOffset = (
|
||||
setStyleFn: ScrollbarsSetupElement['_handleStyle'],
|
||||
structureSetupState: StructureSetupState,
|
||||
viewport: HTMLElement,
|
||||
scrollOffsetElement: HTMLElement,
|
||||
isHorizontal?: boolean
|
||||
) => {
|
||||
const axis = isHorizontal ? 'x' : 'y';
|
||||
const translateAxis = isHorizontal ? 'X' : 'Y';
|
||||
const scrollLeftTop = isHorizontal ? 'Left' : 'Top';
|
||||
const handleRatio = getScrollbarHandleRatio(structureSetupState, isHorizontal);
|
||||
const scrollPosition = viewport[`scroll${scrollLeftTop}`] as number;
|
||||
const scrollPositionMax =
|
||||
(viewport[`scroll${scrollLeftTop}Max`] as number) ||
|
||||
Math.floor(structureSetupState._overflowAmount[axis]);
|
||||
const offsetRatio = getScrollbarHandleOffsetRatio(
|
||||
structureSetupState,
|
||||
scrollOffsetElement,
|
||||
isHorizontal
|
||||
);
|
||||
// eslint-disable-next-line no-self-compare
|
||||
const validOffsetRatio = offsetRatio === offsetRatio; // is false when offset is NaN
|
||||
|
||||
setStyleFn((structure) => [
|
||||
structure._handle,
|
||||
{
|
||||
transform: scrollPositionMax
|
||||
? `translate${translateAxis}(${(
|
||||
(1 / handleRatio) *
|
||||
(1 - handleRatio) *
|
||||
(scrollPosition / scrollPositionMax) *
|
||||
100
|
||||
).toFixed(3)}%)`
|
||||
transform: validOffsetRatio
|
||||
? `translate${translateAxis}(${(offsetRatio * 100).toFixed(3)}%)`
|
||||
: '',
|
||||
},
|
||||
]);
|
||||
@@ -131,34 +119,38 @@ export const createScrollbarsSetup = (
|
||||
const [auotHideTimeout, clearAutoTimeout] = createSelfCancelTimeout(() => globalAutoHideDelay);
|
||||
const [elements, appendElements, destroyElements] = createScrollbarsSetupElements(
|
||||
target,
|
||||
structureSetupState._elements
|
||||
structureSetupState._elements,
|
||||
createScrollbarsSetupEvents(structureSetupState)
|
||||
);
|
||||
const { _host, _viewport, _viewportIsTarget, _isBody, _documentElm } =
|
||||
structureSetupState._elements;
|
||||
const scrollOffsetElement = _isBody ? _documentElm.documentElement : _viewport;
|
||||
const { _horizontal, _vertical } = elements;
|
||||
const { _addRemoveClass: addRemoveClassHorizontal, _handleStyle: styleHorizontal } = _horizontal;
|
||||
const { _addRemoveClass: addRemoveClassVertical, _handleStyle: styleVertical } = _vertical;
|
||||
const {
|
||||
_host,
|
||||
_viewport,
|
||||
_scrollOffsetElement,
|
||||
_scrollEventElement,
|
||||
_viewportIsTarget,
|
||||
_isBody,
|
||||
} = structureSetupState._elements;
|
||||
const { _horizontal, _vertical, _scrollbarsAddRemoveClass: scrollbarsAddRemoveClass } = elements;
|
||||
const { _handleStyle: styleHorizontal } = _horizontal;
|
||||
const { _handleStyle: styleVertical } = _vertical;
|
||||
const styleScrollbarPosition = (structure: ScrollbarStructure) => {
|
||||
const { _scrollbar } = structure;
|
||||
const elm = _viewportIsTarget && !_isBody && parent(_scrollbar) === _viewport && _scrollbar;
|
||||
return [
|
||||
elm,
|
||||
{
|
||||
transform: elm ? `translate(${scrollLeft(_viewport)}px, ${scrollTop(_viewport)}px)` : '',
|
||||
transform: elm
|
||||
? `translate(${scrollLeft(_scrollOffsetElement)}px, ${scrollTop(_scrollOffsetElement)}px)`
|
||||
: '',
|
||||
},
|
||||
] as [HTMLElement | false, StyleObject];
|
||||
};
|
||||
const manageScrollbarsAutoHide = (removeAutoHide: boolean, delayless?: boolean) => {
|
||||
clearAutoTimeout();
|
||||
if (removeAutoHide) {
|
||||
addRemoveClassHorizontal(classNamesScrollbarAutoHidden);
|
||||
addRemoveClassVertical(classNamesScrollbarAutoHidden);
|
||||
scrollbarsAddRemoveClass(classNamesScrollbarAutoHidden);
|
||||
} else {
|
||||
const hide = () => {
|
||||
addRemoveClassHorizontal(classNamesScrollbarAutoHidden, true);
|
||||
addRemoveClassVertical(classNamesScrollbarAutoHidden, true);
|
||||
};
|
||||
const hide = () => scrollbarsAddRemoveClass(classNamesScrollbarAutoHidden, true);
|
||||
if (globalAutoHideDelay > 0 && !delayless) {
|
||||
auotHideTimeout(hide);
|
||||
} else {
|
||||
@@ -195,11 +187,11 @@ export const createScrollbarsSetup = (
|
||||
});
|
||||
});
|
||||
}),
|
||||
on(_isBody ? _documentElm : _viewport, 'scroll', () => {
|
||||
on(_scrollEventElement, 'scroll', () => {
|
||||
requestScrollAnimationFrame(() => {
|
||||
const structureState = structureSetupState();
|
||||
refreshScrollbarHandleOffset(styleHorizontal, structureState, scrollOffsetElement, true);
|
||||
refreshScrollbarHandleOffset(styleVertical, structureState, scrollOffsetElement);
|
||||
refreshScrollbarHandleOffset(styleHorizontal, structureState, _scrollOffsetElement, true);
|
||||
refreshScrollbarHandleOffset(styleVertical, structureState, _scrollOffsetElement);
|
||||
|
||||
autoHideNotNever && manageScrollbarsAutoHide(true);
|
||||
scrollTimeout(() => {
|
||||
@@ -237,13 +229,10 @@ export const createScrollbarsSetup = (
|
||||
const updateHandle = _overflowEdgeChanged || _overflowAmountChanged;
|
||||
const updateVisibility = _overflowStyleChanged || visibilityChanged;
|
||||
|
||||
const setScrollbarVisibility = (
|
||||
overflowStyle: OverflowStyle,
|
||||
addRemoveClass: (classNames: string, add?: boolean) => void
|
||||
) => {
|
||||
const setScrollbarVisibility = (overflowStyle: OverflowStyle, isHorizontal: boolean) => {
|
||||
const isVisible =
|
||||
visibility === 'visible' || (visibility === 'auto' && overflowStyle === 'scroll');
|
||||
addRemoveClass(classNamesScrollbarVisible, isVisible);
|
||||
scrollbarsAddRemoveClass(classNamesScrollbarVisible, isVisible, isHorizontal);
|
||||
return isVisible;
|
||||
};
|
||||
|
||||
@@ -252,19 +241,16 @@ export const createScrollbarsSetup = (
|
||||
if (updateVisibility) {
|
||||
const { _overflowStyle } = currStructureSetupState;
|
||||
|
||||
const xVisible = setScrollbarVisibility(_overflowStyle.x, addRemoveClassHorizontal);
|
||||
const yVisible = setScrollbarVisibility(_overflowStyle.y, addRemoveClassVertical);
|
||||
const xVisible = setScrollbarVisibility(_overflowStyle.x, true);
|
||||
const yVisible = setScrollbarVisibility(_overflowStyle.y, false);
|
||||
const hasCorner = xVisible && yVisible;
|
||||
|
||||
addRemoveClassHorizontal(classNamesScrollbarCornerless, !hasCorner);
|
||||
addRemoveClassVertical(classNamesScrollbarCornerless, !hasCorner);
|
||||
scrollbarsAddRemoveClass(classNamesScrollbarCornerless, !hasCorner);
|
||||
}
|
||||
if (themeChanged) {
|
||||
addRemoveClassHorizontal(prevTheme);
|
||||
addRemoveClassVertical(prevTheme);
|
||||
scrollbarsAddRemoveClass(prevTheme);
|
||||
scrollbarsAddRemoveClass(theme, true);
|
||||
|
||||
addRemoveClassHorizontal(theme, true);
|
||||
addRemoveClassVertical(theme, true);
|
||||
prevTheme = theme;
|
||||
}
|
||||
if (autoHideChanged) {
|
||||
@@ -280,10 +266,10 @@ export const createScrollbarsSetup = (
|
||||
refreshScrollbarHandleOffset(
|
||||
styleHorizontal,
|
||||
currStructureSetupState,
|
||||
scrollOffsetElement,
|
||||
_scrollOffsetElement,
|
||||
true
|
||||
);
|
||||
refreshScrollbarHandleOffset(styleVertical, currStructureSetupState, scrollOffsetElement);
|
||||
refreshScrollbarHandleOffset(styleVertical, currStructureSetupState, _scrollOffsetElement);
|
||||
}
|
||||
},
|
||||
scrollbarsSetupState,
|
||||
|
||||
@@ -60,6 +60,8 @@ export interface StructureSetupElementsObj {
|
||||
_padding: HTMLElement | false;
|
||||
_content: HTMLElement | false;
|
||||
_viewportArrange: HTMLStyleElement | false | null | undefined;
|
||||
_scrollOffsetElement: HTMLElement;
|
||||
_scrollEventElement: HTMLElement | Document;
|
||||
// ctx ----
|
||||
_isTextarea: boolean;
|
||||
_isBody: boolean;
|
||||
@@ -152,6 +154,8 @@ export const createStructureSetupElements = (
|
||||
!_nativeScrollbarsHiding &&
|
||||
createUniqueViewportArrangeElement &&
|
||||
createUniqueViewportArrangeElement(env),
|
||||
_scrollOffsetElement: isBody ? ownerDocument.documentElement : viewportElement,
|
||||
_scrollEventElement: isBody ? ownerDocument : viewportElement,
|
||||
_windowElm: wnd,
|
||||
_documentElm: ownerDocument,
|
||||
_isTextarea: isTextarea,
|
||||
|
||||
@@ -25,7 +25,7 @@ body > .os-scrollbar {
|
||||
border: none !important;
|
||||
}
|
||||
.os-scrollbar-handle {
|
||||
pointer-events: none;
|
||||
pointer-events: auto;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -33,6 +33,7 @@ body > .os-scrollbar {
|
||||
.os-scrollbar-handle-interactive,
|
||||
.os-scrollbar-track-interactive {
|
||||
pointer-events: auto;
|
||||
touch-action: none;
|
||||
}
|
||||
.os-scrollbar-unusable,
|
||||
.os-scrollbar-unusable * {
|
||||
|
||||
Reference in New Issue
Block a user