-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Step つき FormDialog の実装 #4972
Changes from 3 commits
afe7048
13cda5f
bd4424e
a812f15
653fd5a
0c6e6ef
846cd41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ import React, { ComponentProps, FormEvent, useCallback, useId } from 'react' | |
import { DialogContentInner } from '../DialogContentInner' | ||
import { DialogProps } from '../types' | ||
import { useDialogPortal } from '../useDialogPortal' | ||
import { useStepDialog } from '../useStepDialog' | ||
|
||
import { FormDialogContentInner, FormDialogContentInnerProps } from './FormDialogContentInner' | ||
|
||
|
@@ -29,10 +30,20 @@ export const FormDialog: React.FC<Props & ElementProps> = ({ | |
portalParent, | ||
decorators, | ||
id, | ||
steppable, | ||
...props | ||
}) => { | ||
const { createPortal } = useDialogPortal(portalParent, id) | ||
const titleId = useId() | ||
const { | ||
titleSuffix, | ||
focusTrapRef, | ||
childrenSteps, | ||
activeStep, | ||
getActionText, | ||
handleNextSteps, | ||
renderSubActionButton, | ||
} = useStepDialog(children) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nits]
<FormDialog>
// これは一個目のステップ
<Hoge />
// これは二個目のステップ
<Fuga />
</FormDialog>
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. レビューありがとうございますー!全然アリだと思います! 定例で相談したとき、簡単に書けそうだったら FormDialog に hasStep 生やす程度でできたら嬉しいということを聞いたんですが、もやポイントに書いた通り There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ちょっとPR別で作ってみます! |
||
|
||
const handleClickClose = useCallback(() => { | ||
if (!props.isOpen) { | ||
|
@@ -47,9 +58,13 @@ export const FormDialog: React.FC<Props & ElementProps> = ({ | |
return | ||
} | ||
|
||
onSubmit(close, e) | ||
if (steppable) { | ||
handleNextSteps() | ||
} | ||
|
||
onSubmit(close, e, activeStep) | ||
}, | ||
[onSubmit, props.isOpen], | ||
[onSubmit, props.isOpen, steppable, handleNextSteps, activeStep], | ||
) | ||
|
||
return createPortal( | ||
|
@@ -58,26 +73,28 @@ export const FormDialog: React.FC<Props & ElementProps> = ({ | |
ariaLabelledby={titleId} | ||
className={className} | ||
onPressEscape={onPressEscape} | ||
focusTrapRef={focusTrapRef} | ||
> | ||
{/* eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */} | ||
<FormDialogContentInner | ||
title={title} | ||
title={steppable ? `${title}${titleSuffix}` : title} | ||
titleId={titleId} | ||
subtitle={subtitle} | ||
titleTag={titleTag} | ||
contentBgColor={contentBgColor} | ||
contentPadding={contentPadding} | ||
actionText={actionText} | ||
actionText={steppable ? getActionText(actionText) : actionText} | ||
actionTheme={actionTheme} | ||
actionDisabled={actionDisabled} | ||
closeDisabled={closeDisabled} | ||
subActionArea={subActionArea} | ||
subActionArea={steppable ? renderSubActionButton() : subActionArea} | ||
onClickClose={handleClickClose} | ||
onSubmit={handleSubmitAction} | ||
responseMessage={responseMessage} | ||
decorators={decorators} | ||
steppable={steppable} | ||
> | ||
{children} | ||
{steppable ? childrenSteps[activeStep] : children} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. もやポイント2? props 渡す箇所で三項演算子書き過ぎかもなぁと考えています! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. あ、嘘だった。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
</FormDialogContentInner> | ||
</DialogContentInner>, | ||
) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React, { Children, ReactNode, useCallback, useMemo, useRef, useState } from 'react' | ||
|
||
import { Button } from '../Button' | ||
|
||
import { FocusTrapRef } from './FocusTrap' | ||
|
||
const NEXT_BUTTON_LABEL = '次へ' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 聞きたいポイント 次へのラベルは変えることがなさそうと思ったのですが、変更している例があれば教えてほしいです 🙏 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 多言語化などで翻訳する場合に変えるときがあります〜 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. submit のボタンテキストは There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 一旦一番実直な方法で書いてみました! |
||
|
||
export const useStepDialog = (children: ReactNode) => { | ||
const [activeStep, setActiveStep] = useState(0) | ||
const focusTrapRef = useRef<FocusTrapRef>(null) | ||
|
||
const childrenSteps = useMemo(() => { | ||
const steps: ReactNode[] = [] | ||
Children.map(children, (child) => { | ||
steps.push(child) | ||
}) | ||
return steps | ||
}, [children]) | ||
|
||
const getActionText = (submitActionText: ReactNode) => | ||
activeStep < childrenSteps.length - 1 ? NEXT_BUTTON_LABEL : submitActionText | ||
|
||
const handleNextSteps = useCallback(() => { | ||
if (activeStep + 1 === childrenSteps.length) { | ||
setActiveStep(0) | ||
return | ||
} | ||
focusTrapRef.current?.focus() | ||
setActiveStep((pre) => pre + 1) | ||
}, [activeStep, childrenSteps]) | ||
|
||
const handleBackSteps = useCallback(() => { | ||
if (activeStep > 0) { | ||
focusTrapRef.current?.focus() | ||
setActiveStep((pre) => pre - 1) | ||
} | ||
}, [activeStep]) | ||
|
||
const renderSubActionButton = useCallback(() => { | ||
if (activeStep === 0) { | ||
return null | ||
} | ||
return <Button onClick={handleBackSteps}>戻る</Button> | ||
}, [activeStep, handleBackSteps]) | ||
|
||
const titleSuffix = useMemo( | ||
() => ` (${activeStep + 1}/${childrenSteps.length})`, | ||
[activeStep, childrenSteps], | ||
) | ||
|
||
return { | ||
focusTrapRef, | ||
activeStep, | ||
childrenSteps, | ||
titleSuffix, | ||
getActionText, | ||
handleNextSteps, | ||
renderSubActionButton, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
もやポイント1
closeDialog
の実行は FormDialog の使用する側なので、使用する側で最後のページかのチェックをする必要があります!