Open Aaronius opened 8 years ago
This is how I got this working. Note that I removed any code that was irrelevant to getting tether working, so this example will not run by itself.
I borrowed inspiration from here. Certainly not the prettiest solution, but it appears to cover my use cases.
import React from 'react';
import ReactDOM from 'react-dom';
import Tether from 'tether';
import Autosuggest from 'react-autosuggest';
class AutoComplete extends React.Component {
componentDidMount() {
this.update();
}
componentDidUpdate() {
this.update();
}
componentWillUnmount() {
this.destroy();
}
update() {
if (!this.listComponent || !this.textInput) return;
if (!this.tether) {
this.tether = new Tether({
attachment: 'top left',
targetAttachment: 'bottom left',
element: ReactDOM.findDOMNode(this.listComponent),
target: ReactDOM.findDOMNode(this.textInput),
});
}
this.tether.position();
}
destroy() {
this.tether.destroy();
}
renderInputComponent = inputProps => {
return (
<input {...inputProps} ref={(i) => this.textInput = i} />
);
}
renderSuggestionsContainer = ({containerProps, children}) => {
return (
<div { ...containerProps}
style={ { position: 'static', minWidth: '15rem', 'maxHeight': '10rem' } }
ref={ c => this.listComponent = c; containerProps.ref(this.listComponent); }>
{children}
</div>
);
}
render() {
return (
<Autosuggest
renderInputComponent={this.renderInputComponent}
renderSuggestionsContainer={this.renderSuggestionsContainer} />
);
}
}
export default AutoComplete;
@gotdibbs did you consider using the https://github.com/souporserious/react-tether and decide not to?
@rosskevin That I did. I had issues getting it to work with the way that solution is architected. I believe it had something to do with the whole first child/second child mapping to the target
and element
parameters.
I've successfully been able to use react-popper
(popper.js has replaced tether in many projects including bootstrap) with approximately the following:
import {Manager, Target, Popper} from 'react-popper'
import Portal from 'react-travel'
renderInputTarget = (renderInputProps: RenderInputProps) => {
return <Target>{this.props.renderInput(renderInputProps)}</Target>
}
renderSuggestionsContainerPopper = (options: RenderSuggestionsContainerOptions) => {
return (
<Portal>
<Popper placement='bottom-start'>
{this.props.renderSuggestionsContainer(options)}
</Popper>
</Portal>
)
}
render () {
const {
classes,
getSuggestionValue,
shouldRenderSuggestions,
value: valueProp,
getSuggestions, onBlurMatchSuggestion, // eslint-disable-line no-unused-vars
onlyChangeOnSelection, onSuggestionSelected, renderInput, renderSuggestionsContainer, renderSuggestion, // eslint-disable-line no-unused-vars
...other
} = this.props
return (
<Manager>
<ReactAutoSuggest
getSuggestionValue={getSuggestionValue}
inputProps={{
...other,
classes: classes,
onBlur: this.handleBlur,
onChange: this.handleInputChange,
value: inputValue || ''
}}
onSuggestionSelected={this.handleSuggestionSelected}
onSuggestionsFetchRequested={this.handleSuggestionsFetchRequested}
onSuggestionsClearRequested={this.handleSuggestionsClearRequested}
renderInputComponent={this.renderInputTarget}
renderSuggestion={this.renderSuggestion}
renderSuggestionsContainer={this.renderSuggestionsContainerPopper}
shouldRenderSuggestions={shouldRenderSuggestions}
suggestions={this.state.suggestions}
theme={{
container: classes.container,
suggestionsContainerOpen: classes.suggestionsContainerOpen,
suggestionsList: classes.suggestionsList,
suggestion: classes.suggestion
}}
/>
</Manager>
)
}
It works well and very minimal setup, still pluggable with provided render*
methods. It also uses a Portal
so there are no issues with ancestor elements hiding suggestions by specifying overflow.
@rosskevin Sadly we're already too close to :shipit: mode to change now for my use case, but thanks for the tip! Def looks better.
@rosskevin it'd better put your complete example (especially including how to wrap the target dom by PopperJS) Sandbox no ? :)
@be-next-hotdog feel free to do so. I pasted psuedocode from a custom internal codebase as a help for others. Unfortunately I have limited time, so perfect examples for everyone are unlikely to appear.
@rosskevin Yepp, besides of this issue, I remarked that Popover
ruins totally the portal while putting all these components inside of a Popover
@be-next-hotdog feel free to do so. I pasted psuedocode from a custom internal codebase as a help for others. Unfortunately I have limited time, so perfect examples for everyone are unlikely to appear.
@rosskevin So have you found a solution to scroll in portal/popper ?
I'd like to use tether for rendering the suggestions container but I can't figure out how I would do so. Has anyone worked this out?