Modals manager
Modals manager
다중 단계 modals의 상태를 처리할 수 있는 중앙 집중식 modals 관리자예요. @mantine/modals 패키지로 제공되며 MIT 라이선스로 배포돼요.
출처: 문서
본문
설치
yarn add @mantine/modals
ModalsProvider 설정
앱을 ModalsProvider 컴포넌트로 감싸요:
import { MantineProvider } from '@mantine/core';
import { ModalsProvider } from '@mantine/modals';
function Demo() {
return (
<MantineProvider>
<ModalsProvider>
{/* Your app here */}
</ModalsProvider>
</MantineProvider>
);
}
Confirm modal
@mantine/modals 패키지에는 확인(confirmations)에 사용할 수 있는 특별한 modal이 포함돼 있어요. 이 컴포넌트는 confirm과 cancel 버튼을 포함하고, 동작에 대한 추가 정보를 표시하는 children을 지원해요. openConfirmModal 함수로 confirm modal을 열어요:
import { Button, Text } from '@mantine/core';
import { modals } from '@mantine/modals';
function Demo() {
const openModal = () => modals.openConfirmModal({
title: 'Please confirm your action',
children: (
<Text size="sm">
This action is so important that you are required to confirm it with a modal. Please click
one of these buttons to proceed.
</Text>
),
labels: { confirm: 'Confirm', cancel: 'Cancel' },
onCancel: () => console.log('Cancel'),
onConfirm: () => console.log('Confirmed'),
});
return <Button onClick={openModal}>Open confirm modal</Button>;
}
openConfirmModal 함수는 다음 속성을 가진 인자 하나를 받아요:
-
modalId– modal id, 기본은 임의의 id, 프로그래매틱하게 modal을 닫는 데 사용할 수 있어요 -
children– actions 앞에 표시되는 추가 modal 콘텐츠 -
onCancel– cancel 버튼이 클릭될 때 호출돼요 -
onConfirm– confirm 버튼이 클릭될 때 호출돼요 -
closeOnConfirm– confirm 버튼이 클릭될 때 modal을 닫을지, 기본true -
closeOnCancel– cancel 버튼이 클릭될 때 modal을 닫을지, 기본true -
cancelProps– cancel 버튼 props -
confirmProps– confirm 버튼 props -
groupProps– 버튼 Group props -
labels– cancel과 confirm 버튼 라벨, ModalsProvider에서 정의할 수 있어요
이 속성들을 사용해 현재 컨텍스트 요구사항에 맞게 confirm modal을 커스터마이즈할 수 있어요:
import { Button, Text } from '@mantine/core';
import { modals } from '@mantine/modals';
function Demo() {
const openDeleteModal = () =>
modals.openConfirmModal({
title: 'Delete your profile',
centered: true,
children: (
<Text size="sm">
Are you sure you want to delete your profile? This action is destructive and you will have
to contact support to restore your data.
</Text>
),
labels: { confirm: 'Delete account', cancel: "No don't delete it" },
confirmProps: { color: 'red' },
onCancel: () => console.log('Cancel'),
onConfirm: () => console.log('Confirmed'),
});
return <Button onClick={openDeleteModal}>Delete account</Button>;
}
confirm modals의 공유 라벨을 설정하려면 ModalsProvider에 labels를 설정해요:
import { ModalsProvider } from '@mantine/modals';
function Demo() {
return (
<ModalsProvider labels={{ confirm: 'Submit', cancel: 'Cancel' }}>
{/* Your app here */}
</ModalsProvider>
);
}
Context modals
ModalsProvider 컨텍스트에 원하는 만큼 modals를 정의할 수 있어요:
import { Button, Text } from '@mantine/core';
import { ContextModalProps, ModalsProvider } from '@mantine/modals';
const TestModal = ({
context,
id,
innerProps,
}: ContextModalProps<{ modalBody: string }>) => (
<>
<Text>{innerProps.modalBody}</Text>
<Button onClick={() => context.closeModal(id)}>Close modal</Button>
</>
);
function Demo() {
return (
<ModalsProvider
modals={{
demonstration: TestModal,
}}
>
{/* Your app here */}
</ModalsProvider>
);
}
그런 다음 modals.openContextModal 함수로 이 modals 중 하나를 열어요. modals.openContextModal 함수는 modal key(ModalsProvider에 정의된 것과 일치해야 함)와 modal props, 2개의 인자를 받아요:
import { Button } from '@mantine/core';
import { modals } from '@mantine/modals';
function Demo() {
return (
<Button
onClick={() =>
modals.openContextModal({
modal: 'demonstration',
title: 'Test modal from context',
innerProps: {
modalBody:
'This modal was defined in ModalsProvider, you can open it anywhere in you app with useModals hook',
},
})
}
>
Open demonstration context modal
</Button>
);
}
타입 안전한 context modals
기본적으로 innerProps와 modal은 타입 안전하지 않아요. TypeScript 모듈 선언으로 타입 안전성을 추가할 수 있어요.
const TestModal = ({
context,
id,
innerProps,
}: ContextModalProps<{ modalBody: string }>) => (
<>
<Text>{innerProps.modalBody}</Text>
<Button onClick={() => context.closeModal(id)}>Close modal</Button>
</>
);
const modals = {
demonstration: TestModal,
/* ...other modals */
};
declare module '@mantine/modals' {
export interface MantineModalsOverride {
modals: typeof modals;
}
}
function Demo() {
return (
<ModalsProvider modals={modals}>
{/* Your app here */}
</ModalsProvider>
);
}
타입 안전한 context modals는 openContextModal에 올바른 타입을 사용하도록 강제해요:
import { closeModal, openContextModal } from '@mantine/modals';
openContextModal({
modal: 'demonstration',
title: 'Test modal from context',
innerProps: {
modalBody:
'This modal was defined in ModalsProvider, you can open it anywhere in your app with useModals hook',
},
});
closeModal('demonstration');
Content modals
modals.open 함수로 어떤 콘텐츠든 가진 modal을 열 수 있어요:
import { TextInput, Button } from '@mantine/core';
import { modals } from '@mantine/modals';
function Demo() {
return (
<Button
onClick={() => {
modals.open({
title: 'Subscribe to newsletter',
children: (
<>
<TextInput placeholder="Your email" />
<Button onClick={() => modals.closeAll()} mt="md" fullWidth>
Submit
</Button>
</>
),
});
}}
>
Open content modal
</Button>
);
}
여러 열린 modals
여러 레이어의 modals를 열 수 있어요. 열리는 모든 modal은 modals 큐의 첫 번째 요소로 추가돼요. 열려 있는 모든 modals를 닫으려면 modals.closeAll() 함수를 호출해요:
import { Button, Text } from '@mantine/core';
import { modals } from '@mantine/modals';
function Demo() {
return (
<Button
onClick={() =>
modals.openConfirmModal({
title: 'Please confirm your action',
closeOnConfirm: false,
labels: { confirm: 'Next modal', cancel: 'Close modal' },
children: (
<Text size="sm">
This action is so important that you are required to confirm it with a modal. Please
click one of these buttons to proceed.
</Text>
),
onConfirm: () =>
modals.openConfirmModal({
title: 'This is modal at second layer',
labels: { confirm: 'Close modal', cancel: 'Back' },
closeOnConfirm: false,
children: (
<Text size="sm">
When this modal is closed modals state will revert to first modal
</Text>
),
onConfirm: modals.closeAll,
}),
})
}
>
Open multiple steps modal
</Button>
);
}
Modal props
모든 modals.x 함수의 인자에 추가하면 Modal 컴포넌트에 props를 전달할 수 있어요. radius, size, withCloseButton props를 설정하는 예시:
import { Button, Text } from '@mantine/core';
import { modals } from '@mantine/modals';
function Demo() {
const openModal = () => modals.openConfirmModal({
title: 'Please confirm your action',
size: 'sm',
withCloseButton: false,
children: (
<Text size="sm">
This action is so important that you are required to confirm it with a modal. Please click
one of these buttons to proceed.
</Text>
),
labels: { confirm: 'Confirm', cancel: 'Cancel' },
onCancel: () => console.log('Cancel'),
onConfirm: () => console.log('Confirmed'),
});
return <Button onClick={openModal}>Open confirm modal</Button>;
}
동적 콘텐츠와 modals manager
modals manager를 사용하면 standard와 context modals를 연 후 콘텐츠와 속성을 동적으로 업데이트할 수 있어요.
일반 modals를 업데이트하려면 modals.updateModal 함수를 사용해요:
import { Button } from '@mantine/core';
import { modals } from '@mantine/modals';
function Demo() {
return (
<Button
onClick={() => {
const modalId = modals.open({
title: 'Initial Modal Title',
children: <Text>This text will update in 2 seconds.</Text>,
});
setTimeout(() => {
modals.updateModal({
modalId,
title: 'Updated Modal Title',
children: (
<Text>
This is the updated content of the modal.
</Text>
),
});
}, 2000);
}}
>
Open updating modal
</Button>
);
}
Context modals도 modals.updateContextModal을 사용해 동적으로 업데이트할 수 있어요:
import { Button, Text, Stack, Center, Loader } from '@mantine/core';
import { modals, ContextModalProps, ModalsProvider } from '@mantine/modals';
import { CheckIcon } from '@phosphor-icons/react';
const TestModal = ({
context,
id,
innerProps,
}: ContextModalProps<{ modalBody: string; loading: boolean }>) => (
<>
<Text size="sm">{innerProps.modalBody}</Text>
<Center my="lg">
{innerProps.loading ? <Loader size={32} /> : <CheckIcon size={32} />}
</Center>
<Button onClick={() => context.closeModal(id)}>Close modal</Button>
</>
);
function Demo() {
return (
<ModalsProvider modals={{ asyncDemonstration: TestModal }}>
<Button
onClick={() => {
const modalId = modals.openContextModal({
modal: 'asyncDemonstration',
title: 'Processing...',
closeOnEscape: false,
closeOnClickOutside: false,
closeButtonProps:{ disabled:true },
innerProps: {
modalBody:
'You cannot close this modal until 2 seconds have passed.',
loading: true,
},
});
setTimeout(() => {
modals.updateContextModal({
modalId,
title: "Processing Complete!",
closeOnEscape: true,
closeOnClickOutside: true,
closeButtonProps:{ disabled: false },
innerProps: {
modalBody:
'You can now close the modal.',
loading: false,
},
})
}, 2000);
}}
>
Open updating context modal
</Button>
</ModalsProvider>
);
}