Components
Modal
body 로 portal 하는 백드롭 + 패널.
import { Button, Modal } from '@coldsurfers/surf-ui/primitives'import { useRef, useState } from 'react'export default function Example() { const [open, setOpen] = useState(false) const triggerRef = useRef<HTMLButtonElement>(null) return ( <> <Button ref={triggerRef} onClick={() => setOpen(true)}> 모달 열기 </Button> <Modal open={open} onClose={() => setOpen(false)} label="예매를 취소할까요?" triggerRef={triggerRef} panelClassName="preview-modal-panel" > <p style={{ margin: 0, fontWeight: 500 }}>예매를 취소할까요?</p> <p style={{ margin: '8px 0 16px', color: 'var(--surf-text-secondary)' }}> 취소한 자리는 바로 다른 사람에게 넘어갑니다. </p> <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}> <Button variant="ghost" onClick={() => setOpen(false)}> 돌아가기 </Button> <Button variant="accent" onClick={() => setOpen(false)}> 취소하기 </Button> </div> </Modal> </> )}행동은 useDialogBehavior 가, 마크업만 Modal 이 듭니다. 오버레이가 role="dialog" 를 들고,
오버레이 클릭은 dismissible 일 때만 닫습니다.
document.body 로 portal 한다
fixed inset-0 은 overflow 클리핑만 면해줄 뿐입니다. position: sticky · transform ·
filter 를 가진 조상이 있으면 그 조상이 stacking context 를 만들어, 오버레이의 z-index 가
페이지가 아니라 그 조상 안에서만 유효해집니다. 실제로 sticky 레일 위에서 티켓이 모달 위로
올라온 사고가 있었습니다.
대신 표면 오버라이드를 인라인으로 주입하는 서브트리 안에서는 그 값을 못 받습니다. 팔레트는
문제없습니다 — 스킴이 하나뿐이라 :root 가 곧 light 입니다. 바닥색이 필요하면 소비처가 직접
줍니다.
전면 시트처럼 백드롭/패널 구조가 아닌 표면은 이 컴포넌트 대신 훅만 씁니다.
Props
Prop
Type