Skip to content

Commit 3b13693

Browse files
authored
fix: Ensure scroll position is on the file input button when focused (#3847)
1 parent ce69f00 commit 3b13693

File tree

4 files changed

+96
-6
lines changed

4 files changed

+96
-6
lines changed

pages/file-input/integ.page.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import React, { useState } from 'react';
4+
5+
import { Box, FileInput, FileInputProps } from '~components';
6+
7+
import ScreenshotArea from '../utils/screenshot-area';
8+
9+
export default function DateInputScenario() {
10+
const [files, setFiles] = useState<File[]>([]);
11+
12+
const ref = React.useRef<FileInputProps.Ref>(null);
13+
14+
return (
15+
<ScreenshotArea>
16+
<Box padding="l">
17+
<h1>File input</h1>
18+
<button id="focus-before">Click here</button>
19+
<div style={{ paddingBlock: 2000 }}>
20+
<FileInput ref={ref} multiple={true} value={files} onChange={event => setFiles(event.detail.value)}>
21+
Choose files
22+
</FileInput>
23+
<button id="focus-after">Click here</button>
24+
25+
{files.map((file, index) => (
26+
<div key={index}>{file.name}</div>
27+
))}
28+
</div>
29+
</Box>
30+
</ScreenshotArea>
31+
);
32+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { BasePageObject } from '@cloudscape-design/browser-test-tools/page-objects';
4+
import useBrowser from '@cloudscape-design/browser-test-tools/use-browser';
5+
6+
import createWrapper from '../../../lib/components/test-utils/selectors';
7+
8+
const wrapper = createWrapper();
9+
const fileInputWrapper = wrapper.findFileInput();
10+
11+
const setupTest = (testFn: (page: BasePageObject) => Promise<void>) => {
12+
return useBrowser(async browser => {
13+
const page = new BasePageObject(browser);
14+
await browser.url('#/light/file-input/integ');
15+
await page.waitForVisible(fileInputWrapper.toSelector());
16+
await testFn(page);
17+
});
18+
};
19+
20+
describe('FileInput', () => {
21+
test(
22+
'visible in viewport when input is focused',
23+
setupTest(async page => {
24+
await page.click('#focus-before');
25+
await page.keys(['Tab']);
26+
27+
// Check that the file input is still in the viewport
28+
await expect(page.isDisplayedInViewport(fileInputWrapper.findTrigger().toSelector())).resolves.toBe(true);
29+
})
30+
);
31+
32+
test(
33+
'does not scroll the page if the button is already visible',
34+
setupTest(async page => {
35+
await page.click('#focus-before');
36+
await page.keys(['Tab']);
37+
const beforeScrollPosition = await page.getWindowScroll();
38+
39+
await page.click('#focus-after');
40+
await page.keys(['Shift', 'Tab']);
41+
const afterScrollPosition = await page.getWindowScroll();
42+
43+
// Check that the positions are the same
44+
expect(beforeScrollPosition).toStrictEqual(afterScrollPosition);
45+
})
46+
);
47+
});

src/file-input/internal.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ const InternalFileInput = React.forwardRef(
6666
const onUploadButtonClick = () => uploadInputRef.current?.click();
6767
const onUploadInputFocus = () => {
6868
setIsFocused(true);
69-
containerRef.current?.scrollIntoView?.();
7069
};
7170
const onUploadInputBlur = () => setIsFocused(false);
7271

src/file-input/styles.scss

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,25 @@
66
@use '../internal/styles' as styles;
77
@use '@cloudscape-design/component-toolkit/internal/focus-visible' as focus-visible;
88

9-
.root,
10-
.file-input {
11-
/* used in test-utils */
9+
.root {
10+
position: relative;
1211
}
1312

14-
.hidden {
15-
@include styles.awsui-util-hide;
13+
.file-input {
14+
// Adapted from https://webaim.org/techniques/css/invisiblecontent/
15+
16+
position: absolute;
17+
inset-block-start: 0;
18+
inset-inline-start: 0;
19+
clip: rect(1px, 1px, 1px, 1px);
20+
clip-path: inset(50%);
21+
block-size: 1px;
22+
inline-size: 1px;
23+
margin-block: -1px;
24+
margin-inline: -1px;
25+
padding-block: 0;
26+
padding-inline: 0;
27+
overflow: hidden;
1628
}
1729

1830
.file-input-button {

0 commit comments

Comments
 (0)