Giter VIP home page Giter VIP logo

compose-richtext's Introduction

Hi there 👋

I'm currently working as a Software Engineer in Android Text Team at Google.

compose-richtext's People

Contributors

atulgpt avatar equationl avatar halilozercan avatar louiscad avatar morrisseyai avatar mr3y-the-programmer avatar msfjarvis avatar slahay avatar vitorpamplona avatar zach-klippenstein 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

compose-richtext's Issues

Clickable links in SelectionContainer are no longer clickable

Here's an example. With the SelectionContainer selecting the text is possible, but clicking the link does nothing. Without it, clicking the link works, but selecting text doesn't work of course:

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
import com.halilibo.richtext.markdown.Markdown
import com.halilibo.richtext.ui.RichText

fun main() {
    singleWindowApplication {
        LazyColumn {
            item {
                Text("Foo")
            }
            item {
                SelectionContainer {
                    RichText(modifier = Modifier.padding(vertical = 8.dp).fillMaxWidth()) {
                        Markdown("[Google](https://www.google.com)", onLinkClicked = { link ->
                            println(link)
                        })
                    }
                }
            }
        }
    }
}

Is there some other way to make text selectable or is this is a bug?

Support LaTeX ?

I've just found this awesome library. I love your attempt.

I hope that compose-richtext will support LaTeX soon.

Code Viewer

Maybe this feature request should be for another artifact but have you thought to create a Code Viewer?

Missing dependencies

Cause 1: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find org.jetbrains.compose.runtime:runtime:1.2.0-alpha01-dev683.
Searched in the following locations:

Add Gradle Kotlin DSL setup guide

configurations.all {
  resolutionStrategy.eachDependency {
    if (requested.group.contains("org.jetbrains.compose")) {
      val groupName = requested.group.replace("org.jetbrains.compose", "androidx.compose")
      useTarget("$groupName:${requested.name}:${Compose.version}")
    }
  }
}

Linkify?

It'd be really nice to have linkify for urls in Markdown.

richtext-commonmark:0.16.0 depends on desktop-jvm-linux-x64

It looks like implementation("com.halilibo.compose-richtext:richtext-commonmark:0.16.0")

transitively pulls in the linux skiko runtime org.jetbrains.compose.desktop:desktop-jvm-linux-x64:1.2.0 not also on Linux, but also on Windows. I think that's broken. First I thought I had some thing misconfigured, but I can also track this down to the *.module files published on Central.

richtext-commonmark-0.16.0.module seems to declare a dependency on richtext-commonmark-jvm:

    {
      "name": "jvmApiElements-published",
      "attributes": {
        "org.gradle.category": "library",
        "org.gradle.libraryelements": "jar",
        "org.gradle.usage": "java-api",
        "org.jetbrains.kotlin.platform.type": "jvm"
      },
      "available-at": {
        "url": "../../richtext-commonmark-jvm/0.16.0/richtext-commonmark-jvm-0.16.0.module",
        "group": "com.halilibo.compose-richtext",
        "module": "richtext-commonmark-jvm",
        "version": "0.16.0"
      }
    },
    {
      "name": "jvmRuntimeElements-published",
      "attributes": {
        "org.gradle.category": "library",
        "org.gradle.libraryelements": "jar",
        "org.gradle.usage": "java-runtime",
        "org.jetbrains.kotlin.platform.type": "jvm"
      },
      "available-at": {
        "url": "../../richtext-commonmark-jvm/0.16.0/richtext-commonmark-jvm-0.16.0.module",
        "group": "com.halilibo.compose-richtext",
        "module": "richtext-commonmark-jvm",
        "version": "0.16.0"
      }
    }

and in turn richtext-commonmark-jvm-0.16.0.module declares a dependency on org.jetbrains.compose.desktop:desktop-jvm-linux-x64:1.2.0:

        {
          "group": "org.jetbrains.compose.desktop",
          "module": "desktop-jvm-linux-x64",
          "version": {
            "requires": "1.2.0"
          }
        },

It's also verifiable on the command line by showing the dependencies using ./gradlew dependencies where the dependency shows up on Linux and Windows:

…
\--- com.halilibo.compose-richtext:richtext-commonmark:0.16.0
     \--- com.halilibo.compose-richtext:richtext-commonmark-jvm:0.16.0
          +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 1.7.20 (*)
          +--- com.halilibo.compose-richtext:richtext-ui:0.16.0
          |    \--- com.halilibo.compose-richtext:richtext-ui-jvm:0.16.0
          |         +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 1.7.20 (*)
          |         +--- org.jetbrains.compose.ui:ui-tooling-preview-desktop:1.2.0 -> 1.2.1 (*)
          |         +--- org.jetbrains.compose.runtime:runtime:1.2.0 -> 1.2.1 (*)
          |         +--- org.jetbrains.compose.foundation:foundation:1.2.0 -> 1.2.1 (*)
          |         \--- org.jetbrains.compose.ui:ui-util:1.2.0 -> 1.2.1 (*)
          +--- org.jetbrains.compose.desktop:desktop-jvm-linux-x64:1.2.0  <------------ here
          |    \--- org.jetbrains.compose.desktop:desktop:1.2.0 -> 1.2.1 (*)
 …

Here is a minimal example projects that produces the problem: https://github.com/sebkur/test-compose-for-desktop-richtext (it's a simple side by side markdown editor that shows the rendered markdown on the right side next to the source code, see screenshot below)

Screenshot

The program runs fine on Windows, however when producing an uber-jar or msi release, the native libraries are included for both Windows and Linux then on a Windows build. Given the sheer size of the native skiko library, this is rather suboptimal.

$ unzip -l build/compose/jars/Test-linux-x64-1.0.0.jar | grep skiko-
 16768000  2022-10-31 19:56   skiko-windows-x64.dll                                                                                                                                                             
       64  2022-10-31 19:56   skiko-windows-x64.dll.sha256                                                                                                                                                      
 29463280  2022-09-30 08:56   libskiko-linux-x64.so                                                                                                                                                             
       64  2022-09-30 08:56   libskiko-linux-x64.so.sha256 

That's almost 30mb native code that gets packaged into the windows binaries.

I can work around the issue by excluding the linux runtime:

                implementation("com.halilibo.compose-richtext:richtext-commonmark:0.16.0") {
                    exclude(group = "org.jetbrains.skiko", module = "skiko-awt-runtime-linux-x64")
                }

Support compose for desktop

Probably requires making this library MPP, but that should be about it. The same implementation should work out of the box.

Crash when using Slideshow

Crash when using slideshow library and latest compose version (currently 1.1.0-alpha03). Rest richtext libraries are working correctly.

java.lang.NoSuchMethodError: No static method AnimatedVisibility(ZLandroidx/compose/ui/Modifier;Landroidx/compose/animation/EnterTransition;Landroidx/compose/animation/ExitTransition;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V in class Landroidx/compose/animation/AnimatedVisibilityKt; or its super classes (declaration of 'androidx.compose.animation.AnimatedVisibilityKt' appears in /data/data/xxx/code_cache/.overlay/base.apk/classes.dex)
        at com.zachklipp.richtext.ui.slideshow.SlideshowKt$Slideshow$5$1$1.invoke(Slideshow.kt:165)
        at com.zachklipp.richtext.ui.slideshow.SlideshowKt$Slideshow$5$1$1.invoke(Slideshow.kt:134)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:215)
        at androidx.compose.material.TextKt.ProvideTextStyle(Text.kt:252)
        at com.zachklipp.richtext.ui.slideshow.SlideshowKt$Slideshow$5$1.invoke(Slideshow.kt:134)
        at com.zachklipp.richtext.ui.slideshow.SlideshowKt$Slideshow$5$1.invoke(Slideshow.kt:133)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:215)
        at com.zachklipp.richtext.ui.slideshow.SlideshowKt.Slideshow(Slideshow.kt:130)
        at ...

Heading color remains black in Dark Mode

This behavior can easily be observed in RichText Sample. When Dark Mode is enabled, headings do not reflect the change in color. Upon initial investigation, I've found that the problem might be related to fun resolveDefaults(style: TextStyle, direction: LayoutDirection) function.

When passed textStyle contains Unspecified color, it defaults to

color = style.color.useOrElse { DefaultColor },

where DefaultColor is Black. That clearly doesn't respect theming.

Extra blank line at the end of Markdown code blocks

Running the Android sample, we can see that rendered markdown code blocks have an extra blank line at the end:

Calling trim() on the parsed string seems to fix the problem:

is AstIndentedCodeBlock -> {
      CodeBlock(text = astNodeType.literal.trim())
}
is AstFencedCodeBlock -> {
      CodeBlock(text = astNodeType.literal.trim())
}

Refine Tables from RichText under a new module

Table API under RichText is very limited at this time due to fixed layout constraints.

Spreadsheet like tables usually require unlimited horizontal and vertical scroll, while rows and columns have varying range of layout constraints on their own. While allowing simple Tables like a word document, new Table API should offer high level of customization to even express Excel like formulas.

Enable https for the documentation website

Hello, I think ensuring SSL is used for the doc website is a low hanging fruit and ensures the page content can not get tampered with via MITM (machine/man in the middle).

It should just be a checkbox to tick in the GitHub project settings.

How can I resize an image

I'm using an image from assets folder
![image](file:///android_asset/image.jpg "Image")

I tried to resize my image like this 👉 ![image](file:///android_asset/image.jpg =100x20 "Image"), i also tried with HTML, but it doesn't work.

InlineContent for RichTextString should expose PlaceholderVerticalAlign parameter

Currently this parameter is hard-coded to AboveBaseline. However, a user might want to use Text as inline content and align the baseline between this inline-content and the line that it stands in.

Basically, changing InlineContent class to

public class InlineContent(
  internal val initialSize: (Density.() -> IntSize)? = null,
  internal val placeholderVerticalAlign: PlaceholderVerticalAlign = AboveBaseline,
  internal val content: @Composable Density.(alternateText: String) -> Unit
)

should suffice, granted that this new parameter is also passed while creating Placeholder.

Theming and text colors

I'm having some trouble figuring out how to change the color of the text rendered to match the current system theme.

I went through the issues and saw this: #12 however wether I'm using a dark or light theme, my paragraphs are always rendered in dark text.

I went as far as trying to override all styles manually like so:

@Composable
fun MarkdownComponent(markdown: String) {
    RichText(
        modifier = Modifier
            .padding(16.dp)
            .verticalScroll(state = scrollState),
        style = RichTextStyle()
            .resolveDefaults()
            .run {
                copy(
                    headingStyle = { level, textStyle ->
                        when (level) {
                            0 -> TextStyle(
                                fontSize = 36.sp,
                                fontWeight = FontWeight.Bold,
                                color = textStyle.color.w,
                            )
                            1 -> TextStyle(
                                fontSize = 26.sp,
                                fontWeight = FontWeight.Bold,
                                color = textStyle.color.w,
                                )
                            2 -> TextStyle(
                                fontSize = 22.sp,
                                fontWeight = FontWeight.Bold,
                                color = textStyle.color.copy(alpha = .7F).w
                            )
                            3 -> TextStyle(
                                fontSize = 20.sp,
                                fontWeight = FontWeight.Bold,
                                fontStyle = FontStyle.Italic,
                                    color = textStyle.color.w,

                                )
                            4 -> TextStyle(
                                fontSize = 18.sp,
                                fontWeight = FontWeight.Bold,
                                color = textStyle.color.copy(alpha = .7F).w
                            )
                            5 -> TextStyle(
                                fontWeight = FontWeight.Bold,
                                color = textStyle.color.copy(alpha = .5f).w
                            )
                            else -> textStyle.copy(color = textStyle.color.w)
                        }
                    },
                    stringStyle = stringStyle?.copy(
                        boldStyle = stringStyle?.boldStyle?.copy(color = Color.White),
                        italicStyle = stringStyle?.italicStyle?.copy(color = Color.White),
                        underlineStyle = stringStyle?.underlineStyle?.copy(color = Color.White),
                        strikethroughStyle = stringStyle?.strikethroughStyle?.copy(color = Color.White),
                        subscriptStyle = stringStyle?.subscriptStyle?.copy(color = Color.White),
                        superscriptStyle = stringStyle?.superscriptStyle?.copy(color = Color.White),
                        codeStyle = stringStyle?.codeStyle?.copy(color = Color.White),
                        linkStyle = stringStyle?.linkStyle?.copy(color = Color.White),
                    )
                )
            },
    ) {
        Markdown(
            content = markdown
        )
    }
}

private val Color.w get() = copy(red = 1f, green = 1f, blue = 1f)

Which works for everything but regular paragraphs. Pointers much appreciated.

Introduce text styling API

Compose provides a rich API for styling text and paragraphs, as well as doing things like showing unlike composables and reading attributes about laid-out text. This library should provide a higher-level API on top of that which allows applying abstract styles that can be resolved to lower-level compose concepts using the rich text style.

For example, a user can create a string with ranges that are bold, italic, underlined, code, etc and the rich text style will determine exactly how "bold" or "code" text should be styled (specific weight, font, coloring, etc) as well as any inline semantic metadata (link actions, image descriptions, etc).

The Compose API for styling text is AnnotatedString and AnnotatedString.Builder. This library will provide a parallel pair of types (RichTextString(.Builder)?) with a similar API at a higher level, and a way to resolve such strings to AnnotatedStrings given a rich text style. Some features, such as inline images and links, aren't expressible using only AnnotatedString and require coordination with the actual Text composable, so this library will also provide a wrapper composable that accepts a RichTextString.

API

@Immutable
class RichTextString(text: String) {
  operator fun plus(other: RichTextString)

  sealed class Format {
    object Bold : Format()
    object Italic : Format()
    object Underline : Format()
    object Strikethrough : Format()
    object Subscript : Format()
    object Superscript : Format()
    object Code : Format()
    data class Link(val onClick: () -> Unit) : Format()
    // The text inside image ranges is used as the alt text/content description.
    // TODO: Need a way to calculate the size before composing.
    data class Image(val image: @Composable () -> Unit) : Format()
  }

  class Builder(from: RichTextString = RichTextString ("")) {
    fun addFormat(format: Format, start: Int, end: Int)
    fun pushFormat(format: Format): Int
    fun pop()
    fun pop(index: Int)
    fun append(text: String)
    // Provides access to the underlying builder, which can be used to add arbitrary formatting, including mixed with formatting from this Builder.
    fun withAnnotatedString(block: AnnotatedString.Builder.() -> Unit)
  }
}

// TODO: Terrible name, needs work.
@Composable fun RichTextText(
  text: RichTextString,
  modifier: Modifier = Modifier,
  style: RichTextStyle = RichTextStyleAmbient.current
)

Implementation

Stores an AnnotatedString internally along with all the parameterized formats (links, images). Formats are represented as annotation ranges. Parameterized formats are given a UUID which allows their annotation tag to be mapped back to their format object.

The rendering composable passes the internal AnnotatedString through to Text, wraps with gesture filters for link interaction, wires up inline content, adds semantics data, etc.

Support for `CompositionLocalProvider`

I want to display my text with an alpha value dependent on its state. Usually, I would do it like shown here to wrap all composables which should be affected:

CompositionLocalProvider(LocalContentAlpha provides if(isDisabled) { ContentAlpha.high } else { ContentAlpha.disabled }) {
    RichText(
        modifier = Modifier.padding(8.dp),
    ) {
        Markdown(message.body)
    }
}

However, this solution does not work with RichText, so I found this alternative solution:

MaterialRichText(
    modifier = Modifier.alpha(if(isDisabled) { ContentAlpha.high } else { ContentAlpha.disabled })
) {
    RichText(
        modifier = Modifier.padding(8.dp),
    ) {
            Markdown(message.body)
    }
}

Are you planning to support setting values using CompositionLocalProvider?

Can't import RichTextThemeIntegration composable function

Because there is a data class with the same name in the same scope visibility, we can't import RichTextThemeIntegration composable function, the data class take the priority.

We should rename the data class or the data class.

FormattedList should be more like HTML's lists

First, it shouldn't take an explicit list, just a single children slot.

Second, a composable called something like ListItem should be introduced. This composable will be scoped to the list slot and display the list marker inside itself by asking the scope for the marker composable. The list will compose it's children slot and determine how many list markers it needs to show, and use that number to calculate the width required to show markers. All children will be "indented" at the start. List item composables will compose the list markers outside of their actual bounds, so they are correctly placed in the margin. Children without a list item wrapper will simply be indented to match list items, with no marker.

This allows more control over how list markers are rendered. E.g. AnimatedVisibility can be used to affect the row and the marker.

Using an alpha version of the AGP

When you check out and try to build, you get this error:

"The project is using an incompatible version (AGP 7.4.0-alpha01) of the Android Gradle plugin. Latest supported version is AGP 7.2.2"

Unless using the alpha is somehow critical to the library, the AGP should be compatible with the latest, but not some alpha version.

RichTextStyle ignores initial stringStyle: RichTextStringStyle

RichText initiates everything with a merge call on an empty RichTextStyle with the received style from user. However, specific merge function for RichTextStringStyle looks like this

stringStyle = stringStyle?.merge(otherStyle?.stringStyle)

If initially (by default yes) stringStyle is null, it can never merge with the otherStyle and remain as null.

Would this work?

stringStyle = stringStyle?.merge(otherStyle?.stringStyle) ?: otherStyle?.stringStyle

Childless alternatives of CodeBlock, Heading can be removed

CodeBlock and Heading have alternative overloads that take literal text content. These alternatives are proxies to actual implementation which takes composable children. Only child that is passed to actual composable is a Text(...).

This API style of having alternatives is no longer common in Compose, e.g. Button does not offer a label alternative. We should stick with slot API most of the time.

Map HTML tags to custom composables

In the past in React, I've used https://github.com/remarkjs/react-markdown to render url tags with custom react components. For example a github link can be rendered as card with the projects open graph data.

I'd be nice if we had a way to intercept the HTML tags being rendered, read metadata from within it and substitute in our own custom composable.

Use primary as the default for link color (material 3 UI)

Currently its always blue, which doesn't look great for most material themes.

I'm getting around this manually by doing:

val richTextStyle = RichTextStyle().resolveDefaults().copy(
  stringStyle = RichTextStringStyle().copy(
    linkStyle = MaterialTheme.typography.bodyLarge.toSpanStyle().copy(
      color = MaterialTheme.colorScheme.primary
    )
  )
)

Library can't be used with latest Coil version

Hi,
we tried to use compose-richtext to display Markdown in our compose Android App.
Unfortunately, the app is crashing with the latest version (0.11.0), which seems to be related to the Coil Version we are using.
We are using the latest coil version 2.0.0-rc03 and receive the following stacktrace.
Note that when downgrading to 2.0.0-alpha06, everything works fine.

java.lang.NoSuchMethodError: No static method rememberAsyncImagePainter-8BXIMaA(Ljava/lang/Object;ILandroidx/compose/runtime/Composer;II)Lcoil/compose/AsyncImagePainter; in class Lcoil/compose/SingletonAsyncImagePainterKt; or its super classes (declaration of 'coil.compose.SingletonAsyncImagePainterKt' appears in /data/app/~~PGSppQ4FjVn2UYsP16sXHQ==/com.package.develop-UQ2-dt0KxyMNh-356uPjYg==/base.apk!classes21.dex) at com.halilibo.richtext.markdown.RemoteImageKt.RemoteImage(RemoteImage.kt:33) at com.halilibo.richtext.markdown.MarkdownRichTextKt$computeRichTextString$newFormatIndex$3.invoke(MarkdownRichText.kt:107) at com.halilibo.richtext.markdown.MarkdownRichTextKt$computeRichTextString$newFormatIndex$3.invoke(MarkdownRichText.kt:106) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:135) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at com.halilibo.richtext.ui.string.InlineContentKt$reifyInlineContent$1$1.invoke(InlineContent.kt:85) at com.halilibo.richtext.ui.string.InlineContentKt$reifyInlineContent$1$1.invoke(InlineContent.kt:84) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.foundation.text.CoreTextKt.InlineChildren(CoreText.kt:78) at androidx.compose.foundation.text.BasicTextKt$BasicText$6.invoke(BasicText.kt:234) at androidx.compose.foundation.text.BasicTextKt$BasicText$6.invoke(BasicText.kt:234) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.foundation.text.BasicTextKt.BasicText-4YKlhWE(BasicText.kt:322) at com.halilibo.richtext.ui.RichTextLocalsKt.Text-4YKlhWE(RichTextLocals.kt:88) at com.halilibo.richtext.ui.RichTextLocalsKt.ClickableText-VhcvRP8(RichTextLocals.kt:125) at com.halilibo.richtext.ui.string.TextKt$Text$2.invoke(Text.kt:44) at com.halilibo.richtext.ui.string.TextKt$Text$2.invoke(Text.kt:38) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1.invoke(BoxWithConstraints.kt:69) at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1.invoke(BoxWithConstraints.kt:69) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$2$1$1.invoke(SubcomposeLayout.kt:753) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$2$1$1.invoke(SubcomposeLayout.kt:447) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:74) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3164) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3154) at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:252) at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1) at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3154) at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3091) at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:568)

IllegalStateException: Expected a group when changing sliders in RichText demo

Seems to be triggered when ListDemo is followed by a Heading. Either of those on their own is fine.

Might be related to this bug, which is due to bad interaction between remember and default arguments.

Example stacktrace:

java.lang.IllegalStateException: Expected a group
    at androidx.compose.runtime.SlotTableKt.getAsGroup(SlotTable.kt:994)
    at androidx.compose.runtime.SlotTableKt.access$getAsGroup(Unknown Source:0)
    at androidx.compose.runtime.SlotReader.group$runtime_release(SlotTable.kt:46)
    at androidx.compose.runtime.Composer.nodeIndexOf(Composer.kt:1668)
    at androidx.compose.runtime.Composer.recomposeToGroupEnd(Composer.kt:1544)
    at androidx.compose.runtime.Composer.skipToGroupEnd(Composer.kt:1784)
    at com.zachklipp.richtext.ui.DemoKt$RichTextDemo$1.invoke(Demo.kt:142)
    at com.zachklipp.richtext.ui.DemoKt$RichTextDemo$1.invoke(Unknown Source:13)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(ComposableLambda.kt:153)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(Unknown Source:10)
    at com.zachklipp.richtext.ui.RichTextKt$RichText$1$1$1.invoke(RichText.kt:30)
    at com.zachklipp.richtext.ui.RichTextKt$RichText$1$1$1.invoke(Unknown Source:13)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(ComposableLambda.kt:153)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(Unknown Source:10)
    at com.zachklipp.richtext.ui.RichTextScopeKt$WithStyle$1.invoke(RichTextScope.kt:35)
    at com.zachklipp.richtext.ui.RichTextScopeKt$WithStyle$1.invoke(Unknown Source:10)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(ComposableLambda.kt:144)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(Unknown Source:10)
    at androidx.compose.runtime.AmbientKt.Providers(Ambient.kt:175)
    at com.zachklipp.richtext.ui.RichTextScopeKt.WithStyle(RichTextScope.kt:34)
    at com.zachklipp.richtext.ui.RichTextKt$RichText$1$1.invoke(RichText.kt:23)
    at com.zachklipp.richtext.ui.RichTextKt$RichText$1$1.invoke(Unknown Source:10)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(ComposableLambda.kt:144)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(Unknown Source:10)
    at androidx.compose.runtime.RecomposeScope.compose(Composer.kt:257)
    at androidx.compose.runtime.Composer.recomposeToGroupEnd(Composer.kt:1560)
    at androidx.compose.runtime.Composer.skipToGroupEnd(Composer.kt:1784)
    at com.zachklipp.richtext.ui.FormattedListKt.RestartListLevel(FormattedList.kt:156)
    at com.zachklipp.richtext.ui.RichTextKt.RichText(RichText.kt:21)
    at com.zachklipp.richtext.ui.DemoKt.RichTextDemo(Demo.kt:38)
    at com.zachklipp.richtext.sample.RichTextSampleKt$RichTextSample$1$1$1$2.invoke(RichTextSample.kt:58)
    at com.zachklipp.richtext.sample.RichTextSampleKt$RichTextSample$1$1$1$2.invoke(Unknown Source:13)
    at androidx.compose.runtime.internal.ComposableLambda.invoke(ComposableLambda.kt:153)
    at androidx.compose.runtime.internal.ComposableLambda$invoke$1.invoke(ComposableLambda.kt:164)
    at androidx.compose.runtime.internal.ComposableLambda$invoke$1.invoke(Unknown Source:10)
    at androidx.compose.runtime.RecomposeScope.compose(Composer.kt:257)
    at androidx.compose.runtime.Composer.recomposeToGroupEnd(Composer.kt:1560)
    at androidx.compose.runtime.Composer.skipCurrentGroup(Composer.kt:1763)
    at androidx.compose.runtime.Composer.recompose(Composer.kt:1886)
    at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:259)
    at androidx.compose.runtime.Recomposer.access$performRecompose(Unknown Source:0)
    at androidx.compose.runtime.Recomposer$recomposeAndApplyChanges$2$2.invoke(Recomposer.kt:199)
    at androidx.compose.runtime.Recomposer$recomposeAndApplyChanges$2$2.invoke(Unknown Source:7)
    at androidx.compose.runtime.dispatch.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.kt:34)
    at androidx.compose.runtime.dispatch.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.kt:111)
    at androidx.compose.runtime.dispatch.AndroidUiDispatcher.access$performFrameDispatch(Unknown Source:0)
    at androidx.compose.runtime.dispatch.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.kt:71)

Bug with empty list item

Hello! There seems to be a visual bug when there is en empty item in the list, for the text after the list. For example

MaterialRichText(style = null) {
    Markdown(
        content = "List\n* item1\n* \n* item2\n\nSome text",
        onLinkClicked = null
    )
}

produces this result:
image

This is the expected result (I added a non-breaking space for the empty item):
image

Can you tell me, is it caused by a bug in the library? Or is this a problem with the Markdown itself, and its specification?

RichText should be unopinionated about layout

It currently wraps children in a Column, but now that Arrangement.spacedBy exists, there's no need to do that. Not wrapping in a column allows long documents to be rendered using LazyColumn, for example.

Related, maybe RichTextStyle shouldn't include block spacing at all, although I think it still might be useful for lists and stuff.

Printable composable doesn't play well with subcomposition

From https://twitter.com/richp_2003/status/1507732205241610245

I have Tabs, a lazy column and a sticky button on the bottom of screen. Now lazy column has a view that can be dismissed by user. I made lazy column Printable and it works fine.

Except, when the user dismisses that one item from lazy column and the recomposition happens and it crashes with error “Composable already registered” . I tried to move around the printable area. But the screen is complicated, I have many columns for the screen.

When I change the Printable position, sometime I will get error saying “nested scrolling isn’t allowed for lazy column and column”.
Sometime everything will work but my sticky button will disappear. Or everything will work but then when i click print, it will be blank.

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.