From 0624374540eb10ca7d894b02e80931a6e8590a25 Mon Sep 17 00:00:00 2001 From: vincentborko Date: Wed, 3 Jun 2026 00:53:25 +0200 Subject: [PATCH] Add Text Concatenation playground Demonstrates `Text + Text` concatenation with per-segment styling (per-run color, weight/italic/monospaced, mixed font sizes, decorations, gradient foreground, and combined styles with wrapping). Showcase for skiptools/skip-ui#453. Co-Authored-By: Claude Opus 4.8 (1M context) --- Sources/Showcase/PlaygroundListView.swift | 5 ++ .../TextConcatenationPlayground.swift | 61 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 Sources/Showcase/TextConcatenationPlayground.swift diff --git a/Sources/Showcase/PlaygroundListView.swift b/Sources/Showcase/PlaygroundListView.swift index ad4a641..1826fec 100644 --- a/Sources/Showcase/PlaygroundListView.swift +++ b/Sources/Showcase/PlaygroundListView.swift @@ -84,6 +84,7 @@ enum PlaygroundType: CaseIterable, View { case table case tabView case text + case textConcatenation case textEditor case textField case toggle @@ -263,6 +264,8 @@ enum PlaygroundType: CaseIterable, View { return LocalizedStringResource("TabView", comment: "Title of TabView playground") case .text: return LocalizedStringResource("Text", comment: "Title of Text playground") + case .textConcatenation: + return LocalizedStringResource("Text Concatenation", comment: "Title of Text Concatenation playground") case .textEditor: return LocalizedStringResource("TextEditor", comment: "Title of Text playground") case .textField: @@ -470,6 +473,8 @@ enum PlaygroundType: CaseIterable, View { TabViewPlayground() case .text: TextPlayground() + case .textConcatenation: + TextConcatenationPlayground() case .textEditor: TextEditorPlayground() case .textField: diff --git a/Sources/Showcase/TextConcatenationPlayground.swift b/Sources/Showcase/TextConcatenationPlayground.swift new file mode 100644 index 0000000..7593123 --- /dev/null +++ b/Sources/Showcase/TextConcatenationPlayground.swift @@ -0,0 +1,61 @@ +// Copyright 2023–2026 Skip +import SwiftUI + +/// Demonstrates `Text + Text` concatenation: each operand keeps its own styling, and the result +/// renders as a single flowing run (a Compose `AnnotatedString` on Android) rather than separate views. +struct TextConcatenationPlayground: View { + var body: some View { + ScrollView { + VStack(spacing: 16) { + Text("Per-run color").font(.headline) + Text("Plain ") + + Text("red ").foregroundColor(.red) + + Text("green ").foregroundColor(.green) + + Text("blue").foregroundColor(.blue) + + Divider() + + Text("Weight, italic, monospaced").font(.headline) + Text("normal ") + + Text("bold ").bold() + + Text("heavy ").fontWeight(.heavy) + + Text("italic ").italic() + + Text("mono").monospaced() + + Divider() + + Text("Mixed font sizes").font(.headline) + Text("caption ").font(.caption) + + Text("body ").font(.body) + + Text("title ").font(.title) + + Divider() + + Text("Decorations").font(.headline) + Text("plain ") + + Text("underline ").underline() + + Text("strikethrough").strikethrough() + + Divider() + + Text("Gradient foreground").font(.headline) + Text("solid ") + + Text("gradient run") + .foregroundStyle(LinearGradient(colors: [.blue, .purple, .pink], startPoint: .leading, endPoint: .trailing)) + .bold() + + Divider() + + Text("Combined styles + wrapping").font(.headline) + Text("This ").foregroundColor(.orange).bold() + + Text("concatenated ").italic() + + Text("text ").underline() + + Text("mixes several styles and wraps across multiple lines as one paragraph").foregroundColor(.secondary) + } + .padding() + } + .toolbar { + PlaygroundSourceLink(file: "TextConcatenationPlayground.swift") + } + } +}