implement scroll restoration and scroll focus

This commit is contained in:
Rene Haas
2022-08-03 11:38:46 +02:00
parent ea76610bab
commit fa989cabb7
4 changed files with 31 additions and 4 deletions
@@ -20,6 +20,7 @@ import {
attrClass, attrClass,
hasAttrClass, hasAttrClass,
noop, noop,
on,
} from 'support'; } from 'support';
import { import {
dataAttributeHost, dataAttributeHost,
@@ -73,6 +74,7 @@ export interface StructureSetupElementsObj {
_viewportAddRemoveClass: (className: string, attributeClassName: string, add?: boolean) => void; _viewportAddRemoveClass: (className: string, attributeClassName: string, add?: boolean) => void;
} }
const tabIndexStr = 'tabindex';
const createNewDiv = createDiv.bind(0, ''); const createNewDiv = createDiv.bind(0, '');
const unwrap = (elm: HTMLElement | false | null | undefined) => { const unwrap = (elm: HTMLElement | false | null | undefined) => {
@@ -130,6 +132,8 @@ export const createStructureSetupElements = (
); );
const viewportIsTarget = viewportElement === targetElement; const viewportIsTarget = viewportElement === targetElement;
const viewportIsTargetBody = viewportIsTarget && isBody; const viewportIsTargetBody = viewportIsTarget && isBody;
const setFocus =
!viewportIsTarget && wnd.top === wnd && ownerDocument.activeElement === targetElement;
const evaluatedTargetObj: StructureSetupElementsObj = { const evaluatedTargetObj: StructureSetupElementsObj = {
_target: targetElement, _target: targetElement,
_host: isTextarea _host: isTextarea
@@ -240,6 +244,17 @@ export const createStructureSetupElements = (
insertBefore(_viewport, _viewportArrange); insertBefore(_viewport, _viewportArrange);
push(destroyFns, removeElements.bind(0, _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 // @ts-ignore
targetContents = 0; targetContents = 0;
@@ -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 { createState, createOptionCheck } from 'setups/setups';
import { createStructureSetupElements } from 'setups/structureSetup/structureSetup.elements'; import { createStructureSetupElements } from 'setups/structureSetup/structureSetup.elements';
import { createStructureSetupUpdate } from 'setups/structureSetup/structureSetup.update'; import { createStructureSetupUpdate } from 'setups/structureSetup/structureSetup.update';
@@ -97,8 +97,15 @@ export const createStructureSetup = (
addEvent('u', listener); addEvent('u', listener);
}; };
structureSetupState._appendElements = () => { structureSetupState._appendElements = () => {
const { _target, _viewport } = elements;
const initialScrollLeft = scrollLeft(_target);
const initialScrollTop = scrollTop(_target);
appendObserverElements(); appendObserverElements();
appendStructureElements(); appendStructureElements();
scrollLeft(_viewport, initialScrollLeft);
scrollTop(_viewport, initialScrollTop);
}; };
structureSetupState._elements = elements; structureSetupState._elements = elements;
@@ -57,7 +57,7 @@ export const createStructureSetupUpdate = (
structureSetupElements: StructureSetupElementsObj, structureSetupElements: StructureSetupElementsObj,
state: SetupState<StructureSetupState> state: SetupState<StructureSetupState>
): StructureSetupUpdate => { ): StructureSetupUpdate => {
const { _viewport, _viewportAddRemoveClass } = structureSetupElements; const { _target, _viewport, _viewportAddRemoveClass, _viewportIsTarget } = structureSetupElements;
const { _nativeScrollbarsHiding, _nativeScrollbarsOverlaid, _flexboxGlue } = getEnvironment(); const { _nativeScrollbarsHiding, _nativeScrollbarsOverlaid, _flexboxGlue } = getEnvironment();
const doViewportArrange = const doViewportArrange =
!_nativeScrollbarsHiding && (_nativeScrollbarsOverlaid.x || _nativeScrollbarsOverlaid.y); !_nativeScrollbarsHiding && (_nativeScrollbarsOverlaid.x || _nativeScrollbarsOverlaid.y);
@@ -109,6 +109,11 @@ export const createStructureSetupUpdate = (
scrollTop(_viewport, scrollOffsetY); scrollTop(_viewport, scrollOffsetY);
_viewportAddRemoveClass('', dataValueHostUpdating); _viewportAddRemoveClass('', dataValueHostUpdating);
if (!_viewportIsTarget) {
scrollLeft(_target, 0);
scrollTop(_target, 0);
}
return adaptivedUpdateHints; return adaptivedUpdateHints;
}; };
}; };
@@ -1,5 +1,5 @@
import { from } from 'support/utils/array'; 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'; type GetSetPropName = 'scrollLeft' | 'scrollTop' | 'value';
@@ -27,7 +27,7 @@ const getSetProp = (
if (isUndefined(value)) { if (isUndefined(value)) {
return elm ? elm[topLeft] : fallback; return elm ? elm[topLeft] : fallback;
} }
elm && !isNull(value) && value !== false && (elm[topLeft] = value); elm && (isString(value) || isNumber(value)) && (elm[topLeft] = value);
}; };
/** /**