1.0.6 • Published 1 year ago
@locked-dobby/library-react-dialog v1.0.6
Library react dialog
- 해당 라이브러리는 리액트에서 동작하는 dialog 관리 context 입니다.
- 쉽게 confirm, alert, toast 그리고 custom dialog 들을 해당 컨텍스트로 관리 할 수 있습니다.
Installation
$ npm install @locked-dobby/library-react-dialogUsage
모든 컴포넌트가 쓸 수 있도록 DialogContextProvider를 감쌉니다.
<DialogContextProvider>{/* your components */}</DialogContextProvider>Props of DialogContextProvider
experimental_withHistory: 브라우저 뒤로/앞으로 등의 기록 처리를 실험적으로 설정합니다.experimental_withHistoryForwardRestore:experimental_withHistory가 활성화 됬을 때 실험적으로 히스토리 앞으로가기에 대해 dialog 를 복원하는 기능을 설정 합니다.experimental_historySearchParamKey: 브라우저 기록 처리 시 사용되는 키 값을 실험적으로 정의합니다.visibleMultipleDialog: 대화 상자를 스택 형태로 계속 노출할지 아니면 하나의 대화 상자만 노출할지 여부.DialogContainer: 대화 상자를 래핑하는 컨테이너 구성 요소를 제공할 수 있습니다.ToastContainer: 토스트를 포장하는 컨테이너 구성 요소를 제공할 수 있습니다.Alert: 경고를 표시하는 구성요소를 제공합니다. 경고를 표시하려는 경우 필수입니다.Confirm: 확인을 표시하는 컴포넌트를 제공합니다. 확인을 표시하려면 필수입니다.Toast: 토스트를 표시하는 구성 요소를 제공합니다. 토스트를 표시하려는 경우 필수입니다.onInterceptScrollBlocking: 대화상자가 표시될 때 적절한 작업을 처리할 수 있는 이벤트 리스너입니다.
경고, 확인, 알림을 컨텍스트에서 사용할 수 있도록 구성 요소를 제공해야 합니다.
import Confirm from "./component/popup/confirm";
import Alert from "./component/popup/alert";
import Toast from "./component/popup/toast";
<DialogContextProvider
experimental_withHistory={true}
ToastContainer={({ children }: { children: ReactNode }) => {
return <div className="toast-container">{children}</div>;
}}
Confirm={Confirm}
Alert={Alert}
Toast={Toast}>
{/* your components */}
</DialogContextProvider>;- 컨텍스트를 통해
confirm만 사용하는 경우,alert및toast를 제공할 필요가 없습니다.
useDialogContext를 사용하여 dialog를 제어합니다.
const MyComponent = () => {
const { confirm } = useDialogContext();
return (
<>
<button
onClick={async () => {
if (await confirm({ title: "Hello", message: "Select your answer" })) {
console.log("result is true");
} else {
console.log("result is false");
}
}}>
Show confirm
</button>
</>
);
};DialogContextProvider에서 제공하는confirm,alert,showDialog는 Promise를 리턴 합니다.confirm은 Promise,alert은 Promise를 리턴합니다.showDialog는 Promise 반환 값을 원하는 대로 설정할 수 있습니다.
Confirm, alert, and toast 는 어떤식으로 제공 해야 하나요?
useDialogContext로부터confirm,alert,toast를 호출하면,DialogContextProvider에 전달한Confirm,Alert,Toastprops 를 사용합니다.- 전달한 props 들은 컴포넌트로 아래와 같이 직접 구현해서 전달해야 하고, 각 각
AlertProps,ConfirmProps,ToastProps를 사용하거나 상속 받아야 합니다. 예를들어...
import { AlertProps, useDialogActionContext } from "@locked-dobby/library-react-dialog"; const Alert = ({ title, message, textOk = "ok" }: AlertProps) => { const { hide } = useDialogActionContext(); return ( <> <section className="dialog"> <div className="dialog-dimmed" onClick={() => { hide(); }} /> <div className="dialog-content"> <h1>{title}</h1> <h2>{message}</h2> <ul className="horizontal"> <li> <button onClick={() => { hide(); }}> {textOk} </button> </li> </ul> </div> </section> </> ); }; export default Alert;위의 예시에서
DialogContextProvider의해 관리될 dialog 는useDialogActionContext를 사용 해서 상호작용 해야 합니다. 해당 컨텍스트에서hide또는hideAfter등을 통해 dialog를 제어 해야 합니다.hide또는hideAfter를 호출하면서 dialog 가 dismiss 되어야만 promise 가 resolve 됩니다.
Customize dialog
- 직접 dialog를 디자인하고 값을 호출부에 전달 할 수 있습니다.
- 커스텀 dialog로 사용할 컴포넌트를 제작 합니다.
예를들어
type Choice = { id: number; display: string }; export type MyCustomDialogResult = Array<Choice>; interface MyCustomDialogProps { choices: Array<Choice>; } const MyCustomDialog = ({ choices }: MyCustomDialogProps) => { const { hide } = useDialogActionContext<MyCustomDialogResult>(); const checkedChoiceInfo = useRef<{ [id: string]: { isChecked: boolean; data: Choice } }>({}); return ( <> <section className="dialog"> <div className="dialog-dimmed" onClick={() => { hide(); }} /> <div className="dialog-content"> <h2>Select your choice</h2> <ul> {choices.map((choice) => { const checkboxId = `checkboxId-${choice.id}-${choice.display}`; return ( <li key={choice.id}> <input type="checkbox" id={checkboxId} value={choice.id} onChange={(event) => { const isChecked = event.target.checked; if (checkedChoiceInfo.current[event.target.value] !== undefined) { checkedChoiceInfo.current[event.target.value].isChecked = isChecked; } else { checkedChoiceInfo.current[event.target.value] = { isChecked: isChecked, data: choice, }; } }} /> <label htmlFor={checkboxId}>{choice.display}</label> </li> ); })} </ul> <ul className="horizontal"> <li> <button onClick={() => { hide(); }}> Dismiss </button> </li> <li> <button onClick={() => { const selectedList: MyCustomDialogResult = []; const entries = Object.entries(checkedChoiceInfo.current); for (const [, value] of entries) { if (value.isChecked) { selectedList.push(value.data); } } hide(selectedList); }}> Select </button> </li> </ul> </div> </section> </> ); }; export default MyCustomDialog;useDialogActionContext에 데이터 유형을 전달 해서hide를 호출 할 때 값의 일관성을 갖도록 합니다.hide는undefined를 전달 할 수 있습니다.해당 dialog 를 표시하고자 하는 코드에서 아래와 같이 dialog를 제어 합니다.
<button onClick={async () => { const dialog = await showDialog<MyCustomDialogResult>(<MyCustomDialog choices={choices} />); console.log("result", dialog.result); }}> Show custom dialog </button>promise 는 {id, result} 를 리턴합니다. 해당 dialog 에서 전달 하는 값은 result 객체에 있습니다. 값을 사용하세요!
주의해주세요!
Dialog 에서 다른 페이지로 리디렉션
withHistory기능을 활성화 하면, 브라우저 히스토리가 쌓이게 되고. 쌓인 상태로 dialog 에서 외부 또는 내부로 redirect 하려고 할 때 문제가 발생 할 수 있습니다.- 브라우저 히스토리가 쌓인 상태로 새로운 페이지로 리디렉션 한 뒤 다시 돌아오면 동작되지 않는 히스토리가 쌓여 문제가 됩니다.
useDialogActionContext의doNavigate로 redirect 코드를 작성해야 합니다.- 예를들어
// 이렇게 리디렉션 하면 히스토리 문제가 됩니다. navigate("/hello-world"); // 대신 doNavigate 로 감싸야 합니다. doNavigate로 감싸면 리디렉션 전에 dialog와 관련된 브라우저 히스토리를 제거한 뒤 리디렉션 합니다. doNavigate(() => navigate("/hello-world"));- 자세한 내용은 dialog example 의 redirect 관련 내용을 참고하세요. (
redirect-example-dialog.tsx)
1.0.4-canary.2
1 year ago
1.0.4-canary.4
1 year ago
1.0.4-canary.1
1 year ago
1.0.6
1 year ago
1.0.5
1 year ago
1.0.3
1 year ago
1.0.2
1 year ago