Skip to content

Commit 51fce82

Browse files
authored
feat: support popupRender to customize Mentions dropdown menu
1 parent 3f919a1 commit 51fce82

4 files changed

Lines changed: 36 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ Then open `http://localhost:8000`.
114114
| onResize | `(size: { width: number; height: number }) => void` | - | Triggered when textarea size changes. |
115115
| onSearch | `(text: string, prefix: string) => void` | - | Triggered when a prefix starts a search. |
116116
| onSelect | `(option: OptionProps, prefix: string) => void` | - | Triggered when an option is selected. |
117+
| popupRender | `(menu: React.ReactElement) => ReactNode` | - | Customize the dropdown menu rendering |
117118

118119
### Option
119120

src/KeywordTrigger.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ interface KeywordTriggerProps {
5252
getPopupContainer?: () => HTMLElement;
5353
popupClassName?: string;
5454
popupStyle?: React.CSSProperties;
55+
popupRender?: (menu: React.ReactElement) => React.ReactNode;
5556
}
5657

5758
const KeywordTrigger: FC<KeywordTriggerProps> = props => {
@@ -66,6 +67,7 @@ const KeywordTrigger: FC<KeywordTriggerProps> = props => {
6667
popupStyle,
6768
direction,
6869
placement,
70+
popupRender,
6971
} = props;
7072

7173
const dropdownPrefix = `${prefixCls}-dropdown`;
@@ -89,11 +91,15 @@ const KeywordTrigger: FC<KeywordTriggerProps> = props => {
8991
return popupPlacement;
9092
}, [direction, placement]);
9193

94+
const dropdownPopup = popupRender
95+
? popupRender(dropdownElement)
96+
: dropdownElement;
97+
9298
return (
9399
<Trigger
94100
prefixCls={dropdownPrefix}
95101
popupVisible={visible}
96-
popup={dropdownElement}
102+
popup={dropdownPopup}
97103
popupPlacement={dropdownPlacement}
98104
popupMotion={{ motionName: transitionName }}
99105
builtinPlacements={BUILT_IN_PLACEMENTS}

src/Mentions.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ export interface MentionsProps extends BaseTextareaAttrs {
8585
popup?: React.CSSProperties;
8686
};
8787
onPopupScroll?: (event: React.UIEvent<HTMLDivElement>) => void;
88+
/**
89+
* Customize the dropdown menu rendering
90+
* @param menu The default dropdown menu
91+
* @returns The customized dropdown menu
92+
*/
93+
popupRender?: (menu: React.ReactElement) => React.ReactNode;
8894
}
8995

9096
export interface MentionsRef {
@@ -150,6 +156,7 @@ const InternalMentions = forwardRef<MentionsRef, InternalMentionsProps>(
150156
// @ts-expect-error
151157
visible,
152158
onPopupScroll,
159+
popupRender,
153160

154161
// Rest
155162
...restProps
@@ -607,6 +614,7 @@ const InternalMentions = forwardRef<MentionsRef, InternalMentionsProps>(
607614
getPopupContainer={getPopupContainer}
608615
popupClassName={clsx(popupClassName, mentionClassNames?.popup)}
609616
popupStyle={styles?.popup}
617+
popupRender={popupRender}
610618
>
611619
<span>{mergedMeasurePrefix}</span>
612620
</KeywordTrigger>

tests/Mentions.spec.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,4 +484,24 @@ describe('Mentions', () => {
484484
expect(textarea).toHaveStyle({ resize: 'vertical' });
485485
});
486486
});
487+
488+
describe('popupRender', () => {
489+
it('should render custom popup content', () => {
490+
const { container, baseElement } = renderMentions({
491+
popupRender: menu => (
492+
<div className="custom-popup">
493+
<div className="custom-header">Custom Header</div>
494+
{menu}
495+
</div>
496+
),
497+
});
498+
499+
simulateInput(container, '@');
500+
501+
expect(baseElement.querySelector('.custom-header')).toBeTruthy();
502+
expect(
503+
baseElement.querySelector('.rc-mentions-dropdown-menu'),
504+
).toBeTruthy();
505+
});
506+
});
487507
});

0 commit comments

Comments
 (0)