Skip to content

Commit

Permalink
Cleanup and simplify hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
carbonrobot committed Mar 17, 2024
1 parent db05774 commit 623dee3
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 53 deletions.
15 changes: 7 additions & 8 deletions packages/nuka/src/Carousel/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,18 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
ref
) => {
const containerRef = useRef<HTMLDivElement | null>(null);
const wrapperRef = useRef<HTMLDivElement | null>(null);

// -- update page count and scroll offset based on scroll distance
const { totalPages, scrollOffset } = useMeasurement({
scrollDistance,
containerRef,
wrapperRef,
});

// -- paging
const { currentPage, goBack, goForward, goToPage } = usePaging(
const { currentPage, goBack, goForward, goToPage } = usePaging({
totalPages,
wrapAround
);
wrapAround,
});

// -- autoplay
useInterval(goForward, autoplayInterval, autoplay);
Expand Down Expand Up @@ -122,13 +120,14 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
className="nuka-overflow"
ref={containerRef}
onTouchMove={onContainerScroll}
data-testid="overflow"
id="nuka-overflow"
data-testid="nuka-overflow"
style={{ touchAction: swiping ? 'pan-x' : 'none' }}
>
<div
className="nuka-wrapper"
ref={wrapperRef}
data-testid="wrapper"
id="nuka-wrapper"
data-testid="nuka-wrapper"
>
{children}
</div>
Expand Down
69 changes: 32 additions & 37 deletions packages/nuka/src/hooks/use-measurement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import { useDebounced } from 'src/hooks/use-debounced';
import { arraySeq, arraySum } from 'src/utils';

type MeasurementProps = {
scrollDistance: number | 'slide' | 'screen';
containerRef: React.RefObject<HTMLDivElement>;
wrapperRef: React.RefObject<HTMLDivElement>;
scrollDistance: number | 'slide' | 'screen';
};

export function useMeasurement({
scrollDistance,
containerRef,
wrapperRef,
scrollDistance,
}: MeasurementProps) {
const [totalPages, setTotalPages] = useState(0);
const [scrollOffset, setScrollOffset] = useState(arraySeq(totalPages, 0));
Expand All @@ -22,57 +20,54 @@ export function useMeasurement({
// correct dimensions for the calculation
// note: this is similar to useLayout, but runs async
requestAnimationFrame(() => {
const container = containerRef.current;
if (!container) return;

// determine the width of the content that is not visible (overflow)
const remainder = container.scrollWidth - container.offsetWidth;

switch (scrollDistance) {
case 'screen': {
if (containerRef.current && wrapperRef.current) {
const pageCount = Math.ceil(
wrapperRef.current.scrollWidth / containerRef.current.offsetWidth
);
setTotalPages(pageCount);
setScrollOffset(
arraySeq(pageCount, containerRef.current.offsetWidth)
);
}
const pageCount = Math.ceil(
container.scrollWidth / container.offsetWidth
);
setTotalPages(pageCount);
setScrollOffset(arraySeq(pageCount, container.offsetWidth));
break;
}
case 'slide': {
if (wrapperRef.current) {
// creates an array of slide widths in order to support
// slides of varying widths as children
const offsets = Array.from(wrapperRef.current.children).map(
(child) => (child as HTMLElement).offsetWidth
);
// creates an array of slide widths in order to support
// slides of varying widths as children
const children =
container.querySelector('#nuka-wrapper')?.children || [];
const offsets = Array.from(children).map(
(child) => (child as HTMLElement).offsetWidth
);

const scrollOffsets = arraySum([0, ...offsets.slice(0, -1)]);
const scrollOffsets = arraySum([0, ...offsets.slice(0, -1)]);

// find the index of the scroll offset that is greater than
// the remainder of the full width and window width
const remainder =
wrapperRef.current.scrollWidth - wrapperRef.current.offsetWidth;
const pageCount =
scrollOffsets.findIndex((offset) => offset >= remainder) + 1;
// find the index of the scroll offset that is greater than
// the remainder of the full width and window width
const pageCount =
scrollOffsets.findIndex((offset) => offset >= remainder) + 1;

setTotalPages(pageCount);
setScrollOffset(scrollOffsets);
}
setTotalPages(pageCount);
setScrollOffset(scrollOffsets);
break;
}
default: {
if (containerRef.current && typeof scrollDistance === 'number') {
const carouselTotalWidth =
containerRef.current.scrollWidth -
containerRef.current.offsetWidth;

const pageCount =
Math.ceil(carouselTotalWidth / scrollDistance) + 1;
if (typeof scrollDistance === 'number') {
// find the number of pages required to scroll the all slides
// to the end of the container
const pageCount = Math.ceil(remainder / scrollDistance) + 1;

setTotalPages(pageCount);
setScrollOffset(arraySeq(pageCount, scrollDistance));
}
}
}
});
}, [scrollDistance, containerRef, wrapperRef]);
}, [scrollDistance, containerRef]);

// debounce the measure function when resizing so
// it doesnt fire on every pixel change
Expand Down
21 changes: 13 additions & 8 deletions packages/nuka/src/hooks/use-paging.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,33 @@ type UsePagingReturnType = {
goBack: () => void;
};

export function usePaging(
totalSlides: number,
wrapAround: boolean
): UsePagingReturnType {
type PagingProps = {
totalPages: number;
wrapAround: boolean;
};

export function usePaging({
totalPages,
wrapAround,
}: PagingProps): UsePagingReturnType {
const [currentPage, setCurrentPage] = useState(0);

const goToPage = (idx: number) => {
if (idx < 0 || idx >= totalSlides) return;
if (idx < 0 || idx >= totalPages) return;
setCurrentPage(idx);
};

const goForward = () => {
if (wrapAround) {
setCurrentPage((prev) => (prev + 1) % totalSlides);
setCurrentPage((prev) => (prev + 1) % totalPages);
} else {
setCurrentPage((prev) => Math.min(prev + 1, totalSlides - 1));
setCurrentPage((prev) => Math.min(prev + 1, totalPages - 1));
}
};

const goBack = () => {
if (wrapAround) {
setCurrentPage((prev) => (prev - 1 + totalSlides) % totalSlides);
setCurrentPage((prev) => (prev - 1 + totalPages) % totalPages);
} else {
setCurrentPage((prev) => Math.max(prev - 1, 0));
}
Expand Down

0 comments on commit 623dee3

Please sign in to comment.