webscopeio / react-textarea-autocomplete

📝 React component implements configurable GitHub's like textarea autocomplete.
MIT License
454 stars 80 forks source link

Integration with matterial-ui Input components not working #129

Closed japrogramer closed 5 years ago

japrogramer commented 5 years ago

Hello I would like to Integrate auto complete into my react input .. I thought that passing the ref of the input component to ReactTextareaAutocomplete would do the trick but I must be missing something

import Input from '@material-ui/core/Input';
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
import "@webscopeio/react-textarea-autocomplete/style.css";

....

              <Input
                id="comment"
                type={'text'}
                fullwidth={true}
                multiline={true}
                rows={2}
                className={classes.formControl}
                value={this.state.text}
                onChange={this.handleChange('text')}
                inputProps={{
                  ref: this.textRef,
                  style: {
                    resize: 'vertical',
                  }
                }}
              />
              <ReactTextareaAutocomplete
                loadingComponent={Loading}
                value={this.state.text}
                onChange={this.handleChange('text')}
                textAreaComponent={() => this.textRef}
                style={{
                  fontSize: "18px",
                  lineHeight: "20px",
                  width: '100%',
                  resize: 'vertical',
                }}
                containerStyle={{
                  marginTop: 20,
                  margin: "20px auto"
                }}
                minChar={1}
                trigger={{
                  ":": {
                    dataProvider: token => {
                     return [
                        { name: "smile", char: "🙂" },
                        { name: "heart", char: "❤️" }
                      ];
                    },
                    component: Item,
                    output: (item, trigger) => `${trigger}${item.char}`
                  }
                }}
              />
japrogramer commented 5 years ago

And In my now latest attempt after reading the source code, I would thinks that this would work but It doesn't .... Please help

              <ReactTextareaAutocomplete
                loadingComponent={Loading}
                value={this.state.text}
                onChange={this.handleChange('text')}
                textareacomponent={(...rest) => {

                  return (<input
                    id="comment"
                    type={'text'}
                    fullwidth={true}
                    multiline={true}
                    rows={2}
                    classname={classes.formcontrol}
                    inputprops={{
                      style: {
                        resize: 'vertical',
                      },
                      ...rest
                    }}
                  />)
                  }}
                style={{
                  fontSize: "18px",
                  lineHeight: "20px",
                  width: '100%',
                  resize: 'vertical',
                }}
                minChar={1}
                trigger={{
                  ":": {
                    dataProvider: token => {
                     return [
                        { name: "smile", char: "🙂" },
                        { name: "heart", char: "❤️" }
                      ];
                    },
                    component: Item,
                    output: (item, trigger) => `${trigger}${item.char}`
                  }
                }}
              />

Ok it seems that if i change this to the .. following .. it works. But I would like to have the style of the above text box. by passing the style of the auto complete textarea it seems to override more than just what it is specified and changes the look of the entire text area.

                    inputprops={{
                      ...rest
                    }}
jukben commented 5 years ago

Hey. 👋 Could you please provide codepen or something to reproduce it?

japrogramer commented 5 years ago

I'm on mobile, I'll do it in the morning.

jukben commented 5 years ago

@japrogramer awesome. I believe they're gonna be a way how to solve it if input from material-ui has the same API as textarea.

Btw the prop should be textAreaComponent which takes object {component: React.Component, ref: "innerRef"} or React.Component for instance.

If the styling is a bit off let's try to remove

import "@webscopeio/react-textarea-autocomplete/style.css";

RTA automatically adds few classes and on those classes, there is by default applied minimal styling coming from that file.

japrogramer commented 5 years ago

@jukben https://codesandbox.io/s/38zwmm02n6 (forgot to save, now it should be there.) I managed to get an example in codesandbox but as you can see the completion component isn't being rendered which might be a separate bug.

The problem im asking about is the styles .. how can i make them have the same styles.

In material-ui each ui component has a default style applied .. So i guess to rephrase .. what are the essential styles for a drop down menu to work and be placed as expected for completion all other styles i can do without.

jukben commented 5 years ago

Hey, @japrogramer it looks like you are still passing wrong property, it should be textAreaComponent also you have to ensure that the handler's going to be correctly passed (the same for ref). Not sure if it's gonna work with Input, it's (unfortunately) designed for textarea.

japrogramer commented 5 years ago

Input uses textarea as it's component so it should work.. and it does in my implementation I wrote but only in my project . Although I copy pasted the same code to the example above .. it doesn't on the example. Only difference is I'm using hooks instead of class components.

Hmm . I'll make some more changes once I get to a computer.

japrogramer commented 5 years ago

@jukben thats weird using textAreaComponent doesn't work for me but TextAreaComponent does .. meaning that my component passed is actually rendered as expected with dropdown and everything, even my onChange functions are called, its just that the styling is wrong ..

I don't understand how, by looking at src from here

https://github.com/webscopeio/react-textarea-autocomplete/blob/master/src/Textarea.jsx#L907

japrogramer commented 5 years ago

@jukben I made the changes that you suggested and the component is rendered but now my component looses focus everytime i type in it and the autosuggest doesn't show up https://codesandbox.io/s/38zwmm02n6

japrogramer commented 5 years ago
TypeError: _this2.textareaRef is undefined[Learn More] 2 react-textarea-autocomplete.es.js:1025
    setTopLeft react-textarea-autocomplete.es.js:1025
    _changeHandler react-textarea-autocomplete.es.js:1110
    handleChange InputBase.js:290
callCallback8React  forEach (index):262
forEachAccumulated10React   dispatchInteractiveEvent (index):1018

what am i doing wrong here ? Im trying again

  const textRef = React.createRef();
....
              <ReactTextareaAutocomplete
                loadingComponent={Loading}
                value={this.state.text}
                onChange={this.handleChange('text')}
                textAreaComponent={
                  { component: (rest) => {
                    console.log(rest)

                    return (<Input
                      id="comment"
                      type={'text'}
                      fullwidth={true}
                      multiline={true}
                      rows={2}
                      className={classes.formcontrol}
                      inputprops={{
                        style: {
                          resize: 'vertical',
                        },
                      }}
                      {...rest}
                    />)
                    },
                    ref: textRef,
                  }}
                style={{
                  fontSize: "18px",
                  lineHeight: "20px",
                  width: '100%',
                  resize: 'vertical',
                }}
                minChar={1}
                trigger={{
                  "@": {
                    dataProvider: token => {
                     return [
                        { name: "test", char: "SomeUsername" },
                        { name: "user", char: "ADifferentU" }
                      ];
                    },
                    component: Item,
                    output: (item, trigger) => `${trigger}${item.char}`
                  }
                }}
              />

Seriously, its POINTLESS to pass the component and the ref ... It should only need the ref ...

jukben commented 5 years ago

@japrogramer Obviously you don't understand the reason for the ref here. It depends on the API of the component you are passing how to get the ref. In case if this Input component it should be inputRef by the documentation.

But the wrapper with forwardRef should work as well https://github.com/webscopeio/react-textarea-autocomplete/pull/113

jukben commented 5 years ago

I have a feeling that there is something fishy with Codesandbox, I didn't want to waste my time on this so I just quickly prototyped the same inside this repository. Please go check it out this branch https://github.com/webscopeio/react-textarea-autocomplete/tree/example/material-ui (clone this repo and checkout to this branch, don't forget to run yarn). It's working.

Edit:

The important code is

const InPo = React.forwardRef((props, ref) => {
  const { onChange, onBlur, onClick, onKeyDown, onScroll, onSelect } = props;
  return (
    <Input
      id="comment"
      type={"text"}
      multiline={true}
      rows={2}
      inputProps={{
        onChange,
        // onBlur, disabled because the callback inside Input has been passed wrongly
        onClick,
        onKeyDown,
        onScroll,
        onSelect
      }}
      value={props.value}
      inputRef={ref}
    />
  );
});

and

<ReactTextareaAutocomplete
  ...
  textAreaComponent={InPo}
  ...
/>;

material-ui

japrogramer commented 5 years ago

@jukben thanks, that worked.

Only thing now is that my implementation looses focus at every char typed .. hmm. I have cloned the repo and your example works perfectly.

sorry, I thought a ref to an element exposed the interfaces needed to implement the auto suggest just by itself

japrogramer commented 5 years ago

I managed to fix the error where the component would loose focus, by moving the InPo defenition out of render() but now i need access to the classes variable to override a style but if i pass it like so .. the looses input error comes back

const InPo = (classes) => React.forwardRef((props, ref) => {
  const { onChange, onBlur, onClick, onKeyDown, onScroll, onSelect } = props;
  return (
    <Input
      classes={{root: classes.root}}
      id="comment"
      type={"text"}
      multiline={true}
      rows={2}
      inputProps={{
        onChange,
        // onBlur, disabled because the callback inside Input has been passed wrongly
        onClick,
        onKeyDown,
        onScroll,
        onSelect
      }}
      value={props.value}
      inputRef={ref}
    />
  );
});
              <ReactTextareaAutocomplete
                className={classes.fullwidth}
                loadingComponent={Loading}
                value={this.state.text}
                onChange={this.handleChange('text')}
                textAreaComponent={InPo(classes)}
                minChar={1}
                trigger={{
                  "@": {
                    dataProvider: token => {
                     return [
                        { name: "test", char: "SomeUsername" },
                        { name: "user", char: "ADifferentU" }
                      ];
                    },
                    component: Item,
                    output: (item, trigger) => `${trigger}${item.char}`
                  }
                }}
              />

nvm small issue, ill just style it inline.