Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tables extension #339

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ poko = "0.13.1"
[libraries]
commonmark-core = { module = "org.commonmark:commonmark", version.ref = "commonmark" }
commonmark-ext-autolink = { module = "org.commonmark:commonmark-ext-autolink", version.ref = "commonmark" }
commonmark-ext-gfm-tables = { module = "org.commonmark:commonmark-ext-gfm-tables", version.ref = "commonmark" }

filePicker = { module = "com.darkrockstudios:mpfilepicker", version = "3.1.0" }

Expand Down
23 changes: 23 additions & 0 deletions markdown/core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,20 @@ public final class org/jetbrains/jewel/markdown/MarkdownBlock$CodeBlock$Indented
public abstract interface class org/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock : org/jetbrains/jewel/markdown/MarkdownBlock {
}

public final class org/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock$DefaultCustomBlock : org/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock {
public static final synthetic fun box-impl (Lorg/commonmark/node/CustomBlock;)Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock$DefaultCustomBlock;
public static fun constructor-impl (Lorg/commonmark/node/CustomBlock;)Lorg/commonmark/node/CustomBlock;
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (Lorg/commonmark/node/CustomBlock;Ljava/lang/Object;)Z
public static final fun equals-impl0 (Lorg/commonmark/node/CustomBlock;Lorg/commonmark/node/CustomBlock;)Z
public final fun getNativeBlock ()Lorg/commonmark/node/CustomBlock;
public fun hashCode ()I
public static fun hashCode-impl (Lorg/commonmark/node/CustomBlock;)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (Lorg/commonmark/node/CustomBlock;)Ljava/lang/String;
public final synthetic fun unbox-impl ()Lorg/commonmark/node/CustomBlock;
}

public final class org/jetbrains/jewel/markdown/MarkdownBlock$Heading : org/jetbrains/jewel/markdown/BlockWithInlineMarkdown, org/jetbrains/jewel/markdown/MarkdownBlock {
public static final synthetic fun box-impl (Lorg/commonmark/node/Heading;)Lorg/jetbrains/jewel/markdown/MarkdownBlock$Heading;
public static fun constructor-impl (Lorg/commonmark/node/Heading;)Lorg/commonmark/node/Heading;
Expand Down Expand Up @@ -406,6 +420,11 @@ public abstract interface class org/jetbrains/jewel/markdown/extensions/Markdown
public abstract fun processMarkdownBlock (Lorg/commonmark/node/CustomBlock;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;
}

public final class org/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension$DefaultImpls {
public static fun canProcess (Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;Lorg/commonmark/node/CustomBlock;)Z
public static fun processMarkdownBlock (Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;Lorg/commonmark/node/CustomBlock;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;
}

public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension {
public abstract fun canRender (Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;)Z
public abstract fun render (Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;Landroidx/compose/runtime/Composer;I)V
Expand All @@ -417,6 +436,10 @@ public abstract interface class org/jetbrains/jewel/markdown/extensions/Markdown
public abstract fun getTextRendererExtension ()Lorg/commonmark/renderer/text/TextContentRenderer$TextContentRendererExtension;
}

public final class org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension$DefaultImpls {
public static fun getProcessorExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;
}

public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension {
public abstract fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jetbrains.jewel.markdown

import org.commonmark.node.Block
import org.commonmark.node.CustomBlock as CMCustomBlock
import org.commonmark.node.Heading as CMHeading
import org.commonmark.node.Paragraph as CMParagraph

Expand All @@ -22,7 +23,10 @@ public sealed interface MarkdownBlock {
) : CodeBlock
}

public interface CustomBlock : MarkdownBlock
public interface CustomBlock : MarkdownBlock {
@JvmInline
public value class DefaultCustomBlock(public val nativeBlock: CMCustomBlock) : CustomBlock
}

@JvmInline
public value class Heading(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ public interface MarkdownBlockProcessorExtension {
*
* @param block The [CustomBlock] to parse
*/
public fun canProcess(block: CustomBlock): Boolean
public fun canProcess(block: CustomBlock): Boolean = false

/**
* Processes the [block] as a [MarkdownBlock.CustomBlock], if possible. Note
* that you should always check that [canProcess] returns true for the same
* [block], as implementations might throw an exception for unsupported
* block types.
*/
public fun processMarkdownBlock(block: CustomBlock, processor: MarkdownProcessor): MarkdownBlock.CustomBlock?
public fun processMarkdownBlock(block: CustomBlock, processor: MarkdownProcessor): MarkdownBlock.CustomBlock? = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ public interface MarkdownProcessorExtension {
* is already be handled by [org.jetbrains.jewel.markdown.processing.MarkdownProcessor]
* or another [org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension].
*/
public val processorExtension: MarkdownBlockProcessorExtension?
public val processorExtension: MarkdownBlockProcessorExtension
get() = object : MarkdownBlockProcessorExtension {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.jetbrains.jewel.foundation.ExperimentalJewelApi
import org.jetbrains.jewel.markdown.InlineMarkdown
import org.jetbrains.jewel.markdown.MarkdownBlock
import org.jetbrains.jewel.markdown.MarkdownBlock.CodeBlock
import org.jetbrains.jewel.markdown.MarkdownBlock.CustomBlock.DefaultCustomBlock
import org.jetbrains.jewel.markdown.MarkdownBlock.ListBlock
import org.jetbrains.jewel.markdown.MimeType
import org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension
Expand Down Expand Up @@ -189,8 +190,9 @@ public class MarkdownProcessor(
is ThematicBreak -> MarkdownBlock.ThematicBreak
is HtmlBlock -> toMarkdownHtmlBlockOrNull()
is CustomBlock -> {
extensions.find { it.processorExtension?.canProcess(this) == true }
extensions.find { it.processorExtension.canProcess(this) }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we just dropping blocks that can't get processed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I'm following what you mean here: are asking why we are keeping noop extensions? I'm planning to fix that later... my ideal API would just run tryProcess and only register extensions if they do something.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I am asking why we have an Elvis that returns a DefaultCustomBlock, which is something that really makes no sense to me. If it's a custom block, the concept of default is meaningless. We should not have it; instead, every extension should have its own custom block(s) — e.g., TableBlock(...): CustomBlock

?.processorExtension?.processMarkdownBlock(this, this@MarkdownProcessor)
?: DefaultCustomBlock(this)
}

else -> null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package org.jetbrains.jewel.markdown.extension.autolink
import org.commonmark.ext.autolink.AutolinkExtension
import org.commonmark.parser.Parser.ParserExtension
import org.commonmark.renderer.text.TextContentRenderer
import org.jetbrains.jewel.markdown.extensions.MarkdownBlockProcessorExtension
import org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension

public object AutolinkProcessorExtension : MarkdownProcessorExtension {

override val parserExtension: ParserExtension
get() = AutolinkExtension.create() as ParserExtension

Expand All @@ -15,6 +15,4 @@ public object AutolinkProcessorExtension : MarkdownProcessorExtension {
*/
override val textRendererExtension: TextContentRenderer.TextContentRendererExtension?
get() = null
override val processorExtension: MarkdownBlockProcessorExtension?
get() = null
}
35 changes: 35 additions & 0 deletions markdown/extension/gfm-tables/api/gfm-tables.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
public final class org/jetbrains/jewel/markdown/extensions/tables/GitHubTableBlockRenderer : org/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension {
public static final field $stable I
public fun <init> (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;)V
public fun canRender (Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;)Z
public fun render (Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;Landroidx/compose/runtime/Composer;I)V
}

public final class org/jetbrains/jewel/markdown/extensions/tables/GitHubTableProcessorExtension : org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension {
public static final field $stable I
public static final field INSTANCE Lorg/jetbrains/jewel/markdown/extensions/tables/GitHubTableProcessorExtension;
public fun getParserExtension ()Lorg/commonmark/parser/Parser$ParserExtension;
public fun getProcessorExtension ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;
public fun getTextRendererExtension ()Lorg/commonmark/renderer/text/TextContentRenderer$TextContentRendererExtension;
}

public final class org/jetbrains/jewel/markdown/extensions/tables/GitHubTableRendererExtension : org/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension {
public static final field $stable I
public fun <init> (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;)V
public fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
}

public final class org/jetbrains/jewel/markdown/extensions/tables/TableStyling {
public static final field $stable I
public static final field Companion Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;
public synthetic fun <init> (JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getBorderColor-0d7_KjU ()J
public final fun getHeadColor-0d7_KjU ()J
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion {
}

23 changes: 23 additions & 0 deletions markdown/extension/gfm-tables/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
jewel
`jewel-publish`
`jewel-check-public-api`
alias(libs.plugins.composeDesktop)
}

dependencies {
implementation(projects.markdown.core)
implementation(libs.commonmark.ext.gfm.tables)

testImplementation(compose.desktop.uiTestJUnit4)
}

publicApiValidation {
// TODO Oleg remove this once migrated to value classes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @obask there is a TODO here for ya :) (and in at least another module, too!)

excludedClassRegexes = setOf("org.jetbrains.jewel.markdown.extensions.github.alerts.*")
}

publishing.publications.named<MavenPublication>("main") {
val ijpTarget = project.property("ijp.target") as String
artifactId = "jewel-markdown-extension-${project.name}-$ijpTarget"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.jetbrains.jewel.markdown.extensions.tables

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.commonmark.ext.gfm.tables.TableBlock
import org.commonmark.ext.gfm.tables.TableBody
import org.commonmark.ext.gfm.tables.TableHead
import org.commonmark.node.Node
import org.jetbrains.jewel.markdown.InlineMarkdown
import org.jetbrains.jewel.markdown.MarkdownBlock.CustomBlock
import org.jetbrains.jewel.markdown.extensions.MarkdownBlockRendererExtension
import org.jetbrains.jewel.markdown.rendering.InlineMarkdownRenderer
import org.jetbrains.jewel.markdown.rendering.MarkdownBlockRenderer
import org.jetbrains.jewel.markdown.rendering.MarkdownStyling
import org.jetbrains.jewel.markdown.toInlineNode
import org.jetbrains.jewel.ui.component.Text

public class GitHubTableBlockRenderer(
private val styling: TableStyling,
private val rootStyling: MarkdownStyling,
) : MarkdownBlockRendererExtension {

override fun canRender(block: CustomBlock): Boolean =
block is CustomBlock.DefaultCustomBlock && block.nativeBlock is TableBlock

@Composable
private fun RowScope.TableCell(
text: List<InlineMarkdown>,
inlineRenderer: InlineMarkdownRenderer,
) {
Text(
text = inlineRenderer.renderAsAnnotatedString(text, rootStyling.paragraph.inlinesStyling),
Modifier
.border(1.dp, styling.borderColor)
.weight(1.0f)
.padding(8.dp),
)
}

@Composable
override fun render(
block: CustomBlock,
blockRenderer: MarkdownBlockRenderer,
inlineRenderer: InlineMarkdownRenderer,
) {
if (block !is CustomBlock.DefaultCustomBlock) return

val head = block.nativeBlock.firstChild as TableHead
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotta love CommonMark APIs 🙃

Can we expose head and body as properties on our table block model?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to invoke the processor unless it's needed for something. Right now the CustomBlock is an interface and we can always convert it to data classes later if we need to.

val body = block.nativeBlock.lastChild as TableBody

Column(Modifier.fillMaxSize().padding(16.dp)) {
head.forEachChild { row ->
Row(Modifier.background(styling.headColor)) {
row.forEachChild { cell ->
TableCell(text = cell.children().map { it.toInlineNode() }, inlineRenderer)
}
}
}
body.forEachChild { row ->
Row(Modifier.fillMaxWidth()) {
row.forEachChild { cell ->
TableCell(text = cell.children().map { it.toInlineNode() }, inlineRenderer)
}
}
}
}
}

@Composable
private fun Node.children(): List<Node> = buildList {
var child = firstChild

while (child != null) {
add(child)
child = child.next
}
}
}

@Composable
private fun Node.forEachChild(action: @Composable (Node) -> Unit) {
var child = firstChild

while (child != null) {
action(child)
child = child.next
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.jetbrains.jewel.markdown.extensions.tables

import org.commonmark.ext.gfm.tables.TablesExtension
import org.commonmark.parser.Parser.ParserExtension
import org.commonmark.renderer.text.TextContentRenderer.TextContentRendererExtension
import org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension

public object GitHubTableProcessorExtension : MarkdownProcessorExtension {

override val parserExtension: ParserExtension = TablesExtension.create() as ParserExtension
override val textRendererExtension: TextContentRendererExtension = TablesExtension.create() as TextContentRendererExtension
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.jetbrains.jewel.markdown.extensions.tables

import org.jetbrains.jewel.markdown.extensions.MarkdownBlockRendererExtension
import org.jetbrains.jewel.markdown.extensions.MarkdownRendererExtension
import org.jetbrains.jewel.markdown.rendering.MarkdownStyling

public class GitHubTableRendererExtension(
alertStyling: TableStyling,
rootStyling: MarkdownStyling,
) : MarkdownRendererExtension {

override val blockRenderer: MarkdownBlockRendererExtension =
GitHubTableBlockRenderer(alertStyling, rootStyling)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.jetbrains.jewel.markdown.extensions.tables

import androidx.compose.ui.graphics.Color
import org.jetbrains.jewel.foundation.GenerateDataFunctions

@GenerateDataFunctions
public class TableStyling(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any facility to set things like cell padding, min row height, etc. Are those coming later? Or simply weren't considered?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My goal was to add an initial implementation of tables and change it later to follow more specific requirements. So the answer is "weren't considered".

public val headColor: Color,
Comment on lines +7 to +8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a background or content color? Please name accordingly

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial plan was to make it work as an alpha version. (I didn't think adding tables would be so easy) But yes, we should probably set the right styling in place.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would want to avoid having a half-implemented table extension merged in, unless we're sure the rest of the behaviour/styling is ready to go quickly (one day?)

public val borderColor: Color,
) {

public companion object
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,10 @@ public final class org/jetbrains/jewel/intui/markdown/styling/extension/github/a
public static synthetic fun light-gaOEZmc$default (Lorg/jetbrains/jewel/markdown/extensions/github/alerts/WarningAlertStyling$Companion;Landroidx/compose/foundation/layout/PaddingValues;FJLandroidx/compose/ui/graphics/PathEffect;ILandroidx/compose/ui/text/TextStyle;Ljava/lang/String;JJILjava/lang/Object;)Lorg/jetbrains/jewel/markdown/extensions/github/alerts/WarningAlertStyling;
}

public final class org/jetbrains/jewel/intui/markdown/styling/extension/github/alerts/GitHubTableDefaultStylingKt {
public static final fun dark-WkMS-hQ (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJ)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
public static synthetic fun dark-WkMS-hQ$default (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJILjava/lang/Object;)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
public static final fun light-WkMS-hQ (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJ)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
public static synthetic fun light-WkMS-hQ$default (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJILjava/lang/Object;)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
}

1 change: 1 addition & 0 deletions markdown/int-ui-standalone-styling/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies {
api(projects.markdown.core)
api(projects.intUi.intUiStandalone)
compileOnly(projects.markdown.extension.gfmAlerts)
compileOnly(projects.markdown.extension.gfmTables)

testImplementation(compose.desktop.uiTestJUnit4)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.jetbrains.jewel.intui.markdown.styling.extension.github.alerts

import androidx.compose.ui.graphics.Color
import org.jetbrains.jewel.markdown.extensions.tables.TableStyling

public fun TableStyling.Companion.dark(
headColor: Color = Color.DarkGray,
borderColor: Color = Color.Gray,
Comment on lines +7 to +8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these defaults taken from the GitHub CSS, or arbitrary? If arbitrary, please get the actual values from the GitHub CSS (I recommend creating a table in a gist and inspecting in both light and dark themes)

): TableStyling = TableStyling(
headColor,
borderColor,
)

public fun TableStyling.Companion.light(
headColor: Color = Color.LightGray,
borderColor: Color = Color.Gray,
): TableStyling = TableStyling(
headColor,
borderColor,
)
4 changes: 3 additions & 1 deletion samples/standalone/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ dependencies {
implementation(projects.intUi.intUiStandalone)
implementation(projects.intUi.intUiDecoratedWindow)
implementation(projects.markdown.intUiStandaloneStyling)
implementation(projects.markdown.extension.gfmAlerts)
implementation(projects.markdown.extension.autolink)
implementation(projects.markdown.extension.gfmAlerts)
implementation(projects.markdown.extension.gfmTables)

implementation(compose.desktop.currentOs) {
exclude(group = "org.jetbrains.compose.material")
}
Expand Down
Loading