Skip to content

Commit ac2cc48

Browse files
Merge branch 'dev' into fix/environment-type
2 parents 77ceab5 + 6816dcb commit ac2cc48

File tree

1 file changed

+98
-55
lines changed

1 file changed

+98
-55
lines changed

client/packages/lowcoder/src/comps/comps/jsonComp/jsonEditorComp.tsx

Lines changed: 98 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { formDataChildren, FormDataPropertyView } from "../formComp/formDataCons
1212
import { AnimationStyle, JsonEditorStyle } from "comps/controls/styleControlConstants";
1313
import { styleControl } from "comps/controls/styleControl";
1414
import { migrateOldData, withDefault } from "comps/generators/simpleGenerators";
15-
import { useRef, useEffect, useContext } from "react";
15+
import { useRef, useEffect, useContext, useCallback, useMemo } from "react";
1616
import {
1717
EditorState,
1818
EditorView,
@@ -67,7 +67,7 @@ const childrenMap = {
6767
value: jsonValueExposingStateControl('value', defaultData),
6868
onEvent: ChangeEventHandlerControl,
6969
autoHeight: withDefault(AutoHeightControl,'auto'),
70-
showVerticalScrollbar:BoolControl,
70+
showVerticalScrollbar: BoolControl,
7171
label: withDefault(LabelControl, {position: 'column'}),
7272
style: styleControl(JsonEditorStyle, 'style'),
7373
animationStyle: styleControl(AnimationStyle, 'animationStyle'),
@@ -77,72 +77,110 @@ const childrenMap = {
7777
let JsonEditorTmpComp = (function () {
7878
return new UICompBuilder(childrenMap, (props) => {
7979
const wrapperRef = useRef<HTMLDivElement>(null);
80-
const view = useRef<EditorViewType | null>(null);
81-
const initialized = useRef(false);
82-
const state = useRef<EditorState | null>(null);
83-
const editContent = useRef<string>();
80+
const viewRef = useRef<EditorViewType | null>(null);
81+
const initializedRef = useRef(false);
82+
const stateRef = useRef<EditorState | null>(null);
83+
const editContentRef = useRef<string>();
84+
const mountedRef = useRef(true);
85+
86+
const handleChange = useCallback((state: EditorState) => {
87+
if (!mountedRef.current) return;
88+
89+
editContentRef.current = state.doc.toString();
90+
try {
91+
const value = JSON.parse(state.doc.toString());
92+
props.value.onChange(value);
93+
props.onEvent("change");
94+
} catch (error) {
95+
// Invalid JSON - ignore
96+
}
97+
}, [props.value, props.onEvent]);
98+
8499
const { extensions } = useExtensions({
85100
codeType: "PureJSON",
86101
language: "json",
87102
showLineNum: true,
88103
enableClickCompName: false,
89-
onFocus: (focused) => {
104+
onFocus: useCallback((focused: boolean) => {
90105
if (focused) {
91106
wrapperRef.current?.click();
92107
}
93-
},
94-
onChange: (state) => {
95-
editContent.current = state.doc.toString();
96-
try {
97-
const value = JSON.parse(state.doc.toString());
98-
props.value.onChange(value);
99-
props.onEvent("change");
100-
} catch (error) {}
101-
},
108+
}, []),
109+
onChange: handleChange,
102110
});
103111

112+
// Initialize editor state
104113
useEffect(() => {
105-
if (!initialized.current && wrapperRef.current) {
106-
state.current = EditorState.create({
114+
if (!initializedRef.current && wrapperRef.current) {
115+
stateRef.current = EditorState.create({
107116
doc: JSON.stringify(props.value.value, null, 2),
108117
extensions,
109118
});
110119
}
111-
}, [wrapperRef.current]);
120+
if (wrapperRef.current && viewRef.current && !editContentRef.current) {
121+
const newState = EditorState.create({
122+
doc: JSON.stringify(props.value.value, null, 2),
123+
extensions,
124+
});
125+
viewRef.current?.setState(newState);
126+
}
127+
}, [wrapperRef.current, extensions, props.value.value]);
112128

129+
// Create editor view
113130
useEffect(() => {
114-
if (state.current&&wrapperRef.current) {
115-
view.current = new EditorView({ state: state.current, parent: wrapperRef.current });
116-
initialized.current = true;
131+
if (stateRef.current && wrapperRef.current) {
132+
viewRef.current = new EditorView({
133+
state: stateRef.current,
134+
parent: wrapperRef.current
135+
});
136+
initializedRef.current = true;
117137
}
118-
}, [props.showVerticalScrollbar])
119-
120-
if (wrapperRef.current && view.current && !editContent.current) {
121-
const state = EditorState.create({
122-
doc: JSON.stringify(props.value.value, null, 2),
123-
extensions,
124-
});
125-
view.current?.setState(state);
126-
}
127-
if (editContent.current) {
128-
editContent.current = undefined;
129-
}
138+
139+
return () => {
140+
viewRef.current?.destroy();
141+
viewRef.current = null;
142+
stateRef.current = null;
143+
initializedRef.current = false;
144+
};
145+
}, [props.showVerticalScrollbar]);
146+
147+
// Cleanup on unmount
148+
useEffect(() => {
149+
return () => {
150+
mountedRef.current = false;
151+
viewRef.current?.destroy();
152+
viewRef.current = null;
153+
stateRef.current = null;
154+
initializedRef.current = false;
155+
};
156+
}, []);
157+
158+
const handleFocus = useCallback(() => {
159+
editContentRef.current = 'focus';
160+
}, []);
161+
162+
const editorContent = useMemo(() => (
163+
<ScrollBar hideScrollbar={!props.showVerticalScrollbar}>
164+
<Wrapper
165+
ref={wrapperRef}
166+
onFocus={handleFocus}
167+
$height={props.autoHeight}
168+
$showVerticalScrollbar={props.showVerticalScrollbar}
169+
/>
170+
</ScrollBar>
171+
), [props.showVerticalScrollbar, props.autoHeight, handleFocus]);
172+
130173
return props.label({
131174
style: props.style,
132175
animationStyle: props.animationStyle,
133-
children: (
134-
<ScrollBar hideScrollbar={!props.showVerticalScrollbar}>
135-
<Wrapper
136-
ref={wrapperRef}
137-
onFocus={() => (editContent.current = 'focus')}
138-
$height={props.autoHeight}
139-
$showVerticalScrollbar={props.showVerticalScrollbar}
140-
/>
141-
</ScrollBar>
142-
),
176+
children: editorContent,
143177
});
144178
})
145179
.setPropertyViewFn((children) => {
180+
const editorContext = useContext(EditorContext);
181+
const isLogicMode = editorContext.editorModeStatus === "logic" || editorContext.editorModeStatus === "both";
182+
const isLayoutMode = editorContext.editorModeStatus === "layout" || editorContext.editorModeStatus === "both";
183+
146184
return (
147185
<>
148186
<Section name={sectionNames.basic}>
@@ -151,35 +189,40 @@ let JsonEditorTmpComp = (function () {
151189

152190
<FormDataPropertyView {...children} />
153191

154-
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (
192+
{isLogicMode && (
155193
<Section name={sectionNames.interaction}>
156194
{children.onEvent.getPropertyView()}
157195
{hiddenPropertyView(children)}
158196
{showDataLoadingIndicatorsPropertyView(children)}
159197
</Section>
160198
)}
199+
161200
<Section name={trans('prop.height')}>
162201
{children.autoHeight.propertyView({ label: trans('prop.height') })}
163202
</Section>
164-
{!children.autoHeight.getView()&&<Section name={sectionNames.layout}>
165-
{children.showVerticalScrollbar.propertyView({label: trans('prop.showVerticalScrollbar')})}
166-
</Section>}
167-
{(useContext(EditorContext).editorModeStatus === "layout" || useContext(EditorContext).editorModeStatus === "both") && ( children.label.getPropertyView() )}
168-
{(useContext(EditorContext).editorModeStatus === "layout" || useContext(EditorContext).editorModeStatus === "both") && (
169-
<>
170-
<Section name={sectionNames.style}>{children.style.getPropertyView()}</Section>
171-
<Section name={sectionNames.animationStyle} hasTooltip={true}>{children.animationStyle.getPropertyView()}</Section>
172-
</>
203+
204+
{!children.autoHeight.getView() && (
205+
<Section name={sectionNames.layout}>
206+
{children.showVerticalScrollbar.propertyView({label: trans('prop.showVerticalScrollbar')})}
207+
</Section>
173208
)}
174209

210+
{isLayoutMode && (
211+
<>
212+
{children.label.getPropertyView()}
213+
<Section name={sectionNames.style}>{children.style.getPropertyView()}</Section>
214+
<Section name={sectionNames.animationStyle} hasTooltip={true}>
215+
{children.animationStyle.getPropertyView()}
216+
</Section>
217+
</>
218+
)}
175219
</>
176220
);
177221
})
178222
.build();
179223
})();
180224

181225
JsonEditorTmpComp = migrateOldData(JsonEditorTmpComp, fixOldData);
182-
183226
JsonEditorTmpComp = migrateOldData(JsonEditorTmpComp, fixOldDataSecond);
184227

185228
JsonEditorTmpComp = class extends JsonEditorTmpComp {

0 commit comments

Comments
 (0)