mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-22 23:54:07 +03:00
WIP: make content element obsolve
This commit is contained in:
@@ -5,8 +5,8 @@ export const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexbox
|
||||
export const classNameHost = 'os-host';
|
||||
export const classNamePadding = 'os-padding';
|
||||
export const classNameViewport = 'os-viewport';
|
||||
export const classNameViewportArrange = `${classNameViewport}-arrange`;
|
||||
export const classNameContent = 'os-content';
|
||||
export const classNameContentArrange = `${classNameContent}-arrange`;
|
||||
export const classNameViewportScrollbarStyling = `${classNameViewport}-scrollbar-styled`;
|
||||
|
||||
export const classNameSizeObserver = 'os-size-observer';
|
||||
|
||||
@@ -30,6 +30,7 @@ export interface Environment {
|
||||
_nativeScrollbarStyling: boolean;
|
||||
_rtlScrollBehavior: { n: boolean; i: boolean };
|
||||
_flexboxGlue: boolean;
|
||||
_cssCustomProperties: boolean;
|
||||
_addListener(listener: OnEnvironmentChanged): void;
|
||||
_removeListener(listener: OnEnvironmentChanged): void;
|
||||
}
|
||||
@@ -135,6 +136,7 @@ const createEnvironment = (): Environment => {
|
||||
_nativeScrollbarSize: nativeScrollbarSize,
|
||||
_nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,
|
||||
_nativeScrollbarStyling: nativeScrollbarStyling,
|
||||
_cssCustomProperties: style(envElm, 'zIndex') === '-1',
|
||||
_rtlScrollBehavior: getRtlScrollBehavior(envElm, envChildElm),
|
||||
_flexboxGlue: getFlexboxGlue(envElm, envChildElm),
|
||||
_addListener(listener: OnEnvironmentChanged): void {
|
||||
@@ -145,6 +147,8 @@ const createEnvironment = (): Environment => {
|
||||
},
|
||||
};
|
||||
|
||||
console.log(env);
|
||||
|
||||
removeAttr(envElm, 'style');
|
||||
removeElements(envElm);
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@ import { StyleObject } from 'typings';
|
||||
|
||||
export type LifecycleCheckOption = <T>(path: string) => LifecycleOptionInfo<T>;
|
||||
|
||||
export interface PaddingInfo {
|
||||
_absolute: boolean;
|
||||
_padding: TRBL;
|
||||
}
|
||||
|
||||
export interface LifecycleOptionInfo<T> {
|
||||
readonly _value: T;
|
||||
_changed: boolean;
|
||||
@@ -42,8 +47,8 @@ export interface LifecycleHubInstance {
|
||||
export interface LifecycleHub {
|
||||
_options: Options;
|
||||
_structureSetup: StructureSetup;
|
||||
_getPadding(): TRBL;
|
||||
_setPadding(newPadding?: TRBL | null): void;
|
||||
_getPaddingInfo(): PaddingInfo;
|
||||
_setPaddingInfo(newPadding?: PaddingInfo | null): void;
|
||||
_getPaddingStyle(): StyleObject;
|
||||
_setPaddingStyle(newPaddingStlye?: StyleObject | null): void;
|
||||
_getViewportOverflowScroll(): XY<boolean>;
|
||||
@@ -54,7 +59,15 @@ 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 paddingFallback: TRBL = { t: 0, r: 0, b: 0, l: 0 };
|
||||
const paddingInfoFallback: PaddingInfo = {
|
||||
_absolute: false,
|
||||
_padding: {
|
||||
t: 0,
|
||||
r: 0,
|
||||
b: 0,
|
||||
l: 0,
|
||||
},
|
||||
};
|
||||
const viewportPaddingStyleFallback: StyleObject = {
|
||||
marginTop: 0,
|
||||
marginRight: 0,
|
||||
@@ -77,7 +90,7 @@ const heightIntrinsicCacheValuesFallback: CacheValues<boolean> = {
|
||||
};
|
||||
|
||||
export const createLifecycleHub = (options: Options, structureSetup: StructureSetup): LifecycleHubInstance => {
|
||||
let padding = paddingFallback;
|
||||
let paddingInfo = paddingInfoFallback;
|
||||
let viewportPaddingStyle = viewportPaddingStyleFallback;
|
||||
let viewportOverflowScroll = viewportOverflowScrollFallback;
|
||||
const { _host, _viewport, _content, _contentArrange } = structureSetup._targetObj;
|
||||
@@ -91,9 +104,9 @@ export const createLifecycleHub = (options: Options, structureSetup: StructureSe
|
||||
const instance: LifecycleHub = {
|
||||
_options: options,
|
||||
_structureSetup: structureSetup,
|
||||
_getPadding: () => padding,
|
||||
_setPadding(newPadding) {
|
||||
padding = newPadding || paddingFallback;
|
||||
_getPaddingInfo: () => paddingInfo,
|
||||
_setPaddingInfo(newPaddingInfo) {
|
||||
paddingInfo = newPaddingInfo || paddingInfoFallback;
|
||||
},
|
||||
_getPaddingStyle: () => viewportPaddingStyle,
|
||||
_setPaddingStyle(newPaddingStlye) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
createCache,
|
||||
attr,
|
||||
WH,
|
||||
XY,
|
||||
equalXY,
|
||||
@@ -17,7 +18,7 @@ import { LifecycleHub, Lifecycle } from 'lifecycles/lifecycleHub';
|
||||
import { getEnvironment } from 'environment';
|
||||
import { OverflowBehavior } from 'options';
|
||||
import { StyleObject } from 'typings';
|
||||
import { classNameViewportScrollbarStyling } from 'classnames';
|
||||
import { classNameViewport, classNameViewportArrange, classNameViewportScrollbarStyling } from 'classnames';
|
||||
|
||||
interface ContentScrollSizeCacheContext {
|
||||
_viewportRect: DOMRect;
|
||||
@@ -44,7 +45,7 @@ const overlaidScrollbarsHideOffset = 42;
|
||||
const overlaidScrollbarsHideBorderStyle = `${overlaidScrollbarsHideOffset}px solid transparent`;
|
||||
|
||||
export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle => {
|
||||
const { _structureSetup, _getPaddingStyle } = lifecycleHub;
|
||||
const { _structureSetup, _getPaddingStyle, _getPaddingInfo } = lifecycleHub;
|
||||
const { _host, _padding, _viewport, _content, _contentArrange } = _structureSetup._targetObj;
|
||||
const { _update: updateContentScrollSizeCache, _current: getCurrentContentScrollSizeCache } = createCache<
|
||||
WH<number>,
|
||||
@@ -76,14 +77,16 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle =
|
||||
});
|
||||
|
||||
if (heightIntrinsic) {
|
||||
const { _absolute: paddingAbsolute, _padding: padding } = _getPaddingInfo();
|
||||
const { _overflowScroll, _scrollbarsHideOffset } = viewportOverflowState;
|
||||
const hostBCR = getBoundingClientRect(_host);
|
||||
const hostOffsetSize = offsetSize(_host);
|
||||
const hostClientSize = clientSize(_host);
|
||||
const paddingAbsoluteVertical = paddingAbsolute ? padding.b + padding.t : 0;
|
||||
const clientSizeWithoutRounding = hostClientSize.h + (hostBCR.height - hostOffsetSize.h);
|
||||
|
||||
style(_viewport, {
|
||||
maxHeight: clientSizeWithoutRounding + (_overflowScroll.x ? _scrollbarsHideOffset.x : 0),
|
||||
maxHeight: clientSizeWithoutRounding + (_overflowScroll.x ? _scrollbarsHideOffset.x : 0) - paddingAbsoluteVertical,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -92,7 +95,7 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle =
|
||||
const { _nativeScrollbarSize, _nativeScrollbarIsOverlaid, _nativeScrollbarStyling } = getEnvironment();
|
||||
const { x: overlaidX, y: overlaidY } = _nativeScrollbarIsOverlaid;
|
||||
const determineOverflow = !viewportStyleObj;
|
||||
const arrangeHideOffset = _content && !_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;
|
||||
const arrangeHideOffset = !_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;
|
||||
const styleObj = determineOverflow ? style(_viewport, ['overflowX', 'overflowY']) : viewportStyleObj;
|
||||
const scroll = {
|
||||
x: styleObj!.overflowX === 'scroll',
|
||||
@@ -150,23 +153,42 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle =
|
||||
directionIsRTL: boolean,
|
||||
contentStyleObj?: StyleObject
|
||||
) => {
|
||||
const { _scrollbarsHideOffset } = viewportOverflowState;
|
||||
const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;
|
||||
const horizontalBorderKey = directionIsRTL ? 'borderLeft' : 'borderRight';
|
||||
const { _nativeScrollbarStyling, _nativeScrollbarIsOverlaid } = getEnvironment();
|
||||
if ((_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) && !_nativeScrollbarStyling) {
|
||||
const { _scrollbarsHideOffset } = viewportOverflowState;
|
||||
const { _absolute: paddingAbsolute, _padding: padding } = _getPaddingInfo();
|
||||
const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;
|
||||
const horizontalPaddingKey = directionIsRTL ? 'paddingLeft' : 'paddingRight';
|
||||
const horizontalPaddingValue = paddingAbsolute ? 0 : directionIsRTL ? padding.l : padding.r;
|
||||
const verticalPaddingValue = paddingAbsolute ? 0 : padding.b;
|
||||
|
||||
if (_contentArrange && contentStyleObj) {
|
||||
// horizontal
|
||||
contentStyleObj[horizontalBorderKey] = hideOffsetY ? overlaidScrollbarsHideBorderStyle : '';
|
||||
style(_viewport, {
|
||||
[horizontalPaddingKey]: horizontalPaddingValue + hideOffsetY,
|
||||
paddingBottom: verticalPaddingValue + hideOffsetX,
|
||||
});
|
||||
|
||||
// vertical
|
||||
contentStyleObj.borderBottom = hideOffsetX ? overlaidScrollbarsHideBorderStyle : '';
|
||||
// adjust content arrange / before element
|
||||
if (_contentArrange) {
|
||||
const { sheet } = _contentArrange;
|
||||
if (sheet) {
|
||||
const { cssRules } = sheet;
|
||||
if (cssRules) {
|
||||
if (!cssRules.length) {
|
||||
sheet.insertRule(`#${attr(_contentArrange, 'id')} + .${classNameViewportArrange}::before {}`, 0);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const ruleStyle = cssRules[0].style;
|
||||
|
||||
ruleStyle.width = hideOffsetY ? `${contentScrollSize.w}px` : '0px';
|
||||
ruleStyle.height = hideOffsetX ? `${contentScrollSize.h}px` : '0px';
|
||||
|
||||
addClass(_viewport, classNameViewportArrange);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
// adjust content arrange (content arrange doesn't exist if its not needed)
|
||||
style(_contentArrange, {
|
||||
width: hideOffsetY ? hideOffsetY + contentScrollSize.w : '',
|
||||
height: hideOffsetX ? hideOffsetX + contentScrollSize.h : '',
|
||||
});
|
||||
};
|
||||
|
||||
const hideNativeScrollbars = (viewportOverflowState: ViewportOverflowState, directionIsRTL: boolean, viewportStyleObj: StyleObject) => {
|
||||
@@ -220,37 +242,59 @@ export const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle =
|
||||
fixFlexboxGlue(preMeasureViewportOverflowState, !!heightIntrinsic);
|
||||
}
|
||||
|
||||
if (_sizeChanged || _contentMutation) {
|
||||
if (_sizeChanged || _contentMutation || directionChanged) {
|
||||
removeClass(_viewport, classNameViewportArrange);
|
||||
style(_viewport, {
|
||||
paddingRight: _getPaddingInfo()._padding.r,
|
||||
paddingBottom: _getPaddingInfo()._padding.b,
|
||||
marginRight: -_getPaddingInfo()._padding.r - _getPaddingInfo()._padding.l,
|
||||
marginBottom: -_getPaddingInfo()._padding.b - _getPaddingInfo()._padding.t,
|
||||
});
|
||||
|
||||
const viewportRect = getBoundingClientRect(_viewport);
|
||||
const viewportOffsetSize = offsetSize(_viewport);
|
||||
const contentClientSize = clientSize(_content || _viewport); // needs to be client Size because applied border for content arrange on content
|
||||
const contentClientSize = clientSize(_viewport); // needs to be client Size because applied border for content arrange on content
|
||||
let viewportScrollSize = fixScrollSizeRounding(scrollSize(_viewport), viewportOffsetSize, viewportRect);
|
||||
let viewportClientSize = clientSize(_viewport);
|
||||
|
||||
const { _value: contentScrollSize, _changed: contentScrollSizeChanged } = (contentScrollSizeCache = updateContentScrollSizeCache(force, {
|
||||
let { _value: contentScrollSize, _changed: contentScrollSizeChanged } = (contentScrollSizeCache = updateContentScrollSizeCache(force, {
|
||||
_viewportRect: viewportRect,
|
||||
_viewportOffsetSize: viewportOffsetSize,
|
||||
_viewportScrollSize: viewportScrollSize,
|
||||
}));
|
||||
// re measure is only required if we rely on content arrange to hide native scrollbars (no native scrollbar styling and overlaid scrollbars)
|
||||
const reMeasureRequired = contentScrollSizeChanged && !showNativeOverlaidScrollbars && _contentArrange;
|
||||
const reMeasureRequired = contentScrollSizeChanged && !showNativeOverlaidScrollbars;
|
||||
|
||||
if (reMeasureRequired) {
|
||||
setContentArrange(
|
||||
preMeasureViewportOverflowState || getViewportOverflowState(showNativeOverlaidScrollbars),
|
||||
contentScrollSize!,
|
||||
directionIsRTL!
|
||||
);
|
||||
if (true) {
|
||||
const viewportStyle: StyleObject = {
|
||||
overflowY: '',
|
||||
overflowX: '',
|
||||
marginTop: '',
|
||||
marginRight: '',
|
||||
marginBottom: '',
|
||||
marginLeft: '',
|
||||
maxWidth: '',
|
||||
};
|
||||
setContentArrange(getViewportOverflowState(showNativeOverlaidScrollbars), contentScrollSize!, directionIsRTL!);
|
||||
hideNativeScrollbars(getViewportOverflowState(showNativeOverlaidScrollbars), directionIsRTL!, viewportStyle);
|
||||
|
||||
style(_viewport, viewportStyle);
|
||||
|
||||
viewportClientSize = clientSize(_viewport);
|
||||
viewportScrollSize = fixScrollSizeRounding(scrollSize(_viewport), offsetSize(_viewport), getBoundingClientRect(_viewport));
|
||||
|
||||
({ _value: contentScrollSize, _changed: contentScrollSizeChanged } = contentScrollSizeCache = updateContentScrollSizeCache(force, {
|
||||
_viewportRect: viewportRect,
|
||||
_viewportOffsetSize: viewportOffsetSize,
|
||||
_viewportScrollSize: viewportScrollSize,
|
||||
}));
|
||||
}
|
||||
|
||||
const contentArrangeOffsetSize = clientSize(_contentArrange);
|
||||
//const contentArrangeOffsetSize = clientSize(_contentArrange);
|
||||
overflowAmuntCache = updateOverflowAmountCache(force, {
|
||||
_contentScrollSize: {
|
||||
w: Math.max(contentScrollSize!.w, viewportScrollSize.w, contentArrangeOffsetSize.w),
|
||||
h: Math.max(contentScrollSize!.h, viewportScrollSize.h, contentArrangeOffsetSize.h),
|
||||
w: Math.max(contentScrollSize!.w, viewportScrollSize.w),
|
||||
h: Math.max(contentScrollSize!.h, viewportScrollSize.h),
|
||||
},
|
||||
_viewportSize: {
|
||||
w: viewportClientSize.w + Math.max(0, contentClientSize.w - contentScrollSize!.w),
|
||||
|
||||
@@ -76,7 +76,10 @@ export const createPaddingLifecycle = (lifecycleHub: LifecycleHub): Lifecycle =>
|
||||
style(_padding || _viewport, paddingStyle);
|
||||
style(_viewport, viewportStyle);
|
||||
|
||||
lifecycleHub._setPadding(padding);
|
||||
lifecycleHub._setPaddingInfo({
|
||||
_absolute: !paddingRelative,
|
||||
_padding: padding!,
|
||||
});
|
||||
lifecycleHub._setPaddingStyle(!_padding ? paddingStyle : null);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
@import './structurelifecycle.scss';
|
||||
|
||||
.os-environment {
|
||||
--css-custom-prop: -1;
|
||||
position: fixed;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
overflow: scroll;
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
z-index: var(--css-custom-prop);
|
||||
|
||||
div {
|
||||
width: 200%;
|
||||
@@ -68,7 +70,7 @@
|
||||
}
|
||||
.os-environment,
|
||||
.os-viewport {
|
||||
-ms-overflow-style: scrollbar !important;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar !important;
|
||||
}
|
||||
.os-viewport-scrollbar-styled.os-environment,
|
||||
.os-viewport-scrollbar-styled.os-viewport {
|
||||
@@ -85,10 +87,15 @@
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.os-content-arrange {
|
||||
min-width: 1px;
|
||||
min-height: 1px;
|
||||
z-index: -1;
|
||||
.os-viewport-arrange::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
min-width: 1px;
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.os-host {
|
||||
padding: 5px 50px 15px 20px;
|
||||
}
|
||||
|
||||
@@ -12,14 +12,15 @@ import {
|
||||
removeClass,
|
||||
push,
|
||||
runEach,
|
||||
prependChildren,
|
||||
insertBefore,
|
||||
attr,
|
||||
} from 'support';
|
||||
import {
|
||||
classNameHost,
|
||||
classNamePadding,
|
||||
classNameViewport,
|
||||
classNameViewportArrange,
|
||||
classNameContent,
|
||||
classNameContentArrange,
|
||||
classNameViewportScrollbarStyling,
|
||||
} from 'classnames';
|
||||
import { getEnvironment } from 'environment';
|
||||
@@ -36,7 +37,7 @@ export interface OSTargetContext {
|
||||
|
||||
export interface PreparedOSTargetObject extends Required<InternalVersionOf<OSTargetObject>> {
|
||||
_host: HTMLElement;
|
||||
_contentArrange: HTMLElement | null;
|
||||
_contentArrange: HTMLStyleElement | null;
|
||||
}
|
||||
|
||||
export interface StructureSetup {
|
||||
@@ -50,6 +51,16 @@ const unwrap = (elm: HTMLElement | null | undefined) => {
|
||||
removeElements(elm);
|
||||
};
|
||||
|
||||
let contentArrangeCounter = 0;
|
||||
const createUniqueContentArrangeElement = () => {
|
||||
const elm = document.createElement('style');
|
||||
|
||||
attr(elm, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`);
|
||||
contentArrangeCounter++;
|
||||
|
||||
return elm;
|
||||
};
|
||||
|
||||
export const createStructureSetup = (target: OSTarget | OSTargetObject): StructureSetup => {
|
||||
const targetIsElm = isHTMLElement(target);
|
||||
const osTargetObj: InternalVersionOf<OSTargetObject> = targetIsElm
|
||||
@@ -160,14 +171,14 @@ export const createStructureSetup = (target: OSTarget | OSTargetObject): Structu
|
||||
_host,
|
||||
};
|
||||
|
||||
const { _nativeScrollbarStyling, _nativeScrollbarIsOverlaid } = getEnvironment();
|
||||
const { _nativeScrollbarStyling, _nativeScrollbarIsOverlaid, _cssCustomProperties } = getEnvironment();
|
||||
if (_nativeScrollbarStyling) {
|
||||
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));
|
||||
} else if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
|
||||
if (obj._content) {
|
||||
const contentArrangeElm = createDiv(classNameContentArrange);
|
||||
if (true) {
|
||||
const contentArrangeElm = createUniqueContentArrangeElement();
|
||||
|
||||
prependChildren(_viewport, contentArrangeElm);
|
||||
insertBefore(_viewport, contentArrangeElm);
|
||||
push(destroyFns, removeElements.bind(0, contentArrangeElm));
|
||||
|
||||
obj._contentArrange = contentArrangeElm;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { createDiv, appendChildren, parent, style, on, off, addClass, WH, XY, cl
|
||||
import { OverlayScrollbars } from 'overlayscrollbars/OverlayScrollbars';
|
||||
|
||||
const targetElm = document.querySelector('#target') as HTMLElement;
|
||||
window.os = OverlayScrollbars({ target: targetElm, padding: null });
|
||||
window.os = OverlayScrollbars({ target: targetElm, padding: null, content: null });
|
||||
|
||||
export const resize = (element: HTMLElement) => {
|
||||
const strMouseTouchDownEvent = 'mousedown touchstart';
|
||||
|
||||
@@ -57,6 +57,7 @@ body {
|
||||
border: 1px solid black;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#end::before {
|
||||
|
||||
Reference in New Issue
Block a user