Skip to content
Open
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
12 changes: 6 additions & 6 deletions src/tinyTag/__tests__/__snapshots__/tinyTag.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ exports[`test StatusTag should match snapshot 1`] = `
<svg
fill="none"
height="15"
viewBox="0 0 8 15"
width="8"
viewBox="0 0 28 15"
width="28"
xmlns="http://www.w3.org/2000/svg"
>
<rect
Expand All @@ -18,7 +18,7 @@ exports[`test StatusTag should match snapshot 1`] = `
rx="1.5"
stroke="currentColor"
stroke-linejoin="bevel"
width="7"
width="27"
x="0.5"
y="0.5"
/>
Expand Down Expand Up @@ -48,8 +48,8 @@ exports[`test StatusTag should support fill type 1`] = `
<svg
fill="none"
height="15"
viewBox="0 0 8 15"
width="8"
viewBox="0 0 28 15"
width="28"
xmlns="http://www.w3.org/2000/svg"
>
<rect
Expand All @@ -58,7 +58,7 @@ exports[`test StatusTag should support fill type 1`] = `
rx="1.5"
stroke="#D56161"
stroke-linejoin="bevel"
width="7"
width="27"
x="0.5"
y="0.5"
/>
Expand Down
41 changes: 40 additions & 1 deletion src/tinyTag/__tests__/tinyTag.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,36 @@ import '@testing-library/jest-dom/extend-expect';
import TinyTag from '..';

describe('test StatusTag', () => {
beforeEach(cleanup);
const svgElementPrototype = SVGElement.prototype as SVGElement & {
getComputedTextLength?: () => number;
};
const getComputedTextLength = svgElementPrototype.getComputedTextLength;
const requestAnimationFrame = window.requestAnimationFrame;
const cancelAnimationFrame = window.cancelAnimationFrame;

beforeEach(() => {
cleanup();
Object.defineProperty(svgElementPrototype, 'getComputedTextLength', {
configurable: true,
value: jest.fn(() => 20),
});
window.requestAnimationFrame = jest.fn((callback) => {
callback(0);
return 0;
});
window.cancelAnimationFrame = jest.fn();
});

afterEach(() => {
cleanup();
Object.defineProperty(svgElementPrototype, 'getComputedTextLength', {
configurable: true,
value: getComputedTextLength,
});
window.requestAnimationFrame = requestAnimationFrame;
window.cancelAnimationFrame = cancelAnimationFrame;
jest.useRealTimers();
});

test('should match snapshot', () => {
const { asFragment } = render(<TinyTag value="完成" className="dtc-test" />);
Expand All @@ -19,6 +48,16 @@ describe('test StatusTag', () => {
expect(asFragment()).toMatchSnapshot();
});

test('should remeasure width after hidden render', () => {
const measureWidth = svgElementPrototype.getComputedTextLength as jest.Mock;
measureWidth.mockReturnValueOnce(0).mockReturnValue(24);

const { container } = render(<TinyTag value="META" />);

expect(container.querySelector('svg')?.getAttribute('width')).toBe('32');
expect(container.querySelector('rect')?.getAttribute('width')).toBe('31');
});

test('should render custom color in default mode', () => {
const { container } = render(<TinyTag value="标签" color="#1890ff" />);
const rect = container.querySelector('rect');
Expand Down
18 changes: 18 additions & 0 deletions src/tinyTag/demos/hidden.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { useState } from 'react';
import { Button, Space } from 'antd';
import { TinyTag } from 'dt-react-component';

export default () => {
const [visible, setVisible] = useState(false);

return (
<Space direction="vertical" size={8}>
<Button type="primary" onClick={() => setVisible(!visible)}>
{visible ? '隐藏标签' : '显示标签'}
</Button>
<div style={{ display: visible ? 'block' : 'none' }}>
<TinyTag value="隐藏渲染后显示的标签" />
</div>
</Space>
);
};
1 change: 1 addition & 0 deletions src/tinyTag/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ TinyTag 组件通常用于在某些文案后面,用于标识当前行数据的
## 示例

<code src="./demos/basic.tsx">基础使用</code>
<code src="./demos/hidden.tsx">隐藏渲染</code>
<code src="./demos/table.tsx">表格使用</code>

## API
Expand Down
30 changes: 25 additions & 5 deletions src/tinyTag/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useEffect, useLayoutEffect, useState } from 'react';
import classNames from 'classnames';

import './style.scss';
Expand Down Expand Up @@ -29,17 +29,37 @@ const useSvgWidth = (): UseSvgWidthResult => {
const [rectWidth, setRectWidth] = useState(0);

const getWidth = useCallback(() => {
if (!element) return;
if (!element) return false;
const paddingWidth = 8;
const textWidth = Math.round(element.getComputedTextLength?.() ?? 0);
const textWidth = Math.round(element.getComputedTextLength());
if (!textWidth) return false;
const svgWidth = textWidth + paddingWidth;
setSvgWidth(svgWidth);
setRectWidth(Math.max(svgWidth - 1, 0));
return true;
}, [element]);

useEffect(() => {
useLayoutEffect(() => {
getWidth();
}, [element]);
const timer = window.requestAnimationFrame(getWidth);

return () => {
window.cancelAnimationFrame(timer);
};
}, [getWidth]);

useEffect(() => {
if (!element || !window.ResizeObserver) return undefined;

const resizeObserver = new window.ResizeObserver(() => {
getWidth();
});
resizeObserver.observe(element);

return () => {
resizeObserver.disconnect();
};
}, [element, getWidth]);

return [ref, svgWidth, rectWidth];
};
Expand Down
Loading