masonry-snap-grid-layout 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/esm/index.js +243 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.cts +123 -0
- package/dist/index.d.ts +122 -2
- package/dist/index.js +245 -7
- package/dist/index.js.map +1 -0
- package/package.json +17 -4
- package/src/MasonrySnapGridLayout.ts +322 -0
- package/src/index.ts +3 -1
- package/src/masonry-snap-grid-layout.css +75 -0
- package/src/types.ts +51 -0
- package/tsconfig.json +7 -6
- package/tsup.config.ts +15 -0
- package/dist/index.mjs +0 -7
- package/test.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# masonry-snap-grid-layout
|
|
2
|
+
|
|
3
|
+
A performant masonry grid layout library with smooth animations, customizable gutter, columns, and dynamic item content.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Features
|
|
8
|
+
|
|
9
|
+
- **Dynamic Columns & Gutter**: Automatically adapts to container width.
|
|
10
|
+
- **Smooth Animations**: Transitions when layout changes or items shuffle.
|
|
11
|
+
- **Customizable Item Content**: Pass your own HTML or render functions.
|
|
12
|
+
- **Lightweight & Dependency-Free**: Vanilla TypeScript for easy integration.
|
|
13
|
+
- **Responsive & Accessible**: Works well on all screen sizes.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 🔧 Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install masonry-snap-grid-layout
|
|
21
|
+
# or
|
|
22
|
+
yarn add masonry-snap-grid-layout
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 💡 Usage Example
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { MasonrySnapGridLayout } from 'masonry-snap-grid-layout';
|
|
31
|
+
|
|
32
|
+
const container = document.getElementById('masonry-container')!;
|
|
33
|
+
const masonry = new MasonrySnapGridLayout(container, {
|
|
34
|
+
gutter: 12,
|
|
35
|
+
minColWidth: 200,
|
|
36
|
+
initialItems: 20,
|
|
37
|
+
animate: true,
|
|
38
|
+
transitionDuration: 350,
|
|
39
|
+
itemContent: (index) => {
|
|
40
|
+
const div = document.createElement('div');
|
|
41
|
+
div.textContent = `Custom Item #${index + 1}`;
|
|
42
|
+
div.style.padding = '10px';
|
|
43
|
+
div.style.backgroundColor = '#ddd';
|
|
44
|
+
div.style.borderRadius = '8px';
|
|
45
|
+
return div;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## ⚙️ API
|
|
53
|
+
|
|
54
|
+
### Constructor
|
|
55
|
+
|
|
56
|
+
`new MasonrySnapGridLayout(container: HTMLElement, options?: MasonrySnapGridLayoutOptions)`
|
|
57
|
+
|
|
58
|
+
- **container** — The container element where items are rendered.
|
|
59
|
+
- **options** — Configuration options (optional).
|
|
60
|
+
|
|
61
|
+
### Methods
|
|
62
|
+
|
|
63
|
+
- `shuffleItems(): void` — Shuffle items randomly with animation.
|
|
64
|
+
- `addItems(count: number): void` — Add more items dynamically.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 🛠️ Options
|
|
69
|
+
|
|
70
|
+
| Option | Type | Default | Description |
|
|
71
|
+
|--------------------|----------------------------------|-------------|------------------------------------------|
|
|
72
|
+
| `gutter` | `number` | `16` | Spacing between items in pixels. |
|
|
73
|
+
| `minColWidth` | `number` | `250` | Minimum column width in pixels. |
|
|
74
|
+
| `animate` | `boolean` | `true` | Enable/disable animations. |
|
|
75
|
+
| `transitionDuration` | `number` | `400` | Animation duration in milliseconds. |
|
|
76
|
+
| `initialItems` | `number` | `30` | Number of items generated initially. |
|
|
77
|
+
| `classNames` | `object` | Default CSS classes | Override CSS class names for styling. |
|
|
78
|
+
| `itemContent` | `string` \| `HTMLElement` \| `(index: number) => HTMLElement \| string` | `null` | Content or content generator callback for items. |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🎨 Styling
|
|
83
|
+
|
|
84
|
+
You can customize the styles by overriding the CSS classes defined or by providing your own CSS class names through `classNames` option.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 📄 License
|
|
89
|
+
|
|
90
|
+
MIT © Aram Khachatryan
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// src/MasonrySnapGridLayout.ts
|
|
2
|
+
var MasonrySnapGridLayout = class {
|
|
3
|
+
container;
|
|
4
|
+
options;
|
|
5
|
+
classNames;
|
|
6
|
+
items = [];
|
|
7
|
+
positions = [];
|
|
8
|
+
columnHeights = [];
|
|
9
|
+
columns = 0;
|
|
10
|
+
lastPositions = [];
|
|
11
|
+
resizeRaf = null;
|
|
12
|
+
/**
|
|
13
|
+
* Constructor initializes the layout with container element and options
|
|
14
|
+
* @param container HTMLElement container where masonry items are rendered
|
|
15
|
+
* @param options configuration options for layout and styling
|
|
16
|
+
*/
|
|
17
|
+
constructor(container, options = {}) {
|
|
18
|
+
this.container = container;
|
|
19
|
+
this.options = {
|
|
20
|
+
gutter: 16,
|
|
21
|
+
minColWidth: 250,
|
|
22
|
+
animate: true,
|
|
23
|
+
transitionDuration: 400,
|
|
24
|
+
initialItems: 30,
|
|
25
|
+
itemContent: null,
|
|
26
|
+
classNames: {
|
|
27
|
+
container: "masonry-snap-grid-layout-container",
|
|
28
|
+
item: "masonry-snap-grid-layout-item",
|
|
29
|
+
itemContent: "item-content",
|
|
30
|
+
itemHeader: "item-header",
|
|
31
|
+
itemTitle: "item-title",
|
|
32
|
+
itemId: "item-id",
|
|
33
|
+
itemBody: "item-body",
|
|
34
|
+
progressBar: "progress-bar",
|
|
35
|
+
progress: "progress",
|
|
36
|
+
itemFooter: "item-footer"
|
|
37
|
+
},
|
|
38
|
+
...options
|
|
39
|
+
};
|
|
40
|
+
this.classNames = {
|
|
41
|
+
container: "masonry-snap-grid-layout-container",
|
|
42
|
+
item: "masonry-snap-grid-layout-item",
|
|
43
|
+
itemContent: "item-content",
|
|
44
|
+
itemHeader: "item-header",
|
|
45
|
+
itemTitle: "item-title",
|
|
46
|
+
itemId: "item-id",
|
|
47
|
+
itemBody: "item-body",
|
|
48
|
+
progressBar: "progress-bar",
|
|
49
|
+
progress: "progress",
|
|
50
|
+
itemFooter: "item-footer",
|
|
51
|
+
...this.options.classNames || {}
|
|
52
|
+
};
|
|
53
|
+
this.container.classList.add(this.classNames.container);
|
|
54
|
+
this.init();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Initialization: set listeners, generate initial items, layout
|
|
58
|
+
*/
|
|
59
|
+
init() {
|
|
60
|
+
this.setupEventListeners();
|
|
61
|
+
this.generateItems(this.options.initialItems);
|
|
62
|
+
this.calculateLayout();
|
|
63
|
+
this.applyLayout(false);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Setup event listeners for window resize and container resize observer
|
|
67
|
+
*/
|
|
68
|
+
setupEventListeners() {
|
|
69
|
+
const resizeObserver = new ResizeObserver(() => this.handleResize());
|
|
70
|
+
resizeObserver.observe(this.container);
|
|
71
|
+
window.addEventListener("resize", () => this.handleResize());
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generate specified number of items, removing excess if any
|
|
75
|
+
* @param count number of items to generate
|
|
76
|
+
*/
|
|
77
|
+
generateItems(count) {
|
|
78
|
+
if (count < this.items.length) {
|
|
79
|
+
this.items.slice(count).forEach((item) => item.remove());
|
|
80
|
+
this.items = this.items.slice(0, count);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const startIndex = this.items.length;
|
|
84
|
+
const fragment = document.createDocumentFragment();
|
|
85
|
+
for (let i = startIndex; i < count; i++) {
|
|
86
|
+
const item = this.createItem(i);
|
|
87
|
+
fragment.appendChild(item);
|
|
88
|
+
this.items.push(item);
|
|
89
|
+
}
|
|
90
|
+
this.container.appendChild(fragment);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create a single masonry item HTMLElement, with content from renderItemContent callback or default template
|
|
94
|
+
* @param index index of the item
|
|
95
|
+
* @returns HTMLElement for the item
|
|
96
|
+
*/
|
|
97
|
+
createItem(index) {
|
|
98
|
+
const div = document.createElement("div");
|
|
99
|
+
div.className = this.classNames.item;
|
|
100
|
+
const contentOption = this.options.itemContent;
|
|
101
|
+
let content;
|
|
102
|
+
if (typeof contentOption === "function") {
|
|
103
|
+
content = contentOption(index);
|
|
104
|
+
} else if (contentOption instanceof HTMLElement || typeof contentOption === "string") {
|
|
105
|
+
content = contentOption;
|
|
106
|
+
} else {
|
|
107
|
+
content = this.defaultItemContent(index);
|
|
108
|
+
}
|
|
109
|
+
if (typeof content === "string") {
|
|
110
|
+
div.innerHTML = content;
|
|
111
|
+
} else {
|
|
112
|
+
div.appendChild(content);
|
|
113
|
+
}
|
|
114
|
+
const height = 120 + Math.floor(Math.random() * 180);
|
|
115
|
+
div.style.height = `${height}px`;
|
|
116
|
+
const hue = index * 137.508 % 360;
|
|
117
|
+
div.style.background = `linear-gradient(135deg, hsl(${hue}, 70%, 60%), hsl(${hue + 40}, 70%, 50%))`;
|
|
118
|
+
return div;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Default item content template string
|
|
122
|
+
* @param index index of the item
|
|
123
|
+
* @returns string HTML template for item content
|
|
124
|
+
*/
|
|
125
|
+
defaultItemContent(index) {
|
|
126
|
+
return `
|
|
127
|
+
<div class="${this.classNames.itemContent}">
|
|
128
|
+
<div class="${this.classNames.itemHeader}">
|
|
129
|
+
<div class="${this.classNames.itemTitle}">Item ${index + 1}</div>
|
|
130
|
+
<div class="${this.classNames.itemId}">#${index + 1}</div>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="${this.classNames.itemBody}">
|
|
133
|
+
<div class="${this.classNames.progressBar}">
|
|
134
|
+
<div class="${this.classNames.progress}"></div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="${this.classNames.itemFooter}">
|
|
138
|
+
${this.getRandomEmoji()}
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Returns a random emoji from a fixed set for item footer
|
|
145
|
+
*/
|
|
146
|
+
getRandomEmoji() {
|
|
147
|
+
const emojis = ["\u{1F680}", "\u2728", "\u{1F525}", "\u{1F4A1}", "\u{1F31F}", "\u{1F3AF}", "\u26A1", "\u{1F4BB}", "\u{1F527}", "\u{1F4CA}"];
|
|
148
|
+
return emojis[Math.floor(Math.random() * emojis.length)];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Calculate positions of each item in masonry grid based on container width, gutter, min column width
|
|
152
|
+
*/
|
|
153
|
+
calculateLayout() {
|
|
154
|
+
const { gutter, minColWidth } = this.options;
|
|
155
|
+
const containerWidth = this.container.clientWidth;
|
|
156
|
+
this.columns = Math.max(1, Math.floor((containerWidth + gutter) / (minColWidth + gutter)));
|
|
157
|
+
const colWidth = (containerWidth - (this.columns - 1) * gutter) / this.columns;
|
|
158
|
+
this.lastPositions = [...this.positions];
|
|
159
|
+
this.columnHeights = new Array(this.columns).fill(0);
|
|
160
|
+
this.positions = [];
|
|
161
|
+
this.items.forEach((item, i) => {
|
|
162
|
+
const height = item.offsetHeight;
|
|
163
|
+
let minCol = 0;
|
|
164
|
+
for (let c = 1; c < this.columns; c++) {
|
|
165
|
+
if (this.columnHeights[c] < this.columnHeights[minCol]) {
|
|
166
|
+
minCol = c;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const x = minCol * (colWidth + gutter);
|
|
170
|
+
const y = this.columnHeights[minCol];
|
|
171
|
+
this.positions[i] = { x, y, width: colWidth, height };
|
|
172
|
+
this.columnHeights[minCol] += height + gutter;
|
|
173
|
+
});
|
|
174
|
+
const maxHeight = Math.max(...this.columnHeights);
|
|
175
|
+
this.container.style.height = `${maxHeight}px`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Apply calculated positions to each item with optional animation
|
|
179
|
+
* @param animate whether to animate layout changes (default false)
|
|
180
|
+
*/
|
|
181
|
+
applyLayout(animate = false) {
|
|
182
|
+
const duration = this.options.transitionDuration;
|
|
183
|
+
this.items.forEach((item, i) => {
|
|
184
|
+
const pos = this.positions[i] || { x: 0, y: 0, width: 0 };
|
|
185
|
+
const lastPos = this.lastPositions[i] || { x: 0, y: 0 };
|
|
186
|
+
item.style.width = `${pos.width}px`;
|
|
187
|
+
if (animate) {
|
|
188
|
+
const dx = lastPos.x - pos.x;
|
|
189
|
+
const dy = lastPos.y - pos.y;
|
|
190
|
+
item.style.transition = "none";
|
|
191
|
+
item.style.transform = `translate3d(${pos.x + dx}px, ${pos.y + dy}px, 0)`;
|
|
192
|
+
void item.offsetHeight;
|
|
193
|
+
item.style.transition = `transform ${duration}ms cubic-bezier(0.4, 0, 0.2, 1)`;
|
|
194
|
+
item.style.transform = `translate3d(${pos.x}px, ${pos.y}px, 0)`;
|
|
195
|
+
} else {
|
|
196
|
+
item.style.transition = "none";
|
|
197
|
+
item.style.transform = `translate3d(${pos.x}px, ${pos.y}px, 0)`;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Handle container resize using RAF to optimize performance
|
|
203
|
+
*/
|
|
204
|
+
handleResize() {
|
|
205
|
+
if (this.resizeRaf) cancelAnimationFrame(this.resizeRaf);
|
|
206
|
+
this.resizeRaf = requestAnimationFrame(() => {
|
|
207
|
+
this.calculateLayout();
|
|
208
|
+
this.applyLayout(true);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Shuffle items randomly and reapply layout with animation
|
|
213
|
+
*/
|
|
214
|
+
shuffleItems() {
|
|
215
|
+
for (let i = this.items.length - 1; i > 0; i--) {
|
|
216
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
217
|
+
[this.items[i], this.items[j]] = [this.items[j], this.items[i]];
|
|
218
|
+
}
|
|
219
|
+
const fragment = document.createDocumentFragment();
|
|
220
|
+
this.items.forEach((item) => fragment.appendChild(item));
|
|
221
|
+
this.container.appendChild(fragment);
|
|
222
|
+
this.calculateLayout();
|
|
223
|
+
this.applyLayout(true);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Add more items dynamically
|
|
227
|
+
* @param count number of items to add
|
|
228
|
+
*/
|
|
229
|
+
addItems(count) {
|
|
230
|
+
const newCount = this.items.length + count;
|
|
231
|
+
this.generateItems(newCount);
|
|
232
|
+
this.calculateLayout();
|
|
233
|
+
this.applyLayout(true);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// src/index.ts
|
|
238
|
+
var index_default = MasonrySnapGridLayout;
|
|
239
|
+
export {
|
|
240
|
+
MasonrySnapGridLayout,
|
|
241
|
+
index_default as default
|
|
242
|
+
};
|
|
243
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/MasonrySnapGridLayout.ts","../../src/index.ts"],"sourcesContent":["/**\r\n * MasonrySnapGridLayout\r\n * A performant masonry grid layout library with smooth animations,\r\n * customizable gutter, columns, and dynamic item content.\r\n *\r\n * Package name: masonry-snap-grid-layout\r\n */\r\n\r\nimport { MasonrySnapGridLayoutClassNames, MasonrySnapGridLayoutOptions } from \"./types\";\r\n\r\nexport default class MasonrySnapGridLayout {\r\n private readonly container: HTMLElement;\r\n private readonly options: Required<MasonrySnapGridLayoutOptions>;\r\n private classNames: Required<MasonrySnapGridLayoutClassNames>;\r\n\r\n private items: HTMLElement[] = [];\r\n private positions: { x: number; y: number; width: number; height: number }[] = [];\r\n private columnHeights: number[] = [];\r\n private columns: number = 0;\r\n private lastPositions: typeof this.positions = [];\r\n private resizeRaf: number | null = null;\r\n\r\n /**\r\n * Constructor initializes the layout with container element and options\r\n * @param container HTMLElement container where masonry items are rendered\r\n * @param options configuration options for layout and styling\r\n */\r\n constructor(container: HTMLElement, options: MasonrySnapGridLayoutOptions = {}) {\r\n this.container = container;\r\n\r\n // Set default options with overrides from user\r\n this.options = {\r\n gutter: 16,\r\n minColWidth: 250,\r\n animate: true,\r\n transitionDuration: 400,\r\n initialItems: 30,\r\n itemContent: null,\r\n classNames: {\r\n container: \"masonry-snap-grid-layout-container\",\r\n item: \"masonry-snap-grid-layout-item\",\r\n itemContent: \"item-content\",\r\n itemHeader: \"item-header\",\r\n itemTitle: \"item-title\",\r\n itemId: \"item-id\",\r\n itemBody: \"item-body\",\r\n progressBar: \"progress-bar\",\r\n progress: \"progress\",\r\n itemFooter: \"item-footer\",\r\n },\r\n ...options,\r\n };\r\n\r\n // Merge default classNames with user provided classNames\r\n this.classNames = {\r\n container: \"masonry-snap-grid-layout-container\",\r\n item: \"masonry-snap-grid-layout-item\",\r\n itemContent: \"item-content\",\r\n itemHeader: \"item-header\",\r\n itemTitle: \"item-title\",\r\n itemId: \"item-id\",\r\n itemBody: \"item-body\",\r\n progressBar: \"progress-bar\",\r\n progress: \"progress\",\r\n itemFooter: \"item-footer\",\r\n ...(this.options.classNames || {}),\r\n };\r\n\r\n // Add container class for styling\r\n this.container.classList.add(this.classNames.container);\r\n\r\n // Initialize the layout\r\n this.init();\r\n }\r\n\r\n /**\r\n * Initialization: set listeners, generate initial items, layout\r\n */\r\n private init() {\r\n this.setupEventListeners();\r\n this.generateItems(this.options.initialItems);\r\n this.calculateLayout();\r\n this.applyLayout(false);\r\n }\r\n\r\n /**\r\n * Setup event listeners for window resize and container resize observer\r\n */\r\n private setupEventListeners() {\r\n // Use ResizeObserver to handle container size changes\r\n const resizeObserver = new ResizeObserver(() => this.handleResize());\r\n resizeObserver.observe(this.container);\r\n\r\n window.addEventListener(\"resize\", () => this.handleResize());\r\n }\r\n\r\n /**\r\n * Generate specified number of items, removing excess if any\r\n * @param count number of items to generate\r\n */\r\n private generateItems(count: number) {\r\n // Remove extra items if reducing count\r\n if (count < this.items.length) {\r\n this.items.slice(count).forEach((item) => item.remove());\r\n this.items = this.items.slice(0, count);\r\n return;\r\n }\r\n\r\n const startIndex = this.items.length;\r\n const fragment = document.createDocumentFragment();\r\n\r\n for (let i = startIndex; i < count; i++) {\r\n const item = this.createItem(i);\r\n fragment.appendChild(item);\r\n this.items.push(item);\r\n }\r\n\r\n this.container.appendChild(fragment);\r\n }\r\n\r\n /**\r\n * Create a single masonry item HTMLElement, with content from renderItemContent callback or default template\r\n * @param index index of the item\r\n * @returns HTMLElement for the item\r\n */\r\n private createItem(index: number): HTMLElement {\r\n const div = document.createElement(\"div\");\r\n div.className = this.classNames.item;\r\n\r\n const contentOption = this.options.itemContent;\r\n\r\n // Determine content type: function, static HTMLElement, static string, or fallback to default\r\n let content: HTMLElement | string;\r\n\r\n if (typeof contentOption === \"function\") {\r\n // Call function with index to get content\r\n content = contentOption(index);\r\n } else if (contentOption instanceof HTMLElement || typeof contentOption === \"string\") {\r\n // Use static content\r\n content = contentOption;\r\n } else {\r\n // Fallback to default item content template string\r\n content = this.defaultItemContent(index);\r\n }\r\n\r\n // Insert content into item element\r\n if (typeof content === \"string\") {\r\n div.innerHTML = content;\r\n } else {\r\n div.appendChild(content);\r\n }\r\n\r\n // Random height to simulate masonry effect\r\n const height = 120 + Math.floor(Math.random() * 180);\r\n div.style.height = `${height}px`;\r\n\r\n // Color with HSL for distinct appearance\r\n const hue = (index * 137.508) % 360; // golden angle\r\n div.style.background = `linear-gradient(135deg, hsl(${hue}, 70%, 60%), hsl(${hue + 40}, 70%, 50%))`;\r\n\r\n return div;\r\n }\r\n\r\n /**\r\n * Default item content template string\r\n * @param index index of the item\r\n * @returns string HTML template for item content\r\n */\r\n private defaultItemContent(index: number): string {\r\n return `\r\n <div class=\"${this.classNames.itemContent}\">\r\n <div class=\"${this.classNames.itemHeader}\">\r\n <div class=\"${this.classNames.itemTitle}\">Item ${index + 1}</div>\r\n <div class=\"${this.classNames.itemId}\">#${index + 1}</div>\r\n </div>\r\n <div class=\"${this.classNames.itemBody}\">\r\n <div class=\"${this.classNames.progressBar}\">\r\n <div class=\"${this.classNames.progress}\"></div>\r\n </div>\r\n </div>\r\n <div class=\"${this.classNames.itemFooter}\">\r\n ${this.getRandomEmoji()}\r\n </div>\r\n </div>\r\n `;\r\n }\r\n\r\n /**\r\n * Returns a random emoji from a fixed set for item footer\r\n */\r\n private getRandomEmoji(): string {\r\n const emojis = [\"🚀\", \"✨\", \"🔥\", \"💡\", \"🌟\", \"🎯\", \"⚡\", \"💻\", \"🔧\", \"📊\"];\r\n return emojis[Math.floor(Math.random() * emojis.length)];\r\n }\r\n\r\n /**\r\n * Calculate positions of each item in masonry grid based on container width, gutter, min column width\r\n */\r\n private calculateLayout() {\r\n const { gutter, minColWidth } = this.options;\r\n const containerWidth = this.container.clientWidth;\r\n\r\n // Calculate number of columns that fit\r\n this.columns = Math.max(1, Math.floor((containerWidth + gutter) / (minColWidth + gutter)));\r\n\r\n // Calculate each column width\r\n const colWidth = (containerWidth - (this.columns - 1) * gutter) / this.columns;\r\n\r\n // Store previous positions for animation\r\n this.lastPositions = [...this.positions];\r\n\r\n // Reset column heights array\r\n this.columnHeights = new Array(this.columns).fill(0);\r\n this.positions = [];\r\n\r\n // Calculate position for each item and assign column\r\n this.items.forEach((item, i) => {\r\n const height = item.offsetHeight;\r\n\r\n // Find the shortest column index\r\n let minCol = 0;\r\n for (let c = 1; c < this.columns; c++) {\r\n if (this.columnHeights[c] < this.columnHeights[minCol]) {\r\n minCol = c;\r\n }\r\n }\r\n\r\n // Calculate item's x,y position\r\n const x = minCol * (colWidth + gutter);\r\n const y = this.columnHeights[minCol];\r\n\r\n // Save calculated position\r\n this.positions[i] = { x, y, width: colWidth, height };\r\n\r\n // Update column height to include this item + gutter\r\n this.columnHeights[minCol] += height + gutter;\r\n });\r\n\r\n // Set container height to max column height for proper scrolling\r\n const maxHeight = Math.max(...this.columnHeights);\r\n this.container.style.height = `${maxHeight}px`;\r\n }\r\n\r\n /**\r\n * Apply calculated positions to each item with optional animation\r\n * @param animate whether to animate layout changes (default false)\r\n */\r\n private applyLayout(animate: boolean = false) {\r\n const duration = this.options.transitionDuration;\r\n\r\n this.items.forEach((item, i) => {\r\n const pos = this.positions[i] || { x: 0, y: 0, width: 0 };\r\n const lastPos = this.lastPositions[i] || { x: 0, y: 0 };\r\n\r\n // Set item width for responsive columns\r\n item.style.width = `${pos.width}px`;\r\n\r\n if (animate) {\r\n // Calculate differences for smooth animation\r\n const dx = lastPos.x - pos.x;\r\n const dy = lastPos.y - pos.y;\r\n\r\n // Apply initial transform to old position (without transition)\r\n item.style.transition = \"none\";\r\n item.style.transform = `translate3d(${pos.x + dx}px, ${pos.y + dy}px, 0)`;\r\n\r\n // Trigger reflow to apply the style immediately\r\n void item.offsetHeight;\r\n\r\n // Animate transform to new position\r\n item.style.transition = `transform ${duration}ms cubic-bezier(0.4, 0, 0.2, 1)`;\r\n item.style.transform = `translate3d(${pos.x}px, ${pos.y}px, 0)`;\r\n } else {\r\n // Directly set transform without animation\r\n item.style.transition = \"none\";\r\n item.style.transform = `translate3d(${pos.x}px, ${pos.y}px, 0)`;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handle container resize using RAF to optimize performance\r\n */\r\n private handleResize() {\r\n if (this.resizeRaf) cancelAnimationFrame(this.resizeRaf);\r\n this.resizeRaf = requestAnimationFrame(() => {\r\n this.calculateLayout();\r\n this.applyLayout(true);\r\n });\r\n }\r\n\r\n /**\r\n * Shuffle items randomly and reapply layout with animation\r\n */\r\n public shuffleItems() {\r\n // Fisher-Yates shuffle algorithm\r\n for (let i = this.items.length - 1; i > 0; i--) {\r\n const j = Math.floor(Math.random() * (i + 1));\r\n [this.items[i], this.items[j]] = [this.items[j], this.items[i]];\r\n }\r\n\r\n // Re-append items in new order in DOM\r\n const fragment = document.createDocumentFragment();\r\n this.items.forEach((item) => fragment.appendChild(item));\r\n this.container.appendChild(fragment);\r\n\r\n // Update layout positions and animate\r\n this.calculateLayout();\r\n this.applyLayout(true);\r\n }\r\n\r\n /**\r\n * Add more items dynamically\r\n * @param count number of items to add\r\n */\r\n public addItems(count: number) {\r\n const newCount = this.items.length + count;\r\n this.generateItems(newCount);\r\n this.calculateLayout();\r\n this.applyLayout(true);\r\n }\r\n}\r\n","import MasonrySnapGridLayout from './MasonrySnapGridLayout';\nexport default MasonrySnapGridLayout;\nexport { MasonrySnapGridLayout };"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MasonrySnapGridLayoutClassNames
|
|
3
|
+
* Optional CSS class names to override default styling selectors.
|
|
4
|
+
* Enables user to customize CSS classes easily.
|
|
5
|
+
*/
|
|
6
|
+
interface MasonrySnapGridLayoutClassNames {
|
|
7
|
+
container?: string;
|
|
8
|
+
item?: string;
|
|
9
|
+
itemContent?: string;
|
|
10
|
+
itemHeader?: string;
|
|
11
|
+
itemTitle?: string;
|
|
12
|
+
itemId?: string;
|
|
13
|
+
itemBody?: string;
|
|
14
|
+
progressBar?: string;
|
|
15
|
+
progress?: string;
|
|
16
|
+
itemFooter?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* MasonrySnapGridLayoutOptions
|
|
20
|
+
* Configuration options accepted by MasonrySnapGridLayout.
|
|
21
|
+
*/
|
|
22
|
+
interface MasonrySnapGridLayoutOptions {
|
|
23
|
+
/** Spacing between items in pixels (default: 16) */
|
|
24
|
+
gutter?: number;
|
|
25
|
+
/** Minimum width for each column in pixels (default: 250) */
|
|
26
|
+
minColWidth?: number;
|
|
27
|
+
/** Enable or disable animations (default: true) */
|
|
28
|
+
animate?: boolean;
|
|
29
|
+
/** Duration of animation transitions in milliseconds (default: 400) */
|
|
30
|
+
transitionDuration?: number;
|
|
31
|
+
/** Initial number of items to generate on init (default: 30) */
|
|
32
|
+
initialItems?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Optional class names object to override default CSS class names
|
|
35
|
+
*/
|
|
36
|
+
classNames?: MasonrySnapGridLayoutClassNames;
|
|
37
|
+
/**
|
|
38
|
+
* Item content can be:
|
|
39
|
+
* - a callback function that receives the item index and returns an HTMLElement or string (HTML markup),
|
|
40
|
+
* - a static HTMLElement or string (HTML markup) for all items,
|
|
41
|
+
* - or null to use the default template.
|
|
42
|
+
*/
|
|
43
|
+
itemContent?: ((index: number) => HTMLElement | string) | HTMLElement | string | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* MasonrySnapGridLayout
|
|
48
|
+
* A performant masonry grid layout library with smooth animations,
|
|
49
|
+
* customizable gutter, columns, and dynamic item content.
|
|
50
|
+
*
|
|
51
|
+
* Package name: masonry-snap-grid-layout
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
declare class MasonrySnapGridLayout {
|
|
55
|
+
private readonly container;
|
|
56
|
+
private readonly options;
|
|
57
|
+
private classNames;
|
|
58
|
+
private items;
|
|
59
|
+
private positions;
|
|
60
|
+
private columnHeights;
|
|
61
|
+
private columns;
|
|
62
|
+
private lastPositions;
|
|
63
|
+
private resizeRaf;
|
|
64
|
+
/**
|
|
65
|
+
* Constructor initializes the layout with container element and options
|
|
66
|
+
* @param container HTMLElement container where masonry items are rendered
|
|
67
|
+
* @param options configuration options for layout and styling
|
|
68
|
+
*/
|
|
69
|
+
constructor(container: HTMLElement, options?: MasonrySnapGridLayoutOptions);
|
|
70
|
+
/**
|
|
71
|
+
* Initialization: set listeners, generate initial items, layout
|
|
72
|
+
*/
|
|
73
|
+
private init;
|
|
74
|
+
/**
|
|
75
|
+
* Setup event listeners for window resize and container resize observer
|
|
76
|
+
*/
|
|
77
|
+
private setupEventListeners;
|
|
78
|
+
/**
|
|
79
|
+
* Generate specified number of items, removing excess if any
|
|
80
|
+
* @param count number of items to generate
|
|
81
|
+
*/
|
|
82
|
+
private generateItems;
|
|
83
|
+
/**
|
|
84
|
+
* Create a single masonry item HTMLElement, with content from renderItemContent callback or default template
|
|
85
|
+
* @param index index of the item
|
|
86
|
+
* @returns HTMLElement for the item
|
|
87
|
+
*/
|
|
88
|
+
private createItem;
|
|
89
|
+
/**
|
|
90
|
+
* Default item content template string
|
|
91
|
+
* @param index index of the item
|
|
92
|
+
* @returns string HTML template for item content
|
|
93
|
+
*/
|
|
94
|
+
private defaultItemContent;
|
|
95
|
+
/**
|
|
96
|
+
* Returns a random emoji from a fixed set for item footer
|
|
97
|
+
*/
|
|
98
|
+
private getRandomEmoji;
|
|
99
|
+
/**
|
|
100
|
+
* Calculate positions of each item in masonry grid based on container width, gutter, min column width
|
|
101
|
+
*/
|
|
102
|
+
private calculateLayout;
|
|
103
|
+
/**
|
|
104
|
+
* Apply calculated positions to each item with optional animation
|
|
105
|
+
* @param animate whether to animate layout changes (default false)
|
|
106
|
+
*/
|
|
107
|
+
private applyLayout;
|
|
108
|
+
/**
|
|
109
|
+
* Handle container resize using RAF to optimize performance
|
|
110
|
+
*/
|
|
111
|
+
private handleResize;
|
|
112
|
+
/**
|
|
113
|
+
* Shuffle items randomly and reapply layout with animation
|
|
114
|
+
*/
|
|
115
|
+
shuffleItems(): void;
|
|
116
|
+
/**
|
|
117
|
+
* Add more items dynamically
|
|
118
|
+
* @param count number of items to add
|
|
119
|
+
*/
|
|
120
|
+
addItems(count: number): void;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { MasonrySnapGridLayout, MasonrySnapGridLayout as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,123 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* MasonrySnapGridLayoutClassNames
|
|
3
|
+
* Optional CSS class names to override default styling selectors.
|
|
4
|
+
* Enables user to customize CSS classes easily.
|
|
5
|
+
*/
|
|
6
|
+
interface MasonrySnapGridLayoutClassNames {
|
|
7
|
+
container?: string;
|
|
8
|
+
item?: string;
|
|
9
|
+
itemContent?: string;
|
|
10
|
+
itemHeader?: string;
|
|
11
|
+
itemTitle?: string;
|
|
12
|
+
itemId?: string;
|
|
13
|
+
itemBody?: string;
|
|
14
|
+
progressBar?: string;
|
|
15
|
+
progress?: string;
|
|
16
|
+
itemFooter?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* MasonrySnapGridLayoutOptions
|
|
20
|
+
* Configuration options accepted by MasonrySnapGridLayout.
|
|
21
|
+
*/
|
|
22
|
+
interface MasonrySnapGridLayoutOptions {
|
|
23
|
+
/** Spacing between items in pixels (default: 16) */
|
|
24
|
+
gutter?: number;
|
|
25
|
+
/** Minimum width for each column in pixels (default: 250) */
|
|
26
|
+
minColWidth?: number;
|
|
27
|
+
/** Enable or disable animations (default: true) */
|
|
28
|
+
animate?: boolean;
|
|
29
|
+
/** Duration of animation transitions in milliseconds (default: 400) */
|
|
30
|
+
transitionDuration?: number;
|
|
31
|
+
/** Initial number of items to generate on init (default: 30) */
|
|
32
|
+
initialItems?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Optional class names object to override default CSS class names
|
|
35
|
+
*/
|
|
36
|
+
classNames?: MasonrySnapGridLayoutClassNames;
|
|
37
|
+
/**
|
|
38
|
+
* Item content can be:
|
|
39
|
+
* - a callback function that receives the item index and returns an HTMLElement or string (HTML markup),
|
|
40
|
+
* - a static HTMLElement or string (HTML markup) for all items,
|
|
41
|
+
* - or null to use the default template.
|
|
42
|
+
*/
|
|
43
|
+
itemContent?: ((index: number) => HTMLElement | string) | HTMLElement | string | null;
|
|
44
|
+
}
|
|
2
45
|
|
|
3
|
-
|
|
46
|
+
/**
|
|
47
|
+
* MasonrySnapGridLayout
|
|
48
|
+
* A performant masonry grid layout library with smooth animations,
|
|
49
|
+
* customizable gutter, columns, and dynamic item content.
|
|
50
|
+
*
|
|
51
|
+
* Package name: masonry-snap-grid-layout
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
declare class MasonrySnapGridLayout {
|
|
55
|
+
private readonly container;
|
|
56
|
+
private readonly options;
|
|
57
|
+
private classNames;
|
|
58
|
+
private items;
|
|
59
|
+
private positions;
|
|
60
|
+
private columnHeights;
|
|
61
|
+
private columns;
|
|
62
|
+
private lastPositions;
|
|
63
|
+
private resizeRaf;
|
|
64
|
+
/**
|
|
65
|
+
* Constructor initializes the layout with container element and options
|
|
66
|
+
* @param container HTMLElement container where masonry items are rendered
|
|
67
|
+
* @param options configuration options for layout and styling
|
|
68
|
+
*/
|
|
69
|
+
constructor(container: HTMLElement, options?: MasonrySnapGridLayoutOptions);
|
|
70
|
+
/**
|
|
71
|
+
* Initialization: set listeners, generate initial items, layout
|
|
72
|
+
*/
|
|
73
|
+
private init;
|
|
74
|
+
/**
|
|
75
|
+
* Setup event listeners for window resize and container resize observer
|
|
76
|
+
*/
|
|
77
|
+
private setupEventListeners;
|
|
78
|
+
/**
|
|
79
|
+
* Generate specified number of items, removing excess if any
|
|
80
|
+
* @param count number of items to generate
|
|
81
|
+
*/
|
|
82
|
+
private generateItems;
|
|
83
|
+
/**
|
|
84
|
+
* Create a single masonry item HTMLElement, with content from renderItemContent callback or default template
|
|
85
|
+
* @param index index of the item
|
|
86
|
+
* @returns HTMLElement for the item
|
|
87
|
+
*/
|
|
88
|
+
private createItem;
|
|
89
|
+
/**
|
|
90
|
+
* Default item content template string
|
|
91
|
+
* @param index index of the item
|
|
92
|
+
* @returns string HTML template for item content
|
|
93
|
+
*/
|
|
94
|
+
private defaultItemContent;
|
|
95
|
+
/**
|
|
96
|
+
* Returns a random emoji from a fixed set for item footer
|
|
97
|
+
*/
|
|
98
|
+
private getRandomEmoji;
|
|
99
|
+
/**
|
|
100
|
+
* Calculate positions of each item in masonry grid based on container width, gutter, min column width
|
|
101
|
+
*/
|
|
102
|
+
private calculateLayout;
|
|
103
|
+
/**
|
|
104
|
+
* Apply calculated positions to each item with optional animation
|
|
105
|
+
* @param animate whether to animate layout changes (default false)
|
|
106
|
+
*/
|
|
107
|
+
private applyLayout;
|
|
108
|
+
/**
|
|
109
|
+
* Handle container resize using RAF to optimize performance
|
|
110
|
+
*/
|
|
111
|
+
private handleResize;
|
|
112
|
+
/**
|
|
113
|
+
* Shuffle items randomly and reapply layout with animation
|
|
114
|
+
*/
|
|
115
|
+
shuffleItems(): void;
|
|
116
|
+
/**
|
|
117
|
+
* Add more items dynamically
|
|
118
|
+
* @param count number of items to add
|
|
119
|
+
*/
|
|
120
|
+
addItems(count: number): void;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { MasonrySnapGridLayout, MasonrySnapGridLayout as default };
|