From a7ca731a3242e471bc60f06de862850c70c7c850 Mon Sep 17 00:00:00 2001 From: Rene Haas Date: Wed, 14 Sep 2022 09:36:11 +0200 Subject: [PATCH] add clickScrollPlguin for click scrolling support --- .../clickScrollPlugin/clickScrollPlugin.ts | 63 ++++++ .../src/plugins/clickScrollPlugin/index.ts | 1 + .../overlayscrollbars/src/plugins/index.ts | 1 + .../scrollbarsSetup/scrollbarsSetup.events.ts | 90 +++------ .../src/support/dom/animation.ts | 56 ++++++ .../src/support/dom/index.ts | 1 + .../jest-jsdom/observers/domObserver.test.ts | 2 + .../scrollbarsSetup.elements.test.ts | 1 + .../jest-jsdom/support/dom/animation.test.ts | 187 ++++++++++++++++++ .../jest-jsdom/support/utils/function.test.ts | 2 + .../tests/jest-node/treeshaking.test.js | 26 ++- .../structureSetup/update/index.browser.ts | 4 +- 12 files changed, 357 insertions(+), 77 deletions(-) create mode 100644 packages/overlayscrollbars/src/plugins/clickScrollPlugin/clickScrollPlugin.ts create mode 100644 packages/overlayscrollbars/src/plugins/clickScrollPlugin/index.ts create mode 100644 packages/overlayscrollbars/src/support/dom/animation.ts create mode 100644 packages/overlayscrollbars/tests/jest-jsdom/support/dom/animation.test.ts diff --git a/packages/overlayscrollbars/src/plugins/clickScrollPlugin/clickScrollPlugin.ts b/packages/overlayscrollbars/src/plugins/clickScrollPlugin/clickScrollPlugin.ts new file mode 100644 index 0000000..8bae03f --- /dev/null +++ b/packages/overlayscrollbars/src/plugins/clickScrollPlugin/clickScrollPlugin.ts @@ -0,0 +1,63 @@ +import { animateNumber, noop } from 'support'; +import type { Plugin } from 'plugins'; + +export type ClickScrollPluginInstance = { + _: ( + moveHandleRelative: (deltaMovement: number) => void, + getHandleOffset: (handleRect?: DOMRect, trackRect?: DOMRect) => number, + startOffset: number, + handleLength: number, + relativeTrackPointerOffset: number + ) => () => void; +}; + +export const clickScrollPluginName = '__osClickScrollPlugin'; + +export const clickScrollPlugin: Plugin = /* @__PURE__ */ (() => ({ + [clickScrollPluginName]: { + _: ( + moveHandleRelative, + getHandleOffset, + startOffset, + handleLength, + relativeTrackPointerOffset + ) => { + // click scroll animation + let iteration = 0; + let clear = noop; + const animateClickScroll = (clickScrollProgress: number) => { + clear = animateNumber( + clickScrollProgress, + clickScrollProgress + handleLength * Math.sign(startOffset), + 133, + (animationProgress, _, animationCompleted) => { + moveHandleRelative(animationProgress); + const handleStartBound = getHandleOffset(); + const handleEndBound = handleStartBound + handleLength; + const mouseBetweenHandleBounds = + relativeTrackPointerOffset >= handleStartBound && + relativeTrackPointerOffset <= handleEndBound; + + if (animationCompleted && !mouseBetweenHandleBounds) { + if (iteration) { + animateClickScroll(animationProgress); + } else { + const firstIterationPauseTimeout = setTimeout(() => { + animateClickScroll(animationProgress); + }, 222); + clear = () => { + clearTimeout(firstIterationPauseTimeout); + }; + } + iteration++; + } + } + ); + }; + + animateClickScroll(0); + + return () => clear(); + }, + }, +}))(); diff --git a/packages/overlayscrollbars/src/plugins/clickScrollPlugin/index.ts b/packages/overlayscrollbars/src/plugins/clickScrollPlugin/index.ts new file mode 100644 index 0000000..66aafb9 --- /dev/null +++ b/packages/overlayscrollbars/src/plugins/clickScrollPlugin/index.ts @@ -0,0 +1 @@ +export * from 'plugins/clickScrollPlugin/clickScrollPlugin'; diff --git a/packages/overlayscrollbars/src/plugins/index.ts b/packages/overlayscrollbars/src/plugins/index.ts index ff8bf0b..c33fd6d 100644 --- a/packages/overlayscrollbars/src/plugins/index.ts +++ b/packages/overlayscrollbars/src/plugins/index.ts @@ -2,3 +2,4 @@ export * from './plugins'; export * from './optionsValidationPlugin'; export * from './sizeObserverPlugin'; export * from './scrollbarsHidingPlugin'; +export * from './clickScrollPlugin'; diff --git a/packages/overlayscrollbars/src/setups/scrollbarsSetup/scrollbarsSetup.events.ts b/packages/overlayscrollbars/src/setups/scrollbarsSetup/scrollbarsSetup.events.ts index 9e7bdd3..666ca01 100644 --- a/packages/overlayscrollbars/src/setups/scrollbarsSetup/scrollbarsSetup.events.ts +++ b/packages/overlayscrollbars/src/setups/scrollbarsSetup/scrollbarsSetup.events.ts @@ -10,17 +10,16 @@ import { selfClearTimeout, parent, closest, - rAF, - cAF, push, - noop, } from 'support'; +import { getPlugins, clickScrollPluginName } from 'plugins'; import { getEnvironment } from 'environment'; import { classNameScrollbarHandle, classNamesScrollbarInteraction, classNamesScrollbarWheel, } from 'classnames'; +import type { ClickScrollPluginInstance } from 'plugins'; import type { ReadonlyOptions } from 'options'; import type { StructureSetupState } from 'setups'; import type { @@ -37,31 +36,7 @@ export type ScrollbarsSetupEvents = ( isHorizontal?: boolean ) => () => void; -const { round, max, sign } = Math; -const animationCurrentTime = () => performance.now(); -const animateNumber = ( - from: number, - to: number, - duration: number, - onFrame: (progress: number, completed: boolean) => any -) => { - let animationFrameId = 0; - const timeStart = animationCurrentTime(); - const frame = () => { - const timeNow = animationCurrentTime(); - const timeElapsed = timeNow - timeStart; - const stopAnimation = timeElapsed >= duration; - const percent = 1 - (max(0, timeStart + duration - timeNow) / duration || 0); - const progress = (to - from) * percent + from; - const animationCompleted = stopAnimation || percent === 1; - - onFrame(progress, animationCompleted); - - animationFrameId = animationCompleted ? 0 : rAF!(frame); - }; - frame(); - return () => cAF!(animationFrameId); -}; +const { round } = Math; const getScale = (element: HTMLElement): XY => { const { width, height } = getBoundingClientRect(element); const { w, h } = offsetSize(element); @@ -108,8 +83,7 @@ const createInteractiveScrollEvents = ( const leftTopKey = isHorizontal ? 'left' : 'top'; // for BCR (can't use xy because of IE11) const whKey = isHorizontal ? 'w' : 'h'; const xyKey = isHorizontal ? 'x' : 'y'; - const getHandleOffset = (handleRect: DOMRect, trackRect: DOMRect) => - handleRect[leftTopKey] - trackRect[leftTopKey]; + const createRelativeHandleMove = (mouseDownScroll: number, invertedScale: number) => (deltaMovement: number) => { const { _overflowAmount } = structureSetupState(); @@ -129,13 +103,17 @@ const createInteractiveScrollEvents = ( if (continuePointerDown(pointerDownEvent, options, isDragScroll)) { const instantClickScroll = !isDragScroll && pointerDownEvent.shiftKey; + const getHandleRect = () => getBoundingClientRect(_handle); + const getTrackRect = () => getBoundingClientRect(_track); + const getHandleOffset = (handleRect?: DOMRect, trackRect?: DOMRect) => + (handleRect || getHandleRect())[leftTopKey] - (trackRect || getTrackRect())[leftTopKey]; const moveHandleRelative = createRelativeHandleMove( scrollOffsetElement[scrollLeftTopKey] || 0, 1 / getScale(scrollOffsetElement)[xyKey] ); const pointerDownOffset = pointerDownEvent[clientXYKey]; - const handleRect = getBoundingClientRect(_handle); - const trackRect = getBoundingClientRect(_track); + const handleRect = getHandleRect(); + const trackRect = getTrackRect(); const handleLength = handleRect[widthHeightKey]; const handleCenter = getHandleOffset(handleRect, trackRect) + handleLength / 2; const relativeTrackPointerOffset = pointerDownOffset - trackRect[leftTopKey]; @@ -157,42 +135,22 @@ const createInteractiveScrollEvents = ( if (instantClickScroll) { moveHandleRelative(startOffset); } else if (!isDragScroll) { - // click scroll animation - let iteration = 0; - let clear = noop; - const animateClickScroll = (clickScrollProgress: number) => { - clear = animateNumber( - clickScrollProgress, - clickScrollProgress + handleLength * sign(startOffset), - 133, - (animationProgress, animationCompleted) => { - moveHandleRelative(animationProgress); - const handleStartBound = getHandleOffset(getBoundingClientRect(_handle), trackRect); - const handleEndBound = handleStartBound + handleLength; - const mouseBetweenHandleBounds = - relativeTrackPointerOffset >= handleStartBound && - relativeTrackPointerOffset <= handleEndBound; + const sizeObserverPlugin = getPlugins()[clickScrollPluginName] as + | ClickScrollPluginInstance + | undefined; - if (animationCompleted && !mouseBetweenHandleBounds) { - if (iteration) { - animateClickScroll(animationProgress); - } else { - const firstIterationPauseTimeout = setTimeout(() => { - animateClickScroll(animationProgress); - }, 222); - clear = () => { - clearTimeout(firstIterationPauseTimeout); - }; - } - iteration++; - } - } + if (sizeObserverPlugin) { + push( + offFns, + sizeObserverPlugin._( + moveHandleRelative, + getHandleOffset, + startOffset, + handleLength, + relativeTrackPointerOffset + ) ); - }; - - animateClickScroll(0); - - push(offFns, () => clear()); + } } on( diff --git a/packages/overlayscrollbars/src/support/dom/animation.ts b/packages/overlayscrollbars/src/support/dom/animation.ts new file mode 100644 index 0000000..2d2f34a --- /dev/null +++ b/packages/overlayscrollbars/src/support/dom/animation.ts @@ -0,0 +1,56 @@ +import { rAF, cAF } from 'support/compatibility'; +import { isFunction } from 'support/utils'; + +const { max } = Math; +const animationCurrentTime = () => performance.now(); + +/** + * percent: current percent (0 - 1), + * time: current time (duration * percent), + * min: start value + * max: end value + * duration: duration in ms + */ +export type EasingFn = ( + percent: number, + time: number, + min: number, + max: number, + duration: number +) => number; + +export const animateNumber = ( + from: number, + to: number, + duration: number, + onFrame: (progress: number, percent: number, completed: boolean) => any, + easing?: EasingFn | false +): ((complete?: boolean) => void) => { + let animationFrameId = 0; + const timeStart = animationCurrentTime(); + const finalDuration = Math.max(0, duration); + const frame = (complete?: boolean) => { + const timeNow = animationCurrentTime(); + const timeElapsed = timeNow - timeStart; + const stopAnimation = timeElapsed >= finalDuration; + const percent = complete + ? 1 + : 1 - (max(0, timeStart + finalDuration - timeNow) / finalDuration || 0); + const progress = + (to - from) * + (isFunction(easing) + ? easing(percent, percent * finalDuration, 0, 1, finalDuration) + : percent) + + from; + const animationCompleted = stopAnimation || percent === 1; + + onFrame && onFrame(progress, percent, animationCompleted); + + animationFrameId = animationCompleted ? 0 : rAF!(() => frame()); + }; + frame(); + return (complete) => { + cAF!(animationFrameId); + complete && frame(complete); + }; +}; diff --git a/packages/overlayscrollbars/src/support/dom/index.ts b/packages/overlayscrollbars/src/support/dom/index.ts index 1ca5c4b..b3bda9a 100644 --- a/packages/overlayscrollbars/src/support/dom/index.ts +++ b/packages/overlayscrollbars/src/support/dom/index.ts @@ -1,3 +1,4 @@ +export * from 'support/dom/animation'; export * from 'support/dom/attribute'; export * from 'support/dom/class'; export * from 'support/dom/create'; diff --git a/packages/overlayscrollbars/tests/jest-jsdom/observers/domObserver.test.ts b/packages/overlayscrollbars/tests/jest-jsdom/observers/domObserver.test.ts index 58258d2..63327b9 100644 --- a/packages/overlayscrollbars/tests/jest-jsdom/observers/domObserver.test.ts +++ b/packages/overlayscrollbars/tests/jest-jsdom/observers/domObserver.test.ts @@ -9,9 +9,11 @@ jest.mock('support/compatibility/apis', () => { ...originalModule, // @ts-ignore rAF: jest.fn().mockImplementation((...args) => mockRAF(...args)), + // @ts-ignore cAF: jest.fn().mockImplementation((...args) => clearTimeout(...args)), // @ts-ignore setT: jest.fn().mockImplementation((...args) => setTimeout(...args)), + // @ts-ignore clearT: jest.fn().mockImplementation((...args) => clearTimeout(...args)), }; }); diff --git a/packages/overlayscrollbars/tests/jest-jsdom/setups/scrollbarsSetup/scrollbarsSetup.elements.test.ts b/packages/overlayscrollbars/tests/jest-jsdom/setups/scrollbarsSetup/scrollbarsSetup.elements.test.ts index 7d160a2..74161f6 100644 --- a/packages/overlayscrollbars/tests/jest-jsdom/setups/scrollbarsSetup/scrollbarsSetup.elements.test.ts +++ b/packages/overlayscrollbars/tests/jest-jsdom/setups/scrollbarsSetup/scrollbarsSetup.elements.test.ts @@ -26,6 +26,7 @@ jest.mock('support/compatibility/apis', () => { ...originalModule, // @ts-ignore setT: jest.fn().mockImplementation((...args) => setTimeout(...args)), + // @ts-ignore clearT: jest.fn().mockImplementation((...args) => clearTimeout(...args)), }; }); diff --git a/packages/overlayscrollbars/tests/jest-jsdom/support/dom/animation.test.ts b/packages/overlayscrollbars/tests/jest-jsdom/support/dom/animation.test.ts new file mode 100644 index 0000000..8c06a12 --- /dev/null +++ b/packages/overlayscrollbars/tests/jest-jsdom/support/dom/animation.test.ts @@ -0,0 +1,187 @@ +import { animateNumber } from 'support/dom/animation'; + +jest.useFakeTimers(); + +jest.mock('support/compatibility/apis', () => { + const originalModule = jest.requireActual('support/compatibility/apis'); + const mockRAF = (arg: any) => setTimeout(arg, 0); + return { + ...originalModule, + // @ts-ignore + rAF: jest.fn().mockImplementation((...args) => mockRAF(...args)), + // @ts-ignore + cAF: jest.fn().mockImplementation((...args) => clearTimeout(...args)), + // @ts-ignore + setT: jest.fn().mockImplementation((...args) => setTimeout(...args)), + // @ts-ignore + clearT: jest.fn().mockImplementation((...args) => clearTimeout(...args)), + }; +}); + +describe('dom animation', () => { + describe('animateNumber', () => { + test('animate 0 to 1', () => { + const onFrame = jest.fn(); + expect(onFrame).not.toHaveBeenCalled(); + + animateNumber(0, 1, 500, onFrame); + + expect(onFrame).toHaveBeenCalledTimes(1); + expect(onFrame).toHaveBeenLastCalledWith(0, 0, false); + + jest.advanceTimersByTime(250); + + expect(onFrame).toHaveBeenCalledTimes(252); + expect(onFrame).toHaveBeenLastCalledWith(0.5, 0.5, false); + + jest.advanceTimersByTime(250); + + expect(onFrame).toHaveBeenCalledTimes(502); + expect(onFrame).toHaveBeenLastCalledWith(1, 1, true); + + jest.runAllTimers(); + + expect(onFrame).toHaveBeenCalledTimes(502); + }); + + test('animate 1 to 0', () => { + const onFrame = jest.fn(); + expect(onFrame).not.toHaveBeenCalled(); + + animateNumber(1, 0, 1000, onFrame); + + expect(onFrame).toHaveBeenCalledTimes(1); + expect(onFrame).toHaveBeenLastCalledWith(1, 0, false); + + jest.advanceTimersByTime(500); + + expect(onFrame).toHaveBeenCalledTimes(502); + expect(onFrame).toHaveBeenLastCalledWith(0.5, 0.5, false); + + jest.advanceTimersByTime(500); + + expect(onFrame).toHaveBeenCalledTimes(1002); + expect(onFrame).toHaveBeenLastCalledWith(0, 1, true); + + jest.runAllTimers(); + + expect(onFrame).toHaveBeenCalledTimes(1002); + }); + + test('animate duration 0', () => { + const onFrame = jest.fn(); + expect(onFrame).not.toHaveBeenCalled(); + + animateNumber(0, 100, 0, onFrame); + + expect(onFrame).toHaveBeenCalledTimes(1); + expect(onFrame).toHaveBeenLastCalledWith(100, 1, true); + + jest.runAllTimers(); + + expect(onFrame).toHaveBeenCalledTimes(1); + }); + + test('animate negative duration', () => { + const onFrame = jest.fn(); + expect(onFrame).not.toHaveBeenCalled(); + + animateNumber(0, 100, -100, onFrame); + + expect(onFrame).toHaveBeenCalledTimes(1); + expect(onFrame).toHaveBeenLastCalledWith(100, 1, true); + + jest.runAllTimers(); + + expect(onFrame).toHaveBeenCalledTimes(1); + }); + + test('animate with easing and fractions', () => { + const onFrame = jest.fn(); + const onFrameB = jest.fn(); + expect(onFrame).not.toHaveBeenCalled(); + expect(onFrameB).not.toHaveBeenCalled(); + + animateNumber(25.2, 55.5, 1000, onFrame, (percent) => percent); + animateNumber(25.2, 55.5, 1000, onFrameB); + + expect(onFrame).toHaveBeenCalledTimes(1); + expect(onFrameB).toHaveBeenCalledTimes(1); + expect(onFrame).toHaveBeenLastCalledWith(25.2, 0, false); + expect(onFrameB).toHaveBeenLastCalledWith(25.2, 0, false); + + jest.advanceTimersByTime(250); + + expect(onFrame).toHaveBeenCalledTimes(252); + expect(onFrameB).toHaveBeenCalledTimes(252); + expect(onFrame).toHaveBeenLastCalledWith(32.775, 0.25, false); + expect(onFrameB).toHaveBeenLastCalledWith(32.775, 0.25, false); + + jest.advanceTimersByTime(250); + + expect(onFrame).toHaveBeenCalledTimes(502); + expect(onFrameB).toHaveBeenCalledTimes(502); + expect(onFrame).toHaveBeenLastCalledWith(40.35, 0.5, false); + expect(onFrameB).toHaveBeenLastCalledWith(40.35, 0.5, false); + + jest.advanceTimersByTime(100); + + expect(onFrame).toHaveBeenCalledTimes(602); + expect(onFrameB).toHaveBeenCalledTimes(602); + expect(onFrame).toHaveBeenLastCalledWith(43.379999999999995, 0.6, false); + expect(onFrameB).toHaveBeenLastCalledWith(43.379999999999995, 0.6, false); + + jest.runAllTimers(); + + expect(onFrame).toHaveBeenCalledTimes(1002); + expect(onFrameB).toHaveBeenCalledTimes(1002); + expect(onFrame).toHaveBeenLastCalledWith(55.5, 1, true); + expect(onFrameB).toHaveBeenLastCalledWith(55.5, 1, true); + }); + + test('animate and stop animation', () => { + const onFrame = jest.fn(); + expect(onFrame).not.toHaveBeenCalled(); + + const stop = animateNumber(1, 0, 1000, onFrame); + + expect(onFrame).toHaveBeenCalledTimes(1); + expect(onFrame).toHaveBeenLastCalledWith(1, 0, false); + + stop(); + + expect(onFrame).toHaveBeenCalledTimes(1); + + jest.advanceTimersByTime(500); + + expect(onFrame).toHaveBeenCalledTimes(1); + + jest.runAllTimers(); + + expect(onFrame).toHaveBeenCalledTimes(1); + }); + + test('animate and stop animation with complete', () => { + const onFrame = jest.fn(); + expect(onFrame).not.toHaveBeenCalled(); + + const stop = animateNumber(0, 5555, 1000, onFrame); + + expect(onFrame).toHaveBeenCalledTimes(1); + expect(onFrame).toHaveBeenLastCalledWith(0, 0, false); + + stop(true); + + expect(onFrame).toHaveBeenCalledTimes(2); + expect(onFrame).toHaveBeenLastCalledWith(5555, 1, true); + + jest.advanceTimersByTime(500); + + expect(onFrame).toHaveBeenCalledTimes(2); + + jest.runAllTimers(); + + expect(onFrame).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/packages/overlayscrollbars/tests/jest-jsdom/support/utils/function.test.ts b/packages/overlayscrollbars/tests/jest-jsdom/support/utils/function.test.ts index 6d873e6..877ce6b 100644 --- a/packages/overlayscrollbars/tests/jest-jsdom/support/utils/function.test.ts +++ b/packages/overlayscrollbars/tests/jest-jsdom/support/utils/function.test.ts @@ -10,9 +10,11 @@ jest.mock('support/compatibility/apis', () => { ...originalModule, // @ts-ignore rAF: jest.fn().mockImplementation((...args) => mockRAF(...args)), + // @ts-ignore cAF: jest.fn().mockImplementation((...args) => clearTimeout(...args)), // @ts-ignore setT: jest.fn().mockImplementation((...args) => setTimeout(...args)), + // @ts-ignore clearT: jest.fn().mockImplementation((...args) => clearTimeout(...args)), }; }); diff --git a/packages/overlayscrollbars/tests/jest-node/treeshaking.test.js b/packages/overlayscrollbars/tests/jest-node/treeshaking.test.js index dd315a0..f3c0b26 100644 --- a/packages/overlayscrollbars/tests/jest-node/treeshaking.test.js +++ b/packages/overlayscrollbars/tests/jest-node/treeshaking.test.js @@ -17,8 +17,8 @@ const normalizePath = (pathName) => const fixturesDir = path.join(__dirname, '.fixtures'); const libraryFixturePath = normalizePath(path.join(fixturesDir, 'lib.js')); -const unshakedFixturePath = normalizePath(path.join(fixturesDir, 'unshaked.js')); -const shakedFixturePath = normalizePath(path.join(fixturesDir, 'shaked.js')); +const normalFixturePath = normalizePath(path.join(fixturesDir, 'nromal.js')); +const treeshakedFixturePath = normalizePath(path.join(fixturesDir, 'treeshaked.js')); const unshakedFixtureContent = ` export * as os from '${libraryFixturePath}'; @@ -89,18 +89,24 @@ const bundleFunctions = { const testBundler = (bundlerName) => async () => { const bundleFunction = bundleFunctions[bundlerName]; const outputDir = path.join(__dirname, `.${bundlerName}`); - const unshaked = await bundleFunction(unshakedFixturePath, path.join(outputDir, 'unshaked.js')); - const shaked = await bundleFunction(shakedFixturePath, path.join(outputDir, 'shaked.js')); + const normal = await bundleFunction( + normalFixturePath, + path.join(outputDir, path.basename(normalFixturePath)) + ); + const treeshaked = await bundleFunction( + treeshakedFixturePath, + path.join(outputDir, path.basename(treeshakedFixturePath)) + ); cleanBundle && fs.rmSync(outputDir, { recursive: true }); console.info(`${bundlerName} size`, { - unshaked, - shaked, - diff: unshaked - shaked, + normal, + treeshaked, + diff: normal - treeshaked, }); - expect(unshaked - shaked).toBeGreaterThan(expectedBundleDiff); + expect(normal - treeshaked).toBeGreaterThan(expectedBundleDiff); }; describe('tree shaking', () => { @@ -131,8 +137,8 @@ describe('tree shaking', () => { fs.mkdirSync(fixturesDir); } - fs.writeFileSync(unshakedFixturePath, unshakedFixtureContent); - fs.writeFileSync(shakedFixturePath, shakedFixtureContent); + fs.writeFileSync(normalFixturePath, unshakedFixtureContent); + fs.writeFileSync(treeshakedFixturePath, shakedFixtureContent); }, 60000 * 2); // clean the fixture diff --git a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts index de504d9..e8cd394 100644 --- a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts +++ b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts @@ -32,7 +32,9 @@ import { } from 'support'; import { Options } from 'options'; import { DeepPartial } from 'typings'; -import { addPlugin, scrollbarsHidingPlugin, sizeObserverPlugin } from 'plugins'; +import { addPlugin, scrollbarsHidingPlugin, sizeObserverPlugin, clickScrollPlugin } from 'plugins'; + +addPlugin(clickScrollPlugin); if (!window.ResizeObserver) { addPlugin(sizeObserverPlugin);