From 34e148bc34bf5ab1aed289fc93f3948df933d45a Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Thu, 21 Sep 2023 16:22:10 +0300 Subject: [PATCH] fix: fixed rtl direction in ProgressBar --- src/ProgressBar/index.jsx | 23 +++++++++++++++------- src/ProgressBar/index.scss | 16 +++++++++++++-- src/ProgressBar/tests/ProgressBar.test.jsx | 19 +++++++++++++++--- src/ProgressBar/utils.js | 16 ++++++++++----- 4 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/ProgressBar/index.jsx b/src/ProgressBar/index.jsx index 1fe9cc5850a..74105f2b719 100644 --- a/src/ProgressBar/index.jsx +++ b/src/ProgressBar/index.jsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import ProgressBarBase from 'react-bootstrap/ProgressBar'; import PropTypes from 'prop-types'; import classNames from 'classnames'; @@ -31,18 +31,27 @@ function ProgressBarAnnotated({ thresholdHint, ...props }) { + const [direction, setDirection] = useState('ltr'); const progressInfoRef = React.useRef(); const thresholdInfoRef = React.useRef(); + const progressAnnotatedRef = React.useRef(); const thresholdPercent = (threshold || 0) - (now || 0); const isProgressHintAfter = now < HINT_SWAP_PERCENT; const isThresholdHintAfter = threshold < HINT_SWAP_PERCENT; const progressColor = VARIANTS.includes(variant) ? variant : PROGRESS_DEFAULT_VARIANT; const thresholdColor = VARIANTS.includes(thresholdVariant) ? thresholdVariant : THRESHOLD_DEFAULT_VARIANT; + useEffect(() => { + if (progressAnnotatedRef.current) { + const pageDirection = window.getComputedStyle(progressAnnotatedRef.current).getPropertyValue('direction'); + setDirection(pageDirection); + } + }, []); + const positionAnnotations = useCallback(() => { - placeInfoAtZero(progressInfoRef, isProgressHintAfter, ANNOTATION_CLASS); - placeInfoAtZero(thresholdInfoRef, isThresholdHintAfter, ANNOTATION_CLASS); - }, [isProgressHintAfter, isThresholdHintAfter]); + placeInfoAtZero(progressInfoRef, direction, isProgressHintAfter, ANNOTATION_CLASS); + placeInfoAtZero(thresholdInfoRef, direction, isThresholdHintAfter, ANNOTATION_CLASS); + }, [direction, isProgressHintAfter, isThresholdHintAfter]); useEffect(() => { positionAnnotations(); @@ -61,11 +70,11 @@ function ProgressBarAnnotated({ ); return ( -
+
{!!label && (
{!isProgressHintAfter && getHint(progressHint)} @@ -96,7 +105,7 @@ function ProgressBarAnnotated({ {(!!threshold && !!thresholdLabel) && (
{!isThresholdHintAfter && getHint(thresholdHint)} diff --git a/src/ProgressBar/index.scss b/src/ProgressBar/index.scss index 5b3532d62fc..815323d6d95 100644 --- a/src/ProgressBar/index.scss +++ b/src/ProgressBar/index.scss @@ -11,8 +11,10 @@ .pgn__progress-annotated { width: 100%; + height: 200px; position: relative; overflow: visible; + margin-top: 80px; .progress { overflow: visible; @@ -58,6 +60,11 @@ height: $progress-threshold-circle; border-radius: calc($progress-threshold-circle / 2); z-index: 1; + + [dir="rtl"] & { + left: -(calc($progress-threshold-circle / 2)); + right: auto; + } } } } @@ -77,8 +84,13 @@ } .pgn__progress-info { - display: inline-block; - position: relative; + position: absolute; + display: flex; + align-items: baseline; + + &:first-child { + top: -49px; + } } .pgn__progress-hint { diff --git a/src/ProgressBar/tests/ProgressBar.test.jsx b/src/ProgressBar/tests/ProgressBar.test.jsx index 8e372a517be..31e059c2e6e 100644 --- a/src/ProgressBar/tests/ProgressBar.test.jsx +++ b/src/ProgressBar/tests/ProgressBar.test.jsx @@ -1,9 +1,14 @@ import React from 'react'; import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import renderer from 'react-test-renderer'; import ProgressBar, { ANNOTATION_CLASS } from '..'; +window.getComputedStyle = jest.fn().mockImplementation(() => ({ + getPropertyValue: jest.fn().mockReturnValue('ltr'), +})); + const ref = { current: { style: { @@ -47,9 +52,8 @@ describe('', () => { expect(tree).toMatchSnapshot(); }); it('renders info blocks with calculated margins', () => { - const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref); - mount(); - expect(useReferenceSpy).toHaveBeenCalledTimes(2); + jest.spyOn(React, 'useRef').mockReturnValue(ref); + render(); expect(ref.current.style.marginLeft).not.toBeFalsy(); }); it('renders correct variant for progress bar and annotation', () => { @@ -85,5 +89,14 @@ describe('', () => { expect(wrapper.find('.pgn__progress-info').get(0).props.children[2]).toEqual(false); expect(wrapper.find('.pgn__progress-info').get(1).props.children[2]).toEqual(false); }); + it('should apply styles based on direction for threshold', () => { + window.getComputedStyle = jest.fn().mockReturnValue({ getPropertyValue: () => 'rtl' }); + const { container } = render(); + const progressInfo = container.querySelector('.pgn__progress-info'); + const computedStyles = window.getComputedStyle(progressInfo); + + expect(computedStyles.getPropertyValue('directory')).toBe('rtl'); + window.getComputedStyle.mockRestore(); + }); }); }); diff --git a/src/ProgressBar/utils.js b/src/ProgressBar/utils.js index 4d5f6022245..0e42151518b 100644 --- a/src/ProgressBar/utils.js +++ b/src/ProgressBar/utils.js @@ -3,24 +3,30 @@ * that the annotation pointer indicates on zero of the ProgressBar. * * @param {object} ref reference to the info block + * @param {string} direction directing elements to pages * @param {boolean} annotationOnly ignores width of the hint * @param {string} annotationClass is used to identify the annotation element */ // eslint-disable-next-line import/prefer-default-export -export const placeInfoAtZero = (ref, annotationOnly = true, annotationClass = 'pgn__annotation') => { +export const placeInfoAtZero = ( + ref, + direction, + annotationOnly = true, + annotationClass = 'pgn__annotation', +) => { if (!ref.current || !ref.current.style) { return false; } const { children } = ref.current; - let marginLeft = 0.0; + let horizontalMargin = 0.0; for (let i = 0; i < children.length || 0; i++) { const elementParams = children[i].getBoundingClientRect(); if (children[i].className.includes(annotationClass)) { - marginLeft += elementParams.width / 2; + horizontalMargin += elementParams.width / 2; } else { - marginLeft += annotationOnly ? 0.0 : elementParams.width; + horizontalMargin += annotationOnly ? 0.0 : elementParams.width; } } // eslint-disable-next-line no-param-reassign - ref.current.style.marginLeft = `${-marginLeft}px`; + ref.current.style[direction === 'rtl' ? 'marginRight' : 'marginLeft'] = `${-horizontalMargin}px`; return true; };