Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ only_rules:
- is_disjoint

# Tuples shouldn’t have too many members. Create a custom type instead
- large_tuple
# - large_tuple

# Prefer using .last(where:) over .filter { }.last in collections
- last_where
Expand Down
1 change: 0 additions & 1 deletion Sources/ComponentsKit/Components/Card/SUCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ public struct SUCard<Content: View>: View {
self.content()
.padding(self.model.contentPaddings.edgeInsets)
.background(self.model.preferredBackgroundColor.color)
.background(UniversalColor.background.color)
.cornerRadius(self.model.cornerRadius.value)
.overlay(
RoundedRectangle(cornerRadius: self.model.cornerRadius.value)
Expand Down
15 changes: 2 additions & 13 deletions Sources/ComponentsKit/Components/Card/UKCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ open class UKCard: UIView, UKComponent {

/// The primary content of the card, provided as a custom view.
public let content: UIView
/// The container view that holds the card's content.
public let contentView = UIView()

// MARK: - Properties

Expand Down Expand Up @@ -65,8 +63,7 @@ open class UKCard: UIView, UKComponent {

/// Sets up the card's subviews.
open func setup() {
self.addSubview(self.contentView)
self.contentView.addSubview(self.content)
self.addSubview(self.content)

if #available(iOS 17.0, *) {
self.registerForTraitChanges([UITraitUserInterfaceStyle.self]) { (view: Self, _: UITraitCollection) in
Expand All @@ -80,15 +77,12 @@ open class UKCard: UIView, UKComponent {
/// Applies styling to the card's subviews.
open func style() {
Self.Style.mainView(self, model: self.model)
Self.Style.contentView(self.contentView, model: self.model)
}

// MARK: - Layout

/// Configures the layout.
open func layout() {
self.contentView.allEdges()

self.contentConstraints = LayoutConstraints.merged {
self.content.top(self.model.contentPaddings.top)
self.content.bottom(self.model.contentPaddings.bottom)
Expand Down Expand Up @@ -138,7 +132,7 @@ open class UKCard: UIView, UKComponent {
extension UKCard {
fileprivate enum Style {
static func mainView(_ view: UIView, model: Model) {
view.backgroundColor = UniversalColor.background.uiColor
view.backgroundColor = model.preferredBackgroundColor.uiColor
view.layer.cornerRadius = model.cornerRadius.value
view.layer.borderWidth = model.borderWidth.value
view.layer.borderColor = UniversalColor.divider.cgColor
Expand All @@ -147,10 +141,5 @@ extension UKCard {
view.layer.shadowColor = model.shadow.color.cgColor
view.layer.shadowOpacity = 1
}

static func contentView(_ view: UIView, model: Model) {
view.backgroundColor = model.preferredBackgroundColor.uiColor
view.layer.cornerRadius = model.cornerRadius.value
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ struct ModalContent<VM: ModalVM, Header: View, Body: View, Footer: View>: View {
}
.frame(maxWidth: self.model.size.maxWidth, alignment: .leading)
.background(self.model.preferredBackgroundColor.color)
.background(UniversalColor.background.color)
.clipShape(RoundedRectangle(cornerRadius: self.model.cornerRadius.value))
.overlay(
RoundedRectangle(cornerRadius: self.model.cornerRadius.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ struct ModalOverlay<VM: ModalVM>: View {
case .blurred:
Color.clear.background(.ultraThinMaterial)
case .transparent:
// Note: It can't be completely transparent as it won't receive touch gestures.
Color.black.opacity(0.0001)
// Note: The tap gesture isn't recognized when a completely transparent
// color is clicked. This can be fixed by calling contentShape, which
// defines the interactive area of the underlying view.
Color.clear.contentShape(.rect)
}
}
.ignoresSafeArea(.all)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ public class UKBottomModalController: UKModalController<BottomModalVM> {
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

self.container.transform = .init(translationX: 0, y: self.view.screenBounds.height)
self.contentView.transform = .init(translationX: 0, y: self.view.screenBounds.height)
self.overlay.alpha = 0
}

public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

UIView.animate(withDuration: self.model.transition.value) {
self.container.transform = .identity
self.contentView.transform = .identity
self.overlay.alpha = 1
}
}
Expand All @@ -84,7 +84,7 @@ public class UKBottomModalController: UKModalController<BottomModalVM> {
public override func setup() {
super.setup()

self.container.addGestureRecognizer(UIPanGestureRecognizer(
self.contentView.addGestureRecognizer(UIPanGestureRecognizer(
target: self,
action: #selector(self.handleDragGesture)
))
Expand All @@ -95,7 +95,7 @@ public class UKBottomModalController: UKModalController<BottomModalVM> {
public override func layout() {
super.layout()

self.container.bottom(self.model.outerPaddings.bottom, safeArea: true)
self.contentView.bottom(self.model.outerPaddings.bottom, safeArea: true)
}

// MARK: - UIViewController Methods
Expand All @@ -105,7 +105,7 @@ public class UKBottomModalController: UKModalController<BottomModalVM> {
completion: (() -> Void)? = nil
) {
UIView.animate(withDuration: self.model.transition.value) {
self.container.transform = .init(translationX: 0, y: self.view.screenBounds.height)
self.contentView.transform = .init(translationX: 0, y: self.view.screenBounds.height)
self.overlay.alpha = 0
} completion: { _ in
super.dismiss(animated: false)
Expand All @@ -117,25 +117,25 @@ public class UKBottomModalController: UKModalController<BottomModalVM> {

extension UKBottomModalController {
@objc private func handleDragGesture(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: self.container).y
let velocity = gesture.velocity(in: self.container).y
let translation = gesture.translation(in: self.contentView).y
let velocity = gesture.velocity(in: self.contentView).y
let offset = ModalAnimation.bottomModalOffset(translation, model: self.model)

switch gesture.state {
case .changed:
self.container.transform = .init(translationX: 0, y: offset)
self.contentView.transform = .init(translationX: 0, y: offset)
case .ended:
let viewHeight = self.container.frame.height
let viewHeight = self.contentView.frame.height
if ModalAnimation.shouldHideBottomModal(offset: offset, height: viewHeight, velocity: velocity, model: self.model) {
self.dismiss(animated: true)
} else {
UIView.animate(withDuration: 0.2) {
self.container.transform = .identity
self.contentView.transform = .identity
}
}
case .failed, .cancelled:
UIView.animate(withDuration: 0.2) {
self.container.transform = .identity
self.contentView.transform = .identity
}
default:
break
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ public class UKCenterModalController: UKModalController<CenterModalVM> {
super.viewWillAppear(animated)

self.overlay.alpha = 0
self.container.alpha = 0
self.contentView.alpha = 0
}

public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

UIView.animate(withDuration: self.model.transition.value) {
self.overlay.alpha = 1
self.container.alpha = 1
self.contentView.alpha = 1
}
}

Expand All @@ -88,11 +88,11 @@ public class UKCenterModalController: UKModalController<CenterModalVM> {
public override func layout() {
super.layout()

self.container.bottomAnchor.constraint(
self.contentView.bottomAnchor.constraint(
lessThanOrEqualTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -self.model.outerPaddings.bottom
).isActive = true
self.container.centerVertically()
self.contentView.centerVertically()
}

// MARK: - UIViewController Methods
Expand All @@ -103,7 +103,7 @@ public class UKCenterModalController: UKModalController<CenterModalVM> {
) {
UIView.animate(withDuration: self.model.transition.value) {
self.overlay.alpha = 0
self.container.alpha = 0
self.contentView.alpha = 0
} completion: { _ in
super.dismiss(animated: false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ open class UKModalController<VM: ModalVM>: UIViewController {
/// A model that defines the appearance properties.
public let model: VM

private var containerWidthConstraint: NSLayoutConstraint?
private var contentViewWidthConstraint: NSLayoutConstraint?

// MARK: - Subviews

Expand All @@ -24,10 +24,8 @@ open class UKModalController<VM: ModalVM>: UIViewController {
public var body = UIView()
/// The optional footer view of the modal.
public var footer: UIView?
/// The container view that holds the modal's content.
public let container = UIView()
/// The content view inside the container, holding the header, body, and footer.
public let content = UIView()
/// The content view, holding the header, body, and footer.
public let contentView = UIView()
/// A scrollable wrapper for the body content.
public let bodyWrapper: UIScrollView = ContentSizedScrollView()
/// The overlay view that appears behind the modal.
Expand Down Expand Up @@ -70,14 +68,13 @@ open class UKModalController<VM: ModalVM>: UIViewController {
/// Sets up the modal's subviews and gesture recognizers.
open func setup() {
self.view.addSubview(self.overlay)
self.view.addSubview(self.container)
self.container.addSubview(self.content)
self.view.addSubview(self.contentView)
if let header {
self.content.addSubview(header)
self.contentView.addSubview(header)
}
self.content.addSubview(self.bodyWrapper)
self.contentView.addSubview(self.bodyWrapper)
if let footer {
self.content.addSubview(footer)
self.contentView.addSubview(footer)
}

self.bodyWrapper.addSubview(self.body)
Expand All @@ -104,8 +101,7 @@ open class UKModalController<VM: ModalVM>: UIViewController {
/// Applies styling to the modal's subviews.
open func style() {
Self.Style.overlay(self.overlay, model: self.model)
Self.Style.container(self.container, model: self.model)
Self.Style.content(self.content, model: self.model)
Self.Style.contentView(self.contentView, model: self.model)
Self.Style.bodyWrapper(self.bodyWrapper)
}

Expand All @@ -114,7 +110,6 @@ open class UKModalController<VM: ModalVM>: UIViewController {
/// Configures the layout of the modal's subviews.
open func layout() {
self.overlay.allEdges()
self.content.allEdges()

if let header {
header.top(self.model.contentPaddings.top)
Expand Down Expand Up @@ -145,38 +140,38 @@ open class UKModalController<VM: ModalVM>: UIViewController {
self.bodyWrapper.horizontally()
self.bodyWrapper.setContentCompressionResistancePriority(.defaultLow, for: .vertical)

self.body.leading(self.model.contentPaddings.leading, to: self.container)
self.body.trailing(self.model.contentPaddings.trailing, to: self.container)
self.body.leading(self.model.contentPaddings.leading, to: self.contentView)
self.body.trailing(self.model.contentPaddings.trailing, to: self.contentView)

self.container.topAnchor.constraint(
self.contentView.topAnchor.constraint(
greaterThanOrEqualTo: self.view.safeAreaLayoutGuide.topAnchor,
constant: self.model.outerPaddings.top
).isActive = true
self.container.leadingAnchor.constraint(
self.contentView.leadingAnchor.constraint(
greaterThanOrEqualTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: self.model.outerPaddings.leading
).isActive = true
self.container.trailingAnchor.constraint(
self.contentView.trailingAnchor.constraint(
lessThanOrEqualTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -self.model.outerPaddings.trailing
).isActive = true
self.container.heightAnchor.constraint(
self.contentView.heightAnchor.constraint(
greaterThanOrEqualToConstant: 80
).isActive = true

self.containerWidthConstraint = self.container.width(self.model.size.maxWidth).width
self.containerWidthConstraint?.priority = .defaultHigh
self.contentViewWidthConstraint = self.contentView.width(self.model.size.maxWidth).width
self.contentViewWidthConstraint?.priority = .defaultHigh

self.bodyWrapper.widthAnchor.constraint(equalTo: self.container.widthAnchor).isActive = true
self.bodyWrapper.widthAnchor.constraint(equalTo: self.contentView.widthAnchor).isActive = true

self.container.centerHorizontally()
self.contentView.centerHorizontally()
}

open override func viewWillTransition(
to size: CGSize,
with coordinator: any UIViewControllerTransitionCoordinator
) {
self.containerWidthConstraint?.isActive = false
self.contentViewWidthConstraint?.isActive = false
super.viewWillTransition(to: size, with: coordinator)
}

Expand All @@ -188,11 +183,11 @@ open class UKModalController<VM: ModalVM>: UIViewController {
+ self.model.outerPaddings.leading
+ self.model.outerPaddings.trailing
if availableWidth > requiredWidth {
self.containerWidthConstraint?.priority = .required
self.contentViewWidthConstraint?.priority = .required
} else {
self.containerWidthConstraint?.priority = .defaultHigh
self.contentViewWidthConstraint?.priority = .defaultHigh
}
self.containerWidthConstraint?.isActive = true
self.contentViewWidthConstraint?.isActive = true
}

// MARK: - UIViewController Methods
Expand All @@ -207,7 +202,7 @@ open class UKModalController<VM: ModalVM>: UIViewController {
// MARK: - Helpers

@objc private func handleTraitChanges() {
Self.Style.content(self.content, model: self.model)
Self.Style.contentView(self.contentView, model: self.model)
}
}

Expand All @@ -225,11 +220,7 @@ extension UKModalController {
(view as? UIVisualEffectView)?.effect = UIBlurEffect(style: .systemUltraThinMaterial)
}
}
static func container(_ view: UIView, model: VM) {
view.backgroundColor = UniversalColor.background.uiColor
view.layer.cornerRadius = model.cornerRadius.value
}
static func content(_ view: UIView, model: VM) {
static func contentView(_ view: UIView, model: VM) {
view.backgroundColor = model.preferredBackgroundColor.uiColor
view.layer.cornerRadius = model.cornerRadius.value
view.layer.borderColor = UniversalColor.divider.cgColor
Expand Down
8 changes: 6 additions & 2 deletions Sources/ComponentsKit/Shared/Colors/ComponentColor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ public struct ComponentColor: Hashable {
public let contrast: UniversalColor

/// The background color for the component.
public let background: UniversalColor
public var background: UniversalColor {
return self._background ?? self.main.withOpacity(0.15).blended(with: .background)
}

private let _background: UniversalColor?

// MARK: - Initialization

Expand All @@ -28,6 +32,6 @@ public struct ComponentColor: Hashable {
) {
self.main = main
self.contrast = contrast
self.background = background ?? main.withOpacity(0.15)
self._background = background
}
}
Loading
Loading