AttributedTextValueConstraint
A protocol for defining a constraint on the value of a certain attribute.
Declaration
protocol AttributedTextValueConstraint : Hashable, Sendable, AttributedTextFormattingDefinitionOverview
Used as an AttributedTextFormattingDefinition, this constrains the AttributeKey’s value using the constrain(_:)-(Attributes) function.
Given value constraints can read other attribute values, it is crucial to avoid mixing value constraints in a way where they create cyclic dependencies with undefined behavior. Thus, it is recommended to think about value constraints in the context of the AttributedTextFormattingDefinition they will be used in:
A simple constraint only accesses a single attribute. It can be made generic over the attribute scope so it can be reused in different AttributedTextFormattingDefinitions.
struct NoBlackOrWhiteForeground<Scope: AttributeScope>: AttributedTextValueConstraint {
typealias AttributeKey = AttributeScopes.SwiftUIAttributes.ForegroundColorAttribute
func constrain(
_ container: inout Attributes
) {
if container.foregroundColor == .white || container.foregroundColor == .black {
container.foregroundColor = .primary
}
}
}When the constraint needs to access other attribute values, it is recommended to define it on a specific attribute scope that is used for a single AttributedTextFormattingDefinition.
extension MyTextFormattingDefinition {
struct Scope: AttributeScope {
/* ... */
let foregroundColor: AttributeScopes.SwiftUIAttributes.ForegroundColorAttribute
let backgroundColor: AttributeScopes.SwiftUIAttributes.BackgroundColorAttribute
}
}
struct NoEqualForegroundAndBackground: AttributedTextValueConstraint {
typealias Scope = MyTextFormattingDefinition.Scope
typealias AttributeKey = AttributeScopes.SwiftUIAttributes.BackgroundColorAttribute
func constrain(
_ container: inout Attributes
) {
if let color = container.foregroundColor,
container.backgroundColor == color
{
container.backgroundColor = nil
}
}
}Constraints that access multiple attributes and are generic over the scope should document their dependencies so that the dependencies can be considered for the ordering of constraints in the body.
/// Makes the background color for all Genmoji blue.
///
/// - Note: This constraint depends on a valid adaptiveImageGlyph value.
struct BlueGenmojiBackgroundConstraint<Scope: AttributeScope>: AttributedTextValueConstraint {
typealias AttributeKey = AttributeScopes.SwiftUIAttributes
.BackgroundColorAttribute
func constrain(
_ container: inout Attributes
) {
if container[
AttributeScopes.SwiftUIAttributes.AdaptiveImageGlyphAttribute.self
] != nil {
container.backgroundColor = .blue
}
}
}