@music-vine/cadence 3.1.1 → 3.1.3
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/components/button.js +3 -3
- package/dist/components/button.js.map +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +4 -2
- package/dist/components/input.js.map +2 -2
- package/package.json +1 -1
|
@@ -33,12 +33,12 @@ const buttonVariants = cva(
|
|
|
33
33
|
variants: {
|
|
34
34
|
variant: {
|
|
35
35
|
// BRANDING VARIANTS (use CSS variables for themeability)
|
|
36
|
-
subtle: "border-1 border-gray-150 border-solid bg-white text-gray-950 hover:bg-gray-50 active:border-brand-primary-hover active:bg-brand-secondary active:text-brand-primary-hover disabled:bg-gray-50 active:disabled:border-gray-150 active:disabled:bg-gray-50 active:disabled:text-gray-950 dark:border-gray-800 dark:bg-gray-950 dark:text-white dark:disabled:border-gray-900 dark:disabled:bg-gray-950 dark:disabled:text-white dark:active:border-white dark:active:text-white dark:disabled:active:border-gray-900 dark:disabled:active:bg-gray-950 dark:disabled:active:text-white dark:hover:bg-gray-
|
|
36
|
+
subtle: "border-1 border-gray-150 border-solid bg-white text-gray-950 hover:bg-gray-50 active:border-brand-primary-hover active:bg-brand-secondary active:text-brand-primary-hover disabled:bg-gray-50 active:disabled:border-gray-150 active:disabled:bg-gray-50 active:disabled:text-gray-950 dark:border-gray-800 dark:bg-gray-950 dark:text-white dark:disabled:border-gray-900 dark:disabled:bg-gray-950 dark:disabled:text-white dark:active:border-white dark:active:text-white dark:disabled:active:border-gray-900 dark:disabled:active:bg-gray-950 dark:disabled:active:text-white dark:hover:bg-gray-800",
|
|
37
37
|
brand: "border-1 border-brand-primary border-solid bg-brand-primary font-semibold text-white hover:border-brand-primary-hover hover:bg-brand-primary-hover disabled:hover:bg-brand-primary-hover",
|
|
38
|
-
brandSecondary: "border-1 border-brand-secondary border-solid bg-brand-secondary font-semibold text-brand-primary-hover hover:border-brand-secondary-hover hover:bg-brand-secondary-hover disabled:hover:bg-brand-secondary-hover dark:border-gray-900 dark:bg-gray-900 hover:dark:border-gray-800 hover:dark:bg-gray-800 dark:text-white dark:disabled:hover:border-gray-900 dark:disabled:hover:bg-gray-
|
|
38
|
+
brandSecondary: "border-1 border-brand-secondary border-solid bg-brand-secondary font-semibold text-brand-primary-hover hover:border-brand-secondary-hover hover:bg-brand-secondary-hover disabled:hover:bg-brand-secondary-hover dark:border-gray-900 dark:bg-gray-900 hover:dark:border-gray-800 hover:dark:bg-gray-800 dark:text-white dark:disabled:hover:border-gray-900 dark:disabled:hover:bg-gray-800",
|
|
39
39
|
bold: "border-gray-950 bg-gray-950 font-semibold text-white dark:border-white dark:bg-white dark:text-gray-950",
|
|
40
40
|
light: "border-gray-150 bg-gray-100 font-semibold text-gray-950 hover:border-gray-200 hover:bg-gray-200 disabled:hover:border-gray-150 disabled:hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-white dark:hover:bg-gray-700 dark:disabled:hover:bg-gray-800",
|
|
41
|
-
transparent: "border-transparent! bg-transparent font-semibold text-gray-950 hover:border-gray-50 hover:bg-gray-50 disabled:hover:border-transparent disabled:hover:bg-transparent dark:text-white dark:hover:border-gray-900 dark:hover:bg-gray-
|
|
41
|
+
transparent: "border-transparent! bg-transparent font-semibold text-gray-950 hover:border-gray-50 hover:bg-gray-50 disabled:hover:border-transparent disabled:hover:bg-transparent dark:text-white dark:hover:border-gray-900 dark:hover:bg-gray-800",
|
|
42
42
|
contrast: "border-white bg-white font-semibold text-gray-950 hover:bg-gray-50 hover:disabled:border-white hover:disabled:bg-white",
|
|
43
43
|
success: "border-green-600 bg-green-600 font-semibold text-white hover:border-green-700 hover:bg-green-700 disabled:hover:border-green-600 disabled:hover:bg-green-600 dark:border-green-500 dark:bg-green-500 dark:hover:border-green-650 dark:hover:bg-green-650 dark:disabled:hover:border-green-500 dark:disabled:hover:bg-green-500",
|
|
44
44
|
error: "border-red-600 bg-red-600 font-semibold text-white hover:bg-red-700 disabled:hover:border-red-700 disabled:hover:bg-red-700 dark:border-red-500 dark:bg-red-500 dark:hover:border-red-600 dark:hover:bg-red-600 dark:disabled:hover:border-red-600 dark:disabled:hover:bg-red-600"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/button.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * @module Button\n *\n * Versatile button component with multiple variants, sizes, and responsive options.\n * Supports all standard button interactions plus loading states and icon-only modes.\n *\n * @see {@link https://ui.shadcn.com/docs/components/button Shadcn Button}\n *\n * @example\n * // Basic buttons\n * <Button>Default</Button>\n * <Button variant=\"brand\">Primary Action</Button>\n * <Button variant=\"subtle\">Secondary</Button>\n *\n * @example\n * // Sizes\n * <Button size=\"xs\">Extra Small</Button>\n * <Button size=\"sm\">Small</Button>\n * <Button size=\"lg\">Large</Button>\n * <Button size=\"xl\">Extra Large</Button>\n *\n * @example\n * // Responsive size (changes at breakpoints)\n * <Button size={{ default: \"sm\", md: \"default\", lg: \"lg\" }}>\n * Responsive Button\n * </Button>\n *\n * @example\n * // Icon button\n * <Button icon size=\"default\"><PlayIcon /></Button>\n *\n * @example\n * // As link (using asChild)\n * <Button asChild variant=\"brand\">\n * <a href=\"/signup\">Sign Up</a>\n * </Button>\n *\n * @example\n * // With loading state\n * <Button disabled>\n * <Loading visible={isLoading} />\n * {isLoading ? \"Loading...\" : \"Submit\"}\n * </Button>\n */\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { LoaderCircle } from \"lucide-react\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type { ButtonHTMLAttributes, Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Size classes for consistent button dimensions */\n// Define size classes once as a single source of truth (including leading but not font sizes)\nconst sizeClasses = {\n default: \"h-8 px-4 py-2 leading-8\",\n xs: \"h-5 gap-1.5 px-2 leading-5\",\n sm: \"h-7 px-3 py-2 leading-6\",\n lg: \"h-10 px-4 py-2 leading-8\",\n xl: \"h-12 px-8 py-3 leading-10\",\n icon: \"h-8 w-8 leading-8\",\n} as const;\n\nconst fontSizeClasses = {\n xxs: \"text-xxs\",\n xs: \"text-xs\",\n sm: \"text-sm\",\n base: \"text-base\",\n lg: \"text-lg\",\n xl: \"text-xl\",\n} as const;\n\n// Type definitions for responsive sizes\ntype ButtonSize = \"default\" | \"xs\" | \"sm\" | \"lg\" | \"icon\" | \"xl\";\n\ntype ButtonFontSize = \"xxs\" | \"xs\" | \"sm\" | \"base\" | \"lg\" | \"xl\" | null;\n\n// Default font size mapping based on button size (excludes null)\nconst defaultFontSizeForSize: Record<\n ButtonSize,\n Exclude<ButtonFontSize, null>\n> = {\n xs: \"xs\",\n sm: \"xs\",\n default: \"base\",\n lg: \"base\",\n icon: \"base\",\n xl: \"lg\",\n};\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap font-normal font-sans text-base transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--focus-ring-offset)] enabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-50\",\n {\n variants: {\n variant: {\n // BRANDING VARIANTS (use CSS variables for themeability)\n subtle:\n \"border-1 border-gray-150 border-solid bg-white text-gray-950 hover:bg-gray-50 active:border-brand-primary-hover active:bg-brand-secondary active:text-brand-primary-hover disabled:bg-gray-50 active:disabled:border-gray-150 active:disabled:bg-gray-50 active:disabled:text-gray-950 dark:border-gray-800 dark:bg-gray-950 dark:text-white dark:disabled:border-gray-900 dark:disabled:bg-gray-950 dark:disabled:text-white dark:active:border-white dark:active:text-white dark:disabled:active:border-gray-900 dark:disabled:active:bg-gray-950 dark:disabled:active:text-white dark:hover:bg-gray-900\",\n brand:\n \"border-1 border-brand-primary border-solid bg-brand-primary font-semibold text-white hover:border-brand-primary-hover hover:bg-brand-primary-hover disabled:hover:bg-brand-primary-hover\",\n brandSecondary:\n \"border-1 border-brand-secondary border-solid bg-brand-secondary font-semibold text-brand-primary-hover hover:border-brand-secondary-hover hover:bg-brand-secondary-hover disabled:hover:bg-brand-secondary-hover dark:border-gray-900 dark:bg-gray-900 hover:dark:border-gray-800 hover:dark:bg-gray-800 dark:text-white dark:disabled:hover:border-gray-900 dark:disabled:hover:bg-gray-900\",\n bold: \"border-gray-950 bg-gray-950 font-semibold text-white dark:border-white dark:bg-white dark:text-gray-950\",\n light:\n \"border-gray-150 bg-gray-100 font-semibold text-gray-950 hover:border-gray-200 hover:bg-gray-200 disabled:hover:border-gray-150 disabled:hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-white dark:hover:bg-gray-700 dark:disabled:hover:bg-gray-800\",\n transparent:\n \"border-transparent! bg-transparent font-semibold text-gray-950 hover:border-gray-50 hover:bg-gray-50 disabled:hover:border-transparent disabled:hover:bg-transparent dark:text-white dark:hover:border-gray-900 dark:hover:bg-gray-900\",\n contrast:\n \"border-white bg-white font-semibold text-gray-950 hover:bg-gray-50 hover:disabled:border-white hover:disabled:bg-white\",\n success:\n \"border-green-600 bg-green-600 font-semibold text-white hover:border-green-700 hover:bg-green-700 disabled:hover:border-green-600 disabled:hover:bg-green-600 dark:border-green-500 dark:bg-green-500 dark:hover:border-green-650 dark:hover:bg-green-650 dark:disabled:hover:border-green-500 dark:disabled:hover:bg-green-500\",\n error:\n \"border-red-600 bg-red-600 font-semibold text-white hover:bg-red-700 disabled:hover:border-red-700 disabled:hover:bg-red-700 dark:border-red-500 dark:bg-red-500 dark:hover:border-red-600 dark:hover:bg-red-600 dark:disabled:hover:border-red-600 dark:disabled:hover:bg-red-600\",\n },\n\n size: sizeClasses,\n fontSize: {\n ...fontSizeClasses,\n null: \"\", // No font size class, relies on compound variants\n },\n borderRadius: {\n default: \"rounded-lg\",\n sm: \"rounded\",\n full: \"rounded-full\",\n rounded: \"rounded-[100px]\",\n },\n border: {\n true: \"border border-solid\",\n false: \"border-none\",\n },\n noFeedback: {\n true: \"\",\n false: \"transition-transform active:scale-[0.97] disabled:scale-100\",\n },\n },\n compoundVariants: [\n // Size + BorderRadius compounds\n {\n size: \"sm\",\n borderRadius: \"default\",\n className: \"rounded-lg\",\n },\n {\n size: \"xs\",\n borderRadius: \"default\",\n className: \"rounded-md\",\n },\n\n // Variant + Border compounds\n {\n variant: \"transparent\",\n border: true,\n className: \"border-gray-200 dark:border-gray-800\",\n },\n {\n variant: \"success\",\n border: true,\n className: \"border-green-dark\",\n },\n {\n variant: \"contrast\",\n border: true,\n className: \"border-white\",\n },\n // Size + fontSize compounds (default font size for each size when no explicit fontSize)\n { size: \"xs\", fontSize: null, className: \"text-xs\" },\n { size: \"sm\", fontSize: null, className: \"text-xs\" },\n { size: \"default\", fontSize: null, className: \"text-base\" },\n { size: \"lg\", fontSize: null, className: \"text-base\" },\n { size: \"icon\", fontSize: null, className: \"text-base\" },\n { size: \"xl\", fontSize: null, className: \"text-lg\" },\n ],\n defaultVariants: {\n variant: \"bold\",\n size: \"default\",\n fontSize: null,\n borderRadius: \"default\",\n border: false,\n noFeedback: false,\n },\n }\n);\n\ntype ResponsiveButtonSize =\n | ButtonSize\n | {\n default: ButtonSize;\n xxs?: ButtonSize;\n xs?: ButtonSize;\n sm?: ButtonSize;\n md?: ButtonSize;\n lg?: ButtonSize;\n xl?: ButtonSize;\n \"2xl\"?: ButtonSize;\n };\n\ntype ResponsiveButtonFontSize =\n | Exclude<ButtonFontSize, null>\n | {\n default?: Exclude<ButtonFontSize, null>;\n xxs?: Exclude<ButtonFontSize, null>;\n xs?: Exclude<ButtonFontSize, null>;\n sm?: Exclude<ButtonFontSize, null>;\n md?: Exclude<ButtonFontSize, null>;\n lg?: Exclude<ButtonFontSize, null>;\n xl?: Exclude<ButtonFontSize, null>;\n \"2xl\"?: Exclude<ButtonFontSize, null>;\n };\n\nconst getSizeClasses = (sizeKey: ButtonSize): string =>\n sizeClasses[sizeKey] || \"\";\n\nconst getFontSizeClasses = (\n fontSizeKey: Exclude<ButtonFontSize, null>\n): string => fontSizeClasses[fontSizeKey] || \"\";\n\n// Function to generate responsive Tailwind classes\nfunction generateResponsiveSizeClasses(size?: ResponsiveButtonSize): string {\n if (!size || typeof size === \"string\") {\n return \"\";\n }\n\n const classes: string[] = [];\n\n // Add responsive classes for each breakpoint\n const breakpoints = [\n { prefix: \"xxs\", value: size.xxs },\n { prefix: \"xs\", value: size.xs },\n { prefix: \"sm\", value: size.sm },\n { prefix: \"md\", value: size.md },\n { prefix: \"lg\", value: size.lg },\n { prefix: \"xl\", value: size.xl },\n { prefix: \"2xl\", value: size[\"2xl\"] },\n ];\n\n for (const breakpoint of breakpoints) {\n if (breakpoint.value) {\n const breakpointSizeClasses = getSizeClasses(breakpoint.value);\n const responsiveClasses = breakpointSizeClasses\n .split(\" \")\n .filter((cls) => cls.trim() !== \"\")\n .map((cls) => `${breakpoint.prefix}:${cls}`)\n .join(\" \");\n if (responsiveClasses) {\n classes.push(responsiveClasses);\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nfunction generateResponsiveFontSizeClasses(\n fontSize?: ResponsiveButtonFontSize\n): string {\n if (!fontSize || typeof fontSize === \"string\") {\n return \"\";\n }\n\n const classes: string[] = [];\n\n // Add responsive classes for each breakpoint\n const breakpoints = [\n { prefix: \"xxs\", value: fontSize.xxs },\n { prefix: \"xs\", value: fontSize.xs },\n { prefix: \"sm\", value: fontSize.sm },\n { prefix: \"md\", value: fontSize.md },\n { prefix: \"lg\", value: fontSize.lg },\n { prefix: \"xl\", value: fontSize.xl },\n { prefix: \"2xl\", value: fontSize[\"2xl\"] },\n ];\n\n for (const breakpoint of breakpoints) {\n if (breakpoint.value) {\n const breakpointFontSizeClasses = getFontSizeClasses(breakpoint.value);\n const responsiveClasses = breakpointFontSizeClasses\n .split(\" \")\n .filter((cls) => cls.trim() !== \"\")\n .map((cls) => `${breakpoint.prefix}:${cls}`)\n .join(\" \");\n if (responsiveClasses) {\n classes.push(responsiveClasses);\n }\n }\n }\n\n return classes.join(\" \");\n}\n\n/**\n * Props for the Button component.\n *\n * @property variant - Color/style: `brand`, `brandSecondary`, `subtle`, `bold`, `light`, `transparent`, `contrast`, `success`, `error`\n * @property size - Size or responsive size object: `xs`, `sm`, `default`, `lg`, `xl`, `icon`\n * @property fontSize - Override font size or responsive font size object\n * @property borderRadius - Corner style: `default`, `sm`, `full`, `rounded`\n * @property border - Show border when true\n * @property noFeedback - Disable scale animation on click\n * @property asChild - Render as child element (e.g., for links)\n * @property icon - Square aspect ratio with no padding (for icon-only buttons)\n */\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n Omit<VariantProps<typeof buttonVariants>, \"size\" | \"fontSize\"> {\n asChild?: boolean;\n fontSize?: ResponsiveButtonFontSize;\n icon?: boolean;\n ref?: Ref<HTMLButtonElement>;\n size?: ResponsiveButtonSize;\n}\n\nconst Button = ({\n className,\n variant,\n size,\n borderRadius,\n border,\n noFeedback,\n asChild = false,\n type,\n children,\n fontSize,\n icon = false,\n ref,\n ...props\n}: ButtonProps) => {\n const Comp = asChild ? SlotPrimitive.Slot : \"button\";\n const buttonType = asChild ? undefined : (type ?? \"button\");\n\n // Generate responsive classes or use the cva size variant\n const responsiveClasses =\n typeof size === \"object\" ? generateResponsiveSizeClasses(size) : undefined;\n\n // Generate responsive font size classes\n let responsiveFontSizeClasses: string | undefined;\n if (typeof fontSize === \"object\") {\n // User provided explicit responsive font sizes\n responsiveFontSizeClasses = generateResponsiveFontSizeClasses(fontSize);\n } else if (typeof size === \"object\" && fontSize === undefined) {\n // Auto-generate responsive font sizes based on responsive sizes\n const autoFontSize: ResponsiveButtonFontSize = {\n default: defaultFontSizeForSize[size.default] || \"base\",\n };\n\n // Map over the size object to create the auto font size object\n const breakpointMappings = [\n { sizeKey: \"xxs\" as const, fontKey: \"xxs\" as const },\n { sizeKey: \"xs\" as const, fontKey: \"xs\" as const },\n { sizeKey: \"sm\" as const, fontKey: \"sm\" as const },\n { sizeKey: \"md\" as const, fontKey: \"md\" as const },\n { sizeKey: \"lg\" as const, fontKey: \"lg\" as const },\n { sizeKey: \"xl\" as const, fontKey: \"xl\" as const },\n { sizeKey: \"2xl\" as const, fontKey: \"2xl\" as const },\n ];\n\n for (const { sizeKey, fontKey } of breakpointMappings) {\n const sizeValue = (size as Record<string, ButtonSize>)[sizeKey];\n if (sizeValue && sizeValue in defaultFontSizeForSize) {\n (autoFontSize as Record<string, Exclude<ButtonFontSize, null>>)[\n fontKey\n ] = defaultFontSizeForSize[sizeValue as ButtonSize];\n }\n }\n\n responsiveFontSizeClasses = generateResponsiveFontSizeClasses(autoFontSize);\n }\n\n // For object sizes, use the default size in the cva\n const cvaSize = typeof size === \"object\" ? size.default : size;\n\n // Determine font size for cva\n let cvaFontSize: ButtonFontSize = null;\n if (fontSize) {\n if (typeof fontSize === \"object\") {\n // If fontSize object has no default, let compound variants handle it (null)\n cvaFontSize = fontSize.default || null;\n } else {\n cvaFontSize = fontSize;\n }\n } // null triggers compound variants for default font sizes\n\n // Generate icon classes if icon prop is true\n let iconClasses = \"\";\n if (icon) {\n iconClasses = \"aspect-square p-0\";\n\n // If using responsive sizes, we need to override padding at each breakpoint\n if (typeof size === \"object\") {\n const iconResponsiveClasses: string[] = [];\n\n const breakpointMappings = [\n { sizeKey: \"xxs\" as const, prefix: \"xxs\" },\n { sizeKey: \"xs\" as const, prefix: \"xs\" },\n { sizeKey: \"sm\" as const, prefix: \"sm\" },\n { sizeKey: \"md\" as const, prefix: \"md\" },\n { sizeKey: \"lg\" as const, prefix: \"lg\" },\n { sizeKey: \"xl\" as const, prefix: \"xl\" },\n { sizeKey: \"2xl\" as const, prefix: \"2xl\" },\n ];\n\n for (const { sizeKey, prefix } of breakpointMappings) {\n const sizeValue = (size as Record<string, ButtonSize>)[sizeKey];\n if (sizeValue) {\n iconResponsiveClasses.push(`${prefix}:p-0`);\n }\n }\n\n if (iconResponsiveClasses.length > 0) {\n iconClasses += ` ${iconResponsiveClasses.join(\" \")}`;\n }\n }\n }\n\n return (\n <Comp\n className={cn(\n buttonVariants({\n variant,\n size: cvaSize,\n fontSize: cvaFontSize,\n borderRadius,\n border,\n noFeedback,\n }),\n responsiveClasses,\n responsiveFontSizeClasses,\n iconClasses,\n className\n )}\n ref={ref}\n type={buttonType}\n {...props}\n >\n {children}\n </Comp>\n );\n};\n\n/** CVA variants for Loading spinner sizing */\nconst loadingVariants = cva(\n \"hidden w-4 animate-[spin_0.75s_linear_infinite] text-inherit\",\n {\n variants: {\n size: {\n default: \"w-4\",\n lg: \"w-5\",\n sm: \"w-3\",\n xs: \"w-3\",\n icon: \"w-4\",\n xl: \"w-5\",\n },\n visible: {\n true: \"block\",\n false: \"hidden\",\n },\n },\n defaultVariants: {\n size: \"default\",\n visible: false,\n },\n }\n);\n\n/**\n * Animated loading spinner for use inside buttons.\n *\n * @param size - Match parent button size for proper scaling\n * @param visible - Show/hide the spinner\n *\n * @example\n * <Button disabled={isLoading}>\n * <Loading visible={isLoading} size=\"default\" />\n * Submit\n * </Button>\n */\nconst Loading = ({ size, visible }: VariantProps<typeof loadingVariants>) => (\n <LoaderCircle className={cn(loadingVariants({ size, visible }))} />\n);\n\nexport type {\n ButtonFontSize,\n ButtonSize,\n ResponsiveButtonFontSize,\n ResponsiveButtonSize,\n};\nexport { Button, buttonVariants, Loading, loadingVariants };\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * @module Button\n *\n * Versatile button component with multiple variants, sizes, and responsive options.\n * Supports all standard button interactions plus loading states and icon-only modes.\n *\n * @see {@link https://ui.shadcn.com/docs/components/button Shadcn Button}\n *\n * @example\n * // Basic buttons\n * <Button>Default</Button>\n * <Button variant=\"brand\">Primary Action</Button>\n * <Button variant=\"subtle\">Secondary</Button>\n *\n * @example\n * // Sizes\n * <Button size=\"xs\">Extra Small</Button>\n * <Button size=\"sm\">Small</Button>\n * <Button size=\"lg\">Large</Button>\n * <Button size=\"xl\">Extra Large</Button>\n *\n * @example\n * // Responsive size (changes at breakpoints)\n * <Button size={{ default: \"sm\", md: \"default\", lg: \"lg\" }}>\n * Responsive Button\n * </Button>\n *\n * @example\n * // Icon button\n * <Button icon size=\"default\"><PlayIcon /></Button>\n *\n * @example\n * // As link (using asChild)\n * <Button asChild variant=\"brand\">\n * <a href=\"/signup\">Sign Up</a>\n * </Button>\n *\n * @example\n * // With loading state\n * <Button disabled>\n * <Loading visible={isLoading} />\n * {isLoading ? \"Loading...\" : \"Submit\"}\n * </Button>\n */\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { LoaderCircle } from \"lucide-react\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type { ButtonHTMLAttributes, Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Size classes for consistent button dimensions */\n// Define size classes once as a single source of truth (including leading but not font sizes)\nconst sizeClasses = {\n default: \"h-8 px-4 py-2 leading-8\",\n xs: \"h-5 gap-1.5 px-2 leading-5\",\n sm: \"h-7 px-3 py-2 leading-6\",\n lg: \"h-10 px-4 py-2 leading-8\",\n xl: \"h-12 px-8 py-3 leading-10\",\n icon: \"h-8 w-8 leading-8\",\n} as const;\n\nconst fontSizeClasses = {\n xxs: \"text-xxs\",\n xs: \"text-xs\",\n sm: \"text-sm\",\n base: \"text-base\",\n lg: \"text-lg\",\n xl: \"text-xl\",\n} as const;\n\n// Type definitions for responsive sizes\ntype ButtonSize = \"default\" | \"xs\" | \"sm\" | \"lg\" | \"icon\" | \"xl\";\n\ntype ButtonFontSize = \"xxs\" | \"xs\" | \"sm\" | \"base\" | \"lg\" | \"xl\" | null;\n\n// Default font size mapping based on button size (excludes null)\nconst defaultFontSizeForSize: Record<\n ButtonSize,\n Exclude<ButtonFontSize, null>\n> = {\n xs: \"xs\",\n sm: \"xs\",\n default: \"base\",\n lg: \"base\",\n icon: \"base\",\n xl: \"lg\",\n};\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap font-normal font-sans text-base transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--focus-ring-offset)] enabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-50\",\n {\n variants: {\n variant: {\n // BRANDING VARIANTS (use CSS variables for themeability)\n subtle:\n \"border-1 border-gray-150 border-solid bg-white text-gray-950 hover:bg-gray-50 active:border-brand-primary-hover active:bg-brand-secondary active:text-brand-primary-hover disabled:bg-gray-50 active:disabled:border-gray-150 active:disabled:bg-gray-50 active:disabled:text-gray-950 dark:border-gray-800 dark:bg-gray-950 dark:text-white dark:disabled:border-gray-900 dark:disabled:bg-gray-950 dark:disabled:text-white dark:active:border-white dark:active:text-white dark:disabled:active:border-gray-900 dark:disabled:active:bg-gray-950 dark:disabled:active:text-white dark:hover:bg-gray-800\",\n brand:\n \"border-1 border-brand-primary border-solid bg-brand-primary font-semibold text-white hover:border-brand-primary-hover hover:bg-brand-primary-hover disabled:hover:bg-brand-primary-hover\",\n brandSecondary:\n \"border-1 border-brand-secondary border-solid bg-brand-secondary font-semibold text-brand-primary-hover hover:border-brand-secondary-hover hover:bg-brand-secondary-hover disabled:hover:bg-brand-secondary-hover dark:border-gray-900 dark:bg-gray-900 hover:dark:border-gray-800 hover:dark:bg-gray-800 dark:text-white dark:disabled:hover:border-gray-900 dark:disabled:hover:bg-gray-800\",\n bold: \"border-gray-950 bg-gray-950 font-semibold text-white dark:border-white dark:bg-white dark:text-gray-950\",\n light:\n \"border-gray-150 bg-gray-100 font-semibold text-gray-950 hover:border-gray-200 hover:bg-gray-200 disabled:hover:border-gray-150 disabled:hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-white dark:hover:bg-gray-700 dark:disabled:hover:bg-gray-800\",\n transparent:\n \"border-transparent! bg-transparent font-semibold text-gray-950 hover:border-gray-50 hover:bg-gray-50 disabled:hover:border-transparent disabled:hover:bg-transparent dark:text-white dark:hover:border-gray-900 dark:hover:bg-gray-800\",\n contrast:\n \"border-white bg-white font-semibold text-gray-950 hover:bg-gray-50 hover:disabled:border-white hover:disabled:bg-white\",\n success:\n \"border-green-600 bg-green-600 font-semibold text-white hover:border-green-700 hover:bg-green-700 disabled:hover:border-green-600 disabled:hover:bg-green-600 dark:border-green-500 dark:bg-green-500 dark:hover:border-green-650 dark:hover:bg-green-650 dark:disabled:hover:border-green-500 dark:disabled:hover:bg-green-500\",\n error:\n \"border-red-600 bg-red-600 font-semibold text-white hover:bg-red-700 disabled:hover:border-red-700 disabled:hover:bg-red-700 dark:border-red-500 dark:bg-red-500 dark:hover:border-red-600 dark:hover:bg-red-600 dark:disabled:hover:border-red-600 dark:disabled:hover:bg-red-600\",\n },\n\n size: sizeClasses,\n fontSize: {\n ...fontSizeClasses,\n null: \"\", // No font size class, relies on compound variants\n },\n borderRadius: {\n default: \"rounded-lg\",\n sm: \"rounded\",\n full: \"rounded-full\",\n rounded: \"rounded-[100px]\",\n },\n border: {\n true: \"border border-solid\",\n false: \"border-none\",\n },\n noFeedback: {\n true: \"\",\n false: \"transition-transform active:scale-[0.97] disabled:scale-100\",\n },\n },\n compoundVariants: [\n // Size + BorderRadius compounds\n {\n size: \"sm\",\n borderRadius: \"default\",\n className: \"rounded-lg\",\n },\n {\n size: \"xs\",\n borderRadius: \"default\",\n className: \"rounded-md\",\n },\n\n // Variant + Border compounds\n {\n variant: \"transparent\",\n border: true,\n className: \"border-gray-200 dark:border-gray-800\",\n },\n {\n variant: \"success\",\n border: true,\n className: \"border-green-dark\",\n },\n {\n variant: \"contrast\",\n border: true,\n className: \"border-white\",\n },\n // Size + fontSize compounds (default font size for each size when no explicit fontSize)\n { size: \"xs\", fontSize: null, className: \"text-xs\" },\n { size: \"sm\", fontSize: null, className: \"text-xs\" },\n { size: \"default\", fontSize: null, className: \"text-base\" },\n { size: \"lg\", fontSize: null, className: \"text-base\" },\n { size: \"icon\", fontSize: null, className: \"text-base\" },\n { size: \"xl\", fontSize: null, className: \"text-lg\" },\n ],\n defaultVariants: {\n variant: \"bold\",\n size: \"default\",\n fontSize: null,\n borderRadius: \"default\",\n border: false,\n noFeedback: false,\n },\n }\n);\n\ntype ResponsiveButtonSize =\n | ButtonSize\n | {\n default: ButtonSize;\n xxs?: ButtonSize;\n xs?: ButtonSize;\n sm?: ButtonSize;\n md?: ButtonSize;\n lg?: ButtonSize;\n xl?: ButtonSize;\n \"2xl\"?: ButtonSize;\n };\n\ntype ResponsiveButtonFontSize =\n | Exclude<ButtonFontSize, null>\n | {\n default?: Exclude<ButtonFontSize, null>;\n xxs?: Exclude<ButtonFontSize, null>;\n xs?: Exclude<ButtonFontSize, null>;\n sm?: Exclude<ButtonFontSize, null>;\n md?: Exclude<ButtonFontSize, null>;\n lg?: Exclude<ButtonFontSize, null>;\n xl?: Exclude<ButtonFontSize, null>;\n \"2xl\"?: Exclude<ButtonFontSize, null>;\n };\n\nconst getSizeClasses = (sizeKey: ButtonSize): string =>\n sizeClasses[sizeKey] || \"\";\n\nconst getFontSizeClasses = (\n fontSizeKey: Exclude<ButtonFontSize, null>\n): string => fontSizeClasses[fontSizeKey] || \"\";\n\n// Function to generate responsive Tailwind classes\nfunction generateResponsiveSizeClasses(size?: ResponsiveButtonSize): string {\n if (!size || typeof size === \"string\") {\n return \"\";\n }\n\n const classes: string[] = [];\n\n // Add responsive classes for each breakpoint\n const breakpoints = [\n { prefix: \"xxs\", value: size.xxs },\n { prefix: \"xs\", value: size.xs },\n { prefix: \"sm\", value: size.sm },\n { prefix: \"md\", value: size.md },\n { prefix: \"lg\", value: size.lg },\n { prefix: \"xl\", value: size.xl },\n { prefix: \"2xl\", value: size[\"2xl\"] },\n ];\n\n for (const breakpoint of breakpoints) {\n if (breakpoint.value) {\n const breakpointSizeClasses = getSizeClasses(breakpoint.value);\n const responsiveClasses = breakpointSizeClasses\n .split(\" \")\n .filter((cls) => cls.trim() !== \"\")\n .map((cls) => `${breakpoint.prefix}:${cls}`)\n .join(\" \");\n if (responsiveClasses) {\n classes.push(responsiveClasses);\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nfunction generateResponsiveFontSizeClasses(\n fontSize?: ResponsiveButtonFontSize\n): string {\n if (!fontSize || typeof fontSize === \"string\") {\n return \"\";\n }\n\n const classes: string[] = [];\n\n // Add responsive classes for each breakpoint\n const breakpoints = [\n { prefix: \"xxs\", value: fontSize.xxs },\n { prefix: \"xs\", value: fontSize.xs },\n { prefix: \"sm\", value: fontSize.sm },\n { prefix: \"md\", value: fontSize.md },\n { prefix: \"lg\", value: fontSize.lg },\n { prefix: \"xl\", value: fontSize.xl },\n { prefix: \"2xl\", value: fontSize[\"2xl\"] },\n ];\n\n for (const breakpoint of breakpoints) {\n if (breakpoint.value) {\n const breakpointFontSizeClasses = getFontSizeClasses(breakpoint.value);\n const responsiveClasses = breakpointFontSizeClasses\n .split(\" \")\n .filter((cls) => cls.trim() !== \"\")\n .map((cls) => `${breakpoint.prefix}:${cls}`)\n .join(\" \");\n if (responsiveClasses) {\n classes.push(responsiveClasses);\n }\n }\n }\n\n return classes.join(\" \");\n}\n\n/**\n * Props for the Button component.\n *\n * @property variant - Color/style: `brand`, `brandSecondary`, `subtle`, `bold`, `light`, `transparent`, `contrast`, `success`, `error`\n * @property size - Size or responsive size object: `xs`, `sm`, `default`, `lg`, `xl`, `icon`\n * @property fontSize - Override font size or responsive font size object\n * @property borderRadius - Corner style: `default`, `sm`, `full`, `rounded`\n * @property border - Show border when true\n * @property noFeedback - Disable scale animation on click\n * @property asChild - Render as child element (e.g., for links)\n * @property icon - Square aspect ratio with no padding (for icon-only buttons)\n */\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n Omit<VariantProps<typeof buttonVariants>, \"size\" | \"fontSize\"> {\n asChild?: boolean;\n fontSize?: ResponsiveButtonFontSize;\n icon?: boolean;\n ref?: Ref<HTMLButtonElement>;\n size?: ResponsiveButtonSize;\n}\n\nconst Button = ({\n className,\n variant,\n size,\n borderRadius,\n border,\n noFeedback,\n asChild = false,\n type,\n children,\n fontSize,\n icon = false,\n ref,\n ...props\n}: ButtonProps) => {\n const Comp = asChild ? SlotPrimitive.Slot : \"button\";\n const buttonType = asChild ? undefined : (type ?? \"button\");\n\n // Generate responsive classes or use the cva size variant\n const responsiveClasses =\n typeof size === \"object\" ? generateResponsiveSizeClasses(size) : undefined;\n\n // Generate responsive font size classes\n let responsiveFontSizeClasses: string | undefined;\n if (typeof fontSize === \"object\") {\n // User provided explicit responsive font sizes\n responsiveFontSizeClasses = generateResponsiveFontSizeClasses(fontSize);\n } else if (typeof size === \"object\" && fontSize === undefined) {\n // Auto-generate responsive font sizes based on responsive sizes\n const autoFontSize: ResponsiveButtonFontSize = {\n default: defaultFontSizeForSize[size.default] || \"base\",\n };\n\n // Map over the size object to create the auto font size object\n const breakpointMappings = [\n { sizeKey: \"xxs\" as const, fontKey: \"xxs\" as const },\n { sizeKey: \"xs\" as const, fontKey: \"xs\" as const },\n { sizeKey: \"sm\" as const, fontKey: \"sm\" as const },\n { sizeKey: \"md\" as const, fontKey: \"md\" as const },\n { sizeKey: \"lg\" as const, fontKey: \"lg\" as const },\n { sizeKey: \"xl\" as const, fontKey: \"xl\" as const },\n { sizeKey: \"2xl\" as const, fontKey: \"2xl\" as const },\n ];\n\n for (const { sizeKey, fontKey } of breakpointMappings) {\n const sizeValue = (size as Record<string, ButtonSize>)[sizeKey];\n if (sizeValue && sizeValue in defaultFontSizeForSize) {\n (autoFontSize as Record<string, Exclude<ButtonFontSize, null>>)[\n fontKey\n ] = defaultFontSizeForSize[sizeValue as ButtonSize];\n }\n }\n\n responsiveFontSizeClasses = generateResponsiveFontSizeClasses(autoFontSize);\n }\n\n // For object sizes, use the default size in the cva\n const cvaSize = typeof size === \"object\" ? size.default : size;\n\n // Determine font size for cva\n let cvaFontSize: ButtonFontSize = null;\n if (fontSize) {\n if (typeof fontSize === \"object\") {\n // If fontSize object has no default, let compound variants handle it (null)\n cvaFontSize = fontSize.default || null;\n } else {\n cvaFontSize = fontSize;\n }\n } // null triggers compound variants for default font sizes\n\n // Generate icon classes if icon prop is true\n let iconClasses = \"\";\n if (icon) {\n iconClasses = \"aspect-square p-0\";\n\n // If using responsive sizes, we need to override padding at each breakpoint\n if (typeof size === \"object\") {\n const iconResponsiveClasses: string[] = [];\n\n const breakpointMappings = [\n { sizeKey: \"xxs\" as const, prefix: \"xxs\" },\n { sizeKey: \"xs\" as const, prefix: \"xs\" },\n { sizeKey: \"sm\" as const, prefix: \"sm\" },\n { sizeKey: \"md\" as const, prefix: \"md\" },\n { sizeKey: \"lg\" as const, prefix: \"lg\" },\n { sizeKey: \"xl\" as const, prefix: \"xl\" },\n { sizeKey: \"2xl\" as const, prefix: \"2xl\" },\n ];\n\n for (const { sizeKey, prefix } of breakpointMappings) {\n const sizeValue = (size as Record<string, ButtonSize>)[sizeKey];\n if (sizeValue) {\n iconResponsiveClasses.push(`${prefix}:p-0`);\n }\n }\n\n if (iconResponsiveClasses.length > 0) {\n iconClasses += ` ${iconResponsiveClasses.join(\" \")}`;\n }\n }\n }\n\n return (\n <Comp\n className={cn(\n buttonVariants({\n variant,\n size: cvaSize,\n fontSize: cvaFontSize,\n borderRadius,\n border,\n noFeedback,\n }),\n responsiveClasses,\n responsiveFontSizeClasses,\n iconClasses,\n className\n )}\n ref={ref}\n type={buttonType}\n {...props}\n >\n {children}\n </Comp>\n );\n};\n\n/** CVA variants for Loading spinner sizing */\nconst loadingVariants = cva(\n \"hidden w-4 animate-[spin_0.75s_linear_infinite] text-inherit\",\n {\n variants: {\n size: {\n default: \"w-4\",\n lg: \"w-5\",\n sm: \"w-3\",\n xs: \"w-3\",\n icon: \"w-4\",\n xl: \"w-5\",\n },\n visible: {\n true: \"block\",\n false: \"hidden\",\n },\n },\n defaultVariants: {\n size: \"default\",\n visible: false,\n },\n }\n);\n\n/**\n * Animated loading spinner for use inside buttons.\n *\n * @param size - Match parent button size for proper scaling\n * @param visible - Show/hide the spinner\n *\n * @example\n * <Button disabled={isLoading}>\n * <Loading visible={isLoading} size=\"default\" />\n * Submit\n * </Button>\n */\nconst Loading = ({ size, visible }: VariantProps<typeof loadingVariants>) => (\n <LoaderCircle className={cn(loadingVariants({ size, visible }))} />\n);\n\nexport type {\n ButtonFontSize,\n ButtonSize,\n ResponsiveButtonFontSize,\n ResponsiveButtonSize,\n};\nexport { Button, buttonVariants, Loading, loadingVariants };\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -46,7 +46,7 @@ const DialogContent = ({
|
|
|
46
46
|
DialogPrimitive.Close,
|
|
47
47
|
{
|
|
48
48
|
asChild: true,
|
|
49
|
-
className: "absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100
|
|
49
|
+
className: "absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100 outline-hidden focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500 dark:ring-offset-gray-950 dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400 dark:focus-visible:ring-gray-300",
|
|
50
50
|
children: /* @__PURE__ */ jsxs(Button, { "aria-label": "Close", size: "icon", variant: "transparent", children: [
|
|
51
51
|
/* @__PURE__ */ jsx(X, { className: "h-5 w-5" }),
|
|
52
52
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/dialog.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * @module Dialog\n *\n * Modal dialog overlay for focused user interaction. Built on Radix UI Dialog primitive.\n * Includes backdrop overlay, close button, and focus trapping.\n *\n * @see {@link https://ui.shadcn.com/docs/components/dialog Shadcn Dialog}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/dialog Radix Dialog}\n *\n * @example\n * // Basic dialog\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open Dialog</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogDescription>\n * This action cannot be undone.\n * </DialogDescription>\n * </DialogHeader>\n * <DialogFooter>\n * <Button>Confirm</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n *\n * @example\n * // Controlled dialog\n * const [open, setOpen] = useState(false);\n *\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Edit Profile</DialogTitle>\n * </DialogHeader>\n * <form onSubmit={() => setOpen(false)}>\n * ...\n * </form>\n * </DialogContent>\n * </Dialog>\n */\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\nimport { headingVariants } from \"./typography/heading\";\nimport { textVariants } from \"./typography/text\";\n\n/** Root component that manages dialog open/closed state. */\nconst Dialog = DialogPrimitive.Root;\n\n/** Element that opens the dialog when clicked. Use `asChild` to wrap custom buttons. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portal for rendering dialog outside the DOM hierarchy. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when clicked. Use `asChild` to wrap custom close buttons. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Semi-transparent backdrop behind the dialog. Animated fade on open/close. */\nconst DialogOverlay = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Overlay>>;\n}) => (\n <DialogPrimitive.Overlay\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/60 data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/**\n * Main dialog container. Centered on screen with close button.\n * Includes overlay, focus trap, and Escape key handling.\n */\nconst DialogContent = ({\n className,\n children,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Content>>;\n}) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n className={cn(\n \"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-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-150 border-solid bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg dark:border-gray-800 dark:bg-gray-875\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <DialogPrimitive.Close\n asChild\n className=\"absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100
|
|
4
|
+
"sourcesContent": ["/**\n * @module Dialog\n *\n * Modal dialog overlay for focused user interaction. Built on Radix UI Dialog primitive.\n * Includes backdrop overlay, close button, and focus trapping.\n *\n * @see {@link https://ui.shadcn.com/docs/components/dialog Shadcn Dialog}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/dialog Radix Dialog}\n *\n * @example\n * // Basic dialog\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open Dialog</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogDescription>\n * This action cannot be undone.\n * </DialogDescription>\n * </DialogHeader>\n * <DialogFooter>\n * <Button>Confirm</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n *\n * @example\n * // Controlled dialog\n * const [open, setOpen] = useState(false);\n *\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Edit Profile</DialogTitle>\n * </DialogHeader>\n * <form onSubmit={() => setOpen(false)}>\n * ...\n * </form>\n * </DialogContent>\n * </Dialog>\n */\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\nimport { headingVariants } from \"./typography/heading\";\nimport { textVariants } from \"./typography/text\";\n\n/** Root component that manages dialog open/closed state. */\nconst Dialog = DialogPrimitive.Root;\n\n/** Element that opens the dialog when clicked. Use `asChild` to wrap custom buttons. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portal for rendering dialog outside the DOM hierarchy. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when clicked. Use `asChild` to wrap custom close buttons. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Semi-transparent backdrop behind the dialog. Animated fade on open/close. */\nconst DialogOverlay = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Overlay>>;\n}) => (\n <DialogPrimitive.Overlay\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/60 data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/**\n * Main dialog container. Centered on screen with close button.\n * Includes overlay, focus trap, and Escape key handling.\n */\nconst DialogContent = ({\n className,\n children,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Content>>;\n}) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n className={cn(\n \"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-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-150 border-solid bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg dark:border-gray-800 dark:bg-gray-875\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <DialogPrimitive.Close\n asChild\n className=\"absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100 outline-hidden focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500 dark:ring-offset-gray-950 dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400 dark:focus-visible:ring-gray-300\"\n >\n <Button aria-label=\"Close\" size=\"icon\" variant=\"transparent\">\n <X className=\"h-5 w-5\" />\n <span className=\"sr-only\">Close</span>\n </Button>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n);\n\n/** Header section for dialog title and description. Centered on mobile, left-aligned on desktop. */\nconst DialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-1.5 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Footer section for action buttons. Stacks on mobile, horizontal on desktop. */\nconst DialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className\n )}\n {...props}\n />\n);\nDialogFooter.displayName = \"DialogFooter\";\n\n/** Dialog title with Echo typography. Required for accessibility. */\nconst DialogTitle = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Title>>;\n}) => (\n <DialogPrimitive.Title\n className={cn(\n headingVariants({ variant: \"h5\", fontFamily: \"brand\" }),\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Accessible description text below the title. */\nconst DialogDescription = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Description>>;\n}) => (\n <DialogPrimitive.Description\n className={cn(textVariants(), \"text-sm\", className)}\n ref={ref}\n {...props}\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"],
|
|
5
5
|
"mappings": "AAyEE,cAqCM,YArCN;AA9BF,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAIlB,SAAS,UAAU;AACnB,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAG7B,MAAM,SAAS,gBAAgB;AAG/B,MAAM,gBAAgB,gBAAgB;AAGtC,MAAM,eAAe,gBAAgB;AAGrC,MAAM,cAAc,gBAAgB;AAGpC,MAAM,gBAAgB,CAAC;AAAA,EACrB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE;AAAA,EAAC,gBAAgB;AAAA,EAAhB;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACC,GAAG;AAAA;AACN;AAOF,MAAM,gBAAgB,CAAC;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE,qBAAC,gBACC;AAAA,sBAAC,iBAAc;AAAA,EACf;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACD;AAAA,UAAC,gBAAgB;AAAA,UAAhB;AAAA,YACC,SAAO;AAAA,YACP,WAAU;AAAA,YAEV,+BAAC,UAAO,cAAW,SAAQ,MAAK,QAAO,SAAQ,eAC7C;AAAA,kCAAC,KAAE,WAAU,WAAU;AAAA,cACvB,oBAAC,UAAK,WAAU,WAAU,mBAAK;AAAA,eACjC;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAAA,GACF;AAIF,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA,GAAG;AACL,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN;AAEF,aAAa,cAAc;AAG3B,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA,GAAG;AACL,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN;AAEF,aAAa,cAAc;AAG3B,MAAM,cAAc,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE;AAAA,EAAC,gBAAgB;AAAA,EAAhB;AAAA,IACC,WAAW;AAAA,MACT,gBAAgB,EAAE,SAAS,MAAM,YAAY,QAAQ,CAAC;AAAA,MACtD;AAAA,IACF;AAAA,IACA;AAAA,IACC,GAAG;AAAA;AACN;AAIF,MAAM,oBAAoB,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE;AAAA,EAAC,gBAAgB;AAAA,EAAhB;AAAA,IACC,WAAW,GAAG,aAAa,GAAG,WAAW,SAAS;AAAA,IAClD;AAAA,IACC,GAAG;AAAA;AACN;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAkBjC,QAAA,MAAM,aAAa;;;;;
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAkBjC,QAAA,MAAM,aAAa;;;;;8EAkElB,CAAC;AAEF,KAAK,qBAAqB,GAAG,IAAI,CAC/B,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAC3C,MAAM,CACP,CAAC;AAEF,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAK7D,KAAK,wBAAwB,GAAG,IAAI,CAClC,kBAAkB,EAClB,aAAa,GAAG,cAAc,GAAG,MAAM,CACxC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,UACf,SAAQ,qBAAqB,EAC3B,wBAAwB;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B;AAED,QAAA,MAAM,KAAK,GAAI,sFAUZ,UAAU,4CAwDZ,CAAC;AAEF,UAAU,qBACR,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,GAAG,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,QAAA,MAAM,gBAAgB,GAAI,8BAIvB,qBAAqB,4CAcvB,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/components/input.js
CHANGED
|
@@ -23,8 +23,10 @@ const inputVariants = cva(
|
|
|
23
23
|
"font-sans text-base text-black antialiased disabled:text-black/60 dark:text-white dark:disabled:text-white/60",
|
|
24
24
|
// placeholder
|
|
25
25
|
"placeholder-gray-700 placeholder:font-sans dark:placeholder-gray-200",
|
|
26
|
-
// background
|
|
27
|
-
|
|
26
|
+
// background — transparent across interactive states so the input
|
|
27
|
+
// inherits whatever surface it sits on (page, card, modal, drawer).
|
|
28
|
+
// Disabled keeps a faded fill so the state stays distinguishable.
|
|
29
|
+
"bg-transparent focus:bg-transparent enabled:hover:bg-transparent disabled:bg-white/60 dark:disabled:bg-black/60",
|
|
28
30
|
// borders (light)
|
|
29
31
|
"rounded-lg border border-gray-150 border-solid invalid:border-red invalid:hover:border-red focus:border-brand-primary enabled:hover:border-gray-200 enabled:focus:hover:border-brand-primary disabled:border-gray-150/60",
|
|
30
32
|
// borders light
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/input.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * @module Input\n *\n * Styled text input with support for icons, sizes, and clear button.\n * Includes focus state management and dark mode support.\n *\n * @example\n * // Basic input\n * <Input placeholder=\"Enter your email\" type=\"email\" />\n *\n * @example\n * // With icons\n * <Input\n * leftIcon={<Search />}\n * rightIcon={<ClearInputButton onClick={clearValue} />}\n * placeholder=\"Search...\"\n * />\n *\n * @example\n * // Small size\n * <Input size=\"sm\" placeholder=\"Compact input\" />\n *\n * @example\n * // With clear button\n * const [value, setValue] = useState('');\n *\n * <Input\n * value={value}\n * onChange={(e) => setValue(e.target.value)}\n * rightIcon={\n * value && <ClearInputButton onClick={() => setValue('')} />\n * }\n * />\n */\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport { useState } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst inputWrapperVariants = cva(\"relative flex w-full items-center\", {\n variants: {\n size: {\n auto: \"h-auto w-auto\",\n default: \"h-10\",\n sm: \"h-7\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n});\n\nconst inputVariants = cva(\n [\n \"w-full touch-manipulation self-stretch shadow-none outline-hidden outline-0 transition duration-200 ease-out disabled:cursor-not-allowed dark:disabled:cursor-not-allowed\",\n // text\n \"font-sans text-base text-black antialiased disabled:text-black/60 dark:text-white dark:disabled:text-white/60\",\n // placeholder\n \"placeholder-gray-700 placeholder:font-sans dark:placeholder-gray-200\",\n // background\n \"bg-
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * @module Input\n *\n * Styled text input with support for icons, sizes, and clear button.\n * Includes focus state management and dark mode support.\n *\n * @example\n * // Basic input\n * <Input placeholder=\"Enter your email\" type=\"email\" />\n *\n * @example\n * // With icons\n * <Input\n * leftIcon={<Search />}\n * rightIcon={<ClearInputButton onClick={clearValue} />}\n * placeholder=\"Search...\"\n * />\n *\n * @example\n * // Small size\n * <Input size=\"sm\" placeholder=\"Compact input\" />\n *\n * @example\n * // With clear button\n * const [value, setValue] = useState('');\n *\n * <Input\n * value={value}\n * onChange={(e) => setValue(e.target.value)}\n * rightIcon={\n * value && <ClearInputButton onClick={() => setValue('')} />\n * }\n * />\n */\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport { useState } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst inputWrapperVariants = cva(\"relative flex w-full items-center\", {\n variants: {\n size: {\n auto: \"h-auto w-auto\",\n default: \"h-10\",\n sm: \"h-7\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n});\n\nconst inputVariants = cva(\n [\n \"w-full touch-manipulation self-stretch shadow-none outline-hidden outline-0 transition duration-200 ease-out disabled:cursor-not-allowed dark:disabled:cursor-not-allowed\",\n // text\n \"font-sans text-base text-black antialiased disabled:text-black/60 dark:text-white dark:disabled:text-white/60\",\n // placeholder\n \"placeholder-gray-700 placeholder:font-sans dark:placeholder-gray-200\",\n // background \u2014 transparent across interactive states so the input\n // inherits whatever surface it sits on (page, card, modal, drawer).\n // Disabled keeps a faded fill so the state stays distinguishable.\n \"bg-transparent focus:bg-transparent enabled:hover:bg-transparent disabled:bg-white/60 dark:disabled:bg-black/60\",\n // borders (light)\n \"rounded-lg border border-gray-150 border-solid invalid:border-red invalid:hover:border-red focus:border-brand-primary enabled:hover:border-gray-200 enabled:focus:hover:border-brand-primary disabled:border-gray-150/60\", // borders light\n // borders (dark)\n \"dark:border-gray-800 dark:disabled:border-gray-900 dark:focus:border-white dark:enabled:hover:border-gray-700 dark:enabled:focus:hover:border-white dark:invalid:border-red dark:invalid:hover:border-red\", // borders dark\n ],\n {\n variants: {\n size: {\n default: \"px-4\",\n sm: \"px-3\",\n auto: \"px-4\",\n },\n hasLeftIcon: {\n true: \"\",\n false: \"\",\n },\n hasRightIcon: {\n true: \"\",\n false: \"\",\n },\n // Scoped to type=\"search\" only: the Keeper password manager extension\n // misidentifies inputs that style ::-webkit-search-cancel-button as\n // search fields and blocks paste, so non-search inputs must not match.\n type: {\n search: \"dark:[&::-webkit-search-cancel-button]:hidden\",\n },\n },\n compoundVariants: [\n {\n hasLeftIcon: true,\n size: \"default\",\n class: \"pl-10\",\n },\n {\n hasLeftIcon: true,\n size: \"sm\",\n class: \"pl-8\",\n },\n {\n hasRightIcon: true,\n size: \"default\",\n class: \"pr-10\",\n },\n {\n hasRightIcon: true,\n size: \"sm\",\n class: \"pr-8\",\n },\n ],\n defaultVariants: {\n size: \"default\",\n hasLeftIcon: false,\n hasRightIcon: false,\n },\n }\n);\n\ntype InputPropsWithoutSize = Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n>;\n\ntype InputVariantsProps = VariantProps<typeof inputVariants>;\n\n// Omit internal-only variants from the public API. `type` is excluded so\n// consumers keep the full HTMLInputTypeAttribute union; CVA still picks up\n// the runtime value via the `type` argument passed in inputVariants().\ntype PublicInputVariantsProps = Omit<\n InputVariantsProps,\n \"hasLeftIcon\" | \"hasRightIcon\" | \"type\"\n>;\n\n/**\n * Props for the Input component.\n * @property size - Input size: `\"default\"`, `\"sm\"`, or `\"auto\"`\n * @property htmlSize - Native HTML size attribute for input width\n * @property leftIcon - Icon element displayed on the left side\n * @property rightIcon - Icon element displayed on the right side\n */\nexport interface InputProps\n extends InputPropsWithoutSize,\n PublicInputVariantsProps {\n htmlSize?: number;\n leftIcon?: React.ReactNode;\n ref?: Ref<HTMLInputElement>;\n rightIcon?: React.ReactNode;\n}\n\nconst Input = ({\n className,\n size,\n type = \"text\",\n htmlSize,\n leftIcon,\n rightIcon,\n placeholder,\n ref,\n ...props\n}: InputProps) => {\n const [isFocused, setIsFocused] = useState(false);\n\n return (\n // biome-ignore lint/a11y/noNoninteractiveElementInteractions: container needs onBlur to coordinate focus state across child input and icon slots\n // biome-ignore lint/a11y/noStaticElementInteractions: container needs onBlur to coordinate focus state across child input and icon slots\n <div\n className={cn(inputWrapperVariants({ size }))}\n onBlur={() => {\n setTimeout(() => {\n setIsFocused(false);\n }, 50);\n }}\n >\n {!!leftIcon && (\n <SlotPrimitive.Slot\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300 [&:is(svg)]:pointer-events-none\",\n size === \"sm\" ? \"left-3 size-3\" : \"left-4 size-4\"\n )}\n >\n {leftIcon}\n </SlotPrimitive.Slot>\n )}\n <input\n className={cn(\n inputVariants({\n size,\n hasLeftIcon: !!leftIcon,\n hasRightIcon: !!rightIcon,\n type: type === \"search\" ? \"search\" : undefined,\n className,\n })\n )}\n onFocus={(e) => {\n setIsFocused(true);\n props.onFocus?.(e);\n }}\n placeholder={isFocused ? \" \" : placeholder}\n ref={ref}\n size={htmlSize}\n type={type}\n {...props}\n />\n {!!rightIcon && (\n <SlotPrimitive.Slot\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300 [&:is(svg)]:pointer-events-none\",\n size === \"sm\" ? \"right-3 size-3\" : \"right-4 size-4\"\n )}\n >\n {rightIcon}\n </SlotPrimitive.Slot>\n )}\n </div>\n );\n};\n\ninterface ClearInputButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * Clear/reset button designed for use as Input's rightIcon.\n * Displays an X icon and handles focus states.\n */\nconst ClearInputButton = ({\n className,\n ref,\n ...props\n}: ClearInputButtonProps) => (\n <button\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300\",\n \"focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-gray-100\",\n \"rounded-full focus-visible:outline-hidden dark:focus-visible:ring-[var(--focus-ring)] dark:focus-visible:ring-offset-gray-800\",\n className\n )}\n ref={ref}\n type=\"button\"\n {...props}\n >\n <X className=\"absolute inset-0 size-full\" strokeWidth={3} />\n </button>\n);\n\nexport { ClearInputButton, Input, inputVariants };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|