Skip to content

Commit

Permalink
fix(dropdown): Dropdowns without DropdownMenuItem will get focused on…
Browse files Browse the repository at this point in the history
… open (#1099)
  • Loading branch information
silvalaura authored Jun 29, 2023
1 parent 4f45985 commit 1c91ac3
Show file tree
Hide file tree
Showing 8 changed files with 421 additions and 68 deletions.
6 changes: 6 additions & 0 deletions .changeset/dropdown-noitems.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'react-magma-dom': patch
---

fix(dropdown): Dropdowns without `DropdownMenuItem` will get focused on open.
Fixes issue where these dropdowns could not be closed on Escape in Safari, and should be readable by screenreaders.
82 changes: 82 additions & 0 deletions .github/workflows/publish-next-patch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Publish Next Patch
on:
push:
branches:
- dev-patch
jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup
uses: actions/setup-node@v2
with:
node-version: '14'
check-latest: true
- name: Check Node version
run: node -v
- name: Update NPM version
run: npm install -g "npm@^7.6.3"
- name: Install
run: npm ci
- name: Test
run: npm test
- name: Coverage
uses: codecov/codecov-action@v1
- name: Configure NPM
run: |
git config --global user.name 'github-bot'
git config --global user.email '[email protected]'
echo //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} > .npmrc
- name: Check if Prerelease
id: check_files
uses: andstor/file-existence-action@v1
with:
files: ".changeset/pre.json"
- name: Enter Prerelease Mode
if: steps.check_files.outputs.files_exists == 'false'
run: |
npm run version:prerelease
git add .changeset/pre.json
- name: Publish
run: |
npm run version:pkgs
git commit -am "chore: enter prerelease mode"
npm run release
git push --follow-tags
- name: Get Alias
id: info
run: |
echo "::set-output name=alias::$(npm run --silent getAlias)"
echo "::set-output name=version::$(npm run --silent getVersion)"
- name: Build Docs
run: npm run build:docs
- name: Build Storybook
run: npm run build:storybook
- name: Deploy Docs to Netlify
uses: nwtgck/[email protected]
with:
publish-dir: './website/react-magma-docs/public'
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: 'Deploy from GitHub Actions'
enable-pull-request-comment: true
enable-commit-comment: true
overwrites-pull-request-comment: true
alias: next-patch
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
- name: Deploy Dev Storybook to Netlify
uses: nwtgck/[email protected]
with:
publish-dir: './storybook-static'
production-branch: patch-3.x.x
github-token: ${{ secrets.GITHUB_TOKEN }}
enable-pull-request-comment: true
enable-commit-comment: true
overwrites-pull-request-comment: false
alias: storybook-preview-dev-patch
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,11 @@ exports[`ButtonGroup With dropdowns Snapshot: Horizontal & center alignment 1`]
transition: opacity 0.3s;
white-space: nowrap;
z-index: 2;
outline-offset: 0;
}
.emotion-11:focus {
outline: 2px solid #0074B7;
}
.emotion-10 {
Expand Down Expand Up @@ -1472,6 +1477,11 @@ exports[`ButtonGroup With dropdowns Snapshot: Horizontal & center alignment 1`]
transition: opacity 0.3s;
white-space: nowrap;
z-index: 2;
outline-offset: 0;
}
.emotion-11:focus {
outline: 2px solid #0074B7;
}
.emotion-10 {
Expand Down Expand Up @@ -1955,6 +1965,11 @@ exports[`ButtonGroup With dropdowns Snapshot: Vertical & fill alignment 1`] = `
transition: opacity 0.3s;
white-space: nowrap;
z-index: 2;
outline-offset: 0;
}
.emotion-11:focus {
outline: 2px solid #0074B7;
}
.emotion-10 {
Expand Down Expand Up @@ -2301,6 +2316,11 @@ exports[`ButtonGroup With dropdowns Snapshot: Vertical & fill alignment 1`] = `
transition: opacity 0.3s;
white-space: nowrap;
z-index: 2;
outline-offset: 0;
}
.emotion-11:focus {
outline: 2px solid #0074B7;
}
.emotion-10 {
Expand Down Expand Up @@ -2823,6 +2843,11 @@ exports[`ButtonGroup With dropdowns Snapshot: noSpace 1`] = `
transition: opacity 0.3s;
white-space: nowrap;
z-index: 2;
outline-offset: 0;
}
.emotion-11:focus {
outline: 2px solid #0074B7;
}
.emotion-10 {
Expand Down Expand Up @@ -3208,6 +3233,11 @@ exports[`ButtonGroup With dropdowns Snapshot: noSpace 1`] = `
transition: opacity 0.3s;
white-space: nowrap;
z-index: 2;
outline-offset: 0;
}
.emotion-11:focus {
outline: 2px solid #0074B7;
}
.emotion-10 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { Checkbox } from '../Checkbox';
import { PasswordInput } from '../PasswordInput';
import { SettingsIcon, MenuIcon } from 'react-magma-icons';
import { Story, Meta } from '@storybook/react/types-6-0';
import { Paragraph, Spacer } from '../..';
import { ButtonGroup } from '../ButtonGroup';

const Template: Story<DropdownProps> = args => (
<div style={{ margin: '150px auto', textAlign: 'center' }}>
Expand Down Expand Up @@ -349,3 +351,59 @@ Inverse.decorators = [
</Card>
),
];

export const NoItems = args => {
return (
<ButtonGroup>
<Dropdown width="500px" {...args} testId="dropdown">
<DropdownButton>Dropdown without items</DropdownButton>
<DropdownContent style={{ padding: '12px' }}>
<>
<span
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<span style={{ flex: '1 1 auto' }}>
<Paragraph noMargins isInverse={args.isInverse}>
Current take: 1 of 3
</Paragraph>
</span>
<span style={{ flex: '0 0 auto' }}>
<Paragraph noMargins isInverse={args.isInverse}>
Points possible: 10
</Paragraph>
</span>
</span>
<Paragraph noMargins isInverse={args.isInverse}>
Grade uses: Best attempt
</Paragraph>
<Spacer size={12} />
<DropdownDivider />
<Spacer size={12} />
<Paragraph noMargins isInverse={args.isInverse}>
Credit/No Credit Activity
</Paragraph>
In this activity you must achieve 80% or higher to receive credit
<Spacer size={12} />
</>
</DropdownContent>
</Dropdown>
<Dropdown width="500px" {...args}>
<DropdownButton>Dropdown without items, with button</DropdownButton>
<DropdownContent style={{ padding: '12px' }}>
<>
<Paragraph noMargins isInverse={args.isInverse}>
Bacon ipsum dolor amet capicola turkey chicken cupim pastrami pork
spare ribs shankle ball tip. Shank doner burgdoggen tri-tip corned
beef meatloaf pig ground round. Ball tip t-bone cow chicken.{' '}
</Paragraph>
<Button isInverse={args.isInverse}>Foo</Button>
</>
</DropdownContent>
</Dropdown>
</ButtonGroup>
);
};
88 changes: 88 additions & 0 deletions packages/react-magma-dom/src/components/Dropdown/Dropdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -703,4 +703,92 @@ describe('Dropdown', () => {

expect(getByText('Google').querySelector('svg')).toBeInTheDocument();
});

describe('dropdown without items', () => {
it('should focus the entire container when button is clicked', () => {
jest.useFakeTimers();

const { getByText, getByTestId } = render(
<Dropdown testId="dropdown">
<DropdownButton>Toggle me</DropdownButton>
<DropdownContent>
<p>test content</p>
<button>something</button>
</DropdownContent>
</Dropdown>
);

fireEvent.click(getByText('Toggle me'));

act(jest.runAllTimers);

expect(getByTestId('dropdownContent')).toHaveStyleRule(
'display',
'block'
);

expect(getByTestId('dropdownContent')).toHaveFocus();

jest.useRealTimers();
});

it('should close the menu when escape key is pressed', () => {
const { getByText, getByTestId } = render(
<Dropdown testId="dropdown">
<DropdownButton>Toggle me</DropdownButton>
<DropdownContent>
<p>test</p>
</DropdownContent>
</Dropdown>
);

expect(getByTestId('dropdownContent')).toHaveStyleRule('display', 'none');

fireEvent.click(getByText('Toggle me'));

expect(getByTestId('dropdownContent')).toHaveStyleRule(
'display',
'block'
);

fireEvent.keyDown(getByTestId('dropdown'), {
key: 'ArrowDown',
});

fireEvent.keyDown(getByTestId('dropdown'), {
key: 'Escape',
code: 27,
});

expect(getByTestId('dropdownContent')).toHaveStyleRule('display', 'none');
});

it('should close the menu on blur', () => {
jest.useFakeTimers();

const onClose = jest.fn();
const { getByText, getByTestId } = render(
<Dropdown testId="dropdown" onClose={onClose}>
<DropdownButton>Toggle me</DropdownButton>
<DropdownContent>
<p>test</p>
</DropdownContent>
</Dropdown>
);

expect(getByTestId('dropdownContent')).toHaveStyleRule('display', 'none');
userEvent.click(getByText('Toggle me'));
expect(getByTestId('dropdownContent')).toHaveStyleRule(
'display',
'block'
);

userEvent.click(document.body);
act(jest.runAllTimers);

expect(onClose).toHaveBeenCalled();
expect(getByTestId('dropdownContent')).toHaveStyleRule('display', 'none');
jest.useRealTimers();
});
});
});
16 changes: 10 additions & 6 deletions packages/react-magma-dom/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(
(props, forwardedRef) => {
const contextProps = React.useContext(ButtonGroupContext);
const resolvedProps = resolveProps(contextProps, props);

const {
activeIndex,
alignment,
Expand Down Expand Up @@ -140,11 +140,15 @@ export const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(

setIsOpen(true);

setTimeout(() => {
filteredItems.length > 0 &&
filteredItems[0].current &&
filteredItems[0].current.focus();
}, 0);
if (filteredItems.length > 0) {
setTimeout(() => {
filteredItems[0].current && filteredItems[0].current.focus();
}, 0);
} else {
setTimeout(() => {
menuRef.current.focus();
}, 0);
}

onOpen && typeof onOpen === 'function' && onOpen();
}
Expand Down
Loading

2 comments on commit 1c91ac3

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.