Skip to content

Commit

Permalink
[ScrollArea] Read DirectionProvider and use logical positioning CSS…
Browse files Browse the repository at this point in the history
… props (mui#1194)
  • Loading branch information
mj12albert authored and onehanddev committed Jan 8, 2025
1 parent b6f179b commit b511990
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 48 deletions.
4 changes: 2 additions & 2 deletions packages/react/src/scroll-area/corner/ScrollAreaCorner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const ScrollAreaCorner = React.forwardRef(function ScrollAreaCorner(
) {
const { render, className, ...otherProps } = props;

const { dir, cornerRef, cornerSize, hiddenState } = useScrollAreaRootContext();
const { cornerRef, cornerSize, hiddenState } = useScrollAreaRootContext();

const mergedRef = useForkRef(cornerRef, forwardedRef);

Expand All @@ -34,7 +34,7 @@ const ScrollAreaCorner = React.forwardRef(function ScrollAreaCorner(
style: {
position: 'absolute',
bottom: 0,
[dir === 'rtl' ? 'left' : 'right']: 0,
insetInlineEnd: 0,
width: cornerSize.width,
height: cornerSize.height,
},
Expand Down
16 changes: 3 additions & 13 deletions packages/react/src/scroll-area/root/ScrollAreaRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ const ScrollAreaRoot = React.forwardRef(function ScrollAreaRoot(
props: ScrollAreaRoot.Props,
forwardedRef: React.ForwardedRef<HTMLDivElement>,
) {
const { render, className, dir, ...otherProps } = props;
const { render, className, ...otherProps } = props;

const scrollAreaRoot = useScrollAreaRoot({ dir });
const scrollAreaRoot = useScrollAreaRoot();

const { rootId } = scrollAreaRoot;

Expand All @@ -33,13 +33,7 @@ const ScrollAreaRoot = React.forwardRef(function ScrollAreaRoot(
extraProps: otherProps,
});

const contextValue = React.useMemo(
() => ({
dir,
...scrollAreaRoot,
}),
[dir, scrollAreaRoot],
);
const contextValue = React.useMemo(() => scrollAreaRoot, [scrollAreaRoot]);

const viewportId = `[data-id="${rootId}-viewport"]`;

Expand Down Expand Up @@ -83,10 +77,6 @@ ScrollAreaRoot.propTypes /* remove-proptypes */ = {
* returns a class based on the component’s state.
*/
className: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
/**
* @ignore
*/
dir: PropTypes.string,
/**
* Allows you to replace the component’s HTML element
* with a different tag, or compose it with another component.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';

export interface ScrollAreaRootContext {
dir: string | undefined;
cornerSize: { width: number; height: number };
setCornerSize: React.Dispatch<React.SetStateAction<{ width: number; height: number }>>;
thumbSize: { width: number; height: number };
Expand Down
23 changes: 3 additions & 20 deletions packages/react/src/scroll-area/root/useScrollAreaRoot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import { useEventCallback } from '../../utils/useEventCallback';
import { useEnhancedEffect } from '../../utils/useEnhancedEffect';
import { mergeReactProps } from '../../utils/mergeReactProps';
import { useBaseUiId } from '../../utils/useBaseUiId';
import { SCROLL_TIMEOUT } from '../constants';
Expand All @@ -12,9 +11,7 @@ interface Size {
height: number;
}

export function useScrollAreaRoot(params: useScrollAreaRoot.Parameters) {
const { dir: dirParam } = params;

export function useScrollAreaRoot() {
const [hovering, setHovering] = React.useState(false);
const [scrollingX, setScrollingX] = React.useState(false);
const [scrollingY, setScrollingY] = React.useState(false);
Expand Down Expand Up @@ -47,15 +44,6 @@ export function useScrollAreaRoot(params: useScrollAreaRoot.Parameters) {
cornerHidden: false,
});

const [autoDir, setAutoDir] = React.useState(dirParam);
const dir = dirParam ?? autoDir;

useEnhancedEffect(() => {
if (dirParam === undefined && viewportRef.current) {
setAutoDir(getComputedStyle(viewportRef.current).direction);
}
}, [dirParam]);

React.useEffect(() => {
return () => {
window.clearTimeout(scrollYTimeoutRef.current);
Expand Down Expand Up @@ -193,7 +181,6 @@ export function useScrollAreaRoot(params: useScrollAreaRoot.Parameters) {
const getRootProps = React.useCallback(
(externalProps = {}) =>
mergeReactProps<'div'>(externalProps, {
dir,
onPointerEnter: handlePointerEnterOrMove,
onPointerMove: handlePointerEnterOrMove,
onPointerDown({ pointerType }) {
Expand All @@ -208,7 +195,7 @@ export function useScrollAreaRoot(params: useScrollAreaRoot.Parameters) {
[ScrollAreaRootCssVars.scrollAreaCornerWidth as string]: `${cornerSize.width}px`,
},
}),
[cornerSize, dir, handlePointerEnterOrMove],
[cornerSize, handlePointerEnterOrMove],
);

return React.useMemo(
Expand Down Expand Up @@ -266,8 +253,4 @@ export function useScrollAreaRoot(params: useScrollAreaRoot.Parameters) {
);
}

export namespace useScrollAreaRoot {
export interface Parameters {
dir: string | undefined;
}
}
export namespace useScrollAreaRoot {}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import * as React from 'react';
import { useScrollAreaRootContext } from '../root/ScrollAreaRootContext';
import { useDirection } from '../../direction-provider/DirectionContext';
import { mergeReactProps } from '../../utils/mergeReactProps';
import { getOffset } from '../utils/getOffset';
import { useScrollAreaRootContext } from '../root/ScrollAreaRootContext';
import { ScrollAreaRootCssVars } from '../root/ScrollAreaRootCssVars';
import { ScrollAreaScrollbarCssVars } from './ScrollAreaScrollbarCssVars';

export function useScrollAreaScrollbar(params: useScrollAreaScrollbar.Parameters) {
const { orientation } = params;

const {
dir,
scrollbarYRef,
scrollbarXRef,
viewportRef,
Expand All @@ -21,6 +21,8 @@ export function useScrollAreaScrollbar(params: useScrollAreaScrollbar.Parameters
thumbSize,
} = useScrollAreaRootContext();

const direction = useDirection();

React.useEffect(() => {
const viewportEl = viewportRef.current;
const scrollbarEl = orientation === 'vertical' ? scrollbarYRef.current : scrollbarXRef.current;
Expand Down Expand Up @@ -130,7 +132,7 @@ export function useScrollAreaScrollbar(params: useScrollAreaScrollbar.Parameters
const scrollRatioX = clickX / maxThumbOffsetX;

let newScrollLeft: number;
if (dir === 'rtl') {
if (direction === 'rtl') {
// In RTL, invert the scroll direction
newScrollLeft = (1 - scrollRatioX) * (scrollableContentWidth - viewportWidth);

Expand All @@ -154,13 +156,12 @@ export function useScrollAreaScrollbar(params: useScrollAreaScrollbar.Parameters
...(orientation === 'vertical' && {
top: 0,
bottom: `var(${ScrollAreaRootCssVars.scrollAreaCornerHeight})`,
[dir === 'rtl' ? 'left' : 'right']: 0,
insetInlineEnd: 0,
[ScrollAreaScrollbarCssVars.scrollAreaThumbHeight as string]: `${thumbSize.height}px`,
}),
...(orientation === 'horizontal' && {
[dir === 'rtl' ? 'right' : 'left']: 0,
[dir === 'rtl' ? 'left' : 'right']:
`var(${ScrollAreaRootCssVars.scrollAreaCornerWidth})`,
insetInlineStart: 0,
insetInlineEnd: `var(${ScrollAreaRootCssVars.scrollAreaCornerWidth})`,
bottom: 0,
[ScrollAreaScrollbarCssVars.scrollAreaThumbWidth as string]: `${thumbSize.width}px`,
}),
Expand All @@ -170,7 +171,7 @@ export function useScrollAreaScrollbar(params: useScrollAreaScrollbar.Parameters
rootId,
handlePointerUp,
orientation,
dir,
direction,
thumbSize.height,
thumbSize.width,
viewportRef,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react';
import { useScrollAreaRootContext } from '../root/ScrollAreaRootContext';
import { useDirection } from '../../direction-provider/DirectionContext';
import { useEventCallback } from '../../utils/useEventCallback';
import { useEnhancedEffect } from '../../utils/useEnhancedEffect';
import { mergeReactProps } from '../../utils/mergeReactProps';
import { clamp } from '../../utils/clamp';
import { useScrollAreaRootContext } from '../root/ScrollAreaRootContext';
import { MIN_THUMB_SIZE } from '../constants';
import { getOffset } from '../utils/getOffset';

Expand All @@ -17,7 +18,6 @@ export function useScrollAreaViewport(params: useScrollAreaViewport.Parameters)
thumbYRef,
thumbXRef,
cornerRef,
dir,
setCornerSize,
setThumbSize,
rootId,
Expand All @@ -27,6 +27,8 @@ export function useScrollAreaViewport(params: useScrollAreaViewport.Parameters)
setHovering,
} = useScrollAreaRootContext();

const direction = useDirection();

const contentWrapperRef = React.useRef<HTMLDivElement | null>(null);

const computeThumb = useEventCallback(() => {
Expand Down Expand Up @@ -102,7 +104,7 @@ export function useScrollAreaViewport(params: useScrollAreaViewport.Parameters)
// In Safari, don't allow it to go negative or too far as `scrollLeft` considers the rubber
// band effect.
const thumbOffsetX =
dir === 'rtl'
direction === 'rtl'
? clamp(scrollRatioX * maxThumbOffsetX, -maxThumbOffsetX, 0)
: clamp(scrollRatioX * maxThumbOffsetX, 0, maxThumbOffsetX);

Expand Down Expand Up @@ -146,7 +148,7 @@ export function useScrollAreaViewport(params: useScrollAreaViewport.Parameters)

useEnhancedEffect(() => {
computeThumb();
}, [computeThumb, hiddenState, dir]);
}, [computeThumb, hiddenState, direction]);

useEnhancedEffect(() => {
// `onMouseEnter` doesn't fire upon load, so we need to check if the viewport is already
Expand Down

0 comments on commit b511990

Please sign in to comment.