diff --git a/src/Container/index.jsx b/src/Container/index.jsx index 84f3192ac1..a2f38de7bb 100644 --- a/src/Container/index.jsx +++ b/src/Container/index.jsx @@ -28,11 +28,14 @@ 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 = { @@ -40,6 +43,7 @@ Container.defaultProps = { children: undefined, fluid: true, size: undefined, + bsPrefix: 'container', }; export default Container; diff --git a/src/Dropdown/index.jsx b/src/Dropdown/index.jsx index dbc17f4174..d617929ca6 100644 --- a/src/Dropdown/index.jsx +++ b/src/Dropdown/index.jsx @@ -69,6 +69,7 @@ const Dropdown = React.forwardRef( ); }, ); + Dropdown.propTypes = { autoClose: PropTypes.oneOfType([ PropTypes.string, @@ -79,6 +80,7 @@ Dropdown.propTypes = { show: PropTypes.bool, variant: PropTypes.oneOf(['light', 'dark']), }; + Dropdown.defaultProps = { autoClose: true, className: '', @@ -127,9 +129,11 @@ Dropdown.Item = React.forwardRef( ); }, ); + Dropdown.Item.propTypes = { className: PropTypes.string, }; + Dropdown.Item.defaultProps = { className: undefined, }; diff --git a/src/Form/FormSwitch.jsx b/src/Form/FormSwitch.jsx index 59c5f8002b..7504933a4c 100644 --- a/src/Form/FormSwitch.jsx +++ b/src/Form/FormSwitch.jsx @@ -79,8 +79,11 @@ FormSwitch.propTypes = { children: PropTypes.node.isRequired, /** Specifies class name to append to the base element. */ className: PropTypes.string, + /** Specifies class name to append to the label element. */ labelClassName: PropTypes.string, + /** Specifies helper text to display below the switch. */ helperText: PropTypes.node, + /** Determines whether the label should float to the left when the switch is active. */ floatLabelLeft: PropTypes.bool, }; diff --git a/src/Hyperlink/index.jsx b/src/Hyperlink/index.jsx index cb21b3cc2c..7c4a61f882 100644 --- a/src/Hyperlink/index.jsx +++ b/src/Hyperlink/index.jsx @@ -101,18 +101,19 @@ Hyperlink.propTypes = { children: PropTypes.node.isRequired, /** Custom class names for the hyperlink */ className: PropTypes.string, - /** specifies where the link should open. The default behavior is `_self`, which means that the URL will be loaded into the same browsing context as the current one. If the target is `_blank` (opening a new window) `rel='noopener'` will be added to the anchor tag to prevent any potential [reverse tabnabbing attack](https://www.owasp.org/index.php/Reverse_Tabnabbing). - */ + /** specifies where the link should open. The default behavior is `_self`, which means that the URL will be + * loaded into the same browsing context as the current one. + * If the target is `_blank` (opening a new window) `rel='noopener'` will be added to the anchor tag to prevent + * any potential [reverse tabnabbing attack](https://www.owasp.org/index.php/Reverse_Tabnabbing). + */ target: PropTypes.string, /** specifies the callback function when the link is clicked */ onClick: PropTypes.func, - // eslint-disable-next-line max-len /** specifies the text for links with a `_blank` target (which loads the URL in a new browsing context). */ externalLinkAlternativeText: isRequiredIf( PropTypes.string, props => props.target === '_blank', ), - // eslint-disable-next-line max-len /** specifies the title for links with a `_blank` target (which loads the URL in a new browsing context). */ externalLinkTitle: isRequiredIf( PropTypes.string, @@ -120,9 +121,9 @@ Hyperlink.propTypes = { ), /** type of hyperlink */ variant: PropTypes.oneOf(['default', 'muted', 'brand']), - /** specify the link style. By default it will be underlined. */ + /** specify the link style. By default, it will be underlined. */ isInline: PropTypes.bool, - /** specify if we need to show launch Icon. By default it will be visible. */ + /** specify if we need to show launch Icon. By default, it will be visible. */ showLaunchIcon: PropTypes.bool, }; diff --git a/src/Icon/index.jsx b/src/Icon/index.jsx index cb01fb1ad0..482b37d03b 100644 --- a/src/Icon/index.jsx +++ b/src/Icon/index.jsx @@ -70,28 +70,35 @@ function Icon({ } Icon.propTypes = { - // eslint-disable-next-line max-len - /** An icon component to render. Example import of a Paragon icon component: `import { Check } from '@edx/paragon/dist/icon';` */ + /** + * An icon component to render. + * Example import of a Paragon icon component: `import { Check } from '@edx/paragon/icons';` + */ src: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), /** HTML element attributes to pass through to the underlying svg element */ svgAttrs: PropTypes.shape({ 'aria-label': PropTypes.string, 'aria-labelledby': PropTypes.string, }), - // eslint-disable-next-line max-len - /** the `id` property of the Icon element, by default this value is generated with the `newId` function with the `prefix` of `Icon`. */ + /** + * the `id` property of the Icon element, by default this value is generated + * with the `newId` function with the `prefix` of `Icon`. + */ id: PropTypes.string, - // eslint-disable-next-line max-len /** The size of the icon. */ size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']), - // eslint-disable-next-line max-len /** A class name that will define what the Icon looks like. */ className: PropTypes.string, - // eslint-disable-next-line max-len - /** a boolean that determines the value of `aria-hidden` attribute on the Icon span, this value is `true` by default. */ + /** + * a boolean that determines the value of `aria-hidden` attribute on the Icon span, + * this value is `true` by default. + */ hidden: PropTypes.bool, - // eslint-disable-next-line max-len - /** a string or an element that will be used on a secondary span leveraging the `sr-only` style for screenreader only text, this value is `undefined` by default. This value is recommended for use unless the Icon is being used in a way that is purely decorative or provides no additional context for screen reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags. + /** + * a string or an element that will be used on a secondary span leveraging the `sr-only` style + * for screenreader only text, this value is `undefined` by default. This value is recommended for use unless + * the Icon is being used in a way that is purely decorative or provides no additional context for screen + * reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags. */ screenReaderText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), }; diff --git a/src/IconButton/index.jsx b/src/IconButton/index.jsx index acb22265e8..3c07593435 100644 --- a/src/IconButton/index.jsx +++ b/src/IconButton/index.jsx @@ -87,7 +87,7 @@ IconButton.propTypes = { alt: PropTypes.string.isRequired, /** Changes icon styles for dark background */ invertColors: PropTypes.bool, - /** Accepts a React fontawesome icon. https://fontawesome.com/how-to-use/on-the-web/using-with/react */ + /** Accepts a React fontawesome icon. */ icon: PropTypes.shape({ prefix: PropTypes.string, iconName: PropTypes.string, diff --git a/src/Layout/index.jsx b/src/Layout/index.jsx index 46fdbb553b..773b27b245 100644 --- a/src/Layout/index.jsx +++ b/src/Layout/index.jsx @@ -84,9 +84,6 @@ SIZES.forEach(size => { Layout.defaultProps[size] = sizeDefaultProps; }); -export { - Col, - Row, -}; +export { Col, Row }; Layout.Element = LayoutElement; export default Layout; diff --git a/src/Modal/ModalDialog.jsx b/src/Modal/ModalDialog.jsx index afbe102520..926d4bdcea 100644 --- a/src/Modal/ModalDialog.jsx +++ b/src/Modal/ModalDialog.jsx @@ -116,6 +116,9 @@ ModalDialog.propTypes = { * Prevent clicking on the backdrop to close the modal */ isBlocking: PropTypes.bool, + /** + * Specifies the z-index of the modal + */ zIndex: PropTypes.number, }; diff --git a/src/Modal/index.jsx b/src/Modal/index.jsx index ee9c8c1fb8..8e2070c38e 100644 --- a/src/Modal/index.jsx +++ b/src/Modal/index.jsx @@ -1,4 +1,3 @@ -/* eslint-disable max-len */ import React from 'react'; import ReactDOM from 'react-dom'; import classNames from 'classnames'; @@ -271,21 +270,26 @@ class Modal extends React.Component { Modal.propTypes = { /** specifies whether the modal renders open or closed on the initial render. It defaults to false. */ open: PropTypes.bool, - /** is the selector for an element in the dom which the modal should be rendered under. It uses querySelector to find the first element that matches that selector, and then creates a react portal to a div underneath the parent element. - */ + /** is the selector for an element in the dom which the modal should be rendered under. + * It uses querySelector to find the first element that matches that selector, + * and then creates a React portal to a div underneath the parent element. + */ parentSelector: PropTypes.string, /** a string or an element that is rendered inside of the modal title, above the modal body. */ title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, /** a string or an element that is rendered inside of the modal body, between the title and the footer. */ body: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, - /** an array of either elements or shapes that take the form of the buttonPropTypes. See the [buttonPropTypes](https://github.com/openedx/paragon/blob/master/src/Button/index.jsx#L40) for a list of acceptable props to pass as part of a button. */ + /** an array of either elements or shapes that take the form of the buttonPropTypes. + * See the [buttonPropTypes](https://github.com/openedx/paragon/blob/master/src/Button/index.jsx#L40) + * for a list of acceptable props to pass as part of a button. */ buttons: PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.element, PropTypes.shape({}), // TODO: Only accept nodes in the future ])), /** specifies the display text of the default Close button. It defaults to "Close". */ closeText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - /** a function that is called on close. It can be used to perform actions upon closing of the modal, such as restoring focus to the previous logical focusable element. */ + /** a function that is called on close. It can be used to perform actions upon closing of the modal, + * such as restoring focus to the previous logical focusable element. */ onClose: PropTypes.func.isRequired, variant: PropTypes.shape({ status: PropTypes.string, @@ -295,7 +299,8 @@ Modal.propTypes = { /** specifies whether a close button is rendered in the modal header. It defaults to true. */ renderHeaderCloseButton: PropTypes.bool, /** - * Specifies optional classes to add to the element with the '.modal-dialog' class. See Bootstrap documentation for possible classes. Some options: modal-lg, modal-sm, modal-dialog-centered + * Specifies optional classes to add to the element with the '.modal-dialog' class. + * See Bootstrap documentation for possible classes. Some options: modal-lg, modal-sm, modal-dialog-centered */ dialogClassName: PropTypes.string, }; diff --git a/src/Popover/README.md b/src/Popover/README.md index fab24b10f0..5f3036531b 100644 --- a/src/Popover/README.md +++ b/src/Popover/README.md @@ -3,7 +3,6 @@ title: 'Popover' type: 'component' components: - Popover -- WrapperPopover - PopoverTitle - PopoverContent categories: diff --git a/src/Popover/index.jsx b/src/Popover/index.jsx index 1636be5a93..07be9806a0 100644 --- a/src/Popover/index.jsx +++ b/src/Popover/index.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import Popover from 'react-bootstrap/Popover'; +import BasePopover from 'react-bootstrap/Popover'; import BasePopoverTitle from 'react-bootstrap/PopoverTitle'; import BasePopoverContent from 'react-bootstrap/PopoverContent'; @@ -13,18 +13,18 @@ const PLACEMENT_VARIANTS = [ 'right', ]; -const WrapperPopover = React.forwardRef(({ +const Popover = React.forwardRef(({ children, variant, ...props }, ref) => ( - {children} - + )); function PopoverTitle(props) { @@ -44,8 +44,8 @@ const commonPropTypes = { PopoverTitle.propTypes = commonPropTypes; PopoverContent.propTypes = commonPropTypes; -WrapperPopover.propTypes = { - ...Popover.propTypes, +Popover.propTypes = { + ...BasePopover.propTypes, /** An html id attribute, necessary for accessibility. */ id: PropTypes.string.isRequired, /** @@ -88,8 +88,8 @@ WrapperPopover.propTypes = { variant: PropTypes.string, }; -WrapperPopover.defaultProps = { - ...Popover.defaultProps, +Popover.defaultProps = { + ...BasePopover.defaultProps, placement: 'right', title: undefined, arrowProps: undefined, @@ -111,8 +111,8 @@ PopoverContent.defaultProps = { bsPrefix: 'popover-body', }; -WrapperPopover.Title = PopoverTitle; -WrapperPopover.Content = PopoverContent; +Popover.Title = PopoverTitle; +Popover.Content = PopoverContent; export { PopoverTitle, PopoverContent }; -export default WrapperPopover; +export default Popover; diff --git a/src/SearchField/SearchFieldAdvanced.jsx b/src/SearchField/SearchFieldAdvanced.jsx index a15de6bc53..75b261d05c 100644 --- a/src/SearchField/SearchFieldAdvanced.jsx +++ b/src/SearchField/SearchFieldAdvanced.jsx @@ -1,4 +1,3 @@ -/* eslint-disable max-len */ import React, { useRef, createContext, useState, useEffect, } from 'react'; @@ -138,27 +137,32 @@ SearchFieldAdvanced.propTypes = { onSubmit: PropTypes.func.isRequired, /** specifies a custom class name. */ className: PropTypes.string, - /** specifies a callback function for when the user loses focus in the `SearchField` component. The default is an empty function. For example: + /** specifies a callback function for when the user loses focus in the `SearchField` component. + * The default is an empty function. For example: ```jsx console.log(event)} /> ``` */ onBlur: PropTypes.func, - /** specifies a callback function for when the value in `SearchField` is changed by the user. The default is an empty function. For example: + /** specifies a callback function for when the value in `SearchField` is changed by the user. + * The default is an empty function. For example: ```jsx console.log(value)} /> ``` */ onChange: PropTypes.func, - /** specifies a callback function for when the value in `SearchField` is cleared by the user. The default is an empty function. For example: + /** specifies a callback function for when the value in `SearchField` is cleared by the user. + * The default is an empty function. For example: ```jsx console.log('search cleared')} /> ``` */ onClear: PropTypes.func, - /** specifies a callback function for when the user focuses in the `SearchField` component. The default is an empty function. For example: + /** specifies a callback function for when the user focuses in the `SearchField` component. + * The default is an empty function. For example: ```jsx console.log(event)} /> ``` */ onFocus: PropTypes.func, - /** specifies the screenreader text for both the clear and submit buttons (e.g., for i18n translations). The default is `{ label: 'search', clearButton: 'clear search', searchButton: 'submit search' }`. */ + /** specifies the screenreader text for both the clear and submit buttons (e.g., for i18n translations). + * The default is `{ label: 'search', clearButton: 'clear search', searchButton: 'submit search' }`. */ screenReaderText: PropTypes.shape({ label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, submitButton: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, @@ -171,7 +175,8 @@ SearchFieldAdvanced.propTypes = { submit: PropTypes.element.isRequired, clear: PropTypes.element, }), - /** specifies the aria-label attribute on the form element. This is useful if you use the `SearchField` component more than once on a page. */ + /** specifies the aria-label attribute on the form element. This is useful if you use the `SearchField` component + * more than once on a page. */ formAriaLabel: PropTypes.string, /** Specifies whether the `SearchField` is disabled. */ disabled: PropTypes.bool, diff --git a/src/SearchField/SearchFieldLabel.jsx b/src/SearchField/SearchFieldLabel.jsx index 9986eb7234..c310328aa8 100644 --- a/src/SearchField/SearchFieldLabel.jsx +++ b/src/SearchField/SearchFieldLabel.jsx @@ -1,4 +1,3 @@ -/* eslint-disable max-len */ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; @@ -21,8 +20,9 @@ function SearchFieldLabel({ children, ...props }) { SearchFieldLabel.propTypes = { /** - * specifies the label to use for the input field (e.g., for i18n translations). Note: if `children` is not provided, - * a screenreader-only label will be used in its placed based on the `screenReaderText.label` prop for `SearchField.Advanced`. + * specifies the label to use for the input field (e.g., for i18n translations). + * Note: if `children` is not provided, a screenreader-only label will be used in + * its placed based on the `screenReaderText.label` prop for `SearchField.Advanced`. */ children: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), }; diff --git a/src/SearchField/index.jsx b/src/SearchField/index.jsx index af0fd63458..d4a842c111 100644 --- a/src/SearchField/index.jsx +++ b/src/SearchField/index.jsx @@ -1,4 +1,3 @@ -/* eslint-disable max-len */ import React, { useCallback } from 'react'; import PropTypes from 'prop-types'; diff --git a/www/src/components/PropsTable.tsx b/www/src/components/PropsTable.tsx index 5bd2d87a05..eff2e99199 100644 --- a/www/src/components/PropsTable.tsx +++ b/www/src/components/PropsTable.tsx @@ -1,11 +1,33 @@ import React from 'react'; import PropTypes from 'prop-types'; import { MDXRenderer } from 'gatsby-plugin-mdx'; -import { Badge, Card } from '~paragon-react'; +import { Badge, Card, Hyperlink } from '~paragon-react'; import PropType from './PropType'; const IGNORED_COMPONENT_PROPS = ['intl']; +const BOOTSTRAP_BASE_URL = 'https://react-bootstrap-v4.netlify.app/components'; + +const bootstrapLinks = { + Button: `${BOOTSTRAP_BASE_URL}/buttons/#button-props`, + Card: `${BOOTSTRAP_BASE_URL}/cards/#card-props`, + CardBody: `${BOOTSTRAP_BASE_URL}/cards/#card-body-props`, + CardDeck: `${BOOTSTRAP_BASE_URL}/cards/#card-deck-props`, + Dropdown: `${BOOTSTRAP_BASE_URL}/dropdowns/#dropdown-props`, + DropdownToggle: `${BOOTSTRAP_BASE_URL}/dropdowns/#dropdown-toggle-props`, + DropdownItem: `${BOOTSTRAP_BASE_URL}/dropdowns/#dropdown-item-props`, + DropdownMenu: `${BOOTSTRAP_BASE_URL}/dropdowns/#dropdown-menu-props`, + DropdownButton: `${BOOTSTRAP_BASE_URL}/dropdowns/#dropdown-button-props`, + FormControl: `${BOOTSTRAP_BASE_URL}/forms/#form-control-props`, + Nav: `${BOOTSTRAP_BASE_URL}/navs/#nav-props`, + Popover: `${BOOTSTRAP_BASE_URL}/overlays/#popover-props`, + ProgressBar: `${BOOTSTRAP_BASE_URL}/progress/#progress-bar-props`, + Spinner: `${BOOTSTRAP_BASE_URL}/spinners/#spinner-props`, + Tabs: `${BOOTSTRAP_BASE_URL}/tabs/#tabs-api`, + Tab: `${BOOTSTRAP_BASE_URL}/tabs/#tab-props`, + Toast: `${BOOTSTRAP_BASE_URL}/toasts/#toast-props`, +}; + export type DefaultValueTypes = { value: string | undefined, }; @@ -92,10 +114,20 @@ export interface IPropsTable { } function PropsTable({ props: componentProps, displayName, content }: IPropsTable) { + const bootstrapLink = bootstrapLinks[displayName]; + return ( {content &&

{content}

} + {bootstrapLink && ( +

+ This is a pass through component from React-Bootstrap, see original props documentation{' '} + + here. + +

+ )} {componentProps.length > 0 ? (
    {componentProps