Skip to content

Instantly share code, notes, and snippets.

@7iomka
Created September 7, 2023 11:27
Show Gist options
  • Save 7iomka/cfa476e6e164df31fcc56d8caf42f5a7 to your computer and use it in GitHub Desktop.
Save 7iomka/cfa476e6e164df31fcc56d8caf42f5a7 to your computer and use it in GitHub Desktop.
effector-view-example-usage
import type { CarouselStylesNames, Embla } from '@mantine/carousel';
import { Carousel } from '@mantine/carousel';
import { useMantineTheme } from '@mantine/core';
import { useCallback, useEffect, useRef, useState } from 'react';
import AutoHeight from 'embla-carousel-auto-height';
import type { CategoryEntity } from '@/shared/api';
import { createView } from '@/shared/lib/view';
import { ImageCard } from '@/shared/ui';
import type { CustomCarouselStylesParams } from '@/shared/lib/mantine';
import { useCarouselStyles } from '@/shared/lib/mantine';
import styles from './category-cards-carousel.module.scss';
interface CategoryCardsCarouselProps {
className?: string;
items: CategoryEntity[];
}
const CategoryCardsCarousel = createView<CategoryCardsCarouselProps>()
.displayName('CategoryCardsCarousel')
.map(() => {
const autoHeightPluginRef = useRef(AutoHeight());
const [embla, setEmbla] = useState<Embla | null>(null);
const carouselConfig: CustomCarouselStylesParams = {
containScroll: 'trimSnaps',
slidesToScroll: 'auto',
includeGapInSize: true,
slideGap: 16,
loop: true,
slideSize: '50%',
align: 'start',
breakpoints: [{ minWidth: 'lg', slideSize: '25%', slideGap: 30 }],
plugins: [autoHeightPluginRef.current],
};
const { classes, cx } = useCarouselStyles(carouselConfig);
const toggleActiveWhenScrollable = useCallback(() => {
if (!embla) return;
const isScrollable = embla.internalEngine().slideLooper.canLoop();
embla.reInit({ active: isScrollable });
}, [embla]);
const { breakpoints } = useMantineTheme();
const { controls: controlsStyles, ...restClasses } = classes;
const carouselClasses: Partial<Record<CarouselStylesNames, string>> = {
controls: cx(controlsStyles, styles.controls),
...restClasses,
};
return {
embla,
setEmbla,
toggleActiveWhenScrollable,
carouselConfig,
carouselClasses,
breakpoints,
cx,
autoHeightPluginRef,
};
})
.effect(({ embla, toggleActiveWhenScrollable }) => {
useEffect(() => {
if (!embla) return;
toggleActiveWhenScrollable();
embla.on('resize', toggleActiveWhenScrollable);
}, [embla, toggleActiveWhenScrollable]);
})
.memo()
.view(
({
className,
items,
setEmbla,
carouselConfig,
carouselClasses,
cx,
breakpoints,
autoHeightPluginRef,
}) => (
<Carousel
getEmblaApi={setEmbla}
{...carouselConfig}
classNames={carouselClasses}
className={className}
styles={{
container: {
alignItems: 'flex-start',
transition: 'height 0.2s',
},
}}
plugins={[autoHeightPluginRef.current]}
>
{items.map(({ id, name, url, ...rest }, index) => (
<Carousel.Slide key={index}>
<ImageCard
title={name}
href={url}
{...rest}
sizes={`(min-width: ${breakpoints.lg}) 25vw, 50vw`}
/>
</Carousel.Slide>
))}
</Carousel>
),
).Memo;
export type { CategoryCardsCarouselProps };
export { CategoryCardsCarousel };
import type { CarouselStylesNames, Embla } from '@mantine/carousel';
import { Carousel } from '@mantine/carousel';
import { useMantineTheme } from '@mantine/core';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import AutoHeight from 'embla-carousel-auto-height';
import type { CategoryEntity } from '@/shared/api';
import { ImageCard } from '@/shared/ui';
import type { CustomCarouselStylesParams } from '@/shared/lib/mantine';
import { useCarouselStyles } from '@/shared/lib/mantine';
import styles from './category-cards-carousel.module.scss';
interface CategoryCardsCarouselProps {
className?: string;
items: CategoryEntity[];
}
const CategoryCardsCarousel = memo(({ className, items }: CategoryCardsCarouselProps) => {
const autoHeightPluginRef = useRef(AutoHeight());
const [embla, setEmbla] = useState<Embla | null>(null);
const carouselConfig: CustomCarouselStylesParams = {
containScroll: 'trimSnaps',
slidesToScroll: 'auto',
includeGapInSize: true,
slideGap: 16,
loop: true,
slideSize: '50%',
align: 'start',
breakpoints: [{ minWidth: 'lg', slideSize: '25%', slideGap: 30 }],
plugins: [autoHeightPluginRef.current],
};
const { classes, cx } = useCarouselStyles(carouselConfig);
const toggleActiveWhenScrollable = useCallback(() => {
if (!embla) return;
const isScrollable = embla.internalEngine().slideLooper.canLoop();
embla.reInit({ active: isScrollable });
}, [embla]);
const { breakpoints } = useMantineTheme();
const { controls: controlsStyles, ...restClasses } = classes;
const carouselClasses: Partial<Record<CarouselStylesNames, string>> = {
controls: cx(controlsStyles, styles.controls),
...restClasses,
};
useEffect(() => {
if (!embla) return;
toggleActiveWhenScrollable();
embla.on('resize', toggleActiveWhenScrollable);
}, [embla, toggleActiveWhenScrollable]);
return (
<Carousel
getEmblaApi={setEmbla}
{...carouselConfig}
classNames={carouselClasses}
className={className}
styles={{
container: {
alignItems: 'flex-start',
transition: 'height 0.2s',
},
}}
plugins={[autoHeightPluginRef.current]}
>
{items.map(({ id, name, url, ...rest }, index) => (
<Carousel.Slide key={index}>
<ImageCard
title={name}
href={url}
{...rest}
sizes={`(min-width: ${breakpoints.lg}) 25vw, 50vw`}
/>
</Carousel.Slide>
))}
</Carousel>
);
});
export type { CategoryCardsCarouselProps };
export { CategoryCardsCarousel };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment