taiga-family / taiga-ui

Angular UI Kit and components library for awesome people
https://taiga-ui.dev
Apache License 2.0
3.3k stars 465 forks source link

🐞 - `InputInline` has broken scroll in Safari / Firefox #7552

Open goodday21 opened 6 months ago

goodday21 commented 6 months ago

Playground Link

No response

Description

Браузер - Safari.

Компонент - https://taiga-ui.dev/components/input-inline#heading

Шаги: 1) нажать на иконку редактирования у элемента "Page heading" 2) ввести длинную строку, более 150 символов 3) сохранить изменения 4) снова нажать на иконку редактирования 5) попробовать поменять строку

Ожидаемый результат: фокус установлен в конец строки, пользователь может передвигать курсор по тексту и редактировать его Фактический результат: фокус остается на начале строки. Если пользователь работает с концом строки, то он не видит, что вводит

Angular version

No response

Taiga UI version

3.80.0

Which browsers have you used?

Which operating systems have you used?

waterplea commented 2 weeks ago

Safari does not dispatch scroll events for inputs. We need to use additional keypress events, selection change events and whatnot to be able to adjust text-indent to input scroll. Maybe it's even easier to just use silent animation frame for polling, but that might cause a lot of CSS reflow.

nsbarsukov commented 2 days ago

Just some intermediate investigations

We can replace the following logic https://github.com/taiga-family/taiga-ui/blob/432a4867f60c99fa266cd1bfaadf2e983d7c4984/projects/kit/components/input-inline/input-inline.component.ts#L32-L38

with

protected indent$ = merge(
    fromEvent(this.element, 'scroll', {capture: true}), // Only Chrome emits this event for <input />
    // Chrome does not fire `selectionchange` on deletion (but do it on insertion) ¯\_(ツ)_/¯
    fromEvent(this.element, 'selectionchange', {capture: true}), // Firefox + Safari fallback
    // Chrome & Safari scrolls input to the beginning on blur
    // Firefox – keeps the same scrollLeft position on blur
    fromEvent(this.element, 'focusout').pipe(
        concatMap(
            (x) => of(x).pipe(delay(0)), // Without delay `scrollLeft` is not yet updated
        ),
    ),
).pipe(
    map(({target}) => target),
    filter((x): x is HTMLInputElement => tuiIsElement(x) && tuiIsInput(x)),
    map(
        ({scrollLeft}) => -scrollLeft - 1, // -1 for Safari (see styles)
    ),
);

However, it still does fully solves all issue for Safari / Firefox. Try to insert many characters and the use many Backspaces then. The content will slightly shift to the left: textContent of ghost-span updates faster than textIndent calculations (shrinking of ghost-span should be AFTER textIndent calculations). https://github.com/taiga-family/taiga-ui/blob/432a4867f60c99fa266cd1bfaadf2e983d7c4984/projects/kit/components/input-inline/input-inline.template.html#L2-L6 Even if we delay update of textContent (by adding delay(0) to indent$ stream) - insertion of new character will be broken (we should increase size of ghost-span BEFORE textIndent calculations).

nsbarsukov commented 2 days ago

TODO

Discuss this PR with @waterplea

Which problem was solved by this PR ? Could we make <input />-element visible again (and solve that problem in another way) ? If it was about vertical alignment with another inline-elements – probably we could just remove overflow:hidden from the host (to not break baseline of host inline block). https://github.com/taiga-family/taiga-ui/blob/432a4867f60c99fa266cd1bfaadf2e983d7c4984/projects/kit/components/input-inline/input-inline.style.less#L5-L6