-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(Switch): complete refactoring (#527)
* chore(Switch): complete refactoring * test: update snapshots * fix: fix cr
- Loading branch information
Showing
21 changed files
with
1,279 additions
and
206 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,84 @@ | ||
import React, { forwardRef, useMemo } from 'react'; | ||
import classNames from 'classnames'; | ||
import { TdSwitchProps } from './type'; | ||
import isArray from 'lodash/isArray'; | ||
import Loading from '../loading'; | ||
import { TdSwitchProps, SwitchValue } from './type'; | ||
import { switchDefaultProps } from './defaultProps'; | ||
import { StyledProps } from '../common'; | ||
import useConfig from '../_util/useConfig'; | ||
import useDefault from '../_util/useDefault'; | ||
import parseTNode from '../_util/parseTNode'; | ||
import { usePrefixClass } from '../hooks/useClass'; | ||
import useDefaultProps from '../hooks/useDefaultProps'; | ||
|
||
export interface SwitchProps extends TdSwitchProps, StyledProps {} | ||
export interface SwitchProps<T extends SwitchValue = SwitchValue> extends TdSwitchProps<T>, StyledProps {} | ||
|
||
const Switch = forwardRef<HTMLButtonElement, SwitchProps>((props, ref) => { | ||
const { customValue, label, disabled, className, colors, style } = props; | ||
const Switch = forwardRef<HTMLDivElement, SwitchProps>((originalProps, ref) => { | ||
const props = useDefaultProps<SwitchProps<SwitchValue>>(originalProps, switchDefaultProps); | ||
const { className, style, value, defaultValue, customValue, disabled, label, loading, size, onChange } = props; | ||
|
||
const { classPrefix } = useConfig(); | ||
const switchClass = usePrefixClass('switch'); | ||
|
||
const switchBaseClassName = `${classPrefix}-switch`; | ||
const [activeValue = true, inactiveValue = false] = customValue || []; | ||
|
||
const [activeValue, inactiveValue] = customValue; | ||
|
||
const [value, onChange] = useDefault(props.value, props.defaultValue, props.onChange); | ||
const [innerValue, setInnerValue] = useDefault(value, defaultValue, onChange); | ||
|
||
const checked = useMemo(() => { | ||
if (typeof value !== 'undefined') { | ||
if (Array.isArray(customValue) && !customValue.includes(value)) { | ||
throw `${value} is not in customValue: ${JSON.stringify(customValue)}`; | ||
if (typeof innerValue !== 'undefined') { | ||
if (Array.isArray(customValue) && !customValue.includes(innerValue)) { | ||
throw `${innerValue} is not in customValue: ${JSON.stringify(customValue)}`; | ||
} | ||
return value === customValue[0]; | ||
return innerValue === activeValue; | ||
} | ||
}, [value, customValue]); | ||
}, [innerValue, customValue, activeValue]); | ||
|
||
const switchClasses = classNames( | ||
`${switchClass}`, | ||
`${switchClass}--${props.size}`, | ||
{ | ||
[`${switchClass}--checked`]: checked, | ||
[`${switchClass}--disabled`]: disabled || loading, | ||
}, | ||
className, | ||
); | ||
|
||
const onInternalClick = () => { | ||
if (disabled) return; | ||
const dotClasses = classNames(`${switchClass}__dot`, `${switchClass}__dot--${props.size}`, { | ||
[`${switchClass}__dot--checked`]: checked, | ||
[`${switchClass}__dot--plain`]: isArray(label) && label.length !== 2 && !loading, | ||
}); | ||
|
||
onChange?.(!checked ? activeValue : inactiveValue); | ||
}; | ||
const labelClasses = classNames(`${switchClass}__label`, `${switchClass}__label--${size}`, { | ||
[`${switchClass}__label--checked`]: checked, | ||
}); | ||
|
||
const renderSwitchText = (checked: boolean, label: SwitchProps['label']) => { | ||
if (typeof label === 'function') { | ||
return label({ value: checked ? activeValue : inactiveValue }); | ||
const handleToggle: React.MouseEventHandler<HTMLDivElement> = (e) => { | ||
if (disabled || loading) { | ||
return; | ||
} | ||
const changedValue = !checked ? activeValue : inactiveValue; | ||
setInnerValue(changedValue, { e }); | ||
}; | ||
|
||
if (typeof label === 'string') return label; | ||
const readerContent = React.useMemo<React.ReactNode>(() => { | ||
if (loading) return <Loading inheritColor size="small" />; | ||
|
||
if (Array.isArray(label)) { | ||
const [activeContent, inactiveContent] = label; | ||
const [activeContent = '', inactiveContent = ''] = label; | ||
const content = checked ? activeContent : inactiveContent; | ||
|
||
if (typeof content === 'function') return content(); | ||
|
||
return content; | ||
return parseTNode(content, { value }); | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
const switchClassName = classNames(switchBaseClassName, className, { | ||
[`${classPrefix}-is-checked`]: checked, | ||
[`${classPrefix}-is-disabled`]: disabled, | ||
}); | ||
return parseTNode(label, { value }); | ||
}, [loading, label, checked, value]); | ||
|
||
return ( | ||
<button ref={ref} className={switchClassName} style={style} onClick={onInternalClick}> | ||
<span className={`${classPrefix}-switch__text`}>{renderSwitchText(checked, label)}</span> | ||
<span | ||
className={`${classPrefix}-switch__node`} | ||
style={{ backgroundColor: checked ? colors?.[0] : colors?.[1] }} | ||
></span> | ||
</button> | ||
<div ref={ref} className={switchClasses} style={style} onClick={handleToggle}> | ||
<div className={dotClasses}> | ||
<div className={labelClasses}>{readerContent}</div> | ||
</div> | ||
</div> | ||
); | ||
}); | ||
|
||
Switch.defaultProps = { | ||
customValue: [true, false], | ||
}; | ||
Switch.displayName = 'Switch'; | ||
|
||
export default Switch; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React, { useState } from 'react'; | ||
import { Switch, Cell } from 'tdesign-mobile-react'; | ||
import type { SwitchValue } from 'tdesign-mobile-react'; | ||
|
||
export default function SwitchBase() { | ||
const [checked, setChecked] = useState<SwitchValue>(1); | ||
|
||
const onChange = (value: SwitchValue) => { | ||
console.log('value', value); | ||
setChecked(value); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Cell title="基础开关" rightIcon={<Switch value={checked} customValue={[1, 0]} onChange={onChange} />}></Cell> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import React from 'react'; | ||
import { Switch, Cell } from 'tdesign-mobile-react'; | ||
|
||
export default function SwitchColor() { | ||
return ( | ||
<> | ||
<Cell title="自定义颜色开关" rightIcon={<Switch defaultValue={true} className="custom-color" />}></Cell> | ||
</> | ||
); | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import React from 'react'; | ||
import TDemoHeader from '../../../site/mobile/components/DemoHeader'; | ||
import TDemoBlock from '../../../site/mobile/components/DemoBlock'; | ||
import Base from './base'; | ||
import Color from './color'; | ||
import Label from './label'; | ||
import Status from './status'; | ||
import Size from './size'; | ||
|
||
import './style/index.less'; | ||
|
||
export default function () { | ||
return ( | ||
<div className="tdesign-mobile-demo"> | ||
<TDemoHeader title="Switch 开关" summary="开关用于切换当个设置项的状态,开启、关闭为两个互斥的操作" /> | ||
<TDemoBlock title="01 组件类型" summary="基础开关"> | ||
<Base /> | ||
</TDemoBlock> | ||
<TDemoBlock summary="带描述开关"> | ||
<Label /> | ||
</TDemoBlock> | ||
<TDemoBlock summary="自定义颜色开关"> | ||
<Color /> | ||
</TDemoBlock> | ||
<TDemoBlock title="02 状态" summary="加载状态"> | ||
<Status /> | ||
</TDemoBlock> | ||
<TDemoBlock title="03 组件样式" summary="开关尺寸"> | ||
<Size /> | ||
</TDemoBlock> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React, { useState } from 'react'; | ||
import { Switch, Cell } from 'tdesign-mobile-react'; | ||
import { Icon } from 'tdesign-icons-react'; | ||
|
||
export default function SwitchLabel() { | ||
const [checked, setChecked] = useState(true); | ||
|
||
const onChange = (value: boolean) => { | ||
console.log('value', value); | ||
setChecked(value); | ||
}; | ||
|
||
const renderActiveContent = () => <Icon name="check" />; | ||
const renderInactiveContent = () => <Icon name="close" />; | ||
|
||
return ( | ||
<> | ||
<Cell | ||
title="带文字开关" | ||
rightIcon={<Switch value={checked} label={({ value }) => (value ? '开' : '关')} onChange={onChange} />} | ||
></Cell> | ||
<Cell | ||
title="带图标开关" | ||
rightIcon={<Switch defaultValue label={[renderActiveContent(), renderInactiveContent()]} />} | ||
></Cell> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react'; | ||
import { Switch, Cell } from 'tdesign-mobile-react'; | ||
|
||
export default function SwitchSize() { | ||
return ( | ||
<> | ||
<Cell title="大尺寸 32" rightIcon={<Switch defaultValue size="large" />}></Cell> | ||
<Cell title="中尺寸 28" rightIcon={<Switch defaultValue />}></Cell> | ||
<Cell title="小尺寸 24" rightIcon={<Switch defaultValue size="small" />}></Cell> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React from 'react'; | ||
import { Switch, Cell } from 'tdesign-mobile-react'; | ||
|
||
export default function SwitchStatus() { | ||
return ( | ||
<> | ||
<Cell title="加载状态" rightIcon={<Switch loading />}></Cell> | ||
<Cell title="开关开启禁用" note={<Switch defaultValue loading />}></Cell> | ||
|
||
<div className="demo__title">禁用状态</div> | ||
|
||
<Cell title="禁用状态" note={<Switch disabled />}></Cell> | ||
<Cell title="禁用状态" note={<Switch disabled value={true} />}></Cell> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
.custom-color { | ||
--td-switch-checked-color: #00a870; | ||
} | ||
|
||
.t-cell + .t-cell { | ||
margin-top: 16px; | ||
} | ||
|
||
.demo__title { | ||
margin: 24px 16px 16px; | ||
color: var(--td-text-color-secondary, rgba(0, 0, 0, 0.6)); | ||
font-size: 14px; | ||
line-height: 22px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC | ||
* */ | ||
|
||
import { TdSwitchProps } from './type'; | ||
|
||
export const switchDefaultProps: TdSwitchProps = { disabled: undefined, label: [], loading: false, size: 'medium' }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
import '../../_common/style/mobile/components/switch/_index.less'; | ||
import '../../_common/style/mobile/components/switch/v2/_index.less'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
:: BASE_DOC :: | ||
|
||
## API | ||
|
||
### Switch Props | ||
|
||
name | type | default | description | required | ||
-- | -- | -- | -- | -- | ||
className | String | - | className of component | N | ||
style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N | ||
colors | Array | - | `deprecated`。Typescript:`string[]` | N | ||
customValue | Array | - | Typescript:`Array<SwitchValue>` | N | ||
disabled | Boolean | undefined | \- | N | ||
label | TNode | [] | Typescript:`Array<string \| TNode> \| TNode<{ value: SwitchValue }>`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N | ||
loading | Boolean | false | \- | N | ||
size | String | medium | options: small/medium/large | N | ||
value | String / Number / Boolean | - | Typescript:`T` `type SwitchValue = string \| number \| boolean`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/switch/type.ts) | N | ||
defaultValue | String / Number / Boolean | - | uncontrolled property。Typescript:`T` `type SwitchValue = string \| number \| boolean`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/switch/type.ts) | N | ||
onChange | Function | | Typescript:`(value: T, context: { e: MouseEvent }) => void`<br/> | N |
Oops, something went wrong.