Reset home scroll on plugin use (#3757)

This commit is contained in:
Ray Xi
2026-06-05 14:43:00 +00:00
committed by GitHub
parent addf34bbf6
commit 2db4c1b23b
3 changed files with 49 additions and 10 deletions
+17 -1
View File
@@ -438,6 +438,7 @@ export function EntryShell({
useState<CreateTab>('prototype');
const [integrationTab, setIntegrationTab] = useState<IntegrationTab>(integrationInitialTab);
const [homePromptHandoff, setHomePromptHandoff] = useState<HomePromptHandoff | null>(null);
const entryMainScrollRef = useRef<HTMLElement | null>(null);
const analytics = useAnalytics();
const discordOnlineLabel = discordPresence
? t('entry.discordOnlineLabel', {
@@ -476,6 +477,21 @@ export function EntryShell({
changeView('home');
}
useEffect(() => {
if (view !== 'home' || !homePromptHandoff) return;
const frame = window.requestAnimationFrame(() => {
const scrollContainer = entryMainScrollRef.current;
if (!scrollContainer) return;
if (typeof scrollContainer.scrollTo === 'function') {
scrollContainer.scrollTo({ top: 0, left: 0 });
return;
}
scrollContainer.scrollTop = 0;
scrollContainer.scrollLeft = 0;
});
return () => window.cancelAnimationFrame(frame);
}, [homePromptHandoff?.id, view]);
useEffect(() => {
setIntegrationTab(integrationInitialTab);
}, [integrationInitialTab]);
@@ -638,7 +654,7 @@ export function EntryShell({
open={railOpen}
onClose={() => setRailOpen(false)}
/>
<main className="entry-main entry-main--scroll">
<main className="entry-main entry-main--scroll" ref={entryMainScrollRef}>
<div className="entry-main__topbar">
<button
type="button"
+18 -2
View File
@@ -317,9 +317,22 @@ export function HomeView({
});
}, [pendingReplacement, analytics.track]);
const inputRef = useRef<HomeHeroHandle | null>(null);
const homeViewRef = useRef<HTMLDivElement | null>(null);
const consumedHandoffIdRef = useRef<number | null>(null);
const pendingPromptFocusEndRef = useRef(false);
const activePluginApplyRequestRef = useRef(0);
const scrollHomeToTop = useCallback(() => {
requestAnimationFrame(() => {
const scrollContainer = homeViewRef.current?.closest('.entry-main--scroll');
if (!(scrollContainer instanceof HTMLElement)) return;
if (typeof scrollContainer.scrollTo === 'function') {
scrollContainer.scrollTo({ top: 0, left: 0 });
} else {
scrollContainer.scrollTop = 0;
scrollContainer.scrollLeft = 0;
}
});
}, []);
const importSkillId = useMemo(() => {
const prototypeSkills = skills.filter((skill) => skill.mode === 'prototype');
return prototypeSkills.find((skill) => skill.defaultFor.includes('prototype'))?.id
@@ -459,6 +472,7 @@ export function HomeView({
if (promptHandoff.focus) {
focusPromptAtEnd();
}
scrollHomeToTop();
return;
}
@@ -478,7 +492,8 @@ export function HomeView({
setPendingAuthoringInputs(promptHandoff.inputs);
setPendingAuthoringChipId('create-plugin');
setPendingChipId('create-plugin');
}, [promptHandoff]);
scrollHomeToTop();
}, [promptHandoff, scrollHomeToTop]);
const activeContextItemCount = useMemo(
() =>
@@ -847,6 +862,7 @@ export function HomeView({
setError(null);
setDetailsRecord(null);
if (shouldFocusOnly) focusPromptAtEnd();
scrollHomeToTop();
}
function runWithReplacementConfirmation(
@@ -1438,7 +1454,7 @@ export function HomeView({
}
return (
<div className="home-view" data-testid="home-view">
<div className="home-view" data-testid="home-view" ref={homeViewRef}>
<HomeHero
ref={inputRef}
prompt={prompt}
@@ -87,16 +87,20 @@ describe('HomeView plugin i18n', () => {
});
vi.stubGlobal('fetch', fetchMock);
render(
const view = render(
<I18nProvider initial="zh-CN">
<HomeView
projects={[]}
onSubmit={() => undefined}
onOpenProject={() => undefined}
onViewAllProjects={() => undefined}
/>
<div className="entry-main--scroll">
<HomeView
projects={[]}
onSubmit={() => undefined}
onOpenProject={() => undefined}
onViewAllProjects={() => undefined}
/>
</div>
</I18nProvider>,
);
const scrollContainer = view.container.querySelector('.entry-main--scroll') as HTMLElement;
scrollContainer.scrollTop = 240;
fireEvent.click(await waitFor(() => screen.getByTestId('plugins-home-use-localized-plugin')));
@@ -114,6 +118,9 @@ describe('HomeView plugin i18n', () => {
await screen.findByTestId('home-hero-input');
expect(homeHeroPromptText().trim()).toBe('');
expect(fetchMock.mock.calls.some(([url]) => String(url).includes('/apply'))).toBe(false);
await waitFor(() => {
expect(scrollContainer.scrollTop).toBe(0);
});
});
it('hydrates the Home prompt with the localized plugin query', async () => {