11import React from 'react' ;
22import ReactDOM from 'react-dom' ;
3- import PropTypes from 'prop-types' ;
43import ResizeObserver from 'resize-observer-polyfill' ;
54import SubMenu from './SubMenu' ;
65import { getWidth , setStyle , menuAllProps } from './util' ;
6+ import { MenuMode } from './interface' ;
77
88const canUseDOM = ! ! (
99 typeof window !== 'undefined' &&
@@ -20,15 +20,53 @@ if (canUseDOM) {
2020 require ( 'mutationobserver-shim' ) ;
2121}
2222
23- class DOMWrap extends React . Component {
24- state = {
23+ interface DOMWrapProps {
24+ className ?: string ;
25+ children ?: React . ReactElement [ ] ;
26+ mode ?: MenuMode ;
27+ prefixCls ?: string ;
28+ level ?: number ;
29+ theme ?: string ;
30+ overflowedIndicator ?: React . ReactNode ;
31+ visible ?: boolean ;
32+ hiddenClassName ?: string ;
33+ tag ?: string ;
34+ style ?: React . CSSProperties ;
35+ }
36+
37+ interface DOMWrapState {
38+ lastVisibleIndex : number ;
39+ }
40+
41+ class DOMWrap extends React . Component < DOMWrapProps , DOMWrapState > {
42+ static defaultProps = {
43+ tag : 'div' ,
44+ className : '' ,
45+ } ;
46+
47+ overflowedIndicatorWidth : number ;
48+
49+ resizeObserver = null ;
50+
51+ mutationObserver = null ;
52+
53+ // original scroll size of the list
54+ originalTotalWidth = 0 ;
55+
56+ // copy of overflowed items
57+ overflowedItems : React . ReactElement [ ] = [ ] ;
58+
59+ // cache item of the original items (so we can track the size and order)
60+ menuItemSizes : number [ ] = [ ] ;
61+
62+ state : DOMWrapState = {
2563 lastVisibleIndex : undefined ,
2664 } ;
2765
2866 componentDidMount ( ) {
2967 this . setChildrenWidthAndResize ( ) ;
3068 if ( this . props . level === 1 && this . props . mode === 'horizontal' ) {
31- const menuUl = ReactDOM . findDOMNode ( this ) ;
69+ const menuUl = ReactDOM . findDOMNode ( this ) as HTMLElement ;
3270 if ( ! menuUl ) {
3371 return ;
3472 }
@@ -39,7 +77,7 @@ class DOMWrap extends React.Component {
3977 [ ] . slice
4078 . call ( menuUl . children )
4179 . concat ( menuUl )
42- . forEach ( el => {
80+ . forEach ( ( el : HTMLElement ) => {
4381 this . resizeObserver . observe ( el ) ;
4482 } ) ;
4583
@@ -49,7 +87,7 @@ class DOMWrap extends React.Component {
4987 [ ] . slice
5088 . call ( menuUl . children )
5189 . concat ( menuUl )
52- . forEach ( el => {
90+ . forEach ( ( el : HTMLElement ) => {
5391 this . resizeObserver . observe ( el ) ;
5492 } ) ;
5593 this . setChildrenWidthAndResize ( ) ;
@@ -73,9 +111,9 @@ class DOMWrap extends React.Component {
73111 }
74112
75113 // get all valid menuItem nodes
76- getMenuItemNodes = ( ) => {
114+ getMenuItemNodes = ( ) : HTMLElement [ ] => {
77115 const { prefixCls } = this . props ;
78- const ul = ReactDOM . findDOMNode ( this ) ;
116+ const ul = ReactDOM . findDOMNode ( this ) as HTMLElement ;
79117 if ( ! ul ) {
80118 return [ ] ;
81119 }
@@ -84,17 +122,17 @@ class DOMWrap extends React.Component {
84122 return [ ] . slice
85123 . call ( ul . children )
86124 . filter (
87- node =>
125+ ( node : HTMLElement ) =>
88126 node . className . split ( ' ' ) . indexOf ( `${ prefixCls } -overflowed-submenu` ) <
89127 0 ,
90128 ) ;
91129 } ;
92130
93131 getOverflowedSubMenuItem = (
94- keyPrefix ,
95- overflowedItems ,
96- renderPlaceholder ,
97- ) => {
132+ keyPrefix : string ,
133+ overflowedItems : React . ReactElement [ ] ,
134+ renderPlaceholder ?: boolean ,
135+ ) : React . ReactElement => {
98136 const { overflowedIndicator, level, mode, prefixCls, theme } = this . props ;
99137 if ( level !== 1 || mode !== 'horizontal' ) {
100138 return null ;
@@ -109,7 +147,7 @@ class DOMWrap extends React.Component {
109147 ...rest
110148 } = copy . props ;
111149
112- let style = { ...propStyle } ;
150+ let style : React . CSSProperties = { ...propStyle } ;
113151 let key = `${ keyPrefix } -overflowed-indicator` ;
114152 let eventKey = `${ keyPrefix } -overflowed-indicator` ;
115153
@@ -158,7 +196,7 @@ class DOMWrap extends React.Component {
158196 if ( this . props . mode !== 'horizontal' ) {
159197 return ;
160198 }
161- const ul = ReactDOM . findDOMNode ( this ) ;
199+ const ul = ReactDOM . findDOMNode ( this ) as HTMLElement ;
162200
163201 if ( ! ul ) {
164202 return ;
@@ -170,8 +208,9 @@ class DOMWrap extends React.Component {
170208 return ;
171209 }
172210
173- const lastOverflowedIndicatorPlaceholder =
174- ul . children [ ulChildrenNodes . length - 1 ] ;
211+ const lastOverflowedIndicatorPlaceholder = ul . children [
212+ ulChildrenNodes . length - 1
213+ ] as HTMLElement ;
175214
176215 // need last overflowed indicator for calculating length;
177216 setStyle ( lastOverflowedIndicatorPlaceholder , 'display' , 'inline-block' ) ;
@@ -194,9 +233,9 @@ class DOMWrap extends React.Component {
194233 overflowedItems . forEach ( c => {
195234 setStyle ( c , 'display' , 'none' ) ;
196235 } ) ;
197- this . overflowedIndicatorWidth = getWidth (
198- ul . children [ ul . children . length - 1 ] ,
199- ) ;
236+ this . overflowedIndicatorWidth = getWidth ( ul . children [
237+ ul . children . length - 1
238+ ] as HTMLElement ) ;
200239 this . originalTotalWidth = this . menuItemSizes . reduce (
201240 ( acc , cur ) => acc + cur ,
202241 0 ,
@@ -206,25 +245,12 @@ class DOMWrap extends React.Component {
206245 setStyle ( lastOverflowedIndicatorPlaceholder , 'display' , 'none' ) ;
207246 } ;
208247
209- resizeObserver = null ;
210-
211- mutationObserver = null ;
212-
213- // original scroll size of the list
214- originalTotalWidth = 0 ;
215-
216- // copy of overflowed items
217- overflowedItems = [ ] ;
218-
219- // cache item of the original items (so we can track the size and order)
220- menuItemSizes = [ ] ;
221-
222248 handleResize = ( ) => {
223249 if ( this . props . mode !== 'horizontal' ) {
224250 return ;
225251 }
226252
227- const ul = ReactDOM . findDOMNode ( this ) ;
253+ const ul = ReactDOM . findDOMNode ( this ) as HTMLElement ;
228254 if ( ! ul ) {
229255 return ;
230256 }
@@ -234,7 +260,7 @@ class DOMWrap extends React.Component {
234260 let currentSumWidth = 0 ;
235261
236262 // index for last visible child in horizontal mode
237- let lastVisibleIndex ;
263+ let lastVisibleIndex : number ;
238264
239265 // float number comparison could be problematic
240266 // e.g. 0.1 + 0.2 > 0.3 =====> true
@@ -253,60 +279,73 @@ class DOMWrap extends React.Component {
253279 this . setState ( { lastVisibleIndex } ) ;
254280 } ;
255281
256- renderChildren ( children ) {
282+ renderChildren ( children : React . ReactElement [ ] ) {
257283 // need to take care of overflowed items in horizontal mode
258284 const { lastVisibleIndex } = this . state ;
259- return ( children || [ ] ) . reduce ( ( acc , childNode , index ) => {
260- let item = childNode ;
261- if ( this . props . mode === 'horizontal' ) {
262- let overflowed = this . getOverflowedSubMenuItem (
263- childNode . props . eventKey ,
264- [ ] ,
265- ) ;
266- if (
267- lastVisibleIndex !== undefined &&
268- this . props . className . indexOf ( `${ this . props . prefixCls } -root` ) !== - 1
269- ) {
270- if ( index > lastVisibleIndex ) {
271- item = React . cloneElement (
272- childNode ,
273- // 这里修改 eventKey 是为了防止隐藏状态下还会触发 openkeys 事件
274- {
275- style : { display : 'none' } ,
276- eventKey : `${ childNode . props . eventKey } -hidden` ,
277- className : `${ childNode . className } ${ MENUITEM_OVERFLOWED_CLASSNAME } ` ,
278- } ,
279- ) ;
285+ return ( children || [ ] ) . reduce (
286+ (
287+ acc : React . ReactElement [ ] ,
288+ childNode : React . ReactElement ,
289+ index : number ,
290+ ) => {
291+ let item = childNode ;
292+ if ( this . props . mode === 'horizontal' ) {
293+ let overflowed = this . getOverflowedSubMenuItem (
294+ childNode . props . eventKey ,
295+ [ ] ,
296+ ) ;
297+ if (
298+ lastVisibleIndex !== undefined &&
299+ this . props . className . indexOf ( `${ this . props . prefixCls } -root` ) !== - 1
300+ ) {
301+ if ( index > lastVisibleIndex ) {
302+ item = React . cloneElement (
303+ childNode ,
304+ // 这里修改 eventKey 是为了防止隐藏状态下还会触发 openkeys 事件
305+ {
306+ style : { display : 'none' } ,
307+ eventKey : `${ childNode . props . eventKey } -hidden` ,
308+ /**
309+ * Legacy code. Here `className` never used:
310+ * https://github.com/react-component/menu/commit/4cd6b49fce9d116726f4ea00dda85325d6f26500#diff-e2fa48f75c2dd2318295cde428556a76R240
311+ */
312+ className : `${ MENUITEM_OVERFLOWED_CLASSNAME } ` ,
313+ } ,
314+ ) ;
315+ }
316+ if ( index === lastVisibleIndex + 1 ) {
317+ this . overflowedItems = children
318+ . slice ( lastVisibleIndex + 1 )
319+ . map ( c =>
320+ React . cloneElement (
321+ c ,
322+ // children[index].key will become '.$key' in clone by default,
323+ // we have to overwrite with the correct key explicitly
324+ { key : c . props . eventKey , mode : 'vertical-left' } ,
325+ ) ,
326+ ) ;
327+
328+ overflowed = this . getOverflowedSubMenuItem (
329+ childNode . props . eventKey ,
330+ this . overflowedItems ,
331+ ) ;
332+ }
280333 }
281- if ( index === lastVisibleIndex + 1 ) {
282- this . overflowedItems = children . slice ( lastVisibleIndex + 1 ) . map ( c =>
283- React . cloneElement (
284- c ,
285- // children[index].key will become '.$key' in clone by default,
286- // we have to overwrite with the correct key explicitly
287- { key : c . props . eventKey , mode : 'vertical-left' } ,
288- ) ,
289- ) ;
290334
291- overflowed = this . getOverflowedSubMenuItem (
292- childNode . props . eventKey ,
293- this . overflowedItems ,
335+ const ret : React . ReactElement [ ] = [ ...acc , overflowed , item ] ;
336+
337+ if ( index === children . length - 1 ) {
338+ // need a placeholder for calculating overflowed indicator width
339+ ret . push (
340+ this . getOverflowedSubMenuItem ( childNode . props . eventKey , [ ] , true ) ,
294341 ) ;
295342 }
343+ return ret ;
296344 }
297-
298- const ret = [ ...acc , overflowed , item ] ;
299-
300- if ( index === children . length - 1 ) {
301- // need a placeholder for calculating overflowed indicator width
302- ret . push (
303- this . getOverflowedSubMenuItem ( childNode . props . eventKey , [ ] , true ) ,
304- ) ;
305- }
306- return ret ;
307- }
308- return [ ...acc , item ] ;
309- } , [ ] ) ;
345+ return [ ...acc , item ] ;
346+ } ,
347+ [ ] ,
348+ ) ;
310349 }
311350
312351 render ( ) {
@@ -317,7 +356,7 @@ class DOMWrap extends React.Component {
317356 overflowedIndicator,
318357 mode,
319358 level,
320- tag : Tag ,
359+ tag,
321360 children,
322361 theme,
323362 ...rest
@@ -327,33 +366,10 @@ class DOMWrap extends React.Component {
327366 rest . className += ` ${ hiddenClassName } ` ;
328367 }
329368
330- return < Tag { ...rest } > { this . renderChildren ( this . props . children ) } </ Tag > ;
369+ const Tag = tag as any ;
370+
371+ return < Tag { ...rest } > { this . renderChildren ( children ) } </ Tag > ;
331372 }
332373}
333374
334- DOMWrap . propTypes = {
335- className : PropTypes . string ,
336- children : PropTypes . node ,
337- mode : PropTypes . oneOf ( [
338- 'horizontal' ,
339- 'vertical' ,
340- 'vertical-left' ,
341- 'vertical-right' ,
342- 'inline' ,
343- ] ) ,
344- prefixCls : PropTypes . string ,
345- level : PropTypes . number ,
346- theme : PropTypes . string ,
347- overflowedIndicator : PropTypes . node ,
348- visible : PropTypes . bool ,
349- hiddenClassName : PropTypes . string ,
350- tag : PropTypes . string ,
351- style : PropTypes . object ,
352- } ;
353-
354- DOMWrap . defaultProps = {
355- tag : 'div' ,
356- className : '' ,
357- } ;
358-
359375export default DOMWrap ;
0 commit comments