mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-16 23:40:35 +03:00
fix size observer for content-box
This commit is contained in:
@@ -57,7 +57,7 @@ export const createLifecycleBase = <O, C>(
|
|||||||
const cacheOptions = createCache<O>(options, true);
|
const cacheOptions = createCache<O>(options, true);
|
||||||
|
|
||||||
const update = (hints: LifecycleUpdateHints<O, C>) => {
|
const update = (hints: LifecycleUpdateHints<O, C>) => {
|
||||||
const hasForce = isBoolean(hints._force);
|
const hasForce = isBoolean(hints._force); // indication that it was called from outside
|
||||||
const force = hints._force === true;
|
const force = hints._force === true;
|
||||||
|
|
||||||
const changedCache = cacheChange(force ? null : hints._changedCache || (hasForce ? null : []), force);
|
const changedCache = cacheChange(force ? null : hints._changedCache || (hasForce ? null : []), force);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const createStructureLifecycle = (
|
|||||||
target: OSTargetObject,
|
target: OSTargetObject,
|
||||||
initialOptions?: StructureLifecycleOptions
|
initialOptions?: StructureLifecycleOptions
|
||||||
): Lifecycle<StructureLifecycleOptions> => {
|
): Lifecycle<StructureLifecycleOptions> => {
|
||||||
const { host, viewport, content } = target;
|
const { host, padding: paddingElm, viewport, content } = target;
|
||||||
const destructFns: (() => any)[] = [];
|
const destructFns: (() => any)[] = [];
|
||||||
const env: Environment = getEnvironment();
|
const env: Environment = getEnvironment();
|
||||||
const scrollbarsOverlaid = env._nativeScrollbarIsOverlaid;
|
const scrollbarsOverlaid = env._nativeScrollbarIsOverlaid;
|
||||||
@@ -74,7 +74,7 @@ export const createStructureLifecycle = (
|
|||||||
paddingStyle.b -= env._nativeScrollbarSize.x;
|
paddingStyle.b -= env._nativeScrollbarSize.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
style(viewport, { top: paddingStyle.t, left: paddingStyle.l, 'margin-right': paddingStyle.r, 'margin-bottom': paddingStyle.b });
|
style(paddingElm, { top: paddingStyle.t, left: paddingStyle.l, 'margin-right': paddingStyle.r, 'margin-bottom': paddingStyle.b });
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(options); // eslint-disable-line
|
console.log(options); // eslint-disable-line
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const ResizeObserverConstructor = jsAPI('ResizeObserver');
|
|||||||
const classNameSizeObserver = 'os-size-observer';
|
const classNameSizeObserver = 'os-size-observer';
|
||||||
const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;
|
const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;
|
||||||
const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;
|
const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;
|
||||||
|
const classNameSizeObserverListenerScroll = `${classNameSizeObserverListener}-scroll`;
|
||||||
const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;
|
const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;
|
||||||
const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
|
const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
|
||||||
const cAF = cancelAnimationFrame;
|
const cAF = cancelAnimationFrame;
|
||||||
@@ -65,6 +66,7 @@ export const createSizeObserver = (
|
|||||||
`<div class="${classNameSizeObserverListenerItem}" dir="ltr"><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}"></div></div><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}" style="width: 200%; height: 200%"></div></div></div>`
|
`<div class="${classNameSizeObserverListenerItem}" dir="ltr"><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}"></div></div><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}" style="width: 200%; height: 200%"></div></div></div>`
|
||||||
);
|
);
|
||||||
appendChildren(listenerElement, observerElementChildren);
|
appendChildren(listenerElement, observerElementChildren);
|
||||||
|
addClass(listenerElement, classNameSizeObserverListenerScroll);
|
||||||
const observerElementChildrenRoot = observerElementChildren[0] as HTMLElement;
|
const observerElementChildrenRoot = observerElementChildren[0] as HTMLElement;
|
||||||
const shrinkElement = observerElementChildrenRoot.lastChild as HTMLElement;
|
const shrinkElement = observerElementChildrenRoot.lastChild as HTMLElement;
|
||||||
const expandElement = observerElementChildrenRoot.firstChild as HTMLElement;
|
const expandElement = observerElementChildrenRoot.firstChild as HTMLElement;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { createTrinsicObserver } from 'observers/trinsicObserver';
|
|||||||
import { Lifecycle } from 'lifecycles/lifecycleBase';
|
import { Lifecycle } from 'lifecycles/lifecycleBase';
|
||||||
|
|
||||||
const classNameHost = 'os-host';
|
const classNameHost = 'os-host';
|
||||||
|
const classNamePadding = 'os-padding';
|
||||||
const classNameViewport = 'os-viewport';
|
const classNameViewport = 'os-viewport';
|
||||||
const classNameContent = 'os-content';
|
const classNameContent = 'os-content';
|
||||||
|
|
||||||
@@ -13,25 +14,29 @@ const normalizeTarget = (target: OSTarget): OSTargetObject => {
|
|||||||
if (isHTMLElement(target)) {
|
if (isHTMLElement(target)) {
|
||||||
const isTextarea = is(target, 'textarea');
|
const isTextarea = is(target, 'textarea');
|
||||||
const host = (isTextarea ? createDiv() : target) as HTMLElement;
|
const host = (isTextarea ? createDiv() : target) as HTMLElement;
|
||||||
|
const padding = createDiv(classNamePadding);
|
||||||
const viewport = createDiv(classNameViewport);
|
const viewport = createDiv(classNameViewport);
|
||||||
const content = createDiv(classNameContent);
|
const content = createDiv(classNameContent);
|
||||||
|
|
||||||
|
appendChildren(padding, viewport);
|
||||||
appendChildren(viewport, content);
|
appendChildren(viewport, content);
|
||||||
appendChildren(content, contents(target));
|
appendChildren(content, contents(target));
|
||||||
appendChildren(target, viewport);
|
appendChildren(target, padding);
|
||||||
addClass(host, classNameHost);
|
addClass(host, classNameHost);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
target,
|
target,
|
||||||
host,
|
host,
|
||||||
|
padding,
|
||||||
viewport,
|
viewport,
|
||||||
content,
|
content,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { host, viewport, content } = target;
|
const { host, padding, viewport, content } = target;
|
||||||
|
|
||||||
addClass(host, classNameHost);
|
addClass(host, classNameHost);
|
||||||
|
addClass(padding, classNamePadding);
|
||||||
addClass(viewport, classNameViewport);
|
addClass(viewport, classNameViewport);
|
||||||
addClass(content, classNameContent);
|
addClass(content, classNameContent);
|
||||||
|
|
||||||
|
|||||||
@@ -34,9 +34,8 @@ $scrollbar-cushion: 100px;
|
|||||||
|
|
||||||
.os-size-observer-listener {
|
.os-size-observer-listener {
|
||||||
display: block;
|
display: block;
|
||||||
height: 200%;
|
height: 500%;
|
||||||
width: 200%;
|
width: 500%;
|
||||||
box-sizing: content-box;
|
|
||||||
|
|
||||||
// lets assume no scrollbar is 100px wide
|
// lets assume no scrollbar is 100px wide
|
||||||
& > .os-size-observer-listener-item {
|
& > .os-size-observer-listener-item {
|
||||||
@@ -47,6 +46,10 @@ $scrollbar-cushion: 100px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.os-size-observer-listener-scroll {
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
.os-size-observer-listener-item {
|
.os-size-observer-listener-item {
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
.os-host {
|
.os-host,
|
||||||
|
.os-padding {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.os-padding,
|
||||||
.os-viewport {
|
.os-viewport {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -15,6 +17,8 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
border: none;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
max-width: 100%;
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.os-content {
|
.os-content {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export type OSTargetElement = HTMLElement | HTMLTextAreaElement;
|
|||||||
export interface OSTargetObject {
|
export interface OSTargetObject {
|
||||||
target: OSTargetElement;
|
target: OSTargetElement;
|
||||||
host: HTMLElement;
|
host: HTMLElement;
|
||||||
|
padding: HTMLElement;
|
||||||
viewport: HTMLElement;
|
viewport: HTMLElement;
|
||||||
content: HTMLElement;
|
content: HTMLElement;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-10
@@ -10,16 +10,16 @@ import { createSizeObserver } from 'observers/sizeObserver';
|
|||||||
|
|
||||||
let sizeIterations = 0;
|
let sizeIterations = 0;
|
||||||
let directionIterations = 0;
|
let directionIterations = 0;
|
||||||
const contentBox = (elm: HTMLElement | null) => {
|
const contentBox = (elm: HTMLElement | null): WH<number> => {
|
||||||
if (elm) {
|
if (elm) {
|
||||||
const computedStyle = window.getComputedStyle(elm);
|
const computedStyle = window.getComputedStyle(elm);
|
||||||
return {
|
return {
|
||||||
width: elm.clientWidth - (parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight)),
|
w: elm.clientWidth - (parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight)),
|
||||||
height: elm.clientHeight - (parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom)),
|
h: elm.clientHeight - (parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { width: 0, height: 0 };
|
return { w: 0, h: 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
const targetElm = document.querySelector('#target');
|
const targetElm = document.querySelector('#target');
|
||||||
@@ -39,6 +39,7 @@ const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any)
|
|||||||
currSizeIterations: number;
|
currSizeIterations: number;
|
||||||
currDirectionIterations: number;
|
currDirectionIterations: number;
|
||||||
currOffsetSize: WH<number>;
|
currOffsetSize: WH<number>;
|
||||||
|
currContentSize: WH<number>;
|
||||||
currDir: string;
|
currDir: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,36 +48,39 @@ const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any)
|
|||||||
const currSizeIterations = sizeIterations;
|
const currSizeIterations = sizeIterations;
|
||||||
const currDirectionIterations = directionIterations;
|
const currDirectionIterations = directionIterations;
|
||||||
const currOffsetSize = offsetSize(targetElm as HTMLElement);
|
const currOffsetSize = offsetSize(targetElm as HTMLElement);
|
||||||
|
const currContentSize = contentBox(targetElm as HTMLElement);
|
||||||
const currDir = style(targetElm as HTMLElement, 'direction');
|
const currDir = style(targetElm as HTMLElement, 'direction');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currSizeIterations,
|
currSizeIterations,
|
||||||
currDirectionIterations,
|
currDirectionIterations,
|
||||||
currOffsetSize,
|
currOffsetSize,
|
||||||
|
currContentSize,
|
||||||
currDir,
|
currDir,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async check({ currSizeIterations, currDirectionIterations, currOffsetSize, currDir }) {
|
async check({ currSizeIterations, currDirectionIterations, currOffsetSize, currContentSize, currDir }) {
|
||||||
const newOffsetSize = offsetSize(targetElm as HTMLElement);
|
const newOffsetSize = offsetSize(targetElm as HTMLElement);
|
||||||
|
const newContentSize = contentBox(targetElm as HTMLElement);
|
||||||
const newDir = style(targetElm as HTMLElement, 'direction');
|
const newDir = style(targetElm as HTMLElement, 'direction');
|
||||||
const offsetSizeChanged = currOffsetSize.w !== newOffsetSize.w || currOffsetSize.h !== newOffsetSize.h;
|
const offsetSizeChanged = currOffsetSize.w !== newOffsetSize.w || currOffsetSize.h !== newOffsetSize.h;
|
||||||
|
const contentSizeChanged = currContentSize.w !== newContentSize.w || currContentSize.h !== newContentSize.h;
|
||||||
const dirChanged = currDir !== newDir;
|
const dirChanged = currDir !== newDir;
|
||||||
const dimensions = hasDimensions(targetElm as HTMLElement);
|
const dimensions = hasDimensions(targetElm as HTMLElement);
|
||||||
const contentSize = contentBox(targetElm as HTMLElement);
|
|
||||||
const observerElm = targetElm?.firstElementChild as HTMLElement;
|
const observerElm = targetElm?.firstElementChild as HTMLElement;
|
||||||
|
|
||||||
// no overflow if not needed
|
// no overflow if not needed
|
||||||
if (targetElm && contentSize.width > 0) {
|
if (targetElm && newContentSize.w > 0) {
|
||||||
should.ok(observerElm.getBoundingClientRect().right <= targetElm.getBoundingClientRect().right);
|
should.ok(observerElm.getBoundingClientRect().right <= targetElm.getBoundingClientRect().right);
|
||||||
}
|
}
|
||||||
if (targetElm && contentSize.height > 0) {
|
if (targetElm && newContentSize.h > 0) {
|
||||||
should.ok(observerElm.getBoundingClientRect().bottom <= targetElm.getBoundingClientRect().bottom);
|
should.ok(observerElm.getBoundingClientRect().bottom <= targetElm.getBoundingClientRect().bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dimensions && (offsetSizeChanged || dirChanged)) {
|
if (dimensions && (offsetSizeChanged || contentSizeChanged || dirChanged)) {
|
||||||
await waitFor(
|
await waitFor(
|
||||||
() => {
|
() => {
|
||||||
if (offsetSizeChanged) {
|
if (offsetSizeChanged || contentSizeChanged) {
|
||||||
should.equal(sizeIterations, currSizeIterations + 1);
|
should.equal(sizeIterations, currSizeIterations + 1);
|
||||||
}
|
}
|
||||||
if (dirChanged) {
|
if (dirChanged) {
|
||||||
|
|||||||
Reference in New Issue
Block a user