import classNames from 'classnames' import React from 'react' export interface MediaStackTile { /** Renderable tile content (image / video / poster). */ content: React.ReactNode /** Pure-tile aria label (e.g. `'Photo 1'`). Used by `Pressable` mode. */ ariaLabel?: string /** * Cursor utility for the pressable tile shell. Defaults to * `'cursor-zoom-in'` (correct for images); Video passes * `'cursor-pointer'` because activating a video tile starts playback * rather than magnifying a still. */ cursorClassName?: string } /** * Tiles rendered before the last one collapses into a `+N` overflow * indicator. Exported so callers that need to style the overflow tile * differently can work out which index it lands on without restating * the number. */ export const MEDIA_STACK_MAX_VISIBLE = 4 export interface MediaStackGridProps { tiles: MediaStackTile[] /** * When set, every tile is wrapped in a ` ) } return (
{tile.content} {extra}
) } let singleTileStyle: React.CSSProperties | undefined if (singleAspectRatio) { singleTileStyle = { aspectRatio: singleAspectRatio, // Hundredths keep the emitted declaration readable in devtools; // the rounding error is well under a device pixel. width: `min(var(${SINGLE_WIDTH_CAP_PROPERTY}), ${ Math.round(SINGLE_HEIGHT_CAP_PX * singleAspectRatio * 100) / 100 }px)`, // Only bites in a container narrower than the width cap. maxWidth: '100%', } } if (visible.length === 1) { return (
{renderTile(visible[0], 0, overflowBadge)}
) } if (visible.length === 2) { return (
{visible.map((tile, index) => renderTile( tile, index, index === visible.length - 1 ? overflowBadge : null ) )}
) } if (visible.length === 3) { return (
{renderTile(visible[0], 0)}
{renderTile(visible[1], 1)} {renderTile(visible[2], 2, overflowBadge)}
) } // 4 tiles (or 4 visible with overflow on the last) return (
{visible.map((tile, index) => { const isLastWithOverflow = overflow > 0 && index === visible.length - 1 return renderTile( tile, index, isLastWithOverflow ? overflowBadge : null ) })}
) } export default MediaStackGrid