From add74d39fa103f1466a8c75dca4cf5ba7a71f524 Mon Sep 17 00:00:00 2001 From: Eshel Date: Wed, 4 Dec 2024 13:02:31 +0200 Subject: [PATCH 1/4] feat(select): add configurable autoScrollInterval --- packages/react/select/src/Select.tsx | 96 +++++++++++++++------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/packages/react/select/src/Select.tsx b/packages/react/select/src/Select.tsx index 5e848d8ca..f4a8988d6 100644 --- a/packages/react/select/src/Select.tsx +++ b/packages/react/select/src/Select.tsx @@ -1493,60 +1493,66 @@ SelectScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME; type SelectScrollButtonImplElement = React.ElementRef; interface SelectScrollButtonImplProps extends PrimitiveDivProps { onAutoScroll(): void; + autoScrollInterval?: number; } const SelectScrollButtonImpl = React.forwardRef< SelectScrollButtonImplElement, SelectScrollButtonImplProps ->((props: ScopedProps, forwardedRef) => { - const { __scopeSelect, onAutoScroll, ...scrollIndicatorProps } = props; - const contentContext = useSelectContentContext('SelectScrollButton', __scopeSelect); - const autoScrollTimerRef = React.useRef(null); - const getItems = useCollection(__scopeSelect); +>( + ( + { autoScrollInterval = 50, ...props }: ScopedProps, + forwardedRef + ) => { + const { __scopeSelect, onAutoScroll, ...scrollIndicatorProps } = props; + const contentContext = useSelectContentContext('SelectScrollButton', __scopeSelect); + const autoScrollTimerRef = React.useRef(null); + const getItems = useCollection(__scopeSelect); - const clearAutoScrollTimer = React.useCallback(() => { - if (autoScrollTimerRef.current !== null) { - window.clearInterval(autoScrollTimerRef.current); - autoScrollTimerRef.current = null; - } - }, []); + const clearAutoScrollTimer = React.useCallback(() => { + if (autoScrollTimerRef.current !== null) { + window.clearInterval(autoScrollTimerRef.current); + autoScrollTimerRef.current = null; + } + }, []); - React.useEffect(() => { - return () => clearAutoScrollTimer(); - }, [clearAutoScrollTimer]); + React.useEffect(() => { + return () => clearAutoScrollTimer(); + }, [clearAutoScrollTimer]); - // When the viewport becomes scrollable on either side, the relevant scroll button will mount. - // Because it is part of the normal flow, it will push down (top button) or shrink (bottom button) - // the viewport, potentially causing the active item to now be partially out of view. - // We re-run the `scrollIntoView` logic to make sure it stays within the viewport. - useLayoutEffect(() => { - const activeItem = getItems().find((item) => item.ref.current === document.activeElement); - activeItem?.ref.current?.scrollIntoView({ block: 'nearest' }); - }, [getItems]); + // When the viewport becomes scrollable on either side, the relevant scroll button will mount. + // Because it is part of the normal flow, it will push down (top button) or shrink (bottom button) + // the viewport, potentially causing the active item to now be partially out of view. + // We re-run the `scrollIntoView` logic to make sure it stays within the viewport. + useLayoutEffect(() => { + const activeItem = getItems().find((item) => item.ref.current === document.activeElement); + activeItem?.ref.current?.scrollIntoView({ block: 'nearest' }); + }, [getItems]); - return ( - { - if (autoScrollTimerRef.current === null) { - autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50); - } - })} - onPointerMove={composeEventHandlers(scrollIndicatorProps.onPointerMove, () => { - contentContext.onItemLeave?.(); - if (autoScrollTimerRef.current === null) { - autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50); - } - })} - onPointerLeave={composeEventHandlers(scrollIndicatorProps.onPointerLeave, () => { - clearAutoScrollTimer(); - })} - /> - ); -}); + return ( + { + if (autoScrollTimerRef.current === null) { + autoScrollTimerRef.current = window.setInterval(onAutoScroll, autoScrollInterval); + } + })} + onPointerMove={composeEventHandlers(scrollIndicatorProps.onPointerMove, () => { + contentContext.onItemLeave?.(); + if (autoScrollTimerRef.current === null) { + autoScrollTimerRef.current = window.setInterval(onAutoScroll, autoScrollInterval); + } + })} + onPointerLeave={composeEventHandlers(scrollIndicatorProps.onPointerLeave, () => { + clearAutoScrollTimer(); + })} + /> + ); + } +); /* ------------------------------------------------------------------------------------------------- * SelectSeparator From 87df360958654b0caa5fdd5629e84f4cd0a0b95e Mon Sep 17 00:00:00 2001 From: Eshel Date: Wed, 4 Dec 2024 14:55:17 +0200 Subject: [PATCH 2/4] chore(select): add WithCustomAutoScrollInterval to storybook --- packages/react/select/src/Select.stories.tsx | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/packages/react/select/src/Select.stories.tsx b/packages/react/select/src/Select.stories.tsx index 6fe46281e..6443532b2 100644 --- a/packages/react/select/src/Select.stories.tsx +++ b/packages/react/select/src/Select.stories.tsx @@ -717,6 +717,71 @@ export const WithVeryLongSelectItems = () => ( ); +export const WithCustomAutoScrollInterval = () => ( +
+ {[ + { speed: 'slower', interval: 80 }, + { speed: 'default', interval: undefined }, + { speed: 'faster', interval: 25 }, + ].map(({ speed, interval }) => ( + + ))} +
+); + export const ChromaticShortOptionsPaddedContent = () => ( ); From 1466209a0008ad69f15ceaaced516202e62cee69 Mon Sep 17 00:00:00 2001 From: Eshel Date: Wed, 4 Dec 2024 14:22:11 +0200 Subject: [PATCH 3/4] chore(release): update version for Select changes --- .yarn/versions/b4415633.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .yarn/versions/b4415633.yml diff --git a/.yarn/versions/b4415633.yml b/.yarn/versions/b4415633.yml new file mode 100644 index 000000000..63ebe5ba6 --- /dev/null +++ b/.yarn/versions/b4415633.yml @@ -0,0 +1,3 @@ +releases: + "@radix-ui/react-select": patch + primitives: major From e1e20f3ef1e66ecbbe1415b779e47e0e61659bc4 Mon Sep 17 00:00:00 2001 From: Eshel Date: Thu, 5 Dec 2024 11:43:36 +0200 Subject: [PATCH 4/4] fix releases --- .yarn/versions/b4415633.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.yarn/versions/b4415633.yml b/.yarn/versions/b4415633.yml index 63ebe5ba6..0e7f783fd 100644 --- a/.yarn/versions/b4415633.yml +++ b/.yarn/versions/b4415633.yml @@ -1,3 +1,5 @@ releases: "@radix-ui/react-select": patch - primitives: major + +declined: + - primitives \ No newline at end of file