GithubHelp home page GithubHelp logo

mohamedrejeb / compose-rich-editor Goto Github PK

View Code? Open in Web Editor NEW
883.0 9.0 55.0 1.93 MB

A Rich text editor library for both Jetpack Compose and Compose Multiplatform, fully customizable, supports HTML and Markdown.

Home Page: https://mohamedrejeb.github.io/Compose-Rich-Editor/

License: Apache License 2.0

Kotlin 100.00%
android android-library compose compose-android compose-desktop compose-ios compose-multiplatform compose-ui compose-web kmp

compose-rich-editor's Introduction

Compose Rich Editor


License API Profile Maven Central

Compose Rich Editor Compose Rich Editor

A rich text editor library for both Jetpack Compose and Compose Multiplatform, fully customizable and supports the common rich text editor features

  • Multiplatform: Compose Rich Editor supports Compose Multiplatform (Android, iOS, Desktop, Web).
  • Easy to use: Compose Rich Editor's API leverages Kotlin's language features for simplicity and minimal boilerplate.
  • WYSIWYG: Compose Rich Editor is a WYSIWYG editor that supports the most common text styling features.

Download

Maven Central

Compose Rich Editor is available on mavenCentral().

K1

implementation("com.mohamedrejeb.richeditor:richeditor-compose:1.0.0-rc05")

K2

implementation("com.mohamedrejeb.richeditor:richeditor-compose:1.0.0-rc05-k2")

Quick Start

RichTextState

Use RichTextEditor composable to create a rich text editor.

The RichTextEditor composable requires a RichTextState to manage the editor's state.

To create a RichTextState, use the rememberRichTextState function:

val state = rememberRichTextState()

RichTextEditor(
    state = state,
)

Styling Spans

To style spans, RichTextState provides toggleSpanStyle method:

// Toggle a span style.
richTextState.toggleSpanStyle(SpanStyle(fontWeight = FontWeight.Bold))

To get the current span style of the selection, use RichTextState.currentSpanStyle:

// Get the current span style.
val currentSpanStyle = richTextState.currentSpanStyle
val isBold = currentSpanStyle.fontWeight = FontWeight.Bold

Styling Paragraphs

To style paragraphs, RichTextState provides toggleParagraphStyle method:

// Toggle a paragraph style.
richTextState.toggleParagraphStyle(ParagraphStyle(textAlign = TextAlign.Center))

To get the current paragraph style of the selection, use RichTextState.currentParagraphStyle:

// Get the current paragraph style.
val currentParagraphStyle = richTextState.currentParagraphStyle
val isCentered = currentParagraphStyle.textAlign = TextAlign.Center

Add links

To add links, RichTextState provides addLink method:

// Add link after selection.
richTextState.addLink(
    text = "Compose Rich Editor",
    url = "https://github.com/MohamedRejeb/Compose-Rich-Editor"
)

To get if the current selection is a link, use RichTextState.isLink:

// Get if the current selection is a link.
val isLink = richTextState.isLink

By default, links will be opened by your platform's UriHandler, if however you want to handle the links on your own, you can override the composition local as such:

val myUriHandler by remember {
    mutableStateOf(object : UriHandler {
        override fun openUri(uri: String) {
            // Handle the clicked link however you want
        }
    })
}
CompositionLocalProvider(LocalUriHandler provides myUriHandler) {
    RichText( ... )
}

Add Code Blocks

To add code blocks, RichTextState provides toggleCodeSpan method:

// Toggle code span.
richTextState.toggleCodeSpan()

To get if the current selection is a code block, use RichTextState.isCodeSpan:

// Get if the current selection is a code span.
val isCodeSpan = richTextState.isCodeSpan

Ordered and Unordered Lists

You can add ordered and unordered lists using RichTextState:

// Toggle ordered list.
richTextState.toggleOrderedList()

// Toggle unordered list.
richTextState.toggleUnorderedList()

You can get if the current selection is an ordered or unordered list, using RichTextState:

// Get if the current selection is an ordered list.
val isOrderedList = richTextState.isOrderedList

// Get if the current selection is an unordered list.
val isUnorderedList = richTextState.isUnorderedList

Customizing the rich text configuration

Some of the rich text editor's features can be customized, such as the color of the links and the code blocks.

richTextState.config.linkColor = Color.Blue
richTextState.config.linkTextDecoration = TextDecoration.Underline
richTextState.config.codeSpanColor = Color.Yellow
richTextState.config.codeSpanBackgroundColor = Color.Transparent
richTextState.config.codeSpanStrokeColor = Color.LightGray

HTML import and export

To convert HTML to RichTextState, use RichTextState.setHtml method:

val html = "<p><b>Compose Rich Editor</b></p>"
richTextState.setHtml(html)

To convert RichTextState to HTML, use RichTextState.toHtml method:

val html = richTextState.toHtml()

Markdown import and export

To convert Markdown to RichTextState, use RichTextState.setMarkdown method:

val markdown = "**Compose** *Rich* Editor"
richTextState.setMarkdown(markdown)

To convert RichTextState to Markdown, use RichTextState.toMarkdown method:

val markdown = richTextState.toMarkdown()

Check out Compose Rich Editor's full documentation for more details.

Web live demo

You can try out the web demo here.

Contribution

If you've found an error in this sample, please file an issue.
Feel free to help out by sending a pull request ❤️.

Code of Conduct

Find this library useful? ❤️

Support it by joining stargazers for this repository. ⭐
Also, follow me on GitHub for more libraries! 🤩

You can always

License

Copyright 2023 Mohamed Rejeb

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

compose-rich-editor's People

Contributors

azimmuradov avatar donovan-fournier avatar ganfra avatar garretyoder avatar janseeger avatar medvedevaelena avatar mohamedrejeb avatar t8rin avatar vaibhav2002 avatar wakaztahir avatar wavesonics avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

compose-rich-editor's Issues

RichTextState.setHtml() not working on release build (isDebuggable = false)

There is a problem with the RichTextState.setHtml() method on non-debuggable builds.
No text is visible in RichText or BasicRichTextEditor when I use this method.
setText() is working correctly in the same type of build.

In builds with isDebuggable = true everything is working fine.

Sample code:

val html = "<p><b>Compose Rich Editor</b></p>"
val richTextState = rememberRichTextState()
richTextState.setHtml(html)

RichText(state = richTextState)

Some RichTextStyle(s) are not recognized on creating RichTextValue from HTML String

The RichTextStyle(s) that are not recognized are the styles created using the object : RichTextStyle.
The comparison between RichTextStyle(s) should be improved to be something like comparing SpanStyle(s) and making a SpanStyle value as a member for the RichTextStyle interface.
Also there's some intentions to totally remove the RichTextStyle and simply use the SpanStyle to simplify handling these cases.

another java.lang.StringIndexOutOfBoundsException

java.lang.StringIndexOutOfBoundsException: length=0; index=1 at java.lang.String.substring(String.java:2060) at com.mohamedrejeb.richeditor.model.RichTextState.handleAddingCharacters(RichTextState.kt:670) at com.mohamedrejeb.richeditor.model.RichTextState.onTextFieldValueChange$richeditor_compose_release(RichTextState.kt:510) at com.mohamedrejeb.richeditor.ui.BasicRichTextEditorKt$BasicRichTextEditor$12$1.invoke(BasicRichTextEditor.kt:338) at com.mohamedrejeb.richeditor.ui.BasicRichTextEditorKt$BasicRichTextEditor$12$1.invoke(BasicRichTextEditor.kt:335) at androidx.compose.foundation.text.BasicTextFieldKt$BasicTextField$8$1.invoke(BasicTextField.kt:292) at androidx.compose.foundation.text.BasicTextFieldKt$BasicTextField$8$1.invoke(BasicTextField.kt:290) at androidx.compose.foundation.text.TextFieldState$onValueChange$1.invoke(CoreTextField.kt:849) at androidx.compose.foundation.text.TextFieldState$onValueChange$1.invoke(CoreTextField.kt:844) at androidx.compose.foundation.text.TextFieldDelegate$Companion.onEditCommand$foundation_release(TextFieldDelegate.kt:205) at androidx.compose.foundation.text.TextFieldDelegate$Companion$restartInput$1.invoke(TextFieldDelegate.kt:254) at androidx.compose.foundation.text.TextFieldDelegate$Companion$restartInput$1.invoke(TextFieldDelegate.kt:251) at androidx.compose.ui.text.input.TextInputServiceAndroid$createInputConnection$1.onEditCommands(TextInputServiceAndroid.android.kt:128) at androidx.compose.ui.text.input.RecordingInputConnection.endBatchEditInternal(RecordingInputConnection.android.kt:157) at androidx.compose.ui.text.input.RecordingInputConnection.addEditCommandWithBatch(RecordingInputConnection.android.kt:131) at androidx.compose.ui.text.input.RecordingInputConnection.commitText(RecordingInputConnection.android.kt:177) at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:339) at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:89) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7386) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)

Found another StringIndexOutOfBoundsException, which occours by adding two linebreaks (enter) in an empty text field.

BTW Thank you for this nice Libary. This makes the developmet for my project much easier.

Feature request: Nested lists

Can you provide some guide to implement nested list elements.
Eg.

  1. First item
  2. Second item
    1. First nested item
    2. Second nested item

Implementing new core foundation

Currently I'm working on a new core foundation for the library based on nodes representation for the rich text.
Here's some benefits of this change:

  • Improve scalability of the library
  • Implement new features more easily
  • Bug fixes
  • Improve HTML output (Shorter)
  • Performance improvements
    ...

This update will bring breaking changes so we are going to move from 0.x to 1.x
The work is in its last stages, it will be ready soon

Support String Operations on Rich Text while retaining styles

User can perform following operations on the text when its a string

  1. User can remove a text range
  2. User can replace a text range
  3. User can add text at an index

These operations are easier because text is a string , you can perform all these operations easily because String is a perfect representation of the Text user wrote , But not in the case of Rich Text

If you want to remove a range of text , You know the indexes , startIndex & endIndex

The problem is retaining styles

I propose that the following methods be added to RichTextState and be exposed publicly

  1. removeTextRange(startIndex : Int,endIndex : Int) : Boolean
  2. replaceTextRange(startIndex : Int,endIndex : Int,replacement : AnnotatedString) : Boolean
  3. addTextAtIndex(index : Int,text : AnnotatedString) : Boolean

When user calls these methods , text range is removed / replaced , or text is added at an index , Without affecting the styles of other text

We can create full toolbar like this

It would nice to have support for full toolbar

fun RichTextStyleRow(
    modifier: Modifier = Modifier,
    value: RichTextValue,
    onValueChanged: (RichTextValue) -> Unit,
) {
    LazyRow(
        modifier = modifier
    ) {
        item {
            RichTextStyleButton(
                style = RichTextStyle.Bold,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_bold,
                tint = <TintColor>
            )
        }

        item {
            RichTextStyleButton(
                style = RichTextStyle.Italic,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_italic,
                tint = <TintColor>
            )
        }
    }
    LazyRow(
        modifier = modifier
    ) {
        item {
            RichTextStyleButton(
                style = RichTextStyle.H1,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_heading_1,
                tint = <TintColor>
            )
        }

        item {
            RichTextStyleButton(
                style = RichTextStyle.H2,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_heading_2,
                tint = <TintColor>
            )
        }

        item {
            RichTextStyleButton(
                style = RichTextStyle.H3,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_heading_3,
                tint = <TintColor>
            )
        }

        item {
            RichTextStyleButton(
                style = RichTextStyle.H4,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_heading_4,
                tint = <TintColor>
            )
        }
        item {
            RichTextStyleButton(
                style = RichTextStyle.H5,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_heading_5,
                tint = <TintColor>
            )
        }
        item {
            RichTextStyleButton(
                style = RichTextStyle.H6,
                value = value,
                onValueChanged = onValueChanged,
                icon = R.drawable.ic_heading_6,
                tint = <TintColor>
            )
        }
    }
}
----------------
@Composable
fun RichTextStyleButton(
    style: RichTextStyle,
    value: RichTextValue,
    onValueChanged: (RichTextValue) -> Unit,
    icon: ImageVector,
    tint: Color? = null
) {
    IconButton(
        modifier = Modifier
            .focusProperties { canFocus = false },
        onClick = {
            onValueChanged(value.toggleStyle(style))
        },
        colors = IconButtonDefaults.iconButtonColors(
            contentColor = if (value.currentStyles.contains(style)) {
                MaterialTheme.colorScheme.onPrimary
            } else {
                MaterialTheme.colorScheme.onBackground
            },
        ),
    ) {
        Icon(
            icon,
            contentDescription = icon.name,
            tint = if (value.currentStyles.contains(style)) tint
                ?: LocalContentColor.current else <DiasabledColor>
        )
    }
}

@Composable
fun RichTextStyleButton(
    style: RichTextStyle,
    value: RichTextValue,
    onValueChanged: (RichTextValue) -> Unit,
    icon: Int,
    tint: Color? = null
) {
    IconButton(
        modifier = Modifier
            .size(30.dp)
            .focusProperties { canFocus = false },
        onClick = {
            onValueChanged(value.toggleStyle(style))
        },
    ) {
        Icon(
            painter = painterResource(id = icon),
            contentDescription = "",
            tint = if (value.currentStyles.contains(style)) tint
                ?: LocalContentColor.current else <DiasabledColor>
        )
    }
}
--------------

Allow implementing editor actions differently

Currently the editor options support addCode, addBold, This is like a toggle which turns on and user keeps going with the styles

However some people prefer editing differently , like myself , for example when I click bold , I want editor to grab the current word and just make it bold , unless I have a selection, This also allows editor to have no state other than selection, Not that previous API shouldn't be the way, but there's no way currently to do the above.

So Editor State of isBold on currently , isItalic on should be separated from the editor and allowed to have a different state

I implemented this initially in my editor which doesn't retain styles

https://github.com/Qawaz/markdown-compose/blob/5293904088ab9ace4d4b1e7e7788437cadd513d6/md-compose-core/src/commonMain/kotlin/com/wakaztahir/markdowncompose/editor/utils/TextFormatter.kt#L121

Allow storing Editor Value State somewhere else

rememberRichTextState() can only be called inside a compose context

We should be able to do something like this

val value = RichTextEditorValue() // this doesn't need to be remembered
val state = rememberRichTextState(myValue)

I know something like this exists in the previous deprecated API but I am talking about current implementation that supports paragraph , Since idea of separating the core is already there , This could be part of core. Which should be done when the implementation of editor is done

Add HTML import and export support

  • Support creating RichTextValue from a html string
  • Support exporting RichTextValue as html string

This could be helpful specially when dealing with api and you need to share the rich text content between mobile and web so it needs it be saved as html in the database.

Multiple paragraphs Not working

Here's the code where html

<p style="text-align: left;"><span style="font-weight: 700;">A Story</span></p><p style="text-align: left;"><span style="font-weight: 700;"></span></p><ul><li style="text-align: left;">something something something</li><li style="text-align: left;">Something something something</li><li style="text-align: left;">Something something something</li><li style="text-align: left;">Something something something</li></ul><p style="text-align: left;"></p><p style="text-align: center;">somethingsomething something something</p><p style="text-align: left;">something tomorrow something</p><p style="text-align: left;"><span style="font-weight: 700;">something like this</span></p><p style="text-align: left;"><span style="font-weight: 700;"></span></p><p style="text-align: right;"><span style="font-weight: 700;">something something something </span><span style="font-style: italic;">somethingsomething something something</span></p>

This html was generated for some text I wrote with multiple paragraphs with different alignment

Not able to run for ios

Hi i added a build config for ios project using following config given in screen shot
Screenshot 2023-05-09 at 12 36 10 PM

But i am not able to build, getting following error:
`** BUILD FAILED **

The following build commands failed:
SwiftCompile normal arm64 Compiling\ ComposeViewControllerToSwiftUi.swift /Users/sunil/AndroidStudioProjects/Compose-Rich-Editor/sample/ios/Compose\ Rich\ Editor/ComposeViewControllerToSwiftUi.swift (in target 'Compose Rich Editor' from project 'Compose Rich Editor')
SwiftCompile normal arm64 /Users/sunil/AndroidStudioProjects/Compose-Rich-Editor/sample/ios/Compose\ Rich\ Editor/ComposeViewControllerToSwiftUi.swift (in target 'Compose Rich Editor' from project 'Compose Rich Editor')
(2 failures)`

complete logs file:
logs.docx

Support Initializing / setting the RichTextState from TextFieldValue / Annotated String

Right now rememberRichTextState has no parameters , I would like to initialize rememberRichTextState via text field value / annotated string

There's also no function setTextFieldValue , setAnnotatedString , but there's setText

This would make it easier to replace OutlinedTextField with OutlinedTextEditor , since we only need to initialize / set the text field value to rich text state and provide rich text state to editor

Add mentions @ support

Provide easy ways to support mentions with @ in the Rich Editor:

  • Listener for the text written after the @
  • Highlight the mention text (optional)
  • Delete the mention text at once (optional)

Toggle selected text style

Is there a way to toggle the style of selected text?

Ex:
I type

foo bar

Then I select the foo and toggle the italic style, I expect it to become

foo bar

Richtext cursor fixed at position 0

I am trying to instantiate the remember delegate with a starting value when in the editing state. It always shows as an empty description state :/ Here's the code and a screenshot below:

var richTextValue by remember { mutableStateOf(RichTextValue.from(htmlStringFromBackend)) }

RichTextEditor(
    enabled = enabled,
    modifier = innerModifier.fillMaxWidth(),
    value = richTextValue,
    onValueChange = {
        richTextValue = it
    },
    colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White),
)

Screenshot 2023-06-12 at 1 08 39 PM

How can I fix this so it will start with loading in the data?

Support Immutable Data Structure

The initial importing and exporting using HTML or Markdown is good but its not the one that fits every requirement

Problem

Suppose I have a backend, I can store the output of this editor as HTML or Markdown , Now that goes to my database, I have a website which is built using React which needs to display this rich text in another editor which is built using React or Javascript, If I store it using HTML, well I must be able to parse and display the HTML exactly like this editor does otherwise differences will be introduced. If I store markdown, I will have to make sacrifices on features that markdown doesn't support, An immutable data structure makes it very easy

We make very clean, immutable data classes storing only primitive types like strings, representing the rich text in editor

Solution

A immutable data structure model must be created

Since data classes would be immutable, The structure will be clear so user knows all the types of models our editor has suppose ImmutableParagraph, ImmutableRichText(val isBold, ...)

The data structure would only contain properties that the editor supports and to methods to convert to the mutable data structure that is editable when editor is running

for example

internal data class ImmutableRichTextParagraph(
    val items : List<ImmutableRichItem>
){
    fun toRichTextParagraph() : RichTextParagraph {
        val para = RichTextParagraph()
        para.addSpans(items.map { it.toRichTextSpan() })
        return para
    }
}

In Kotlin, usually immutable classes don't start with immutable word and instead mutable classes have mutable in their names like List and MutableList, since mutable classes are already internal, This change could be made any time when the data structure is mature enough

Pros

  • Standardizes Everything in Immutable Data Classes that Rich Text Editor supports
  • This immutable data structure can be taken out and separated into core library
  • More export and import formats can be supported by just creating libraries that would convert to this immutable data structure
  • Clean code with better organization and structure

Cons

  • Maintain compatibility with previous versions of data structure (if supporting JSON serialization)
  • More code

Thoughts on Exposing Core Data Structure

The data structure must be separated out to another library core, The editor must make implementation dependency on core, so Users cannot access the data structure unless they explicitly specify a implementation dependency on the core library

This would solve

  • No need to have internal on each data class, making it unable to use with a solid use case
  • Hide data structure from users, so library API is not polluted and allow to work on the model until its stable

Where when the user gives HTML , The HTML parser parses the html to this immutable data structure, When markdown is given the parser converts to this immutable data structure

Supporting JSON Serialization

If users were to store the immutable model as json in their databases, We must maintain compatibility backwards

  • Renaming a property, we must use @JsonNames("previous_property_name") annotation from kotlinx.serialization on the new property
  • Removing a property, Either we must make sure user deserializes his json using the option ignoreUnknownKeys in kotlinx.serialization library, or we need to make it nullable and set its default value to null and make the property deprecated
  • Adding a property, No requirement, since if we added a property in new version of the library, user can only generate json with that property using the new version of the library, previous version of the library just cannot deserialize it

Let me know if you need any help, I can contribute

java.lang.StringIndexOutOfBoundsException

java.lang.StringIndexOutOfBoundsException: String index out of range: -2 at java.lang.String.substring(String.java:2064) at com.mohamedrejeb.richeditor.model.RichTextState.removeUnorderedList(RichTextState.kt:403) at com.mohamedrejeb.richeditor.model.RichTextState.toggleUnorderedList(RichTextState.kt:366)

Error occours for example if you inserting a list:

  • Point one
  • Point two

And than move the cursor to the very first position and than toggle list again.

Add Copy/Paste support for Rich Text

For now the copy/paste works the same as the normal TextField. It just copies and pastes non styles text.
I'm currently working on adding this feature

Add support for changing styles for texts initialized to RichTextValue

Ex: RichTextValue(text = "This lib is awesome")
This initialized text does not react to style changes

my code

    var body by remember { mutableStateOf(RichTextValue(text = "This lib is awesome")) }

    RichTextEditor(
            modifier = Modifier,
            value = body,
            onValueChange = onValueChange,
            textStyle = textStyle.copy(fontSize = textSize),
            colors = TextFieldDefaults.textFieldColors(
                focusedIndicatorColor = Color.Transparent,
                unfocusedIndicatorColor = Color.Transparent,
                backgroundColor = Color.Transparent
            ),
            maxLines = maxLines ?: Int.MAX_VALUE,
            singleLine = singleLine,
        )
     NotesEditorMenu(
            modifier = Modifier
                .inlineSpacingMedium()
                .bottomSpacing(),
            styleSelected = styleSelected.value,
            onStyleSelected = {
                styleSelected.value = it
            },
            onClickBoldStyle = {
                body = body.toggleStyle(RichTextStyle.Bold)
            },
            onClickUnderlineStyle = {
                body = body.toggleStyle(RichTextStyle.Underline)
            },
            onClickItalicStyle = {
                body = body.toggleStyle(RichTextStyle.Italic)
            },
            onClickMarkStyle = {
                body = body.toggleStyle(RichTextStyle.Mark)
            },
            onClickLeftAlign = {
                textAlign = TextAlign.Left
            },
            onClickRightAlign = {
                textAlign = TextAlign.Right
            },
            onClickCenterAlign = {
                textAlign = TextAlign.Center
            }
        )
bug.mp4

Export Android version

Hi there, great library. Thanks.
How do I export only Android version from this project?
Thanks.

Not worked toggleSpanStyle

Not worked toggleSpanStyle if you try set textDecoration like null.

Below my code for changing underline:
fun RichTextState.isUnderline(): Boolean = currentSpanStyle.textDecoration == TextDecoration.Underline
fun RichTextState.toggleUnderlineFont() { toggleSpanStyle( SpanStyle( textDecoration = if (isUnderline()) { null } else { TextDecoration.Underline } ) ) }

If i set textDecoration like Underline this is work, not work if i set null.

Problem with text selection.

When using RichTextEditor and trying to select text there is a lag and issues with the precision of selection.
The issue is especially noticeable when after selecting a single word by long press, I try to extend or contract the selection by dragging selection handles. Sometimes I can't move the handles at all.

Example

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.