Skip to content

Commit 2edfcb7

Browse files
authored
Add onItemHighlighted prop (#192)
* Add onItemHighlighted prop Useful for updating other parts of the page in reaction to the highlighted item in the autocomplete dropdown being changed * Revert version bump
1 parent c9ceda4 commit 2edfcb7

File tree

6 files changed

+45
-3
lines changed

6 files changed

+45
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ or there is UMD build available. [Check out this pen as example](https://codepen
5454
| boundariesElement | string \| HTMLElement | Element which should prevent autocomplete to overflow. Defaults to _body_. |
5555
| textAreaComponent | React.Component \| {component: React.Component, ref: string} | What component use for as textarea. Default is `textarea`. (You can combine this with [react-autosize-textarea](https://github.com/buildo/react-autosize-textarea) for instance) |
5656
| renderToBody | boolean | When set to `true` the autocomplete will be rendered at the end of the `<body>`. Default is `false`. |
57+
| onItemHighlighted | ({currentTrigger: string \| null, item: string \| Object \| null}) => void | Callback get called everytime item is highlighted in the list |
5758
| onItemSelected | ({currentTrigger: string, item: string \| Object}) => void | Callback get called everytime item is selected |
5859
| style | Style Object | Style's of textarea |
5960
| listStyle | Style Object | Styles of list's wrapper |

cypress/integration/textarea.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,19 @@ describe("React Textarea Autocomplete", () => {
134134
cy.get('[data-test="minChar"]').clear({ force: true });
135135
});
136136

137-
it("onSelectItem should return correct item and trigger", () => {
137+
it("onItemHighlighted should return correct item and trigger", () => {
138+
cy.get(".rta__textarea").type(":ro{uparrow}{uparrow}");
139+
cy.window().then(async win => {
140+
const shouldSelectItem = {
141+
currentTrigger: ":",
142+
item: { name: "rofl", char: "🤣" }
143+
};
144+
145+
expect(win.__lastHighlightedItem).to.deep.equal(shouldSelectItem);
146+
});
147+
});
148+
149+
it("onItemSelected should return correct item and trigger", () => {
138150
cy.get(".rta__textarea").type(":ro{uparrow}{uparrow}{enter}");
139151
cy.window().then(async win => {
140152
const shouldSelectItem = {

example/App.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,10 @@ class App extends React.Component {
271271
}}
272272
movePopupAsYouType={movePopupAsYouType}
273273
onCaretPositionChange={this._onCaretPositionChangeHandle}
274+
onItemHighlighted={info => {
275+
// save highlighted item to window; use it later in E2E tests
276+
window.__lastHighlightedItem = info;
277+
}}
274278
onItemSelected={info => {
275279
// save selected item to window; use it later in E2E tests
276280
window.__lastSelectedItem = info;

src/List.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,13 @@ export default class List extends React.Component<ListProps, ListState> {
114114
};
115115

116116
selectItem = (item: Object | string, keyboard: boolean = false) => {
117+
const { onItemHighlighted } = this.props;
118+
117119
if (this.state.selectedItem === item) return;
118120

119121
this.setState({ selectedItem: item }, () => {
122+
onItemHighlighted(item);
123+
120124
if (keyboard) {
121125
this.props.dropdownScroll(this.itemsRef[this.getId(item)]);
122126
}

src/Textarea.jsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,11 +666,14 @@ class ReactTextareaAutocomplete extends React.Component<
666666
* Close autocomplete, also clean up trigger (to avoid slow promises)
667667
*/
668668
_closeAutocomplete = () => {
669+
const { currentTrigger } = this.state;
669670
this.escListenerDestroy();
670671
this.setState({
671672
data: null,
672673
dataLoading: false,
673674
currentTrigger: null
675+
}, () => {
676+
if(currentTrigger) this._onItemHighlightedHandler(null);
674677
});
675678
};
676679

@@ -703,7 +706,8 @@ class ReactTextareaAutocomplete extends React.Component<
703706
"movePopupAsYouType",
704707
"textAreaComponent",
705708
"renderToBody",
706-
"onItemSelected"
709+
"onItemSelected",
710+
"onItemHighlighted"
707711
];
708712

709713
// eslint-disable-next-line
@@ -951,6 +955,18 @@ class ReactTextareaAutocomplete extends React.Component<
951955
this._closeAutocomplete();
952956
};
953957

958+
_onItemHighlightedHandler = (item: Object | string | null) => {
959+
const { onItemHighlighted } = this.props;
960+
const { currentTrigger } = this.state;
961+
if(onItemHighlighted) {
962+
if(typeof onItemHighlighted === "function") {
963+
onItemHighlighted({currentTrigger, item});
964+
} else {
965+
throw new Error("`onItemHighlighted` has to be a function");
966+
}
967+
}
968+
}
969+
954970
_dropdownScroll = (item: HTMLDivElement) => {
955971
const { scrollToItem } = this.props;
956972

@@ -1087,6 +1103,7 @@ class ReactTextareaAutocomplete extends React.Component<
10871103
itemClassName={itemClassName}
10881104
itemStyle={itemStyle}
10891105
getTextToReplace={textToReplace}
1106+
onItemHighlighted={this._onItemHighlightedHandler}
10901107
onSelect={this._onSelect}
10911108
dropdownScroll={this._dropdownScroll}
10921109
/>
@@ -1197,7 +1214,9 @@ ReactTextareaAutocomplete.propTypes = {
11971214
dropdownClassName: PropTypes.string,
11981215
boundariesElement: containerPropCheck, //eslint-disable-line
11991216
trigger: triggerPropsCheck, //eslint-disable-line
1200-
renderToBody: PropTypes.bool
1217+
renderToBody: PropTypes.bool,
1218+
onItemSelected: PropTypes.func,
1219+
onItemHighlighted: PropTypes.func,
12011220
};
12021221

12031222
export default ReactTextareaAutocomplete;

src/types.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type ListProps = {
3636
itemStyle: ?Object,
3737
className: ?string,
3838
itemClassName: ?string,
39+
onItemHighlighted: (Object | string ) => void,
3940
onSelect: (Object | string) => void,
4041
dropdownScroll: HTMLDivElement => void
4142
};
@@ -79,6 +80,7 @@ export type TextareaProps = {
7980
| boolean
8081
| ((container: HTMLDivElement, item: HTMLDivElement) => void),
8182
closeOnClickOutside?: boolean,
83+
onItemHighlighted?: ({ currentTrigger: ?string, item: ?Object | ?string }) => void,
8284
onItemSelected?: ({ currentTrigger: string, item: Object | string }) => void,
8385
movePopupAsYouType?: boolean,
8486
boundariesElement: string | HTMLElement,

0 commit comments

Comments
 (0)