mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[JEWEL-845] Add Context Menu to External Links
[JEWEL-845] Add Context Menu to External Links Updating branch now that #3091 merged update api dumps applying pr suggestions reran apichecktest add KDoc to MessageResourceResolver add KDoc to MessageResourceResolver undo sample xml run config code fixes running ktlint and apichecktest again remove default value for uri param in ExternalLinkImpl fix api dump + run configs remove empty blank line at stand_alone_sample eof more code fixes closes https://github.com/JetBrains/intellij-community/pull/3107 GitOrigin-RevId: c5842c900120b6d96c563e79568f524e3e96540b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9c9d20fbd4
commit
91ce83f05d
@@ -26,6 +26,11 @@ f:org.jetbrains.jewel.bridge.BridgeTypography
|
||||
- getMedium(androidx.compose.runtime.Composer,I):androidx.compose.ui.text.TextStyle
|
||||
- getRegular(androidx.compose.runtime.Composer,I):androidx.compose.ui.text.TextStyle
|
||||
- getSmall(androidx.compose.runtime.Composer,I):androidx.compose.ui.text.TextStyle
|
||||
f:org.jetbrains.jewel.bridge.BridgeUriHandler
|
||||
- androidx.compose.ui.platform.UriHandler
|
||||
- sf:$stable:I
|
||||
- sf:INSTANCE:org.jetbrains.jewel.bridge.BridgeUriHandler
|
||||
- openUri(java.lang.String):V
|
||||
f:org.jetbrains.jewel.bridge.BridgeUtilsKt
|
||||
- sf:createVerticalBrush-8A-3gB4(java.util.List,F,F,I):androidx.compose.ui.graphics.Brush
|
||||
- bs:createVerticalBrush-8A-3gB4$default(java.util.List,F,F,I,I,java.lang.Object):androidx.compose.ui.graphics.Brush
|
||||
|
||||
@@ -35,6 +35,12 @@ public final class org/jetbrains/jewel/bridge/BridgeTypography : org/jetbrains/j
|
||||
public fun getSmall (Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/text/TextStyle;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/bridge/BridgeUriHandler : androidx/compose/ui/platform/UriHandler {
|
||||
public static final field $stable I
|
||||
public static final field INSTANCE Lorg/jetbrains/jewel/bridge/BridgeUriHandler;
|
||||
public fun openUri (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/bridge/BridgeUtilsKt {
|
||||
public static final fun createVerticalBrush-8A-3gB4 (Ljava/util/List;FFI)Landroidx/compose/ui/graphics/Brush;
|
||||
public static synthetic fun createVerticalBrush-8A-3gB4$default (Ljava/util/List;FFIILjava/lang/Object;)Landroidx/compose/ui/graphics/Brush;
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jewel.bridge
|
||||
|
||||
import com.intellij.ide.IdeBundle
|
||||
import org.jetbrains.jewel.ui.util.MessageResourceResolver
|
||||
|
||||
/**
|
||||
* A provider for fetching localized strings using the IDE's message bundle.
|
||||
*
|
||||
* This class implements the [MessageResourceResolver] interface and delegates the retrieval of strings to the
|
||||
* [IdeBundle.message] method. It can be used to retrieve strings associated with a specific key from the IDE's resource
|
||||
* bundle.
|
||||
*/
|
||||
internal class BridgeMessageResourceResolver : MessageResourceResolver {
|
||||
/**
|
||||
* Fetches a string associated with the given key from the IDE's message bundle.
|
||||
*
|
||||
* This function uses the [IdeBundle.message] method to retrieve a localized string based on the provided key. The
|
||||
* key should correspond to a message ID defined in the IDE's resource bundle.
|
||||
*
|
||||
* @param key The key representing the string to fetch. This key typically corresponds to a message ID in the IDE's
|
||||
* message bundle (e.g, ""action.text.copy.link.address").
|
||||
* @return The string associated with the provided key. If the key is not found, it will return an empty string.
|
||||
*/
|
||||
override fun resolveIdeBundleMessage(key: String): String = IdeBundle.message(key)
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jewel.bridge
|
||||
|
||||
import androidx.compose.ui.platform.UriHandler
|
||||
import com.intellij.ide.BrowserUtil
|
||||
|
||||
/**
|
||||
* A custom implementation of [UriHandler] that delegates the handling to IntelliJ's BrowserUtil class.
|
||||
*
|
||||
* This object overrides the [openUri] function to invoke the [BrowserUtil.browse] method, which attempts to open the
|
||||
* provided URI. If the URI is valid, it opens in the system's default web browser. If the URI is invalid (e.g., an
|
||||
* empty string), it may open a local file explorer (Windows) or Finder (macOS), depending on the URI and operating
|
||||
* system.
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* BridgeUriHandler.openUri("https://www.example.com")
|
||||
* BridgeUriHandler.openUri("") // May open file explorer or Finder
|
||||
* ```
|
||||
*/
|
||||
public object BridgeUriHandler : UriHandler {
|
||||
override fun openUri(uri: String) {
|
||||
BrowserUtil.browse(uri)
|
||||
}
|
||||
}
|
||||
+3
@@ -20,6 +20,7 @@ import org.jetbrains.jewel.foundation.ExperimentalJewelApi
|
||||
import org.jetbrains.jewel.foundation.InternalJewelApi
|
||||
import org.jetbrains.jewel.foundation.util.JewelLogger
|
||||
import org.jetbrains.jewel.ui.component.LocalPopupRenderer
|
||||
import org.jetbrains.jewel.ui.util.LocalMessageResourceResolverProvider
|
||||
|
||||
public fun compose(config: ComposePanel.() -> Unit = {}, content: @Composable () -> Unit): JComponent =
|
||||
JewelComposePanel(config, content)
|
||||
@@ -73,6 +74,7 @@ public fun JewelComposeNoThemePanel(config: ComposePanel.() -> Unit = {}, conten
|
||||
CompositionLocalProvider(
|
||||
LocalComponent provides this@createJewelComposePanel,
|
||||
LocalPopupRenderer provides JBPopupRenderer,
|
||||
LocalMessageResourceResolverProvider provides BridgeMessageResourceResolver(),
|
||||
) {
|
||||
ComponentDataProviderBridge(jewelPanel, content = content)
|
||||
}
|
||||
@@ -97,6 +99,7 @@ public fun JewelToolWindowNoThemeComposePanel(
|
||||
CompositionLocalProvider(
|
||||
LocalComponent provides this@createJewelComposePanel,
|
||||
LocalPopupRenderer provides JBPopupRenderer,
|
||||
LocalMessageResourceResolverProvider provides BridgeMessageResourceResolver(),
|
||||
) {
|
||||
ComponentDataProviderBridge(jewelPanel, content = content)
|
||||
}
|
||||
|
||||
+6
@@ -7,8 +7,11 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import org.jetbrains.jewel.bridge.BridgeMessageResourceResolver
|
||||
import org.jetbrains.jewel.bridge.BridgePainterHintsProvider
|
||||
import org.jetbrains.jewel.bridge.BridgeTypography
|
||||
import org.jetbrains.jewel.bridge.BridgeUriHandler
|
||||
import org.jetbrains.jewel.bridge.SwingBridgeReader
|
||||
import org.jetbrains.jewel.bridge.clipboard.JewelBridgeClipboard
|
||||
import org.jetbrains.jewel.bridge.icon.BridgeNewUiChecker
|
||||
@@ -23,6 +26,7 @@ import org.jetbrains.jewel.ui.LocalTypography
|
||||
import org.jetbrains.jewel.ui.icon.LocalNewUiChecker
|
||||
import org.jetbrains.jewel.ui.painter.LocalPainterHintsProvider
|
||||
import org.jetbrains.jewel.ui.theme.BaseJewelTheme
|
||||
import org.jetbrains.jewel.ui.util.LocalMessageResourceResolverProvider
|
||||
|
||||
private val bridgeThemeReader by lazy { SwingBridgeReader() }
|
||||
|
||||
@@ -44,6 +48,8 @@ public fun SwingBridgeTheme(content: @Composable () -> Unit) {
|
||||
LocalMenuItemShortcutProvider provides BridgeMenuItemShortcutProvider,
|
||||
LocalMenuItemShortcutHintProvider provides BridgeMenuItemShortcutHintProvider,
|
||||
LocalTypography provides BridgeTypography,
|
||||
LocalUriHandler provides BridgeUriHandler,
|
||||
LocalMessageResourceResolverProvider provides BridgeMessageResourceResolver(),
|
||||
) {
|
||||
content()
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jewel.intui.standalone
|
||||
|
||||
import org.jetbrains.jewel.ui.util.MessageResourceResolver
|
||||
|
||||
/**
|
||||
* A provider for UI strings that returns localized or default string values based on a given key.
|
||||
*
|
||||
* This class implements the [MessageResourceResolver] interface and is responsible for fetching string values
|
||||
* associated with specific keys. It can be used to retrieve action text for UI elements, like buttons or menu items
|
||||
* based on the string keys from IntelliJ Platform resource bundle.
|
||||
*/
|
||||
internal class IntUiMessageResourceResolver : MessageResourceResolver {
|
||||
/**
|
||||
* Fetches the string associated with a given key.
|
||||
*
|
||||
* This function looks up the provided key and returns the corresponding string value. If the key is not found, it
|
||||
* returns an empty string by default.
|
||||
*
|
||||
* @param key The key representing the string to fetch. This key typically corresponds to a message ID in the IDE's
|
||||
* message bundle (e.g, ""action.text.copy.link.address").
|
||||
* @return The string associated with the provided key. If the key is not found, an empty string is returned.
|
||||
*/
|
||||
override fun resolveIdeBundleMessage(key: String): String =
|
||||
when (key) {
|
||||
"action.text.open.link.in.browser" -> "Open Link in Browser"
|
||||
"action.text.copy.link.address" -> "Copy Link Address"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
+3
@@ -14,6 +14,7 @@ import org.jetbrains.jewel.foundation.theme.ThemeDefinition
|
||||
import org.jetbrains.jewel.foundation.theme.ThemeIconData
|
||||
import org.jetbrains.jewel.intui.core.theme.IntUiDarkTheme
|
||||
import org.jetbrains.jewel.intui.core.theme.IntUiLightTheme
|
||||
import org.jetbrains.jewel.intui.standalone.IntUiMessageResourceResolver
|
||||
import org.jetbrains.jewel.intui.standalone.IntUiTypography
|
||||
import org.jetbrains.jewel.intui.standalone.StandalonePainterHintsProvider
|
||||
import org.jetbrains.jewel.intui.standalone.icon.StandaloneNewUiChecker
|
||||
@@ -62,6 +63,7 @@ import org.jetbrains.jewel.ui.component.styling.TooltipStyle
|
||||
import org.jetbrains.jewel.ui.icon.LocalNewUiChecker
|
||||
import org.jetbrains.jewel.ui.painter.LocalPainterHintsProvider
|
||||
import org.jetbrains.jewel.ui.theme.BaseJewelTheme
|
||||
import org.jetbrains.jewel.ui.util.LocalMessageResourceResolverProvider
|
||||
|
||||
/**
|
||||
* Create a light theme definition.
|
||||
@@ -320,6 +322,7 @@ public fun IntUiTheme(
|
||||
LocalMenuItemShortcutProvider provides StandaloneShortcutProvider,
|
||||
LocalMenuItemShortcutHintProvider provides StandaloneMenuItemShortcutHintProvider,
|
||||
LocalTypography provides IntUiTypography,
|
||||
LocalMessageResourceResolverProvider provides IntUiMessageResourceResolver(),
|
||||
) {
|
||||
content()
|
||||
}
|
||||
|
||||
+22
-13
@@ -89,26 +89,35 @@ internal class SwingComparisonTabPanel : BorderLayoutPanel() {
|
||||
}
|
||||
|
||||
private fun Panel.linksRow() {
|
||||
row("Links:") {
|
||||
browserLink("Enabled link", "")
|
||||
val jewelReadmeLink = "https://github.com/JetBrains/intellij-community/tree/master/platform/jewel/#readme"
|
||||
|
||||
compose { ExternalLink(text = "Enabled link", enabled = true, onClick = {}) }
|
||||
row("Links:") {
|
||||
cell(
|
||||
component =
|
||||
BrowserLink(
|
||||
icon = AllIcons.Ide.External_link_arrow,
|
||||
text = "Enabled link",
|
||||
tooltip = null,
|
||||
url = "",
|
||||
)
|
||||
.apply { enabled(true) }
|
||||
)
|
||||
|
||||
compose { ExternalLink(text = "Enabled link", uri = "", enabled = true) }
|
||||
|
||||
cell(
|
||||
component =
|
||||
BrowserLink(
|
||||
icon = IconLoader.getDisabledIcon(AllIcons.Ide.External_link_arrow),
|
||||
text = "Disabled link",
|
||||
tooltip = null,
|
||||
url = "",
|
||||
)
|
||||
icon = IconLoader.getDisabledIcon(AllIcons.Ide.External_link_arrow),
|
||||
text = "Disabled link",
|
||||
tooltip = null,
|
||||
url = jewelReadmeLink,
|
||||
)
|
||||
.apply { isEnabled = false }
|
||||
)
|
||||
.applyToComponent {
|
||||
enabled(false)
|
||||
autoHideOnDisable = false
|
||||
}
|
||||
.applyToComponent { autoHideOnDisable = false }
|
||||
|
||||
compose { ExternalLink(text = "Disabled link", enabled = false, onClick = {}) }
|
||||
compose { ExternalLink(text = "Disabled link", uri = "", enabled = false) }
|
||||
}
|
||||
.layout(RowLayout.PARENT_GRID)
|
||||
}
|
||||
|
||||
+2
-2
@@ -63,8 +63,8 @@ public fun Banners() {
|
||||
style = JewelTheme.defaultBannerStyle.information,
|
||||
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt",
|
||||
actions = {
|
||||
Link("Action A", onClick = { clickLabel = "Info default no icon Action A clicked" })
|
||||
Link("Action B", onClick = { clickLabel = "Info default no icon Action B clicked" })
|
||||
Link("Action A", onClick = { clickLabel = "Info default with icon Action A clicked" })
|
||||
Link("Action B", onClick = { clickLabel = "Info default with icon Action B clicked" })
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
+3
-2
@@ -27,12 +27,13 @@ import org.jetbrains.jewel.ui.theme.linkStyle
|
||||
@Composable
|
||||
public fun Links() {
|
||||
val alwaysUnderline = JewelTheme.linkStyle.copy(underlineBehavior = LinkUnderlineBehavior.ShowAlways)
|
||||
val jewelReadMeLink = "https://github.com/JetBrains/intellij-community/tree/master/platform/jewel/#readme"
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Link(text = "Link", onClick = {})
|
||||
|
||||
Link(text = "Always underlined", onClick = {}, style = alwaysUnderline)
|
||||
|
||||
ExternalLink("ExternalLink", {})
|
||||
ExternalLink(text = "ExternalLink", uri = jewelReadMeLink)
|
||||
|
||||
val items = remember { listOf("Light", "Dark", "---", "High Contrast", "Darcula", "IntelliJ Light") }
|
||||
var selected by remember { mutableStateOf(items.first()) }
|
||||
@@ -51,7 +52,7 @@ public fun Links() {
|
||||
|
||||
Link(text = "Always underlined", onClick = {}, style = alwaysUnderline, enabled = false)
|
||||
|
||||
ExternalLink(text = "ExternalLink", onClick = {}, enabled = false)
|
||||
ExternalLink(text = "ExternalLink", uri = jewelReadMeLink)
|
||||
|
||||
DropdownLink(text = "DropdownLink", enabled = false) {}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,8 @@ f:org.jetbrains.jewel.ui.component.DefaultMenuController
|
||||
- onHoveredChange(Z):V
|
||||
- registerShortcutAction(javax.swing.KeyStroke,kotlin.jvm.functions.Function0):V
|
||||
- submenuController(kotlin.jvm.functions.Function1):org.jetbrains.jewel.ui.component.DefaultMenuController
|
||||
f:org.jetbrains.jewel.ui.component.LinkKt
|
||||
- sf:ExternalLink-kye4rC8(java.lang.String,java.lang.String,androidx.compose.ui.Modifier,Z,androidx.compose.ui.text.TextStyle,I,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.LinkStyle,androidx.compose.runtime.Composer,I,I):V
|
||||
org.jetbrains.jewel.ui.component.MenuController
|
||||
- a:clearShortcutActions():V
|
||||
- a:close-iuPiT84(I):Z
|
||||
@@ -372,3 +374,7 @@ org.jetbrains.jewel.ui.painter.PainterProviderScope
|
||||
org.jetbrains.jewel.ui.painter.ResourcePainterProviderScope
|
||||
- org.jetbrains.jewel.ui.painter.PainterProviderScope
|
||||
- a:getClassLoaders():java.util.Set
|
||||
org.jetbrains.jewel.ui.util.MessageResourceResolver
|
||||
- a:resolveIdeBundleMessage(java.lang.String):java.lang.String
|
||||
f:org.jetbrains.jewel.ui.util.MessageResourceResolverKt
|
||||
- sf:getLocalMessageResourceResolverProvider():androidx.compose.runtime.ProvidableCompositionLocal
|
||||
|
||||
@@ -625,6 +625,7 @@ public final class org/jetbrains/jewel/ui/component/LinearProgressBarKt {
|
||||
|
||||
public final class org/jetbrains/jewel/ui/component/LinkKt {
|
||||
public static final fun DropdownLink-RWo7tUw (Ljava/lang/String;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/text/TextStyle;ILandroidx/compose/foundation/interaction/MutableInteractionSource;Lorg/jetbrains/jewel/ui/component/styling/LinkStyle;Landroidx/compose/ui/Modifier;Lorg/jetbrains/jewel/ui/component/styling/MenuStyle;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
|
||||
public static final fun ExternalLink-kye4rC8 (Ljava/lang/String;Ljava/lang/String;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/text/TextStyle;ILandroidx/compose/foundation/interaction/MutableInteractionSource;Lorg/jetbrains/jewel/ui/component/styling/LinkStyle;Landroidx/compose/runtime/Composer;II)V
|
||||
public static final fun ExternalLink-kye4rC8 (Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/text/TextStyle;ILandroidx/compose/foundation/interaction/MutableInteractionSource;Lorg/jetbrains/jewel/ui/component/styling/LinkStyle;Landroidx/compose/runtime/Composer;II)V
|
||||
public static final fun Link-kye4rC8 (Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/text/TextStyle;ILandroidx/compose/foundation/interaction/MutableInteractionSource;Lorg/jetbrains/jewel/ui/component/styling/LinkStyle;Landroidx/compose/runtime/Composer;II)V
|
||||
}
|
||||
@@ -5096,6 +5097,14 @@ public final class org/jetbrains/jewel/ui/util/ColorExtensionsKt {
|
||||
public static final fun toRgbaHexString-8_81llA (J)Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract interface class org/jetbrains/jewel/ui/util/MessageResourceResolver {
|
||||
public abstract fun resolveIdeBundleMessage (Ljava/lang/String;)Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/ui/util/MessageResourceResolverKt {
|
||||
public static final fun getLocalMessageResourceResolverProvider ()Landroidx/compose/runtime/ProvidableCompositionLocal;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/ui/util/ModifierExtensionsKt {
|
||||
public static final fun thenIf (Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public class ContextSubmenu(label: String, public val submenu: () -> List<Contex
|
||||
|
||||
public class ContextMenuItemOption(
|
||||
public val icon: IconKey? = null,
|
||||
public val actionType: ContextMenuItemOptionAction,
|
||||
public val actionType: ContextMenuItemOptionAction? = null,
|
||||
label: String,
|
||||
action: () -> Unit,
|
||||
) : ContextMenuItem(label, action)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.jewel.ui.component
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.FocusInteraction
|
||||
import androidx.compose.foundation.interaction.HoverInteraction
|
||||
@@ -17,18 +18,26 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.InputMode
|
||||
import androidx.compose.ui.input.pointer.PointerIcon
|
||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.platform.ClipEntry
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.platform.LocalInputModeManager
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.platform.UriHandler
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import java.awt.Cursor
|
||||
import java.awt.datatransfer.StringSelection
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.jewel.foundation.modifier.onHover
|
||||
import org.jetbrains.jewel.foundation.modifier.thenIf
|
||||
import org.jetbrains.jewel.foundation.state.CommonStateBitMask
|
||||
@@ -40,6 +49,7 @@ import org.jetbrains.jewel.foundation.state.CommonStateBitMask.Pressed
|
||||
import org.jetbrains.jewel.foundation.state.FocusableComponentState
|
||||
import org.jetbrains.jewel.foundation.theme.JewelTheme
|
||||
import org.jetbrains.jewel.foundation.theme.JewelTheme.Companion.isSwingCompatMode
|
||||
import org.jetbrains.jewel.foundation.util.JewelLogger
|
||||
import org.jetbrains.jewel.ui.component.styling.LinkStyle
|
||||
import org.jetbrains.jewel.ui.component.styling.LinkUnderlineBehavior.ShowAlways
|
||||
import org.jetbrains.jewel.ui.component.styling.LinkUnderlineBehavior.ShowOnHover
|
||||
@@ -49,7 +59,9 @@ import org.jetbrains.jewel.ui.component.styling.MenuStyle
|
||||
import org.jetbrains.jewel.ui.disabledAppearance
|
||||
import org.jetbrains.jewel.ui.focusOutline
|
||||
import org.jetbrains.jewel.ui.icon.IconKey
|
||||
import org.jetbrains.jewel.ui.icons.AllIconsKeys
|
||||
import org.jetbrains.jewel.ui.painter.hints.Stateful
|
||||
import org.jetbrains.jewel.ui.util.LocalMessageResourceResolverProvider
|
||||
|
||||
/**
|
||||
* A clickable text link that follows the standard visual styling with customizable appearance.
|
||||
@@ -112,8 +124,8 @@ public fun Link(
|
||||
* **Usage example:**
|
||||
* [`Links.kt`](https://github.com/JetBrains/intellij-community/blob/master/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/component/Links.kt)
|
||||
*
|
||||
* **Swing equivalent:** [`JLabel`](https://docs.oracle.com/javase/tutorial/uiswing/components/label.html) with HTML
|
||||
* link styling and external link icon
|
||||
* **Swing equivalent:**
|
||||
* [`BrowserLink`](https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/ui/components/BrowserLink.kt)
|
||||
*
|
||||
* @param text The text to be displayed as a link
|
||||
* @param onClick Called when the link is clicked
|
||||
@@ -136,8 +148,9 @@ public fun ExternalLink(
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
style: LinkStyle = LocalLinkStyle.current,
|
||||
) {
|
||||
LinkImpl(
|
||||
ExternalLinkImpl(
|
||||
text = text,
|
||||
uri = "",
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
@@ -145,10 +158,120 @@ public fun ExternalLink(
|
||||
interactionSource = interactionSource,
|
||||
style = style,
|
||||
textStyle = textStyle,
|
||||
icon = style.icons.externalLink,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An external link that follows the standard visual styling, including an external link icon.
|
||||
*
|
||||
* Please be aware that this ExternalLink will automatically open a link on click, unlike the other overloads.
|
||||
*
|
||||
* Provides a text link with an external link icon that indicates the link leads to external content. The link supports
|
||||
* various states including enabled/disabled, focused, and hovered, with optional underline behavior based on the style
|
||||
* configuration.
|
||||
*
|
||||
* **Guidelines:** [on IJP SDK webhelp](https://plugins.jetbrains.com/docs/intellij/link.html#external-link-icon)
|
||||
*
|
||||
* **Usage example:**
|
||||
* [`Links.kt`](https://github.com/JetBrains/intellij-community/blob/master/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/component/Links.kt)
|
||||
*
|
||||
* **Swing equivalent:**
|
||||
* [`BrowserLink`](https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/ui/components/BrowserLink.kt)
|
||||
*
|
||||
* @param text The text to be displayed as a link
|
||||
* @param uri The actual uri that will be used to open in the browser. If it fails to open, the error is suppressed and
|
||||
* the error is logged.
|
||||
* @param modifier Modifier to be applied to the link
|
||||
* @param enabled Controls whether the link can be interacted with
|
||||
* @param textStyle The typography style to be applied to the link text
|
||||
* @param overflow How the text should handle overflow
|
||||
* @param interactionSource Source of interactions for this link
|
||||
* @param style The visual styling configuration for the link
|
||||
* @see javax.swing.JLabel
|
||||
*/
|
||||
@Composable
|
||||
public fun ExternalLink(
|
||||
text: String,
|
||||
uri: String,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
textStyle: TextStyle = JewelTheme.defaultTextStyle,
|
||||
overflow: TextOverflow = TextOverflow.Clip,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
style: LinkStyle = LocalLinkStyle.current,
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
ExternalLinkImpl(
|
||||
text = text,
|
||||
onClick = { openUri(uriHandler, uri) },
|
||||
uri = uri,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
overflow = overflow,
|
||||
interactionSource = interactionSource,
|
||||
style = style,
|
||||
textStyle = textStyle,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ExternalLinkImpl(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
uri: String,
|
||||
modifier: Modifier,
|
||||
enabled: Boolean,
|
||||
overflow: TextOverflow,
|
||||
interactionSource: MutableInteractionSource,
|
||||
style: LinkStyle,
|
||||
textStyle: TextStyle,
|
||||
) {
|
||||
val clipboard = LocalClipboard.current
|
||||
val stringProvider = LocalMessageResourceResolverProvider.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
ContextMenuArea(
|
||||
items = {
|
||||
listOf(
|
||||
ContextMenuItemOption(
|
||||
label = stringProvider.resolveIdeBundleMessage("action.text.open.link.in.browser"),
|
||||
action = { onClick() },
|
||||
icon = AllIconsKeys.Nodes.PpWeb,
|
||||
),
|
||||
ContextMenuItemOption(
|
||||
label = stringProvider.resolveIdeBundleMessage("action.text.copy.link.address"),
|
||||
action = { scope.launch { clipboard.setClipEntry(ClipEntry(StringSelection(uri))) } },
|
||||
icon = AllIconsKeys.Actions.Copy,
|
||||
),
|
||||
)
|
||||
},
|
||||
enabled = enabled,
|
||||
content = {
|
||||
LinkImpl(
|
||||
text = text,
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
overflow = overflow,
|
||||
interactionSource = interactionSource,
|
||||
style = style,
|
||||
textStyle = textStyle,
|
||||
icon = style.icons.externalLink,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun openUri(uriHandler: UriHandler, link: String) =
|
||||
try {
|
||||
uriHandler.openUri(link)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
JewelLogger.getInstance("ExternalLink").error("Unable to open link ($link). Error: $e")
|
||||
} catch (e: IOException) {
|
||||
JewelLogger.getInstance("ExternalLink").error("Unable to open link ($link). Error: $e")
|
||||
}
|
||||
|
||||
/**
|
||||
* A dropdown link that follows the standard visual styling with customizable appearance and menu content.
|
||||
*
|
||||
|
||||
@@ -166,7 +166,9 @@ public fun MenuContent(
|
||||
val selectableItems = remember(items) { items.filterIsInstance<MenuSelectableItem>() }
|
||||
|
||||
val anyItemHasIcon = remember { selectableItems.any { it.iconKey != null } }
|
||||
val anyItemHasKeybinding = remember { selectableItems.any { it.keybinding != null || it.itemOptionAction != null } }
|
||||
val anyItemHasKeybinding = remember {
|
||||
selectableItems.any { it.keybinding?.isNotEmpty() == true || it.itemOptionAction != null }
|
||||
}
|
||||
|
||||
val localMenuController = LocalMenuController.current
|
||||
val localInputModeManager = LocalInputModeManager.current
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jewel.ui.util
|
||||
|
||||
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import org.jetbrains.jewel.foundation.InternalJewelApi
|
||||
|
||||
/**
|
||||
* Interface for resolving messages from the IDE's resource bundle.
|
||||
*
|
||||
* This interface provides a mechanism to resolve strings based on a given key. It is used to fetch UI strings from the
|
||||
* IDE's internal resource bundle.
|
||||
*/
|
||||
@InternalJewelApi
|
||||
public interface MessageResourceResolver {
|
||||
/**
|
||||
* Resolves a message using the provided key.
|
||||
*
|
||||
* @param key The key representing the message to resolve.
|
||||
* @return The resolved message string associated with the provided key. If the key is not found, an empty string
|
||||
* will be returned.
|
||||
*/
|
||||
public fun resolveIdeBundleMessage(key: String): String
|
||||
}
|
||||
|
||||
public val LocalMessageResourceResolverProvider: ProvidableCompositionLocal<MessageResourceResolver> =
|
||||
staticCompositionLocalOf {
|
||||
error("No LocalMessageResourceResolverProvider provided. Have you forgotten the theme?")
|
||||
}
|
||||
Reference in New Issue
Block a user