Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

252 lines
6.8 KiB
TypeScript

import {
useCallback,
useEffect,
useLayoutEffect,
useRef,
useState,
type CSSProperties,
type JSX,
type ReactNode,
type TransitionEvent
} from "react";
interface CollapsibleRevealProps {
expanded: boolean;
children: ReactNode;
className?: string;
innerClassName?: string;
onHeightTransitionEnd?: () => void;
preMountOnIdle?: boolean;
}
export function CollapsibleReveal({
expanded,
children,
className,
innerClassName,
onHeightTransitionEnd,
preMountOnIdle = false
}: CollapsibleRevealProps): JSX.Element | null {
"use memo";
const [mounted, setMounted] = useState(expanded);
const [visible, setVisible] = useState(expanded);
const [height, setHeight] = useState<string>(expanded ? "auto" : "0px");
const rootRef = useRef<HTMLDivElement | null>(null);
const innerRef = useRef<HTMLDivElement | null>(null);
const heightRef = useRef(height);
const measuredHeightRef = useRef<number | null>(null);
const previousExpandedRef = useRef(expanded);
const heightTransitionPendingRef = useRef(false);
const setRootRef = useCallback(
(node: HTMLDivElement | null) => {
if (
rootRef.current !== null &&
node === null &&
heightTransitionPendingRef.current
) {
heightTransitionPendingRef.current = false;
onHeightTransitionEnd?.();
}
rootRef.current = node;
},
[onHeightTransitionEnd]
);
const setRevealHeight = useCallback((nextHeight: string) => {
heightRef.current = nextHeight;
setHeight(nextHeight);
}, []);
useLayoutEffect(() => {
if (!expanded || mounted) {
return undefined;
}
if (preMountOnIdle) {
setMounted(true);
return undefined;
}
let mountFrameStarted = false;
const animationFrame = requestAnimationFrame(() => {
mountFrameStarted = true;
setMounted(true);
});
return () => {
cancelAnimationFrame(animationFrame);
if (!mountFrameStarted) {
onHeightTransitionEnd?.();
}
};
}, [expanded, mounted, onHeightTransitionEnd, preMountOnIdle]);
useEffect(() => {
if (!preMountOnIdle || mounted || expanded) {
return undefined;
}
const mountCollapsedContent = () => setMounted(true);
if ("requestIdleCallback" in window) {
const idleCallbackId = window.requestIdleCallback(mountCollapsedContent, {
timeout: 600
});
return () => window.cancelIdleCallback(idleCallbackId);
}
const timeoutId = globalThis.setTimeout(mountCollapsedContent, 120);
return () => globalThis.clearTimeout(timeoutId);
}, [expanded, mounted, preMountOnIdle]);
useLayoutEffect(() => {
if (!mounted) {
return undefined;
}
const root = rootRef.current;
if (!root) {
return undefined;
}
const wasExpanded = previousExpandedRef.current;
previousExpandedRef.current = expanded;
if (expanded) {
if (wasExpanded && visible && height === "auto") {
return undefined;
}
heightTransitionPendingRef.current = true;
setVisible(false);
setRevealHeight("0px");
const animationFrame = requestAnimationFrame(() => {
const measured = Math.max(
root.scrollHeight,
innerRef.current?.scrollHeight ?? 0
);
measuredHeightRef.current = measured;
// Make the reveal accessible on the first measure frame even when
// children have not reported a measurable height yet.
setVisible(true);
setRevealHeight(measured > 0 ? `${measured}px` : "auto");
});
return () => {
cancelAnimationFrame(animationFrame);
};
}
if (!wasExpanded) {
heightTransitionPendingRef.current = false;
setVisible(false);
setRevealHeight("0px");
return undefined;
}
const renderedHeight = root.getBoundingClientRect().height;
const cachedHeight = measuredHeightRef.current;
const measuredHeight =
renderedHeight > 0 ? renderedHeight : (cachedHeight ?? root.scrollHeight);
measuredHeightRef.current = measuredHeight;
heightTransitionPendingRef.current = true;
setRevealHeight(`${measuredHeight}px`);
setVisible(false);
const animationFrame = requestAnimationFrame(() => {
setRevealHeight("0px");
});
return () => cancelAnimationFrame(animationFrame);
}, [expanded, mounted]);
useLayoutEffect(() => {
if (!mounted || !expanded || !visible) {
return undefined;
}
const root = rootRef.current;
const inner = innerRef.current;
if (!root || !inner || typeof ResizeObserver === "undefined") {
return undefined;
}
let animationFrame: number | null = null;
const resizeObserver = new ResizeObserver((entries) => {
const innerScrollHeight = inner.scrollHeight;
const nextHeight = Math.ceil(
innerScrollHeight > 0
? innerScrollHeight
: (entries[0]?.contentRect.height ?? 0)
);
const previousHeight = measuredHeightRef.current;
if (!nextHeight || previousHeight === nextHeight) {
return;
}
measuredHeightRef.current = nextHeight;
if (heightRef.current === "auto") {
return;
}
setRevealHeight(
`${previousHeight ?? root.getBoundingClientRect().height}px`
);
if (animationFrame !== null) {
cancelAnimationFrame(animationFrame);
}
animationFrame = requestAnimationFrame(() => {
setRevealHeight(`${nextHeight}px`);
});
});
resizeObserver.observe(inner);
return () => {
if (animationFrame !== null) {
cancelAnimationFrame(animationFrame);
}
resizeObserver.disconnect();
};
}, [expanded, mounted, setRevealHeight, visible]);
if (!mounted) {
return null;
}
const handleTransitionEnd = (event: TransitionEvent<HTMLDivElement>) => {
if (
event.target !== event.currentTarget ||
(event.propertyName ? event.propertyName !== "height" : false)
) {
return;
}
if (visible) {
setRevealHeight("auto");
} else if (!expanded && !preMountOnIdle) {
setMounted(false);
}
if (heightTransitionPendingRef.current) {
heightTransitionPendingRef.current = false;
onHeightTransitionEnd?.();
}
};
const rootStyle: CSSProperties = { height };
return (
<div
ref={setRootRef}
className={["agent-collapsible-reveal", className ?? ""]
.filter(Boolean)
.join(" ")}
data-expanded={
preMountOnIdle && expanded ? "true" : visible ? "true" : "false"
}
aria-hidden={visible ? undefined : true}
style={rootStyle}
onTransitionEnd={handleTransitionEnd}
>
<div
ref={innerRef}
className={["agent-collapsible-reveal__inner", innerClassName ?? ""]
.filter(Boolean)
.join(" ")}
>
{children}
</div>
</div>
);
}