Add Primary/Secondary/Tertiary/QuaternaryContentStyle (#419)

This commit is contained in:
Carson Katri 2021-07-07 18:44:34 -04:00 committed by GitHub
parent 4a7748ad6b
commit 2efa80a57d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 195 additions and 22 deletions

View File

@ -74,6 +74,9 @@ public extension View {
}
public func modifyEnvironment(_ values: inout EnvironmentValues) {
values._backgroundStyle = .init(styles: [style, style, style], environment: values)
values._backgroundStyle = .init(
styles: (primary: style, secondary: style, tertiary: style),
environment: values
)
}
}

View File

@ -0,0 +1,104 @@
// Copyright 2020-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Created by Carson Katri on 7/7/21.
//
@frozen public struct PrimaryContentStyle {
@inlinable
public init() {}
}
extension PrimaryContentStyle: ShapeStyle {
public func _apply(to shape: inout _ShapeStyle_Shape) {
if !shape.inRecursiveStyle,
let foregroundStyle = shape.environment._foregroundStyle
{
if foregroundStyle.styles.primary is Self {
shape.inRecursiveStyle = true
}
foregroundStyle.styles.primary._apply(to: &shape)
} else {
shape.result = .color(shape.environment.foregroundColor ?? .primary)
}
}
public static func _apply(to shape: inout _ShapeStyle_ShapeType) {}
}
@frozen public struct SecondaryContentStyle {
@inlinable
public init() {}
}
extension SecondaryContentStyle: ShapeStyle {
public func _apply(to shape: inout _ShapeStyle_Shape) {
if !shape.inRecursiveStyle,
let foregroundStyle = shape.environment._foregroundStyle
{
if foregroundStyle.styles.secondary is Self {
shape.inRecursiveStyle = true
}
foregroundStyle.styles.secondary._apply(to: &shape)
} else {
shape.result = .color((shape.environment.foregroundColor ?? .primary).opacity(0.5))
}
}
public static func _apply(to shape: inout _ShapeStyle_ShapeType) {}
}
@frozen public struct TertiaryContentStyle {
@inlinable
public init() {}
}
extension TertiaryContentStyle: ShapeStyle {
public func _apply(to shape: inout _ShapeStyle_Shape) {
if !shape.inRecursiveStyle,
let foregroundStyle = shape.environment._foregroundStyle
{
if foregroundStyle.styles.tertiary is Self {
shape.inRecursiveStyle = true
}
foregroundStyle.styles.tertiary._apply(to: &shape)
} else {
shape.result = .color((shape.environment.foregroundColor ?? .primary).opacity(0.3))
}
}
public static func _apply(to shape: inout _ShapeStyle_ShapeType) {}
}
@frozen public struct QuaternaryContentStyle {
@inlinable
public init() {}
}
extension QuaternaryContentStyle: ShapeStyle {
public func _apply(to shape: inout _ShapeStyle_Shape) {
if !shape.inRecursiveStyle,
let foregroundStyle = shape.environment._foregroundStyle
{
if foregroundStyle.styles.tertiary is Self {
shape.inRecursiveStyle = true
}
foregroundStyle.styles.tertiary._apply(to: &shape)
} else {
shape.result = .color((shape.environment.foregroundColor ?? .primary).opacity(0.2))
}
}
public static func _apply(to shape: inout _ShapeStyle_ShapeType) {}
}

View File

@ -60,24 +60,36 @@ public extension View {
}
@inlinable
func foregroundStyle<S1, S2, S3>(_ primary: S1, _ secondary: S2,
_ tertiary: S3) -> some View
func foregroundStyle<S1, S2, S3>(
_ primary: S1,
_ secondary: S2,
_ tertiary: S3
) -> some View
where S1: ShapeStyle, S2: ShapeStyle, S3: ShapeStyle
{
modifier(_ForegroundStyleModifier(styles: [primary, secondary, tertiary]))
modifier(_ForegroundStyleModifier(primary: primary, secondary: secondary, tertiary: tertiary))
}
}
@frozen public struct _ForegroundStyleModifier: ViewModifier, EnvironmentModifier {
public var styles: [ShapeStyle]
@frozen public struct _ForegroundStyleModifier<Primary, Secondary, Tertiary>: ViewModifier,
EnvironmentModifier
where Primary: ShapeStyle, Secondary: ShapeStyle, Tertiary: ShapeStyle
{
public var primary: Primary
public var secondary: Secondary
public var tertiary: Tertiary
@inlinable
public init(styles: [ShapeStyle]) {
self.styles = styles
public init(
primary: Primary,
secondary: Secondary,
tertiary: Tertiary
) {
(self.primary, self.secondary, self.tertiary) = (primary, secondary, tertiary)
}
public typealias Body = Never
public func modifyEnvironment(_ values: inout EnvironmentValues) {
values._foregroundStyle = .init(styles: styles, environment: values)
values._foregroundStyle = .init(styles: (primary, secondary, tertiary), environment: values)
}
}

View File

@ -23,23 +23,23 @@ public protocol ShapeStyle {
}
public struct AnyShapeStyle: ShapeStyle {
let styles: [ShapeStyle]
let styles: (primary: ShapeStyle, secondary: ShapeStyle, tertiary: ShapeStyle)
var stylesArray: [ShapeStyle] {
[styles.primary, styles.secondary, styles.tertiary]
}
let environment: EnvironmentValues
public func _apply(to shape: inout _ShapeStyle_Shape) {
shape.environment = environment
if styles.count > 1 {
let results = styles.map { style -> _ShapeStyle_Shape.Result in
var copy = shape
style._apply(to: &copy)
return copy.result
}
shape
.result =
.resolved(.array(results.compactMap { $0.resolvedStyle(on: shape, in: environment) }))
} else if let first = styles.first {
first._apply(to: &shape)
let results = stylesArray.map { style -> _ShapeStyle_Shape.Result in
var copy = shape
style._apply(to: &copy)
return copy.result
}
shape
.result =
.resolved(.array(results.compactMap { $0.resolvedStyle(on: shape, in: environment) }))
switch shape.operation {
case let .prepare(text, level):
@ -50,7 +50,9 @@ public struct AnyShapeStyle: ShapeStyle {
shape.result = .prepared(Text(storage: text.storage, modifiers: modifiers))
case let .resolveStyle(levels):
if case let .resolved(resolved) = shape.result {
if case let .array(children) = resolved {
if case let .array(children) = resolved,
children.count >= levels.upperBound
{
shape.result = .resolved(.array(.init(children[levels])))
}
} else if let resolved = shape.result.resolvedStyle(on: shape, in: environment) {

View File

@ -83,7 +83,16 @@ public typealias Rectangle = TokamakCore.Rectangle
public typealias RoundedRectangle = TokamakCore.RoundedRectangle
public typealias ContainerRelativeShape = TokamakCore.ContainerRelativeShape
// MARK: Shape Styles
public typealias PrimaryContentStyle = TokamakCore.PrimaryContentStyle
public typealias SecondaryContentStyle = TokamakCore.SecondaryContentStyle
public typealias TertiaryContentStyle = TokamakCore.TertiaryContentStyle
public typealias QuaternaryContentStyle = TokamakCore.QuaternaryContentStyle
public typealias ForegroundStyle = TokamakCore.ForegroundStyle
public typealias BackgroundStyle = TokamakCore.BackgroundStyle
public typealias Material = TokamakCore.Material
// MARK: Primitive values

View File

@ -89,6 +89,18 @@ struct ShapeStyleDemo: View {
}
}
}
HStack {
VStack {
Text("Primary")
.foregroundStyle(PrimaryContentStyle())
Text("Secondary")
.foregroundStyle(SecondaryContentStyle())
Text("Tertiary")
.foregroundStyle(TertiaryContentStyle())
Text("Quaternary")
.foregroundStyle(QuaternaryContentStyle())
}
}
#endif
}
}

View File

@ -44,7 +44,16 @@ public typealias Rectangle = TokamakCore.Rectangle
public typealias RoundedRectangle = TokamakCore.RoundedRectangle
public typealias ContainerRelativeShape = TokamakCore.ContainerRelativeShape
// MARK: Shape Styles
public typealias PrimaryContentStyle = TokamakCore.PrimaryContentStyle
public typealias SecondaryContentStyle = TokamakCore.SecondaryContentStyle
public typealias TertiaryContentStyle = TokamakCore.TertiaryContentStyle
public typealias QuaternaryContentStyle = TokamakCore.QuaternaryContentStyle
public typealias ForegroundStyle = TokamakCore.ForegroundStyle
public typealias BackgroundStyle = TokamakCore.BackgroundStyle
public typealias Material = TokamakCore.Material
// MARK: Primitive values

View File

@ -200,6 +200,28 @@ final class RenderingTests: XCTestCase {
)
}
func testContentStyles() {
assertSnapshot(
matching: HStack {
Rectangle()
.frame(width: 50, height: 50)
.foregroundStyle(PrimaryContentStyle())
Rectangle()
.frame(width: 50, height: 50)
.foregroundStyle(SecondaryContentStyle())
Rectangle()
.frame(width: 50, height: 50)
.foregroundStyle(TertiaryContentStyle())
Rectangle()
.frame(width: 50, height: 50)
.foregroundStyle(QuaternaryContentStyle())
}
.foregroundColor(.blue),
as: .image(size: .init(width: 275, height: 100)),
timeout: defaultSnapshotTimeout
)
}
func testMaterial() {
assertSnapshot(
matching: ZStack {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB