@@ -3,109 +3,155 @@ import { Splitter } from "antd";
33import  styled  from  "styled-components" ; 
44import  {  DispatchType ,  RecordConstructorToView ,  wrapDispatch  }  from  "lowcoder-core" ; 
55import  {  CompAction ,  CompActionTypes ,  deleteCompAction ,  wrapChildAction  }  from  "lowcoder-core" ; 
6- import  {  ColumnOptionControl  }  from  "comps/controls/optionsControl" ; 
7- import  {  NumberControl  }  from  "comps/controls/codeControl" ; 
6+ import  {  SplitColumnOptionControl  }  from  "comps/controls/optionsControl" ; 
7+ import  {  NumberControl ,   StringControl  }  from  "comps/controls/codeControl" ; 
88import  {  BoolControl  }  from  "comps/controls/boolControl" ; 
9+ import  {  dropdownControl  }  from  "comps/controls/dropdownControl" ; 
910import  {  styleControl  }  from  "comps/controls/styleControl" ; 
10- import  {  SplitLayoutColStyle ,  SplitLayoutColStyleType ,  AnimationStyle  }  from  "comps/controls/styleControlConstants" ; 
11+ import  {  SplitLayoutColStyle ,  SplitLayoutRowStyle ,   SplitLayoutRowStyleType ,   SplitLayoutColStyleType ,  AnimationStyle ,   heightCalculator  }  from  "comps/controls/styleControlConstants" ; 
1112import  {  sameTypeMap ,  UICompBuilder ,  withDefault  }  from  "comps/generators" ; 
1213import  {  addMapChildAction  }  from  "comps/generators/sameTypeMap" ; 
1314import  {  BackgroundColorContext  }  from  "comps/utils/backgroundColorContext" ; 
14- import  {  Section ,  sectionNames   }  from  "lowcoder-design" ; 
15+ import  {  Section ,  sectionNames }  from  "lowcoder-design" ; 
1516import  {  trans  }  from  "i18n" ; 
16- import  {  SimpleContainerComp  }  from  "../containerBase/simpleContainerComp" ; 
1717import  {  ContainerBaseProps ,  gridItemCompToGridItems ,  InnerGrid  }  from  "../containerComp/containerView" ; 
18+ import  {  useContext  }  from  "react" ; 
19+ import  {  EditorContext  }  from  "comps/editorState" ; 
20+ 
21+ import  {  disabledPropertyView ,  hiddenPropertyView  }  from  "comps/utils/propertyUtils" ; 
1822import  {  DisabledContext  }  from  "comps/generators/uiCompBuilder" ; 
19- import  {  useScreenInfo  }  from  "../../hooks/screenInfoComp" ; 
23+ import  {  JSONObject ,  JSONValue  }  from  "util/jsonTypes" ; 
24+ import  {  IContainer  }  from  "../containerBase/iContainer" ; 
25+ import  {  SimpleContainerComp  }  from  "../containerBase/simpleContainerComp" ; 
26+ import  {  CompTree ,  mergeCompTrees  }  from  "../containerBase/utils" ; 
27+ import  {  NameGenerator  }  from  "comps/utils" ; 
28+ import  {  AutoHeightControl  }  from  "comps/controls/autoHeightControl" ; 
29+ import  {  messageInstance  }  from  "lowcoder-design/src/components/GlobalInstances" ; 
30+ import  {  NameConfigHidden ,  withExposingConfigs  }  from  "comps/generators/withExposing" ; 
31+ import  SliderControl  from  "@lowcoder-ee/comps/controls/sliderControl" ; 
32+ import  {  getBackgroundStyle  }  from  "@lowcoder-ee/util/styleUtils" ; 
33+ import  _  from  "lodash" ; 
2034
21- const  SplitPanelWrapper  =  styled ( Splitter . Panel ) < {  $collapsible : boolean  } > ` 
22-   flex-grow: 1; 
23-   ${ ( props )  =>  props . $collapsible  &&  `min-width: 50px;` }  
35+ import  {  
36+   HorizontalIcon , 
37+   VerticalIcon , 
38+ }  from  "lowcoder-design/src/icons" ; 
39+ import  {  BackgroundColor  }  from  "@lowcoder-ee/constants/style" ; 
40+ 
41+ const  SplitPanelWrapper  =  styled ( Splitter . Panel ) < {  } > ` 
2442` ; 
2543
26- export  interface  SplitterLayoutTypes  { 
27-   orientation : "horizontal"  |  "vertical" ; 
28- } 
44+ const  SplitterWrapper  =  styled . div < {  $style : SplitLayoutRowStyleType  } > ` 
45+   border-radius: ${ ( props )  =>  props . $style ?. radius  ||  "0px" }  ; 
46+   border-width: ${ ( props )  =>  props . $style ?. borderWidth  ||  "0px" }  ; 
47+   border-color: ${ ( props )  =>  props . $style ?. border  ||  "transparent" }  ; 
48+   border-style: ${ ( props )  =>  props . $style ?. borderStyle  ||  "solid" }  ; 
49+   margin: ${ ( props )  =>  props . $style ?. margin  ||  "0px" }  ; 
50+   padding: ${ ( props )  =>  props . $style ?. padding  ||  "0px" }  ; 
51+   ${ ( props )  =>  ( props . $style  ? getBackgroundStyle ( props . $style )  : "" ) }  
52+ ` ; 
2953
30- /*  
54+ const  OrientationOptions  =  [ 
55+   { 
56+     label : < HorizontalIcon  /> , 
57+     value : "horizontal" , 
58+   } , 
59+   { 
60+     label : < VerticalIcon  /> , 
61+     value : "vertical" , 
62+   } , 
63+ ]  as  const ; 
3164
3265const  childrenMap  =  { 
3366  disabled : BoolControl , 
34-   columns: ColumnOptionControl , 
67+   columns : SplitColumnOptionControl , 
3568  containers : withDefault ( sameTypeMap ( SimpleContainerComp ) ,  { 
3669    0 : {  view : { } ,  layout : { }  } , 
3770    1 : {  view : { } ,  layout : { }  } , 
3871  } ) , 
39-   collapsiblePanels: BoolControl, 
40-   orientation: withDefault(ColumnOptionControl, "horizontal"), 
41-   panelCount: withDefault(NumberControl, 2), 
72+   autoHeight : AutoHeightControl , 
73+   horizontalGridCells : SliderControl , 
74+   verticalGridCells : SliderControl , 
75+   orientation : dropdownControl ( OrientationOptions ,  "horizontal" ) , 
76+   matchColumnsHeight : withDefault ( BoolControl ,  true ) , 
4277  columnStyle : styleControl ( SplitLayoutColStyle ,  "columnStyle" ) , 
78+   bodyStyle : styleControl ( SplitLayoutRowStyle ,  'bodyStyle' ) , 
4379  animationStyle : styleControl ( AnimationStyle ,  "animationStyle" ) , 
80+   mainScrollbar : withDefault ( BoolControl ,  false ) , 
4481} ; 
4582
4683type  ViewProps  =  RecordConstructorToView < typeof  childrenMap > ; 
4784type  SplitLayoutProps  =  ViewProps  &  {  dispatch : DispatchType  } ; 
85+ 
4886type  ColumnContainerProps  =  Omit < ContainerBaseProps ,  "style" >  &  { 
4987  style : SplitLayoutColStyleType ; 
88+   matchColumnsHeight : boolean ; 
89+   backgroundColor : string ; 
90+   backgroundImage : string ; 
91+   padding : string ; 
92+   orientation : string ; 
93+   margin : string ; 
5094} ; 
5195
5296const  ColumnContainer  =  ( props : ColumnContainerProps )  =>  { 
5397  return  ( 
5498    < InnerGrid 
5599      { ...props } 
56-       emptyRows={15} 
57100      radius = { props . style . radius } 
58-       style={props.style} 
101+       bgColor = { props . backgroundColor } 
102+       style = { { 
103+         ...props . style , 
104+         height : props . orientation  ===  "horizontal" 
105+           ? ( props . matchColumnsHeight  ? heightCalculator ( props . margin )  : "auto" ) 
106+           : ( props . autoHeight  ? "100%"  : "auto" ) , 
107+       } } 
59108    /> 
60109  ) ; 
61110} ; 
62111
63112const  SplitLayout  =  ( props : SplitLayoutProps )  =>  { 
64-   const screenInfo = useScreenInfo(); 
65-   const containerRef = useRef<HTMLDivElement | null>(null); 
66-   const [componentWidth, setComponentWidth] = useState<number | null>(null); 
67- 
68-   let { columns, containers, dispatch, collapsiblePanels, orientation, panelCount, columnStyle } = props; 
69- 
70-   useEffect(() => { 
71-     if (!containerRef.current) return; 
72-     const resizeObserver = new ResizeObserver((entries) => { 
73-       for (let entry of entries) { 
74-         setComponentWidth(entry.contentRect.width); 
75-       } 
76-     }); 
77- 
78-     resizeObserver.observe(containerRef.current); 
79-     return () => resizeObserver.disconnect(); 
80-   }, []); 
81113
82114  return  ( 
83-     <BackgroundColorContext.Provider value={props.style? .background}> 
115+     < BackgroundColorContext . Provider  value = { props . columnStyle . background } > 
84116      < DisabledContext . Provider  value = { props . disabled } > 
85-         <div ref={containerRef} style={{ height: "100%" }}> 
86-           <Splitter layout={orientation}> 
87-             {Array.from({ length: panelCount }, (_, index) => { 
88-               const id = String(index); 
89-               const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id); 
90-               if (!containers[id]) return null; 
91-               const containerProps = containers[id].children; 
92- 
117+         < SplitterWrapper  $style = { props . bodyStyle } > 
118+           < Splitter  style = { {  overflow : props . mainScrollbar  ? "auto"  : "hidden" } }  layout = { props . orientation } > 
119+             { props . columns . map ( ( col ,  index )  =>  { 
120+               const  id  =  String ( col . id ) ; 
121+               const  childDispatch  =  wrapDispatch ( wrapDispatch ( props . dispatch ,  "containers" ) ,  id ) ; 
122+               const  containerProps  =  props . containers [ id ] ?. children ; 
93123              return  ( 
94-                 <SplitPanelWrapper key={id} $collapsible={collapsiblePanels}> 
124+                 < SplitPanelWrapper  
125+                   key = { id }  
126+                   collapsible = { col . collapsible } 
127+                   { ...( col . minWidth  !==  undefined  ? {  min : col . minWidth  }  : { } ) } 
128+                   { ...( col . maxWidth  !==  undefined  ? {  max : col . maxWidth  }  : { } ) } 
129+                   { ...( col . width  !==  undefined  ? {  defaultSize : col . width  }  : { } ) } 
130+                   > 
95131                  < ColumnContainer 
96132                    layout = { containerProps . layout . getView ( ) } 
97133                    items = { gridItemCompToGridItems ( containerProps . items . getView ( ) ) } 
98134                    positionParams = { containerProps . positionParams . getView ( ) } 
99135                    dispatch = { childDispatch } 
100-                     style={columnStyle} 
136+                     style = { props . columnStyle } 
137+                     backgroundColor = { col . backgroundColor } 
138+                     backgroundImage = { col . backgroundImage } 
139+                     padding = { col . padding } 
140+                     autoHeight = { props . autoHeight } 
141+                     horizontalGridCells = { props . horizontalGridCells } 
142+                     emptyRows = { props . verticalGridCells } 
143+                     matchColumnsHeight = { props . matchColumnsHeight } 
144+                     orientation = { props . orientation } 
145+                     margin = { props . columnStyle . margin } 
101146                  /> 
102147                </ SplitPanelWrapper > 
103148              ) ; 
104149            } ) } 
105150          </ Splitter > 
106-         </div > 
151+         </ SplitterWrapper > 
107152      </ DisabledContext . Provider > 
108153    </ BackgroundColorContext . Provider > 
154+ 
109155  ) ; 
110156} ; 
111157
@@ -116,27 +162,151 @@ export const SplitLayoutBaseComp = (function () {
116162        < Section  name = { sectionNames . basic } > 
117163          { children . columns . propertyView ( {  title : trans ( "splitLayout.column" )  } ) } 
118164        </ Section > 
119-         <Section name={sectionNames.layout}> 
120-           {children.panelCount.propertyView({ label: trans("splitLayout.panelCount") }) } 
121-           {children.collapsiblePanels.propertyView({ label: trans("splitLayout.collapsiblePanels") }) } 
122-           {children.orientation.propertyView({ label: trans("splitLayout.orientation") }) } 
123-         </Section> 
124-         <Section name={sectionNames.style}> 
125-           {children.columnStyle.getPropertyView()} 
126-           {children.animationStyle.getPropertyView()} 
127-         </Section> 
165+ 
166+         { ( useContext ( EditorContext ) . editorModeStatus  ===  "logic"  ||  useContext ( EditorContext ) . editorModeStatus  ===  "both" )  &&  ( 
167+             < Section  name = { sectionNames . interaction } > 
168+               { disabledPropertyView ( children ) } 
169+               { hiddenPropertyView ( children ) } 
170+             </ Section > 
171+           ) } 
172+         { [ "layout" ,  "both" ] . includes ( useContext ( EditorContext ) . editorModeStatus )  &&  ( 
173+           < > 
174+             < Section  name = { sectionNames . layout } > 
175+               { children . orientation . propertyView ( { 
176+                 label : trans ( "splitLayout.orientation" ) , 
177+                 radioButton : true , 
178+                 tooltip : trans ( "splitLayout.orientationTooltip" ) , 
179+               } ) } 
180+               { children . autoHeight . getPropertyView ( ) } 
181+               { ( ! children . autoHeight . getView ( ) )  &&  children . mainScrollbar . propertyView ( { 
182+                 label : trans ( "prop.mainScrollbar" ) 
183+               } ) } 
184+               { ( children . orientation . getView ( )  ==  "horizontal" )  &&  
185+                 children . matchColumnsHeight . propertyView ( {  label : trans ( "splitLayout.matchColumnsHeight" )  } 
186+               ) } 
187+               { children . horizontalGridCells . propertyView ( { 
188+                 label : trans ( 'prop.horizontalGridCells' ) , 
189+               } ) } 
190+               { children . verticalGridCells . propertyView ( { 
191+                 label : trans ( 'prop.verticalGridCells' ) , 
192+               } ) } 
193+             </ Section > 
194+             < Section  name = { sectionNames . bodyStyle } >  
195+               { children . bodyStyle . getPropertyView ( ) } 
196+             </ Section > 
197+             < Section  name = { sectionNames . detailStyle } >  
198+               { children . columnStyle . getPropertyView ( ) } 
199+             </ Section > 
200+             < Section  name = { sectionNames . animationStyle }  hasTooltip = { true } > 
201+               { children . animationStyle . getPropertyView ( ) } 
202+             </ Section > 
203+           </ > 
204+         ) } 
128205      </ > 
129206    ) ) 
130207    . build ( ) ; 
131208} ) ( ) ; 
132209
133- class SplitLayoutImplComp extends SplitLayoutBaseComp { 
210+ class  SplitLayoutImplComp  extends  SplitLayoutBaseComp  implements  IContainer  { 
211+   private  syncContainers ( ) : this { 
212+     const  columns  =  this . children . columns . getView ( ) ; 
213+     const  ids : Set < string >  =  new  Set ( columns . map ( ( column )  =>  String ( column . id ) ) ) ; 
214+     let  containers  =  this . children . containers . getView ( ) ; 
215+     // delete 
216+     const  actions : CompAction [ ]  =  [ ] ; 
217+     Object . keys ( containers ) . forEach ( ( id )  =>  { 
218+       if  ( ! ids . has ( id ) )  { 
219+         // log.debug("syncContainers delete. ids=", ids, " id=", id); 
220+         actions . push ( wrapChildAction ( "containers" ,  wrapChildAction ( id ,  deleteCompAction ( ) ) ) ) ; 
221+       } 
222+     } ) ; 
223+     // new 
224+     ids . forEach ( ( id )  =>  { 
225+       if  ( ! containers . hasOwnProperty ( id ) )  { 
226+         // log.debug("syncContainers new containers: ", containers, " id: ", id); 
227+         actions . push ( 
228+           wrapChildAction ( "containers" ,  addMapChildAction ( id ,  {  layout : { } ,  items : { }  } ) ) 
229+         ) ; 
230+       } 
231+     } ) ; 
232+     // log.debug("syncContainers. actions: ", actions); 
233+     let  instance  =  this ; 
234+     actions . forEach ( ( action )  =>  { 
235+       instance  =  instance . reduce ( action ) ; 
236+     } ) ; 
237+     return  instance ; 
238+   } 
239+ 
134240  override  reduce ( action : CompAction ) : this { 
241+     const  columns  =  this . children . columns . getView ( ) ; 
242+     if  ( action . type  ===  CompActionTypes . CUSTOM )  { 
243+       const  value  =  action . value  as  JSONObject ; 
244+       if  ( value . type  ===  "push" )  { 
245+         const  itemValue  =  value . value  as  JSONObject ; 
246+         if  ( _ . isEmpty ( itemValue . key ) )  itemValue . key  =  itemValue . label ; 
247+         action  =  { 
248+           ...action , 
249+           value : { 
250+             ...value , 
251+             value : {  ...itemValue  } , 
252+           } , 
253+         }  as  CompAction ; 
254+       } 
255+       const  {  path }  =  action ; 
256+       if  ( value . type  ===  "delete"  &&  path [ 0 ]  ===  'columns'  &&  columns . length  <=  1 )  { 
257+         messageInstance . warning ( trans ( "responsiveLayout.atLeastOneColumnError" ) ) ; 
258+         // at least one column 
259+         return  this ; 
260+       } 
261+     } 
262+     // log.debug("before super reduce. action: ", action); 
135263    let  newInstance  =  super . reduce ( action ) ; 
264+     if  ( action . type  ===  CompActionTypes . UPDATE_NODES_V2 )  { 
265+       // Need eval to get the value in StringControl 
266+       newInstance  =  newInstance . syncContainers ( ) ; 
267+     } 
268+     // log.debug("reduce. instance: ", this, " newInstance: ", newInstance); 
136269    return  newInstance ; 
137270  } 
138- } 
139271
140- */ 
272+   realSimpleContainer ( key ?: string ) : SimpleContainerComp  |  undefined  { 
273+     return  Object . values ( this . children . containers . children ) . find ( ( container )  => 
274+       container . realSimpleContainer ( key ) 
275+     ) ; 
276+   } 
277+ 
278+   getCompTree ( ) : CompTree  { 
279+     const  containerMap  =  this . children . containers . getView ( ) ; 
280+     const  compTrees  =  Object . values ( containerMap ) . map ( ( container )  =>  container . getCompTree ( ) ) ; 
281+     return  mergeCompTrees ( compTrees ) ; 
282+   } 
283+ 
284+   findContainer ( key : string ) : IContainer  |  undefined  { 
285+     const  containerMap  =  this . children . containers . getView ( ) ; 
286+     for  ( const  container  of  Object . values ( containerMap ) )  { 
287+       const  foundContainer  =  container . findContainer ( key ) ; 
288+       if  ( foundContainer )  { 
289+         return  foundContainer  ===  container  ? this  : foundContainer ; 
290+       } 
291+     } 
292+     return  undefined ; 
293+   } 
294+ 
295+   getPasteValue ( nameGenerator : NameGenerator ) : JSONValue  { 
296+     const  containerMap  =  this . children . containers . getView ( ) ; 
297+     const  containerPasteValueMap  =  _ . mapValues ( containerMap ,  ( container )  => 
298+       container . getPasteValue ( nameGenerator ) 
299+     ) ; 
300+ 
301+     return  {  ...this . toJsonValue ( ) ,  containers : containerPasteValueMap  } ; 
302+   } 
303+ 
304+   override  autoHeight ( ) : boolean  { 
305+     return  this . children . autoHeight . getView ( ) ; 
306+   } 
307+ } 
141308
142- export  const  SplitLayoutComp  =  null ; 
309+ export  const  SplitLayoutComp  =  withExposingConfigs ( 
310+   SplitLayoutImplComp , 
311+   [  NameConfigHidden ] 
312+ ) ; 
0 commit comments