@zapperwing/pinterest-view
Version:
A Pinterest-style grid layout component for React.js with responsive design, dynamic content support, and bulletproof virtualization
269 lines (218 loc) • 10.7 kB
Markdown
# pintrest-view
[](https://www.npmjs.com/package/@zapperwing/pintrest-view)
[](https://www.npmjs.com/package/@zapperwing/pintrest-view)
A Pinterest-style grid layout component for React.js with responsive design, dynamic content support, and **frozen layout capabilities**. Create beautiful, responsive grid layouts that automatically adjust to your content while maintaining user experience with layout control.
## Features
- 🎯 Simple API with minimal configuration required
- 📱 Responsive design with flexible column widths (pixels or percentages)
- 🌐 RTL (Right-to-Left) support for international layouts
- ↔️ Both vertical and horizontal layout options
- 🖼️ Automatic image handling with layout adjustments
- 🎨 Works with any React component
- 🚀 Optimized performance with minimal DOM operations
- 🖥️ Server-side rendering support
- 🔄 Smooth transitions during layout changes
- 🏎️ **Virtualized Rendering** – render only visible items for large grids to improve performance
- 🧊 **Frozen Layout System** – lock layouts to prevent unwanted rearrangements while allowing incremental content addition
## Installation
```bash
# Using npm
npm install @zapperwing/pintrest-view
# Using yarn
yarn add @zapperwing/pintrest-view
```
Make sure you have `react` and `react-dom` installed in your project (version 17.0.0 or higher).
## Quick Start
Here's a simple example to get you started:
```jsx
import React from "react";
import StackGrid from "@zapperwing/pintrest-view";
const SimpleGrid = () => {
return (
<StackGrid
columnWidth={300}
gutterWidth={15}
gutterHeight={15}
virtualized={true} // Enable virtualization for performance with many items
>
<div key="item1">First Item</div>
<div key="item2">Second Item</div>
<div key="item3">Third Item</div>
</StackGrid>
);
};
export default SimpleGrid;
```
## Frozen Layout Feature
The frozen layout system allows you to lock the current layout to prevent automatic rearrangements while still allowing new items to be added incrementally. This is perfect for content management systems, social media feeds, and any application where you want to maintain user context.
### Basic Frozen Layout Usage
```jsx
import React, { useState, useRef } from "react";
import StackGrid from "@zapperwing/pintrest-view";
const FrozenLayoutExample = () => {
const [items, setItems] = useState(initialItems);
const [isLayoutFrozen, setIsLayoutFrozen] = useState(false);
const [isGridReady, setIsGridReady] = useState(false);
const gridRef = useRef(null);
const handleFreezeToggle = () => {
if (gridRef.current) {
if (isLayoutFrozen) {
gridRef.current.unfreeze();
setIsLayoutFrozen(false);
} else {
gridRef.current.freeze();
setIsLayoutFrozen(true);
}
}
};
const addItems = () => {
const newItems = generateNewItems();
setItems([...items, ...newItems]);
};
return (
<div>
<button
onClick={handleFreezeToggle}
disabled={!isGridReady}
style={{
backgroundColor: isLayoutFrozen ? '#d9534f' : '#5cb85c',
color: 'white',
border: 'none',
padding: '8px 16px',
borderRadius: '4px',
cursor: 'pointer',
}}
>
{isLayoutFrozen ? 'Unfreeze Layout' : 'Freeze Layout'}
</button>
<button onClick={addItems}>Add Items</button>
<StackGrid
ref={(ref) => {
gridRef.current = ref;
setIsGridReady(!!ref);
}}
columnWidth={300}
gutterWidth={20}
gutterHeight={20}
virtualized={true}
>
{items.map(item => (
<div key={item.id}>{item.content}</div>
))}
</StackGrid>
</div>
);
};
```
### Frozen Layout API
#### Methods Available on Grid Ref
```javascript
// Freeze the current layout - prevents automatic rearrangements
gridRef.current.freeze();
// Unfreeze the layout - allows normal automatic updates
gridRef.current.unfreeze();
// Force a manual layout update
gridRef.current.layout();
```
#### How Frozen Layout Works
1. **Freeze**: When you call `freeze()`, the grid stores the current column configuration and item positions
2. **Preserve**: Existing items maintain their exact positions and don't move
3. **Add**: New items can be added and are automatically placed at the bottom of the shortest columns
4. **Measure**: The grid temporarily renders all items to measure their real heights
5. **Place**: New items are positioned using accurate height measurements
6. **Unfreeze**: When you call `unfreeze()`, normal automatic layout behavior resumes
### Use Cases for Frozen Layout
- **Content Management Systems**: Freeze layout when users are viewing content, add new posts without disrupting the current view
- **Social Media Feeds**: Prevent layout shifts when new posts load, maintain user's reading position
- **E-commerce Product Grids**: Freeze layout during product browsing, add new products without rearranging existing ones
- **Dashboard Widgets**: Lock widget positions during data updates, preserve user's dashboard configuration
## Using Custom Components
The grid can handle any React component as a child. The only requirement is that each child must have a unique `key` prop:
```jsx
import React from "react";
import StackGrid from "@zapperwing/pintrest-view";
import YourCustomCard from "./YourCustomCard";
const GridWithCustomComponents = () => {
const items = [
{ id: 1, title: "First Card", content: "Some content..." },
{ id: 2, title: "Second Card", content: "More content..." },
// ... more items
];
return (
<StackGrid
columnWidth={300}
gutterWidth={15}
gutterHeight={15}
monitorImagesLoaded={true} // Important if your components contain images
virtualized={true} // Activate virtualization for large grids
>
{items.map(item => (
<YourCustomCard
key={item.id.toString()} // Unique key is required
title={item.title}
content={item.content}
/>
))}
</StackGrid>
);
};
export default GridWithCustomComponents;
```
### Tips for Custom Components
1. **Height Calculation**: The grid automatically detects the rendered height of your components. No special configuration is needed.
2. **Images**: If your components contain images, set `monitorImagesLoaded={true}` to ensure proper layout after images load.
3. **Dynamic Content**: If your component's height might change (e.g., expandable cards), call `updateLayout()` after the change:
```jsx
const ExpandableCard = ({ content, gridRef }) => {
const [isExpanded, setIsExpanded] = useState(false);
const handleToggle = () => {
setIsExpanded(!isExpanded);
// Update grid layout after expansion/collapse
if (gridRef.current) {
gridRef.current.updateLayout();
}
};
return (
<div>
<h3>Card Title</h3>
{isExpanded ? <p>{content}</p> : null}
<button onClick={handleToggle}>
{isExpanded ? 'Show Less' : 'Show More'}
</button>
</div>
);
};
```
## Props
| Property | Type | Default | Description |
|------------------------|---------------------|-------------|-----------------------------------------------------------------------------------------------------|
| `className` | `string` | `undefined` | Additional CSS class for the grid container |
| `style` | `object` | `{}` | Additional styles for the grid container |
| `gridRef` | `function` | `null` | Ref callback to access the grid instance |
| `component` | `string` | `"div"` | HTML tag for the grid container |
| `itemComponent` | `string` | `"span"` | HTML tag for grid items |
| `columnWidth` | `number \| string` | `150` | Width of each column (px or percentage). Example: `150` or `"33.33%"` |
| `gutterWidth` | `number` | `5` | Horizontal spacing between items (px) |
| `gutterHeight` | `number` | `5` | Vertical spacing between items (px) |
| `monitorImagesLoaded` | `boolean` | `false` | Whether to monitor and reflow when images load |
| `enableSSR` | `boolean` | `false` | Enable server-side rendering support |
| `onLayout` | `function` | `null` | Callback after layout is complete |
| `horizontal` | `boolean` | `false` | Whether to use horizontal layout |
| `rtl` | `boolean` | `false` | Enable right-to-left layouts |
| `virtualized` | `boolean` | `false` | **Enable virtualization** – only render items within (or near) the viewport for better performance with large grids |
| `debug` | `boolean` | `false` | Enable debug logging for troubleshooting |
## Performance Features
### Virtualization
Enable virtualization for large grids to improve performance:
```jsx
<StackGrid virtualized={true}>
{/* Only visible items are rendered */}
</StackGrid>
```
### Frozen Layout Performance
- **Event-driven architecture** - no timeouts or polling
- **Efficient height measurement** - only measures new items
- **Maintained virtualization** - performance not compromised during frozen state
- **Single layout calculation** - updates happen in one batch
## License
MIT