Skip to content

Commit

Permalink
fix: Do not dismiss modal on ESC if dropdown is opened (#1701)
Browse files Browse the repository at this point in the history
  • Loading branch information
Al-Dani authored Nov 6, 2023
1 parent 2294c10 commit 49829b2
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 6 deletions.
186 changes: 186 additions & 0 deletions pages/modal/with-dropdowns.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';
import {
Modal,
Button,
SpaceBetween,
Autosuggest,
ButtonDropdown,
DatePicker,
DateRangePicker,
DateRangePickerProps,
Multiselect,
MultiselectProps,
Popover,
} from '~components';

export default function () {
const [visible, setVisible] = useState(false);
const [value, setValue] = useState('');
const [dateRangeValue, setDateRangeValue] = useState<DateRangePickerProps['value']>(null);
const [selectedOptions, setSelectedOptions] = useState<MultiselectProps['selectedOptions']>([
{
label: 'Option 1',
value: '1',
description: 'This is a description',
},
]);

return (
<article>
<h1>Simple modal</h1>
<Button onClick={() => setVisible(true)}>Show modal</Button>
<Modal
header="Delete instance"
visible={visible}
onDismiss={() => setVisible(false)}
closeAriaLabel="Close modal"
footer={
<span style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button variant="link">Cancel</Button>
<Button variant="primary">Delete</Button>
</span>
}
>
<SpaceBetween size={'xs'}>
<Autosuggest
onChange={({ detail }) => setValue(detail.value)}
value={value}
options={[
{ value: 'Suggestion 1' },
{ value: 'Suggestion 2' },
{ value: 'Suggestion 3' },
{ value: 'Suggestion 4' },
]}
ariaLabel="Autosuggest example with suggestions"
placeholder="Enter value"
empty="No matches found"
/>

<ButtonDropdown
items={[
{ text: 'Delete', id: 'rm', disabled: false },
{ text: 'Move', id: 'mv', disabled: false },
{ text: 'Rename', id: 'rn', disabled: true },
{
id: 'view',
text: 'View metrics',
href: 'https://example.com',
external: true,
externalIconAriaLabel: '(opens in new tab)',
},
]}
>
Short
</ButtonDropdown>

<DatePicker
onChange={({ detail }) => setValue(detail.value)}
value={value}
openCalendarAriaLabel={selectedDate =>
'Choose certificate expiry date' + (selectedDate ? `, selected date is ${selectedDate}` : '')
}
placeholder="YYYY/MM/DD"
/>

<DateRangePicker
onChange={({ detail }) => setDateRangeValue(detail.value)}
value={dateRangeValue}
relativeOptions={[
{
key: 'previous-5-minutes',
amount: 5,
unit: 'minute',
type: 'relative',
},
{
key: 'previous-30-minutes',
amount: 30,
unit: 'minute',
type: 'relative',
},
{
key: 'previous-1-hour',
amount: 1,
unit: 'hour',
type: 'relative',
},
{
key: 'previous-6-hours',
amount: 6,
unit: 'hour',
type: 'relative',
},
]}
isValidRange={range => {
if (range?.type === 'absolute') {
const [startDateWithoutTime] = range.startDate.split('T');
const [endDateWithoutTime] = range.endDate.split('T');
if (!startDateWithoutTime || !endDateWithoutTime) {
return {
valid: false,
errorMessage:
'The selected date range is incomplete. Select a start and end date for the date range.',
};
}
}
return { valid: true };
}}
i18nStrings={{}}
placeholder="Filter by a date and time range"
/>

<Multiselect
selectedOptions={selectedOptions}
onChange={({ detail }) => setSelectedOptions(detail.selectedOptions)}
options={[
{
label: 'Option 1',
value: '1',
description: 'This is a description',
},
{
label: 'Option 2',
value: '2',
iconName: 'unlocked',
labelTag: 'This is a label tag',
},
{
label: 'Option 3 (disabled)',
value: '3',
iconName: 'share',
tags: ['Tags go here', 'Tag1', 'Tag2'],
disabled: true,
},
{
label: 'Option 4',
value: '4',
filteringTags: ['filtering', 'tags', 'these are filtering tags'],
},
{ label: 'Option 5', value: '5' },
]}
placeholder="Choose options"
/>

<Popover
header="Memory Error"
content="This instance contains insufficient memory. Stop the instance, choose a different instance type with more memory, and restart it."
>
Error
</Popover>

<Popover
dismissButton={false}
position="top"
size="small"
triggerType="custom"
content={'Code snippet copied'}
>
<Button iconName="copy">Copy</Button>
</Popover>
</SpaceBetween>
</Modal>
</article>
);
}
3 changes: 3 additions & 0 deletions src/button-dropdown/utils/use-button-dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ export function useButtonDropdown({
onReturnFocus();
closeDropdown();
event.preventDefault();
if (isOpen) {
event.stopPropagation();
}
break;
}
case KeyCode.tab: {
Expand Down
1 change: 1 addition & 0 deletions src/date-picker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const DatePicker = React.forwardRef(

const onWrapperKeyDownHandler = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.keyCode === KeyCode.escape && isDropDownOpen) {
event.stopPropagation();
buttonRef.current?.focus();
setIsDropDownOpen(false);
}
Expand Down
3 changes: 3 additions & 0 deletions src/date-range-picker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ const DateRangePicker = React.forwardRef(

const onWrapperKeyDownHandler = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.keyCode === KeyCode.escape) {
if (isDropDownOpen) {
event.stopPropagation();
}
closeDropdown(true);
}
};
Expand Down
2 changes: 2 additions & 0 deletions src/internal/components/autosuggest-input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ const AutosuggestInput = React.forwardRef(
}
case KeyCode.escape: {
if (open) {
event.stopPropagation();
closeDropdown();
} else if (value) {
event.stopPropagation();
fireNonCancelableEvent(onChange, { value: '' });
}
event.preventDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const menuKeys: any = [
['enter', KeyCode.enter],
['space', KeyCode.space],
].reduce<any>((acc, [name, keyCode]) => {
acc[name] = { detail: { keyCode }, preventDefault: jest.fn() };
acc[name] = { detail: { keyCode }, preventDefault: jest.fn(), stopPropagation: jest.fn() };
return acc;
}, {});

Expand Down
1 change: 1 addition & 0 deletions src/internal/components/options-list/utils/use-keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const useMenuKeyboard: UseMenuKeyboard = ({
goEnd();
break;
case KeyCode.escape:
e.stopPropagation();
closeDropdown();
break;
case KeyCode.enter:
Expand Down
Loading

0 comments on commit 49829b2

Please sign in to comment.