Skip to content

Commit

Permalink
feat: render empty columns when there aren't enough photos
Browse files Browse the repository at this point in the history
BREAKING CHANGE: columnConstraints prop is no longer supported
  • Loading branch information
igordanchenko committed Dec 9, 2022
1 parent 7d11200 commit 237d481
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 456 deletions.
2 changes: 0 additions & 2 deletions src/PhotoAlbum.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const resolveLayoutOptions = <T extends Photo>({
containerWidth,
targetRowHeight,
rowConstraints,
columnConstraints,
columns,
spacing,
padding,
Expand All @@ -39,7 +38,6 @@ const resolveLayoutOptions = <T extends Photo>({
(w) => w / 2,
]),
rowConstraints: unwrapParameter(rowConstraints, containerWidth),
columnConstraints: unwrapParameter(columnConstraints, containerWidth),
sizes,
});

Expand Down
34 changes: 10 additions & 24 deletions src/layouts/columns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,16 @@ const computeColumnsModel = <T extends Photo = Photo>({

// fill first available columns if there are not enough photos
if (photos.length <= columns) {
for (let index = 0; index < photos.length; index += 1) {
columnsGaps[index] = 2 * padding;
columnsRatios[index] = ratio(photos[index]);
const averageRatio =
photos.length > 0 ? photos.reduce((acc, photo) => acc + ratio(photo), 0) / photos.length : 1;

for (let i = 0; i < columns; i += 1) {
columnsGaps[i] = 2 * padding;
columnsRatios[i] = i < photos.length ? ratio(photos[i]) : averageRatio;
}

const columnsModel = buildColumnsModel({
path: Array.from({ length: photos.length + 1 }).map((_, index) => index),
path: Array.from({ length: columns + 1 }).map((_, index) => Math.min(index, photos.length)),
photos,
columnsRatios,
columnsGaps,
Expand All @@ -117,13 +120,6 @@ const computeColumnsModel = <T extends Photo = Photo>({
padding,
});

for (let i = photos.length; i < (layoutOptions.columnConstraints?.minColumns || 0); i += 1) {
columnsGaps[i] = 0;
columnsRatios[i] =
photos.length > 0 ? photos.reduce((acc, photo) => acc + ratio(photo), 0) / photos.length : 1;
columnsModel[i] = [];
}

return { columnsGaps, columnsRatios, columnsModel };
}

Expand Down Expand Up @@ -223,21 +219,11 @@ const computeColumnsLayout = <T extends Photo = Photo>({
}: ComputeColumnsLayoutProps<T>): ColumnsLayoutModel<T> => {
instrumentation?.onStartLayout?.();

const result = computeLayout({
photos,
layoutOptions: {
...layoutOptions,
columns: Math.min(
layoutOptions.columns,
Math.max(photos.length, layoutOptions.columnConstraints?.minColumns || 0)
),
},
instrumentation,
});
const layout = computeLayout({ photos, layoutOptions, instrumentation });

instrumentation?.onFinishLayout?.(result);
instrumentation?.onFinishLayout?.(layout);

return result;
return layout;
};

export default computeColumnsLayout;
13 changes: 4 additions & 9 deletions src/layouts/masonry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,7 @@ type MasonryColumnsModel<T extends Photo = Photo> = { photo: T; layout: PhotoLay

const computeMasonryLayout = <T extends Photo = Photo>(props: ComputeMasonryLayoutProps<T>): MasonryColumnsModel<T> => {
const { photos, layoutOptions, instrumentation } = props;
const { spacing, padding, containerWidth } = layoutOptions;

const columns = Math.min(
layoutOptions.columns,
Math.max(photos.length, layoutOptions.columnConstraints?.minColumns || 0)
);
const { columns, spacing, padding, containerWidth } = layoutOptions;

instrumentation?.onStartLayout?.();

Expand Down Expand Up @@ -66,7 +61,7 @@ const computeMasonryLayout = <T extends Photo = Photo>(props: ComputeMasonryLayo
);

// map through each column and photo and add layout properties
const result = columnsModel.map((column) =>
const layout = columnsModel.map((column) =>
column.map(({ photo, index }, photoIndex) => ({
photo,
layout: {
Expand All @@ -79,9 +74,9 @@ const computeMasonryLayout = <T extends Photo = Photo>(props: ComputeMasonryLayo
}))
);

instrumentation?.onFinishLayout?.(result);
instrumentation?.onFinishLayout?.(layout);

return result;
return layout;
};

export default computeMasonryLayout;
8 changes: 4 additions & 4 deletions src/layouts/rows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const computeRowsLayout = <T extends Photo = Photo>({
// impossible layout
if (path === undefined) return undefined;

const result = [];
const layout = [];

for (let i = 1; i < path.length; i += 1) {
const row = photos.map((photo, index) => ({ photo, index })).slice(+path[i - 1], +path[i]);
Expand All @@ -118,7 +118,7 @@ const computeRowsLayout = <T extends Photo = Photo>({
spacing,
padding
);
result.push(
layout.push(
row.map(({ photo, index }, photoIndex) => ({
photo,
layout: {
Expand All @@ -132,9 +132,9 @@ const computeRowsLayout = <T extends Photo = Photo>({
);
}

instrumentation?.onFinishLayout?.(result);
instrumentation?.onFinishLayout?.(layout);

return result;
return layout;
};

export default computeRowsLayout;
9 changes: 0 additions & 9 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ export type PhotoAlbumProps<T extends Photo = Photo> = {
targetRowHeight?: ResponsiveParameter;
/** Additional row constraints */
rowConstraints?: ResponsiveParameter<RowConstraints>;
/** Additional columnn constraints */
columnConstraints?: ResponsiveParameter<ColumnConstraints>;
/** Photo album width at various viewport sizes. */
sizes?: ResponsiveSizes;
/** Photo click callback function. */
Expand Down Expand Up @@ -149,8 +147,6 @@ export type ColumnsLayoutOptions<T extends Photo = Photo> = GenericLayoutOptions
layout: Extract<LayoutType, "columns" | "masonry">;
/** number of columns in 'columns' or 'masonry' layout */
columns: number;
/** Additional column constraints */
columnConstraints?: ColumnConstraints;
};

export type LayoutOptions<T extends Photo = Photo> = ColumnsLayoutOptions<T> | RowsLayoutOptions<T>;
Expand Down Expand Up @@ -221,11 +217,6 @@ export type RowConstraints = {
maxPhotos?: number;
};

export type ColumnConstraints = {
/** minimum number of columns in 'masonry' or 'columns' layout when there isn't enough photos to fill all the columns */
minColumns?: number;
};

/** internal instrumentation for research and performance testing purposes, subject to change without notice */
export type Instrumentation = {
fullGraphSearch?: boolean;
Expand Down
32 changes: 6 additions & 26 deletions test/PhotoAlbum.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,35 +72,15 @@ describe("PhotoAlbum", () => {
});

it("renders columns layout correctly when there isn't enough photos", () => {
whenAskedToRender(<PhotoAlbum layout={"columns"} photos={photos.slice(0, 3)} columns={5} />);
});
whenAskedToRender(<PhotoAlbum layout={"columns"} photos={photos.slice(0, 2)} columns={4} />);

it("supports minimum number of columns parameter", () => {
whenAskedToRender(
<PhotoAlbum
layout={"masonry"}
photos={photos.slice(0, 2)}
columns={4}
columnConstraints={{ minColumns: 4 }}
/>
);

whenAskedToRender(
<PhotoAlbum
layout={"columns"}
photos={photos.slice(0, 2)}
columns={4}
columnConstraints={{ minColumns: 4 }}
/>
);
whenAskedToRender(<PhotoAlbum layout={"columns"} photos={[]} columns={4} />);
});

whenAskedToRender(
<PhotoAlbum layout={"masonry"} photos={[]} columns={4} columnConstraints={{ minColumns: 4 }} />
);
it("renders masonry layout correctly when there isn't enough photos", () => {
whenAskedToRender(<PhotoAlbum layout={"masonry"} photos={photos.slice(0, 2)} columns={4} />);

whenAskedToRender(
<PhotoAlbum layout={"columns"} photos={[]} columns={4} columnConstraints={{ minColumns: 4 }} />
);
whenAskedToRender(<PhotoAlbum layout={"masonry"} photos={[]} columns={4} />);
});

it("renders correctly with invalid defaultContainerWidth", () => {
Expand Down
Loading

0 comments on commit 237d481

Please sign in to comment.