Skip to content

Commit 6dfa88e

Browse files
Kirill BolotskyPepe Cano
authored andcommitted
refactor(components): this commit reverses code blocks toggler mechanism behavior
- prop `isInitiallyExpanded` doesn't make sense anymore, so it is renamed to `heightTogglers` in CodeGroup and `showHeightToggler` in Code components - toggler logic abstracted to custom hook
1 parent 073f68c commit 6dfa88e

File tree

6 files changed

+78
-33
lines changed

6 files changed

+78
-33
lines changed

CONTRIBUTING_FILE_FORMAT.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -326,26 +326,28 @@ See _'Then do this?'_ text line between tabs? **You can not do that**. Put nothi
326326

327327
</CodeGroup>
328328

329-
#### State control
329+
#### Height control
330330

331-
Large code blocks (>400px) by default have a collapsed state, i.e. have a max-height prop of `400px` and user can change their behavior via toggler:
331+
You can provide large code blocks (>400px, ~20 LoC) with expand/collapse toggler that will allow users to control code block's height.
332332

333333
![Code Block States](internal-images/code-block-states.png)
334334

335-
If you are using `CodeGroup` wrapper you can specify the initial state of code blocks via `isInitiallyExpanded` prop which works very similarly to the other available props:
335+
Prop `heightTogglers` passed to `CodeGroup` component makes it possible, which works very similar to `labels` and `lineNumbers` props:
336336

337-
<CodeGroup labels={["Nice code!", "This one is better", "Oh my.."]} lineNumbers={[true, true, true]} isInitiallyExpanded=[true, false, false]>
337+
<CodeGroup labels={["Nice code!", "This one is better", "Oh my.."]} lineNumbers={[true, true, true]} heightTogglers=[true, false, false]>
338338

339339
```javascript
340-
// a lot of lines of important code
340+
// a lot of lines of code,
341+
// maxHeight of this code block will be set to `400px`
342+
// and a toggler will appear
341343
```
342344

343345
```javascript
344-
// a lot of lines of not so important code
346+
// a lot of lines of code, default behavior
345347
```
346348

347349
```javascript
348-
// a lot of lines of not so important code
350+
// a lot of lines of code, default behavior
349351
```
350352

351353

src/components/shared/code/code-group.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getRandomKey } from 'utils';
55
import Code from './code';
66
import styles from './code-group.module.scss';
77

8-
const CodeGroup = ({ children, labels, lineNumbers }) => {
8+
const CodeGroup = ({ children, labels, lineNumbers, heightTogglers }) => {
99
const [currentIndex, setCurrentIndex] = useState(0);
1010
const randomKey = getRandomKey();
1111
return (
@@ -35,7 +35,11 @@ const CodeGroup = ({ children, labels, lineNumbers }) => {
3535
</style>
3636
<div className={`${styles.itemsContainer} ${randomKey}`}>
3737
{React.Children.map(children, (child, i) => (
38-
<Code showLineNumbers={lineNumbers[i]} key={i}>
38+
<Code
39+
showLineNumbers={lineNumbers[i]}
40+
key={i}
41+
showHeightToggler={heightTogglers[i]}
42+
>
3943
{child.props.children}
4044
</Code>
4145
))}
@@ -48,12 +52,14 @@ CodeGroup.propTypes = {
4852
children: PropTypes.node,
4953
labels: PropTypes.arrayOf(PropTypes.string),
5054
lineNumbers: PropTypes.arrayOf(PropTypes.bool),
55+
heightTogglers: PropTypes.arrayOf(PropTypes.bool),
5156
};
5257

5358
CodeGroup.defaultProps = {
5459
children: null,
5560
labels: [],
5661
lineNumbers: [],
62+
heightTogglers: [],
5763
};
5864

5965
export default CodeGroup;

src/components/shared/code/code.js

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,41 @@
11
import classNames from 'classnames';
22
import { WithCopyButton } from 'components/shared/with-copy-button';
3+
import { useCodeBlockHeightToggler } from 'hooks';
34
import Highlight, { defaultProps } from 'prism-react-renderer';
45
import PropTypes from 'prop-types';
5-
import React, { useEffect, useState, useRef } from 'react';
6+
import React, { useRef } from 'react';
67

78
import styles from './code.module.scss';
89

9-
const Code = ({ children, showLineNumbers, isInitiallyExpanded }) => {
10+
const DEFAULT_HEIGHT = `100%`;
11+
const MAX_HEIGHT = 400;
12+
13+
const Code = ({ children, showLineNumbers, showHeightToggler }) => {
1014
if (!children) return null;
11-
const [isExpanded, setIsExpanded] = useState(true);
12-
const [height, setHeight] = useState('100%');
15+
1316
const containerRef = useRef(null);
14-
const toggleHandler = () => setIsExpanded((prev) => !prev);
1517

16-
useEffect(() => {
17-
if (containerRef?.current) {
18-
const computedHeight = containerRef.current.offsetHeight;
19-
if (computedHeight > 420) {
20-
setHeight(computedHeight);
21-
}
22-
}
23-
if (!isInitiallyExpanded) {
24-
setIsExpanded(false);
25-
}
26-
}, [containerRef]);
18+
const { toggleHandler, height, isExpanded } = useCodeBlockHeightToggler({
19+
ref: containerRef,
20+
defaultHeight: DEFAULT_HEIGHT,
21+
maxHeight: MAX_HEIGHT,
22+
isEnabled: showHeightToggler,
23+
});
2724

2825
let toggler = null;
29-
if (height !== '100%') {
26+
let containerStyles = {};
27+
// if `height` isn't equla default height,
28+
// code blocks fits the height requirements
29+
// for toggler to be shown
30+
if (height !== DEFAULT_HEIGHT) {
3031
toggler = (
3132
<button className={styles.toggler} type="button" onClick={toggleHandler}>
3233
{isExpanded ? 'Collapse' : 'Expand'}
3334
</button>
3435
);
36+
containerStyles = {
37+
maxHeight: isExpanded ? height : `${MAX_HEIGHT}px`,
38+
};
3539
}
3640

3741
return (
@@ -45,10 +49,7 @@ const Code = ({ children, showLineNumbers, isInitiallyExpanded }) => {
4549
<pre
4650
className={classNames(className, styles.code, styles.codeContainer)}
4751
ref={containerRef}
48-
style={{
49-
transition: 'max-height .2s ease',
50-
maxHeight: isExpanded ? height : '400px',
51-
}}
52+
style={containerStyles}
5253
>
5354
<code className={styles.code}>
5455
{tokens.map((line, i) => {
@@ -81,13 +82,13 @@ const Code = ({ children, showLineNumbers, isInitiallyExpanded }) => {
8182
Code.propTypes = {
8283
children: PropTypes.node,
8384
showLineNumbers: PropTypes.bool,
84-
isInitiallyExpanded: PropTypes.bool,
85+
showHeightToggler: PropTypes.bool,
8586
};
8687

8788
Code.defaultProps = {
8889
children: null,
8990
showLineNumbers: false,
90-
isInitiallyExpanded: false,
91+
showHeightToggler: false,
9192
};
9293

9394
export default Code;

src/components/shared/code/code.module.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
height: 100%;
44
overflow-y: auto;
55
text-align: left;
6+
transition: max-height 0.2s ease-in-out;
67
@include no-scrollbars;
78
}
89

src/hooks/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
import useCodeBlockHeightToggler from './use-code-block-height-toggler';
12
import useElementsReplacement from './use-elements-replacement';
23
import useLandmark from './use-landmark';
34
import useScrollToAnchor from './use-scroll-to-anchor';
45

5-
export { useLandmark, useScrollToAnchor, useElementsReplacement };
6+
export {
7+
useLandmark,
8+
useScrollToAnchor,
9+
useElementsReplacement,
10+
useCodeBlockHeightToggler,
11+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useEffect, useState } from 'react';
2+
3+
const useCodeBlockHeightToggler = ({
4+
ref,
5+
defaultHeight,
6+
maxHeight,
7+
isEnabled,
8+
}) => {
9+
const [isExpanded, setIsExpanded] = useState(false);
10+
const [height, setHeight] = useState(defaultHeight);
11+
12+
const toggleHandler = () => setIsExpanded((prev) => !prev);
13+
14+
useEffect(() => {
15+
if (ref?.current && isEnabled) {
16+
const computedHeight = ref.current.offsetHeight;
17+
// add a little margin to maxHeight
18+
// to prevent showing toggler in blocks
19+
// which height is just about maxHeight,
20+
// therefore very little moving during toggle action
21+
if (computedHeight > maxHeight + 20) {
22+
setHeight(`${computedHeight}px`);
23+
}
24+
}
25+
}, [ref, isEnabled]);
26+
return { toggleHandler, isExpanded, height };
27+
};
28+
29+
export default useCodeBlockHeightToggler;

0 commit comments

Comments
 (0)