From 274fca97d8cac7670d2f164d514cc011e57292c5 Mon Sep 17 00:00:00 2001 From: Ike Mawira Date: Thu, 18 Feb 2021 02:30:28 +0300 Subject: [PATCH] Restyle slider component - Add slider :unstyled? arg - Add slider :disabled state parts - Change slider styles to use garden and spade --- project.clj | 4 ++- src/re_com/box.cljs | 48 ++++++++++++++++++++++++++++++++++++ src/re_com/slider.cljs | 55 ++++++++++++++++++++++++++---------------- 3 files changed, 85 insertions(+), 22 deletions(-) diff --git a/project.clj b/project.clj index 4717fd44..4a2b8f03 100644 --- a/project.clj +++ b/project.clj @@ -17,7 +17,9 @@ [thheller/shadow-cljs "2.11.18" :scope "provided"] [reagent "0.10.0" :scope "provided"] [org.clojure/core.async "1.3.610"] - [com.andrewmcveigh/cljs-time "0.5.2"]] + [com.andrewmcveigh/cljs-time "0.5.2"] + [garden "1.3.10"] + [net.dhleong/spade "1.0.4"]] :plugins [[day8/lein-git-inject "0.0.14"] [lein-shadow "0.3.1"] diff --git a/src/re_com/box.cljs b/src/re_com/box.cljs index 09f9c45d..ee95d4a1 100644 --- a/src/re_com/box.cljs +++ b/src/re_com/box.cljs @@ -3,7 +3,10 @@ [re-com.debug :refer [src-coordinates]] [re-com.validate :refer [validate-args-macro]]) (:require + [spade.core :refer [defclass]] [clojure.string :as string] + [garden.units :as u] + [garden.selectors :as s] [re-com.config :refer [include-args-desc?]] [re-com.debug :refer [src->attr]] [re-com.validate :refer [justify-style? justify-options-list align-style? align-options-list scroll-style? @@ -64,6 +67,51 @@ {:-webkit-flex flex :flex flex})) +;Determines the value for the 'flex' attribute (which has grow, shrink and basis), based on the :size parameter. +; IMPORTANT: The term 'size' means width of the item in the case of flex-direction 'row' OR height of the item in the case of flex-direction 'column'. +; Flex property explanation: +; - grow Integer ratio (used with other siblings) to determined how a flex item grows it's size if there is extra space to distribute. 0 for no growing. +; - shrink Integer ratio (used with other siblings) to determined how a flex item shrinks it's size if space needs to be removed. 0 for no shrinking. +; - basis Initial size (width, actually) of item before any growing or shrinking. Can be any size value, e.g. 60%, 100px, auto +; Note: auto will cause the initial size to be calculated to take up as much space as possible, in conjunction with it's siblings :flex settings. +; Supported values: +; - initial '0 1 auto' - Use item's width/height for dimensions (or content dimensions if w/h not specifed). Never grow. Shrink (to min-size) if necessary. +; Good for creating boxes with fixed maximum size, but that can shrink to a fixed smaller size (min-width/height) if space becomes tight. +; NOTE: When using initial, you should also set a width/height value (depending on flex-direction) to specify it's default size +; and an optional min-width/height value to specify the size it can shrink to. +; - auto '1 1 auto' - Use item's width/height for dimensions. Grow if necessary. Shrink (to min-size) if necessary. +; Good for creating really flexible boxes that will gobble as much available space as they are allowed or shrink as much as they are forced to. +; - none '0 0 auto' - Use item's width/height for dimensions (or content dimensions if not specifed). Never grow. Never shrink. +; Good for creating rigid boxes that stick to their width/height if specified, otherwise their content size. +; - 100px '0 0 100px' - Non flexible 100px size (in the flex direction) box. +; Good for fixed headers/footers and side bars of an exact size. +; - 60% '60 1 0px' - Set the item's size (it's width/height depending on flex-direction) to be 60% of the parent container's width/height. +; NOTE: If you use this, then all siblings with percentage values must add up to 100%. +; - 60 '60 1 0px' - Same as percentage above. +; - grow shrink basis 'grow shrink basis' - If none of the above common valaues above meet your needs, this gives you precise control. +; If number of words is not 1 or 3, an exception is thrown. +; Reference: http://www.w3.org/TR/css3-flexbox/#flexibility +; Diagram: http://www.w3.org/TR/css3-flexbox/#flex-container +; Regex101 testing: ^(initial|auto|none)|(\\d+)(px|%|em)|(\\d+)\\w(\\d+)\\w(.*) - remove double backslashes +(defclass spade-flex-child-style + [size] + ;; TODO: Could make initial/auto/none into keywords??? + (let [split-size (string/split (string/trim size) #"\s+") ;; Split into words separated by whitespace + split-count (count split-size) + _ (assert (contains? #{1 3} split-count) "Must pass either 1 or 3 words to flex-child-style") + size-only (when (= split-count 1) (first split-size)) ;; Contains value when only one word passed (e.g. auto, 60px) + split-size-only (when size-only (string/split size-only #"(\d+)(.*)")) ;; Split into number + string + [_ num units] (when size-only split-size-only) ;; grab number and units + pass-through? (nil? num) ;; If we can't split, then we'll pass this straign through + grow-ratio? (or (= units "%") (= units "") (nil? units)) ;; Determine case for using grow ratio + grow (if grow-ratio? num "0") ;; Set grow based on percent or integer, otherwise no grow + shrink (if grow-ratio? "1" "0") ;; If grow set, then set shrink to even shrinkage as well + basis (if grow-ratio? (u/px 0) size) ;; If grow set, then even growing, otherwise set basis size to the passed in size (e.g. 100px, 5em) + flex (if (and size-only (not pass-through?)) + (str grow " " shrink " " basis) + size)] + {:-webkit-flex flex + :flex flex})) (defn flex-flow-style "A cross-browser helper function to output flex-flow with all it's potential browser prefixes" diff --git a/src/re_com/slider.cljs b/src/re_com/slider.cljs index bfaae623..85c8ee9f 100644 --- a/src/re_com/slider.cljs +++ b/src/re_com/slider.cljs @@ -4,13 +4,16 @@ [re-com.debug :refer [src-coordinates]] [re-com.validate :refer [validate-args-macro]]) (:require - [re-com.config :refer [include-args-desc?]] - [re-com.debug :refer [src->attr]] - [re-com.util :refer [deref-or-value px]] - [re-com.popover :refer [popover-tooltip]] - [re-com.box :refer [h-box v-box box gap line flex-child-style align-style]] - [re-com.validate :refer [input-status-type? input-status-types-list regex? string-or-hiccup? css-style? html-attr? parts? - number-or-string? string-or-atom? nillable-string-or-atom? throbber-size? throbber-sizes-list]])) + [spade.core :refer [defclass]] + [garden.units :as u] + [garden.selectors :as s] + [re-com.config :refer [include-args-desc?]] + [re-com.debug :refer [src->attr]] + [re-com.util :refer [deref-or-value px]] + [re-com.popover :refer [popover-tooltip]] + [re-com.box :refer [h-box v-box box gap line spade-flex-child-style flex-child-style align-style]] + [re-com.validate :refer [input-status-type? input-status-types-list regex? string-or-hiccup? css-style? html-attr? parts? + number-or-string? string-or-atom? nillable-string-or-atom? throbber-size? throbber-sizes-list]])) ;; ------------------------------------------------------------------------------------ ;; Component: slider @@ -18,8 +21,11 @@ (def slider-parts-desc (when include-args-desc? - [{:name :wrapper :level 0 :class "rc-slider-wrapper" :impl "[slider]" :notes "Outer wrapper of the slider."} - {:type :legacy :level 1 :class "rc-slider" :impl "[:input]" :notes "The actual input field."}])) + [{:name :wrapper :level 0 :class "rc-slider-wrapper" :impl "[slider]" :notes "Outer wrapper of the slider when disabled is false."} + {:name :wrapper:disabled :level 0 :class "rc-slider-wrapper" :impl "[slider]" :notes "Outer wrapper of the slider when disabled? is true."} + {:type :legacy :level 1 :class "rc-slider" :impl "[:input]" :notes "The actual input field."} + {:name :input :level 1 :class "rc-slider" :impl "[:input]" :notes "The actual input field when disabled? is false."} + {:name :input:disabled :level 1 :class "rc-slider" :impl "[:input]" :notes "The actual input field when disabled? is true."}])) (def slider-parts (when include-args-desc? @@ -38,11 +44,20 @@ {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "CSS styles to add or override (applies to the slider, not the wrapping div)"} {:name :attr :required false :type "HTML attr map" :validate-fn html-attr? :description [:span "HTML attributes, like " [:code ":on-mouse-move"] [:br] "No " [:code ":class"] " or " [:code ":style"] "allowed (applies to the slider, not the wrapping div)"]} {:name :parts :required false :type "map" :validate-fn (parts? slider-parts) :description "See Parts section below."} + {:name :unstyled? :required false :default false :type "boolean" :description [:span "if true, all default CSS classes and styles are removed. Enables you to provide your own styling via " [:code ":parts"]]} {:name :src :required false :type "map" :validate-fn map? :description "Source code coordinates. See 'Debugging'."}])) +;:-webkit-appearance "slider-vertical" ;; TODO: Make a :orientation (:horizontal/:vertical) option +;:writing-mode "bt-lr" ;; Make IE slider vertical +(defclass slider-style + [width disabled?] + {:composes (spade-flex-child-style "none") + :width (or width (u/px 400)) + :cursor (if disabled? :default :pointer)}) + (defn slider "Returns markup for an HTML5 slider input" - [& {:keys [model min max step width on-change disabled? class style attr parts src] + [& {:keys [model min max step width on-change disabled? class style attr parts unstyled? src] :or {min 0 max 100} :as args}] (or @@ -54,26 +69,24 @@ disabled? (deref-or-value disabled?)] [box :src src - :class (str "rc-slider-wrapper " (get-in parts [:wrapper :class])) - :style (get-in parts [:wrapper :style] {}) - :attr (get-in parts [:wrapper :attr] {}) + :class (str (if unstyled? "" "rc-slider-wrapper ") + (if-not disabled? (get-in parts [:wrapper :class]) (get-in parts [:wrapper:disabled :class]))) + :style (if-not disabled? (get-in parts [:wrapper :style]) (get-in parts [:wrapper:disabled :style])) + :attr (if-not disabled? (get-in parts [:wrapper :attr]) (get-in parts [:wrapper:disabled :attr])) :align :start :child [:input (merge - {:class (str "rc-slider " class) + {:class (str (if unstyled? "" (str "rc-slider " (slider-style width disabled?))) + (if-not disabled? (get-in parts [:input :class]) (get-in parts [:input:disabled :class])) + class) :type "range" ;:orient "vertical" ;; Make Firefox slider vertical (doesn't work because React ignores it, I think) - :style (merge - (flex-child-style "none") - {;:-webkit-appearance "slider-vertical" ;; TODO: Make a :orientation (:horizontal/:vertical) option - ;:writing-mode "bt-lr" ;; Make IE slider vertical - :width (or width "400px") - :cursor (if disabled? "default" "pointer")} - style) + :style (merge style (if-not disabled? (get-in parts [:input :style]) (get-in parts [:input:disabled :style]))) :min min :max max :step step :value model :disabled disabled? :on-change (handler-fn (on-change (js/Number (-> event .-target .-value))))} + (if-not disabled? (get-in parts [:input :attr]) (get-in parts [:input:disabled :attr])) attr)]]))) \ No newline at end of file