diff --git a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js
index 99b95f8..e427dfe 100644
--- a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js
+++ b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js
@@ -864,7 +864,7 @@ const createEnvironment = () => {
const envDOM = createDOM(`
`);
const envElm = envDOM[0];
const envChildElm = envElm.firstChild;
- const onChangedListener = new Set();
+ const [addEvent,, triggerEvent] = createEventListenerHub();
const [updateNativeScrollbarSizeCache, getNativeScrollbarSizeCache] = createCache({
_initialValue: getNativeScrollbarSize(body, envElm, envChildElm),
_equal: equalXY
@@ -884,12 +884,7 @@ const createEnvironment = () => {
_cssCustomProperties: style(envElm, 'zIndex') === '-1',
_rtlScrollBehavior: getRtlScrollBehavior(envElm, envChildElm),
_flexboxGlue: getFlexboxGlue(envElm, envChildElm),
-
- _addListener(listener) {
- onChangedListener.add(listener);
- return () => onChangedListener.delete(listener);
- },
-
+ _addListener: listener => addEvent('_', listener),
_getInitializationStrategy: assignDeep.bind(0, {}, initializationStrategy),
_setInitializationStrategy(newInitializationStrategy) {
@@ -912,40 +907,38 @@ const createEnvironment = () => {
let size = windowSize();
let dpr = getWindowDPR();
window.addEventListener('resize', () => {
- if (onChangedListener.size) {
- const sizeNew = windowSize();
- const deltaSize = {
- w: sizeNew.w - size.w,
- h: sizeNew.h - size.h
- };
- if (deltaSize.w === 0 && deltaSize.h === 0) return;
- const deltaAbsSize = {
- w: abs(deltaSize.w),
- h: abs(deltaSize.h)
- };
- const deltaAbsRatio = {
- w: abs(round(sizeNew.w / (size.w / 100.0))),
- h: abs(round(sizeNew.h / (size.h / 100.0)))
- };
- const dprNew = getWindowDPR();
- const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
- const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
- const dprChanged = dprNew !== dpr && dpr > 0;
- const isZoom = deltaIsBigger && difference && dprChanged;
+ const sizeNew = windowSize();
+ const deltaSize = {
+ w: sizeNew.w - size.w,
+ h: sizeNew.h - size.h
+ };
+ if (deltaSize.w === 0 && deltaSize.h === 0) return;
+ const deltaAbsSize = {
+ w: abs(deltaSize.w),
+ h: abs(deltaSize.h)
+ };
+ const deltaAbsRatio = {
+ w: abs(round(sizeNew.w / (size.w / 100.0))),
+ h: abs(round(sizeNew.h / (size.h / 100.0)))
+ };
+ const dprNew = getWindowDPR();
+ const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
+ const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
+ const dprChanged = dprNew !== dpr && dpr > 0;
+ const isZoom = deltaIsBigger && difference && dprChanged;
- if (isZoom) {
- const [scrollbarSize, scrollbarSizeChanged] = updateNativeScrollbarSizeCache(getNativeScrollbarSize(body, envElm, envChildElm));
- assignDeep(environmentInstance._nativeScrollbarSize, scrollbarSize);
- removeElements(envElm);
+ if (isZoom) {
+ const [scrollbarSize, scrollbarSizeChanged] = updateNativeScrollbarSizeCache(getNativeScrollbarSize(body, envElm, envChildElm));
+ assignDeep(environmentInstance._nativeScrollbarSize, scrollbarSize);
+ removeElements(envElm);
- if (scrollbarSizeChanged) {
- runEach(onChangedListener);
- }
+ if (scrollbarSizeChanged) {
+ triggerEvent('_');
}
-
- size = sizeNew;
- dpr = dprNew;
}
+
+ size = sizeNew;
+ dpr = dprNew;
});
}
@@ -1115,14 +1108,18 @@ const createTrinsicUpdate = (structureSetupElements, state) => {
} = structureSetupElements;
const [getState] = state;
return updateHints => {
+ const {
+ _flexboxGlue
+ } = getEnvironment();
const {
_heightIntrinsic
} = getState();
const {
_heightIntrinsicChanged
} = updateHints;
+ const heightIntrinsicChanged = (_content || !_flexboxGlue) && _heightIntrinsicChanged;
- if (_heightIntrinsicChanged) {
+ if (heightIntrinsicChanged) {
style(_content, {
height: _heightIntrinsic ? '' : '100%',
display: _heightIntrinsic ? '' : 'inline'
@@ -1130,8 +1127,8 @@ const createTrinsicUpdate = (structureSetupElements, state) => {
}
return {
- _sizeChanged: _heightIntrinsicChanged,
- _contentMutation: _heightIntrinsicChanged
+ _sizeChanged: heightIntrinsicChanged,
+ _contentMutation: heightIntrinsicChanged
};
};
};
@@ -1208,6 +1205,7 @@ const {
max
} = Math;
const strVisible = 'visible';
+const strHidden = 'hidden';
const overlaidScrollbarsHideOffset = 42;
const whCacheOptions = {
_equal: equalWH,
@@ -1219,8 +1217,8 @@ const whCacheOptions = {
const xyCacheOptions = {
_equal: equalXY,
_initialValue: {
- x: false,
- y: false
+ x: strHidden,
+ y: strHidden
}
};
@@ -1258,7 +1256,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
const [updateSizeFraction, getCurrentSizeFraction] = createCache(whCacheOptions, fractionalSize.bind(0, _host));
const [updateViewportScrollSizeCache, getCurrentViewportScrollSizeCache] = createCache(whCacheOptions, scrollSize.bind(0, _viewport));
const [updateOverflowAmountCache, getCurrentOverflowAmountCache] = createCache(whCacheOptions);
- const [updateOverflowScrollCache] = createCache(xyCacheOptions);
+ const [updateOverflowStyleCache] = createCache(xyCacheOptions);
const fixFlexboxGlue = (viewportOverflowState, heightIntrinsic) => {
style(_viewport, {
@@ -1286,39 +1284,45 @@ const createOverflowUpdate = (structureSetupElements, state) => {
};
const getViewportOverflowState = (showNativeOverlaidScrollbars, viewportStyleObj) => {
- const {
- x: overlaidX,
- y: overlaidY
- } = _nativeScrollbarIsOverlaid;
- const determineOverflow = !viewportStyleObj;
const arrangeHideOffset = !_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;
- const styleObj = determineOverflow ? style(_viewport, ['overflowX', 'overflowY']) : viewportStyleObj;
- const scroll = {
- x: styleObj.overflowX === 'scroll',
- y: styleObj.overflowY === 'scroll'
- };
- const nonScrollbarStylingHideOffset = {
- x: overlaidX ? arrangeHideOffset : _nativeScrollbarSize.x,
- y: overlaidY ? arrangeHideOffset : _nativeScrollbarSize.y
- };
- const scrollbarsHideOffset = {
- x: scroll.x && !_nativeScrollbarStyling ? nonScrollbarStylingHideOffset.x : 0,
- y: scroll.y && !_nativeScrollbarStyling ? nonScrollbarStylingHideOffset.y : 0
+
+ const getStatePerAxis = (styleKey, isOverlaid, nativeScrollbarSize) => {
+ const overflowStyle = style(_viewport, styleKey);
+ const objectPrefferedOverflowStyle = viewportStyleObj ? viewportStyleObj[styleKey] : overflowStyle;
+ const overflowScroll = objectPrefferedOverflowStyle === 'scroll';
+ const nonScrollbarStylingHideOffset = isOverlaid ? arrangeHideOffset : nativeScrollbarSize;
+ const scrollbarsHideOffset = overflowScroll && !_nativeScrollbarStyling ? nonScrollbarStylingHideOffset : 0;
+ const scrollbarsHideOffsetArrange = isOverlaid && !!arrangeHideOffset;
+ return [overflowStyle, overflowScroll, scrollbarsHideOffset, scrollbarsHideOffsetArrange];
};
+
+ const [xOverflowStyle, xOverflowScroll, xScrollbarsHideOffset, xScrollbarsHideOffsetArrange] = getStatePerAxis('overflowX', _nativeScrollbarIsOverlaid.x, _nativeScrollbarSize.x);
+ const [yOverflowStyle, yOverflowScroll, yScrollbarsHideOffset, yScrollbarsHideOffsetArrange] = getStatePerAxis('overflowY', _nativeScrollbarIsOverlaid.y, _nativeScrollbarSize.y);
return {
- _overflowScroll: scroll,
- _scrollbarsHideOffsetArrange: {
- x: overlaidX && !!arrangeHideOffset,
- y: overlaidY && !!arrangeHideOffset
+ _overflowStyle: {
+ x: xOverflowStyle,
+ y: yOverflowStyle
},
- _scrollbarsHideOffset: scrollbarsHideOffset
+ _overflowScroll: {
+ x: xOverflowScroll,
+ y: yOverflowScroll
+ },
+ _scrollbarsHideOffset: {
+ x: xScrollbarsHideOffset,
+ y: yScrollbarsHideOffset
+ },
+ _scrollbarsHideOffsetArrange: {
+ x: xScrollbarsHideOffsetArrange,
+ y: yScrollbarsHideOffsetArrange
+ }
};
};
const setViewportOverflowState = (showNativeOverlaidScrollbars, hasOverflow, overflowOption, viewportStyleObj) => {
const setAxisOverflowStyle = (behavior, hasOverflowAxis) => {
const overflowVisible = overflowIsVisible(behavior);
- return [hasOverflowAxis && !overflowVisible ? behavior : '', hasOverflowAxis && overflowVisible && behavior.replace(`${strVisible}-`, '') || ''];
+ const overflowVisibleBehavior = hasOverflowAxis && overflowVisible && behavior.replace(`${strVisible}-`, '') || '';
+ return [hasOverflowAxis && !overflowVisible ? behavior : '', overflowIsVisible(overflowVisibleBehavior) ? 'hidden' : overflowVisibleBehavior];
};
const [overflowX, visibleBehaviorX] = setAxisOverflowStyle(overflowOption.x, hasOverflow.x);
@@ -1486,7 +1490,6 @@ const createOverflowUpdate = (structureSetupElements, state) => {
let sizeFractionCache = getCurrentSizeFraction(force);
let viewportScrollSizeCache = getCurrentViewportScrollSizeCache(force);
let overflowAmuntCache = getCurrentOverflowAmountCache(force);
- let updateHintsReturn;
let preMeasureViewportOverflowState;
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
@@ -1498,11 +1501,11 @@ const createOverflowUpdate = (structureSetupElements, state) => {
fixFlexboxGlue(preMeasureViewportOverflowState, _heightIntrinsic);
}
- if (overflowVisible) {
- removeClass(_viewport, classNameOverflowVisible);
- }
-
if (_sizeChanged || _paddingStyleChanged || _contentMutation || _directionChanged || showNativeOverlaidScrollbarsChanged) {
+ if (overflowVisible) {
+ removeClass(_viewport, classNameOverflowVisible);
+ }
+
const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange(showNativeOverlaidScrollbars, _directionIsRTL, preMeasureViewportOverflowState);
const [_sizeFraction, _sizeFractionChanged] = sizeFractionCache = updateSizeFraction(force);
const [_viewportScrollSize, _viewportScrollSizeChanged] = viewportScrollSizeCache = updateViewportScrollSizeCache(force);
@@ -1545,7 +1548,6 @@ const createOverflowUpdate = (structureSetupElements, state) => {
};
const viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, hasOverflow, overflow, viewportStyle);
const viewportArranged = arrangeViewport(viewportOverflowState, viewportScrollSize, sizeFraction, _directionIsRTL);
- const [overflowScroll, overflowScrollChanged] = updateOverflowScrollCache(viewportOverflowState._overflowScroll);
hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);
if (adjustFlexboxGlue) {
@@ -1553,21 +1555,24 @@ const createOverflowUpdate = (structureSetupElements, state) => {
}
style(_viewport, viewportStyle);
- setState({
- _overflowScroll: overflowScroll,
- _overflowAmount: overflowAmount,
- _hasOverflow: hasOverflow
- });
- updateHintsReturn = {
- _overflowAmountChanged: overflowAmountChanged,
- _overflowScrollChanged: overflowScrollChanged
- };
}
attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');
conditionalClass(_padding, classNameOverflowVisible, removeClipping);
conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
- return updateHintsReturn;
+ const [overflowStyle, overflowStyleChanged] = updateOverflowStyleCache(getViewportOverflowState(showNativeOverlaidScrollbars)._overflowStyle);
+ setState({
+ _overflowStyle: overflowStyle,
+ _overflowAmount: {
+ x: overflowAmount.w,
+ y: overflowAmount.h
+ },
+ _hasOverflow: hasOverflow
+ });
+ return {
+ _overflowStyleChanged: overflowStyleChanged,
+ _overflowAmountChanged: overflowAmountChanged
+ };
};
};
@@ -1600,8 +1605,8 @@ const createStructureSetupUpdate = (structureSetupElements, state) => {
_paddingStyleChanged: false,
_directionChanged: false,
_heightIntrinsicChanged: false,
- _overflowScrollChanged: false,
_overflowAmountChanged: false,
+ _overflowStyleChanged: false,
_hostMutation: false,
_contentMutation: false
}, updateHints), {}, force);
@@ -2178,12 +2183,12 @@ const initialStructureSetupUpdateState = {
paddingLeft: 0
},
_overflowAmount: {
- w: 0,
- h: 0
+ x: 0,
+ y: 0
},
- _overflowScroll: {
- x: false,
- y: false
+ _overflowStyle: {
+ x: 'hidden',
+ y: 'hidden'
},
_hasOverflow: {
x: false,
@@ -2384,15 +2389,6 @@ const getInstance = target => targetInstanceMap.get(target);
const createOSEventListenerHub = initialEventListeners => createEventListenerHub(initialEventListeners);
-const createOverflowChangedArgs = (overflowAmount, hasOverflow, overflowScroll) => ({
- amount: {
- x: overflowAmount.w,
- y: overflowAmount.h
- },
- overflow: hasOverflow,
- scrollableOverflow: assignDeep({}, overflowScroll)
-});
-
const OverlayScrollbars = (target, options, eventListeners) => {
const {
_getDefaultOptions,
@@ -2430,35 +2426,25 @@ const OverlayScrollbars = (target, options, eventListeners) => {
updateScrollbars(changedOptions, force);
};
+ const removeEnvListener = addEnvListener(update.bind(0, {}, true));
+
structureState._addOnUpdatedListener((updateHints, changedOptions, force) => {
const {
_sizeChanged,
_directionChanged,
_heightIntrinsicChanged,
_overflowAmountChanged,
- _overflowScrollChanged,
+ _overflowStyleChanged,
_contentMutation,
_hostMutation
} = updateHints;
- const {
- _overflowAmount,
- _overflowScroll,
- _hasOverflow
- } = structureState();
-
- if (_overflowAmountChanged || _overflowScrollChanged) {
- triggerEvent('overflowChanged', assignDeep({}, createOverflowChangedArgs(_overflowAmount, _hasOverflow, _overflowScroll), {
- previous: createOverflowChangedArgs(_overflowAmount, _hasOverflow, _overflowScroll)
- }));
- }
-
triggerEvent('updated', {
updateHints: {
sizeChanged: _sizeChanged,
directionChanged: _directionChanged,
heightIntrinsicChanged: _heightIntrinsicChanged,
overflowAmountChanged: _overflowAmountChanged,
- overflowScrollChanged: _overflowScrollChanged,
+ overflowStyleChanged: _overflowStyleChanged,
contentMutation: _contentMutation,
hostMutation: _hostMutation
},
@@ -2467,7 +2453,6 @@ const OverlayScrollbars = (target, options, eventListeners) => {
});
});
- const removeEnvListener = addEnvListener(update.bind(0, {}, true));
const instance = {
options(newOptions) {
if (newOptions) {
@@ -2479,14 +2464,27 @@ const OverlayScrollbars = (target, options, eventListeners) => {
}
}
- return currentOptions;
+ return assignDeep({}, currentOptions);
},
on: addEvent,
off: removeEvent,
- state: () => ({
- _overflowAmount: structureState()._overflowAmount
- }),
+ state: () => {
+ const {
+ _overflowAmount,
+ _overflowStyle,
+ _hasOverflow,
+ _padding,
+ _paddingAbsolute
+ } = structureState();
+ return assignDeep({}, {
+ overflowAmount: _overflowAmount,
+ overflowStyle: _overflowStyle,
+ hasOverflow: _hasOverflow,
+ padding: _padding,
+ paddingAbsolute: _paddingAbsolute
+ });
+ },
update(force) {
update({}, force);
@@ -2513,7 +2511,38 @@ const OverlayScrollbars = (target, options, eventListeners) => {
triggerEvent('initialized');
return instance;
};
-OverlayScrollbars.extend = addPlugin;
+OverlayScrollbars.plugin = addPlugin;
+
+OverlayScrollbars.env = () => {
+ const {
+ _nativeScrollbarSize,
+ _nativeScrollbarIsOverlaid,
+ _nativeScrollbarStyling,
+ _rtlScrollBehavior,
+ _flexboxGlue,
+ _cssCustomProperties,
+ _defaultInitializationStrategy,
+ _defaultDefaultOptions,
+ _getInitializationStrategy,
+ _setInitializationStrategy,
+ _getDefaultOptions,
+ _setDefaultOptions
+ } = getEnvironment();
+ return assignDeep({}, {
+ scrollbarSize: _nativeScrollbarSize,
+ scrollbarIsOverlaid: _nativeScrollbarIsOverlaid,
+ scrollbarStyling: _nativeScrollbarStyling,
+ rtlScrollBehavior: _rtlScrollBehavior,
+ flexboxGlue: _flexboxGlue,
+ cssCustomProperties: _cssCustomProperties,
+ defaultInitializationStrategy: _defaultInitializationStrategy,
+ defaultDefaultOptions: _defaultDefaultOptions,
+ getInitializationStrategy: _getInitializationStrategy,
+ setInitializationStrategy: _setInitializationStrategy,
+ getDefaultOptions: _getDefaultOptions,
+ setDefaultOptions: _setDefaultOptions
+ });
+};
export { OverlayScrollbars as default };
//# sourceMappingURL=overlayscrollbars.esm.js.map
diff --git a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map
index f24bcf8..29852af 100644
--- a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map
+++ b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map
@@ -1 +1 @@
-{"version":3,"file":"overlayscrollbars.esm.js","sources":["../src/support/cache.ts","../src/support/utils/types.ts","../src/support/utils/array.ts","../src/support/utils/object.ts","../src/support/dom/attribute.ts","../src/support/dom/traversal.ts","../src/support/dom/manipulation.ts","../src/support/dom/create.ts","../src/support/compatibility/vendors.ts","../src/support/compatibility/apis.ts","../src/support/dom/class.ts","../src/support/utils/equal.ts","../src/support/utils/function.ts","../src/support/dom/style.ts","../src/support/dom/dimensions.ts","../src/support/dom/events.ts","../src/support/dom/offset.ts","../src/support/eventListeners.ts","../src/setups/setups.ts","../src/classnames.ts","../src/options.ts","../src/environment.ts","../src/setups/structureSetup/structureSetup.elements.ts","../src/setups/structureSetup/updateSegments/trinsicUpdateSegment.ts","../src/setups/structureSetup/updateSegments/paddingUpdateSegment.ts","../src/setups/structureSetup/updateSegments/overflowUpdateSegment.ts","../src/setups/structureSetup/structureSetup.update.ts","../src/observers/sizeObserver.ts","../src/observers/trinsicObserver.ts","../src/observers/domObserver.ts","../src/setups/structureSetup/structureSetup.observers.ts","../src/setups/structureSetup/structureSetup.ts","../src/setups/scrollbarsSetup/scrollbarsSetup.elements.ts","../src/setups/scrollbarsSetup/scrollbarsSetup.ts","../src/plugins/plugins.ts","../../../node_modules/@babel/runtime/helpers/extends.js","../src/plugins/optionsValidation/validation.ts","../src/plugins/optionsValidation/optionsValidation.ts","../src/instances.ts","../src/eventListeners.ts","../src/overlayscrollbars.ts"],"sourcesContent":["export interface CacheOptions {\r\n // initial value of _value.\r\n _initialValue: Value;\r\n // Custom comparison function if shallow compare isn't enough. Returns true if nothing changed.\r\n _equal?: EqualCachePropFunction;\r\n // If true always updates _value and _previous, otherwise they update only when they changed.\r\n _alwaysUpdateValues?: boolean;\r\n}\r\n\r\nexport type CacheValues = [value: T, changed: boolean, previous?: T];\r\n\r\nexport type EqualCachePropFunction = (currentVal: Value, newVal: Value) => boolean;\r\n\r\nexport type CacheUpdater = (current: Value, previous?: Value) => Value;\r\n\r\nexport type UpdateCacheContextual = (newValue: Value, force?: boolean) => CacheValues;\r\n\r\nexport type UpdateCache = (force?: boolean) => CacheValues;\r\n\r\nexport type GetCurrentCache = (force?: boolean) => CacheValues;\r\n\r\nexport type Cache = [UpdateCache, GetCurrentCache];\r\n\r\nexport type CacheContextual = [UpdateCacheContextual, GetCurrentCache];\r\n\r\nexport function createCache(options: CacheOptions): CacheContextual;\r\nexport function createCache(\r\n options: CacheOptions,\r\n update: CacheUpdater\r\n): Cache;\r\nexport function createCache(\r\n options: CacheOptions,\r\n update?: CacheUpdater\r\n): CacheContextual | Cache {\r\n const { _initialValue, _equal, _alwaysUpdateValues } = options;\r\n let _value: Value = _initialValue;\r\n let _previous: Value | undefined;\r\n\r\n const cacheUpdateContextual: UpdateCacheContextual = (newValue, force?) => {\r\n const curr = _value;\r\n\r\n const newVal = newValue;\r\n const changed = force || (_equal ? !_equal(curr, newVal) : curr !== newVal);\r\n\r\n if (changed || _alwaysUpdateValues) {\r\n _value = newVal;\r\n _previous = curr;\r\n }\r\n\r\n return [_value, changed, _previous];\r\n };\r\n const cacheUpdateIsolated: UpdateCache = (force?) =>\r\n cacheUpdateContextual(update!(_value, _previous), force);\r\n\r\n const getCurrentCache: GetCurrentCache = (force?: boolean) => [\r\n _value,\r\n !!force, // changed\r\n _previous,\r\n ];\r\n\r\n return [update ? cacheUpdateIsolated : cacheUpdateContextual, getCurrentCache] as\r\n | CacheContextual\r\n | Cache;\r\n}\r\n","import { PlainObject } from 'typings';\r\n\r\nconst ElementNodeType = Node.ELEMENT_NODE;\r\nconst { toString, hasOwnProperty } = Object.prototype;\r\n\r\nexport function isUndefined(obj: any): obj is undefined {\r\n return obj === undefined;\r\n}\r\n\r\nexport function isNull(obj: any): obj is null {\r\n return obj === null;\r\n}\r\n\r\nexport const type: (obj: any) => string = (obj) =>\r\n isUndefined(obj) || isNull(obj)\r\n ? `${obj}`\r\n : toString\r\n .call(obj)\r\n .replace(/^\\[object (.+)\\]$/, '$1')\r\n .toLowerCase();\r\n\r\nexport function isNumber(obj: any): obj is number {\r\n return typeof obj === 'number';\r\n}\r\n\r\nexport function isString(obj: any): obj is string {\r\n return typeof obj === 'string';\r\n}\r\n\r\nexport function isBoolean(obj: any): obj is boolean {\r\n return typeof obj === 'boolean';\r\n}\r\n\r\nexport function isFunction(obj: any): obj is (...args: any[]) => any {\r\n return typeof obj === 'function';\r\n}\r\n\r\nexport function isArray(obj: any): obj is Array {\r\n return Array.isArray(obj);\r\n}\r\n\r\nexport function isObject(obj: any): boolean {\r\n return typeof obj === 'object' && !isArray(obj) && !isNull(obj);\r\n}\r\n\r\n/**\r\n * Returns true if the given object is array like, false otherwise.\r\n * @param obj The Object\r\n */\r\nexport function isArrayLike(obj: any): obj is ArrayLike {\r\n const length = !!obj && obj.length;\r\n const lengthCorrectFormat = isNumber(length) && length > -1 && length % 1 == 0; // eslint-disable-line eqeqeq\r\n\r\n return isArray(obj) || (!isFunction(obj) && lengthCorrectFormat)\r\n ? length > 0 && isObject(obj)\r\n ? length - 1 in obj\r\n : true\r\n : false;\r\n}\r\n\r\n/**\r\n * Returns true if the given object is a \"plain\" (e.g. { key: value }) object, false otherwise.\r\n * @param obj The Object.\r\n */\r\nexport function isPlainObject(obj: any): obj is PlainObject {\r\n if (!obj || !isObject(obj) || type(obj) !== 'object') return false;\r\n\r\n let key;\r\n const cstr = 'constructor';\r\n const ctor = obj[cstr];\r\n const ctorProto = ctor && ctor.prototype;\r\n const hasOwnConstructor = hasOwnProperty.call(obj, cstr);\r\n const hasIsPrototypeOf = ctorProto && hasOwnProperty.call(ctorProto, 'isPrototypeOf');\r\n\r\n if (ctor && !hasOwnConstructor && !hasIsPrototypeOf) {\r\n return false;\r\n }\r\n\r\n /* eslint-disable no-restricted-syntax */\r\n for (key in obj) {\r\n /**/\r\n }\r\n /* eslint-enable */\r\n\r\n return isUndefined(key) || hasOwnProperty.call(obj, key);\r\n}\r\n\r\n/**\r\n * Checks whether the given object is a HTMLElement.\r\n * @param obj The object which shall be checked.\r\n */\r\nexport function isHTMLElement(obj: any): obj is HTMLElement {\r\n const instanceofObj = window.HTMLElement;\r\n return obj\r\n ? instanceofObj\r\n ? obj instanceof instanceofObj\r\n : obj.nodeType === ElementNodeType\r\n : false;\r\n}\r\n\r\n/**\r\n * Checks whether the given object is a Element.\r\n * @param obj The object which shall be checked.\r\n */\r\nexport function isElement(obj: any): obj is Element {\r\n const instanceofObj = window.Element;\r\n return obj\r\n ? instanceofObj\r\n ? obj instanceof instanceofObj\r\n : obj.nodeType === ElementNodeType\r\n : false;\r\n}\r\n","import { isArrayLike, isString } from 'support/utils/types';\r\nimport { PlainObject } from 'typings';\r\n\r\ntype RunEachItem = ((...args: any) => any | any[]) | null | undefined;\r\n\r\n/**\r\n * Iterates through a array or object\r\n * @param arrayLikeOrObject The array or object through which shall be iterated.\r\n * @param callback The function which is responsible for the iteration.\r\n * If the function returns true its treated like a \"continue\" statement.\r\n * If the function returns false its treated like a \"break\" statement.\r\n */\r\nexport function each(\r\n array: Array | ReadonlyArray,\r\n callback: (value: T, indexOrKey: number, source: Array) => boolean | unknown\r\n): Array | ReadonlyArray;\r\nexport function each(\r\n array: Array | ReadonlyArray | null | undefined,\r\n callback: (value: T, indexOrKey: number, source: Array) => boolean | unknown\r\n): Array | ReadonlyArray | null | undefined;\r\nexport function each(\r\n arrayLikeObject: ArrayLike,\r\n callback: (value: T, indexOrKey: number, source: ArrayLike) => boolean | unknown\r\n): ArrayLike;\r\nexport function each(\r\n arrayLikeObject: ArrayLike | null | undefined,\r\n callback: (value: T, indexOrKey: number, source: ArrayLike) => boolean | unknown\r\n): ArrayLike | null | undefined;\r\nexport function each(\r\n obj: PlainObject,\r\n callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown\r\n): PlainObject;\r\nexport function each(\r\n obj: PlainObject | null | undefined,\r\n callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown\r\n): PlainObject | null | undefined;\r\nexport function each(\r\n source: ArrayLike | PlainObject | null | undefined,\r\n callback: (value: T, indexOrKey: any, source: any) => boolean | unknown\r\n): Array | ReadonlyArray | ArrayLike | PlainObject | null | undefined {\r\n if (isArrayLike(source)) {\r\n for (let i = 0; i < source.length; i++) {\r\n if (callback(source[i], i, source) === false) {\r\n break;\r\n }\r\n }\r\n } else if (source) {\r\n each(Object.keys(source), (key) => callback(source[key], key, source));\r\n }\r\n return source;\r\n}\r\n\r\n/**\r\n * Returns the index of the given inside the given array or -1 if the given item isn't part of the given array.\r\n * @param arr The array.\r\n * @param item The item.\r\n * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.\r\n */\r\nexport const indexOf = (arr: T[], item: T, fromIndex?: number): number =>\r\n arr.indexOf(item, fromIndex);\r\n\r\n/**\r\n * Pushesh all given items into the given array and returns it.\r\n * @param array The array the items shall be pushed into.\r\n * @param items The items which shall be pushed into the array.\r\n */\r\nexport const push = (array: T[], items: T | ArrayLike, arrayIsSingleItem?: boolean): T[] => {\r\n !arrayIsSingleItem && !isString(items) && isArrayLike(items)\r\n ? Array.prototype.push.apply(array, items as T[])\r\n : array.push(items as T);\r\n return array;\r\n};\r\n\r\n/**\r\n * Creates a shallow-copied Array instance from an array-like or iterable object.\r\n * @param arr The object from which the array instance shall be created.\r\n */\r\nexport const from = (arr?: ArrayLike | Set) => {\r\n if (Array.from && arr) {\r\n return Array.from(arr);\r\n }\r\n const result: T[] = [];\r\n\r\n if (arr instanceof Set) {\r\n arr.forEach((value) => {\r\n push(result, value);\r\n });\r\n } else {\r\n each(arr, (elm) => {\r\n push(result, elm);\r\n });\r\n }\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Check whether the passed array is empty.\r\n * @param array The array which shall be checked.\r\n */\r\nexport const isEmptyArray = (array: any[] | null | undefined): boolean =>\r\n !!array && array.length === 0;\r\n\r\n/**\r\n * Calls all functions in the passed array/set of functions.\r\n * @param arr The array filled with function which shall be called.\r\n * @param p1 The first param.\r\n */\r\nexport const runEach = (arr: ArrayLike | Set, args?: any[]): void => {\r\n // eslint-disable-next-line prefer-spread\r\n const runFn = (fn: RunEachItem) => fn && fn.apply(undefined, args || []);\r\n if (arr instanceof Set) {\r\n arr.forEach(runFn);\r\n } else {\r\n each(arr, runFn);\r\n }\r\n};\r\n","import { isArray, isFunction, isPlainObject, isNull } from 'support/utils/types';\r\nimport { each } from 'support/utils/array';\r\n\r\n/**\r\n * Determines whether the passed object has a property with the passed name.\r\n * @param obj The object.\r\n * @param prop The name of the property.\r\n */\r\nexport const hasOwnProperty = (obj: any, prop: string | number | symbol): boolean =>\r\n Object.prototype.hasOwnProperty.call(obj, prop);\r\n\r\n/**\r\n * Returns the names of the enumerable string properties and methods of an object.\r\n * @param obj The object of which the properties shall be returned.\r\n */\r\nexport const keys = (obj: any): Array => (obj ? Object.keys(obj) : []);\r\n\r\n// https://github.com/jquery/jquery/blob/master/src/core.js#L116\r\nexport function assignDeep(target: T, object1: U): T & U;\r\nexport function assignDeep(target: T, object1: U, object2: V): T & U & V;\r\nexport function assignDeep(\r\n target: T,\r\n object1: U,\r\n object2: V,\r\n object3: W\r\n): T & U & V & W;\r\nexport function assignDeep(\r\n target: T,\r\n object1: U,\r\n object2: V,\r\n object3: W,\r\n object4: X\r\n): T & U & V & W & X;\r\nexport function assignDeep(\r\n target: T,\r\n object1: U,\r\n object2: V,\r\n object3: W,\r\n object4: X,\r\n object5: Y\r\n): T & U & V & W & X & Y;\r\nexport function assignDeep(\r\n target: T,\r\n object1?: U,\r\n object2?: V,\r\n object3?: W,\r\n object4?: X,\r\n object5?: Y,\r\n object6?: Z\r\n): T & U & V & W & X & Y & Z {\r\n const sources: Array = [object1, object2, object3, object4, object5, object6];\r\n\r\n // Handle case when target is a string or something (possible in deep copy)\r\n if ((typeof target !== 'object' || isNull(target)) && !isFunction(target)) {\r\n target = {} as T;\r\n }\r\n\r\n each(sources, (source) => {\r\n // Extend the base object\r\n each(keys(source), (key) => {\r\n const copy: any = source[key];\r\n\r\n // Prevent Object.prototype pollution\r\n // Prevent never-ending loop\r\n if (target === copy) {\r\n return true;\r\n }\r\n\r\n const copyIsArray = isArray(copy);\r\n\r\n // Recurse if we're merging plain objects or arrays\r\n if (copy && (isPlainObject(copy) || copyIsArray)) {\r\n const src = target[key];\r\n let clone: any = src;\r\n\r\n // Ensure proper type for the source value\r\n if (copyIsArray && !isArray(src)) {\r\n clone = [];\r\n } else if (!copyIsArray && !isPlainObject(src)) {\r\n clone = {};\r\n }\r\n\r\n // Never move original objects, clone them\r\n target[key] = assignDeep(clone, copy) as any;\r\n } else {\r\n target[key] = copy;\r\n }\r\n });\r\n });\r\n\r\n // Return the modified object\r\n return target as any;\r\n}\r\n\r\n/**\r\n * Returns true if the given object is empty, false otherwise.\r\n * @param obj The Object.\r\n */\r\nexport function isEmptyObject(obj: any): boolean {\r\n /* eslint-disable no-restricted-syntax, guard-for-in */\r\n for (const name in obj) return false;\r\n return true;\r\n /* eslint-enable */\r\n}\r\n","import { isUndefined } from 'support/utils/types';\r\n\r\ntype GetSetPropName = 'scrollLeft' | 'scrollTop' | 'value';\r\n\r\nfunction getSetProp(\r\n topLeft: GetSetPropName,\r\n fallback: number | string,\r\n elm: HTMLElement | HTMLInputElement | null,\r\n value?: number | string\r\n): number | string | void {\r\n if (isUndefined(value)) {\r\n return elm ? elm[topLeft] : fallback;\r\n }\r\n elm && (elm[topLeft] = value);\r\n}\r\n\r\n/**\r\n * Gets or sets a attribute with the given attribute of the given element depending whether the value attribute is given.\r\n * Returns null if the element has no attribute with the given name.\r\n * @param elm The element of which the attribute shall be get or set.\r\n * @param attrName The attribute name which shall be get or set.\r\n * @param value The value of the attribute which shall be set.\r\n */\r\nexport function attr(elm: HTMLElement | null, attrName: string): string | null;\r\nexport function attr(elm: HTMLElement | null, attrName: string, value: string): void;\r\nexport function attr(\r\n elm: HTMLElement | null,\r\n attrName: string,\r\n value?: string\r\n): string | null | void {\r\n if (isUndefined(value)) {\r\n return elm ? elm.getAttribute(attrName) : null;\r\n }\r\n elm && elm.setAttribute(attrName, value);\r\n}\r\n\r\n/**\r\n * Removes the given attribute from the given element.\r\n * @param elm The element of which the attribute shall be removed.\r\n * @param attrName The attribute name.\r\n */\r\nexport const removeAttr = (elm: Element | null, attrName: string): void => {\r\n elm && elm.removeAttribute(attrName);\r\n};\r\n\r\n/**\r\n * Gets or sets the scrollLeft value of the given element depending whether the value attribute is given.\r\n * @param elm The element of which the scrollLeft value shall be get or set.\r\n * @param value The scrollLeft value which shall be set.\r\n */\r\nexport function scrollLeft(elm: HTMLElement | null): number;\r\nexport function scrollLeft(elm: HTMLElement | null, value: number): void;\r\nexport function scrollLeft(elm: HTMLElement | null, value?: number): number | void {\r\n return getSetProp('scrollLeft', 0, elm, value) as number;\r\n}\r\n\r\n/**\r\n * Gets or sets the scrollTop value of the given element depending whether the value attribute is given.\r\n * @param elm The element of which the scrollTop value shall be get or set.\r\n * @param value The scrollTop value which shall be set.\r\n */\r\nexport function scrollTop(elm: HTMLElement | null): number;\r\nexport function scrollTop(elm: HTMLElement | null, value: number): void;\r\nexport function scrollTop(elm: HTMLElement | null, value?: number): number | void {\r\n return getSetProp('scrollTop', 0, elm, value) as number;\r\n}\r\n\r\n/**\r\n * Gets or sets the value of the given input element depending whether the value attribute is given.\r\n * @param elm The input element of which the value shall be get or set.\r\n * @param value The value which shall be set.\r\n */\r\nexport function val(elm: HTMLInputElement | null): string;\r\nexport function val(elm: HTMLInputElement | null, value: string): void;\r\nexport function val(elm: HTMLInputElement | null, value?: string): string | void {\r\n return getSetProp('value', '', elm, value) as string;\r\n}\r\n","import { isElement } from 'support/utils/types';\r\nimport { push, from } from 'support/utils/array';\r\n\r\ntype InputElementType = Element | Node | false | null | undefined;\r\ntype OutputElementType = Element | null;\r\n\r\nconst elmPrototype = Element.prototype;\r\n\r\n/**\r\n * Find all elements with the passed selector, outgoing (and including) the passed element or the document if no element was provided.\r\n * @param selector The selector which has to be searched by.\r\n * @param elm The element from which the search shall be outgoing.\r\n */\r\nconst find = (selector: string, elm?: InputElementType): Element[] => {\r\n const arr: Array = [];\r\n const rootElm = elm ? (isElement(elm) ? elm : null) : document;\r\n\r\n return rootElm ? push(arr, rootElm.querySelectorAll(selector)) : arr;\r\n};\r\n\r\n/**\r\n * Find the first element with the passed selector, outgoing (and including) the passed element or the document if no element was provided.\r\n * @param selector The selector which has to be searched by.\r\n * @param elm The element from which the search shall be outgoing.\r\n */\r\nconst findFirst = (selector: string, elm?: InputElementType): OutputElementType => {\r\n const rootElm = elm ? (isElement(elm) ? elm : null) : document;\r\n\r\n return rootElm ? rootElm.querySelector(selector) : null;\r\n};\r\n\r\n/**\r\n * Determines whether the passed element is matching with the passed selector.\r\n * @param elm The element which has to be compared with the passed selector.\r\n * @param selector The selector which has to be compared with the passed element. Additional selectors: ':visible' and ':hidden'.\r\n */\r\nconst is = (elm: InputElementType, selector: string): boolean => {\r\n if (isElement(elm)) {\r\n /* istanbul ignore next */\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n const fn: (...args: any) => boolean = elmPrototype.matches || elmPrototype.msMatchesSelector;\r\n return fn.call(elm, selector);\r\n }\r\n return false;\r\n};\r\n\r\n/**\r\n * Returns the children (no text-nodes or comments) of the passed element which are matching the passed selector. An empty array is returned if the passed element is null.\r\n * @param elm The element of which the children shall be returned.\r\n * @param selector The selector which must match with the children elements.\r\n */\r\nconst children = (elm: InputElementType, selector?: string): ReadonlyArray => {\r\n const childs: Array = [];\r\n\r\n return isElement(elm)\r\n ? push(\r\n childs,\r\n from(elm.children).filter((child) => (selector ? is(child, selector) : child))\r\n )\r\n : childs;\r\n};\r\n\r\n/**\r\n * Returns the childNodes (incl. text-nodes or comments etc.) of the passed element. An empty array is returned if the passed element is null.\r\n * @param elm The element of which the childNodes shall be returned.\r\n */\r\nconst contents = (elm: InputElementType): ReadonlyArray =>\r\n elm ? from(elm.childNodes) : [];\r\n\r\n/**\r\n * Returns the parent element of the passed element, or null if the passed element is null.\r\n * @param elm The element of which the parent element shall be returned.\r\n */\r\nconst parent = (elm: InputElementType): OutputElementType => (elm ? elm.parentElement : null);\r\n\r\nconst closest = (elm: InputElementType, selector: string): OutputElementType => {\r\n if (isElement(elm)) {\r\n const closestFn = elmPrototype.closest;\r\n if (closestFn) {\r\n return closestFn.call(elm, selector);\r\n }\r\n\r\n do {\r\n if (is(elm, selector)) {\r\n return elm as Element;\r\n }\r\n elm = parent(elm);\r\n } while (elm);\r\n }\r\n\r\n return null;\r\n};\r\n\r\n/**\r\n * Determines whether the given element lies between two selectors in the DOM.\r\n * @param elm The element.\r\n * @param highBoundarySelector The high boundary selector.\r\n * @param deepBoundarySelector The deep boundary selector.\r\n */\r\nconst liesBetween = (\r\n elm: InputElementType,\r\n highBoundarySelector: string,\r\n deepBoundarySelector: string\r\n): boolean => {\r\n const closestHighBoundaryElm = elm && closest(elm, highBoundarySelector);\r\n const closestDeepBoundaryElm = elm && findFirst(deepBoundarySelector, closestHighBoundaryElm);\r\n\r\n return closestHighBoundaryElm && closestDeepBoundaryElm\r\n ? closestHighBoundaryElm === elm ||\r\n closestDeepBoundaryElm === elm ||\r\n closest(closest(elm, deepBoundarySelector), highBoundarySelector) !== closestHighBoundaryElm\r\n : false;\r\n};\r\n\r\nexport { find, findFirst, is, children, contents, parent, liesBetween };\r\n","import { isArrayLike } from 'support/utils/types';\r\nimport { each, from } from 'support/utils/array';\r\nimport { parent } from 'support/dom/traversal';\r\n\r\ntype NodeCollection = ArrayLike | Node | false | null | undefined;\r\n\r\n/**\r\n * Inserts Nodes before the given preferredAnchor element.\r\n * @param parentElm The parent of the preferredAnchor element or the element which shall be the parent of the inserted Nodes.\r\n * @param preferredAnchor The element before which the Nodes shall be inserted or null if the elements shall be appended at the end.\r\n * @param insertedElms The Nodes which shall be inserted.\r\n */\r\nconst before = (\r\n parentElm: Node | false | null | undefined,\r\n preferredAnchor: Node | null | undefined,\r\n insertedElms: NodeCollection\r\n): void => {\r\n if (insertedElms) {\r\n let anchor: Node | null | undefined = preferredAnchor;\r\n let fragment: DocumentFragment | Node | null | undefined;\r\n\r\n // parent must be defined\r\n if (parentElm) {\r\n if (isArrayLike(insertedElms)) {\r\n fragment = document.createDocumentFragment();\r\n\r\n // append all insertedElms to the fragment and if one of these is the anchor, change the anchor\r\n each(insertedElms, (insertedElm) => {\r\n if (insertedElm === anchor) {\r\n anchor = insertedElm.previousSibling;\r\n }\r\n fragment!.appendChild(insertedElm);\r\n });\r\n } else {\r\n fragment = insertedElms;\r\n }\r\n\r\n // if the preferred anchor isn't null set it to a valid anchor\r\n if (preferredAnchor) {\r\n if (!anchor) {\r\n anchor = parentElm.firstChild;\r\n } else if (anchor !== preferredAnchor) {\r\n anchor = anchor.nextSibling;\r\n }\r\n }\r\n\r\n parentElm.insertBefore(fragment, anchor || null);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Appends the given children at the end of the given Node.\r\n * @param node The Node to which the children shall be appended.\r\n * @param children The Nodes which shall be appended.\r\n */\r\nexport const appendChildren = (node: Node | null | undefined, children: NodeCollection): void => {\r\n before(node, null, children);\r\n};\r\n\r\n/**\r\n * Prepends the given children at the start of the given Node.\r\n * @param node The Node to which the children shall be prepended.\r\n * @param children The Nodes which shall be prepended.\r\n */\r\nexport const prependChildren = (node: Node | null | undefined, children: NodeCollection): void => {\r\n before(node, node && node.firstChild, children);\r\n};\r\n\r\n/**\r\n * Inserts the given Nodes before the given Node.\r\n * @param node The Node before which the given Nodes shall be inserted.\r\n * @param insertedNodes The Nodes which shall be inserted.\r\n */\r\nexport const insertBefore = (\r\n node: Node | null | undefined,\r\n insertedNodes: NodeCollection\r\n): void => {\r\n before(parent(node), node, insertedNodes);\r\n};\r\n\r\n/**\r\n * Inserts the given Nodes after the given Node.\r\n * @param node The Node after which the given Nodes shall be inserted.\r\n * @param insertedNodes The Nodes which shall be inserted.\r\n */\r\nexport const insertAfter = (node: Node | null | undefined, insertedNodes: NodeCollection): void => {\r\n before(parent(node), node && node.nextSibling, insertedNodes);\r\n};\r\n\r\n/**\r\n * Removes the given Nodes from their parent.\r\n * @param nodes The Nodes which shall be removed.\r\n */\r\nexport const removeElements = (nodes: NodeCollection): void => {\r\n if (isArrayLike(nodes)) {\r\n each(from(nodes), (e) => removeElements(e));\r\n } else if (nodes) {\r\n const parentElm = parent(nodes);\r\n if (parentElm) {\r\n parentElm.removeChild(nodes);\r\n }\r\n }\r\n};\r\n","import { each } from 'support/utils/array';\r\nimport { attr } from 'support/dom/attribute';\r\nimport { contents } from 'support/dom/traversal';\r\nimport { removeElements } from 'support/dom/manipulation';\r\n\r\n/**\r\n * Creates a div DOM node.\r\n */\r\nexport const createDiv = (classNames?: string): HTMLDivElement => {\r\n const div = document.createElement('div');\r\n if (classNames) {\r\n attr(div, 'class', classNames);\r\n }\r\n return div;\r\n};\r\n\r\n/**\r\n * Creates DOM nodes modeled after the passed html string and returns the root dom nodes as a array.\r\n * @param html The html string after which the DOM nodes shall be created.\r\n */\r\nexport const createDOM = (html: string): ReadonlyArray => {\r\n const createdDiv = createDiv();\r\n createdDiv.innerHTML = html.trim();\r\n\r\n return each(contents(createdDiv), (elm) => removeElements(elm));\r\n};\r\n","import { each } from 'support/utils/array';\r\nimport { hasOwnProperty } from 'support/utils/object';\r\nimport { createDiv } from 'support/dom/create';\r\n\r\nconst firstLetterToUpper = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1);\r\nconst getDummyStyle = (): CSSStyleDeclaration => createDiv().style;\r\n\r\n// https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix\r\n\r\nexport const cssPrefixes: ReadonlyArray = ['-webkit-', '-moz-', '-o-', '-ms-'];\r\nexport const jsPrefixes: ReadonlyArray = [\r\n 'WebKit',\r\n 'Moz',\r\n 'O',\r\n 'MS',\r\n 'webkit',\r\n 'moz',\r\n 'o',\r\n 'ms',\r\n];\r\n\r\nexport const jsCache: { [key: string]: any } = {};\r\nexport const cssCache: { [key: string]: string } = {};\r\n\r\n/**\r\n * Gets the name of the given CSS property with vendor prefix if it isn't supported without it, or and empty string if unsupported.\r\n * @param name The name of the CSS property which shall be get.\r\n */\r\nexport const cssProperty = (name: string): string => {\r\n let result: string | undefined = cssCache[name];\r\n\r\n if (hasOwnProperty(cssCache, name)) {\r\n return result;\r\n }\r\n\r\n const uppercasedName: string = firstLetterToUpper(name);\r\n const elmStyle: CSSStyleDeclaration = getDummyStyle();\r\n\r\n each(cssPrefixes, (prefix: string) => {\r\n const prefixWithoutDashes: string = prefix.replace(/-/g, '');\r\n const resultPossibilities: Array = [\r\n name, // transition\r\n prefix + name, // -webkit-transition\r\n prefixWithoutDashes + uppercasedName, // webkitTransition\r\n firstLetterToUpper(prefixWithoutDashes) + uppercasedName, // WebkitTransition\r\n ];\r\n\r\n // eslint-disable-next-line no-return-assign\r\n return !(result = resultPossibilities.find(\r\n (resultPossibility: string) => elmStyle[resultPossibility] !== undefined\r\n ));\r\n });\r\n\r\n // eslint-disable-next-line no-return-assign\r\n return (cssCache[name] = result || '');\r\n};\r\n\r\n/**\r\n * Get the name of the given CSS property value(s), with vendor prefix if it isn't supported without it, or an empty string if no value is supported.\r\n * @param property The CSS property to which the CSS property value(s) belong.\r\n * @param values The value(s) separated by spaces which shall be get.\r\n * @param suffix A suffix which is added to each value in case the value is a function or something else more advanced.\r\n */\r\nexport const cssPropertyValue = (property: string, values: string, suffix?: string): string => {\r\n const name = `${property} ${values}`;\r\n let result: string | undefined = cssCache[name];\r\n\r\n if (hasOwnProperty(cssCache, name)) {\r\n return result;\r\n }\r\n\r\n const dummyStyle: CSSStyleDeclaration = getDummyStyle();\r\n const possbleValues: Array = values.split(' ');\r\n const preparedSuffix: string = suffix || '';\r\n const cssPrefixesWithFirstEmpty = [''].concat(cssPrefixes);\r\n\r\n each(possbleValues, (possibleValue: string) => {\r\n each(cssPrefixesWithFirstEmpty, (prefix: string) => {\r\n const prop = prefix + possibleValue;\r\n dummyStyle.cssText = `${property}:${prop}${preparedSuffix}`;\r\n if (dummyStyle.length) {\r\n result = prop;\r\n return false;\r\n }\r\n });\r\n return !result;\r\n });\r\n\r\n // eslint-disable-next-line no-return-assign\r\n return (cssCache[name] = result || '');\r\n};\r\n\r\n/**\r\n * Get the requested JS function, object or constructor with vendor prefix if it isn't supported without or undefined if unsupported.\r\n * @param name The name of the JS function, object or constructor.\r\n */\r\nexport const jsAPI = (name: string): T | undefined => {\r\n let result: any = jsCache[name] || window[name];\r\n\r\n if (hasOwnProperty(jsCache, name)) {\r\n return result;\r\n }\r\n\r\n each(jsPrefixes, (prefix: string) => {\r\n result = result || window[prefix + firstLetterToUpper(name)];\r\n return !result;\r\n });\r\n\r\n jsCache[name] = result;\r\n return result;\r\n};\r\n","import { jsAPI } from 'support/compatibility/vendors';\r\n\r\nexport const MutationObserverConstructor = jsAPI('MutationObserver');\r\nexport const IntersectionObserverConstructor = jsAPI(\r\n 'IntersectionObserver'\r\n);\r\nexport const ResizeObserverConstructor = jsAPI('ResizeObserver');\r\nexport const cAF = jsAPI('cancelAnimationFrame');\r\nexport const rAF = jsAPI('requestAnimationFrame');\r\n","import { isString } from 'support/utils/types';\r\nimport { each } from 'support/utils/array';\r\nimport { keys } from 'support/utils/object';\r\n\r\nconst rnothtmlwhite = /[^\\x20\\t\\r\\n\\f]+/g;\r\nconst classListAction = (\r\n elm: Element | false | null | undefined,\r\n className: string,\r\n action: (elmClassList: DOMTokenList, clazz: string) => boolean | void\r\n): boolean => {\r\n let clazz: string;\r\n let i = 0;\r\n let result = false;\r\n\r\n if (elm && isString(className)) {\r\n const classes: Array = className.match(rnothtmlwhite) || [];\r\n result = classes.length > 0;\r\n while ((clazz = classes[i++])) {\r\n result = !!action(elm.classList, clazz) && result;\r\n }\r\n }\r\n return result;\r\n};\r\n\r\n/**\r\n * Check whether the given element has the given class name(s).\r\n * @param elm The element.\r\n * @param className The class name(s).\r\n */\r\nexport const hasClass = (elm: Element | false | null | undefined, className: string): boolean =>\r\n classListAction(elm, className, (classList, clazz) => classList.contains(clazz));\r\n\r\n/**\r\n * Removes the given class name(s) from the given element.\r\n * @param elm The element.\r\n * @param className The class name(s) which shall be removed. (separated by spaces)\r\n */\r\nexport const removeClass = (elm: Element | false | null | undefined, className: string): void => {\r\n classListAction(elm, className, (classList, clazz) => classList.remove(clazz));\r\n};\r\n\r\n/**\r\n * Adds the given class name(s) to the given element.\r\n * @param elm The element.\r\n * @param className The class name(s) which shall be added. (separated by spaces)\r\n * @returns A function which removes the added class name(s).\r\n */\r\nexport const addClass = (\r\n elm: Element | false | null | undefined,\r\n className: string\r\n): (() => void) => {\r\n classListAction(elm, className, (classList, clazz) => classList.add(clazz));\r\n return removeClass.bind(0, elm, className);\r\n};\r\n\r\n/**\r\n * Takes two className strings, compares them and returns the difference as array.\r\n * @param classNameA ClassName A.\r\n * @param classNameB ClassName B.\r\n */\r\nexport const diffClass = (\r\n classNameA: string | null | undefined,\r\n classNameB: string | null | undefined\r\n) => {\r\n const classNameASplit = classNameA && classNameA.split(' ');\r\n const classNameBSplit = classNameB && classNameB.split(' ');\r\n const tempObj = {};\r\n\r\n each(classNameASplit, (className) => {\r\n tempObj[className] = 1;\r\n });\r\n each(classNameBSplit, (className) => {\r\n if (tempObj[className]) {\r\n delete tempObj[className];\r\n } else {\r\n tempObj[className] = 1;\r\n }\r\n });\r\n\r\n return keys(tempObj);\r\n};\r\n","import { each } from 'support/utils/array';\r\nimport { WH, XY, TRBL } from 'support/dom';\r\nimport { PlainObject } from 'typings';\r\n\r\n/**\r\n * Compares two objects and returns true if all values of the passed prop names are identical, false otherwise or if one of the two object is falsy.\r\n * @param a Object a.\r\n * @param b Object b.\r\n * @param props The props which shall be compared.\r\n */\r\nexport const equal = (\r\n a: T | undefined,\r\n b: T | undefined,\r\n props: Array,\r\n propMutation?: ((value: any) => any) | null | false\r\n): boolean => {\r\n if (a && b) {\r\n let result = true;\r\n each(props, (prop) => {\r\n const compareA = propMutation ? propMutation(a[prop]) : a[prop];\r\n const compareB = propMutation ? propMutation(b[prop]) : b[prop];\r\n if (compareA !== compareB) {\r\n result = false;\r\n }\r\n });\r\n return result;\r\n }\r\n return false;\r\n};\r\n\r\n/**\r\n * Compares object a with object b and returns true if both have the same property values, false otherwise.\r\n * Also returns false if one of the objects is undefined or null.\r\n * @param a Object a.\r\n * @param b Object b.\r\n */\r\nexport const equalWH = (a?: WH, b?: WH) => equal>(a, b, ['w', 'h']);\r\n\r\n/**\r\n * Compares object a with object b and returns true if both have the same property values, false otherwise.\r\n * Also returns false if one of the objects is undefined or null.\r\n * @param a Object a.\r\n * @param b Object b.\r\n */\r\nexport const equalXY = (a?: XY, b?: XY) => equal>(a, b, ['x', 'y']);\r\n\r\n/**\r\n * Compares object a with object b and returns true if both have the same property values, false otherwise.\r\n * Also returns false if one of the objects is undefined or null.\r\n * @param a Object a.\r\n * @param b Object b.\r\n */\r\nexport const equalTRBL = (a?: TRBL, b?: TRBL) => equal(a, b, ['t', 'r', 'b', 'l']);\r\n\r\n/**\r\n * Compares two DOM Rects for their equality of their width and height properties\r\n * Also returns false if one of the DOM Rects is undefined or null.\r\n * @param a DOM Rect a.\r\n * @param b DOM Rect b.\r\n * @param round Whether the values should be rounded.\r\n */\r\nexport const equalBCRWH = (a?: DOMRect, b?: DOMRect, round?: boolean) =>\r\n equal(a, b, ['width', 'height'], round && ((value) => Math.round(value)));\r\n","import { isNumber, isFunction } from 'support/utils/types';\r\nimport { from } from 'support/utils/array';\r\nimport { rAF, cAF } from 'support/compatibility/apis';\r\n\r\nconst clearTimeouts = (id: number | undefined) => {\r\n id && window.clearTimeout(id);\r\n id && cAF!(id);\r\n};\r\n\r\ntype DebounceTiming = number | false | null | undefined;\r\n\r\nexport interface DebounceOptions any> {\r\n /**\r\n * The timeout for debouncing. If null, no debounce is applied.\r\n */\r\n _timeout?: DebounceTiming | (() => DebounceTiming);\r\n /**\r\n * A maximum amount of ms. before the function will be called even with debounce.\r\n */\r\n _maxDelay?: DebounceTiming | (() => DebounceTiming);\r\n /**\r\n * Function which merges parameters for each canceled debounce.\r\n * If parameters can't be merged the function will return null, otherwise it returns the merged parameters.\r\n */\r\n _mergeParams?: (\r\n prev: Parameters,\r\n curr: Parameters\r\n ) => Parameters | false | null | undefined;\r\n}\r\n\r\nexport interface Debounced any> {\r\n (...args: Parameters): ReturnType;\r\n _flush(): void;\r\n}\r\n\r\nexport const noop = () => {}; // eslint-disable-line\r\n\r\n/**\r\n * Debounces the given function either with a timeout or a animation frame.\r\n * @param functionToDebounce The function which shall be debounced.\r\n * @param options Options for debouncing.\r\n */\r\nexport const debounce = any>(\r\n functionToDebounce: FunctionToDebounce,\r\n options?: DebounceOptions\r\n): Debounced => {\r\n let timeoutId: number | undefined;\r\n let maxTimeoutId: number | undefined;\r\n let prevArguments: Parameters | null | undefined;\r\n let latestArguments: Parameters | null | undefined;\r\n const { _timeout, _maxDelay, _mergeParams } = options || {};\r\n const setT = window.setTimeout;\r\n\r\n const invokeFunctionToDebounce = function (args: IArguments) {\r\n clearTimeouts(timeoutId);\r\n clearTimeouts(maxTimeoutId);\r\n maxTimeoutId = timeoutId = prevArguments = undefined;\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n functionToDebounce.apply(this, args);\r\n };\r\n\r\n const mergeParms = (\r\n curr: Parameters\r\n ): Parameters | false | null | undefined =>\r\n _mergeParams && prevArguments ? _mergeParams(prevArguments, curr) : curr;\r\n\r\n const flush = () => {\r\n /* istanbul ignore next */\r\n if (timeoutId) {\r\n invokeFunctionToDebounce(mergeParms(latestArguments!) || latestArguments!);\r\n }\r\n };\r\n\r\n const debouncedFn = function () {\r\n // eslint-disable-next-line prefer-rest-params\r\n const args: Parameters = from(arguments) as Parameters;\r\n const finalTimeout = isFunction(_timeout) ? _timeout() : _timeout;\r\n const hasTimeout = isNumber(finalTimeout) && finalTimeout >= 0;\r\n\r\n if (hasTimeout) {\r\n const finalMaxWait = isFunction(_maxDelay) ? _maxDelay() : _maxDelay;\r\n const hasMaxWait = isNumber(finalMaxWait) && finalMaxWait >= 0;\r\n const setTimeoutFn = finalTimeout > 0 ? setT : rAF!;\r\n const mergeParamsResult = mergeParms(args);\r\n const invokedArgs = mergeParamsResult || args;\r\n const boundInvoke = invokeFunctionToDebounce.bind(0, invokedArgs);\r\n\r\n // if (!mergeParamsResult) {\r\n // invokeFunctionToDebounce(prevArguments || args);\r\n // }\r\n\r\n clearTimeouts(timeoutId);\r\n // @ts-ignore\r\n timeoutId = setTimeoutFn(boundInvoke, finalTimeout as number) as number;\r\n\r\n if (hasMaxWait && !maxTimeoutId) {\r\n maxTimeoutId = setT(flush, finalMaxWait as number);\r\n }\r\n\r\n prevArguments = latestArguments = invokedArgs;\r\n } else {\r\n invokeFunctionToDebounce(args);\r\n }\r\n };\r\n debouncedFn._flush = flush;\r\n\r\n return debouncedFn as Debounced;\r\n};\r\n","import { each, keys } from 'support/utils';\r\nimport { isString, isNumber, isArray, isUndefined } from 'support/utils/types';\r\nimport { PlainObject, StyleObject } from 'typings';\r\n\r\nexport interface TRBL {\r\n t: number;\r\n r: number;\r\n b: number;\r\n l: number;\r\n}\r\n\r\nconst cssNumber = {\r\n // animationiterationcount: 1,\r\n // columncount: 1,\r\n // fillopacity: 1,\r\n // flexgrow: 1,\r\n // flexshrink: 1,\r\n // fontweight: 1,\r\n // lineheight: 1,\r\n // order: 1,\r\n // orphans: 1,\r\n // widows: 1,\r\n // zoom: 1,\r\n opacity: 1,\r\n zindex: 1,\r\n};\r\n\r\nconst parseToZeroOrNumber = (value: string, toFloat?: boolean): number => {\r\n /* istanbul ignore next */\r\n const num = toFloat ? parseFloat(value) : parseInt(value, 10);\r\n /* istanbul ignore next */\r\n return Number.isNaN(num) ? 0 : num;\r\n};\r\nconst adaptCSSVal = (prop: string, val: string | number): string | number =>\r\n !cssNumber[prop.toLowerCase()] && isNumber(val) ? `${val}px` : val;\r\nconst getCSSVal = (elm: HTMLElement, computedStyle: CSSStyleDeclaration, prop: string): string =>\r\n /* istanbul ignore next */\r\n computedStyle != null\r\n ? computedStyle[prop] || computedStyle.getPropertyValue(prop)\r\n : elm.style[prop];\r\nconst setCSSVal = (\r\n elm: HTMLElement | false | null | undefined,\r\n prop: string,\r\n val: string | number\r\n): void => {\r\n try {\r\n if (elm) {\r\n const { style: elmStyle } = elm;\r\n if (!isUndefined(elmStyle[prop])) {\r\n elmStyle[prop] = adaptCSSVal(prop, val);\r\n } else {\r\n elmStyle.setProperty(prop, val as string);\r\n }\r\n }\r\n } catch (e) {}\r\n};\r\n\r\n/**\r\n * Gets or sets the passed styles to the passed element.\r\n * @param elm The element to which the styles shall be applied to / be read from.\r\n * @param styles The styles which shall be set or read.\r\n */\r\nexport function style(\r\n elm: HTMLElement | false | null | undefined,\r\n styles: StyleObject\r\n): void;\r\nexport function style(\r\n elm: HTMLElement | false | null | undefined,\r\n styles: string\r\n): string;\r\nexport function style(\r\n elm: HTMLElement | false | null | undefined,\r\n styles: Array | string\r\n): { [key: string]: string };\r\nexport function style(\r\n elm: HTMLElement | false | null | undefined,\r\n styles: StyleObject | Array | string\r\n): { [key: string]: string } | string | void {\r\n const getSingleStyle = isString(styles);\r\n const getStyles = isArray(styles) || getSingleStyle;\r\n\r\n if (getStyles) {\r\n let getStylesResult: string | PlainObject = getSingleStyle ? '' : {};\r\n if (elm) {\r\n const computedStyle: CSSStyleDeclaration = window.getComputedStyle(elm, null);\r\n getStylesResult = getSingleStyle\r\n ? getCSSVal(elm, computedStyle, styles as string)\r\n : (styles as Array).reduce((result, key) => {\r\n result[key] = getCSSVal(elm, computedStyle, key as string);\r\n return result;\r\n }, getStylesResult);\r\n }\r\n return getStylesResult;\r\n }\r\n each(keys(styles), (key) => setCSSVal(elm, key, styles[key]));\r\n}\r\n\r\n/**\r\n * Hides the passed element (display: none).\r\n * @param elm The element which shall be hidden.\r\n */\r\nexport const hide = (elm: HTMLElement | false | null | undefined): void => {\r\n style(elm, { display: 'none' });\r\n};\r\n\r\n/**\r\n * Shows the passed element (display: block).\r\n * @param elm The element which shall be shown.\r\n */\r\nexport const show = (elm: HTMLElement | false | null | undefined): void => {\r\n style(elm, { display: 'block' });\r\n};\r\n\r\n/**\r\n * Returns the top right bottom left values of the passed css property.\r\n * @param elm The element of which the values shall be returned.\r\n * @param propertyPrefix The css property prefix. (e.g. \"border\")\r\n * @param propertySuffix The css property suffix. (e.g. \"width\")\r\n */\r\nexport const topRightBottomLeft = (\r\n elm?: HTMLElement | false | null | undefined,\r\n propertyPrefix?: string,\r\n propertySuffix?: string\r\n): TRBL => {\r\n const finalPrefix = propertyPrefix ? `${propertyPrefix}-` : '';\r\n const finalSuffix = propertySuffix ? `-${propertySuffix}` : '';\r\n const top = `${finalPrefix}top${finalSuffix}`;\r\n const right = `${finalPrefix}right${finalSuffix}`;\r\n const bottom = `${finalPrefix}bottom${finalSuffix}`;\r\n const left = `${finalPrefix}left${finalSuffix}`;\r\n const result = style(elm, [top, right, bottom, left]);\r\n return {\r\n t: parseToZeroOrNumber(result[top]),\r\n r: parseToZeroOrNumber(result[right]),\r\n b: parseToZeroOrNumber(result[bottom]),\r\n l: parseToZeroOrNumber(result[left]),\r\n };\r\n};\r\n","import { style } from 'support/dom/style';\r\n\r\nexport interface WH {\r\n w: T;\r\n h: T;\r\n}\r\n\r\nconst elementHasDimensions = (elm: HTMLElement): boolean =>\r\n !!(elm.offsetWidth || elm.offsetHeight || elm.getClientRects().length);\r\nconst zeroObj: WH = {\r\n w: 0,\r\n h: 0,\r\n};\r\n\r\n/**\r\n * Returns the window inner- width and height.\r\n */\r\nexport const windowSize = (): WH => ({\r\n w: window.innerWidth,\r\n h: window.innerHeight,\r\n});\r\n\r\n/**\r\n * Returns the scroll- width and height of the passed element. If the element is null the width and height values are 0.\r\n * @param elm The element of which the scroll- width and height shall be returned.\r\n */\r\nexport const offsetSize = (elm: HTMLElement | null | undefined): WH =>\r\n elm\r\n ? {\r\n w: elm.offsetWidth,\r\n h: elm.offsetHeight,\r\n }\r\n : zeroObj;\r\n\r\n/**\r\n * Returns the client- width and height of the passed element. If the element is null the width and height values are 0.\r\n * @param elm The element of which the client- width and height shall be returned.\r\n */\r\nexport const clientSize = (elm: HTMLElement | false | null | undefined): WH =>\r\n elm\r\n ? {\r\n w: elm.clientWidth,\r\n h: elm.clientHeight,\r\n }\r\n : zeroObj;\r\n\r\n/**\r\n * Returns the client- width and height of the passed element. If the element is null the width and height values are 0.\r\n * @param elm The element of which the client- width and height shall be returned.\r\n */\r\nexport const scrollSize = (elm: HTMLElement | false | null | undefined): WH =>\r\n elm\r\n ? {\r\n w: elm.scrollWidth,\r\n h: elm.scrollHeight,\r\n }\r\n : zeroObj;\r\n\r\n/**\r\n * Returns the fractional- width and height of the passed element. If the element is null the width and height values are 0.\r\n * @param elm The element of which the fractional- width and height shall be returned.\r\n */\r\nexport const fractionalSize = (elm: HTMLElement | false | null | undefined): WH => {\r\n const cssHeight = parseFloat(style(elm, 'height')) || 0;\r\n const cssWidth = parseFloat(style(elm, 'height')) || 0;\r\n return {\r\n w: cssWidth - Math.round(cssWidth),\r\n h: cssHeight - Math.round(cssHeight),\r\n };\r\n};\r\n\r\n/**\r\n * Returns the BoundingClientRect of the passed element.\r\n * @param elm The element of which the BoundingClientRect shall be returned.\r\n */\r\nexport const getBoundingClientRect = (elm: HTMLElement): DOMRect => elm.getBoundingClientRect();\r\n\r\n/**\r\n * Determines whether the passed element has any dimensions.\r\n * @param elm The element.\r\n */\r\nexport const hasDimensions = (elm: HTMLElement | false | null | undefined): boolean =>\r\n elm ? elementHasDimensions(elm as HTMLElement) : false;\r\n","import { isUndefined } from 'support/utils/types';\r\nimport { each, push, runEach } from 'support/utils/array';\r\n\r\nlet passiveEventsSupport: boolean;\r\nconst supportPassiveEvents = (): boolean => {\r\n if (isUndefined(passiveEventsSupport)) {\r\n passiveEventsSupport = false;\r\n try {\r\n /* eslint-disable */\r\n // @ts-ignore\r\n window.addEventListener(\r\n 'test',\r\n null,\r\n Object.defineProperty({}, 'passive', {\r\n get: function () {\r\n passiveEventsSupport = true;\r\n },\r\n })\r\n );\r\n /* eslint-enable */\r\n } catch (e) {}\r\n }\r\n return passiveEventsSupport;\r\n};\r\nconst splitEventNames = (eventNames: string) => eventNames.split(' ');\r\n\r\nexport interface OnOptions {\r\n _capture?: boolean;\r\n _passive?: boolean;\r\n _once?: boolean;\r\n}\r\n\r\n/**\r\n * Removes the passed event listener for the passed events with the passed options.\r\n * @param target The element from which the listener shall be removed.\r\n * @param eventNames The eventsnames for which the listener shall be removed.\r\n * @param listener The listener which shall be removed.\r\n * @param capture The options of the removed listener.\r\n */\r\nexport const off = (\r\n target: EventTarget,\r\n eventNames: string,\r\n listener: (event: T) => any,\r\n capture?: boolean\r\n): void => {\r\n each(splitEventNames(eventNames), (eventName) => {\r\n target.removeEventListener(eventName, listener as EventListener, capture);\r\n });\r\n};\r\n\r\n/**\r\n * Adds the passed event listener for the passed eventnames with the passed options.\r\n * @param target The element to which the listener shall be added.\r\n * @param eventNames The eventsnames for which the listener shall be called.\r\n * @param listener The listener which is called on the eventnames.\r\n * @param options The options of the added listener.\r\n */\r\nexport const on = (\r\n target: EventTarget,\r\n eventNames: string,\r\n listener: (event: T) => any,\r\n options?: OnOptions\r\n): (() => void) => {\r\n const doSupportPassiveEvents = supportPassiveEvents();\r\n const passive = (doSupportPassiveEvents && options && options._passive) || false;\r\n const capture = (options && options._capture) || false;\r\n const once = (options && options._once) || false;\r\n const offListeners: (() => void)[] = [];\r\n const nativeOptions: AddEventListenerOptions | boolean = doSupportPassiveEvents\r\n ? {\r\n passive,\r\n capture,\r\n }\r\n : capture;\r\n\r\n each(splitEventNames(eventNames), (eventName) => {\r\n const finalListener = (once\r\n ? (evt: T) => {\r\n target.removeEventListener(eventName, finalListener, capture);\r\n listener && listener(evt);\r\n }\r\n : listener) as EventListener;\r\n\r\n push(offListeners, off.bind(null, target, eventName, finalListener, capture));\r\n target.addEventListener(eventName, finalListener, nativeOptions);\r\n });\r\n\r\n return runEach.bind(0, offListeners);\r\n};\r\n\r\n/**\r\n * Shorthand for the stopPropagation event Method.\r\n * @param evt The event of which the stopPropagation method shall be called.\r\n */\r\nexport const stopPropagation = (evt: Event): void => evt.stopPropagation();\r\n\r\n/**\r\n * Shorthand for the preventDefault event Method.\r\n * @param evt The event of which the preventDefault method shall be called.\r\n */\r\nexport const preventDefault = (evt: Event): void => evt.preventDefault();\r\n\r\n/**\r\n * Shorthand for the stopPropagation and preventDefault event Method.\r\n * @param evt The event of which the stopPropagation and preventDefault methods shall be called.\r\n */\r\nexport const stopAndPrevent = (evt: Event): void =>\r\n (stopPropagation(evt) as undefined) || (preventDefault(evt) as undefined);\r\n","import { getBoundingClientRect } from 'support/dom/dimensions';\r\n\r\nexport interface XY {\r\n x: T;\r\n y: T;\r\n}\r\n\r\nconst zeroObj: XY = {\r\n x: 0,\r\n y: 0,\r\n};\r\n\r\n/**\r\n * Returns the offset- left and top coordinates of the passed element relative to the document. If the element is null the top and left values are 0.\r\n * @param elm The element of which the offset- top and left coordinates shall be returned.\r\n */\r\nexport const absoluteCoordinates = (elm: HTMLElement | null | undefined): XY => {\r\n const rect = elm ? getBoundingClientRect(elm) : 0;\r\n return rect\r\n ? {\r\n x: rect.left + window.pageYOffset,\r\n y: rect.top + window.pageXOffset,\r\n }\r\n : zeroObj;\r\n};\r\n\r\n/**\r\n * Returns the offset- left and top coordinates of the passed element. If the element is null the top and left values are 0.\r\n * @param elm The element of which the offset- top and left coordinates shall be returned.\r\n */\r\nexport const offsetCoordinates = (elm: HTMLElement | null | undefined): XY =>\r\n elm\r\n ? {\r\n x: elm.offsetLeft,\r\n y: elm.offsetTop,\r\n }\r\n : zeroObj;\r\n","import { isArray } from 'support/utils/types';\r\nimport { keys } from 'support/utils/object';\r\nimport { each, from } from 'support/utils/array';\r\n\r\nexport type EventListener<\r\n NameArgsMap extends Record,\r\n Name extends Extract = Extract\r\n> = (...args: NameArgsMap[Name] extends undefined ? [] : [args: NameArgsMap[Name]]) => void;\r\n\r\nexport type EventListenerGroup<\r\n NameArgsMap extends Record,\r\n Name extends Extract = Extract\r\n> = EventListener | EventListener[];\r\n\r\nexport type AddEventListener> = <\r\n Name extends Extract\r\n>(\r\n name: Name,\r\n listener: EventListenerGroup\r\n) => () => void;\r\n\r\nexport type RemoveEventListener> = <\r\n Name extends Extract\r\n>(\r\n name?: Name,\r\n listener?: EventListenerGroup\r\n) => void;\r\n\r\nexport type TriggerEventListener> = <\r\n Name extends Extract\r\n>(\r\n name: Name,\r\n ...args: NameArgsMap[Name] extends undefined ? [] : [args: NameArgsMap[Name]]\r\n) => void;\r\n\r\nexport type InitialEventListeners> = {\r\n [K in Extract]?: EventListenerGroup;\r\n};\r\n\r\nconst manageListener = >(\r\n callback: (listener?: EventListener) => void,\r\n listener?: EventListener | EventListener[]\r\n) => {\r\n each(isArray(listener) ? listener : [listener], callback);\r\n};\r\n\r\nexport const createEventListenerHub = >(\r\n initialEventListeners?: InitialEventListeners\r\n): [\r\n AddEventListener,\r\n RemoveEventListener,\r\n TriggerEventListener\r\n] => {\r\n const events = new Map, Set>>();\r\n const removeEvent: RemoveEventListener = (name?, listener?) => {\r\n if (name) {\r\n const eventSet = events.get(name);\r\n manageListener((currListener) => {\r\n if (eventSet) {\r\n eventSet[currListener ? 'delete' : 'clear'](currListener!);\r\n }\r\n }, listener as EventListenerGroup | undefined);\r\n } else {\r\n events.forEach((eventSet) => {\r\n eventSet.clear();\r\n });\r\n events.clear();\r\n }\r\n };\r\n const addEvent: AddEventListener = (name, listener) => {\r\n const eventSet = events.get(name) || new Set();\r\n events.set(name, eventSet);\r\n\r\n manageListener((currListener) => {\r\n currListener && eventSet.add(currListener);\r\n }, listener as EventListenerGroup);\r\n\r\n return removeEvent.bind(0, name as any, listener as EventListenerGroup);\r\n };\r\n const triggerEvent: TriggerEventListener = (name, args?) => {\r\n const eventSet = events.get(name);\r\n\r\n each(from(eventSet), (event) => {\r\n if (args) {\r\n (event as (args: NameArgsMap[Extract]) => void)(args as any);\r\n } else {\r\n (event as () => void)();\r\n }\r\n });\r\n };\r\n\r\n const initialListenerKeys = keys(initialEventListeners) as Extract[];\r\n each(initialListenerKeys, (key) => {\r\n addEvent(key, initialEventListeners![key] as any);\r\n });\r\n\r\n return [addEvent, removeEvent, triggerEvent];\r\n};\r\n","import { assignDeep, hasOwnProperty } from 'support';\r\nimport type { OSOptions, ReadonlyOSOptions } from 'options';\r\nimport type { PartialOptions } from 'typings';\r\n\r\nexport type SetupElements> = [elements: T, destroy: () => void];\r\n\r\nexport type SetupUpdate = (\r\n changedOptions: PartialOptions,\r\n force?: boolean\r\n) => T;\r\n\r\nexport type SetupUpdateCheckOption = (path: string) => [value: T, changed: boolean];\r\n\r\nexport type SetupUpdateSegment> = (\r\n updateHints: Hints,\r\n checkOption: SetupUpdateCheckOption,\r\n force: boolean\r\n) => Partial | void;\r\n\r\nexport type SetupState> = [\r\n get: () => T,\r\n set: (newState: Partial) => void\r\n];\r\n\r\nexport type Setup = Record> = [\r\n update: SetupUpdate,\r\n state: (() => DynamicState) & StaticState,\r\n destroy: () => void\r\n];\r\n\r\nconst getPropByPath = (obj: any, path: string): T =>\r\n obj\r\n ? path.split('.').reduce((o, prop) => (o && hasOwnProperty(o, prop) ? o[prop] : undefined), obj)\r\n : undefined;\r\n\r\nexport const createOptionCheck =\r\n (\r\n options: ReadonlyOSOptions,\r\n changedOptions: PartialOptions,\r\n force?: boolean\r\n ): SetupUpdateCheckOption =>\r\n (path: string) =>\r\n [getPropByPath(options, path), force || getPropByPath(changedOptions, path) !== undefined];\r\n\r\nexport const createState = (initialState: S): SetupState => {\r\n let state: S = initialState;\r\n return [\r\n () => state,\r\n (newState: Partial) => {\r\n state = assignDeep({}, state, newState);\r\n },\r\n ];\r\n};\r\n","export const classNameEnvironment = 'os-environment';\r\nexport const classNameEnvironmentFlexboxGlue = `${classNameEnvironment}-flexbox-glue`;\r\nexport const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`;\r\n\r\nexport const dataAttributeHost = 'data-overlayscrollbars';\r\nexport const classNamePadding = 'os-padding';\r\nexport const classNameViewport = 'os-viewport';\r\nexport const classNameViewportArrange = `${classNameViewport}-arrange`;\r\nexport const classNameContent = 'os-content';\r\nexport const classNameViewportScrollbarStyling = `${classNameViewport}-scrollbar-styled`;\r\nexport const classNameOverflowVisible = `os-overflow-visible`;\r\n\r\nexport const classNameSizeObserver = 'os-size-observer';\r\nexport const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;\r\nexport const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;\r\nexport const classNameSizeObserverListenerScroll = `${classNameSizeObserverListener}-scroll`;\r\nexport const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;\r\nexport const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;\r\n\r\nexport const classNameTrinsicObserver = 'os-trinsic-observer';\r\n\r\nexport const classNameScrollbar = 'os-scrollbar';\r\nexport const classNameScrollbarHorizontal = `${classNameScrollbar}-horizontal`;\r\nexport const classNameScrollbarVertical = `${classNameScrollbar}-vertical`;\r\nexport const classNameScrollbarTrack = 'os-scrollbar-track';\r\nexport const classNameScrollbarHandle = 'os-scrollbar-handle';\r\n","import { assignDeep, each, isObject, keys, isArray, hasOwnProperty, isFunction } from 'support';\r\nimport { PartialOptions, ReadonlyOptions } from 'typings';\r\n\r\nconst stringify = (value: any) =>\r\n JSON.stringify(value, (_, val) => {\r\n if (isFunction(val)) {\r\n throw new Error();\r\n }\r\n return val;\r\n });\r\n\r\nexport type ResizeBehavior = 'none' | 'both' | 'horizontal' | 'vertical';\r\n\r\nexport type OverflowBehavior =\r\n | 'hidden'\r\n | 'scroll'\r\n | 'visible'\r\n | 'visible-hidden'\r\n | 'visible-scroll';\r\n\r\nexport type VisibilityBehavior = 'visible' | 'hidden' | 'auto';\r\n\r\nexport type AutoHideBehavior = 'never' | 'scroll' | 'leave' | 'move';\r\n\r\nexport type ScrollBehavior = 'always' | 'ifneeded' | 'never';\r\n\r\nexport type BasicEventCallback = (this: any) => void;\r\n\r\nexport type ScrollEventCallback = (this: any, args?: UIEvent) => void;\r\n\r\nexport type OverflowChangedCallback = (this: any, args?: OverflowChangedArgs) => void;\r\n\r\nexport type OverflowAmountChangedCallback = (this: any, args?: OverflowAmountChangedArgs) => void;\r\n\r\nexport type DirectionChangedCallback = (this: any, args?: DirectionChangedArgs) => void;\r\n\r\nexport type SizeChangedCallback = (this: any, args?: SizeChangedArgs) => void;\r\n\r\nexport type UpdatedCallback = (this: any, args?: UpdatedArgs) => void;\r\n\r\nexport interface OSOptions {\r\n resize: ResizeBehavior;\r\n paddingAbsolute: boolean;\r\n updating: {\r\n elementEvents: Array<[string, string]> | null;\r\n attributes: string[] | null;\r\n debounce: number | [number, number] | null;\r\n };\r\n overflow: {\r\n x: OverflowBehavior;\r\n y: OverflowBehavior;\r\n };\r\n scrollbars: {\r\n visibility: VisibilityBehavior;\r\n autoHide: AutoHideBehavior;\r\n autoHideDelay: number;\r\n dragScroll: boolean;\r\n clickScroll: boolean;\r\n touch: boolean;\r\n };\r\n textarea: {\r\n dynWidth: boolean;\r\n dynHeight: boolean;\r\n inheritedAttrs: string | Array | null;\r\n };\r\n nativeScrollbarsOverlaid: {\r\n show: boolean;\r\n initialize: boolean;\r\n };\r\n callbacks: {\r\n onUpdated: (() => any) | null;\r\n };\r\n /*\r\n callbacks?: {\r\n onInitialized?: BasicEventCallback | null;\r\n onInitializationWithdrawn?: BasicEventCallback | null;\r\n onDestroyed?: BasicEventCallback | null;\r\n onScrollStart?: ScrollEventCallback | null;\r\n onScroll?: ScrollEventCallback | null;\r\n onScrollStop?: ScrollEventCallback | null;\r\n onOverflowChanged?: OverflowChangedCallback | null;\r\n onOverflowAmountChanged?: OverflowAmountChangedCallback | null;\r\n onDirectionChanged?: DirectionChangedCallback | null;\r\n onContentSizeChanged?: SizeChangedCallback | null;\r\n onHostSizeChanged?: SizeChangedCallback | null;\r\n onUpdated?: UpdatedCallback | null;\r\n };\r\n */\r\n}\r\n\r\nexport type ReadonlyOSOptions = ReadonlyOptions;\r\n\r\nexport interface OverflowChangedArgs {\r\n x: boolean;\r\n y: boolean;\r\n xScrollable: boolean;\r\n yScrollable: boolean;\r\n clipped: boolean;\r\n}\r\n\r\nexport interface OverflowAmountChangedArgs {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport interface DirectionChangedArgs {\r\n isRTL: number;\r\n dir: string;\r\n}\r\n\r\nexport interface SizeChangedArgs {\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface UpdatedArgs {\r\n forced: boolean;\r\n}\r\n\r\nexport const defaultOptions: OSOptions = {\r\n resize: 'none', // none || both || horizontal || vertical || n || b || h || v\r\n paddingAbsolute: false, // true || false\r\n updating: {\r\n elementEvents: [['img', 'load']], // array of tuples || null\r\n attributes: null,\r\n debounce: [0, 33], // number || number array || null\r\n },\r\n overflow: {\r\n x: 'scroll', // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s\r\n y: 'scroll', // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s\r\n },\r\n scrollbars: {\r\n visibility: 'auto', // visible || hidden || auto || v || h || a\r\n autoHide: 'never', // never || scroll || leave || move || n || s || l || m\r\n autoHideDelay: 800, // number\r\n dragScroll: true, // true || false\r\n clickScroll: false, // true || false\r\n touch: true, // true || false\r\n },\r\n textarea: {\r\n dynWidth: false, // true || false\r\n dynHeight: false, // true || false\r\n inheritedAttrs: ['style', 'class'], // string || array || null\r\n },\r\n nativeScrollbarsOverlaid: {\r\n show: false, // true || false\r\n initialize: false, // true || false\r\n },\r\n callbacks: {\r\n onUpdated: null,\r\n },\r\n};\r\n\r\nexport const getOptionsDiff = (\r\n currOptions: T,\r\n newOptions: PartialOptions\r\n): PartialOptions => {\r\n const diff: PartialOptions = {};\r\n const optionsKeys = keys(newOptions).concat(keys(currOptions));\r\n\r\n each(optionsKeys, (optionKey) => {\r\n const currOptionValue = currOptions[optionKey];\r\n const newOptionValue = newOptions[optionKey];\r\n\r\n if (isObject(currOptionValue) && isObject(newOptionValue)) {\r\n assignDeep((diff[optionKey] = {}), getOptionsDiff(currOptionValue, newOptionValue));\r\n } else if (hasOwnProperty(newOptions, optionKey) && newOptionValue !== currOptionValue) {\r\n let isDiff = true;\r\n\r\n if (isArray(currOptionValue) || isArray(newOptionValue)) {\r\n try {\r\n if (stringify(currOptionValue) === stringify(newOptionValue)) {\r\n isDiff = false;\r\n }\r\n } catch {}\r\n }\r\n\r\n if (isDiff) {\r\n diff[optionKey] = newOptionValue;\r\n }\r\n }\r\n });\r\n\r\n return diff;\r\n};\r\n","import {\r\n createDOM,\r\n addClass,\r\n style,\r\n appendChildren,\r\n fractionalSize,\r\n clientSize,\r\n absoluteCoordinates,\r\n offsetSize,\r\n scrollLeft,\r\n XY,\r\n removeAttr,\r\n removeElements,\r\n windowSize,\r\n runEach,\r\n equalBCRWH,\r\n getBoundingClientRect,\r\n assignDeep,\r\n cssProperty,\r\n createCache,\r\n equalXY,\r\n} from 'support';\r\nimport {\r\n classNameEnvironment,\r\n classNameEnvironmentFlexboxGlue,\r\n classNameEnvironmentFlexboxGlueMax,\r\n classNameViewportScrollbarStyling,\r\n} from 'classnames';\r\nimport { OSOptions, defaultOptions } from 'options';\r\nimport { OSTargetElement, PartialOptions } from 'typings';\r\n\r\ntype StructureInitializationStrategyElementFn =\r\n | ((target: OSTargetElement) => HTMLElement | T)\r\n | T;\r\n\r\ntype ScrollbarsInitializationStrategyElementFn =\r\n | ((target: OSTargetElement, host: HTMLElement, viewport: HTMLElement) => HTMLElement | T)\r\n | T;\r\n\r\n/**\r\n * A Static element is an element which MUST be generated.\r\n * If null or undefined (or the returned result is null or undefined), the initialization function is generatig the element, otherwise\r\n * the element returned by the function acts as the generated element.\r\n */\r\nexport type StructureInitializationStrategyStaticElement = StructureInitializationStrategyElementFn<\r\n null | undefined\r\n>;\r\n\r\n/**\r\n * A Dynamic element is an element which CAN be generated.\r\n * If boolean (or the returned result is boolean), the generation of the element is forced (or not).\r\n * If the function returns and element, the element returned by the function acts as the generated element.\r\n */\r\nexport type StructureInitializationStrategyDynamicElement =\r\n StructureInitializationStrategyElementFn;\r\n\r\nexport interface StructureInitializationStrategy {\r\n _host: StructureInitializationStrategyStaticElement;\r\n _viewport: StructureInitializationStrategyStaticElement;\r\n _padding: StructureInitializationStrategyDynamicElement;\r\n _content: StructureInitializationStrategyDynamicElement;\r\n}\r\n\r\nexport interface ScrollbarsInitializationStrategy {\r\n /**\r\n * The scrollbars slot. If null or undefined (or the returned result is null or undefined), the initialization function is deciding the element, otherwise\r\n * the element returned by the function acts as the scrollbars slot.\r\n */\r\n _scrollbarsSlot: ScrollbarsInitializationStrategyElementFn;\r\n}\r\n\r\nexport interface InitializationStrategy\r\n extends StructureInitializationStrategy,\r\n ScrollbarsInitializationStrategy {}\r\n\r\nexport type DefaultInitializationStrategy = {\r\n [K in keyof InitializationStrategy]: Extract<\r\n InitializationStrategy[K],\r\n boolean | null | undefined\r\n >;\r\n};\r\n\r\nexport type OnEnvironmentChanged = (env: Environment) => void;\r\nexport interface Environment {\r\n readonly _nativeScrollbarSize: XY;\r\n readonly _nativeScrollbarIsOverlaid: XY;\r\n readonly _nativeScrollbarStyling: boolean;\r\n readonly _rtlScrollBehavior: { n: boolean; i: boolean };\r\n readonly _flexboxGlue: boolean;\r\n readonly _cssCustomProperties: boolean;\r\n readonly _defaultInitializationStrategy: DefaultInitializationStrategy;\r\n readonly _defaultDefaultOptions: OSOptions;\r\n _addListener(listener: OnEnvironmentChanged): () => void;\r\n _getInitializationStrategy(): InitializationStrategy;\r\n _setInitializationStrategy(newInitializationStrategy: Partial): void;\r\n _getDefaultOptions(): OSOptions;\r\n _setDefaultOptions(newDefaultOptions: PartialOptions): void;\r\n}\r\n\r\nlet environmentInstance: Environment;\r\nconst { abs, round } = Math;\r\n\r\nconst diffBiggerThanOne = (valOne: number, valTwo: number): boolean => {\r\n const absValOne = abs(valOne);\r\n const absValTwo = abs(valTwo);\r\n return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);\r\n};\r\n\r\nconst getNativeScrollbarSize = (\r\n body: HTMLElement,\r\n measureElm: HTMLElement,\r\n measureElmChild: HTMLElement\r\n): XY => {\r\n appendChildren(body, measureElm);\r\n\r\n const cSize = clientSize(measureElm);\r\n const oSize = offsetSize(measureElm);\r\n const fSize = fractionalSize(measureElmChild);\r\n\r\n return {\r\n x: oSize.h - cSize.h + fSize.h,\r\n y: oSize.w - cSize.w + fSize.w,\r\n };\r\n};\r\n\r\nconst getNativeScrollbarStyling = (testElm: HTMLElement): boolean => {\r\n let result = false;\r\n const revertClass = addClass(testElm, classNameViewportScrollbarStyling);\r\n try {\r\n result =\r\n style(testElm, cssProperty('scrollbar-width')) === 'none' ||\r\n window.getComputedStyle(testElm, '::-webkit-scrollbar').getPropertyValue('display') ===\r\n 'none';\r\n } catch (ex) {}\r\n revertClass();\r\n return result;\r\n};\r\n\r\nconst getRtlScrollBehavior = (\r\n parentElm: HTMLElement,\r\n childElm: HTMLElement\r\n): { i: boolean; n: boolean } => {\r\n const strHidden = 'hidden';\r\n style(parentElm, { overflowX: strHidden, overflowY: strHidden, direction: 'rtl' });\r\n scrollLeft(parentElm, 0);\r\n\r\n const parentOffset = absoluteCoordinates(parentElm);\r\n const childOffset = absoluteCoordinates(childElm);\r\n scrollLeft(parentElm, -999); // https://github.com/KingSora/OverlayScrollbars/issues/187\r\n const childOffsetAfterScroll = absoluteCoordinates(childElm);\r\n return {\r\n /**\r\n * origin direction = determines if the zero scroll position is on the left or right side\r\n * 'i' means 'invert' (i === true means that the axis must be inverted to be correct)\r\n * true = on the left side\r\n * false = on the right side\r\n */\r\n i: parentOffset.x === childOffset.x,\r\n /**\r\n * negative = determines if the maximum scroll is positive or negative\r\n * 'n' means 'negate' (n === true means that the axis must be negated to be correct)\r\n * true = negative\r\n * false = positive\r\n */\r\n n: childOffset.x !== childOffsetAfterScroll.x,\r\n };\r\n};\r\n\r\nconst getFlexboxGlue = (parentElm: HTMLElement, childElm: HTMLElement): boolean => {\r\n const revertFbxGlue = addClass(parentElm, classNameEnvironmentFlexboxGlue);\r\n const minOffsetsizeParent = getBoundingClientRect(parentElm);\r\n const minOffsetsize = getBoundingClientRect(childElm);\r\n const supportsMin = equalBCRWH(minOffsetsize, minOffsetsizeParent, true);\r\n\r\n const revertFbxGlueMax = addClass(parentElm, classNameEnvironmentFlexboxGlueMax);\r\n const maxOffsetsizeParent = getBoundingClientRect(parentElm);\r\n const maxOffsetsize = getBoundingClientRect(childElm);\r\n const supportsMax = equalBCRWH(maxOffsetsize, maxOffsetsizeParent, true);\r\n\r\n revertFbxGlue();\r\n revertFbxGlueMax();\r\n\r\n return supportsMin && supportsMax;\r\n};\r\n\r\nconst getWindowDPR = (): number => {\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n const dDPI = window.screen.deviceXDPI || 0;\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n const sDPI = window.screen.logicalXDPI || 1;\r\n return window.devicePixelRatio || dDPI / sDPI;\r\n};\r\n\r\nconst getDefaultInitializationStrategy = (\r\n nativeScrollbarStyling: boolean\r\n): DefaultInitializationStrategy => ({\r\n _host: null,\r\n _viewport: null,\r\n _padding: !nativeScrollbarStyling,\r\n _content: false,\r\n _scrollbarsSlot: null,\r\n});\r\n\r\nconst createEnvironment = (): Environment => {\r\n const { body } = document;\r\n const envDOM = createDOM(``);\r\n const envElm = envDOM[0] as HTMLElement;\r\n const envChildElm = envElm.firstChild as HTMLElement;\r\n const onChangedListener: Set = new Set();\r\n const [updateNativeScrollbarSizeCache, getNativeScrollbarSizeCache] = createCache({\r\n _initialValue: getNativeScrollbarSize(body, envElm, envChildElm),\r\n _equal: equalXY,\r\n });\r\n const [nativeScrollbarSize] = getNativeScrollbarSizeCache();\r\n const nativeScrollbarStyling = getNativeScrollbarStyling(envElm);\r\n const nativeScrollbarIsOverlaid = {\r\n x: nativeScrollbarSize.x === 0,\r\n y: nativeScrollbarSize.y === 0,\r\n };\r\n const initializationStrategy = getDefaultInitializationStrategy(nativeScrollbarStyling);\r\n const defaultDefaultOptions = assignDeep({}, defaultOptions);\r\n\r\n const env: Environment = {\r\n _nativeScrollbarSize: nativeScrollbarSize,\r\n _nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,\r\n _nativeScrollbarStyling: nativeScrollbarStyling,\r\n _cssCustomProperties: style(envElm, 'zIndex') === '-1',\r\n _rtlScrollBehavior: getRtlScrollBehavior(envElm, envChildElm),\r\n _flexboxGlue: getFlexboxGlue(envElm, envChildElm),\r\n _addListener(listener) {\r\n onChangedListener.add(listener);\r\n return () => onChangedListener.delete(listener);\r\n },\r\n _getInitializationStrategy: assignDeep.bind(\r\n 0,\r\n {} as InitializationStrategy,\r\n initializationStrategy\r\n ),\r\n _setInitializationStrategy(newInitializationStrategy) {\r\n assignDeep(initializationStrategy, newInitializationStrategy);\r\n },\r\n _getDefaultOptions: assignDeep.bind(\r\n 0,\r\n {} as OSOptions,\r\n defaultDefaultOptions\r\n ),\r\n _setDefaultOptions(newDefaultOptions) {\r\n assignDeep(defaultDefaultOptions, newDefaultOptions);\r\n },\r\n _defaultInitializationStrategy: assignDeep({}, initializationStrategy),\r\n _defaultDefaultOptions: assignDeep({}, defaultDefaultOptions),\r\n };\r\n\r\n removeAttr(envElm, 'style');\r\n removeElements(envElm);\r\n\r\n if (!nativeScrollbarStyling && (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y)) {\r\n let size = windowSize();\r\n let dpr = getWindowDPR();\r\n\r\n window.addEventListener('resize', () => {\r\n if (onChangedListener.size) {\r\n const sizeNew = windowSize();\r\n const deltaSize = {\r\n w: sizeNew.w - size.w,\r\n h: sizeNew.h - size.h,\r\n };\r\n\r\n if (deltaSize.w === 0 && deltaSize.h === 0) return;\r\n\r\n const deltaAbsSize = {\r\n w: abs(deltaSize.w),\r\n h: abs(deltaSize.h),\r\n };\r\n const deltaAbsRatio = {\r\n w: abs(round(sizeNew.w / (size.w / 100.0))),\r\n h: abs(round(sizeNew.h / (size.h / 100.0))),\r\n };\r\n const dprNew = getWindowDPR();\r\n const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;\r\n const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);\r\n const dprChanged = dprNew !== dpr && dpr > 0;\r\n const isZoom = deltaIsBigger && difference && dprChanged;\r\n\r\n if (isZoom) {\r\n const [scrollbarSize, scrollbarSizeChanged] = updateNativeScrollbarSizeCache(\r\n getNativeScrollbarSize(body, envElm, envChildElm)\r\n );\r\n\r\n assignDeep(environmentInstance._nativeScrollbarSize, scrollbarSize); // keep the object same!\r\n removeElements(envElm);\r\n\r\n if (scrollbarSizeChanged) {\r\n runEach(onChangedListener);\r\n }\r\n }\r\n\r\n size = sizeNew;\r\n dpr = dprNew;\r\n }\r\n });\r\n }\r\n\r\n return env;\r\n};\r\n\r\nexport const getEnvironment = (): Environment => {\r\n if (!environmentInstance) {\r\n environmentInstance = createEnvironment();\r\n }\r\n return environmentInstance;\r\n};\r\n","import {\r\n isHTMLElement,\r\n appendChildren,\r\n is,\r\n createDiv,\r\n contents,\r\n insertAfter,\r\n addClass,\r\n parent,\r\n indexOf,\r\n removeElements,\r\n removeClass,\r\n push,\r\n runEach,\r\n insertBefore,\r\n attr,\r\n isBoolean,\r\n isFunction,\r\n keys,\r\n removeAttr,\r\n} from 'support';\r\nimport {\r\n dataAttributeHost,\r\n classNamePadding,\r\n classNameViewport,\r\n classNameViewportArrange,\r\n classNameContent,\r\n classNameViewportScrollbarStyling,\r\n} from 'classnames';\r\nimport {\r\n getEnvironment,\r\n StructureInitializationStrategyStaticElement,\r\n StructureInitializationStrategyDynamicElement,\r\n} from 'environment';\r\nimport { OSTarget, OSTargetElement, StructureInitialization } from 'typings';\r\n\r\nexport type StructureSetupElements = [targetObj: StructureSetupElementsObj, destroy: () => void];\r\n\r\nexport interface StructureSetupElementsObj {\r\n _target: OSTargetElement;\r\n _host: HTMLElement;\r\n _viewport: HTMLElement;\r\n _padding: HTMLElement | false;\r\n _content: HTMLElement | false;\r\n _viewportArrange: HTMLStyleElement | false;\r\n // ctx ----\r\n _isTextarea: boolean;\r\n _isBody: boolean;\r\n _htmlElm: HTMLHtmlElement;\r\n _bodyElm: HTMLBodyElement;\r\n _windowElm: Window;\r\n _documentElm: Document;\r\n _targetIsElm: boolean;\r\n}\r\n\r\nlet contentArrangeCounter = 0;\r\n\r\nconst unwrap = (elm: HTMLElement | false | null | undefined) => {\r\n appendChildren(parent(elm), contents(elm));\r\n removeElements(elm);\r\n};\r\n\r\nconst createUniqueViewportArrangeElement = (): HTMLStyleElement | false => {\r\n const { _nativeScrollbarStyling, _nativeScrollbarIsOverlaid, _cssCustomProperties } =\r\n getEnvironment();\r\n /* istanbul ignore next */\r\n const create =\r\n !_cssCustomProperties &&\r\n !_nativeScrollbarStyling &&\r\n (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);\r\n const result = create ? document.createElement('style') : false;\r\n\r\n if (result) {\r\n attr(result, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`);\r\n contentArrangeCounter++;\r\n }\r\n\r\n return result;\r\n};\r\n\r\nconst staticCreationFromStrategy = (\r\n target: OSTargetElement,\r\n initializationValue: HTMLElement | undefined,\r\n strategy: StructureInitializationStrategyStaticElement\r\n): HTMLElement => {\r\n const result =\r\n initializationValue ||\r\n (isFunction(strategy) ? strategy(target) : (strategy as null | undefined));\r\n return result || createDiv();\r\n};\r\n\r\nconst dynamicCreationFromStrategy = (\r\n target: OSTargetElement,\r\n initializationValue: HTMLElement | boolean | undefined,\r\n strategy: StructureInitializationStrategyDynamicElement\r\n): HTMLElement | false => {\r\n const takeInitializationValue = isBoolean(initializationValue) || initializationValue;\r\n const result = takeInitializationValue\r\n ? (initializationValue as boolean | HTMLElement)\r\n : isFunction(strategy)\r\n ? strategy(target)\r\n : strategy;\r\n\r\n return result === true ? createDiv() : result;\r\n};\r\n\r\nconst addDataAttrHost = (elm: HTMLElement) => {\r\n attr(elm, dataAttributeHost, '');\r\n return removeAttr.bind(0, elm, dataAttributeHost);\r\n};\r\n\r\nexport const createStructureSetupElements = (target: OSTarget): StructureSetupElements => {\r\n const { _getInitializationStrategy, _nativeScrollbarStyling } = getEnvironment();\r\n const {\r\n _host: hostInitializationStrategy,\r\n _viewport: viewportInitializationStrategy,\r\n _padding: paddingInitializationStrategy,\r\n _content: contentInitializationStrategy,\r\n } = _getInitializationStrategy();\r\n const targetIsElm = isHTMLElement(target);\r\n const targetStructureInitialization = target as StructureInitialization;\r\n const targetElement = targetIsElm\r\n ? (target as OSTargetElement)\r\n : targetStructureInitialization.target;\r\n const isTextarea = is(targetElement, 'textarea');\r\n const isBody = !isTextarea && is(targetElement, 'body');\r\n const ownerDocument = targetElement!.ownerDocument;\r\n const bodyElm = ownerDocument.body as HTMLBodyElement;\r\n const wnd = ownerDocument.defaultView as Window;\r\n const evaluatedTargetObj: StructureSetupElementsObj = {\r\n _target: targetElement,\r\n _host: isTextarea\r\n ? staticCreationFromStrategy(\r\n targetElement,\r\n targetStructureInitialization.host,\r\n hostInitializationStrategy\r\n )\r\n : (targetElement as HTMLElement),\r\n _viewport: staticCreationFromStrategy(\r\n targetElement,\r\n targetStructureInitialization.viewport,\r\n viewportInitializationStrategy\r\n ),\r\n _padding: dynamicCreationFromStrategy(\r\n targetElement,\r\n targetStructureInitialization.padding,\r\n paddingInitializationStrategy\r\n ),\r\n _content: dynamicCreationFromStrategy(\r\n targetElement,\r\n targetStructureInitialization.content,\r\n contentInitializationStrategy\r\n ),\r\n _viewportArrange: createUniqueViewportArrangeElement(),\r\n _windowElm: wnd,\r\n _documentElm: ownerDocument,\r\n _htmlElm: parent(bodyElm) as HTMLHtmlElement,\r\n _bodyElm: bodyElm,\r\n _isTextarea: isTextarea,\r\n _isBody: isBody,\r\n _targetIsElm: targetIsElm,\r\n };\r\n const generatedElements = keys(evaluatedTargetObj).reduce((arr, key: string) => {\r\n const value = evaluatedTargetObj[key];\r\n return push(arr, value && !parent(value) ? value : false);\r\n }, [] as HTMLElement[]);\r\n const elementIsGenerated = (elm: HTMLElement | false) =>\r\n elm ? indexOf(generatedElements, elm) > -1 : null;\r\n const { _target, _host, _padding, _viewport, _content, _viewportArrange } = evaluatedTargetObj;\r\n const destroyFns: (() => any)[] = [];\r\n const isTextareaHostGenerated = isTextarea && elementIsGenerated(_host);\r\n const targetContents = isTextarea\r\n ? _target\r\n : contents(\r\n [_content, _viewport, _padding, _host, _target].find(\r\n (elm) => elementIsGenerated(elm) === false\r\n )\r\n );\r\n const contentSlot = _content || _viewport;\r\n const removeHostDataAttr = addDataAttrHost(_host);\r\n const removePaddingClass = addClass(_padding, classNamePadding);\r\n const removeViewportClass = addClass(_viewport, classNameViewport);\r\n const removeContentClass = addClass(_content, classNameContent);\r\n\r\n // only insert host for textarea after target if it was generated\r\n if (isTextareaHostGenerated) {\r\n insertAfter(_target, _host);\r\n\r\n push(destroyFns, () => {\r\n insertAfter(_host, _target);\r\n removeElements(_host);\r\n });\r\n }\r\n\r\n appendChildren(contentSlot, targetContents);\r\n appendChildren(_host, _padding);\r\n appendChildren(_padding || _host, _viewport);\r\n appendChildren(_viewport, _content);\r\n\r\n push(destroyFns, () => {\r\n if (targetIsElm) {\r\n appendChildren(_host, contents(contentSlot));\r\n removeElements(_padding || _viewport);\r\n removeHostDataAttr();\r\n } else {\r\n if (elementIsGenerated(_content)) {\r\n unwrap(_content);\r\n }\r\n if (elementIsGenerated(_viewport)) {\r\n unwrap(_viewport);\r\n }\r\n if (elementIsGenerated(_padding)) {\r\n unwrap(_padding);\r\n }\r\n removeHostDataAttr();\r\n removePaddingClass();\r\n removeViewportClass();\r\n removeContentClass();\r\n }\r\n });\r\n\r\n if (_nativeScrollbarStyling) {\r\n push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));\r\n }\r\n if (_viewportArrange) {\r\n insertBefore(_viewport, _viewportArrange);\r\n push(destroyFns, removeElements.bind(0, _viewportArrange));\r\n }\r\n\r\n return [evaluatedTargetObj, runEach.bind(0, destroyFns)];\r\n};\r\n","import { style } from 'support';\r\nimport type { CreateStructureUpdateSegment } from 'setups/structureSetup/structureSetup.update';\r\n\r\n/**\r\n * Lifecycle with the responsibility to adjust the trinsic behavior of the content element.\r\n * @param structureUpdateHub\r\n * @returns\r\n */\r\nexport const createTrinsicUpdate: CreateStructureUpdateSegment = (\r\n structureSetupElements,\r\n state\r\n) => {\r\n const { _content } = structureSetupElements;\r\n const [getState] = state;\r\n\r\n return (updateHints) => {\r\n const { _heightIntrinsic } = getState();\r\n const { _heightIntrinsicChanged } = updateHints;\r\n\r\n if (_heightIntrinsicChanged) {\r\n style(_content, {\r\n height: _heightIntrinsic ? '' : '100%',\r\n display: _heightIntrinsic ? '' : 'inline',\r\n });\r\n }\r\n\r\n return {\r\n _sizeChanged: _heightIntrinsicChanged,\r\n _contentMutation: _heightIntrinsicChanged,\r\n };\r\n };\r\n};\r\n","import { createCache, topRightBottomLeft, equalTRBL, style, assignDeep } from 'support';\r\nimport { StyleObject } from 'typings';\r\nimport { getEnvironment } from 'environment';\r\nimport type { CreateStructureUpdateSegment } from 'setups/structureSetup/structureSetup.update';\r\n\r\n/**\r\n * Lifecycle with the responsibility to adjust the padding styling of the padding and viewport element.\r\n * @param structureUpdateHub\r\n * @returns\r\n */\r\nexport const createPaddingUpdate: CreateStructureUpdateSegment = (\r\n structureSetupElements,\r\n state\r\n) => {\r\n const [getState, setState] = state;\r\n const { _host, _padding, _viewport } = structureSetupElements;\r\n const [updatePaddingCache, currentPaddingCache] = createCache(\r\n {\r\n _equal: equalTRBL,\r\n _initialValue: topRightBottomLeft(),\r\n },\r\n topRightBottomLeft.bind(0, _host, 'padding', '')\r\n );\r\n\r\n return (updateHints, checkOption, force) => {\r\n let [padding, paddingChanged] = currentPaddingCache(force);\r\n const { _nativeScrollbarStyling, _flexboxGlue } = getEnvironment();\r\n const { _directionIsRTL } = getState();\r\n const { _sizeChanged, _contentMutation, _directionChanged } = updateHints;\r\n const [paddingAbsolute, paddingAbsoluteChanged] = checkOption('paddingAbsolute');\r\n const contentMutation = !_flexboxGlue && _contentMutation;\r\n\r\n if (_sizeChanged || paddingChanged || contentMutation) {\r\n [padding, paddingChanged] = updatePaddingCache(force);\r\n }\r\n\r\n const paddingStyleChanged = paddingAbsoluteChanged || _directionChanged || paddingChanged;\r\n\r\n if (paddingStyleChanged) {\r\n // if there is no padding element and no scrollbar styling, paddingAbsolute isn't supported\r\n const paddingRelative = !paddingAbsolute || (!_padding && !_nativeScrollbarStyling);\r\n const paddingHorizontal = padding.r + padding.l;\r\n const paddingVertical = padding.t + padding.b;\r\n\r\n const paddingStyle: StyleObject = {\r\n marginRight: paddingRelative && !_directionIsRTL ? -paddingHorizontal : 0,\r\n marginBottom: paddingRelative ? -paddingVertical : 0,\r\n marginLeft: paddingRelative && _directionIsRTL ? -paddingHorizontal : 0,\r\n top: paddingRelative ? -padding.t : 0,\r\n right: paddingRelative ? (_directionIsRTL ? -padding.r : 'auto') : 0,\r\n left: paddingRelative ? (_directionIsRTL ? 'auto' : -padding.l) : 0,\r\n width: paddingRelative ? `calc(100% + ${paddingHorizontal}px)` : '',\r\n };\r\n const viewportStyle: StyleObject = {\r\n paddingTop: paddingRelative ? padding.t : 0,\r\n paddingRight: paddingRelative ? padding.r : 0,\r\n paddingBottom: paddingRelative ? padding.b : 0,\r\n paddingLeft: paddingRelative ? padding.l : 0,\r\n };\r\n\r\n // if there is no padding element apply the style to the viewport element instead\r\n style(_padding || _viewport, paddingStyle);\r\n style(_viewport, viewportStyle);\r\n\r\n setState({\r\n _padding: padding,\r\n _paddingAbsolute: !paddingRelative,\r\n _viewportPaddingStyle: _padding\r\n ? viewportStyle\r\n : assignDeep({}, paddingStyle, viewportStyle),\r\n });\r\n }\r\n\r\n return {\r\n _paddingStyleChanged: paddingStyleChanged,\r\n };\r\n };\r\n};\r\n","import {\r\n createCache,\r\n keys,\r\n attr,\r\n WH,\r\n XY,\r\n style,\r\n scrollSize,\r\n fractionalSize,\r\n equalWH,\r\n addClass,\r\n removeClass,\r\n clientSize,\r\n noop,\r\n each,\r\n equalXY,\r\n} from 'support';\r\nimport { getEnvironment } from 'environment';\r\nimport {\r\n classNameViewportArrange,\r\n classNameViewportScrollbarStyling,\r\n classNameOverflowVisible,\r\n dataAttributeHost,\r\n} from 'classnames';\r\nimport type { StyleObject } from 'typings';\r\nimport type { OverflowBehavior } from 'options';\r\nimport type { CreateStructureUpdateSegment } from 'setups/structureSetup/structureSetup.update';\r\n\r\ninterface ViewportOverflowState {\r\n _scrollbarsHideOffset: XY;\r\n _scrollbarsHideOffsetArrange: XY;\r\n _overflowScroll: XY;\r\n}\r\n\r\ntype UndoViewportArrangeResult = [\r\n redoViewportArrange: () => void,\r\n overflowState?: ViewportOverflowState\r\n];\r\n\r\nconst { max } = Math;\r\nconst strVisible = 'visible';\r\nconst overlaidScrollbarsHideOffset = 42;\r\nconst whCacheOptions = {\r\n _equal: equalWH,\r\n _initialValue: { w: 0, h: 0 },\r\n};\r\nconst xyCacheOptions = {\r\n _equal: equalXY,\r\n _initialValue: { x: false, y: false },\r\n};\r\n\r\nconst getOverflowAmount = (\r\n viewportScrollSize: WH,\r\n viewportClientSize: WH,\r\n sizeFraction: WH\r\n) => {\r\n const tollerance = window.devicePixelRatio % 1 !== 0 ? 1 : 0;\r\n const amount = {\r\n w: max(0, viewportScrollSize.w - viewportClientSize.w - max(0, sizeFraction.w)),\r\n h: max(0, viewportScrollSize.h - viewportClientSize.h - max(0, sizeFraction.h)),\r\n };\r\n\r\n return {\r\n w: amount.w > tollerance ? amount.w : 0,\r\n h: amount.h > tollerance ? amount.h : 0,\r\n };\r\n};\r\n\r\nconst conditionalClass = (\r\n elm: Element | false | null | undefined,\r\n classNames: string,\r\n condition: boolean\r\n) => (condition ? addClass(elm, classNames) : removeClass(elm, classNames));\r\n\r\nconst overflowIsVisible = (overflowBehavior: OverflowBehavior) =>\r\n overflowBehavior.indexOf(strVisible) === 0;\r\n\r\n/**\r\n * Lifecycle with the responsibility to set the correct overflow and scrollbar hiding styles of the viewport element.\r\n * @param structureUpdateHub\r\n * @returns\r\n */\r\nexport const createOverflowUpdate: CreateStructureUpdateSegment = (\r\n structureSetupElements,\r\n state\r\n) => {\r\n const [getState, setState] = state;\r\n const { _host, _padding, _viewport, _viewportArrange } = structureSetupElements;\r\n const {\r\n _nativeScrollbarSize,\r\n _flexboxGlue,\r\n _nativeScrollbarStyling,\r\n _nativeScrollbarIsOverlaid,\r\n } = getEnvironment();\r\n const doViewportArrange =\r\n !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);\r\n\r\n const [updateSizeFraction, getCurrentSizeFraction] = createCache>(\r\n whCacheOptions,\r\n fractionalSize.bind(0, _host)\r\n );\r\n\r\n const [updateViewportScrollSizeCache, getCurrentViewportScrollSizeCache] = createCache<\r\n WH\r\n >(whCacheOptions, scrollSize.bind(0, _viewport));\r\n\r\n const [updateOverflowAmountCache, getCurrentOverflowAmountCache] =\r\n createCache>(whCacheOptions);\r\n\r\n const [updateOverflowScrollCache] = createCache>(xyCacheOptions);\r\n\r\n /**\r\n * Applies a fixed height to the viewport so it can't overflow or underflow the host element.\r\n * @param viewportOverflowState The current overflow state.\r\n * @param heightIntrinsic Whether the host height is intrinsic or not.\r\n */\r\n const fixFlexboxGlue = (\r\n viewportOverflowState: ViewportOverflowState,\r\n heightIntrinsic: boolean\r\n ) => {\r\n style(_viewport, {\r\n height: '',\r\n });\r\n\r\n if (heightIntrinsic) {\r\n const { _paddingAbsolute, _padding: padding } = getState();\r\n const { _overflowScroll, _scrollbarsHideOffset } = viewportOverflowState;\r\n const fSize = fractionalSize(_host);\r\n const hostClientSize = clientSize(_host);\r\n\r\n // padding subtraction is only needed if padding is absolute or if viewport is content-box\r\n const isContentBox = style(_viewport, 'boxSizing') === 'content-box';\r\n const paddingVertical = _paddingAbsolute || isContentBox ? padding.b + padding.t : 0;\r\n const subtractXScrollbar = !(_nativeScrollbarIsOverlaid.x && isContentBox);\r\n\r\n style(_viewport, {\r\n height:\r\n hostClientSize.h +\r\n fSize.h +\r\n (_overflowScroll.x && subtractXScrollbar ? _scrollbarsHideOffset.x : 0) -\r\n paddingVertical,\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * Gets the current overflow state of the viewport.\r\n * @param showNativeOverlaidScrollbars Whether native overlaid scrollbars are shown instead of hidden.\r\n * @param viewportStyleObj The viewport style object where the overflow scroll property can be read of, or undefined if shall be determined.\r\n * @returns A object which contains informations about the current overflow state.\r\n */\r\n const getViewportOverflowState = (\r\n showNativeOverlaidScrollbars: boolean,\r\n viewportStyleObj?: StyleObject\r\n ): ViewportOverflowState => {\r\n const { x: overlaidX, y: overlaidY } = _nativeScrollbarIsOverlaid;\r\n const determineOverflow = !viewportStyleObj;\r\n const arrangeHideOffset =\r\n !_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;\r\n const styleObj = determineOverflow\r\n ? style(_viewport, ['overflowX', 'overflowY'])\r\n : viewportStyleObj;\r\n const scroll = {\r\n x: styleObj.overflowX === 'scroll',\r\n y: styleObj.overflowY === 'scroll',\r\n };\r\n const nonScrollbarStylingHideOffset = {\r\n x: overlaidX ? arrangeHideOffset : _nativeScrollbarSize.x,\r\n y: overlaidY ? arrangeHideOffset : _nativeScrollbarSize.y,\r\n };\r\n const scrollbarsHideOffset = {\r\n x: scroll.x && !_nativeScrollbarStyling ? nonScrollbarStylingHideOffset.x : 0,\r\n y: scroll.y && !_nativeScrollbarStyling ? nonScrollbarStylingHideOffset.y : 0,\r\n };\r\n\r\n return {\r\n _overflowScroll: scroll,\r\n _scrollbarsHideOffsetArrange: {\r\n x: overlaidX && !!arrangeHideOffset,\r\n y: overlaidY && !!arrangeHideOffset,\r\n },\r\n _scrollbarsHideOffset: scrollbarsHideOffset,\r\n };\r\n };\r\n\r\n /**\r\n * Sets the overflow property of the viewport and calculates the a overflow state according to the new parameters.\r\n * @param showNativeOverlaidScrollbars Whether to show natively overlaid scrollbars.\r\n * @param overflowAmount The overflow amount.\r\n * @param overflow The overflow behavior according to the options.\r\n * @param viewportStyleObj The viewport style object to which the overflow style shall be applied.\r\n * @returns A object which represents the newly set overflow state.\r\n */\r\n const setViewportOverflowState = (\r\n showNativeOverlaidScrollbars: boolean,\r\n hasOverflow: XY,\r\n overflowOption: XY,\r\n viewportStyleObj: StyleObject\r\n ): ViewportOverflowState => {\r\n const setAxisOverflowStyle = (behavior: OverflowBehavior, hasOverflowAxis: boolean) => {\r\n const overflowVisible = overflowIsVisible(behavior);\r\n return [\r\n hasOverflowAxis && !overflowVisible ? behavior : '',\r\n (hasOverflowAxis && overflowVisible && behavior.replace(`${strVisible}-`, '')) || '',\r\n ];\r\n };\r\n\r\n const [overflowX, visibleBehaviorX] = setAxisOverflowStyle(overflowOption.x, hasOverflow.x);\r\n const [overflowY, visibleBehaviorY] = setAxisOverflowStyle(overflowOption.y, hasOverflow.y);\r\n\r\n viewportStyleObj.overflowX = visibleBehaviorX && overflowY ? visibleBehaviorX : overflowX;\r\n viewportStyleObj.overflowY = visibleBehaviorY && overflowX ? visibleBehaviorY : overflowY;\r\n\r\n return getViewportOverflowState(showNativeOverlaidScrollbars, viewportStyleObj);\r\n };\r\n\r\n /**\r\n * Sets the styles of the viewport arrange element.\r\n * @param viewportOverflowState The viewport overflow state according to which the scrollbars shall be hidden.\r\n * @param viewportScrollSize The content scroll size.\r\n * @param directionIsRTL Whether the direction is RTL or not.\r\n * @returns A boolean which indicates whether the viewport arrange element was adjusted.\r\n */\r\n const arrangeViewport = (\r\n viewportOverflowState: ViewportOverflowState,\r\n viewportScrollSize: WH,\r\n sizeFraction: WH,\r\n directionIsRTL: boolean\r\n ) => {\r\n if (doViewportArrange) {\r\n const { _viewportPaddingStyle } = getState();\r\n const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;\r\n const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;\r\n const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;\r\n const viewportArrangeHorizontalPaddingKey: keyof StyleObject = directionIsRTL\r\n ? 'paddingRight'\r\n : 'paddingLeft';\r\n const viewportArrangeHorizontalPaddingValue = _viewportPaddingStyle[\r\n viewportArrangeHorizontalPaddingKey\r\n ] as number;\r\n const viewportArrangeVerticalPaddingValue = _viewportPaddingStyle.paddingTop as number;\r\n const fractionalContentWidth = viewportScrollSize.w + sizeFraction.w;\r\n const fractionalContenHeight = viewportScrollSize.h + sizeFraction.h;\r\n const arrangeSize = {\r\n w:\r\n hideOffsetY && arrangeY\r\n ? `${hideOffsetY + fractionalContentWidth - viewportArrangeHorizontalPaddingValue}px`\r\n : '',\r\n h:\r\n hideOffsetX && arrangeX\r\n ? `${hideOffsetX + fractionalContenHeight - viewportArrangeVerticalPaddingValue}px`\r\n : '',\r\n };\r\n\r\n // adjust content arrange / before element\r\n if (_viewportArrange) {\r\n const { sheet } = _viewportArrange;\r\n if (sheet) {\r\n const { cssRules } = sheet;\r\n if (cssRules) {\r\n if (!cssRules.length) {\r\n sheet.insertRule(\r\n `#${attr(_viewportArrange, 'id')} + .${classNameViewportArrange}::before {}`,\r\n 0\r\n );\r\n }\r\n\r\n // @ts-ignore\r\n const ruleStyle = cssRules[0].style;\r\n\r\n ruleStyle.width = arrangeSize.w;\r\n ruleStyle.height = arrangeSize.h;\r\n }\r\n }\r\n } else {\r\n style<'--os-vaw' | '--os-vah'>(_viewport, {\r\n '--os-vaw': arrangeSize.w,\r\n '--os-vah': arrangeSize.h,\r\n });\r\n }\r\n }\r\n\r\n return doViewportArrange;\r\n };\r\n\r\n /**\r\n * Hides the native scrollbars according to the passed parameters.\r\n * @param viewportOverflowState The viewport overflow state.\r\n * @param directionIsRTL Whether the direction is RTL or not.\r\n * @param viewportArrange Whether special styles related to the viewport arrange strategy shall be applied.\r\n * @param viewportStyleObj The viewport style object to which the needed styles shall be applied.\r\n */\r\n const hideNativeScrollbars = (\r\n viewportOverflowState: ViewportOverflowState,\r\n directionIsRTL: boolean,\r\n viewportArrange: boolean,\r\n viewportStyleObj: StyleObject\r\n ) => {\r\n const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;\r\n const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;\r\n const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;\r\n const { _viewportPaddingStyle: viewportPaddingStyle } = getState();\r\n const horizontalMarginKey: keyof StyleObject = directionIsRTL ? 'marginLeft' : 'marginRight';\r\n const viewportHorizontalPaddingKey: keyof StyleObject = directionIsRTL\r\n ? 'paddingLeft'\r\n : 'paddingRight';\r\n const horizontalMarginValue = viewportPaddingStyle[horizontalMarginKey] as number;\r\n const verticalMarginValue = viewportPaddingStyle.marginBottom as number;\r\n const horizontalPaddingValue = viewportPaddingStyle[viewportHorizontalPaddingKey] as number;\r\n const verticalPaddingValue = viewportPaddingStyle.paddingBottom as number;\r\n\r\n // horizontal\r\n viewportStyleObj.width = `calc(100% + ${hideOffsetY + horizontalMarginValue * -1}px)`;\r\n viewportStyleObj[horizontalMarginKey] = -hideOffsetY + horizontalMarginValue;\r\n\r\n // vertical\r\n viewportStyleObj.marginBottom = -hideOffsetX + verticalMarginValue;\r\n\r\n // viewport arrange additional styles\r\n if (viewportArrange) {\r\n viewportStyleObj[viewportHorizontalPaddingKey] =\r\n horizontalPaddingValue + (arrangeY ? hideOffsetY : 0);\r\n viewportStyleObj.paddingBottom = verticalPaddingValue + (arrangeX ? hideOffsetX : 0);\r\n }\r\n };\r\n\r\n /**\r\n * Removes all styles applied because of the viewport arrange strategy.\r\n * @param showNativeOverlaidScrollbars Whether native overlaid scrollbars are shown instead of hidden.\r\n * @param directionIsRTL Whether the direction is RTL or not.\r\n * @param viewportOverflowState The currentviewport overflow state or undefined if it has to be determined.\r\n * @returns A object with a function which applies all the removed styles and the determined viewport vverflow state.\r\n */\r\n const undoViewportArrange = (\r\n showNativeOverlaidScrollbars: boolean,\r\n directionIsRTL: boolean,\r\n viewportOverflowState?: ViewportOverflowState\r\n ): UndoViewportArrangeResult => {\r\n if (doViewportArrange) {\r\n const finalViewportOverflowState =\r\n viewportOverflowState || getViewportOverflowState(showNativeOverlaidScrollbars);\r\n const { _viewportPaddingStyle: viewportPaddingStyle } = getState();\r\n const { _scrollbarsHideOffsetArrange } = finalViewportOverflowState;\r\n const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;\r\n const finalPaddingStyle: StyleObject = {};\r\n const assignProps = (props: string) =>\r\n each(props.split(' '), (prop) => {\r\n finalPaddingStyle[prop] = viewportPaddingStyle[prop];\r\n });\r\n\r\n if (arrangeX) {\r\n assignProps('marginBottom paddingTop paddingBottom');\r\n }\r\n\r\n if (arrangeY) {\r\n assignProps('marginLeft marginRight paddingLeft paddingRight');\r\n }\r\n\r\n const prevStyle = style(_viewport, keys(finalPaddingStyle));\r\n\r\n removeClass(_viewport, classNameViewportArrange);\r\n\r\n if (!_flexboxGlue) {\r\n finalPaddingStyle.height = '';\r\n }\r\n\r\n style(_viewport, finalPaddingStyle);\r\n\r\n return [\r\n () => {\r\n hideNativeScrollbars(\r\n finalViewportOverflowState,\r\n directionIsRTL,\r\n doViewportArrange,\r\n prevStyle\r\n );\r\n style(_viewport, prevStyle);\r\n addClass(_viewport, classNameViewportArrange);\r\n },\r\n finalViewportOverflowState,\r\n ];\r\n }\r\n return [noop];\r\n };\r\n\r\n return (updateHints, checkOption, force) => {\r\n const {\r\n _sizeChanged,\r\n _hostMutation,\r\n _contentMutation,\r\n _paddingStyleChanged,\r\n _heightIntrinsicChanged,\r\n _directionChanged,\r\n } = updateHints;\r\n const { _heightIntrinsic, _directionIsRTL } = getState();\r\n const [showNativeOverlaidScrollbarsOption, showNativeOverlaidScrollbarsChanged] =\r\n checkOption('nativeScrollbarsOverlaid.show');\r\n const [overflow, overflowChanged] = checkOption>('overflow');\r\n const showNativeOverlaidScrollbars =\r\n showNativeOverlaidScrollbarsOption &&\r\n _nativeScrollbarIsOverlaid.x &&\r\n _nativeScrollbarIsOverlaid.y;\r\n const adjustFlexboxGlue =\r\n !_flexboxGlue &&\r\n (_sizeChanged ||\r\n _contentMutation ||\r\n _hostMutation ||\r\n showNativeOverlaidScrollbarsChanged ||\r\n _heightIntrinsicChanged);\r\n const overflowXVisible = overflowIsVisible(overflow.x);\r\n const overflowYVisible = overflowIsVisible(overflow.y);\r\n const overflowVisible = overflowXVisible || overflowYVisible;\r\n\r\n let sizeFractionCache = getCurrentSizeFraction(force);\r\n let viewportScrollSizeCache = getCurrentViewportScrollSizeCache(force);\r\n let overflowAmuntCache = getCurrentOverflowAmountCache(force);\r\n let updateHintsReturn;\r\n let preMeasureViewportOverflowState: ViewportOverflowState | undefined;\r\n\r\n if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {\r\n conditionalClass(_viewport, classNameViewportScrollbarStyling, !showNativeOverlaidScrollbars);\r\n }\r\n\r\n if (adjustFlexboxGlue) {\r\n preMeasureViewportOverflowState = getViewportOverflowState(showNativeOverlaidScrollbars);\r\n fixFlexboxGlue(preMeasureViewportOverflowState, _heightIntrinsic);\r\n }\r\n\r\n if (overflowVisible) {\r\n removeClass(_viewport, classNameOverflowVisible);\r\n }\r\n\r\n if (\r\n _sizeChanged ||\r\n _paddingStyleChanged ||\r\n _contentMutation ||\r\n _directionChanged ||\r\n showNativeOverlaidScrollbarsChanged\r\n ) {\r\n const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange(\r\n showNativeOverlaidScrollbars,\r\n _directionIsRTL,\r\n preMeasureViewportOverflowState\r\n );\r\n const [sizeFraction, sizeFractionChanged] = (sizeFractionCache = updateSizeFraction(force));\r\n const [viewportScrollSize, viewportScrollSizeChanged] = (viewportScrollSizeCache =\r\n updateViewportScrollSizeCache(force));\r\n const viewportclientSize = clientSize(_viewport);\r\n let arrangedViewportScrollSize = viewportScrollSize;\r\n let arrangedViewportClientSize = viewportclientSize;\r\n\r\n redoViewportArrange();\r\n\r\n // if re measure is required (only required if content arrange strategy is used)\r\n if (\r\n (viewportScrollSizeChanged || sizeFractionChanged || showNativeOverlaidScrollbarsChanged) &&\r\n undoViewportArrangeOverflowState &&\r\n !showNativeOverlaidScrollbars &&\r\n arrangeViewport(\r\n undoViewportArrangeOverflowState,\r\n viewportScrollSize,\r\n sizeFraction,\r\n _directionIsRTL\r\n )\r\n ) {\r\n arrangedViewportClientSize = clientSize(_viewport);\r\n arrangedViewportScrollSize = scrollSize(_viewport);\r\n }\r\n\r\n overflowAmuntCache = updateOverflowAmountCache(\r\n getOverflowAmount(\r\n {\r\n w: max(viewportScrollSize.w, arrangedViewportScrollSize.w),\r\n h: max(viewportScrollSize.h, arrangedViewportScrollSize.h),\r\n }, // scroll size\r\n {\r\n w: arrangedViewportClientSize.w + max(0, viewportclientSize.w - viewportScrollSize.w),\r\n h: arrangedViewportClientSize.h + max(0, viewportclientSize.h - viewportScrollSize.h),\r\n }, // client size\r\n sizeFraction\r\n ),\r\n force\r\n );\r\n }\r\n\r\n const [overflowAmount, overflowAmountChanged] = overflowAmuntCache;\r\n const [viewportScrollSize, viewportScrollSizeChanged] = viewportScrollSizeCache;\r\n const [sizeFraction, sizeFractionChanged] = sizeFractionCache;\r\n const hasOverflow = {\r\n x: overflowAmount.w > 0,\r\n y: overflowAmount.h > 0,\r\n };\r\n const removeClipping =\r\n (overflowXVisible && overflowYVisible && (hasOverflow.x || hasOverflow.y)) ||\r\n (overflowXVisible && hasOverflow.x && !hasOverflow.y) ||\r\n (overflowYVisible && hasOverflow.y && !hasOverflow.x);\r\n\r\n if (\r\n _paddingStyleChanged ||\r\n _directionChanged ||\r\n sizeFractionChanged ||\r\n viewportScrollSizeChanged ||\r\n overflowAmountChanged ||\r\n overflowChanged ||\r\n showNativeOverlaidScrollbarsChanged ||\r\n adjustFlexboxGlue\r\n ) {\r\n const viewportStyle: StyleObject = {\r\n marginRight: 0,\r\n marginBottom: 0,\r\n marginLeft: 0,\r\n width: '',\r\n overflowY: '',\r\n overflowX: '',\r\n };\r\n const viewportOverflowState = setViewportOverflowState(\r\n showNativeOverlaidScrollbars,\r\n hasOverflow,\r\n overflow,\r\n viewportStyle\r\n );\r\n const viewportArranged = arrangeViewport(\r\n viewportOverflowState,\r\n viewportScrollSize,\r\n sizeFraction,\r\n _directionIsRTL\r\n );\r\n const [overflowScroll, overflowScrollChanged] = updateOverflowScrollCache(\r\n viewportOverflowState._overflowScroll\r\n );\r\n hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);\r\n\r\n if (adjustFlexboxGlue) {\r\n fixFlexboxGlue(viewportOverflowState, _heightIntrinsic);\r\n }\r\n\r\n style(_viewport, viewportStyle);\r\n\r\n setState({\r\n _overflowScroll: overflowScroll,\r\n _overflowAmount: overflowAmount,\r\n _hasOverflow: hasOverflow,\r\n });\r\n\r\n updateHintsReturn = {\r\n _overflowAmountChanged: overflowAmountChanged,\r\n _overflowScrollChanged: overflowScrollChanged,\r\n };\r\n }\r\n\r\n attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');\r\n conditionalClass(_padding, classNameOverflowVisible, removeClipping);\r\n conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);\r\n\r\n return updateHintsReturn;\r\n };\r\n};\r\n","import { each, isNumber, scrollLeft, scrollTop, assignDeep, keys } from 'support';\r\nimport { getEnvironment } from 'environment';\r\nimport {\r\n createTrinsicUpdate,\r\n createPaddingUpdate,\r\n createOverflowUpdate,\r\n} from 'setups/structureSetup/updateSegments';\r\nimport type { SetupState, SetupUpdateSegment, SetupUpdateCheckOption } from 'setups';\r\nimport type { StructureSetupState } from 'setups/structureSetup';\r\nimport type { StructureSetupElementsObj } from 'setups/structureSetup/structureSetup.elements';\r\n\r\nexport type CreateStructureUpdateSegment = (\r\n structureSetupElements: StructureSetupElementsObj,\r\n state: SetupState\r\n) => StructureSetupUpdateSegment;\r\n\r\nexport type StructureSetupUpdateSegment = SetupUpdateSegment;\r\n\r\nexport type StructureSetupUpdate = (\r\n checkOption: SetupUpdateCheckOption,\r\n updateHints: Partial,\r\n force?: boolean\r\n) => StructureSetupUpdateHints;\r\n\r\nexport interface StructureSetupUpdateHints {\r\n _sizeChanged: boolean;\r\n _directionChanged: boolean;\r\n _heightIntrinsicChanged: boolean;\r\n _overflowScrollChanged: boolean;\r\n _overflowAmountChanged: boolean;\r\n _paddingStyleChanged: boolean;\r\n _hostMutation: boolean;\r\n _contentMutation: boolean;\r\n}\r\n\r\nconst prepareUpdateHints = (\r\n leading: Required,\r\n adaptive?: Partial,\r\n force?: boolean\r\n): Required => {\r\n const result = {};\r\n const finalAdaptive = adaptive || {};\r\n const objKeys = keys(leading).concat(keys(finalAdaptive));\r\n\r\n each(objKeys, (key) => {\r\n const leadingValue = leading[key];\r\n const adaptiveValue = finalAdaptive[key];\r\n result[key] = !!(force || leadingValue || adaptiveValue);\r\n });\r\n\r\n return result as Required;\r\n};\r\n\r\nexport const createStructureSetupUpdate = (\r\n structureSetupElements: StructureSetupElementsObj,\r\n state: SetupState\r\n): StructureSetupUpdate => {\r\n const { _viewport } = structureSetupElements;\r\n const { _nativeScrollbarStyling, _nativeScrollbarIsOverlaid, _flexboxGlue } = getEnvironment();\r\n const doViewportArrange =\r\n !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);\r\n\r\n const updateSegments: StructureSetupUpdateSegment[] = [\r\n createTrinsicUpdate(structureSetupElements, state),\r\n createPaddingUpdate(structureSetupElements, state),\r\n createOverflowUpdate(structureSetupElements, state),\r\n ];\r\n\r\n return (\r\n checkOption: SetupUpdateCheckOption,\r\n updateHints: Partial,\r\n force?: boolean\r\n ) => {\r\n const initialUpdateHints = prepareUpdateHints(\r\n assignDeep(\r\n {\r\n _sizeChanged: false,\r\n _paddingStyleChanged: false,\r\n _directionChanged: false,\r\n _heightIntrinsicChanged: false,\r\n _overflowScrollChanged: false,\r\n _overflowAmountChanged: false,\r\n _hostMutation: false,\r\n _contentMutation: false,\r\n },\r\n updateHints\r\n ),\r\n {},\r\n force\r\n );\r\n const adjustScrollOffset = doViewportArrange || !_flexboxGlue;\r\n const scrollOffsetX = adjustScrollOffset && scrollLeft(_viewport);\r\n const scrollOffsetY = adjustScrollOffset && scrollTop(_viewport);\r\n\r\n let adaptivedUpdateHints: Required = initialUpdateHints;\r\n each(updateSegments, (updateSegment) => {\r\n adaptivedUpdateHints = prepareUpdateHints(\r\n adaptivedUpdateHints,\r\n updateSegment(adaptivedUpdateHints, checkOption, !!force) || {},\r\n force\r\n );\r\n });\r\n\r\n if (isNumber(scrollOffsetX)) {\r\n scrollLeft(_viewport, scrollOffsetX);\r\n }\r\n if (isNumber(scrollOffsetY)) {\r\n scrollTop(_viewport, scrollOffsetY);\r\n }\r\n\r\n return adaptivedUpdateHints;\r\n };\r\n};\r\n","import {\r\n Cache,\r\n CacheValues,\r\n createCache,\r\n createDOM,\r\n style,\r\n appendChildren,\r\n offsetSize,\r\n scrollLeft,\r\n scrollTop,\r\n runEach,\r\n prependChildren,\r\n removeElements,\r\n on,\r\n stopAndPrevent,\r\n addClass,\r\n equalWH,\r\n push,\r\n cAF,\r\n rAF,\r\n ResizeObserverConstructor,\r\n isArray,\r\n isBoolean,\r\n removeClass,\r\n isObject,\r\n} from 'support';\r\nimport { getEnvironment } from 'environment';\r\nimport {\r\n classNameSizeObserver,\r\n classNameSizeObserverAppear,\r\n classNameSizeObserverListener,\r\n classNameSizeObserverListenerScroll,\r\n classNameSizeObserverListenerItem,\r\n classNameSizeObserverListenerItemFinal,\r\n} from 'classnames';\r\n\r\nexport interface SizeObserverOptions {\r\n _direction?: boolean;\r\n _appear?: boolean;\r\n}\r\n\r\nexport interface SizeObserverCallbackParams {\r\n _sizeChanged: boolean;\r\n _directionIsRTLCache?: CacheValues;\r\n _appear?: boolean;\r\n}\r\n\r\nexport type DestroySizeObserver = () => void;\r\n\r\nconst animationStartEventName = 'animationstart';\r\nconst scrollEventName = 'scroll';\r\nconst scrollAmount = 3333333;\r\nconst getElmDirectionIsRTL = (elm: HTMLElement): boolean => style(elm, 'direction') === 'rtl';\r\nconst domRectHasDimensions = (rect?: DOMRectReadOnly) => rect && (rect.height || rect.width);\r\n\r\n/**\r\n * Creates a size observer which observes any size, padding, border, margin and box-sizing changes of the target element. Depending on the options also direction and appear can be observed.\r\n * @param target The target element which shall be observed.\r\n * @param onSizeChangedCallback The callback which gets called after a size change was detected.\r\n * @param options The options for size detection, whether to observe also direction and appear.\r\n * @returns A object which represents the instance of the size observer.\r\n */\r\nexport const createSizeObserver = (\r\n target: HTMLElement,\r\n onSizeChangedCallback: (params: SizeObserverCallbackParams) => any,\r\n options?: SizeObserverOptions\r\n): DestroySizeObserver => {\r\n const { _direction: observeDirectionChange = false, _appear: observeAppearChange = false } =\r\n options || {};\r\n const { _rtlScrollBehavior: rtlScrollBehavior } = getEnvironment();\r\n const baseElements = createDOM(\r\n ``\r\n );\r\n const sizeObserver = baseElements[0] as HTMLElement;\r\n const listenerElement = sizeObserver.firstChild as HTMLElement;\r\n const getIsDirectionRTL = getElmDirectionIsRTL.bind(0, sizeObserver);\r\n const [updateResizeObserverContentRectCache] = createCache({\r\n _initialValue: undefined,\r\n _alwaysUpdateValues: true,\r\n _equal: (currVal, newVal) =>\r\n !(\r\n !currVal || // if no initial value\r\n // if from display: none to display: block\r\n (!domRectHasDimensions(currVal) && domRectHasDimensions(newVal))\r\n ),\r\n });\r\n const onSizeChangedCallbackProxy = (\r\n sizeChangedContext?: CacheValues | ResizeObserverEntry[] | Event | boolean\r\n ) => {\r\n const isResizeObserverCall =\r\n isArray(sizeChangedContext) &&\r\n sizeChangedContext.length > 0 &&\r\n isObject(sizeChangedContext[0]);\r\n\r\n const hasDirectionCache =\r\n !isResizeObserverCall && isBoolean((sizeChangedContext as CacheValues)[0]);\r\n\r\n let skip = false;\r\n let appear: boolean | number | undefined = false;\r\n let doDirectionScroll = true; // always true if sizeChangedContext is Event (appear callback or RO. Polyfill)\r\n\r\n // if triggered from RO.\r\n if (isResizeObserverCall) {\r\n const [currRContentRect, , prevContentRect] = updateResizeObserverContentRectCache(\r\n (sizeChangedContext as ResizeObserverEntry[]).pop()!.contentRect\r\n );\r\n const hasDimensions = domRectHasDimensions(currRContentRect);\r\n const hadDimensions = domRectHasDimensions(prevContentRect);\r\n skip = !prevContentRect || !hasDimensions; // skip on initial RO. call or if display is none\r\n appear = !hadDimensions && hasDimensions;\r\n\r\n doDirectionScroll = !skip; // direction scroll when not skipping\r\n }\r\n // else if its triggered with DirectionCache\r\n else if (hasDirectionCache) {\r\n [, doDirectionScroll] = sizeChangedContext as CacheValues; // direction scroll when DirectionCache changed, false otherwise\r\n }\r\n // else if it triggered with appear from polyfill\r\n else {\r\n appear = sizeChangedContext === true;\r\n }\r\n\r\n if (observeDirectionChange && doDirectionScroll) {\r\n const rtl = hasDirectionCache\r\n ? (sizeChangedContext as CacheValues)[0]\r\n : getElmDirectionIsRTL(sizeObserver);\r\n scrollLeft(\r\n sizeObserver,\r\n rtl\r\n ? rtlScrollBehavior.n\r\n ? -scrollAmount\r\n : rtlScrollBehavior.i\r\n ? 0\r\n : scrollAmount\r\n : scrollAmount\r\n );\r\n scrollTop(sizeObserver, scrollAmount);\r\n }\r\n\r\n if (!skip) {\r\n onSizeChangedCallback({\r\n _sizeChanged: !hasDirectionCache,\r\n _directionIsRTLCache: hasDirectionCache\r\n ? (sizeChangedContext as CacheValues)\r\n : undefined,\r\n _appear: !!appear,\r\n });\r\n }\r\n };\r\n const offListeners: (() => void)[] = [];\r\n let appearCallback: ((...args: any) => any) | false = observeAppearChange\r\n ? onSizeChangedCallbackProxy\r\n : false;\r\n let directionIsRTLCache: Cache | undefined;\r\n\r\n if (ResizeObserverConstructor) {\r\n const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);\r\n resizeObserverInstance.observe(listenerElement);\r\n push(offListeners, () => {\r\n resizeObserverInstance.disconnect();\r\n });\r\n } else {\r\n const observerElementChildren = createDOM(\r\n ``\r\n );\r\n appendChildren(listenerElement, observerElementChildren);\r\n addClass(listenerElement, classNameSizeObserverListenerScroll);\r\n const observerElementChildrenRoot = observerElementChildren[0] as HTMLElement;\r\n const shrinkElement = observerElementChildrenRoot.lastChild as HTMLElement;\r\n const expandElement = observerElementChildrenRoot.firstChild as HTMLElement;\r\n const expandElementChild = expandElement?.firstChild as HTMLElement;\r\n\r\n let cacheSize = offsetSize(observerElementChildrenRoot);\r\n let currSize = cacheSize;\r\n let isDirty = false;\r\n let rAFId: number;\r\n\r\n const reset = () => {\r\n scrollLeft(expandElement, scrollAmount);\r\n scrollTop(expandElement, scrollAmount);\r\n scrollLeft(shrinkElement, scrollAmount);\r\n scrollTop(shrinkElement, scrollAmount);\r\n };\r\n const onResized = (appear?: unknown) => {\r\n rAFId = 0;\r\n if (isDirty) {\r\n cacheSize = currSize;\r\n onSizeChangedCallbackProxy(appear === true);\r\n }\r\n };\r\n const onScroll = (scrollEvent?: Event | false) => {\r\n currSize = offsetSize(observerElementChildrenRoot);\r\n isDirty = !scrollEvent || !equalWH(currSize, cacheSize);\r\n\r\n if (scrollEvent) {\r\n stopAndPrevent(scrollEvent);\r\n\r\n if (isDirty && !rAFId) {\r\n cAF!(rAFId);\r\n rAFId = rAF!(onResized);\r\n }\r\n } else {\r\n onResized(scrollEvent === false);\r\n }\r\n\r\n reset();\r\n };\r\n\r\n push(offListeners, [\r\n on(expandElement, scrollEventName, onScroll),\r\n on(shrinkElement, scrollEventName, onScroll),\r\n ]);\r\n\r\n // lets assume that the divs will never be that large and a constant value is enough\r\n style(expandElementChild, {\r\n width: scrollAmount,\r\n height: scrollAmount,\r\n });\r\n\r\n reset();\r\n\r\n appearCallback = observeAppearChange ? onScroll.bind(0, false) : reset;\r\n }\r\n\r\n if (observeDirectionChange) {\r\n directionIsRTLCache = createCache(\r\n {\r\n _initialValue: !getIsDirectionRTL(), // invert current value to trigger initial change\r\n },\r\n getIsDirectionRTL\r\n );\r\n const [updateDirectionIsRTLCache] = directionIsRTLCache;\r\n\r\n push(\r\n offListeners,\r\n on(sizeObserver, scrollEventName, (event: Event) => {\r\n const directionIsRTLCacheValues = updateDirectionIsRTLCache();\r\n const [directionIsRTL, directionIsRTLChanged] = directionIsRTLCacheValues;\r\n\r\n if (directionIsRTLChanged) {\r\n removeClass(listenerElement, 'ltr rtl');\r\n if (directionIsRTL) {\r\n addClass(listenerElement, 'rtl');\r\n } else {\r\n addClass(listenerElement, 'ltr');\r\n }\r\n onSizeChangedCallbackProxy(directionIsRTLCacheValues);\r\n }\r\n\r\n stopAndPrevent(event);\r\n })\r\n );\r\n }\r\n\r\n // appearCallback is always needed on scroll-observer strategy to reset it\r\n if (appearCallback) {\r\n addClass(sizeObserver, classNameSizeObserverAppear);\r\n push(\r\n offListeners,\r\n on(sizeObserver, animationStartEventName, appearCallback, {\r\n // Fire only once for \"CSS is ready\" event if ResizeObserver strategy is used\r\n _once: !!ResizeObserverConstructor,\r\n })\r\n );\r\n }\r\n\r\n prependChildren(target, sizeObserver);\r\n\r\n return () => {\r\n runEach(offListeners);\r\n removeElements(sizeObserver);\r\n };\r\n};\r\n","import {\r\n WH,\r\n CacheValues,\r\n createDiv,\r\n offsetSize,\r\n runEach,\r\n prependChildren,\r\n removeElements,\r\n createCache,\r\n push,\r\n IntersectionObserverConstructor,\r\n} from 'support';\r\nimport { createSizeObserver } from 'observers/sizeObserver';\r\nimport { classNameTrinsicObserver } from 'classnames';\r\n\r\nexport type DestroyTrinsicObserver = () => void;\r\n\r\nconst isHeightIntrinsic = (ioEntryOrSize: IntersectionObserverEntry | WH): boolean =>\r\n (ioEntryOrSize as WH).h === 0 ||\r\n (ioEntryOrSize as IntersectionObserverEntry).isIntersecting ||\r\n (ioEntryOrSize as IntersectionObserverEntry).intersectionRatio > 0;\r\n\r\n/**\r\n * Creates a trinsic observer which observes changes to intrinsic or extrinsic sizing for the height of the target element.\r\n * @param target The element which shall be observed.\r\n * @param onTrinsicChangedCallback The callback which gets called after a change was detected.\r\n * @returns A object which represents the instance of the trinsic observer.\r\n */\r\nexport const createTrinsicObserver = (\r\n target: HTMLElement,\r\n onTrinsicChangedCallback: (heightIntrinsic: CacheValues) => any\r\n): DestroyTrinsicObserver => {\r\n const trinsicObserver = createDiv(classNameTrinsicObserver);\r\n const offListeners: (() => void)[] = [];\r\n const [updateHeightIntrinsicCache] = createCache({\r\n _initialValue: false,\r\n });\r\n\r\n const triggerOnTrinsicChangedCallback = (\r\n updateValue?: IntersectionObserverEntry | WH\r\n ) => {\r\n if (updateValue) {\r\n const heightIntrinsic = updateHeightIntrinsicCache(isHeightIntrinsic(updateValue));\r\n const [, heightIntrinsicChanged] = heightIntrinsic;\r\n\r\n if (heightIntrinsicChanged) {\r\n onTrinsicChangedCallback(heightIntrinsic);\r\n }\r\n }\r\n };\r\n\r\n if (IntersectionObserverConstructor) {\r\n const intersectionObserverInstance: IntersectionObserver = new IntersectionObserverConstructor(\r\n (entries: IntersectionObserverEntry[]) => {\r\n if (entries && entries.length > 0) {\r\n triggerOnTrinsicChangedCallback(entries.pop());\r\n }\r\n },\r\n { root: target }\r\n );\r\n intersectionObserverInstance.observe(trinsicObserver);\r\n push(offListeners, () => {\r\n intersectionObserverInstance.disconnect();\r\n });\r\n } else {\r\n const onSizeChanged = () => {\r\n const newSize = offsetSize(trinsicObserver);\r\n triggerOnTrinsicChangedCallback(newSize);\r\n };\r\n push(offListeners, createSizeObserver(trinsicObserver, onSizeChanged));\r\n onSizeChanged();\r\n }\r\n\r\n prependChildren(target, trinsicObserver);\r\n\r\n return () => {\r\n runEach(offListeners);\r\n removeElements(trinsicObserver);\r\n };\r\n};\r\n","import {\r\n each,\r\n noop,\r\n debounce,\r\n indexOf,\r\n isString,\r\n MutationObserverConstructor,\r\n isEmptyArray,\r\n on,\r\n attr,\r\n is,\r\n find,\r\n push,\r\n} from 'support';\r\n\r\ntype DOMContentObserverCallback = (contentChangedTroughEvent: boolean) => any;\r\n\r\ntype DOMTargetObserverCallback = (targetChangedAttrs: string[], targetStyleChanged: boolean) => any;\r\n\r\ninterface DOMObserverOptionsBase {\r\n _attributes?: string[];\r\n _styleChangingAttributes?: string[];\r\n}\r\n\r\ninterface DOMContentObserverOptions extends DOMObserverOptionsBase {\r\n _eventContentChange?: DOMObserverEventContentChange; // [selector, eventname(s) | function returning eventname(s)] -> eventnames divided by whitespaces\r\n _nestedTargetSelector?: string;\r\n _ignoreContentChange?: DOMObserverIgnoreContentChange; // function which will prevent marking certain dom changes as content change if it returns true\r\n _ignoreNestedTargetChange?: DOMObserverIgnoreTargetChange; // a function which will prevent marking certain attributes as changed on nested targets if it returns true\r\n}\r\n\r\ninterface DOMTargetObserverOptions extends DOMObserverOptionsBase {\r\n _ignoreTargetChange?: DOMObserverIgnoreTargetChange; // a function which will prevent marking certain attributes as changed if it returns true\r\n}\r\n\r\ntype ContentChangeArrayItem = [string?, string?] | null | undefined;\r\n\r\nexport type DOMObserverEventContentChange =\r\n | Array\r\n | false\r\n | null\r\n | undefined;\r\n\r\nexport type DOMObserverIgnoreContentChange = (\r\n mutation: MutationRecord,\r\n isNestedTarget: boolean,\r\n domObserverTarget: HTMLElement,\r\n domObserverOptions?: DOMContentObserverOptions\r\n) => boolean;\r\n\r\nexport type DOMObserverIgnoreTargetChange = (\r\n target: Node,\r\n attributeName: string,\r\n oldAttributeValue: string | null,\r\n newAttributeValue: string | null\r\n) => boolean;\r\n\r\nexport type DOMObserverCallback = ContentObserver extends true\r\n ? DOMContentObserverCallback\r\n : DOMTargetObserverCallback;\r\n\r\nexport type DOMObserverOptions = ContentObserver extends true\r\n ? DOMContentObserverOptions\r\n : DOMTargetObserverOptions;\r\n\r\nexport type DOMObserver = [destroy: () => void, update: () => void];\r\n\r\ntype EventContentChangeUpdateElement = (getElements?: (selector: string) => Node[]) => void;\r\ntype EventContentChange = [destroy: () => void, updateElements: EventContentChangeUpdateElement];\r\n\r\n/**\r\n * Creates a set of helper functions to observe events of elements inside the target element.\r\n * @param target The target element of which the children elements shall be observed. (not only direct children but also nested ones)\r\n * @param eventContentChange The event content change array. (array of tuples: selector and eventname(s))\r\n * @param callback Callback which is called if one of the elements emits the corresponding event.\r\n * @returns A object which contains a set of helper functions to destroy and update the observation of elements.\r\n */\r\nconst createEventContentChange = (\r\n target: Element,\r\n callback: (...args: any) => any,\r\n eventContentChange?: DOMObserverEventContentChange\r\n): EventContentChange => {\r\n let map: WeakMap any]> | undefined; // weak map to prevent memory leak for detached elements\r\n let destroyed = false;\r\n const destroy = () => {\r\n destroyed = true;\r\n };\r\n const updateElements: EventContentChangeUpdateElement = (getElements?) => {\r\n if (eventContentChange) {\r\n const eventElmList = eventContentChange.reduce>((arr, item) => {\r\n if (item) {\r\n const selector = item[0];\r\n const eventNames = item[1];\r\n const elements =\r\n eventNames &&\r\n selector &&\r\n (getElements ? getElements(selector) : find(selector, target));\r\n\r\n if (elements && elements.length && eventNames && isString(eventNames)) {\r\n push(arr, [elements, eventNames.trim()], true);\r\n }\r\n }\r\n return arr;\r\n }, []);\r\n\r\n each(eventElmList, (item) =>\r\n each(item[0], (elm) => {\r\n const eventNames = item[1];\r\n const entry = map!.get(elm);\r\n\r\n if (entry) {\r\n const entryEventNames = entry[0];\r\n const entryOff = entry[1];\r\n\r\n // in case an already registered element is registered again, unregister the previous events\r\n if (entryEventNames === eventNames) {\r\n entryOff();\r\n }\r\n }\r\n\r\n const off = on(elm, eventNames, (event: Event) => {\r\n if (destroyed) {\r\n off();\r\n map!.delete(elm);\r\n } else {\r\n callback(event);\r\n }\r\n });\r\n map!.set(elm, [eventNames, off]);\r\n })\r\n );\r\n }\r\n };\r\n\r\n if (eventContentChange) {\r\n map = new WeakMap();\r\n updateElements();\r\n }\r\n\r\n return [destroy, updateElements];\r\n};\r\n\r\n/**\r\n * Creates a DOM observer which observes DOM changes to either the target element or its children.\r\n * @param target The element which shall be observed.\r\n * @param isContentObserver Whether this observer is just observing the target or just the targets children. (not only direct children but also nested ones)\r\n * @param callback The callback which gets called if a change was detected.\r\n * @param options The options for DOM change detection.\r\n * @returns A object which represents the instance of the DOM observer.\r\n */\r\nexport const createDOMObserver =