Skip to content

Commit e120d2b

Browse files
authored
docs: Add matching details section in the docs (#72)
## Description Add matching details section in the docs ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [x] Documentation update (improves or adds clarity to existing documentation) ### Checklist - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have updated the documentation accordingly - [x] My changes generate no new warnings
1 parent 98cbe68 commit e120d2b

File tree

6 files changed

+184
-0
lines changed

6 files changed

+184
-0
lines changed

docs/src/theme/MDXComponents.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Import the original mapper
2+
import MDXComponents from '@theme-original/MDXComponents';
3+
4+
export default {
5+
// Re-use the default mapping
6+
...MDXComponents,
7+
};
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react';
2+
import DetailsStyling from '@site/src/theme/MDXComponents/DetailsStyling';
3+
4+
const MDXDetails = (props) => {
5+
const items = React.Children.toArray(props.children);
6+
// Split summary item from the rest to pass it as a separate prop to the
7+
// Details theme component
8+
const summary = items.find(
9+
(item) => React.isValidElement(item) && item.props?.mdxType === 'summary'
10+
);
11+
12+
const children = <>{items.filter((item) => item !== summary)}</>;
13+
return (
14+
<DetailsStyling {...props} summary={summary}>
15+
{children}
16+
</DetailsStyling>
17+
);
18+
};
19+
20+
export default MDXDetails;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { useCollapsible, Collapsible } from '@docusaurus/theme-common';
2+
3+
import clsx from 'clsx';
4+
import React from 'react';
5+
import { useRef, useState } from 'react';
6+
7+
import styles from './styles.module.css';
8+
import useIsBrowser from '@docusaurus/useIsBrowser';
9+
import ThemedImage from '@theme/ThemedImage';
10+
import useBaseUrl from '@docusaurus/useBaseUrl';
11+
12+
const DetailsStyling = ({ summary, children, ...props }): JSX.Element => {
13+
const isBrowser = useIsBrowser();
14+
const { collapsed, setCollapsed } = useCollapsible({
15+
initialState: !props.open,
16+
});
17+
18+
const arrowIcon = {
19+
light: useBaseUrl('/img/Arrow.svg'),
20+
dark: useBaseUrl('img/Arrow-dark.svg'),
21+
};
22+
23+
const detailsRef = useRef<HTMLDetailsElement>(null);
24+
const [open, setOpen] = useState(props.open);
25+
26+
// As we need to modify our own summary, we need to extract original content of summary
27+
const extractedSummaryElement = summary.props.children;
28+
29+
return (
30+
<details
31+
{...props}
32+
ref={detailsRef}
33+
open={open}
34+
data-collapsed={collapsed}
35+
className={clsx(
36+
styles.details,
37+
isBrowser && styles.isBrowser,
38+
props.className
39+
)}
40+
onMouseDown={(e) => {
41+
const target = e.target as HTMLElement;
42+
// Prevent a double-click to highlight summary text
43+
if (isInSummary(target) && e.detail > 1) {
44+
e.preventDefault();
45+
}
46+
}}
47+
onClick={(e) => {
48+
e.stopPropagation(); // For isolation of multiple nested details/summary
49+
const target = e.target as HTMLElement;
50+
const shouldToggle =
51+
isInSummary(target) && hasParent(target, detailsRef.current!);
52+
if (!shouldToggle) {
53+
return;
54+
}
55+
e.preventDefault();
56+
if (collapsed) {
57+
setCollapsed(false);
58+
setOpen(true);
59+
} else {
60+
setCollapsed(true);
61+
// Don't do this, it breaks close animation!
62+
// setOpen(false);
63+
}
64+
}}
65+
>
66+
<summary>
67+
<ThemedImage sources={arrowIcon} className={styles.arrow} />
68+
69+
<p>{extractedSummaryElement}</p>
70+
</summary>
71+
72+
<Collapsible
73+
lazy={false}
74+
collapsed={collapsed}
75+
disableSSRStyle
76+
onCollapseTransitionEnd={(newCollapsed) => {
77+
setCollapsed(newCollapsed);
78+
setOpen(!newCollapsed);
79+
}}
80+
>
81+
<div className={styles.collapsibleContent}>{children}</div>
82+
</Collapsible>
83+
</details>
84+
);
85+
};
86+
87+
function isInSummary(node: HTMLElement | null): boolean {
88+
if (!node) {
89+
return false;
90+
}
91+
return node.tagName === 'SUMMARY' || isInSummary(node.parentElement);
92+
}
93+
94+
function hasParent(node: HTMLElement | null, parent: HTMLElement): boolean {
95+
if (!node) {
96+
return false;
97+
}
98+
return node === parent || hasParent(node.parentElement, parent);
99+
}
100+
101+
export default DetailsStyling;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
.details {
2+
background-color: var(--swm-details-foreground);
3+
box-shadow: -8px 8px 0 var(--swm-details-background);
4+
5+
color: var(--swm-details-color);
6+
}
7+
8+
.details a {
9+
color: var(--swm-details-color);
10+
}
11+
12+
.details > summary {
13+
display: flex;
14+
align-items: center;
15+
cursor: pointer;
16+
list-style: none;
17+
padding: 1.5em 2em;
18+
}
19+
20+
.details > summary > p {
21+
margin: 0;
22+
}
23+
24+
/* TODO: deprecation, need to remove this after Safari will support `::marker` */
25+
.details > summary::-webkit-details-marker {
26+
display: none;
27+
}
28+
29+
.arrow {
30+
height: 12px;
31+
width: 12px;
32+
margin-right: 1.5rem;
33+
left: 0;
34+
35+
transition: var(--swm-expandable-transition);
36+
}
37+
38+
.details[open]:not(.isBrowser) > summary > .arrow,
39+
/* When JS works: we use the data-attribute for arrow animation */
40+
.details[data-collapsed='false'].isBrowser > summary > .arrow {
41+
transform: rotate(180deg);
42+
}
43+
44+
.collapsibleContent {
45+
padding: 0 2em 1.5em 2em;
46+
}
47+
48+
.collapsibleContent > *:last-child {
49+
margin-bottom: 0;
50+
}

docs/static/img/Arrow-dark.svg

+3
Loading

docs/static/img/Arrow.svg

+3
Loading

0 commit comments

Comments
 (0)