-
-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support custom arrow icon in vertical and inline mode. #182
Changes from 11 commits
6de7d05
c0379c6
9468e29
00f4c2f
4efb5c8
d0ecaf6
474b1e3
a6e6434
f4d4650
b8f7e61
b421fa4
fc36cd9
98d394d
d27ee52
af3fdce
c87971e
952f5b6
3885f3c
c8ca3d7
34356d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -192,6 +192,18 @@ ReactDOM.render(<Menu> | |
<th>see <a href="./src/placements.jsx">placements.jsx</a></th> | ||
<td>Describes how the popup menus should be positioned</td> | ||
</tr> | ||
<tr> | ||
<td>itemIcon</td> | ||
<td>(props: MenuItemProps) => ReactNode</td> | ||
<th></th> | ||
<td>specific the menu item icon.</td> | ||
</tr> | ||
<tr> | ||
<td>expandIcon</td> | ||
<td>(props: SubMenuProps) => ReactNode</td> | ||
<th></th> | ||
<td>specific the menu item icon.</td> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SubMenu There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Specify expanded icon for |
||
</tr> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
</tbody> | ||
</table> | ||
|
||
|
@@ -237,6 +249,12 @@ ReactDOM.render(<Menu> | |
<th></th> | ||
<td></td> | ||
</tr> | ||
<tr> | ||
<td>itemIcon</td> | ||
<td>(props: MenuItemProps) => ReactNode</td> | ||
<th></th> | ||
<td>specific the menu item icon.</td> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Specify icon for menu item. |
||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
|
@@ -313,6 +331,18 @@ ReactDOM.render(<Menu> | |
<th></th> | ||
<td>The offset of the popup submenu, in an x, y coordinate array. e.g.: `[0,15]`</td> | ||
</tr> | ||
<tr> | ||
<td>expandIcon</td> | ||
<td>(props: SubMenuProps) => ReactNode</td> | ||
<th></th> | ||
<td>specific the menu item icon.</td> | ||
</tr> | ||
<tr> | ||
<td>itemIcon</td> | ||
<td>(props: SubMenuProps & { isSubMenu: boolean }) => ReactNode</td> | ||
<th></th> | ||
<td>specific the menu item icon.</td> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 同上 |
||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
/* eslint no-console:0 */ | ||
import * as React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import PropTypes from 'prop-types'; | ||
import Menu, { SubMenu, Item as MenuItem, Divider } from 'rc-menu'; | ||
import 'rc-menu/assets/index.less'; | ||
import animate from 'css-animation'; | ||
|
||
const getSvgIcon = (style = {}, text) => { | ||
if (text) { | ||
return ( | ||
<i style={style}> | ||
{text} | ||
</i> | ||
); | ||
} | ||
const path = 'M869 487.8L491.2 159.9c-2.9-2.5-6.6-3.9-10.5-3.9h' + | ||
'-88.5c-7.4 0-10.8 9.2-5.2 14l350.2 304H152c-4.4 0-8 3.6-8 8v' + | ||
'60c0 4.4 3.6 8 8 8h585.1L386.9 854c-5.6 4.9-2.2 14 5.2 14h91' + | ||
'.5c1.9 0 3.8-0.7 5.2-2L869 536.2c14.7-12.8 14.7-35.6 0-48.4z'; | ||
return ( | ||
<i style={style}> | ||
<svg | ||
viewBox="0 0 1024 1024" | ||
width="1em" | ||
height="1em" | ||
fill="currentColor" | ||
style={{ verticalAlign: '-.125em' }} | ||
> | ||
<path d={path} /> | ||
</svg> | ||
</i> | ||
); | ||
}; | ||
|
||
function itemIcon(props) { | ||
return getSvgIcon({ | ||
position: 'absolute', | ||
right: '1rem', | ||
color: props.isSelected ? 'pink' : 'inherit', | ||
}); | ||
} | ||
|
||
function expandIcon(props) { | ||
return getSvgIcon({ | ||
position: 'absolute', | ||
right: '1rem', | ||
color: 'lightblue', | ||
transform: `rotate(${props.isOpen ? 90 : 0}deg)`, | ||
}); | ||
} | ||
|
||
const animation = { | ||
enter(node, done) { | ||
let height; | ||
return animate(node, 'rc-menu-collapse', { | ||
start() { | ||
height = node.offsetHeight; | ||
node.style.height = 0; | ||
}, | ||
active() { | ||
node.style.height = `${height}px`; | ||
}, | ||
end() { | ||
node.style.height = ''; | ||
done(); | ||
}, | ||
}); | ||
}, | ||
|
||
appear() { | ||
return this.enter.apply(this, arguments); | ||
}, | ||
|
||
leave(node, done) { | ||
return animate(node, 'rc-menu-collapse', { | ||
start() { | ||
node.style.height = `${node.offsetHeight}px`; | ||
}, | ||
active() { | ||
node.style.height = 0; | ||
}, | ||
end() { | ||
node.style.height = ''; | ||
done(); | ||
}, | ||
}); | ||
}, | ||
}; | ||
|
||
class Demo extends React.Component { | ||
|
||
static childContextTypes = { | ||
expandIcon: PropTypes.func, | ||
itemIcon: PropTypes.func, | ||
} | ||
|
||
state = { | ||
useContext: false, | ||
}; | ||
|
||
getChildContext() { | ||
if (!this.state.useContext) { | ||
return {}; | ||
} | ||
return { | ||
expandIcon: (props) => getSvgIcon({ | ||
position: 'absolute', | ||
right: '1rem', | ||
color: 'lightblue', | ||
transform: `rotate(${props.isOpen ? 90 : 0}deg)`, | ||
}, '>>'), | ||
itemIcon: (props) => getSvgIcon({ | ||
position: 'absolute', | ||
right: '1rem', | ||
color: props.isSelected ? 'pink' : 'inherit', | ||
}, '--'), | ||
}; | ||
} | ||
|
||
onOpenChange = (value) => { | ||
console.log('onOpenChange', value); | ||
} | ||
|
||
handleClick = (info) => { | ||
console.log(`clicked ${info.key}`); | ||
console.log(info); | ||
} | ||
|
||
toggleContext = () => { | ||
this.setState({ | ||
useContext: !this.state.useContext, | ||
}); | ||
} | ||
|
||
renderNestSubMenu = (props = {}) => { | ||
return ( | ||
<SubMenu title={<span>offset sub menu 2</span>} key="4" popupOffset={[10, 15]} {...props}> | ||
<MenuItem key="4-1">inner inner</MenuItem> | ||
<Divider /> | ||
<SubMenu | ||
key="4-2" | ||
title={<span>sub menu 3</span>} | ||
> | ||
<SubMenu title="sub 4-2-0" key="4-2-0"> | ||
<MenuItem key="4-2-0-1">inner inner</MenuItem> | ||
<MenuItem key="4-2-0-2">inner inner2</MenuItem> | ||
</SubMenu> | ||
<MenuItem key="4-2-1">inn</MenuItem> | ||
<SubMenu title={<span>sub menu 4</span>} key="4-2-2"> | ||
<MenuItem key="4-2-2-1">inner inner</MenuItem> | ||
<MenuItem key="4-2-2-2">inner inner2</MenuItem> | ||
</SubMenu> | ||
<SubMenu title="sub 4-2-3" key="4-2-3"> | ||
<MenuItem key="4-2-3-1">inner inner</MenuItem> | ||
<MenuItem key="4-2-3-2">inner inner2</MenuItem> | ||
</SubMenu> | ||
</SubMenu> | ||
</SubMenu> | ||
); | ||
} | ||
|
||
renderCommonMenu = (props = {}) => { | ||
return ( | ||
<Menu onClick={this.handleClick} onOpenChange={this.onOpenChange} {...props}> | ||
<SubMenu title={<span>sub menu</span>} key="1"> | ||
<MenuItem key="1-1">0-1</MenuItem> | ||
<MenuItem key="1-2">0-2</MenuItem> | ||
</SubMenu> | ||
{this.renderNestSubMenu()} | ||
<MenuItem key="2">1</MenuItem> | ||
<MenuItem key="3">outer</MenuItem> | ||
<MenuItem disabled>disabled</MenuItem> | ||
<MenuItem key="5">outer3</MenuItem> | ||
</Menu> | ||
); | ||
} | ||
|
||
render() { | ||
const verticalMenu = this.renderCommonMenu({ | ||
mode: 'vertical', | ||
openAnimation: 'zoom', | ||
itemIcon, | ||
expandIcon, | ||
}); | ||
|
||
const inlineMenu = this.renderCommonMenu({ | ||
mode: 'inline', | ||
defaultOpenKeys: ['1'], | ||
openAnimation: animation, | ||
itemIcon, | ||
expandIcon, | ||
}); | ||
|
||
return ( | ||
<div style={{ margin: 20 }}> | ||
<h2>Antd menu - custom icon</h2> | ||
<div> | ||
<input | ||
type="checkbox" | ||
checked={this.state.useContext} | ||
onChange={this.toggleContext} | ||
/> use context | ||
</div> | ||
<div> | ||
<h3>vertical</h3> | ||
<div style={{ margin: 20, width: 200 }}>{verticalMenu}</div> | ||
<h3>inline</h3> | ||
<div style={{ margin: 20, width: 400 }}>{inlineMenu}</div> | ||
</div> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
ReactDOM.render(<Demo />, document.getElementById('__react-content')); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,8 +32,15 @@ class Menu extends React.Component { | |
activeKey: PropTypes.string, | ||
prefixCls: PropTypes.string, | ||
builtinPlacements: PropTypes.object, | ||
itemIcon: PropTypes.func, | ||
expandIcon: PropTypes.func, | ||
}; | ||
|
||
static contextTypes = { | ||
itemIcon: PropTypes.func, | ||
expandIcon: PropTypes.func, | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. context 应该去掉? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
static defaultProps = { | ||
selectable: true, | ||
onClick: noop, | ||
|
@@ -195,6 +202,10 @@ class Menu extends React.Component { | |
|
||
render() { | ||
let { ...props } = this.props; | ||
const { | ||
itemIcon: itemIconFromCtx, | ||
expandIcon: expandIconFromCtx, | ||
} = this.context; | ||
props.className += ` ${props.prefixCls}-root`; | ||
props = { | ||
...props, | ||
|
@@ -204,6 +215,8 @@ class Menu extends React.Component { | |
onSelect: this.onSelect, | ||
openTransitionName: this.getOpenTransitionName(), | ||
parentMenu: this, | ||
itemIcon: itemIconFromCtx || props.itemIcon, | ||
expandIcon: expandIconFromCtx || props.expandIcon, | ||
}; | ||
return ( | ||
<Provider store={this.store}> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,8 @@ export class SubMenu extends React.Component { | |
store: PropTypes.object, | ||
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']), | ||
manualRef: PropTypes.func, | ||
expandIcon: PropTypes.func, | ||
itemIcon: PropTypes.func, | ||
}; | ||
|
||
static defaultProps = { | ||
|
@@ -366,6 +368,8 @@ export class SubMenu extends React.Component { | |
prefixCls: props.rootPrefixCls, | ||
id: this._menuId, | ||
manualRef: this.saveMenuInstance, | ||
itemIcon: props.itemIcon, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 多余的? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SubMenu也类似Menu一样,需要ItemIcon传给children中的MenuItem。 |
||
expandIcon: props.expandIcon, | ||
}; | ||
|
||
const haveRendered = this.haveRendered; | ||
|
@@ -461,6 +465,13 @@ export class SubMenu extends React.Component { | |
}; | ||
} | ||
|
||
// expand custom icon should NOT be displayed in menu with horizontal mode. | ||
let icon = null; | ||
if (props.mode !== 'horizontal') { | ||
icon = typeof this.props.expandIcon === 'function' ? | ||
React.createElement(this.props.expandIcon, { ...this.props, isSubMenu: true }) : null; | ||
} | ||
|
||
const title = ( | ||
<div | ||
ref={this.saveSubMenuTitle} | ||
|
@@ -474,7 +485,7 @@ export class SubMenu extends React.Component { | |
title={typeof props.title === 'string' ? props.title : undefined} | ||
> | ||
{props.title} | ||
<i className={`${prefixCls}-arrow`} /> | ||
{icon || <i className={`${prefixCls}-arrow`} />} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个 icon 应该只给 MenuItem 用吧 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
</div> | ||
); | ||
const children = this.renderChildren(props.children); | ||
|
@@ -529,7 +540,10 @@ export class SubMenu extends React.Component { | |
} | ||
} | ||
|
||
const connected = connect(({ openKeys, activeKey, selectedKeys }, { eventKey, subMenuKey }) => ({ | ||
const connected = connect(( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 无关的提交 |
||
{ openKeys, activeKey, selectedKeys }, | ||
{ eventKey, subMenuKey } | ||
) => ({ | ||
isOpen: openKeys.indexOf(eventKey) > -1, | ||
active: activeKey[subMenuKey] === eventKey, | ||
selectedKeys, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specify icon for menu item.