main 8f237fd0c144 cached
104 files
428.5 KB
95.7k tokens
1 requests
Download .txt
Showing preview only (465K chars total). Download the full file or copy to clipboard to get everything.
Repository: ButterCam/compose-jetbrains-theme
Branch: main
Commit: 8f237fd0c144
Files: 104
Total size: 428.5 KB

Directory structure:
gitextract_99aa8iq5/

├── .github/
│   └── workflows/
│       ├── build.yml
│       └── release.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── build.gradle.kts
├── classic/
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── io/
│                   └── kanro/
│                       └── compose/
│                           └── jetbrains/
│                               ├── JBTheme.kt
│                               ├── JBTypography.kt
│                               ├── color/
│                               │   ├── ButtonColors.kt
│                               │   ├── CheckBoxColors.kt
│                               │   ├── FieldColors.kt
│                               │   ├── FocusColors.kt
│                               │   ├── IconColors.kt
│                               │   ├── PanelColors.kt
│                               │   ├── ProgressColors.kt
│                               │   ├── ScrollColors.kt
│                               │   ├── SelectionColors.kt
│                               │   ├── TabColors.kt
│                               │   ├── TableColors.kt
│                               │   ├── TextColors.kt
│                               │   ├── ToggleColors.kt
│                               │   └── ToolBarColors.kt
│                               ├── control/
│                               │   ├── ActionButton.kt
│                               │   ├── Button.kt
│                               │   ├── CheckBox.kt
│                               │   ├── ComboBox.kt
│                               │   ├── ContentAlpha.kt
│                               │   ├── ContentColor.kt
│                               │   ├── ContextMenu.kt
│                               │   ├── DropdownMenu.kt
│                               │   ├── EmbeddedTextField.kt
│                               │   ├── Icon.kt
│                               │   ├── JBToolBar.kt
│                               │   ├── JBTree.kt
│                               │   ├── JPanel.kt
│                               │   ├── ListView.kt
│                               │   ├── ProgressBar.kt
│                               │   ├── Selection.kt
│                               │   ├── Tab.kt
│                               │   ├── Text.kt
│                               │   └── TextField.kt
│                               └── icons/
│                                   ├── __JBIcons.kt
│                                   └── jbicons/
│                                       ├── __Actions.kt
│                                       ├── __General.kt
│                                       ├── actions/
│                                       │   ├── ArrowExpand.kt
│                                       │   ├── ArrowExpandDark.kt
│                                       │   ├── Checkmark.kt
│                                       │   ├── CheckmarkIndeterminate.kt
│                                       │   └── Close.kt
│                                       └── general/
│                                           ├── ButtonDropTriangle.kt
│                                           └── ButtonDropTriangleDark.kt
├── expui/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── io/
│                   └── kanro/
│                       └── compose/
│                           └── jetbrains/
│                               └── expui/
│                                   ├── DesktopPlatform.kt
│                                   ├── control/
│                                   │   ├── ActionButton.kt
│                                   │   ├── Button.kt
│                                   │   ├── CheckBox.kt
│                                   │   ├── ComboBox.kt
│                                   │   ├── ContextCompositionLocals.kt
│                                   │   ├── ContextMenu.kt
│                                   │   ├── DropdownMenu.kt
│                                   │   ├── Icon.kt
│                                   │   ├── Indication.kt
│                                   │   ├── Label.kt
│                                   │   ├── Link.kt
│                                   │   ├── Painter.kt
│                                   │   ├── PointerInput.kt
│                                   │   ├── ProgressBar.kt
│                                   │   ├── RadioButton.kt
│                                   │   ├── SegmentedButton.kt
│                                   │   ├── Tab.kt
│                                   │   ├── TextArea.kt
│                                   │   ├── TextField.kt
│                                   │   ├── ToolBar.kt
│                                   │   └── Tooltip.kt
│                                   ├── style/
│                                   │   ├── AreaColors.kt
│                                   │   ├── AreaProvider.kt
│                                   │   ├── Border.kt
│                                   │   └── TextStyle.kt
│                                   ├── theme/
│                                   │   ├── DarkTheme.kt
│                                   │   ├── Fonts.kt
│                                   │   ├── LightTheme.kt
│                                   │   └── Theme.kt
│                                   ├── util/
│                                   │   ├── CustomWindowDecorationAccessing.kt
│                                   │   └── UnsafeAccessing.kt
│                                   └── window/
│                                       ├── JBWindow.Linux.kt
│                                       ├── JBWindow.MacOS.kt
│                                       ├── JBWindow.Windows.kt
│                                       ├── JBWindow.kt
│                                       ├── MainToolBar.Basic.kt
│                                       ├── MainToolBar.Linux.kt
│                                       ├── MainToolBar.MacOS.kt
│                                       ├── MainToolBar.Windows.kt
│                                       └── MainToolBar.kt
├── expui-gallery/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── Main.kt
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build.yml
================================================
name: Build
on:
  # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests)
  push:
    branches: [ main ]
  # Trigger the workflow on any pull request
  pull_request:

jobs:
  # Run Gradle Wrapper Validation Action to verify the wrapper's checksum
  gradleValidation:
    name: Gradle Wrapper
    runs-on: ubuntu-latest
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.3.4

      # Validate wrapper
      - name: Gradle Wrapper Validation
        uses: gradle/wrapper-validation-action@v1.0.4
  build:
    name: Build
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.properties.outputs.version }}
      changelog: ${{ steps.properties.outputs.changelog }}
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2

      - name: Download JBR
        uses: carlosperate/download-file-action@v2
        with:
          file-url: 'https://cache-redirector.jetbrains.com/intellij-jbr/jbr-17.0.5-linux-x64-b653.14.tar.gz'
          file-name: 'jbr-17.0.5.tar.gz'

      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          java-version: 17
          distribution: jdkfile
          jdkFile: jbr-17.0.5.tar.gz
          cache: gradle

      # Set environment variables
      - name: Export Properties
        id: properties
        shell: bash
        run: |
          PROPERTIES="$(./gradlew properties -q)"
          VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
          NAME="$(echo "$PROPERTIES" | grep "^name:" | cut -f2- -d ' ')"
          CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"
          CHANGELOG="${CHANGELOG//'%'/'%25'}"
          CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
          CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
          echo "version=$VERSION"
          echo "name=$NAME"
          echo "changelog=$CHANGELOG"
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "name=$NAME" >> $GITHUB_OUTPUT
          echo "changelog=$CHANGELOG" >> $GITHUB_OUTPUT
      # Build artifact using buildPlugin Gradle task
      - name: Build
        run: ./gradlew build

      # Store built plugin as an artifact for downloading
      - name: Upload artifacts
        uses: actions/upload-artifact@v3
        with:
          name: "${{ steps.properties.outputs.name }} - ${{ steps.properties.outputs.version }}"
          path: ./**/build/libs/*

  # Prepare a draft release for GitHub Releases page for the manual verification
  # If accepted and published, release workflow would be triggered
  releaseDraft:
    name: Release Draft
    if: github.event_name != 'pull_request'
    needs: build
    runs-on: ubuntu-latest
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.3.4

      # Remove old release drafts by using the curl request for the available releases with draft flag
      - name: Remove Old Release Drafts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh api repos/{owner}/{repo}/releases \
            --jq '.[] | select(.draft == true) | .id' \
            | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}
      # Create new release draft - which is not publicly visible and requires manual acceptance
      - name: Create Release Draft
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create v${{ needs.build.outputs.version }} \
            --draft \
            --title "v${{ needs.build.outputs.version }}" \
            --notes "${{ needs.build.outputs.changelog }}"


================================================
FILE: .github/workflows/release.yml
================================================
# GitHub Actions Workflow created for handling the release process based on the draft release prepared
# with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided.

name: Release
on:
  release:
    types: [ prereleased, released ]

jobs:

  # Prepare and publish the plugin to the Marketplace repository
  release:
    name: Publish Plugin
    runs-on: ubuntu-latest
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.3.4
        with:
          ref: ${{ github.event.release.tag_name }}

      - name: Download JBR
        uses: carlosperate/download-file-action@v2
        with:
          file-url: 'https://cache-redirector.jetbrains.com/intellij-jbr/jbr-17.0.5-linux-x64-b653.14.tar.gz'
          file-name: 'jbr-17.0.5.tar.gz'

      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          java-version: 17
          distribution: jdkfile
          jdkFile: jbr-17.0.5.tar.gz
          cache: gradle

      # Update Unreleased section with the current release note
      - name: Patch Changelog
        run: |
          ./gradlew patchChangelog --release-note="`cat << EOM
          ${{ github.event.release.body }}
          EOM`"

      - name: Import GPG key
        uses: crazy-max/ghaction-import-gpg@v3
        with:
          gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}

      - uses: ButterCam/setup-sisyphus-build@v1
        with:
          dependency-repositories: local,central,portal,google,snapshot
          snapshot-url: https://s01.oss.sonatype.org/content/repositories/snapshots
          snapshot-username: ${{ secrets.OSSRH_USERNAME }}
          snapshot-password: ${{ secrets.OSSRH_PASSWORD }}
          release-url: https://s01.oss.sonatype.org/service/local/staging/deploy/maven2
          release-username: ${{ secrets.OSSRH_USERNAME }}
          release-password: ${{ secrets.OSSRH_PASSWORD }}
          gradle-portal-key: ${{ secrets.GRADLE_PUBLISH_KEY }}
          gradle-portal-secret: ${{ secrets.GRADLE_PUBLISH_SECRET }}
          gpg-key-name: ${{ secrets.GPG_KEY_NAME }}

      # Publish the plugin to the Marketplace
      - name: Publish
        env:
          PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
        run: ./gradlew publish

      # Upload artifact as a release asset
      - name: Upload Release Asset
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh release upload ${{ github.event.release.tag_name }} ./**/build/libs/*

      # Create pull request
      - name: Create Pull Request
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          VERSION="${{ github.event.release.tag_name }}"
          BRANCH="changelog-update-$VERSION"
          git config user.email "action@github.com"
          git config user.name "GitHub Action"
          git checkout -b $BRANCH
          git commit -am "Changelog update - $VERSION"
          git push --set-upstream origin $BRANCH
          gh pr create \
            --title ":bookmark: Changelog update - \`$VERSION\`" \
            --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \
            --base main \
            --head $BRANCH

================================================
FILE: .gitignore
================================================
.gradle
/build/
!foundation/gradle/wrapper/gradle-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

logs/
out/
data/elasticsearch
.DS_Store

================================================
FILE: CHANGELOG.md
================================================
# Changelog

## [Unreleased]

## [2.2.0]
- Upgrade to compose 1.5.2

## [2.1.0]
- Provide BasicMainToolBar #18 
- Disable minimize and maximize button when resizeable is false #19 
- Fix the custom title bar when MainToolBar Content is empty #20
- Optimize the implementation of themes. Switching themes will not cause full recompose.
- Add text styles for theme

## [2.0.0]
- Exp UI theme support

## [1.1.0]
- Target to jvm 1.11 #11
- Replacing SVG Resources with Compose generated Image Vectors #13
- IntelliJ Dracula colors (Dark Theme) #12

Thanks @DevSrSouza

## [1.0.1]
- Upgrade to compose 1.0.1

## [1.0.0]
- JetBrains UI Kit for Compose desktop

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 ButterCam

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# We are planning to migrate to [JetBrains/jewel](https://github.com/JetBrains/jewel)!

We are discussing with JetBrains officials about migrating this project to [JetBrains/jewel](https://github.com/JetBrains/jewel). This will be the focus of our next work.

Track progress in this issue: JetBrains/jewel#28

# JetBrains UI Kit for Compose Desktop

New JetBrains style controls and UI kits for [Compose Desktop](https://www.jetbrains.com/lp/compose/).

Classic JetBrains UI kit have been moved to [here](classic).

![screenshot](docs/screenshot-expui.png)

## Quick Start

## Requirements

### JetBrains Runtime

To get the best presentation across platforms, this library requires the application to run
on [JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime) (JBR).

[JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime) is a modified version of the JetBrains JDK
distribution, which is widely used across the JetBrains' IDEs such as IntelliJ, GoLand and others.

In this library we use the additional API provided by JetBrains Runtime to customise the title bar in Windows and macOS.

If the `JBWindow` component is not used, it can also be used without the JetBrains Runtime.

When using `JBWindow` in a non-JetBrains Runtime environment, a native title bar may additionally be displayed.

JBR-17 (corresponding to JDK 17) can be downloaded from [the SDK page](https://www.jetbrains.com/help/idea/sdk.html) of
IntelliJ.

Make sure that the [project SDK](https://www.jetbrains.com/help/idea/project-settings-and-structure.html#project-sdk)
and [Gradle JVM](https://www.jetbrains.com/help/idea/gradle-jvm-selection.html) are both JBR-17.

#### Project SDK settings

![](docs/project-sdk.png)

#### Gradle JVM settings

![](docs/gradle-jvm.png)

### `jdk.unsupported` module

Most of the JetBrains Runtime APIs are private to JetBrains, and the class `sun.misc.Unsafe` is used to get access to
these APIs.

You need to add the `jdk.unsupported` module to the compose dependency as in the following code to make it work.

You can also skip this step if you don't need to use the `JBWindow` component.

```kotlin
compose.desktop {
    application {
        nativeDistributions {
            modules("jdk.unsupported")
        }
    }
}
```

## 1. Add dependency

```kotlin
dependencies {
    implementation(compose.desktop.currentOs) {
        exclude("org.jetbrains.compose.material")
    }
    implementation("com.bybutter.compose:compose-jetbrains-expui-theme:2.0.0")
}
```

## 2. Use JBWindow DSL

The optimal display of JBWindow requires JetBrains Runtime, refer to the previous [requirements](#Requirements).

```kotlin
fun main() = application {
    JBWindow(
        title = "JetBrains ExpUI Gallery",
        showTitle = true, // If you want to render your own component in the center of the title bar like Intellij do, disable this to hide the title of the MainToolBar (TitleBar).
        theme = LightTheme, // Change the theme here, LightTheme and DarkTheme are provided.
        state = rememberWindowState(size = DpSize(900.dp, 700.dp)),
        onCloseRequest = {
            exitApplication()
        },
        mainToolBar = {
            // Render your own component in the MainToolBar (TitleBar).
            Row(
                Modifier.mainToolBarItem(
                    Alignment.End,
                    true
                )
            ) { // Use the mainToolBarItem modifier to change alignment of components and enable/disable window drag area on this component.
            }
        }) {
        // Window content
    }
}
```

## 3. Use LightTheme and DarkTheme DSL

Since `JBWindow` requires JetBrains Runtime, if you don't want to use the `JBWindow` component, you can also use a
normal `Window` with `LightTheme`/`DarkTheme` DSL.

```kotlin
fun main() = application {
    Window({}) {
        LightTheme {
            // Your components here
        }
    }
}
```


# Screenshot

## MacOS

<img width="1012" alt="截屏2022-11-21 17 11 56" src="https://user-images.githubusercontent.com/9367842/203010912-68f54752-a598-49ad-9e50-9217dba544be.png">
<img width="1012" alt="截屏2022-11-21 17 12 18" src="https://user-images.githubusercontent.com/9367842/203011027-3a835525-f44a-42e0-83f5-b1e27011b9e4.png">

## Windows  

![image](https://user-images.githubusercontent.com/9367842/203374673-be0e25ab-de0c-4682-a511-bbadf0949446.png)  
![image](https://user-images.githubusercontent.com/9367842/203374902-0b384bdd-fff4-4cbc-a8eb-93d6b58229a2.png)

## Linux(Ubuntu with Gnome)

![image](https://user-images.githubusercontent.com/9367842/203574847-6b6a3d4a-0da2-41f8-ac3f-9a8402f26b16.png)
![image](https://user-images.githubusercontent.com/9367842/203574918-953092bc-b00f-455b-a43a-237c63093095.png)


================================================
FILE: build.gradle.kts
================================================
plugins {
    id("com.bybutter.sisyphus.project") version "2.1.0" apply false
    id("com.netflix.nebula.contacts") version "7.0.1"
    id("com.netflix.nebula.info") version "12.1.6" apply false
    id("com.netflix.nebula.maven-publish") version "20.3.0" apply false
    id("com.netflix.nebula.source-jar") version "20.3.0" apply false
    id("org.jetbrains.changelog") version "1.3.0"
    id("org.jetbrains.compose") version "1.5.2" apply false
    kotlin("jvm") version "1.9.10" apply false
}

allprojects {
    apply(plugin = "com.netflix.nebula.contacts")
    apply(plugin = "com.netflix.nebula.info")

    group = "com.bybutter.compose"
    version = "2.2.0"

    contacts {
        addPerson(
            "higan@live.cn",
            delegateClosureOf<nebula.plugin.contacts.Contact> {
                moniker = "higan"
                github = "devkanro"
                roles.add("owner")
            },
        )
    }
}

subprojects {
    apply(plugin = "org.jetbrains.compose")

    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>() {
        kotlinOptions.jvmTarget = "17"
    }

    repositories {
        mavenLocal()
        mavenCentral()
        google()
        maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
    }
}

changelog {
    version.set(project.version.toString())
    groups.set(emptyList())
}


================================================
FILE: classic/README.md
================================================
# JetBrains UI Kit for Compose Desktop

JetBrains style controls and UI for [Compose Desktop](https://www.jetbrains.com/lp/compose/).

![screenshot](../docs/screenshot.png)

## Quick Start

## 1. Add dependency

```kotlin
dependencies {
    implementation(compose.desktop.currentOs) {
        exclude("org.jetbrains.compose.material")
    }
    implementation("com.bybutter.compose:compose-jetbrains-theme:2.0.0")
}
```

## 2. JBTheme DSL

```kotlin
fun main() = application {
    Window(
        onCloseRequest = ::exitApplication,
        title = "Compose for Desktop",
        state = rememberWindowState(width = 300.dp, height = 300.dp)
    ) {
        val count = remember { mutableStateOf(0) }

        JBTheme {
            JPanel(Modifier.fillMaxSize().jBorder(top = 1.dp, color = JBTheme.panelColors.border)) {
                Column(Modifier.fillMaxSize(), Arrangement.spacedBy(5.dp)) {
                    Button(modifier = Modifier.align(Alignment.CenterHorizontally),
                        onClick = {
                            count.value++
                        }) {
                        Text(if (count.value == 0) "Hello World" else "Clicked ${count.value}!")
                    }
                    Button(modifier = Modifier.align(Alignment.CenterHorizontally),
                        onClick = {
                            count.value = 0
                        }) {
                        Text("Reset")
                    }
                }
            }
        }
    }
}
```

================================================
FILE: classic/build.gradle.kts
================================================
plugins {
    kotlin("jvm")
    `java-library`
    id("com.netflix.nebula.maven-publish")
    id("com.netflix.nebula.source-jar")
    id("com.bybutter.sisyphus.project")
    id("org.jetbrains.compose")
}

description = "JetBrains UI Kit for Compose Desktop"

dependencies {
    implementation(kotlin("stdlib"))
    implementation(compose.desktop.common) {
        exclude("org.jetbrains.compose.material")
    }
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>() {
    kotlinOptions.jvmTarget = "17"
    kotlinOptions.freeCompilerArgs += listOf(
        // "-P", "plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true"
    )
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/JBTheme.kt
================================================
package io.kanro.compose.jetbrains

import androidx.compose.foundation.LocalScrollbarStyle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ProvidedValue
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
import io.kanro.compose.jetbrains.color.ButtonColors
import io.kanro.compose.jetbrains.color.CheckBoxColors
import io.kanro.compose.jetbrains.color.FieldColors
import io.kanro.compose.jetbrains.color.FocusColors
import io.kanro.compose.jetbrains.color.IconColors
import io.kanro.compose.jetbrains.color.LocalButtonColors
import io.kanro.compose.jetbrains.color.LocalCheckBoxColors
import io.kanro.compose.jetbrains.color.LocalFieldColors
import io.kanro.compose.jetbrains.color.LocalFocusColors
import io.kanro.compose.jetbrains.color.LocalIconColors
import io.kanro.compose.jetbrains.color.LocalPanelColors
import io.kanro.compose.jetbrains.color.LocalProgressColors
import io.kanro.compose.jetbrains.color.LocalScrollColors
import io.kanro.compose.jetbrains.color.LocalSelectionColors
import io.kanro.compose.jetbrains.color.LocalTabColors
import io.kanro.compose.jetbrains.color.LocalTextColors
import io.kanro.compose.jetbrains.color.LocalToolBarColors
import io.kanro.compose.jetbrains.color.PanelColors
import io.kanro.compose.jetbrains.color.ProgressColors
import io.kanro.compose.jetbrains.color.ScrollColors
import io.kanro.compose.jetbrains.color.SelectionColors
import io.kanro.compose.jetbrains.color.TabColors
import io.kanro.compose.jetbrains.color.TextColors
import io.kanro.compose.jetbrains.color.ToolBarColors
import io.kanro.compose.jetbrains.color.darkButtonColors
import io.kanro.compose.jetbrains.color.darkCheckBoxColors
import io.kanro.compose.jetbrains.color.darkFieldColors
import io.kanro.compose.jetbrains.color.darkFocusColors
import io.kanro.compose.jetbrains.color.darkIconColors
import io.kanro.compose.jetbrains.color.darkPanelColors
import io.kanro.compose.jetbrains.color.darkProgressColors
import io.kanro.compose.jetbrains.color.darkScrollColors
import io.kanro.compose.jetbrains.color.darkSelectionColors
import io.kanro.compose.jetbrains.color.darkTabColors
import io.kanro.compose.jetbrains.color.darkTextColors
import io.kanro.compose.jetbrains.color.darkToolBarColors
import io.kanro.compose.jetbrains.color.lightButtonColors
import io.kanro.compose.jetbrains.color.lightCheckBoxColors
import io.kanro.compose.jetbrains.color.lightFieldColors
import io.kanro.compose.jetbrains.color.lightFocusColors
import io.kanro.compose.jetbrains.color.lightIconColors
import io.kanro.compose.jetbrains.color.lightPanelColors
import io.kanro.compose.jetbrains.color.lightProgressColors
import io.kanro.compose.jetbrains.color.lightScrollColors
import io.kanro.compose.jetbrains.color.lightSelectionColors
import io.kanro.compose.jetbrains.color.lightTabColors
import io.kanro.compose.jetbrains.color.lightTextColors
import io.kanro.compose.jetbrains.color.lightToolBarColors
import io.kanro.compose.jetbrains.control.LocalContentColor
import io.kanro.compose.jetbrains.control.ProvideTextStyle
import io.kanro.compose.jetbrains.control.darkSelectionScope
import io.kanro.compose.jetbrains.control.lightSelectionScope

@Composable
fun JBTheme(style: JBThemeStyle, content: @Composable () -> Unit) {
    JBTheme(
        style = style,
        buttonColors = if (style == JBThemeStyle.LIGHT) lightButtonColors() else darkButtonColors(),
        fieldColors = if (style == JBThemeStyle.LIGHT) lightFieldColors() else darkFieldColors(),
        focusColors = if (style == JBThemeStyle.LIGHT) lightFocusColors() else darkFocusColors(),
        panelColors = if (style == JBThemeStyle.LIGHT) lightPanelColors() else darkPanelColors(),
        textColors = if (style == JBThemeStyle.LIGHT) lightTextColors() else darkTextColors(),
        toolBarColors = if (style == JBThemeStyle.LIGHT) lightToolBarColors() else darkToolBarColors(),
        progressColors = if (style == JBThemeStyle.LIGHT) lightProgressColors() else darkProgressColors(),
        scrollColors = if (style == JBThemeStyle.LIGHT) lightScrollColors() else darkScrollColors(),
        tabColors = if (style == JBThemeStyle.LIGHT) lightTabColors() else darkTabColors(),
        selectionColors = if (style == JBThemeStyle.LIGHT) lightSelectionColors() else darkSelectionColors(),
        checkBoxColors = if (style == JBThemeStyle.LIGHT) lightCheckBoxColors() else darkCheckBoxColors(),
        iconColors = if (style == JBThemeStyle.LIGHT) lightIconColors() else darkIconColors(),
        typography = JBTypography(),
        iconTheme = if (style == JBThemeStyle.LIGHT) JBThemeStyle.LIGHT else JBThemeStyle.DARK,
        selectionScope = if (style == JBThemeStyle.LIGHT) lightSelectionScope else darkSelectionScope,
        content = content
    )
}

@Composable
fun JBDraculaTheme(content: @Composable () -> Unit) {
    JBTheme(
        style = JBThemeStyle.DARK,
        buttonColors = darkButtonColors(),
        fieldColors = darkFieldColors(),
        focusColors = darkFocusColors(),
        panelColors = darkPanelColors(),
        textColors = darkTextColors(),
        toolBarColors = darkToolBarColors(),
        progressColors = darkProgressColors(),
        scrollColors = darkScrollColors(),
        tabColors = darkTabColors(),
        selectionColors = darkSelectionColors(),
        checkBoxColors = darkCheckBoxColors(),
        iconColors = darkIconColors(),
        typography = JBTypography(),
        iconTheme = JBThemeStyle.DARK,
        selectionScope = darkSelectionScope,
        content = content
    )
}

@Composable
fun JBLightTheme(content: @Composable () -> Unit) {
    JBTheme(content = content)
}

@Composable
fun JBTheme(
    style: JBThemeStyle = JBThemeStyle.LIGHT,
    buttonColors: ButtonColors = lightButtonColors(),
    fieldColors: FieldColors = lightFieldColors(),
    focusColors: FocusColors = lightFocusColors(),
    panelColors: PanelColors = lightPanelColors(),
    textColors: TextColors = lightTextColors(),
    toolBarColors: ToolBarColors = lightToolBarColors(),
    progressColors: ProgressColors = lightProgressColors(),
    scrollColors: ScrollColors = lightScrollColors(),
    tabColors: TabColors = lightTabColors(),
    selectionColors: SelectionColors = lightSelectionColors(),
    checkBoxColors: CheckBoxColors = lightCheckBoxColors(),
    iconColors: IconColors = lightIconColors(),
    typography: JBTypography = JBTypography(),
    iconTheme: JBThemeStyle = JBThemeStyle.LIGHT,
    selectionScope: @Composable () -> Array<ProvidedValue<out Any>> = lightSelectionScope,
    content: @Composable () -> Unit,
) {
    CompositionLocalProvider(
        LocalThemeStyle provides style,
        LocalButtonColors provides buttonColors,
        LocalFieldColors provides fieldColors,
        LocalFocusColors provides focusColors,
        LocalPanelColors provides panelColors,
        LocalTextColors provides textColors,
        LocalToolBarColors provides toolBarColors,
        LocalProgressColors provides progressColors,
        LocalScrollColors provides scrollColors,
        LocalTabColors provides tabColors,
        LocalSelectionColors provides selectionColors,
        LocalCheckBoxColors provides checkBoxColors,
        LocalIconColors provides iconColors,
        LocalTypography provides typography,
        LocalIconTheme provides iconTheme,
        LocalContentColor provides Color.Unspecified,
        LocalSelectionScope provides selectionScope,
        LocalScrollbarStyle provides scrollColors.style()
    ) {
        ProvideTextStyle(value = typography.default, content = content)
    }
}

object JBTheme {
    val style: JBThemeStyle
        @Composable @ReadOnlyComposable get() = LocalThemeStyle.current

    val buttonColors: ButtonColors
        @Composable @ReadOnlyComposable get() = LocalButtonColors.current

    val fieldColors: FieldColors
        @Composable @ReadOnlyComposable get() = LocalFieldColors.current

    val focusColors: FocusColors
        @Composable @ReadOnlyComposable get() = LocalFocusColors.current

    val panelColors: PanelColors
        @Composable @ReadOnlyComposable get() = LocalPanelColors.current

    val textColors: TextColors
        @Composable @ReadOnlyComposable get() = LocalTextColors.current

    val toolBarColors: ToolBarColors
        @Composable @ReadOnlyComposable get() = LocalToolBarColors.current

    val progressColors: ProgressColors
        @Composable @ReadOnlyComposable get() = LocalProgressColors.current

    val scrollColors: ScrollColors
        @Composable @ReadOnlyComposable get() = LocalScrollColors.current

    val tabColors: TabColors
        @Composable @ReadOnlyComposable get() = LocalTabColors.current

    val selectionColors: SelectionColors
        @Composable @ReadOnlyComposable get() = LocalSelectionColors.current

    val checkBoxColors: CheckBoxColors
        @Composable @ReadOnlyComposable get() = LocalCheckBoxColors.current

    val iconColors: IconColors
        @Composable @ReadOnlyComposable get() = LocalIconColors.current

    val typography: JBTypography
        @Composable @ReadOnlyComposable get() = LocalTypography.current

    val iconTheme: JBThemeStyle
        @Composable @ReadOnlyComposable get() = LocalIconTheme.current
}

enum class JBThemeStyle {
    LIGHT, DARK
}

val LocalThemeStyle = compositionLocalOf { JBThemeStyle.LIGHT }

val LocalIconTheme = compositionLocalOf { JBThemeStyle.LIGHT }

val LocalSelectionScope = compositionLocalOf<@Composable () -> Array<ProvidedValue<out Any>>> {
    lightSelectionScope
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/JBTypography.kt
================================================
package io.kanro.compose.jetbrains

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.sp

class JBTypography(
    val h0: TextStyle,
    val h1: TextStyle,
    val h2: TextStyle,
    val h2Bold: TextStyle,
    val h3: TextStyle,
    val h3Bold: TextStyle,
    val default: TextStyle,
    val defaultBold: TextStyle,
    val defaultUnderlined: TextStyle,
    val paragraph: TextStyle,
    val medium: TextStyle,
    val mediumBold: TextStyle,
    val small: TextStyle,
    val smallUnderlined: TextStyle,
) {
    constructor(
        defaultFontFamily: FontFamily = FontFamily.Default,
        h0: TextStyle = TextStyle(
            fontWeight = FontWeight.Medium,
            fontSize = 25.sp
        ),
        h1: TextStyle = TextStyle(
            fontWeight = FontWeight.Medium,
            fontSize = 22.sp
        ),
        h2: TextStyle = TextStyle(
            fontWeight = FontWeight.Normal,
            fontSize = 18.sp,
        ),
        h2Bold: TextStyle = h2.copy(fontWeight = FontWeight.Medium),
        h3: TextStyle = TextStyle(
            fontWeight = FontWeight.Normal,
            fontSize = 16.sp,
            lineHeight = 20.sp
        ),
        h3Bold: TextStyle = h3.copy(fontWeight = FontWeight.Medium),
        default: TextStyle = TextStyle(
            fontWeight = FontWeight.Normal,
            fontSize = 12.5.sp,
            lineHeight = 15.sp
        ),
        defaultBold: TextStyle = default.copy(fontWeight = FontWeight.Medium),
        defaultUnderlined: TextStyle = default.copy(textDecoration = TextDecoration.Underline),
        paragraph: TextStyle = TextStyle(
            fontWeight = FontWeight.Normal,
            fontSize = 13.sp,
            lineHeight = 19.sp
        ),
        medium: TextStyle = TextStyle(
            fontWeight = FontWeight.Normal,
            fontSize = 12.sp,
            lineHeight = 15.sp
        ),
        mediumBold: TextStyle = medium.copy(fontWeight = FontWeight.Medium),
        small: TextStyle = TextStyle(
            fontWeight = FontWeight.Normal,
            fontSize = 11.sp,
            lineHeight = 14.sp
        ),
        smallUnderlined: TextStyle = small.copy(textDecoration = TextDecoration.Underline),
    ) : this(
        h0.withDefaultFontFamily(defaultFontFamily),
        h1.withDefaultFontFamily(defaultFontFamily),
        h2.withDefaultFontFamily(defaultFontFamily),
        h2Bold.withDefaultFontFamily(defaultFontFamily),
        h3.withDefaultFontFamily(defaultFontFamily),
        h3Bold.withDefaultFontFamily(defaultFontFamily),
        default.withDefaultFontFamily(defaultFontFamily),
        defaultBold.withDefaultFontFamily(defaultFontFamily),
        defaultUnderlined.withDefaultFontFamily(defaultFontFamily),
        paragraph.withDefaultFontFamily(defaultFontFamily),
        medium.withDefaultFontFamily(defaultFontFamily),
        mediumBold.withDefaultFontFamily(defaultFontFamily),
        small.withDefaultFontFamily(defaultFontFamily),
        smallUnderlined.withDefaultFontFamily(defaultFontFamily)
    )

    companion object {
        private fun TextStyle.withDefaultFontFamily(default: FontFamily): TextStyle {
            return if (fontFamily != null) this else copy(fontFamily = default)
        }
    }
}

val LocalTypography = compositionLocalOf { JBTypography() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ButtonColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import io.kanro.compose.jetbrains.JBTheme

class ButtonColors(
    bg: Color,
    border: Color,
    borderRegularFocused: Color,
    defaultStart: Color,
    defaultEnd: Color,
    borderDefaultStart: Color,
    borderDefaultEnd: Color,
    borderDefaultFocused: Color,
    bgDisabled: Color,
    borderDisabled: Color,
) {
    var bg by mutableStateOf(bg)
    var border by mutableStateOf(border)
    var borderRegularFocused by mutableStateOf(borderRegularFocused)
    var defaultStart by mutableStateOf(defaultStart)
    var defaultEnd by mutableStateOf(defaultEnd)
    var borderDefaultStart by mutableStateOf(borderDefaultStart)
    var borderDefaultEnd by mutableStateOf(borderDefaultEnd)
    var borderDefaultFocused by mutableStateOf(borderDefaultFocused)
    var bgDisabled by mutableStateOf(bgDisabled)
    var borderDisabled by mutableStateOf(borderDisabled)

    fun copy(
        bg: Color = this.bg,
        border: Color = this.border,
        borderRegularFocused: Color = this.borderRegularFocused,
        defaultStart: Color = this.defaultStart,
        defaultEnd: Color = this.defaultEnd,
        borderDefaultStart: Color = this.borderDefaultStart,
        borderDefaultEnd: Color = this.borderDefaultEnd,
        borderDefaultFocused: Color = this.borderDefaultFocused,
        disabled: Color = this.bgDisabled,
        borderDisabled: Color = this.borderDisabled,
    ): ButtonColors {
        return ButtonColors(
            bg,
            border,
            borderRegularFocused,
            defaultStart,
            defaultEnd,
            borderDefaultStart,
            borderDefaultEnd,
            borderDefaultFocused,
            disabled,
            borderDisabled
        )
    }

    @Composable
    private fun bgStartColor(enable: Boolean, default: Boolean): State<Color> {
        val targetValue = when {
            !enable -> bgDisabled
            default -> defaultStart
            else -> bg
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    private fun bgEndColor(enable: Boolean, default: Boolean): State<Color> {
        val targetValue = when {
            !enable -> bgDisabled
            default -> defaultStart
            else -> bg
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    fun bgBrush(enable: Boolean, default: Boolean): State<Brush> {
        val start by bgStartColor(enable, default)
        val end by bgEndColor(enable, default)
        val targetValue = if (start == end) {
            SolidColor(start)
        } else {
            Brush.linearGradient(listOf(start, end))
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    private fun borderStartColor(enable: Boolean, default: Boolean, focused: Boolean): State<Color> {
        val targetValue = when {
            !enable -> borderDisabled
            default && focused -> borderDefaultFocused
            default -> borderDefaultStart
            focused -> borderRegularFocused
            else -> border
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    private fun borderEndColor(enable: Boolean, default: Boolean, focused: Boolean): State<Color> {
        val targetValue = when {
            !enable -> borderDisabled
            default && focused -> borderDefaultFocused
            default -> borderDefaultEnd
            focused -> borderRegularFocused
            else -> border
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    fun borderBrush(enable: Boolean, default: Boolean, interactionSource: InteractionSource): State<Brush> {
        val focused by interactionSource.collectIsFocusedAsState()
        val start by borderStartColor(enable, default, focused)
        val end by borderEndColor(enable, default, focused)
        val targetValue = if (start == end) {
            SolidColor(start)
        } else {
            Brush.linearGradient(listOf(start, end))
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    fun textColor(enable: Boolean, default: Boolean): State<Color> {
        val start by bgStartColor(enable, default)
        val targetValue = if ((start.green + start.blue + start.red) / 3.0 > 0.6) {
            JBTheme.textColors.default
        } else {
            JBTheme.textColors.white
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    fun focusingColor(enable: Boolean, interactionSource: InteractionSource): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()
        val targetValue = when {
            !enable -> Color.Transparent
            focused -> JBTheme.focusColors.default
            else -> Color.Transparent
        }
        return rememberUpdatedState(targetValue)
    }
}

fun lightButtonColors(): ButtonColors {
    return ButtonColors(
        Color.White,
        Color(0xFFC4C4C4),
        Color(0xFF87AFDA),
        Color(0xFF528CC7), Color(0xFF4989CC),
        Color(0xFF487EB8), Color(0xFF346DAD),
        Color(0xFFA8CEF6),
        Color(0xFFF2F2F2),
        Color(0xFFCFCFCF),
    )
}

fun darkButtonColors(): ButtonColors {
    return ButtonColors(
        Color(0xFF4C5052),
        Color(0xFF5E6060),
        Color(0xFF456A90),
        Color(0xFF365880), Color(0xFF365880),
        Color(0xFF4C708C), Color(0xFF4C708C),
        Color(0xFF537699),
        Color(0xFF3C3F41),
        Color(0xFF646464),
    )
}

val LocalButtonColors = compositionLocalOf { lightButtonColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/CheckBoxColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class CheckBoxColors(
    bg: Color,
    bgSelected: Color,
    bgDisabled: Color,
    border: Color,
    borderSelected: Color,
    borderFocused: Color,
    borderDisabled: Color,
) {
    var bg by mutableStateOf(bg)
    var bgSelected by mutableStateOf(bgSelected)
    var bgDisabled by mutableStateOf(bgDisabled)
    var border by mutableStateOf(border)
    var borderSelected by mutableStateOf(borderSelected)
    var borderFocused by mutableStateOf(borderFocused)
    var borderDisabled by mutableStateOf(borderDisabled)

    fun copy(
        bg: Color = this.bg,
        bgSelected: Color = this.bgSelected,
        bgDisabled: Color = this.bgDisabled,
        border: Color = this.border,
        borderSelected: Color = this.borderSelected,
        borderFocused: Color = this.borderFocused,
        borderDisabled: Color = this.borderDisabled,
    ): CheckBoxColors {
        return CheckBoxColors(
            bg,
            bgSelected,
            bgDisabled,
            border,
            borderSelected,
            borderFocused,
            borderDisabled
        )
    }
}

fun lightCheckBoxColors(): CheckBoxColors {
    return CheckBoxColors(
        Color.White,
        Color(0xFF4F9EE3),
        Color(0xFFF2F2F2),
        Color(0xFFB0B0B0),
        Color(0xFF4B97D9),
        Color(0xFF7B9FC7),
        Color(0xFFBDBDBD),
    )
}

fun darkCheckBoxColors(): CheckBoxColors {
    return CheckBoxColors(
        Color(0xFF43494A),
        Color(0xFF43494A),
        Color(0xFF3C3F41),
        Color(0xFF6B6B6B),
        Color(0xFF4C708C),
        Color(0xFF43698E),
        Color(0xFF545556),
    )
}

val LocalCheckBoxColors = compositionLocalOf { lightCheckBoxColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/FieldColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import io.kanro.compose.jetbrains.JBTheme

class FieldColors(
    bg: Color,
    border: Color,
    borderFocused: Color,
    comboboxButton: Color,
    bgDisabled: Color,
    borderDisabled: Color,
    borderError: Color,
) {
    var bg by mutableStateOf(bg)
    var border by mutableStateOf(border)
    var borderFocused by mutableStateOf(borderFocused)
    var comboboxButton by mutableStateOf(comboboxButton)
    var bgDisabled by mutableStateOf(bgDisabled)
    var borderDisabled by mutableStateOf(borderDisabled)
    var borderError by mutableStateOf(borderError)

    fun copy(
        bg: Color = this.bg,
        border: Color = this.border,
        borderFocused: Color = this.borderFocused,
        comboboxButton: Color = this.comboboxButton,
        bgDisabled: Color = this.bgDisabled,
        borderDisabled: Color = this.borderDisabled,
        borderError: Color = this.borderError,
    ): FieldColors {
        return FieldColors(bg, border, borderFocused, comboboxButton, bgDisabled, borderDisabled, borderError)
    }

    @Composable
    fun bgColor(enable: Boolean): State<Color> {
        return rememberUpdatedState(if (enable) bg else bgDisabled)
    }

    @Composable
    fun borderColor(enable: Boolean, error: Boolean, interactionSource: InteractionSource): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()
        val targetValue = when {
            !enable -> borderDisabled
            error -> borderError
            focused -> borderFocused
            else -> border
        }
        return if (enable) {
            animateColorAsState(targetValue, tween(durationMillis = AnimationDuration))
        } else {
            rememberUpdatedState(targetValue)
        }
    }

    @Composable
    fun focusingColor(enable: Boolean, error: Boolean, interactionSource: InteractionSource): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()
        val targetValue = when {
            !enable -> Color.Transparent
            error -> JBTheme.focusColors.error
            focused -> JBTheme.focusColors.default
            else -> Color.Transparent
        }
        return rememberUpdatedState(targetValue)
    }

    companion object {
        internal const val AnimationDuration = 150
    }
}

fun lightFieldColors(): FieldColors {
    return FieldColors(
        Color.White,
        Color(0xFFC4C4C4),
        Color(0xFF87AFDA),
        Color(0xFFFAFAFA),
        Color(0xFFF2F2F2),
        Color(0xFFCFCFCF),
        Color(0xFFCE3845),
    )
}

fun darkFieldColors(): FieldColors {
    return FieldColors(
        Color(0xFF4C5052),
        Color(0xFF5E6060),
        Color(0xFF456A90),
        Color(0xFF3C3F41),
        Color(0xFF3C3F41),
        Color(0xFF646464),
        Color(0xFF73454B),
    )
}

val LocalFieldColors = compositionLocalOf { lightFieldColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/FocusColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class FocusColors(
    default: Color,
    error: Color,
    warning: Color,
    warningInactive: Color,
) {
    var default by mutableStateOf(default)
    var error by mutableStateOf(error)
    var warning by mutableStateOf(warning)
    var warningInactive by mutableStateOf(warningInactive)

    fun copy(
        default: Color = this.default,
        error: Color = this.error,
        warning: Color = this.warning,
        warningInactive: Color = this.warningInactive,
    ): FocusColors {
        return FocusColors(default, error, warning, warningInactive)
    }
}

fun lightFocusColors(): FocusColors {
    return FocusColors(
        Color(0xFF97C3F3),
        Color(0xFFE53E4D),
        Color(0xFFE1A336),
        Color(0xFFEAD2A1),
    )
}

fun darkFocusColors(): FocusColors {
    return FocusColors(
        Color(0xFF3D6185),
        Color(0xFF8B3C3C),
        Color(0xFFAC7920),
        Color(0xFF6E5324),
    )
}

val LocalFocusColors = compositionLocalOf { lightFocusColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/IconColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class IconColors(
    selected: Color,
    disabled: Color,
) {
    var selected by mutableStateOf(selected)
    var disabled by mutableStateOf(disabled)

    fun copy(
        selected: Color = this.selected,
        disabled: Color = this.disabled,
    ): IconColors {
        return IconColors(
            selected,
            disabled,
        )
    }
}

fun lightIconColors(): IconColors {
    return IconColors(
        Color.White,
        Color(0xFFABABAB),
    )
}

fun darkIconColors(): IconColors {
    return IconColors(
        Color(0xFFFEFEFE),
        Color(0xFFABABAB),
    )
}

val LocalIconColors = compositionLocalOf { lightIconColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/PanelColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class PanelColors(
    border: Color,
    bgContent: Color,
    bgDialog: Color,
) {
    var border by mutableStateOf(border)
    var bgContent by mutableStateOf(bgContent)
    var bgDialog by mutableStateOf(bgDialog)

    fun copy(
        border: Color = this.border,
        bgContent: Color = this.bgContent,
        bgDialog: Color = this.bgDialog,
    ): PanelColors {
        return PanelColors(border, bgContent, bgDialog)
    }
}

fun lightPanelColors(): PanelColors {
    return PanelColors(
        Color(0xFFD1D1D1),
        Color.White,
        Color(0xFFF2F2F2),
    )
}

fun darkPanelColors(): PanelColors {
    return PanelColors(
        Color(0xFF323232),
        Color(0xFF3C3F41),
        Color(0xFF3C3F41),
    )
}

val LocalPanelColors = compositionLocalOf { lightPanelColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ProgressColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class ProgressColors(
    progress: Color,
    bg: Color,
) {
    var progress by mutableStateOf(progress)
    var bg by mutableStateOf(bg)

    fun copy(
        progress: Color = this.progress,
        bg: Color = this.bg,
    ): ProgressColors {
        return ProgressColors(progress, bg)
    }
}

fun lightProgressColors(): ProgressColors {
    return ProgressColors(
        Color(0xFF1E82E6),
        Color(0xFFD5D5D5),
    )
}

fun darkProgressColors(): ProgressColors {
    return ProgressColors(
        Color(0xFFA0A0A0),
        Color(0xFF555555),
    )
}

val LocalProgressColors = compositionLocalOf { lightProgressColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ScrollColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.foundation.ScrollbarStyle
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

class ScrollColors(
    bg: Color,
) {
    var bg by mutableStateOf(bg)

    fun copy(
        bg: Color = this.bg,
    ): ScrollColors {
        return ScrollColors(bg)
    }

    fun style(): ScrollbarStyle {
        return ScrollbarStyle(
            minimalHeight = 30.dp,
            thickness = 7.dp,
            shape = CircleShape,
            hoverDurationMillis = 0,
            unhoverColor = bg,
            hoverColor = bg
        )
    }
}

fun lightScrollColors(): ScrollColors {
    return ScrollColors(
        Color(0xFFC9C9C9),
    )
}

fun darkScrollColors(): ScrollColors {
    return ScrollColors(
        Color(0xFF494949)
    )
}

val LocalScrollColors = compositionLocalOf { lightScrollColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/SelectionColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class SelectionColors(
    active: Color,
    inactive: Color,
    hover: Color,
    lightActive: Color,
    lightInactive: Color,
    completionPopup: Color,
) {
    var active by mutableStateOf(active)
    var inactive by mutableStateOf(inactive)
    var hover by mutableStateOf(hover)
    var lightActive by mutableStateOf(lightActive)
    var lightInactive by mutableStateOf(lightInactive)
    var completionPopup by mutableStateOf(completionPopup)

    fun copy(
        active: Color = this.active,
        inactive: Color = this.inactive,
        hover: Color = this.hover,
        lightActive: Color = this.lightActive,
        lightInactive: Color = this.lightInactive,
        completionPopup: Color = this.completionPopup,
    ): SelectionColors {
        return SelectionColors(active, inactive, hover, lightActive, lightInactive, completionPopup)
    }
}

fun lightSelectionColors(): SelectionColors {
    return SelectionColors(
        Color(0xFF2675BF),
        Color(0xFFD5D5D5),
        Color(0xFFEDF5FC),
        Color(0xFFEDF6FE),
        Color(0xFFF5F5F5),
        Color(0xFFC5DFFC),
    )
}

fun darkSelectionColors(): SelectionColors {
    return SelectionColors(
        Color(0xFF2F65CA),
        Color(0xFF0D293E),
        Color(0xFF464A4D),
        Color(0xFF464A4D),
        Color(0xFF35383B),
        Color(0xFF113A5C),
    )
}

val LocalSelectionColors = compositionLocalOf { lightSelectionColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/TabColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class TabColors(
    selection: Color,
    focus: Color,
    selectionInactive: Color,
    hover: Color,
    selectionDisabled: Color,
    bgSelected: Color,
) {
    var selection by mutableStateOf(selection)
    var focus by mutableStateOf(focus)
    var selectionInactive by mutableStateOf(selectionInactive)
    var hover by mutableStateOf(hover)
    var selectionDisabled by mutableStateOf(selectionDisabled)
    var bgSelected by mutableStateOf(bgSelected)

    fun copy(
        selection: Color = this.selection,
        focus: Color = this.focus,
        selectionInactive: Color = this.selectionInactive,
        hover: Color = this.hover,
        selectionDisabled: Color = this.selectionDisabled,
        bgSelected: Color = this.bgSelected,
    ): TabColors {
        return TabColors(selection, focus, selectionInactive, hover, selectionDisabled, bgSelected)
    }
}

fun lightTabColors(): TabColors {
    return TabColors(
        Color(0xFF4083C9),
        Color(0xFFDAE4ED),
        Color(0xFF9CA7B8),
        Color(0x19000000),
        Color(0xFFABABAB),
        Color(0xFFFFFFFF),
    )
}

fun darkTabColors(): TabColors {
    return TabColors(
        Color(0xFF4A88C7),
        Color(0xFF3D4B5C),
        Color(0xFF747A80),
        Color(0xFF2E3133),
        Color(0xFF595959),
        Color(0xFF4E5254),
    )
}

val LocalTabColors = compositionLocalOf { lightTabColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/TableColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class TableColors(
    bg: Color,
    headerBorder: Color,
    outerBorder: Color,
) {
    var bg by mutableStateOf(bg)
    var headerBorder by mutableStateOf(headerBorder)
    var outerBorder by mutableStateOf(outerBorder)
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/TextColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class TextColors(
    default: Color,
    disabled: Color,
    white: Color,
    link: Color,
    infoPanel: Color,
    infoInput: Color,
    error: Color,
    success: Color,
) {
    var default by mutableStateOf(default)
    var disabled by mutableStateOf(disabled)
    var white by mutableStateOf(white)
    var link by mutableStateOf(link)
    var infoPanel by mutableStateOf(infoPanel)
    var infoInput by mutableStateOf(infoInput)
    var error by mutableStateOf(error)
    var success by mutableStateOf(success)

    fun copy(
        default: Color = this.default,
        disabled: Color = this.disabled,
        white: Color = this.white,
        link: Color = this.link,
        infoPanel: Color = this.infoPanel,
        infoInput: Color = this.infoInput,
        error: Color = this.error,
        success: Color = this.success,
    ): TextColors {
        return TextColors(default, disabled, white, link, infoPanel, infoInput, error, success)
    }
}

fun lightTextColors(): TextColors {
    return TextColors(
        Color.Black,
        Color(0xFF8C8C8C),
        Color.White,
        Color(0xFF2470B3),
        Color(0xFF808080),
        Color(0xFF999999),
        Color(0xFFC7222D),
        Color(0xFF368746),
    )
}

fun darkTextColors(): TextColors {
    return TextColors(
        Color(0xFFBBBBBB),
        Color(0xFF777777),
        Color(0xFFFEFEFE),
        Color(0xFF589DF6),
        Color(0xFF8C8C8C),
        Color(0xFF787878),
        Color(0xFFFF5261),
        Color(0xFF50A661),
    )
}

val LocalTextColors = compositionLocalOf { lightTextColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ToggleColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class ToggleColors(
    bg: Color,
    off: Color,
    on: Color,
) {
    var bg by mutableStateOf(bg)
    var off by mutableStateOf(off)
    var on by mutableStateOf(on)
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ToolBarColors.kt
================================================
package io.kanro.compose.jetbrains.color

import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color

class ToolBarColors(
    buttonPressed: Color,
    buttonHover: Color,
    iconSplitBorder: Color,
) {
    var buttonPressed by mutableStateOf(buttonPressed)
    var buttonHover by mutableStateOf(buttonHover)
    var iconSplitBorder by mutableStateOf(iconSplitBorder)

    fun copy(
        buttonPressed: Color = this.buttonPressed,
        buttonHover: Color = this.buttonHover,
        iconSplitBorder: Color = this.iconSplitBorder,
    ): ToolBarColors {
        return ToolBarColors(buttonPressed, buttonHover, iconSplitBorder)
    }

    @Composable
    fun actionIconBgColor(interactionSource: InteractionSource): State<Color> {
        val pressed by interactionSource.collectIsPressedAsState()
        val hover by interactionSource.collectIsHoveredAsState()
        val targetValue = when {
            pressed -> buttonPressed
            hover -> buttonHover
            else -> Color.Transparent
        }
        return rememberUpdatedState(targetValue)
    }
}

fun lightToolBarColors(): ToolBarColors {
    return ToolBarColors(
        Color(0xFFCFCFCF),
        Color(0xFFDFDFDF),
        Color(0xFFB3B3B3),
    )
}

fun darkToolBarColors(): ToolBarColors {
    return ToolBarColors(
        Color(0xFF5C6164),
        Color(0xFF4C5052),
        Color(0xFF6B6B6B),
    )
}

val LocalToolBarColors = compositionLocalOf { lightToolBarColors() }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ActionButton.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Indication
import androidx.compose.foundation.IndicationInstance
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBTheme

object ActionButtonIndication : Indication {
    private class ActionButtonIndicationInstance(
        private val shape: Shape,
        private val isHover: State<Boolean>,
        private val isPressed: State<Boolean>,
        private val hoverColor: Color,
        private val pressedColor: Color,
    ) : IndicationInstance {
        override fun ContentDrawScope.drawIndication() {
            when {
                isPressed.value -> {
                    val outline = shape.createOutline(size, layoutDirection, this)
                    drawOutline(outline, pressedColor)
                }

                isHover.value -> {
                    val outline = shape.createOutline(size, layoutDirection, this)
                    drawOutline(outline, hoverColor)
                }
            }
            drawContent()
        }
    }

    @Composable
    override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
        val shape = remember { RoundedCornerShape(3.dp) }
        val isPressed = interactionSource.collectIsPressedAsState()
        val isHover = interactionSource.collectIsHoveredAsState()
        val hoverColor = JBTheme.toolBarColors.buttonHover
        val pressedColor = JBTheme.toolBarColors.buttonPressed
        return remember(JBTheme.toolBarColors, interactionSource) {
            ActionButtonIndicationInstance(
                shape,
                isHover,
                isPressed,
                hoverColor,
                pressedColor
            )
        }
    }
}

object ActionButtonDefaults {
    private val ButtonHorizontalPadding = 3.dp
    private val ButtonVerticalPadding = 3.dp

    val MinWidth = 22.dp

    val MinHeight = 22.dp

    val IconSize = 16.dp

    val ContentPadding = PaddingValues(
        start = ButtonHorizontalPadding,
        top = ButtonVerticalPadding,
        end = ButtonHorizontalPadding,
        bottom = ButtonVerticalPadding
    )
}

@Composable
fun ActionButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    background: Color = Color.Transparent,
    indication: Indication? = ActionButtonIndication,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = RoundedCornerShape(3.dp),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ActionButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit,
) {
    Box(
        modifier
            .then(if (border != null) Modifier.border(border, shape) else Modifier)
            .background(
                color = background,
                shape = shape
            )
            .clip(shape)
            .clickable(
                interactionSource = interactionSource,
                indication = indication,
                enabled = enabled,
                onClick = onClick
            )
            .hoverable(interactionSource, enabled),
        propagateMinConstraints = true
    ) {
        CompositionLocalProvider(
            LocalContentColor provides (if (!enabled) JBTheme.iconColors.disabled else LocalContentColor.current)
        ) {
            Row(
                Modifier
                    .defaultMinSize(
                        minWidth = ActionButtonDefaults.MinWidth,
                        minHeight = ActionButtonDefaults.MinHeight
                    )
                    .padding(contentPadding),
                horizontalArrangement = Arrangement.Center,
                verticalAlignment = Alignment.CenterVertically,
                content = content
            )
        }
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Button.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathFillType
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.addOutline
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.isSpecified
import io.kanro.compose.jetbrains.JBTheme

@Stable
interface ButtonStyle {
    @Composable
    fun borderBrush(enabled: Boolean): State<Brush>

    @Composable
    fun backgroundBrush(enabled: Boolean): State<Brush>

    @Composable
    fun contentColor(enabled: Boolean): State<Color>

    @Composable
    fun focusingColor(enabled: Boolean, interactionSource: InteractionSource): State<Color>
}

private data class DefaultButtonStyle(
    private val borderBrush: Brush,
    private val backgroundBrush: Brush,
    private val contentColor: Color,
    private val disableBorderBrush: Brush,
    private val disableBackgroundBrush: Brush,
    private val disabledContentColor: Color,
    private val focusingColor: Color,
) : ButtonStyle {
    @Composable
    override fun borderBrush(enabled: Boolean): State<Brush> {
        return rememberUpdatedState(if (enabled) borderBrush else disableBorderBrush)
    }

    @Composable
    override fun backgroundBrush(enabled: Boolean): State<Brush> {
        return rememberUpdatedState(if (enabled) backgroundBrush else disableBackgroundBrush)
    }

    @Composable
    override fun contentColor(enabled: Boolean): State<Color> {
        return rememberUpdatedState(if (enabled) contentColor else disabledContentColor)
    }

    @Composable
    override fun focusingColor(enabled: Boolean, interactionSource: InteractionSource): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()
        return rememberUpdatedState(if (enabled && focused) focusingColor else Color.Transparent)
    }
}

object ButtonDefaults {
    private val ButtonHorizontalPadding = 14.dp
    private val ButtonVerticalPadding = 3.dp

    val ContentPadding = PaddingValues(
        start = ButtonHorizontalPadding,
        top = ButtonVerticalPadding,
        end = ButtonHorizontalPadding,
        bottom = ButtonVerticalPadding
    )

    val MinWidth = 72.dp

    val MinHeight = 24.dp

    val IconSize = 16.dp

    val IconSpacing = 8.dp

    @Composable
    fun buttonStyle(
        borderBrush: Brush = Brush.verticalGradient(
            listOf(
                JBTheme.buttonColors.borderDefaultStart,
                JBTheme.buttonColors.borderDefaultEnd
            )
        ),
        backgroundBrush: Brush = Brush.verticalGradient(
            listOf(
                JBTheme.buttonColors.defaultStart,
                JBTheme.buttonColors.defaultEnd
            )
        ),
        contentColor: Color = JBTheme.contentColorFor(JBTheme.buttonColors.defaultEnd),
        disableBorderBrush: Brush = SolidColor(JBTheme.buttonColors.borderDisabled),
        disableBackgroundBrush: Brush = SolidColor(JBTheme.buttonColors.bgDisabled),
        disabledContentColor: Color = JBTheme.textColors.disabled,
        focusingColor: Color = JBTheme.focusColors.default,
    ): ButtonStyle = DefaultButtonStyle(
        borderBrush,
        backgroundBrush,
        contentColor,
        disableBorderBrush,
        disableBackgroundBrush,
        disabledContentColor,
        focusingColor
    )

    @Composable
    fun outlineButtonStyle(
        borderBrush: Brush = SolidColor(JBTheme.buttonColors.border),
        backgroundBrush: Brush = SolidColor(JBTheme.buttonColors.bg),
        contentColor: Color = JBTheme.contentColorFor(JBTheme.buttonColors.bg),
        disableBorderBrush: Brush = SolidColor(JBTheme.buttonColors.borderDisabled),
        disableBackgroundBrush: Brush = SolidColor(JBTheme.buttonColors.bgDisabled),
        disabledContentColor: Color = JBTheme.textColors.disabled,
        focusingColor: Color = JBTheme.focusColors.default,
    ): ButtonStyle = DefaultButtonStyle(
        borderBrush,
        backgroundBrush,
        contentColor,
        disableBorderBrush,
        disableBackgroundBrush,
        disabledContentColor,
        focusingColor
    )
}

@Composable
fun Button(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = RoundedCornerShape(3.dp),
    borderWidth: Dp = 1.dp,
    style: ButtonStyle = ButtonDefaults.buttonStyle(),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit,
) {
    val focusRequester = remember { FocusRequester() }

    Box(
        modifier
            .then(
                if (borderWidth.isSpecified) Modifier.border(
                    borderWidth,
                    style.borderBrush(enabled).value,
                    shape
                ) else Modifier
            )
            .background(
                brush = style.backgroundBrush(enabled).value,
                shape = shape
            )
            .focusRequester(focusRequester)
            .focusable(enabled, interactionSource)
            .clickable(
                interactionSource = interactionSource,
                indication = null,
                enabled = enabled,
                onClick = onClick
            )
            .pointerInput("Fo") {
                this.awaitPointerEventScope {
                    var event: PointerEvent
                    do {
                        event = awaitPointerEvent()
                        if (event.changes.any { it.changedToDownIgnoreConsumed() }) {
                            focusRequester.requestFocus()
                        }
                    } while (true)
                }
            }
            .buttonIndicator(style.focusingColor(enabled, interactionSource).value, shape, 2.dp, 5.dp),
        propagateMinConstraints = true
    ) {
        val contentColor by style.contentColor(enabled)
        CompositionLocalProvider(
            LocalContentAlpha provides contentColor.alpha,
            LocalContentColor provides contentColor
        ) {
            ProvideTextStyle(JBTheme.typography.defaultBold) {
                Row(
                    Modifier
                        .defaultMinSize(
                            minWidth = ButtonDefaults.MinWidth,
                            minHeight = ButtonDefaults.MinHeight
                        )
                        .padding(contentPadding),
                    horizontalArrangement = Arrangement.Center,
                    verticalAlignment = Alignment.CenterVertically,
                    content = content
                )
            }
        }
    }
}

private fun Modifier.buttonIndicator(color: Color, shape: Shape, width: Dp, cornerRadius: Dp): Modifier {
    if (color.alpha == 0f) return this
    return drawBehind {
        val controlOutline = shape.createOutline(size, layoutDirection, this)
        val highlightOutline = RoundRect(controlOutline.bounds.inflate(width.toPx()), CornerRadius(cornerRadius.toPx()))
        val highlightPath = Path().apply {
            this.fillType = PathFillType.EvenOdd
            addRoundRect(highlightOutline)
            addOutline(controlOutline)
            close()
        }

        drawPath(highlightPath, color)
    }
}

@Composable
fun OutlineButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = RoundedCornerShape(3.dp),
    borderWidth: Dp = 1.dp,
    style: ButtonStyle = ButtonDefaults.outlineButtonStyle(),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit,
) = Button(onClick, modifier, enabled, interactionSource, shape, borderWidth, style, contentPadding, content)


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/CheckBox.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.selection.triStateToggleable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.state.ToggleableState
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBTheme
import io.kanro.compose.jetbrains.icons.JBIcons
import io.kanro.compose.jetbrains.icons.jbicons.Actions
import io.kanro.compose.jetbrains.icons.jbicons.actions.Checkmark
import io.kanro.compose.jetbrains.icons.jbicons.actions.CheckmarkIndeterminate

@Composable
fun CheckBox(
    checked: Boolean,
    onCheckedChange: ((Boolean) -> Unit)?,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
    TriStateCheckbox(
        state = ToggleableState(checked),
        onClick = if (onCheckedChange != null) {
            { onCheckedChange(!checked) }
        } else null,
        interactionSource = interactionSource,
        enabled = enabled,
        modifier = modifier
    )
}

@Composable
fun TriStateCheckbox(
    state: ToggleableState,
    onClick: (() -> Unit)?,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
    val toggleableModifier =
        if (onClick != null) {
            Modifier.triStateToggleable(
                state = state,
                onClick = onClick,
                enabled = enabled,
                role = Role.Checkbox,
                interactionSource = interactionSource,
                indication = null
            )
        } else {
            Modifier
        }

    CheckboxImpl(
        enabled = enabled,
        value = state,
        modifier = modifier
            .then(toggleableModifier),
    )
}

@Composable
private fun CheckboxImpl(
    enabled: Boolean,
    value: ToggleableState,
    modifier: Modifier,
) {
    val icon = when (value) {
        ToggleableState.On -> rememberVectorPainter(JBIcons.Actions.Checkmark)
        ToggleableState.Indeterminate -> rememberVectorPainter(JBIcons.Actions.CheckmarkIndeterminate)
        else -> null
    }
    val iconFilter = if (!enabled) {
        ColorFilter.tint(JBTheme.iconColors.disabled, BlendMode.DstIn)
    } else null

    val bg = if (enabled) {
        when (value) {
            ToggleableState.On, ToggleableState.Indeterminate -> JBTheme.checkBoxColors.bgSelected
            ToggleableState.Off -> JBTheme.checkBoxColors.bg
        }
    } else JBTheme.checkBoxColors.bgDisabled

    val border = if (enabled) {
        when (value) {
            ToggleableState.On, ToggleableState.Indeterminate -> JBTheme.checkBoxColors.borderSelected
            ToggleableState.Off -> JBTheme.checkBoxColors.border
        }
    } else JBTheme.checkBoxColors.borderDisabled

    Canvas(modifier.wrapContentSize(Alignment.Center).requiredSize(14.dp)) {
        drawRoundRect(border, cornerRadius = CornerRadius(2.dp.toPx()))
        drawRoundRect(
            bg,
            size = Size(12.dp.toPx(), 12.dp.toPx()),
            topLeft = Offset(1.dp.toPx(), 1.dp.toPx()),
            cornerRadius = CornerRadius(1.dp.toPx())
        )
        if (icon != null) {
            with(icon) {
                14.dp.toPx()
                draw(Size(14.dp.toPx(), 14.dp.toPx()), colorFilter = iconFilter)
            }
        }
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ComboBox.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathFillType
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.addOutline
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBThemeStyle
import io.kanro.compose.jetbrains.LocalIconTheme
import io.kanro.compose.jetbrains.icons.JBIcons
import io.kanro.compose.jetbrains.icons.jbicons.General
import io.kanro.compose.jetbrains.icons.jbicons.general.ButtonDropTriangle
import io.kanro.compose.jetbrains.icons.jbicons.general.ButtonDropTriangleDark

@Composable
fun <T> DropdownList(
    items: List<T>,
    value: T,
    onValueChange: ((T) -> Unit)? = null,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    valueRender: (T) -> String = { it.toString() },
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    style: TextFieldStyle = TextFieldDefaults.textFieldStyle(),
) {
    val shape = RoundedCornerShape(3.dp)
    val focusRequester = remember { FocusRequester() }
    val expanded = remember { mutableStateOf(false) }

    Box(
        modifier.border(1.dp, style.borderColor(enabled, false, interactionSource).value, shape).height(24.dp)
            .background(style.backgroundColor(enabled, interactionSource).value).focusable(enabled, interactionSource)
            .focusRequester(focusRequester)
            .clickable(interactionSource = interactionSource, indication = null, enabled = enabled, onClick = {
                expanded.value = true
                focusRequester.requestFocus()
            }).comboBoxIndicator(style.indicatorColor(false, interactionSource).value, shape, 2.dp)
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            Spacer(Modifier.width(6.dp))
            Text(
                valueRender(value),
                Modifier.defaultMinSize(50.dp),
                color = style.textColor(enabled, false, interactionSource).value
            )
            Spacer(Modifier.width(1.dp).fillMaxHeight())
            Box(Modifier.size(22.dp), contentAlignment = Alignment.Center) {
                val isDarkTheme = LocalIconTheme.current == JBThemeStyle.DARK
                Icon(
                    imageVector = if (isDarkTheme) JBIcons.General.ButtonDropTriangleDark
                    else JBIcons.General.ButtonDropTriangle
                )
            }
        }

        DropdownMenu(expanded.value, offset = DpOffset(0.dp, 4.dp), onDismissRequest = {
            expanded.value = false
        }) {
            items.forEach {
                DropdownMenuItem(
                    modifier = Modifier.defaultMinSize(79.dp, 21.dp), onClick = {
                        expanded.value = false
                        onValueChange?.invoke(it)
                    }, enabled = enabled
                ) {
                    Text(valueRender(it), Modifier.padding(horizontal = 6.dp))
                }
            }
        }
    }
}

private fun Modifier.comboBoxIndicator(color: Color, shape: Shape, width: Dp): Modifier {
    if (color.alpha == 0f) return this
    return drawBehind {
        val controlOutline = shape.createOutline(size, layoutDirection, this)
        val highlightPath = Path().apply {
            this.fillType = PathFillType.EvenOdd
            addOutline(controlOutline)
            val borderRect = controlOutline.bounds.inflate(width.toPx())
            addRoundRect(RoundRect(borderRect, 4.dp.toPx(), 4.dp.toPx()))
            close()
        }
        drawPath(highlightPath, color)
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ContentAlpha.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.runtime.compositionLocalOf

val LocalContentAlpha = compositionLocalOf { 1f }


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ContentColor.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.runtime.Composable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
import io.kanro.compose.jetbrains.JBTheme

val LocalContentColor = compositionLocalOf { Color.Unspecified }

@Composable
fun JBTheme.contentColorFor(backgroundColor: Color): Color {
    return if ((backgroundColor.green + backgroundColor.blue + backgroundColor.red) / 3.0 > 0.6) {
        textColors.default
    } else {
        textColors.white
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ContextMenu.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.ContextMenuData
import androidx.compose.foundation.ContextMenuItem
import androidx.compose.foundation.ContextMenuRepresentation
import androidx.compose.foundation.ContextMenuState
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.forEachGesture
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.isUnspecified
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.pointer.AwaitPointerEventScope
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.changedToDown
import androidx.compose.ui.input.pointer.isSecondaryPressed
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.rememberCursorPositionProvider
import io.kanro.compose.jetbrains.JBTheme

private val LocalContextMenuData = staticCompositionLocalOf<ContextMenuData?> {
    null
}

@Composable
internal fun ContextMenuDataProvider(
    data: ContextMenuData,
    content: @Composable () -> Unit,
) {
    CompositionLocalProvider(
        LocalContextMenuData provides data
    ) {
        content()
    }
}

private suspend fun AwaitPointerEventScope.awaitEventFirstDown(): PointerEvent {
    var event: PointerEvent
    do {
        event = awaitPointerEvent()
    } while (!event.changes.all { it.changedToDown() })
    return event
}

private fun Modifier.contextMenuDetector(
    state: ContextMenuState,
    enabled: Boolean = true,
): Modifier {
    return if (enabled && state.status == ContextMenuState.Status.Closed) {
        this.pointerInput(state) {
            forEachGesture {
                awaitPointerEventScope {
                    val event = awaitEventFirstDown()
                    if (event.buttons.isSecondaryPressed) {
                        event.changes.forEach { if (it.pressed != it.previousPressed) it.consume() }
                        state.status = ContextMenuState.Status.Open(Rect(event.changes[0].position, 0f))
                    }
                }
            }
        }
    } else {
        Modifier
    }
}

val LocalContextMenuRepresentation: ProvidableCompositionLocal<ContextMenuRepresentation> = staticCompositionLocalOf {
    JBContextMenuRepresentation(Color.Unspecified, Color.Unspecified)
}

@Composable
fun ContextMenuArea(
    items: () -> List<ContextMenuItem>,
    state: ContextMenuState = remember { ContextMenuState() },
    enabled: Boolean = true,
    content: @Composable () -> Unit,
) {
    val data = ContextMenuData(items, LocalContextMenuData.current)

    ContextMenuDataProvider(data) {
        Box(Modifier.contextMenuDetector(state, enabled), propagateMinConstraints = true) {
            content()
        }
        LocalContextMenuRepresentation.current.Representation(state, items)
    }
}

@OptIn(ExperimentalComposeUiApi::class)
class JBContextMenuRepresentation(
    private val backgroundColor: Color,
    private val borderColor: Color,
) : ContextMenuRepresentation {

    @Composable
    override fun Representation(state: ContextMenuState, items: () -> List<ContextMenuItem>) {
        val isOpen = state.status is ContextMenuState.Status.Open
        if (isOpen) {
            Popup(
                focusable = true,
                onDismissRequest = { state.status = ContextMenuState.Status.Closed },
                popupPositionProvider = rememberCursorPositionProvider(),
                onKeyEvent = {
                    if (it.key == Key.Escape) {
                        state.status = ContextMenuState.Status.Closed
                        true
                    } else {
                        false
                    }
                },
            ) {
                val backgroundColor = if (backgroundColor.isUnspecified) {
                    JBTheme.panelColors.bgContent
                } else backgroundColor
                val borderColor = if (borderColor.isUnspecified) {
                    JBTheme.panelColors.border
                } else borderColor
                Column(
                    Modifier.background(backgroundColor).border(1.dp, borderColor).width(IntrinsicSize.Max)
                ) {
                    items().forEach {
                        DropdownMenuItem(
                            modifier = Modifier.defaultMinSize(79.dp, 21.dp),
                            onClick = {
                                it.onClick()
                                state.status = ContextMenuState.Status.Closed
                            },
                        ) {
                            Text(it.label, Modifier.padding(horizontal = 6.dp))
                        }
                    }
                }
            }
        }
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/DropdownMenu.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.Indication
import androidx.compose.foundation.IndicationInstance
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import io.kanro.compose.jetbrains.JBTheme
import io.kanro.compose.jetbrains.color.LocalPanelColors

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun DropdownMenu(
    expanded: Boolean,
    onDismissRequest: () -> Unit,
    focusable: Boolean = true,
    modifier: Modifier = Modifier,
    offset: DpOffset = DpOffset(0.dp, 0.dp),
    content: @Composable ColumnScope.() -> Unit,
) {
    if (expanded) {
        val density = LocalDensity.current
        val popupPositionProvider = DropdownMenuPositionProvider(
            offset,
            density
        )

        Popup(
            focusable = focusable,
            onDismissRequest = onDismissRequest,
            popupPositionProvider = popupPositionProvider,
            onKeyEvent = {
                if (it.key == Key.Escape) {
                    onDismissRequest()
                    true
                } else {
                    false
                }
            },
        ) {
            val panelColor = LocalPanelColors.current
            Column(modifier.background(panelColor.bgContent).border(1.dp, panelColor.border).width(IntrinsicSize.Max)) {
                content()
            }
        }
    }
}

@Composable
fun DropdownMenuItem(
    modifier: Modifier = Modifier,
    onClick: () -> Unit,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    content: @Composable () -> Unit,
) {
    Box(
        modifier
            .clickable(
                interactionSource = interactionSource,
                indication = DropdownMenuItemHoverIndication,
                enabled = enabled,
                onClick = onClick
            )
            .fillMaxWidth()
            .hoverable(interactionSource, enabled),
        contentAlignment = Alignment.CenterStart
    ) {
        val isHovered = interactionSource.collectIsHoveredAsState()
        SelectionScope(isHovered.value) {
            content()
        }
    }
}

object DropdownMenuItemHoverIndication : Indication {
    private class HoverIndicationInstance(
        private val isHover: State<Boolean>,
        private val hoverColor: Color,
    ) : IndicationInstance {
        override fun ContentDrawScope.drawIndication() {
            when {
                isHover.value -> {
                    drawRect(hoverColor, size = size)
                }
            }
            drawContent()
        }
    }

    @Composable
    override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
        val isHover = interactionSource.collectIsHoveredAsState()
        val hoverColor = JBTheme.selectionColors.active
        return remember(JBTheme.selectionColors, interactionSource) {
            HoverIndicationInstance(
                isHover,
                hoverColor,
            )
        }
    }
}

data class DropdownMenuPositionProvider(
    val contentOffset: DpOffset,
    val density: Density,
    val onPositionCalculated: (IntRect, IntRect) -> Unit = { _, _ -> },
) : PopupPositionProvider {
    override fun calculatePosition(
        anchorBounds: IntRect,
        windowSize: IntSize,
        layoutDirection: LayoutDirection,
        popupContentSize: IntSize,
    ): IntOffset {
        // The min margin above and below the menu, relative to the screen.
        val verticalMargin = with(density) { 0 }
        // The content offset specified using the dropdown offset parameter.
        val contentOffsetX = with(density) { contentOffset.x.roundToPx() }
        val contentOffsetY = with(density) { contentOffset.y.roundToPx() }

        // Compute horizontal position.
        val toRight = anchorBounds.left + contentOffsetX
        val toLeft = anchorBounds.right - contentOffsetX - popupContentSize.width
        val toDisplayRight = windowSize.width - popupContentSize.width
        val toDisplayLeft = 0
        val x = if (layoutDirection == LayoutDirection.Ltr) {
            sequenceOf(toRight, toLeft, toDisplayRight)
        } else {
            sequenceOf(toLeft, toRight, toDisplayLeft)
        }.firstOrNull {
            it >= 0 && it + popupContentSize.width <= windowSize.width
        } ?: toLeft

        // Compute vertical position.
        val toBottom = maxOf(anchorBounds.bottom + contentOffsetY, verticalMargin)
        val toTop = anchorBounds.top - contentOffsetY - popupContentSize.height
        val toCenter = anchorBounds.top - popupContentSize.height / 2
        val toDisplayBottom = windowSize.height - popupContentSize.height - verticalMargin
        var y = sequenceOf(toBottom, toTop, toCenter, toDisplayBottom).firstOrNull {
            it >= verticalMargin &&
                    it + popupContentSize.height <= windowSize.height - verticalMargin
        } ?: toTop

        // Desktop specific vertical position checking
        val aboveAnchor = anchorBounds.top + contentOffsetY
        val belowAnchor = windowSize.height - anchorBounds.bottom - contentOffsetY

        if (belowAnchor >= aboveAnchor) {
            y = anchorBounds.bottom + contentOffsetY
        }

        if (y + popupContentSize.height > windowSize.height) {
            y = windowSize.height - popupContentSize.height
        }

        if (y < 0) {
            y = 0
        }

        onPositionCalculated(
            anchorBounds,
            IntRect(x, y, x + popupContentSize.width, y + popupContentSize.height)
        )
        return IntOffset(x, y)
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/EmbeddedTextField.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathFillType
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.addOutline
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Composable
fun EmbeddedTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = true,
    maxLines: Int = 1,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = RectangleShape,
    style: TextFieldStyle = TextFieldDefaults.textFieldStyle(),
) {
    TextField(
        value,
        onValueChange,
        modifier.embeddedTextFieldIndicator(style.indicatorColor(isError, interactionSource).value, shape, 2.dp),
        enabled,
        readOnly,
        textStyle,
        placeholder,
        leadingIcon,
        trailingIcon,
        isError,
        visualTransformation,
        keyboardOptions,
        keyboardActions,
        singleLine,
        maxLines,
        interactionSource,
        shape,
        InnerStyle(style)
    )
}

private class InnerStyle(val style: TextFieldStyle) : TextFieldStyle {
    @Composable
    override fun textColor(enabled: Boolean, isError: Boolean, interactionSource: InteractionSource): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()

        return if (focused) style.textColor(
            enabled,
            isError,
            interactionSource
        ) else rememberUpdatedState(Color.Unspecified)
    }

    @Composable
    override fun backgroundColor(enabled: Boolean, interactionSource: InteractionSource): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()

        return if (focused) style.backgroundColor(
            enabled,
            interactionSource
        ) else rememberUpdatedState(Color.Transparent)
    }

    @Composable
    override fun placeholderColor(enabled: Boolean): State<Color> {
        return style.placeholderColor(enabled)
    }

    @Composable
    override fun borderColor(enabled: Boolean, isError: Boolean, interactionSource: InteractionSource): State<Color> {
        return rememberUpdatedState(Color.Transparent)
    }

    @Composable
    override fun indicatorColor(isError: Boolean, interactionSource: InteractionSource): State<Color> {
        return rememberUpdatedState(Color.Transparent)
    }

    @Composable
    override fun cursorColor(isError: Boolean): State<Color> {
        return style.cursorColor(isError)
    }
}

private fun Modifier.embeddedTextFieldIndicator(color: Color, shape: Shape, width: Dp): Modifier {
    if (color.alpha == 0f) return this
    return drawBehind {
        val controlOutline = shape.createOutline(size, layoutDirection, this)
        val highlightPath = Path().apply {
            this.fillType = PathFillType.EvenOdd
            addOutline(controlOutline)
            addRect(controlOutline.bounds.deflate(width.toPx()))
            close()
        }
        drawPath(highlightPath, color)
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Icon.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.paint
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.toolingGraphicsLayer
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBThemeStyle
import io.kanro.compose.jetbrains.LocalIconTheme

@Composable
fun Icon(
    resource: String,
    contentDescription: String? = null,
    modifier: Modifier = Modifier,
    colorFilter: ColorFilter? = null,
) {
    Icon(
        themedSvgResource(resource, LocalIconTheme.current), contentDescription, modifier,
        colorFilter = colorFilter,
    )
}

@Composable
fun Icon(
    bitmap: ImageBitmap,
    contentDescription: String? = null,
    modifier: Modifier = Modifier,
    colorFilter: ColorFilter? = null,
) {
    val painter = remember(bitmap) { BitmapPainter(bitmap) }
    Icon(
        painter = painter,
        contentDescription = contentDescription,
        modifier = modifier,
        colorFilter = colorFilter,
    )
}

@Composable
fun Icon(
    imageVector: ImageVector,
    contentDescription: String? = null,
    modifier: Modifier = Modifier,
    colorFilter: ColorFilter? = null,
) {
    Icon(
        painter = rememberVectorPainter(imageVector),
        contentDescription = contentDescription,
        modifier = modifier,
        colorFilter = colorFilter,
    )
}

@Composable
fun Icon(
    painter: Painter,
    contentDescription: String? = null,
    modifier: Modifier = Modifier,
    colorFilter: ColorFilter? = null,
) {
    val semantics = if (contentDescription != null) {
        Modifier.semantics {
            this.contentDescription = contentDescription
            this.role = Role.Image
        }
    } else {
        Modifier
    }
    val filter = colorFilter ?: run {
        if (LocalContentColor.current.isSpecified) {
            ColorFilter.tint(LocalContentColor.current.copy(alpha = LocalContentAlpha.current))
        } else {
            null
        }
    }
    Box(
        modifier.toolingGraphicsLayer().defaultSizeFor(painter)
            .paint(
                painter,
                contentScale = ContentScale.None,
                colorFilter = filter
            )
            .then(semantics)
    )
}

@Composable
fun themedSvgResource(resource: String, theme: JBThemeStyle = LocalIconTheme.current): Painter {
    var realResource = resource
    if (theme == JBThemeStyle.DARK) {
        if (!realResource.endsWith("_dark.svg")) {
            val dark = realResource.replace(".svg", "_dark.svg")
            if (Thread.currentThread().contextClassLoader.getResource(dark) != null) {
                realResource = dark
            }
        }
    } else {
        if (realResource.endsWith("_dark.svg")) {
            val light = realResource.replace("_dark.svg", ".svg")
            if (Thread.currentThread().contextClassLoader.getResource(light) != null) {
                realResource = light
            }
        }
    }
    return painterResource(realResource)
}

private fun Modifier.defaultSizeFor(painter: Painter) =
    this.then(
        if (painter.intrinsicSize == Size.Unspecified || painter.intrinsicSize.isInfinite()) {
            DefaultIconSizeModifier
        } else {
            Modifier
        }
    )

private fun Size.isInfinite() = width.isInfinite() && height.isInfinite()

private val DefaultIconSizeModifier = Modifier.size(16.dp)


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/JBToolBar.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBTheme

@Composable
fun JBToolBar(
    orientation: Orientation,
    arrangement: Arrangement.HorizontalOrVertical = Arrangement.spacedBy(8.dp),
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit,
) {
    CompositionLocalProvider(
        LocalToolBarOrientation provides orientation,
    ) {
        when (orientation) {
            Orientation.Vertical -> JBToolBarColumn(
                modifier.width(28.dp),
                verticalArrangement = arrangement,
                content = content
            )

            Orientation.Horizontal -> JBToolBarRow(
                modifier.height(28.dp),
                horizontalArrangement = arrangement,
                content = content
            )
        }
    }
}

@Composable
private fun JBToolBarColumn(
    modifier: Modifier,
    verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp),
    content: @Composable () -> Unit,
) {
    Column(
        modifier,
        verticalArrangement,
        Alignment.CenterHorizontally,
    ) {
        content()
    }
}

@Composable
private fun JBToolBarRow(
    modifier: Modifier,
    horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(8.dp),
    content: @Composable () -> Unit,
) {
    Row(
        modifier,
        horizontalArrangement,
        Alignment.CenterVertically,
    ) {
        content()
    }
}

val LocalToolBarOrientation = compositionLocalOf { Orientation.Horizontal }

@Composable
fun ToolBarSeparator(modifier: Modifier = Modifier, color: Color = JBTheme.toolBarColors.iconSplitBorder) {
    val orientation = LocalToolBarOrientation.current
    Spacer(
        modifier = modifier.run {
            when (orientation) {
                Orientation.Vertical -> size(20.dp, 1.dp)
                Orientation.Horizontal -> size(1.dp, 20.dp)
            }
        }.background(color)
    )
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/JBTree.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBTheme
import io.kanro.compose.jetbrains.JBThemeStyle
import io.kanro.compose.jetbrains.LocalIconTheme
import io.kanro.compose.jetbrains.icons.JBIcons
import io.kanro.compose.jetbrains.icons.jbicons.Actions
import io.kanro.compose.jetbrains.icons.jbicons.actions.ArrowExpand
import io.kanro.compose.jetbrains.icons.jbicons.actions.ArrowExpandDark

@Composable
fun JBTreeItem(
    modifier: Modifier = Modifier,
    selected: Boolean,
    onClick: () -> Unit,
    content: @Composable () -> Unit,
) {
    JBTreeBasicItem(modifier, selected, onClick) {
        Box(Modifier.padding(start = 16.dp)) {
            content()
        }
    }
}

@Composable
fun JBTreeItem(
    modifier: Modifier = Modifier,
    selected: Boolean,
    onClick: () -> Unit,
    expanded: Boolean,
    expanding: (Boolean) -> Unit,
    content: @Composable () -> Unit,
    children: @Composable () -> Unit,
) {
    Column(modifier) {
        JBTreeBasicItem(
            modifier, selected, onClick = onClick,
            onDoubleClick = {
                expanding(!expanded)
                onClick()
            }
        ) {
            Row {
                val isDarkTheme = LocalIconTheme.current == JBThemeStyle.DARK
                Icon(
                    imageVector = if (isDarkTheme) JBIcons.Actions.ArrowExpandDark else JBIcons.Actions.ArrowExpand,
                    modifier = Modifier.size(16.dp).clickable(
                        interactionSource = remember { MutableInteractionSource() },
                        indication = null
                    ) {
                        expanding(!expanded)
                        onClick()
                    }.graphicsLayer(rotationZ = if (expanded) 90f else 0f).align(Alignment.CenterVertically)
                )
                Box {
                    content()
                }
            }
        }
        if (expanded) {
            CompositionLocalProvider(
                LocalTreeLevel provides LocalTreeLevel.current + 1,
                content = children
            )
        }
    }
}

@Composable
@OptIn(ExperimentalFoundationApi::class)
internal fun JBTreeBasicItem(
    modifier: Modifier = Modifier,
    selected: Boolean = false,
    onClick: () -> Unit,
    onDoubleClick: (() -> Unit)? = null,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    content: @Composable () -> Unit,
) {
    val padding = 7 + (LocalTreeLevel.current - 1) * 18
    Box(
        Modifier.combinedClickable(
            interactionSource,
            indication = ListItemHoverIndication,
            onDoubleClick = onDoubleClick,
            onClick = onClick
        ).then(modifier)
            .height(20.dp)
            .run {
                if (selected) {
                    background(color = JBTheme.selectionColors.active)
                } else {
                    this
                }
            }.hoverable(interactionSource),
    ) {
        SelectionScope(selected) {
            Box(Modifier.padding(start = padding.dp)) {
                content()
            }
        }
    }
}

@Composable
fun JBTreeList(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit,
) {
    Column(modifier) {
        content()
    }
}

val LocalTreeLevel: ProvidableCompositionLocal<Int> = compositionLocalOf {
    1
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/JPanel.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBTheme

@Composable
fun JPanel(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit,
) {
    Box(modifier.background(JBTheme.panelColors.bgDialog)) {
        content()
    }
}

@Composable
fun JPanelBorder(modifier: Modifier = Modifier) {
    Spacer(modifier.background(JBTheme.panelColors.border))
}

fun Modifier.jBorder(all: Dp = 0.dp, color: Color): Modifier {
    return jBorder(all, all, all, all, color)
}

fun Modifier.jBorder(
    horizontal: Dp = 0.dp,
    vertical: Dp = 0.dp,
    color: Color,
): Modifier {
    return jBorder(horizontal, horizontal, vertical, vertical, color)
}

fun Modifier.jBorder(
    start: Dp = 0.dp,
    end: Dp = 0.dp,
    top: Dp = 0.dp,
    bottom: Dp = 0.dp,
    color: Color,
): Modifier {
    return drawWithCache {
        onDrawWithContent {
            drawContent()
            var rect = Rect(Offset.Zero, size)

            if (start.roundToPx() > 0) {
                drawRect(color, rect.topLeft, Size(start.toPx(), rect.height))
                rect = Rect(rect.left + start.roundToPx(), rect.top, rect.right, rect.bottom)
            }

            if (end.roundToPx() > 0) {
                drawRect(color, Offset(rect.right - end.toPx(), rect.top), Size(end.toPx(), rect.height))
                rect = Rect(rect.left, rect.top, rect.right - end.roundToPx(), rect.bottom)
            }

            if (top.roundToPx() > 0) {
                drawRect(color, rect.topLeft, Size(rect.width, top.toPx()))
                rect = Rect(rect.left, rect.top + top.roundToPx(), rect.right, rect.bottom)
            }

            if (bottom.roundToPx() > 0) {
                drawRect(color, Offset(rect.left, rect.bottom - bottom.toPx()), Size(rect.width, bottom.toPx()))
            }
        }
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ListView.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.Indication
import androidx.compose.foundation.IndicationInstance
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import io.kanro.compose.jetbrains.JBTheme

object ListItemHoverIndication : Indication {
    private class HoverIndicationInstance(
        private val isHover: State<Boolean>,
        private val hoverColor: Color,
    ) : IndicationInstance {
        override fun ContentDrawScope.drawIndication() {
            if (isHover.value) {
                drawRect(hoverColor, size = size)
            }
            drawContent()
        }
    }

    @Composable
    override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
        val isHover = interactionSource.collectIsHoveredAsState()
        val hoverColor = JBTheme.selectionColors.hover

        return remember(JBTheme.selectionColors, interactionSource) {
            HoverIndicationInstance(
                isHover, hoverColor
            )
        }
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ProgressBar.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.progressSemantics
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBTheme

@Composable
fun ProgressBar(
    progress: Float,
    modifier: Modifier = Modifier,
) {
    val bgColor = JBTheme.progressColors.bg
    val progressColor = JBTheme.progressColors.progress
    Canvas(
        modifier
            .progressSemantics(progress)
            .size(200.dp, 4.dp)
            .focusable()
    ) {
        val strokeWidth = size.height
        val length = size.width

        drawLine(
            bgColor,
            Offset(0f, strokeWidth / 2f),
            Offset(length, strokeWidth / 2f),
            strokeWidth,
            cap = StrokeCap.Round
        )
        drawLine(
            progressColor,
            Offset(0f, strokeWidth / 2f),
            Offset(length * progress, strokeWidth / 2f),
            strokeWidth,
            cap = StrokeCap.Round
        )
    }
}

@Composable
fun ProgressBar(
    modifier: Modifier = Modifier,
) {
    val transition = rememberInfiniteTransition()
    val currentOffset by transition.animateFloat(
        0f,
        1f,
        infiniteRepeatable(
            animation = keyframes {
                durationMillis = 1000
            }
        )
    )
    val progressColor = JBTheme.progressColors.progress

    Canvas(
        modifier
            .progressSemantics()
            .size(200.dp, 4.dp)
            .focusable()
    ) {
        val strokeWidth = size.height
        val length = size.width
        val offset = currentOffset * 80f
        val brush = Brush.linearGradient(
            listOf(
                Color(0x00FFFFFF), Color(0x7FFFFFFF), Color(0x00FFFFFF)
            ),
            start = Offset(offset, 0f),
            end = Offset(offset + 80f, 0f),
            tileMode = TileMode.Repeated
        )
        drawLine(
            progressColor,
            Offset(0f, strokeWidth / 2f),
            Offset(length, strokeWidth / 2f),
            strokeWidth,
            cap = StrokeCap.Round
        )
        drawLine(
            brush,
            Offset(0f, strokeWidth / 2f),
            Offset(length, strokeWidth / 2f),
            strokeWidth,
            cap = StrokeCap.Round
        )
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Selection.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.selection.selectable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ProvidedValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import io.kanro.compose.jetbrains.JBTheme
import io.kanro.compose.jetbrains.JBThemeStyle
import io.kanro.compose.jetbrains.LocalIconTheme
import io.kanro.compose.jetbrains.LocalSelectionScope
import io.kanro.compose.jetbrains.color.LocalTextColors

val emptySelectionScope = emptyArray<ProvidedValue<out Any>>()

val lightSelectionScope: @Composable () -> Array<ProvidedValue<out Any>> = {
    arrayOf(
        LocalIconTheme provides JBThemeStyle.DARK,
        LocalTextColors provides JBTheme.textColors.copy(
            infoInput = Color.White
        ),
        LocalContentColor provides Color.White,
        LocalContentAlpha provides 1.0f,
        LocalContextMenuRepresentation provides JBContextMenuRepresentation(
            JBTheme.panelColors.bgContent, JBTheme.panelColors.border
        )
    )
}

val darkSelectionScope: @Composable () -> Array<ProvidedValue<out Any>> = {
    arrayOf(
        LocalIconTheme provides JBThemeStyle.DARK,
        LocalTextColors provides JBTheme.textColors.copy(
            infoInput = Color.White
        ),
        LocalContentColor provides Color.White,
        LocalContentAlpha provides 1.0f,
        LocalContextMenuRepresentation provides JBContextMenuRepresentation(
            JBTheme.panelColors.bgContent, JBTheme.panelColors.border
        )
    )
}

@Composable
fun SelectionScope(selected: Boolean, block: @Composable () -> Unit) {
    CompositionLocalProvider(* if (selected) LocalSelectionScope.current() else emptySelectionScope) {
        block()
    }
}

@Composable
fun SelectionRow(
    selected: Boolean,
    modifier: Modifier = Modifier,
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    verticalAlignment: Alignment.Vertical = Alignment.Top,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    role: Role? = null,
    onClick: () -> Unit,
    content: @Composable RowScope.() -> Unit,
) {
    SelectionScope(selected) {
        val selectedColor = JBTheme.selectionColors.active
        Row(
            modifier = modifier.background(color = JBTheme.panelColors.bgContent).selectable(
                selected = selected,
                interactionSource = interactionSource,
                indication = ListItemHoverIndication,
                onClick = onClick,
                role = role
            ).drawWithContent {
                if (selected) {
                    drawRect(selectedColor, size = size)
                }
                drawContent()
            },
            horizontalArrangement = horizontalArrangement, verticalAlignment = verticalAlignment, content = content
        )
    }
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Tab.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.Indication
import androidx.compose.foundation.IndicationInstance
import androidx.compose.foundation.background
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.selection.selectable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.JBTheme

object TabIndication : Indication {
    private class TabIndicationInstance(
        private val isHover: State<Boolean>,
        private val hoverColor: Color,
    ) : IndicationInstance {
        override fun ContentDrawScope.drawIndication() {
            if (isHover.value) {
                drawRect(hoverColor, Offset.Zero, size)
            }
            drawContent()
        }
    }

    @Composable
    override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
        val isHover = interactionSource.collectIsHoveredAsState()
        val hoverColor = JBTheme.tabColors.hover

        return remember(JBTheme.tabColors, interactionSource) {
            TabIndicationInstance(
                isHover,
                hoverColor,
            )
        }
    }
}

@Composable
fun Tab(
    selected: Boolean,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    content: @Composable BoxScope.() -> Unit,
) {
    val selectionColor = JBTheme.tabColors.selection
    Box(
        modifier
            .hoverable(interactionSource)
            .height(28.dp)
            .run {
                if (selected) {
                    background(JBTheme.tabColors.bgSelected)
                } else {
                    this
                }
            }
            .drawWithContent {
                drawContent()
                if (selected) {
                    val height = 3.dp.toPx()
                    drawRect(
                        selectionColor,
                        Offset(0f, size.height - height),
                        Size(size.width, height)
                    )
                }
            }.selectable(
                selected = selected,
                onClick = onClick,
                enabled = enabled,
                role = Role.Tab,
                interactionSource = interactionSource,
                indication = TabIndication
            ),
        propagateMinConstraints = true,
        contentAlignment = Alignment.Center,
        content = content
    )
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Text.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.TextUnit
import io.kanro.compose.jetbrains.color.LocalTextColors
import io.kanro.compose.jetbrains.color.TextColors

@Composable
fun Text(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current,
    textColors: TextColors = LocalTextColors.current,
) {
    Text(
        AnnotatedString(text),
        modifier,
        color,
        fontSize,
        fontStyle,
        fontWeight,
        fontFamily,
        letterSpacing,
        textDecoration,
        textAlign,
        lineHeight,
        overflow,
        softWrap,
        maxLines,
        emptyMap(),
        onTextLayout,
        style,
        textColors,
    )
}

@Composable
fun Text(
    text: AnnotatedString,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    inlineContent: Map<String, InlineTextContent> = mapOf(),
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current,
    textColors: TextColors = LocalTextColors.current,
) {
    val textColor = color.takeOrElse {
        style.color.takeOrElse {
            LocalContentColor.current.takeOrElse {
                textColors.default
            }.copy(alpha = LocalContentAlpha.current)
        }
    }
    val mergedStyle = style.merge(
        TextStyle(
            color = textColor,
            fontSize = fontSize,
            fontWeight = fontWeight,
            textAlign = textAlign,
            lineHeight = lineHeight,
            fontFamily = fontFamily,
            textDecoration = textDecoration,
            fontStyle = fontStyle,
            letterSpacing = letterSpacing,
        ),
    )
    BasicText(
        text = text,
        modifier = modifier,
        style = mergedStyle,
        onTextLayout = onTextLayout,
        overflow = overflow,
        softWrap = softWrap,
        maxLines = maxLines,
        minLines = 1,
        inlineContent = inlineContent,
    )
}

val LocalTextStyle = compositionLocalOf(structuralEqualityPolicy()) { TextStyle.Default }

@Composable
fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit) {
    val mergedStyle = LocalTextStyle.current.merge(value)
    CompositionLocalProvider(LocalTextStyle provides mergedStyle, content = content)
}


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/control/TextField.kt
================================================
package io.kanro.compose.jetbrains.control

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathFillType
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.addOutline
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.offset
import io.kanro.compose.jetbrains.JBTheme
import kotlin.math.max
import kotlin.math.roundToInt

@Stable
interface TextFieldStyle {
    @Composable
    fun textColor(enabled: Boolean, isError: Boolean, interactionSource: InteractionSource): State<Color>

    @Composable
    fun backgroundColor(enabled: Boolean, interactionSource: InteractionSource): State<Color>

    @Composable
    fun placeholderColor(enabled: Boolean): State<Color>

    @Composable
    fun borderColor(enabled: Boolean, isError: Boolean, interactionSource: InteractionSource): State<Color>

    @Composable
    fun indicatorColor(isError: Boolean, interactionSource: InteractionSource): State<Color>

    @Composable
    fun cursorColor(isError: Boolean): State<Color>
}

private data class DefaultTextFieldStyle(
    private val textColor: Color,
    private val disabledTextColor: Color,
    private val errorTextColor: Color,
    private val backgroundColor: Color,
    private val disabledBackgroundColor: Color,
    private val placeholderColor: Color,
    private val disabledPlaceholderColor: Color,
    private val borderColor: Color,
    private val disabledBorderColor: Color,
    private val errorBorderColor: Color,
    private val focusedBorderColor: Color,
    private val indicatorColor: Color,
    private val errorIndicatorColor: Color,
    private val cursorColor: Color,
    private val errorCursorColor: Color,
) : TextFieldStyle {
    @Composable
    override fun textColor(enabled: Boolean, isError: Boolean, interactionSource: InteractionSource): State<Color> {
        return rememberUpdatedState(
            when {
                !enabled -> disabledTextColor
                isError -> errorTextColor
                else -> textColor
            }
        )
    }

    @Composable
    override fun backgroundColor(enabled: Boolean, interactionSource: InteractionSource): State<Color> {
        return rememberUpdatedState(if (enabled) backgroundColor else disabledBackgroundColor)
    }

    @Composable
    override fun placeholderColor(enabled: Boolean): State<Color> {
        return rememberUpdatedState(if (enabled) placeholderColor else disabledPlaceholderColor)
    }

    @Composable
    override fun borderColor(enabled: Boolean, isError: Boolean, interactionSource: InteractionSource): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()

        val targetValue = when {
            !enabled -> disabledBorderColor
            isError -> errorBorderColor
            focused -> focusedBorderColor
            else -> borderColor
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    override fun indicatorColor(
        isError: Boolean,
        interactionSource: InteractionSource,
    ): State<Color> {
        val focused by interactionSource.collectIsFocusedAsState()

        val targetValue = when {
            isError -> errorIndicatorColor
            focused -> indicatorColor
            else -> Color.Transparent
        }
        return rememberUpdatedState(targetValue)
    }

    @Composable
    override fun cursorColor(isError: Boolean): State<Color> {
        return rememberUpdatedState(if (isError) errorCursorColor else cursorColor)
    }
}

@Composable
fun TextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = true,
    maxLines: Int = 1,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = RectangleShape,
    style: TextFieldStyle = TextFieldDefaults.textFieldStyle(),
) {
    var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = value)) }
    val textFieldValue = textFieldValueState.copy(text = value)

    TextField(
        enabled = enabled,
        readOnly = readOnly,
        value = textFieldValue,
        onValueChange = {
            textFieldValueState = it
            if (value != it.text) {
                onValueChange(it.text)
            }
        },
        modifier = modifier,
        singleLine = singleLine,
        textStyle = textStyle,
        placeholder = placeholder,
        leadingIcon = leadingIcon,
        trailingIcon = trailingIcon,
        isError = isError,
        visualTransformation = visualTransformation,
        keyboardOptions = keyboardOptions,
        keyboardActions = keyboardActions,
        maxLines = maxLines,
        interactionSource = interactionSource,
        shape = shape,
        style = style
    )
}

@Composable
fun TextField(
    value: TextFieldValue,
    onValueChange: (TextFieldValue) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = true,
    maxLines: Int = 1,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = RectangleShape,
    style: TextFieldStyle = TextFieldDefaults.textFieldStyle(),
) {
    val textColor = textStyle.color.takeOrElse {
        style.textColor(enabled, isError, interactionSource).value
    }.takeOrElse {
        LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
    }
    val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))

    val transformedText = remember(value.annotatedString, visualTransformation) {
        visualTransformation.filter(value.annotatedString)
    }.text

    val decoratedPlaceholder: @Composable ((Modifier) -> Unit)? =
        if (placeholder != null && transformedText.isEmpty()) {
            @Composable { _ ->
                Box {
                    Decoration(
                        contentColor = style.placeholderColor(enabled).value,
                        content = placeholder,
                        typography = JBTheme.typography.default
                    )
                }
            }
        } else null

    TextFieldLayout(
        modifier = modifier,
        value = value,
        onValueChange = onValueChange,
        enabled = enabled,
        readOnly = readOnly,
        keyboardOptions = keyboardOptions,
        keyboardActions = keyboardActions,
        textStyle = mergedTextStyle,
        singleLine = singleLine,
        maxLines = maxLines,
        visualTransformation = visualTransformation,
        interactionSource = interactionSource,
        decoratedPlaceholder = decoratedPlaceholder,
        leading = leadingIcon,
        trailing = trailingIcon,
        borderWidth = 1.dp,
        borderColor = style.borderColor(enabled, isError, interactionSource).value,
        indicatorWidth = 2.dp,
        indicatorColor = style.indicatorColor(isError, interactionSource).value,
        shape = shape,
        backgroundColor = style.backgroundColor(enabled, interactionSource).value,
        cursorColor = style.cursorColor(isError).value
    )
}

@Composable
internal fun TextFieldLayout(
    modifier: Modifier,
    value: TextFieldValue,
    onValueChange: (TextFieldValue) -> Unit,
    enabled: Boolean,
    readOnly: Boolean,
    keyboardOptions: KeyboardOptions,
    keyboardActions: KeyboardActions,
    textStyle: TextStyle,
    singleLine: Boolean,
    maxLines: Int = Int.MAX_VALUE,
    visualTransformation: VisualTransformation,
    interactionSource: MutableInteractionSource,
    decoratedPlaceholder: @Composable ((Modifier) -> Unit)?,
    leading: @Composable (() -> Unit)?,
    trailing: @Composable (() -> Unit)?,
    borderWidth: Dp,
    borderColor: Color,
    indicatorWidth: Dp,
    indicatorColor: Color,
    cursorColor: Color,
    backgroundColor: Color,
    shape: Shape,
) {
    BasicTextField(
        value = value,
        modifier = Modifier
            .defaultMinSize(
                minWidth = TextFieldDefaults.MinWidth,
                minHeight = TextFieldDefaults.MinHeight
            )
            .background(backgroundColor, shape)
            .then(modifier),
        onValueChange = onValueChange,
        enabled = enabled,
        readOnly = readOnly,
        textStyle = textStyle,
        cursorBrush = SolidColor(cursorColor),
        visualTransformation = visualTransformation,
        keyboardOptions = keyboardOptions,
        keyboardActions = keyboardActions,
        interactionSource = interactionSource,
        singleLine = singleLine,
        maxLines = maxLines,
        decorationBox = @Composable { coreTextField ->
            // places leading icon, input field, label, placeholder, trailing icon
            IconsWithTextFieldLayout(
                textField = coreTextField,
                leading = leading,
                trailing = trailing,
                singleLine = singleLine,
                placeholder = decoratedPlaceholder,
                shape = shape,
                borderWidth = borderWidth,
                borderColor = borderColor,
                indicatorWidth = indicatorWidth,
                indicatorColor = indicatorColor,
            )
        }
    )
}

private fun Modifier.textFieldIndicator(color: Color, shape: Shape, width: Dp, cornerRadius: Dp): Modifier {
    if (color.alpha == 0f) return this
    return drawBehind {
        val controlOutline = shape.createOutline(size, layoutDirection, this)
        val highlightOutline = RoundRect(controlOutline.bounds.inflate(width.toPx()), CornerRadius(cornerRadius.toPx()))
        val highlightPath = Path().apply {
            this.fillType = PathFillType.EvenOdd
            addRoundRect(highlightOutline)
            addOutline(controlOutline)
            close()
        }
        drawPath(highlightPath, color)
    }
}

@Composable
private fun IconsWithTextFieldLayout(
    textField: @Composable () -> Unit,
    placeholder: @Composable ((Modifier) -> Unit)?,
    leading: @Composable (() -> Unit)?,
    trailing: @Composable (() -> Unit)?,
    singleLine: Boolean,
    shape: Shape,
    borderWidth: Dp,
    borderColor: Color,
    indicatorWidth: Dp,
    indicatorColor: Color,
) {
    Layout(
        content = {
            Box(
                Modifier
                    .layoutId("border")
                    .border(
                        width = borderWidth,
                        color = borderColor,
                        shape = shape
                    )
                    .textFieldIndicator(
                        width = indicatorWidth,
                        color = indicatorColor,
                        shape = shape,
                        cornerRadius = 4.dp
                    )
            )

            if (leading != null) {
                Box(
                    modifier = Modifier.layoutId(LeadingId).then(IconDefaultSizeModifier)
                        .padding(start = HorizontalIconPadding),
                    contentAlignment = Alignment.Center
                ) {
                    leading()
                }
            }
            if (trailing != null) {
                Box(
                    modifier = Modifier.layoutId(TrailingId).then(IconDefaultSizeModifier)
                        .padding(end = HorizontalIconPadding),
                    contentAlignment = Alignment.Center
                ) {
                    trailing()
                }
            }
            val padding = Modifier.padding(
                start = HorizontalTextFieldPadding,
                end = HorizontalTextFieldPadding
            )
            if (placeholder != null) {
                placeholder(Modifier.layoutId(PlaceholderId).then(padding))
            }

            Box(
                modifier = Modifier.layoutId(TextFieldId).then(padding),
                propagateMinConstraints = true
            ) {
                textField()
            }
        }
    ) { measurables, incomingConstraints ->
        // used to calculate the constraints for measuring elements that will be placed in a row
        var occupiedSpaceHorizontally = 0
        val bottomPadding = VerticalTextFieldPadding.roundToPx()

        // measure leading icon
        val constraints =
            incomingConstraints.copy(minWidth = 0, minHeight = 0)
        val leadingPlaceable = measurables.find { it.layoutId == LeadingId }?.measure(constraints)
        occupiedSpaceHorizontally += widthOrZero(
            leadingPlaceable
        )

        // measure trailing icon
        val trailingPlaceable = measurables.find { it.layoutId == TrailingId }
            ?.measure(constraints.offset(horizontal = -occupiedSpaceHorizontally))
        occupiedSpaceHorizontally += widthOrZero(
            trailingPlaceable
        )

        // measure label
        constraints.offset(
            horizontal = -occupiedSpaceHorizontally,
            vertical = -bottomPadding
        )

        // measure text field
        // on top we offset either by default padding or by label's half height if its too big
        // minWidth must not be set to 0 due to how foundation TextField treats zero minWidth
        val topPadding = bottomPadding
        val textConstraints = incomingConstraints.offset(
            horizontal = -occupiedSpaceHorizontally,
            vertical = -bottomPadding - topPadding
        ).copy(minHeight = 0)
        val textFieldPlaceable =
            measurables.first { it.layoutId == TextFieldId }.measure(textConstraints)

        // measure placeholder
        val placeholderConstraints = textConstraints.copy(minWidth = 0)
        val placeholderPlaceable =
            measurables.find { it.layoutId == PlaceholderId }?.measure(placeholderConstraints)

        val width =
            calculateWidth(
                leadingPlaceable,
                trailingPlaceable,
                textFieldPlaceable,
                placeholderPlaceable,
                incomingConstraints
            )
        val height =
            calculateHeight(
                leadingPlaceable,
                trailingPlaceable,
                textFieldPlaceable,
                placeholderPlaceable,
                incomingConstraints,
                density
            )

        val borderPlaceable = measurables.first { it.layoutId == "border" }.measure(
            Constraints(
                minWidth = if (width != Constraints.Infinity) width else 0,
                maxWidth = width,
                minHeight = if (height != Constraints.Infinity) height else 0,
                maxHeight = height
            )
        )
        layout(width, height) {
            place(
                height,
                width,
                leadingPlaceable,
                trailingPlaceable,
                textFieldPlaceable,
                placeholderPlaceable,
                borderPlaceable,
                singleLine,
                density
            )
        }
    }
}

private fun calculateWidth(
    leadingPlaceable: Placeable?,
    trailingPlaceable: Placeable?,
    textFieldPlaceable: Placeable,
    placeholderPlaceable: Placeable?,
    constraints: Constraints,
): Int {
    val middleSection = maxOf(
        textFieldPlaceable.width,
        widthOrZero(placeholderPlaceable)
    )
    val wrappedWidth =
        widthOrZero(leadingPlaceable) + middleSection + widthOrZero(
            trailingPlaceable
        )
    return max(wrappedWidth, constraints.minWidth)
}

private fun calculateHeight(
    leadingPlaceable: Placeable?,
    trailingPlaceable: Placeable?,
    textFieldPlaceable: Placeable,
    placeholderPlaceable: Placeable?,
    constraints: Constraints,
    density: Float,
): Int {
    // middle section is defined as a height of the text field or placeholder ( whichever is
    // taller) plus 16.dp or half height of the label if it is taller, given that the label
    // is vertically centered to the top edge of the resulting text field's container
    val inputFieldHeight = max(
        textFieldPlaceable.height,
        heightOrZero(placeholderPlaceable)
    )
    val topBottomPadding = VerticalTextFieldPadding.value * density
    val middleSectionHeight = inputFieldHeight + topBottomPadding + topBottomPadding
    return max(
        constraints.minHeight,
        maxOf(
            heightOrZero(leadingPlaceable),
            heightOrZero(trailingPlaceable),
            middleSectionHeight.roundToInt()
        )
    )
}

private fun Placeable.PlacementScope.place(
    height: Int,
    width: Int,
    leadingPlaceable: Placeable?,
    trailingPlaceable: Placeable?,
    textFieldPlaceable: Placeable,
    placeholderPlaceable: Placeable?,
    borderPlaceable: Placeable,
    singleLine: Boolean,
    density: Float,
) {
    val topBottomPadding = (VerticalTextFieldPadding.value * density).roundToInt()

    // placed center vertically and to the start edge horizontally
    leadingPlaceable?.placeRelative(
        0,
        Alignment.CenterVertically.align(leadingPlaceable.height, height)
    )

    // placed center vertically and to the end edge horizontally
    trailingPlaceable?.placeRelative(
        width - trailingPlaceable.width,
        Alignment.CenterVertically.align(trailingPlaceable.height, height)
    )

    // placed center vertically and after the leading icon horizontally if single line text field
    // placed to the top with padding for multi line text field
    val textVerticalPosition = if (singleLine) {
        Alignment.CenterVertically.align(textFieldPlaceable.height, height)
    } else {
        topBottomPadding
    }
    textFieldPlaceable.placeRelative(widthOrZero(leadingPlaceable), textVerticalPosition)

    // placed similar to the input text above
    placeholderPlaceable?.let {
        val placeholderVerticalPosition = if (singleLine) {
            Alignment.CenterVertically.align(it.height, height)
        } else {
            topBottomPadding
        }
        it.placeRelative(widthOrZero(leadingPlaceable), placeholderVerticalPosition)
    }

    // place border
    borderPlaceable.place(IntOffset.Zero)
}

@Composable
internal fun Decoration(
    contentColor: Color,
    typography: TextStyle? = null,
    contentAlpha: Float? = null,
    content: @Composable () -> Unit,
) {
    val colorAndEmphasis: @Composable () -> Unit = @Composable {
        CompositionLocalProvider(LocalContentColor provides contentColor) {
            if (contentAlpha != null) {
                CompositionLocalProvider(
                    LocalContentAlpha provides contentAlpha,
                    content = content
                )
            } else {
                CompositionLocalProvider(
                    LocalContentAlpha provides contentColor.alpha,
                    content = content
                )
            }
        }
    }
    if (typography != null) ProvideTextStyle(typography, colorAndEmphasis) else colorAndEmphasis()
}

object TextFieldDefaults {
    val MinHeight = 24.dp

    val MinWidth = 64.dp

    @Composable
    fun textFieldStyle(
        textColor: Color = JBTheme.textColors.default,
        disabledTextColor: Color = JBTheme.textColors.disabled,
        errorTextColor: Color = JBTheme.textColors.error,
        backgroundColor: Color = JBTheme.fieldColors.bg,
        disabledBackgroundColor: Color = JBTheme.fieldColors.bgDisabled,
        placeholderColor: Color = JBTheme.textColors.infoInput,
        disabledPlaceholderColor: Color = JBTheme.textColors.infoInput,
        borderColor: Color = JBTheme.fieldColors.border,
        disabledBorderColor: Color = JBTheme.fieldColors.borderDisabled,
        errorBorderColor: Color = JBTheme.fieldColors.borderError,
        focusedBorderColor: Color = JBTheme.fieldColors.borderFocused,
        indicatorColor: Color = JBTheme.focusColors.default,
        errorIndicatorColor: Color = JBTheme.focusColors.error,
        cursorColor: Color = JBTheme.textColors.default,
        errorCursorColor: Color = JBTheme.textColors.error,
    ): TextFieldStyle = DefaultTextFieldStyle(
        textColor,
        disabledTextColor,
        errorTextColor,
        backgroundColor,
        disabledBackgroundColor,
        placeholderColor,
        disabledPlaceholderColor,
        borderColor,
        disabledBorderColor,
        errorBorderColor,
        focusedBorderColor,
        indicatorColor,
        errorIndicatorColor,
        cursorColor,
        errorCursorColor
    )
}

internal fun widthOrZero(placeable: Placeable?) = placeable?.width ?: 0
internal fun heightOrZero(placeable: Placeable?) = placeable?.height ?: 0

internal val HorizontalTextFieldPadding = 6.dp
internal val VerticalTextFieldPadding = 3.dp
internal val HorizontalIconPadding = 6.dp

internal val IconDefaultSizeModifier = Modifier.defaultMinSize(16.dp, 16.dp)

private const val PlaceholderId = "Placeholder"
private const val TextFieldId = "TextField"
private const val LeadingId = "Leading"
private const val TrailingId = "Trailing"


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/__JBIcons.kt
================================================
package io.kanro.compose.jetbrains.icons

internal object JBIcons


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/__Actions.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons

import io.kanro.compose.jetbrains.icons.JBIcons

internal object ActionsGroup

internal val JBIcons.Actions: ActionsGroup
    get() = ActionsGroup


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/__General.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons

import io.kanro.compose.jetbrains.icons.JBIcons

internal object GeneralGroup

internal val JBIcons.General: GeneralGroup
    get() = GeneralGroup


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/ArrowExpand.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons.actions

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.icons.jbicons.ActionsGroup

internal val ActionsGroup.ArrowExpand: ImageVector
    get() {
        if (_arrowExpand != null) {
            return _arrowExpand!!
        }
        _arrowExpand = Builder(
            name = "ArrowExpand", defaultWidth = 16.0.dp,
            defaultHeight =
            16.0.dp,
            viewportWidth = 16.0f, viewportHeight = 16.0f
        ).apply {
            path(
                fill = SolidColor(Color(0x00000000)), stroke = SolidColor(Color(0xFF6E6E6E)),
                strokeLineWidth = 2.0f, strokeLineCap = Butt, strokeLineJoin = Miter,
                strokeLineMiter = 4.0f, pathFillType = NonZero
            ) {
                moveTo(6.0f, 13.0f)
                lineTo(11.0f, 8.0f)
                lineTo(6.0f, 3.0f)
            }
        }
            .build()
        return _arrowExpand!!
    }

private var _arrowExpand: ImageVector? = null


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/ArrowExpandDark.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons.actions

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.icons.jbicons.ActionsGroup

internal val ActionsGroup.ArrowExpandDark: ImageVector
    get() {
        if (_arrowExpandDark != null) {
            return _arrowExpandDark!!
        }
        _arrowExpandDark = Builder(
            name = "ArrowexpandDark", defaultWidth = 16.0.dp,
            defaultHeight =
            16.0.dp,
            viewportWidth = 16.0f, viewportHeight = 16.0f
        ).apply {
            path(
                fill = SolidColor(Color(0x00000000)), stroke = SolidColor(Color(0xFFAFB1B3)),
                strokeLineWidth = 2.0f, strokeLineCap = Butt, strokeLineJoin = Miter,
                strokeLineMiter = 4.0f, pathFillType = NonZero
            ) {
                moveTo(6.0f, 13.0f)
                lineTo(11.0f, 8.0f)
                lineTo(6.0f, 3.0f)
            }
        }
            .build()
        return _arrowExpandDark!!
    }

private var _arrowExpandDark: ImageVector? = null


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/Checkmark.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons.actions

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType.Companion.EvenOdd
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.icons.jbicons.ActionsGroup

internal val ActionsGroup.Checkmark: ImageVector
    get() {
        if (_checkmark != null) {
            return _checkmark!!
        }
        _checkmark = Builder(
            name = "Checkmark", defaultWidth = 14.0.dp, defaultHeight = 14.0.dp,
            viewportWidth = 14.0f, viewportHeight = 14.0f
        ).apply {
            path(
                fill = SolidColor(Color(0xFFffffff)), stroke = null, strokeLineWidth = 0.0f,
                strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
                pathFillType = EvenOdd
            ) {
                moveTo(5.625f, 8.4267f)
                lineTo(9.5566f, 2.9336f)
                curveTo(9.5566f, 2.9336f, 10.1737f, 2.3242f, 10.8612f, 2.8242f)
                curveTo(11.4433f, 3.3867f, 10.998f, 4.0938f, 10.998f, 4.0938f)
                lineTo(6.3183f, 10.6445f)
                curveTo(6.3183f, 10.6445f, 5.9941f, 11.0f, 5.5839f, 11.0f)
                curveTo(5.1737f, 11.0f, 4.873f, 10.6445f, 4.873f, 10.6445f)
                lineTo(2.9394f, 7.7461f)
                curveTo(2.9394f, 7.7461f, 2.5683f, 6.9805f, 3.2558f, 6.4609f)
                curveTo(4.0605f, 6.0781f, 4.5605f, 6.8394f, 4.5605f, 6.8394f)
                lineTo(5.625f, 8.4267f)
                close()
            }
        }
            .build()
        return _checkmark!!
    }

private var _checkmark: ImageVector? = null


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/CheckmarkIndeterminate.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons.actions

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.icons.jbicons.ActionsGroup

internal val ActionsGroup.CheckmarkIndeterminate: ImageVector
    get() {
        if (_checkmarkIndeterminate != null) {
            return _checkmarkIndeterminate!!
        }
        _checkmarkIndeterminate = Builder(
            name = "CheckmarkIndeterminate", defaultWidth = 14.0.dp,
            defaultHeight = 14.0.dp, viewportWidth = 14.0f, viewportHeight = 14.0f
        ).apply {
            path(
                fill = SolidColor(Color(0xFFffffff)), stroke = null, strokeLineWidth = 0.0f,
                strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
                pathFillType = NonZero
            ) {
                moveTo(3.7402f, 5.73f)
                lineTo(10.1402f, 5.73f)
                arcTo(1.0f, 1.0f, 0.0f, false, true, 11.1402f, 6.73f)
                lineTo(11.1402f, 7.23f)
                arcTo(1.0f, 1.0f, 0.0f, false, true, 10.1402f, 8.23f)
                lineTo(3.7402f, 8.23f)
                arcTo(1.0f, 1.0f, 0.0f, false, true, 2.7402f, 7.23f)
                lineTo(2.7402f, 6.73f)
                arcTo(1.0f, 1.0f, 0.0f, false, true, 3.7402f, 5.73f)
                close()
            }
        }
            .build()
        return _checkmarkIndeterminate!!
    }

private var _checkmarkIndeterminate: ImageVector? = null


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/Close.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons.actions

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType.Companion.EvenOdd
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.icons.jbicons.ActionsGroup

internal val ActionsGroup.Close: ImageVector
    get() {
        if (_close != null) {
            return _close!!
        }
        _close = Builder(
            name = "Close", defaultWidth = 16.0.dp, defaultHeight = 16.0.dp,
            viewportWidth = 16.0f, viewportHeight = 16.0f
        ).apply {
            path(
                fill = SolidColor(Color(0xFF7F8B91)), stroke = null, fillAlpha = 0.5f,
                strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter,
                strokeLineMiter = 4.0f, pathFillType = EvenOdd
            ) {
                moveTo(7.9949f, 8.7051f)
                lineTo(4.8541f, 11.8541f)
                lineTo(4.147f, 11.147f)
                lineTo(7.2949f, 8.0051f)
                lineTo(4.147f, 4.8571f)
                lineTo(4.8541f, 4.15f)
                lineTo(8.002f, 7.298f)
                lineTo(11.144f, 4.15f)
                lineTo(11.8511f, 4.8571f)
                lineTo(8.702f, 7.998f)
                lineTo(11.8511f, 11.147f)
                lineTo(11.144f, 11.8541f)
                lineTo(7.9949f, 8.7051f)
                close()
            }
        }
            .build()
        return _close!!
    }

private var _close: ImageVector? = null


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/general/ButtonDropTriangle.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons.general

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType.Companion.EvenOdd
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.icons.jbicons.GeneralGroup

internal val GeneralGroup.ButtonDropTriangle: ImageVector
    get() {
        if (_buttonDropTriangle != null) {
            return _buttonDropTriangle!!
        }
        _buttonDropTriangle = Builder(
            name = "ButtonDropTriangle", defaultWidth = 8.0.dp,
            defaultHeight = 4.0.dp, viewportWidth = 8.0f, viewportHeight = 4.0f
        ).apply {
            path(
                fill = SolidColor(Color(0xFF6E6E6E)), stroke = null, strokeLineWidth = 0.0f,
                strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
                pathFillType = EvenOdd
            ) {
                moveTo(4.0f, 4.0f)
                lineToRelative(4.0f, -4.0f)
                lineToRelative(-8.0f, -0.0f)
                close()
            }
        }
            .build()
        return _buttonDropTriangle!!
    }

private var _buttonDropTriangle: ImageVector? = null


================================================
FILE: classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/general/ButtonDropTriangleDark.kt
================================================
package io.kanro.compose.jetbrains.icons.jbicons.general

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType.Companion.EvenOdd
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.icons.jbicons.GeneralGroup

internal val GeneralGroup.ButtonDropTriangleDark: ImageVector
    get() {
        if (_buttonDropTriangleDark != null) {
            return _buttonDropTriangleDark!!
        }
        _buttonDropTriangleDark = Builder(
            name = "ButtonDropTriangleDark", defaultWidth = 8.0.dp,
            defaultHeight = 4.0.dp, viewportWidth = 8.0f, viewportHeight = 4.0f
        ).apply {
            path(
                fill = SolidColor(Color(0xFFAFB1B3)), stroke = null, strokeLineWidth = 0.0f,
                strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
                pathFillType = EvenOdd
            ) {
                moveTo(4.0f, 4.0f)
                lineToRelative(4.0f, -4.0f)
                lineToRelative(-8.0f, -0.0f)
                close()
            }
        }
            .build()
        return _buttonDropTriangleDark!!
    }

private var _buttonDropTriangleDark: ImageVector? = null


================================================
FILE: expui/build.gradle.kts
================================================
plugins {
    kotlin("jvm")
    id("com.netflix.nebula.maven-publish")
    id("com.netflix.nebula.source-jar")
    id("com.bybutter.sisyphus.project")
    id("org.jetbrains.compose")
    `java-library`
}

description = "JetBrains ExpUI Kit for Compose Desktop"

dependencies {
    implementation(kotlin("stdlib"))
    implementation(compose.desktop.common) {
        exclude("org.jetbrains.compose.material")
    }
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>() {
    kotlinOptions.jvmTarget = "17"
}


================================================
FILE: expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/DesktopPlatform.kt
================================================
package io.kanro.compose.jetbrains.expui

enum class DesktopPlatform {
    Linux,
    Windows,
    MacOS,
    Unknown;

    companion object {
        val Current: DesktopPlatform by lazy {
            val name = System.getProperty("os.name")
            when {
                name?.startsWith("Linux") == true -> Linux
                name?.startsWith("Win") == true -> Windows
                name == "Mac OS X" -> MacOS
                else -> Unknown
            }
        }
    }
}


================================================
FILE: expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ActionButton.kt
================================================
package io.kanro.compose.jetbrains.expui.control

import androidx.compose.foundation.Indication
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.expui.style.AreaColors
import io.kanro.compose.jetbrains.expui.style.AreaProvider
import io.kanro.compose.jetbrains.expui.style.DisabledAreaProvider
import io.kanro.compose.jetbrains.expui.style.HoverAreaProvider
import io.kanro.compose.jetbrains.expui.style.LocalAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalDisabledAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalHoverAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalNormalAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalPressedAreaColors
import io.kanro.compose.jetbrains.expui.style.PressedAreaProvider
import io.kanro.compose.jetbrains.expui.style.areaBackground
import io.kanro.compose.jetbrains.expui.theme.LightTheme

class ActionButtonColors(
    override val normalAreaColors: AreaColors,
    override val hoverAreaColors: AreaColors,
    override val pressedAreaColors: AreaColors,
    override val disabledAreaColors: AreaColors,
) : AreaProvider, HoverAreaProvider, PressedAreaProvider, DisabledAreaProvider {
    @Composable
    fun provideArea(enabled: Boolean, content: @Composable () -> Unit) {
        CompositionLocalProvider(
            LocalAreaColors provides if (enabled) normalAreaColors else disabledAreaColors,
            LocalNormalAreaColors provides normalAreaColors,
            LocalDisabledAreaColors provides disabledAreaColors,
            LocalHoverAreaColors provides hoverAreaColors,
            LocalPressedAreaColors provides pressedAreaColors,
            content = content
        )
    }
}

val LocalActionButtonColors = compositionLocalOf {
    LightTheme.ActionButtonColors
}

@Composable
fun ActionButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = RoundedCornerShape(6.dp),
    indication: Indication? = HoverOrPressedIndication(shape),
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: ActionButtonColors = LocalActionButtonColors.current,
    content: @Composable BoxScope.() -> Unit,
) {
    colors.provideArea(enabled) {
        Box(
            modifier.areaBackground(shape = shape).clickable(
                interactionSource = interactionSource,
                indication = indication,
                enabled = enabled,
                onClick = onClick,
                role = Role.Button
            ),
            propagateMinConstraints = true
        ) {
            content()
        }
    }
}


================================================
FILE: expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Button.kt
================================================
package io.kanro.compose.jetbrains.expui.control

import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.expui.style.AreaColors
import io.kanro.compose.jetbrains.expui.style.AreaProvider
import io.kanro.compose.jetbrains.expui.style.DisabledAreaProvider
import io.kanro.compose.jetbrains.expui.style.FocusAreaProvider
import io.kanro.compose.jetbrains.expui.style.LocalAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalDisabledAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalFocusAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalNormalAreaColors
import io.kanro.compose.jetbrains.expui.theme.LightTheme

class ButtonColors(
    override val normalAreaColors: AreaColors,
    override val focusAreaColors: AreaColors,
    override val disabledAreaColors: AreaColors,
) : AreaProvider, FocusAreaProvider, DisabledAreaProvider {

    @Composable
    fun provideArea(enabled: Boolean, focused: Boolean, content: @Composable () -> Unit) {
        val currentAreaColor = when {
            !enabled -> disabledAreaColors
            focused -> focusAreaColors
            else -> normalAreaColors
        }

        CompositionLocalProvider(
            LocalAreaColors provides currentAreaColor,
            LocalNormalAreaColors provides normalAreaColors,
            LocalFocusAreaColors provides focusAreaColors,
            LocalDisabledAreaColors provides disabledAreaColors,
            content = content
        )
    }
}

val LocalPrimaryButtonColors = compositionLocalOf {
    LightTheme.PrimaryButtonColors
}

val LocalOutlineButtonColors = compositionLocalOf {
    LightTheme.OutlineButtonColors
}

@Composable
fun OutlineButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: ButtonColors = LocalOutlineButtonColors.current,
    content: @Composable RowScope.() -> Unit,
) {
    ButtonImpl(onClick, modifier, enabled, interactionSource, colors, content)
}

@Composable
fun PrimaryButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: ButtonColors = LocalPrimaryButtonColors.current,
    content: @Composable RowScope.() -> Unit,
) {
    ButtonImpl(onClick, modifier, enabled, interactionSource, colors, content)
}

@Composable
private fun ButtonImpl(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: ButtonColors,
    content: @Composable RowScope.() -> Unit,
) {
    val isFocused = remember { mutableStateOf(false) }
    colors.provideArea(enabled, isFocused.value) {
        val areaColors = LocalAreaColors.current
        Box(
            Modifier.defaultMinSize(72.dp, 24.dp).drawWithCache {
                onDrawBehind {
                    if (isFocused.value) {
                        drawRoundRect(
                            areaColors.focusColor,
                            size = Size(size.width + 4.dp.toPx(), size.height + 4.dp.toPx()),
                            topLeft = Offset(-2.dp.toPx(), -2.dp.toPx()),
                            cornerRadius = CornerRadius(5.dp.toPx())
                        )
                    }
                    drawRoundRect(areaColors.startBorderColor, cornerRadius = CornerRadius(3.dp.toPx()))
                    drawRoundRect(
                        areaColors.startBackground,
                        size = Size(size.width - 2.dp.toPx(), size.height - 2.dp.toPx()),
                        topLeft = Offset(1.dp.toPx(), 1.dp.toPx()),
                        cornerRadius = CornerRadius(2.dp.toPx())
                    )
                }
            }.onFocusEvent {
                isFocused.value = it.isFocused
            }.clickable(
                interactionSource = interactionSource,
                indication = null,
                enabled = enabled,
                onClick = onClick,
                role = Role.Button
            ).then(modifier),
            contentAlignment = Alignment.Center
        ) {
            Row(
                modifier = Modifier.padding(14.dp, 3.dp),
                horizontalArrangement = Arrangement.Center,
                verticalAlignment = Alignment.CenterVertically
            ) {
                content()
            }
        }
    }
}


================================================
FILE: expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/CheckBox.kt
================================================
package io.kanro.compose.jetbrains.expui.control

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.selection.triStateToggleable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.PathFillType
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.state.ToggleableState
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.expui.style.AreaColors
import io.kanro.compose.jetbrains.expui.style.AreaProvider
import io.kanro.compose.jetbrains.expui.style.DisabledAreaProvider
import io.kanro.compose.jetbrains.expui.style.FocusAreaProvider
import io.kanro.compose.jetbrains.expui.style.LocalAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalDisabledAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalFocusAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalNormalAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalSelectionAreaColors
import io.kanro.compose.jetbrains.expui.style.SelectionAreaProvider
import io.kanro.compose.jetbrains.expui.theme.LightTheme

class CheckBoxColors(
    override val normalAreaColors: AreaColors,
    override val selectionAreaColors: AreaColors,
    override val focusAreaColors: AreaColors,
    override val disabledAreaColors: AreaColors,
) : AreaProvider, DisabledAreaProvider, FocusAreaProvider, SelectionAreaProvider {
    @Composable
    fun provideArea(enabled: Boolean, focused: Boolean, selected: Boolean, content: @Composable () -> Unit) {
        val currentColors = when {
            !enabled -> disabledAreaColors
            focused -> focusAreaColors
            selected -> selectionAreaColors
            else -> normalAreaColors
        }

        CompositionLocalProvider(
            LocalAreaColors provides currentColors,
            LocalNormalAreaColors provides normalAreaColors,
            LocalSelectionAreaColors provides selectionAreaColors,
            LocalFocusAreaColors provides focusAreaColors,
            LocalDisabledAreaColors provides disabledAreaColors,
            content = content
        )
    }
}

val LocalCheckBoxColors = compositionLocalOf<CheckBoxColors> {
    LightTheme.CheckBoxColors
}

@Composable
fun Checkbox(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: CheckBoxColors = LocalCheckBoxColors.current,
) {
    TriStateCheckbox(
        state = ToggleableState(checked),
        onClick = { onCheckedChange(!checked) },
        interactionSource = interactionSource,
        enabled = enabled,
        modifier = modifier,
        colors = colors
    )
}

@Composable
fun Checkbox(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: CheckBoxColors = LocalCheckBoxColors.current,
    content: @Composable () -> Unit,
) {
    TriStateCheckbox(
        state = ToggleableState(checked),
        onClick = { onCheckedChange(!checked) },
        interactionSource = interactionSource,
        enabled = enabled,
        modifier = modifier,
        colors = colors,
        content = content
    )
}

@Composable
fun TriStateCheckbox(
    state: ToggleableState,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: CheckBoxColors = LocalCheckBoxColors.current,
) {
    val isFocused = remember { mutableStateOf(false) }
    colors.provideArea(enabled, isFocused.value, state != ToggleableState.Off) {
        CheckboxImpl(
            isFocused = isFocused.value, value = state,
            modifier = Modifier.onFocusEvent {
                isFocused.value = it.isFocused
            }.triStateToggleable(
                state = state,
                onClick = onClick,
                enabled = enabled,
                role = Role.Checkbox,
                interactionSource = interactionSource,
                indication = null
            )
        )
    }
}

@Composable
fun TriStateCheckbox(
    state: ToggleableState,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: CheckBoxColors = LocalCheckBoxColors.current,
    content: @Composable () -> Unit,
) {
    val isFocused = remember { mutableStateOf(false) }
    colors.provideArea(enabled, isFocused.value, state != ToggleableState.Off) {
        Row(
            modifier.onFocusEvent {
                isFocused.value = it.isFocused
            }.triStateToggleable(
                state = state,
                onClick = onClick,
                enabled = enabled,
                role = Role.Checkbox,
                interactionSource = interactionSource,
                indication = null
            ),
            verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)
        ) {
            CheckboxImpl(isFocused = isFocused.value, value = state)
            content()
        }
    }
}

private fun Checkmark() = ImageVector.Builder(
    name = "Checkmark", defaultWidth = 14.0.dp, defaultHeight = 14.0.dp, viewportWidth = 14.0f, viewportHeight = 14.0f
).apply {
    path(
        fill = SolidColor(Color(0xFFffffff)),
        stroke = null,
        strokeLineWidth = 0.0f,
        strokeLineCap = StrokeCap.Butt,
        strokeLineJoin = StrokeJoin.Miter,
        strokeLineMiter = 4.0f,
        pathFillType = PathFillType.EvenOdd
    ) {
        moveTo(5.625f, 8.4267f)
        lineTo(9.5566f, 2.9336f)
        curveTo(9.5566f, 2.9336f, 10.1737f, 2.3242f, 10.8612f, 2.8242f)
        curveTo(11.4433f, 3.3867f, 10.998f, 4.0938f, 10.998f, 4.0938f)
        lineTo(6.3183f, 10.6445f)
        curveTo(6.3183f, 10.6445f, 5.9941f, 11.0f, 5.5839f, 11.0f)
        curveTo(5.1737f, 11.0f, 4.873f, 10.6445f, 4.873f, 10.6445f)
        lineTo(2.9394f, 7.7461f)
        curveTo(2.9394f, 7.7461f, 2.5683f, 6.9805f, 3.2558f, 6.4609f)
        curveTo(4.0605f, 6.0781f, 4.5605f, 6.8394f, 4.5605f, 6.8394f)
        lineTo(5.625f, 8.4267f)
        close()
    }
}.build()

private fun CheckmarkIndeterminate() = ImageVector.Builder(
    name = "CheckmarkIndeterminate",
    defaultWidth = 14.0.dp,
    defaultHeight = 14.0.dp,
    viewportWidth = 14.0f,
    viewportHeight = 14.0f
).apply {
    path(
        fill = SolidColor(Color(0xFFffffff)),
        stroke = null,
        strokeLineWidth = 0.0f,
        strokeLineCap = StrokeCap.Butt,
        strokeLineJoin = StrokeJoin.Miter,
        strokeLineMiter = 4.0f,
        pathFillType = PathFillType.NonZero
    ) {
        moveTo(3.7402f, 5.73f)
        lineTo(10.1402f, 5.73f)
        arcTo(1.0f, 1.0f, 0.0f, false, true, 11.1402f, 6.73f)
        lineTo(11.1402f, 7.23f)
        arcTo(1.0f, 1.0f, 0.0f, false, true, 10.1402f, 8.23f)
        lineTo(3.7402f, 8.23f)
        arcTo(1.0f, 1.0f, 0.0f, false, true, 2.7402f, 7.23f)
        lineTo(2.7402f, 6.73f)
        arcTo(1.0f, 1.0f, 0.0f, false, true, 3.7402f, 5.73f)
        close()
    }
}.build()

@Composable
private fun CheckboxImpl(
    isFocused: Boolean,
    value: ToggleableState,
    modifier: Modifier = Modifier,
) {
    val icon = when (value) {
        ToggleableState.On -> rememberVectorPainter(Checkmark())
        ToggleableState.Indeterminate -> rememberVectorPainter(CheckmarkIndeterminate())
        else -> null
    }

    val colors = LocalAreaColors.current
    Canvas(modifier.wrapContentSize(Alignment.Center).requiredSize(14.dp)) {
        if (isFocused) {
            drawRoundRect(
                colors.focusColor,
                size = Size(18.dp.toPx(), 18.dp.toPx()),
                topLeft = Offset(-2.dp.toPx(), -2.dp.toPx()),
                cornerRadius = CornerRadius(4.dp.toPx())
            )
        }
        drawRoundRect(colors.startBorderColor, cornerRadius = CornerRadius(2.dp.toPx()))
        drawRoundRect(
            colors.startBackground,
            size = Size(12.dp.toPx(), 12.dp.toPx()),
            topLeft = Offset(1.dp.toPx(), 1.dp.toPx()),
            cornerRadius = CornerRadius(1.dp.toPx())
        )
        if (icon != null) {
            with(icon) {
                14.dp.toPx()
                draw(Size(14.dp.toPx(), 14.dp.toPx()), colorFilter = ColorFilter.tint(colors.foreground))
            }
        }
    }
}


================================================
FILE: expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ComboBox.kt
================================================
package io.kanro.compose.jetbrains.expui.control

import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import io.kanro.compose.jetbrains.expui.style.AreaColors
import io.kanro.compose.jetbrains.expui.style.AreaProvider
import io.kanro.compose.jetbrains.expui.style.DisabledAreaProvider
import io.kanro.compose.jetbrains.expui.style.FocusAreaProvider
import io.kanro.compose.jetbrains.expui.style.LocalAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalDisabledAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalFocusAreaColors
import io.kanro.compose.jetbrains.expui.style.LocalNormalAreaColors

class ComboBoxColors(
    override val normalAreaColors: AreaColors,
    override val focusAreaColors: AreaColors,
    override val disabledAreaColors: AreaColors,
    val dropdownMenuColors: DropdownMenuColors,
) : AreaProvider, FocusAreaProvider, DisabledAreaProvider {

    @Composable
    fun provideArea(enabled: Boolean, focused: Boolean, content: @Composable () -> Unit) {
        val currentAreaColor = when {
            !enabled -> disabledAreaColors
            focused -> focusAreaColors
            else -> normalAreaColors
        }

        CompositionLocalProvider(
            LocalAreaColors provides currentAreaColor,
            LocalNormalAreaColors provides normalAreaColors,
            LocalFocusAreaColors provides focusAreaColors,
            LocalDisabledAreaColors provides disabledAreaColors,
            LocalDropdownMenuColors provides dropdownMenuColors,
            content = content
        )
    }
}

val LocalComboBoxColors = compositionLocalOf<ComboBoxColors> {
    error("No ComboBoxColors provided")
}

@Composable
fun <T> ComboBox(
    items: List<T>,
    value: T,
    onValueChange: ((T) -> Unit)? = null,
    modifier: Modifier = Modifier,
    menuModifier: Modifier = Modifier,
    enabled: Boolean = true,
    valueRender: @Composable (T) -> Unit = { Label("$it") },
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: ComboBoxColors = LocalComboBoxColors.current,
) {
    val isFocused = remember { mutableStateOf(false) }
    var menuOpened by remember { mutableStateOf(false) }
    colors.provideArea(enabled, isFocused.value) {
        val areaColors = LocalAreaColors.current
        Box {
            Box(
                Modifier.defaultMinSize(72.dp, 24.dp).drawWithCache {
                    onDrawBehind {
                        if (isFocused.value) {
                            drawRoundRect(
                                areaColors.focusColor,
                                size = Size(size.width + 4.dp.toPx(), size.height + 4.dp.toPx()),
                                topLeft = Offset(-2.dp.toPx(), -2.dp.toPx()),
                                cornerRadius = CornerRadius(5.dp.toPx())
                            )
                        }
                        drawRoundRect(areaColors.startBorderColor, cornerRadius = CornerRadius(3.dp.toPx()))
                        drawRoundRect(
                            areaColors.startBackground,
                            size = Size(size.width - 2.dp.toPx(), size.height - 2.dp.toPx()),
                            topLeft = Offset(1.dp.toPx(), 1.dp.toPx()),
                            cornerRadius = CornerRadius(2.dp.toPx())
                        )
                    }
                }.onFocusEvent {
                    isFocused.value = it.isFocused
                }.clickable(
                    interactionSource = interactionSource, indication = null, enabled = enabled, onClick = {
                        menuOpened = true
                    }, role = Role.Button
                ).padding(6.dp, 3.dp).then(modifier),
                contentAlignment = Alignment.CenterStart
            ) {
                Row(
                    horizontalArrangement = Arrangement.Start,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    valueRender(value)
                }

                Icon("icons/buttonDropTriangle.svg", modifier = Modifier.align(Alignment.CenterEnd))
            }

            DropdownMenu(menuOpened, { menuOpened = false }, modifier = menuModifier) {
                items.forEach { item ->
                    val focusRequester = remember { FocusRequester() }
                    DropdownMenuItem(
                        onClick = {
                            if (value != item) {
                                onValueChange?.invoke(item)
                            }
                            menuOpened = false
                        },
                        Modifier.focusRequester(focusRequester).onFocusEvent {
                            if (it.isFocused && value != item) {
                                onValueChange?.invoke(item)
                            }
                        }
                    ) {
                        valueRender(item)
                    }
                    LaunchedEffect(menuOpened) {
                        if (menuOpened && value == item) {
                            focusRequester.requestFocus()
                        }
                    }
                }
            }
        }
    }
}


================================================
FILE: expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ContextCompositionLocals.kt
================================================
package io.kanro.compose.jetbrains.expui.control

import androidx.compose.runtime.compositionLocalOf

val LocalContentActivated = compositionLocalOf { true }


================================================
FILE: expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ContextMenu.kt
================================================
package io.kanro.compose.jetbrains.expui.control

import androidx.compose.foundation.ContextMenuItem
import androidx.compose.foundation.ContextMenuRepresentation
import androidx.compose.foundation.ContextMenuState
import androidx.compose.foundation.VerticalScrollbar
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.co
Download .txt
gitextract_99aa8iq5/

├── .github/
│   └── workflows/
│       ├── build.yml
│       └── release.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── build.gradle.kts
├── classic/
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── io/
│                   └── kanro/
│                       └── compose/
│                           └── jetbrains/
│                               ├── JBTheme.kt
│                               ├── JBTypography.kt
│                               ├── color/
│                               │   ├── ButtonColors.kt
│                               │   ├── CheckBoxColors.kt
│                               │   ├── FieldColors.kt
│                               │   ├── FocusColors.kt
│                               │   ├── IconColors.kt
│                               │   ├── PanelColors.kt
│                               │   ├── ProgressColors.kt
│                               │   ├── ScrollColors.kt
│                               │   ├── SelectionColors.kt
│                               │   ├── TabColors.kt
│                               │   ├── TableColors.kt
│                               │   ├── TextColors.kt
│                               │   ├── ToggleColors.kt
│                               │   └── ToolBarColors.kt
│                               ├── control/
│                               │   ├── ActionButton.kt
│                               │   ├── Button.kt
│                               │   ├── CheckBox.kt
│                               │   ├── ComboBox.kt
│                               │   ├── ContentAlpha.kt
│                               │   ├── ContentColor.kt
│                               │   ├── ContextMenu.kt
│                               │   ├── DropdownMenu.kt
│                               │   ├── EmbeddedTextField.kt
│                               │   ├── Icon.kt
│                               │   ├── JBToolBar.kt
│                               │   ├── JBTree.kt
│                               │   ├── JPanel.kt
│                               │   ├── ListView.kt
│                               │   ├── ProgressBar.kt
│                               │   ├── Selection.kt
│                               │   ├── Tab.kt
│                               │   ├── Text.kt
│                               │   └── TextField.kt
│                               └── icons/
│                                   ├── __JBIcons.kt
│                                   └── jbicons/
│                                       ├── __Actions.kt
│                                       ├── __General.kt
│                                       ├── actions/
│                                       │   ├── ArrowExpand.kt
│                                       │   ├── ArrowExpandDark.kt
│                                       │   ├── Checkmark.kt
│                                       │   ├── CheckmarkIndeterminate.kt
│                                       │   └── Close.kt
│                                       └── general/
│                                           ├── ButtonDropTriangle.kt
│                                           └── ButtonDropTriangleDark.kt
├── expui/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── io/
│                   └── kanro/
│                       └── compose/
│                           └── jetbrains/
│                               └── expui/
│                                   ├── DesktopPlatform.kt
│                                   ├── control/
│                                   │   ├── ActionButton.kt
│                                   │   ├── Button.kt
│                                   │   ├── CheckBox.kt
│                                   │   ├── ComboBox.kt
│                                   │   ├── ContextCompositionLocals.kt
│                                   │   ├── ContextMenu.kt
│                                   │   ├── DropdownMenu.kt
│                                   │   ├── Icon.kt
│                                   │   ├── Indication.kt
│                                   │   ├── Label.kt
│                                   │   ├── Link.kt
│                                   │   ├── Painter.kt
│                                   │   ├── PointerInput.kt
│                                   │   ├── ProgressBar.kt
│                                   │   ├── RadioButton.kt
│                                   │   ├── SegmentedButton.kt
│                                   │   ├── Tab.kt
│                                   │   ├── TextArea.kt
│                                   │   ├── TextField.kt
│                                   │   ├── ToolBar.kt
│                                   │   └── Tooltip.kt
│                                   ├── style/
│                                   │   ├── AreaColors.kt
│                                   │   ├── AreaProvider.kt
│                                   │   ├── Border.kt
│                                   │   └── TextStyle.kt
│                                   ├── theme/
│                                   │   ├── DarkTheme.kt
│                                   │   ├── Fonts.kt
│                                   │   ├── LightTheme.kt
│                                   │   └── Theme.kt
│                                   ├── util/
│                                   │   ├── CustomWindowDecorationAccessing.kt
│                                   │   └── UnsafeAccessing.kt
│                                   └── window/
│                                       ├── JBWindow.Linux.kt
│                                       ├── JBWindow.MacOS.kt
│                                       ├── JBWindow.Windows.kt
│                                       ├── JBWindow.kt
│                                       ├── MainToolBar.Basic.kt
│                                       ├── MainToolBar.Linux.kt
│                                       ├── MainToolBar.MacOS.kt
│                                       ├── MainToolBar.Windows.kt
│                                       └── MainToolBar.kt
├── expui-gallery/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── Main.kt
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
Condensed preview — 104 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (461K chars).
[
  {
    "path": ".github/workflows/build.yml",
    "chars": 3772,
    "preview": "name: Build\non:\n  # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 3271,
    "preview": "# GitHub Actions Workflow created for handling the release process based on the draft release prepared\n# with the Build "
  },
  {
    "path": ".gitignore",
    "chars": 312,
    "preview": ".gradle\n/build/\n!foundation/gradle/wrapper/gradle-wrapper.jar\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.proje"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 654,
    "preview": "# Changelog\n\n## [Unreleased]\n\n## [2.2.0]\n- Upgrade to compose 1.5.2\n\n## [2.1.0]\n- Provide BasicMainToolBar #18 \n- Disabl"
  },
  {
    "path": "LICENSE",
    "chars": 1066,
    "preview": "MIT License\n\nCopyright (c) 2020 ButterCam\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
  },
  {
    "path": "README.md",
    "chars": 4752,
    "preview": "# We are planning to migrate to [JetBrains/jewel](https://github.com/JetBrains/jewel)!\n\nWe are discussing with JetBrains"
  },
  {
    "path": "build.gradle.kts",
    "chars": 1355,
    "preview": "plugins {\n    id(\"com.bybutter.sisyphus.project\") version \"2.1.0\" apply false\n    id(\"com.netflix.nebula.contacts\") vers"
  },
  {
    "path": "classic/README.md",
    "chars": 1513,
    "preview": "# JetBrains UI Kit for Compose Desktop\n\nJetBrains style controls and UI for [Compose Desktop](https://www.jetbrains.com/"
  },
  {
    "path": "classic/build.gradle.kts",
    "chars": 684,
    "preview": "plugins {\n    kotlin(\"jvm\")\n    `java-library`\n    id(\"com.netflix.nebula.maven-publish\")\n    id(\"com.netflix.nebula.sou"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/JBTheme.kt",
    "chars": 9679,
    "preview": "package io.kanro.compose.jetbrains\n\nimport androidx.compose.foundation.LocalScrollbarStyle\nimport androidx.compose.runti"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/JBTypography.kt",
    "chars": 3527,
    "preview": "package io.kanro.compose.jetbrains\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.ui.text.T"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ButtonColors.kt",
    "chars": 6185,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.foundation.interaction.InteractionSource\nimport androi"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/CheckBoxColors.kt",
    "chars": 1962,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/FieldColors.kt",
    "chars": 3506,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.animation.animateColorAsState\nimport androidx.compose."
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/FocusColors.kt",
    "chars": 1262,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/IconColors.kt",
    "chars": 926,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/PanelColors.kt",
    "chars": 1067,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ProgressColors.kt",
    "chars": 905,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ScrollColors.kt",
    "chars": 1125,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.foundation.ScrollbarStyle\nimport androidx.compose.foun"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/SelectionColors.kt",
    "chars": 1696,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/TabColors.kt",
    "chars": 1660,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/TableColors.kt",
    "chars": 440,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutab"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/TextColors.kt",
    "chars": 1851,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.run"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ToggleColors.kt",
    "chars": 387,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutab"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/color/ToolBarColors.kt",
    "chars": 1967,
    "preview": "package io.kanro.compose.jetbrains.color\n\nimport androidx.compose.foundation.interaction.InteractionSource\nimport androi"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ActionButton.kt",
    "chars": 5273,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.BorderStroke\nimport androidx.compose.foun"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Button.kt",
    "chars": 9681,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.background\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/CheckBox.kt",
    "chars": 4109,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.Canvas\nimport androidx.compose.foundation"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ComboBox.kt",
    "chars": 4883,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.background\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ContentAlpha.kt",
    "chars": 146,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.runtime.compositionLocalOf\n\nval LocalContentAlpha = "
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ContentColor.kt",
    "chars": 534,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.c"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ContextMenu.kt",
    "chars": 5633,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.ContextMenuData\nimport androidx.compose.f"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/DropdownMenu.kt",
    "chars": 7170,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/EmbeddedTextField.kt",
    "chars": 4438,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.interaction.InteractionSource\nimport andr"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Icon.kt",
    "chars": 4262,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/JBToolBar.kt",
    "chars": 2694,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.background\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/JBTree.kt",
    "chars": 4431,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimport androidx"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/JPanel.kt",
    "chars": 2412,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.background\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ListView.kt",
    "chars": 1363,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/ProgressBar.kt",
    "chars": 2992,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.animation.core.animateFloat\nimport androidx.compose."
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Selection.kt",
    "chars": 3418,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.background\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Tab.kt",
    "chars": 3377,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/Text.kt",
    "chars": 4185,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.text.BasicText\nimport androidx.compose.fo"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/control/TextField.kt",
    "chars": 23794,
    "preview": "package io.kanro.compose.jetbrains.control\n\nimport androidx.compose.foundation.background\nimport androidx.compose.founda"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/__JBIcons.kt",
    "chars": 66,
    "preview": "package io.kanro.compose.jetbrains.icons\n\ninternal object JBIcons\n"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/__Actions.kt",
    "chars": 197,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons\n\nimport io.kanro.compose.jetbrains.icons.JBIcons\n\ninternal object Actio"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/__General.kt",
    "chars": 197,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons\n\nimport io.kanro.compose.jetbrains.icons.JBIcons\n\ninternal object Gener"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/ArrowExpand.kt",
    "chars": 1471,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons.actions\n\nimport androidx.compose.ui.graphics.Color\nimport androidx.comp"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/ArrowExpandDark.kt",
    "chars": 1499,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons.actions\n\nimport androidx.compose.ui.graphics.Color\nimport androidx.comp"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/Checkmark.kt",
    "chars": 1995,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons.actions\n\nimport androidx.compose.ui.graphics.Color\nimport androidx.comp"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/CheckmarkIndeterminate.kt",
    "chars": 1891,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons.actions\n\nimport androidx.compose.ui.graphics.Color\nimport androidx.comp"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/actions/Close.kt",
    "chars": 1842,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons.actions\n\nimport androidx.compose.ui.graphics.Color\nimport androidx.comp"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/general/ButtonDropTriangle.kt",
    "chars": 1508,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons.general\n\nimport androidx.compose.ui.graphics.Color\nimport androidx.comp"
  },
  {
    "path": "classic/src/main/kotlin/io/kanro/compose/jetbrains/icons/jbicons/general/ButtonDropTriangleDark.kt",
    "chars": 1536,
    "preview": "package io.kanro.compose.jetbrains.icons.jbicons.general\n\nimport androidx.compose.ui.graphics.Color\nimport androidx.comp"
  },
  {
    "path": "expui/build.gradle.kts",
    "chars": 523,
    "preview": "plugins {\n    kotlin(\"jvm\")\n    id(\"com.netflix.nebula.maven-publish\")\n    id(\"com.netflix.nebula.source-jar\")\n    id(\"c"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/DesktopPlatform.kt",
    "chars": 488,
    "preview": "package io.kanro.compose.jetbrains.expui\n\nenum class DesktopPlatform {\n    Linux,\n    Windows,\n    MacOS,\n    Unknown;\n\n"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ActionButton.kt",
    "chars": 3236,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Button.kt",
    "chars": 5554,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.clickable\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/CheckBox.kt",
    "chars": 9780,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.Canvas\nimport androidx.compose.foun"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ComboBox.kt",
    "chars": 6400,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.clickable\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ContextCompositionLocals.kt",
    "chars": 158,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.runtime.compositionLocalOf\n\nval LocalContentAc"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ContextMenu.kt",
    "chars": 8794,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.ContextMenuItem\nimport androidx.com"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/DropdownMenu.kt",
    "chars": 15137,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.animation.core.MutableTransitionState\nimport a"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Icon.kt",
    "chars": 4486,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Indication.kt",
    "chars": 2489,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Label.kt",
    "chars": 3877,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.text.BasicText\nimport androidx.comp"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Link.kt",
    "chars": 12411,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Painter.kt",
    "chars": 13228,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifi"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/PointerInput.kt",
    "chars": 558,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.input.p"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ProgressBar.kt",
    "chars": 3071,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.animation.core.animateFloat\nimport androidx.co"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/RadioButton.kt",
    "chars": 5432,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.Canvas\nimport androidx.compose.foun"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/SegmentedButton.kt",
    "chars": 8642,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.focusable\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Tab.kt",
    "chars": 7717,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.clickable\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/TextArea.kt",
    "chars": 8183,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.interaction.MutableInteractionSourc"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/TextField.kt",
    "chars": 13861,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.interaction.MutableInteractionSourc"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/ToolBar.kt",
    "chars": 4313,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/control/Tooltip.kt",
    "chars": 3043,
    "preview": "package io.kanro.compose.jetbrains.expui.control\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimport an"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/style/AreaColors.kt",
    "chars": 4016,
    "preview": "package io.kanro.compose.jetbrains.expui.style\n\nimport androidx.compose.foundation.background\nimport androidx.compose.fo"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/style/AreaProvider.kt",
    "chars": 1232,
    "preview": "package io.kanro.compose.jetbrains.expui.style\n\ninterface AreaProvider {\n    val normalAreaColors: AreaColors\n}\n\ninterfa"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/style/Border.kt",
    "chars": 9163,
    "preview": "package io.kanro.compose.jetbrains.expui.style\n\nimport androidx.compose.foundation.BorderStroke\nimport androidx.compose."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/style/TextStyle.kt",
    "chars": 1131,
    "preview": "package io.kanro.compose.jetbrains.expui.style\n\nimport androidx.compose.runtime.compositionLocalOf\nimport io.kanro.compo"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/theme/DarkTheme.kt",
    "chars": 30271,
    "preview": "package io.kanro.compose.jetbrains.expui.theme\n\nimport androidx.compose.foundation.LocalContextMenuRepresentation\nimport"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/theme/Fonts.kt",
    "chars": 1271,
    "preview": "package io.kanro.compose.jetbrains.expui.theme\n\nimport androidx.compose.ui.text.font.FontFamily\nimport androidx.compose."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/theme/LightTheme.kt",
    "chars": 30128,
    "preview": "package io.kanro.compose.jetbrains.expui.theme\n\nimport androidx.compose.foundation.LocalContextMenuRepresentation\nimport"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/theme/Theme.kt",
    "chars": 572,
    "preview": "package io.kanro.compose.jetbrains.expui.theme\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runti"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/util/CustomWindowDecorationAccessing.kt",
    "chars": 2397,
    "preview": "package io.kanro.compose.jetbrains.expui.util\n\nimport java.awt.Shape\nimport java.awt.Window\nimport java.lang.reflect.Met"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/util/UnsafeAccessing.kt",
    "chars": 1920,
    "preview": "package io.kanro.compose.jetbrains.expui.util\n\nimport sun.misc.Unsafe\nimport java.lang.reflect.AccessibleObject\n\ninterna"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/JBWindow.Linux.kt",
    "chars": 2543,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.foundation.background\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/JBWindow.MacOS.kt",
    "chars": 4153,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.foundation.background\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/JBWindow.Windows.kt",
    "chars": 2714,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.foundation.background\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/JBWindow.kt",
    "chars": 2608,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runt"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/MainToolBar.Basic.kt",
    "chars": 1052,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx."
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/MainToolBar.Linux.kt",
    "chars": 370,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.w"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/MainToolBar.MacOS.kt",
    "chars": 866,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compos"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/MainToolBar.Windows.kt",
    "chars": 3940,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.f"
  },
  {
    "path": "expui/src/main/kotlin/io/kanro/compose/jetbrains/expui/window/MainToolBar.kt",
    "chars": 8909,
    "preview": "package io.kanro.compose.jetbrains.expui.window\n\nimport androidx.compose.foundation.layout.LayoutScopeMarker\nimport andr"
  },
  {
    "path": "expui-gallery/build.gradle.kts",
    "chars": 679,
    "preview": "plugins {\n    kotlin(\"jvm\")\n    id(\"org.jetbrains.compose\")\n}\n\ndependencies {\n    implementation(\"org.jetbrains.kotlinx:"
  },
  {
    "path": "expui-gallery/src/main/kotlin/Main.kt",
    "chars": 15842,
    "preview": "import androidx.compose.animation.core.animateFloat\nimport androidx.compose.animation.core.infiniteRepeatable\nimport and"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 200,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradle.properties",
    "chars": 26,
    "preview": "kotlin.code.style=official"
  },
  {
    "path": "gradlew",
    "chars": 5774,
    "preview": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "gradlew.bat",
    "chars": 2674,
    "preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
  },
  {
    "path": "settings.gradle.kts",
    "chars": 409,
    "preview": "pluginManagement {\n    repositories {\n        mavenLocal()\n        gradlePluginPortal()\n        maven(\"https://maven.pkg"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the ButterCam/compose-jetbrains-theme GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 104 files (428.5 KB), approximately 95.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!