feat: qrcode support render svg (#42570)

* fet: QRCode support type(renderAs)

* fet: QRCode support type(renderAs)

* fet: QRCode support type(renderAs)

* fet: QRCode support type(renderAs)

* fix: Improve type.md,  export QRProps

* Update components/qrcode/demo/type.md

Co-authored-by: lijianan <574980606@qq.com>

* Update components/qrcode/index.tsx

Co-authored-by: lijianan <574980606@qq.com>

* fix: qrCodeProps

* fix: qrcode snap

* Update components/qrcode/demo/type.md

Co-authored-by: lijianan <574980606@qq.com>

* fix: QRCode docs

* fix: QRCode demo

* Update components/qrcode/demo/download.tsx

Co-authored-by: lijianan <574980606@qq.com>

* Update components/qrcode/demo/download.tsx

Co-authored-by: lijianan <574980606@qq.com>

* fix: QRCode snap

* fix: QRCode snap

* fix: 恢复下载示例

---------

Co-authored-by: lijianan <574980606@qq.com>
This commit is contained in:
sy296565890 2023-05-25 13:32:48 +08:00 committed by GitHub
parent e12e87f1f0
commit b534c1ecb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 147 additions and 25 deletions

View File

@ -430,3 +430,50 @@ exports[`renders components/qrcode/demo/status.tsx extend context correctly 1`]
</div>
</div>
`;
exports[`renders components/qrcode/demo/type.tsx extend context correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center"
>
<div
class="ant-space-item"
style="margin-right: 8px;"
>
<div
class="ant-qrcode"
style="width: 160px; height: 160px; background-color: transparent;"
>
<canvas
height="134"
style="height: 134px; width: 134px;"
width="134"
/>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-qrcode"
style="width: 160px; height: 160px; background-color: transparent;"
>
<svg
height="134"
viewBox="0 0 25 25"
width="134"
>
<path
d="M0,0 h25v25H0z"
fill="transparent"
shape-rendering="crispEdges"
/>
<path
d="M0 0h7v1H0zM8 0h2v1H8zM11 0h5v1H11zM18,0 h7v1H18zM0 1h1v1H0zM6 1h1v1H6zM10 1h6v1H10zM18 1h1v1H18zM24,1 h1v1H24zM0 2h1v1H0zM2 2h3v1H2zM6 2h1v1H6zM8 2h1v1H8zM10 2h1v1H10zM12 2h1v1H12zM15 2h1v1H15zM18 2h1v1H18zM20 2h3v1H20zM24,2 h1v1H24zM0 3h1v1H0zM2 3h3v1H2zM6 3h1v1H6zM8 3h2v1H8zM15 3h1v1H15zM18 3h1v1H18zM20 3h3v1H20zM24,3 h1v1H24zM0 4h1v1H0zM2 4h3v1H2zM6 4h1v1H6zM10 4h1v1H10zM12 4h1v1H12zM14 4h3v1H14zM18 4h1v1H18zM20 4h3v1H20zM24,4 h1v1H24zM0 5h1v1H0zM6 5h1v1H6zM8 5h1v1H8zM11 5h1v1H11zM15 5h2v1H15zM18 5h1v1H18zM24,5 h1v1H24zM0 6h7v1H0zM8 6h1v1H8zM10 6h1v1H10zM12 6h1v1H12zM14 6h1v1H14zM16 6h1v1H16zM18,6 h7v1H18zM8 7h1v1H8zM14 7h3v1H14zM1 8h1v1H1zM3 8h1v1H3zM5 8h8v1H5zM15 8h5v1H15zM21 8h2v1H21zM24,8 h1v1H24zM0 9h3v1H0zM7 9h1v1H7zM9 9h2v1H9zM16 9h3v1H16zM24,9 h1v1H24zM4 10h1v1H4zM6 10h2v1H6zM16 10h2v1H16zM20 10h1v1H20zM23,10 h2v1H23zM0 11h1v1H0zM2 11h2v1H2zM8 11h1v1H8zM11 11h2v1H11zM14 11h1v1H14zM18 11h3v1H18zM0 12h2v1H0zM4 12h4v1H4zM10 12h3v1H10zM17 12h2v1H17zM21 12h1v1H21zM23,12 h2v1H23zM1 13h2v1H1zM5 13h1v1H5zM7 13h1v1H7zM9 13h1v1H9zM11 13h1v1H11zM18 13h2v1H18zM21 13h2v1H21zM24,13 h1v1H24zM0 14h1v1H0zM2 14h2v1H2zM6 14h2v1H6zM9 14h1v1H9zM11 14h1v1H11zM18 14h3v1H18zM22 14h1v1H22zM24,14 h1v1H24zM1 15h1v1H1zM3 15h3v1H3zM7 15h1v1H7zM9 15h2v1H9zM13 15h1v1H13zM15 15h3v1H15zM20 15h1v1H20zM23 15h1v1H23zM0 16h3v1H0zM4 16h1v1H4zM6 16h1v1H6zM9 16h1v1H9zM12 16h1v1H12zM14 16h1v1H14zM16 16h7v1H16zM8 17h1v1H8zM10 17h1v1H10zM12 17h5v1H12zM20 17h2v1H20zM24,17 h1v1H24zM0 18h7v1H0zM8 18h3v1H8zM14 18h3v1H14zM18 18h1v1H18zM20 18h2v1H20zM23,18 h2v1H23zM0 19h1v1H0zM6 19h1v1H6zM8 19h2v1H8zM13 19h1v1H13zM16 19h1v1H16zM20 19h3v1H20zM24,19 h1v1H24zM0 20h1v1H0zM2 20h3v1H2zM6 20h1v1H6zM9 20h1v1H9zM11 20h3v1H11zM16 20h6v1H16zM23,20 h2v1H23zM0 21h1v1H0zM2 21h3v1H2zM6 21h1v1H6zM8 21h2v1H8zM11 21h1v1H11zM15 21h1v1H15zM17 21h1v1H17zM19 21h4v1H19zM0 22h1v1H0zM2 22h3v1H2zM6 22h1v1H6zM9 22h5v1H9zM15 22h1v1H15zM19 22h2v1H19zM22 22h1v1H22zM24,22 h1v1H24zM0 23h1v1H0zM6 23h1v1H6zM8 23h1v1H8zM10 23h1v1H10zM13 23h1v1H13zM15 23h4v1H15zM21 23h1v1H21zM0 24h7v1H0zM14 24h3v1H14zM19 24h1v1H19zM23,24 h2v1H23z"
fill="#000"
shape-rendering="crispEdges"
/>
</svg>
</div>
</div>
</div>
`;

View File

@ -395,3 +395,50 @@ exports[`renders components/qrcode/demo/status.tsx correctly 1`] = `
</div>
</div>
`;
exports[`renders components/qrcode/demo/type.tsx correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center"
>
<div
class="ant-space-item"
style="margin-right:8px"
>
<div
class="ant-qrcode"
style="width:160px;height:160px;background-color:transparent"
>
<canvas
height="134"
style="height:134px;width:134px"
width="134"
/>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-qrcode"
style="width:160px;height:160px;background-color:transparent"
>
<svg
height="134"
viewBox="0 0 25 25"
width="134"
>
<path
d="M0,0 h25v25H0z"
fill="transparent"
shape-rendering="crispEdges"
/>
<path
d="M0 0h7v1H0zM8 0h2v1H8zM11 0h5v1H11zM18,0 h7v1H18zM0 1h1v1H0zM6 1h1v1H6zM10 1h6v1H10zM18 1h1v1H18zM24,1 h1v1H24zM0 2h1v1H0zM2 2h3v1H2zM6 2h1v1H6zM8 2h1v1H8zM10 2h1v1H10zM12 2h1v1H12zM15 2h1v1H15zM18 2h1v1H18zM20 2h3v1H20zM24,2 h1v1H24zM0 3h1v1H0zM2 3h3v1H2zM6 3h1v1H6zM8 3h2v1H8zM15 3h1v1H15zM18 3h1v1H18zM20 3h3v1H20zM24,3 h1v1H24zM0 4h1v1H0zM2 4h3v1H2zM6 4h1v1H6zM10 4h1v1H10zM12 4h1v1H12zM14 4h3v1H14zM18 4h1v1H18zM20 4h3v1H20zM24,4 h1v1H24zM0 5h1v1H0zM6 5h1v1H6zM8 5h1v1H8zM11 5h1v1H11zM15 5h2v1H15zM18 5h1v1H18zM24,5 h1v1H24zM0 6h7v1H0zM8 6h1v1H8zM10 6h1v1H10zM12 6h1v1H12zM14 6h1v1H14zM16 6h1v1H16zM18,6 h7v1H18zM8 7h1v1H8zM14 7h3v1H14zM1 8h1v1H1zM3 8h1v1H3zM5 8h8v1H5zM15 8h5v1H15zM21 8h2v1H21zM24,8 h1v1H24zM0 9h3v1H0zM7 9h1v1H7zM9 9h2v1H9zM16 9h3v1H16zM24,9 h1v1H24zM4 10h1v1H4zM6 10h2v1H6zM16 10h2v1H16zM20 10h1v1H20zM23,10 h2v1H23zM0 11h1v1H0zM2 11h2v1H2zM8 11h1v1H8zM11 11h2v1H11zM14 11h1v1H14zM18 11h3v1H18zM0 12h2v1H0zM4 12h4v1H4zM10 12h3v1H10zM17 12h2v1H17zM21 12h1v1H21zM23,12 h2v1H23zM1 13h2v1H1zM5 13h1v1H5zM7 13h1v1H7zM9 13h1v1H9zM11 13h1v1H11zM18 13h2v1H18zM21 13h2v1H21zM24,13 h1v1H24zM0 14h1v1H0zM2 14h2v1H2zM6 14h2v1H6zM9 14h1v1H9zM11 14h1v1H11zM18 14h3v1H18zM22 14h1v1H22zM24,14 h1v1H24zM1 15h1v1H1zM3 15h3v1H3zM7 15h1v1H7zM9 15h2v1H9zM13 15h1v1H13zM15 15h3v1H15zM20 15h1v1H20zM23 15h1v1H23zM0 16h3v1H0zM4 16h1v1H4zM6 16h1v1H6zM9 16h1v1H9zM12 16h1v1H12zM14 16h1v1H14zM16 16h7v1H16zM8 17h1v1H8zM10 17h1v1H10zM12 17h5v1H12zM20 17h2v1H20zM24,17 h1v1H24zM0 18h7v1H0zM8 18h3v1H8zM14 18h3v1H14zM18 18h1v1H18zM20 18h2v1H20zM23,18 h2v1H23zM0 19h1v1H0zM6 19h1v1H6zM8 19h2v1H8zM13 19h1v1H13zM16 19h1v1H16zM20 19h3v1H20zM24,19 h1v1H24zM0 20h1v1H0zM2 20h3v1H2zM6 20h1v1H6zM9 20h1v1H9zM11 20h3v1H11zM16 20h6v1H16zM23,20 h2v1H23zM0 21h1v1H0zM2 21h3v1H2zM6 21h1v1H6zM8 21h2v1H8zM11 21h1v1H11zM15 21h1v1H15zM17 21h1v1H17zM19 21h4v1H19zM0 22h1v1H0zM2 22h3v1H2zM6 22h1v1H6zM9 22h5v1H9zM15 22h1v1H15zM19 22h2v1H19zM22 22h1v1H22zM24,22 h1v1H24zM0 23h1v1H0zM6 23h1v1H6zM8 23h1v1H8zM10 23h1v1H10zM13 23h1v1H13zM15 23h4v1H15zM21 23h1v1H21zM0 24h7v1H0zM14 24h3v1H14zM19 24h1v1H19zM23,24 h2v1H23z"
fill="#000"
shape-rendering="crispEdges"
/>
</svg>
</div>
</div>
</div>
`;

View File

@ -1,5 +1,5 @@
import { Button, QRCode } from 'antd';
import React from 'react';
import { QRCode, Button } from 'antd';
const downloadQRCode = () => {
const canvas = document.getElementById('myqrcode')?.querySelector<HTMLCanvasElement>('canvas');

View File

@ -0,0 +1,7 @@
## zh-CN
通过设置 `type` 自定义渲染结果,提供 `canvas``svg` 两个选项。
## en-US
Customize the rendering results by `type`, provide options `canvas` and `svg`.

View File

@ -0,0 +1,11 @@
import { QRCode, Space } from 'antd';
import React from 'react';
const App: React.FC = () => (
<Space>
<QRCode type="canvas" value="https://ant.design/" />
<QRCode type="svg" value="https://ant.design/" />
</Space>
);
export default App;

View File

@ -24,6 +24,7 @@ Used when the text needs to be converted into a QR Code.
<code src="./demo/base.tsx">base</code>
<code src="./demo/icon.tsx">With Icon</code>
<code src="./demo/status.tsx">other status</code>
<code src="./demo/type.tsx">Custom Render Type</code>
<code src="./demo/customSize.tsx">Custom Size</code>
<code src="./demo/customColor.tsx">Custom Color</code>
<code src="./demo/download.tsx">Download QRCode</code>
@ -37,6 +38,7 @@ Used when the text needs to be converted into a QR Code.
| Property | Description | Type | Default | Version |
| :-- | :-- | :-- | :-- | :-- |
| value | scanned text | string | - |
| type | render type | `canvas \| svg ` | `canvas` | 5.6.0 |
| icon | include image url (only image link are supported) | string | - |
| size | QRCode size | number | 128 |
| iconSize | include image size | number | 32 |

View File

@ -1,7 +1,7 @@
import { ReloadOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import { QRCodeCanvas } from 'qrcode.react';
import React, { useContext, useMemo } from 'react';
import { QRCodeCanvas, QRCodeSVG } from 'qrcode.react';
import React, { useContext } from 'react';
import warning from '../_util/warning';
import Button from '../button';
import type { ConfigConsumerProps } from '../config-provider';
@ -9,7 +9,7 @@ import { ConfigContext } from '../config-provider';
import { useLocale } from '../locale';
import Spin from '../spin';
import theme from '../theme';
import type { QRCodeProps, QRPropsCanvas } from './interface';
import type { QRCodeProps, QRProps } from './interface';
import useStyle from './style/index';
const { useToken } = theme;
@ -17,6 +17,7 @@ const { useToken } = theme;
const QRCode: React.FC<QRCodeProps> = (props) => {
const {
value,
type = 'canvas',
icon = '',
size = 160,
iconSize = 40,
@ -35,25 +36,25 @@ const QRCode: React.FC<QRCodeProps> = (props) => {
const prefixCls = getPrefixCls('qrcode', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls);
const { token } = useToken();
const qrCodeProps = useMemo<QRPropsCanvas>(() => {
const imageSettings: QRCodeProps['imageSettings'] = {
src: icon,
x: undefined,
y: undefined,
height: iconSize,
width: iconSize,
excavate: true,
};
return {
value,
size: size - (token.paddingSM + token.lineWidth) * 2,
level: errorLevel,
bgColor,
fgColor: color,
imageSettings: icon ? imageSettings : undefined,
};
}, [errorLevel, color, icon, iconSize, size, value, bgColor]);
const imageSettings: QRProps['imageSettings'] = {
src: icon,
x: undefined,
y: undefined,
height: iconSize,
width: iconSize,
excavate: true,
};
const qrCodeProps = {
value,
size: size - (token.paddingSM + token.lineWidth) * 2,
level: errorLevel,
bgColor,
fgColor: color,
imageSettings: icon ? imageSettings : undefined,
}
const [locale] = useLocale('QRCode');
if (!value) {
@ -92,7 +93,11 @@ const QRCode: React.FC<QRCodeProps> = (props) => {
)}
</div>
)}
<QRCodeCanvas {...qrCodeProps} />
{type === 'canvas' ? (
<QRCodeCanvas {...qrCodeProps} />
) : (
<QRCodeSVG {...qrCodeProps} />
)}
</div>,
);
};

View File

@ -25,6 +25,7 @@ group:
<code src="./demo/base.tsx">基本使用</code>
<code src="./demo/icon.tsx">带 Icon 的例子</code>
<code src="./demo/status.tsx">不同的状态</code>
<code src="./demo/type.tsx">自定义渲染类型</code>
<code src="./demo/customSize.tsx">自定义尺寸</code>
<code src="./demo/customColor.tsx">自定义颜色</code>
<code src="./demo/download.tsx">下载二维码</code>
@ -38,6 +39,7 @@ group:
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| :-- | :-- | :-- | :-- | :-- |
| value | 扫描后的文本 | string | - |
| type | 渲染类型 | `canvas \| svg ` | `canvas` | 5.6.0 |
| icon | 二维码中图片的地址(目前只支持图片地址) | string | - |
| size | 二维码大小 | number | 160 |
| iconSize | 二维码中图片的大小 | number | 40 |

View File

@ -9,8 +9,9 @@ interface ImageSettings {
y?: number;
}
interface QRProps {
export interface QRProps {
value: string;
type?: 'canvas' | 'svg';
size?: number;
color?: string;
style?: CSSProperties;
@ -20,7 +21,7 @@ interface QRProps {
}
export type QRPropsCanvas = QRProps & React.CanvasHTMLAttributes<HTMLCanvasElement>;
export type QRPropsSvg = QRProps & React.SVGAttributes<SVGSVGElement>;
export interface QRCodeProps extends QRProps {
className?: string;
rootClassName?: string;