Skip to content

Commit

Permalink
feat: add singleRowMaxHeight row constraint (fix #121)
Browse files Browse the repository at this point in the history
  • Loading branch information
igordanchenko committed Aug 18, 2023
1 parent c1d384a commit 7d7cc94
Show file tree
Hide file tree
Showing 6 changed files with 499 additions and 18 deletions.
1 change: 1 addition & 0 deletions docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Parameters marked with an asterisk (<span class="required" />) are required.
<ul>
<li>`minPhotos` - minimum number of photos per row</li>
<li>`maxPhotos` - maximum number of photos per row</li>
<li>`singleRowMaxHeight` - maximum row height when there is not enough photos to fill more than one row</li>
</ul>
</td>
</tr>
Expand Down
50 changes: 39 additions & 11 deletions src/PhotoAlbum.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import MasonryLayout from "./components/layouts/MasonryLayout";
import ContainerRenderer from "./components/renderers/ContainerRenderer";
import useArray from "./hooks/useArray";
import useContainerWidth from "./hooks/useContainerWidth";
import { resolveResponsiveParameter, unwrapParameter } from "./utils/responsive";
import { ComponentsProps, ComponentsPropsParameter, Photo, PhotoAlbumProps } from "./types";
import { resolveResponsiveParameter, unwrap, unwrapParameter } from "./utils/responsive";
import { ComponentsProps, Photo, PhotoAlbumProps } from "./types";

function resolveLayoutOptions<T extends Photo>({
layout,
Expand Down Expand Up @@ -40,19 +40,46 @@ function resolveLayoutOptions<T extends Photo>({
};
}

function resolveComponentsProps(componentsProps?: ComponentsPropsParameter, containerWidth?: number) {
return typeof componentsProps === "function" ? componentsProps(containerWidth) : componentsProps || {};
function resolveComponentsProps<T extends Photo>(
props: PhotoAlbumProps<T>,
containerWidth?: number,
layoutOptions?: ReturnType<typeof resolveLayoutOptions<T>>
) {
const { photos, componentsProps: componentsPropsProp } = props;

const componentsProps = unwrap(componentsPropsProp, containerWidth) || {};

if (layoutOptions) {
const { layout, spacing, padding, rowConstraints } = layoutOptions;

if (layout === "rows") {
const { singleRowMaxHeight } = rowConstraints || {};
if (singleRowMaxHeight) {
const maxWidth = Math.floor(
photos.reduce(
(acc, { width, height }) => acc + (width / height) * singleRowMaxHeight - 2 * padding,
padding * photos.length * 2 + spacing * (photos.length - 1)
)
);

if (maxWidth > 0) {
componentsProps.containerProps = componentsProps.containerProps || {};
componentsProps.containerProps.style = { maxWidth, ...componentsProps.containerProps.style };
}
}
}
}

return componentsProps;
}

function renderLayout<T extends Photo>(
props: PhotoAlbumProps<T>,
containerWidth: number,
componentsProps: ComponentsProps
componentsProps: ComponentsProps,
layoutOptions: ReturnType<typeof resolveLayoutOptions<T>>
) {
const { photos, layout, renderPhoto, renderRowContainer, renderColumnContainer } = props;

const layoutOptions = resolveLayoutOptions({ containerWidth, ...props });

const commonLayoutProps = { photos, renderPhoto, componentsProps };

if (layout === "rows") {
Expand Down Expand Up @@ -92,8 +119,9 @@ export default function PhotoAlbum<T extends Photo>(props: PhotoAlbumProps<T>) {
// safeguard against incorrect usage
if (!layout || !["rows", "columns", "masonry"].includes(layout) || !Array.isArray(photos)) return null;

// eslint-disable-next-line react/destructuring-assignment
const componentsProps = resolveComponentsProps(props.componentsProps, containerWidth);
const layoutOptions = containerWidth ? resolveLayoutOptions({ containerWidth, ...props }) : undefined;

const componentsProps = resolveComponentsProps(props, containerWidth, layoutOptions);

return (
<ContainerRenderer
Expand All @@ -102,7 +130,7 @@ export default function PhotoAlbum<T extends Photo>(props: PhotoAlbumProps<T>) {
renderContainer={renderContainer}
containerProps={componentsProps.containerProps}
>
{containerWidth && renderLayout(props, containerWidth, componentsProps)}
{layoutOptions && renderLayout(props, componentsProps, layoutOptions)}
</ContainerRenderer>
);
}
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ export type RowConstraints = {
minPhotos?: number;
/** maximum number of photos per row in 'rows' layout */
maxPhotos?: number;
/** maximum row height when there is not enough photos to fill more than one row */
singleRowMaxHeight?: number;
};

export type ComponentsProps = {
Expand Down
6 changes: 3 additions & 3 deletions src/utils/responsive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { ResponsiveParameter } from "../types";

const breakpoints = Object.freeze([1200, 600, 300, 0]);

type AnyFunction = (...args: unknown[]) => unknown;
type AnyFunction = (args: any) => unknown;

function unwrap<T, P = T extends AnyFunction ? ReturnType<T> : T>(value: T, containerWidth: number): P {
return typeof value === "function" ? value(containerWidth) : value;
export function unwrap<V, A, R = V extends AnyFunction ? ReturnType<V> : V>(value: V, arg: A): R {
return typeof value === "function" ? value(arg) : value;
}

export function unwrapParameter<T>(value: ResponsiveParameter<T> | undefined, containerWidth: number): T | undefined {
Expand Down
9 changes: 5 additions & 4 deletions test/PhotoAlbum.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ describe("PhotoAlbum", () => {
whenAskedToRender(<PhotoAlbum layout="rows" photos={photos} rowConstraints={{ maxPhotos: 4 }} />);
});

it("supports single row maximum height parameter", () => {
whenAskedToRender(<PhotoAlbum layout="rows" photos={photos} rowConstraints={{ singleRowMaxHeight: 300 }} />);
});

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

Expand Down Expand Up @@ -288,10 +292,7 @@ describe("PhotoAlbum", () => {
spacing={() => 10}
padding={() => 5}
targetRowHeight={() => 100}
rowConstraints={() => ({
minPhotos: 1,
maxPhotos: 2,
})}
rowConstraints={() => ({ minPhotos: 1, maxPhotos: 2 })}
/>
);

Expand Down
Loading

0 comments on commit 7d7cc94

Please sign in to comment.