67 lines
2 KiB
TypeScript
67 lines
2 KiB
TypeScript
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
import styles from './FormGeneratorTable.module.css';
|
|
|
|
export interface ExpandableDetailRowProps {
|
|
open: boolean;
|
|
colSpan: number;
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
/**
|
|
* Table detail row with smooth expand/collapse (grid 0fr → 1fr).
|
|
* Stays mounted until the close animation finishes.
|
|
*/
|
|
export function ExpandableDetailRow({ open, colSpan, children }: ExpandableDetailRowProps) {
|
|
const [mounted, setMounted] = useState(open);
|
|
const [revealed, setRevealed] = useState(false);
|
|
const openRef = useRef(open);
|
|
openRef.current = open;
|
|
|
|
useEffect(() => {
|
|
if (open) {
|
|
setMounted(true);
|
|
const id = requestAnimationFrame(() => {
|
|
requestAnimationFrame(() => {
|
|
if (openRef.current) setRevealed(true);
|
|
});
|
|
});
|
|
return () => cancelAnimationFrame(id);
|
|
}
|
|
setRevealed(false);
|
|
const fallback = window.setTimeout(() => {
|
|
if (!openRef.current) setMounted(false);
|
|
}, 420);
|
|
return () => window.clearTimeout(fallback);
|
|
}, [open]);
|
|
|
|
const handleTransitionEnd = useCallback((e: React.TransitionEvent<HTMLDivElement>) => {
|
|
if (e.target !== e.currentTarget) return;
|
|
if (e.propertyName !== 'grid-template-rows') return;
|
|
if (!openRef.current) {
|
|
setMounted(false);
|
|
}
|
|
}, []);
|
|
|
|
if (!mounted) return null;
|
|
|
|
return (
|
|
<tr className={styles.expandedDetailRow}>
|
|
<td
|
|
colSpan={colSpan}
|
|
className={`${styles.expandedDetailCell} ${revealed ? styles.expandedDetailCellOpen : ''}`}
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<div
|
|
className={`${styles.expandedCollapsible} ${revealed ? styles.expandedCollapsibleOpen : ''}`}
|
|
onTransitionEnd={handleTransitionEnd}
|
|
>
|
|
<div className={styles.expandedCollapsibleInner}>
|
|
<div className={styles.expandedDetailInner}>{children}</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
);
|
|
}
|
|
|
|
export default ExpandableDetailRow;
|