mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-23 04:14:07 +03:00
improve code and public interface
This commit is contained in:
@@ -6,12 +6,12 @@ export const dataAttributeHost = 'data-overlayscrollbars';
|
||||
export const dataAttributeHostOverflowX = `${dataAttributeHost}-overflow-x`;
|
||||
export const dataAttributeHostOverflowY = `${dataAttributeHost}-overflow-y`;
|
||||
export const dataValueHostOverflowVisible = 'overflowVisible';
|
||||
export const dataValueHostViewportScrollbarStyling = 'viewportStyled';
|
||||
export const dataValueHostScrollbarHidden = 'scrollbarHidden';
|
||||
export const classNamePadding = 'os-padding';
|
||||
export const classNameViewport = 'os-viewport';
|
||||
export const classNameViewportArrange = `${classNameViewport}-arrange`;
|
||||
export const classNameContent = 'os-content';
|
||||
export const classNameViewportScrollbarStyling = `${classNameViewport}-scrollbar-styled`;
|
||||
export const classNameViewportScrollbarHidden = `${classNameViewport}-scrollbar-hidden`;
|
||||
export const classNameOverflowVisible = `os-overflow-visible`;
|
||||
|
||||
export const classNameSizeObserver = 'os-size-observer';
|
||||
|
||||
@@ -24,11 +24,11 @@ import {
|
||||
classNameEnvironment,
|
||||
classNameEnvironmentFlexboxGlue,
|
||||
classNameEnvironmentFlexboxGlueMax,
|
||||
classNameViewportScrollbarStyling,
|
||||
classNameViewportScrollbarHidden,
|
||||
} from 'classnames';
|
||||
import { Options, defaultOptions } from 'options';
|
||||
import { PartialOptions } from 'typings';
|
||||
import { InitializationStrategy } from 'initialization';
|
||||
import { DeepPartial } from 'typings';
|
||||
import { DefaultInitialization } from 'initialization';
|
||||
import { getPlugins, ScrollbarsHidingPluginInstance, scrollbarsHidingPluginName } from 'plugins';
|
||||
|
||||
type EnvironmentEventMap = {
|
||||
@@ -42,13 +42,13 @@ export interface InternalEnvironment {
|
||||
readonly _rtlScrollBehavior: { n: boolean; i: boolean };
|
||||
readonly _flexboxGlue: boolean;
|
||||
readonly _cssCustomProperties: boolean;
|
||||
readonly _defaultInitializationStrategy: InitializationStrategy;
|
||||
readonly _defaultDefaultOptions: Options;
|
||||
readonly _staticDefaultInitialization: DefaultInitialization;
|
||||
readonly _staticDefaultOptions: Options;
|
||||
_addListener(listener: EventListener<EnvironmentEventMap, '_'>): () => void;
|
||||
_getInitializationStrategy(): InitializationStrategy;
|
||||
_setInitializationStrategy(newInitializationStrategy: Partial<InitializationStrategy>): void;
|
||||
_getDefaultInitialization(): DefaultInitialization;
|
||||
_setDefaultInitialization(newInitialization: DeepPartial<DefaultInitialization>): void;
|
||||
_getDefaultOptions(): Options;
|
||||
_setDefaultOptions(newDefaultOptions: PartialOptions<Options>): void;
|
||||
_setDefaultOptions(newDefaultOptions: DeepPartial<Options>): void;
|
||||
}
|
||||
|
||||
let environmentInstance: InternalEnvironment;
|
||||
@@ -75,7 +75,7 @@ const getNativeScrollbarSize = (
|
||||
|
||||
const getNativeScrollbarsHiding = (testElm: HTMLElement): boolean => {
|
||||
let result = false;
|
||||
const revertClass = addClass(testElm, classNameViewportScrollbarStyling);
|
||||
const revertClass = addClass(testElm, classNameViewportScrollbarHidden);
|
||||
try {
|
||||
result =
|
||||
style(testElm, cssProperty('scrollbar-width')) === 'none' ||
|
||||
@@ -152,9 +152,13 @@ const createEnvironment = (): InternalEnvironment => {
|
||||
x: nativeScrollbarsSize.x === 0,
|
||||
y: nativeScrollbarsSize.y === 0,
|
||||
};
|
||||
const initializationStrategy = {
|
||||
const defaultInitialization = {
|
||||
padding: !nativeScrollbarsHiding,
|
||||
content: false,
|
||||
cancel: {
|
||||
nativeScrollbarsOverlaid: true,
|
||||
body: null,
|
||||
},
|
||||
};
|
||||
const defaultDefaultOptions = assignDeep({}, defaultOptions);
|
||||
|
||||
@@ -166,20 +170,20 @@ const createEnvironment = (): InternalEnvironment => {
|
||||
_rtlScrollBehavior: getRtlScrollBehavior(envElm, envChildElm),
|
||||
_flexboxGlue: getFlexboxGlue(envElm, envChildElm),
|
||||
_addListener: (listener) => addEvent('_', listener),
|
||||
_getInitializationStrategy: assignDeep<InitializationStrategy, InitializationStrategy>.bind(
|
||||
_getDefaultInitialization: assignDeep<DefaultInitialization, DefaultInitialization>.bind(
|
||||
0,
|
||||
{} as InitializationStrategy,
|
||||
initializationStrategy
|
||||
{} as DefaultInitialization,
|
||||
defaultInitialization
|
||||
),
|
||||
_setInitializationStrategy(newInitializationStrategy) {
|
||||
assignDeep(initializationStrategy, newInitializationStrategy);
|
||||
_setDefaultInitialization(newInitializationStrategy) {
|
||||
assignDeep(defaultInitialization, newInitializationStrategy);
|
||||
},
|
||||
_getDefaultOptions: assignDeep<Options, Options>.bind(0, {} as Options, defaultDefaultOptions),
|
||||
_setDefaultOptions(newDefaultOptions) {
|
||||
assignDeep(defaultDefaultOptions, newDefaultOptions);
|
||||
},
|
||||
_defaultInitializationStrategy: assignDeep({}, initializationStrategy),
|
||||
_defaultDefaultOptions: assignDeep({}, defaultDefaultOptions),
|
||||
_staticDefaultInitialization: assignDeep({}, defaultInitialization),
|
||||
_staticDefaultOptions: assignDeep({}, defaultDefaultOptions),
|
||||
};
|
||||
|
||||
removeAttr(envElm, 'style');
|
||||
|
||||
@@ -1,24 +1,37 @@
|
||||
import { isFunction, isNull, isUndefined } from 'support';
|
||||
import { isBoolean, isFunction, isNull, isUndefined } from 'support';
|
||||
import type {
|
||||
StructureInitialization,
|
||||
StructureInitializationStrategy,
|
||||
DefaultStructureInitialization,
|
||||
} from 'setups/structureSetup';
|
||||
import type {
|
||||
ScrollbarsInitialization,
|
||||
ScrollbarsInitializationStrategy,
|
||||
DefaultScrollbarsInitialization,
|
||||
} from 'setups/scrollbarsSetup';
|
||||
import { getEnvironment } from 'environment';
|
||||
import { DeepPartial } from 'typings';
|
||||
import { StructureSetupElementsObj } from 'setups/structureSetup/structureSetup.elements';
|
||||
|
||||
type StaticInitialization = HTMLElement | null | undefined;
|
||||
type DynamicInitialization = HTMLElement | boolean | null | undefined;
|
||||
|
||||
export type CancelInitialization = {
|
||||
cancel: {
|
||||
nativeScrollbarsOverlaid: boolean | undefined;
|
||||
body: boolean | null | undefined;
|
||||
};
|
||||
};
|
||||
|
||||
export type InitializationTargetElement = HTMLElement | HTMLTextAreaElement;
|
||||
|
||||
export type InitializationTargetObject = StructureInitialization & ScrollbarsInitialization;
|
||||
export type InitializationTargetObject = StructureInitialization &
|
||||
ScrollbarsInitialization &
|
||||
DeepPartial<CancelInitialization>;
|
||||
|
||||
export type InitializationTarget = InitializationTargetElement | InitializationTargetObject;
|
||||
|
||||
export type InitializationStrategy = StructureInitializationStrategy &
|
||||
ScrollbarsInitializationStrategy;
|
||||
export type DefaultInitialization = DefaultStructureInitialization &
|
||||
DefaultScrollbarsInitialization &
|
||||
CancelInitialization;
|
||||
|
||||
/**
|
||||
* Static elements MUST be present.
|
||||
@@ -39,9 +52,9 @@ export type DynamicInitializationElement<Args extends any[]> =
|
||||
| ((...args: Args) => DynamicInitialization)
|
||||
| DynamicInitialization;
|
||||
|
||||
export type InitializtationElementStrategy<InitElm> = Exclude<InitElm, HTMLElement>;
|
||||
export type DefaultInitializtationElement<InitElm> = Exclude<InitElm, HTMLElement>;
|
||||
|
||||
export type DefaultInitializtationElementStrategy<
|
||||
export type FallbackInitializtationElement<
|
||||
InitElm extends StaticInitializationElement<any> | DynamicInitializationElement<any>
|
||||
> = Extract<InitElm, (...args: any[]) => any> extends (...args: infer P) => any
|
||||
? (...args: P) => HTMLElement
|
||||
@@ -52,20 +65,20 @@ const resolveInitialization = <T>(value: any, args: any): T =>
|
||||
|
||||
const staticInitializationElement = <T extends StaticInitializationElement<any>>(
|
||||
args: Parameters<Extract<T, (...args: any[]) => any>>,
|
||||
defaultStaticInitializationElement: DefaultInitializtationElementStrategy<T>,
|
||||
staticInitializationElementStrategy?: InitializtationElementStrategy<T>,
|
||||
fallbackStaticInitializationElement: FallbackInitializtationElement<T>,
|
||||
defaultStaticInitializationElementStrategy?: DefaultInitializtationElement<T>,
|
||||
staticInitializationElementValue?: T | false
|
||||
): HTMLElement =>
|
||||
resolveInitialization<StaticInitialization>(
|
||||
staticInitializationElementValue ||
|
||||
resolveInitialization<StaticInitialization>(staticInitializationElementStrategy, args),
|
||||
resolveInitialization<StaticInitialization>(defaultStaticInitializationElementStrategy, args),
|
||||
args
|
||||
) || defaultStaticInitializationElement.apply(0, args);
|
||||
) || fallbackStaticInitializationElement.apply(0, args);
|
||||
|
||||
const dynamicInitializationElement = <T extends DynamicInitializationElement<any>>(
|
||||
args: Parameters<Extract<T, (...args: any[]) => any>>,
|
||||
defaultDynamicInitializationElement: DefaultInitializtationElementStrategy<T>,
|
||||
dynamicInitializationElementStrategy?: InitializtationElementStrategy<T>,
|
||||
fallbackDynamicInitializationElement: FallbackInitializtationElement<T>,
|
||||
defaultDynamicInitializationElementStrategy?: DefaultInitializtationElement<T>,
|
||||
dynamicInitializationElementValue?: T | false
|
||||
): HTMLElement | false => {
|
||||
let result = resolveInitialization<DynamicInitialization>(
|
||||
@@ -75,14 +88,40 @@ const dynamicInitializationElement = <T extends DynamicInitializationElement<any
|
||||
|
||||
if (isNull(result) || isUndefined(result)) {
|
||||
result = resolveInitialization<DynamicInitialization>(
|
||||
dynamicInitializationElementStrategy,
|
||||
defaultDynamicInitializationElementStrategy,
|
||||
args
|
||||
);
|
||||
}
|
||||
|
||||
return result === true || isNull(result) || isUndefined(result)
|
||||
? defaultDynamicInitializationElement.apply(0, args)
|
||||
? fallbackDynamicInitializationElement.apply(0, args)
|
||||
: result;
|
||||
};
|
||||
|
||||
export { staticInitializationElement, dynamicInitializationElement };
|
||||
const cancelInitialization = (
|
||||
cancelInitializationValue: DeepPartial<CancelInitialization['cancel']> | false | null | undefined,
|
||||
structureSetupElements: StructureSetupElementsObj
|
||||
): boolean => {
|
||||
const { nativeScrollbarsOverlaid, body } = cancelInitializationValue || {};
|
||||
const { _isBody, _viewportIsTarget } = structureSetupElements;
|
||||
const { _getDefaultInitialization, _nativeScrollbarsOverlaid } = getEnvironment();
|
||||
const { nativeScrollbarsOverlaid: defaultNativeScrollbarsOverlaid, body: defaultbody } =
|
||||
_getDefaultInitialization().cancel;
|
||||
|
||||
const resolvedNativeScrollbarsOverlaid =
|
||||
nativeScrollbarsOverlaid ?? defaultNativeScrollbarsOverlaid;
|
||||
const resolvedDocumentScrollingElement = isBoolean(body) || isNull(body) ? body : defaultbody;
|
||||
|
||||
const finalNativeScrollbarsOverlaid =
|
||||
(_nativeScrollbarsOverlaid.x || _nativeScrollbarsOverlaid.y) &&
|
||||
resolvedNativeScrollbarsOverlaid;
|
||||
const finalDocumentScrollingElement =
|
||||
_isBody &&
|
||||
(isNull(resolvedDocumentScrollingElement)
|
||||
? !_viewportIsTarget
|
||||
: resolvedDocumentScrollingElement);
|
||||
|
||||
return !!finalNativeScrollbarsOverlaid || !!finalDocumentScrollingElement;
|
||||
};
|
||||
|
||||
export { staticInitializationElement, dynamicInitializationElement, cancelInitialization };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { assignDeep, each, isObject, keys, isArray, hasOwnProperty, isFunction } from 'support';
|
||||
import { PartialOptions, ReadonlyOptions } from 'typings';
|
||||
import { DeepPartial, ReadonlyOptions } from 'typings';
|
||||
|
||||
const opsStringify = (value: any) =>
|
||||
JSON.stringify(value, (_, val) => {
|
||||
@@ -40,6 +40,7 @@ export type UpdatedCallback = (this: any, args?: UpdatedArgs) => void;
|
||||
|
||||
export interface Options {
|
||||
paddingAbsolute: boolean;
|
||||
showNativeOverlaidScrollbars: boolean;
|
||||
updating: {
|
||||
elementEvents: Array<[elementSelector: string, eventNames: string]> | null;
|
||||
attributes: string[] | null;
|
||||
@@ -59,10 +60,6 @@ export interface Options {
|
||||
clickScroll: boolean;
|
||||
touch: boolean;
|
||||
};
|
||||
nativeScrollbarsOverlaid: {
|
||||
show: boolean;
|
||||
initialize: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type ReadonlyOSOptions = ReadonlyOptions<Options>;
|
||||
@@ -97,6 +94,7 @@ export interface UpdatedArgs {
|
||||
export const defaultOptions: Options = {
|
||||
// resize: 'none', // none || both || horizontal || vertical || n || b || h || v
|
||||
paddingAbsolute: false, // true || false
|
||||
showNativeOverlaidScrollbars: false, // true || false
|
||||
updating: {
|
||||
elementEvents: [['img', 'load']], // array of tuples || null
|
||||
debounce: [0, 33], // number || number array || null
|
||||
@@ -107,10 +105,6 @@ export const defaultOptions: Options = {
|
||||
x: 'scroll', // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
|
||||
y: 'scroll', // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
|
||||
},
|
||||
nativeScrollbarsOverlaid: {
|
||||
show: false, // true || false
|
||||
initialize: false, // true || false
|
||||
},
|
||||
scrollbars: {
|
||||
theme: 'os-theme-dark',
|
||||
visibility: 'auto', // visible || hidden || auto || v || h || a
|
||||
@@ -129,11 +123,8 @@ export const defaultOptions: Options = {
|
||||
*/
|
||||
};
|
||||
|
||||
export const getOptionsDiff = <T>(
|
||||
currOptions: T,
|
||||
newOptions: PartialOptions<T>
|
||||
): PartialOptions<T> => {
|
||||
const diff: PartialOptions<T> = {};
|
||||
export const getOptionsDiff = <T>(currOptions: T, newOptions: DeepPartial<T>): DeepPartial<T> => {
|
||||
const diff: DeepPartial<T> = {};
|
||||
const optionsKeys = keys(newOptions).concat(keys(currOptions));
|
||||
|
||||
each(optionsKeys, (optionKey) => {
|
||||
|
||||
@@ -20,11 +20,12 @@ import {
|
||||
OptionsValidationPluginInstance,
|
||||
} from 'plugins';
|
||||
import { addInstance, getInstance, removeInstance } from 'instances';
|
||||
import type { PartialOptions, OverflowStyle } from 'typings';
|
||||
import type {
|
||||
import type { DeepPartial, OverflowStyle } from 'typings';
|
||||
import {
|
||||
InitializationTarget,
|
||||
InitializationTargetObject,
|
||||
InitializationStrategy,
|
||||
DefaultInitialization,
|
||||
cancelInitialization,
|
||||
} from 'initialization';
|
||||
import type {
|
||||
InitialEventListeners as GeneralInitialEventListeners,
|
||||
@@ -34,7 +35,7 @@ import type {
|
||||
export interface OverlayScrollbarsStatic {
|
||||
(
|
||||
target: InitializationTarget | InitializationTargetObject,
|
||||
options?: PartialOptions<Options>,
|
||||
options?: DeepPartial<Options>,
|
||||
eventListeners?: GeneralInitialEventListeners<EventListenerMap>
|
||||
): OverlayScrollbars;
|
||||
|
||||
@@ -49,13 +50,13 @@ export interface Environment {
|
||||
rtlScrollBehavior: { n: boolean; i: boolean };
|
||||
flexboxGlue: boolean;
|
||||
cssCustomProperties: boolean;
|
||||
defaultInitializationStrategy: InitializationStrategy;
|
||||
defaultDefaultOptions: Options;
|
||||
staticDefaultInitialization: DefaultInitialization;
|
||||
staticDefaultOptions: Options;
|
||||
|
||||
getInitializationStrategy(): InitializationStrategy;
|
||||
setInitializationStrategy(newInitializationStrategy: Partial<InitializationStrategy>): void;
|
||||
getDefaultInitialization(): DefaultInitialization;
|
||||
setDefaultInitialization(newDefaultInitialization: DeepPartial<DefaultInitialization>): void;
|
||||
getDefaultOptions(): Options;
|
||||
setDefaultOptions(newDefaultOptions: PartialOptions<Options>): void;
|
||||
setDefaultOptions(newDefaultOptions: DeepPartial<Options>): void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
@@ -87,7 +88,7 @@ export interface OnUpdatedEventListenerArgs {
|
||||
hostMutation: boolean;
|
||||
contentMutation: boolean;
|
||||
};
|
||||
changedOptions: PartialOptions<Options>;
|
||||
changedOptions: DeepPartial<Options>;
|
||||
force: boolean;
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ export type EventListenerMap = {
|
||||
/**
|
||||
* Triggered after all elements, observers and events are destroyed.
|
||||
*/
|
||||
destroyed: [instance: OverlayScrollbars, withdrawn: boolean];
|
||||
destroyed: [instance: OverlayScrollbars, canceled: boolean];
|
||||
};
|
||||
|
||||
export type InitialEventListeners = GeneralInitialEventListeners<EventListenerMap>;
|
||||
@@ -115,7 +116,7 @@ export type EventListener<Name extends keyof EventListenerMap> = GeneralEventLis
|
||||
|
||||
export interface OverlayScrollbars {
|
||||
options(): Options;
|
||||
options(newOptions?: PartialOptions<Options>): Options;
|
||||
options(newOptions?: DeepPartial<Options>): Options;
|
||||
|
||||
update(force?: boolean): OverlayScrollbars;
|
||||
|
||||
@@ -143,13 +144,10 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
eventListeners?
|
||||
): OverlayScrollbars => {
|
||||
let destroyed = false;
|
||||
const {
|
||||
_getDefaultOptions,
|
||||
_nativeScrollbarsOverlaid: _nativeScrollbarIsOverlaid,
|
||||
_addListener: addEnvListener,
|
||||
} = getEnvironment();
|
||||
const { _getDefaultOptions, _addListener: addEnvListener } = getEnvironment();
|
||||
const plugins = getPlugins();
|
||||
const instanceTarget = isHTMLElement(target) ? target : target.target;
|
||||
const targetIsElement = isHTMLElement(target);
|
||||
const instanceTarget = targetIsElement ? target : target.target;
|
||||
const potentialInstance = getInstance(instanceTarget);
|
||||
if (potentialInstance) {
|
||||
return potentialInstance;
|
||||
@@ -158,7 +156,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
const optionsValidationPlugin = plugins[
|
||||
optionsValidationPluginName
|
||||
] as OptionsValidationPluginInstance;
|
||||
const validateOptions = (newOptions?: PartialOptions<Options>) => {
|
||||
const validateOptions = (newOptions?: DeepPartial<Options>) => {
|
||||
const opts = newOptions || {};
|
||||
const validate = optionsValidationPlugin && optionsValidationPlugin._;
|
||||
return validate ? validate(opts, true) : opts;
|
||||
@@ -178,11 +176,11 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
currentOptions,
|
||||
structureState
|
||||
);
|
||||
const update = (changedOptions: PartialOptions<Options>, force?: boolean) => {
|
||||
const update = (changedOptions: DeepPartial<Options>, force?: boolean) => {
|
||||
updateStructure(changedOptions, !!force);
|
||||
};
|
||||
const removeEnvListener = addEnvListener(update.bind(0, {}, true));
|
||||
const destroy = (withdrawn?: boolean) => {
|
||||
const destroy = (canceled?: boolean) => {
|
||||
removeInstance(instanceTarget);
|
||||
removeEnvListener();
|
||||
|
||||
@@ -192,12 +190,12 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
destroyed = true;
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
triggerEvent('destroyed', [instance, !!withdrawn]);
|
||||
triggerEvent('destroyed', [instance, !!canceled]);
|
||||
removeEvent();
|
||||
};
|
||||
|
||||
const instance: OverlayScrollbars = {
|
||||
options(newOptions?: PartialOptions<Options>) {
|
||||
options(newOptions?: DeepPartial<Options>) {
|
||||
if (newOptions) {
|
||||
const changedOptions = getOptionsDiff(currentOptions, validateOptions(newOptions));
|
||||
|
||||
@@ -265,11 +263,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
}
|
||||
});
|
||||
|
||||
if (
|
||||
_nativeScrollbarIsOverlaid.x &&
|
||||
_nativeScrollbarIsOverlaid.y &&
|
||||
!currentOptions.nativeScrollbarsOverlaid.initialize
|
||||
) {
|
||||
if (cancelInitialization(!targetIsElement && target.cancel, structureState._elements)) {
|
||||
destroy(true);
|
||||
return instance;
|
||||
}
|
||||
@@ -323,10 +317,10 @@ OverlayScrollbars.env = () => {
|
||||
_rtlScrollBehavior,
|
||||
_flexboxGlue,
|
||||
_cssCustomProperties,
|
||||
_defaultInitializationStrategy,
|
||||
_defaultDefaultOptions,
|
||||
_getInitializationStrategy,
|
||||
_setInitializationStrategy,
|
||||
_staticDefaultInitialization,
|
||||
_staticDefaultOptions,
|
||||
_getDefaultInitialization,
|
||||
_setDefaultInitialization,
|
||||
_getDefaultOptions,
|
||||
_setDefaultOptions,
|
||||
} = getEnvironment();
|
||||
@@ -339,11 +333,11 @@ OverlayScrollbars.env = () => {
|
||||
rtlScrollBehavior: _rtlScrollBehavior,
|
||||
flexboxGlue: _flexboxGlue,
|
||||
cssCustomProperties: _cssCustomProperties,
|
||||
defaultInitializationStrategy: _defaultInitializationStrategy,
|
||||
defaultDefaultOptions: _defaultDefaultOptions,
|
||||
staticDefaultInitialization: _staticDefaultInitialization,
|
||||
staticDefaultOptions: _staticDefaultOptions,
|
||||
|
||||
getInitializationStrategy: _getInitializationStrategy,
|
||||
setInitializationStrategy: _setInitializationStrategy,
|
||||
getDefaultInitialization: _getDefaultInitialization,
|
||||
setDefaultInitialization: _setDefaultInitialization,
|
||||
getDefaultOptions: _getDefaultOptions,
|
||||
setDefaultOptions: _setDefaultOptions,
|
||||
}
|
||||
|
||||
+4
-7
@@ -10,7 +10,7 @@ import {
|
||||
OptionsTemplateValue,
|
||||
optionsTemplateTypes as oTypes,
|
||||
} from 'plugins/optionsValidationPlugin/validation';
|
||||
import type { PartialOptions } from 'typings';
|
||||
import type { DeepPartial } from 'typings';
|
||||
import type { Plugin } from 'plugins';
|
||||
|
||||
const numberAllowedValues: OptionsTemplateValue<number> = oTypes.number;
|
||||
@@ -26,6 +26,7 @@ const scrollbarsAutoHideAllowedValues: OptionsTemplateValue<ScrollbarAutoHideBeh
|
||||
const optionsTemplate: OptionsTemplate<Options> = {
|
||||
// resize: resizeAllowedValues, // none || both || horizontal || vertical || n || b ||
|
||||
paddingAbsolute: booleanAllowedValues, // true || false
|
||||
showNativeOverlaidScrollbars: booleanAllowedValues, // true || false
|
||||
updating: {
|
||||
elementEvents: arrayNullValues, // array of tuples || null
|
||||
attributes: arrayNullValues,
|
||||
@@ -52,21 +53,17 @@ const optionsTemplate: OptionsTemplate<Options> = {
|
||||
inheritedAttrs: stringArrayNullAllowedValues, // string || array || nul
|
||||
},
|
||||
*/
|
||||
nativeScrollbarsOverlaid: {
|
||||
show: booleanAllowedValues, // true || false
|
||||
initialize: booleanAllowedValues, // true || false
|
||||
},
|
||||
};
|
||||
|
||||
export type OptionsValidationPluginInstance = {
|
||||
_: (options: PartialOptions<Options>, doWriteErrors?: boolean) => PartialOptions<Options>;
|
||||
_: (options: DeepPartial<Options>, doWriteErrors?: boolean) => DeepPartial<Options>;
|
||||
};
|
||||
|
||||
export const optionsValidationPluginName = '__osOptionsValidationPlugin';
|
||||
|
||||
export const optionsValidationPlugin: Plugin<OptionsValidationPluginInstance> = {
|
||||
[optionsValidationPluginName]: {
|
||||
_: (options: PartialOptions<Options>, doWriteErrors?: boolean) => {
|
||||
_: (options: DeepPartial<Options>, doWriteErrors?: boolean) => {
|
||||
const [validated, foreign] = validateOptions(optionsTemplate, options, doWriteErrors);
|
||||
return { ...foreign, ...validated };
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { each, hasOwnProperty, keys, push, isEmptyObject } from 'support/utils';
|
||||
import { type, isArray, isUndefined, isPlainObject, isString } from 'support/utils/types';
|
||||
import { PlainObject, PartialOptions } from 'typings';
|
||||
import { PlainObject, DeepPartial } from 'typings';
|
||||
|
||||
export type OptionsObjectType = Record<string, unknown>;
|
||||
export type OptionsFunctionType = (this: any, ...args: any[]) => any;
|
||||
@@ -26,7 +26,7 @@ export type OptionsTemplate<T> = {
|
||||
};
|
||||
|
||||
export type OptionsValidationResult<T> = [
|
||||
PartialOptions<T>, // validated
|
||||
DeepPartial<T>, // validated
|
||||
Record<string, unknown> // foreign
|
||||
];
|
||||
|
||||
@@ -88,12 +88,12 @@ const optionsTemplateTypes: OptionsTemplateTypesDictionary = {
|
||||
*/
|
||||
const validateRecursive = <T extends PlainObject>(
|
||||
template: OptionsTemplate<T>,
|
||||
options: PartialOptions<T>,
|
||||
options: DeepPartial<T>,
|
||||
doWriteErrors?: boolean,
|
||||
propPath?: string
|
||||
): OptionsValidationResult<T> => {
|
||||
const validatedOptions: PartialOptions<T> = {};
|
||||
const optionsCopy: PartialOptions<T> = { ...options };
|
||||
const validatedOptions: DeepPartial<T> = {};
|
||||
const optionsCopy: DeepPartial<T> = { ...options };
|
||||
const props = keys(template).filter((prop) => hasOwnProperty(options, prop));
|
||||
|
||||
each(props, (prop: Extract<keyof T, string>) => {
|
||||
@@ -189,7 +189,7 @@ const validateRecursive = <T extends PlainObject>(
|
||||
*/
|
||||
const validateOptions = <T extends PlainObject>(
|
||||
template: OptionsTemplate<T>,
|
||||
options: PartialOptions<T>,
|
||||
options: DeepPartial<T>,
|
||||
doWriteErrors?: boolean
|
||||
): OptionsValidationResult<T> => validateRecursive<T>(template, options, doWriteErrors);
|
||||
|
||||
|
||||
+3
-7
@@ -82,15 +82,11 @@ export const scrollbarsHidingPluginName = '__osScrollbarsHidingPlugin';
|
||||
export const scrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> = {
|
||||
[scrollbarsHidingPluginName]: {
|
||||
_createUniqueViewportArrangeElement: (env: InternalEnvironment) => {
|
||||
const {
|
||||
_nativeScrollbarsHiding: _nativeScrollbarStyling,
|
||||
_nativeScrollbarsOverlaid: _nativeScrollbarIsOverlaid,
|
||||
_cssCustomProperties,
|
||||
} = env;
|
||||
const { _nativeScrollbarsHiding, _nativeScrollbarsOverlaid, _cssCustomProperties } = env;
|
||||
const create =
|
||||
!_cssCustomProperties &&
|
||||
!_nativeScrollbarStyling &&
|
||||
(_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
|
||||
!_nativeScrollbarsHiding &&
|
||||
(_nativeScrollbarsOverlaid.x || _nativeScrollbarsOverlaid.y);
|
||||
const result = create ? document.createElement('style') : false;
|
||||
|
||||
if (result) {
|
||||
|
||||
@@ -29,7 +29,7 @@ import type { InitializationTarget } from 'initialization';
|
||||
import type { StructureSetupElementsObj } from 'setups/structureSetup/structureSetup.elements';
|
||||
import type {
|
||||
ScrollbarsInitialization,
|
||||
ScrollbarsInitializationStrategy,
|
||||
DefaultScrollbarsInitialization,
|
||||
ScrollbarsDynamicInitializationElement,
|
||||
} from 'setups/scrollbarsSetup/scrollbarsSetup.initialization';
|
||||
import { StyleObject } from 'typings';
|
||||
@@ -85,19 +85,17 @@ export const createScrollbarsSetupElements = (
|
||||
target: InitializationTarget,
|
||||
structureSetupElements: StructureSetupElementsObj
|
||||
): ScrollbarsSetupElements => {
|
||||
const { _getInitializationStrategy } = getEnvironment();
|
||||
const { scrollbarsSlot: environmentScrollbarSlot } =
|
||||
_getInitializationStrategy() as ScrollbarsInitializationStrategy;
|
||||
const { _getDefaultInitialization } = getEnvironment();
|
||||
const { scrollbarsSlot: defaultScrollbarSlot } =
|
||||
_getDefaultInitialization() as DefaultScrollbarsInitialization;
|
||||
const { _documentElm, _target, _host, _viewport, _targetIsElm } = structureSetupElements;
|
||||
const initializationScrollbarSlot = _targetIsElm
|
||||
? null
|
||||
: (target as ScrollbarsInitialization).scrollbarsSlot;
|
||||
const scrollbarSlot = _targetIsElm ? null : (target as ScrollbarsInitialization).scrollbarsSlot;
|
||||
const evaluatedScrollbarSlot =
|
||||
generalDynamicInitializationElement<ScrollbarsDynamicInitializationElement>(
|
||||
[_target, _host, _viewport],
|
||||
() => _host,
|
||||
environmentScrollbarSlot,
|
||||
initializationScrollbarSlot
|
||||
defaultScrollbarSlot,
|
||||
scrollbarSlot
|
||||
);
|
||||
const scrollbarsAddRemoveClass = (
|
||||
scrollbarStructures: ScrollbarStructure[],
|
||||
|
||||
+3
-5
@@ -1,6 +1,6 @@
|
||||
import type {
|
||||
InitializationTargetElement,
|
||||
InitializtationElementStrategy,
|
||||
DefaultInitializtationElement,
|
||||
DynamicInitializationElement,
|
||||
} from 'initialization';
|
||||
|
||||
@@ -20,8 +20,6 @@ export interface ScrollbarsInitialization {
|
||||
scrollbarsSlot?: ScrollbarsDynamicInitializationElement;
|
||||
}
|
||||
|
||||
export type ScrollbarsInitializationStrategy = {
|
||||
[K in keyof ScrollbarsInitialization]: InitializtationElementStrategy<
|
||||
ScrollbarsInitialization[K]
|
||||
>;
|
||||
export type DefaultScrollbarsInitialization = {
|
||||
[K in keyof ScrollbarsInitialization]: DefaultInitializtationElement<ScrollbarsInitialization[K]>;
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { assignDeep, hasOwnProperty } from 'support';
|
||||
import type { Options, ReadonlyOSOptions } from 'options';
|
||||
import type { PartialOptions } from 'typings';
|
||||
import type { DeepPartial } from 'typings';
|
||||
|
||||
export type SetupElements<T extends Record<string, any>> = [elements: T, destroy: () => void];
|
||||
|
||||
export type SetupUpdate<T extends any[]> = (
|
||||
changedOptions: PartialOptions<Options>,
|
||||
changedOptions: DeepPartial<Options>,
|
||||
force: boolean,
|
||||
...args: T
|
||||
) => void;
|
||||
@@ -37,7 +37,7 @@ const getPropByPath = <T>(obj: any, path: string): T =>
|
||||
export const createOptionCheck =
|
||||
(
|
||||
options: ReadonlyOSOptions,
|
||||
changedOptions: PartialOptions<Options>,
|
||||
changedOptions: DeepPartial<Options>,
|
||||
force?: boolean
|
||||
): SetupUpdateCheckOption =>
|
||||
(path: string) =>
|
||||
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
attrClass,
|
||||
hasAttrClass,
|
||||
ResizeObserverConstructor,
|
||||
hasOwnProperty,
|
||||
noop,
|
||||
} from 'support';
|
||||
import {
|
||||
dataAttributeHost,
|
||||
@@ -28,7 +30,7 @@ import {
|
||||
classNamePadding,
|
||||
classNameViewport,
|
||||
classNameContent,
|
||||
classNameViewportScrollbarStyling,
|
||||
classNameViewportScrollbarHidden,
|
||||
} from 'classnames';
|
||||
import { getEnvironment } from 'environment';
|
||||
import { getPlugins, scrollbarsHidingPluginName } from 'plugins';
|
||||
@@ -36,11 +38,11 @@ import type { ScrollbarsHidingPluginInstance } from 'plugins/scrollbarsHidingPlu
|
||||
import {
|
||||
staticInitializationElement as generalStaticInitializationElement,
|
||||
dynamicInitializationElement as generalDynamicInitializationElement,
|
||||
InitializationTargetObject,
|
||||
} from 'initialization';
|
||||
import type { InitializationTarget, InitializationTargetElement } from 'initialization';
|
||||
import type {
|
||||
StructureDynamicInitializationElement,
|
||||
StructureInitialization,
|
||||
StructureStaticInitializationElement,
|
||||
} from 'setups/structureSetup/structureSetup.initialization';
|
||||
|
||||
@@ -60,8 +62,6 @@ export interface StructureSetupElementsObj {
|
||||
// ctx ----
|
||||
_isTextarea: boolean;
|
||||
_isBody: boolean;
|
||||
_htmlElm: HTMLHtmlElement;
|
||||
_bodyElm: HTMLBodyElement;
|
||||
_windowElm: Window;
|
||||
_documentElm: Document;
|
||||
_targetIsElm: boolean;
|
||||
@@ -86,29 +86,35 @@ export const createStructureSetupElements = (
|
||||
target: InitializationTarget
|
||||
): StructureSetupElements => {
|
||||
const env = getEnvironment();
|
||||
const { _getInitializationStrategy, _nativeScrollbarsHiding } = env;
|
||||
const { _getDefaultInitialization, _nativeScrollbarsHiding } = env;
|
||||
const scrollbarsHidingPlugin = getPlugins()[scrollbarsHidingPluginName] as
|
||||
| ScrollbarsHidingPluginInstance
|
||||
| undefined;
|
||||
const createUniqueViewportArrangeElement =
|
||||
scrollbarsHidingPlugin && scrollbarsHidingPlugin._createUniqueViewportArrangeElement;
|
||||
const {
|
||||
host: hostInitializationStrategy,
|
||||
viewport: viewportInitializationStrategy,
|
||||
padding: paddingInitializationStrategy,
|
||||
content: contentInitializationStrategy,
|
||||
} = _getInitializationStrategy();
|
||||
host: defaultHostInitializationStrategy,
|
||||
viewport: defaultViewportInitializationStrategy,
|
||||
padding: defaultPaddingInitializationStrategy,
|
||||
content: defaultContentInitializationStrategy,
|
||||
} = _getDefaultInitialization();
|
||||
const targetIsElm = isHTMLElement(target);
|
||||
const targetStructureInitialization = target as StructureInitialization;
|
||||
const targetElement = targetIsElm
|
||||
? (target as InitializationTargetElement)
|
||||
: targetStructureInitialization.target;
|
||||
const targetStructureInitialization = (targetIsElm ? {} : target) as InitializationTargetObject;
|
||||
const {
|
||||
host: hostInitializationStrategy,
|
||||
padding: paddingInitializationStrategy,
|
||||
viewport: viewportInitializationStrategy,
|
||||
content: contentInitializationStrategy,
|
||||
} = targetStructureInitialization;
|
||||
|
||||
const targetElement = targetIsElm ? target : targetStructureInitialization.target;
|
||||
const isTextarea = is(targetElement, 'textarea');
|
||||
const isBody = !isTextarea && is(targetElement, 'body');
|
||||
const ownerDocument = targetElement!.ownerDocument;
|
||||
const bodyElm = ownerDocument.body as HTMLBodyElement;
|
||||
const ownerDocument = targetElement.ownerDocument;
|
||||
const isBody = targetElement === ownerDocument.body;
|
||||
const wnd = ownerDocument.defaultView as Window;
|
||||
const singleElmSupport = !!ResizeObserverConstructor && !isTextarea && _nativeScrollbarsHiding;
|
||||
const singleElmSupport = isBody
|
||||
? _nativeScrollbarsHiding
|
||||
: !!ResizeObserverConstructor && !isTextarea && _nativeScrollbarsHiding;
|
||||
const staticInitializationElement =
|
||||
generalStaticInitializationElement<StructureStaticInitializationElement>.bind(0, [
|
||||
targetElement,
|
||||
@@ -120,13 +126,15 @@ export const createStructureSetupElements = (
|
||||
const viewportElement = [
|
||||
staticInitializationElement(
|
||||
createNewDiv,
|
||||
viewportInitializationStrategy,
|
||||
targetStructureInitialization.viewport
|
||||
defaultViewportInitializationStrategy,
|
||||
isBody && !hasOwnProperty(targetStructureInitialization, 'viewport')
|
||||
? targetElement
|
||||
: viewportInitializationStrategy
|
||||
),
|
||||
staticInitializationElement(createNewDiv, viewportInitializationStrategy),
|
||||
staticInitializationElement(createNewDiv, defaultViewportInitializationStrategy),
|
||||
staticInitializationElement(createNewDiv),
|
||||
].filter((potentialViewport) =>
|
||||
!singleElmSupport ? potentialViewport !== targetElement : true
|
||||
singleElmSupport ? true : potentialViewport !== targetElement
|
||||
)[0];
|
||||
const viewportIsTarget = viewportElement === targetElement;
|
||||
const evaluatedTargetObj: StructureSetupElementsObj = {
|
||||
@@ -134,8 +142,8 @@ export const createStructureSetupElements = (
|
||||
_host: isTextarea
|
||||
? staticInitializationElement(
|
||||
createNewDiv,
|
||||
hostInitializationStrategy,
|
||||
targetStructureInitialization.host
|
||||
defaultHostInitializationStrategy,
|
||||
hostInitializationStrategy
|
||||
)
|
||||
: (targetElement as HTMLElement),
|
||||
_viewport: viewportElement,
|
||||
@@ -143,15 +151,15 @@ export const createStructureSetupElements = (
|
||||
!viewportIsTarget &&
|
||||
dynamicInitializationElement(
|
||||
createNewDiv,
|
||||
paddingInitializationStrategy,
|
||||
targetStructureInitialization.padding
|
||||
defaultPaddingInitializationStrategy,
|
||||
paddingInitializationStrategy
|
||||
),
|
||||
_content:
|
||||
!viewportIsTarget &&
|
||||
dynamicInitializationElement(
|
||||
createNewDiv,
|
||||
contentInitializationStrategy,
|
||||
targetStructureInitialization.content
|
||||
defaultContentInitializationStrategy,
|
||||
contentInitializationStrategy
|
||||
),
|
||||
_viewportArrange:
|
||||
!viewportIsTarget &&
|
||||
@@ -160,8 +168,6 @@ export const createStructureSetupElements = (
|
||||
createUniqueViewportArrangeElement(env),
|
||||
_windowElm: wnd,
|
||||
_documentElm: ownerDocument,
|
||||
_htmlElm: parent(bodyElm) as HTMLHtmlElement,
|
||||
_bodyElm: bodyElm,
|
||||
_isTextarea: isTextarea,
|
||||
_isBody: isBody,
|
||||
_targetIsElm: targetIsElm,
|
||||
@@ -197,6 +203,9 @@ export const createStructureSetupElements = (
|
||||
const removePaddingClass = addClass(_padding, classNamePadding);
|
||||
const removeViewportClass = addClass(_viewport, !viewportIsTarget && classNameViewport);
|
||||
const removeContentClass = addClass(_content, classNameContent);
|
||||
const removeHtmlClass = isBody
|
||||
? addClass(parent(targetElement), classNameViewportScrollbarHidden)
|
||||
: noop;
|
||||
|
||||
// only insert host for textarea after target if it was generated
|
||||
if (isTextareaHostGenerated) {
|
||||
@@ -214,6 +223,7 @@ export const createStructureSetupElements = (
|
||||
appendChildren(_viewport, _content);
|
||||
|
||||
push(destroyFns, () => {
|
||||
removeHtmlClass();
|
||||
removeHostDataAttr();
|
||||
removeAttr(_viewport, dataAttributeHostOverflowX);
|
||||
removeAttr(_viewport, dataAttributeHostOverflowY);
|
||||
@@ -233,7 +243,7 @@ export const createStructureSetupElements = (
|
||||
});
|
||||
|
||||
if (_nativeScrollbarsHiding && !viewportIsTarget) {
|
||||
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));
|
||||
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarHidden));
|
||||
}
|
||||
if (_viewportArrange) {
|
||||
insertBefore(_viewport, _viewportArrange);
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@ import type {
|
||||
InitializationTargetElement,
|
||||
StaticInitializationElement,
|
||||
DynamicInitializationElement,
|
||||
InitializtationElementStrategy,
|
||||
DefaultInitializtationElement,
|
||||
} from 'initialization';
|
||||
|
||||
export type StructureStaticInitializationElement = StaticInitializationElement<
|
||||
@@ -31,8 +31,8 @@ export interface StructureInitialization {
|
||||
content?: StructureDynamicInitializationElement;
|
||||
}
|
||||
|
||||
export type StructureInitializationStrategy = {
|
||||
[K in keyof Omit<StructureInitialization, 'target'>]: InitializtationElementStrategy<
|
||||
export type DefaultStructureInitialization = {
|
||||
[K in keyof Omit<StructureInitialization, 'target'>]: DefaultInitializtationElement<
|
||||
StructureInitialization[K]
|
||||
>;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { TRBL, XY, EventListener } from 'support';
|
||||
import type { Options, ReadonlyOSOptions } from 'options';
|
||||
import type { Setup } from 'setups';
|
||||
import type { InitializationTarget } from 'initialization';
|
||||
import type { PartialOptions, StyleObject, OverflowStyle } from 'typings';
|
||||
import type { DeepPartial, StyleObject, OverflowStyle } from 'typings';
|
||||
|
||||
export interface StructureSetupState {
|
||||
_padding: TRBL;
|
||||
@@ -30,11 +30,7 @@ export interface StructureSetupStaticState {
|
||||
}
|
||||
|
||||
type StructureSetupEventMap = {
|
||||
u: [
|
||||
updateHints: StructureSetupUpdateHints,
|
||||
changedOptions: PartialOptions<Options>,
|
||||
force: boolean
|
||||
];
|
||||
u: [updateHints: StructureSetupUpdateHints, changedOptions: DeepPartial<Options>, force: boolean];
|
||||
};
|
||||
|
||||
const initialXYNumber = { x: 0, y: 0 };
|
||||
|
||||
@@ -57,13 +57,9 @@ export const createStructureSetupUpdate = (
|
||||
state: SetupState<StructureSetupState>
|
||||
): StructureSetupUpdate => {
|
||||
const { _viewport } = structureSetupElements;
|
||||
const {
|
||||
_nativeScrollbarsHiding: _nativeScrollbarStyling,
|
||||
_nativeScrollbarsOverlaid: _nativeScrollbarIsOverlaid,
|
||||
_flexboxGlue,
|
||||
} = getEnvironment();
|
||||
const { _nativeScrollbarsHiding, _nativeScrollbarsOverlaid, _flexboxGlue } = getEnvironment();
|
||||
const doViewportArrange =
|
||||
!_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
|
||||
!_nativeScrollbarsHiding && (_nativeScrollbarsOverlaid.x || _nativeScrollbarsOverlaid.y);
|
||||
|
||||
const updateSegments: StructureSetupUpdateSegment[] = [
|
||||
createTrinsicUpdateSegment(structureSetupElements, state),
|
||||
|
||||
+5
-5
@@ -16,12 +16,12 @@ import {
|
||||
} from 'support';
|
||||
import { getEnvironment } from 'environment';
|
||||
import {
|
||||
classNameViewportScrollbarStyling,
|
||||
classNameViewportScrollbarHidden,
|
||||
classNameOverflowVisible,
|
||||
dataAttributeHost,
|
||||
dataAttributeHostOverflowX,
|
||||
dataAttributeHostOverflowY,
|
||||
dataValueHostViewportScrollbarStyling,
|
||||
dataValueHostScrollbarHidden,
|
||||
dataValueHostOverflowVisible,
|
||||
} from 'classnames';
|
||||
import { getPlugins, scrollbarsHidingPluginName } from 'plugins';
|
||||
@@ -328,7 +328,7 @@ export const createOverflowUpdateSegment: CreateStructureUpdateSegment = (
|
||||
} = updateHints;
|
||||
const { _heightIntrinsic, _directionIsRTL } = getState();
|
||||
const [showNativeOverlaidScrollbarsOption, showNativeOverlaidScrollbarsChanged] =
|
||||
checkOption<boolean>('nativeScrollbarsOverlaid.show');
|
||||
checkOption<boolean>('showNativeOverlaidScrollbars');
|
||||
const [overflow, overflowChanged] = checkOption<XY<OverflowBehavior>>('overflow');
|
||||
|
||||
const showNativeOverlaidScrollbars =
|
||||
@@ -356,8 +356,8 @@ export const createOverflowUpdateSegment: CreateStructureUpdateSegment = (
|
||||
|
||||
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarsHiding) {
|
||||
_viewportAddRemoveClass(
|
||||
classNameViewportScrollbarStyling,
|
||||
dataValueHostViewportScrollbarStyling,
|
||||
classNameViewportScrollbarHidden,
|
||||
dataValueHostScrollbarHidden,
|
||||
!showNativeOverlaidScrollbars
|
||||
);
|
||||
}
|
||||
|
||||
@@ -53,17 +53,20 @@
|
||||
.os-viewport {
|
||||
-ms-overflow-style: scrollbar !important;
|
||||
}
|
||||
[data-overlayscrollbars~='viewportStyled'],
|
||||
.os-viewport-scrollbar-styled.os-environment,
|
||||
.os-viewport-scrollbar-styled.os-viewport {
|
||||
[data-overlayscrollbars~='scrollbarHidden'],
|
||||
html.os-viewport-scrollbar-hidden,
|
||||
.os-viewport-scrollbar-hidden.os-environment,
|
||||
.os-viewport-scrollbar-hidden.os-viewport {
|
||||
scrollbar-width: none !important;
|
||||
}
|
||||
[data-overlayscrollbars~='viewportStyled']::-webkit-scrollbar,
|
||||
[data-overlayscrollbars~='viewportStyled']::-webkit-scrollbar-corner,
|
||||
.os-viewport-scrollbar-styled.os-environment::-webkit-scrollbar,
|
||||
.os-viewport-scrollbar-styled.os-viewport::-webkit-scrollbar,
|
||||
.os-viewport-scrollbar-styled.os-environment::-webkit-scrollbar-corner,
|
||||
.os-viewport-scrollbar-styled.os-viewport::-webkit-scrollbar-corner {
|
||||
[data-overlayscrollbars~='scrollbarHidden']::-webkit-scrollbar,
|
||||
[data-overlayscrollbars~='scrollbarHidden']::-webkit-scrollbar-corner,
|
||||
html.os-viewport-scrollbar-hidden::-webkit-scrollbar,
|
||||
html.os-viewport-scrollbar-hidden::-webkit-scrollbar-corner,
|
||||
.os-viewport-scrollbar-hidden.os-environment::-webkit-scrollbar,
|
||||
.os-viewport-scrollbar-hidden.os-environment::-webkit-scrollbar-corner,
|
||||
.os-viewport-scrollbar-hidden.os-viewport::-webkit-scrollbar,
|
||||
.os-viewport-scrollbar-hidden.os-viewport::-webkit-scrollbar-corner {
|
||||
display: none !important;
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type PartialOptions<T> = {
|
||||
[P in keyof T]?: T[P] extends Record<string, unknown> ? PartialOptions<T[P]> : T[P];
|
||||
export type DeepPartial<T> = {
|
||||
[P in keyof T]?: T[P] extends Record<string, unknown> ? DeepPartial<T[P]> : T[P];
|
||||
};
|
||||
|
||||
export type ReadonlyOptions<T> = {
|
||||
@@ -15,382 +15,3 @@ export type StyleObject<CustomCssProps = ''> = {
|
||||
};
|
||||
|
||||
export type OverflowStyle = 'scroll' | 'hidden' | 'visible';
|
||||
|
||||
/*
|
||||
export namespace OverlayScrollbars {
|
||||
export type ResizeBehavior = 'none' | 'both' | 'horizontal' | 'vertical';
|
||||
|
||||
export type OverflowBehavior = 'hidden' | 'scroll' | 'visible-hidden' | 'visible-scroll';
|
||||
|
||||
export type VisibilityBehavior = 'visible' | 'hidden' | 'auto';
|
||||
|
||||
export type AutoHideBehavior = 'never' | 'scroll' | 'leave' | 'move';
|
||||
|
||||
export type ScrollBehavior = 'always' | 'ifneeded' | 'never';
|
||||
|
||||
export type BlockBehavior = 'begin' | 'end' | 'center' | 'nearest';
|
||||
|
||||
export type Easing = string | null | undefined;
|
||||
|
||||
export type Margin = number | boolean;
|
||||
|
||||
export type Position = number | string;
|
||||
|
||||
export type Extensions = string | ReadonlyArray<string> | { [extensionName: string]: {} };
|
||||
|
||||
export type BasicEventCallback = (this: OverlayScrollbars) => void;
|
||||
|
||||
export type ScrollEventCallback = (this: OverlayScrollbars, args?: UIEvent) => void;
|
||||
|
||||
export type OverflowChangedCallback = (this: OverlayScrollbars, args?: OverflowChangedArgs) => void;
|
||||
|
||||
export type OverflowAmountChangedCallback = (this: OverlayScrollbars, args?: OverflowAmountChangedArgs) => void;
|
||||
|
||||
export type DirectionChangedCallback = (this: OverlayScrollbars, args?: DirectionChangedArgs) => void;
|
||||
|
||||
export type SizeChangedCallback = (this: OverlayScrollbars, args?: SizeChangedArgs) => void;
|
||||
|
||||
export type UpdatedCallback = (this: OverlayScrollbars, args?: UpdatedArgs) => void;
|
||||
|
||||
export type Coordinates =
|
||||
| { x?: Position; y?: Position }
|
||||
| { l?: Position; t?: Position }
|
||||
| { left?: Position; top?: Position }
|
||||
| [Position, Position]
|
||||
| Position
|
||||
| HTMLElement
|
||||
| {
|
||||
el: HTMLElement;
|
||||
scroll?: ScrollBehavior | { x?: ScrollBehavior; y?: ScrollBehavior } | [ScrollBehavior, ScrollBehavior];
|
||||
block?: BlockBehavior | { x?: BlockBehavior; y?: BlockBehavior } | [BlockBehavior, BlockBehavior];
|
||||
margin?:
|
||||
| Margin
|
||||
| {
|
||||
top?: Margin;
|
||||
right?: Margin;
|
||||
bottom?: Margin;
|
||||
left?: Margin;
|
||||
}
|
||||
| [Margin, Margin]
|
||||
| [Margin, Margin, Margin, Margin];
|
||||
};
|
||||
|
||||
export interface OverflowChangedArgs {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xScrollable: boolean;
|
||||
yScrollable: boolean;
|
||||
clipped: boolean;
|
||||
}
|
||||
|
||||
export interface OverflowAmountChangedArgs {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface DirectionChangedArgs {
|
||||
isRTL: number;
|
||||
dir: string;
|
||||
}
|
||||
|
||||
export interface SizeChangedArgs {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface UpdatedArgs {
|
||||
forced: boolean;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
className?: string | null;
|
||||
resize?: ResizeBehavior;
|
||||
sizeAutoCapable?: boolean;
|
||||
clipAlways?: boolean;
|
||||
normalizeRTL?: boolean;
|
||||
paddingAbsolute?: boolean;
|
||||
autoUpdate?: boolean | null;
|
||||
autoUpdateInterval?: number;
|
||||
updateOnLoad?: string | ReadonlyArray<string> | null;
|
||||
nativeScrollbarsOverlaid?: {
|
||||
showNativeScrollbars?: boolean;
|
||||
initialize?: boolean;
|
||||
};
|
||||
overflowBehavior?: {
|
||||
x?: OverflowBehavior;
|
||||
y?: OverflowBehavior;
|
||||
};
|
||||
scrollbars?: {
|
||||
visibility?: VisibilityBehavior;
|
||||
autoHide?: AutoHideBehavior;
|
||||
autoHideDelay?: number;
|
||||
dragScrolling?: boolean;
|
||||
clickScrolling?: boolean;
|
||||
touchSupport?: boolean;
|
||||
snapHandle?: boolean;
|
||||
};
|
||||
textarea?: {
|
||||
dynWidth?: boolean;
|
||||
dynHeight?: boolean;
|
||||
inheritedAttrs?: string | ReadonlyArray<string> | null;
|
||||
};
|
||||
callbacks?: {
|
||||
onInitialized?: BasicEventCallback | null;
|
||||
onInitializationWithdrawn?: BasicEventCallback | null;
|
||||
onDestroyed?: BasicEventCallback | null;
|
||||
onScrollStart?: ScrollEventCallback | null;
|
||||
onScroll?: ScrollEventCallback | null;
|
||||
onScrollStop?: ScrollEventCallback | null;
|
||||
onOverflowChanged?: OverflowChangedCallback | null;
|
||||
onOverflowAmountChanged?: OverflowAmountChangedCallback | null;
|
||||
onDirectionChanged?: DirectionChangedCallback | null;
|
||||
onContentSizeChanged?: SizeChangedCallback | null;
|
||||
onHostSizeChanged?: SizeChangedCallback | null;
|
||||
onUpdated?: UpdatedCallback | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ScrollInfo {
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
ratio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
max: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLengthRatio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
trackLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
snappedHandleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
isRTL: boolean;
|
||||
isRTLNormalized: boolean;
|
||||
}
|
||||
|
||||
export interface Elements {
|
||||
target: HTMLElement;
|
||||
host: HTMLElement;
|
||||
padding: HTMLElement;
|
||||
viewport: HTMLElement;
|
||||
content: HTMLElement;
|
||||
scrollbarHorizontal: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarVertical: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarCorner: HTMLElement;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
destroyed: boolean;
|
||||
sleeping: boolean;
|
||||
autoUpdate: boolean;
|
||||
widthAuto: boolean;
|
||||
heightAuto: boolean;
|
||||
documentMixed: boolean;
|
||||
padding: {
|
||||
t: number;
|
||||
r: number;
|
||||
b: number;
|
||||
l: number;
|
||||
};
|
||||
overflowAmount: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
hideOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xs: boolean;
|
||||
ys: boolean;
|
||||
};
|
||||
hasOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
contentScrollSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
viewportSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
hostSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Extension {
|
||||
contract(global: any): boolean;
|
||||
|
||||
added(options?: {}): void;
|
||||
|
||||
removed(): void;
|
||||
|
||||
on(
|
||||
callbackName: string,
|
||||
callbackArgs?: UIEvent | OverflowChangedArgs | OverflowAmountChangedArgs | DirectionChangedArgs | SizeChangedArgs | UpdatedArgs,
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface ExtensionInfo {
|
||||
name: string;
|
||||
extensionFactory: (this: OverlayScrollbars, defaultOptions: {}, compatibility: Compatibility, framework: any) => Extension;
|
||||
defaultOptions?: {};
|
||||
}
|
||||
|
||||
export interface Globals {
|
||||
defaultOptions: {};
|
||||
autoUpdateLoop: boolean;
|
||||
autoUpdateRecommended: boolean;
|
||||
supportMutationObserver: boolean;
|
||||
supportResizeObserver: boolean;
|
||||
supportPassiveEvents: boolean;
|
||||
supportTransform: boolean;
|
||||
supportTransition: boolean;
|
||||
restrictedMeasuring: boolean;
|
||||
nativeScrollbarStyling: boolean;
|
||||
cssCalc: string | null;
|
||||
nativeScrollbarSize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
nativeScrollbarIsOverlaid: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
overlayScrollbarDummySize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
rtlScrollBehavior: {
|
||||
i: boolean;
|
||||
n: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Compatibility {
|
||||
wW(): number;
|
||||
wH(): number;
|
||||
mO(): any;
|
||||
rO(): any;
|
||||
rAF(): (callback: (...args: any[]) => any) => number;
|
||||
cAF(): (requestID: number) => void;
|
||||
now(): number;
|
||||
stpP(event: Event): void;
|
||||
prvD(event: Event): void;
|
||||
page(event: MouseEvent): { x: number; y: number };
|
||||
mBtn(event: MouseEvent): number;
|
||||
inA<T>(item: T, array: T[]): number;
|
||||
isA(obj: any): boolean;
|
||||
type(obj: any): string;
|
||||
bind(func: (...args: any[]) => any, thisObj: any, ...args: any[]): any;
|
||||
}
|
||||
}
|
||||
|
||||
interface OverlayScrollbars {
|
||||
options(): OverlayScrollbars.Options;
|
||||
options(options: OverlayScrollbars.Options): void;
|
||||
options(optionName: string): any;
|
||||
options(optionName: string, optionValue: {} | null): void;
|
||||
|
||||
update(force?: boolean): void;
|
||||
|
||||
sleep(): void;
|
||||
|
||||
scroll(): OverlayScrollbars.ScrollInfo;
|
||||
scroll(
|
||||
coordinates: OverlayScrollbars.Coordinates,
|
||||
duration?: number,
|
||||
easing?:
|
||||
| OverlayScrollbars.Easing
|
||||
| { x?: OverlayScrollbars.Easing; y?: OverlayScrollbars.Easing }
|
||||
| [OverlayScrollbars.Easing, OverlayScrollbars.Easing],
|
||||
complete?: (...args: any[]) => any,
|
||||
): void;
|
||||
scroll(coordinates: OverlayScrollbars.Coordinates, options: {}): void;
|
||||
|
||||
scrollStop(): OverlayScrollbars;
|
||||
|
||||
getElements(): OverlayScrollbars.Elements;
|
||||
getElements(elementName: string): any;
|
||||
|
||||
getState(): OverlayScrollbars.State;
|
||||
getState(stateProperty: string): any;
|
||||
|
||||
destroy(): void;
|
||||
|
||||
ext(): {};
|
||||
ext(extensionName: string): OverlayScrollbars.Extension;
|
||||
|
||||
addExt(extensionName: string, options: {}): OverlayScrollbars.Extension;
|
||||
|
||||
removeExt(extensionName: string): boolean;
|
||||
}
|
||||
|
||||
interface OverlayScrollbarsStatic {
|
||||
(element: HTMLElement | Element, options: OverlayScrollbars.Options, extensions?: OverlayScrollbars.Extensions): OverlayScrollbars;
|
||||
(element: HTMLElement | Element | null): OverlayScrollbars | undefined;
|
||||
|
||||
(elements: NodeListOf<Element> | ReadonlyArray<Element>, options: OverlayScrollbars.Options, extensions?: OverlayScrollbars.Extensions):
|
||||
| OverlayScrollbars
|
||||
| OverlayScrollbars[]
|
||||
| undefined;
|
||||
(elements: NodeListOf<Element> | ReadonlyArray<Element>, filter?: string | ((element: Element, instance: OverlayScrollbars) => boolean)):
|
||||
| OverlayScrollbars
|
||||
| OverlayScrollbars[]
|
||||
| undefined;
|
||||
|
||||
globals(): OverlayScrollbars.Globals;
|
||||
|
||||
defaultOptions(): OverlayScrollbars.Options;
|
||||
defaultOptions(newDefaultOptions: OverlayScrollbars.Options): void;
|
||||
|
||||
extension(): {
|
||||
[index: number]: OverlayScrollbars.ExtensionInfo;
|
||||
length: number;
|
||||
};
|
||||
extension(extensionName: string): OverlayScrollbars.ExtensionInfo;
|
||||
extension(
|
||||
extensionName: string,
|
||||
extensionFactory: (
|
||||
this: OverlayScrollbars,
|
||||
defaultOptions: {},
|
||||
compatibility: OverlayScrollbars.Compatibility,
|
||||
framework: any,
|
||||
) => OverlayScrollbars.Extension,
|
||||
defaultOptions?: {},
|
||||
): void;
|
||||
extension(extensionName: string, extensionFactory: null | undefined): void;
|
||||
|
||||
valid(osInstance: any): boolean;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
+5
-5
@@ -5,7 +5,7 @@ import {
|
||||
createStructureSetupElements,
|
||||
StructureSetupElementsObj,
|
||||
} from 'setups/structureSetup/structureSetup.elements';
|
||||
import type { InitializationTarget, InitializtationElementStrategy } from 'initialization';
|
||||
import type { InitializationTarget, DefaultInitializtationElement } from 'initialization';
|
||||
import type {
|
||||
StructureInitialization,
|
||||
StructureStaticInitializationElement,
|
||||
@@ -208,8 +208,8 @@ const assertCorrectSetupElements = (
|
||||
inputStrategy: StructureStaticInitializationElement | StructureDynamicInitializationElement,
|
||||
isStaticStrategy: boolean,
|
||||
strategy:
|
||||
| InitializtationElementStrategy<StructureStaticInitializationElement>
|
||||
| InitializtationElementStrategy<StructureDynamicInitializationElement>,
|
||||
| DefaultInitializtationElement<StructureStaticInitializationElement>
|
||||
| DefaultInitializtationElement<StructureDynamicInitializationElement>,
|
||||
kind: 'padding' | 'viewport' | 'content' | 'host'
|
||||
) => {
|
||||
const input = isFunction(inputStrategy) ? inputStrategy(target) : inputStrategy;
|
||||
@@ -224,7 +224,7 @@ const assertCorrectSetupElements = (
|
||||
if (input === undefined) {
|
||||
if (isStaticStrategy) {
|
||||
strategy =
|
||||
strategy as InitializtationElementStrategy<StructureStaticInitializationElement>;
|
||||
strategy as DefaultInitializtationElement<StructureStaticInitializationElement>;
|
||||
if (typeof strategy === 'function') {
|
||||
const result = strategy(target);
|
||||
if (_viewportIsTarget) {
|
||||
@@ -243,7 +243,7 @@ const assertCorrectSetupElements = (
|
||||
}
|
||||
} else {
|
||||
strategy =
|
||||
strategy as InitializtationElementStrategy<StructureDynamicInitializationElement>;
|
||||
strategy as DefaultInitializtationElement<StructureDynamicInitializationElement>;
|
||||
|
||||
if (typeof strategy === 'function') {
|
||||
const result = strategy(target);
|
||||
|
||||
+6
-63
@@ -2,67 +2,10 @@ import './index.scss';
|
||||
import 'index.scss';
|
||||
import { OverlayScrollbars } from 'overlayscrollbars';
|
||||
|
||||
OverlayScrollbars.env().setDefaultOptions({
|
||||
nativeScrollbarsOverlaid: { initialize: true },
|
||||
// test with different cancel values for body
|
||||
|
||||
OverlayScrollbars.env().setDefaultInitialization({
|
||||
cancel: { nativeScrollbarsOverlaid: false },
|
||||
});
|
||||
|
||||
OverlayScrollbars.env().setInitializationStrategy({ viewport: (target) => target });
|
||||
|
||||
window.os = OverlayScrollbars(document.body, {});
|
||||
|
||||
// test viewport inheritted attrs (tabindex) for multiple and single element init
|
||||
// test appear & resize for multiple and single element init
|
||||
// test children changing attr according to dom observer
|
||||
|
||||
/*
|
||||
import { OverlayScrollbars } from 'overlayscrollbars';
|
||||
|
||||
import should from 'should';
|
||||
import { resize } from '@/testing-browser/Resize';
|
||||
import { timeout } from '@/testing-browser/timeout';
|
||||
import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult';
|
||||
import { addClass, each, isArray, removeAttr, style } from 'support';
|
||||
|
||||
OverlayScrollbars.env().setDefaultOptions({
|
||||
nativeScrollbarsOverlaid: { initialize: true },
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
const startBtn: HTMLButtonElement | null = document.querySelector('#start');
|
||||
const target: HTMLElement | null = document.querySelector('#target');
|
||||
const updatesSlot: HTMLElement | null = document.querySelector('#update');
|
||||
|
||||
let updateCount = 0;
|
||||
|
||||
const osInstance = OverlayScrollbars(
|
||||
{ target: target! },
|
||||
{
|
||||
updating: {
|
||||
ignoreMutation(mutation) {
|
||||
console.log(mutation);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
updated() {
|
||||
updateCount++;
|
||||
requestAnimationFrame(() => {
|
||||
if (updatesSlot) {
|
||||
updatesSlot.textContent = `${updateCount}`;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const start = async () => {
|
||||
setTestResult(null);
|
||||
|
||||
setTestResult(true);
|
||||
};
|
||||
|
||||
startBtn?.addEventListener('click', start);
|
||||
*/
|
||||
// @ts-ignore
|
||||
window.os = OverlayScrollbars({ target: document.body, cancel: { body: null } }, {});
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ if (!OverlayScrollbars.env().scrollbarsHiding) {
|
||||
// @ts-ignore
|
||||
window.OverlayScrollbars = OverlayScrollbars;
|
||||
|
||||
OverlayScrollbars.env().setDefaultOptions({
|
||||
nativeScrollbarsOverlaid: { initialize: true },
|
||||
OverlayScrollbars.env().setDefaultInitialization({
|
||||
cancel: { nativeScrollbarsOverlaid: false },
|
||||
});
|
||||
|
||||
const startBtn: HTMLButtonElement | null = document.querySelector('#start');
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@ import { timeout } from '@/testing-browser/timeout';
|
||||
import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult';
|
||||
import { addClass, each, isArray, removeAttr, style } from 'support';
|
||||
|
||||
OverlayScrollbars.env().setDefaultOptions({
|
||||
nativeScrollbarsOverlaid: { initialize: true },
|
||||
OverlayScrollbars.env().setInitializationStrategy({
|
||||
cancel: { nativeScrollbarsOverlaid: false },
|
||||
});
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -23,7 +23,7 @@ import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult';
|
||||
import { generateClassChangeSelectCallback, iterateSelect } from '@/testing-browser/Select';
|
||||
import { timeout } from '@/testing-browser/timeout';
|
||||
import { Options } from 'options';
|
||||
import { PartialOptions } from 'typings';
|
||||
import { DeepPartial } from 'typings';
|
||||
import { addPlugin, scrollbarsHidingPlugin, sizeObserverPlugin } from 'plugins';
|
||||
|
||||
if (!window.ResizeObserver) {
|
||||
@@ -36,8 +36,8 @@ if (!OverlayScrollbars.env().scrollbarsHiding) {
|
||||
// @ts-ignore
|
||||
window.OverlayScrollbars = OverlayScrollbars;
|
||||
|
||||
OverlayScrollbars.env().setDefaultOptions({
|
||||
nativeScrollbarsOverlaid: { initialize: true },
|
||||
OverlayScrollbars.env().setDefaultInitialization({
|
||||
cancel: { nativeScrollbarsOverlaid: false },
|
||||
});
|
||||
|
||||
interface Metrics {
|
||||
@@ -587,7 +587,7 @@ const iterateMinMax = async (afterEach?: () => any) => {
|
||||
await iterate(containerMinMaxSelect, afterEach);
|
||||
};
|
||||
|
||||
const overflowTest = async (osOptions?: PartialOptions<Options>) => {
|
||||
const overflowTest = async (osOptions?: DeepPartial<Options>) => {
|
||||
const additiveOverflow = () => {
|
||||
if (isFractionalPixelRatio()) {
|
||||
return 1;
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
type CacheValues<T> = [
|
||||
value: T,
|
||||
changed: boolean,
|
||||
previous?: T
|
||||
];
|
||||
type UpdateCache<Value> = (force?: boolean) => CacheValues<Value>;
|
||||
interface WH<T> {
|
||||
w: T;
|
||||
h: T;
|
||||
}
|
||||
type PartialOptions<T> = {
|
||||
[P in keyof T]?: T[P] extends Record<string, unknown> ? PartialOptions<T[P]> : T[P];
|
||||
};
|
||||
type StyleObject<CustomCssProps> = {
|
||||
[Key in keyof CSSStyleDeclaration | (CustomCssProps extends string ? CustomCssProps : "")]?: string | number;
|
||||
};
|
||||
type OverflowStyle = "scroll" | "hidden" | "visible";
|
||||
interface TRBL {
|
||||
t: number;
|
||||
r: number;
|
||||
b: number;
|
||||
l: number;
|
||||
}
|
||||
interface XY<T> {
|
||||
x: T;
|
||||
y: T;
|
||||
}
|
||||
type EventListener<EventMap extends Record<string, any[]>, Name extends keyof EventMap> = (...args: EventMap[Name]) => void;
|
||||
type InitialEventListeners<EventMap extends Record<string, any[]>> = {
|
||||
[K in keyof EventMap]?: EventListener<EventMap> | EventListener<EventMap>[];
|
||||
};
|
||||
type OverflowBehavior = "hidden" | "scroll" | "visible" | "visible-hidden" | "visible-scroll";
|
||||
type ScrollbarVisibilityBehavior = "visible" | "hidden" | "auto";
|
||||
type ScrollbarAutoHideBehavior = "never" | "scroll" | "leave" | "move";
|
||||
interface Options {
|
||||
paddingAbsolute: boolean;
|
||||
updating: {
|
||||
elementEvents: Array<[
|
||||
elementSelector: string,
|
||||
eventNames: string
|
||||
]> | null;
|
||||
attributes: string[] | null;
|
||||
debounce: [
|
||||
timeout: number,
|
||||
maxWait: number
|
||||
] | number | null; // (if tuple: [timeout: 0, maxWait: 33], if number: [timeout: number, maxWait: false]) debounce for content Changes
|
||||
ignoreMutation: ((mutation: MutationRecord) => any) | null;
|
||||
};
|
||||
overflow: {
|
||||
x: OverflowBehavior;
|
||||
y: OverflowBehavior;
|
||||
};
|
||||
scrollbars: {
|
||||
theme: string | null;
|
||||
visibility: ScrollbarVisibilityBehavior;
|
||||
autoHide: ScrollbarAutoHideBehavior;
|
||||
autoHideDelay: number;
|
||||
dragScroll: boolean;
|
||||
clickScroll: boolean;
|
||||
touch: boolean;
|
||||
};
|
||||
nativeScrollbarsOverlaid: {
|
||||
show: boolean;
|
||||
initialize: boolean;
|
||||
};
|
||||
}
|
||||
type PluginInstance = Record<string, unknown> | ((staticObj: OverlayScrollbarsStatic, instanceObj: OverlayScrollbars) => void);
|
||||
type Plugin<T extends PluginInstance> = {
|
||||
[pluginName: string]: T;
|
||||
};
|
||||
type OptionsValidationPluginInstance = {
|
||||
_: (options: PartialOptions<Options>, doWriteErrors?: boolean) => PartialOptions<Options>;
|
||||
};
|
||||
declare const optionsValidationPlugin: Plugin<OptionsValidationPluginInstance>;
|
||||
type SizeObserverPluginInstance = {
|
||||
_: (listenerElement: HTMLElement, onSizeChangedCallback: (appear: boolean) => any, observeAppearChange: boolean) => [
|
||||
appearCallback: () => any,
|
||||
offFns: (() => any)[]
|
||||
];
|
||||
};
|
||||
declare const sizeObserverPlugin: Plugin<SizeObserverPluginInstance>;
|
||||
type StaticInitialization = HTMLElement | null | undefined;
|
||||
type DynamicInitialization = HTMLElement | boolean | null | undefined;
|
||||
type InitializationTargetElement = HTMLElement | HTMLTextAreaElement;
|
||||
type InitializationTargetObject = StructureInitialization & ScrollbarsInitialization;
|
||||
type InitializationTarget = InitializationTargetElement | InitializationTargetObject;
|
||||
type InitializationStrategy = StructureInitializationStrategy & ScrollbarsInitializationStrategy;
|
||||
/**
|
||||
* Static elements MUST be present.
|
||||
* Null or undefined behave like if this element wasn't specified during initialization.
|
||||
*/
|
||||
type StaticInitializationElement<Args extends any[]> = ((...args: Args) => StaticInitialization) | StaticInitialization;
|
||||
/**
|
||||
* 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.
|
||||
* Null or undefined behave like if this element wasn't specified during initialization.
|
||||
*/
|
||||
type DynamicInitializationElement<Args extends any[]> = ((...args: Args) => DynamicInitialization) | DynamicInitialization;
|
||||
type InitializtationElementStrategy<InitElm> = Exclude<InitElm, HTMLElement>;
|
||||
type ScrollbarsDynamicInitializationElement = DynamicInitializationElement<[
|
||||
target: InitializationTargetElement,
|
||||
host: HTMLElement,
|
||||
viewport: HTMLElement
|
||||
]>;
|
||||
/**
|
||||
* Object for special initialization.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Null or Undefined means that the environment initialization strategy is used.
|
||||
*/
|
||||
interface ScrollbarsInitialization {
|
||||
scrollbarsSlot?: ScrollbarsDynamicInitializationElement;
|
||||
}
|
||||
type ScrollbarsInitializationStrategy = {
|
||||
[K in keyof ScrollbarsInitialization]: InitializtationElementStrategy<ScrollbarsInitialization[K]>;
|
||||
};
|
||||
interface StructureSetupState {
|
||||
_padding: TRBL;
|
||||
_paddingAbsolute: boolean;
|
||||
_viewportPaddingStyle: StyleObject;
|
||||
_overflowEdge: XY<number>;
|
||||
_overflowAmount: XY<number>;
|
||||
_overflowStyle: XY<OverflowStyle>;
|
||||
_hasOverflow: XY<boolean>;
|
||||
_heightIntrinsic: boolean;
|
||||
_directionIsRTL: boolean;
|
||||
}
|
||||
type StructureStaticInitializationElement = StaticInitializationElement<[
|
||||
target: InitializationTargetElement
|
||||
]>;
|
||||
type StructureDynamicInitializationElement = DynamicInitializationElement<[
|
||||
target: InitializationTargetElement
|
||||
]>;
|
||||
/**
|
||||
* Object for special initialization.
|
||||
*
|
||||
* Target is always required, if element is not provided or undefined it will be generated.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Null or Undefined means that the environment initialization strategy is used.
|
||||
*/
|
||||
interface StructureInitialization {
|
||||
target: InitializationTargetElement;
|
||||
host?: StructureStaticInitializationElement; // only relevant for textarea
|
||||
viewport?: StructureStaticInitializationElement;
|
||||
padding?: StructureDynamicInitializationElement;
|
||||
content?: StructureDynamicInitializationElement;
|
||||
}
|
||||
type StructureInitializationStrategy = {
|
||||
[K in keyof Omit<StructureInitialization, "target">]: InitializtationElementStrategy<StructureInitialization[K]>;
|
||||
};
|
||||
interface ViewportOverflowState {
|
||||
_scrollbarsHideOffset: XY<number>;
|
||||
_scrollbarsHideOffsetArrange: XY<boolean>;
|
||||
_overflowScroll: XY<boolean>;
|
||||
_overflowStyle: XY<OverflowStyle>;
|
||||
}
|
||||
type GetViewportOverflowState = (showNativeOverlaidScrollbars: boolean, viewportStyleObj?: StyleObject) => ViewportOverflowState;
|
||||
type HideNativeScrollbars = (viewportOverflowState: ViewportOverflowState, directionIsRTL: boolean, viewportArrange: boolean, viewportStyleObj: StyleObject) => void;
|
||||
type EnvironmentEventMap = {
|
||||
_: [
|
||||
];
|
||||
};
|
||||
interface InternalEnvironment {
|
||||
readonly _nativeScrollbarsSize: XY;
|
||||
readonly _nativeScrollbarsOverlaid: XY<boolean>;
|
||||
readonly _nativeScrollbarsHiding: boolean;
|
||||
readonly _rtlScrollBehavior: {
|
||||
n: boolean;
|
||||
i: boolean;
|
||||
};
|
||||
readonly _flexboxGlue: boolean;
|
||||
readonly _cssCustomProperties: boolean;
|
||||
readonly _defaultInitializationStrategy: InitializationStrategy;
|
||||
readonly _defaultDefaultOptions: Options;
|
||||
_addListener(listener: EventListener<EnvironmentEventMap, "_">): () => void;
|
||||
_getInitializationStrategy(): InitializationStrategy;
|
||||
_setInitializationStrategy(newInitializationStrategy: Partial<InitializationStrategy>): void;
|
||||
_getDefaultOptions(): Options;
|
||||
_setDefaultOptions(newDefaultOptions: PartialOptions<Options>): void;
|
||||
}
|
||||
type ArrangeViewport = (viewportOverflowState: ViewportOverflowState, viewportScrollSize: WH<number>, sizeFraction: WH<number>, directionIsRTL: boolean) => boolean;
|
||||
type UndoViewportArrangeResult = [
|
||||
redoViewportArrange: () => void,
|
||||
overflowState?: ViewportOverflowState
|
||||
];
|
||||
type UndoArrangeViewport = (showNativeOverlaidScrollbars: boolean, directionIsRTL: boolean, viewportOverflowState?: ViewportOverflowState) => UndoViewportArrangeResult;
|
||||
type ScrollbarsHidingPluginInstance = {
|
||||
_createUniqueViewportArrangeElement(env: InternalEnvironment): HTMLStyleElement | false;
|
||||
_overflowUpdateSegment(doViewportArrange: boolean, flexboxGlue: boolean, viewport: HTMLElement, viewportArrange: HTMLStyleElement | false | null | undefined, getState: () => StructureSetupState, getViewportOverflowState: GetViewportOverflowState, hideNativeScrollbars: HideNativeScrollbars): [
|
||||
ArrangeViewport,
|
||||
UndoArrangeViewport
|
||||
];
|
||||
_envWindowZoom(): (envInstance: InternalEnvironment, updateNativeScrollbarSizeCache: UpdateCache<XY<number>>, triggerEvent: () => void) => void;
|
||||
};
|
||||
declare const scrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance>;
|
||||
type GeneralInitialEventListeners = InitialEventListeners;
|
||||
type GeneralEventListener = EventListener;
|
||||
interface OverlayScrollbarsStatic {
|
||||
(target: InitializationTarget | InitializationTargetObject, options?: PartialOptions<Options>, eventListeners?: GeneralInitialEventListeners<EventListenerMap>): OverlayScrollbars;
|
||||
plugin(plugin: Plugin | Plugin[]): void;
|
||||
env(): Environment;
|
||||
}
|
||||
interface Environment {
|
||||
scrollbarsSize: XY<number>;
|
||||
scrollbarsOverlaid: XY<boolean>;
|
||||
scrollbarsHiding: boolean;
|
||||
rtlScrollBehavior: {
|
||||
n: boolean;
|
||||
i: boolean;
|
||||
};
|
||||
flexboxGlue: boolean;
|
||||
cssCustomProperties: boolean;
|
||||
defaultInitializationStrategy: InitializationStrategy;
|
||||
defaultDefaultOptions: Options;
|
||||
getInitializationStrategy(): InitializationStrategy;
|
||||
setInitializationStrategy(newInitializationStrategy: Partial<InitializationStrategy>): void;
|
||||
getDefaultOptions(): Options;
|
||||
setDefaultOptions(newDefaultOptions: PartialOptions<Options>): void;
|
||||
}
|
||||
interface State {
|
||||
padding: TRBL;
|
||||
paddingAbsolute: boolean;
|
||||
overflowEdge: XY<number>;
|
||||
overflowAmount: XY<number>;
|
||||
overflowStyle: XY<OverflowStyle>;
|
||||
hasOverflow: XY<boolean>;
|
||||
destroyed: boolean;
|
||||
}
|
||||
interface Elements {
|
||||
target: HTMLElement;
|
||||
host: HTMLElement;
|
||||
padding: HTMLElement;
|
||||
viewport: HTMLElement;
|
||||
content: HTMLElement;
|
||||
}
|
||||
interface OnUpdatedEventListenerArgs {
|
||||
updateHints: {
|
||||
sizeChanged: boolean;
|
||||
directionChanged: boolean;
|
||||
heightIntrinsicChanged: boolean;
|
||||
overflowEdgeChanged: boolean;
|
||||
overflowAmountChanged: boolean;
|
||||
overflowStyleChanged: boolean;
|
||||
hostMutation: boolean;
|
||||
contentMutation: boolean;
|
||||
};
|
||||
changedOptions: PartialOptions<Options>;
|
||||
force: boolean;
|
||||
}
|
||||
type EventListenerMap = {
|
||||
/**
|
||||
* Triggered after all elements are initialized and appended.
|
||||
*/
|
||||
initialized: [
|
||||
instance: OverlayScrollbars
|
||||
];
|
||||
/**
|
||||
* Triggered after an update.
|
||||
*/
|
||||
updated: [
|
||||
instance: OverlayScrollbars,
|
||||
onUpdatedArgs: OnUpdatedEventListenerArgs
|
||||
];
|
||||
/**
|
||||
* Triggered after all elements, observers and events are destroyed.
|
||||
*/
|
||||
destroyed: [
|
||||
instance: OverlayScrollbars,
|
||||
withdrawn: boolean
|
||||
];
|
||||
};
|
||||
type EventListener$0<Name extends keyof EventListenerMap> = GeneralEventListener<EventListenerMap, Name>;
|
||||
interface OverlayScrollbars {
|
||||
options(): Options;
|
||||
options(newOptions?: PartialOptions<Options>): Options;
|
||||
update(force?: boolean): OverlayScrollbars;
|
||||
destroy(): void;
|
||||
state(): State;
|
||||
elements(): Elements;
|
||||
on<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>): () => void;
|
||||
on<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>[]): () => void;
|
||||
off<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>): void;
|
||||
off<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>[]): void;
|
||||
}
|
||||
/**
|
||||
* Notes:
|
||||
* Height intrinsic detection use "content: true" init strategy - or open ticket for custom height intrinsic observer
|
||||
*/
|
||||
declare const OverlayScrollbars: OverlayScrollbarsStatic;
|
||||
export { OverlayScrollbars, optionsValidationPlugin, scrollbarsHidingPlugin, sizeObserverPlugin };
|
||||
Reference in New Issue
Block a user