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

Commit4747b25

Browse files
committed
#1987 introduce delta for editor
1 parent7dc8e77 commit4747b25

File tree

1 file changed

+56
-20
lines changed

1 file changed

+56
-20
lines changed

‎client/packages/lowcoder/src/comps/comps/richTextEditorComp.tsx‎

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ const toolbarOptions = [
171171
];
172172

173173
constchildrenMap={
174-
value:stringExposingStateControl("value"),
174+
value:stringExposingStateControl("value"),
175+
delta:stringExposingStateControl("delta"),
175176
hideToolbar:BoolControl,
176177
readOnly:BoolControl,
177178
autoHeight:withDefault(AutoHeightControl,"fixed"),
@@ -194,7 +195,7 @@ interface IProps {
194195
hideToolbar:boolean;
195196
readOnly:boolean;
196197
autoHeight:boolean;
197-
onChange:(value:string)=>void;
198+
onChange:(html:string,deltaJSON:string,text:string)=>void;
198199
$style:RichTextEditorStyleType;
199200
contentScrollBar:boolean;
200201
tabIndex?:number;
@@ -207,15 +208,30 @@ function RichTextEditor(props: IProps) {
207208
const[content,setContent]=useState("");
208209
constwrapperRef=useRef<HTMLDivElement>(null);
209210
consteditorRef=useRef<ReactQuill>(null);
211+
212+
constgetQuill=()=>(editorRef.currentasany)?.getEditor?.();
213+
214+
consttryParseDelta=(v:unknown)=>{
215+
if(!v)returnnull;
216+
if(typeofv==="string"){
217+
try{
218+
constd=JSON.parse(v);
219+
returnArray.isArray(d?.ops) ?d :null;
220+
}catch{returnnull;}
221+
}
222+
if(typeofv==="object"&&Array.isArray((vasany).ops))returnvasany;
223+
returnnull;
224+
};
225+
210226
constisTypingRef=useRef(0);
211227

212228
constdebounce=INPUT_DEFAULT_ONCHANGE_DEBOUNCE;
213229

214230
constoriginOnChangeRef=useRef(props.onChange);
215231
originOnChangeRef.current=props.onChange;
216232

217-
constonChangeRef=useRef(
218-
(v:string)=>originOnChangeRef.current?.(v)
233+
constonChangeRef=useRef((html:string,deltaJSON:string,text:string)=>
234+
originOnChangeRef.current?.(html,deltaJSON,text)
219235
);
220236

221237
// react-quill will not take effect after the placeholder is updated
@@ -235,7 +251,7 @@ function RichTextEditor(props: IProps) {
235251
(editor.scroll.domNodeasHTMLElement).tabIndex=props.tabIndex;
236252
}
237253
}
238-
},[props.tabIndex,key]);// Also re-run when key changes due to placeholder update
254+
},[props.tabIndex,key]);
239255

240256
constcontains=(parent:HTMLElement,descendant:HTMLElement)=>{
241257
try{
@@ -248,19 +264,31 @@ function RichTextEditor(props: IProps) {
248264
returnparent.contains(descendant);
249265
};
250266

251-
consthandleChange=(value:string)=>{
252-
setContent(value);
253-
// props.onChange(value);
254-
onChangeRef.current(value);
255-
};
256267

257268
useEffect(()=>{
258-
letfinalValue=props.value;
259-
if(!/^<\w+>.+<\/\w+>$/.test(props.value)){
260-
finalValue=`<p class="">${props.value}</p>`;
269+
constq=getQuill();
270+
271+
if(!q){
272+
constv=props.value??"";
273+
constlooksHtml=/<\/?[a-z][\s\S]*>/i.test(v);
274+
setContent(looksHtml ?v :`<p class="">${v}</p>`);
275+
return;
261276
}
262-
setContent(finalValue);
277+
278+
constasDelta=tryParseDelta(props.value);
279+
if(asDelta){
280+
q.setContents(asDelta,"api");
281+
consthtml=q.root?.innerHTML??"";
282+
setContent(html);
283+
return;
284+
}
285+
286+
constv=props.value??"";
287+
constlooksHtml=/<\/?[a-z][\s\S]*>/i.test(v);
288+
consthtml=looksHtml ?v :`<p class="">${v}</p>`;
289+
setContent(html);
263290
},[props.value]);
291+
264292

265293
consthandleClickWrapper=(e:React.MouseEvent<HTMLDivElement>)=>{
266294
// grid item prevents bubbling, quill can't listen to events on document.body, so it can't close the toolbar drop-down box
@@ -297,7 +325,13 @@ function RichTextEditor(props: IProps) {
297325
value={content}
298326
placeholder={props.placeholder}
299327
readOnly={props.readOnly}
300-
onChange={handleChange}
328+
onChange={(html,_delta,source,editor)=>{
329+
setContent(html);
330+
constquill=editorRef.current?.getEditor?.();
331+
constfullDelta=quill?.getContents?.()??{ops:[]};
332+
consttext=quill?.getText?.()??"";
333+
onChangeRef.current(html,JSON.stringify(fullDelta),text);
334+
}}
301335
/>
302336
</Suspense>
303337
</Wrapper>
@@ -306,15 +340,16 @@ function RichTextEditor(props: IProps) {
306340

307341
constRichTextEditorCompBase=newUICompBuilder(childrenMap,(props)=>{
308342
constdebouncedOnChangeRef=useRef(
309-
debounce((value:string)=>{
310-
props.value.onChange(value);
343+
debounce((html:string,deltaJSON:string,text:string)=>{
344+
props.value.onChange(html);
345+
props.delta.onChange(deltaJSON);
311346
props.onEvent("change");
312347
},1000)
313348
);
314349

315-
consthandleChange=(value:string)=>{
316-
debouncedOnChangeRef.current?.(value);
317-
};
350+
consthandleChange=(html:string,deltaJSON:string,text:string)=>{
351+
debouncedOnChangeRef.current?.(html,deltaJSON,text);
352+
};
318353

319354
return(
320355
<RichTextEditor
@@ -379,6 +414,7 @@ class RichTextEditorCompAutoHeight extends RichTextEditorCompBase {
379414

380415
exportconstRichTextEditorComp=withExposingConfigs(RichTextEditorCompAutoHeight,[
381416
newNameConfig("value",trans("export.richTextEditorValueDesc")),
417+
newNameConfig("delta",trans("export.richTextEditorDeltaDesc")),
382418
newNameConfig("readOnly",trans("export.richTextEditorReadOnlyDesc")),
383419
newNameConfig("hideToolbar",trans("export.richTextEditorHideToolBarDesc")),
384420
NameConfigHidden,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp