ClojureScript application framework.
ClojureScript single-page application framework inspired by re-frame, Elm Architecture, Redux and Cerebral.
Carry provides a structure for making GUI application code easier to modify, debug, test and be worked on by multiple programmers.
The core of the framework is a simple state management library. UI bindings, routing, debugger, etc. are implemented as separate optional packages.
Stable. Was used in production.
I now focus on the successor Aide framework instead.
Carry enforces:
It also advises to decouple view and view model code in the presentation layer:
HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Carry • Counter</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body>
<div id="root"></div>
<script src="js/compiled/frontend.js" type="text/javascript"></script>
</body>
</html>
Main file:
(ns app.core
(:require [counter.core :as counter]
[carry.core :as carry]
[carry-reagent.core :as carry-reagent]
[reagent.core :as r]))
(let [app (carry/app counter/blueprint)
[_ app-view] (carry-reagent/connect app counter/view-model counter/view)]
(r/render app-view (.getElementById js/document "root"))
((:dispatch-signal app) :on-start))
UI (using Reagent and carry-reagent):
(ns counter.core
(:require [cljs.core.match :refer-macros [match]]
[reagent.ratom :refer [reaction]]))
(defn view-model
[model]
{:counter (reaction (str "#" (:val @model)))})
(defn view
[{:keys [counter] :as _view-model} dispatch]
[:p
@counter " "
[:button {:on-click #(dispatch :on-increment)} "+"] " "
[:button {:on-click #(dispatch :on-decrement)} "-"] " "
[:button {:on-click #(dispatch :on-increment-if-odd)} "Increment if odd"] " "
[:button {:on-click #(dispatch :on-increment-async)} "Increment async"]])
Blueprint:
(def -initial-model {:val 0})
(defn -on-signal
[model signal _dispatch-signal dispatch-action]
(match signal
:on-start nil
:on-stop nil
:on-increment
(dispatch-action :increment)
:on-decrement
(dispatch-action :decrement)
:on-increment-if-odd
(when (odd? (:val @model))
(dispatch-action :increment))
:on-increment-async
(.setTimeout js/window #(dispatch-action :increment) 1000)))
(defn -on-action
[model action]
(match action
:increment (update model :val inc)
:decrement (update model :val dec)))
(def blueprint {:initial-model -initial-model
:on-signal -on-signal
:on-action -on-action})
More information can be found at the project site:
Copyright © 2016 Yuri Govorushchenko.
Released under an MIT license.