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
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ on:
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
node: [20, 24]
continue-on-error: ${{ matrix.node == 24 }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -16,13 +20,13 @@ jobs:
- name: Setup Nodejs
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
node-version: ${{ matrix.node }}
- name: Install dependencies
run: npm ci
- name: Check Types
run: npm run type-check
- name: Lint
run: npm run lint
run: make lint
- name: Test
run: npm run test
- name: Verify icon changes
Expand All @@ -38,7 +42,7 @@ jobs:
- name: Build
run: npm run build
- name: Build Docs
run: npm run build-docs
run: make build-docs
- name: Coverage
uses: codecov/codecov-action@v4
with:
Expand Down
20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@ test.npm.%: validate-no-uncommitted-package-lock-changes
requirements: ## install ci requirements
npm ci

# npm swallows errors
# see https://github.com/openedx/paragon/issues/3329
#
# Instead of having this directly in the build-docs script
# in the top-level package.json, put it here so we can have
# a single source of truth and get proper error codes in CI
.PHONY: build-docs
build-docs:
npm run build --workspace=www

# npm swallows errors
# see https://github.com/openedx/paragon/issues/3329
#
# Instead of having this directly in the lint script
# in the top-level package.json, put it here so we can have
# a single source of truth and get proper error codes in CI
.PHONY: lint
lint:
npm run stylelint && npm run eslint && npm run lint --workspaces --if-present

i18n.extract:
# Pulling display strings from .jsx files into .json files...
npm run-script i18n_extract
Expand Down
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 }],
"@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
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@
"sideEffects": false,
"scripts": {
"build": "make build",
"build-docs": "npm run build --workspace=www",
"build-docs": "make build-docs",
"commit": "commit",
"debug-test": "node --inspect-brk node_modules/.bin/jest --runInBand --coverage",
"stylelint": "stylelint \"src/**/*.scss\" \"scss/**/*.scss\" \"www/src/**/*.scss\" --config .stylelintrc.json",
"lint": "npm run stylelint && eslint --ext .js --ext .jsx --ext .ts --ext .tsx --ext .json . && npm run lint --workspaces --if-present",
"eslint": "eslint --ext .js --ext .jsx --ext .ts --ext .tsx --ext .json .",
"lint": "make lint",
"lint:fix": "npm run stylelint && eslint --fix --ext .js --ext .jsx --ext .ts --ext .tsx --ext .json . && npm run lint --workspaces --if-present",
"prepublishOnly": "npm run build",
"semantic-release": "semantic-release",
Expand Down
36 changes: 14 additions & 22 deletions src/ActionRow/index.jsx → src/ActionRow/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

interface ActionRowProps extends React.HTMLAttributes<HTMLElement> {
/** Specifies the base element */
as?: React.ElementType;
/** Specifies the contents of the row */
children: React.ReactNode;
/** Specifies class name to append to the base element */
className?: string;
/** Specifies whether row should be displayed horizontally */
isStacked?: boolean;
}

function ActionRow({
as,
isStacked,
as = 'div',
isStacked = false,
children,
...props
}) {
}: ActionRowProps) {
return React.createElement(
as,
{
Expand All @@ -21,24 +31,6 @@ function ActionRow({
);
}

ActionRow.propTypes = {
/** Specifies the base element */
as: PropTypes.elementType,
/** Specifies class name to append to the base element */
className: PropTypes.string,
/** Specifies the contents of the row */
children: PropTypes.node,
/** Specifies whether row should be displayed horizontally */
isStacked: PropTypes.bool,
};

ActionRow.defaultProps = {
as: 'div',
className: undefined,
children: null,
isStacked: false,
};

function ActionRowSpacer() {
return <span className="pgn__action-row-spacer" />;
}
Expand Down
37 changes: 15 additions & 22 deletions src/Annotation/index.jsx → src/Annotation/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import React, { ForwardedRef } from 'react';
import classNames from 'classnames';

interface AnnotationProps extends React.HTMLAttributes<HTMLSpanElement> {
/** Specifies contents of the component. */
children: React.ReactNode;
/** Specifies class name to append to the base element. */
className?: string;
/** Specifies variant to use. */
variant?: 'error' | 'success' | 'warning' | 'light' | 'dark';
/** Specifies arrow position. */
arrowPlacement?: 'top' | 'right' | 'bottom' | 'left';
}

const Annotation = React.forwardRef(({
className,
variant,
variant = 'success',
children,
arrowPlacement,
arrowPlacement = 'bottom',
...props
}, ref) => (
} : AnnotationProps, ref : ForwardedRef<HTMLSpanElement>) => (
<span
className={classNames(
className,
Expand All @@ -22,21 +32,4 @@ const Annotation = React.forwardRef(({
</span>
));

Annotation.defaultProps = {
className: undefined,
variant: 'success',
arrowPlacement: 'bottom',
};

Annotation.propTypes = {
/** Specifies contents of the component. */
children: PropTypes.node.isRequired,
/** Specifies class name to append to the base element. */
className: PropTypes.string,
/** Specifies variant to use. */
variant: PropTypes.oneOf(['error', 'success', 'warning', 'light', 'dark']),
/** Specifies arrow position. */
arrowPlacement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
};

export default Annotation;
32 changes: 13 additions & 19 deletions src/Avatar/index.jsx → src/Avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
// @ts-ignore
import defaultAvatar from './default-avatar.svg';

export interface AvatarProps extends React.ImgHTMLAttributes<HTMLImageElement> {
/** Alt text. Usually the user's name */
alt?: string;
/** Size of the avatar */
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'huge';
/** Image src of the avatar image */
src?: string;
}

function Avatar({
alt,
size,
alt = '',
size = 'md',
src,
...attrs
}) {
}: AvatarProps) {
return (
<img
{...attrs}
Expand All @@ -23,19 +32,4 @@ function Avatar({
);
}

Avatar.propTypes = {
/** Alt text. Usually the user's name */
alt: PropTypes.string,
/** Size of the avatar */
size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl', 'xxl', 'huge']),
/** Image src of the avatar image */
src: PropTypes.string,
};

Avatar.defaultProps = {
alt: '',
size: 'md',
src: undefined,
};

export default Avatar;
54 changes: 23 additions & 31 deletions src/AvatarButton/index.jsx → src/AvatarButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import React, { ForwardedRef } from 'react';
import classNames from 'classnames';
import Button from '../Button';
import Avatar from '../Avatar';
import Avatar, { AvatarProps } from '../Avatar';

const buttonSizesToAvatarSize = {
sm: 'xs',
md: 'sm',
lg: 'md',
};

interface AvatarButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
/** The button text */
children?: string;
/** A class name to append to the button */
className?: string;
/** Show the label or only the avatar */
showLabel?: boolean;
/** The button size */
size?: 'sm' | 'md' | 'lg';
/** Image src of the avatar image */
src?: string;
/** The button style variant to use */
variant?: string;
}

const AvatarButton = React.forwardRef(({
children,
className,
showLabel,
size,
showLabel = true,
size = 'md',
src,
variant = 'tertiary',
...attrs
}, ref) => {
}: AvatarButtonProps, ref: ForwardedRef<HTMLButtonElement>) => {
const avatarSize = buttonSizesToAvatarSize[size] || 'sm';
return (
<Button
Expand All @@ -31,35 +46,12 @@ const AvatarButton = React.forwardRef(({
)}
size={size}
ref={ref}
variant={variant}
>
<Avatar src={src} alt={showLabel ? '' : children} size={avatarSize} />
<Avatar src={src} alt={showLabel ? '' : children} size={avatarSize as AvatarProps['size']} />
{showLabel && children}
</Button>
);
});

AvatarButton.propTypes = {
/** The button text */
children: PropTypes.string,
/** A class name to append to the button */
className: PropTypes.string,
/** Show the label or only the avatar */
showLabel: PropTypes.bool,
/** The button size */
size: PropTypes.oneOf(['sm', 'md', 'lg']),
/** Image src of the avatar image */
src: PropTypes.string,
/** The button style variant to use */
variant: PropTypes.string,
};

AvatarButton.defaultProps = {
children: undefined,
className: undefined,
showLabel: true,
size: 'md',
src: undefined,
variant: 'tertiary',
};

export default AvatarButton;
8 changes: 5 additions & 3 deletions src/Card/BaseCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import type { ReactNode } from 'react';
// React import needed to support JSX outside functions, if removed build-docs fails
import React, { forwardRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

Expand Down Expand Up @@ -34,11 +36,11 @@ interface Props extends BsPropsWithAs {
borderColor?: ColorVariant;
hasBody?: boolean;
className?: string;
children: React.ReactNode;
children: ReactNode;
}
type BaseCardType = ComponentWithAsProp<'div', Props>;

const BaseCard : BaseCardType = React.forwardRef<HTMLDivElement, Props>(
const BaseCard : BaseCardType = forwardRef<HTMLDivElement, Props>(
(
{
prefix,
Expand Down
4 changes: 2 additions & 2 deletions src/Card/CardBody.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { forwardRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

const CardBody = React.forwardRef(({ className, children, ...rest }, ref) => (
const CardBody = forwardRef(({ className, children, ...rest }, ref) => (
<div className={classNames('pgn__card-body', className)} ref={ref} {...rest}>
{children}
</div>
Expand Down
1 change: 0 additions & 1 deletion src/Card/CardCarousel/CardCarousel.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import PropTypes from 'prop-types';
import { OverflowScroll } from '../../OverflowScroll';
import CardCarouselProvider from './CardCarouselProvider';
Expand Down
2 changes: 1 addition & 1 deletion src/Card/CardCarousel/CardCarouselControls.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import { useContext } from 'react';
import { useIntl } from 'react-intl';
import Stack from '../../Stack';
import IconButton from '../../IconButton';
Expand Down
2 changes: 1 addition & 1 deletion src/Card/CardCarousel/CardCarouselHeader.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, isValidElement } from 'react';
import { useContext, isValidElement } from 'react';
import PropTypes from 'prop-types';
import CardCarouselTitle from './CardCarouselTitle';
import CardCarouselSubtitle from './CardCarouselSubtitle';
Expand Down
2 changes: 1 addition & 1 deletion src/Card/CardCarousel/CardCarouselItems.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import { useContext } from 'react';
import PropTypes from 'prop-types';
import CardDeck from '../CardDeck';
import { CardCarouselContext } from './CardCarouselProvider';
Expand Down
Loading