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