-
-
Save mccraigmccraig/05637d98213988ff577e2d533966a292 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 er-webui.components.swipable.views | |
(:require-macros | |
[schema.core :as sm]) | |
(:require | |
[clojure.string :as str] | |
[taoensso.timbre :refer-macros [debug info warn]] | |
[reagent.core :as r] | |
[re-frame.core | |
:refer [reg-sub-raw subscribe reg-event-db dispatch]] | |
[schema.core :as s] | |
[er-model.util.set :as setu] | |
[er-webui.util.dom :as dom] | |
[er-webui.util.hiccup :as hu] | |
[er-webui.util.touch :as touch] | |
[er-webui.util.touch.swipe :as touch-swipe])) | |
(defn transform-style | |
[{x :x y :y z :z}] | |
(let [s (str "translate3d(" | |
(or x 0) "px, " | |
(or y 0) "px, " | |
(or z 0) "px)")] | |
{:-webkit-transform s | |
:transform s})) | |
(defn reveal-style | |
[swipe-reveals reveal] | |
(case reveal | |
:left (transform-style {:x (- (touch-swipe/direction-value swipe-reveals reveal))}) | |
:right (transform-style {:x (touch-swipe/direction-value swipe-reveals reveal)}) | |
:up (transform-style {:y (- (touch-swipe/direction-value swipe-reveals reveal))}) | |
:down (transform-style {:y (touch-swipe/direction-value swipe-reveals reveal)}))) | |
(defn reveal->transform | |
[swipe-reveals reveal] | |
(case reveal | |
:left {:x (- (touch-swipe/direction-value swipe-reveals reveal))} | |
:right {:x (touch-swipe/direction-value swipe-reveals reveal)} | |
:up {:y (- (touch-swipe/direction-value swipe-reveals reveal))} | |
:down {:y (touch-swipe/direction-value swipe-reveals reveal)})) | |
(defn touch-move->transform | |
([touch-move] | |
(touch-move->transform nil touch-move)) | |
([{start-x :x | |
start-y :y | |
:or {start-x 0 start-y 0} | |
:as start-transform} | |
touch-move] | |
(->> (for [dir touch-swipe/swipe-directions-set] | |
(when-let [d (get touch-move dir)] | |
(when (>= d 0) ;; only take the +ve of opposing dirs | |
(case dir | |
:left [:x (- start-x d)] | |
:right [:x (+ start-x d)] | |
:up [:y (- start-y d)] | |
:down [:y (+ start-y d)])))) | |
(filter identity) | |
(into {})))) | |
(defn limit-value | |
[lower upper n] | |
(->> n | |
(max (or lower n)) | |
(min (or upper n)))) | |
(defn limit-transform | |
[{l-left :left | |
l-right :right | |
l-up :up | |
l-down :down | |
:as limits} | |
transform] | |
(let [r (->> (for [[k v] transform] | |
[k | |
(case k | |
:x (limit-value (when l-left (- l-left)) l-right v) | |
:y (limit-value (when l-up (- l-up)) l-down v) | |
v)]) | |
(into {}))] | |
;; (info "limit-transform" limits transform r) | |
r)) | |
(def initial-transform | |
{:x 0 :y 0 :z 0}) | |
(def initial-reveal-state | |
{;; set when a swipe has completed successfully | |
:reveal nil | |
;; set when a swipe is in progress | |
:transform initial-transform | |
;; set when a swipe has completed or cancelled | |
;; and final animation is taking place | |
:animate nil | |
;; the final touch-move at which a swipe was cancelled | |
:cancelled-at nil}) | |
(sm/defn ^:always-validate swipe-to-reveal | |
([opts content revealed-content] | |
(swipe-to-reveal nil opts content revealed-content)) | |
([el :- (s/maybe s/Keyword) | |
{swipe-directions :swipe-directions | |
swipe-thresholds :swipe-thresholds | |
swipe-reveals :swipe-reveals | |
swipe-limits :swipe-limits | |
:as opts} :- {:swipe-directions touch-swipe/SwipeDirections | |
:swipe-thresholds touch-swipe/SwipeDirectionValues | |
:swipe-reveals touch-swipe/SwipeDirectionValues | |
:swipe-limits touch-swipe/SwipeDirectionValues} | |
content | |
revealed-content] | |
(let [dn-a (atom nil) | |
;; need to re-render when swipe-handlers are set, so r/atom | |
swipe-handlers-a (r/atom nil) | |
reveal-state-a (r/atom initial-reveal-state)] | |
(r/create-class | |
{:display-name | |
"swipe-to-reveal" | |
:component-did-mount | |
(fn [ref] | |
(reset! dn-a (r/dom-node ref)) | |
(reset! swipe-handlers-a | |
(touch/touch-handlers | |
(touch-swipe/create-touch-swipe-state | |
@dn-a | |
{:swipe-directions (touch-swipe/add-opposing-directions | |
swipe-directions) | |
:swipe-thresholds swipe-thresholds | |
:on-start-fn (fn [tm] | |
(if (:reveal @reveal-state-a) | |
(swap! reveal-state-a | |
assoc | |
:transform | |
(reveal->transform | |
swipe-reveals | |
(:reveal @reveal-state-a))) | |
(reset! reveal-state-a | |
initial-reveal-state)) | |
(info "on-start-fn" @reveal-state-a)) | |
:on-move-fn (fn [tm] | |
(cond | |
(and | |
(:reveal @reveal-state-a) | |
(:transform @reveal-state-a)) | |
(swap! reveal-state-a | |
assoc | |
:transform | |
(limit-transform | |
swipe-limits | |
(touch-move->transform | |
(reveal->transform | |
swipe-reveals | |
(:reveal @reveal-state-a)) | |
tm))) | |
(:transform @reveal-state-a) | |
(swap! reveal-state-a | |
assoc | |
:transform | |
(limit-transform | |
swipe-limits | |
(touch-move->transform | |
tm))))) | |
:on-swipe-fn (fn [swipe] | |
(info "on-swipe-fn" swipe) | |
(cond | |
(and | |
(:reveal @reveal-state-a) | |
(:transform @reveal-state-a) | |
(= (touch-swipe/opposing-direction | |
(:reveal @reveal-state-a)) | |
(-> swipe first first))) | |
(let [sk (-> swipe first first)] | |
(reset! reveal-state-a | |
{:reveal nil | |
:transform nil | |
:animate :home | |
:cancelled-at swipe})) | |
;; swipe in a permitted direction | |
(and (:transform @reveal-state-a) | |
(contains? | |
(setu/coerce swipe-directions) | |
(-> swipe first first))) | |
(let [sk (-> swipe first first)] | |
(reset! reveal-state-a | |
{:reveal sk | |
:transform nil | |
:animate sk | |
:cancelled-at nil})) | |
;; not a permitted direction | |
(:transform @reveal-state-a) | |
(reset! reveal-state-a | |
{:reveal nil | |
:transform nil | |
:animate :home | |
:cancelled-at swipe}))) | |
:on-cancel-fn (fn [tm] | |
(cond | |
(:reveal @reveal-state-a) | |
(reset! reveal-state-a | |
{:reveal (:reveal @reveal-state-a) | |
:transform nil | |
:animate (:reveal @reveal-state-a) | |
:cancelled-at tm}) | |
:else | |
(reset! reveal-state-a | |
{:reveal nil | |
:transform nil | |
:animate :home | |
:cancelled-at tm})))})))) | |
:component-will-unmount | |
(fn [_] | |
(reset! dn-a nil) | |
(reset! swipe-handlers-a nil) | |
(reset! reveal-state-a initial-reveal-state)) | |
:reagent-render | |
(fn swipe-to-reveal-r | |
([opts content revealed-content] | |
(swipe-to-reveal-r nil opts content revealed-content)) | |
([el | |
{swipe-directions :swipe-directions | |
swipe-thresholds :swipe-thresholds | |
swipe-reveals :swipe-reveals | |
swipe-limits :swipe-limits | |
:as opts} | |
content | |
revealed-content] | |
(let [opts (dissoc opts | |
:swipe-directions | |
:swipe-thresholds | |
:swipe-reveals | |
:swipe-limits) | |
{rs-reveal :reveal | |
rs-transform :transform | |
rs-animate :animate | |
:as reveal-state} @reveal-state-a] | |
[(or el :div.swipe-to-reveal-container) | |
(merge opts @swipe-handlers-a) | |
[:div.swipe-to-reveal-content-wrapper | |
{ | |
:on-click-capture (fn [e] | |
(info "on-click-capture" @reveal-state-a) | |
(cond | |
(and (:reveal @reveal-state-a) | |
(:cancelled-at @reveal-state-a)) | |
(do | |
(.preventDefault e) | |
(.stopPropagation e) | |
;; click on the main content when revealed | |
;; closes the reveal | |
(when (< (->> @reveal-state-a | |
:cancelled-at | |
vals | |
(map #(js/Math.abs %)) | |
(apply max)) | |
10) | |
(reset! reveal-state-a | |
{:reveal nil | |
:transform nil | |
:animate :home | |
:cancelled-at nil}))) | |
(:reveal @reveal-state-a) | |
(do | |
(.preventDefault e) | |
(.stopPropagation e)) | |
;; ignore click and drag which didn't swipe | |
(and (:cancelled-at @reveal-state-a) | |
(> (->> @reveal-state-a | |
:cancelled-at | |
vals | |
(map #(js/Math.abs %)) | |
(apply max)) | |
10)) | |
(do | |
(.preventDefault e) | |
(.stopPropagation e)))) | |
:style (cond | |
rs-transform (transform-style rs-transform) | |
(touch-swipe/swipe-directions-set rs-reveal) | |
(reveal-style swipe-reveals rs-reveal) | |
:else (transform-style initial-transform)) | |
;; :class (cond | |
;; (= :home rs-animate) | |
;; "animate animate-home" | |
;; (= :left rs-animate) | |
;; "animate animate-left" | |
;; :else nil) | |
} | |
content] | |
(hu/into-or-wrap | |
[:div.swipe-to-reveal-revealed-content-wrapper] | |
revealed-content)])))})))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment