Skip to content
Closed
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
4 changes: 2 additions & 2 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"presets": [
["@babel/preset-env", { "modules": false } ],
["@babel/preset-react", { "useSpread": true } ],
["@babel/preset-react", { "useSpread": true, "runtime": "automatic" } ],
"@babel/preset-typescript"
],
"env": {
"test": {
"presets": [
["@babel/preset-env", {}],
["@babel/preset-react", { "useSpread": true } ],
["@babel/preset-react", { "useSpread": true, "runtime": "automatic" }],
"@babel/preset-typescript"
]
}
Expand Down
8 changes: 4 additions & 4 deletions src/Carousel/index.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import { forwardRef } from 'react';
import PropTypes from 'prop-types';
import BaseCarousel from 'react-bootstrap/Carousel';
import BaseCarouselItem from 'react-bootstrap/CarouselItem';
Expand All @@ -7,11 +7,11 @@ import BaseCarouselCaption from 'react-bootstrap/CarouselCaption';
export const CAROUSEL_NEXT_LABEL_TEXT = 'Next';
export const CAROUSEL_PREV_LABEL_TEXT = 'Previous';

const Carousel = React.forwardRef((props, ref) => <BaseCarousel {...props} ref={ref} />);
const Carousel = forwardRef((props, ref) => <BaseCarousel {...props} ref={ref} />);

const CarouselItem = React.forwardRef((props, ref) => <BaseCarouselItem {...props} ref={ref} />);
const CarouselItem = forwardRef((props, ref) => <BaseCarouselItem {...props} ref={ref} />);

const CarouselCaption = React.forwardRef((props, ref) => <BaseCarouselCaption {...props} ref={ref} />);
const CarouselCaption = forwardRef((props, ref) => <BaseCarouselCaption {...props} ref={ref} />);

Carousel.propTypes = {
/** Specifies element type for this component. */
Expand Down
4 changes: 2 additions & 2 deletions src/Chip/Chip.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import type { ComponentProps } from 'react';
import renderer from 'react-test-renderer';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
Expand All @@ -7,7 +7,7 @@ import { Close } from '../../icons';
import { STYLE_VARIANTS } from './constants';
import Chip from '.';

function TestChip(props: Omit<React.ComponentProps<typeof Chip>, 'children'>) {
function TestChip(props: Omit<ComponentProps<typeof Chip>, 'children'>) {
return (
<Chip {...props}>
Test
Expand Down
5 changes: 3 additions & 2 deletions src/Chip/ChipIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { KeyboardEventHandler, MouseEventHandler } from 'react';
import type { ComponentType } from 'react';
import { KeyboardEventHandler, MouseEventHandler } from 'react';
import PropTypes from 'prop-types';
import Icon from '../Icon';
import IconButton from '../IconButton';
import { STYLE_VARIANTS } from './constants';

export type ChipIconProps = {
className: string,
src: React.ComponentType,
src: ComponentType,
variant: typeof STYLE_VARIANTS[keyof typeof STYLE_VARIANTS],
disabled?: boolean,
} & (
Expand Down
67 changes: 62 additions & 5 deletions src/Chip/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import React, { ForwardedRef, KeyboardEventHandler, MouseEventHandler } from 'react';
import type { ReactNode, ComponentType } from 'react';
import {
forwardRef, ForwardedRef, KeyboardEventHandler, MouseEventHandler,
} from 'react';
import PropTypes, { type Requireable } from 'prop-types';
import classNames from 'classnames';
// @ts-ignore
import { requiredWhen } from '../utils/propTypes';
import ChipIcon from './ChipIcon';
import { STYLE_VARIANTS } from './constants';

export const CHIP_PGN_CLASS = 'pgn__chip';

export interface IChip {
/** Specifies the content of the `Chip`. */
children: React.ReactNode,
children: ReactNode,
/** Click handler for the whole `Chip`, has effect only when Chip does not have any interactive icons. */
onClick?: KeyboardEventHandler & MouseEventHandler,
/** Specifies an additional `className` to add to the base element. */
Expand All @@ -20,7 +26,7 @@ export interface IChip {
*
* `import { Check } from '@openedx/paragon/icons';`
*/
iconBefore?: React.ComponentType,
iconBefore?: ComponentType,
/** Specifies icon alt text. */
iconBeforeAlt?: string,
/**
Expand All @@ -29,7 +35,7 @@ export interface IChip {
*
* `import { Check } from '@openedx/paragon/icons';`
*/
iconAfter?: React.ComponentType,
iconAfter?: ComponentType,
/** Specifies icon alt text. */
iconAfterAlt?: string,
/** A click handler for the `Chip` icon before. */
Expand All @@ -42,7 +48,7 @@ export interface IChip {
isSelected?: boolean,
}

const Chip = React.forwardRef(({
const Chip = forwardRef(({
children,
className,
variant = 'light',
Expand Down Expand Up @@ -111,4 +117,55 @@ const Chip = React.forwardRef(({
);
});

Chip.propTypes = {
/** Specifies the content of the `Chip`. */
// @ts-ignore
children: PropTypes.node.isRequired,
/** Specifies an additional `className` to add to the base element. */
className: PropTypes.string,
/** The `Chip` style variant to use. */
variant: PropTypes.oneOf(['light', 'dark']),
/** Disables the `Chip`. */
disabled: PropTypes.bool,
/** Click handler for the whole Chip, has effect only when Chip does not have any interactive icons. */
onClick: PropTypes.func,
/**
* An icon component to render before the content.
* Example import of a Paragon icon component:
*
* `import { Check } from '@openedx/paragon/icons';`
*/
iconBefore: PropTypes.elementType as Requireable<ComponentType>,
/** Specifies icon alt text. */
iconBeforeAlt: requiredWhen(PropTypes.string, ['iconBefore', 'onIconBeforeClick']),
/** A click handler for the `Chip` icon before. */
onIconBeforeClick: PropTypes.func,
/**
* An icon component to render before after the content.
* Example import of a Paragon icon component:
*
* `import { Check } from '@openedx/paragon/icons';`
*/
iconAfter: PropTypes.elementType as Requireable<ComponentType>,
/** Specifies icon alt text. */
iconAfterAlt: requiredWhen(PropTypes.string, ['iconAfter', 'onIconAfterClick']),
/** A click handler for the `Chip` icon after. */
onIconAfterClick: PropTypes.func,
/** Indicates if `Chip` has been selected. */
isSelected: PropTypes.bool,
};

Chip.defaultProps = {
className: undefined,
variant: STYLE_VARIANTS.LIGHT,
disabled: false,
onClick: undefined,
iconBefore: undefined,
iconAfter: undefined,
onIconBeforeClick: undefined,
onIconAfterClick: undefined,
isSelected: false,
iconAfterAlt: undefined,
iconBeforeAlt: undefined,
};
export default Chip;
1 change: 0 additions & 1 deletion src/ChipCarousel/ChipCarousel.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { IntlProvider } from 'react-intl';
Expand Down
97 changes: 50 additions & 47 deletions src/ChipCarousel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { ForwardedRef } from 'react';
import type { ReactElement } from 'react';
import { forwardRef, createElement, ForwardedRef } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import classNames from 'classnames';
Expand All @@ -22,7 +23,7 @@ export interface OverflowScrollContextProps {

export interface ChipCarouselProps {
className?: string;
items: Array<React.ReactElement>;
items: Array<ReactElement>;
ariaLabel: string;
disableOpacityMasks?: boolean;
onScrollPrevious?: () => void;
Expand All @@ -33,7 +34,7 @@ export interface ChipCarouselProps {
gap?: number;
}

const ChipCarousel = React.forwardRef(({
const ChipCarousel = forwardRef(({
className,
items,
ariaLabel,
Expand All @@ -49,32 +50,33 @@ const ChipCarousel = React.forwardRef(({
const intl = useIntl();

return (
<div
className={classNames('pgn__chip-carousel', className, gap ? `pgn__chip-carousel-gap__${gap}` : '')}
{...props}
ref={ref}
>
<OverflowScroll
ariaLabel={ariaLabel}
hasInteractiveChildren
disableScroll={!canScrollHorizontal}
disableOpacityMasks={disableOpacityMasks}
onScrollPrevious={onScrollPrevious}
onScrollNext={onScrollNext}
offset={offset}
offsetType={offsetType}
(
<div
className={classNames('pgn__chip-carousel', className, gap ? `pgn__chip-carousel-gap__${gap}` : '')}
{...props}
ref={ref}
>
<OverflowScrollContext.Consumer>
{({
setOverflowRef,
isScrolledToStart,
isScrolledToEnd,
scrollToPrevious,
scrollToNext,
}: OverflowScrollContextProps) => (
<>
<OverflowScroll
ariaLabel={ariaLabel}
hasInteractiveChildren
disableScroll={!canScrollHorizontal}
disableOpacityMasks={disableOpacityMasks}
onScrollPrevious={onScrollPrevious}
onScrollNext={onScrollNext}
offset={offset}
offsetType={offsetType}
>
<OverflowScrollContext.Consumer>
{({
setOverflowRef,
isScrolledToStart,
isScrolledToEnd,
scrollToPrevious,
scrollToNext,
}: OverflowScrollContextProps) => (
<>
{!isScrolledToStart && (
<>
{!isScrolledToStart && (
<IconButton
size="sm"
className="pgn__chip-carousel__left-control"
Expand All @@ -83,8 +85,8 @@ const ChipCarousel = React.forwardRef(({
alt={intl.formatMessage(messages.scrollToPrevious)}
onClick={scrollToPrevious}
/>
)}
{!isScrolledToEnd && (
)}
{!isScrolledToEnd && (
<IconButton
size="sm"
className="pgn__chip-carousel__right-control"
Expand All @@ -93,25 +95,26 @@ const ChipCarousel = React.forwardRef(({
alt={intl.formatMessage(messages.scrollToNext)}
onClick={scrollToNext}
/>
)}
)}
</>
<div ref={setOverflowRef} className="d-flex">
<OverflowScroll.Items>
{items?.map((item, id) => {
const { children } = item?.props || {};
if (!children) {
return null;
}
// eslint-disable-next-line react/no-array-index-key
return createElement(Chip, { ...item.props, key: id });
})}
</OverflowScroll.Items>
</div>
</>
<div ref={setOverflowRef} className="d-flex">
<OverflowScroll.Items>
{items?.map((item, id) => {
const { children } = item?.props || {};
if (!children) {
return null;
}
// eslint-disable-next-line react/no-array-index-key
return React.createElement(Chip, { ...item.props, key: id });
})}
</OverflowScroll.Items>
</div>
</>
)}
</OverflowScrollContext.Consumer>
</OverflowScroll>
</div>
)}
</OverflowScrollContext.Consumer>
</OverflowScroll>
</div>
)
);
});

Expand Down
8 changes: 4 additions & 4 deletions src/Collapsible/Collapsible.test.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import { createRef } from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import renderer from 'react-test-renderer';
import userEvent from '@testing-library/user-event';
Expand Down Expand Up @@ -69,7 +69,7 @@ describe('<Collapsible />', () => {
});

describe('Imperative Methods', () => {
const ref = React.createRef();
const ref = createRef();
beforeEach(() => {
render(
<Collapsible.Advanced ref={ref}>{collapsibleContent}</Collapsible.Advanced>,
Expand Down Expand Up @@ -117,7 +117,7 @@ describe('<Collapsible />', () => {

describe('Mouse Interactions', () => {
let collapsible;
const ref = React.createRef();
const ref = createRef();
beforeEach(() => {
render(
<Collapsible.Advanced ref={ref}>{collapsibleContent}</Collapsible.Advanced>,
Expand Down Expand Up @@ -167,7 +167,7 @@ describe('<Collapsible />', () => {

describe('Keyboard Interactions', () => {
let collapsible;
const ref = React.createRef();
const ref = createRef();
beforeEach(() => {
render(
<Collapsible.Advanced ref={ref}>{collapsibleContent}</Collapsible.Advanced>,
Expand Down
6 changes: 3 additions & 3 deletions src/Collapsible/CollapsibleAdvanced.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import { createContext, Component } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';

export const CollapsibleContext = React.createContext();
export const CollapsibleContext = createContext();

class CollapsibleAdvanced extends React.Component {
class CollapsibleAdvanced extends Component {
static getDerivedStateFromProps(props) {
if (props.open !== undefined) {
return {
Expand Down
6 changes: 3 additions & 3 deletions src/Collapsible/CollapsibleBody.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import { createElement, cloneElement, useContext } from 'react';
import PropTypes from 'prop-types';

import Collapse from '../Collapse';
Expand All @@ -13,11 +13,11 @@ function CollapsibleBody({
// Keys are added to these elements so that TransitionReplace
// will recognize them as unique components and perform the
// transition properly.
const content = React.createElement(tag, { key: 'body', ...props }, children);
const content = createElement(tag, { key: 'body', ...props }, children);
const transitionBody = isOpen ? content : <div key="empty" />;

if (transitionWrapper) {
return React.cloneElement(transitionWrapper, {}, transitionBody);
return cloneElement(transitionWrapper, {}, transitionBody);
}
/* istanbul ignore next */
return unmountOnExit
Expand Down
Loading
Loading