fix(desktop): respect RTL profile rail edges and wheel direction

This commit is contained in:
funky-xamarin
2026-09-26 11:17:14 +08:00
committed by brooklyn!
parent 24bbdab4c7
commit 44a0fe0359
2 changed files with 29 additions and 3 deletions

View File

@@ -292,6 +292,26 @@ describe('ProfileRail overflow', () => {
expect(container.querySelector('[data-slot="profile-dropdown"]')).toBeNull()
})
it('maps negative RTL offsets to physical clipped edges and scrolls toward hidden profiles', () => {
profiles.set(Array.from({ length: 8 }, (_, index) => ({ is_default: index === 0, name: index ? `agent${index}` : 'default' })))
render(<ProfileRail />)
const scroller = screen.getByRole('button', { name: 'agent1' }).closest('.overflow-x-auto') as HTMLDivElement
scroller.style.direction = 'rtl'
Object.defineProperties(scroller, {
clientWidth: { configurable: true, value: 100 },
scrollWidth: { configurable: true, value: 200 }
})
fireEvent.scroll(scroller)
expect(mask.mock.calls.at(-1)?.[0]).toContain('to right, transparent,')
expect(mask.mock.calls.at(-1)?.[0]).toMatch(/, black\)$/)
scroller.dispatchEvent(new WheelEvent('wheel', { cancelable: true, deltaY: 30 }))
expect(scroller.scrollLeft).toBe(-30)
scroller.scrollLeft = -100
fireEvent.scroll(scroller)
expect(mask.mock.calls.at(-1)?.[0]).toContain('to right, black,')
expect(mask.mock.calls.at(-1)?.[0]).toContain('transparent)')
})
it('restores wheel navigation and edge feedback after leaving the condensed menu', () => {
profiles.set(
Array.from({ length: 14 }, (_, index) => ({ is_default: index === 0, name: index ? `agent${index}` : 'default' }))

View File

@@ -213,7 +213,7 @@ const stepThroughCells: Modifier = ({ containerNodeRect, draggingNodeRect, trans
// the picker spans the fleet. Groups keep registry order regardless of which
// one is active, so a square never moves under the pointer that clicked it.
export function ProfileRail() {
const { t } = useI18n()
const { t, locale } = useI18n()
const p = t.profiles
const profiles = useStore($profiles)
const scope = useStore($profileScope)
@@ -314,7 +314,10 @@ export function ProfileRail() {
scrollEdges({
clientHeight: el.clientWidth,
scrollHeight: el.scrollWidth,
scrollTop: el.scrollLeft
scrollTop:
getComputedStyle(el).direction === 'rtl'
? el.scrollWidth - el.clientWidth + el.scrollLeft
: el.scrollLeft
}),
'x'
)
@@ -324,6 +327,9 @@ export function ProfileRail() {
// Observe both widths: adding/removing a profile need not resize the viewport.
useResizeObserver(measureScroll, scrollRef, scrollContentRef)
// A locale switch can reverse direction without changing either width.
useEffect(measureScroll, [locale, measureScroll])
const switchToRest = (agent: FleetAgent) => {
const commitRestSwitch = (target: FleetAgent) => {
const key = fleetRouteKey(target.connectionId, target.profile)
@@ -378,7 +384,7 @@ export function ProfileRail() {
return
}
el.scrollLeft += event.deltaY
el.scrollLeft += event.deltaY * (getComputedStyle(el).direction === 'rtl' ? -1 : 1)
event.preventDefault()
}