@openedx/paragon 23.14.9 → 23.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Card/CardBody.d.ts +9 -0
- package/dist/Card/CardBody.js +0 -11
- package/dist/Card/CardBody.js.map +1 -1
- package/dist/Card/CardContext.d.ts +17 -0
- package/dist/Card/CardContext.js +8 -21
- package/dist/Card/CardContext.js.map +1 -1
- package/dist/Card/CardDivider.d.ts +7 -0
- package/dist/Card/CardDivider.js +2 -10
- package/dist/Card/CardDivider.js.map +1 -1
- package/dist/Card/CardFallbackDefaultImage.d.ts +1 -0
- package/dist/Card/CardFallbackDefaultImage.js +1 -0
- package/dist/Card/CardFallbackDefaultImage.js.map +1 -0
- package/dist/Card/CardGrid.d.ts +22 -0
- package/dist/Card/CardGrid.js +6 -31
- package/dist/Card/CardGrid.js.map +1 -1
- package/dist/DataTable/DataTableContext.d.ts +3 -0
- package/dist/DataTable/DataTableContext.js.map +1 -1
- package/dist/DataTable/TableCell.d.ts +14 -0
- package/dist/DataTable/TableCell.js +0 -12
- package/dist/DataTable/TableCell.js.map +1 -1
- package/dist/DataTable/TableHeaderCell.d.ts +26 -0
- package/dist/DataTable/TableHeaderCell.js +4 -32
- package/dist/DataTable/TableHeaderCell.js.map +1 -1
- package/dist/Menu/MenuItem.d.ts +17 -0
- package/dist/Menu/MenuItem.js +5 -27
- package/dist/Menu/MenuItem.js.map +1 -1
- package/dist/Menu/index.d.ts +16 -0
- package/dist/Menu/index.js +4 -24
- package/dist/Menu/index.js.map +1 -1
- package/dist/OverflowScroll/data/constants.d.ts +1 -0
- package/dist/OverflowScroll/data/constants.js +1 -0
- package/dist/OverflowScroll/data/constants.js.map +1 -0
- package/dist/PageBanner/index.d.ts +27 -0
- package/dist/PageBanner/index.js +5 -28
- package/dist/PageBanner/index.js.map +1 -1
- package/dist/Sheet/SheetContainer.js +30 -8
- package/dist/Sheet/SheetContainer.js.map +1 -1
- package/dist/Sheet/index.js +15 -5
- package/dist/Sheet/index.js.map +1 -1
- package/dist/Stack/index.d.ts +20 -0
- package/dist/Stack/index.js +3 -28
- package/dist/Stack/index.js.map +1 -1
- package/dist/Tabs/Tab.d.ts +19 -0
- package/dist/Tabs/Tab.js +0 -23
- package/dist/Tabs/Tab.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/Card/CardBody.tsx +19 -0
- package/src/Card/{CardContext.jsx → CardContext.tsx} +24 -25
- package/src/Card/CardDivider.tsx +13 -0
- package/src/Card/{CardGrid.jsx → CardGrid.tsx} +28 -35
- package/src/DataTable/{TableCell.jsx → TableCell.tsx} +13 -15
- package/src/DataTable/{TableHeaderCell.jsx → TableHeaderCell.tsx} +32 -33
- package/src/Menu/MenuItem.tsx +55 -0
- package/src/Menu/{index.jsx → index.tsx} +25 -28
- package/src/PageBanner/{index.jsx → index.tsx} +27 -29
- package/src/Sheet/Sheet.test.jsx +63 -3
- package/src/Sheet/SheetContainer.jsx +34 -7
- package/src/Sheet/SheetContainer.test.jsx +34 -1
- package/src/Sheet/__snapshots__/Sheet.test.jsx.snap +15 -6
- package/src/Sheet/index.jsx +12 -2
- package/src/Stack/{index.jsx → index.tsx} +22 -35
- package/src/Tabs/{Tab.jsx → Tab.tsx} +10 -18
- package/src/index.ts +1 -2
- package/src/Card/CardBody.jsx +0 -23
- package/src/Card/CardDivider.jsx +0 -18
- package/src/Menu/MenuItem.jsx +0 -57
- /package/src/Card/{CardFallbackDefaultImage.js → CardFallbackDefaultImage.ts} +0 -0
- /package/src/DataTable/{DataTableContext.jsx → DataTableContext.tsx} +0 -0
- /package/src/OverflowScroll/data/{constants.js → constants.ts} +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { ForwardedRef } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
|
|
4
|
+
interface CardBodyProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/** Specifies the content of the component. */
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
/** The class to append to the base element. */
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CardBody = React.forwardRef(({
|
|
12
|
+
className, children, ...rest
|
|
13
|
+
}: CardBodyProps, ref: ForwardedRef<HTMLDivElement>) => (
|
|
14
|
+
<div className={classNames('pgn__card-body', className)} ref={ref} {...rest}>
|
|
15
|
+
{children}
|
|
16
|
+
</div>
|
|
17
|
+
));
|
|
18
|
+
|
|
19
|
+
export default CardBody;
|
|
@@ -1,14 +1,31 @@
|
|
|
1
|
-
import React, { createContext } from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
1
|
+
import React, { createContext, ReactNode } from 'react';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
interface CardContextData {
|
|
4
|
+
/** Specifies which orientation to use. */
|
|
5
|
+
orientation: 'horizontal' | 'vertical';
|
|
6
|
+
/** Specifies loading state. */
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
/** Specifies `Card` style variant */
|
|
9
|
+
variant: 'light' | 'dark' | 'muted';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const CardContext = createContext<CardContextData>({
|
|
13
|
+
orientation: 'vertical',
|
|
14
|
+
isLoading: false,
|
|
15
|
+
variant: 'light',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
interface CardContextProviderProps extends Partial<CardContextData> {
|
|
19
|
+
/** Specifies content of the component. */
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}
|
|
5
22
|
|
|
6
23
|
function CardContextProvider({
|
|
7
|
-
orientation,
|
|
24
|
+
orientation = 'vertical',
|
|
8
25
|
children,
|
|
9
|
-
isLoading,
|
|
10
|
-
variant,
|
|
11
|
-
}) {
|
|
26
|
+
isLoading = false,
|
|
27
|
+
variant = 'light',
|
|
28
|
+
}: CardContextProviderProps) {
|
|
12
29
|
return (
|
|
13
30
|
<CardContext.Provider value={{ orientation, isLoading, variant }}>
|
|
14
31
|
{children}
|
|
@@ -16,23 +33,5 @@ function CardContextProvider({
|
|
|
16
33
|
);
|
|
17
34
|
}
|
|
18
35
|
|
|
19
|
-
CardContextProvider.propTypes = {
|
|
20
|
-
/** Specifies which orientation to use. */
|
|
21
|
-
orientation: PropTypes.oneOf(['horizontal', 'vertical']),
|
|
22
|
-
/** Specifies loading state. */
|
|
23
|
-
isLoading: PropTypes.bool,
|
|
24
|
-
/** Specifies content of the component. */
|
|
25
|
-
children: PropTypes.node,
|
|
26
|
-
/** Specifies `Card` style variant */
|
|
27
|
-
variant: PropTypes.oneOf(['light', 'dark', 'muted']),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
CardContextProvider.defaultProps = {
|
|
31
|
-
orientation: 'vertical',
|
|
32
|
-
isLoading: false,
|
|
33
|
-
children: null,
|
|
34
|
-
variant: 'light',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
36
|
export { CardContextProvider };
|
|
38
37
|
export default CardContext;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { forwardRef, ForwardedRef } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
|
|
4
|
+
interface CardDividerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/** Specifies class name to append to the base element. */
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const CardDivider = forwardRef(({ className, ...props }: CardDividerProps, ref: ForwardedRef<HTMLDivElement>) => (
|
|
10
|
+
<div className={classNames('pgn__card-divider', className)} ref={ref} {...props} />
|
|
11
|
+
));
|
|
12
|
+
|
|
13
|
+
export default CardDivider;
|
|
@@ -1,15 +1,38 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
1
|
+
import React, { useMemo, ReactNode } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
3
|
import Row from 'react-bootstrap/Row';
|
|
5
4
|
import Col from 'react-bootstrap/Col';
|
|
6
5
|
|
|
6
|
+
interface CardGridProps {
|
|
7
|
+
/** The class name for the CardGrid component */
|
|
8
|
+
className?: string;
|
|
9
|
+
/** The Card components to organize into a responsive grid */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* An object containing the desired column size at each breakpoint, following a similar
|
|
13
|
+
* props API as ``react-bootstrap/Col``
|
|
14
|
+
*/
|
|
15
|
+
columnSizes?: {
|
|
16
|
+
xs?: number;
|
|
17
|
+
sm?: number;
|
|
18
|
+
md?: number;
|
|
19
|
+
lg?: number;
|
|
20
|
+
xl?: number;
|
|
21
|
+
};
|
|
22
|
+
/** Whether to disable the default equal height cards across rows in the card grid */
|
|
23
|
+
hasEqualColumnHeights?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
7
26
|
function CardGrid({
|
|
8
27
|
className,
|
|
9
28
|
children,
|
|
10
|
-
columnSizes
|
|
11
|
-
|
|
12
|
-
|
|
29
|
+
columnSizes = {
|
|
30
|
+
sm: 12,
|
|
31
|
+
lg: 6,
|
|
32
|
+
xl: 4,
|
|
33
|
+
},
|
|
34
|
+
hasEqualColumnHeights = true,
|
|
35
|
+
}: CardGridProps) {
|
|
13
36
|
const cards = useMemo(
|
|
14
37
|
() => React.Children.map(children, (card) => (
|
|
15
38
|
<Col
|
|
@@ -36,34 +59,4 @@ function CardGrid({
|
|
|
36
59
|
);
|
|
37
60
|
}
|
|
38
61
|
|
|
39
|
-
CardGrid.propTypes = {
|
|
40
|
-
/** The class name for the CardGrid component */
|
|
41
|
-
className: PropTypes.string,
|
|
42
|
-
/** The Card components to organize into a responsive grid */
|
|
43
|
-
children: PropTypes.node.isRequired,
|
|
44
|
-
/**
|
|
45
|
-
* An object containing the desired column size at each breakpoint, following a similar
|
|
46
|
-
* props API as ``react-bootstrap/Col``
|
|
47
|
-
*/
|
|
48
|
-
columnSizes: PropTypes.shape({
|
|
49
|
-
xs: PropTypes.number,
|
|
50
|
-
sm: PropTypes.number,
|
|
51
|
-
md: PropTypes.number,
|
|
52
|
-
lg: PropTypes.number,
|
|
53
|
-
xl: PropTypes.number,
|
|
54
|
-
}),
|
|
55
|
-
/** Whether to disable the default equal height cards across rows in the card grid */
|
|
56
|
-
hasEqualColumnHeights: PropTypes.bool,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
CardGrid.defaultProps = {
|
|
60
|
-
className: undefined,
|
|
61
|
-
columnSizes: {
|
|
62
|
-
sm: 12,
|
|
63
|
-
lg: 6,
|
|
64
|
-
xl: 4,
|
|
65
|
-
},
|
|
66
|
-
hasEqualColumnHeights: true,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
62
|
export default CardGrid;
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
1
|
+
import React, { ReactNode, TdHTMLAttributes } from 'react';
|
|
3
2
|
import classNames from 'classnames';
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
interface TableCellProps {
|
|
5
|
+
/** Props for the td element */
|
|
6
|
+
getCellProps: () => TdHTMLAttributes<HTMLTableCellElement>;
|
|
7
|
+
/** Function that renders the cell contents. Will be called with the string 'Cell' */
|
|
8
|
+
render: (type: 'Cell') => ReactNode;
|
|
9
|
+
/** Table column */
|
|
10
|
+
column: {
|
|
11
|
+
/** Class(es) to be applied to the cells in the given column */
|
|
12
|
+
cellClassName?: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function TableCell({ getCellProps, render, column }: TableCellProps) {
|
|
6
16
|
const { className, ...rest } = getCellProps();
|
|
7
17
|
return (
|
|
8
18
|
<td {...rest} className={classNames('pgn__data-table-cell-wrap', className, column.cellClassName)}>
|
|
@@ -11,16 +21,4 @@ function TableCell({ getCellProps, render, column }) {
|
|
|
11
21
|
);
|
|
12
22
|
}
|
|
13
23
|
|
|
14
|
-
TableCell.propTypes = {
|
|
15
|
-
/** Props for the td element */
|
|
16
|
-
getCellProps: PropTypes.func.isRequired,
|
|
17
|
-
/** Function that renders the cell contents. Will be called with the string 'Cell' */
|
|
18
|
-
render: PropTypes.func.isRequired,
|
|
19
|
-
/** Table column */
|
|
20
|
-
column: PropTypes.shape({
|
|
21
|
-
/** Class(es) to be applied to the cells in the given column */
|
|
22
|
-
cellClassName: PropTypes.string,
|
|
23
|
-
}).isRequired,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
24
|
export default TableCell;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
2
|
import classNames from 'classnames';
|
|
4
3
|
import Icon from '../Icon';
|
|
5
4
|
import { ArrowDropDown, ArrowDropUp, ArrowDropUpDown } from '../../icons';
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
interface SortIndicatorProps {
|
|
7
|
+
/** Indicates whether or not a column is sorted */
|
|
8
|
+
isSorted: boolean;
|
|
9
|
+
/** Indicates whether the column is sorted in descending order */
|
|
10
|
+
isSortedDesc: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function SortIndicator({ isSorted, isSortedDesc }: SortIndicatorProps) {
|
|
8
14
|
if (!isSorted) {
|
|
9
15
|
return <Icon style={{ opacity: 0.5 }} src={ArrowDropUpDown} data-testid="arrow-drop-up-down" />;
|
|
10
16
|
}
|
|
@@ -16,14 +22,32 @@ export function SortIndicator({ isSorted, isSortedDesc }) {
|
|
|
16
22
|
return <Icon src={ArrowDropUp} data-testid="arrow-drop-up" />;
|
|
17
23
|
}
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
interface TableHeaderCellProps {
|
|
26
|
+
/** Returns props for the th element */
|
|
27
|
+
getHeaderProps: (...args: any[]) => Record<string, any>;
|
|
28
|
+
/** Indicates whether or not a column is sorted */
|
|
29
|
+
isSorted?: boolean;
|
|
30
|
+
/** Renders the header content. Passed the string 'Header' */
|
|
31
|
+
render: (type: 'Header') => React.ReactNode;
|
|
32
|
+
/** Indicates whether the column is sorted in descending order */
|
|
33
|
+
isSortedDesc?: boolean;
|
|
34
|
+
/** Gets props related to sorting that will be passed to th */
|
|
35
|
+
getSortByToggleProps?: (...args: any[]) => Record<string, any>;
|
|
36
|
+
/** Indicates whether a column is sortable */
|
|
37
|
+
canSort?: boolean;
|
|
38
|
+
/** Class(es) to be applied to header cells */
|
|
39
|
+
headerClassName?: string;
|
|
40
|
+
}
|
|
23
41
|
|
|
24
42
|
function TableHeaderCell({
|
|
25
|
-
getHeaderProps,
|
|
26
|
-
|
|
43
|
+
getHeaderProps,
|
|
44
|
+
render,
|
|
45
|
+
canSort = false,
|
|
46
|
+
getSortByToggleProps = () => ({}),
|
|
47
|
+
isSorted = false,
|
|
48
|
+
isSortedDesc = false,
|
|
49
|
+
headerClassName,
|
|
50
|
+
}: TableHeaderCellProps) {
|
|
27
51
|
const toggleProps = canSort && getSortByToggleProps ? getSortByToggleProps() : {};
|
|
28
52
|
|
|
29
53
|
return (
|
|
@@ -36,29 +60,4 @@ function TableHeaderCell({
|
|
|
36
60
|
);
|
|
37
61
|
}
|
|
38
62
|
|
|
39
|
-
TableHeaderCell.defaultProps = {
|
|
40
|
-
headerClassName: null,
|
|
41
|
-
isSorted: false,
|
|
42
|
-
isSortedDesc: false,
|
|
43
|
-
canSort: false,
|
|
44
|
-
getSortByToggleProps: () => {},
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
TableHeaderCell.propTypes = {
|
|
48
|
-
/** Returns props for the th element */
|
|
49
|
-
getHeaderProps: PropTypes.func.isRequired,
|
|
50
|
-
/** Indicates whether or not a column is sorted */
|
|
51
|
-
isSorted: PropTypes.bool,
|
|
52
|
-
/** Renders the header content. Passed the string 'Header' */
|
|
53
|
-
render: PropTypes.func.isRequired,
|
|
54
|
-
/** Indicates whether the column is sorted in descending order */
|
|
55
|
-
isSortedDesc: PropTypes.bool,
|
|
56
|
-
/** Gets props related to sorting that will be passed to th */
|
|
57
|
-
getSortByToggleProps: PropTypes.func,
|
|
58
|
-
/** Indicates whether a column is sortable */
|
|
59
|
-
canSort: PropTypes.bool,
|
|
60
|
-
/** Class(es) to be applied to header cells */
|
|
61
|
-
headerClassName: PropTypes.string,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
63
|
export default TableHeaderCell;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
type ReactElement,
|
|
3
|
+
type ReactNode,
|
|
4
|
+
type ElementType,
|
|
5
|
+
createElement,
|
|
6
|
+
type ComponentType,
|
|
7
|
+
type ComponentPropsWithoutRef,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import classNames from 'classnames';
|
|
10
|
+
import Icon from '../Icon';
|
|
11
|
+
|
|
12
|
+
interface MenuItemProps<As extends ElementType> {
|
|
13
|
+
/** Specifies that this `MenuItem` is selected inside the `SelectMenu` */
|
|
14
|
+
defaultSelected?: boolean;
|
|
15
|
+
/** Specifies class name to append to the base element */
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Specifies the content of the `MenuItem` */
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
/** Specifies the base element */
|
|
20
|
+
as?: As;
|
|
21
|
+
/** Specifies the jsx before the content of the `MenuItem` */
|
|
22
|
+
iconBefore?: ReactElement | ElementType;
|
|
23
|
+
/** Specifies the jsx after the content of the `MenuItem` */
|
|
24
|
+
iconAfter?: ReactElement | ElementType;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function MenuItem<As extends ElementType = 'button'>({
|
|
28
|
+
as = 'button' as As,
|
|
29
|
+
children,
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
31
|
+
defaultSelected = false,
|
|
32
|
+
iconAfter,
|
|
33
|
+
iconBefore,
|
|
34
|
+
...props
|
|
35
|
+
}: MenuItemProps<As> & ComponentPropsWithoutRef<As>) {
|
|
36
|
+
const className = classNames(props.className, 'pgn__menu-item');
|
|
37
|
+
|
|
38
|
+
return createElement(
|
|
39
|
+
as,
|
|
40
|
+
{
|
|
41
|
+
...props,
|
|
42
|
+
className,
|
|
43
|
+
},
|
|
44
|
+
(
|
|
45
|
+
<>
|
|
46
|
+
{iconBefore && <Icon className="btn-icon-before" src={iconBefore as ComponentType} />}
|
|
47
|
+
<span className="pgn__menu-item-text">{children}</span>
|
|
48
|
+
<span className="pgn__menu-item-content-spacer" />
|
|
49
|
+
{iconAfter && <Icon className="btn-icon-after" src={iconAfter as ComponentType} />}
|
|
50
|
+
</>
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default MenuItem;
|
|
@@ -1,18 +1,36 @@
|
|
|
1
|
-
import React
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
createElement,
|
|
3
|
+
type ElementType,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
type ComponentPropsWithoutRef,
|
|
6
|
+
} from 'react';
|
|
3
7
|
import classNames from 'classnames';
|
|
4
8
|
import useArrowKeyNavigation from '../hooks/useArrowKeyNavigationHook';
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
interface MenuProps<As extends ElementType> {
|
|
11
|
+
/** Specifies class name to append to the base element */
|
|
12
|
+
className?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Specifies the CSS selector string that indicates to which elements
|
|
15
|
+
* the user can navigate using the arrow keys
|
|
16
|
+
*/
|
|
17
|
+
arrowKeyNavigationSelector?: string;
|
|
18
|
+
/** Specifies the base element */
|
|
19
|
+
as?: As;
|
|
20
|
+
/** Specifies the content of the menu */
|
|
21
|
+
children?: ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function Menu<As extends ElementType = 'div'>({
|
|
25
|
+
as = 'div' as As,
|
|
26
|
+
arrowKeyNavigationSelector = 'a:not(:disabled),button:not(:disabled),input:not(:disabled)',
|
|
9
27
|
children,
|
|
10
28
|
...props
|
|
11
|
-
}) {
|
|
29
|
+
}: MenuProps<As> & ComponentPropsWithoutRef<As>) {
|
|
12
30
|
const parentRef = useArrowKeyNavigation({ selectors: arrowKeyNavigationSelector });
|
|
13
31
|
const className = classNames(props.className, 'pgn__menu');
|
|
14
32
|
|
|
15
|
-
return
|
|
33
|
+
return createElement(
|
|
16
34
|
as,
|
|
17
35
|
{
|
|
18
36
|
...props,
|
|
@@ -28,25 +46,4 @@ function Menu({
|
|
|
28
46
|
);
|
|
29
47
|
}
|
|
30
48
|
|
|
31
|
-
Menu.propTypes = {
|
|
32
|
-
/** Specifies class name to append to the base element */
|
|
33
|
-
className: PropTypes.string,
|
|
34
|
-
/**
|
|
35
|
-
* Specifies the CSS selector string that indicates to which elements
|
|
36
|
-
* the user can navigate using the arrow keys
|
|
37
|
-
*/
|
|
38
|
-
arrowKeyNavigationSelector: PropTypes.string,
|
|
39
|
-
/** Specifies the base element */
|
|
40
|
-
as: PropTypes.elementType,
|
|
41
|
-
/** Specifies the content of the menu */
|
|
42
|
-
children: PropTypes.node,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
Menu.defaultProps = {
|
|
46
|
-
className: undefined,
|
|
47
|
-
arrowKeyNavigationSelector: 'a:not(:disabled),button:not(:disabled),input:not(:disabled)',
|
|
48
|
-
as: 'div',
|
|
49
|
-
children: null,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
49
|
export default Menu;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
3
2
|
import classNames from 'classnames';
|
|
4
3
|
import { Close } from '../../icons';
|
|
5
4
|
import Icon from '../Icon';
|
|
@@ -13,11 +12,34 @@ export const VARIANTS = {
|
|
|
13
12
|
warning: 'warning',
|
|
14
13
|
accentA: 'accentA',
|
|
15
14
|
accentB: 'accentB',
|
|
16
|
-
};
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
interface PageBannerProps {
|
|
18
|
+
/** An element rendered inside the `Page Banner`. */
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
/** Boolean used to control whether `Page Banner` is dismissible. */
|
|
21
|
+
dismissible: boolean;
|
|
22
|
+
/** An element to be set as the dismiss button's alt text (preferably a translated string). */
|
|
23
|
+
dismissAltText: string;
|
|
24
|
+
/** A function to be called on dismiss of the `Page Banner`. */
|
|
25
|
+
onDismiss: () => void;
|
|
26
|
+
/** Boolean used to control whether the Page Banner shows. */
|
|
27
|
+
show: boolean;
|
|
28
|
+
/** A string designating which color variant of the `Page Banner` to display.
|
|
29
|
+
* The full list of variants can be seen [here.](https://github.com/openedx/paragon/blob/release-23.x/src/PageBanner/index.tsx)
|
|
30
|
+
*/
|
|
31
|
+
variant: keyof typeof VARIANTS;
|
|
32
|
+
}
|
|
17
33
|
|
|
18
34
|
function PageBanner({
|
|
19
|
-
children,
|
|
20
|
-
|
|
35
|
+
children,
|
|
36
|
+
dismissible = false,
|
|
37
|
+
dismissAltText = PAGE_BANNER_DISMISS_ALT_TEXT,
|
|
38
|
+
onDismiss = () => {},
|
|
39
|
+
show = true,
|
|
40
|
+
variant = VARIANTS.accentA,
|
|
41
|
+
...rest
|
|
42
|
+
}: PageBannerProps) {
|
|
21
43
|
if (!show) {
|
|
22
44
|
return null;
|
|
23
45
|
}
|
|
@@ -52,28 +74,4 @@ function PageBanner({
|
|
|
52
74
|
);
|
|
53
75
|
}
|
|
54
76
|
|
|
55
|
-
PageBanner.propTypes = {
|
|
56
|
-
/** An element rendered inside the `Page Banner`. */
|
|
57
|
-
children: PropTypes.node,
|
|
58
|
-
/** Boolean used to control whether `Page Banner` is dismissible. */
|
|
59
|
-
dismissible: PropTypes.bool,
|
|
60
|
-
/** An element to be set as the dismiss button's alt text (preferably a translated string). */
|
|
61
|
-
dismissAltText: PropTypes.node,
|
|
62
|
-
/** A function to be called on dismiss of the `Page Banner`. */
|
|
63
|
-
onDismiss: PropTypes.func,
|
|
64
|
-
/** Boolean used to control whether the Page Banner shows. */
|
|
65
|
-
show: PropTypes.bool,
|
|
66
|
-
/** A string designating which color variant of the `Page Banner` to display */
|
|
67
|
-
variant: PropTypes.oneOf([VARIANTS.light, VARIANTS.dark, VARIANTS.warning, VARIANTS.accentA, VARIANTS.accentB]),
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
PageBanner.defaultProps = {
|
|
71
|
-
children: undefined,
|
|
72
|
-
dismissible: false,
|
|
73
|
-
dismissAltText: PAGE_BANNER_DISMISS_ALT_TEXT,
|
|
74
|
-
onDismiss: () => {},
|
|
75
|
-
show: true,
|
|
76
|
-
variant: VARIANTS.accentA,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
77
|
export default PageBanner;
|
package/src/Sheet/Sheet.test.jsx
CHANGED
|
@@ -6,11 +6,12 @@ import Sheet, { POSITIONS, VARIANTS } from '.';
|
|
|
6
6
|
|
|
7
7
|
/* eslint-disable react/prop-types */
|
|
8
8
|
jest.mock('./SheetContainer', () => function SheetContainerMock(props) {
|
|
9
|
-
const { children, ...otherProps } = props;
|
|
9
|
+
const { children, className, ...otherProps } = props;
|
|
10
|
+
const allClasses = ['sheet-container', className].filter(Boolean).join(' ');
|
|
10
11
|
return (
|
|
11
|
-
<sheet-container {...otherProps}>
|
|
12
|
+
<div data-testid="sheet-container" className={allClasses} {...otherProps}>
|
|
12
13
|
{children}
|
|
13
|
-
</
|
|
14
|
+
</div>
|
|
14
15
|
);
|
|
15
16
|
});
|
|
16
17
|
|
|
@@ -53,5 +54,64 @@ describe('<Sheet />', () => {
|
|
|
53
54
|
const { container: container2 } = render(<Sheet />);
|
|
54
55
|
expect(container2.firstChild).not.toBeNull();
|
|
55
56
|
});
|
|
57
|
+
|
|
58
|
+
it('renders with custom className', () => {
|
|
59
|
+
const customClassName = 'custom-class';
|
|
60
|
+
const { container } = render(<Sheet className={customClassName} />);
|
|
61
|
+
const sheetElement = container.querySelector('.pgn__sheet-component');
|
|
62
|
+
|
|
63
|
+
expect(sheetElement).toBeInTheDocument();
|
|
64
|
+
expect(sheetElement).toHaveClass('pgn__sheet-component');
|
|
65
|
+
expect(sheetElement).toHaveClass(customClassName);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('handles multiple custom className', () => {
|
|
69
|
+
const customClasses = 'class-one class-two';
|
|
70
|
+
const { container } = render(<Sheet className={customClasses} />);
|
|
71
|
+
const sheetElement = container.querySelector('.pgn__sheet-component');
|
|
72
|
+
|
|
73
|
+
expect(sheetElement).toHaveClass('pgn__sheet-component');
|
|
74
|
+
expect(sheetElement).toHaveClass('class-one');
|
|
75
|
+
expect(sheetElement).toHaveClass('class-two');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('renders with custom className on SheetContainer', () => {
|
|
79
|
+
const customClassName = 'custom-container-class';
|
|
80
|
+
const { getByTestId } = render(<Sheet containerClassName={customClassName} />);
|
|
81
|
+
const sheetContainer = getByTestId('sheet-container');
|
|
82
|
+
|
|
83
|
+
expect(sheetContainer).toBeInTheDocument();
|
|
84
|
+
expect(sheetContainer).toHaveClass('sheet-container');
|
|
85
|
+
expect(sheetContainer).toHaveClass(customClassName);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('handles multiple custom className values on SheetContainer', () => {
|
|
89
|
+
const customClasses = 'container-one container-two';
|
|
90
|
+
const { getByTestId } = render(<Sheet containerClassName={customClasses} />);
|
|
91
|
+
const sheetContainer = getByTestId('sheet-container');
|
|
92
|
+
|
|
93
|
+
expect(sheetContainer).toBeInTheDocument();
|
|
94
|
+
expect(sheetContainer).toHaveClass('sheet-container');
|
|
95
|
+
expect(sheetContainer).toHaveClass('container-one');
|
|
96
|
+
expect(sheetContainer).toHaveClass('container-two');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('handles className and containerClassName simultaneously', () => {
|
|
100
|
+
const containerClass = 'container-class';
|
|
101
|
+
const sheetClass = 'sheet-class';
|
|
102
|
+
const { getByTestId, container } = render(
|
|
103
|
+
<Sheet containerClassName={containerClass} className={sheetClass} />,
|
|
104
|
+
);
|
|
105
|
+
const sheetContainer = getByTestId('sheet-container');
|
|
106
|
+
const sheetElement = container.querySelector('.pgn__sheet-component');
|
|
107
|
+
|
|
108
|
+
expect(sheetContainer).toBeInTheDocument();
|
|
109
|
+
expect(sheetContainer).toHaveClass('sheet-container');
|
|
110
|
+
expect(sheetContainer).toHaveClass(containerClass);
|
|
111
|
+
|
|
112
|
+
expect(sheetElement).toBeInTheDocument();
|
|
113
|
+
expect(sheetElement).toHaveClass('pgn__sheet-component');
|
|
114
|
+
expect(sheetElement).toHaveClass(sheetClass);
|
|
115
|
+
});
|
|
56
116
|
});
|
|
57
117
|
});
|
|
@@ -1,23 +1,44 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import ReactDOM from 'react-dom';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
|
+
import classNames from 'classnames';
|
|
4
5
|
|
|
5
6
|
class SheetContainer extends React.Component {
|
|
6
7
|
constructor(props) {
|
|
7
8
|
super(props);
|
|
8
9
|
this.sheetRootName = 'sheet-root';
|
|
10
|
+
this.updateRootElement();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
componentDidUpdate(prevProps) {
|
|
14
|
+
if (prevProps.className !== this.props.className) {
|
|
15
|
+
this.updateRootElement();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
updateRootElement = () => {
|
|
20
|
+
const { className } = this.props;
|
|
21
|
+
|
|
22
|
+
/* istanbul ignore next */
|
|
9
23
|
if (typeof document === 'undefined') {
|
|
10
24
|
this.rootElement = null;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let rootElement = document.getElementById(this.sheetRootName);
|
|
29
|
+
|
|
30
|
+
if (!rootElement) {
|
|
31
|
+
rootElement = document.createElement('div');
|
|
15
32
|
rootElement.setAttribute('id', this.sheetRootName);
|
|
16
|
-
rootElement.setAttribute('class', 'sheet-container');
|
|
17
33
|
rootElement.setAttribute('data-testid', 'sheet-container');
|
|
18
|
-
|
|
34
|
+
document.body.appendChild(rootElement);
|
|
19
35
|
}
|
|
20
|
-
|
|
36
|
+
|
|
37
|
+
const classes = classNames('sheet-container', className);
|
|
38
|
+
rootElement.setAttribute('class', classes);
|
|
39
|
+
|
|
40
|
+
this.rootElement = rootElement;
|
|
41
|
+
};
|
|
21
42
|
|
|
22
43
|
render() {
|
|
23
44
|
if (this.rootElement) {
|
|
@@ -32,6 +53,12 @@ class SheetContainer extends React.Component {
|
|
|
32
53
|
|
|
33
54
|
SheetContainer.propTypes = {
|
|
34
55
|
children: PropTypes.node.isRequired,
|
|
56
|
+
/** Additional CSS classes to apply to the sheet container */
|
|
57
|
+
className: PropTypes.string,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
SheetContainer.defaultProps = {
|
|
61
|
+
className: undefined,
|
|
35
62
|
};
|
|
36
63
|
|
|
37
64
|
export default SheetContainer;
|