or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composables.mdcore-ui.mdgraphics.mdindex.mdinput.mdios-integration.mdlayout.mdmaterial-design.mdresources.mdstate.mdtext.mdwindow.md

text.mddocs/

0

# Text Handling and Typography

1

2

Complete text system with styling, input capabilities, and internationalization support for creating rich text experiences across all platforms.

3

4

## Capabilities

5

6

### Text Styling

7

8

Comprehensive text appearance configuration system supporting fonts, colors, spacing, and advanced typography features.

9

10

```kotlin { .api }

11

/**

12

* Configuration object to define the styling of text content.

13

*/

14

@Immutable

15

data class TextStyle(

16

val color: Color = Color.Unspecified,

17

val fontSize: TextUnit = TextUnit.Unspecified,

18

val fontWeight: FontWeight? = null,

19

val fontStyle: FontStyle? = null,

20

val fontSynthesis: FontSynthesis? = null,

21

val fontFamily: FontFamily? = null,

22

val fontFeatureSettings: String? = null,

23

val letterSpacing: TextUnit = TextUnit.Unspecified,

24

val baselineShift: BaselineShift? = null,

25

val textGeometricTransform: TextGeometricTransform? = null,

26

val localeList: LocaleList? = null,

27

val background: Color = Color.Unspecified,

28

val textDecoration: TextDecoration? = null,

29

val shadow: Shadow? = null,

30

val textAlign: TextAlign? = null,

31

val textDirection: TextDirection? = null,

32

val lineHeight: TextUnit = TextUnit.Unspecified,

33

val textIndent: TextIndent? = null,

34

val platformStyle: PlatformTextStyle? = null,

35

val lineHeightStyle: LineHeightStyle? = null,

36

val lineBreak: LineBreak? = null,

37

val hyphens: Hyphens? = null

38

) {

39

/**

40

* Returns a new text style that is a combination of this style and the given other style.

41

*/

42

fun merge(other: TextStyle? = null): TextStyle

43

44

/**

45

* Plus operator overload that applies a merge.

46

*/

47

operator fun plus(other: TextStyle): TextStyle

48

49

/**

50

* Returns a copy of this TextStyle with the given values replaced.

51

*/

52

fun copy(

53

color: Color = this.color,

54

fontSize: TextUnit = this.fontSize,

55

fontWeight: FontWeight? = this.fontWeight,

56

fontStyle: FontStyle? = this.fontStyle,

57

fontSynthesis: FontSynthesis? = this.fontSynthesis,

58

fontFamily: FontFamily? = this.fontFamily,

59

fontFeatureSettings: String? = this.fontFeatureSettings,

60

letterSpacing: TextUnit = this.letterSpacing,

61

baselineShift: BaselineShift? = this.baselineShift,

62

textGeometricTransform: TextGeometricTransform? = this.textGeometricTransform,

63

localeList: LocaleList? = this.localeList,

64

background: Color = this.background,

65

textDecoration: TextDecoration? = this.textDecoration,

66

shadow: Shadow? = this.shadow,

67

textAlign: TextAlign? = this.textAlign,

68

textDirection: TextDirection? = this.textDirection,

69

lineHeight: TextUnit = this.lineHeight,

70

textIndent: TextIndent? = this.textIndent,

71

platformStyle: PlatformTextStyle? = this.platformStyle,

72

lineHeightStyle: LineHeightStyle? = this.lineHeightStyle,

73

lineBreak: LineBreak? = this.lineBreak,

74

hyphens: Hyphens? = this.hyphens

75

): TextStyle

76

77

companion object {

78

/**

79

* Constant for default text style.

80

*/

81

val Default: TextStyle

82

}

83

}

84

85

/**

86

* Font weight values from thin to black.

87

*/

88

@Immutable

89

class FontWeight private constructor(val weight: Int) : Comparable<FontWeight> {

90

override fun compareTo(other: FontWeight): Int

91

92

companion object {

93

val Thin: FontWeight // 100

94

val ExtraLight: FontWeight // 200

95

val Light: FontWeight // 300

96

val Normal: FontWeight // 400

97

val Medium: FontWeight // 500

98

val SemiBold: FontWeight // 600

99

val Bold: FontWeight // 700

100

val ExtraBold: FontWeight // 800

101

val Black: FontWeight // 900

102

103

/**

104

* Create a FontWeight with a specific weight value.

105

*/

106

fun W100: FontWeight

107

fun W200: FontWeight

108

fun W300: FontWeight

109

fun W400: FontWeight

110

fun W500: FontWeight

111

fun W600: FontWeight

112

fun W700: FontWeight

113

fun W800: FontWeight

114

fun W900: FontWeight

115

}

116

}

117

118

/**

119

* Font style enumeration for normal and italic text.

120

*/

121

enum class FontStyle(val value: Int) {

122

Normal(0), Italic(1)

123

}

124

125

/**

126

* Font synthesis options for generating synthetic font variants.

127

*/

128

@Immutable

129

class FontSynthesis private constructor(val value: Int) {

130

companion object {

131

val None: FontSynthesis

132

val All: FontSynthesis

133

val Weight: FontSynthesis

134

val Style: FontSynthesis

135

}

136

}

137

```

138

139

**Usage Examples:**

140

141

```kotlin

142

// Basic text styling

143

val titleStyle = TextStyle(

144

fontSize = 24.sp,

145

fontWeight = FontWeight.Bold,

146

color = Color.Black,

147

letterSpacing = 0.5.sp

148

)

149

150

val bodyStyle = TextStyle(

151

fontSize = 16.sp,

152

fontWeight = FontWeight.Normal,

153

lineHeight = 24.sp,

154

color = Color.DarkGray

155

)

156

157

// Merging styles

158

val emphasisStyle = bodyStyle.copy(

159

fontWeight = FontWeight.SemiBold,

160

fontStyle = FontStyle.Italic

161

)

162

163

// Using styles in Text composables

164

Text(

165

text = "Hello, World!",

166

style = titleStyle

167

)

168

169

Text(

170

text = "This is body text with custom styling.",

171

style = bodyStyle.merge(

172

TextStyle(textDecoration = TextDecoration.Underline)

173

)

174

)

175

```

176

177

### Font Management

178

179

Font family definition and loading system supporting platform-specific fonts and custom font resources.

180

181

```kotlin { .api }

182

/**

183

* The base class of font families.

184

*/

185

abstract class FontFamily(

186

val canLoadSynchronously: Boolean

187

) {

188

companion object {

189

/**

190

* The platform default font.

191

*/

192

val Default: SystemFontFamily

193

194

/**

195

* Generic serif font family.

196

*/

197

val Serif: GenericFontFamily

198

199

/**

200

* Generic sans-serif font family.

201

*/

202

val SansSerif: GenericFontFamily

203

204

/**

205

* Generic monospace font family.

206

*/

207

val Monospace: GenericFontFamily

208

209

/**

210

* Generic cursive font family.

211

*/

212

val Cursive: GenericFontFamily

213

}

214

}

215

216

/**

217

* Defines a font family with explicitly defined fonts.

218

*/

219

class FontFamily private constructor(

220

val fonts: List<Font>

221

) : FontFamily(false) {

222

constructor(vararg fonts: Font) : this(fonts.toList())

223

constructor(font: Font) : this(listOf(font))

224

}

225

226

/**

227

* Base class for font definitions.

228

*/

229

abstract class Font {

230

/**

231

* The weight of the font.

232

*/

233

abstract val weight: FontWeight

234

235

/**

236

* The style of the font.

237

*/

238

abstract val style: FontStyle

239

240

/**

241

* Load result for font loading.

242

*/

243

sealed class LoadResult {

244

class Success(val typeface: Any) : LoadResult()

245

class Failure(val exception: Exception) : LoadResult()

246

}

247

}

248

249

/**

250

* Create a font from a resource.

251

*/

252

expect fun Font(

253

resId: Int,

254

weight: FontWeight = FontWeight.Normal,

255

style: FontStyle = FontStyle.Normal

256

): Font

257

258

/**

259

* Create a font from a file path.

260

*/

261

expect fun Font(

262

path: String,

263

weight: FontWeight = FontWeight.Normal,

264

style: FontStyle = FontStyle.Normal

265

): Font

266

267

/**

268

* Create a font from byte array.

269

*/

270

expect fun Font(

271

data: ByteArray,

272

weight: FontWeight = FontWeight.Normal,

273

style: FontStyle = FontStyle.Normal

274

): Font

275

276

/**

277

* Font loading with suspending functions.

278

*/

279

@Composable

280

fun rememberFontFamily(vararg fonts: Font): State<FontFamily?>

281

```

282

283

**Usage Examples:**

284

285

```kotlin

286

// Using system font families

287

val titleFamily = FontFamily.Serif

288

val bodyFamily = FontFamily.SansSerif

289

val codeFamily = FontFamily.Monospace

290

291

// Creating custom font family (platform-specific)

292

val customFontFamily = FontFamily(

293

Font(R.font.my_regular_font, FontWeight.Normal),

294

Font(R.font.my_bold_font, FontWeight.Bold),

295

Font(R.font.my_italic_font, FontWeight.Normal, FontStyle.Italic)

296

)

297

298

// Using fonts in text styles

299

val customTextStyle = TextStyle(

300

fontFamily = customFontFamily,

301

fontSize = 18.sp,

302

fontWeight = FontWeight.Bold

303

)

304

305

// Loading fonts asynchronously

306

@Composable

307

fun CustomText() {

308

val fontFamily by rememberFontFamily(

309

Font("path/to/font.ttf", FontWeight.Normal)

310

)

311

312

fontFamily?.let { family ->

313

Text(

314

text = "Custom font text",

315

style = TextStyle(fontFamily = family)

316

)

317

}

318

}

319

```

320

321

### Text Layout and Alignment

322

323

Text positioning, alignment, and layout configuration for precise text placement and appearance.

324

325

```kotlin { .api }

326

/**

327

* Text alignment within its container.

328

*/

329

enum class TextAlign {

330

Left, Right, Center, Justify, Start, End

331

}

332

333

/**

334

* Text direction for bidirectional text support.

335

*/

336

enum class TextDirection {

337

Ltr, Rtl, Content, ContentOrLtr, ContentOrRtl

338

}

339

340

/**

341

* Text overflow handling strategies.

342

*/

343

enum class TextOverflow {

344

Clip, Ellipsis, Visible

345

}

346

347

/**

348

* Text decoration options.

349

*/

350

@Immutable

351

class TextDecoration private constructor(val mask: Int) {

352

operator fun plus(decoration: TextDecoration): TextDecoration

353

operator fun contains(other: TextDecoration): Boolean

354

355

companion object {

356

val None: TextDecoration

357

val Underline: TextDecoration

358

val LineThrough: TextDecoration

359

360

/**

361

* Combine multiple text decorations.

362

*/

363

fun combine(decorations: List<TextDecoration>): TextDecoration

364

}

365

}

366

367

/**

368

* Text shadow configuration.

369

*/

370

@Immutable

371

data class Shadow(

372

val color: Color = Color.Black,

373

val offset: Offset = Offset.Zero,

374

val blurRadius: Float = 0.0f

375

) {

376

companion object {

377

val None: Shadow

378

}

379

}

380

381

/**

382

* Text indentation configuration.

383

*/

384

@Immutable

385

data class TextIndent(

386

val firstLine: TextUnit = 0.sp,

387

val restLine: TextUnit = 0.sp

388

) {

389

companion object {

390

val None: TextIndent

391

}

392

}

393

394

/**

395

* Baseline shift for subscript and superscript text.

396

*/

397

@Immutable

398

class BaselineShift private constructor(val multiplier: Float) {

399

companion object {

400

val None: BaselineShift

401

val Subscript: BaselineShift

402

val Superscript: BaselineShift

403

}

404

}

405

406

/**

407

* Text geometric transformations.

408

*/

409

@Immutable

410

data class TextGeometricTransform(

411

val scaleX: Float = 1.0f,

412

val skewX: Float = 0.0f

413

) {

414

companion object {

415

val None: TextGeometricTransform

416

}

417

}

418

```

419

420

**Usage Examples:**

421

422

```kotlin

423

// Text alignment examples

424

Text(

425

text = "Left aligned text",

426

style = TextStyle(textAlign = TextAlign.Left),

427

modifier = Modifier.fillMaxWidth()

428

)

429

430

Text(

431

text = "Centered text",

432

style = TextStyle(textAlign = TextAlign.Center),

433

modifier = Modifier.fillMaxWidth()

434

)

435

436

// Text with decorations

437

Text(

438

text = "Underlined text",

439

style = TextStyle(

440

textDecoration = TextDecoration.Underline,

441

color = Color.Blue

442

)

443

)

444

445

// Text with shadow

446

Text(

447

text = "Shadow text",

448

style = TextStyle(

449

shadow = Shadow(

450

color = Color.Gray,

451

offset = Offset(2.0f, 2.0f),

452

blurRadius = 4.0f

453

),

454

fontSize = 20.sp

455

)

456

)

457

458

// Subscript and superscript

459

Text(

460

text = buildAnnotatedString {

461

append("H")

462

withStyle(

463

style = SpanStyle(

464

baselineShift = BaselineShift.Subscript,

465

fontSize = 12.sp

466

)

467

) {

468

append("2")

469

}

470

append("O")

471

}

472

)

473

```

474

475

### Text Input System

476

477

Comprehensive text input handling with field state management, validation, and input method control.

478

479

```kotlin { .api }

480

/**

481

* Value holder for TextField that contains text, cursor position, and selection range.

482

*/

483

@Immutable

484

class TextFieldValue(

485

val text: String,

486

val selection: TextRange = TextRange.Zero,

487

val composition: TextRange? = null

488

) {

489

/**

490

* Returns a copy of this TextFieldValue with the given values replaced.

491

*/

492

fun copy(

493

text: String = this.text,

494

selection: TextRange = this.selection,

495

composition: TextRange? = this.composition

496

): TextFieldValue

497

498

companion object {

499

/**

500

* Default TextFieldValue with empty text.

501

*/

502

val Saver: Saver<TextFieldValue, Any>

503

}

504

}

505

506

/**

507

* Text range for selection and composition.

508

*/

509

@Immutable

510

data class TextRange(

511

val start: Int,

512

val end: Int

513

) {

514

/**

515

* The minimum offset of the range.

516

*/

517

val min: Int

518

519

/**

520

* The maximum offset of the range.

521

*/

522

val max: Int

523

524

/**

525

* The length of the range.

526

*/

527

val length: Int

528

529

/**

530

* Whether this range represents a collapsed selection.

531

*/

532

val collapsed: Boolean

533

534

/**

535

* Whether this range represents a reversed selection.

536

*/

537

val reversed: Boolean

538

539

companion object {

540

val Zero: TextRange

541

}

542

}

543

544

/**

545

* Keyboard types for different input contexts.

546

*/

547

enum class KeyboardType {

548

Text, Ascii, Number, Phone, Uri, Email, Password, NumberPassword

549

}

550

551

/**

552

* Input method editor (IME) actions.

553

*/

554

enum class ImeAction {

555

Default, None, Go, Search, Send, Previous, Next, Done

556

}

557

558

/**

559

* Capitalization strategies for text input.

560

*/

561

enum class KeyboardCapitalization {

562

None, Characters, Words, Sentences

563

}

564

565

/**

566

* Keyboard options for configuring text input behavior.

567

*/

568

@Immutable

569

data class KeyboardOptions(

570

val capitalization: KeyboardCapitalization = KeyboardCapitalization.None,

571

val autoCorrect: Boolean = true,

572

val keyboardType: KeyboardType = KeyboardType.Text,

573

val imeAction: ImeAction = ImeAction.Default

574

) {

575

companion object {

576

val Default: KeyboardOptions

577

}

578

}

579

580

/**

581

* Visual transformation for text input display.

582

*/

583

fun interface VisualTransformation {

584

/**

585

* Transform the text for display.

586

*/

587

fun filter(text: AnnotatedString): TransformedText

588

589

companion object {

590

/**

591

* No transformation applied.

592

*/

593

val None: VisualTransformation

594

}

595

}

596

597

/**

598

* Password visual transformation that masks input.

599

*/

600

class PasswordVisualTransformation(

601

val mask: Char = '\u2022'

602

) : VisualTransformation {

603

override fun filter(text: AnnotatedString): TransformedText

604

}

605

606

/**

607

* Result of visual transformation.

608

*/

609

class TransformedText(

610

val text: AnnotatedString,

611

val offsetMapping: OffsetMapping

612

)

613

614

/**

615

* Maps character offsets between original and transformed text.

616

*/

617

interface OffsetMapping {

618

/**

619

* Convert offset from original to transformed text.

620

*/

621

fun originalToTransformed(offset: Int): Int

622

623

/**

624

* Convert offset from transformed to original text.

625

*/

626

fun transformedToOriginal(offset: Int): Int

627

628

companion object {

629

/**

630

* Identity mapping (no transformation).

631

*/

632

val Identity: OffsetMapping

633

}

634

}

635

```

636

637

**Usage Examples:**

638

639

```kotlin

640

// Basic text field state

641

var textState by remember { mutableStateOf(TextFieldValue("")) }

642

643

TextField(

644

value = textState,

645

onValueChange = { textState = it },

646

label = { Text("Enter text") }

647

)

648

649

// Password field with visual transformation

650

var passwordState by remember { mutableStateOf("") }

651

652

TextField(

653

value = passwordState,

654

onValueChange = { passwordState = it },

655

label = { Text("Password") },

656

visualTransformation = PasswordVisualTransformation(),

657

keyboardOptions = KeyboardOptions(

658

keyboardType = KeyboardType.Password,

659

imeAction = ImeAction.Done

660

)

661

)

662

663

// Number input field

664

var numberState by remember { mutableStateOf("") }

665

666

TextField(

667

value = numberState,

668

onValueChange = { numberState = it },

669

label = { Text("Enter number") },

670

keyboardOptions = KeyboardOptions(

671

keyboardType = KeyboardType.Number,

672

imeAction = ImeAction.Next

673

)

674

)

675

676

// Email input with auto-correction disabled

677

var emailState by remember { mutableStateOf("") }

678

679

TextField(

680

value = emailState,

681

onValueChange = { emailState = it },

682

label = { Text("Email address") },

683

keyboardOptions = KeyboardOptions(

684

keyboardType = KeyboardType.Email,

685

autoCorrect = false,

686

capitalization = KeyboardCapitalization.None

687

)

688

)

689

```

690

691

### Annotated Text

692

693

Rich text system supporting spans, styles, and clickable text segments for complex text formatting.

694

695

```kotlin { .api }

696

/**

697

* Text with multiple styles and annotations.

698

*/

699

@Immutable

700

class AnnotatedString(

701

val text: String,

702

val spanStyles: List<Range<SpanStyle>> = emptyList(),

703

val paragraphStyles: List<Range<ParagraphStyle>> = emptyList(),

704

val annotations: List<Range<out Any>> = emptyList()

705

) : CharSequence {

706

707

override val length: Int

708

override fun get(index: Int): Char

709

override fun subSequence(startIndex: Int, endIndex: Int): AnnotatedString

710

711

/**

712

* Return a substring of this AnnotatedString.

713

*/

714

fun substring(startIndex: Int, endIndex: Int = length): AnnotatedString

715

716

/**

717

* Plus operator for concatenating AnnotatedStrings.

718

*/

719

operator fun plus(other: AnnotatedString): AnnotatedString

720

721

/**

722

* Returns a list of annotations attached to this AnnotatedString.

723

*/

724

fun <T : Any> getStringAnnotations(tag: String, start: Int, end: Int): List<Range<T>>

725

726

/**

727

* Range class for associating data with text ranges.

728

*/

729

@Immutable

730

data class Range<T>(

731

val item: T,

732

val start: Int,

733

val end: Int,

734

val tag: String = ""

735

)

736

737

companion object {

738

val Saver: Saver<AnnotatedString, Any>

739

}

740

}

741

742

/**

743

* Styling information that can be applied to a span of text.

744

*/

745

@Immutable

746

data class SpanStyle(

747

val color: Color = Color.Unspecified,

748

val fontSize: TextUnit = TextUnit.Unspecified,

749

val fontWeight: FontWeight? = null,

750

val fontStyle: FontStyle? = null,

751

val fontSynthesis: FontSynthesis? = null,

752

val fontFamily: FontFamily? = null,

753

val fontFeatureSettings: String? = null,

754

val letterSpacing: TextUnit = TextUnit.Unspecified,

755

val baselineShift: BaselineShift? = null,

756

val textGeometricTransform: TextGeometricTransform? = null,

757

val localeList: LocaleList? = null,

758

val background: Color = Color.Unspecified,

759

val textDecoration: TextDecoration? = null,

760

val shadow: Shadow? = null,

761

val platformStyle: PlatformSpanStyle? = null

762

) {

763

/**

764

* Returns a new span style that is a combination of this style and the given other style.

765

*/

766

fun merge(other: SpanStyle? = null): SpanStyle

767

768

/**

769

* Plus operator overload that applies a merge.

770

*/

771

operator fun plus(other: SpanStyle): SpanStyle

772

}

773

774

/**

775

* Styling information for paragraphs.

776

*/

777

@Immutable

778

data class ParagraphStyle(

779

val textAlign: TextAlign? = null,

780

val textDirection: TextDirection? = null,

781

val lineHeight: TextUnit = TextUnit.Unspecified,

782

val textIndent: TextIndent? = null,

783

val platformStyle: PlatformParagraphStyle? = null,

784

val lineHeightStyle: LineHeightStyle? = null,

785

val lineBreak: LineBreak? = null,

786

val hyphens: Hyphens? = null

787

) {

788

/**

789

* Returns a new paragraph style that is a combination of this style and the given other style.

790

*/

791

fun merge(other: ParagraphStyle? = null): ParagraphStyle

792

793

/**

794

* Plus operator overload that applies a merge.

795

*/

796

operator fun plus(other: ParagraphStyle): ParagraphStyle

797

}

798

799

/**

800

* Builder for creating AnnotatedStrings with styled content.

801

*/

802

class AnnotatedString.Builder(capacity: Int = 16) {

803

/**

804

* Current length of the built string.

805

*/

806

val length: Int

807

808

/**

809

* Append text to the builder.

810

*/

811

fun append(text: String)

812

fun append(text: Char)

813

fun append(text: AnnotatedString)

814

815

/**

816

* Apply a SpanStyle to the given range.

817

*/

818

fun addStyle(style: SpanStyle, start: Int, end: Int)

819

820

/**

821

* Apply a ParagraphStyle to the given range.

822

*/

823

fun addStyle(style: ParagraphStyle, start: Int, end: Int)

824

825

/**

826

* Add an annotation to the given range.

827

*/

828

fun addStringAnnotation(tag: String, annotation: String, start: Int, end: Int)

829

830

/**

831

* Apply styles within a scope.

832

*/

833

inline fun withStyle(style: SpanStyle, action: AnnotatedString.Builder.() -> Unit): Int

834

inline fun withStyle(style: ParagraphStyle, action: AnnotatedString.Builder.() -> Unit): Int

835

836

/**

837

* Build the final AnnotatedString.

838

*/

839

fun toAnnotatedString(): AnnotatedString

840

}

841

842

/**

843

* DSL for building AnnotatedString.

844

*/

845

inline fun buildAnnotatedString(

846

builder: AnnotatedString.Builder.() -> Unit

847

): AnnotatedString

848

```

849

850

**Usage Examples:**

851

852

```kotlin

853

// Creating rich text with annotations

854

val richText = buildAnnotatedString {

855

append("Visit our ")

856

857

// Add clickable link

858

pushStringAnnotation(tag = "URL", annotation = "https://example.com")

859

withStyle(style = SpanStyle(color = Color.Blue, textDecoration = TextDecoration.Underline)) {

860

append("website")

861

}

862

pop()

863

864

append(" for more information.\n\n")

865

866

// Add emphasized text

867

withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, fontSize = 18.sp)) {

868

append("Important Notice")

869

}

870

871

append("\nThis text contains ")

872

873

// Add styled span

874

withStyle(style = SpanStyle(

875

color = Color.Red,

876

fontStyle = FontStyle.Italic,

877

background = Color.Yellow.copy(alpha = 0.3f)

878

)) {

879

append("highlighted content")

880

}

881

882

append(" within the paragraph.")

883

}

884

885

// Using the rich text in a Text composable

886

ClickableText(

887

text = richText,

888

onClick = { offset ->

889

richText.getStringAnnotations(tag = "URL", start = offset, end = offset)

890

.firstOrNull()?.let { annotation ->

891

// Handle URL click

892

println("Clicked URL: ${annotation.item}")

893

}

894

}

895

)

896

897

// Multi-styled paragraph

898

val styledText = buildAnnotatedString {

899

withStyle(style = ParagraphStyle(textAlign = TextAlign.Center)) {

900

withStyle(style = SpanStyle(fontSize = 24.sp, fontWeight = FontWeight.Bold)) {

901

append("Centered Title")

902

}

903

}

904

905

append("\n\n")

906

907

withStyle(style = ParagraphStyle(textAlign = TextAlign.Justify, lineHeight = 20.sp)) {

908

append("This is a justified paragraph with custom line height. ")

909

910

withStyle(style = SpanStyle(fontWeight = FontWeight.SemiBold)) {

911

append("Bold text")

912

}

913

914

append(" mixed with ")

915

916

withStyle(style = SpanStyle(fontStyle = FontStyle.Italic)) {

917

append("italic text")

918

}

919

920

append(" in the same paragraph.")

921

}

922

}

923

```