fulcro-rad-carbon/src/main/com/fulcrologic/rad/rendering/semantic_ui/components.cljc

93 lines
4.5 KiB
Clojure

(ns com.fulcrologic.rad.rendering.semantic-ui.components
(:require
#?@(:cljs
[[com.fulcrologic.fulcro.dom :as dom :refer [div label input]]
[com.fulcrologic.semantic-ui.modules.dropdown.ui-dropdown :refer [ui-dropdown]]]
:clj
[[com.fulcrologic.fulcro.dom-server :as dom :refer [div label input]]])
[com.fulcrologic.fulcro.components :as comp :refer [defsc]]
[com.fulcrologic.fulcro.algorithms.transit :as ftransit]
[taoensso.timbre :as log]))
(defn sui-format->user-format
"Converts transit encoded value(s), used by Semantic UI, into CLJS datastructure."
[{:keys [multiple]} value]
(if multiple
(into [] (map ftransit/transit-str->clj value))
(ftransit/transit-str->clj value)))
(defn user-format->sui-format [{:keys [multiple]} value]
"Converts CLJS datastructure into transit encoded string(s), usable by Semantic UI."
(if multiple
(if value
(to-array (map ftransit/transit-clj->str value))
#js [])
(if (or value (boolean? value))
(ftransit/transit-clj->str value)
"")))
(defn wrapped-onChange
"Wraps userOnChange fn with try/catch and sui-form->user-format conversion."
[props userOnChange]
(fn [_ v]
#?(:cljs
(try
(if (and (.-value v) (seq (.-value v)))
(let [value (sui-format->user-format props (.-value v))]
(when (and value userOnChange) (userOnChange value)))
(userOnChange nil))
(catch :default e
(log/error e "Unable to read dropdown value " (when v (.-value v))))))))
(defsc WrappedDropdown [this {:keys [onChange value multiple] :as props}]
{:initLocalState (fn [this]
#?(:cljs
(let [xform-options (memoize (fn [options]
(clj->js (mapv (fn [{:keys [text value]}]
#js {:text text :value (some-> value (ftransit/transit-clj->str))})
options))))
xform-value (fn [multiple? value]
(user-format->sui-format {:multiple multiple?} value))]
{:get-options (fn [props] (xform-options (:options props)))
:format-value (fn [props value] (xform-value (:multiple props) value))})))}
#?(:cljs
(let [{:keys [get-options format-value]} (comp/get-state this)
userOnChange onChange
options (get-options props)
value (format-value props value)
props (merge
{:search true
:selection true
:closeOnBlur true
:openOnFocus true
:selectOnBlur true
:selectOnNavigation true
:multiple (boolean multiple)}
props
{:value value
:options options
:onChange (fn [e v]
(try
(let [string-value (.-value v)
value (if multiple
(mapv #(when (seq %) (ftransit/transit-str->clj %)) string-value)
(when (seq string-value) (ftransit/transit-str->clj string-value)))]
(when userOnChange
(userOnChange value)))
(catch :default e
(log/error "Unable to read dropdown value " e (when v (.-value v))))))})]
(ui-dropdown props))
:clj
(dom/div :.ui.selection.dropdown
(dom/input {:type "hidden"})
(dom/i :.dropdown.icon)
(dom/div :.default.text "")
(dom/div :.menu))))
(def ui-wrapped-dropdown
"Draw a SUI dropdown with the given props. The arguments are identical to sui/ui-dropdown, but options and onChange
are auto-wrapped so that clojure data (e.g. keywords) can be used for the option :value fields. It also defaults
a number of things (:search, :closeOnBlue, openOnFocus, selectOnBlue, and :selectOnNavigation) to true, but you can"
(comp/factory WrappedDropdown))