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

fix: TileGroup to accept wrappers around RadioTiles. #16001

Merged
merged 7 commits into from Mar 21, 2024
Merged
2 changes: 2 additions & 0 deletions packages/react/src/components/RadioTile/RadioTile.tsx
Expand Up @@ -162,6 +162,8 @@ const RadioTile = React.forwardRef(function RadioTile(
);
});

RadioTile.displayName = 'RadioTile';

RadioTile.propTypes = {
/**
* Specify whether the `RadioTile` should be checked.
Expand Down
62 changes: 32 additions & 30 deletions packages/react/src/components/TileGroup/TileGroup.tsx
Expand Up @@ -5,10 +5,9 @@
* LICENSE file in the root directory of this source tree.
*/

import PropTypes, { ReactElementLike, ReactNodeLike } from 'prop-types';
import PropTypes, { ReactNodeLike } from 'prop-types';
import React, { useState } from 'react';
import RadioTile from '../RadioTile';
import { warning } from '../../internal/warning';
import { usePrefix } from '../../internal/usePrefix';
import { ReactAttr } from '../../types/common';
import { noopFn } from '../../internal/noopFn';
Expand Down Expand Up @@ -83,33 +82,36 @@ const TileGroup = (props) => {
setPrevValueSelected(valueSelected);
}

const getRadioTiles = () => {
const childrenArray = React.Children.toArray(children);
const radioTiles = childrenArray.map((tileRadio) => {
const tileRadioProps = (tileRadio as ReactElementLike).props ?? undefined;
const { value, ...other } = tileRadioProps;
/* istanbul ignore if */
if (typeof tileRadioProps.checked !== 'undefined') {
warning(
false,
`Instead of using the checked property on the RadioTile, set
the defaultSelected property or valueSelected property on the TileGroup.`
);
}

return (
<RadioTile
{...other}
name={name}
key={value}
value={value}
onChange={handleChange}
checked={value === selected}
/>
);
});

return radioTiles;
const getRadioTilesWithWrappers = (children) => {
const traverseAndModifyChildren = (children) => {
return React.Children.map(children, (child) => {
// If RadioTile found, return it with necessary props
if (child.type === RadioTile) {
const { value, ...otherProps } = child.props;
return (
<RadioTile
{...otherProps}
name={name}
key={value}
value={value}
onChange={handleChange}
checked={value === selected}
/>
);
} else if (child.props && child.props.children) {
// If the child is not RadioTile and has children, recheck the children
return React.cloneElement(child, {
...child.props,
children: traverseAndModifyChildren(child.props.children),
});
} else {
// If the child is neither a RadioTile nor has children, return it as is
return child;
}
});
};

return <>{traverseAndModifyChildren(children)}</>;
};

const handleChange = (newSelection, value, evt) => {
Expand All @@ -130,7 +132,7 @@ const TileGroup = (props) => {
className={className ?? `${prefix}--tile-group`}
disabled={disabled}>
{renderLegend(legend)}
<div>{getRadioTiles()}</div>
<div>{getRadioTilesWithWrappers(children)}</div>
</fieldset>
);
};
Expand Down