-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(Modal): Create a Modal using shorthand props #1508
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1508 +/- ##
==========================================
+ Coverage 99.74% 99.74% +<.01%
==========================================
Files 141 141
Lines 2384 2396 +12
==========================================
+ Hits 2378 2390 +12
Misses 6 6
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the work! Here's an initial pass review on progress so far.
src/modules/Modal/Modal.js
Outdated
@@ -265,6 +279,18 @@ class Modal extends Component { | |||
<ElementType {...rest} className={classes} style={{ marginTop }} ref={this.handleRef}> | |||
{Icon.create(closeIconName, { onClick: this.handleClose })} | |||
{children} | |||
{_.isNil(children) && header && ModalHeader.create(header)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove the && header
check for each shorthand create
method as the factories handle falsy values internally.
src/modules/Modal/ModalActions.js
Outdated
@@ -37,4 +38,6 @@ ModalActions.propTypes = { | |||
className: PropTypes.string, | |||
} | |||
|
|||
ModalActions.create = createShorthandFactory(ModalActions, children => ({ children })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there can be many buttons, we need to allow the user to pass a key
or our childKey
prop. The third parameter to acreateShorthandFactory
function is a boolean telling the factory to accept keys:
createShorthandFactory(ModalActions, children => ({ children }), true)
Next, this should probably map its value to an actions
prop rather than children
. The render method will then map over the actions
and create buttons:
createShorthandFactory(ModalActions, actions => ({ actions }), true)
This enables users to use the actions
prop on the Modal.Actions
themselves as well:
<Modal>
<Modal.Actions actions={['No', { primary: true, content: 'Yes' }]} />
</Modal>
src/modules/Modal/Modal.js
Outdated
} | ||
action.onClick = onClick(action.onClick) | ||
} | ||
return Button.create(action, { key: i }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using index for a key is an antipattern. Instead, we can configure the factory to allow the to pass a key. See comment on ModalActions.create
below.
@@ -53,15 +57,21 @@ class Modal extends Component { | |||
/** Whether or not the Modal should close when the document is clicked. */ | |||
closeOnDocumentClick: PropTypes.bool, | |||
|
|||
/** Simple text content for the Modal. */ | |||
content: customPropTypes.itemShorthand, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we update propTypes, we should also update the typings in the same directory. Example, Modal.d.ts
.
…rop for action in Modal Action to fix failing test
I've made the changes. |
src/modules/Modal/ModalActions.js
Outdated
@@ -27,6 +35,9 @@ ModalActions._meta = { | |||
} | |||
|
|||
ModalActions.propTypes = { | |||
/** Elements to render as Modal action buttons. */ | |||
actions: PropTypes.arrayOf(customPropTypes.itemShorthand), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as
is always first in propTypes
src/modules/Modal/ModalActions.js
Outdated
|
||
/** | ||
* A modal can contain a row of actions. | ||
*/ | ||
function ModalActions(props) { | ||
const { children, className } = props | ||
const { children, className, actions } = props |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please sort props in alphabetical order
src/modules/Modal/ModalActions.js
Outdated
{children} | ||
{_.isNil(children) && actions.map((action) => Button.create(action, true))} | ||
</ElementType> | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can make there a short condition:
if(!_.isNil(children)) return <ElementType {...rest} className={classes}>{children}</ElementType>
return (
<ElementType {...rest} className={classes}>
{actions.map(action => Button.create(action, true))}
</ElementType>
)
src/modules/Modal/Modal.js
Outdated
if (callback) callback(e, this.props) | ||
this.handleClose() | ||
} | ||
action.onClick = onClick(action.onClick) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move event handler to a class method?
I've made the changes, and I added an example. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is another interim review. We're getting closer here, thanks for continuing on this!
import { Button, Modal } from 'semantic-ui-react' | ||
|
||
const ModalShorthandExample = () => ( | ||
<Modal trigger={<Button>Show Modal</Button>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trigger
on new line please.
src/modules/Modal/ModalActions.js
Outdated
|
||
return ( | ||
<ElementType {...rest} className={classes}> | ||
{actions.map((action) => Button.create(action, true))} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is a new use case. We currently don't have a way to enable keys for a create method during runtime like this. Instead, the create method itself is defined as supporting keys or not. The button currently does not support keys.
The second param here is actually defaultProps
. In order to support keys, we need to pass true
as the 3rd param to createShorthandFactory
for the Button's create
method:
-Button.create = createShorthandFactory(Button, value => ({ content: value }))
+Button.create = createShorthandFactory(Button, value => ({ content: value }), true)
We have a PR up for factory updates. I'll enable keys for all factories in light of this issue. We want users to be able to use the create
method themselves as well, and, they may need keys.
src/modules/Modal/ModalActions.js
Outdated
actions: [], | ||
} | ||
|
||
ModalActions.create = createShorthandFactory(ModalActions, actions => ({ actions }), true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there will only be one instance of Modal.Actions, the Modal.Actions component itself won't need to have keys. We can remove true
from here.
See above comment regarding Button.create
which is what will need the keys, since, there is an array of button elements being created (within Modal.Actions).
Changes are made - I've enjoyed learning whats going on under the hood a bit more. |
update branch to master
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one change on this review. I think we're ready to get some tests in here as well 👍
We have a common test for testing shorthand props. Search for implementsShorthandProp
in other tests to see how it works. You'll have a bit of a tricky case with actions
when using triggerClose
as this is not a Button prop and needs to be removed from the object.
src/modules/Modal/ModalActions.js
Outdated
/** Primary content. */ | ||
children: PropTypes.node, | ||
|
||
/** Additional classes. */ | ||
className: PropTypes.string, | ||
} | ||
|
||
ModalActions.defaultProps = { | ||
actions: [], | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since shorthand is disallowed with children
, we'll want to avoid setting default values for it. Otherwise, when a user uses children
they will also have conflicting actions
array defined unawares.
Instead, in the render method, just use _.map
which will gracefully handle undefined values:
-{actions.map((action) => Button.create(action))}
+{_.map(actions, action => Button.create(action))}
I added some tests to Modal. Should the situation with triggerClose/Button be throwing an error? I could prevent triggerClose from being passed to ModalActions by using _.omit(action, 'triggerClose') and not using _.forEach. I had to add _.isPlanObject(action) to prevent implementsShorthandProp from failing for actions:
|
Is there anything I should change/fix here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@josie11 Thanks for PR, again 👍 I shipped some updates there. I'll finish review tomorrow, need more time on tests
Thanks, folks! As a heads up, I'll be out on travel for a week starting today. Expect silence from me during this time, however, I will try to catch some mobile updates as I am able. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated tests. @levithomason we need your review there 😄
…React into modal # Conflicts: # src/modules/Modal/ModalActions.js
@levithomason I've resolved merge conflicts, will be glad to receive your review there 👍 |
Changes look great, merging! |
Released in |
can pass modal header, content, and actions via shorthand props (#1390)
can pass actions props a triggerClose option that will allow buttons to control open/closing modal