Skip to content

Commit 6f643b9

Browse files
committed
✨ feat: add disable scroll into view option to accordion
1 parent 41a0be9 commit 6f643b9

File tree

7 files changed

+34
-6
lines changed

7 files changed

+34
-6
lines changed

src/components/InteractiveGroup/useInteractiveGroupItem.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { useEffect } from 'react';
22
import { useScrollIntoView, UseScrollIntoViewProps } from './../../hooks/useScrollIntoView';
33

44
export type UseInteractiveGroupItemProps<E extends HTMLElement> = Omit<UseScrollIntoViewProps<E>, 'behavior'> & {
5-
scrollBehavior?: UseScrollIntoViewProps<E>['behavior'];
5+
disableScrollIntoView?: boolean;
66
moveBrowserFocus?: boolean | ((props: { ref: React.MutableRefObject<E | null>; focused?: boolean }) => boolean);
7+
scrollBehavior?: UseScrollIntoViewProps<E>['behavior'];
78
};
89

910
/**
@@ -12,12 +13,13 @@ export type UseInteractiveGroupItemProps<E extends HTMLElement> = Omit<UseScroll
1213
* view and changes the active element to that ref element.
1314
*/
1415
export function useInteractiveGroupItem<E extends HTMLElement>({
16+
disableScrollIntoView = false,
1517
focused = false,
1618
moveBrowserFocus = false,
1719
ref,
1820
scrollBehavior,
1921
}: UseInteractiveGroupItemProps<E>): void {
20-
useScrollIntoView<E>({ behavior: scrollBehavior, ref, focused });
22+
useScrollIntoView<E>({ behavior: scrollBehavior, disabled: disableScrollIntoView, ref, focused });
2123

2224
useEffect(() => {
2325
if (focused && document.activeElement !== ref.current) {

src/compositions/Accordion/Accordion.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ export type AccordionProps = Pick<
2323
InteractiveGroupProviderProps,
2424
'maxSelect' | 'minSelect' | 'initialSelected' | 'onKeyDown' | 'onSelect'
2525
> &
26-
Pick<AccordionListProps, 'duration' | 'easing' | 'flush' | 'items' | 'orientation' | 'unstyled' | 'variant'> &
26+
Pick<
27+
AccordionListProps,
28+
'disableScrollIntoView' | 'duration' | 'easing' | 'flush' | 'items' | 'orientation' | 'unstyled' | 'variant'
29+
> &
2730
ThemeProps & {
2831
children?: AccordionRenderChildren;
2932
className?: string;
@@ -73,6 +76,7 @@ export function Accordion({
7376
children,
7477
className,
7578
contrast = false,
79+
disableScrollIntoView = false,
7680
duration,
7781
easing,
7882
flush = false,
@@ -135,6 +139,7 @@ export function Accordion({
135139
<AccordionList
136140
componentId={componentId}
137141
contrast={contrast}
142+
disableScrollIntoView={disableScrollIntoView}
138143
duration={duration}
139144
easing={easing}
140145
flush={flush}

src/compositions/Accordion/AccordionLabel.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type LocalAccordionLabelProps = AccordionItemStateProps & {
1010
children: React.ReactNode;
1111
className?: string;
1212
contentRef?: React.RefObject<HTMLDivElement>;
13+
disableScrollIntoView?: boolean;
1314
flush?: boolean;
1415
iconOnly?: boolean;
1516
id: string;
@@ -34,6 +35,7 @@ export function AccordionLabel({
3435
className,
3536
contentRef,
3637
disabled = false,
38+
disableScrollIntoView = false,
3739
flush = false,
3840
focused = false,
3941
iconOnly = false,
@@ -53,7 +55,13 @@ export function AccordionLabel({
5355
return true;
5456
}, [contentRef]);
5557

56-
useInteractiveGroupItem<HTMLDivElement>({ focused, ref, moveBrowserFocus, scrollBehavior: 'smooth' });
58+
useInteractiveGroupItem<HTMLDivElement>({
59+
disableScrollIntoView,
60+
focused,
61+
ref,
62+
moveBrowserFocus,
63+
scrollBehavior: 'smooth',
64+
});
5765
useListRegistryItem({ id, ref });
5866

5967
// wrap the content in a class so the content opacity can change without affecting the pseudo elements

src/compositions/Accordion/AccordionList.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type AccordionListProps = React.HTMLAttributes<HTMLDivElement> &
1515
ThemeProps & {
1616
className?: string;
1717
componentId: string;
18+
disableScrollIntoView?: boolean;
1819
flush?: boolean;
1920
items: readonly AccordionItemType[];
2021
onBlur?: (e: React.FocusEvent<HTMLDivElement>) => void;
@@ -37,6 +38,7 @@ export const AccordionList = React.forwardRef<HTMLDivElement, AccordionListProps
3738
className,
3839
componentId,
3940
contrast = false,
41+
disableScrollIntoView = false,
4042
duration,
4143
easing,
4244
flush,
@@ -104,6 +106,7 @@ export const AccordionList = React.forwardRef<HTMLDivElement, AccordionListProps
104106
items.map(({ id, ...item }, index) => (
105107
<AccordionListItem
106108
componentId={componentId}
109+
disableScrollIntoView={disableScrollIntoView}
107110
duration={duration}
108111
easing={easing}
109112
flush={flush}

src/compositions/Accordion/AccordionListItem.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type AccordionListItemProps = React.HTMLAttributes<HTMLDivElement> &
1515
Pick<AccordionContentProps, 'duration' | 'easing' | 'orientation'> &
1616
AccordionItemType & {
1717
componentId: string;
18+
disableScrollIntoView?: boolean;
1819
flush?: boolean;
1920
/** The accordion's focus state */
2021
focused?: boolean;
@@ -39,6 +40,7 @@ export const AccordionListItem = React.forwardRef<HTMLDivElement, AccordionListI
3940
content,
4041
contentProps,
4142
disabled,
43+
disableScrollIntoView,
4244
duration,
4345
easing,
4446
flush,
@@ -127,6 +129,7 @@ export const AccordionListItem = React.forwardRef<HTMLDivElement, AccordionListI
127129
aria-disabled={disabled}
128130
aria-expanded={!!stateProps.selected}
129131
contentRef={contentRef}
132+
disableScrollIntoView={disableScrollIntoView}
130133
flush={flush}
131134
iconOnly={iconOnly}
132135
id={generateComponentId(id)}

src/compositions/Accordion/stories/Accordion.stories.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ export default {
8888
category: 'Uncommon',
8989
},
9090
},
91+
disableScrollIntoView: {
92+
table: {
93+
category: 'Uncommon',
94+
},
95+
},
9196
id: {
9297
table: {
9398
category: 'Uncommon',

src/hooks/useScrollIntoView.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useLayoutEffect, useRef } from 'react';
22

33
export type UseScrollIntoViewProps<E extends HTMLElement> = {
44
behavior?: 'auto' | 'smooth';
5+
disabled?: boolean;
56
focused?: boolean;
67
ref: React.MutableRefObject<E | null>;
78
};
@@ -12,6 +13,7 @@ export type UseScrollIntoViewProps<E extends HTMLElement> = {
1213
* view.
1314
*/
1415
export function useScrollIntoView<E extends HTMLElement>({
16+
disabled = false,
1517
focused = false,
1618
ref,
1719
behavior = 'smooth',
@@ -20,9 +22,9 @@ export function useScrollIntoView<E extends HTMLElement>({
2022

2123
// make sure focused has previously been set so this doesn't scroll the whole page to this element on load
2224
useLayoutEffect((): void => {
23-
if (focused && previous.current !== undefined) {
25+
if (focused && previous.current !== undefined && !disabled) {
2426
ref.current?.scrollIntoView({ behavior, block: 'nearest', inline: 'start' });
2527
}
2628
previous.current = !!focused;
27-
}, [behavior, focused, ref]);
29+
}, [behavior, disabled, focused, ref]);
2830
}

0 commit comments

Comments
 (0)