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

Commit c7bddbf

Browse files
author
FalkWolsky
committed
Work in Progress for Responsive Layout
1 parent 9618206 commit c7bddbf

File tree

2 files changed

+214
-229
lines changed

2 files changed

+214
-229
lines changed

‎client/packages/lowcoder/src/comps/comps/jsonSchemaFormComp/ObjectFieldTemplate.tsx‎

Lines changed: 128 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,14 @@
11
import React, { useEffect, useRef, useState } from "react";
2-
import { Row, Col } from "antd";
3-
import {
4-
ObjectFieldTemplateProps,
5-
getTemplate,
6-
getUiOptions,
7-
descriptionId,
8-
titleId,
9-
canExpand,
10-
} from "@rjsf/utils";
11-
import { ConfigConsumer } from "antd/es/config-provider/context";
2+
import { Row, Col } from 'antd';
3+
import { ObjectFieldTemplateProps, getTemplate, getUiOptions, descriptionId, titleId, canExpand } from '@rjsf/utils';
4+
import { ConfigConsumer } from 'antd/es/config-provider/context';
5+
import { useContainerWidth } from "./jsonSchemaFormComp";
6+
import styled from "styled-components";
127

138
const DESCRIPTION_COL_STYLE = {
14-
paddingBottom: "8px",
9+
paddingBottom: '8px',
1510
};
1611

17-
interface ColSpan {
18-
xs: number;
19-
sm: number;
20-
md: number;
21-
lg: number;
22-
xl: number;
23-
}
24-
25-
interface UiOptions {
26-
colSpan: ColSpan;
27-
rowGutter: number;
28-
// other properties...
29-
}
30-
3112
const ObjectFieldTemplate = (props: ObjectFieldTemplateProps) => {
3213
const {
3314
title,
@@ -42,59 +23,62 @@ const ObjectFieldTemplate = (props: ObjectFieldTemplateProps) => {
4223
readonly,
4324
registry,
4425
} = props;
45-
46-
const containerRef = useRef<HTMLDivElement>(null);
47-
const [containerWidth, setContainerWidth] = useState(0);
48-
49-
// Monitor the container's width
50-
useEffect(() => {
51-
const updateWidth = () => {
52-
if (containerRef.current) {
53-
setContainerWidth(containerRef.current.offsetWidth);
54-
}
55-
};
56-
57-
// Create a ResizeObserver to watch for width changes
58-
const resizeObserver = new ResizeObserver(() => {
59-
updateWidth();
60-
});
61-
62-
if (containerRef.current) {
63-
resizeObserver.observe(containerRef.current);
64-
}
65-
66-
// Initial update
67-
updateWidth();
68-
69-
// Cleanup observer on unmount
70-
return () => {
71-
resizeObserver.disconnect();
72-
};
73-
}, []);
26+
const containerWidth = useContainerWidth();
7427

7528
const uiOptions = getUiOptions(uiSchema);
76-
const TitleFieldTemplate = getTemplate("TitleFieldTemplate", registry, uiOptions);
77-
const DescriptionFieldTemplate = getTemplate("DescriptionFieldTemplate", registry, uiOptions);
29+
const TitleFieldTemplate = getTemplate('TitleFieldTemplate', registry, uiOptions);
30+
const DescriptionFieldTemplate = getTemplate('DescriptionFieldTemplate', registry, uiOptions);
7831
const {
7932
ButtonTemplates: { AddButton },
8033
} = registry.templates;
8134

82-
const defaultResponsiveColSpan = (width: number) => {
83-
if (width > 1200) return 8; // Wide screens
84-
if (width > 768) return 12; // Tablets
85-
return 24; // Mobile
35+
// Define responsive column spans based on the ui:props or fallback to defaults
36+
const defaultResponsiveColSpan = {
37+
xs: 24, // Extra small devices
38+
sm: 24, // Small devices
39+
md: 12, // Medium devices
40+
lg: 12, // Large devices
41+
xl: 8, // Extra large devices
8642
};
8743

88-
const { rowGutter = 4 } = uiSchema?.["ui:props"] || {};
89-
90-
const calculateResponsiveColSpan = (element: any): { span: number } => {
44+
const { rowGutter = 4 } = uiSchema?.['ui:props'] || {};
45+
46+
const calculateResponsiveColSpan = (element: any, level: number): { span: number } => {
47+
48+
console.log("Calculating span for", element.name, "at level", level);
49+
50+
// root level
51+
if (level === 0) return { span: 24 };
52+
53+
// Check if the element has a layout definition in ui:grid
54+
const gridColSpan = uiSchema?.['ui:grid']
55+
?.find((row: Record<string, any>) => row[element.name])
56+
?. [element.name];
57+
58+
if (gridColSpan) {
59+
if (typeof gridColSpan === "number") {
60+
return { span: gridColSpan };
61+
} else if (typeof gridColSpan === "object") {
62+
if (containerWidth > 1200 && gridColSpan.xl !== undefined) {
63+
return { span: gridColSpan.xl };
64+
} else if (containerWidth > 992 && gridColSpan.lg !== undefined) {
65+
return { span: gridColSpan.lg };
66+
} else if (containerWidth > 768 && gridColSpan.md !== undefined) {
67+
return { span: gridColSpan.md };
68+
} else if (containerWidth > 576 && gridColSpan.sm !== undefined) {
69+
return { span: gridColSpan.sm };
70+
} else if (gridColSpan.xs !== undefined) {
71+
return { span: gridColSpan.xs };
72+
}
73+
}
74+
}
9175

76+
// Fallback to default colSpan or ui:props.colSpan
9277
const uiSchemaProps = getUiOptions(element.content.props.uiSchema)?.["ui:props"] as
9378
| { colSpan?: Record<string, number> | number }
9479
| undefined;
9580

9681
const uiSchemaColSpan = uiSchemaProps?.colSpan;
97-
const defaultSpan = containerWidth > 1200 ? 8 : containerWidth > 768 ? 12 : 24;
9882

9983
if (uiSchemaColSpan) {
10084
if (typeof uiSchemaColSpan === "number") {
@@ -114,133 +98,94 @@ const ObjectFieldTemplate = (props: ObjectFieldTemplateProps) => {
11498
}
11599
}
116100

101+
// Default responsive behavior
102+
const defaultSpan = containerWidth > 1200 ? 8 : containerWidth > 768 ? 12 : 24;
117103
return { span: defaultSpan };
118104
};
119105

120-
const renderSectionLayout = (properties: any[], uiGrid: any, section: string) => {
121-
122-
if (uiGrid && Array.isArray(uiGrid)) {
123-
return (
124-
<Row gutter={rowGutter} key={section}>
125-
{uiGrid.map((ui_row: Record<string, any>) =>
126-
Object.keys(ui_row).map((row_item) => {
127-
const element = properties.find((p) => p.name === row_item);
128-
if (element) {
129-
const span = calculateResponsiveColSpan(element).span;
130-
return (
131-
<Col key={element.name} span={span}>
132-
{element.content}
133-
</Col>
134-
);
135-
}
136-
return null;
137-
})
138-
)}
139-
</Row>
140-
);
141-
}
142-
143-
// Default layout if no grid is provided
106+
const renderProperties = (properties: any[], level: number) => {
107+
console.log("Rendering level:", level); // Debugging level
144108
return (
145-
<Row gutter={rowGutter} key={section}>
146-
{properties.map((element) => (
147-
<Col key={element.name} {...calculateResponsiveColSpan(element)}>
148-
{element.content}
149-
</Col>
150-
))}
109+
<Row
110+
gutter={rowGutter}
111+
style={level === 0 ? { width: "100%" } : { marginLeft: -8, marginRight: -8 }}
112+
>
113+
{properties.map((element) => {
114+
const span = calculateResponsiveColSpan(element, level);
115+
116+
// Check if the element is an object or array and has nested properties
117+
if (element.content?.props?.schema?.type === "object" && element.content.props.properties) {
118+
// Render nested objects with an incremented level
119+
return (
120+
<Col key={element.name} span={24}>
121+
<fieldset>
122+
<legend>{element.content.props.title || element.name}</legend>
123+
{renderProperties(element.content.props.properties, level + 1)}
124+
</fieldset>
125+
</Col>
126+
);
127+
}
128+
129+
// Render normal elements
130+
return (
131+
<Col key={element.name} span={span.span}>
132+
{element.content}
133+
</Col>
134+
);
135+
})}
151136
</Row>
152137
);
153138
};
154-
155-
const renderCustomLayout = () => {
156-
const schemaType = schema.type as string;
157-
switch (schemaType) {
158-
case "Group":
159-
return (
160-
<div style={{ border: "1px solid #ccc", padding: "15px", marginBottom: "10px" }}>
161-
<h3>{schema.label || "Group"}</h3>
162-
{renderSectionLayout(properties, uiSchema?.["ui:grid"], schema.label)}
163-
</div>
164-
);
165-
case "HorizontalLayout":
166-
return (
167-
<Row gutter={rowGutter} style={{ display: "flex", gap: "10px" }}>
168-
{properties.map((element) => (
169-
<Col key={element.name} {...calculateResponsiveColSpan(element)}>
170-
{element.content}
171-
</Col>
172-
))}
173-
</Row>
174-
);
175-
case "VerticalLayout":
176-
return (
177-
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
178-
{properties.map((element) => (
179-
<div key={element.name}>{element.content}</div>
180-
))}
181-
</div>
182-
);
183-
default:
184-
return null; // Fall back to default rendering if no match
185-
}
186-
};
187-
188-
// Check if the schema is a custom layout type
189-
const schemaType = schema.type as string; // Extract schema type safely
190-
const isCustomLayout = ["Group", "HorizontalLayout", "VerticalLayout"].includes(schemaType);
191-
139+
192140
return (
193-
<div ref={containerRef}>
194-
<ConfigConsumer>
195-
{(configProps) => (
196-
<fieldset id={idSchema.$id} className="form-section">
197-
{!isCustomLayout && (
198-
<>
199-
{schema.type === "object" && title && (
200-
<legend>
201-
<TitleFieldTemplate
202-
id={titleId(idSchema)}
203-
title={title}
204-
required={props.required}
205-
schema={schema}
206-
uiSchema={uiSchema}
207-
registry={registry}
208-
/>
209-
</legend>
210-
)}
211-
{description && (
212-
<Col span={24} style={DESCRIPTION_COL_STYLE}>
213-
<DescriptionFieldTemplate
214-
id={descriptionId(idSchema)}
215-
description={description}
216-
schema={schema}
217-
uiSchema={uiSchema}
218-
registry={registry}
219-
/>
220-
</Col>
221-
)}
222-
{renderSectionLayout(properties, uiSchema?.["ui:grid"], "root")}
223-
</>
224-
)}
225-
226-
{isCustomLayout && renderCustomLayout()}
227-
228-
{canExpand(schema, uiSchema, formData) && (
229-
<Row justify="end" style={{ marginTop: "24px" }}>
230-
<Col>
231-
<AddButton
232-
className="object-property-expand"
233-
onClick={onAddClick(schema)}
234-
disabled={disabled || readonly}
235-
registry={registry}
236-
/>
237-
</Col>
238-
</Row>
239-
)}
240-
</fieldset>
241-
)}
242-
</ConfigConsumer>
243-
</div>
141+
<ConfigConsumer>
142+
{(configProps) => (
143+
<fieldset id={idSchema.$id} className="form-section">
144+
{/* Render Title */}
145+
{schema.type === "object" && title && (
146+
<legend>
147+
<TitleFieldTemplate
148+
id={titleId(idSchema)}
149+
title={title}
150+
required={props.required}
151+
schema={schema}
152+
uiSchema={uiSchema}
153+
registry={registry}
154+
/>
155+
</legend>
156+
)}
157+
{/* Render Description */}
158+
{description && (
159+
<Row>
160+
<Col span={24} style={DESCRIPTION_COL_STYLE}>
161+
<DescriptionFieldTemplate
162+
id={descriptionId(idSchema)}
163+
description={description}
164+
schema={schema}
165+
uiSchema={uiSchema}
166+
registry={registry}
167+
/>
168+
</Col>
169+
</Row>
170+
)}
171+
{/* Render Properties */}
172+
{renderProperties(properties, 0)}
173+
{/* Expand Button */}
174+
{canExpand(schema, uiSchema, formData) && (
175+
<Row justify="end" style={{ width: "100%", marginTop: "24px" }}>
176+
<Col>
177+
<AddButton
178+
className="object-property-expand"
179+
onClick={onAddClick(schema)}
180+
disabled={disabled || readonly}
181+
registry={registry}
182+
/>
183+
</Col>
184+
</Row>
185+
)}
186+
</fieldset>
187+
)}
188+
</ConfigConsumer>
244189
);
245190
};
246191

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /