Skip to content

Commit 4f5f960

Browse files
authored
chore: fix ssr render (#127)
1 parent 01580cf commit 4f5f960

File tree

5 files changed

+149
-36
lines changed

5 files changed

+149
-36
lines changed

src/Circle.tsx

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ import * as React from 'react';
22
import classNames from 'classnames';
33
import { useTransitionDuration, defaultProps } from './common';
44
import type { ProgressProps, GapPositionType } from './interface';
5-
6-
let gradientSeed = 0;
5+
import useId from './hooks/useId';
76

87
function stripPercentToNumber(percent: string) {
98
return +percent.replace('%', '');
109
}
1110

12-
function toArray(symArray: any) {
13-
return Array.isArray(symArray) ? symArray : [symArray];
11+
function toArray<T>(value: T | T[]): T[] {
12+
const mergedValue = value ?? [];
13+
return Array.isArray(mergedValue) ? mergedValue : [mergedValue];
1414
}
1515

1616
function getPathStyles(
1717
offset: number,
1818
percent: number,
19-
strokeColor: string,
19+
strokeColor: string | Record<string, string>,
2020
strokeWidth: number,
2121
gapDegree = 0,
2222
gapPosition: GapPositionType,
@@ -65,6 +65,7 @@ function getPathStyles(
6565
}
6666

6767
const Circle: React.FC<ProgressProps> = ({
68+
id,
6869
prefixCls,
6970
strokeWidth,
7071
trailWidth,
@@ -78,10 +79,10 @@ const Circle: React.FC<ProgressProps> = ({
7879
percent,
7980
...restProps
8081
}) => {
81-
const gradientId = React.useMemo(() => {
82-
gradientSeed += 1;
83-
return gradientSeed;
84-
}, []);
82+
const mergedId = useId(id);
83+
84+
const gradientId = `${mergedId}-gradient`;
85+
8586
const { pathString, pathStyle } = getPathStyles(
8687
0,
8788
100,
@@ -92,20 +93,15 @@ const Circle: React.FC<ProgressProps> = ({
9293
);
9394
const percentList = toArray(percent);
9495
const strokeColorList = toArray(strokeColor);
95-
const gradient = strokeColorList.find(
96-
(color) => Object.prototype.toString.call(color) === '[object Object]',
97-
);
96+
const gradient = strokeColorList.find((color) => color && typeof color === 'object');
9897

9998
const [paths] = useTransitionDuration(percentList);
10099

101100
const getStokeList = () => {
102101
let stackPtg = 0;
103102
return percentList.map((ptg, index) => {
104103
const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1];
105-
const stroke =
106-
Object.prototype.toString.call(color) === '[object Object]'
107-
? `url(#${prefixCls}-gradient-${gradientId})`
108-
: '';
104+
const stroke = color && typeof color === 'object' ? `url(#${gradientId})` : '';
109105
const pathStyles = getPathStyles(stackPtg, ptg, color, strokeWidth, gapDegree, gapPosition);
110106
stackPtg += ptg;
111107
return (
@@ -130,17 +126,12 @@ const Circle: React.FC<ProgressProps> = ({
130126
className={classNames(`${prefixCls}-circle`, className)}
131127
viewBox="0 0 100 100"
132128
style={style}
129+
id={id}
133130
{...restProps}
134131
>
135132
{gradient && (
136133
<defs>
137-
<linearGradient
138-
id={`${prefixCls}-gradient-${gradientId}`}
139-
x1="100%"
140-
y1="0%"
141-
x2="0%"
142-
y2="0%"
143-
>
134+
<linearGradient id={gradientId} x1="100%" y1="0%" x2="0%" y2="0%">
144135
{Object.keys(gradient)
145136
.sort((a, b) => stripPercentToNumber(a) - stripPercentToNumber(b))
146137
.map((key, index) => (

src/hooks/useId.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as React from 'react';
2+
import canUseDom from 'rc-util/lib/Dom/canUseDom';
3+
4+
let uuid = 0;
5+
6+
/** Is client side and not jsdom */
7+
export const isBrowserClient = process.env.NODE_ENV !== 'test' && canUseDom();
8+
9+
/** Get unique id for accessibility usage */
10+
function getUUID(): number | string {
11+
let retId: string | number;
12+
13+
// Test never reach
14+
/* istanbul ignore if */
15+
if (isBrowserClient) {
16+
retId = uuid;
17+
uuid += 1;
18+
} else {
19+
retId = 'TEST_OR_SSR';
20+
}
21+
22+
return retId;
23+
}
24+
25+
export default (id?: string) => {
26+
// Inner id for accessibility usage. Only work in client side
27+
const [innerId, setInnerId] = React.useState<string>();
28+
React.useEffect(() => {
29+
setInnerId(`rc_progress_${getUUID()}`);
30+
}, []);
31+
return id || innerId;
32+
};

src/interface.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import * as React from 'react';
2-
31
export interface ProgressProps {
2+
id?: string;
43
strokeWidth?: number;
54
trailWidth?: number;
65
className?: string;
@@ -15,7 +14,7 @@ export interface ProgressProps {
1514
transition?: string;
1615
}
1716

18-
export type StrokeColorType = string | string[] | object;
17+
export type StrokeColorType = string | string[] | Record<string, string>;
1918

2019
export type GapPositionType = 'top' | 'right' | 'bottom' | 'left';
2120

tests/__snapshots__/index.spec.js.snap

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,103 @@ Array [
142142
]
143143
`;
144144

145+
exports[`Progress Circle should gradient works and circles have different gradient IDs 1`] = `
146+
<div>
147+
<svg
148+
class="rc-progress-circle"
149+
viewBox="0 0 100 100"
150+
>
151+
<defs>
152+
<linearGradient
153+
id="rc_progress_TEST_OR_SSR-gradient"
154+
x1="100%"
155+
x2="0%"
156+
y1="0%"
157+
y2="0%"
158+
>
159+
<stop
160+
offset="0%"
161+
stop-color="#108ee9"
162+
/>
163+
<stop
164+
offset="100%"
165+
stop-color="#87d068"
166+
/>
167+
</linearGradient>
168+
</defs>
169+
<path
170+
class="rc-progress-circle-trail"
171+
d="M 50,50 m 0,-47
172+
a 47,47 0 1 1 0,94
173+
a 47,47 0 1 1 0,-94"
174+
fill-opacity="0"
175+
stroke="#D9D9D9"
176+
stroke-linecap="round"
177+
stroke-width="1"
178+
style="stroke: #D9D9D9; stroke-dasharray: 295.3097094374406px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"
179+
/>
180+
<path
181+
class="rc-progress-circle-path"
182+
d="M 50,50 m 0,-47
183+
a 47,47 0 1 1 0,94
184+
a 47,47 0 1 1 0,-94"
185+
fill-opacity="0"
186+
opacity="1"
187+
stroke="url(#rc_progress_TEST_OR_SSR-gradient)"
188+
stroke-linecap="round"
189+
stroke-width="6"
190+
style="stroke-dasharray: 265.77873849369655px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: 0s, 0s;"
191+
/>
192+
</svg>
193+
<svg
194+
class="rc-progress-circle"
195+
viewBox="0 0 100 100"
196+
>
197+
<defs>
198+
<linearGradient
199+
id="rc_progress_TEST_OR_SSR-gradient"
200+
x1="100%"
201+
x2="0%"
202+
y1="0%"
203+
y2="0%"
204+
>
205+
<stop
206+
offset="0%"
207+
stop-color="#108ee9"
208+
/>
209+
<stop
210+
offset="100%"
211+
stop-color="#87d068"
212+
/>
213+
</linearGradient>
214+
</defs>
215+
<path
216+
class="rc-progress-circle-trail"
217+
d="M 50,50 m 0,-47
218+
a 47,47 0 1 1 0,94
219+
a 47,47 0 1 1 0,-94"
220+
fill-opacity="0"
221+
stroke="#D9D9D9"
222+
stroke-linecap="round"
223+
stroke-width="1"
224+
style="stroke: #D9D9D9; stroke-dasharray: 295.3097094374406px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"
225+
/>
226+
<path
227+
class="rc-progress-circle-path"
228+
d="M 50,50 m 0,-47
229+
a 47,47 0 1 1 0,94
230+
a 47,47 0 1 1 0,-94"
231+
fill-opacity="0"
232+
opacity="1"
233+
stroke="url(#rc_progress_TEST_OR_SSR-gradient)"
234+
stroke-linecap="round"
235+
stroke-width="6"
236+
style="stroke-dasharray: 265.77873849369655px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: 0s, 0s;"
237+
/>
238+
</svg>
239+
</div>
240+
`;
241+
145242
exports[`Progress Circle should show right gapPosition 1`] = `
146243
Array [
147244
<Circle

tests/index.spec.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ describe('Progress', () => {
5959
});
6060

6161
it('should gradient works and circles have different gradient IDs', () => {
62-
const c = mount(
63-
<>
62+
const wrapper = mount(
63+
<div>
6464
<Circle
6565
percent={90}
6666
strokeWidth="6"
@@ -79,16 +79,10 @@ describe('Progress', () => {
7979
'100%': '#87d068',
8080
}}
8181
/>
82-
</>,
82+
</div>,
8383
);
8484

85-
const gradientDefs = c.find('defs');
86-
const idFirst = gradientDefs.at(0).props().children.props.id;
87-
const idSecond = gradientDefs.at(1).props().children.props.id;
88-
const idRE = /^rc-progress-gradient-\d{1,}$/;
89-
expect(idFirst).toMatch(idRE);
90-
expect(idSecond).toMatch(idRE);
91-
expect(idFirst === idSecond).toBeFalsy();
85+
expect(wrapper.render()).toMatchSnapshot();
9286
});
9387

9488
it('should show right gapPosition', () => {

0 commit comments

Comments
 (0)