Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui): resolve issue with PasswordInput component reveal icon #70

Merged
merged 2 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/www/public/registry/components/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": [
{
"name": "input.tsx",
"content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { EyeClosedIcon, EyeOpenIcon } from \"@radix-ui/react-icons\";\n\nexport interface InputProps\n extends Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"children\" | \"prefix\" | \"suffix\"\n > {\n \n className?: string;\n \n iclassName?: string;\n \n prefix?: React.ReactNode | string;\n \n suffix?: React.ReactNode | string;\n \n prefixStyling?: boolean;\n \n label?: string;\n \n suffixStyling?: boolean;\n \n error?: string;\n}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n (\n {\n className,\n iclassName,\n prefix,\n suffix,\n prefixStyling = true,\n suffixStyling = true,\n label,\n type,\n error,\n ...props\n },\n ref,\n ) => {\n \n const prefixRef = React.useRef<HTMLDivElement>(null);\n const suffixRef = React.useRef<HTMLDivElement>(null);\n \n const [prefixWidth, setPrefixWidth] = React.useState(0);\n const [suffixWidth, setSuffixWidth] = React.useState(0);\n \n React.useEffect(() => {\n if (prefixRef.current) {\n setPrefixWidth(prefixRef.current.offsetWidth);\n }\n if (suffixRef.current) {\n setSuffixWidth(suffixRef.current.offsetWidth);\n }\n }, [prefix, suffix]);\n\n return (\n <div className={cn(\"relative\", className)}>\n {label && (\n <label\n className={`text-sm ${error ? \"text-[#ff6166]\" : \"text-muted-foreground\"} `}\n htmlFor={props.id}\n >\n {label}\n </label>\n )}\n {prefix && (\n <div\n ref={prefixRef}\n className={cn(\n \"absolute top-0 left-0 h-full flex items-center justify-center pl-2 text-muted-foreground\",\n `${prefixStyling ? \"rounded-l-md\" : \"\"}`,\n )}\n >\n {prefix}\n {prefixStyling && <div className=\"h-[94%] w-px ml-2 bg-border \" />}\n </div>\n )}\n <input\n type={type}\n className={cn(\n \"flex w-full h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-shadow file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:border-primary/75 focus-visible:ring-primary/35 disabled:cursor-not-allowed disabled:opacity-50\",\n iclassName,\n `${error ? \"outline-none ring-2 ring-[#ffe6e6] border-[#ff6166] dark:ring-[#561a1e] focus-visible:dark:ring-primary/35 dark:hover:ring-[#832126] hover:ring-[#f8b9b9]\" : \"\"}`,\n )}\n style={{\n paddingLeft: prefix ? `${prefixWidth + 12}px` : \"0.75rem\",\n paddingRight: suffix ? `${suffixWidth + 12}px` : \"0.75rem\",\n }}\n ref={ref}\n {...props}\n />\n {suffix && (\n <div\n ref={suffixRef}\n className={cn(\n \"absolute top-0 right-0 h-full flex items-center justify-center pr-2 text-muted-foreground\",\n `${suffixStyling ? \"rounded-r-md\" : \"\"}`,\n )}\n >\n {suffixStyling && (\n <div className=\"h-[94%] w-[1px] mr-2 bg-border \" />\n )}\n {suffix}\n </div>\n )}\n {error && (\n <div\n className=\"flex items-center text-sm text-[#ff6166] mt-1\"\n role=\"alert\"\n >\n <svg\n data-testid=\"geist-icon\"\n height=\"16\"\n strokeLinejoin=\"round\"\n viewBox=\"0 0 16 16\"\n width=\"16\"\n style={{ color: \"currentcolor\" }}\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M5.30761 1.5L1.5 5.30761L1.5 10.6924L5.30761 14.5H10.6924L14.5 10.6924V5.30761L10.6924 1.5H5.30761ZM5.10051 0C4.83529 0 4.58094 0.105357 4.3934 0.292893L0.292893 4.3934C0.105357 4.58094 0 4.83529 0 5.10051V10.8995C0 11.1647 0.105357 11.4191 0.292894 11.6066L4.3934 15.7071C4.58094 15.8946 4.83529 16 5.10051 16H10.8995C11.1647 16 11.4191 15.8946 11.6066 15.7071L15.7071 11.6066C15.8946 11.4191 16 11.1647 16 10.8995V5.10051C16 4.83529 15.8946 4.58093 15.7071 4.3934L11.6066 0.292893C11.4191 0.105357 11.1647 0 10.8995 0H5.10051ZM8.75 3.75V4.5V8L8.75 8.75H7.25V8V4.5V3.75H8.75ZM8 12C8.55229 12 9 11.5523 9 11C9 10.4477 8.55229 10 8 10C7.44772 10 7 10.4477 7 11C7 11.5523 7.44772 12 8 12Z\"\n fill=\"currentColor\"\n ></path>\n </svg>\n <label className=\"ml-1\" htmlFor=\"error\">\n {error}\n </label>\n </div>\n )}\n </div>\n );\n },\n);\n\nInput.displayName = \"Input\";\n\nexport interface SearchInputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"children\"> {\n \n enablePrefixStyling?: boolean;\n}\n\nconst SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(\n ({ enablePrefixStyling = false, ...props }, ref) => {\n return (\n <Input\n type=\"search\"\n prefix={\n <svg\n width=\"15\"\n height=\"15\"\n viewBox=\"0 0 15 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10 6.5C10 8.433 8.433 10 6.5 10C4.567 10 3 8.433 3 6.5C3 4.567 4.567 3 6.5 3C8.433 3 10 4.567 10 6.5ZM9.30884 10.0159C8.53901 10.6318 7.56251 11 6.5 11C4.01472 11 2 8.98528 2 6.5C2 4.01472 4.01472 2 6.5 2C8.98528 2 11 4.01472 11 6.5C11 7.56251 10.6318 8.53901 10.0159 9.30884L12.8536 12.1464C13.0488 12.3417 13.0488 12.6583 12.8536 12.8536C12.6583 13.0488 12.3417 13.0488 12.1464 12.8536L9.30884 10.0159Z\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n ></path>\n </svg>\n }\n prefixStyling={enablePrefixStyling}\n className={cn(\"rounded-full\", props.className)}\n ref={ref}\n {...props}\n />\n );\n },\n);\n\nSearchInput.displayName = \"SearchInput\";\n\nconst PasswordInput = React.forwardRef<\n HTMLInputElement,\n Omit<InputProps, \"label\" | \"error\">\n>(({ className, ...props }, ref) => {\n const [showPassword, setShowPassword] = React.useState(false);\n\n return (\n <div className=\"relative\">\n <Input\n type={showPassword ? \"text\" : \"password\"}\n className={cn(\"hide-password-toggle\", className)}\n ref={ref}\n {...props}\n />\n <button\n type=\"button\"\n className={\n \"absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent\"\n }\n onClick={() => setShowPassword((prev) => !prev)}\n disabled={props.disabled}\n >\n {showPassword ? (\n <EyeOpenIcon className=\"h-4 w-4\" aria-hidden=\"true\" />\n ) : (\n <EyeClosedIcon className=\"h-4 w-4\" aria-hidden=\"true\" />\n )}\n <span className=\"sr-only\">\n {showPassword ? \"Hide password\" : \"Show password\"}\n </span>\n </button>\n\n {}\n <style>{`\n\t\t\t\t\t.hide-password-toggle::-ms-reveal,\n\t\t\t\t\t.hide-password-toggle::-ms-clear {\n\t\t\t\t\t\tvisibility: hidden;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\tdisplay: none;\n\t\t\t\t\t}\n\t\t\t\t`}</style>\n </div>\n );\n});\nPasswordInput.displayName = \"PasswordInput\";\n\nexport { Input, SearchInput, PasswordInput };\n"
"content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { EyeClosedIcon, EyeOpenIcon } from \"@radix-ui/react-icons\";\n\nexport interface InputProps\n extends Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"children\" | \"prefix\" | \"suffix\"\n > {\n \n className?: string;\n \n iclassName?: string;\n \n prefix?: React.ReactNode | string;\n \n suffix?: React.ReactNode | string;\n \n prefixStyling?: boolean;\n \n label?: string;\n \n suffixStyling?: boolean;\n \n error?: string;\n}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n (\n {\n className,\n iclassName,\n prefix,\n suffix,\n prefixStyling = true,\n suffixStyling = true,\n label,\n type,\n error,\n ...props\n },\n ref,\n ) => {\n \n const prefixRef = React.useRef<HTMLDivElement>(null);\n const suffixRef = React.useRef<HTMLDivElement>(null);\n \n const [prefixWidth, setPrefixWidth] = React.useState(0);\n const [suffixWidth, setSuffixWidth] = React.useState(0);\n \n React.useEffect(() => {\n if (prefixRef.current) {\n setPrefixWidth(prefixRef.current.offsetWidth);\n }\n if (suffixRef.current) {\n setSuffixWidth(suffixRef.current.offsetWidth);\n }\n }, [prefix, suffix]);\n\n return (\n <div className={cn(\"relative\", className)}>\n {label && (\n <label\n className={`text-sm ${error ? \"text-[#ff6166]\" : \"text-muted-foreground\"} `}\n htmlFor={props.id}\n >\n {label}\n </label>\n )}\n {prefix && (\n <div\n ref={prefixRef}\n className={cn(\n \"absolute top-0 left-0 h-full flex items-center justify-center pl-2 text-muted-foreground\",\n `${prefixStyling ? \"rounded-l-md\" : \"\"}`,\n )}\n >\n {prefix}\n {prefixStyling && <div className=\"h-[94%] w-px ml-2 bg-border \" />}\n </div>\n )}\n <input\n type={type}\n className={cn(\n \"flex w-full h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-shadow file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:border-primary/75 focus-visible:ring-primary/35 disabled:cursor-not-allowed disabled:opacity-50\",\n iclassName,\n `${error ? \"outline-none ring-2 ring-[#ffe6e6] border-[#ff6166] dark:ring-[#561a1e] focus-visible:dark:ring-primary/35 dark:hover:ring-[#832126] hover:ring-[#f8b9b9]\" : \"\"}`,\n )}\n style={{\n paddingLeft: prefix ? `${prefixWidth + 12}px` : \"0.75rem\",\n paddingRight: suffix ? `${suffixWidth + 12}px` : \"0.75rem\",\n }}\n ref={ref}\n {...props}\n />\n {suffix && (\n <div\n ref={suffixRef}\n className={cn(\n \"absolute top-0 right-0 h-full flex items-center justify-center pr-2 text-muted-foreground\",\n `${suffixStyling ? \"rounded-r-md\" : \"\"}`,\n )}\n >\n {suffixStyling && (\n <div className=\"h-[94%] w-[1px] mr-2 bg-border \" />\n )}\n {suffix}\n </div>\n )}\n {error && (\n <div\n className=\"flex items-center text-sm text-[#ff6166] mt-1\"\n role=\"alert\"\n >\n <svg\n data-testid=\"geist-icon\"\n height=\"16\"\n strokeLinejoin=\"round\"\n viewBox=\"0 0 16 16\"\n width=\"16\"\n style={{ color: \"currentcolor\" }}\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M5.30761 1.5L1.5 5.30761L1.5 10.6924L5.30761 14.5H10.6924L14.5 10.6924V5.30761L10.6924 1.5H5.30761ZM5.10051 0C4.83529 0 4.58094 0.105357 4.3934 0.292893L0.292893 4.3934C0.105357 4.58094 0 4.83529 0 5.10051V10.8995C0 11.1647 0.105357 11.4191 0.292894 11.6066L4.3934 15.7071C4.58094 15.8946 4.83529 16 5.10051 16H10.8995C11.1647 16 11.4191 15.8946 11.6066 15.7071L15.7071 11.6066C15.8946 11.4191 16 11.1647 16 10.8995V5.10051C16 4.83529 15.8946 4.58093 15.7071 4.3934L11.6066 0.292893C11.4191 0.105357 11.1647 0 10.8995 0H5.10051ZM8.75 3.75V4.5V8L8.75 8.75H7.25V8V4.5V3.75H8.75ZM8 12C8.55229 12 9 11.5523 9 11C9 10.4477 8.55229 10 8 10C7.44772 10 7 10.4477 7 11C7 11.5523 7.44772 12 8 12Z\"\n fill=\"currentColor\"\n ></path>\n </svg>\n <label className=\"ml-1\" htmlFor=\"error\">\n {error}\n </label>\n </div>\n )}\n </div>\n );\n },\n);\n\nInput.displayName = \"Input\";\n\nexport interface SearchInputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"children\"> {\n \n enablePrefixStyling?: boolean;\n}\n\nconst SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(\n ({ enablePrefixStyling = false, ...props }, ref) => {\n return (\n <Input\n type=\"search\"\n prefix={\n <svg\n width=\"15\"\n height=\"15\"\n viewBox=\"0 0 15 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10 6.5C10 8.433 8.433 10 6.5 10C4.567 10 3 8.433 3 6.5C3 4.567 4.567 3 6.5 3C8.433 3 10 4.567 10 6.5ZM9.30884 10.0159C8.53901 10.6318 7.56251 11 6.5 11C4.01472 11 2 8.98528 2 6.5C2 4.01472 4.01472 2 6.5 2C8.98528 2 11 4.01472 11 6.5C11 7.56251 10.6318 8.53901 10.0159 9.30884L12.8536 12.1464C13.0488 12.3417 13.0488 12.6583 12.8536 12.8536C12.6583 13.0488 12.3417 13.0488 12.1464 12.8536L9.30884 10.0159Z\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n ></path>\n </svg>\n }\n prefixStyling={enablePrefixStyling}\n className={cn(\"rounded-full\", props.className)}\n ref={ref}\n {...props}\n />\n );\n },\n);\n\nSearchInput.displayName = \"SearchInput\";\n\nconst PasswordInput = React.forwardRef<\n HTMLInputElement,\n Omit<InputProps, \"label\" | \"error\">\n>(({ className, ...props }, ref) => {\n const [showPassword, setShowPassword] = React.useState(false);\n\n return (\n <div className=\"relative\">\n <Input\n type={showPassword ? \"text\" : \"password\"}\n iclassName=\"hide-password-toggle\"\n className={className}\n ref={ref}\n {...props}\n />\n <button\n type=\"button\"\n className={\n \"absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent\"\n }\n onClick={() => setShowPassword((prev) => !prev)}\n disabled={props.disabled}\n >\n {showPassword ? (\n <EyeOpenIcon className=\"h-4 w-4\" aria-hidden=\"true\" />\n ) : (\n <EyeClosedIcon className=\"h-4 w-4\" aria-hidden=\"true\" />\n )}\n <span className=\"sr-only\">\n {showPassword ? \"Hide password\" : \"Show password\"}\n </span>\n </button>\n\n {}\n <style>{`\n\t\t\t\t\t.hide-password-toggle::-ms-reveal,\n\t\t\t\t\t.hide-password-toggle::-ms-clear {\n\t\t\t\t\t\tvisibility: hidden;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\tdisplay: none;\n\t\t\t\t\t}\n\t\t\t\t`}</style>\n </div>\n );\n});\nPasswordInput.displayName = \"PasswordInput\";\n\nexport { Input, SearchInput, PasswordInput };\n"
}
],
"type": "components:ui"
Expand Down
3 changes: 2 additions & 1 deletion packages/ui/src/components/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ const PasswordInput = React.forwardRef<
<div className="relative">
<Input
type={showPassword ? "text" : "password"}
className={cn("hide-password-toggle", className)}
iclassName="hide-password-toggle"
className={className}
ref={ref}
{...props}
/>
Expand Down
Loading