From 46c9e78abd4c5bfaa19826e22163c5051451c2b0 Mon Sep 17 00:00:00 2001 From: epoll-j Date: Thu, 29 Aug 2024 15:28:21 +0800 Subject: [PATCH] =?UTF-8?q?refactor(checkbox):=20checkbox=E5=8F=8Acheckbox?= =?UTF-8?q?group=E7=BB=93=E6=9E=84=E5=AF=B9=E9=BD=90vue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit re #459 --- src/checkbox/Checkbox.tsx | 204 +++++++++++++++++++-------------- src/checkbox/CheckboxGroup.tsx | 39 +++---- src/checkbox/style/index.js | 3 +- src/checkbox/type.ts | 5 + 4 files changed, 138 insertions(+), 113 deletions(-) diff --git a/src/checkbox/Checkbox.tsx b/src/checkbox/Checkbox.tsx index 7fe7eb1b..601ff6f3 100644 --- a/src/checkbox/Checkbox.tsx +++ b/src/checkbox/Checkbox.tsx @@ -1,11 +1,20 @@ -import React, { useContext, useMemo, Ref, forwardRef, CSSProperties } from 'react'; +import React, { useContext, useMemo, Ref, forwardRef } from 'react'; import classNames from 'classnames'; -import { Icon } from 'tdesign-icons-react'; +import { + CheckIcon, + MinusIcon, + CheckCircleFilledIcon, + CircleIcon, + MinusCircleFilledIcon, + MinusRectangleFilledIcon, + CheckRectangleFilledIcon, +} from 'tdesign-icons-react'; import { TdCheckboxProps } from './type'; import forwardRefWithStatics from '../_util/forwardRefWithStatics'; import CheckboxGroup from './CheckboxGroup'; import useConfig from '../_util/useConfig'; import useDefault from '../_util/useDefault'; +import { parseContentTNode } from '../_util/parseTNode'; export interface CheckBoxProps extends TdCheckboxProps { ref: Ref; @@ -17,125 +26,150 @@ export interface CheckContextValue { export const CheckContext = React.createContext(null); -const getLimitRowStyle = (row: number): CSSProperties => ({ - display: '-webkit-box', - overflow: 'hidden', - WebkitBoxOrient: 'vertical', - WebkitLineClamp: row, -}); - -const Checkbox = forwardRef((_props: CheckBoxProps, ref: Ref) => { +const Checkbox = forwardRef((_props: CheckBoxProps) => { const context = useContext(CheckContext); const props = context ? context.inject(_props) : _props; const { classPrefix } = useConfig(); + const classPrefixCheckBox = `${classPrefix}-checkbox`; const { - name, - align = 'left', + placement = 'left', content, - children, - disabled, indeterminate, label, onChange, checked, defaultChecked = false, - readonly, - value, maxLabelRow = 3, maxContentRow = 5, - icon, + icon = 'circle', contentDisabled = false, - // borderless = false, + block = true, + borderless = false, } = props; const [internalChecked, setInternalChecked] = useDefault(checked, defaultChecked, onChange); const checkboxClassName = classNames(`${classPrefix}-checkbox`, { - [`${classPrefix}-is-checked`]: internalChecked || indeterminate, - [`${classPrefix}-is-disabled`]: disabled, + [`${classPrefixCheckBox}--${placement}`]: true, + [`${classPrefixCheckBox}--checked`]: props.checked, + [`${classPrefixCheckBox}--block`]: block, }); - const iconName = useMemo(() => { - if (indeterminate) { - return 'minus-circle-filled'; + + const checkIcons = useMemo(() => { + if (Array.isArray(icon) && icon.length > 1) { + return icon.map((i) => + typeof i === 'string' ? : i, + ); } - if (internalChecked) { - return 'check-circle-filled'; + return [, ]; + }, [classPrefixCheckBox, icon]); + + const checkIcon = useMemo(() => { + if (icon === 'circle' || icon === true) { + return indeterminate ? : ; } - return 'circle'; - }, [indeterminate, internalChecked]); - const renderIcon = () => { + if (icon === 'rectangle') { + return indeterminate ? : ; + } + if (icon === 'line') { + return indeterminate ? : ; + } + return null; + }, [icon, indeterminate]); + + const renderIconArray = () => { if (Array.isArray(icon)) { - if (internalChecked) { - return icon[0]; - } - return icon[1]; + return parseContentTNode(internalChecked ? checkIcons[0] : checkIcons[1], { + className: classNames({ [`${classPrefixCheckBox}__icon-wrapper`]: true }), + }); + } + if (props.checked) { + return parseContentTNode(checkIcon, { + className: classNames({ [`${classPrefixCheckBox}__icon-wrapper`]: true }), + }); + } + return ( + <> + {(icon === 'circle' || icon === true || icon === 'rectangle') && ( +
+ )} + {icon === 'line' &&
} + + ); + }; + + const renderIconNode = () => { + if (!icon) { + return null; } return ( - + > + {renderIconArray()} + ); }; - const labelStyle: CSSProperties = { - color: disabled ? '#dcdcdc' : 'inherit', - ...getLimitRowStyle(maxLabelRow), - }; + const handleClick = (e) => { if (contentDisabled) { e.preventDefault(); } - setInternalChecked(!internalChecked, { e }) + setInternalChecked(!internalChecked, { e }); }; + + const renderCheckBoxContent = () => ( +
{ + event.stopPropagation(); + handleClick(event); + }} + > +
+ {label} +
+
+ {content} +
+
+ ); + return ( <> -
-
- { align ==='left' && - e.stopPropagation()} - onChange={(e) => setInternalChecked(e.currentTarget.checked, { e })} - /> - {renderIcon()} - } - - - {label} - - - {children || content} - - - - { align ==='right' && - e.stopPropagation()} - onChange={(e) => setInternalChecked(e.currentTarget.checked, { e })} - /> - {renderIcon()} - } -
+
+ {renderIconNode()} + {renderCheckBoxContent()} {/* 下边框 */} - {/* { !borderless &&
} */} - {
} + {!borderless && ( +
+ )}
); diff --git a/src/checkbox/CheckboxGroup.tsx b/src/checkbox/CheckboxGroup.tsx index 3af972d8..d9427fa2 100644 --- a/src/checkbox/CheckboxGroup.tsx +++ b/src/checkbox/CheckboxGroup.tsx @@ -27,18 +27,7 @@ const getCheckboxValue = (v: CheckboxOption): string | number => { export function CheckboxGroup(props: CheckboxGroupProps) { const { classPrefix } = useConfig(); - const { - value, - defaultValue, - disabled, - className, - max, - options = [], - name, - style, - children, - onChange, - } = props; + const { value, defaultValue, disabled, className, max, options = [], name, style, children, onChange } = props; const internalOptions = Array.isArray(options) && options.length > 0 @@ -116,8 +105,8 @@ export function CheckboxGroup(props: CheckboxGroupProps) { setInternalValue(Array.from(checkedSet), { e, - current: checkProps.checkAll ? undefined : (checkValue as TdCheckboxProps), - type: checked ? 'check' : 'uncheck' + current: checkProps.checkAll ? undefined : (checkValue as TdCheckboxProps), + type: checked ? 'check' : 'uncheck', }); }, }; @@ -129,11 +118,10 @@ export function CheckboxGroup(props: CheckboxGroupProps) { return (
-
-
- - {useOptions - ? options.map((v, index) => { + + + {useOptions + ? options.map((v, index) => { const type = typeof v; switch (type) { case 'number' || 'string': { @@ -148,20 +136,19 @@ export function CheckboxGroup(props: CheckboxGroupProps) { const vs = v as CheckboxOptionObj; // CheckAll 的 checkBox 不存在 value,故用 checkAll_index 来保证尽量不和用户的 value 冲突. return vs.checkAll ? ( - + ) : ( - + ); } default: return null; } }) - : children} - -
-
+ : children} + +
- ) + ); } export default CheckboxGroup; diff --git a/src/checkbox/style/index.js b/src/checkbox/style/index.js index 61286c46..8e93d9ce 100644 --- a/src/checkbox/style/index.js +++ b/src/checkbox/style/index.js @@ -1,7 +1,6 @@ // index.js -import '../../_common/style/mobile/components/checkbox/_index.less'; +import '../../_common/style/mobile/components/checkbox/v2/_index.less'; import '../../_common/style/mobile/components/checkbox-group/_index.less'; // css.js import './index.less'; - diff --git a/src/checkbox/type.ts b/src/checkbox/type.ts index 642b4d47..87734b93 100644 --- a/src/checkbox/type.ts +++ b/src/checkbox/type.ts @@ -92,6 +92,11 @@ export interface TdCheckboxProps { * 多选框的值 */ value?: string | number | boolean; + /** + * 是否无边框 + * @default false + */ + borderless?: boolean; /** * 值变化时触发 */