Skip to content
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
67 changes: 67 additions & 0 deletions packages/design/src/_util/document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import { Space, Divider, Tooltip } from 'antd';

export type DocumentType = string | React.MouseEventHandler<HTMLAnchorElement> | React.ReactNode;

export const DocumentIcon = ({ className }: { className?: string }) => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<g clipPath="url(#clip0_61186_2038)">
<path
d="M7.99992 4.66667C7.99992 3.95942 7.71897 3.28115 7.21887 2.78105C6.71877 2.28095 6.0405 2 5.33325 2H1.33325V12H5.99992C6.53035 12 7.03906 12.2107 7.41413 12.5858C7.78921 12.9609 7.99992 13.4696 7.99992 14M7.99992 4.66667V14M7.99992 4.66667C7.99992 3.95942 8.28087 3.28115 8.78097 2.78105C9.28106 2.28095 9.95934 2 10.6666 2H14.6666V12H9.99992C9.46949 12 8.96078 12.2107 8.5857 12.5858C8.21063 12.9609 7.99992 13.4696 7.99992 14"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_61186_2038">
<rect width="16" height="16" fill="white" />
</clipPath>
</defs>
</svg>
);
};

export interface DocumentProps {
document: DocumentType;
prefixCls: string;
viewDocument?: string;
}

export const Document: React.FC<DocumentProps> = ({ document, prefixCls, viewDocument }) => {
if (!document) {
return null;
}

const documentLink = typeof document === 'string' ? document : undefined;
const documentClick = typeof document === 'function' ? document : undefined;

return (
<Space size="small">
<Divider type="vertical" className={`${prefixCls}-document-divider`} />
<Tooltip title={viewDocument}>
<a
href={documentLink}
target="_blank"
rel="noopener noreferrer"
onClick={documentClick}
className={`${prefixCls}-document-icon`}
>
{documentLink || documentClick ? (
<DocumentIcon className={`${prefixCls}-document-default-icon`} />
) : (
(document as React.ReactNode)
)}
</a>
</Tooltip>
</Space>
);
};
2 changes: 2 additions & 0 deletions packages/design/src/_util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ export const isPaddingBottomZero = (padding?: string | number) => {

return false;
};

export { DocumentIcon, Document, type DocumentType } from './document';
74 changes: 13 additions & 61 deletions packages/design/src/card/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isNullValue } from '@oceanbase/util';
import { Card as AntCard, Space, Tag, Divider, Tooltip } from 'antd';
import { Card as AntCard, Space, Tag } from 'antd';
import type {
CardProps as AntCardProps,
CardTabListType as AntCardTabListType,
Expand All @@ -10,7 +10,12 @@ import { CaretRightFilled } from '@oceanbase/icons';
import ConfigProvider from '../config-provider';
import type { ConfigConsumerProps } from '../config-provider';
import defaultLocale from '../locale/en-US';
import { isHorizontalPaddingZero, isPaddingBottomZero } from '../_util';
import {
isHorizontalPaddingZero,
isPaddingBottomZero,
Document,
type DocumentType,
} from '../_util';
import theme from '../theme';
import useStyle, { genTableStyle } from './style';

Expand All @@ -21,13 +26,11 @@ export interface CardTabListType extends AntCardTabListType {
tag?: React.ReactNode;
}

export interface CardLocale {
viewDocument?: string;
}
export type CardLocale = Record<string, never>;

export interface CardProps extends AntCardProps {
subTitle?: React.ReactNode;
document?: string | React.MouseEventHandler<HTMLAnchorElement> | React.ReactNode;
document?: DocumentType;
divided?: boolean;
gray?: boolean;
tabList?: CardTabListType[];
Expand Down Expand Up @@ -83,6 +86,8 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>(
const tabsPrefixCls = getPrefixCls('tabs', customizePrefixCls);
const [wrapCSSVar] = useStyle(prefixCls, tabsPrefixCls);

const viewDocument = contextLocale?.global?.viewDocument;

const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed ?? false);
const collapsed = outerCollapsed !== undefined ? outerCollapsed : internalCollapsed;

Expand All @@ -94,9 +99,6 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>(
onCollapse?.(newCollapsed);
}, [collapsed, outerCollapsed, onCollapse]);

const documentLink = typeof document === 'string' ? document : undefined;
const documentClick = typeof document === 'function' ? document : undefined;

const cardTitle = useMemo(() => {
if (!collapsible && !subTitle && !document) {
return title;
Expand All @@ -111,28 +113,7 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>(
{(subTitle || document) && (
<Space className={`${prefixCls}-sub-title-wrapper`} size="small">
{subTitle && <div className={`${prefixCls}-sub-title`}>{subTitle}</div>}
{document && (
<Space size="small">
{document && (
<Divider type="vertical" className={`${prefixCls}-document-divider`} />
)}
<Tooltip title={cardLocale.viewDocument}>
<a
href={documentLink}
target="_blank"
rel="noopener noreferrer"
onClick={documentClick}
className={`${prefixCls}-document-icon`}
>
{documentLink || documentClick ? (
<DocumentIcon className={`${prefixCls}-document-default-icon`} />
) : (
(document as React.ReactNode)
)}
</a>
</Tooltip>
</Space>
)}
<Document document={document} prefixCls={prefixCls} viewDocument={viewDocument} />
</Space>
)}
</>
Expand Down Expand Up @@ -172,13 +153,11 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>(
title,
subTitle,
document,
documentLink,
documentClick,
collapsed,
prefixCls,
token,
handleCollapse,
cardLocale.viewDocument,
viewDocument,
]);

// card body no horizontal padding
Expand Down Expand Up @@ -246,33 +225,6 @@ if (process.env.NODE_ENV !== 'production') {
Card.displayName = AntCard.displayName;
}

const DocumentIcon = ({ className }: { className?: string }) => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<g clipPath="url(#clip0_61186_2038)">
<path
d="M7.99992 4.66667C7.99992 3.95942 7.71897 3.28115 7.21887 2.78105C6.71877 2.28095 6.0405 2 5.33325 2H1.33325V12H5.99992C6.53035 12 7.03906 12.2107 7.41413 12.5858C7.78921 12.9609 7.99992 13.4696 7.99992 14M7.99992 4.66667V14M7.99992 4.66667C7.99992 3.95942 8.28087 3.28115 8.78097 2.78105C9.28106 2.28095 9.95934 2 10.6666 2H14.6666V12H9.99992C9.46949 12 8.96078 12.2107 8.5857 12.5858C8.21063 12.9609 7.99992 13.4696 7.99992 14"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_61186_2038">
<rect width="16" height="16" fill="white" />
</clipPath>
</defs>
</svg>
);
};

export default Object.assign(Card, {
Grid: AntCard.Grid,
Meta: AntCard.Meta,
Expand Down
84 changes: 84 additions & 0 deletions packages/design/src/drawer/demo/document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { useState } from 'react';
import { Drawer, Button, message } from '@oceanbase/design';
import { BookOutlined } from '@oceanbase/icons';

export default () => {
const [open1, setOpen1] = useState(false);
const [open2, setOpen2] = useState(false);
const [open3, setOpen3] = useState(false);

return (
<>
<Button
type="primary"
onClick={() => {
setOpen1(true);
}}
style={{ marginRight: 8 }}
>
Document with URL
</Button>
<Button
type="primary"
onClick={() => {
setOpen2(true);
}}
style={{ marginRight: 8 }}
>
Document with Function
</Button>
<Button
type="primary"
onClick={() => {
setOpen3(true);
}}
>
Document with Custom Icon
</Button>
<Drawer
title="Drawer Title"
document="https://www.oceanbase.com"
open={open1}
onCancel={() => {
setOpen1(false);
}}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Drawer>
<Drawer
title="Drawer Title"
document={() => {
message.info('Click document');
}}
open={open2}
onCancel={() => {
setOpen2(false);
}}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Drawer>
<Drawer
title="Drawer Title"
document={
<BookOutlined
onClick={() => {
message.info('Click document');
}}
/>
}
open={open3}
onCancel={() => {
setOpen3(false);
}}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Drawer>
</>
);
};
25 changes: 14 additions & 11 deletions packages/design/src/drawer/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ nav:
- 内容区滚动时,动态设置页头和页脚的阴影。
- 当内容高度大于等于抽屉高度时,页脚会置底展示;当内容高度小于抽屉高度时,`footer` 会跟随内容展示。
- 📢 `destroyOnClose` 属性的默认值为 `true`。
- 🆕 新增 `document` 属性,用于在标题旁设置文档链接。
- 🆕 新增 `footer` 属性,用于设置抽屉的底部内容,默认为 `取消` 和 `确定` 按钮。
- 🆕 新增 `footerExtra` 属性,用于设置抽屉底部的额外内容,仅默认页脚生效。
- 🆕 新增 `onOk` 和 `onCancel` 属性,用于设置 `取消` 和 `确定` 按钮的回调。
Expand All @@ -22,6 +23,7 @@ nav:

<!-- prettier-ignore -->
<code src="./demo/basic.tsx" title="基础抽屉" description="默认包含标题、内容。"></code>
<code src="./demo/document.tsx" title="文档链接" description="可通过 `document` 属性在标题旁显示文档链接图标。"></code>
<code src="./demo/footer.tsx" title="开启页脚" description="内容较短时,页脚跟随内容展示;可通过 `onOk` 或 `footer` 开启页脚。"></code>
<code src="./demo/footerExtra.tsx" title="设置默认页脚的额外内容" description="通过 `footerExtra` 设置,仅默认页脚生效。"></code>
<code src="./demo/custom-footer.tsx" title="自定义页脚"></code>
Expand All @@ -33,16 +35,17 @@ nav:

## API

| 参数 | 说明 | 类型 | 默认值 | 版本 |
| :------------- | :--------------------------------- | :------------------- | :----- | :--- |
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | true | - |
| onOk | 点击确定回调,设置时会开启默认页脚 | (e) => void | - | - |
| onCancel | 点击取消按钮的回调 | (e) => void | - | - |
| cancelText | 设置取消按钮文字 | string | 取消 | - |
| okText | 确认按钮文字 | string | 确定 | - |
| okButtonProps | ok 按钮 props | ButtonProps | - | - |
| confirmLoading | 确定按钮 loading | boolean | - | - |
| footer | 抽屉的页脚 | boolean \| ReactNode | - | - |
| footerExtra | 抽屉页脚的额外内容,仅默认页脚生效 | ReactNode | - | - |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| :-- | :-- | :-- | :-- | :-- |
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | true | - |
| document | 文档链接,支持字符串、函数或自定义图标 | string \| React.MouseEventHandler\<HTMLAnchorElement\> \| React.ReactNode | - | - |
| onOk | 点击确定回调,设置时会开启默认页脚 | (e) => void | - | - |
| onCancel | 点击取消按钮的回调 | (e) => void | - | - |
| cancelText | 设置取消按钮文字 | string | 取消 | - |
| okText | 确认按钮文字 | string | 确定 | - |
| okButtonProps | ok 按钮 props | ButtonProps | - | - |
| confirmLoading | 确定按钮 loading | boolean | - | - |
| footer | 抽屉的页脚 | boolean \| ReactNode | - | - |
| footerExtra | 抽屉页脚的额外内容,仅默认页脚生效 | ReactNode | - | - |

- 更多 API 详见 antd Drawer 文档: https://ant.design/components/drawer-cn
Loading