Carbon🚴 A declarative library for building component-based user interfaces in UITableView and UICollectionView.

Overview

A declarative library for building component-based user interfaces
in UITableView and UICollectionView.

Declarative Component-Based Non-Destructive
Provides a declarative design with power of diffing algorithm for building list UIs. Declare component once, it can be reused regardless kind of the list element. Solves the various problems by architecture and algorithm without destructing UIKit.

Release CocoaPods Carthage
CI Status Swift 5.1 Platform Lincense


Introduction

Carbon is a library for building component-based user interfaces in UITableView and UICollectionView inspired by SwiftUI and React.
This make it painless to build and maintain the complex UIs.
Since components made with Carbon can be works directly on SwiftUI, the cost of future migration can be greatly reduced.

Uses DifferenceKit which is highly optimized based on Paul Heckel's paper for diffing.
Declarative design and diffing algorithm make your code more predictable, debugging easier and providing beautiful animations to users.

Our goal is similar to Instagram/IGListKit and airbnb/Epoxy, we respect those library as pioneers.


Examples

Pangram Kyoto Emoji Todo Form

renderer.render {
    Header("GREET")
        .identified(by: \.title)

    HelloMessage("Vincent")
    HelloMessage("Jules")
    HelloMessage("Mia")

    Footer("πŸ‘‹ Greeting from Carbon")
        .identified(by: \.text)
}

SwiftUI Compatibility

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                Text("GREET")
                    .font(.title)
                    .padding(.horizontal, 16)

                HelloMessage("World")
                    .frame(height: 60)
                    .background(Color.red)
            }
        }
    }
}

Getting Started

Build for Development

$ git clone https://github.com/ra1028/Carbon.git
$ cd Carbon/
$ make setup
$ open Carbon.xcworkspace

Basic Usage

Described here are the fundamentals for building list UIs with Carbon.
The API document will help you understand the details of each type.
For more advanced usage, see the Advanced Guide.
And the more practical examples are here.

Component

Component is the base unit of the UI in Carbon.
All elements are made up of components, and it can be animated by diffing update.

UIView, UIViewController and its subclasses are available as content of component by default.
You can declare fixed size component by implementing referenceSize(in bounds: CGRect) -> CGSize?. The default is to return nil and falls back to a value such as UITableView.rowHeight or UICollectionViewFlowLayout.itemSize.
See here for more depth of component.

Definition below is the simplest implementation.

struct HelloMessage: Component {
    var name: String

    func renderContent() -> UILabel {
        UILabel()
    }

    func render(in content: UILabel) {
        content.text = "Hello \(name)"
    }
}

Component used as a cell requires to specify an arbitrary id.
Give an id by Component.identified(by:) or declare it by using IdentifiableComponent protocol.

Renderer

The components are displayed on the list UI by Renderer.render.
Boilerplates such as registering element types to a table view are no longer needed in Carbon.

The adapter acts as delegate and dataSource, the updater handles updates.
You can also change the behaviors by inheriting and customizing it.
There are also UITableViewReloadDataUpdater and UICollectionViewReloadDataUpdater which update by reloadData without diffing updates.

When render called again, the updater calculates the diff from the currently rendered components and updates them with the system animation.

Renderer for UITableView:

@IBOutlet var tableView: UITableView!

let renderer = Renderer(
    adapter: UITableViewAdapter(),
    updater: UITableViewUpdater()
)

override func viewDidLoad() {
    super.viewDidLoad()

    renderer.target = tableView
}

Renderer for UICollectionView:

@IBOutlet var collectionView: UICollectionView!

let renderer = Renderer(
    adapter: UICollectionViewFlowLayoutAdapter(),
    updater: UICollectionViewUpdater()
)

override func viewDidLoad() {
    super.viewDidLoad()

    renderer.target = collectionView
}

Render Components:

renderer.render {
    Header("GREET")
        .identified(by: \.title)

    HelloMessage("Butch")
    HelloMessage("Fabianne")
}

Section

A section can include header, footer and cells.
This also needs to specify id for identify from among multiple sections.
The cells can be declared using a function builder as below:

let appearsBottomSection: Bool = ...
let appearsFourthMan: Bool = ...

renderer.render {
    Section(
        id: "Bottom",
        header: Header("GREET"),
        footer: Footer("πŸ‘‹ Greeting from Carbon"),
        cells: {
            HelloMessage("Marsellus")
            HelloMessage("The Wolf")
        }
    )

    if appearsBottomSection {
        Section(id: "Top") {
            HelloMessage("Brett")
            HelloMessage("Roger")

            if appearsFourthMan {
                HelloMessage("Fourth Man")
            }
        }
    }
}

Group

The number of limit to declare cells or section with function builder syntax is until 10. You can avoid that limitation by grouping with Group.
It can also be used to create a cell or section from an array with N elements.

Group of Components:

renderer.render {
    Group {
        Header("GREET")
            .identified(by: \.title)

        HelloMessage("Vincent")
        HelloMessage("Jules")
    }

    Group(of: ["Pumpkin", "Honey Bunny"]) { name in
        HelloMessage(name)
    }
}

Group of Sections:

renderer.render {
    Group {
        Section(id: 0) {
            HelloMessage("Jimmie")
        }

        Section(id: 1) {
            HelloMessage("Bonnie")
        }
    }

    Group(of: ["Lance", "Jody"]) { name in
        Section(id: name) {
            HelloMessage(name)
        }
    }
}

[See More Usage] [See Example App]


Advanced Guide

Custom Content

Of course, the content of component can use custom class. You can also instantiate it from Xib.
It can be inherited whichever class, but the common means is inherit UIView or UIViewController.

class HelloMessageContent: UIView {
    @IBOutlet var label: UILabel!
}
struct HelloMessage: Component {
    var name: String

    func renderContent() -> HelloMessageContent {
        HelloMessageContent.loadFromNib()  // Extension for instantiate from Xib. Not in Carbon.
    }

    func render(in content: HelloMessageContent) {
        content.label.text = "Hello \(name)"
    }
}

IdentifiableComponent

IdentifiableComponent is a component that simply can predefine an identifier.
It can be omitted the definition of id if the component conforms to Hashable.

struct HelloMessage: IdentifiableComponent {
    var name: String

    var id: String {
        name
    }

    ...

SwiftUI Compatibility

Components made with Carbon are compatible with SwiftUI.
The component can easily works as SwiftUI by composing with View protocol.
Currently SwiftUI doesn't support self-sizing, so can use UIView.intrinsicContentSize or specify the height explicitly by Component.referenceSize(in:) or View.frame(height:).

struct HelloMessage: Component, View {
    ...
}
struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("GREET")

            HelloMessage("World")
                .frame(height: 60)

            Spacer()
        }
    }
}

Component in-Depth

Components can define more detailed behaviors.
Following are part of it.

  • shouldContentUpdate(with next: Self) -> Bool
    If the result is true, the component displayed as a cell is reloaded individually, header or footer is reloaded with entire section.
    By default it returns false, but the updater will always re-render visible components changed.

  • referenceSize(in bounds: CGRect) -> CGSize?
    Defining the size of component on the list UI.
    You can use default value such as UITableView.rowHeight or UICollectionViewLayout.itemSize by returning nil.
    Returns nil by default.

  • shouldRender(next: Self, in content: Content) -> Bool
    By returning false, you can skip component re-rendering when reloading or dequeuing element.
    Instead of re-rendering, detects component changes by comparing with next value.
    This is recommended to use only for performance tuning.

  • contentWillDisplay(_ content: Content)
    Invoked every time of before a component got into visible area.

  • contentDidEndDisplay(_ content: Content)
    Invoked every time of after a component went out from visible area.

See more

Selection

Cell selection can be handled by setting didSelect to the instance of UITableViewAdapter or UICollectionViewAdapter.

renderer.adapter.didSelect { context in
    print(context)
}

However, we recommend to make the Content of the component to the class inherited from UIControl.
It's more maintainable and extensible.

class MenuItemContent: UIControl {
    @IBOutlet var label: UILabel!

    var onSelect: (() -> Void)?

    @objc func handleSelect() {
        onSelect?()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        addTarget(self, action: #selector(handleSelect), for: .touchUpInside)
    }
}
struct MenuItem: Component {
    var text: String
    var onSelect: () -> Void

    func renderContent() -> MenuItemContent {
        MenuItemContent.loadFromNib()
    }

    func render(in content: MenuItemContent) {
        content.label.text = text
        content.onSelect = onSelect
    }
}

In this way, in order to cancel the selection by scrolling, you need to implement the following extension.

extension UITableView {
    open override func touchesShouldCancel(in view: UIView) -> Bool {
        true
    }
}

extension UICollectionView {
    open override func touchesShouldCancel(in view: UIView) -> Bool {
        true
    }
}

Adapter Customization

You can add methods of delegate, dataSource by subclassing each adapter.

class CustomTableViewdapter: UITableViewAdapter {
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        "Header title for section\(section)"
    }
}

let renderer = Renderer(
    adapter: CustomTableViewAdapter(),
    updater: UITableViewUpdater()
)

Furthermore, it can be customized the class of the elements(cell/header/footer) which becomes the container of components by overriding some methods in adapter as following.
You can also use xib by giving nib as parameter of init of the return value Registration.

class CustomTableViewAdapter: UITableViewAdapter {
    // Use custom cell.
    override func cellRegistration(tableView: UITableView, indexPath: IndexPath, node: CellNode) -> CellRegistration {
        CellRegistration(class: CustomTableViewCell.self)
    }

    // Use custom header view.
    override func headerViewRegistration(tableView: UITableView, section: Int, node: ViewNode) -> ViewRegistration {
        ViewRegistration(class: CustomTableViewHeaderFooterView.self)
    }

    // Use custom footer view.
    override func footerViewRegistration(tableView: UITableView, section: Int, node: ViewNode) -> ViewRegistration {
        ViewRegistration(class: CustomTableViewHeaderFooterView.self)
    }
}

In UICollectionViewAdapter, you can select the node corresponding to a certain kind.

class CustomCollectionViewAdapter: UICollectionViewAdapter {
    override func supplementaryViewNode(forElementKind kind: String, collectionView: UICollectionView, at indexPath: IndexPath) -> ViewNode? {
        switch kind {
        case "CustomSupplementaryViewKindSectionHeader":
            return headerNode(in: indexPath.section)

        default:
            return super.supplementaryViewNode(forElementKind: kind, collectionView: collectionView, at: indexPath)
        }
    }
}

See more

Updater Customization

It can be modify the updating behavior of the list UI by inheriting Updater.
This is important thing to make Carbon well adapted to your project.
Below are some of the default provided settings of updater.

  • isAnimationEnabled
    Indicating whether enables animation for diffing updates, setting false will perform it using UIView.performWithoutAnimation.
    Default is true.

  • isAnimationEnabledWhileScrolling
    Indicating whether enables animation for diffing updates while target is scrolling, setting false will perform it using UIView.performWithoutAnimation.
    Default is false.

  • animatableChangeCount
    The max number of changes to perform diffing updates. It falls back to reloadData if it exceeded.
    Default is 300.

  • keepsContentOffset
    Indicating whether that to reset content offset after updated.
    The content offset become unintended position after diffing updates in some case. If set true, revert content offset after updates.
    Default is true.

See more

Without FunctionBuilder Syntax

Carbon can also build a UI with declarative syntax without function builder as following.

  • ViewNode

This is a node representing header or footer. The node is wrap an instance of type conforming to Component protocol.

ViewNode(Header("GREET"))
  • CellNode

CellNode is a node representing cell.
Unlike in the ViewNode, this needs an id which Hashable type to identify from among a lot of cells.
The id is used to find the same component in the list data before and after changed.

CellNode(id: 0, HelloMessage("Jules"))
CellNode(HelloMessage("Jules").identified(by: \.name))
CellNode(HelloMessage("Jules"))  // Using `IdentifiableComponent`.
  • Section and render
renderer.render(
    Section(
        id: "Section",
        header: ViewNode(Header("GREET")),
        cells: [
            CellNode(HelloMessage("Vincent")),
            CellNode(HelloMessage("Mia")),
            CellNode(HelloMessage("Jules"))
        ],
        footer: ViewNode(Footer("πŸ‘‹ Greeting from Carbon"))
    )
)

See more


Requirements

  • Swift 5.1+
  • Xcode 11.0+

Installation

CocoaPods

Add the following to your Podfile:

pod 'Carbon'

Carthage

Add the following to your Cartfile:

github "ra1028/Carbon"

Swift Package Manager

Select Xcode menu File > Swift Packages > Add Package Dependency... and enter repository URL with GUI.

Repository: https://github.com/ra1028/Carbon

Contributing

Pull requests, bug reports and feature requests are welcome πŸš€
Please see the CONTRIBUTING file for learn how to contribute to Carbon.


Respect

Libraries for list UIs using diffing algorithm that I have sincerely ❀️ and respected.


License

Carbon is released under the Apache 2.0 License.


Carbon Logo

Comments
  • How to show hide Section with UICollectionView?

    How to show hide Section with UICollectionView?

    i'm trying to show hide section with UICollectionView, but every rendering component its like ugly animation, how to implement show hide with UICollectionView?

    Thanks for helping :)

    opened by arimunandar 6
  • Generic parameter 'Element' could not be inferred

    Generic parameter 'Element' could not be inferred

    Checklist

    Expected Behavior

    While updating from RC2 to RC4, the next issue happens.

    Current Behavior

    Array of class [ClassName], using the group function to list as cells.

    cells: {
                            Group(of: state.todos.enumerated()) { offset, todo in
                                TodoText(todo: todo, isCompleted: false)
    }}
    

    Detailed Description (Include Screenshots)

    However, using another class results in this error: Generic parameter 'Element' could not be inferred. Explicitly specify the generic arguments to fix this issue When explicitly specifying arguments I get the following error: Unable to infer closure type in the current context.

    What am I doing wrong?

    Environment

    • Carbon version: RC4
    opened by wousser 5
  • Declarative syntax with function builder

    Declarative syntax with function builder

    This is WIP Until Xcode GM is released.

    close https://github.com/ra1028/Carbon/issues/35

    Checklist

    Description

    Add support declarative syntax like SwiftUI with function builder for Swift5.1.

    renderer.render {
        Label("foo")
        Label("bar")
        Label("baz")
    
        if flag {
            Label("qux")
        }
    }
    
    renderer.render {
        Section(id: "section1") {
            Label("foo")
            Label("bar")
            Label("baz")
        }
    
        Section(
            id: "section2",
            header: Label("header"),
            footer: Label("footer"),
            cells: {
                Label("qux")
                
                if flag {
                    Label("quux")
                }
            }
        )
    }
    

    Related Issue

    https://github.com/ra1028/Carbon/issues/35

    Motivation and Context

    See related issues and description.

    opened by ra1028 5
  • [SUGESTION] Add demo with custom cell classes

    [SUGESTION] Add demo with custom cell classes

    I think a demo with custom cell classes will help some users. For example the demo can integrate https://github.com/SwipeCellKit/SwipeCellKit for the cells

    opened by andrefmsilva 5
  • Why the removal of `UITableViewCellContent` related classes?

    Why the removal of `UITableViewCellContent` related classes?

    Checklist

    Hi, I appreciate your work but I was wondering: why did you remove UITableViewCellContent in the latest release (rc1)? It was the only way to access the cell that actually is rendered by the tableview. Now I can't, for example, add an accessory view to the cell keeping the cell's background color the same, and I can't make use of the default cell selection behavior.

    opened by rcasula 4
  • Need the ability to add event handling to the Component

    Need the ability to add event handling to the Component

    Checklist

    Description

    I would like to be able to add event handling directly to the component.

    Example: struct HelloMessage: Component { Β Β Β  ... }

    HelloMessage().on(.click) { ... }.cellNode HelloMessage().on(.viewWillAppear) { ... }.cellNode

    or

    HelloMessage().cellNode.on(.click) { ... } HelloMessage().cellNode.on(.viewWillAppear) { ... }

    Motivation and Context

    Allows you to make ViewController cleaner.

    opened by BarredEwe 3
  • Crash when building and launching for iOS 10, 11 and 12 simulator

    Crash when building and launching for iOS 10, 11 and 12 simulator

    dyld: Library not loaded: /System/Library/Frameworks/SwiftUI.framework/SwiftUI
      Referenced from: /Users/thomasricouard/Library/Developer/CoreSimulator/Devices/A09605A4-9BF2-4D63-9B5A-000D85C18FCA/data/Containers/Bundle/Application/92E5E64B-1EBD-46C3-A9A0-486C122D0E41/Glose Education Staging.app/Frameworks/Carbon.framework/Carbon
      Reason: no suitable image found.  Did find:
    	/System/Library/Frameworks/SwiftUI.framework/SwiftUI: mach-o, but not built for iOS simulator
    

    SwiftUI is not conditionally linked? I'm getting crash on launch as SwiftUI can't be linked on any earlier iOS version than 13.

    opened by Dimillian 3
  • Weird behaviour as I scroll up

    Weird behaviour as I scroll up

    Hello,

    I'm making a fairly complexe UITableView, and I have some weird behaviours. As I scroll down, mostly no problem. As I scroll up I get really weird behaviours, like blank space (missing components?) and wrongly sized component.

    Here is two images, one normal and one as I scroll up. IMG_0496 IMG_0495

    Here is some code, this is a big project, it would be very hard for me to extract and isolate this code to make a self contain package in order to reproduce it. But maybe something is wrong in my approach.

    Here is my datasource Screenshot 2019-10-23 at 18 41 18

    And also the code of one of my component as an example

    struct ReadingActivityQuoteComponent: IdentifiableComponent {
        let quote: Quote?
        let isTop: Bool
        
        var id: String {
            quote?.id ?? "quoteLoading"
        }
        
        class View: UIView {
            var quote: Quote? {
                didSet {
                    render()
                }
            }
            
            var isTop: Bool = false {
                didSet {
                    if isTop {
                        cardView.maskedCorners = [.topLeft, .topRight]
                    } else {
                        cardView.maskedCorners = []
                    }
                }
            }
            
            let quoteLabel = QuoteDarkerLeft(frame: .zero)
            let cardView = CardView(frame: .zero)
            
            init() {
                super.init(frame: CGRect.zero)
                
                cardView.maskedCorners = []
                
                quoteLabel.showAnimatedGradientSkeleton()
                quoteLabel.numberOfLines = 0
            
                addSubview(cardView)
                cardView.addSubview(quoteLabel)
    
                
                constrain(self, cardView, quoteLabel) { parent, card, quote in
                    card.top == parent.top
                    card.left == parent.readableContentGuide.left + 12
                    card.right == parent.readableContentGuide.right - 12
                    card.bottom == parent.bottom
                    
                    quote.top == card.top + 12
                    quote.left == card.left + 12
                    quote.right == card.right - 12
                    quote.bottom == card.bottom - 12
                }
            }
            
            required init?(coder: NSCoder) {
                fatalError("init(coder:) has not been implemented")
            }
            
            func render() {
                quoteLabel.hideSkeleton()
                quoteLabel.text = quote?.text
            }
        }
        
        func renderContent() -> ReadingActivityQuoteComponent.View {
            View()
        }
        
        func render(in content: ReadingActivityQuoteComponent.View) {
            content.quote = quote
            content.isTop = isTop
        }
    }
    
    

    Coming from a lot of SwiftUI lately, Carbon is really awesome to use in the UIKit world. But I'm having quite some issues right now. Again, I have no idea if my architecture is wrong or if I'm hitting some underlying Carbon or UITableView related bugs. I'm self sizing every component with auto layout using Cartography.

    opened by Dimillian 3
  • Click to enlarge the Image Content?

    Click to enlarge the Image Content?

    Checklist

    Expected Behavior

    Would you like to add a tap gesture or so, so that when tapping on imageview content, the image view will zoom in or pop up in a larger view to preview?

    opened by yo1995 3
  • [Proposal] Consider `estimateItemSize` in addition to `itemSize.`

    [Proposal] Consider `estimateItemSize` in addition to `itemSize.`

    Checklist

    Description

    I used UICollectionViewFlowLayout to implement a collectionView where collectionView.height and collectionView.contentSize.height are equal and the width of the cell is dynamic. Then, I set estimatedItemSize on prepare () method(didn't set itemSize). It makes UICollectionViewFlowLayoutBreakForInvalidSizes of layout error.(I called layoutIfNeeded after reloadData)

    I resolved to set itemSize on prepare().

    Found Carbon handle for only itemSize.

    Apple Document don't say need both estimatedItemSize and itemSize.

    Proposed Solution

    Carbon handle both itemSize and estimatedItemSize or write doc about estimatedItemSize. (It may not be necessary because itemSize is already written πŸ€” )

    opened by tomosaaan 3
  • Keep UITableView ContentOffset to prepend list items

    Keep UITableView ContentOffset to prepend list items

    Checklist

    Expected Behavior

    I want to make a timeline like Twitter using Carbon and UITableView.

    • When I continue to load the latest items and append the Component Items in List, UITableView contentOffset works properly. (= keep the current position)
    • When I pull to refresh and prepend Component items in List, UITableView contentOffset moves to top position in List.

    Current Behavior

    Add to append items.

    list = [Component3, Component4, Component5]
    appendItems = [Component6, Component7]
    

    I scroll to the latest item Component5.

    newList = [Component3, Component4, Component5, Component6, Component7]
    

    and UITableView's contentOffset indicates Component5. Keep current position.

    Add to prepend items.

    list = [Component3, Component4, Component5]
    appendItems = [Component1, Component2]
    

    I pull to refresh.

    newList = [Component1, Component2, Component3, Component4, Component5]
    

    and UITableView's contentOffset indicates Component1. Not Component3

    Detailed Description (Include Screenshots)

    • I want to resolve latter case. (add to prepend items)
      • UITableView's contentOffset should indicate Component3.
    • Do you have any solutions? Thank you.

    Environment

    • Carbon version: 1.0.0 Release Candidate 6

    • Swift version: Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)

    • iOS version: 13.4.1

    • Xcode version: 11.4.1

    • Devices/Simulators: iPhone11Pro 13.4.1

    • using SPM

    opened by shimastripe 2
  • Bump tzinfo from 1.2.5 to 1.2.10

    Bump tzinfo from 1.2.5 to 1.2.10

    Bumps tzinfo from 1.2.5 to 1.2.10.

    Release notes

    Sourced from tzinfo's releases.

    v1.2.10

    TZInfo v1.2.10 on RubyGems.org

    v1.2.9

    • Fixed an incorrect InvalidTimezoneIdentifier exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123.

    TZInfo v1.2.9 on RubyGems.org

    v1.2.8

    • Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. The 64-bit section is now always used regardless of whether Time has support for 64-bit times. #120.
    • Rubinius is no longer supported.

    TZInfo v1.2.8 on RubyGems.org

    v1.2.7

    • Fixed 'wrong number of arguments' errors when running on JRuby 9.0. #114.
    • Fixed warnings when running on Ruby 2.8. #112.

    TZInfo v1.2.7 on RubyGems.org

    v1.2.6

    • Timezone#strftime('%s', time) will now return the correct number of seconds since the epoch. #91.
    • Removed the unused TZInfo::RubyDataSource::REQUIRE_PATH constant.
    • Fixed "SecurityError: Insecure operation - require" exceptions when loading data with recent Ruby releases in safe mode.
    • Fixed warnings when running on Ruby 2.7. #106 and #111.

    TZInfo v1.2.6 on RubyGems.org

    Changelog

    Sourced from tzinfo's changelog.

    Version 1.2.10 - 19-Jul-2022

    Version 1.2.9 - 16-Dec-2020

    • Fixed an incorrect InvalidTimezoneIdentifier exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123.

    Version 1.2.8 - 8-Nov-2020

    • Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. The 64-bit section is now always used regardless of whether Time has support for 64-bit times. #120.
    • Rubinius is no longer supported.

    Version 1.2.7 - 2-Apr-2020

    • Fixed 'wrong number of arguments' errors when running on JRuby 9.0. #114.
    • Fixed warnings when running on Ruby 2.8. #112.

    Version 1.2.6 - 24-Dec-2019

    • Timezone#strftime('%s', time) will now return the correct number of seconds since the epoch. #91.
    • Removed the unused TZInfo::RubyDataSource::REQUIRE_PATH constant.
    • Fixed "SecurityError: Insecure operation - require" exceptions when loading data with recent Ruby releases in safe mode.
    • Fixed warnings when running on Ruby 2.7. #106 and #111.
    Commits
    • 0814dcd Fix the release date.
    • fd05e2a Preparing v1.2.10.
    • b98c32e Merge branch 'fix-directory-traversal-1.2' into 1.2
    • ac3ee68 Remove unnecessary escaping of + within regex character classes.
    • 9d49bf9 Fix relative path loading tests.
    • 394c381 Remove private_constant for consistency and compatibility.
    • 5e9f990 Exclude Arch Linux's SECURITY file from the time zone index.
    • 17fc9e1 Workaround for 'Permission denied - NUL' errors with JRuby on Windows.
    • 6bd7a51 Update copyright years.
    • 9905ca9 Fix directory traversal in Timezone.get when using Ruby data source
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump cocoapods-downloader from 1.2.2 to 1.6.3

    Bump cocoapods-downloader from 1.2.2 to 1.6.3

    Bumps cocoapods-downloader from 1.2.2 to 1.6.3.

    Release notes

    Sourced from cocoapods-downloader's releases.

    1.6.3

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124

    1.5.1

    Enhancements
    • None.
    Bug Fixes
    • Fix "can't modify frozen string" errors when pods are integrated using the branch option
      buju77 #10920

    1.5.0

    ... (truncated)

    Changelog

    Sourced from cocoapods-downloader's changelog.

    1.6.3 (2022-04-01)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2 (2022-03-28)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1 (2022-03-23)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0 (2022-03-22)

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124

    1.5.1 (2021-09-07)

    Enhancements
    • None.

    ... (truncated)

    Commits
    • c03e2ed Release 1.6.3
    • f75bccc Disable Bazaar tests due to macOS 12.3 not including python2
    • 52a0d54 Merge pull request #128 from CocoaPods/validate_before_dl
    • d27c983 Ensure that the git pre-processor doesn't accidentally bail also
    • 3adfe1f [CHANGELOG] Add empty Master section
    • 591167a Release 1.6.2
    • d2564c3 Merge pull request #127 from CocoaPods/validate_before_dl
    • 99fec61 Switches where we check for invalid input, to move it inside the download fun...
    • 96679f2 [CHANGELOG] Add empty Master section
    • 3a7c54b Release 1.6.1
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • XCode 13+ issues

    XCode 13+ issues

    Checklist

    Expected Behavior

    Expecting to be able to do pod install & to archive a build.

    Current Behavior

    pod install results in errors for Carbon. Trying to archive the project results in compile errors.

    Steps to Reproduce

    1. Open a project that uses Carbon on a system with above described details
    2. Try to do an archive

    Environments

    • Carbon version: 1.0.0-rc6

    • Swift version: 5.5

    • Xcode version: 13.1

    opened by dtln820 2
  • Work around canImport(Combine) being broken in Xcode 13

    Work around canImport(Combine) being broken in Xcode 13

    Checklist

    Description

    When using Carbon in Xcode 13, an error occurs during archiving.
    Same fix as Realm, Alamofire, etc. https://github.com/realm/realm-cocoa/pull/7401

    opened by kitwtnb 0
  • Bump redcarpet from 3.5.0 to 3.5.1

    Bump redcarpet from 3.5.0 to 3.5.1

    Bumps redcarpet from 3.5.0 to 3.5.1.

    Release notes

    Sourced from redcarpet's releases.

    Redcarpet v3.5.1

    Fix a security vulnerability using :quote in combination with the :escape_html option.

    Reported by Johan Smits.

    Changelog

    Sourced from redcarpet's changelog.

    Version 3.5.1 (Security)

    • Fix a security vulnerability using :quote in combination with the :escape_html option.

      Reported by Johan Smits.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
Releases(1.0.0-rc.6)
  • 1.0.0-rc.6(Oct 30, 2019)

  • 1.0.0-rc.5(Oct 23, 2019)

    Enhancement

    • Add support for SwiftUI compatibility :tada: (#58)
    struct HelloMessage: Component, View {
        ...
    }
    
    struct ContentView: View {
        var body: some View {
            ScrollView {
                VStack {
                    Text("GREET")
                        .font(.title)
                        .padding(.horizontal, 16)
    
                    HelloMessage("World")
                        .frame(height: 60)
                        .background(Color.red)
                }
            }
        }
    }
    
    • Add Group.init without elements (#50)

    Breaking Changes

    • Add Component.intrinsicContentSize(for:) to get intrinsic content size for content to infer size of the UIView in SwiftUI (#58)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0-rc.4(Sep 13, 2019)

  • 1.0.0-rc.3(Sep 11, 2019)

    This version Carbon supports both Swift 5.0 and Swift 5.1.

    Breaking Changes

    • Declarative syntax with function builder (#46)
    • Make isAnimationEnabledWhileScrolling set false by default (#47)
    • Make keepsContentOffset set true by default (#48)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0-rc.2(Sep 4, 2019)

    This version Carbon supports both Swift 5.0 and Swift 5.1.

    Breaking Changes

    • Make Adapter.alwaysRenderVisibleComponents true by default. (#37)
    • Make Component.shouldContentUpdate returns false by default. (#37)
    • Constraints of type parameters Adapter in UITableViewUpdater is now changed to UITableViewAdapter. (#37)
    - class CustomUpdater<A: Adapter & UITableViewDataSource & UITableViewDelegate>: UITableViewUpdater<A> {...}
    + class CustomUpdater<A: UITableViewAdapter>: UITableViewUpdater<A> {...}
    
    • Constraints of type parameters Adapter in UICollectionViewUpdater is now changed to UICollectionViewAdapter. (#37)
    - class CustomUpdater<A: Adapter & UICollectionViewDataSource & UICollectionViewDelegate>: UICollectionViewUpdater<A> {...}
    + class CustomUpdater<A: UITableViewAdapter>: UITableViewUpdater<A> {...}
    
    • Adapter.skipReloadComponents is now obsolete. (#37)
    • Make referenceSize(in bounds:) returns nil by default. (#38)
    • Refactor method signature and responsibility of the UITableViewUpdater/UICollectionViewUpdater. (#40) You can now intercepts arbitrary processes before or after updates, for example:
    - override func performDifferentialUpdates(target: UITableView, adapter: A, data: [Section], stagedChangeset: StagedDataChangeset, completion: (() -> Void)?) {
    }
    + super.performDifferentialUpdates(target: target, adapter: adapter, stagedChangeset: stagedDataChangeset)
    
    open func performDifferentialUpdates(target: UITableView, adapter: Adapter, stagedChangeset: StagedDataChangeset) {
        super.performDifferentialUpdates(target: target, adapter: adapter, stagedChangeset: stagedDataChangeset)
    
        if stagedChangeset.allSatisfy({ $0.hasChanges }) {
            let y = target.contentSize.height - (target.bounds.height - target.adjustedContentInset.bottom)
            let contentOffset = CGPoint(x: target.contentOffset.x, y: y)
            setContentOffset(contentOffset, animated: true)
        }
    }
    
    • Remove completion from Renderer. (#40)
    - renderer.completion {
    -     // do something
    - }
    
    + renderer.updater.completion {
    +     // do something
    + }
    
    • Change constraints of type parameters Adapter of UITableViewReloadDataUpdater/UICollectionReloadDataViewUpdater to UITableViewAdapter/UICollectionViewAdapter. (#40)
    • Closure style render function and section initializer are now deprecated. (#42)

    Enhancement

    • Adds support for Swift Package Manager (by @robcas3 #25)
    • UICollectionViewUpdater. renderVisibleComponents supports custom supplementary elements. (#37)
    • Add completion to UITableViewUpdater/UICollectionViewUpdater. (#40)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0-rc.1(Jul 29, 2019)

    This version Carbon supports both Swift 5.0 and Swift 5.1.

    Features

    • Add support for use custom container cell/header/footer class (#21)
    • Add closure style initializer for Section (#28)
    • Add a render function with closure style builder (#28)
    • Add completion closure property to Renderer (#28)

    Breaking Changes

    • Remove UITableViewCellContent, UITableViewHeaderFooterViewContent, UICollectionViewCellContent and UICollectionReusableViewContent (#21)
    • Remove UITableViewAdapter.Config and UICollectionViewAdapter.Config (#21)
    • Remove the completion parameter from each render functions (#28)
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(May 13, 2019)

    This version Carbon supports both Swift 4.2 and Swift 5.

    Features

    1. Add isAnimationEnabledWhileScrolling option for disable animation while scrolling (#17)
    2. Initializing Renderer without passing the target instance (#18)
    let renderer = Renderer(
        adapter: UITableViewAdapter(),
        updater: UITableViewUpdater()
    )
    
    renderer.target = tableView
    

    Deprecation

    1. Renderer.init(target:adapter:updater:) is now deprecated. Use Renderer.init(adapter:updater:) instead (#18)
    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Mar 28, 2019)

    This version Carbon supports both Swift 4.2 and Swift 5.

    Xcode 10.2 Support

    1. Swift 5.0 and Xcode 10.2 support (#8)

    Features

    1. Add new updater's option to keeping content offset after diffing updates (#9)
    Source code(tar.gz)
    Source code(zip)
  • 0.1.0(Feb 12, 2019)

Owner
Ryo Aoyama
β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–€β–„β–‘β–‘β–‘β–„β–€β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–„β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–„β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–‘β–‘β–‘ β–‘β–‘β–‘β–ˆβ–‘β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–‘β–ˆβ–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–€β–€β–‘β–‘β–‘β–€β–€β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘
Ryo Aoyama
Former is a fully customizable Swift library for easy creating UITableView based form.

Former is a fully customizable Swift library for easy creating UITableView based form. Submitting Issues Click HERE to get started with filing a bug r

Ryo Aoyama 1.3k Dec 27, 2022
Declarative data validation framework, written in Swift

Peppermint Introduction Requirements Installation Swift Package Manager Usage Examples Predicates Constraints Predicate Constraint Compound Constraint

iOS NSAgora 43 Nov 22, 2022
Custom Field component with validation for creating easier form-like UI from interface builder.

#YALField Custom Field component with validation for creating easier form-like UI from interface builder. ##Example Project To run the example project

Yalantis 476 Sep 1, 2022
A rule-based validation library for Swift

SwiftValidator Swift Validator is a rule-based validation library for Swift. Core Concepts UITextField + [Rule] + (and optional error UILabel) go into

null 1.4k Dec 29, 2022
SwiftForms is a small and lightweight library written in Swift that allows you to easily create forms.

SwiftForms is a powerful and extremely flexible library written in Swift that allows to create forms by just defining them in a couple of lines. It also provides the ability to customize cells appearance, use custom cells and define your own selector controllers.

Miguel Ángel Ortuño 1.3k Dec 27, 2022
XLForm is the most flexible and powerful iOS library to create dynamic table-view forms. Fully compatible with Swift & Obj-C.

XLForm By XMARTLABS. If you are working in Swift then you should have a look at Eureka, a complete re-design of XLForm in Swift and with more features

xmartlabs 5.8k Jan 6, 2023
ObjectForm - a simple yet powerful library to build form for your class models.

ObjectForm A simple yet powerful library to build form for your class models. Motivations I found most form libraries for swift are too complicated to

jakehao 175 Nov 2, 2022
iOS Validation Library

Honour Validation library for iOS inspired by Respect/Validation. Validator.mustBe(Uppercase()).andMust(StartsWith("F")).validate("FOOBAR") ❗ If you w

Jean Pimentel 55 Jun 3, 2021
The most flexible and powerful way to build a form on iOS

The most flexible and powerful way to build a form on iOS. Form came out from our need to have a form that could share logic between our iOS apps and

HyperRedink 32 Aug 15, 2022
A framework to validate inputs of text fields and text views in a convenient way.

FormValidatorSwift The FormValidatorSwift framework allows you to validate inputs of text fields and text views in a convenient way. It has been devel

ustwoβ„’ 500 Nov 29, 2022
Discover new programming concepts and more new SwiftUI 2 features in this section

Africa-Zoo One thing is sure, we will discover new programming concepts and more new SwiftUI 2 features in this section. TOPICS ARE COVERED: JSON with

Noye Samuel 2 Nov 8, 2022
SherlockForms - An elegant SwiftUI Form builder to create a searchable Settings and DebugMenu screens for iOS

??️‍♂️ SherlockForms What one man can invent Settings UI, another can discover i

Yasuhiro Inami 98 Dec 27, 2022
🚴 A declarative library for building component-based user interfaces in UITableView and UICollectionView.

A declarative library for building component-based user interfaces in UITableView and UICollectionView. Declarative Component-Based Non-Destructive Pr

Ryo Aoyama 1.2k Jan 5, 2023
React-inspired framework for building component-based user interfaces in Swift.

TemplateKit React-inspired framework for building component-based user interfaces in Swift. Features ?? Completely native - write your app in Swift ??

Matias Cudich 160 Nov 3, 2022
TemplateKit - React inspired framework for building component-based user interfaces in Swift

TemplateKit React-inspired framework for building component-based user interface

null 0 Feb 6, 2022
WLEmptyState is an iOS based component that lets you customize the view when the dataset of a UITableView or a UICollectionView is empty.

Table of Content Overview Running an Example Project Installing WLEmptyState Configuring WLEmptyState Using WLEmptyState Customizing WLEmptyState Cont

Wizeline 315 Dec 5, 2022
Introducing SwiftUI. A declarative way to create User Interfaces with Swift.

SwiftUI - Landmarks Introducing SwiftUI. A declarative way to create User Interfaces with Swift. SwiftUI was introduced at WWDC 2019 by Apple. It is t

Alex Paul 8 Sep 21, 2021
AppKit Carbon key codes to UIKey-compatible enums

KeyCodes Versions of UIKey, UIKeyboardHIDUsage, and UIKeyModifierFlags that work with AppKit's NSEvent. No need for Carbon.HIToolbox. Aside from being

Chime 26 Nov 24, 2022
UITableView based component designed to display a hierarchy of expandable/foldable comments.

SwiftyComments UITableView based component designed to display a hierarchy of expandable/foldable comments. Installation Manually Just copy the .swift

StΓ©phane Sercu 220 Dec 22, 2022
Nice library to show placeholders and Empty States for any UITableView/UICollectionView in your project

HGPlaceholders Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements iOS 8.0+ Xcode 9

Hamza Ghazouani 2.2k Dec 24, 2022