From 4496053d98843195eecec6ebbf686786fdb52033 Mon Sep 17 00:00:00 2001 From: mortezaei Date: Mon, 24 Aug 2026 18:28:42 +0330 Subject: [PATCH] refactor: standardize bottom sheet animations using CSS classes and consistent 200ms timing --- src/app/globals.css | 42 +++++++++++++++++++ src/app/questions-list/sections-request.tsx | 1 + .../Componentes/call-result-sheet.tsx | 12 +++--- src/components/Componentes/currency-sheet.tsx | 11 +++-- .../Componentes/dismiss-reason-sheet.tsx | 12 +++--- .../Componentes/female-consent-sheet.tsx | 12 +++--- .../Componentes/female-outcome-sheet.tsx | 12 +++--- src/components/Componentes/help-modal.tsx | 12 +++--- .../Componentes/information-sheet.tsx | 10 ++--- .../Componentes/outcome-selection-sheet.tsx | 12 +++--- .../Componentes/question-birthplace.tsx | 10 ++--- .../Componentes/question-date-sheet.tsx | 11 +++-- src/components/Componentes/question-phone.tsx | 11 +++-- src/components/Componentes/question-sheet.tsx | 11 +++-- .../Componentes/report-actions-sheet.tsx | 14 +++---- src/components/Componentes/support-sheet.tsx | 12 +++--- 16 files changed, 122 insertions(+), 83 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index cdc3128..bc50f1e 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -258,6 +258,48 @@ body.section-overlay-open .app-shell { overflow-y: hidden; } +/* ─── Flutter BottomSheet Exact Motion Match (Najm: 250ms in, 200ms out, easeOutCubic / easeIn) ─── */ +@keyframes flutter-bottomsheet-enter { + 0% { + transform: translate3d(0, 100%, 0); + } + 100% { + transform: translate3d(0, 0, 0); + } +} + +@keyframes flutter-scrim-enter { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +.flutter-sheet-surface { + animation: flutter-bottomsheet-enter 250ms cubic-bezier(0, 0, 0.2, 1) forwards; + will-change: transform; +} + +.flutter-sheet-surface-exit { + transform: translate3d(0, 100%, 0) !important; + transition: transform 200ms cubic-bezier(0.4, 0, 1, 1) !important; + will-change: transform; +} + +.flutter-scrim { + background-color: rgba(0, 0, 0, 0.54); + animation: flutter-scrim-enter 250ms cubic-bezier(0, 0, 0.2, 1) forwards; + will-change: opacity; +} + +.flutter-scrim-exit { + opacity: 0 !important; + transition: opacity 200ms cubic-bezier(0.4, 0, 1, 1) !important; + will-change: opacity; +} + /* ── Section Overlay Slide-in Panel (Exact Flutter Najm Matching: 350ms in, 200ms out, easeInOut) ── */ .section-overlay { position: fixed; diff --git a/src/app/questions-list/sections-request.tsx b/src/app/questions-list/sections-request.tsx index 398f075..dbdb660 100644 --- a/src/app/questions-list/sections-request.tsx +++ b/src/app/questions-list/sections-request.tsx @@ -87,6 +87,7 @@ export default function SectionsRequest({ return ( ( diff --git a/src/components/Componentes/call-result-sheet.tsx b/src/components/Componentes/call-result-sheet.tsx index e675ac0..bdb7065 100644 --- a/src/components/Componentes/call-result-sheet.tsx +++ b/src/components/Componentes/call-result-sheet.tsx @@ -4,7 +4,7 @@ import type { HTMLAttributes } from "react"; import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react"; import { useI18n } from "@/translations/provider"; -const EXIT_ANIMATION_MS = 220; +const EXIT_ANIMATION_MS = 200; export type CallResultSheetProps = Omit< HTMLAttributes, @@ -89,10 +89,8 @@ export function CallResultSheet({ return (
{ @@ -104,8 +107,8 @@ export function CurrencySheet({
{/* Header */} diff --git a/src/components/Componentes/dismiss-reason-sheet.tsx b/src/components/Componentes/dismiss-reason-sheet.tsx index 6ab7f51..3defaad 100644 --- a/src/components/Componentes/dismiss-reason-sheet.tsx +++ b/src/components/Componentes/dismiss-reason-sheet.tsx @@ -6,7 +6,7 @@ import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler"; import { useI18n } from "@/translations/provider"; import Button from "./button"; -const EXIT_ANIMATION_MS = 220; +const EXIT_ANIMATION_MS = 200; export type DismissReasonSheetProps = Omit< HTMLAttributes, @@ -104,10 +104,8 @@ export function DismissReasonSheet({ return (
, @@ -81,10 +81,8 @@ export function FemaleConsentSheet({ return (
diff --git a/src/components/Componentes/information-sheet.tsx b/src/components/Componentes/information-sheet.tsx index cfcfafb..ca28a68 100644 --- a/src/components/Componentes/information-sheet.tsx +++ b/src/components/Componentes/information-sheet.tsx @@ -9,7 +9,7 @@ import { LoadingThreeDot } from "./loading-three-dot"; import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler"; import { useI18n } from "@/translations/provider"; -const EXIT_ANIMATION_MS = 220; +const EXIT_ANIMATION_MS = 200; type InformationSheetPresetIcon = | "play" @@ -266,8 +266,8 @@ export function InformationSheet({ return (
, @@ -83,10 +83,8 @@ export function OutcomeSelectionSheet({ return (
e.stopPropagation()} > diff --git a/src/components/Componentes/question-date-sheet.tsx b/src/components/Componentes/question-date-sheet.tsx index 9a1e250..eb84f27 100644 --- a/src/components/Componentes/question-date-sheet.tsx +++ b/src/components/Componentes/question-date-sheet.tsx @@ -14,7 +14,7 @@ import { useI18n } from "@/translations/provider"; import { Button } from "./button"; import { useSheetScrollLock } from "./use-sheet-scroll-lock"; -const EXIT_ANIMATION_MS = 300; +const EXIT_ANIMATION_MS = 200; const WHEEL_ITEM_HEIGHT = 48; const WHEEL_EDGE_PADDING = 108; const SCROLL_SETTLE_MS = 90; @@ -274,7 +274,10 @@ export function QuestionDateSheet({ return createPortal(
diff --git a/src/components/Componentes/question-phone.tsx b/src/components/Componentes/question-phone.tsx index 580c316..86b35b3 100644 --- a/src/components/Componentes/question-phone.tsx +++ b/src/components/Componentes/question-phone.tsx @@ -15,7 +15,7 @@ import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; import { useSheetScrollLock } from "./use-sheet-scroll-lock"; -const EXIT_ANIMATION_MS = 300; +const EXIT_ANIMATION_MS = 200; type QuestionPhoneProps = { question: QuestionField; @@ -796,7 +796,10 @@ export function QuestionPhone({ {isOpen && createPortal(
{ @@ -808,8 +811,8 @@ export function QuestionPhone({ >
{/* Header with Title and Close Button */} diff --git a/src/components/Componentes/question-sheet.tsx b/src/components/Componentes/question-sheet.tsx index 4028d71..e51ee0c 100644 --- a/src/components/Componentes/question-sheet.tsx +++ b/src/components/Componentes/question-sheet.tsx @@ -13,7 +13,7 @@ import QuestionTitle from "./question-title"; import { registerCompactQuestionSheet } from "./question-viewport-coordinator"; import { useSheetScrollLock } from "./use-sheet-scroll-lock"; -const EXIT_ANIMATION_MS = 300; +const EXIT_ANIMATION_MS = 200; const EMPTY_ARRAY: string[] = []; export type QuestionSheetProps = { @@ -413,7 +413,10 @@ export function QuestionSheet({ question, disabled }: QuestionSheetProps) { {isOpen && createPortal(
{ @@ -426,11 +429,11 @@ export function QuestionSheet({ question, disabled }: QuestionSheetProps) {
diff --git a/src/components/Componentes/report-actions-sheet.tsx b/src/components/Componentes/report-actions-sheet.tsx index 2ba7b78..bd7b4b1 100644 --- a/src/components/Componentes/report-actions-sheet.tsx +++ b/src/components/Componentes/report-actions-sheet.tsx @@ -13,7 +13,7 @@ import { pickManualLocation, } from "@/lib/webview-actions"; -const EXIT_ANIMATION_MS = 220; +const EXIT_ANIMATION_MS = 200; type ReportActionsSheetProps = { onClose?: () => void; @@ -176,10 +176,8 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) { return (
{/* Header */} -
+

diff --git a/src/components/Componentes/support-sheet.tsx b/src/components/Componentes/support-sheet.tsx index 6fe9a07..f87c492 100644 --- a/src/components/Componentes/support-sheet.tsx +++ b/src/components/Componentes/support-sheet.tsx @@ -7,7 +7,7 @@ import { FiHeadphones } from "react-icons/fi"; import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler"; import { useI18n } from "@/translations/provider"; -const EXIT_ANIMATION_MS = 220; +const EXIT_ANIMATION_MS = 200; export type SupportSheetProps = { isOpen: boolean; @@ -89,10 +89,8 @@ export function SupportSheet({ isOpen, onClose }: SupportSheetProps) { return createPortal(