Skip to content

Commit f8b643e

Browse files
authored
feat: Add UserInterfaceOverridingElement (#545)
Adds a `UserInterfaceStyleOverridingElement` and a `overrideUserInterfaceStyle()` extension on `Element` so that subtrees of views can have their `userInterfaceStyle` (i.e. light/dark) overridden a la SwiftUI's `colorScheme` environment variable.
1 parent f07fc7b commit f8b643e

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import BlueprintUI
2+
import UIKit
3+
4+
/// An element that allows overriding the user interface style (light/dark mode) for its wrapped content.
5+
///
6+
/// Use this element to force a specific appearance for a portion of your UI, regardless of the system-wide
7+
/// settings. This can be useful when you need to ensure certain UI elements maintain a consistent appearance
8+
/// across different user interface styles.
9+
///
10+
/// Example:
11+
/// ```swift
12+
/// let content = Label(text: "Hello, World!")
13+
/// let forcedLightMode = UserInterfaceStyleOverridingElement(
14+
/// userInterfaceStyle: .light,
15+
/// wrapping: content
16+
/// )
17+
/// ```
18+
public struct UserInterfaceStyleOverridingElement: Element {
19+
20+
/// The element being wrapped with the overridden interface style.
21+
public var wrappedElement: Element
22+
23+
/// The user interface style to apply to the wrapped content.
24+
/// This can be `.light`, `.dark`, or `.unspecified`.
25+
public var userInterfaceStyle: UIUserInterfaceStyle
26+
27+
/// Creates a new element that overrides the user interface style for its wrapped content.
28+
///
29+
/// - Parameters:
30+
/// - userInterfaceStyle: The desired interface style to apply (`.light`, `.dark`, or `.unspecified`).
31+
/// - wrapping: The content whose interface style should be overridden.
32+
public init(
33+
userInterfaceStyle: UIUserInterfaceStyle,
34+
wrapping content: () -> (Element)
35+
) {
36+
self.userInterfaceStyle = userInterfaceStyle
37+
wrappedElement = content()
38+
}
39+
40+
public var content: ElementContent {
41+
ElementContent(child: wrappedElement)
42+
}
43+
44+
public func backingViewDescription(with context: ViewDescriptionContext) -> ViewDescription? {
45+
UIView.describe { config in
46+
config[\.overrideUserInterfaceStyle] = userInterfaceStyle
47+
}
48+
}
49+
}
50+
51+
extension Element {
52+
/// Wraps this element in a `UserInterfaceStyleOverridingElement` to override its interface style.
53+
///
54+
/// This method provides a convenient way to override the user interface style (light/dark mode)
55+
/// for any element.
56+
///
57+
/// Example:
58+
/// ```swift
59+
/// Label(text: "Always Light Mode")
60+
/// .overrideUserInterfaceStyle(.light)
61+
/// ```
62+
///
63+
/// - Parameter override: The desired interface style to apply. Defaults to `.unspecified`.
64+
/// - Returns: A new element wrapped with the specified interface style override.
65+
public func overrideUserInterfaceStyle(
66+
_ override: UIUserInterfaceStyle = .unspecified
67+
) -> UserInterfaceStyleOverridingElement {
68+
UserInterfaceStyleOverridingElement(userInterfaceStyle: override) {
69+
self
70+
}
71+
}
72+
}

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
### Added
13+
- Added `UserInterfaceStyleOverridingElement` which allows child elements to have their `userInterfaceStyle` to be forced to light/dark. Additionally added a `overrideUserInterfaceStyle` convenience to `Element`.
1314

1415
### Removed
1516
- `AccessibilityElement.deprecated_accessibility(…)`. This was deprecated in September 2021, and renamed from .accessibility(…) to .deprecated_accessibility(…) in Oct 2024.

0 commit comments

Comments
 (0)