-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add breaking improvements page (#86)
- Loading branch information
Showing
6 changed files
with
2,053 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** | ||
* This file has been copied from the original source code located in | ||
* `@docusaurus/theme-common/src/components/Details/index.tsx` and modified | ||
* to include a workaround for the Details component. | ||
* | ||
* All of the parts of the code that hve been modified are marked with | ||
* comments like so: `// >>>> THIS IS PART OF THE WORKAROUND FOR DETAILS COMPONENT <<<<`. | ||
* | ||
* It is needed to allow the Details component to be searchable using | ||
* the find in page feature of the browser. And also so tht links can be clicked | ||
* inside the summary element. | ||
*/ | ||
|
||
import React, { | ||
useRef, | ||
useState, | ||
type ComponentProps, | ||
type ReactElement, | ||
} from 'react'; | ||
import clsx from 'clsx'; | ||
import useIsBrowser from '@docusaurus/useIsBrowser'; | ||
import {useCollapsible, Collapsible} from '@docusaurus/theme-common'; | ||
import styles from './styles.module.css'; | ||
|
||
// >>>> THIS IS PART OF THE WORKAROUND FOR DETAILS COMPONENT <<<< | ||
// we don't recurse parents like the original to allow clicking on links | ||
function isTheSummary(node: HTMLElement | null): boolean { | ||
if (!node) { | ||
return false; | ||
} | ||
return node.tagName === 'SUMMARY'; | ||
} | ||
|
||
function hasParent(node: HTMLElement | null, parent: HTMLElement): boolean { | ||
if (!node) { | ||
return false; | ||
} | ||
return node === parent || hasParent(node.parentElement, parent); | ||
} | ||
|
||
export type DetailsProps = { | ||
/** | ||
* Summary is provided as props, optionally including the wrapping | ||
* `<summary>` tag | ||
*/ | ||
summary?: ReactElement | string; | ||
} & ComponentProps<'details'>; | ||
|
||
/** | ||
* A mostly un-styled `<details>` element with smooth collapsing. Provides some | ||
* very lightweight styles, but you should bring your UI. | ||
*/ | ||
export function Details({ | ||
summary, | ||
children, | ||
...props | ||
}: DetailsProps): JSX.Element { | ||
const isBrowser = useIsBrowser(); | ||
const detailsRef = useRef<HTMLDetailsElement>(null); | ||
|
||
const {collapsed, setCollapsed} = useCollapsible({ | ||
initialState: !props.open, | ||
}); | ||
// Use a separate state for the actual details prop, because it must be set | ||
// only after animation completes, otherwise close animations won't work | ||
const [open, setOpen] = useState(props.open); | ||
|
||
const summaryElement = React.isValidElement(summary) ? ( | ||
summary | ||
) : ( | ||
<summary>{summary ?? 'Details'}</summary> | ||
); | ||
|
||
// >>>> THIS IS PART OF THE WORKAROUND FOR DETAILS COMPONENT <<<< | ||
const [skipAnimation, setSkipAnimation] = useState(false); | ||
|
||
return ( | ||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions | ||
<details | ||
{...props} | ||
ref={detailsRef} | ||
open={open} | ||
data-collapsed={collapsed} | ||
className={clsx( | ||
styles.details, | ||
isBrowser && styles.isBrowser, | ||
props.className, | ||
)} | ||
onMouseDown={(e) => { | ||
const target = e.target as HTMLElement; | ||
// Prevent a double-click to highlight summary text | ||
if (isTheSummary(target) && e.detail > 1) { | ||
e.preventDefault(); | ||
} | ||
}} | ||
onClick={(e) => { | ||
console.log(e.target) | ||
e.stopPropagation(); // For isolation of multiple nested details/summary | ||
const target = e.target as HTMLElement; | ||
const shouldToggle = | ||
isTheSummary(target) && hasParent(target, detailsRef.current!); | ||
if (!shouldToggle) { | ||
return; | ||
} | ||
e.preventDefault(); | ||
|
||
setSkipAnimation(false); | ||
if (collapsed) { | ||
setCollapsed(false); | ||
setOpen(true); | ||
} else { | ||
setCollapsed(true); | ||
// Don't do this, it breaks close animation! | ||
// setOpen(false); | ||
} | ||
}} | ||
|
||
// >>>> THIS IS PART OF THE WORKAROUND FOR DETAILS COMPONENT <<<< | ||
onToggle={(e) => { | ||
if (e.target !== detailsRef.current || detailsRef.current === null) return; | ||
const isDOMOpen = detailsRef.current.open; | ||
|
||
// May skip closing animation if DOM state is forcefully closed | ||
// But generally this workaround here is needed for triggering open toggle | ||
if (isDOMOpen !== open) { | ||
setSkipAnimation(true); | ||
setOpen(isDOMOpen); | ||
setCollapsed(!isDOMOpen); | ||
} | ||
}}> | ||
{summaryElement} | ||
|
||
<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); | ||
}} | ||
animation={skipAnimation ? { | ||
duration: 0, | ||
} : undefined} | ||
|
||
// >>>> THIS IS PART OF THE WORKAROUND FOR DETAILS COMPONENT <<<< | ||
// 1. Must be displayed to be searchable | ||
// 2. Must have a height to find location of the element | ||
className={!open && collapsed ? clsx(styles.collapsibleContainer, styles.autoHeight) : styles.collapsibleContainer } | ||
> | ||
<div className={styles.collapsibleContent}>{children}</div> | ||
</Collapsible> | ||
</details> | ||
); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
|
||
|
||
/* This is used as a workaround to allow the find-in-page feature to work with collapsible content */ | ||
.collapsibleContainer { | ||
display: block !important; | ||
} | ||
|
||
.autoHeight { | ||
height: auto !important; | ||
} | ||
|
||
/* | ||
CSS variables, meant to be overridden by final theme | ||
*/ | ||
.details { | ||
--docusaurus-details-summary-arrow-size: 0.38rem; | ||
--docusaurus-details-transition: transform 200ms ease; | ||
--docusaurus-details-decoration-color: grey; | ||
} | ||
|
||
.details > summary { | ||
position: relative; | ||
cursor: pointer; | ||
list-style: none; | ||
padding-left: 1rem; | ||
} | ||
|
||
/* TODO: deprecation, need to remove this after Safari will support `::marker` */ | ||
.details > summary::-webkit-details-marker { | ||
display: none; | ||
} | ||
|
||
.details > summary::before { | ||
position: absolute; | ||
top: 0.45rem; | ||
left: 0; | ||
|
||
/* CSS-only Arrow */ | ||
content: ''; | ||
border-width: var(--docusaurus-details-summary-arrow-size); | ||
border-style: solid; | ||
border-color: transparent transparent transparent | ||
var(--docusaurus-details-decoration-color); | ||
|
||
/* Arrow rotation anim */ | ||
transform: rotate(0deg); | ||
transition: var(--docusaurus-details-transition); | ||
transform-origin: calc(var(--docusaurus-details-summary-arrow-size) / 2) 50%; | ||
} | ||
|
||
/* When JS disabled/failed to load: we use the open property for arrow animation: */ | ||
.details[open]:not(.isBrowser) > summary::before, | ||
/* When JS works: we use the data-attribute for arrow animation */ | ||
.details[data-collapsed='false'].isBrowser > summary::before { | ||
transform: rotate(90deg); | ||
} | ||
|
||
.collapsibleContent { | ||
margin-top: 1rem; | ||
border-top: 1px solid var(--docusaurus-details-decoration-color); | ||
padding-top: 1rem; | ||
} | ||
|
||
.collapsibleContent p:last-child { | ||
margin-bottom: 0; | ||
} | ||
|
||
.details > summary > p:last-child { | ||
margin-bottom: 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from 'react'; | ||
import clsx from 'clsx'; | ||
import {Details as DetailsGeneric} from '@site/src/components/Details'; | ||
import styles from './styles.module.css'; | ||
// Should we have a custom details/summary comp in Infima instead of reusing | ||
// alert classes? | ||
const InfimaClasses = 'alert alert--info'; | ||
export default function Details({...props}) { | ||
return ( | ||
<DetailsGeneric | ||
{...props} | ||
className={clsx(InfimaClasses, styles.details, props.className)} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.details { | ||
--docusaurus-details-decoration-color: var(--ifm-alert-border-color); | ||
--docusaurus-details-transition: transform var(--ifm-transition-fast) ease; | ||
margin: 0 0 var(--ifm-spacing-vertical); | ||
border: 1px solid var(--ifm-alert-border-color); | ||
} |
Oops, something went wrong.