Skip to content

Commit 08f4b2a

Browse files
authored
fix(react): resolve React warnings and fix Alert title margin (#72)
* fix(react): resolve React warnings and fix Alert title margin - List: wrap renderItem results in keyed Fragments to fix missing key warning - Collapse: move extra content outside header button to fix nested button warning - Waterfall: prevent infinite loop in onLayoutChange by deduplicating layout updates - InputOTP: move onChange call outside setState updater to fix setState-during-render warning - Tag: destructure visible prop to prevent it leaking to DOM - StrengthIndicator: destructure labels prop to prevent it leaking to DOM - NativeSelect: use defaultValue instead of value in disabled demo - Alert: only apply title bottom margin when children are present * chore: add changeset for React warning fixes and Alert style fix * test(collapse): update snapshot for header restructure
1 parent b566e51 commit 08f4b2a

12 files changed

Lines changed: 141 additions & 95 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tiny-design/react": patch
3+
---
4+
5+
Fix React warnings (missing keys, nested buttons, DOM attribute leaks, setState during render, infinite loop) and Alert title margin

packages/react/src/alert/alert.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const Alert = React.forwardRef<HTMLDivElement, AlertProps>((props, forwardedRef)
4141
const closeBtnOnClick = (e: React.MouseEvent<HTMLSpanElement>): void => {
4242
ref.current && setClosedStyle(ref.current as HTMLDivElement);
4343
setShow(false);
44-
onClose && onClose(e);
44+
onClose?.(e);
4545
};
4646

4747
// Setting close text attribute also allows to be closable
@@ -77,7 +77,7 @@ const Alert = React.forwardRef<HTMLDivElement, AlertProps>((props, forwardedRef)
7777
}}>
7878
{icon && renderIcon()}
7979
<div>
80-
{title && <p className={`${prefixCls}__title`}>{title}</p>}
80+
{title && <p className={classNames(`${prefixCls}__title`, { [`${prefixCls}__title_has-content`]: children })}>{title}</p>}
8181
{children}
8282
</div>
8383
{closeIcon}

packages/react/src/alert/style/_index.scss

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222

2323
&__title {
2424
box-sizing: border-box;
25-
margin: 0 0 5px;
26-
font-size: 18px;
25+
margin: 0;
26+
font-size: 17px;
2727
font-weight: 500;
28+
29+
&_has-content {
30+
margin-bottom: 5px;
31+
}
2832
}
2933

3034
&__desc {

packages/react/src/collapse/__tests__/__snapshots__/collapse.test.tsx.snap

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,34 @@ exports[`<Collapse /> should match the snapshot 1`] = `
88
<div
99
class="ty-collapse-item"
1010
>
11-
<button
12-
aria-controls=":r0:"
13-
aria-expanded="false"
11+
<div
1412
class="ty-collapse-item__header"
15-
id=":r1:"
16-
type="button"
1713
>
18-
<svg
19-
class="ty-collapse-item__arrow"
20-
height="10"
21-
viewBox="0 0 1024 1024"
22-
width="10"
23-
>
24-
<path
25-
d="M472.064 751.552 72.832 352.32c-22.08-22.08-22.08-57.792 0-79.872 22.016-22.016 57.792-22.08 79.872 0L512 631.744l359.296-359.296c22.016-22.016 57.792-22.08 79.872 0 22.08 22.08 22.016 57.792 0 79.872l-399.232 399.232C529.856 773.568 494.144 773.568 472.064 751.552z"
26-
fill="currentcolor"
27-
/>
28-
</svg>
29-
<div
30-
class="ty-collapse-item__title"
14+
<button
15+
aria-controls=":r0:"
16+
aria-expanded="false"
17+
class="ty-collapse-item__toggle"
18+
id=":r1:"
19+
type="button"
3120
>
32-
Panel 1
33-
</div>
34-
<div
35-
class="ty-collapse-item__extra"
36-
/>
37-
</button>
21+
<svg
22+
class="ty-collapse-item__arrow"
23+
height="10"
24+
viewBox="0 0 1024 1024"
25+
width="10"
26+
>
27+
<path
28+
d="M472.064 751.552 72.832 352.32c-22.08-22.08-22.08-57.792 0-79.872 22.016-22.016 57.792-22.08 79.872 0L512 631.744l359.296-359.296c22.016-22.016 57.792-22.08 79.872 0 22.08 22.08 22.016 57.792 0 79.872l-399.232 399.232C529.856 773.568 494.144 773.568 472.064 751.552z"
29+
fill="currentcolor"
30+
/>
31+
</svg>
32+
<div
33+
class="ty-collapse-item__title"
34+
>
35+
Panel 1
36+
</div>
37+
</button>
38+
</div>
3839
<div
3940
class="ty-collapse-transition"
4041
style="display: block;"
@@ -52,33 +53,34 @@ exports[`<Collapse /> should match the snapshot 1`] = `
5253
<div
5354
class="ty-collapse-item"
5455
>
55-
<button
56-
aria-controls=":r2:"
57-
aria-expanded="false"
56+
<div
5857
class="ty-collapse-item__header"
59-
id=":r3:"
60-
type="button"
6158
>
62-
<svg
63-
class="ty-collapse-item__arrow"
64-
height="10"
65-
viewBox="0 0 1024 1024"
66-
width="10"
67-
>
68-
<path
69-
d="M472.064 751.552 72.832 352.32c-22.08-22.08-22.08-57.792 0-79.872 22.016-22.016 57.792-22.08 79.872 0L512 631.744l359.296-359.296c22.016-22.016 57.792-22.08 79.872 0 22.08 22.08 22.016 57.792 0 79.872l-399.232 399.232C529.856 773.568 494.144 773.568 472.064 751.552z"
70-
fill="currentcolor"
71-
/>
72-
</svg>
73-
<div
74-
class="ty-collapse-item__title"
59+
<button
60+
aria-controls=":r2:"
61+
aria-expanded="false"
62+
class="ty-collapse-item__toggle"
63+
id=":r3:"
64+
type="button"
7565
>
76-
Panel 2
77-
</div>
78-
<div
79-
class="ty-collapse-item__extra"
80-
/>
81-
</button>
66+
<svg
67+
class="ty-collapse-item__arrow"
68+
height="10"
69+
viewBox="0 0 1024 1024"
70+
width="10"
71+
>
72+
<path
73+
d="M472.064 751.552 72.832 352.32c-22.08-22.08-22.08-57.792 0-79.872 22.016-22.016 57.792-22.08 79.872 0L512 631.744l359.296-359.296c22.016-22.016 57.792-22.08 79.872 0 22.08 22.08 22.016 57.792 0 79.872l-399.232 399.232C529.856 773.568 494.144 773.568 472.064 751.552z"
74+
fill="currentcolor"
75+
/>
76+
</svg>
77+
<div
78+
class="ty-collapse-item__title"
79+
>
80+
Panel 2
81+
</div>
82+
</button>
83+
</div>
8284
<div
8385
class="ty-collapse-transition"
8486
style="display: block;"

packages/react/src/collapse/collapse-panel.tsx

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,21 +69,27 @@ const CollapsePanel = (props: CollapsePanelProps): React.ReactElement => {
6969
[`${prefixCls}__arrow_active`]: active,
7070
});
7171

72+
const hasExtra = deletable || extra;
73+
7274
return (
73-
<button
74-
type="button"
75-
id={headerId}
76-
className={headerCls}
77-
onClick={headerOnClick}
78-
aria-expanded={active}
79-
aria-controls={panelId}
80-
aria-disabled={disabled || undefined}>
81-
{showArrow && <ArrowDown size={10} className={arrowCls} />}
82-
<div className={`${prefixCls}__title`}>{richNode(header, active)}</div>
83-
<div className={`${prefixCls}__extra`}>
84-
{deletable ? <span onClick={removeItem}></span> : richNode(extra, active)}
85-
</div>
86-
</button>
75+
<div className={headerCls}>
76+
<button
77+
type="button"
78+
id={headerId}
79+
className={`${prefixCls}__toggle`}
80+
onClick={headerOnClick}
81+
aria-expanded={active}
82+
aria-controls={panelId}
83+
aria-disabled={disabled || undefined}>
84+
{showArrow && <ArrowDown size={10} className={arrowCls} />}
85+
<div className={`${prefixCls}__title`}>{richNode(header, active)}</div>
86+
</button>
87+
{hasExtra && (
88+
<div className={`${prefixCls}__extra`}>
89+
{deletable ? <span onClick={removeItem}></span> : richNode(extra, active)}
90+
</div>
91+
)}
92+
</div>
8793
);
8894
};
8995

packages/react/src/collapse/style/_index.scss

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,9 @@
2727
align-items: center;
2828
box-sizing: border-box;
2929
position: relative;
30-
padding: 12px 16px;
3130
color: var(--ty-color-text);
3231
line-height: 22px;
33-
cursor: pointer;
3432
transition: all 300ms;
35-
background: none;
36-
border: none;
37-
width: 100%;
38-
text-align: left;
39-
font-size: inherit;
40-
font-family: inherit;
4133

4234
&:hover {
4335
background-color: var(--ty-collapse-header-hover-bg);
@@ -49,11 +41,33 @@
4941
}
5042
}
5143

44+
&__toggle {
45+
display: flex;
46+
align-items: center;
47+
flex: 1;
48+
min-width: 0;
49+
box-sizing: border-box;
50+
padding: 12px 16px;
51+
cursor: pointer;
52+
background: none;
53+
border: none;
54+
width: 100%;
55+
text-align: left;
56+
font-size: inherit;
57+
font-family: inherit;
58+
color: inherit;
59+
line-height: inherit;
60+
}
61+
62+
&__header_disabled &__toggle {
63+
cursor: not-allowed;
64+
}
65+
5266
&__arrow {
5367
margin-right: 10px;
5468
transform: rotate(-90deg);
5569
text-align: center;
56-
color: currentColor;
70+
color: currentcolor;
5771
transition: all 300ms;
5872

5973
&_active {
@@ -66,9 +80,12 @@
6680
}
6781

6882
&__extra {
83+
display: flex;
84+
align-items: center;
6985
color: inherit;
7086
font-size: 11px;
71-
margin-left: 15px;
87+
padding-right: 16px;
88+
margin-left: auto;
7289
}
7390

7491
&__content {

packages/react/src/input-otp/input-otp.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,14 @@ const InputOTP = React.forwardRef<InputOTPRef, InputOTPProps>(
8585
// Trigger onChange when value cells change
8686
const triggerValueCellsChange = useCallback(
8787
(nextValueCells: string[]) => {
88-
setValueCells((prev) => {
89-
const prevValue = prev.join('');
90-
const nextValue = nextValueCells.join('');
91-
if (onChange && prevValue !== nextValue) {
92-
onChange(nextValue);
93-
}
94-
return nextValueCells;
95-
});
88+
const prevValue = valueCells.join('');
89+
const nextValue = nextValueCells.join('');
90+
setValueCells(nextValueCells);
91+
if (onChange && prevValue !== nextValue) {
92+
onChange(nextValue);
93+
}
9694
},
97-
[onChange]
95+
[onChange, valueCells]
9896
);
9997

10098
// Patch value at given index

packages/react/src/list/list.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ const List = React.forwardRef<HTMLDivElement, ListProps>((props, ref) => {
8585
}
8686
if (renderItem) {
8787
const [start, end] = visibleRange;
88-
const visibleItems = dataSource.slice(start, end + 1).map((item, i) => renderItem(item, start + i));
88+
const visibleItems = dataSource.slice(start, end + 1).map((item, i) => (
89+
<React.Fragment key={start + i}>{renderItem(item, start + i)}</React.Fragment>
90+
));
8991
return (
9092
<div style={{ height: totalHeight, position: 'relative' }}>
9193
<div style={{ position: 'absolute', top: 0, left: 0, right: 0, transform: `translateY(${offsetY}px)` }}>
@@ -106,7 +108,9 @@ const List = React.forwardRef<HTMLDivElement, ListProps>((props, ref) => {
106108
);
107109
}
108110
if (renderItem) {
109-
const rendered = items.map((item, index) => renderItem(item, index));
111+
const rendered = items.map((item, index) => (
112+
<React.Fragment key={index}>{renderItem(item, index)}</React.Fragment>
113+
));
110114
if (grid) {
111115
return (
112116
<div

packages/react/src/native-select/demo/Disabled.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default function DisabledDemo() {
55
const { Option } = NativeSelect;
66

77
return (
8-
<NativeSelect disabled value="oliver">
8+
<NativeSelect disabled defaultValue="oliver">
99
<Option value="tom">Tom</Option>
1010
<Option value="oliver">Oliver</Option>
1111
<Option value="jack">Jack</Option>

packages/react/src/strength-indicator/strength-indicator.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ const StrengthIndicator = React.forwardRef<HTMLDivElement, StrengthIndicatorProp
1010
current = 0,
1111
blocks = 3,
1212
colors = ['#f44336', '#ff9800', '#52c41a'],
13+
labels,
1314
className,
1415
prefixCls: customisedCls,
1516
...otherProps
1617
} = props;
1718
const configContext = useContext(ConfigContext);
1819
const prefixCls = getPrefixCls('strength-indicator', configContext.prefixCls, customisedCls);
1920
const cls = classNames(prefixCls, className);
20-
const displayLabels: React.ReactNode[] = Array.isArray(props.labels)
21-
? props.labels
21+
const showLabels = labels !== undefined;
22+
const displayLabels: React.ReactNode[] = Array.isArray(labels)
23+
? labels
2224
: ['Weak', 'Medium', 'Strong'];
2325

2426
return (
@@ -31,7 +33,7 @@ const StrengthIndicator = React.forwardRef<HTMLDivElement, StrengthIndicatorProp
3133
return (
3234
<div key={idx} className={itemCls}>
3335
<div className={`${prefixCls}__inner`} style={{ backgroundColor: bgColor }} />
34-
{'labels' in props && (
36+
{showLabels && (
3537
<div className={`${prefixCls}__label`}>{displayLabels[idx]}</div>
3638
)}
3739
</div>

0 commit comments

Comments
 (0)