From e8d4567878756bf91ef82f213347aa69e0b923b2 Mon Sep 17 00:00:00 2001 From: PointerL <124577547+PointerL@users.noreply.github.com> Date: Mon, 26 Oct 2026 04:15:29 +0800 Subject: [PATCH] fix(site-components): initialize backtop visibility on connect --- .../src/__tests__/td-backtop.spec.ts | 74 +++++++++++++++++++ .../src/components/td-backtop/index.ts | 1 + 2 files changed, 75 insertions(+) create mode 100644 packages/site-components/src/__tests__/td-backtop.spec.ts diff --git a/packages/site-components/src/__tests__/td-backtop.spec.ts b/packages/site-components/src/__tests__/td-backtop.spec.ts new file mode 100644 index 000000000..8b0a5fb99 --- /dev/null +++ b/packages/site-components/src/__tests__/td-backtop.spec.ts @@ -0,0 +1,74 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import backtop from '../components/td-backtop'; + +const { mockDefine } = vi.hoisted(() => ({ + mockDefine: vi.fn((definition: unknown) => definition), +})); + +vi.mock('hybrids', () => ({ + define: mockDefine, + html: vi.fn(), +})); + +const backtopShow = backtop.backtopShow as unknown as { + connect: (host: { backtopShow: boolean }, key: string, invalidate: () => void) => () => void; +}; + +describe('td-backtop visibility', () => { + let originalScrollTop: number; + const cleanups: Array<() => void> = []; + + beforeEach(() => { + originalScrollTop = document.documentElement.scrollTop; + }); + + afterEach(() => { + cleanups.splice(0).forEach((cleanup) => cleanup()); + document.documentElement.scrollTop = originalScrollTop; + }); + + function connect(host: { backtopShow: boolean }) { + const cleanup = backtopShow.connect(host, 'backtopShow', vi.fn()); + cleanups.push(cleanup); + return cleanup; + } + + it('is visible immediately when mounted on a scrolled page', () => { + document.documentElement.scrollTop = 400; + const host = { backtopShow: false }; + + connect(host); + + expect(host.backtopShow).toBe(true); + }); + + it('starts hidden at the top and follows later scroll events', () => { + document.documentElement.scrollTop = 0; + const host = { backtopShow: true }; + + connect(host); + expect(host.backtopShow).toBe(false); + + document.documentElement.scrollTop = 1; + document.dispatchEvent(new Event('scroll')); + expect(host.backtopShow).toBe(true); + + document.documentElement.scrollTop = 0; + document.dispatchEvent(new Event('scroll')); + expect(host.backtopShow).toBe(false); + }); + + it('stops responding after cleanup and synchronizes on reconnect', () => { + document.documentElement.scrollTop = 0; + const host = { backtopShow: false }; + const cleanup = connect(host); + + cleanup(); + document.documentElement.scrollTop = 400; + document.dispatchEvent(new Event('scroll')); + expect(host.backtopShow).toBe(false); + + connect(host); + expect(host.backtopShow).toBe(true); + }); +}); diff --git a/packages/site-components/src/components/td-backtop/index.ts b/packages/site-components/src/components/td-backtop/index.ts index 8b04b8a24..a1d8e6065 100644 --- a/packages/site-components/src/components/td-backtop/index.ts +++ b/packages/site-components/src/components/td-backtop/index.ts @@ -25,6 +25,7 @@ export default define({ invalidate(); } document.addEventListener('scroll', toggleVisible); + toggleVisible(); return () => document.removeEventListener('scroll', toggleVisible); },