Home

Awesome

iOS Kit for FramerJS

iOS Kit was created to make prototyping for iOS fast and easy without compromising the quality or customization.

There are three core pieces that make up iOS Kit. There is the foundational elements that help iOS Kit mold to devices. There is the component library that’ll save you time by providing native iOS offerings, and then there’s the supporting functions that help power the foundation & components.

##Updates August 3rd, 2016 – Sketch integration & major code cleanup:

Table of Contents

<div id='setup' /> ## Setup To setup the kit, add the following list of files to your modules folder in your project. Don't worry, you'll only need to require one. <br><br> <pre> ios-kit.coffee ios-kit-alert.coffee ios-kit-banner.coffee ios-kit-button.coffee ios-kit-field.coffee ios-kit-keyboard.coffee ios-kit-layout.coffee ios-kit-library.coffee ios-kit-nav-bar.coffee ios-kit-sheet.coffee ios-kit-status-bar.coffee ios-kit-tab-bar.coffee ios-kit-text.coffee ios-kit-utils.coffee </pre>

Please note: that Framer Studio currently doesn't support subfolders in the modules folder, so they'll need to be added to the root.

In Framer Studio, write – ios = require 'ios-kit'

You can write any variable name you'd like, but for the purposes of this guide we'll be using ios.

<div id='foundational' /> ## Foundational Elements <div id='convert' /> ### Sketch convert *NEW* Sketch convert brings a whole new set of logic to help make the transition from Sketch to Framer seamless. Sketch convert will go through your sketch layers & write constraints for you, so all your layers will scale & position perfectly no matter the device. You also won’t have the dreaded over-scaling problems.

To use Sketch convert, just wrap your sketch file inside of ios.convert()

<pre> ios = require "ios-kit" sketch = Framer.Importer.load("imported/iOS Kit Demo@1x") sketch = ios.convert(sketch) </pre>

That’s it! You’re done.

Pro-Tip – Framer imports layers that not in groups as combined layers, so the more you separate your layers into groups the more accurate Sketch convert can be.

<div id='sketch-com' /> ### Sketch components Included in this kit is a iOS Kit for Framer Sketch file full of components. These components will be written for you when converted. So right away, you can interact with them. Smart components are aware of a lot of properties, which saves a lot of time, but please be aware that not all properties will carry over.

To convert Sketch layers into iOS Kit components, you write the same convert statement as above.

<div id='dynamic' /> ### Dynamic Layout

The most fundamental piece of this module is Dynamic Layout. Dynamic Layout is a robust layout engine that’ll not only help make positioning layers easier and smarter, it'll will make positioning layers across devices possible.

<div id='point' /> #### The Point In Dynamic Layout, like in iOS, everything is based around the point instead of the pixel. The exact number of pixels will change from device to device, but the number of points will not. There's a simple equation for finding points.

1pt = 1px * scale

Side note: you can also use the built-in functions. ios.pt(6) #returns 3 points on iPhone 6 and 2 points on iPhone 6 plus ios.px(1) #returns 2 pixels on iPhone 6 and 3 pixels on iPhone 6 plus

Positioning

As we get away from using pixel positioning, we won't be using x & y based positioning. Instead, we'll be setting things called constraints. When you set a constraint, it's like saying that a layer can't go beyond a certain position. There are four constraints for positioning: leading, trailing, top, and bottom.

To set a leading & top constraint on a box, write this –

<pre> layer = new Layer layer.constraints = top:10 leading:10 ios.layout.set() </pre>

This will position the layer at x:20, y:20 on iPhone 6, and x:30, y:30 on iPhone 6 plus.

Side note: you can also do this on one line if you'd prefer using this syntax. Just replace the layer.constraints line from above with this line. You'll still need to run the ios.layout.set function.

<pre> layer.constraints = {top:10, leading:10} </pre> <div id='opposite' />
Setting Opposing Constraints

If you set a leading & trailing or a top & bottom, Dynamic Layout will do its best to honor the constraints, which will mean the height/width will need to be adjusted. For example, if you set the constraints of a layer to leading: 0 and trailing:0, the layer's width will be adjusted to the device's width.

WARNING - If you set too many opposing constraints, I'm not sure what'll happen. Best of luck. ¯\_(ツ)_/¯ Try to just set no more than one of each constraint.

Relationships

One of the most powerful things of Dynamic Layout is relationships. Relationships allows you to link a layer onto another layer in a variety of ways.

<div id='pos-rel' /> #####Positioning Relationships

When you declare a constraint, you can set a constraint as a layer instead of an integer. For example, if you have two layers (boxA & boxB) you can set boxB's top as boxA. <br>

<pre> boxB.constraints = <b>top:boxA</b> ios.layout.set() </pre> <p>This will stack the boxes so that boxB's top edge is constrained to below boxA, but what if you want a little buffer? That's really easy. We'll use a little different syntax with wrapping the layer and buffer in brackets.</p> <pre> boxB.constraints = <b>top:[boxA, 10]</b> ios.layout.set() </pre>

This will set boxB's top edge to 10 points below boxA.

<div id='center-rel' /> #####Centering Relationships

There are a couple other types of constraints that'll help make positioning layers even easier. There are two centering constraints: verticalCenter, horizontalCenter. These constraints will only accept just a layer as a constraint.

For example, if you'd like boxB to be horizontally centered on boxA, write this:

<pre> boxB.constraints = top:[boxA, 10] <b>horizontalCenter:boxA</b> ios.layout.set() </pre>

This will set boxB 10 points below boxA, and it'll center it within boxA on the x-axis. The other centering constraint verticalCenter will work simliarly center boxB within boxA on the y-axis. If you've set a top/bottom constraint, it'll ignore those constraints.

<div id='align-rel' /> #####Aligning Relationships ![](https://dl.dropboxusercontent.com/u/143270556/ioskit/align.png) The last type of relationships will allow you to align any edge of layer onto another layer's edge. To do this, there are four constraints at your disposal: leadingEdges, trailingEdges, topEdges, and bottomEdges. These layers, like centers, will not accept anything other than another layer.

If you'd like to align boxB's trailing edge onto boxA's trailing edge, write this:

<pre> boxB.constraints = top:[boxA, 10] <b>trailingEdges:boxA</b> ios.layout.set() </pre> <div id='animating' /> #### Animating Constraints You can animate between constraints by running ` ios.layout.animate()`.
Properties

Example

If we have a bunch of layers in a column and we want them to all move up, we can set the topLayer's constraint to 50, and all the layers with a relationship with topLayer will also move up.

<pre> topLayer.constraints.top = 50 ##Set a new constraint ios.animateLayout stagger:.05 curve:"spring" </pre>

Note: When updating a constraint on a layer, please be careful on your syntax. Writing layer.constraints = will wipe out your previous object.

This will wipe out your top constraint.

<pre> topLayer.constraints = top:50 leading:10 topLayer.constraints = leading:20 </pre>

Where as, this will keep your top constraint.

<pre> topLayer.constraints = top:50 leading:10 topLayer.constraints.leading = 20 </pre> <div id='size-constraints' /> ####Size Constraints You can also set height/width constraints just like above. This will ensure that your layers will remain a particular size. One big difference in setting a height/width constraint over a property height/width is that you'll need to set the height/width constraint in points. <pre> boxB.constraints = top:[boxA, 10] trailingEdges:boxA <b>height:100</b> <b>width:100</b> ios.layout.set() </pre> <div id='layout' /> ####ios.layout.set() This function only need to be called once for all constraints. It'll cycle through all the layers in order of creation, and it'll fulfill all constraints.

#####When to call it You'll need to call it before any x/y positions are referenced. If you have a function that's based off another layer, you'll need to call ios.layout.set before that positioning is stored otherwise it'll be wrong or 0. Once you call ios.layout.set(), it'll set the position to the accurate position. <br><br>

#####Mixing up the queue ios.layout.set will accept layers in the parathesis. This will layout only that layer and ignore all other constraints. This is to be used if a layer created after others needs to be laid out before others.<br>

ios.layout.set(boxB) This will only layout boxB and not boxA. <br> You may also want to play with the creation order if you're having issues with relationships.

<div id='real' /> ### Real device override This module is meant to make prototyping look real, and one of things that prevents this is when you open a prototype that was built for an iPhone 6 on an iPhone 6+. If you do this, you’ll end up seeing a lot of white space. When this module is on, your frame will be overridden by the device in your hand, so the iPhone 6+ will no longer see the iPhone 6 frame. Using Dynamic Layout will ensure that your prototype looks presentable at every size.

For this to work properly, you'll need a full-screen browser. I use & recommend Frameless.

<div id='details' /> ### Device details library You’ll now be able to refer to a set of new variables that’ll allow you to get more details on the device. <pre><b>ios.scale</b> # returns 1,2,3 <b>ios.height</b> # returns the height of the device in pixels <b>ios.width</b> # returns the width of the device in pixels <b>ios.device</b> # returns one of the device names below <b>ipad</b> # for any iPad other than the pro <b>ipad-pro</b> # for the iPad Pro <b>iphone-5</b> # for iPhone 5, iPhone 5s, iPhone 5c, and iPhone SE <b>iphone-6s</b> # for iPhone 6 & 6s <b>iphone-6s-plus</b> # for iPhone 6 plus & 6s plus </pre> <div id='system' /> ## System components These are easy to implement & fully customizable native iOS components. The idea is that implementing native iOS components should be easy & quick, so that you can spend the time working on what makes your prototype unique.

Every component in this module was written to feel native to Framer, so the way you create components should feel as familar as creating a new layer. The difference is that in addition to Framer properties there's added customization parameters, which will be accepted, and any component that can accept constraints from Dynamic Layout is able to.

After creation, components will operate as native layers under the variable name you declared. The only difference is the sublayers of the component are accessible via dot notation, so it's easier for you to turn on event listeners etc.

<div id='shortcuts' /> ##### Action string shortcuts To provide even more customization, any string in an action context can have these prepended shortcuts.

-b - bold string<br> -g - make string green<br> -r - make string red<br> -rb - make string blue <br> -lb - make string light blue<br> -o - make string orange<br> -p - make string pink<br> -y - make string yellow<br> -#000000 - change color to any 6 digit hex code. <br><br>

Alert

Alerts are blocking notifications that will force the users to address the alert before continuing.

Properties

Example

<pre> alert = new ios.Alert title:"Warning" message:"Don't do this" actions:["OK", "Cancel"] </pre>

Schema

<pre> alert : { alert.modal alert.title alert.message alert.actions : { OK, Cancel } alert.overlay } </pre>

Listening to Actions

To listen to different actions, you can use dot notation if it's a single word or brackets for any case

Banner

The banner is a non-blocking notification. Typically, the banner will send you to a specific screen in an app.

####Properties

**NOTE - ** The banner will be, by default, draggable. If you drag down, it'll reset, and if you drag up it'll dismiss & destroy the banner.

Example

<pre> banner = new ios.Banner title:"Time to do something" message:"Don't miss out" icon:iconLayer animated:true </pre>

Schema

<pre> banner : { banner.icon banner.title banner.message } </pre>

Listening to actions

To make the banner clickable, you can write -

<pre> banner.on Events... </pre>

Button

Button is a small versatile component that handles press states automatically.

####Properties

Example

<pre> button = new ios.Button text:"Download" buttonType:"small" color:"red" </pre>

####Schema

<pre> button: { button.label } </pre>

Listening to buttons

Listening to buttons is no different than normal framer.<br> button.on Events...

Field

The field is a versatile input for the keyboard. Please note, this is not a HTML field.

####Properties

####Example

<pre> field = new ios.Field placeholderText:"Enter a name or email address" constraints:{align:"center"} </pre>

####Schema

<pre> field: { field.placeholder field.text # after touchEnd event field.keyboard { ... Keyboard Schema } } </pre>

####Listening to keys inside of a field In order to listen for the return key or any other key, you'll need to wrap it up in a touch event since the keyboard only exists after the field is being touched.

<pre> field.on Events.TouchEnd, -> field.keyboard.keys.return.on Events... </pre>

Keyboard

The keyboard is a fully rendered component that mimics the native iOS keyboard. It'll adapt to all devices.

####Properties

Example

<pre> board = new ios.Keyboard returnText = "Done" </pre> <div id="keyboard-schema" /> ####Schema <pre> board: { board.keysArray #contains all keys A-Z in array object board.keys { board.keys.a - board.keys.z board.keys.shift boards.keys.return boards.keys.num boards.keys.space boards.keys.emoji
	# if on iPad
	boards.keys.shift2
	boards.keys.num2
	boards.keys.dismiss
} 

} </pre>

Listening to Keys

You can listen to keys using dot notation or square bracket notation.

##Sheet

The sheet is quick action list. The sheet component is super simple to create.

####Properties

**NOTE - ** The cancel button will always animate-out. You don't have to add any additional code to handle/animate that.

Example

<pre> sheet = new ios.sheet actions:[“-r Delete, Edit, Share”] animated:true description:"Do something" </pre>

####Schema

<pre> sheet : { sheet.cancel sheet.overlay sheet.description sheet.actions : {"-r Delete", Edit, Share} } </pre>

Listening to actions

To listen to different actions, you can use dot notation if it's a single word or brackets for any case

<div id='status' /> ## Status Bar

The status bar allows users to see the connection, current time, and battery.

####Properties

Example

<pre> statusBar = new ios.StatusBar carrier:"Verizon" network:"3G" battery:70 style:"light" </pre>

####Schema

<pre> statusBar : { statusBar.battery.percent statusBar.battery.icon statusBar.bluetooth statusBar.time statusBar.network statusBar.carrier statusBar.signal } </pre> <div id="nav" /> ## Navigation Bar

The navigation bar is made up of 3 elements, two actions and a title.

####Properties

Example

<pre> nav = new ios.NavBar right:"Share" left:"< Back" title:"Document" blur:false </pre>

####Schema

<pre> bar: { bar.right bar.left bar.title } </pre>

Listening to actions

To listen to different actions, you can use dot notation if it's a single word or brackets for any case

Tab

Tabs are light-weight objects that fit into the tab bar component.

####Properties

Example

<pre> home = new ios.Tab label:"home" icon:"< svg>...< /svg>" </pre>

####Schema

<pre> home: { home.label home.icon home.view } </pre>

####Adding contents to a tab Creating a tab will give you access to tab.view. In this case, you'll have home.view. When the home tab is active only those layers inside of home.view will be shown.

discovery = new Layer superLayer:home.view

The discovery layer will only be shown when the home tab is active in the tab bar.

<div id='tabbar' /> ## Tab Bar

The tab bar is comprised of multiple tabs. It'll handle switching of tabs and views.

####Properties

Example

<pre> tabBar = new ios.TabBar tabs:[home, discovery, profile], activeColor:"#blue", inactiveColor:"grey" </pre>

Listening to Tabs

Tab switching is automatically given, so there shouldn't necessarily be anything you need to do. If you'd like to do something additional when a user clicks a tab, you can reference your tab object.

Text

A dynamic text object that'll automatically size for you.

####Properties

####Example

<pre> text = new ios.Text text:"Try iOS Kit for Framer JS" fontSize:21 fontWeight:100 width:320 constraints:{align:"center"} </pre> <div id="view" /> ## View

A generic layer that you can set constraints at initiization. These constraints will be rendered immediately.

Example

<pre> view = new ios.View constraints: top:0 leading:25 width:200 backgroundColor:'red' </pre> <div id="supporting" /> ## Supporting Functions These are a set of functions that were created to help provide functionality to various elements of this module. I opened them up, so if you by chance need any of these functions you can use them.

ios.utils.update(layer, styleArray)

This was specifically intended for text objects. If the html or style of a text object is altered, the width/height of the object would be incorrect. With ios.update, you'll be able to pass your changes in while also resizing the text layer.

<pre> ios.update(headerOne, [text:"Done!"] </pre>

ios.utils.pt(int) & ios.utils.px(int)

These functions will automatically convert pixels -> points and points -> pixels.

<pre> ios.pt(6) # will return 3 points on an iPhone 6 ios.px(6) # will return 12 pixels on an iPhone 6 </pre>

####ios.utils.clean(string) This will remove any space or bracket HTML syntax from a string. ios.clean("Hi,&nbsp;how&nbsp;are&nbsp;you?<br>") returns "Hi, how are you?"

####ios.utils.svg(svg path) This does a series of things: it'll rewrite the SVG path into points, and it'll provide variables to set the layer's height and width.

<pre> svgObj = ios.svg(svgPath) svgObj.svg = # is the new SVG path in points svgObj.height = # is the value for the height of the layer svgObj.width = # is the value for the width of the layer </pre>

####ios.utils.changeFill(layer, color) This only works with layers with a SVG path. This will change the SVG fill to whatever color is passed.

####ios.utils.capitalize(string) This will capitalize only the first letter of the entire string.

<pre> print ios.capitalize("welcome to the party") #returns "Welcome to the party" </pre>

####ios.utils.getTime() Fetches the current time and returns a neatly organized time object with some humanization.

<pre> time = ios.getTime() print time.month # prints "April" print time.date # prints "12" print time.day # prints "Tuesday" print time.hours # prints "10" print time.mins # prints "33" print time.secs # prints "1" </pre>

####ios.utis.timeDelegate(layer, clock24) This sets up a reoccuring task at the top of every minute to update whatever layer passed to the current time. If clock24 is set to true, it'll return 24-hour clock values. If set to false or omitted, it'll return 12-hour clock values.

####ios.utils.timeFormatter(timeObj, clock24) This will create a time string for screen display. It'll return a hours-minutes string based on the clock24 object.

ios.utils.color(colorString)

This changes the color words to be set to iOS default colors in place of web color defaults. If it's a hexcode, it'll set the hexcode. If invalid, it'll return a grey hexcode.

Supports - red, blue, pink, grey/gray, black, white, orange, green, light blue/light-blue, yellow

<pre> ios.utils.color("light-blue) # returns "#54C7FC" </pre>

ios.utils.autoColor(colorObject)

This will decide whether to return black or white based on the contrast of the color passed through the color object. So an easy example would be: if you pass white it'll return black. If you pass black, it'll return white. It'll work with any color.

<pre> ios.utils.autoColor(ios.utils.color("yellow")) # returns "#000" ios.utils.autoColor(ios.utils.color("blue")) # returns "#FFF" </pre>

ios.utils.bgBlur(layer)

Add background blur to any layer using -webkit-backdrop-filter. Make sure that whatever layer you use is using rgba with an alpha set below 1.

<div id="contribute" /> ## How to contribute Contributions are welcome! If you'd like to add any new components/any new logic, please follow the guidelines below:

For components

If you'd like to add a component, please start a new coffee file, unless it's a directly related to another component similar to Tab & TabBar. Please use this boilerplate to help make the components consistent.

<pre> ## Allows you to use all the ios kit components & logic ios = require 'ios-kit' exports.defaults = { ## Add any thing a user can set in here. For example: backgroundColor: "blue" } ## Creates a property list exports.defaults.props = Object.keys(exports.defaults) exports.create = (array) -> ## Creates a setup object that has defaults + any custom props. setup = ios.utils.setupComponent(array, exports.defaults) print setup.backgroundColor ## prints blue</pre>

For logic

Please add any layout logic to the layout file. Otherwise, please add the logic to ios-kit-utils.coffee.

For data

Please add any referencable data object to ios-kit-library.coffee. You can either reference it with ios.library["object"] or with ios.assets["object"]. Whatever works best for you.

For help

Feel free to hit me up on Twitter.