Skip to content
Open
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
93 changes: 45 additions & 48 deletions src/ProgressBar/index.jsx → src/ProgressBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable react/require-default-props */
import React, { useCallback, useEffect } from 'react';
import ProgressBarBase from 'react-bootstrap/ProgressBar';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Annotation from '../Annotation';
import { getOffsetStyles, placeInfoAtZero } from './utils';
Expand All @@ -14,30 +14,53 @@ const VARIANTS = [
'warning',
'success',
'error',
];
] as const;

function ProgressBar(props) {
type Variant = typeof VARIANTS[number];

export interface ProgressBarAnnotatedProps {
/** Current value of progress. */
now?: number;
/** Show label that represents visual percentage. */
label?: React.ReactNode;
/** The `ProgressBar` style variant to use. */
variant?: Variant;
/** Specifies an additional `className` to add to the base element. */
className?: string;
/** Threshold current value. */
threshold?: number;
/** Specifies label for `threshold`. */
thresholdLabel?: React.ReactNode;
/** Variant for threshold value. */
thresholdVariant?: Variant;
/** Text near the progress annotation. */
progressHint?: React.ReactNode;
/** Text near the threshold annotation. */
thresholdHint?: React.ReactNode;
}

function ProgressBar(props: React.ComponentPropsWithoutRef<typeof ProgressBarBase>) {
return <ProgressBarBase {...props} />;
}

function ProgressBarAnnotated({
now,
label,
variant,
variant = PROGRESS_DEFAULT_VARIANT,
threshold,
thresholdLabel,
thresholdVariant,
thresholdVariant = THRESHOLD_DEFAULT_VARIANT,
progressHint,
thresholdHint,
...props
}) {
const progressInfoRef = React.useRef();
const thresholdInfoRef = React.useRef();
}: ProgressBarAnnotatedProps) {
const progressInfoRef = React.useRef<HTMLDivElement>(null);
const thresholdInfoRef = React.useRef<HTMLDivElement>(null);
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;
const isProgressHintAfter = (now as number) < HINT_SWAP_PERCENT;
const isThresholdHintAfter = (threshold as number) < 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(() => {
Expand All @@ -51,11 +74,11 @@ function ProgressBarAnnotated({
positionAnnotations();
});
const progressInfoEl = progressInfoRef.current;
observer.observe(progressInfoEl);
return () => progressInfoEl && observer.unobserve(progressInfoEl);
observer.observe(progressInfoEl!);
return () => { if (progressInfoEl) { observer.unobserve(progressInfoEl); } };
}, [positionAnnotations]);

const getHint = (text) => (
const getHint = (text: React.ReactNode) => (
<span className="pgn__progress-hint" data-testid="progress-hint">
{text}
</span>
Expand Down Expand Up @@ -114,38 +137,12 @@ function ProgressBarAnnotated({
);
}

ProgressBarAnnotated.propTypes = {
/** Current value of progress. */
now: PropTypes.number,
/** Show label that represents visual percentage. */
label: PropTypes.node,
/** The `ProgressBar` style variant to use. */
variant: PropTypes.oneOf(VARIANTS),
/** Specifies an additional `className` to add to the base element. */
className: PropTypes.string,
/** Threshold current value. */
threshold: PropTypes.number,
/** Specifies label for `threshold`. */
thresholdLabel: PropTypes.node,
/** Variant for threshold value. */
thresholdVariant: PropTypes.oneOf(VARIANTS),
/** Text near the progress annotation. */
progressHint: PropTypes.node,
/** Text near the threshold annotation. */
thresholdHint: PropTypes.node,
};
interface ProgressBarComponent {
(props: React.ComponentPropsWithoutRef<typeof ProgressBarBase>): React.JSX.Element;
Annotated: React.FC<ProgressBarAnnotatedProps>;
}

ProgressBarAnnotated.defaultProps = {
now: undefined,
label: undefined,
variant: PROGRESS_DEFAULT_VARIANT,
className: undefined,
threshold: undefined,
thresholdLabel: undefined,
thresholdVariant: THRESHOLD_DEFAULT_VARIANT,
progressHint: undefined,
thresholdHint: undefined,
};
const ProgressBarWithAnnotated = ProgressBar as unknown as ProgressBarComponent;
ProgressBarWithAnnotated.Annotated = ProgressBarAnnotated;

ProgressBar.Annotated = ProgressBarAnnotated;
export default ProgressBar;
export default ProgressBarWithAnnotated;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { render } from '@testing-library/react';
import renderer from 'react-test-renderer';

import ProgressBar, { ANNOTATION_CLASS } from '..';
import ProgressBar, { ANNOTATION_CLASS, ProgressBarAnnotatedProps } from '..';

const ref = {
current: {
Expand All @@ -24,9 +24,9 @@ const ref = {
},
],
},
};
} as any;

function ProgressBarElement(props) {
function ProgressBarElement(props: ProgressBarAnnotatedProps) {
return (
<ProgressBar.Annotated
now={20}
Expand Down Expand Up @@ -99,13 +99,13 @@ describe('<ProgressBar.Annotated />', () => {
expect(progressHints[1].textContent).toEqual('');
});
it('should apply styles based on direction for threshold', () => {
window.getComputedStyle = jest.fn().mockReturnValue({ getPropertyValue: () => 'rtl' });
window.getComputedStyle = jest.fn().mockReturnValue({ getPropertyValue: () => 'rtl' }) as any;
const { container } = render(<ProgressBarElement />);
const progressInfo = container.querySelector('.pgn__progress-info');
const computedStyles = window.getComputedStyle(progressInfo);
const computedStyles = window.getComputedStyle(progressInfo!);

expect(computedStyles.getPropertyValue('directory')).toBe('rtl');
window.getComputedStyle.mockRestore();
(window.getComputedStyle as jest.Mock).mockRestore();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const ref = {
},
],
},
};
} as any;

describe('utils', () => {
describe('placeInfoAtZero', () => {
Expand Down Expand Up @@ -86,8 +86,8 @@ describe('utils', () => {
expect(actualMarginRight).toEqual(expectedHorizontalMargin);
});
it('returns false if reference is wrong', () => {
const wrongRef1 = {};
const wrongRef2 = { current: {} };
const wrongRef1 = {} as any;
const wrongRef2 = { current: {} } as any;
expect(placeInfoAtZero(wrongRef1)).toEqual(false);
expect(placeInfoAtZero(wrongRef2)).toEqual(false);
});
Expand Down
18 changes: 10 additions & 8 deletions src/ProgressBar/utils.js → src/ProgressBar/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import React from 'react';

/**
* Gets the current annotation styles and calculates the left margin so
* that the annotation pointer indicates on zero of the ProgressBar.
Expand All @@ -8,11 +10,11 @@
* @param {string} annotationClass is used to identify the annotation element
*/
export const placeInfoAtZero = (
ref,
direction = 'ltr',
annotationOnly = true,
annotationClass = 'pgn__annotation',
) => {
ref: React.RefObject<HTMLElement | null>,
direction: string = 'ltr',
annotationOnly: boolean = true,
annotationClass: string = 'pgn__annotation',
): boolean => {
if (!ref.current || !ref.current.style) { return false; }
const { children } = ref.current;
let horizontalMargin = 0.0;
Expand All @@ -38,6 +40,6 @@ export const placeInfoAtZero = (
* depending on the direction.
*/
export const getOffsetStyles = (
value,
direction,
) => (direction === 'rtl' ? { right: `${value}%` } : { left: `${value}%` });
value: number | undefined,
direction: string,
): { left: string } | { right: string } => (direction === 'rtl' ? { right: `${value}%` } : { left: `${value}%` });
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ export {
} from './Pagination';
// @ts-ignore: has yet to be converted to TypeScript
export { default as Popover, PopoverTitle, PopoverContent } from './Popover';
// @ts-ignore: has yet to be converted to TypeScript
export { default as ProgressBar } from './ProgressBar';
export type { ProgressBarAnnotatedProps } from './ProgressBar';
// @ts-ignore: has yet to be converted to TypeScript
export { default as ProductTour } from './ProductTour';
// @ts-ignore: has yet to be converted to TypeScript
Expand Down