Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit26f4dd3

Browse files
Merge pull request#1993 from iamfaran/feat/1949-tabs
[Feat]: TAB Component Different Behaviours
2 parents060a20e +289ee7a commit26f4dd3

File tree

2 files changed

+157
-95
lines changed

2 files changed

+157
-95
lines changed

‎client/packages/lowcoder/src/comps/comps/tabs/tabbedContainerComp.tsx‎

Lines changed: 149 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { NameGenerator } from "comps/utils";
1515
import{ScrollBar,Section,sectionNames}from"lowcoder-design";
1616
import{HintPlaceHolder}from"lowcoder-design";
1717
import_from"lodash";
18-
importReact,{useCallback,useContext,useEffect}from"react";
18+
importReact,{useContext,useMemo}from"react";
1919
importstyled,{css}from"styled-components";
2020
import{IContainer}from"../containerBase/iContainer";
2121
import{SimpleContainerComp}from"../containerBase/simpleContainerComp";
@@ -34,7 +34,7 @@ import { EditorContext } from "comps/editorState";
3434
import{checkIsMobile}from"util/commonUtils";
3535
import{messageInstance}from"lowcoder-design/src/components/GlobalInstances";
3636
import{BoolControl}from"comps/controls/boolControl";
37-
import{PositionControl}from"comps/controls/dropdownControl";
37+
import{PositionControl,dropdownControl}from"comps/controls/dropdownControl";
3838
import{SliderControl}from"@lowcoder-ee/comps/controls/sliderControl";
3939
import{getBackgroundStyle}from"@lowcoder-ee/util/styleUtils";
4040

@@ -46,6 +46,14 @@ const EVENT_OPTIONS = [
4646
},
4747
]asconst;
4848

49+
constTAB_BEHAVIOR_OPTIONS=[
50+
{label:trans("tabbedContainer.tabBehaviorLazy"),value:"lazy"},
51+
{label:trans("tabbedContainer.tabBehaviorKeepAlive"),value:"keep-alive"},
52+
{label:trans("tabbedContainer.tabBehaviorDestroy"),value:"destroy"},
53+
]asconst;
54+
55+
constTabBehaviorControl=dropdownControl(TAB_BEHAVIOR_OPTIONS,"lazy");
56+
4957
constchildrenMap={
5058
tabs:TabsOptionControl,
5159
selectedTabKey:stringExposingStateControl("key","Tab1"),
@@ -61,7 +69,7 @@ const childrenMap = {
6169
onEvent:eventHandlerControl(EVENT_OPTIONS),
6270
disabled:BoolCodeControl,
6371
showHeader:withDefault(BoolControl,true),
64-
destroyInactiveTab:withDefault(BoolControl,false),
72+
tabBehavior:withDefault(TabBehaviorControl,"lazy"),
6573
style:styleControl(TabContainerStyle,'style'),
6674
headerStyle:styleControl(ContainerHeaderStyle,'headerStyle'),
6775
bodyStyle:styleControl(TabBodyStyle,'bodyStyle'),
@@ -72,7 +80,7 @@ const childrenMap = {
7280

7381
typeViewProps=RecordConstructorToView<typeofchildrenMap>;
7482
typeTabbedContainerProps=ViewProps&{dispatch:DispatchType};
75-
83+
7684
constgetStyle=(
7785
style:TabContainerStyleType,
7886
headerStyle:ContainerHeaderStyleType,
@@ -138,13 +146,14 @@ const getStyle = (
138146
`;
139147
};
140148

141-
constStyledTabs=styled(Tabs)<{
149+
constStyledTabs=styled(Tabs)<{
142150
$style:TabContainerStyleType;
143151
$headerStyle:ContainerHeaderStyleType;
144152
$bodyStyle:TabBodyStyleType;
145-
$isMobile?:boolean;
153+
$isMobile?:boolean;
146154
$showHeader?:boolean;
147-
$animationStyle:AnimationStyleType
155+
$animationStyle:AnimationStyleType;
156+
$isDestroyPane?:boolean;
148157
}>`
149158
&.ant-tabs {
150159
height: 100%;
@@ -157,13 +166,11 @@ const StyledTabs = styled(Tabs)<{
157166
158167
.ant-tabs-content {
159168
height: 100%;
160-
// margin-top: -16px;
161169
}
162170
163171
.ant-tabs-nav {
164172
display:${(props)=>(props.$showHeader ?"block" :"none")};
165173
padding: 0${(props)=>(props.$isMobile ?16 :24)}px;
166-
// background: white;
167174
margin: 0px;
168175
}
169176
@@ -175,16 +182,71 @@ const StyledTabs = styled(Tabs)<{
175182
margin-right: -24px;
176183
}
177184
178-
${(props)=>props.$style&&getStyle(
179-
props.$style,
180-
props.$headerStyle,
181-
props.$bodyStyle,
182-
)}
185+
${(props)=>
186+
props.$style&&getStyle(props.$style,props.$headerStyle,props.$bodyStyle)}
187+
188+
/* Conditional styling for all modes except Destroy Inactive Pane */
189+
${(props)=>!props.$isDestroyPane&&`
190+
.ant-tabs-content-holder { position: relative; }
191+
192+
.ant-tabs-tabpane[aria-hidden="true"],
193+
.ant-tabs-tabpane-hidden {
194+
display: block !important;
195+
visibility: hidden !important;
196+
position: absolute !important;
197+
inset: 0;
198+
pointer-events: none;
199+
}
200+
`}
183201
`;
184202

185203
constContainerInTab=(props:ContainerBaseProps)=>{
204+
return<InnerGrid{...props}emptyRows={15}hintPlaceholder={HintPlaceHolder}/>;
205+
};
206+
207+
typeTabPaneContentProps={
208+
autoHeight:boolean;
209+
showVerticalScrollbar:boolean;
210+
paddingWidth:number;
211+
horizontalGridCells:number;
212+
bodyBackground:string;
213+
layoutView:any;
214+
itemsView:any;
215+
positionParamsView:any;
216+
dispatch:DispatchType;
217+
};
218+
219+
constTabPaneContent:React.FC<TabPaneContentProps>=({
220+
autoHeight,
221+
showVerticalScrollbar,
222+
paddingWidth,
223+
horizontalGridCells,
224+
bodyBackground,
225+
layoutView,
226+
itemsView,
227+
positionParamsView,
228+
dispatch,
229+
})=>{
230+
constgridItems=useMemo(()=>gridItemCompToGridItems(itemsView),[itemsView]);
231+
186232
return(
187-
<InnerGrid{...props}emptyRows={15}hintPlaceholder={HintPlaceHolder}/>
233+
<BackgroundColorContext.Providervalue={bodyBackground}>
234+
<ScrollBar
235+
style={{height:autoHeight ?"auto" :"100%",margin:"0px",padding:"0px"}}
236+
hideScrollbar={!showVerticalScrollbar}
237+
overflow={autoHeight ?"hidden" :"scroll"}
238+
>
239+
<ContainerInTab
240+
layout={layoutView}
241+
items={gridItems}
242+
horizontalGridCells={horizontalGridCells}
243+
positionParams={positionParamsView}
244+
dispatch={dispatch}
245+
autoHeight={autoHeight}
246+
containerPadding={[paddingWidth,20]}
247+
/>
248+
</ScrollBar>
249+
</BackgroundColorContext.Provider>
188250
);
189251
};
190252

@@ -197,27 +259,13 @@ const TabbedContainer = (props: TabbedContainerProps) => {
197259
headerStyle,
198260
bodyStyle,
199261
horizontalGridCells,
200-
destroyInactiveTab,
262+
tabBehavior,
201263
}=props;
202264

203265
constvisibleTabs=tabs.filter((tab)=>!tab.hidden);
204266
constselectedTab=visibleTabs.find((tab)=>tab.key===props.selectedTabKey.value);
205-
constactiveKey=selectedTab
206-
?selectedTab.key
207-
:visibleTabs.length>0
208-
?visibleTabs[0].key
209-
:undefined;
210-
211-
constonTabClick=useCallback(
212-
(key:string,event:React.KeyboardEvent<Element>|React.MouseEvent<Element,MouseEvent>)=>{
213-
// log.debug("onTabClick. event: ", event);
214-
consttarget=event.target;
215-
(targetasany).parentNode.click
216-
?(targetasany).parentNode.click()
217-
:(targetasany).parentNode.parentNode.click();
218-
},
219-
[]
220-
);
267+
constactiveKey=selectedTab?selectedTab.key:visibleTabs.length>0 ?visibleTabs[0].key :undefined;
268+
221269

222270
consteditorState=useContext(EditorContext);
223271
constmaxWidth=editorState.getAppSettings().maxWidth;
@@ -228,73 +276,69 @@ const TabbedContainer = (props: TabbedContainerProps) => {
228276
consttabItems=visibleTabs.map((tab)=>{
229277
constid=String(tab.id);
230278
constchildDispatch=wrapDispatch(wrapDispatch(dispatch,"containers"),id);
231-
constcontainerProps=containers[id].children;
279+
constcontainerChildren=containers[id].children;
232280
consthasIcon=tab.icon.props.value;
281+
233282
constlabel=(
234283
<>
235-
{tab.iconPosition==="left"&&hasIcon&&(
236-
<spanstyle={{marginRight:"4px"}}>{tab.icon}</span>
237-
)}
284+
{tab.iconPosition==="left"&&hasIcon&&<spanstyle={{marginRight:4}}>{tab.icon}</span>}
238285
{tab.label}
239-
{tab.iconPosition==="right"&&hasIcon&&(
240-
<spanstyle={{marginLeft:"4px"}}>{tab.icon}</span>
241-
)}
286+
{tab.iconPosition==="right"&&hasIcon&&<spanstyle={{marginLeft:4}}>{tab.icon}</span>}
242287
</>
243288
);
289+
290+
constforceRender=tabBehavior==="keep-alive";
291+
244292
return{
245293
label,
246-
key:tab.key,
247-
forceRender:!destroyInactiveTab,
248-
destroyInactiveTab:destroyInactiveTab,
294+
key:tab.key,
295+
forceRender,
249296
children:(
250-
<BackgroundColorContext.Providervalue={bodyStyle.background}>
251-
<ScrollBarstyle={{height:props.autoHeight ?"auto" :"100%",margin:"0px",padding:"0px"}}hideScrollbar={!props.showVerticalScrollbar}overflow={props.autoHeight ?'hidden':'scroll'}>
252-
<ContainerInTab
253-
layout={containerProps.layout.getView()}
254-
items={gridItemCompToGridItems(containerProps.items.getView())}
255-
horizontalGridCells={horizontalGridCells}
256-
positionParams={containerProps.positionParams.getView()}
257-
dispatch={childDispatch}
258-
autoHeight={props.autoHeight}
259-
containerPadding={[paddingWidth,20]}
260-
/>
261-
</ScrollBar>
262-
</BackgroundColorContext.Provider>
263-
)
264-
}
265-
})
297+
<TabPaneContent
298+
autoHeight={props.autoHeight}
299+
showVerticalScrollbar={props.showVerticalScrollbar}
300+
paddingWidth={paddingWidth}
301+
horizontalGridCells={horizontalGridCells}
302+
bodyBackground={bodyStyle.background}
303+
layoutView={containerChildren.layout.getView()}
304+
itemsView={containerChildren.items.getView()}
305+
positionParamsView={containerChildren.positionParams.getView()}
306+
dispatch={childDispatch}
307+
/>
308+
),
309+
};
310+
});
266311

267312
return(
268313
<divstyle={{padding:props.style.margin,height:props.autoHeight ?"auto" :"100%"}}>
269-
<BackgroundColorContext.Providervalue={headerStyle.headerBackground}>
270-
<StyledTabs
271-
$animationStyle={props.animationStyle}
272-
tabPosition={props.placement}
273-
activeKey={activeKey}
274-
$style={style}
275-
$headerStyle={headerStyle}
276-
$bodyStyle={bodyStyle}
277-
$showHeader={showHeader}
278-
onChange={(key)=>{
279-
if(key!==props.selectedTabKey.value){
280-
props.selectedTabKey.onChange(key);
281-
props.onEvent("change");
282-
}
283-
}}
284-
// onTabClick={onTabClick}
285-
animated
286-
$isMobile={isMobile}
287-
items={tabItems}
288-
tabBarGutter={props.tabsGutter}
289-
centered={props.tabsCentered}
290-
>
291-
</StyledTabs>
292-
</BackgroundColorContext.Provider>
293-
</div>
314+
<BackgroundColorContext.Providervalue={headerStyle.headerBackground}>
315+
<StyledTabs
316+
destroyOnHidden={tabBehavior==="destroy"}
317+
$animationStyle={props.animationStyle}
318+
tabPosition={props.placement}
319+
activeKey={activeKey}
320+
$style={style}
321+
$headerStyle={headerStyle}
322+
$bodyStyle={bodyStyle}
323+
$showHeader={showHeader}
324+
$isDestroyPane={tabBehavior==="destroy"}
325+
onChange={(key)=>{
326+
if(key!==props.selectedTabKey.value){
327+
props.selectedTabKey.onChange(key);
328+
props.onEvent("change");
329+
}
330+
}}
331+
animated
332+
$isMobile={isMobile}
333+
items={tabItems}
334+
tabBarGutter={props.tabsGutter}
335+
centered={props.tabsCentered}
336+
/>
337+
</BackgroundColorContext.Provider>
338+
</div>
294339
);
295340
};
296341

297-
298342
exportconstTabbedContainerBaseComp=(function(){
299343
returnnewUICompBuilder(childrenMap,(props,dispatch)=>{
300344
return(
@@ -313,14 +357,32 @@ export const TabbedContainerBaseComp = (function () {
313357
})}
314358
{children.selectedTabKey.propertyView({label:trans("prop.defaultValue")})}
315359
</Section>
316-
360+
317361
{["logic","both"].includes(useContext(EditorContext).editorModeStatus)&&(
318362
<Sectionname={sectionNames.interaction}>
319363
{children.onEvent.getPropertyView()}
320364
{disabledPropertyView(children)}
321365
{hiddenPropertyView(children)}
322366
{children.showHeader.propertyView({label:trans("tabbedContainer.showTabs")})}
323-
{children.destroyInactiveTab.propertyView({label:trans("tabbedContainer.destroyInactiveTab")})}
367+
{children.tabBehavior.propertyView({
368+
label:trans("tabbedContainer.tabBehavior"),
369+
tooltip:(
370+
<divstyle={{display:"flex",flexDirection:"column",gap:6}}>
371+
<div>
372+
<b>{trans("tabbedContainer.tabBehaviorLazy")}:</b>
373+
&nbsp;{trans("tabbedContainer.tabBehaviorLazyTooltip")}
374+
</div>
375+
<div>
376+
<b>{trans("tabbedContainer.tabBehaviorKeepAlive")}:</b>
377+
&nbsp;{trans("tabbedContainer.tabBehaviorKeepAliveTooltip")}
378+
</div>
379+
<div>
380+
<b>{trans("tabbedContainer.tabBehaviorDestroy")}:</b>
381+
&nbsp;{trans("tabbedContainer.tabBehaviorDestroyTooltip")}
382+
</div>
383+
</div>
384+
),
385+
})}
324386
</Section>
325387
)}
326388

@@ -371,21 +433,18 @@ class TabbedContainerImplComp extends TabbedContainerBaseComp implements IContai
371433
constactions:CompAction[]=[];
372434
Object.keys(containers).forEach((id)=>{
373435
if(!ids.has(id)){
374-
// log.debug("syncContainers delete. ids=", ids, " id=", id);
375436
actions.push(wrapChildAction("containers",wrapChildAction(id,deleteCompAction())));
376437
}
377438
});
378439
// new
379440
ids.forEach((id)=>{
380441
if(!containers.hasOwnProperty(id)){
381-
// log.debug("syncContainers new containers: ", containers, " id: ", id);
382442
actions.push(
383443
wrapChildAction("containers",addMapChildAction(id,{layout:{},items:{}}))
384444
);
385445
}
386446
});
387447

388-
// log.debug("syncContainers. actions: ", actions);
389448
letinstance=this;
390449
actions.forEach((action)=>{
391450
instance=instance.reduce(action);
@@ -414,13 +473,12 @@ class TabbedContainerImplComp extends TabbedContainerBaseComp implements IContai
414473
returnthis;
415474
}
416475
}
417-
// log.debug("before super reduce. action: ", action);
476+
418477
letnewInstance=super.reduce(action);
419478
if(action.type===CompActionTypes.UPDATE_NODES_V2){
420479
// Need eval to get the value in StringControl
421480
newInstance=newInstance.syncContainers();
422481
}
423-
// log.debug("reduce. instance: ", this, " newInstance: ", newInstance);
424482
returnnewInstance;
425483
}
426484

@@ -464,12 +522,9 @@ class TabbedContainerImplComp extends TabbedContainerBaseComp implements IContai
464522
overrideautoHeight():boolean{
465523
returnthis.children.autoHeight.getView();
466524
}
467-
468-
469525
}
470526

471527
exportconstTabbedContainerComp=withExposingConfigs(TabbedContainerImplComp,[
472528
newNameConfig("selectedTabKey",trans("tabbedContainer.selectedTabKeyDesc")),
473529
NameConfigHidden,
474530
]);
475-

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp