From a5ff572816f71c8f9b16c7ad952e28fc8ddc8e95 Mon Sep 17 00:00:00 2001 From: Alexander Fedyashov Date: Fri, 17 Feb 2017 18:07:26 +0200 Subject: [PATCH] style(Modal): update typings and propTypes usage (#1331) --- src/modules/Modal/Modal.js | 54 ++++++------- src/modules/Modal/ModalActions.js | 7 +- src/modules/Modal/ModalContent.js | 5 +- src/modules/Modal/ModalDescription.js | 7 +- src/modules/Modal/ModalHeader.js | 3 + src/modules/Modal/index.d.ts | 75 ++++++++++--------- test/specs/modules/Modal/ModalContent-test.js | 2 + test/specs/modules/Modal/ModalHeader-test.js | 2 + 8 files changed, 85 insertions(+), 70 deletions(-) diff --git a/src/modules/Modal/Modal.js b/src/modules/Modal/Modal.js index f1422660c0..6bf8444d6c 100644 --- a/src/modules/Modal/Modal.js +++ b/src/modules/Modal/Modal.js @@ -1,13 +1,6 @@ +import cx from 'classnames' import _ from 'lodash' import React, { PropTypes } from 'react' -import cx from 'classnames' - -import ModalHeader from './ModalHeader' -import ModalContent from './ModalContent' -import ModalActions from './ModalActions' -import ModalDescription from './ModalDescription' -import Icon from '../../elements/Icon' -import Portal from '../../addons/Portal' import { AutoControlledComponent as Component, @@ -19,20 +12,17 @@ import { META, useKeyOnly, } from '../../lib' +import Icon from '../../elements/Icon' +import Portal from '../../addons/Portal' +import ModalHeader from './ModalHeader' +import ModalContent from './ModalContent' +import ModalActions from './ModalActions' +import ModalDescription from './ModalDescription' const debug = makeDebugger('modal') -const _meta = { - name: 'Modal', - type: META.TYPES.MODULE, - props: { - size: ['fullscreen', 'large', 'small'], - dimmer: ['inverted', 'blurring'], - }, -} - /** - * A modal displays content that temporarily blocks interactions with the main view of a site + * A modal displays content that temporarily blocks interactions with the main view of a site. * @see Confirm * @see Portal */ @@ -50,16 +40,14 @@ class Modal extends Component { /** Additional classes. */ className: PropTypes.string, - /** Icon */ + /** Icon. */ closeIcon: PropTypes.oneOfType([ PropTypes.node, PropTypes.object, PropTypes.bool, ]), - /** - * Whether or not the Modal should close when the dimmer is clicked. - */ + /** Whether or not the Modal should close when the dimmer is clicked. */ closeOnDimmerClick: PropTypes.bool, /** Whether or not the Modal should close when the document is clicked. */ @@ -68,17 +56,17 @@ class Modal extends Component { /** Initial value of open. */ defaultOpen: PropTypes.bool, - /** A modal can appear in a dimmer */ + /** A modal can appear in a dimmer. */ dimmer: PropTypes.oneOfType([ PropTypes.bool, - PropTypes.oneOf(_meta.props.dimmer), + PropTypes.oneOf(['inverted', 'blurring']), ]), - /** The node where the modal should mount. Defaults to document.body. */ + /** The node where the modal should mount. Defaults to document.body. */ mountNode: PropTypes.any, /** - * Called when a close event happens + * Called when a close event happens. * * @param {SyntheticEvent} event - React's original SyntheticEvent. * @param {object} data - All props. @@ -86,7 +74,7 @@ class Modal extends Component { onClose: PropTypes.func, /** - * Called when the portal is mounted on the DOM + * Called when the portal is mounted on the DOM. * * @param {null} * @param {object} data - All props. @@ -94,7 +82,7 @@ class Modal extends Component { onMount: PropTypes.func, /** - * Called when an open event happens + * Called when an open event happens. * * @param {SyntheticEvent} event - React's original SyntheticEvent. * @param {object} data - All props. @@ -102,7 +90,7 @@ class Modal extends Component { onOpen: PropTypes.func, /** - * Called when the portal is unmounted from the DOM + * Called when the portal is unmounted from the DOM. * * @param {null} * @param {object} data - All props. @@ -113,7 +101,7 @@ class Modal extends Component { open: PropTypes.bool, /** A modal can vary in size */ - size: PropTypes.oneOf(_meta.props.size), + size: PropTypes.oneOf(['fullscreen', 'large', 'small']), /** * NOTE: Any unhandled props that are defined in Portal are passed-through @@ -131,7 +119,11 @@ class Modal extends Component { 'open', ] - static _meta = _meta + static _meta = { + name: 'Modal', + type: META.TYPES.MODULE, + } + static Header = ModalHeader static Content = ModalContent static Description = ModalDescription diff --git a/src/modules/Modal/ModalActions.js b/src/modules/Modal/ModalActions.js index e434bb8dc2..f561ea29f1 100644 --- a/src/modules/Modal/ModalActions.js +++ b/src/modules/Modal/ModalActions.js @@ -1,5 +1,5 @@ -import React, { PropTypes } from 'react' import cx from 'classnames' +import React, { PropTypes } from 'react' import { customPropTypes, @@ -8,9 +8,12 @@ import { META, } from '../../lib' +/** + * A modal can contain a row of actions. + */ function ModalActions(props) { const { children, className } = props - const classes = cx(className, 'actions') + const classes = cx('actions', className) const rest = getUnhandledProps(ModalActions, props) const ElementType = getElementType(ModalActions, props) diff --git a/src/modules/Modal/ModalContent.js b/src/modules/Modal/ModalContent.js index 90b0b4d48f..5b0a4e576b 100644 --- a/src/modules/Modal/ModalContent.js +++ b/src/modules/Modal/ModalContent.js @@ -11,6 +11,9 @@ import { useKeyOnly, } from '../../lib' +/** + * A modal can contain content. + */ function ModalContent(props) { const { children, @@ -53,7 +56,7 @@ ModalContent.propTypes = { /** Shorthand for primary content. */ content: customPropTypes.contentShorthand, - /** A modal can contain image content */ + /** A modal can contain image content. */ image: PropTypes.bool, } diff --git a/src/modules/Modal/ModalDescription.js b/src/modules/Modal/ModalDescription.js index a21f6d939b..54e5f2975b 100644 --- a/src/modules/Modal/ModalDescription.js +++ b/src/modules/Modal/ModalDescription.js @@ -1,5 +1,5 @@ -import React, { PropTypes } from 'react' import cx from 'classnames' +import React, { PropTypes } from 'react' import { customPropTypes, @@ -8,9 +8,12 @@ import { META, } from '../../lib' +/** + * A modal can have a header. + */ function ModalDescription(props) { const { children, className } = props - const classes = cx(className, 'description') + const classes = cx('description', className) const rest = getUnhandledProps(ModalDescription, props) const ElementType = getElementType(ModalDescription, props) diff --git a/src/modules/Modal/ModalHeader.js b/src/modules/Modal/ModalHeader.js index be6096e00f..9650af625a 100644 --- a/src/modules/Modal/ModalHeader.js +++ b/src/modules/Modal/ModalHeader.js @@ -10,6 +10,9 @@ import { META, } from '../../lib' +/** + * A modal can have a header. + */ function ModalHeader(props) { const { children, className, content } = props const classes = cx(className, 'header') diff --git a/src/modules/Modal/index.d.ts b/src/modules/Modal/index.d.ts index 33f6a559c0..d33afb25ea 100644 --- a/src/modules/Modal/index.d.ts +++ b/src/modules/Modal/index.d.ts @@ -1,7 +1,8 @@ -import { SemanticSIZES } from '../..'; import * as React from 'react'; +import {PortalProps} from '../../addons/Portal'; -interface ModalProps { +interface ModalProps extends PortalProps { + [key: string]: any; /** An element type to render as (string or function). */ as?: any; @@ -15,75 +16,74 @@ interface ModalProps { /** Additional classes. */ className?: string; - /** Icon */ - closeIcon?:any; + /** Icon. */ + closeIcon?: any; - /** - * Whether or not the Modal should close when the dimmer is clicked. - */ + /** Whether or not the Modal should close when the dimmer is clicked. */ closeOnDimmerClick?: boolean; /** Whether or not the Modal should close when the document is clicked. */ closeOnDocumentClick?: boolean; /** Initial value of open. */ - defaultOpen?:boolean; + defaultOpen?: boolean; - /** A modal can appear in a dimmer */ + /** A modal can appear in a dimmer. */ dimmer?: boolean | 'blurring' | 'inverted'; + /** The node where the modal should mount. Defaults to document.body. */ + mountNode?: any; + /** - * Called when a close event happens + * Called when a close event happens. * * @param {SyntheticEvent} event - React's original SyntheticEvent. * @param {object} data - All props. */ - onClose?: Function; + onClose?: (event: React.MouseEvent, data: ModalProps) => void; /** - * Called when the portal is mounted on the DOM + * Called when the portal is mounted on the DOM. * * @param {null} * @param {object} data - All props. */ - onMount?: Function; + onMount?: (nothing: null, data: ModalProps) => void; /** - * Called when an open event happens + * Called when an open event happens. * * @param {SyntheticEvent} event - React's original SyntheticEvent. * @param {object} data - All props. */ - onOpen?:Function; + onOpen?: (event: React.MouseEvent, data: ModalProps) => void; /** - * Called when the dropdown is unmounted from the DOM + * Called when the portal is unmounted from the DOM. * * @param {null} * @param {object} data - All props. */ - onUnmount?: Function; + onUnmount?: (nothing: null, data: ModalProps) => void; + /** Controls whether or not the Modal is displayed. */ open?: boolean; - /** The node where the modal should mount.. */ - mountNode?: any; - - /** A modal can vary in size */ - size?: SemanticSIZES; - + /** A modal can vary in size. */ + size?: 'fullscreen' | 'large' | 'small'; } -interface ModalClass extends React.ComponentClass { - Header: typeof ModalHeader; +interface ModalComponent extends React.ComponentClass { + Actions: typeof ModalActions; Content: typeof ModalContent; Description: typeof ModalDescription; - Actions: typeof ModalActions; + Header: typeof ModalHeader; } -export const Modal: ModalClass; +export const Modal: ModalComponent; -interface ModalHeaderProps { +interface ModalActionsProps { + [key: string]: any; /** An element type to render as (string or function). */ as?: any; @@ -95,9 +95,10 @@ interface ModalHeaderProps { className?: string; } -export const ModalHeader: React.ComponentClass; +export const ModalActions: React.StatelessComponent; interface ModalContentProps { + [key: string]: any; /** An element type to render as (string or function). */ as?: any; @@ -108,13 +109,14 @@ interface ModalContentProps { /** Additional classes. */ className?: string; - /** A modal can contain image content */ + /** A modal can contain image content. */ image?: boolean; } -export const ModalContent: React.ComponentClass; +export const ModalContent: React.StatelessComponent; interface ModalDescriptionProps { + [key: string]: any; /** An element type to render as (string or function). */ as?: any; @@ -126,9 +128,10 @@ interface ModalDescriptionProps { className?: string; } -export const ModalDescription: React.ComponentClass; +export const ModalDescription: React.StatelessComponent; -interface ModalActionsProps { +interface ModalHeaderProps { + [key: string]: any; /** An element type to render as (string or function). */ as?: any; @@ -138,6 +141,10 @@ interface ModalActionsProps { /** Additional classes. */ className?: string; + + /** Shorthand for primary content. */ + content?: React.ReactNode; } -export const ModalActions: React.ComponentClass; +export const ModalHeader: React.StatelessComponent; + diff --git a/test/specs/modules/Modal/ModalContent-test.js b/test/specs/modules/Modal/ModalContent-test.js index daa11ba2d4..5dffcfb0b3 100644 --- a/test/specs/modules/Modal/ModalContent-test.js +++ b/test/specs/modules/Modal/ModalContent-test.js @@ -5,5 +5,7 @@ describe('ModalContent', () => { common.isConformant(ModalContent) common.rendersChildren(ModalContent) + common.implementsCreateMethod(ModalContent) + common.propKeyOnlyToClassName(ModalContent, 'image') }) diff --git a/test/specs/modules/Modal/ModalHeader-test.js b/test/specs/modules/Modal/ModalHeader-test.js index f69f9d45e7..a8b0d1c962 100644 --- a/test/specs/modules/Modal/ModalHeader-test.js +++ b/test/specs/modules/Modal/ModalHeader-test.js @@ -4,4 +4,6 @@ import * as common from 'test/specs/commonTests' describe('ModalHeader', () => { common.isConformant(ModalHeader) common.rendersChildren(ModalHeader) + + common.implementsCreateMethod(ModalHeader) })