mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-22 08:25:21 +08:00
fix(ui): prevent closing selects from stealing focus
Preserve focus when another control becomes active during the close animation. Add regression tests for filter persistence, Escape, and custom range dialog focus.
This commit is contained in:
@@ -52,6 +52,7 @@ function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = 'popper',
|
||||
onCloseAutoFocus,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
@@ -66,6 +67,19 @@ function SelectContent({
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
onCloseAutoFocus={(event) => {
|
||||
onCloseAutoFocus?.(event);
|
||||
if (event.defaultPrevented) return;
|
||||
const content = event.target as HTMLElement;
|
||||
const activeElement = content.ownerDocument.activeElement;
|
||||
// Exit animations may finish after another control has taken focus.
|
||||
if (
|
||||
activeElement &&
|
||||
activeElement !== content.ownerDocument.body &&
|
||||
!content.contains(activeElement)
|
||||
)
|
||||
event.preventDefault();
|
||||
}}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
|
||||
@@ -575,6 +575,35 @@ test('shares mode and status filters with dashboard charts and records', async (
|
||||
}
|
||||
});
|
||||
|
||||
test('restores filter trigger focus when closing with Escape', async ({
|
||||
page,
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, { authenticated: true });
|
||||
await page.goto('/home/monitoring');
|
||||
for (const id of ['bot', 'mode', 'status', 'time']) {
|
||||
const trigger = page.locator(`#monitoring-filter-${id}`);
|
||||
await trigger.click();
|
||||
await expect(page.getByRole('listbox')).toBeVisible();
|
||||
await page.keyboard.press('Escape');
|
||||
await expect(trigger).toBeFocused();
|
||||
await expect(page.getByRole('listbox')).toHaveCount(0);
|
||||
}
|
||||
});
|
||||
|
||||
test('keeps the custom range dialog focused when its select closes', async ({
|
||||
page,
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, { authenticated: true });
|
||||
await page.goto('/home/monitoring');
|
||||
await page.locator('#monitoring-filter-time').click();
|
||||
await page
|
||||
.getByRole('option', { name: 'Custom time range', exact: true })
|
||||
.click();
|
||||
const dialog = page.getByRole('dialog', { name: 'Custom time range' });
|
||||
await expect(dialog).toBeVisible();
|
||||
await expect(dialog.locator('input').first()).toBeFocused();
|
||||
});
|
||||
|
||||
test('remembers all filters on reload and persists resetting them', async ({
|
||||
page,
|
||||
}) => {
|
||||
|
||||
Reference in New Issue
Block a user