WIP: make content element obsolve

This commit is contained in:
Rene Haas
2021-04-03 13:30:08 +02:00
parent ea6794eca8
commit 7db7fd551d
9 changed files with 136 additions and 53 deletions
+1 -1
View File
@@ -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;
@@ -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 {