diff --git a/README.md b/README.md index dab04184..d8757380 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,8 @@ re-com is available from clojars. Add it to your project.clj dependencies: [![Clojars Project](http://clojars.org/re-com/latest-version.svg)](http://clojars.org/re-com) +You'll then need to include these asset folders in your app: +https://github.com/Day8/re-com/tree/master/run/resources/public/assets As far as your `index.html` is concerned, take inspiration from here: https://github.com/Day8/re-com/tree/master/run/resources/public @@ -182,14 +184,20 @@ In particular, you'll need bootstrap (assumedly via a CDN): ``` -You'll then need these assets, including the re-com.css: -https://github.com/Day8/re-com/tree/master/run/resources/public/assets +And a reference to these two CSS files: ```html ``` +And a reference to the Roboto fonts (but this can be overridden relatively easily): + +```html + + +``` + Reagent comes bundled with a matching version of ReactJS, so you don't need to include it explicitly. diff --git a/docs/release-procedure.md b/docs/release-procedure.md new file mode 100644 index 00000000..a3952a44 --- /dev/null +++ b/docs/release-procedure.md @@ -0,0 +1,105 @@ +# Re-com Release Procedure + +## Setting your environment up + +A number of things need to be set up before the release procedure can commence. + +### GPG + +Here are the basic instructions to follow to get GPG running: https://github.com/technomancy/leiningen/blob/stable/doc/GPG.md + +A few notes for Windows: + + - The recommended gpg version for windows is: http://www.gpg4win.org. + - There are several version on the download page. I used the "Vanilla" one. Direct link: http://files.gpg4win.org/gpg4win-vanilla-2.2.4.exe + - To display your public key, just type: `gpg --export -a`. + +### Clojars + +Simply need to set up your own account, then get the Day8 Clojars admin to add you to the family. Then you can publish to Day8 Clojars. + +Note that your GPG public key from above needs to be pasted into your Clojars profile for this process to work. + +More info on deploying libraries using lein: https://github.com/technomancy/leiningen/blob/master/doc/DEPLOY.md + +## Release Steps + +### Build library and test the demo + +Note that all these commands are entered at the repo root folder. + +- [ ] Close all auto-compiles (command line and/or IntelliJ). +- [ ] Build each of these aliases (will require separate terminals for each): + - `lein debug` + - `lein debug-prod` + - `lein debug-test` +- [ ] For `dev` and `prod`, run through each demo page and make sure no errors or debug output appears in the console. +- [ ] For `test`, make sure all tests pass. Modify code/tests until all tests pass. +- [ ] Close all auto-compiles again. + +### Make a Github release + +- [ ] TODO: IntelliJ should be able to do all of these steps as it has integrated gitflow - investigate. +- [ ] Make sure your master branch is up-to-date with Github (in 99% of cases it will be): + - `git checkout master` (TODO: might have to shelve develop or feature branch outstanding changes - confirm). + - `git pull` + - `git checkout {the branch you are working in}` +- [ ] Start a new release: + - `git checkout develop` (TODO: may just need to be in the branch you are working in - confirm). + - `git flow release start x.x.x` + - A branch called 'release/x.x.x' is created. +- [ ] Bump version in project.clj to `x.x.x`. +- [ ] Update README.md file if required. +- [ ] Commit to develop or finish feature: + - `git commit -a -m "..."` +- [ ] Push develop to GitHub: + - `git push` +- [ ] Finish the release: + - `git flow release finish 'x.x.x'` + - Merges develop into master. + - Creates a tag with that version number. + - Pops up an editor to describe the release. I just put "Version x.x.x". + - Deletes the release branch. +- [ ] Push develop to GitHub: + - `git push` +- [ ] Go to master branch: + - `git checkout master` +- [ ] Push master to GitHub: + - `git push` +- [ ] Push the tags to GitHub: + - `git push --tags` +- [ ] Create a GitHub Release: + - Go to: https://github.com/Day8/re-com/releases + - Should see your version `x.x.x` tag at the top. + - Press the `Draft a new release` button. + - Select this new `x.x.x` version in the Tag version dropdown. + - Make sure this is based on a Target of master. + - For the title, enter the version number: `x.x.x`. + - Enter a description that includes a list of "Changes" and "Fixes" (since the last release). + - Click the `Publish release` button. + +### Push library to Clojars + +- [ ] Push this release to Clojars: + - `lein deploy clojars` + - Will prompt for your Clojars username and password. + - Will also prompt for your GPG passphrase. +- [ ] "Promote" the Clojars release: + - Go to the re-com Clojars page for this version: https://clojars.org/re-com + - Log in. + - Click on the link for this new version. + - Click the big blue button at the bottom of the release page to make it live. + +### Deploy demo to AWS + +- [ ] Deploy demo to AWS: + - `lein s3-static-deploy` + - Could have used `lein deploy-aws` but this also builds the `prod` version which we have already just built. + - Manually change `index.html` to `index_prod.html` in S3 Browser. TODO: Find a way to automate this. + - Test it: http://re-demo.s3-website-ap-southeast-2.amazonaws.com. + +### Final tasks + +- [ ] Reply to all issues and pull requests relating to this release. +- [ ] Post a note in #re-com Slack channel pointing to GitHub release page. +- [ ] Post to Google Groups if necessary. diff --git a/project.clj b/project.clj index 1e00c29c..bb761a2d 100644 --- a/project.clj +++ b/project.clj @@ -32,7 +32,7 @@ ;; --------------------------------------------------------------------------------------- -(defproject re-com "0.5.3" +(defproject re-com "0.5.4" :description "Reusable UI components for Reagent" :url "https://github.com/Day8/re-com.git" :license {:name "MIT"} diff --git a/src/re_com/alert.cljs b/src/re_com/alert.cljs index 2a299453..4e29a279 100644 --- a/src/re_com/alert.cljs +++ b/src/re_com/alert.cljs @@ -17,7 +17,7 @@ {:name :body :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "displayed within the body of the alert"} {:name :padding :required false :default "15px" :type "string" :validate-fn string? :description "padding surounding the alert"} {:name :closeable? :required false :default false :type "boolean" :description [:span "if true, render a close button. " [:code ":on-close"] " should be supplied"]} - {:name :on-close :required false :type "(:id) -> nil" :validate-fn fn? :description [:span "called when the user clicks the close 'X' button. Passed the " [:code ":id"] " of the alert to close"]} + {:name :on-close :required false :type ":id -> nil" :validate-fn fn? :description [:span "called when the user clicks the close 'X' button. Passed the " [:code ":id"] " of the alert to close"]} {:name :class :required false :type "string" :validate-fn string? :description "CSS classes (whitespace separated). Applied to outer container"} {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "CSS styles. Applied to outer container"} {: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. Applied to outer container"]}]) @@ -66,7 +66,7 @@ (def alert-list-args-desc [{:name :alerts :required true :type "vector of maps | atom" :validate-fn vector-of-maps? :description "alerts to render (in the order supplied). Can also be a list of maps"} - {:name :on-close :required true :type "(:id) -> nil" :validate-fn fn? :description [:span "called when the user clicks the close 'X' button. Passed the alert's " [:code ":id"]]} + {:name :on-close :required true :type ":id -> nil" :validate-fn fn? :description [:span "called when the user clicks the close 'X' button. Passed the alert's " [:code ":id"]]} {:name :max-height :required false :type "string" :validate-fn string? :description "CSS style for maximum list height. By default, it grows forever"} {:name :padding :required false :default "4px" :type "string" :validate-fn string? :description "CSS padding within the alert"} {:name :border-style :required false :default "1px solid lightgrey" :type "string" :validate-fn string? :description "CSS border style surrounding the list"} diff --git a/src/re_com/box.cljs b/src/re_com/box.cljs index 5561446a..ba7dc5d1 100644 --- a/src/re_com/box.cljs +++ b/src/re_com/box.cljs @@ -256,7 +256,7 @@ style) gap-form (when gap [re-com.box/gap :size gap - :width gap]) ;; required to get around a Chrome bug + :width gap]) ;; TODO: required to get around a Chrome bug: https://code.google.com/p/chromium/issues/detail?id=423112. Remove once fixed. children (if gap (interpose gap-form (filter identity children)) ;; filter is to remove possible nils so we don't add unwanted gaps children)] @@ -316,7 +316,7 @@ style) gap-form (when gap [re-com.box/gap :size gap - :height gap]) ;; required to get around a Chrome bug + :height gap]) ;; TODO: required to get around a Chrome bug: https://code.google.com/p/chromium/issues/detail?id=423112. Remove once fixed. children (if gap (interpose gap-form (filter identity children)) ;; filter is to remove possible nils so we don't add unwanted gaps children)] diff --git a/src/re_com/buttons.cljs b/src/re_com/buttons.cljs index ae8beb67..2732880e 100644 --- a/src/re_com/buttons.cljs +++ b/src/re_com/buttons.cljs @@ -14,7 +14,7 @@ (def button-args-desc [{:name :label :required true :type "string | hiccup" :validate-fn string-or-hiccup? :description "label for the button"} {:name :class :required false :type "string" :validate-fn string? :description "CSS class names, space separated"} - {:name :on-click :required false :type "( ) -> nil" :validate-fn fn? :description "called when the button is clicked"} + {:name :on-click :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the button is clicked"} {:name :tooltip :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "what to show in the tooltip"} {:name :tooltip-position :required false :default :below-center :type "keyword" :validate-fn position? :description [:span "relative to this anchor. One of " position-options-list]} {:name :disabled? :required false :default false :type "boolean | atom" :description "if true, the user can't click the button"} @@ -64,7 +64,7 @@ (def md-circle-icon-button-args-desc [{:name :md-icon-name :required true :default "md-add" :type "string" :validate-fn string? :description [:span "the name of the icon." [:br] "For example, " [:code "\"md-add\""] " or " [:code "\"md-undo\""]] } - {:name :on-click :required false :type "( ) -> nil" :validate-fn fn? :description "called when the button is clicked"} + {:name :on-click :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the button is clicked"} {:name :size :required false :default :regular :type "keyword" :validate-fn button-size? :description [:span "one of " button-sizes-list]} {:name :tooltip :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "what to show in the tooltip"} {:name :tooltip-position :required false :default :below-center :type "keyword" :validate-fn position? :description [:span "relative to this anchor. One of " position-options-list]} @@ -120,7 +120,7 @@ (def md-icon-button-args-desc [{:name :md-icon-name :required true :default "md-add" :type "string" :validate-fn string? :description [:span "the name of the icon." [:br] "For example, " [:code "\"md-add\""] " or " [:code "\"md-undo\""]]} - {:name :on-click :required false :type "( ) -> nil" :validate-fn fn? :description "called when the button is clicked"} + {:name :on-click :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the button is clicked"} {:name :size :required false :default :regular :type "keyword" :validate-fn button-size? :description [:span "one of " button-sizes-list]} {:name :tooltip :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "what to show in the tooltip"} {:name :tooltip-position :required false :default :below-center :type "keyword" :validate-fn position? :description [:span "relative to this anchor. One of " position-options-list]} @@ -218,7 +218,7 @@ (def row-button-args-desc [{:name :md-icon-name :required true :default "md-add" :type "string" :validate-fn string? :description [:span "the name of the icon." [:br] "For example, " [:code "\"md-add\""] " or " [:code "\"md-undo\""]]} - {:name :on-click :required false :type "( ) -> nil" :validate-fn fn? :description "called when the button is clicked"} + {:name :on-click :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the button is clicked"} {:name :mouse-over-row? :required false :default false :type "boolean" :description "true if the mouse is hovering over the row"} {:name :tooltip :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "what to show in the tooltip"} {:name :tooltip-position :required false :default :below-center :type "keyword" :validate-fn position? :description [:span "relative to this anchor. One of " position-options-list]} @@ -267,7 +267,7 @@ (def hyperlink-args-desc [{:name :label :required true :type "string | hiccup | atom" :validate-fn string-or-hiccup? :description "label/hiccup for the button"} - {:name :on-click :required false :type "( ) -> nil" :validate-fn fn? :description "called when the button is clicked"} + {:name :on-click :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the button is clicked"} {:name :tooltip :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "what to show in the tooltip"} {:name :tooltip-position :required false :default :below-center :type "keyword" :validate-fn position? :description [:span "relative to this anchor. One of " position-options-list]} {:name :disabled? :required false :default false :type "boolean | atom" :description "if true, the user can't click the button"} diff --git a/src/re_com/datepicker.cljs b/src/re_com/datepicker.cljs index 2f81d2a3..7f54f8ea 100644 --- a/src/re_com/datepicker.cljs +++ b/src/re_com/datepicker.cljs @@ -202,7 +202,7 @@ (def datepicker-args-desc [{:name :model :required true :type "goog.date.UtcDateTime | atom" :validate-fn goog-date? :description "the selected date. Should match :enabled-days"} - {:name :on-change :required true :type "(goog.date.UtcDateTime) -> nil" :validate-fn fn? :description "called when a new selection is made"} + {:name :on-change :required true :type "goog.date.UtcDateTime -> nil" :validate-fn fn? :description "called when a new selection is made"} {:name :disabled? :required false :default false :type "boolean | atom" :description "when true, the can't select dates but can navigate"} {:name :enabled-days :required false :type "set" :validate-fn set? :description "a subset of #{:Su :Mo :Tu :We :Th :Fr :Sa}. Only dates falling on these days will be user-selectable. Default is all 7 days"} {:name :show-weeks? :required false :default false :type "boolean" :description "when true, week numbers are shown to the left"} diff --git a/src/re_com/dropdown.cljs b/src/re_com/dropdown.cljs index 8a5abaae..e41b959d 100644 --- a/src/re_com/dropdown.cljs +++ b/src/re_com/dropdown.cljs @@ -12,38 +12,35 @@ (defn- move-to-new-choice "In a vector of maps (where each map has an :id), return the id of the choice offset posititions away from id (usually +1 or -1 to go to next/previous). Also accepts :start and :end" - [choices id offset] - (let [current-index (position-for-id id choices) + [choices id-fn id offset] + (let [current-index (position-for-id id choices :id-fn id-fn) new-index (cond (= offset :start) 0 (= offset :end) (dec (count choices)) (nil? current-index) 0 :else (mod (+ current-index offset) (count choices)))] - (when new-index (:id (nth choices new-index))))) + (when new-index (id-fn (nth choices new-index))))) (defn- choices-with-group-headings "If necessary, inserts group headings entries into the choices" - [opts] - (let [groups (partition-by :group opts) + [opts group-fn] + (let [groups (partition-by group-fn opts) group-headers (->> groups (map first) - (map :group) - (map #(hash-map :id % :group % :group-header? true)))] - ;(if (= 1 (count groups)) - ; opts - ; (flatten (interleave group-headers groups))) - (flatten (interleave group-headers groups)))) + (map group-fn) + (map #(hash-map :id (gensym) :group %)))] + [group-headers groups])) (defn- filter-choices "Filter a list of choices based on a filter string using plain string searches (case insensitive). Less powerful than regex's but no confusion with reserved characters" - [choices filter-text] + [choices group-fn label-fn filter-text] (let [lower-filter-text (string/lower-case filter-text) filter-fn (fn [opt] - (let [group (if (nil? (:group opt)) "" (:group opt)) - label (str (:label opt))] ;; Need str for non-string labels like hiccup + (let [group (if (nil? (group-fn opt)) "" (group-fn opt)) + label (str (label-fn opt))] ;; Need str for non-string labels like hiccup (or (>= (.indexOf (string/lower-case group) lower-filter-text) 0) (>= (.indexOf (string/lower-case label) lower-filter-text) 0))))] @@ -53,13 +50,13 @@ (defn- filter-choices-regex "Filter a list of choices based on a filter string using regex's (case insensitive). More powerful but can cause confusion for users entering reserved characters such as [ ] * + . ( ) etc." - [choices filter-text] + [choices group-fn label-fn filter-text] (let [re (try (js/RegExp. filter-text "i") (catch js/Object e nil)) filter-fn (partial (fn [re opt] (when-not (nil? re) - (or (.test re (:group opt)) (.test re (:label opt))))) + (or (.test re (group-fn opt)) (.test re (label-fn opt))))) re)] (filter filter-fn choices))) @@ -85,11 +82,11 @@ (when new-scroll-top (set! (.-scrollTop parent) new-scroll-top)))) -(defn- choice-group-heading +(defn- make-group-heading "Render a group heading" - [group] - [:li.group-result - group]) + [m] + ^{:key (:id m)} [:li.group-result + (:group m)]) (defn- choice-item @@ -124,6 +121,13 @@ label]))}))) +(defn make-choice-item + [id-fn label-fn callback internal-model opt] + (let [id (id-fn opt) + label (label-fn opt)] + ^{:key (str id)} [choice-item id label callback internal-model])) + + (defn- filter-text-box-base "Base function (before lifecycle metadata) to render a filter text box" [] @@ -156,7 +160,7 @@ [] (let [ignore-click (atom false)] (fn - [internal-model choices tab-index placeholder dropdown-click key-handler filter-box? drop-showing?] + [internal-model choices id-fn label-fn tab-index placeholder dropdown-click key-handler filter-box? drop-showing?] (let [_ (reagent/set-state (reagent/current-component) {:filter-box? filter-box?})] [:a.chosen-single.chosen-default {:href "javascript:" ;; Required to make this anchor appear in the tab order @@ -176,7 +180,7 @@ } [:span (if @internal-model - (:label (item-for-id @internal-model choices)) + (label-fn (item-for-id @internal-model choices :id-fn id-fn)) placeholder)] [:div [:b]]])))) ;; This odd bit of markup produces the visual arrow on the right @@ -188,7 +192,7 @@ (def single-dropdown-args-desc [{:name :choices :required true :type "vector of maps | atom" :validate-fn vector-of-maps? :description "each has an :id, a :label and, optionally, a :group (list of maps also allowed)"} {:name :model :required true :type "an :id within :choices | atom" :description "the :id of the selected choice. If nil, :placeholder text is shown"} - {:name :on-change :required true :type "(:id) -> nil" :validate-fn fn? :description [:span "called when a new selection is made. Passed the " [:code ":id"] " of new selection"] } + {:name :on-change :required true :type ":id -> nil" :validate-fn fn? :description [:span "called when a new selection is made. Passed the " [:code ":id"] " of new selection"] } {:name :disabled? :required false :default false :type "boolean | atom" :description "if true, no user selection is allowed"} {:name :filter-box? :required false :default false :type "boolean" :description "if true, a filter text field is placed at the top of the dropdown"} {:name :regex-filter? :required false :default false :type "boolean | atom" :description "if true, the filter text field will support JavaScript regular expressions. If false, just plain text"} @@ -196,9 +200,9 @@ {:name :width :required false :default "100%" :type "string" :validate-fn string? :description "the CSS width. e.g.: \"500px\" or \"20em\""} {:name :max-height :required false :default "240px" :type "string" :validate-fn string? :description "the maximum height of the dropdown part"} {:name :tab-index :required false :type "integer | string" :validate-fn number-or-string? :description "component's tabindex. A value of -1 removes from order"} - {:name :id-fn :required false :default :id :type "(map) -> anything" :validate-fn fn? :description [:span "given an element of " [:code ":choices"] ", returns the unique identifier for this dropdown entry"]} - {:name :label-fn :required false :default :label :type "(map) -> string | hiccup" :validate-fn fn? :description [:span "given an element of " [:code ":choices"] ", returns what should be displayed in this dropdown entry"]} - {:name :group-fn :required false :default :group :type "(map) -> anything" :validate-fn fn? :description [:span "given an element of " [:code ":choices"] ", returns the group identifier for this dropdown entry"]} + {:name :id-fn :required false :default :id :type "map -> anything" :validate-fn ifn? :description [:span "given an element of " [:code ":choices"] ", returns the unique identifier for this dropdown entry"]} + {:name :label-fn :required false :default :label :type "map -> string | hiccup" :validate-fn ifn? :description [:span "given an element of " [:code ":choices"] ", returns what should be displayed in this dropdown entry"]} + {:name :group-fn :required false :default :group :type "map -> anything" :validate-fn ifn? :description [:span "given an element of " [:code ":choices"] ", returns the group identifier for this dropdown entry"]} {:name :class :required false :type "string" :validate-fn string? :description "CSS class names, space separated"} {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "CSS styles to add or override"} {: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"]}]) @@ -239,8 +243,8 @@ dropdown-click #(when-not disabled? (swap! drop-showing? not)) filtered-choices (if regex-filter? - (filter-choices-regex choices @filter-text) - (filter-choices choices @filter-text)) + (filter-choices-regex choices group-fn label-fn @filter-text) + (filter-choices choices group-fn label-fn @filter-text)) press-enter (fn [] (if disabled? (cancel) @@ -260,19 +264,19 @@ true) press-up (fn [] (if @drop-showing? ;; Up arrow - (reset! internal-model (move-to-new-choice filtered-choices @internal-model -1)) + (reset! internal-model (move-to-new-choice filtered-choices id-fn @internal-model -1)) (reset! drop-showing? true)) true) press-down (fn [] (if @drop-showing? ;; Down arrow - (reset! internal-model (move-to-new-choice filtered-choices @internal-model 1)) + (reset! internal-model (move-to-new-choice filtered-choices id-fn @internal-model 1)) (reset! drop-showing? true)) true) press-home (fn [] - (reset! internal-model (move-to-new-choice filtered-choices @internal-model :start)) + (reset! internal-model (move-to-new-choice filtered-choices id-fn @internal-model :start)) true) press-end (fn [] - (reset! internal-model (move-to-new-choice filtered-choices @internal-model :end)) + (reset! internal-model (move-to-new-choice filtered-choices id-fn @internal-model :end)) true) key-handler #(if disabled? false @@ -293,18 +297,21 @@ {:width (when width width)} style)} attr) ;; Prevent user text selection - [dropdown-top internal-model choices tab-index placeholder dropdown-click key-handler filter-box? drop-showing?] + [dropdown-top internal-model choices id-fn label-fn tab-index placeholder dropdown-click key-handler filter-box? drop-showing?] (when (and @drop-showing? (not disabled?)) [:div.chosen-drop [filter-text-box filter-box? filter-text key-handler drop-showing?] [:ul.chosen-results (when max-height {:style {:max-height max-height}}) (if (-> filtered-choices count pos?) - (for [opt (choices-with-group-headings filtered-choices)] - (let [id (id-fn opt) - label (label-fn opt) - group (group-fn opt)] - (if (:group-header? opt) - ^{:key (str id)} [choice-group-heading group] - ^{:key (str id)} [choice-item id label callback internal-model]))) + (let [[group-names group-opt-lists] (choices-with-group-headings filtered-choices group-fn) + make-a-choice (partial make-choice-item id-fn label-fn callback internal-model) + make-choices #(map make-a-choice %1) + make-h-then-choices (fn [h opts] + (cons (make-group-heading h) + (make-choices opts))) + has-no-group-names? (nil? (:group (first group-names)))] + (if (and (= 1 (count group-opt-lists)) has-no-group-names?) + (make-choices (first group-opt-lists)) ;; one group means no headings + (apply concat (map make-h-then-choices group-names group-opt-lists)))) [:li.no-results (str "No results match \"" @filter-text "\"")])]])])))) diff --git a/src/re_com/input_time.cljs b/src/re_com/input_time.cljs index c720c870..17d1ce5d 100644 --- a/src/re_com/input_time.cljs +++ b/src/re_com/input_time.cljs @@ -126,7 +126,7 @@ (def input-time-args-desc [{:name :model :required true :type "integer | string | atom" :validate-fn number-or-string? :description "a time in integer form. e.g. '09:30am' is 930"} - {:name :on-change :required true :type "(integer) -> nil" :validate-fn fn? :description "called when user entry completes and value is new. Passed new value as integer"} + {:name :on-change :required true :type "integer -> nil" :validate-fn fn? :description "called when user entry completes and value is new. Passed new value as integer"} {:name :minimum :required false :default 0 :type "integer | string" :validate-fn number-or-string? :description "user can't enter a time less than this value"} {:name :maximum :required false :default 2359 :type "integer | string" :validate-fn number-or-string? :description "user can't enter a time more than this value"} {:name :disabled? :required false :default false :type "boolean | atom" :description "when true, user input is disabled"} diff --git a/src/re_com/misc.cljs b/src/re_com/misc.cljs index eb9ed283..1fae18ce 100644 --- a/src/re_com/misc.cljs +++ b/src/re_com/misc.cljs @@ -15,7 +15,7 @@ (def input-text-args-desc [{:name :model :required true :type "string | atom" :validate-fn string-or-atom? :description "text of the input (can be atom or value)"} - {:name :on-change :required true :type "(string) -> nil" :validate-fn fn? :description [:span [:code ":change-on-blur?"] " controls when it is called. Passed the current input string"] } + {:name :on-change :required true :type "string -> nil" :validate-fn fn? :description [:span [:code ":change-on-blur?"] " controls when it is called. Passed the current input string"] } {:name :status :required false :type "keyword" :validate-fn input-status-type? :description [:span "validation status. " [:code "nil/omitted"] " for normal status or one of: " input-status-types-list]} {:name :status-icon? :required false :default false :type "boolean" :description [:span "when true, display an icon to match " [:code ":status"] " (no icon for nil)"]} {:name :status-tooltip :required false :type "string" :validate-fn string? :description "displayed in status icon's tooltip"} @@ -71,7 +71,7 @@ [input-type (merge {:class (str "form-control noselect " class) - :type (when (= input-type :text) "text") + :type (when (= input-type :input) "text") :rows (when (= input-type :textarea) (if rows rows 3)) :style (merge (flex-child-style "none") @@ -140,12 +140,12 @@ (defn input-text [& args] - (apply input-text-base :input-type :input args)) + (apply input-text-base :input-type :input args)) (defn input-textarea - [& args] - (apply input-text-base :input-type :textarea args)) + [& args] + (apply input-text-base :input-type :textarea args)) ;; ------------------------------------------------------------------------------------ @@ -154,7 +154,7 @@ (def checkbox-args-desc [{:name :model :required true :type "boolean | atom" :description "holds state of the checkbox when it is called"} - {:name :on-change :required true :type "(boolean) -> nil" :validate-fn fn? :description "called when the checkbox is clicked. Passed the new value of the checkbox"} + {:name :on-change :required true :type "boolean -> nil" :validate-fn fn? :description "called when the checkbox is clicked. Passed the new value of the checkbox"} {:name :label :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "the label shown to the right"} {:name :disabled? :required false :default false :type "boolean | atom" :description "if true, user interaction is disabled"} {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "the CSS style style map"} @@ -202,7 +202,7 @@ (def radio-button-args-desc [{:name :model :required true :type "anything | atom" :description [:span "selected value of the radio button group. See also " [:code ":value"]] } {:name :value :required false :type "anything" :description [:span "if " [:code ":model"] " equals " [:code ":value"] " then this radio button is selected"] } - {:name :on-change :required true :type "(anything) -> nil" :validate-fn fn? :description [:span "called when the radio button is clicked. Passed " [:code ":value"]]} + {:name :on-change :required true :type "anything -> nil" :validate-fn fn? :description [:span "called when the radio button is clicked. Passed " [:code ":value"]]} {:name :label :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "the label shown to the right"} {:name :disabled? :required false :default false :type "boolean | atom" :description "if true, the user can't click the radio button"} {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "radio button style map"} @@ -249,7 +249,7 @@ (def slider-args-desc [{:name :model :required true :type "double | string | atom" :validate-fn number-or-string? :description "current value of the slider"} - {:name :on-change :required true :type "(double) -> nil" :validate-fn fn? :description "called when the slider is moved. Passed the new value of the slider"} + {:name :on-change :required true :type "double -> nil" :validate-fn fn? :description "called when the slider is moved. Passed the new value of the slider"} {:name :min :required false :default 0 :type "double | string | atom" :validate-fn number-or-string? :description "the minimum value of the slider"} {:name :max :required false :default 100 :type "double | string | atom" :validate-fn number-or-string? :description "the maximum value of the slider"} {:name :step :required false :default 1 :type "double | string | atom" :validate-fn number-or-string? :description "step value between min and max"} diff --git a/src/re_com/popover.cljs b/src/re_com/popover.cljs index b4301072..713605d5 100644 --- a/src/re_com/popover.cljs +++ b/src/re_com/popover.cljs @@ -107,7 +107,7 @@ (def backdrop-args-desc [{:name :opacity :required false :default 0.0 :type "double | string" :validate-fn number-or-string? :description [:span "opacity of backdrop from:" [:br] "0.0 (transparent) to 1.0 (opaque)"]} - {:name :on-click :required false :type "( ) -> nil" :validate-fn fn? :description "function to call when the backdrop is clicked"}]) + {:name :on-click :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the backdrop is clicked"}]) (defn- backdrop "Renders a backdrop dive which fills the entire page and responds to clicks on it. Can also specify how tranparent it should be" @@ -233,7 +233,7 @@ [{:name :showing? :required true :type "boolean atom" :description "an atom. When the value is true, the popover shows."} {:name :title :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "describes the title of the popover. Default font size is 18px to make it stand out"} {:name :close-button? :required false :default true :type "boolean" :description "when true, displays the close button"} - {:name :close-callback :required false :type "function" :validate-fn fn? :description "callback taking no parameters, used when the close button is pressed. Not required if :showing? atom passed in OR :close-button? is set to false"}]) + {:name :close-callback :required false :type "-> nil" :validate-fn fn? :description [:span "a function which takes no params and returns nothing. Called when the close button is pressed. Not required if " [:code ":showing?"] " atom passed in OR " [:code ":close-button?"] " is set to false"]}]) (defn- popover-title "Renders a title at the top of a popover with an optional close button on the far right" @@ -262,7 +262,7 @@ {:name :width :required false :type "string" :validate-fn string? :description "a CSS style representing the popover width"} {:name :height :required false :type "string" :validate-fn string? :description "a CSS style representing the popover height"} {:name :backdrop-opacity :required false :default 0.0 :type "double | string" :validate-fn number-or-string? :description "indicates the opacity of the backdrop where 0.0=transparent, 1.0=opaque"} - {:name :on-cancel :required false :type "function" :validate-fn fn? :description "a callback taking no parameters, invoked when the popover is cancelled (e.g. user clicks away)"} + {:name :on-cancel :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the popover is cancelled (e.g. user clicks away)"} {:name :title :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "describes the title of the popover. The default font size is 18px to make it stand out"} {:name :close-button? :required false :default true :type "boolean" :description "when true, displays the close button"} {:name :body :required false :type "string | hiccup" :validate-fn string-or-hiccup? :description "describes the popover body. Must be a single component"} @@ -372,7 +372,7 @@ (def popover-tooltip-args-desc [{:name :label :required true :type "string | hiccup | atom" :validate-fn string-or-hiccup? :description "the text (or component) for the tooltip"} {:name :showing? :required true :default false :type "boolean atom" :description "an atom. When the value is true, the tooltip shows"} - {:name :on-cancel :required false :type "function" :validate-fn fn? :description "a callback taking no parameters, invoked when the popover is cancelled (e.g. user clicks away)"} + {:name :on-cancel :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the popover is cancelled (e.g. user clicks away)"} {:name :close-button? :required false :default false :type "boolean" :description "when true, displays the close button"} {:name :status :required false :type "keyword" :validate-fn popover-status-type? :description [:span "controls background color of the tooltip. " [:code "nil/omitted"] " for black or one of " popover-status-types-list]} {:name :anchor :required true :type "hiccup" :validate-fn string-or-hiccup? :description "the component the tooltip is attached to"} diff --git a/src/re_com/selection_list.cljs b/src/re_com/selection_list.cljs index 0411828d..084eeab9 100644 --- a/src/re_com/selection_list.cljs +++ b/src/re_com/selection_list.cljs @@ -84,7 +84,7 @@ (def selection-list-args-desc [{:name :choices :required true :type "vector of maps | atom" :validate-fn vector-of-maps? :description [:span "the selectable items. Elements can be strings or more interesting data items like {:label \"some name\" :sort 5}. Also see " [:code ":label-fn"] " below (list of maps also allowed)"]} {:name :model :required true :type "set of :ids within :choices | atom" :validate-fn set-or-atom? :description "the currently selected items. Note: items are considered distinct"} - {:name :on-change :required true :type "(set of :ids) -> nil | atom" :validate-fn fn? :description "a callback which will be passed set of selected items"} + {:name :on-change :required true :type "set of :ids -> nil | atom" :validate-fn fn? :description "a callback which will be passed set of selected items"} {:name :multi-select? :required false :default true :type "boolean | atom" :description "when true, use check boxes, otherwise radio buttons"} {:name :as-exclusions? :required false :default false :type "boolean | atom" :description "when true, selected items are shown with struck-out labels"} {:name :required? :required false :default false :type "boolean | atom" :description "when true, at least one item must be selected. Note: being able to un-select a radio button is not a common use case, so this should probably be set to true when in single select mode"} @@ -93,8 +93,8 @@ {:name :max-height :required false :type "string | atom" :validate-fn string-or-atom? :description "a CSS style e.g. \"150px\". If there are less items then this height, box will shrink. If there are more, items will scroll"} {:name :disabled? :required false :default false :type "boolean | atom" :description "when true, the time input will be disabled. Can be atom or value"} {:name :hide-border? :required false :default false :type "boolean | atom" :description "when true, the list will be displayed without a border"} - {:name :item-renderer :required false :type "function | atom" :validate-fn fn? :description "called for each element during setup, the returned component renders the element, responds to clicks etc."} - {:name :label-fn :required false :default 'str :type "function | atom" :validate-fn ifn? :description "called for each element to get label string"}]) + {:name :item-renderer :required false :type "-> nil | atom" :validate-fn fn? :description "a function which takes no params and returns nothing. Called for each element during setup, the returned component renders the element, responds to clicks etc."} + {:name :label-fn :required false :default 'str :type "-> nil | atom" :validate-fn ifn? :description "a function which takes no params and returns nothing. Called for each element to get label string"}]) ;;TODO hide hover highlights for links when disabled (defn- list-container @@ -111,7 +111,8 @@ bounds (select-keys args [:width :height :max-height]) spacing (if hide-border? spacing-unbordered spacing-bordered)] ;; In single select mode force selections to one. This causes a second render - (when-not (= selected model) (on-change selected)) + ;; TODO: GR commented this out to fix the bug where #{nil} was being returned for an empty list. Remove when we're sure there are no ill effects. + #_(when-not (= selected model) (on-change selected)) [border :radius "4px" :border (when hide-border? "none") diff --git a/src/re_com/splits.cljs b/src/re_com/splits.cljs index 4c31e425..141017c9 100644 --- a/src/re_com/splits.cljs +++ b/src/re_com/splits.cljs @@ -42,7 +42,7 @@ {:name :size :required false :default "auto" :type "string" :validate-fn string? :description [:span "applied to the outer container of the two panels. Equivalent to CSS style " [:span.bold "flex"] "." [:br] "Examples: " [:code "initial"] ", " [:code "auto"] ", " [:code "none"]", " [:code "100px"] ", " [:code "2"] " or a generic triple of " [:code "grow shrink basis"]]} {:name :width :required false :type "string" :validate-fn string? :description "width of the outer container of the two panels. A CSS width style"} {:name :height :required false :type "string" :validate-fn string? :description "height of the outer container of the two panels. A CSS height style"} - {:name :on-split-change :required false :type "(double) -> nil" :validate-fn fn? :description [:span "called when the user moves the splitter bar (on mouse up, not on each mouse move). Given the new " [:code ":panel-1"] " percentage split"]} + {:name :on-split-change :required false :type "double -> nil" :validate-fn fn? :description [:span "called when the user moves the splitter bar (on mouse up, not on each mouse move). Given the new " [:code ":panel-1"] " percentage split"]} {:name :initial-split :required false :default 50 :type "double | string" :validate-fn number-or-string? :description [:span "initial split percentage for " [:code ":panel-1"] ". Can be double value or string (with/without percentage sign)"]} {:name :splitter-size :required false :default "8px" :type "string" :validate-fn string? :description "thickness of the splitter"} {:name :margin :required false :default "8px" :type "string" :validate-fn string? :description "thickness of the margin around the panels"} diff --git a/src/re_com/tabs.cljs b/src/re_com/tabs.cljs index 282b6446..ba3eed8b 100644 --- a/src/re_com/tabs.cljs +++ b/src/re_com/tabs.cljs @@ -12,9 +12,9 @@ (def tabs-args-desc [{:name :tabs :required true :type "vector | atom" :validate-fn vector-of-maps? :description "one element in the vector for each tab. Typically, each element is a map with :id and :label keys"} {:name :model :required true :type "unique-id | atom" :description "the unique identifier of the currently selected tab"} - {:name :on-change :required true :type "(unique-id) -> nil" :validate-fn fn? :description "called when user alters the selection. Passed the unique identifier of the selection"} - {:name :id-fn :required false :default :id :type "(map) -> anything" :validate-fn fn? :description [:span "given an element of " [:code ":tabs"] ", returns the unique identifier for this tab"]} - {:name :label-fn :required false :default :label :type "(map) -> string | hiccup" :validate-fn fn? :description [:span "given an element of " [:code ":tabs"] ", returns what should be displayed in the tab"]} + {:name :on-change :required true :type "unique-id -> nil" :validate-fn fn? :description "called when user alters the selection. Passed the unique identifier of the selection"} + {:name :id-fn :required false :default :id :type "map -> anything" :validate-fn fn? :description [:span "given an element of " [:code ":tabs"] ", returns the unique identifier for this tab"]} + {:name :label-fn :required false :default :label :type "map -> string | hiccup" :validate-fn fn? :description [:span "given an element of " [:code ":tabs"] ", returns what should be displayed in the tab"]} {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "CSS styles to add or override (for each individual tab rather than the container)"}]) (defn horizontal-tabs diff --git a/src/re_com/text.cljs b/src/re_com/text.cljs index 9e3985db..e08e08b4 100644 --- a/src/re_com/text.cljs +++ b/src/re_com/text.cljs @@ -11,7 +11,7 @@ (def label-args-desc [{:name :label :required true :type "anything" :description "text or hiccup or whatever to display"} - {:name :on-click :required false :type "() -> nil" :validate-fn fn? :description "called when the label is clicked"} + {:name :on-click :required false :type "-> nil" :validate-fn fn? :description "a function which takes no params and returns nothing. Called when the label is clicked"} {:name :width :required false :type "string" :validate-fn string? :description "a CSS width"} {:name :class :required false :type "string" :validate-fn string? :description "CSS class names, space separated"} {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "additional CSS styles"} diff --git a/src/re_com/util.cljs b/src/re_com/util.cljs index 8a05da42..9d2e38c8 100644 --- a/src/re_com/util.cljs +++ b/src/re_com/util.cljs @@ -60,26 +60,26 @@ ;; ---------------------------------------------------------------------------- (defn position-for-id - "Takes a vector of maps 'v'. Returns the postion of the first item in 'v' whose :id matches 'id'. + "Takes a vector of maps 'v'. Returns the position of the first item in 'v' whose id-fn (default :id) matches 'id'. Returns nil if id not found" - [id v] - (let [index-fn (fn [index item] (when (= (:id item) id) index))] + [id v & {:keys [id-fn] :or {id-fn :id}}] + (let [index-fn (fn [index item] (when (= (id-fn item) id) index))] (first (keep-indexed index-fn v)))) (defn item-for-id - "Takes a vector of maps 'v'. Returns the first item in 'v' whose :id matches 'id'. + "Takes a vector of maps 'v'. Returns the first item in 'v' whose id-fn (default :id) matches 'id'. Returns nil if id not found" - [id v] - (first (filter #(= (:id %) id) v))) + [id v & {:keys [id-fn] :or {id-fn :id}}] + (first (filter #(= (id-fn %) id) v))) (defn remove-id-item - "Takes a vector of maps 'v', each of which has an :id key. + "Takes a vector of maps 'v', each of which has an id-fn (default :id) key. Return v where item matching 'id' is excluded" - [id v] - (filterv #(not= (:id %) id) v)) + [id v & {:keys [id-fn] :or {id-fn :id}}] + (filterv #(not= (id-fn %) id) v)) ;; ---------------------------------------------------------------------------- diff --git a/src/re_demo/core.cljs b/src/re_demo/core.cljs index b3bed4ec..d1560e48 100644 --- a/src/re_demo/core.cljs +++ b/src/re_demo/core.cljs @@ -197,7 +197,7 @@ [scroller :child [v-box :size "auto" - :children [(when-not (>= (.indexOf (.-userAgent (.-navigator js/window)) "Chrome") 0) [browser-alert]) + :children [(when-not (-> js/goog .-labs .-userAgent .-browser .isChrome) [browser-alert]) [(:panel (item-for-id @selected-tab-id tabs-definition))]]]]]]))) ;; the tab panel to show, for the selected tab (defn ^:export mount-demo diff --git a/src/re_demo/dropdowns.cljs b/src/re_demo/dropdowns.cljs index 51aed7a5..30c3b4d7 100644 --- a/src/re_demo/dropdowns.cljs +++ b/src/re_demo/dropdowns.cljs @@ -9,9 +9,10 @@ (def demos [{:id 1 :label "Simple dropdown"} {:id 2 :label "Dropdown with grouping"} {:id 3 :label "Dropdown with filtering"} - {:id 4 :label "Keyboard support"} - {:id 5 :label "Other parameters"} - {:id 6 :label "Two dependent dropdowns"}]) + ;{:id 4 :label "Use of :id-fn etc."} ;; for testing + {:id 5 :label "Keyboard support"} + {:id 6 :label "Other parameters"} + {:id 7 :label "Two dependent dropdowns"}]) (def countries [{:id "au" :label "Australia"} @@ -94,6 +95,15 @@ {:id "37" :label "Burundi" :group "'B' COUNTRIES"}]) +(def grouped-countries-2 [{:code "AU" :country "Australia" :region "EN Speakers"} + {:code "US" :country "United States" :region "EN Speakers"} + {:code "E1" :country "Iraq" :region "Updated Axis Of Evil"} + {:code "E2" :country "New Zealand" :region "Updated Axis Of Evil"} + {:code "03" :country "Afghanistan" :region "'A' COUNTRIES"} + {:code "04" :country "Albania" :region "'A' COUNTRIES"} + {:code "18" :country "Bahamas" :region "'B' COUNTRIES"} + {:code "19" :country "Bahrain" :region "'B' COUNTRIES"}]) + (defn demo1 [] [p "The dropdown above is the simple case."] @@ -126,7 +136,7 @@ [:strong "Selected country: "] (if (nil? @selected-country-id) "None" - (str (:label (item-for-id grouped-countries @selected-country-id)) " [" @selected-country-id "]"))]]]]]))) + (str (:label (item-for-id @selected-country-id grouped-countries)) " [" @selected-country-id "]"))]]]]]))) (defn demo3 @@ -157,6 +167,39 @@ (defn demo4 + [] + (let [id-fn #(str (:code %) "$") + label-fn #(str (:country %) "!") + group-fn #(str "[" (:region %) "]") + selected-country-id (reagent/atom (id-fn {:code "US"}))] + (fn [] + [v-box + :gap "10px" + :children [[p "This example is the same as the previous one except the list is shorter and the following parameters have been added to use different keywords for the data and transform the values provided:"] + [p [:code ":id-fn"] " is set to " [:code "#(str (:code %) \"$\")"]] + [p [:code ":label-fn"] " is set to " [:code "#(str (:country %) \"!\")"]] + [p [:code ":group-fn"] " is set to " [:code "#(str \"[\" (:region %) \"]\")"]] + [h-box + :gap "10px" + :align :center + :children [[single-dropdown + :choices grouped-countries-2 + :model selected-country-id + :width "300px" + :max-height "400px" + :filter-box? true + :id-fn id-fn + :label-fn label-fn + :group-fn group-fn + :on-change #(reset! selected-country-id %)] + [:div + [:strong "Selected country: "] + (if (nil? @selected-country-id) + "None" + (str (label-fn (item-for-id @selected-country-id grouped-countries-2 :id-fn id-fn)) " [" @selected-country-id "]"))]]]]]))) + + +(defn demo5 [] (let [selected-country-id (reagent/atom "US")] (fn [] @@ -190,7 +233,7 @@ (str (:label (item-for-id @selected-country-id grouped-countries)) " [" @selected-country-id "]"))]]]]]))) -(defn demo5 +(defn demo6 [] (let [selected-country-id (reagent/atom "US") disabled? (reagent/atom false) @@ -250,7 +293,7 @@ (str (:label (item-for-id @selected-country-id grouped-countries)) " [" @selected-country-id "]"))]]]]]))) -(defn demo6 +(defn demo7 [] (let [selected-country-id (reagent/atom nil) filtered-cities (reagent/atom []) @@ -274,7 +317,7 @@ [:strong "Selected country: "] (if (nil? @selected-country-id) "None" - (str (:label (item-for-id @selected-country-id countries )) " [" @selected-country-id "]"))]]] + (str (:label (item-for-id @selected-country-id countries)) " [" @selected-country-id "]"))]]] [gap :size "10px"] [h-box :gap "10px" @@ -288,7 +331,7 @@ [:strong "Selected city: "] (if (nil? @selected-city-id) "None" - (str (:label (item-for-id @selected-city-id cities )) " [" @selected-city-id "]"))]]]]]))) + (str (:label (item-for-id @selected-city-id cities)) " [" @selected-city-id "]"))]]]]]))) (defn panel2 @@ -341,9 +384,10 @@ 1 [demo1] 2 [demo2] 3 [demo3] - 4 [demo4] + 4 [demo4] ;; for testing - uncomment equivalent line in demos vector above 5 [demo5] - 6 [demo6])]]]]]]))) + 6 [demo6] + 7 [demo7])]]]]]]))) ;; core holds a reference to panel, so need one level of indirection to get figwheel updates diff --git a/src/re_demo/h_box.cljs b/src/re_demo/h_box.cljs index 906c296e..c99162bf 100644 --- a/src/re_demo/h_box.cljs +++ b/src/re_demo/h_box.cljs @@ -31,7 +31,6 @@ (def current-demo (reagent/atom 0)) -;(def paragraph-filler "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.") ;(def paragraph-filler "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") (def paragraph-filler [v-box :children [[:p.bold "Lorem Ipsum"] @@ -42,9 +41,7 @@ [:ul [:li "Dolor in reprehenderit in voluptate velit esse."] [:li "Cillum dolore eu fugiat nulla pariatur."] - [:li "Excepteur sint occaecat cupidatat non proident."] - ;[:li "Sunt in culpa qui officia deserunt mollit anim id est laborum."] - ]]]) + [:li "Excepteur sint occaecat cupidatat non proident."]]]]) (def buttons-filler [h-box :children [[button @@ -57,62 +54,62 @@ :on-click #()]]]) (def demos [;; Basic - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} - :width {:value "300px" :omit? true :editing? (atom false) :range [0 1000]} - :justify {:value :start :omit? true :editing? (atom false)} - :align {:value :stretch :omit? true :editing? (atom false)} - :gap {:value "4px" :omit? true :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} + :width {:value "300px" :omit? true :editing? (atom false) :range [0 1000]} + :justify {:value :start :omit? true :editing? (atom false)} + :align {:value :stretch :omit? true :editing? (atom false)} + :gap {:value "4px" :omit? true :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}}} + :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}}} ;; Justify - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} - :width {:value "450px" :omit? false :editing? (atom false) :range [0 1000]} - :justify {:value :start :omit? false :editing? (atom true)} - :align {:value :stretch :omit? true :editing? (atom false)} - :gap {:value "4px" :omit? true :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} + :width {:value "450px" :omit? false :editing? (atom false) :range [0 1000]} + :justify {:value :start :omit? false :editing? (atom true )} + :align {:value :stretch :omit? true :editing? (atom false)} + :gap {:value "4px" :omit? true :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} - :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} + :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} - :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "2" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} + :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "2" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} - :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "1" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} + :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "1" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :desc [v-box :children [[:p.info-subheading "The " [:code ":justify"] " parameter"] [:p "Specifies how children (the three boxes) are arranged horizontally."] @@ -127,33 +124,33 @@ [:p [:strong "Note: "] "There is a bug in Chrome. When switching from :between to :around (or visa versa), the change is not shown. To get around this, select a different value beforehand."]]]} ;; Align - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom true) :range [0 200]} - :width {:value "450px" :omit? false :editing? (atom false) :range [0 1000]} - :justify {:value :start :omit? true :editing? (atom false)} - :align {:value :stretch :omit? false :editing? (atom true)} - :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom true ) :range [0 200]} + :width {:value "450px" :omit? false :editing? (atom false) :range [0 1000]} + :justify {:value :start :omit? true :editing? (atom false)} + :align {:value :stretch :omit? false :editing? (atom true )} + :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} - :align-self {:value :center :omit? false :editing? (atom true)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} + :align-self {:value :center :omit? false :editing? (atom true )} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} - :align-self {:value :end :omit? false :editing? (atom true)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} + :align-self {:value :end :omit? false :editing? (atom true )} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :desc [v-box :children [[:p.info-subheading "The " [:code ":align"] " & " [:code ":align-self"] " parameters"] [:p [:code ":align"] " specifies how children are arranged vertically."] @@ -169,40 +166,40 @@ :target "_blank"] "."]]]} ;; Size - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} - :width {:value "450px" :omit? false :editing? (atom true) :range [0 1000]} - :justify {:value :start :omit? true :editing? (atom false)} - :align {:value :stretch :omit? true :editing? (atom false)} - :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} + :width {:value "450px" :omit? false :editing? (atom true ) :range [0 1000]} + :justify {:value :start :omit? true :editing? (atom false)} + :align {:value :stretch :omit? true :editing? (atom false)} + :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} - :size {:value "none" :omit? false :editing? (atom true) :type :none :px "50px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} + :size {:value "none" :omit? false :editing? (atom true ) :type :none :px "50px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} - :size {:value "100px" :omit? false :editing? (atom true) :type :px :px "100px" :ratio "2" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} + :size {:value "100px" :omit? false :editing? (atom true ) :type :px :px "100px" :ratio "2" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} - :size {:value "1" :omit? false :editing? (atom true) :type :ratio :px "150px" :ratio "1" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} + :size {:value "1" :omit? false :editing? (atom true ) :type :ratio :px "150px" :ratio "1" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :desc [v-box :children [[:p.info-subheading "The " [:code ":size"] " parameter"] [p "The " [hyperlink-href - :label [:span "Layout page"] - :href "#/layout" - :target "_blank"] + :label [:span "Layout page"] + :href "#/layout" + :target "_blank"] " describes the importance of " [:code ":size"] "."] [:p [:strong "Box1"] " has a " [:code ":size"] " of \"none\" which means it will take up as much width as its content, in this case, the text \"Box1\"."] [:p [:strong "Box2"] " has a fixed 100 pixel " [:code ":size"] ". Width in the case on an h-box."] @@ -211,41 +208,40 @@ [:ul [:li "Adjust the h-box " [:code ":width"] " and notice how Box1 and Box2 don't change in width, and Box3 greedily takes any excess space and squeezes down to nothing as the h-box width is reduced further."] [:li "Set the Box2 " [:code ":size"] " to a ratio value of \"2\" and notice how it will always take up double the width of Box3 (ratio \"1\") as you adjust the h-box " [:code ":width"] "."] - [:li "Set the Box2 " [:code ":size"] " to a gsb value of \"0 0 80%\". Its width is fixed to 80% of its parent h-box, with no growing or shrinking. Box1 and Box2 now have fixed widths. Box3 can grow and shrink. See this in action as you adjust the h-box " [:code ":width"] "."] - ] + [:li "Set the Box2 " [:code ":size"] " to a gsb value of \"0 0 80%\". Its width is fixed to 80% of its parent h-box, with no growing or shrinking. Box1 and Box2 now have fixed widths. Box3 can grow and shrink. See this in action as you adjust the h-box " [:code ":width"] "."]] [:p [:code ":size"] " is the analog of " [hyperlink-href - :label "Flexbox flex style" - :href "https://developer.mozilla.org/en-US/docs/Web/CSS/flex" - :target "_blank"] "."]]]} + :label "Flexbox flex style" + :href "https://developer.mozilla.org/en-US/docs/Web/CSS/flex" + :target "_blank"] "."]]]} ;; Size2 - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} - :width {:value "500px" :omit? false :editing? (atom true) :range [0 1000]} - :justify {:value :start :omit? true :editing? (atom false)} - :align {:value :stretch :omit? true :editing? (atom false)} - :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} + :width {:value "500px" :omit? false :editing? (atom true ) :range [0 1000]} + :justify {:value :start :omit? true :editing? (atom false)} + :align {:value :stretch :omit? true :editing? (atom false)} + :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} - :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} + :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} - :size {:value "5 1 200px" :omit? false :editing? (atom true) :type :gsb :px "100px" :ratio "2" :gsb "5 1 200px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} + :size {:value "5 1 200px" :omit? false :editing? (atom true ) :type :gsb :px "100px" :ratio "2" :gsb "5 1 200px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} - :size {:value "1 3 200px" :omit? false :editing? (atom true) :type :gsb :px "150px" :ratio "1" :gsb "1 3 200px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} + :size {:value "1 3 200px" :omit? false :editing? (atom true ) :type :gsb :px "150px" :ratio "1" :gsb "1 3 200px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :desc [v-box :children [[:p.info-subheading "The " [:code ":size"] " parameter - Advanced GSB"] [:p "This demonstrates a complex example of gsb."] @@ -256,37 +252,36 @@ [:p.info-subheading "Things to try"] [:ul [:li "Increase the h-box " [:code ":width"] " from the initial 500px. The extra space (excluding the initial 200px for Box2 and Box3) will be distributed between Box2 and Box3 in a ratio of 5 to 1, so Box2 will grow faster than Box3."] - [:li "Decrease the h-box " [:code ":width"] " from the initial 500px. The space to be removed from Box2 and Box3 will be removed in a ratio of 1 to 3, so Box3 will shrink faster than Box2 until it reaches 0px. Box2 will then continue to reduce until it too gets to 0px."] - ]]]} + [:li "Decrease the h-box " [:code ":width"] " from the initial 500px. The space to be removed from Box2 and Box3 will be removed in a ratio of 1 to 3, so Box3 will shrink faster than Box2 until it reaches 0px. Box2 will then continue to reduce until it too gets to 0px."]]]]} ;; Width - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} - :width {:value "450px" :omit? false :editing? (atom true ) :range [0 1000]} - :justify {:value :start :omit? true :editing? (atom false)} - :align {:value :stretch :omit? true :editing? (atom false)} - :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} + :width {:value "450px" :omit? false :editing? (atom true ) :range [0 1000]} + :justify {:value :start :omit? true :editing? (atom false)} + :align {:value :stretch :omit? true :editing? (atom false)} + :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} - :size {:value "auto" :omit? false :editing? (atom true) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :min-width {:value "100px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "200px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} + :size {:value "auto" :omit? false :editing? (atom true ) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :min-width {:value "100px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "200px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} - :min-width {:value "100px" :omit? false :editing? (atom true) :range [0 200]} - :max-width {:value "200px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} + :min-width {:value "100px" :omit? false :editing? (atom true ) :range [0 200]} + :max-width {:value "200px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "25px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "75px" :omit? false :editing? (atom true) :range [0 200]}} + :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "25px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "75px" :omit? false :editing? (atom true ) :range [0 200]}} :desc [v-box :children [[:p.info-subheading "The " [:code ":width"] " & " [:code ":min/max-width"] " parameters"] [:p "It's interesting to see how child :min-width and :max-width parameters affect layout."] @@ -296,37 +291,36 @@ [:ul [:li "Decrease the h-box " [:code ":width"] " and notice how Box2 shrinks only until it reaches the minimum of 100px."] [:li "Increase the h-box " [:code ":width"] " and notice how Box3 grows only until it reaches the maximum of 75px."] - [:li "Turn on " [:code ":min-width"] " for Box3 and while adjusting the h-box " [:code ":width"] ", notice how Box3 grows & shrinks only between the min and max values."] - ]]]} + [:li "Turn on " [:code ":min-width"] " for Box3 and while adjusting the h-box " [:code ":width"] ", notice how Box3 grows & shrinks only between the min and max values."]]]]} ;; Height - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom true) :range [0 200]} - :width {:value "450px" :omit? false :editing? (atom false) :range [0 1000]} - :justify {:value :start :omit? true :editing? (atom false)} - :align {:value :stretch :omit? false :editing? (atom false)} - :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom true ) :range [0 200]} + :width {:value "450px" :omit? false :editing? (atom false) :range [0 1000]} + :justify {:value :start :omit? true :editing? (atom false)} + :align {:value :stretch :omit? false :editing? (atom false)} + :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "40px" :omit? false :editing? (atom true) :range [0 200]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom false) :type :text :text "Box1"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "50px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "40px" :omit? false :editing? (atom true ) :range [0 200]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "80px" :omit? false :editing? (atom true) :range [0 300]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box2" :omit? false :editing? (atom false) :type :text :text "Box2"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "80px" :omit? false :editing? (atom true ) :range [0 300]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "110px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box3" :omit? false :editing? (atom false) :type :text :text "Box3"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "150px" :ratio "1" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "110px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :desc [v-box :children [[:p.info-subheading "The " [:code ":height"] " parameter"] [:p "It's interesting to see how the child :height parameter affects layout."] @@ -334,37 +328,36 @@ [:p.info-subheading "Things to try"] [:ul [:li "Turn on the Box3 " [:code ":height"] " parameter and see how it can spill outside the h-box when it has a :height set."] - [:li "Turn off the h-box " [:code ":height"] " parameter then adjust the :height of one or more boxes. Notice how h-box :height is now determined by the height on the maximum box heights."] - ]]]} + [:li "Turn off the h-box " [:code ":height"] " parameter then adjust the :height of one or more boxes. Notice how h-box :height is now determined by the height on the maximum box heights."]]]]} ;; Children - {:hbox {:over? false - :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} - :width {:value "600px" :omit? false :editing? (atom true) :range [0 1000]} - :justify {:value :start :omit? true :editing? (atom false)} - :align {:value :stretch :omit? true :editing? (atom false)} - :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} + {:hbox {:over? false + :height {:value "100px" :omit? false :editing? (atom false) :range [0 200]} + :width {:value "600px" :omit? false :editing? (atom true ) :range [0 1000]} + :justify {:value :start :omit? true :editing? (atom false)} + :align {:value :stretch :omit? true :editing? (atom false)} + :gap {:value "4px" :omit? false :editing? (atom false) :range [0 100]}} :box1 {:over? false - :text {:value "Box1" :omit? false :editing? (atom true) :type :text :text "Box1"} - :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "3" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value "Box1" :omit? false :editing? (atom true ) :type :text :text "Box1"} + :size {:value "100px" :omit? false :editing? (atom false) :type :px :px "100px" :ratio "3" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box2 {:over? false - :text {:value paragraph-filler :omit? false :editing? (atom true) :type :paras :text "Box2"} - :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} - :align-self {:value :stretch :omit? true :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value paragraph-filler :omit? false :editing? (atom true ) :type :paras :text "Box2"} + :size {:value "auto" :omit? false :editing? (atom false) :type :auto :px "100px" :ratio "2" :gsb "1 1 0px"} + :align-self {:value :stretch :omit? true :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 300]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :box3 {:over? false - :text {:value buttons-filler :omit? false :editing? (atom true) :type :buttons :text "Box3"} - :size {:value "none" :omit? false :editing? (atom false) :type :none :px "100px" :ratio "1" :gsb "1 1 0px"} - :align-self {:value :end :omit? false :editing? (atom false)} - :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} - :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} - :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} + :text {:value buttons-filler :omit? false :editing? (atom true ) :type :buttons :text "Box3"} + :size {:value "none" :omit? false :editing? (atom false) :type :none :px "100px" :ratio "1" :gsb "1 1 0px"} + :align-self {:value :end :omit? false :editing? (atom false)} + :height {:value "50px" :omit? true :editing? (atom false) :range [0 400]} + :min-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]} + :max-width {:value "50px" :omit? true :editing? (atom false) :range [0 200]}} :desc [v-box :children [[:p.info-subheading "The " [:code ":children"] " & " [:code ":child"] " parameters"] [:p "The content of an h-box is specified by the " [:code ":children"] " parameter. It's a vector of n components."] @@ -373,9 +366,7 @@ [:ul [:li "Adjust the h-box " [:code ":width"] " parameter to see how Box2 is the only one that shrinks and grows."] [:li "Turn off the h-box " [:code ":height"] " parameter to see how it automatically expands to show the rest of the content in Box2."] - [:li "Edit the box " [:code ":child"] " parameters to change the content to see how the current layout handles more or less content."] - ]]]} - ]) + [:li "Edit the box " [:code ":child"] " parameters to change the content to see how the current layout handles more or less content."]]]]}]) (def box-state (reaction (get demos @current-demo))) @@ -581,7 +572,7 @@ (reset! size-status :warning)))]) [close-button on-close]]] [:span - {:style {:font-family "Segoe UI, Roboto, sans-serif" + {:style {:font-family "sans-serif" :font-size "10px" :color "#aaa"}} "GSB: " (case @model @@ -631,7 +622,7 @@ :else (str "\"" val "\"")))) row-active? (and @mouse-over-row? active?) mouse-over-group? (= (nth path 0) (:over-group @box-state)) - show-checkbox? (and row-active? (not (contains? (set path) :text))) + show-checkbox? (and editor (not (contains? (set path) :text))) ;; To only show on mouse over, use: (and row-active? (not (contains? (set path) :text))) allow-edit? (and row-active? (not @omit?)) editing? (if editor (get-in @box-state editing?-path) (reagent/atom false)) arg-hiccup [h-box @@ -646,7 +637,7 @@ :on-mouse-out #(mouse-over-fn false)} :children [[box :size "20px" - :child (if (and editor (not (contains? (set path) :text))) ;show-checkbox? ;; TODO: Cleanup here if we like always showing checkboxes + :child (if show-checkbox? [checkbox :model (not @omit?) :style {:opacity "0.6"} @@ -808,11 +799,10 @@ :gap "10px" :width "650px" :height "800px" - ;:style {:border "dashed 1px #ddd"} + ;:style {:border "dashed 1px #ddd"} ;; Adds a slightly visible border around the h-box parent :children [[title2 "Demo"] [editable-code] [gap :size "0px"] [demo] [gap :size "0px"] - [choose-a-demo] - ]]]]]])) + [choose-a-demo]]]]]]])) diff --git a/src/re_demo/selection_list.cljs b/src/re_demo/selection_list.cljs index 03a5b45d..310916ea 100644 --- a/src/re_demo/selection_list.cljs +++ b/src/re_demo/selection_list.cljs @@ -65,7 +65,7 @@ :multi-select? multi-select? :disabled? disabled? :required? required? - :on-change #(do (println "selections: '" % "'") (reset! selections %))]]] + :on-change #(reset! selections %)]]] multi-select? disabled? required? diff --git a/src/re_demo/title.cljs b/src/re_demo/title.cljs index 6ed981ba..41534627 100644 --- a/src/re_demo/title.cljs +++ b/src/re_demo/title.cljs @@ -11,7 +11,7 @@ (fn [] (let [base-url (str "https://github.com/Day8/re-com/tree/" (if ^boolean js/goog.DEBUG "develop" "master") "/") - para-text (fn [] [p "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quod si ita est, sequitur id ipsum, quod te velle video, omnes semper beatos esse sapientes. Tamen a proposito, inquam, aberramus. "])] + para-text [p "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quod si ita est, sequitur id ipsum, quod te velle video, omnes semper beatos esse sapientes. Tamen a proposito, inquam, aberramus. "]] [v-box :size "auto" :gap "10px" @@ -34,15 +34,20 @@ :target "_blank"] " will apply."] [p - "Re-com uses the " + "Re-com uses " [hyperlink-href - :label "Roboto" - :href "http://www.google.com/fonts/specimen/Roboto" + :label "Segoe UI" + :href "https://www.microsoft.com/typography/fonts/family.aspx?FID=331" :target "_blank"] - " as its default font. See " + " as its default font (available on Windows) with a fallback to the public domain " [hyperlink-href - :label "re-com.css" - :href (str base-url "run/resources/public/assets/css/re-com.css") + :label "Roboto" + :href "http://www.google.com/fonts/specimen/Roboto" + :target "_blank"] + " font. See " + [hyperlink-href + :label "re-com.css" + :href (str base-url "run/resources/public/assets/css/re-com.css") :target "_blank"] "."] [args-table title-args-desc]]] @@ -55,15 +60,15 @@ :model underline? :on-change #(reset! underline? %)] [gap :size "40px"] - (para-text) + para-text [title :level :level1 :underline? @underline? :label ":level1 - Light 42px"] - (para-text) + para-text [title :level :level2 :underline? @underline? :label ":level2 - Light 26px"] - (para-text) + para-text [title :level :level3 :underline? @underline? :label ":level3 - Semibold 15px"] - (para-text) + para-text [title :level :level4 :underline? @underline? :label ":level4 - Semibold 15px"] - (para-text)]]]]]]]])))) + para-text]]]]]]]])))) ;; core holds a reference to panel, so need one level of indirection to get figwheel updates