├── LICENSE ├── README.md └── Router.coffee /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jared Palmer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Framer Router 2 | A layer management module for [Framer](http://framerjs.com) that resembles an SPA router. 3 | 4 | ### Demos 5 | - [Simple](http://share.framerjs.com/ql44rmd36tju/) 6 | - [Link API](http://share.framerjs.com/u2rvcvm0h2dq/) 7 | 8 | ## Quick Start 9 | #### 1. Include in your Framer project 10 | ```coffeescript 11 | { Router, Route, Link } = require 'Router' 12 | ``` 13 | #### 2. Instantiate a new Router. Give it an indexRoute 14 | 15 | ```coffeescript 16 | router = new Router 17 | indexRoute: 'RouteOne' 18 | ``` 19 | 20 | #### 3. Create a few routes and some child layers to go in them 21 | 22 | ```coffeescript 23 | RouteOne = new Route 24 | router: router 25 | name: 'RouteOne' 26 | 27 | RouteTwo = new Route 28 | router: router # connect it to your router 29 | name: 'RouteTwo' # give your route a name 30 | x: 755 31 | 32 | ``` 33 | #### 4. Make a link 34 | 35 | ```coffeescript 36 | RouteOne.onClick () -> 37 | router.push('RouteTwo') 38 | 39 | # Or, you can use the Link API 40 | Button = new Link 41 | router: router 42 | to: 'RouteTwo' 43 | parent: RouteOne 44 | ``` 45 | 46 | #### 5. Add Animations 47 | By default, framer-router will just toggle visibilty. When you want to animate things, each `Route` has an optional `onEnter` and `onLeave` hook. Both `onEnter` and `onLeave` can call a callback function that simply emits `routeDidLeave` and `routeDidEnter` respectively. 48 | 49 | ```coffeescript 50 | # You can use a state machine, or just the `animate` API to manage intros and outros 51 | 52 | RouteOne.onEnter = () -> 53 | @animate 54 | properties: 55 | y: 0 56 | scale: 1 57 | curve: "spring(400,40,0)" 58 | 59 | RouteOne.onLeave = () -> 60 | @animate 61 | properties: 62 | y: 500 63 | scale: .5 64 | curve: "spring(400,60,0)" 65 | ... 66 | 67 | RouteTwo.onEnter = (done) -> 68 | @animate 69 | properties: 70 | x: 0 71 | curve: "spring(400,40,0)" 72 | done() # emits 'routeDidEnter' event 73 | 74 | RouteTwo.onLeave = (done) -> 75 | @animate 76 | properties: 77 | x: 755 78 | curve: "spring(400,60,0)" 79 | done() # emits 'routeDidLeave' event 80 | ``` 81 | #### Help 82 | Get in touch on twitter [@jaredpalmer](http://twitter.com/jaredpalmer) with any questions or file an issue. 83 | -------------------------------------------------------------------------------- /Router.coffee: -------------------------------------------------------------------------------- 1 | # $$\ 2 | # $$ | 3 | # $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ 4 | # $$ __$$\ $$ __$$\ $$ | $$ |\_$$ _| $$ __$$\ $$ __$$\ 5 | # $$ | \__|$$ / $$ |$$ | $$ | $$ | $$$$$$$$ |$$ | \__| 6 | # $$ | $$ | $$ |$$ | $$ | $$ |$$\ $$ ____|$$ | 7 | # $$ | \$$$$$$ |\$$$$$$ | \$$$$ |\$$$$$$$\ $$ | 8 | # \__| \______/ \______/ \____/ \_______|\__| 9 | # 10 | # 11 | # Copyright (c) 2016 Jared Palmer 12 | # www.jaredpalmer.com 13 | # @jaredpalmer 14 | 15 | 16 | class Router extends Framer.BaseClass 17 | constructor: (props) -> 18 | props.debug ?= false 19 | super() 20 | @route = props.indexRoute 21 | @debug = props.debug 22 | @lastRoute = null 23 | @nextRoute = null 24 | 25 | push: (i) => 26 | unless @route is i 27 | @lastRoute = @route 28 | @nextRoute = i 29 | if @debug 30 | print 31 | routeWillChange: 32 | lastRoute: @lastRoute 33 | nextRoute: @nextRoute 34 | 35 | @emit "routeWillChange" 36 | @route = i 37 | @emit "routeDidChange" # could be interesting if you want. 38 | if @debug then print routeDidChange: @route 39 | 40 | # @TODO: 41 | # goBack: () => 42 | # handle history array 43 | # 44 | # replace: () => 45 | # switch instantly to a route, perhaps no animations? 46 | 47 | 48 | # Define the view classes to keep their code organized 49 | class Route extends Layer 50 | constructor: (props) -> 51 | props.x ?= 0 # set default props 52 | props.y ?= 0 # set default props 53 | super(props) 54 | @router = props.router 55 | @visible = @router.route == @name 56 | @width = Framer.Screen.width 57 | @height = Framer.Screen.height 58 | @onLeave = props.onLeave 59 | @onEnter = props.onEnter 60 | @router.on "routeWillChange", @handleRouteChange 61 | 62 | handleOnLeave: () => 63 | @emit "routeDidLeave" 64 | if @router.debug then print routeDidLeave: @name 65 | 66 | handleOnEnter: () => 67 | @emit "routeDidEnter" 68 | if @router.debug then print routeDidEnter: @name 69 | 70 | handleRouteChange: () => 71 | if @router.lastRoute is @name 72 | if @router.debug then print routeWillLeave: @name 73 | @emit "routeWillLeave" 74 | @ignoreEvents = true 75 | if @onLeave then @onLeave(@handleOnLeave) else visible = false 76 | 77 | if @router.nextRoute is @name 78 | if @router.debug then print routeWillEnter: @name 79 | @emit "routeWillEnter" 80 | @ignoreEvents = false 81 | @visible = true 82 | if @onEnter then @onEnter(@handleOnEnter) 83 | 84 | # Link will tell the router to update. 85 | # Should feel a little like a React Router's . 86 | class Link extends Layer 87 | constructor: (props) -> 88 | super props 89 | @router = props.router 90 | @to = props.to 91 | @on Events.Click, @clicked 92 | # When you click a Link, change routes 93 | clicked: () => 94 | @router.push(@to) 95 | 96 | 97 | 98 | exports.Route = Route 99 | exports.Router = Router 100 | exports.Link = Link 101 | --------------------------------------------------------------------------------