@carbon/react
Version:
React components for the Carbon Design System
122 lines (115 loc) • 3.91 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
import PropTypes from 'prop-types';
import React, { useState, useEffect, Children, isValidElement, cloneElement } from 'react';
import RadioTile from '../RadioTile/RadioTile.js';
import { usePrefix } from '../../internal/usePrefix.js';
import { noopFn } from '../../internal/noopFn.js';
const TileGroup = ({
children,
className,
defaultSelected,
disabled,
legend,
name,
onChange = noopFn,
valueSelected,
required
}) => {
const prefix = usePrefix();
const [selected, setSelected] = useState(valueSelected ?? defaultSelected);
useEffect(() => {
if (typeof valueSelected !== 'undefined' && valueSelected !== selected) {
setSelected(valueSelected);
}
}, [valueSelected, selected]);
const handleChange = (value, name, evt) => {
if (value !== selected) {
setSelected(value);
onChange(value, name ?? '', evt);
}
};
const getRadioTilesWithWrappers = elements => {
const traverseAndModifyChildren = elements => {
return Children.map(elements, child => {
if (! /*#__PURE__*/isValidElement(child)) return child;
// If a `RadioTile` is found, return it with necessary props,
if (/*#__PURE__*/isValidElement(child) && child.type === RadioTile) {
const {
value,
...otherProps
} = child.props;
return /*#__PURE__*/React.createElement(RadioTile, _extends({}, otherProps, {
required: required,
name: name,
key: value,
value: value,
onChange: handleChange,
checked: value === selected
}));
}
// If the child is not RadioTile and has children, recheck the children
const children = child.props.children;
const hasChildren = Children.count(children) > 0;
if (hasChildren) {
return /*#__PURE__*/cloneElement(child, undefined, traverseAndModifyChildren(children));
}
// If the child is neither a RadioTile nor has children, return it as is
return child;
});
};
return /*#__PURE__*/React.createElement(React.Fragment, null, traverseAndModifyChildren(elements));
};
return /*#__PURE__*/React.createElement("fieldset", {
className: className ?? `${prefix}--tile-group`,
disabled: disabled
}, legend && /*#__PURE__*/React.createElement("legend", {
className: `${prefix}--label`
}, legend), /*#__PURE__*/React.createElement("div", null, getRadioTilesWithWrappers(children)));
};
TileGroup.displayName = 'TileGroup';
TileGroup.propTypes = {
/**
* Provide a collection of <RadioTile> components to render in the group
*/
children: PropTypes.node,
/**
* Provide an optional className to be applied to the container node
*/
className: PropTypes.string,
/**
* Specify the the value of <RadioTile> to be selected by default
*/
defaultSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/**
* Specify whether the group is disabled
*/
disabled: PropTypes.bool,
/**
* Provide an optional legend for this group
*/
legend: PropTypes.string,
/**
* Specify the name of the underlying `<input>` nodes
*/
name: PropTypes.string.isRequired,
/**
* Provide an optional `onChange` hook that is called whenever the value of
* the group changes
*/
onChange: PropTypes.func,
/**
* `true` to specify if input selection in group is required.
*/
required: PropTypes.bool,
/**
* Specify the value that is currently selected in the group
*/
valueSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
};
export { TileGroup };