mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
feat: flash the settings section a jump-row button scrolls to
This commit is contained in:
@@ -93,6 +93,24 @@ describe('settings section links', () => {
|
||||
expect(scrolled).toContain('tags');
|
||||
});
|
||||
|
||||
it('flashes the section a jump-row button scrolls to', async () => {
|
||||
const { container } = render(<SettingsApp linkSegments={['organize']} />);
|
||||
const nav = screen.getByTestId('settings-section-nav');
|
||||
await waitFor(() => expect(nav).not.toHaveAttribute('hidden'));
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Tags' }));
|
||||
const tags = container.querySelector('[data-settings-section="tags"]')!;
|
||||
const folders = container.querySelector('[data-settings-section="folders"]')!;
|
||||
expect(tags).toHaveClass('settings-search-highlight');
|
||||
expect(folders).not.toHaveClass('settings-search-highlight');
|
||||
act(() => { vi.advanceTimersByTime(1800); });
|
||||
expect(tags).not.toHaveClass('settings-search-highlight');
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it('follows a tab-change event that names a retired tab to its new section', async () => {
|
||||
render(<SettingsApp linkSegments={[]} />);
|
||||
act(() => { window.dispatchEvent(new CustomEvent('settings-tab-change', { detail: 'identities' })); });
|
||||
|
||||
@@ -96,11 +96,25 @@ export function AdvancedOnly({ children }: { children: ReactNode }) {
|
||||
return visible ? <>{children}</> : null;
|
||||
}
|
||||
|
||||
/** Scrolls the section with this id into view, if the open page has it. */
|
||||
const highlightTimers = new WeakMap<HTMLElement, ReturnType<typeof setTimeout>>();
|
||||
|
||||
/**
|
||||
* Scrolls the section with this id into view, if the open page has it, and
|
||||
* flashes the same halo a settings search result gets.
|
||||
*/
|
||||
export function scrollToSettingsSection(id: string, root: ParentNode = document): boolean {
|
||||
const el = root.querySelector<HTMLElement>(`[data-settings-section="${id.replace(/"/g, '\\"')}"]`);
|
||||
if (!el) return false;
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
// Remove + reflow + add restarts the animation on a second click.
|
||||
clearTimeout(highlightTimers.get(el));
|
||||
el.classList.remove('settings-search-highlight');
|
||||
void el.offsetWidth;
|
||||
el.classList.add('settings-search-highlight');
|
||||
highlightTimers.set(el, setTimeout(() => {
|
||||
el.classList.remove('settings-search-highlight');
|
||||
highlightTimers.delete(el);
|
||||
}, 1800));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user