canvas-ui-sdk 0.3.8 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +74 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/registry/blocks/component-palette.json +1 -1
- package/registry/blocks/component-search.json +1 -1
- package/registry/blocks/custom-component-helper.json +1 -1
- package/registry/blocks/faqs-table.json +1 -1
- package/registry/blocks/infinity-canvas.json +1 -1
- package/registry/blocks/menu-section.json +1 -1
- package/registry/blocks/messenger-sidebar.json +1 -1
- package/registry/blocks/mobile-bottom-nav.json +1 -1
- package/registry/blocks/pagination.json +1 -1
- package/registry/blocks/pill-tabs.json +1 -1
- package/registry/blocks/pricing-cards.json +1 -1
- package/registry/blocks/profile-card.json +1 -1
- package/registry/blocks/prompt-template.json +1 -1
- package/registry/blocks/screen-flowchart.json +1 -1
- package/registry/blocks/screen-prompt-builder.json +1 -1
- package/registry/blocks/screen-prompt-template.json +1 -1
- package/registry/blocks/sidebar-cards.json +1 -1
- package/registry/blocks/slideshow-grid-tiles.json +1 -1
- package/registry/blocks/social-feed.json +1 -1
- package/registry/blocks/upvoting-posts-table.json +1 -1
- package/registry/layout/double-sidebar.json +1 -1
- package/registry/layout/header.json +1 -1
- package/registry/layout/icon-sidebar.json +1 -1
- package/registry/layout/project-context-shell.json +1 -1
- package/registry/layout/sidebar-nav.json +1 -1
- package/registry/ui/button.json +1 -1
- package/registry/ui/dialog.json +1 -1
- package/registry/ui/dropdown-menu.json +1 -1
- package/registry/ui/line-tabs.json +1 -1
- package/registry/ui/popover.json +1 -1
- package/registry/ui/select.json +1 -1
- package/registry/ui/selectable-pills.json +1 -1
- package/registry/ui/sheet.json +1 -1
- package/registry/ui/tabs.json +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/layout/icon-sidebar.tsx",
|
|
8
8
|
"type": "registry:layout",
|
|
9
|
-
"content": "\"use client\";\n\nimport { cn } from \"../../lib/utils\";\nimport { LucideIcon, Home, Users, Calendar, MessageSquare, PieChart, FileText, ShoppingBag } from \"lucide-react\";\nimport { useThemeImages, useThemeBranding } from \"../../context/theme-context\";\n\n// Phosphor Icons for Logo\nimport { Buildings, type Icon as PhosphorIcon } from \"@phosphor-icons/react\";\nimport {\n Diamond, Hexagon, Star, Lightning, Sparkle, Infinity, Code, Terminal, Cpu,\n Database, Globe, Cloud, WifiHigh, Briefcase, Storefront, Handshake, ChartLine,\n Palette as PaletteIcon, PencilSimple, Camera, MusicNote, Lightbulb, Leaf, Tree,\n Sun, Moon, Fire, Drop, ChatCircle, Envelope, Phone, Megaphone, Heart, Shield,\n Trophy, Rocket, Target, Flag,\n} from \"@phosphor-icons/react\";\n\n// ============================================\n// Icon Shape Presets for Logo Creator\n// ============================================\n\ntype IconShapeId = \"rounded\" | \"circle\" | \"square\";\n\ninterface IconShape {\n id: IconShapeId;\n renderBackground: (bgColor: string) => React.ReactNode;\n}\n\nconst iconShapes: IconShape[] = [\n {\n id: \"rounded\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" rx=\"10\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"circle\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <circle cx=\"16\" cy=\"16\" r=\"16\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"square\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n];\n\n// Map icon names to components\nconst iconMap: Record<string, PhosphorIcon> = {\n Diamond, Hexagon, Star, Lightning, Sparkle, Infinity, Code, Terminal, Cpu,\n Database, Globe, Cloud, WifiHigh, Briefcase, Buildings, Storefront, Handshake,\n ChartLine, Palette: PaletteIcon, PencilSimple, Camera, MusicNote, Lightbulb,\n Leaf, Tree, Sun, Moon, Fire, Drop, ChatCircle, Envelope, Phone, Megaphone,\n Heart, Shield, Trophy, Rocket, Target, Flag,\n};\n\n// Helper to resolve CSS variable references to actual hex colors\nfunction resolveBrandingColor(value: string): string {\n if (!value) return \"#ffffff\";\n if (value.startsWith(\"var(\")) {\n const varName = value.replace(\"var(\", \"\").replace(\")\", \"\");\n if (typeof window !== \"undefined\") {\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();\n return computed || \"#ffffff\";\n }\n return \"#ffffff\";\n }\n return value;\n}\n\n// ============================================\n// Icon Nav Item\n// ============================================\n\nexport interface IconNavItemConfig {\n id: string;\n label: string;\n icon: LucideIcon;\n href?: string;\n isActive?: boolean;\n hasNotification?: boolean;\n}\n\ninterface IconNavItemProps {\n item: IconNavItemConfig;\n variant?: \"dark\" | \"light\";\n onClick?: () => void;\n}\n\nfunction IconNavItem({ item, variant = \"dark\", onClick }: IconNavItemProps) {\n const Icon = item.icon;\n const isDark = variant === \"dark\";\n const isActive = item.isActive;\n\n return (\n <button\n onClick={onClick}\n className={cn(\n \"relative flex flex-col items-center justify-center gap-1 w-16 h-16 rounded-[var(--radius-nav)] transition-colors\",\n // Dark variant\n isDark && isActive && \"bg-[var(--canvas-sidebar-dark-active-bg)]\",\n isDark && !isActive && \"hover:bg-[var(--canvas-sidebar-dark-active-bg)]/50\",\n // Light variant\n !isDark && isActive && \"bg-[var(--canvas-sidebar-light-active-bg)]\",\n !isDark && !isActive && \"hover:bg-[var(--canvas-sidebar-light-active-bg)]/50\"\n )}\n >\n <Icon\n className={cn(\n \"size-4\",\n isDark && isActive && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)]\",\n !isDark && isActive && \"text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)]\"\n )}\n />\n <span\n className={cn(\n isDark && isActive && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)]\",\n !isDark && isActive && \"text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)]\"\n )}\n style={{\n fontFamily: \"var(--typo-sidebar-tab-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-body-xs-size)\",\n fontWeight: \"var(--typo-sidebar-tab-weight)\",\n letterSpacing: \"var(--typo-sidebar-tab-spacing)\",\n lineHeight: \"var(--typo-sidebar-tab-line-height)\",\n }}\n >\n {item.label}\n </span>\n\n {/* Notification Badge */}\n {item.hasNotification && (\n <div className=\"absolute top-2 right-4 size-1.5 rounded-full bg-[var(--canvas-destructive)]\" />\n )}\n </button>\n );\n}\n\n// ============================================\n// Default Navigation Items\n// ============================================\n\nexport const defaultIconNavItems: IconNavItemConfig[] = [\n { id: \"home\", label: \"Home\", icon: Home, isActive: true },\n { id: \"teams\", label: \"Teams\", icon: Users },\n { id: \"calendar\", label: \"Calendar\", icon: Calendar },\n { id: \"messages\", label: \"Messages\", icon: MessageSquare, hasNotification: true },\n { id: \"reports\", label: \"Reports\", icon: PieChart },\n { id: \"docs\", label: \"Docs\", icon: FileText },\n { id: \"orders\", label: \"Orders\", icon: ShoppingBag },\n];\n\n// ============================================\n// Icon Sidebar\n// ============================================\n\ninterface IconSidebarProps {\n /** Navigation items to display */\n items?: IconNavItemConfig[];\n /** Visual variant - dark for desktop, light for mobile sheet */\n variant?: \"dark\" | \"light\";\n /** Callback when a nav item is clicked */\n onItemClick?: (item: IconNavItemConfig) => void;\n /** Additional class names */\n className?: string;\n}\n\n/**\n * Canvas Design System - Icon Sidebar Component\n * \n * A narrow sidebar (96px) with vertically stacked icon navigation.\n * Desktop: Fixed dark sidebar on the left\n * Mobile: Light theme sidebar rendered inside a Sheet\n */\nexport function IconSidebar({\n items = defaultIconNavItems,\n variant = \"dark\",\n onItemClick,\n className\n}: IconSidebarProps) {\n const isDark = variant === \"dark\";\n const themeImages = useThemeImages();\n const { branding, isMounted } = useThemeBranding();\n\n // Get the appropriate logo based on variant\n const logoUrl = isDark ? themeImages.logoDark : themeImages.logoLight;\n\n // Get the icon shape renderer\n const iconShape = iconShapes.find(s => s.id === branding.iconShape) || iconShapes[0];\n\n return (\n <aside\n className={cn(\n \"flex flex-col items-center h-full w-[var(--icon-sidebar-width)]\",\n isDark && \"bg-[var(--canvas-sidebar-dark-bg)] border-r border-[var(--canvas-sidebar-dark-border)]\",\n !isDark && \"bg-[var(--canvas-background)] border-r border-[var(--canvas-border)]\",\n className\n )}\n >\n {/* Logo Section - Just the icon, no wordmark */}\n {/* Hidden until mounted to prevent hydration flash */}\n <div className={`flex items-center justify-center shrink-0 py-5 ${isMounted ? 'opacity-100' : 'opacity-0'}`}>\n {logoUrl ? (\n // Custom logo\n <img\n src={logoUrl}\n alt=\"Logo\"\n className=\"size-8 object-contain\"\n />\n ) : (\n // Logo creator: dynamic icon shape + Phosphor icon (no wordmark for narrow sidebar)\n // Uses CSS variables directly - no JavaScript resolution needed\n <div className=\"relative size-8 shrink-0\">\n {iconShape.renderBackground(branding.bgColor || \"var(--canvas-primary)\")}\n <div className=\"absolute inset-0 flex items-center justify-center z-10\">\n {(() => {\n const IconComponent = iconMap[branding.iconName || \"Buildings\"] || Buildings;\n return <IconComponent weight=\"bold\" size={18} color={branding.iconColor || \"var(--canvas-primary-foreground)\"} />;\n })()}\n </div>\n </div>\n )}\n </div>\n\n {/* Navigation Items */}\n <nav className=\"flex flex-col items-center gap-1 flex-1 px-4 pb-5\">\n {items.map((item) => (\n <IconNavItem\n key={item.id}\n item={item}\n variant={variant}\n onClick={() => onItemClick?.(item)}\n />\n ))}\n </nav>\n </aside>\n );\n}\n\n"
|
|
9
|
+
"content": "\"use client\";\n\nimport { cn } from \"../../lib/utils\";\nimport { LucideIcon, Home, Users, Calendar, MessageSquare, PieChart, FileText, ShoppingBag } from \"lucide-react\";\nimport { useThemeImages, useThemeBranding } from \"../../context/theme-context\";\n\n// Phosphor Icons for Logo\nimport { Buildings, type Icon as PhosphorIcon } from \"@phosphor-icons/react\";\nimport {\n Diamond, Hexagon, Star, Lightning, Sparkle, Infinity, Code, Terminal, Cpu,\n Database, Globe, Cloud, WifiHigh, Briefcase, Storefront, Handshake, ChartLine,\n Palette as PaletteIcon, PencilSimple, Camera, MusicNote, Lightbulb, Leaf, Tree,\n Sun, Moon, Fire, Drop, ChatCircle, Envelope, Phone, Megaphone, Heart, Shield,\n Trophy, Rocket, Target, Flag,\n} from \"@phosphor-icons/react\";\n\n// ============================================\n// Icon Shape Presets for Logo Creator\n// ============================================\n\ntype IconShapeId = \"rounded\" | \"circle\" | \"square\";\n\ninterface IconShape {\n id: IconShapeId;\n renderBackground: (bgColor: string) => React.ReactNode;\n}\n\nconst iconShapes: IconShape[] = [\n {\n id: \"rounded\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" rx=\"10\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"circle\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <circle cx=\"16\" cy=\"16\" r=\"16\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"square\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n];\n\n// Map icon names to components\nconst iconMap: Record<string, PhosphorIcon> = {\n Diamond, Hexagon, Star, Lightning, Sparkle, Infinity, Code, Terminal, Cpu,\n Database, Globe, Cloud, WifiHigh, Briefcase, Buildings, Storefront, Handshake,\n ChartLine, Palette: PaletteIcon, PencilSimple, Camera, MusicNote, Lightbulb,\n Leaf, Tree, Sun, Moon, Fire, Drop, ChatCircle, Envelope, Phone, Megaphone,\n Heart, Shield, Trophy, Rocket, Target, Flag,\n};\n\n// Helper to resolve CSS variable references to actual hex colors\nfunction resolveBrandingColor(value: string): string {\n if (!value) return \"#ffffff\";\n if (value.startsWith(\"var(\")) {\n const varName = value.replace(\"var(\", \"\").replace(\")\", \"\");\n if (typeof window !== \"undefined\") {\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();\n return computed || \"#ffffff\";\n }\n return \"#ffffff\";\n }\n return value;\n}\n\n// ============================================\n// Icon Nav Item\n// ============================================\n\nexport interface IconNavItemConfig {\n id: string;\n label: string;\n icon: LucideIcon;\n href?: string;\n isActive?: boolean;\n hasNotification?: boolean;\n}\n\ninterface IconNavItemProps {\n item: IconNavItemConfig;\n variant?: \"dark\" | \"light\";\n onClick?: () => void;\n}\n\nfunction IconNavItem({ item, variant = \"dark\", onClick }: IconNavItemProps) {\n const Icon = item.icon;\n const isDark = variant === \"dark\";\n const isActive = item.isActive;\n\n return (\n <button\n onClick={onClick}\n className={cn(\n \"cursor-pointer relative flex flex-col items-center justify-center gap-1 w-16 h-16 rounded-[var(--radius-nav)] transition-colors\",\n // Dark variant\n isDark && isActive && \"bg-[var(--canvas-sidebar-dark-active-bg)]\",\n isDark && !isActive && \"hover:bg-[var(--canvas-sidebar-dark-active-bg)]/50\",\n // Light variant\n !isDark && isActive && \"bg-[var(--canvas-sidebar-light-active-bg)]\",\n !isDark && !isActive && \"hover:bg-[var(--canvas-sidebar-light-active-bg)]/50\"\n )}\n >\n <Icon\n className={cn(\n \"size-4\",\n isDark && isActive && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)]\",\n !isDark && isActive && \"text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)]\"\n )}\n />\n <span\n className={cn(\n isDark && isActive && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)]\",\n !isDark && isActive && \"text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)]\"\n )}\n style={{\n fontFamily: \"var(--typo-sidebar-tab-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-body-xs-size)\",\n fontWeight: \"var(--typo-sidebar-tab-weight)\",\n letterSpacing: \"var(--typo-sidebar-tab-spacing)\",\n lineHeight: \"var(--typo-sidebar-tab-line-height)\",\n }}\n >\n {item.label}\n </span>\n\n {/* Notification Badge */}\n {item.hasNotification && (\n <div className=\"absolute top-2 right-4 size-1.5 rounded-full bg-[var(--canvas-destructive)]\" />\n )}\n </button>\n );\n}\n\n// ============================================\n// Default Navigation Items\n// ============================================\n\nexport const defaultIconNavItems: IconNavItemConfig[] = [\n { id: \"home\", label: \"Home\", icon: Home, isActive: true },\n { id: \"teams\", label: \"Teams\", icon: Users },\n { id: \"calendar\", label: \"Calendar\", icon: Calendar },\n { id: \"messages\", label: \"Messages\", icon: MessageSquare, hasNotification: true },\n { id: \"reports\", label: \"Reports\", icon: PieChart },\n { id: \"docs\", label: \"Docs\", icon: FileText },\n { id: \"orders\", label: \"Orders\", icon: ShoppingBag },\n];\n\n// ============================================\n// Icon Sidebar\n// ============================================\n\ninterface IconSidebarProps {\n /** Navigation items to display */\n items?: IconNavItemConfig[];\n /** Visual variant - dark for desktop, light for mobile sheet */\n variant?: \"dark\" | \"light\";\n /** Callback when a nav item is clicked */\n onItemClick?: (item: IconNavItemConfig) => void;\n /** Additional class names */\n className?: string;\n}\n\n/**\n * Canvas Design System - Icon Sidebar Component\n * \n * A narrow sidebar (96px) with vertically stacked icon navigation.\n * Desktop: Fixed dark sidebar on the left\n * Mobile: Light theme sidebar rendered inside a Sheet\n */\nexport function IconSidebar({\n items = defaultIconNavItems,\n variant = \"dark\",\n onItemClick,\n className\n}: IconSidebarProps) {\n const isDark = variant === \"dark\";\n const themeImages = useThemeImages();\n const { branding, isMounted } = useThemeBranding();\n\n // Get the appropriate logo based on variant\n const logoUrl = isDark ? themeImages.logoDark : themeImages.logoLight;\n\n // Get the icon shape renderer\n const iconShape = iconShapes.find(s => s.id === branding.iconShape) || iconShapes[0];\n\n return (\n <aside\n className={cn(\n \"flex flex-col items-center h-full w-[var(--icon-sidebar-width)]\",\n isDark && \"bg-[var(--canvas-sidebar-dark-bg)] border-r border-[var(--canvas-sidebar-dark-border)]\",\n !isDark && \"bg-[var(--canvas-background)] border-r border-[var(--canvas-border)]\",\n className\n )}\n >\n {/* Logo Section - Just the icon, no wordmark */}\n {/* Hidden until mounted to prevent hydration flash */}\n <div className={`flex items-center justify-center shrink-0 py-5 ${isMounted ? 'opacity-100' : 'opacity-0'}`}>\n {logoUrl ? (\n // Custom logo\n <img\n src={logoUrl}\n alt=\"Logo\"\n className=\"size-8 object-contain\"\n />\n ) : (\n // Logo creator: dynamic icon shape + Phosphor icon (no wordmark for narrow sidebar)\n // Uses CSS variables directly - no JavaScript resolution needed\n <div className=\"relative size-8 shrink-0\">\n {iconShape.renderBackground(branding.bgColor || \"var(--canvas-primary)\")}\n <div className=\"absolute inset-0 flex items-center justify-center z-10\">\n {(() => {\n const IconComponent = iconMap[branding.iconName || \"Buildings\"] || Buildings;\n return <IconComponent weight=\"bold\" size={18} color={branding.iconColor || \"var(--canvas-primary-foreground)\"} />;\n })()}\n </div>\n </div>\n )}\n </div>\n\n {/* Navigation Items */}\n <nav className=\"flex flex-col items-center gap-1 flex-1 px-4 pb-5\">\n {items.map((item) => (\n <IconNavItem\n key={item.id}\n item={item}\n variant={variant}\n onClick={() => onItemClick?.(item)}\n />\n ))}\n </nav>\n </aside>\n );\n}\n\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/layout/project-context-shell.tsx",
|
|
8
8
|
"type": "registry:layout",
|
|
9
|
-
"content": "\"use client\";\n\nimport { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { ScrollArea } from \"../ui/scroll-area\";\nimport {\n FileText,\n Users,\n LayoutGrid,\n Wand2,\n} from \"lucide-react\";\nimport { useThemeImages, useThemeBranding } from \"../../context/theme-context\";\nimport {\n Diamond,\n Hexagon,\n Star,\n Lightning,\n Sparkle,\n Infinity,\n Code,\n Terminal,\n Cpu,\n Database,\n Globe,\n Cloud,\n WifiHigh,\n Briefcase,\n Buildings,\n Storefront,\n Handshake,\n ChartLine,\n Palette as PaletteIcon,\n PencilSimple,\n Camera,\n MusicNote,\n Lightbulb,\n Leaf,\n Tree,\n Sun,\n Moon,\n Fire,\n Drop,\n ChatCircle,\n Envelope,\n Phone,\n Megaphone,\n Heart,\n Shield,\n Trophy,\n Rocket,\n Target,\n Flag,\n type Icon as PhosphorIcon,\n} from \"@phosphor-icons/react\";\n\n// ═══════════════════════════════════════════════════════════\n// LOGO ICON SHAPES\n// ═══════════════════════════════════════════════════════════\n\ntype IconShapeId = \"rounded\" | \"circle\" | \"square\";\n\nconst iconShapes: { id: IconShapeId; renderBackground: (bgColor: string) => React.ReactNode }[] = [\n {\n id: \"rounded\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" rx=\"10\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"circle\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <circle cx=\"16\" cy=\"16\" r=\"16\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"square\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n];\n\nconst iconMap: Record<string, PhosphorIcon> = {\n Diamond, Hexagon, Star, Lightning, Sparkle, Infinity, Code, Terminal, Cpu, Database,\n Globe, Cloud, WifiHigh, Briefcase, Buildings, Storefront, Handshake, ChartLine,\n Palette: PaletteIcon, PencilSimple, Camera, MusicNote, Lightbulb, Leaf, Tree,\n Sun, Moon, Fire, Drop, ChatCircle, Envelope, Phone, Megaphone, Heart, Shield,\n Trophy, Rocket, Target, Flag,\n};\n\nfunction resolveBrandingColor(value: string): string {\n if (!value) return \"#ffffff\";\n if (value.startsWith(\"var(\")) {\n const varName = value.replace(\"var(\", \"\").replace(\")\", \"\");\n if (typeof window !== \"undefined\") {\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();\n return computed || \"#ffffff\";\n }\n return \"#ffffff\";\n }\n return value;\n}\n\n// ═══════════════════════════════════════════════════════════\n// TAB TYPES\n// ═══════════════════════════════════════════════════════════\n\nexport type ProjectContextTab = \"scope\" | \"personas\" | \"screens\" | \"prompts\";\n\ninterface TabConfig {\n id: ProjectContextTab;\n label: string;\n icon: typeof FileText;\n description: string;\n}\n\nconst tabs: TabConfig[] = [\n {\n id: \"scope\",\n label: \"Scope\",\n icon: FileText,\n description: \"Upload your project scope document\",\n },\n {\n id: \"personas\",\n label: \"Personas\",\n icon: Users,\n description: \"Define who you're building for\",\n },\n {\n id: \"screens\",\n label: \"Screens\",\n icon: LayoutGrid,\n description: \"Map out your product's screens and flows\",\n },\n {\n id: \"prompts\",\n label: \"Prompt Helpers\",\n icon: Wand2,\n description: \"Build prompts with existing components\",\n },\n];\n\n// ═══════════════════════════════════════════════════════════\n// SHELL COMPONENT\n// ═══════════════════════════════════════════════════════════\n\ninterface ProjectContextShellProps {\n children: ReactNode;\n activeTab: ProjectContextTab;\n onTabChange: (tab: ProjectContextTab) => void;\n}\n\nexport function ProjectContextShell({\n children,\n activeTab,\n onTabChange,\n}: ProjectContextShellProps) {\n const activeTabConfig = tabs.find((t) => t.id === activeTab);\n const themeImages = useThemeImages();\n const { branding, isMounted } = useThemeBranding();\n \n // Get logo (use light variant for this light sidebar)\n const logoUrl = themeImages.logoLight;\n const iconShape = iconShapes.find(s => s.id === branding.iconShape) || iconShapes[0];\n\n return (\n <div className=\"min-h-screen flex bg-[var(--canvas-background)]\">\n {/* Sidebar */}\n <aside className=\"w-64 border-r border-[var(--canvas-border)] bg-[var(--canvas-background)] flex flex-col shrink-0\">\n {/* Logo + Title Header - matches main header height */}\n <div className=\"px-4 border-b border-[var(--canvas-border)] flex items-center h-[97px]\">\n {/* Logo */}\n <div className={`flex items-center ${isMounted ? 'opacity-100' : 'opacity-0'}`}>\n {logoUrl ? (\n <img \n src={logoUrl} \n alt=\"Logo\" \n className=\"h-8 w-auto object-contain\"\n />\n ) : (\n // Uses CSS variables directly - no JavaScript resolution needed\n <div className=\"flex items-center\">\n <div className=\"relative size-8 shrink-0\">\n {iconShape.renderBackground(branding.bgColor || \"var(--canvas-primary)\")}\n <div className=\"absolute inset-0 flex items-center justify-center z-10\">\n {(() => {\n const IconComponent = iconMap[branding.iconName || \"Buildings\"] || Buildings;\n return <IconComponent weight=\"bold\" size={18} color={branding.iconColor || \"var(--canvas-primary-foreground)\"} />;\n })()}\n </div>\n </div>\n <span className=\"font-semibold ml-2.5 text-[var(--canvas-text)]\" style={{ fontSize: \"var(--typo-body-xl-size)\" }}>\n {branding.wordmark || \"canvas\"}\n </span>\n </div>\n )}\n </div>\n </div>\n\n <nav className=\"flex-1 p-2\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const isActive = activeTab === tab.id;\n\n return (\n <button\n key={tab.id}\n onClick={() => onTabChange(tab.id)}\n className={cn(\n \"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-colors mb-1\",\n isActive\n ? \"bg-[var(--canvas-surface-brand)] text-[var(--canvas-primary)]\"\n : \"text-[var(--canvas-text-muted)] hover:bg-[var(--canvas-surface)] hover:text-[var(--canvas-text)]\"\n )}\n >\n <Icon className=\"size-4 shrink-0\" />\n <span className=\"font-medium\" style={{ fontSize: \"var(--typo-body-s-size)\" }}>{tab.label}</span>\n </button>\n );\n })}\n </nav>\n\n {/* Help section */}\n <div className=\"p-4 border-t border-[var(--canvas-border)]\">\n <div className=\"rounded-lg bg-[var(--canvas-surface)] p-3\">\n <p className=\"text-[var(--canvas-text-muted)] leading-relaxed\" style={{ fontSize: \"var(--typo-body-xs-size)\" }}>\n 💡 Use the prompt templates to generate content with Cursor AI\n </p>\n </div>\n </div>\n </aside>\n\n {/* Content Area */}\n <main className=\"flex-1 flex flex-col min-w-0 overflow-hidden\">\n {/* Tab Header */}\n <div className=\"border-b border-[var(--canvas-border)] px-8 py-6 bg-[var(--canvas-background)]\">\n {activeTabConfig && (\n <div>\n <h2 className=\"font-semibold text-[var(--canvas-text)]\" style={{ fontSize: \"var(--typo-body-xl-size)\" }}>\n {activeTabConfig.label}\n </h2>\n <p className=\"text-[var(--canvas-text-muted)]\" style={{ fontSize: \"var(--typo-body-s-size)\" }}>\n {activeTabConfig.description}\n </p>\n </div>\n )}\n </div>\n\n {/* Scrollable Content */}\n <ScrollArea className=\"flex-1\">\n <div className=\"p-8\">{children}</div>\n </ScrollArea>\n </main>\n </div>\n );\n}\n"
|
|
9
|
+
"content": "\"use client\";\n\nimport { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { ScrollArea } from \"../ui/scroll-area\";\nimport {\n FileText,\n Users,\n LayoutGrid,\n Wand2,\n} from \"lucide-react\";\nimport { useThemeImages, useThemeBranding } from \"../../context/theme-context\";\nimport {\n Diamond,\n Hexagon,\n Star,\n Lightning,\n Sparkle,\n Infinity,\n Code,\n Terminal,\n Cpu,\n Database,\n Globe,\n Cloud,\n WifiHigh,\n Briefcase,\n Buildings,\n Storefront,\n Handshake,\n ChartLine,\n Palette as PaletteIcon,\n PencilSimple,\n Camera,\n MusicNote,\n Lightbulb,\n Leaf,\n Tree,\n Sun,\n Moon,\n Fire,\n Drop,\n ChatCircle,\n Envelope,\n Phone,\n Megaphone,\n Heart,\n Shield,\n Trophy,\n Rocket,\n Target,\n Flag,\n type Icon as PhosphorIcon,\n} from \"@phosphor-icons/react\";\n\n// ═══════════════════════════════════════════════════════════\n// LOGO ICON SHAPES\n// ═══════════════════════════════════════════════════════════\n\ntype IconShapeId = \"rounded\" | \"circle\" | \"square\";\n\nconst iconShapes: { id: IconShapeId; renderBackground: (bgColor: string) => React.ReactNode }[] = [\n {\n id: \"rounded\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" rx=\"10\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"circle\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <circle cx=\"16\" cy=\"16\" r=\"16\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n {\n id: \"square\",\n renderBackground: (bgColor: string) => (\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"size-full absolute inset-0\">\n <rect width=\"32\" height=\"32\" style={{ fill: bgColor }} />\n </svg>\n ),\n },\n];\n\nconst iconMap: Record<string, PhosphorIcon> = {\n Diamond, Hexagon, Star, Lightning, Sparkle, Infinity, Code, Terminal, Cpu, Database,\n Globe, Cloud, WifiHigh, Briefcase, Buildings, Storefront, Handshake, ChartLine,\n Palette: PaletteIcon, PencilSimple, Camera, MusicNote, Lightbulb, Leaf, Tree,\n Sun, Moon, Fire, Drop, ChatCircle, Envelope, Phone, Megaphone, Heart, Shield,\n Trophy, Rocket, Target, Flag,\n};\n\nfunction resolveBrandingColor(value: string): string {\n if (!value) return \"#ffffff\";\n if (value.startsWith(\"var(\")) {\n const varName = value.replace(\"var(\", \"\").replace(\")\", \"\");\n if (typeof window !== \"undefined\") {\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();\n return computed || \"#ffffff\";\n }\n return \"#ffffff\";\n }\n return value;\n}\n\n// ═══════════════════════════════════════════════════════════\n// TAB TYPES\n// ═══════════════════════════════════════════════════════════\n\nexport type ProjectContextTab = \"scope\" | \"personas\" | \"screens\" | \"prompts\";\n\ninterface TabConfig {\n id: ProjectContextTab;\n label: string;\n icon: typeof FileText;\n description: string;\n}\n\nconst tabs: TabConfig[] = [\n {\n id: \"scope\",\n label: \"Scope\",\n icon: FileText,\n description: \"Upload your project scope document\",\n },\n {\n id: \"personas\",\n label: \"Personas\",\n icon: Users,\n description: \"Define who you're building for\",\n },\n {\n id: \"screens\",\n label: \"Screens\",\n icon: LayoutGrid,\n description: \"Map out your product's screens and flows\",\n },\n {\n id: \"prompts\",\n label: \"Prompt Helpers\",\n icon: Wand2,\n description: \"Build prompts with existing components\",\n },\n];\n\n// ═══════════════════════════════════════════════════════════\n// SHELL COMPONENT\n// ═══════════════════════════════════════════════════════════\n\ninterface ProjectContextShellProps {\n children: ReactNode;\n activeTab: ProjectContextTab;\n onTabChange: (tab: ProjectContextTab) => void;\n}\n\nexport function ProjectContextShell({\n children,\n activeTab,\n onTabChange,\n}: ProjectContextShellProps) {\n const activeTabConfig = tabs.find((t) => t.id === activeTab);\n const themeImages = useThemeImages();\n const { branding, isMounted } = useThemeBranding();\n \n // Get logo (use light variant for this light sidebar)\n const logoUrl = themeImages.logoLight;\n const iconShape = iconShapes.find(s => s.id === branding.iconShape) || iconShapes[0];\n\n return (\n <div className=\"min-h-screen flex bg-[var(--canvas-background)]\">\n {/* Sidebar */}\n <aside className=\"w-64 border-r border-[var(--canvas-border)] bg-[var(--canvas-background)] flex flex-col shrink-0\">\n {/* Logo + Title Header - matches main header height */}\n <div className=\"px-4 border-b border-[var(--canvas-border)] flex items-center h-[97px]\">\n {/* Logo */}\n <div className={`flex items-center ${isMounted ? 'opacity-100' : 'opacity-0'}`}>\n {logoUrl ? (\n <img \n src={logoUrl} \n alt=\"Logo\" \n className=\"h-8 w-auto object-contain\"\n />\n ) : (\n // Uses CSS variables directly - no JavaScript resolution needed\n <div className=\"flex items-center\">\n <div className=\"relative size-8 shrink-0\">\n {iconShape.renderBackground(branding.bgColor || \"var(--canvas-primary)\")}\n <div className=\"absolute inset-0 flex items-center justify-center z-10\">\n {(() => {\n const IconComponent = iconMap[branding.iconName || \"Buildings\"] || Buildings;\n return <IconComponent weight=\"bold\" size={18} color={branding.iconColor || \"var(--canvas-primary-foreground)\"} />;\n })()}\n </div>\n </div>\n <span className=\"font-semibold ml-2.5 text-[var(--canvas-text)]\" style={{ fontSize: \"var(--typo-body-xl-size)\" }}>\n {branding.wordmark || \"canvas\"}\n </span>\n </div>\n )}\n </div>\n </div>\n\n <nav className=\"flex-1 p-2\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const isActive = activeTab === tab.id;\n\n return (\n <button\n key={tab.id}\n onClick={() => onTabChange(tab.id)}\n className={cn(\n \"cursor-pointer w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-colors mb-1\",\n isActive\n ? \"bg-[var(--canvas-surface-brand)] text-[var(--canvas-primary)]\"\n : \"text-[var(--canvas-text-muted)] hover:bg-[var(--canvas-surface)] hover:text-[var(--canvas-text)]\"\n )}\n >\n <Icon className=\"size-4 shrink-0\" />\n <span className=\"font-medium\" style={{ fontSize: \"var(--typo-body-s-size)\" }}>{tab.label}</span>\n </button>\n );\n })}\n </nav>\n\n {/* Help section */}\n <div className=\"p-4 border-t border-[var(--canvas-border)]\">\n <div className=\"rounded-lg bg-[var(--canvas-surface)] p-3\">\n <p className=\"text-[var(--canvas-text-muted)] leading-relaxed\" style={{ fontSize: \"var(--typo-body-xs-size)\" }}>\n 💡 Use the prompt templates to generate content with Cursor AI\n </p>\n </div>\n </div>\n </aside>\n\n {/* Content Area */}\n <main className=\"flex-1 flex flex-col min-w-0 overflow-hidden\">\n {/* Tab Header */}\n <div className=\"border-b border-[var(--canvas-border)] px-8 py-6 bg-[var(--canvas-background)]\">\n {activeTabConfig && (\n <div>\n <h2 className=\"font-semibold text-[var(--canvas-text)]\" style={{ fontSize: \"var(--typo-body-xl-size)\" }}>\n {activeTabConfig.label}\n </h2>\n <p className=\"text-[var(--canvas-text-muted)]\" style={{ fontSize: \"var(--typo-body-s-size)\" }}>\n {activeTabConfig.description}\n </p>\n </div>\n )}\n </div>\n\n {/* Scrollable Content */}\n <ScrollArea className=\"flex-1\">\n <div className=\"p-8\">{children}</div>\n </ScrollArea>\n </main>\n </div>\n );\n}\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/layout/sidebar-nav.tsx",
|
|
8
8
|
"type": "registry:layout",
|
|
9
|
-
"content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { LucideIcon, ChevronDown } from \"lucide-react\";\n\nexport interface NavItem {\n id: string;\n label: string;\n icon: LucideIcon;\n href?: string;\n isActive?: boolean;\n /** Nested subtabs - when present, the item becomes expandable */\n children?: Omit<NavItem, \"children\" | \"icon\">[];\n}\n\nexport interface NavSection {\n id: string;\n title: string;\n items: NavItem[];\n}\n\ninterface SidebarNavProps {\n sections: NavSection[];\n variant?: \"dark\" | \"light\";\n onItemClick?: (item: NavItem | Omit<NavItem, \"children\" | \"icon\">) => void;\n}\n\n/**\n * Canvas Design System - Sidebar Navigation\n * \n * Renders navigation sections with collapsible groups and nav items.\n * Supports dark (desktop) and light (mobile sheet) variants.\n * Items with children become expandable with nested subtabs.\n */\nexport function SidebarNav({ sections, variant = \"dark\", onItemClick }: SidebarNavProps) {\n const isDark = variant === \"dark\";\n \n // Track which items are expanded (by item id)\n const [expandedItems, setExpandedItems] = useState<Set<string>>(() => {\n // Auto-expand items that have active children\n const initialExpanded = new Set<string>();\n sections.forEach(section => {\n section.items.forEach(item => {\n if (item.children?.some(child => child.isActive)) {\n initialExpanded.add(item.id);\n }\n });\n });\n return initialExpanded;\n });\n\n const toggleExpanded = (itemId: string) => {\n setExpandedItems(prev => {\n const next = new Set(prev);\n if (next.has(itemId)) {\n next.delete(itemId);\n } else {\n next.add(itemId);\n }\n return next;\n });\n };\n \n return (\n <nav className=\"flex flex-col gap-[var(--spacing-xs)] w-full\">\n {sections.map((section) => (\n <div key={section.id} className=\"flex flex-col w-full\">\n {/* Section Title */}\n <div className=\"flex items-center pt-11 pb-[var(--spacing-md)] pl-[var(--spacing-2xl)] pr-0\">\n <span\n className={cn(\n \"uppercase\",\n isDark \n ? \"text-[var(--canvas-sidebar-dark-text)]\" \n : \"text-[var(--canvas-neutral-placeholder)]\"\n )}\n style={{\n fontFamily: \"var(--typo-sidebar-label-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-sidebar-label-size)\",\n fontWeight: \"var(--typo-sidebar-label-weight)\",\n letterSpacing: \"var(--typo-sidebar-label-spacing)\",\n lineHeight: \"var(--typo-sidebar-label-line-height)\",\n }}\n >\n {section.title}\n </span>\n </div>\n \n {/* Nav Items */}\n <div className=\"flex flex-col gap-0\">\n {section.items.map((item) => {\n const Icon = item.icon;\n const isActive = item.isActive;\n const hasChildren = item.children && item.children.length > 0;\n const isExpanded = expandedItems.has(item.id);\n \n return (\n <div key={item.id} className=\"flex flex-col\">\n {/* Parent Nav Item */}\n <button\n onClick={() => {\n if (hasChildren) {\n toggleExpanded(item.id);\n } else {\n onItemClick?.(item);\n }\n }}\n className={cn(\n \"flex items-center gap-[var(--spacing-md)] h-11 px-[var(--spacing-xl)] rounded-[var(--radius-nav)] w-full text-left transition-colors\",\n // Dark variant (desktop sidebar)\n isDark && isActive && !hasChildren && \"bg-[var(--canvas-sidebar-dark-active-bg)] text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)] hover:bg-[var(--canvas-sidebar-dark-active-bg)]/50\",\n isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n // Light variant (mobile sheet)\n !isDark && isActive && !hasChildren && \"bg-[var(--canvas-sidebar-light-active-bg)] text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)] hover:bg-[var(--canvas-sidebar-light-active-bg)]/50\",\n !isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-light-active-text)]\"\n )}\n >\n <Icon \n className={cn(\n \"size-4 shrink-0\",\n isDark && isActive && !hasChildren && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)]\",\n isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n !isDark && isActive && !hasChildren && \"text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)]\",\n !isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-light-active-text)]\"\n )} \n />\n <span \n className=\"flex-1 truncate\"\n style={{\n fontFamily: \"var(--typo-sidebar-tab-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-sidebar-tab-size)\",\n fontWeight: \"var(--typo-sidebar-tab-weight)\",\n letterSpacing: \"var(--typo-sidebar-tab-spacing)\",\n lineHeight: \"var(--typo-sidebar-tab-line-height)\",\n }}\n >\n {item.label}\n </span>\n {hasChildren && (\n <ChevronDown \n className={cn(\n \"size-4 shrink-0 transition-transform duration-200\",\n isExpanded && \"rotate-180\",\n isDark ? \"text-[var(--canvas-sidebar-dark-text)]\" : \"text-[var(--canvas-neutral-text)]\"\n )}\n />\n )}\n </button>\n\n {/* Nested Subtabs */}\n {hasChildren && isExpanded && (\n <div className=\"flex flex-col mt-1 mb-1\">\n {item.children!.map((child) => {\n const isChildActive = child.isActive;\n \n return (\n <button\n key={child.id}\n onClick={() => onItemClick?.(child)}\n className={cn(\n \"flex items-center h-9 pl-12 pr-[var(--spacing-xl)] rounded-[var(--radius-nav)] w-full text-left transition-colors\",\n // Dark variant\n isDark && isChildActive && \"bg-[var(--canvas-sidebar-dark-active-bg)] text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isChildActive && \"text-[var(--canvas-sidebar-dark-text)] hover:bg-[var(--canvas-sidebar-dark-active-bg)]/50\",\n // Light variant\n !isDark && isChildActive && \"bg-[var(--canvas-sidebar-light-active-bg)] text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isChildActive && \"text-[var(--canvas-sidebar-light-text)] hover:bg-[var(--canvas-sidebar-light-active-bg)]/50\"\n )}\n >\n <span \n className=\"truncate\"\n style={{\n fontFamily: \"var(--typo-sidebar-subtab-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-sidebar-subtab-size)\",\n fontWeight: \"var(--typo-sidebar-subtab-weight)\",\n letterSpacing: \"var(--typo-sidebar-subtab-spacing)\",\n lineHeight: \"var(--typo-sidebar-subtab-line-height)\",\n }}\n >\n {child.label}\n </span>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n })}\n </div>\n </div>\n ))}\n </nav>\n );\n}\n"
|
|
9
|
+
"content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { LucideIcon, ChevronDown } from \"lucide-react\";\n\nexport interface NavItem {\n id: string;\n label: string;\n icon: LucideIcon;\n href?: string;\n isActive?: boolean;\n /** Nested subtabs - when present, the item becomes expandable */\n children?: Omit<NavItem, \"children\" | \"icon\">[];\n}\n\nexport interface NavSection {\n id: string;\n title: string;\n items: NavItem[];\n}\n\ninterface SidebarNavProps {\n sections: NavSection[];\n variant?: \"dark\" | \"light\";\n onItemClick?: (item: NavItem | Omit<NavItem, \"children\" | \"icon\">) => void;\n}\n\n/**\n * Canvas Design System - Sidebar Navigation\n * \n * Renders navigation sections with collapsible groups and nav items.\n * Supports dark (desktop) and light (mobile sheet) variants.\n * Items with children become expandable with nested subtabs.\n */\nexport function SidebarNav({ sections, variant = \"dark\", onItemClick }: SidebarNavProps) {\n const isDark = variant === \"dark\";\n \n // Track which items are expanded (by item id)\n const [expandedItems, setExpandedItems] = useState<Set<string>>(() => {\n // Auto-expand items that have active children\n const initialExpanded = new Set<string>();\n sections.forEach(section => {\n section.items.forEach(item => {\n if (item.children?.some(child => child.isActive)) {\n initialExpanded.add(item.id);\n }\n });\n });\n return initialExpanded;\n });\n\n const toggleExpanded = (itemId: string) => {\n setExpandedItems(prev => {\n const next = new Set(prev);\n if (next.has(itemId)) {\n next.delete(itemId);\n } else {\n next.add(itemId);\n }\n return next;\n });\n };\n \n return (\n <nav className=\"flex flex-col gap-[var(--spacing-xs)] w-full\">\n {sections.map((section) => (\n <div key={section.id} className=\"flex flex-col w-full\">\n {/* Section Title */}\n <div className=\"flex items-center pt-11 pb-[var(--spacing-md)] pl-[var(--spacing-2xl)] pr-0\">\n <span\n className={cn(\n \"uppercase\",\n isDark \n ? \"text-[var(--canvas-sidebar-dark-text)]\" \n : \"text-[var(--canvas-neutral-placeholder)]\"\n )}\n style={{\n fontFamily: \"var(--typo-sidebar-label-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-sidebar-label-size)\",\n fontWeight: \"var(--typo-sidebar-label-weight)\",\n letterSpacing: \"var(--typo-sidebar-label-spacing)\",\n lineHeight: \"var(--typo-sidebar-label-line-height)\",\n }}\n >\n {section.title}\n </span>\n </div>\n \n {/* Nav Items */}\n <div className=\"flex flex-col gap-0\">\n {section.items.map((item) => {\n const Icon = item.icon;\n const isActive = item.isActive;\n const hasChildren = item.children && item.children.length > 0;\n const isExpanded = expandedItems.has(item.id);\n \n return (\n <div key={item.id} className=\"flex flex-col\">\n {/* Parent Nav Item */}\n <button\n onClick={() => {\n if (hasChildren) {\n toggleExpanded(item.id);\n } else {\n onItemClick?.(item);\n }\n }}\n className={cn(\n \"cursor-pointer flex items-center gap-[var(--spacing-md)] h-11 px-[var(--spacing-xl)] rounded-[var(--radius-nav)] w-full text-left transition-colors\",\n // Dark variant (desktop sidebar)\n isDark && isActive && !hasChildren && \"bg-[var(--canvas-sidebar-dark-active-bg)] text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)] hover:bg-[var(--canvas-sidebar-dark-active-bg)]/50\",\n isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n // Light variant (mobile sheet)\n !isDark && isActive && !hasChildren && \"bg-[var(--canvas-sidebar-light-active-bg)] text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)] hover:bg-[var(--canvas-sidebar-light-active-bg)]/50\",\n !isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-light-active-text)]\"\n )}\n >\n <Icon \n className={cn(\n \"size-4 shrink-0\",\n isDark && isActive && !hasChildren && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isActive && \"text-[var(--canvas-sidebar-dark-text)]\",\n isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-dark-active-text)]\",\n !isDark && isActive && !hasChildren && \"text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isActive && \"text-[var(--canvas-sidebar-light-text)]\",\n !isDark && hasChildren && isExpanded && \"text-[var(--canvas-sidebar-light-active-text)]\"\n )} \n />\n <span \n className=\"flex-1 truncate\"\n style={{\n fontFamily: \"var(--typo-sidebar-tab-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-sidebar-tab-size)\",\n fontWeight: \"var(--typo-sidebar-tab-weight)\",\n letterSpacing: \"var(--typo-sidebar-tab-spacing)\",\n lineHeight: \"var(--typo-sidebar-tab-line-height)\",\n }}\n >\n {item.label}\n </span>\n {hasChildren && (\n <ChevronDown \n className={cn(\n \"size-4 shrink-0 transition-transform duration-200\",\n isExpanded && \"rotate-180\",\n isDark ? \"text-[var(--canvas-sidebar-dark-text)]\" : \"text-[var(--canvas-neutral-text)]\"\n )}\n />\n )}\n </button>\n\n {/* Nested Subtabs */}\n {hasChildren && isExpanded && (\n <div className=\"flex flex-col mt-1 mb-1\">\n {item.children!.map((child) => {\n const isChildActive = child.isActive;\n \n return (\n <button\n key={child.id}\n onClick={() => onItemClick?.(child)}\n className={cn(\n \"cursor-pointer flex items-center h-9 pl-12 pr-[var(--spacing-xl)] rounded-[var(--radius-nav)] w-full text-left transition-colors\",\n // Dark variant\n isDark && isChildActive && \"bg-[var(--canvas-sidebar-dark-active-bg)] text-[var(--canvas-sidebar-dark-active-text)]\",\n isDark && !isChildActive && \"text-[var(--canvas-sidebar-dark-text)] hover:bg-[var(--canvas-sidebar-dark-active-bg)]/50\",\n // Light variant\n !isDark && isChildActive && \"bg-[var(--canvas-sidebar-light-active-bg)] text-[var(--canvas-sidebar-light-active-text)]\",\n !isDark && !isChildActive && \"text-[var(--canvas-sidebar-light-text)] hover:bg-[var(--canvas-sidebar-light-active-bg)]/50\"\n )}\n >\n <span \n className=\"truncate\"\n style={{\n fontFamily: \"var(--typo-sidebar-subtab-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-sidebar-subtab-size)\",\n fontWeight: \"var(--typo-sidebar-subtab-weight)\",\n letterSpacing: \"var(--typo-sidebar-subtab-spacing)\",\n lineHeight: \"var(--typo-sidebar-subtab-line-height)\",\n }}\n >\n {child.label}\n </span>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n })}\n </div>\n </div>\n ))}\n </nav>\n );\n}\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
package/registry/ui/button.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/button.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\n\n// Base button styles (layout and structure only, colors applied via CSS variables)\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n {\n variants: {\n variant: {\n // Custom Canvas variants (styled via CSS variables in component)\n primary: \"\",\n \"primary-outline\": \"border\",\n \"primary-neutral\": \"\",\n neutral: \"border\",\n \"neutral-delete\": \"border\",\n delete: \"\",\n // Legacy shadcn variants (for backwards compatibility)\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-white hover:bg-destructive/90\",\n outline: \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n // Custom Canvas sizes (styled via CSS variables in component)\n mini: \"\",\n sm: \"\",\n default: \"\",\n lg: \"\",\n // Legacy shadcn sizes\n icon: \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\n// CSS variable mappings for Canvas design system variants\nconst variantStyles: Record<string, React.CSSProperties> = {\n primary: {\n backgroundColor: \"var(--btn-primary-bg)\",\n color: \"var(--btn-primary-text)\",\n borderColor: \"var(--btn-primary-border)\",\n },\n \"primary-outline\": {\n backgroundColor: \"var(--btn-primary-outline-bg)\",\n color: \"var(--btn-primary-outline-text)\",\n borderColor: \"var(--btn-primary-outline-border)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n },\n \"primary-neutral\": {\n backgroundColor: \"var(--btn-primary-neutral-bg)\",\n color: \"var(--btn-primary-neutral-text)\",\n borderColor: \"var(--btn-primary-neutral-border)\",\n },\n neutral: {\n backgroundColor: \"var(--btn-neutral-bg)\",\n color: \"var(--btn-neutral-text)\",\n borderColor: \"var(--btn-neutral-border)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n },\n \"neutral-delete\": {\n backgroundColor: \"var(--btn-neutral-delete-bg)\",\n color: \"var(--btn-neutral-delete-text)\",\n borderColor: \"var(--btn-neutral-delete-border)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n },\n delete: {\n backgroundColor: \"var(--btn-delete-bg)\",\n color: \"var(--btn-delete-text)\",\n borderColor: \"var(--btn-delete-border)\",\n },\n}\n\n// CSS variable mappings for Canvas design system sizes\nconst sizeStyles: Record<string, React.CSSProperties> = {\n mini: {\n height: \"var(--btn-mini-height)\",\n paddingLeft: \"var(--btn-mini-px)\",\n paddingRight: \"var(--btn-mini-px)\",\n fontSize: \"var(--btn-mini-font-size)\",\n borderRadius: \"var(--btn-mini-radius)\",\n fontWeight: \"var(--btn-mini-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-mini-letter-spacing)\",\n fontFamily: \"var(--btn-mini-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n sm: {\n height: \"var(--btn-small-height)\",\n paddingLeft: \"var(--btn-small-px)\",\n paddingRight: \"var(--btn-small-px)\",\n fontSize: \"var(--btn-small-font-size)\",\n borderRadius: \"var(--btn-small-radius)\",\n fontWeight: \"var(--btn-small-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-small-letter-spacing)\",\n fontFamily: \"var(--btn-small-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n default: {\n height: \"var(--btn-standard-height)\",\n paddingLeft: \"var(--btn-standard-px)\",\n paddingRight: \"var(--btn-standard-px)\",\n fontSize: \"var(--btn-standard-font-size)\",\n borderRadius: \"var(--btn-standard-radius)\",\n fontWeight: \"var(--btn-standard-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-standard-letter-spacing)\",\n fontFamily: \"var(--btn-standard-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n lg: {\n height: \"var(--btn-large-height)\",\n paddingLeft: \"var(--btn-large-px)\",\n paddingRight: \"var(--btn-large-px)\",\n fontSize: \"var(--btn-large-font-size)\",\n borderRadius: \"var(--btn-large-radius)\",\n fontWeight: \"var(--btn-large-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-large-letter-spacing)\",\n fontFamily: \"var(--btn-large-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n}\n\n// Custom Canvas variants that use CSS variables\nconst canvasVariants = [\"primary\", \"primary-outline\", \"primary-neutral\", \"neutral\", \"neutral-delete\", \"delete\"]\nconst canvasSizes = [\"mini\", \"sm\", \"default\", \"lg\"]\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n style,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot : \"button\"\n\n // Build style object with CSS variables for Canvas variants/sizes\n const computedStyle: React.CSSProperties = { ...style }\n \n if (variant && canvasVariants.includes(variant)) {\n Object.assign(computedStyle, variantStyles[variant])\n }\n \n if (size && canvasSizes.includes(size)) {\n Object.assign(computedStyle, sizeStyles[size])\n }\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n style={Object.keys(computedStyle).length > 0 ? computedStyle : undefined}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n"
|
|
9
|
+
"content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\n\n// Base button styles (layout and structure only, colors applied via CSS variables)\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-all cursor-pointer disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n {\n variants: {\n variant: {\n // Custom Canvas variants (styled via CSS variables in component)\n primary: \"\",\n \"primary-outline\": \"border\",\n \"primary-neutral\": \"\",\n neutral: \"border\",\n \"neutral-delete\": \"border\",\n delete: \"\",\n // Legacy shadcn variants (for backwards compatibility)\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-white hover:bg-destructive/90\",\n outline: \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n // Custom Canvas sizes (styled via CSS variables in component)\n mini: \"\",\n sm: \"\",\n default: \"\",\n lg: \"\",\n // Legacy shadcn sizes\n icon: \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\n// CSS variable mappings for Canvas design system variants\nconst variantStyles: Record<string, React.CSSProperties> = {\n primary: {\n backgroundColor: \"var(--btn-primary-bg)\",\n color: \"var(--btn-primary-text)\",\n borderColor: \"var(--btn-primary-border)\",\n },\n \"primary-outline\": {\n backgroundColor: \"var(--btn-primary-outline-bg)\",\n color: \"var(--btn-primary-outline-text)\",\n borderColor: \"var(--btn-primary-outline-border)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n },\n \"primary-neutral\": {\n backgroundColor: \"var(--btn-primary-neutral-bg)\",\n color: \"var(--btn-primary-neutral-text)\",\n borderColor: \"var(--btn-primary-neutral-border)\",\n },\n neutral: {\n backgroundColor: \"var(--btn-neutral-bg)\",\n color: \"var(--btn-neutral-text)\",\n borderColor: \"var(--btn-neutral-border)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n },\n \"neutral-delete\": {\n backgroundColor: \"var(--btn-neutral-delete-bg)\",\n color: \"var(--btn-neutral-delete-text)\",\n borderColor: \"var(--btn-neutral-delete-border)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n },\n delete: {\n backgroundColor: \"var(--btn-delete-bg)\",\n color: \"var(--btn-delete-text)\",\n borderColor: \"var(--btn-delete-border)\",\n },\n}\n\n// CSS variable mappings for Canvas design system sizes\nconst sizeStyles: Record<string, React.CSSProperties> = {\n mini: {\n height: \"var(--btn-mini-height)\",\n paddingLeft: \"var(--btn-mini-px)\",\n paddingRight: \"var(--btn-mini-px)\",\n fontSize: \"var(--btn-mini-font-size)\",\n borderRadius: \"var(--btn-mini-radius)\",\n fontWeight: \"var(--btn-mini-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-mini-letter-spacing)\",\n fontFamily: \"var(--btn-mini-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n sm: {\n height: \"var(--btn-small-height)\",\n paddingLeft: \"var(--btn-small-px)\",\n paddingRight: \"var(--btn-small-px)\",\n fontSize: \"var(--btn-small-font-size)\",\n borderRadius: \"var(--btn-small-radius)\",\n fontWeight: \"var(--btn-small-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-small-letter-spacing)\",\n fontFamily: \"var(--btn-small-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n default: {\n height: \"var(--btn-standard-height)\",\n paddingLeft: \"var(--btn-standard-px)\",\n paddingRight: \"var(--btn-standard-px)\",\n fontSize: \"var(--btn-standard-font-size)\",\n borderRadius: \"var(--btn-standard-radius)\",\n fontWeight: \"var(--btn-standard-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-standard-letter-spacing)\",\n fontFamily: \"var(--btn-standard-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n lg: {\n height: \"var(--btn-large-height)\",\n paddingLeft: \"var(--btn-large-px)\",\n paddingRight: \"var(--btn-large-px)\",\n fontSize: \"var(--btn-large-font-size)\",\n borderRadius: \"var(--btn-large-radius)\",\n fontWeight: \"var(--btn-large-font-weight)\" as React.CSSProperties[\"fontWeight\"],\n letterSpacing: \"var(--btn-large-letter-spacing)\",\n fontFamily: \"var(--btn-large-font-family, var(--typo-button-font, var(--typo-global-font)))\",\n },\n}\n\n// Custom Canvas variants that use CSS variables\nconst canvasVariants = [\"primary\", \"primary-outline\", \"primary-neutral\", \"neutral\", \"neutral-delete\", \"delete\"]\nconst canvasSizes = [\"mini\", \"sm\", \"default\", \"lg\"]\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n style,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot : \"button\"\n\n // Build style object with CSS variables for Canvas variants/sizes\n const computedStyle: React.CSSProperties = { ...style }\n \n if (variant && canvasVariants.includes(variant)) {\n Object.assign(computedStyle, variantStyles[variant])\n }\n \n if (size && canvasSizes.includes(size)) {\n Object.assign(computedStyle, sizeStyles[size])\n }\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n style={Object.keys(computedStyle).length > 0 ? computedStyle : undefined}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
package/registry/ui/dialog.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/dialog.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\"\nimport { XIcon } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Dialog({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />\n}\n\nfunction DialogTrigger({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\nfunction DialogPortal({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\nfunction DialogClose({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean\n}) {\n return (\n <DialogPortal data-slot=\"dialog-portal\">\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\"\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"text-lg leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n}\n"
|
|
9
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\"\nimport { XIcon } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Dialog({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />\n}\n\nfunction DialogTrigger({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\nfunction DialogPortal({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\nfunction DialogClose({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean\n}) {\n return (\n <DialogPortal data-slot=\"dialog-portal\">\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-[var(--canvas-border)] p-6 shadow-lg duration-200 outline-none sm:max-w-lg\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\"\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"text-lg leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n}\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/dropdown-menu.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\"\nimport { CheckIcon, ChevronRightIcon, CircleIcon } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction DropdownMenu({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuPortal({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return (\n <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n )\n}\n\nfunction DropdownMenuTrigger({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return (\n <DropdownMenuPrimitive.Trigger\n data-slot=\"dropdown-menu-trigger\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return (\n <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n )\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground focus:[&_svg:not([class*='text-'])]:text-accent-foreground relative flex cursor-default items-center gap-1.5 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n )\n}\n\nfunction DropdownMenuRadioGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return (\n <DropdownMenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CircleIcon className=\"size-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n \"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n \"text-muted-foreground ml-auto text-xs tracking-widest\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSub({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto size-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n )\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n"
|
|
9
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\"\nimport { CheckIcon, ChevronRightIcon, CircleIcon } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction DropdownMenu({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuPortal({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return (\n <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n )\n}\n\nfunction DropdownMenuTrigger({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return (\n <DropdownMenuPrimitive.Trigger\n data-slot=\"dropdown-menu-trigger\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-[var(--canvas-border)] p-1 shadow-md\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return (\n <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n )\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground focus:[&_svg:not([class*='text-'])]:text-accent-foreground relative flex cursor-default items-center gap-1.5 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n )\n}\n\nfunction DropdownMenuRadioGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return (\n <DropdownMenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CircleIcon className=\"size-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n \"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n \"text-muted-foreground ml-auto text-xs tracking-widest\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSub({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto size-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n )\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border border-[var(--canvas-border)] p-1 shadow-lg\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/line-tabs.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport interface LineTab {\n id: string;\n label: string;\n}\n\ninterface LineTabsProps {\n /** Array of tab items */\n tabs: LineTab[];\n /** ID of the currently active tab */\n activeTab?: string;\n /** Callback when a tab is clicked */\n onTabChange?: (tabId: string) => void;\n /** Additional class names */\n className?: string;\n}\n\n/**\n * Canvas Design System - Line Tabs Component\n * \n * Horizontal underline-style tabs for page navigation.\n * Active tab has blue text with 2px blue bottom border.\n * Inactive tabs have gray text with 1px gray bottom border.\n * \n * @example\n * ```tsx\n * <LineTabs \n * tabs={[\n * { id: \"tab1\", label: \"Tab 1\" },\n * { id: \"tab2\", label: \"Tab 2\" },\n * ]} \n * activeTab=\"tab1\"\n * onTabChange={(id) => console.log(id)}\n * />\n * ```\n */\nexport function LineTabs({\n tabs,\n activeTab: controlledActiveTab,\n onTabChange,\n className,\n}: LineTabsProps) {\n // Use internal state if not controlled\n const [internalActiveTab, setInternalActiveTab] = useState(tabs[0]?.id || \"\");\n const activeTab = controlledActiveTab ?? internalActiveTab;\n\n const handleTabClick = (tabId: string) => {\n if (!controlledActiveTab) {\n setInternalActiveTab(tabId);\n }\n onTabChange?.(tabId);\n };\n\n return (\n <div className={cn(\"flex items-end w-full\", className)}>\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab;\n const isLast = index === tabs.length - 1;\n\n return (\n <div key={tab.id} className=\"flex items-end h-12\">\n {/* Tab Button */}\n <button\n onClick={() => handleTabClick(tab.id)}\n className={cn(\n \"flex items-center justify-center h-full px-0 transition-colors\",\n isActive\n ? \"border-b-2 border-[var(--canvas-primary)] text-[var(--canvas-primary)]\"\n : \"border-b border-[var(--canvas-border)] text-[var(--canvas-text-muted)] hover:text-[var(--canvas-text)]\"\n )}\n >\n <span className=\"text-base font-medium leading-6\">\n {tab.label}\n </span>\n </button>\n\n {/* Divider - 24px wide line */}\n {!isLast && (\n <div className=\"w-6 h-0 border-b border-[var(--canvas-border)]\" />\n )}\n </div>\n );\n })}\n\n {/* Trailing line to fill remaining space */}\n <div className=\"flex-1 h-0 border-b border-[var(--canvas-border)]\" />\n </div>\n );\n}\n\n"
|
|
9
|
+
"content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport interface LineTab {\n id: string;\n label: string;\n}\n\ninterface LineTabsProps {\n /** Array of tab items */\n tabs: LineTab[];\n /** ID of the currently active tab */\n activeTab?: string;\n /** Callback when a tab is clicked */\n onTabChange?: (tabId: string) => void;\n /** Additional class names */\n className?: string;\n}\n\n/**\n * Canvas Design System - Line Tabs Component\n * \n * Horizontal underline-style tabs for page navigation.\n * Active tab has blue text with 2px blue bottom border.\n * Inactive tabs have gray text with 1px gray bottom border.\n * \n * @example\n * ```tsx\n * <LineTabs \n * tabs={[\n * { id: \"tab1\", label: \"Tab 1\" },\n * { id: \"tab2\", label: \"Tab 2\" },\n * ]} \n * activeTab=\"tab1\"\n * onTabChange={(id) => console.log(id)}\n * />\n * ```\n */\nexport function LineTabs({\n tabs,\n activeTab: controlledActiveTab,\n onTabChange,\n className,\n}: LineTabsProps) {\n // Use internal state if not controlled\n const [internalActiveTab, setInternalActiveTab] = useState(tabs[0]?.id || \"\");\n const activeTab = controlledActiveTab ?? internalActiveTab;\n\n const handleTabClick = (tabId: string) => {\n if (!controlledActiveTab) {\n setInternalActiveTab(tabId);\n }\n onTabChange?.(tabId);\n };\n\n return (\n <div className={cn(\"flex items-end w-full\", className)}>\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab;\n const isLast = index === tabs.length - 1;\n\n return (\n <div key={tab.id} className=\"flex items-end h-12\">\n {/* Tab Button */}\n <button\n onClick={() => handleTabClick(tab.id)}\n className={cn(\n \"flex items-center justify-center h-full px-0 transition-colors cursor-pointer\",\n isActive\n ? \"border-b-2 border-[var(--canvas-primary)] text-[var(--canvas-primary)]\"\n : \"border-b border-[var(--canvas-border)] text-[var(--canvas-text-muted)] hover:text-[var(--canvas-text)]\"\n )}\n >\n <span className=\"text-base font-medium leading-6\">\n {tab.label}\n </span>\n </button>\n\n {/* Divider - 24px wide line */}\n {!isLast && (\n <div className=\"w-6 h-0 border-b border-[var(--canvas-border)]\" />\n )}\n </div>\n );\n })}\n\n {/* Trailing line to fill remaining space */}\n <div className=\"flex-1 h-0 border-b border-[var(--canvas-border)]\" />\n </div>\n );\n}\n\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [],
|
package/registry/ui/popover.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/popover.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Popover({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n )\n}\n\nfunction PopoverAnchor({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />\n}\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }\n"
|
|
9
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Popover({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border border-[var(--canvas-border)] p-4 shadow-md outline-hidden\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n )\n}\n\nfunction PopoverAnchor({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />\n}\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
package/registry/ui/select.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/select.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SelectPrimitive from \"@radix-ui/react-select\"\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"lucide-react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\n\nconst selectTriggerVariants = cva(\n // Base styles using CSS variables\n \"flex w-full items-center justify-between gap-2 bg-[var(--canvas-background)] border border-[var(--canvas-border-input)] text-[var(--canvas-text)] whitespace-nowrap transition-colors outline-none focus:border-[var(--canvas-border-input-focus)] focus:ring-2 focus:ring-[var(--canvas-border-input-focus)] focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-[var(--canvas-input-disabled-bg)] disabled:border-[var(--canvas-input-disabled-border)] disabled:text-[var(--canvas-input-disabled-text)] aria-invalid:border-[var(--canvas-border-input-invalid)] data-[placeholder]:text-[var(--canvas-text-placeholder)] [&_svg:not([class*='text-'])]:text-[var(--canvas-text-muted)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 font-[family-name:var(--typo-global-font)]\",\n {\n variants: {\n inputSize: {\n sm: \"h-[var(--input-small-height)] px-[var(--input-small-px)] text-[length:var(--input-small-font-size)] rounded-[var(--input-small-radius)]\",\n default: \"h-[var(--input-standard-height)] px-[var(--input-standard-px)] text-[length:var(--input-standard-font-size)] rounded-[var(--input-standard-radius)]\",\n lg: \"h-[var(--input-large-height)] px-[var(--input-large-px)] text-[length:var(--input-large-font-size)] rounded-[var(--input-large-radius)]\",\n },\n },\n defaultVariants: {\n inputSize: \"default\",\n },\n }\n)\n\nfunction Select({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Root>) {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />\n}\n\nfunction SelectGroup({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Group>) {\n return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />\n}\n\nfunction SelectValue({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Value>) {\n return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />\n}\n\nfunction SelectTrigger({\n className,\n inputSize,\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> &\n VariantProps<typeof selectTriggerVariants>) {\n return (\n <SelectPrimitive.Trigger\n data-slot=\"select-trigger\"\n data-size={inputSize}\n className={cn(selectTriggerVariants({ inputSize, className }))}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon className=\"size-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n}\n\nfunction SelectContent({\n className,\n children,\n position = \"popper\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n data-slot=\"select-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n sideOffset={sideOffset}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n )\n}\n\nfunction SelectLabel({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n data-slot=\"select-label\"\n className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n return (\n <SelectPrimitive.Item\n data-slot=\"select-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 font-[family-name:var(--typo-global-font)]\",\n className\n )}\n {...props}\n >\n <span\n data-slot=\"select-item-indicator\"\n className=\"absolute right-2 flex size-3.5 items-center justify-center\"\n >\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\nfunction SelectSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator\n data-slot=\"select-separator\"\n className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectScrollUpButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n return (\n <SelectPrimitive.ScrollUpButton\n data-slot=\"select-scroll-up-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronUpIcon className=\"size-4\" />\n </SelectPrimitive.ScrollUpButton>\n )\n}\n\nfunction SelectScrollDownButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n return (\n <SelectPrimitive.ScrollDownButton\n data-slot=\"select-scroll-down-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronDownIcon className=\"size-4\" />\n </SelectPrimitive.ScrollDownButton>\n )\n}\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n selectTriggerVariants,\n}\n"
|
|
9
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SelectPrimitive from \"@radix-ui/react-select\"\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"lucide-react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\n\nconst selectTriggerVariants = cva(\n // Base styles using CSS variables\n \"flex w-full items-center justify-between gap-2 bg-[var(--canvas-background)] border border-[var(--canvas-border-input)] text-[var(--canvas-text)] whitespace-nowrap transition-colors outline-none focus:border-[var(--canvas-border-input-focus)] focus:ring-2 focus:ring-[var(--canvas-border-input-focus)] focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-[var(--canvas-input-disabled-bg)] disabled:border-[var(--canvas-input-disabled-border)] disabled:text-[var(--canvas-input-disabled-text)] aria-invalid:border-[var(--canvas-border-input-invalid)] data-[placeholder]:text-[var(--canvas-text-placeholder)] [&_svg:not([class*='text-'])]:text-[var(--canvas-text-muted)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 font-[family-name:var(--typo-global-font)]\",\n {\n variants: {\n inputSize: {\n sm: \"h-[var(--input-small-height)] px-[var(--input-small-px)] text-[length:var(--input-small-font-size)] rounded-[var(--input-small-radius)]\",\n default: \"h-[var(--input-standard-height)] px-[var(--input-standard-px)] text-[length:var(--input-standard-font-size)] rounded-[var(--input-standard-radius)]\",\n lg: \"h-[var(--input-large-height)] px-[var(--input-large-px)] text-[length:var(--input-large-font-size)] rounded-[var(--input-large-radius)]\",\n },\n },\n defaultVariants: {\n inputSize: \"default\",\n },\n }\n)\n\nfunction Select({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Root>) {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />\n}\n\nfunction SelectGroup({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Group>) {\n return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />\n}\n\nfunction SelectValue({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Value>) {\n return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />\n}\n\nfunction SelectTrigger({\n className,\n inputSize,\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> &\n VariantProps<typeof selectTriggerVariants>) {\n return (\n <SelectPrimitive.Trigger\n data-slot=\"select-trigger\"\n data-size={inputSize}\n className={cn(selectTriggerVariants({ inputSize, className }))}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon className=\"size-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n}\n\nfunction SelectContent({\n className,\n children,\n position = \"popper\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n data-slot=\"select-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-[var(--canvas-border)] shadow-md\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n sideOffset={sideOffset}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n )\n}\n\nfunction SelectLabel({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n data-slot=\"select-label\"\n className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n return (\n <SelectPrimitive.Item\n data-slot=\"select-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 font-[family-name:var(--typo-global-font)]\",\n className\n )}\n {...props}\n >\n <span\n data-slot=\"select-item-indicator\"\n className=\"absolute right-2 flex size-3.5 items-center justify-center\"\n >\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\nfunction SelectSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator\n data-slot=\"select-separator\"\n className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectScrollUpButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n return (\n <SelectPrimitive.ScrollUpButton\n data-slot=\"select-scroll-up-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronUpIcon className=\"size-4\" />\n </SelectPrimitive.ScrollUpButton>\n )\n}\n\nfunction SelectScrollDownButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n return (\n <SelectPrimitive.ScrollDownButton\n data-slot=\"select-scroll-down-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronDownIcon className=\"size-4\" />\n </SelectPrimitive.ScrollDownButton>\n )\n}\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n selectTriggerVariants,\n}\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/selectable-pills.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport interface PillOption {\n id: string;\n label: string;\n}\n\nexport interface SelectablePillsProps {\n inputSize?: \"sm\" | \"default\" | \"lg\";\n options: PillOption[];\n selected: string[];\n onSelectionChange: (selected: string[]) => void;\n allowMultiple?: boolean;\n className?: string;\n disabled?: boolean;\n}\n\nconst SelectablePills = React.forwardRef<HTMLDivElement, SelectablePillsProps>(\n ({ \n inputSize = \"default\", \n options, \n selected, \n onSelectionChange,\n allowMultiple = true,\n className,\n disabled,\n }, ref) => {\n // Size mappings - using fixed values that scale appropriately\n const sizeStyles = {\n sm: {\n pill: \"h-7 px-2.5 text-xs gap-1\",\n container: \"gap-2\",\n },\n default: {\n pill: \"h-9 px-3.5 text-sm gap-1.5\",\n container: \"gap-3\",\n },\n lg: {\n pill: \"h-11 px-4 text-base gap-2\",\n container: \"gap-4\",\n },\n };\n\n const styles = sizeStyles[inputSize];\n\n const handlePillClick = (optionId: string) => {\n if (disabled) return;\n\n if (allowMultiple) {\n // Toggle selection\n if (selected.includes(optionId)) {\n onSelectionChange(selected.filter(id => id !== optionId));\n } else {\n onSelectionChange([...selected, optionId]);\n }\n } else {\n // Single selection - toggle or replace\n if (selected.includes(optionId)) {\n onSelectionChange([]);\n } else {\n onSelectionChange([optionId]);\n }\n }\n };\n\n return (\n <div \n ref={ref}\n className={cn(\n \"flex flex-wrap\",\n styles.container,\n className\n )}\n >\n {options.map((option) => {\n const isSelected = selected.includes(option.id);\n \n return (\n <button\n key={option.id}\n type=\"button\"\n onClick={() => handlePillClick(option.id)}\n disabled={disabled}\n className={cn(\n \"inline-flex items-center justify-center rounded-[var(--radius-xs)] border transition-colors\",\n \"font-medium whitespace-nowrap\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--canvas-border-input-focus)] focus-visible:ring-offset-2\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n styles.pill,\n isSelected\n ? \"bg-[var(--canvas-surface-brand)] border-[var(--canvas-primary)] text-[var(--canvas-primary)]\"\n : \"bg-[var(--canvas-background)] border-[var(--canvas-border)] text-[var(--canvas-text-muted)] hover:border-[var(--canvas-text-muted)]\"\n )}\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n }\n);\n\nSelectablePills.displayName = \"SelectablePills\";\n\nexport { SelectablePills };\n\n"
|
|
9
|
+
"content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport interface PillOption {\n id: string;\n label: string;\n}\n\nexport interface SelectablePillsProps {\n inputSize?: \"sm\" | \"default\" | \"lg\";\n options: PillOption[];\n selected: string[];\n onSelectionChange: (selected: string[]) => void;\n allowMultiple?: boolean;\n className?: string;\n disabled?: boolean;\n}\n\nconst SelectablePills = React.forwardRef<HTMLDivElement, SelectablePillsProps>(\n ({ \n inputSize = \"default\", \n options, \n selected, \n onSelectionChange,\n allowMultiple = true,\n className,\n disabled,\n }, ref) => {\n // Size mappings - using fixed values that scale appropriately\n const sizeStyles = {\n sm: {\n pill: \"h-7 px-2.5 text-xs gap-1\",\n container: \"gap-2\",\n },\n default: {\n pill: \"h-9 px-3.5 text-sm gap-1.5\",\n container: \"gap-3\",\n },\n lg: {\n pill: \"h-11 px-4 text-base gap-2\",\n container: \"gap-4\",\n },\n };\n\n const styles = sizeStyles[inputSize];\n\n const handlePillClick = (optionId: string) => {\n if (disabled) return;\n\n if (allowMultiple) {\n // Toggle selection\n if (selected.includes(optionId)) {\n onSelectionChange(selected.filter(id => id !== optionId));\n } else {\n onSelectionChange([...selected, optionId]);\n }\n } else {\n // Single selection - toggle or replace\n if (selected.includes(optionId)) {\n onSelectionChange([]);\n } else {\n onSelectionChange([optionId]);\n }\n }\n };\n\n return (\n <div \n ref={ref}\n className={cn(\n \"flex flex-wrap\",\n styles.container,\n className\n )}\n >\n {options.map((option) => {\n const isSelected = selected.includes(option.id);\n \n return (\n <button\n key={option.id}\n type=\"button\"\n onClick={() => handlePillClick(option.id)}\n disabled={disabled}\n className={cn(\n \"inline-flex items-center justify-center rounded-[var(--radius-xs)] border transition-colors cursor-pointer\",\n \"font-medium whitespace-nowrap\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--canvas-border-input-focus)] focus-visible:ring-offset-2\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n styles.pill,\n isSelected\n ? \"bg-[var(--canvas-surface-brand)] border-[var(--canvas-primary)] text-[var(--canvas-primary)]\"\n : \"bg-[var(--canvas-background)] border-[var(--canvas-border)] text-[var(--canvas-text-muted)] hover:border-[var(--canvas-text-muted)]\"\n )}\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n }\n);\n\nSelectablePills.displayName = \"SelectablePills\";\n\nexport { SelectablePills };\n\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [],
|
package/registry/ui/sheet.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/sheet.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\"\nimport { XIcon } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Close>) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {\n return (\n <SheetPrimitive.Overlay\n data-slot=\"sheet-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SheetContent({\n className,\n children,\n side = \"right\",\n overlayClassName,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\n side?: \"top\" | \"right\" | \"bottom\" | \"left\"\n overlayClassName?: string\n}) {\n return (\n <SheetPortal>\n <SheetOverlay className={overlayClassName} />\n <SheetPrimitive.Content\n data-slot=\"sheet-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n side === \"right\" &&\n \"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm\",\n side === \"left\" &&\n \"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm\",\n side === \"top\" &&\n \"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b\",\n side === \"bottom\" &&\n \"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t\",\n className\n )}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none\">\n <XIcon className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n </SheetPortal>\n )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-header\"\n className={cn(\"flex flex-col gap-1.5 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetTitle({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Title>) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn(\"text-foreground font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetDescription({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n}\n"
|
|
9
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\"\nimport { XIcon } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Close>) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {\n return (\n <SheetPrimitive.Overlay\n data-slot=\"sheet-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SheetContent({\n className,\n children,\n side = \"right\",\n overlayClassName,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\n side?: \"top\" | \"right\" | \"bottom\" | \"left\"\n overlayClassName?: string\n}) {\n return (\n <SheetPortal>\n <SheetOverlay className={overlayClassName} />\n <SheetPrimitive.Content\n data-slot=\"sheet-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n side === \"right\" &&\n \"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l border-[var(--canvas-border)] sm:max-w-sm\",\n side === \"left\" &&\n \"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r border-[var(--canvas-border)] sm:max-w-sm\",\n side === \"top\" &&\n \"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b border-[var(--canvas-border)]\",\n side === \"bottom\" &&\n \"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t border-[var(--canvas-border)]\",\n className\n )}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none\">\n <XIcon className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n </SheetPortal>\n )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-header\"\n className={cn(\"flex flex-col gap-1.5 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetTitle({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Title>) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn(\"text-foreground font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetDescription({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n}\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|
package/registry/ui/tabs.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"path": "components/ui/tabs.tsx",
|
|
8
8
|
"type": "registry:ui",
|
|
9
|
-
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Tabs({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n return (\n <TabsPrimitive.Root\n data-slot=\"tabs\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction TabsList({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.List>) {\n return (\n <TabsPrimitive.List\n data-slot=\"tabs-list\"\n className={cn(\n \"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction TabsTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n return (\n <TabsPrimitive.Trigger\n data-slot=\"tabs-trigger\"\n className={cn(\n \"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction TabsContent({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n return (\n <TabsPrimitive.Content\n data-slot=\"tabs-content\"\n className={cn(\"flex-1 outline-none\", className)}\n {...props}\n />\n )\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent }\n"
|
|
9
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Tabs({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n return (\n <TabsPrimitive.Root\n data-slot=\"tabs\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction TabsList({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.List>) {\n return (\n <TabsPrimitive.List\n data-slot=\"tabs-list\"\n className={cn(\n \"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction TabsTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n return (\n <TabsPrimitive.Trigger\n data-slot=\"tabs-trigger\"\n className={cn(\n \"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] cursor-pointer focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction TabsContent({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n return (\n <TabsPrimitive.Content\n data-slot=\"tabs-content\"\n className={cn(\"flex-1 outline-none\", className)}\n {...props}\n />\n )\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent }\n"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"dependencies": [
|