forked from microsoft/fluentui-apple
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFluentButtonStyle.swift
More file actions
123 lines (105 loc) · 4.55 KB
/
FluentButtonStyle.swift
File metadata and controls
123 lines (105 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
import SwiftUI
import UIKit
/// `ButtonStyle` which configures the `Button` according to its state and design tokens.
public struct FluentButtonStyle: SwiftUI.ButtonStyle {
public init(style: ButtonStyle, isIconOnly: Bool = false) {
self.style = style
self.isIconOnly = isIconOnly
}
public func makeBody(configuration: Configuration) -> some View {
let isPressed = configuration.isPressed
let isDisabled = !isEnabled
let isFocused = isFocused
let size = size
let tokenSet = ButtonTokenSet(style: { style }, size: { size })
tokenSet.replaceAllOverrides(with: tokenOverrides)
tokenSet.update(fluentTheme)
let cornerRadius = tokenSet[.cornerRadius].float
let shadowToken = (isDisabled || isFocused || isPressed) ? ButtonToken.shadowPressed : ButtonToken.shadowRest
let shadowInfo = tokenSet[shadowToken].shadowInfo
let foregroundColor: Color
let borderColor: Color
let backgroundColor: Color
if isDisabled {
foregroundColor = Color(tokenSet[.foregroundDisabledColor].uiColor)
borderColor = Color(tokenSet[.borderDisabledColor].uiColor)
backgroundColor = Color(tokenSet[.backgroundDisabledColor].uiColor)
} else if isPressed || isFocused {
foregroundColor = Color(tokenSet[.foregroundPressedColor].uiColor)
borderColor = Color(tokenSet[.borderPressedColor].uiColor)
backgroundColor = Color(tokenSet[.backgroundPressedColor].uiColor)
} else {
foregroundColor = Color(tokenSet[.foregroundColor].uiColor)
borderColor = Color(tokenSet[.borderColor].uiColor)
backgroundColor = Color(tokenSet[.backgroundColor].uiColor)
}
@ViewBuilder var backgroundView: some View {
if backgroundColor != Color(.clear) {
backgroundColor.clipShape(RoundedRectangle(cornerRadius: cornerRadius))
}
}
@ViewBuilder var overlayView: some View {
if borderColor != Color(.clear) {
contentShape
.stroke(style: .init(lineWidth: tokenSet[.borderWidth].float))
.foregroundStyle(borderColor)
}
}
@ViewBuilder var contentShape: some Shape {
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
}
return configuration.label
.font(Font(tokenSet[.titleFont].uiFont))
.foregroundStyle(foregroundColor)
.padding(edgeInsets)
.frame(minHeight: ButtonTokenSet.minContainerHeight(style: style, size: size))
.background(backgroundView)
.overlay { overlayView }
.applyFluentShadow(shadowInfo: shadowInfo)
.contentShape(contentShape)
.pointerInteraction(isEnabled)
}
@Environment(\.controlSize) private var controlSize: ControlSize
@Environment(\.fluentTheme) private var fluentTheme: FluentTheme
@Environment(\.isEnabled) private var isEnabled: Bool
@Environment(\.isFocused) private var isFocused: Bool
private let style: ButtonStyle
private let isIconOnly: Bool
private var size: ButtonSizeCategory {
switch controlSize {
case .mini, .small:
return .small
case .regular:
return .medium
case .large, .extraLarge:
return .large
@unknown default:
assertionFailure("Unknown SwiftUI.ControlSize: \(controlSize). Reverting to .medium")
return .medium
}
}
private var edgeInsets: EdgeInsets {
let size = size
let horizontalPadding = ButtonTokenSet.horizontalPadding(style: style, size: size)
let fabAlternativePadding = ButtonTokenSet.fabAlternativePadding(size)
// If the button is floating and includes text, use fabAlternativePadding; otherwise, use horizontalPadding.
let trailingPadding = style.isFloating && !isIconOnly ? fabAlternativePadding : horizontalPadding
return EdgeInsets(
top: .zero,
leading: horizontalPadding,
bottom: .zero,
trailing: trailingPadding
)
}
private var tokenOverrides: [ButtonToken: ControlTokenValue]?
}
public extension FluentButtonStyle {
/// Provide override values for various `ButtonToken` values.
mutating func overrideTokens(_ overrides: [ButtonToken: ControlTokenValue]) {
tokenOverrides = overrides
}
}