Skip to content

Commit

Permalink
feat(typography): typography finished
Browse files Browse the repository at this point in the history
  • Loading branch information
insekkei committed Mar 29, 2024
1 parent a5680f4 commit fe7cba6
Show file tree
Hide file tree
Showing 26 changed files with 1,480 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"cSpell.words": ["activable", "actived", "borderless", "Cascader", "Popconfirm", "Swiper", "tdesign"]
}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,18 @@
"@types/tinycolor2": "^1.4.3",
"@types/validator": "^13.1.3",
"classnames": "~2.3.1",
"copy-to-clipboard": "^3.3.3",
"dayjs": "~1.11.4",
"hoist-non-react-statics": "~3.3.2",
"install": "^0.13.0",
"lodash": "~4.17.15",
"mitt": "^3.0.0",
"npm": "^10.5.0",
"raf": "~3.4.1",
"react-is": "^18.2.0",
"react-lines-ellipsis": "^0.15.4",
"react-popper": "~2.3.0",
"react-show-more-text": "^1.7.1",
"react-transition-group": "~4.4.1",
"sortablejs": "^1.15.0",
"tdesign-icons-react": "^0.3.0",
Expand Down
8 changes: 8 additions & 0 deletions site/site.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,14 @@ export const docs = [
component: () => import('tdesign-react/tooltip/tooltip.md'),
componentEn: () => import('tdesign-react/tooltip/tooltip.en-US.md'),
},
{
title: 'Typography 排版',
titleEn: 'Typography',
name: 'typography',
path: '/react/components/typography',
component: () => import('tdesign-react/typography/typography.md'),
componentEn: () => import('tdesign-react/typography/typography.en-US.md'),
},
{
title: 'Tree 树',
titleEn: 'Tree',
Expand Down
2 changes: 1 addition & 1 deletion src/_common
Submodule _common updated 36 files
+22 −0 docs/mobile/api_v2/guide.md
+7 −0 docs/mobile/overview.en-US.md
+7 −0 docs/mobile/overview.md
+1 −1 docs/web/api/date-picker.md
+5 −1 docs/web/api/descriptions.en-US.md
+5 −1 docs/web/api/descriptions.md
+6 −0 docs/web/api/tag.en-US.md
+6 −0 docs/web/api/tag.md
+27 −0 docs/web/api/typography.md
+27 −0 docs/web/api/typogrpahy.en-US.md
+1 −1 docs/web/design/button.md
+3 −3 docs/web/overview.en-US.md
+3 −3 docs/web/overview.md
+9 −0 js/date-picker/utils.ts
+2 −0 js/global-config/default-config.ts
+7 −0 js/global-config/locale/ar_KW.ts
+17 −10 js/global-config/locale/en_US.ts
+7 −0 js/global-config/locale/it_IT.ts
+7 −0 js/global-config/locale/ja_JP.ts
+7 −0 js/global-config/locale/ko_KR.ts
+7 −0 js/global-config/locale/ru_RU.ts
+7 −0 js/global-config/locale/zh_CN.ts
+7 −0 js/global-config/locale/zh_TW.ts
+3 −1 js/table/tree-store.ts
+151 −0 style/mobile/components/guide/_index.less
+42 −0 style/mobile/components/guide/_var.less
+3 −3 style/mobile/theme/_dark.less
+2 −0 style/web/components/_docs.less
+10 −19 style/web/components/descriptions/_index.less
+11 −0 style/web/components/descriptions/_mixin.less
+27 −7 style/web/components/table/_index.less
+10 −1 style/web/components/tabs/_index.less
+9 −0 style/web/components/tree/_index.less
+15 −0 style/web/components/typography/_docs.less
+118 −0 style/web/components/typography/_index.less
+19 −0 style/web/components/typography/_var.less
6 changes: 3 additions & 3 deletions src/guide/__tests__/__snapshots__/vitest-guide.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ exports[`Guide Component > GuideStep.placement is equal to bottom-left 1`] = `
style="width: 16px; height: 16px; top: -8px; left: -8px;"
/>
<div
class="t-portal-wrapper appear appear-active"
class="t-portal-wrapper appear-done enter-done"
>
<div
class="t-popup t-popup--animation-enter-active t-popup--animation-enter-to"
Expand Down Expand Up @@ -1092,7 +1092,7 @@ exports[`Guide Component > GuideStep.stepOverlayClass is equal to t-test-guide-s
style="width: 16px; height: 16px; top: -8px; left: -8px;"
/>
<div
class="t-portal-wrapper appear appear-active"
class="t-portal-wrapper appear-done enter-done"
>
<div
class="t-popup t-test-guide-step-overlay t-popup--animation-enter-active t-popup--animation-enter-to"
Expand Down Expand Up @@ -1263,7 +1263,7 @@ exports[`Guide Component > GuideStep.title works fine 1`] = `
style="width: 16px; height: 16px; top: -8px; left: -8px;"
/>
<div
class="t-portal-wrapper appear appear-active"
class="t-portal-wrapper appear-done enter-done"
>
<div
class="t-popup t-popup--animation-enter-active t-popup--animation-enter-to"
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ export * from './guide';
export * from './back-top';
export * from './statistic';
export * from './descriptions';
export * from './typography';
99 changes: 99 additions & 0 deletions src/typography/Ellipsis.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React, { ReactNode, useEffect, useRef, useState } from 'react';

import classNames from 'classnames';
import Truncate from './Truncate';
import useConfig from '../hooks/useConfig';

type TdEllipsis = {
className?: string;
children: ReactNode;
lines: number;
ellipsisClassName: string;
ellipsisPrefix: ReactNode;
onToggleExpand?: (isExpanded: boolean, e: Event) => void;
width: number;
onTruncate?: (truncated: boolean) => void;
component: string;
collapsible: boolean;
expandable: boolean;
more: ReactNode;
less: ReactNode;
};

const Ellipsis = ({
className,
children,
lines = 1,
ellipsisClassName,
ellipsisPrefix = '...',
onToggleExpand,
width = 0,
onTruncate,
component: Component = 'div',
collapsible = false,
expandable = false,
more,
less,
...rest
}: TdEllipsis) => {
const { classPrefix } = useConfig();
const symbolClassName = ellipsisClassName || `${classPrefix}-typography-ellipsis-symbol`;

const isMountRef = useRef(false);
useEffect(() => {
isMountRef.current = true;
}, []);

const [isExpanded, setIsExpanded] = useState(false);
const handleToggleExpand = (e) => {
if (!expandable) return;

if (isMountRef.current) {
setIsExpanded(!isExpanded);
onToggleExpand?.(!isExpanded, e);
}
};

const truncateRef = useRef();
const [isTruncated, setTruncated] = useState(false);
const handleTruncate = (truncated) => {
if (isMountRef.current && truncated !== isTruncated) {
setTruncated(truncated);

if (truncated) {
truncateRef.current?.onResize();
}
onTruncate?.(truncated);
}
};

return (
<Component className={className} {...rest}>
<Truncate
width={width}
lines={!isExpanded && lines}
className={`${classPrefix}-typography-ellipsis`}
ellipsis={
<span className={`${classPrefix}-typography-ellipsis-symbol-wrapper`}>
{ellipsisPrefix}
<span className={symbolClassName} onClick={handleToggleExpand}>
{more}
</span>
</span>
}
onTruncate={handleTruncate}
ref={truncateRef}
lineClassName={`${classPrefix}-typography-ellipsis-line`}
>
{children}
</Truncate>
{!isTruncated && collapsible && isExpanded && (
<span className={classNames(symbolClassName, `${symbolClassName}--expanded`)} onClick={handleToggleExpand}>
{less}
</span>
)}
</Component>
);
};

export default Ellipsis;
38 changes: 38 additions & 0 deletions src/typography/Paragraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { forwardRef } from 'react';
import classNames from 'classnames';
import Ellipsis from './Ellipsis';
import { TdParagraphProps } from './type';
import { paragraphDefaultProps } from './defaultProps';
import useConfig from '../hooks/useConfig';
import useEllipsis from './useEllipsis';

export type TypographyParagraphProps = TdParagraphProps;

const ParagraphFunction = (props: TypographyParagraphProps, ref: React.Ref<HTMLDivElement>) => {
const { classPrefix } = useConfig();
const { ellipsis, children, className, ...rest } = props;
const prefixCls = `${classPrefix}-typography`;

const { ellipsisProps } = useEllipsis(ellipsis);

if (!ellipsis) {
return (
<div className={classNames(className, prefixCls)} ref={ref} {...rest}>
{children}
</div>
);
}

return (
<Ellipsis {...ellipsisProps} className={classNames(className, prefixCls)} ref={ref} {...rest}>
{children}
</Ellipsis>
);
};

export const Paragraph = forwardRef(ParagraphFunction);

Paragraph.displayName = 'Paragraph';
Paragraph.defaultProps = paragraphDefaultProps;

export default Paragraph;
166 changes: 166 additions & 0 deletions src/typography/Text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import React, { forwardRef, useRef, useState } from 'react';
import classNames from 'classnames';
import { CheckIcon, CopyIcon } from 'tdesign-icons-react';
import copy from 'copy-to-clipboard';

import Ellipsis from './Ellipsis';
import { TdTextProps } from './type';
import { titleDefaultProps } from './defaultProps';
import useConfig from '../hooks/useConfig';
import useEllipsis from './useEllipsis';
import Button from '../button/Button';
import Tooltip from '../tooltip';
import { useLocaleReceiver } from '../locale/LocalReceiver';

export type TypographyTextProps = TdTextProps;

const TextFunction = (props: TypographyTextProps, ref: React.Ref<HTMLSpanElement>) => {
const { classPrefix } = useConfig();
const prefixCls = `${classPrefix}-typography`;

const [local, t] = useLocaleReceiver('typography');
const copiedText = t(local.copied);

const {
theme,
disabled,
className,
copyable,
strong,
mark,
code,
keyboard,
underline,
delete: deleteProp,
italic,
children,
ellipsis,
...rest
} = props;
const getComponent = () => {
const componentMap = {
strong: !!strong,
mark: !!mark,
code: !!code,
kbd: !!keyboard,
u: !!underline,
del: !!deleteProp,
i: !!italic,
};
return Object.entries(componentMap).find(([, condition]) => !!condition)?.[0];
};

const currentRef = useRef();
const { ellipsisProps } = useEllipsis(ellipsis);
const Component = getComponent();

const textEllipsisProps = {
...ellipsisProps,
};

const [isCopied, setIsCopied] = useState(false);

const copyProps =
typeof copyable === 'boolean'
? {
text: children.toString(),
onCopy: Function.prototype,
tooltipProps: isCopied
? {
content: copiedText,
}
: null,
}
: {
text: copyable?.text || children.toString(),
onCopy: copyable?.onCopy?.(),
tooltipProps: {
...copyable?.tooltipProps,
content: isCopied ? copiedText : copyable?.tooltipProps?.content,
},
suffix: copyable?.suffix,
};

const handleCopy = () => {
copy(copyProps?.text);
setIsCopied(true);
setTimeout(() => {
setIsCopied(false);
}, 1500);
copyProps.onCopy?.();
};

const renderContent = (withChildren: boolean) => {
const { tooltipProps } = copyProps;
const wrapWithTooltip = (wrapContent) =>
tooltipProps ? <Tooltip {...tooltipProps}>{wrapContent}</Tooltip> : wrapContent;

const getSuffix = () => {
if (typeof copyProps?.suffix === 'function') {
return copyProps.suffix({ copied: isCopied });
}
return isCopied ? <CheckIcon /> : <CopyIcon />;
};

return (
<>
{withChildren ? children : null}
{copyable
? wrapWithTooltip(
<Button shape="circle" theme="primary" variant="text" icon={getSuffix()} onClick={handleCopy} />,
)
: null}
</>
);
};

if (!ellipsis) {
return Component ? (
<span className={classNames(className, prefixCls)} ref={ref || currentRef} {...rest}>
<Component>{renderContent(true)}</Component>
</span>
) : (
<span
className={classNames(className, {
[`${prefixCls}--${theme}`]: theme,
[`${prefixCls}--disabled`]: disabled,
})}
{...rest}
>
{renderContent(true)}
</span>
);
}

return (
<>
{Component ? (
<span className={classNames(className, prefixCls)} ref={ref || currentRef} {...rest}>
<Ellipsis {...textEllipsisProps} component={Component}>
{children}
</Ellipsis>
</span>
) : (
<Ellipsis
{...textEllipsisProps}
className={classNames(className, {
[`${prefixCls}--${theme}`]: theme,
[`${prefixCls}--disabled`]: disabled,
})}
text={children}
{...rest}
>
{children}
</Ellipsis>
)}
{renderContent(false)}
</>
);
};

export const Text = forwardRef(TextFunction);

Text.displayName = 'Text';
Text.defaultProps = titleDefaultProps;

export default Text;
Loading

0 comments on commit fe7cba6

Please sign in to comment.