From fca2dff86985c1e6ecf86303c5f88562a67b24da Mon Sep 17 00:00:00 2001 From: Rene Date: Sun, 27 Dec 2020 13:39:51 +0100 Subject: [PATCH] fix size observer for content-box --- .../src/lifecycles/lifecycleBase.ts | 2 +- .../src/lifecycles/structureLifecycle.ts | 4 ++-- .../src/observers/sizeObserver.ts | 2 ++ .../overlayscrollbars/OverlayScrollbars.ts | 9 +++++-- .../overlayscrollbars/src/sizeobserver.scss | 9 ++++--- .../src/structurelifecycle.scss | 6 ++++- packages/overlayscrollbars/src/typings.ts | 1 + .../observers/sizeObserver/index.browser.ts | 24 +++++++++++-------- 8 files changed, 38 insertions(+), 19 deletions(-) diff --git a/packages/overlayscrollbars/src/lifecycles/lifecycleBase.ts b/packages/overlayscrollbars/src/lifecycles/lifecycleBase.ts index 253d714..7c82232 100644 --- a/packages/overlayscrollbars/src/lifecycles/lifecycleBase.ts +++ b/packages/overlayscrollbars/src/lifecycles/lifecycleBase.ts @@ -57,7 +57,7 @@ export const createLifecycleBase = ( const cacheOptions = createCache(options, true); const update = (hints: LifecycleUpdateHints) => { - 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); diff --git a/packages/overlayscrollbars/src/lifecycles/structureLifecycle.ts b/packages/overlayscrollbars/src/lifecycles/structureLifecycle.ts index e3f58a1..775b218 100644 --- a/packages/overlayscrollbars/src/lifecycles/structureLifecycle.ts +++ b/packages/overlayscrollbars/src/lifecycles/structureLifecycle.ts @@ -29,7 +29,7 @@ export const createStructureLifecycle = ( target: OSTargetObject, initialOptions?: StructureLifecycleOptions ): Lifecycle => { - 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 diff --git a/packages/overlayscrollbars/src/observers/sizeObserver.ts b/packages/overlayscrollbars/src/observers/sizeObserver.ts index 6ba85cf..16b47bf 100644 --- a/packages/overlayscrollbars/src/observers/sizeObserver.ts +++ b/packages/overlayscrollbars/src/observers/sizeObserver.ts @@ -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 = ( `
` ); appendChildren(listenerElement, observerElementChildren); + addClass(listenerElement, classNameSizeObserverListenerScroll); const observerElementChildrenRoot = observerElementChildren[0] as HTMLElement; const shrinkElement = observerElementChildrenRoot.lastChild as HTMLElement; const expandElement = observerElementChildrenRoot.firstChild as HTMLElement; diff --git a/packages/overlayscrollbars/src/overlayscrollbars/OverlayScrollbars.ts b/packages/overlayscrollbars/src/overlayscrollbars/OverlayScrollbars.ts index 723f1d7..fb15dd7 100644 --- a/packages/overlayscrollbars/src/overlayscrollbars/OverlayScrollbars.ts +++ b/packages/overlayscrollbars/src/overlayscrollbars/OverlayScrollbars.ts @@ -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); diff --git a/packages/overlayscrollbars/src/sizeobserver.scss b/packages/overlayscrollbars/src/sizeobserver.scss index 6605fd0..a0eab2d 100644 --- a/packages/overlayscrollbars/src/sizeobserver.scss +++ b/packages/overlayscrollbars/src/sizeobserver.scss @@ -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; diff --git a/packages/overlayscrollbars/src/structurelifecycle.scss b/packages/overlayscrollbars/src/structurelifecycle.scss index b1d9874..99e8ba2 100644 --- a/packages/overlayscrollbars/src/structurelifecycle.scss +++ b/packages/overlayscrollbars/src/structurelifecycle.scss @@ -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 { diff --git a/packages/overlayscrollbars/src/typings.ts b/packages/overlayscrollbars/src/typings.ts index 341fa98..4ea60b8 100644 --- a/packages/overlayscrollbars/src/typings.ts +++ b/packages/overlayscrollbars/src/typings.ts @@ -5,6 +5,7 @@ export type OSTargetElement = HTMLElement | HTMLTextAreaElement; export interface OSTargetObject { target: OSTargetElement; host: HTMLElement; + padding: HTMLElement; viewport: HTMLElement; content: HTMLElement; } diff --git a/packages/overlayscrollbars/tests/puppeteer/observers/sizeObserver/index.browser.ts b/packages/overlayscrollbars/tests/puppeteer/observers/sizeObserver/index.browser.ts index 2230e84..b10b2cf 100644 --- a/packages/overlayscrollbars/tests/puppeteer/observers/sizeObserver/index.browser.ts +++ b/packages/overlayscrollbars/tests/puppeteer/observers/sizeObserver/index.browser.ts @@ -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 => { 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; + currContentSize: WH; 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) {