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 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":[]}
@@ -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
- declare const masonrySnapGridLayout: () => void;
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
- export { masonrySnapGridLayout };
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 };