Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ React.render(<Demo />, container);
| name | description | type | default |
|----------|----------------|----------|--------------|
| autoFocus | Auto get focus when component mounted | boolean | `false` |
| enableClick | Enable click on mention to open dropdown | boolean | `false` |
| defaultValue | Default value | string | - |
| filterOption | Customize filter option logic | false \| (input: string, option: OptionProps) => boolean | - |
| notFoundContent | Set mentions content when not match | ReactNode | 'Not Found' |
Expand Down
43 changes: 43 additions & 0 deletions examples/click.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* eslint no-console: 0 */

import React from 'react';
import Mentions from '../src';
import '../assets/index.less';

const { Option } = Mentions;

class Demo extends React.Component {
onSelect = (option, prefix) => {
console.log('Select:', prefix, '-', option.value);
};

onFocus = () => {
console.log('onFocus');
};

onBlur = () => {
console.log('onBlur');
};

render() {
return (
<div>
<Mentions
autoFocus
enableClick
rows={3}
defaultValue="Insert some mention and click on them"
onSelect={this.onSelect}
onFocus={this.onFocus}
onBlur={this.onBlur}
>
<Option value="light">Light</Option>
<Option value="bamboo">Bamboo</Option>
<Option value="cat">Cat</Option>
</Mentions>
</div>
);
}
}

export default Demo;
84 changes: 49 additions & 35 deletions src/Mentions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export type Placement = 'top' | 'bottom';

export interface MentionsProps extends BaseTextareaAttrs {
autoFocus?: boolean;
enableClick?: boolean;
className?: string;
defaultValue?: string;
notFoundContent?: React.ReactNode;
Expand Down Expand Up @@ -149,20 +150,64 @@ class Mentions extends React.Component<MentionsProps, MentionsState> {
}
};

public onKeyUp: React.KeyboardEventHandler<HTMLTextAreaElement> = event => {
this.handleMeasure(event);
};

public onMouseSelect: React.MouseEventHandler<HTMLTextAreaElement> = event => {
const { enableClick } = this.props;
if (enableClick) {
this.handleMeasure(event);
}
};

public onInputFocus: React.FocusEventHandler<HTMLTextAreaElement> = event => {
this.onFocus(event);
};

public onInputBlur: React.FocusEventHandler<HTMLTextAreaElement> = event => {
this.onBlur(event);
};

public onDropdownFocus = () => {
this.onFocus();
};

public onFocus = (event?: React.FocusEvent<HTMLTextAreaElement>) => {
window.clearTimeout(this.focusId);
const { isFocus } = this.state;
const { onFocus } = this.props;
if (!isFocus && event && onFocus) {
onFocus(event);
}
this.setState({ isFocus: true });
};

public onBlur = (event: React.FocusEvent<HTMLTextAreaElement>) => {
this.focusId = window.setTimeout(() => {
const { onBlur } = this.props;
this.setState({ isFocus: false });
this.stopMeasure();
if (onBlur) {
onBlur(event);
}
}, 0);
};

/**
* When to start measure:
* 1. When user press `prefix`
* 2. When measureText !== prevMeasureText
* - If measure hit
* - If measuring
* 3. When user click on mentions
*
* When to stop measure:
* 1. Selection is out of range
* 2. Contains `space`
* 3. ESC or select one
*/
public onKeyUp: React.KeyboardEventHandler<HTMLTextAreaElement> = event => {
const { key, which } = event;
public handleMeasure = event => {
const { measureText: prevMeasureText, measuring } = this.state;
const { prefix = '', onSearch, validateSearch } = this.props;
const target = event.target as HTMLTextAreaElement;
Expand All @@ -171,6 +216,7 @@ class Mentions extends React.Component<MentionsProps, MentionsState> {
selectionStartText,
prefix,
);
const { key = measurePrefix, which } = event;

// Skip if match the white key list
if ([KeyCode.ESC, KeyCode.UP, KeyCode.DOWN, KeyCode.ENTER].indexOf(which) !== -1) {
Expand Down Expand Up @@ -207,39 +253,6 @@ class Mentions extends React.Component<MentionsProps, MentionsState> {
}
};

public onInputFocus: React.FocusEventHandler<HTMLTextAreaElement> = event => {
this.onFocus(event);
};

public onInputBlur: React.FocusEventHandler<HTMLTextAreaElement> = event => {
this.onBlur(event);
};

public onDropdownFocus = () => {
this.onFocus();
};

public onFocus = (event?: React.FocusEvent<HTMLTextAreaElement>) => {
window.clearTimeout(this.focusId);
const { isFocus } = this.state;
const { onFocus } = this.props;
if (!isFocus && event && onFocus) {
onFocus(event);
}
this.setState({ isFocus: true });
};

public onBlur = (event: React.FocusEvent<HTMLTextAreaElement>) => {
this.focusId = window.setTimeout(() => {
const { onBlur } = this.props;
this.setState({ isFocus: false });
this.stopMeasure();
if (onBlur) {
onBlur(event);
}
}, 0);
};

public selectOption = (option: OptionProps) => {
const { value, measureLocation, measurePrefix } = this.state;
const { split, onSelect } = this.props;
Expand Down Expand Up @@ -362,6 +375,7 @@ class Mentions extends React.Component<MentionsProps, MentionsState> {
onKeyUp={this.onKeyUp}
onFocus={this.onInputFocus}
onBlur={this.onInputBlur}
onMouseUp={this.onMouseSelect}
/>
{measuring && (
<div ref={this.setMeasureRef} className={`${prefixCls}-measure`}>
Expand Down