@openedx/paragon 23.14.8 → 23.15.0

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.
Files changed (132) hide show
  1. package/dist/Card/CardBody.d.ts +9 -0
  2. package/dist/Card/CardBody.js +0 -11
  3. package/dist/Card/CardBody.js.map +1 -1
  4. package/dist/Card/CardContext.d.ts +17 -0
  5. package/dist/Card/CardContext.js +8 -21
  6. package/dist/Card/CardContext.js.map +1 -1
  7. package/dist/Card/CardDivider.d.ts +7 -0
  8. package/dist/Card/CardDivider.js +2 -10
  9. package/dist/Card/CardDivider.js.map +1 -1
  10. package/dist/Card/CardFallbackDefaultImage.d.ts +1 -0
  11. package/dist/Card/CardFallbackDefaultImage.js +1 -0
  12. package/dist/Card/CardFallbackDefaultImage.js.map +1 -0
  13. package/dist/Card/CardGrid.d.ts +22 -0
  14. package/dist/Card/CardGrid.js +6 -31
  15. package/dist/Card/CardGrid.js.map +1 -1
  16. package/dist/Chip/constants.js +0 -1
  17. package/dist/Chip/constants.js.map +1 -1
  18. package/dist/Container/index.js +0 -1
  19. package/dist/Container/index.js.map +1 -1
  20. package/dist/DataTable/CollapsibleButtonGroup.js +0 -1
  21. package/dist/DataTable/CollapsibleButtonGroup.js.map +1 -1
  22. package/dist/DataTable/DataTableContext.d.ts +3 -0
  23. package/dist/DataTable/DataTableContext.js.map +1 -1
  24. package/dist/DataTable/TableCell.d.ts +14 -0
  25. package/dist/DataTable/TableCell.js +0 -12
  26. package/dist/DataTable/TableCell.js.map +1 -1
  27. package/dist/DataTable/TableHeaderCell.d.ts +26 -0
  28. package/dist/DataTable/TableHeaderCell.js +4 -32
  29. package/dist/DataTable/TableHeaderCell.js.map +1 -1
  30. package/dist/DataTable/filters/CheckboxFilter.js +1 -1
  31. package/dist/DataTable/filters/CheckboxFilter.js.map +1 -1
  32. package/dist/DataTable/index.js +7 -2
  33. package/dist/DataTable/index.js.map +1 -1
  34. package/dist/Dropdown/index.js +10 -18
  35. package/dist/Dropdown/index.js.map +1 -1
  36. package/dist/Menu/MenuItem.d.ts +17 -0
  37. package/dist/Menu/MenuItem.js +5 -27
  38. package/dist/Menu/MenuItem.js.map +1 -1
  39. package/dist/Menu/index.d.ts +16 -0
  40. package/dist/Menu/index.js +4 -24
  41. package/dist/Menu/index.js.map +1 -1
  42. package/dist/Modal/ModalDialogHeader.js +4 -1
  43. package/dist/Modal/ModalDialogHeader.js.map +1 -1
  44. package/dist/Modal/ModalLayer.js +7 -12
  45. package/dist/Modal/ModalLayer.js.map +1 -1
  46. package/dist/OverflowScroll/data/constants.d.ts +1 -0
  47. package/dist/OverflowScroll/data/constants.js +1 -2
  48. package/dist/OverflowScroll/data/constants.js.map +1 -0
  49. package/dist/PageBanner/index.d.ts +27 -0
  50. package/dist/PageBanner/index.js +5 -28
  51. package/dist/PageBanner/index.js.map +1 -1
  52. package/dist/ProductTour/index.js +5 -7
  53. package/dist/ProductTour/index.js.map +1 -1
  54. package/dist/ProgressBar/utils.js +0 -1
  55. package/dist/SelectableBox/utils.js +1 -1
  56. package/dist/Sheet/SheetContainer.js +30 -8
  57. package/dist/Sheet/SheetContainer.js.map +1 -1
  58. package/dist/Sheet/index.js +15 -5
  59. package/dist/Sheet/index.js.map +1 -1
  60. package/dist/Stack/index.d.ts +20 -0
  61. package/dist/Stack/index.js +3 -28
  62. package/dist/Stack/index.js.map +1 -1
  63. package/dist/Sticky/index.js +1 -2
  64. package/dist/Sticky/index.js.map +1 -1
  65. package/dist/Tabs/Tab.d.ts +19 -0
  66. package/dist/Tabs/Tab.js +0 -23
  67. package/dist/Tabs/Tab.js.map +1 -1
  68. package/dist/asInput/index.js +7 -14
  69. package/dist/asInput/index.js.map +1 -1
  70. package/dist/index.d.ts +1 -1
  71. package/dist/index.js +1 -2
  72. package/dist/index.js.map +1 -1
  73. package/dist/setupTest.js.map +1 -1
  74. package/dist/utils/index.js +0 -1
  75. package/dist/utils/index.js.map +1 -1
  76. package/lib/version.js +1 -2
  77. package/package.json +3 -3
  78. package/src/Card/CardBody.tsx +19 -0
  79. package/src/Card/CardCarousel/tests/CardCarousel.test.jsx +0 -1
  80. package/src/Card/{CardContext.jsx → CardContext.tsx} +24 -25
  81. package/src/Card/CardDivider.tsx +13 -0
  82. package/src/Card/{CardGrid.jsx → CardGrid.tsx} +28 -35
  83. package/src/Chip/constants.ts +0 -1
  84. package/src/ChipCarousel/ChipCarousel.test.jsx +9 -11
  85. package/src/Container/index.tsx +0 -1
  86. package/src/DataTable/CollapsibleButtonGroup.jsx +0 -1
  87. package/src/DataTable/README.md +12 -12
  88. package/src/DataTable/{TableCell.jsx → TableCell.tsx} +13 -15
  89. package/src/DataTable/{TableHeaderCell.jsx → TableHeaderCell.tsx} +32 -33
  90. package/src/DataTable/filters/CheckboxFilter.jsx +1 -1
  91. package/src/DataTable/filters/tests/CheckboxFilter.test.jsx +31 -0
  92. package/src/DataTable/index.jsx +6 -2
  93. package/src/DataTable/selection/tests/utils.js +0 -1
  94. package/src/DataTable/tablecontrolbar.mdx +4 -4
  95. package/src/DataTable/tablefilters.mdx +8 -8
  96. package/src/DataTable/tests/DataTable.test.jsx +6 -4
  97. package/src/DataTable/tests/TableHeaderCell.test.jsx +0 -1
  98. package/src/DataTable/utils/tests/getTableArgs.test.js +3 -2
  99. package/src/DataTable/utils/tests/getVisibleColumns.test.js +0 -2
  100. package/src/Dropdown/index.jsx +11 -16
  101. package/src/Form/tests/useCheckboxSetValues.test.jsx +17 -9
  102. package/src/Menu/MenuItem.tsx +49 -0
  103. package/src/Menu/{index.jsx → index.tsx} +18 -27
  104. package/src/Modal/ModalDialogHeader.tsx +5 -1
  105. package/src/Modal/ModalLayer.tsx +1 -2
  106. package/src/Modal/tests/ModalLayer.test.tsx +1 -2
  107. package/src/OverflowScroll/data/{constants.js → constants.ts} +0 -2
  108. package/src/PageBanner/{index.jsx → index.tsx} +27 -29
  109. package/src/ProductTour/index.jsx +5 -7
  110. package/src/ProgressBar/utils.js +0 -1
  111. package/src/SelectableBox/tests/SelectableBox.test.jsx +0 -1
  112. package/src/SelectableBox/utils.js +1 -1
  113. package/src/Sheet/Sheet.test.jsx +63 -3
  114. package/src/Sheet/SheetContainer.jsx +34 -7
  115. package/src/Sheet/SheetContainer.test.jsx +34 -1
  116. package/src/Sheet/__snapshots__/Sheet.test.jsx.snap +15 -6
  117. package/src/Sheet/index.jsx +12 -2
  118. package/src/Stack/{index.jsx → index.tsx} +22 -35
  119. package/src/Sticky/index.jsx +1 -1
  120. package/src/Tabs/{Tab.jsx → Tab.tsx} +10 -18
  121. package/src/TransitionReplace/README.md +2 -2
  122. package/src/TransitionReplace/TransitionReplace.test.jsx +1 -1
  123. package/src/asInput/index.jsx +0 -3
  124. package/src/hooks/tests/useToggle.test.tsx +4 -5
  125. package/src/index.ts +1 -2
  126. package/src/setupTest.ts +0 -1
  127. package/src/utils/index.ts +0 -1
  128. package/src/Card/CardBody.jsx +0 -23
  129. package/src/Card/CardDivider.jsx +0 -18
  130. package/src/Menu/MenuItem.jsx +0 -57
  131. /package/src/Card/{CardFallbackDefaultImage.js → CardFallbackDefaultImage.ts} +0 -0
  132. /package/src/DataTable/{DataTableContext.jsx → DataTableContext.tsx} +0 -0
@@ -1,18 +1,30 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
1
+ import React, { ElementType, ReactNode, createElement } from 'react';
3
2
  import classNames from 'classnames';
4
3
  import useArrowKeyNavigation from '../hooks/useArrowKeyNavigationHook';
5
4
 
5
+ interface MenuProps {
6
+ /** Specifies class name to append to the base element */
7
+ className?: string;
8
+ /**
9
+ * Specifies the CSS selector string that indicates to which elements
10
+ * the user can navigate using the arrow keys
11
+ */
12
+ arrowKeyNavigationSelector?: string;
13
+ /** Specifies the base element */
14
+ as?: ElementType;
15
+ /** Specifies the content of the menu */
16
+ children?: ReactNode;
17
+ }
6
18
  function Menu({
7
- as,
8
- arrowKeyNavigationSelector,
19
+ as = 'div',
20
+ arrowKeyNavigationSelector = 'a:not(:disabled),button:not(:disabled),input:not(:disabled)',
9
21
  children,
10
22
  ...props
11
- }) {
23
+ }: MenuProps) {
12
24
  const parentRef = useArrowKeyNavigation({ selectors: arrowKeyNavigationSelector });
13
25
  const className = classNames(props.className, 'pgn__menu');
14
26
 
15
- return React.createElement(
27
+ return createElement(
16
28
  as,
17
29
  {
18
30
  ...props,
@@ -28,25 +40,4 @@ function Menu({
28
40
  );
29
41
  }
30
42
 
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
43
  export default Menu;
@@ -1,4 +1,3 @@
1
- /* eslint-disable react/require-default-props */
2
1
  import React from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import classNames from 'classnames';
@@ -37,4 +36,9 @@ ModalDialogHeader.propTypes = {
37
36
  className: PropTypes.string,
38
37
  };
39
38
 
39
+ ModalDialogHeader.defaultProps = {
40
+ as: 'div',
41
+ className: '',
42
+ };
43
+
40
44
  export default ModalDialogHeader;
@@ -4,15 +4,14 @@ import { FocusOn } from 'react-focus-on';
4
4
  import Portal from './Portal';
5
5
  import { ModalContextProvider } from './ModalContext';
6
6
 
7
- // istanbul ignore next
8
7
  function ModalBackdrop({ onClick }: { onClick?: () => void }) {
9
8
  return (
10
- // eslint-disable-next-line jsx-a11y/no-static-element-interactions
11
9
  <div
12
10
  className="pgn__modal-backdrop"
13
11
  onClick={onClick}
14
12
  onKeyDown={onClick}
15
13
  data-testid="modal-backdrop"
14
+ role="presentation"
16
15
  />
17
16
  );
18
17
  }
@@ -5,7 +5,6 @@ import userEvent from '@testing-library/user-event';
5
5
 
6
6
  import ModalLayer from '../ModalLayer';
7
7
 
8
- /* eslint-disable react/prop-types */
9
8
  jest.mock('../Portal', () => function PortalMock(props: any) {
10
9
  const { children, ...otherProps } = props;
11
10
  return (
@@ -66,7 +65,7 @@ describe('<ModalLayer />', () => {
66
65
  });
67
66
  });
68
67
 
69
- test('when isOpen is false the dialog is not rendered', () => {
68
+ it('when isOpen is false the dialog is not rendered', () => {
70
69
  render(
71
70
  <ModalLayer isOpen={false} onClose={jest.fn()}>
72
71
  <Dialog />
@@ -1,3 +1 @@
1
- /* eslint-disable import/prefer-default-export */
2
-
3
1
  export const OVERFLOW_SCROLL_ITEM_CLASS = 'pgn__overflow-scroll-item';
@@ -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, dismissible, dismissAltText, onDismiss, show, variant, ...rest
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;
@@ -111,16 +111,14 @@ const ProductTour = React.forwardRef(({ tours }, ref) => {
111
111
  }
112
112
  setCurrentCheckpointData(null);
113
113
  };
114
- /* eslint-disable */
115
114
  /**
116
115
  * Takes the final checkpoint array index value and looks for an existing onEnd callback.
117
- *
118
- * If an onEnd callback exist on checkpointIndex value and it is the final checkpoint
119
- * in the array, the onEnd callback will be called for the parent, and individual onEnd object.
120
- *
121
- * @param {Integer} checkpointIndex
116
+ *
117
+ * If an onEnd callback exist on checkpointIndex value and it is the final checkpoint
118
+ * in the array, the onEnd callback will be called for the parent, and individual onEnd object.
119
+ *
120
+ * @param {Integer} checkpointIndex
122
121
  */
123
- /* eslint-enable */
124
122
  const handleEnd = (checkpointIndex) => {
125
123
  setIndex(0);
126
124
  setIsTourEnabled(false);
@@ -25,7 +25,6 @@ export const placeInfoAtZero = (
25
25
  horizontalMargin += annotationOnly ? 0.0 : elementParams.width;
26
26
  }
27
27
  }
28
- // eslint-disable-next-line no-param-reassign
29
28
  ref.current.style[direction === 'rtl' ? 'marginRight' : 'marginLeft'] = `${-horizontalMargin}px`;
30
29
  return true;
31
30
  };
@@ -38,7 +38,6 @@ describe('<SelectableBox />', () => {
38
38
  it('renders with radio input type if neither checkbox nor radio is passed', () => {
39
39
  // Mock the `console.error` is intentional because an invalid `type` prop
40
40
  // with `wrongType` specified for `ForwardRef` expects one of the ['radio','flag'] parameters.
41
- // eslint-disable-next-line no-console
42
41
  const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
43
42
  render(<SelectableRadio type="wrongType" />);
44
43
  const selectableBox = screen.getByRole('button');
@@ -1,6 +1,5 @@
1
1
  import Form, { CheckboxControl, RadioControl } from '../Form';
2
2
 
3
- // eslint-disable-next-line import/prefer-default-export,consistent-return
4
3
  export const getInputType = (component, type) => {
5
4
  if (component === 'SelectableBox') {
6
5
  switch (type) {
@@ -21,4 +20,5 @@ export const getInputType = (component, type) => {
21
20
  return Form.RadioSet;
22
21
  }
23
22
  }
23
+ return null;
24
24
  };
@@ -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
- </sheet-container>
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
- } else if (document.getElementById(this.sheetRootName)) {
12
- this.rootElement = document.getElementById(this.sheetRootName);
13
- } else {
14
- const rootElement = document.createElement('div');
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
- this.rootElement = document.body.appendChild(rootElement);
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;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { render, screen } from '@testing-library/react';
2
+ import { render, screen, act } from '@testing-library/react';
3
3
  import SheetContainer from './SheetContainer';
4
4
 
5
5
  const childId1 = 'sheet-container-TEST-child1';
@@ -31,4 +31,37 @@ describe('<SheetContainer />', () => {
31
31
  const childEl2 = screen.getByText(childContent2);
32
32
  expect(childEl2).toBeTruthy();
33
33
  });
34
+
35
+ it('applies custom className if provided', () => {
36
+ const customClass = 'custom-class';
37
+ render(<SheetContainer className={customClass}>{child1}</SheetContainer>);
38
+ const rootEl = screen.getByTestId('sheet-container');
39
+ expect(rootEl).toBeTruthy();
40
+ expect(rootEl.className).toContain('sheet-container');
41
+ expect(rootEl.className).toContain(customClass);
42
+ });
43
+
44
+ it('calls updateRootElement when className changes (componentDidUpdate)', () => {
45
+ const { rerender } = render(
46
+ <SheetContainer className="first-class">
47
+ <div>Content</div>
48
+ </SheetContainer>,
49
+ );
50
+
51
+ const sheetRoot = document.getElementById('sheet-root');
52
+ expect(sheetRoot).toHaveClass('sheet-container');
53
+ expect(sheetRoot).toHaveClass('first-class');
54
+
55
+ act(() => {
56
+ rerender(
57
+ <SheetContainer className="second-class">
58
+ <div>Content</div>
59
+ </SheetContainer>,
60
+ );
61
+ });
62
+
63
+ expect(sheetRoot).toHaveClass('sheet-container');
64
+ expect(sheetRoot).toHaveClass('second-class');
65
+ expect(sheetRoot).not.toHaveClass('first-class');
66
+ });
34
67
  });
@@ -1,7 +1,10 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<Sheet /> snapshots blocking, left snapshot 1`] = `
4
- <sheet-container>
4
+ <div
5
+ className="sheet-container"
6
+ data-testid="sheet-container"
7
+ >
5
8
  <div
6
9
  className="pgn__sheet-skrim"
7
10
  role="presentation"
@@ -28,11 +31,14 @@ exports[`<Sheet /> snapshots blocking, left snapshot 1`] = `
28
31
  />
29
32
  </div>
30
33
  </focus-on>
31
- </sheet-container>
34
+ </div>
32
35
  `;
33
36
 
34
37
  exports[`<Sheet /> snapshots dark, right snapshot 1`] = `
35
- <sheet-container>
38
+ <div
39
+ className="sheet-container"
40
+ data-testid="sheet-container"
41
+ >
36
42
  <div
37
43
  className="pgn__sheet-skrim hidden"
38
44
  role="presentation"
@@ -59,11 +65,14 @@ exports[`<Sheet /> snapshots dark, right snapshot 1`] = `
59
65
  />
60
66
  </div>
61
67
  </focus-on>
62
- </sheet-container>
68
+ </div>
63
69
  `;
64
70
 
65
71
  exports[`<Sheet /> snapshots default args snapshot: bottom, show, light 1`] = `
66
- <sheet-container>
72
+ <div
73
+ className="sheet-container"
74
+ data-testid="sheet-container"
75
+ >
67
76
  <div
68
77
  className="pgn__sheet-skrim hidden"
69
78
  role="presentation"
@@ -96,5 +105,5 @@ exports[`<Sheet /> snapshots default args snapshot: bottom, show, light 1`] = `
96
105
  </div>
97
106
  </div>
98
107
  </focus-on>
99
- </sheet-container>
108
+ </div>
100
109
  `;
@@ -26,13 +26,16 @@ class Sheet extends React.Component {
26
26
  }
27
27
 
28
28
  renderSheet() {
29
- const { children, position, variant } = this.props;
29
+ const {
30
+ children, position, variant, className,
31
+ } = this.props;
30
32
  return (
31
33
  <div
32
34
  className={classNames(
33
35
  'pgn__sheet-component',
34
36
  `pgn__sheet__${variant}`,
35
37
  position,
38
+ className,
36
39
  )}
37
40
  role="alert"
38
41
  aria-live="polite"
@@ -50,12 +53,13 @@ class Sheet extends React.Component {
50
53
  blocking,
51
54
  show,
52
55
  onClose,
56
+ containerClassName,
53
57
  } = this.props;
54
58
  if (!show) {
55
59
  return null;
56
60
  }
57
61
  return (
58
- <SheetContainer>
62
+ <SheetContainer className={classNames(containerClassName)}>
59
63
  <div
60
64
  className={classNames(
61
65
  'pgn__sheet-skrim',
@@ -80,6 +84,10 @@ Sheet.propTypes = {
80
84
  blocking: PropTypes.bool,
81
85
  /** an element rendered inside the sheet */
82
86
  children: PropTypes.node,
87
+ /** A class that is appended to the sheet container element. */
88
+ containerClassName: PropTypes.string,
89
+ /** A class that is appended to the sheet element. */
90
+ className: PropTypes.string,
83
91
  /** a string designating the sheet's position on the window */
84
92
  position: PropTypes.oneOf([
85
93
  POSITIONS.left,
@@ -102,6 +110,8 @@ Sheet.defaultProps = {
102
110
  show: true,
103
111
  onClose: () => {},
104
112
  variant: VARIANTS.light,
113
+ containerClassName: undefined,
114
+ className: undefined,
105
115
  };
106
116
 
107
117
  export default Sheet;
@@ -1,20 +1,32 @@
1
- import React, { forwardRef } from 'react';
2
- import PropTypes from 'prop-types';
1
+ import React, { forwardRef, ForwardedRef } from 'react';
3
2
  import classNames from 'classnames';
4
3
 
5
- const DIRECTION_VARIANTS = [
6
- 'horizontal',
7
- 'vertical',
8
- ];
4
+ interface StackProps {
5
+ /** Specifies the content of the `Stack`. */
6
+ children: React.ReactNode;
7
+ /** Specifies direction of the children blocks (column/row). */
8
+ direction?: 'horizontal' | 'vertical';
9
+ /**
10
+ * Specifies inner space between children blocks.
11
+ *
12
+ * Valid values are based on `the spacing classes`:
13
+ * `0, 0.5, ... 6`.
14
+ */
15
+ gap?: number;
16
+ /** Specifies the order of the children. */
17
+ reversed?: boolean;
18
+ /** Specifies an additional `className` to add to the base element. */
19
+ className?: string;
20
+ }
9
21
 
10
22
  const Stack = forwardRef(({
11
- direction,
12
- gap,
13
- reversed,
23
+ direction = 'vertical',
24
+ gap = 0,
25
+ reversed = false,
14
26
  children,
15
27
  className,
16
28
  ...rest
17
- }, ref) => (
29
+ }: StackProps, ref: ForwardedRef<HTMLDivElement>) => (
18
30
  <div
19
31
  ref={ref}
20
32
  className={classNames(
@@ -29,29 +41,4 @@ const Stack = forwardRef(({
29
41
  </div>
30
42
  ));
31
43
 
32
- Stack.propTypes = {
33
- /** Specifies the content of the `Stack`. */
34
- children: PropTypes.node.isRequired,
35
- /** Specifies direction of the children blocks (column/row). */
36
- direction: PropTypes.oneOf(DIRECTION_VARIANTS),
37
- /**
38
- * Specifies inner space between children blocks.
39
- *
40
- * Valid values are based on `the spacing classes`:
41
- * `0, 0.5, ... 6`.
42
- */
43
- gap: PropTypes.number,
44
- /** Specifies the order of the children. */
45
- reversed: PropTypes.bool,
46
- /** Specifies an additional `className` to add to the base element. */
47
- className: PropTypes.string,
48
- };
49
-
50
- Stack.defaultProps = {
51
- direction: 'vertical',
52
- gap: 0,
53
- className: undefined,
54
- reversed: false,
55
- };
56
-
57
44
  export default Stack;
@@ -18,7 +18,6 @@ const Sticky = React.forwardRef(({
18
18
  const defaultRef = React.useRef();
19
19
  const resolvedRef = ref || defaultRef;
20
20
 
21
- // eslint-disable-next-line consistent-return
22
21
  useLayoutEffect(() => {
23
22
  if (resolvedRef.current) {
24
23
  const stickyElement = resolvedRef.current;
@@ -45,6 +44,7 @@ const Sticky = React.forwardRef(({
45
44
  observer.unobserve(stickyElement);
46
45
  };
47
46
  }
47
+ return undefined;
48
48
  }, [position, resolvedRef]);
49
49
 
50
50
  return (
@@ -1,33 +1,25 @@
1
1
  import React from 'react';
2
- import PropTypes from 'prop-types';
3
2
  import BaseTab from 'react-bootstrap/Tab';
4
3
 
5
- function Tab(props) {
6
- return <BaseTab {...props} />;
7
- }
8
-
9
- Tab.propTypes = {
4
+ interface TabProps {
10
5
  /** Specifies the `Tab` navigation title. */
11
- title: PropTypes.node.isRequired,
6
+ title: React.ReactNode;
12
7
  /** Specifies notification bubble content. It appears on the top right of the `Tab`. */
13
- notification: PropTypes.node,
8
+ notification?: React.ReactNode;
14
9
  /** Specifies whether `Tab` is disabled. */
15
- disabled: PropTypes.bool,
10
+ disabled?: boolean;
16
11
  /**
17
12
  * A unique identifier for the Component, the `eventKey` makes it distinguishable
18
13
  * from others in a set. Similar to React's `key` prop, in that it only needs to be
19
14
  * unique amongst the Components siblings, not globally.
20
15
  */
21
- eventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
16
+ eventKey?: string | number;
22
17
  /** Specifies class name to append to the base element. */
23
- tabClassName: PropTypes.string,
24
- };
18
+ tabClassName?: string;
19
+ }
25
20
 
26
- Tab.defaultProps = {
27
- notification: undefined,
28
- disabled: undefined,
29
- eventKey: undefined,
30
- tabClassName: undefined,
31
- };
21
+ function Tab(props: TabProps) {
22
+ return <BaseTab {...props} />;
23
+ }
32
24
 
33
25
  export default Tab;