Skip to content

Commit

Permalink
feat: adding 4 direction in blur fade
Browse files Browse the repository at this point in the history
  • Loading branch information
itsarghyadas committed Dec 19, 2024
1 parent 49e7e31 commit 6d3921b
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 23 deletions.
23 changes: 12 additions & 11 deletions content/docs/components/blur-fade.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ npx shadcn@latest add "https://magicui.design/r/blur-fade"

## Props

| Prop | Type | Description | Default |
| ------------ | --------------- | ------------------------------------------------------ | ------- |
| children | React.ReactNode | The content to be animated | |
| className | string | The class name to be applied to the component | |
| variant | object | Custom animation variants for motion component | |
| duration | number | Duration (seconds) for the animation | 0.4 |
| delay | number | Delay (seconds) before the animation starts | 0 |
| yOffset | number | Vertical offset for the animation | 6 |
| inView | boolean | Whether to trigger animation when component is in view | false |
| inViewMargin | MarginType | Margin for triggering the in-view animation | "-50px" |
| blur | string | Amount of blur to apply during the animation | "6px" |
| Prop | Type | Description | Default |
| ------------ | --------------- | ----------------------------------------------------------- | ------- |
| children | React.ReactNode | The content to be animated | |
| className | string | The class name to be applied to the component | |
| variant | object | Custom animation variants for motion component | |
| duration | number | Duration (seconds) for the animation | 0.4 |
| delay | number | Delay (seconds) before the animation starts | 0 |
| offset | number | Offset for the animation | 6 |
| direction | string | Direction for the animation (`up`, `down`, `left`, `right`) | "down" |
| inView | boolean | Whether to trigger animation when component is in view | false |
| inViewMargin | MarginType | Margin for triggering the in-view animation | "-50px" |
| blur | string | Amount of blur to apply during the animation | "6px" |
2 changes: 1 addition & 1 deletion public/r/styles/default/blur-fade.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"files": [
{
"path": "magicui/blur-fade.tsx",
"content": "\"use client\";\n\nimport { useRef } from \"react\";\nimport {\n AnimatePresence,\n motion,\n useInView,\n UseInViewOptions,\n Variants,\n} from \"framer-motion\";\n\ntype MarginType = UseInViewOptions[\"margin\"];\n\ninterface BlurFadeProps {\n children: React.ReactNode;\n className?: string;\n variant?: {\n hidden: { y: number };\n visible: { y: number };\n };\n duration?: number;\n delay?: number;\n yOffset?: number;\n inView?: boolean;\n inViewMargin?: MarginType;\n blur?: string;\n}\n\nexport default function BlurFade({\n children,\n className,\n variant,\n duration = 0.4,\n delay = 0,\n yOffset = 6,\n inView = false,\n inViewMargin = \"-50px\",\n blur = \"6px\",\n}: BlurFadeProps) {\n const ref = useRef(null);\n const inViewResult = useInView(ref, { once: true, margin: inViewMargin });\n const isInView = !inView || inViewResult;\n const defaultVariants: Variants = {\n hidden: { y: yOffset, opacity: 0, filter: `blur(${blur})` },\n visible: { y: -yOffset, opacity: 1, filter: `blur(0px)` },\n };\n const combinedVariants = variant || defaultVariants;\n return (\n <AnimatePresence>\n <motion.div\n ref={ref}\n initial=\"hidden\"\n animate={isInView ? \"visible\" : \"hidden\"}\n exit=\"hidden\"\n variants={combinedVariants}\n transition={{\n delay: 0.04 + delay,\n duration,\n ease: \"easeOut\",\n }}\n className={className}\n >\n {children}\n </motion.div>\n </AnimatePresence>\n );\n}\n",
"content": "\"use client\";\n\nimport { useRef } from \"react\";\nimport {\n AnimatePresence,\n motion,\n useInView,\n UseInViewOptions,\n Variants,\n} from \"framer-motion\";\n\ntype MarginType = UseInViewOptions[\"margin\"];\n\ninterface BlurFadeProps {\n children: React.ReactNode;\n className?: string;\n variant?: {\n hidden: { y: number };\n visible: { y: number };\n };\n duration?: number;\n delay?: number;\n offset?: number;\n direction?: \"up\" | \"down\" | \"left\" | \"right\";\n inView?: boolean;\n inViewMargin?: MarginType;\n blur?: string;\n}\n\nexport default function BlurFade({\n children,\n className,\n variant,\n duration = 0.4,\n delay = 0,\n offset = 6,\n direction = \"down\",\n inView = false,\n inViewMargin = \"-50px\",\n blur = \"6px\",\n}: BlurFadeProps) {\n const ref = useRef(null);\n const inViewResult = useInView(ref, { once: true, margin: inViewMargin });\n const isInView = !inView || inViewResult;\n const defaultVariants: Variants = {\n hidden: {\n [direction === \"left\" || direction === \"right\" ? \"x\" : \"y\"]:\n direction === \"right\" || direction === \"down\" ? -offset : offset,\n opacity: 0,\n filter: `blur(${blur})`,\n },\n visible: {\n [direction === \"left\" || direction === \"right\" ? \"x\" : \"y\"]: 0,\n opacity: 1,\n filter: `blur(0px)`,\n },\n };\n const combinedVariants = variant || defaultVariants;\n return (\n <AnimatePresence>\n <motion.div\n ref={ref}\n initial=\"hidden\"\n animate={isInView ? \"visible\" : \"hidden\"}\n exit=\"hidden\"\n variants={combinedVariants}\n transition={{\n delay: 0.04 + delay,\n duration,\n ease: \"easeOut\",\n }}\n className={className}\n >\n {children}\n </motion.div>\n </AnimatePresence>\n );\n}\n",
"type": "registry:ui",
"target": ""
}
Expand Down
2 changes: 1 addition & 1 deletion public/r/styles/default/dock.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"files": [
{
"path": "magicui/dock.tsx",
"content": "\"use client\";\n\nimport React, { PropsWithChildren, useRef } from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport {\n motion,\n MotionValue,\n useMotionValue,\n useSpring,\n useTransform,\n} from \"framer-motion\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface DockProps extends VariantProps<typeof dockVariants> {\n className?: string;\n iconSize?: number;\n iconMagnification?: number;\n iconDistance?: number;\n direction?: \"top\" | \"middle\" | \"bottom\";\n children: React.ReactNode;\n}\n\nconst DEFAULT_SIZE = 40;\nconst DEFAULT_MAGNIFICATION = 60;\nconst DEFAULT_DISTANCE = 140;\n\nconst dockVariants = cva(\n \"supports-backdrop-blur:bg-white/10 supports-backdrop-blur:dark:bg-black/10 mx-auto mt-8 flex h-[58px] w-max items-center justify-center gap-2 rounded-2xl border p-2 backdrop-blur-md\",\n);\n\nconst Dock = React.forwardRef<HTMLDivElement, DockProps>(\n (\n {\n className,\n children,\n iconSize = DEFAULT_SIZE,\n iconMagnification = DEFAULT_MAGNIFICATION,\n iconDistance = DEFAULT_DISTANCE,\n direction = \"middle\",\n ...props\n },\n ref,\n ) => {\n const mouseX = useMotionValue(Infinity);\n\n const renderChildren = () => {\n return React.Children.map(children, (child) => {\n if (React.isValidElement(child) && child.type === DockIcon) {\n return React.cloneElement(child, {\n ...child.props,\n mouseX: mouseX,\n size: iconSize,\n magnification: iconMagnification,\n distance: iconDistance,\n });\n }\n return child;\n });\n };\n\n return (\n <motion.div\n ref={ref}\n onMouseMove={(e) => mouseX.set(e.pageX)}\n onMouseLeave={() => mouseX.set(Infinity)}\n {...props}\n className={cn(dockVariants({ className }), {\n \"items-start\": direction === \"top\",\n \"items-center\": direction === \"middle\",\n \"items-end\": direction === \"bottom\",\n })}\n >\n {renderChildren()}\n </motion.div>\n );\n },\n);\n\nDock.displayName = \"Dock\";\n\nexport interface DockIconProps {\n size?: number;\n magnification?: number;\n distance?: number;\n mouseX?: MotionValue<number>;\n className?: string;\n children?: React.ReactNode;\n props?: PropsWithChildren;\n}\n\nconst DockIcon = ({\n size = DEFAULT_SIZE,\n magnification = DEFAULT_MAGNIFICATION,\n distance = DEFAULT_DISTANCE,\n mouseX,\n className,\n children,\n ...props\n}: DockIconProps) => {\n const ref = useRef<HTMLDivElement>(null);\n const padding = Math.max(6, size * 0.2);\n const defaultMouseX = useMotionValue(Infinity);\n\n const distanceCalc = useTransform(mouseX ?? defaultMouseX, (val: number) => {\n const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };\n return val - bounds.x - bounds.width / 2;\n });\n\n const sizeTransform = useTransform(\n distanceCalc,\n [-distance, 0, distance],\n [size, magnification, size],\n );\n\n const scaleSize = useSpring(sizeTransform, {\n mass: 0.1,\n stiffness: 150,\n damping: 12,\n });\n\n return (\n <motion.div\n ref={ref}\n style={{ width: scaleSize, height: scaleSize, padding }}\n className={cn(\n \"flex aspect-square cursor-pointer items-center justify-center rounded-full\",\n className,\n )}\n {...props}\n >\n {children}\n </motion.div>\n );\n};\n\nDockIcon.displayName = \"DockIcon\";\n\nexport { Dock, DockIcon, dockVariants };\n",
"content": "\"use client\";\n\nimport React, { PropsWithChildren, useRef } from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport {\n motion,\n MotionValue,\n useMotionValue,\n useSpring,\n useTransform,\n MotionProps,\n} from \"framer-motion\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface DockProps extends VariantProps<typeof dockVariants> {\n className?: string;\n iconSize?: number;\n iconMagnification?: number;\n iconDistance?: number;\n direction?: \"top\" | \"middle\" | \"bottom\";\n children: React.ReactNode;\n}\n\nconst DEFAULT_SIZE = 40;\nconst DEFAULT_MAGNIFICATION = 60;\nconst DEFAULT_DISTANCE = 140;\n\nconst dockVariants = cva(\n \"supports-backdrop-blur:bg-white/10 supports-backdrop-blur:dark:bg-black/10 mx-auto mt-8 flex h-[58px] w-max items-center justify-center gap-2 rounded-2xl border p-2 backdrop-blur-md\",\n);\n\nconst Dock = React.forwardRef<HTMLDivElement, DockProps>(\n (\n {\n className,\n children,\n iconSize = DEFAULT_SIZE,\n iconMagnification = DEFAULT_MAGNIFICATION,\n iconDistance = DEFAULT_DISTANCE,\n direction = \"middle\",\n ...props\n },\n ref,\n ) => {\n const mouseX = useMotionValue(Infinity);\n\n const renderChildren = () => {\n return React.Children.map(children, (child) => {\n if (React.isValidElement(child) && child.type === DockIcon) {\n return React.cloneElement(child, {\n ...child.props,\n mouseX: mouseX,\n size: iconSize,\n magnification: iconMagnification,\n distance: iconDistance,\n });\n }\n return child;\n });\n };\n\n return (\n <motion.div\n ref={ref}\n onMouseMove={(e) => mouseX.set(e.pageX)}\n onMouseLeave={() => mouseX.set(Infinity)}\n {...props}\n className={cn(dockVariants({ className }), {\n \"items-start\": direction === \"top\",\n \"items-center\": direction === \"middle\",\n \"items-end\": direction === \"bottom\",\n })}\n >\n {renderChildren()}\n </motion.div>\n );\n },\n);\n\nDock.displayName = \"Dock\";\n\nexport interface DockIconProps\n extends Omit<MotionProps & React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n size?: number;\n magnification?: number;\n distance?: number;\n mouseX?: MotionValue<number>;\n className?: string;\n children?: React.ReactNode;\n props?: PropsWithChildren;\n}\n\nconst DockIcon = ({\n size = DEFAULT_SIZE,\n magnification = DEFAULT_MAGNIFICATION,\n distance = DEFAULT_DISTANCE,\n mouseX,\n className,\n children,\n ...props\n}: DockIconProps) => {\n const ref = useRef<HTMLDivElement>(null);\n const padding = Math.max(6, size * 0.2);\n const defaultMouseX = useMotionValue(Infinity);\n\n const distanceCalc = useTransform(mouseX ?? defaultMouseX, (val: number) => {\n const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };\n return val - bounds.x - bounds.width / 2;\n });\n\n const sizeTransform = useTransform(\n distanceCalc,\n [-distance, 0, distance],\n [size, magnification, size],\n );\n\n const scaleSize = useSpring(sizeTransform, {\n mass: 0.1,\n stiffness: 150,\n damping: 12,\n });\n\n return (\n <motion.div\n ref={ref}\n style={{ width: scaleSize, height: scaleSize, padding }}\n className={cn(\n \"flex aspect-square cursor-pointer items-center justify-center rounded-full\",\n className,\n )}\n {...props}\n >\n {children}\n </motion.div>\n );\n};\n\nDockIcon.displayName = \"DockIcon\";\n\nexport { Dock, DockIcon, dockVariants };\n",
"type": "registry:ui",
"target": ""
}
Expand Down
1 change: 1 addition & 0 deletions registry/default/example/blur-fade-demo.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @next/next/no-img-element */
import BlurFade from "@/registry/default/magicui/blur-fade";

const images = Array.from({ length: 9 }, (_, i) => {
Expand Down
2 changes: 1 addition & 1 deletion registry/default/example/blur-fade-text-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function BlurFadeTextDemo() {
</h2>
</BlurFade>
<BlurFade delay={0.25 * 2} inView>
<span className="text-xl text-pretty tracking-tighter sm:text-3xl xl:text-4xl/none">
<span className="text-pretty text-xl tracking-tighter sm:text-3xl xl:text-4xl/none">
Nice to meet you
</span>
</BlurFade>
Expand Down
19 changes: 15 additions & 4 deletions registry/default/magicui/blur-fade.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ interface BlurFadeProps {
};
duration?: number;
delay?: number;
yOffset?: number;
offset?: number;
direction?: "up" | "down" | "left" | "right";
inView?: boolean;
inViewMargin?: MarginType;
blur?: string;
Expand All @@ -32,7 +33,8 @@ export default function BlurFade({
variant,
duration = 0.4,
delay = 0,
yOffset = 6,
offset = 6,
direction = "down",
inView = false,
inViewMargin = "-50px",
blur = "6px",
Expand All @@ -41,8 +43,17 @@ export default function BlurFade({
const inViewResult = useInView(ref, { once: true, margin: inViewMargin });
const isInView = !inView || inViewResult;
const defaultVariants: Variants = {
hidden: { y: yOffset, opacity: 0, filter: `blur(${blur})` },
visible: { y: -yOffset, opacity: 1, filter: `blur(0px)` },
hidden: {
[direction === "left" || direction === "right" ? "x" : "y"]:
direction === "right" || direction === "down" ? -offset : offset,
opacity: 0,
filter: `blur(${blur})`,
},
visible: {
[direction === "left" || direction === "right" ? "x" : "y"]: 0,
opacity: 1,
filter: `blur(0px)`,
},
};
const combinedVariants = variant || defaultVariants;
return (
Expand Down
10 changes: 5 additions & 5 deletions registry/default/magicui/dock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const DEFAULT_MAGNIFICATION = 60;
const DEFAULT_DISTANCE = 140;

const dockVariants = cva(
"supports-backdrop-blur:bg-white/10 supports-backdrop-blur:dark:bg-black/10 mx-auto mt-8 flex h-[58px] w-max items-center justify-center gap-2 rounded-2xl border p-2 backdrop-blur-md"
"supports-backdrop-blur:bg-white/10 supports-backdrop-blur:dark:bg-black/10 mx-auto mt-8 flex h-[58px] w-max items-center justify-center gap-2 rounded-2xl border p-2 backdrop-blur-md",
);

const Dock = React.forwardRef<HTMLDivElement, DockProps>(
Expand All @@ -41,7 +41,7 @@ const Dock = React.forwardRef<HTMLDivElement, DockProps>(
direction = "middle",
...props
},
ref
ref,
) => {
const mouseX = useMotionValue(Infinity);

Expand Down Expand Up @@ -75,7 +75,7 @@ const Dock = React.forwardRef<HTMLDivElement, DockProps>(
{renderChildren()}
</motion.div>
);
}
},
);

Dock.displayName = "Dock";
Expand Down Expand Up @@ -112,7 +112,7 @@ const DockIcon = ({
const sizeTransform = useTransform(
distanceCalc,
[-distance, 0, distance],
[size, magnification, size]
[size, magnification, size],
);

const scaleSize = useSpring(sizeTransform, {
Expand All @@ -127,7 +127,7 @@ const DockIcon = ({
style={{ width: scaleSize, height: scaleSize, padding }}
className={cn(
"flex aspect-square cursor-pointer items-center justify-center rounded-full",
className
className,
)}
{...props}
>
Expand Down

0 comments on commit 6d3921b

Please sign in to comment.