forked from alibaba-fusion/next
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nav.jsx
277 lines (258 loc) · 9.15 KB
/
nav.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import ConfigProvider from '../config-provider';
import Menu from '../menu';
/**
* Nav
* @description 继承自 `Menu` 的能力请查看 `Menu` 文档
*/
class Nav extends Component {
static propTypes = {
prefix: PropTypes.string,
pure: PropTypes.bool,
rtl: PropTypes.bool,
className: PropTypes.string,
style: PropTypes.object,
/**
* 导航项和子导航
*/
children: PropTypes.node,
/**
* 导航类型
* @enumdesc 普通, 主要, 次要, 线形
*/
type: PropTypes.oneOf(['normal', 'primary', 'secondary', 'line']),
/**
* 导航布局
* @enumdesc 水平, 垂直
*/
direction: PropTypes.oneOf(['hoz', 'ver']),
/**
* 横向导航条 items 和 footer 的对齐方向,在 direction 设置为 'hoz' 并且 header 存在时生效
*/
hozAlign: PropTypes.oneOf(['left', 'right']),
/**
* 设置组件选中状态的 active 边方向
* @enumdesc 无, 上, 下, 左, 右
* @default 当 direction 为 'hoz' 时,默认值为 'bottom',当 direction 为 'ver' 时,默认值为 'left'
*/
activeDirection: PropTypes.oneOf([null, 'top', 'bottom', 'left', 'right']),
/**
* 子导航打开的模式(水平导航只支持弹出)
* @eumdesc 行内, 弹出
*/
mode: PropTypes.oneOf(['inline', 'popup']),
/**
* 子导航打开的触发方式
*/
triggerType: PropTypes.oneOf(['click', 'hover']),
/**
* 内联子导航缩进距离
*/
inlineIndent: PropTypes.number,
/**
* 首次渲染展开所有的子导航,只在 mode 设置为 'inline' 以及 openMode 设置为 'multiple' 下生效
*/
defaultOpenAll: PropTypes.bool,
/**
* 内联子导航的展开模式,同时可以展开一个同级子导航还是多个同级子导航,该属性仅在 mode 为 inline 时生效
* @eumdesc 一个, 多个
*/
openMode: PropTypes.oneOf(['single', 'multiple']),
/**
* 当前选中导航项的 key 值
*/
selectedKeys: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
/**
* 初始选中导航项的 key 值
*/
defaultSelectedKeys: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
/**
* 选中或取消选中导航项触发的回调函数
* @param {Array} selectedKeys 选中的所有导航项的 key
* @param {Object} item 选中或取消选中的导航项
* @param {Object} extra 额外参数
* @param {Boolean} extra.select 是否是选中
* @param {Array} extra.key 导航项的 key
* @param {Object} extra.label 导航项的文本
* @param {Array} extra.keyPath 导航项 key 的路径
*/
onSelect: PropTypes.func,
/**
* 弹出子导航的对齐方式(水平导航只支持 follow )
* @eumdesc Item 顶端对齐, Nav 顶端对齐
*/
popupAlign: PropTypes.oneOf(['follow', 'outside']),
/**
* 弹出子导航的自定义类名
*/
popupClassName: PropTypes.string,
/**
* 是否只显示图标
*/
iconOnly: PropTypes.bool,
/**
* iconOnly 模式下的宽度(仅在 iconOnly=true 时生效) 如果传入了iconOnlyWidth,那么会隐藏文本,例如 Nav.Item 的 label
*/
iconOnlyWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/**
* iconOnly模式下是否展示文字(仅在 iconOnly=true 时生效)
*/
iconTextOnly: PropTypes.bool,
/**
* 是否显示右侧的箭头(仅在 iconOnly=true 时生效)
*/
hasArrow: PropTypes.bool,
/**
* 是否有 ToolTips (仅在 iconOnly=true 时生效)
*/
hasTooltip: PropTypes.bool,
/**
* 自定义导航头部
*/
header: PropTypes.node,
/**
* 自定义导航尾部
*/
footer: PropTypes.node,
/**
* 是否开启嵌入式模式,一般用于Layout的布局中,开启后没有默认背景、外层border、box-shadow,可以配合`<Nav style={{lineHeight: '100px'}}>` 自定义高度
* @version 1.18
*/
embeddable: PropTypes.bool,
popupProps: PropTypes.object,
};
static defaultProps = {
prefix: 'next-',
pure: false,
type: 'normal',
direction: 'ver',
hozAlign: 'left',
mode: 'inline',
triggerType: 'click',
inlineIndent: 20,
defaultOpenAll: false,
openMode: 'multiple',
defaultSelectedKeys: [],
popupAlign: 'follow',
hasTooltip: false,
embeddable: false,
hasArrow: true,
popupProps: {},
};
static childContextTypes = {
prefix: PropTypes.string,
mode: PropTypes.string,
iconOnly: PropTypes.bool,
iconOnlyWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
iconTextOnly: PropTypes.bool,
hasTooltip: PropTypes.bool,
hasArrow: PropTypes.bool,
};
static contextTypes = {
isCollapse: PropTypes.bool,
};
constructor(props) {
super(props);
this.getMenuRef = this.getMenuRef.bind(this);
}
getChildContext() {
const { prefix, direction, mode, iconOnly, iconOnlyWidth, iconTextOnly, hasTooltip, hasArrow } = this.props;
const { isCollapse } = this.context;
return {
prefix,
mode: direction === 'hoz' ? 'popup' : mode,
iconOnly: 'iconOnly' in this.props ? iconOnly : isCollapse,
iconOnlyWidth: 'iconOnlyWidth' in this.props ? iconOnlyWidth : undefined,
iconTextOnly,
hasTooltip,
hasArrow,
};
}
getMenuRef(ref) {
this.menu = ref;
}
render() {
// eslint-disable-next-line
const {
prefix,
className,
style,
children,
type,
direction,
activeDirection,
mode,
triggerType,
inlineIndent,
openMode,
popupAlign,
popupClassName,
iconOnly,
iconOnlyWidth,
iconTextOnly,
hasArrow,
hasTooltip,
embeddable,
popupProps,
rtl,
...others
} = this.props;
const { isCollapse } = this.context;
const newIconOnly = 'iconOnly' in this.props ? iconOnly : isCollapse;
let realActiveDirection = activeDirection;
if (
realActiveDirection &&
((direction === 'hoz' && (realActiveDirection === 'left' || realActiveDirection === 'right')) ||
(direction === 'ver' && (realActiveDirection === 'top' || realActiveDirection === 'bottom')))
) {
realActiveDirection = null;
}
if (!newIconOnly && realActiveDirection === undefined) {
realActiveDirection = direction === 'hoz' ? 'bottom' : type === 'line' ? 'right' : 'left';
}
const cls = classNames({
[`${prefix}nav`]: true,
[`${prefix}${type}`]: type,
[`${prefix}active`]: realActiveDirection,
[`${prefix}${realActiveDirection}`]: realActiveDirection,
[`${prefix}icon-only`]: newIconOnly,
[`${prefix}icon-only-text`]: newIconOnly && iconTextOnly,
[`${prefix}custom-icon-only-width`]: newIconOnly && 'iconOnlyWidth' in this.props,
[`${prefix}no-arrow`]: !hasArrow,
[`${prefix}nav-embeddable`]: embeddable,
[className]: !!className,
});
const newStyle = newIconOnly ? { ...style, width: iconOnlyWidth || 58 } : style;
const props = {
prefix,
direction,
openMode,
triggerType,
mode: direction === 'hoz' ? 'popup' : mode,
popupAlign: direction === 'hoz' ? 'follow' : popupAlign,
inlineIndent: newIconOnly ? 0 : inlineIndent,
hasSelectedIcon: false,
popupAutoWidth: true,
selectMode: 'single',
itemClassName: `${prefix}nav-item`,
popupClassName: classNames({
[cls.replace(`${prefix}icon-only`, '').replace(`${prefix}nav-embeddable`, '')]: mode === 'popup',
[`${prefix}icon-only`]: newIconOnly && mode === 'inline',
[popupClassName]: !!popupClassName,
}),
popupProps: () => {
return {
...popupProps,
};
},
};
return (
<Menu className={cls} style={newStyle} {...props} {...others} ref={this.getMenuRef}>
{children}
</Menu>
);
}
}
export default ConfigProvider.config(Nav);