|
1 | 1 | (ns cljfx.dev
|
| 2 | + "Helpers for cljfx app development that shouldn't be included into production |
| 3 | +
|
| 4 | + You can get help for existing lifecycles and props by using help fn: |
| 5 | +
|
| 6 | + (cljfx.dev/help) |
| 7 | + ;; prints information about all cljfx lifecycles including :label |
| 8 | + (cljfx.dev/help :label) |
| 9 | + ;; prints information about label and its props including :graphic |
| 10 | + (cljfx.dev/help :label :graphic) |
| 11 | + ;; prints information about :graphic prop of a label |
| 12 | +
|
| 13 | + You can also add cljfx component validation that greatly improves error |
| 14 | + messages using cljfx.dev/type->lifecycle (or cljfx.dev/wrap-type->lifecycle): |
| 15 | +
|
| 16 | + (fx/create-component |
| 17 | + {:fx/type :stage |
| 18 | + :scene {:fx/type :scene |
| 19 | + :root {:fx/type :label |
| 20 | + :text true}}} |
| 21 | + {:fx.opt/type->lifecycle cljfx.dev/type->lifecycle}) |
| 22 | + ;; Execution error (ExceptionInfo) at cljfx.dev/ensure-valid-desc (validation.clj:62). |
| 23 | + ;; Invalid cljfx description of :stage type: |
| 24 | + ;; true - failed: string? in [:scene :root :text] |
| 25 | + ;; |
| 26 | + ;; Cljfx component stack: |
| 27 | + ;; :stage" |
2 | 28 | (:require [cljfx.lifecycle :as lifecycle]
|
3 | 29 | [cljfx.api :as fx]
|
4 | 30 | [clojure.spec.alpha :as s]
|
|
72 | 98 | (s/and map? valid-fx-type? desc->spec))
|
73 | 99 |
|
74 | 100 | (defn register-props!
|
| 101 | + "Associate props description with some id |
| 102 | +
|
| 103 | + Args: |
| 104 | + id prop identifier, either keyword or symbol |
| 105 | + parent semantical parent id of the prop map, meaning props with the id |
| 106 | + should also accept props with parent id |
| 107 | + props a map from keyword to prop description, which is a map with |
| 108 | + a :type key that can be either: |
| 109 | + - symbol of a class name |
| 110 | + - keyword that defines a corresponding spec form by extending |
| 111 | + keyword-prop->spec-form multi-method" |
75 | 112 | ([id props]
|
76 | 113 | (register-props! id nil props))
|
77 | 114 | ([id parent props]
|
| 115 | + {:pre [(ident? id) |
| 116 | + (or (nil? parent) (ident? parent)) |
| 117 | + (or (nil? props) |
| 118 | + (and (map? props) |
| 119 | + (every? (fn [[k v]] |
| 120 | + (and (keyword? k) |
| 121 | + (contains? v :type))) |
| 122 | + props)))]} |
78 | 123 | (swap!
|
79 | 124 | registry
|
80 | 125 | (fn [registry]
|
|
94 | 139 | (assoc id->props id props))))))
|
95 | 140 | id))
|
96 | 141 |
|
97 |
| -(defn ^{:arglists '([id & {:keys [spec of]}])} register-type! [id & {:as opts}] |
98 |
| - {:pre [(ident? id)]} |
| 142 | +(defn register-type! |
| 143 | + "Associate cljfx type description with some id |
| 144 | +
|
| 145 | + Optional kv-args: |
| 146 | + :spec a spec to use when validating props of components with the id |
| 147 | + :of component instance class identifier, either: |
| 148 | + - symbol of a class name, e.g. javafx.scene.Node |
| 149 | + - keyword of a prop that hold another cljfx description that |
| 150 | + defines component instance class, e.g. :desc" |
| 151 | + [id & {:keys [spec of] :as opts}] |
| 152 | + {:pre [(ident? id) |
| 153 | + (or (nil? of) |
| 154 | + (ident? of))]} |
99 | 155 | (swap! registry update :types assoc id (assoc opts :id id))
|
100 | 156 | id)
|
101 | 157 |
|
|
109 | 165 |
|
110 | 166 | (defmulti keyword-prop->spec-form :type)
|
111 | 167 |
|
112 |
| -(defn prop->spec-form [prop] |
| 168 | +(defn prop->spec-form |
| 169 | + "Convert prop type config to spec form (i.e. clojure form that evals to spec) |
| 170 | +
|
| 171 | + You can extend prop type configs by adding more implementations to |
| 172 | + keyword-prop->spec-form multimethod" |
| 173 | + [prop] |
113 | 174 | (let [{:keys [type]} prop]
|
114 | 175 | (if (symbol? type)
|
115 | 176 | `(instance-of ~type)
|
|
132 | 193 | :opt-un ~(into [] (map k->spec-kw) (sort ks)))
|
133 | 194 | (only-keys ~ks))))))
|
134 | 195 |
|
135 |
| -(defn register-composite! [id & {:keys [parent props of req]}] |
| 196 | +(defn register-composite! |
| 197 | + "Associate a composite lifecycle type description with some id |
| 198 | +
|
| 199 | + Required kv-args: |
| 200 | + :of symbol of a component instance class |
| 201 | +
|
| 202 | + Optional kv-args: |
| 203 | + :parent semantic parent id of a lifecycle, meaning lifecycle with the id |
| 204 | + should also accept all props of parent id |
| 205 | + :props a map from keyword to prop description, which is a map with |
| 206 | + a :type key that can be either: |
| 207 | + - symbol of a class name |
| 208 | + - keyword that defines a corresponding spec form by extending |
| 209 | + keyword-prop->spec-form multi-method |
| 210 | + :req required props on the component, either: |
| 211 | + - a vector of prop keywords (all are required) |
| 212 | + - a set of vectors of prop keywords (either vector is required)" |
| 213 | + [id & {:keys [parent props of req]}] |
136 | 214 | {:pre [(symbol? of)
|
137 | 215 | (every? simple-keyword? (keys props))]}
|
138 | 216 | (register-props! id parent props)
|
|
241 | 319 | (load "dev/validation")
|
242 | 320 |
|
243 | 321 | (defn wrap-type->lifecycle
|
| 322 | + "Wrap type->lifecycle used in the cljfx UI app with improved error messages |
| 323 | +
|
| 324 | + Wrapped lifecycle performs spec validation of cljfx descriptions that results |
| 325 | + in better error messages shown when cljfx descriptions are invalid. |
| 326 | +
|
| 327 | + Additionally, exceptions thrown during cljfx lifecycle show a cljfx component |
| 328 | + stack to help with debugging. |
| 329 | +
|
| 330 | + Args: |
| 331 | + type->lifecycle the type->lifecycle fn used in opts of your app |
| 332 | + type->id custom type->id if you need a way to get id from your |
| 333 | + custom lifecycles" |
244 | 334 | ([type->lifecycle]
|
245 | 335 | (wrap-type->lifecycle type->lifecycle *type->id*))
|
246 | 336 | ([type->lifecycle type->id]
|
|
249 | 339 | (f type type->lifecycle type->id)))))
|
250 | 340 |
|
251 | 341 | (def type->lifecycle
|
| 342 | + "Default type->lifecycle that can be used in the cljfx UI app to improve error |
| 343 | + messages" |
252 | 344 | (wrap-type->lifecycle (some-fn fx/keyword->lifecycle fx/fn->lifecycle)))
|
253 | 345 |
|
254 | 346 | ;; next steps:
|
|
0 commit comments