Files
OverlayScrollbars/packages/overlayscrollbars/src/setups/scrollbarsSetup/scrollbarsSetup.elements.ts
T
2022-07-24 23:43:10 +02:00

196 lines
6.6 KiB
TypeScript

import {
addClass,
appendChildren,
createDiv,
each,
isEmptyArray,
noop,
on,
push,
removeClass,
removeElements,
runEachAndClear,
setT,
stopPropagation,
style,
} from 'support';
import {
classNameScrollbar,
classNameScrollbarHorizontal,
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 {
ScrollbarsInitialization,
ScrollbarsDynamicInitializationElement,
} from 'setups/scrollbarsSetup/scrollbarsSetup.initialization';
import { StyleObject } from 'typings';
export interface ScrollbarStructure {
_scrollbar: HTMLElement;
_track: HTMLElement;
_handle: HTMLElement;
}
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 {
_horizontal: ScrollbarsSetupElement;
_vertical: ScrollbarsSetupElement;
}
export type ScrollbarsSetupElements = [
elements: ScrollbarsSetupElementsObj,
appendElements: () => void,
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
): ScrollbarsSetupElements => {
const { _getDefaultInitialization } = getEnvironment();
const { scrollbarsSlot: defaultScrollbarsSlot } = _getDefaultInitialization();
const { _documentElm, _target, _host, _viewport, _targetIsElm } = structureSetupElements;
const { scrollbarsSlot } = (_targetIsElm ? {} : target) as ScrollbarsInitialization;
const evaluatedScrollbarSlot =
generalDynamicInitializationElement<ScrollbarsDynamicInitializationElement>(
[_target, _host, _viewport],
() => _host,
defaultScrollbarsSlot,
scrollbarsSlot
);
const scrollbarsAddRemoveClass = (
scrollbarStructures: ScrollbarStructure[],
classNames: string | false | null | undefined,
add?: boolean,
elm?: (scrollbarStructure: ScrollbarStructure) => HTMLElement | false | null | undefined
) => {
const action = add ? addClass : removeClass;
each(scrollbarStructures, (scrollbarStructure) => {
action((elm || noop)(scrollbarStructure) || scrollbarStructure._scrollbar, classNames);
});
};
const scrollbarsHandleStyle = (
scrollbarStructures: ScrollbarStructure[],
elmStyle: (
scrollbarStructure: ScrollbarStructure
) => [HTMLElement | false | null | undefined, StyleObject]
) => {
each(scrollbarStructures, (scrollbarStructure) => {
const [elm, styles] = elmStyle(scrollbarStructure);
style(elm, styles);
});
};
const destroyFns: (() => void)[] = [];
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
? classNameScrollbarHorizontal
: classNameScrollbarVertical;
const arrToPush = horizontal ? horizontalScrollbars : verticalScrollbars;
const transitionlessClass = isEmptyArray(arrToPush) ? classNamesScrollbarTransitionless : '';
const scrollbar = createDiv(
`${classNameScrollbar} ${scrollbarClassName} ${transitionlessClass}`
);
const track = createDiv(classNameScrollbarTrack);
const handle = createDiv(classNameScrollbarHandle);
const result = {
_scrollbar: scrollbar,
_track: track,
_handle: handle,
};
appendChildren(scrollbar, track);
appendChildren(track, handle);
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),
]);
return result;
};
const generateHorizontalScrollbarStructure = generateScrollbarDOM.bind(0, true);
const generateVerticalScrollbarStructure = generateScrollbarDOM.bind(0, false);
const appendElements = () => {
appendChildren(evaluatedScrollbarSlot, horizontalScrollbars[0]._scrollbar);
appendChildren(evaluatedScrollbarSlot, verticalScrollbars[0]._scrollbar);
setT(() => {
addRemoveClassHorizontal(classNamesScrollbarTransitionless);
addRemoveClassVertical(classNamesScrollbarTransitionless);
}, 300);
};
generateHorizontalScrollbarStructure();
generateVerticalScrollbarStructure();
return [
{
_horizontal: {
_scrollbarStructures: horizontalScrollbars,
_clone: generateHorizontalScrollbarStructure,
_addRemoveClass: addRemoveClassHorizontal,
_handleStyle: scrollbarsHandleStyle.bind(0, horizontalScrollbars),
},
_vertical: {
_scrollbarStructures: verticalScrollbars,
_clone: generateVerticalScrollbarStructure,
_addRemoveClass: addRemoveClassVertical,
_handleStyle: scrollbarsHandleStyle.bind(0, verticalScrollbars),
},
},
appendElements,
runEachAndClear.bind(0, destroyFns),
];
};