From 7d38a0c3657f45e481f028bbec35009b53013283 Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Thu, 14 Sep 2023 18:07:51 -0400 Subject: [PATCH 1/3] fix(popper): add start/end positioning with RTL support, update default --- .../react-core/src/helpers/Popper/Popper.tsx | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/react-core/src/helpers/Popper/Popper.tsx b/packages/react-core/src/helpers/Popper/Popper.tsx index 403e232dfd6..4f642abc471 100644 --- a/packages/react-core/src/helpers/Popper/Popper.tsx +++ b/packages/react-core/src/helpers/Popper/Popper.tsx @@ -45,6 +45,14 @@ const getOppositePlacement = (placement: Placement): any => export const getOpacityTransition = (animationDuration: number) => `opacity ${animationDuration}ms cubic-bezier(.54, 1.5, .38, 1.11)`; +export const getLanguageDirection = (targetElement: HTMLElement) => { + if (!targetElement) { + return 'ltr'; + } + + return getComputedStyle(targetElement).getPropertyValue('direction') as 'ltr' | 'rtl'; +}; + export interface PopperProps { /** * Trigger reference element to which the popper is relatively placed to. @@ -66,7 +74,7 @@ export interface PopperProps { /** popper direction */ direction?: 'up' | 'down'; /** popper position */ - position?: 'right' | 'left' | 'center'; + position?: 'right' | 'left' | 'center' | 'start' | 'end'; /** Instead of direction and position can set the placement of the popper */ placement?: Placement; /** Custom width of the popper. If the value is "trigger", it will set the width to the trigger element's width */ @@ -177,7 +185,7 @@ export const Popper: React.FunctionComponent = ({ trigger, popper, direction = 'down', - position = 'left', + position = 'start', placement, width, minWidth = 'trigger', @@ -226,6 +234,28 @@ export const Popper: React.FunctionComponent = ({ const refOrTrigger = refElement || triggerElement; const showPopper = isVisible || internalIsVisible; + const triggerParent = ((triggerRef as React.RefObject)?.current || triggerElement)?.parentElement; + const languageDirection = getLanguageDirection(triggerParent); + + const internalPosition = React.useMemo<'left' | 'right' | 'center'>(() => { + const fixedPositions = { left: 'left', right: 'right', center: 'center' }; + + const positionMap = { + ltr: { + start: 'left', + end: 'right', + ...fixedPositions + }, + rtl: { + start: 'right', + end: 'left', + ...fixedPositions + } + }; + + return positionMap[languageDirection][position] as 'left' | 'right' | 'center'; + }, [position, languageDirection]); + const onDocumentClickCallback = React.useCallback( (event: MouseEvent) => onDocumentClick(event, refOrTrigger, popperElement), [showPopper, triggerElement, refElement, popperElement, onDocumentClick] @@ -333,15 +363,15 @@ export const Popper: React.FunctionComponent = ({ return placement; } let convertedPlacement = direction === 'up' ? 'top' : 'bottom'; - if (position !== 'center') { - convertedPlacement = `${convertedPlacement}-${position === 'right' ? 'end' : 'start'}`; + if (internalPosition !== 'center') { + convertedPlacement = `${convertedPlacement}-${internalPosition === 'right' ? 'end' : 'start'}`; } return convertedPlacement as Placement; }; - const getPlacementMemo = React.useMemo(getPlacement, [direction, position, placement]); + const getPlacementMemo = React.useMemo(getPlacement, [direction, internalPosition, placement]); const getOppositePlacementMemo = React.useMemo( () => getOppositePlacement(getPlacement()), - [direction, position, placement] + [direction, internalPosition, placement] ); const widthMods: Modifier<'widthMods', {}> = React.useMemo( From a29627b063e13122a8454a4181d3b3e58cefc44f Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Fri, 15 Sep 2023 12:01:44 -0400 Subject: [PATCH 2/3] ensure that getLanguageDirection only returns ltr or rtl --- packages/react-core/src/helpers/Popper/Popper.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/react-core/src/helpers/Popper/Popper.tsx b/packages/react-core/src/helpers/Popper/Popper.tsx index 4f642abc471..b7ba8663470 100644 --- a/packages/react-core/src/helpers/Popper/Popper.tsx +++ b/packages/react-core/src/helpers/Popper/Popper.tsx @@ -46,11 +46,18 @@ export const getOpacityTransition = (animationDuration: number) => `opacity ${animationDuration}ms cubic-bezier(.54, 1.5, .38, 1.11)`; export const getLanguageDirection = (targetElement: HTMLElement) => { - if (!targetElement) { - return 'ltr'; + const defaultDirection = 'ltr'; + let direction = defaultDirection; + + if (targetElement) { + direction = getComputedStyle(targetElement).getPropertyValue('direction'); + } + + if (['ltr', 'rtl'].includes(direction)) { + return direction as 'ltr' | 'rtl'; } - return getComputedStyle(targetElement).getPropertyValue('direction') as 'ltr' | 'rtl'; + return defaultDirection; }; export interface PopperProps { From 6e1d2f4d8ae7a7efadb73b8b964dcef6061c4582 Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Wed, 20 Sep 2023 15:51:05 -0400 Subject: [PATCH 3/3] fix(Popper): expanded types to include start/end; updated position value --- packages/react-core/src/components/Dropdown/Dropdown.tsx | 2 +- packages/react-core/src/components/Menu/MenuContainer.tsx | 2 +- packages/react-core/src/components/Select/Select.tsx | 2 +- packages/react-table/src/components/Table/ActionsColumn.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-core/src/components/Dropdown/Dropdown.tsx b/packages/react-core/src/components/Dropdown/Dropdown.tsx index b94c301f017..2819cc8eea1 100644 --- a/packages/react-core/src/components/Dropdown/Dropdown.tsx +++ b/packages/react-core/src/components/Dropdown/Dropdown.tsx @@ -8,7 +8,7 @@ export interface DropdownPopperProps { /** Vertical direction of the popper. If enableFlip is set to true, this will set the initial direction before the popper flips. */ direction?: 'up' | 'down'; /** Horizontal position of the popper */ - position?: 'right' | 'left' | 'center'; + position?: 'right' | 'left' | 'center' | 'start' | 'end'; /** Custom width of the popper. If the value is "trigger", it will set the width to the dropdown toggle's width */ width?: string | 'trigger'; /** Minimum width of the popper. If the value is "trigger", it will set the min width to the dropdown toggle's width */ diff --git a/packages/react-core/src/components/Menu/MenuContainer.tsx b/packages/react-core/src/components/Menu/MenuContainer.tsx index 16f002561f3..f1bceac4eff 100644 --- a/packages/react-core/src/components/Menu/MenuContainer.tsx +++ b/packages/react-core/src/components/Menu/MenuContainer.tsx @@ -5,7 +5,7 @@ export interface MenuPopperProps { /** Vertical direction of the popper. If enableFlip is set to true, this will set the initial direction before the popper flips. */ direction?: 'up' | 'down'; /** Horizontal position of the popper */ - position?: 'right' | 'left' | 'center'; + position?: 'right' | 'left' | 'center' | 'start' | 'end'; /** Custom width of the popper. If the value is "trigger", it will set the width to the dropdown toggle's width */ width?: string | 'trigger'; /** Minimum width of the popper. If the value is "trigger", it will set the min width to the dropdown toggle's width */ diff --git a/packages/react-core/src/components/Select/Select.tsx b/packages/react-core/src/components/Select/Select.tsx index d3f71d5862f..2b8a0691208 100644 --- a/packages/react-core/src/components/Select/Select.tsx +++ b/packages/react-core/src/components/Select/Select.tsx @@ -8,7 +8,7 @@ export interface SelectPopperProps { /** Vertical direction of the popper. If enableFlip is set to true, this will set the initial direction before the popper flips. */ direction?: 'up' | 'down'; /** Horizontal position of the popper */ - position?: 'right' | 'left' | 'center'; + position?: 'right' | 'left' | 'center' | 'start' | 'end'; /** Custom width of the popper. If the value is "trigger", it will set the width to the select toggle's width */ width?: string | 'trigger'; /** Minimum width of the popper. If the value is "trigger", it will set the min width to the select toggle's width */ diff --git a/packages/react-table/src/components/Table/ActionsColumn.tsx b/packages/react-table/src/components/Table/ActionsColumn.tsx index 369951d4a5d..5d8f01f0b94 100644 --- a/packages/react-table/src/components/Table/ActionsColumn.tsx +++ b/packages/react-table/src/components/Table/ActionsColumn.tsx @@ -39,7 +39,7 @@ const ActionsColumnBase: React.FunctionComponent = ({ extraData, actionsToggle, popperProps = { - position: 'right', + position: 'end', direction: 'down' }, innerRef,