Skip to content

Commit a733af3

Browse files
authored
Add DynamicTypeSize (#215)
1 parent 037df1f commit a733af3

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//
2+
// DynamicTypeSize.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for iOS 18.0
6+
// Status: Complete
7+
// ID: B498FA81088CF7FADFFFFFC897E05C74 (SwiftUICore)
8+
9+
/// A Dynamic Type size, which specifies how large scalable content should be.
10+
///
11+
/// For more information, see
12+
/// [Typography](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/typography/)
13+
/// in the Human Interface Guidelines.
14+
public enum DynamicTypeSize: Hashable, Comparable, CaseIterable, Sendable {
15+
/// An extra small size.
16+
case xSmall
17+
18+
/// A small size.
19+
case small
20+
21+
/// A medium size.
22+
case medium
23+
24+
/// A large size.
25+
case large
26+
27+
/// An extra large size.
28+
case xLarge
29+
30+
/// An extra extra large size.
31+
case xxLarge
32+
33+
/// An extra extra extra large size.
34+
case xxxLarge
35+
36+
/// The first accessibility size.
37+
case accessibility1
38+
39+
/// The second accessibility size.
40+
case accessibility2
41+
42+
/// The third accessibility size.
43+
case accessibility3
44+
45+
/// The fourth accessibility size.
46+
case accessibility4
47+
48+
/// The fifth accessibility size.
49+
case accessibility5
50+
51+
/// A Boolean value indicating whether the size is one that is associated
52+
/// with accessibility.
53+
public var isAccessibilitySize: Bool {
54+
switch self {
55+
case .accessibility1, .accessibility2, .accessibility3, .accessibility4, .accessibility5: true
56+
default: false
57+
}
58+
}
59+
60+
package static var systemDefault: DynamicTypeSize {
61+
.large
62+
// CoreGlue2.shared.systemDefaultDynamicTypeSize
63+
}
64+
}
65+
66+
private struct DynamicTypeSizeKey: EnvironmentKey {
67+
static var defaultValue: DynamicTypeSize { .large }
68+
}
69+
70+
extension EnvironmentValues {
71+
public var dynamicTypeSize: DynamicTypeSize {
72+
get { self[DynamicTypeSizeKey.self] }
73+
set { self[DynamicTypeSizeKey.self] = newValue }
74+
}
75+
}
76+
77+
extension View {
78+
nonisolated public func dynamicTypeSize(_ size: DynamicTypeSize) -> some View {
79+
self.environment(\.dynamicTypeSize, size)
80+
}
81+
82+
nonisolated public func dynamicTypeSize<T>(_ range: T) -> some View where T: RangeExpression, T.Bound == DynamicTypeSize {
83+
self.transformEnvironment(\.dynamicTypeSize) { $0 = $0.clamped(to: range) }
84+
}
85+
}
86+
87+
private struct DynamicTypeSizeCollection: Collection {
88+
func index(after i: DynamicTypeSize) -> DynamicTypeSize {
89+
let index = DynamicTypeSize.allCases.firstIndex(of: i)!
90+
let targetIndex = index + 1
91+
let count = DynamicTypeSize.allCases.count
92+
let resultIndex = targetIndex < count ? targetIndex : count-1
93+
return DynamicTypeSize.allCases[resultIndex]
94+
}
95+
96+
subscript(position: DynamicTypeSize) -> Element {
97+
_read { yield position }
98+
}
99+
100+
typealias Index = DynamicTypeSize
101+
102+
typealias Element = DynamicTypeSize
103+
104+
var startIndex: Index { .small }
105+
106+
var endIndex: Index { .accessibility5 }
107+
}
108+
109+
extension DynamicTypeSize {
110+
package func clamped<T>(to range: T) -> DynamicTypeSize where T: RangeExpression, T.Bound == DynamicTypeSize {
111+
let bound = range.relative(to: DynamicTypeSizeCollection())
112+
113+
let upperBound: DynamicTypeSize
114+
if range.contains(bound.upperBound) {
115+
upperBound = bound.upperBound
116+
} else {
117+
let index = DynamicTypeSize.allCases.firstIndex(of: bound.upperBound)!
118+
let targetIndex = index + 1
119+
let resultIndex = max(0, index)
120+
upperBound = DynamicTypeSize.allCases[resultIndex]
121+
}
122+
return clamp(min: bound.lowerBound, max: upperBound)
123+
}
124+
}

0 commit comments

Comments
 (0)