summaryrefslogtreecommitdiff
path: root/apps/web/src/components/ui/input.tsx
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-06-22 10:02:50 +0200
committerMaze Winther <mazewinther@gmail.com>2025-06-22 10:02:50 +0200
commit87a83a5604b20550430ef4eefbcd573d309694e2 (patch)
tree7ed86f00b8414cb6543f5c5ac98ea6e9abd2e10f /apps/web/src/components/ui/input.tsx
downloadopencut-87a83a5604b20550430ef4eefbcd573d309694e2.tar.gz
Initial commit
Diffstat (limited to 'apps/web/src/components/ui/input.tsx')
-rw-r--r--apps/web/src/components/ui/input.tsx63
1 files changed, 63 insertions, 0 deletions
diff --git a/apps/web/src/components/ui/input.tsx b/apps/web/src/components/ui/input.tsx
new file mode 100644
index 00000000..c458e036
--- /dev/null
+++ b/apps/web/src/components/ui/input.tsx
@@ -0,0 +1,63 @@
+import * as React from "react";
+import { Eye, EyeOff } from "lucide-react";
+
+import { cn } from "../../lib/utils";
+import { Button } from "./button";
+
+interface InputProps extends React.ComponentProps<"input"> {
+ showPassword?: boolean;
+ onShowPasswordChange?: (show: boolean) => void;
+}
+
+const Input = React.forwardRef<HTMLInputElement, InputProps>(
+ (
+ {
+ className,
+ type,
+ showPassword,
+ onShowPasswordChange,
+ value = "",
+ ...props
+ },
+ ref
+ ) => {
+ const isPassword = type === "password";
+ const showPasswordToggle = isPassword && onShowPasswordChange;
+ const inputType = isPassword && showPassword ? "text" : type;
+
+ return (
+ <div className="relative w-full">
+ <input
+ type={inputType}
+ className={cn(
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
+ showPasswordToggle && "pr-10",
+ className
+ )}
+ ref={ref}
+ value={value}
+ {...props}
+ />
+ {showPasswordToggle && (
+ <Button
+ type="button"
+ variant="ghost"
+ size="icon"
+ onClick={() => onShowPasswordChange?.(!showPassword)}
+ className="absolute right-0 top-0 h-full px-3 text-muted-foreground hover:text-foreground"
+ aria-label={showPassword ? "Hide password" : "Show password"}
+ >
+ {showPassword ? (
+ <Eye className="h-4 w-4" />
+ ) : (
+ <EyeOff className="h-4 w-4" />
+ )}
+ </Button>
+ )}
+ </div>
+ );
+ }
+);
+Input.displayName = "Input";
+
+export { Input };