Radial Nav
animate-ui/components-community-radial-navFreeComponent
A circular navigation menu with animated pointer and expanding buttons for smooth interactive transitions.
Install it
npx shadcn@latest add https://animate-ui.com/r/components-community-radial-nav.jsonSource
1'use client';23import * as React from 'react';4import { MousePointer2, type LucideIcon } from 'lucide-react';5import { motion, type Variants, type Transition } from 'motion/react';67type RadialNavProps = {8 size?: number;9 items: RadialNavItem[];10 menuButtonConfig?: MenuButtonConfig;11 defaultActiveId?: number;12 onActiveChange?: (id: number) => void;13};1415type RadialNavItem = {16 id: number;17 icon: LucideIcon;18 label: string;19 angle: number;20};2122type MenuButtonConfig = {23 iconSize?: number; // px24 buttonSize?: number; // px, button diameter when collapsed25 buttonPadding?: number; // px26};2728const defaultMenuButtonConfig: Required<MenuButtonConfig> = {29 iconSize: 20,30 buttonSize: 40,31 buttonPadding: 8,32};3334const POINTER_BASE_DEG = 45;3536const POINTER_ROT_SPRING = {37 type: 'spring',38 stiffness: 220,39 damping: 26,40} as const;4142const BUTTON_MOTION_CONFIG = {43 initial: 'rest',44 variants: {45 rest: { maxWidth: '40px' },46 hover: {47 maxWidth: '140px',48 transition: { type: 'spring', stiffness: 200, damping: 35, delay: 0.05 },49 },50 tap: { scale: 0.95 },51 },52 transition: { type: 'spring', stiffness: 200, damping: 25 },53} as const;5455const LABEL_VARIANTS: Variants = {56 rest: { opacity: 0, x: 4 },57 hover: {58 opacity: 1,59 x: 0,60 visibility: 'visible',61 width: 'auto',62 },63 tap: { opacity: 1, x: 0, visibility: 'visible', width: 'auto' },64};6566const LABEL_TRANSITION: Transition = {67 type: 'spring',68 stiffness: 200,69 damping: 25,70};7172function getPolarCoordinates(angleDeg: number, r: number) {73 const rad = ((angleDeg - 90) * Math.PI) / 180;74 return { x: r * Math.cos(rad), y: r * Math.sin(rad) };75}7677function calculateIconOffset({78 buttonSize,79 iconSize,80 buttonPadding,81 bias = 0,82}: {83 buttonSize: number;84 iconSize: number;85 buttonPadding: number;86 bias?: number;87}) {88 const centerOffset = (buttonSize - iconSize) / 2;89 return centerOffset - buttonPadding + bias;90}9192// eslint-disable-next-line @typescript-eslint/no-explicit-any93function withDefaults<T extends Record<string, any>>(94 defaults: T,95 overrides?: Partial<T>,96): T {97 return { ...defaults, ...overrides };98}99100function normalizeDeg(a: number) {101 return ((a % 360) + 360) % 360;102}103104function toNearestTurn(prev: number | undefined, target: number) {105 const b = normalizeDeg(target);106 if (prev === undefined) return b;107 const k = Math.round((prev - b) / 360);108 return b + 360 * k;109}110111function useShortestRotation(target: number) {112// … truncated
What it pulls in
npm packages
Files it writes
More from Animate UI
All 580 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Avatar Groupcomponents-animate-avatar-group | Animate UI | Components | Free | 1 dep | |
| Codecomponents-animate-code | Animate UI | Components | Free | 1 dep | |
| Code Tabscomponents-animate-code-tabs | Animate UI | Components | Free | 1 dep | |
| Cursorcomponents-animate-cursor | Animate UI | Components | Free | no deps | |
| GitHub Stars Wheelcomponents-animate-github-stars-wheel | Animate UI | Components | Free | 1 dep | |
| Tabscomponents-animate-tabs | Animate UI | Components | Free | no deps | |
| Tooltipcomponents-animate-tooltip | Animate UI | Components | Free | 1 dep | |
| Bubble Backgroundcomponents-backgrounds-bubble | Animate UI | Components | Free | 1 dep |
