2.0 KB62 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {ReactNode} from 'react';
9
10import {Button} from 'isl-components/Button';
11import {Icon} from 'isl-components/Icon';
12import {useLayoutEffect, useRef, useState} from 'react';
13import {T} from '../i18n';
14
15import './SeeMoreContainer.css';
16
17const MAX_NON_EXPANDBLE_HEIGHT_PX = 375;
18
19export function SeeMoreContainer({
20 children,
21 maxHeight = MAX_NON_EXPANDBLE_HEIGHT_PX,
22 className,
23}: {
24 children: ReactNode;
25 maxHeight?: number;
26 className?: string;
27}) {
28 const ref = useRef<null | HTMLDivElement>(null);
29 const [shouldShowExpandButton, setShouldShowExpandbutton] = useState(false);
30 const [isExpanded, setIsExpanded] = useState(false);
31
32 useLayoutEffect(() => {
33 const element = ref.current;
34 if (element != null && element.scrollHeight > maxHeight) {
35 shouldShowExpandButton === false && setShouldShowExpandbutton(true);
36 } else {
37 shouldShowExpandButton === true && setShouldShowExpandbutton(false);
38 }
39 // Weird: we pass children to trick it to rerun this effect when the selected commit changes
40 // We could also do this by passing a new key to <SeeMoreContainer> in the caller
41 }, [ref, shouldShowExpandButton, children, maxHeight]);
42
43 return (
44 <div className={'see-more-container ' + (className ?? '')}>
45 <div
46 className={`see-more-container-${isExpanded ? 'expanded' : 'collapsed'}`}
47 ref={ref}
48 style={{maxHeight: isExpanded ? undefined : maxHeight}}>
49 {children}
50 </div>
51 {shouldShowExpandButton ? (
52 <div className={`see-${isExpanded ? 'less' : 'more'}-button`}>
53 <Button icon onClick={() => setIsExpanded(val => !val)}>
54 <Icon icon={isExpanded ? 'fold-up' : 'fold-down'} slot="start" />
55 {isExpanded ? <T>See less</T> : <T>See more</T>}
56 </Button>
57 </div>
58 ) : null}
59 </div>
60 );
61}
62