Skip to content

Commit

Permalink
feat(factories): add autoGenerateKey option (#2424)
Browse files Browse the repository at this point in the history
* feat(factories): add `generateKey` option

Can be used to disable automatic key generation for shorthand props with string/number values
when the factory is called (not when it is created).

* Rename generateKey to autoGenerateKey

* Refactor tests

* Add failing shorthand prop tests

* Clean up JSDoc

* `autoGenerateKey: false` flag added for shorthands that are tested, tests passing

* fix(Confirm): fix shorthand key generation

* fix(Label): fix shorthand key generation

* feat(LabelDetail): add create method

* fix(Step): fix shorthand key generation

* fix(List): fix shorthand key generation

* fix(Popup): fix shorthand key generation

* fix(Progress): fix shorthand key generation

* fix(Search): fix shorthand key generation

* fix(Tab): fix shorthand key generation

* fix(Card): fix shorthand key generation

* fix(CommentAvatar): fix shorthand key generation

* feat(docs): improve ux

* fix(Tab): restore tab pane keys
  • Loading branch information
noinkling authored and levithomason committed May 21, 2018
1 parent cd73084 commit 99b6a57
Show file tree
Hide file tree
Showing 44 changed files with 295 additions and 196 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ class ComponentExample extends PureComponent {
}
}, 100)

getComponentName = () => this.props.examplePath.split('/')[1]

handleChangeCode = (sourceCode) => {
this.setState({ sourceCode }, this.renderSourceCode)
}
Expand Down
13 changes: 4 additions & 9 deletions docs/app/Examples/addons/Confirm/Types/ConfirmExampleConfirm.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,14 @@ import { Button, Confirm } from 'semantic-ui-react'
class ConfirmExampleConfirm extends Component {
state = { open: false }

show = () => this.setState({ open: true })
handleConfirm = () => this.setState({ open: false })
handleCancel = () => this.setState({ open: false })
open = () => this.setState({ open: true })
close = () => this.setState({ open: false })

render() {
return (
<div>
<Button onClick={this.show}>Show</Button>
<Confirm
open={this.state.open}
onCancel={this.handleCancel}
onConfirm={this.handleConfirm}
/>
<Button onClick={this.open}>Show</Button>
<Confirm open={this.state.open} onCancel={this.close} onConfirm={this.close} />
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ const ModalExampleScrollingContent = () => (
<Modal trigger={<Button>Scrolling Content Modal</Button>}>
<Modal.Header>Profile Picture</Modal.Header>
<Modal.Content image scrolling>
<Image
size='medium'
src='/assets/images/wireframe/image.png'
wrapped
/>
<Image size='medium' src='/assets/images/wireframe/image.png' wrapped />

<Modal.Description>
<Header>Modal Header</Header>
Expand All @@ -34,4 +30,3 @@ const ModalExampleScrollingContent = () => (
)

export default ModalExampleScrollingContent

25 changes: 9 additions & 16 deletions src/addons/Confirm/Confirm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import _ from 'lodash'
import PropTypes from 'prop-types'
import React, { Component } from 'react'

import {
customPropTypes,
getUnhandledProps,
META,
} from '../../lib'
import { customPropTypes, getUnhandledProps, META } from '../../lib'
import Button from '../../elements/Button'
import Modal from '../../modules/Modal'

Expand Down Expand Up @@ -82,14 +78,7 @@ class Confirm extends Component {
})

render() {
const {
cancelButton,
confirmButton,
content,
header,
open,
size,
} = this.props
const { cancelButton, confirmButton, content, header, open, size } = this.props
const rest = getUnhandledProps(Confirm, this.props)

// `open` is auto controlled by the Modal
Expand All @@ -100,11 +89,15 @@ class Confirm extends Component {

return (
<Modal {...rest} {...openProp} size={size} onClose={this.handleCancel}>
{Modal.Header.create(header)}
{Modal.Content.create(content)}
{Modal.Header.create(header, { autoGenerateKey: false })}
{Modal.Content.create(content, { autoGenerateKey: false })}
<Modal.Actions>
{Button.create(cancelButton, { overrideProps: this.handleCancelOverrides })}
{Button.create(cancelButton, {
autoGenerateKey: false,
overrideProps: this.handleCancelOverrides,
})}
{Button.create(confirmButton, {
autoGenerateKey: false,
defaultProps: { primary: true },
overrideProps: this.handleConfirmOverrides,
})}
Expand Down
8 changes: 7 additions & 1 deletion src/collections/Breadcrumb/BreadcrumbDivider.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ function BreadcrumbDivider(props) {
const rest = getUnhandledProps(BreadcrumbDivider, props)
const ElementType = getElementType(BreadcrumbDivider, props)

if (!_.isNil(icon)) return Icon.create(icon, { defaultProps: { ...rest, className: classes } })
if (!_.isNil(icon)) {
return Icon.create(icon, {
defaultProps: { ...rest, className: classes },
autoGenerateKey: false,
})
}

if (!_.isNil(content)) return <ElementType {...rest} className={classes}>{content}</ElementType>

return (
Expand Down
11 changes: 8 additions & 3 deletions src/collections/Form/FormField.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ function FormField(props) {
)
}

return <ElementType {...rest} className={classes}>{createHTMLLabel(label)}</ElementType>
return (
<ElementType {...rest} className={classes}>
{createHTMLLabel(label, { autoGenerateKey: false })}
</ElementType>
)
}

// ----------------------------------------
Expand Down Expand Up @@ -102,8 +106,9 @@ function FormField(props) {

return (
<ElementType className={classes}>
{createHTMLLabel(label, { defaultProps: {
htmlFor: _.get(controlProps, 'id') },
{createHTMLLabel(label, {
defaultProps: { htmlFor: _.get(controlProps, 'id') },
autoGenerateKey: false,
})}
{createElement(control, controlProps)}
</ElementType>
Expand Down
2 changes: 1 addition & 1 deletion src/collections/Menu/MenuItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export default class MenuItem extends Component {

return (
<ElementType {...rest} className={classes} onClick={this.handleClick}>
{Icon.create(icon)}
{Icon.create(icon, { autoGenerateKey: false })}
{childrenUtils.isNil(content) ? _.startCase(name) : content}
</ElementType>
)
Expand Down
8 changes: 4 additions & 4 deletions src/collections/Message/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,12 @@ export default class Message extends Component {
return (
<ElementType {...rest} className={classes}>
{dismissIcon}
{Icon.create(icon)}
{Icon.create(icon, { autoGenerateKey: false })}
{(!_.isNil(header) || !_.isNil(content) || !_.isNil(list)) && (
<MessageContent>
{MessageHeader.create(header)}
{MessageList.create(list)}
{createHTMLParagraph(content)}
{MessageHeader.create(header, { autoGenerateKey: false })}
{MessageList.create(list, { autoGenerateKey: false })}
{createHTMLParagraph(content, { autoGenerateKey: false })}
</MessageContent>
)}
</ElementType>
Expand Down
5 changes: 3 additions & 2 deletions src/elements/Button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,14 @@ class Button extends Component {
basic: true,
pointing: labelPosition === 'left' ? 'right' : 'left',
},
autoGenerateKey: false,
})

return (
<ElementType {...rest} className={containerClasses} onClick={this.handleClick}>
{labelPosition === 'left' && labelElement}
<button className={buttonClasses} disabled={disabled} ref={this.handleRef} tabIndex={tabIndex}>
{Icon.create(icon)} {content}
{Icon.create(icon, { autoGenerateKey: false })} {content}
</button>
{(labelPosition === 'right' || !labelPosition) && labelElement}
</ElementType>
Expand All @@ -280,7 +281,7 @@ class Button extends Component {
tabIndex={tabIndex}
>
{hasChildren && children}
{!hasChildren && Icon.create(icon)}
{!hasChildren && Icon.create(icon, { autoGenerateKey: false })}
{!hasChildren && content}
</ElementType>
)
Expand Down
6 changes: 3 additions & 3 deletions src/elements/Header/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ function Header(props) {
return <ElementType {...rest} className={classes}>{children}</ElementType>
}

const iconElement = Icon.create(icon)
const imageElement = Image.create(image)
const subheaderElement = HeaderSubheader.create(subheader)
const iconElement = Icon.create(icon, { autoGenerateKey: false })
const imageElement = Image.create(image, { autoGenerateKey: false })
const subheaderElement = HeaderSubheader.create(subheader, { autoGenerateKey: false })

if (iconElement || imageElement) {
return (
Expand Down
4 changes: 2 additions & 2 deletions src/elements/Image/Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ function Image(props) {
if (ElementType === 'img') return <ElementType {...rootProps} {...imgTagProps} className={classes} />
return (
<ElementType {...rootProps} className={classes} href={href}>
{Dimmer.create(dimmer)}
{Label.create(label)}
{Dimmer.create(dimmer, { autoGenerateKey: false })}
{Label.create(label, { autoGenerateKey: false })}
<img {...imgTagProps} />
</ElementType>
)
Expand Down
7 changes: 4 additions & 3 deletions src/elements/Input/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ class Input extends Component {

// Render Shorthand
// ----------------------------------------
const actionElement = Button.create(action)
const actionElement = Button.create(action, { autoGenerateKey: false })
const labelElement = Label.create(label, {
defaultProps: {
className: cx(
Expand All @@ -230,15 +230,16 @@ class Input extends Component {
_.includes(labelPosition, 'corner') && labelPosition,
),
},
autoGenerateKey: false,
})

return (
<ElementType {...rest} className={classes}>
{actionPosition === 'left' && actionElement}
{labelPosition !== 'right' && labelElement}
{createHTMLInput(input || type, { defaultProps: htmlInputProps })}
{createHTMLInput(input || type, { defaultProps: htmlInputProps, autoGenerateKey: false })}
{actionPosition !== 'left' && actionElement}
{Icon.create(this.computeIcon())}
{Icon.create(this.computeIcon(), { autoGenerateKey: false })}
{labelPosition === 'right' && labelElement}
</ElementType>
)
Expand Down
55 changes: 29 additions & 26 deletions src/elements/Label/Label.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import React, { Component } from 'react'

import {
childrenUtils,
createShorthand,
createShorthandFactory,
customPropTypes,
getElementType,
Expand Down Expand Up @@ -33,7 +32,14 @@ export default class Label extends Component {
active: PropTypes.bool,

/** A label can attach to a content segment. */
attached: PropTypes.oneOf(['top', 'bottom', 'top right', 'top left', 'bottom left', 'bottom right']),
attached: PropTypes.oneOf([
'top',
'bottom',
'top right',
'top left',
'bottom left',
'bottom right',
]),

/** A label can reduce its complexity. */
basic: PropTypes.bool,
Expand All @@ -54,19 +60,13 @@ export default class Label extends Component {
content: customPropTypes.contentShorthand,

/** A label can position itself in the corner of an element. */
corner: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.oneOf(['left', 'right']),
]),
corner: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['left', 'right'])]),

/** Shorthand for LabelDetail. */
detail: customPropTypes.itemShorthand,

/** Formats the label as a dot. */
empty: customPropTypes.every([
PropTypes.bool,
customPropTypes.demand(['circular']),
]),
empty: customPropTypes.every([PropTypes.bool, customPropTypes.demand(['circular'])]),

/** Float above another element in the upper right corner. */
floating: PropTypes.bool,
Expand All @@ -78,10 +78,7 @@ export default class Label extends Component {
icon: customPropTypes.itemShorthand,

/** A label can be formatted to emphasize an image or prop can be used as shorthand for Image. */
image: PropTypes.oneOfType([
PropTypes.bool,
customPropTypes.itemShorthand,
]),
image: PropTypes.oneOfType([PropTypes.bool, customPropTypes.itemShorthand]),

/**
* Called on click.
Expand Down Expand Up @@ -109,10 +106,7 @@ export default class Label extends Component {
removeIcon: customPropTypes.itemShorthand,

/** A label can appear as a ribbon attaching itself to an element. */
ribbon: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.oneOf(['right']),
]),
ribbon: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['right'])]),

/** A label can have different sizes. */
size: PropTypes.oneOf(SUI.SIZES),
Expand Down Expand Up @@ -167,9 +161,10 @@ export default class Label extends Component {
tag,
} = this.props

const pointingClass = (pointing === true && 'pointing')
|| ((pointing === 'left' || pointing === 'right') && `${pointing} pointing`)
|| ((pointing === 'above' || pointing === 'below') && `pointing ${pointing}`)
const pointingClass =
(pointing === true && 'pointing') ||
((pointing === 'left' || pointing === 'right') && `${pointing} pointing`) ||
((pointing === 'above' || pointing === 'below') && `pointing ${pointing}`)

const classes = cx(
'ui',
Expand All @@ -194,18 +189,26 @@ export default class Label extends Component {
const ElementType = getElementType(Label, this.props)

if (!childrenUtils.isNil(children)) {
return <ElementType {...rest} className={classes} onClick={this.handleClick}>{children}</ElementType>
return (
<ElementType {...rest} className={classes} onClick={this.handleClick}>
{children}
</ElementType>
)
}

const removeIconShorthand = _.isUndefined(removeIcon) ? 'delete' : removeIcon

return (
<ElementType className={classes} onClick={this.handleClick} {...rest}>
{Icon.create(icon)}
{typeof image !== 'boolean' && Image.create(image)}
{Icon.create(icon, { autoGenerateKey: false })}
{typeof image !== 'boolean' && Image.create(image, { autoGenerateKey: false })}
{content}
{createShorthand(LabelDetail, val => ({ content: val }), detail)}
{onRemove && Icon.create(removeIconShorthand, { overrideProps: this.handleIconOverrides })}
{LabelDetail.create(detail, { autoGenerateKey: false })}
{onRemove &&
Icon.create(removeIconShorthand, {
autoGenerateKey: false,
overrideProps: this.handleIconOverrides,
})}
</ElementType>
)
}
Expand Down
3 changes: 3 additions & 0 deletions src/elements/Label/LabelDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react'

import {
childrenUtils,
createShorthandFactory,
customPropTypes,
getElementType,
getUnhandledProps,
Expand Down Expand Up @@ -43,4 +44,6 @@ LabelDetail.propTypes = {
content: customPropTypes.contentShorthand,
}

LabelDetail.create = createShorthandFactory(LabelDetail, val => ({ content: val }))

export default LabelDetail
Loading

0 comments on commit 99b6a57

Please sign in to comment.