ThemeKitSwiftUI.ThemeApplierrenders the default variant's color scheme for the current system scheme until a value is persisted, so a first launch no longer renders its first frame infallback.colorSchemeand then flips, which could leave macOS window titles and sidebar text resolved for the wrong appearanceThemeKitSwiftUI.ThemeApplierapplies the stored default variant's color scheme on first appear instead of relying ononChange(of:), which did not fire when that value equalledfallbackand leftNSApplication.shared.appearance/UIWindow.overrideUserInterfaceStyleunset for the first sessionThemeKitUIKit.ThemeAppliersets the window'soverrideUserInterfaceStylefor the stored default variant on first appear, instead of leaving it unset until the theme next changed, because theme observation starts afteronAppear()
- watchOS 10+ support for the
ThemeKitandThemeKitSwiftUIproducts - A standalone
ExampleWatchapp demonstrating persisted, watch-appropriate palette selection - watchOS integration builds on both existing CI toolchain lanes
- A watchOS UI smoke test that verifies the standalone example installs and launches
- SwiftUI appearance side effects now use explicit iOS and macOS branches, with watchOS relying on the scoped SwiftUI color-scheme environment
- UIKit-only appearance APIs and tests are now explicitly restricted to iOS
- The standalone watchOS example now declares itself watch-only so it installs without a companion iOS app
ThemeKitUIKit.ThemeAppliercapturesselfexplicitly inside itswithObservationTrackingchange handler, avoiding an implicit-self warning under strict concurrency- CI now runs the test matrix against macOS 15 (iPhone 16 simulator) and macOS 26 (iPhone 17 simulator)
- Lowered
swift-tools-versionfrom 6.3 to 6.0 so the package resolves on Swift 6.0, 6.1, and 6.2 toolchains
- macOS 14+ support —
ThemeKitandThemeKitSwiftUInow compile and run on macOS;ThemeKitUIKitremains iOS-only ThemeKitSwiftUI.ThemeApplierusesNSWindow.appearanceon macOS to force the window appearance, matching theUIWindow.overrideUserInterfaceStylebehaviour on iOSSystemColorScheme.uiUserInterfaceStyleandSystemColorScheme.init(_ style:)are now conditionally compiled on UIKit platforms onlyUIColor(hex:),UIColor.hex, andCodableColorare now conditionally compiled on UIKit platforms only- macOS test run added to CI (
swift test --arch arm64) alongside the existing iOS Simulator run
Package.swiftplatforms updated to[.iOS(.v17), .macOS(.v14)]
Initial release.
Theme—@Observable @MainActorcentral store backed byUserDefaults. Supports customThemeStoragebackends for testing or alternative persistence (Keychain, CloudKit, etc.)ThemeExtensionprotocol — define anyCodable & Equatable & Sendablestruct as a block of theme values (colors, fonts, spacing, image names, etc.)ThemeVariantprotocol — pair a light and darkThemeExtensionvalue under a stable ID for preset-based theming and relaunch restorationThemeOverridableprotocol andProp<T>— declare per-field user overrides; drivesTheme.merge(_:)andcompare(to:)for detecting drift from a presetSystemColorScheme—Codablelight/dark enum bridgingUIUserInterfaceStyleand SwiftUIColorSchemeCodableColorproperty wrapper — storesUIColoras a hex integer forCodablesynthesis in UIKitThemeExtensiontypesUIColor(hex:alpha:)andUIColor.hex— hex integer convenience API- ThemeKitSwiftUI:
ThemeApplierViewModifierand.applyTheme(_:default:available:)view modifier; retroactiveColor: Codableconformance encoding as hex integer;Color(hex:)initializer;SystemColorScheme↔ColorSchemebridging - ThemeKitUIKit:
ThemeApplierclass withonAppear(),onChangeOfThemeState(), andonChangeOfSystemUserInterfaceStyle()lifecycle hooks; Combine-based trait change publisher - Three appearance modes across both appliers:
.firstLaunch(applies default variant),.followingSystem(tracks system light/dark),.forced(locks to the active extension'scolorScheme) - Full test coverage for
Theme, bothThemeApplierimplementations,CodableColor, and hex round-trips