Commit 8f322a05 by Xianquan Committed by GitHub

fix: agent v2 plan select expand/fold animation (#7181)

* fix: agent v2 plan select expand/fold animation

* pro submodule
parent 4bdf7471
Subproject commit 9a950b77868f43a056f996ee78ab0099f1de12a2 Subproject commit b4fea0a55abc616d4a3f3cdb2bb0a6e9adf81a52
...@@ -38,7 +38,8 @@ const RenderAgentPlanAskInteractive = React.memo(function RenderAgentPlanAskInte ...@@ -38,7 +38,8 @@ const RenderAgentPlanAskInteractive = React.memo(function RenderAgentPlanAskInte
selectedAnswerPlacement, selectedAnswerPlacement,
shouldShowOptions, shouldShowOptions,
scheduleCollapse, scheduleCollapse,
toggleOptionsExpanded toggleOptionsExpanded,
handleOptionsCollapseExited
} = useInteractiveChoiceCollapse(effectiveAnswer); } = useInteractiveChoiceCollapse(effectiveAnswer);
const showOtherInput = !!answeredOther || isOtherSelected; const showOtherInput = !!answeredOther || isOtherSelected;
const radioValue = const radioValue =
...@@ -93,13 +94,17 @@ const RenderAgentPlanAskInteractive = React.memo(function RenderAgentPlanAskInte ...@@ -93,13 +94,17 @@ const RenderAgentPlanAskInteractive = React.memo(function RenderAgentPlanAskInte
)} )}
<Collapse <Collapse
in={shouldShowOptions} in={shouldShowOptions}
animateOpacity onTransitionEnd={() => {
if (!shouldShowOptions) {
handleOptionsCollapseExited();
}
}}
transitionEnd={{ transitionEnd={{
enter: { overflow: 'visible' }, enter: { overflow: 'visible' },
exit: { overflow: 'hidden' } exit: { overflow: 'visible' }
}} }}
> >
<Flex w={'360px'} maxW={'100%'} flexDirection={'column'} gap={3}> <Flex w={'360px'} maxW={'100%'} flexDirection={'column'} gap={3} p={'3px'} mx={'-3px'}>
<LeftRadio<string> <LeftRadio<string>
px={4} px={4}
py={4} py={4}
......
...@@ -9,28 +9,25 @@ type SelectedAnswerPlacement = 'above' | 'below'; ...@@ -9,28 +9,25 @@ type SelectedAnswerPlacement = 'above' | 'below';
* 选中后先保留选项 1 秒用于反馈,再折叠为答案摘要;刷新后如果已有答案则默认折叠。 * 选中后先保留选项 1 秒用于反馈,再折叠为答案摘要;刷新后如果已有答案则默认折叠。
*/ */
export const useInteractiveChoiceCollapse = (selectedAnswer?: string) => { export const useInteractiveChoiceCollapse = (selectedAnswer?: string) => {
const [isOptionsExpanded, setIsOptionsExpanded] = React.useState(!selectedAnswer);
const [selectedAnswerPlacement, setSelectedAnswerPlacement] =
React.useState<SelectedAnswerPlacement>(selectedAnswer ? 'above' : 'below');
const collapseTimerRef = React.useRef<ReturnType<typeof setTimeout>>(); const collapseTimerRef = React.useRef<ReturnType<typeof setTimeout>>();
const placementTimerRef = React.useRef<ReturnType<typeof setTimeout>>(); const [internalExpanded, setInternalExpanded] = React.useState(() => !selectedAnswer);
const [internalPlacement, setInternalPlacement] = React.useState<SelectedAnswerPlacement>(() =>
selectedAnswer ? 'above' : 'below'
);
// 无答案时直接派生默认展示,避免在 effect 里同步 setState 触发额外渲染。
const isOptionsExpanded = selectedAnswer ? internalExpanded : true;
const selectedAnswerPlacement = selectedAnswer ? internalPlacement : 'below';
const clearCollapseTimers = React.useCallback(() => { const clearCollapseTimers = React.useCallback(() => {
if (collapseTimerRef.current) { if (collapseTimerRef.current) {
clearTimeout(collapseTimerRef.current); clearTimeout(collapseTimerRef.current);
collapseTimerRef.current = undefined; collapseTimerRef.current = undefined;
} }
if (placementTimerRef.current) {
clearTimeout(placementTimerRef.current);
placementTimerRef.current = undefined;
}
}, []); }, []);
React.useEffect(() => { React.useEffect(() => {
if (!selectedAnswer) { if (!selectedAnswer) {
clearCollapseTimers(); clearCollapseTimers();
setIsOptionsExpanded(true);
setSelectedAnswerPlacement('below');
} }
}, [clearCollapseTimers, selectedAnswer]); }, [clearCollapseTimers, selectedAnswer]);
...@@ -42,30 +39,34 @@ export const useInteractiveChoiceCollapse = (selectedAnswer?: string) => { ...@@ -42,30 +39,34 @@ export const useInteractiveChoiceCollapse = (selectedAnswer?: string) => {
const scheduleCollapse = React.useCallback(() => { const scheduleCollapse = React.useCallback(() => {
clearCollapseTimers(); clearCollapseTimers();
setSelectedAnswerPlacement('below'); setInternalPlacement('below');
setIsOptionsExpanded(true); setInternalExpanded(true);
collapseTimerRef.current = setTimeout(() => { collapseTimerRef.current = setTimeout(() => {
setIsOptionsExpanded(false); setInternalExpanded(false);
collapseTimerRef.current = undefined; collapseTimerRef.current = undefined;
placementTimerRef.current = setTimeout(() => {
setSelectedAnswerPlacement('above');
placementTimerRef.current = undefined;
}, 240);
}, 1000); }, 1000);
}, [clearCollapseTimers]); }, [clearCollapseTimers]);
const toggleOptionsExpanded = React.useCallback(() => { const toggleOptionsExpanded = React.useCallback(() => {
clearCollapseTimers(); clearCollapseTimers();
setSelectedAnswerPlacement('above'); setInternalPlacement('above');
setIsOptionsExpanded((state) => !state); setInternalExpanded((state) => !state);
}, [clearCollapseTimers]); }, [clearCollapseTimers]);
/** 选项区域收起动画结束后,将答案摘要移到选项上方,避免与硬编码动画时长不同步。 */
const handleOptionsCollapseExited = React.useCallback(() => {
if (selectedAnswer) {
setInternalPlacement('above');
}
}, [selectedAnswer]);
return { return {
isOptionsExpanded, isOptionsExpanded,
selectedAnswerPlacement, selectedAnswerPlacement,
shouldShowOptions: !selectedAnswer || isOptionsExpanded, shouldShowOptions: !selectedAnswer || isOptionsExpanded,
scheduleCollapse, scheduleCollapse,
toggleOptionsExpanded toggleOptionsExpanded,
handleOptionsCollapseExited
}; };
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment