Go to file
Matt Bruce 40d1285c38 Fix Swift 6 concurrency warning for showDebugLogs
Mark showDebugLogs as nonisolated(unsafe) to resolve the 'static property is not concurrency-safe' error. This is appropriate for a debug flag that is typically set once at app launch.
2026-01-04 12:36:22 -06:00
Sources/Bedrock Fix Swift 6 concurrency warning for showDebugLogs 2026-01-04 12:36:22 -06:00
Tests/BedrockTests Initial commit: Bedrock design system and UI component library 2026-01-02 11:58:30 -06:00
.gitignore Initial commit: Bedrock design system and UI component library 2026-01-02 11:58:30 -06:00
Package.swift Initial commit: Bedrock design system and UI component library 2026-01-02 11:58:30 -06:00
README.md docs: Update README with complete feature documentation 2026-01-02 11:59:57 -06:00

Bedrock

A foundational design system and UI component library for building consistent, beautiful SwiftUI applications.

Overview

Bedrock is designed to be the foundation upon which apps are built, providing:

  • Design System: Consistent spacing, typography, colors, and animations
  • Color Protocols: Define consistent color naming with custom palettes per app
  • Settings Components: Ready-to-use toggle, picker, and selector views
  • Sound & Haptics: Generic sound manager with haptic feedback support
  • Onboarding: First-time user experience and contextual hints
  • Cloud Sync: Generic iCloud data synchronization
  • Visual Effects: Confetti celebrations, pulsing animations
  • Utilities: Device detection, debugging tools, and more

Installation

Add Bedrock as a dependency in your Package.swift:

dependencies: [
    .package(url: "ssh://git@192.168.1.128:220/mbrucedogs/Bedrock.git", branch: "master")
]

Then add it to your target:

.target(
    name: "YourApp",
    dependencies: ["Bedrock"]
)

Usage

Design Constants

Use the Design enum for consistent spacing, sizing, and styling:

import Bedrock

struct MyView: View {
    var body: some View {
        VStack(spacing: Design.Spacing.medium) {
            Text("Hello")
                .font(.system(size: Design.BaseFontSize.title))
                .padding(Design.Spacing.large)
            
            Button("Tap Me") { }
                .clipShape(.rect(cornerRadius: Design.CornerRadius.medium))
        }
    }
}

Color System

Bedrock provides a protocol-based color system that enforces consistent naming while allowing apps to define their own palettes.

Using Default Colors

Bedrock includes neutral default colors that work out of the box:

Text("Primary Text")
    .foregroundStyle(Color.Text.primary)

Text("Secondary Text")
    .foregroundStyle(Color.Text.secondary)

VStack { }
    .background(Color.Surface.primary)

Creating Custom Color Themes

Apps can define custom color palettes by conforming to the color protocols:

// Define custom accent colors
public enum MyAppAccentColors: AccentColorProvider {
    public static let primary = Color(red: 0.9, green: 0.75, blue: 0.3)
    public static let light = Color(red: 1.0, green: 0.85, blue: 0.4)
    public static let dark = Color(red: 0.7, green: 0.55, blue: 0.2)
    public static let secondary = Color(red: 0.2, green: 0.7, blue: 0.7)
}

// Create a complete theme
public enum MyAppTheme: AppColorTheme {
    public typealias Surface = DefaultSurfaceColors     // Reuse Bedrock defaults
    public typealias Text = DefaultTextColors
    public typealias Accent = MyAppAccentColors         // Custom accents
    public typealias Button = DefaultButtonColors
    public typealias Status = DefaultStatusColors
    public typealias Border = DefaultBorderColors
    public typealias Interactive = DefaultInteractiveColors
}

// Use in views
Button("Action") { }
    .background(MyAppTheme.Accent.primary)

Available Color Protocols

Protocol Properties
SurfaceColorProvider primary, secondary, tertiary, overlay, card, groupedFill, sectionFill
TextColorProvider primary, secondary, tertiary, disabled, placeholder, inverse
AccentColorProvider primary, light, dark, secondary
ButtonColorProvider primaryLight, primaryDark, secondary, destructive, cancelText
StatusColorProvider success, warning, error, info
BorderColorProvider subtle, standard, emphasized, selected
InteractiveColorProvider selected, hover, pressed, focus

Sound & Haptics

Generic sound manager that works with any app-defined sounds:

// Define your app's sounds
enum MyAppSound: String, AppSound {
    case success, error, notification
    
    var resourceName: String { rawValue }
    var resourceExtension: String { "mp3" }
    var bundle: Bundle { .main }
    var fallbackSystemSoundID: UInt32? { nil }
}

// Play sounds and haptics
let soundManager = SoundManager.shared
soundManager.play(MyAppSound.success)
soundManager.playHaptic(.success)
soundManager.playHaptic(.light)

Onboarding State

Track first-time user experience and contextual hints:

@Observable
class AppState {
    let onboarding = OnboardingState(appIdentifier: "myApp")
    
    var showWelcome: Bool {
        !onboarding.hasCompletedWelcome
    }
}

// Register hints for skip functionality
onboarding.registerHintKeys("firstBet", "settings", "tutorial")

// Check if hints should show
if onboarding.shouldShowHint("firstBet") {
    // Show hint
    onboarding.markHintShown("firstBet")
}

// Complete onboarding
onboarding.completeWelcome()

Cloud Sync

Generic iCloud synchronization for app data:

// Define your persisted data
struct MyAppData: PersistableData {
    static var dataIdentifier = "myApp"
    static var empty = MyAppData()
    
    var syncPriority: Int { score }
    var lastModified: Date = .now
    var score: Int = 0
}

// Create sync manager
let syncManager = CloudSyncManager<MyAppData>()

// Access and modify data
syncManager.data.score += 10
syncManager.save()

Visual Effects

Confetti

ZStack {
    MainContentView()
    
    if showCelebration {
        ConfettiView(colors: [.red, .blue, .gold], count: 50)
    }
}

Pulsing Attention

Button("Tap Here") { }
    .pulsing(isActive: shouldHighlight, color: .white)

Settings Components

Ready-to-use settings UI components:

// Toggle with title and subtitle
SettingsToggle(
    title: "Notifications",
    subtitle: "Receive push notifications",
    isOn: $notificationsEnabled
)

// Volume slider
VolumePicker(label: "Volume", volume: $soundVolume)

// Segmented picker
SegmentedPicker(
    title: "Theme",
    options: [
        SegmentedOption(label: "Light", value: "light"),
        SegmentedOption(label: "Dark", value: "dark")
    ],
    selection: $theme
)

// Selectable row with badge
SelectableRow(
    title: "Premium Plan",
    subtitle: "Unlock all features",
    isSelected: plan == .premium,
    badge: { BadgePill(text: "$9.99", isSelected: plan == .premium) },
    action: { plan = .premium }
)

Debug Tools

MyComplexView()
    .debugBorder(isDebugMode, color: .red, label: "Header")

Device Detection

Adapt your UI based on device characteristics:

if DeviceInfo.isPad {
    SidebarView()
} else {
    TabBarView()
}

if DeviceInfo.isLandscape {
    HorizontalLayout()
}

Design System Reference

Spacing

Name Value Usage
xxxSmall 1pt Hairline spacing
xxSmall 2pt Minimal spacing
xSmall 4pt Tight spacing
small 8pt Compact spacing
medium 12pt Default spacing
large 16pt Comfortable spacing
xLarge 20pt Generous spacing
xxLarge 24pt Section spacing
xxxLarge 32pt Large section spacing

Opacity

Name Value Usage
verySubtle 0.05 Barely visible
subtle 0.1 Subtle backgrounds
hint 0.2 Hints and disabled states
light 0.3 Light overlays
medium 0.5 Medium emphasis
strong 0.7 Strong emphasis
heavy 0.8 Heavy overlays
almostFull 0.9 Nearly opaque

Animation

Name Value Usage
quick 0.3s Quick transitions
standard 0.5s Standard animations
springDuration 0.4s Spring animations
staggerDelay 0.1s Staggered animations

Requirements

  • iOS 18.0+
  • macOS 15.0+
  • Swift 6.0+

License

Proprietary - All rights reserved.