Before using antD component library, this component is quite cool to use, I didn’t feel that a component is so difficult to write, but I found that there are many difficulties in a small button when WRITING by myself, sure enough, the wheel is still cool to use, but painful to build.

Without further ado, what should we do when we start writing a full-fledged component like ANTD?

First, like a mature component library, they all set up a color scheme for their component library: it consists of two sets of color plates

1. System palette – Basic + neutral palette

2. Product color plate – Brand color + function color plate

Reference elementUI:

In addition to a set of colors of its own brand, there are some component library base systems: For example, font system, border shadow, configurable switch, etc., since I will learn a series of components in the future, I have done some understanding here. But now I just imitate ANTD as a button component, and I just need to pick some color fonts I like, and I will not do entanglements here.

Now let’s analyze a button’s requirements:

1. Different Button types

Primary Default Danger LinkButton

2. Different Button sizes

normal small large

3. The disabled state

Disabled (Button unclickable A unclickable)

Start by defining the basic types of button described above:

Export enum ButtonSize {Large = 'lg', Small = "sm"} export enum ButtonType {Primary = "Primary ", Default = 'Default ', Danger =' Danger ', Link = 'Link'}// Button props {className? : string; disabled ? : boolean; size? :ButtonSize; btnType? :ButtonType; children: React.ReactNode; href? :string}Copy the code

Then pass the above basic type to Button Button, but the Button is divided into ordinary Button and link form a label, so you need to make a judgment on the type and return different labels

const Button: React.FC<BaseButtonProps> = (props) =>{ const { className, btnType, disabled, size, children, href, ... // BTN,btn-lg, // BTN,btn-lg, btn-primary const classes = classNames('btn',className,{ [`btn-${btnType}`]: btnType, [`btn-${size}`]: size, 'disabled':(btnType=== buttontype.link)&& disabled}) if(btnType === buttontype.link && href){return (<a) className={classes} href={href} {... restProps} >{children}</a> ) }else { return ( <button className={classes} disabled={disabled} >{children}</button> ) }}Copy the code

ClassName =” BTN bTN-lg btn-danger” className=” BTN bTN-lg btn-danger” className=” BTN bTN-lg btn-danger” className=” BTN bTN-lg btn-danger” className=” BTN bTN-lg Btn-danger “className=” BTN btn-lg Btn-danger” Of course, here we can also use the ternary operator, one by one to determine the classname, but the code will soon look very jumpy, more learning can refer to the official documentation github.com/JedWatson/c…

Finally, we give default values to the button properties and throw them. The basic skeleton of the button components is ready.

Button .

We can see that the code is in effect, generating the appropriate Disable attribute and a tag.

Next we can start to enrich the basic style of the button. Here we can define different styles for different class names of the button:

.btn { position: relative; display: inline-block; font-weight: 400; The line - height: 1.5; color: #212529; white-space: nowrap; text-align: center; vertical-align: middle; background-image: none; border: 1px solid transparent; Padding: 0.75 rem 0.375 rem; font-size: 1rem; Border - the radius: 0.25 rem; box-shadow: inset 0 1px 0 rgb(255 255 255 / 15%), 0 1px 1px rgb(0 0 0 / 8%); cursor: pointer; transition: Color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, border-color 0.15s ease-in-out, The box - 0.15 s ease - in-out shadow; } .btn-primary { color: #fff; background: #0d6efd; border-color: #0d6efd; } .btn-primary:hover { color: #fff; background: #3385fd; border-color: #408cfd; } button:not(:disabled), [type="button"]:not(:disabled), [type="reset"]:not(:disabled), [type="submit"]:not(:disabled) { cursor: pointer; }Copy the code

In addition to this, a more uniform way is to use SASS and set up a color scheme for the component library. We can write a default SET of SCSS code first, and then use the characteristics of SCSS to reference its basic color scheme in different class names. For example, in the base style file _variable. SCSS we write the style corresponding to the size of the button:

$btn-padding-y-sm: 0.25rem! default; $BTN - padding - x - sm: 0.5 rem! default; $btn-font-size-sm: $font-size-sm ! default; $BTN - padding - y - lg: 0.5 rem! default; $btn-padding-x-lg: 1rem ! default; $btn-font-size-lg: $font-size-lg ! default;Copy the code

Button/_style. SCSS = button-size;

.btn-lg { @include button-size( $btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg ); }.btn-sm { @include button-size( $btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm ); }Copy the code

Get the corresponding button-size:

@mixin button-size($padding-x, $padding-y, $font-size, $border-radius) { padding: $padding-y $padding-x; font-size: $font-size; border-radius: $border-radius; }Copy the code

Specific code SCSS code can refer to my personal warehouse github.com/woshidashua…

This allows us to get the style of a button for each attribute class name, but because we didn’t define button methods like click on button props, and the a tag didn’t pass in methods, we need to define methods for them. But if we were to write the methods on the button and a tags one by one, it would be very messy, So we use the react with the react. AnchorHTMLAttributes and react ButtonHTMLAttributes to define all the methods above, here we use ts to write need to use a joint properties, Pass an intersection of the properties we wrote and the properties that exist in the props

// The methods of button and A are passed to the porps one by one. It contains the attribute too much type NativeButtonProps = BaseButtonProps & React. ButtonHTMLAttributes < HTMLElement > / / buttontype joint type AnchorButtonProps = BaseButtonProps & React. AnchorHTMLAttributes < HTMLElement > / / a label export type ButtonProps = Partial<NativeButtonProps & AnchorButtonProps> // All properties optionalCopy the code

Complete button code

const Button: React.FC<ButtonProps> = (props) =>{ const { className, btnType, disabled, size, children, href, ... // BTN,btn-lg, // BTN,btn-lg, btn-primary const classes = classNames('btn',className,{ [`btn-${btnType}`]: btnType, [`btn-${size}`]: size, 'disabled':(btnType=== buttontype.link)&& disabled}) if(btnType === buttontype.link && href){return (<a) className={classes} href={href} {... restProps} >{children}</a> ) }else { return ( <button className={classes} disabled={disabled} >{children}</button> ) }}Button.defaultProps={ disabled:false, btnType:ButtonType.Default}Copy the code

Finally let’s see the effect!

Finally, paste the warehouse address:

Github.com/woshidashua…

References:

Juejin. Cn/post / 684490…

Juejin. Cn/post / 692259…

Coding.imooc.com/class/chapt…

Jeryqwq. Making. IO/Others/Antd…

Juejin. Cn/post / 697404…

Ps: Ask for praise, collect and forward, like 5, the next component menu update within a week