Skip to content

Commit

Permalink
SOEOPSFY24-350 | update timeline list to include manual keyboard acce…
Browse files Browse the repository at this point in the history
…ssibility
  • Loading branch information
rebeccahongsf committed Dec 18, 2024
1 parent d0b5de5 commit 1214fcb
Showing 1 changed file with 73 additions and 5 deletions.
78 changes: 73 additions & 5 deletions components/Timeline/TimelineOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type TimelineProps = {
const TimelineOverview = ({ timelineData }: TimelineProps) => {
const [isMounted, setIsMounted] = useState(false);
const [expandedUuid, setExpandedUuid] = useState<string | null>(null);
const [expandedRowIndex, setExpandedRowIndex] = useState<number | null>(null);
const [focusedTabIndex, setFocusedTabIndex] = useState<number>(0);

// Ensure the component is mounted before running media queries
useEffect(() => {
Expand All @@ -39,16 +41,69 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
return acc;
}, []);

const handleToggle = (uuid: string) => {
setExpandedUuid((currentUuid) => (currentUuid === uuid ? null : uuid));
const handleToggle = (uuid: string, rowIndex: number) => {
setExpandedUuid((currentUuid) => {
const isSameRow = rowIndex === expandedRowIndex;
const isSameItem = uuid === currentUuid;

if (isSameRow) return isSameItem ? null : uuid;

setExpandedRowIndex(rowIndex);
return uuid;
});
};

const handleKeyDown = (
event: React.KeyboardEvent<HTMLButtonElement>,
itemUuid: string,
rowIndex: number,
) => {
switch (event.key) {
case "Enter":
case " ":
event.preventDefault();
handleToggle(itemUuid, rowIndex);
break;
case "ArrowRight":
case "ArrowDown":
event.preventDefault();
setFocusedTabIndex(
(prevIndex) => (prevIndex + 1) % timelineData.length,
);
break;
case "ArrowLeft":
case "ArrowUp":
event.preventDefault();
setFocusedTabIndex(
(prevIndex) =>
(prevIndex - 1 + timelineData.length) % timelineData.length,
);
break;
case "Home":
event.preventDefault();
setFocusedTabIndex(0);
break;
case "End":
event.preventDefault();
setFocusedTabIndex(timelineData.length - 1);
break;
default:
break;
}
};

if (!isMounted) {
return <ClipLoader />;
}

return (
<Container width="site" pb={5} bgColor="fog-light" className="mb-50">
<Container
id="main-content"
width="site"
pb={5}
bgColor="fog-light"
className="mb-50"
>
<div className="grid rs-mb-10 sm:mb-0 sm:gap-[32px] md:gap-[76px]">
{rows.map((row, rowIndex) => (
<div
Expand All @@ -57,12 +112,14 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
>
<div
role="tablist"
aria-label={`Timeline row ${rowIndex + 1}`}
className="flex flex-col items-center md:items-start md:flex-row md:justify-between"
>
{row.map((item, itemIndex) => {
const sizePattern: SizeType[] = ["large", "medium", "small"];
const size = sizePattern[itemIndex % sizePattern.length];
const trapezoid = itemIndex % 2 === 0 ? "left" : "right";
const globalIndex = rowIndex * itemsPerRow + itemIndex;

return (
<TimelineItem
Expand All @@ -75,14 +132,22 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
isExpanded={expandedUuid === item.uuid}
size={size}
trapezoid={trapezoid}
onClick={() => handleToggle(item.uuid)}
onClick={() => handleToggle(item.uuid, rowIndex)}
tabIndex={focusedTabIndex === globalIndex ? 0 : -1}
onKeyDown={(e) => handleKeyDown(e, item.uuid, rowIndex)}
ref={(el) => {
if (focusedTabIndex === globalIndex) {
el?.focus();
}
}}
/>
);
})}
</div>

<AnimatePresence>
{expandedUuid &&
expandedRowIndex === rowIndex &&
row.some((item) => item.uuid === expandedUuid) && (
<motion.div
id={`tabpanel-${expandedUuid}`}
Expand All @@ -98,7 +163,10 @@ const TimelineOverview = ({ timelineData }: TimelineProps) => {
{...timelineData.find(
(item) => item.uuid === expandedUuid,
)!}
onClose={() => setExpandedUuid(null)}
onClose={() => {
setExpandedUuid(null);
setExpandedRowIndex(null);
}}
/>
</motion.div>
)}
Expand Down

0 comments on commit 1214fcb

Please sign in to comment.