@@ -14,7 +14,7 @@ import { Layers } from "constants/Layers";
14
14
import { HintPlaceHolder , Modal , Section , sectionNames } from "lowcoder-design" ;
15
15
import { trans } from "i18n" ;
16
16
import { changeChildAction } from "lowcoder-core" ;
17
- import { CSSProperties , useCallback } from "react" ;
17
+ import { CSSProperties , useCallback , useMemo , useRef } from "react" ;
18
18
import { ResizeHandle } from "react-resizable" ;
19
19
import styled , { css } from "styled-components" ;
20
20
import { useUserViewMode } from "util/hooks" ;
@@ -116,19 +116,36 @@ let TmpModalComp = (function () {
116
116
( props , dispatch ) => {
117
117
const userViewMode = useUserViewMode ( ) ;
118
118
const appID = useApplicationId ( ) ;
119
- const bodyStyle : CSSProperties = { padding : 0 } ;
120
- const width = transToPxSize ( props . width || DEFAULT_WIDTH ) ;
121
- let height = undefined ;
122
- let resizeHandles : ResizeHandle [ ] = [ "w" , "e" ] ;
123
- if ( ! props . autoHeight ) {
124
- height = transToPxSize ( props . height || DEFAULT_HEIGHT ) ;
125
- resizeHandles . push ( "s" ) ;
126
- bodyStyle . overflow = "hidden auto" ;
127
- }
128
- if ( userViewMode ) {
129
- resizeHandles = [ ] ;
130
- }
131
- const { items, ...otherContainerProps } = props . container ;
119
+ const containerRef = useRef < HTMLElement | null > ( null ) ;
120
+
121
+ // Memoize body style
122
+ const bodyStyle = useMemo < CSSProperties > ( ( ) => ( {
123
+ padding : 0 ,
124
+ overflow : props . autoHeight ? undefined : "hidden auto"
125
+ } ) , [ props . autoHeight ] ) ;
126
+
127
+ // Memoize width and height
128
+ const width = useMemo ( ( ) =>
129
+ transToPxSize ( props . width || DEFAULT_WIDTH ) ,
130
+ [ props . width ]
131
+ ) ;
132
+
133
+ const height = useMemo ( ( ) =>
134
+ ! props . autoHeight ? transToPxSize ( props . height || DEFAULT_HEIGHT ) : undefined ,
135
+ [ props . autoHeight , props . height ]
136
+ ) ;
137
+
138
+ // Memoize resize handles
139
+ const resizeHandles = useMemo < ResizeHandle [ ] > ( ( ) => {
140
+ if ( userViewMode ) return [ ] ;
141
+ const handles : ResizeHandle [ ] = [ "w" , "e" ] ;
142
+ if ( ! props . autoHeight ) {
143
+ handles . push ( "s" ) ;
144
+ }
145
+ return handles ;
146
+ } , [ userViewMode , props . autoHeight ] ) ;
147
+
148
+ // Memoize resize handler
132
149
const onResizeStop = useCallback (
133
150
(
134
151
e : React . SyntheticEvent ,
@@ -144,13 +161,48 @@ let TmpModalComp = (function () {
144
161
} ,
145
162
[ dispatch ]
146
163
) ;
147
- let paddingValues = [ 10 , 10 ] ;
148
- if ( props . style . padding != undefined ) {
164
+
165
+ // Memoize padding values
166
+ const paddingValues = useMemo ( ( ) => {
167
+ if ( ! props . style . padding ) return [ 10 , 10 ] ;
149
168
const extractedValues = extractMarginValues ( props . style ) ;
150
- if ( extractedValues !== null ) {
151
- paddingValues = extractedValues ;
152
- }
153
- }
169
+ return extractedValues || [ 10 , 10 ] ;
170
+ } , [ props . style . padding ] ) ;
171
+
172
+ // Memoize container getter
173
+ const getContainer = useCallback ( ( ) => {
174
+ if ( ! containerRef . current ) {
175
+ containerRef . current = document . querySelector ( `#${ CanvasContainerID } ` ) || document . body ;
176
+ }
177
+ return containerRef . current ;
178
+ } , [ ] ) ;
179
+
180
+ // Memoize event handlers
181
+ const handleCancel = useCallback ( ( e : React . MouseEvent ) => {
182
+ if ( props . toggleClose ) {
183
+ props . visible . onChange ( false ) ;
184
+ }
185
+ } , [ props . toggleClose , props . visible ] ) ;
186
+
187
+ const handleAfterClose = useCallback ( ( ) => {
188
+ if ( props . toggleClose ) {
189
+ props . onEvent ( "close" ) ;
190
+ }
191
+ } , [ props . toggleClose , props . onEvent ] ) ;
192
+
193
+ const handleAfterOpenChange = useCallback ( ( open : boolean ) => {
194
+ if ( open ) {
195
+ props . onEvent ( "open" ) ;
196
+ }
197
+ } , [ props . onEvent ] ) ;
198
+
199
+ // Memoize modal render function
200
+ const modalRender = useCallback ( ( node : React . ReactNode ) => (
201
+ < ModalStyled $style = { props . style } $modalScrollbar = { props . modalScrollbar } >
202
+ { node }
203
+ </ ModalStyled >
204
+ ) , [ props . style , props . modalScrollbar ] ) ;
205
+
154
206
return (
155
207
< BackgroundColorContext . Provider value = { props . style . background } >
156
208
< ModalWrapper >
@@ -162,30 +214,24 @@ let TmpModalComp = (function () {
162
214
open = { props . visible . value }
163
215
maskClosable = { props . maskClosable }
164
216
focusTriggerAfterClose = { false }
165
- getContainer = { ( ) => document . querySelector ( `# ${ CanvasContainerID } ` ) || document . body }
217
+ getContainer = { getContainer }
166
218
footer = { null }
167
219
styles = { { body : bodyStyle } }
168
220
title = { props . title }
169
221
$titleAlign = { props . titleAlign }
170
222
width = { width }
171
- onCancel = { ( e ) => {
172
- props . toggleClose && props . visible . onChange ( false ) ;
173
- } }
174
- afterClose = { ( ) => {
175
- props . toggleClose && props . onEvent ( "close" ) ;
176
- } }
177
- afterOpenChange = { ( open : boolean ) => {
178
- if ( open ) props . onEvent ( "open" ) ;
179
- } }
223
+ onCancel = { handleCancel }
224
+ afterClose = { handleAfterClose }
225
+ afterOpenChange = { handleAfterOpenChange }
180
226
zIndex = { Layers . modal }
181
- modalRender = { ( node ) => < ModalStyled $style = { props . style } $modalScrollbar = { props . modalScrollbar } > { node } </ ModalStyled > }
227
+ modalRender = { modalRender }
182
228
mask = { props . showMask }
183
229
className = { clsx ( `app-${ appID } ` , props . className ) }
184
230
data-testid = { props . dataTestId as string }
185
231
>
186
232
< InnerGrid
187
- { ...otherContainerProps }
188
- items = { gridItemCompToGridItems ( items ) }
233
+ { ...props . container }
234
+ items = { gridItemCompToGridItems ( props . container . items ) }
189
235
horizontalGridCells = { props . horizontalGridCells }
190
236
autoHeight = { props . autoHeight }
191
237
minHeight = { paddingValues ? DEFAULT_HEIGHT - paddingValues [ 0 ] * 2 + "px" : "" }
0 commit comments