Skip to content
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

polish: bind key listener to light/dark toggle + a11y lint fixes #5341

Merged
merged 6 commits into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from 5 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
6 changes: 6 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const Toggle = memo(
'react-toggle--focus': focused,
'react-toggle--disabled': disabled,
})}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div
className="react-toggle-track"
role="button"
Expand All @@ -73,6 +74,11 @@ const Toggle = memo(
onClick={() => setChecked(!checked)}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
inputRef.current?.click();
}
}}
/>
</div>
);
Expand Down
78 changes: 42 additions & 36 deletions packages/docusaurus-theme-common/src/components/Details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@ const Details = ({summary, children, ...props}: DetailsProps): JSX.Element => {
// We use a separate prop because it must be set only after animation completes
// Otherwise close anim won't work
const [open, setOpen] = useState(props.open);
const toggle = (e: React.SyntheticEvent) => {
Copy link
Collaborator

@slorber slorber Aug 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I'd rather not extract this method, it's only used in one place and it's not even meant to be reusable considering it's handling a click dom event. Extracting the code and naming it "toggle" makes this more implicit and imply a reusable api. If you really want to extract this (like for perf reasons using useCallback which in this case wouldn't improve anything), you'd rather name it handleClick.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I wrote this a week ago and no idea why I extracted it back then 🤦‍♂️

e.stopPropagation(); // For isolation of multiple nested details/summary
const target = e.target as HTMLElement;
const shouldToggle =
isInSummary(target) && hasParent(target, detailsRef.current!);
if (!shouldToggle) {
return;
}
e.preventDefault();
if (collapsed) {
setCollapsed(false);
setOpen(true);
} else {
setCollapsed(true);
// setOpen(false); // Don't do this, it breaks close animation!
}
};

return (
<details
Expand All @@ -50,43 +67,32 @@ const Details = ({summary, children, ...props}: DetailsProps): JSX.Element => {
styles.details,
{[styles.isClient]: isClient},
props.className,
)}
onMouseDown={(e) => {
const target = e.target as HTMLElement;
// Prevent a double-click to highlight summary text
if (isInSummary(target) && e.detail > 1) {
e.preventDefault();
}
}}
onClick={(e) => {
e.stopPropagation(); // For isolation of multiple nested details/summary
const target = e.target as HTMLElement;
const shouldToggle =
isInSummary(target) && hasParent(target, detailsRef.current!);
if (!shouldToggle) {
return;
}
e.preventDefault();
if (collapsed) {
setCollapsed(false);
setOpen(true);
} else {
setCollapsed(true);
// setOpen(false); // Don't do this, it breaks close animation!
}
}}>
{summary}
)}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div
role="button"
tabIndex={0}
onMouseDown={(e) => {
const target = e.target as HTMLElement;
// Prevent a double-click to highlight summary text
if (isInSummary(target) && e.detail > 1) {
e.preventDefault();
}
}}
onClick={toggle}>
{summary}

<Collapsible
lazy={false} // Content might matter for SEO in this case
collapsed={collapsed}
disableSSRStyle // Allows component to work fine even with JS disabled!
onCollapseTransitionEnd={(newCollapsed) => {
setCollapsed(newCollapsed);
setOpen(!newCollapsed);
}}>
<div className={styles.collapsibleContent}>{children}</div>
</Collapsible>
<Collapsible
lazy={false} // Content might matter for SEO in this case
collapsed={collapsed}
disableSSRStyle // Allows component to work fine even with JS disabled!
onCollapseTransitionEnd={(newCollapsed) => {
setCollapsed(newCollapsed);
setOpen(!newCollapsed);
}}>
<div className={styles.collapsibleContent}>{children}</div>
</Collapsible>
</div>
</details>
);
};
Expand Down