i-like-robots / react-tag-autocomplete

⚛️ A simple, accessible, tagging component ready to drop into your React projects (new repo)
https://i-like-robots.github.io/react-tag-autocomplete/
ISC License
178 stars 12 forks source link

Inconsistent behavior with `onShouldExpand` and `onShouldCollapse` #49

Closed acelaya closed 1 year ago

acelaya commented 1 year ago

I'm trying to make the suggestions dropdown to not be displayed unless at least two characters have been input.

In order to do so, and following the docs, I have implemented the callbacks like this.

<ReactTags
  onShouldExpand={(value) => {
    console.log('Should expand', value);
    return value.length > 1;
  }}
  onShouldCollapse={(value) => {
    console.log('Should collapse', value);
    return value.length < 2;
  }}
  // [...]
/>

Expected behavior

The suggestions dropdown appears when the second character is input, and stays displayed as long as 2 or more characters remain.

As soon as the input has 1 or less characters, the suggestions dropdown is collapsed.

Current behaviour

I haven't debugged any further than using the console.logs above, but the onShouldExpand callback is always invoked onInput, but with the previous value. For example, if I have just written foo, it gets called with fo.

Regarding onShouldCollapse, it never gets called onInput, but instead, it appears to be called onChange, so it only applies when the input looses focus (for example).

Steps to Reproduce

Using the code snippet above, you should be able to see the console.logs as described in previous point.

Example and screenshots

You can see it here in action on this recording (ignore the UI, I'm migrating from v6 and haven't tackled that yet).

Grabación de pantalla desde 2023-08-12 13-40-19.webm

i-like-robots commented 1 year ago

Thank you for the detailed report and examples @acelaya

I've had a look into this and I can confirm that I see the onShouldExpand() callback being called with the previously rendered value and not the latest. I believe this is because it reads from state but it's being called synchronously alongside the value state change rather than after. This is a bug that needs to be fixed 🐛

The onShouldExpand callback is called after actions which may expand the listbox such as the focus event or typing when collapsed.

Similarly, the onShouldCollapse callback is only called after actions which may collapse the listbox such as the blur event or pressing the escape key. It is not called on input or on change and this is the intended behaviour.

To collapse the list box when the input value is below a certain length it's possible to use the onInput callback alongside the onShouldExpand callback:

      <ReactTags
        onAdd={onAdd}
        onDelete={onDelete}
        onShouldExpand={(value) => {
          return value.length > 1
        }}
        onInput={(value) => {
          if (value.length < 2) {
            api.current.listBox.collapse()
          }
        }}
        ref={api}
        selected={selected}
        suggestions={suggestions}
      />