Skip to content

Instantly share code, notes, and snippets.

@martinklepsch
Last active August 29, 2015 14:20
Show Gist options
  • Save martinklepsch/58bf7da3aeec6b748aed to your computer and use it in GitHub Desktop.
Save martinklepsch/58bf7da3aeec6b748aed to your computer and use it in GitHub Desktop.
(ns ui.flag
(:require [reagent.core :as reagent :refer [atom]]))
(defn flag
"Simple flag object component as described by Harry Roberts:
http://csswizardry.com/2013/05/the-flag-object"
[& {:keys [image bodies]}]
[:div.flag
[:div.flag__image image]
(for [b bodies]
[:div.flag__body b])])
(defn expandable-flag
"An extension of the flag object that will maintain initial
positioning even if flag body expands.
Example (note the +/~ difference):
+-----+
| (I) | ++++++++++++++
+-----+
If the flag body is being expanded the vertical centering would
be maintained, causing a jump of the flag image (I):
++++++++++++++
+-----+ ~~ ~~~~~~~~~
| (I) | ~~~~~~ ~~~~~
+-----+ ~~ ~~~~~~~~~
~~~~~ ~~~
Now the expandable flag object maintains the initial positioning,
avoiding any jumps while still achieving perfect vertical alignment
of the unexpanded flag (keep in mind that the ++ lines could also be
higher than the image):
+-----+
| (I) | ++++++++++++++
+-----+ ~~ ~~~~~~~~~
~~~~~~ ~~~~~
~~ ~~~~~~~~~
~~~~~ ~~~
--- Keyword Arguments ---
- `image`: simple component which will be rendered as flag image
- `bodies`: list of body components. Either plain components or
components taking a boolean `expanded` parameter
- `expanded?`: Whether the flag is currently expanded or not
--- Caveat ---
This uses a local atom to store state and any remounting,
as it's done by Figwheel and the likes, will cause the values to be reset.
Depending on the state the flag is in this can result in odd behaviour.
(Should only ever occur in live-reloading workflows.)"
[& {:keys [image bodies expanded?]}]
(let [pads (atom [])
pad (fn [ex i] {:style {:padding-top (if ex (str (get @pads i) "px"))}})]
(reagent/create-class
{:component-did-mount
(fn [cmpnt]
(when (and (empty? @pads) (not expanded?))
(let [h (.-offsetHeight (reagent/dom-node cmpnt))
c (array-seq (.-children (reagent/dom-node cmpnt)))
ps (mapv #(/ (- h (-> % .-firstChild .-offsetHeight)) 2) c)]
(reset! pads ps))))
:reagent-render
(fn [& {:keys [image bodies expanded?]}]
[:div.flag {:class (if expanded? "flag--top")}
[:div.flag__image (pad expanded? 0) image]
(map-indexed (fn [i b]
[:div.flag__body
(pad expanded? (inc i))
(if (fn? b) [b expanded?] b)])
bodies)])})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment