Skip to content

Commit

Permalink
Merge pull request #839 from oceanbase/dengfuping-dev
Browse files Browse the repository at this point in the history
improve(design): Typography editable and editing style
  • Loading branch information
dengfuping authored Nov 19, 2024
2 parents 1565aa8 + fedc38d commit 4d000fa
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 9 deletions.
12 changes: 10 additions & 2 deletions packages/design/src/typography/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { Typography as AntTypography } from 'antd';
import type { LinkProps as AntLinkProps } from 'antd/es/typography/Link';
import ConfigProvider from '../config-provider';
import useClassName from './hooks/useClassName';
import useStyle from './style';

const { Link: AntLink } = AntTypography;
Expand All @@ -11,13 +12,20 @@ export * from 'antd/es/typography/Link';
export interface LinkProps extends AntLinkProps {}

const Link = React.forwardRef<HTMLElement, LinkProps>(
({ prefixCls: customizePrefixCls, children, ...restProps }, ref) => {
({ editable, prefixCls: customizePrefixCls, className, children, ...restProps }, ref) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('typography', customizePrefixCls);
const { wrapSSR } = useStyle(prefixCls);
const typographyCls = useClassName(prefixCls, className, editable);

return wrapSSR(
<AntLink ref={ref} prefixCls={customizePrefixCls} {...restProps}>
<AntLink
ref={ref}
editable={editable}
prefixCls={customizePrefixCls}
className={typographyCls}
{...restProps}
>
{children}
</AntLink>
);
Expand Down
12 changes: 10 additions & 2 deletions packages/design/src/typography/Paragraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { Typography as AntTypography } from 'antd';
import type { ParagraphProps as AntParagraphProps } from 'antd/es/typography/Paragraph';
import ConfigProvider from '../config-provider';
import useClassName from './hooks/useClassName';
import useStyle from './style';

const { Paragraph: AntParagraph } = AntTypography;
Expand All @@ -11,13 +12,20 @@ export * from 'antd/es/typography/Paragraph';
export interface ParagraphProps extends AntParagraphProps {}

const Paragraph = React.forwardRef<HTMLElement, ParagraphProps>(
({ prefixCls: customizePrefixCls, children, ...restProps }, ref) => {
({ editable, prefixCls: customizePrefixCls, className, children, ...restProps }, ref) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('typography', customizePrefixCls);
const { wrapSSR } = useStyle(prefixCls);
const typographyCls = useClassName(prefixCls, className, editable);

return wrapSSR(
<AntParagraph ref={ref} prefixCls={customizePrefixCls} {...restProps}>
<AntParagraph
ref={ref}
editable={editable}
prefixCls={customizePrefixCls}
className={typographyCls}
{...restProps}
>
{children}
</AntParagraph>
);
Expand Down
12 changes: 10 additions & 2 deletions packages/design/src/typography/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { Typography as AntTypography } from 'antd';
import type { TextProps as AntTextProps } from 'antd/es/typography/Text';
import ConfigProvider from '../config-provider';
import useClassName from './hooks/useClassName';
import useStyle from './style';

const { Text: AntText } = AntTypography;
Expand All @@ -11,13 +12,20 @@ export * from 'antd/es/typography/Text';
export interface TextProps extends AntTextProps {}

const Text = React.forwardRef<HTMLSpanElement, TextProps>(
({ prefixCls: customizePrefixCls, children, ...restProps }, ref) => {
({ editable, prefixCls: customizePrefixCls, className, children, ...restProps }, ref) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('typography', customizePrefixCls);
const { wrapSSR } = useStyle(prefixCls);
const typographyCls = useClassName(prefixCls, className, editable);

return wrapSSR(
<AntText ref={ref} prefixCls={customizePrefixCls} {...restProps}>
<AntText
ref={ref}
editable={editable}
prefixCls={customizePrefixCls}
className={typographyCls}
{...restProps}
>
{children}
</AntText>
);
Expand Down
12 changes: 10 additions & 2 deletions packages/design/src/typography/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { Typography as AntTypography } from 'antd';
import type { TitleProps as AntTitleProps } from 'antd/es/typography/Title';
import ConfigProvider from '../config-provider';
import useClassName from './hooks/useClassName';
import useStyle from './style';

const { Title: AntTitle } = AntTypography;
Expand All @@ -11,13 +12,20 @@ export * from 'antd/es/typography/Title';
export interface TitleProps extends AntTitleProps {}

const Title = React.forwardRef<HTMLElement, TitleProps>(
({ prefixCls: customizePrefixCls, children, ...restProps }, ref) => {
({ editable, prefixCls: customizePrefixCls, className, children, ...restProps }, ref) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('typography', customizePrefixCls);
const { wrapSSR } = useStyle(prefixCls);
const typographyCls = useClassName(prefixCls, className, editable);

return wrapSSR(
<AntTitle ref={ref} prefixCls={customizePrefixCls} {...restProps}>
<AntTitle
ref={ref}
editable={editable}
prefixCls={customizePrefixCls}
className={typographyCls}
{...restProps}
>
{children}
</AntTitle>
);
Expand Down
155 changes: 155 additions & 0 deletions packages/design/src/typography/demo/editable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, { useMemo, useState } from 'react';
import { CheckOutlined, HighlightOutlined } from '@oceanbase/icons';
import { Radio, Typography } from '@oceanbase/design';

const { Paragraph } = Typography;

const App: React.FC = () => {
const [editableStr, setEditableStr] = useState('This is an editable text.');
const [editableStrWithSuffix, setEditableStrWithSuffix] = useState(
'This is a loooooooooooooooooooooooooooooooong editable text with suffix.'
);
const [editableStrWithSuffixStartPart, editableStrWithSuffixSuffixPart] = useMemo(
() => [editableStrWithSuffix.slice(0, -12), editableStrWithSuffix.slice(-12)],
[editableStrWithSuffix]
);
const [customIconStr, setCustomIconStr] = useState('Custom Edit icon and replace tooltip text.');
const [clickTriggerStr, setClickTriggerStr] = useState(
'Text or icon as trigger - click to start editing.'
);
const [chooseTrigger, setChooseTrigger] = useState<('icon' | 'text')[]>(['icon']);
const [customEnterIconStr, setCustomEnterIconStr] = useState(
'Editable text with a custom enter icon in edit field.'
);
const [noEnterIconStr, setNoEnterIconStr] = useState(
'Editable text with no enter icon in edit field.'
);
const [hideTooltipStr, setHideTooltipStr] = useState('Hide Edit tooltip.');
const [lengthLimitedStr, setLengthLimitedStr] = useState(
'This is an editable text with limited length.'
);

const radioToState = (input: string): ('icon' | 'text')[] => {
switch (input) {
case 'text':
return ['text'];
case 'both':
return ['icon', 'text'];
case 'icon':
return ['icon'];
default:
return ['icon'];
}
};

const stateToRadio = useMemo<string>(() => {
if (chooseTrigger.includes('text')) {
return chooseTrigger.includes('icon') ? 'both' : 'text';
}
return 'icon';
}, [chooseTrigger]);

return (
<>
<div style={{ marginBottom: 12 }}>
Trigger edit with:{' '}
<Radio.Group
onChange={e => setChooseTrigger(radioToState(e.target.value))}
value={stateToRadio}
>
<Radio value="icon">icon</Radio>
<Radio value="text">text</Radio>
<Radio value="both">both</Radio>
</Radio.Group>
</div>
<Paragraph editable={{ onChange: setEditableStr, triggerType: chooseTrigger }}>
{editableStr}
</Paragraph>
<Paragraph
editable={{
onChange: setEditableStrWithSuffix,
text: editableStrWithSuffix,
triggerType: chooseTrigger,
}}
ellipsis={{
suffix: editableStrWithSuffixSuffixPart,
}}
>
{editableStrWithSuffixStartPart}
</Paragraph>
<Paragraph
editable={{
icon: <HighlightOutlined />,
tooltip: 'click to edit text',
onChange: setCustomIconStr,
triggerType: chooseTrigger,
}}
>
{customIconStr}
</Paragraph>
<Paragraph
editable={{
tooltip: 'click to edit text',
onChange: setClickTriggerStr,
triggerType: chooseTrigger,
}}
>
{clickTriggerStr}
</Paragraph>
<Paragraph
editable={{
icon: <HighlightOutlined />,
tooltip: 'click to edit text',
onChange: setCustomEnterIconStr,
triggerType: chooseTrigger,
enterIcon: <CheckOutlined />,
}}
>
{customEnterIconStr}
</Paragraph>
<Paragraph
editable={{
icon: <HighlightOutlined />,
tooltip: 'click to edit text',
onChange: setNoEnterIconStr,
triggerType: chooseTrigger,
enterIcon: null,
}}
>
{noEnterIconStr}
</Paragraph>
<Paragraph
editable={{ tooltip: false, onChange: setHideTooltipStr, triggerType: chooseTrigger }}
>
{hideTooltipStr}
</Paragraph>
<Paragraph
editable={{
onChange: setLengthLimitedStr,
triggerType: chooseTrigger,
maxLength: 50,
autoSize: { maxRows: 5, minRows: 3 },
}}
>
{lengthLimitedStr}
</Paragraph>
<Typography.Title editable={{ triggerType: chooseTrigger }} level={1} style={{ margin: 0 }}>
h1. Ant Design
</Typography.Title>
<Typography.Title editable={{ triggerType: chooseTrigger }} level={2} style={{ margin: 0 }}>
h2. Ant Design
</Typography.Title>
<Typography.Title editable={{ triggerType: chooseTrigger }} level={3} style={{ margin: 0 }}>
h3. Ant Design
</Typography.Title>
<Typography.Title editable={{ triggerType: chooseTrigger }} level={4} style={{ margin: 0 }}>
h4. Ant Design
</Typography.Title>
<Typography.Title editable={{ triggerType: chooseTrigger }} level={5} style={{ margin: 0 }}>
h5. Ant Design
</Typography.Title>
</>
);
};

export default App;
17 changes: 17 additions & 0 deletions packages/design/src/typography/hooks/useClassName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import type { BlockProps } from 'antd/es/typography/Base';
import classNames from 'classnames';

const useClassName = (prefixCls: string, className: string, editable?: BlockProps['editable']) => {
const typographyCls = classNames(
prefixCls,
{
[`${prefixCls}-editable-text`]:
typeof editable === 'object' && editable?.triggerType?.includes('text'),
},
className
);
return typographyCls;
};

export default useClassName;
2 changes: 2 additions & 0 deletions packages/design/src/typography/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ nav:

<code src="./demo/text.tsx" title="文本与超链接"></code>

<code src="./demo/editable.tsx" title="可编辑"></code>

<code src="./demo/font-family.tsx" title="字体" description="详见 [字体设计规范](/docs/spec/typography)。"></code>

<code src="./demo/inner.tsx" title="和其他组件组合使用" debug></code>
Expand Down
40 changes: 39 additions & 1 deletion packages/design/src/typography/style/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export type TypographyToken = FullToken<'Typography'>;
export const genTypographyStyle: GenerateStyle<TypographyToken> = (
token: TypographyToken
): CSSObject => {
const { componentCls } = token;
const { componentCls, controlHeight, fontSize, lineHeight } = token;
const marginOffset = (controlHeight - fontSize * lineHeight) / 2;

return {
// inherit color and lineHeight from parent instead of fixed colorText
Expand All @@ -21,6 +22,43 @@ export const genTypographyStyle: GenerateStyle<TypographyToken> = (
color: 'inherit',
fontSize: 'inherit',
},
[`${componentCls}`]: {
[`${componentCls}-edit`]: {
fontSize: token.fontSize,
},
},
[`${componentCls}${componentCls}-editable-text:not(${componentCls}-edit-content)`]: {
'&:hover': {
background: token.colorBgContainer,
border: `${token.lineWidth}px ${token.lineType} ${token.colorBorder}`,
borderRadius: token.borderRadius,
position: 'relative',
insetInlineStart: -token.paddingSM,
padding: `${marginOffset - token.lineWidth}px ${token.paddingSM - token.lineWidth}px`,
},
'div&:hover': {
height: token.controlHeight,
marginTop: -marginOffset,
marginBottom: `calc(1em - ${marginOffset}px)`,
},
'h1&:hover, h2&:hover, h3&:hover, h4&:hover, h5&:hover': {
marginTop: `${-marginOffset}px !important`,
marginBottom: `${-marginOffset}px !important`,
},
},
[`${componentCls}${componentCls}-edit-content`]: {
'div&': {
insetInlineStart: -token.paddingSM,
marginTop: -marginOffset,
marginBottom: `calc(1em - ${marginOffset}px)`,
},
[`${componentCls}-h1&, ${componentCls}-h2&, ${componentCls}-h3&, ${componentCls}-h4&, ${componentCls}-h5&`]:
{
insetInlineStart: -token.paddingSM,
marginTop: `${-marginOffset}px !important`,
marginBottom: `${-marginOffset}px !important`,
},
},
};
};

Expand Down

0 comments on commit 4d000fa

Please sign in to comment.