Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[text-area] Infinite ResizeObserver loop #7828

Open
robrez opened this issue Sep 19, 2024 · 2 comments
Open

[text-area] Infinite ResizeObserver loop #7828

robrez opened this issue Sep 19, 2024 · 2 comments

Comments

@robrez
Copy link
Contributor

robrez commented Sep 19, 2024

Description

In certain situations, text-area's resize observer causes an infinite loop

Expected outcome

Loop should be terminated

Minimal reproducible example

I've had some difficultly creating a very minimalist reproduction. Here is a gif and stackblitz

https://stackblitz.com/edit/vitejs-vite-wmooik?file=main.js

text-area-resize-loop

Steps to reproduce

Place text-area(s) in the dom, provide values, and slowly make the window / dom parent narrower until you see "jittery" behavior

Environment

Vaadin version(s): 23, 24
OS: windows

Browsers

Chrome

@robrez
Copy link
Contributor Author

robrez commented Sep 19, 2024

Potential general solutions:

  _onResize() {
    const width = this.getBoundingClientRect()?.width;
    const value = this.value;
    if (width === this.__prevWidth && value === this.__prevValue) {
      return;
    }
    this.__prevWidth = width;
    this.__prevValue = value;
    this._updateHeight();
    this.__scrollPositionUpdated();
  }

Memoize width and value onResize. Don't re-try resize whenever width and value match the previous effort. This would misbehave in a lot of circumstances, some examples:

  • CSS updates styling such as font-size, font-weight, line-height, padding
  • Slot-changes, such as new prefix / suffix elements
  • CSS updates to sizing of slotted children

After typing that, I realize checking the width of the input element would be better versus "this". The only other idea I have for a solution involves some sort of debouncing of resize observers or maybe saying, "ignore the next one" whenever we cause the resize ourselves

@robrez
Copy link
Contributor Author

robrez commented Sep 19, 2024

I think that doing some sort of "skipNextResize" is the better strategy.. probably still not perfect:

  _onResize() {
    if (this.__resizing) {
      return;
    }
    if (this.__skipNextResize) {
      this.__skipNextResize = false;
      return;
    }
    this.__resizing = true;
    this._updateHeight();
    this.__resizing = false;
    this.__scrollPositionUpdated();
  }
  
  _updateHeight() {
    // ...
    
    
    const inputHeight = input.scrollHeight;
    if (inputHeight > input.clientHeight) {
      // add these 3 lines.. not sure it really makes sense to have an "if"... we'd probably
      // want to just _always_ skip the next resize observer when we are the ones who caused it
      if (this.__resizing) {
          this.__skipNextResize = true;
      }
      input.style.height = `${inputHeight}px`;
    }

   // ...
 }
  

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants