diff --git a/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.api.mdx b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.api.mdx
new file mode 100644
index 000000000..bb27f315e
--- /dev/null
+++ b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.api.mdx
@@ -0,0 +1,37 @@
+import { Meta } from '@storybook/addon-docs';
+import LinkTo from '@storybook/addon-links/react';
+import { TableInterface } from '~storybook/components/TableInterface';
+
+
+
+# ConfirmationDialog API
+
+```js
+import { ConfirmationDialog } from '@esfront/react';
+```
+
+## Component name
+
+The name `ESConfirmationDialog` can be used when providing default props or style overrides in the theme.
+
+## Props
+
+
+
+
+
+## CSS
+
+
+
+
+
+## Demos
+
+
+ -
+
+
ConfirmationDialog
+
+
+
diff --git a/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.classes.ts b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.classes.ts
new file mode 100644
index 000000000..7e9268e62
--- /dev/null
+++ b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.classes.ts
@@ -0,0 +1,18 @@
+import { generateUtilityClass, generateUtilityClasses } from '@mui/material';
+
+export type ConfirmationDialogClasses = {
+ /** Styles applied to the root element. */
+ root: string;
+ /** Styles applied to the icon element. */
+ icon: string;
+};
+export type ConfirmationDialogClassKey = keyof ConfirmationDialogClasses;
+
+export function getConfirmationDialogUtilityClass(slot: string): string {
+ return generateUtilityClass('ESConfirmationDialog', slot);
+}
+
+export const confirmationDialogClasses: ConfirmationDialogClasses = generateUtilityClasses('ESConfirmationDialog', [
+ 'root',
+ 'icon',
+]);
diff --git a/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.stories.tsx b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.stories.tsx
new file mode 100644
index 000000000..c513b919e
--- /dev/null
+++ b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.stories.tsx
@@ -0,0 +1,91 @@
+import { ComponentProps } from 'react';
+
+import { Meta, StoryContext, StoryObj } from '@storybook/react';
+
+import { Typography } from '@mui/material';
+
+import { ConfirmationDialog } from '.';
+
+import { Button } from '../Button';
+import { DialogClose } from '../Dialog';
+import { useDialogStack } from '../DialogStack';
+
+type Args = ComponentProps;
+
+const getOpenButtonText = (context: StoryContext) => {
+ return context.globals.locale === 'en' ? 'Open dialog window' : 'Открыть диалоговое окно';
+};
+
+const getHeadingText = (context: StoryContext) => {
+ return context.globals.locale === 'en' ? 'Are you confirm?' : 'Вы подтверждаете согласие?';
+};
+
+const getCancelButtonText = (context: StoryContext) => {
+ return context.globals.locale === 'en' ? 'Cancel' : 'Отмена';
+};
+
+const getConfirmButtonText = (context: StoryContext) => {
+ return context.globals.locale === 'en' ? 'Confirm' : 'Подтвердить';
+};
+
+const meta: Meta = {
+ tags: ['autodocs'],
+ component: ConfirmationDialog,
+ parameters: {
+ references: ['ConfirmationDialog'],
+ },
+ argTypes: {
+ children: {
+ table: {
+ disable: true,
+ },
+ },
+ },
+ args: {
+ severity: 'primary',
+ icon: true,
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Demo: Story = {
+ render: function Render(args, context) {
+ const dialogStack = useDialogStack();
+
+ const onOpen = () => {
+ dialogStack
+ .open(({ close }) => (
+ Promise.resolve(true)}
+ align="center"
+ before={ close()} />}
+ close={() => close()}
+ icon={args.icon ? undefined : false}
+ labelCancel={getCancelButtonText(context)}
+ labelConfirm={getConfirmButtonText(context)}
+ maxWidth="700px"
+ severity={args.severity}
+ title={getHeadingText(context)}
+ >
+
+ Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget
+ quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet
+ fermentum.
+
+
+ ))
+ .afterClosed.then((data) => {
+ console.info(data);
+ });
+ };
+
+ return (
+
+ );
+ },
+};
diff --git a/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.tsx b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.tsx
new file mode 100644
index 000000000..35c2e048a
--- /dev/null
+++ b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.tsx
@@ -0,0 +1,225 @@
+import { forwardRef, useState } from 'react';
+
+import { ConfirmationDialogProps } from './ConfirmationDialog.types';
+
+import clsx from 'clsx';
+import { getConfirmationDialogUtilityClass } from './ConfirmationDialog.classes';
+
+import { unstable_composeClasses as composeClasses } from '@mui/base';
+
+import { styled, useThemeProps } from '@mui/material/styles';
+import { buttonBaseClasses } from '@mui/material';
+// eslint-disable-next-line no-restricted-imports
+import IconButton from '@mui/material/IconButton';
+
+import { IconAlertW500, IconInformation2W500 } from '../../icons';
+import { Button } from '../Button';
+import { Dialog, DialogActions, DialogContent, DialogTitle } from '../Dialog';
+import { LoadingButton } from '../LoadingButton';
+import { svgIconClasses } from '../SvgIcon';
+
+type ConfirmationDialogOwnerState = {
+ classes?: ConfirmationDialogProps['classes'];
+};
+
+const useUtilityClasses = (ownerState: ConfirmationDialogOwnerState) => {
+ const { classes } = ownerState;
+
+ const slots = {
+ root: ['root'],
+ icon: ['icon'],
+ };
+
+ return composeClasses(slots, getConfirmationDialogUtilityClass, classes);
+};
+
+const ConfirmationDialogRoot = styled(Dialog, {
+ name: 'ESConfirmationDialog',
+ slot: 'Root',
+ overridesResolver: (props, styles) => styles.root,
+})(() => ({
+ '& .ESDialog-paper': {
+ position: 'relative',
+ borderRadius: '16px',
+ height: '100%',
+ },
+}));
+
+const ConfirmationDialogTitle = styled(DialogTitle, {
+ name: 'ESConfirmationDialog',
+ slot: 'Title',
+ overridesResolver: (props, styles) => styles.title,
+})<{ ownerState: { severity: 'error' | 'primary' } }>(({ theme, ownerState }) => ({
+ padding: '52px 8px 12px',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ textAlign: 'center',
+ gap: '12px',
+
+ [theme.breakpoints.up('tabletXS')]: {
+ gap: '8px',
+ padding: '22px 24px',
+ flexDirection: 'row',
+ },
+ [`& .${svgIconClasses.root}`]: {
+ color: `${theme.vars.palette[ownerState.severity][300]}`,
+
+ [theme.breakpoints.down('tabletXS')]: {
+ width: '56px !important',
+ height: '56px !important',
+ },
+ },
+}));
+
+const ConfirmationDialogIcon = styled('div', {
+ name: 'ESConfirmationDialog',
+ slot: 'Icon',
+ overridesResolver: (props, styles) => styles.icon,
+})(() => ({
+ paddingTop: '8px',
+ marginRight: '8px',
+}));
+
+const ConfirmationDialogContent = styled(DialogContent, {
+ name: 'ESConfirmationDialog',
+ slot: 'Content',
+ overridesResolver: (props, styles) => styles.content,
+})(({ theme }) => ({
+ padding: '0 16px',
+ color: theme.vars.palette.monoA.A800,
+ textAlign: 'center',
+
+ [theme.breakpoints.up('tabletXS')]: {
+ padding: '0 24px',
+ textAlign: 'left',
+ },
+}));
+
+const ConfirmationDialogActions = styled(DialogActions, {
+ name: 'ESConfirmationDialog',
+ slot: 'Actions',
+ overridesResolver: (props, styles) => styles.actions,
+})(({ theme }) => ({
+ padding: '16px',
+
+ [theme.breakpoints.up('tabletXS')]: {
+ padding: '24px',
+ },
+
+ [`.${buttonBaseClasses.root}`]: {
+ width: '100%',
+
+ [theme.breakpoints.up('tabletXS')]: {
+ width: 'auto',
+ padding: '0 16px',
+ },
+ },
+}));
+
+const ConfirmationDialogClose = styled(IconButton)(() => ({
+ position: 'absolute',
+ right: '8px',
+ top: '8px',
+}));
+
+const defaultIconMapping = {
+ error: ,
+ primary: ,
+};
+
+/**
+ * ConfirmationDialog asks user to approve requested operation.
+ */
+
+export const ConfirmationDialog = forwardRef(
+ function Dialog(inProps, ref) {
+ const {
+ children,
+ disabled,
+ icon,
+ iconClose,
+ labelCancel,
+ labelConfirm,
+ className,
+ severity = 'primary',
+ action,
+ close,
+ open,
+ title,
+ iconMapping = defaultIconMapping,
+ ...props
+ } = useThemeProps({
+ props: inProps,
+ name: 'ESConfirmationDialog',
+ });
+
+ const [isSending, setSending] = useState(false);
+ const ownerState = {
+ ...props,
+ severity,
+ };
+
+ const onConfirm = () => {
+ setSending(true);
+
+ action()
+ .then((data) => {
+ close(data);
+ })
+ .catch((error) => {
+ setSending(false);
+ return Promise.reject(error);
+ });
+ };
+
+ const onClose = () => {
+ if (!isSending) {
+ close();
+ }
+ };
+
+ const classes = useUtilityClasses(ownerState);
+
+ return (
+
+ {iconClose && (
+
+ {iconClose}
+
+ )}
+
+
+ {icon !== false && (
+ {icon || iconMapping[severity]}
+ )}
+ {title}
+
+ {children}
+
+
+ {!!labelConfirm && (
+
+ {labelConfirm}
+
+ )}
+
+
+ );
+ }
+);
diff --git a/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.types.ts b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.types.ts
new file mode 100644
index 000000000..e09459538
--- /dev/null
+++ b/packages/react/src/components/ConfirmationDialog/ConfirmationDialog.types.ts
@@ -0,0 +1,42 @@
+import { ReactNode } from 'react';
+
+import { ConfirmationDialogClasses } from './ConfirmationDialog.classes';
+
+import { DialogProps } from '../Dialog';
+
+export interface ConfirmationDialogProps extends DialogProps {
+ /** Override or extend the styles applied to the component. */
+ classes?: Partial;
+ /** Confirmation dialog children, usually the included sub-components. */
+ children?: React.ReactNode;
+ /** The icon displayed before the title. */
+ icon?: ReactNode;
+ /** The icon for closing the modal. */
+ iconClose?: ReactNode;
+ /**
+ * The severity of the confirmation dialog. This defines the color and icon used.
+ * @default 'primary'
+ */
+ severity?: 'error' | 'primary';
+ /** The title text. */
+ title: ReactNode;
+ /** Text for the confirm buttony. */
+ labelConfirm?: ReactNode;
+ /** Text for the cancel buttony. */
+ labelCancel?: ReactNode;
+ /** If true, the button is disabled. */
+ disabled?: boolean;
+ /**
+ * Callback fired when the user clicks the button.
+ */
+ action: () => Promise;
+ /**
+ * Callback fired when the component requests to be closed.
+ */
+ close: (data?: any) => void;
+ /**
+ * The component maps the severity prop to a range of different icons.
+ * If you wish to change this mapping, you can provide your own.
+ */
+ iconMapping?: Record<'error' | 'primary', ReactNode>;
+}
diff --git a/packages/react/src/components/ConfirmationDialog/index.ts b/packages/react/src/components/ConfirmationDialog/index.ts
new file mode 100644
index 000000000..61f201046
--- /dev/null
+++ b/packages/react/src/components/ConfirmationDialog/index.ts
@@ -0,0 +1,7 @@
+export { ConfirmationDialog } from './ConfirmationDialog';
+export {
+ ConfirmationDialogClasses,
+ confirmationDialogClasses,
+ ConfirmationDialogClassKey,
+} from './ConfirmationDialog.classes';
+export { ConfirmationDialogProps } from './ConfirmationDialog.types';
diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts
index 21e6de9e8..5ce589be6 100644
--- a/packages/react/src/components/index.ts
+++ b/packages/react/src/components/index.ts
@@ -15,6 +15,7 @@ export * from './Button';
export * from './ButtonBase';
export * from './Calendar';
export * from './Checkbox';
+export * from './ConfirmationDialog';
export * from './DateAdapter';
export * from './Dialog';
export * from './DialogStack';
diff --git a/packages/react/src/overrides.d.ts b/packages/react/src/overrides.d.ts
index 4ded9188a..9f4ef6832 100644
--- a/packages/react/src/overrides.d.ts
+++ b/packages/react/src/overrides.d.ts
@@ -71,6 +71,7 @@ import {
CalendarProps,
} from './components/Calendar';
import { CheckboxClassKey, CheckboxProps, CheckboxIconClassKey, CheckboxIconProps } from './components/Checkbox';
+import { ConfirmationDialog } from './components/ConfirmationDialog';
import {
DialogActionsClassKey,
DialogActionsProps,
@@ -361,6 +362,7 @@ declare module '@mui/material/styles/props' {
ESCalendarHead: CalendarHeadProps;
ESCheckbox: CheckboxProps;
ESCheckboxIcon: CheckboxIconProps;
+ ESConfirmationDialog: ConfirmationDialogProps;
ESDialog: DialogProps;
ESDialogActions: DialogActionsProps;
ESDialogArrow: DialogArrowProps;
@@ -497,6 +499,7 @@ declare module '@mui/material/styles/overrides' {
ESCalendarHead: CalendarHeadClassKey;
ESCheckbox: CheckboxClassKey;
ESCheckboxIcon: CheckboxIconClassKey;
+ ESConfirmationDialog: ConfirmationDialogClassKey;
ESDialog: DialogClassKey;
ESDialogActions: DialogActionsClassKey;
ESDialogArrow: DialogArrowClassKey;
@@ -716,6 +719,10 @@ declare module '@mui/material/styles/components' {
defaultProps?: ComponentsProps['ESCheckboxIcon'];
styleOverrides?: ComponentsOverrides['ESCheckboxIcon'];
};
+ ESConfirmationDialog?: {
+ defaultProps?: ComponentsProps['ESConfirmationDialog'];
+ styleOverrides?: ComponentsOverrides['ESConfirmationDialog'];
+ };
ESDialog?: {
defaultProps?: ComponentsProps['ESDialog'];
styleOverrides?: ComponentsOverrides['ESDialog'];