mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-17 12:39:40 +03:00
improve initialization strategy and begin with scrollbars
This commit is contained in:
+1
-1
@@ -60,7 +60,7 @@
|
||||
"rollup-plugin-typescript2": "^0.27.1",
|
||||
"should": "^13.2.3",
|
||||
"tslib": "^2.2.0",
|
||||
"typescript": "^4.2.4",
|
||||
"typescript": "^4.3.2",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -17,3 +17,9 @@ export const classNameSizeObserverListenerItem = `${classNameSizeObserverListene
|
||||
export const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
|
||||
|
||||
export const classNameTrinsicObserver = 'os-trinsic-observer';
|
||||
|
||||
export const classNameScrollbar = 'os-scrollbar';
|
||||
export const classNameScrollbarHorizontal = `${classNameScrollbar}-horizontal`;
|
||||
export const classNameScrollbarVertical = `${classNameScrollbar}-vertical`;
|
||||
export const classNameScrollbarTrack = 'os-scrollbar-track';
|
||||
export const classNameScrollbarHandle = 'os-scrollbar-handle';
|
||||
|
||||
@@ -25,12 +25,40 @@ import {
|
||||
classNameViewportScrollbarStyling,
|
||||
} from 'classnames';
|
||||
import { OSOptions, defaultOptions } from 'options';
|
||||
import { OSTargetElement } from 'typings';
|
||||
|
||||
export interface InitializationStrategy {
|
||||
_padding: boolean;
|
||||
_content: boolean;
|
||||
type StructureInitializationElementFn<T> = ((target: OSTargetElement) => HTMLElement | T) | T;
|
||||
|
||||
type ScrollbarsInitializationElementFn<T> = ((target: OSTargetElement, host: HTMLElement, viewport: HTMLElement) => HTMLElement | T) | T;
|
||||
|
||||
/**
|
||||
* A Static element is an element which MUST be generated.
|
||||
* If null (or the returned result is null), the initialization function is generatig the element, otherwise
|
||||
* the element returned by the function acts as the generated element.
|
||||
*/
|
||||
export type StructureInitializationStaticElement = StructureInitializationElementFn<null>;
|
||||
|
||||
/**
|
||||
* A Dynamic element is an element which CAN be generated.
|
||||
* If null (or the returned result is null), then the default behavior is used.
|
||||
* If boolean (or the returned result is boolean), the generation of the element is forced (or not).
|
||||
* If the function returns and element, the element returned by the function acts as the generated element.
|
||||
*/
|
||||
export type StructureInitializationDynamicElement = StructureInitializationElementFn<boolean | null>;
|
||||
|
||||
export interface StructureInitializationStrategy {
|
||||
_host: StructureInitializationStaticElement;
|
||||
_viewport: StructureInitializationStaticElement;
|
||||
_padding: StructureInitializationDynamicElement;
|
||||
_content: StructureInitializationDynamicElement;
|
||||
}
|
||||
|
||||
export interface ScrollbarsInitializationStrategy {
|
||||
_scrollbarsSlot: ScrollbarsInitializationElementFn<null | undefined>;
|
||||
}
|
||||
|
||||
export interface InitializationStrategy extends StructureInitializationStrategy, ScrollbarsInitializationStrategy {}
|
||||
|
||||
export type OnEnvironmentChanged = (env: Environment) => void;
|
||||
export interface Environment {
|
||||
_nativeScrollbarSize: XY;
|
||||
@@ -132,9 +160,13 @@ const getWindowDPR = (): number => {
|
||||
return window.devicePixelRatio || dDPI / sDPI;
|
||||
};
|
||||
|
||||
// init function decides for all values
|
||||
const getDefaultInitializationStrategy = (nativeScrollbarStyling: boolean): InitializationStrategy => ({
|
||||
_padding: !nativeScrollbarStyling,
|
||||
_content: false,
|
||||
_host: null,
|
||||
_viewport: null,
|
||||
_padding: null,
|
||||
_content: null,
|
||||
_scrollbarsSlot: null,
|
||||
});
|
||||
|
||||
const createEnvironment = (): Environment => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { createTrinsicLifecycle } from 'lifecycles/trinsicLifecycle';
|
||||
import { createPaddingLifecycle } from 'lifecycles/paddingLifecycle';
|
||||
import { createOverflowLifecycle } from 'lifecycles/overflowLifecycle';
|
||||
import { StyleObject } from 'typings';
|
||||
import { ScrollbarsSetup } from 'setups/scrollbarsSetup';
|
||||
|
||||
export type LifecycleCheckOption = <T>(path: string) => LifecycleOptionInfo<T>;
|
||||
|
||||
@@ -99,7 +100,7 @@ const lifecycleCommunicationFallback: LifecycleCommunication = {
|
||||
},
|
||||
};
|
||||
|
||||
export const createLifecycleHub = (options: OSOptions, structureSetup: StructureSetup): LifecycleHubInstance => {
|
||||
export const createLifecycleHub = (options: OSOptions, structureSetup: StructureSetup, scrollbarsSetup: ScrollbarsSetup): LifecycleHubInstance => {
|
||||
let lifecycleCommunication = lifecycleCommunicationFallback;
|
||||
const { _viewport } = structureSetup._targetObj;
|
||||
const {
|
||||
@@ -201,6 +202,9 @@ export const createLifecycleHub = (options: OSOptions, structureSetup: Structure
|
||||
_destroy() {
|
||||
destroyObservers();
|
||||
removeEnvironmentListener(envUpdateListener);
|
||||
|
||||
structureSetup._destroy();
|
||||
scrollbarsSetup._destroy();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { OSTarget, OSTargetObject } from 'typings';
|
||||
import { OSTarget, OSInitializationObject } from 'typings';
|
||||
import { PartialOptions, validateOptions, assignDeep, isEmptyObject } from 'support';
|
||||
import { createStructureSetup, StructureSetup } from 'setups/structureSetup';
|
||||
import { createScrollbarsSetup, ScrollbarsSetup } from 'setups/scrollbarsSetup';
|
||||
import { createLifecycleHub } from 'lifecycles/lifecycleHub';
|
||||
import { OSOptions, optionsTemplate } from 'options';
|
||||
import { getEnvironment } from 'environment';
|
||||
|
||||
export interface OverlayScrollbarsStatic {
|
||||
(target: OSTarget | OSTargetObject, options?: PartialOptions<OSOptions>, extensions?: any): OverlayScrollbars;
|
||||
(target: OSTarget | OSInitializationObject, options?: PartialOptions<OSOptions>, extensions?: any): OverlayScrollbars;
|
||||
}
|
||||
|
||||
export interface OverlayScrollbars {
|
||||
@@ -14,12 +15,13 @@ export interface OverlayScrollbars {
|
||||
options(newOptions?: PartialOptions<OSOptions>): OSOptions;
|
||||
|
||||
update(force?: boolean): void;
|
||||
destroy(): void;
|
||||
|
||||
state(): any;
|
||||
}
|
||||
|
||||
export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
target: OSTarget | OSTargetObject,
|
||||
target: OSTarget | OSInitializationObject,
|
||||
options?: PartialOptions<OSOptions>,
|
||||
extensions?: any
|
||||
): OverlayScrollbars => {
|
||||
@@ -30,7 +32,9 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
validateOptions(options || ({} as PartialOptions<OSOptions>), optionsTemplate, null, true)._validated
|
||||
);
|
||||
const structureSetup: StructureSetup = createStructureSetup(target);
|
||||
const lifecycleHub = createLifecycleHub(currentOptions, structureSetup);
|
||||
const scrollbarsSetup: ScrollbarsSetup = createScrollbarsSetup(target, structureSetup);
|
||||
const lifecycleHub = createLifecycleHub(currentOptions, structureSetup, scrollbarsSetup);
|
||||
|
||||
const instance: OverlayScrollbars = {
|
||||
options(newOptions?: PartialOptions<OSOptions>) {
|
||||
if (newOptions) {
|
||||
@@ -47,6 +51,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
update(force?: boolean) {
|
||||
lifecycleHub._update(null, force);
|
||||
},
|
||||
destroy: () => lifecycleHub._destroy(),
|
||||
};
|
||||
|
||||
instance.update(true);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { appendChildren, createDiv, removeElements, isFunction } from 'support';
|
||||
import {
|
||||
classNameScrollbar,
|
||||
classNameScrollbarHorizontal,
|
||||
classNameScrollbarVertical,
|
||||
classNameScrollbarTrack,
|
||||
classNameScrollbarHandle,
|
||||
} from 'classnames';
|
||||
import { getEnvironment, ScrollbarsInitializationStrategy } from 'environment';
|
||||
import { OSTarget, ScrollbarsInitialization } from 'typings';
|
||||
import { StructureSetup } from 'setups/structureSetup';
|
||||
|
||||
export interface ScrollbarStructure {
|
||||
_scrollbar: HTMLElement;
|
||||
_track: HTMLElement;
|
||||
_handle: HTMLElement;
|
||||
}
|
||||
|
||||
export interface ScrollbarsSetup {
|
||||
_horizontalScrollbarStructure: ScrollbarStructure;
|
||||
_verticalScrollbarStructure: ScrollbarStructure;
|
||||
_destroy: () => void;
|
||||
}
|
||||
|
||||
const generateScrollbarDOM = (scrollbarClassName: string): ScrollbarStructure => {
|
||||
const scrollbar = createDiv(`${classNameScrollbar} ${scrollbarClassName}`);
|
||||
const track = createDiv(classNameScrollbarTrack);
|
||||
const handle = createDiv(classNameScrollbarHandle);
|
||||
|
||||
appendChildren(scrollbar, track);
|
||||
appendChildren(track, handle);
|
||||
|
||||
return {
|
||||
_scrollbar: scrollbar,
|
||||
_track: track,
|
||||
_handle: handle,
|
||||
};
|
||||
};
|
||||
|
||||
export const createScrollbarsSetup = (target: OSTarget | ScrollbarsInitialization, structureSetup: StructureSetup): ScrollbarsSetup => {
|
||||
const { _getInitializationStrategy } = getEnvironment();
|
||||
const { _scrollbarsSlot: environmentScrollbarSlot } = _getInitializationStrategy() as ScrollbarsInitializationStrategy;
|
||||
const { _targetObj, _targetCtx } = structureSetup;
|
||||
const { _target, _host, _viewport } = _targetObj;
|
||||
const initializationScrollbarSlot = !_targetCtx._targetIsElm && (target as ScrollbarsInitialization).scrollbarsSlot;
|
||||
const initializationScrollbarSlotResult = isFunction(initializationScrollbarSlot)
|
||||
? initializationScrollbarSlot(_target, _host, _viewport)
|
||||
: initializationScrollbarSlot;
|
||||
const evaluatedScrollbarSlot =
|
||||
initializationScrollbarSlotResult ||
|
||||
(isFunction(environmentScrollbarSlot) ? environmentScrollbarSlot(_target, _host, _viewport) : environmentScrollbarSlot) ||
|
||||
_host;
|
||||
|
||||
const horizontalScrollbarStructure = generateScrollbarDOM(classNameScrollbarHorizontal);
|
||||
const verticalScrollbarStructure = generateScrollbarDOM(classNameScrollbarVertical);
|
||||
|
||||
const { _scrollbar: horizontalScrollbar } = horizontalScrollbarStructure;
|
||||
const { _scrollbar: verticalScrollbar } = verticalScrollbarStructure;
|
||||
|
||||
appendChildren(evaluatedScrollbarSlot, horizontalScrollbar);
|
||||
appendChildren(evaluatedScrollbarSlot, verticalScrollbar);
|
||||
|
||||
return {
|
||||
_horizontalScrollbarStructure: horizontalScrollbarStructure,
|
||||
_verticalScrollbarStructure: verticalScrollbarStructure,
|
||||
_destroy() {
|
||||
removeElements([horizontalScrollbar, verticalScrollbar]);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
insertAfter,
|
||||
addClass,
|
||||
parent,
|
||||
isUndefined,
|
||||
indexOf,
|
||||
removeElements,
|
||||
removeClass,
|
||||
push,
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
insertBefore,
|
||||
attr,
|
||||
isBoolean,
|
||||
isFunction,
|
||||
keys,
|
||||
} from 'support';
|
||||
import {
|
||||
classNameHost,
|
||||
@@ -24,8 +26,13 @@ import {
|
||||
classNameContent,
|
||||
classNameViewportScrollbarStyling,
|
||||
} from 'classnames';
|
||||
import { getEnvironment } from 'environment';
|
||||
import { OSTarget, OSTargetObject, OSTargetElement } from 'typings';
|
||||
import {
|
||||
getEnvironment,
|
||||
StructureInitializationStaticElement,
|
||||
StructureInitializationDynamicElement,
|
||||
StructureInitializationStrategy,
|
||||
} from 'environment';
|
||||
import { OSTarget, OSTargetElement, StructureInitialization } from 'typings';
|
||||
|
||||
export interface OSTargetContext {
|
||||
_isTextarea: boolean;
|
||||
@@ -34,15 +41,16 @@ export interface OSTargetContext {
|
||||
_bodyElm: HTMLBodyElement;
|
||||
_windowElm: Window;
|
||||
_documentElm: HTMLDocument;
|
||||
_targetIsElm: boolean;
|
||||
}
|
||||
|
||||
export interface PreparedOSTargetObject {
|
||||
_target: OSTargetElement;
|
||||
_host: HTMLElement;
|
||||
_viewport: HTMLElement;
|
||||
_padding: HTMLElement | false | null;
|
||||
_content: HTMLElement | false | null;
|
||||
_viewportArrange: HTMLStyleElement | false | null;
|
||||
_padding: HTMLElement | false;
|
||||
_content: HTMLElement | false;
|
||||
_viewportArrange: HTMLStyleElement | false;
|
||||
}
|
||||
|
||||
export interface StructureSetup {
|
||||
@@ -51,60 +59,113 @@ export interface StructureSetup {
|
||||
_destroy: () => void;
|
||||
}
|
||||
|
||||
let contentArrangeCounter = 0;
|
||||
|
||||
const unwrap = (elm: HTMLElement | false | null | undefined) => {
|
||||
appendChildren(parent(elm), contents(elm));
|
||||
removeElements(elm);
|
||||
};
|
||||
|
||||
let contentArrangeCounter = 0;
|
||||
const createUniqueViewportArrangeElement = (): HTMLStyleElement => {
|
||||
const elm = document.createElement('style');
|
||||
const createUniqueViewportArrangeElement = (): HTMLStyleElement | false => {
|
||||
const { _nativeScrollbarStyling, _nativeScrollbarIsOverlaid, _cssCustomProperties } = getEnvironment();
|
||||
/* istanbul ignore next */
|
||||
const create = !_cssCustomProperties && !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
|
||||
const result = create ? document.createElement('style') : false;
|
||||
|
||||
attr(elm, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`);
|
||||
contentArrangeCounter++;
|
||||
|
||||
return elm;
|
||||
};
|
||||
const evaluateCreationFromStrategy = (initializationValue: HTMLElement | boolean | undefined, strategy: boolean): HTMLElement | false | undefined => {
|
||||
const isBooleanValue = isBoolean(initializationValue);
|
||||
if (isBooleanValue || isUndefined(initializationValue)) {
|
||||
return (isBooleanValue ? initializationValue : strategy) && undefined;
|
||||
if (result) {
|
||||
attr(result, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`);
|
||||
contentArrangeCounter++;
|
||||
}
|
||||
return initializationValue as HTMLElement;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const createStructureSetup = (target: OSTarget | OSTargetObject): StructureSetup => {
|
||||
const { _getInitializationStrategy, _nativeScrollbarStyling, _nativeScrollbarIsOverlaid, _cssCustomProperties } = getEnvironment();
|
||||
const { _padding: paddingNeeded, _content: contentNeeded } = _getInitializationStrategy();
|
||||
const staticCreationFromStrategy = (
|
||||
target: OSTargetElement,
|
||||
initializationValue: HTMLElement | undefined,
|
||||
strategy: StructureInitializationStaticElement,
|
||||
elementClass: string
|
||||
): HTMLElement => {
|
||||
const result = initializationValue ? initializationValue : isFunction(strategy) ? strategy(target) : (strategy as null);
|
||||
return result ? result : createDiv(elementClass);
|
||||
};
|
||||
|
||||
const dynamicCreationFromStrategy = (
|
||||
target: OSTargetElement,
|
||||
initializationValue: HTMLElement | boolean | undefined,
|
||||
strategy: StructureInitializationDynamicElement,
|
||||
elementClass: string,
|
||||
defaultValue: boolean
|
||||
): HTMLElement | false => {
|
||||
const takeInitializationValue = isBoolean(initializationValue) || initializationValue;
|
||||
const result = takeInitializationValue ? (initializationValue as boolean | HTMLElement) : isFunction(strategy) ? strategy(target) : strategy;
|
||||
|
||||
if (result === null) {
|
||||
return defaultValue ? createDiv(elementClass) : false;
|
||||
}
|
||||
|
||||
return result === true ? createDiv(elementClass) : result;
|
||||
};
|
||||
|
||||
export const createStructureSetup = (target: OSTarget | StructureInitialization): StructureSetup => {
|
||||
const { _getInitializationStrategy, _nativeScrollbarStyling } = getEnvironment();
|
||||
const {
|
||||
_host: hostInitializationStrategy,
|
||||
_viewport: viewportInitializationStrategy,
|
||||
_padding: paddingInitializationStrategy,
|
||||
_content: contentInitializationStrategy,
|
||||
} = _getInitializationStrategy() as StructureInitializationStrategy;
|
||||
const targetIsElm = isHTMLElement(target);
|
||||
const osTargetObj: Partial<PreparedOSTargetObject> = targetIsElm
|
||||
? ({} as Partial<PreparedOSTargetObject>)
|
||||
: {
|
||||
_host: (target as OSTargetObject).host,
|
||||
_target: (target as OSTargetObject).target,
|
||||
_viewport: (target as OSTargetObject).viewport,
|
||||
_padding: evaluateCreationFromStrategy((target as OSTargetObject).padding, paddingNeeded),
|
||||
_content: evaluateCreationFromStrategy((target as OSTargetObject).content, contentNeeded),
|
||||
};
|
||||
|
||||
if (targetIsElm) {
|
||||
const viewport = createDiv(classNameViewport);
|
||||
const padding = paddingNeeded && createDiv(classNamePadding);
|
||||
const content = contentNeeded && createDiv(classNameContent);
|
||||
|
||||
osTargetObj._target = target as OSTargetElement;
|
||||
osTargetObj._padding = padding;
|
||||
osTargetObj._viewport = viewport;
|
||||
osTargetObj._content = content;
|
||||
}
|
||||
|
||||
let { _target, _padding, _viewport, _content } = osTargetObj;
|
||||
const targetStructureInitialization = target as StructureInitialization;
|
||||
const targetElement = targetIsElm ? (target as OSTargetElement) : targetStructureInitialization.target;
|
||||
const isTextarea = is(targetElement, 'textarea');
|
||||
const isBody = !isTextarea && is(targetElement, 'body');
|
||||
const ownerDocument: HTMLDocument = targetElement!.ownerDocument;
|
||||
const bodyElm = ownerDocument.body as HTMLBodyElement;
|
||||
const wnd = ownerDocument.defaultView as Window;
|
||||
const evaluatedTargetObj: PreparedOSTargetObject = {
|
||||
_target: targetElement,
|
||||
_host: isTextarea
|
||||
? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy, classNameHost)
|
||||
: (targetElement as HTMLElement),
|
||||
_viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy, classNameViewport),
|
||||
_padding: dynamicCreationFromStrategy(
|
||||
targetElement,
|
||||
targetStructureInitialization.padding,
|
||||
paddingInitializationStrategy,
|
||||
classNamePadding,
|
||||
!_nativeScrollbarStyling // default value for padding
|
||||
),
|
||||
_content: dynamicCreationFromStrategy(
|
||||
targetElement,
|
||||
targetStructureInitialization.content,
|
||||
contentInitializationStrategy,
|
||||
classNameContent,
|
||||
false // default value for content
|
||||
),
|
||||
_viewportArrange: createUniqueViewportArrangeElement(),
|
||||
};
|
||||
const ctx: OSTargetContext = {
|
||||
_windowElm: wnd,
|
||||
_documentElm: ownerDocument,
|
||||
_htmlElm: parent(bodyElm) as HTMLHtmlElement,
|
||||
_bodyElm: bodyElm,
|
||||
_isTextarea: isTextarea,
|
||||
_isBody: isBody,
|
||||
_targetIsElm: targetIsElm,
|
||||
};
|
||||
const generatedElements = keys(evaluatedTargetObj).reduce((arr, key: string) => {
|
||||
const value = evaluatedTargetObj[key];
|
||||
return push(arr, value && !parent(value) ? value : false);
|
||||
}, [] as HTMLElement[]);
|
||||
const elementIsGenerated = (elm: HTMLElement | false) => (elm ? indexOf(generatedElements, elm) > -1 : null);
|
||||
const { _target, _host, _padding, _viewport, _content, _viewportArrange } = evaluatedTargetObj;
|
||||
const destroyFns: (() => any)[] = [];
|
||||
const isTextarea = is(_target, 'textarea');
|
||||
const isBody = !isTextarea && is(_target, 'body');
|
||||
const _host = (isTextarea ? osTargetObj._host || createDiv() : _target) as HTMLElement;
|
||||
const getTargetContents = (contentSlot: HTMLElement) => (isTextarea ? (_target as HTMLTextAreaElement) : contents(contentSlot as HTMLElement));
|
||||
const isTextareaHostGenerated = isTextarea && _host !== osTargetObj._host;
|
||||
const isTextareaHostGenerated = isTextarea && elementIsGenerated(_host);
|
||||
const targetContents = isTextarea
|
||||
? _target
|
||||
: contents([_content, _viewport, _padding, _host, _target].find((elm) => elementIsGenerated(elm) === false));
|
||||
const contentSlot = _content || _viewport;
|
||||
|
||||
// only insert host for textarea after target if it was generated
|
||||
if (isTextareaHostGenerated) {
|
||||
@@ -116,88 +177,48 @@ export const createStructureSetup = (target: OSTarget | OSTargetObject): Structu
|
||||
});
|
||||
}
|
||||
|
||||
if (targetIsElm) {
|
||||
const contentSlot = _content || _viewport;
|
||||
appendChildren(contentSlot, getTargetContents(_target!));
|
||||
appendChildren(_host, _padding);
|
||||
appendChildren(_padding || _host, _viewport);
|
||||
appendChildren(_viewport, _content);
|
||||
|
||||
push(destroyFns, () => {
|
||||
appendChildren(_host, contents(contentSlot));
|
||||
removeElements(_padding || _viewport);
|
||||
removeClass(_host, classNameHost);
|
||||
});
|
||||
} else {
|
||||
const contentContainingElm = _content || _viewport || _padding || _host;
|
||||
const createPadding = isUndefined(_padding);
|
||||
const createViewport = isUndefined(_viewport);
|
||||
const createContent = isUndefined(_content);
|
||||
const targetContents = getTargetContents(contentContainingElm);
|
||||
|
||||
_padding = osTargetObj._padding = createPadding ? createDiv() : _padding;
|
||||
_viewport = osTargetObj._viewport = createViewport ? createDiv() : _viewport;
|
||||
_content = osTargetObj._content = createContent ? createDiv() : _content;
|
||||
|
||||
appendChildren(_host, _padding);
|
||||
appendChildren(_padding || _host, _viewport);
|
||||
appendChildren(_viewport, _content);
|
||||
|
||||
const contentSlot = _content || _viewport;
|
||||
appendChildren(contentSlot, targetContents);
|
||||
|
||||
push(destroyFns, () => {
|
||||
if (createContent) {
|
||||
unwrap(_content);
|
||||
}
|
||||
if (createViewport) {
|
||||
unwrap(_viewport);
|
||||
}
|
||||
if (createPadding) {
|
||||
unwrap(_padding);
|
||||
}
|
||||
removeClass(_host, classNameHost);
|
||||
removeClass(_padding, classNamePadding);
|
||||
removeClass(_viewport, classNameViewport);
|
||||
removeClass(_content, classNameContent);
|
||||
});
|
||||
}
|
||||
appendChildren(contentSlot, targetContents);
|
||||
appendChildren(_host, _padding);
|
||||
appendChildren(_padding || _host, _viewport);
|
||||
appendChildren(_viewport, _content);
|
||||
|
||||
addClass(_host, classNameHost);
|
||||
addClass(_padding, classNamePadding);
|
||||
addClass(_viewport, classNameViewport);
|
||||
addClass(_content, classNameContent);
|
||||
|
||||
const ownerDocument: HTMLDocument = _target!.ownerDocument;
|
||||
const bodyElm = ownerDocument.body as HTMLBodyElement;
|
||||
const wnd = ownerDocument.defaultView as Window;
|
||||
const ctx: OSTargetContext = {
|
||||
_windowElm: wnd,
|
||||
_documentElm: ownerDocument,
|
||||
_htmlElm: parent(bodyElm) as HTMLHtmlElement,
|
||||
_bodyElm: bodyElm,
|
||||
_isTextarea: isTextarea,
|
||||
_isBody: isBody,
|
||||
};
|
||||
// @ts-ignore
|
||||
const obj: PreparedOSTargetObject = {
|
||||
...osTargetObj,
|
||||
_host,
|
||||
};
|
||||
push(destroyFns, () => {
|
||||
if (targetIsElm) {
|
||||
appendChildren(_host, contents(contentSlot));
|
||||
removeElements(_padding || _viewport);
|
||||
removeClass(_host, classNameHost);
|
||||
} else {
|
||||
if (elementIsGenerated(_content)) {
|
||||
unwrap(_content);
|
||||
}
|
||||
if (elementIsGenerated(_viewport)) {
|
||||
unwrap(_viewport);
|
||||
}
|
||||
if (elementIsGenerated(_padding)) {
|
||||
unwrap(_padding);
|
||||
}
|
||||
removeClass(_host, classNameHost);
|
||||
removeClass(_padding, classNamePadding);
|
||||
removeClass(_viewport, classNameViewport);
|
||||
removeClass(_content, classNameContent);
|
||||
}
|
||||
});
|
||||
|
||||
if (_nativeScrollbarStyling) {
|
||||
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));
|
||||
} else if (!_cssCustomProperties && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y)) {
|
||||
const viewportArrangeElm = createUniqueViewportArrangeElement();
|
||||
|
||||
insertBefore(_viewport, viewportArrangeElm);
|
||||
push(destroyFns, removeElements.bind(0, viewportArrangeElm));
|
||||
|
||||
obj._viewportArrange = viewportArrangeElm;
|
||||
}
|
||||
if (_viewportArrange) {
|
||||
insertBefore(_viewport, _viewportArrange);
|
||||
push(destroyFns, removeElements.bind(0, _viewportArrange));
|
||||
}
|
||||
|
||||
return {
|
||||
_targetObj: obj,
|
||||
_targetObj: evaluatedTargetObj,
|
||||
_targetCtx: ctx,
|
||||
_destroy: () => {
|
||||
runEach(destroyFns);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import './sizeobserver.scss';
|
||||
@import './trinsicobserver.scss';
|
||||
@import './scrollbars.scss';
|
||||
|
||||
.os-environment {
|
||||
--os-custom-prop: -1;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -32,7 +32,7 @@ export function isBoolean(obj: any): obj is boolean {
|
||||
return typeof obj === 'boolean';
|
||||
}
|
||||
|
||||
export function isFunction(obj: any): obj is (...args: Array<unknown>) => unknown {
|
||||
export function isFunction(obj: any): obj is (...args: any[]) => any {
|
||||
return typeof obj === 'function';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
export type PlainObject<T = any> = { [name: string]: T };
|
||||
|
||||
export type StyleObject<CustomCssProps = ''> = {
|
||||
@@ -10,6 +12,19 @@ export type InternalVersionOf<T> = {
|
||||
|
||||
export type OSTargetElement = HTMLElement | HTMLTextAreaElement;
|
||||
|
||||
/**
|
||||
* Static elements MUST be present.
|
||||
*/
|
||||
type StructureInitializationStaticElement = HTMLElement;
|
||||
|
||||
/**
|
||||
* Dynamic element CAN be present.
|
||||
* If its a element the element will be handled as the repsective element.
|
||||
* True means that the respective dynamic element is forced to be generated.
|
||||
* False means that the respective dynamic element is forced NOT to be generated.
|
||||
*/
|
||||
type StructureInitializationDynamicElement = HTMLElement | boolean;
|
||||
|
||||
/**
|
||||
* Object for special initialization.
|
||||
*
|
||||
@@ -18,19 +33,29 @@ export type OSTargetElement = HTMLElement | HTMLTextAreaElement;
|
||||
* If element is provided, the provided element takes all its responsibilities.
|
||||
* DOM hierarchy isn't checked in this case, its assumed that hieararchy is correct in such a case.
|
||||
*
|
||||
* Undefined means that the plugin decides whether the respective element needs to be added or can be savely omitted.
|
||||
* True means that even if the plugin would decide to not generate the element, the element is still generated.
|
||||
* False means that event if the plugin would decide to generate the element, the element won't be generated.
|
||||
* Undefined means that the environment initialization strategy for the respective element is used.
|
||||
*/
|
||||
export interface OSTargetObject {
|
||||
export interface StructureInitialization {
|
||||
target: OSTargetElement;
|
||||
host?: HTMLElement;
|
||||
padding?: HTMLElement | boolean;
|
||||
viewport?: HTMLElement;
|
||||
content?: HTMLElement | boolean;
|
||||
host?: StructureInitializationStaticElement; // only relevant for textarea
|
||||
viewport?: StructureInitializationStaticElement;
|
||||
padding?: StructureInitializationDynamicElement;
|
||||
content?: StructureInitializationDynamicElement;
|
||||
}
|
||||
|
||||
export type OSTarget = OSTargetElement | OSTargetObject;
|
||||
/**
|
||||
* Object for special initialization.
|
||||
*
|
||||
* scrollbarsSlot is the element to which the scrollbars are applied to. If null or undefined the plugin decides by itself whats the scrollbars slot.
|
||||
*/
|
||||
export interface ScrollbarsInitialization {
|
||||
scrollbarsSlot?: null | HTMLElement | ((target: OSTargetElement, host: HTMLElement, viewport: HTMLElement) => null | HTMLElement);
|
||||
}
|
||||
|
||||
export interface OSInitializationObject extends StructureInitialization, ScrollbarsInitialization {
|
||||
}
|
||||
|
||||
export type OSTarget = OSTargetElement | OSInitializationObject;
|
||||
|
||||
/*
|
||||
export namespace OverlayScrollbars {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8790,10 +8790,10 @@ typescript@^3.9.3:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
typescript@^4.2.4:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
|
||||
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
|
||||
typescript@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
|
||||
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
|
||||
|
||||
unicode-canonical-property-names-ecmascript@^1.0.4:
|
||||
version "1.0.4"
|
||||
|
||||
Reference in New Issue
Block a user