feat: implement ModalFooter component for consistent modal action layout

This commit is contained in:
estifanos
2026-08-05 08:50:38 +00:00
parent c8df8e1578
commit bbae230ad5
21 changed files with 152 additions and 74 deletions

View File

@@ -1,5 +1,6 @@
export * from "./lib/input/BilingualInput";
export * from "./lib/feedback/ConfirmModal";
export * from "./lib/feedback/ModalFooter";
export * from "./lib/feedback/ApiErrorAlert";
export * from "./lib/feedback/notify";
export * from "./lib/feedback/FeatureUnavailable";

View File

@@ -1,4 +1,5 @@
import { Modal, Button, Group, Text } from '@mantine/core';
import { Modal, Button, Text } from '@mantine/core';
import { ModalFooter } from './ModalFooter';
interface ConfirmModalProps {
opened: boolean;
@@ -26,14 +27,14 @@ export function ConfirmModal({
<Text size="sm" mb="xl">
{message}
</Text>
<Group justify="flex-end">
<ModalFooter>
<Button variant="subtle" onClick={onClose} disabled={loading}>
{cancelLabel}
</Button>
<Button color="red" onClick={onConfirm} loading={loading}>
{confirmLabel}
</Button>
</Group>
</ModalFooter>
</Modal>
);
}

View File

@@ -0,0 +1,38 @@
import { Group, type GroupProps } from '@mantine/core';
import type { CSSProperties } from 'react';
/**
* Action row pinned to the bottom of a modal.
*
* Modal bodies scroll (see the Modal styles in the theme), which would carry the
* confirm button off-screen on a tall modal. Sticking to the bottom of the
* scrollport keeps the decision reachable from any scroll position. Negative
* margins bleed the background over the body's padding so nothing shows through
* underneath; on a modal short enough not to scroll this renders identically to
* a plain Group.
*/
export function ModalFooter({
children,
style,
...props
}: Omit<GroupProps, 'style'> & { style?: CSSProperties }) {
return (
<Group
justify="flex-end"
{...props}
style={{
position: 'sticky',
bottom: 'calc(var(--mb-padding, var(--mantine-spacing-md)) * -1)',
marginInline: 'calc(var(--mb-padding, var(--mantine-spacing-md)) * -1)',
marginBottom: 'calc(var(--mb-padding, var(--mantine-spacing-md)) * -1)',
padding: 'var(--mb-padding, var(--mantine-spacing-md))',
background: 'var(--mantine-color-body)',
borderTop: '1px solid var(--mantine-color-default-border)',
zIndex: 1,
...style,
}}
>
{children}
</Group>
);
}