{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "selection-bar", "title": "Selection Bar", "description": "Floating bulk-action toolbar that appears when items are selected in a list or table.", "dependencies": [ "class-variance-authority", "lucide-react" ], "registryDependencies": [ "button" ], "files": [ { "path": "packages/ui/src/selection-bar.tsx", "content": "\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X as XIcon } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Button, type ButtonProps } from \"./button\";\nimport { cn } from \"./utils\";\n\nconst EXIT_DURATION_MS = 220;\n\ninterface SelectionBarProps extends React.HTMLAttributes {\n /** Whether the bar is visible. Drives the enter/exit animation. */\n open: boolean;\n /** Where the bar is positioned. `fixed` (default) anchors to the viewport bottom; `inline` lets the consumer place it. */\n position?: \"fixed\" | \"inline\";\n}\n\nfunction SelectionBar({\n open,\n position = \"fixed\",\n className,\n children,\n style,\n ...props\n}: SelectionBarProps) {\n const [shouldRender, setShouldRender] = React.useState(open);\n const [isVisible, setIsVisible] = React.useState(open);\n const exitTimeoutRef = React.useRef(null);\n\n React.useEffect(() => {\n if (exitTimeoutRef.current !== null) {\n window.clearTimeout(exitTimeoutRef.current);\n exitTimeoutRef.current = null;\n }\n\n if (open) {\n const frameId = window.requestAnimationFrame(() => {\n setShouldRender(true);\n setIsVisible(true);\n });\n return () => window.cancelAnimationFrame(frameId);\n }\n\n setIsVisible(false);\n exitTimeoutRef.current = window.setTimeout(() => {\n setShouldRender(false);\n exitTimeoutRef.current = null;\n }, EXIT_DURATION_MS);\n\n return () => {\n if (exitTimeoutRef.current !== null) {\n window.clearTimeout(exitTimeoutRef.current);\n exitTimeoutRef.current = null;\n }\n };\n }, [open]);\n\n if (!shouldRender) {\n return null;\n }\n\n const inner = (\n
\n {children}\n
\n );\n\n if (position === \"inline\") {\n return (\n \n {inner}\n \n );\n }\n\n return (\n \n {inner}\n \n );\n}\n\nconst barInnerClass =\n \"pointer-events-auto flex w-fit max-w-full transform-gpu items-center gap-1 overflow-x-auto rounded-2xl border border-zinc-800/90 bg-zinc-950 px-1.5 py-1.5 text-zinc-100 shadow-xl ring-1 ring-black/20 will-change-[transform,opacity] dark:border-zinc-300/80 dark:bg-zinc-100 dark:text-zinc-900 dark:ring-white/25 transition-[opacity,transform] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none\";\nconst barVisible = \"translate-y-0 opacity-100\";\nconst barHidden = \"translate-y-3 opacity-0\";\n\nfunction SelectionBarGroup({\n className,\n ...props\n}: React.HTMLAttributes) {\n return (\n \n );\n}\n\nfunction SelectionBarLabel({\n className,\n ...props\n}: React.HTMLAttributes) {\n return (\n \n );\n}\n\nfunction SelectionBarBullet({\n className,\n children,\n ...props\n}: React.HTMLAttributes) {\n return (\n \n {children ?? \"•\"}\n \n );\n}\n\nconst linkClass =\n \"h-7 rounded-md px-2 text-xs font-medium text-inherit underline-offset-4 hover:bg-white/10 hover:text-inherit hover:underline dark:hover:bg-black/8 dark:hover:text-inherit\";\n\nfunction SelectionBarLink({ className, ...props }: ButtonProps) {\n return (\n \n );\n}\n\nfunction SelectionBarSeparator({\n className,\n ...props\n}: React.HTMLAttributes) {\n return (\n \n );\n}\n\nconst selectionBarButtonVariants = cva(\n \"shrink-0 text-inherit hover:text-inherit dark:hover:text-inherit\",\n {\n variants: {\n tone: {\n default:\n \"hover:bg-white/10 aria-expanded:bg-white/10 dark:aria-expanded:bg-black/8 dark:hover:bg-black/8\",\n success:\n \"text-emerald-300 hover:bg-emerald-500/10 hover:text-emerald-200 dark:text-emerald-700 dark:hover:bg-emerald-500/10 dark:hover:text-emerald-800\",\n destructive:\n \"text-rose-400 hover:bg-rose-500/10 hover:text-rose-300 dark:text-rose-600 dark:hover:bg-rose-500/10 dark:hover:text-rose-700\",\n },\n shape: {\n text: \"h-8 rounded-lg px-2.5 text-[13px]\",\n icon: \"size-8 rounded-lg\",\n },\n },\n defaultVariants: {\n tone: \"default\",\n shape: \"text\",\n },\n }\n);\n\ntype SelectionBarButtonShape = \"text\" | \"icon\";\ntype SelectionBarButtonTone = \"default\" | \"success\" | \"destructive\";\n\ninterface SelectionBarButtonProps\n extends Omit,\n VariantProps {\n shape?: SelectionBarButtonShape;\n tone?: SelectionBarButtonTone;\n}\n\nconst SelectionBarButton = ({\n className,\n shape = \"text\",\n tone = \"default\",\n ref,\n ...props\n}: SelectionBarButtonProps & React.RefAttributes) => (\n \n);\n\nSelectionBarButton.displayName = \"SelectionBarButton\";\n\ninterface SelectionBarCloseProps\n extends Omit {\n \"aria-label\"?: string;\n}\n\nfunction SelectionBarClose({\n \"aria-label\": ariaLabel = \"Clear selection\",\n ...props\n}: SelectionBarCloseProps) {\n return (\n \n \n \n );\n}\n\nexport type {\n SelectionBarButtonProps,\n SelectionBarCloseProps,\n SelectionBarProps,\n};\nexport {\n SelectionBar,\n SelectionBarBullet,\n SelectionBarButton,\n SelectionBarClose,\n SelectionBarGroup,\n SelectionBarLabel,\n SelectionBarLink,\n SelectionBarSeparator,\n selectionBarButtonVariants,\n};\n", "type": "registry:ui" } ], "type": "registry:ui" }