Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor cell #432

Merged
merged 7 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion site/mobile/mobile.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export default {
{
title: 'Cell 单元格',
name: 'cell',
component: () => import('tdesign-mobile-react/cell/_example/base.jsx'),
component: () => import('tdesign-mobile-react/cell/_example/base.tsx'),
},
{
title: 'Upload 上传',
Expand Down
12 changes: 0 additions & 12 deletions src/cell-group/cell-group.md

This file was deleted.

9 changes: 0 additions & 9 deletions src/cell-group/index.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/cell-group/style/css.js

This file was deleted.

2 changes: 0 additions & 2 deletions src/cell-group/style/index.js

This file was deleted.

17 changes: 0 additions & 17 deletions src/cell-group/type.ts

This file was deleted.

100 changes: 55 additions & 45 deletions src/cell/Cell.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useMemo, useCallback } from 'react';
import classNames from 'classnames';
import classnames from 'classnames';
import isString from 'lodash/isString';
import { ChevronRightIcon } from 'tdesign-icons-react';

import { TdCellProps } from './type';
import { cellDefaultProps } from './defaultProps';
import withNativeProps, { NativeProps } from '../_util/withNativeProps';
import useHover from '../hooks/useHover';
import useConfig from '../_util/useConfig';

export interface CellProps extends TdCellProps, NativeProps {}
Expand All @@ -23,7 +24,6 @@ const Cell: React.FC<CellProps> = (props) => {
required,
rightIcon,
title,
url,
onClick,
children,
} = props;
Expand All @@ -32,20 +32,19 @@ const Cell: React.FC<CellProps> = (props) => {

const name = `${classPrefix}-cell`;

const renderIcon = useMemo(() => {
let content: React.ReactNode | null = null;
if (arrow) {
content = <ChevronRightIcon size={24} />;
} else if (rightIcon) {
content = rightIcon;
}

if (content === null) {
return content;
}
const classNames = useMemo(
() => [
`${name}`,
`${name}--${align}`,
{
[`${name}--borderless`]: !bordered,
},
],
[align, bordered, name],
);

return <div className={`${name}__right-icon`}>{content}</div>;
}, [arrow, rightIcon, name]);
const hoverDisabled = useMemo(() => !hover, [hover]);
const ref = useHover({ className: `${name}--hover`, disabled: hoverDisabled });

const handleClick = useCallback(
(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
Expand All @@ -54,41 +53,52 @@ const Cell: React.FC<CellProps> = (props) => {
[onClick],
);

const content = (
<div
className={classNames([`${name}`, `${name}--${align}`], {
[`${name}--bordered`]: bordered,
[`${name}--hover`]: hover,
})}
onClick={handleClick}
>
{(leftIcon || image) && (
<div className={`${name}__left-icon`}>
{leftIcon}
{isString(image) ? <img src={image} className={`${name}__image`} /> : image}
</div>
)}
{title && (
<div className={`${name}__title`}>
{title}
{required && <span className={`${name}--required`}>&nbsp;*</span>}
{description && <div className={`${name}__description`}>{description}</div>}
</div>
)}
{(note || children) && <div className={`${name}__note`}>{children ? children : note}</div>}
{renderIcon}
const readerImage = () => {
if (isString(image)) {
return <img src={image} className={`${name}__left-image`} />;
}
return image;
};

const readerLeft = () => (
<div className={`${name}__left`}>
{leftIcon && <div className={`${name}__left-icon`}>{leftIcon}</div>}
{readerImage()}
</div>
);

const readerTitle = () => {
if (!title) {
return null;
}
return (
<div className={`${name}__title`}>
{title}
{required && <span className={`${name}--required`}>&nbsp;*</span>}
{description && <div className={`${name}__description`}>{description}</div>}
</div>
);
};
const readerRight = () => {
const Icon = arrow ? <ChevronRightIcon /> : rightIcon;
if (!Icon) {
return null;
}
return (
<div className={`${name}__right`}>
<div className={`${name}__right-icon`}>{Icon}</div>
</div>
);
};

return withNativeProps(
props,
url ? (
<a style={{ textDecoration: 'none' }} href={url} rel="noreferrer">
{content}
</a>
) : (
content
),
<div ref={ref} className={classnames(classNames)} onClick={handleClick}>
{readerLeft()}
{readerTitle()}
{note ? <div className={`${name}__note`}>{note}</div> : children}
{readerRight()}
</div>,
);
};

Expand Down
25 changes: 16 additions & 9 deletions src/cell-group/CellGroup.tsx → src/cell/CellGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import classNames from 'classnames';
import React, { useMemo } from 'react';
import classnames from 'classnames';
import useConfig from '../_util/useConfig';
import { TdCellGroupProps } from './type';
import withNativeProps, { NativeProps } from '../_util/withNativeProps';
Expand All @@ -12,19 +12,26 @@ const defaultProps = {
};

const CellGroup: React.FC<CellGroupProps> = (props) => {
const { children, bordered, title } = props;
const { children, bordered, title, theme } = props;
const { classPrefix } = useConfig();
const name = `${classPrefix}-cell-group`;

const classNames = useMemo(
() => [
name,
`${name}--${theme}`,
{
[`${name}--bordered`]: bordered,
},
],
[name, bordered, theme],
);

return withNativeProps(
props,
<div
className={classNames(`${name}`, `${name}__container`, {
'border--top-bottom': bordered,
})}
>
<div>
{title && <div className={`${name}__title`}>{title}</div>}
<div className={`${name}-body`}>{children}</div>
<div className={classnames(classNames)}>{children}</div>
</div>,
);
};
Expand Down
46 changes: 46 additions & 0 deletions src/cell/__tests__/cell.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, it, expect, vi, render, fireEvent, screen } from '@test/utils';
import React from 'react';
import Cell from '../Cell';

describe('Cell', () => {
it('renders the correct content', () => {
const { getByText } = render(
<Cell title="Test Title" description="Test Description">
Test Children
</Cell>,
);

expect(getByText('Test Title')).toBeInTheDocument();
expect(getByText('Test Description')).toBeInTheDocument();
expect(getByText('Test Children')).toBeInTheDocument();
});

it('renders left icon and image if provided', () => {
const { getByTestId } = render(
<Cell
leftIcon={<div data-testid="left-icon">Left Icon</div>}
image="https://tdesign.gtimg.com/mobile/demos/avatar1.png"
>
Test Children
</Cell>,
);

expect(getByTestId('left-icon')).toBeInTheDocument();
expect(screen.getByText('Test Children')).toBeInTheDocument();
});

it('renders right icon if provided', () => {
const { getByTestId } = render(<Cell rightIcon={<div data-testid="right-icon">Right Icon</div>} />);

expect(getByTestId('right-icon')).toBeInTheDocument();
});

it('calls onClick when the cell is clicked', () => {
const handleClick = vi.fn();
const { container } = render(<Cell onClick={handleClick} />);

fireEvent.click(container.firstChild);

expect(handleClick).toHaveBeenCalledTimes(1);
});
});
6 changes: 5 additions & 1 deletion src/cell/_example/base.jsx → src/cell/_example/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import './style/index.less';

import Single from './single';
import Multiple from './multiple';
import Group from './group';

export default function Base() {
return (
Expand All @@ -16,9 +17,12 @@ export default function Base() {
<TDemoBlock title="01 类型" summary="单行单元格">
<Single />
</TDemoBlock>
<TDemoBlock title="" summary="多行单元格">
<TDemoBlock title="02" summary="多行单元格">
<Multiple />
</TDemoBlock>
<TDemoBlock title="03 组件样式" summary="卡片单元格">
<Group />
</TDemoBlock>
</div>
);
}
13 changes: 13 additions & 0 deletions src/cell/_example/group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { CellGroup, Cell } from 'tdesign-mobile-react';
import { LockOnIcon, ServiceIcon, InternetIcon } from 'tdesign-icons-react';

export default function Group() {
return (
<CellGroup theme="card">
<Cell leftIcon={<LockOnIcon />} title="单行标题" arrow />
<Cell leftIcon={<ServiceIcon />} title="单行标题" arrow />
<Cell leftIcon={<InternetIcon />} title="单行标题" arrow />
</CellGroup>
);
}
34 changes: 0 additions & 34 deletions src/cell/_example/multiple.jsx

This file was deleted.

32 changes: 32 additions & 0 deletions src/cell/_example/multiple.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { CellGroup, Cell, Badge, Switch, Avatar } from 'tdesign-mobile-react';
import { ChevronRightIcon, LockOnIcon } from 'tdesign-icons-react';

export default function Multiple() {
const chevronRightIcon = <ChevronRightIcon />;
const avatarUrl = 'https://tdesign.gtimg.com/mobile/demos/avatar1.png';
const imgUrl = 'https://tdesign.gtimg.com/mobile/demos/example4.png';

return (
<CellGroup>
<Cell title="单行标题" description="一段很长很长的内容文字" arrow />
<Cell title="单行标题" description="一段很长很长的内容文字" arrow required />
<Cell title="单行标题" description="一段很长很长的内容文字" arrow note={<Badge count={16} />} />
<Cell title="单行标题" description="一段很长很长的内容文字" note={<Switch defaultValue={true} />} />
<Cell title="单行标题" description="一段很长很长的内容文字" note="辅助信息" arrow />
<Cell title="单行标题" description="一段很长很长的内容文字" arrow leftIcon={<LockOnIcon />} />
<Cell title="单行标题" description="一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容" />
<Cell
title="多行高度不定,长文本自动换行,该选项的描述是一段很长的内容"
description="一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容"
/>
<Cell
title="多行带头像"
description="一段很长很长的内容文字"
leftIcon={<Avatar shape="circle" image={avatarUrl} />}
rightIcon={chevronRightIcon}
/>
<Cell title="多行带图片" description="一段很长很长的内容文字" image={imgUrl} />
</CellGroup>
);
}
Loading
Loading