Implement issue #58: text styling + TextField config#110
Merged
jonathanpeppers merged 2 commits intoJun 6, 2026
Conversation
Adds the missing Material 3 Text styling parameters (color, italic, font family, alignment, overflow, max/min lines, soft wrap) and the missing TextField configuration parameters (label, placeholder, leading/trailing icons, prefix/suffix, supportingText, isError, enabled, readOnly, singleLine, max/min lines). Generator changes ----------------- ComposeBridgeGenerator + ComposeFacadeGenerator now recognize nullable primitives (`bool?`, `int?`, `long?`, `float?`, `double?`). At the bridge level they lower to `(name ?? defaultLiteral)` so a `null` clears the corresponding `$default` bit and Kotlin's default runs; at the facade level they surface as nullable auto-properties (parity with existing nullable Compose value types like `Dp?`/`Sp?`). New types --------- * `FontStyle` — `Java.Lang.Object` subclass exposing `Normal`/`Italic` via Kotlin's mangled inline-class accessor (`getNormal-_-LCdwA()I`) + synthesized `box-impl(int) -> FontStyle` static, then handed to the bridge as a boxed reference (slot `L`). Material 3 declares every `fontStyle:` slot as nullable, which forces the inline class to box at the JNI boundary. * `TextOverflow` — value struct (slot `I`, packed). Compose declares `overflow:` as non-nullable so it travels as a raw `int`. * `FontFamily` — `Java.Lang.Object` subclass exposing `Default`, `SansSerif`, `Serif`, `Monospace`, `Cursive`. Each companion getter has its own concrete return descriptor (`SystemFontFamily` for Default, `GenericFontFamily` for the rest) that we resolve individually. * `TextAlign` — converted from value struct to `Java.Lang.Object` subclass, same shape as `FontStyle` (mangled `getCenter-e0LSkKk()I` + `box-impl`). Same nullable-in-source reason for the boxed lowering. Bridge expansions ----------------- `Text` gains: `color`, `fontStyle`, `fontFamily`, `align`, `overflow`, `softWrap`, `maxLines`, `minLines`. `TextField` and `OutlinedTextField` each gain: `enabled`, `readOnly`, `label`, `placeholder`, `leadingIcon`, `trailingIcon`, `prefix`, `suffix`, `supportingText`, `isError`, `singleLine`, `maxLines`, `minLines`. The matching `[ComposeDefaults]` declarations already had every bit position named; no `ComposeDefaults.cs` changes were needed. Sample ------ `MainActivity.cs` (Greeting tab) now demos the new styling — color + italic serif center-aligned text, monospace end-aligned text, ellipsis clipping with `MaxLines = 1`, two-line clamp with reserved height, plus a `TextField` and `OutlinedTextField` exercising the new slots (label, placeholder, leading/trailing icons, prefix/suffix, supportingText). Deferred (blocked or out of scope) ---------------------------------- * `KeyboardOptions` / `KeyboardActions` — `KeyboardOptions` ctor is stripped from the binding (inline-class params: `KeyboardType`, `ImeAction`, `KeyboardCapitalization`); needs a `[ComposeBridge(JvmName="<init>")]` follow-up. * `VisualTransformation`, `AnnotatedString`, `TextStyle`, `LinkAnnotation` — all in `androidx.compose.ui.text.input` / `androidx.compose.ui.text`, still 0 exported types until the next Compose package release post `dotnet/android-libraries#1440`. * `BasicText` / `BasicTextField` / `LocalTextStyle` / `FocusRequester` — separate facades; out of scope. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Implements most of issue #58 by extending the ComposeNet facade to expose additional Text styling knobs and TextField/OutlinedTextField configuration slots, supported by source-generator updates that broaden what parameter shapes can be expressed as optional/defaultable Kotlin parameters.
Changes:
- Extend
ComposeBridgeGenerator/ComposeFacadeGeneratorto recognize nullable primitives (bool?,int?,long?,float?,double?) as “optional” defaultable parameters. - Add new text-related wrapper types (
FontFamily,FontStyle,TextOverflow) and migrateTextAlignto a boxed reference wrapper to match Compose’s nullable inline-class usage. - Update sample + generator tests + public API tracking to cover the new surface area.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ComposeNet.SourceGenerators/ComposeValueTypes.cs | Updates recognized packed value-type registry (adds TextOverflow, removes packed TextAlign). |
| src/ComposeNet.SourceGenerators/ComposeReferenceTypes.cs | Adds new reference-wrapper types (FontFamily, FontStyle, TextAlign) to the facade classification registry. |
| src/ComposeNet.SourceGenerators/ComposeFacadeGenerator.cs | Classifies nullable primitives as optional-value facade properties (doc comment needs a small update). |
| src/ComposeNet.SourceGenerators/ComposeBridgeGenerator.cs | Lowers nullable primitives via ?? zero-literals and updates default-bit clearing (comment needs a small update). |
| src/ComposeNet.SourceGenerators.Tests/FacadeGeneratorTests.cs | Adds coverage for nullable primitives and TextOverflow optional-value classification. |
| src/ComposeNet.SourceGenerators.Tests/BridgeGeneratorTests.cs | Adds coverage for nullable primitive lowering + packed TextOverflow lowering. |
| src/ComposeNet.Sample/MainActivity.cs | Demonstrates new Text styling and TextField slot properties (one comment needs a small wording correction). |
| src/ComposeNet.Compose/TextOverflow.cs | Introduces packed TextOverflow value wrapper and constants. |
| src/ComposeNet.Compose/TextAlign.cs | Migrates TextAlign from packed struct to boxed JNI-backed reference wrapper. |
| src/ComposeNet.Compose/PublicAPI.Unshipped.txt | Updates tracked public API for new types/properties and the TextAlign shape change. |
| src/ComposeNet.Compose/FontStyle.cs | Adds boxed JNI-backed FontStyle wrapper with companion constant resolution. |
| src/ComposeNet.Compose/FontFamily.cs | Adds JNI-backed FontFamily wrapper with companion constant resolution. |
| src/ComposeNet.Compose/ComposeBridges.cs | Extends bridge/facade signatures for Text, TextField, and OutlinedTextField to include new parameters/slots. |
- ComposeFacadeGenerator: doc comment for IsOptionalValueType now lists TextOverflow under packed @JvmInline value classes, and spells out which wrappers live in ComposeReferenceTypes (FontWeight/FontStyle/FontFamily/TextAlign/...). - ComposeBridgeGenerator: NeedsKeepAlive comment swaps the stale TextAlign mention for TextOverflow now that TextAlign is a reference wrapper. - MainActivity sample comment: clarifies that the issue #58 styling set spans three generator paths (nullable primitive, nullable reference wrapper, packed value class) instead of just one. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #58 (the bulk of it — see Deferred at the bottom for the remainder).
What ships
New
TextpropertiesColor,FontStyle,FontFamily,Align,Overflow,SoftWrap,MaxLines,MinLines.New
TextField/OutlinedTextFieldslotsEnabled,ReadOnly,Label,Placeholder,LeadingIcon,TrailingIcon,Prefix,Suffix,SupportingText,IsError,SingleLine,MaxLines,MinLines.Generator changes
ComposeBridgeGeneratorandComposeFacadeGeneratornow recognize nullable primitives (bool?,int?,long?,float?,double?). At the bridge level these lower to(name ?? defaultLiteral)so anullclears the corresponding$defaultbit and Kotlin's default runs; at the facade level they surface as nullable auto-properties — parity with existing nullable Compose value types likeDp?/Sp?. Three tests cover the new behaviour (one bridge, one facade, one mixed).New wrapper types
FontStyleL)@JvmInline value classbut Compose declaresfontStyle:nullable, which boxesFontFamilyL)TextOverflowint(slotI)@JvmInline value class, declared non-nullable in ComposeTextAlignL) — breaking change, was a value structFontStyleFontStyleandTextAlignreach Compose's companion via the mangled inline-class accessors (getCenter-e0LSkKk()I,getNormal-_-LCdwA()I) and box through the synthesizedbox-impl(I)L<Type>;static.FontFamily's companion getters return concrete subtypes (SystemFontFamily/GenericFontFamily) so each call uses its exact descriptor. All names verified againstui-text-android1.11.2.1 bytecode.Sample
The Greeting tab in
MainActivity.csnow demos the new styling — color + italic serif center-aligned text, monospace end-aligned text, ellipsis clipping withMaxLines = 1, two-line clamp with reserved height, plus aTextFieldandOutlinedTextFieldexercising the new slots.Verification
dotnet test src/ComposeNet.SourceGenerators.Tests— 83/83 passingdotnet build src/ComposeNet.Compose— clean (PublicAPI.Unshipped.txtupdated)dotnet build src/ComposeNet.Sample— cleanDeferred (blocked or out of scope)
KeyboardOptions/KeyboardActions—KeyboardOptionsctor is stripped from the binding (inline-class params:KeyboardType,ImeAction,KeyboardCapitalization); needs a[ComposeBridge(JvmName="<init>")]follow-up.VisualTransformation,AnnotatedString,TextStyle,LinkAnnotation— all inandroidx.compose.ui.text.input/androidx.compose.ui.text, still 0 exported types until the next Compose package release post dotnet/android-libraries#1440 (merged but not yet shipped).BasicText/BasicTextField/LocalTextStyle/FocusRequester— separate facades; out of scope here.Breaking change
TextAlignis no longer arecord struct. Callers that previously used thePackstatic,Equals/Deconstruct, or accessedValuedirectly will need to migrate; theTextAlign.Left/Right/Center/Justify/Start/End/Unspecifiedaccessors are unchanged in name and still typedTextAlign.Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>