From b27361412861997245c177498ae703f4b1a1329f Mon Sep 17 00:00:00 2001 From: BOHA Date: Sun, 7 Jun 2026 09:53:41 +0200 Subject: [PATCH] feat(mui): PageEnter kit primitive (consistent staggered page entrance) + adopt in WarehouseSuppliers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/admin/pages/WarehouseSuppliers.tsx | 30 ++++++--------- src/admin/ui/PageEnter.tsx | 51 ++++++++++++++++++++++++++ src/admin/ui/index.ts | 1 + 3 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 src/admin/ui/PageEnter.tsx diff --git a/src/admin/pages/WarehouseSuppliers.tsx b/src/admin/pages/WarehouseSuppliers.tsx index 4f7f83f..62cadf1 100644 --- a/src/admin/pages/WarehouseSuppliers.tsx +++ b/src/admin/pages/WarehouseSuppliers.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import { motion } from "framer-motion"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; import IconButton from "@mui/material/IconButton"; @@ -24,6 +23,7 @@ import { TextField, StatusChip, PageHeader, + PageEnter, FilterBar, EmptyState, LoadingState, @@ -344,22 +344,16 @@ export default function WarehouseSuppliers() { ]; return ( - - - - Přidat dodavatele - - } - /> - + + + Přidat dodavatele + + } + /> @@ -525,6 +519,6 @@ export default function WarehouseSuppliers() { confirmVariant="danger" loading={deleteMutation.isPending} /> - + ); } diff --git a/src/admin/ui/PageEnter.tsx b/src/admin/ui/PageEnter.tsx new file mode 100644 index 0000000..64d75d9 --- /dev/null +++ b/src/admin/ui/PageEnter.tsx @@ -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 ``): 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; +}) { + const reduce = useReducedMotion(); + if (reduce) return {children}; + + return ( + + {Children.map(children, (child) => + isValidElement(child) ? ( + {child} + ) : ( + child + ), + )} + + ); +} diff --git a/src/admin/ui/index.ts b/src/admin/ui/index.ts index a220d0c..8418222 100644 --- a/src/admin/ui/index.ts +++ b/src/admin/ui/index.ts @@ -28,3 +28,4 @@ export { default as FileUpload } from "./FileUpload"; export { default as ProgressBar } from "./ProgressBar"; export type { ProgressColor } from "./ProgressBar"; export { default as ThemeToggle } from "./ThemeToggle"; +export { default as PageEnter } from "./PageEnter";