improve public api

This commit is contained in:
Rene Haas
2022-08-01 10:28:38 +02:00
parent 1eb3d305b1
commit 7b7053bfd2
2 changed files with 205 additions and 200 deletions
@@ -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];