UNPKG

4.39 kBTypeScriptView Raw
1/*
2 * Copyright 2016 Palantir Technologies, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import * as React from "react";
18import { polyfill } from "react-lifecycles-compat";
19
20import { AbstractPureComponent2, Classes } from "../../common";
21import * as Errors from "../../common/errors";
22import { DISPLAYNAME_PREFIX, OptionProps, Props } from "../../common/props";
23import { isElementOfType } from "../../common/utils";
24import { RadioProps, Radio } from "./controls";
25
26// eslint-disable-next-line deprecation/deprecation
27export type RadioGroupProps = IRadioGroupProps;
28/** @deprecated use RadioGroupProps */
29export interface IRadioGroupProps extends Props {
30 /**
31 * Whether the group and _all_ its radios are disabled.
32 * Individual radios can be disabled using their `disabled` prop.
33 */
34 disabled?: boolean;
35
36 /**
37 * Whether the radio buttons are to be displayed inline horizontally.
38 */
39 inline?: boolean;
40
41 /** Optional label text to display above the radio buttons. */
42 label?: React.ReactNode;
43
44 /**
45 * Name of the group, used to link radio buttons together in HTML.
46 * If omitted, a unique name will be generated internally.
47 */
48 name?: string;
49
50 /**
51 * Callback invoked when the currently selected radio changes.
52 * Use `event.currentTarget.value` to read the currently selected value.
53 * This prop is required because this component only supports controlled usage.
54 */
55 onChange: (event: React.FormEvent<HTMLInputElement>) => void;
56
57 /**
58 * Array of options to render in the group. This prop is mutually exclusive
59 * with `children`: either provide an array of `OptionProps` objects or
60 * provide `<Radio>` children elements.
61 */
62 options?: OptionProps[];
63
64 /** Value of the selected radio. The child with this value will be `:checked`. */
65 selectedValue?: string | number;
66}
67
68let counter = 0;
69function nextName() {
70 return `${RadioGroup.displayName}-${counter++}`;
71}
72
73@polyfill
74export class RadioGroup extends AbstractPureComponent2<RadioGroupProps> {
75 public static displayName = `${DISPLAYNAME_PREFIX}.RadioGroup`;
76
77 // a unique name for this group, which can be overridden by `name` prop.
78 private autoGroupName = nextName();
79
80 public render() {
81 const { label } = this.props;
82 return (
83 <div className={this.props.className}>
84 {label == null ? null : <label className={Classes.LABEL}>{label}</label>}
85 {Array.isArray(this.props.options) ? this.renderOptions() : this.renderChildren()}
86 </div>
87 );
88 }
89
90 protected validateProps() {
91 if (this.props.children != null && this.props.options != null) {
92 console.warn(Errors.RADIOGROUP_WARN_CHILDREN_OPTIONS_MUTEX);
93 }
94 }
95
96 private renderChildren() {
97 return React.Children.map(this.props.children, child => {
98 if (isElementOfType(child, Radio)) {
99 return React.cloneElement(child, this.getRadioProps(child.props as OptionProps));
100 } else {
101 return child;
102 }
103 });
104 }
105
106 private renderOptions() {
107 return this.props.options?.map(option => (
108 <Radio {...this.getRadioProps(option)} key={option.value} labelElement={option.label || option.value} />
109 ));
110 }
111
112 private getRadioProps(optionProps: OptionProps): RadioProps {
113 const { name } = this.props;
114 const { className, disabled, value } = optionProps;
115 return {
116 checked: value === this.props.selectedValue,
117 className,
118 disabled: disabled || this.props.disabled,
119 inline: this.props.inline,
120 name: name == null ? this.autoGroupName : name,
121 onChange: this.props.onChange,
122 value,
123 };
124 }
125}