diff --git a/Sources/Bedrock/Theme/TYPOGRAPHY_GUIDE.md b/Sources/Bedrock/Theme/TYPOGRAPHY_GUIDE.md index 24206f3..f3ec390 100644 --- a/Sources/Bedrock/Theme/TYPOGRAPHY_GUIDE.md +++ b/Sources/Bedrock/Theme/TYPOGRAPHY_GUIDE.md @@ -9,9 +9,7 @@ The typography system consists of: 1. **`Theme`** - Global theme registration for all color providers 2. **`Typography` enum** - All font definitions with explicit naming 3. **`TextEmphasis` enum** - Semantic text colors -4. **`StyledLabel`** - Simple text component combining typography + emphasis -5. **`IconLabel`** - Icon + text component -6. **`.typography()` modifier** - View extension for applying fonts +4. **`Text().styled()` / `Label().styled()`** - View extensions for semantic styling --- @@ -37,8 +35,8 @@ This enables Bedrock components to use your app's colors automatically. After registration, use `Theme.*` to access your registered colors: ```swift -// In Bedrock components (automatic via TextEmphasis) -StyledLabel("Title", .heading) // Uses Theme.Text.primary +// In views (automatic via TextEmphasis) +Text("Title").styled(.heading) // Uses Theme.Text.primary // Direct access when needed let bgColor = Theme.Surface.card @@ -88,7 +86,7 @@ All fonts are defined in the `Typography` enum. Each case name explicitly descri ## TextEmphasis Enum -Semantic text colors resolved from the registered `TextTheme`: +Semantic text colors resolved from the registered Theme: | Emphasis | Description | |----------|-------------| @@ -101,52 +99,67 @@ Semantic text colors resolved from the registered `TextTheme`: ### When to Use `.custom()` -Only use `.custom()` for colors that aren't text colors: +Only use `.custom()` for colors that aren't semantic text colors: ```swift // ✅ Semantic text colors - use the emphasis value directly -StyledLabel("Title", .heading) // .primary is default -StyledLabel("Subtitle", .subheading, emphasis: .secondary) -StyledLabel("Hint", .caption, emphasis: .tertiary) +Text("Title").styled(.heading) // .primary is default +Text("Subtitle").styled(.subheading, emphasis: .secondary) +Text("Hint").styled(.caption, emphasis: .tertiary) // ✅ Use .custom() for non-text colors -StyledLabel("Success!", .heading, emphasis: .custom(AppStatus.success)) -StyledLabel("Arc 3", .caption, emphasis: .custom(AppAccent.primary)) +Text("Success!").styled(.heading, emphasis: .custom(AppStatus.success)) +Text("Arc 3").styled(.caption, emphasis: .custom(AppAccent.primary)) // ✅ Use .custom() for conditional colors -StyledLabel(text, .body, emphasis: .custom(isActive ? AppStatus.success : AppTextColors.tertiary)) +Text(text).styled(.body, emphasis: .custom(isActive ? AppStatus.success : AppTextColors.tertiary)) ``` --- -## StyledLabel Component +## Text().styled() Extension -A single component for all styled text: +The primary way to style text: ```swift -StyledLabel( - _ text: String, - _ typography: Typography = .body, - emphasis: TextEmphasis = .primary, - alignment: TextAlignment? = nil, - lineLimit: Int? = nil -) +Text(_ text: String) + .styled(_ typography: Typography = .body, emphasis: TextEmphasis = .primary) ``` ### Examples ```swift // Simple - uses registered theme's primary color -StyledLabel("Morning Ritual", .heading) -StyledLabel("Day 6 of 28", .caption, emphasis: .secondary) +Text("Morning Ritual").styled(.heading) +Text("Day 6 of 28").styled(.caption, emphasis: .secondary) -// With alignment and line limit -StyledLabel("Centered text", .body, alignment: .center) -StyledLabel("One line", .caption, emphasis: .tertiary, lineLimit: 1) +// String interpolation +Text("Count: \(count)").styled(.bodyEmphasis) + +// With additional modifiers +Text("Centered text") + .styled(.body) + .multilineTextAlignment(.center) + +Text("One line") + .styled(.caption, emphasis: .tertiary) + .lineLimit(1) + +// Font design variants +Text("$9.99") + .styled(.subheadingEmphasis) + .fontDesign(.rounded) + +// Uppercase headers +Text("SECTION") + .styled(.captionEmphasis, emphasis: .secondary) + .textCase(.uppercase) + .tracking(0.5) // In buttons Button(action: onContinue) { - StyledLabel("Continue", .heading, emphasis: .inverse) + Text("Continue") + .styled(.heading, emphasis: .inverse) .frame(maxWidth: .infinity) .frame(height: 50) .background(AppAccent.primary) @@ -155,66 +168,48 @@ Button(action: onContinue) { --- -## IconLabel Component +## Label().styled() Extension For icon + text combinations: ```swift -IconLabel(_ icon: String, _ text: String, _ typography: Typography = .body, emphasis: TextEmphasis = .primary) +Label(_ text: String, systemImage: String) + .styled(_ typography: Typography = .body, emphasis: TextEmphasis = .primary) ``` ### Examples ```swift -IconLabel("bell.fill", "Notifications", .subheading) -IconLabel("star.fill", "Favorites", .body, emphasis: .secondary) -IconLabel("flame.fill", "5-day streak", .caption, emphasis: .custom(AppStatus.success)) +Label("Notifications", systemImage: "bell.fill") + .styled(.subheading) + +Label("Favorites", systemImage: "star.fill") + .styled(.body, emphasis: .secondary) + +Label("5-day streak", systemImage: "flame.fill") + .styled(.caption, emphasis: .custom(AppStatus.success)) + +// In buttons +Button(action: addItem) { + Label("Add to Rituals", systemImage: "plus.circle.fill") + .styled(.heading, emphasis: .inverse) + .frame(maxWidth: .infinity) + .background(AppAccent.primary) +} ``` --- -## When to Use StyledLabel vs Text() - -### Use StyledLabel (Preferred) - -Use `StyledLabel` for 95% of text: - -```swift -StyledLabel("Settings", .subheadingEmphasis) -StyledLabel("Description", .subheading, emphasis: .secondary) -StyledLabel("Centered", .body, alignment: .center) -``` - -### Use Text() with .typography() (Rare Exceptions) - -Only when you need modifiers `StyledLabel` doesn't support: - -```swift -// Font design variants -Text(formattedValue) - .typography(.subheadingEmphasis) - .fontDesign(.rounded) - -// TextField styling -TextField("Placeholder", text: $value) - .typography(.heading) - -// Inside special view builders (like Charts AxisValueLabel) -AxisValueLabel { - Text("\(value)%") - .font(Typography.caption2.font) - .foregroundStyle(color) -} -``` - -### Never Use Raw `.font()` with System Fonts +## Never Use Raw `.font()` with System Fonts ```swift // ❌ BAD Text("Title").font(.headline) +Text("Body").font(.body).foregroundStyle(.white) // ✅ GOOD -StyledLabel("Title", .heading) +Text("Title").styled(.heading) +Text("Body").styled(.body, emphasis: .inverse) ``` --- @@ -227,16 +222,21 @@ StyledLabel("Title", .heading) // OLD: Design.Typography Text("Title").font(Design.Typography.headline) -// NEW: StyledLabel -StyledLabel("Title", .heading) +// NEW: Text().styled() +Text("Title").styled(.heading) -// OLD: Multiple Label components -TitleLabel("Title", style: .headline, color: .white) -BodyLabel("Body", emphasis: .secondary) - -// NEW: Single StyledLabel +// OLD: StyledLabel component StyledLabel("Title", .heading, emphasis: .inverse) -StyledLabel("Body", .subheading, emphasis: .secondary) + +// NEW: Text().styled() +Text("Title").styled(.heading, emphasis: .inverse) + +// OLD: IconLabel component +IconLabel("bell.fill", "Notifications", .subheading) + +// NEW: Label().styled() +Label("Notifications", systemImage: "bell.fill") + .styled(.subheading) ``` ### Mapping Table diff --git a/Sources/Bedrock/Theme/TextEmphasis.swift b/Sources/Bedrock/Theme/TextEmphasis.swift index c53928c..ddfbf6a 100644 --- a/Sources/Bedrock/Theme/TextEmphasis.swift +++ b/Sources/Bedrock/Theme/TextEmphasis.swift @@ -26,9 +26,9 @@ import SwiftUI /// ) /// /// // Then use emphasis levels directly -/// StyledLabel("Primary text", .body) // uses .primary -/// StyledLabel("Secondary text", .caption, emphasis: .secondary) -/// StyledLabel("Custom color", .heading, emphasis: .custom(.red)) +/// Text("Primary text").styled(.body) // uses .primary +/// Text("Secondary text").styled(.caption, emphasis: .secondary) +/// Text("Custom color").styled(.heading, emphasis: .custom(.red)) /// ``` public enum TextEmphasis: Sendable { /// Primary text color (highest emphasis). Default. diff --git a/Sources/Bedrock/Theme/Theme.swift b/Sources/Bedrock/Theme/Theme.swift index 7d27a1b..848722a 100644 --- a/Sources/Bedrock/Theme/Theme.swift +++ b/Sources/Bedrock/Theme/Theme.swift @@ -12,7 +12,7 @@ import SwiftUI /// Global theme provider for Bedrock components. /// /// Register your app's theme once at launch to enable semantic colors -/// in `StyledLabel`, `IconLabel`, and other Bedrock components. +/// in `Text().styled()`, `Label().styled()`, and other Bedrock components. /// /// ## Usage /// @@ -26,8 +26,8 @@ import SwiftUI /// ) /// /// // Then use semantic emphasis directly -/// StyledLabel("Title", .heading) // uses Theme.Text.primary -/// StyledLabel("Subtitle", .subheading, emphasis: .secondary) // uses Theme.Text.secondary +/// Text("Title").styled(.heading) // uses Theme.Text.primary +/// Text("Subtitle").styled(.subheading, emphasis: .secondary) // uses Theme.Text.secondary /// ``` public enum Theme { // MARK: - Registered Providers diff --git a/Sources/Bedrock/Views/Effects/PulsingModifier.swift b/Sources/Bedrock/Views/Effects/PulsingModifier.swift index 0734997..dcb39c5 100644 --- a/Sources/Bedrock/Views/Effects/PulsingModifier.swift +++ b/Sources/Bedrock/Views/Effects/PulsingModifier.swift @@ -73,7 +73,7 @@ public extension View { .clipShape(.rect(cornerRadius: Design.CornerRadius.medium)) .pulsing(isActive: true) - StyledLabel("Pulsing highlights interactive areas", .caption, emphasis: .secondary) + Text("Pulsing highlights interactive areas").styled(.caption, emphasis: .secondary) } } } diff --git a/Sources/Bedrock/Views/Settings/LicensesView.swift b/Sources/Bedrock/Views/Settings/LicensesView.swift index 047b7d2..7563a08 100644 --- a/Sources/Bedrock/Views/Settings/LicensesView.swift +++ b/Sources/Bedrock/Views/Settings/LicensesView.swift @@ -75,18 +75,20 @@ public struct LicensesView: View { private func licenseCard(_ license: License) -> some View { SettingsCard(backgroundColor: cardBackgroundColor, borderColor: cardBorderColor) { VStack(alignment: .leading, spacing: Design.Spacing.small) { - StyledLabel(license.name, .bodyEmphasis, emphasis: .inverse) + Text(license.name).styled(.bodyEmphasis, emphasis: .inverse) - StyledLabel(license.description, .caption, emphasis: .secondary) + Text(license.description).styled(.caption, emphasis: .secondary) HStack { - IconLabel("doc.text", license.licenseType, .caption2, emphasis: .custom(accentColor)) + Label(license.licenseType, systemImage: "doc.text") + .styled(.caption2, emphasis: .custom(accentColor)) Spacer() if let linkURL = URL(string: license.url) { Link(destination: linkURL) { - IconLabel("arrow.up.right.square", String(localized: "View on GitHub"), .caption2, emphasis: .custom(accentColor)) + Label(String(localized: "View on GitHub"), systemImage: "arrow.up.right.square") + .styled(.caption2, emphasis: .custom(accentColor)) } } } diff --git a/Sources/Bedrock/Views/Settings/SegmentedPicker.swift b/Sources/Bedrock/Views/Settings/SegmentedPicker.swift index 20ec7c6..220c512 100644 --- a/Sources/Bedrock/Views/Settings/SegmentedPicker.swift +++ b/Sources/Bedrock/Views/Settings/SegmentedPicker.swift @@ -51,7 +51,7 @@ public struct SegmentedPicker: View { public var body: some View { VStack(alignment: .leading, spacing: Design.Spacing.small) { - StyledLabel(title, .subheadingEmphasis, emphasis: .inverse) + Text(title).styled(.subheadingEmphasis, emphasis: .inverse) HStack(spacing: Design.Spacing.small) { ForEach(options.indices, id: \.self) { index in @@ -59,7 +59,8 @@ public struct SegmentedPicker: View { Button { selection = option.1 } label: { - StyledLabel(option.0, .subheadingEmphasis, emphasis: .custom(selection == option.1 ? .black : .white.opacity(Design.Opacity.strong))) + Text(option.0) + .styled(.subheadingEmphasis, emphasis: .custom(selection == option.1 ? .black : .white.opacity(Design.Opacity.strong))) .padding(.vertical, Design.Spacing.small) .frame(maxWidth: .infinity) .background( diff --git a/Sources/Bedrock/Views/Settings/SelectableRow.swift b/Sources/Bedrock/Views/Settings/SelectableRow.swift index df45f72..e1ecd17 100644 --- a/Sources/Bedrock/Views/Settings/SelectableRow.swift +++ b/Sources/Bedrock/Views/Settings/SelectableRow.swift @@ -67,9 +67,9 @@ public struct SelectableRow: View { Button(action: action) { HStack { VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) { - StyledLabel(title, .calloutEmphasis, emphasis: .inverse) + Text(title).styled(.calloutEmphasis, emphasis: .inverse) - StyledLabel(subtitle, .subheading, emphasis: .tertiary) + Text(subtitle).styled(.subheading, emphasis: .tertiary) } Spacer() diff --git a/Sources/Bedrock/Views/Settings/SettingsNavigationRow.swift b/Sources/Bedrock/Views/Settings/SettingsNavigationRow.swift index e6657d7..a88fa7c 100644 --- a/Sources/Bedrock/Views/Settings/SettingsNavigationRow.swift +++ b/Sources/Bedrock/Views/Settings/SettingsNavigationRow.swift @@ -67,10 +67,10 @@ public struct SettingsNavigationRow: View { } label: { HStack { VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) { - StyledLabel(title, .subheadingEmphasis) + Text(title).styled(.subheadingEmphasis) if let subtitle { - StyledLabel(subtitle, .caption, emphasis: .secondary) + Text(subtitle).styled(.caption, emphasis: .secondary) } } diff --git a/Sources/Bedrock/Views/Settings/SettingsRow.swift b/Sources/Bedrock/Views/Settings/SettingsRow.swift index 50b58ed..f8fed9e 100644 --- a/Sources/Bedrock/Views/Settings/SettingsRow.swift +++ b/Sources/Bedrock/Views/Settings/SettingsRow.swift @@ -59,12 +59,12 @@ public struct SettingsRow: View { .background(iconColor.opacity(Design.Opacity.heavy)) .clipShape(.rect(cornerRadius: Design.CornerRadius.xSmall)) - StyledLabel(title, .subheading) + Text(title).styled(.subheading) Spacer() if let value { - StyledLabel(value, .subheading, emphasis: .secondary) + Text(value).styled(.subheading, emphasis: .secondary) } if let accessory { diff --git a/Sources/Bedrock/Views/Settings/SettingsSectionHeader.swift b/Sources/Bedrock/Views/Settings/SettingsSectionHeader.swift index de52816..568a0ec 100644 --- a/Sources/Bedrock/Views/Settings/SettingsSectionHeader.swift +++ b/Sources/Bedrock/Views/Settings/SettingsSectionHeader.swift @@ -40,8 +40,7 @@ public struct SettingsSectionHeader: View { } Text(title) - .font(Typography.captionEmphasis.font) - .foregroundStyle(Theme.Text.secondary) + .styled(.captionEmphasis, emphasis: .secondary) .textCase(.uppercase) .tracking(0.5) diff --git a/Sources/Bedrock/Views/Settings/SettingsSegmentedPicker.swift b/Sources/Bedrock/Views/Settings/SettingsSegmentedPicker.swift index fd4e0ef..a185594 100644 --- a/Sources/Bedrock/Views/Settings/SettingsSegmentedPicker.swift +++ b/Sources/Bedrock/Views/Settings/SettingsSegmentedPicker.swift @@ -79,7 +79,7 @@ public struct SettingsSegmentedPicker: View { VStack(alignment: .leading, spacing: Design.Spacing.small) { // Title row with optional accessory HStack(spacing: Design.Spacing.xSmall) { - StyledLabel(title, .subheadingEmphasis) + Text(title).styled(.subheadingEmphasis) if let titleAccessory { titleAccessory @@ -88,7 +88,7 @@ public struct SettingsSegmentedPicker: View { } // Subtitle - StyledLabel(subtitle, .caption, emphasis: .secondary) + Text(subtitle).styled(.caption, emphasis: .secondary) // Segmented buttons HStack(spacing: Design.Spacing.small) { @@ -97,7 +97,8 @@ public struct SettingsSegmentedPicker: View { Button { selection = option.1 } label: { - StyledLabel(option.0, .subheadingEmphasis, emphasis: .custom(selection == option.1 ? Color.white : Theme.Text.primary)) + Text(option.0) + .styled(.subheadingEmphasis, emphasis: .custom(selection == option.1 ? Color.white : Theme.Text.primary)) .padding(.vertical, Design.Spacing.small) .frame(maxWidth: .infinity) .background( diff --git a/Sources/Bedrock/Views/Settings/SettingsSlider.swift b/Sources/Bedrock/Views/Settings/SettingsSlider.swift index 5fbfcf7..6c4da49 100644 --- a/Sources/Bedrock/Views/Settings/SettingsSlider.swift +++ b/Sources/Bedrock/Views/Settings/SettingsSlider.swift @@ -110,18 +110,17 @@ public struct SettingsSlider: View where public var body: some View { VStack(alignment: .leading, spacing: Design.Spacing.small) { HStack { - StyledLabel(title, .subheadingEmphasis) + Text(title).styled(.subheadingEmphasis) Spacer() // Exception: Needs .fontDesign(.rounded) modifier Text(format(value)) - .font(Typography.subheadingEmphasis.font) + .styled(.subheadingEmphasis, emphasis: .secondary) .fontDesign(.rounded) - .foregroundStyle(.secondary) } - StyledLabel(subtitle, .caption, emphasis: .secondary) + Text(subtitle).styled(.caption, emphasis: .secondary) HStack(spacing: Design.Spacing.medium) { if let leadingIcon { diff --git a/Sources/Bedrock/Views/Settings/SettingsToggle.swift b/Sources/Bedrock/Views/Settings/SettingsToggle.swift index 36b1d56..7b534b4 100644 --- a/Sources/Bedrock/Views/Settings/SettingsToggle.swift +++ b/Sources/Bedrock/Views/Settings/SettingsToggle.swift @@ -78,7 +78,7 @@ public struct SettingsToggle: View { Toggle(isOn: $isOn) { VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) { HStack(spacing: Design.Spacing.xSmall) { - StyledLabel(title, .subheadingEmphasis) + Text(title).styled(.subheadingEmphasis) if let titleAccessory { titleAccessory @@ -86,7 +86,7 @@ public struct SettingsToggle: View { } } - StyledLabel(subtitle, .subheading, emphasis: .secondary) + Text(subtitle).styled(.subheading, emphasis: .secondary) } } .tint(accentColor) diff --git a/Sources/Bedrock/Views/Settings/iCloudSyncSettingsView.swift b/Sources/Bedrock/Views/Settings/iCloudSyncSettingsView.swift index 5fe1686..00ee1a5 100644 --- a/Sources/Bedrock/Views/Settings/iCloudSyncSettingsView.swift +++ b/Sources/Bedrock/Views/Settings/iCloudSyncSettingsView.swift @@ -117,14 +117,14 @@ public struct iCloudSyncSettingsView: View { HStack(spacing: Design.Spacing.small) { SymbolIcon(syncStatusIcon, size: .inline, color: syncStatusColor) - StyledLabel(syncStatusText, .caption, emphasis: .tertiary) + Text(syncStatusText).styled(.caption, emphasis: .tertiary) Spacer() Button { viewModel.forceSync() } label: { - StyledLabel(String(localized: "Sync Now"), .captionEmphasis, emphasis: .custom(accentColor)) + Text(String(localized: "Sync Now")).styled(.captionEmphasis, emphasis: .custom(accentColor)) } } .padding(.top, Design.Spacing.xSmall) diff --git a/Sources/Bedrock/Views/Text/StyledText.swift b/Sources/Bedrock/Views/Text/StyledText.swift index 176fd7d..6dac8dc 100644 --- a/Sources/Bedrock/Views/Text/StyledText.swift +++ b/Sources/Bedrock/Views/Text/StyledText.swift @@ -2,100 +2,70 @@ // StyledText.swift // Bedrock // -// Semantic text components for consistent typography. +// Semantic text styling extensions for consistent typography. // import SwiftUI -// MARK: - Styled Label +// MARK: - Text Extension -/// A text label with semantic typography and color. -/// -/// Use `StyledLabel` for all text that follows the typography system. -/// It combines a `Typography` style with a `TextEmphasis` color. -/// -/// ## Example -/// -/// ```swift -/// StyledLabel("Morning Ritual", .heading) -/// StyledLabel("Day 6 of 28", .caption, emphasis: .secondary) -/// StyledLabel("Warning", .bodyEmphasis, emphasis: .custom(.red)) -/// ``` -public struct StyledLabel: View { - private let text: String - private let typography: Typography - private let emphasis: TextEmphasis - private let alignment: TextAlignment? - private let lineLimit: Int? - - /// Creates a styled label. +public extension Text { + /// Applies semantic typography and emphasis styling to a Text view. + /// + /// ## Example + /// + /// ```swift + /// Text("Hello, \(name)!") + /// .styled(.bodyEmphasis, emphasis: .secondary) + /// + /// Text(attributedString) + /// .styled(.caption) + /// + /// // With additional modifiers + /// Text("HEADER") + /// .styled(.captionEmphasis, emphasis: .secondary) + /// .textCase(.uppercase) + /// .tracking(0.5) + /// ``` + /// /// - Parameters: - /// - text: The text to display. /// - typography: The typography style (default: `.body`). /// - emphasis: The text emphasis/color (default: `.primary`). - /// - alignment: Optional multiline text alignment. - /// - lineLimit: Optional line limit. - public init( - _ text: String, + /// - Returns: A styled Text view. + func styled( _ typography: Typography = .body, - emphasis: TextEmphasis = .primary, - alignment: TextAlignment? = nil, - lineLimit: Int? = nil - ) { - self.text = text - self.typography = typography - self.emphasis = emphasis - self.alignment = alignment - self.lineLimit = lineLimit - } - - public var body: some View { - Text(text) + emphasis: TextEmphasis = .primary + ) -> some View { + self .font(typography.font) .foregroundStyle(emphasis.color) - .multilineTextAlignment(alignment ?? .leading) - .lineLimit(lineLimit) } } -// MARK: - Icon Label +// MARK: - Label Extension -/// A label with an icon and text, styled with semantic typography. -/// -/// Use `IconLabel` for icon + text combinations like menu items or list rows. -/// -/// ## Example -/// -/// ```swift -/// IconLabel("bell.fill", "Notifications", .subheading) -/// IconLabel("star.fill", "Favorites", .body, emphasis: .secondary) -/// ``` -public struct IconLabel: View { - private let icon: String - private let text: String - private let typography: Typography - private let emphasis: TextEmphasis - - /// Creates an icon label. +public extension Label where Title == Text, Icon == Image { + /// Applies semantic typography and emphasis styling to a Label view. + /// + /// ## Example + /// + /// ```swift + /// Label("Notifications", systemImage: "bell.fill") + /// .styled(.subheading, emphasis: .secondary) + /// + /// Label("Settings", systemImage: "gear") + /// .styled(.body) + /// ``` + /// /// - Parameters: - /// - icon: The SF Symbol name. - /// - text: The text to display. /// - typography: The typography style (default: `.body`). /// - emphasis: The text emphasis/color (default: `.primary`). - public init( - _ icon: String, - _ text: String, + /// - Returns: A styled Label view. + func styled( _ typography: Typography = .body, emphasis: TextEmphasis = .primary - ) { - self.icon = icon - self.text = text - self.typography = typography - self.emphasis = emphasis - } - - public var body: some View { - Label(text, systemImage: icon) + ) -> some View { + self .font(typography.font) .foregroundStyle(emphasis.color) } @@ -137,8 +107,7 @@ public struct SectionHeader: View { } Text(title) - .font(Typography.caption.font) - .foregroundStyle(Theme.Text.secondary) + .styled(.caption, emphasis: .secondary) .textCase(.uppercase) .tracking(0.5) } @@ -147,41 +116,57 @@ public struct SectionHeader: View { // MARK: - Previews -#Preview("Styled Labels") { +#Preview("Text.styled()") { VStack(alignment: .leading, spacing: Design.Spacing.medium) { Group { - StyledLabel("Hero Bold", .heroBold) - StyledLabel("Title Bold", .titleBold) - StyledLabel("Title 2", .title2) - StyledLabel("Heading", .heading) - StyledLabel("Heading Emphasis", .headingEmphasis) + Text("Hero Bold").styled(.heroBold) + Text("Title Bold").styled(.titleBold) + Text("Title 2").styled(.title2) + Text("Heading").styled(.heading) + Text("Heading Emphasis").styled(.headingEmphasis) } Divider() Group { - StyledLabel("Body", .body) - StyledLabel("Body Emphasis", .bodyEmphasis) - StyledLabel("Subheading", .subheading, emphasis: .secondary) - StyledLabel("Caption", .caption, emphasis: .secondary) - StyledLabel("Caption 2", .caption2, emphasis: .tertiary) + Text("Body").styled(.body) + Text("Body Emphasis").styled(.bodyEmphasis) + Text("Subheading").styled(.subheading, emphasis: .secondary) + Text("Caption").styled(.caption, emphasis: .secondary) + Text("Caption 2").styled(.caption2, emphasis: .tertiary) } Divider() Group { - StyledLabel("Custom Color", .body, emphasis: .custom(.orange)) - StyledLabel("Disabled", .body, emphasis: .disabled) + Text("Custom Color").styled(.body, emphasis: .custom(.orange)) + Text("Disabled").styled(.body, emphasis: .disabled) + } + + Divider() + + Group { + Text("Count: \(42)").styled(.heading) + Text("UPPERCASE") + .styled(.captionEmphasis, emphasis: .secondary) + .textCase(.uppercase) + .tracking(0.5) + Text("$9.99") + .styled(.subheadingEmphasis) + .fontDesign(.rounded) } } .padding() } -#Preview("Icon Labels") { +#Preview("Label.styled()") { VStack(alignment: .leading, spacing: Design.Spacing.medium) { - IconLabel("bell.fill", "Notifications", .subheading) - IconLabel("star.fill", "Favorites", .body, emphasis: .secondary) - IconLabel("gear", "Settings", .caption) + Label("Notifications", systemImage: "bell.fill") + .styled(.subheading) + Label("Favorites", systemImage: "star.fill") + .styled(.body, emphasis: .secondary) + Label("Settings", systemImage: "gear") + .styled(.caption) } .padding() }