Skip to content

Commit

Permalink
feat: ✨ implement radio
Browse files Browse the repository at this point in the history
  • Loading branch information
huang-xiao-jian committed Jun 7, 2020
1 parent 7b9e2c7 commit dea0afe
Show file tree
Hide file tree
Showing 9 changed files with 417 additions and 0 deletions.
68 changes: 68 additions & 0 deletions packages/Radio/Radio.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.van-radio {
display: flex;
align-items: center;
overflow: hidden;
user-select: none;
}
.van-radio__icon-wrap {
flex: none;
}
.van-radio__icon {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 1em;
height: 1em;
color: transparent;
text-align: center;
transition-property: color, border-color, background-color;
border: 1px solid #c8c9cc;
border: 1px solid var(--radio-border-color, #c8c9cc);
font-size: 20px;
font-size: var(--radio-size, 20px);
transition-duration: 0.2s;
transition-duration: var(--radio-transition-duration, 0.2s);
}
.van-radio__icon--round {
border-radius: 100%;
}
.van-radio__icon--checked {
color: #fff;
color: var(--white, #fff);
background-color: #1989fa;
background-color: var(--radio-checked-icon-color, #1989fa);
border-color: #1989fa;
border-color: var(--radio-checked-icon-color, #1989fa);
}
.van-radio__icon--disabled {
background-color: #ebedf0;
background-color: var(--radio-disabled-background-color, #ebedf0);
border-color: #c8c9cc;
border-color: var(--radio-disabled-icon-color, #c8c9cc);
}
.van-radio__icon--disabled.van-radio__icon--checked {
color: #c8c9cc;
color: var(--radio-disabled-icon-color, #c8c9cc);
}
.van-radio__label {
word-wrap: break-word;
margin-left: 10px;
margin-left: var(--radio-label-margin, 10px);
color: #323233;
color: var(--radio-label-color, #323233);
line-height: 20px;
line-height: var(--radio-size, 20px);
}
.van-radio__label--left {
float: left;
margin: 0 10px 0 0;
margin: 0 var(--radio-label-margin, 10px) 0 0;
}
.van-radio__label--disabled {
color: #c8c9cc;
color: var(--radio-disabled-label-color, #c8c9cc);
}
.van-radio__label:empty {
margin: 0;
}
144 changes: 144 additions & 0 deletions packages/Radio/Radio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// packages
import React, {
FunctionComponent,
CSSProperties,
ReactNode,
useContext,
} from 'react';
import clsx from 'clsx';
import { View } from 'remax/wechat';
// internal
import Icon from '../Icon';
import RadioGroupContext from '../RadioGroup/RadioGroupContext';
import pickStyle from '../tools/pick-style';
import { Select } from '../tools/Switch';
import withDefaultProps from '../tools/with-default-props-advance';
import './Radio.css';

// 默认值填充属性
interface NeutralRadioProps {
shape: 'square' | 'round';
disabled: boolean;
labelDisabled: boolean;
labelPosition: 'left' | 'right';
iconSize: string;
checkedColor: string;
}

interface ExogenousRadioProps {
// 标识符
name: string;
// icon slot
icon?: ReactNode;
// 容器类名,用以覆盖内部
className?: string;
}

type RadioProps = NeutralRadioProps & ExogenousRadioProps;

const DefaultRadioProps: NeutralRadioProps = {
shape: 'round',
disabled: false,
labelDisabled: false,
labelPosition: 'right',
iconSize: '20px',
checkedColor: '#1989fa',
};

const Radio: FunctionComponent<RadioProps> = (props) => {
const { value, onChange, disabled: _disabled1 } = useContext(
RadioGroupContext
);

const {
labelPosition,
labelDisabled,
shape,
iconSize,
className,
checkedColor,
name,
children,
disabled: _disabled2,
} = props;

// derivation
const disabled = _disabled1 || _disabled2;
const color = !disabled && value === name ? checkedColor : undefined;

// bindings
const classnames = {
container: clsx(className, 'van-radio'),
label: clsx('van-radio__label', `van-radio__label--${labelPosition}`, {
'van-radio__label--disabled': disabled,
}),
iconParent: clsx('van-radio__icon', `van-radio__icon--${shape}`, {
'van-radio__icon--disabled': disabled,
'van-radio__icon--checked': name === value,
}),
};
const stylesheets: Record<
'label' | 'iconWrap' | 'iconParent' | 'icon',
CSSProperties
> = {
label: {
fontSize: iconSize,
},
iconWrap: {
fontSize: iconSize,
},
iconParent: pickStyle({
fontSize: iconSize,
borderColor: color,
backgroundColor: color,
}),
icon: {
display: 'block',
fontSize: '.8em',
lineHeight: iconSize,
},
};

const onChangeWrap = () => {
if (!disabled) {
if (typeof onChange === 'function') {
onChange({ detail: name });
}
}
};
const onClickLabelWrap = () => {
if (!disabled && !labelDisabled) {
if (typeof onChange === 'function') {
onChange({ detail: name });
}
}
};

return (
<View className={classnames.container}>
<Select in={labelPosition === 'left'}>
<View className={classnames.label} onClick={onClickLabelWrap}>
{children}
</View>
</Select>
<View
className="van-radio__icon-wrap"
style={stylesheets.iconWrap}
onClick={onChangeWrap}
>
<View style={stylesheets.iconParent} className={classnames.iconParent}>
<Icon name="success" style={stylesheets.icon} />
</View>
</View>
<Select in={labelPosition === 'right'}>
<View className={classnames.label} onClick={onClickLabelWrap}>
{children}
</View>
</Select>
</View>
);
};

export default withDefaultProps<ExogenousRadioProps, NeutralRadioProps>(
DefaultRadioProps
)(Radio);
4 changes: 4 additions & 0 deletions packages/Radio/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @description - nothing but export component
*/
export { default } from './Radio';
Empty file.
43 changes: 43 additions & 0 deletions packages/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// packages
import React, { FunctionComponent } from 'react';
// internal
import withDefaultProps from '../tools/with-default-props-advance';
import RadioGroupContext from './RadioGroupContext';
import './RadioGroup.css';

// 默认值填充属性
interface NeutralRadioGroupProps {
disabled: boolean;
}

interface ExogenousRadioGroupProps {
name?: string;
value: string;
onChange?: (event: { detail: string }) => void;
}

type RadioGroupProps = NeutralRadioGroupProps & ExogenousRadioGroupProps;

const DefaultRadioGroupProps: NeutralRadioGroupProps = {
disabled: false,
};

const RadioGroup: FunctionComponent<RadioGroupProps> = (props) => {
const { disabled, value, onChange, children } = props;
const payload = {
disabled,
value,
onChange,
};

return (
<RadioGroupContext.Provider value={payload}>
{children}
</RadioGroupContext.Provider>
);
};

export default withDefaultProps<
ExogenousRadioGroupProps,
NeutralRadioGroupProps
>(DefaultRadioGroupProps)(RadioGroup);
14 changes: 14 additions & 0 deletions packages/RadioGroup/RadioGroupContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// packages
import { createContext } from 'react';

// interface
interface RadioGroupContextAbstract {
disabled: boolean;
value?: string;
onChange?: (event: { detail: string }) => void;
}

// 默认值需要保持一致,以防万一
export default createContext<RadioGroupContextAbstract>({
disabled: false,
});
4 changes: 4 additions & 0 deletions packages/RadioGroup/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @description - nothing but export component
*/
export { default } from './RadioGroup';
4 changes: 4 additions & 0 deletions public/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,7 @@ page {
.demo-block__tabbar {
position: static !important;
}

.demo-block__radio {
margin-top: 6px;
}
Loading

0 comments on commit dea0afe

Please sign in to comment.