2024-02-02 01:38:58 -08:00
|
|
|
import clsx from 'clsx';
|
|
|
|
|
import { HTMLAttributes, ReactNode, useRef, useState } from 'react';
|
2024-02-01 03:58:36 -08:00
|
|
|
import styles from './spoiler.module.scss';
|
2024-02-02 01:38:58 -08:00
|
|
|
import { useIsOverflow } from '/@/renderer/hooks';
|
2024-02-01 03:58:36 -08:00
|
|
|
|
2024-02-02 01:38:58 -08:00
|
|
|
interface SpoilerProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
|
|
children?: ReactNode;
|
|
|
|
|
defaultOpened?: boolean;
|
|
|
|
|
maxHeight?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const Spoiler = ({ maxHeight, defaultOpened, children, ...props }: SpoilerProps) => {
|
|
|
|
|
const ref = useRef(null);
|
|
|
|
|
const isOverflow = useIsOverflow(ref);
|
|
|
|
|
const [isExpanded, setIsExpanded] = useState(!!defaultOpened);
|
|
|
|
|
|
|
|
|
|
const spoilerClassNames = clsx(styles.spoiler, {
|
|
|
|
|
[styles.canExpand]: isOverflow,
|
|
|
|
|
[styles.isExpanded]: isExpanded,
|
|
|
|
|
});
|
2024-02-01 03:58:36 -08:00
|
|
|
|
2024-02-02 01:38:58 -08:00
|
|
|
const handleToggleExpand = () => {
|
|
|
|
|
setIsExpanded((val) => !val);
|
|
|
|
|
};
|
2024-02-01 03:58:36 -08:00
|
|
|
|
|
|
|
|
return (
|
2024-02-02 01:38:58 -08:00
|
|
|
<div
|
|
|
|
|
ref={ref}
|
|
|
|
|
className={spoilerClassNames}
|
|
|
|
|
role="button"
|
2024-09-11 07:41:15 -07:00
|
|
|
style={{ maxHeight: maxHeight ?? '100px', whiteSpace: 'pre-wrap' }}
|
2024-02-02 01:38:58 -08:00
|
|
|
tabIndex={-1}
|
|
|
|
|
onClick={handleToggleExpand}
|
|
|
|
|
{...props}
|
2024-02-01 03:58:36 -08:00
|
|
|
>
|
|
|
|
|
{children}
|
2024-02-02 01:38:58 -08:00
|
|
|
</div>
|
2024-02-01 03:58:36 -08:00
|
|
|
);
|
|
|
|
|
};
|