Skip to content

Commit 18045b9

Browse files
committed
Added Styling actions (Fixed Constant)
Added Nesting components
1 parent 4197d0b commit 18045b9

File tree

9 files changed

+297
-37
lines changed

9 files changed

+297
-37
lines changed

client/packages/lowcoder/src/comps/comps/preLoadComp/actionConfigs.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
configureComponentAction,
99
changeLayoutAction,
1010
addEventHandlerAction,
11-
applyStyleAction
11+
applyStyleAction,
12+
nestComponentAction
1213
} from "./actions";
1314

1415
export const actionCategories: ActionCategory[] = [
@@ -20,7 +21,8 @@ export const actionCategories: ActionCategory[] = [
2021
moveComponentAction,
2122
deleteComponentAction,
2223
resizeComponentAction,
23-
renameComponentAction
24+
renameComponentAction,
25+
nestComponentAction
2426
]
2527
},
2628
{

client/packages/lowcoder/src/comps/comps/preLoadComp/actionInputSection.tsx

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ export function ActionInputSection() {
2525
const [placeholderText, setPlaceholderText] = useState<string>("");
2626
const [selectedComponent, setSelectedComponent] = useState<string | null>(null);
2727
const [showComponentDropdown, setShowComponentDropdown] = useState<boolean>(false);
28+
const [isNestedComponent, setIsNestedComponent] = useState<boolean>(false);
29+
const [selectedNestComponent, setSelectedNestComponent] = useState<string | null>(null);
2830
const [showEditorComponentsDropdown, setShowEditorComponentsDropdown] = useState<boolean>(false);
31+
const [showStylingInput, setShowStylingInput] = useState<boolean>(false);
2932
const [selectedEditorComponent, setSelectedEditorComponent] = useState<string | null>(null);
3033
const [validationError, setValidationError] = useState<string | null>(null);
3134
const inputRef = useRef<InputRef>(null);
@@ -73,44 +76,55 @@ export function ActionInputSection() {
7376

7477
setShowComponentDropdown(false);
7578
setShowEditorComponentsDropdown(false);
79+
setShowStylingInput(false);
7680
setSelectedComponent(null);
7781
setSelectedEditorComponent(null);
82+
setIsNestedComponent(false);
83+
setSelectedNestComponent(null);
7884
setActionValue("");
7985

8086
if (action.requiresComponentSelection) {
8187
setShowComponentDropdown(true);
8288
setPlaceholderText("Select a component to add");
83-
} else if (action.requiresEditorComponentSelection) {
89+
}
90+
if (action.requiresEditorComponentSelection) {
8491
setShowEditorComponentsDropdown(true);
8592
setPlaceholderText(`Select a component to ${action.label.toLowerCase()}`);
86-
} else if (action.requiresInput) {
93+
}
94+
if (action.requiresInput) {
8795
setPlaceholderText(action.inputPlaceholder || `Enter ${action.label.toLowerCase()} value`);
8896
} else {
8997
setPlaceholderText(`Execute ${action.label.toLowerCase()}`);
9098
}
99+
if (action.requiresStyle) {
100+
setShowStylingInput(true);
101+
setPlaceholderText(`Select a component to style`);
102+
}
103+
if (action.isNested) {
104+
setIsNestedComponent(true);
105+
}
91106
}, []);
92107

93108
const handleComponentSelection = useCallback((key: string) => {
94109
if (key.startsWith('comp-')) {
95110
const compName = key.replace('comp-', '');
96-
setSelectedComponent(compName);
111+
isNestedComponent ? setSelectedNestComponent(compName) : setSelectedComponent(compName);
97112
setPlaceholderText(`Configure ${compName} component`);
98113
}
99-
}, []);
114+
}, [isNestedComponent]);
100115

101116
const handleEditorComponentSelection = useCallback((key: string) => {
102117
setSelectedEditorComponent(key);
103-
if (currentAction) {
104-
setPlaceholderText(`${currentAction.label}`);
105-
}
118+
setPlaceholderText(`${currentAction?.label}`);
106119
}, [currentAction]);
107120

121+
108122
const validateInput = useCallback((value: string): string | null => {
109123
if (!currentAction?.validation) return null;
110124
return currentAction.validation(value);
111125
}, [currentAction]);
112126

113-
const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
127+
const handleInputChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
114128
const value = e.target.value;
115129
setActionValue(value);
116130

@@ -149,12 +163,18 @@ export function ActionInputSection() {
149163
return;
150164
}
151165

166+
if(currentAction.isNested && !selectedNestComponent) {
167+
message.error('Please select a component to nest');
168+
return;
169+
}
170+
152171
try {
153172
await currentAction.execute({
154173
actionKey: selectedActionKey,
155174
actionValue,
156175
selectedComponent,
157176
selectedEditorComponent,
177+
selectedNestComponent,
158178
editorState
159179
});
160180

@@ -167,6 +187,8 @@ export function ActionInputSection() {
167187
setSelectedEditorComponent(null);
168188
setPlaceholderText("");
169189
setValidationError(null);
190+
setIsNestedComponent(false);
191+
setSelectedNestComponent(null);
170192

171193
} catch (error) {
172194
console.error('Error executing action:', error);
@@ -177,6 +199,7 @@ export function ActionInputSection() {
177199
actionValue,
178200
selectedComponent,
179201
selectedEditorComponent,
202+
selectedNestComponent,
180203
editorState,
181204
currentAction,
182205
validateInput
@@ -235,7 +258,7 @@ export function ActionInputSection() {
235258
</Button>
236259
</CustomDropdown>
237260

238-
{showComponentDropdown && (
261+
{(showComponentDropdown || isNestedComponent) && (
239262
<CustomDropdown
240263
overlayStyle={{
241264
maxHeight: '400px',
@@ -253,7 +276,13 @@ export function ActionInputSection() {
253276
>
254277
<Button size={"small"}>
255278
<Space>
256-
{selectedComponent ? selectedComponent : 'Select Component'}
279+
{
280+
selectedComponent
281+
? selectedComponent
282+
: selectedNestComponent
283+
? selectedNestComponent
284+
: 'New Component'
285+
}
257286
<DownOutlined />
258287
</Space>
259288
</Button>
@@ -278,23 +307,34 @@ export function ActionInputSection() {
278307
>
279308
<Button size={"small"}>
280309
<Space>
281-
{selectedEditorComponent ? selectedEditorComponent : 'Select Component'}
310+
{selectedEditorComponent ? selectedEditorComponent : 'Editor Component'}
282311
<DownOutlined />
283312
</Space>
284313
</Button>
285314
</CustomDropdown>
286315
)}
287-
316+
288317
{shouldShowInput && (
289-
<Input
290-
ref={inputRef}
291-
value={actionValue}
292-
onChange={handleInputChange}
293-
placeholder={placeholderText}
294-
status={validationError ? 'error' : undefined}
295-
/>
318+
showStylingInput ? (
319+
<Input.TextArea
320+
ref={inputRef}
321+
value={actionValue}
322+
onChange={handleInputChange}
323+
placeholder={placeholderText}
324+
status={validationError ? 'error' : undefined}
325+
autoSize={{ minRows: 1 }}
326+
/>
327+
) : (
328+
<Input
329+
ref={inputRef}
330+
value={actionValue}
331+
onChange={handleInputChange}
332+
placeholder={placeholderText}
333+
status={validationError ? 'error' : undefined}
334+
/>
335+
)
296336
)}
297-
337+
298338
{validationError && (
299339
<div style={{ color: '#ff4d4f', fontSize: '12px', marginTop: '-8px' }}>
300340
{validationError}

client/packages/lowcoder/src/comps/comps/preLoadComp/actions/componentManagement.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,125 @@ export const addComponentAction: ActionConfig = {
108108
}
109109
};
110110

111+
export const nestComponentAction: ActionConfig = {
112+
key: 'nest-components',
113+
label: 'Nest a component',
114+
category: 'component-management',
115+
requiresEditorComponentSelection: true,
116+
requiresInput: false,
117+
isNested: true,
118+
execute: async (params: ActionExecuteParams) => {
119+
const { selectedEditorComponent, selectedNestComponent, editorState } = params;
120+
121+
if (!selectedEditorComponent || !selectedNestComponent || !editorState) {
122+
message.error('Parent component, child component, and editor state are required');
123+
return;
124+
}
125+
126+
const parentComponentInfo = getEditorComponentInfo(editorState, selectedEditorComponent);
127+
128+
if (!parentComponentInfo) {
129+
message.error(`Parent component "${selectedEditorComponent}" not found`);
130+
return;
131+
}
132+
133+
const { componentKey: parentKey, items } = parentComponentInfo;
134+
135+
if (!parentKey) {
136+
message.error(`Parent component "${selectedEditorComponent}" not found in layout`);
137+
return;
138+
}
139+
140+
const parentItem = items[parentKey];
141+
if (!parentItem) {
142+
message.error(`Parent component "${selectedEditorComponent}" not found in items`);
143+
return;
144+
}
145+
146+
// Check if parent is a container
147+
const parentCompType = parentItem.children.compType.getView();
148+
const parentManifest = uiCompRegistry[parentCompType];
149+
150+
if (!parentManifest?.isContainer) {
151+
message.error(`Component "${selectedEditorComponent}" is not a container and cannot nest components`);
152+
return;
153+
}
154+
155+
try {
156+
157+
const nameGenerator = editorState.getNameGenerator();
158+
const compInfo = parseCompType(selectedNestComponent);
159+
const compName = nameGenerator.genItemName(compInfo.compName);
160+
const key = genRandomKey();
161+
162+
const manifest = uiCompRegistry[selectedNestComponent];
163+
let defaultDataFn = undefined;
164+
165+
if (manifest?.lazyLoad) {
166+
const { defaultDataFnName, defaultDataFnPath } = manifest;
167+
if (defaultDataFnName && defaultDataFnPath) {
168+
const module = await import(`../../../${defaultDataFnPath}.tsx`);
169+
defaultDataFn = module[defaultDataFnName];
170+
}
171+
} else if (!compInfo.isRemote) {
172+
defaultDataFn = manifest?.defaultDataFn;
173+
}
174+
175+
const widgetValue: GridItemDataType = {
176+
compType: selectedNestComponent,
177+
name: compName,
178+
comp: defaultDataFn ? defaultDataFn(compName, nameGenerator, editorState) : undefined,
179+
};
180+
181+
const parentContainer = parentItem.children.comp;
182+
183+
const realContainer = parentContainer.realSimpleContainer();
184+
if (!realContainer) {
185+
message.error(`Container "${selectedEditorComponent}" cannot accept nested components`);
186+
return;
187+
}
188+
189+
const currentLayout = realContainer.children.layout.getView();
190+
const layoutInfo = manifest?.layoutInfo || defaultLayout(selectedNestComponent as UICompType);
191+
192+
let itemPos = 0;
193+
if (Object.keys(currentLayout).length > 0) {
194+
itemPos = Math.max(...Object.values(currentLayout).map((l: any) => l.pos || 0)) + 1;
195+
}
196+
197+
const layoutItem = {
198+
i: key,
199+
x: 0,
200+
y: 0,
201+
w: layoutInfo.w || 6,
202+
h: layoutInfo.h || 5,
203+
pos: itemPos,
204+
isDragging: false,
205+
};
206+
207+
realContainer.dispatch(
208+
wrapActionExtraInfo(
209+
multiChangeAction({
210+
layout: changeValueAction({
211+
...currentLayout,
212+
[key]: layoutItem,
213+
}, true),
214+
items: addMapChildAction(key, widgetValue),
215+
}),
216+
{ compInfos: [{ compName: compName, compType: selectedNestComponent, type: "add" }] }
217+
)
218+
);
219+
220+
editorState.setSelectedCompNames(new Set([compName]), "nestComp");
221+
222+
message.success(`Component "${manifest?.name || selectedNestComponent}" nested in "${selectedEditorComponent}" successfully!`);
223+
} catch (error) {
224+
console.error('Error nesting component:', error);
225+
message.error('Failed to nest component. Please try again.');
226+
}
227+
}
228+
}
229+
111230
export const deleteComponentAction: ActionConfig = {
112231
key: 'delete-components',
113232
label: 'Delete a component',

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy