Skip to content

Commit 8e7aeb2

Browse files
authored
fix: duplicated selected menu item when selectedKeys is string (#374)
* fix: duplicated selected menu item when selectedKeys is string close ant-design/ant-design#29429 * fix eslint
1 parent 8085da9 commit 8e7aeb2

File tree

9 files changed

+100
-68
lines changed

9 files changed

+100
-68
lines changed

src/DOMWrap.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from 'react';
22
import ResizeObserver from 'resize-observer-polyfill';
33
import SubMenu from './SubMenu';
44
import { getWidth, setStyle, menuAllProps } from './util';
5-
import { MenuMode } from './interface';
5+
import type { MenuMode } from './interface';
66

77
const MENUITEM_OVERFLOWED_CLASSNAME = 'menuitem-overflowed';
88
const FLOAT_PRECISION_ADJUST = 0.5;
@@ -60,7 +60,7 @@ class DOMWrap extends React.Component<DOMWrapProps, DOMWrapState> {
6060
if (!menuUl) {
6161
return;
6262
}
63-
this.resizeObserver = new ResizeObserver(entries => {
63+
this.resizeObserver = new ResizeObserver((entries) => {
6464
entries.forEach(() => {
6565
const { cancelFrameId } = this;
6666
cancelAnimationFrame(cancelFrameId);
@@ -166,7 +166,7 @@ class DOMWrap extends React.Component<DOMWrapProps, DOMWrapState> {
166166

167167
const popupClassName = theme ? `${prefixCls}-${theme}` : '';
168168
const props = {};
169-
menuAllProps.forEach(k => {
169+
menuAllProps.forEach((k) => {
170170
if (rest[k] !== undefined) {
171171
props[k] = rest[k];
172172
}
@@ -218,16 +218,16 @@ class DOMWrap extends React.Component<DOMWrapProps, DOMWrapState> {
218218
// and then reset to original state after width calculation
219219

220220
const overflowedItems = menuItemNodes.filter(
221-
c => c.className.split(' ').indexOf(MENUITEM_OVERFLOWED_CLASSNAME) >= 0,
221+
(c) => c.className.split(' ').indexOf(MENUITEM_OVERFLOWED_CLASSNAME) >= 0,
222222
);
223223

224-
overflowedItems.forEach(c => {
224+
overflowedItems.forEach((c) => {
225225
setStyle(c, 'display', 'inline-block');
226226
});
227227

228-
this.menuItemSizes = menuItemNodes.map(c => getWidth(c, true));
228+
this.menuItemSizes = menuItemNodes.map((c) => getWidth(c, true));
229229

230-
overflowedItems.forEach(c => {
230+
overflowedItems.forEach((c) => {
231231
setStyle(c, 'display', 'none');
232232
});
233233
this.overflowedIndicatorWidth = getWidth(
@@ -266,7 +266,7 @@ class DOMWrap extends React.Component<DOMWrapProps, DOMWrapState> {
266266
if (this.originalTotalWidth > width + FLOAT_PRECISION_ADJUST) {
267267
lastVisibleIndex = -1;
268268

269-
this.menuItemSizes.forEach(liWidth => {
269+
this.menuItemSizes.forEach((liWidth) => {
270270
currentSumWidth += liWidth;
271271
if (currentSumWidth + this.overflowedIndicatorWidth <= width) {
272272
lastVisibleIndex += 1;
@@ -314,7 +314,7 @@ class DOMWrap extends React.Component<DOMWrapProps, DOMWrapState> {
314314
if (index === lastVisibleIndex + 1) {
315315
this.overflowedItems = children
316316
.slice(lastVisibleIndex + 1)
317-
.map(c =>
317+
.map((c) =>
318318
React.cloneElement(
319319
c,
320320
// children[index].key will become '.$key' in clone by default,

src/Menu.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import * as React from 'react';
22
import { Provider, create } from 'mini-store';
33
import omit from 'rc-util/lib/omit';
4-
import { CSSMotionProps } from 'rc-motion';
4+
import type { CSSMotionProps } from 'rc-motion';
55
import SubPopupMenu, { getActiveKey } from './SubPopupMenu';
66
import { noop } from './util';
7-
import {
7+
import type {
88
RenderIconType,
99
SelectInfo,
1010
SelectEventHandler,
@@ -69,7 +69,7 @@ export interface MenuProps
6969
export interface MenuState {
7070
switchingModeFromInline: boolean;
7171
prevProps: MenuProps;
72-
inlineOpenKeys: Array<string>;
72+
inlineOpenKeys: string[];
7373
store: MiniStore;
7474
}
7575

@@ -235,7 +235,7 @@ class Menu extends React.Component<MenuProps, MenuState> {
235235
}
236236
};
237237

238-
onClick: MenuClickEventHandler = e => {
238+
onClick: MenuClickEventHandler = (e) => {
239239
const mode = this.getRealMenuMode();
240240
const {
241241
store,
@@ -259,11 +259,11 @@ class Menu extends React.Component<MenuProps, MenuState> {
259259
this.innerMenu.getWrappedInstance().onKeyDown(e, callback);
260260
};
261261

262-
onOpenChange = event => {
262+
onOpenChange = (event) => {
263263
const { props } = this;
264264
const openKeys = this.store.getState().openKeys.concat();
265265
let changed = false;
266-
const processSingle = e => {
266+
const processSingle = (e) => {
267267
let oneChanged = false;
268268
if (e.open) {
269269
oneChanged = openKeys.indexOf(e.key) === -1;
@@ -379,7 +379,7 @@ class Menu extends React.Component<MenuProps, MenuState> {
379379
}
380380
}
381381

382-
setInnerMenu = node => {
382+
setInnerMenu = (node) => {
383383
this.innerMenu = node;
384384
};
385385

@@ -427,7 +427,7 @@ class Menu extends React.Component<MenuProps, MenuState> {
427427

428428
return (
429429
<Provider store={this.store}>
430-
<SubPopupMenu {...props as any} ref={this.setInnerMenu}>
430+
<SubPopupMenu {...(props as any)} ref={this.setInnerMenu}>
431431
{this.props.children}
432432
</SubPopupMenu>
433433
</Provider>

src/MenuItem.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import classNames from 'classnames';
44
import omit from 'rc-util/lib/omit';
55
import { connect } from 'mini-store';
66
import { noop, menuAllProps } from './util';
7-
import {
7+
import type {
88
SelectEventHandler,
99
HoverEventHandler,
1010
DestroyEventHandler,
@@ -91,7 +91,7 @@ export class MenuItem extends React.Component<MenuItemProps> {
9191
return undefined;
9292
};
9393

94-
onMouseLeave: React.MouseEventHandler<HTMLElement> = e => {
94+
onMouseLeave: React.MouseEventHandler<HTMLElement> = (e) => {
9595
const { eventKey, onItemHover, onMouseLeave } = this.props;
9696
onItemHover({
9797
key: eventKey,
@@ -103,7 +103,7 @@ export class MenuItem extends React.Component<MenuItemProps> {
103103
});
104104
};
105105

106-
onMouseEnter: React.MouseEventHandler<HTMLElement> = e => {
106+
onMouseEnter: React.MouseEventHandler<HTMLElement> = (e) => {
107107
const { eventKey, onItemHover, onMouseEnter } = this.props;
108108
onItemHover({
109109
key: eventKey,
@@ -115,7 +115,7 @@ export class MenuItem extends React.Component<MenuItemProps> {
115115
});
116116
};
117117

118-
onClick: React.MouseEventHandler<HTMLElement> = e => {
118+
onClick: React.MouseEventHandler<HTMLElement> = (e) => {
119119
const {
120120
eventKey,
121121
multiple,
@@ -221,7 +221,7 @@ export class MenuItem extends React.Component<MenuItemProps> {
221221
style.paddingLeft = props.inlineIndent * props.level;
222222
}
223223
}
224-
menuAllProps.forEach(key => delete props[key]);
224+
menuAllProps.forEach((key) => delete props[key]);
225225
delete props.direction;
226226
let icon = this.props.itemIcon;
227227
if (typeof this.props.itemIcon === 'function') {
@@ -251,7 +251,11 @@ export class MenuItem extends React.Component<MenuItemProps> {
251251
const connected = connect<any, any, any>(
252252
({ activeKey, selectedKeys }, { eventKey, subMenuKey }) => ({
253253
active: activeKey[subMenuKey] === eventKey,
254-
isSelected: selectedKeys.indexOf(eventKey) !== -1,
254+
// selectedKeys should be array in any circumstance
255+
// when it is not, we have fallback logic for https://github.com/ant-design/ant-design/issues/29430
256+
isSelected: Array.isArray(selectedKeys)
257+
? selectedKeys.indexOf(eventKey) !== -1
258+
: selectedKeys === eventKey,
255259
}),
256260
)(MenuItem);
257261

src/MenuItemGroup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { menuAllProps } from './util';
3-
import { MenuClickEventHandler } from './interface';
3+
import type { MenuClickEventHandler } from './interface';
44

55
export interface MenuItemGroupProps {
66
disabled?: boolean;
@@ -36,7 +36,7 @@ class MenuItemGroup extends React.Component<MenuItemGroupProps> {
3636
const titleClassName = `${rootPrefixCls}-item-group-title`;
3737
const listClassName = `${rootPrefixCls}-item-group-list`;
3838
const { title, children } = props;
39-
menuAllProps.forEach(key => delete props[key]);
39+
menuAllProps.forEach((key) => delete props[key]);
4040

4141
// Set onClick to null, to ignore propagated onClick event
4242
delete props.onClick;

src/SubMenu.tsx

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@ import * as ReactDOM from 'react-dom';
33
import Trigger from 'rc-trigger';
44
import raf from 'rc-util/lib/raf';
55
import KeyCode from 'rc-util/lib/KeyCode';
6-
import CSSMotion, { CSSMotionProps } from 'rc-motion';
6+
import type { CSSMotionProps } from 'rc-motion';
7+
import CSSMotion from 'rc-motion';
78
import classNames from 'classnames';
89
import { connect } from 'mini-store';
9-
import SubPopupMenu, { SubPopupMenuProps } from './SubPopupMenu';
10+
import type { SubPopupMenuProps } from './SubPopupMenu';
11+
import SubPopupMenu from './SubPopupMenu';
1012
import { placements, placementsRtl } from './placements';
1113
import {
1214
noop,
1315
loopMenuItemRecursively,
1416
getMenuIdFromSubMenuEventKey,
1517
menuAllProps,
1618
} from './util';
17-
import {
19+
import type {
1820
MiniStore,
1921
RenderIconType,
2022
LegacyFunctionRef,
@@ -29,7 +31,7 @@ import {
2931
TriggerSubMenuAction,
3032
HoverEventHandler,
3133
} from './interface';
32-
import { MenuItem } from './MenuItem';
34+
import type { MenuItem } from './MenuItem';
3335

3436
let guid = 0;
3537

@@ -232,7 +234,7 @@ export class SubMenu extends React.Component<SubMenuProps, SubMenuState> {
232234
* This legacy code that `onKeyDown` is called by parent instead of dom self.
233235
* which need return code to check if this event is handled
234236
*/
235-
onKeyDown: React.KeyboardEventHandler<HTMLElement> = e => {
237+
onKeyDown: React.KeyboardEventHandler<HTMLElement> = (e) => {
236238
const { keyCode } = e;
237239
const menu = this.menuInstance;
238240
const { store } = this.props;
@@ -275,15 +277,15 @@ export class SubMenu extends React.Component<SubMenuProps, SubMenuState> {
275277
return undefined;
276278
};
277279

278-
onOpenChange: OpenEventHandler = e => {
280+
onOpenChange: OpenEventHandler = (e) => {
279281
this.props.onOpenChange(e);
280282
};
281283

282284
onPopupVisibleChange = (visible: boolean) => {
283285
this.triggerOpenChange(visible, visible ? 'mouseenter' : 'mouseleave');
284286
};
285287

286-
onMouseEnter: React.MouseEventHandler<HTMLElement> = e => {
288+
onMouseEnter: React.MouseEventHandler<HTMLElement> = (e) => {
287289
const { eventKey: key, onMouseEnter, store } = this.props;
288290
updateDefaultActiveFirst(store, this.props.eventKey, false);
289291
onMouseEnter({
@@ -292,7 +294,7 @@ export class SubMenu extends React.Component<SubMenuProps, SubMenuState> {
292294
});
293295
};
294296

295-
onMouseLeave: React.MouseEventHandler<HTMLElement> = e => {
297+
onMouseLeave: React.MouseEventHandler<HTMLElement> = (e) => {
296298
const { parentMenu, eventKey, onMouseLeave } = this.props;
297299
parentMenu.subMenuInstance = this;
298300
onMouseLeave({
@@ -301,7 +303,7 @@ export class SubMenu extends React.Component<SubMenuProps, SubMenuState> {
301303
});
302304
};
303305

304-
onTitleMouseEnter: React.MouseEventHandler<HTMLElement> = domEvent => {
306+
onTitleMouseEnter: React.MouseEventHandler<HTMLElement> = (domEvent) => {
305307
const { eventKey: key, onItemHover, onTitleMouseEnter } = this.props;
306308
onItemHover({
307309
key,
@@ -313,7 +315,7 @@ export class SubMenu extends React.Component<SubMenuProps, SubMenuState> {
313315
});
314316
};
315317

316-
onTitleMouseLeave: React.MouseEventHandler<HTMLElement> = e => {
318+
onTitleMouseLeave: React.MouseEventHandler<HTMLElement> = (e) => {
317319
const { parentMenu, eventKey, onItemHover, onTitleMouseLeave } = this.props;
318320
parentMenu.subMenuInstance = this;
319321
onItemHover({
@@ -349,11 +351,11 @@ export class SubMenu extends React.Component<SubMenuProps, SubMenuState> {
349351
}
350352
};
351353

352-
onSelect: SelectEventHandler = info => {
354+
onSelect: SelectEventHandler = (info) => {
353355
this.props.onSelect(info);
354356
};
355357

356-
onDeselect: SelectEventHandler = info => {
358+
onDeselect: SelectEventHandler = (info) => {
357359
this.props.onDeselect(info);
358360
};
359361

@@ -649,12 +651,12 @@ export class SubMenu extends React.Component<SubMenuProps, SubMenuState> {
649651
subMenuCloseDelay,
650652
builtinPlacements,
651653
} = props;
652-
menuAllProps.forEach(key => delete props[key]);
654+
menuAllProps.forEach((key) => delete props[key]);
653655
// Set onClick to null, to ignore propagated onClick event
654656
delete props.onClick;
655657
const placement = isRTL
656-
? Object.assign({}, placementsRtl, builtinPlacements)
657-
: Object.assign({}, placements, builtinPlacements);
658+
? { ...placementsRtl, ...builtinPlacements }
659+
: { ...placements, ...builtinPlacements };
658660
delete props.direction;
659661

660662
// [Legacy] It's a fast fix,

0 commit comments

Comments
 (0)