Skip to content

Commit 3c74ad1

Browse files
authored
chore: support internal props (#428)
* chore: support internal props * chore: more props
1 parent fbc51ff commit 3c74ad1

File tree

4 files changed

+116
-46
lines changed

4 files changed

+116
-46
lines changed

src/Menu.tsx

Lines changed: 69 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import useUUID from './hooks/useUUID';
2626
import { PathRegisterContext, PathUserContext } from './context/PathContext';
2727
import useKeyRecords, { OVERFLOW_KEY } from './hooks/useKeyRecords';
2828
import { IdContext } from './context/IdContext';
29+
import PrivateContext from './context/PrivateContext';
2930

3031
/**
3132
* Menu modify after refactor:
@@ -110,6 +111,16 @@ export interface MenuProps
110111
// >>>>> Events
111112
onClick?: MenuClickEventHandler;
112113
onOpenChange?: (openKeys: string[]) => void;
114+
115+
// >>>>> Internal
116+
/***
117+
* @private Only used for `pro-layout`. Do not use in your prod directly
118+
* and we do not promise any compatibility for this.
119+
*/
120+
_internalRenderMenuItem?: (
121+
originNode: React.ReactElement,
122+
menuItemProps: any,
123+
) => React.ReactElement;
113124
}
114125

115126
interface LegacyMenuProps extends MenuProps {
@@ -184,6 +195,9 @@ const Menu: React.FC<MenuProps> = props => {
184195
openAnimation,
185196
openTransitionName,
186197

198+
// Internal
199+
_internalRenderMenuItem,
200+
187201
...restProps
188202
} = props as LegacyMenuProps;
189203

@@ -426,6 +440,14 @@ const Menu: React.FC<MenuProps> = props => {
426440
setMounted(true);
427441
}, []);
428442

443+
// ======================= Context ========================
444+
const privateContext = React.useMemo(
445+
() => ({
446+
_internalRenderMenuItem,
447+
}),
448+
[_internalRenderMenuItem],
449+
);
450+
429451
// ======================== Render ========================
430452

431453
// >>>>> Children
@@ -502,51 +524,53 @@ const Menu: React.FC<MenuProps> = props => {
502524

503525
// >>>>> Render
504526
return (
505-
<IdContext.Provider value={uuid}>
506-
<MenuContextProvider
507-
prefixCls={prefixCls}
508-
mode={mergedMode}
509-
openKeys={mergedOpenKeys}
510-
rtl={isRtl}
511-
// Disabled
512-
disabled={disabled}
513-
// Motion
514-
motion={mounted ? motion : null}
515-
defaultMotions={mounted ? defaultMotions : null}
516-
// Active
517-
activeKey={mergedActiveKey}
518-
onActive={onActive}
519-
onInactive={onInactive}
520-
// Selection
521-
selectedKeys={mergedSelectKeys}
522-
// Level
523-
inlineIndent={inlineIndent}
524-
// Popup
525-
subMenuOpenDelay={subMenuOpenDelay}
526-
subMenuCloseDelay={subMenuCloseDelay}
527-
forceSubMenuRender={forceSubMenuRender}
528-
builtinPlacements={builtinPlacements}
529-
triggerSubMenuAction={triggerSubMenuAction}
530-
getPopupContainer={getInternalPopupContainer}
531-
// Icon
532-
itemIcon={itemIcon}
533-
expandIcon={expandIcon}
534-
// Events
535-
onItemClick={onInternalClick}
536-
onOpenChange={onInternalOpenChange}
537-
>
538-
<PathUserContext.Provider value={pathUserContext}>
539-
{container}
540-
</PathUserContext.Provider>
541-
542-
{/* Measure menu keys. Add `display: none` to avoid some developer miss use the Menu */}
543-
<div style={{ display: 'none' }} aria-hidden>
544-
<PathRegisterContext.Provider value={registerPathContext}>
545-
{childList}
546-
</PathRegisterContext.Provider>
547-
</div>
548-
</MenuContextProvider>
549-
</IdContext.Provider>
527+
<PrivateContext.Provider value={privateContext}>
528+
<IdContext.Provider value={uuid}>
529+
<MenuContextProvider
530+
prefixCls={prefixCls}
531+
mode={mergedMode}
532+
openKeys={mergedOpenKeys}
533+
rtl={isRtl}
534+
// Disabled
535+
disabled={disabled}
536+
// Motion
537+
motion={mounted ? motion : null}
538+
defaultMotions={mounted ? defaultMotions : null}
539+
// Active
540+
activeKey={mergedActiveKey}
541+
onActive={onActive}
542+
onInactive={onInactive}
543+
// Selection
544+
selectedKeys={mergedSelectKeys}
545+
// Level
546+
inlineIndent={inlineIndent}
547+
// Popup
548+
subMenuOpenDelay={subMenuOpenDelay}
549+
subMenuCloseDelay={subMenuCloseDelay}
550+
forceSubMenuRender={forceSubMenuRender}
551+
builtinPlacements={builtinPlacements}
552+
triggerSubMenuAction={triggerSubMenuAction}
553+
getPopupContainer={getInternalPopupContainer}
554+
// Icon
555+
itemIcon={itemIcon}
556+
expandIcon={expandIcon}
557+
// Events
558+
onItemClick={onInternalClick}
559+
onOpenChange={onInternalOpenChange}
560+
>
561+
<PathUserContext.Provider value={pathUserContext}>
562+
{container}
563+
</PathUserContext.Provider>
564+
565+
{/* Measure menu keys. Add `display: none` to avoid some developer miss use the Menu */}
566+
<div style={{ display: 'none' }} aria-hidden>
567+
<PathRegisterContext.Provider value={registerPathContext}>
568+
{childList}
569+
</PathRegisterContext.Provider>
570+
</div>
571+
</MenuContextProvider>
572+
</IdContext.Provider>
573+
</PrivateContext.Provider>
550574
);
551575
};
552576

src/MenuItem.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Icon from './Icon';
1717
import useDirectionStyle from './hooks/useDirectionStyle';
1818
import { useFullPath, useMeasure } from './context/PathContext';
1919
import { useMenuId } from './context/IdContext';
20+
import PrivateContext from './context/PrivateContext';
2021

2122
export interface MenuItemProps
2223
extends Omit<
@@ -116,6 +117,9 @@ const InternalMenuItem = (props: MenuItemProps) => {
116117
// Active
117118
onActive,
118119
} = React.useContext(MenuContext);
120+
121+
const { _internalRenderMenuItem } = React.useContext(PrivateContext);
122+
119123
const itemCls = `${prefixCls}-item`;
120124

121125
const legacyMenuItemRef = React.useRef<any>();
@@ -199,7 +203,7 @@ const InternalMenuItem = (props: MenuItemProps) => {
199203
optionRoleProps['aria-selected'] = selected;
200204
}
201205

202-
return (
206+
let renderNode = (
203207
<LegacyMenuItem
204208
ref={legacyMenuItemRef}
205209
elementRef={elementRef}
@@ -238,6 +242,12 @@ const InternalMenuItem = (props: MenuItemProps) => {
238242
/>
239243
</LegacyMenuItem>
240244
);
245+
246+
if (_internalRenderMenuItem) {
247+
renderNode = _internalRenderMenuItem(renderNode, props);
248+
}
249+
250+
return renderNode;
241251
};
242252

243253
function MenuItem(props: MenuItemProps): React.ReactElement {

src/context/PrivateContext.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as React from 'react';
2+
import type { MenuProps } from '../Menu';
3+
4+
export interface PrivateContextProps {
5+
_internalRenderMenuItem?: MenuProps['_internalRenderMenuItem'];
6+
}
7+
8+
const PrivateContext = React.createContext<PrivateContextProps>({});
9+
10+
export default PrivateContext;

tests/Private.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* eslint-disable no-undef */
2+
import React from 'react';
3+
import { mount } from 'enzyme';
4+
import classnames from 'classnames';
5+
import Menu, { MenuItem } from '../src';
6+
7+
describe('Private Props', () => {
8+
it('_internalRenderMenuItem', () => {
9+
const wrapper = mount(
10+
<Menu
11+
_internalRenderMenuItem={node =>
12+
React.cloneElement(node, {
13+
className: classnames(node.props.className, 'inject-cls'),
14+
})
15+
}
16+
>
17+
<MenuItem key="1">1</MenuItem>
18+
</Menu>,
19+
);
20+
21+
console.log(wrapper.html());
22+
23+
expect(wrapper.exists('.inject-cls')).toBeTruthy();
24+
});
25+
});
26+
/* eslint-enable */

0 commit comments

Comments
 (0)