Skip to content

Commit fb678e3

Browse files
refactor: Transform <Badge>, <Breadcrumb>, ... to typescript (#3807)
1 parent c27fd97 commit fb678e3

File tree

8 files changed

+109
-138
lines changed

8 files changed

+109
-138
lines changed

src/Badge/index.jsx

Lines changed: 0 additions & 36 deletions
This file was deleted.

src/Badge/index.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, { ForwardedRef } from 'react';
2+
import BaseBadge from 'react-bootstrap/Badge';
3+
import { ComponentWithAsProp } from '../utils/types/bootstrap';
4+
5+
const STYLE_VARIANTS = [
6+
'primary',
7+
'secondary',
8+
'success',
9+
'danger',
10+
'warning',
11+
'info',
12+
'light',
13+
'dark',
14+
];
15+
16+
interface BadgeProps {
17+
/** Specifies element type for this component */
18+
as?: React.ElementType;
19+
/** Visual style of the badge. The full type definition can be seen [here](https://github.com/openedx/paragon/blob/release-23.x/src/Badge/index.tsx) */
20+
variant?: typeof STYLE_VARIANTS[number];
21+
/** Add the `pill` modifier to make badges more rounded with some additional horizontal padding */
22+
pill?: boolean;
23+
/** Overrides underlying component base CSS class name */
24+
bsPrefix?: string;
25+
}
26+
27+
const Badge: ComponentWithAsProp<'span', BadgeProps> = React.forwardRef(({
28+
as = 'span', variant = 'primary', pill = false, bsPrefix = 'badge', ...props
29+
}: BadgeProps, ref: ForwardedRef<HTMLSpanElement>) => (
30+
<BaseBadge as={as} variant={variant} pill={pill} bsPrefix={bsPrefix} {...props} ref={ref} />
31+
));
32+
33+
export default Badge;
Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
import React from 'react';
2-
import PropTypes from 'prop-types';
32
import classNames from 'classnames';
43

5-
export default function BreadcrumbLink({ as, clickHandler, linkProps }) {
4+
interface BreadcrumbLinkProps {
5+
as: React.ElementType;
6+
clickHandler?: (event: React.MouseEvent, link: any) => void;
7+
linkProps: {
8+
label: string;
9+
url?: string; // deprecated, use href instead when rendering as 'a'
10+
className?: string;
11+
[key: string]: any;
12+
};
13+
}
14+
15+
interface AdditionalProps {
16+
href?: string;
17+
onClick?: (event: React.MouseEvent, link: any) => void;
18+
}
19+
20+
export default function BreadcrumbLink({ as, clickHandler = undefined, linkProps }: BreadcrumbLinkProps) {
621
const {
722
label,
823
url,
924
className,
1025
...props
1126
} = linkProps;
12-
const addtlProps = {};
27+
const addtlProps: AdditionalProps = {};
1328

1429
if (as === 'a' && url) {
1530
// eslint-disable-next-line no-console
@@ -34,17 +49,3 @@ export default function BreadcrumbLink({ as, clickHandler, linkProps }) {
3449
label,
3550
);
3651
}
37-
38-
BreadcrumbLink.propTypes = {
39-
as: PropTypes.elementType.isRequired,
40-
clickHandler: PropTypes.func,
41-
linkProps: PropTypes.shape({
42-
label: PropTypes.string.isRequired,
43-
url: PropTypes.string,
44-
className: PropTypes.string,
45-
}).isRequired,
46-
};
47-
48-
BreadcrumbLink.defaultProps = {
49-
clickHandler: undefined,
50-
};
Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
11
import React from 'react';
2-
import PropTypes from 'prop-types';
32
import classNames from 'classnames';
43

54
import BreadcrumbLink from './BreadcrumbLink';
65
import { ChevronRight } from '../../icons';
76
import Icon from '../Icon';
87

8+
interface BreadcrumbProps {
9+
/** An array of objects describing links to be rendered. The contents of an object depend on the value of `linkAs`
10+
* prop as these objects will get passed down as props to the underlying component defined by `linkAs` prop.
11+
*/
12+
links: Array<{ label: string, [key: string]: any }>;
13+
/** allows to add a label that is not a link to the end of the breadcrumb. */
14+
activeLabel?: string;
15+
/** label of the element */
16+
ariaLabel?: string;
17+
/** allows to add a custom element between the breadcrumb items.
18+
* Defaults to `>` rendered using the `Icon` component. */
19+
spacer?: React.ReactElement;
20+
/** allows to add a custom function to be called `onClick` of a breadcrumb link.
21+
* The use case for this is for adding custom analytics to the component. */
22+
clickHandler?: (event: React.MouseEvent, link: any) => void;
23+
/** The `Breadcrumbs` style variant to use. */
24+
variant?: 'light' | 'dark';
25+
/** The `Breadcrumbs` mobile variant view. */
26+
isMobile?: boolean;
27+
/** Specifies the base element to use when rendering links, you should generally use either plain 'a' or
28+
* [react-router's Link](https://reactrouter.com/en/main/components/link).
29+
*/
30+
linkAs?: React.ElementType;
31+
}
32+
933
function Breadcrumb({
1034
links, activeLabel, spacer, clickHandler,
11-
variant, isMobile, ariaLabel, linkAs, ...props
12-
}) {
35+
variant = 'light', isMobile = false, ariaLabel = 'breadcrumb', linkAs = 'a', ...props
36+
}: BreadcrumbProps) {
1337
const linkCount = links.length;
1438
const displayLinks = isMobile ? [links[linkCount - 1]] : links;
1539

@@ -39,41 +63,4 @@ function Breadcrumb({
3963
);
4064
}
4165

42-
Breadcrumb.propTypes = {
43-
/** An array of objects describing links to be rendered. The contents of an object depend on the value of `linkAs`
44-
* prop as these objects will get passed down as props to the underlying component defined by `linkAs` prop.
45-
*/
46-
links: PropTypes.arrayOf(PropTypes.shape({
47-
label: PropTypes.string,
48-
})).isRequired,
49-
/** allows to add a label that is not a link to the end of the breadcrumb. */
50-
activeLabel: PropTypes.string,
51-
/** label of the element */
52-
ariaLabel: PropTypes.string,
53-
/** allows to add a custom element between the breadcrumb items.
54-
* Defaults to `>` rendered using the `Icon` component. */
55-
spacer: PropTypes.element,
56-
/** allows to add a custom function to be called `onClick` of a breadcrumb link.
57-
* The use case for this is for adding custom analytics to the component. */
58-
clickHandler: PropTypes.func,
59-
/** The `Breadcrumbs` style variant to use. */
60-
variant: PropTypes.oneOf(['light', 'dark']),
61-
/** The `Breadcrumbs` mobile variant view. */
62-
isMobile: PropTypes.bool,
63-
/** Specifies the base element to use when rendering links, you should generally use either plain 'a' or
64-
* [react-router's Link](https://reactrouter.com/en/main/components/link).
65-
*/
66-
linkAs: PropTypes.elementType,
67-
};
68-
69-
Breadcrumb.defaultProps = {
70-
activeLabel: undefined,
71-
ariaLabel: 'breadcrumb',
72-
spacer: undefined,
73-
clickHandler: undefined,
74-
variant: 'light',
75-
isMobile: false,
76-
linkAs: 'a',
77-
};
78-
7966
export default Breadcrumb;
Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
import React from 'react';
2-
import PropTypes from 'prop-types';
32
import classNames from 'classnames';
43

5-
function CardCarouselSubtitle({ children, as, className }) {
4+
interface CardCarouselSubtitleProps {
5+
/** Specifies contents of the component. */
6+
children: React.ReactNode;
7+
/** Specifies the base element */
8+
as?: React.ElementType;
9+
/** A class name to append to the base element. */
10+
className?: string;
11+
}
12+
13+
function CardCarouselSubtitle({ children, as, className }: CardCarouselSubtitleProps) {
614
const Component = as || 'p';
715
return (
816
<Component className={classNames('pgn__card-carousel-subtitle', className)}>
@@ -11,18 +19,4 @@ function CardCarouselSubtitle({ children, as, className }) {
1119
);
1220
}
1321

14-
CardCarouselSubtitle.propTypes = {
15-
/** Specifies contents of the component. */
16-
children: PropTypes.node.isRequired,
17-
/** Specifies the base element */
18-
as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
19-
/** A class name to append to the base element. */
20-
className: PropTypes.string,
21-
};
22-
23-
CardCarouselSubtitle.defaultProps = {
24-
as: undefined,
25-
className: undefined,
26-
};
27-
2822
export default CardCarouselSubtitle;

src/Card/CardCarousel/CardCarouselTitle.jsx

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
import classNames from 'classnames';
3+
4+
interface CardCarouselTitleProps {
5+
children: React.ReactNode;
6+
as?: React.ElementType;
7+
className?: string;
8+
}
9+
10+
function CardCarouselTitle({ children, as, className }: CardCarouselTitleProps) {
11+
const Component = as || 'h2';
12+
return (
13+
<Component className={classNames('pgn__card-carousel-title', className)}>
14+
{children}
15+
</Component>
16+
);
17+
}
18+
19+
export default CardCarouselTitle;

src/index.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export { default as Alert, ALERT_CLOSE_LABEL_TEXT } from './Alert';
66
export { default as Annotation } from './Annotation';
77
export { default as Avatar } from './Avatar';
88
export { default as AvatarButton } from './AvatarButton';
9+
export { default as Badge } from './Badge';
10+
export { default as Breadcrumb } from './Breadcrumb';
911
export { default as Bubble } from './Bubble';
1012
export { default as Button, ButtonGroup, ButtonToolbar } from './Button';
1113
export { default as Chip, CHIP_PGN_CLASS } from './Chip';
@@ -57,10 +59,6 @@ export { default as breakpoints } from './utils/breakpoints';
5759
// // // // // // // // // // // // // // // // // // // // // // // // // // //
5860
// @ts-ignore: has yet to be converted to TypeScript
5961
export { default as asInput } from './asInput';
60-
// @ts-ignore: has yet to be converted to TypeScript
61-
export { default as Badge } from './Badge';
62-
// @ts-ignore: has yet to be converted to TypeScript
63-
export { default as Breadcrumb } from './Breadcrumb';
6462

6563
export {
6664
default as Card,

0 commit comments

Comments
 (0)