11import { useState , useRef , useEffect } from "react"
22import { vscode } from "@/utils/vscode"
33import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
4+ import { useClickAway } from "react-use"
45
56interface NewRuleRowProps {
6- isGlobal : boolean // To determine where to create the file
7+ isGlobal : boolean
78}
89
910const NewRuleRow : React . FC < NewRuleRowProps > = ( { isGlobal } ) => {
@@ -12,25 +13,36 @@ const NewRuleRow: React.FC<NewRuleRowProps> = ({ isGlobal }) => {
1213 const inputRef = useRef < HTMLInputElement > ( null )
1314 const [ error , setError ] = useState < string | null > ( null )
1415
16+ const componentRef = useRef < HTMLDivElement > ( null )
17+
1518 // Focus the input when expanded
1619 useEffect ( ( ) => {
1720 if ( isExpanded && inputRef . current ) {
1821 inputRef . current . focus ( )
1922 }
2023 } , [ isExpanded ] )
2124
25+ useClickAway ( componentRef , ( ) => {
26+ if ( isExpanded ) {
27+ setIsExpanded ( false )
28+ setFilename ( "" )
29+ setError ( null )
30+ }
31+ } )
32+
2233 const getExtension = ( filename : string ) : string => {
2334 if ( filename . startsWith ( "." ) && ! filename . includes ( "." , 1 ) ) return ""
2435 const match = filename . match ( / \. [ ^ . ] + $ / )
2536 return match ? match [ 0 ] . toLowerCase ( ) : ""
2637 }
2738
2839 const isValidExtension = ( ext : string ) : boolean => {
29- // Valid if it's empty (no extension) or .md or .txt
3040 return ext === "" || ext === ".md" || ext === ".txt"
3141 }
3242
33- const handleCreateRule = ( ) => {
43+ const handleSubmit = ( e : React . FormEvent < HTMLFormElement > ) => {
44+ e . preventDefault ( )
45+
3446 if ( filename . trim ( ) ) {
3547 const trimmedFilename = filename . trim ( )
3648 const extension = getExtension ( trimmedFilename )
@@ -57,38 +69,30 @@ const NewRuleRow: React.FC<NewRuleRowProps> = ({ isGlobal }) => {
5769 }
5870 }
5971
60- const handleBlur = ( ) => {
61- setIsExpanded ( false )
62- setError ( null )
63- setFilename ( "" )
64- }
65-
6672 const handleKeyDown = ( e : React . KeyboardEvent ) => {
67- if ( e . key === "Enter" ) {
68- handleCreateRule ( )
69- } else if ( e . key === "Escape" ) {
73+ if ( e . key === "Escape" ) {
7074 setIsExpanded ( false )
7175 setFilename ( "" )
7276 }
7377 }
7478
7579 return (
7680 < div
81+ ref = { componentRef }
7782 className = { `mb-2.5 transition-all duration-300 ease-in-out ${ isExpanded ? "opacity-100" : "opacity-70 hover:opacity-100" } ` }
7883 onClick = { ( ) => ! isExpanded && setIsExpanded ( true ) } >
7984 < div
8085 className = { `flex items-center p-2 rounded bg-[var(--vscode-input-background)] transition-all duration-300 ease-in-out h-[18px] ${
8186 isExpanded ? "shadow-sm" : ""
8287 } `} >
8388 { isExpanded ? (
84- < >
89+ < form onSubmit = { handleSubmit } className = "flex flex-1 items-center" >
8590 < input
8691 ref = { inputRef }
8792 type = "text"
8893 placeholder = "rule-name (.md, .txt, or no extension)"
8994 value = { filename }
9095 onChange = { ( e ) => setFilename ( e . target . value ) }
91- onBlur = { handleBlur }
9296 onKeyDown = { handleKeyDown }
9397 className = "flex-1 bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-0 outline-0 rounded focus:outline-none focus:ring-0 focus:border-transparent"
9498 style = { {
@@ -99,14 +103,14 @@ const NewRuleRow: React.FC<NewRuleRowProps> = ({ isGlobal }) => {
99103 < div className = "flex items-center ml-2 space-x-2" >
100104 < VSCodeButton
101105 appearance = "icon"
106+ type = "submit"
102107 aria-label = "Create rule file"
103108 title = "Create rule file"
104- onClick = { handleCreateRule }
105109 style = { { padding : "0px" } } >
106110 < span className = "codicon codicon-add text-[14px]" />
107111 </ VSCodeButton >
108112 </ div >
109- </ >
113+ </ form >
110114 ) : (
111115 < >
112116 < span className = "flex-1 text-[var(--vscode-descriptionForeground)] bg-[var(--vscode-input-background)] italic text-xs" >
0 commit comments