diff --git a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppNavGraph.kt b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppNavGraph.kt index e3176ff..f14c92b 100644 --- a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppNavGraph.kt +++ b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppNavGraph.kt @@ -35,6 +35,7 @@ fun appRouteTitle(route: NativeRoute): String = when (route) { is AppRoute.ComponentMatrix -> "Component matrix" is AppRoute.InteropRepro -> "iOS interop repro" is AppRoute.InteropChurn -> "Interop churn" + is AppRoute.LiquidGlassDemo -> "Liquid glass" is AppRoute.ChromeDemo -> "Chrome demo" is AppRoute.ToolbarStyles -> "Toolbar styles" is AppRoute.ImmersiveDemo -> "Immersive" @@ -80,6 +81,7 @@ fun appNavGraph(navigator: NativeNavigator): NativeNavGraph = nativeNavGraph { onOpenComponentMatrix = { navigator.push(AppRoute.ComponentMatrix) }, onOpenInteropRepro = { navigator.push(AppRoute.InteropRepro) }, onOpenInteropChurn = { navigator.push(AppRoute.InteropChurn) }, + onOpenLiquidGlass = { navigator.push(AppRoute.LiquidGlassDemo) }, onOpenChromeDemo = { navigator.push(AppRoute.ChromeDemo) }, onOpenToolbarStyles = { navigator.push(AppRoute.ToolbarStyles) }, ) @@ -92,6 +94,7 @@ fun appNavGraph(navigator: NativeNavigator): NativeNavGraph = nativeNavGraph { screen { ImmersiveDemoScreen(onBack = { navigator.pop() }) } screen { InteropReproScreen() } screen { InteropChurnScreen() } + screen { LiquidGlassDemoScreen() } screen { ShowcaseHomeScreen(onOpenCategory = { key -> navigator.push(AppRoute.Showcase(key)) }) } diff --git a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppRoute.kt b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppRoute.kt index fec7a7c..94270c5 100644 --- a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppRoute.kt +++ b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppRoute.kt @@ -53,6 +53,11 @@ sealed interface AppRoute : NativeRoute { override val id = "debug/interop-repro" } + /** Debug screen: Liquid Glass buttons refracting live content (device-verified iOS 26 behavior). */ + data object LiquidGlassDemo : AppRoute { + override val id = "debug/liquid-glass" + } + /** Debug screen: the interop-churn regression harness (AnimatedVisibility collapse of native leaves). */ data object InteropChurn : AppRoute { override val id = "debug/interop-churn" diff --git a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppScreens.kt b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppScreens.kt index d5cbd70..279e514 100644 --- a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppScreens.kt +++ b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/AppScreens.kt @@ -30,6 +30,7 @@ fun SettingsScreen( onOpenComponentMatrix: () -> Unit = {}, onOpenInteropRepro: () -> Unit = {}, onOpenInteropChurn: () -> Unit = {}, + onOpenLiquidGlass: () -> Unit = {}, onOpenChromeDemo: () -> Unit = {}, onOpenToolbarStyles: () -> Unit = {}, ) { @@ -71,6 +72,13 @@ fun SettingsScreen( onClick = onOpenInteropRepro, ) }, + { + NativeListItem( + "Liquid glass buttons", + supporting = "Glass and prominent-glass NativeButtons refracting auto-scrolling content (iOS 26)", + onClick = onOpenLiquidGlass, + ) + }, { NativeListItem( "Interop churn test", diff --git a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/LiquidGlassDemoScreen.kt b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/LiquidGlassDemoScreen.kt new file mode 100644 index 0000000..049c05f --- /dev/null +++ b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/app/LiquidGlassDemoScreen.kt @@ -0,0 +1,92 @@ +package io.github.apdelrahman1911.nativecomposekit.app + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.graphics.Color +import androidx.compose.ui.unit.dp +import io.github.apdelrahman1911.nativecomposekit.components.NativeButton +import io.github.apdelrahman1911.nativecomposekit.components.NativeText +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeTextStyle +import kotlinx.coroutines.delay + +/** + * Debug screen: **Liquid Glass buttons over live content**. Colorful stripes auto-scroll beneath two + * floating [NativeButton]s using `ios = NativeButtonIosOptions(background = Glass / ProminentGlass)` — + * on an iOS 26 device/simulator the capsules visibly refract the stripes moving under them and morph + * on press (tap them; the toggle row is the pause switch). On Android and pre-26 iOS the same code + * renders the buttons' regular variant styling — which is exactly the documented fallback contract. + */ +@Composable +fun LiquidGlassDemoScreen(autoRun: Boolean = true) { + val stripes = listOf( + Color(0xFFE57373), Color(0xFFFFB74D), Color(0xFFFFF176), Color(0xFFAED581), + Color(0xFF4DB6AC), Color(0xFF4FC3F7), Color(0xFF7986CB), Color(0xFFBA68C8), + ) + var scrolling by remember { mutableStateOf(autoRun) } + val listState = rememberLazyListState() + LaunchedEffect(scrolling) { + while (scrolling) { + listState.animateScrollToItem(24) + delay(400) + listState.animateScrollToItem(0) + delay(400) + } + } + Box(Modifier.fillMaxSize()) { + LazyColumn( + state = listState, + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(vertical = 12.dp), + ) { + items(count = 32) { i -> + Box( + Modifier.fillMaxWidth().height(72.dp).padding(horizontal = 12.dp, vertical = 4.dp) + .background(stripes[i % stripes.size]), + contentAlignment = Alignment.Center, + ) { + NativeText("Stripe ${i + 1}", style = NativeTextStyle.Label) + } + } + } + Column( + // Clear the floating tab bar: the content inset local carries its height on iOS. + modifier = Modifier.align(Alignment.BottomCenter) + .padding(bottom = 24.dp + LocalNativeContentBottomInset.current), + verticalArrangement = Arrangement.spacedBy(12.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + NativeButton( + text = if (scrolling) "Glass — tap to pause" else "Glass — tap to scroll", + onClick = { scrolling = !scrolling }, + variant = NativeButtonVariant.Secondary, + ios = NativeButtonIosOptions(background = NativeButtonIosBackground.Glass), + ) + NativeButton( + text = "Prominent glass", + onClick = { }, + variant = NativeButtonVariant.Primary, + ios = NativeButtonIosOptions(background = NativeButtonIosBackground.ProminentGlass), + ) + } + } +} diff --git a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/showcase/categories/ButtonsShowcase.kt b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/showcase/categories/ButtonsShowcase.kt index 8b19951..94719d8 100644 --- a/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/showcase/categories/ButtonsShowcase.kt +++ b/composeApp/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/showcase/categories/ButtonsShowcase.kt @@ -24,6 +24,8 @@ import io.github.apdelrahman1911.nativecomposekit.components.NativeSplitButton import io.github.apdelrahman1911.nativecomposekit.components.feedback.LocalNativeFeedbackController import io.github.apdelrahman1911.nativecomposekit.components.feedback.NativeAlertAction import io.github.apdelrahman1911.nativecomposekit.components.feedback.NativeAlertActionRole +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonShape import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant @@ -70,6 +72,24 @@ fun ButtonsShowcase() = ShowcaseScreen( NativeButton("Destructive", { feedback.toast("Destructive") }, variant = NativeButtonVariant.Destructive) } + ExampleLabel("Liquid Glass (iOS 26)") + // iOS: a real UIGlassEffect capsule that refracts the content beneath (Automatic below + // iOS 26). Android: the ios options are a documented no-op — these render as the variant. + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + NativeButton( + "Glass", + { feedback.toast("Glass") }, + variant = NativeButtonVariant.Secondary, + ios = NativeButtonIosOptions(background = NativeButtonIosBackground.Glass), + ) + NativeButton( + "Prominent glass", + { feedback.toast("Prominent glass") }, + variant = NativeButtonVariant.Primary, + ios = NativeButtonIosOptions(background = NativeButtonIosBackground.ProminentGlass), + ) + } + ExampleLabel("Sizes") Row( modifier = Modifier.fillMaxWidth(), diff --git a/docs/components/buttons.md b/docs/components/buttons.md index 0966849..234d961 100644 --- a/docs/components/buttons.md +++ b/docs/components/buttons.md @@ -17,6 +17,33 @@ A text button with optional leading and trailing icons, an optional loading stat - The control is icon-only — use `NativeIconButton`. - You need one main action plus a related menu — use `NativeSplitButton` (a menu-bearing button's tap only opens the menu; `onClick` is not called). +#### Liquid Glass (`ios = NativeButtonIosOptions(background = …)`) + +iOS 26 introduced **Liquid Glass** — a system material that refracts the content beneath a control and +morphs on press. The button family opts in per call site through `NativeButtonIosOptions`; it is an +iOS-only appearance knob layered on the variant, never a shared abstraction: + +| `background` | iOS 26+ | iOS < 26 | Android | +|---|---|---|---| +| `Automatic` (default) | the variant's flat rendering | same | the variant's Material rendering | +| `Glass` | clear adaptive glass capsule; content uses the system label color | falls back to `Automatic` | no-op (`Automatic`) | +| `ProminentGlass` | glass tinted with the variant's **container** color; content keeps the variant's content color | falls back to `Automatic` | no-op (`Automatic`) | + +Implementation notes and constraints: + +- The glass is a **real `UIGlassEffect`** (instantiated at runtime — the class postdates the K/N + bindings), not a blur imitation. Reduce Transparency is handled by the system material itself. +- A glass button is composited **above** the Compose canvas (overlay interop placement) so the effect + can sample the content it floats over; the overlay scroll-drift trade from + [interop-notes §1](../interop-notes.md) applies while actively scrolling. +- Per the HIG, glass belongs to elements **floating above content** — action buttons over a scroll, + control strips — not to every inline form button. +- `NativeSplitButton` renders glass as `Automatic` in this release: a two-segment control needs one + *shared* glass body (`UIGlassEffectContainer` territory), and per-half capsules read wrong. The + option is accepted so call sites are forward-compatible. +- Live demo: sample app → Settings → Developer → **"Liquid glass buttons"** (glass capsules refracting + auto-scrolling stripes). + **Parameters** | Parameter | Type | Default | Description | diff --git a/docs/design-system-rules.md b/docs/design-system-rules.md index 31282c7..be1ebbd 100644 --- a/docs/design-system-rules.md +++ b/docs/design-system-rules.md @@ -51,6 +51,10 @@ Shared props where behavior aligns; a typed `ios`/`android` option object where recorded on the component's reference page. `NativeText` is the one sanctioned Compose-fallback (Compose `Text` on material surfaces, native `UILabel` on solid) — and that exception is documented, not silent. +- **Liquid Glass buttons** are the pattern in action: `ios = NativeButtonIosOptions(background = Glass)` + is an explicitly iOS-scoped knob — real `UIGlassEffect` on iOS 26, documented `Automatic` fallback + below iOS 26, documented no-op on Android. No fake cross-platform "glass" is drawn anywhere. + ## What is intentionally NOT in the kit - **`NativeImage` / image loading** → app-level via Coil 3 (rules 3 + 4). - **Wheel / `UIPickerView` picker** → covered by `NativeSegmentedControl` / `NativeMenu` / `NativeRadioGroup` / diff --git a/docs/interop-notes.md b/docs/interop-notes.md index bcf1895..650ff2e 100644 --- a/docs/interop-notes.md +++ b/docs/interop-notes.md @@ -110,6 +110,9 @@ fix (re-queue on skipped presents, no dedup of undelivered rects) is engine-leve ## Practical guidance +- Liquid Glass buttons (`ios = NativeButtonIosOptions(background = Glass/ProminentGlass)`) are + overlay-placed by construction — the glass must sit above the canvas to refract it — so the overlay + drift trade in §1 applies to them while scrolling. - Don't put many menu-bearing buttons in a long scroll if the post-open drift would be noticeable; prefer a non-menu action or present the menu from a fixed bar. - For sheet-style content use `NativeSheet` (a real `UISheetPresentationController`) rather than diff --git a/nativecomposekit/api/nativecomposekit.api b/nativecomposekit/api/nativecomposekit.api index db8e984..ba8a9b7 100644 --- a/nativecomposekit/api/nativecomposekit.api +++ b/nativecomposekit/api/nativecomposekit.api @@ -154,7 +154,7 @@ public final class io/github/apdelrahman1911/nativecomposekit/components/NativeB } public final class io/github/apdelrahman1911/nativecomposekit/components/NativeButtonKt { - public static final fun NativeButton-Ew51_bE (Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonVariant;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonSize;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonShape;ZZZLio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeMenu;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/ui/unit/Dp;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonColors;Landroidx/compose/ui/text/TextStyle;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeInteropTouch;Ljava/lang/String;Ljava/lang/String;Landroidx/compose/runtime/Composer;III)V + public static final fun NativeButton-Z13oVjI (Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonVariant;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonSize;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonShape;ZZZLio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeMenu;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/ui/unit/Dp;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonColors;Landroidx/compose/ui/text/TextStyle;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeInteropTouch;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosOptions;Ljava/lang/String;Ljava/lang/String;Landroidx/compose/runtime/Composer;III)V } public final class io/github/apdelrahman1911/nativecomposekit/components/NativeCardKt { @@ -257,7 +257,7 @@ public final class io/github/apdelrahman1911/nativecomposekit/components/NativeF } public final class io/github/apdelrahman1911/nativecomposekit/components/NativeIconButtonKt { - public static final fun NativeIconButton-j5vxNqM (Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Lkotlin/jvm/functions/Function0;Ljava/lang/String;Landroidx/compose/ui/Modifier;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonVariant;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonSize;ZZLio/github/apdelrahman1911/nativecomposekit/components/model/NativeMenu;Landroidx/compose/ui/unit/Dp;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonColors;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeInteropTouch;Ljava/lang/String;Landroidx/compose/runtime/Composer;III)V + public static final fun NativeIconButton-o_a_alY (Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Lkotlin/jvm/functions/Function0;Ljava/lang/String;Landroidx/compose/ui/Modifier;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonVariant;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonSize;ZZLio/github/apdelrahman1911/nativecomposekit/components/model/NativeMenu;Landroidx/compose/ui/unit/Dp;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonColors;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeInteropTouch;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosOptions;Ljava/lang/String;Landroidx/compose/runtime/Composer;III)V } public final class io/github/apdelrahman1911/nativecomposekit/components/NativeImePadding_androidKt { @@ -446,7 +446,7 @@ public final class io/github/apdelrahman1911/nativecomposekit/components/NativeS } public final class io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButtonKt { - public static final fun NativeSplitButton-b1Ouy7s (Ljava/lang/String;Lkotlin/jvm/functions/Function0;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeMenu;Landroidx/compose/ui/Modifier;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonVariant;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonSize;ZZLio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Landroidx/compose/ui/unit/Dp;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonColors;Landroidx/compose/ui/text/TextStyle;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeInteropTouch;Ljava/lang/String;Ljava/lang/String;Landroidx/compose/runtime/Composer;III)V + public static final fun NativeSplitButton-_w2l-jM (Ljava/lang/String;Lkotlin/jvm/functions/Function0;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeMenu;Landroidx/compose/ui/Modifier;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonVariant;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonSize;ZZLio/github/apdelrahman1911/nativecomposekit/components/model/NativeIcon;Landroidx/compose/ui/unit/Dp;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonColors;Landroidx/compose/ui/text/TextStyle;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeInteropTouch;Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosOptions;Ljava/lang/String;Ljava/lang/String;Landroidx/compose/runtime/Composer;III)V } public final class io/github/apdelrahman1911/nativecomposekit/components/NativeStepperKt { @@ -626,6 +626,25 @@ public final class io/github/apdelrahman1911/nativecomposekit/components/model/N public fun hashCode ()I } +public final class io/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground : java/lang/Enum { + public static final field Automatic Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground; + public static final field Glass Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground; + public static final field ProminentGlass Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground; + public static fun values ()[Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground; +} + +public final class io/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosOptions { + public static final field $stable I + public fun ()V + public fun (Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground;)V + public synthetic fun (Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getBackground ()Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonIosBackground; + public fun hashCode ()I +} + public final class io/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonShape : java/lang/Enum { public static final field Pill Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonShape; public static final field Rounded Lio/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonShape; diff --git a/nativecomposekit/api/nativecomposekit.klib.api b/nativecomposekit/api/nativecomposekit.klib.api index 571732a..4a1b66b 100644 --- a/nativecomposekit/api/nativecomposekit.klib.api +++ b/nativecomposekit/api/nativecomposekit.klib.api @@ -77,6 +77,18 @@ final enum class io.github.apdelrahman1911.nativecomposekit.components.feedback/ final fun values(): kotlin/Array // io.github.apdelrahman1911.nativecomposekit.components.feedback/NativeQueueBehavior.values|values#static(){}[0] } +final enum class io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground : kotlin/Enum { // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground|null[0] + enum entry Automatic // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground.Automatic|null[0] + enum entry Glass // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground.Glass|null[0] + enum entry ProminentGlass // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground.ProminentGlass|null[0] + + final val entries // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground.values|values#static(){}[0] +} + final enum class io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonShape : kotlin/Enum { // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonShape|null[0] enum entry Pill // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonShape.Pill|null[0] enum entry Rounded // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonShape.Rounded|null[0] @@ -611,6 +623,16 @@ final class io.github.apdelrahman1911.nativecomposekit.components.model/NativeBu final fun hashCode(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonColors.hashCode|hashCode(){}[0] } +final class io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions { // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions|null[0] + constructor (io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground = ...) // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions.|(io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground){}[0] + + final val background // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions.background|{}background[0] + final fun (): io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosBackground // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions.background.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions.hashCode|hashCode(){}[0] +} + final class io.github.apdelrahman1911.nativecomposekit.components.model/NativeCharacterLimit { // io.github.apdelrahman1911.nativecomposekit.components.model/NativeCharacterLimit|null[0] constructor (kotlin/Int, io.github.apdelrahman1911.nativecomposekit.components.model/NativeCharacterLimitBehavior = ...) // io.github.apdelrahman1911.nativecomposekit.components.model/NativeCharacterLimit.|(kotlin.Int;io.github.apdelrahman1911.nativecomposekit.components.model.NativeCharacterLimitBehavior){}[0] @@ -1080,6 +1102,7 @@ final val io.github.apdelrahman1911.nativecomposekit.components.feedback/io_gith final val io.github.apdelrahman1911.nativecomposekit.components.feedback/io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeFeedbackController$stableprop // io.github.apdelrahman1911.nativecomposekit.components.feedback/io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeFeedbackController$stableprop|#static{}io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeFeedbackController$stableprop[0] final val io.github.apdelrahman1911.nativecomposekit.components.feedback/io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeToastAndroidOptions$stableprop // io.github.apdelrahman1911.nativecomposekit.components.feedback/io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeToastAndroidOptions$stableprop|#static{}io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeToastAndroidOptions$stableprop[0] final val io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonColors$stableprop // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonColors$stableprop|#static{}io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonColors$stableprop[0] +final val io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonIosOptions$stableprop // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonIosOptions$stableprop|#static{}io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonIosOptions$stableprop[0] final val io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeCharacterLimit$stableprop // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeCharacterLimit$stableprop|#static{}io_github_apdelrahman1911_nativecomposekit_components_model_NativeCharacterLimit$stableprop[0] final val io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeDialogColors$stableprop // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeDialogColors$stableprop|#static{}io_github_apdelrahman1911_nativecomposekit_components_model_NativeDialogColors$stableprop[0] final val io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeFieldColors$stableprop // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeFieldColors$stableprop|#static{}io_github_apdelrahman1911_nativecomposekit_components_model_NativeFieldColors$stableprop[0] @@ -1154,6 +1177,7 @@ final fun io.github.apdelrahman1911.nativecomposekit.components.feedback/io_gith final fun io.github.apdelrahman1911.nativecomposekit.components.feedback/io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeToastAndroidOptions$stableprop_getter(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.feedback/io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeToastAndroidOptions$stableprop_getter|io_github_apdelrahman1911_nativecomposekit_components_feedback_NativeToastAndroidOptions$stableprop_getter(){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components.feedback/rememberNativeFeedbackController(androidx.compose.runtime/Composer?, kotlin/Int): io.github.apdelrahman1911.nativecomposekit.components.feedback/NativeFeedbackController // io.github.apdelrahman1911.nativecomposekit.components.feedback/rememberNativeFeedbackController|rememberNativeFeedbackController(androidx.compose.runtime.Composer?;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonColors$stableprop_getter(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonColors$stableprop_getter|io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonColors$stableprop_getter(){}[0] +final fun io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonIosOptions$stableprop_getter(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonIosOptions$stableprop_getter|io_github_apdelrahman1911_nativecomposekit_components_model_NativeButtonIosOptions$stableprop_getter(){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeCharacterLimit$stableprop_getter(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeCharacterLimit$stableprop_getter|io_github_apdelrahman1911_nativecomposekit_components_model_NativeCharacterLimit$stableprop_getter(){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeDialogColors$stableprop_getter(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeDialogColors$stableprop_getter|io_github_apdelrahman1911_nativecomposekit_components_model_NativeDialogColors$stableprop_getter(){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeFieldColors$stableprop_getter(): kotlin/Int // io.github.apdelrahman1911.nativecomposekit.components.model/io_github_apdelrahman1911_nativecomposekit_components_model_NativeFieldColors$stableprop_getter|io_github_apdelrahman1911_nativecomposekit_components_model_NativeFieldColors$stableprop_getter(){}[0] @@ -1169,7 +1193,7 @@ final fun io.github.apdelrahman1911.nativecomposekit.components.model/io_github_ final fun io.github.apdelrahman1911.nativecomposekit.components/NativeAvatar(androidx.compose.ui/Modifier?, androidx.compose.ui.graphics.painter/Painter?, kotlin/String?, androidx.compose.ui.graphics.vector/ImageVector?, io.github.apdelrahman1911.nativecomposekit.components/NativeAvatarSize?, io.github.apdelrahman1911.nativecomposekit.components/NativeAvatarShape?, androidx.compose.ui.graphics/Color?, androidx.compose.ui.graphics/Color?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeAvatar|NativeAvatar(androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.painter.Painter?;kotlin.String?;androidx.compose.ui.graphics.vector.ImageVector?;io.github.apdelrahman1911.nativecomposekit.components.NativeAvatarSize?;io.github.apdelrahman1911.nativecomposekit.components.NativeAvatarShape?;androidx.compose.ui.graphics.Color?;androidx.compose.ui.graphics.Color?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeBadge(androidx.compose.ui/Modifier?, kotlin/Int?, kotlin/Int, androidx.compose.ui.graphics/Color?, androidx.compose.ui.graphics/Color?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeBadge|NativeBadge(androidx.compose.ui.Modifier?;kotlin.Int?;kotlin.Int;androidx.compose.ui.graphics.Color?;androidx.compose.ui.graphics.Color?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeBadgedBox(kotlin/Function2, androidx.compose.ui/Modifier?, kotlin/Function3, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeBadgedBox|NativeBadgedBox(kotlin.Function2;androidx.compose.ui.Modifier?;kotlin.Function3;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] -final fun io.github.apdelrahman1911.nativecomposekit.components/NativeButton(kotlin/String, kotlin/Function0, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonVariant?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonSize?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonShape?, kotlin/Boolean, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeMenu?, androidx.compose.foundation.layout/PaddingValues?, androidx.compose.ui.unit/Dp?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonColors?, androidx.compose.ui.text/TextStyle?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeInteropTouch?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeButton|NativeButton(kotlin.String;kotlin.Function0;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonShape?;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu?;androidx.compose.foundation.layout.PaddingValues?;androidx.compose.ui.unit.Dp?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors?;androidx.compose.ui.text.TextStyle?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] +final fun io.github.apdelrahman1911.nativecomposekit.components/NativeButton(kotlin/String, kotlin/Function0, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonVariant?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonSize?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonShape?, kotlin/Boolean, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeMenu?, androidx.compose.foundation.layout/PaddingValues?, androidx.compose.ui.unit/Dp?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonColors?, androidx.compose.ui.text/TextStyle?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeInteropTouch?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeButton|NativeButton(kotlin.String;kotlin.Function0;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonShape?;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu?;androidx.compose.foundation.layout.PaddingValues?;androidx.compose.ui.unit.Dp?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors?;androidx.compose.ui.text.TextStyle?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeCard(androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components/NativeCardVariant?, kotlin/Function0?, kotlin/String?, kotlin/Function0?, kotlin/String?, kotlin/Boolean, androidx.compose.ui.unit/Dp?, androidx.compose.foundation.layout/PaddingValues?, androidx.compose.ui.graphics/Color?, androidx.compose.ui.graphics/Color?, kotlin/String?, kotlin/String?, kotlin/Function3, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeCard|NativeCard(androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.NativeCardVariant?;kotlin.Function0?;kotlin.String?;kotlin.Function0?;kotlin.String?;kotlin.Boolean;androidx.compose.ui.unit.Dp?;androidx.compose.foundation.layout.PaddingValues?;androidx.compose.ui.graphics.Color?;androidx.compose.ui.graphics.Color?;kotlin.String?;kotlin.String?;kotlin.Function3;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeCheckbox(kotlin/Boolean, kotlin/Function1?, androidx.compose.ui/Modifier?, kotlin/String?, kotlin/Boolean, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeCheckbox|NativeCheckbox(kotlin.Boolean;kotlin.Function1?;androidx.compose.ui.Modifier?;kotlin.String?;kotlin.Boolean;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeChip(kotlin/String, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components/NativeChipStyle?, kotlin/Boolean, kotlin/Function0?, kotlin/Boolean, androidx.compose.ui.graphics.vector/ImageVector?, androidx.compose.ui.graphics.vector/ImageVector?, kotlin/Function0?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeChip|NativeChip(kotlin.String;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.NativeChipStyle?;kotlin.Boolean;kotlin.Function0?;kotlin.Boolean;androidx.compose.ui.graphics.vector.ImageVector?;androidx.compose.ui.graphics.vector.ImageVector?;kotlin.Function0?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] @@ -1180,7 +1204,7 @@ final fun io.github.apdelrahman1911.nativecomposekit.components/NativeDialog(kot final fun io.github.apdelrahman1911.nativecomposekit.components/NativeDialog(kotlin/String?, kotlin/Function0, androidx.compose.ui/Modifier?, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components.model/NativeDialogColors?, androidx.compose.ui.unit/Dp?, androidx.compose.ui.unit/Dp?, androidx.compose.foundation.layout/PaddingValues?, androidx.compose.ui/Alignment.Horizontal?, androidx.compose.ui.window/DialogProperties?, kotlin/String?, kotlin/Function3?, kotlin/Function3, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeDialog|NativeDialog(kotlin.String?;kotlin.Function0;androidx.compose.ui.Modifier?;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.model.NativeDialogColors?;androidx.compose.ui.unit.Dp?;androidx.compose.ui.unit.Dp?;androidx.compose.foundation.layout.PaddingValues?;androidx.compose.ui.Alignment.Horizontal?;androidx.compose.ui.window.DialogProperties?;kotlin.String?;kotlin.Function3?;kotlin.Function3;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeDivider(androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components/NativeDividerOrientation?, androidx.compose.ui.unit/Dp, androidx.compose.ui.graphics/Color?, androidx.compose.ui.unit/Dp, androidx.compose.ui.unit/Dp, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeDivider|NativeDivider(androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.NativeDividerOrientation?;androidx.compose.ui.unit.Dp;androidx.compose.ui.graphics.Color?;androidx.compose.ui.unit.Dp;androidx.compose.ui.unit.Dp;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeEmptyState(kotlin/String, androidx.compose.ui/Modifier?, kotlin/String?, androidx.compose.ui.graphics.vector/ImageVector?, kotlin/String?, kotlin/Function0?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeEmptyState|NativeEmptyState(kotlin.String;androidx.compose.ui.Modifier?;kotlin.String?;androidx.compose.ui.graphics.vector.ImageVector?;kotlin.String?;kotlin.Function0?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] -final fun io.github.apdelrahman1911.nativecomposekit.components/NativeIconButton(io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon, kotlin/Function0, kotlin/String, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonVariant?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonSize?, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components.model/NativeMenu?, androidx.compose.ui.unit/Dp?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonColors?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeInteropTouch?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeIconButton|NativeIconButton(io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon;kotlin.Function0;kotlin.String;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize?;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu?;androidx.compose.ui.unit.Dp?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] +final fun io.github.apdelrahman1911.nativecomposekit.components/NativeIconButton(io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon, kotlin/Function0, kotlin/String, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonVariant?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonSize?, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components.model/NativeMenu?, androidx.compose.ui.unit/Dp?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonColors?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeInteropTouch?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeIconButton|NativeIconButton(io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon;kotlin.Function0;kotlin.String;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize?;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu?;androidx.compose.ui.unit.Dp?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeListItem(kotlin/String, androidx.compose.ui/Modifier?, kotlin/String?, kotlin/String?, kotlin/Function2?, kotlin/Function2?, kotlin/String?, kotlin/Function0?, kotlin/String?, kotlin/Function0?, kotlin/String?, kotlin/Boolean, kotlin/Boolean, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components/NativeSwipeAction?, kotlin/Boolean, androidx.compose.ui.unit/Dp, androidx.compose.foundation.layout/PaddingValues?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeListItem|NativeListItem(kotlin.String;androidx.compose.ui.Modifier?;kotlin.String?;kotlin.String?;kotlin.Function2?;kotlin.Function2?;kotlin.String?;kotlin.Function0?;kotlin.String?;kotlin.Function0?;kotlin.String?;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.NativeSwipeAction?;kotlin.Boolean;androidx.compose.ui.unit.Dp;androidx.compose.foundation.layout.PaddingValues?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeListSection(kotlin.collections/List>, androidx.compose.ui/Modifier?, kotlin/String?, kotlin/String?, io.github.apdelrahman1911.nativecomposekit.components/NativeListSectionStyle?, kotlin/Boolean, androidx.compose.ui.unit/Dp, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeListSection|NativeListSection(kotlin.collections.List>;androidx.compose.ui.Modifier?;kotlin.String?;kotlin.String?;io.github.apdelrahman1911.nativecomposekit.components.NativeListSectionStyle?;kotlin.Boolean;androidx.compose.ui.unit.Dp;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeLoadMoreEffect(androidx.compose.foundation.lazy.grid/LazyGridState, kotlin/Int, kotlin/Boolean, kotlin/Function0, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeLoadMoreEffect|NativeLoadMoreEffect(androidx.compose.foundation.lazy.grid.LazyGridState;kotlin.Int;kotlin.Boolean;kotlin.Function0;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] @@ -1201,7 +1225,7 @@ final fun io.github.apdelrahman1911.nativecomposekit.components/NativeSegmentedC final fun io.github.apdelrahman1911.nativecomposekit.components/NativeSheet(kotlin/Boolean, kotlin/Function0, androidx.compose.ui/Modifier?, kotlin.collections/List?, kotlin/Boolean, kotlin/String?, kotlin/Function2, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeSheet|NativeSheet(kotlin.Boolean;kotlin.Function0;androidx.compose.ui.Modifier?;kotlin.collections.List?;kotlin.Boolean;kotlin.String?;kotlin.Function2;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeSkeleton(androidx.compose.ui/Modifier?, androidx.compose.ui.graphics/Shape?, kotlin/Boolean, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeSkeleton|NativeSkeleton(androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.Shape?;kotlin.Boolean;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeSlider(kotlin/Float, kotlin/Function1, androidx.compose.ui/Modifier?, kotlin.ranges/ClosedFloatingPointRange?, kotlin/Int, kotlin/Function0?, kotlin/Boolean, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeSlider|NativeSlider(kotlin.Float;kotlin.Function1;androidx.compose.ui.Modifier?;kotlin.ranges.ClosedFloatingPointRange?;kotlin.Int;kotlin.Function0?;kotlin.Boolean;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] -final fun io.github.apdelrahman1911.nativecomposekit.components/NativeSplitButton(kotlin/String, kotlin/Function0, io.github.apdelrahman1911.nativecomposekit.components.model/NativeMenu, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonVariant?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonSize?, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon?, androidx.compose.ui.unit/Dp?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonColors?, androidx.compose.ui.text/TextStyle?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeInteropTouch?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeSplitButton|NativeSplitButton(kotlin.String;kotlin.Function0;io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize?;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon?;androidx.compose.ui.unit.Dp?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors?;androidx.compose.ui.text.TextStyle?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] +final fun io.github.apdelrahman1911.nativecomposekit.components/NativeSplitButton(kotlin/String, kotlin/Function0, io.github.apdelrahman1911.nativecomposekit.components.model/NativeMenu, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonVariant?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonSize?, kotlin/Boolean, kotlin/Boolean, io.github.apdelrahman1911.nativecomposekit.components.model/NativeIcon?, androidx.compose.ui.unit/Dp?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonColors?, androidx.compose.ui.text/TextStyle?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeInteropTouch?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeButtonIosOptions?, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeSplitButton|NativeSplitButton(kotlin.String;kotlin.Function0;io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize?;kotlin.Boolean;kotlin.Boolean;io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon?;androidx.compose.ui.unit.Dp?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors?;androidx.compose.ui.text.TextStyle?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions?;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeStepper(kotlin/Int, kotlin/Function1, androidx.compose.ui/Modifier?, kotlin/Int, kotlin/Int, kotlin/Int, kotlin/Boolean, kotlin/String?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeStepper|NativeStepper(kotlin.Int;kotlin.Function1;androidx.compose.ui.Modifier?;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Boolean;kotlin.String?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeText(kotlin/String, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeTextStyle?, androidx.compose.ui.graphics/Color, androidx.compose.ui.text.font/FontWeight?, androidx.compose.ui.text.style/TextAlign?, kotlin/Int, androidx.compose.ui.text.style/TextOverflow, androidx.compose.ui.text/TextStyle?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeText|NativeText(kotlin.String;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeTextStyle?;androidx.compose.ui.graphics.Color;androidx.compose.ui.text.font.FontWeight?;androidx.compose.ui.text.style.TextAlign?;kotlin.Int;androidx.compose.ui.text.style.TextOverflow;androidx.compose.ui.text.TextStyle?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun io.github.apdelrahman1911.nativecomposekit.components/NativeText(kotlin/String, androidx.compose.ui/Modifier?, io.github.apdelrahman1911.nativecomposekit.components.model/NativeTextStyle?, androidx.compose.ui.graphics/Color, androidx.compose.ui.text.font/FontWeight?, androidx.compose.ui.text.style/TextAlign?, kotlin/Int, androidx.compose.ui.text.style/TextOverflow?, androidx.compose.ui.text/TextStyle?, kotlin/String?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.apdelrahman1911.nativecomposekit.components/NativeText|NativeText(kotlin.String;androidx.compose.ui.Modifier?;io.github.apdelrahman1911.nativecomposekit.components.model.NativeTextStyle?;androidx.compose.ui.graphics.Color;androidx.compose.ui.text.font.FontWeight?;androidx.compose.ui.text.style.TextAlign?;kotlin.Int;androidx.compose.ui.text.style.TextOverflow?;androidx.compose.ui.text.TextStyle?;kotlin.String?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] diff --git a/nativecomposekit/src/androidUnitTest/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonsUiTest.kt b/nativecomposekit/src/androidUnitTest/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonsUiTest.kt index 3ee7551..d384f92 100644 --- a/nativecomposekit/src/androidUnitTest/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonsUiTest.kt +++ b/nativecomposekit/src/androidUnitTest/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonsUiTest.kt @@ -15,6 +15,8 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.runComposeUiTest +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions import io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon import io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu import io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenuItem @@ -37,6 +39,24 @@ import org.robolectric.annotation.Config @Config(sdk = [34]) class NativeButtonsUiTest { + @Test + fun glass_ios_options_are_a_no_op_on_android() = runComposeUiTest { + var clicks = 0 + setContent { + NativeAppearanceScope { + NativeButton( + "Glassy", + onClick = { clicks++ }, + ios = NativeButtonIosOptions(background = NativeButtonIosBackground.Glass), + ) + } + } + // Same Material rendering and semantics as any other button — the ios knob must change nothing here. + onNodeWithText("Glassy").assertIsDisplayed() + onNodeWithText("Glassy").performClick() + assertEquals(1, clicks) + } + /** Matches the node whose click action carries the given `onClickLabel`. */ private fun hasClickLabel(label: String): SemanticsMatcher = SemanticsMatcher("onClickLabel = $label") { node -> diff --git a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.kt b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.kt index f2f25ad..a7c661d 100644 --- a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.kt +++ b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.kt @@ -14,6 +14,8 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonShape import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant @@ -54,11 +56,13 @@ public fun NativeButton( colorsOverride: NativeButtonColors? = null, textStyleOverride: TextStyle? = null, touch: NativeInteropTouch = NativeInteropTouch.Cooperative, + ios: NativeButtonIosOptions = NativeButtonIosOptions(), contentDescription: String? = null, testTag: String? = null, ) { val resolved = resolveButtonStyle( variant, size, shape, enabled, contentPadding, cornerRadius, colorsOverride, textStyleOverride, + iosBackground = ios.background, ) PlatformNativeButton( text = text, @@ -87,6 +91,7 @@ private fun resolveButtonStyle( cornerRadius: Dp?, colorsOverride: NativeButtonColors?, textStyleOverride: TextStyle?, + iosBackground: NativeButtonIosBackground = NativeButtonIosBackground.Automatic, ): ResolvedButtonStyle { val tokens = NativeTheme.tokens val scheme = MaterialTheme.colorScheme @@ -142,6 +147,7 @@ private fun resolveButtonStyle( cornerRadius = resolvedCorner, iconSpacing = tokens.spacingSm, textStyle = textStyle, + iosBackground = iosBackground, ) } diff --git a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.kt b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.kt index 8660063..5394c48 100644 --- a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.kt +++ b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.kt @@ -5,6 +5,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant import io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon @@ -39,9 +41,10 @@ public fun NativeIconButton( cornerRadius: Dp? = null, colorsOverride: NativeButtonColors? = null, touch: NativeInteropTouch = NativeInteropTouch.Cooperative, + ios: NativeButtonIosOptions = NativeButtonIosOptions(), testTag: String? = null, ) { - val resolved = resolveIconButtonStyle(variant, size, enabled, cornerRadius, colorsOverride) + val resolved = resolveIconButtonStyle(variant, size, enabled, cornerRadius, colorsOverride, iosBackground = ios.background) PlatformNativeIconButton( icon = icon, onClick = onClick, @@ -63,6 +66,7 @@ private fun resolveIconButtonStyle( enabled: Boolean, cornerRadius: Dp?, colorsOverride: NativeButtonColors?, + iosBackground: NativeButtonIosBackground = NativeButtonIosBackground.Automatic, ): ResolvedButtonStyle { val tokens = NativeTheme.tokens val scheme = MaterialTheme.colorScheme @@ -81,6 +85,7 @@ private fun resolveIconButtonStyle( cornerRadius = cornerRadius ?: side / 2f, // circular by default iconSpacing = tokens.spacingSm, textStyle = MaterialTheme.typography.labelLarge.copy(color = colors.content), // unused (no label) + iosBackground = iosBackground, ) } diff --git a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.kt b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.kt index 4c3863e..33ba77d 100644 --- a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.kt +++ b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.kt @@ -7,6 +7,8 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonColors +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosOptions import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonSize import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonVariant import io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon @@ -37,10 +39,11 @@ public fun NativeSplitButton( colorsOverride: NativeButtonColors? = null, textStyleOverride: TextStyle? = null, touch: NativeInteropTouch = NativeInteropTouch.Cooperative, + ios: NativeButtonIosOptions = NativeButtonIosOptions(), contentDescription: String? = null, testTag: String? = null, ) { - val resolved = resolveSplitButtonStyle(variant, size, enabled, cornerRadius, colorsOverride, textStyleOverride) + val resolved = resolveSplitButtonStyle(variant, size, enabled, cornerRadius, colorsOverride, textStyleOverride, iosBackground = ios.background) PlatformNativeSplitButton( text = text, onPrimaryClick = onPrimaryClick, @@ -64,6 +67,7 @@ private fun resolveSplitButtonStyle( cornerRadius: Dp?, colorsOverride: NativeButtonColors?, textStyleOverride: TextStyle?, + iosBackground: NativeButtonIosBackground = NativeButtonIosBackground.Automatic, ): ResolvedButtonStyle { val tokens = NativeTheme.tokens val scheme = MaterialTheme.colorScheme @@ -97,6 +101,7 @@ private fun resolveSplitButtonStyle( cornerRadius = cornerRadius ?: tokens.cornerMedium, iconSpacing = tokens.spacingSm, textStyle = textStyle, + iosBackground = iosBackground, ) } diff --git a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonOptions.kt b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonOptions.kt new file mode 100644 index 0000000..428d68f --- /dev/null +++ b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/model/NativeButtonOptions.kt @@ -0,0 +1,38 @@ +package io.github.apdelrahman1911.nativecomposekit.components.model + +import androidx.compose.runtime.Immutable + +/** + * iOS background treatment for the button family (`NativeButton` / `NativeIconButton` / + * `NativeSplitButton`). + * + * - [Automatic] (default): the variant's regular flat rendering — exactly the pre-options appearance. + * - [Glass]: an iOS 26 **Liquid Glass** capsule — a real `UIGlassEffect` that refracts the content + * beneath the button and morphs on press. The button's content adopts the system label color (glass + * is content-adaptive by design; the variant's container/content colors don't apply). Per the HIG, + * glass belongs to elements *floating above content* (action buttons over a scroll, control strips), + * not to every inline form button. + * - [ProminentGlass]: Liquid Glass **tinted with the variant's container color** (a `Primary` button + * becomes primary-tinted glass); content keeps the variant's content color. + * + * On systems without Liquid Glass (below iOS 26) both glass values silently fall back to [Automatic]; + * with Reduce Transparency enabled, the system renders its own accessible replacement. On Android + * every value is a documented no-op — the variant renders through Material as always. + */ +public enum class NativeButtonIosBackground { Automatic, Glass, ProminentGlass } + +/** + * iOS-only knobs for the button family. Each is a documented no-op on Android. Lives in + * `components.model` beside [NativeSearchBarIosOptions] so the `*IosOptions` types share one import + * surface. Compares by value. + */ +@Immutable +public class NativeButtonIosOptions( + /** See [NativeButtonIosBackground]. */ + public val background: NativeButtonIosBackground = NativeButtonIosBackground.Automatic, +) { + override fun equals(other: Any?): Boolean = + this === other || (other is NativeButtonIosOptions && background == other.background) + + override fun hashCode(): Int = background.hashCode() +} diff --git a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/model/ResolvedStyles.kt b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/model/ResolvedStyles.kt index 5ae218d..04568f2 100644 --- a/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/model/ResolvedStyles.kt +++ b/nativecomposekit/src/commonMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/model/ResolvedStyles.kt @@ -50,6 +50,8 @@ internal data class ResolvedButtonStyle( /** Gap between a leading/trailing icon and the label (from NativeTokens.spacingSm). */ val iconSpacing: Dp, val textStyle: TextStyle, + /** iOS background treatment (Liquid Glass opt-in); Android and pre-26 iOS render [NativeButtonIosBackground.Automatic]. */ + val iosBackground: NativeButtonIosBackground = NativeButtonIosBackground.Automatic, ) /** diff --git a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.ios.kt b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.ios.kt index 04017f0..c31de76 100644 --- a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.ios.kt +++ b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButton.ios.kt @@ -10,6 +10,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.UIKitView import androidx.compose.ui.viewinterop.remeasureRequester import androidx.compose.ui.viewinterop.rememberUIKitInteropRemeasureRequester +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import platform.UIKit.UIColor import io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon import io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch import io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu @@ -59,6 +61,9 @@ internal actual fun PlatformNativeButton( val backingColor = interopBackingColor() // published surface on solid; clear on Liquid Glass // Overlay placement inside a NativeDialog (no cut-out hole → no first-frame black flash); cut-out elsewhere. val overlay = LocalNativeInteropPlacement.current == NativeInteropPlacement.Overlay + // Liquid Glass must composite ABOVE the canvas: its backdrop sampling refracts the Compose content + // there; behind the canvas (cut-out) it would sample the empty backdrop. Backing goes clear too. + val glassActive = style.iosBackground != NativeButtonIosBackground.Automatic && nativeGlassAvailable() // Trailing glyph is an explicit trailing icon, or the auto chevron for a menu button. val trailGlyph = trailingIcon?.sfSymbolName ?: if (menu != null) "chevron.down" else null @@ -95,9 +100,9 @@ internal actual fun PlatformNativeButton( backing }, modifier = m.remeasureRequester(remeasure).then(rememberInteropPositionHeal(backing)), - properties = touch.toInteropProperties(overlay = overlay, nativeAccessibility = true), + properties = touch.toInteropProperties(overlay = overlay || glassActive, nativeAccessibility = true), update = { _ -> - backing.backgroundColor = backingColor + backing.backgroundColor = if (glassActive) UIColor.clearColor() else backingColor views.apply( style = style, text = if (loading) "" else text, diff --git a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonInterop.ios.kt b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonInterop.ios.kt index 03f43c3..3bf0e56 100644 --- a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonInterop.ios.kt +++ b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeButtonInterop.ios.kt @@ -4,7 +4,17 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.isSpecified import io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu import platform.UIKit.UIMenu +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground import io.github.apdelrahman1911.nativecomposekit.components.model.ResolvedButtonStyle +import platform.Foundation.NSClassFromString +import platform.Foundation.NSNumber +import platform.Foundation.NSSelectorFromString +import platform.Foundation.numberWithBool +import platform.Foundation.performSelector +import platform.Foundation.setValue +import platform.UIKit.UIVisualEffect +import platform.UIKit.UIVisualEffectView +import platform.UIKit.labelColor import kotlinx.cinterop.BetaInteropApi import kotlinx.cinterop.CValue import kotlinx.cinterop.ExperimentalForeignApi @@ -51,12 +61,41 @@ internal class ButtonTapHandler : NSObject() { * TouchUpInside into one frame, so an instant set/reset would be invisible. Forcing the pressed state in * [pressUp] and animating back guarantees a visible pop for any tap speed (and a held press still dims). */ + +/** Liquid Glass exists on this system (iOS 26+). Cheap runtime class lookup — the kit has no SDK gate. */ +internal fun nativeGlassAvailable(): Boolean = NSClassFromString("UIGlassEffect") != null + +/** + * Builds a `UIGlassEffect` at runtime — the class is newer than the Kotlin/Native UIKit bindings, so it + * is looked up by name, instantiated by sending `new` to the class object, and used through the bound + * `UIVisualEffect` supertype (device-verified: the effect refracts the Compose canvas through an + * overlay-placed interop view). `interactive` gives the system press morph; [tint] makes it the + * "prominent" tinted flavor. Returns null below iOS 26 — callers fall back to the flat style. + */ +@OptIn(ExperimentalForeignApi::class) +internal fun nativeGlassEffect(tint: UIColor?): UIVisualEffect? { + val cls = NSClassFromString("UIGlassEffect") ?: return null + val clsObj = cls as? NSObject ?: return null + val effect = clsObj.performSelector(NSSelectorFromString("new")) as? UIVisualEffect ?: return null + if (effect.respondsToSelector(NSSelectorFromString("setInteractive:"))) { + effect.setValue(NSNumber.numberWithBool(true), forKey = "interactive") + } + if (tint != null && effect.respondsToSelector(NSSelectorFromString("setTintColor:"))) { + effect.setValue(tint, forKey = "tintColor") + } + return effect +} + @OptIn(BetaInteropApi::class, ExperimentalForeignApi::class) internal class ButtonPressDimmer : NSObject() { var target: UIView? = null + /** True while a Liquid Glass backdrop is active — the interactive glass owns press feedback. */ + var suppressed: Boolean = false + @ObjCAction fun pressDown() { + if (suppressed) return val v = target ?: return UIView.animateWithDuration(0.09, animations = { v.transform = CGAffineTransformMakeScale(0.96, 0.96) @@ -66,6 +105,7 @@ internal class ButtonPressDimmer : NSObject() { @ObjCAction fun pressUp() { + if (suppressed) return val v = target ?: return // Ensure the pressed state is applied, then animate back — so an instant tap still shows the pop. v.transform = CGAffineTransformMakeScale(0.96, 0.96) @@ -232,6 +272,53 @@ internal class NativeButtonViews { * Re-theme and set state. [showLabel] is false for icon-only buttons. [leadName]/[trailName] are SF * Symbol names (null = hidden). When [menu] is non-null the button presents it as its primary action. */ + private var glassView: UIVisualEffectView? = null + private var glassSpec: String? = null + + /** + * Installs/updates/removes the Liquid Glass backdrop behind the content stack. The effect view sits + * at index 0 inside the button (below the `[icon|label|icon]` stack), non-interactive so touches + * reach the button, clipped to the button's corner radius; the effect object is rebuilt only when + * the requested flavor/tint changes (effects are copied on assignment — mutating a live one is not + * reliable). + */ + private fun applyGlassBackdrop(style: ResolvedButtonStyle, active: Boolean) { + if (!active) { + glassView?.removeFromSuperview() + glassView = null + glassSpec = null + return + } + val prominent = style.iosBackground == NativeButtonIosBackground.ProminentGlass + val spec = if (prominent) "prominent:${style.colors.container.value}" else "glass" + if (glassSpec != spec) { + glassView?.removeFromSuperview() + glassView = null + glassSpec = null + val effect = nativeGlassEffect( + tint = if (prominent) style.colors.container.toUIColor() else null, + ) ?: return + val gv = UIVisualEffectView(effect = effect) + gv.userInteractionEnabled = false + gv.translatesAutoresizingMaskIntoConstraints = false + button.insertSubview(gv, atIndex = 0) + NSLayoutConstraint.activateConstraints( + listOf( + gv.leadingAnchor.constraintEqualToAnchor(button.leadingAnchor), + gv.trailingAnchor.constraintEqualToAnchor(button.trailingAnchor), + gv.topAnchor.constraintEqualToAnchor(button.topAnchor), + gv.bottomAnchor.constraintEqualToAnchor(button.bottomAnchor), + ), + ) + glassView = gv + glassSpec = spec + } + glassView?.let { + it.layer.cornerRadius = style.cornerRadius.value.toDouble() + it.clipsToBounds = true + } + } + fun apply( style: ResolvedButtonStyle, text: String, @@ -242,17 +329,34 @@ internal class NativeButtonViews { trailName: String?, menu: NativeMenu?, ) { - val content = style.colors.content.toUIColor() + val glassActive = style.iosBackground != NativeButtonIosBackground.Automatic && nativeGlassAvailable() + applyGlassBackdrop(style, glassActive) + dimmer.suppressed = glassActive // interactive glass owns press feedback + + // Clear glass is content-adaptive: the system label color reads on whatever is refracted. + // Prominent (tinted) glass keeps the variant's content color on its tinted body. + val content = + if (glassActive && style.iosBackground == NativeButtonIosBackground.Glass) UIColor.labelColor() + else style.colors.content.toUIColor() val transparent = style.colors.container == Color.Transparent - button.backgroundColor = if (transparent) UIColor.clearColor() else style.colors.container.toUIColor() - button.layer.cornerRadius = style.cornerRadius.value.toDouble() - button.clipsToBounds = true - if (style.colors.border.isSpecified) { - button.layer.borderWidth = 1.0 - button.layer.borderColor = style.colors.border.toUIColor().CGColor - } else { + if (glassActive) { + button.backgroundColor = UIColor.clearColor() + // The glass lens highlight paints just past the capsule edge — clipping the button would + // shave it; the effect view itself is clipped to the corner radius instead. + button.clipsToBounds = false + button.layer.cornerRadius = 0.0 button.layer.borderWidth = 0.0 + } else { + button.backgroundColor = if (transparent) UIColor.clearColor() else style.colors.container.toUIColor() + button.layer.cornerRadius = style.cornerRadius.value.toDouble() + button.clipsToBounds = true + if (style.colors.border.isSpecified) { + button.layer.borderWidth = 1.0 + button.layer.borderColor = style.colors.border.toUIColor().CGColor + } else { + button.layer.borderWidth = 0.0 + } } leadingConstraint?.setConstant(style.insets.start.value.toDouble()) diff --git a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.ios.kt b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.ios.kt index 16fdaaa..306585d 100644 --- a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.ios.kt +++ b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeIconButton.ios.kt @@ -9,6 +9,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.UIKitView import androidx.compose.ui.viewinterop.remeasureRequester import androidx.compose.ui.viewinterop.rememberUIKitInteropRemeasureRequester +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground +import platform.UIKit.UIColor import io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon import io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch import io.github.apdelrahman1911.nativecomposekit.components.model.NativeMenu @@ -47,6 +49,9 @@ internal actual fun PlatformNativeIconButton( val remeasure = rememberUIKitInteropRemeasureRequester() // Overlay placement inside a NativeDialog (no cut-out hole → no first-frame black flash); cut-out elsewhere. val overlay = LocalNativeInteropPlacement.current == NativeInteropPlacement.Overlay + // Liquid Glass must composite ABOVE the canvas: its backdrop sampling refracts the Compose content + // there; behind the canvas (cut-out) it would sample the empty backdrop. Backing goes clear too. + val glassActive = style.iosBackground != NativeButtonIosBackground.Automatic && nativeGlassAvailable() // HIG: ≥44pt touch target. A compact visual keeps its true size, centered in a 44pt host square, // with MinHitButton accepting taps in the surrounding margin. @@ -86,9 +91,9 @@ internal actual fun PlatformNativeIconButton( backing }, modifier = modifier.size(if (compact) minTouch else style.height).remeasureRequester(remeasure).then(rememberInteropPositionHeal(backing)), - properties = touch.toInteropProperties(overlay = overlay, nativeAccessibility = true), + properties = touch.toInteropProperties(overlay = overlay || glassActive, nativeAccessibility = true), update = { _ -> - backing.backgroundColor = backingColor + backing.backgroundColor = if (glassActive) UIColor.clearColor() else backingColor views.apply( style = style, text = "", diff --git a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.ios.kt b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.ios.kt index 48c4f46..4edddd3 100644 --- a/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.ios.kt +++ b/nativecomposekit/src/iosMain/kotlin/io/github/apdelrahman1911/nativecomposekit/components/NativeSplitButton.ios.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.viewinterop.UIKitView import androidx.compose.ui.viewinterop.remeasureRequester import androidx.compose.ui.viewinterop.rememberUIKitInteropRemeasureRequester +import io.github.apdelrahman1911.nativecomposekit.components.model.NativeButtonIosBackground import io.github.apdelrahman1911.nativecomposekit.components.model.NativeIcon import io.github.apdelrahman1911.nativecomposekit.theme.LocalNativeStrings import io.github.apdelrahman1911.nativecomposekit.components.model.NativeInteropTouch @@ -59,6 +60,10 @@ internal actual fun PlatformNativeSplitButton( val backingColor = interopBackingColor() // published surface on solid; clear on Liquid Glass val remeasure = rememberUIKitInteropRemeasureRequester() // Overlay placement inside a NativeDialog (no cut-out hole → no first-frame black flash); cut-out elsewhere. + // Split renders `ios.background` as Automatic in this release: a two-segment capsule needs a SHARED + // glass body (UIGlassEffectContainer territory), and per-half capsules read wrong. Documented in + // docs/components/buttons.md; the option stays accepted so call sites are forward-compatible. + @Suppress("NAME_SHADOWING") val style = style.copy(iosBackground = NativeButtonIosBackground.Automatic) val overlay = LocalNativeInteropPlacement.current == NativeInteropPlacement.Overlay val layoutDirection = LocalLayoutDirection.current val moreLabel = LocalNativeStrings.current.splitButtonMore