Skip to content

Instantly share code, notes, and snippets.

@LinusU
Last active March 6, 2018 15:38

Revisions

  1. LinusU revised this gist Mar 6, 2018. 1 changed file with 39 additions and 32 deletions.
    71 changes: 39 additions & 32 deletions react.swift
    Original file line number Diff line number Diff line change
    @@ -6,20 +6,23 @@ import PlaygroundSupport
    /**********************************************
    * Library Types *
    **********************************************/
    typealias REProps = [String: Any]
    protocol REElement {
    func render() -> REElement?
    func toNativeView() -> UIView?
    }

    class REComponent {
    var children: [REComponent]
    var props: REProps
    class REComponent<Props>: REElement {
    var children: [REElement]
    var props: [Props]
    var state: Any?

    required init(_ props: REProps, _ children: [REComponent] = []) {
    init(_ props: [Props], _ children: [REElement] = []) {
    self.props = props
    self.children = children
    self.state = nil
    }

    func render() -> REComponent? { return nil }
    func render() -> REElement? { return nil }
    func toNativeView() -> UIView? { return nil }
    }

    @@ -28,42 +31,46 @@ class REComponent {
    /**********************************************
    * Built-in components *
    **********************************************/
    class RELabel: REComponent {
    enum RELabelProps {
    case backgroundColor(UIColor)
    case text(String)
    case textColor(UIColor)
    }

    class RELabel: REComponent<RELabelProps> {
    override func toNativeView() -> UIView? {
    let view = UILabel()

    if props["backgroundColor"] != nil {
    view.backgroundColor = (props["backgroundColor"] as! UIColor)
    }

    if props["text"] != nil {
    view.text = (props["text"] as! String)
    }

    if props["textColor"] != nil {
    view.textColor = (props["textColor"] as! UIColor)
    for prop in props {
    switch prop {
    case .backgroundColor(let value): view.backgroundColor = value
    case .text(let value): view.text = value
    case .textColor(let value): view.textColor = value
    }
    }

    return view
    }
    }

    class REStack: REComponent {
    enum REStackProps {
    case alignment(UIStackViewAlignment)
    case axis(UILayoutConstraintAxis)
    case distribution(UIStackViewDistribution)
    }

    class REStack: REComponent<REStackProps> {
    override func toNativeView() -> UIView? {
    let view = UIStackView()

    view.frame = CGRect(x: 0, y: 0, width: 200, height: 200)

    if props["alignment"] != nil {
    view.alignment = (props["alignment"] as! UIStackViewAlignment)
    }

    if props["axis"] != nil {
    view.axis = (props["axis"] as! UILayoutConstraintAxis)
    }

    if props["distribution"] != nil {
    view.distribution = (props["distribution"] as! UIStackViewDistribution)
    for prop in props {
    switch prop {
    case .alignment(let value): view.alignment = value
    case .axis(let value): view.axis = value
    case .distribution(let value): view.distribution = value
    }
    }

    for child in children {
    @@ -79,7 +86,7 @@ class REStack: REComponent {
    /**********************************************
    * Rendering function *
    **********************************************/
    func RE_render(node: REComponent, toTargetView targetView: UIView) {
    func RE_render(node: REElement, toTargetView targetView: UIView) {
    if let view = node.toNativeView() {
    if let stackedView = targetView as? UIStackView {
    stackedView.addArrangedSubview(view)
    @@ -105,9 +112,9 @@ class MyViewController : UIViewController {
    let view = UIView()
    view.backgroundColor = .white

    let tree = REStack(["alignment": UIStackViewAlignment.center], [
    RELabel(["backgroundColor": UIColor.cyan, "text": "Hello:"]),
    RELabel(["textColor": UIColor.blue, "text": "World!"])
    let tree = REStack([.alignment(.center)], [
    RELabel([.backgroundColor(.cyan), .text("Hello:")]),
    RELabel([.textColor(.blue), .text("World!")])
    ])

    RE_render(node: tree, toTargetView: view)
  2. LinusU created this gist Mar 6, 2018.
    120 changes: 120 additions & 0 deletions react.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,120 @@
    import UIKit
    import PlaygroundSupport



    /**********************************************
    * Library Types *
    **********************************************/
    typealias REProps = [String: Any]

    class REComponent {
    var children: [REComponent]
    var props: REProps
    var state: Any?

    required init(_ props: REProps, _ children: [REComponent] = []) {
    self.props = props
    self.children = children
    self.state = nil
    }

    func render() -> REComponent? { return nil }
    func toNativeView() -> UIView? { return nil }
    }



    /**********************************************
    * Built-in components *
    **********************************************/
    class RELabel: REComponent {
    override func toNativeView() -> UIView? {
    let view = UILabel()

    if props["backgroundColor"] != nil {
    view.backgroundColor = (props["backgroundColor"] as! UIColor)
    }

    if props["text"] != nil {
    view.text = (props["text"] as! String)
    }

    if props["textColor"] != nil {
    view.textColor = (props["textColor"] as! UIColor)
    }

    return view
    }
    }

    class REStack: REComponent {
    override func toNativeView() -> UIView? {
    let view = UIStackView()

    view.frame = CGRect(x: 0, y: 0, width: 200, height: 200)

    if props["alignment"] != nil {
    view.alignment = (props["alignment"] as! UIStackViewAlignment)
    }

    if props["axis"] != nil {
    view.axis = (props["axis"] as! UILayoutConstraintAxis)
    }

    if props["distribution"] != nil {
    view.distribution = (props["distribution"] as! UIStackViewDistribution)
    }

    for child in children {
    RE_render(node: child, toTargetView: view)
    }

    return view
    }
    }



    /**********************************************
    * Rendering function *
    **********************************************/
    func RE_render(node: REComponent, toTargetView targetView: UIView) {
    if let view = node.toNativeView() {
    if let stackedView = targetView as? UIStackView {
    stackedView.addArrangedSubview(view)
    } else {
    targetView.addSubview(view)
    }
    return
    }

    if let child = node.render() {
    RE_render(node: child, toTargetView: targetView)
    return
    }
    }



    /**********************************************
    * User code *
    **********************************************/
    class MyViewController : UIViewController {
    override func loadView() {
    let view = UIView()
    view.backgroundColor = .white

    let tree = REStack(["alignment": UIStackViewAlignment.center], [
    RELabel(["backgroundColor": UIColor.cyan, "text": "Hello:"]),
    RELabel(["textColor": UIColor.blue, "text": "World!"])
    ])

    RE_render(node: tree, toTargetView: view)

    self.view = view
    }
    }

    // Present the view controller in the Live View window
    PlaygroundPage.current.liveView = MyViewController()