diff --git a/components/lib/confirmdialog/ConfirmDialog.d.ts b/components/lib/confirmdialog/ConfirmDialog.d.ts index d7c278c876..3e4b0094e9 100644 --- a/components/lib/confirmdialog/ConfirmDialog.d.ts +++ b/components/lib/confirmdialog/ConfirmDialog.d.ts @@ -23,6 +23,7 @@ interface ConfirmDialogOptions { } export interface ConfirmDialogProps extends Omit { + tagKey?: string; visible?: boolean; message?: ConfirmDialogTemplateType; rejectLabel?: string; @@ -46,6 +47,8 @@ interface ConfirmDialogReturn { hide(): void; } -export declare class ConfirmDialog extends React.Component { } +export declare class ConfirmDialog extends React.Component { + public confirm(props?: ConfirmDialogProps): void; +} export declare function confirmDialog(props: ConfirmDialogProps): ConfirmDialogReturn; diff --git a/components/lib/confirmdialog/ConfirmDialog.js b/components/lib/confirmdialog/ConfirmDialog.js index 7a4942b884..7cf89c5a2b 100644 --- a/components/lib/confirmdialog/ConfirmDialog.js +++ b/components/lib/confirmdialog/ConfirmDialog.js @@ -1,115 +1,140 @@ -import React, { forwardRef, memo, useState } from 'react'; -import ReactDOM from 'react-dom'; +import React, { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from 'react'; import { localeOption } from '../api/Api'; import { Dialog } from '../dialog/Dialog'; import { Button } from '../button/Button'; import { Portal } from '../portal/Portal'; -import { DomHandler, ObjectUtils, classNames, IconUtils } from '../utils/Utils'; -import { useUpdateEffect } from '../hooks/Hooks'; - -export const confirmDialog = (props) => { - const appendTo = props.appendTo || document.body; - - const confirmDialogWrapper = document.createDocumentFragment(); - DomHandler.appendChild(confirmDialogWrapper, appendTo); +import { ObjectUtils, classNames, IconUtils } from '../utils/Utils'; +import { useUnmountEffect, useUpdateEffect } from '../hooks/Hooks'; +import { OverlayService } from '../overlayservice/OverlayService'; +export const confirmDialog = (props = {}) => { props = { ...props, ...{ visible: props.visible === undefined ? true : props.visible } }; + props.visible && OverlayService.emit('confirm-dialog', props); - const confirmDialogEl = React.createElement(ConfirmDialog, props); - ReactDOM.render(confirmDialogEl, confirmDialogWrapper); - - const updateConfirmDialog = (newProps) => { - props = { ...props, ...newProps }; - ReactDOM.render(React.cloneElement(confirmDialogEl, props), confirmDialogWrapper); - }; - - return { - _destroy: () => { - ReactDOM.unmountComponentAtNode(confirmDialogWrapper); - }, - show: () => { - updateConfirmDialog({ - visible: true, onHide: () => { - updateConfirmDialog({ visible: false }); // reset - } - }); - }, - hide: () => { - updateConfirmDialog({ visible: false }); - }, - update: (newProps) => { - updateConfirmDialog(newProps); - } + const show = (updatedProps = {}) => { + OverlayService.emit('confirm-dialog', { ...props, ...updatedProps, ...{ visible: true } }); + } + + const hide = () => { + OverlayService.emit('confirm-dialog', { visible: false }); } + + return [show, hide]; } export const ConfirmDialog = memo(forwardRef((props, ref) => { const [visibleState, setVisibleState] = useState(props.visible); - const acceptLabel = props.acceptLabel || localeOption('accept'); - const rejectLabel = props.rejectLabel || localeOption('reject'); + const [reshowState, setReshowState] = useState(false); + const confirmProps = useRef(null); + const getCurrentProps = () => confirmProps.current || props; + const getPropValue = (key) => (confirmProps.current || props)[key]; + const callbackFromProp = (key, ...param) => ObjectUtils.getPropValue(getPropValue(key), param); + + const acceptLabel = getPropValue('acceptLabel') || localeOption('accept'); + const rejectLabel = getPropValue('rejectLabel') || localeOption('reject'); const accept = () => { - props.accept && props.accept(); + callbackFromProp('accept'); hide('accept'); } const reject = () => { - props.reject && props.reject(); + callbackFromProp('reject'); hide('reject'); } const show = () => { - setVisibleState(true) + setVisibleState(true); } const hide = (result) => { setVisibleState(false); - props.onHide && props.onHide(result); + callbackFromProp('onHide', result); } - useUpdateEffect(() => { - setVisibleState(props.visible); + const confirm = (updatedProps) => { + if (updatedProps.tagKey === props.tagKey) { + const isVisibleChanged = visibleState !== updatedProps.visible; + const targetChanged = getPropValue('target') !== updatedProps.target; + + if (targetChanged && !props.target) { + hide(); + confirmProps.current = updatedProps; + setReshowState(true); + } + else if (isVisibleChanged) { + confirmProps.current = updatedProps; + updatedProps.visible ? show() : hide(); + } + } + } + + useEffect(() => { + props.visible ? show() : hide(); }, [props.visible]); + useEffect(() => { + if (!props.target && !props.message) { + OverlayService.on('confirm-dialog', confirm); + } + + return () => { + OverlayService.off('confirm-dialog', confirm); + } + }, [props.target]); + + useUpdateEffect(() => { + reshowState && show(); + }, [reshowState]); + + useUnmountEffect(() => { + OverlayService.off('confirm-dialog', confirm); + }); + + useImperativeHandle(ref, () => ({ + confirm + })); + const createFooter = () => { - const acceptClassName = classNames('p-confirm-dialog-accept', props.acceptClassName); + const acceptClassName = classNames('p-confirm-dialog-accept', getPropValue('acceptClassName')); const rejectClassName = classNames('p-confirm-dialog-reject', { - 'p-button-text': !props.rejectClassName - }, props.rejectClassName); + 'p-button-text': !getPropValue('rejectClassName') + }, getPropValue('rejectClassName')); const content = ( <> - diff --git a/pages/confirmpopup/index.js b/pages/confirmpopup/index.js index d67a215fa7..0c66209e62 100644 --- a/pages/confirmpopup/index.js +++ b/pages/confirmpopup/index.js @@ -59,6 +59,8 @@ const ConfirmPopupDemo = () => {
+ +
Basic