Skip to content

Commit daac1c9

Browse files
committed
docs: new examples
1 parent 848a84b commit daac1c9

File tree

9 files changed

+445
-0
lines changed

9 files changed

+445
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { useMemo } from 'react'
2+
3+
export interface ControlsData {
4+
itemsCount: number
5+
frameWidth: number
6+
gap: number
7+
containerWidth: number
8+
}
9+
10+
interface ControlsProps {
11+
data: ControlsData
12+
onChange: (data: ControlsData) => void
13+
}
14+
15+
export type AspectRatio = [number, number]
16+
17+
const aspectRatios: AspectRatio[] = [
18+
[1, 1],
19+
[2, 3],
20+
[3, 2]
21+
]
22+
23+
function getRandomAspectRatio(prevAspectRatio?: AspectRatio) {
24+
const newAspectRatio =
25+
aspectRatios[Math.floor(Math.random() * aspectRatios.length)]
26+
27+
if (newAspectRatio === prevAspectRatio) {
28+
return getRandomAspectRatio(prevAspectRatio)
29+
}
30+
31+
return newAspectRatio
32+
}
33+
34+
function getRandomColor() {
35+
return `hsl(${Math.floor(Math.random() * 360)}, 100%, 75%)`
36+
}
37+
38+
export const defaultControlsData: ControlsData = {
39+
itemsCount: 35,
40+
frameWidth: 200,
41+
gap: 10,
42+
containerWidth: 100
43+
}
44+
45+
export function useItems(itemsCount: number) {
46+
return useMemo(() => {
47+
let aspectRatio: AspectRatio
48+
49+
return Array.from({
50+
length: itemsCount
51+
}, () => {
52+
aspectRatio = getRandomAspectRatio(aspectRatio)
53+
54+
const backgroundColor = getRandomColor()
55+
56+
return {
57+
width: aspectRatio[0],
58+
height: aspectRatio[1],
59+
backgroundColor
60+
}
61+
})
62+
}, [itemsCount])
63+
}
64+
65+
export function Controls({ data, onChange }: ControlsProps) {
66+
const handleChange = (key: keyof ControlsData, value: number) => {
67+
onChange({ ...data, [key]: value })
68+
}
69+
70+
return (
71+
<div className='controls'>
72+
<div className='control-group'>
73+
<label htmlFor='itemsCount'>Items Count: {data.itemsCount}</label>
74+
<input
75+
id='itemsCount'
76+
type='range'
77+
min='3'
78+
max='100'
79+
value={data.itemsCount}
80+
onChange={(e) => handleChange('itemsCount', Number(e.target.value))}
81+
/>
82+
</div>
83+
84+
<div className='control-group'>
85+
<label htmlFor='frameWidth'>Frame Width: {data.frameWidth}px</label>
86+
<input
87+
id='frameWidth'
88+
type='range'
89+
min='50'
90+
max='300'
91+
value={data.frameWidth}
92+
onChange={(e) => handleChange('frameWidth', Number(e.target.value))}
93+
/>
94+
</div>
95+
96+
<div className='control-group'>
97+
<label htmlFor='gap'>Gap: {data.gap}px</label>
98+
<input
99+
id='gap'
100+
type='range'
101+
min='0'
102+
max='40'
103+
value={data.gap}
104+
onChange={(e) => handleChange('gap', Number(e.target.value))}
105+
/>
106+
</div>
107+
108+
<div className='control-group'>
109+
<label htmlFor='containerWidth'>Container Width: {data.containerWidth}%</label>
110+
<input
111+
id='containerWidth'
112+
type='range'
113+
min='0'
114+
max='100'
115+
value={data.containerWidth}
116+
onChange={(e) => handleChange('containerWidth', Number(e.target.value))}
117+
/>
118+
</div>
119+
</div>
120+
)
121+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
* {
2+
box-sizing: border-box;
3+
margin: 0;
4+
padding: 0;
5+
}
6+
7+
body {
8+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
9+
padding: 20px;
10+
background: #f5f5f5;
11+
}
12+
13+
h1 {
14+
margin-bottom: 10px;
15+
color: #333;
16+
}
17+
18+
.description {
19+
margin-bottom: 20px;
20+
color: #666;
21+
line-height: 1.5;
22+
}
23+
24+
.controls {
25+
margin-bottom: 30px;
26+
padding: 20px;
27+
background: white;
28+
border-radius: 8px;
29+
display: grid;
30+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
31+
gap: 20px;
32+
}
33+
34+
.control-group {
35+
display: flex;
36+
flex-direction: column;
37+
gap: 8px;
38+
}
39+
40+
.control-group label {
41+
font-size: 14px;
42+
font-weight: 500;
43+
color: #555;
44+
}
45+
46+
.control-group input[type="range"] {
47+
width: 100%;
48+
height: 6px;
49+
border-radius: 3px;
50+
background: #e0e0e0;
51+
outline: none;
52+
cursor: pointer;
53+
}
54+
55+
.control-group input[type="range"]::-webkit-slider-thumb {
56+
-webkit-appearance: none;
57+
appearance: none;
58+
width: 16px;
59+
height: 16px;
60+
border-radius: 50%;
61+
background: #007bff;
62+
cursor: pointer;
63+
}
64+
65+
.control-group input[type="range"]::-moz-range-thumb {
66+
width: 16px;
67+
height: 16px;
68+
border-radius: 50%;
69+
background: #007bff;
70+
cursor: pointer;
71+
border: none;
72+
}
73+
74+
.masonry-list {
75+
list-style: none;
76+
margin: 0;
77+
padding: 0;
78+
}
79+
80+
.frame {
81+
display: flex;
82+
align-items: center;
83+
justify-content: center;
84+
font-size: 18px;
85+
font-weight: bold;
86+
color: rgba(0, 0, 0, 0.3);
87+
}
88+
89+
.container {
90+
max-width: 1200px;
91+
margin: 0 auto;
92+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Unordered List Masonry Grid - React</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/main.tsx"></script>
11+
</body>
12+
</html>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { useState } from 'react'
2+
import { createRoot } from 'react-dom/client'
3+
import {
4+
BalancedMasonryGrid,
5+
Frame
6+
} from '@masonry-grid/react'
7+
import {
8+
type ControlsData,
9+
Controls,
10+
defaultControlsData,
11+
useItems
12+
} from './controls'
13+
import './index.css'
14+
15+
function App() {
16+
const [controlsData, setControlsData] = useState<ControlsData>(defaultControlsData)
17+
const items = useItems(controlsData.itemsCount)
18+
19+
return (
20+
<div className='container'>
21+
<h1>Unordered List Masonry Grid - React</h1>
22+
<p className='description'>
23+
This example demonstrates using semantic HTML elements (ul/li) with the masonry grid.
24+
</p>
25+
26+
<Controls onChange={setControlsData} data={controlsData} />
27+
28+
<BalancedMasonryGrid
29+
as='ul'
30+
className='container masonry-list'
31+
gap={controlsData.gap}
32+
frameWidth={controlsData.frameWidth}
33+
style={{ width: `${controlsData.containerWidth}%` }}
34+
>
35+
{items.map(({ width, height, backgroundColor }, i) => (
36+
<Frame
37+
as='li'
38+
key={i}
39+
className='frame'
40+
width={width}
41+
height={height}
42+
style={{ backgroundColor }}
43+
>
44+
{i + 1}
45+
</Frame>
46+
))}
47+
</BalancedMasonryGrid>
48+
</div>
49+
)
50+
}
51+
52+
createRoot(document.getElementById('root')!).render(<App />)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"type": "module",
3+
"scripts": {
4+
"dev": "vite"
5+
},
6+
"dependencies": {
7+
"@masonry-grid/react": "^1.0.0",
8+
"react": "^19.0.0",
9+
"react-dom": "^19.0.0"
10+
},
11+
"devDependencies": {
12+
"@types/react": "^19.0.0",
13+
"@types/react-dom": "^19.0.0",
14+
"@vitejs/plugin-react": "^4.3.4",
15+
"typescript": "^5.3.3",
16+
"vite": "^7.0.0"
17+
}
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
5+
"module": "ESNext",
6+
"skipLibCheck": true,
7+
8+
"moduleResolution": "bundler",
9+
"allowImportingTsExtensions": true,
10+
"isolatedModules": true,
11+
"moduleDetection": "force",
12+
"noEmit": true,
13+
"jsx": "react-jsx",
14+
15+
"strict": true,
16+
"noUnusedLocals": true,
17+
"noUnusedParameters": true,
18+
"noFallthroughCasesInSwitch": true
19+
},
20+
"include": ["."]
21+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { defineConfig } from 'vite'
2+
import react from '@vitejs/plugin-react'
3+
4+
export default defineConfig({
5+
plugins: [react()]
6+
})

0 commit comments

Comments
 (0)