MohamedRejeb / compose-rich-editor

A Rich text editor library for both Jetpack Compose and Compose Multiplatform, fully customizable, supports HTML and Markdown.
https://mohamedrejeb.github.io/compose-rich-editor/
Apache License 2.0
1.12k stars 70 forks source link

Bring signature of RichTextEditor more inline with normal TextFields #95

Open ChrisTitos opened 1 year ago

ChrisTitos commented 1 year ago

Hi,

We are looking into your library to integrate in our app, and use it in our forms. The library looks great and seems to support all our needs.

However there is one thing now that we are struggling with a bit.

Our use case is that the editor is in a form with other textfields, and the content of the form input fields is controlled somewhere else (a ViewModel) This works great for normal Compose inputs, like the TextField where we have a value and onValueChange.

In the current setup of the library we need to use rememberRichTextState and then manually call setHTML in a LaunchedEffect, which already feels strange. And I don't see a way to continuously update the state in the view model, since I do not see an equivalent of onValueChange. I only see the method toHTML which needs to be called manually on the state object.

I see you had something like this before in the pre-v1.0 versions but you deprecated this.

Our ideal structure would be to be able to do something like this:

OurCustomizedRichTextEditor(value, onValueChange) {
  RichTextToolbar(richTextState) //to show the buttons
  val richTextState = rememberRichTextState(value, onValueChange) //somehow set HTML as input, and get it as output
  RichTextEditor( richTextState) 
}

Where the input and output would HTML (or other options depending on what the someone wants, our use case is HTML). This way it can be more or less a drop-in replacement for normal Compose TextFields

What do you suggest? Is something like this already possible?

I think this is similar to #66

MohamedRejeb commented 1 year ago

Hi, You are right, I'm thinking of adding some public APIs to register a listener. There's something similar but it's internal, for now there's a possible workaround.

LaunchedEffect(state.annotatedString) {
    // This is going to be called after any change of the text
    val html = state.toHtml()
}

Give it a try and let me know if it works and I'll work on providing a better approach ASAP

ChrisTitos commented 1 year ago

Thanks for the quick reply. We'll give the workaround a try.

ChrisTitos commented 7 months ago

Hi,

Is this still a thing you plan to add?

We currently have the following structure with the work around mentioned above:

OurCustomizedRichTextEditor(value, onValueChange) {

  val richTextState = rememberRichTextState() 

 LaunchedEffect(value) {
      richTextState.setHtml(value ?: "")
  }

  LaunchedEffect(state.annotatedString) {
     val html = richTextState.toHtml()
     onValueChange(html) //propagate new value back up
  }
  RichTextEditor( richTextState) 
}

However this results in very buggy behavior. Things I noticed:

The above things don't happen when I don't call onValueChange.

ChrisTitos commented 6 months ago

FYI I fixed my issues in the comment above by not always calling setHTML, only doing it when the incoming value differs from the one in the state.

OurCustomizedRichTextEditor(value, onValueChange) {

  val richTextState = rememberRichTextState() 

 LaunchedEffect(value) {
      //preventing buggy behavior in the rich text editor,
      //basically we try not to touch the richTextState
      if (richTextState.toHtml() != value) {
            richTextState.setHtml(value ?: "")
        }
  }

  LaunchedEffect(state.annotatedString) {
     val html = richTextState.toHtml()
     onValueChange(html) //propagate new value back up
  }
  RichTextEditor( richTextState) 
}
MohamedRejeb commented 6 months ago

Hello, Hopefully this will be added soon. I'm still thinking of the type of data that will be passed with the onValueChange, either AnnotatedString or a tree representation of the rich text.