Last active
November 13, 2019 22:41
-
-
Save jjttjj/9d29a3d93f5598068eb2d5195265e614 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns app.index | |
(:require [cljs.core.async :as a] | |
[lib.dom :as d :refer-macros [tpl-let tpl-with tpl=]])) | |
;;EXAMPLE USAGE | |
(enable-console-print!) | |
(def todos-db (atom {})) | |
(defn todo-input [] | |
(let [val (atom "")] | |
(d/input | |
{:onkeyup #(reset! val (.-target.value %)) | |
:onkeydown #(case (.-which %) | |
13 (do (swap! todos-db | |
assoc | |
(random-uuid) | |
{:text @val | |
:done? false}) | |
(js/console.log %) | |
(set! (.-target.value %) "") | |
) | |
nil)}))) | |
(defn todo-list [] | |
(d/div | |
((d/tpl | |
(fn [todos] | |
(d/ul | |
(for [[id {:keys [text done?]}] todos] | |
(d/li (d/label {:for id} text) | |
(d/input {:id id | |
:type "checkbox" | |
:checked done? | |
:onchange #(swap! todos-db | |
assoc-in | |
[id | |
:done?] | |
(.-target.checked %))})))))) | |
todos-db) | |
;;derefs given atoms, binds to same name | |
(d/tpl-with todos-db | |
(d/div "count:" (count todos-db))) | |
;;more magical version, auto-walks all watchables | |
(d/tpl= | |
(d/div (pr-str todos-db))))) | |
(defn ui [] | |
(d/div | |
(todo-input) | |
(todo-list))) | |
(defn init [] | |
(doto (d/$ "#app") | |
d/clear | |
(d/append (ui)))) | |
(init) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns lib.dom | |
(:require [javelin.core :as j])) | |
(def to-list #(into '() (reverse %))) | |
(defmacro tpl= [expr] | |
(let [[f args] (j/hoist expr &env)] | |
(to-list `((tpl ~f) ~@args)))) | |
;;todo:consider destructuring | |
(defmacro tpl-let [bindings & body] | |
`(let ~bindings ;;(destructure bindings) | |
((tpl | |
(fn ~(vec (take-nth 2 bindings)) ~@body)) | |
~@(take-nth 2 bindings)))) | |
(defmacro tpl-with [& args] | |
(let [tpl-args (butlast args) | |
body (last args)] | |
`((tpl (fn ~(vec tpl-args) ~body)) | |
~@tpl-args))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns lib.dom | |
(:require [goog.dom :as gdom] | |
[goog.object :as gobj] | |
[goog.array :as garr] | |
[goog.style :as gstyle] | |
["set-dom" :as set-dom]) | |
(:require-macros [lib.dom :refer [tpl-let tpl-with tpl=]])) | |
(defn $ [selector] | |
(js/document.querySelector selector)) | |
(defn append [node & children] | |
(doto node (gdom/append (garr/flatten (clj->js children))))) | |
(defn frag [& kids] | |
(doto (js/document.createDocumentFragment) (append kids))) | |
(defn clear [node] | |
(gdom/removeChildren node) | |
node) | |
(defn set-styles [node kvs] | |
(doseq [[k v] kvs] | |
(gobj/set (.-style node) (name k) (str v))) | |
node) | |
(defn elem-fn | |
"Creates a function which creates a dom node of type tagname. The | |
created function takes an optional attribute map as a first argument | |
followed by any number of child nodes. Nodes are created via | |
`goog.dom/createDom`, so attributes are created via | |
`goog.dom/setProperties`." | |
[tag-name] | |
(fn [& attrs-kids] | |
(let [maybe-attrs (first attrs-kids) | |
is-attr? (map? maybe-attrs) | |
attrs (if is-attr? maybe-attrs {}) | |
styled? (and is-attr? (:style attrs)) | |
kids (if is-attr? (rest attrs-kids) attrs-kids) | |
elem (->> (map #(if (number? %) (str %) %) kids) | |
clj->js | |
garr/flatten | |
(gdom/createDom tag-name (clj->js attrs)))] | |
(cond-> elem ;;note: this slows things down | |
styled? (set-styles (:style attrs)))))) | |
(defn reconciliate! [old-el new-el] | |
(set-dom old-el new-el)) | |
(defn deref* | |
"If x is derefable, deref it, otherwise returns x." | |
[x] | |
(if (satisfies? cljs.core/IDeref x) @x x)) | |
(defn tpl | |
"Takes a dom-element-returning-function of any number of arguments | |
that may implement IWatchable. Returns the element. When any | |
watchable arguments change, re-runs the function and reconciliates | |
the old element with the new one" | |
[f] | |
(fn [& args] | |
(let [e (apply f (map deref* args))] | |
(doseq [arg (filter #(satisfies? cljs.core/IWatchable %) args)] | |
(add-watch | |
arg (gensym) | |
(fn [k ref o new] | |
(->> (map #(if (= % ref) new (deref* %)) args) | |
(apply f) | |
(reconciliate! e))))) | |
e))) | |
(def a (elem-fn "a")) | |
(def abbr (elem-fn "abbr")) | |
(def address (elem-fn "address")) | |
(def area (elem-fn "area")) | |
(def article (elem-fn "article")) | |
(def aside (elem-fn "aside")) | |
(def audio (elem-fn "audio")) | |
(def b (elem-fn "b")) | |
(def base (elem-fn "base")) | |
(def bdi (elem-fn "bdi")) | |
(def bdo (elem-fn "bdo")) | |
(def blockquote (elem-fn "blockquote")) | |
(def br (elem-fn "br")) | |
(def button (elem-fn "button")) | |
(def canvas (elem-fn "canvas")) | |
(def caption (elem-fn "caption")) | |
(def cite (elem-fn "cite")) | |
(def code (elem-fn "code")) | |
(def col (elem-fn "col")) | |
(def colgroup (elem-fn "colgroup")) | |
(def data (elem-fn "data")) | |
(def datalist (elem-fn "datalist")) | |
(def dd (elem-fn "dd")) | |
(def del (elem-fn "del")) | |
(def details (elem-fn "details")) | |
(def dfn (elem-fn "dfn")) | |
(def dialog (elem-fn "dialog")) | |
(def div (elem-fn "div")) | |
(def dl (elem-fn "dl")) | |
(def dt (elem-fn "dt")) | |
(def em (elem-fn "em")) | |
(def embed (elem-fn "embed")) | |
(def fieldset (elem-fn "fieldset")) | |
(def figcaption (elem-fn "figcaption")) | |
(def figure (elem-fn "figure")) | |
(def footer (elem-fn "footer")) | |
(def form (elem-fn "form")) | |
(def h1 (elem-fn "h1")) | |
(def h2 (elem-fn "h2")) | |
(def h3 (elem-fn "h3")) | |
(def h4 (elem-fn "h4")) | |
(def h5 (elem-fn "h5")) | |
(def h6 (elem-fn "h6")) | |
(def header (elem-fn "header")) | |
(def hgroup (elem-fn "hgroup")) | |
(def hr (elem-fn "hr")) | |
(def i (elem-fn "i")) | |
(def iframe (elem-fn "iframe")) | |
(def img (elem-fn "img")) | |
(def input (elem-fn "input")) | |
(def ins (elem-fn "ins")) | |
(def kbd (elem-fn "kbd")) | |
(def keygen (elem-fn "keygen")) | |
(def label (elem-fn "label")) | |
(def legend (elem-fn "legend")) | |
(def li (elem-fn "li")) | |
(def link (elem-fn "link")) | |
(def main (elem-fn "main")) | |
(def html-map (elem-fn "map")) | |
(def mark (elem-fn "mark")) | |
(def menu (elem-fn "menu")) | |
(def menuitem (elem-fn "menuitem")) | |
(def html-meta (elem-fn "meta")) | |
(def meter (elem-fn "meter")) | |
(def multicol (elem-fn "multicol")) | |
(def nav (elem-fn "nav")) | |
(def noframes (elem-fn "noframes")) | |
(def noscript (elem-fn "noscript")) | |
(def html-object (elem-fn "object")) | |
(def ol (elem-fn "ol")) | |
(def optgroup (elem-fn "optgroup")) | |
(def option (elem-fn "option")) | |
(def output (elem-fn "output")) | |
(def p (elem-fn "p")) | |
(def param (elem-fn "param")) | |
(def picture (elem-fn "picture")) | |
(def pre (elem-fn "pre")) | |
(def progress (elem-fn "progress")) | |
(def q (elem-fn "q")) | |
(def rp (elem-fn "rp")) | |
(def rt (elem-fn "rt")) | |
(def rtc (elem-fn "rtc")) | |
(def ruby (elem-fn "ruby")) | |
(def s (elem-fn "s")) | |
(def samp (elem-fn "samp")) | |
(def script (elem-fn "script")) | |
(def section (elem-fn "section")) | |
(def select (elem-fn "select")) | |
(def shadow (elem-fn "shadow")) | |
(def small (elem-fn "small")) | |
(def source (elem-fn "source")) | |
(def span (elem-fn "span")) | |
(def strong (elem-fn "strong")) | |
(def style (elem-fn "style")) | |
(def sub (elem-fn "sub")) | |
(def summary (elem-fn "summary")) | |
(def sup (elem-fn "sup")) | |
(def table (elem-fn "table")) | |
(def tbody (elem-fn "tbody")) | |
(def td (elem-fn "td")) | |
(def template (elem-fn "template")) | |
(def textarea (elem-fn "textarea")) | |
(def tfoot (elem-fn "tfoot")) | |
(def th (elem-fn "th")) | |
(def thead (elem-fn "thead")) | |
(def html-time (elem-fn "time")) | |
(def title (elem-fn "title")) | |
(def tr (elem-fn "tr")) | |
(def track (elem-fn "track")) | |
(def u (elem-fn "u")) | |
(def ul (elem-fn "ul")) | |
(def html-var (elem-fn "var")) | |
(def video (elem-fn "video")) | |
(def wbr (elem-fn "wbr")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment