diff --git a/CHANGELOG.md b/CHANGELOG.md index 20ba30f0e1..3fc6640178 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### BREAKING CHANGES +- Add `render` callback as an option for shorthand value @kuzhelov ([#562](https://github.com/stardust-ui/react/pull/562)) +- Rename `renderContent` and `renderTitle` to `renderPanelContent` and `renderPanelTitle` for `Accordion` @kuzhelov ([#562](https://github.com/stardust-ui/react/pull/562)) + ## [v0.13.3](https://github.com/stardust-ui/react/tree/v0.13.3) (2018-12-05) [Compare changes](https://github.com/stardust-ui/react/compare/v0.13.2...v0.13.3) diff --git a/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx b/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx index b1d623574f..071c5b92b6 100644 --- a/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx +++ b/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx @@ -9,9 +9,9 @@ const AvatarExampleImageCustomizationShorthand = () => ( />   ( + image={ - )} + } status={{ color: 'green', icon: 'check', title: 'Available' }} /> diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx index fa30571e34..940a4598ba 100644 --- a/src/components/Accordion/Accordion.tsx +++ b/src/components/Accordion/Accordion.tsx @@ -14,11 +14,12 @@ import AccordionTitle from './AccordionTitle' import AccordionContent from './AccordionContent' import { defaultBehavior } from '../../lib/accessibility' import { Accessibility } from '../../lib/accessibility/types' + import { ComponentEventHandler, Extendable, - ShorthandRenderFunction, ShorthandValue, + ShorthandRenderFunction, } from '../../../types/utils' export interface AccordionProps extends UIComponentProps, ChildrenComponentProps { @@ -46,24 +47,20 @@ export interface AccordionProps extends UIComponentProps, ChildrenComponentProps }[] /** - * A custom render iterator for rendering each Accordion panel content. - * The default component, props, and children are available for each panel content. + * A custom renderer for each Accordion's panel title. * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. + * @param {React.ReactType} Component - The panel's component type. + * @param {object} props - The panel's computed props. */ - renderContent?: ShorthandRenderFunction + renderPanelTitle?: ShorthandRenderFunction /** - * A custom render iterator for rendering each Accordion panel title. - * The default component, props, and children are available for each panel title. + * A custom renderer for each Accordion's panel content. * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. + * @param {React.ReactType} Component - The panel's component type. + * @param {object} props - The panel's computed props. */ - renderTitle?: ShorthandRenderFunction + renderPanelContent?: ShorthandRenderFunction /** * Accessibility behavior if overridden by the user. @@ -104,8 +101,9 @@ class Accordion extends AutoControlledComponent, any> ), ]), accessibility: PropTypes.func, - renderTitle: PropTypes.func, - renderContent: PropTypes.func, + + renderPanelTitle: PropTypes.func, + renderPanelContent: PropTypes.func, } public static defaultProps = { @@ -153,7 +151,7 @@ class Accordion extends AutoControlledComponent, any> renderPanels = () => { const children: any[] = [] - const { panels, renderContent, renderTitle } = this.props + const { panels, renderPanelContent, renderPanelTitle } = this.props _.each(panels, (panel, index) => { const { content, title } = panel @@ -163,13 +161,13 @@ class Accordion extends AutoControlledComponent, any> AccordionTitle.create(title, { defaultProps: { active, index }, overrideProps: this.handleTitleOverrides, - render: renderTitle, + render: renderPanelTitle, }), ) children.push( AccordionContent.create(content, { defaultProps: { active }, - render: renderContent, + render: renderPanelContent, }), ) }) diff --git a/src/components/Attachment/Attachment.tsx b/src/components/Attachment/Attachment.tsx index aa8528c7e0..37839624b8 100644 --- a/src/components/Attachment/Attachment.tsx +++ b/src/components/Attachment/Attachment.tsx @@ -1,6 +1,7 @@ import * as PropTypes from 'prop-types' import * as React from 'react' import * as _ from 'lodash' +import { Extendable, ShorthandValue } from '../../../types/utils' import { UIComponent, customPropTypes, @@ -9,7 +10,6 @@ import { ChildrenComponentProps, commonPropTypes, } from '../../lib' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' import Icon from '../Icon/Icon' import Button from '../Button/Button' import Text from '../Text/Text' @@ -33,51 +33,6 @@ export interface AttachmentProps extends UIComponentProps, ChildrenComponentProp /** Value indicating percent complete. */ progress?: string | number - - /** - * A custom render function the action slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderAction?: ShorthandRenderFunction - - /** - * A custom render function the description slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderDescription?: ShorthandRenderFunction - - /** - * A custom render function the header slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderHeader?: ShorthandRenderFunction - - /** - * A custom render function the icon slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderIcon?: ShorthandRenderFunction - - /** - * A custom render function the progress slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderProgress?: ShorthandRenderFunction } /** @@ -100,26 +55,10 @@ class Attachment extends UIComponent, any> { header: customPropTypes.itemShorthand, icon: customPropTypes.itemShorthand, progress: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - renderAction: PropTypes.func, - renderDescription: PropTypes.func, - renderHeader: PropTypes.func, - renderIcon: PropTypes.func, - renderProgress: PropTypes.func, } renderComponent({ ElementType, classes, rest, styles, variables }) { - const { - header, - description, - icon, - action, - progress, - renderIcon, - renderHeader, - renderDescription, - renderAction, - renderProgress, - } = this.props + const { header, description, icon, action, progress } = this.props return ( @@ -127,7 +66,6 @@ class Attachment extends UIComponent, any> {
{Icon.create(icon, { defaultProps: { size: 'big' }, - render: renderIcon, })}
)} @@ -135,12 +73,10 @@ class Attachment extends UIComponent, any> {
{Text.create(header, { defaultProps: { styles: styles.header }, - render: renderHeader, })} {Text.create(description, { defaultProps: { styles: styles.description }, - render: renderDescription, })}
)} @@ -148,14 +84,12 @@ class Attachment extends UIComponent, any> {
{Button.create(action, { defaultProps: { iconOnly: true, text: true }, - render: renderAction, })}
)} {!_.isNil(progress) && Slot.create('', { defaultProps: { className: classes.progress }, - render: renderProgress, })}
) diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index 4e5936eec9..790c63979b 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -1,7 +1,7 @@ import * as PropTypes from 'prop-types' import * as React from 'react' import { Image, Label, Status } from '../../' - +import { Extendable, ShorthandValue } from '../../../types/utils' import { createShorthandFactory, customPropTypes, @@ -9,7 +9,6 @@ import { UIComponentProps, commonPropTypes, } from '../../lib' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' export interface AvatarProps extends UIComponentProps { /** Shorthand for the image. */ @@ -21,33 +20,6 @@ export interface AvatarProps extends UIComponentProps { /** The name used for displaying the initials of the avatar if the image is not provided. */ name?: string - /** - * A custom render function the image slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderImage?: ShorthandRenderFunction - - /** - * A custom render function the label slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderLabel?: ShorthandRenderFunction - - /** - * A custom render function the status slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderStatus?: ShorthandRenderFunction - /** Size multiplier. */ size?: number @@ -79,9 +51,6 @@ class Avatar extends UIComponent, any> { size: PropTypes.number, status: customPropTypes.itemShorthand, getInitials: PropTypes.func, - renderImage: PropTypes.func, - renderLabel: PropTypes.func, - renderStatus: PropTypes.func, } static defaultProps = { @@ -110,8 +79,7 @@ class Avatar extends UIComponent, any> { } renderComponent({ ElementType, classes, rest, styles, variables }) { - const { name, status, image, label, getInitials, renderImage, renderLabel, renderStatus } = this - .props as AvatarPropsWithDefaults + const { name, status, image, label, getInitials } = this.props as AvatarPropsWithDefaults return ( @@ -122,10 +90,8 @@ class Avatar extends UIComponent, any> { title: name, styles: styles.image, }, - render: renderImage, })} {!image && - !renderImage && Label.create(label || {}, { defaultProps: { content: getInitials(name), @@ -133,7 +99,6 @@ class Avatar extends UIComponent, any> { title: name, styles: styles.label, }, - render: renderLabel, })} {Status.create(status, { defaultProps: { @@ -143,7 +108,6 @@ class Avatar extends UIComponent, any> { borderWidth: variables.statusBorderWidth, }, }, - render: renderStatus, })} ) diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 01d2c7af69..1528611fc4 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -16,12 +16,7 @@ import Icon from '../Icon/Icon' import Slot from '../Slot/Slot' import { buttonBehavior } from '../../lib/accessibility' import { Accessibility } from '../../lib/accessibility/types' -import { - ComponentEventHandler, - Extendable, - ShorthandRenderFunction, - ShorthandValue, -} from '../../../types/utils' +import { ComponentEventHandler, Extendable, ShorthandValue } from '../../../types/utils' import ButtonGroup from './ButtonGroup' import isFromKeyboard from '../../lib/isFromKeyboard' @@ -70,15 +65,6 @@ export interface ButtonProps /** A button can be formatted to show different levels of emphasis. */ primary?: boolean - /** - * A custom render function the icon slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderIcon?: ShorthandRenderFunction - /** A button can be formatted to show only text in order to indicate some less-pronounced actions. */ text?: boolean @@ -120,7 +106,6 @@ class Button extends UIComponent, ButtonState> { text: PropTypes.bool, secondary: customPropTypes.every([customPropTypes.disallow(['primary']), PropTypes.bool]), accessibility: PropTypes.func, - renderIcon: PropTypes.func, } public static defaultProps = { @@ -163,7 +148,7 @@ class Button extends UIComponent, ButtonState> { } public renderIcon = (variables, styles) => { - const { icon, iconPosition, content, renderIcon } = this.props + const { icon, iconPosition, content } = this.props return Icon.create(icon, { defaultProps: { @@ -171,7 +156,6 @@ class Button extends UIComponent, ButtonState> { xSpacing: !content ? 'none' : iconPosition === 'after' ? 'before' : 'after', variables: variables.icon, }, - render: renderIcon, }) } diff --git a/src/components/Button/ButtonGroup.tsx b/src/components/Button/ButtonGroup.tsx index ba0a460e3d..c6e4e1b880 100644 --- a/src/components/Button/ButtonGroup.tsx +++ b/src/components/Button/ButtonGroup.tsx @@ -2,6 +2,7 @@ import * as PropTypes from 'prop-types' import * as React from 'react' import * as _ from 'lodash' +import { Extendable, ShorthandValue } from '../../../types/utils' import { UIComponent, childrenExist, @@ -11,7 +12,6 @@ import { ContentComponentProps, commonPropTypes, } from '../../lib' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' import Button from './Button' import { buttonGroupBehavior } from '../../lib/accessibility' import { Accessibility } from '../../lib/accessibility/types' @@ -31,16 +31,6 @@ export interface ButtonGroupProps /** The buttons inside group can appear circular. */ circular?: boolean - - /** - * A custom render iterator for rendering each of the Button.Group buttons. - * The default component, props, and children are available for each button. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderButton?: ShorthandRenderFunction } /** @@ -56,7 +46,6 @@ class ButtonGroup extends UIComponent, any> { accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), buttons: customPropTypes.collectionShorthand, circular: PropTypes.bool, - renderButton: PropTypes.func, } public static defaultProps = { @@ -72,7 +61,7 @@ class ButtonGroup extends UIComponent, any> { styles, rest, }): React.ReactNode { - const { children, content, buttons, circular, renderButton } = this.props + const { children, content, buttons, circular } = this.props if (_.isNil(buttons)) { return ( @@ -89,7 +78,6 @@ class ButtonGroup extends UIComponent, any> { circular, styles: this.getStyleForButtonIndex(styles, idx === 0, idx === buttons.length - 1), }, - render: renderButton, }), )} diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx index 0cdd987494..db91546580 100644 --- a/src/components/Chat/Chat.tsx +++ b/src/components/Chat/Chat.tsx @@ -5,7 +5,7 @@ import * as React from 'react' import { childrenExist, customPropTypes, UIComponent, commonPropTypes } from '../../lib' import ChatItem from './ChatItem' import ChatMessage from './ChatMessage' -import { Extendable, ShorthandValue, ShorthandRenderFunction } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibility/types' import { chatBehavior } from '../../lib/accessibility' import { UIComponentProps, ChildrenComponentProps } from '../../lib/commonPropInterfaces' @@ -19,16 +19,6 @@ export interface ChatProps extends UIComponentProps, ChildrenComponentProps { /** Shorthand array of the items inside the chat. */ items?: ShorthandValue[] - - /** - * A custom render iterator for rendering each of the Chat items. - * The default component, props, and children are available for each item. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderItem?: ShorthandRenderFunction } /** @@ -45,7 +35,6 @@ class Chat extends UIComponent, any> { }), accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), items: PropTypes.arrayOf(customPropTypes.itemShorthand), - renderItem: PropTypes.func, } static defaultProps = { accessibility: chatBehavior, as: 'ul' } @@ -58,7 +47,7 @@ class Chat extends UIComponent, any> { } renderComponent({ ElementType, classes, accessibility, rest }) { - const { children, items, renderItem } = this.props + const { children, items } = this.props return ( , any> { {...accessibility.keyHandlers.root} {...rest} > - {childrenExist(children) - ? children - : _.map(items, item => ChatItem.create(item, { render: renderItem }))} + {childrenExist(children) ? children : _.map(items, item => ChatItem.create(item))} ) } diff --git a/src/components/Chat/ChatItem.tsx b/src/components/Chat/ChatItem.tsx index bbbded6818..308e012394 100644 --- a/src/components/Chat/ChatItem.tsx +++ b/src/components/Chat/ChatItem.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import * as PropTypes from 'prop-types' +import { Extendable, ShorthandValue } from '../../../types/utils' import { childrenExist, createShorthandFactory, @@ -12,21 +12,11 @@ import { commonPropTypes, } from '../../lib' import Slot from '../Slot/Slot' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' export interface ChatItemProps extends UIComponentProps, ChildrenComponentProps, - ContentComponentProps { - /** - * A custom render function the content slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderContent?: ShorthandRenderFunction -} + ContentComponentProps {} /** * A chat item represents a single event in a chat. @@ -42,7 +32,6 @@ class ChatItem extends UIComponent, any> { ...commonPropTypes.createCommon({ content: 'shorthand', }), - renderContent: PropTypes.func, } static defaultProps = { @@ -56,7 +45,7 @@ class ChatItem extends UIComponent, any> { variables, rest, }: RenderResultConfig) { - const { children, content, renderContent } = this.props + const { children, content } = this.props return ( @@ -65,7 +54,6 @@ class ChatItem extends UIComponent, any> { : Slot.create(content, { styles: styles.content, variables: variables.content, - render: renderContent, })} ) diff --git a/src/components/Chat/ChatMessage.tsx b/src/components/Chat/ChatMessage.tsx index f7683298a6..3acbd70672 100644 --- a/src/components/Chat/ChatMessage.tsx +++ b/src/components/Chat/ChatMessage.tsx @@ -18,7 +18,7 @@ import { ComponentSlotClasses, ComponentSlotStylesInput, } from '../../themes/types' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' import Avatar from '../Avatar/Avatar' import { chatMessageBehavior } from '../../lib/accessibility' import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibility/types' @@ -44,42 +44,6 @@ export interface ChatMessageProps /** Indicates whether message belongs to the current user. */ mine?: boolean - /** - * A custom render function the author slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderAuthor?: ShorthandRenderFunction - - /** - * A custom render function the avatar slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderAvatar?: ShorthandRenderFunction - - /** - * A custom render function the content slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderContent?: ShorthandRenderFunction - - /** - * A custom render function the timestamp slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderTimestamp?: ShorthandRenderFunction - /** Timestamp of the message. */ timestamp?: ShorthandValue } @@ -102,10 +66,6 @@ class ChatMessage extends UIComponent, any> { author: customPropTypes.itemShorthand, avatar: customPropTypes.itemShorthand, mine: PropTypes.bool, - renderAuthor: PropTypes.func, - renderAvatar: PropTypes.func, - renderContent: PropTypes.func, - renderTimestamp: PropTypes.func, timestamp: customPropTypes.itemShorthand, } @@ -150,24 +110,13 @@ class ChatMessage extends UIComponent, any> { styles: ComponentSlotStylesInput, variables: ComponentVariablesInput, ) => { - const { - author, - avatar, - content, - mine, - renderAuthor, - renderAvatar, - renderTimestamp, - renderContent, - timestamp, - } = this.props + const { author, avatar, content, mine, timestamp } = this.props const avatarElement = Avatar.create(avatar, { defaultProps: { styles: styles.avatar, variables: variables.avatar, }, - render: renderAvatar, }) const authorElement = Text.create(author, { @@ -175,7 +124,6 @@ class ChatMessage extends UIComponent, any> { size: 'small', styles: styles.author, }, - render: renderAuthor, }) const timestampElement = Text.create(timestamp, { @@ -184,12 +132,10 @@ class ChatMessage extends UIComponent, any> { styles: styles.timestamp, timestamp: true, }, - render: renderTimestamp, }) const contentElement = Slot.create(content, { defaultProps: { styles: styles.content }, - render: renderContent, }) return ( diff --git a/src/components/Form/Form.tsx b/src/components/Form/Form.tsx index 9a1f8d4a9b..da0bf853d7 100644 --- a/src/components/Form/Form.tsx +++ b/src/components/Form/Form.tsx @@ -10,12 +10,7 @@ import { ChildrenComponentProps, commonPropTypes, } from '../../lib' -import { - ComponentEventHandler, - Extendable, - ShorthandValue, - ShorthandRenderFunction, -} from '../../../types/utils' +import { ComponentEventHandler, Extendable, ShorthandValue } from '../../../types/utils' import FormField from './FormField' export interface FormProps extends UIComponentProps, ChildrenComponentProps { @@ -31,16 +26,6 @@ export interface FormProps extends UIComponentProps, ChildrenComponentProps { * @param {object} data - All props. */ onSubmit?: ComponentEventHandler - - /** - * A custom render iterator for rendering each of the Form fields. - * The default component, props, and children are available for each field. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderField?: ShorthandRenderFunction } /** @@ -62,7 +47,6 @@ class Form extends UIComponent, any> { action: PropTypes.string, fields: customPropTypes.collectionShorthand, onSubmit: PropTypes.func, - renderField: PropTypes.func, } public static defaultProps = { @@ -71,14 +55,7 @@ class Form extends UIComponent, any> { public static Field = FormField - public renderComponent({ - ElementType, - classes, - accessibility, - variables, - styles, - rest, - }): React.ReactNode { + public renderComponent({ ElementType, classes, rest }): React.ReactNode { const { action, children } = this.props return ( @@ -97,12 +74,8 @@ class Form extends UIComponent, any> { } private renderFields = () => { - const { fields, renderField } = this.props - return _.map(fields, field => - FormField.create(field, { - render: renderField, - }), - ) + const { fields } = this.props + return _.map(fields, field => FormField.create(field)) } } diff --git a/src/components/Form/FormField.tsx b/src/components/Form/FormField.tsx index d8a93468af..de17dfb17f 100644 --- a/src/components/Form/FormField.tsx +++ b/src/components/Form/FormField.tsx @@ -10,7 +10,7 @@ import { ChildrenComponentProps, commonPropTypes, } from '../../lib' -import { Extendable, ShorthandValue, ShorthandRenderFunction } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' import Text from '../Text/Text' import Input from '../Input/Input' import Slot from '../Slot/Slot' @@ -34,33 +34,6 @@ export interface FormFieldProps extends UIComponentProps, ChildrenComponentProps /** The HTML input name. */ name?: string - /** - * A custom render function for the control slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderControl?: ShorthandRenderFunction - - /** - * A custom render function for the label slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderLabel?: ShorthandRenderFunction - - /** - * A custom render function for the message slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderMessage?: ShorthandRenderFunction - /** A field can show that input is mandatory. */ required?: boolean @@ -88,9 +61,6 @@ class FormField extends UIComponent, any> { label: customPropTypes.itemShorthand, message: customPropTypes.itemShorthand, name: PropTypes.string, - renderControl: PropTypes.func, - renderLabel: PropTypes.func, - renderMessage: PropTypes.func, required: PropTypes.bool, type: PropTypes.string, } @@ -108,19 +78,7 @@ class FormField extends UIComponent, any> { styles, rest, }): React.ReactNode { - const { - children, - control, - id, - label, - message, - name, - renderControl, - renderLabel, - renderMessage, - required, - type, - } = this.props + const { children, control, id, label, message, name, required, type } = this.props const labelElement = Text.create(label, { defaultProps: { @@ -128,19 +86,16 @@ class FormField extends UIComponent, any> { htmlFor: id, styles: styles.label, }, - render: renderLabel, }) const messageElement = Text.create(message, { defaultProps: { styles: styles.message, }, - render: renderMessage, }) const controlElement = Slot.create(control || {}, { defaultProps: { required, id, name, type, styles: styles.control }, - render: renderControl, }) const content = ( diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 19e7c1f4e1..d9ade9af52 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -11,7 +11,7 @@ import { commonPropTypes, } from '../../lib' import HeaderDescription from './HeaderDescription' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' export interface HeaderProps extends UIComponentProps, @@ -22,15 +22,6 @@ export interface HeaderProps /** Align header content. */ textAlign?: 'left' | 'center' | 'right' | 'justified' - - /** - * A custom render function the description slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderDescription?: ShorthandRenderFunction } /** @@ -52,7 +43,6 @@ class Header extends UIComponent, any> { ...commonPropTypes.createCommon(), description: customPropTypes.itemShorthand, textAlign: PropTypes.oneOf(['left', 'center', 'right', 'justified']), - renderDescription: PropTypes.func, } static defaultProps = { @@ -62,7 +52,7 @@ class Header extends UIComponent, any> { static Description = HeaderDescription renderComponent({ ElementType, classes, variables: v, rest }) { - const { children, content, description, renderDescription } = this.props + const { children, content, description } = this.props if (childrenExist(children)) { return ( @@ -81,7 +71,6 @@ class Header extends UIComponent, any> { ...(v.descriptionColor && { color: v.descriptionColor }), }, }, - render: renderDescription, })} ) diff --git a/src/components/Input/Input.tsx b/src/components/Input/Input.tsx index 239cff9fa1..239d81a549 100644 --- a/src/components/Input/Input.tsx +++ b/src/components/Input/Input.tsx @@ -12,12 +12,7 @@ import { ChildrenComponentProps, commonPropTypes, } from '../../lib' -import { - Extendable, - ShorthandValue, - ShorthandRenderFunction, - ComponentEventHandler, -} from '../../../types/utils' +import { Extendable, ShorthandValue, ComponentEventHandler } from '../../../types/utils' import Icon from '../Icon/Icon' import Ref from '../Ref/Ref' import Slot from '../Slot/Slot' @@ -52,33 +47,6 @@ export interface InputProps extends UIComponentProps, ChildrenComponentProps { */ onChange?: ComponentEventHandler - /** - * A custom render function the icon slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderIcon?: ShorthandRenderFunction - - /** - * A custom render function the input slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderInput?: ShorthandRenderFunction - - /** - * A custom render function the wrapper slot. - * - * @param { React.ReactType } Component - The computed component for this slot. - * @param { object } props - The computed props for this slot. - * @param { ReactNode | ReactNodeArray } children - The computed children for this slot. - */ - renderWrapper?: ShorthandRenderFunction - /** The HTML input type. */ type?: string @@ -128,9 +96,6 @@ class Input extends AutoControlledComponent, InputState> inputRef: PropTypes.func, inline: PropTypes.bool, onChange: PropTypes.func, - renderIcon: PropTypes.func, - renderInput: PropTypes.func, - renderWrapper: PropTypes.func, type: PropTypes.string, value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), wrapper: customPropTypes.wrapperShorthand, @@ -151,7 +116,7 @@ class Input extends AutoControlledComponent, InputState> styles, variables, }: RenderResultConfig) { - const { className, input, renderIcon, renderInput, renderWrapper, type, wrapper } = this.props + const { className, input, type, wrapper } = this.props const { value = '' } = this.state const [htmlInputProps, rest] = partitionHTMLProps(restProps) @@ -170,7 +135,6 @@ class Input extends AutoControlledComponent, InputState> className: classes.input, onChange: this.handleChange, }, - render: renderInput, })} {Icon.create(this.computeIcon(), { @@ -179,7 +143,6 @@ class Input extends AutoControlledComponent, InputState> variables: variables.icon, }, overrideProps: this.handleIconOverrides, - render: renderIcon, })} ), @@ -194,7 +157,6 @@ class Input extends AutoControlledComponent, InputState> overrideProps: { as: (wrapper && (wrapper as any).as) || ElementType, }, - render: renderWrapper, }) } diff --git a/src/components/Label/Label.tsx b/src/components/Label/Label.tsx index 21496a2ef7..a24a3f5b74 100644 --- a/src/components/Label/Label.tsx +++ b/src/components/Label/Label.tsx @@ -15,8 +15,7 @@ import { import { Icon, Image, Layout } from '../..' import { Accessibility } from '../../lib/accessibility/types' - -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' export interface LabelProps extends UIComponentProps, @@ -41,24 +40,6 @@ export interface LabelProps /** An icon label can format an Icon to appear before or after the text in the label */ imagePosition?: 'start' | 'end' - - /** - * A custom render function the icon slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderIcon?: ShorthandRenderFunction - - /** - * A custom render function the image slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderImage?: ShorthandRenderFunction } /** @@ -79,8 +60,6 @@ class Label extends UIComponent, any> { image: customPropTypes.itemShorthand, imagePosition: PropTypes.oneOf(['start', 'end']), fluid: PropTypes.bool, - renderIcon: PropTypes.func, - renderImage: PropTypes.func, } static defaultProps = { @@ -99,16 +78,7 @@ class Label extends UIComponent, any> { } renderComponent({ ElementType, classes, rest, variables, styles }) { - const { - children, - content, - icon, - iconPosition, - image, - imagePosition, - renderIcon, - renderImage, - } = this.props + const { children, content, icon, iconPosition, image, imagePosition } = this.props const imageElement = image && @@ -117,7 +87,6 @@ class Label extends UIComponent, any> { styles: styles.image, variables: variables.image, }, - render: renderImage, }) const iconElement = @@ -128,7 +97,6 @@ class Label extends UIComponent, any> { variables: variables.icon, }, overrideProps: this.handleIconOverrides, - render: renderIcon, }) let start: React.ReactNode = null diff --git a/src/components/List/List.tsx b/src/components/List/List.tsx index 6ac3316591..cee47f7d2e 100644 --- a/src/components/List/List.tsx +++ b/src/components/List/List.tsx @@ -15,8 +15,7 @@ import ListItem from './ListItem' import { listBehavior } from '../../lib/accessibility' import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibility/types' import { ContainerFocusHandler } from '../../lib/accessibility/FocusHandling/FocusContainer' - -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' export interface ListProps extends UIComponentProps, ChildrenComponentProps { /** @@ -39,16 +38,6 @@ export interface ListProps extends UIComponentProps, ChildrenComponentProps { /** Truncates header */ truncateHeader?: boolean - - /** - * A custom render iterator for rendering each of the List items. - * The default component, props, and children are available for each item. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderItem?: ShorthandRenderFunction } export interface ListState { @@ -73,7 +62,6 @@ class List extends UIComponent, ListState> { selection: PropTypes.bool, truncateContent: PropTypes.bool, truncateHeader: PropTypes.bool, - renderItem: PropTypes.func, } static defaultProps = { @@ -142,7 +130,7 @@ class List extends UIComponent, ListState> { } renderItems() { - const { items, renderItem } = this.props + const { items } = this.props const { selectedItemIndex } = this.state this.itemRefs = [] @@ -166,7 +154,6 @@ class List extends UIComponent, ListState> { return ListItem.create(item, { defaultProps: itemProps, - render: renderItem, }) }) } diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx index 5aa37c2d45..07b6960906 100644 --- a/src/components/Menu/Menu.tsx +++ b/src/components/Menu/Menu.tsx @@ -15,7 +15,7 @@ import { menuBehavior } from '../../lib/accessibility' import { Accessibility } from '../../lib/accessibility/types' import { ComponentVariablesObject } from '../../themes/types' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' export interface MenuProps extends UIComponentProps, ChildrenComponentProps { /** @@ -51,16 +51,6 @@ export interface MenuProps extends UIComponentProps, ChildrenComponentProps { /** The menu can have primary type. */ primary?: boolean - /** - * A custom render iterator for rendering each of the Menu items. - * The default component, props, and children are available for each item. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderItem?: ShorthandRenderFunction - /** The menu can have secondary type. */ secondary?: boolean @@ -94,7 +84,6 @@ class Menu extends AutoControlledComponent, any> { pills: PropTypes.bool, pointing: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['start', 'end'])]), primary: customPropTypes.every([customPropTypes.disallow(['secondary']), PropTypes.bool]), - renderItem: PropTypes.func, secondary: customPropTypes.every([customPropTypes.disallow(['primary']), PropTypes.bool]), underlined: PropTypes.bool, vertical: PropTypes.bool, @@ -126,7 +115,6 @@ class Menu extends AutoControlledComponent, any> { pills, pointing, primary, - renderItem, secondary, underlined, vertical, @@ -148,7 +136,6 @@ class Menu extends AutoControlledComponent, any> { active: parseInt(activeIndex, 10) === index, }, overrideProps: this.handleItemOverrides, - render: renderItem, }), ) } diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx index b115d7e1e9..ae090630f8 100644 --- a/src/components/Menu/MenuItem.tsx +++ b/src/components/Menu/MenuItem.tsx @@ -18,13 +18,7 @@ import Slot from '../Slot/Slot' import { menuItemBehavior } from '../../lib/accessibility' import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibility/types' import IsFromKeyboard from '../../lib/isFromKeyboard' - -import { - ComponentEventHandler, - Extendable, - ShorthandRenderFunction, - ShorthandValue, -} from '../../../types/utils' +import { ComponentEventHandler, Extendable, ShorthandValue } from '../../../types/utils' export interface MenuItemProps extends UIComponentProps, @@ -72,24 +66,6 @@ export interface MenuItemProps /** The menu item can have primary type. */ primary?: boolean - /** - * A custom render function the icon slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderIcon?: ShorthandRenderFunction - - /** - * A custom render function the wrapper slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderWrapper?: ShorthandRenderFunction - /** The menu item can have secondary type. */ secondary?: boolean @@ -132,9 +108,7 @@ class MenuItem extends UIComponent, MenuItemState> { secondary: customPropTypes.every([customPropTypes.disallow(['primary']), PropTypes.bool]), underlined: PropTypes.bool, vertical: PropTypes.bool, - renderIcon: PropTypes.func, wrapper: PropTypes.oneOfType([PropTypes.node, PropTypes.object]), - renderWrapper: PropTypes.func, } static defaultProps = { @@ -146,7 +120,7 @@ class MenuItem extends UIComponent, MenuItemState> { state = IsFromKeyboard.initial renderComponent({ ElementType, classes, accessibility, rest }) { - const { children, content, icon, renderIcon, renderWrapper, wrapper } = this.props + const { children, content, icon, wrapper } = this.props const menuItemInner = childrenExist(children) ? ( children @@ -163,7 +137,6 @@ class MenuItem extends UIComponent, MenuItemState> { {icon && Icon.create(this.props.icon, { defaultProps: { xSpacing: !!content ? 'after' : 'none' }, - render: renderIcon, })} {content} @@ -176,7 +149,6 @@ class MenuItem extends UIComponent, MenuItemState> { ...accessibility.attributes.root, ...accessibility.keyHandlers.root, }, - render: renderWrapper, overrideProps: () => ({ children: menuItemInner, }), diff --git a/src/components/RadioGroup/RadioGroup.tsx b/src/components/RadioGroup/RadioGroup.tsx index 5a05319ed5..c27ca0ebd4 100644 --- a/src/components/RadioGroup/RadioGroup.tsx +++ b/src/components/RadioGroup/RadioGroup.tsx @@ -15,13 +15,7 @@ import { import RadioGroupItem, { RadioGroupItemProps } from './RadioGroupItem' import { radioGroupBehavior } from '../../lib/accessibility' import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibility/types' - -import { - Extendable, - ShorthandValue, - ShorthandRenderFunction, - ComponentEventHandler, -} from '../../../types/utils' +import { Extendable, ShorthandValue, ComponentEventHandler } from '../../../types/utils' export interface RadioGroupProps extends UIComponentProps, ChildrenComponentProps { /** @@ -46,16 +40,6 @@ export interface RadioGroupProps extends UIComponentProps, ChildrenComponentProp /** Shorthand array of props for RadioGroup. */ items?: ShorthandValue[] - /** - * A custom render iterator for rendering each of the RadioGroup items. - * The default component, props, and children are available for each item. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderItem?: ShorthandRenderFunction - /** A vertical radio group displays elements vertically. */ vertical?: boolean } @@ -79,7 +63,6 @@ class RadioGroup extends AutoControlledComponent, an defaultCheckedValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), items: customPropTypes.collectionShorthand, checkedValueChanged: PropTypes.func, - renderItem: PropTypes.func, vertical: PropTypes.bool, } @@ -177,13 +160,12 @@ class RadioGroup extends AutoControlledComponent, an }) private renderItems = (vertical: boolean) => { - const { items, renderItem } = this.props + const { items } = this.props return _.map(items, item => RadioGroupItem.create(item, { defaultProps: { vertical }, overrideProps: this.handleItemOverrides, - render: renderItem, }), ) } diff --git a/src/components/RadioGroup/RadioGroupItem.tsx b/src/components/RadioGroup/RadioGroupItem.tsx index d0061133aa..d49f1571c2 100644 --- a/src/components/RadioGroup/RadioGroupItem.tsx +++ b/src/components/RadioGroup/RadioGroupItem.tsx @@ -12,12 +12,7 @@ import { commonPropTypes, } from '../../lib' import Label from '../Label/Label' -import { - ComponentEventHandler, - Extendable, - ShorthandRenderFunction, - ShorthandValue, -} from '../../../types/utils' +import { ComponentEventHandler, Extendable, ShorthandValue } from '../../../types/utils' import Icon from '../Icon/Icon' import { Accessibility } from '../../lib/accessibility/types' import { radioGroupItemBehavior } from '../../lib/accessibility' @@ -79,15 +74,6 @@ export interface RadioGroupItemProps extends UIComponentProps, ChildrenComponent */ onFocus?: ComponentEventHandler - /** - * A custom render function the icon slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderIcon?: ShorthandRenderFunction - /** Whether should focus when checked */ shouldFocus?: boolean // TODO: RFC #306 @@ -141,7 +127,6 @@ class RadioGroupItem extends AutoControlledComponent< onClick: PropTypes.func, onFocus: PropTypes.func, checkedChanged: PropTypes.func, - renderIcon: PropTypes.func, shouldFocus: PropTypes.bool, value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), vertical: PropTypes.bool, @@ -167,7 +152,7 @@ class RadioGroupItem extends AutoControlledComponent< } renderComponent({ ElementType, classes, rest, styles, variables, accessibility }) { - const { label, icon, renderIcon } = this.props + const { label, icon } = this.props return ( { /** A segment can have its colors inverted for contrast. */ inverted?: boolean - - /** - * A custom render function the content slot. - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderContent?: ShorthandRenderFunction } /** @@ -40,7 +32,6 @@ class Segment extends UIComponent, any> { content: 'shorthand', }), inverted: PropTypes.bool, - renderContent: PropTypes.func, } static defaultProps = { @@ -48,11 +39,11 @@ class Segment extends UIComponent, any> { } renderComponent({ ElementType, classes, rest }) { - const { children, content, renderContent } = this.props + const { children, content } = this.props return ( - {childrenExist(children) ? children : Slot.create(content, { render: renderContent })} + {childrenExist(children) ? children : Slot.create(content)} ) } diff --git a/src/components/Status/Status.tsx b/src/components/Status/Status.tsx index ec5a1534d2..80410fa281 100644 --- a/src/components/Status/Status.tsx +++ b/src/components/Status/Status.tsx @@ -9,7 +9,7 @@ import { UIComponentProps, commonPropTypes, } from '../../lib' -import { Extendable, ShorthandRenderFunction, ShorthandValue } from '../../../types/utils' +import { Extendable, ShorthandValue } from '../../../types/utils' export interface StatusProps extends UIComponentProps { /** A custom color. */ @@ -18,15 +18,6 @@ export interface StatusProps extends UIComponentProps { /** Shorthand for the icon, to provide customizing status */ icon?: ShorthandValue - /** - * A custom render function the icon slot. - * - * @param {React.ReactType} Component - The computed component for this slot. - * @param {object} props - The computed props for this slot. - * @param {ReactNode|ReactNodeArray} children - The computed children for this slot. - */ - renderIcon?: ShorthandRenderFunction - /** Size multiplier */ size?: number @@ -51,7 +42,6 @@ class Status extends UIComponent, any> { }), color: PropTypes.string, icon: customPropTypes.itemShorthand, - renderIcon: PropTypes.func, size: PropTypes.number, state: PropTypes.oneOf(['success', 'info', 'warning', 'error', 'unknown']), } @@ -63,7 +53,7 @@ class Status extends UIComponent, any> { } renderComponent({ ElementType, classes, rest, variables, styles }) { - const { icon, renderIcon } = this.props as StatusPropsWithDefaults + const { icon } = this.props as StatusPropsWithDefaults return ( {Icon.create(icon, { @@ -72,7 +62,6 @@ class Status extends UIComponent, any> { styles: styles.icon, variables: variables.icon, xSpacing: 'none', - render: renderIcon, }, })} diff --git a/src/lib/factories.tsx b/src/lib/factories.tsx index fb4d1d208b..2684c19ef0 100644 --- a/src/lib/factories.tsx +++ b/src/lib/factories.tsx @@ -1,16 +1,19 @@ import * as _ from 'lodash' import * as cx from 'classnames' import * as React from 'react' -import { ShorthandRenderFunction, ShorthandValue, Props } from '../../types/utils' +import { + ShorthandValue, + Props, + ShorthandRenderCallback, + ShorthandRenderFunction, + ShorthandRenderer, +} from '../../types/utils' import { mergeStyles } from './mergeThemes' type HTMLTag = 'iframe' | 'img' | 'input' type ShorthandProp = 'children' | 'src' | 'type' interface CreateShorthandOptions { - /** Override the default render implementation. */ - render?: ShorthandRenderFunction - /** Default props object */ defaultProps?: Props @@ -19,12 +22,16 @@ interface CreateShorthandOptions { /** Whether or not automatic key generation is allowed */ generateKey?: boolean + + /** Override the default render implementation. */ + render?: ShorthandRenderFunction } const CREATE_SHORTHAND_DEFAULT_OPTIONS: CreateShorthandOptions = { defaultProps: {}, overrideProps: {}, generateKey: true, + render: (Component, props) => , } // It's only necessary to map props that don't use 'children' as value ('children' is the default) @@ -42,9 +49,55 @@ const mappedProps: { [key in HTMLTag]: ShorthandProp } = { export function createShorthand( Component: React.ReactType, mappedProp: string, - value?: ShorthandValue, + valueOrRenderCallback?: ShorthandValue | ShorthandRenderCallback, options: CreateShorthandOptions = CREATE_SHORTHAND_DEFAULT_OPTIONS, ): React.ReactElement | null | undefined { + const valIsRenderFunction = + typeof valueOrRenderCallback === 'function' && !React.isValidElement(valueOrRenderCallback) + if (valIsRenderFunction) { + return createShorthandFromRenderCallback( + Component, + mappedProp, + valueOrRenderCallback as ShorthandRenderCallback, + options, + ) + } + + return createShorthandFromValue( + Component, + mappedProp, + valueOrRenderCallback as ShorthandValue, + options, + ) +} + +// ============================================================ +// Factory Creators +// ============================================================ + +/** + * @param {React.ReactType} Component A ReactClass or string + * @param {string} mappedProp A function that maps a primitive value to the Component props + * @returns {function} A shorthand factory function waiting for `val` and `defaultProps`. + */ +export function createShorthandFactory(Component: React.ReactType, mappedProp?: string) { + if (typeof Component !== 'function' && typeof Component !== 'string') { + throw new Error('createShorthandFactory() Component must be a string or function.') + } + + return (val, options) => createShorthand(Component, mappedProp, val, options) +} + +// ============================================================ +// Private Utils +// ============================================================ + +function createShorthandFromValue( + Component: React.ReactType, + mappedProp: string, + value?: ShorthandValue, + options: CreateShorthandOptions = CREATE_SHORTHAND_DEFAULT_OPTIONS, +) { if (typeof Component !== 'function' && typeof Component !== 'string') { throw new Error('createShorthand() Component must be a string or function.') } @@ -134,9 +187,8 @@ export function createShorthand( // Create Element // ---------------------------------------- const { render } = options - if (render) { - return render(Component, props, props.children) + return render(Component, props) } // Clone ReactElements @@ -148,19 +200,18 @@ export function createShorthand( return null } -// ============================================================ -// Factory Creators -// ============================================================ - -/** - * @param {React.ReactType} Component A ReactClass or string - * @param {string} mappedProp A function that maps a primitive value to the Component props - * @returns {function} A shorthand factory function waiting for `val` and `defaultProps`. - */ -export function createShorthandFactory(Component: React.ReactType, mappedProp?: string) { - if (typeof Component !== 'function' && typeof Component !== 'string') { - throw new Error('createShorthandFactory() Component must be a string or function.') +function createShorthandFromRenderCallback( + Component: React.ReactType, + mappedProp: string, + renderCallback: ShorthandRenderCallback, + options: CreateShorthandOptions = CREATE_SHORTHAND_DEFAULT_OPTIONS, +) { + const render: ShorthandRenderer = (shorthandValue, renderTree) => { + return createShorthandFromValue(Component, mappedProp, shorthandValue, { + ...options, + ...(renderTree && { render: renderTree }), + }) } - return (val, options) => createShorthand(Component, mappedProp, val, options) + return renderCallback(render) } diff --git a/test/specs/lib/factories-test.tsx b/test/specs/lib/factories-test.tsx index 555f5e1554..5b3b22461a 100644 --- a/test/specs/lib/factories-test.tsx +++ b/test/specs/lib/factories-test.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import * as _ from 'lodash' import { shallow } from 'enzyme' import { createShorthand, createShorthandFactory } from 'src/lib' -import { Props, ShorthandValue, ObjectOf } from 'types/utils' +import { Props, ShorthandValue, ObjectOf, ShorthandRenderFunction } from 'types/utils' import { consoleUtil } from 'test/utils' import callable from '../../../src/lib/callable' @@ -17,7 +17,7 @@ type GetShorthandArgs = { overrideProps?: Props & ((props: Props) => Props) | Props generateKey?: boolean value?: ShorthandValue - render?: any + render?: ShorthandRenderFunction } /** @@ -200,54 +200,61 @@ describe('factories', () => { }) }) - describe('render', () => { - const testValue = 'hi' + describe('render callback', () => { + test('returns the same React element as if shorthand value would be passed directly', () => { + const createShorthandElement = valueOrRenderCallback => + getShorthand({ + value: valueOrRenderCallback, + Component: 'div', + defaultProps: { + baz: 'original', + }, + overrideProps: { + baz: 'overriden', + }, + }) - test('is called once', () => { - const spy = jest.fn() + const shorthandValue = { dataFoo: 'bar' } - getShorthand({ value: testValue, render: spy }) + const elementFromShorthandValue = createShorthandElement(shorthandValue) + const elementFromRenderCallback = createShorthandElement(render => render(shorthandValue)) - expect(spy).toHaveBeenCalledTimes(1) + expect(elementFromShorthandValue.type).toEqual(elementFromRenderCallback.type) + expect(elementFromShorthandValue.props).toEqual(elementFromRenderCallback.props) }) - test('is called with the computed component, props, and children', () => { - const spy = jest.fn(() =>
) - - getShorthand({ - value: testValue, - Component: 'p', - mappedProp: 'children', - render: spy, + describe('custom tree renderer', () => { + test('passes evaluated Component type as the first argument', () => { + getShorthand({ + value: render => + render({}, (Component, props) => { + expect(Component).toBe('foo-span') + }), + Component: 'foo-span', + }) }) - expect(spy).toHaveBeenCalledWith('p', { key: testValue, children: testValue }, testValue) - }) - - test('receives defaultProps and defaults mappedProp to children in its props argument', () => { - const spy = jest.fn(() =>
) - const defaultProps = { defaults: true } + test('passes evaluated props as the second argument', () => { + const shorthandProps = { bar: 'foo' } - getShorthand({ value: testValue, defaultProps, Component: 'p', render: spy }) - - expect(spy).toHaveBeenCalledWith( - 'p', - { key: testValue, children: testValue, ...defaultProps }, - testValue, - ) - }) + getShorthand({ + value: render => + render(shorthandProps, (Component, props) => { + expect(props.bar).toBe(shorthandProps.bar) + }), + }) + }) - test('receives overrideProps and defaults mappedProp to children in its props argument', () => { - const spy = jest.fn(() =>
) - const overrideProps = { overrides: true } + test('overrides render prop from shorthand options', () => { + const CustomComponent = 'overriden-div' as any - getShorthand({ value: testValue, overrideProps, Component: 'p', render: spy }) + const shorthandElement = getShorthand({ + value: render => render({}, (Component, props) => ), + render: (Component, props) =>
Default
, + }) - expect(spy).toHaveBeenCalledWith( - 'p', - { key: testValue, children: testValue, ...overrideProps }, - testValue, - ) + expect(shorthandElement.type).toBe(CustomComponent) + }) }) }) @@ -266,15 +273,15 @@ describe('factories', () => { } getShorthand({ - value: props, + value: render => + render(props, (Component, props) => { + expect(callable(props.styles)()).toMatchObject({ + color: 'black', + ':hover': { color: 'blue' }, + }) + }), Component: 'p', defaultProps, - render(Component, props) { - expect(callable(props.styles)()).toMatchObject({ - color: 'black', - ':hover': { color: 'blue' }, - }) - }, }) }) @@ -301,19 +308,19 @@ describe('factories', () => { } getShorthand({ - value: props, + value: render => + render(props, (Component, props) => { + expect(callable(props.styles)()).toMatchObject({ + position: 'keep', + color: 'black', + ':hover': { + position: 'keep', + color: 'blue', + }, + }) + }), Component: 'p', overrideProps, - render(Component, props) { - expect(callable(props.styles)()).toMatchObject({ - position: 'keep', - color: 'black', - ':hover': { - position: 'keep', - color: 'blue', - }, - }) - }, }) }) @@ -331,15 +338,15 @@ describe('factories', () => { } getShorthand({ - value: props, + value: render => + render(props, (Component, props) => { + expect(callable(props.styles)()).toMatchObject({ + color: 'black', + ':hover': { color: 'blue' }, + }) + }), Component: 'p', defaultProps, - render(Component, props) { - expect(callable(props.styles)()).toMatchObject({ - color: 'black', - ':hover': { color: 'blue' }, - }) - }, }) }) @@ -366,19 +373,19 @@ describe('factories', () => { } getShorthand({ - value: props, + value: render => + render(props, (Component, props) => { + expect(callable(props.styles)()).toMatchObject({ + position: 'keep', + color: 'black', + ':hover': { + position: 'keep', + color: 'blue', + }, + }) + }), Component: 'p', overrideProps, - render(Component, props) { - expect(callable(props.styles)()).toMatchObject({ - position: 'keep', - color: 'black', - ':hover': { - position: 'keep', - color: 'blue', - }, - }) - }, }) }) }) diff --git a/types/utils.d.ts b/types/utils.d.ts index fa3651dff5..8d7078163c 100644 --- a/types/utils.d.ts +++ b/types/utils.d.ts @@ -30,9 +30,16 @@ export type ComponentEventHandler = (event: React.SyntheticEvent, data: // Shorthand Factories // ======================================================== -export type ShorthandValue = React.ReactNode | Props export type ShorthandRenderFunction = ( Component: React.ReactType, props: Props, - children: ReactChildren, ) => React.ReactElement + +export type ShorthandRenderer = ( + value: ShorthandValue, + renderTree?: ShorthandRenderFunction, +) => React.ReactElement + +export type ShorthandRenderCallback = (render: ShorthandRenderer) => React.ReactElement + +export type ShorthandValue = React.ReactNode | Props