fix size observer for content-box

This commit is contained in:
Rene
2020-12-27 13:39:51 +01:00
parent aaa87e208a
commit fca2dff869
8 changed files with 38 additions and 19 deletions
@@ -57,7 +57,7 @@ export const createLifecycleBase = <O, C>(
const cacheOptions = createCache<O>(options, true);
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 changedCache = cacheChange(force ? null : hints._changedCache || (hasForce ? null : []), force);
@@ -29,7 +29,7 @@ export const createStructureLifecycle = (
target: OSTargetObject,
initialOptions?: StructureLifecycleOptions
): Lifecycle<StructureLifecycleOptions> => {
const { host, viewport, content } = target;
const { host, padding: paddingElm, viewport, content } = target;
const destructFns: (() => any)[] = [];
const env: Environment = getEnvironment();
const scrollbarsOverlaid = env._nativeScrollbarIsOverlaid;
@@ -74,7 +74,7 @@ export const createStructureLifecycle = (
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
@@ -25,6 +25,7 @@ const ResizeObserverConstructor = jsAPI('ResizeObserver');
const classNameSizeObserver = 'os-size-observer';
const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;
const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;
const classNameSizeObserverListenerScroll = `${classNameSizeObserverListener}-scroll`;
const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;
const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
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>`
);
appendChildren(listenerElement, observerElementChildren);
addClass(listenerElement, classNameSizeObserverListenerScroll);
const observerElementChildrenRoot = observerElementChildren[0] as HTMLElement;
const shrinkElement = observerElementChildrenRoot.lastChild as HTMLElement;
const expandElement = observerElementChildrenRoot.firstChild as HTMLElement;
@@ -6,6 +6,7 @@ import { createTrinsicObserver } from 'observers/trinsicObserver';
import { Lifecycle } from 'lifecycles/lifecycleBase';
const classNameHost = 'os-host';
const classNamePadding = 'os-padding';
const classNameViewport = 'os-viewport';
const classNameContent = 'os-content';
@@ -13,25 +14,29 @@ const normalizeTarget = (target: OSTarget): OSTargetObject => {
if (isHTMLElement(target)) {
const isTextarea = is(target, 'textarea');
const host = (isTextarea ? createDiv() : target) as HTMLElement;
const padding = createDiv(classNamePadding);
const viewport = createDiv(classNameViewport);
const content = createDiv(classNameContent);
appendChildren(padding, viewport);
appendChildren(viewport, content);
appendChildren(content, contents(target));
appendChildren(target, viewport);
appendChildren(target, padding);
addClass(host, classNameHost);
return {
target,
host,
padding,
viewport,
content,
};
}
const { host, viewport, content } = target;
const { host, padding, viewport, content } = target;
addClass(host, classNameHost);
addClass(padding, classNamePadding);
addClass(viewport, classNameViewport);
addClass(content, classNameContent);
@@ -34,9 +34,8 @@ $scrollbar-cushion: 100px;
.os-size-observer-listener {
display: block;
height: 200%;
width: 200%;
box-sizing: content-box;
height: 500%;
width: 500%;
// lets assume no scrollbar is 100px wide
& > .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 {
right: 0;
bottom: 0;
@@ -1,10 +1,12 @@
.os-host {
.os-host,
.os-padding {
position: relative;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.os-padding,
.os-viewport {
box-sizing: border-box;
position: relative;
@@ -15,6 +17,8 @@
margin: 0;
border: none;
overflow: visible;
max-width: 100%;
z-index: 0;
}
.os-content {
@@ -5,6 +5,7 @@ export type OSTargetElement = HTMLElement | HTMLTextAreaElement;
export interface OSTargetObject {
target: OSTargetElement;
host: HTMLElement;
padding: HTMLElement;
viewport: HTMLElement;
content: HTMLElement;
}
@@ -10,16 +10,16 @@ import { createSizeObserver } from 'observers/sizeObserver';
let sizeIterations = 0;
let directionIterations = 0;
const contentBox = (elm: HTMLElement | null) => {
const contentBox = (elm: HTMLElement | null): WH<number> => {
if (elm) {
const computedStyle = window.getComputedStyle(elm);
return {
width: elm.clientWidth - (parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight)),
height: elm.clientHeight - (parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom)),
w: elm.clientWidth - (parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight)),
h: elm.clientHeight - (parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom)),
};
}
return { width: 0, height: 0 };
return { w: 0, h: 0 };
};
const targetElm = document.querySelector('#target');
@@ -39,6 +39,7 @@ const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any)
currSizeIterations: number;
currDirectionIterations: number;
currOffsetSize: WH<number>;
currContentSize: WH<number>;
currDir: string;
}
@@ -47,36 +48,39 @@ const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any)
const currSizeIterations = sizeIterations;
const currDirectionIterations = directionIterations;
const currOffsetSize = offsetSize(targetElm as HTMLElement);
const currContentSize = contentBox(targetElm as HTMLElement);
const currDir = style(targetElm as HTMLElement, 'direction');
return {
currSizeIterations,
currDirectionIterations,
currOffsetSize,
currContentSize,
currDir,
};
},
async check({ currSizeIterations, currDirectionIterations, currOffsetSize, currDir }) {
async check({ currSizeIterations, currDirectionIterations, currOffsetSize, currContentSize, currDir }) {
const newOffsetSize = offsetSize(targetElm as HTMLElement);
const newContentSize = contentBox(targetElm as HTMLElement);
const newDir = style(targetElm as HTMLElement, 'direction');
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 dimensions = hasDimensions(targetElm as HTMLElement);
const contentSize = contentBox(targetElm as HTMLElement);
const observerElm = targetElm?.firstElementChild as HTMLElement;
// no overflow if not needed
if (targetElm && contentSize.width > 0) {
if (targetElm && newContentSize.w > 0) {
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);
}
if (dimensions && (offsetSizeChanged || dirChanged)) {
if (dimensions && (offsetSizeChanged || contentSizeChanged || dirChanged)) {
await waitFor(
() => {
if (offsetSizeChanged) {
if (offsetSizeChanged || contentSizeChanged) {
should.equal(sizeIterations, currSizeIterations + 1);
}
if (dirChanged) {