mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-21 11:54:06 +03:00
host without classname & clipping with overflow visible
This commit is contained in:
+77
-68
@@ -687,12 +687,13 @@ const createState = initialState => {
|
||||
const classNameEnvironment = 'os-environment';
|
||||
const classNameEnvironmentFlexboxGlue = `${classNameEnvironment}-flexbox-glue`;
|
||||
const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`;
|
||||
const classNameHost = 'os-host';
|
||||
const dataAttributeHost = 'data-overlayscrollbars';
|
||||
const classNamePadding = 'os-padding';
|
||||
const classNameViewport = 'os-viewport';
|
||||
const classNameViewportArrange = `${classNameViewport}-arrange`;
|
||||
const classNameContent = 'os-content';
|
||||
const classNameViewportScrollbarStyling = `${classNameViewport}-scrollbar-styled`;
|
||||
const classNameOverflowVisible = `os-overflow-visible`;
|
||||
const classNameSizeObserver = 'os-size-observer';
|
||||
const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;
|
||||
const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;
|
||||
@@ -983,15 +984,20 @@ const createUniqueViewportArrangeElement = () => {
|
||||
return result;
|
||||
};
|
||||
|
||||
const staticCreationFromStrategy = (target, initializationValue, strategy, elementClass) => {
|
||||
const staticCreationFromStrategy = (target, initializationValue, strategy) => {
|
||||
const result = initializationValue || (isFunction(strategy) ? strategy(target) : strategy);
|
||||
return result || createDiv(elementClass);
|
||||
return result || createDiv();
|
||||
};
|
||||
|
||||
const dynamicCreationFromStrategy = (target, initializationValue, strategy, elementClass) => {
|
||||
const dynamicCreationFromStrategy = (target, initializationValue, strategy) => {
|
||||
const takeInitializationValue = isBoolean(initializationValue) || initializationValue;
|
||||
const result = takeInitializationValue ? initializationValue : isFunction(strategy) ? strategy(target) : strategy;
|
||||
return result === true ? createDiv(elementClass) : result;
|
||||
return result === true ? createDiv() : result;
|
||||
};
|
||||
|
||||
const addDataAttrHost = elm => {
|
||||
attr(elm, dataAttributeHost, '');
|
||||
return removeAttr.bind(0, elm, dataAttributeHost);
|
||||
};
|
||||
|
||||
const createStructureSetupElements = target => {
|
||||
@@ -1017,10 +1023,10 @@ const createStructureSetupElements = target => {
|
||||
const wnd = ownerDocument.defaultView;
|
||||
const evaluatedTargetObj = {
|
||||
_target: targetElement,
|
||||
_host: isTextarea ? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy, classNameHost) : targetElement,
|
||||
_viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy, classNameViewport),
|
||||
_padding: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.padding, paddingInitializationStrategy, classNamePadding),
|
||||
_content: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.content, contentInitializationStrategy, classNameContent),
|
||||
_host: isTextarea ? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy) : targetElement,
|
||||
_viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy),
|
||||
_padding: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.padding, paddingInitializationStrategy),
|
||||
_content: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.content, contentInitializationStrategy),
|
||||
_viewportArrange: createUniqueViewportArrangeElement(),
|
||||
_windowElm: wnd,
|
||||
_documentElm: ownerDocument,
|
||||
@@ -1049,6 +1055,10 @@ const createStructureSetupElements = target => {
|
||||
const isTextareaHostGenerated = isTextarea && elementIsGenerated(_host);
|
||||
const targetContents = isTextarea ? _target : contents([_content, _viewport, _padding, _host, _target].find(elm => elementIsGenerated(elm) === false));
|
||||
const contentSlot = _content || _viewport;
|
||||
const removeHostDataAttr = addDataAttrHost(_host);
|
||||
const removePaddingClass = addClass(_padding, classNamePadding);
|
||||
const removeViewportClass = addClass(_viewport, classNameViewport);
|
||||
const removeContentClass = addClass(_content, classNameContent);
|
||||
|
||||
if (isTextareaHostGenerated) {
|
||||
insertAfter(_target, _host);
|
||||
@@ -1062,15 +1072,11 @@ const createStructureSetupElements = target => {
|
||||
appendChildren(_host, _padding);
|
||||
appendChildren(_padding || _host, _viewport);
|
||||
appendChildren(_viewport, _content);
|
||||
addClass(_host, classNameHost);
|
||||
addClass(_padding, classNamePadding);
|
||||
addClass(_viewport, classNameViewport);
|
||||
addClass(_content, classNameContent);
|
||||
push(destroyFns, () => {
|
||||
if (targetIsElm) {
|
||||
appendChildren(_host, contents(contentSlot));
|
||||
removeElements(_padding || _viewport);
|
||||
removeClass(_host, classNameHost);
|
||||
removeHostDataAttr();
|
||||
} else {
|
||||
if (elementIsGenerated(_content)) {
|
||||
unwrap(_content);
|
||||
@@ -1084,10 +1090,10 @@ const createStructureSetupElements = target => {
|
||||
unwrap(_padding);
|
||||
}
|
||||
|
||||
removeClass(_host, classNameHost);
|
||||
removeClass(_padding, classNamePadding);
|
||||
removeClass(_viewport, classNameViewport);
|
||||
removeClass(_content, classNameContent);
|
||||
removeHostDataAttr();
|
||||
removePaddingClass();
|
||||
removeViewportClass();
|
||||
removeContentClass();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1201,6 +1207,7 @@ const createPaddingUpdate = (structureSetupElements, state) => {
|
||||
const {
|
||||
max
|
||||
} = Math;
|
||||
const strVisible = 'visible';
|
||||
const overlaidScrollbarsHideOffset = 42;
|
||||
const whCacheOptions = {
|
||||
_equal: equalWH,
|
||||
@@ -1217,40 +1224,27 @@ const xyCacheOptions = {
|
||||
}
|
||||
};
|
||||
|
||||
const setAxisOverflowStyle = (horizontal, overflowAmount, behavior, styleObj) => {
|
||||
const overflowKey = horizontal ? 'overflowX' : 'overflowY';
|
||||
const behaviorIsVisible = behavior.indexOf('visible') === 0;
|
||||
const behaviorIsVisibleHidden = behavior === 'visible-hidden';
|
||||
const behaviorIsScroll = behavior === 'scroll';
|
||||
const hasOverflow = overflowAmount > 0;
|
||||
|
||||
if (behaviorIsVisible) {
|
||||
styleObj[overflowKey] = 'visible';
|
||||
}
|
||||
|
||||
if (behaviorIsScroll && hasOverflow) {
|
||||
styleObj[overflowKey] = behavior;
|
||||
}
|
||||
|
||||
return [behaviorIsVisible, behaviorIsVisibleHidden ? 'hidden' : 'scroll'];
|
||||
};
|
||||
|
||||
const getOverflowAmount = (viewportScrollSize, viewportClientSize, sizeFraction) => {
|
||||
const tollerance = window.devicePixelRatio % 2 !== 0 ? 1 : 0;
|
||||
const tollerance = window.devicePixelRatio % 1 !== 0 ? 1 : 0;
|
||||
const amount = {
|
||||
w: max(0, viewportScrollSize.w - viewportClientSize.w - max(0, sizeFraction.w)),
|
||||
h: max(0, viewportScrollSize.h - viewportClientSize.h - max(0, sizeFraction.h))
|
||||
};
|
||||
return {
|
||||
w: amount.w >= tollerance ? amount.w : 0,
|
||||
h: amount.h >= tollerance ? amount.h : 0
|
||||
w: amount.w > tollerance ? amount.w : 0,
|
||||
h: amount.h > tollerance ? amount.h : 0
|
||||
};
|
||||
};
|
||||
|
||||
const conditionalClass = (elm, classNames, condition) => condition ? addClass(elm, classNames) : removeClass(elm, classNames);
|
||||
|
||||
const overflowIsVisible = overflowBehavior => overflowBehavior.indexOf(strVisible) === 0;
|
||||
|
||||
const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
const [getState, setState] = state;
|
||||
const {
|
||||
_host,
|
||||
_padding,
|
||||
_viewport,
|
||||
_viewportArrange
|
||||
} = structureSetupElements;
|
||||
@@ -1274,7 +1268,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
if (heightIntrinsic) {
|
||||
const {
|
||||
_paddingAbsolute,
|
||||
_padding
|
||||
_padding: padding
|
||||
} = getState();
|
||||
const {
|
||||
_overflowScroll,
|
||||
@@ -1283,7 +1277,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
const fSize = fractionalSize(_host);
|
||||
const hostClientSize = clientSize(_host);
|
||||
const isContentBox = style(_viewport, 'boxSizing') === 'content-box';
|
||||
const paddingVertical = _paddingAbsolute || isContentBox ? _padding.b + _padding.t : 0;
|
||||
const paddingVertical = _paddingAbsolute || isContentBox ? padding.b + padding.t : 0;
|
||||
const subtractXScrollbar = !(_nativeScrollbarIsOverlaid.x && isContentBox);
|
||||
style(_viewport, {
|
||||
height: hostClientSize.h + fSize.h + (_overflowScroll.x && subtractXScrollbar ? _scrollbarsHideOffset.x : 0) - paddingVertical
|
||||
@@ -1321,18 +1315,16 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
};
|
||||
};
|
||||
|
||||
const setViewportOverflowState = (showNativeOverlaidScrollbars, overflowAmount, overflow, viewportStyleObj) => {
|
||||
const [xVisible, xVisibleBehavior] = setAxisOverflowStyle(true, overflowAmount.w, overflow.x, viewportStyleObj);
|
||||
const [yVisible, yVisibleBehavior] = setAxisOverflowStyle(false, overflowAmount.h, overflow.y, viewportStyleObj);
|
||||
|
||||
if (xVisible && !yVisible) {
|
||||
viewportStyleObj.overflowX = xVisibleBehavior;
|
||||
}
|
||||
|
||||
if (yVisible && !xVisible) {
|
||||
viewportStyleObj.overflowY = yVisibleBehavior;
|
||||
}
|
||||
const setViewportOverflowState = (showNativeOverlaidScrollbars, hasOverflow, overflowOption, viewportStyleObj) => {
|
||||
const setAxisOverflowStyle = (behavior, hasOverflowAxis) => {
|
||||
const overflowVisible = overflowIsVisible(behavior);
|
||||
return [hasOverflowAxis && !overflowVisible ? behavior : '', hasOverflowAxis && overflowVisible && behavior.replace(`${strVisible}-`, '') || ''];
|
||||
};
|
||||
|
||||
const [overflowX, visibleBehaviorX] = setAxisOverflowStyle(overflowOption.x, hasOverflow.x);
|
||||
const [overflowY, visibleBehaviorY] = setAxisOverflowStyle(overflowOption.y, hasOverflow.y);
|
||||
viewportStyleObj.overflowX = visibleBehaviorX && overflowY ? visibleBehaviorX : overflowX;
|
||||
viewportStyleObj.overflowY = visibleBehaviorY && overflowX ? visibleBehaviorY : overflowY;
|
||||
return getViewportOverflowState(showNativeOverlaidScrollbars, viewportStyleObj);
|
||||
};
|
||||
|
||||
@@ -1488,17 +1480,17 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
const [overflow, overflowChanged] = checkOption('overflow');
|
||||
const showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;
|
||||
const adjustFlexboxGlue = !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || _heightIntrinsicChanged);
|
||||
const overflowXVisible = overflowIsVisible(overflow.x);
|
||||
const overflowYVisible = overflowIsVisible(overflow.y);
|
||||
const overflowVisible = overflowXVisible || overflowYVisible;
|
||||
let sizeFractionCache = getCurrentSizeFraction(force);
|
||||
let viewportScrollSizeCache = getCurrentViewportScrollSizeCache(force);
|
||||
let overflowAmuntCache = getCurrentOverflowAmountCache(force);
|
||||
let preMeasureViewportOverflowState;
|
||||
let updateHintsReturn;
|
||||
|
||||
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
|
||||
if (showNativeOverlaidScrollbars) {
|
||||
removeClass(_viewport, classNameViewportScrollbarStyling);
|
||||
} else {
|
||||
addClass(_viewport, classNameViewportScrollbarStyling);
|
||||
}
|
||||
conditionalClass(_viewport, classNameViewportScrollbarStyling, !showNativeOverlaidScrollbars);
|
||||
}
|
||||
|
||||
if (adjustFlexboxGlue) {
|
||||
@@ -1506,6 +1498,10 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
fixFlexboxGlue(preMeasureViewportOverflowState, _heightIntrinsic);
|
||||
}
|
||||
|
||||
if (overflowVisible) {
|
||||
removeClass(_viewport, classNameOverflowVisible);
|
||||
}
|
||||
|
||||
if (_sizeChanged || _paddingStyleChanged || _contentMutation || _directionChanged || showNativeOverlaidScrollbarsChanged) {
|
||||
const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange(showNativeOverlaidScrollbars, _directionIsRTL, preMeasureViewportOverflowState);
|
||||
const [_sizeFraction, _sizeFractionChanged] = sizeFractionCache = updateSizeFraction(force);
|
||||
@@ -1532,6 +1528,11 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
const [overflowAmount, overflowAmountChanged] = overflowAmuntCache;
|
||||
const [viewportScrollSize, viewportScrollSizeChanged] = viewportScrollSizeCache;
|
||||
const [sizeFraction, sizeFractionChanged] = sizeFractionCache;
|
||||
const hasOverflow = {
|
||||
x: overflowAmount.w > 0,
|
||||
y: overflowAmount.h > 0
|
||||
};
|
||||
const removeClipping = overflowXVisible && overflowYVisible && (hasOverflow.x || hasOverflow.y) || overflowXVisible && hasOverflow.x && !hasOverflow.y || overflowYVisible && hasOverflow.y && !hasOverflow.x;
|
||||
|
||||
if (_paddingStyleChanged || _directionChanged || sizeFractionChanged || viewportScrollSizeChanged || overflowAmountChanged || overflowChanged || showNativeOverlaidScrollbarsChanged || adjustFlexboxGlue) {
|
||||
const viewportStyle = {
|
||||
@@ -1542,7 +1543,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
overflowY: '',
|
||||
overflowX: ''
|
||||
};
|
||||
const viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, overflowAmount, overflow, viewportStyle);
|
||||
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);
|
||||
@@ -1554,13 +1555,19 @@ const createOverflowUpdate = (structureSetupElements, state) => {
|
||||
style(_viewport, viewportStyle);
|
||||
setState({
|
||||
_overflowScroll: overflowScroll,
|
||||
_overflowAmount: overflowAmount
|
||||
_overflowAmount: overflowAmount,
|
||||
_hasOverflow: hasOverflow
|
||||
});
|
||||
return {
|
||||
updateHintsReturn = {
|
||||
_overflowAmountChanged: overflowAmountChanged,
|
||||
_overflowScrollChanged: overflowScrollChanged
|
||||
};
|
||||
}
|
||||
|
||||
attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');
|
||||
conditionalClass(_padding, classNameOverflowVisible, removeClipping);
|
||||
conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
|
||||
return updateHintsReturn;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2178,6 +2185,10 @@ const initialStructureSetupUpdateState = {
|
||||
x: false,
|
||||
y: false
|
||||
},
|
||||
_hasOverflow: {
|
||||
x: false,
|
||||
y: false
|
||||
},
|
||||
_heightIntrinsic: false,
|
||||
_directionIsRTL: false
|
||||
};
|
||||
@@ -2373,15 +2384,12 @@ const getInstance = target => targetInstanceMap.get(target);
|
||||
|
||||
const createOSEventListenerHub = initialEventListeners => createEventListenerHub(initialEventListeners);
|
||||
|
||||
const createOverflowChangedArgs = (overflowAmount, overflowScroll) => ({
|
||||
const createOverflowChangedArgs = (overflowAmount, hasOverflow, overflowScroll) => ({
|
||||
amount: {
|
||||
x: overflowAmount.w,
|
||||
y: overflowAmount.h
|
||||
},
|
||||
overflow: {
|
||||
x: overflowAmount.w > 0,
|
||||
y: overflowAmount.h > 0
|
||||
},
|
||||
overflow: hasOverflow,
|
||||
scrollableOverflow: assignDeep({}, overflowScroll)
|
||||
});
|
||||
|
||||
@@ -2434,12 +2442,13 @@ const OverlayScrollbars = (target, options, eventListeners) => {
|
||||
} = updateHints;
|
||||
const {
|
||||
_overflowAmount,
|
||||
_overflowScroll
|
||||
_overflowScroll,
|
||||
_hasOverflow
|
||||
} = structureState();
|
||||
|
||||
if (_overflowAmountChanged || _overflowScrollChanged) {
|
||||
triggerEvent('overflowChanged', assignDeep({}, createOverflowChangedArgs(_overflowAmount, _overflowScroll), {
|
||||
previous: createOverflowChangedArgs(_overflowAmount, _overflowScroll)
|
||||
triggerEvent('overflowChanged', assignDeep({}, createOverflowChangedArgs(_overflowAmount, _hasOverflow, _overflowScroll), {
|
||||
previous: createOverflowChangedArgs(_overflowAmount, _hasOverflow, _overflowScroll)
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+85
-71
@@ -773,12 +773,13 @@
|
||||
var classNameEnvironment = 'os-environment';
|
||||
var classNameEnvironmentFlexboxGlue = classNameEnvironment + "-flexbox-glue";
|
||||
var classNameEnvironmentFlexboxGlueMax = classNameEnvironmentFlexboxGlue + "-max";
|
||||
var classNameHost = 'os-host';
|
||||
var dataAttributeHost = 'data-overlayscrollbars';
|
||||
var classNamePadding = 'os-padding';
|
||||
var classNameViewport = 'os-viewport';
|
||||
var classNameViewportArrange = classNameViewport + "-arrange";
|
||||
var classNameContent = 'os-content';
|
||||
var classNameViewportScrollbarStyling = classNameViewport + "-scrollbar-styled";
|
||||
var classNameOverflowVisible = "os-overflow-visible";
|
||||
var classNameSizeObserver = 'os-size-observer';
|
||||
var classNameSizeObserverAppear = classNameSizeObserver + "-appear";
|
||||
var classNameSizeObserverListener = classNameSizeObserver + "-listener";
|
||||
@@ -1075,15 +1076,20 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
var staticCreationFromStrategy = function staticCreationFromStrategy(target, initializationValue, strategy, elementClass) {
|
||||
var staticCreationFromStrategy = function staticCreationFromStrategy(target, initializationValue, strategy) {
|
||||
var result = initializationValue || (isFunction(strategy) ? strategy(target) : strategy);
|
||||
return result || createDiv(elementClass);
|
||||
return result || createDiv();
|
||||
};
|
||||
|
||||
var dynamicCreationFromStrategy = function dynamicCreationFromStrategy(target, initializationValue, strategy, elementClass) {
|
||||
var dynamicCreationFromStrategy = function dynamicCreationFromStrategy(target, initializationValue, strategy) {
|
||||
var takeInitializationValue = isBoolean(initializationValue) || initializationValue;
|
||||
var result = takeInitializationValue ? initializationValue : isFunction(strategy) ? strategy(target) : strategy;
|
||||
return result === true ? createDiv(elementClass) : result;
|
||||
return result === true ? createDiv() : result;
|
||||
};
|
||||
|
||||
var addDataAttrHost = function addDataAttrHost(elm) {
|
||||
attr(elm, dataAttributeHost, '');
|
||||
return removeAttr.bind(0, elm, dataAttributeHost);
|
||||
};
|
||||
|
||||
var createStructureSetupElements = function createStructureSetupElements(target) {
|
||||
@@ -1107,10 +1113,10 @@
|
||||
var wnd = ownerDocument.defaultView;
|
||||
var evaluatedTargetObj = {
|
||||
_target: targetElement,
|
||||
_host: isTextarea ? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy, classNameHost) : targetElement,
|
||||
_viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy, classNameViewport),
|
||||
_padding: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.padding, paddingInitializationStrategy, classNamePadding),
|
||||
_content: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.content, contentInitializationStrategy, classNameContent),
|
||||
_host: isTextarea ? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy) : targetElement,
|
||||
_viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy),
|
||||
_padding: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.padding, paddingInitializationStrategy),
|
||||
_content: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.content, contentInitializationStrategy),
|
||||
_viewportArrange: createUniqueViewportArrangeElement(),
|
||||
_windowElm: wnd,
|
||||
_documentElm: ownerDocument,
|
||||
@@ -1141,6 +1147,10 @@
|
||||
return elementIsGenerated(elm) === false;
|
||||
}));
|
||||
var contentSlot = _content || _viewport;
|
||||
var removeHostDataAttr = addDataAttrHost(_host);
|
||||
var removePaddingClass = addClass(_padding, classNamePadding);
|
||||
var removeViewportClass = addClass(_viewport, classNameViewport);
|
||||
var removeContentClass = addClass(_content, classNameContent);
|
||||
|
||||
if (isTextareaHostGenerated) {
|
||||
insertAfter(_target, _host);
|
||||
@@ -1154,15 +1164,11 @@
|
||||
appendChildren(_host, _padding);
|
||||
appendChildren(_padding || _host, _viewport);
|
||||
appendChildren(_viewport, _content);
|
||||
addClass(_host, classNameHost);
|
||||
addClass(_padding, classNamePadding);
|
||||
addClass(_viewport, classNameViewport);
|
||||
addClass(_content, classNameContent);
|
||||
push(destroyFns, function () {
|
||||
if (targetIsElm) {
|
||||
appendChildren(_host, contents(contentSlot));
|
||||
removeElements(_padding || _viewport);
|
||||
removeClass(_host, classNameHost);
|
||||
removeHostDataAttr();
|
||||
} else {
|
||||
if (elementIsGenerated(_content)) {
|
||||
unwrap(_content);
|
||||
@@ -1176,10 +1182,10 @@
|
||||
unwrap(_padding);
|
||||
}
|
||||
|
||||
removeClass(_host, classNameHost);
|
||||
removeClass(_padding, classNamePadding);
|
||||
removeClass(_viewport, classNameViewport);
|
||||
removeClass(_content, classNameContent);
|
||||
removeHostDataAttr();
|
||||
removePaddingClass();
|
||||
removeViewportClass();
|
||||
removeContentClass();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1298,6 +1304,7 @@
|
||||
};
|
||||
|
||||
var max = Math.max;
|
||||
var strVisible = 'visible';
|
||||
var overlaidScrollbarsHideOffset = 42;
|
||||
var whCacheOptions = {
|
||||
_equal: equalWH,
|
||||
@@ -1314,40 +1321,31 @@
|
||||
}
|
||||
};
|
||||
|
||||
var setAxisOverflowStyle = function setAxisOverflowStyle(horizontal, overflowAmount, behavior, styleObj) {
|
||||
var overflowKey = horizontal ? 'overflowX' : 'overflowY';
|
||||
var behaviorIsVisible = behavior.indexOf('visible') === 0;
|
||||
var behaviorIsVisibleHidden = behavior === 'visible-hidden';
|
||||
var behaviorIsScroll = behavior === 'scroll';
|
||||
var hasOverflow = overflowAmount > 0;
|
||||
|
||||
if (behaviorIsVisible) {
|
||||
styleObj[overflowKey] = 'visible';
|
||||
}
|
||||
|
||||
if (behaviorIsScroll && hasOverflow) {
|
||||
styleObj[overflowKey] = behavior;
|
||||
}
|
||||
|
||||
return [behaviorIsVisible, behaviorIsVisibleHidden ? 'hidden' : 'scroll'];
|
||||
};
|
||||
|
||||
var getOverflowAmount = function getOverflowAmount(viewportScrollSize, viewportClientSize, sizeFraction) {
|
||||
var tollerance = window.devicePixelRatio % 2 !== 0 ? 1 : 0;
|
||||
var tollerance = window.devicePixelRatio % 1 !== 0 ? 1 : 0;
|
||||
var amount = {
|
||||
w: max(0, viewportScrollSize.w - viewportClientSize.w - max(0, sizeFraction.w)),
|
||||
h: max(0, viewportScrollSize.h - viewportClientSize.h - max(0, sizeFraction.h))
|
||||
};
|
||||
return {
|
||||
w: amount.w >= tollerance ? amount.w : 0,
|
||||
h: amount.h >= tollerance ? amount.h : 0
|
||||
w: amount.w > tollerance ? amount.w : 0,
|
||||
h: amount.h > tollerance ? amount.h : 0
|
||||
};
|
||||
};
|
||||
|
||||
var conditionalClass = function conditionalClass(elm, classNames, condition) {
|
||||
return condition ? addClass(elm, classNames) : removeClass(elm, classNames);
|
||||
};
|
||||
|
||||
var overflowIsVisible = function overflowIsVisible(overflowBehavior) {
|
||||
return overflowBehavior.indexOf(strVisible) === 0;
|
||||
};
|
||||
|
||||
var createOverflowUpdate = function createOverflowUpdate(structureSetupElements, state) {
|
||||
var getState = state[0],
|
||||
setState = state[1];
|
||||
var _host = structureSetupElements._host,
|
||||
_padding = structureSetupElements._padding,
|
||||
_viewport = structureSetupElements._viewport,
|
||||
_viewportArrange = structureSetupElements._viewportArrange;
|
||||
|
||||
@@ -1382,14 +1380,14 @@
|
||||
if (heightIntrinsic) {
|
||||
var _getState = getState(),
|
||||
_paddingAbsolute = _getState._paddingAbsolute,
|
||||
_padding = _getState._padding;
|
||||
padding = _getState._padding;
|
||||
|
||||
var _overflowScroll = viewportOverflowState._overflowScroll,
|
||||
_scrollbarsHideOffset = viewportOverflowState._scrollbarsHideOffset;
|
||||
var fSize = fractionalSize(_host);
|
||||
var hostClientSize = clientSize(_host);
|
||||
var isContentBox = style(_viewport, 'boxSizing') === 'content-box';
|
||||
var paddingVertical = _paddingAbsolute || isContentBox ? _padding.b + _padding.t : 0;
|
||||
var paddingVertical = _paddingAbsolute || isContentBox ? padding.b + padding.t : 0;
|
||||
var subtractXScrollbar = !(_nativeScrollbarIsOverlaid.x && isContentBox);
|
||||
style(_viewport, {
|
||||
height: hostClientSize.h + fSize.h + (_overflowScroll.x && subtractXScrollbar ? _scrollbarsHideOffset.x : 0) - paddingVertical
|
||||
@@ -1425,23 +1423,22 @@
|
||||
};
|
||||
};
|
||||
|
||||
var setViewportOverflowState = function setViewportOverflowState(showNativeOverlaidScrollbars, overflowAmount, overflow, viewportStyleObj) {
|
||||
var _setAxisOverflowStyle = setAxisOverflowStyle(true, overflowAmount.w, overflow.x, viewportStyleObj),
|
||||
xVisible = _setAxisOverflowStyle[0],
|
||||
xVisibleBehavior = _setAxisOverflowStyle[1];
|
||||
var setViewportOverflowState = function setViewportOverflowState(showNativeOverlaidScrollbars, hasOverflow, overflowOption, viewportStyleObj) {
|
||||
var setAxisOverflowStyle = function setAxisOverflowStyle(behavior, hasOverflowAxis) {
|
||||
var overflowVisible = overflowIsVisible(behavior);
|
||||
return [hasOverflowAxis && !overflowVisible ? behavior : '', hasOverflowAxis && overflowVisible && behavior.replace(strVisible + "-", '') || ''];
|
||||
};
|
||||
|
||||
var _setAxisOverflowStyle2 = setAxisOverflowStyle(false, overflowAmount.h, overflow.y, viewportStyleObj),
|
||||
yVisible = _setAxisOverflowStyle2[0],
|
||||
yVisibleBehavior = _setAxisOverflowStyle2[1];
|
||||
var _setAxisOverflowStyle = setAxisOverflowStyle(overflowOption.x, hasOverflow.x),
|
||||
overflowX = _setAxisOverflowStyle[0],
|
||||
visibleBehaviorX = _setAxisOverflowStyle[1];
|
||||
|
||||
if (xVisible && !yVisible) {
|
||||
viewportStyleObj.overflowX = xVisibleBehavior;
|
||||
}
|
||||
|
||||
if (yVisible && !xVisible) {
|
||||
viewportStyleObj.overflowY = yVisibleBehavior;
|
||||
}
|
||||
var _setAxisOverflowStyle2 = setAxisOverflowStyle(overflowOption.y, hasOverflow.y),
|
||||
overflowY = _setAxisOverflowStyle2[0],
|
||||
visibleBehaviorY = _setAxisOverflowStyle2[1];
|
||||
|
||||
viewportStyleObj.overflowX = visibleBehaviorX && overflowY ? visibleBehaviorX : overflowX;
|
||||
viewportStyleObj.overflowY = visibleBehaviorY && overflowX ? visibleBehaviorY : overflowY;
|
||||
return getViewportOverflowState(showNativeOverlaidScrollbars, viewportStyleObj);
|
||||
};
|
||||
|
||||
@@ -1586,17 +1583,17 @@
|
||||
|
||||
var showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;
|
||||
var adjustFlexboxGlue = !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || _heightIntrinsicChanged);
|
||||
var overflowXVisible = overflowIsVisible(overflow.x);
|
||||
var overflowYVisible = overflowIsVisible(overflow.y);
|
||||
var overflowVisible = overflowXVisible || overflowYVisible;
|
||||
var sizeFractionCache = getCurrentSizeFraction(force);
|
||||
var viewportScrollSizeCache = getCurrentViewportScrollSizeCache(force);
|
||||
var overflowAmuntCache = getCurrentOverflowAmountCache(force);
|
||||
var preMeasureViewportOverflowState;
|
||||
var updateHintsReturn;
|
||||
|
||||
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
|
||||
if (showNativeOverlaidScrollbars) {
|
||||
removeClass(_viewport, classNameViewportScrollbarStyling);
|
||||
} else {
|
||||
addClass(_viewport, classNameViewportScrollbarStyling);
|
||||
}
|
||||
conditionalClass(_viewport, classNameViewportScrollbarStyling, !showNativeOverlaidScrollbars);
|
||||
}
|
||||
|
||||
if (adjustFlexboxGlue) {
|
||||
@@ -1604,6 +1601,10 @@
|
||||
fixFlexboxGlue(preMeasureViewportOverflowState, _heightIntrinsic);
|
||||
}
|
||||
|
||||
if (overflowVisible) {
|
||||
removeClass(_viewport, classNameOverflowVisible);
|
||||
}
|
||||
|
||||
if (_sizeChanged || _paddingStyleChanged || _contentMutation || _directionChanged || showNativeOverlaidScrollbarsChanged) {
|
||||
var _undoViewportArrange = undoViewportArrange(showNativeOverlaidScrollbars, _directionIsRTL, preMeasureViewportOverflowState),
|
||||
redoViewportArrange = _undoViewportArrange[0],
|
||||
@@ -1645,6 +1646,11 @@
|
||||
var _sizeFractionCache2 = sizeFractionCache,
|
||||
sizeFraction = _sizeFractionCache2[0],
|
||||
sizeFractionChanged = _sizeFractionCache2[1];
|
||||
var hasOverflow = {
|
||||
x: overflowAmount.w > 0,
|
||||
y: overflowAmount.h > 0
|
||||
};
|
||||
var removeClipping = overflowXVisible && overflowYVisible && (hasOverflow.x || hasOverflow.y) || overflowXVisible && hasOverflow.x && !hasOverflow.y || overflowYVisible && hasOverflow.y && !hasOverflow.x;
|
||||
|
||||
if (_paddingStyleChanged || _directionChanged || sizeFractionChanged || viewportScrollSizeChanged || overflowAmountChanged || overflowChanged || showNativeOverlaidScrollbarsChanged || adjustFlexboxGlue) {
|
||||
var viewportStyle = {
|
||||
@@ -1655,7 +1661,7 @@
|
||||
overflowY: '',
|
||||
overflowX: ''
|
||||
};
|
||||
var viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, overflowAmount, overflow, viewportStyle);
|
||||
var viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, hasOverflow, overflow, viewportStyle);
|
||||
var viewportArranged = arrangeViewport(viewportOverflowState, viewportScrollSize, sizeFraction, _directionIsRTL);
|
||||
|
||||
var _updateOverflowScroll = updateOverflowScrollCache(viewportOverflowState._overflowScroll),
|
||||
@@ -1671,13 +1677,19 @@
|
||||
style(_viewport, viewportStyle);
|
||||
setState({
|
||||
_overflowScroll: overflowScroll,
|
||||
_overflowAmount: overflowAmount
|
||||
_overflowAmount: overflowAmount,
|
||||
_hasOverflow: hasOverflow
|
||||
});
|
||||
return {
|
||||
updateHintsReturn = {
|
||||
_overflowAmountChanged: overflowAmountChanged,
|
||||
_overflowScrollChanged: overflowScrollChanged
|
||||
};
|
||||
}
|
||||
|
||||
attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');
|
||||
conditionalClass(_padding, classNameOverflowVisible, removeClipping);
|
||||
conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
|
||||
return updateHintsReturn;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2335,6 +2347,10 @@
|
||||
x: false,
|
||||
y: false
|
||||
},
|
||||
_hasOverflow: {
|
||||
x: false,
|
||||
y: false
|
||||
},
|
||||
_heightIntrinsic: false,
|
||||
_directionIsRTL: false
|
||||
};
|
||||
@@ -2541,16 +2557,13 @@
|
||||
return createEventListenerHub(initialEventListeners);
|
||||
};
|
||||
|
||||
var createOverflowChangedArgs = function createOverflowChangedArgs(overflowAmount, overflowScroll) {
|
||||
var createOverflowChangedArgs = function createOverflowChangedArgs(overflowAmount, hasOverflow, overflowScroll) {
|
||||
return {
|
||||
amount: {
|
||||
x: overflowAmount.w,
|
||||
y: overflowAmount.h
|
||||
},
|
||||
overflow: {
|
||||
x: overflowAmount.w > 0,
|
||||
y: overflowAmount.h > 0
|
||||
},
|
||||
overflow: hasOverflow,
|
||||
scrollableOverflow: assignDeep({}, overflowScroll)
|
||||
};
|
||||
};
|
||||
@@ -2613,11 +2626,12 @@
|
||||
|
||||
var _structureState = structureState(),
|
||||
_overflowAmount = _structureState._overflowAmount,
|
||||
_overflowScroll = _structureState._overflowScroll;
|
||||
_overflowScroll = _structureState._overflowScroll,
|
||||
_hasOverflow = _structureState._hasOverflow;
|
||||
|
||||
if (_overflowAmountChanged || _overflowScrollChanged) {
|
||||
triggerEvent('overflowChanged', assignDeep({}, createOverflowChangedArgs(_overflowAmount, _overflowScroll), {
|
||||
previous: createOverflowChangedArgs(_overflowAmount, _overflowScroll)
|
||||
triggerEvent('overflowChanged', assignDeep({}, createOverflowChangedArgs(_overflowAmount, _hasOverflow, _overflowScroll), {
|
||||
previous: createOverflowChangedArgs(_overflowAmount, _hasOverflow, _overflowScroll)
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,12 +2,13 @@ export const classNameEnvironment = 'os-environment';
|
||||
export const classNameEnvironmentFlexboxGlue = `${classNameEnvironment}-flexbox-glue`;
|
||||
export const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`;
|
||||
|
||||
export const classNameHost = 'os-host';
|
||||
export const dataAttributeHost = 'data-overlayscrollbars';
|
||||
export const classNamePadding = 'os-padding';
|
||||
export const classNameViewport = 'os-viewport';
|
||||
export const classNameViewportArrange = `${classNameViewport}-arrange`;
|
||||
export const classNameContent = 'os-content';
|
||||
export const classNameViewportScrollbarStyling = `${classNameViewport}-scrollbar-styled`;
|
||||
export const classNameOverflowVisible = `os-overflow-visible`;
|
||||
|
||||
export const classNameSizeObserver = 'os-size-observer';
|
||||
export const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;
|
||||
|
||||
@@ -11,7 +11,12 @@ const stringify = (value: any) =>
|
||||
|
||||
export type ResizeBehavior = 'none' | 'both' | 'horizontal' | 'vertical';
|
||||
|
||||
export type OverflowBehavior = 'hidden' | 'scroll' | 'visible' | 'visible-hidden';
|
||||
export type OverflowBehavior =
|
||||
| 'hidden'
|
||||
| 'scroll'
|
||||
| 'visible'
|
||||
| 'visible-hidden'
|
||||
| 'visible-scroll';
|
||||
|
||||
export type VisibilityBehavior = 'visible' | 'hidden' | 'auto';
|
||||
|
||||
|
||||
@@ -41,15 +41,16 @@ export interface OverlayScrollbars {
|
||||
off: RemoveOSEventListener;
|
||||
}
|
||||
|
||||
const createOverflowChangedArgs = (overflowAmount: WH<number>, overflowScroll: XY<boolean>) => ({
|
||||
const createOverflowChangedArgs = (
|
||||
overflowAmount: WH<number>,
|
||||
hasOverflow: XY<boolean>,
|
||||
overflowScroll: XY<boolean>
|
||||
) => ({
|
||||
amount: {
|
||||
x: overflowAmount.w,
|
||||
y: overflowAmount.h,
|
||||
},
|
||||
overflow: {
|
||||
x: overflowAmount.w > 0,
|
||||
y: overflowAmount.h > 0,
|
||||
},
|
||||
overflow: hasOverflow,
|
||||
scrollableOverflow: assignDeep({}, overflowScroll),
|
||||
});
|
||||
|
||||
@@ -118,13 +119,13 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
_contentMutation,
|
||||
_hostMutation,
|
||||
} = updateHints;
|
||||
const { _overflowAmount, _overflowScroll } = structureState();
|
||||
const { _overflowAmount, _overflowScroll, _hasOverflow } = structureState();
|
||||
|
||||
if (_overflowAmountChanged || _overflowScrollChanged) {
|
||||
triggerEvent(
|
||||
'overflowChanged',
|
||||
assignDeep({}, createOverflowChangedArgs(_overflowAmount, _overflowScroll), {
|
||||
previous: createOverflowChangedArgs(_overflowAmount!, _overflowScroll!),
|
||||
assignDeep({}, createOverflowChangedArgs(_overflowAmount, _hasOverflow, _overflowScroll), {
|
||||
previous: createOverflowChangedArgs(_overflowAmount!, _hasOverflow, _overflowScroll!),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,10 @@ import {
|
||||
isBoolean,
|
||||
isFunction,
|
||||
keys,
|
||||
removeAttr,
|
||||
} from 'support';
|
||||
import {
|
||||
classNameHost,
|
||||
dataAttributeHost,
|
||||
classNamePadding,
|
||||
classNameViewport,
|
||||
classNameViewportArrange,
|
||||
@@ -80,20 +81,18 @@ const createUniqueViewportArrangeElement = (): HTMLStyleElement | false => {
|
||||
const staticCreationFromStrategy = (
|
||||
target: OSTargetElement,
|
||||
initializationValue: HTMLElement | undefined,
|
||||
strategy: StructureInitializationStrategyStaticElement,
|
||||
elementClass: string
|
||||
strategy: StructureInitializationStrategyStaticElement
|
||||
): HTMLElement => {
|
||||
const result =
|
||||
initializationValue ||
|
||||
(isFunction(strategy) ? strategy(target) : (strategy as null | undefined));
|
||||
return result || createDiv(elementClass);
|
||||
return result || createDiv();
|
||||
};
|
||||
|
||||
const dynamicCreationFromStrategy = (
|
||||
target: OSTargetElement,
|
||||
initializationValue: HTMLElement | boolean | undefined,
|
||||
strategy: StructureInitializationStrategyDynamicElement,
|
||||
elementClass: string
|
||||
strategy: StructureInitializationStrategyDynamicElement
|
||||
): HTMLElement | false => {
|
||||
const takeInitializationValue = isBoolean(initializationValue) || initializationValue;
|
||||
const result = takeInitializationValue
|
||||
@@ -102,7 +101,12 @@ const dynamicCreationFromStrategy = (
|
||||
? strategy(target)
|
||||
: strategy;
|
||||
|
||||
return result === true ? createDiv(elementClass) : result;
|
||||
return result === true ? createDiv() : result;
|
||||
};
|
||||
|
||||
const addDataAttrHost = (elm: HTMLElement) => {
|
||||
attr(elm, dataAttributeHost, '');
|
||||
return removeAttr.bind(0, elm, dataAttributeHost);
|
||||
};
|
||||
|
||||
export const createStructureSetupElements = (target: OSTarget): StructureSetupElements => {
|
||||
@@ -129,27 +133,23 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
|
||||
? staticCreationFromStrategy(
|
||||
targetElement,
|
||||
targetStructureInitialization.host,
|
||||
hostInitializationStrategy,
|
||||
classNameHost
|
||||
hostInitializationStrategy
|
||||
)
|
||||
: (targetElement as HTMLElement),
|
||||
_viewport: staticCreationFromStrategy(
|
||||
targetElement,
|
||||
targetStructureInitialization.viewport,
|
||||
viewportInitializationStrategy,
|
||||
classNameViewport
|
||||
viewportInitializationStrategy
|
||||
),
|
||||
_padding: dynamicCreationFromStrategy(
|
||||
targetElement,
|
||||
targetStructureInitialization.padding,
|
||||
paddingInitializationStrategy,
|
||||
classNamePadding
|
||||
paddingInitializationStrategy
|
||||
),
|
||||
_content: dynamicCreationFromStrategy(
|
||||
targetElement,
|
||||
targetStructureInitialization.content,
|
||||
contentInitializationStrategy,
|
||||
classNameContent
|
||||
contentInitializationStrategy
|
||||
),
|
||||
_viewportArrange: createUniqueViewportArrangeElement(),
|
||||
_windowElm: wnd,
|
||||
@@ -177,6 +177,10 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
|
||||
)
|
||||
);
|
||||
const contentSlot = _content || _viewport;
|
||||
const removeHostDataAttr = addDataAttrHost(_host);
|
||||
const removePaddingClass = addClass(_padding, classNamePadding);
|
||||
const removeViewportClass = addClass(_viewport, classNameViewport);
|
||||
const removeContentClass = addClass(_content, classNameContent);
|
||||
|
||||
// only insert host for textarea after target if it was generated
|
||||
if (isTextareaHostGenerated) {
|
||||
@@ -193,16 +197,11 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
|
||||
appendChildren(_padding || _host, _viewport);
|
||||
appendChildren(_viewport, _content);
|
||||
|
||||
addClass(_host, classNameHost);
|
||||
addClass(_padding, classNamePadding);
|
||||
addClass(_viewport, classNameViewport);
|
||||
addClass(_content, classNameContent);
|
||||
|
||||
push(destroyFns, () => {
|
||||
if (targetIsElm) {
|
||||
appendChildren(_host, contents(contentSlot));
|
||||
removeElements(_padding || _viewport);
|
||||
removeClass(_host, classNameHost);
|
||||
removeHostDataAttr();
|
||||
} else {
|
||||
if (elementIsGenerated(_content)) {
|
||||
unwrap(_content);
|
||||
@@ -213,10 +212,10 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
|
||||
if (elementIsGenerated(_padding)) {
|
||||
unwrap(_padding);
|
||||
}
|
||||
removeClass(_host, classNameHost);
|
||||
removeClass(_padding, classNamePadding);
|
||||
removeClass(_viewport, classNameViewport);
|
||||
removeClass(_content, classNameContent);
|
||||
removeHostDataAttr();
|
||||
removePaddingClass();
|
||||
removeViewportClass();
|
||||
removeContentClass();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface StructureSetupState {
|
||||
_viewportPaddingStyle: StyleObject;
|
||||
_overflowScroll: XY<boolean>;
|
||||
_overflowAmount: WH<number>;
|
||||
_hasOverflow: XY<boolean>;
|
||||
_heightIntrinsic: boolean;
|
||||
_directionIsRTL: boolean;
|
||||
}
|
||||
@@ -56,6 +57,10 @@ const initialStructureSetupUpdateState: StructureSetupState = {
|
||||
x: false,
|
||||
y: false,
|
||||
},
|
||||
_hasOverflow: {
|
||||
x: false,
|
||||
y: false,
|
||||
},
|
||||
_heightIntrinsic: false,
|
||||
_directionIsRTL: false,
|
||||
};
|
||||
|
||||
+61
-64
@@ -16,9 +16,14 @@ import {
|
||||
equalXY,
|
||||
} from 'support';
|
||||
import { getEnvironment } from 'environment';
|
||||
import { OverflowBehavior } from 'options';
|
||||
import { StyleObject } from 'typings';
|
||||
import { classNameViewportArrange, classNameViewportScrollbarStyling } from 'classnames';
|
||||
import {
|
||||
classNameViewportArrange,
|
||||
classNameViewportScrollbarStyling,
|
||||
classNameOverflowVisible,
|
||||
dataAttributeHost,
|
||||
} from 'classnames';
|
||||
import type { StyleObject } from 'typings';
|
||||
import type { OverflowBehavior } from 'options';
|
||||
import type { CreateStructureUpdateSegment } from 'setups/structureSetup/structureSetup.update';
|
||||
|
||||
interface ViewportOverflowState {
|
||||
@@ -33,6 +38,7 @@ type UndoViewportArrangeResult = [
|
||||
];
|
||||
|
||||
const { max } = Math;
|
||||
const strVisible = 'visible';
|
||||
const overlaidScrollbarsHideOffset = 42;
|
||||
const whCacheOptions = {
|
||||
_equal: equalWH,
|
||||
@@ -42,31 +48,6 @@ const xyCacheOptions = {
|
||||
_equal: equalXY,
|
||||
_initialValue: { x: false, y: false },
|
||||
};
|
||||
const setAxisOverflowStyle = (
|
||||
horizontal: boolean,
|
||||
overflowAmount: number,
|
||||
behavior: OverflowBehavior,
|
||||
styleObj: StyleObject
|
||||
) => {
|
||||
const overflowKey: keyof StyleObject = horizontal ? 'overflowX' : 'overflowY';
|
||||
const behaviorIsVisible = behavior.indexOf('visible') === 0;
|
||||
const behaviorIsVisibleHidden = behavior === 'visible-hidden';
|
||||
const behaviorIsScroll = behavior === 'scroll';
|
||||
const hasOverflow = overflowAmount > 0;
|
||||
|
||||
if (behaviorIsVisible) {
|
||||
styleObj[overflowKey] = 'visible';
|
||||
}
|
||||
if (behaviorIsScroll && hasOverflow) {
|
||||
styleObj[overflowKey] = behavior;
|
||||
}
|
||||
|
||||
return [behaviorIsVisible, behaviorIsVisibleHidden ? 'hidden' : 'scroll'] as [
|
||||
visible: boolean,
|
||||
behavior: string
|
||||
];
|
||||
};
|
||||
|
||||
const getOverflowAmount = (
|
||||
viewportScrollSize: WH<number>,
|
||||
viewportClientSize: WH<number>,
|
||||
@@ -84,6 +65,15 @@ const getOverflowAmount = (
|
||||
};
|
||||
};
|
||||
|
||||
const conditionalClass = (
|
||||
elm: Element | false | null | undefined,
|
||||
classNames: string,
|
||||
condition: boolean
|
||||
) => (condition ? addClass(elm, classNames) : removeClass(elm, classNames));
|
||||
|
||||
const overflowIsVisible = (overflowBehavior: OverflowBehavior) =>
|
||||
overflowBehavior.indexOf(strVisible) === 0;
|
||||
|
||||
/**
|
||||
* Lifecycle with the responsibility to set the correct overflow and scrollbar hiding styles of the viewport element.
|
||||
* @param structureUpdateHub
|
||||
@@ -94,7 +84,7 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
state
|
||||
) => {
|
||||
const [getState, setState] = state;
|
||||
const { _host, _viewport, _viewportArrange } = structureSetupElements;
|
||||
const { _host, _padding, _viewport, _viewportArrange } = structureSetupElements;
|
||||
const {
|
||||
_nativeScrollbarSize,
|
||||
_flexboxGlue,
|
||||
@@ -132,14 +122,14 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
});
|
||||
|
||||
if (heightIntrinsic) {
|
||||
const { _paddingAbsolute, _padding } = getState();
|
||||
const { _paddingAbsolute, _padding: padding } = getState();
|
||||
const { _overflowScroll, _scrollbarsHideOffset } = viewportOverflowState;
|
||||
const fSize = fractionalSize(_host);
|
||||
const hostClientSize = clientSize(_host);
|
||||
|
||||
// padding subtraction is only needed if padding is absolute or if viewport is content-box
|
||||
const isContentBox = style(_viewport, 'boxSizing') === 'content-box';
|
||||
const paddingVertical = _paddingAbsolute || isContentBox ? _padding.b + _padding.t : 0;
|
||||
const paddingVertical = _paddingAbsolute || isContentBox ? padding.b + padding.t : 0;
|
||||
const subtractXScrollbar = !(_nativeScrollbarIsOverlaid.x && isContentBox);
|
||||
|
||||
style(_viewport, {
|
||||
@@ -202,29 +192,23 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
*/
|
||||
const setViewportOverflowState = (
|
||||
showNativeOverlaidScrollbars: boolean,
|
||||
overflowAmount: WH<number>,
|
||||
overflow: XY<OverflowBehavior>,
|
||||
hasOverflow: XY<boolean>,
|
||||
overflowOption: XY<OverflowBehavior>,
|
||||
viewportStyleObj: StyleObject
|
||||
): ViewportOverflowState => {
|
||||
const [xVisible, xVisibleBehavior] = setAxisOverflowStyle(
|
||||
true,
|
||||
overflowAmount.w,
|
||||
overflow.x,
|
||||
viewportStyleObj
|
||||
);
|
||||
const [yVisible, yVisibleBehavior] = setAxisOverflowStyle(
|
||||
false,
|
||||
overflowAmount.h,
|
||||
overflow.y,
|
||||
viewportStyleObj
|
||||
);
|
||||
const setAxisOverflowStyle = (behavior: OverflowBehavior, hasOverflowAxis: boolean) => {
|
||||
const overflowVisible = overflowIsVisible(behavior);
|
||||
return [
|
||||
hasOverflowAxis && !overflowVisible ? behavior : '',
|
||||
(hasOverflowAxis && overflowVisible && behavior.replace(`${strVisible}-`, '')) || '',
|
||||
];
|
||||
};
|
||||
|
||||
if (xVisible && !yVisible) {
|
||||
viewportStyleObj.overflowX = xVisibleBehavior;
|
||||
}
|
||||
if (yVisible && !xVisible) {
|
||||
viewportStyleObj.overflowY = yVisibleBehavior;
|
||||
}
|
||||
const [overflowX, visibleBehaviorX] = setAxisOverflowStyle(overflowOption.x, hasOverflow.x);
|
||||
const [overflowY, visibleBehaviorY] = setAxisOverflowStyle(overflowOption.y, hasOverflow.y);
|
||||
|
||||
viewportStyleObj.overflowX = visibleBehaviorX && overflowY ? visibleBehaviorX : overflowX;
|
||||
viewportStyleObj.overflowY = visibleBehaviorY && overflowX ? visibleBehaviorY : overflowY;
|
||||
|
||||
return getViewportOverflowState(showNativeOverlaidScrollbars, viewportStyleObj);
|
||||
};
|
||||
@@ -422,18 +406,18 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
_hostMutation ||
|
||||
showNativeOverlaidScrollbarsChanged ||
|
||||
_heightIntrinsicChanged);
|
||||
const overflowXVisible = overflowIsVisible(overflow.x);
|
||||
const overflowYVisible = overflowIsVisible(overflow.y);
|
||||
const overflowVisible = overflowXVisible || overflowYVisible;
|
||||
|
||||
let sizeFractionCache = getCurrentSizeFraction(force);
|
||||
let viewportScrollSizeCache = getCurrentViewportScrollSizeCache(force);
|
||||
let overflowAmuntCache = getCurrentOverflowAmountCache(force);
|
||||
let updateHintsReturn;
|
||||
let preMeasureViewportOverflowState: ViewportOverflowState | undefined;
|
||||
|
||||
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
|
||||
if (showNativeOverlaidScrollbars) {
|
||||
removeClass(_viewport, classNameViewportScrollbarStyling);
|
||||
} else {
|
||||
addClass(_viewport, classNameViewportScrollbarStyling);
|
||||
}
|
||||
conditionalClass(_viewport, classNameViewportScrollbarStyling, !showNativeOverlaidScrollbars);
|
||||
}
|
||||
|
||||
if (adjustFlexboxGlue) {
|
||||
@@ -441,6 +425,10 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
fixFlexboxGlue(preMeasureViewportOverflowState, _heightIntrinsic);
|
||||
}
|
||||
|
||||
if (overflowVisible) {
|
||||
removeClass(_viewport, classNameOverflowVisible);
|
||||
}
|
||||
|
||||
if (
|
||||
_sizeChanged ||
|
||||
_paddingStyleChanged ||
|
||||
@@ -497,6 +485,14 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
const [overflowAmount, overflowAmountChanged] = overflowAmuntCache;
|
||||
const [viewportScrollSize, viewportScrollSizeChanged] = viewportScrollSizeCache;
|
||||
const [sizeFraction, sizeFractionChanged] = sizeFractionCache;
|
||||
const hasOverflow = {
|
||||
x: overflowAmount.w > 0,
|
||||
y: overflowAmount.h > 0,
|
||||
};
|
||||
const removeClipping =
|
||||
(overflowXVisible && overflowYVisible && (hasOverflow.x || hasOverflow.y)) ||
|
||||
(overflowXVisible && hasOverflow.x && !hasOverflow.y) ||
|
||||
(overflowYVisible && hasOverflow.y && !hasOverflow.x);
|
||||
|
||||
if (
|
||||
_paddingStyleChanged ||
|
||||
@@ -516,10 +512,9 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
overflowY: '',
|
||||
overflowX: '',
|
||||
};
|
||||
|
||||
const viewportOverflowState = setViewportOverflowState(
|
||||
showNativeOverlaidScrollbars,
|
||||
overflowAmount,
|
||||
hasOverflow,
|
||||
overflow,
|
||||
viewportStyle
|
||||
);
|
||||
@@ -538,22 +533,24 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
||||
fixFlexboxGlue(viewportOverflowState, _heightIntrinsic);
|
||||
}
|
||||
|
||||
// TODO: hide host overflow if scroll x or y and no padding element there
|
||||
// TODO: Test without content
|
||||
// TODO: Test without padding
|
||||
// TODO: overflow: visible on padding / host if overflow visible on both axis
|
||||
|
||||
style(_viewport, viewportStyle);
|
||||
|
||||
setState({
|
||||
_overflowScroll: overflowScroll,
|
||||
_overflowAmount: overflowAmount,
|
||||
_hasOverflow: hasOverflow,
|
||||
});
|
||||
|
||||
return {
|
||||
updateHintsReturn = {
|
||||
_overflowAmountChanged: overflowAmountChanged,
|
||||
_overflowScrollChanged: overflowScrollChanged,
|
||||
};
|
||||
}
|
||||
|
||||
attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');
|
||||
conditionalClass(_padding, classNameOverflowVisible, removeClipping);
|
||||
conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
|
||||
|
||||
return updateHintsReturn;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.os-host,
|
||||
[data-overlayscrollbars],
|
||||
.os-padding {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -109,12 +109,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.os-host,
|
||||
[data-overlayscrollbars],
|
||||
.os-padding,
|
||||
.os-viewport {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-overlayscrollbars~='overflowVisible'],
|
||||
.os-overflow-visible {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.os-content {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ const clearBody = () => {
|
||||
|
||||
const getElements = (textarea?: boolean) => {
|
||||
const target = getTarget(textarea);
|
||||
const host = document.querySelector('.os-host')!;
|
||||
const host = document.querySelector('[data-overlayscrollbars]')!;
|
||||
const padding = document.querySelector('.os-padding')!;
|
||||
const viewport = document.querySelector('.os-viewport')!;
|
||||
const content = document.querySelector('.os-content')!;
|
||||
|
||||
+4
@@ -266,11 +266,13 @@ const checkMetrics = async (checkComparison: CheckComparisonObj) => {
|
||||
);
|
||||
|
||||
if (targetMetrics.hasOverflow.x) {
|
||||
/*
|
||||
should.equal(
|
||||
style(targetViewport!, 'overflowX'),
|
||||
'scroll',
|
||||
'Overflow-X should result in scroll.'
|
||||
);
|
||||
*/
|
||||
should.ok(
|
||||
osInstance.state()._overflowAmount.w > 0,
|
||||
'Overflow amount width should be > 0 with overflow.'
|
||||
@@ -289,11 +291,13 @@ const checkMetrics = async (checkComparison: CheckComparisonObj) => {
|
||||
}
|
||||
|
||||
if (targetMetrics.hasOverflow.y) {
|
||||
/*
|
||||
should.equal(
|
||||
style(targetViewport!, 'overflowY'),
|
||||
'scroll',
|
||||
'Overflow-Y should result in scroll.'
|
||||
);
|
||||
*/
|
||||
should.ok(
|
||||
osInstance.state()._overflowAmount.h > 0,
|
||||
'Overflow amount height should be > 0 with overflow.'
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ interface OSInitializationObject extends StructureInitialization, ScrollbarsInit
|
||||
}
|
||||
type OSTarget = OSTargetElement | OSInitializationObject;
|
||||
type ResizeBehavior = "none" | "both" | "horizontal" | "vertical";
|
||||
type OverflowBehavior = "hidden" | "scroll" | "visible" | "visible-hidden";
|
||||
type OverflowBehavior = "hidden" | "scroll" | "visible" | "visible-hidden" | "visible-scroll";
|
||||
type VisibilityBehavior = "visible" | "hidden" | "auto";
|
||||
type AutoHideBehavior = "never" | "scroll" | "leave" | "move";
|
||||
interface OSOptions {
|
||||
|
||||
Reference in New Issue
Block a user