SkillAgentSearch skills...

Teacup

This project has been sunset in favor of MotionKit

Install / Use

/learn @colinta/Teacup
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Teacup

A community-driven DSL for creating user interfaces on iOS and OS X.

Build Status

Using Teacup, you can create and style layouts and keeping your code dry. The goal is to offer a rubyesque (well, actually a rubymotion-esque) way to create interfaces programmatically.

A note about Teacup and MotionKit

Read a letter from Colin T.A. Gray regarding the future of Teacup and introducing MotionKit, its successor.

Check out some sample apps!

Quick Install

> gem install teacup

and in your Rakefile

require 'teacup'

10 second primer, iOS

  1. Create a UIViewController subclass:

    class MyController < UIViewController
    
  2. Assign a stylesheet name:

    class MyController < UIViewController
      stylesheet :main_screen
    
  3. Create a layout:

    class MyController < UIViewController
      stylesheet :main_screen
    
      def teacup_layout
        subview(UIButton, :hi_button)
      end
    end
    
  4. Create the stylesheet (in app/styles/ or somewhere near the controller)

    Teacup::Stylesheet.new :main_screen do
      style :hi_button,
        origin: [10, 10],
        title: 'Hi!'
    end
    

10 second primer, OS X

Pretty much the same! Note that on OS X, view coordinates are based on having the origin in the bottom-left corner, not the upper-left like it is on every other GUI system ever. :-|

You should use the TeacupWindowController parent class instead of NSWindowController

  1. Create a TeacupWindowController subclass.

    class MyController < TeacupWindowController
    
  2. Assign a stylesheet name:

    class MyController < TeacupWindowController
      stylesheet :main_window
    
  3. Create a layout:

    class MyController < TeacupWindowController
      stylesheet :main_window
    
      def teacup_layout
        subview(NSButton, :hi_button)
      end
    end
    
  4. Create the stylesheet (in app/styles/ or somewhere near the controller)

    Teacup::Stylesheet.new :main_window do
      style :hi_button,
        origin: [10, 10],
        title: 'Hi!'
    end
    

Teacup

Teacup's goal is to facilitate the creation and styling of your view hierarchy. Say "Goodbye!" to Xcode & XIB files!

Teacup is composed of two systems:

  • Layouts A DSL to create Views and to organize them in a hierarchy. You assign the style name and style classes from these methods.

  • Stylesheets Store the "styles" that get applied to your views. The stylesheet DSL is meant to resemble CSS, but is targeted at iOS, and so the precedence rules are very different.

Teacup supports [Pixate][] and [NUI][], too, so you can use those systems for styling and Teacup to manage your view hierarchy and apply auto-layout constraints. Teacup can also integrate with the [motion-layout][] gem!

Changes in 3.0

There is one significant change in version 3.0. In every version of Teacup prior (from 0.2.0 to 2.3.0) the controller layout was usually created by calling a class method called layout. It was discovered, embarrassingly late, that this system is causing memory leaks. To fix it we had to remove this feature altogether. So if you are looking at old Teacup examples, you will see this block syntax that is no longer offered. It is easy to update to 3.0, though:

# <= 2.3.0
class MyController < UIViewController
  layout(:root_stylename) do  # <= this block is what caused the memory leak!
    # teacup code goes here
  end
end

# 3.0
class MyController < UIViewController
  def teacup_layout  # in 3.0 we just changed it to be a method
    # introduced in 3.0, this is how you assign a stylename to the root view
    root(:root_stylename, { background: UIColor.blueColor })
    # teacup code goes here - no other code changes necessary
  end
  # actually, this method still works as long as you don't pass a block.  It's
  # the same as calling `root(stylename, {})`
  layout(:root_stylename, {})
end

Table of Contents

Layouts

The Teacup::Layout module is mixed into UIViewController and UIView on iOS, and NSWindowController, NSViewController, and NSView on OS X. These classes can take advantage of the view-hierarchy DSL.

You saw an example in the primer, using the UIViewController/NSWindowController class method layout and the teacup_layout method. You could just as easily use Teacup's DSL to create your views from a loadView method, for instance you might want to use a custom view subclass as your root view. An example might look like this:

# controller example
class MyController < UIViewController

  def loadView
    # we will create the controller's view, assigning it the stylename :root
    self.view = layout(FancyView, :root) do
      # these subviews will be added to `self.view`
      subview(UIToolbar, :toolbar)
      subview(UIButton, :hi_button)
    end
  end

end

You can use very similar code in your view subclasses.

# view example
#
# if you use Teacup in all your projects, you can bundle your custom views with
# their own stylesheets
def MyView < UIView

  def initWithFrame(frame)
    super.tap do
      self.stylesheet = :my_stylesheet
      subview(UIImageView, :image)
    end
  end

end

The layout and subview methods are the work horses of the Teacup view DSL.

  • layout(view|ViewClass, stylename, style_classes, additional_styles, &block)
    • view|ViewClass - You can layout an existing class or you can have Teacup create it for you (it just calls new on the class, nothing special). This argument is required.
    • stylename (Symbol) - This is the name of a style in your stylesheet. It is optional
    • style_classes ([Symbol,...]) - Other stylenames, they have lower priority than the stylename.
    • additional_styles (Hash) - You can pass other styles in here as well, either to override or augment the settings from the Stylesheet. It is common to use this feature to assign the delegate or dataSource.
    • &block - See discussion below
    • Returns the view that was created or passed to layout.
    • only the view arg is required. You can pass any combination of stylename, style_classes, and additional_styles (some, none, or all).
  • subview(view|UIViewClass, stylename, style_classes, additional_styles, &block)
    • Identical to layout, but adds the view to the current target

The reason it is so easy to define view hierarchies in Teacup is because the layout and subview methods can be "nested" by passing a block.

subview(UIView, :container) do  # create a UIView instance and give it the stylename :container
  subview(UIView, :inputs) do  # create another container
    # these views will be added to the :inputs view
    @email_input = subview(UITextField, :email_input)
    @password_input = subview(UITextField, :password_input)
  end
  # this view will be added to :container
  subview(UIButton.buttonWithType(UIButtonTypeRoundedRect), :submit_button)
end

These methods are defined in the Layout module. And guess what!? It's easy to add your own view helpers! I refer to this as a "partials" system, but really it's just Ruby code (and isn't that the best system?).

# the methods you add here will be available in UIView/NSView,
# UIViewController/NSViewController/NSWindowController, and any of your own
# classes that `include Teacup::Layout`
module Teacup::Layout

  # creates a button and assigns
View on GitHub
GitHub Stars599
CategoryDevelopment
Updated4d ago
Forks83

Languages

Ruby

Security Score

80/100

Audited on Apr 4, 2026

No findings