폼 submit
children을 form body에 넣고 onSubmit으로 저장 흐름을 처리합니다.
wide
필드가 많거나 본문 폭이 필요한 경우 720px 폭으로 확장합니다.
status
자동 저장 아님, 검토 중 같은 보조 상태를 header 아래에 표시합니다.
loading
저장 중에는 submit과 cancel 동작을 잠그는 데 사용합니다.

기본 폼

제목, 설명, 필드, 저장 footer
코드 보기tsx
import { useState } from "react";
import { FormModal, Input, Textarea, Button } from "@olundot/ui";

export function FormModalBasic() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button variant="primary" onClick={() => setOpen(true)}>
        메모 작성
      </Button>
      <FormModal
        open={open}
        onOpenChange={setOpen}
        title="학습 메모 작성"
        description="문항 검토에 필요한 짧은 메모를 남깁니다."
        submitLabel="저장"
        onSubmit={async () => {
          await new Promise((resolve) => setTimeout(resolve, 800));
        }}
      >
        <Input surface="canvas" label="제목" name="title" placeholder="예: 감별진단 확인" />
        <Textarea surface="canvas" label="내용" name="body" placeholder="메모 내용을 입력하세요." rows={4} />
      </FormModal>
    </>
  );
}

상태 메시지

status 영역과 비동기 저장
코드 보기tsx
import { useState } from "react";
import { FormModal, Input, Badge, Button } from "@olundot/ui";

export function FormModalStatus() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        그룹 이름 변경
      </Button>
      <FormModal
        open={open}
        onOpenChange={setOpen}
        title="그룹 이름 변경"
        description="학생에게 보이는 그룹 이름을 수정합니다."
        status={<Badge tone="info">자동 저장 아님</Badge>}
        submitLabel="변경 저장"
        onSubmit={async () => {
          await new Promise((resolve) => setTimeout(resolve, 900));
        }}
      >
        <Input surface="canvas" label="그룹 이름" name="name" defaultValue="심장학 보충반" />
      </FormModal>
    </>
  );
}

넓은 폼

wide 레이아웃과 복수 필드
코드 보기tsx
import { useState } from "react";
import { FormModal, Input, Textarea, Button } from "@olundot/ui";

export function FormModalWide() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        공지 작성
      </Button>
      <FormModal
        open={open}
        onOpenChange={setOpen}
        title="수업 공지 작성"
        description="목록과 상세 화면에 함께 노출되는 공지를 작성합니다."
        wide
        submitLabel="공지 저장"
        onSubmit={async () => {
          await new Promise((resolve) => setTimeout(resolve, 800));
        }}
      >
        <Input surface="canvas" label="공지 제목" name="notice-title" />
        <Textarea surface="canvas" label="공지 본문" name="notice-body" rows={6} />
      </FormModal>
    </>
  );
}