Skip to content
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

[WIP] feat(radio-input): add components prop to radio input option #1139

Merged
merged 4 commits into from
Oct 30, 2019

Conversation

dogayuksel
Copy link
Contributor

Summary

Allows passing in a react element to wrap RadioInput.Option with.

@dogayuksel dogayuksel added the 🚧 Status: WIP Work in progress label Oct 25, 2019
@dogayuksel dogayuksel self-assigned this Oct 25, 2019
@dogayuksel
Copy link
Contributor Author

#1136

Copy link
Contributor

@tdeekens tdeekens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool you picked this up so quickly!

@@ -29,7 +29,7 @@ const Group = props => {
const optionElements = React.Children.map(props.children, (child, index) => {
// NOTE: Allowing to intersperse other elements than `Option`.
if (child && child.type.displayName === Option.displayName) {
return React.cloneElement(child, {
const option = React.cloneElement(child, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: maybe children as a name would be apt here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const clonedChild?

@@ -41,6 +41,13 @@ const Group = props => {
onFocus: props.onFocus,
onBlur: props.onBlur,
});
return child.props.components.WrapperComponent ? (
Copy link
Contributor

@tdeekens tdeekens Oct 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Wondering, as I always struggle to read <a with a lowercase character if it is actually a React component. Would

const Wrapper = child.props.components.WrapperComponent || React.Fragment;

work to then just do:

<Wrapper>{children}</Wrapper>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, another approach we could go for just allows any child but leave it up to the consumer to not allow prop spreading. That way we don't need a new components prop.

So for your case, you would do something like this. Basically capture the props in your wrapper then pass them to the component that should receive them (RadioOption).

const Wrapper = props => {
 <ToolTip off={isTooltipOff}>
    <RadioInput.Option {...props} />
  <ToolTip>
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this self-service approach. Would we be recursively searching for an RadioInput.Option as a child for the invariant, or removing the check all together, what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be fine with removing it. A recursive search could also be misleading. As in: somewhere in the component tree there is a Radio.Option but it wasn't the one the developer but "nearby" his concern. So the invariant will maybe rarely give an appropriate hint.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I'm not sure how we could do this though without making it a breaking change.

@@ -66,6 +67,16 @@ Option.propTypes = {
PropTypes.element,
PropTypes.func,
]).isRequired,
components: PropTypes.shape({
WrapperComponent: (props, propName) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really necessary? Can't we just make it optional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the children prop right?

@dogayuksel
Copy link
Contributor Author

@montezume @tdeekens
Any ideas how to pass in props to WrapperComponent in this setup? For example, wrapper being a Tooltip and user wanting to control the off prop.

  • Add an other prop to RadioInput.Option, like WrapperComponentProps and spread them on to WrapperComponent?
  • Otherwise, WrapperComponent can be a JSX.Element but I don't know, if it is possible to append children to that.

@tdeekens
Copy link
Contributor

Hm, good question. So far we only swaped out default components while applying "internal" props to them. Correct me if that's wrong @montezume.

  1. A prop-getter like getWrapperComponentProps feels sort of backwards
  2. A props.props.WrapperComponent feels also a bit odd
  3. A props.components.WrapperComponent.props and props.components.WrapperComponent.component also looks like an odd API

Sorry I am just thinking out loud. 🤔 would it make sense just not to render the wrapper component in the parent? It doesn't really solve the "issue" though.

return new Error(
`Invalid prop 'components.WrapperComponent' supplied to 'RadioInput.Option': the prop is not a valid React component`
);
wrapper: (props, propName) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering. Is this almost the same as PropTypes.oneOf([PropTypes.func, PropTypes.array, PropTypes.elementType])?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to restrict it to a function (1st if) that receives one argument (2nd if) and returns a valid react.element (3rd if)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a bit over engineered and fails stupidly, thought it could help/guide the user maybe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. It's a nice idea! Maybe it's also something UIKit could share and reuse internally.

Copy link
Contributor

@montezume montezume left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I played around with it locally. Really nice approach. 🎉

Thanks @dogayuksel

@montezume
Copy link
Contributor

@tdeekens do you want to review?

@montezume
Copy link
Contributor

Not sure why Percy didn't report ... it passed https://percy.io/commercetools-GmbH/ui-kit/builds/2967506

@@ -41,6 +41,8 @@ const Group = props => {
onFocus: props.onFocus,
onBlur: props.onBlur,
});
const { wrapper } = child.props.components;
return wrapper ? wrapper(clonedChild) : clonedChild;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool.

@montezume montezume merged commit a939a97 into master Oct 30, 2019
@montezume montezume deleted the dy-components-prop-for-radio-input-option branch October 30, 2019 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants