masonry-simple 4.5.0 → 5.0.1

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
@@ -2,15 +2,24 @@
2
2
 
3
3
  A lightweight masonry layout helper built on top of CSS Grid.
4
4
 
5
+ [![npm](https://img.shields.io/npm/v/masonry-simple.svg?colorB=brightgreen)](https://www.npmjs.com/package/masonry-simple)
6
+ [![NPM Downloads](https://img.shields.io/npm/dm/masonry-simple.svg?style=flat)](https://www.npmjs.com/package/masonry-simple)
7
+
8
+ [Demo](https://codepen.io/ux-ui/pen/poxGEqX)
9
+
10
+ ---
11
+
5
12
  - Idempotent lifecycle: `init()`, `refresh()`, `destroy()`.
6
13
  - Unified layout scheduling for resize, mutations, image load, and manual refresh.
7
14
  - Safe teardown with observer/listener cleanup and inline-style restoration.
8
15
  - Supports dynamic image content and responsive CSS changes.
9
16
 
17
+ ---
18
+
10
19
  ## Install
11
20
 
12
21
  ```bash
13
- yarn add masonry-simple
22
+ npm install masonry-simple
14
23
  ```
15
24
 
16
25
  ## Usage (TypeScript)
package/dist/index.cjs ADDED
@@ -0,0 +1,198 @@
1
+
2
+ //#region src/index.ts
3
+ var MasonrySimple = class {
4
+ containerOption;
5
+ container = null;
6
+ gridItems = [];
7
+ rowHeight = 1;
8
+ rowGap = 0;
9
+ resizeScheduled = false;
10
+ rafId = null;
11
+ resizeObserver = null;
12
+ mutationObserver = null;
13
+ observerAbortController = null;
14
+ imageAbortController = null;
15
+ observedImages = /* @__PURE__ */ new WeakSet();
16
+ isInitialized = false;
17
+ isDestroyed = false;
18
+ originalContainerStyles = {
19
+ gridAutoRows: "",
20
+ contain: "",
21
+ alignItems: ""
22
+ };
23
+ constructor(options = {}) {
24
+ this.containerOption = options.container;
25
+ }
26
+ init() {
27
+ if (this.isInitialized) return;
28
+ this.container = this.resolveContainer();
29
+ if (!this.container) return;
30
+ this.isInitialized = true;
31
+ this.isDestroyed = false;
32
+ this.setupAbortControllers();
33
+ this.storeContainerStyles();
34
+ this.initializeContainerStyles();
35
+ this.initializeGridItems();
36
+ this.setupResizeObserver();
37
+ this.setupMutationObserver();
38
+ this.scheduleLayout();
39
+ }
40
+ refresh() {
41
+ if (!this.isInitialized || this.isDestroyed || !this.container) return;
42
+ this.initializeGridItems();
43
+ this.scheduleLayout();
44
+ }
45
+ destroy() {
46
+ if (!this.isInitialized && !this.container) return;
47
+ this.isDestroyed = true;
48
+ this.isInitialized = false;
49
+ this.cancelScheduledLayout();
50
+ this.observerAbortController?.abort();
51
+ this.imageAbortController?.abort();
52
+ this.resizeObserver?.disconnect();
53
+ this.mutationObserver?.disconnect();
54
+ this.gridItems.forEach((item) => {
55
+ item.style.gridRowEnd = "";
56
+ });
57
+ if (this.container) {
58
+ this.container.style.gridAutoRows = this.originalContainerStyles.gridAutoRows;
59
+ this.container.style.contain = this.originalContainerStyles.contain;
60
+ this.container.style.alignItems = this.originalContainerStyles.alignItems;
61
+ }
62
+ this.gridItems = [];
63
+ this.rowHeight = 1;
64
+ this.rowGap = 0;
65
+ this.resizeObserver = null;
66
+ this.mutationObserver = null;
67
+ this.observerAbortController = null;
68
+ this.imageAbortController = null;
69
+ this.observedImages = /* @__PURE__ */ new WeakSet();
70
+ this.resizeScheduled = false;
71
+ this.container = null;
72
+ this.originalContainerStyles = {
73
+ gridAutoRows: "",
74
+ contain: "",
75
+ alignItems: ""
76
+ };
77
+ }
78
+ resolveContainer() {
79
+ if (this.containerOption instanceof HTMLElement) return this.containerOption;
80
+ if (typeof document === "undefined") return null;
81
+ if (typeof this.containerOption === "string") return document.querySelector(this.containerOption);
82
+ return document.querySelector(".masonry");
83
+ }
84
+ scheduleLayout() {
85
+ if (!this.isInitialized || this.isDestroyed || !this.container || this.resizeScheduled) return;
86
+ this.resizeScheduled = true;
87
+ if (typeof requestAnimationFrame === "function") {
88
+ this.rafId = requestAnimationFrame(() => {
89
+ this.rafId = null;
90
+ this.resizeScheduled = false;
91
+ this.performLayout();
92
+ });
93
+ return;
94
+ }
95
+ this.rafId = null;
96
+ this.resizeScheduled = false;
97
+ this.performLayout();
98
+ }
99
+ cancelScheduledLayout() {
100
+ if (this.rafId !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(this.rafId);
101
+ this.rafId = null;
102
+ this.resizeScheduled = false;
103
+ }
104
+ performLayout() {
105
+ if (!this.isInitialized || this.isDestroyed || !this.container) return;
106
+ this.measureContainerMetrics();
107
+ this.resizeAllItems();
108
+ }
109
+ resizeAllItems() {
110
+ const denominator = this.rowHeight + this.rowGap;
111
+ this.gridItems.forEach((item) => {
112
+ if (denominator <= 0 || !Number.isFinite(denominator)) {
113
+ item.style.gridRowEnd = "span 1";
114
+ return;
115
+ }
116
+ const rowSpan = Math.max(1, Math.ceil((item.getBoundingClientRect().height + this.rowGap) / denominator));
117
+ item.style.gridRowEnd = `span ${rowSpan}`;
118
+ });
119
+ }
120
+ setupAbortControllers() {
121
+ this.observerAbortController = new AbortController();
122
+ this.imageAbortController = new AbortController();
123
+ this.observerAbortController.signal.addEventListener("abort", () => {
124
+ this.resizeObserver?.disconnect();
125
+ this.mutationObserver?.disconnect();
126
+ });
127
+ }
128
+ setupResizeObserver() {
129
+ if (!this.container || typeof ResizeObserver === "undefined") return;
130
+ this.resizeObserver = new ResizeObserver(() => this.handleResize());
131
+ this.resizeObserver.observe(this.container);
132
+ }
133
+ setupMutationObserver() {
134
+ if (!this.container || typeof MutationObserver === "undefined") return;
135
+ this.mutationObserver = new MutationObserver(() => {
136
+ this.initializeGridItems();
137
+ this.scheduleLayout();
138
+ });
139
+ this.mutationObserver.observe(this.container, {
140
+ childList: true,
141
+ subtree: false
142
+ });
143
+ }
144
+ handleResize() {
145
+ this.scheduleLayout();
146
+ }
147
+ initializeContainerStyles() {
148
+ if (!this.container) return;
149
+ this.container.style.gridAutoRows = "1px";
150
+ this.container.style.contain = "layout";
151
+ this.container.style.alignItems = "start";
152
+ }
153
+ measureContainerMetrics() {
154
+ if (!this.container) return;
155
+ const cs = getComputedStyle(this.container);
156
+ this.rowGap = this.parseCssPixelValue(cs.rowGap);
157
+ const parsedRowHeight = this.parseCssPixelValue(cs.gridAutoRows);
158
+ this.rowHeight = parsedRowHeight > 0 ? parsedRowHeight : 1;
159
+ }
160
+ initializeGridItems() {
161
+ if (!this.container) return;
162
+ this.gridItems = Array.from(this.container.children).filter((item) => item instanceof HTMLElement);
163
+ this.gridItems.forEach((item) => {
164
+ item.querySelectorAll("img").forEach((image) => {
165
+ this.observeImage(image);
166
+ });
167
+ });
168
+ }
169
+ observeImage(image) {
170
+ if (image.complete || this.observedImages.has(image)) return;
171
+ this.observedImages.add(image);
172
+ const onLoad = () => this.scheduleLayout();
173
+ if (this.imageAbortController) {
174
+ image.addEventListener("load", onLoad, {
175
+ once: true,
176
+ signal: this.imageAbortController.signal
177
+ });
178
+ return;
179
+ }
180
+ image.addEventListener("load", onLoad, { once: true });
181
+ }
182
+ parseCssPixelValue(value) {
183
+ const parsedValue = Number.parseFloat(value);
184
+ return Number.isFinite(parsedValue) ? parsedValue : 0;
185
+ }
186
+ storeContainerStyles() {
187
+ if (!this.container) return;
188
+ this.originalContainerStyles = {
189
+ gridAutoRows: this.container.style.gridAutoRows || "",
190
+ contain: this.container.style.contain || "",
191
+ alignItems: this.container.style.alignItems || ""
192
+ };
193
+ }
194
+ };
195
+
196
+ //#endregion
197
+ module.exports = MasonrySimple;
198
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","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,42 @@
1
+ //#region src/index.d.ts
2
+ interface MasonrySimpleOptions {
3
+ container?: HTMLElement | string;
4
+ }
5
+ declare class MasonrySimple {
6
+ private readonly containerOption;
7
+ private container;
8
+ private gridItems;
9
+ private rowHeight;
10
+ private rowGap;
11
+ private resizeScheduled;
12
+ private rafId;
13
+ private resizeObserver;
14
+ private mutationObserver;
15
+ private observerAbortController;
16
+ private imageAbortController;
17
+ private observedImages;
18
+ private isInitialized;
19
+ private isDestroyed;
20
+ private originalContainerStyles;
21
+ constructor(options?: MasonrySimpleOptions);
22
+ init(): void;
23
+ refresh(): void;
24
+ destroy(): void;
25
+ private resolveContainer;
26
+ private scheduleLayout;
27
+ private cancelScheduledLayout;
28
+ private performLayout;
29
+ private resizeAllItems;
30
+ private setupAbortControllers;
31
+ private setupResizeObserver;
32
+ private setupMutationObserver;
33
+ private handleResize;
34
+ private initializeContainerStyles;
35
+ private measureContainerMetrics;
36
+ private initializeGridItems;
37
+ private observeImage;
38
+ private parseCssPixelValue;
39
+ private storeContainerStyles;
40
+ }
41
+ export = MasonrySimple;
42
+ //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,43 +1,43 @@
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 { }
1
+ //#region src/index.d.ts
2
+ interface MasonrySimpleOptions {
3
+ container?: HTMLElement | string;
4
+ }
5
+ declare class MasonrySimple {
6
+ private readonly containerOption;
7
+ private container;
8
+ private gridItems;
9
+ private rowHeight;
10
+ private rowGap;
11
+ private resizeScheduled;
12
+ private rafId;
13
+ private resizeObserver;
14
+ private mutationObserver;
15
+ private observerAbortController;
16
+ private imageAbortController;
17
+ private observedImages;
18
+ private isInitialized;
19
+ private isDestroyed;
20
+ private originalContainerStyles;
21
+ constructor(options?: MasonrySimpleOptions);
22
+ init(): void;
23
+ refresh(): void;
24
+ destroy(): void;
25
+ private resolveContainer;
26
+ private scheduleLayout;
27
+ private cancelScheduledLayout;
28
+ private performLayout;
29
+ private resizeAllItems;
30
+ private setupAbortControllers;
31
+ private setupResizeObserver;
32
+ private setupMutationObserver;
33
+ private handleResize;
34
+ private initializeContainerStyles;
35
+ private measureContainerMetrics;
36
+ private initializeGridItems;
37
+ private observeImage;
38
+ private parseCssPixelValue;
39
+ private storeContainerStyles;
40
+ }
41
+ //#endregion
42
+ export { MasonrySimple as default };
43
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,197 @@
1
+ //#region src/index.ts
2
+ var MasonrySimple = class {
3
+ containerOption;
4
+ container = null;
5
+ gridItems = [];
6
+ rowHeight = 1;
7
+ rowGap = 0;
8
+ resizeScheduled = false;
9
+ rafId = null;
10
+ resizeObserver = null;
11
+ mutationObserver = null;
12
+ observerAbortController = null;
13
+ imageAbortController = null;
14
+ observedImages = /* @__PURE__ */ new WeakSet();
15
+ isInitialized = false;
16
+ isDestroyed = false;
17
+ originalContainerStyles = {
18
+ gridAutoRows: "",
19
+ contain: "",
20
+ alignItems: ""
21
+ };
22
+ constructor(options = {}) {
23
+ this.containerOption = options.container;
24
+ }
25
+ init() {
26
+ if (this.isInitialized) return;
27
+ this.container = this.resolveContainer();
28
+ if (!this.container) return;
29
+ this.isInitialized = true;
30
+ this.isDestroyed = false;
31
+ this.setupAbortControllers();
32
+ this.storeContainerStyles();
33
+ this.initializeContainerStyles();
34
+ this.initializeGridItems();
35
+ this.setupResizeObserver();
36
+ this.setupMutationObserver();
37
+ this.scheduleLayout();
38
+ }
39
+ refresh() {
40
+ if (!this.isInitialized || this.isDestroyed || !this.container) return;
41
+ this.initializeGridItems();
42
+ this.scheduleLayout();
43
+ }
44
+ destroy() {
45
+ if (!this.isInitialized && !this.container) return;
46
+ this.isDestroyed = true;
47
+ this.isInitialized = false;
48
+ this.cancelScheduledLayout();
49
+ this.observerAbortController?.abort();
50
+ this.imageAbortController?.abort();
51
+ this.resizeObserver?.disconnect();
52
+ this.mutationObserver?.disconnect();
53
+ this.gridItems.forEach((item) => {
54
+ item.style.gridRowEnd = "";
55
+ });
56
+ if (this.container) {
57
+ this.container.style.gridAutoRows = this.originalContainerStyles.gridAutoRows;
58
+ this.container.style.contain = this.originalContainerStyles.contain;
59
+ this.container.style.alignItems = this.originalContainerStyles.alignItems;
60
+ }
61
+ this.gridItems = [];
62
+ this.rowHeight = 1;
63
+ this.rowGap = 0;
64
+ this.resizeObserver = null;
65
+ this.mutationObserver = null;
66
+ this.observerAbortController = null;
67
+ this.imageAbortController = null;
68
+ this.observedImages = /* @__PURE__ */ new WeakSet();
69
+ this.resizeScheduled = false;
70
+ this.container = null;
71
+ this.originalContainerStyles = {
72
+ gridAutoRows: "",
73
+ contain: "",
74
+ alignItems: ""
75
+ };
76
+ }
77
+ resolveContainer() {
78
+ if (this.containerOption instanceof HTMLElement) return this.containerOption;
79
+ if (typeof document === "undefined") return null;
80
+ if (typeof this.containerOption === "string") return document.querySelector(this.containerOption);
81
+ return document.querySelector(".masonry");
82
+ }
83
+ scheduleLayout() {
84
+ if (!this.isInitialized || this.isDestroyed || !this.container || this.resizeScheduled) return;
85
+ this.resizeScheduled = true;
86
+ if (typeof requestAnimationFrame === "function") {
87
+ this.rafId = requestAnimationFrame(() => {
88
+ this.rafId = null;
89
+ this.resizeScheduled = false;
90
+ this.performLayout();
91
+ });
92
+ return;
93
+ }
94
+ this.rafId = null;
95
+ this.resizeScheduled = false;
96
+ this.performLayout();
97
+ }
98
+ cancelScheduledLayout() {
99
+ if (this.rafId !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(this.rafId);
100
+ this.rafId = null;
101
+ this.resizeScheduled = false;
102
+ }
103
+ performLayout() {
104
+ if (!this.isInitialized || this.isDestroyed || !this.container) return;
105
+ this.measureContainerMetrics();
106
+ this.resizeAllItems();
107
+ }
108
+ resizeAllItems() {
109
+ const denominator = this.rowHeight + this.rowGap;
110
+ this.gridItems.forEach((item) => {
111
+ if (denominator <= 0 || !Number.isFinite(denominator)) {
112
+ item.style.gridRowEnd = "span 1";
113
+ return;
114
+ }
115
+ const rowSpan = Math.max(1, Math.ceil((item.getBoundingClientRect().height + this.rowGap) / denominator));
116
+ item.style.gridRowEnd = `span ${rowSpan}`;
117
+ });
118
+ }
119
+ setupAbortControllers() {
120
+ this.observerAbortController = new AbortController();
121
+ this.imageAbortController = new AbortController();
122
+ this.observerAbortController.signal.addEventListener("abort", () => {
123
+ this.resizeObserver?.disconnect();
124
+ this.mutationObserver?.disconnect();
125
+ });
126
+ }
127
+ setupResizeObserver() {
128
+ if (!this.container || typeof ResizeObserver === "undefined") return;
129
+ this.resizeObserver = new ResizeObserver(() => this.handleResize());
130
+ this.resizeObserver.observe(this.container);
131
+ }
132
+ setupMutationObserver() {
133
+ if (!this.container || typeof MutationObserver === "undefined") return;
134
+ this.mutationObserver = new MutationObserver(() => {
135
+ this.initializeGridItems();
136
+ this.scheduleLayout();
137
+ });
138
+ this.mutationObserver.observe(this.container, {
139
+ childList: true,
140
+ subtree: false
141
+ });
142
+ }
143
+ handleResize() {
144
+ this.scheduleLayout();
145
+ }
146
+ initializeContainerStyles() {
147
+ if (!this.container) return;
148
+ this.container.style.gridAutoRows = "1px";
149
+ this.container.style.contain = "layout";
150
+ this.container.style.alignItems = "start";
151
+ }
152
+ measureContainerMetrics() {
153
+ if (!this.container) return;
154
+ const cs = getComputedStyle(this.container);
155
+ this.rowGap = this.parseCssPixelValue(cs.rowGap);
156
+ const parsedRowHeight = this.parseCssPixelValue(cs.gridAutoRows);
157
+ this.rowHeight = parsedRowHeight > 0 ? parsedRowHeight : 1;
158
+ }
159
+ initializeGridItems() {
160
+ if (!this.container) return;
161
+ this.gridItems = Array.from(this.container.children).filter((item) => item instanceof HTMLElement);
162
+ this.gridItems.forEach((item) => {
163
+ item.querySelectorAll("img").forEach((image) => {
164
+ this.observeImage(image);
165
+ });
166
+ });
167
+ }
168
+ observeImage(image) {
169
+ if (image.complete || this.observedImages.has(image)) return;
170
+ this.observedImages.add(image);
171
+ const onLoad = () => this.scheduleLayout();
172
+ if (this.imageAbortController) {
173
+ image.addEventListener("load", onLoad, {
174
+ once: true,
175
+ signal: this.imageAbortController.signal
176
+ });
177
+ return;
178
+ }
179
+ image.addEventListener("load", onLoad, { once: true });
180
+ }
181
+ parseCssPixelValue(value) {
182
+ const parsedValue = Number.parseFloat(value);
183
+ return Number.isFinite(parsedValue) ? parsedValue : 0;
184
+ }
185
+ storeContainerStyles() {
186
+ if (!this.container) return;
187
+ this.originalContainerStyles = {
188
+ gridAutoRows: this.container.style.gridAutoRows || "",
189
+ contain: this.container.style.contain || "",
190
+ alignItems: this.container.style.alignItems || ""
191
+ };
192
+ }
193
+ };
194
+
195
+ //#endregion
196
+ export { MasonrySimple as default };
197
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "masonry-simple",
3
- "version": "4.5.0",
3
+ "version": "5.0.1",
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",
@@ -14,49 +14,57 @@
14
14
  "homepage": "https://github.com/ux-ui-pro/masonry-simple",
15
15
  "sideEffects": false,
16
16
  "type": "module",
17
- "packageManager": "yarn@1.22.22",
17
+ "packageManager": "npm@10.9.3",
18
18
  "engines": {
19
- "node": ">=18.0.0"
19
+ "node": ">=20.19.0"
20
20
  },
21
21
  "scripts": {
22
22
  "clean": "rimraf dist",
23
- "build": "vite build",
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",
23
+ "build": "tsdown",
24
+ "verify": "npm run lint && npm run typecheck && npm run build && npm run test:smoke && npm run pack:check",
25
+ "lint": "biome check src tests tsdown.config.ts",
26
+ "lint:fix": "biome check --write src tests tsdown.config.ts",
27
+ "format": "biome format --write src tests tsdown.config.ts",
29
28
  "typecheck": "tsc -p tsconfig.json --noEmit",
30
- "test:smoke": "node --test tests/*.js",
31
- "prepublishOnly": "yarn clean && yarn verify"
29
+ "test:smoke": "node --test \"tests/**/*.js\"",
30
+ "pack:check": "npm pack --dry-run && publint && attw --pack . --profile node16 --ignore-rules false-export-default",
31
+ "prepublishOnly": "npm run clean && npm run verify"
32
32
  },
33
33
  "source": "src/index.ts",
34
- "main": "dist/index.cjs.js",
35
- "module": "dist/index.es.js",
36
- "browser": "./dist/index.umd.js",
37
- "types": "dist/index.d.ts",
34
+ "main": "./dist/index.cjs",
35
+ "module": "./dist/index.js",
36
+ "types": "./dist/index.d.ts",
38
37
  "exports": {
39
38
  ".": {
40
- "types": "./dist/index.d.ts",
41
- "import": "./dist/index.es.js",
42
- "require": "./dist/index.cjs.js",
43
- "default": "./dist/index.umd.js"
44
- },
45
- "./dist/*": "./dist/*"
39
+ "import": {
40
+ "types": "./dist/index.d.ts",
41
+ "default": "./dist/index.js"
42
+ },
43
+ "require": {
44
+ "types": "./dist/index.d.cts",
45
+ "default": "./dist/index.cjs"
46
+ }
47
+ }
46
48
  },
47
49
  "files": [
48
50
  "dist",
49
51
  "README.md",
50
52
  "LICENSE"
51
53
  ],
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
52
57
  "devDependencies": {
53
- "@biomejs/biome": "2.4.8",
54
- "@types/node": "25.5.0",
55
- "esbuild": "0.27.4",
58
+ "@arethetypeswrong/cli": "^0.18.3",
59
+ "@biomejs/biome": "2.4.16",
60
+ "@types/node": "25.9.2",
61
+ "@ux-ui/biome-config": "^0.1.0",
62
+ "@ux-ui/tsconfig-base": "^0.1.0",
63
+ "@ux-ui/tsdown-config": "^0.1.0",
64
+ "publint": "^0.3.21",
56
65
  "rimraf": "6.1.3",
57
- "typescript": "6.0.2",
58
- "vite": "8.0.2",
59
- "vite-plugin-dts": "4.5.4"
66
+ "tsdown": "0.22.3",
67
+ "typescript": "6.0.3"
60
68
  },
61
69
  "keywords": [
62
70
  "masonry",
package/dist/index.cjs.js DELETED
@@ -1,3 +0,0 @@
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
@@ -1 +0,0 @@
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.es.js DELETED
@@ -1,135 +0,0 @@
1
- var r = class {
2
- containerOption;
3
- container = null;
4
- gridItems = [];
5
- rowHeight = 1;
6
- rowGap = 0;
7
- resizeScheduled = !1;
8
- rafId = null;
9
- resizeObserver = null;
10
- mutationObserver = null;
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;
23
- }
24
- init() {
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()));
26
- }
27
- refresh() {
28
- !this.isInitialized || this.isDestroyed || !this.container || (this.initializeGridItems(), this.scheduleLayout());
29
- }
30
- destroy() {
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
- });
38
- }
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());
58
- }
59
- resizeAllItems() {
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
- });
69
- }
70
- setupAbortControllers() {
71
- this.observerAbortController = new AbortController(), this.imageAbortController = new AbortController(), this.observerAbortController.signal.addEventListener("abort", () => {
72
- this.resizeObserver?.disconnect(), this.mutationObserver?.disconnect();
73
- });
74
- }
75
- setupResizeObserver() {
76
- !this.container || typeof ResizeObserver > "u" || (this.resizeObserver = new ResizeObserver(() => this.handleResize()), this.resizeObserver.observe(this.container));
77
- }
78
- setupMutationObserver() {
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();
88
- }
89
- initializeContainerStyles() {
90
- this.container && (this.container.style.gridAutoRows = "1px", this.container.style.contain = "layout", this.container.style.alignItems = "start");
91
- }
92
- measureContainerMetrics() {
93
- if (!this.container) return;
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;
98
- }
99
- initializeGridItems() {
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
- });
104
- }));
105
- }
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 });
118
- }
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
- };
131
- export {
132
- r as default
133
- };
134
-
135
- //# sourceMappingURL=index.es.js.map
@@ -1 +0,0 @@
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":"AAIA,IAAqB,IAArB,MAAmC;AAAA,EACjC;AAAA,EACA,YAAwC;AAAA,EACxC,YAAmC,CAAA;AAAA,EACnC,YAAoB;AAAA,EACpB,SAAiB;AAAA,EACjB,kBAA0B;AAAA,EAC1B,QAA+B;AAAA,EAC/B,iBAAgD;AAAA,EAChD,mBAAoD;AAAA,EACpD,0BAA0D;AAAA,EAC1D,uBAAuD;AAAA,EACvD,iBAAyB,oBAAI,QAAA;AAAA,EAC7B,gBAAwB;AAAA,EACxB,cAAsB;AAAA,EACtB,0BAAkC;AAAA,IAChC,cAAc;AAAA,IACd,SAAS;AAAA,IACT,YAAY;AAAA;EAGd,YAAY,IAAgC,CAAA,GAAI;AAC9C,SAAK,kBAAkB,EAAQ;AAAA;EAGjC,OAAoB;AAClB,IAAI,KAAK,kBAET,KAAK,YAAY,KAAK,iBAAA,GAEjB,KAAK,cAEV,KAAK,gBAAgB,IACrB,KAAK,cAAc,IAEnB,KAAK,sBAAA,GACL,KAAK,qBAAA,GACL,KAAK,0BAAA,GACL,KAAK,oBAAA,GACL,KAAK,oBAAA,GACL,KAAK,sBAAA,GACL,KAAK,eAAA;AAAA;EAGP,UAAuB;AACrB,IAAI,CAAC,KAAK,iBAAiB,KAAK,eAAe,CAAC,KAAK,cAErD,KAAK,oBAAA,GACL,KAAK,eAAA;AAAA;EAGP,UAAuB;AACrB,IAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,cAEjC,KAAK,cAAc,IACnB,KAAK,gBAAgB,IACrB,KAAK,sBAAA,GACL,KAAK,yBAAyB,MAAA,GAC9B,KAAK,sBAAsB,MAAA,GAC3B,KAAK,gBAAgB,WAAA,GACrB,KAAK,kBAAkB,WAAA,GACvB,KAAK,UAAU,QAAA,CAAS,MAAS;AAC/B,MAAA,EAAK,MAAM,aAAa;AAAA,QAGtB,KAAK,cACP,KAAK,UAAU,MAAM,eAAe,KAAK,wBAAwB,cACjE,KAAK,UAAU,MAAM,UAAU,KAAK,wBAAwB,SAC5D,KAAK,UAAU,MAAM,aAAa,KAAK,wBAAwB,aAGjE,KAAK,YAAY,CAAA,GACjB,KAAK,YAAY,GACjB,KAAK,SAAS,GACd,KAAK,iBAAiB,MACtB,KAAK,mBAAmB,MACxB,KAAK,0BAA0B,MAC/B,KAAK,uBAAuB,MAC5B,KAAK,iBAAiB,oBAAI,QAAA,GAC1B,KAAK,kBAAkB,IACvB,KAAK,YAAY,MACjB,KAAK,0BAA0B;AAAA,MAC7B,cAAc;AAAA,MACd,SAAS;AAAA,MACT,YAAY;AAAA;;EAIhB,mBAA+C;AAC7C,WAAI,KAAK,2BAA2B,cAC3B,KAAK,kBAGV,OAAO,WAAa,MAAoB,OAExC,OAAO,KAAK,mBAAoB,WAC3B,SAAS,cAA2B,KAAK,eAAA,IAG3C,SAAS,cAA2B,UAAA;AAAA;EAG7C,iBAA+B;AAC7B,QAAI,GAAC,KAAK,iBAAiB,KAAK,eAAe,CAAC,KAAK,aAAa,KAAK,kBAIvE;AAAA,UAFA,KAAK,kBAAkB,IAEnB,OAAO,yBAA0B,YAAY;AAC/C,aAAK,QAAQ,sBAAA,MAA4B;AACvC,eAAK,QAAQ,MACb,KAAK,kBAAkB,IACvB,KAAK,cAAA;AAAA;AAGP;AAAA;AAGF,WAAK,QAAQ,MACb,KAAK,kBAAkB,IACvB,KAAK,cAAA;AAAA;AAAA;EAGP,wBAAsC;AACpC,IAAI,KAAK,UAAU,QAAQ,OAAO,wBAAyB,cACzD,qBAAqB,KAAK,KAAA,GAG5B,KAAK,QAAQ,MACb,KAAK,kBAAkB;AAAA;EAGzB,gBAA8B;AAC5B,IAAI,CAAC,KAAK,iBAAiB,KAAK,eAAe,CAAC,KAAK,cAErD,KAAK,wBAAA,GACL,KAAK,eAAA;AAAA;EAGP,iBAA+B;AAC7B,UAAM,IAAc,KAAK,YAAY,KAAK;AAE1C,SAAK,UAAU,QAAA,CAAS,MAAS;AAC/B,UAAI,KAAe,KAAK,CAAC,OAAO,SAAS,CAAA,GAAc;AACrD,QAAA,EAAK,MAAM,aAAa;AAExB;AAAA;AAGF,YAAM,IAAU,KAAK,IACnB,GACA,KAAK,MAAM,EAAK,sBAAA,EAAwB,SAAS,KAAK,UAAU,CAAA,CAAY;AAE9E,MAAA,EAAK,MAAM,aAAa,QAAQ,CAAA;AAAA;;EAIpC,wBAAsC;AACpC,SAAK,0BAA0B,IAAI,gBAAA,GACnC,KAAK,uBAAuB,IAAI,gBAAA,GAEhC,KAAK,wBAAwB,OAAO,iBAAiB,SAAA,MAAe;AAClE,WAAK,gBAAgB,WAAA,GACrB,KAAK,kBAAkB,WAAA;AAAA;;EAI3B,sBAAoC;AAClC,IAAI,CAAC,KAAK,aAAa,OAAO,iBAAmB,QAEjD,KAAK,iBAAiB,IAAI,eAAA,MAAqB,KAAK,aAAA,CAAc,GAElE,KAAK,eAAe,QAAQ,KAAK,SAAA;AAAA;EAGnC,wBAAsC;AACpC,IAAI,CAAC,KAAK,aAAa,OAAO,mBAAqB,QAEnD,KAAK,mBAAmB,IAAI,iBAAA,MAAuB;AACjD,WAAK,oBAAA,GACL,KAAK,eAAA;AAAA,QAGP,KAAK,iBAAiB,QAAQ,KAAK,WAAW;AAAA,MAC5C,WAAW;AAAA,MACX,SAAS;AAAA,KACV;AAAA;EAGH,eAA6B;AAC3B,SAAK,eAAA;AAAA;EAGP,4BAA0C;AACxC,IAAK,KAAK,cAEV,KAAK,UAAU,MAAM,eAAe,OACpC,KAAK,UAAU,MAAM,UAAU,UAC/B,KAAK,UAAU,MAAM,aAAa;AAAA;EAGpC,0BAAwC;AACtC,QAAI,CAAC,KAAK,UAAW;AAErB,UAAM,IAAK,iBAAiB,KAAK,SAAA;AAEjC,SAAK,SAAS,KAAK,mBAAmB,EAAG,MAAA;AAEzC,UAAM,IAAkB,KAAK,mBAAmB,EAAG,YAAA;AAEnD,SAAK,YAAY,IAAkB,IAAI,IAAkB;AAAA;EAG3D,sBAAoC;AAClC,IAAK,KAAK,cAEV,KAAK,YAAY,MAAM,KAAK,KAAK,UAAU,QAAA,EAAU,OAAA,CAClD,MAA8B,aAAgB,WAAA,GAGjD,KAAK,UAAU,QAAA,CAAS,MAAS;AAChB,MAAA,EAAK,iBAAiB,KAAA,EAE9B,QAAA,CAAS,MAAU;AACxB,aAAK,aAAa,CAAA;AAAA;;;EAKxB,aAAqB,GAA+B;AAClD,QAAI,EAAM,YAAY,KAAK,eAAe,IAAI,CAAA,EAAQ;AAEtD,SAAK,eAAe,IAAI,CAAA;AAExB,UAAM,IAAA,MAAqB,KAAK,eAAA;AAEhC,QAAI,KAAK,sBAAsB;AAC7B,MAAA,EAAM,iBAAiB,QAAQ,GAAQ;AAAA,QACrC,MAAM;AAAA,QACN,QAAQ,KAAK,qBAAqB;AAAA,OACnC;AAED;AAAA;AAGF,IAAA,EAAM,iBAAiB,QAAQ,GAAQ,EAAE,MAAM,GAAA,CAAM;AAAA;EAGvD,mBAA2B,GAAuB;AAChD,UAAM,IAAc,OAAO,WAAW,CAAA;AAEtC,WAAO,OAAO,SAAS,CAAA,IAAe,IAAc;AAAA;EAGtD,uBAAqC;AACnC,IAAK,KAAK,cAEV,KAAK,0BAA0B;AAAA,MAC7B,cAAc,KAAK,UAAU,MAAM,gBAAgB;AAAA,MACnD,SAAS,KAAK,UAAU,MAAM,WAAW;AAAA,MACzC,YAAY,KAAK,UAAU,MAAM,cAAc;AAAA"}
package/dist/index.umd.js DELETED
@@ -1,3 +0,0 @@
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
@@ -1 +0,0 @@
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":"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"}