Skip to content

Commit

Permalink
Fix primefaces#4158: Dialog/Confirm re-focus original element on close (
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware committed Jun 28, 2023
1 parent cd73445 commit 62cb776
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
12 changes: 9 additions & 3 deletions components/lib/confirmdialog/ConfirmDialog.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import * as React from 'react';
import { localeOption } from '../api/Api';
import { PrimeReactContext, localeOption } from '../api/Api';
import { Button } from '../button/Button';
import { Dialog } from '../dialog/Dialog';
import { useUnmountEffect, useUpdateEffect } from '../hooks/Hooks';
import { OverlayService } from '../overlayservice/OverlayService';
import { Portal } from '../portal/Portal';
import { IconUtils, ObjectUtils, classNames, mergeProps } from '../utils/Utils';
import { DomHandler, IconUtils, ObjectUtils, classNames, mergeProps } from '../utils/Utils';
import { ConfirmDialogBase } from './ConfirmDialogBase';
import { PrimeReactContext } from '../api/Api';

export const confirmDialog = (props = {}) => {
props = { ...props, ...{ visible: props.visible === undefined ? true : props.visible } };
Expand All @@ -33,6 +32,7 @@ export const ConfirmDialog = React.memo(
const [reshowState, setReshowState] = React.useState(false);
const confirmProps = React.useRef(null);
const isCallbackExecuting = React.useRef(false);
const focusElementOnHide = React.useRef(null);
const getCurrentProps = () => confirmProps.current || props;
const getPropValue = (key) => (confirmProps.current || props)[key];
const callbackFromProp = (key, ...param) => ObjectUtils.getPropValue(getPropValue(key), param);
Expand Down Expand Up @@ -66,11 +66,17 @@ export const ConfirmDialog = React.memo(
const show = () => {
setVisibleState(true);
isCallbackExecuting.current = false;

// Remember the focused element before we opened the dialog
// so we can return focus to it once we close the dialog.
focusElementOnHide.current = document.activeElement;
};

const hide = (result = 'cancel') => {
setVisibleState(false);
callbackFromProp('onHide', { result });
DomHandler.focus(focusElementOnHide.current);
focusElementOnHide.current = null;
};

const confirm = (updatedProps) => {
Expand Down
11 changes: 9 additions & 2 deletions components/lib/confirmpopup/ConfirmPopup.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import PrimeReact, { localeOption } from '../api/Api';
import { PrimeReactContext } from '../api/Api';
import PrimeReact, { PrimeReactContext, localeOption } from '../api/Api';
import { Button } from '../button/Button';
import { CSSTransition } from '../csstransition/CSSTransition';
import { useOverlayListener, useUnmountEffect, useUpdateEffect } from '../hooks/Hooks';
Expand Down Expand Up @@ -44,6 +43,7 @@ export const ConfirmPopup = React.memo(
const isPanelClicked = React.useRef(false);
const overlayEventListener = React.useRef(null);
const confirmProps = React.useRef(null);
const focusElementOnHide = React.useRef(null);
const isCallbackExecuting = React.useRef(false);
const getCurrentProps = () => confirmProps.current || props;
const getPropValue = (key) => (confirmProps.current || props)[key];
Expand Down Expand Up @@ -91,6 +91,10 @@ export const ConfirmPopup = React.memo(
};

const show = () => {
// Remember the focused element before we opened the dialog
// so we can return focus to it once we close the dialog.
focusElementOnHide.current = document.activeElement;

setVisibleState(true);
setReshowState(false);
isCallbackExecuting.current = false;
Expand All @@ -110,6 +114,9 @@ export const ConfirmPopup = React.memo(
if (result) {
callbackFromProp('onHide', result);
}

DomHandler.focus(focusElementOnHide.current);
focusElementOnHide.current = null;
};

const onEnter = () => {
Expand Down
16 changes: 13 additions & 3 deletions components/lib/dialog/Dialog.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import PrimeReact, { localeOption } from '../api/Api';
import { PrimeReactContext } from '../api/Api';
import PrimeReact, { PrimeReactContext, localeOption } from '../api/Api';
import { CSSTransition } from '../csstransition/CSSTransition';
import { useEventListener, useMountEffect, useUnmountEffect, useUpdateEffect } from '../hooks/Hooks';
import { TimesIcon } from '../icons/times';
Expand Down Expand Up @@ -33,6 +32,7 @@ export const Dialog = React.forwardRef((inProps, ref) => {
const lastPageY = React.useRef(null);
const styleElement = React.useRef(null);
const attributeSelector = React.useRef(uniqueId);
const focusElementOnHide = React.useRef(null);
const maximized = props.onMaximize ? props.maximized : maximizedState;

const { ptm } = DialogBase.setMetaData({
Expand Down Expand Up @@ -303,6 +303,10 @@ export const Dialog = React.forwardRef((inProps, ref) => {
ZIndexUtils.clear(maskRef.current);
setMaskVisibleState(false);
disableDocumentSettings();

// return focus to element before dialog was open
DomHandler.focus(focusElementOnHide.current);
focusElementOnHide.current = null;
};

const enableDocumentSettings = () => {
Expand Down Expand Up @@ -400,7 +404,13 @@ export const Dialog = React.forwardRef((inProps, ref) => {
if (props.visible !== visibleState && maskVisibleState) {
setVisibleState(props.visible);
}
});

if (props.visible) {
// Remember the focused element before we opened the dialog
// so we can return focus to it once we close the dialog.
focusElementOnHide.current = document.activeElement;
}
}, [props.visible, maskVisibleState]);

useUpdateEffect(() => {
if (maskVisibleState) {
Expand Down

0 comments on commit 62cb776

Please sign in to comment.