Created
April 20, 2017 00:57
-
-
Save smitch88/fdbd3a4ded63ba337126052e45f28a00 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 example.dialog | |
(:require [reagent.core :as r] | |
[reagent.dom :as rdom] | |
[clojure.string :refer [blank? join]] | |
[goog.dom :as gdom])) | |
(defn add-container-el | |
[mount-to id {:keys [mount-to]}] | |
(when-not (gdom/getElement id) | |
(let [container-el (.createElement js/document "div")] | |
(aset container-el "id" id) | |
(.appendChild mount-to container-el)))) | |
(defn PortalContainer | |
[uuid {:keys [id class content]}] | |
[:div.portal {:id uuid | |
:key uuid | |
:class class} | |
[:div.portal-content {:id id} | |
content]]) | |
(defn Portal | |
"Wrapping component that places children into a `mount-to` dom node. | |
This generates an empty render container which is populated on update in the | |
container element uuid. This pattern allows for arbitrary | |
DOM positioning of the child node" | |
[{:keys [uuid mount-to] :as props}] | |
(let [uuid (or uuid (rand-int 100000000)) | |
portal-uuid (str "portal-" uuid) | |
container (str "portal-container-" uuid)] | |
(r/create-class | |
{:component-will-unmount | |
(fn [] | |
(when-let [el (gdom/getElement container)] | |
(when-let [parent-node (aget el "parentNode")] | |
(.removeChild parent-node el)))) | |
:component-did-update | |
(fn [this] | |
(let [props (r/props this)] | |
(if (:opened? props) | |
(do | |
(add-container-el mount-to container props) | |
(rdom/render [PortalContainer portal-uuid props] | |
(gdom/getElement container))) | |
(when-let [portal-el (gdom/getElement portal-uuid)] | |
(.remove (gdom/getElement container)))))) | |
:component-did-mount | |
(fn [this] | |
(let [props (r/props this)] | |
(when (:opened? props) | |
(add-container-el mount-to container props) | |
(rdom/render [PortalContainer portal-uuid props] | |
(gdom/getElement container))))) | |
:reagent-render | |
(fn [] nil)}))) | |
(def base-styles | |
{:dialog {:position "fixed" | |
:left 0 | |
:top 0 | |
:height "100%" | |
:width "100%" | |
:z-index 1081 | |
:margin "0 auto"} | |
:overlay {:position "absolute" | |
:left 0 | |
:top 0 | |
:height "100%" | |
:width "100%" | |
:z-index 1 | |
:background-color "rgba(0,0,0,0.8)"} | |
:container {:position "absolute" | |
:height "100%" | |
:width "100%" | |
:z-index 2} | |
:window {:height "auto" | |
:width "50%" | |
:margin "100px auto" | |
:background-color "#ffffff" | |
:border "1px solid #eee"}}) | |
(defn Dialog | |
[{:keys [opened? mount-pt style]} & children] | |
(let [styles (merge-with merge base-styles style)] | |
[Portal {:opened? opened? | |
:mount-to (gdom/getElement mount-pt) | |
:content [:div.dialog {:style (:dialog styles)} | |
[:div.overlay {:style (:overlay styles)}] | |
[:div.container {:style (:container styles)} | |
(into [:div.window {:style (:window styles)}] | |
children)]]}])) | |
;; Example of using generic dialog for specific case | |
(defn specific-dialog [] | |
(let [dialog-opened? (atom false) | |
open-dialog #(reset! dialog-opened? true) | |
close-dialog #(reset! dialog-opened? false) | |
dialog-style {:window {:width 400 | |
:background-color "red"}}] | |
(fn [] | |
[:div [:h1 "Click button to open dialog"] | |
[Dialog {:mount-pt "app" | |
:opened? @dialog-opened? | |
:on-dismiss close-dialog | |
:style dialog-style} | |
[:div {:style {:padding 20}} | |
[:h2 "Header"] | |
[:p "Content"] | |
[:button {:on-click close-dialog} "Close"]]] | |
[:button {:on-click open-dialog} "Open dialog"]]))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment