UNPKG

5.06 kBTypeScriptView Raw
1import React, {Component} from 'react';
2import Tooltip from '@beisen-phoenix/tooltip';
3import utils from '@beisen-phoenix/common-utils';
4import './style.scss';
5const classes = utils.BEMClass('radio');
6
7function isPxStyle (value: string){
8 return /^([\d]+)px$/.test(value)
9}
10
11
12export interface RadioData {
13 label?: string | number | React.ReactNode;
14 value: string | number;
15 checked: boolean | undefined;
16}
17
18export type LayoutType = 'vertical' | 'horizontal';
19
20interface styledRadioProps {
21 label?: string | number | React.ReactNode;
22 value: string | number;
23 checked?: boolean;
24 children?: React.ReactText,
25 defaultChecked?: boolean,
26 disabled?: boolean,
27 onChange?: (data: RadioData,event: any) => void,
28 extralCls?: string,
29 minWidth?: string,
30 maxWidth?: string,
31 disableAnimation?: boolean ,
32 extraCls?:string,
33 fontSize?: 'normal' | 'middle'
34 textColor?: 'M1' | 'M2' | 'M3' | 'M4' | 'M5'
35}
36interface radioState {
37 checked?:boolean;
38 radioClicked:boolean
39}
40class Radio extends React.Component<styledRadioProps,radioState>{
41 constructor(props){
42 super(props);
43 this.state={
44 checked:!!this.props.defaultChecked,
45 radioClicked:false,
46 }
47 }
48 private txtRef: React.RefObject<HTMLSpanElement> = React.createRef();
49
50 radioOnclick = (e) => {
51 const isDisabled = this.isDisabled();
52 const isRadioControled = this.isRadioControled();
53 const isChecked = this.isChecked();
54
55 if (isDisabled || isChecked) return;
56
57 this.setState({"radioClicked": true});
58
59 if (!isRadioControled) {
60 // 非受控情况下先更新状态,然后同步syncClick
61 this.setState({checked: true}, () => {
62 this.syncClick(e);
63 })
64 } else {
65 // 受控情况下,直接syncClick,checked状态为true
66 this.syncClick(e)
67 }
68 }
69
70 isRadioControled = () => {
71 return (this.props.checked !== undefined);
72 }
73 getValue = ():RadioData => {
74 return {
75 label: this.props.label || this.props.children,
76 value: this.props.value,
77 checked: this.isChecked()
78 };
79 }
80 syncClick = (e) => {
81 const isRadioControled = this.isRadioControled();
82 const curRadioData = this.getValue();
83
84 if (isRadioControled) {
85 curRadioData.checked = true
86 }
87 this.props.onChange && this.props.onChange(curRadioData,e)
88 }
89
90 isChecked = () => {
91 let checked = this.props.checked;
92 return checked === undefined ? this.state.checked : checked;
93 }
94
95 isDisabled = () => {
96 let disabled = this.props.disabled;
97 return disabled === undefined ? false : disabled;
98 }
99
100 getMinWidth = () => {
101 // 先检查是否是有值
102 // 然后检查是否是以px为单位
103 // 检查值得数值部分是否大于42(设计规定raido文字加图标最小宽度为42px)
104 const {minWidth} = this.props;
105
106 if (minWidth === undefined) return '42px';
107 if (!isPxStyle(minWidth)) return '42px';
108
109 const minWidthInNumber = parseInt(minWidth);
110 return (minWidthInNumber >= 42) ? `${minWidthInNumber}px` : '42px';
111 }
112
113 getMaxWidth = () => {
114 const {maxWidth} = this.props;
115
116 if (maxWidth === undefined) return '';
117 return (isPxStyle(maxWidth)) ? maxWidth : '100%'
118 }
119 render(){
120 const {label=this.props.children,extraCls='',fontSize,textColor} = this.props;
121 const hasLabel = !!(label);
122 const containerCls = classes({element:"",modifier:{
123 disabled:this.isDisabled(),
124 checked :this.isChecked(),
125 withLabel: label
126 },extra:extraCls+' animation'});
127 const flexWrapperCls = classes({element:"wrapper",modifier:{
128 }});
129 const circleWrapperCls = classes({element:"circle-wrapper",modifier:{
130 disabled:this.isDisabled(),
131 checked:this.isChecked(),
132 disabledWithChecked:this.isDisabled() && this.isChecked()}})
133 const circleCls = classes({element:"circle",modifier:{
134 // disabled:this.isDisabled() && !this.isChecked(),
135 disabled:this.isDisabled(),
136 checked:this.isChecked(),
137 disabledWithChecked:this.isDisabled() && this.isChecked()},extral:'center'});
138 const dotCls = classes({element:"dot",modifier:{
139 disabled:this.isDisabled(),
140 checked:this.isChecked(),
141 checkedWithRadioClicked:this.isChecked() && this.state.radioClicked}});
142 const textCls = classes({element:"radio-text",modifier:{
143 disabled:this.isDisabled(),
144 appear:hasLabel,fontMiddle: fontSize === 'middle'},extra: `color-${textColor}`});
145
146 const widthStyle = label ? {maxWidth:this.getMaxWidth(),minWidth:this.getMinWidth()} : {};
147 const tipCls = classes({element:'tooltip',extra:this.props.extraCls});
148
149 return(
150 <label
151 className={containerCls}
152 onClick={this.radioOnclick}
153 style={widthStyle}
154 >
155 <div className={flexWrapperCls}>
156 <div className={circleWrapperCls}>
157 <div className={circleCls}></div>
158 <div className={dotCls}></div>
159 </div>
160 <Tooltip extraCls={tipCls} title={label} showOverflowTooltip={true} >
161 <span className={textCls} ref={this.txtRef}>{label}</span>
162 </Tooltip>
163 </div>
164
165 </label>
166 )
167 }
168}
169
170export default Radio;
171