mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-23 16:20:37 +03:00
padding Lifecycle
This commit is contained in:
@@ -123,7 +123,7 @@ const createEnvironment = (): Environment => {
|
|||||||
|
|
||||||
const onChangedListener: Set<OnEnvironmentChanged> = new Set();
|
const onChangedListener: Set<OnEnvironmentChanged> = new Set();
|
||||||
const nativeScrollbarSize = getNativeScrollbarSize(body, envElm);
|
const nativeScrollbarSize = getNativeScrollbarSize(body, envElm);
|
||||||
const nativeScrollbarStyling = false; //getNativeScrollbarStyling(envElm); TODO: Re-enable
|
const nativeScrollbarStyling = false; //getNativeScrollbarStyling(envElm); TODO: Re - enable;
|
||||||
const nativeScrollbarIsOverlaid = {
|
const nativeScrollbarIsOverlaid = {
|
||||||
x: nativeScrollbarSize.x === 0,
|
x: nativeScrollbarSize.x === 0,
|
||||||
y: nativeScrollbarSize.y === 0,
|
y: nativeScrollbarSize.y === 0,
|
||||||
|
|||||||
@@ -1,13 +1,39 @@
|
|||||||
import { CacheValues, each, push, validateOptions, assignDeep, isEmptyObject, OptionsValidated } from 'support';
|
import { TRBL, CacheValues, each, push, OptionsValidated, hasOwnProperty } from 'support';
|
||||||
import { Options } from 'options';
|
import { Options } from 'options';
|
||||||
import { getEnvironment, Environment } from 'environment';
|
import { getEnvironment } from 'environment';
|
||||||
import { StructureSetup } from 'setups/structureSetup';
|
import { StructureSetup } from 'setups/structureSetup';
|
||||||
import { createStructureLifecycle } from 'lifecycles/structureLifecycle';
|
import { createStructureLifecycle } from 'lifecycles/structureLifecycle';
|
||||||
|
import { createPaddingLifecycle } from 'lifecycles/paddingLifecycle';
|
||||||
import { createOverflowLifecycle } from 'lifecycles/overflowLifecycle';
|
import { createOverflowLifecycle } from 'lifecycles/overflowLifecycle';
|
||||||
import { LifecycleUpdateFunction, LifecycleUpdateHints } from 'lifecycles/lifecycleUpdateFunction';
|
|
||||||
import { createSizeObserver } from 'observers/sizeObserver';
|
import { createSizeObserver } from 'observers/sizeObserver';
|
||||||
import { createTrinsicObserver } from 'observers/trinsicObserver';
|
import { createTrinsicObserver } from 'observers/trinsicObserver';
|
||||||
import { createDOMObserver } from 'observers/domObserver';
|
import { createDOMObserver } from 'observers/domObserver';
|
||||||
|
import { StyleObject } from 'typings';
|
||||||
|
|
||||||
|
export type LifecycleCheckOption = <T>(path: string) => LifecycleOptionInfo<T>;
|
||||||
|
|
||||||
|
export interface LifecycleOptionInfo<T> {
|
||||||
|
readonly _value: T;
|
||||||
|
_changed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LifecycleAdaptiveUpdateHints {
|
||||||
|
_sizeChanged: boolean;
|
||||||
|
_hostMutation: boolean;
|
||||||
|
_contentMutation: boolean;
|
||||||
|
_paddingStyleChanged: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LifecycleUpdateHints extends LifecycleAdaptiveUpdateHints {
|
||||||
|
_directionIsRTL: CacheValues<boolean>;
|
||||||
|
_heightIntrinsic: CacheValues<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Lifecycle = (
|
||||||
|
updateHints: LifecycleUpdateHints,
|
||||||
|
checkOption: LifecycleCheckOption,
|
||||||
|
force: boolean
|
||||||
|
) => Partial<LifecycleAdaptiveUpdateHints> | void;
|
||||||
|
|
||||||
export interface LifecycleHubInstance {
|
export interface LifecycleHubInstance {
|
||||||
_update(changedOptions?: OptionsValidated<Options> | null, force?: boolean): void;
|
_update(changedOptions?: OptionsValidated<Options> | null, force?: boolean): void;
|
||||||
@@ -17,9 +43,23 @@ export interface LifecycleHubInstance {
|
|||||||
export interface LifecycleHub {
|
export interface LifecycleHub {
|
||||||
_options: Options;
|
_options: Options;
|
||||||
_structureSetup: StructureSetup;
|
_structureSetup: StructureSetup;
|
||||||
|
_getPadding(): TRBL;
|
||||||
|
_setPadding(newPadding?: TRBL | null): void;
|
||||||
|
_getPaddingStyle(): StyleObject;
|
||||||
|
_setPaddingStyle(newPaddingStlye?: StyleObject | null): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getPropByPath = <T>(obj: any, path: string): T =>
|
||||||
|
obj && path.split('.').reduce((o, prop) => (o && hasOwnProperty(o, prop) ? o[prop] : undefined), obj);
|
||||||
|
|
||||||
const attrs = ['id', 'class', 'style', 'open'];
|
const attrs = ['id', 'class', 'style', 'open'];
|
||||||
|
const paddingFallback: TRBL = { t: 0, r: 0, b: 0, l: 0 };
|
||||||
|
const viewportPaddingStyleFallback: StyleObject = {
|
||||||
|
marginTop: 0,
|
||||||
|
marginRight: 0,
|
||||||
|
marginBottom: 0,
|
||||||
|
marginLeft: 0,
|
||||||
|
};
|
||||||
const directionIsRTLCacheValuesFallback: CacheValues<boolean> = {
|
const directionIsRTLCacheValuesFallback: CacheValues<boolean> = {
|
||||||
_value: false,
|
_value: false,
|
||||||
_previous: false,
|
_previous: false,
|
||||||
@@ -32,6 +72,8 @@ const heightIntrinsicCacheValuesFallback: CacheValues<boolean> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const createLifecycleHub = (options: Options, structureSetup: StructureSetup): LifecycleHubInstance => {
|
export const createLifecycleHub = (options: Options, structureSetup: StructureSetup): LifecycleHubInstance => {
|
||||||
|
let padding = paddingFallback;
|
||||||
|
let viewportPaddingStyle = viewportPaddingStyleFallback;
|
||||||
const { _host, _viewport, _content } = structureSetup._targetObj;
|
const { _host, _viewport, _content } = structureSetup._targetObj;
|
||||||
const {
|
const {
|
||||||
_nativeScrollbarStyling,
|
_nativeScrollbarStyling,
|
||||||
@@ -39,39 +81,66 @@ export const createLifecycleHub = (options: Options, structureSetup: StructureSe
|
|||||||
_addListener: addEnvironmentListener,
|
_addListener: addEnvironmentListener,
|
||||||
_removeListener: removeEnvironmentListener,
|
_removeListener: removeEnvironmentListener,
|
||||||
} = getEnvironment();
|
} = getEnvironment();
|
||||||
const lifecycles: LifecycleUpdateFunction[] = [];
|
const lifecycles: Lifecycle[] = [];
|
||||||
const instance: LifecycleHub = {
|
const instance: LifecycleHub = {
|
||||||
_options: options,
|
_options: options,
|
||||||
_structureSetup: structureSetup,
|
_structureSetup: structureSetup,
|
||||||
|
_getPadding: () => padding,
|
||||||
|
_setPadding(newPadding) {
|
||||||
|
padding = newPadding || paddingFallback;
|
||||||
|
},
|
||||||
|
_getPaddingStyle: () => viewportPaddingStyle,
|
||||||
|
_setPaddingStyle(newPaddingStlye: StyleObject) {
|
||||||
|
viewportPaddingStyle = newPaddingStlye || viewportPaddingStyleFallback;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// push(lifecycles, createStructureLifecycle(instance));
|
// push(lifecycles, createStructureLifecycle(instance));
|
||||||
|
push(lifecycles, createPaddingLifecycle(instance));
|
||||||
push(lifecycles, createOverflowLifecycle(instance));
|
push(lifecycles, createOverflowLifecycle(instance));
|
||||||
|
|
||||||
const runLifecycles = (updateHints?: Partial<LifecycleUpdateHints> | null, changedOptions?: OptionsValidated<Options> | null, force?: boolean) => {
|
const runLifecycles = (updateHints?: Partial<LifecycleUpdateHints> | null, changedOptions?: OptionsValidated<Options> | null, force?: boolean) => {
|
||||||
let { _directionIsRTL, _heightIntrinsic, _sizeChanged = force || false, _hostMutation = force || false, _contentMutation = force || false } =
|
let {
|
||||||
updateHints || {};
|
_directionIsRTL,
|
||||||
|
_heightIntrinsic,
|
||||||
|
_sizeChanged = force || false,
|
||||||
|
_hostMutation = force || false,
|
||||||
|
_contentMutation = force || false,
|
||||||
|
_paddingStyleChanged = force || false,
|
||||||
|
} = updateHints || {};
|
||||||
const finalDirectionIsRTL =
|
const finalDirectionIsRTL =
|
||||||
_directionIsRTL || (sizeObserver ? sizeObserver._getCurrentCacheValues(force)._directionIsRTL : directionIsRTLCacheValuesFallback);
|
_directionIsRTL || (sizeObserver ? sizeObserver._getCurrentCacheValues(force)._directionIsRTL : directionIsRTLCacheValuesFallback);
|
||||||
const finalHeightIntrinsic =
|
const finalHeightIntrinsic =
|
||||||
_heightIntrinsic || (trinsicObserver ? trinsicObserver._getCurrentCacheValues(force)._heightIntrinsic : heightIntrinsicCacheValuesFallback);
|
_heightIntrinsic || (trinsicObserver ? trinsicObserver._getCurrentCacheValues(force)._heightIntrinsic : heightIntrinsicCacheValuesFallback);
|
||||||
|
const checkOption: LifecycleCheckOption = (path) => ({
|
||||||
|
_value: getPropByPath(options, path),
|
||||||
|
_changed: force || getPropByPath(changedOptions, path) !== undefined,
|
||||||
|
});
|
||||||
|
|
||||||
each(lifecycles, (lifecycle) => {
|
each(lifecycles, (lifecycle) => {
|
||||||
const { _sizeChanged: adaptiveSizeChanged, _hostMutation: adaptiveHostMutation, _contentMutation: adaptiveContentMutation } = lifecycle(
|
const {
|
||||||
{
|
_sizeChanged: adaptiveSizeChanged,
|
||||||
_directionIsRTL: finalDirectionIsRTL,
|
_hostMutation: adaptiveHostMutation,
|
||||||
_heightIntrinsic: finalHeightIntrinsic,
|
_contentMutation: adaptiveContentMutation,
|
||||||
_sizeChanged,
|
_paddingStyleChanged: adaptivePaddingStyleChanged,
|
||||||
_hostMutation,
|
} =
|
||||||
_contentMutation,
|
lifecycle(
|
||||||
},
|
{
|
||||||
changedOptions,
|
_directionIsRTL: finalDirectionIsRTL,
|
||||||
force
|
_heightIntrinsic: finalHeightIntrinsic,
|
||||||
);
|
_sizeChanged,
|
||||||
|
_hostMutation,
|
||||||
|
_contentMutation,
|
||||||
|
_paddingStyleChanged,
|
||||||
|
},
|
||||||
|
checkOption,
|
||||||
|
!!force
|
||||||
|
) || {};
|
||||||
|
|
||||||
_sizeChanged = adaptiveSizeChanged || _sizeChanged;
|
_sizeChanged = adaptiveSizeChanged || _sizeChanged;
|
||||||
_hostMutation = adaptiveHostMutation || _hostMutation;
|
_hostMutation = adaptiveHostMutation || _hostMutation;
|
||||||
_contentMutation = adaptiveContentMutation || _contentMutation;
|
_contentMutation = adaptiveContentMutation || _contentMutation;
|
||||||
|
_paddingStyleChanged = adaptivePaddingStyleChanged || _paddingStyleChanged;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import { CacheValues, OptionsValidated, hasOwnProperty } from 'support';
|
|
||||||
import { Options } from 'options';
|
|
||||||
import { LifecycleHub } from 'lifecycles/lifecycleHub';
|
|
||||||
|
|
||||||
export interface LifecycleAdaptiveUpdateHints {
|
|
||||||
_sizeChanged: boolean;
|
|
||||||
_hostMutation: boolean;
|
|
||||||
_contentMutation: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LifecycleUpdateHints extends LifecycleAdaptiveUpdateHints {
|
|
||||||
_directionIsRTL: CacheValues<boolean>;
|
|
||||||
_heightIntrinsic: CacheValues<boolean>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LifecycleUpdateFunction = (
|
|
||||||
updateHints: LifecycleUpdateHints,
|
|
||||||
changedOptions?: OptionsValidated<Options> | null,
|
|
||||||
force?: boolean
|
|
||||||
) => Partial<LifecycleAdaptiveUpdateHints>;
|
|
||||||
|
|
||||||
export interface LifecycleOptionInfo<T> {
|
|
||||||
readonly _value: T;
|
|
||||||
_changed: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LifecycleCheckOption = <T>(path: string) => LifecycleOptionInfo<T>;
|
|
||||||
|
|
||||||
const getPropByPath = <T>(obj: any, path: string): T =>
|
|
||||||
obj && path.split('.').reduce((o, prop) => (o && hasOwnProperty(o, prop) ? o[prop] : undefined), obj);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a update function for a lifecycle.
|
|
||||||
* @param lifecycleHub The LifecycleHub which is managing this lifecylce.
|
|
||||||
* @param updateFunction The update function where cache and options updates are handled. Has two arguments which are the changedOptions and the changedCache objects.
|
|
||||||
*/
|
|
||||||
export const createLifecycleUpdateFunction = (
|
|
||||||
lifecycleHub: LifecycleHub,
|
|
||||||
updateFunction: (
|
|
||||||
force: boolean,
|
|
||||||
updateHints: LifecycleUpdateHints,
|
|
||||||
checkOption: LifecycleCheckOption
|
|
||||||
) => Partial<LifecycleAdaptiveUpdateHints> | void
|
|
||||||
): LifecycleUpdateFunction => {
|
|
||||||
return (updateHints: LifecycleUpdateHints, changedOptions?: OptionsValidated<Options> | null, force?: boolean) => {
|
|
||||||
const checkOption: LifecycleCheckOption = (path) => ({
|
|
||||||
_value: getPropByPath(lifecycleHub._options, path),
|
|
||||||
_changed: force || getPropByPath(changedOptions, path) !== undefined,
|
|
||||||
});
|
|
||||||
return updateFunction(!!force, updateHints, checkOption) || {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -5,19 +5,18 @@ import {
|
|||||||
equalXY,
|
equalXY,
|
||||||
style,
|
style,
|
||||||
scrollSize,
|
scrollSize,
|
||||||
offsetSize,
|
|
||||||
CacheValues,
|
CacheValues,
|
||||||
equalWH,
|
equalWH,
|
||||||
scrollLeft,
|
scrollLeft,
|
||||||
scrollTop,
|
scrollTop,
|
||||||
addClass,
|
addClass,
|
||||||
removeClass,
|
removeClass,
|
||||||
|
clientSize,
|
||||||
} from 'support';
|
} from 'support';
|
||||||
import { createLifecycleUpdateFunction, LifecycleUpdateFunction } from 'lifecycles/lifecycleUpdateFunction';
|
import { LifecycleHub, Lifecycle } from 'lifecycles/lifecycleHub';
|
||||||
import { LifecycleHub } from 'lifecycles/lifecycleHub';
|
|
||||||
import { getEnvironment } from 'environment';
|
import { getEnvironment } from 'environment';
|
||||||
import { OverflowBehavior } from 'options';
|
import { OverflowBehavior } from 'options';
|
||||||
import { PlainObject } from 'typings';
|
import { StyleObject } from 'typings';
|
||||||
import { classNameViewportScrollbarStyling } from 'classnames';
|
import { classNameViewportScrollbarStyling } from 'classnames';
|
||||||
|
|
||||||
const overlaidScrollbarsHideOffset = 42;
|
const overlaidScrollbarsHideOffset = 42;
|
||||||
@@ -27,8 +26,9 @@ interface OverflowAmountCacheContext {
|
|||||||
_viewportSize: WH<number>;
|
_viewportSize: WH<number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUpdateFunction => {
|
export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle => {
|
||||||
const { _host, _padding, _viewport, _content, _contentArrange } = lifecycleHub._structureSetup._targetObj;
|
const { _structureSetup, _getPaddingStyle } = lifecycleHub;
|
||||||
|
const { _host, _padding, _viewport, _content, _contentArrange } = _structureSetup._targetObj;
|
||||||
const { _update: updateContentScrollSizeCache, _current: getCurrentContentScrollSizeCache } = createCache<WH<number>>(
|
const { _update: updateContentScrollSizeCache, _current: getCurrentContentScrollSizeCache } = createCache<WH<number>>(
|
||||||
() => scrollSize(_content || _viewport),
|
() => scrollSize(_content || _viewport),
|
||||||
{ _equal: equalWH }
|
{ _equal: equalWH }
|
||||||
@@ -41,7 +41,7 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
{ _equal: equalXY }
|
{ _equal: equalXY }
|
||||||
);
|
);
|
||||||
|
|
||||||
const setViewportOverflowStyle = (horizontal: boolean, amount: number, behavior: OverflowBehavior, styleObj: PlainObject) => {
|
const setViewportOverflowStyle = (horizontal: boolean, amount: number, behavior: OverflowBehavior, styleObj: StyleObject) => {
|
||||||
const overflowKey = horizontal ? 'overflowX' : 'overflowY';
|
const overflowKey = horizontal ? 'overflowX' : 'overflowY';
|
||||||
//const scrollMaxKey = horizontal ? 'scrollLeftMax' : 'scrollTopMax';
|
//const scrollMaxKey = horizontal ? 'scrollLeftMax' : 'scrollTopMax';
|
||||||
const behaviorIsScroll = behavior === 'scroll';
|
const behaviorIsScroll = behavior === 'scroll';
|
||||||
@@ -65,40 +65,43 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
contentScrollSize: WH<number>,
|
contentScrollSize: WH<number>,
|
||||||
showNativeOverlaidScrollbars: boolean,
|
showNativeOverlaidScrollbars: boolean,
|
||||||
directionIsRTL: boolean,
|
directionIsRTL: boolean,
|
||||||
viewportStyleObj: PlainObject,
|
viewportStyleObj: StyleObject,
|
||||||
contentStyleObj: PlainObject
|
contentStyleObj: StyleObject
|
||||||
) => {
|
) => {
|
||||||
const { _nativeScrollbarSize, _nativeScrollbarIsOverlaid, _nativeScrollbarStyling } = getEnvironment();
|
const { _nativeScrollbarSize, _nativeScrollbarIsOverlaid, _nativeScrollbarStyling } = getEnvironment();
|
||||||
const { x: overlaidX, y: overlaidY } = _nativeScrollbarIsOverlaid;
|
const { x: overlaidX, y: overlaidY } = _nativeScrollbarIsOverlaid;
|
||||||
|
const paddingStyle = _getPaddingStyle();
|
||||||
const scrollX = viewportStyleObj.overflowX === 'scroll';
|
const scrollX = viewportStyleObj.overflowX === 'scroll';
|
||||||
const scrollY = viewportStyleObj.overflowY === 'scroll';
|
const scrollY = viewportStyleObj.overflowY === 'scroll';
|
||||||
const horizontalMarginKey = directionIsRTL ? 'marginLeft' : 'marginRight';
|
const horizontalMarginKey = directionIsRTL ? 'marginLeft' : 'marginRight';
|
||||||
const horizontalBorderKey = directionIsRTL ? 'borderLeft' : 'borderRight';
|
const horizontalBorderKey = directionIsRTL ? 'borderLeft' : 'borderRight';
|
||||||
const overlaidHideOffset = _content && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;
|
const horizontalPaddingValue = paddingStyle[horizontalMarginKey] as number;
|
||||||
|
const overlaidHideOffset = _content && !_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;
|
||||||
const scrollbarsHideOffset = {
|
const scrollbarsHideOffset = {
|
||||||
x: overlaidX ? overlaidHideOffset : _nativeScrollbarSize.x,
|
x: scrollX && !_nativeScrollbarStyling ? (overlaidX ? overlaidHideOffset : _nativeScrollbarSize.x) : 0,
|
||||||
y: overlaidY ? overlaidHideOffset : _nativeScrollbarSize.y,
|
y: scrollY && !_nativeScrollbarStyling ? (overlaidY ? overlaidHideOffset : _nativeScrollbarSize.y) : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// vertical
|
||||||
|
viewportStyleObj.marginBottom = -scrollbarsHideOffset.x + (paddingStyle.marginBottom as number);
|
||||||
|
contentStyleObj.borderBottom = scrollX && overlaidX && overlaidHideOffset ? overlaidScrollbarsHideBorderStyle : '';
|
||||||
|
|
||||||
|
// horizontal
|
||||||
|
viewportStyleObj.maxWidth = `calc(100% + ${scrollbarsHideOffset.y + horizontalPaddingValue * -1}px)`;
|
||||||
|
viewportStyleObj[horizontalMarginKey] = -scrollbarsHideOffset.y + horizontalPaddingValue;
|
||||||
|
contentStyleObj[horizontalBorderKey] = scrollY && overlaidY && overlaidHideOffset ? overlaidScrollbarsHideBorderStyle : '';
|
||||||
|
|
||||||
|
// adjust content arrange (content arrange doesn't exist if its not needed)
|
||||||
|
style(_contentArrange, {
|
||||||
|
width: scrollY && !showNativeOverlaidScrollbars ? overlaidHideOffset + contentScrollSize.w : '',
|
||||||
|
height: scrollX && !showNativeOverlaidScrollbars ? overlaidHideOffset + contentScrollSize.h : '',
|
||||||
|
});
|
||||||
|
|
||||||
|
// hide overflowing scrollbars if there are any
|
||||||
if (!_nativeScrollbarStyling) {
|
if (!_nativeScrollbarStyling) {
|
||||||
if (scrollX) {
|
style(_padding, {
|
||||||
viewportStyleObj.marginBottom = -scrollbarsHideOffset.x;
|
overflow: scrollX || scrollY ? 'hidden' : 'visible',
|
||||||
|
});
|
||||||
contentStyleObj.borderBottom = overlaidX && overlaidHideOffset ? overlaidScrollbarsHideBorderStyle : '';
|
|
||||||
}
|
|
||||||
if (scrollY) {
|
|
||||||
viewportStyleObj.maxWidth = `calc(100% + ${scrollbarsHideOffset.y}px)`;
|
|
||||||
viewportStyleObj[horizontalMarginKey] = -scrollbarsHideOffset.y;
|
|
||||||
|
|
||||||
contentStyleObj[horizontalBorderKey] = overlaidY && overlaidHideOffset ? overlaidScrollbarsHideBorderStyle : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_contentArrange) {
|
|
||||||
style(_contentArrange, {
|
|
||||||
width: scrollY && !showNativeOverlaidScrollbars ? overlaidHideOffset + contentScrollSize.w : '',
|
|
||||||
height: scrollX && !showNativeOverlaidScrollbars ? overlaidHideOffset + contentScrollSize.h : '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -128,16 +131,16 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
scrollTop(_viewport, offsetTop);
|
scrollTop(_viewport, offsetTop);
|
||||||
};
|
};
|
||||||
|
|
||||||
return createLifecycleUpdateFunction(lifecycleHub, (force, updateHints, checkOption) => {
|
return (updateHints, checkOption, force) => {
|
||||||
const { _directionIsRTL, _heightIntrinsic, _sizeChanged, _hostMutation, _contentMutation } = updateHints;
|
const { _directionIsRTL, _heightIntrinsic, _sizeChanged, _hostMutation, _contentMutation, _paddingStyleChanged } = updateHints;
|
||||||
const { _flexboxGlue, _nativeScrollbarStyling, _nativeScrollbarIsOverlaid } = getEnvironment();
|
const { _flexboxGlue, _nativeScrollbarStyling, _nativeScrollbarIsOverlaid } = getEnvironment();
|
||||||
const { _value: showNativeOverlaidScrollbarsOption, _changed: showNativeOverlaidScrollbarsChanged } = checkOption<boolean>(
|
const { _value: showNativeOverlaidScrollbarsOption, _changed: showNativeOverlaidScrollbarsChanged } = checkOption<boolean>(
|
||||||
'nativeScrollbarsOverlaid.show'
|
'nativeScrollbarsOverlaid.show'
|
||||||
);
|
);
|
||||||
const adjustFlexboxGlue = !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged);
|
const adjustFlexboxGlue = !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged);
|
||||||
const showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;
|
const showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;
|
||||||
let overflowAmuntCache: CacheValues<XY<number>> = getCurrentOverflowAmountCache();
|
let overflowAmuntCache: CacheValues<XY<number>> = getCurrentOverflowAmountCache(force);
|
||||||
let contentScrollSizeCache: CacheValues<WH<number>> = getCurrentContentScrollSizeCache();
|
let contentScrollSizeCache: CacheValues<WH<number>> = getCurrentContentScrollSizeCache(force);
|
||||||
|
|
||||||
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
|
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
|
||||||
if (showNativeOverlaidScrollbars) {
|
if (showNativeOverlaidScrollbars) {
|
||||||
@@ -148,20 +151,21 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_sizeChanged || _contentMutation) {
|
if (_sizeChanged || _contentMutation) {
|
||||||
const viewportOffsetSize = offsetSize(_padding);
|
const viewportSize = clientSize(_viewport); // needs to be client Size because possible scrollbar offset
|
||||||
const contentClientSize = offsetSize(_content || _viewport);
|
const viewportScrollSize = scrollSize(_viewport);
|
||||||
const contentArrangeOffsetSize = offsetSize(_contentArrange);
|
const contentClientSize = clientSize(_content || _viewport); // needs to be client Size because applied border for content arrange on content
|
||||||
|
const contentArrangeOffsetSize = clientSize(_contentArrange); // can be offset size aswell
|
||||||
|
|
||||||
contentScrollSizeCache = updateContentScrollSizeCache(force);
|
contentScrollSizeCache = updateContentScrollSizeCache(force);
|
||||||
const { _value: contentScrollSize } = contentScrollSizeCache;
|
const { _value: contentScrollSize } = contentScrollSizeCache;
|
||||||
overflowAmuntCache = updateOverflowAmountCache(force, {
|
overflowAmuntCache = updateOverflowAmountCache(force, {
|
||||||
_contentScrollSize: {
|
_contentScrollSize: {
|
||||||
w: Math.max(contentScrollSize!.w, contentArrangeOffsetSize.w),
|
w: Math.max(contentScrollSize!.w, viewportScrollSize.w, contentArrangeOffsetSize.w),
|
||||||
h: Math.max(contentScrollSize!.h, contentArrangeOffsetSize.h),
|
h: Math.max(contentScrollSize!.h, viewportScrollSize.h, contentArrangeOffsetSize.h),
|
||||||
},
|
},
|
||||||
_viewportSize: {
|
_viewportSize: {
|
||||||
w: viewportOffsetSize.w + Math.max(0, contentClientSize.w - contentScrollSize!.w),
|
w: viewportSize.w + Math.max(0, contentClientSize.w - contentScrollSize!.w),
|
||||||
h: viewportOffsetSize.h + Math.max(0, contentClientSize.h - contentScrollSize!.h),
|
h: viewportSize.h + Math.max(0, contentClientSize.h - contentScrollSize!.h),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -176,6 +180,7 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
const adjustDirection = directionChanged && !_nativeScrollbarStyling;
|
const adjustDirection = directionChanged && !_nativeScrollbarStyling;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
_paddingStyleChanged ||
|
||||||
contentScrollSizeChanged ||
|
contentScrollSizeChanged ||
|
||||||
overflowAmountChanged ||
|
overflowAmountChanged ||
|
||||||
overflowChanged ||
|
overflowChanged ||
|
||||||
@@ -183,7 +188,7 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
adjustDirection ||
|
adjustDirection ||
|
||||||
adjustFlexboxGlue
|
adjustFlexboxGlue
|
||||||
) {
|
) {
|
||||||
const viewportStyle: PlainObject = {
|
const viewportStyle: StyleObject = {
|
||||||
overflowY: '',
|
overflowY: '',
|
||||||
overflowX: '',
|
overflowX: '',
|
||||||
marginTop: '',
|
marginTop: '',
|
||||||
@@ -192,7 +197,7 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
marginLeft: '',
|
marginLeft: '',
|
||||||
maxWidth: '',
|
maxWidth: '',
|
||||||
};
|
};
|
||||||
const contentStyle: PlainObject = {
|
const contentStyle: StyleObject = {
|
||||||
borderTop: '',
|
borderTop: '',
|
||||||
borderRight: '',
|
borderRight: '',
|
||||||
borderBottom: '',
|
borderBottom: '',
|
||||||
@@ -225,9 +230,12 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): LifecycleUp
|
|||||||
// TODO: Test without content
|
// TODO: Test without content
|
||||||
// TODO: Test without padding
|
// TODO: Test without padding
|
||||||
// TODO: hide host || padding overflow if scroll x or y
|
// TODO: hide host || padding overflow if scroll x or y
|
||||||
|
// TODO: fix false overflow bug (fractal scroll size)
|
||||||
|
// TODO: add trinsic lifecycle
|
||||||
|
// TODO: remove lifecycleHub get set padding if not needed
|
||||||
|
|
||||||
style(_viewport, viewportStyle);
|
style(_viewport, viewportStyle);
|
||||||
style(_content, contentStyle);
|
style(_content, contentStyle);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { createCache, topRightBottomLeft, TRBL, equalTRBL, style } from 'support';
|
||||||
|
import { LifecycleHub, Lifecycle } from 'lifecycles/lifecycleHub';
|
||||||
|
import { StyleObject } from 'typings';
|
||||||
|
import { getEnvironment } from 'environment';
|
||||||
|
|
||||||
|
export const createPaddingLifecycle = (lifecycleHub: LifecycleHub): Lifecycle => {
|
||||||
|
const { _host, _padding, _viewport } = lifecycleHub._structureSetup._targetObj;
|
||||||
|
const { _update: updatePaddingCache, _current: currentPaddingCache } = createCache(() => topRightBottomLeft(_host, 'padding'), {
|
||||||
|
_equal: equalTRBL,
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
const onTrinsicChanged = (heightIntrinsic: CacheValues<boolean>) => {
|
||||||
|
const { _changed, _value } = heightIntrinsic;
|
||||||
|
if (_changed) {
|
||||||
|
style(_content, { height: _value ? 'auto' : '100%' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
return (updateHints, checkOption, force) => {
|
||||||
|
let { _value: padding, _changed: paddingChanged } = currentPaddingCache(force);
|
||||||
|
const { _nativeScrollbarStyling } = getEnvironment();
|
||||||
|
const { _sizeChanged, _directionIsRTL } = updateHints;
|
||||||
|
const { _value: directionIsRTL, _changed: directionRTLChanged } = _directionIsRTL;
|
||||||
|
const { _value: paddingAbsolute, _changed: paddingAbsoluteChanged } = checkOption('paddingAbsolute');
|
||||||
|
|
||||||
|
if (_sizeChanged || paddingChanged) {
|
||||||
|
({ _value: padding, _changed: paddingChanged } = updatePaddingCache(force));
|
||||||
|
}
|
||||||
|
|
||||||
|
const paddingStyleChanged = paddingAbsoluteChanged || directionRTLChanged || paddingChanged;
|
||||||
|
|
||||||
|
if (paddingStyleChanged) {
|
||||||
|
// if there is no padding element and no scrollbar styling padding absolute isn't supported
|
||||||
|
const { _value: padding } = updatePaddingCache(force);
|
||||||
|
const paddingRelative = !paddingAbsolute || (!_padding && !_nativeScrollbarStyling);
|
||||||
|
const paddingHorizontal = padding!.r + padding!.l;
|
||||||
|
const paddingVertical = padding!.t + padding!.b;
|
||||||
|
const paddingStyle: StyleObject = {
|
||||||
|
marginTop: '',
|
||||||
|
marginRight: '',
|
||||||
|
marginBottom: '',
|
||||||
|
marginLeft: '',
|
||||||
|
top: '',
|
||||||
|
right: '',
|
||||||
|
bottom: '',
|
||||||
|
left: '',
|
||||||
|
maxWidth: '',
|
||||||
|
};
|
||||||
|
const viewportStyle: StyleObject = {
|
||||||
|
paddingTop: '',
|
||||||
|
paddingRight: '',
|
||||||
|
paddingBottom: '',
|
||||||
|
paddingLeft: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (paddingRelative) {
|
||||||
|
const horizontalPositionKey = directionIsRTL ? 'right' : 'left';
|
||||||
|
const horizontalPositionValue = directionIsRTL ? padding!.r : padding!.l;
|
||||||
|
const horizontalMarginKey = directionIsRTL ? 'marginLeft' : 'marginRight';
|
||||||
|
|
||||||
|
paddingStyle.top = -padding!.t;
|
||||||
|
paddingStyle[horizontalPositionKey] = -horizontalPositionValue;
|
||||||
|
paddingStyle.marginBottom = -paddingVertical;
|
||||||
|
paddingStyle[horizontalMarginKey] = -paddingHorizontal;
|
||||||
|
paddingStyle.maxWidth = `calc(100% + ${paddingHorizontal}px)`;
|
||||||
|
|
||||||
|
viewportStyle.paddingTop = padding!.t;
|
||||||
|
viewportStyle.paddingRight = padding!.r;
|
||||||
|
viewportStyle.paddingBottom = padding!.b;
|
||||||
|
viewportStyle.paddingLeft = padding!.l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is no padding element apply the style to the viewport element instead
|
||||||
|
style(_padding || _viewport, paddingStyle);
|
||||||
|
style(_viewport, viewportStyle);
|
||||||
|
|
||||||
|
lifecycleHub._setPadding(padding);
|
||||||
|
lifecycleHub._setPaddingStyle(!_padding ? paddingStyle : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
_paddingStyleChanged: paddingStyleChanged,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { each, keys } from 'support/utils';
|
import { each, keys } from 'support/utils';
|
||||||
import { isString, isNumber, isArray } from 'support/utils/types';
|
import { isString, isNumber, isArray } from 'support/utils/types';
|
||||||
import { PlainObject } from 'typings';
|
import { PlainObject, StyleObject } from 'typings';
|
||||||
|
|
||||||
export interface TRBL {
|
export interface TRBL {
|
||||||
t: number;
|
t: number;
|
||||||
@@ -9,7 +9,6 @@ export interface TRBL {
|
|||||||
l: number;
|
l: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type CssStyles = { [key: string]: string | number };
|
|
||||||
const cssNumber = {
|
const cssNumber = {
|
||||||
animationiterationcount: 1,
|
animationiterationcount: 1,
|
||||||
columncount: 1,
|
columncount: 1,
|
||||||
@@ -49,10 +48,10 @@ const setCSSVal = (elm: HTMLElement | null | undefined, prop: string, val: strin
|
|||||||
* @param elm The element to which the styles shall be applied to / be read from.
|
* @param elm The element to which the styles shall be applied to / be read from.
|
||||||
* @param styles The styles which shall be set or read.
|
* @param styles The styles which shall be set or read.
|
||||||
*/
|
*/
|
||||||
export function style(elm: HTMLElement | null | undefined, styles: CssStyles): void;
|
export function style(elm: HTMLElement | null | undefined, styles: StyleObject): void;
|
||||||
export function style(elm: HTMLElement | null | undefined, styles: string): string;
|
export function style(elm: HTMLElement | null | undefined, styles: string): string;
|
||||||
export function style(elm: HTMLElement | null | undefined, styles: Array<string> | string): { [key: string]: string };
|
export function style(elm: HTMLElement | null | undefined, styles: Array<string> | string): { [key: string]: string };
|
||||||
export function style(elm: HTMLElement | null | undefined, styles: CssStyles | Array<string> | string): { [key: string]: string } | string | void {
|
export function style(elm: HTMLElement | null | undefined, styles: StyleObject | Array<string> | string): { [key: string]: string } | string | void {
|
||||||
const getSingleStyle = isString(styles);
|
const getSingleStyle = isString(styles);
|
||||||
const getStyles = isArray(styles) || getSingleStyle;
|
const getStyles = isArray(styles) || getSingleStyle;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
export type PlainObject<T = any> = { [name: string]: T };
|
export type PlainObject<T = any> = { [name: string]: T };
|
||||||
|
|
||||||
|
export type StyleObject = {
|
||||||
|
[K in keyof CSSStyleDeclaration]?: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
export type InternalVersionOf<T> = {
|
export type InternalVersionOf<T> = {
|
||||||
[K in keyof T as `_${Uncapitalize<string & K>}`]: T[K];
|
[K in keyof T as `_${Uncapitalize<string & K>}`]: T[K];
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import { createDiv, appendChildren, parent, style, on, off, addClass, WH, XY, cl
|
|||||||
import { OverlayScrollbars } from 'overlayscrollbars/OverlayScrollbars';
|
import { OverlayScrollbars } from 'overlayscrollbars/OverlayScrollbars';
|
||||||
|
|
||||||
const targetElm = document.querySelector('#target') as HTMLElement;
|
const targetElm = document.querySelector('#target') as HTMLElement;
|
||||||
window.os = OverlayScrollbars(targetElm);
|
window.os = OverlayScrollbars({ target: targetElm, padding: null });
|
||||||
|
|
||||||
export const resize = (element: HTMLElement) => {
|
export const resize = (element: HTMLElement) => {
|
||||||
const strMouseTouchDownEvent = 'mousedown touchstart';
|
const strMouseTouchDownEvent = 'mousedown touchstart';
|
||||||
|
|||||||
Reference in New Issue
Block a user