diff --git a/components/common/Button.js b/components/common/Button.js index 5e92d0d8..0cdb5fbc 100644 --- a/components/common/Button.js +++ b/components/common/Button.js @@ -1,10 +1,11 @@ import React from 'react'; +import PropTypes from 'prop-types'; import ReactTooltip from 'react-tooltip'; import classNames from 'classnames'; import Icon from './Icon'; import styles from './Button.module.css'; -export default function Button({ +function Button({ type = 'button', icon, size, @@ -43,3 +44,19 @@ export default function Button({ ); } + +Button.propTypes = { + type: PropTypes.oneOf(['button', 'submit', 'reset']), + icon: PropTypes.node, + size: PropTypes.oneOf(['xlarge', 'large', 'medium', 'small', 'xsmall']), + variant: PropTypes.oneOf(['action', 'danger', 'light']), + children: PropTypes.node, + className: PropTypes.string, + tooltip: PropTypes.node, + tooltipId: PropTypes.string, + disabled: PropTypes.bool, + iconRight: PropTypes.bool, + onClick: PropTypes.func, +}; + +export default Button; diff --git a/components/common/ButtonGroup.js b/components/common/ButtonGroup.js index c91bb743..353ce690 100644 --- a/components/common/ButtonGroup.js +++ b/components/common/ButtonGroup.js @@ -1,16 +1,10 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import Button from './Button'; import styles from './ButtonGroup.module.css'; -export default function ButtonGroup({ - items = [], - selectedItem, - className, - size, - icon, - onClick = () => {}, -}) { +function ButtonGroup({ items = [], selectedItem, className, size, icon, onClick = () => {} }) { return (
{items.map(item => { @@ -30,3 +24,19 @@ export default function ButtonGroup({
); } + +ButtonGroup.propTypes = { + items: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.node, + value: PropTypes.any.isRequired, + }), + ), + selectedItem: PropTypes.any, + className: PropTypes.string, + size: PropTypes.oneOf(['xlarge', 'large', 'medium', 'small', 'xsmall']), + icon: PropTypes.node, + onClick: PropTypes.func, +}; + +export default ButtonGroup; diff --git a/components/common/Checkbox.js b/components/common/Checkbox.js index 1a66a258..67eea80d 100644 --- a/components/common/Checkbox.js +++ b/components/common/Checkbox.js @@ -1,9 +1,10 @@ import React, { useRef } from 'react'; +import PropTypes from 'prop-types'; import Icon from 'components/common/Icon'; import Check from 'assets/check.svg'; import styles from './Checkbox.module.css'; -export default function Checkbox({ name, value, label, onChange }) { +function Checkbox({ name, value, label, onChange }) { const ref = useRef(); return ( @@ -25,3 +26,12 @@ export default function Checkbox({ name, value, label, onChange }) { ); } + +Checkbox.propTypes = { + name: PropTypes.string, + value: PropTypes.any, + label: PropTypes.node, + onChange: PropTypes.func, +}; + +export default Checkbox; diff --git a/components/common/CopyButton.js b/components/common/CopyButton.js index 460c68ac..b300ef31 100644 --- a/components/common/CopyButton.js +++ b/components/common/CopyButton.js @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import PropTypes from 'prop-types'; import Button from './Button'; import { FormattedMessage } from 'react-intl'; @@ -6,7 +7,7 @@ const defaultText = ( ); -export default function CopyButton({ element, ...props }) { +function CopyButton({ element, ...props }) { const [text, setText] = useState(defaultText); function handleClick() { @@ -24,3 +25,13 @@ export default function CopyButton({ element, ...props }) { ); } + +CopyButton.propTypes = { + element: PropTypes.shape({ + current: PropTypes.shape({ + select: PropTypes.func.isRequired, + }), + }), +}; + +export default CopyButton; diff --git a/components/common/DateFilter.js b/components/common/DateFilter.js index fb76a081..6279d338 100644 --- a/components/common/DateFilter.js +++ b/components/common/DateFilter.js @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import { endOfYear, isSameDay } from 'date-fns'; import Modal from './Modal'; @@ -54,7 +55,7 @@ const filterOptions = [ }, ]; -export default function DateFilter({ value, startDate, endDate, onChange, className }) { +function DateFilter({ value, startDate, endDate, onChange, className }) { const [showPicker, setShowPicker] = useState(false); const displayValue = value === 'custom' ? ( @@ -117,3 +118,13 @@ const CustomRange = ({ startDate, endDate, onClick }) => { ); }; + +DateFilter.propTypes = { + value: PropTypes.string, + startDate: PropTypes.instanceOf(Date), + endDate: PropTypes.instanceOf(Date), + onChange: PropTypes.func, + className: PropTypes.string, +}; + +export default DateFilter; diff --git a/components/common/Dot.js b/components/common/Dot.js index d5dcf914..81454c48 100644 --- a/components/common/Dot.js +++ b/components/common/Dot.js @@ -1,8 +1,9 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Dot.module.css'; -export default function Dot({ color, size, className }) { +function Dot({ color, size, className }) { return (
); } + +Dot.propTypes = { + color: PropTypes.string, + size: PropTypes.oneOf(['small', 'large']), + className: PropTypes.string, +}; + +export default Dot; diff --git a/components/common/DropDown.js b/components/common/DropDown.js index 3b3be39e..00d20e34 100644 --- a/components/common/DropDown.js +++ b/components/common/DropDown.js @@ -1,4 +1,5 @@ import React, { useState, useRef } from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import Menu from './Menu'; import useDocumentClick from 'hooks/useDocumentClick'; @@ -6,13 +7,7 @@ import Chevron from 'assets/chevron-down.svg'; import styles from './Dropdown.module.css'; import Icon from './Icon'; -export default function DropDown({ - value, - className, - menuClassName, - options = [], - onChange = () => {}, -}) { +function DropDown({ value, className, menuClassName, options = [], onChange = () => {} }) { const [showMenu, setShowMenu] = useState(false); const ref = useRef(); const selectedOption = options.find(e => e.value === value); @@ -52,3 +47,18 @@ export default function DropDown({
); } + +DropDown.propTypes = { + value: PropTypes.any, + className: PropTypes.string, + menuClassName: PropTypes.string, + options: PropTypes.arrayOf( + PropTypes.shape({ + value: PropTypes.any.isRequired, + label: PropTypes.node, + }), + ), + onChange: PropTypes.func, +}; + +export default DropDown; diff --git a/components/common/EmptyPlaceholder.js b/components/common/EmptyPlaceholder.js index 26a9fcbf..a223814d 100644 --- a/components/common/EmptyPlaceholder.js +++ b/components/common/EmptyPlaceholder.js @@ -1,9 +1,10 @@ import React from 'react'; +import PropTypes from 'prop-types'; import Icon from 'components/common/Icon'; import Logo from 'assets/logo.svg'; import styles from './EmptyPlaceholder.module.css'; -export default function EmptyPlaceholder({ msg, children }) { +function EmptyPlaceholder({ msg, children }) { return (
} size="xlarge" /> @@ -12,3 +13,10 @@ export default function EmptyPlaceholder({ msg, children }) {
); } + +EmptyPlaceholder.propTypes = { + msg: PropTypes.node, + children: PropTypes.node, +}; + +export default EmptyPlaceholder; diff --git a/components/common/Favicon.js b/components/common/Favicon.js index 07ec696c..d72cd3c7 100644 --- a/components/common/Favicon.js +++ b/components/common/Favicon.js @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import styles from './Favicon.module.css'; function getHostName(url) { @@ -6,7 +7,7 @@ function getHostName(url) { return match && match.length > 1 ? match[1] : null; } -export default function Favicon({ domain, ...props }) { +function Favicon({ domain, ...props }) { const hostName = domain ? getHostName(domain) : null; return hostName ? ( @@ -19,3 +20,9 @@ export default function Favicon({ domain, ...props }) { /> ) : null; } + +Favicon.propTypes = { + domain: PropTypes.string, +}; + +export default Favicon; diff --git a/components/common/FilterButtons.js b/components/common/FilterButtons.js index 5b898bf4..ea811216 100644 --- a/components/common/FilterButtons.js +++ b/components/common/FilterButtons.js @@ -1,11 +1,25 @@ import React from 'react'; +import PropTypes from 'prop-types'; import ButtonLayout from 'components/layout/ButtonLayout'; import ButtonGroup from './ButtonGroup'; -export default function FilterButtons({ buttons, selected, onClick }) { +function FilterButtons({ buttons, selected, onClick }) { return ( ); } + +FilterButtons.propTypes = { + buttons: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.node, + value: PropTypes.any.isRequired, + }), + ), + selected: PropTypes.any, + onClick: PropTypes.func, +}; + +export default FilterButtons; diff --git a/components/common/Icon.js b/components/common/Icon.js index 8a794f61..e9d96eb5 100644 --- a/components/common/Icon.js +++ b/components/common/Icon.js @@ -1,8 +1,9 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Icon.module.css'; -export default function Icon({ icon, className, size = 'medium', ...props }) { +function Icon({ icon, className, size = 'medium', ...props }) { return (
); } + +Icon.propTypes = { + className: PropTypes.string, + icon: PropTypes.node.isRequired, + size: PropTypes.oneOf(['xlarge', 'large', 'medium', 'small', 'xsmall']), +}; + +export default Icon; diff --git a/components/common/Link.js b/components/common/Link.js index 466e018c..f0fad731 100644 --- a/components/common/Link.js +++ b/components/common/Link.js @@ -1,10 +1,11 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import NextLink from 'next/link'; import Icon from './Icon'; import styles from './Link.module.css'; -export default function Link({ className, icon, children, size, iconRight, ...props }) { +function Link({ className, icon, children, size, iconRight, ...props }) { return ( ); } + +Link.propTypes = { + className: PropTypes.string, + icon: PropTypes.node, + children: PropTypes.node, + size: PropTypes.oneOf(['large', 'small', 'xsmall']), + iconRight: PropTypes.bool, +}; + +export default Link; diff --git a/components/common/Loading.js b/components/common/Loading.js index 46e72f17..16d8bb8a 100644 --- a/components/common/Loading.js +++ b/components/common/Loading.js @@ -1,8 +1,9 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Loading.module.css'; -export default function Loading({ className }) { +function Loading({ className }) { return (
@@ -11,3 +12,9 @@ export default function Loading({ className }) {
); } + +Loading.propTypes = { + className: PropTypes.string, +}; + +export default Loading; diff --git a/components/common/Menu.js b/components/common/Menu.js index 6421ba55..91eeee97 100644 --- a/components/common/Menu.js +++ b/components/common/Menu.js @@ -1,8 +1,9 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Menu.module.css'; -export default function Menu({ +function Menu({ options = [], selectedOption, className, @@ -46,3 +47,24 @@ export default function Menu({
); } + +Menu.propTypes = { + options: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.node, + value: PropTypes.any, + className: PropTypes.string, + render: PropTypes.func, + divider: PropTypes.bool, + }), + ), + selectedOption: PropTypes.any, + className: PropTypes.string, + float: PropTypes.oneOf(['top', 'bottom']), + align: PropTypes.oneOf(['left', 'right']), + optionClassName: PropTypes.string, + selectedClassName: PropTypes.string, + onSelect: PropTypes.func, +}; + +export default Menu; diff --git a/components/common/MenuButton.js b/components/common/MenuButton.js index c3e2b0ec..40df2e0c 100644 --- a/components/common/MenuButton.js +++ b/components/common/MenuButton.js @@ -1,11 +1,12 @@ import React, { useState, useRef } from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import Menu from 'components/common/Menu'; import Button from 'components/common/Button'; import useDocumentClick from 'hooks/useDocumentClick'; import styles from './MenuButton.module.css'; -export default function MenuButton({ +function MenuButton({ icon, value, options, @@ -58,3 +59,25 @@ export default function MenuButton({
); } + +MenuButton.propTypes = { + icon: PropTypes.node, + value: PropTypes.any, + options: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.node, + value: PropTypes.any, + className: PropTypes.string, + render: PropTypes.func, + divider: PropTypes.bool, + }), + ), + buttonClassName: PropTypes.string, + menuClassName: PropTypes.string, + menuPosition: PropTypes.oneOf(['top', 'bottom']), + menuAlign: PropTypes.oneOf(['left', 'right']), + onSelect: PropTypes.func, + renderValue: PropTypes.func, +}; + +export default MenuButton; diff --git a/components/common/Modal.js b/components/common/Modal.js index 42df57e2..694fba60 100644 --- a/components/common/Modal.js +++ b/components/common/Modal.js @@ -1,9 +1,10 @@ import React from 'react'; +import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import { useSpring, animated } from 'react-spring'; import styles from './Modal.module.css'; -export default function Modal({ title, children }) { +function Modal({ title, children }) { const props = useSpring({ opacity: 1, from: { opacity: 0 } }); return ReactDOM.createPortal( @@ -16,3 +17,10 @@ export default function Modal({ title, children }) { document.getElementById('__modals'), ); } + +Modal.propTypes = { + title: PropTypes.node, + children: PropTypes.node, +}; + +export default Modal; diff --git a/components/common/NavMenu.js b/components/common/NavMenu.js index 6cbe7559..82d97fff 100644 --- a/components/common/NavMenu.js +++ b/components/common/NavMenu.js @@ -1,9 +1,10 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { useRouter } from 'next/router'; import classNames from 'classnames'; import styles from './NavMenu.module.css'; -export default function NavMenu({ options = [], className, onSelect = () => {} }) { +function NavMenu({ options = [], className, onSelect = () => {} }) { const router = useRouter(); return ( @@ -30,3 +31,17 @@ export default function NavMenu({ options = [], className, onSelect = () => {} }
); } + +NavMenu.propTypes = { + options: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.node, + value: PropTypes.any, + className: PropTypes.string, + render: PropTypes.func, + }), + ), + className: PropTypes.string, + onSelect: PropTypes.func, +}; +export default NavMenu; diff --git a/components/common/NoData.js b/components/common/NoData.js index bb27c18f..9d523437 100644 --- a/components/common/NoData.js +++ b/components/common/NoData.js @@ -1,12 +1,19 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import { FormattedMessage } from 'react-intl'; import styles from './NoData.module.css'; -export default function NoData({ className }) { +function NoData({ className }) { return (
); } + +NoData.propTypes = { + className: PropTypes.string, +}; + +export default NoData; diff --git a/components/common/RefreshButton.js b/components/common/RefreshButton.js index b1b80a83..a2857522 100644 --- a/components/common/RefreshButton.js +++ b/components/common/RefreshButton.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; import { setDateRange } from 'redux/actions/websites'; @@ -8,7 +9,7 @@ import Dots from 'assets/ellipsis-h.svg'; import useDateRange from 'hooks/useDateRange'; import { getDateRange } from '../../lib/date'; -export default function RefreshButton({ websiteId }) { +function RefreshButton({ websiteId }) { const dispatch = useDispatch(); const [dateRange] = useDateRange(websiteId); const [loading, setLoading] = useState(false); @@ -35,3 +36,9 @@ export default function RefreshButton({ websiteId }) { /> ); } + +RefreshButton.propTypes = { + websiteId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), +}; + +export default RefreshButton; diff --git a/components/common/Table.js b/components/common/Table.js index f0989903..004b5af6 100644 --- a/components/common/Table.js +++ b/components/common/Table.js @@ -1,9 +1,10 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import NoData from 'components/common/NoData'; import styles from './Table.module.css'; -export default function Table({ +function Table({ columns, rows, empty, @@ -45,6 +46,34 @@ export default function Table({ ); } +const styledObject = PropTypes.shape({ + className: PropTypes.string, + style: PropTypes.object, +}); + +Table.propTypes = { + columns: PropTypes.arrayOf( + PropTypes.shape({ + cell: styledObject, + className: PropTypes.string, + header: styledObject, + key: PropTypes.string, + label: PropTypes.node, + render: PropTypes.func, + style: PropTypes.object, + }), + ), + rows: PropTypes.arrayOf(PropTypes.object), + empty: PropTypes.node, + className: PropTypes.string, + bodyClassName: PropTypes.string, + rowKey: PropTypes.func, + showHeader: PropTypes.bool, + children: PropTypes.node, +}; + +export default Table; + export const TableRow = ({ columns, row }) => (
{columns.map(({ key, render, className, style, cell }, index) => ( diff --git a/components/common/Tag.js b/components/common/Tag.js index 29612dca..08589c36 100644 --- a/components/common/Tag.js +++ b/components/common/Tag.js @@ -1,7 +1,15 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Tag.module.css'; -export default function Tag({ className, children }) { +function Tag({ className, children }) { return {children}; } + +Tag.propTypes = { + className: PropTypes.string, + children: PropTypes.node, +}; + +export default Tag; diff --git a/components/common/Toast.js b/components/common/Toast.js index 12787985..e8218766 100644 --- a/components/common/Toast.js +++ b/components/common/Toast.js @@ -1,11 +1,12 @@ import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import { useSpring, animated } from 'react-spring'; import styles from './Toast.module.css'; import Icon from 'components/common/Icon'; import Close from 'assets/times.svg'; -export default function Toast({ message, timeout = 3000, onClose }) { +function Toast({ message, timeout = 3000, onClose }) { const props = useSpring({ opacity: 1, transform: 'translate3d(0,0px,0)', @@ -24,3 +25,11 @@ export default function Toast({ message, timeout = 3000, onClose }) { document.getElementById('__modals'), ); } + +Toast.propTypes = { + message: PropTypes.node, + timeout: PropTypes.number, + onClose: PropTypes.func, +}; + +export default Toast; diff --git a/components/common/WorldMap.js b/components/common/WorldMap.js index 7a4a0fda..ee3a0a00 100644 --- a/components/common/WorldMap.js +++ b/components/common/WorldMap.js @@ -1,4 +1,5 @@ import React, { useState, useMemo } from 'react'; +import PropTypes from 'prop-types'; import ReactTooltip from 'react-tooltip'; import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; import classNames from 'classnames'; @@ -12,7 +13,7 @@ import { useRouter } from 'next/router'; const geoUrl = '/world-110m.json'; -export default function WorldMap({ data, className }) { +function WorldMap({ data, className }) { const { basePath } = useRouter(); const [tooltip, setTooltip] = useState(); const [theme] = useTheme(); @@ -89,3 +90,16 @@ export default function WorldMap({ data, className }) {
); } + +WorldMap.propTypes = { + data: PropTypes.arrayOf( + PropTypes.shape({ + x: PropTypes.string, + y: PropTypes.number, + z: PropTypes.number, + }), + ), + className: PropTypes.string, +}; + +export default WorldMap;