diff --git a/src/Container/Container.test.jsx b/src/Container/Container.test.tsx
similarity index 62%
rename from src/Container/Container.test.jsx
rename to src/Container/Container.test.tsx
index b3a6faaf7c..82efafa24b 100644
--- a/src/Container/Container.test.jsx
+++ b/src/Container/Container.test.tsx
@@ -1,8 +1,8 @@
import React from 'react';
import { render } from '@testing-library/react';
-import Container from '.';
+import Container, { type ContainerSize } from '.';
-const getClassNames = (container) => container.className.split(' ');
+const getClassNames = (container: HTMLElement) => container.className.split(' ');
describe('', () => {
it('displays children', () => {
@@ -12,32 +12,38 @@ describe('', () => {
it('adds the .container-fluid class', () => {
const { container } = render(Content);
- const containerElement = container.firstChild;
+ const containerElement = container.firstChild as HTMLElement;
expect(getClassNames(containerElement)).toContain('container-fluid');
});
it('adds the .container class', () => {
const { container } = render(Content);
- const containerElement = container.firstChild;
- expect(getClassNames(containerElement)).toContain('container');
+ const containerElement = container.firstChild as HTMLElement;
+ expect(getClassNames(containerElement!)).toContain('container');
expect(getClassNames(containerElement)).not.toContain('container-fluid');
});
- ['xs', 'sm', 'md', 'lg', 'xl'].forEach((size) => {
+ ['xs', 'sm', 'md', 'lg', 'xl'].forEach((size: ContainerSize) => {
it(`adds the .container-mw-${size} class`, () => {
const { container } = render(Content);
- const containerElement = container.firstChild;
+ const containerElement = container.firstChild as HTMLElement;
expect(getClassNames(containerElement)).toContain(`container-mw-${size}`);
});
});
+ it('does not add a size class when size is not specified', () => {
+ const { container } = render(Content);
+ const containerElement = container.firstChild as HTMLElement;
+ expect(getClassNames(containerElement)).toEqual(['container-fluid']);
+ });
+
it('preserves custom class names', () => {
const { container } = render(
Content
,
);
- const containerElement = container.firstChild;
+ const containerElement = container.firstChild as HTMLElement;
expect(getClassNames(containerElement)).toContain('container-mw-md');
expect(getClassNames(containerElement)).toContain('container-fluid');
expect(getClassNames(containerElement)).toContain('custom-class');
diff --git a/src/Container/README.md b/src/Container/README.md
index de2bdab76c..8c2f6a4775 100644
--- a/src/Container/README.md
+++ b/src/Container/README.md
@@ -19,6 +19,10 @@ The base container to contain, pad, and center content in the viewport. This com
```jsx live
+
+ The content in this container doesn't have a max width
+
+
The content in this container won't exceed the extra large width.
diff --git a/src/Container/index.jsx b/src/Container/index.jsx
deleted file mode 100644
index a2f38de7bb..0000000000
--- a/src/Container/index.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import React, { forwardRef } from 'react';
-import classNames from 'classnames';
-import RBContainer from 'react-bootstrap/Container';
-import PropTypes from 'prop-types';
-
-const SIZE_CLASS_NAMES = {
- xs: 'container-mw-xs',
- sm: 'container-mw-sm',
- md: 'container-mw-md',
- lg: 'container-mw-lg',
- xl: 'container-mw-xl',
-};
-
-const Container = forwardRef(({ size, children, ...props }, ref) => (
-
- {children}
-
-));
-
-Container.propTypes = {
- ...RBContainer.propTypes,
- /** Override the base element */
- as: PropTypes.elementType,
- /** Specifies the contents of the container */
- children: PropTypes.node,
- /** Fill all available space at any breakpoint */
- fluid: PropTypes.bool,
- /** Set the maximum width for the container */
- size: PropTypes.oneOf(Object.keys(SIZE_CLASS_NAMES)),
- /** Overrides underlying component base CSS class name */
- bsPrefix: PropTypes.string,
-};
-
-Container.defaultProps = {
- as: 'div',
- children: undefined,
- fluid: true,
- size: undefined,
- bsPrefix: 'container',
-};
-
-export default Container;
diff --git a/src/Container/index.tsx b/src/Container/index.tsx
new file mode 100644
index 0000000000..ea95d58867
--- /dev/null
+++ b/src/Container/index.tsx
@@ -0,0 +1,64 @@
+/* eslint-disable react/require-default-props */
+import React from 'react';
+import classNames from 'classnames';
+import PropTypes from 'prop-types';
+import RBContainer, { type ContainerProps as RBContainerProps } from 'react-bootstrap/Container';
+
+import type { ComponentWithAsProp } from '../utils/types/bootstrap';
+
+enum ContainerSizeClass {
+ xs = 'container-mw-xs',
+ sm = 'container-mw-sm',
+ md = 'container-mw-md',
+ lg = 'container-mw-lg',
+ xl = 'container-mw-xl',
+}
+
+export type ContainerSize = keyof typeof ContainerSizeClass;
+
+interface ContainerProps extends RBContainerProps {
+ size?: ContainerSize;
+}
+
+type ContainerType = ComponentWithAsProp<'div', ContainerProps>;
+
+const Container: ContainerType = React.forwardRef(({
+ size,
+ children,
+ ...props
+}, ref) => (
+
+ {children}
+
+));
+
+Container.propTypes = {
+ ...RBContainer.propTypes,
+ /** Override the base element */
+ as: PropTypes.elementType,
+ /** Specifies the contents of the container */
+ children: PropTypes.node,
+ /** Fill all available space at any breakpoint */
+ fluid: PropTypes.bool,
+ /** Set the maximum width for the container. Omiting the prop will remove the max-width */
+ size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
+ /** Overrides underlying component base CSS class name */
+ bsPrefix: PropTypes.string,
+};
+
+Container.defaultProps = {
+ as: 'div',
+ children: undefined,
+ fluid: true,
+ size: undefined,
+ bsPrefix: 'container',
+};
+
+export default Container;
diff --git a/src/index.d.ts b/src/index.d.ts
index a680a1ac86..f28715349d 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -8,6 +8,7 @@ export { default as Bubble } from './Bubble';
export { default as Button, ButtonGroup, ButtonToolbar } from './Button';
export { default as Chip, CHIP_PGN_CLASS } from './Chip';
export { default as ChipCarousel } from './ChipCarousel';
+export { default as Container, ContainerSize } from './Container';
export { default as Hyperlink, HYPER_LINK_EXTERNAL_LINK_ALT_TEXT, HYPER_LINK_EXTERNAL_LINK_TITLE } from './Hyperlink';
export { default as Icon } from './Icon';
export { default as IconButton, IconButtonWithTooltip } from './IconButton';
@@ -41,7 +42,6 @@ export const
export const CheckBox: any; // from './CheckBox';
export const CheckBoxGroup: any; // from './CheckBoxGroup';
export const CloseButton: any; // from './CloseButton';
-export const Container: any; // from './Container';
export const Layout: any, Col: any, Row: any; // from './Layout';
export const Collapse: any; // from './Collapse';
export const Collapsible: any; // from './Collapsible';
diff --git a/www/src/context/SettingsContext.tsx b/www/src/context/SettingsContext.tsx
index 777c3a73bb..156ae8f3f3 100644
--- a/www/src/context/SettingsContext.tsx
+++ b/www/src/context/SettingsContext.tsx
@@ -2,7 +2,7 @@ import React, { createContext, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import { IntlProvider } from 'react-intl';
-import { messages } from '~paragon-react';
+import { messages, type ContainerSize } from '~paragon-react';
import { THEMES, DEFAULT_THEME } from '../../theme-config';
import { SETTINGS_EVENTS, sendUserAnalyticsEvent } from '../../segment-events';
@@ -12,7 +12,7 @@ export interface IDefaultValue {
theme?: string,
direction?: string,
language?: string,
- containerWidth?: string,
+ containerWidth?: ContainerSize,
},
theme?: string,
handleSettingsChange: Function,
@@ -35,7 +35,7 @@ function SettingsContextProvider({ children }) {
theme: DEFAULT_THEME,
direction: 'ltr',
language: 'en',
- containerWidth: 'md',
+ containerWidth: 'md' as ContainerSize,
});
const [showSettings, setShowSettings] = useState(false);