Skip to content

Commit

Permalink
UIComponent 2.0 (#36)
Browse files Browse the repository at this point in the history
* WIP

* remove some unused

* Test

* merge RenderNode with ViewRenderNode

* merge ViewComponent with Component

* unify ViewComponent and Component APIs

* fix flexible

* rename SimpleViewComponent to ViewComponent

* polish

* some more tweaks

* dont render space

* some cleanup

* some more fixes

* fix cell keypath issue

* rename shouldRender to shouldRenderView and add migration guide

* Update Version2MigrationGuide.md

* Update Version2MigrationGuide.md

* fix visibleFrameInset not working as expected
  • Loading branch information
lkzhao authored Nov 14, 2023
1 parent f799ce2 commit b6c4eec
Show file tree
Hide file tree
Showing 77 changed files with 892 additions and 843 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/lkzhao/BaseToolbox",
"state": {
"branch": null,
"revision": "2962cea0ff0725629c0c90cddca1398faf2f807a",
"version": "0.1.14"
"revision": "62fe235533582054af1d7f13de714c76a72cf12f",
"version": "0.4.1"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Kingfisher
import UIComponent
import UIKit

public struct AsyncImage: ViewComponentBuilder {
public struct AsyncImage: ComponentBuilder {

public typealias AsyncIndicatorType = IndicatorType
public typealias ConfigurationBuilder = (KF.Builder) -> KF.Builder
Expand Down Expand Up @@ -33,8 +33,8 @@ public struct AsyncImage: ViewComponentBuilder {
self.configurationBuilder = configurationBuilder
}

public func build() -> ViewUpdateComponent<SimpleViewComponent<UIImageView>> {
SimpleViewComponent<UIImageView>()
public func build() -> UpdateComponent<ViewComponent<UIImageView>> {
ViewComponent<UIImageView>()
.update {
$0.kf.indicatorType = indicatorType
if let configurationBuilder = configurationBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class AsyncImageViewController: ComponentViewController {
}
}

override var component: Component {
override var component: any Component {
Waterfall(columns: 2, spacing: 1) {
for (index, image) in images.enumerated() {
AsyncImage(image.url)
Expand Down Expand Up @@ -86,7 +86,7 @@ class AsyncImageViewController: ComponentViewController {
class AsyncImageDetailViewController: ComponentViewController {
var image: ImageData!

override var component: Component {
override var component: any Component {
VStack {
AsyncImage(image.url)
.size(width: .fill, height: .aspectPercentage(image.size.height / image.size.width))
Expand Down
6 changes: 3 additions & 3 deletions Examples/UIComponentExample/Examples/BadgeExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import UIComponent
import UIKit

class BadgeViewController: ComponentViewController {
override var component: Component {
override var component: any Component {
VStack {
Text("Badges", font: .boldSystemFont(ofSize: 20)).id("label3")
VStack(spacing: 10) {
Expand Down Expand Up @@ -39,7 +39,7 @@ class BadgeViewController: ComponentViewController {
struct NumberBadge: ComponentBuilder {
let text: String
let isRoundStyle: Bool
func build() -> Component {
func build() -> some Component {
Text(
text,
font: .systemFont(ofSize: 12)
Expand Down Expand Up @@ -82,7 +82,7 @@ struct NumberBadge: ComponentBuilder {

struct BannerBadge: ComponentBuilder {
let text: String
func build() -> Component {
func build() -> some Component {
Text(text, font: .systemFont(ofSize: 11)).textAlignment(.center).textColor(.white).backgroundColor(.systemRed).adjustsFontSizeToFitWidth(true).size(height: .absolute(15))
.inset(h: 2)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import UIComponent

struct AddCardButton: ComponentBuilder {
let onTap: () -> Void
func build() -> Component {
func build() -> some Component {
HStack(spacing: 10, justifyContent: .center, alignItems: .center) {
Image(systemName: "plus").tintColor(.label)
Text("Add")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ private class CardView: UIView {
}
}

private struct CardViewComponent: ViewComponent {
private struct CardComponent: Component {
let data: CardData
let onTap: () -> Void
func layout(_ constraint: Constraint) -> CardViewRenderNode {
CardViewRenderNode(data: data, onTap: onTap, size: CGSize(width: constraint.maxSize.width, height: 80))
func layout(_ constraint: Constraint) -> CardRenderNode {
CardRenderNode(data: data, onTap: onTap, size: CGSize(width: constraint.maxSize.width, height: 80))
}
}

private struct CardViewRenderNode: ViewRenderNode {
private struct CardRenderNode: RenderNode {
let data: CardData
let onTap: () -> Void
var id: String? {
Expand All @@ -80,10 +80,10 @@ class CardViewController: ComponentViewController {
componentView.animator = AnimatedReloadAnimator()
}

override var component: Component {
override var component: any Component {
VStack(spacing: 8) {
for (index, card) in cards.enumerated() {
CardViewComponent(data: card) { [unowned self] in
CardComponent(data: card) { [unowned self] in
print("Tapped \(card.title)")
self.cards.remove(at: index)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class CardViewController2: ComponentViewController {
componentView.animator = AnimatedReloadAnimator()
}

override var component: Component {
override var component: any Component {
VStack(spacing: 8) {
for (index, card) in cards.enumerated() {
let title = card.title
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import UIKit
private struct Card: ComponentBuilder {
let card: CardData
let onTap: () -> Void
func build() -> Component {
func build() -> some Component {
VStack(spacing: 8) {
Text(card.title, font: UIFont.boldSystemFont(ofSize: 22))
Text(card.subtitle)
Expand Down Expand Up @@ -34,7 +34,7 @@ class CardViewController3: ComponentViewController {
componentView.animator = AnimatedReloadAnimator()
}

override var component: Component {
override var component: any Component {
VStack(spacing: 8) {
for (index, card) in cards.enumerated() {
Card(card: card) { [unowned self] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class ComplexLayoutViewController: ComponentViewController {
return button
}()

override var component: Component {
override var component: any Component {
VStack(spacing: 20) {
Text("Complex layouts", font: .boldSystemFont(ofSize: 20)).size(width: .fill).id("label")
VStack(spacing: 10) {
Expand Down Expand Up @@ -166,8 +166,8 @@ class ComplexLayoutViewController: ComponentViewController {
}
.showsHorizontalScrollIndicator(false).with(\.animator, AnimatedReloadAnimator())
HStack(spacing: 10) {
SimpleViewComponent<UIButton>(view: resetButton).isEnabled(horizontalListData != ComplexLayoutViewController.defaultHorizontalListData).id("reset")
SimpleViewComponent<UIButton>(view: shuffleButton).isEnabled(!horizontalListData.isEmpty).id("shuffled")
ViewComponent<UIButton>(view: resetButton).isEnabled(horizontalListData != ComplexLayoutViewController.defaultHorizontalListData).id("reset")
ViewComponent<UIButton>(view: shuffleButton).isEnabled(!horizontalListData.isEmpty).id("shuffled")
}
.inset(left: 10)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct HorizontalCardItem: ComponentBuilder {

let data: Context

func build() -> Component {
func build() -> some Component {
HStack(spacing: 10, alignItems: .center) {
VStack(spacing: 5, justifyContent: .center, alignItems: .center) {
Image(systemName: "hand.tap")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct IntroductionCard: ComponentBuilder {
Built in layouts including Stack, Flow, & Waterfall.
Declaritive API based on resultBuilder and modifier syntax.
Work seemless with existing UIKit views, viewControllers, and transitions.
dynamicMemberLookup support for all ViewComponents which can help you easily update your UIKit views.
dynamicMemberLookup support for all Components which can help you easily update your UIKit views.
Animator API to apply animations when cells are being moved, updated, inserted, or deleted.
Simple architecture for anyone to be able to understand.
Easy to create your own Components.
Expand All @@ -24,7 +24,7 @@ struct IntroductionCard: ComponentBuilder {
let isExpanded: Bool
let tapHandler: () -> Void

func build() -> Component {
func build() -> some Component {
HStack(spacing: 15, alignItems: .stretch) {
VStack(spacing: 5, alignItems: .center) {
AsyncImage(URL(string: "https://unsplash.com/photos/MR2A97jFDAs/download?force=true&w=640")!).size(width: 50, height: 50).update { $0.layer.cornerRadius = 50 / 2 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import Kingfisher
import UIComponent
import UIKit.UIImageView

extension ViewComponent where R.View: UIView {
fileprivate func shadowAvatar() -> ViewUpdateComponent<Self> {
extension Component {
fileprivate func shadowAvatar() -> UpdateComponent<Self> {
update {
$0.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
$0.layer.shadowOffset = CGSize(width: 0, height: 3)
Expand All @@ -21,7 +21,7 @@ struct UserProfile: ComponentBuilder {
let userName: String
let introduce: String

func build() -> Component {
func build() -> some Component {
HStack(spacing: 10, alignItems: .center) {
AsyncImage(avatar)
.contentMode(.scaleAspectFill)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import UIKit

class FlexLayoutViewController: ComponentViewController {

override var component: Component {
override var component: any Component {

VStack(spacing: 20) {
Text("Flex layouts", font: .boldSystemFont(ofSize: 20)).size(width: .fill)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct GalleryItemData: Equatable {

struct GalleryItem: ComponentBuilder {
let data: GalleryItemData
func build() -> Component {
func build() -> some Component {
AsyncImage(data.cover, indicatorType: .activity, configurationBuilder: { $0.transition(.flipFromBottom(0.35)) })
.contentMode(.scaleAspectFill)
.clipsToBounds(true)
Expand All @@ -20,7 +20,7 @@ struct GalleryItem: ComponentBuilder {

struct GalleryIndexOverlay: ComponentBuilder {
let index: Int
func build() -> Component {
func build() -> some Component {
Text("\(index)").textColor(.white).textAlignment(.center)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ protocol GalleryTemplate {
func calculateFrames(spacing: CGFloat, side: CGFloat, makeFrame: (Point, Size) -> CGRect) -> [CGRect]
}

protocol GalleryLayout: Component, BaseLayoutProtocol {
protocol GalleryLayout: BaseLayoutProtocol {
var spacing: CGFloat { get }
var children: [Component] { get }
var children: [any Component] { get }
var template: [GalleryTemplate] { get }
init(spacing: CGFloat, template: [GalleryTemplate], children: [Component])
init(spacing: CGFloat, template: [GalleryTemplate], children: [any Component])
}

extension GalleryLayout {
init(spacing: CGFloat = 0, template: [GalleryTemplate], @ComponentArrayBuilder _ content: () -> [Component]) {
init(spacing: CGFloat = 0, template: [GalleryTemplate], @ComponentArrayBuilder _ content: () -> [any Component]) {
self.init(spacing: spacing, template: template, children: content())
}
}

extension GalleryLayout {

func layout(_ constraint: Constraint) -> RenderNode {
func layout(_ constraint: Constraint) -> R {

var allFrames = [CGRect]()
var index = 0
Expand Down Expand Up @@ -67,24 +67,24 @@ extension GalleryLayout {
}
}

struct VerticalGallery: GalleryLayout, VerticalLayoutProtocol {
struct VerticalGallery: Component, GalleryLayout, VerticalLayoutProtocol {
var spacing: CGFloat
var template: [GalleryTemplate]
var children: [Component]
var children: [any Component]

init(spacing: CGFloat, template: [GalleryTemplate], children: [Component]) {
init(spacing: CGFloat, template: [GalleryTemplate], children: [any Component]) {
self.spacing = spacing
self.template = template
self.children = children
}
}

struct HorizontalGallery: GalleryLayout, HorizontalLayoutProtocol {
struct HorizontalGallery: Component, GalleryLayout, HorizontalLayoutProtocol {
var spacing: CGFloat
var template: [GalleryTemplate]
var children: [Component]
var children: [any Component]

init(spacing: CGFloat, template: [GalleryTemplate], children: [Component]) {
init(spacing: CGFloat, template: [GalleryTemplate], children: [any Component]) {
self.spacing = spacing
self.template = template
self.children = children
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class GalleryViewController: ComponentViewController {

let horizontalData: [GalleryItemData] = (0...33).map { _ in GalleryItemData() }

override var component: Component {
override var component: any Component {
VStack(spacing: 20) {
Text("Gallery layouts", font: .boldSystemFont(ofSize: 20)).size(width: .fill).inset(h: 20)
HStack(spacing: 20) {
Expand Down
4 changes: 2 additions & 2 deletions Examples/UIComponentExample/Examples/SizeExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import UIComponent
import UIKit

class SizeExampleViewController: ComponentViewController {
override var component: Component {
Space(width: 50, height: 50).view().backgroundColor(.red).centered().size(CGSize(width: 200, height: 200)).view().backgroundColor(.green)
override var component: any Component {
Text("Test").backgroundColor(.red).textColor(.green).centered().size(width: 200, height: 200).backgroundColor(.green)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class WaterfallLayoutViewController: ComponentViewController {
return sizes
}()

override var component: Component {
override var component: any Component {
VStack(spacing: 20) {
Text("Waterfall layouts", font: .boldSystemFont(ofSize: 20)).id("label3")
VStack(spacing: 10) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ComponentViewController: UIViewController {
componentView.component = component
}

var component: Component {
var component: any Component {
VStack(justifyContent: .center, alignItems: .center) {
Text("Empty")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Box: ComponentBuilder {
convenience init(width: CGFloat = 40, height: CGFloat = 40) {
self.init("", width: width, height: height)
}
func build() -> Component {
func build() -> some Component {
Space(width: width, height: height).styleColor(.systemBlue).overlay(Text(text).textColor(.white).textAlignment(.center).size(width: .fill, height: .fill))
}
}
4 changes: 2 additions & 2 deletions Examples/UIComponentExample/Supporting Files/Modifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import UIKit

extension Component {

func styleColor(_ tintColor: UIColor) -> ViewUpdateComponent<ComponentViewComponent<ComponentView>> {
func styleColor(_ tintColor: UIColor) -> UpdateComponent<ComponentViewComponent<ComponentView>> {
view()
.update {
$0.backgroundColor = tintColor.withAlphaComponent(0.5)
Expand All @@ -16,7 +16,7 @@ extension Component {
}
}

func defaultShadow() -> ViewUpdateComponent<ComponentViewComponent<ComponentView>> {
func defaultShadow() -> UpdateComponent<ComponentViewComponent<ComponentView>> {
view()
.update {
$0.backgroundColor = .systemBackground
Expand Down
4 changes: 2 additions & 2 deletions Examples/UIComponentExample/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import UIComponent
import UIKit

class ViewController: ComponentViewController {
override var component: Component {
override var component: any Component {
VStack {
Join {
ExampleItem(name: "Card Example", viewController: CardViewController())
Expand All @@ -31,7 +31,7 @@ struct ExampleItem: ComponentBuilder {
self.name = name
self.viewController = viewController
}
func build() -> Component {
func build() -> some Component {
VStack {
Text(name)
}
Expand Down
Loading

0 comments on commit b6c4eec

Please sign in to comment.