masonry-snap-grid-layout 1.0.6 → 1.0.8
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/dist/esm/react.js +9 -10
- package/dist/esm/react.js.map +1 -1
- package/dist/react.d.cts +5 -2
- package/dist/react.d.ts +5 -2
- package/dist/react.js +8 -8
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/esm/react.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
useEffect,
|
|
4
4
|
useRef,
|
|
5
|
-
forwardRef
|
|
6
|
-
useImperativeHandle
|
|
5
|
+
forwardRef
|
|
7
6
|
} from "react";
|
|
8
7
|
import ReactDOM from "react-dom/client";
|
|
9
8
|
|
|
@@ -86,13 +85,13 @@ var MasonrySnapGridLayout = class {
|
|
|
86
85
|
|
|
87
86
|
// src/react.tsx
|
|
88
87
|
import { jsx } from "react/jsx-runtime";
|
|
89
|
-
|
|
88
|
+
var MasonrySnapGridInner = ({
|
|
90
89
|
items,
|
|
91
90
|
renderItem,
|
|
92
91
|
className,
|
|
93
92
|
style,
|
|
94
93
|
...options
|
|
95
|
-
}, ref) {
|
|
94
|
+
}, ref) => {
|
|
96
95
|
const containerRef = useRef(null);
|
|
97
96
|
const masonryRef = useRef(null);
|
|
98
97
|
const rootsRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -110,7 +109,10 @@ function MasonrySnapGridInner({
|
|
|
110
109
|
}
|
|
111
110
|
});
|
|
112
111
|
return () => {
|
|
113
|
-
rootsRef.current.forEach((root) =>
|
|
112
|
+
rootsRef.current.forEach((root, div) => {
|
|
113
|
+
root.unmount();
|
|
114
|
+
div.remove();
|
|
115
|
+
});
|
|
114
116
|
rootsRef.current.clear();
|
|
115
117
|
masonryRef.current?.destroy();
|
|
116
118
|
masonryRef.current = null;
|
|
@@ -121,9 +123,6 @@ function MasonrySnapGridInner({
|
|
|
121
123
|
masonryRef.current.updateItems(items);
|
|
122
124
|
}
|
|
123
125
|
}, [items]);
|
|
124
|
-
useImperativeHandle(ref, () => ({
|
|
125
|
-
layout: masonryRef.current
|
|
126
|
-
}));
|
|
127
126
|
return /* @__PURE__ */ jsx(
|
|
128
127
|
"div",
|
|
129
128
|
{
|
|
@@ -132,9 +131,9 @@ function MasonrySnapGridInner({
|
|
|
132
131
|
style: { position: "relative", width: "100%", ...style }
|
|
133
132
|
}
|
|
134
133
|
);
|
|
135
|
-
}
|
|
134
|
+
};
|
|
136
135
|
var MasonrySnapGrid = forwardRef(MasonrySnapGridInner);
|
|
137
|
-
var react_default =
|
|
136
|
+
var react_default = MasonrySnapGrid;
|
|
138
137
|
export {
|
|
139
138
|
react_default as default
|
|
140
139
|
};
|
package/dist/esm/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react.tsx","../../src/MasonrySnapGridLayout.ts"],"sourcesContent":["import React, {\r\n useEffect,\r\n useRef,\r\n forwardRef,\r\n useImperativeHandle,\r\n} from 'react';\r\nimport ReactDOM from 'react-dom/client';\r\nimport MasonrySnapGridLayout from './MasonrySnapGridLayout';\r\nimport {\r\n MasonrySnapGridLayoutOptions,\r\n MasonrySnapGridRef,\r\n} from './types';\r\n\r\ninterface MasonrySnapGridProps<T>\r\n extends Omit<MasonrySnapGridLayoutOptions<T>, 'items' | 'renderItem'> {\r\n items: T[];\r\n renderItem: (item: T) => React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\nfunction MasonrySnapGridInner<T>(\r\n {\r\n items,\r\n renderItem,\r\n className,\r\n style,\r\n ...options\r\n }: MasonrySnapGridProps<T>,\r\n ref: React.Ref<MasonrySnapGridRef>\r\n) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const masonryRef = useRef<MasonrySnapGridLayout<T> | null>(null);\r\n\r\n // React roots storage to prevent memory leaks\r\n const rootsRef = useRef<Map<HTMLElement, ReactDOM.Root>>(new Map());\r\n\r\n // Initialize masonry layout\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n masonryRef.current = new MasonrySnapGridLayout(containerRef.current, {\r\n ...options,\r\n items,\r\n renderItem: (item) => {\r\n const div = document.createElement('div');\r\n const root = ReactDOM.createRoot(div);\r\n root.render(renderItem(item));\r\n rootsRef.current.set(div, root);\r\n return div;\r\n },\r\n });\r\n\r\n return () => {\r\n // Unmount all React roots to avoid memory leaks\r\n rootsRef.current.forEach((root) => root.unmount());\r\n rootsRef.current.clear();\r\n\r\n masonryRef.current?.destroy();\r\n masonryRef.current = null;\r\n };\r\n }, [options, renderItem]); // include renderItem if it's not memoized\r\n\r\n // Update items on change\r\n useEffect(() => {\r\n if (masonryRef.current) {\r\n masonryRef.current.updateItems(items);\r\n }\r\n }, [items]);\r\n\r\n // Expose layout instance through ref\r\n useImperativeHandle(ref, () => ({\r\n layout: masonryRef.current!,\r\n }));\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n className={className}\r\n style={{ position: 'relative', width: '100%', ...style }}\r\n />\r\n );\r\n}\r\n\r\n// Apply generic type correctly to forwardRef\r\nconst MasonrySnapGrid = forwardRef(MasonrySnapGridInner) as <T>(\r\n props: MasonrySnapGridProps<T> & { ref?: React.Ref<MasonrySnapGridRef> }\r\n) => ReturnType<typeof MasonrySnapGridInner>;\r\n\r\nexport default MasonrySnapGridInner\r\n","import { MasonrySnapGridLayoutOptions } from './types';\r\n\r\nexport default class MasonrySnapGridLayout<T = any> {\r\n private readonly container: HTMLElement;\r\n private readonly options: Required<MasonrySnapGridLayoutOptions<T>>;\r\n private items: HTMLElement[] = [];\r\n private columnHeights: number[] = [];\r\n private resizeObserver: ResizeObserver | undefined;\r\n private rafId: number | null = null;\r\n\r\n constructor(container: HTMLElement, options: MasonrySnapGridLayoutOptions<T>) {\r\n this.container = container;\r\n this.options = {\r\n gutter: 16,\r\n minColWidth: 250,\r\n animate: true,\r\n transitionDuration: 400,\r\n classNames: {\r\n container: 'masonry-snap-grid-container',\r\n item: 'masonry-snap-grid-item',\r\n },\r\n ...options,\r\n };\r\n\r\n // Apply container class\r\n this.container.classList.add(this.options.classNames.container || \"\");\r\n\r\n // Initialize\r\n this.renderItems();\r\n this.setupResizeObserver();\r\n }\r\n\r\n private renderItems() {\r\n // Clear existing items\r\n this.items.forEach(item => item.remove());\r\n this.items = [];\r\n\r\n // Create fragment for batch DOM insertion\r\n const fragment = document.createDocumentFragment();\r\n\r\n // Create and append items\r\n this.options.items.forEach(itemData => {\r\n const itemElement = this.options.renderItem(itemData);\r\n itemElement.classList.add(this.options.classNames.item|| \"\");\r\n fragment.appendChild(itemElement);\r\n this.items.push(itemElement);\r\n });\r\n\r\n this.container.appendChild(fragment);\r\n this.updateLayout();\r\n }\r\n\r\n private setupResizeObserver() {\r\n this.resizeObserver = new ResizeObserver(() => {\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.rafId = requestAnimationFrame(() => this.updateLayout());\r\n });\r\n this.resizeObserver.observe(this.container);\r\n }\r\n\r\n private updateLayout() {\r\n const { gutter, minColWidth, animate, transitionDuration } = this.options;\r\n const containerWidth = this.container.clientWidth;\r\n\r\n // Calculate columns\r\n const columns = Math.max(1, Math.floor((containerWidth + gutter) / (minColWidth + gutter)));\r\n const colWidth = (containerWidth - (columns - 1) * gutter) / columns;\r\n\r\n // Reset column heights\r\n this.columnHeights = new Array(columns).fill(0);\r\n\r\n // Position items\r\n this.items.forEach((item) => {\r\n const height = item.offsetHeight;\r\n const minCol = this.findShortestColumn();\r\n const x = minCol * (colWidth + gutter);\r\n const y = this.columnHeights[minCol];\r\n\r\n // Apply position and size\r\n item.style.width = `${colWidth}px`;\r\n item.style.transform = `translate3d(${x}px, ${y}px, 0)`;\r\n item.style.transition = animate\r\n ? `transform ${transitionDuration}ms ease`\r\n : 'none';\r\n\r\n // Update column height\r\n this.columnHeights[minCol] += height + gutter;\r\n });\r\n\r\n // Set container height\r\n const maxHeight = Math.max(...this.columnHeights);\r\n this.container.style.height = `${maxHeight}px`;\r\n }\r\n\r\n private findShortestColumn(): number {\r\n return this.columnHeights.indexOf(Math.min(...this.columnHeights));\r\n }\r\n\r\n public updateItems(newItems: T[]) {\r\n this.options.items = newItems;\r\n this.renderItems();\r\n }\r\n\r\n public destroy() {\r\n this.resizeObserver?.disconnect();\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.container.innerHTML = '';\r\n this.container.removeAttribute('style');\r\n this.container.classList.remove(this.options.classNames.container || \"\");\r\n }\r\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/react.tsx","../../src/MasonrySnapGridLayout.ts"],"sourcesContent":["import React, {\r\n useEffect,\r\n useRef,\r\n forwardRef,\r\n useImperativeHandle,\r\n} from 'react';\r\nimport ReactDOM from 'react-dom/client';\r\nimport MasonrySnapGridLayout from './MasonrySnapGridLayout';\r\nimport {\r\n MasonrySnapGridLayoutOptions,\r\n MasonrySnapGridRef,\r\n} from './types';\r\n\r\ninterface MasonrySnapGridProps<T>\r\n extends Omit<MasonrySnapGridLayoutOptions<T>, 'items' | 'renderItem'> {\r\n items: T[];\r\n renderItem: (item: T) => React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\nconst MasonrySnapGridInner = <T,>(\r\n {\r\n items,\r\n renderItem,\r\n className,\r\n style,\r\n ...options\r\n }: MasonrySnapGridProps<T>,\r\n ref: React.ForwardedRef<MasonrySnapGridRef>\r\n) => {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const masonryRef = useRef<MasonrySnapGridLayout<T> | null>(null);\r\n const rootsRef = useRef<Map<HTMLElement, ReactDOM.Root>>(new Map());\r\n\r\n // Initialize masonry layout\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n masonryRef.current = new MasonrySnapGridLayout(containerRef.current, {\r\n ...options,\r\n items,\r\n renderItem: (item) => {\r\n const div = document.createElement('div');\r\n const root = ReactDOM.createRoot(div);\r\n root.render(renderItem(item));\r\n rootsRef.current.set(div, root);\r\n return div;\r\n },\r\n });\r\n\r\n return () => {\r\n // Proper cleanup\r\n rootsRef.current.forEach((root, div) => {\r\n root.unmount();\r\n div.remove();\r\n });\r\n rootsRef.current.clear();\r\n masonryRef.current?.destroy();\r\n masonryRef.current = null;\r\n };\r\n }, [options, renderItem]);\r\n\r\n // Update items on change\r\n useEffect(() => {\r\n if (masonryRef.current) {\r\n masonryRef.current.updateItems(items);\r\n }\r\n }, [items]);\r\n\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n className={className}\r\n style={{ position: 'relative', width: '100%', ...style }}\r\n />\r\n );\r\n};\r\n\r\n// Properly typed forwardRef component\r\nconst MasonrySnapGrid = forwardRef(MasonrySnapGridInner) as <T>(\r\n props: MasonrySnapGridProps<T> & { ref?: React.ForwardedRef<MasonrySnapGridRef> }\r\n) => ReturnType<typeof MasonrySnapGridInner>;\r\n\r\nexport default MasonrySnapGrid;","import { MasonrySnapGridLayoutOptions } from './types';\r\n\r\nexport default class MasonrySnapGridLayout<T = any> {\r\n private readonly container: HTMLElement;\r\n private readonly options: Required<MasonrySnapGridLayoutOptions<T>>;\r\n private items: HTMLElement[] = [];\r\n private columnHeights: number[] = [];\r\n private resizeObserver: ResizeObserver | undefined;\r\n private rafId: number | null = null;\r\n\r\n constructor(container: HTMLElement, options: MasonrySnapGridLayoutOptions<T>) {\r\n this.container = container;\r\n this.options = {\r\n gutter: 16,\r\n minColWidth: 250,\r\n animate: true,\r\n transitionDuration: 400,\r\n classNames: {\r\n container: 'masonry-snap-grid-container',\r\n item: 'masonry-snap-grid-item',\r\n },\r\n ...options,\r\n };\r\n\r\n // Apply container class\r\n this.container.classList.add(this.options.classNames.container || \"\");\r\n\r\n // Initialize\r\n this.renderItems();\r\n this.setupResizeObserver();\r\n }\r\n\r\n private renderItems() {\r\n // Clear existing items\r\n this.items.forEach(item => item.remove());\r\n this.items = [];\r\n\r\n // Create fragment for batch DOM insertion\r\n const fragment = document.createDocumentFragment();\r\n\r\n // Create and append items\r\n this.options.items.forEach(itemData => {\r\n const itemElement = this.options.renderItem(itemData);\r\n itemElement.classList.add(this.options.classNames.item|| \"\");\r\n fragment.appendChild(itemElement);\r\n this.items.push(itemElement);\r\n });\r\n\r\n this.container.appendChild(fragment);\r\n this.updateLayout();\r\n }\r\n\r\n private setupResizeObserver() {\r\n this.resizeObserver = new ResizeObserver(() => {\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.rafId = requestAnimationFrame(() => this.updateLayout());\r\n });\r\n this.resizeObserver.observe(this.container);\r\n }\r\n\r\n private updateLayout() {\r\n const { gutter, minColWidth, animate, transitionDuration } = this.options;\r\n const containerWidth = this.container.clientWidth;\r\n\r\n // Calculate columns\r\n const columns = Math.max(1, Math.floor((containerWidth + gutter) / (minColWidth + gutter)));\r\n const colWidth = (containerWidth - (columns - 1) * gutter) / columns;\r\n\r\n // Reset column heights\r\n this.columnHeights = new Array(columns).fill(0);\r\n\r\n // Position items\r\n this.items.forEach((item) => {\r\n const height = item.offsetHeight;\r\n const minCol = this.findShortestColumn();\r\n const x = minCol * (colWidth + gutter);\r\n const y = this.columnHeights[minCol];\r\n\r\n // Apply position and size\r\n item.style.width = `${colWidth}px`;\r\n item.style.transform = `translate3d(${x}px, ${y}px, 0)`;\r\n item.style.transition = animate\r\n ? `transform ${transitionDuration}ms ease`\r\n : 'none';\r\n\r\n // Update column height\r\n this.columnHeights[minCol] += height + gutter;\r\n });\r\n\r\n // Set container height\r\n const maxHeight = Math.max(...this.columnHeights);\r\n this.container.style.height = `${maxHeight}px`;\r\n }\r\n\r\n private findShortestColumn(): number {\r\n return this.columnHeights.indexOf(Math.min(...this.columnHeights));\r\n }\r\n\r\n public updateItems(newItems: T[]) {\r\n this.options.items = newItems;\r\n this.renderItems();\r\n }\r\n\r\n public destroy() {\r\n this.resizeObserver?.disconnect();\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.container.innerHTML = '';\r\n this.container.removeAttribute('style');\r\n this.container.classList.remove(this.options.classNames.container || \"\");\r\n }\r\n}"],"mappings":"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","names":[]}
|
package/dist/react.d.cts
CHANGED
|
@@ -8,6 +8,9 @@ interface MasonrySnapGridProps<T> extends Omit<MasonrySnapGridLayoutOptions<T>,
|
|
|
8
8
|
className?: string;
|
|
9
9
|
style?: React.CSSProperties;
|
|
10
10
|
}
|
|
11
|
-
declare
|
|
11
|
+
declare const MasonrySnapGridInner: <T>({ items, renderItem, className, style, ...options }: MasonrySnapGridProps<T>, ref: React.ForwardedRef<MasonrySnapGridRef>) => react_jsx_runtime.JSX.Element;
|
|
12
|
+
declare const MasonrySnapGrid: <T>(props: MasonrySnapGridProps<T> & {
|
|
13
|
+
ref?: React.ForwardedRef<MasonrySnapGridRef>;
|
|
14
|
+
}) => ReturnType<typeof MasonrySnapGridInner>;
|
|
12
15
|
|
|
13
|
-
export {
|
|
16
|
+
export { MasonrySnapGrid as default };
|
package/dist/react.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ interface MasonrySnapGridProps<T> extends Omit<MasonrySnapGridLayoutOptions<T>,
|
|
|
8
8
|
className?: string;
|
|
9
9
|
style?: React.CSSProperties;
|
|
10
10
|
}
|
|
11
|
-
declare
|
|
11
|
+
declare const MasonrySnapGridInner: <T>({ items, renderItem, className, style, ...options }: MasonrySnapGridProps<T>, ref: React.ForwardedRef<MasonrySnapGridRef>) => react_jsx_runtime.JSX.Element;
|
|
12
|
+
declare const MasonrySnapGrid: <T>(props: MasonrySnapGridProps<T> & {
|
|
13
|
+
ref?: React.ForwardedRef<MasonrySnapGridRef>;
|
|
14
|
+
}) => ReturnType<typeof MasonrySnapGridInner>;
|
|
12
15
|
|
|
13
|
-
export {
|
|
16
|
+
export { MasonrySnapGrid as default };
|
package/dist/react.js
CHANGED
|
@@ -115,13 +115,13 @@ var MasonrySnapGridLayout = class {
|
|
|
115
115
|
|
|
116
116
|
// src/react.tsx
|
|
117
117
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
118
|
-
|
|
118
|
+
var MasonrySnapGridInner = ({
|
|
119
119
|
items,
|
|
120
120
|
renderItem,
|
|
121
121
|
className,
|
|
122
122
|
style,
|
|
123
123
|
...options
|
|
124
|
-
}, ref) {
|
|
124
|
+
}, ref) => {
|
|
125
125
|
const containerRef = (0, import_react.useRef)(null);
|
|
126
126
|
const masonryRef = (0, import_react.useRef)(null);
|
|
127
127
|
const rootsRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
@@ -139,7 +139,10 @@ function MasonrySnapGridInner({
|
|
|
139
139
|
}
|
|
140
140
|
});
|
|
141
141
|
return () => {
|
|
142
|
-
rootsRef.current.forEach((root) =>
|
|
142
|
+
rootsRef.current.forEach((root, div) => {
|
|
143
|
+
root.unmount();
|
|
144
|
+
div.remove();
|
|
145
|
+
});
|
|
143
146
|
rootsRef.current.clear();
|
|
144
147
|
masonryRef.current?.destroy();
|
|
145
148
|
masonryRef.current = null;
|
|
@@ -150,9 +153,6 @@ function MasonrySnapGridInner({
|
|
|
150
153
|
masonryRef.current.updateItems(items);
|
|
151
154
|
}
|
|
152
155
|
}, [items]);
|
|
153
|
-
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
154
|
-
layout: masonryRef.current
|
|
155
|
-
}));
|
|
156
156
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
157
157
|
"div",
|
|
158
158
|
{
|
|
@@ -161,7 +161,7 @@ function MasonrySnapGridInner({
|
|
|
161
161
|
style: { position: "relative", width: "100%", ...style }
|
|
162
162
|
}
|
|
163
163
|
);
|
|
164
|
-
}
|
|
164
|
+
};
|
|
165
165
|
var MasonrySnapGrid = (0, import_react.forwardRef)(MasonrySnapGridInner);
|
|
166
|
-
var react_default =
|
|
166
|
+
var react_default = MasonrySnapGrid;
|
|
167
167
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.tsx","../src/MasonrySnapGridLayout.ts"],"sourcesContent":["import React, {\r\n useEffect,\r\n useRef,\r\n forwardRef,\r\n useImperativeHandle,\r\n} from 'react';\r\nimport ReactDOM from 'react-dom/client';\r\nimport MasonrySnapGridLayout from './MasonrySnapGridLayout';\r\nimport {\r\n MasonrySnapGridLayoutOptions,\r\n MasonrySnapGridRef,\r\n} from './types';\r\n\r\ninterface MasonrySnapGridProps<T>\r\n extends Omit<MasonrySnapGridLayoutOptions<T>, 'items' | 'renderItem'> {\r\n items: T[];\r\n renderItem: (item: T) => React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\nfunction MasonrySnapGridInner<T>(\r\n {\r\n items,\r\n renderItem,\r\n className,\r\n style,\r\n ...options\r\n }: MasonrySnapGridProps<T>,\r\n ref: React.Ref<MasonrySnapGridRef>\r\n) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const masonryRef = useRef<MasonrySnapGridLayout<T> | null>(null);\r\n\r\n // React roots storage to prevent memory leaks\r\n const rootsRef = useRef<Map<HTMLElement, ReactDOM.Root>>(new Map());\r\n\r\n // Initialize masonry layout\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n masonryRef.current = new MasonrySnapGridLayout(containerRef.current, {\r\n ...options,\r\n items,\r\n renderItem: (item) => {\r\n const div = document.createElement('div');\r\n const root = ReactDOM.createRoot(div);\r\n root.render(renderItem(item));\r\n rootsRef.current.set(div, root);\r\n return div;\r\n },\r\n });\r\n\r\n return () => {\r\n // Unmount all React roots to avoid memory leaks\r\n rootsRef.current.forEach((root) => root.unmount());\r\n rootsRef.current.clear();\r\n\r\n masonryRef.current?.destroy();\r\n masonryRef.current = null;\r\n };\r\n }, [options, renderItem]); // include renderItem if it's not memoized\r\n\r\n // Update items on change\r\n useEffect(() => {\r\n if (masonryRef.current) {\r\n masonryRef.current.updateItems(items);\r\n }\r\n }, [items]);\r\n\r\n // Expose layout instance through ref\r\n useImperativeHandle(ref, () => ({\r\n layout: masonryRef.current!,\r\n }));\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n className={className}\r\n style={{ position: 'relative', width: '100%', ...style }}\r\n />\r\n );\r\n}\r\n\r\n// Apply generic type correctly to forwardRef\r\nconst MasonrySnapGrid = forwardRef(MasonrySnapGridInner) as <T>(\r\n props: MasonrySnapGridProps<T> & { ref?: React.Ref<MasonrySnapGridRef> }\r\n) => ReturnType<typeof MasonrySnapGridInner>;\r\n\r\nexport default MasonrySnapGridInner\r\n","import { MasonrySnapGridLayoutOptions } from './types';\r\n\r\nexport default class MasonrySnapGridLayout<T = any> {\r\n private readonly container: HTMLElement;\r\n private readonly options: Required<MasonrySnapGridLayoutOptions<T>>;\r\n private items: HTMLElement[] = [];\r\n private columnHeights: number[] = [];\r\n private resizeObserver: ResizeObserver | undefined;\r\n private rafId: number | null = null;\r\n\r\n constructor(container: HTMLElement, options: MasonrySnapGridLayoutOptions<T>) {\r\n this.container = container;\r\n this.options = {\r\n gutter: 16,\r\n minColWidth: 250,\r\n animate: true,\r\n transitionDuration: 400,\r\n classNames: {\r\n container: 'masonry-snap-grid-container',\r\n item: 'masonry-snap-grid-item',\r\n },\r\n ...options,\r\n };\r\n\r\n // Apply container class\r\n this.container.classList.add(this.options.classNames.container || \"\");\r\n\r\n // Initialize\r\n this.renderItems();\r\n this.setupResizeObserver();\r\n }\r\n\r\n private renderItems() {\r\n // Clear existing items\r\n this.items.forEach(item => item.remove());\r\n this.items = [];\r\n\r\n // Create fragment for batch DOM insertion\r\n const fragment = document.createDocumentFragment();\r\n\r\n // Create and append items\r\n this.options.items.forEach(itemData => {\r\n const itemElement = this.options.renderItem(itemData);\r\n itemElement.classList.add(this.options.classNames.item|| \"\");\r\n fragment.appendChild(itemElement);\r\n this.items.push(itemElement);\r\n });\r\n\r\n this.container.appendChild(fragment);\r\n this.updateLayout();\r\n }\r\n\r\n private setupResizeObserver() {\r\n this.resizeObserver = new ResizeObserver(() => {\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.rafId = requestAnimationFrame(() => this.updateLayout());\r\n });\r\n this.resizeObserver.observe(this.container);\r\n }\r\n\r\n private updateLayout() {\r\n const { gutter, minColWidth, animate, transitionDuration } = this.options;\r\n const containerWidth = this.container.clientWidth;\r\n\r\n // Calculate columns\r\n const columns = Math.max(1, Math.floor((containerWidth + gutter) / (minColWidth + gutter)));\r\n const colWidth = (containerWidth - (columns - 1) * gutter) / columns;\r\n\r\n // Reset column heights\r\n this.columnHeights = new Array(columns).fill(0);\r\n\r\n // Position items\r\n this.items.forEach((item) => {\r\n const height = item.offsetHeight;\r\n const minCol = this.findShortestColumn();\r\n const x = minCol * (colWidth + gutter);\r\n const y = this.columnHeights[minCol];\r\n\r\n // Apply position and size\r\n item.style.width = `${colWidth}px`;\r\n item.style.transform = `translate3d(${x}px, ${y}px, 0)`;\r\n item.style.transition = animate\r\n ? `transform ${transitionDuration}ms ease`\r\n : 'none';\r\n\r\n // Update column height\r\n this.columnHeights[minCol] += height + gutter;\r\n });\r\n\r\n // Set container height\r\n const maxHeight = Math.max(...this.columnHeights);\r\n this.container.style.height = `${maxHeight}px`;\r\n }\r\n\r\n private findShortestColumn(): number {\r\n return this.columnHeights.indexOf(Math.min(...this.columnHeights));\r\n }\r\n\r\n public updateItems(newItems: T[]) {\r\n this.options.items = newItems;\r\n this.renderItems();\r\n }\r\n\r\n public destroy() {\r\n this.resizeObserver?.disconnect();\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.container.innerHTML = '';\r\n this.container.removeAttribute('style');\r\n this.container.classList.remove(this.options.classNames.container || \"\");\r\n }\r\n}"],"mappings":"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","names":["ReactDOM"]}
|
|
1
|
+
{"version":3,"sources":["../src/react.tsx","../src/MasonrySnapGridLayout.ts"],"sourcesContent":["import React, {\r\n useEffect,\r\n useRef,\r\n forwardRef,\r\n useImperativeHandle,\r\n} from 'react';\r\nimport ReactDOM from 'react-dom/client';\r\nimport MasonrySnapGridLayout from './MasonrySnapGridLayout';\r\nimport {\r\n MasonrySnapGridLayoutOptions,\r\n MasonrySnapGridRef,\r\n} from './types';\r\n\r\ninterface MasonrySnapGridProps<T>\r\n extends Omit<MasonrySnapGridLayoutOptions<T>, 'items' | 'renderItem'> {\r\n items: T[];\r\n renderItem: (item: T) => React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\nconst MasonrySnapGridInner = <T,>(\r\n {\r\n items,\r\n renderItem,\r\n className,\r\n style,\r\n ...options\r\n }: MasonrySnapGridProps<T>,\r\n ref: React.ForwardedRef<MasonrySnapGridRef>\r\n) => {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const masonryRef = useRef<MasonrySnapGridLayout<T> | null>(null);\r\n const rootsRef = useRef<Map<HTMLElement, ReactDOM.Root>>(new Map());\r\n\r\n // Initialize masonry layout\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n masonryRef.current = new MasonrySnapGridLayout(containerRef.current, {\r\n ...options,\r\n items,\r\n renderItem: (item) => {\r\n const div = document.createElement('div');\r\n const root = ReactDOM.createRoot(div);\r\n root.render(renderItem(item));\r\n rootsRef.current.set(div, root);\r\n return div;\r\n },\r\n });\r\n\r\n return () => {\r\n // Proper cleanup\r\n rootsRef.current.forEach((root, div) => {\r\n root.unmount();\r\n div.remove();\r\n });\r\n rootsRef.current.clear();\r\n masonryRef.current?.destroy();\r\n masonryRef.current = null;\r\n };\r\n }, [options, renderItem]);\r\n\r\n // Update items on change\r\n useEffect(() => {\r\n if (masonryRef.current) {\r\n masonryRef.current.updateItems(items);\r\n }\r\n }, [items]);\r\n\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n className={className}\r\n style={{ position: 'relative', width: '100%', ...style }}\r\n />\r\n );\r\n};\r\n\r\n// Properly typed forwardRef component\r\nconst MasonrySnapGrid = forwardRef(MasonrySnapGridInner) as <T>(\r\n props: MasonrySnapGridProps<T> & { ref?: React.ForwardedRef<MasonrySnapGridRef> }\r\n) => ReturnType<typeof MasonrySnapGridInner>;\r\n\r\nexport default MasonrySnapGrid;","import { MasonrySnapGridLayoutOptions } from './types';\r\n\r\nexport default class MasonrySnapGridLayout<T = any> {\r\n private readonly container: HTMLElement;\r\n private readonly options: Required<MasonrySnapGridLayoutOptions<T>>;\r\n private items: HTMLElement[] = [];\r\n private columnHeights: number[] = [];\r\n private resizeObserver: ResizeObserver | undefined;\r\n private rafId: number | null = null;\r\n\r\n constructor(container: HTMLElement, options: MasonrySnapGridLayoutOptions<T>) {\r\n this.container = container;\r\n this.options = {\r\n gutter: 16,\r\n minColWidth: 250,\r\n animate: true,\r\n transitionDuration: 400,\r\n classNames: {\r\n container: 'masonry-snap-grid-container',\r\n item: 'masonry-snap-grid-item',\r\n },\r\n ...options,\r\n };\r\n\r\n // Apply container class\r\n this.container.classList.add(this.options.classNames.container || \"\");\r\n\r\n // Initialize\r\n this.renderItems();\r\n this.setupResizeObserver();\r\n }\r\n\r\n private renderItems() {\r\n // Clear existing items\r\n this.items.forEach(item => item.remove());\r\n this.items = [];\r\n\r\n // Create fragment for batch DOM insertion\r\n const fragment = document.createDocumentFragment();\r\n\r\n // Create and append items\r\n this.options.items.forEach(itemData => {\r\n const itemElement = this.options.renderItem(itemData);\r\n itemElement.classList.add(this.options.classNames.item|| \"\");\r\n fragment.appendChild(itemElement);\r\n this.items.push(itemElement);\r\n });\r\n\r\n this.container.appendChild(fragment);\r\n this.updateLayout();\r\n }\r\n\r\n private setupResizeObserver() {\r\n this.resizeObserver = new ResizeObserver(() => {\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.rafId = requestAnimationFrame(() => this.updateLayout());\r\n });\r\n this.resizeObserver.observe(this.container);\r\n }\r\n\r\n private updateLayout() {\r\n const { gutter, minColWidth, animate, transitionDuration } = this.options;\r\n const containerWidth = this.container.clientWidth;\r\n\r\n // Calculate columns\r\n const columns = Math.max(1, Math.floor((containerWidth + gutter) / (minColWidth + gutter)));\r\n const colWidth = (containerWidth - (columns - 1) * gutter) / columns;\r\n\r\n // Reset column heights\r\n this.columnHeights = new Array(columns).fill(0);\r\n\r\n // Position items\r\n this.items.forEach((item) => {\r\n const height = item.offsetHeight;\r\n const minCol = this.findShortestColumn();\r\n const x = minCol * (colWidth + gutter);\r\n const y = this.columnHeights[minCol];\r\n\r\n // Apply position and size\r\n item.style.width = `${colWidth}px`;\r\n item.style.transform = `translate3d(${x}px, ${y}px, 0)`;\r\n item.style.transition = animate\r\n ? `transform ${transitionDuration}ms ease`\r\n : 'none';\r\n\r\n // Update column height\r\n this.columnHeights[minCol] += height + gutter;\r\n });\r\n\r\n // Set container height\r\n const maxHeight = Math.max(...this.columnHeights);\r\n this.container.style.height = `${maxHeight}px`;\r\n }\r\n\r\n private findShortestColumn(): number {\r\n return this.columnHeights.indexOf(Math.min(...this.columnHeights));\r\n }\r\n\r\n public updateItems(newItems: T[]) {\r\n this.options.items = newItems;\r\n this.renderItems();\r\n }\r\n\r\n public destroy() {\r\n this.resizeObserver?.disconnect();\r\n if (this.rafId) cancelAnimationFrame(this.rafId);\r\n this.container.innerHTML = '';\r\n this.container.removeAttribute('style');\r\n this.container.classList.remove(this.options.classNames.container || \"\");\r\n }\r\n}"],"mappings":"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","names":["ReactDOM"]}
|
package/package.json
CHANGED