UNPKG

masonry-snap-grid-layout

Version:

A performant, responsive masonry layout library with smooth animations, dynamic columns, and zero dependencies.

145 lines (142 loc) 5.19 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { MasonrySnapGridLayout: () => MasonrySnapGridLayout, default: () => index_default }); module.exports = __toCommonJS(index_exports); // src/MasonrySnapGridLayout.ts var MasonrySnapGridLayout = class { /** * Creates a new MasonrySnapGridLayout instance. * * @param container - The HTML element that will act as the grid container. * @param options - Partial configuration object for layout behavior and rendering. */ constructor(container, options) { /** A reference to all grid item elements currently rendered. */ this.items = []; /** Tracks the current heights of each column to position new items. */ this.columnHeights = []; /** Stores requestAnimationFrame ID for layout updates to prevent redundant calls. */ this.rafId = null; this.container = container; this.options = { gutter: 16, minColWidth: 250, animate: true, transitionDuration: 400, classNames: { container: "masonry-snap-grid-container", item: "masonry-snap-grid-item" }, ...options }; this.container.classList.add(this.options.classNames.container || ""); this.renderItems(); this.setupResizeObserver(); } /** * Renders the provided items into the container. * Clears previous items and re-builds DOM structure. */ renderItems() { this.items.forEach((item) => item.remove()); this.items = []; const fragment = document.createDocumentFragment(); this.options.items.forEach((itemData) => { const itemElement = this.options.renderItem(itemData); itemElement.classList.add(this.options.classNames.item || ""); fragment.appendChild(itemElement); this.items.push(itemElement); }); this.container.appendChild(fragment); this.updateLayout(); } /** * Sets up a ResizeObserver to re-calculate layout when container size changes. */ setupResizeObserver() { this.resizeObserver = new ResizeObserver(() => { if (this.rafId) cancelAnimationFrame(this.rafId); this.rafId = requestAnimationFrame(() => this.updateLayout()); }); this.resizeObserver.observe(this.container); } /** * Calculates item positions and updates their transforms. * Also adjusts the container height to fit all items. */ updateLayout() { const { gutter, minColWidth, animate, transitionDuration } = this.options; const containerWidth = this.container.clientWidth; const columns = Math.max(1, Math.floor((containerWidth + gutter) / (minColWidth + gutter))); const colWidth = (containerWidth - (columns - 1) * gutter) / columns; this.columnHeights = new Array(columns).fill(0); this.items.forEach((item) => { const height = item.offsetHeight; const minCol = this.findShortestColumn(); const x = minCol * (colWidth + gutter); const y = this.columnHeights[minCol]; item.style.width = `${colWidth}px`; item.style.transform = `translate3d(${x}px, ${y}px, 0)`; item.style.transition = animate ? `transform ${transitionDuration}ms ease` : "none"; this.columnHeights[minCol] += height + gutter; }); const maxHeight = Math.max(...this.columnHeights); this.container.style.height = `${maxHeight}px`; } /** * Finds the index of the column with the smallest total height. * * @returns Index of the shortest column. */ findShortestColumn() { return this.columnHeights.indexOf(Math.min(...this.columnHeights)); } /** * Replaces current items with a new set and re-renders the layout. * * @param newItems - New set of data items to render. */ updateItems(newItems) { this.options.items = newItems; this.renderItems(); } /** * Cleans up event listeners, observers, and DOM modifications. * This should be called before discarding the instance. */ destroy() { this.resizeObserver?.disconnect(); if (this.rafId) cancelAnimationFrame(this.rafId); this.container.innerHTML = ""; this.container.removeAttribute("style"); this.container.classList.remove(this.options.classNames.container || ""); } }; // src/index.ts var index_default = MasonrySnapGridLayout; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { MasonrySnapGridLayout }); //# sourceMappingURL=index.js.map