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

Commit79acea5

Browse files
Merge pull request#2003 from iamfaran/fix/1987-rich-editor
[Fix]:#1987 introduce delta for editor
2 parents4c8b4ea +c7c02ac commit79acea5

File tree

1 file changed

+70
-23
lines changed

1 file changed

+70
-23
lines changed

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

Lines changed: 70 additions & 23 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,37 @@ function RichTextEditor(props: IProps) {
207208
const[content,setContent]=useState("");
208209
constwrapperRef=useRef<HTMLDivElement>(null);
209210
consteditorRef=useRef<ReactQuill>(null);
211+
212+
// know exactly when the editor mounts
213+
const[editorReady,setEditorReady]=useState(false);
214+
constsetEditorRef=(node:ReactQuill|null)=>{
215+
(editorRefasany).current=nodeasany;
216+
setEditorReady(!!node);
217+
};
218+
219+
constgetQuill=()=>(editorRef.currentasany)?.getEditor?.();
220+
221+
consttryParseDelta=(v:unknown)=>{
222+
if(!v)returnnull;
223+
if(typeofv==="string"){
224+
try{
225+
constd=JSON.parse(v);
226+
returnArray.isArray(d?.ops) ?d :null;
227+
}catch{returnnull;}
228+
}
229+
if(typeofv==="object"&&Array.isArray((vasany).ops))returnvasany;
230+
returnnull;
231+
};
232+
210233
constisTypingRef=useRef(0);
211234

212235
constdebounce=INPUT_DEFAULT_ONCHANGE_DEBOUNCE;
213236

214237
constoriginOnChangeRef=useRef(props.onChange);
215238
originOnChangeRef.current=props.onChange;
216239

217-
constonChangeRef=useRef(
218-
(v:string)=>originOnChangeRef.current?.(v)
240+
constonChangeRef=useRef((html:string,deltaJSON:string,text:string)=>
241+
originOnChangeRef.current?.(html,deltaJSON,text)
219242
);
220243

221244
// react-quill will not take effect after the placeholder is updated
@@ -235,7 +258,7 @@ function RichTextEditor(props: IProps) {
235258
(editor.scroll.domNodeasHTMLElement).tabIndex=props.tabIndex;
236259
}
237260
}
238-
},[props.tabIndex,key]);// Also re-run when key changes due to placeholder update
261+
},[props.tabIndex,key]);
239262

240263
constcontains=(parent:HTMLElement,descendant:HTMLElement)=>{
241264
try{
@@ -248,19 +271,26 @@ function RichTextEditor(props: IProps) {
248271
returnparent.contains(descendant);
249272
};
250273

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

257275
useEffect(()=>{
258-
letfinalValue=props.value;
259-
if(!/^<\w+>.+<\/\w+>$/.test(props.value)){
260-
finalValue=`<p>${props.value}</p>`;
276+
constq=getQuill();
277+
if(!q){
278+
return;
261279
}
262-
setContent(finalValue);
263-
},[props.value]);
280+
281+
constasDelta=tryParseDelta(props.value);
282+
if(asDelta){
283+
q.setContents(asDelta,"api");
284+
consthtml=q.root?.innerHTML??"";
285+
setContent(html);
286+
return;
287+
}
288+
constv=props.value??"";
289+
constlooksHtml=/<\/?[a-z][\s\S]*>/i.test(v);
290+
consthtml=looksHtml ?v :`<p class="">${v}</p>`;
291+
setContent(html);
292+
},[props.value,editorReady]);
293+
264294

265295
consthandleClickWrapper=(e:React.MouseEvent<HTMLDivElement>)=>{
266296
// grid item prevents bubbling, quill can't listen to events on document.body, so it can't close the toolbar drop-down box
@@ -288,7 +318,7 @@ function RichTextEditor(props: IProps) {
288318
<Suspensefallback={<Skeleton/>}>
289319
<ReactQuillEditor
290320
key={key}
291-
ref={editorRef}
321+
ref={setEditorRef}
292322
bounds={`#${id}`}
293323
modules={{
294324
toolbar:JSON.parse(props.toolbar),
@@ -297,23 +327,39 @@ function RichTextEditor(props: IProps) {
297327
value={content}
298328
placeholder={props.placeholder}
299329
readOnly={props.readOnly}
300-
onChange={handleChange}
330+
onChange={(html,_delta,source,editor)=>{
331+
setContent(html);
332+
constquill=editorRef.current?.getEditor?.();
333+
constfullDelta=quill?.getContents?.()??{ops:[]};
334+
consttext=quill?.getText?.()??"";
335+
onChangeRef.current(html,JSON.stringify(fullDelta),text);
336+
}}
301337
/>
302338
</Suspense>
303339
</Wrapper>
304340
);
305341
}
306342

307343
constRichTextEditorCompBase=newUICompBuilder(childrenMap,(props)=>{
344+
constpropsRef=useRef(props);
345+
propsRef.current=props;
346+
308347
constdebouncedOnChangeRef=useRef(
309-
debounce((value:string)=>{
310-
props.value.onChange(value);
311-
props.onEvent("change");
312-
},1000)
348+
debounce((html:string,deltaJSON:string,text:string)=>{
349+
propsRef.current.value.onChange(html);
350+
propsRef.current.delta.onChange(deltaJSON);
351+
propsRef.current.onEvent("change");
352+
},500)
313353
);
314354

315-
consthandleChange=(value:string)=>{
316-
debouncedOnChangeRef.current?.(value);
355+
useEffect(()=>{
356+
return()=>{
357+
debouncedOnChangeRef.current?.cancel();
358+
};
359+
},[]);
360+
361+
consthandleChange=(html:string,deltaJSON:string,text:string)=>{
362+
debouncedOnChangeRef.current?.(html,deltaJSON,text);
317363
};
318364

319365
return(
@@ -379,6 +425,7 @@ class RichTextEditorCompAutoHeight extends RichTextEditorCompBase {
379425

380426
exportconstRichTextEditorComp=withExposingConfigs(RichTextEditorCompAutoHeight,[
381427
newNameConfig("value",trans("export.richTextEditorValueDesc")),
428+
newNameConfig("delta",trans("export.richTextEditorDeltaDesc")),
382429
newNameConfig("readOnly",trans("export.richTextEditorReadOnlyDesc")),
383430
newNameConfig("hideToolbar",trans("export.richTextEditorHideToolBarDesc")),
384431
NameConfigHidden,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp