-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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(common): Improve shorthand array handling #543
Conversation
Could also simplify to: const mergePropsAndClassName = (props, extraProps) => {
const { childKey, ...newProps } = { ...props, ...extraProps }
if (_.has(props, 'className') || _.has(extraProps.className)) {
newProps.className = cx(props.className, extraProps.className) // eslint-disable-line react/prop-types
}
if (!props.key) {
props.key = _.isFunction(childKey) ? childKey(props) : childKey
}
return mergeChildKey(newProps)
} This also makes me wonder, currently anything in |
Love the function idea. Unrelated to this PR, I was thinking the
👍 Regarding comments on
Simply flipping the args in those calls to |
23278c6
to
4301bc3
Compare
This updates the createShorthand factory to handle setting key - If the key is set, leaves it as-is - If the childKey prop is a string/number it uses childKey as the key - If the childKey prop is a function it called childKey with props and uses the return value as the key. This also fixes some issues I noticed using the menu `items` shorthand prop: - Use the createShorthand factory to create a MenuItem for each item. - Do not infer activeIndex from the items array on mount. Regarding the second point, there were a few issues with it: - The array items may not be objects - they could be primitives or elements - You should be able to reliably set the activeIndex or defaultActiveIndex via props, but this would overwrite that.
4301bc3
to
bc5d81f
Compare
Current coverage is 98.86% (diff: 100%)@@ master #543 diff @@
==========================================
Files 108 108
Lines 1764 1762 -2
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
- Hits 1744 1742 -2
Misses 20 20
Partials 0 0
|
@levithomason - Updated based on the comments here.
I think should be g2g 👍 |
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 comment regarding defaultProps ordering
} | ||
|
||
// Map values to props and create a ReactElement | ||
if (_.isString(val) || _.isNumber(val)) { | ||
return <Component {...mergePropsAndClassName(mapValueToProps(val), extraProps)} /> | ||
return <Component {...mergePropsAndClassName(defaultProps, mapValueToProps(val))} /> |
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.
In this case, I believe the factory's mapValueToProps is the default. The other props here are what ever the developer passed when calling createFoo
. Otherwise, you wouldn't be able to override the default mapping when using the component.
Feedback?
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.
The defaultProps
will always be what we (the stardust authors) set as the default. The props, whether passed directly or derived from mapValueToProps
, will be what the end-user wants. So those should always win.
Take this example component that has an image with a default src:
// Example:
const Foo = (props) => (
<div>
createShorthand(Image, val => ({ src: val }), props.image, { src: 'foo.png' })
</div>
)
The different usages are:
React Element:
<Foo image={<MyImage src='bar.png'> />
// Within createShorthand:
// Clone ReactElements
if (isValidElement(val)) {
return React.cloneElement(val, mergePropsAndClassName(defaultProps, val.props))
}
Props object
<Foo image={{ src: 'bar.png' }} />
// Within createShorthand:
// Create ReactElements from props objects
if (_.isPlainObject(val)) {
return <Component {...mergePropsAndClassName(defaultProps, val)} />
}
Primitive:
<Foo image='bar.png' />
// Within createShorthand:
// Map values to props and create a ReactElement
if (_.isString(val) || _.isNumber(val)) {
return <Component {...mergePropsAndClassName(defaultProps, mapValueToProps(val))} />
}
In all of these cases, if we swapped the argument order of defaultProps
the src would not be what the user passed.
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.
Wrote out a detailed explanation of how I didn't actually think this would work for the string/number literal case only to come to see it correctly. Thanks for the clarifications!
Released in |
Note: Abstracted from #430
This updates the createShorthand factory to take two special props as extraProps to generate a key if missing. This is necessary for shorthand props that are arrays. The props are:
This PR also fixes some issues I noticed using the menu
items
shorthand prop:Regarding the second point, there were a few issues with it:
I was also thinking about just using
childKey
that could either be a function or a string, so:But then we'd have to make sure that if the
childKey
were passed in props, it's not overwritten byextraProps
. Might be worth it to remove the need for that additional key.