Go to file
2026-01-02 11:59:29 -06:00
Sources/Bedrock Initial commit: Bedrock design system and UI component library 2026-01-02 11:58:30 -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 Update README with complete feature documentation 2026-01-02 11:59:29 -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 and haptic feedback management
  • Onboarding: Track user onboarding progress and contextual hints
  • Cloud Sync: Generic iCloud and local data synchronization
  • Visual Effects: Confetti, pulsing animations, debug borders
  • Utilities: Device detection, debugging helpers, and more

Installation

Add Bedrock as a dependency in your Package.swift:

dependencies: [
    .package(url: "https://github.com/yourname/Bedrock.git", from: "1.0.0")
]

Or for local development:

dependencies: [
    .package(path: "../Bedrock")
]

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)

Sound & Haptic Feedback

Bedrock provides a generic sound manager that works with any app-defined sounds:

// Define your app's sounds
enum MySound: String, AppSound {
    case tap, success, error
    
    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(MySound.success)
soundManager.playHaptic(.success)

Onboarding State

Track user onboarding and progressive feature discovery:

let onboarding = OnboardingState(appIdentifier: "myApp")

// Register all hint keys for skip functionality
onboarding.registerHintKeys("welcome", "feature1", "feature2")

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

// Skip or complete onboarding
onboarding.completeWelcome()  // Mark as completed
onboarding.skipOnboarding()    // Skip all hints

Cloud Sync

Synchronize data between iCloud and local storage:

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

// Use the cloud sync manager
let syncManager = CloudSyncManager<MyAppData>()
await syncManager.save(myData)
let loaded = await syncManager.load()

Visual Effects

Confetti

ZStack {
    MainContentView()
    
    if showCelebration {
        ConfettiView(colors: [.red, .blue, .green, .yellow])
    }
}

Pulsing Animation

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

Debug Borders

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

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: [("Light", "light"), ("Dark", "dark"), ("Auto", "auto")],
    selection: $theme
)

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

Device Detection

Adapt your UI based on device characteristics:

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

let bounds = DeviceInfo.screenBounds
let isLandscape = DeviceInfo.isLandscape

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

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

Requirements

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

License

MIT License