Skip to content

Commit

Permalink
fix(toggle-button-group): migrate to be ref forwarder
Browse files Browse the repository at this point in the history
Relevant to #4194.
  • Loading branch information
bpas247 committed Oct 5, 2019
1 parent ebdfb9d commit ba45a53
Showing 1 changed file with 47 additions and 52 deletions.
99 changes: 47 additions & 52 deletions src/ToggleButtonGroup.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import invariant from 'invariant';
import { uncontrollable } from 'uncontrollable';
import { useUncontrolled } from 'uncontrollable';

import chainFunction from './utils/createChainedFunction';
import { map } from './utils/ElementChildren';
Expand Down Expand Up @@ -43,68 +43,63 @@ const defaultProps = {
type: 'radio',
};

class ToggleButtonGroup extends React.Component {
getValues() {
const { value } = this.props;
return value == null ? [] : [].concat(value);
}
const ToggleButtonGroup = React.forwardRef((props, ref) => {
let {
children,
type,
name,
value,
onChange,
...controlledProps
} = useUncontrolled(props, {
value: 'onChange',
});

handleToggle(value, event) {
const { type, onChange } = this.props;
const values = this.getValues();
const isActive = values.indexOf(value) !== -1;
const getValues = () => (value == null ? [] : [].concat(value));

const handleToggle = (inputVal, event) => {
const values = getValues();
const isActive = values.indexOf(inputVal) !== -1;

if (type === 'radio') {
if (!isActive) onChange(value, event);
if (!isActive) onChange(inputVal, event);
return;
}

if (isActive) {
onChange(values.filter(n => n !== value), event);
onChange(values.filter(n => n !== inputVal), event);
} else {
onChange([...values, value], event);
onChange([...values, inputVal], event);
}
}

render() {
const { children, type, name, ...props } = this.props;

delete props.onChange;
delete props.value;

const values = this.getValues();

invariant(
type !== 'radio' || !!name,
'A `name` is required to group the toggle buttons when the `type` ' +
'is set to "radio"',
);

return (
<ButtonGroup {...props} toggle>
{map(children, child => {
const { value, onChange } = child.props;
const handler = e => this.handleToggle(value, e);

return React.cloneElement(child, {
type,
name: child.name || name,
checked: values.indexOf(value) !== -1,
onChange: chainFunction(onChange, handler),
});
})}
</ButtonGroup>
);
}
}
};

invariant(
type !== 'radio' || !!name,
'A `name` is required to group the toggle buttons when the `type` ' +
'is set to "radio"',
);

return (
<ButtonGroup {...controlledProps} ref={ref} toggle>
{map(children, child => {
const values = getValues();
const { value: childVal, onChange: childOnChange } = child.props;
const handler = e => handleToggle(childVal, e);

return React.cloneElement(child, {
type,
name: child.name || name,
checked: values.indexOf(childVal) !== -1,
onChange: chainFunction(childOnChange, handler),
});
})}
</ButtonGroup>
);
});

ToggleButtonGroup.propTypes = propTypes;
ToggleButtonGroup.defaultProps = defaultProps;

const UncontrolledToggleButtonGroup = uncontrollable(ToggleButtonGroup, {
value: 'onChange',
});

UncontrolledToggleButtonGroup.Button = ToggleButton;
ToggleButtonGroup.Button = ToggleButton;

export default UncontrolledToggleButtonGroup;
export default ToggleButtonGroup;

0 comments on commit ba45a53

Please sign in to comment.