From c1453c55d78c1ed27ecfec05046ca71ff7f769df Mon Sep 17 00:00:00 2001 From: Inomdzhon Mirdzhamolov Date: Tue, 26 Mar 2024 14:15:09 +0300 Subject: [PATCH] feat: create ModalPageV2 --- .../src/components/AppRoot/ScrollContext.tsx | 4 + .../ModalCard/ModalCard.e2e-playground.tsx | 2 +- .../components/ModalCard/ModalCard.module.css | 103 ++- .../ModalCard/ModalCard.stories.tsx | 72 +- .../src/components/ModalCard/ModalCard.tsx | 108 +-- .../components/ModalCard/ModalCardPrivate.tsx | 204 +++++ .../ModalCardBase/ModalCardBase.module.css | 1 - .../ModalCardBase/ModalCardBase.tsx | 9 +- .../components/ModalPage/ModalPage.module.css | 262 +++--- .../ModalPage/ModalPage.stories.tsx | 481 ++++++++--- .../components/ModalPage/ModalPage.test.tsx | 24 +- .../src/components/ModalPage/ModalPage.tsx | 198 +---- .../components/ModalPage/ModalPageContext.tsx | 8 +- .../components/ModalPage/ModalPagePrivate.tsx | 216 +++++ .../src/components/ModalPage/checklist.md | 25 + .../vkui/src/components/ModalPage/types.ts | 104 +++ .../ModalPageBackdrop.module.css | 60 ++ .../ModalPageBackdrop/ModalPageBackdrop.tsx | 50 ++ .../ModalPageContent.module.css | 4 + .../ModalPageContent/ModalPageContent.tsx | 25 + .../ModalPageFooter.module.css | 14 + .../ModalPageFooter/ModalPageFooter.tsx | 25 + .../ModalPageHeader.module.css | 11 +- .../ModalPageHeader/ModalPageHeader.tsx | 8 +- .../ModalPageRoot/ModalPageRoot.module.css | 16 + .../ModalPageRoot/ModalPageRoot.tsx | 31 + .../components/ModalRoot/ModalRoot.module.css | 59 -- .../ModalRoot/ModalRoot.stories.tsx | 67 +- .../components/ModalRoot/ModalRoot.test.tsx | 674 ++++----------- .../src/components/ModalRoot/ModalRoot.tsx | 769 ++---------------- .../ModalRoot/ModalRootAdaptive.test.tsx | 41 - .../ModalRoot/ModalRootAdaptive.tsx | 21 - .../components/ModalRoot/ModalRootContext.tsx | 56 +- .../components/ModalRoot/ModalRootDesktop.tsx | 243 ------ .../vkui/src/components/ModalRoot/Readme.md | 91 +-- .../src/components/ModalRoot/constants.ts | 1 - .../vkui/src/components/ModalRoot/types.ts | 65 +- .../ModalRoot/useModalManager.test.tsx | 302 ------- .../components/ModalRoot/useModalManager.tsx | 305 ++----- .../ModalRoot/useModalRootContext.tsx | 3 +- .../ModalRoot/withModalRootContext.test.tsx | 4 + .../ModalRoot/withModalRootContext.tsx | 2 +- .../SplitLayout/SplitLayout.stories.tsx | 2 +- packages/vkui/src/helpers/range.ts | 4 + packages/vkui/src/hooks/useKeyboard.ts | 56 -- .../vkui/src/hooks/useVirtualKeyboardState.ts | 170 ++++ packages/vkui/src/index.ts | 4 +- packages/vkui/src/lib/adaptivity/functions.ts | 9 +- packages/vkui/src/lib/animation/index.ts | 7 +- packages/vkui/src/lib/dom.tsx | 55 ++ packages/vkui/src/lib/sheet/constants.ts | 32 + .../controllers/BottomSheetController.ts | 331 ++++++++ .../controllers/CSSTransitionController.ts | 51 ++ packages/vkui/src/lib/sheet/index.ts | 10 + packages/vkui/src/lib/sheet/useBottomSheet.ts | 143 ++++ .../src/lib/touch/UIPanGestureRecognizer.ts | 21 +- packages/vkui/src/lib/touch/index.ts | 5 +- packages/vkui/src/storybook/ModalWrapper.tsx | 4 +- styleguide/config.js | 2 +- 59 files changed, 2706 insertions(+), 2968 deletions(-) create mode 100644 packages/vkui/src/components/ModalCard/ModalCardPrivate.tsx create mode 100644 packages/vkui/src/components/ModalPage/ModalPagePrivate.tsx create mode 100644 packages/vkui/src/components/ModalPage/checklist.md create mode 100644 packages/vkui/src/components/ModalPage/types.ts create mode 100644 packages/vkui/src/components/ModalPageBackdrop/ModalPageBackdrop.module.css create mode 100644 packages/vkui/src/components/ModalPageBackdrop/ModalPageBackdrop.tsx create mode 100644 packages/vkui/src/components/ModalPageContent/ModalPageContent.module.css create mode 100644 packages/vkui/src/components/ModalPageContent/ModalPageContent.tsx create mode 100644 packages/vkui/src/components/ModalPageFooter/ModalPageFooter.module.css create mode 100644 packages/vkui/src/components/ModalPageFooter/ModalPageFooter.tsx create mode 100644 packages/vkui/src/components/ModalPageRoot/ModalPageRoot.module.css create mode 100644 packages/vkui/src/components/ModalPageRoot/ModalPageRoot.tsx delete mode 100644 packages/vkui/src/components/ModalRoot/ModalRoot.module.css delete mode 100644 packages/vkui/src/components/ModalRoot/ModalRootAdaptive.test.tsx delete mode 100644 packages/vkui/src/components/ModalRoot/ModalRootAdaptive.tsx delete mode 100644 packages/vkui/src/components/ModalRoot/ModalRootDesktop.tsx delete mode 100644 packages/vkui/src/components/ModalRoot/constants.ts delete mode 100644 packages/vkui/src/components/ModalRoot/useModalManager.test.tsx delete mode 100644 packages/vkui/src/hooks/useKeyboard.ts create mode 100644 packages/vkui/src/hooks/useVirtualKeyboardState.ts create mode 100644 packages/vkui/src/lib/sheet/constants.ts create mode 100644 packages/vkui/src/lib/sheet/controllers/BottomSheetController.ts create mode 100644 packages/vkui/src/lib/sheet/controllers/CSSTransitionController.ts create mode 100644 packages/vkui/src/lib/sheet/index.ts create mode 100644 packages/vkui/src/lib/sheet/useBottomSheet.ts diff --git a/packages/vkui/src/components/AppRoot/ScrollContext.tsx b/packages/vkui/src/components/AppRoot/ScrollContext.tsx index 48e9c103450..3e148463661 100644 --- a/packages/vkui/src/components/AppRoot/ScrollContext.tsx +++ b/packages/vkui/src/components/AppRoot/ScrollContext.tsx @@ -13,6 +13,7 @@ const clearDisableScrollStyle = (node: HTMLElement) => { top: '', left: '', right: '', + overscrollBehavior: '', overflowY: '', overflowX: '', }); @@ -117,11 +118,13 @@ export const GlobalScrollController = ({ children }: ScrollControllerProps): Rea const overflowY = window!.innerWidth > document!.documentElement.clientWidth ? 'scroll' : ''; const overflowX = window!.innerHeight > document!.documentElement.clientHeight ? 'scroll' : ''; + document!.documentElement.style.setProperty('overscroll-behavior', 'none'); Object.assign(document!.body.style, { position: 'fixed', top: `-${scrollY}px`, left: `-${scrollX}px`, right: '0', + overscrollBehavior: 'none', overflowY, overflowX, }); @@ -131,6 +134,7 @@ export const GlobalScrollController = ({ children }: ScrollControllerProps): Rea const scrollY = document!.body.style.top; const scrollX = document!.body.style.left; + document!.documentElement.style.removeProperty('overscroll-behavior'); clearDisableScrollStyle(document!.body); window!.scrollTo(-parseInt(scrollX || '0'), -parseInt(scrollY || '0')); }, [document, window]); diff --git a/packages/vkui/src/components/ModalCard/ModalCard.e2e-playground.tsx b/packages/vkui/src/components/ModalCard/ModalCard.e2e-playground.tsx index 00b576a1487..7fb8bd9b637 100644 --- a/packages/vkui/src/components/ModalCard/ModalCard.e2e-playground.tsx +++ b/packages/vkui/src/components/ModalCard/ModalCard.e2e-playground.tsx @@ -9,7 +9,7 @@ import { import { Button } from '../Button/Button'; import { ButtonGroup } from '../ButtonGroup/ButtonGroup'; import { Image } from '../Image/Image'; -import { ModalRoot } from '../ModalRoot/ModalRootAdaptive'; +import { ModalRoot } from '../ModalRoot/ModalRoot'; import { Spacing } from '../Spacing/Spacing'; import { Textarea } from '../Textarea/Textarea'; import { UsersStack } from '../UsersStack/UsersStack'; diff --git a/packages/vkui/src/components/ModalCard/ModalCard.module.css b/packages/vkui/src/components/ModalCard/ModalCard.module.css index a421a005080..ce0c5b046f5 100644 --- a/packages/vkui/src/components/ModalCard/ModalCard.module.css +++ b/packages/vkui/src/components/ModalCard/ModalCard.module.css @@ -1,65 +1,82 @@ .host { - box-sizing: border-box; - position: absolute; - inset-block-start: 0; - padding: 8px; - inset-inline-start: 0; + padding: var(--vkui--spacing_size_m); + margin-inline: auto; inline-size: 100%; - block-size: 100%; - display: flex; - align-items: flex-end; + box-sizing: border-box; } .host:focus { outline: none; } -.in { - inline-size: 100%; - margin-inline: auto; - transform: translateY(calc(100% + 16px)); - transition: transform 340ms var(--vkui--animation_easing_platform); +.hostMaxWidthS { + max-inline-size: 400px; } -/** - * iOS - */ - -.ios .in { +.hostMaxWidthM { max-inline-size: 414px; } -/** - * Android + vkcom - */ - -.android .in { +.hostMaxWidthL { max-inline-size: 440px; } -.vkcom .in { - max-inline-size: 400px; -} +/* Mobile */ +@media (--viewWidth-smallTabletMinus) { + .host { + --vkui_internal_ModalCard--snapPoint: 100%; + --vkui_internal_ModalCard--safeAreaInsetBottom: var(--vkui_internal--safe_area_inset_bottom); -/** - * Desktop - */ + position: absolute; + inset-inline: 0; + inset-block-end: 0; + margin-block-end: var(--vkui_internal_ModalCard--safeAreaInsetBottom); + transform: translate3d(0, calc(100% - var(--vkui_internal_ModalCard--snapPoint)), 0); + transition: transform var(--vkui--animation_duration_l) var(--vkui--animation_easing_platform); + } -.desktop { - align-items: center; -} + .hostStateEnter { + transform: translate3d(0, 100%, 0); + transition-property: none; + } + + .hostStateEntering { + transition-property: transform; + transition-delay: 0.2s; + } -.desktop .in { - transform: unset; - opacity: 0; - transition: opacity 340ms var(--vkui--animation_easing_platform); + .hostStateExiting { + transform: translate3d(0, 100%, 0); + transition-property: transform; + } + + .hostStateExited { + transform: translate3d(0, 100%, 0); + transition-property: transform; + } } +/* Desktop */ +@media (--viewWidth-smallTabletPlus) { + .host { + margin-block: auto; + opacity: 1; + transition: opacity 340ms var(--vkui--animation_easing_platform); + } + + .hostStateEnter { + opacity: 0; + transition-property: none; + } + + .hostStateEntering { + opacity: 1; + } + + .hostStateExiting { + opacity: 0; + } -/** - * CMP: - * ModalRoot - */ -/* stylelint-disable-next-line selector-pseudo-class-disallowed-list */ -:global(.vkuiInternalModalRoot--touched) .in { - transition: none; + .hostStateExited { + opacity: 0; + } } diff --git a/packages/vkui/src/components/ModalCard/ModalCard.stories.tsx b/packages/vkui/src/components/ModalCard/ModalCard.stories.tsx index f5af257b3b5..9e6c75371bd 100644 --- a/packages/vkui/src/components/ModalCard/ModalCard.stories.tsx +++ b/packages/vkui/src/components/ModalCard/ModalCard.stories.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Icon56MoneyTransferOutline, Icon56NotificationOutline } from '@vkontakte/icons'; -import { ModalWrapper } from '../../storybook/ModalWrapper'; import { CanvasFullLayout, DisableCartesianParam } from '../../storybook/constants'; import { getAvatarUrl } from '../../testing/mock'; import { Avatar } from '../Avatar/Avatar'; @@ -23,17 +22,14 @@ export default story; type Story = StoryObj; -const MODAL_CARD_MONEY_SEND = 'money-send'; -const MODAL_CARD_APP_TO_MENU = 'app-to-menu'; -const MODAL_CARD_ABOUT = 'say-about'; -const MODAL_CARD_NOTIFICATIONS = 'notifications'; -const MODAL_CARD_CHAT_INVITE = 'chat-invite'; - export const SimpleCard: Story = { - render: () => ( - + render: function Render() { + const [open, setOpen] = React.useState(true); + const handleClose = () => setOpen(false); + return ( } title="Отправляйте деньги друзьям, используя банковскую карту" description="Номер карты получателя не нужен — он сам решит, куда зачислить средства." @@ -43,15 +39,18 @@ export const SimpleCard: Story = { } /> - - ), + ); + }, }; export const CardWithAvatar: Story = { - render: () => ( - + render: function Render() { + const [open, setOpen] = React.useState(true); + const handleClose = () => setOpen(false); + return ( } title="Добавить игру «Загадки детства» в меню?" description="Игра появится под списком разделов на экране меню и будет всегда под рукой." @@ -61,15 +60,18 @@ export const CardWithAvatar: Story = { } /> - - ), + ); + }, }; export const CardWithTextArea: Story = { - render: () => ( - + render: function Render() { + const [open, setOpen] = React.useState(true); + const handleClose = () => setOpen(false); + return ( @@ -79,15 +81,18 @@ export const CardWithTextArea: Story = { >