-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
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
Is there a better alternative to cloneElement? #12921
Comments
@casank25 Either you need to reverse the order: <ToggleButton value="left">
<Tooltip title="left" placement="top">
<FormatAlignLeftIcon />
</Tooltip>
</ToggleButton> or to write a wrapping component to forward the properties where it's needed (jumping the tooltip). |
Actually, we could forward the unused properties to the children to make it work out of the box. Do you want to work on that? |
Working on it, I'll submit a PR today |
Ha, I guess I came too late to check back on this issue :) |
Actually, this might need a little more consideration. The problem stated by the OP is caused by ToggleButtonGroup. ToggleButtonGroup uses the 'value' prop of it's children to make toggle functionality work. const children = React.Children.map(childrenProp, child => {
if (!React.isValidElement(child)) {
return null;
}
// value comes from children. Having an empty tooltip is breaking this
const { selected: buttonSelected, value: buttonValue } = child.props;
const selected =
buttonSelected === undefined ? isValueSelected(buttonValue, value) : buttonSelected;
return React.cloneElement(child, {
selected,
onChange: exclusive ? this.handleExclusiveChange : this.handleChange,
});
}); @oliviertassinari let me know if you still want to progress with this, I am not sure there's a good way to support what OP is asking and whether or not it's worth it |
Just a random thought but wouldn't it be better to create a context in ToggleButtonGroup that the ToggleButtons can listen to? That way we could get away from the cloneElement pattern. |
This issue is really interesting it's at the reunion of many pain points:
|
Regarding the
<ToggleButtonGroup
value={alignment}
exclusive
onChange={this.handleAlignment}
>
{childProps => (
<Tooltip value="left" title="left" placement="top">
<ToggleButton {...childProps}>
<FormatAlignLeftIcon />
</ToggleButton>
</Tooltip>
)}
<ToggleButton value="left">
<FormatAlignLeftIcon />
</ToggleButton>
</ToggleButtonGroup> It's solving the wrapping issue quite elegantly. However, it doesn't solve the virtualization problem. Notice that I had to move the What do you think? I like option 3. I have been benchmark a large number of competitive tooltip implementations. Most of them don't forward the properties. For consistency with all our components, I think that it's best that we forward the properties to the children, it's what will be the first node the DOM structure. This way, our component is more flexible. I'm gonna work on it. |
I'm not a big fan of the context API either since it's so verbose. But it makes composing the controlled children with other components much easier. Moving the value property up looks really bad. It would be really nice if people could just wrap whatever they want around the controlled child without worrying that they overwrite something important by accident. It's really tempting to "just do it"™, see what problems we encounter and then benchmark against master. react-bootstrap is also using |
@eps1lon How do you think we should solve the problem? |
Maybe there isn't even a problem. Concerning this issue it might be sufficient to wrap the icon inside the ToggleButton in the Tooltip. Maybe it's only a perf issue. But this would require a benchmark against another implementation. The easiest thing is probably to look into other libraries and check out how they solved the problem and why. When I watched https://www.youtube.com/watch?v=AiJ8tRRH0f8 I immediately thought about mui and I think there is a great solution in there. It's just not an immediate problem in my opinion and I'm really unsure which way to go first. |
@eps1lon By wrapping icon inside ToggleButton instead of wrapping ToggleButton itself, wouldn't that present an inconsistency? Based on docs, we wrap Button in Tooltip and we wrap IconButton in Tooltip. Also, what if ToggleButton needs bigger padding? The user would have to hover over icon in order to see the tooltip. |
@casank25 Oh I completely agree. This was just a meant as a temporary workaround. |
Actually, if I put title directly on ToggleButton, things work. No Tooltip needed. I updated https://codesandbox.io/s/38w8xry8rq |
Couldn't we solve this with hooks now? |
Hooks would just improve DX ergonomics. What actually solves this is the context API. |
Sorry, I meant to answer this the problem bellow. I should have been more clear.
The hook API has an |
Just FYI. As per closed issue #17079, I am unable to wrap my toggle buttons and get full functionality. Clicking the button does fire the event, but the background does not latch to the new toggle state. See https://codesandbox.io/s/create-react-app-jf5qe I see that it is the same root design issue as described here, in that ToggleButtonGroup requires its buttons to be immediate children. Thanks. |
@leantide you'd just have to set value on your wrapping component and not in your wrapped component, i.e.
https://codesandbox.io/s/create-react-app-kuhkl |
Simplest answer to me was to add the propery "value" to Tooltip: function generateToggleButton(filter, brand, tooltip) {
return (
<Tooltip
arrow
key={filter}
title={tooltip}
value={filter}
disableHoverListener={tooltip === `brands.${filter}.tooltip`}
disableTouchListener={tooltip === `brands.${filter}.tooltip`}
>
<ToggleButton color="primary" value={filter}>
{brand}
</ToggleButton>
</Tooltip>
);
}
<ToggleButtonGroup
size="small"
value={brands}
onClick={e => setBrandsInQuery(e.target?.value)}
color="primary"
>
{Object.values(ProductBrands).map(
brand => generateToggleButton(brand, t(`brands.${brand}.label`), t(`brands.${brand}.tooltip`)),
)}
</ToggleButtonGroup> |
Passing
I still need to test out the solution at #21026 (comment) which is way less code. |
When using ToggleButton from lab package and wrapping it in tooltip it raises a warning:
Warning: Failed prop type: The following properties are not supported: selected, onChange. Please remove them.
Expected Behavior
It should be possible to add a tooltip to ToggleButton
Current Behavior
Steps to Reproduce
Link: https://codesandbox.io/s/q7m82k4024
Context
Since ToggleButtons are IconButton (at least that's how we intend to use it) it would be helpful to a user to see what that button will do and the best way for that is Tooltip
Your Environment
The text was updated successfully, but these errors were encountered: