Skip to content

Commit e549774

Browse files
committed
Change the selectedItem state to keep the index instead of the React element
1 parent 99a9f77 commit e549774

File tree

1 file changed

+56
-29
lines changed

1 file changed

+56
-29
lines changed

src/AbstractMenu.js

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -131,50 +131,77 @@ export default class AbstractMenu extends Component {
131131
return i === currentIndex ? null : i;
132132
}
133133

134-
const currentIndex = children.indexOf(selectedItem);
134+
const currentIndex = selectedItem ? selectedItem.index : -1;
135135
const nextEnabledChildIndex = findNextEnabledChildIndex(currentIndex);
136136

137137
if (nextEnabledChildIndex !== null) {
138138
this.setState({
139-
selectedItem: children[nextEnabledChildIndex],
139+
selectedItem: {
140+
index: nextEnabledChildIndex,
141+
// We need to know the type of the selected item, so we can
142+
// check it during render and tryToOpenSubMenu.
143+
type: children[nextEnabledChildIndex].type
144+
},
140145
forceSubMenuOpen: false
141146
});
142147
}
143148
};
144149

145-
onChildMouseMove = (child) => {
146-
if (this.state.selectedItem !== child) {
147-
this.setState({ selectedItem: child, forceSubMenuOpen: false });
150+
onChildMouseMove = (child, itemIndex) => {
151+
if (this.state.selectedItem === null || this.state.selectedItem.index !== itemIndex) {
152+
this.setState({
153+
selectedItem: {
154+
index: itemIndex,
155+
type: child.type
156+
},
157+
forceSubMenuOpen: false
158+
});
148159
}
149160
};
150161

151162
onChildMouseLeave = () => {
152163
this.setState({ selectedItem: null, forceSubMenuOpen: false });
153164
};
154165

155-
renderChildren = children => React.Children.map(children, (child) => {
156-
const props = {};
157-
if (!React.isValidElement(child)) return child;
158-
if ([MenuItem, this.getSubMenuType()].indexOf(child.type) < 0) {
159-
// Maybe the MenuItem or SubMenu is capsuled in a wrapper div or something else
160-
props.children = this.renderChildren(child.props.children);
161-
return React.cloneElement(child, props);
162-
}
163-
props.onMouseLeave = this.onChildMouseLeave.bind(this);
164-
if (child.type === this.getSubMenuType()) {
165-
// special props for SubMenu only
166-
props.forceOpen = this.state.forceSubMenuOpen && (this.state.selectedItem === child);
167-
props.forceClose = this.handleForceClose;
168-
props.parentKeyNavigationHandler = this.handleKeyNavigation;
169-
}
170-
if (!child.props.divider && this.state.selectedItem === child) {
171-
// special props for selected item only
172-
props.selected = true;
173-
props.ref = (ref) => { this.seletedItemRef = ref; };
166+
renderChildren = (children, childIndexRef = { value: -1 }) =>
167+
React.Children.map(children, (child) => {
168+
let currentChildIndexRef = childIndexRef;
169+
const props = {};
170+
if (!React.isValidElement(child)) return child;
171+
172+
if ([MenuItem, this.getSubMenuType()].indexOf(child.type) < 0) {
173+
// Maybe the MenuItem or SubMenu is capsuled in a wrapper div or something else
174+
props.children = this.renderChildren(child.props.children, currentChildIndexRef);
175+
return React.cloneElement(child, props);
176+
}
177+
178+
// At this point we know that this is a menu item and we are going to
179+
// render it. We need to increment the child index and assign it as
180+
// the item index.
181+
let itemIndex = null;
182+
if (!child.props.divider) {
183+
// A MenuItem can be a divider. Do not increment the value if it's.
184+
itemIndex = ++currentChildIndexRef.value;
185+
}
186+
187+
props.onMouseLeave = this.onChildMouseLeave.bind(this);
188+
if (child.type === this.getSubMenuType()) {
189+
// special props for SubMenu only
190+
props.forceOpen = this.state.forceSubMenuOpen &&
191+
(this.state.selectedItem && this.state.selectedItem.index === itemIndex);
192+
props.forceClose = this.handleForceClose;
193+
props.parentKeyNavigationHandler = this.handleKeyNavigation;
194+
}
195+
if (!child.props.divider &&
196+
(this.state.selectedItem && this.state.selectedItem.index === itemIndex)) {
197+
// special props for selected item only
198+
props.selected = true;
199+
props.ref = (ref) => { this.seletedItemRef = ref; };
200+
return React.cloneElement(child, props);
201+
}
202+
203+
// onMouseMove is only needed for non selected items
204+
props.onMouseMove = () => this.onChildMouseMove(child, itemIndex);
174205
return React.cloneElement(child, props);
175-
}
176-
// onMouseMove is only needed for non selected items
177-
props.onMouseMove = () => this.onChildMouseMove(child);
178-
return React.cloneElement(child, props);
179-
});
206+
});
180207
}

0 commit comments

Comments
 (0)