Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BD-46] fix: fixed rtl direction in ProgressBar #2641

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/ProgressBar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ProgressBarBase from 'react-bootstrap/ProgressBar';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Annotation from '../Annotation';
import { placeInfoAtZero } from './utils';
import { getOffsetStyles, placeInfoAtZero } from './utils';

export const ANNOTATION_CLASS = 'pgn__annotation';
const HINT_SWAP_PERCENT = 50;
Expand Down Expand Up @@ -38,11 +38,12 @@ function ProgressBarAnnotated({
const isThresholdHintAfter = threshold < HINT_SWAP_PERCENT;
const progressColor = VARIANTS.includes(variant) ? variant : PROGRESS_DEFAULT_VARIANT;
const thresholdColor = VARIANTS.includes(thresholdVariant) ? thresholdVariant : THRESHOLD_DEFAULT_VARIANT;
const direction = window.getComputedStyle(document.body).getPropertyValue('direction');

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();
Expand All @@ -65,7 +66,7 @@ function ProgressBarAnnotated({
{!!label && (
<div
className="pgn__progress-info"
style={{ left: `${now}%` }}
style={getOffsetStyles(now, direction)}
ref={progressInfoRef}
>
{!isProgressHintAfter && getHint(progressHint)}
Expand Down Expand Up @@ -96,7 +97,7 @@ function ProgressBarAnnotated({
{(!!threshold && !!thresholdLabel) && (
<div
className="pgn__progress-info"
style={{ left: `${threshold}%` }}
style={getOffsetStyles(threshold, direction)}
ref={thresholdInfoRef}
>
{!isThresholdHintAfter && getHint(thresholdHint)}
Expand Down
15 changes: 13 additions & 2 deletions src/ProgressBar/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
width: 100%;
position: relative;
overflow: visible;
padding: 3.125rem 0;

.progress {
overflow: visible;
Expand Down Expand Up @@ -58,6 +59,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;
}
}
}
}
Expand All @@ -77,8 +83,13 @@
}

.pgn__progress-info {
display: inline-block;
position: relative;
position: absolute;
display: flex;
align-items: baseline;

&:first-child {
top: 0;
}
}

.pgn__progress-hint {
Expand Down
15 changes: 12 additions & 3 deletions src/ProgressBar/tests/ProgressBar.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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 '..';
Expand Down Expand Up @@ -47,9 +48,8 @@ describe('<ProgressBar.Annotated />', () => {
expect(tree).toMatchSnapshot();
});
it('renders info blocks with calculated margins', () => {
const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref);
mount(<ProgressBarElement />);
expect(useReferenceSpy).toHaveBeenCalledTimes(2);
jest.spyOn(React, 'useRef').mockReturnValue(ref);
render(<ProgressBarElement />);
expect(ref.current.style.marginLeft).not.toBeFalsy();
});
it('renders correct variant for progress bar and annotation', () => {
Expand Down Expand Up @@ -85,5 +85,14 @@ describe('<ProgressBar.Annotated />', () => {
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(<ProgressBarElement />);
const progressInfo = container.querySelector('.pgn__progress-info');
const computedStyles = window.getComputedStyle(progressInfo);

expect(computedStyles.getPropertyValue('directory')).toBe('rtl');
window.getComputedStyle.mockRestore();
});
});
});
30 changes: 24 additions & 6 deletions src/ProgressBar/tests/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,42 @@ describe('utils', () => {

expect(actualMarginLeft).toEqual(expectedMarginLeft);
});
it('correctly calculates left margin when annotationOnly equals to true', () => {
placeInfoAtZero(ref, false);
it('correctly calculates left margin when annotationOnly equals to true and dir equal ltr', () => {
placeInfoAtZero(ref, 'ltr', 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(ANNOTATION_CLASS)) {
marginLeft += elementParams.width / 2;
horizontalMargin += elementParams.width / 2;
} else {
marginLeft += elementParams.width;
horizontalMargin += elementParams.width;
}
}
const expectedMarginLeft = `${-marginLeft}px`;
const expectedMarginLeft = `${-horizontalMargin}px`;
const actualMarginLeft = ref.current.style.marginLeft;

expect(actualMarginLeft).toEqual(expectedMarginLeft);
});
it('correctly calculates right margin when annotationOnly equals to true and dir equal rtl', () => {
placeInfoAtZero(ref, 'rtl', false);

const { children } = ref.current;
let horizontalMargin = 0.0;
for (let i = 0; i < children.length || 0; i++) {
const elementParams = children[i].getBoundingClientRect();
if (children[i].className.includes(ANNOTATION_CLASS)) {
horizontalMargin += elementParams.width / 2;
} else {
horizontalMargin += elementParams.width;
}
}
const expectedHorizontalMargin = `${-horizontalMargin}px`;
const actualMarginRight = ref.current.style.marginRight;

expect(actualMarginRight).toEqual(expectedHorizontalMargin);
});
it('returns false if reference is wrong', () => {
const wrongRef1 = {};
const wrongRef2 = { current: {} };
Expand Down
30 changes: 24 additions & 6 deletions src/ProgressBar/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,42 @@
* that the annotation pointer indicates on zero of the ProgressBar.
*
* @param {object} ref reference to the info block
* @param {string} direction direction of the page ("ltr" or "rtl")
* @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 = 'ltr',
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;
PKulkoRaccoonGang marked this conversation as resolved.
Show resolved Hide resolved

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;
};

/**
* Retrieves offset styles based on the page direction.
*
* @param {number} value - The offset value in percentages.
* @param {string} direction - The offset direction ('rtl' for rightward offset, 'ltr' for leftward offset).
* @returns {Object} An object containing offset styles with either the 'left' or 'right' property,
* depending on the direction.
*/
export const getOffsetStyles = (
value,
direction,
) => (direction === 'rtl' ? { right: `${value}%` } : { left: `${value}%` });
Loading