-
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(shorthand): Custom shorthand proptypes #618
Conversation
Current coverage is 100% (diff: 100%)@@ master #618 diff @@
====================================
Files 119 119
Lines 1881 1887 +6
Methods 0 0
Messages 0 0
Branches 0 0
====================================
+ Hits 1881 1887 +6
Misses 0 0
Partials 0 0
|
c5ec8e3
to
40a40ed
Compare
Ah! So pumped to see this :D I'm in agreement with everything noted in this PR. These exact items were on my bucket list.
Yes please! One way disallow is perfect, children can just be node. Icon/ImageI also had an |
May be some shorter names?
It will look good with
👍 |
@@ -490,7 +490,7 @@ Label.propTypes = { | |||
/** A label can reduce its complexity. */ | |||
basic: PropTypes.bool, | |||
|
|||
/** Primary content of the label, same as text. */ | |||
/** Primary content. */ | |||
children: PropTypes.node, | |||
|
|||
/** Classes to add to the label className. */ |
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.
Any chance we could also grep the className doc block? Just about every one is different as well :/
EDIT I see many others were caught, perhaps just add this one?
@@ -83,7 +83,7 @@ function Table(props) { | |||
return ( | |||
<ElementType {...rest} className={classes}> | |||
{headerRow && <TableHeader>{TableRow.create(headerRow, { cellAs: 'th' })}</TableHeader>} | |||
{<TableBody>{_.map(tableData, (data, index) => TableRow.create(renderBodyRow(data, index)))}</TableBody>} | |||
<TableBody>{_.map(tableData, (data, index) => TableRow.create(renderBodyRow(data, index)))}</TableBody> |
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.
Seems we should be checking for renderBodyRow
before calling it:
{renderBodyRow && <TableBody ...}
Otherwise, it's gonna throw if the user only gives a header/footer config.
*/ | ||
export const children = (Component) => (...args) => { | ||
const disallowedProps = _.flow( | ||
_.pickBy(checker => _.some(shorthandPropTypes, (propType) => propType === checker)), |
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.
Is this working correctly? This file uses lodash/fp
which takes data last, so I'd expect the shorthandPropTypes
(data) to be provided after the some
function.
Also, might be slightly cleaner to use _.includes
:
_.pickBy(checker => _.includes(checker, shorthandPropTypes))
I believe this is correct, data last again. Didn't test it though.
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 per https://github.com/TechnologyAdvice/stardust/pull/618#issuecomment-251318050 I'm just going to scrap this whole custom propType and make all the children propType.node
. The "disallow" will happen on the shorthand side.
Can we also close #452 with this PR? It pretty much covers the rest of that one. The only remaining prop of concern is childKey, and that will get handled when do the collection factory I'm sure. |
40a40ed
to
0ff9c3a
Compare
Apologies for the long PR, but I don't think there's a great way to break it up and most of the changed lines are just comments. FWIW, I ran specs before/after and there were the same number of warnings, so I'm pretty confident this didn't introduce any regressions in prop validations. This is ready for review now, but let's hold off on merging until #619 since there are going to be a ton of merge conflicts. TODO on separate PRs:
|
Bump, this is ready for conflict resolutions. Good luck my friend 🎱 |
0ff9c3a
to
23803e0
Compare
@levithomason - Already rebased and handled the conflicts 😄 This is ready for final review 👍 |
Oh snap! I'm on it, wanna trade me reviews? #552 factory tests :) |
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.
Accepting as I only have 2 suggestions that I'm deferring to you on. Will merge on your word, cheers!
* ArrayOf shorthand ensures a prop is an array of item shorthand | ||
*/ | ||
export const items = (...args) => every([ | ||
disallow(['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.
This is duplicate disallowing since the item disallows. Suggest removing that. I'm also not sure we should have this checker. Seems we could just do PropTypes.arrayOf(item)
in the component and collection
below to simplify. Will let you make the call on that.
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'm trying to unwind this a little bit because it's gets a little complicated with the nested every
calls. Turns out this disallow
is actually necessary, I'll try to explain. Consider the following:
const cells = ['Name', 'Status', 'Notes']
<TableRow cells={cells}>some child</TableRow>
If cells were PropTypes.arrayOf(item)
this doesn't give a warning because arrayOf
will use the given validation (item
in this case) to validate each item in the cells
within the context of cells
, not within the context of TableRow
.
Nested disallow
doesn't actually seem to work as expected since it operates on the parent context of the given prop. So when checking cells
with:
const items = (...args) => every([
disallow(['children']),
PropTypes.arrayOf(item),
])(...args)
It's evaluating cells
within the context of the TableRow props and asking "is cells an array of items AND is the children key undefined in TableRow props". When it's evaluating each item via arrayOf(item)
, it's asking "is this item one of these valid types AND is the children key undefined in this item's array" (i.e. array['children']
) which doesn't throw but doesn't really make sense
I hope that makes sense but it's pretty complicated haha.
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.
Got it, perhaps that is one of the differences with the arrayOf
checker. I know if has a different signature and operates uniquely compared to all other checkers. Either way, it makes sense and I think we leave it as is for now.
@@ -181,6 +181,49 @@ export const demand = (requiredProps) => { | |||
} | |||
|
|||
/** | |||
* Ensure a component can render as a node passed as a prop value in place of children. | |||
*/ | |||
export const content = (...args) => every([ |
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.
Apologies for the lack of response when you asked about this previously, but I really liked having the longer names here. I think it is more clear and more in line with the React community to be explicit. Especially being collection
is a legitimate data type and the collection propType refers to something different, shorthand.
contentShorthand
itemShorthand
collectionShorthand
Given all the back and forth you suffered here, if you wanna push this off to another PR, I get that and am OK doing so. :)
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.
No worries, I don't think there's been much back and forth here.
I'm torn because I like the terseness of the shorter names but I'm also kinda leaning these longer names. Ultimately I think clarity wins out, I'll update the names now.
See that last comment regarding the need for the four types. I'm going to rename the others, but I'm struggling to think of a clear naming distinction between the What are your thoughts on adding It could be up to the the component's This would mean that there'd be the following prop validations:
Hate to throw a curveball like this after a PR has gone through review, but my gut is telling me maybe just those three would be sufficient and we can split out a Thoughts? |
23803e0
to
2290392
Compare
Appended |
This seems correct to me, since it mirrors the I also note that since we've expanded it's ability and definition quite a bit,
Where we're actually just adding |
2290392
to
9928ccc
Compare
👍 just made the updates. Once the specs pass I think we're cool to merge |
Sounds good, will do. |
This adds a few new customPropTypes (took some code and ideas from #452, thanks @levithomason 👍). It's very much WIP but wanted to get it up and get some feedback before I go too crazy here. The new propTypes are:
itemShorthand
arrayOfShorthand
(better name?)collectionShorthand
nodeShorthand
The large majority of our components have a
content
prop that can be rendered in place of the children. This was validated differently in various components as strings/numbers/elements, but really it can be any renderable thing. This is where thenodeShorthand
came from. We could theoretically just usenode
but I wanted to be able to disallow children.I also wound up simplifying/standardizing the doc blocks for common propTypes (there was like 10 ways we described the
className
prop haha). I did it via regex so it's super easy to change so let me know if you think the descriptions could be improved.Open questions:
PropTypes.node
which is definitely simpler. Currently it's a customPropType that disallows any shorthands (inferring which are shorthand props from Component.propTypes)cc @levithomason @layershifter