fix(desktop): respect RTL profile rail edges and wheel direction
This commit is contained in:
@@ -292,6 +292,26 @@ describe('ProfileRail overflow', () => {
|
|||||||
expect(container.querySelector('[data-slot="profile-dropdown"]')).toBeNull()
|
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', () => {
|
it('restores wheel navigation and edge feedback after leaving the condensed menu', () => {
|
||||||
profiles.set(
|
profiles.set(
|
||||||
Array.from({ length: 14 }, (_, index) => ({ is_default: index === 0, name: index ? `agent${index}` : 'default' }))
|
Array.from({ length: 14 }, (_, index) => ({ is_default: index === 0, name: index ? `agent${index}` : 'default' }))
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ const stepThroughCells: Modifier = ({ containerNodeRect, draggingNodeRect, trans
|
|||||||
// the picker spans the fleet. Groups keep registry order regardless of which
|
// 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.
|
// one is active, so a square never moves under the pointer that clicked it.
|
||||||
export function ProfileRail() {
|
export function ProfileRail() {
|
||||||
const { t } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
const p = t.profiles
|
const p = t.profiles
|
||||||
const profiles = useStore($profiles)
|
const profiles = useStore($profiles)
|
||||||
const scope = useStore($profileScope)
|
const scope = useStore($profileScope)
|
||||||
@@ -314,7 +314,10 @@ export function ProfileRail() {
|
|||||||
scrollEdges({
|
scrollEdges({
|
||||||
clientHeight: el.clientWidth,
|
clientHeight: el.clientWidth,
|
||||||
scrollHeight: el.scrollWidth,
|
scrollHeight: el.scrollWidth,
|
||||||
scrollTop: el.scrollLeft
|
scrollTop:
|
||||||
|
getComputedStyle(el).direction === 'rtl'
|
||||||
|
? el.scrollWidth - el.clientWidth + el.scrollLeft
|
||||||
|
: el.scrollLeft
|
||||||
}),
|
}),
|
||||||
'x'
|
'x'
|
||||||
)
|
)
|
||||||
@@ -324,6 +327,9 @@ export function ProfileRail() {
|
|||||||
// Observe both widths: adding/removing a profile need not resize the viewport.
|
// Observe both widths: adding/removing a profile need not resize the viewport.
|
||||||
useResizeObserver(measureScroll, scrollRef, scrollContentRef)
|
useResizeObserver(measureScroll, scrollRef, scrollContentRef)
|
||||||
|
|
||||||
|
// A locale switch can reverse direction without changing either width.
|
||||||
|
useEffect(measureScroll, [locale, measureScroll])
|
||||||
|
|
||||||
const switchToRest = (agent: FleetAgent) => {
|
const switchToRest = (agent: FleetAgent) => {
|
||||||
const commitRestSwitch = (target: FleetAgent) => {
|
const commitRestSwitch = (target: FleetAgent) => {
|
||||||
const key = fleetRouteKey(target.connectionId, target.profile)
|
const key = fleetRouteKey(target.connectionId, target.profile)
|
||||||
@@ -378,7 +384,7 @@ export function ProfileRail() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
el.scrollLeft += event.deltaY
|
el.scrollLeft += event.deltaY * (getComputedStyle(el).direction === 'rtl' ? -1 : 1)
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user