|
6 | 6 | [clojure.string :as str] |
7 | 7 | [reagent.core :as r] |
8 | 8 | [re-com.config :refer [include-args-desc?]] |
9 | | - [re-com.util :refer [deref-or-value]] |
| 9 | + [re-com.util :refer [deref-or-value remove-id-item]] |
10 | 10 | [re-com.box :refer [h-box v-box box gap]] |
11 | 11 | [re-com.checkbox :refer [checkbox]] |
12 | | - [re-com.validate :as validate :refer [css-style? html-attr?] :refer-macros [validate-args-macro]])) |
| 12 | + [re-com.validate :as validate :refer [css-style? html-attr? parts?] :refer-macros [validate-args-macro]])) |
13 | 13 |
|
14 | 14 | (def tree-select-dropdown-parts-desc |
15 | 15 | (when include-args-desc? |
|
22 | 22 | {:name :dropdown-wrapper :level 2 :class "rc-tree-select-dropdown-dropdown-wrapper" :impl "[v-box]"} |
23 | 23 | {:name :body :level 3 :class "rc-tree-select-dropdown-body" :impl "[tree-select]"}])) |
24 | 24 |
|
| 25 | +(def tree-select-dropdown-parts |
| 26 | + (when include-args-desc? |
| 27 | + (-> (map :name tree-select-dropdown-parts-desc) set))) |
| 28 | + |
25 | 29 | (def tree-select-parts-desc |
26 | 30 | (when include-args-desc? |
27 | 31 | [{:type :legacy :level 0 :class "rc-tree-select" :impl "[tree-select]"} |
|
32 | 36 | {:name :expander :level 3 :class "rc-tree-select-expander" :impl "[box]"} |
33 | 37 | {:name :checkbox :level 3 :class "rc-tree-select-checkbox" :impl "[checkbox]"}])) |
34 | 38 |
|
| 39 | +(def tree-select-parts |
| 40 | + (when include-args-desc? |
| 41 | + (-> (map :name tree-select-parts-desc) set))) |
| 42 | + |
35 | 43 | (def tree-select-args-desc |
36 | 44 | (when include-args-desc? |
37 | 45 | [{:name :choices |
|
107 | 115 | :validate-fn ifn? |
108 | 116 | :description [:span "A function which can turn a group vector into a displayable label. Will be called for each element in " |
109 | 117 | [:code ":groups"] ". Given one argument, a group vector, it returns a string or hiccup."]} |
110 | | - {:name :class :required false :type "string" :validate-fn string? :description "CSS class names, space separated (applies to the outer container)"} |
111 | | - {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "CSS styles to add or override (applies to the outer container)"} |
112 | | - {:name :attr :required false :type "HTML attr map" :validate-fn html-attr? :description [:span "HTML attributes, like " [:code ":on-mouse-move"] [:br] "No " [:code ":class"] " or " [:code ":style"] "allowed (applies to the outer container)"]} |
113 | | - {:name :src :required false :type "map" :validate-fn map? :description [:span "Used in dev builds to assist with debugging. Source code coordinates map containing keys" [:code ":file"] "and" [:code ":line"] ". See 'Debugging'."]}])) |
| 118 | + {:name :class |
| 119 | + :required false |
| 120 | + :type "string" |
| 121 | + :validate-fn string? |
| 122 | + :description "CSS class names, space separated (applies to the outer container)"} |
| 123 | + {:name :style |
| 124 | + :required false |
| 125 | + :type "CSS style map" |
| 126 | + :validate-fn css-style? |
| 127 | + :description "CSS styles to add or override (applies to the outer container)"} |
| 128 | + {:name :attr |
| 129 | + :required false |
| 130 | + :type "HTML attr map" |
| 131 | + :validate-fn html-attr? |
| 132 | + :description [:span "HTML attributes, like " [:code ":on-mouse-move"] [:br] |
| 133 | + "No " [:code ":class"] " or " [:code ":style"] "allowed (applies to the outer container)"]} |
| 134 | + {:name :parts |
| 135 | + :required false |
| 136 | + :type "map" |
| 137 | + :validate-fn (parts? tree-select-parts) |
| 138 | + :description "See Parts section below."} |
| 139 | + {:name :src |
| 140 | + :required false |
| 141 | + :type "map" |
| 142 | + :validate-fn map? |
| 143 | + :description [:span "Used in dev builds to assist with debugging. Source code coordinates map containing keys" |
| 144 | + [:code ":file"] "and" [:code ":line"] ". See 'Debugging'."]}])) |
114 | 145 |
|
115 | 146 | (def tree-select-dropdown-args-desc |
116 | 147 | (when include-args-desc? |
117 | | - (into tree-select-args-desc |
118 | | - [{:name :placeholder |
119 | | - :required false |
120 | | - :type "string" |
121 | | - :validate-fn string? |
122 | | - :description "(Dropdown version only). Background text shown when there's no selection."} |
123 | | - {:name :field-label-fn |
124 | | - :required false |
125 | | - :type "map -> string or hiccup" |
126 | | - :validate-fn ifn? |
127 | | - :description (str "(Dropdown version only). Accepts a map, including keys :items, :group-label-fn and :label-fn. " |
128 | | - "Can return a string or hiccup, which will be rendered inside the dropdown anchor box.")} |
129 | | - {:name :alt-text-fn |
130 | | - :required false |
131 | | - :type "map -> string" |
132 | | - :validate-fn ifn? |
133 | | - :description (str "(Dropdown version only). Accepts a map, including keys :items, :group-label-fn and :label-fn. " |
134 | | - "Returns a string that will display in the native browser tooltip that appears on mouse hover.")}]))) |
| 148 | + (into |
| 149 | + (remove-id-item :parts tree-select-args-desc {:id-fn :name}) |
| 150 | + [{:name :placeholder |
| 151 | + :required false |
| 152 | + :type "string" |
| 153 | + :validate-fn string? |
| 154 | + :description "(Dropdown version only). Background text shown when there's no selection."} |
| 155 | + {:name :field-label-fn |
| 156 | + :required false |
| 157 | + :type "map -> string or hiccup" |
| 158 | + :validate-fn ifn? |
| 159 | + :description (str "(Dropdown version only). Accepts a map, including keys :items, :group-label-fn and :label-fn. " |
| 160 | + "Can return a string or hiccup, which will be rendered inside the dropdown anchor box.")} |
| 161 | + {:name :alt-text-fn |
| 162 | + :required false |
| 163 | + :type "map -> string" |
| 164 | + :validate-fn ifn? |
| 165 | + :description (str "(Dropdown version only). Accepts a map, including keys :items, :group-label-fn and :label-fn. " |
| 166 | + "Returns a string that will display in the native browser tooltip that appears on mouse hover.")} |
| 167 | + {:name :parts |
| 168 | + :required false |
| 169 | + :type "map" |
| 170 | + :validate-fn (parts? tree-select-dropdown-parts) |
| 171 | + :description "See Parts section below."}]))) |
135 | 172 |
|
136 | 173 | (defn backdrop |
137 | 174 | [{:keys [opacity on-click parts]}] |
|
149 | 186 | :on-click (when on-click (handler-fn (on-click)))} |
150 | 187 | (get-in parts [:backdrop :attr])))]) |
151 | 188 |
|
152 | | -(defn offset [{:keys [parts level]}] |
| 189 | +(defn offset [& {:keys [parts level]}] |
153 | 190 | [box |
154 | 191 | :src (at) |
155 | 192 | :style (into {:visibility "hidden"} (get-in parts [:offset :style])) |
|
162 | 199 | :src (at) |
163 | 200 | :style (get-in parts [:checkbox :style]) |
164 | 201 | :class (str "rc-tree-select-checkbox " (get-in parts [:checkbox :class])) |
165 | | - :attr (merge {} |
166 | | - (when attr attr) |
167 | | - (get-in parts [:checkbox :attr])) |
| 202 | + :attr (into attr (get-in parts [:checkbox :attr])) |
168 | 203 | :model checked? |
169 | 204 | :on-change toggle! |
170 | 205 | :label label |
171 | 206 | :disabled? disabled?]) |
172 | 207 |
|
173 | | -(defn choice-item [{:keys [level showing? parts] :as props}] |
| 208 | +(defn choice-item [& {:keys [level showing? parts] :as props}] |
174 | 209 | (when showing? |
175 | 210 | [h-box |
176 | 211 | :src (at) |
177 | 212 | :style (get-in parts [:choice :style]) |
178 | 213 | :class (str "rc-tree-select-choice " (get-in parts [:choice :class])) |
179 | 214 | :attr (get-in parts [:choice :attr]) |
180 | 215 | :children |
181 | | - [[offset {:parts parts :level level}] |
182 | | - [choice-checkbox (into props {:attr {}})]]])) |
| 216 | + [[offset :parts parts :level level] |
| 217 | + [choice-checkbox props]]])) |
183 | 218 |
|
184 | | -(defn group-item [{:keys [label checked? toggle! hide-show! level showing? open? disabled? parts] :as props}] |
| 219 | +(defn group-item [& {:keys [label checked? toggle! hide-show! level showing? open? disabled? parts] :as props}] |
185 | 220 | (when showing? |
186 | 221 | [h-box |
187 | 222 | :src (at) |
188 | | - :class "chosen-container chosen-container-single chosen-container-active" |
189 | 223 | :style (get-in parts [:group :style]) |
190 | 224 | :class (str "rc-tree-select-group " (get-in parts [:group :class])) |
191 | 225 | :attr (get-in parts [:group :attr]) |
192 | 226 | :children |
193 | | - [[offset {:parts parts :level (dec level)}] |
| 227 | + [[offset :parts parts :level (dec level)] |
194 | 228 | [box |
195 | 229 | :src (at) |
196 | 230 | :attr (into {:on-click hide-show!} (get-in parts [:expander :attr])) |
|
279 | 313 | item (fn [item-props] |
280 | 314 | (let [{:keys [id group] :as item-props} (update item-props :group as-v)] |
281 | 315 | (if (group? item-props) |
282 | | - [group-item |
283 | | - (let [descendants (filter-descendants* group choices) |
284 | | - descendant-ids (map :id descendants) |
285 | | - checked? (cond |
286 | | - (every? model descendant-ids) :all |
287 | | - (some model descendant-ids) :some) |
288 | | - new-model (->> (cond->> descendants choice-disabled-fn (remove choice-disabled-fn)) |
289 | | - (map :id) |
290 | | - ((if (= :all checked?) set/difference set/union) model) |
291 | | - set) |
292 | | - new-groups (into #{} (map :group) (full-groups new-model choices))] |
293 | | - {:group item-props |
294 | | - :label (group-label-fn item-props) |
295 | | - :style (get-in parts [:group :style]) |
296 | | - :class (str "rc-tree-select-group " (get-in parts [:group :class])) |
297 | | - :attr (str get-in parts [:group :attr]) |
298 | | - :hide-show! #(swap! expanded-groups toggle group) |
299 | | - :toggle! (handler-fn (on-change new-model new-groups)) |
300 | | - :open? (contains? @expanded-groups group) |
301 | | - :checked? checked? |
302 | | - :model model |
303 | | - :disabled? (or disabled? (when choice-disabled-fn (every? choice-disabled-fn descendants))) |
304 | | - :showing? (every? (set @expanded-groups) (rest (ancestor-paths group))) |
305 | | - :level (count group)})] |
| 316 | + (let [descendants (filter-descendants* group choices) |
| 317 | + descendant-ids (map :id descendants) |
| 318 | + checked? (cond |
| 319 | + (every? model descendant-ids) :all |
| 320 | + (some model descendant-ids) :some) |
| 321 | + new-model (->> (cond->> descendants choice-disabled-fn (remove choice-disabled-fn)) |
| 322 | + (map :id) |
| 323 | + ((if (= :all checked?) set/difference set/union) model) |
| 324 | + set) |
| 325 | + new-groups (into #{} (map :group) (full-groups new-model choices))] |
| 326 | + [group-item |
| 327 | + :group item-props |
| 328 | + :label (group-label-fn item-props) |
| 329 | + :parts parts |
| 330 | + :hide-show! #(swap! expanded-groups toggle group) |
| 331 | + :toggle! (handler-fn (on-change new-model new-groups)) |
| 332 | + :open? (contains? @expanded-groups group) |
| 333 | + :checked? checked? |
| 334 | + :model model |
| 335 | + :disabled? (or disabled? (when choice-disabled-fn (every? choice-disabled-fn descendants))) |
| 336 | + :showing? (every? (set @expanded-groups) (rest (ancestor-paths group))) |
| 337 | + :level (count group)]) |
306 | 338 | [choice-item |
307 | | - {:choice item-props |
308 | | - :model model |
309 | | - :label (label-fn item-props) |
310 | | - :style (get-in parts [:choice :style]) |
311 | | - :class (str "rc-tree-select-choice " (get-in parts [:choice :class])) |
312 | | - :attr (str get-in parts [:choice :attr]) |
313 | | - :showing? (if-not group |
314 | | - true |
315 | | - (every? (set @expanded-groups) (ancestor-paths group))) |
316 | | - :disabled? (or disabled? (when choice-disabled-fn (choice-disabled-fn item-props))) |
317 | | - :toggle! (handler-fn (let [new-model (toggle model id) |
318 | | - new-groups (into #{} (map :group) (full-groups new-model choices))] |
319 | | - (on-change new-model new-groups))) |
320 | | - :checked? (get model id) |
321 | | - :level (inc (count group))}])))] |
| 339 | + :choice item-props |
| 340 | + :model model |
| 341 | + :label (label-fn item-props) |
| 342 | + :parts parts |
| 343 | + :showing? (if-not group |
| 344 | + true |
| 345 | + (every? (set @expanded-groups) (ancestor-paths group))) |
| 346 | + :disabled? (or disabled? (when choice-disabled-fn (choice-disabled-fn item-props))) |
| 347 | + :toggle! (handler-fn (let [new-model (toggle model id) |
| 348 | + new-groups (into #{} (map :group) (full-groups new-model choices))] |
| 349 | + (on-change new-model new-groups))) |
| 350 | + :checked? (get model id) |
| 351 | + :level (inc (count group))])))] |
322 | 352 | [v-box |
323 | 353 | :src (at) |
324 | 354 | :min-width min-width |
|
465 | 495 | (when @showing? |
466 | 496 | [:div {:class "fade in" |
467 | 497 | :style {:position "relative"}} |
468 | | - [backdrop {:on-click #(reset! showing? false)}] |
| 498 | + [backdrop {:parts parts |
| 499 | + :on-click #(reset! showing? false)}] |
469 | 500 | body])])))) |
0 commit comments