Skip to content

CORE-675: rename SectionNav to ButtonNav and refactor props from ToggleButtonGroup #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SectionNav } from './SectionNav/index';
import { ButtonNav } from './ButtonNav/index';
import renderer from 'react-test-renderer';

describe('SectionNav', () => {
describe('ButtonNav', () => {

const childrenListWithKeys = [
<button key='1'>Slide 1</button>,
Expand All @@ -16,26 +16,26 @@ describe('SectionNav', () => {

it('matches snapshot', () => {
const tree = renderer.create(
<SectionNav
<ButtonNav
handlePrevArrow={handlePrev}
handleNextArrow={handleNext}
>
{childrenListWithKeys}
</SectionNav>
</ButtonNav>
).toJSON();
expect(tree).toMatchSnapshot();
});

it('matches snapshot when arrows are disabled', () => {
const tree = renderer.create(
<SectionNav
<ButtonNav
handlePrevArrow={handlePrev}
handleNextArrow={handleNext}
isPrevArrowDisabled
isNextArrowDisabled
>
{childrenListWithKeys}
</SectionNav>
</ButtonNav>
).toJSON();
expect(tree).toMatchSnapshot();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { SectionNav } from "./SectionNav/index";
import { ButtonNav } from "./ButtonNav/index";
import { ToggleButtonGroup } from "./ToggleButtonGroup/index";
import { Key } from "react-aria-components";

Expand Down Expand Up @@ -28,14 +28,14 @@ export const Default = () => {

return (
<>
<SectionNav
<ButtonNav
handlePrevArrow={handlePrevArrow}
handleNextArrow={handleNextArrow}
isPrevArrowDisabled={selectedIndex === 0}
isNextArrowDisabled={selectedIndex === childrenListWithKeys.length - 1}
>
{[childrenListWithKeys]}
</SectionNav>
</ButtonNav>
<span>Selected section: {selectedIndex + 1}</span>
</>

Expand Down Expand Up @@ -68,62 +68,63 @@ export const WithToggleButtonGroups = () => {

const flattenedSections = sections.flat();

const [selectedItems, setSelectedItems] = React.useState(new Set<Key>([flattenedSections[0].id]));
const [selectedItem, setSelectedItem] = React.useState<string>(flattenedSections ? flattenedSections[0].id : '');

const scrollToIndex = (id: Key) => {
const child = document.querySelector(`[data-button-id="${id}"]`) as HTMLElement;
const scrollNavToSection = (sectionDataId: string) => {
const child = document.querySelector<HTMLElement>(`[data-button-id="${sectionDataId}"]`);
if (child) {
child.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
}
};

const handlePrevArrow = () => {
setSelectedItems((prev) => {
const newSet = new Set<Key>();
const firstSectionKeys = flattenedSections.map(section => section.id);
const currentIndex = firstSectionKeys.indexOf([...prev][0] as string);
setSelectedItem((prev) => {
const currentIndex = flattenedSections.findIndex((element) => element.id === prev);
let newSelectedItem = prev;
if (currentIndex > 0) {
newSet.add(firstSectionKeys[currentIndex - 1]);
scrollToIndex(firstSectionKeys[currentIndex - 1]);
newSelectedItem = flattenedSections[currentIndex - 1].id;
scrollNavToSection(newSelectedItem);
}
return newSet;
return newSelectedItem;
});
};

const handleNextArrow = () => {
setSelectedItems((prev) => {
const newSet = new Set<Key>();
const firstSectionKeys = flattenedSections.map(section => section.id);
const currentIndex = firstSectionKeys.indexOf([...prev][0] as string);
if (currentIndex < firstSectionKeys.length - 1) {
newSet.add(firstSectionKeys[currentIndex + 1]);
scrollToIndex(firstSectionKeys[currentIndex + 1]);
setSelectedItem((prev) => {
const currentIndex = flattenedSections.findIndex((element) => element.id === prev);
let newSelectedItem = prev;
if (currentIndex < flattenedSections.length - 1) {
newSelectedItem = flattenedSections[currentIndex + 1].id;
scrollNavToSection(newSelectedItem);
}
return newSet;
return newSelectedItem;
});
};

const ToggleGroup = sections.map(
(sectionSet, index) =>
<ToggleButtonGroup
key={`section-${index + 1}`}
selectedItems={selectedItems}
onSelectionChange={setSelectedItems}
selectedItems={new Set<Key>([selectedItem])}
onSelectionChange={(newSet) => setSelectedItem(newSet.size ? [...newSet][0] as string : '')}
items={sectionSet}
/>
);

return (
<>
<SectionNav
<ButtonNav
handlePrevArrow={handlePrevArrow}
handleNextArrow={handleNextArrow}
isPrevArrowDisabled={selectedItems.has(flattenedSections[0].id) || selectedItems.size === 0}
isNextArrowDisabled={selectedItems.has(flattenedSections[flattenedSections.length - 1].id) || selectedItems.size === 0}
isPrevArrowDisabled={selectedItem === flattenedSections[0].id || selectedItem.length === 0}
isNextArrowDisabled={
selectedItem === flattenedSections[flattenedSections.length - 1].id ||
selectedItem.length === 0
}
>
{ToggleGroup}
</SectionNav>
<p>Current selections: {[...selectedItems].join(', ')}</p>
</ButtonNav>
<p>Current selected: {selectedItem}</p>
</>
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import React from "react";
import {
SectionNavContainer,
SectionNavWrapper,
SectionNavGroup,
ButtonNavContainer,
ButtonNavWrapper,
ButtonNavGroup,
StyledArrow,
} from './styles';
import { LeftArrow } from "../svgs/LeftArrow";
import { RightArrow } from "../svgs/RightArrow";

export interface SectionNavProps {
export interface ButtonNavProps {
children: React.ReactNode[];
handlePrevArrow: () => void;
handleNextArrow: () => void;
isPrevArrowDisabled?: boolean;
isNextArrowDisabled?: boolean;
}

export const SectionNav = (
export const ButtonNav = (
{
children,
handlePrevArrow,
handleNextArrow,
isPrevArrowDisabled = false,
isNextArrowDisabled = false
}: SectionNavProps) => {
}: ButtonNavProps) => {
const wrapperRef = React.useRef<HTMLDivElement>(null);

return (
<SectionNavContainer>
<ButtonNavContainer>
<StyledArrow
onClick={handlePrevArrow}
className="left-arrow"
Expand All @@ -36,20 +36,20 @@ export const SectionNav = (
>
<LeftArrow width={14} height={14} />
</StyledArrow>
<SectionNavWrapper ref={wrapperRef} >
<ButtonNavWrapper ref={wrapperRef} >
{children.map((child, index) =>
<SectionNavGroup key={`section-group-${index + 1}`} >
<ButtonNavGroup key={`section-group-${index + 1}`} >
{child}
</SectionNavGroup>
</ButtonNavGroup>
)}
</SectionNavWrapper>
</ButtonNavWrapper>
<StyledArrow
onClick={handleNextArrow}
className="right-arrow"
aria-label="move to next item"
disabled={isNextArrowDisabled} >
<RightArrow width={14} height={14} />
</StyledArrow>
</SectionNavContainer>
</ButtonNavContainer>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import styled from 'styled-components';
import { palette } from '../../theme/palette';

export const SectionNavContainer = styled.div`
export const ButtonNavContainer = styled.div`
position: relative;
display: flex;
justify-content: space-between;
Expand All @@ -10,15 +10,15 @@ export const SectionNavContainer = styled.div`
max-width: fit-content;
`;

export const SectionNavWrapper = styled.div`
export const ButtonNavWrapper = styled.div`
display: flex;
position: inherit;
overflow-x: auto;
width: auto;
transition: transform 0.3s ease-in-out;
`;

export const SectionNavGroup = styled.div`
export const ButtonNavGroup = styled.div`
flex: 0 0 auto;
&:not(:last-child) {
margin-right: 0.8rem;
Expand Down
8 changes: 4 additions & 4 deletions src/components/ToggleButtonGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ export const MultipleSelection = () => {
};

export const SingleSelection = () => {
const [selectedItems, setSelectedItems] = React.useState(new Set<Key>([]));
const [selectedItem, setSelectedItem] = React.useState('');
return (
<>
<ToggleButtonGroup
selectedItems={selectedItems}
onSelectionChange={setSelectedItems}
selectedItems={new Set<Key>([selectedItem])}
onSelectionChange={(newSet) => setSelectedItem(newSet.size ? [...newSet][0] as string : '')}
items={childrenListWithKeys}
/>
<p>Current selections: {[...selectedItems].join(', ')}</p>
<p>Current selections: {selectedItem}</p>
</>
);
};
5 changes: 2 additions & 3 deletions src/components/ToggleButtonGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from "react";
import { StyledToggleButtonGroup, StyledToggleButton } from "./styles";
import { Key } from "react-aria-components";

export interface ToggleButtonGroupProps {
items: { id: string, value: string }[];
selectedItems: Set<Key>;
onSelectionChange?: React.Dispatch<React.SetStateAction<Set<Key>>>;
selectedItems?: Iterable<Key>;
onSelectionChange?: ((keys: Set<Key>) => void);
selectionMode?: 'single' | 'multiple';
className?: string;
}
Expand Down
1 change: 1 addition & 0 deletions src/components/ToggleButtonGroup/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const StyledToggleButton = styled(ToggleButton)`
font-size: 1.6rem;
line-height: 2rem;
white-space: nowrap;
user-select: none;

& + & {
border-left: none;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`SectionNav matches snapshot 1`] = `
exports[`ButtonNav matches snapshot 1`] = `
<div
className="sc-bczRLJ caOXAc"
>
Expand Down Expand Up @@ -84,7 +84,7 @@ exports[`SectionNav matches snapshot 1`] = `
</div>
`;

exports[`SectionNav matches snapshot when arrows are disabled 1`] = `
exports[`ButtonNav matches snapshot when arrows are disabled 1`] = `
<div
className="sc-bczRLJ caOXAc"
>
Expand Down
Loading
Loading