-
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
perf(shorthand): standardize childKey and shorthand props #452
Conversation
Current coverage is 99.63% (diff: 88.88%)
|
It seems, that we need -children: customPropTypes.every([
- customPropTypes.disallow(['description', 'header', 'image', 'meta']),
- PropTypes.node,
-]),
+children: customPropTypes.children(['description', 'header', 'image', 'meta']) I make some updates, see comments. |
@@ -87,7 +87,7 @@ Card.propTypes = { | |||
/** A Card can center itself inside its container. */ | |||
centered: PropTypes.bool, | |||
|
|||
/** Primary content of the Card. */ | |||
/** Primary content of the Card. Mutually exclusive with all shorthand 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.
Updated all comments on views
to unified format.
Thanks much, I'll pick it up from here. |
dc4c3f3
to
1c6b29d
Compare
I've paused this work. It seems we need to further consider standardization for shorthand props. Thinking out loud... Initially it seems shorthand props are strings only. Then there are the icon/image exceptions, which can also be a props object or an element (factory). Then there are also two types of array shorthand props, either an array of strings (extraImages, etc) or an array of objects (accordion panels, feed events, breadcrumb sections, etc) which are being handled individually in the render method. Ideally, there would be a single shorthand prop type and a single shorthand factory for all components. // Single Usage
<Feed extraText='Hello' /> // string
<Feed extraText={{ content: 'Hello' }} /> // props
<Feed extraText={<p>Hello</p>} /> // dom component
<Feed extraText={<Segment>Hello</Segment>} /> // composite component
<Feed date='1 day ago' /> // string
<Feed date={{ as: 'a', content: '1 day ago' }} /> // props
<Feed date={<img src='1 day ago' />} /> // dom component
<Feed date={<Image src='1 day ago' />} /> // composite component
// Array Usage
<Feed extraImages={['foo.png']} /> // string
<Feed extraImages={[{ src: 'foo.png' }]} /> // props
<Feed extraImages={[<img src='foo.png' />]} /> // dom component
<Feed extraImages={[<Image src='foo.png' />]} /> // composite component Shorthand FactoryCould take a Component (string|function), a function mapping shorthand value to Component props, and finally the shorthand value (string|props object|element|array of any of these). We may also solve #345 reusable component parts by doing this. // Feed Shorthand Props
const { content, extraImages, extraText, date, meta, summary } = props
const contentJSX = shorthand(FeedContent, x => ({ content: x }), content)
const extraImagesJSX = shorthand(FeedExtra, x => ({ content: x, images: true }), extraImages)
const extraTextJSX = shorthand(FeedExtra, x => ({ content: x, text: true }), extraText)
const dateJSX = shorthand(FeedDate, x => ({ content: x }), date)
const metaJSX = shorthand(FeedMeta, x => ({ content: x }), meta)
const summaryJSX = shorthand(FeedSummary, x => ({ content: x }), summary) This is almost identical to the customPropTypes.shorthandSingleString, object, element, disallow children. Intended to be used with simple shorthand props that map directly to sub components (i.e. Feed shorthand). customPropTypes.shorthandMultipleStrictly an array of objects. Intended to be used with the more complicated shorthand arrays (Accordion panels, Breadcrumb sections, Feed events, etc). I'm going to think on all this for a bit before continuing. |
If we allow this: <Feed.Event extraText='Hello' /> // string
<Feed.Event extraText={{ content: 'Hello' }} /> // props
<Feed.Event extraText={<p>Hello</p>} /> // dom component
<Feed.Event extraText={<Segment>Hello</Segment>} /> // composite component We need need allow this: const items = ['Hello', 'World']
const items = [ {content: 'Hello'}, {content: 'World'} ]
const items = [ <p>Hello</p>, <p>World</p> ]
const items = [ <Segment>Hello</Segment>, <Segment>World</Segment> ]
<Feed.Group items={items} /> Looks cool. Then we can standardize - if (children) {
- return <ElementType {...rest} className={classes}>{children}</ElementType>
- }
- const eventsJSX = _.map(events, eventProps => {
- const { childKey, date, meta, summary, ...eventData } = eventProps
- const finalKey = childKey || [date, meta, summary].join('-')
-
- return (
- <FeedEvent
- date={date}
- key={finalKey}
- meta={meta}
- summary={summary}
- {...eventData}
- />
- )
- })
-
- return <ElementType {...rest} className={classes}>{eventsJSX}</ElementType>
+return (
+ <ElementType {...rest} className={classes}>
+ {children || getItemsJSX(Feed, items)}
+ </ElementType>
+) And then add commontest for this: common.implementsItemsProp(Feed) We can write less code and implementation will be clean and uniform. But, there is only one problem - handling |
ItemsAs I said I think that we need standartize class Menu {
static PropTypes: customPropTypes.items,
render() {
renderItems(Menu, MenuItem, this.props, ['content'])
}
} renderItems = (Component, ChildComponent, props, keyProps) => {
const {children, items} = props
if(children) {
return <Component>{children}</Component>
}
const itemsJSX = _map(items, item => {
const {childKey, ...itemProps} = item
// Ugly variant #1
const key = childKey || shortid.generate()
// Ugly variant #2
const key = () => {
if(childKey) return childKey
const keyParts = _map(keyProps, keyProp => {
const propVal = itemProps[keyProp]
if(_.isString(propVal)) return propVal
if(_.isObject(propVal)) return hash(propVal)
})
return keyParts.length > 0 ? keyParts.join('-') : shortid.generate()
}
return <ChildComponent {...itemProps} key={key} />
})
} @levithomason here is some ugly preudocode. As you might understand, I'm not from frontend, so it may be that there is a decision easier and better, but I'm tried to to suggest an idea 😺 |
I'm gonna break this PR up into smaller bite sized PRs. |
1c6b29d
to
acfdd0d
Compare
Just stupid note about future |
I think Another note, in this PR currently <ElementType {...rest} className={classes}>
{createShorthand(ItemHeader, val => ({ content: val }), header)}
{createShorthand(ItemMeta, val => ({ content: val }), meta)}
{createShorthand(ItemDescription, val => ({ content: val }), description)}
{createShorthand(ItemExtra, val => ({ content: val }), extra)}
{children || content}
</ElementType> We're using shorthand for |
We need also check |
👍
There is now a function (#543) that deals with merging the key. It can also deal with creating one. We can use the string/number literal if provided, this was one of the reasons we limited shorthand to strings/numbers. If the user provides a props object or an element, then they can also pass a
There are deep seated reasons why we should not allow children with shorthand. The CONTRIBUTING.md guide for component parts points this out and links this response as the thorough reasoning. Though I want to allow it, I'm still of the mind for v1 that is best not to for the reasons noted. |
0b01f0b
to
27ed48a
Compare
What is mostly remaining here is Feed component prop updates and examples. I'll make a PR pulling those out soon. |
3e92547
to
8dd5a69
Compare
8dd5a69
to
535b279
Compare
With the merge of #618 this work is done. Closing. |
INVALID
This PR is being broken down and merged as smaller PRs
This PR standardizes
childKey
and shorthand props. It also addscommonTests
andcustomPropTypes
for these. In doing so, it also defines a custom prop type for theas
prop.Implementing these also means we need to implement the standardized content prop names and patterns for shorthand props. This will also be done here.
Docs / Components
New
customPropTypes
New
commonTests