FormFooterChangeBadge.tsx42 lines · main
| 1 | import { AnimatePresence, motion } from 'framer-motion' |
| 2 | |
| 3 | interface FormFooterChangeBadgeProps { |
| 4 | formState: { |
| 5 | dirtyFields: Record<string, boolean> |
| 6 | } |
| 7 | } |
| 8 | export const FormFooterChangeBadge = ({ formState }: FormFooterChangeBadgeProps) => { |
| 9 | return ( |
| 10 | <AnimatePresence mode="wait"> |
| 11 | {Object.keys(formState.dirtyFields).length > 0 && ( |
| 12 | <motion.div |
| 13 | initial={{ opacity: 0, scale: 0.9 }} |
| 14 | animate={{ opacity: 1, scale: 1 }} |
| 15 | exit={{ opacity: 0, scale: 0.9 }} |
| 16 | transition={{ duration: 0.2 }} |
| 17 | > |
| 18 | <motion.div |
| 19 | animate={{ |
| 20 | scale: [1, 1.05, 1], |
| 21 | transition: { duration: 0.3 }, |
| 22 | }} |
| 23 | > |
| 24 | <p className="text-sm text-foreground-lighter"> |
| 25 | <motion.span |
| 26 | key={Object.keys(formState.dirtyFields).length} |
| 27 | initial={{ opacity: 0, scale: 0.9 }} |
| 28 | animate={{ opacity: 1, scale: 1 }} |
| 29 | exit={{ opacity: 0, scale: 0.9 }} |
| 30 | transition={{ duration: 0.1 }} |
| 31 | > |
| 32 | {Object.keys(formState.dirtyFields).length === 1 |
| 33 | ? '1 change to review' |
| 34 | : `${Object.keys(formState.dirtyFields).length} changes to review`} |
| 35 | </motion.span> |
| 36 | </p> |
| 37 | </motion.div> |
| 38 | </motion.div> |
| 39 | )} |
| 40 | </AnimatePresence> |
| 41 | ) |
| 42 | } |