diff --git a/.editorconfig b/.editorconfig index 604c94e..af20abd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,11 @@ -# top-most EditorConfig file +# 🎨 editorconfig.org + root = true -# Unix-style newlines with a newline ending every file -[*.{js,css}] +[*] +charset = utf-8 end_of_line = lf -insert_final_newline = true indent_style = space indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/src/index.d.ts b/src/index.d.ts deleted file mode 100644 index fd41fc6..0000000 --- a/src/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as React from 'react'; - -export interface Props { - prefixCls?: string; - className?: string; - style?: React.CSSProperties; - name?: string; - id?: string; - type?: string; - title?: string; - defaultChecked?: number | boolean; - checked?: number | boolean; - disabled?: boolean; - onFocus?: (e: React.FocusEvent) => void; - onBlur?: (e: React.FocusEvent) => void; - onChange?: (e: Event) => void; - onClick?: (e: React.MouseEvent) => void; - tabIndex?: string | number; - readOnly?: boolean; - required?: boolean; - autoFocus?: boolean; - value?: any; -} - -export default class CheckBox extends React.Component {} diff --git a/src/index.jsx b/src/index.jsx deleted file mode 100644 index dd42cdb..0000000 --- a/src/index.jsx +++ /dev/null @@ -1,149 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import React, { Component } from 'react'; -import classNames from 'classnames'; - -class Checkbox extends Component { - static defaultProps = { - prefixCls: 'rc-checkbox', - className: '', - style: {}, - type: 'checkbox', - title: '', - defaultChecked: false, - onFocus() {}, - onBlur() {}, - onChange() {}, - onKeyDown() {}, - onKeyPress() {}, - onKeyUp() {}, - }; - - constructor(props) { - super(props); - - const checked = 'checked' in props ? props.checked : props.defaultChecked; - - this.state = { - checked, - }; - } - - static getDerivedStateFromProps(props, state) { - if ('checked' in props) { - return { - ...state, - checked: props.checked, - }; - } - return null; - } - - focus() { - this.input.focus(); - } - - blur() { - this.input.blur(); - } - - handleChange = e => { - const { disabled, onChange } = this.props; - if (disabled) { - return; - } - if (!('checked' in this.props)) { - this.setState({ - checked: e.target.checked, - }); - } - if (onChange) { - onChange({ - target: { - ...this.props, - checked: e.target.checked, - }, - stopPropagation() { - e.stopPropagation(); - }, - preventDefault() { - e.preventDefault(); - }, - nativeEvent: e.nativeEvent, - }); - } - }; - - saveInput = node => { - this.input = node; - }; - - render() { - const { - prefixCls, - className, - style, - name, - id, - type, - title, - disabled, - readOnly, - tabIndex, - onClick, - onFocus, - onBlur, - onKeyDown, - onKeyPress, - onKeyUp, - autoFocus, - value, - required, - ...others - } = this.props; - - const globalProps = Object.keys(others).reduce((prev, key) => { - if (key.substr(0, 5) === 'aria-' || key.substr(0, 5) === 'data-' || key === 'role') { - // eslint-disable-next-line no-param-reassign - prev[key] = others[key]; - } - return prev; - }, {}); - - const { checked } = this.state; - const classString = classNames(prefixCls, className, { - [`${prefixCls}-checked`]: checked, - [`${prefixCls}-disabled`]: disabled, - }); - - return ( - - - - - ); - } -} - -export default Checkbox; diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..17a896a --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,104 @@ +import * as React from 'react'; +import { forwardRef, useImperativeHandle, useRef } from 'react'; +import useMergedState from 'rc-util/lib/hooks/useMergedState'; +import classNames from 'classnames'; + +export interface CheckboxChangeEvent { + target: CheckboxChangeEventTarget; + stopPropagation: () => void; + preventDefault: () => void; + nativeEvent: React.ChangeEvent['nativeEvent']; +} + +export interface CheckboxChangeEventTarget extends CheckboxProps { + checked: boolean; +} + +export interface CheckboxRef { + focus: () => void; + blur: () => void; + input: HTMLInputElement | null; +} + +export interface CheckboxProps + extends Omit, 'onChange'> { + prefixCls?: string; + onChange?: (e: CheckboxChangeEvent) => void; +} + +export const Checkbox = forwardRef((props, ref) => { + const { + prefixCls = 'rc-checkbox', + className, + style, + checked, + disabled, + defaultChecked = false, + type = 'checkbox', + onChange, + ...inputProps + } = props; + + const inputRef = useRef(null); + const [rawValue, setRawValue] = useMergedState(defaultChecked, { + value: checked, + }); + + useImperativeHandle(ref, () => ({ + focus: () => { + inputRef.current?.focus(); + }, + blur: () => { + inputRef.current?.blur(); + }, + input: inputRef.current, + })); + + const classString = classNames(prefixCls, className, { + [`${prefixCls}-checked`]: rawValue, + [`${prefixCls}-disabled`]: disabled, + }); + + const handleChange = (e: React.ChangeEvent) => { + if (disabled) { + return; + } + + const checked = e.target.checked; + + if (!('checked' in props)) { + setRawValue(checked); + } + + onChange?.({ + target: { + ...props, + checked, + }, + stopPropagation() { + e.stopPropagation(); + }, + preventDefault() { + e.preventDefault(); + }, + nativeEvent: e.nativeEvent, + }); + }; + + return ( + + + + + ); +}); + +export default Checkbox; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7ee3c49 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "esnext", + "moduleResolution": "node", + "baseUrl": "./", + "strict": true, + "jsx": "preserve", + "declaration": true, + "skipLibCheck": true, + "esModuleInterop": true, + "paths": { + "@/*": ["src/*"], + "@@/*": ["src/.umi/*"], + "rc-checkbox": ["src/index.tsx"] + } + } +}