Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(HorizontalMosaic, VerticalMosaic): allow passing gridMode information to each item #1289

Merged
merged 1 commit into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions src/__tests__/mosaic-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import * as React from 'react';
import {render, screen} from '@testing-library/react';
import ThemeContextProvider from '../theme-context-provider';
import {makeTheme} from './test-utils';
import {HorizontalMosaic, VerticalMosaic} from '../mosaic';
import {Text2} from '../text';

const ITEMS_COUNT = [1, 2, 3, 4, 5, 6];

const verticalMosaicItemsGridMode = [
// 1 item
['horizontal'],

// 2 items
['square', 'square'],

// 3 items
['vertical', 'square', 'square'],

// 4 items
['vertical', 'square', 'square', 'vertical'],

// 5 items
['vertical', 'square', 'square', 'vertical', 'horizontal'],

// 6 items
['vertical', 'square', 'square', 'vertical', 'square', 'square'],
];

const horizontalMosaicItemsGridMode = [
// 1 item
['horizontal'],

// 2 items
['horizontal', 'horizontal'],

// 3 items
['horizontal', 'square', 'square'],

// 4 items
['square', 'square', 'square', 'square'],

// 5 items
['horizontal', 'square', 'square', 'horizontal', 'horizontal'],

// 6 items
['horizontal', 'square', 'square', 'square', 'square', 'horizontal'],
];

test.each(ITEMS_COUNT)(
'VerticalMosaic - gridMode passed as a function is correct with %s items',
(itemsCount) => {
render(
<ThemeContextProvider theme={makeTheme()}>
<VerticalMosaic
items={Array.from({length: itemsCount}, (_, index) => ({gridMode}) => (
<Text2 regular>{`${index + 1}-${gridMode}`}</Text2>
))}
/>
</ThemeContextProvider>
);

const expectedGridModes = verticalMosaicItemsGridMode[itemsCount - 1];

expectedGridModes.forEach((gridMode, index) => {
expect(screen.getByText(`${index + 1}-${gridMode}`)).toBeInTheDocument();
});
}
);

test.each(ITEMS_COUNT)(
'HorizontalMosaic - gridMode passed as a function is correct with %s items',
(itemsCount) => {
render(
<ThemeContextProvider theme={makeTheme()}>
<HorizontalMosaic
items={Array.from({length: itemsCount}, (_, index) => ({gridMode}) => (
<Text2 regular>{`${index + 1}-${gridMode}`}</Text2>
))}
/>
</ThemeContextProvider>
);

const expectedGridModes = horizontalMosaicItemsGridMode[itemsCount - 1];

expectedGridModes.forEach((gridMode, index) => {
expect(screen.getByText(`${index + 1}-${gridMode}`)).toBeInTheDocument();
});
}
);
44 changes: 28 additions & 16 deletions src/mosaic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,32 @@ import type {DataAttributes} from './utils/types';

const GRID_GAP = {mobile: 8, desktop: 16} as const;

type MosaicItemGridMode = 'horizontal' | 'square' | 'vertical';

type MosaicItem = React.ReactElement | ((config: {gridMode: MosaicItemGridMode}) => React.ReactElement);

type HorizontalMosaicPageProps = {
items: ReadonlyArray<React.ReactElement>;
items: ReadonlyArray<MosaicItem>;
isEven: boolean;
};

const renderItem = (item: MosaicItem, gridMode: MosaicItemGridMode) => {
return typeof item === 'function' ? item({gridMode}) : item;
};

const HorizontalMosaicPage = ({items, isEven}: HorizontalMosaicPageProps) => {
return (
<div className={items.length === 1 ? styles.singleItemRowContainer : styles.squareContainer}>
<Grid gap={GRID_GAP} rows={2} columns={2} height="100%">
{items.length === 3 ? (
<>
<GridItem columnSpan={isEven ? 2 : undefined}>{items[0]}</GridItem>
<GridItem>{items[1]}</GridItem>
<GridItem columnSpan={isEven ? undefined : 2}>{items[2]}</GridItem>
<GridItem columnSpan={isEven ? 2 : undefined}>
{renderItem(items[0], isEven ? 'horizontal' : 'square')}
</GridItem>
<GridItem>{renderItem(items[1], 'square')}</GridItem>
<GridItem columnSpan={isEven ? undefined : 2}>
{renderItem(items[2], isEven ? 'square' : 'horizontal')}
</GridItem>
</>
) : (
items.map((item, itemIndex) => (
Expand All @@ -29,7 +41,7 @@ const HorizontalMosaicPage = ({items, isEven}: HorizontalMosaicPageProps) => {
rowSpan={items.length === 1 ? 2 : undefined}
key={itemIndex}
>
{item}
{renderItem(item, items.length === 4 ? 'square' : 'horizontal')}
</GridItem>
))
)}
Expand All @@ -39,7 +51,7 @@ const HorizontalMosaicPage = ({items, isEven}: HorizontalMosaicPageProps) => {
};

type HorizontalMosaicProps = {
items: ReadonlyArray<React.ReactElement>;
items: ReadonlyArray<MosaicItem>;
withBullets?: boolean;
free?: boolean;
dataAttributes?: DataAttributes;
Expand All @@ -54,7 +66,7 @@ export const HorizontalMosaic = ({
const itemsCount = items.length;

const pagesCount = itemsCount < 5 ? Math.min(itemsCount, 1) : Math.floor((itemsCount + 1) / 3);
const pages = Array.from({length: pagesCount}, () => [] as Array<React.ReactElement>);
const pages = Array.from({length: pagesCount}, () => [] as Array<MosaicItem>);

items.forEach((item, index) => {
const itemPageIndex = Math.min(pagesCount - 1, Math.floor(index / 3));
Expand All @@ -76,7 +88,7 @@ export const HorizontalMosaic = ({
};

type VerticalMosaicPageProps = {
items: ReadonlyArray<React.ReactElement>;
items: ReadonlyArray<MosaicItem>;
};

const VerticalMosaicPage = ({items}: VerticalMosaicPageProps) => {
Expand All @@ -88,7 +100,7 @@ const VerticalMosaicPage = ({items}: VerticalMosaicPageProps) => {
<Grid gap={GRID_GAP} columns={2} height="100%">
{items.map((item, itemIndex) => (
<GridItem columnSpan={items.length === 2 ? undefined : 2} key={itemIndex}>
{item}
{renderItem(item, items.length === 2 ? 'square' : 'horizontal')}
</GridItem>
))}
</Grid>
Expand All @@ -101,7 +113,7 @@ const VerticalMosaicPage = ({items}: VerticalMosaicPageProps) => {
<Grid gap={GRID_GAP} columns={2} flow="column" height="100%">
{items.map((item, itemIndex) => (
<GridItem rowSpan={itemIndex === 0 ? 2 : undefined} key={itemIndex}>
{item}
{renderItem(item, itemIndex === 0 ? 'vertical' : 'square')}
</GridItem>
))}
</Grid>
Expand All @@ -113,26 +125,26 @@ const VerticalMosaicPage = ({items}: VerticalMosaicPageProps) => {
return (
<div className={styles.fourItemsContainer}>
<Grid gap={GRID_GAP} rows={3} columns={2} height="100%">
<GridItem rowSpan={2}>{items[0]}</GridItem>
<GridItem>{items[1]}</GridItem>
<GridItem rowSpan={2}>{items[3]}</GridItem>
<GridItem>{items[2]}</GridItem>
<GridItem rowSpan={2}>{renderItem(items[0], 'vertical')}</GridItem>
<GridItem>{renderItem(items[1], 'square')}</GridItem>
<GridItem rowSpan={2}>{renderItem(items[3], 'vertical')}</GridItem>
<GridItem>{renderItem(items[2], 'square')}</GridItem>
</Grid>
</div>
);
}
};

type VerticalMosaicProps = {
items: ReadonlyArray<React.ReactElement>;
items: ReadonlyArray<MosaicItem>;
dataAttributes?: DataAttributes;
};

export const VerticalMosaic = ({items, dataAttributes}: VerticalMosaicProps): JSX.Element => {
const itemsCount = items.length;

const pagesCount = Math.ceil(itemsCount / 4);
const pages = Array.from({length: pagesCount}, () => [] as Array<React.ReactElement<any>>);
const pages = Array.from({length: pagesCount}, () => [] as Array<MosaicItem>);

items.forEach((item, index) => {
const itemPageIndex = Math.floor(index / 4);
Expand Down
Loading