Skip to content

Commit a11f589

Browse files
authored
Added RenderInput signavio#622 (#14)
signavio#623
2 parents b605f09 + b40908d commit a11f589

File tree

6 files changed

+120
-41
lines changed

6 files changed

+120
-41
lines changed

.changeset/six-actors-clean.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-mentions": minor
3+
---
4+
5+
Added RenderInput

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ You can find more examples here: [demo/src/examples](https://github.com/signavio
6161
The `MentionsInput` supports the following props for configuring the widget:
6262
6363
| Prop name | Type | Default value | Description |
64-
| --------------------------- | ------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------- |
64+
|-----------------------------|---------------------------------------------------------|----------------|----------------------------------------------------------------------------------------|
6565
| value | string | `''` | The value containing markup for mentions |
6666
| onChange | function (event, newValue, newPlainTextValue, mentions) | empty function | A callback that is invoked when the user changes the value in the mentions input |
6767
| onKeyDown | function (event) | empty function | A callback that is invoked when the user presses a key in the mentions input |
@@ -74,6 +74,7 @@ The `MentionsInput` supports the following props for configuring the widget:
7474
| forceSuggestionsAboveCursor | boolean | false | Forces the SuggestionList to be rendered above the cursor |
7575
| a11ySuggestionsListLabel | string | `''` | This label would be exposed to screen readers when suggestion popup appears |
7676
| customSuggestionsContainer | function(children) | empty function | Allows customizing the container of the suggestions |
77+
| renderInput | React component | undefined | Allows customizing the input element |
7778
7879
Each data source is configured using a `Mention` component, which has the following props:
7980

demo/src/examples/Examples.js

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import SingleLineIgnoringAccents from './SingleLineIgnoringAccents'
1313
import SuggestionPortal from './SuggestionPortal'
1414
import BottomGuard from './BottomGuard'
1515
import CustomSuggestionsContainer from './CustomSuggestionsContainer'
16+
import RendererInput from './RenderInput'
1617

1718
const users = [
1819
{
@@ -90,6 +91,7 @@ export default function Examples() {
9091
<SuggestionPortal data={users} />
9192
<BottomGuard data={users} />
9293
<CustomSuggestionsContainer data={users} />
94+
<RendererInput data={users} />
9395
</div>
9496
</StylesViaJss>
9597
)

demo/src/examples/RenderInput.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react'
2+
3+
import { Mention, MentionsInput } from '../../../src'
4+
5+
import { provideExampleValue } from './higher-order'
6+
import defaultStyle from './defaultStyle'
7+
import defaultMentionStyle from './defaultMentionStyle'
8+
9+
const CustomRenderer = React.forwardRef((props, ref) => (
10+
<label>
11+
I am a custom input!
12+
<input type="text" {...props} ref={ref} />
13+
</label>
14+
))
15+
16+
function RenderInput({ value, data, onChange, onAdd }) {
17+
return (
18+
<div className="single-line">
19+
<h3>Single line input</h3>
20+
21+
<MentionsInput
22+
renderInput={CustomRenderer}
23+
value={value}
24+
onChange={onChange}
25+
style={defaultStyle}
26+
placeholder={"Mention people using '@'"}
27+
a11ySuggestionsListLabel={'Suggested mentions'}
28+
>
29+
<Mention data={data} onAdd={onAdd} style={defaultMentionStyle} />
30+
</MentionsInput>
31+
</div>
32+
)
33+
}
34+
35+
const asExample = provideExampleValue('')
36+
37+
export default asExample(RenderInput)

src/MentionsInput.js

+41-28
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ const propTypes = {
101101
PropTypes.element,
102102
PropTypes.arrayOf(PropTypes.element),
103103
]).isRequired,
104+
105+
renderInput: PropTypes.elementType,
104106
}
105107

106108
class MentionsInput extends React.Component {
@@ -177,7 +179,7 @@ class MentionsInput extends React.Component {
177179
)
178180
}
179181

180-
setContainerElement = (el) => {
182+
setContainerElement = el => {
181183
this.containerElement = el
182184
}
183185

@@ -223,28 +225,35 @@ class MentionsInput extends React.Component {
223225
}
224226

225227
renderControl = () => {
226-
let { singleLine, style } = this.props
228+
let { singleLine, style, renderInput } = this.props
227229
let inputProps = this.getInputProps()
228230

229231
return (
230232
<div {...style('control')}>
231233
{this.renderHighlighter()}
232-
{singleLine
234+
{renderInput
235+
? this.renderCustom(inputProps)
236+
: singleLine
233237
? this.renderInput(inputProps)
234238
: this.renderTextarea(inputProps)}
235239
</div>
236240
)
237241
}
238242

239-
renderInput = (props) => {
243+
renderCustom = props => {
244+
let { renderInput: RenderInput } = this.props
245+
return <RenderInput ref={this.setInputRef} {...props} />
246+
}
247+
248+
renderInput = props => {
240249
return <input type="text" ref={this.setInputRef} {...props} />
241250
}
242251

243-
renderTextarea = (props) => {
252+
renderTextarea = props => {
244253
return <textarea ref={this.setInputRef} {...props} />
245254
}
246255

247-
setInputRef = (el) => {
256+
setInputRef = el => {
248257
this.inputElement = el
249258
const { inputRef } = this.props
250259
if (typeof inputRef === 'function') {
@@ -254,7 +263,7 @@ class MentionsInput extends React.Component {
254263
}
255264
}
256265

257-
setSuggestionsElement = (el) => {
266+
setSuggestionsElement = el => {
258267
this.suggestionsElement = el
259268
}
260269

@@ -278,7 +287,7 @@ class MentionsInput extends React.Component {
278287
scrollFocusedIntoView={this.state.scrollFocusedIntoView}
279288
containerRef={this.setSuggestionsElement}
280289
suggestions={this.state.suggestions}
281-
customSuggestionsContainer ={this.props.customSuggestionsContainer}
290+
customSuggestionsContainer={this.props.customSuggestionsContainer}
282291
onSelect={this.addMention}
283292
onMouseDown={this.handleSuggestionsMouseDown}
284293
onMouseEnter={this.handleSuggestionsMouseEnter}
@@ -319,11 +328,11 @@ class MentionsInput extends React.Component {
319328
)
320329
}
321330

322-
setHighlighterElement = (el) => {
331+
setHighlighterElement = el => {
323332
this.highlighterElement = el
324333
}
325334

326-
handleCaretPositionChange = (position) => {
335+
handleCaretPositionChange = position => {
327336
this.setState({ caretPosition: position })
328337
}
329338

@@ -487,9 +496,9 @@ class MentionsInput extends React.Component {
487496
}
488497

489498
// Handle input element's change event
490-
handleChange = (ev) => {
499+
handleChange = ev => {
491500
isComposing = false
492-
if(isIE()){
501+
if (isIE()) {
493502
// if we are inside iframe, we need to find activeElement within its contentDocument
494503
const currentDocument =
495504
(document.activeElement && document.activeElement.contentDocument) ||
@@ -560,7 +569,7 @@ class MentionsInput extends React.Component {
560569
}
561570

562571
// Handle input element's select event
563-
handleSelect = (ev) => {
572+
handleSelect = ev => {
564573
// keep track of selection range / caret position
565574
this.setState({
566575
selectionStart: ev.target.selectionStart,
@@ -584,7 +593,7 @@ class MentionsInput extends React.Component {
584593
this.props.onSelect(ev)
585594
}
586595

587-
handleKeyDown = (ev) => {
596+
handleKeyDown = ev => {
588597
// do not intercept key events if the suggestions overlay is not shown
589598
const suggestionsCount = countSuggestions(this.state.suggestions)
590599

@@ -626,7 +635,7 @@ class MentionsInput extends React.Component {
626635
}
627636
}
628637

629-
shiftFocus = (delta) => {
638+
shiftFocus = delta => {
630639
const suggestionsCount = countSuggestions(this.state.suggestions)
631640

632641
this.setState({
@@ -642,7 +651,7 @@ class MentionsInput extends React.Component {
642651
const { result, queryInfo } = Object.values(suggestions).reduce(
643652
(acc, { results, queryInfo }) => [
644653
...acc,
645-
...results.map((result) => ({ result, queryInfo })),
654+
...results.map(result => ({ result, queryInfo })),
646655
],
647656
[]
648657
)[focusIndex]
@@ -654,7 +663,7 @@ class MentionsInput extends React.Component {
654663
})
655664
}
656665

657-
handleBlur = (ev) => {
666+
handleBlur = ev => {
658667
const clickedSuggestion = this._suggestionsMouseDown
659668
this._suggestionsMouseDown = false
660669

@@ -674,11 +683,11 @@ class MentionsInput extends React.Component {
674683
this.props.onBlur(ev, clickedSuggestion)
675684
}
676685

677-
handleSuggestionsMouseDown = (ev) => {
686+
handleSuggestionsMouseDown = ev => {
678687
this._suggestionsMouseDown = true
679688
}
680689

681-
handleSuggestionsMouseEnter = (focusIndex) => {
690+
handleSuggestionsMouseEnter = focusIndex => {
682691
this.setState({
683692
focusIndex,
684693
scrollFocusedIntoView: false,
@@ -687,7 +696,11 @@ class MentionsInput extends React.Component {
687696

688697
updateSuggestionsPosition = () => {
689698
let { caretPosition } = this.state
690-
const { suggestionsPortalHost, allowSuggestionsAboveCursor, forceSuggestionsAboveCursor } = this.props
699+
const {
700+
suggestionsPortalHost,
701+
allowSuggestionsAboveCursor,
702+
forceSuggestionsAboveCursor,
703+
} = this.props
691704

692705
if (!caretPosition || !this.suggestionsElement) {
693706
return
@@ -739,9 +752,9 @@ class MentionsInput extends React.Component {
739752
// is small enough to NOT cover up the caret
740753
if (
741754
(allowSuggestionsAboveCursor &&
742-
top + suggestions.offsetHeight > viewportHeight &&
755+
top + suggestions.offsetHeight > viewportHeight &&
743756
suggestions.offsetHeight < top - caretHeight) ||
744-
forceSuggestionsAboveCursor
757+
forceSuggestionsAboveCursor
745758
) {
746759
position.top = Math.max(0, top - suggestions.offsetHeight - caretHeight)
747760
} else {
@@ -761,12 +774,12 @@ class MentionsInput extends React.Component {
761774
// is small enough to NOT cover up the caret
762775
if (
763776
(allowSuggestionsAboveCursor &&
764-
viewportRelative.top -
765-
highlighter.scrollTop +
766-
suggestions.offsetHeight >
767-
viewportHeight &&
768-
suggestions.offsetHeight <
769-
caretOffsetParentRect.top - caretHeight - highlighter.scrollTop) ||
777+
viewportRelative.top -
778+
highlighter.scrollTop +
779+
suggestions.offsetHeight >
780+
viewportHeight &&
781+
suggestions.offsetHeight <
782+
caretOffsetParentRect.top - caretHeight - highlighter.scrollTop) ||
770783
forceSuggestionsAboveCursor
771784
) {
772785
position.top = top - suggestions.offsetHeight - caretHeight

0 commit comments

Comments
 (0)