{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"notification","type":"registry:block","title":"Notification","description":"A reusable notification component that displays animated messages with smooth slide and scale transitions, perfect for in-app alerts, toasts, and contextual updates.","dependencies":["motion"],"files":[{"path":"registry/100xui/blocks/notification/components/notification.tsx","content":"\"use client\";\n\nimport * as React from \"react\";\nimport {\n  motion,\n  useAnimate,\n  type Transition,\n  type HTMLMotionProps,\n  type MotionStyle,\n} from \"motion/react\";\nimport { XIcon } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface NotificationContextType {\n  dismissNotification: () => void;\n  showNotification: () => Promise<void>;\n  hideNotification: () => Promise<void>;\n  scope: React.RefObject<HTMLDivElement>;\n  expandedGap: React.CSSProperties[\"gap\"];\n  minVisibleContentHeight: React.CSSProperties[\"height\"];\n  initialContentScale: React.CSSProperties[\"scale\"];\n  slideFromTop: boolean;\n}\n\nconst NotificationContext = React.createContext<NotificationContextType | null>(\n  null,\n);\n\nfunction useNotification() {\n  const ctx = React.useContext(NotificationContext);\n  if (!ctx)\n    throw new Error(\n      \"useNotification must be used within Notification Provider\",\n    );\n  return ctx;\n}\n\ninterface NotificationProps extends React.ComponentProps<\"div\"> {\n  transition?: Partial<Record<\"scale\" | \"translateY\", Transition>>;\n  initialContentScale?: React.CSSProperties[\"scale\"];\n  expandedGap?: React.CSSProperties[\"gap\"];\n  minVisibleContentHeight?: React.CSSProperties[\"height\"];\n  slideContentFrom?: \"bottom\" | \"top\";\n}\n\nexport function Notification({\n  transition: { scale: scaleTransition, translateY: translateYTransition } = {\n    scale: { ease: \"easeOut\" },\n    translateY: { ease: \"easeOut\" },\n  },\n  initialContentScale = 0.95,\n  expandedGap = \"calc(var(--spacing) * 2)\",\n  minVisibleContentHeight = \"calc(var(--spacing) * 2)\",\n  onMouseLeave,\n  className,\n  children,\n  slideContentFrom = \"top\",\n  ...rest\n}: NotificationProps) {\n  const [isRendered, setIsRendered] = React.useState(true);\n  const [scope, animate] = useAnimate();\n  const slideFromTop = slideContentFrom === \"top\";\n\n  const showNotification = async () => {\n    await animate(scope.current, { y: \"0px\" }, translateYTransition);\n    await animate(scope.current, { scale: 1 }, scaleTransition);\n  };\n\n  const hideNotification = async () => {\n    await animate(\n      scope.current,\n      { scale: initialContentScale },\n      scaleTransition,\n    );\n    await animate(\n      scope.current,\n      {\n        y: `calc(${slideFromTop ? \"1\" : \"-1\"} * (-100% - ${expandedGap} + ${minVisibleContentHeight}))`,\n      },\n      translateYTransition,\n    );\n  };\n\n  const dismissNotification = () => setIsRendered(false);\n\n  return (\n    <>\n      {isRendered && (\n        <NotificationContext.Provider\n          value={{\n            dismissNotification,\n            showNotification,\n            hideNotification,\n            scope,\n            expandedGap,\n            minVisibleContentHeight,\n            initialContentScale,\n            slideFromTop,\n          }}\n        >\n          <div\n            className={cn(\"fixed isolate flex flex-col\", className)}\n            onMouseLeave={(e) => {\n              hideNotification();\n              onMouseLeave?.(e);\n            }}\n            {...rest}\n          >\n            {children}\n          </div>\n        </NotificationContext.Provider>\n      )}\n    </>\n  );\n}\n\nexport function NotificationTrigger({\n  className,\n  children,\n  onMouseEnter,\n  ...rest\n}: React.ComponentProps<\"div\">) {\n  const { showNotification, slideFromTop } = useNotification();\n\n  return (\n    <div\n      onMouseEnter={(e) => {\n        showNotification();\n        onMouseEnter?.(e);\n      }}\n      className={cn(\n        \"bg-secondary text-secondary-foreground border-border/50 relative z-20 rounded-lg border p-3 shadow-md\",\n        className,\n        slideFromTop ? \"order-1\" : \"order-2\",\n      )}\n      {...rest}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport function NotificationContent({\n  children,\n  className,\n  style,\n  ...rest\n}: Omit<HTMLMotionProps<\"div\">, \"ref\">) {\n  const {\n    scope,\n    expandedGap,\n    minVisibleContentHeight,\n    initialContentScale,\n    slideFromTop,\n  } = useNotification();\n\n  const contentStyle: MotionStyle = {\n    ...style,\n    scale: initialContentScale,\n    y: `calc(${slideFromTop ? \"1\" : \"-1\"} * (-100% - ${expandedGap} + ${minVisibleContentHeight}))`,\n    transformOrigin: `50% ${slideFromTop ? \"100%\" : \"0%\"}`,\n    [slideFromTop ? \"marginTop\" : \"marginBottom\"]: expandedGap,\n  };\n\n  return (\n    <div\n      className={cn(\n        \"pointer-events-none relative z-10 -m-2 flex overflow-hidden p-2\",\n        slideFromTop ? \"order-2 pb-10\" : \"order-1 pt-10\",\n      )}\n    >\n      <motion.div\n        style={contentStyle}\n        ref={scope}\n        className={cn(\n          \"bg-secondary text-secondary-foreground border-border/50 pointer-events-auto w-full overflow-y-auto rounded-lg border p-3 shadow-md\",\n          className,\n        )}\n        {...rest}\n      >\n        {children}\n      </motion.div>\n    </div>\n  );\n}\n\nexport function NotificationCancel({\n  children = <XIcon className=\"size-3\" />,\n}: React.ComponentProps<\"button\">) {\n  const { dismissNotification, hideNotification, slideFromTop } =\n    useNotification();\n\n  return (\n    <button\n      onClick={dismissNotification}\n      onMouseEnter={hideNotification}\n      className={cn(\n        \"bg-destructive text-primary-foreground absolute right-0 z-30 aspect-square translate-x-1/3 cursor-pointer rounded-full p-1\",\n        slideFromTop ? \"top-0 -translate-y-1/3\" : \"bottom-0 translate-y-1/3\",\n      )}\n    >\n      {children}\n    </button>\n  );\n}\n","type":"registry:component"}]}