smarthr-ui
smarthr-ui copied to clipboard
feat: Stepを持つダイアログをキーボードフォーカスしやすく開発しやすくするカスタムフックを作る
Related URL
Overview
useDialogStepsを作成
返り値
type UseDialogStepsResult = [
number, // currentStep
{
setStep: React.Dispatch<React.SetStateAction<number>> // stepをset
nextStep: () => void // 次のstepへ
prevStep: () => void // 前のstepへ
},
() => React.JSX.Element, // ステップ移動したときにフォーカスを当て直すための要素。通常は Dialog の children の最初に配置する
]
アプリケーション側の実装
// useDialogSteps()を実行して必要なものを作る
const [currentStep, { setStep, nextStep, prevStep }, renderFocusTarget] = useDialogSteps()
const dialogContents: DialogContents = {
0: (各ステップごとのDialogのPropsを定義しておく),
1: ...,
2: ...,
}
const dialogContent = dialogContents[currentStep]
return (
<ActionDialog
{...dialogContent}
title={`Stepper Dialog ${currentStep} / 2`}
isOpen={currentStep > 0}
onClickClose={currentStep === 2 ? () => setStep(0) : prevStep}
>
/* childrenの最初で、renderFocusTarget() を実行する。stepが変わったらこの位置に focus がリセットされる */
{renderFocusTarget()}
{dialogContent.children}
</ActionDialog>
)
What I did
Capture
検討している実装方法
- focusTargetRef のような、Dialog に渡すための値を返り値に持つ useDialogSteps を提供する
- メリット
- 実装側が Dialog, ActionDialog 関係なく使える
- デメリット
- ref を Dialog に渡し忘れがありそう
- メリット
-
<StepsDialog>コンポーネントを実装する- メリット
- 実装側で Dialog を持つため渡し忘れがない
- デメリット
- 開発チーム側で独自にダイアログを実装していた場合に対応できない
- メリット
focusTargetRef のような、Dialog に渡すための値を返り値に持つ useDialogSteps を提供する
返り値
type UseDialogStepsResult = [
number, // currentStep
{
setStep: React.Dispatch<React.SetStateAction<number>> // stepをset
nextStep: () => void // 次のstepへ
prevStep: () => void // 前のstepへ
},
refObject<HTMLElement> // ステップ移動したときにフォーカスを当て直すための要素にわたすための ref。Dialog の props として渡す想定
]
アプリケーション側
// useDialogSteps()を実行して必要なものを作る
const [currentStep, { setStep, nextStep, prevStep }, focusTargetRef] = useDialogSteps()
const dialogContents: DialogContents = {
0: (各ステップごとのDialogのPropsを定義しておく),
1: ...,
2: ...,
}
const dialogContent = dialogContents[currentStep]
return (
<ActionDialog
{...dialogContent}
focusTargetRef={focusTargetRef}
title={`Stepper Dialog ${currentStep} / 2`}
isOpen={currentStep > 0}
onClickClose={currentStep === 2 ? () => setStep(0) : prevStep}
>
{dialogContent.children}
</ActionDialog>
)
WIP: <StepsDialog> コンポーネントを実装する
イメージ
type Props = {
onNext: (index: number) => void;
onPrev: (index: number) => void;
children: ReactNode;
defaultIndex: number
} & ActionDialogProps
使う側
const [currentStep, setCurrentStep] = useState(0)
const dialogContents: DialogContents = {
0: (各ステップごとのDialogのPropsを定義しておく),
1: ...,
2: ...,
}
const dialogContent = dialogContents[currentStep]
const onNextStep = (step: number) => {
setCurrentStep(step)
}
return (
<StepsDialog
{...dialogContent}
title={`Stepper Dialog ${currentStep} / 2`}
isOpen={currentStep > 0}
onClickClose={currentStep === 2 ? () => setStep(0) : prevStep}
onNext={onNextStep}
>
{dialogContent.children}
</StepsDialog>
)
https://github.com/kufu/smarthr-ui/pull/5004 で解決予定だと思うのでcloseしちゃいます!