Skip to content

Commit 64a835d

Browse files
committed
refactor(icons): move withSpin HOC from icons to react package
Replace inline JS animation with CSS class (.ty-icon-spin) using the existing ty-rotate keyframe from @tiny-design/tokens. Update docs to reference the new @tiny-design/react import path.
1 parent 7752c9e commit 64a835d

11 files changed

Lines changed: 77 additions & 86 deletions

File tree

packages/icons/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ All icons accept the following props (plus any standard SVG attributes):
3939

4040
### Spinning Icons
4141

42-
Use the `withSpin` HOC to create spinning variants (useful for loaders):
42+
Use the `withSpin` HOC from `@tiny-design/react` to create spinning variants (useful for loaders):
4343

4444
```tsx
45-
import { IconLoader, withSpin } from '@tiny-design/icons';
45+
import { withSpin } from '@tiny-design/react';
46+
import { IconLoader } from '@tiny-design/icons';
4647

4748
const SpinningLoader = withSpin(IconLoader);
4849

packages/icons/src/__tests__/icons.test.tsx

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { createRef } from 'react';
22
import { render } from '@testing-library/react';
3-
import { IconClose, IconPlus, IconSearch, IconHeart, IconStar, withSpin } from '../index';
3+
import { IconClose, IconPlus, IconSearch, IconHeart, IconStar } from '../index';
44

55
const sampleIcons = [
66
{ name: 'IconClose', Component: IconClose },
@@ -73,44 +73,3 @@ describe('Icon components', () => {
7373
});
7474

7575
});
76-
77-
describe('withSpin HOC', () => {
78-
const SpinClose = withSpin(IconClose);
79-
80-
it('applies spin animation style', () => {
81-
const { container } = render(<SpinClose />);
82-
const svg = container.querySelector('svg')!;
83-
expect(svg.style.animation).toBe('tiny-icon-spin 1s linear infinite');
84-
});
85-
86-
it('injects keyframes style tag into document head', () => {
87-
render(<SpinClose />);
88-
const styleEl = document.getElementById('__tiny_icon_spin__');
89-
expect(styleEl).toBeTruthy();
90-
expect(styleEl!.textContent).toContain('@keyframes tiny-icon-spin');
91-
});
92-
93-
it('passes through icon props', () => {
94-
const { container } = render(<SpinClose size={24} color="red" />);
95-
const svg = container.querySelector('svg')!;
96-
expect(svg.getAttribute('width')).toBe('24');
97-
expect(svg.getAttribute('fill')).toBe('red');
98-
});
99-
100-
it('merges custom style with spin animation', () => {
101-
const { container } = render(<SpinClose style={{ color: 'red' }} />);
102-
const svg = container.querySelector('svg')!;
103-
expect(svg.style.animation).toBe('tiny-icon-spin 1s linear infinite');
104-
expect(svg.style.color).toBe('red');
105-
});
106-
107-
it('forwards ref', () => {
108-
const ref = createRef<SVGSVGElement>();
109-
render(<SpinClose ref={ref} />);
110-
expect(ref.current).toBeInstanceOf(SVGSVGElement);
111-
});
112-
113-
it('sets displayName', () => {
114-
expect(SpinClose.displayName).toBe('withSpin(IconClose)');
115-
});
116-
});

packages/icons/src/with-spin.tsx

Lines changed: 0 additions & 41 deletions
This file was deleted.

packages/react/src/icon/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ All icon components share the same props interface (`IconProps`), which extends
4747
A higher-order component that wraps any icon to add a continuous spin animation.
4848

4949
```jsx
50-
import { IconLoader, withSpin } from '@tiny-design/icons';
50+
import { withSpin } from '@tiny-design/react';
51+
import { IconLoader } from '@tiny-design/icons';
5152

5253
const SpinLoader = withSpin(IconLoader);
5354

packages/react/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export { default as Typography } from './typography';
8080
export { default as Upload } from './upload';
8181

8282
export { withLocale } from './intl-provider/with-locale';
83+
export { withSpin } from './with-spin';
8384
export { en_US, zh_CN } from './locale';
8485
export type { Locale } from './locale';
8586

packages/react/src/style/_component.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,4 @@
7575
@use "../tree/style/index" as *;
7676
@use "../typography/style/index" as *;
7777
@use "../upload/style/index" as *;
78+
@use "../with-spin/style/index" as *;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { createRef } from 'react';
2+
import { render } from '@testing-library/react';
3+
import { IconClose } from '@tiny-design/icons';
4+
import { withSpin } from '../with-spin';
5+
6+
describe('withSpin HOC', () => {
7+
const SpinClose = withSpin(IconClose);
8+
9+
it('applies ty-icon-spin CSS class', () => {
10+
const { container } = render(<SpinClose />);
11+
const svg = container.querySelector('svg')!;
12+
expect(svg).toHaveClass('ty-icon-spin');
13+
});
14+
15+
it('passes through icon props', () => {
16+
const { container } = render(<SpinClose size={24} color="red" />);
17+
const svg = container.querySelector('svg')!;
18+
expect(svg.getAttribute('width')).toBe('24');
19+
expect(svg.getAttribute('fill')).toBe('red');
20+
});
21+
22+
it('merges className with existing className prop', () => {
23+
const { container } = render(<SpinClose className="custom" />);
24+
const svg = container.querySelector('svg')!;
25+
expect(svg).toHaveClass('ty-icon-spin');
26+
expect(svg).toHaveClass('custom');
27+
});
28+
29+
it('forwards ref', () => {
30+
const ref = createRef<SVGSVGElement>();
31+
render(<SpinClose ref={ref} />);
32+
expect(ref.current).toBeInstanceOf(SVGSVGElement);
33+
});
34+
35+
it('sets displayName', () => {
36+
expect(SpinClose.displayName).toBe('withSpin(IconClose)');
37+
});
38+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { withSpin } from './with-spin';
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@use '../../style/variables' as *;
2+
3+
.#{$prefix}-icon-spin {
4+
animation: ty-rotate 1s linear infinite;
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import './index.scss';

0 commit comments

Comments
 (0)