feat(mui): PageEnter kit primitive (consistent staggered page entrance) + adopt in WarehouseSuppliers
Each top-level child rises+fades in, staggered (0.4s, ease-out), so every page enters the same way and nothing appears instantly; honors prefers-reduced-motion. Replaces ad-hoc per-page motion.div entrance wrappers. One component → the look is tunable in one place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
51
src/admin/ui/PageEnter.tsx
Normal file
51
src/admin/ui/PageEnter.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Children, isValidElement, type ReactNode } from "react";
|
||||
import { motion, useReducedMotion, type Variants } from "framer-motion";
|
||||
import Box from "@mui/material/Box";
|
||||
import type { SxProps, Theme } from "@mui/material/styles";
|
||||
|
||||
const MotionBox = motion(Box);
|
||||
|
||||
const container: Variants = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: 0.05, delayChildren: 0.03 } },
|
||||
};
|
||||
|
||||
const itemVariant: Variants = {
|
||||
hidden: { opacity: 0, y: 12 },
|
||||
show: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.4, ease: [0.16, 1, 0.3, 1] },
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Consistent page entrance. Use as a page's OUTERMOST wrapper (in place of the
|
||||
* page's root `<Box>`): each top-level child rises + fades in, staggered, so the
|
||||
* whole page comes in the same way everywhere — no element appears instantly.
|
||||
* Wrapping each child in a block `motion.div` is layout-safe for the vertical
|
||||
* section stacks our pages use (header → filters → card/table); nested grids/
|
||||
* flex inside a section are untouched. Honors prefers-reduced-motion.
|
||||
*/
|
||||
export default function PageEnter({
|
||||
children,
|
||||
sx,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
sx?: SxProps<Theme>;
|
||||
}) {
|
||||
const reduce = useReducedMotion();
|
||||
if (reduce) return <Box sx={sx}>{children}</Box>;
|
||||
|
||||
return (
|
||||
<MotionBox variants={container} initial="hidden" animate="show" sx={sx}>
|
||||
{Children.map(children, (child) =>
|
||||
isValidElement(child) ? (
|
||||
<motion.div variants={itemVariant}>{child}</motion.div>
|
||||
) : (
|
||||
child
|
||||
),
|
||||
)}
|
||||
</MotionBox>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user