Skip to content

Commit e3620b7

Browse files
committed
fixup! feat(masonry-layout): add new component
1 parent 4bfb353 commit e3620b7

1 file changed

Lines changed: 54 additions & 24 deletions

File tree

src/components/masonry-layout/masonry-layout.tsx

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Component, Element, h, Host, Prop, State } from '@stencil/core';
1313
* browser support or produce poor results.
1414
*
1515
* The number of columns is determined automatically based on the
16-
* available width and the preferred column width.
16+
* available width and the minimum column width.
1717
*
1818
* :::note
1919
* This component has `shadow: false`, so consumers can treat it as
@@ -106,11 +106,13 @@ export class MasonryLayout {
106106
);
107107
}
108108

109-
private pxToRem(px: number): number {
110-
const rootFontSize = Number.parseFloat(
109+
private getRootFontSize(): number {
110+
return Number.parseFloat(
111111
getComputedStyle(document.documentElement).fontSize
112112
);
113+
}
113114

115+
private pxToRem(px: number, rootFontSize: number): number {
114116
return px / rootFontSize;
115117
}
116118

@@ -121,8 +123,13 @@ export class MasonryLayout {
121123
*
122124
* @param property - The CSS custom property name to read.
123125
* @param fallback - The fallback CSS value if the property is not set.
126+
* @param rootFontSize - The root font size in pixels for rem conversion.
124127
*/
125-
private getCssPropertyInPx(property: string, fallback: string): number {
128+
private getCssPropertyInPx(
129+
property: string,
130+
fallback: string,
131+
rootFontSize: number,
132+
): number {
126133
const value =
127134
getComputedStyle(this.host).getPropertyValue(property).trim() ||
128135
fallback;
@@ -132,10 +139,6 @@ export class MasonryLayout {
132139
return number;
133140
}
134141

135-
const rootFontSize = Number.parseFloat(
136-
getComputedStyle(document.documentElement).fontSize
137-
);
138-
139142
// Assume rem for any other unit (rem is the project standard)
140143
return number * rootFontSize;
141144
}
@@ -169,28 +172,53 @@ export class MasonryLayout {
169172
return;
170173
}
171174

172-
const gapPx = this.getCssPropertyInPx('--masonry-layout-gap', '1rem');
173-
const columnWidthPx = this.calculateColumnWidth(hostWidth, gapPx);
174-
const columnHeights = this.positionItems(items, columnWidthPx, gapPx);
175+
const rootFontSize = this.getRootFontSize();
176+
const gapPx = this.getCssPropertyInPx(
177+
'--masonry-layout-gap',
178+
'1rem',
179+
rootFontSize,
180+
);
181+
const { columnCount, columnWidth } = this.calculateColumns(
182+
hostWidth,
183+
gapPx,
184+
rootFontSize,
185+
);
186+
const columnHeights = this.positionItems(
187+
items,
188+
columnCount,
189+
columnWidth,
190+
gapPx,
191+
rootFontSize,
192+
);
175193

176-
const newHeight = this.pxToRem(Math.max(...columnHeights) - gapPx);
194+
const newHeight = this.pxToRem(
195+
Math.max(...columnHeights) - gapPx,
196+
rootFontSize,
197+
);
177198
if (Math.abs(newHeight - this.containerHeight) > 0.1) {
178199
this.containerHeight = newHeight;
179200
}
180201
}
181202

182-
private calculateColumnWidth(hostWidth: number, gapPx: number): number {
203+
private calculateColumns(
204+
hostWidth: number,
205+
gapPx: number,
206+
rootFontSize: number,
207+
): { columnCount: number; columnWidth: number } {
183208
const minColumnWidthPx = this.getCssPropertyInPx(
184209
'--masonry-layout-min-column-width',
185-
'12rem'
210+
'12rem',
211+
rootFontSize,
186212
);
187213

188214
const columnCount = Math.max(
189215
1,
190-
Math.floor((hostWidth + gapPx) / (minColumnWidthPx + gapPx))
216+
Math.floor((hostWidth + gapPx) / (minColumnWidthPx + gapPx)),
191217
);
218+
const columnWidth =
219+
(hostWidth - (columnCount - 1) * gapPx) / columnCount;
192220

193-
return (hostWidth - (columnCount - 1) * gapPx) / columnCount;
221+
return { columnCount, columnWidth };
194222
}
195223

196224
/**
@@ -202,12 +230,11 @@ export class MasonryLayout {
202230
*/
203231
private positionItems(
204232
items: HTMLElement[],
233+
columnCount: number,
205234
columnWidth: number,
206-
gapPx: number
235+
gapPx: number,
236+
rootFontSize: number,
207237
): number[] {
208-
const columnCount = Math.round(
209-
(this.host.offsetWidth + gapPx) / (columnWidth + gapPx)
210-
);
211238
const columnHeights = Array.from({ length: columnCount }, () => 0);
212239

213240
let index = 0;
@@ -220,10 +247,13 @@ export class MasonryLayout {
220247
const y = columnHeights[column];
221248

222249
item.style.position = 'absolute';
223-
item.style.left = `${this.pxToRem(x)}rem`;
224-
item.style.top = `${this.pxToRem(y)}rem`;
225-
item.style.width = `${this.pxToRem(columnWidth)}rem`;
226-
item.style.animationDelay = `${index * 15}ms`;
250+
item.style.left = `${this.pxToRem(x, rootFontSize)}rem`;
251+
item.style.top = `${this.pxToRem(y, rootFontSize)}rem`;
252+
item.style.width = `${this.pxToRem(columnWidth, rootFontSize)}rem`;
253+
254+
if (!this.hasRendered) {
255+
item.style.animationDelay = `${index * 15}ms`;
256+
}
227257

228258
columnHeights[column] += item.offsetHeight + gapPx;
229259
index++;

0 commit comments

Comments
 (0)