site: cc => fc (#39635)

This commit is contained in:
lijianan 2022-12-19 11:25:21 +08:00 committed by GitHub
parent d675c09bd0
commit a0b713c98b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 209 additions and 266 deletions

View File

@ -1,4 +1,4 @@
import React, { Component } from 'react'; import React, { useMemo } from 'react';
import CopyToClipboard from 'react-copy-to-clipboard'; import CopyToClipboard from 'react-copy-to-clipboard';
import { message } from 'antd'; import { message } from 'antd';
@ -8,37 +8,25 @@ interface ColorBlockProps {
dark?: boolean; dark?: boolean;
} }
class ColorBlock extends Component<ColorBlockProps> { const ColorBlock: React.FC<ColorBlockProps> = (props) => {
getTextStyle() { const { color, index, dark } = props;
const { color, index, dark } = this.props; const textStyle = useMemo<React.CSSProperties>(() => {
const colorMap = { const colorMap = { default: ['#fff', 'unset'], dark: ['#314659', '#fff'] };
default: ['#fff', 'unset'],
dark: ['#314659', '#fff'],
};
const [lastColor, firstColor] = dark ? colorMap.dark : colorMap.default; const [lastColor, firstColor] = dark ? colorMap.dark : colorMap.default;
return { return {
background: color, background: color,
color: index > 5 ? lastColor : firstColor, color: index > 5 ? lastColor : firstColor,
fontWeight: index === 6 ? 'bold' : 'normal', fontWeight: index === 6 ? 'bold' : 'normal',
}; };
} }, [color, dark, index]);
return (
onCopied = () => { <CopyToClipboard text={color} onCopy={() => message.success(`Copied: ${color}`)}>
const { color } = this.props; <div className="main-color-item" style={textStyle}>
message.success(`Copied: ${color}`); color-{index}
}; <span className="main-color-value">{color.toLowerCase()}</span>
</div>
render() { </CopyToClipboard>
const { color, index } = this.props; );
return ( };
<CopyToClipboard text={color} onCopy={this.onCopied}>
<div className="main-color-item" style={this.getTextStyle()}>
color-{index}
<span className="main-color-value">{color.toLowerCase()}</span>
</div>
</CopyToClipboard>
);
}
}
export default ColorBlock; export default ColorBlock;

View File

@ -1,5 +1,5 @@
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import React, { Component } from 'react'; import React, { useMemo, useState } from 'react';
import { FormattedMessage } from 'dumi'; import { FormattedMessage } from 'dumi';
import ColorPicker from './ColorPicker'; import ColorPicker from './ColorPicker';
import ColorPatterns from './ColorPatterns'; import ColorPatterns from './ColorPatterns';
@ -7,21 +7,17 @@ import ColorPatterns from './ColorPatterns';
const primaryMinSaturation = 70; // 主色推荐最小饱和度 const primaryMinSaturation = 70; // 主色推荐最小饱和度
const primaryMinBrightness = 70; // 主色推荐最小亮度 const primaryMinBrightness = 70; // 主色推荐最小亮度
class ColorPaletteTool extends Component { const ColorPaletteTool: React.FC = () => {
state = { const [primaryColor, setPrimaryColor] = useState<string>('#1890ff');
primaryColor: '#1890ff', const [primaryColorInstance, setPrimaryColorInstance] = useState(null);
primaryColorInstance: null, const handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => {
};
handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => {
const value = (e as ChangeEvent<HTMLInputElement>).target const value = (e as ChangeEvent<HTMLInputElement>).target
? (e as ChangeEvent<HTMLInputElement>).target.value ? (e as ChangeEvent<HTMLInputElement>).target.value
: e; : e;
this.setState({ primaryColor: value, primaryColorInstance: color }); setPrimaryColor(value as string);
setPrimaryColorInstance(color);
}; };
const colorValidation = useMemo<React.ReactNode>(() => {
renderColorValidation() {
const { primaryColorInstance } = this.state;
let text = ''; let text = '';
if (primaryColorInstance) { if (primaryColorInstance) {
if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) { if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) {
@ -36,26 +32,22 @@ class ColorPaletteTool extends Component {
} }
} }
return <span className="color-palette-picker-validation">{text.trim()}</span>; return <span className="color-palette-picker-validation">{text.trim()}</span>;
} }, [primaryColorInstance, primaryMinSaturation, primaryMinBrightness]);
return (
render() { <div className="color-palette-horizontal">
const { primaryColor } = this.state; <div className="color-palette-pick">
return ( <FormattedMessage id="app.docs.color.pick-primary" />
<div className="color-palette-horizontal">
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-primary" />
</div>
<div className="main-color">{ColorPatterns({ color: primaryColor })}</div>
<div className="color-palette-picker">
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<ColorPicker color={primaryColor} onChange={this.handleChangeColor} />
</span>
<span className="color-palette-picker-value">{primaryColor}</span>
{this.renderColorValidation()}
</div>
</div> </div>
); <div className="main-color">{ColorPatterns({ color: primaryColor })}</div>
} <div className="color-palette-picker">
} <span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<ColorPicker color={primaryColor} onChange={handleChangeColor} />
</span>
<span className="color-palette-picker-value">{primaryColor}</span>
{colorValidation}
</div>
</div>
);
};
export default ColorPaletteTool; export default ColorPaletteTool;

View File

@ -1,5 +1,5 @@
import React, { useMemo, useState } from 'react';
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import React, { Component } from 'react';
import { FormattedMessage } from 'dumi'; import { FormattedMessage } from 'dumi';
import { Row, Col } from 'antd'; import { Row, Col } from 'antd';
import ColorPicker from './ColorPicker'; import ColorPicker from './ColorPicker';
@ -8,29 +8,27 @@ import ColorPatterns from './ColorPatterns';
const primaryMinSaturation = 70; // 主色推荐最小饱和度 const primaryMinSaturation = 70; // 主色推荐最小饱和度
const primaryMinBrightness = 70; // 主色推荐最小亮度 const primaryMinBrightness = 70; // 主色推荐最小亮度
class ColorPaletteTool extends Component { const ColorPaletteTool: React.FC = () => {
state = { const [primaryColor, setPrimaryColor] = useState<string>('#1890ff');
primaryColor: '#1890ff', const [backgroundColor, setBackgroundColor] = useState<string>('#141414');
backgroundColor: '#141414', const [primaryColorInstance, setPrimaryColorInstance] = useState(null);
primaryColorInstance: null,
};
handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => { const handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => {
const value = (e as ChangeEvent<HTMLInputElement>).target const value = (e as ChangeEvent<HTMLInputElement>).target
? (e as ChangeEvent<HTMLInputElement>).target.value ? (e as ChangeEvent<HTMLInputElement>).target.value
: e; : e;
this.setState({ primaryColor: value, primaryColorInstance: color }); setPrimaryColor(value as string);
setPrimaryColorInstance(color);
}; };
handleChangeBackgroundColor = (e: string | ChangeEvent) => { const handleChangeBackgroundColor = (e: string | ChangeEvent) => {
const value = (e as ChangeEvent<HTMLInputElement>).target const value = (e as ChangeEvent<HTMLInputElement>).target
? (e as ChangeEvent<HTMLInputElement>).target.value ? (e as ChangeEvent<HTMLInputElement>).target.value
: e; : e;
this.setState({ backgroundColor: value }); setBackgroundColor(value as string);
}; };
renderColorValidation() { const colorValidation = useMemo<React.ReactNode>(() => {
const { primaryColorInstance } = this.state;
let text = ''; let text = '';
if (primaryColorInstance) { if (primaryColorInstance) {
if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) { if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) {
@ -49,56 +47,50 @@ class ColorPaletteTool extends Component {
{text.trim()} {text.trim()}
</span> </span>
); );
} }, [primaryColorInstance]);
render() { return (
const { primaryColor, backgroundColor } = this.state; <div className="color-palette-horizontal color-palette-horizontal-dark">
return ( <div className="main-color">
<div className="color-palette-horizontal color-palette-horizontal-dark"> {ColorPatterns({ color: primaryColor, dark: true, backgroundColor })}
<div className="main-color">
{ColorPatterns({ color: primaryColor, dark: true, backgroundColor })}
</div>
<div className="color-palette-picker">
<Row>
<Col span={12}>
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-primary" />
</div>
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker color={primaryColor} onChange={this.handleChangeColor} />
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{primaryColor}</span>
</Col>
</Row>
</span>
</Col>
<Col span={12}>
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-background" />
</div>
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker
color={backgroundColor}
onChange={this.handleChangeBackgroundColor}
/>
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{backgroundColor}</span>
</Col>
</Row>
</span>
</Col>
</Row>
{this.renderColorValidation()}
</div>
</div> </div>
); <div className="color-palette-picker">
} <Row>
} <Col span={12}>
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-primary" />
</div>
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker color={primaryColor} onChange={handleChangeColor} />
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{primaryColor}</span>
</Col>
</Row>
</span>
</Col>
<Col span={12}>
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-background" />
</div>
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker color={backgroundColor} onChange={handleChangeBackgroundColor} />
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{backgroundColor}</span>
</Col>
</Row>
</span>
</Col>
</Row>
{colorValidation}
</div>
</div>
);
};
export default ColorPaletteTool; export default ColorPaletteTool;

View File

@ -1,4 +1,4 @@
import React, { Component } from 'react'; import React, { useState } from 'react';
import { SketchPicker } from 'react-color'; import { SketchPicker } from 'react-color';
const noop = () => {}; const noop = () => {};
@ -12,115 +12,105 @@ interface ColorPickerProps {
onChangeComplete?: (hex: string) => void; onChangeComplete?: (hex: string) => void;
} }
export default class ColorPicker extends Component<ColorPickerProps> { const ColorPicker: React.FC<ColorPickerProps> = (props) => {
static getDerivedStateFromProps(props: ColorPickerProps) { const {
if ('color' in props) { small,
return { position = 'bottom',
color: props.color, presetColors,
}; onChange = noop,
} onChangeComplete = noop,
return null; } = props;
const [color, setColor] = useState<string>(props.color);
const [displayColorPicker, setDisplayColorPicker] = useState<boolean>(false);
const handleClick = () => {
setDisplayColorPicker(displayColorPicker);
};
const handleClose = () => {
setDisplayColorPicker(false);
};
const handleChange = (changeColor: { hex: string }) => {
setColor(changeColor.hex);
onChange(changeColor.hex, changeColor);
};
const handleChangeComplete = (completeColor: { hex: string }) => {
setColor(completeColor.hex);
onChangeComplete(completeColor.hex);
};
const width = small ? 80 : 120;
const styles: Record<PropertyKey, React.CSSProperties> = {
color: {
width: `${width}px`,
height: small ? '16px' : '24px',
borderRadius: '2px',
background: color,
},
swatch: {
padding: '4px',
background: '#fff',
borderRadius: '2px',
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
display: 'inline-block',
cursor: 'pointer',
},
popover: {
position: 'absolute',
zIndex: 10,
},
cover: {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
},
wrapper: {
position: 'inherit',
zIndex: 100,
},
};
if (position === 'top') {
styles.wrapper.transform = `translate(calc(-100% + ${width + 8}px), -100%)`;
styles.wrapper.paddingBottom = 8;
} }
state = { const swatch: React.ReactNode = (
displayColorPicker: false, <div style={styles.swatch} onClick={handleClick}>
color: undefined, <div style={styles.color} />
}; </div>
);
handleClick = () => { const picker: React.ReactNode = displayColorPicker ? (
const { displayColorPicker } = this.state; <div style={styles.popover}>
this.setState({ displayColorPicker: !displayColorPicker }); <div style={styles.cover} onClick={handleClose} />
}; <div style={styles.wrapper}>
<SketchPicker
handleClose = () => { presetColors={presetColors}
this.setState({ displayColorPicker: false }); color={color}
}; onChange={handleChange}
onChangeComplete={handleChangeComplete}
handleChange = (color: { hex: string }) => { />
const { onChange = noop } = this.props;
this.setState({ color: color.hex });
onChange(color.hex, color);
};
handleChangeComplete = (color: { hex: string }) => {
const { onChangeComplete = noop } = this.props;
this.setState({ color: color.hex });
onChangeComplete(color.hex);
};
render() {
const { small, position = 'bottom', presetColors } = this.props;
const { color, displayColorPicker } = this.state;
const width = small ? 80 : 120;
const styles: Record<PropertyKey, React.CSSProperties> = {
color: {
width: `${width}px`,
height: small ? '16px' : '24px',
borderRadius: '2px',
background: color,
},
swatch: {
padding: '4px',
background: '#fff',
borderRadius: '2px',
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
display: 'inline-block',
cursor: 'pointer',
},
popover: {
position: 'absolute',
zIndex: 10,
},
cover: {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
},
wrapper: {
position: 'inherit',
zIndex: 100,
},
};
if (position === 'top') {
styles.wrapper.transform = `translate(calc(-100% + ${width + 8}px), -100%)`;
styles.wrapper.paddingBottom = 8;
}
const swatch = (
<div style={styles.swatch} onClick={this.handleClick}>
<div style={styles.color} />
</div> </div>
); </div>
const picker = displayColorPicker ? ( ) : null;
<div style={styles.popover}>
<div style={styles.cover} onClick={this.handleClose} />
<div style={styles.wrapper}>
<SketchPicker
presetColors={presetColors}
color={color}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
</div>
</div>
) : null;
if (position === 'top') { return position === 'top' ? (
return ( <div>
<div> {picker}
{picker} {swatch}
{swatch} </div>
</div> ) : (
); <div>
} {swatch}
return ( {picker}
<div> </div>
{swatch} );
{picker} };
</div>
); export default ColorPicker;
}
}

View File

@ -1,12 +1,13 @@
import { SearchOutlined } from '@ant-design/icons'; import { SearchOutlined } from '@ant-design/icons';
import { resetWarned } from 'rc-util/lib/warning'; import { resetWarned } from 'rc-util/lib/warning';
import React, { Component } from 'react'; import React, { useState } from 'react';
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
import Button from '..'; import Button from '..';
import mountTest from '../../../tests/shared/mountTest'; import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest'; import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils'; import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import ConfigProvider from '../../config-provider'; import ConfigProvider from '../../config-provider';
import type { BaseButtonProps } from '../button';
describe('Button', () => { describe('Button', () => {
mountTest(Button); mountTest(Button);
@ -133,48 +134,28 @@ describe('Button', () => {
}); });
it('should change loading state instantly by default', () => { it('should change loading state instantly by default', () => {
class DefaultButton extends Component { const DefaultButton: React.FC = () => {
state = { const [loading, setLoading] = useState<BaseButtonProps['loading']>(false);
loading: false, return (
}; <Button loading={loading} onClick={() => setLoading(true)}>
Button
enterLoading = () => { </Button>
this.setState({ loading: true }); );
}; };
render() {
const { loading } = this.state;
return (
<Button loading={loading} onClick={this.enterLoading}>
Button
</Button>
);
}
}
const wrapper = render(<DefaultButton />); const wrapper = render(<DefaultButton />);
fireEvent.click(wrapper.container.firstChild!); fireEvent.click(wrapper.container.firstChild!);
expect(wrapper.container.querySelectorAll('.ant-btn-loading').length).toBe(1); expect(wrapper.container.querySelectorAll('.ant-btn-loading').length).toBe(1);
}); });
it('should change loading state with delay', () => { it('should change loading state with delay', () => {
class DefaultButton extends Component { const DefaultButton: React.FC = () => {
state = { const [loading, setLoading] = useState<BaseButtonProps['loading']>(false);
loading: false, return (
}; <Button loading={loading} onClick={() => setLoading({ delay: 1000 })}>
Button
enterLoading = () => { </Button>
this.setState({ loading: { delay: 1000 } }); );
}; };
render() {
const { loading } = this.state;
return (
<Button loading={loading} onClick={this.enterLoading}>
Button
</Button>
);
}
}
const wrapper = render(<DefaultButton />); const wrapper = render(<DefaultButton />);
fireEvent.click(wrapper.container.firstChild!); fireEvent.click(wrapper.container.firstChild!);
expect(wrapper.container.firstChild).not.toHaveClass('ant-btn-loading'); expect(wrapper.container.firstChild).not.toHaveClass('ant-btn-loading');