Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ab92983
add background style to su modals
mikhailChelbaev Jun 5, 2026
a159da7
add background style to `UKModalController`
mikhailChelbaev Jun 5, 2026
83c2592
add alert background styles
mikhailChelbaev Jun 5, 2026
c0d83df
add background style picker helper
mikhailChelbaev Jun 5, 2026
8e3f4ca
fix blur background when background color is applied
mikhailChelbaev Jun 5, 2026
d818ac5
add background style in cards
mikhailChelbaev Jun 5, 2026
0153bfe
add background style in buttons
mikhailChelbaev Jun 5, 2026
4c31088
refactor: share SwiftUI component backgrounds
mikhailChelbaev Jun 5, 2026
c1ace08
refactor: share UIKit background styling
mikhailChelbaev Jun 5, 2026
f815aa2
address warning about custom tap animations in buttons
mikhailChelbaev Jun 5, 2026
83a36e0
Merge pull request #113 from componentskit/liquid-glass/modals
mikhailChelbaev Jun 5, 2026
e9e6022
Merge pull request #114 from componentskit/liquid-glass/cards
mikhailChelbaev Jun 5, 2026
413b69c
Merge pull request #115 from componentskit/liquid-glass/buttons
mikhailChelbaev Jun 5, 2026
33a311c
remove deprecations
mikhailChelbaev Jun 5, 2026
f6c9eb7
Merge pull request #116 from componentskit/liquid-glass/improvements
mikhailChelbaev Jun 5, 2026
2ff535a
Merge pull request #118 from componentskit/clean-up-deprecations
mikhailChelbaev Jun 6, 2026
62eae19
make uk classes `open`
mikhailChelbaev Jun 6, 2026
d936146
address compilation errors
mikhailChelbaev Jun 6, 2026
89f7fdf
add `backgroundStyle` to `AlertButtonVM`
mikhailChelbaev Jun 6, 2026
25ab597
run swiftlint
mikhailChelbaev Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct ModalPreviewHelpers {
Text("Warning Background").tag(UniversalColor.warningBackground)
Text("Danger Background").tag(UniversalColor.dangerBackground)
}
BackgroundStylePicker(selection: self.$model.backgroundStyle)
BorderWidthPicker(selection: self.$model.borderWidth)
Toggle("Closes On Overlay Tap", isOn: self.$model.closesOnOverlayTap)
.disabled(self.footer == nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ struct AutocapitalizationPicker: View {
}
}

// MARK: - BackgroundStylePicker

struct BackgroundStylePicker: View {
@Binding var selection: ComponentsKit.BackgroundStyle

var body: some View {
Picker("Background Style", selection: self.$selection) {
Text("Solid").tag(ComponentsKit.BackgroundStyle.solid)
Text("Blur").tag(ComponentsKit.BackgroundStyle.blur)
if #available(iOS 26.0, *) {
Text("Liquid Glass").tag(ComponentsKit.BackgroundStyle.liquidGlass)
}
}
}
}

// MARK: - BorderWidthPicker

struct BorderWidthPicker: View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct AlertPreview: View {
Text("Warning Background").tag(UniversalColor.warningBackground)
Text("Danger Background").tag(UniversalColor.dangerBackground)
}
BackgroundStylePicker(selection: self.$model.backgroundStyle)
BorderWidthPicker(selection: self.$model.borderWidth)
Toggle("Closes On Overlay Tap", isOn: self.$model.closesOnOverlayTap)
Picker("Content Paddings", selection: self.$model.contentPaddings) {
Expand All @@ -111,6 +112,7 @@ struct AlertPreview: View {
private func buttonPickers(for buttonVM: Binding<AlertButtonVM>) -> some View {
Group {
AnimationScalePicker(selection: buttonVM.animationScale)
BackgroundStylePicker(selection: buttonVM.backgroundStyle)
ComponentOptionalColorPicker(selection: buttonVM.color)
ComponentRadiusPicker(selection: buttonVM.cornerRadius) {
Text("Custom: 20px").tag(ComponentRadius.custom(20))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct ButtonPreview: View {
}
Form {
AnimationScalePicker(selection: self.$model.animationScale)
BackgroundStylePicker(selection: self.$model.backgroundStyle)
ComponentOptionalColorPicker(selection: self.$model.color)
Picker("Content Spacing", selection: self.$model.contentSpacing) {
Text("4").tag(CGFloat(4))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ struct CardPreview: View {
Form {
AnimationScalePicker(selection: self.$model.animationScale)
Picker("Background Color", selection: self.$model.backgroundColor) {
Text("Clear").tag(Optional<UniversalColor>.none)
Text("Background").tag(UniversalColor.background)
Text("Secondary Background").tag(UniversalColor.secondaryBackground)
Text("Accent Background").tag(UniversalColor.accentBackground)
Text("Success Background").tag(UniversalColor.successBackground)
Text("Warning Background").tag(UniversalColor.warningBackground)
Text("Danger Background").tag(UniversalColor.dangerBackground)
}
BackgroundStylePicker(selection: self.$model.backgroundStyle)
Picker("Border Color", selection: self.$model.borderColor) {
Text("Divider").tag(UniversalColor.divider)
Text("Primary").tag(UniversalColor.primary)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public struct AlertButtonVM: ComponentVM {
/// Defaults to `.medium`.
public var animationScale: AnimationScale = .medium

/// Defines how the button renders its background.
///
/// Defaults to `.solid`.
public var backgroundStyle: BackgroundStyle = .solid

/// The color of the button.
public var color: ComponentColor?

Expand Down
5 changes: 5 additions & 0 deletions Sources/ComponentsKit/Components/Alert/Models/AlertVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public struct AlertVM: ComponentVM {
/// The background color of the alert.
public var backgroundColor: UniversalColor?

/// Defines how the alert renders its background.
public var backgroundStyle: BackgroundStyle = .solid

/// The border thickness of the alert.
///
/// Defaults to `.small`.
Expand Down Expand Up @@ -61,6 +64,7 @@ extension AlertVM {
var modalVM: CenterModalVM {
return CenterModalVM {
$0.backgroundColor = self.backgroundColor
$0.backgroundStyle = self.backgroundStyle
$0.borderWidth = self.borderWidth
$0.closesOnOverlayTap = self.closesOnOverlayTap
$0.contentPaddings = self.contentPaddings
Expand Down Expand Up @@ -88,6 +92,7 @@ extension AlertVM {
return ButtonVM {
$0.title = model.title
$0.animationScale = model.animationScale
$0.backgroundStyle = model.backgroundStyle
$0.color = model.color
$0.cornerRadius = model.cornerRadius
$0.style = model.style
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import UIKit
///
/// vc.present(alert, animated: true)
/// ```
public class UKAlertController: UKCenterModalController {
open class UKAlertController: UKCenterModalController {
// MARK: - Properties

/// A model that defines the appearance properties for an alert.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,5 @@ extension AvatarVM {
///
/// - Parameter image: See ``UniversalImage``.
case local(_ image: UniversalImage)

/// An image loaded from a local asset.
@available(*, deprecated, message: "Use `local(_:)` instead.")
public static func local(_ name: String, _ bundle: Bundle? = nil) -> Self {
return .local(.init(name, bundle: bundle))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,5 @@ extension AvatarVM {
///
/// - Parameter image: See ``UniversalImage``.
case image(_ image: UniversalImage)

/// A placeholder that displays an SF Symbol.
@available(*, deprecated, message: "Use `image(_:)` instead.")
public static func sfSymbol(_ name: String) -> Self {
return .image(.init(systemName: name))
}

/// A placeholder that displays a custom icon from an asset catalog.
@available(*, deprecated, message: "Use `image(_:)` instead.")
public static func icon(_ name: String, _ bundle: Bundle? = nil) -> Self {
return .image(.init(name, bundle: bundle))
}
}
}
43 changes: 16 additions & 27 deletions Sources/ComponentsKit/Components/Button/Models/ButtonVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public struct ButtonVM: ComponentVM {
/// The color of the button.
public var color: ComponentColor?

/// Defines how the button renders its background.
///
/// Defaults to `.solid`.
public var backgroundStyle: BackgroundStyle = .solid

/// The spacing between the button's title and its image or loading indicator.
///
/// Defaults to `8.0`.
Expand All @@ -33,14 +38,6 @@ public struct ButtonVM: ComponentVM {
/// Defaults to `.leading`.
public var imageLocation: ImageLocation = .leading

/// Defines how image is rendered.
@available(*, deprecated, message: "Use `image.withRenderingMode(_:)` instead.")
public var imageRenderingMode: ImageRenderingMode?

/// The source of the image to be displayed.
@available(*, deprecated, message: "Use `image` instead.")
public var imageSrc: ImageSource?

/// A Boolean value indicating whether the button is enabled or disabled.
///
/// Defaults to `true`.
Expand Down Expand Up @@ -84,6 +81,14 @@ extension ButtonVM {
var isInteractive: Bool {
self.isEnabled && !self.isLoading
}
var isCustomTapAnimationEnabled: Bool {
switch self.backgroundStyle {
case .solid, .blur:
return true
case .liquidGlass:
return false
}
}
var preferredLoadingVM: LoadingVM {
return self.loadingVM ?? .init {
$0.color = .init(
Expand Down Expand Up @@ -187,30 +192,13 @@ extension ButtonVM {
}
}
}
var imageWithLegacyFallback: UniversalImage? {
if let image { return image }

guard let imageSrc else { return nil }

let image = switch imageSrc {
case .sfSymbol(let name):
UniversalImage(systemName: name)
case .local(let name, let bundle):
UniversalImage(name, bundle: bundle)
}
if let imageRenderingMode {
return image.withRenderingMode(imageRenderingMode)
} else {
return image
}
}
}

// MARK: UIKit Helpers

extension ButtonVM {
var isImageHidden: Bool {
return self.isLoading || self.imageWithLegacyFallback.isNil
return self.isLoading || self.image.isNil
}
func preferredSize(
for contentSize: CGSize,
Expand Down Expand Up @@ -243,9 +231,10 @@ extension ButtonVM {
|| self.font != oldModel.font
|| self.isFullWidth != oldModel.isFullWidth
|| self.isLoading != oldModel.isLoading
|| self.imageWithLegacyFallback != oldModel.imageWithLegacyFallback
|| self.image != oldModel.image
|| self.contentSpacing != oldModel.contentSpacing
|| self.title != oldModel.title
|| self.style != oldModel.style
}
}

Expand Down
59 changes: 26 additions & 33 deletions Sources/ComponentsKit/Components/Button/SUButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,32 @@ public struct SUButton: View {
HStack(spacing: self.model.contentSpacing) {
self.content
}
.font(self.model.preferredFont.font)
.lineLimit(1)
.padding(.horizontal, self.model.horizontalPadding)
.frame(maxWidth: self.model.width)
.frame(height: self.model.height)
.contentShape(.rect)
.foregroundStyle(self.model.foregroundColor.color)
.componentBackground(
shape: RoundedRectangle(cornerRadius: self.model.cornerRadius.value()),
backgroundStyle: self.model.backgroundStyle,
backgroundColor: self.model.backgroundColor?.color,
borderColor: self.model.borderColor?.color ?? .clear,
borderWidth: self.model.borderWidth,
isGlassInteractive: self.model.isInteractive
)
}
.buttonStyle(CustomButtonStyle(model: self.model))
.simultaneousGesture(DragGesture(minimumDistance: 0.0)
.onChanged { _ in
self.scale = self.model.animationScale.value
}
.onEnded { _ in
self.scale = 1.0
}
.buttonStyle(CustomButtonStyle())
.simultaneousGesture(
DragGesture(minimumDistance: 0.0)
.onChanged { _ in
self.scale = self.model.animationScale.value
}
.onEnded { _ in
self.scale = 1.0
},
isEnabled: self.model.isCustomTapAnimationEnabled
)
.disabled(!self.model.isInteractive)
.scaleEffect(self.scale, anchor: .center)
Expand All @@ -50,7 +67,7 @@ public struct SUButton: View {

@ViewBuilder
private var content: some View {
switch (self.model.isLoading, self.model.imageWithLegacyFallback, self.model.imageLocation) {
switch (self.model.isLoading, self.model.image, self.model.imageLocation) {
case (true, _, _) where self.model.title.isEmpty:
SULoading(model: self.model.preferredLoadingVM)
case (true, _, _):
Expand Down Expand Up @@ -109,31 +126,7 @@ private struct ButtonImage: View {
}

private struct CustomButtonStyle: SwiftUI.ButtonStyle {
let model: ButtonVM

func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(self.model.preferredFont.font)
.lineLimit(1)
.padding(.horizontal, self.model.horizontalPadding)
.frame(maxWidth: self.model.width)
.frame(height: self.model.height)
.contentShape(.rect)
.foregroundStyle(self.model.foregroundColor.color)
.background(self.model.backgroundColor?.color ?? .clear)
.clipShape(
RoundedRectangle(
cornerRadius: self.model.cornerRadius.value()
)
)
.overlay {
RoundedRectangle(
cornerRadius: self.model.cornerRadius.value()
)
.strokeBorder(
self.model.borderColor?.color ?? .clear,
lineWidth: self.model.borderWidth
)
}
}
}
Loading