diff --git a/.changeset/strong-poems-double.md b/.changeset/strong-poems-double.md new file mode 100644 index 00000000000..4df6142f2ed --- /dev/null +++ b/.changeset/strong-poems-double.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris': minor +--- + +Clicking on the modal backdrop triggers the pressed state of the modal's close button diff --git a/polaris-react/src/components/Backdrop/Backdrop.tsx b/polaris-react/src/components/Backdrop/Backdrop.tsx index ba274071f75..4a0ca77d734 100644 --- a/polaris-react/src/components/Backdrop/Backdrop.tsx +++ b/polaris-react/src/components/Backdrop/Backdrop.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {Dispatch, SetStateAction} from 'react'; import {classNames} from '../../utilities/css'; import {ScrollLock} from '../ScrollLock'; @@ -10,10 +10,12 @@ export interface BackdropProps { transparent?: boolean; onClick?(): void; onTouchStart?(): void; + setClosing?: Dispatch>; } export function Backdrop(props: BackdropProps) { - const {onClick, onTouchStart, belowNavigation, transparent} = props; + const {onClick, onTouchStart, belowNavigation, transparent, setClosing} = + props; const className = classNames( styles.Backdrop, @@ -21,6 +23,19 @@ export function Backdrop(props: BackdropProps) { transparent && styles.transparent, ); + const handleMouseDown = () => { + if (setClosing) { + setClosing(true); + } + }; + + const handleMouseUp = () => { + if (setClosing && onClick) { + setClosing(false); + onClick(); + } + }; + return ( <> @@ -28,6 +43,8 @@ export function Backdrop(props: BackdropProps) { className={className} onClick={onClick} onTouchStart={onTouchStart} + onMouseDown={handleMouseDown} + onMouseUp={handleMouseUp} /> ); diff --git a/polaris-react/src/components/Modal/Modal.tsx b/polaris-react/src/components/Modal/Modal.tsx index 0967d78e459..b1126b44f70 100644 --- a/polaris-react/src/components/Modal/Modal.tsx +++ b/polaris-react/src/components/Modal/Modal.tsx @@ -90,6 +90,7 @@ export const Modal: React.FunctionComponent & { fullScreen, }: ModalProps) { const [iframeHeight, setIframeHeight] = useState(IFRAME_LOADING_HEIGHT); + const [closing, setClosing] = useState(false); const headerId = useUniqueId('modal-header'); const activatorRef = useRef(null); @@ -195,8 +196,14 @@ export const Modal: React.FunctionComponent & { small={small} limitHeight={limitHeight} fullScreen={fullScreen} + setClosing={setClosing} > -
+
{title}
{bodyMarkup}
@@ -204,7 +211,7 @@ export const Modal: React.FunctionComponent & { ); - backdrop = ; + backdrop = ; } const animated = !instant; diff --git a/polaris-react/src/components/Modal/components/CloseButton/CloseButton.scss b/polaris-react/src/components/Modal/components/CloseButton/CloseButton.scss index cd79fee5ac7..8cc0a360491 100644 --- a/polaris-react/src/components/Modal/components/CloseButton/CloseButton.scss +++ b/polaris-react/src/components/Modal/components/CloseButton/CloseButton.scss @@ -13,7 +13,8 @@ @include recolor-icon(var(--p-icon-hovered)); } - &:active { + &:active, + &.pressed { background: var(--p-surface-pressed); } diff --git a/polaris-react/src/components/Modal/components/CloseButton/CloseButton.tsx b/polaris-react/src/components/Modal/components/CloseButton/CloseButton.tsx index 7517c5fc159..176f52ef244 100644 --- a/polaris-react/src/components/Modal/components/CloseButton/CloseButton.tsx +++ b/polaris-react/src/components/Modal/components/CloseButton/CloseButton.tsx @@ -8,11 +8,16 @@ import {Icon} from '../../../Icon'; import styles from './CloseButton.scss'; export interface CloseButtonProps { + pressed?: boolean; titleHidden?: boolean; onClick(): void; } -export function CloseButton({titleHidden = false, onClick}: CloseButtonProps) { +export function CloseButton({ + pressed, + titleHidden = false, + onClick, +}: CloseButtonProps) { const i18n = useI18n(); return ( @@ -21,6 +26,7 @@ export function CloseButton({titleHidden = false, onClick}: CloseButtonProps) { className={classNames( styles.CloseButton, titleHidden && styles.titleHidden, + pressed && styles.pressed, )} aria-label={i18n.translate('Polaris.Common.close')} > diff --git a/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx b/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx index f640db87986..f13f4ef74b1 100644 --- a/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx +++ b/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx @@ -1,4 +1,4 @@ -import React, {useRef, useEffect} from 'react'; +import React, {useRef, useEffect, SetStateAction, Dispatch} from 'react'; import {Transition, CSSTransition} from 'react-transition-group'; import {motion} from '@shopify/polaris-tokens'; @@ -22,6 +22,7 @@ export interface DialogProps { onExited?(): void; in?: boolean; fullScreen?: boolean; + setClosing?: Dispatch>; } export function Dialog({ @@ -35,6 +36,7 @@ export function Dialog({ small, limitHeight, fullScreen, + setClosing, ...props }: DialogProps) { const containerNode = useRef(null); @@ -53,6 +55,19 @@ export function Dialog({ focusFirstFocusableNode(containerNode.current); }, []); + const handleKeyDown = () => { + if (setClosing) { + setClosing(true); + } + }; + + const handleKeyUp = () => { + if (setClosing) { + setClosing(false); + } + onClose(); + }; + return (
- + + {children}
diff --git a/polaris-react/src/components/Modal/components/Header/Header.tsx b/polaris-react/src/components/Modal/components/Header/Header.tsx index e5d9c71dafd..47e6f86947c 100644 --- a/polaris-react/src/components/Modal/components/Header/Header.tsx +++ b/polaris-react/src/components/Modal/components/Header/Header.tsx @@ -8,11 +8,18 @@ import styles from './Header.scss'; export interface HeaderProps { id: string; titleHidden: boolean; + closing: boolean; children?: React.ReactNode; onClose(): void; } -export function Header({id, titleHidden, children, onClose}: HeaderProps) { +export function Header({ + id, + titleHidden, + closing, + children, + onClose, +}: HeaderProps) { return (
- + ); }