Skip to content

Commit

Permalink
revert: Revert "feat: Add scroll snapping to responsive tabs (#2899)" (
Browse files Browse the repository at this point in the history
  • Loading branch information
jperals authored Nov 20, 2024
1 parent 6313be9 commit 22af933
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 8 deletions.
1 change: 0 additions & 1 deletion src/tabs/__integ__/tabs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ test(
await page.setWindowSize({ width: 500, height: 1000 });
await page.click('#add-tab');
await page.click(page.paginationButton('right', true));
await page.click(page.paginationButton('right', true));
await page.click(wrapper.findTabLinkByIndex(7).toSelector());
await page.waitForAssertion(async () =>
expect(await page.isExisting(page.paginationButton('right', true))).toBe(false)
Expand Down
30 changes: 30 additions & 0 deletions src/tabs/__tests__/smooth-scroll.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import { render } from '@testing-library/react';
import { waitFor } from '@testing-library/react';

import { isMotionDisabled } from '@cloudscape-design/component-toolkit/internal';

import nativeSupport from '../../../lib/components/tabs/native-smooth-scroll-supported';
import smoothScroll from '../../../lib/components/tabs/smooth-scroll';
import createWrapper from '../../../lib/components/test-utils/dom';

jest.mock('../../../lib/components/tabs/native-smooth-scroll-supported', () => {
return jest.fn();
});
jest.mock('@cloudscape-design/component-toolkit/internal', () => ({
...jest.requireActual('@cloudscape-design/component-toolkit/internal'),
isMotionDisabled: jest.fn(),
Expand All @@ -26,17 +31,42 @@ function renderScrollableElement(): HTMLElement {
return createWrapper(renderResult.container).findByClassName('scrollable')!.getElement();
}

async function usesCustomScrollingFunction(element: HTMLElement, scrollLeft: number) {
expect(nativeScrollMock).not.toHaveBeenCalled();
await waitFor(() => {
expect(element.scrollLeft).toEqual(scrollLeft);
});
}

beforeEach(() => {
(nativeSupport as jest.Mock).mockReturnValue(false);
(isMotionDisabled as jest.Mock).mockReturnValue(false);
nativeScrollMock.mockClear();
});

describe('Smooth scroll', () => {
test('uses native scrollTo function if the browser supports it', () => {
(nativeSupport as jest.Mock).mockReturnValue(true);
const element = renderScrollableElement();
smoothScroll(element, 100);
expect(nativeScrollMock).toHaveBeenCalled();
});
test('relies on custom function when browsers do not support it', async () => {
const element = renderScrollableElement();
smoothScroll(element, 100);
await usesCustomScrollingFunction(element, 100);
});
test('does not animate when motion is disabled', () => {
(isMotionDisabled as jest.Mock).mockReturnValue(true);
const element = renderScrollableElement();
smoothScroll(element, 100);
expect(nativeScrollMock).not.toHaveBeenCalled();
expect(element.scrollLeft).toEqual(100);
});
test('animates left with custom function', async () => {
const element = renderScrollableElement();
element.scrollLeft = 500;
smoothScroll(element, 100);
await usesCustomScrollingFunction(element, 100);
});
});
7 changes: 7 additions & 0 deletions src/tabs/native-smooth-scroll-supported.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// This function is in a separate file to allow for mocking in unit tests
export default function () {
return 'scrollBehavior' in document.documentElement.style;
}
52 changes: 49 additions & 3 deletions src/tabs/smooth-scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,62 @@
// SPDX-License-Identifier: Apache-2.0
import { isMotionDisabled } from '@cloudscape-design/component-toolkit/internal';

import isNativeSmoothScrollingSupported from './native-smooth-scroll-supported';

interface ScrollContext {
scrollable: HTMLElement;
startX: number;
endX: number;
startTime: number;
scrollTime: number;
}

// The scroll speed depends on the scrolling distance. The equation below is an interpolation of measurements in Chrome.
const getScrollSpeed = (pixels: number) => 0.0015 * Math.abs(pixels) + 0.558;
const getScrollTime = (pixels: number) => Math.round(Math.abs(pixels) / getScrollSpeed(pixels));

const now = () => (window.performance ? window.performance.now() : Date.now());

const ease = (k: number): number => {
return 0.5 * (1 - Math.cos(Math.PI * k));
};

const step = (context: ScrollContext): void => {
const time = now();
const elapsed = Math.min((time - context.startTime) / context.scrollTime, 1);
const value = ease(elapsed);
const currentX = context.startX + (context.endX - context.startX) * value;
context.scrollable.scrollLeft = currentX;
// scroll more if we have not reached our destination
if (currentX !== context.endX) {
requestAnimationFrame(() => step(context));
}
};

const simulateSmoothScroll = (element: HTMLElement, endX: number): void => {
const startX = element.scrollLeft;
step({
scrollable: element,
startX,
endX,
startTime: now(),
scrollTime: getScrollTime(endX - startX),
});
};

const smoothScroll = (element: HTMLElement, to: number) => {
if (isMotionDisabled(element) || !element.scrollTo) {
if (isMotionDisabled(element)) {
element.scrollLeft = to;
} else {
// istanbul ignore next: unit tests always have motion disabled
return;
}
if (isNativeSmoothScrollingSupported() && element.scrollTo) {
element.scrollTo({
left: to,
behavior: 'smooth',
});
return;
}
simulateSmoothScroll(element, to);
};

export default smoothScroll;
4 changes: 0 additions & 4 deletions src/tabs/tab-header-bar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ $label-horizontal-spacing: awsui.$space-xs;
overflow-y: hidden;
position: relative;
inline-size: 100%;
scroll-snap-type: inline proximity;
// do not use pointer-events none because it disables scroll by sliding

// Hide scrollbar in all browsers
Expand Down Expand Up @@ -75,7 +74,6 @@ $label-horizontal-spacing: awsui.$space-xs;
flex-shrink: 0;
display: flex;
max-inline-size: calc(90% - awsui.$space-l);
scroll-snap-align: start;
}

.tabs-tab-label {
Expand Down Expand Up @@ -207,7 +205,6 @@ $label-horizontal-spacing: awsui.$space-xs;
// Remediate focus shadow
.tabs-tab:first-child {
margin-inline-start: 1px;
scroll-margin-inline-start: 1px;
& > .tabs-tab-header-container {
padding-inline-start: calc(#{$label-horizontal-spacing} - 1px);
}
Expand All @@ -216,7 +213,6 @@ $label-horizontal-spacing: awsui.$space-xs;
// Remediate focus shadow
.tabs-tab:last-child {
margin-inline-end: 1px;
scroll-margin-inline-end: 1px;
& > .tabs-tab-header-container {
padding-inline-end: calc(#{$label-horizontal-spacing} - 1px);
}
Expand Down

0 comments on commit 22af933

Please sign in to comment.