Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restyle slider component #250

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
48 changes: 48 additions & 0 deletions src/re_com/box.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -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"
Expand Down
55 changes: 34 additions & 21 deletions src/re_com/slider.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,28 @@
[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
;; ------------------------------------------------------------------------------------

(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?
Expand All @@ -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
Expand All @@ -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)]])))