diff --git a/.gitignore b/.gitignore index 0f7f11b..d3fd097 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,7 @@ jspm_packages/ # TypeScript v1 declaration files typings/ +types/ # TypeScript cache *.tsbuildinfo diff --git a/package.json b/package.json index a4a1b91..2e9ed70 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.0.19", "main": "dist/index.cjs.js", "module": "dist/index.esm.js", + "types": "./types/types.d.ts", "scripts": { "prepublish": "npm run test && npm run build", "start": "start-storybook -p 9009 -s public", @@ -12,7 +13,8 @@ "lint": "npm run lint:scss && npm run lint:js", "lint:js": "eslint --ext js,jsx,ts .", "lint:scss": "stylelint '?(.)**/*.{css,scss}' --aei", - "build-storybook": "build-storybook -s public" + "build-storybook": "build-storybook -s public", + "types": "jsdoc -t node_modules/tsd-jsdoc/dist -r src/. -d types" }, "publishConfig": { "@acpaas-ui:registry": "https://nexusrepo.antwerpen.be/repository/npm-private" @@ -35,6 +37,7 @@ "@popperjs/core": "^2.6.0", "array-tree-filter": "^2.1.0", "classnames": "^2.2.6", + "docsjs": "^1.2.7", "lodash.debounce": "^4.0.8", "prop-types": "^15.7.2", "ramda": "^0.27.1", @@ -91,6 +94,7 @@ "stylelint": "^13.2.1", "stylelint-config-standard": "^20.0.0", "stylelint-scss": "^3.18.0", + "tsd-jsdoc": "^2.5.0", "typescript": "^3.8.3" } } diff --git a/src/components/ActionBar/ActionBar.jsx b/src/components/ActionBar/ActionBar.jsx index 1a2f73f..f67c51e 100644 --- a/src/components/ActionBar/ActionBar.jsx +++ b/src/components/ActionBar/ActionBar.jsx @@ -10,6 +10,16 @@ import { ActionBarContentSection } from './ActionBar.slots'; const cx = classNames.bind(styles); +/** + * @typedef ActionBarProps + * @prop {string} [className] + * @prop {React.ReactNode} [children] + * @prop {React.ReactNode} [container] + * @prop {boolean} [disablePortal] + * @prop {boolean} isOpen + */ + +/** @param {ActionBarProps} props */ const ActionBar = ({ children, className, diff --git a/src/components/Cascader/Cascader.jsx b/src/components/Cascader/Cascader.jsx index 64b349f..b1c0fd3 100644 --- a/src/components/Cascader/Cascader.jsx +++ b/src/components/Cascader/Cascader.jsx @@ -9,6 +9,46 @@ import { ALLOWED_KEYS, BUILT_IN_PLACEMENTS, REOPEN_POPUP_KEYS } from './Cascader import { Menus } from './Menus'; import './Cascader.scss'; +/** + * @typedef {object} CascaderOption +* Value of the option +* @prop {string|number} value +* Human readable label +* @prop {React.ReactNode} label +* True when loading +* @prop {boolean} CascaderOptionsProps.loading +* Indicates the end of a cascader tree +* @prop {boolean} CascaderOptionsProps.isLeaf + */ + +/** + * @typedef CascaderProps + * Component class prefix + * @prop {string} [prefixCls] + * Default value + * @prop {string[] | number[]} [defaultValue] + * Value + * @prop {string[] | number[]} [value] + * Cascader options + * @prop {object[]} [options] + * @prop {string | number} [options.value] + * @prop {React.ReactNode} [options.label] + * @prop {boolean} [options.loading] + * @prop {boolean} [options.isLeaf] + * @prop {CascaderOption[]} [options.children] + * Change the value on each selection, by default it will only + * trigger the onchange event when selecting a leaf option + * @prop {boolean} [changeOnSelect] + * Callback when finisching the cascader select + * @prop {Function} [onChange] + * Lazy load children + * @prop {Function} [loadData] + * Selecting an option is not possible when disabled + * @prop {boolean} [disabled] + * @prop {React.ReactElement} [children] + */ + +/** @param {CascaderProps} props */ const Cascader = ({ defaultValue, value, diff --git a/src/components/Cascader/Menus/Menus.jsx b/src/components/Cascader/Menus/Menus.jsx index c5971b1..b369e48 100644 --- a/src/components/Cascader/Menus/Menus.jsx +++ b/src/components/Cascader/Menus/Menus.jsx @@ -3,6 +3,35 @@ import classnames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; +/** + * @typedef {object} CascaderOption +* Value of the option +* @prop {string|number} value +* Human readable label +* @prop {React.ReactNode} label +* True when loading +* @prop {boolean} CascaderOptionsProps.loading +* Indicates the end of a cascader tree +* @prop {boolean} CascaderOptionsProps.isLeaf + */ + +/** + * @typedef MenusProps + * @prop {string} [prefixCls] + * Value + * @prop {string[] | number[]} [value] + * Callback when selecting an option + * @prop {function} [onSelect] + * Options + * @prop {object[]} [options] + * @prop {string | number} [options.value] + * @prop {React.ReactNode} [options.label] + * @prop {boolean} [options.loading] + * @prop {boolean} [options.isLeaf] + * @prop {CascaderOption[]} [options.children] + */ + +/** @param {MenusProps} props */ const Menus = ({ value = [], options = [], diff --git a/src/components/Container/Container.jsx b/src/components/Container/Container.jsx index d161c65..fbd5b19 100644 --- a/src/components/Container/Container.jsx +++ b/src/components/Container/Container.jsx @@ -2,6 +2,13 @@ import classnames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; +/** + * @typedef {object} ContainerProp + * @prop {string} [className] + * @prop {React.ReactNode} [children] + */ + +/** @param {ContainerProp} props */ const Container = ({ className, children }) => (
{children} diff --git a/src/components/ContextHeader/ContextHeader.jsx b/src/components/ContextHeader/ContextHeader.jsx index 03b4ce9..ad92e16 100644 --- a/src/components/ContextHeader/ContextHeader.jsx +++ b/src/components/ContextHeader/ContextHeader.jsx @@ -11,6 +11,23 @@ import { ContextHeaderActionsSection, ContextHeaderTopSection } from './ContextH const cx = classNames.bind(styles); +/** + * @typedef ContextHeaderProps + * @prop {string} [className] + * @prop {React.ReactNode|React.ReactNode[]} [children] + * @prop {string | React.ReactNode} [title] + * @prop {object[]} [badges] + * @prop {'primary' | 'secondary' | 'success' | 'warning' | 'danger'} badges.type + * @prop {string} badges.name + * @prop {object[]} [tabs] + * @prop {string} tabs.name + * @prop {string} tabs.target + * @prop {boolean} [tabs.active] + * @prop {boolean} [tabs.disabled] + * @prop {Function} [linkProps] + * + */ +/** @param {ContextHeaderProps} props */ const ContextHeader = ({ className, children, diff --git a/src/components/ControlledModal/ControlledModal.jsx b/src/components/ControlledModal/ControlledModal.jsx index fbff7d1..6bdf69e 100644 --- a/src/components/ControlledModal/ControlledModal.jsx +++ b/src/components/ControlledModal/ControlledModal.jsx @@ -13,6 +13,19 @@ import { const cx = classnames.bind(styles); +/** + * @typedef ControlledModalProp + * @prop {string} [className] + * @prop {React.ReactElement} [children] + * @prop {string} [overlayClassName] + * @prop {Element} [node] + * @prop {Function} [onClose] + * @prop {boolean} show + * @prop {'large'} [size] + * @prop {boolean} [lockBodyScroll] + */ + +/** @param {ControlledModalProp} props */ const ControlledModal = ({ children, className, overlayClassName, lockBodyScroll = true, node, onClose, show, size, }) => { diff --git a/src/components/Dnd/DndContainer/DndContainer.jsx b/src/components/Dnd/DndContainer/DndContainer.jsx index 0d96e7b..9cd47e8 100644 --- a/src/components/Dnd/DndContainer/DndContainer.jsx +++ b/src/components/Dnd/DndContainer/DndContainer.jsx @@ -5,6 +5,13 @@ import { HTML5Backend } from 'react-dnd-html5-backend'; const DNDContext = createDndContext(HTML5Backend); +/** + * @typedef {object} DndContainerProp + * @prop {boolean} [draggable] + * @prop {React.ReactNode[] | React.ReactNode} [children] + */ + +/** @param {DndContainerProp} props */ const DndContainer = ({ draggable, children }) => { const manager = useRef(DNDContext); diff --git a/src/components/Dnd/DndDragDroppable/DndDragDroppable.jsx b/src/components/Dnd/DndDragDroppable/DndDragDroppable.jsx index cda44eb..e0c5e61 100644 --- a/src/components/Dnd/DndDragDroppable/DndDragDroppable.jsx +++ b/src/components/Dnd/DndDragDroppable/DndDragDroppable.jsx @@ -1,7 +1,17 @@ -import { PropTypes } from 'prop-types'; import { useRef } from 'react'; import { useDrag, useDrop } from 'react-dnd'; +/** + * @typedef DndDragDroppableProp + * @prop {string[]} [accept] + * @prop {boolean} [allowHorizontalDrag] + * @prop {number} [index] + * @prop {Function} [moveRow] + * @prop {Function} [children] + * @prop {*} [id] + */ + +/** @param {DndDragDroppableProp} props */ const DndDragDroppable = ({ allowHorizontalDrag = false, accept, @@ -81,13 +91,4 @@ const DndDragDroppable = ({ return children({ dragDropRef, isDragging }); }; -DndDragDroppable.propTypes = { - accept: PropTypes.arrayOf(PropTypes.string), - allowHorizontalDrag: PropTypes.bool, - index: PropTypes.number, - moveRow: PropTypes.func, - children: PropTypes.func, - id: PropTypes.any, // eslint-disable-line -}; - export default DndDragDroppable; diff --git a/src/components/EllipsisWithTooltip/EllipsisWithTooltip.jsx b/src/components/EllipsisWithTooltip/EllipsisWithTooltip.jsx index abd8e7c..2a8c799 100644 --- a/src/components/EllipsisWithTooltip/EllipsisWithTooltip.jsx +++ b/src/components/EllipsisWithTooltip/EllipsisWithTooltip.jsx @@ -8,6 +8,18 @@ import styles from './EllipsisWithTooltip.module.scss'; const cx = classnames.bind(styles); +/** + * @typedef EllipsisProp + * @prop {string} [className] + * @prop {string} [value] + * @prop {React.ReactNode[] | React.ReactNode} children + * @prop {object} [style] + * @prop {TooltipTypeMap.DEFAULT| TooltipTypeMap.PRIMARY | TooltipTypeMap.SECONDARY} [type] + * @prop {number} [delayShow] + * + */ + +/** @param {EllipsisProp} props */ const EllipsisWithTooltip = ({ children, style, diff --git a/src/components/FileUpload/FileUpload.jsx b/src/components/FileUpload/FileUpload.jsx index f3fde9f..6dc357e 100644 --- a/src/components/FileUpload/FileUpload.jsx +++ b/src/components/FileUpload/FileUpload.jsx @@ -10,6 +10,34 @@ import { FileUploadZone } from './FileUploadZone'; import { Uploader } from './Uploader'; import { ValidationList } from './ValidationList'; +/** + * @typedef FileUploadProps + * @prop {string} id + * @prop {boolean} [disabled] + * @prop {string} [ariaLabelRemove] + * @prop {object} [options] + * @prop {string[]} [options.allowedMimeTypes] + * @prop {string[]} [options.allowedFileTypes] + * @prop {number} [options.maxFileSize] + * @prop {string} [options.type] + * @prop {string} [options.url] + * @prop {number} [options.fileLimit] + * @prop {object} [options.messages] + * @prop {string} [options.messages.INVALID_FILE_TYPE] + * @prop {string} [options.messages.INVALID_FILE_SIZE] + * @prop {string} [options.messages.INVALID_MIME_TYPE] + * @prop {string} [options.messages.REQUEST_ERROR] + * @prop {object} [options.requestHeader] + * @prop {string} [options.requestHeader.key] + * @prop {string} [options.requestHeader.value] + * @prop {object[]} [files] + * @prop {string} files.id + * @prop {string} files.name + * @prop {Function} [selectUploadedFiles] + * @prop {Function} [removeFile] + * @prop {React.ReactNode[] | React.ReactNode} [children] + */ +/** @param {FileUploadProps} props */ const FileUpload = ({ id = '', ariaLabelRemove = 'Verwijder', diff --git a/src/components/FileUpload/FileUploadZone/FileUploadZone.jsx b/src/components/FileUpload/FileUploadZone/FileUploadZone.jsx index a0a5f1b..62822a6 100644 --- a/src/components/FileUpload/FileUploadZone/FileUploadZone.jsx +++ b/src/components/FileUpload/FileUploadZone/FileUploadZone.jsx @@ -7,6 +7,24 @@ import { ProgressBar } from '../../ProgressBar'; import { FileUploadDescription, FileUploadMessage } from '../FileUpload.slots'; import { Uploader } from '../Uploader'; +/** + * @typedef FileUploadZoneProps + * @prop {boolean} [autoUpload] + * @prop {string} [id] + * @prop {Uploader} [uploader] + * @prop {boolean} [disabled] + * @prop {boolean} [multiple] + * @prop {string} [ariaId] + * @prop {Function} [uploadedFiles] + * @prop {Function} [invalidFiles] + * @prop {Function} [onRequestError] + * @prop {Function} [onCustomClick] + * @prop {Function} [onCustomDrop] + * @prop {string[]} [allowedMimeTypes] + * @prop {string[]} [allowedFileTypes] + * @prop {React.ReactNode[] | React.ReactNode} [children] + */ +/** @param {FileUploadZoneProps} props */ const FileUploadZone = ({ autoUpload = true, id = '', diff --git a/src/components/FileUpload/ValidationList/ValidationList.jsx b/src/components/FileUpload/ValidationList/ValidationList.jsx index 686cf96..86331f1 100644 --- a/src/components/FileUpload/ValidationList/ValidationList.jsx +++ b/src/components/FileUpload/ValidationList/ValidationList.jsx @@ -3,6 +3,19 @@ import React from 'react'; import { VALIDATION_MESSAGES_DEFAULT } from '../FileUpload.const'; +/** + * @typedef ValidationListProp + * @prop {object[]} [invalidFiles] + * @prop {string[]} [invalidFiles.reasons] + * @prop {File} [invalidFiles.file] + * @prop {string} [ariaLabelRemove] + * @prop {Function} [removeInvalidFile] + * @prop {object} [messages] + * @prop {string} [messages.INVALID_FILE_TYPE] + * @prop {string} [messages.INVALID_FILE_SIZE] + * @prop {string} [messages.INVALID_MIME_TYPE] + */ +/** @param {ValidationListProp} props */ const ValidationList = ({ invalidFiles = [], messages = VALIDATION_MESSAGES_DEFAULT, diff --git a/src/components/Filter/Filter.jsx b/src/components/Filter/Filter.jsx index 084eb6f..888bfbd 100644 --- a/src/components/Filter/Filter.jsx +++ b/src/components/Filter/Filter.jsx @@ -10,6 +10,26 @@ import { useSlot } from '../../hooks/useSlot'; import './Filter.scss'; import { FilterBody } from './Filter.slots'; +/** + * @typedef FilterProps + * @prop {string} [actionsClassName] + * @prop {React.ReactNode[] | React.ReactNode} [children] + * @prop {string} [className] + * @prop {string} [title] + * @prop {string} [noFilterText] + * @prop {Function} [onConfirm] + * @prop {string} [confirmText] + * @prop {Function} [onClean] + * @prop {string} [cleanText] + * @prop {object[]} [activeFilters] + * @prop {string} [activeFilters.valuePrefix] + * @prop {string} [activeFilters.value] + * @prop {string} [activeFilters.key] + * @prop {Function} [onFilterRemove] + * @prop {boolean} [enableSubmitOnEnter] + */ + +/** @param {FilterProps} props */ const Filter = ({ actionsClassName, className, diff --git a/src/components/NavList/NavList.jsx b/src/components/NavList/NavList.jsx index 5cc1d27..2ae0d0b 100644 --- a/src/components/NavList/NavList.jsx +++ b/src/components/NavList/NavList.jsx @@ -5,6 +5,19 @@ import sanitizeHtml from 'sanitize-html'; import './NavList.scss'; +/** + * @typedef NavListProps + * @prop {string} [className] + * @prop {React.ElementType} [linkComponent] + * @prop {object[]} items + * @prop {boolean} [items.hasError] + * @prop {string} items.label + * @prop {string} [items.description] + * @prop {'large'} [size] + * @prop {boolean} [lockBodyScroll] + */ + +/** @param {NavListProps} props */ const NavList = ({ className, linkComponent: LinkComponent = 'a', items }) => (