PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.15
Yatra – Travel Booking & Tour Operator Software v3.0.15
3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 All 83 releases
yatra / resources / js / components / ui / button.tsx

button.tsx in Yatra – Travel Booking & Tour Operator Software 3.0.15, at resources/js/components/ui/button.tsx

78 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import * as React from "react";
2
3 interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4 variant?: "default" | "outline" | "ghost" | "destructive";
5 size?: "default" | "sm" | "lg" | "icon";
6 /**
7 * Radix-style slot pattern — when true, Button renders no <button> element
8 * of its own and instead spreads its className + props onto its single
9 * child (typically an <a>). Lets pages compose `<Button asChild><a href="...">`
10 * for upgrade / external links while keeping the Button look and a11y.
11 *
12 * Implementation note: we don't pull in @radix-ui/react-slot. The Pro
13 * pages that use this pattern always pass a single React element child;
14 * cloning it with the merged className + the rest of the props is what
15 * Slot does internally. Keeping this dependency-free saves ~8 KB gzipped
16 * and avoids a third React tree-traversal pass on every render.
17 */
18 asChild?: boolean;
19 }
20
21 const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
22 (
23 {
24 className = "",
25 variant = "default",
26 size = "default",
27 asChild = false,
28 children,
29 ...props
30 },
31 ref,
32 ) => {
33 const baseClasses =
34 "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50";
35
36 const variantClasses = {
37 default:
38 "bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600",
39 outline:
40 "border border-gray-300 bg-transparent hover:bg-gray-100 dark:border-gray-600 dark:hover:bg-gray-800",
41 ghost: "hover:bg-gray-100 dark:hover:bg-gray-800",
42 destructive:
43 "bg-red-600 text-white hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600",
44 };
45
46 const sizeClasses = {
47 default: "h-10 px-4 py-2",
48 sm: "h-9 rounded-md px-3",
49 lg: "h-11 rounded-md px-8",
50 icon: "h-10 w-10",
51 };
52
53 const mergedClassName = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${className}`;
54
55 if (asChild && React.isValidElement(children)) {
56 // Clone the single child element and merge our styling + props onto
57 // it. The child keeps its semantics (href, onClick, etc.) and gains
58 // the Button look. Ref forwarding is best-effort — pages that need a
59 // ref on the child should use a real ref directly on the <a>.
60 const child = children as React.ReactElement<{ className?: string }>;
61 const childClassName = (child.props as { className?: string }).className;
62 return React.cloneElement(child, {
63 ...(props as object),
64 className: `${mergedClassName}${childClassName ? ` ${childClassName}` : ""}`,
65 } as React.HTMLAttributes<HTMLElement>);
66 }
67
68 return (
69 <button className={mergedClassName} ref={ref} {...props}>
70 {children}
71 </button>
72 );
73 },
74 );
75 Button.displayName = "Button";
76
77 export { Button };
78