Skip to content

Commit 7ac1e59

Browse files
committed
fix(chat): handle native focus and touch resize gestures
1 parent fad6186 commit 7ac1e59

3 files changed

Lines changed: 56 additions & 2 deletions

File tree

‎apps/desktop/e2e/chat-panel.spec.ts‎

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ test('chat panel sizes survive navigation, chat switches, collapse, and layout c
113113
})
114114
const shell = app
115115
const page = await shell.firstWindow()
116+
const inputSession = await page.context().newCDPSession(page)
117+
// Playwright otherwise keeps the document focused when its native window loses focus.
118+
await inputSession.send('Emulation.setFocusEmulationEnabled', { enabled: false })
116119
page.on('pageerror', (error) => errors.push(error.message))
117120
page.on('crash', () => {
118121
rendererCrashed = true
@@ -267,7 +270,8 @@ test('chat panel sizes survive navigation, chat switches, collapse, and layout c
267270
await divider.evaluate((element) => element.releasePointerCapture(1))
268271
await page.mouse.move(rect.x + 100, rect.y + 100)
269272
} else if (interruption === 'blur') {
270-
await page.evaluate(() => window.dispatchEvent(new Event('blur')))
273+
await shell.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].blur())
274+
await expect.poll(() => page.evaluate(() => document.hasFocus())).toBe(false)
271275
} else if (interruption === 'chat switch') {
272276
await page
273277
.getByRole('button', { name: 'organization-chat-a', exact: true })
@@ -279,6 +283,18 @@ test('chat panel sizes survive navigation, chat switches, collapse, and layout c
279283
.evaluate((element: HTMLButtonElement) => element.click())
280284
await expect(panel).toHaveCount(0)
281285
}
286+
if (keepsDraggedWidth) {
287+
await expectWidth(598)
288+
expect(await page.evaluate(() => JSON.stringify(localStorage))).not.toBe(before)
289+
if (interruption === 'blur') {
290+
await shell.evaluate(({ app, BrowserWindow }) => {
291+
app.focus({ steal: true })
292+
BrowserWindow.getAllWindows()[0].focus()
293+
})
294+
}
295+
await page.mouse.move(rect.x + 150, rect.y + 100)
296+
await expectWidth(598)
297+
}
282298
await page.mouse.up()
283299
if (interruption === 'chat switch') {
284300
await page.getByRole('button', { name: 'workspace-chat-b', exact: true }).click()
@@ -299,6 +315,43 @@ test('chat panel sizes survive navigation, chat switches, collapse, and layout c
299315
)
300316
}
301317

318+
for (const button of ['middle', 'right'] as const) {
319+
await check(`${button}-button drags leave the panel width unchanged`, async () => {
320+
const before = await page.evaluate(() => JSON.stringify(localStorage))
321+
await divider.hover({ position: { x: 4, y: 100 } })
322+
const rect = await panel.boundingBox()
323+
if (!rect) throw new Error('Missing panel bounds')
324+
await page.mouse.down({ button })
325+
await page.mouse.move(rect.x + 100, rect.y + 100, { steps: 12 })
326+
await page.mouse.up({ button })
327+
await expectWidth(698)
328+
expect(await page.evaluate(() => JSON.stringify(localStorage))).toBe(before)
329+
})
330+
}
331+
332+
await check('a touch drag resizes the panel without becoming a scroll gesture', async () => {
333+
const rect = await panel.boundingBox()
334+
if (!rect) throw new Error('Missing panel bounds')
335+
await inputSession.send('Emulation.setTouchEmulationEnabled', { enabled: true })
336+
await inputSession.send('Input.dispatchTouchEvent', {
337+
type: 'touchStart',
338+
touchPoints: [{ x: rect.x, y: rect.y + 100 }],
339+
})
340+
for (let offset = 10; offset <= 100; offset += 10) {
341+
await inputSession.send('Input.dispatchTouchEvent', {
342+
type: 'touchMove',
343+
touchPoints: [{ x: rect.x + offset, y: rect.y + 100 }],
344+
})
345+
}
346+
await inputSession.send('Input.dispatchTouchEvent', { type: 'touchEnd', touchPoints: [] })
347+
await inputSession.send('Emulation.setTouchEmulationEnabled', { enabled: false })
348+
await expectWidth(598)
349+
await page.reload()
350+
await page.getByRole('button', { name: 'workspace-chat-b', exact: true }).click()
351+
await expectWidth(598)
352+
await dragTo(698)
353+
})
354+
302355
await check('a viewport change during a drag clamps the committed display width', async () => {
303356
await expectWidth(698)
304357
const rect = await beginDrag()

‎apps/sim/app/workspace/[workspaceId]/home/components/chat-panel-layout.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export function ChatPanelLayout({
5252
{!collapsed && (
5353
<div className='relative z-20 w-0 flex-none max-md:hidden'>
5454
<div
55-
className='absolute inset-y-0 left-[-4px] w-[8px] cursor-ew-resize focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--selection)]'
55+
className='absolute inset-y-0 left-[-4px] w-[8px] cursor-ew-resize touch-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--selection)]'
5656
role='separator'
5757
tabIndex={0}
5858
aria-orientation='vertical'

‎apps/sim/app/workspace/[workspaceId]/home/hooks/use-mothership-resize.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export function useMothershipResize(
205205

206206
const handleResizePointerDown = useCallback(
207207
(e: React.PointerEvent) => {
208+
if (e.button !== 0) return
208209
e.preventDefault()
209210

210211
const el = mothershipRef.current

0 commit comments

Comments
 (0)