{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "button", "title": "Button", "description": "Embossed button with classic raised look, multiple variants and sizes", "dependencies": [ "@base-ui/react", "class-variance-authority", "web-haptics" ], "registryDependencies": [ "utils", "use-haptics" ], "files": [ { "path": "registry/new-york/ui/button.tsx", "content": "\"use client\"\n\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { useHaptics } from \"@/hooks/use-haptics\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"btn-classic btn-classic-primary bg-primary text-primary-foreground\",\n outline:\n \"btn-classic btn-classic-outline bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30 dark:hover:bg-input/50\",\n secondary:\n \"btn-classic btn-classic-secondary bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"btn-classic btn-classic-destructive bg-destructive text-white focus-visible:border-destructive/40 focus-visible:ring-destructive/20\",\n link: \"text-primary underline-offset-4 hover:underline hover:decoration-dotted hover:decoration-muted-foreground/50\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3\",\n icon: \"size-8\",\n \"icon-xs\":\n \"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\":\n \"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n haptic = true,\n onClick,\n ...props\n}: ButtonPrimitive.Props &\n VariantProps & {\n haptic?: boolean\n }) {\n const { trigger } = useHaptics()\n\n return (\n {\n if (haptic) trigger(\"nudge\")\n onClick?.(e)\n }}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n", "type": "registry:ui" } ], "cssVars": { "light": { "--ease-out-cubic": "cubic-bezier(0.215, 0.61, 0.355, 1)", "--ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)", "--ease-in-out-cubic": "cubic-bezier(0.645, 0.045, 0.355, 1)" } }, "css": { "@layer components": "/* btn-classic: Embossed/raised button treatment via layered shadows + ::after gradient */\n.btn-classic {\n position: relative;\n z-index: 0;\n background-clip: border-box !important;\n background-image:\n linear-gradient(to bottom, transparent 50%, oklch(0 0 0 / 0.04)),\n linear-gradient(to bottom, transparent 50%, var(--btn-classic-bg, transparent) 80%);\n box-shadow:\n inset 0 1px 0 0 oklch(1 0 0 / 0.12),\n inset 0 0 0 1px var(--btn-classic-bg, transparent),\n 0 1px 2px 0 oklch(0 0 0 / 0.06),\n 0 1px 3px 0 oklch(0 0 0 / 0.04);\n}\n.btn-classic::after {\n content: '';\n position: absolute;\n border-radius: inherit;\n pointer-events: none;\n inset: 0;\n z-index: 1;\n border: 1px solid transparent;\n background-clip: content-box;\n background-image: linear-gradient(oklch(0 0 0 / 0.02), transparent 40%, oklch(1 0 0 / 0.06));\n box-shadow: inset 0 2px 3px -1px oklch(1 0 0 / 0.12);\n transition: background-color 150ms ease, background-image 150ms ease, box-shadow 150ms ease;\n}\n.btn-classic > * {\n position: relative;\n z-index: 2;\n}\n@media (hover: hover) and (pointer: fine) {\n .btn-classic:hover:not(:disabled, [data-disabled])::after {\n background-image: linear-gradient(oklch(0 0 0 / 0.04) -15%, transparent 40%, oklch(1 0 0 / 0.08));\n }\n .btn-classic-primary:hover:not(:disabled, [data-disabled])::after,\n .btn-classic-destructive:hover:not(:disabled, [data-disabled])::after {\n background-color: oklch(1 0 0 / 0.1);\n background-image: linear-gradient(oklch(1 0 0 / 0.14), oklch(1 0 0 / 0.05) 40%, transparent 60%, oklch(0 0 0 / 0.03));\n box-shadow: inset 0 1px 2px 0 oklch(1 0 0 / 0.25), inset 0 -1px 2px 0 oklch(0 0 0 / 0.1);\n }\n}\n.btn-classic:active:not(:disabled, [data-disabled]) {\n background-image: linear-gradient(oklch(0 0 0 / 0.03), transparent);\n box-shadow:\n inset 0 4px 2px -2px oklch(0 0 0 / 0.06),\n inset 0 1px 1px oklch(0 0 0 / 0.08),\n inset 0 0 0 1px oklch(0 0 0 / 0.05),\n inset 0 0 0 1px var(--btn-classic-bg, transparent),\n inset 0 3px 2px oklch(0 0 0 / 0.04);\n padding-top: 1px;\n}\n.btn-classic:active:not(:disabled, [data-disabled])::after {\n box-shadow: none;\n background-image: linear-gradient(oklch(0 0 0 / 0.04), transparent 40%, oklch(1 0 0 / 0.06));\n}\n.btn-classic:where(:disabled, [data-disabled]) {\n background-image: none;\n box-shadow: none;\n}\n.btn-classic:where(:disabled, [data-disabled])::after {\n box-shadow: none;\n background-image: linear-gradient(oklch(0 0 0 / 0.02) -20%, transparent, oklch(1 0 0 / 0.02));\n}\n.btn-classic-primary {\n --btn-classic-bg: var(--primary);\n background-image: linear-gradient(to bottom, transparent 50%, oklch(0 0 0 / 0.15)), linear-gradient(to bottom, transparent 50%, var(--primary) 80%);\n box-shadow: inset 0 1px 0 0 oklch(1 0 0 / 0.25), inset 0 0 0 1px var(--primary), inset 0 -1px 0 0 oklch(0 0 0 / 0.2), 0 1px 3px 0 oklch(0 0 0 / 0.12), 0 2px 6px 0 oklch(0 0 0 / 0.08);\n}\n.btn-classic-primary::after {\n background-image: linear-gradient(oklch(1 0 0 / 0.1), oklch(1 0 0 / 0.03) 40%, transparent 60%, oklch(0 0 0 / 0.05));\n box-shadow: inset 0 1px 2px 0 oklch(1 0 0 / 0.2), inset 0 -1px 2px 0 oklch(0 0 0 / 0.15);\n}\n.btn-classic-outline {\n --btn-classic-bg: var(--background);\n background-image: linear-gradient(to bottom, transparent 50%, oklch(0 0 0 / 0.02));\n box-shadow: inset 0 1px 0 0 oklch(1 0 0 / 0.6), 0 1px 2px 0 oklch(0 0 0 / 0.05), 0 0 0 1px var(--border);\n}\n.btn-classic-outline::after {\n box-shadow: inset 0 2px 3px -1px oklch(1 0 0 / 0.3);\n}\n.btn-classic-secondary {\n --btn-classic-bg: var(--secondary);\n background-image: linear-gradient(to bottom, transparent 50%, oklch(0 0 0 / 0.02));\n box-shadow: inset 0 1px 0 0 oklch(1 0 0 / 0.5), 0 1px 2px 0 oklch(0 0 0 / 0.04), 0 0 0 1px oklch(0 0 0 / 0.06);\n}\n.btn-classic-secondary::after {\n box-shadow: inset 0 2px 3px -1px oklch(1 0 0 / 0.25);\n}\n.btn-classic-destructive {\n --btn-classic-bg: var(--destructive);\n background-image: linear-gradient(to bottom, transparent 50%, oklch(0 0 0 / 0.15)), linear-gradient(to bottom, transparent 50%, var(--destructive) 80%);\n box-shadow: inset 0 1px 0 0 oklch(1 0 0 / 0.25), inset 0 0 0 1px var(--destructive), inset 0 -1px 0 0 oklch(0 0 0 / 0.2), 0 1px 3px 0 oklch(0 0 0 / 0.12), 0 2px 6px 0 oklch(0 0 0 / 0.08);\n}\n.btn-classic-destructive::after {\n background-image: linear-gradient(oklch(1 0 0 / 0.1), oklch(1 0 0 / 0.03) 40%, transparent 60%, oklch(0 0 0 / 0.05));\n box-shadow: inset 0 1px 2px 0 oklch(1 0 0 / 0.2), inset 0 -1px 2px 0 oklch(0 0 0 / 0.15);\n}" }, "type": "registry:ui" }