1- import { useContext , useEffect , useState } from "react" ;
1+ import React , { useContext , useEffect , useState , useCallback , useMemo } from "react" ;
22import styled from "styled-components" ;
33import { PointIcon , SearchOutlinedIcon } from "lowcoder-design/src/icons" ;
44import type { EditPopoverItemType } from 'lowcoder-design/src/components/popover' ;
@@ -72,89 +72,100 @@ interface Iprops {
7272 search ?: { searchText : string ; setSearchText : ( t : string ) => void } ;
7373}
7474
75- export const CompName = ( props : Iprops ) => {
75+ export const CompName = React . memo ( ( props : Iprops ) => {
7676 const [ error , setError ] = useState < string | undefined > ( undefined ) ;
7777 const [ editing , setEditing ] = useState ( false ) ;
7878 const [ upgrading , setUpgrading ] = useState ( false ) ;
79+ const [ showSearch , setShowSearch ] = useState < boolean > ( false ) ;
80+
7981 const editorState = useContext ( EditorContext ) ;
80- const selectedComp = values ( editorState . selectedComps ( ) ) [ 0 ] ;
81- const compType = selectedComp . children . compType . getView ( ) as UICompType ;
82- const compInfo = parseCompType ( compType ) ;
83- const docUrl = getComponentDocUrl ( compType ) ;
84- const playgroundUrl = getComponentPlaygroundUrl ( compType ) ;
85-
86- const items : EditPopoverItemType [ ] = [ ] ;
87-
88- // Falk: TODO - Implement upgrade for individual Version functionality
89- const handleUpgrade = async ( ) => {
90- if ( upgrading ) {
91- return ;
92- }
82+ const selectedComp = useMemo ( ( ) => values ( editorState . selectedComps ( ) ) [ 0 ] , [ editorState ] ) ;
83+ const compType = useMemo ( ( ) => selectedComp . children . compType . getView ( ) as UICompType , [ selectedComp ] ) ;
84+ const compInfo = useMemo ( ( ) => parseCompType ( compType ) , [ compType ] ) ;
85+ const docUrl = useMemo ( ( ) => getComponentDocUrl ( compType ) , [ compType ] ) ;
86+ const playgroundUrl = useMemo ( ( ) => getComponentPlaygroundUrl ( compType ) , [ compType ] ) ;
87+
88+ // Cleanup on unmount
89+ useEffect ( ( ) => {
90+ return ( ) => {
91+ setError ( undefined ) ;
92+ setEditing ( false ) ;
93+ setUpgrading ( false ) ;
94+ setShowSearch ( false ) ;
95+ } ;
96+ } , [ ] ) ;
97+
98+ // Reset search when name changes
99+ useEffect ( ( ) => {
100+ setShowSearch ( false ) ;
101+ } , [ props . name ] ) ;
102+
103+ const handleUpgrade = useCallback ( async ( ) => {
104+ if ( upgrading ) return ;
93105 setUpgrading ( true ) ;
94- await GridCompOperator . upgradeCurrentComp ( editorState ) ;
95- setUpgrading ( false ) ;
96- } ;
97-
98- if ( docUrl ) {
99- items . push ( {
100- text : trans ( "comp.menuViewDocs" ) ,
101- onClick : ( ) => {
102- window . open ( docUrl , "_blank" ) ;
103- } ,
104- } ) ;
105- }
106+ try {
107+ await GridCompOperator . upgradeCurrentComp ( editorState ) ;
108+ } finally {
109+ setUpgrading ( false ) ;
110+ }
111+ } , [ upgrading , editorState ] ) ;
106112
107- if ( playgroundUrl ) {
108- items . push ( {
109- text : trans ( "comp.menuViewPlayground" ) ,
110- onClick : ( ) => {
111- window . open ( playgroundUrl , "_blank" ) ;
112- } ,
113- } ) ;
114- }
113+ const handleRename = useCallback ( ( value : string ) => {
114+ if ( editorState . rename ( props . name , value ) ) {
115+ editorState . setSelectedCompNames ( new Set ( [ value ] ) ) ;
116+ setError ( undefined ) ;
117+ }
118+ } , [ editorState , props . name ] ) ;
115119
120+ const handleSearchChange = useCallback ( ( e : React . ChangeEvent < HTMLInputElement > ) => {
121+ props . search ?. setSearchText ( e . target . value ) ;
122+ } , [ props . search ] ) ;
116123
117- if ( compInfo . isRemote ) {
118- // Falk: Displaying the current version of the component
119- items . push ( {
120- text : trans ( "history.currentVersion" ) + ": " + compInfo . packageVersion ,
121- onClick : ( ) => {
122- } ,
123- } ) ;
124- // items.push({
125- // text: trans("history.currentVersion") + ": " + compInfo.packageVersion,
126- // onClick: () => {
127-
128- // },
129- // });
130-
131- items . push ( {
132- text : trans ( "comp.menuUpgradeToLatest" ) ,
133- onClick : ( ) => {
134- handleUpgrade ( ) ;
135- } ,
136-
137- } ) ;
138- }
124+ const handleSearchToggle = useCallback ( ( ) => {
125+ setShowSearch ( prev => ! prev ) ;
126+ props . search ?. setSearchText ( "" ) ;
127+ } , [ props . search ] ) ;
139128
140- const [ showSearch , setShowSearch ] = useState < boolean > ( false ) ;
141- const { search } = props ;
142- useEffect ( ( ) => {
143- setShowSearch ( false ) ;
144- } , [ props . name ] ) ;
145- const compName = (
146- < CompDiv $width = { props . width } $hasSearch = { ! ! search } $showSearch = { showSearch } >
129+ const items = useMemo < EditPopoverItemType [ ] > ( ( ) => {
130+ const menuItems : EditPopoverItemType [ ] = [ ] ;
131+
132+ if ( docUrl ) {
133+ menuItems . push ( {
134+ text : trans ( "comp.menuViewDocs" ) ,
135+ onClick : ( ) => window . open ( docUrl , "_blank" ) ,
136+ } ) ;
137+ }
138+
139+ if ( playgroundUrl ) {
140+ menuItems . push ( {
141+ text : trans ( "comp.menuViewPlayground" ) ,
142+ onClick : ( ) => window . open ( playgroundUrl , "_blank" ) ,
143+ } ) ;
144+ }
145+
146+ if ( compInfo . isRemote ) {
147+ menuItems . push ( {
148+ text : trans ( "history.currentVersion" ) + ": " + compInfo . packageVersion ,
149+ onClick : ( ) => { } ,
150+ } ) ;
151+
152+ menuItems . push ( {
153+ text : trans ( "comp.menuUpgradeToLatest" ) ,
154+ onClick : handleUpgrade ,
155+ } ) ;
156+ }
157+
158+ return menuItems ;
159+ } , [ docUrl , playgroundUrl , compInfo , handleUpgrade ] ) ;
160+
161+ const compName = useMemo ( ( ) => (
162+ < CompDiv $width = { props . width } $hasSearch = { ! ! props . search } $showSearch = { showSearch } >
147163 < div >
148164 < EditText
149165 text = { props . name }
150- onFinish = { ( value ) => {
151- if ( editorState . rename ( props . name , value ) ) {
152- editorState . setSelectedCompNames ( new Set ( [ value ] ) ) ;
153- setError ( undefined ) ;
154- }
155- } }
166+ onFinish = { handleRename }
156167 onChange = { ( value ) => setError ( editorState . checkRename ( props . name , value ) ) }
157- onEditStateChange = { ( editing ) => setEditing ( editing ) }
168+ onEditStateChange = { setEditing }
158169 />
159170 < PopupCard
160171 editorFocus = { ! ! error && editing }
@@ -163,16 +174,13 @@ export const CompName = (props: Iprops) => {
163174 hasError = { ! ! error }
164175 />
165176 </ div >
166- { ! ! search && (
177+ { ! ! props . search && (
167178 < SearchIcon
168- onClick = { ( ) => {
169- setShowSearch ( ! showSearch ) ;
170- search ?. setSearchText ( "" ) ;
171- } }
179+ onClick = { handleSearchToggle }
172180 style = { { color : showSearch ? "#315EFB" : "#8B8FA3" } }
173181 />
174182 ) }
175- { compType === "module" ? (
183+ { compType === "module" ? (
176184 < EditPopover
177185 items = { items }
178186 edit = { ( ) => GridCompOperator . editComp ( editorState ) }
@@ -189,19 +197,32 @@ export const CompName = (props: Iprops) => {
189197 </ EditPopover >
190198 ) }
191199 </ CompDiv >
192- ) ;
200+ ) , [
201+ props . width ,
202+ props . search ,
203+ props . name ,
204+ showSearch ,
205+ error ,
206+ editing ,
207+ compType ,
208+ items ,
209+ editorState ,
210+ handleRename ,
211+ handleSearchToggle
212+ ] ) ;
213+
193214 return (
194215 < div >
195216 { compName }
196- { search && showSearch && (
217+ { props . search && showSearch && (
197218 < Search
198219 placeholder = { trans ( "comp.searchProp" ) }
199- value = { search . searchText }
200- onChange = { ( e ) => search . setSearchText ( e . target . value ) }
220+ value = { props . search . searchText }
221+ onChange = { handleSearchChange }
201222 allowClear = { true }
202223 style = { { padding : "0 16px" , margin : "0 0 4px 0" } }
203224 />
204225 ) }
205226 </ div >
206227 ) ;
207- } ;
228+ } ) ;
0 commit comments