Skip to content

Commit 91e8860

Browse files
authored
refactor: function component (#175)
1 parent f240eea commit 91e8860

File tree

4 files changed

+65
-68
lines changed

4 files changed

+65
-68
lines changed

src/KeywordTrigger.tsx

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import Trigger from 'rc-trigger';
22
import * as React from 'react';
3+
import { FC, useMemo } from 'react';
34
import DropdownMenu from './DropdownMenu';
4-
import type { Direction, Placement, DataDrivenOptionProps } from './Mentions';
5+
import type { DataDrivenOptionProps, Direction, Placement } from './Mentions';
56

67
const BUILT_IN_PLACEMENTS = {
78
bottomRight: {
@@ -51,47 +52,49 @@ interface KeywordTriggerProps {
5152
dropdownClassName?: string;
5253
}
5354

54-
class KeywordTrigger extends React.Component<KeywordTriggerProps, {}> {
55-
public getDropdownPrefix = () => `${this.props.prefixCls}-dropdown`;
55+
const KeywordTrigger: FC<KeywordTriggerProps> = props => {
56+
const {
57+
prefixCls,
58+
options,
59+
children,
60+
visible,
61+
transitionName,
62+
getPopupContainer,
63+
dropdownClassName,
64+
direction,
65+
placement,
66+
} = props;
5667

57-
public getDropdownElement = () => {
58-
const { options } = this.props;
59-
return (
60-
<DropdownMenu prefixCls={this.getDropdownPrefix()} options={options} />
61-
);
62-
};
68+
const dropdownPrefix = `${prefixCls}-dropdown`;
6369

64-
public getDropDownPlacement = () => {
65-
const { placement, direction } = this.props;
70+
const dropdownElement = (
71+
<DropdownMenu prefixCls={dropdownPrefix} options={options} />
72+
);
73+
74+
const dropdownPlacement = useMemo(() => {
6675
let popupPlacement;
6776
if (direction === 'rtl') {
6877
popupPlacement = placement === 'top' ? 'topLeft' : 'bottomLeft';
6978
} else {
7079
popupPlacement = placement === 'top' ? 'topRight' : 'bottomRight';
7180
}
7281
return popupPlacement;
73-
};
74-
75-
public render() {
76-
const { children, visible, transitionName, getPopupContainer } = this.props;
77-
78-
const popupElement = this.getDropdownElement();
82+
}, [direction, placement]);
7983

80-
return (
81-
<Trigger
82-
prefixCls={this.getDropdownPrefix()}
83-
popupVisible={visible}
84-
popup={popupElement}
85-
popupPlacement={this.getDropDownPlacement()}
86-
popupTransitionName={transitionName}
87-
builtinPlacements={BUILT_IN_PLACEMENTS}
88-
getPopupContainer={getPopupContainer}
89-
popupClassName={this.props.dropdownClassName}
90-
>
91-
{children}
92-
</Trigger>
93-
);
94-
}
95-
}
84+
return (
85+
<Trigger
86+
prefixCls={dropdownPrefix}
87+
popupVisible={visible}
88+
popup={dropdownElement}
89+
popupPlacement={dropdownPlacement}
90+
popupTransitionName={transitionName}
91+
builtinPlacements={BUILT_IN_PLACEMENTS}
92+
getPopupContainer={getPopupContainer}
93+
popupClassName={dropdownClassName}
94+
>
95+
{children}
96+
</Trigger>
97+
);
98+
};
9699

97100
export default KeywordTrigger;

src/Mentions.tsx

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import classNames from 'classnames';
2-
import useMergedState from 'rc-util/lib/hooks/useMergedState';
2+
import type { TextAreaProps } from 'rc-textarea';
3+
import TextArea from 'rc-textarea';
34
import toArray from 'rc-util/lib/Children/toArray';
5+
import useMergedState from 'rc-util/lib/hooks/useMergedState';
46
import KeyCode from 'rc-util/lib/KeyCode';
57
import warning from 'rc-util/lib/warning';
68
import React, { useEffect, useRef, useState } from 'react';
7-
import type { TextAreaProps } from 'rc-textarea';
8-
import TextArea from 'rc-textarea';
9+
import useEffectState from './hooks/useEffectState';
910
import KeywordTrigger from './KeywordTrigger';
1011
import MentionsContext from './MentionsContext';
1112
import type { OptionProps } from './Option';
@@ -18,7 +19,6 @@ import {
1819
setInputSelection,
1920
validateSearch as defaultValidateSearch,
2021
} from './util';
21-
import useEffectState from './hooks/useEffectState';
2222

2323
type BaseTextareaAttrs = Omit<
2424
TextAreaProps,
@@ -71,23 +71,23 @@ export interface MentionsRef {
7171
const Mentions = React.forwardRef<MentionsRef, MentionsProps>((props, ref) => {
7272
const {
7373
// Style
74-
prefixCls,
74+
prefixCls = 'rc-mentions',
7575
className,
7676
style,
7777

7878
// Misc
79-
prefix,
80-
split,
81-
notFoundContent,
79+
prefix = '@',
80+
split = ' ',
81+
notFoundContent = 'Not Found',
8282
value,
8383
defaultValue,
8484
children,
8585
options,
8686
open,
8787

8888
// Events
89-
validateSearch,
90-
filterOption,
89+
validateSearch = defaultValidateSearch,
90+
filterOption = defaultFilterOption,
9191
onChange,
9292
onKeyDown,
9393
onKeyUp,
@@ -105,15 +105,13 @@ const Mentions = React.forwardRef<MentionsRef, MentionsProps>((props, ref) => {
105105
getPopupContainer,
106106
dropdownClassName,
107107

108+
rows = 1,
109+
108110
// Rest
109111
...restProps
110112
} = props;
111113

112114
const mergedPrefix = Array.isArray(prefix) ? prefix : [prefix];
113-
const mergedProps = {
114-
...props,
115-
prefix: mergedPrefix,
116-
};
117115

118116
// =============================== Refs ===============================
119117
const textareaRef = useRef<TextArea>(null);
@@ -355,10 +353,7 @@ const Mentions = React.forwardRef<MentionsRef, MentionsProps>((props, ref) => {
355353
const nextMeasureText = selectionStartText.slice(
356354
measureIndex + nextMeasurePrefix.length,
357355
);
358-
const validateMeasure: boolean = validateSearch(
359-
nextMeasureText,
360-
mergedProps,
361-
);
356+
const validateMeasure: boolean = validateSearch(nextMeasureText, split);
362357
const matchOption = !!getOptions(nextMeasureText).length;
363358

364359
if (validateMeasure) {
@@ -429,6 +424,7 @@ const Mentions = React.forwardRef<MentionsRef, MentionsProps>((props, ref) => {
429424
ref={textareaRef}
430425
value={mergedValue}
431426
{...restProps}
427+
rows={rows}
432428
onChange={onInternalChange}
433429
onKeyDown={onInternalKeyDown}
434430
onKeyUp={onInternalKeyUp}
@@ -475,16 +471,6 @@ const Mentions = React.forwardRef<MentionsRef, MentionsProps>((props, ref) => {
475471
Option: typeof Option;
476472
};
477473

478-
Mentions.defaultProps = {
479-
prefixCls: 'rc-mentions',
480-
prefix: '@',
481-
split: ' ',
482-
validateSearch: defaultValidateSearch,
483-
filterOption: defaultFilterOption,
484-
notFoundContent: 'Not Found',
485-
rows: 1,
486-
};
487-
488474
Mentions.Option = Option;
489475

490476
export default Mentions;

src/util.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ export function setInputSelection(
122122
input.focus();
123123
}
124124

125-
export function validateSearch(text: string, props: MentionsProps) {
126-
const { split } = props;
125+
export function validateSearch(text: string, split: MentionsProps['split']) {
127126
return !split || text.indexOf(split) === -1;
128127
}
129128

tests/Mentions.spec.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import React, { createRef } from 'react';
2-
import KeyCode from 'rc-util/lib/KeyCode';
3-
import Mentions from '../src';
4-
import type { MentionsProps } from '../src';
5-
import { expectMatchOptions, expectMeasuring, simulateInput } from './util';
61
import { fireEvent, render } from '@testing-library/react';
2+
import KeyCode from 'rc-util/lib/KeyCode';
3+
import React, { createRef } from 'react';
74
import { act } from 'react-dom/test-utils';
5+
import type { MentionsProps } from '../src';
6+
import Mentions from '../src';
87
import type { MentionsRef } from '../src/Mentions';
8+
import { expectMatchOptions, expectMeasuring, simulateInput } from './util';
99

1010
const { Option } = Mentions;
1111

@@ -244,6 +244,15 @@ describe('Mentions', () => {
244244
).toBeTruthy();
245245
});
246246

247+
it('should support direction', () => {
248+
const { container } = renderMentions({ direction: 'rtl' });
249+
simulateInput(container, '@');
250+
act(() => {
251+
jest.runAllTimers();
252+
});
253+
expect(container.querySelector('.rc-mentions-dropdown')).toBeTruthy();
254+
});
255+
247256
it('should support textarea in ref', () => {
248257
const ref = createRef<MentionsRef>();
249258
const { container } = render(createMentions({ ref }));

0 commit comments

Comments
 (0)