mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-24 05:04:06 +03:00
improve public api
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
XY,
|
||||
TRBL,
|
||||
createEventListenerHub,
|
||||
isPlainObject,
|
||||
} from 'support';
|
||||
import { createStructureSetup, createScrollbarsSetup } from 'setups';
|
||||
import { getOptionsDiff, Options, ReadonlyOptions } from 'options';
|
||||
@@ -31,14 +32,19 @@ import {
|
||||
ScrollbarStructure,
|
||||
} from 'setups/scrollbarsSetup/scrollbarsSetup.elements';
|
||||
|
||||
// Notes:
|
||||
// Height intrinsic detection use "content: true" init strategy - or open ticket for custom height intrinsic observer
|
||||
|
||||
export interface OverlayScrollbarsStatic {
|
||||
(target: InitializationTarget): OverlayScrollbars | undefined;
|
||||
(
|
||||
target: InitializationTarget,
|
||||
options?: DeepPartial<Options>,
|
||||
options: DeepPartial<Options>,
|
||||
eventListeners?: GeneralInitialEventListeners<EventListenerMap>
|
||||
): OverlayScrollbars;
|
||||
|
||||
plugin(plugin: Plugin | Plugin[]): void;
|
||||
valid(osInstance: any): boolean;
|
||||
env(): Environment;
|
||||
}
|
||||
|
||||
@@ -147,222 +153,221 @@ export interface OverlayScrollbars {
|
||||
off<Name extends keyof EventListenerMap>(name: Name, listener: EventListener<Name>[]): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
* Height intrinsic detection use "content: true" init strategy - or open ticket for custom height intrinsic observer
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
||||
export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
target,
|
||||
options?,
|
||||
eventListeners?
|
||||
): OverlayScrollbars => {
|
||||
let destroyed = false;
|
||||
target: InitializationTarget,
|
||||
options?: DeepPartial<Options>,
|
||||
eventListeners?: GeneralInitialEventListeners<EventListenerMap>
|
||||
) => {
|
||||
const { _getDefaultOptions, _addListener: addEnvListener } = getEnvironment();
|
||||
const plugins = getPlugins();
|
||||
const targetIsElement = isHTMLElement(target);
|
||||
const instanceTarget = targetIsElement ? target : target.target;
|
||||
const potentialInstance = getInstance(instanceTarget);
|
||||
if (potentialInstance) {
|
||||
return potentialInstance;
|
||||
}
|
||||
if (options && !potentialInstance) {
|
||||
let destroyed = false;
|
||||
const optionsValidationPlugin = plugins[
|
||||
optionsValidationPluginName
|
||||
] as OptionsValidationPluginInstance;
|
||||
const validateOptions = (newOptions?: DeepPartial<Options>) => {
|
||||
const opts = newOptions || {};
|
||||
const validate = optionsValidationPlugin && optionsValidationPlugin._;
|
||||
return validate ? validate(opts, true) : opts;
|
||||
};
|
||||
const currentOptions: ReadonlyOptions = assignDeep(
|
||||
{},
|
||||
_getDefaultOptions(),
|
||||
validateOptions(options)
|
||||
);
|
||||
const [addEvent, removeEvent, triggerEvent] = createEventListenerHub(eventListeners);
|
||||
const [updateStructure, structureState, destroyStructure] = createStructureSetup(
|
||||
target,
|
||||
currentOptions
|
||||
);
|
||||
const [updateScrollbars, scrollbarsState, destroyScrollbars] = createScrollbarsSetup(
|
||||
target,
|
||||
currentOptions,
|
||||
structureState
|
||||
);
|
||||
const update = (changedOptions: DeepPartial<Options>, force?: boolean) => {
|
||||
updateStructure(changedOptions, !!force);
|
||||
};
|
||||
const removeEnvListener = addEnvListener(update.bind(0, {}, true));
|
||||
const destroy = (canceled?: boolean) => {
|
||||
removeInstance(instanceTarget);
|
||||
removeEnvListener();
|
||||
|
||||
const optionsValidationPlugin = plugins[
|
||||
optionsValidationPluginName
|
||||
] as OptionsValidationPluginInstance;
|
||||
const validateOptions = (newOptions?: DeepPartial<Options>) => {
|
||||
const opts = newOptions || {};
|
||||
const validate = optionsValidationPlugin && optionsValidationPlugin._;
|
||||
return validate ? validate(opts, true) : opts;
|
||||
};
|
||||
const currentOptions: ReadonlyOptions = assignDeep(
|
||||
{},
|
||||
_getDefaultOptions(),
|
||||
validateOptions(options)
|
||||
);
|
||||
const [addEvent, removeEvent, triggerEvent] = createEventListenerHub(eventListeners);
|
||||
const [updateStructure, structureState, destroyStructure] = createStructureSetup(
|
||||
target,
|
||||
currentOptions
|
||||
);
|
||||
const [updateScrollbars, scrollbarsState, destroyScrollbars] = createScrollbarsSetup(
|
||||
target,
|
||||
currentOptions,
|
||||
structureState
|
||||
);
|
||||
const update = (changedOptions: DeepPartial<Options>, force?: boolean) => {
|
||||
updateStructure(changedOptions, !!force);
|
||||
};
|
||||
const removeEnvListener = addEnvListener(update.bind(0, {}, true));
|
||||
const destroy = (canceled?: boolean) => {
|
||||
removeInstance(instanceTarget);
|
||||
removeEnvListener();
|
||||
destroyScrollbars();
|
||||
destroyStructure();
|
||||
|
||||
destroyScrollbars();
|
||||
destroyStructure();
|
||||
destroyed = true;
|
||||
|
||||
destroyed = true;
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
triggerEvent('destroyed', [instance, !!canceled]);
|
||||
removeEvent();
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
triggerEvent('destroyed', [instance, !!canceled]);
|
||||
removeEvent();
|
||||
};
|
||||
const instance: OverlayScrollbars = {
|
||||
options(newOptions?: DeepPartial<Options>) {
|
||||
if (newOptions) {
|
||||
const changedOptions = getOptionsDiff(currentOptions, validateOptions(newOptions));
|
||||
|
||||
const instance: OverlayScrollbars = {
|
||||
options(newOptions?: DeepPartial<Options>) {
|
||||
if (newOptions) {
|
||||
const changedOptions = getOptionsDiff(currentOptions, validateOptions(newOptions));
|
||||
|
||||
if (!isEmptyObject(changedOptions)) {
|
||||
assignDeep(currentOptions, changedOptions);
|
||||
update(changedOptions);
|
||||
if (!isEmptyObject(changedOptions)) {
|
||||
assignDeep(currentOptions, changedOptions);
|
||||
update(changedOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
return assignDeep({}, currentOptions);
|
||||
},
|
||||
on: addEvent,
|
||||
off: (name, listener) => {
|
||||
name && listener && removeEvent(name, listener as any);
|
||||
},
|
||||
state() {
|
||||
const {
|
||||
_overflowEdge,
|
||||
_overflowAmount,
|
||||
_overflowStyle,
|
||||
_hasOverflow,
|
||||
_padding,
|
||||
_paddingAbsolute,
|
||||
_directionIsRTL,
|
||||
} = structureState();
|
||||
return assignDeep(
|
||||
{},
|
||||
{
|
||||
overflowEdge: _overflowEdge,
|
||||
overflowAmount: _overflowAmount,
|
||||
overflowStyle: _overflowStyle,
|
||||
hasOverflow: _hasOverflow,
|
||||
padding: _padding,
|
||||
paddingAbsolute: _paddingAbsolute,
|
||||
directionRTL: _directionIsRTL,
|
||||
destroyed,
|
||||
}
|
||||
);
|
||||
},
|
||||
elements() {
|
||||
const {
|
||||
_target,
|
||||
_host,
|
||||
_padding,
|
||||
_viewport,
|
||||
_content,
|
||||
_scrollOffsetElement,
|
||||
_scrollEventElement,
|
||||
} = structureState._elements;
|
||||
const { _horizontal, _vertical } = scrollbarsState._elements;
|
||||
const translateScrollbarStructure = (
|
||||
scrollbarStructure: ScrollbarStructure
|
||||
): ScrollbarElements => {
|
||||
const { _handle, _track, _scrollbar } = scrollbarStructure;
|
||||
return {
|
||||
scrollbar: _scrollbar,
|
||||
track: _track,
|
||||
handle: _handle,
|
||||
};
|
||||
};
|
||||
const translateScrollbarsSetupElement = (
|
||||
scrollbarsSetupElement: ScrollbarsSetupElement
|
||||
): CloneableScrollbarElements => {
|
||||
const { _scrollbarStructures, _clone } = scrollbarsSetupElement;
|
||||
const translatedStructure = translateScrollbarStructure(_scrollbarStructures[0]);
|
||||
|
||||
return assignDeep({}, translatedStructure, {
|
||||
clone: () => {
|
||||
const result = translateScrollbarStructure(_clone());
|
||||
updateScrollbars({}, true, {});
|
||||
return result;
|
||||
},
|
||||
});
|
||||
};
|
||||
return assignDeep(
|
||||
{},
|
||||
{
|
||||
target: _target,
|
||||
host: _host,
|
||||
padding: _padding || _viewport,
|
||||
viewport: _viewport,
|
||||
content: _content || _viewport,
|
||||
scrollOffsetElement: _scrollOffsetElement,
|
||||
scrollEventElement: _scrollEventElement,
|
||||
scrollbarHorizontal: translateScrollbarsSetupElement(_horizontal),
|
||||
scrollbarVertical: translateScrollbarsSetupElement(_vertical),
|
||||
}
|
||||
);
|
||||
},
|
||||
update(force?: boolean) {
|
||||
update({}, force);
|
||||
return instance;
|
||||
},
|
||||
destroy: destroy.bind(0),
|
||||
};
|
||||
|
||||
structureState._addOnUpdatedListener((updateHints, changedOptions, force: boolean) => {
|
||||
updateScrollbars(changedOptions, force, updateHints);
|
||||
});
|
||||
|
||||
each(keys(plugins), (pluginName) => {
|
||||
const pluginInstance = plugins[pluginName];
|
||||
if (isFunction(pluginInstance)) {
|
||||
pluginInstance(OverlayScrollbars, instance);
|
||||
}
|
||||
});
|
||||
|
||||
if (cancelInitialization(!targetIsElement && target.cancel, structureState._elements)) {
|
||||
destroy(true);
|
||||
return instance;
|
||||
}
|
||||
|
||||
structureState._appendElements();
|
||||
scrollbarsState._appendElements();
|
||||
|
||||
addInstance(instanceTarget, instance);
|
||||
triggerEvent('initialized', [instance]);
|
||||
|
||||
structureState._addOnUpdatedListener((updateHints, changedOptions, force) => {
|
||||
const {
|
||||
_sizeChanged,
|
||||
_directionChanged,
|
||||
_heightIntrinsicChanged,
|
||||
_overflowEdgeChanged,
|
||||
_overflowAmountChanged,
|
||||
_overflowStyleChanged,
|
||||
_contentMutation,
|
||||
_hostMutation,
|
||||
} = updateHints;
|
||||
|
||||
triggerEvent('updated', [
|
||||
instance,
|
||||
{
|
||||
updateHints: {
|
||||
sizeChanged: _sizeChanged,
|
||||
directionChanged: _directionChanged,
|
||||
heightIntrinsicChanged: _heightIntrinsicChanged,
|
||||
overflowEdgeChanged: _overflowEdgeChanged,
|
||||
overflowAmountChanged: _overflowAmountChanged,
|
||||
overflowStyleChanged: _overflowStyleChanged,
|
||||
contentMutation: _contentMutation,
|
||||
hostMutation: _hostMutation,
|
||||
},
|
||||
changedOptions,
|
||||
force,
|
||||
return assignDeep({}, currentOptions);
|
||||
},
|
||||
]);
|
||||
});
|
||||
on: addEvent,
|
||||
off: (name, listener) => {
|
||||
name && listener && removeEvent(name, listener as any);
|
||||
},
|
||||
state() {
|
||||
const {
|
||||
_overflowEdge,
|
||||
_overflowAmount,
|
||||
_overflowStyle,
|
||||
_hasOverflow,
|
||||
_padding,
|
||||
_paddingAbsolute,
|
||||
_directionIsRTL,
|
||||
} = structureState();
|
||||
return assignDeep(
|
||||
{},
|
||||
{
|
||||
overflowEdge: _overflowEdge,
|
||||
overflowAmount: _overflowAmount,
|
||||
overflowStyle: _overflowStyle,
|
||||
hasOverflow: _hasOverflow,
|
||||
padding: _padding,
|
||||
paddingAbsolute: _paddingAbsolute,
|
||||
directionRTL: _directionIsRTL,
|
||||
destroyed,
|
||||
}
|
||||
);
|
||||
},
|
||||
elements() {
|
||||
const {
|
||||
_target,
|
||||
_host,
|
||||
_padding,
|
||||
_viewport,
|
||||
_content,
|
||||
_scrollOffsetElement,
|
||||
_scrollEventElement,
|
||||
} = structureState._elements;
|
||||
const { _horizontal, _vertical } = scrollbarsState._elements;
|
||||
const translateScrollbarStructure = (
|
||||
scrollbarStructure: ScrollbarStructure
|
||||
): ScrollbarElements => {
|
||||
const { _handle, _track, _scrollbar } = scrollbarStructure;
|
||||
return {
|
||||
scrollbar: _scrollbar,
|
||||
track: _track,
|
||||
handle: _handle,
|
||||
};
|
||||
};
|
||||
const translateScrollbarsSetupElement = (
|
||||
scrollbarsSetupElement: ScrollbarsSetupElement
|
||||
): CloneableScrollbarElements => {
|
||||
const { _scrollbarStructures, _clone } = scrollbarsSetupElement;
|
||||
const translatedStructure = translateScrollbarStructure(_scrollbarStructures[0]);
|
||||
|
||||
return instance.update(true);
|
||||
return assignDeep({}, translatedStructure, {
|
||||
clone: () => {
|
||||
const result = translateScrollbarStructure(_clone());
|
||||
updateScrollbars({}, true, {});
|
||||
return result;
|
||||
},
|
||||
});
|
||||
};
|
||||
return assignDeep(
|
||||
{},
|
||||
{
|
||||
target: _target,
|
||||
host: _host,
|
||||
padding: _padding || _viewport,
|
||||
viewport: _viewport,
|
||||
content: _content || _viewport,
|
||||
scrollOffsetElement: _scrollOffsetElement,
|
||||
scrollEventElement: _scrollEventElement,
|
||||
scrollbarHorizontal: translateScrollbarsSetupElement(_horizontal),
|
||||
scrollbarVertical: translateScrollbarsSetupElement(_vertical),
|
||||
}
|
||||
);
|
||||
},
|
||||
update(force?: boolean) {
|
||||
update({}, force);
|
||||
return instance;
|
||||
},
|
||||
destroy: destroy.bind(0),
|
||||
};
|
||||
|
||||
structureState._addOnUpdatedListener((updateHints, changedOptions, force: boolean) => {
|
||||
updateScrollbars(changedOptions, force, updateHints);
|
||||
});
|
||||
|
||||
each(keys(plugins), (pluginName) => {
|
||||
const pluginInstance = plugins[pluginName];
|
||||
if (isFunction(pluginInstance)) {
|
||||
pluginInstance(OverlayScrollbars, instance);
|
||||
}
|
||||
});
|
||||
|
||||
if (cancelInitialization(!targetIsElement && target.cancel, structureState._elements)) {
|
||||
destroy(true);
|
||||
return instance;
|
||||
}
|
||||
|
||||
structureState._appendElements();
|
||||
scrollbarsState._appendElements();
|
||||
|
||||
addInstance(instanceTarget, instance);
|
||||
triggerEvent('initialized', [instance]);
|
||||
|
||||
structureState._addOnUpdatedListener((updateHints, changedOptions, force) => {
|
||||
const {
|
||||
_sizeChanged,
|
||||
_directionChanged,
|
||||
_heightIntrinsicChanged,
|
||||
_overflowEdgeChanged,
|
||||
_overflowAmountChanged,
|
||||
_overflowStyleChanged,
|
||||
_contentMutation,
|
||||
_hostMutation,
|
||||
} = updateHints;
|
||||
|
||||
triggerEvent('updated', [
|
||||
instance,
|
||||
{
|
||||
updateHints: {
|
||||
sizeChanged: _sizeChanged,
|
||||
directionChanged: _directionChanged,
|
||||
heightIntrinsicChanged: _heightIntrinsicChanged,
|
||||
overflowEdgeChanged: _overflowEdgeChanged,
|
||||
overflowAmountChanged: _overflowAmountChanged,
|
||||
overflowStyleChanged: _overflowStyleChanged,
|
||||
contentMutation: _contentMutation,
|
||||
hostMutation: _hostMutation,
|
||||
},
|
||||
changedOptions,
|
||||
force,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
return instance.update(true);
|
||||
}
|
||||
return potentialInstance!;
|
||||
};
|
||||
|
||||
OverlayScrollbars.plugin = addPlugin;
|
||||
OverlayScrollbars.valid = (osInstance: any) => {
|
||||
const hasElmsFn = osInstance && (osInstance as OverlayScrollbars).elements;
|
||||
const elements = isFunction(hasElmsFn) && hasElmsFn();
|
||||
return isPlainObject(elements) && !!getInstance(elements.target);
|
||||
};
|
||||
OverlayScrollbars.env = () => {
|
||||
const {
|
||||
_nativeScrollbarsSize,
|
||||
|
||||
@@ -12,7 +12,7 @@ const pluginRegistry: Record<string, PluginInstance> = {};
|
||||
|
||||
export const getPlugins = () => pluginRegistry;
|
||||
|
||||
export const addPlugin = (addedPlugin: Plugin | Plugin[]) => {
|
||||
export const addPlugin = (addedPlugin: Plugin | Plugin[]): void => {
|
||||
each((isArray(addedPlugin) ? addedPlugin : [addedPlugin]) as Plugin[], (plugin) => {
|
||||
const pluginName = keys(plugin)[0];
|
||||
pluginRegistry[pluginName] = plugin[pluginName];
|
||||
|
||||
Reference in New Issue
Block a user