Skip to content

Instantly share code, notes, and snippets.

@mberneti
Created March 12, 2024 09:09
Show Gist options
  • Save mberneti/5d26fa6b508c64139c9a4d44990426aa to your computer and use it in GitHub Desktop.
Save mberneti/5d26fa6b508c64139c9a4d44990426aa to your computer and use it in GitHub Desktop.
import { useState } from 'react';
import classnames from 'classnames';
import { Box } from './Box'; // Assuming Box component is imported from a file
interface Slide {
[key: string]: any;
}
interface AttachElementsType {
isSimple: boolean;
width: number;
element?: JSX.Element;
className?: string;
appendToSlideComponent?: boolean;
}
interface Props<SlideElement extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> {
slides: Slide[];
chunkSize?: number;
SlidesElement: SlideElement;
slidesProps?: Partial<ComponentProps<SlideElement>>;
chunkStyles?: CSSProperties;
chunkClassNames?: string;
sliderOptions?: KeenSliderOptions;
isRtl?: boolean;
sliderMode?: 'snap' | 'free' | 'free-snap';
isLoading?: boolean;
slidesConditionalClassName?: Record<number, string>;
prependSlot?: AttachElementsType;
appendSlot?: AttachElementsType;
}
export function TwoDimensionSliderConstructorV2<
SlideElement extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>
>({
slides,
slidesProps,
chunkSize = 1,
chunkClassNames,
chunkStyles,
sliderOptions,
isRtl = true,
sliderMode = 'free-snap',
isLoading,
SlidesElement,
slidesConditionalClassName,
prependSlot,
appendSlot
}: Props<SlideElement>): [(node: HTMLElement | null) => void, JSX.Element[] | null] {
const [sliderRef] = useState<HTMLElement | null>(null);
if (!slides || slides.length === 0) {
return [sliderRef, null];
}
const conditionalClassNameMaker = (index: number): string => {
let conditionalClassName = '';
if (slidesConditionalClassName) {
const className = slidesConditionalClassName[index];
if (className) {
conditionalClassName += className;
}
}
return conditionalClassName;
};
const renderSlideComponents = () => {
const slideComponents: JSX.Element[] = [];
slides.forEach((slideColumn: Slide, index) => {
slideColumn.isLoading = isLoading;
const slideElement = (
<Box
className={classnames('keen-slider__slide', conditionalClassNameMaker(index), chunkClassNames)}
style={chunkStyles}
key={index}
>
<SlidesElement {...slidesProps} {...cleanObject(slideColumn)} position={index + 1} />
</Box>
);
slideComponents.push(slideElement);
});
return slideComponents;
};
const renderChunkedSlideComponents = () => {
const slideComponents: JSX.Element[] = [];
for (let i = 0; i < slides.length; i += chunkSize) {
const sliderColumnChunk = slides.slice(i, i + chunkSize);
const chunkElement = (
<Box
className={classnames('keen-slider__slide', conditionalClassNameMaker(i), chunkClassNames)}
style={chunkStyles}
key={i}
>
{sliderColumnChunk.map((slidesColumnProps: Slide, mapIndex) => {
slidesColumnProps.isLoading = isLoading;
return (
<SlidesElement
key={i + mapIndex}
{...slidesProps}
{...cleanObject(slidesColumnProps)}
position={i * 2 + (mapIndex + 1)}
/>
);
})}
</Box>
);
slideComponents.push(chunkElement);
}
return slideComponents;
};
const prependSlotElement = prependSlot?.isSimple ? (
<Box
className='keen-slider__slide'
style={{
maxWidth: `${prependSlot.width}px`,
minWidth: `${prependSlot.width}px`
}}
key="prepend-slot"
/>
) : prependSlot?.element;
const appendSlotElement = appendSlot?.isSimple ? (
<Box
className={classnames('keen-slider__slide', appendSlot.className)}
key="append-slot"
/>
) : appendSlot?.element;
const slideComponents = chunkSize <= 1 ? renderSlideComponents() : renderChunkedSlideComponents();
if (prependSlotElement) {
slideComponents.unshift(prependSlotElement);
}
if (appendSlotElement) {
slideComponents.push(appendSlotElement);
}
return [sliderRef, slideComponents];
}
@mberneti
Copy link
Author

Key changes and improvements:

  1. Changed the conditional check for empty slides to a simpler check.
  2. Simplified the loop logic for rendering slide components and chunked slide components.
  3. Extracted common JSX elements and logic into separate functions.
  4. Improved type definitions for clarity.
  5. Utilized useState hook instead of useKeenSlider, assuming that sliderRef is only used for attaching the slider to a DOM element.
  6. Made use of optional chaining and nullish coalescing operators for safer access to properties and values.
  7. Added key props to elements rendered in arrays to avoid React warnings.
  8. Made sure to handle cases where slidesConditionalClassName might not be defined.
  9. Simplified handling of prependSlot and appendSlot elements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment