Skip to content

Commit

Permalink
Create SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
marinaaisa committed Jun 17, 2024
1 parent f47301f commit 6924446
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 17 deletions.
6 changes: 3 additions & 3 deletions src/components/Filter/FilterInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
</button>
<div
:class="['filter__input-box-wrapper', { 'scrolling': isScrolling }]"
v-bind="{[SCROLL_LOCK_DISABLE_ATTR]: true}"
v-bind="{[SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR]: true}"
@scroll="handleScroll"
>
<TagList
Expand Down Expand Up @@ -129,7 +129,7 @@
import ClearRoundedIcon from 'theme/components/Icons/ClearRoundedIcon.vue';
import multipleSelection from 'docc-render/mixins/multipleSelection';
import handleScrollbar from 'docc-render/mixins/handleScrollbar';
import { SCROLL_LOCK_DISABLE_ATTR } from 'docc-render/utils/scroll-lock';
import { SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR } from 'docc-render/utils/scroll-lock';
import FilterIcon from 'theme/components/Icons/FilterIcon.vue';
import TagList from './TagList.vue';

Expand Down Expand Up @@ -227,7 +227,7 @@ export default {
SuggestedTagsId,
AXinputProperties,
showSuggestedTags: false,
SCROLL_LOCK_DISABLE_ATTR,
SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR,
};
},
computed: {
Expand Down
6 changes: 3 additions & 3 deletions src/components/Filter/TagList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
role="listbox"
:aria-multiselectable="areTagsRemovable ? 'true' : 'false'"
aria-orientation="horizontal"
v-bind="{[SCROLL_LOCK_DISABLE_ATTR]: true}"
v-bind="{[SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR]: true}"
@keydown.left.capture.prevent="focusPrev"
@keydown.right.capture.prevent="focusNext"
@keydown.up.capture.prevent="focusPrev"
Expand Down Expand Up @@ -62,7 +62,7 @@
import { isSingleCharacter } from 'docc-render/utils/input-helper';
import handleScrollbar from 'docc-render/mixins/handleScrollbar';
import keyboardNavigation from 'docc-render/mixins/keyboardNavigation';
import { SCROLL_LOCK_DISABLE_ATTR } from 'docc-render/utils/scroll-lock';
import { SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR } from 'docc-render/utils/scroll-lock';
import Tag from './Tag.vue';

export default {
Expand All @@ -73,7 +73,7 @@ export default {
],
data() {
return {
SCROLL_LOCK_DISABLE_ATTR,
SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR,
};
},
props: {
Expand Down
22 changes: 13 additions & 9 deletions src/utils/scroll-lock.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ let isLocked = false;
let initialClientY = -1;
let initialClientX = -1;
let scrolledClientY = 0;
// Adds this attribute to an inner scrollable element to allow it to scroll
// Adds this attribute to an vertical scrollable element to allow it to scroll
export const SCROLL_LOCK_DISABLE_ATTR = 'data-scroll-lock-disable';
// Adds this attribute to an horizontal scrollable element to allow it to scroll
export const SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR = 'data-scroll-lock-horizontal-disable';

const isIosDevice = () => window.navigator
&& window.navigator.platform
Expand Down Expand Up @@ -74,19 +76,17 @@ function advancedUnlock(targetElement) {
document.removeEventListener('touchmove', preventDefault);
}

const isVerticalScroll = ({ scrollHeight, scrollWidth }) => scrollHeight > scrollWidth;

/**
* Handles the scrolling of the targetElement
* @param {TouchEvent} event
* @param {HTMLElement} targetElement
* @return {boolean}
*/
function handleScroll(event, target) {
function handleScroll(event, target, isHorizontal) {
const clientY = event.targetTouches[0].clientY - initialClientY;
const clientX = event.targetTouches[0].clientX - initialClientX;

if (isVerticalScroll(target)) {
if (!isHorizontal) {
if (target.scrollTop === 0 && clientY > 0) {
// element is at the top of its scroll.
return preventDefault(event);
Expand All @@ -110,7 +110,7 @@ function handleScroll(event, target) {
* Advanced scroll locking for iOS devices.
* @param targetElement
*/
function advancedLock(targetElement) {
function advancedLock(targetElement, isHorizontal = false) {
// add a scroll listener to the body
document.addEventListener('touchmove', preventDefault, { passive: false });
if (!targetElement) return;
Expand All @@ -126,7 +126,7 @@ function advancedLock(targetElement) {
targetElement.ontouchmove = (event) => {
if (event.targetTouches.length === 1) {
// detect single touch.
handleScroll(event, targetElement);
handleScroll(event, targetElement, isHorizontal);
}
};
}
Expand All @@ -149,9 +149,12 @@ export default {
} else {
// lock everything but target element
advancedLock(targetElement);
// lock everything but disabled targets
// lock everything but disabled targets with vertical scrolling
const disabledTargets = document.querySelectorAll(`[${SCROLL_LOCK_DISABLE_ATTR}]`);
disabledTargets.forEach(target => advancedLock(target));
// lock everything but disabled targets with horizontal scrolling
const disabledHorizontalTargets = document.querySelectorAll(`[${SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR}]`);
disabledHorizontalTargets.forEach(target => advancedLock(target, true));
}
isLocked = true;
},
Expand All @@ -167,7 +170,8 @@ export default {
advancedUnlock(targetElement);
// revert the old scroll position for disabled targets
const disabledTargets = document.querySelectorAll(`[${SCROLL_LOCK_DISABLE_ATTR}]`);
disabledTargets.forEach(target => advancedUnlock(target));
const disabledHorizontalTargets = document.querySelectorAll(`[${SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR}]`);
[...disabledTargets, ...disabledHorizontalTargets].forEach(target => advancedUnlock(target));
} else {
// remove all inline styles added by the `simpleLock` function
document.body.style.removeProperty('overflow');
Expand Down
19 changes: 17 additions & 2 deletions tests/unit/utils/scroll-lock.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import scrollLock, { SCROLL_LOCK_DISABLE_ATTR } from 'docc-render/utils/scroll-lock';
import scrollLock, { SCROLL_LOCK_DISABLE_ATTR, SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR } from 'docc-render/utils/scroll-lock';
import { createEvent, parseHTMLString } from '../../../test-utils';

const { platform } = window.navigator;
Expand All @@ -32,6 +32,7 @@ describe('scroll-lock', () => {
<div class="container">
<div class="scrollable">long</div>
<div ${SCROLL_LOCK_DISABLE_ATTR}="true" class="disabled-target"></div>
<div ${SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR}="true" class="disabled-horizontal-target"></div>
</div>
`);
document.body.appendChild(DOM);
Expand Down Expand Up @@ -90,23 +91,37 @@ describe('scroll-lock', () => {

it('adds event listeners to the disabled targets too', () => {
const disabledTarget = DOM.querySelector('.disabled-target');
const disabledHorizontalTarget = DOM.querySelector('.disabled-horizontal-target');
// init the scroll lock
scrollLock.lockScroll(container);
// assert event listeners are attached
expect(disabledTarget.ontouchstart).toEqual(expect.any(Function));
expect(disabledTarget.ontouchmove).toEqual(expect.any(Function));
expect(disabledHorizontalTarget.ontouchstart).toEqual(expect.any(Function));
expect(disabledHorizontalTarget.ontouchmove).toEqual(expect.any(Function));

scrollLock.unlockScroll(container);
expect(disabledTarget.ontouchmove).toBeFalsy();
expect(disabledTarget.ontouchstart).toBeFalsy();
expect(disabledHorizontalTarget.ontouchstart).toBeFalsy();
expect(disabledHorizontalTarget.ontouchmove).toBeFalsy();
});

it('prevent event if user tries to perform vertical scroll in an horizontal scrolling element', () => {
Object.defineProperty(container, 'scrollWidth', { value: 100, writable: true });
// set horizontal scrolling element only
DOM = parseHTMLString(`
<div class="container">
<div class="scrollable">long</div>
<div ${SCROLL_LOCK_DISABLE_HORIZONTAL_ATTR}="true" class="disabled-horizontal-target"></div>
</div>
`);
document.body.appendChild(DOM);
container = DOM.querySelector('.container');

const touchStartEvent = {
targetTouches: [{ clientY: 0, clientX: 0 }],
};
// perform vertical scroll
const touchMoveEvent = {
targetTouches: [{ clientY: -10, clientX: 0 }],
preventDefault,
Expand Down

0 comments on commit 6924446

Please sign in to comment.