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

refactor: reduce motion #6979

Merged
merged 12 commits into from
Jun 20, 2024
Merged

Conversation

inomdzhon
Copy link
Contributor

@inomdzhon inomdzhon commented May 31, 2024


Описание

В CSS файлах применил медиа-выражение @media screen and (prefers-reduced-motion: reduce) там, где необходимо. Попутно рефакторил некоторые из них. Например, примененил токен --vkui--animation_duration_m где это возможно.

Note

Упрощал основываясь на поведении iOS и приложений под него. При включении параметра Уменьшение движения + Предпочтение перекрёстным наплывам (Настройки -> Универсальный доступ -> Движение) переходы, зачастую, заменяются на анимацию через смену прозрачности.

Затронутые анимации:

Note

Длительность и изинги НЕ трогал, только подменял изменение размеров и/или передвижения.

  • ActionSheet
    • параметры анимации вынесены в переменные --vkui_internal--*;
    • анимация появления/скрытия упрощается до появление через прозрачность.
    • для анимаций теперь используется useCSSKeyframesAnimationController().
  • Alert
    • параметры анимации вынесены в переменные --vkui_internal--*;
    • анимация появления/скрытия упрощается до появление через прозрачность;
    • добавил анимацию для десктоп ([Feature] Анимации у выпадающих меню #2250);
    • для анимаций теперь используется useCSSKeyframesAnimationController().
  • Button
    • удалён @media screen and (prefers-reduced-motion: no-preference), т.к. допустимая анимация.
  • PanelHeaderContext
    • параметры анимации вынесены в переменные --vkui_internal--*;
    • для анимаций теперь используется useCSSKeyframesAnimationController().
    • useGlobalEventListener() заменён на useGlobalOnClickOutside(). И теперь, если visible === false, то компонент не остаётся в DOM;
    • теперь при visible === false возвращаем null.
  • Removable
    • удалён @media screen and (prefers-reduced-motion: no-preference), т.к. допустимая анимация.
  • Root
    • анимация появления/скрытия упрощается до появление через прозрачность.
  • Skeleton
    • анимации отключаются.
  • Snackbar
    • анимация появления/скрытия упрощается до появление через прозрачность;
    • остаётся возможность закрыть через свайп – вызывает закрытие через прозрачность.
  • Switch
    • удалён @media screen and (prefers-reduced-motion: no-preference), т.к. допустимая анимация.
  • View
    • анимация появления/скрытия упрощается до появление через прозрачность;
    • остаётся возможность свайпать;
    • в примеры документации добавил кнопки "Назад" в PanelHeader.
  • animationFades.module.css
    • удалён @media screen and (prefers-reduced-motion: no-preference), т.к. допустимая анимация.
  • focusVisible.module.css
    • заменил @media screen and (prefers-reduced-motion: no-preference) на @media screen and (prefers-reduced-motion: reduce)

Что не затронул?

Не трогал мобильный ModalRoot дабы не сломать его. Лучше сделать в рамках #2449.

Остальные изменения

  • в docs/CONTRIBUTING.md добавил информацию про a11y (заодно немного освежил документ);
  • удалён хук useTimeout() и везде заменён на ручной запуск и очистку – этот хук больше усложняет код, чем упрощает;
  • удалён lib/supportEvents.ts, т.к. все браузеры из текущего .browserslistrc поддерживают событие transitionend;
    - удалён хук useReducedMotion() – на текущий момент больше не используется, т.к. оказывается (prefers-reduced-motion: reduce) не предполагает полное отключение всех анимаций, а лишь говорит, что надо их упростить. (UPD вернул в рамках ⚡ c89d7d1).

Эти изменения привели к следующему:

  • useWaitTransitionFinish() – теперь и возвращает сразу функцию не оборачивая его в объект;
  • PopoutWrapper – теперь компонент неконтролируемый – показывается/скрывается в зависимости от параметра closing.

Типы

  • добавлен TimeoutId, чтобы не приходилось каждый раз писать ReturnType<typeof setTimeout> | null;.

Тесты

  • применён waitCSSKeyframeAnimationEnd() там, где раньше была завязка на setTimeout;
  • добавлена утилита waitCSSTransitionEnd();
  • добавлен мок для TransitionEvent.

Copy link
Contributor

github-actions bot commented May 31, 2024

size-limit report 📦

Path Size
JS 363.36 KB (-0.38% 🔽)
JS (gzip) 111.2 KB (-0.4% 🔽)
JS (brotli) 91.58 KB (-0.28% 🔽)
JS import Div (tree shaking) 1.42 KB (0%)
CSS 284.36 KB (+0.53% 🔺)
CSS (gzip) 37.1 KB (+0.79% 🔺)
CSS (brotli) 30.04 KB (+0.78% 🔺)

Copy link

codesandbox-ci bot commented May 31, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Copy link
Contributor

github-actions bot commented May 31, 2024

e2e tests

Playwright Report

Copy link
Contributor

github-actions bot commented May 31, 2024

👀 Docs deployed

Commit 2fa4fbb

Copy link

codecov bot commented May 31, 2024

Codecov Report

Attention: Patch coverage is 84.57143% with 27 lines in your changes missing coverage. Please review.

Project coverage is 83.49%. Comparing base (2566673) to head (2fa4fbb).

Files Patch % Lines
packages/vkui/src/components/Gallery/hooks.ts 19.04% 17 Missing ⚠️
...mponents/PanelHeaderContext/PanelHeaderContext.tsx 84.21% 3 Missing ⚠️
packages/vkui/src/components/View/View.tsx 90.62% 3 Missing ⚠️
packages/vkui/src/components/View/ViewInfinite.tsx 81.25% 3 Missing ⚠️
packages/vkui/src/components/Root/Root.tsx 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6979      +/-   ##
==========================================
+ Coverage   83.46%   83.49%   +0.03%     
==========================================
  Files         353      351       -2     
  Lines       10570    10499      -71     
  Branches     3510     3473      -37     
==========================================
- Hits         8822     8766      -56     
+ Misses       1748     1733      -15     
Flag Coverage Δ
unittests 83.49% <84.57%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@inomdzhon inomdzhon force-pushed the imirdzhamolov/issue2703/feat/reduce-motion branch 3 times, most recently from 3bc5b30 to 809fb94 Compare June 6, 2024 13:56
@inomdzhon inomdzhon marked this pull request as ready for review June 6, 2024 14:09
@inomdzhon inomdzhon requested a review from a team as a code owner June 6, 2024 14:09
@inomdzhon inomdzhon linked an issue Jun 6, 2024 that may be closed by this pull request
@qurle qurle requested a review from a team June 11, 2024 13:52
qurle
qurle previously approved these changes Jun 11, 2024
Copy link
Contributor

@qurle qurle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Доброе дело!

@BlackySoul
Copy link
Contributor

Офигенная работа проделана 💪

@BlackySoul
Copy link
Contributor

Заодно поправим здесь? Спиннер нужно медленнее крутить?)

@inomdzhon inomdzhon force-pushed the imirdzhamolov/issue2703/feat/reduce-motion branch from 5cdb6fd to c89d7d1 Compare June 14, 2024 12:43
@inomdzhon
Copy link
Contributor Author

Заодно поправим здесь? Спиннер нужно медленнее крутить?)

Заменил анимацию на периодическую смену прозрачности c89d7d1 (вернул хук useReducedMotion()).

Смена длительность анимации на rotate показалась сомнительной, т.к. всё-равно можем вызывать головокружение 🤔

Copy link
Contributor

@mendrew mendrew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Грандиозная работа! 👏

Нашел пару моментов, на которые стоит обратить внимание.

И в целом мысли по анимациям.
Давай где-нибудь пропишем результаты твоего ресерча по анимациям, чтобы всегда можно было на это сослаться в будущем! в Contribution, например, со ссылкой на этот PR. (в комментарию к самому файлу Contribution я подробнее расписал). Чтобы контрибьютеру было понятно как дальше с ними быть. Что вот такое мы завернём ещё и в медиа выражение, а вот такое просто оставим как есть.

Будем плюсом ещё добавить ссылку на файл по хэшу комита, где ты по фэн шую разруливаешь сложные анимации с помощью css переменных (например, Root), опять же, чтобы было место на которое всегда можно сослаться в качестве рекомендуемой практики. И ссылку на Removable, например, где есть простая анимация не требующая ничего более и которую в медиа выражение заворачивать не надо.

docs/CONTRIBUTING.md Outdated Show resolved Hide resolved
packages/vkui/src/components/Alert/Alert.module.css Outdated Show resolved Hide resolved
packages/vkui/src/components/Gallery/hooks.ts Outdated Show resolved Hide resolved
docs/CONTRIBUTING.md Outdated Show resolved Hide resolved
packages/vkui/src/components/Tappable/Ripple.tsx Outdated Show resolved Hide resolved
packages/vkui/src/hooks/useDocumentVisibilityState.test.ts Outdated Show resolved Hide resolved
inomdzhon and others added 6 commits June 19, 2024 16:05
- удалён хук `useTimeout()` и везде заменён на ручной запуск и очистку – этот хук больше усложняет код, чем упрощает;
- удалён `lib/supportEvents.ts`, т.к. все браузеры из текущего `.browserslistrc` поддерживают событие [transitionend](https://developer.mozilla.org/ru/docs/Web/API/Element/transitionend_event#%D1%81%D0%BE%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C_%D1%81_%D0%B1%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80%D0%B0%D0%BC%D0%B8);
- удалён хук `useReducedMotion()` – на текущий момент больше не используется, т.к. оказывается `(prefers-reduced-motion: reduce)` не предполагает полное отключение всех анимаций, а лишь говорит, что надо их упростить.

Эти изменения привели к следующему:

- `useWaitTransitionFinish()` – теперь и возвращает сразу функцию не оборачивая его в объект;
- в следующих компонентах для анимаций теперь используется `useCSSKeyframesAnimationController()`:
  - `ActionSheet`
  - `Alert`
  - `PanelHeaderContext` – заодно `useGlobalEventListener()` заменён на `useGlobalOnClickOutside()`. И теперь, если `visible === false`, то компонент не остаётся в DOM.
- `PopoutWrapper` теперь неконтролируемый – показывается/скрывается в зависимости от параметра `closing`;
- создан хук `useDocumentVisibilityState()` – в этом коммите используется в `Gallery`.

h2. Типы

- добавлен `TimeoutId`, чтобы не приходилось каждый раз писать `ReturnType<typeof setTimeout> | null;`.

h2. Тесты

- применён `waitCSSKeyframeAnimationEnd()` там, где раньше была завязка на `setTimeout`;
- добавлена утилита `waitCSSTransitionEnd()`;
- добавлен мок для `TransitionEvent`.
Заодно поправил устаревшую информацию.
Co-authored-by: Victoria Zhizhonkova <indarklight@gmail.com>
…le.tsx

Co-authored-by: Andrey Medvedev <andr.medv.spb@gmail.com>
@inomdzhon inomdzhon force-pushed the imirdzhamolov/issue2703/feat/reduce-motion branch from acedc77 to 0ad1433 Compare June 19, 2024 13:05
@inomdzhon inomdzhon force-pushed the imirdzhamolov/issue2703/feat/reduce-motion branch from 8a9fc8f to a18db43 Compare June 19, 2024 13:11
Copy link
Contributor

@mendrew mendrew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥
💯
💅

@inomdzhon inomdzhon merged commit 37f3689 into master Jun 20, 2024
26 checks passed
@inomdzhon inomdzhon deleted the imirdzhamolov/issue2703/feat/reduce-motion branch June 20, 2024 09:33
inomdzhon added a commit that referenced this pull request Jun 24, 2024
В #6979 для теста менял на `2s` и случайно закоммитил.
inomdzhon added a commit that referenced this pull request Jun 24, 2024
В #6979 для теста менял на `2s` и случайно закоммитил.

Вернул `0.1s`.

#6979 ждёт релиза `v6.2.0`, поэтому фикс без майлстоун.
inomdzhon added a commit that referenced this pull request Aug 14, 2024
Была проблема, что до #6979:

1. переменная `prevSwipeBackResult` использовалась в `React.useEffect()`, из-за чего она была всегда актуальная, т.к. обращались мы к ней после окончания рендера. В #6979 она переместилась в **render prop**, где мы обращаемся к переменной до окончания рендера, поэтому и получалось так, что свайп бёк срабатывал в первый раз, пока `prevSwipeBackResult` являлся `null`, а во второй раз уже не срабатывал, т.к. `prevSwipeBackResult` имел предыдущее состояние. Изучил, что проверку на `prevSwipeBackResult` в целом можно удалить.

2. Событие `transitionend` навешивалось в обход **React**, а также был фолбек на `setTimeout()`. В #6979 события навешиваются через **React** – `onTransitionEnd`. Иногда обработчик не вызывался. Чтобы исправить это, перенёс навешивания события на текущий элемент (`isSwipeBackPrev`) вместо последующего (`isSwipeBackNext`). Поправил тесты под это изменение.

**Изменения**

- удалил `React.useCallback()` на обработчике события `onAnimationEnd`, т.к. это обычный `<div />` и мемоизация ни к чему
- заодно отрефакторил `calcPanelSwipeStyles()` и `calcPanelSwipeBackOverlayStyles()`;
inomdzhon added a commit that referenced this pull request Aug 19, 2024
h2. Описание

Была проблема, что до #6979:

1. переменная `prevSwipeBackResult` использовалась в `React.useEffect()`, из-за чего она была всегда актуальная, т.к. обращались мы к ней после окончания рендера. В #6979 она переместилась в **render prop**, где мы обращаемся к переменной до окончания рендера, поэтому и получалось так, что свайп бёк срабатывал в первый раз, пока `prevSwipeBackResult` являлся `null`, а во второй раз уже не срабатывал, т.к. `prevSwipeBackResult` имел предыдущее состояние. Изучил, что проверку на `prevSwipeBackResult` в целом можно удалить.

2. Событие `transitionend` навешивалось в обход **React**, а также был фолбек с `setTimeout()`. В #6979 события навешиваются через **React** – `onTransitionEnd`. Иногда обработчик не вызывался. Чтобы исправить это, перенёс навешивания события на текущий элемент (`isSwipeBackPrev`) вместо последующего (`isSwipeBackNext`). Поправил тесты под это изменение.

h2. Изменения

- удалил `React.useCallback()` на обработчике события `onAnimationEnd`, т.к. это обычный `<div />` и мемоизация ни к чему;
- заодно отрефакторил `calcPanelSwipeStyles()` и `calcPanelSwipeBackOverlayStyles()`.
vkcom-publisher pushed a commit that referenced this pull request Aug 19, 2024
h2. Описание

Была проблема, что до #6979:

1. переменная `prevSwipeBackResult` использовалась в `React.useEffect()`, из-за чего она была всегда актуальная, т.к. обращались мы к ней после окончания рендера. В #6979 она переместилась в **render prop**, где мы обращаемся к переменной до окончания рендера, поэтому и получалось так, что свайп бёк срабатывал в первый раз, пока `prevSwipeBackResult` являлся `null`, а во второй раз уже не срабатывал, т.к. `prevSwipeBackResult` имел предыдущее состояние. Изучил, что проверку на `prevSwipeBackResult` в целом можно удалить.

2. Событие `transitionend` навешивалось в обход **React**, а также был фолбек с `setTimeout()`. В #6979 события навешиваются через **React** – `onTransitionEnd`. Иногда обработчик не вызывался. Чтобы исправить это, перенёс навешивания события на текущий элемент (`isSwipeBackPrev`) вместо последующего (`isSwipeBackNext`). Поправил тесты под это изменение.

h2. Изменения

- удалил `React.useCallback()` на обработчике события `onAnimationEnd`, т.к. это обычный `<div />` и мемоизация ни к чему;
- заодно отрефакторил `calcPanelSwipeStyles()` и `calcPanelSwipeBackOverlayStyles()`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants