feat: Enhance modal button behavior and validation feedback

- Updated modal button handling to disable all buttons by default, with exceptions for specific button types (e.g., cancel, close, delete).
- Introduced a new validation mechanism that visually indicates empty required fields with red borders and error messages after a delay.
- Improved the `useDialogAutoValidation` hook to manage button states based on field validation, ensuring a smoother user experience.
- Added CSS animations to prevent flickering during validation state changes.

Made-with: Cursor
This commit is contained in:
2026-03-03 14:54:41 +09:00
parent dca89a698f
commit eb2bd8f10f
7 changed files with 236 additions and 106 deletions

View File

@@ -83,17 +83,17 @@ const DialogContent = React.forwardRef<
const container = explicitContainer !== undefined ? explicitContainer : autoContainer;
const scoped = !!container;
// 모달 자동 검증용 내부 ref
const internalRef = React.useRef<HTMLDivElement>(null);
// state 기반 ref: DialogPrimitive.Content 마운트/언마운트 시 useEffect 재실행 보장
const [contentNode, setContentNode] = React.useState<HTMLDivElement | null>(null);
const mergedRef = React.useCallback(
(node: HTMLDivElement | null) => {
internalRef.current = node;
setContentNode(node);
if (typeof ref === "function") ref(node);
else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
},
[ref],
);
useDialogAutoValidation(internalRef);
useDialogAutoValidation(contentNode);
const handleInteractOutside = React.useCallback(
(e: any) => {
@@ -152,7 +152,7 @@ const DialogContent = React.forwardRef<
{...props}
>
{children}
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 cursor-pointer rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none">
<DialogPrimitive.Close data-dialog-close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 cursor-pointer rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>