From ab50551a3ec0507e878206082b151b3a8ebff5c1 Mon Sep 17 00:00:00 2001 From: atomiks Date: Thu, 18 Sep 2025 19:22:30 +1000 Subject: [PATCH 1/3] [scroll area] Fix RTL horizontal scrollbar on Safari --- .../scroll-area/scroll-area-inset.tsx | 28 ++++++++++++++++++- .../react/src/scroll-area/utils/getOffset.ts | 5 ++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx b/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx index a77a437c5b..380de78b59 100644 --- a/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx +++ b/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx @@ -1,11 +1,37 @@ import * as React from 'react'; import { ScrollArea } from '@base-ui-components/react/scroll-area'; +import { DirectionProvider } from '@base-ui-components/react/direction-provider'; import styles from './scroll-area-inset.module.css'; export default function ScrollAreaInset() { return (
-

Scroll content is not clipped by inset scrollbars (user-defined paddings)

+

RTL

+ +

Scroll content is not clipped by inset scrollbars (user-defined paddings)

+ + +
+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute + irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. +

+
+
+ + + + + + + +
+
+ +

LTR

diff --git a/packages/react/src/scroll-area/utils/getOffset.ts b/packages/react/src/scroll-area/utils/getOffset.ts index a92e8e07da..e50920cfe3 100644 --- a/packages/react/src/scroll-area/utils/getOffset.ts +++ b/packages/react/src/scroll-area/utils/getOffset.ts @@ -8,8 +8,7 @@ export function getOffset( } const styles = getComputedStyle(element); - const start = axis === 'x' ? 'Left' : 'Top'; - const end = axis === 'x' ? 'Right' : 'Bottom'; + const name = axis === 'x' ? 'Inline' : 'Block'; - return parseFloat(styles[`${prop}${start}`]) + parseFloat(styles[`${prop}${end}`]); + return parseFloat(styles[`${prop}${name}`]); } From dbc4de19aa7c05eacc542b6981fe39cc776c7b8e Mon Sep 17 00:00:00 2001 From: atomiks Date: Thu, 18 Sep 2025 19:42:33 +1000 Subject: [PATCH 2/3] lint --- .../app/(private)/experiments/scroll-area/scroll-area-inset.tsx | 2 +- packages/react/src/scroll-area/utils/getOffset.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx b/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx index 7b42cc4279..380de78b59 100644 --- a/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx +++ b/docs/src/app/(private)/experiments/scroll-area/scroll-area-inset.tsx @@ -51,6 +51,6 @@ export default function ScrollAreaInset() { - +
); } diff --git a/packages/react/src/scroll-area/utils/getOffset.ts b/packages/react/src/scroll-area/utils/getOffset.ts index e50920cfe3..f8fddab1da 100644 --- a/packages/react/src/scroll-area/utils/getOffset.ts +++ b/packages/react/src/scroll-area/utils/getOffset.ts @@ -10,5 +10,5 @@ export function getOffset( const styles = getComputedStyle(element); const name = axis === 'x' ? 'Inline' : 'Block'; - return parseFloat(styles[`${prop}${name}`]); + return parseFloat(styles[`${prop}${name}Start`]) + parseFloat(styles[`${prop}${name}End`]); } From 69bbb5dca8bd70a74fd5029354c9e66de108cee9 Mon Sep 17 00:00:00 2001 From: atomiks Date: Thu, 18 Sep 2025 21:16:02 +1000 Subject: [PATCH 3/3] fix --- packages/react/src/scroll-area/utils/getOffset.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/react/src/scroll-area/utils/getOffset.ts b/packages/react/src/scroll-area/utils/getOffset.ts index f8fddab1da..64f5c62799 100644 --- a/packages/react/src/scroll-area/utils/getOffset.ts +++ b/packages/react/src/scroll-area/utils/getOffset.ts @@ -8,7 +8,15 @@ export function getOffset( } const styles = getComputedStyle(element); - const name = axis === 'x' ? 'Inline' : 'Block'; + const propAxis = axis === 'x' ? 'Inline' : 'Block'; - return parseFloat(styles[`${prop}${name}Start`]) + parseFloat(styles[`${prop}${name}End`]); + // Safari misreports `marginInlineEnd` in RTL. + // We have to assume the start/end values are symmetrical, which is likely. + if (axis === 'x' && prop === 'margin') { + return parseFloat(styles[`${prop}InlineStart`]) * 2; + } + + return ( + parseFloat(styles[`${prop}${propAxis}Start`]) + parseFloat(styles[`${prop}${propAxis}End`]) + ); }