1
This commit is contained in:
+59
@@ -0,0 +1,59 @@
|
||||
import * as React from 'react';
|
||||
import type { CheckboxRef } from '@rc-component/checkbox';
|
||||
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
|
||||
export interface AbstractCheckboxProps<T> {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
rootClassName?: string;
|
||||
defaultChecked?: boolean;
|
||||
checked?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
onChange?: (e: T) => void;
|
||||
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||
onMouseEnter?: React.MouseEventHandler<HTMLElement>;
|
||||
onMouseLeave?: React.MouseEventHandler<HTMLElement>;
|
||||
onKeyPress?: React.KeyboardEventHandler<HTMLElement>;
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
|
||||
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
||||
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
||||
value?: any;
|
||||
tabIndex?: number;
|
||||
name?: string;
|
||||
children?: React.ReactNode;
|
||||
id?: string;
|
||||
autoFocus?: boolean;
|
||||
type?: string;
|
||||
skipGroup?: boolean;
|
||||
required?: boolean;
|
||||
}
|
||||
export interface CheckboxChangeEventTarget extends CheckboxProps {
|
||||
checked: boolean;
|
||||
}
|
||||
export interface CheckboxChangeEvent {
|
||||
target: CheckboxChangeEventTarget;
|
||||
stopPropagation: () => void;
|
||||
preventDefault: () => void;
|
||||
nativeEvent: MouseEvent;
|
||||
}
|
||||
export type CheckboxSemanticName = keyof CheckboxSemanticClassNames & keyof CheckboxSemanticStyles;
|
||||
export type CheckboxSemanticClassNames = {
|
||||
root?: string;
|
||||
icon?: string;
|
||||
label?: string;
|
||||
};
|
||||
export type CheckboxSemanticStyles = {
|
||||
root?: React.CSSProperties;
|
||||
icon?: React.CSSProperties;
|
||||
label?: React.CSSProperties;
|
||||
};
|
||||
export type CheckboxClassNamesType = SemanticClassNamesType<CheckboxProps, CheckboxSemanticClassNames>;
|
||||
export type CheckboxStylesType = SemanticStylesType<CheckboxProps, CheckboxSemanticStyles>;
|
||||
export interface CheckboxProps extends AbstractCheckboxProps<CheckboxChangeEvent> {
|
||||
indeterminate?: boolean;
|
||||
classNames?: CheckboxClassNamesType;
|
||||
styles?: CheckboxStylesType;
|
||||
}
|
||||
declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<CheckboxRef>>;
|
||||
export default Checkbox;
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
"use client";
|
||||
|
||||
import * as React from 'react';
|
||||
import RcCheckbox from '@rc-component/checkbox';
|
||||
import { useControlledState, useEvent } from '@rc-component/util';
|
||||
import { useComposeRef } from "@rc-component/util/es/ref";
|
||||
import { clsx } from 'clsx';
|
||||
import { useMergeSemantic } from '../_util/hooks';
|
||||
import { isNonNullable } from '../_util/is';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import Wave from '../_util/wave';
|
||||
import { TARGET_CLS } from '../_util/wave/interface';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import DisabledContext from '../config-provider/DisabledContext';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
|
||||
import { FormItemInputContext } from '../form/context';
|
||||
import GroupContext from './GroupContext';
|
||||
import useStyle from './style';
|
||||
import useBubbleLock from './useBubbleLock';
|
||||
const InternalCheckbox = (props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
children,
|
||||
indeterminate = false,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
skipGroup = false,
|
||||
disabled,
|
||||
// Style
|
||||
rootClassName,
|
||||
className,
|
||||
style,
|
||||
classNames,
|
||||
styles,
|
||||
// Name
|
||||
name,
|
||||
// Value
|
||||
value,
|
||||
// Checked
|
||||
checked,
|
||||
defaultChecked,
|
||||
onChange,
|
||||
...restProps
|
||||
} = props;
|
||||
const {
|
||||
getPrefixCls,
|
||||
direction,
|
||||
className: contextClassName,
|
||||
style: contextStyle,
|
||||
classNames: contextClassNames,
|
||||
styles: contextStyles
|
||||
} = useComponentConfig('checkbox');
|
||||
const checkboxGroup = React.useContext(GroupContext);
|
||||
const {
|
||||
isFormItemInput
|
||||
} = React.useContext(FormItemInputContext);
|
||||
const contextDisabled = React.useContext(DisabledContext);
|
||||
const mergedDisabled = (checkboxGroup?.disabled || disabled) ?? contextDisabled;
|
||||
// ============================= Warning ==============================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Checkbox');
|
||||
process.env.NODE_ENV !== "production" ? warning('checked' in props || !!checkboxGroup || !('value' in props), 'usage', '`value` is not a valid prop, do you mean `checked`?') : void 0;
|
||||
}
|
||||
// ============================= Checked ==============================
|
||||
const [innerChecked, setInnerChecked] = useControlledState(defaultChecked, checked);
|
||||
let mergedChecked = innerChecked;
|
||||
const onInternalChange = useEvent(event => {
|
||||
setInnerChecked(event.target.checked);
|
||||
onChange?.(event);
|
||||
if (!skipGroup && checkboxGroup?.toggleOption) {
|
||||
checkboxGroup.toggleOption({
|
||||
label: children,
|
||||
value
|
||||
});
|
||||
}
|
||||
});
|
||||
// ============================== Group ===============================
|
||||
if (checkboxGroup && !skipGroup) {
|
||||
mergedChecked = checkboxGroup.value.includes(value);
|
||||
}
|
||||
const checkboxRef = React.useRef(null);
|
||||
const mergedRef = useComposeRef(ref, checkboxRef);
|
||||
React.useEffect(() => {
|
||||
if (skipGroup || !checkboxGroup) {
|
||||
return;
|
||||
}
|
||||
checkboxGroup.registerValue(value);
|
||||
return () => {
|
||||
checkboxGroup.cancelValue(value);
|
||||
};
|
||||
}, [value, skipGroup]);
|
||||
// ========================== Indeterminate ===========================
|
||||
React.useEffect(() => {
|
||||
if (checkboxRef.current?.input) {
|
||||
checkboxRef.current.input.indeterminate = indeterminate;
|
||||
}
|
||||
}, [indeterminate]);
|
||||
// ============================== Style ===============================
|
||||
const prefixCls = getPrefixCls('checkbox', customizePrefixCls);
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
const checkboxProps = {
|
||||
...restProps
|
||||
};
|
||||
// =========== Merged Props for Semantic ==========
|
||||
const mergedProps = {
|
||||
...props,
|
||||
indeterminate,
|
||||
disabled: mergedDisabled,
|
||||
checked: mergedChecked
|
||||
};
|
||||
const [mergedClassNames, mergedStyles] = useMergeSemantic([contextClassNames, classNames], [contextStyles, styles], {
|
||||
props: mergedProps
|
||||
});
|
||||
const classString = clsx(`${prefixCls}-wrapper`, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-wrapper-checked`]: mergedChecked,
|
||||
[`${prefixCls}-wrapper-disabled`]: mergedDisabled,
|
||||
[`${prefixCls}-wrapper-in-form-item`]: isFormItemInput
|
||||
}, contextClassName, className, mergedClassNames.root, rootClassName, cssVarCls, rootCls, hashId);
|
||||
const checkboxClass = clsx(mergedClassNames.icon, {
|
||||
[`${prefixCls}-indeterminate`]: indeterminate
|
||||
}, TARGET_CLS, hashId);
|
||||
// ============================ Event Lock ============================
|
||||
const [onLabelClick, onInputClick] = useBubbleLock(checkboxProps.onClick);
|
||||
// ============================== Render ==============================
|
||||
return /*#__PURE__*/React.createElement(Wave, {
|
||||
component: "Checkbox",
|
||||
disabled: mergedDisabled
|
||||
}, /*#__PURE__*/React.createElement("label", {
|
||||
className: classString,
|
||||
style: {
|
||||
...mergedStyles.root,
|
||||
...contextStyle,
|
||||
...style
|
||||
},
|
||||
onMouseEnter: onMouseEnter,
|
||||
onMouseLeave: onMouseLeave,
|
||||
onClick: onLabelClick
|
||||
}, /*#__PURE__*/React.createElement(RcCheckbox, {
|
||||
...checkboxProps,
|
||||
name: !skipGroup && checkboxGroup ? checkboxGroup.name : name,
|
||||
checked: mergedChecked,
|
||||
onClick: onInputClick,
|
||||
onChange: onInternalChange,
|
||||
prefixCls: prefixCls,
|
||||
className: checkboxClass,
|
||||
style: mergedStyles.icon,
|
||||
disabled: mergedDisabled,
|
||||
ref: mergedRef,
|
||||
value: value
|
||||
}), isNonNullable(children) && (/*#__PURE__*/React.createElement("span", {
|
||||
className: clsx(`${prefixCls}-label`, mergedClassNames.label),
|
||||
style: mergedStyles.label
|
||||
}, children))));
|
||||
};
|
||||
const Checkbox = /*#__PURE__*/React.forwardRef(InternalCheckbox);
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Checkbox.displayName = 'Checkbox';
|
||||
}
|
||||
export default Checkbox;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import * as React from 'react';
|
||||
import type { HTMLAriaDataAttributes } from '../_util/aria-data-attrs';
|
||||
import type { CheckboxChangeEvent } from './Checkbox';
|
||||
import GroupContext from './GroupContext';
|
||||
export interface CheckboxOptionType<T = any> {
|
||||
label: React.ReactNode;
|
||||
value: T;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
id?: string;
|
||||
onChange?: (e: CheckboxChangeEvent) => void;
|
||||
required?: boolean;
|
||||
}
|
||||
export interface AbstractCheckboxGroupProps<T = any> extends HTMLAriaDataAttributes {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
rootClassName?: string;
|
||||
options?: (CheckboxOptionType<T> | string | number)[];
|
||||
disabled?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
export interface CheckboxGroupProps<T = any> extends AbstractCheckboxGroupProps<T> {
|
||||
name?: string;
|
||||
defaultValue?: T[];
|
||||
value?: T[];
|
||||
onChange?: (checkedValue: T[]) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
export type { CheckboxGroupContext } from './GroupContext';
|
||||
export { GroupContext };
|
||||
declare const _default: <T = any>(props: CheckboxGroupProps<T> & React.RefAttributes<HTMLDivElement>) => React.ReactElement;
|
||||
export default _default;
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
"use client";
|
||||
|
||||
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
||||
import * as React from 'react';
|
||||
import { omit } from '@rc-component/util';
|
||||
import { clsx } from 'clsx';
|
||||
import { isNumber } from '../_util/is';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
|
||||
import Checkbox from './Checkbox';
|
||||
import GroupContext from './GroupContext';
|
||||
import useStyle from './style';
|
||||
const CheckboxGroup = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
defaultValue,
|
||||
children,
|
||||
options = [],
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
rootClassName,
|
||||
style,
|
||||
onChange,
|
||||
role = 'group',
|
||||
...restProps
|
||||
} = props;
|
||||
const {
|
||||
getPrefixCls,
|
||||
direction
|
||||
} = React.useContext(ConfigContext);
|
||||
const [value, setValue] = React.useState(restProps.value || defaultValue || []);
|
||||
const [registeredValues, setRegisteredValues] = React.useState([]);
|
||||
React.useEffect(() => {
|
||||
if ('value' in restProps) {
|
||||
setValue(restProps.value || []);
|
||||
}
|
||||
}, [restProps.value]);
|
||||
const memoizedOptions = React.useMemo(() => options.map(option => {
|
||||
if (typeof option === 'string' || isNumber(option)) {
|
||||
return {
|
||||
label: option,
|
||||
value: option
|
||||
};
|
||||
}
|
||||
return option;
|
||||
}), [options]);
|
||||
const cancelValue = val => {
|
||||
setRegisteredValues(prevValues => prevValues.filter(v => v !== val));
|
||||
};
|
||||
const registerValue = val => {
|
||||
setRegisteredValues(prevValues => [].concat(_toConsumableArray(prevValues), [val]));
|
||||
};
|
||||
const toggleOption = option => {
|
||||
const optionIndex = value.indexOf(option.value);
|
||||
const newValue = _toConsumableArray(value);
|
||||
if (optionIndex === -1) {
|
||||
newValue.push(option.value);
|
||||
} else {
|
||||
newValue.splice(optionIndex, 1);
|
||||
}
|
||||
if (!('value' in restProps)) {
|
||||
setValue(newValue);
|
||||
}
|
||||
onChange?.(newValue.filter(val => registeredValues.includes(val)).sort((a, b) => {
|
||||
const indexA = memoizedOptions.findIndex(opt => opt.value === a);
|
||||
const indexB = memoizedOptions.findIndex(opt => opt.value === b);
|
||||
return indexA - indexB;
|
||||
}));
|
||||
};
|
||||
const prefixCls = getPrefixCls('checkbox', customizePrefixCls);
|
||||
const groupPrefixCls = `${prefixCls}-group`;
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
const domProps = omit(restProps, ['value', 'disabled']);
|
||||
const childrenNode = options.length ? memoizedOptions.map(option => (/*#__PURE__*/React.createElement(Checkbox, {
|
||||
prefixCls: prefixCls,
|
||||
key: option.value.toString(),
|
||||
disabled: 'disabled' in option ? option.disabled : restProps.disabled,
|
||||
value: option.value,
|
||||
checked: value.includes(option.value),
|
||||
onChange: option.onChange,
|
||||
className: clsx(`${groupPrefixCls}-item`, option.className),
|
||||
style: option.style,
|
||||
title: option.title,
|
||||
id: option.id,
|
||||
required: option.required
|
||||
}, option.label))) : children;
|
||||
const memoizedContext = React.useMemo(() => ({
|
||||
toggleOption,
|
||||
value,
|
||||
disabled: restProps.disabled,
|
||||
name: restProps.name,
|
||||
// https://github.com/ant-design/ant-design/issues/16376
|
||||
registerValue,
|
||||
cancelValue
|
||||
}), [toggleOption, value, restProps.disabled, restProps.name, registerValue, cancelValue]);
|
||||
const classString = clsx(groupPrefixCls, {
|
||||
[`${groupPrefixCls}-rtl`]: direction === 'rtl'
|
||||
}, className, rootClassName, cssVarCls, rootCls, hashId);
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: classString,
|
||||
style: style,
|
||||
role: role,
|
||||
...domProps,
|
||||
ref: ref
|
||||
}, /*#__PURE__*/React.createElement(GroupContext.Provider, {
|
||||
value: memoizedContext
|
||||
}, childrenNode));
|
||||
});
|
||||
export { GroupContext };
|
||||
export default CheckboxGroup;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import type { CheckboxOptionType } from './Group';
|
||||
export interface CheckboxGroupContext<T = any> {
|
||||
name?: string;
|
||||
toggleOption?: (option: CheckboxOptionType<T>) => void;
|
||||
value?: any;
|
||||
disabled?: boolean;
|
||||
registerValue: (val: T) => void;
|
||||
cancelValue: (val: T) => void;
|
||||
}
|
||||
declare const GroupContext: React.Context<CheckboxGroupContext<any> | null>;
|
||||
export default GroupContext;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import React from 'react';
|
||||
const GroupContext = /*#__PURE__*/React.createContext(null);
|
||||
export default GroupContext;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { CheckboxRef } from '@rc-component/checkbox';
|
||||
import InternalCheckbox from './Checkbox';
|
||||
import Group from './Group';
|
||||
export type { CheckboxChangeEvent, CheckboxProps, CheckboxSemanticClassNames, CheckboxSemanticName, CheckboxSemanticStyles, } from './Checkbox';
|
||||
export type { CheckboxGroupProps, CheckboxOptionType } from './Group';
|
||||
export type { CheckboxRef };
|
||||
type CompoundedComponent = typeof InternalCheckbox & {
|
||||
Group: typeof Group;
|
||||
};
|
||||
declare const Checkbox: CompoundedComponent;
|
||||
export default Checkbox;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import InternalCheckbox from './Checkbox';
|
||||
import Group from './Group';
|
||||
const Checkbox = InternalCheckbox;
|
||||
Checkbox.Group = Group;
|
||||
Checkbox.__ANT_CHECKBOX = true;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Checkbox.displayName = 'Checkbox';
|
||||
}
|
||||
export default Checkbox;
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
export interface ComponentToken {
|
||||
}
|
||||
/**
|
||||
* @desc Checkbox 组件的 Token
|
||||
* @descEN Token for Checkbox component
|
||||
*/
|
||||
interface CheckboxToken extends FullToken<'Checkbox'> {
|
||||
/**
|
||||
* @desc Checkbox 类名
|
||||
* @descEN Checkbox class name
|
||||
*/
|
||||
checkboxCls: string;
|
||||
/**
|
||||
* @desc Checkbox 尺寸
|
||||
* @descEN Size of Checkbox
|
||||
*/
|
||||
checkboxSize: number;
|
||||
}
|
||||
export declare const genCheckboxStyle: GenerateStyle<CheckboxToken>;
|
||||
export declare function getStyle(prefixCls: string, token: FullToken<'Checkbox'>): import("@ant-design/cssinjs").CSSInterpolation;
|
||||
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
|
||||
export default _default;
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
import { unit } from '@ant-design/cssinjs';
|
||||
import { genFocusOutline, resetComponent } from '../../style';
|
||||
import { genNoMotionStyle } from '../../style/motion';
|
||||
import { genStyleHooks, mergeToken } from '../../theme/internal';
|
||||
// ============================== Styles ==============================
|
||||
export const genCheckboxStyle = token => {
|
||||
const {
|
||||
checkboxCls,
|
||||
checkboxSize,
|
||||
lineWidth
|
||||
} = token;
|
||||
const wrapperCls = `${checkboxCls}-wrapper`;
|
||||
return [
|
||||
// ===================== Basic =====================
|
||||
{
|
||||
// Group
|
||||
[`${checkboxCls}-group`]: {
|
||||
...resetComponent(token),
|
||||
display: 'inline-flex',
|
||||
flexWrap: 'wrap',
|
||||
columnGap: token.marginXS,
|
||||
// Group > Grid
|
||||
[`> ${token.antCls}-row`]: {
|
||||
flex: 1
|
||||
}
|
||||
},
|
||||
// Wrapper
|
||||
[wrapperCls]: {
|
||||
...resetComponent(token),
|
||||
display: 'inline-flex',
|
||||
alignItems: 'baseline',
|
||||
cursor: 'pointer',
|
||||
// Fix checkbox & radio in flex align #30260
|
||||
'&:after': {
|
||||
display: 'inline-block',
|
||||
width: 0,
|
||||
overflow: 'hidden',
|
||||
content: "'\\a0'"
|
||||
},
|
||||
// Checkbox near checkbox
|
||||
[`& + ${wrapperCls}`]: {
|
||||
marginInlineStart: 0
|
||||
},
|
||||
[`&${wrapperCls}-in-form-item`]: {
|
||||
'input[type="checkbox"]': {
|
||||
width: 14,
|
||||
// FIXME: magic
|
||||
height: 14 // FIXME: magic
|
||||
}
|
||||
}
|
||||
},
|
||||
// Wrapper > Checkbox
|
||||
[checkboxCls]: {
|
||||
...resetComponent(token),
|
||||
position: 'relative',
|
||||
whiteSpace: 'nowrap',
|
||||
lineHeight: 1,
|
||||
cursor: 'pointer',
|
||||
// To make alignment right when `controlHeight` is changed
|
||||
// Ref: https://github.com/ant-design/ant-design/issues/41564
|
||||
alignSelf: 'center',
|
||||
// Styles moved from inner
|
||||
boxSizing: 'border-box',
|
||||
display: 'block',
|
||||
width: checkboxSize,
|
||||
height: checkboxSize,
|
||||
direction: 'ltr',
|
||||
backgroundColor: token.colorBgContainer,
|
||||
border: `${unit(lineWidth)} ${token.lineType} ${token.colorBorder}`,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
borderCollapse: 'separate',
|
||||
transition: `all ${token.motionDurationSlow}`,
|
||||
flex: 'none',
|
||||
...genNoMotionStyle(),
|
||||
// Checkmark
|
||||
'&:after': {
|
||||
boxSizing: 'border-box',
|
||||
position: 'absolute',
|
||||
top: `calc(${checkboxSize} / 2 - ${lineWidth})`,
|
||||
insetInlineStart: `calc(${checkboxSize} / 4 - ${lineWidth})`,
|
||||
display: 'table',
|
||||
width: token.calc(checkboxSize).div(14).mul(5).equal(),
|
||||
height: token.calc(checkboxSize).div(14).mul(8).equal(),
|
||||
border: `${unit(token.lineWidthBold)} solid ${token.colorWhite}`,
|
||||
borderTop: 0,
|
||||
borderInlineStart: 0,
|
||||
transform: 'rotate(45deg) scale(0) translate(-50%,-50%)',
|
||||
opacity: 0,
|
||||
content: '""',
|
||||
transition: `all ${token.motionDurationFast} ${token.motionEaseInBack}, opacity ${token.motionDurationFast}`,
|
||||
...genNoMotionStyle()
|
||||
},
|
||||
// Wrapper > Checkbox > input
|
||||
[`${checkboxCls}-input`]: {
|
||||
position: 'absolute',
|
||||
// Since baseline align will get additional space offset,
|
||||
// we need to move input to top to make it align with text.
|
||||
// Ref: https://github.com/ant-design/ant-design/issues/38926#issuecomment-1486137799
|
||||
inset: `calc(-1 * (${lineWidth}))`,
|
||||
zIndex: 1,
|
||||
cursor: 'pointer',
|
||||
opacity: 0,
|
||||
margin: 0
|
||||
},
|
||||
// Focus outline on checkbox when input is focus-visible
|
||||
[`&:has(${checkboxCls}-input:focus-visible)`]: genFocusOutline(token),
|
||||
// Wrapper > Checkbox + Text
|
||||
'& + span': {
|
||||
paddingInlineStart: token.paddingXS,
|
||||
paddingInlineEnd: token.paddingXS
|
||||
}
|
||||
}
|
||||
},
|
||||
// ===================== Hover =====================
|
||||
{
|
||||
// Wrapper & Wrapper > Checkbox
|
||||
[`
|
||||
${wrapperCls}:not(${wrapperCls}-disabled),
|
||||
${checkboxCls}:not(${checkboxCls}-disabled)
|
||||
`]: {
|
||||
[`&:hover ${checkboxCls}`]: {
|
||||
borderColor: token.colorPrimary
|
||||
}
|
||||
},
|
||||
[`${wrapperCls}:not(${wrapperCls}-disabled)`]: {
|
||||
[`&:hover ${checkboxCls}-checked:not(${checkboxCls}-disabled)`]: {
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
borderColor: 'transparent'
|
||||
}
|
||||
}
|
||||
},
|
||||
// ==================== Checked ====================
|
||||
{
|
||||
// Wrapper > Checkbox
|
||||
[`${checkboxCls}-checked`]: {
|
||||
backgroundColor: token.colorPrimary,
|
||||
borderColor: token.colorPrimary,
|
||||
'&:after': {
|
||||
opacity: 1,
|
||||
transform: 'rotate(45deg) scale(1) translate(-50%,-50%)',
|
||||
transition: `all ${token.motionDurationMid} ${token.motionEaseOutBack} ${token.motionDurationFast}`,
|
||||
...genNoMotionStyle()
|
||||
},
|
||||
// Hover on checked checkbox directly
|
||||
[`&:not(${checkboxCls}-disabled):hover`]: {
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
borderColor: 'transparent'
|
||||
}
|
||||
}
|
||||
},
|
||||
// ================= Indeterminate =================
|
||||
{
|
||||
[checkboxCls]: {
|
||||
'&-indeterminate': {
|
||||
backgroundColor: token.colorBgContainer,
|
||||
borderColor: token.colorBorder,
|
||||
'&:after': {
|
||||
top: '50%',
|
||||
insetInlineStart: '50%',
|
||||
width: token.calc(token.fontSizeLG).div(2).equal(),
|
||||
height: token.calc(token.fontSizeLG).div(2).equal(),
|
||||
backgroundColor: token.colorPrimary,
|
||||
border: 0,
|
||||
transform: 'translate(-50%, -50%) scale(1)',
|
||||
opacity: 1,
|
||||
content: '""'
|
||||
},
|
||||
// https://github.com/ant-design/ant-design/issues/50074
|
||||
'&:hover': {
|
||||
backgroundColor: token.colorBgContainer,
|
||||
borderColor: token.colorPrimary
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// ==================== Disable ====================
|
||||
{
|
||||
// Wrapper
|
||||
[`${wrapperCls}-disabled`]: {
|
||||
cursor: 'not-allowed'
|
||||
},
|
||||
// Wrapper > Checkbox
|
||||
[`${checkboxCls}-disabled`]: {
|
||||
// Wrapper > Checkbox > input
|
||||
[`&, ${checkboxCls}-input`]: {
|
||||
cursor: 'not-allowed',
|
||||
// Disabled for native input to enable Tooltip event handler
|
||||
// ref: https://github.com/ant-design/ant-design/issues/39822#issuecomment-1365075901
|
||||
pointerEvents: 'none'
|
||||
},
|
||||
// Disabled checkbox styles
|
||||
background: token.colorBgContainerDisabled,
|
||||
borderColor: token.colorBorder,
|
||||
'&:after': {
|
||||
borderColor: token.colorTextDisabled
|
||||
},
|
||||
'& + span': {
|
||||
color: token.colorTextDisabled
|
||||
},
|
||||
[`&${checkboxCls}-indeterminate::after`]: {
|
||||
background: token.colorTextDisabled
|
||||
}
|
||||
}
|
||||
}];
|
||||
};
|
||||
// ============================== Export ==============================
|
||||
export function getStyle(prefixCls, token) {
|
||||
const checkboxToken = mergeToken(token, {
|
||||
checkboxCls: `.${prefixCls}`,
|
||||
checkboxSize: token.controlInteractiveSize
|
||||
});
|
||||
return genCheckboxStyle(checkboxToken);
|
||||
}
|
||||
export default genStyleHooks('Checkbox', (token, {
|
||||
prefixCls
|
||||
}) => [getStyle(prefixCls, token)]);
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
/**
|
||||
* When click on the label,
|
||||
* the event will be stopped to prevent the label from being clicked twice.
|
||||
* label click -> input click -> label click again
|
||||
*/
|
||||
export default function useBubbleLock(onOriginInputClick?: React.MouseEventHandler<HTMLInputElement>): readonly [React.MouseEventHandler<HTMLLabelElement>, React.MouseEventHandler<HTMLInputElement>];
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import raf from "@rc-component/util/es/raf";
|
||||
/**
|
||||
* When click on the label,
|
||||
* the event will be stopped to prevent the label from being clicked twice.
|
||||
* label click -> input click -> label click again
|
||||
*/
|
||||
export default function useBubbleLock(onOriginInputClick) {
|
||||
const labelClickLockRef = React.useRef(null);
|
||||
const clearLock = () => {
|
||||
raf.cancel(labelClickLockRef.current);
|
||||
labelClickLockRef.current = null;
|
||||
};
|
||||
const onLabelClick = () => {
|
||||
clearLock();
|
||||
labelClickLockRef.current = raf(() => {
|
||||
labelClickLockRef.current = null;
|
||||
});
|
||||
};
|
||||
const onInputClick = e => {
|
||||
if (labelClickLockRef.current) {
|
||||
e.stopPropagation();
|
||||
clearLock();
|
||||
}
|
||||
onOriginInputClick?.(e);
|
||||
};
|
||||
return [onLabelClick, onInputClick];
|
||||
}
|
||||
Reference in New Issue
Block a user