123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- /* eslint-disable max-len */
- import React from 'react';
- import cls from 'classnames';
- import PropTypes from 'prop-types';
- import SwitchFoudation, { SwitchAdapter } from '@douyinfe/semi-foundation/switch/foundation';
- import { cssClasses, strings } from '@douyinfe/semi-foundation/switch/constants';
- import BaseComponent from '../_base/baseComponent';
- import '@douyinfe/semi-foundation/switch/switch.scss';
- import { noop } from 'lodash';
- import Spin from '../spin';
- export interface SwitchProps {
- 'aria-label'?: React.AriaAttributes['aria-label'];
- 'aria-describedby'?: React.AriaAttributes['aria-describedby'];
- 'aria-errormessage'?: React.AriaAttributes['aria-errormessage'];
- 'aria-invalid'?: React.AriaAttributes['aria-invalid'];
- 'aria-labelledby'?: React.AriaAttributes['aria-labelledby'];
- defaultChecked?: boolean;
- checked?: boolean;
- disabled?: boolean;
- onChange?: (checked: boolean, e: React.ChangeEvent<HTMLInputElement>) => void;
- loading?: boolean;
- className?: string;
- style?: React.CSSProperties;
- onMouseEnter?: (e: React.MouseEvent) => any;
- onMouseLeave?: (e: React.MouseEvent) => any;
- size?: 'large' | 'default' | 'small';
- checkedText?: React.ReactNode;
- uncheckedText?: React.ReactNode;
- id?: string;
- }
- export interface SwitchState {
- nativeControlChecked: boolean;
- nativeControlDisabled: boolean;
- focusVisible: boolean;
- }
- class Switch extends BaseComponent<SwitchProps, SwitchState> {
- static propTypes = {
- 'aria-label': PropTypes.string,
- 'aria-labelledby': PropTypes.string,
- 'aria-invalid': PropTypes.bool,
- 'aria-errormessage': PropTypes.string,
- 'aria-describedby': PropTypes.string,
- className: PropTypes.string,
- checked: PropTypes.bool,
- checkedText: PropTypes.node,
- defaultChecked: PropTypes.bool,
- disabled: PropTypes.bool,
- loading: PropTypes.bool,
- onChange: PropTypes.func,
- onMouseEnter: PropTypes.func,
- onMouseLeave: PropTypes.func,
- style: PropTypes.object,
- size: PropTypes.oneOf<SwitchProps['size']>(strings.SIZE_MAP),
- uncheckedText: PropTypes.node,
- id: PropTypes.string,
- };
- static defaultProps: Partial<SwitchProps> = {
- disabled: false,
- className: '',
- onChange: noop,
- loading: false,
- onMouseEnter: noop,
- onMouseLeave: noop,
- size: 'default',
- };
- private switchRef: React.RefObject<HTMLInputElement>;
- constructor(props: SwitchProps) {
- super(props);
- this.state = {
- nativeControlChecked: false,
- nativeControlDisabled: false,
- focusVisible: false
- };
- this.switchRef = React.createRef();
- this.foundation = new SwitchFoudation(this.adapter);
- }
- componentDidMount() {
- this.foundation.init();
- }
- componentDidUpdate(prevProps: SwitchProps) {
- if (this.props.checked !== prevProps.checked) {
- this.foundation.setChecked(this.props.checked);
- }
- if (this.props.disabled !== prevProps.disabled) {
- this.foundation.setDisabled(this.props.disabled);
- }
- }
- componentWillUnmount() {
- this.foundation.destroy();
- }
- get adapter(): SwitchAdapter<SwitchProps, SwitchState> {
- return {
- ...super.adapter,
- setNativeControlChecked: (nativeControlChecked: boolean): void => {
- this.setState({ nativeControlChecked });
- },
- setNativeControlDisabled: (nativeControlDisabled: boolean): void => {
- this.setState({ nativeControlDisabled });
- },
- setFocusVisible: (focusVisible: boolean): void => {
- this.setState({ focusVisible });
- },
- notifyChange: (checked: boolean, e: React.ChangeEvent<HTMLInputElement>): void => {
- this.props.onChange(checked, e);
- },
- };
- }
- handleFocusVisible = (event: React.FocusEvent) => {
- this.foundation.handleFocusVisible(event);
- }
- handleBlur = (event: React.FocusEvent) => {
- this.foundation.handleBlur();
- }
- render() {
- const { nativeControlChecked, nativeControlDisabled, focusVisible } = this.state;
- const { className, style, onMouseEnter, onMouseLeave, size, checkedText, uncheckedText, loading, id } = this.props;
- const wrapperCls = cls(className, {
- [cssClasses.PREFIX]: true,
- [cssClasses.CHECKED]: nativeControlChecked,
- [cssClasses.DISABLED]: nativeControlDisabled,
- [cssClasses.LARGE]: size === 'large',
- [cssClasses.SMALL]: size === 'small',
- [cssClasses.LOADING]: loading,
- [cssClasses.FOCUS]: focusVisible,
- });
- const switchProps = {
- type: 'checkbox',
- className: cssClasses.NATIVE_CONTROL,
- disabled: nativeControlDisabled || loading,
- checked: nativeControlChecked || false,
- };
- const showCheckedText = checkedText && nativeControlChecked && size !== 'small';
- const showUncheckedText = uncheckedText && !nativeControlChecked && size !== 'small';
- return (
- <div className={wrapperCls} style={style} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
- {loading ? (
- <Spin wrapperClassName={cssClasses.LOADING_SPIN} size={size === 'default' ? 'middle' : size} />
- ) : (
- <div className={cssClasses.KNOB} aria-hidden={true} />
- )}
- {showCheckedText ? (
- <div className={cssClasses.CHECKED_TEXT} x-semi-prop="checkedText">
- {checkedText}
- </div>
- ) : null}
- {showUncheckedText ? (
- <div className={cssClasses.UNCHECKED_TEXT} x-semi-prop="uncheckedText">
- {uncheckedText}
- </div>
- ) : null}
- <input
- {...switchProps}
- ref={this.switchRef}
- id={id}
- role="switch"
- aria-checked={nativeControlChecked}
- aria-invalid={this.props['aria-invalid']}
- aria-errormessage={this.props['aria-errormessage']}
- aria-label={this.props['aria-label']}
- aria-labelledby={this.props['aria-labelledby']}
- aria-describedby={this.props['aria-describedby']}
- aria-disabled={this.props['disabled']}
- onChange={e => this.foundation.handleChange(e.target.checked, e)}
- onFocus={e => this.handleFocusVisible(e)}
- onBlur={e => this.handleBlur(e)}
- />
- </div>
- );
- }
- }
- export default Switch;
|