Skip to content

Commit

Permalink
feat(tag): 示例代码文件改为tsx,props使用默认值
Browse files Browse the repository at this point in the history
  • Loading branch information
raylotan committed Aug 9, 2024
1 parent 8dd010e commit 7d233ea
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 106 deletions.
2 changes: 1 addition & 1 deletion site/mobile/mobile.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export default {
{
title: 'Tag 标签',
name: 'tag',
component: () => import('tdesign-mobile-react/tag/_example/index.jsx'),
component: () => import('tdesign-mobile-react/tag/_example/index.tsx'),
},
{
title: 'Toast 轻提示',
Expand Down
39 changes: 39 additions & 0 deletions src/_util/parseTNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import isFunction from 'lodash/isFunction';
import React, { ReactElement, ReactNode } from 'react';
import log from '../_common/js/log';
import { TNode } from '../common';

// 解析 TNode 数据结构
export default function parseTNode(
renderNode: TNode | TNode<any> | undefined,
renderParams?: any,
defaultNode?: ReactNode,
): ReactNode {
let node: ReactNode = null;

if (typeof renderNode === 'function') {
node = renderNode(renderParams);
} else if (renderNode === true) {
node = defaultNode;
} else if (renderNode !== null) {
node = renderNode ?? defaultNode;
}
return node as ReactNode;
}

/**
* 解析各种数据类型的 TNode
* 函数类型:content={(props) => <Icon></Icon>}
* 组件类型:content={<Button>click me</Button>} 这种方式可以避免函数重复渲染,对应的 props 已经注入
* 字符类型
*/
export function parseContentTNode<T>(tnode: TNode<T>, props: T) {
if (isFunction(tnode)) return tnode(props) as ReactNode;
if (!tnode || ['string', 'number', 'boolean'].includes(typeof tnode)) return tnode as ReactNode;
try {
return React.cloneElement(tnode as ReactElement, { ...props });
} catch (e) {
log.warn('parseContentTNode', `${tnode} is not a valid ReactNode`);
return null;
}
}
62 changes: 33 additions & 29 deletions src/tag/CheckTag.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
import classNames from 'classnames';
import React, { forwardRef, Ref, type MouseEvent } from 'react';
import React, {
forwardRef,
memo
} from 'react';
import { Icon } from 'tdesign-icons-react';
import noop from '../_util/noop';
import { StyledProps } from 'tdesign-mobile-react/common';
import useConfig from '../_util/useConfig';
import useDefault, { ChangeHandler } from '../_util/useDefault';
import useDefault from '../_util/useDefault';
import useDefaultProps from '../hooks/useDefaultProps';
import { checkTagDefaultProps } from "./defaultProps";
import { TdCheckTagProps } from './type';

export interface TagCheckProps extends TdCheckTagProps {
className?: string;
style?: object;
}
export interface TagCheckProps extends TdCheckTagProps, StyledProps { }

const TagCheck: React.FC<TagCheckProps> = React.memo(
forwardRef((props, ref: Ref<HTMLButtonElement>) => {

const TagCheck: React.FC<TagCheckProps> = memo(
forwardRef<HTMLSpanElement, TagCheckProps>((originProps, ref) => {
const props = useDefaultProps(originProps, checkTagDefaultProps)
const {
checked = undefined,
defaultChecked = undefined,
content = '',
checked,
defaultChecked,
content,
children,
style = {},
className = '',
icon = '',
disabled = false,
closable = false,
size = 'medium',
shape = 'square',
variant = 'dark',
onClick = noop,
onChange = noop,
onClose = noop,
...other
style,
className,
icon,
disabled,
closable,
size,
shape,
variant,
onClick,
onChange,
onClose,
...otherProps
} = props;

const { classPrefix } = useConfig();

const [innerChecked, onInnerChecked] = useDefault(checked, defaultChecked, onChange as ChangeHandler<any, any>);
const [innerChecked, onInnerChecked] = useDefault(checked, defaultChecked, onChange);

const baseClass = `${classPrefix}-tag`;

Expand Down Expand Up @@ -65,15 +69,15 @@ const TagCheck: React.FC<TagCheckProps> = React.memo(
...style,
};

const handleClick = (e: MouseEvent) => {
const handleClick = (e) => {
if (!props.disabled) {
onClick?.({ e });
onClick?.(e);
onInnerChecked(!innerChecked);
}
};


const handleClose = (e: MouseEvent): void => {
const handleClose = (e) => {
e.stopPropagation();
if (!props.disabled) {
onClose?.({ e });
Expand All @@ -88,7 +92,7 @@ const TagCheck: React.FC<TagCheckProps> = React.memo(
role="button"
onClick={handleClick}
style={tagStyle}
{...other}
{...otherProps}
>
{icon && <span className={`${baseClass}__icon`}>{icon}</span>}
<span className={`${baseClass}__text`}>{renderText() || children}</span>
Expand Down
154 changes: 79 additions & 75 deletions src/tag/Tag.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,92 @@
import classNames from 'classnames';
import React, { forwardRef, type MouseEvent } from 'react';
import React, { forwardRef, memo } from 'react';
import { Icon } from 'tdesign-icons-react';
import noop from '../_util/noop';
import parseTNode from 'tdesign-mobile-react/_util/parseTNode';
import { StyledProps } from 'tdesign-mobile-react/common';
import useDefaultProps from 'tdesign-mobile-react/hooks/useDefaultProps';
import useConfig from '../_util/useConfig';
import { tagDefaultProps } from './defaultProps';
import { TdTagProps } from './type';

export interface TagProps extends TdTagProps {
className: string;
style: object;
}
export interface TagProps extends TdTagProps, StyledProps { }

const Tag = forwardRef<HTMLDivElement, TagProps>((props, ref) => {
const {
className = '',
style = {},
closable = false,
content = null,
disabled = false,
icon = undefined,
maxWidth,
children = '',
shape = 'square',
size = 'medium',
theme = 'default',
variant = 'dark',
onClick = noop,
onClose = noop,
...other
} = props;
const Tag: React.FC<TagProps> = memo(
forwardRef<HTMLDivElement, TagProps>((originProps, ref) => {
const props = useDefaultProps(originProps, tagDefaultProps)
const {
className,
style,
closable,
content,
disabled,
icon,
maxWidth,
children,
shape,
size,
theme,
variant,
onClick,
onClose,
...otherProps
} = props;

const { classPrefix } = useConfig();
const baseClass = `${classPrefix}-tag`;
const { classPrefix } = useConfig();
const baseClass = `${classPrefix}-tag`;

const tagClassNames = classNames(
`${baseClass}`,
`${baseClass}--${theme}`,
`${baseClass}--${shape}`,
`${baseClass}--${variant}`,
`${baseClass}--${size}`,
{
[`${classPrefix}-is-closable ${baseClass}--closable`]: closable,
[`${classPrefix}-is-disabled ${baseClass}--disabled`]: disabled,
},
className,
);
const tagClassNames = classNames(
`${baseClass}`,
`${baseClass}--${theme}`,
`${baseClass}--${shape}`,
`${baseClass}--${variant}`,
`${baseClass}--${size}`,
{
[`${classPrefix}-is-closable ${baseClass}--closable`]: closable,
[`${classPrefix}-is-disabled ${baseClass}--disabled`]: disabled,
},
className,
);

const tagStyle = {
...style,
maxWidth: typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth,
};
const tagStyle = {
...style,
maxWidth: typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth,
};

const handleClose = (e: MouseEvent): void => {
e.stopPropagation();
if (!props.disabled) {
onClose?.({ e });
}
};
const handleClose = (e) => {
e.stopPropagation();
if (!props.disabled) {
onClose?.({ e });
}
};

const handleClick = (e: MouseEvent) => {
if (disabled) {
return;
}
onClick?.({ e });
};
const handleClick = (e) => {
if (disabled) {
return;
}
onClick?.({ e });
};

return (
<span
className={tagClassNames}
style={tagStyle}
aria-disabled={props.disabled}
role="button"
onClick={handleClick}
ref={ref}
{...other}
>
{icon && <span className={`${baseClass}__icon`}>{icon}</span>}
<span className={`${baseClass}__text`}>{content || children}</span>
{props.closable && (
<span className={`${baseClass}__icon-close`} onClick={handleClose}>
<Icon name="close" />
</span>
)}
</span>
)
});
const ChildNode = parseTNode(content) || parseTNode(children);

export default React.memo(Tag);
return (
<span
className={tagClassNames}
style={tagStyle}
aria-disabled={props.disabled}
role="button"
onClick={handleClick}
ref={ref}
{...otherProps}
>
{icon && <span className={`${baseClass}__icon`}>{icon}</span>}
<span className={`${baseClass}__text`}>{ChildNode}</span>
{props.closable && (
<span className={`${baseClass}__icon-close`} onClick={handleClose}>
<Icon name="close" />
</span>
)}
</span>
)
}));

export default Tag;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/tag/_example/type.jsx → src/tag/_example/type.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Icon } from 'tdesign-icons-react';
import { Tag } from 'tdesign-mobile-react';
import { Tag } from "tdesign-mobile-react";

const TypeDemo = () => (
<>
Expand Down
23 changes: 23 additions & 0 deletions src/tag/defaultProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
* */

import { TdCheckTagProps, TdTagProps } from './type';

export const tagDefaultProps: TdTagProps = {
closable: false,
disabled: false,
icon: undefined,
shape: 'square',
size: 'medium',
theme: 'default',
variant: 'dark',
};

export const checkTagDefaultProps: TdCheckTagProps = {
closable: false,
disabled: false,
shape: 'square',
size: 'medium',
variant: 'dark',
};

0 comments on commit 7d233ea

Please sign in to comment.