From fa989cabb7c17a921ab07182f7894cf9ddb3e47f Mon Sep 17 00:00:00 2001 From: Rene Haas Date: Wed, 3 Aug 2022 11:38:46 +0200 Subject: [PATCH] implement scroll restoration and scroll focus --- .../structureSetup/structureSetup.elements.ts | 15 +++++++++++++++ .../src/setups/structureSetup/structureSetup.ts | 9 ++++++++- .../structureSetup/structureSetup.update.ts | 7 ++++++- .../src/support/dom/attribute.ts | 4 ++-- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.elements.ts b/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.elements.ts index 43c754d..1b216ac 100644 --- a/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.elements.ts +++ b/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.elements.ts @@ -20,6 +20,7 @@ import { attrClass, hasAttrClass, noop, + on, } from 'support'; import { dataAttributeHost, @@ -73,6 +74,7 @@ export interface StructureSetupElementsObj { _viewportAddRemoveClass: (className: string, attributeClassName: string, add?: boolean) => void; } +const tabIndexStr = 'tabindex'; const createNewDiv = createDiv.bind(0, ''); const unwrap = (elm: HTMLElement | false | null | undefined) => { @@ -130,6 +132,8 @@ export const createStructureSetupElements = ( ); const viewportIsTarget = viewportElement === targetElement; const viewportIsTargetBody = viewportIsTarget && isBody; + const setFocus = + !viewportIsTarget && wnd.top === wnd && ownerDocument.activeElement === targetElement; const evaluatedTargetObj: StructureSetupElementsObj = { _target: targetElement, _host: isTextarea @@ -240,6 +244,17 @@ export const createStructureSetupElements = ( insertBefore(_viewport, _viewportArrange); push(destroyFns, removeElements.bind(0, _viewportArrange)); } + if (setFocus) { + const ogTabindex = attr(_viewport, tabIndexStr); + + attr(_viewport, tabIndexStr, '-1'); + _viewport.focus(); + + const off = on(ownerDocument, 'pointerdown keydown', () => { + ogTabindex ? attr(_viewport, tabIndexStr, ogTabindex) : removeAttr(_viewport, tabIndexStr); + off(); + }); + } // @ts-ignore targetContents = 0; diff --git a/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.ts b/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.ts index ecae24c..297e006 100644 --- a/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.ts +++ b/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.ts @@ -1,4 +1,4 @@ -import { createEventListenerHub, isEmptyObject, keys } from 'support'; +import { createEventListenerHub, isEmptyObject, keys, scrollLeft, scrollTop } from 'support'; import { createState, createOptionCheck } from 'setups/setups'; import { createStructureSetupElements } from 'setups/structureSetup/structureSetup.elements'; import { createStructureSetupUpdate } from 'setups/structureSetup/structureSetup.update'; @@ -97,8 +97,15 @@ export const createStructureSetup = ( addEvent('u', listener); }; structureSetupState._appendElements = () => { + const { _target, _viewport } = elements; + const initialScrollLeft = scrollLeft(_target); + const initialScrollTop = scrollTop(_target); + appendObserverElements(); appendStructureElements(); + + scrollLeft(_viewport, initialScrollLeft); + scrollTop(_viewport, initialScrollTop); }; structureSetupState._elements = elements; diff --git a/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.update.ts b/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.update.ts index f67d5a1..6ed79bc 100644 --- a/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.update.ts +++ b/packages/overlayscrollbars/src/setups/structureSetup/structureSetup.update.ts @@ -57,7 +57,7 @@ export const createStructureSetupUpdate = ( structureSetupElements: StructureSetupElementsObj, state: SetupState ): StructureSetupUpdate => { - const { _viewport, _viewportAddRemoveClass } = structureSetupElements; + const { _target, _viewport, _viewportAddRemoveClass, _viewportIsTarget } = structureSetupElements; const { _nativeScrollbarsHiding, _nativeScrollbarsOverlaid, _flexboxGlue } = getEnvironment(); const doViewportArrange = !_nativeScrollbarsHiding && (_nativeScrollbarsOverlaid.x || _nativeScrollbarsOverlaid.y); @@ -109,6 +109,11 @@ export const createStructureSetupUpdate = ( scrollTop(_viewport, scrollOffsetY); _viewportAddRemoveClass('', dataValueHostUpdating); + if (!_viewportIsTarget) { + scrollLeft(_target, 0); + scrollTop(_target, 0); + } + return adaptivedUpdateHints; }; }; diff --git a/packages/overlayscrollbars/src/support/dom/attribute.ts b/packages/overlayscrollbars/src/support/dom/attribute.ts index 0b25ebd..4dc80e6 100644 --- a/packages/overlayscrollbars/src/support/dom/attribute.ts +++ b/packages/overlayscrollbars/src/support/dom/attribute.ts @@ -1,5 +1,5 @@ import { from } from 'support/utils/array'; -import { isNull, isUndefined } from 'support/utils/types'; +import { isNumber, isString, isUndefined } from 'support/utils/types'; type GetSetPropName = 'scrollLeft' | 'scrollTop' | 'value'; @@ -27,7 +27,7 @@ const getSetProp = ( if (isUndefined(value)) { return elm ? elm[topLeft] : fallback; } - elm && !isNull(value) && value !== false && (elm[topLeft] = value); + elm && (isString(value) || isNumber(value)) && (elm[topLeft] = value); }; /**