diff --git a/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialog.tsx b/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialog.tsx index b39960ab13..d1f420fb57 100644 --- a/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialog.tsx +++ b/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialog.tsx @@ -24,7 +24,7 @@ export const ActionDialog: React.FC = ({ onClickClose, onPressEscape = onClickClose, responseMessage, - actionDisabled = false, + actionDisabled, closeDisabled, subActionArea, className, @@ -37,17 +37,15 @@ export const ActionDialog: React.FC = ({ const titleId = useId() const handleClickClose = useCallback(() => { - if (!props.isOpen) { - return + if (props.isOpen) { + onClickClose() } - onClickClose() }, [onClickClose, props.isOpen]) const handleClickAction = useCallback(() => { - if (!props.isOpen) { - return + if (props.isOpen) { + onClickAction(onClickClose) } - onClickAction(onClickClose) }, [onClickAction, onClickClose, props.isOpen]) return createPortal( diff --git a/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContent.tsx b/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContent.tsx index 2202f21684..b79ee4eef4 100644 --- a/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContent.tsx +++ b/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContent.tsx @@ -20,7 +20,7 @@ export const ActionDialogContent: React.FC = ({ actionText, actionTheme, onClickAction, - actionDisabled = false, + actionDisabled, portalParent, className = '', decorators, @@ -30,17 +30,15 @@ export const ActionDialogContent: React.FC = ({ const { createPortal } = useDialogPortal(portalParent) const handleClickClose = useCallback(() => { - if (!active) { - return + if (active) { + onClickClose() } - onClickClose() }, [active, onClickClose]) const handleClickAction = useCallback(() => { - if (!active) { - return + if (active) { + onClickAction(onClickClose) } - onClickAction(onClickClose) }, [active, onClickAction, onClickClose]) const titleId = useId() diff --git a/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContentInner.tsx b/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContentInner.tsx index 4d83d9a9bf..414bec0910 100644 --- a/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContentInner.tsx +++ b/packages/smarthr-ui/src/components/Dialog/ActionDialog/ActionDialogContentInner.tsx @@ -1,10 +1,11 @@ 'use client' -import React, { type FC, type PropsWithChildren, type ReactNode, useCallback } from 'react' +import React, { type FC, type PropsWithChildren, type ReactNode, useCallback, useMemo } from 'react' import { Button } from '../../Button' import { Cluster, Stack } from '../../Layout' import { ResponseMessage } from '../../ResponseMessage' +import { Section } from '../../SectioningContent' import { DialogBody, type Props as DialogBodyProps } from '../DialogBody' import { DialogHeader, type Props as DialogHeaderProps } from '../DialogHeader' import { dialogContentInner } from '../dialogInnerStyle' @@ -40,6 +41,8 @@ export type ActionDialogContentInnerProps = BaseProps & { } const CLOSE_BUTTON_LABEL = 'キャンセル' +const ACTION_AREA_CLUSTER_GAP = { row: 0.5, column: 1 } as const + export const ActionDialogContentInner: FC = ({ children, title, @@ -49,59 +52,166 @@ export const ActionDialogContentInner: FC = ({ contentBgColor, contentPadding, actionText, - actionTheme = 'primary', + actionTheme, onClickAction, onClickClose, responseMessage, - actionDisabled = false, + actionDisabled, closeDisabled, subActionArea, decorators, }) => { - const handleClickAction = useCallback(() => { - onClickAction(onClickClose) - }, [onClickAction, onClickClose]) - const isRequestProcessing = responseMessage && responseMessage.status === 'processing' + const calcedResponseStatus = useMemo(() => { + if (!responseMessage) { + return { + isProcessing: false, + visibleMessage: false, + } + } + + if (responseMessage.status === 'processing') { + return { + isProcessing: true, + visibleMessage: false, + } + } - const { wrapper, actionArea, buttonArea, message } = dialogContentInner() + return { + isProcessing: false, + visibleMessage: true, + // HINT: statusがprocessingではない === success or errorであることが確定する + // success or error の場合、text属性も必ず存在する + status: responseMessage.status as 'success' | 'error', + message: (responseMessage as { text: string }).text, + } + }, [responseMessage]) + + const styles = useMemo(() => { + const { wrapper, actionArea, buttonArea, message } = dialogContentInner() + + return { + wrapper: wrapper(), + actionArea: actionArea(), + buttonArea: buttonArea(), + message: message(), + } + }, []) return ( - // eslint-disable-next-line smarthr/best-practice-for-layouts, smarthr/a11y-heading-in-sectioning-content - + // eslint-disable-next-line smarthr/a11y-heading-in-sectioning-content +
{children} - + {subActionArea} - - - - + - {(responseMessage?.status === 'success' || responseMessage?.status === 'error') && ( -
- - {responseMessage.text} + {calcedResponseStatus.visibleMessage && ( +
+ + {calcedResponseStatus.message}
)} - +
) } + +const ActionAreaCluster = React.memo< + Pick< + ActionDialogContentInnerProps, + | 'onClickClose' + | 'onClickAction' + | 'closeDisabled' + | 'actionDisabled' + | 'actionTheme' + | 'decorators' + | 'actionText' + > & { loading: boolean; className: string } +>( + ({ + onClickClose, + onClickAction, + closeDisabled, + actionDisabled, + loading, + actionTheme, + decorators, + actionText, + className, + }) => { + const handleClickAction = useCallback(() => { + onClickAction(onClickClose) + }, [onClickAction, onClickClose]) + + return ( + + + + {actionText} + + + ) + }, +) + +const ActionButton = React.memo< + PropsWithChildren<{ + variant: ActionDialogContentInnerProps['actionTheme'] + disabled: ActionDialogContentInnerProps['actionDisabled'] + loading: boolean + onClick: () => void + }> +>(({ variant = 'primary', disabled, loading, onClick, children }) => ( + +)) + +const CloseButton = React.memo< + Pick & { + onClick: ActionDialogContentInnerProps['onClickClose'] + disabled: boolean + } +>(({ onClick, disabled, decorators }) => { + const children = useMemo( + () => decorators?.closeButtonLabel?.(CLOSE_BUTTON_LABEL) || CLOSE_BUTTON_LABEL, + [decorators], + ) + + return ( + + ) +}) diff --git a/packages/smarthr-ui/src/components/Dialog/ActionDialogWithTrigger/ActionDialogWithTrigger.tsx b/packages/smarthr-ui/src/components/Dialog/ActionDialogWithTrigger/ActionDialogWithTrigger.tsx index ee360419fe..1f7aa68bb3 100644 --- a/packages/smarthr-ui/src/components/Dialog/ActionDialogWithTrigger/ActionDialogWithTrigger.tsx +++ b/packages/smarthr-ui/src/components/Dialog/ActionDialogWithTrigger/ActionDialogWithTrigger.tsx @@ -21,29 +21,20 @@ export const ActionDialogWithTrigger: React.FC< const open = useCallback(() => setIsOpen(true), []) const close = useCallback(() => setIsOpen(false), []) - const onClickOpen = useCallback(() => { - if (onClickTrigger) { - return onClickTrigger(open) - } - - open() - }, [onClickTrigger, open]) - - const actualOnClickClose = useCallback(() => { - if (onClickClose) { - return onClickClose(close) - } - - close() - }, [onClickClose, close]) + const onClickOpen = useMemo( + () => (onClickTrigger ? () => onClickTrigger(open) : open), + [onClickTrigger, open], + ) - const actualOnPressEscape = useCallback(() => { - if (onPressEscape) { - return onPressEscape(close) - } + const actualOnClickClose = useMemo( + () => (onClickClose ? () => onClickClose(close) : close), + [onClickClose, close], + ) - close() - }, [onPressEscape, close]) + const actualOnPressEscape = useMemo( + () => (onPressEscape ? () => onPressEscape(close) : close), + [onPressEscape, close], + ) const actualTrigger = useMemo( () =>