masonry-simple 4.4.0 → 4.5.0

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 CHANGED
@@ -1,68 +1,126 @@
1
- <div align="center">
2
- <br>
1
+ # masonry-simple
3
2
 
4
- <h1>masonry-simple</h1>
3
+ A lightweight masonry layout helper built on top of CSS Grid.
5
4
 
6
- <p><sup>MasonrySimple implements a simple system for placing masonry style elements using CSS Grid. Masonry placement is used for dynamic grids where elements may have different heights and need to be placed neatly without gaps.</sup></p>
5
+ - Idempotent lifecycle: `init()`, `refresh()`, `destroy()`.
6
+ - Unified layout scheduling for resize, mutations, image load, and manual refresh.
7
+ - Safe teardown with observer/listener cleanup and inline-style restoration.
8
+ - Supports dynamic image content and responsive CSS changes.
7
9
 
8
- [![npm](https://img.shields.io/npm/v/masonry-simple.svg?colorB=brightgreen)](https://www.npmjs.com/package/masonry-simple)
9
- [![GitHub package version](https://img.shields.io/github/package-json/v/ux-ui-pro/masonry-simple.svg)](https://github.com/ux-ui-pro/masonry-simple)
10
- [![NPM Downloads](https://img.shields.io/npm/dm/masonry-simple.svg?style=flat)](https://www.npmjs.org/package/masonry-simple)
10
+ ## Install
11
11
 
12
- <sup>1kB gzipped</sup>
13
-
14
- <a href="https://codepen.io/ux-ui/pen/poxGEqX">Demo</a>
15
-
16
- </div>
17
- <br>
18
-
19
- &#10148; **Install**
20
- ```console
21
- $ yarn add masonry-simple
12
+ ```bash
13
+ yarn add masonry-simple
22
14
  ```
23
- <br>
24
15
 
25
- &#10148; **Import**
26
- ```javascript
16
+ ## Usage (TypeScript)
17
+
18
+ ```ts
27
19
  import MasonrySimple from 'masonry-simple';
28
- ```
29
- <br>
30
20
 
31
- &#10148; **Usage**
32
- ```javascript
33
21
  const masonry = new MasonrySimple({
34
22
  container: '.masonry',
35
23
  });
36
24
 
37
25
  masonry.init();
38
26
  ```
39
- ```HTML
27
+
28
+ ## Usage (Vue 3)
29
+
30
+ ```vue
31
+ <script setup lang="ts">
32
+ import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue';
33
+ import MasonrySimple from 'masonry-simple';
34
+
35
+ const masonryRef = ref<HTMLElement | null>(null);
36
+ const masonry = shallowRef<MasonrySimple | null>(null);
37
+
38
+ onMounted(() => {
39
+ if (!masonryRef.value) return;
40
+ masonry.value = new MasonrySimple({ container: masonryRef.value });
41
+ masonry.value.init();
42
+ });
43
+
44
+ onBeforeUnmount(() => {
45
+ masonry.value?.destroy();
46
+ masonry.value = null;
47
+ });
48
+ </script>
49
+
50
+ <template>
51
+ <div ref="masonryRef" class="masonry">
52
+ <div class="masonry__item">...</div>
53
+ <div class="masonry__item">...</div>
54
+ </div>
55
+ </template>
56
+ ```
57
+
58
+ ## HTML Layout
59
+
60
+ ```html
40
61
  <div class="masonry">
41
62
  <div class="masonry__item">
42
- ...
63
+ <img src="/img/1.jpg" alt="">
43
64
  </div>
44
65
  <div class="masonry__item">
45
- ...
66
+ Lorem ipsum
46
67
  </div>
47
- ...
48
68
  </div>
49
69
  ```
50
- ```SCSS
70
+
71
+ ## CSS Contract
72
+
73
+ ```css
51
74
  .masonry {
52
75
  display: grid;
53
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
54
- grid-auto-flow: dense;
55
- grid-gap: 10px;
76
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
77
+ gap: 12px;
56
78
  }
57
79
  ```
58
- <br>
59
80
 
60
- &#10148; **Destroy**
61
- ```javascript
81
+ - Container must use CSS Grid.
82
+ - Item heights are measured from rendered content.
83
+ - Library temporarily applies inline styles while active:
84
+ - `gridAutoRows: 1px`
85
+ - `contain: layout`
86
+ - `alignItems: start`
87
+ - These inline styles are restored on `destroy()`.
88
+
89
+ ## Options
90
+
91
+ | Option | Type | Default | Description |
92
+ |:------------|:-------------------------|:------------:|:--------------------------------------------------|
93
+ | `container` | `HTMLElement \| string` | `'.masonry'` | Target container element or selector. |
94
+
95
+ ## Methods
96
+
97
+ ```ts
98
+ masonry.init();
99
+ masonry.refresh();
62
100
  masonry.destroy();
63
101
  ```
64
- <br>
65
102
 
66
- &#10148; **License**
103
+ ## Lifecycle Behavior
104
+
105
+ - `init()` is idempotent and does not duplicate observers/listeners.
106
+ - `refresh()` re-collects grid items and schedules a single layout pass.
107
+ - `destroy()` cancels scheduled animation frame work, disconnects observers, clears listeners, and resets item styles (`gridRowEnd`).
108
+ - `refresh()` after `destroy()` is a safe no-op.
109
+
110
+ ## Edge Cases and Limitations
111
+
112
+ - Missing container: methods do nothing.
113
+ - SSR / non-DOM environments: graceful no-op behavior when `document` is unavailable.
114
+ - Missing `ResizeObserver` / `MutationObserver`: layout still works via manual `refresh()`.
115
+ - Hidden container (`display: none`) or zero-size state may produce temporary fallback spans.
116
+ - If size changes happen without child mutations, call `refresh()` manually.
117
+
118
+ ## Performance Notes
119
+
120
+ - Batch DOM changes and call one `refresh()`.
121
+ - Avoid frequent style mutations during animation loops.
122
+ - Prefer known image dimensions to reduce post-load relayout work.
123
+
124
+ ## License
67
125
 
68
- masonry-simple is released under MIT license
126
+ MIT
package/dist/index.cjs.js CHANGED
@@ -1 +1,3 @@
1
- "use strict";module.exports=class{container;gridItems=[];rowHeight=1;rowGap=0;resizeScheduled=!1;resizeObserver=null;mutationObserver=null;abortController=null;originalAutoRows="";constructor(t={}){this.container=t.container instanceof HTMLElement?t.container:typeof t.container=="string"?document.querySelector(t.container):document.querySelector(".masonry")}init(){this.container&&(this.setupAbortController(),this.storeAndSetAutoRows(),this.initializeContainerStyles(),this.initializeGridItems(),this.setupResizeObserver(),this.setupMutationObserver(),this.resizeAllItems())}refresh(){this.initializeGridItems(),this.resizeAllItems()}destroy(){this.container&&(this.abortController?.abort(),this.container.style.gridAutoRows=this.originalAutoRows,this.container.style.contain="",this.container.style.alignItems="",this.gridItems.forEach(t=>t.style.gridRowEnd=""),this.gridItems=[],this.resizeObserver=null,this.mutationObserver=null,this.abortController=null,this.originalAutoRows="")}handleResize(){this.resizeScheduled||(this.resizeScheduled=!0,requestAnimationFrame(()=>{this.resizeAllItems(),this.resizeScheduled=!1}))}resizeAllItems(){this.container&&(this.container.style.alignItems="start",this.gridItems.forEach(t=>{const e=Math.ceil((t.clientHeight+this.rowGap)/(this.rowHeight+this.rowGap));t.style.gridRowEnd=`span ${e}`}))}setupAbortController(){this.abortController=new AbortController,this.abortController.signal.addEventListener("abort",()=>{this.resizeObserver?.disconnect(),this.mutationObserver?.disconnect()})}setupResizeObserver(){this.resizeObserver=new ResizeObserver(()=>this.handleResize()),this.resizeObserver.observe(this.container)}setupMutationObserver(){this.mutationObserver=new MutationObserver(()=>{this.initializeGridItems(),this.resizeAllItems()}),this.mutationObserver.observe(this.container,{childList:!0,subtree:!1})}initializeContainerStyles(){if(!this.container)return;const t=getComputedStyle(this.container);this.rowGap=parseInt(t.rowGap,10)||0;const e=parseInt(t.gridAutoRows,10);this.rowHeight=Number.isNaN(e)?this.rowHeight:e,this.container.style.contain="layout"}initializeGridItems(){this.container&&(this.gridItems=Array.from(this.container.children),this.gridItems.forEach(t=>{const e=t.querySelector("img");e&&!e.complete&&e.addEventListener("load",()=>this.resizeAllItems(),{once:!0})}))}storeAndSetAutoRows(){this.container&&(this.originalAutoRows||(this.originalAutoRows=this.container.style.gridAutoRows||""),this.container.style.gridAutoRows="1px")}};
1
+ var r=class{containerOption;container=null;gridItems=[];rowHeight=1;rowGap=0;resizeScheduled=!1;rafId=null;resizeObserver=null;mutationObserver=null;observerAbortController=null;imageAbortController=null;observedImages=new WeakSet;isInitialized=!1;isDestroyed=!1;originalContainerStyles={gridAutoRows:"",contain:"",alignItems:""};constructor(e={}){this.containerOption=e.container}init(){this.isInitialized||(this.container=this.resolveContainer(),this.container&&(this.isInitialized=!0,this.isDestroyed=!1,this.setupAbortControllers(),this.storeContainerStyles(),this.initializeContainerStyles(),this.initializeGridItems(),this.setupResizeObserver(),this.setupMutationObserver(),this.scheduleLayout()))}refresh(){!this.isInitialized||this.isDestroyed||!this.container||(this.initializeGridItems(),this.scheduleLayout())}destroy(){!this.isInitialized&&!this.container||(this.isDestroyed=!0,this.isInitialized=!1,this.cancelScheduledLayout(),this.observerAbortController?.abort(),this.imageAbortController?.abort(),this.resizeObserver?.disconnect(),this.mutationObserver?.disconnect(),this.gridItems.forEach(e=>{e.style.gridRowEnd=""}),this.container&&(this.container.style.gridAutoRows=this.originalContainerStyles.gridAutoRows,this.container.style.contain=this.originalContainerStyles.contain,this.container.style.alignItems=this.originalContainerStyles.alignItems),this.gridItems=[],this.rowHeight=1,this.rowGap=0,this.resizeObserver=null,this.mutationObserver=null,this.observerAbortController=null,this.imageAbortController=null,this.observedImages=new WeakSet,this.resizeScheduled=!1,this.container=null,this.originalContainerStyles={gridAutoRows:"",contain:"",alignItems:""})}resolveContainer(){return this.containerOption instanceof HTMLElement?this.containerOption:typeof document>"u"?null:typeof this.containerOption=="string"?document.querySelector(this.containerOption):document.querySelector(".masonry")}scheduleLayout(){if(!(!this.isInitialized||this.isDestroyed||!this.container||this.resizeScheduled)){if(this.resizeScheduled=!0,typeof requestAnimationFrame=="function"){this.rafId=requestAnimationFrame(()=>{this.rafId=null,this.resizeScheduled=!1,this.performLayout()});return}this.rafId=null,this.resizeScheduled=!1,this.performLayout()}}cancelScheduledLayout(){this.rafId!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.rafId),this.rafId=null,this.resizeScheduled=!1}performLayout(){!this.isInitialized||this.isDestroyed||!this.container||(this.measureContainerMetrics(),this.resizeAllItems())}resizeAllItems(){const e=this.rowHeight+this.rowGap;this.gridItems.forEach(t=>{if(e<=0||!Number.isFinite(e)){t.style.gridRowEnd="span 1";return}const i=Math.max(1,Math.ceil((t.getBoundingClientRect().height+this.rowGap)/e));t.style.gridRowEnd=`span ${i}`})}setupAbortControllers(){this.observerAbortController=new AbortController,this.imageAbortController=new AbortController,this.observerAbortController.signal.addEventListener("abort",()=>{this.resizeObserver?.disconnect(),this.mutationObserver?.disconnect()})}setupResizeObserver(){!this.container||typeof ResizeObserver>"u"||(this.resizeObserver=new ResizeObserver(()=>this.handleResize()),this.resizeObserver.observe(this.container))}setupMutationObserver(){!this.container||typeof MutationObserver>"u"||(this.mutationObserver=new MutationObserver(()=>{this.initializeGridItems(),this.scheduleLayout()}),this.mutationObserver.observe(this.container,{childList:!0,subtree:!1}))}handleResize(){this.scheduleLayout()}initializeContainerStyles(){this.container&&(this.container.style.gridAutoRows="1px",this.container.style.contain="layout",this.container.style.alignItems="start")}measureContainerMetrics(){if(!this.container)return;const e=getComputedStyle(this.container);this.rowGap=this.parseCssPixelValue(e.rowGap);const t=this.parseCssPixelValue(e.gridAutoRows);this.rowHeight=t>0?t:1}initializeGridItems(){this.container&&(this.gridItems=Array.from(this.container.children).filter(e=>e instanceof HTMLElement),this.gridItems.forEach(e=>{e.querySelectorAll("img").forEach(t=>{this.observeImage(t)})}))}observeImage(e){if(e.complete||this.observedImages.has(e))return;this.observedImages.add(e);const t=()=>this.scheduleLayout();if(this.imageAbortController){e.addEventListener("load",t,{once:!0,signal:this.imageAbortController.signal});return}e.addEventListener("load",t,{once:!0})}parseCssPixelValue(e){const t=Number.parseFloat(e);return Number.isFinite(t)?t:0}storeContainerStyles(){this.container&&(this.originalContainerStyles={gridAutoRows:this.container.style.gridAutoRows||"",contain:this.container.style.contain||"",alignItems:this.container.style.alignItems||""})}};module.exports=r;
2
+
3
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["interface MasonrySimpleOptions {\n container?: HTMLElement | string;\n}\n\nexport default class MasonrySimple {\n private readonly containerOption: HTMLElement | string | undefined;\n private container: HTMLElement | null = null;\n private gridItems: HTMLElement[] = [];\n private rowHeight = 1;\n private rowGap = 0;\n private resizeScheduled = false;\n private rafId: number | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private mutationObserver: MutationObserver | null = null;\n private observerAbortController: AbortController | null = null;\n private imageAbortController: AbortController | null = null;\n private observedImages = new WeakSet<HTMLImageElement>();\n private isInitialized = false;\n private isDestroyed = false;\n private originalContainerStyles = {\n gridAutoRows: '',\n contain: '',\n alignItems: '',\n };\n\n constructor(options: MasonrySimpleOptions = {}) {\n this.containerOption = options.container;\n }\n\n public init(): void {\n if (this.isInitialized) return;\n\n this.container = this.resolveContainer();\n\n if (!this.container) return;\n\n this.isInitialized = true;\n this.isDestroyed = false;\n\n this.setupAbortControllers();\n this.storeContainerStyles();\n this.initializeContainerStyles();\n this.initializeGridItems();\n this.setupResizeObserver();\n this.setupMutationObserver();\n this.scheduleLayout();\n }\n\n public refresh(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container) return;\n\n this.initializeGridItems();\n this.scheduleLayout();\n }\n\n public destroy(): void {\n if (!this.isInitialized && !this.container) return;\n\n this.isDestroyed = true;\n this.isInitialized = false;\n this.cancelScheduledLayout();\n this.observerAbortController?.abort();\n this.imageAbortController?.abort();\n this.resizeObserver?.disconnect();\n this.mutationObserver?.disconnect();\n this.gridItems.forEach((item) => {\n item.style.gridRowEnd = '';\n });\n\n if (this.container) {\n this.container.style.gridAutoRows = this.originalContainerStyles.gridAutoRows;\n this.container.style.contain = this.originalContainerStyles.contain;\n this.container.style.alignItems = this.originalContainerStyles.alignItems;\n }\n\n this.gridItems = [];\n this.rowHeight = 1;\n this.rowGap = 0;\n this.resizeObserver = null;\n this.mutationObserver = null;\n this.observerAbortController = null;\n this.imageAbortController = null;\n this.observedImages = new WeakSet<HTMLImageElement>();\n this.resizeScheduled = false;\n this.container = null;\n this.originalContainerStyles = {\n gridAutoRows: '',\n contain: '',\n alignItems: '',\n };\n }\n\n private resolveContainer(): HTMLElement | null {\n if (this.containerOption instanceof HTMLElement) {\n return this.containerOption;\n }\n\n if (typeof document === 'undefined') return null;\n\n if (typeof this.containerOption === 'string') {\n return document.querySelector<HTMLElement>(this.containerOption);\n }\n\n return document.querySelector<HTMLElement>('.masonry');\n }\n\n private scheduleLayout(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container || this.resizeScheduled) return;\n\n this.resizeScheduled = true;\n\n if (typeof requestAnimationFrame === 'function') {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n this.resizeScheduled = false;\n this.performLayout();\n });\n\n return;\n }\n\n this.rafId = null;\n this.resizeScheduled = false;\n this.performLayout();\n }\n\n private cancelScheduledLayout(): void {\n if (this.rafId !== null && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(this.rafId);\n }\n\n this.rafId = null;\n this.resizeScheduled = false;\n }\n\n private performLayout(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container) return;\n\n this.measureContainerMetrics();\n this.resizeAllItems();\n }\n\n private resizeAllItems(): void {\n const denominator = this.rowHeight + this.rowGap;\n\n this.gridItems.forEach((item) => {\n if (denominator <= 0 || !Number.isFinite(denominator)) {\n item.style.gridRowEnd = 'span 1';\n\n return;\n }\n\n const rowSpan = Math.max(\n 1,\n Math.ceil((item.getBoundingClientRect().height + this.rowGap) / denominator),\n );\n item.style.gridRowEnd = `span ${rowSpan}`;\n });\n }\n\n private setupAbortControllers(): void {\n this.observerAbortController = new AbortController();\n this.imageAbortController = new AbortController();\n\n this.observerAbortController.signal.addEventListener('abort', () => {\n this.resizeObserver?.disconnect();\n this.mutationObserver?.disconnect();\n });\n }\n\n private setupResizeObserver(): void {\n if (!this.container || typeof ResizeObserver === 'undefined') return;\n\n this.resizeObserver = new ResizeObserver(() => this.handleResize());\n\n this.resizeObserver.observe(this.container);\n }\n\n private setupMutationObserver(): void {\n if (!this.container || typeof MutationObserver === 'undefined') return;\n\n this.mutationObserver = new MutationObserver(() => {\n this.initializeGridItems();\n this.scheduleLayout();\n });\n\n this.mutationObserver.observe(this.container, {\n childList: true,\n subtree: false,\n });\n }\n\n private handleResize(): void {\n this.scheduleLayout();\n }\n\n private initializeContainerStyles(): void {\n if (!this.container) return;\n\n this.container.style.gridAutoRows = '1px';\n this.container.style.contain = 'layout';\n this.container.style.alignItems = 'start';\n }\n\n private measureContainerMetrics(): void {\n if (!this.container) return;\n\n const cs = getComputedStyle(this.container);\n\n this.rowGap = this.parseCssPixelValue(cs.rowGap);\n\n const parsedRowHeight = this.parseCssPixelValue(cs.gridAutoRows);\n\n this.rowHeight = parsedRowHeight > 0 ? parsedRowHeight : 1;\n }\n\n private initializeGridItems(): void {\n if (!this.container) return;\n\n this.gridItems = Array.from(this.container.children).filter(\n (item): item is HTMLElement => item instanceof HTMLElement,\n );\n\n this.gridItems.forEach((item) => {\n const images = item.querySelectorAll('img');\n\n images.forEach((image) => {\n this.observeImage(image);\n });\n });\n }\n\n private observeImage(image: HTMLImageElement): void {\n if (image.complete || this.observedImages.has(image)) return;\n\n this.observedImages.add(image);\n\n const onLoad = (): void => this.scheduleLayout();\n\n if (this.imageAbortController) {\n image.addEventListener('load', onLoad, {\n once: true,\n signal: this.imageAbortController.signal,\n });\n\n return;\n }\n\n image.addEventListener('load', onLoad, { once: true });\n }\n\n private parseCssPixelValue(value: string): number {\n const parsedValue = Number.parseFloat(value);\n\n return Number.isFinite(parsedValue) ? parsedValue : 0;\n }\n\n private storeContainerStyles(): void {\n if (!this.container) return;\n\n this.originalContainerStyles = {\n gridAutoRows: this.container.style.gridAutoRows || '',\n contain: this.container.style.contain || '',\n alignItems: this.container.style.alignItems || '',\n };\n }\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,27 +1,43 @@
1
- interface MasonrySimpleOptions {
2
- container?: HTMLElement | string;
3
- }
4
- export default class MasonrySimple {
5
- private readonly container;
6
- private gridItems;
7
- private rowHeight;
8
- private rowGap;
9
- private resizeScheduled;
10
- private resizeObserver;
11
- private mutationObserver;
12
- private abortController;
13
- private originalAutoRows;
14
- constructor(options?: MasonrySimpleOptions);
15
- init(): void;
16
- refresh(): void;
17
- destroy(): void;
18
- private handleResize;
19
- private resizeAllItems;
20
- private setupAbortController;
21
- private setupResizeObserver;
22
- private setupMutationObserver;
23
- private initializeContainerStyles;
24
- private initializeGridItems;
25
- private storeAndSetAutoRows;
26
- }
27
- export {};
1
+ declare class MasonrySimple {
2
+ private readonly containerOption;
3
+ private container;
4
+ private gridItems;
5
+ private rowHeight;
6
+ private rowGap;
7
+ private resizeScheduled;
8
+ private rafId;
9
+ private resizeObserver;
10
+ private mutationObserver;
11
+ private observerAbortController;
12
+ private imageAbortController;
13
+ private observedImages;
14
+ private isInitialized;
15
+ private isDestroyed;
16
+ private originalContainerStyles;
17
+ constructor(options?: MasonrySimpleOptions);
18
+ init(): void;
19
+ refresh(): void;
20
+ destroy(): void;
21
+ private resolveContainer;
22
+ private scheduleLayout;
23
+ private cancelScheduledLayout;
24
+ private performLayout;
25
+ private resizeAllItems;
26
+ private setupAbortControllers;
27
+ private setupResizeObserver;
28
+ private setupMutationObserver;
29
+ private handleResize;
30
+ private initializeContainerStyles;
31
+ private measureContainerMetrics;
32
+ private initializeGridItems;
33
+ private observeImage;
34
+ private parseCssPixelValue;
35
+ private storeContainerStyles;
36
+ }
37
+ export default MasonrySimple;
38
+
39
+ declare interface MasonrySimpleOptions {
40
+ container?: HTMLElement | string;
41
+ }
42
+
43
+ export { }
package/dist/index.es.js CHANGED
@@ -1,66 +1,135 @@
1
- class s {
2
- container;
1
+ var r = class {
2
+ containerOption;
3
+ container = null;
3
4
  gridItems = [];
4
5
  rowHeight = 1;
5
6
  rowGap = 0;
6
7
  resizeScheduled = !1;
8
+ rafId = null;
7
9
  resizeObserver = null;
8
10
  mutationObserver = null;
9
- abortController = null;
10
- originalAutoRows = "";
11
- constructor(t = {}) {
12
- this.container = t.container instanceof HTMLElement ? t.container : typeof t.container == "string" ? document.querySelector(t.container) : document.querySelector(".masonry");
11
+ observerAbortController = null;
12
+ imageAbortController = null;
13
+ observedImages = /* @__PURE__ */ new WeakSet();
14
+ isInitialized = !1;
15
+ isDestroyed = !1;
16
+ originalContainerStyles = {
17
+ gridAutoRows: "",
18
+ contain: "",
19
+ alignItems: ""
20
+ };
21
+ constructor(e = {}) {
22
+ this.containerOption = e.container;
13
23
  }
14
24
  init() {
15
- this.container && (this.setupAbortController(), this.storeAndSetAutoRows(), this.initializeContainerStyles(), this.initializeGridItems(), this.setupResizeObserver(), this.setupMutationObserver(), this.resizeAllItems());
25
+ this.isInitialized || (this.container = this.resolveContainer(), this.container && (this.isInitialized = !0, this.isDestroyed = !1, this.setupAbortControllers(), this.storeContainerStyles(), this.initializeContainerStyles(), this.initializeGridItems(), this.setupResizeObserver(), this.setupMutationObserver(), this.scheduleLayout()));
16
26
  }
17
27
  refresh() {
18
- this.initializeGridItems(), this.resizeAllItems();
28
+ !this.isInitialized || this.isDestroyed || !this.container || (this.initializeGridItems(), this.scheduleLayout());
19
29
  }
20
30
  destroy() {
21
- this.container && (this.abortController?.abort(), this.container.style.gridAutoRows = this.originalAutoRows, this.container.style.contain = "", this.container.style.alignItems = "", this.gridItems.forEach((t) => t.style.gridRowEnd = ""), this.gridItems = [], this.resizeObserver = null, this.mutationObserver = null, this.abortController = null, this.originalAutoRows = "");
31
+ !this.isInitialized && !this.container || (this.isDestroyed = !0, this.isInitialized = !1, this.cancelScheduledLayout(), this.observerAbortController?.abort(), this.imageAbortController?.abort(), this.resizeObserver?.disconnect(), this.mutationObserver?.disconnect(), this.gridItems.forEach((e) => {
32
+ e.style.gridRowEnd = "";
33
+ }), this.container && (this.container.style.gridAutoRows = this.originalContainerStyles.gridAutoRows, this.container.style.contain = this.originalContainerStyles.contain, this.container.style.alignItems = this.originalContainerStyles.alignItems), this.gridItems = [], this.rowHeight = 1, this.rowGap = 0, this.resizeObserver = null, this.mutationObserver = null, this.observerAbortController = null, this.imageAbortController = null, this.observedImages = /* @__PURE__ */ new WeakSet(), this.resizeScheduled = !1, this.container = null, this.originalContainerStyles = {
34
+ gridAutoRows: "",
35
+ contain: "",
36
+ alignItems: ""
37
+ });
22
38
  }
23
- handleResize() {
24
- this.resizeScheduled || (this.resizeScheduled = !0, requestAnimationFrame(() => {
25
- this.resizeAllItems(), this.resizeScheduled = !1;
26
- }));
39
+ resolveContainer() {
40
+ return this.containerOption instanceof HTMLElement ? this.containerOption : typeof document > "u" ? null : typeof this.containerOption == "string" ? document.querySelector(this.containerOption) : document.querySelector(".masonry");
41
+ }
42
+ scheduleLayout() {
43
+ if (!(!this.isInitialized || this.isDestroyed || !this.container || this.resizeScheduled)) {
44
+ if (this.resizeScheduled = !0, typeof requestAnimationFrame == "function") {
45
+ this.rafId = requestAnimationFrame(() => {
46
+ this.rafId = null, this.resizeScheduled = !1, this.performLayout();
47
+ });
48
+ return;
49
+ }
50
+ this.rafId = null, this.resizeScheduled = !1, this.performLayout();
51
+ }
52
+ }
53
+ cancelScheduledLayout() {
54
+ this.rafId !== null && typeof cancelAnimationFrame == "function" && cancelAnimationFrame(this.rafId), this.rafId = null, this.resizeScheduled = !1;
55
+ }
56
+ performLayout() {
57
+ !this.isInitialized || this.isDestroyed || !this.container || (this.measureContainerMetrics(), this.resizeAllItems());
27
58
  }
28
59
  resizeAllItems() {
29
- this.container && (this.container.style.alignItems = "start", this.gridItems.forEach((t) => {
30
- const e = Math.ceil((t.clientHeight + this.rowGap) / (this.rowHeight + this.rowGap));
31
- t.style.gridRowEnd = `span ${e}`;
32
- }));
60
+ const e = this.rowHeight + this.rowGap;
61
+ this.gridItems.forEach((t) => {
62
+ if (e <= 0 || !Number.isFinite(e)) {
63
+ t.style.gridRowEnd = "span 1";
64
+ return;
65
+ }
66
+ const i = Math.max(1, Math.ceil((t.getBoundingClientRect().height + this.rowGap) / e));
67
+ t.style.gridRowEnd = `span ${i}`;
68
+ });
33
69
  }
34
- setupAbortController() {
35
- this.abortController = new AbortController(), this.abortController.signal.addEventListener("abort", () => {
70
+ setupAbortControllers() {
71
+ this.observerAbortController = new AbortController(), this.imageAbortController = new AbortController(), this.observerAbortController.signal.addEventListener("abort", () => {
36
72
  this.resizeObserver?.disconnect(), this.mutationObserver?.disconnect();
37
73
  });
38
74
  }
39
75
  setupResizeObserver() {
40
- this.resizeObserver = new ResizeObserver(() => this.handleResize()), this.resizeObserver.observe(this.container);
76
+ !this.container || typeof ResizeObserver > "u" || (this.resizeObserver = new ResizeObserver(() => this.handleResize()), this.resizeObserver.observe(this.container));
41
77
  }
42
78
  setupMutationObserver() {
43
- this.mutationObserver = new MutationObserver(() => {
44
- this.initializeGridItems(), this.resizeAllItems();
45
- }), this.mutationObserver.observe(this.container, { childList: !0, subtree: !1 });
79
+ !this.container || typeof MutationObserver > "u" || (this.mutationObserver = new MutationObserver(() => {
80
+ this.initializeGridItems(), this.scheduleLayout();
81
+ }), this.mutationObserver.observe(this.container, {
82
+ childList: !0,
83
+ subtree: !1
84
+ }));
85
+ }
86
+ handleResize() {
87
+ this.scheduleLayout();
46
88
  }
47
89
  initializeContainerStyles() {
90
+ this.container && (this.container.style.gridAutoRows = "1px", this.container.style.contain = "layout", this.container.style.alignItems = "start");
91
+ }
92
+ measureContainerMetrics() {
48
93
  if (!this.container) return;
49
- const t = getComputedStyle(this.container);
50
- this.rowGap = parseInt(t.rowGap, 10) || 0;
51
- const e = parseInt(t.gridAutoRows, 10);
52
- this.rowHeight = Number.isNaN(e) ? this.rowHeight : e, this.container.style.contain = "layout";
94
+ const e = getComputedStyle(this.container);
95
+ this.rowGap = this.parseCssPixelValue(e.rowGap);
96
+ const t = this.parseCssPixelValue(e.gridAutoRows);
97
+ this.rowHeight = t > 0 ? t : 1;
53
98
  }
54
99
  initializeGridItems() {
55
- this.container && (this.gridItems = Array.from(this.container.children), this.gridItems.forEach((t) => {
56
- const e = t.querySelector("img");
57
- e && !e.complete && e.addEventListener("load", () => this.resizeAllItems(), { once: !0 });
100
+ this.container && (this.gridItems = Array.from(this.container.children).filter((e) => e instanceof HTMLElement), this.gridItems.forEach((e) => {
101
+ e.querySelectorAll("img").forEach((t) => {
102
+ this.observeImage(t);
103
+ });
58
104
  }));
59
105
  }
60
- storeAndSetAutoRows() {
61
- this.container && (this.originalAutoRows || (this.originalAutoRows = this.container.style.gridAutoRows || ""), this.container.style.gridAutoRows = "1px");
106
+ observeImage(e) {
107
+ if (e.complete || this.observedImages.has(e)) return;
108
+ this.observedImages.add(e);
109
+ const t = () => this.scheduleLayout();
110
+ if (this.imageAbortController) {
111
+ e.addEventListener("load", t, {
112
+ once: !0,
113
+ signal: this.imageAbortController.signal
114
+ });
115
+ return;
116
+ }
117
+ e.addEventListener("load", t, { once: !0 });
62
118
  }
63
- }
119
+ parseCssPixelValue(e) {
120
+ const t = Number.parseFloat(e);
121
+ return Number.isFinite(t) ? t : 0;
122
+ }
123
+ storeContainerStyles() {
124
+ this.container && (this.originalContainerStyles = {
125
+ gridAutoRows: this.container.style.gridAutoRows || "",
126
+ contain: this.container.style.contain || "",
127
+ alignItems: this.container.style.alignItems || ""
128
+ });
129
+ }
130
+ };
64
131
  export {
65
- s as default
132
+ r as default
66
133
  };
134
+
135
+ //# sourceMappingURL=index.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.es.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["interface MasonrySimpleOptions {\n container?: HTMLElement | string;\n}\n\nexport default class MasonrySimple {\n private readonly containerOption: HTMLElement | string | undefined;\n private container: HTMLElement | null = null;\n private gridItems: HTMLElement[] = [];\n private rowHeight = 1;\n private rowGap = 0;\n private resizeScheduled = false;\n private rafId: number | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private mutationObserver: MutationObserver | null = null;\n private observerAbortController: AbortController | null = null;\n private imageAbortController: AbortController | null = null;\n private observedImages = new WeakSet<HTMLImageElement>();\n private isInitialized = false;\n private isDestroyed = false;\n private originalContainerStyles = {\n gridAutoRows: '',\n contain: '',\n alignItems: '',\n };\n\n constructor(options: MasonrySimpleOptions = {}) {\n this.containerOption = options.container;\n }\n\n public init(): void {\n if (this.isInitialized) return;\n\n this.container = this.resolveContainer();\n\n if (!this.container) return;\n\n this.isInitialized = true;\n this.isDestroyed = false;\n\n this.setupAbortControllers();\n this.storeContainerStyles();\n this.initializeContainerStyles();\n this.initializeGridItems();\n this.setupResizeObserver();\n this.setupMutationObserver();\n this.scheduleLayout();\n }\n\n public refresh(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container) return;\n\n this.initializeGridItems();\n this.scheduleLayout();\n }\n\n public destroy(): void {\n if (!this.isInitialized && !this.container) return;\n\n this.isDestroyed = true;\n this.isInitialized = false;\n this.cancelScheduledLayout();\n this.observerAbortController?.abort();\n this.imageAbortController?.abort();\n this.resizeObserver?.disconnect();\n this.mutationObserver?.disconnect();\n this.gridItems.forEach((item) => {\n item.style.gridRowEnd = '';\n });\n\n if (this.container) {\n this.container.style.gridAutoRows = this.originalContainerStyles.gridAutoRows;\n this.container.style.contain = this.originalContainerStyles.contain;\n this.container.style.alignItems = this.originalContainerStyles.alignItems;\n }\n\n this.gridItems = [];\n this.rowHeight = 1;\n this.rowGap = 0;\n this.resizeObserver = null;\n this.mutationObserver = null;\n this.observerAbortController = null;\n this.imageAbortController = null;\n this.observedImages = new WeakSet<HTMLImageElement>();\n this.resizeScheduled = false;\n this.container = null;\n this.originalContainerStyles = {\n gridAutoRows: '',\n contain: '',\n alignItems: '',\n };\n }\n\n private resolveContainer(): HTMLElement | null {\n if (this.containerOption instanceof HTMLElement) {\n return this.containerOption;\n }\n\n if (typeof document === 'undefined') return null;\n\n if (typeof this.containerOption === 'string') {\n return document.querySelector<HTMLElement>(this.containerOption);\n }\n\n return document.querySelector<HTMLElement>('.masonry');\n }\n\n private scheduleLayout(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container || this.resizeScheduled) return;\n\n this.resizeScheduled = true;\n\n if (typeof requestAnimationFrame === 'function') {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n this.resizeScheduled = false;\n this.performLayout();\n });\n\n return;\n }\n\n this.rafId = null;\n this.resizeScheduled = false;\n this.performLayout();\n }\n\n private cancelScheduledLayout(): void {\n if (this.rafId !== null && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(this.rafId);\n }\n\n this.rafId = null;\n this.resizeScheduled = false;\n }\n\n private performLayout(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container) return;\n\n this.measureContainerMetrics();\n this.resizeAllItems();\n }\n\n private resizeAllItems(): void {\n const denominator = this.rowHeight + this.rowGap;\n\n this.gridItems.forEach((item) => {\n if (denominator <= 0 || !Number.isFinite(denominator)) {\n item.style.gridRowEnd = 'span 1';\n\n return;\n }\n\n const rowSpan = Math.max(\n 1,\n Math.ceil((item.getBoundingClientRect().height + this.rowGap) / denominator),\n );\n item.style.gridRowEnd = `span ${rowSpan}`;\n });\n }\n\n private setupAbortControllers(): void {\n this.observerAbortController = new AbortController();\n this.imageAbortController = new AbortController();\n\n this.observerAbortController.signal.addEventListener('abort', () => {\n this.resizeObserver?.disconnect();\n this.mutationObserver?.disconnect();\n });\n }\n\n private setupResizeObserver(): void {\n if (!this.container || typeof ResizeObserver === 'undefined') return;\n\n this.resizeObserver = new ResizeObserver(() => this.handleResize());\n\n this.resizeObserver.observe(this.container);\n }\n\n private setupMutationObserver(): void {\n if (!this.container || typeof MutationObserver === 'undefined') return;\n\n this.mutationObserver = new MutationObserver(() => {\n this.initializeGridItems();\n this.scheduleLayout();\n });\n\n this.mutationObserver.observe(this.container, {\n childList: true,\n subtree: false,\n });\n }\n\n private handleResize(): void {\n this.scheduleLayout();\n }\n\n private initializeContainerStyles(): void {\n if (!this.container) return;\n\n this.container.style.gridAutoRows = '1px';\n this.container.style.contain = 'layout';\n this.container.style.alignItems = 'start';\n }\n\n private measureContainerMetrics(): void {\n if (!this.container) return;\n\n const cs = getComputedStyle(this.container);\n\n this.rowGap = this.parseCssPixelValue(cs.rowGap);\n\n const parsedRowHeight = this.parseCssPixelValue(cs.gridAutoRows);\n\n this.rowHeight = parsedRowHeight > 0 ? parsedRowHeight : 1;\n }\n\n private initializeGridItems(): void {\n if (!this.container) return;\n\n this.gridItems = Array.from(this.container.children).filter(\n (item): item is HTMLElement => item instanceof HTMLElement,\n );\n\n this.gridItems.forEach((item) => {\n const images = item.querySelectorAll('img');\n\n images.forEach((image) => {\n this.observeImage(image);\n });\n });\n }\n\n private observeImage(image: HTMLImageElement): void {\n if (image.complete || this.observedImages.has(image)) return;\n\n this.observedImages.add(image);\n\n const onLoad = (): void => this.scheduleLayout();\n\n if (this.imageAbortController) {\n image.addEventListener('load', onLoad, {\n once: true,\n signal: this.imageAbortController.signal,\n });\n\n return;\n }\n\n image.addEventListener('load', onLoad, { once: true });\n }\n\n private parseCssPixelValue(value: string): number {\n const parsedValue = Number.parseFloat(value);\n\n return Number.isFinite(parsedValue) ? parsedValue : 0;\n }\n\n private storeContainerStyles(): void {\n if (!this.container) return;\n\n this.originalContainerStyles = {\n gridAutoRows: this.container.style.gridAutoRows || '',\n contain: this.container.style.contain || '',\n alignItems: this.container.style.alignItems || '',\n };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ (function(i,e){typeof exports=="object"&&typeof module<"u"?module.exports=e():typeof define=="function"&&define.amd?define([],e):(i=typeof globalThis<"u"?globalThis:i||self,i.MasonrySimple=e())})(this,function(){var i=class{containerOption;container=null;gridItems=[];rowHeight=1;rowGap=0;resizeScheduled=!1;rafId=null;resizeObserver=null;mutationObserver=null;observerAbortController=null;imageAbortController=null;observedImages=new WeakSet;isInitialized=!1;isDestroyed=!1;originalContainerStyles={gridAutoRows:"",contain:"",alignItems:""};constructor(e={}){this.containerOption=e.container}init(){this.isInitialized||(this.container=this.resolveContainer(),this.container&&(this.isInitialized=!0,this.isDestroyed=!1,this.setupAbortControllers(),this.storeContainerStyles(),this.initializeContainerStyles(),this.initializeGridItems(),this.setupResizeObserver(),this.setupMutationObserver(),this.scheduleLayout()))}refresh(){!this.isInitialized||this.isDestroyed||!this.container||(this.initializeGridItems(),this.scheduleLayout())}destroy(){!this.isInitialized&&!this.container||(this.isDestroyed=!0,this.isInitialized=!1,this.cancelScheduledLayout(),this.observerAbortController?.abort(),this.imageAbortController?.abort(),this.resizeObserver?.disconnect(),this.mutationObserver?.disconnect(),this.gridItems.forEach(e=>{e.style.gridRowEnd=""}),this.container&&(this.container.style.gridAutoRows=this.originalContainerStyles.gridAutoRows,this.container.style.contain=this.originalContainerStyles.contain,this.container.style.alignItems=this.originalContainerStyles.alignItems),this.gridItems=[],this.rowHeight=1,this.rowGap=0,this.resizeObserver=null,this.mutationObserver=null,this.observerAbortController=null,this.imageAbortController=null,this.observedImages=new WeakSet,this.resizeScheduled=!1,this.container=null,this.originalContainerStyles={gridAutoRows:"",contain:"",alignItems:""})}resolveContainer(){return this.containerOption instanceof HTMLElement?this.containerOption:typeof document>"u"?null:typeof this.containerOption=="string"?document.querySelector(this.containerOption):document.querySelector(".masonry")}scheduleLayout(){if(!(!this.isInitialized||this.isDestroyed||!this.container||this.resizeScheduled)){if(this.resizeScheduled=!0,typeof requestAnimationFrame=="function"){this.rafId=requestAnimationFrame(()=>{this.rafId=null,this.resizeScheduled=!1,this.performLayout()});return}this.rafId=null,this.resizeScheduled=!1,this.performLayout()}}cancelScheduledLayout(){this.rafId!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.rafId),this.rafId=null,this.resizeScheduled=!1}performLayout(){!this.isInitialized||this.isDestroyed||!this.container||(this.measureContainerMetrics(),this.resizeAllItems())}resizeAllItems(){const e=this.rowHeight+this.rowGap;this.gridItems.forEach(t=>{if(e<=0||!Number.isFinite(e)){t.style.gridRowEnd="span 1";return}const s=Math.max(1,Math.ceil((t.getBoundingClientRect().height+this.rowGap)/e));t.style.gridRowEnd=`span ${s}`})}setupAbortControllers(){this.observerAbortController=new AbortController,this.imageAbortController=new AbortController,this.observerAbortController.signal.addEventListener("abort",()=>{this.resizeObserver?.disconnect(),this.mutationObserver?.disconnect()})}setupResizeObserver(){!this.container||typeof ResizeObserver>"u"||(this.resizeObserver=new ResizeObserver(()=>this.handleResize()),this.resizeObserver.observe(this.container))}setupMutationObserver(){!this.container||typeof MutationObserver>"u"||(this.mutationObserver=new MutationObserver(()=>{this.initializeGridItems(),this.scheduleLayout()}),this.mutationObserver.observe(this.container,{childList:!0,subtree:!1}))}handleResize(){this.scheduleLayout()}initializeContainerStyles(){this.container&&(this.container.style.gridAutoRows="1px",this.container.style.contain="layout",this.container.style.alignItems="start")}measureContainerMetrics(){if(!this.container)return;const e=getComputedStyle(this.container);this.rowGap=this.parseCssPixelValue(e.rowGap);const t=this.parseCssPixelValue(e.gridAutoRows);this.rowHeight=t>0?t:1}initializeGridItems(){this.container&&(this.gridItems=Array.from(this.container.children).filter(e=>e instanceof HTMLElement),this.gridItems.forEach(e=>{e.querySelectorAll("img").forEach(t=>{this.observeImage(t)})}))}observeImage(e){if(e.complete||this.observedImages.has(e))return;this.observedImages.add(e);const t=()=>this.scheduleLayout();if(this.imageAbortController){e.addEventListener("load",t,{once:!0,signal:this.imageAbortController.signal});return}e.addEventListener("load",t,{once:!0})}parseCssPixelValue(e){const t=Number.parseFloat(e);return Number.isFinite(t)?t:0}storeContainerStyles(){this.container&&(this.originalContainerStyles={gridAutoRows:this.container.style.gridAutoRows||"",contain:this.container.style.contain||"",alignItems:this.container.style.alignItems||""})}};return i});
2
+
3
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["interface MasonrySimpleOptions {\n container?: HTMLElement | string;\n}\n\nexport default class MasonrySimple {\n private readonly containerOption: HTMLElement | string | undefined;\n private container: HTMLElement | null = null;\n private gridItems: HTMLElement[] = [];\n private rowHeight = 1;\n private rowGap = 0;\n private resizeScheduled = false;\n private rafId: number | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private mutationObserver: MutationObserver | null = null;\n private observerAbortController: AbortController | null = null;\n private imageAbortController: AbortController | null = null;\n private observedImages = new WeakSet<HTMLImageElement>();\n private isInitialized = false;\n private isDestroyed = false;\n private originalContainerStyles = {\n gridAutoRows: '',\n contain: '',\n alignItems: '',\n };\n\n constructor(options: MasonrySimpleOptions = {}) {\n this.containerOption = options.container;\n }\n\n public init(): void {\n if (this.isInitialized) return;\n\n this.container = this.resolveContainer();\n\n if (!this.container) return;\n\n this.isInitialized = true;\n this.isDestroyed = false;\n\n this.setupAbortControllers();\n this.storeContainerStyles();\n this.initializeContainerStyles();\n this.initializeGridItems();\n this.setupResizeObserver();\n this.setupMutationObserver();\n this.scheduleLayout();\n }\n\n public refresh(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container) return;\n\n this.initializeGridItems();\n this.scheduleLayout();\n }\n\n public destroy(): void {\n if (!this.isInitialized && !this.container) return;\n\n this.isDestroyed = true;\n this.isInitialized = false;\n this.cancelScheduledLayout();\n this.observerAbortController?.abort();\n this.imageAbortController?.abort();\n this.resizeObserver?.disconnect();\n this.mutationObserver?.disconnect();\n this.gridItems.forEach((item) => {\n item.style.gridRowEnd = '';\n });\n\n if (this.container) {\n this.container.style.gridAutoRows = this.originalContainerStyles.gridAutoRows;\n this.container.style.contain = this.originalContainerStyles.contain;\n this.container.style.alignItems = this.originalContainerStyles.alignItems;\n }\n\n this.gridItems = [];\n this.rowHeight = 1;\n this.rowGap = 0;\n this.resizeObserver = null;\n this.mutationObserver = null;\n this.observerAbortController = null;\n this.imageAbortController = null;\n this.observedImages = new WeakSet<HTMLImageElement>();\n this.resizeScheduled = false;\n this.container = null;\n this.originalContainerStyles = {\n gridAutoRows: '',\n contain: '',\n alignItems: '',\n };\n }\n\n private resolveContainer(): HTMLElement | null {\n if (this.containerOption instanceof HTMLElement) {\n return this.containerOption;\n }\n\n if (typeof document === 'undefined') return null;\n\n if (typeof this.containerOption === 'string') {\n return document.querySelector<HTMLElement>(this.containerOption);\n }\n\n return document.querySelector<HTMLElement>('.masonry');\n }\n\n private scheduleLayout(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container || this.resizeScheduled) return;\n\n this.resizeScheduled = true;\n\n if (typeof requestAnimationFrame === 'function') {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n this.resizeScheduled = false;\n this.performLayout();\n });\n\n return;\n }\n\n this.rafId = null;\n this.resizeScheduled = false;\n this.performLayout();\n }\n\n private cancelScheduledLayout(): void {\n if (this.rafId !== null && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(this.rafId);\n }\n\n this.rafId = null;\n this.resizeScheduled = false;\n }\n\n private performLayout(): void {\n if (!this.isInitialized || this.isDestroyed || !this.container) return;\n\n this.measureContainerMetrics();\n this.resizeAllItems();\n }\n\n private resizeAllItems(): void {\n const denominator = this.rowHeight + this.rowGap;\n\n this.gridItems.forEach((item) => {\n if (denominator <= 0 || !Number.isFinite(denominator)) {\n item.style.gridRowEnd = 'span 1';\n\n return;\n }\n\n const rowSpan = Math.max(\n 1,\n Math.ceil((item.getBoundingClientRect().height + this.rowGap) / denominator),\n );\n item.style.gridRowEnd = `span ${rowSpan}`;\n });\n }\n\n private setupAbortControllers(): void {\n this.observerAbortController = new AbortController();\n this.imageAbortController = new AbortController();\n\n this.observerAbortController.signal.addEventListener('abort', () => {\n this.resizeObserver?.disconnect();\n this.mutationObserver?.disconnect();\n });\n }\n\n private setupResizeObserver(): void {\n if (!this.container || typeof ResizeObserver === 'undefined') return;\n\n this.resizeObserver = new ResizeObserver(() => this.handleResize());\n\n this.resizeObserver.observe(this.container);\n }\n\n private setupMutationObserver(): void {\n if (!this.container || typeof MutationObserver === 'undefined') return;\n\n this.mutationObserver = new MutationObserver(() => {\n this.initializeGridItems();\n this.scheduleLayout();\n });\n\n this.mutationObserver.observe(this.container, {\n childList: true,\n subtree: false,\n });\n }\n\n private handleResize(): void {\n this.scheduleLayout();\n }\n\n private initializeContainerStyles(): void {\n if (!this.container) return;\n\n this.container.style.gridAutoRows = '1px';\n this.container.style.contain = 'layout';\n this.container.style.alignItems = 'start';\n }\n\n private measureContainerMetrics(): void {\n if (!this.container) return;\n\n const cs = getComputedStyle(this.container);\n\n this.rowGap = this.parseCssPixelValue(cs.rowGap);\n\n const parsedRowHeight = this.parseCssPixelValue(cs.gridAutoRows);\n\n this.rowHeight = parsedRowHeight > 0 ? parsedRowHeight : 1;\n }\n\n private initializeGridItems(): void {\n if (!this.container) return;\n\n this.gridItems = Array.from(this.container.children).filter(\n (item): item is HTMLElement => item instanceof HTMLElement,\n );\n\n this.gridItems.forEach((item) => {\n const images = item.querySelectorAll('img');\n\n images.forEach((image) => {\n this.observeImage(image);\n });\n });\n }\n\n private observeImage(image: HTMLImageElement): void {\n if (image.complete || this.observedImages.has(image)) return;\n\n this.observedImages.add(image);\n\n const onLoad = (): void => this.scheduleLayout();\n\n if (this.imageAbortController) {\n image.addEventListener('load', onLoad, {\n once: true,\n signal: this.imageAbortController.signal,\n });\n\n return;\n }\n\n image.addEventListener('load', onLoad, { once: true });\n }\n\n private parseCssPixelValue(value: string): number {\n const parsedValue = Number.parseFloat(value);\n\n return Number.isFinite(parsedValue) ? parsedValue : 0;\n }\n\n private storeContainerStyles(): void {\n if (!this.container) return;\n\n this.originalContainerStyles = {\n gridAutoRows: this.container.style.gridAutoRows || '',\n contain: this.container.style.contain || '',\n alignItems: this.container.style.alignItems || '',\n };\n }\n}\n"],"mappings":"oNAIA,IAAqB,EAArB,KAAmC,CACjC,gBACA,UAAwC,KACxC,UAAmC,CAAA,EACnC,UAAoB,EACpB,OAAiB,EACjB,gBAA0B,GAC1B,MAA+B,KAC/B,eAAgD,KAChD,iBAAoD,KACpD,wBAA0D,KAC1D,qBAAuD,KACvD,eAAyB,IAAI,QAC7B,cAAwB,GACxB,YAAsB,GACtB,wBAAkC,CAChC,aAAc,GACd,QAAS,GACT,WAAY,IAGd,YAAY,EAAgC,CAAA,EAAI,CAC9C,KAAK,gBAAkB,EAAQ,UAGjC,MAAoB,CACd,KAAK,gBAET,KAAK,UAAY,KAAK,iBAAA,EAEjB,KAAK,YAEV,KAAK,cAAgB,GACrB,KAAK,YAAc,GAEnB,KAAK,sBAAA,EACL,KAAK,qBAAA,EACL,KAAK,0BAAA,EACL,KAAK,oBAAA,EACL,KAAK,oBAAA,EACL,KAAK,sBAAA,EACL,KAAK,eAAA,IAGP,SAAuB,CACjB,CAAC,KAAK,eAAiB,KAAK,aAAe,CAAC,KAAK,YAErD,KAAK,oBAAA,EACL,KAAK,eAAA,GAGP,SAAuB,CACjB,CAAC,KAAK,eAAiB,CAAC,KAAK,YAEjC,KAAK,YAAc,GACnB,KAAK,cAAgB,GACrB,KAAK,sBAAA,EACL,KAAK,yBAAyB,MAAA,EAC9B,KAAK,sBAAsB,MAAA,EAC3B,KAAK,gBAAgB,WAAA,EACrB,KAAK,kBAAkB,WAAA,EACvB,KAAK,UAAU,QAAS,GAAS,CAC/B,EAAK,MAAM,WAAa,KAGtB,KAAK,YACP,KAAK,UAAU,MAAM,aAAe,KAAK,wBAAwB,aACjE,KAAK,UAAU,MAAM,QAAU,KAAK,wBAAwB,QAC5D,KAAK,UAAU,MAAM,WAAa,KAAK,wBAAwB,YAGjE,KAAK,UAAY,CAAA,EACjB,KAAK,UAAY,EACjB,KAAK,OAAS,EACd,KAAK,eAAiB,KACtB,KAAK,iBAAmB,KACxB,KAAK,wBAA0B,KAC/B,KAAK,qBAAuB,KAC5B,KAAK,eAAiB,IAAI,QAC1B,KAAK,gBAAkB,GACvB,KAAK,UAAY,KACjB,KAAK,wBAA0B,CAC7B,aAAc,GACd,QAAS,GACT,WAAY,KAIhB,kBAA+C,CAC7C,OAAI,KAAK,2BAA2B,YAC3B,KAAK,gBAGV,OAAO,SAAa,IAAoB,KAExC,OAAO,KAAK,iBAAoB,SAC3B,SAAS,cAA2B,KAAK,eAAA,EAG3C,SAAS,cAA2B,UAAA,EAG7C,gBAA+B,CAC7B,GAAI,GAAC,KAAK,eAAiB,KAAK,aAAe,CAAC,KAAK,WAAa,KAAK,iBAIvE,IAFA,KAAK,gBAAkB,GAEnB,OAAO,uBAA0B,WAAY,CAC/C,KAAK,MAAQ,sBAAA,IAA4B,CACvC,KAAK,MAAQ,KACb,KAAK,gBAAkB,GACvB,KAAK,cAAA,IAGP,OAGF,KAAK,MAAQ,KACb,KAAK,gBAAkB,GACvB,KAAK,cAAA,GAGP,uBAAsC,CAChC,KAAK,QAAU,MAAQ,OAAO,sBAAyB,YACzD,qBAAqB,KAAK,KAAA,EAG5B,KAAK,MAAQ,KACb,KAAK,gBAAkB,GAGzB,eAA8B,CACxB,CAAC,KAAK,eAAiB,KAAK,aAAe,CAAC,KAAK,YAErD,KAAK,wBAAA,EACL,KAAK,eAAA,GAGP,gBAA+B,CAC7B,MAAM,EAAc,KAAK,UAAY,KAAK,OAE1C,KAAK,UAAU,QAAS,GAAS,CAC/B,GAAI,GAAe,GAAK,CAAC,OAAO,SAAS,CAAA,EAAc,CACrD,EAAK,MAAM,WAAa,SAExB,OAGF,MAAM,EAAU,KAAK,IACnB,EACA,KAAK,MAAM,EAAK,sBAAA,EAAwB,OAAS,KAAK,QAAU,CAAA,CAAY,EAE9E,EAAK,MAAM,WAAa,QAAQ,CAAA,KAIpC,uBAAsC,CACpC,KAAK,wBAA0B,IAAI,gBACnC,KAAK,qBAAuB,IAAI,gBAEhC,KAAK,wBAAwB,OAAO,iBAAiB,QAAA,IAAe,CAClE,KAAK,gBAAgB,WAAA,EACrB,KAAK,kBAAkB,WAAA,IAI3B,qBAAoC,CAC9B,CAAC,KAAK,WAAa,OAAO,eAAmB,MAEjD,KAAK,eAAiB,IAAI,eAAA,IAAqB,KAAK,aAAA,CAAc,EAElE,KAAK,eAAe,QAAQ,KAAK,SAAA,GAGnC,uBAAsC,CAChC,CAAC,KAAK,WAAa,OAAO,iBAAqB,MAEnD,KAAK,iBAAmB,IAAI,iBAAA,IAAuB,CACjD,KAAK,oBAAA,EACL,KAAK,eAAA,IAGP,KAAK,iBAAiB,QAAQ,KAAK,UAAW,CAC5C,UAAW,GACX,QAAS,GACV,GAGH,cAA6B,CAC3B,KAAK,eAAA,EAGP,2BAA0C,CACnC,KAAK,YAEV,KAAK,UAAU,MAAM,aAAe,MACpC,KAAK,UAAU,MAAM,QAAU,SAC/B,KAAK,UAAU,MAAM,WAAa,SAGpC,yBAAwC,CACtC,GAAI,CAAC,KAAK,UAAW,OAErB,MAAM,EAAK,iBAAiB,KAAK,SAAA,EAEjC,KAAK,OAAS,KAAK,mBAAmB,EAAG,MAAA,EAEzC,MAAM,EAAkB,KAAK,mBAAmB,EAAG,YAAA,EAEnD,KAAK,UAAY,EAAkB,EAAI,EAAkB,EAG3D,qBAAoC,CAC7B,KAAK,YAEV,KAAK,UAAY,MAAM,KAAK,KAAK,UAAU,QAAA,EAAU,OAClD,GAA8B,aAAgB,WAAA,EAGjD,KAAK,UAAU,QAAS,GAAS,CAChB,EAAK,iBAAiB,KAAA,EAE9B,QAAS,GAAU,CACxB,KAAK,aAAa,CAAA,OAKxB,aAAqB,EAA+B,CAClD,GAAI,EAAM,UAAY,KAAK,eAAe,IAAI,CAAA,EAAQ,OAEtD,KAAK,eAAe,IAAI,CAAA,EAExB,MAAM,EAAA,IAAqB,KAAK,eAAA,EAEhC,GAAI,KAAK,qBAAsB,CAC7B,EAAM,iBAAiB,OAAQ,EAAQ,CACrC,KAAM,GACN,OAAQ,KAAK,qBAAqB,OACnC,EAED,OAGF,EAAM,iBAAiB,OAAQ,EAAQ,CAAE,KAAM,EAAA,CAAM,EAGvD,mBAA2B,EAAuB,CAChD,MAAM,EAAc,OAAO,WAAW,CAAA,EAEtC,OAAO,OAAO,SAAS,CAAA,EAAe,EAAc,EAGtD,sBAAqC,CAC9B,KAAK,YAEV,KAAK,wBAA0B,CAC7B,aAAc,KAAK,UAAU,MAAM,cAAgB,GACnD,QAAS,KAAK,UAAU,MAAM,SAAW,GACzC,WAAY,KAAK,UAAU,MAAM,YAAc"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "masonry-simple",
3
- "version": "4.4.0",
3
+ "version": "4.5.0",
4
4
  "description": "MasonrySimple implements a simple system for placing masonry style elements using CSS Grid. Masonry placement is used for dynamic grids where elements may have different heights and need to be placed neatly without gaps.",
5
5
  "author": "ux-ui.pro",
6
6
  "license": "MIT",
@@ -13,43 +13,49 @@
13
13
  },
14
14
  "homepage": "https://github.com/ux-ui-pro/masonry-simple",
15
15
  "sideEffects": false,
16
+ "type": "module",
17
+ "packageManager": "yarn@1.22.22",
18
+ "engines": {
19
+ "node": ">=18.0.0"
20
+ },
16
21
  "scripts": {
17
22
  "clean": "rimraf dist",
18
23
  "build": "vite build",
19
- "lint:js": "eslint src/**/*.{ts,js}",
20
- "lint:fix:js": "eslint src/**/*.{ts,js} --fix",
21
- "format:js": "prettier --write src/**/*.{ts,js}",
22
- "lint:fix": "yarn lint:fix:js && yarn format:js"
24
+ "dev": "vite",
25
+ "verify": "yarn build && yarn lint && yarn typecheck && yarn test:smoke",
26
+ "lint": "biome check src tests",
27
+ "lint:fix": "biome check --write src tests",
28
+ "format": "biome format --write src tests",
29
+ "typecheck": "tsc -p tsconfig.json --noEmit",
30
+ "test:smoke": "node --test tests/*.js",
31
+ "prepublishOnly": "yarn clean && yarn verify"
23
32
  },
24
33
  "source": "src/index.ts",
25
34
  "main": "dist/index.cjs.js",
26
35
  "module": "dist/index.es.js",
36
+ "browser": "./dist/index.umd.js",
27
37
  "types": "dist/index.d.ts",
28
38
  "exports": {
29
39
  ".": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/index.es.js",
30
42
  "require": "./dist/index.cjs.js",
31
- "import": "./dist/index.es.js"
43
+ "default": "./dist/index.umd.js"
32
44
  },
33
45
  "./dist/*": "./dist/*"
34
46
  },
35
47
  "files": [
36
- "dist/"
48
+ "dist",
49
+ "README.md",
50
+ "LICENSE"
37
51
  ],
38
52
  "devDependencies": {
39
- "@eslint/js": "9.31.0",
40
- "@rollup/plugin-terser": "0.4.4",
41
- "@types/node": "24.0.14",
42
- "@typescript-eslint/eslint-plugin": "8.37.0",
43
- "@typescript-eslint/parser": "8.37.0",
44
- "eslint": "9.31.0",
45
- "eslint-config-prettier": "10.1.5",
46
- "eslint-import-resolver-typescript": "4.4.4",
47
- "eslint-plugin-import": "2.32.0",
48
- "globals": "16.3.0",
49
- "prettier": "3.6.2",
50
- "rimraf": "6.0.1",
51
- "typescript": "5.8.3",
52
- "vite": "7.0.4",
53
+ "@biomejs/biome": "2.4.8",
54
+ "@types/node": "25.5.0",
55
+ "esbuild": "0.27.4",
56
+ "rimraf": "6.1.3",
57
+ "typescript": "6.0.2",
58
+ "vite": "8.0.2",
53
59
  "vite-plugin-dts": "4.5.4"
54
60
  },
55
61
  "keywords": [