Skip to content

Commit

Permalink
[@mantine/carousel] Fix wrong carousel size calculation (#2572)
Browse files Browse the repository at this point in the history
  • Loading branch information
7iomka committed Sep 29, 2022
1 parent 901b0df commit 9a4be06
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 46 deletions.
68 changes: 61 additions & 7 deletions src/mantine-carousel/src/Carousel.styles.ts
@@ -1,29 +1,83 @@
import { createStyles, MantineNumberSize } from '@mantine/core';
import { createStyles, getSortedBreakpoints, MantineNumberSize } from '@mantine/core';
import { CarouselBreakpoint } from './types';

export interface CarouselStylesParams {
controlSize: number;
controlsOffset: MantineNumberSize;
orientation: 'vertical' | 'horizontal';
height: React.CSSProperties['height'];
includeGapInSize: boolean;
breakpoints: CarouselBreakpoint[];
slideGap: MantineNumberSize;
}

export default createStyles(
(theme, { controlSize, controlsOffset, orientation, height }: CarouselStylesParams) => {
(
theme,
{
controlSize,
controlsOffset,
orientation,
height,
includeGapInSize,
breakpoints = [],
slideGap,
}: CarouselStylesParams
) => {
const horizontal = orientation === 'horizontal';

// Container styles by slideGap (for includeGapInSize case)
const getContainerStyles = (gap: MantineNumberSize) => {
if (!includeGapInSize) return {};

const slideGapValue = theme.fn.size({
size: gap,
sizes: theme.spacing,
});

return {
[orientation === 'horizontal' ? 'marginRight' : 'marginBottom']: slideGapValue * -1,
};
};

const hasDiff = breakpoints.some(
(v) => typeof v.slideGap !== 'undefined' || typeof v.slideSize !== 'undefined'
);

// Apply styles for breakpoints only if has different gap or size
const containerBreakpoints = !hasDiff
? null
: getSortedBreakpoints(theme, breakpoints).reduce((acc, breakpoint) => {
const property = 'maxWidth' in breakpoint ? 'max-width' : 'min-width';
const breakpointSize = theme.fn.size({
size: (property === 'max-width' ? breakpoint.maxWidth : breakpoint.minWidth)!,
sizes: theme.breakpoints,
});

const breakpointSlideGap =
(typeof breakpoint.slideGap === 'undefined' ? slideGap : breakpoint.slideGap) ?? 0;

acc[`@media (${property}: ${breakpointSize - (property === 'max-width' ? 1 : 0)}px)`] =
getContainerStyles(breakpointSlideGap);

return acc;
}, {} as any);

return {
root: {
overflow: 'hidden',
position: 'relative',
},
viewport: {
height,
overflow: 'hidden',
},

container: {
display: 'flex',
flexDirection: horizontal ? 'row' : 'column',
height,
},

viewport: {
height,
...getContainerStyles(slideGap),
...containerBreakpoints,
},

controls: {
Expand Down
2 changes: 1 addition & 1 deletion src/mantine-carousel/src/Carousel.tsx
Expand Up @@ -172,7 +172,7 @@ export const _Carousel = forwardRef<HTMLDivElement, CarouselProps>((props, ref)
} = useComponentDefaultProps('Carousel', defaultProps, props);

const { classes, cx, theme } = useStyles(
{ controlSize, controlsOffset, orientation, height },
{ controlSize, controlsOffset, orientation, height, includeGapInSize, breakpoints, slideGap },
{ name: 'Carousel', classNames, styles, unstyled }
);

Expand Down
78 changes: 40 additions & 38 deletions src/mantine-carousel/src/CarouselSlide/CarouselSlide.styles.ts
Expand Up @@ -14,54 +14,56 @@ export default createStyles(
theme,
{ size, gap, orientation, includeGapInSize, breakpoints = [] }: CarouselSlideStylesParams
) => {
const slideBreakpoints = getSortedBreakpoints(theme, breakpoints).reduce((acc, breakpoint) => {
const property = 'maxWidth' in breakpoint ? 'max-width' : 'min-width';
const breakpointSize = theme.fn.size({
size: property === 'max-width' ? breakpoint.maxWidth : breakpoint.minWidth,
sizes: theme.breakpoints,
// Slide styles by slideGap and slideSize
const getSlideStyles = (slideGap: MantineNumberSize, slideSize: string | number) => {
const slideGapValue = theme.fn.size({
size: slideGap,
sizes: theme.spacing,
});

const breakpointGap = typeof breakpoint.slideGap === 'undefined' ? gap : breakpoint.slideGap;
const flexBasisValue = typeof slideSize === 'number' ? `${slideSize}px` : slideSize;

acc[`@media (${property}: ${breakpointSize + (property === 'max-width' ? 0 : 1)}px)`] = {
flex: `0 0 calc(${
typeof breakpoint.slideSize === 'number'
? `${breakpoint.slideSize}px`
: breakpoint.slideSize
} - ${
includeGapInSize
? theme.fn.size({
size: breakpointGap,
sizes: theme.spacing,
}) / 2
: 0
}px)`,
const marginStyles = includeGapInSize
? {
[orientation === 'horizontal' ? 'paddingRight' : 'paddinBottom']: slideGapValue,
}
: {
[orientation === 'horizontal' ? 'marginRight' : 'marginBottom']: slideGapValue,
};

[orientation === 'horizontal' ? 'marginRight' : 'marginBottom']: theme.fn.size({
size: breakpointGap,
sizes: theme.spacing,
}),
return {
flex: `0 0 ${flexBasisValue}`,
...marginStyles,
};
};

const hasDiff = breakpoints.some(
(v) => typeof v.slideGap !== 'undefined' || typeof v.slideSize !== 'undefined'
);

// Apply styles for breakpoints only if has different gap or size
const slideBreakpoints = !hasDiff
? null
: getSortedBreakpoints(theme, breakpoints).reduce((acc, breakpoint) => {
const property = 'maxWidth' in breakpoint ? 'max-width' : 'min-width';
const breakpointSize = theme.fn.size({
size: property === 'max-width' ? breakpoint.maxWidth : breakpoint.minWidth,
sizes: theme.breakpoints,
});

return acc;
}, {});
const breakpointGap =
typeof breakpoint.slideGap === 'undefined' ? gap : breakpoint.slideGap;

acc[`@media (${property}: ${breakpointSize - (property === 'max-width' ? 1 : 0)}px)`] =
getSlideStyles(breakpointGap, breakpoint.slideSize);

return acc;
}, {});

return {
slide: {
position: 'relative',
flex: `0 0 calc(${typeof size === 'number' ? `${size}px` : size} - ${
includeGapInSize
? theme.fn.size({
size: gap,
sizes: theme.spacing,
}) / 2
: 0
}px)`,
[orientation === 'horizontal' ? 'marginRight' : 'marginBottom']: theme.fn.size({
size: gap,
sizes: theme.spacing,
}),

...getSlideStyles(gap, size),
...slideBreakpoints,
},
};
Expand Down

0 comments on commit 9a4be06

Please sign in to comment.