Enhance TextField example with other options

This commit is contained in:
Juho Teperi 2018-06-17 21:51:53 +03:00
parent 91ea195796
commit 199533a1ea
2 changed files with 67 additions and 6 deletions

View File

@ -50,8 +50,16 @@ it is useful to wrap the `TextField` component in a way that the option is added
(let [props (-> props
(assoc-in [:InputProps :inputComponent] input-component)
rtpl/convert-prop-value)]
(apply r/create-element mui/TextField props children)))
(apply r/create-element mui/TextField props (map r/as-element children))))
```
Here `r/create-element` and `reagent.impl.template/covert-prop-values` achieve
the same as what `adapt-react-class` does, but allows modifying the props.
**Check the example project for complete code.** Some additional logic is
required to ensure option like `:multiline` and `:select` work correctly,
as they affect how the `inputComponent` should work.
TODO: `:multiline` `TextField` without `:rows` (i.e. automatic height) doesn't
work, because that requires Material-UI `Input/Textarea`, which doesn't work
with Reagent cursor fix.

View File

@ -5,6 +5,7 @@
[reagent.impl.template :as rtpl]))
(def mui-theme-provider (r/adapt-react-class mui/MuiThemeProvider))
(def menu-item (r/adapt-react-class mui/MenuItem))
(def ^:private input-component
(r/reactify-component
@ -13,36 +14,88 @@
(assoc :ref (:inputRef props))
(dissoc :inputRef))])))
(def ^:private textarea-component
(r/reactify-component
(fn [props]
[:textarea (-> props
(assoc :ref (:inputRef props))
(dissoc :inputRef))])))
;; To fix cursor jumping when controlled input value is changed,
;; use wrapper input element created by Reagent instead of
;; letting Material-UI to create input element directly using React.
;; Create-element + convert-props-value is the same as what adapt-react-class does.
(defn text-field [props & children]
(let [props (-> props
(assoc-in [:InputProps :inputComponent] input-component)
(assoc-in [:InputProps :inputComponent] (cond
(and (:multiline props) (:rows props) (not (:maxRows props)))
textarea-component
;; FIXME: Autosize multiline input is broken.
(:multiline props)
nil
(not (:select props))
nil
:else
input-component))
rtpl/convert-prop-value)]
(apply r/create-element mui/TextField props children)))
(apply r/create-element mui/TextField props (map r/as-element children))))
(defonce text-state (r/atom "foobar"))
(defn main []
[:div
[:form
{:style {:display "flex"
:flex-direction "column"
:flex-wrap "wrap"}}
[:div
[:strong @text-state]]
[:button
{:on-click #(swap! text-state str " foo")}
"update value property"]
[:button
{:on-click #(reset! text-state "")}
"reset"]
[text-field
{:id "example"
:value @text-state
:label "Label"
:label "Text input"
:placeholder "Placeholder"
:helper-text "Helper text"
:on-change (fn [e]
(reset! text-state (.. e -target -value)))
:inputRef #(js/console.log "input-ref" %)}]])
:inputRef #(js/console.log "input-ref" %)}]
[text-field
{:id "example"
:value @text-state
:label "Textarea"
:placeholder "Placeholder"
:helper-text "Helper text"
:on-change (fn [e]
(reset! text-state (.. e -target -value)))
:multiline true
;; TODO: Autosize textarea is broken.
:rows 10}]
[text-field
{:id "example"
:value @text-state
:label "Select"
:placeholder "Placeholder"
:helper-text "Helper text"
:on-change (fn [e]
(reset! text-state (.. e -target -value)))
:select true}
[menu-item
{:value 1} "Item 1"]
[menu-item
{:value 2} "Item 2"]]])
(defn start []
(r/render [main] (js/document.getElementById "app")))