mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-29 23:24:07 +03:00
575 lines
20 KiB
TypeScript
575 lines
20 KiB
TypeScript
import {
|
|
createCache,
|
|
keys,
|
|
attr,
|
|
WH,
|
|
XY,
|
|
style,
|
|
scrollSize,
|
|
CacheValues,
|
|
equalWH,
|
|
addClass,
|
|
removeClass,
|
|
clientSize,
|
|
noop,
|
|
each,
|
|
equalXY,
|
|
} from 'support';
|
|
import { getEnvironment } from 'environment';
|
|
import { OverflowBehavior } from 'options';
|
|
import { StyleObject } from 'typings';
|
|
import { classNameViewportArrange, classNameViewportScrollbarStyling } from 'classnames';
|
|
import type { CreateStructureUpdateSegment } from 'setups/structureSetup/structureSetup.update';
|
|
|
|
interface ViewportOverflowState {
|
|
_scrollbarsHideOffset: XY<number>;
|
|
_scrollbarsHideOffsetArrange: XY<boolean>;
|
|
_overflowScroll: XY<boolean>;
|
|
}
|
|
|
|
type UndoViewportArrangeResult = [
|
|
() => void, // redoViewportArrange
|
|
ViewportOverflowState?
|
|
];
|
|
|
|
const { max, round } = Math;
|
|
const overlaidScrollbarsHideOffset = 42;
|
|
const whCacheOptions = {
|
|
_equal: equalWH,
|
|
_initialValue: { w: 0, h: 0 },
|
|
};
|
|
const xyCacheOptions = {
|
|
_equal: equalXY,
|
|
_initialValue: { x: false, y: false },
|
|
};
|
|
const getSizeFraction = (elm: HTMLElement): WH<number> => {
|
|
const cssHeight = parseFloat(style(elm, 'height'));
|
|
const cssWidth = parseFloat(style(elm, 'height'));
|
|
|
|
return {
|
|
w: cssWidth - round(cssWidth),
|
|
h: cssHeight - round(cssHeight),
|
|
};
|
|
};
|
|
const fractionalPixelRatioTollerance = () => (window.devicePixelRatio % 1 === 0 ? 0 : 1);
|
|
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 {
|
|
_visible: behaviorIsVisible,
|
|
_behavior: behaviorIsVisibleHidden ? 'hidden' : 'scroll',
|
|
};
|
|
};
|
|
|
|
const getOverflowAmount = (
|
|
viewportScrollSize: WH<number>,
|
|
viewportClientSize: WH<number>,
|
|
viewportSizeFraction: WH<number>
|
|
) => ({
|
|
w: max(
|
|
0,
|
|
round(
|
|
max(0, viewportScrollSize.w - viewportClientSize.w) -
|
|
(fractionalPixelRatioTollerance() || max(0, viewportSizeFraction.w))
|
|
)
|
|
),
|
|
h: max(
|
|
0,
|
|
round(
|
|
max(0, viewportScrollSize.h - viewportClientSize.h) -
|
|
(fractionalPixelRatioTollerance() || max(0, viewportSizeFraction.h))
|
|
)
|
|
),
|
|
});
|
|
|
|
/**
|
|
* Lifecycle with the responsibility to set the correct overflow and scrollbar hiding styles of the viewport element.
|
|
* @param structureUpdateHub
|
|
* @returns
|
|
*/
|
|
export const createOverflowUpdate: CreateStructureUpdateSegment = (
|
|
structureSetupElements,
|
|
state
|
|
) => {
|
|
const [getState, setState] = state;
|
|
const { _host, _viewport, _viewportArrange } = structureSetupElements;
|
|
const {
|
|
_nativeScrollbarSize,
|
|
_flexboxGlue,
|
|
_nativeScrollbarStyling,
|
|
_nativeScrollbarIsOverlaid,
|
|
} = getEnvironment();
|
|
const doViewportArrange =
|
|
!_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
|
|
|
|
const [updateSizeFraction, getCurrentSizeFraction] = createCache<WH<number>>(
|
|
whCacheOptions,
|
|
getSizeFraction.bind(0, _host)
|
|
);
|
|
|
|
const [updateViewportScrollSizeCache, getCurrentViewportScrollSizeCache] = createCache<
|
|
WH<number>
|
|
>(whCacheOptions, scrollSize.bind(0, _viewport));
|
|
|
|
const [updateOverflowAmountCache, getCurrentOverflowAmountCache] =
|
|
createCache<WH<number>>(whCacheOptions);
|
|
|
|
const [updateOverflowScrollCache] = createCache<XY<boolean>>(xyCacheOptions);
|
|
|
|
/**
|
|
* Applies a fixed height to the viewport so it can't overflow or underflow the host element.
|
|
* @param viewportOverflowState The current overflow state.
|
|
* @param heightIntrinsic Whether the host height is intrinsic or not.
|
|
*/
|
|
const fixFlexboxGlue = (
|
|
viewportOverflowState: ViewportOverflowState,
|
|
heightIntrinsic: boolean
|
|
) => {
|
|
style(_viewport, {
|
|
height: '',
|
|
});
|
|
|
|
if (heightIntrinsic) {
|
|
const { _paddingAbsolute, _padding } = getState();
|
|
const { _overflowScroll, _scrollbarsHideOffset } = viewportOverflowState;
|
|
const hostCssHeight = parseFloat(style(_host, 'height'));
|
|
const hostClientSize = clientSize(_host);
|
|
// const hostOffsetSize = offsetSize(_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 fractionalClientHeight = hostClientSize.h + (hostCssHeight - round(hostCssHeight));
|
|
|
|
const subtractXScrollbar = !(_nativeScrollbarIsOverlaid.x && isContentBox);
|
|
|
|
style(_viewport, {
|
|
height:
|
|
fractionalClientHeight +
|
|
(_overflowScroll.x && subtractXScrollbar ? _scrollbarsHideOffset.x : 0) -
|
|
paddingVertical,
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Gets the current overflow state of the viewport.
|
|
* @param showNativeOverlaidScrollbars Whether native overlaid scrollbars are shown instead of hidden.
|
|
* @param viewportStyleObj The viewport style object where the overflow scroll property can be read of, or undefined if shall be determined.
|
|
* @returns A object which contains informations about the current overflow state.
|
|
*/
|
|
const getViewportOverflowState = (
|
|
showNativeOverlaidScrollbars: boolean,
|
|
viewportStyleObj?: StyleObject
|
|
): ViewportOverflowState => {
|
|
const { x: overlaidX, y: overlaidY } = _nativeScrollbarIsOverlaid;
|
|
const determineOverflow = !viewportStyleObj;
|
|
const arrangeHideOffset =
|
|
!_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;
|
|
const styleObj = determineOverflow
|
|
? style(_viewport, ['overflowX', 'overflowY'])
|
|
: viewportStyleObj;
|
|
const scroll = {
|
|
x: styleObj.overflowX === 'scroll',
|
|
y: styleObj.overflowY === 'scroll',
|
|
};
|
|
const nonScrollbarStylingHideOffset = {
|
|
x: overlaidX ? arrangeHideOffset : _nativeScrollbarSize.x,
|
|
y: overlaidY ? arrangeHideOffset : _nativeScrollbarSize.y,
|
|
};
|
|
const scrollbarsHideOffset = {
|
|
x: scroll.x && !_nativeScrollbarStyling ? nonScrollbarStylingHideOffset.x : 0,
|
|
y: scroll.y && !_nativeScrollbarStyling ? nonScrollbarStylingHideOffset.y : 0,
|
|
};
|
|
|
|
return {
|
|
_overflowScroll: scroll,
|
|
_scrollbarsHideOffsetArrange: {
|
|
x: overlaidX && !!arrangeHideOffset,
|
|
y: overlaidY && !!arrangeHideOffset,
|
|
},
|
|
_scrollbarsHideOffset: scrollbarsHideOffset,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Sets the overflow property of the viewport and calculates the a overflow state according to the new parameters.
|
|
* @param showNativeOverlaidScrollbars Whether to show natively overlaid scrollbars.
|
|
* @param overflowAmount The overflow amount.
|
|
* @param overflow The overflow behavior according to the options.
|
|
* @param viewportStyleObj The viewport style object to which the overflow style shall be applied.
|
|
* @returns A object which represents the newly set overflow state.
|
|
*/
|
|
const setViewportOverflowState = (
|
|
showNativeOverlaidScrollbars: boolean,
|
|
overflowAmount: WH<number>,
|
|
overflow: XY<OverflowBehavior>,
|
|
viewportStyleObj: StyleObject
|
|
): ViewportOverflowState => {
|
|
const { _visible: xVisible, _behavior: xVisibleBehavior } = setAxisOverflowStyle(
|
|
true,
|
|
overflowAmount.w,
|
|
overflow.x,
|
|
viewportStyleObj
|
|
);
|
|
const { _visible: yVisible, _behavior: yVisibleBehavior } = setAxisOverflowStyle(
|
|
false,
|
|
overflowAmount.h,
|
|
overflow.y,
|
|
viewportStyleObj
|
|
);
|
|
|
|
if (xVisible && !yVisible) {
|
|
viewportStyleObj.overflowX = xVisibleBehavior;
|
|
}
|
|
if (yVisible && !xVisible) {
|
|
viewportStyleObj.overflowY = yVisibleBehavior;
|
|
}
|
|
|
|
return getViewportOverflowState(showNativeOverlaidScrollbars, viewportStyleObj);
|
|
};
|
|
|
|
/**
|
|
* Sets the styles of the viewport arrange element.
|
|
* @param viewportOverflowState The viewport overflow state according to which the scrollbars shall be hidden.
|
|
* @param viewportScrollSize The content scroll size.
|
|
* @param directionIsRTL Whether the direction is RTL or not.
|
|
* @returns A boolean which indicates whether the viewport arrange element was adjusted.
|
|
*/
|
|
const arrangeViewport = (
|
|
viewportOverflowState: ViewportOverflowState,
|
|
viewportScrollSize: WH<number>,
|
|
sizeFraction: WH<number>,
|
|
directionIsRTL: boolean
|
|
) => {
|
|
if (doViewportArrange) {
|
|
const { _viewportPaddingStyle } = getState();
|
|
const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;
|
|
const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;
|
|
const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;
|
|
const viewportArrangeHorizontalPaddingKey: keyof StyleObject = directionIsRTL
|
|
? 'paddingRight'
|
|
: 'paddingLeft';
|
|
const viewportArrangeHorizontalPaddingValue = _viewportPaddingStyle[
|
|
viewportArrangeHorizontalPaddingKey
|
|
] as number;
|
|
const viewportArrangeVerticalPaddingValue = _viewportPaddingStyle.paddingTop as number;
|
|
const fractionalContentWidth = viewportScrollSize.w + sizeFraction.w;
|
|
const fractionalContenHeight = viewportScrollSize.h + sizeFraction.h;
|
|
const arrangeSize = {
|
|
w:
|
|
hideOffsetY && arrangeY
|
|
? `${hideOffsetY + fractionalContentWidth - viewportArrangeHorizontalPaddingValue}px`
|
|
: '',
|
|
h:
|
|
hideOffsetX && arrangeX
|
|
? `${hideOffsetX + fractionalContenHeight - viewportArrangeVerticalPaddingValue}px`
|
|
: '',
|
|
};
|
|
|
|
// adjust content arrange / before element
|
|
if (_viewportArrange) {
|
|
const { sheet } = _viewportArrange;
|
|
if (sheet) {
|
|
const { cssRules } = sheet;
|
|
if (cssRules) {
|
|
if (!cssRules.length) {
|
|
sheet.insertRule(
|
|
`#${attr(_viewportArrange, 'id')} + .${classNameViewportArrange}::before {}`,
|
|
0
|
|
);
|
|
}
|
|
|
|
// @ts-ignore
|
|
const ruleStyle = cssRules[0].style;
|
|
|
|
ruleStyle.width = arrangeSize.w;
|
|
ruleStyle.height = arrangeSize.h;
|
|
}
|
|
}
|
|
} else {
|
|
style<'--os-vaw' | '--os-vah'>(_viewport, {
|
|
'--os-vaw': arrangeSize.w,
|
|
'--os-vah': arrangeSize.h,
|
|
});
|
|
}
|
|
}
|
|
|
|
return doViewportArrange;
|
|
};
|
|
|
|
/**
|
|
* Hides the native scrollbars according to the passed parameters.
|
|
* @param viewportOverflowState The viewport overflow state.
|
|
* @param directionIsRTL Whether the direction is RTL or not.
|
|
* @param viewportArrange Whether special styles related to the viewport arrange strategy shall be applied.
|
|
* @param viewportStyleObj The viewport style object to which the needed styles shall be applied.
|
|
*/
|
|
const hideNativeScrollbars = (
|
|
viewportOverflowState: ViewportOverflowState,
|
|
directionIsRTL: boolean,
|
|
viewportArrange: boolean,
|
|
viewportStyleObj: StyleObject
|
|
) => {
|
|
const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;
|
|
const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;
|
|
const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;
|
|
const { _viewportPaddingStyle: viewportPaddingStyle } = getState();
|
|
const horizontalMarginKey: keyof StyleObject = directionIsRTL ? 'marginLeft' : 'marginRight';
|
|
const viewportHorizontalPaddingKey: keyof StyleObject = directionIsRTL
|
|
? 'paddingLeft'
|
|
: 'paddingRight';
|
|
const horizontalMarginValue = viewportPaddingStyle[horizontalMarginKey] as number;
|
|
const verticalMarginValue = viewportPaddingStyle.marginBottom as number;
|
|
const horizontalPaddingValue = viewportPaddingStyle[viewportHorizontalPaddingKey] as number;
|
|
const verticalPaddingValue = viewportPaddingStyle.paddingBottom as number;
|
|
|
|
// horizontal
|
|
viewportStyleObj.width = `calc(100% + ${hideOffsetY + horizontalMarginValue * -1}px)`;
|
|
viewportStyleObj[horizontalMarginKey] = -hideOffsetY + horizontalMarginValue;
|
|
|
|
// vertical
|
|
viewportStyleObj.marginBottom = -hideOffsetX + verticalMarginValue;
|
|
|
|
// viewport arrange additional styles
|
|
if (viewportArrange) {
|
|
viewportStyleObj[viewportHorizontalPaddingKey] =
|
|
horizontalPaddingValue + (arrangeY ? hideOffsetY : 0);
|
|
viewportStyleObj.paddingBottom = verticalPaddingValue + (arrangeX ? hideOffsetX : 0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Removes all styles applied because of the viewport arrange strategy.
|
|
* @param showNativeOverlaidScrollbars Whether native overlaid scrollbars are shown instead of hidden.
|
|
* @param directionIsRTL Whether the direction is RTL or not.
|
|
* @param viewportOverflowState The currentviewport overflow state or undefined if it has to be determined.
|
|
* @returns A object with a function which applies all the removed styles and the determined viewport vverflow state.
|
|
*/
|
|
const undoViewportArrange = (
|
|
showNativeOverlaidScrollbars: boolean,
|
|
directionIsRTL: boolean,
|
|
viewportOverflowState?: ViewportOverflowState
|
|
): UndoViewportArrangeResult => {
|
|
if (doViewportArrange) {
|
|
const finalViewportOverflowState =
|
|
viewportOverflowState || getViewportOverflowState(showNativeOverlaidScrollbars);
|
|
const { _viewportPaddingStyle: viewportPaddingStyle } = getState();
|
|
const { _scrollbarsHideOffsetArrange } = finalViewportOverflowState;
|
|
const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;
|
|
const finalPaddingStyle: StyleObject = {};
|
|
const assignProps = (props: string) =>
|
|
each(props.split(' '), (prop) => {
|
|
finalPaddingStyle[prop] = viewportPaddingStyle[prop];
|
|
});
|
|
|
|
if (arrangeX) {
|
|
assignProps('marginBottom paddingTop paddingBottom');
|
|
}
|
|
|
|
if (arrangeY) {
|
|
assignProps('marginLeft marginRight paddingLeft paddingRight');
|
|
}
|
|
|
|
const prevStyle = style(_viewport, keys(finalPaddingStyle));
|
|
|
|
removeClass(_viewport, classNameViewportArrange);
|
|
|
|
if (!_flexboxGlue) {
|
|
finalPaddingStyle.height = '';
|
|
}
|
|
|
|
style(_viewport, finalPaddingStyle);
|
|
|
|
return [
|
|
() => {
|
|
hideNativeScrollbars(
|
|
finalViewportOverflowState,
|
|
directionIsRTL,
|
|
doViewportArrange,
|
|
prevStyle
|
|
);
|
|
style(_viewport, prevStyle);
|
|
addClass(_viewport, classNameViewportArrange);
|
|
},
|
|
finalViewportOverflowState,
|
|
];
|
|
}
|
|
return [noop];
|
|
};
|
|
|
|
return (updateHints, checkOption, force) => {
|
|
const {
|
|
_sizeChanged,
|
|
_hostMutation,
|
|
_contentMutation,
|
|
_paddingStyleChanged,
|
|
_heightIntrinsicChanged,
|
|
_directionChanged,
|
|
} = updateHints;
|
|
const { _heightIntrinsic, _directionIsRTL } = getState();
|
|
const [showNativeOverlaidScrollbarsOption, showNativeOverlaidScrollbarsChanged] =
|
|
checkOption<boolean>('nativeScrollbarsOverlaid.show');
|
|
const showNativeOverlaidScrollbars =
|
|
showNativeOverlaidScrollbarsOption &&
|
|
_nativeScrollbarIsOverlaid.x &&
|
|
_nativeScrollbarIsOverlaid.y;
|
|
const adjustFlexboxGlue =
|
|
!_flexboxGlue &&
|
|
(_sizeChanged ||
|
|
_contentMutation ||
|
|
_hostMutation ||
|
|
showNativeOverlaidScrollbarsChanged ||
|
|
_heightIntrinsicChanged);
|
|
|
|
let sizeFractionCache: CacheValues<WH<number>> = getCurrentSizeFraction(force);
|
|
let viewportScrollSizeCache: CacheValues<WH<number>> = getCurrentViewportScrollSizeCache(force);
|
|
let overflowAmuntCache: CacheValues<WH<number>> = getCurrentOverflowAmountCache(force);
|
|
let preMeasureViewportOverflowState: ViewportOverflowState | undefined;
|
|
|
|
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
|
|
if (showNativeOverlaidScrollbars) {
|
|
removeClass(_viewport, classNameViewportScrollbarStyling);
|
|
} else {
|
|
addClass(_viewport, classNameViewportScrollbarStyling);
|
|
}
|
|
}
|
|
|
|
if (adjustFlexboxGlue) {
|
|
preMeasureViewportOverflowState = getViewportOverflowState(showNativeOverlaidScrollbars);
|
|
fixFlexboxGlue(preMeasureViewportOverflowState, _heightIntrinsic);
|
|
}
|
|
|
|
if (
|
|
_sizeChanged ||
|
|
_paddingStyleChanged ||
|
|
_contentMutation ||
|
|
_directionChanged ||
|
|
showNativeOverlaidScrollbarsChanged
|
|
) {
|
|
const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange(
|
|
showNativeOverlaidScrollbars,
|
|
_directionIsRTL,
|
|
preMeasureViewportOverflowState
|
|
);
|
|
const [sizeFraction, sizeFractionChanged] = (sizeFractionCache = updateSizeFraction(force));
|
|
const [viewportScrollSize, viewportScrollSizeChanged] = (viewportScrollSizeCache =
|
|
updateViewportScrollSizeCache(force));
|
|
const viewportContentSize = clientSize(_viewport);
|
|
let arrangedViewportScrollSize = viewportScrollSize;
|
|
let arrangedViewportClientSize = viewportContentSize;
|
|
|
|
redoViewportArrange();
|
|
|
|
// if re measure is required (only required if content arrange strategy is used)
|
|
if (
|
|
(viewportScrollSizeChanged || sizeFractionChanged || showNativeOverlaidScrollbarsChanged) &&
|
|
undoViewportArrangeOverflowState &&
|
|
!showNativeOverlaidScrollbars &&
|
|
arrangeViewport(
|
|
undoViewportArrangeOverflowState,
|
|
viewportScrollSize,
|
|
sizeFraction,
|
|
_directionIsRTL
|
|
)
|
|
) {
|
|
arrangedViewportClientSize = clientSize(_viewport);
|
|
arrangedViewportScrollSize = scrollSize(_viewport);
|
|
}
|
|
|
|
overflowAmuntCache = updateOverflowAmountCache(
|
|
getOverflowAmount(
|
|
{
|
|
w: max(viewportScrollSize.w, arrangedViewportScrollSize.w),
|
|
h: max(viewportScrollSize.h, arrangedViewportScrollSize.h),
|
|
}, // scroll size
|
|
{
|
|
w: arrangedViewportClientSize.w + max(0, viewportContentSize.w - viewportScrollSize.w),
|
|
h: arrangedViewportClientSize.h + max(0, viewportContentSize.h - viewportScrollSize.h),
|
|
}, // client size
|
|
sizeFraction
|
|
),
|
|
force
|
|
);
|
|
}
|
|
|
|
const [sizeFraction, sizeFractionChanged] = sizeFractionCache;
|
|
const [viewportScrollSize, viewportScrollSizeChanged] = viewportScrollSizeCache;
|
|
const [overflowAmount, overflowAmountChanged] = overflowAmuntCache;
|
|
const [overflow, overflowChanged] = checkOption<XY<OverflowBehavior>>('overflow');
|
|
|
|
if (
|
|
_paddingStyleChanged ||
|
|
_directionChanged ||
|
|
sizeFractionChanged ||
|
|
viewportScrollSizeChanged ||
|
|
overflowAmountChanged ||
|
|
overflowChanged ||
|
|
showNativeOverlaidScrollbarsChanged ||
|
|
adjustFlexboxGlue
|
|
) {
|
|
const viewportStyle: StyleObject = {
|
|
marginRight: 0,
|
|
marginBottom: 0,
|
|
marginLeft: 0,
|
|
width: '',
|
|
overflowY: '',
|
|
overflowX: '',
|
|
};
|
|
|
|
const viewportOverflowState = setViewportOverflowState(
|
|
showNativeOverlaidScrollbars,
|
|
overflowAmount,
|
|
overflow,
|
|
viewportStyle
|
|
);
|
|
const viewportArranged = arrangeViewport(
|
|
viewportOverflowState,
|
|
viewportScrollSize,
|
|
sizeFraction,
|
|
_directionIsRTL
|
|
);
|
|
const [overflowScroll, overflowScrollChanged] = updateOverflowScrollCache(
|
|
viewportOverflowState._overflowScroll
|
|
);
|
|
hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);
|
|
|
|
if (adjustFlexboxGlue) {
|
|
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({
|
|
_viewportOverflowScroll: overflowScroll,
|
|
_viewportOverflowAmount: overflowAmount,
|
|
});
|
|
|
|
return {
|
|
_overflowAmountChanged: overflowAmountChanged,
|
|
_overflowScrollChanged: overflowScrollChanged,
|
|
};
|
|
}
|
|
};
|
|
};
|