UNPKG

gestalt

Version:

A set of React UI components which enforce Pinterest's design language

214 lines (213 loc) 12.3 kB
import { Component as ReactComponent, ReactNode } from 'react'; import { DebounceReturn } from './debounce'; import { Cache } from './Masonry/Cache'; import MeasurementStore from './Masonry/MeasurementStore'; import { ColumnSpanConfig, ModulePositioningConfig, ResponsiveModuleConfig } from './Masonry/multiColumnLayout'; import ScrollContainer from './Masonry/ScrollContainer'; import { Align, Layout, Position } from './Masonry/types'; import { ThrottleReturn } from './throttle'; type Props<T> = { /** * Controls the horizontal alignment of items within the Masonry grid. The `align` property determines how items are aligned along the main-axis (horizontally) across multiple columns. * `start`: Aligns items to the start of the Masonry container. This is the default behavior where items are placed starting from the left side of the container. * `center`: Centers items in the Masonry grid. This will adjust the spacing on either side of the grid to ensure that the items are centered within the container. * `end`: Aligns items to the end of the Masonry container. Items will be placed starting from the right, moving leftwards, which may leave space on the left side of the container. * Using the `align` property can help control the visual balance and alignment of the grid, especially in responsive layouts or when dealing with varying item widths. * * _Note that layout='basic' must be set for align to take effect._ */ align?: Align; /** * The preferred/target item width in pixels. If `layout="flexible"` is set, the item width will * grow to fill column space, and shrink to fit if below the minimum number of columns. */ columnWidth?: number; /** * The amount of vertical and horizontal space between each item, specified in pixels. */ gutterWidth?: number; /** * An array of items to display that contains the data to be rendered by `renderItem`. */ items: ReadonlyArray<T>; /** * `basic`: Left-aligned, fixed-column-width masonry layout. * `basicCentered`: Center-aligned, fixed-column-width masonry layout. * `flexible`: Item width grows to fill column space and shrinks to fit if below the minimum number of columns. * `serverRenderedFlexible`: Item width grows to fill column space and shrinks to fit if below the minimum number of columns. Main differerence with `flexible` is that we do not store the initial measurement. More context in [#2084](https://github.com/pinterest/gestalt/pull/2084) * `uniformRow`: Items are laid out in a single row, with all items having the same height. Note that Masonry does _not_ crop or alter items in any way — rows will take the height of the tallest item in the row, with additional whitespace shown below any shorter items. */ layout?: Layout; /** * A callback fired when the user scrolls past a given threshold, based on the height of the container. The callback should update the state of the items, which must be reflected in the `items` prop. * * _Note that `scrollContainer` must be specified._ */ loadItems?: (arg1?: { from: number; } | null | undefined) => void; /** * Masonry internally caches item heights using a measurement store. If `measurementStore` is provided, Masonry will use it as its cache and will keep it updated with future measurements. This is often used to prevent re-measurement when users navigate away from and back to a grid. Create a new measurement store with `Masonry.createMeasurementStore()`. */ measurementStore?: Cache<T, number>; /** * Minimum number of columns to display, regardless of the container width. */ minCols: number; /** * Masonry internally caches positions using a position store. If `positionStore` is provided, Masonry will use it as its cache and will keep it updated with future positions. */ positionStore?: Cache<T, Position>; /** * A function that renders the item you would like displayed in the grid. This function is passed three props: the item's data, the item's index in the grid, and a flag indicating if Masonry is currently measuring the item. * * If present, `heightAdjustment` indicates the number of pixels this item needs to grow/shrink to accommodate a 2-column item in the grid. Items must respond to this prop by adjusting their height or layout issues will occur. */ renderItem: (arg1: { readonly data: T; readonly itemIdx: number; readonly isMeasuring: boolean; }) => ReactNode; /** * A function that returns a DOM node that Masonry uses for scroll event subscription. This DOM node is intended to be the most immediate ancestor of Masonry in the DOM that will have a scroll bar; in most cases this will be the `window` itself, although sometimes Masonry is used inside containers that have `overflow: auto`. `scrollContainer` is optional, although it is required for features such as `virtualize` and `loadItems`. * * This is required if the grid is expected to be scrollable. */ scrollContainer?: () => HTMLElement | Window; /** * If `virtualize` is enabled, Masonry will only render items that fit in the viewport, plus some buffer. `virtualBoundsBottom` allows customization of the buffer size below the viewport, specified in pixels. */ virtualBoundsBottom?: number; /** * If `virtualize` is enabled, Masonry will only render items that fit in the viewport, plus some buffer. `virtualBoundsTop` allows customization of the buffer size above the viewport, specified in pixels. */ virtualBoundsTop?: number; /** * If `virtualize` is enabled, Masonry will only render items that fit in the viewport, plus some buffer. `virtualBufferFactor` allows customization of the buffer size, specified as a multiplier of the container height. It specifies the amount of extra buffer space for populating visible items. For example, if `virtualBufferFactor` is 2, then Masonry will render items that fit in the viewport, plus 2x the viewport height. */ virtualBufferFactor?: number; /** * Specifies whether or not Masonry dynamically adds/removes content from the grid based on the user's viewport and scroll position. Note that `scrollContainer` must be specified when virtualization is used. */ virtualize?: boolean; /** * Experimental prop to log the additional whitespace shown above multicolumn items and the number of iterations it took to position it. * * This is an experimental prop and may be removed in the future. */ _logTwoColWhitespace?: (additionalWhitespace: ReadonlyArray<number>, numberOfIterations: number, columnSpan: number) => void; /** * Experimental prop to define how many columns a module should span. This is also used to enable multi-column support * _getColumnSpanConfig is a function that takes an individual grid item as an input and returns a ColumnSpanConfig. ColumnSpanConfig can be one of two things: * - A number, which indicates a static number of columns the item should span * - An object, which allows for configuration of the item's column span across the following grid sizes: sm (2 columns), md (3-4 columns), lg (5-8 columns), xl (9+ columns) * * This is an experimental prop and may be removed or changed in the future. */ _getColumnSpanConfig?: (item: T) => ColumnSpanConfig; /** * Experimental prop to define the minimum and maximum limit a flexible width module could span. * This used to enable multi-column flexible width support ONLY ON SECOND ITEM OF THE ARRAY OF ITEMS. * Also, for the flexible width to work, the _getColumnSpanConfig prop should be set. * _getResponsiveModuleConfigForSecondItem is a function that takes an individual grid item as an input and returns a ResponsiveModuleConfig. * ResponsiveModuleConfig can be one of the following: * - A number, which indicates a static number of columns the item should span * - An object, which sets the minimum and maximum limits a multi-column item could span filling the empty columns in the first row of the grid (flexible width). * - Undefined, which is used to indicate that this prop isn't set. * * This is an experimental prop and may be removed or changed in the future. */ _getResponsiveModuleConfigForSecondItem?: (item: T) => ResponsiveModuleConfig; /** * Experimental flag to enable dynamic heights on items. This only works if multi column items are enabled. */ _dynamicHeights?: boolean; /** * Experimental flag to enable an experiment to use a revamped version of dynamic heights (This needs _dynamicHeights enabled) */ _dynamicHeightsV2Experiment?: boolean; /** * Experimental prop to enable dynamic batch sizing and early bailout when positioning a module * - Early bailout: How much whitespace is "good enough" * - Dynamic batch sizing: How many items it can use. If this prop isn't used, it uses 5 * * This is an experimental prop and may be removed or changed in the future */ _getModulePositioningConfig?: (gridSize: number, moduleSize: number) => ModulePositioningConfig; /** * Experimental flag to enable new multi column position layout algorithm */ _multiColPositionAlgoV2?: boolean; }; type State<T> = { gutter: number; hasPendingMeasurements: boolean; isFetching: boolean; items: ReadonlyArray<T>; measurementStore: Cache<T, number>; scrollTop: number; width: number | null | undefined; }; /** * [Masonry](https://gestalt.pinterest.systems/web/masonry) creates a deterministic grid layout, positioning items based on available vertical space. It contains performance optimizations like virtualization and support for infinite scrolling. * * ![Masonry light mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/Masonry.spec.ts-snapshots/Masonry-chromium-darwin.png) * */ export default class Masonry<T> extends ReactComponent<Props<T>, State<T>> { static createMeasurementStore<T1 extends Record<any, any>, T2>(): MeasurementStore<T1, T2>; static defaultProps: { align?: Align; columnWidth?: number; layout?: Layout; loadItems?: (arg1?: { from: number; } | null | undefined) => void; minCols: number; virtualBufferFactor: number; virtualize?: boolean; }; static displayName: string | null | undefined; constructor(props: Props<T>); resizeObserver: ResizeObserver | undefined; containerHeight: number; containerOffset: number; gridWrapper: HTMLElement | null | undefined; positionStore: Cache<T, Position>; insertAnimationFrame: number | null; scrollContainer: ScrollContainer | null | undefined; maxHeight: number; /** * Delays resize handling in case the scroll container is still being resized. */ handleResize: DebounceReturn; updateScrollPosition: ThrottleReturn; measureContainerAsync: DebounceReturn; /** * Adds hooks after the component mounts. */ componentDidMount(): void; componentDidUpdate(prevProps: Props<T>, prevState: State<T>): void; /** * Remove listeners when unmounting. */ componentWillUnmount(): void; static getDerivedStateFromProps<K>(props: Props<K>, state: State<K>): null | { hasPendingMeasurements: boolean; isFetching?: boolean; items: ReadonlyArray<K>; }; setGridWrapperRef: (ref?: HTMLElement | null | undefined) => void; setScrollContainerRef: (ref?: ScrollContainer | null | undefined) => void; fetchMore: () => void; measureContainer(): void; /** * Clear measurements/positions and force a reflow of the entire grid. * Only use this if absolutely necessary - ex: We need to reflow items if the * number of columns we would display should change after a resize. */ reflow(): void; renderMasonryComponent: (itemData: T, idx: number, position: Position) => ReactNode; render(): import("react/jsx-runtime").JSX.Element; } export {};