buildBlueskyAnnotatedString

fun buildBlueskyAnnotatedString(text: String, facets: List<Facet>?, styleMapper: (feature: FacetFeaturesUnion) -> SpanStyle): AnnotatedString

Render Bluesky post text + facets as an AnnotatedString, with styling controlled by the consumer's styleMapper.

This is the 80% case in the Compose helper. It wraps the lower-level appendBlueskyText primitive with sensible defaults:

  • Each facet's char range is decorated with SpanStyle returned by styleMapper, so the consumer's design system stays in control of colors, weights, and decorations.

  • #link facets are attached via Compose 1.7+ LinkAnnotation.Url, so Text(annotated) opens the URL via the OS browser intent without any consumer-side click wiring. To use Custom Tabs or another in-app browser, override the click via Text(...)'s standard LinkInteractionListener parameter.

  • #mention facets attach a String annotation under ANNOTATION_TAG_MENTION whose value is the mentioned account's DID raw string. Click handlers extract via annotated.getStringAnnotations(ANNOTATION_TAG_MENTION, offset, offset).

  • #tag facets attach a String annotation under ANNOTATION_TAG_TAG whose value is the bare tag string.

  • FacetFeaturesUnion.Unknown variants are silently skipped, so the text remains readable when the upstream lexicon adds a new facet feature kind.

UTF-8 byte-to-UTF-16 char index mapping is bullet-proof across emoji, multi-byte CJK, and combining marks. Malformed facets are silently dropped — the helper never throws.

Material 3 consumers should prefer rememberBlueskyAnnotatedString from the :compose-material3 artifact, which defaults styleMapper to a SpanStyle colored by the current MaterialTheme.colorScheme.primary.

Parameters

text

the post's plain text.

facets

the post record's facets (may be null).

styleMapper

produces a SpanStyle for each facet feature variant. Receives the typed sealed parent so when is exhaustive and IDE-completable.