@srcroot/ui 0.0.61 → 0.0.63

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.
@@ -1,44 +1,47 @@
1
- import * as React from "react"
2
- import { cva, type VariantProps } from "class-variance-authority"
3
- import { cn } from "@/lib/utils"
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+ import { cn } from "@/lib/utils";
4
6
 
5
7
  const containerVariants = cva("mx-auto w-full px-4", {
6
- variants: {
7
- size: {
8
- sm: "max-w-screen-sm",
9
- md: "max-w-screen-md",
10
- lg: "max-w-screen-lg",
11
- xl: "max-w-screen-xl",
12
- "2xl": "max-w-screen-2xl",
13
- full: "max-w-full",
14
- },
15
- },
16
- defaultVariants: {
17
- size: "xl",
8
+ variants: {
9
+ size: {
10
+ sm: "max-w-screen-sm",
11
+ md: "max-w-screen-md",
12
+ lg: "max-w-screen-lg",
13
+ xl: "max-w-screen-xl",
14
+ "2xl": "max-w-screen-2xl",
15
+ full: "max-w-full",
18
16
  },
19
- })
17
+ },
18
+ defaultVariants: {
19
+ size: "xl",
20
+ },
21
+ });
20
22
 
21
23
  interface ContainerProps
22
- extends React.HTMLAttributes<HTMLDivElement>,
23
- VariantProps<typeof containerVariants> { }
24
+ extends
25
+ React.HTMLAttributes<HTMLDivElement>,
26
+ VariantProps<typeof containerVariants> {}
24
27
 
25
28
  /**
26
29
  * Container for max-width layouts
27
- *
30
+ *
28
31
  * @example
29
32
  * <Container size="lg">Content</Container>
30
33
  */
31
34
  const Container = React.forwardRef<HTMLDivElement, ContainerProps>(
32
- ({ className, size, ...props }, ref) => {
33
- return (
34
- <div
35
- ref={ref}
36
- className={cn(containerVariants({ size }), className)}
37
- {...props}
38
- />
39
- )
40
- }
41
- )
42
- Container.displayName = "Container"
35
+ ({ className, size, ...props }, ref) => {
36
+ return (
37
+ <div
38
+ ref={ref}
39
+ className={cn(containerVariants({ size }), className)}
40
+ {...props}
41
+ />
42
+ );
43
+ },
44
+ );
45
+ Container.displayName = "Container";
43
46
 
44
- export { Container, containerVariants }
47
+ export { Container, containerVariants };
@@ -1,38 +1,40 @@
1
- import { cn } from "@/lib/utils"
1
+ "use client";
2
+
3
+ import { cn } from "@/lib/utils";
2
4
 
3
5
  interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
4
- icon?: React.ElementType
5
- title: string
6
- description: string
7
- action?: React.ReactNode
6
+ icon?: React.ElementType;
7
+ title: string;
8
+ description: string;
9
+ action?: React.ReactNode;
8
10
  }
9
11
 
10
12
  export function EmptyState({
11
- icon: Icon,
12
- title,
13
- description,
14
- action,
15
- className,
16
- ...props
13
+ icon: Icon,
14
+ title,
15
+ description,
16
+ action,
17
+ className,
18
+ ...props
17
19
  }: EmptyStateProps) {
18
- return (
19
- <div
20
- className={cn(
21
- "flex flex-col items-center justify-center py-12 text-center border-2 border-dashed rounded-lg bg-muted/5",
22
- className
23
- )}
24
- {...props}
25
- >
26
- {Icon && (
27
- <div className="flex h-20 w-20 items-center justify-center rounded-full bg-muted/50 mb-4">
28
- <Icon className="h-10 w-10 text-muted-foreground" />
29
- </div>
30
- )}
31
- <h3 className="text-lg font-semibold tracking-tight">{title}</h3>
32
- <p className="text-muted-foreground text-sm max-w-sm mt-2 mb-6">
33
- {description}
34
- </p>
35
- {action && <div>{action}</div>}
20
+ return (
21
+ <div
22
+ className={cn(
23
+ "flex flex-col items-center justify-center py-12 text-center border-2 border-dashed rounded-lg bg-muted/5",
24
+ className,
25
+ )}
26
+ {...props}
27
+ >
28
+ {Icon && (
29
+ <div className="flex h-20 w-20 items-center justify-center rounded-full bg-muted/50 mb-4">
30
+ <Icon className="h-10 w-10 text-muted-foreground" />
36
31
  </div>
37
- )
32
+ )}
33
+ <h3 className="text-lg font-semibold tracking-tight">{title}</h3>
34
+ <p className="text-muted-foreground text-sm max-w-sm mt-2 mb-6">
35
+ {description}
36
+ </p>
37
+ {action && <div>{action}</div>}
38
+ </div>
39
+ );
38
40
  }
@@ -1,33 +1,35 @@
1
- import * as React from "react"
2
- import { Label } from "@/components/ui/label"
3
- import { cn } from "@/lib/utils"
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Label } from "@/components/ui/label";
5
+ import { cn } from "@/lib/utils";
4
6
 
5
7
  export interface FormFieldProps extends React.HTMLAttributes<HTMLDivElement> {
6
- /**
7
- * The label for the field
8
- */
9
- label?: React.ReactNode
10
- /**
11
- * Helper text description
12
- */
13
- description?: React.ReactNode
14
- /**
15
- * Error message
16
- */
17
- error?: React.ReactNode
18
- /**
19
- * Whether the field is required (shows asterisk)
20
- */
21
- required?: boolean
22
- /**
23
- * The ID of the input element, used for label association
24
- */
25
- htmlFor?: string
8
+ /**
9
+ * The label for the field
10
+ */
11
+ label?: React.ReactNode;
12
+ /**
13
+ * Helper text description
14
+ */
15
+ description?: React.ReactNode;
16
+ /**
17
+ * Error message
18
+ */
19
+ error?: React.ReactNode;
20
+ /**
21
+ * Whether the field is required (shows asterisk)
22
+ */
23
+ required?: boolean;
24
+ /**
25
+ * The ID of the input element, used for label association
26
+ */
27
+ htmlFor?: string;
26
28
  }
27
29
 
28
30
  /**
29
31
  * FormField wrapper for consistent label and error placement
30
- *
32
+ *
31
33
  * @example
32
34
  * <FormField
33
35
  * label="Email"
@@ -39,53 +41,62 @@ export interface FormFieldProps extends React.HTMLAttributes<HTMLDivElement> {
39
41
  * </FormField>
40
42
  */
41
43
  const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>(
42
- ({ className, label, description, error, required, htmlFor, children, ...props }, ref) => {
43
- const id = htmlFor || React.useId()
44
+ (
45
+ {
46
+ className,
47
+ label,
48
+ description,
49
+ error,
50
+ required,
51
+ htmlFor,
52
+ children,
53
+ ...props
54
+ },
55
+ ref,
56
+ ) => {
57
+ const id = htmlFor || React.useId();
44
58
 
45
- // Clone child to inject id and error state if it's a valid React element
46
- const childWithProps = React.isValidElement(children)
47
- ? React.cloneElement(children as React.ReactElement<any>, {
48
- id: id,
49
- error: !!error,
50
- "aria-describedby": error ? `${id}-error` : description ? `${id}-desc` : undefined,
51
- })
52
- : children
59
+ // Clone child to inject id and error state if it's a valid React element
60
+ const childWithProps = React.isValidElement(children)
61
+ ? React.cloneElement(children as React.ReactElement<any>, {
62
+ id: id,
63
+ error: !!error,
64
+ "aria-describedby": error
65
+ ? `${id}-error`
66
+ : description
67
+ ? `${id}-desc`
68
+ : undefined,
69
+ })
70
+ : children;
53
71
 
54
- return (
55
- <div
56
- ref={ref}
57
- className={cn("space-y-2", className)}
58
- {...props}
59
- >
60
- {label && (
61
- <Label htmlFor={id} required={required}>
62
- {label}
63
- </Label>
64
- )}
72
+ return (
73
+ <div ref={ref} className={cn("space-y-2", className)} {...props}>
74
+ {label && (
75
+ <Label htmlFor={id} required={required}>
76
+ {label}
77
+ </Label>
78
+ )}
65
79
 
66
- {childWithProps}
80
+ {childWithProps}
67
81
 
68
- {description && !error && (
69
- <p
70
- id={`${id}-desc`}
71
- className="text-[0.8rem] text-muted-foreground"
72
- >
73
- {description}
74
- </p>
75
- )}
82
+ {description && !error && (
83
+ <p id={`${id}-desc`} className="text-[0.8rem] text-muted-foreground">
84
+ {description}
85
+ </p>
86
+ )}
76
87
 
77
- {error && (
78
- <p
79
- id={`${id}-error`}
80
- className="text-[0.8rem] font-medium text-destructive"
81
- >
82
- {error}
83
- </p>
84
- )}
85
- </div>
86
- )
87
- }
88
- )
89
- FormField.displayName = "FormField"
88
+ {error && (
89
+ <p
90
+ id={`${id}-error`}
91
+ className="text-[0.8rem] font-medium text-destructive"
92
+ >
93
+ {error}
94
+ </p>
95
+ )}
96
+ </div>
97
+ );
98
+ },
99
+ );
100
+ FormField.displayName = "FormField";
90
101
 
91
- export { FormField }
102
+ export { FormField };
@@ -1,144 +1,152 @@
1
- import * as React from "react"
2
- import { cva, type VariantProps } from "class-variance-authority"
3
- import { cn } from "@/lib/utils"
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+ import { cn } from "@/lib/utils";
4
6
 
5
7
  const imageVariants = cva("", {
6
- variants: {
7
- rounded: {
8
- none: "rounded-none",
9
- sm: "rounded-sm",
10
- default: "rounded-md",
11
- md: "rounded-md",
12
- lg: "rounded-lg",
13
- xl: "rounded-xl",
14
- full: "rounded-full",
15
- },
16
- objectFit: {
17
- cover: "object-cover",
18
- contain: "object-contain",
19
- fill: "object-fill",
20
- none: "object-none",
21
- },
8
+ variants: {
9
+ rounded: {
10
+ none: "rounded-none",
11
+ sm: "rounded-sm",
12
+ default: "rounded-md",
13
+ md: "rounded-md",
14
+ lg: "rounded-lg",
15
+ xl: "rounded-xl",
16
+ full: "rounded-full",
22
17
  },
23
- defaultVariants: {
24
- rounded: "default",
25
- objectFit: "cover",
18
+ objectFit: {
19
+ cover: "object-cover",
20
+ contain: "object-contain",
21
+ fill: "object-fill",
22
+ none: "object-none",
26
23
  },
27
- })
24
+ },
25
+ defaultVariants: {
26
+ rounded: "default",
27
+ objectFit: "cover",
28
+ },
29
+ });
28
30
 
29
- type ImageVariants = VariantProps<typeof imageVariants>
31
+ type ImageVariants = VariantProps<typeof imageVariants>;
30
32
 
31
33
  interface ImageProps
32
- extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "onLoad" | "onError">,
34
+ extends
35
+ Omit<React.ImgHTMLAttributes<HTMLImageElement>, "onLoad" | "onError">,
33
36
  ImageVariants {
34
- /** Fallback content or URL when image fails to load */
35
- fallback?: React.ReactNode | string
36
- /** Show skeleton loading state */
37
- showSkeleton?: boolean
38
- /** Aspect ratio (width/height) */
39
- aspectRatio?: number
37
+ /** Fallback content or URL when image fails to load */
38
+ fallback?: React.ReactNode | string;
39
+ /** Show skeleton loading state */
40
+ showSkeleton?: boolean;
41
+ /** Aspect ratio (width/height) */
42
+ aspectRatio?: number;
40
43
  }
41
44
 
42
45
  /**
43
46
  * Enhanced Image with loading states and fallback
44
- *
47
+ *
45
48
  * @example
46
49
  * <Image src="/photo.jpg" alt="Photo" aspectRatio={16/9} />
47
50
  * <Image src="/avatar.jpg" alt="User" rounded="full" fallback="JD" />
48
51
  */
49
52
  const Image = React.forwardRef<HTMLImageElement, ImageProps>(
50
- (
51
- {
52
- className,
53
- src,
54
- alt,
55
- fallback,
56
- showSkeleton = true,
57
- aspectRatio,
58
- rounded,
59
- objectFit,
60
- style,
61
- ...props
62
- },
63
- ref
64
- ) => {
65
- const [status, setStatus] = React.useState<"loading" | "loaded" | "error">("loading")
53
+ (
54
+ {
55
+ className,
56
+ src,
57
+ alt,
58
+ fallback,
59
+ showSkeleton = true,
60
+ aspectRatio,
61
+ rounded,
62
+ objectFit,
63
+ style,
64
+ ...props
65
+ },
66
+ ref,
67
+ ) => {
68
+ const [status, setStatus] = React.useState<"loading" | "loaded" | "error">(
69
+ "loading",
70
+ );
66
71
 
67
- React.useEffect(() => {
68
- setStatus("loading")
69
- }, [src])
72
+ React.useEffect(() => {
73
+ setStatus("loading");
74
+ }, [src]);
70
75
 
71
- const containerStyle: React.CSSProperties = aspectRatio
72
- ? { paddingBottom: `${100 / aspectRatio}%`, ...(style || {}) }
73
- : (style || {})
76
+ const containerStyle: React.CSSProperties = aspectRatio
77
+ ? { paddingBottom: `${100 / aspectRatio}%`, ...(style || {}) }
78
+ : style || {};
74
79
 
75
- // Render fallback
76
- if (status === "error" && fallback) {
77
- if (typeof fallback === "string") {
78
- // If fallback is a string, check if it's a URL or initials
79
- if (fallback.startsWith("http") || fallback.startsWith("/")) {
80
- return (
81
- <img
82
- ref={ref}
83
- src={fallback}
84
- alt={alt}
85
- className={cn(imageVariants({ rounded, objectFit }), className)}
86
- style={style}
87
- {...props}
88
- />
89
- )
90
- }
91
- // Initials fallback
92
- return (
93
- <div
94
- className={cn(
95
- "flex items-center justify-center bg-muted text-muted-foreground font-medium",
96
- imageVariants({ rounded }),
97
- className
98
- )}
99
- style={containerStyle}
100
- >
101
- {fallback}
102
- </div>
103
- )
104
- }
105
- return <>{fallback}</>
80
+ // Render fallback
81
+ if (status === "error" && fallback) {
82
+ if (typeof fallback === "string") {
83
+ // If fallback is a string, check if it's a URL or initials
84
+ if (fallback.startsWith("http") || fallback.startsWith("/")) {
85
+ return (
86
+ <img
87
+ ref={ref}
88
+ src={fallback}
89
+ alt={alt}
90
+ className={cn(imageVariants({ rounded, objectFit }), className)}
91
+ style={style}
92
+ {...props}
93
+ />
94
+ );
106
95
  }
107
-
96
+ // Initials fallback
108
97
  return (
109
- <div
110
- className={cn("relative overflow-hidden", aspectRatio && "w-full")}
111
- style={aspectRatio ? { paddingBottom: `${100 / aspectRatio}%` } : undefined}
112
- >
113
- {/* Skeleton */}
114
- {status === "loading" && showSkeleton && (
115
- <div
116
- className={cn(
117
- "absolute inset-0 animate-pulse bg-muted",
118
- imageVariants({ rounded })
119
- )}
120
- />
121
- )}
122
-
123
- <img
124
- ref={ref}
125
- src={src}
126
- alt={alt}
127
- className={cn(
128
- imageVariants({ rounded, objectFit }),
129
- aspectRatio && "absolute inset-0 h-full w-full",
130
- status === "loading" && "opacity-0",
131
- status === "loaded" && "opacity-100 transition-opacity duration-300",
132
- className
133
- )}
134
- onLoad={() => setStatus("loaded")}
135
- onError={() => setStatus("error")}
136
- {...props}
137
- />
138
- </div>
139
- )
98
+ <div
99
+ className={cn(
100
+ "flex items-center justify-center bg-muted text-muted-foreground font-medium",
101
+ imageVariants({ rounded }),
102
+ className,
103
+ )}
104
+ style={containerStyle}
105
+ >
106
+ {fallback}
107
+ </div>
108
+ );
109
+ }
110
+ return <>{fallback}</>;
140
111
  }
141
- )
142
- Image.displayName = "Image"
143
112
 
144
- export { Image, imageVariants }
113
+ return (
114
+ <div
115
+ className={cn("relative overflow-hidden", aspectRatio && "w-full")}
116
+ style={
117
+ aspectRatio ? { paddingBottom: `${100 / aspectRatio}%` } : undefined
118
+ }
119
+ >
120
+ {/* Skeleton */}
121
+ {status === "loading" && showSkeleton && (
122
+ <div
123
+ className={cn(
124
+ "absolute inset-0 animate-pulse bg-muted",
125
+ imageVariants({ rounded }),
126
+ )}
127
+ />
128
+ )}
129
+
130
+ <img
131
+ ref={ref}
132
+ src={src}
133
+ alt={alt}
134
+ className={cn(
135
+ imageVariants({ rounded, objectFit }),
136
+ aspectRatio && "absolute inset-0 h-full w-full",
137
+ status === "loading" && "opacity-0",
138
+ status === "loaded" &&
139
+ "opacity-100 transition-opacity duration-300",
140
+ className,
141
+ )}
142
+ onLoad={() => setStatus("loaded")}
143
+ onError={() => setStatus("error")}
144
+ {...props}
145
+ />
146
+ </div>
147
+ );
148
+ },
149
+ );
150
+ Image.displayName = "Image";
151
+
152
+ export { Image, imageVariants };