From 020059d640b714016f94329d22748901e297e5ba Mon Sep 17 00:00:00 2001 From: schktjm Date: Wed, 2 Oct 2024 19:50:44 +0900 Subject: [PATCH 01/20] =?UTF-8?q?feat:=20FocusTrap=20=E3=82=92=E4=BB=BB?= =?UTF-8?q?=E6=84=8F=E3=81=AE=E3=82=BF=E3=82=A4=E3=83=9F=E3=83=B3=E3=82=B0?= =?UTF-8?q?=E3=81=A7=20focus=20=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20ref=20=E3=81=AE=E3=83=95=E3=82=A9=E3=83=AF?= =?UTF-8?q?=E3=83=BC=E3=83=87=E3=82=A3=E3=83=B3=E3=82=B0=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Dialog/FocusTrap.tsx | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/FocusTrap.tsx b/packages/smarthr-ui/src/components/Dialog/FocusTrap.tsx index 50d2308360..02cf7f3483 100644 --- a/packages/smarthr-ui/src/components/Dialog/FocusTrap.tsx +++ b/packages/smarthr-ui/src/components/Dialog/FocusTrap.tsx @@ -1,4 +1,12 @@ -import React, { FC, PropsWithChildren, RefObject, useCallback, useEffect, useRef } from 'react' +import React, { + PropsWithChildren, + RefObject, + forwardRef, + useCallback, + useEffect, + useImperativeHandle, + useRef, +} from 'react' import { tabbable } from '../../libs/tabbable' @@ -6,15 +14,29 @@ type Props = PropsWithChildren<{ firstFocusTarget?: RefObject }> -export const FocusTrap: FC = ({ firstFocusTarget, children }) => { - const ref = useRef(null) +export type FocusTrapRef = { + focus: () => void +} + +export const FocusTrap = forwardRef(({ firstFocusTarget, children }, ref) => { + const innerRef = useRef(null) const dummyFocusRef = useRef(null) + useImperativeHandle(ref, () => ({ + focus: () => { + if (firstFocusTarget?.current) { + firstFocusTarget.current.focus() + } else { + dummyFocusRef.current?.focus() + } + }, + })) + const handleKeyDown = useCallback((e: KeyboardEvent) => { - if (e.key !== 'Tab' || ref.current === null) { + if (e.key !== 'Tab' || innerRef.current === null) { return } - const tabbables = tabbable(ref.current).filter((elm) => elm.tabIndex >= 0) + const tabbables = tabbable(innerRef.current).filter((elm) => elm.tabIndex >= 0) if (tabbables.length === 0) { return } @@ -57,10 +79,10 @@ export const FocusTrap: FC = ({ firstFocusTarget, children }) => { }, [firstFocusTarget]) return ( -
+
{/* dummy element for focus management. */}
{children}
) -} +}) From 4664cf21e59fe225018fd41e183dfa5406dfefe6 Mon Sep 17 00:00:00 2001 From: schktjm Date: Fri, 11 Oct 2024 18:40:46 +0900 Subject: [PATCH 02/20] =?UTF-8?q?feat:=20DialogContentInner=20=E3=81=B8=20?= =?UTF-8?q?focusTrap=20=E3=81=AE=20props=20=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Dialog/DialogContentInner.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/DialogContentInner.tsx b/packages/smarthr-ui/src/components/Dialog/DialogContentInner.tsx index a668e6538e..969d218581 100644 --- a/packages/smarthr-ui/src/components/Dialog/DialogContentInner.tsx +++ b/packages/smarthr-ui/src/components/Dialog/DialogContentInner.tsx @@ -14,7 +14,7 @@ import { tv } from 'tailwind-variants' import { useHandleEscape } from '../../hooks/useHandleEscape' import { DialogOverlap } from './DialogOverlap' -import { FocusTrap } from './FocusTrap' +import { FocusTrap, FocusTrapRef } from './FocusTrap' import { useBodyScrollLock } from './useBodyScrollLock' export type DialogContentInnerProps = PropsWithChildren<{ @@ -51,6 +51,10 @@ export type DialogContentInnerProps = PropsWithChildren<{ * ダイアログの `aria-labelledby` */ ariaLabelledby?: string + /** + * ダイアログトップのフォーカストラップへの ref + */ + focusTrapRef?: RefObject }> type ElementProps = Omit, keyof DialogContentInnerProps> @@ -79,6 +83,7 @@ export const DialogContentInner: FC = ({ ariaLabelledby, children, className, + focusTrapRef, ...rest }) => { const { layoutStyleProps, innerStyle, backgroundStyle } = useMemo(() => { @@ -128,7 +133,9 @@ export const DialogContentInner: FC = ({ aria-modal="true" className={innerStyle} > - {children} + + {children} +
From 92a615431bc3a649b37bb7c05aa18e974bee4966 Mon Sep 17 00:00:00 2001 From: schktjm Date: Fri, 11 Oct 2024 18:43:47 +0900 Subject: [PATCH 03/20] =?UTF-8?q?feat:=20StepActionDialog=20=E3=81=AE?= =?UTF-8?q?=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialog/StepFormDialog/StepFormDialog.tsx | 114 +++++++++++++ .../StepFormDialog/StepFormDialogContent.tsx | 97 +++++++++++ .../StepFormDialogContentInner.tsx | 151 ++++++++++++++++++ .../components/Dialog/StepFormDialog/index.ts | 2 + .../Dialog/StepFormDialog/useStep.tsx | 42 +++++ 5 files changed, 406 insertions(+) create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx new file mode 100644 index 0000000000..a1411d483e --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx @@ -0,0 +1,114 @@ +import React, { ComponentProps, FormEvent, useCallback, useId } from 'react' + +import { DialogContentInner } from '../DialogContentInner' +import { DialogProps } from '../types' +import { useDialogPortal } from '../useDialogPortal' + +import { + StepFormDialogContentInner, + StepFormDialogContentInnerProps, +} from './StepFormDialogContentInner' +import { useStepDialog } from './useStep' + +type Props = Omit & + DialogProps +type ElementProps = Omit, keyof Props> + +export const StepFormDialog: React.FC = ({ + children, + title, + subtitle, + titleTag, + contentBgColor, + contentPadding, + actionTheme, + submitLabel, + onSubmit, + onClickClose, + onPressEscape = onClickClose, + responseMessage, + actionDisabled = false, + closeDisabled, + className, + portalParent, + decorators, + id, + ...props +}) => { + const { createPortal } = useDialogPortal(portalParent, id) + const titleId = useId() + const { + activeStep, + childrenSteps, + onSubmit: onSubmitStep, + onBackSteps, + onNextSteps, + focusTrapRef, + } = useStepDialog(children) + + const handleClickClose = useCallback(() => { + if (!props.isOpen) { + return + } + onClickClose() + }, [onClickClose, props.isOpen]) + + const handleSubmitAction = useCallback( + (close: () => void, e: FormEvent) => { + if (!props.isOpen) { + return + } + + onSubmitStep() + onSubmit(close, e) + }, + [onSubmit, onSubmitStep, props.isOpen], + ) + const handleBackSteps = useCallback(() => { + if (!props.isOpen) { + return + } + onBackSteps() + }, [props.isOpen, onBackSteps]) + + const handleNextSteps = useCallback(() => { + if (!props.isOpen) { + return + } + onNextSteps() + }, [props.isOpen, onNextSteps]) + + return createPortal( + + {/* eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} + + {childrenSteps[activeStep]} + + , + ) +} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx new file mode 100644 index 0000000000..a2ad2d7f1a --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx @@ -0,0 +1,97 @@ +import React, { FormEvent, HTMLAttributes, useCallback, useContext, useId } from 'react' + +import { DialogContentInner } from '../DialogContentInner' +import { DialogContext } from '../DialogWrapper' +import { UncontrolledDialogProps } from '../types' +import { useDialogPortal } from '../useDialogPortal' + +import { BaseProps, StepFormDialogContentInner } from './StepFormDialogContentInner' +import { useStepDialog } from './useStep' + +type Props = BaseProps & UncontrolledDialogProps +type ElementProps = Omit, keyof Props> + +export const StepFormDialogContent: React.FC = ({ + children, + title, + contentBgColor, + contentPadding, + submitLabel, + actionTheme, + onSubmit, + actionDisabled = false, + portalParent, + className = '', + decorators, + ...props +}) => { + const { activeStep, childrenSteps, onBackSteps, onNextSteps, focusTrapRef } = + useStepDialog(children) + const { onClickClose, active } = useContext(DialogContext) + const { createPortal } = useDialogPortal(portalParent) + + const handleClickClose = useCallback(() => { + if (!active) { + return + } + onClickClose() + }, [active, onClickClose]) + + const handleSubmitAction = useCallback( + (close: () => void, e: FormEvent) => { + if (!active) { + return + } + + onSubmit(close, e) + }, + [active, onSubmit], + ) + + const handleBackSteps = useCallback(() => { + if (!active) { + return + } + onBackSteps() + }, [active, onBackSteps]) + + const handleNextSteps = useCallback(() => { + if (!active) { + return + } + onNextSteps() + }, [active, onNextSteps]) + + const titleId = useId() + + return createPortal( + + {/* eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} + + {childrenSteps[activeStep]} + + , + ) +} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx new file mode 100644 index 0000000000..61751fc22f --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx @@ -0,0 +1,151 @@ +import React, { + type FC, + type FormEvent, + 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, Props as DialogBodyProps } from '../DialogBody' +import { DialogHeader, type Props as DialogHeaderProps } from '../DialogHeader' +import { dialogContentInner } from '../dialogInnerStyle' + +import type { DecoratorsType, ResponseMessageType } from '../../../types' + +export type BaseProps = PropsWithChildren< + DialogHeaderProps & + DialogBodyProps & { + /** アクションボタンのラベル */ + submitLabel: ReactNode + /** アクションボタンのスタイル */ + actionTheme?: 'primary' | 'secondary' | 'danger' + /** + * アクションボタンをクリックした時に発火するコールバック関数 + * @param closeDialog ダイアログを閉じる関数 + */ + onSubmit: (closeDialog: () => void, e: FormEvent) => void + /** アクションボタンを無効にするかどうか */ + actionDisabled?: boolean + /** 閉じるボタンを無効にするかどうか */ + closeDisabled?: boolean + /** コンポーネント内の文言を変更するための関数を設定 */ + decorators?: DecoratorsType<'closeButtonLabel' | 'nextButtonLabel' | 'backButtonLabel'> + } +> + +export type StepFormDialogContentInnerProps = BaseProps & { + onClickClose: () => void + responseMessage?: ResponseMessageType + activeStep: number + stepLength: number + onClickNext?: () => void + onClickBack?: () => void +} + +const CLOSE_BUTTON_LABEL = 'キャンセル' +const NEXT_BUTTON_LABEL = '次へ' +const BACK_BUTTON_LABEL = '戻る' + +export const StepFormDialogContentInner: FC = ({ + children, + title, + titleId, + subtitle, + titleTag, + contentBgColor, + contentPadding, + submitLabel, + actionTheme = 'primary', + activeStep, + stepLength, + onSubmit, + onClickClose, + responseMessage, + actionDisabled = false, + closeDisabled, + decorators, + onClickNext, + onClickBack, +}) => { + const handleSubmitAction = useCallback( + (e: FormEvent) => { + console.log('handleSubmitAction', activeStep) + e.preventDefault() + // HINT: React Potals などで擬似的にformがネストしている場合など、stopPropagationを実行しないと + // 親formが意図せずsubmitされてしまう場合がある + e.stopPropagation() + console.log('onSubmit', activeStep) + onSubmit(onClickClose, e) + }, + [activeStep, onSubmit, onClickClose], + ) + + const isRequestProcessing = responseMessage && responseMessage.status === 'processing' + + const { wrapper, actionArea, buttonArea, message } = dialogContentInner() + + const actionText = + activeStep === stepLength - 1 + ? submitLabel + : decorators?.nextButtonLabel?.(NEXT_BUTTON_LABEL) || NEXT_BUTTON_LABEL + + return ( + // eslint-disable-next-line smarthr/a11y-heading-in-sectioning-content +
+
+ {/* eslint-disable-next-line smarthr/best-practice-for-layouts */} + + + + {children} + + + + {activeStep > 0 && ( + + )} + + + + + + {(responseMessage?.status === 'success' || responseMessage?.status === 'error') && ( +
+ + {responseMessage.text} + +
+ )} +
+
+
+
+ ) +} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts new file mode 100644 index 0000000000..d84663facb --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts @@ -0,0 +1,2 @@ +export { StepFormDialog } from './StepFormDialog' +export { StepFormDialogContent } from './StepFormDialogContent' diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx new file mode 100644 index 0000000000..5de6f2b8bf --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx @@ -0,0 +1,42 @@ +import { Children, ReactNode, useCallback, useMemo, useRef, useState, useTransition } from 'react' + +import { FocusTrapRef } from '../FocusTrap' + +export const useStepDialog = (children: ReactNode) => { + const [activeStep, setActiveStep] = useState(0) + const focusTrapRef = useRef(null) + const [_, startTransition] = useTransition() + + const childrenSteps = useMemo(() => { + const steps: ReactNode[] = [] + Children.map(children, (child) => { + steps.push(child) + }) + return steps + }, [children]) + + const onSubmit = useCallback(() => { + setActiveStep(0) + }, []) + + const onNextSteps = useCallback(() => { + focusTrapRef.current?.focus() + startTransition(() => setActiveStep((pre) => pre + 1)) + }, []) + + const onBackSteps = useCallback(() => { + if (activeStep > 0) { + focusTrapRef.current?.focus() + setActiveStep((pre) => pre - 1) + } + }, [activeStep]) + + return { + focusTrapRef, + activeStep, + childrenSteps, + onSubmit, + onNextSteps, + onBackSteps, + } +} From 463ab26af6b7effccc4bb49e39bce8e0cf327792 Mon Sep 17 00:00:00 2001 From: schktjm Date: Fri, 11 Oct 2024 18:44:31 +0900 Subject: [PATCH 04/20] =?UTF-8?q?feat:=20FormDialog=20=E7=94=A8storybook?= =?UTF-8?q?=E3=81=AE=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Dialog/FormDialog.stories.tsx | 275 ++++++++++++++++++ .../smarthr-ui/src/components/Dialog/index.ts | 1 + 2 files changed, 276 insertions(+) create mode 100644 packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx diff --git a/packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx b/packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx new file mode 100644 index 0000000000..e1d7a15d4e --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx @@ -0,0 +1,275 @@ +import { action } from '@storybook/addon-actions' +import { StoryFn } from '@storybook/react' +import React, { ComponentProps, useRef, useState } from 'react' +import styled from 'styled-components' + +import { Button } from '../Button' +import { CheckBox } from '../CheckBox' +import { Fieldset } from '../Fieldset' +import { FormControl } from '../FormControl' +import { Input } from '../Input' +import { Cluster, Stack } from '../Layout' +import { RadioButton } from '../RadioButton' + +import { StepFormDialog } from './StepFormDialog' + +import { ActionDialog, ActionDialogContent, DialogTrigger, FormDialog } from '.' + +export default { + title: 'Dialog(ダイアログ)/FormDialog', + component: FormDialog, + subcomponents: { + DialogTrigger, + ActionDialogContent, + }, + parameters: { + docs: { + source: { + type: 'code', + }, + story: { + inline: false, + iframeHeight: '500px', + }, + }, + withTheming: true, + }, +} + +export const Default: StoryFn = () => { + const [openedDialog, setOpenedDialog] = useState<'normal' | 'opened' | null>(null) + const [value, setValue] = React.useState('Apple') + const [responseMessage, setResponseMessage] = + useState['responseMessage']>() + const openedFocusRef = useRef(null) + const onClickClose = () => { + setOpenedDialog(null) + setResponseMessage(undefined) + } + const onChange = (e: React.ChangeEvent) => setValue(e.currentTarget.name) + + return ( + + + `cancel.(${txt})` }} + onSubmit={(closeDialog, e) => { + action('executed')() + console.log('event', e) + setResponseMessage(undefined) + closeDialog() + }} + onClickClose={onClickClose} + responseMessage={responseMessage} + id="dialog-form" + data-test="form-dialog-content" + width="40em" + subActionArea={} + > + +
+ +
  • + + Apple + +
  • +
  • + + Orange + +
  • +
  • + + Grape + +
  • +
    +
    + +

    切り替えボタン:

    + + + +
    +
    +
    + + {openedDialog === 'opened' && ( + { + action('execute')() + closeDialog() + }} + onClickClose={onClickClose} + decorators={{ closeButtonLabel: (txt) => `close.(${txt})` }} + firstFocusTarget={openedFocusRef} + data-test="opened-form-dialog" + > + + isOpen=true の状態で DOM に投入した場合のダイアログ + + } + > + + + + )} +
    + ) +} + +Default.parameters = { + docs: { + description: { + story: '`ActionDialog` includes an action button that used for submitting, etc.', + }, + }, +} + +const RadioListCluster = styled(Cluster).attrs({ gap: 1.25 })` + list-style: none; +` + +export const Form_Dialog_With_Step: StoryFn = () => { + const [openedDialog, setOpenedDialog] = useState<'normal' | 'opened' | null>(null) + const [value, setValue] = React.useState('Apple') + const [responseMessage, setResponseMessage] = + useState['responseMessage']>() + const onClickClose = () => { + setOpenedDialog(null) + setResponseMessage(undefined) + } + const onChange = (e: React.ChangeEvent) => setValue(e.currentTarget.name) + + return ( + + + {/* // eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} + '閉じる', nextButtonLabel: () => 'Next' }} + onSubmit={(closeDialog) => { + action('executed')() + setResponseMessage(undefined) + closeDialog() + }} + onClickClose={onClickClose} + responseMessage={responseMessage} + id="dialog-form" + data-test="form-dialog-content" + width="40em" + > +
    + +
  • + + Apple + +
  • +
  • + + Orange + +
  • +
  • + + Grape + +
  • +
    +
    + + + +
    +
      +
    • + CheckBox +
    • + +
    • + + CheckBox / error + +
    • + +
    • + + CheckBox / disabled + +
    • +
    +
    +
    +
    + ) +} + +Form_Dialog_With_Step.parameters = { + docs: { + description: { + story: '`FormDialog with step` is a form dialog that can be divided into multiple steps.', + }, + }, +} diff --git a/packages/smarthr-ui/src/components/Dialog/index.ts b/packages/smarthr-ui/src/components/Dialog/index.ts index 71b9717d0b..b0bc0b68bc 100644 --- a/packages/smarthr-ui/src/components/Dialog/index.ts +++ b/packages/smarthr-ui/src/components/Dialog/index.ts @@ -3,6 +3,7 @@ export { MessageDialog, MessageDialogContent } from './MessageDialog' export { ActionDialog, ActionDialogContent } from './ActionDialog' export { ActionDialogWithTrigger } from './ActionDialogWithTrigger' export { FormDialog, FormDialogContent } from './FormDialog' +export { StepFormDialog, StepFormDialogContent } from './StepFormDialog' export { DialogWrapper } from './DialogWrapper' export { DialogTrigger } from './DialogTrigger' export { DialogContent } from './DialogContent' From f78c2831f29d1c9c033eb3b08ac3d429c816dd7d Mon Sep 17 00:00:00 2001 From: schktjm Date: Tue, 15 Oct 2024 16:18:24 +0900 Subject: [PATCH 05/20] =?UTF-8?q?refactor:=20FormDialog=20=E3=81=A8?= =?UTF-8?q?=E5=88=A5=E6=A6=82=E5=BF=B5=E3=81=AA=E3=81=9F=E3=82=81=20story?= =?UTF-8?q?=20=E3=81=AE=E5=90=8D=E7=A7=B0=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Dialog/FormDialog.stories.tsx | 275 ------------------ .../Dialog/StepFormDialog.stories.tsx | 140 +++++++++ 2 files changed, 140 insertions(+), 275 deletions(-) delete mode 100644 packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx diff --git a/packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx b/packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx deleted file mode 100644 index e1d7a15d4e..0000000000 --- a/packages/smarthr-ui/src/components/Dialog/FormDialog.stories.tsx +++ /dev/null @@ -1,275 +0,0 @@ -import { action } from '@storybook/addon-actions' -import { StoryFn } from '@storybook/react' -import React, { ComponentProps, useRef, useState } from 'react' -import styled from 'styled-components' - -import { Button } from '../Button' -import { CheckBox } from '../CheckBox' -import { Fieldset } from '../Fieldset' -import { FormControl } from '../FormControl' -import { Input } from '../Input' -import { Cluster, Stack } from '../Layout' -import { RadioButton } from '../RadioButton' - -import { StepFormDialog } from './StepFormDialog' - -import { ActionDialog, ActionDialogContent, DialogTrigger, FormDialog } from '.' - -export default { - title: 'Dialog(ダイアログ)/FormDialog', - component: FormDialog, - subcomponents: { - DialogTrigger, - ActionDialogContent, - }, - parameters: { - docs: { - source: { - type: 'code', - }, - story: { - inline: false, - iframeHeight: '500px', - }, - }, - withTheming: true, - }, -} - -export const Default: StoryFn = () => { - const [openedDialog, setOpenedDialog] = useState<'normal' | 'opened' | null>(null) - const [value, setValue] = React.useState('Apple') - const [responseMessage, setResponseMessage] = - useState['responseMessage']>() - const openedFocusRef = useRef(null) - const onClickClose = () => { - setOpenedDialog(null) - setResponseMessage(undefined) - } - const onChange = (e: React.ChangeEvent) => setValue(e.currentTarget.name) - - return ( - - - `cancel.(${txt})` }} - onSubmit={(closeDialog, e) => { - action('executed')() - console.log('event', e) - setResponseMessage(undefined) - closeDialog() - }} - onClickClose={onClickClose} - responseMessage={responseMessage} - id="dialog-form" - data-test="form-dialog-content" - width="40em" - subActionArea={} - > - -
    - -
  • - - Apple - -
  • -
  • - - Orange - -
  • -
  • - - Grape - -
  • -
    -
    - -

    切り替えボタン:

    - - - -
    -
    -
    - - {openedDialog === 'opened' && ( - { - action('execute')() - closeDialog() - }} - onClickClose={onClickClose} - decorators={{ closeButtonLabel: (txt) => `close.(${txt})` }} - firstFocusTarget={openedFocusRef} - data-test="opened-form-dialog" - > - - isOpen=true の状態で DOM に投入した場合のダイアログ - - } - > - - - - )} -
    - ) -} - -Default.parameters = { - docs: { - description: { - story: '`ActionDialog` includes an action button that used for submitting, etc.', - }, - }, -} - -const RadioListCluster = styled(Cluster).attrs({ gap: 1.25 })` - list-style: none; -` - -export const Form_Dialog_With_Step: StoryFn = () => { - const [openedDialog, setOpenedDialog] = useState<'normal' | 'opened' | null>(null) - const [value, setValue] = React.useState('Apple') - const [responseMessage, setResponseMessage] = - useState['responseMessage']>() - const onClickClose = () => { - setOpenedDialog(null) - setResponseMessage(undefined) - } - const onChange = (e: React.ChangeEvent) => setValue(e.currentTarget.name) - - return ( - - - {/* // eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} - '閉じる', nextButtonLabel: () => 'Next' }} - onSubmit={(closeDialog) => { - action('executed')() - setResponseMessage(undefined) - closeDialog() - }} - onClickClose={onClickClose} - responseMessage={responseMessage} - id="dialog-form" - data-test="form-dialog-content" - width="40em" - > -
    - -
  • - - Apple - -
  • -
  • - - Orange - -
  • -
  • - - Grape - -
  • -
    -
    - - - -
    -
      -
    • - CheckBox -
    • - -
    • - - CheckBox / error - -
    • - -
    • - - CheckBox / disabled - -
    • -
    -
    -
    -
    - ) -} - -Form_Dialog_With_Step.parameters = { - docs: { - description: { - story: '`FormDialog with step` is a form dialog that can be divided into multiple steps.', - }, - }, -} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx new file mode 100644 index 0000000000..469e897995 --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx @@ -0,0 +1,140 @@ +import { action } from '@storybook/addon-actions' +import { StoryFn } from '@storybook/react' +import React, { ComponentProps, useState } from 'react' +import styled from 'styled-components' + +import { Button } from '../Button' +import { CheckBox } from '../CheckBox' +import { Fieldset } from '../Fieldset' +import { FormControl } from '../FormControl' +import { Input } from '../Input' +import { Cluster } from '../Layout' +import { RadioButton } from '../RadioButton' + +import { StepFormDialog } from './StepFormDialog' + +import { ActionDialog, ActionDialogContent, DialogTrigger } from '.' + +export default { + title: 'Dialog(ダイアログ)/StepFormDialog', + component: StepFormDialog, + subcomponents: { + DialogTrigger, + ActionDialogContent, + }, + parameters: { + docs: { + source: { + type: 'code', + }, + story: { + inline: false, + iframeHeight: '500px', + }, + }, + withTheming: true, + }, +} + +const RadioListCluster = styled(Cluster).attrs({ gap: 1.25 })` + list-style: none; +` + +export const Default: StoryFn = () => { + const [openedDialog, setOpenedDialog] = useState<'normal' | 'opened' | null>(null) + const [value, setValue] = React.useState('Apple') + const [responseMessage, setResponseMessage] = + useState['responseMessage']>() + const onChange = (e: React.ChangeEvent) => setValue(e.currentTarget.name) + + return ( + + + {/* // eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} + '閉じる', nextButtonLabel: () => 'Next' }} + onSubmit={(closeDialog) => { + action('executed')() + setResponseMessage(undefined) + closeDialog() + }} + onClickClose={() => { + action('closed')() + setOpenedDialog(null) + setResponseMessage(undefined) + }} + onClickNext={() => { + action('next')() + }} + onClickBack={() => { + action('back')() + }} + responseMessage={responseMessage} + id="dialog-form" + data-test="form-dialog-content" + width="40em" + > +
    + +
  • + + Apple + +
  • +
  • + + Orange + +
  • +
  • + + Grape + +
  • +
    +
    + + + +
    +
      +
    • + CheckBox +
    • + +
    • + + CheckBox / error + +
    • + +
    • + + CheckBox / disabled + +
    • +
    +
    +
    +
    + ) +} + +Default.parameters = { + docs: { + description: { + story: '`FormDialog with step` is a form dialog that can be divided into multiple steps.', + }, + }, +} From fc89865ed2dc5b7b6fc9d2d20fab90fb1ea43d4d Mon Sep 17 00:00:00 2001 From: schktjm Date: Tue, 15 Oct 2024 16:19:09 +0900 Subject: [PATCH 06/20] =?UTF-8?q?fix:=20remoteTrigger=20=E7=94=A8=E3=82=B3?= =?UTF-8?q?=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=81=AF?= =?UTF-8?q?=E5=BF=85=E9=A0=88=E3=81=A7=E3=81=AF=E3=81=AA=E3=81=84=E3=81=9F?= =?UTF-8?q?=E3=82=81=E4=BD=9C=E3=82=89=E3=81=AA=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StepFormDialog/StepFormDialogContent.tsx | 97 ------------------- .../components/Dialog/StepFormDialog/index.ts | 1 - .../smarthr-ui/src/components/Dialog/index.ts | 2 +- 3 files changed, 1 insertion(+), 99 deletions(-) delete mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx deleted file mode 100644 index a2ad2d7f1a..0000000000 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContent.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { FormEvent, HTMLAttributes, useCallback, useContext, useId } from 'react' - -import { DialogContentInner } from '../DialogContentInner' -import { DialogContext } from '../DialogWrapper' -import { UncontrolledDialogProps } from '../types' -import { useDialogPortal } from '../useDialogPortal' - -import { BaseProps, StepFormDialogContentInner } from './StepFormDialogContentInner' -import { useStepDialog } from './useStep' - -type Props = BaseProps & UncontrolledDialogProps -type ElementProps = Omit, keyof Props> - -export const StepFormDialogContent: React.FC = ({ - children, - title, - contentBgColor, - contentPadding, - submitLabel, - actionTheme, - onSubmit, - actionDisabled = false, - portalParent, - className = '', - decorators, - ...props -}) => { - const { activeStep, childrenSteps, onBackSteps, onNextSteps, focusTrapRef } = - useStepDialog(children) - const { onClickClose, active } = useContext(DialogContext) - const { createPortal } = useDialogPortal(portalParent) - - const handleClickClose = useCallback(() => { - if (!active) { - return - } - onClickClose() - }, [active, onClickClose]) - - const handleSubmitAction = useCallback( - (close: () => void, e: FormEvent) => { - if (!active) { - return - } - - onSubmit(close, e) - }, - [active, onSubmit], - ) - - const handleBackSteps = useCallback(() => { - if (!active) { - return - } - onBackSteps() - }, [active, onBackSteps]) - - const handleNextSteps = useCallback(() => { - if (!active) { - return - } - onNextSteps() - }, [active, onNextSteps]) - - const titleId = useId() - - return createPortal( - - {/* eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} - - {childrenSteps[activeStep]} - - , - ) -} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts index d84663facb..e46a4e3eea 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts @@ -1,2 +1 @@ export { StepFormDialog } from './StepFormDialog' -export { StepFormDialogContent } from './StepFormDialogContent' diff --git a/packages/smarthr-ui/src/components/Dialog/index.ts b/packages/smarthr-ui/src/components/Dialog/index.ts index b0bc0b68bc..2940596a53 100644 --- a/packages/smarthr-ui/src/components/Dialog/index.ts +++ b/packages/smarthr-ui/src/components/Dialog/index.ts @@ -3,7 +3,7 @@ export { MessageDialog, MessageDialogContent } from './MessageDialog' export { ActionDialog, ActionDialogContent } from './ActionDialog' export { ActionDialogWithTrigger } from './ActionDialogWithTrigger' export { FormDialog, FormDialogContent } from './FormDialog' -export { StepFormDialog, StepFormDialogContent } from './StepFormDialog' +export { StepFormDialog } from './StepFormDialog' export { DialogWrapper } from './DialogWrapper' export { DialogTrigger } from './DialogTrigger' export { DialogContent } from './DialogContent' From fa6453dc157b8da1afe7cdcc586eb7385947feb5 Mon Sep 17 00:00:00 2001 From: schktjm Date: Tue, 15 Oct 2024 16:19:46 +0900 Subject: [PATCH 07/20] =?UTF-8?q?feat:=20=E5=88=A9=E7=94=A8=E5=81=B4?= =?UTF-8?q?=E3=81=A7=E6=B8=A1=E3=81=97=E3=81=9F=E9=96=A2=E6=95=B0=E3=82=92?= =?UTF-8?q?=E5=AE=9F=E8=A1=8C=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Dialog/StepFormDialog/StepFormDialog.tsx | 8 ++++++-- .../Dialog/StepFormDialog/StepFormDialogContentInner.tsx | 5 +---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx index a1411d483e..dafd043eaf 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx @@ -25,6 +25,8 @@ export const StepFormDialog: React.FC = ({ submitLabel, onSubmit, onClickClose, + onClickBack, + onClickNext, onPressEscape = onClickClose, responseMessage, actionDisabled = false, @@ -68,15 +70,17 @@ export const StepFormDialog: React.FC = ({ if (!props.isOpen) { return } + onClickBack?.() onBackSteps() - }, [props.isOpen, onBackSteps]) + }, [props.isOpen, onBackSteps, onClickBack]) const handleNextSteps = useCallback(() => { if (!props.isOpen) { return } + onClickNext?.() onNextSteps() - }, [props.isOpen, onNextSteps]) + }, [props.isOpen, onNextSteps, onClickNext]) return createPortal( = ( }) => { const handleSubmitAction = useCallback( (e: FormEvent) => { - console.log('handleSubmitAction', activeStep) e.preventDefault() // HINT: React Potals などで擬似的にformがネストしている場合など、stopPropagationを実行しないと // 親formが意図せずsubmitされてしまう場合がある e.stopPropagation() - console.log('onSubmit', activeStep) onSubmit(onClickClose, e) }, - [activeStep, onSubmit, onClickClose], + [onSubmit, onClickClose], ) const isRequestProcessing = responseMessage && responseMessage.status === 'processing' From a36f26a0d4081177eb6ca107955736fb2fe1f7d3 Mon Sep 17 00:00:00 2001 From: schktjm Date: Tue, 15 Oct 2024 16:42:34 +0900 Subject: [PATCH 08/20] =?UTF-8?q?refactor:=20=E3=82=AF=E3=83=A9=E3=82=B9?= =?UTF-8?q?=E5=90=8D=E8=BF=BD=E5=8A=A0=E3=81=A8=E5=AE=9F=E8=A3=85=E9=A0=86?= =?UTF-8?q?=E3=81=AE=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Dialog/StepFormDialog.stories.tsx | 8 ++++---- .../Dialog/StepFormDialog/StepFormDialogContentInner.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx index 469e897995..fbc15e2d41 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx @@ -36,10 +36,6 @@ export default { }, } -const RadioListCluster = styled(Cluster).attrs({ gap: 1.25 })` - list-style: none; -` - export const Default: StoryFn = () => { const [openedDialog, setOpenedDialog] = useState<'normal' | 'opened' | null>(null) const [value, setValue] = React.useState('Apple') @@ -138,3 +134,7 @@ Default.parameters = { }, }, } + +const RadioListCluster = styled(Cluster).attrs({ gap: 1.25 })` + list-style: none; +` diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx index 3637b55024..c15a1e02ed 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx @@ -109,7 +109,7 @@ export const StepFormDialogContentInner: FC = ( {activeStep > 0 && ( - )} From 394b8841ba20abf0e9563184e74ebc05b262f3b9 Mon Sep 17 00:00:00 2001 From: schktjm Date: Tue, 15 Oct 2024 21:45:48 +0900 Subject: [PATCH 09/20] =?UTF-8?q?feat:=20index=20=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E3=81=AB=E3=82=B3=E3=83=B3=E3=83=9D=E3=83=BC?= =?UTF-8?q?=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/smarthr-ui/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/smarthr-ui/src/index.ts b/packages/smarthr-ui/src/index.ts index b3cd1d4834..5ef99cdbca 100644 --- a/packages/smarthr-ui/src/index.ts +++ b/packages/smarthr-ui/src/index.ts @@ -38,6 +38,7 @@ export { RemoteTriggerActionDialog, RemoteTriggerFormDialog, RemoteTriggerMessageDialog, + StepFormDialog, } from './components/Dialog' export { Pagination } from './components/Pagination' export { RadioButton } from './components/RadioButton' From f04ee151d813a8a8233974da2c735e68c9d753ac Mon Sep 17 00:00:00 2001 From: schktjm Date: Thu, 19 Dec 2024 13:58:54 +0900 Subject: [PATCH 10/20] =?UTF-8?q?feat:=20Step=E3=82=92=E9=A3=9B=E3=81=B0?= =?UTF-8?q?=E3=81=9B=E3=82=8B=E3=82=88=E3=81=86=E3=81=ABid=E3=81=A7?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialog/StepFormDialog.stories.tsx | 116 +++++++++++------- .../Dialog/StepFormDialog/StepFormDialog.tsx | 109 ++++++++-------- .../StepFormDialogContentInner.tsx | 66 +++++++--- .../StepFormDialog/StepFormDialogItem.tsx | 13 ++ .../StepFormDialog/StepFormDialogProvider.tsx | 41 +++++++ .../components/Dialog/StepFormDialog/index.ts | 1 + .../Dialog/StepFormDialog/useStep.tsx | 42 ------- 7 files changed, 223 insertions(+), 165 deletions(-) create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogItem.tsx create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx delete mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx index fbc15e2d41..6e761deddd 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx @@ -11,7 +11,7 @@ import { Input } from '../Input' import { Cluster } from '../Layout' import { RadioButton } from '../RadioButton' -import { StepFormDialog } from './StepFormDialog' +import { StepFormDialog, StepFormDialogItem } from './StepFormDialog' import { ActionDialog, ActionDialogContent, DialogTrigger } from '.' @@ -42,6 +42,14 @@ export const Default: StoryFn = () => { const [responseMessage, setResponseMessage] = useState['responseMessage']>() const onChange = (e: React.ChangeEvent) => setValue(e.currentTarget.name) + const stepOrder = [ + { id: 'a', stepNumber: 1 }, + { + id: 'b', + stepNumber: 2, + }, + { id: 'c', stepNumber: 3 }, + ] return ( @@ -59,69 +67,83 @@ export const Default: StoryFn = () => { title="FormDialog" subtitle="副題" submitLabel="保存" - decorators={{ closeButtonLabel: () => '閉じる', nextButtonLabel: () => 'Next' }} - onSubmit={(closeDialog) => { - action('executed')() + firstStep={stepOrder[0]} + onSubmit={(closeDialog, e, currentStep) => { + action('onSubmit')() setResponseMessage(undefined) - closeDialog() + const currentStepIndex = stepOrder.findIndex((step) => step.id === currentStep.id) + if (currentStepIndex >= 2) { + closeDialog() + } + if (currentStepIndex === 0) { + const grape = e.currentTarget.elements.namedItem('Grape') as HTMLInputElement + if (grape.checked) { + return stepOrder[2] + } + } + return stepOrder.at(currentStepIndex + 1) }} onClickClose={() => { action('closed')() setOpenedDialog(null) setResponseMessage(undefined) }} - onClickNext={() => { - action('next')() - }} onClickBack={() => { action('back')() }} + stepLength={3} responseMessage={responseMessage} id="dialog-form" data-test="form-dialog-content" width="40em" > -
    - -
  • - - Apple - -
  • -
  • - - Orange - -
  • -
  • - - Grape - -
  • -
    -
    - - - -
    -
      -
    • - CheckBox -
    • + +
      + +
    • + + Apple + +
    • +
    • + + Orange + +
    • +
    • + + これを選ぶとステップ2を飛ばして3に進みます + +
    • +
      +
      +
      + + + + + + +
      +
        +
      • + CheckBox +
      • -
      • - - CheckBox / error - -
      • +
      • + + CheckBox / error + +
      • -
      • - - CheckBox / disabled - -
      • -
      -
      +
    • + + CheckBox / disabled + +
    • +
    +
    +
    ) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx index dafd043eaf..64951959bf 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.tsx @@ -1,32 +1,34 @@ -import React, { ComponentProps, FormEvent, useCallback, useId } from 'react' +import React, { ComponentProps, FormEvent, useCallback, useId, useRef } from 'react' import { DialogContentInner } from '../DialogContentInner' -import { DialogProps } from '../types' +import { FocusTrapRef } from '../FocusTrap' +import { DialogProps /** コンテンツなにもないDialogの基本props */ } from '../types' import { useDialogPortal } from '../useDialogPortal' import { StepFormDialogContentInner, StepFormDialogContentInnerProps, } from './StepFormDialogContentInner' -import { useStepDialog } from './useStep' +import { StepFormDialogProvider, type StepItem } from './StepFormDialogProvider' + +type Props = Omit & DialogProps -type Props = Omit & - DialogProps type ElementProps = Omit, keyof Props> export const StepFormDialog: React.FC = ({ children, title, subtitle, + stepLength, titleTag, contentBgColor, contentPadding, actionTheme, submitLabel, + firstStep, onSubmit, onClickClose, onClickBack, - onClickNext, onPressEscape = onClickClose, responseMessage, actionDisabled = false, @@ -39,80 +41,67 @@ export const StepFormDialog: React.FC = ({ }) => { const { createPortal } = useDialogPortal(portalParent, id) const titleId = useId() - const { - activeStep, - childrenSteps, - onSubmit: onSubmitStep, - onBackSteps, - onNextSteps, - focusTrapRef, - } = useStepDialog(children) + const focusTrapRef = useRef(null) const handleClickClose = useCallback(() => { if (!props.isOpen) { return } + focusTrapRef.current?.focus() onClickClose() }, [onClickClose, props.isOpen]) const handleSubmitAction = useCallback( - (close: () => void, e: FormEvent) => { + (close: () => void, e: FormEvent, currentStep: StepItem) => { if (!props.isOpen) { - return + return undefined } - - onSubmitStep() - onSubmit(close, e) + focusTrapRef.current?.focus() + return onSubmit(close, e, currentStep) }, - [onSubmit, onSubmitStep, props.isOpen], + [onSubmit, props.isOpen], ) + const handleBackSteps = useCallback(() => { if (!props.isOpen) { return } + focusTrapRef.current?.focus() onClickBack?.() - onBackSteps() - }, [props.isOpen, onBackSteps, onClickBack]) - - const handleNextSteps = useCallback(() => { - if (!props.isOpen) { - return - } - onClickNext?.() - onNextSteps() - }, [props.isOpen, onNextSteps, onClickNext]) + }, [props.isOpen, onClickBack]) return createPortal( - - {/* eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} - + - {childrenSteps[activeStep]} - - , + {/* eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} + + {children} + +
    + , ) } diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx index c15a1e02ed..8ad594e0ae 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx @@ -4,6 +4,8 @@ import React, { type PropsWithChildren, type ReactNode, useCallback, + useContext, + useMemo, } from 'react' import { Button } from '../../Button' @@ -14,6 +16,12 @@ import { DialogBody, Props as DialogBodyProps } from '../DialogBody' import { DialogHeader, type Props as DialogHeaderProps } from '../DialogHeader' import { dialogContentInner } from '../dialogInnerStyle' +import { + StepFormDialogActionContext, + StepFormDialogContext, + StepItem, +} from './StepFormDialogProvider' + import type { DecoratorsType, ResponseMessageType } from '../../../types' export type BaseProps = PropsWithChildren< @@ -26,8 +34,14 @@ export type BaseProps = PropsWithChildren< /** * アクションボタンをクリックした時に発火するコールバック関数 * @param closeDialog ダイアログを閉じる関数 + * @param currentStep onSubmitが発火した時のステップ + * @returns 次のステップに遷移する場合は次のステップ、遷移しない場合はundefined */ - onSubmit: (closeDialog: () => void, e: FormEvent) => void + onSubmit: ( + closeDialog: () => void, + e: FormEvent, + currentStep: StepItem, + ) => StepItem | undefined /** アクションボタンを無効にするかどうか */ actionDisabled?: boolean /** 閉じるボタンを無効にするかどうか */ @@ -38,11 +52,10 @@ export type BaseProps = PropsWithChildren< > export type StepFormDialogContentInnerProps = BaseProps & { + firstStep: StepItem onClickClose: () => void responseMessage?: ResponseMessageType - activeStep: number stepLength: number - onClickNext?: () => void onClickBack?: () => void } @@ -55,39 +68,62 @@ export const StepFormDialogContentInner: FC = ( title, titleId, subtitle, - titleTag, contentBgColor, contentPadding, submitLabel, actionTheme = 'primary', - activeStep, stepLength, + firstStep, onSubmit, onClickClose, responseMessage, actionDisabled = false, closeDisabled, decorators, - onClickNext, onClickBack, }) => { + const { currentStep, stepQueue } = useContext(StepFormDialogContext) + const { setCurrentStep } = useContext(StepFormDialogActionContext) + const activeStep = useMemo(() => currentStep?.stepNumber ?? 1, [currentStep]) + + const handleCloseAction = useCallback(() => { + onClickClose() + setTimeout(() => { + // HINT: ダイアログが閉じるtransitionが完了してから初期化をしている + stepQueue.current = [firstStep] + setCurrentStep(firstStep) + }, 300) + }, [firstStep, stepQueue, setCurrentStep, onClickClose]) + const handleSubmitAction = useCallback( (e: FormEvent) => { e.preventDefault() // HINT: React Potals などで擬似的にformがネストしている場合など、stopPropagationを実行しないと // 親formが意図せずsubmitされてしまう場合がある e.stopPropagation() - onSubmit(onClickClose, e) + + const next = onSubmit(handleCloseAction, e, currentStep) + if (!next) { + return + } + setCurrentStep(next) }, - [onSubmit, onClickClose], + [currentStep, onSubmit, setCurrentStep, handleCloseAction], ) + const handleBackAction = useCallback(() => { + if (onClickBack) { + onClickBack() + } + const prev = stepQueue.current.pop() ?? firstStep + setCurrentStep(prev) + }, [firstStep, stepQueue, onClickBack, setCurrentStep]) const isRequestProcessing = responseMessage && responseMessage.status === 'processing' const { wrapper, actionArea, buttonArea, message } = dialogContentInner() const actionText = - activeStep === stepLength - 1 + activeStep === stepLength ? submitLabel : decorators?.nextButtonLabel?.(NEXT_BUTTON_LABEL) || NEXT_BUTTON_LABEL @@ -98,9 +134,8 @@ export const StepFormDialogContentInner: FC = ( {/* eslint-disable-next-line smarthr/best-practice-for-layouts */} @@ -108,26 +143,25 @@ export const StepFormDialogContentInner: FC = ( - {activeStep > 0 && ( - )} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogItem.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogItem.tsx new file mode 100644 index 0000000000..1346247669 --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogItem.tsx @@ -0,0 +1,13 @@ +import { PropsWithChildren, useContext } from 'react' + +import { StepFormDialogContext, type StepItem } from './StepFormDialogProvider' + +type Props = PropsWithChildren + +export const StepFormDialogItem: React.FC = ({ children, id }) => { + const { currentStep } = useContext(StepFormDialogContext) + + if (currentStep.id !== id) return null + + return children +} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx new file mode 100644 index 0000000000..81affd2651 --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx @@ -0,0 +1,41 @@ +import React, { ReactNode, createContext, useRef, useState } from 'react' + +export type StepItem = { + /** StepのID */ + id: string + /** 何ステップ目か */ + stepNumber: number +} + +type StepFormDialogContextType = { + stepQueue: React.MutableRefObject + currentStep: StepItem +} +export const StepFormDialogContext = createContext({ + stepQueue: { current: [] }, + currentStep: { id: '', stepNumber: 0 }, +}) + +type StepFormDialogActionType = { + setCurrentStep: (step: StepItem) => void +} +export const StepFormDialogActionContext = createContext({ + setCurrentStep: () => {}, +}) + +type Props = { + children: ReactNode + firstStep: StepItem +} +export const StepFormDialogProvider: React.FC = ({ children, firstStep }) => { + const [currentStep, setCurrentStep] = useState(firstStep) + const stepQueue = useRef([firstStep]) + + return ( + + + {children} + + + ) +} diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts index e46a4e3eea..1035b1ec7d 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/index.ts @@ -1 +1,2 @@ export { StepFormDialog } from './StepFormDialog' +export { StepFormDialogItem } from './StepFormDialogItem' diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx deleted file mode 100644 index 5de6f2b8bf..0000000000 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/useStep.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Children, ReactNode, useCallback, useMemo, useRef, useState, useTransition } from 'react' - -import { FocusTrapRef } from '../FocusTrap' - -export const useStepDialog = (children: ReactNode) => { - const [activeStep, setActiveStep] = useState(0) - const focusTrapRef = useRef(null) - const [_, startTransition] = useTransition() - - const childrenSteps = useMemo(() => { - const steps: ReactNode[] = [] - Children.map(children, (child) => { - steps.push(child) - }) - return steps - }, [children]) - - const onSubmit = useCallback(() => { - setActiveStep(0) - }, []) - - const onNextSteps = useCallback(() => { - focusTrapRef.current?.focus() - startTransition(() => setActiveStep((pre) => pre + 1)) - }, []) - - const onBackSteps = useCallback(() => { - if (activeStep > 0) { - focusTrapRef.current?.focus() - setActiveStep((pre) => pre - 1) - } - }, [activeStep]) - - return { - focusTrapRef, - activeStep, - childrenSteps, - onSubmit, - onNextSteps, - onBackSteps, - } -} From 27a4c223505236db6d1fa1566446a19432ae035d Mon Sep 17 00:00:00 2001 From: schktjm Date: Thu, 19 Dec 2024 14:42:27 +0900 Subject: [PATCH 11/20] =?UTF-8?q?feat:=20storybook=E3=81=AE=E3=82=B9?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=AB=E3=82=92=E6=95=B4=E3=81=88=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialog/StepFormDialog.stories.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx index 6e761deddd..03f2405de8 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog.stories.tsx @@ -64,23 +64,22 @@ export const Default: StoryFn = () => { {/* // eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} { action('onSubmit')() setResponseMessage(undefined) - const currentStepIndex = stepOrder.findIndex((step) => step.id === currentStep.id) - if (currentStepIndex >= 2) { + if (currentStep.id === stepOrder[2].id) { closeDialog() } - if (currentStepIndex === 0) { - const grape = e.currentTarget.elements.namedItem('Grape') as HTMLInputElement - if (grape.checked) { + if (currentStep.id === stepOrder[0].id) { + const skip = e.currentTarget.elements.namedItem('skip') as HTMLInputElement + if (skip.checked) { return stepOrder[2] } } + const currentStepIndex = stepOrder.findIndex((step) => step.id === currentStep.id) return stepOrder.at(currentStepIndex + 1) }} onClickClose={() => { @@ -111,7 +110,7 @@ export const Default: StoryFn = () => {
  • - + これを選ぶとステップ2を飛ばして3に進みます
  • @@ -152,7 +151,7 @@ export const Default: StoryFn = () => { Default.parameters = { docs: { description: { - story: '`FormDialog with step` is a form dialog that can be divided into multiple steps.', + story: '`StepFormDialog` is a form dialog that can be divided into multiple steps.', }, }, } From dfeba97d0c303fc2ab7bf09124d1c123076021bf Mon Sep 17 00:00:00 2001 From: schktjm Date: Thu, 19 Dec 2024 14:58:23 +0900 Subject: [PATCH 12/20] =?UTF-8?q?feat:=20=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialog/StepFormDialog/StepFormDialogContentInner.tsx | 6 +++++- packages/smarthr-ui/src/components/Dialog/index.ts | 2 +- packages/smarthr-ui/src/index.ts | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx index 8ad594e0ae..e8d55e2c88 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx @@ -144,7 +144,11 @@ export const StepFormDialogContentInner: FC = ( {activeStep > 1 && ( - )} diff --git a/packages/smarthr-ui/src/components/Dialog/index.ts b/packages/smarthr-ui/src/components/Dialog/index.ts index 2940596a53..cc2054139b 100644 --- a/packages/smarthr-ui/src/components/Dialog/index.ts +++ b/packages/smarthr-ui/src/components/Dialog/index.ts @@ -3,7 +3,7 @@ export { MessageDialog, MessageDialogContent } from './MessageDialog' export { ActionDialog, ActionDialogContent } from './ActionDialog' export { ActionDialogWithTrigger } from './ActionDialogWithTrigger' export { FormDialog, FormDialogContent } from './FormDialog' -export { StepFormDialog } from './StepFormDialog' +export { StepFormDialog, StepFormDialogItem } from './StepFormDialog' export { DialogWrapper } from './DialogWrapper' export { DialogTrigger } from './DialogTrigger' export { DialogContent } from './DialogContent' diff --git a/packages/smarthr-ui/src/index.ts b/packages/smarthr-ui/src/index.ts index 5ef99cdbca..33c70f5c23 100644 --- a/packages/smarthr-ui/src/index.ts +++ b/packages/smarthr-ui/src/index.ts @@ -39,6 +39,7 @@ export { RemoteTriggerFormDialog, RemoteTriggerMessageDialog, StepFormDialog, + StepFormDialogItem, } from './components/Dialog' export { Pagination } from './components/Pagination' export { RadioButton } from './components/RadioButton' From 6e41e434828b1ce5557d221339d61a687a704955 Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 15:39:22 +0900 Subject: [PATCH 13/20] =?UTF-8?q?fix:=20=E6=88=BB=E3=82=8B=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialog/StepFormDialog/StepFormDialogContentInner.tsx | 3 ++- .../Dialog/StepFormDialog/StepFormDialogProvider.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx index e8d55e2c88..a164900e85 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogContentInner.tsx @@ -90,7 +90,7 @@ export const StepFormDialogContentInner: FC = ( onClickClose() setTimeout(() => { // HINT: ダイアログが閉じるtransitionが完了してから初期化をしている - stepQueue.current = [firstStep] + stepQueue.current = [] setCurrentStep(firstStep) }, 300) }, [firstStep, stepQueue, setCurrentStep, onClickClose]) @@ -102,6 +102,7 @@ export const StepFormDialogContentInner: FC = ( // 親formが意図せずsubmitされてしまう場合がある e.stopPropagation() + stepQueue.current.push(currentStep) const next = onSubmit(handleCloseAction, e, currentStep) if (!next) { return diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx index 81affd2651..03ccaaea74 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialogProvider.tsx @@ -29,7 +29,7 @@ type Props = { } export const StepFormDialogProvider: React.FC = ({ children, firstStep }) => { const [currentStep, setCurrentStep] = useState(firstStep) - const stepQueue = useRef([firstStep]) + const stepQueue = useRef([]) return ( From ffaf5fa548bf787db386b45e5e6a52e6adf60d5b Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 16:46:38 +0900 Subject: [PATCH 14/20] =?UTF-8?q?feat:=20StepFormDialog=E3=81=AE=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=AE=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StepFormDialog/StepFormDialog.test.tsx | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx new file mode 100644 index 0000000000..d18de38426 --- /dev/null +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx @@ -0,0 +1,96 @@ +import { userEvent } from '@storybook/test' +import { act, render, screen, waitFor } from '@testing-library/react' +import React, { useState } from 'react' + +import { Button } from '../../Button' +import { Text } from '../../Text' + +import { StepFormDialog } from './StepFormDialog' +import { StepFormDialogItem } from './StepFormDialogItem' + +describe('StepFormDialog', () => { + const DialogTemplate: React.FC = () => { + const [isOpen, setIsOpen] = useState(false) + const steps = [ + { id: 'a', stepNumber: 1 }, + { id: 'b', stepNumber: 2 }, + ] + return ( + <> + + { + closeDialog() + const nextStep = steps.find((step) => step.stepNumber === currentStep.stepNumber + 1) + return nextStep + }} + onClickClose={() => { + setIsOpen(false) + }} + > + + Step1 + + + Step2 + + + + ) + } + it('ダイアログが開閉できること', async () => { + render() + + expect(screen.queryByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeNull() + await act(() => userEvent.tab()) + await act(() => userEvent.keyboard('{enter}')) + expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() + + await act(() => userEvent.click(screen.getByRole('button', { name: 'キャンセル' }))) + await act(() => userEvent.keyboard('{ }')) + await waitFor( + () => { + expect(screen.queryByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeNull() + }, + { timeout: 1000 }, + ) + + // ダイアログを閉じた後、トリガがフォーカスされることを確認 + expect(screen.getByRole('button', { name: 'StepFormDialog' })).toHaveFocus() + }) + + it('ダイアログのステップの移動ができること', async () => { + render() + + await act(() => userEvent.tab()) + await act(() => userEvent.keyboard('{enter}')) + expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() + + await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) + await act(() => userEvent.keyboard('{ }')) + expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() + + await act(() => userEvent.click(screen.getByRole('button', { name: '戻る' }))) + await act(() => userEvent.keyboard('{ }')) + expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() + + await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) + await act(() => userEvent.keyboard('{ }')) + await act(() => userEvent.click(screen.getByRole('button', { name: '保存' }))) + await act(() => userEvent.keyboard('{ }')) + await waitFor( + () => { + expect(screen.queryByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeNull() + }, + { timeout: 1000 }, + ) + + // ダイアログを閉じた後、トリガがフォーカスされることを確認 + expect(screen.getByRole('button', { name: 'StepFormDialog' })).toHaveFocus() + }) +}) From ca7d76c3fdda8b024360d3b896116a0dc89e2cc3 Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 16:51:06 +0900 Subject: [PATCH 15/20] fix: test --- .../components/Dialog/StepFormDialog/StepFormDialog.test.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx index d18de38426..87c0c8f901 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx @@ -81,6 +81,8 @@ describe('StepFormDialog', () => { await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) await act(() => userEvent.keyboard('{ }')) + expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() + await act(() => userEvent.click(screen.getByRole('button', { name: '保存' }))) await act(() => userEvent.keyboard('{ }')) await waitFor( From 4aa8b69e2299d9c22a1caae488ef3fd7ef3ab374 Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 17:08:59 +0900 Subject: [PATCH 16/20] fix: test --- .../components/Dialog/StepFormDialog/StepFormDialog.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx index 87c0c8f901..25015f479b 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx @@ -80,7 +80,9 @@ describe('StepFormDialog', () => { expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) - await act(() => userEvent.keyboard('{ }')) + await act(async () => { + await userEvent.keyboard('{ }') + }) expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '保存' }))) From 872e9a0f5c50cedba4762a11e7c20b11c7c49d5d Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 17:36:48 +0900 Subject: [PATCH 17/20] =?UTF-8?q?fix:=20=E5=95=8F=E9=A1=8C=E3=81=AE?= =?UTF-8?q?=E7=AE=87=E6=89=80=E3=81=ABasync/await=E3=82=92=E3=81=A4?= =?UTF-8?q?=E3=81=91=E3=81=A6=E3=81=BF=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Dialog/StepFormDialog/StepFormDialog.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx index 25015f479b..46d1764cf8 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx @@ -86,7 +86,9 @@ describe('StepFormDialog', () => { expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '保存' }))) - await act(() => userEvent.keyboard('{ }')) + await act(async () => { + await userEvent.keyboard('{ }') + }) await waitFor( () => { expect(screen.queryByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeNull() From a2fa3a28ce8a5c4ae1bd2077beac7e0e71d65a68 Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 17:50:14 +0900 Subject: [PATCH 18/20] fix: test --- .../Dialog/StepFormDialog/StepFormDialog.test.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx index 46d1764cf8..54c0e8052a 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx @@ -52,7 +52,6 @@ describe('StepFormDialog', () => { expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: 'キャンセル' }))) - await act(() => userEvent.keyboard('{ }')) await waitFor( () => { expect(screen.queryByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeNull() @@ -72,23 +71,15 @@ describe('StepFormDialog', () => { expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) - await act(() => userEvent.keyboard('{ }')) expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '戻る' }))) - await act(() => userEvent.keyboard('{ }')) expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) - await act(async () => { - await userEvent.keyboard('{ }') - }) expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '保存' }))) - await act(async () => { - await userEvent.keyboard('{ }') - }) await waitFor( () => { expect(screen.queryByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeNull() From b9c570e1aa3ef3222aa9f6dfb8286b41622682d8 Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 18:00:25 +0900 Subject: [PATCH 19/20] fix: test --- .../components/Dialog/StepFormDialog/StepFormDialog.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx index 54c0e8052a..a363d4cc87 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx @@ -76,7 +76,9 @@ describe('StepFormDialog', () => { await act(() => userEvent.click(screen.getByRole('button', { name: '戻る' }))) expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() - await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) + await act(async () => { + await userEvent.click(screen.getByRole('button', { name: '次へ' })) + }) expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() await act(() => userEvent.click(screen.getByRole('button', { name: '保存' }))) From f2622cf88fd181d2092fc8114ca7d1896b7af8f3 Mon Sep 17 00:00:00 2001 From: schktjm Date: Mon, 23 Dec 2024 18:04:51 +0900 Subject: [PATCH 20/20] =?UTF-8?q?fix:=20assertion=E6=B6=88=E3=81=97?= =?UTF-8?q?=E3=81=9F=E3=82=89=E5=8B=95=E3=81=8F=E3=81=AE=E3=81=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialog/StepFormDialog/StepFormDialog.test.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx index a363d4cc87..ee7d396218 100644 --- a/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx +++ b/packages/smarthr-ui/src/components/Dialog/StepFormDialog/StepFormDialog.test.tsx @@ -76,11 +76,7 @@ describe('StepFormDialog', () => { await act(() => userEvent.click(screen.getByRole('button', { name: '戻る' }))) expect(screen.getByRole('dialog', { name: 'StepFormDialog 1/2' })).toBeVisible() - await act(async () => { - await userEvent.click(screen.getByRole('button', { name: '次へ' })) - }) - expect(screen.getByRole('dialog', { name: 'StepFormDialog 2/2' })).toBeVisible() - + await act(() => userEvent.click(screen.getByRole('button', { name: '次へ' }))) await act(() => userEvent.click(screen.getByRole('button', { name: '保存' }))) await waitFor( () => {