-
Notifications
You must be signed in to change notification settings - Fork 185
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: ModalRoot/ModalPage/ModalCard #6759
Conversation
size-limit report 📦
|
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. Latest deployment of this branch, based on commit 49b82a4:
|
e2e tests |
👀 Docs deployed
Commit 49b82a4 |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #6759 +/- ##
==========================================
+ Coverage 95.45% 95.49% +0.03%
==========================================
Files 384 393 +9
Lines 11312 11188 -124
Branches 3780 3708 -72
==========================================
- Hits 10798 10684 -114
+ Misses 514 504 -10
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
4a0d455
to
7d03282
Compare
cd0da9c
to
c382b8f
Compare
c382b8f
to
fba65d5
Compare
c1453c5
to
a1c9447
Compare
481fc96
to
f07b8b4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Грандиозная работа! 👏 👏 👏 💪
Здорово раскидал по компонентам!
Понравилось, что компоненты теперь функции как практически везде!
Офигенно как переведена анимация/перетаскивание на CSS Transition и контроллеры. (Там я, конечно, поплыл, но приятно видеть знакомое API с коллбэками и то, что всё сводится к установке css переменных)
Надо пристально пройтись по местам где коллбёки передаются в компоненты, а не напрямую в html элементы и обернуть их useCallback, и по местам, где объекты возвращаются из хуков или передаются в контекст, чтобы обернуть в useMemo и избежать лишних ререндеров.
По стайлгайду и сторибуку прошелся и так и на устройстве, ничего такого не заметил.
добавил мемоизацию там где можно, но во всех местах сильная завязка на пользователя, т.к. используются колбеки ( ждём React 19, где не нужно будет руками мемоизировать) |
Ещё заметила, что как будто пропала фича, которая позволяла высоту модалки "запоминать". Т.е. если мы вытянули первую модалку на всю высоту, переключились на другую и вернулись на первую - первая должна сохранить высоту |
воу, действительно, пропала...
|
Co-authored-by: Victoria Zhizhonkova <indarklight@gmail.com>
49b82a4
0346909
to
49b82a4
Compare
Зарезолвил TODO в тесте `useBottomSheet()`, который оставлял в #6759 Упростил `getFakeTouchEvent` и `getFakeMouseEvent` до функций, которые возвращают объект. Заметил, что если вторым аргументом в `fireEvent` из `testing-library/react` передавать объект события, то он работает не корректно – лучше передавать сразу опции, которые принимают те или иные события.
settlingHeight
в 0, минимальное значение ограничено до 25, а максимальное до 100)Проверить после
[ ] Дизайн-ревью– визуально не компонент не затрагивал, поменял только поведение, к сожалению, поведение дизайн пока не документирует.Описание
Переписаны компоненты ModalPage/ModalCard
ModalRoot
.ModalPage
/ModalCard
:open
;keepMounted
;onClose
изменён сVoidFunction
на(reason: ModalPageCloseReason, event?: UIEvent<HTMLElement>) => void
;noFocusToDialog
, приоритетней чемnoFocusToDialog
вModalRoot
;modalOverlayTestId
, приоритетней чемmodalOverlayTestId
вModalRoot
.ModalOutlet
;ModalOverlay
;ModalPageInternal
иModalCardInternal
, у них есть свойствоModalOverlay
;ModalContext
, который теперь используется в компонентахModalPageHeader
,Group
иPanelHeader
вместоModalRootContext
.ModalPage
:settlingHeight
теперь имеет значение по умолчанию50%
вместо75%
, обратил внимание, что в обычноBottomSheet
'ы открываются на половину экрана;footer
, а также создан компонентModalPageFooter
;ModalPageContent
– вынес, чтобы можно было в будущем перейти на сборModalPage
через композицию компонентов.lib/sheet
:В папке хранится логика отвечающая за взаимодействие с модалкой на мобильных экранах. Отдаёт хук
useBottomSheet()
.Переписан компонент ModalRoot
open
компонентовModalCard
иModalPage
в зависимости от ихid
/nav
и параметраactiveModal
, а также рендера общейModalOverlay
для всех модалок.ModalRoot
:onOpen
,onOpened
,onClosed
, которые всплывают отactiveModal
;PopoutRoot
удалёнPopoutRootModal
в пользуModalOutlet
уModalPage
иModalCard
.ModalRootContext
:onClose
нужно теперь обязательно передаватьid
модального окна;onOpen
,onOpened
,onClosed
, чтобы их могли вызыватьModalPage
иModalCard
;registerModal
теперь@deprecated
– не нужно отдельно регистрировать модальное окно.updateModalHeight
теперь@deprecated
– задача с обновлением высоты контента приdynamicContentHeight
решается через CSS;ModalRootOverlayContext
/VisuallyHiddenModalOverlay
:ModalOverlay
для всех модалок в контекстеModalRoot
, происходит подменаModalOverlay
вModalPage
иModalCard
наVisuallyHiddenModalOverlay
, который отвечает за приёмonClick
иmodalOverlayTestId
, а самModalOverlay
попадает в началоModalRoot
useModalManager()
:unmounted
состояние;ModalRoot
иModalPage
/ModalCard
;ModalOverlay
наVisuallyHiddenModalOverlay
.withModalRootContext
:updateModalHeight
HOC тоже@deprecated
.Изменения, которые нужно вынести в отдельные PR после первичного ревью
Нюансы
Обратная совместимость
Постарался сделать так, чтобы миграция прошла бесследно.
Сломаются вот такой кейс:
который нужно будет править руками.
BottomSheet, анимации и свайп
Полное появление и полное скрытие происходит через
transform
, но анимация взаимодействия через свайп реализована черезheight
, т.к. это оказалось самым оптимальным способом для решения задач:ModalPageFooter
внизу;settlingHeight
меньше100
;dynamicContentHeight
.Нашёл решение допустимым, т.к. свайп используется либо для закрытия, либо для разворачивания/сворачивания модального окна на всю или на половину страницы. В первом случае сработает закрытие через
transform
, а во втором разворачивание/сворачивание произойдёт черезheight
.dynamicContentHeight
Обновление высоты происходит без анимации, т.к.
height: auto
не анимируется. Опустил анимирование, т.к. усложняет компонент. В теории можно прибегнуть кuseResizeObserver()
.Адативность
При
platform="vkcom"
и при разрешении экрана767px
компонент теперь превращается в BottomSheet, но при этом логику взаимодействия через тач не имеет, т.к.isDesktop
приplatform="vkcom"
всегдаtrue
вне зависимости от размера экрана.Решения
Выделение текста 🔗
С помощью функции
hasSelectionWithRangeType
определяем, что пользователь выделил текст и перестаём реагировать наtouchstart
иtouchmove
пока выделение не будет удалено.Вертикальный и горизонтальный скроллы 🔗
ModalPageContent
): проверяем наscrollTop !== 0
touchstart
достаём скроллируемый элемент черезevent.target
и проверяем на положениеscrollTop !== 0
и направление пальца вверхПлавающие элементы внутри модалки 🔗
Нужно рекомендовать использовать
forcePortal
– в коде проверяем, что идёт взаимодействие с элементом вне модалки.Или нужно рекомендовать добавлять в корневой элемент плавающего элемента атрибут
data-vkui-prevent-swipe
.Поля ввода 🔗
Наилучшего варианта не нашёл кроме как:
useVirtualKeyboardState()
узнавать, что пользователь работает с клавиатурой, и перебиватьsafe-area-inset-bottom
натот, что возвращает хук0 (попытка вычислять разницу высоты черезVisualViewport
, чтобы реагировать на смену размера клавиатуры, например, из-за панели эмодзи, не удалась);window
и сохранять его позицию наwindow.scrollTo(0, visualViewport.offsetTop)
.Так как иные решения приводят к другим проблемам (подробнее можно прочесть в JSDoc хука
useVirtualKeyboardState()
), следующие баги нужно закрыть:Референсы
Release notes
BREAKING CHANGE
ModalRoot: удалена реализация контекста через
React.cloneElement
, которая требовала передаватьsettlingHeight
иdynamicContentHeight
в обёртки надModalPage
/ModalCard
.Пример миграции (перенос `settlingHeight` / `dynamicContentHeight`)
Пример миграции (пробрасывание `settlingHeight` / `dynamicContentHeight`)
Улучшения
updateModalHeight()
помечен как@depreacted
, т.к. в нём больше нет необходимости –ModalPage
, приdynamicContentHeight
, теперь автоматически подстраиваются под контент;registerModal()
помечен как@depreacted
, т.к. изменилась логика работы компонента – теперьModalPage
иModalCard
ориентируется на контекст, создаваемыйModalRoot
;usePortal
.ModalPage
:ModalRoot
(для рендера в портале можно обернуть вAppRootPortal
);settlingHeight
–75
→50
;keepMounted
;footer
;disableContentPanningGestureProp
;onClose
до(reason: ModalPageCloseReason, event?: UIEvent<HTMLElement>) => void
.ModalCard
:ModalRoot
(для рендера в портале можно обернуть вAppRootPortal
);keepMounted
;onClose
до(reason: ModalPageCloseReason, event?: UIEvent<HTMLElement>) => void
.