Patterns
Masonry
카드를 가장 낮은 열에 차례로 놓는 다단 그리드. 웹 · RN 이 같은 간격을 쓴다.
import { Masonry, PinCard, pinCardHeight } from '@coldsurfers/surf-ui/cards'import { Button } from '@coldsurfers/surf-ui/primitives'import { useState } from 'react'import { type SamplePin, samplePins } from './pin-samples'/** 다음 쪽 흉내 — 같은 핀을 새 키로 한 쪽 더. */const pageOf = (page: number): SamplePin[] => samplePins.map((pin) => ({ ...pin, id: `${pin.id}-${page}` }))export default function Example() { const [pages, setPages] = useState(1) const items = Array.from({ length: pages }, (_, page) => pageOf(page)).flat() return ( <div style={{ width: 360, display: 'grid', gap: 16 }}> <Masonry items={items} keyOf={(pin) => pin.id} heightOf={(pin) => pinCardHeight(pin.ratio ?? undefined, !!pin.meta)} renderItem={(pin) => ( <PinCard poster={pin.poster ?? undefined} meta={pin.meta} fallback={pin.title}> <a href={`#${pin.id}`}>{pin.title}</a> </PinCard> )} /> <Button variant="outline" onClick={() => setPages((n) => n + 1)}> 다음 쪽 붙이기 </Button> </div> )}항목을 가장 낮은 열에 차례로 놓습니다. 다음 쪽이 붙어도 이미 놓인 카드는 다른 열로 옮기지 않습니다 —
CSS column-count 와 다른 점입니다. 쪽은 따로 그리지 말고 이어 붙인 items 하나로 넘기세요 — 쪽 사이에 빈칸이 남지 않습니다.
높이는 그려진 칸이면 실측으로, 아직 안 그려진 칸만 heightOf(열 폭 = 1)로 칩니다. 핀 카드면 pinCardHeight 를 쓰고, 비율을 모르면 undefined 를 넘겨도 됩니다.
「다음 쪽 붙이기」를 눌러 보세요 — 새 칸은 아래에서 살짝 떠오르고, PinCard 포스터는 3:4 자리에서 받은 비율로 옮겨 갑니다. 동작 줄이기 설정이면 둘 다 바로 바뀝니다.
간격(열 12 · 줄 16)은 MASONRY_SPEC 이 정본이라 native 와 같습니다.
native
RN 판은 Native › Masonry · PinCard — FlashList v2 위에 서고 높이를 재서 놓습니다.
Props
Prop
Type