From cc3be0a6ac8b852ed1bfaf11d7c7e66a69df13b9 Mon Sep 17 00:00:00 2001 From: Jeroen Reumkens Date: Wed, 10 May 2023 10:26:59 +0200 Subject: [PATCH] CAL-1623 CAL-1620: Improve animation for booker, and push mini calendar down in fullscreen views (#8773) * CAL-1623 CAL-1620: Improve animation for booker, and push mini calendar down in fullscreen views * Updated yarn.lock --- packages/features/bookings/Booker/Booker.tsx | 23 ++-- packages/features/bookings/Booker/config.ts | 71 +++++++++++- packages/features/package.json | 2 +- yarn.lock | 108 +++---------------- 4 files changed, 91 insertions(+), 113 deletions(-) diff --git a/packages/features/bookings/Booker/Booker.tsx b/packages/features/bookings/Booker/Booker.tsx index 684b6f447e..3a88bff122 100644 --- a/packages/features/bookings/Booker/Booker.tsx +++ b/packages/features/bookings/Booker/Booker.tsx @@ -19,7 +19,7 @@ import { EventMeta } from "./components/EventMeta"; import { LargeCalendar } from "./components/LargeCalendar"; import { LargeViewHeader } from "./components/LargeViewHeader"; import { BookerSection } from "./components/Section"; -import { fadeInLeft, resizeAnimationConfig } from "./config"; +import { fadeInLeft, useBookerResizeAnimation } from "./config"; import { useBookerStore, useInitializeBookerStore } from "./store"; import type { BookerLayout, BookerProps } from "./types"; import { useEvent } from "./utils/event"; @@ -56,6 +56,8 @@ const BookerComponent = ({ username, eventSlug, month, rescheduleBooking }: Book const extraDays = layout === "large_timeslots" ? (isTablet ? 2 : 4) : 0; const onLayoutToggle = useCallback((newLayout: BookerLayout) => setLayout(newLayout), [setLayout]); + const animationScope = useBookerResizeAnimation(layout, bookerState); + useBrandColors({ brandColor: event.data?.profile.brandColor, darkBrandColor: event.data?.profile.darkBrandColor, @@ -124,24 +126,21 @@ const BookerComponent = ({ username, eventSlug, month, rescheduleBooking }: Book )}
- - + + {layout !== "small_calendar" && !(layout === "mobile" && bookerState === "booking") && (
diff --git a/packages/features/bookings/Booker/config.ts b/packages/features/bookings/Booker/config.ts index f77fd0ecbe..36ba429ffd 100644 --- a/packages/features/bookings/Booker/config.ts +++ b/packages/features/bookings/Booker/config.ts @@ -1,3 +1,7 @@ +import { cubicBezier, useAnimate } from "framer-motion"; +import { useReducedMotion } from "framer-motion"; +import { useEffect } from "react"; + import type { BookerLayout, BookerState } from "./types"; // Framer motion fade in animation configs. @@ -43,6 +47,7 @@ export const resizeAnimationConfig: ResizeAnimationConfig = { mobile: { default: { width: "100%", + minHeight: "0px", gridTemplateAreas: ` "meta" "main" @@ -54,28 +59,86 @@ export const resizeAnimationConfig: ResizeAnimationConfig = { small_calendar: { default: { width: "calc(var(--booker-meta-width) + var(--booker-main-width))", + minHeight: "450px", + height: "auto", gridTemplateAreas: `"meta main"`, gridTemplateColumns: "var(--booker-meta-width) var(--booker-main-width)", }, selecting_time: { - width: "100%", - maxWidth: "calc(var(--booker-meta-width) + var(--booker-main-width) + var(--booker-timeslots-width))", + width: "calc(var(--booker-meta-width) + var(--booker-main-width) + var(--booker-timeslots-width))", + minHeight: "450px", + height: "auto", gridTemplateAreas: `"meta main timeslots"`, gridTemplateColumns: "var(--booker-meta-width) 1fr var(--booker-timeslots-width)", }, }, large_calendar: { default: { - width: "100%", + width: "100vw", + height: "100vh", gridTemplateAreas: `"meta main"`, gridTemplateColumns: "var(--booker-meta-width) 1fr", }, }, large_timeslots: { default: { - width: "100%", + width: "100vw", + height: "100vh", gridTemplateAreas: `"meta main"`, gridTemplateColumns: "var(--booker-meta-width) 1fr", }, }, }; + +/** + * This hook returns a ref that should be set on the booker element. + * Based on that ref this hook animates the size of the booker element with framer motion. + * It also takes into account the prefers-reduced-motion setting, to not animate when that's set. + */ +export const useBookerResizeAnimation = (layout: BookerLayout, state: BookerState) => { + const prefersReducedMotion = useReducedMotion(); + const [animationScope, animate] = useAnimate(); + + useEffect(() => { + const animationConfig = resizeAnimationConfig[layout][state] || resizeAnimationConfig[layout].default; + + const animatedProperties = { + height: animationConfig?.height || "auto", + }; + + const nonAnimatedProperties = { + // Width is animated by the css class instead of via framer motion, + // because css is better at animating the calcs, framer motion might + // make some mistakes in that. + width: animationConfig?.width || "auto", + gridTemplateAreas: animationConfig?.gridTemplateAreas, + gridTemplateColumns: animationConfig?.gridTemplateColumns, + minHeight: animationConfig?.minHeight, + }; + + // We don't animate if users has set prefers-reduced-motion, + // or when the layout is mobile. + if (prefersReducedMotion || layout === "mobile") { + animate( + animationScope.current, + { + ...animatedProperties, + ...nonAnimatedProperties, + }, + { + duration: 0, + } + ); + } else { + animate(animationScope.current, nonAnimatedProperties, { + duration: 0, + }); + animate(animationScope.current, animatedProperties, { + duration: 0.5, + ease: cubicBezier(0.4, 0, 0.2, 1), + }); + } + }, [animate, animationScope, layout, prefersReducedMotion, state]); + + return animationScope; +}; diff --git a/packages/features/package.json b/packages/features/package.json index 7582de6295..2e74a919af 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -12,7 +12,7 @@ "@calcom/ui": "*", "@lexical/react": "^0.5.0", "dompurify": "^2.4.1", - "framer-motion": "^10.12.3", + "framer-motion": "^10.12.8", "lexical": "^0.5.0", "react-sticky-box": "^2.0.4", "zustand": "^4.3.2" diff --git a/yarn.lock b/yarn.lock index 3075c559e7..26578d35b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -134,25 +134,6 @@ __metadata: languageName: node linkType: hard -"@auth/core@npm:^0.1.4": - version: 0.1.4 - resolution: "@auth/core@npm:0.1.4" - dependencies: - "@panva/hkdf": 1.0.2 - cookie: 0.5.0 - jose: 4.11.1 - oauth4webapi: 2.0.5 - preact: 10.11.3 - preact-render-to-string: 5.2.3 - peerDependencies: - nodemailer: 6.8.0 - peerDependenciesMeta: - nodemailer: - optional: true - checksum: 64854404ea1883e0deb5535b34bed95cd43fc85094aeaf4f15a79e14045020eb944f844defe857edfc8528a0a024be89cbb2a3069dedef0e9217a74ca6c3eb79 - languageName: node - linkType: hard - "@aws-crypto/ie11-detection@npm:^3.0.0": version: 3.0.0 resolution: "@aws-crypto/ie11-detection@npm:3.0.0" @@ -4015,39 +3996,6 @@ __metadata: languageName: unknown linkType: soft -"@calcom/auth@workspace:apps/auth": - version: 0.0.0-use.local - resolution: "@calcom/auth@workspace:apps/auth" - dependencies: - "@auth/core": ^0.1.4 - "@calcom/app-store": "*" - "@calcom/app-store-cli": "*" - "@calcom/config": "*" - "@calcom/core": "*" - "@calcom/dayjs": "*" - "@calcom/embed-core": "workspace:*" - "@calcom/embed-react": "workspace:*" - "@calcom/embed-snippet": "workspace:*" - "@calcom/features": "*" - "@calcom/lib": "*" - "@calcom/prisma": "*" - "@calcom/trpc": "*" - "@calcom/tsconfig": "*" - "@calcom/types": "*" - "@calcom/ui": "*" - "@types/node": 16.9.1 - "@types/react": 18.0.26 - "@types/react-dom": 18.0.9 - eslint: ^8.34.0 - eslint-config-next: ^13.2.1 - next: ^13.2.1 - next-auth: ^4.20.1 - react: ^18.2.0 - react-dom: ^18.2.0 - typescript: ^4.9.4 - languageName: unknown - linkType: soft - "@calcom/caldavcalendar@workspace:packages/app-store/caldavcalendar": version: 0.0.0-use.local resolution: "@calcom/caldavcalendar@workspace:packages/app-store/caldavcalendar" @@ -4387,7 +4335,7 @@ __metadata: "@lexical/react": ^0.5.0 "@testing-library/react-hooks": ^8.0.1 dompurify: ^2.4.1 - framer-motion: ^10.12.3 + framer-motion: ^10.12.8 lexical: ^0.5.0 mockdate: ^3.0.5 react-sticky-box: ^2.0.4 @@ -8388,13 +8336,6 @@ __metadata: languageName: node linkType: hard -"@panva/hkdf@npm:1.0.2": - version: 1.0.2 - resolution: "@panva/hkdf@npm:1.0.2" - checksum: 75183b4d5ea816ef516dcea70985c610683579a9e2ac540c2d59b9a3ed27eedaff830a43a1c43c1683556a457c92ac66e09109ee995ab173090e4042c4c4bb03 - languageName: node - linkType: hard - "@panva/hkdf@npm:^1.0.2": version: 1.0.4 resolution: "@panva/hkdf@npm:1.0.4" @@ -22743,9 +22684,9 @@ __metadata: languageName: node linkType: hard -"framer-motion@npm:^10.12.3": - version: 10.12.3 - resolution: "framer-motion@npm:10.12.3" +"framer-motion@npm:^10.12.8": + version: 10.12.8 + resolution: "framer-motion@npm:10.12.8" dependencies: "@emotion/is-prop-valid": ^0.8.2 tslib: ^2.4.0 @@ -22760,7 +22701,7 @@ __metadata: optional: true react-dom: optional: true - checksum: c292da47b5bcb313e3db2ffe19e61b3c76bf59f4a45dc72f62a3d9b33f58533d420aced47d5e9eb06be20be97651c937ae91aebb93d8bad6d0412c2768715956 + checksum: 2e21e06eed99967e816c27101cc4d438048d9c7c36d318acfdb4f3d14eee593b022696303a9416032caf735f6817cdc6b287a7ed004b21d07f67c7cbe534edfe languageName: node linkType: hard @@ -26594,13 +26535,6 @@ __metadata: languageName: node linkType: hard -"jose@npm:4.11.1": - version: 4.11.1 - resolution: "jose@npm:4.11.1" - checksum: cd15cba258d0fd20f6168631ce2e94fda8442df80e43c1033c523915cecdf390a1cc8efe0eab0c2d65935ca973d791c668aea80724d2aa9c2879d4e70f3081d7 - languageName: node - linkType: hard - "jose@npm:4.12.0": version: 4.12.0 resolution: "jose@npm:4.12.0" @@ -30703,13 +30637,6 @@ __metadata: languageName: node linkType: hard -"oauth4webapi@npm:2.0.5": - version: 2.0.5 - resolution: "oauth4webapi@npm:2.0.5" - checksum: 32d0cb7b1cca42d51dfb88075ca2d69fe33172a807e8ea50e317d17cab3bc80588ab8ebcb7eb4600c371a70af4674595b4b341daf6f3a655f1efa1ab715bb6c9 - languageName: node - linkType: hard - "oauth@npm:^0.9.15": version: 0.9.15 resolution: "oauth@npm:0.9.15" @@ -32400,17 +32327,6 @@ __metadata: languageName: node linkType: hard -"preact-render-to-string@npm:5.2.3": - version: 5.2.3 - resolution: "preact-render-to-string@npm:5.2.3" - dependencies: - pretty-format: ^3.8.0 - peerDependencies: - preact: ">=10" - checksum: 6e46288d8956adde35b9fe3a21aecd9dea29751b40f0f155dea62f3896f27cb8614d457b32f48d33909d2da81135afcca6c55077520feacd7d15164d1371fb44 - languageName: node - linkType: hard - "preact-render-to-string@npm:^5.1.19": version: 5.2.6 resolution: "preact-render-to-string@npm:5.2.6" @@ -32422,13 +32338,6 @@ __metadata: languageName: node linkType: hard -"preact@npm:10.11.3, preact@npm:^10.6.3": - version: 10.11.3 - resolution: "preact@npm:10.11.3" - checksum: 9387115aa0581e8226309e6456e9856f17dfc0e3d3e63f774de80f3d462a882ba7c60914c05942cb51d51e23e120dcfe904b8d392d46f29ad15802941fe7a367 - languageName: node - linkType: hard - "preact@npm:10.4.1": version: 10.4.1 resolution: "preact@npm:10.4.1" @@ -32443,6 +32352,13 @@ __metadata: languageName: node linkType: hard +"preact@npm:^10.6.3": + version: 10.11.3 + resolution: "preact@npm:10.11.3" + checksum: 9387115aa0581e8226309e6456e9856f17dfc0e3d3e63f774de80f3d462a882ba7c60914c05942cb51d51e23e120dcfe904b8d392d46f29ad15802941fe7a367 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1"