Skip to content

Commit

Permalink
fix(Tearsheet): resolve focus issue (carbon-design-system#6217)
Browse files Browse the repository at this point in the history
* fix(Tearsheet): resolve focus issue 6164

* fix(TearsheetShell): remove allements from dependencies

* fix(TearsheetShell): update useEffect dependencies

* test(createTearsheet): wrap click in act

* test(CreateTearsheet): implement avt test for focus
  • Loading branch information
makafsal authored Oct 18, 2024
1 parent 42ccd9f commit dc53a09
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 8 deletions.
103 changes: 103 additions & 0 deletions e2e/components/CreateFlows/CreateTearsheet-test.avt.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,107 @@ test.describe('CreateTearsheet @avt', () => {
'CreateTearsheet @avt-default-state'
);
});

test('@avt-focus-move-properly-across-steps', async ({ page }) => {
await visitStory(page, {
component: 'CreateTearsheet',
id: 'ibm-products-patterns-create-flows-createtearsheet--multi-step-tearsheet',
globals: {
carbonTheme: 'white',
},
});

const modalElement = page.locator(`.${carbon.prefix}--modal.is-visible`);
// Pressing 'Tab' key to focus on the "Open CreateTearsheet" button in the Storybook
await page.keyboard.press('Tab');
// Pressing 'Enter' key to open the Tearsheet
await page.keyboard.press('Enter');

await expect(modalElement).toBeVisible();
await modalElement.evaluate((element) =>
Promise.all(
element.getAnimations().map((animation) => animation.finished)
)
);

const learnMoreAnchor = page.getByText('Learn more.');
const step1Input1 = page.locator(
'#tearsheet-multi-step-story-text-input-multi-step-1'
);
const nextButton = page.getByText('Next');
const backButton = page.getByText('Back');
// Expect the Learn More link to be focused
await expect(learnMoreAnchor).toBeFocused();

// Switch focus to input box
await page.keyboard.press('Tab');
// Expect the input box to be focused
await expect(step1Input1).toBeFocused();

// Type some text in the input field
await page.keyboard.type('H');
// Expect the Next button to be enabled at this moment
await expect(nextButton).toBeEnabled();

// Switch focus to next button
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');

// Expect next button to be focused
await expect(nextButton).toBeFocused();

// Goto next step by pressing enter
await page.keyboard.press('Enter');

const step2Input1 = page.locator('#custom-step-input');
// Expect the Step 2 input field is focused
await expect(step2Input1).toBeFocused();
// Also confirm the Next button disabled in this step
await expect(nextButton).toBeDisabled();

// Type some text in the input field
await page.keyboard.type('L');
// Expect Next button enabled now
await expect(nextButton).toBeEnabled();

// Switch focus to next button
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');

// Goto next step by pressing enter
await page.keyboard.press('Enter');

const step3Input1 = page.locator('#carbon-number');
// Expect the first input element to be focuses
await expect(step3Input1).toBeFocused();

// Switch focus to next button
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');

// Goto previous step by pressing enter
await expect(backButton).toBeFocused();
await page.keyboard.press('Enter');

// Expect the first element in the previous step to be focused
await expect(step2Input1).toBeFocused();

// Switch focus to next button
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');

// Goto previous step by pressing enter
await expect(backButton).toBeFocused();
await page.keyboard.press('Enter');

// Expect the previous page first element to be focused
await expect(learnMoreAnchor).toBeFocused();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ describe(CreateTearsheet.displayName, () => {
const createTearsheetSteps = tearsheetElement.querySelector(
`.${createTearsheetBlockClass}__content .${carbon.prefix}--form`
).children;
click(nextButtonElement);
act(() => {
/* fire events that update state */
click(nextButtonElement);
});
expect(
createTearsheetSteps[1].classList.contains(
`.${createTearsheetBlockClass}__step__step--visible-section`
Expand Down
26 changes: 19 additions & 7 deletions packages/ibm-products/src/components/Tearsheet/TearsheetShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -338,15 +338,27 @@ export const TearsheetShell = React.forwardRef(
useEffect(() => {
if (open) {
// Focusing the first element or selectorPrimaryFocus element
setTimeout(() => {
if (selectorPrimaryFocus) {
return specifiedElement?.focus();
if (
selectorPrimaryFocus &&
getSpecificElement(modalRef?.current, selectorPrimaryFocus)
) {
const specifiedEl = getSpecificElement(
modalRef?.current,
selectorPrimaryFocus
);

if (
specifiedEl &&
window?.getComputedStyle(specifiedEl)?.display !== 'none'
) {
setTimeout(() => specifiedEl.focus(), 0);
return;
}
firstElement?.focus();
}, 0);
}

setTimeout(() => firstElement?.focus(), 0);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open]);
}, [firstElement, modalRef, open, selectorPrimaryFocus]);

useEffect(() => {
if (prevOpen && !open && launcherButtonRef) {
Expand Down

0 comments on commit dc53a09

Please sign in to comment.