Merge pull request #24 from drapanjanas/support-om-next

Support om next fixes #15
This commit is contained in:
Artūr Girenko 2016-02-11 13:50:27 +01:00
commit 055e123476
7 changed files with 144 additions and 7 deletions

View File

@ -7,7 +7,8 @@ Artur Girenko, MIT License
This project is a fork of [dmotz/natal](https://github.com/dmotz/natal) by Dan Motzenbecker with
the goal of generating skeleton of native app for iOS and Android based on
[Reagent](https://github.com/reagent-project/reagent) and [re-frame](https://github.com/Day8/re-frame).
[Reagent](https://github.com/reagent-project/reagent) and [re-frame](https://github.com/Day8/re-frame)
or [Om.Next](https://github.com/omcljs/om/wiki/Quick-Start-(om.next)).
The support of Figwheel is based on brilliant solution developed by Will Decker [decker405/figwheel-react-native](https://github.com/decker405/figwheel-react-native)
which works in both platforms.
@ -54,12 +55,15 @@ To bootstrap a new app, run `re-natal init` with your app's name as an argument:
```
$ re-natal init FutureApp
```
Or, for Om.Next project:
```
$ re-natal init FutureApp -i om-next
```
If your app's name is more than a single word, be sure to type it in CamelCase.
A corresponding hyphenated Clojure namespace will be created.
Re-Natal will create a simple skeleton based on the current
version of [Reagent](https://github.com/reagent-project/reagent) and [Day8/re-frame](https://github.com/Day8/re-frame).
If all goes well you should see printed out basic instructions how to run in iOS simulator.
```

View File

@ -37,11 +37,26 @@ interfaceConf =
ios: ["core.cljs"]
android: ["core.cljs"]
common: ["handlers.cljs", "subs.cljs", "db.cljs"]
other: []
deps: ['[reagent "0.5.1" :exclusions [cljsjs/react]]'
'[re-frame "0.6.0"]'
'[prismatic/schema "1.0.4"]']
shims: ["cljsjs.react"]
sampleCommandNs: '(in-ns \'$PROJECT_NAME_HYPHENATED$.ios.core)'
sampleCommand: '(dispatch [:set-greeting "Hello Native World!"])'
'om-next':
cljsDir: "cljs-om-next"
sources:
ios: ["core.cljs"]
android: ["core.cljs"]
common: ["state.cljs"]
other: [["support.cljs","re_natal/support.cljs"]]
deps: ['[org.omcljs/om "1.0.0-alpha28" :exclusions [cljsjs/react cljsjs/react-dom]]'
'[natal-shell "0.1.6"]']
shims: ["cljsjs.react", "cljsjs.react.dom"]
sampleCommandNs: '(in-ns \'$PROJECT_NAME_HYPHENATED$.state)'
sampleCommand: '(swap! app-state assoc :app/msg "Hello Native World!")'
interfaceNames = Object.keys interfaceConf
log = (s, color = 'green') ->
console.log chalk[color] s
@ -246,6 +261,7 @@ shimCljsNamespace = (ns) ->
copySrcFiles = (interfaceName, projName, projNameUs, projNameHyph) ->
cljsDir = interfaceConf[interfaceName].cljsDir
fileNames = interfaceConf[interfaceName].sources.common;
for fileName in fileNames
path = "src/#{projNameUs}/#{fileName}"
@ -261,6 +277,12 @@ copySrcFiles = (interfaceName, projName, projNameUs, projNameHyph) ->
fs.copySync("#{resources}/#{cljsDir}/#{fileName}", path)
edit path, [[projNameHyphRx, projNameHyph], [projNameRx, projName], [platformRx, platform]]
otherFiles = interfaceConf[interfaceName].sources.other;
for cpFile in otherFiles
from = "#{resources}/#{cljsDir}/#{cpFile[0]}"
to = "src/#{cpFile[1]}"
fs.copySync(from, to)
shims = fileNames = interfaceConf[interfaceName].shims;
for namespace in shims
shimCljsNamespace(namespace)
@ -348,7 +370,7 @@ init = (interfaceName, projName) ->
log 'Reload the app in simulator'
log ''
log 'At the REPL prompt type this:', 'yellow'
log "(in-ns '#{projNameHyph}.ios.core)", 'inverse'
log interfaceConf[interfaceName].sampleCommandNs.replace(projNameHyphRx, projNameHyph), 'inverse'
log ''
log 'Changes you make via the REPL or by changing your .cljs files should appear live.', 'yellow'
log ''
@ -476,15 +498,17 @@ cli.version pkgJson.version
cli.command 'init <name>'
.description 'create a new ClojureScript React Native project'
.action (name) ->
.option "-i, --interface [#{interfaceNames.join ' '}]", 'specify React interface', 'reagent'
.action (name, cmd) ->
if typeof name isnt 'string'
logErr '''
re-natal init requires a project name as the first argument.
e.g.
re-natal init HelloWorld
'''
ensureFreePort -> init('reagent', name)
unless interfaceConf[cmd.interface]
logErr "Unsupported React interface: #{cmd.interface}, one of [#{interfaceNames}] was expected."
ensureFreePort -> init(cmd.interface, name)
cli.command 'upgrade'
.description 'upgrades project files to current installed version of re-natal (the upgrade of re-natal itself is done via npm)'

View File

@ -0,0 +1,34 @@
(ns $PROJECT_NAME_HYPHENATED$.$PLATFORM$.core
(:require-macros [natal-shell.components :refer [view text image touchable-highlight]]
[natal-shell.alert :refer [alert]])
(:require [om.next :as om :refer-macros [defui]]
[re-natal.support :as sup]
[$PROJECT_NAME_HYPHENATED$.state :as state]))
(set! js/React (js/require "react-native"))
(def app-registry (.-AppRegistry js/React))
(def logo-img (js/require "./images/cljs.png"))
(defui AppRoot
static om/IQuery
(query [this]
'[:app/msg])
Object
(render [this]
(.log js/console "rendering app")
(let [{:keys [app/msg]} (om/props this)]
(view {:style {:flexDirection "column" :margin 40 :alignItems "center"}}
(text {:style {:fontSize 30 :fontWeight "100" :marginBottom 20 :textAlign "center"}} msg)
(image {:source logo-img
:style {:width 80 :height 80 :marginBottom 30}})
(touchable-highlight {:style {:backgroundColor "#999" :padding 10 :borderRadius 5}
:onPress #(alert "HELLO!")}
(text {:style {:color "white" :textAlign "center" :fontWeight "bold"}} "press me"))))))
(defonce RootNode (sup/root-node 1))
(defonce app-root (om/factory RootNode))
(defn init []
(om/add-root! state/reconciler AppRoot 1)
(.registerComponent app-registry "$PROJECT_NAME$" (fn [] app-root)))

View File

@ -0,0 +1,16 @@
(ns ^:figwheel-no-load env.$PLATFORM$.main
(:require [om.next :as om]
[$PROJECT_NAME_HYPHENATED$.$PLATFORM$.core :as core]
[$PROJECT_NAME_HYPHENATED$.state :as state]
[figwheel.client :as figwheel :include-macros true]))
(enable-console-print!)
(figwheel/watch-and-reload
:websocket-url "ws://localhost:3449/figwheel-ws"
:heads-up-display true
:jsload-callback #(om/add-root! state/reconciler core/AppRoot 1))
(core/init)
(def root-el (core/app-root))

View File

@ -0,0 +1,4 @@
(ns env.$PLATFORM$.main
(:require [$PROJECT_NAME_HYPHENATED$.$PLATFORM$.core :as core]))
(core/init)

View File

@ -0,0 +1,20 @@
(ns $PROJECT_NAME_HYPHENATED$.state
(:require [om.next :as om]
[re-natal.support :as sup]))
(defonce app-state (atom {:app/msg "Hello Clojure in iOS and Android!"}))
(defmulti read om/dispatch)
(defmethod read :default
[{:keys [state]} k _]
(let [st @state]
(if-let [[_ v] (find st k)]
{:value v}
{:value :not-found})))
(defonce reconciler
(om/reconciler
{:state app-state
:parser (om/parser {:read read})
:root-render sup/root-render
:root-unmount sup/root-unmount}))

View File

@ -0,0 +1,35 @@
(ns re-natal.support
(:require [om.next :refer-macros [ui]]))
(def root-nodes (atom {}))
(defn root-node
"A substitute for a real root node (1) for mounting om-next component.
You have to call function :on-render and :on-unmount in reconciler :root-render :root-unmount function."
[id]
(let [content (atom nil)
instance (atom nil)
class (ui Object
(componentWillMount [this] (reset! instance this))
(render [_] @content))]
(swap! root-nodes assoc id {:on-render (fn [el]
(reset! content el)
(when @instance
(.forceUpdate @instance)))
:on-unmount (fn [])
:class class})
class))
(defn root-render
"Use this as reconciler :root-render function."
[el id]
(let [node (get @root-nodes id)
on-render (:on-render node)]
(when on-render (on-render el))))
(defn root-unmount
"Use this as reconciler :root-unmount function."
[id]
(let [node (get @root-nodes id)
unmount-fn (:on-unmount node)]
(when unmount-fn (unmount-fn))))