diff --git a/packages/overlayscrollbars/src/index.ts b/packages/overlayscrollbars/src/index.ts
index 0f35efe..aa80cd1 100644
--- a/packages/overlayscrollbars/src/index.ts
+++ b/packages/overlayscrollbars/src/index.ts
@@ -1,6 +1,7 @@
import { createDOM } from 'support/dom';
import { getEnvironment } from 'environment';
import { createSizeObserver } from 'overlayscrollbars/observers/SizeObserver';
+import { createTrinsicObserver } from 'overlayscrollbars/observers/TrinsicObserver';
const abc = {
a: 1,
@@ -12,6 +13,7 @@ export default () => {
return [
getEnvironment(),
createSizeObserver(document.body, () => {}),
+ createTrinsicObserver(document.body, () => {}),
createDOM(
'\
\
diff --git a/packages/overlayscrollbars/src/overlayscrollbars.scss b/packages/overlayscrollbars/src/overlayscrollbars.scss
index eae946d..e31bb56 100644
--- a/packages/overlayscrollbars/src/overlayscrollbars.scss
+++ b/packages/overlayscrollbars/src/overlayscrollbars.scss
@@ -1,4 +1,5 @@
@import './sizeobserver.scss';
+@import './trinsicobserver.scss';
#os-environment {
position: fixed;
diff --git a/packages/overlayscrollbars/src/overlayscrollbars/observers/SizeObserver.ts b/packages/overlayscrollbars/src/overlayscrollbars/observers/SizeObserver.ts
index 297d45f..914d8fa 100644
--- a/packages/overlayscrollbars/src/overlayscrollbars/observers/SizeObserver.ts
+++ b/packages/overlayscrollbars/src/overlayscrollbars/observers/SizeObserver.ts
@@ -52,7 +52,7 @@ export const createSizeObserver = (
onSizeChangedCallback(dir === true);
};
const offListeners: (() => void)[] = [];
- let appearCallback: (...args: any) => any = onSizeChangedCallbackProxy;
+ let appearCallback: ((...args: any) => any) | null = appear ? onSizeChangedCallbackProxy : null;
if (ResizeObserverConstructor) {
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
@@ -81,7 +81,9 @@ export const createSizeObserver = (
};
const onResized = function () {
rAFId = 0;
- if (!isDirty) return;
+ if (!isDirty) {
+ return;
+ }
cacheSize = currSize;
onSizeChangedCallbackProxy();
@@ -114,7 +116,7 @@ export const createSizeObserver = (
height: scrollAmount,
});
reset();
- appearCallback = onScroll;
+ appearCallback = appear ? onScroll : reset;
}
if (direction) {
@@ -140,7 +142,8 @@ export const createSizeObserver = (
);
}
- if (appear) {
+ // appearCallback is always needed on scroll-observer strategy to reset it
+ if (appearCallback) {
addClass(sizeObserver, classNameSizeObserverAppear);
offListeners.push(on(sizeObserver, animationStartEventName, appearCallback));
}
diff --git a/packages/overlayscrollbars/src/overlayscrollbars/observers/TrinsicObserver.ts b/packages/overlayscrollbars/src/overlayscrollbars/observers/TrinsicObserver.ts
index 1adf14b..88b09f9 100644
--- a/packages/overlayscrollbars/src/overlayscrollbars/observers/TrinsicObserver.ts
+++ b/packages/overlayscrollbars/src/overlayscrollbars/observers/TrinsicObserver.ts
@@ -36,6 +36,7 @@ export const createTrinsicObserver = (
createSizeObserver(trinsicObserver, () => {
const newSize = offsetSize(trinsicObserver);
const newHeightIntrinsic = newSize.h === 0;
+
if (newHeightIntrinsic !== heightIntrinsic) {
onTrinsicChangedCallback(false, newSize.h === 0);
heightIntrinsic = newHeightIntrinsic;
diff --git a/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.browser.ts b/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.browser.ts
index 7ac4b42..8237b89 100644
--- a/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.browser.ts
+++ b/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.browser.ts
@@ -75,7 +75,7 @@ const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any)
if (dimensions && (offsetSizeChanged || dirChanged)) {
await waitFor(
- async () => {
+ () => {
if (offsetSizeChanged) {
should.equal(sizeIterations, currSizeIterations + 1);
}
diff --git a/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.browser.ts b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.browser.ts
new file mode 100644
index 0000000..bdfbbf5
--- /dev/null
+++ b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.browser.ts
@@ -0,0 +1,141 @@
+import 'overlayscrollbars.scss';
+import './index.scss';
+import should from 'should';
+import { waitFor } from '@testing-library/dom';
+import { generateSelectCallback, iterateSelect, selectOption } from '@/testing-browser/Select';
+import { timeout } from '@/testing-browser/timeout';
+import { setTestResult } from '@/testing-browser/TestResult';
+import { offsetSize } from 'support';
+
+import { createTrinsicObserver } from 'overlayscrollbars/observers/TrinsicObserver';
+
+const waitForOptions = {
+ onTimeout(error: Error): Error {
+ setTestResult(false);
+ return error;
+ },
+};
+
+let heightIterations = 0;
+let heightIntrinsicCache: boolean;
+const envElm = document.querySelector('#env');
+const targetElm = document.querySelector('#target');
+const checkElm = document.querySelector('#check');
+const envHeightSelect: HTMLSelectElement | null = document.querySelector('#envHeight');
+const targetHeightSelect: HTMLSelectElement | null = document.querySelector('#targetHeight');
+const displaySelect: HTMLSelectElement | null = document.querySelector('#display');
+const startBtn: HTMLButtonElement | null = document.querySelector('#start');
+const changesSlot: HTMLButtonElement | null = document.querySelector('#changes');
+
+const envElmSelectCallback = generateSelectCallback(envElm as HTMLElement);
+const targetElmSelectCallback = generateSelectCallback(targetElm as HTMLElement);
+
+envHeightSelect?.addEventListener('change', envElmSelectCallback);
+targetHeightSelect?.addEventListener('change', targetElmSelectCallback);
+displaySelect?.addEventListener('change', targetElmSelectCallback);
+
+envElmSelectCallback(envHeightSelect);
+targetElmSelectCallback(targetHeightSelect);
+targetElmSelectCallback(displaySelect);
+
+const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any) => {
+ interface IterateSelect {
+ currHeightIterations: number;
+ currHeightIntrinsic: boolean;
+ }
+
+ await iterateSelect
(select, {
+ beforeEach() {
+ const currHeightIterations = heightIterations;
+ const currHeightIntrinsic = offsetSize(checkElm as HTMLElement).h === 0;
+ return {
+ currHeightIterations,
+ currHeightIntrinsic,
+ };
+ },
+ async check({ currHeightIterations, currHeightIntrinsic }) {
+ const newHeightIntrinsic = offsetSize(checkElm as HTMLElement).h === 0;
+ const trinsicHeightChanged = newHeightIntrinsic !== currHeightIntrinsic;
+
+ await waitFor(() => {
+ if (trinsicHeightChanged) {
+ should.equal(heightIterations, currHeightIterations + 1);
+ }
+ }, waitForOptions);
+ },
+ afterEach,
+ });
+};
+
+const iterateEnvHeight = async (afterEach?: () => any) => {
+ await iterate(envHeightSelect, afterEach);
+};
+const iterateTargetHeight = async (afterEach?: () => any) => {
+ await iterate(targetHeightSelect, afterEach);
+};
+const changeWhileHidden = async () => {
+ selectOption(targetHeightSelect as HTMLSelectElement, 'targetHeightHundred');
+
+ const autoToHundred = async () => {
+ selectOption(envHeightSelect as HTMLSelectElement, 'envHeightAuto');
+ selectOption(displaySelect as HTMLSelectElement, 'displayNone');
+
+ await timeout(250);
+
+ selectOption(envHeightSelect as HTMLSelectElement, 'envHeightHundred');
+ selectOption(displaySelect as HTMLSelectElement, 'displayBlock');
+
+ await waitFor(() => {
+ should.equal(heightIntrinsicCache, false);
+ }, waitForOptions);
+ };
+
+ const hundredToAuto = async () => {
+ selectOption(envHeightSelect as HTMLSelectElement, 'envHeightHundred');
+ selectOption(displaySelect as HTMLSelectElement, 'displayNone');
+
+ await timeout(250);
+
+ selectOption(envHeightSelect as HTMLSelectElement, 'envHeightAuto');
+ selectOption(displaySelect as HTMLSelectElement, 'displayBlock');
+
+ await waitFor(() => {
+ should.equal(heightIntrinsicCache, true);
+ }, waitForOptions);
+ };
+
+ await autoToHundred();
+ await hundredToAuto();
+ await autoToHundred();
+ await hundredToAuto();
+};
+
+const start = async () => {
+ setTestResult(null);
+
+ targetElm?.removeAttribute('style');
+ await iterateEnvHeight();
+ await iterateTargetHeight();
+ await iterateEnvHeight(async () => {
+ await iterateTargetHeight();
+ });
+ await changeWhileHidden();
+
+ setTestResult(true);
+};
+
+startBtn?.addEventListener('click', start);
+
+createTrinsicObserver(targetElm as HTMLElement, (widthIntrinsic: boolean, heightIntrinsic: boolean) => {
+ if (heightIntrinsic !== heightIntrinsicCache) {
+ heightIterations += 1;
+ heightIntrinsicCache = heightIntrinsic;
+ }
+ requestAnimationFrame(() => {
+ if (changesSlot) {
+ changesSlot.textContent = heightIterations.toString();
+ }
+ });
+});
+
+export { start };
diff --git a/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.html b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.html
new file mode 100644
index 0000000..e208a2d
--- /dev/null
+++ b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+ Detected changes: 0
+
+
diff --git a/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.scss b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.scss
new file mode 100644
index 0000000..5f44e4c
--- /dev/null
+++ b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.scss
@@ -0,0 +1,67 @@
+body {
+ display: flex;
+ flex-direction: column;
+}
+#controls {
+ flex: none;
+}
+#stage {
+ flex: auto;
+ position: relative;
+
+ & > div {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background: lightgoldenrodyellow;
+ }
+}
+
+#canvas > div {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+
+#env {
+ background: rgba(0, 0, 0, 0.3);
+}
+
+#target {
+ background: rgba(0, 0, 0, 0.3);
+ overflow: hidden;
+ position: relative;
+ // prevent container from reaching 0x0 dimensions for testing purposes
+ min-width: 50px;
+ min-height: 50px;
+}
+
+#check {
+ height: 100%;
+}
+
+.envHeightAuto,
+.targetHeightAuto {
+ height: auto;
+}
+
+.envHeight200,
+.targetHeight200 {
+ height: 200px;
+}
+
+.envHeightHundred,
+.targetHeightHundred {
+ height: 100%;
+}
+
+.displayNone {
+ display: none;
+}
+.displayBlock {
+ display: block;
+}
diff --git a/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.test.ts b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.test.ts
new file mode 100644
index 0000000..0d2ffb1
--- /dev/null
+++ b/packages/overlayscrollbars/tests/puppeteer/TrinsicObserver/index.test.ts
@@ -0,0 +1,15 @@
+import expectPuppeteer from 'expect-puppeteer';
+import url from './.build/build.html';
+
+describe('Environment', () => {
+ beforeAll(async () => {
+ await page.goto(url);
+ });
+
+ it('test', async () => {
+ await expectPuppeteer(page).toClick('#start');
+ await expectPuppeteer(page).toMatchElement('#testResult.passed', {
+ timeout: 60000,
+ });
+ }, 60000);
+});