Skip to content

Commit

Permalink
Fix primefaces#6095: Dialog refactor using FocusTrap
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware committed Apr 29, 2024
1 parent b3d109a commit 738cdcf
Showing 1 changed file with 25 additions and 71 deletions.
96 changes: 25 additions & 71 deletions components/lib/dialog/Dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import PrimeReact, { PrimeReactContext, localeOption } from '../api/Api';
import { useHandleStyle } from '../componentbase/ComponentBase';
import { CSSTransition } from '../csstransition/CSSTransition';
import FocusTrap from '../focustrap/FocusTrap';
import { ESC_KEY_HANDLING_PRIORITIES, useDisplayOrder, useEventListener, useGlobalOnEscapeKey, useMergeProps, useMountEffect, useUnmountEffect, useUpdateEffect } from '../hooks/Hooks';
import { TimesIcon } from '../icons/times';
import { WindowMaximizeIcon } from '../icons/windowmaximize';
Expand Down Expand Up @@ -60,7 +61,6 @@ export const Dialog = React.forwardRef((inProps, ref) => {
priority: [ESC_KEY_HANDLING_PRIORITIES.DIALOG, displayOrder]
});

const [bindDocumentKeyDownListener, unbindDocumentKeyDownListener] = useEventListener({ type: 'keydown', listener: (event) => onKeyDown(event) });
const [bindDocumentResizeListener, unbindDocumentResizeListener] = useEventListener({ type: 'mousemove', target: () => window.document, listener: (event) => onResize(event) });
const [bindDocumentResizeEndListener, unbindDocumentResizEndListener] = useEventListener({ type: 'mouseup', target: () => window.document, listener: (event) => onResizeEnd(event) });
const [bindDocumentDragListener, unbindDocumentDragListener] = useEventListener({ type: 'mousemove', target: () => window.document, listener: (event) => onDrag(event) });
Expand Down Expand Up @@ -107,49 +107,6 @@ export const Dialog = React.forwardRef((inProps, ref) => {
event.preventDefault();
};

const onKeyDown = (event) => {
const currentTarget = event.currentTarget;

if (!currentTarget || !currentTarget.primeDialogParams) {
return;
}

const params = currentTarget.primeDialogParams;
const paramLength = params.length;
const dialogId = params[paramLength - 1] ? params[paramLength - 1].id : undefined;

if (dialogId !== idState) {
return;
}

const dialog = document.getElementById(dialogId);

if (event.key === 'Tab') {
event.preventDefault();
const focusableElements = DomHandler.getFocusableElements(dialog);

if (focusableElements && focusableElements.length > 0) {
if (!document.activeElement) {
focusableElements[0].focus();
} else {
const focusedIndex = focusableElements.indexOf(document.activeElement);

if (event.shiftKey) {
if (focusedIndex === -1 || focusedIndex === 0) {
focusableElements[focusableElements.length - 1].focus();
} else {
focusableElements[focusedIndex - 1].focus();
}
} else if (focusedIndex === -1 || focusedIndex === focusableElements.length - 1) {
focusableElements[0].focus();
} else {
focusableElements[focusedIndex + 1].focus();
}
}
}
}
};

const onDragStart = (event) => {
if (DomHandler.hasClass(event.target, 'p-dialog-header-icon') || DomHandler.hasClass(event.target.parentElement, 'p-dialog-header-icon')) {
return;
Expand Down Expand Up @@ -376,16 +333,13 @@ export const Dialog = React.forwardRef((inProps, ref) => {
bindDocumentResizeListener();
bindDocumentResizeEndListener();
}

bindDocumentKeyDownListener();
};

const unbindGlobalListeners = () => {
unbindDocumentDragListener();
unbindDocumentDragEndListener();
unbindDocumentResizeListener();
unbindDocumentResizEndListener();
unbindDocumentKeyDownListener();
};

const createStyle = () => {
Expand Down Expand Up @@ -655,7 +609,7 @@ export const Dialog = React.forwardRef((inProps, ref) => {
return undefined;
};

const createTemplateElement = ({ maskProps, rootProps, transitionProps }) => {
const createTemplateElement = () => {
const messageProps = {
header: props.header,
content: props.message,
Expand All @@ -664,32 +618,22 @@ export const Dialog = React.forwardRef((inProps, ref) => {

const templateElementProps = { headerRef, contentRef, footerRef, closeRef, hide: onClose, message: messageProps };

return (
<div {...maskProps}>
<CSSTransition nodeRef={dialogRef} {...transitionProps}>
<div {...rootProps}>{ObjectUtils.getJSXElement(inProps.content, templateElementProps)}</div>
</CSSTransition>
</div>
);
return ObjectUtils.getJSXElement(inProps.content, templateElementProps);
};

const createElement = ({ maskProps, rootProps, transitionProps }) => {
const createElement = () => {
const header = createHeader();
const content = createContent();
const footer = createFooter();
const resizer = createResizer();

return (
<div {...maskProps}>
<CSSTransition nodeRef={dialogRef} {...transitionProps}>
<div {...rootProps}>
{header}
{content}
{footer}
{resizer}
</div>
</CSSTransition>
</div>
<>
{header}
{content}
{footer}
{resizer}
</>
);
};

Expand Down Expand Up @@ -744,15 +688,25 @@ export const Dialog = React.forwardRef((inProps, ref) => {
ptm('transition')
);

if (inProps?.content) {
const templateElement = createTemplateElement({ maskProps, rootProps, transitionProps });
let contentElement = null;

return <Portal element={templateElement} appendTo={props.appendTo} visible />;
if (inProps?.content) {
contentElement = createTemplateElement();
} else {
contentElement = createElement();
}

const element = createElement({ maskProps, rootProps, transitionProps });
const rootElement = (
<div {...maskProps}>
<CSSTransition nodeRef={dialogRef} {...transitionProps}>
<div {...rootProps}>
<FocusTrap autoFocus>{contentElement}</FocusTrap>
</div>
</CSSTransition>
</div>
);

return <Portal element={element} appendTo={props.appendTo} visible />;
return <Portal element={rootElement} appendTo={props.appendTo} visible />;
};

return maskVisibleState && createDialog();
Expand Down

0 comments on commit 738cdcf

Please sign in to comment.