migrating to react state. step 2 (#18905)
This commit is contained in:
parent
047e45d2a3
commit
b7bffb3bd3
|
@ -8,36 +8,36 @@
|
|||
[quo.components.calendar.calendar.years-list.view :as years-list]
|
||||
[quo.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[utils.number :as utils.number]))
|
||||
|
||||
(defn- view-internal
|
||||
[]
|
||||
(let [selected-year (reagent/atom (utils/current-year))
|
||||
selected-month (reagent/atom (utils/current-month))
|
||||
on-change-year #(reset! selected-year %)
|
||||
on-change-month (fn [new-date]
|
||||
(reset! selected-year (utils.number/parse-int (:year new-date)))
|
||||
(reset! selected-month (utils.number/parse-int (:month new-date))))]
|
||||
(fn [{:keys [on-change start-date end-date theme]}]
|
||||
[rn/view
|
||||
{:style (style/container theme)}
|
||||
[years-list/view
|
||||
{:on-change-year on-change-year
|
||||
:year @selected-year}]
|
||||
[rn/view
|
||||
{:style style/container-main}
|
||||
[month-picker/view
|
||||
{:year @selected-year
|
||||
:month @selected-month
|
||||
:on-change on-change-month}]
|
||||
[weekdays-header/view]
|
||||
[days-grid/view
|
||||
{:year @selected-year
|
||||
:month @selected-month
|
||||
:start-date start-date
|
||||
:end-date end-date
|
||||
:on-change on-change
|
||||
:customization-color :blue}]]])))
|
||||
|
||||
(def view (theme/with-theme view-internal))
|
||||
(defn view
|
||||
[{:keys [on-change start-date end-date]}]
|
||||
(let [theme (theme/use-theme-value)
|
||||
[selected-year set-selected-year] (rn/use-state (utils/current-year))
|
||||
[selected-month set-selected-month] (rn/use-state (utils/current-month))
|
||||
on-change-year (rn/use-callback #(set-selected-year %))
|
||||
on-change-month (rn/use-callback
|
||||
(fn [new-date]
|
||||
(set-selected-year
|
||||
(utils.number/parse-int (:year new-date)))
|
||||
(set-selected-month
|
||||
(utils.number/parse-int (:month new-date)))))]
|
||||
[rn/view
|
||||
{:style (style/container theme)}
|
||||
[years-list/view
|
||||
{:on-change-year on-change-year
|
||||
:year selected-year}]
|
||||
[rn/view
|
||||
{:style style/container-main}
|
||||
[month-picker/view
|
||||
{:year selected-year
|
||||
:month selected-month
|
||||
:on-change on-change-month}]
|
||||
[weekdays-header/view]
|
||||
[days-grid/view
|
||||
{:year selected-year
|
||||
:month selected-month
|
||||
:start-date start-date
|
||||
:end-date end-date
|
||||
:on-change on-change
|
||||
:customization-color :blue}]]]))
|
||||
|
|
|
@ -3,13 +3,7 @@
|
|||
[quo.components.colors.color.constants :as constants]
|
||||
[quo.components.colors.color.view :as color]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn- on-change-handler
|
||||
[selected color-name on-change]
|
||||
(reset! selected color-name)
|
||||
(when on-change (on-change color-name)))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn get-item-layout
|
||||
[_ index]
|
||||
|
@ -18,15 +12,34 @@
|
|||
:offset (* (+ constants/color-size 8) index)
|
||||
:index index})
|
||||
|
||||
(defn- view-internal
|
||||
(defn view
|
||||
"Options
|
||||
- `default-selected` Default selected color name.
|
||||
- `on-change` Callback called when a color is selected `(fn [color-name])`.
|
||||
- `blur?` Boolean to enable blur background support.}"
|
||||
[{:keys [default-selected blur? on-change feng-shui? container-style]}]
|
||||
(let [selected (reagent/atom default-selected)
|
||||
{window-width :width} (rn/get-window)
|
||||
ref (atom nil)]
|
||||
(let [[selected set-selected] (rn/use-state default-selected)
|
||||
{window-width :width} (rn/get-window)
|
||||
ref (rn/use-ref-atom nil)
|
||||
on-ref (rn/use-callback #(reset! ref %))
|
||||
render-fn (rn/use-callback
|
||||
(fn [color idx]
|
||||
[color/view
|
||||
{:selected? (= color selected)
|
||||
:on-press (fn [color-name]
|
||||
(.scrollToIndex ^js @ref
|
||||
#js
|
||||
{:animated true
|
||||
:index idx
|
||||
:viewPosition 0.5})
|
||||
(set-selected color-name)
|
||||
(when on-change (on-change color-name)))
|
||||
:blur? blur?
|
||||
:key color
|
||||
:color color
|
||||
:idx idx
|
||||
:window-width window-width}])
|
||||
[selected blur? on-change @ref])]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(js/setTimeout
|
||||
|
@ -40,32 +53,14 @@
|
|||
:viewPosition 0.5})))))
|
||||
50)))
|
||||
[rn/flat-list
|
||||
{:ref #(reset! ref %)
|
||||
{:ref on-ref
|
||||
;; TODO: using :feng-shui? temporarily while b & w is being developed.
|
||||
;; https://github.com/status-im/status-mobile/discussions/16676
|
||||
:data (if feng-shui?
|
||||
(conj colors/account-colors :feng-shui)
|
||||
colors/account-colors)
|
||||
:render-fn (fn [color idx]
|
||||
[color/view
|
||||
{:selected? (= color @selected)
|
||||
:on-press (fn [e]
|
||||
(.scrollToIndex ^js @ref
|
||||
#js
|
||||
{:animated true
|
||||
:index idx
|
||||
:viewPosition 0.5})
|
||||
(on-change-handler selected e on-change))
|
||||
:blur? blur?
|
||||
:key color
|
||||
:color color
|
||||
:idx idx
|
||||
:window-width window-width}])
|
||||
:render-fn render-fn
|
||||
:get-item-layout get-item-layout
|
||||
:horizontal true
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:content-container-style container-style}]))
|
||||
|
||||
(defn view
|
||||
[props]
|
||||
[:f> view-internal props])
|
||||
|
|
|
@ -35,12 +35,11 @@
|
|||
(defn image
|
||||
"Same as rn/image but cache the image source in a js/Set, so the image won't
|
||||
flicker when re-render on android"
|
||||
[]
|
||||
(let [loaded-source (reagent/atom nil)
|
||||
on-source-loaded #(reset! loaded-source %)]
|
||||
(fn [props]
|
||||
(if platform/ios?
|
||||
[rn/image props]
|
||||
[:<>
|
||||
[rn/image (assoc props :source @loaded-source)]
|
||||
[caching-image props on-source-loaded]]))))
|
||||
[props]
|
||||
(let [[loaded-source set-loaded-source] (rn/use-state nil)
|
||||
on-source-loaded (rn/use-callback #(set-loaded-source %))]
|
||||
(if platform/ios?
|
||||
[rn/image props]
|
||||
[:<>
|
||||
[rn/image (assoc props :source loaded-source)]
|
||||
[caching-image props on-source-loaded]])))
|
||||
|
|
|
@ -3,25 +3,23 @@
|
|||
[quo.components.dropdowns.network-dropdown.style :as style]
|
||||
[quo.components.list-items.preview-list.view :as preview-list]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- internal-view
|
||||
[_ _]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [on-press state] :as props} networks]
|
||||
[rn/pressable
|
||||
{:style (style/dropdown-container (merge props {:pressed? @pressed?}))
|
||||
:accessibility-label :network-dropdown
|
||||
:disabled (= state :disabled)
|
||||
:on-press on-press
|
||||
:on-press-in (fn [] (reset! pressed? true))
|
||||
:on-press-out (fn [] (reset! pressed? false))}
|
||||
[preview-list/view
|
||||
{:type :network
|
||||
:list-size (count networks)
|
||||
:size :size-20}
|
||||
networks]])))
|
||||
|
||||
(def view (quo.theme/with-theme internal-view))
|
||||
(defn view
|
||||
[{:keys [on-press state] :as props} networks]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[pressed? set-pressed] (rn/use-state false)
|
||||
on-press-in (rn/use-callback #(set-pressed true))
|
||||
on-press-out (rn/use-callback #(set-pressed false))]
|
||||
[rn/pressable
|
||||
{:style (style/dropdown-container (merge props {:pressed? pressed? :theme theme}))
|
||||
:accessibility-label :network-dropdown
|
||||
:disabled (= state :disabled)
|
||||
:on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out}
|
||||
[preview-list/view
|
||||
{:type :network
|
||||
:list-size (count networks)
|
||||
:size :size-20}
|
||||
networks]]))
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
(def initial-spacing 56)
|
||||
(def end-spacing 22)
|
||||
(def y-axis-label-width -33)
|
||||
(def inspecting? (reagent/atom false))
|
||||
|
||||
(defn- pointer
|
||||
[customization-color]
|
||||
|
@ -32,14 +31,9 @@
|
|||
:pointer-color customization-color
|
||||
:pointer-strip-enable-gradient true})
|
||||
|
||||
(defn- get-pointer-props
|
||||
[pointer-props]
|
||||
(let [pointer-index (.-pointerIndex ^js pointer-props)]
|
||||
(reset! inspecting? (not= pointer-index -1))))
|
||||
|
||||
(defn- get-line-color
|
||||
[state theme]
|
||||
(if @inspecting?
|
||||
[state theme inspecting?]
|
||||
(if inspecting?
|
||||
(colors/theme-colors colors/neutral-80-opa-40
|
||||
colors/white-opa-20
|
||||
theme)
|
||||
|
@ -51,11 +45,13 @@
|
|||
colors/danger-60
|
||||
theme))))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [data state customization-color theme reference-value reference-prefix decimal-separator]
|
||||
(defn view
|
||||
[{:keys [data state customization-color reference-value reference-prefix decimal-separator]
|
||||
:or {reference-prefix "$"
|
||||
decimal-separator :dot}}]
|
||||
(let [data (if (> (count data) max-data-points)
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[inspecting? set-inspecting] (rn/use-state false)
|
||||
data (if (> (count data) max-data-points)
|
||||
(utils/downsample-data data max-data-points)
|
||||
data)
|
||||
highest-value (utils/find-highest-value data)
|
||||
|
@ -64,7 +60,11 @@
|
|||
max-value (- (utils/calculate-rounded-max highest-value) min-value)
|
||||
step-value (/ max-value 4)
|
||||
width (:width (rn/get-window))
|
||||
line-color (get-line-color state theme)
|
||||
line-color (get-line-color state theme inspecting?)
|
||||
get-pointer-props (rn/use-callback
|
||||
(fn [pointer-props]
|
||||
(let [pointer-index (.-pointerIndex ^js pointer-props)]
|
||||
(set-inspecting (not= pointer-index -1)))))
|
||||
rules-color (colors/theme-colors colors/neutral-80-opa-10
|
||||
colors/white-opa-5
|
||||
theme)
|
||||
|
@ -119,7 +119,7 @@
|
|||
:show-strip-on-focus true
|
||||
:reference-line-1-config {:color rules-color}
|
||||
:reference-line-1-position 0
|
||||
:show-reference-line-2 (and (not @inspecting?)
|
||||
:show-reference-line-2 (and (not inspecting?)
|
||||
(<= reference-value highest-value)
|
||||
(>= reference-value lowest-value))
|
||||
:reference-line-2-config {:color y-axis-label-text-color
|
||||
|
@ -138,5 +138,3 @@
|
|||
:x-axis-label-text-style (style/x-axis-label-text (/ width (count x-axis-label-texts))
|
||||
y-axis-label-text-color)
|
||||
:x-axis-label-texts x-axis-label-texts}]]))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
(h/fire-event :on-focus (h/get-by-label-text :address-text-input))
|
||||
(h/has-prop (h/get-by-label-text :address-text-input)
|
||||
:placeholder-text-color
|
||||
colors/neutral-40)))
|
||||
colors/neutral-30)))
|
||||
|
||||
(h/test "on focus with blur? true"
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
|
@ -30,27 +30,22 @@
|
|||
(h/fire-event :on-focus (h/get-by-label-text :address-text-input))
|
||||
(h/has-prop (h/get-by-label-text :address-text-input)
|
||||
:placeholder-text-color
|
||||
colors/neutral-80-opa-40)))
|
||||
colors/neutral-80-opa-20)))
|
||||
|
||||
(h/test "scanned value is properly set"
|
||||
(let [on-change-text (h/mock-fn)
|
||||
scanned-value "scanned-value"]
|
||||
(h/test "default value is properly set"
|
||||
(let [default-value "default-value"]
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
(h/render [address-input/address-input
|
||||
{:scanned-value scanned-value
|
||||
:on-change-text on-change-text
|
||||
:ens-regex ens-regex}])
|
||||
(-> (h/wait-for #(h/get-by-label-text :clear-button))
|
||||
(.then (fn []
|
||||
(h/was-called-with on-change-text scanned-value)
|
||||
(h/has-prop (h/get-by-label-text :address-text-input)
|
||||
:default-value
|
||||
scanned-value)))))))
|
||||
{:default-value default-value
|
||||
:ens-regex ens-regex}])
|
||||
(h/has-prop (h/get-by-label-text :address-text-input)
|
||||
:value
|
||||
default-value))))
|
||||
|
||||
(h/test "clear icon is shown when input has text"
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
(h/render [address-input/address-input
|
||||
{:scanned-value "scanned value"
|
||||
{:default-value "default value"
|
||||
:ens-regex ens-regex}])
|
||||
(-> (h/wait-for #(h/get-by-label-text :clear-button-container))
|
||||
(.then #(h/is-truthy (h/get-by-label-text :clear-button))))))
|
||||
|
@ -58,7 +53,7 @@
|
|||
(h/test "on blur with text and blur? false"
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
(h/render [address-input/address-input
|
||||
{:scanned-value "scanned value"
|
||||
{:default-value "default value"
|
||||
:ens-regex ens-regex}])
|
||||
(-> (h/wait-for #(h/get-by-label-text :clear-button))
|
||||
(.then (fn []
|
||||
|
@ -71,7 +66,7 @@
|
|||
(h/test "on blur with text blur? true"
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
(h/render [address-input/address-input
|
||||
{:scanned-value "scanned value"
|
||||
{:default-value "default value"
|
||||
:blur? true
|
||||
:ens-regex ens-regex}])
|
||||
(-> (h/wait-for #(h/get-by-label-text :clear-button))
|
||||
|
@ -106,7 +101,7 @@
|
|||
(let [on-clear (h/mock-fn)]
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
(h/render [address-input/address-input
|
||||
{:scanned-value "scanned value"
|
||||
{:default-value "default value"
|
||||
:on-clear on-clear
|
||||
:ens-regex ens-regex}])
|
||||
(-> (h/wait-for #(h/get-by-label-text :clear-button))
|
||||
|
@ -148,7 +143,7 @@
|
|||
(-> (h/wait-for #(h/get-by-label-text :clear-button))
|
||||
(.then (fn []
|
||||
(h/has-prop (h/get-by-label-text :address-text-input)
|
||||
:default-value
|
||||
:value
|
||||
clipboard)))))))
|
||||
|
||||
(h/test "ENS loading state and call on-detect-ens"
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
[react-native.clipboard :as clipboard]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn- icon-color
|
||||
|
@ -55,124 +54,135 @@
|
|||
(and (not= status :default) (not blur?))
|
||||
(colors/theme-colors colors/neutral-30 colors/neutral-60 theme)))
|
||||
|
||||
(defn- f-address-input-internal
|
||||
[]
|
||||
(let [status (reagent/atom :default)
|
||||
value (reagent/atom "")
|
||||
focused? (atom false)]
|
||||
(fn [{:keys [scanned-value theme blur? on-change-text on-blur on-focus on-clear on-scan
|
||||
on-detect-ens on-detect-address on-detect-unclassified address-regex ens-regex
|
||||
valid-ens-or-address? container-style]}]
|
||||
(let [on-change (fn [text]
|
||||
(when (not= @value text)
|
||||
(let [address? (when address-regex
|
||||
(boolean (re-matches address-regex text)))
|
||||
ens? (when ens-regex
|
||||
(boolean (re-matches ens-regex text)))]
|
||||
(if (> (count text) 0)
|
||||
(reset! status :typing)
|
||||
(reset! status :active))
|
||||
(reset! value text)
|
||||
(when on-change-text
|
||||
(on-change-text text))
|
||||
(when (and on-detect-ens ens?)
|
||||
(reset! status :loading)
|
||||
(on-detect-ens text #(reset! status :typing)))
|
||||
(when (and address? on-detect-address)
|
||||
(reset! status :loading)
|
||||
(on-detect-address text))
|
||||
(when (and (not address?)
|
||||
(not ens?)
|
||||
on-detect-unclassified)
|
||||
(on-detect-unclassified text)))))
|
||||
on-paste (fn []
|
||||
(clipboard/get-string
|
||||
(fn [clipboard]
|
||||
(when-not (empty? clipboard)
|
||||
(on-change clipboard)
|
||||
(reset! value clipboard)))))
|
||||
on-clear (fn []
|
||||
(reset! value "")
|
||||
(reset! status (if @focused? :active :default))
|
||||
(when on-change-text
|
||||
(on-change-text ""))
|
||||
(when on-clear
|
||||
(on-clear)))
|
||||
on-scan #(when on-scan
|
||||
(on-scan))
|
||||
on-focus (fn []
|
||||
(when (= (count @value) 0)
|
||||
(reset! status :active))
|
||||
(reset! focused? true)
|
||||
(when on-focus (on-focus)))
|
||||
on-blur (fn []
|
||||
(when (= @status :active)
|
||||
(reset! status :default))
|
||||
(reset! focused? false)
|
||||
(when on-blur (on-blur)))
|
||||
placeholder-text-color (get-placeholder-text-color @status theme blur?)]
|
||||
(rn/use-effect (fn []
|
||||
(when-not (empty? scanned-value)
|
||||
(on-change scanned-value)))
|
||||
[scanned-value])
|
||||
[rn/view {:style (style/container container-style)}
|
||||
[rn/text-input
|
||||
{:accessibility-label :address-text-input
|
||||
:style (style/input-text theme)
|
||||
:placeholder (i18n/label :t/name-ens-or-address)
|
||||
:placeholder-text-color placeholder-text-color
|
||||
:default-value @value
|
||||
:auto-complete (when platform/ios? :off)
|
||||
:auto-capitalize :none
|
||||
:auto-correct false
|
||||
:spell-check false
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur
|
||||
:on-change-text on-change}]
|
||||
(when (or (= @status :default)
|
||||
(= @status :active))
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :paste-scan-buttons-container}
|
||||
[button/button
|
||||
{:accessibility-label :paste-button
|
||||
:type :outline
|
||||
:size 24
|
||||
:container-style {:margin-right 8}
|
||||
:inner-style (style/accessory-button blur? theme)
|
||||
:on-press on-paste}
|
||||
(i18n/label :t/paste)]
|
||||
[button/button
|
||||
{:accessibility-label :scan-button
|
||||
:icon-only? true
|
||||
:type :outline
|
||||
:size 24
|
||||
:inner-style (style/accessory-button blur? theme)
|
||||
:on-press on-scan}
|
||||
:main-icons/scan]])
|
||||
(when (= @status :typing)
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :clear-button-container}
|
||||
[clear-button
|
||||
{:on-press on-clear
|
||||
:blur? blur?
|
||||
:theme theme}]])
|
||||
(when (and (= @status :loading) (not valid-ens-or-address?))
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :loading-button-container}
|
||||
[loading-icon blur? theme]])
|
||||
(when (and (= @status :loading) valid-ens-or-address?)
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :positive-button-container}
|
||||
[positive-state-icon theme]])]))))
|
||||
|
||||
(defn address-input-internal
|
||||
[props]
|
||||
[:f> f-address-input-internal props])
|
||||
|
||||
(def address-input
|
||||
(quo.theme/with-theme address-input-internal))
|
||||
(defn address-input
|
||||
[{:keys [default-value blur? on-change-text on-blur on-focus on-clear on-scan
|
||||
on-detect-ens on-detect-address on-detect-unclassified address-regex ens-regex
|
||||
valid-ens-or-address? container-style]}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[status set-status] (rn/use-state :default)
|
||||
value (rn/use-ref-atom nil)
|
||||
[_ trigger-render-value] (rn/use-state @value)
|
||||
[focused? set-focused] (rn/use-state false)
|
||||
on-change (rn/use-callback
|
||||
(fn [text]
|
||||
(let [address? (when address-regex
|
||||
(boolean (re-matches address-regex text)))
|
||||
ens? (when ens-regex
|
||||
(boolean (re-matches ens-regex text)))]
|
||||
(reset! value text)
|
||||
(if (> (count text) 0)
|
||||
(set-status :typing)
|
||||
(set-status :active))
|
||||
(when on-change-text
|
||||
(on-change-text text))
|
||||
(when (and on-detect-ens ens?)
|
||||
(set-status :loading)
|
||||
(on-detect-ens text #(set-status :typing)))
|
||||
(when (and address? on-detect-address)
|
||||
(set-status :loading)
|
||||
(on-detect-address text))
|
||||
(when (and (not address?)
|
||||
(not ens?)
|
||||
on-detect-unclassified)
|
||||
(on-detect-unclassified text)))))
|
||||
set-value (rn/use-callback
|
||||
(fn [new-value]
|
||||
(reset! value new-value)
|
||||
(on-change new-value)
|
||||
(trigger-render-value new-value)))
|
||||
on-paste (rn/use-callback
|
||||
(fn []
|
||||
(clipboard/get-string
|
||||
(fn [clipboard]
|
||||
(when-not (empty? clipboard)
|
||||
(set-value clipboard))))))
|
||||
on-clear (rn/use-callback
|
||||
(fn []
|
||||
(set-value "")
|
||||
(set-status (if focused? :active :default))
|
||||
(when on-change-text
|
||||
(on-change-text ""))
|
||||
(when on-clear
|
||||
(on-clear)))
|
||||
[focused?])
|
||||
on-clear (rn/use-callback
|
||||
(fn []
|
||||
(set-value "")
|
||||
(set-status (if focused? :active :default))
|
||||
(when on-change-text
|
||||
(on-change-text ""))
|
||||
(when on-clear
|
||||
(on-clear)))
|
||||
[focused?])
|
||||
on-scan (when on-scan (rn/use-callback #(on-scan set-value)))
|
||||
on-focus (rn/use-callback
|
||||
(fn []
|
||||
(when (= (count @value) 0)
|
||||
(set-status :active))
|
||||
(set-focused true)
|
||||
(when on-focus (on-focus))))
|
||||
on-blur (rn/use-callback
|
||||
(fn []
|
||||
(when (= status :active)
|
||||
(set-status :default))
|
||||
(set-focused false)
|
||||
(when on-blur (on-blur)))
|
||||
[status])
|
||||
placeholder-text-color (rn/use-memo #(get-placeholder-text-color status theme blur?)
|
||||
[status theme blur?])]
|
||||
(rn/use-mount #(on-change (or default-value "")))
|
||||
[rn/view {:style (style/container container-style)}
|
||||
[rn/text-input
|
||||
{:accessibility-label :address-text-input
|
||||
:style (style/input-text theme)
|
||||
:placeholder (i18n/label :t/name-ens-or-address)
|
||||
:placeholder-text-color placeholder-text-color
|
||||
:value @value
|
||||
:auto-complete (when platform/ios? :off)
|
||||
:auto-capitalize :none
|
||||
:auto-correct false
|
||||
:spell-check false
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur
|
||||
:on-change-text on-change}]
|
||||
(when (or (= status :default)
|
||||
(= status :active))
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :paste-scan-buttons-container}
|
||||
[button/button
|
||||
{:accessibility-label :paste-button
|
||||
:type :outline
|
||||
:size 24
|
||||
:container-style {:margin-right 8}
|
||||
:inner-style (style/accessory-button blur? theme)
|
||||
:on-press on-paste}
|
||||
(i18n/label :t/paste)]
|
||||
(when on-scan
|
||||
[button/button
|
||||
{:accessibility-label :scan-button
|
||||
:icon-only? true
|
||||
:type :outline
|
||||
:size 24
|
||||
:inner-style (style/accessory-button blur? theme)
|
||||
:on-press on-scan}
|
||||
:main-icons/scan])])
|
||||
(when (= status :typing)
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :clear-button-container}
|
||||
[clear-button
|
||||
{:on-press on-clear
|
||||
:blur? blur?
|
||||
:theme theme}]])
|
||||
(when (and (= status :loading) (not valid-ens-or-address?))
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :loading-button-container}
|
||||
[loading-icon blur? theme]])
|
||||
(when (and (= status :loading) valid-ens-or-address?)
|
||||
[rn/view
|
||||
{:style style/buttons-container
|
||||
:accessibility-label :positive-button-container}
|
||||
[positive-state-icon theme]])]))
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
[quo.components.markdown.text :as text]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(defn- label-&-counter
|
||||
[{:keys [label current-chars char-limit variant-colors]}]
|
||||
|
@ -61,99 +60,104 @@
|
|||
:container-style])
|
||||
|
||||
(defn- base-input
|
||||
[{:keys [on-change-text on-char-limit-reach weight default-value]}]
|
||||
(let [status (reagent/atom :default)
|
||||
internal-on-focus #(reset! status :focus)
|
||||
internal-on-blur #(reset! status :default)
|
||||
multiple-lines? (reagent/atom false)
|
||||
set-multiple-lines! #(let [height (oops/oget % "nativeEvent.contentSize.height")
|
||||
;; In Android height comes with padding
|
||||
min-height (if platform/android? 40 22)]
|
||||
(if (> height min-height)
|
||||
(reset! multiple-lines? true)
|
||||
(reset! multiple-lines? false)))
|
||||
char-count (reagent/atom (count default-value))
|
||||
update-char-limit! (fn [new-text char-limit]
|
||||
(when on-change-text (on-change-text new-text))
|
||||
(let [amount-chars (count new-text)]
|
||||
(reset! char-count amount-chars)
|
||||
(when (and (>= amount-chars char-limit) on-char-limit-reach)
|
||||
(on-char-limit-reach amount-chars))))]
|
||||
(fn [{:keys [blur? theme error? right-icon left-icon disabled? small? button
|
||||
label char-limit multiline? clearable? on-focus on-blur container-style]
|
||||
:as props}]
|
||||
(let [status-kw (cond
|
||||
disabled? :disabled
|
||||
error? :error
|
||||
:else @status)
|
||||
colors-by-status (style/status-colors status-kw blur? theme)
|
||||
variant-colors (style/variants-colors blur? theme)
|
||||
clean-props (apply dissoc props custom-props)]
|
||||
[rn/view {:style container-style}
|
||||
(when (or label char-limit)
|
||||
[label-&-counter
|
||||
{:variant-colors variant-colors
|
||||
:label label
|
||||
:current-chars @char-count
|
||||
:char-limit char-limit}])
|
||||
[rn/view {:style (style/input-container colors-by-status small? disabled?)}
|
||||
(when-let [{:keys [icon-name]} left-icon]
|
||||
[left-accessory
|
||||
{:variant-colors variant-colors
|
||||
:small? small?
|
||||
:icon-name icon-name}])
|
||||
[rn/text-input
|
||||
(cond-> {:style (style/input colors-by-status small? @multiple-lines? weight)
|
||||
:accessibility-label :input
|
||||
:placeholder-text-color (:placeholder colors-by-status)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:cursor-color (:cursor variant-colors)
|
||||
:editable (not disabled?)
|
||||
:on-focus (fn []
|
||||
(when on-focus (on-focus))
|
||||
(internal-on-focus))
|
||||
:on-blur (fn []
|
||||
(when on-blur (on-blur))
|
||||
(internal-on-blur))}
|
||||
:always (merge clean-props)
|
||||
multiline? (assoc :multiline true
|
||||
:on-content-size-change set-multiple-lines!)
|
||||
char-limit (assoc :on-change-text #(update-char-limit! % char-limit)))]
|
||||
(when-let [{:keys [on-press icon-name style-fn]} right-icon]
|
||||
[right-accessory
|
||||
{:variant-colors variant-colors
|
||||
:small? small?
|
||||
:disabled? disabled?
|
||||
:icon-style-fn style-fn
|
||||
:icon-name icon-name
|
||||
:on-press (fn []
|
||||
(when clearable? (reset! char-count 0))
|
||||
(on-press))}])
|
||||
(when-let [{:keys [on-press text]} button]
|
||||
[right-button
|
||||
{:colors-by-status colors-by-status
|
||||
:variant-colors variant-colors
|
||||
:small? small?
|
||||
:disabled? disabled?
|
||||
:on-press on-press
|
||||
:text text}])]]))))
|
||||
[{:keys [blur? theme error? right-icon left-icon disabled? small? button
|
||||
label char-limit multiline? clearable? on-focus on-blur container-style
|
||||
on-change-text on-char-limit-reach weight default-value]
|
||||
:as props}]
|
||||
(let [[status set-status] (rn/use-state :default)
|
||||
internal-on-focus (rn/use-callback #(set-status :focus))
|
||||
internal-on-blur (rn/use-callback #(set-status :default))
|
||||
[multiple-lines?
|
||||
set-multiple-lines] (rn/use-state false)
|
||||
on-content-size-change (rn/use-callback
|
||||
(fn [event]
|
||||
(let [height (oops/oget event "nativeEvent.contentSize.height")
|
||||
;; In Android height comes with padding
|
||||
min-height (if platform/android? 40 22)]
|
||||
(if (> height min-height)
|
||||
(set-multiple-lines true)
|
||||
(set-multiple-lines false)))))
|
||||
[char-count
|
||||
set-char-count] (rn/use-state (count default-value))
|
||||
on-change-text (rn/use-callback
|
||||
(fn [new-text]
|
||||
(when on-change-text (on-change-text new-text))
|
||||
(let [amount-chars (count new-text)]
|
||||
(set-char-count amount-chars)
|
||||
(when (and (>= amount-chars char-limit) on-char-limit-reach)
|
||||
(on-char-limit-reach amount-chars)))))
|
||||
status-kw (cond
|
||||
disabled? :disabled
|
||||
error? :error
|
||||
:else status)
|
||||
colors-by-status (style/status-colors status-kw blur? theme)
|
||||
variant-colors (style/variants-colors blur? theme)
|
||||
clean-props (apply dissoc props custom-props)]
|
||||
[rn/view {:style container-style}
|
||||
(when (or label char-limit)
|
||||
[label-&-counter
|
||||
{:variant-colors variant-colors
|
||||
:label label
|
||||
:current-chars char-count
|
||||
:char-limit char-limit}])
|
||||
[rn/view {:style (style/input-container colors-by-status small? disabled?)}
|
||||
(when-let [{:keys [icon-name]} left-icon]
|
||||
[left-accessory
|
||||
{:variant-colors variant-colors
|
||||
:small? small?
|
||||
:icon-name icon-name}])
|
||||
[rn/text-input
|
||||
(cond-> {:style (style/input colors-by-status small? multiple-lines? weight)
|
||||
:accessibility-label :input
|
||||
:placeholder-text-color (:placeholder colors-by-status)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:cursor-color (:cursor variant-colors)
|
||||
:editable (not disabled?)
|
||||
:on-focus (fn []
|
||||
(when on-focus (on-focus))
|
||||
(internal-on-focus))
|
||||
:on-blur (fn []
|
||||
(when on-blur (on-blur))
|
||||
(internal-on-blur))}
|
||||
:always (merge clean-props)
|
||||
multiline? (assoc :multiline true
|
||||
:on-content-size-change on-content-size-change)
|
||||
char-limit (assoc :on-change-text on-change-text))]
|
||||
(when-let [{:keys [on-press icon-name style-fn]} right-icon]
|
||||
[right-accessory
|
||||
{:variant-colors variant-colors
|
||||
:small? small?
|
||||
:disabled? disabled?
|
||||
:icon-style-fn style-fn
|
||||
:icon-name icon-name
|
||||
:on-press (fn []
|
||||
(when clearable? (set-char-count 0))
|
||||
(on-press))}])
|
||||
(when-let [{:keys [on-press text]} button]
|
||||
[right-button
|
||||
{:colors-by-status colors-by-status
|
||||
:variant-colors variant-colors
|
||||
:small? small?
|
||||
:disabled? disabled?
|
||||
:on-press on-press
|
||||
:text text}])]]))
|
||||
|
||||
(defn- password-input
|
||||
[{:keys [default-shown?]
|
||||
:or {default-shown? false}}]
|
||||
(let [password-shown? (reagent/atom default-shown?)]
|
||||
(fn [props]
|
||||
[base-input
|
||||
(assoc props
|
||||
:accessibility-label :password-input
|
||||
:auto-capitalize :none
|
||||
:auto-complete :password
|
||||
:secure-text-entry (not @password-shown?)
|
||||
:right-icon {:style-fn style/password-icon
|
||||
:icon-name (if @password-shown? :i/hide-password :i/reveal)
|
||||
:on-press #(swap! password-shown? not)})])))
|
||||
:or {default-shown? false}
|
||||
:as props}]
|
||||
(let [[password-shown? set-password-shown] (rn/use-state default-shown?)]
|
||||
[base-input
|
||||
(assoc props
|
||||
:accessibility-label :password-input
|
||||
:auto-capitalize :none
|
||||
:auto-complete :password
|
||||
:secure-text-entry (not password-shown?)
|
||||
:right-icon {:style-fn style/password-icon
|
||||
:icon-name (if password-shown? :i/hide-password :i/reveal)
|
||||
:on-press #(set-password-shown (not password-shown?))})]))
|
||||
|
||||
(defn input-internal
|
||||
(defn input
|
||||
"This input supports the following properties:
|
||||
- :type - Can be `:text`(default) or `:password`.
|
||||
- :blur? - Boolean to set the blur color variant.
|
||||
|
@ -177,21 +181,15 @@
|
|||
- :on-change-text
|
||||
...
|
||||
"
|
||||
[{:keys [type clearable? on-clear on-change-text icon-name]
|
||||
[{:keys [type clearable? on-clear icon-name]
|
||||
:or {type :text}
|
||||
:as props}]
|
||||
(let [base-props (cond-> props
|
||||
icon-name (assoc-in [:left-icon :icon-name] icon-name)
|
||||
clearable? (assoc :right-icon
|
||||
{:style-fn style/clear-icon
|
||||
:icon-name :i/clear
|
||||
:on-press #(when on-clear (on-clear))})
|
||||
on-change-text (assoc :on-change-text
|
||||
(fn [new-text]
|
||||
(on-change-text new-text)
|
||||
(reagent/flush))))]
|
||||
icon-name (assoc-in [:left-icon :icon-name] icon-name)
|
||||
clearable? (assoc :right-icon
|
||||
{:style-fn style/clear-icon
|
||||
:icon-name :i/clear
|
||||
:on-press #(when on-clear (on-clear))}))]
|
||||
(if (= type :password)
|
||||
[password-input base-props]
|
||||
[base-input base-props])))
|
||||
|
||||
(def input (quo.theme/with-theme input-internal))
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
[clojure.string :as string]
|
||||
[quo.components.inputs.recovery-phrase.style :as style]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def ^:private custom-props
|
||||
[:customization-color :theme :blur? :cursor-color :multiline :on-focus :on-blur
|
||||
|
@ -38,42 +37,42 @@
|
|||
:idx 0})
|
||||
:result)))
|
||||
|
||||
(defn recovery-phrase-input-internal
|
||||
[_ _]
|
||||
(let [state (reagent/atom :default)
|
||||
set-focused #(reset! state :focused)
|
||||
set-default #(reset! state :default)]
|
||||
(fn [{:keys [customization-color theme blur? on-focus on-blur mark-errors?
|
||||
error-pred-current-word error-pred-written-words word-limit
|
||||
container-style]
|
||||
:or {customization-color :blue
|
||||
word-limit ##Inf
|
||||
error-pred-current-word (constantly false)
|
||||
error-pred-written-words (constantly false)}
|
||||
:as props}
|
||||
text]
|
||||
(let [extra-props (apply dissoc props custom-props)]
|
||||
[rn/view {:style (style/container container-style)}
|
||||
[rn/text-input
|
||||
(merge {:accessibility-label :recovery-phrase-input
|
||||
:style (style/input)
|
||||
:placeholder-text-color (style/placeholder-color @state theme blur?)
|
||||
:cursor-color (style/cursor-color customization-color theme)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:multiline true
|
||||
:on-focus (fn []
|
||||
(set-focused)
|
||||
(when on-focus (on-focus)))
|
||||
:on-blur (fn []
|
||||
(set-default)
|
||||
(when on-blur (on-blur)))}
|
||||
extra-props)
|
||||
(if mark-errors?
|
||||
(mark-error-words {:pred-last-word error-pred-current-word
|
||||
:pred-previous-words error-pred-written-words
|
||||
:text text
|
||||
:word-limit word-limit
|
||||
:theme theme})
|
||||
text)]]))))
|
||||
|
||||
(def recovery-phrase-input (quo.theme/with-theme recovery-phrase-input-internal))
|
||||
(defn recovery-phrase-input
|
||||
[{:keys [customization-color blur? on-focus on-blur mark-errors?
|
||||
error-pred-current-word error-pred-written-words word-limit
|
||||
container-style]
|
||||
:or {customization-color :blue
|
||||
word-limit ##Inf
|
||||
error-pred-current-word (constantly false)
|
||||
error-pred-written-words (constantly false)}
|
||||
:as props}
|
||||
text]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[state set-state] (rn/use-state :default)
|
||||
on-focus (rn/use-callback
|
||||
(fn []
|
||||
(set-state :focused)
|
||||
(when on-focus (on-focus))))
|
||||
on-blur (rn/use-callback
|
||||
(fn []
|
||||
(set-state :default)
|
||||
(when on-blur (on-blur))))
|
||||
extra-props (apply dissoc props custom-props)]
|
||||
[rn/view {:style (style/container container-style)}
|
||||
[rn/text-input
|
||||
(merge {:accessibility-label :recovery-phrase-input
|
||||
:style (style/input)
|
||||
:placeholder-text-color (style/placeholder-color state theme blur?)
|
||||
:cursor-color (style/cursor-color customization-color theme)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:multiline true
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur}
|
||||
extra-props)
|
||||
(if mark-errors?
|
||||
(mark-error-words {:pred-last-word error-pred-current-word
|
||||
:pred-previous-words error-pred-written-words
|
||||
:text text
|
||||
:word-limit word-limit
|
||||
:theme theme})
|
||||
text)]]))
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
[quo.components.icon :as icon]
|
||||
[quo.components.inputs.search-input.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def ^:private tag-separator [rn/view {:style style/tag-separator}])
|
||||
|
||||
|
@ -41,54 +40,52 @@
|
|||
text-input))
|
||||
|
||||
(defn search-input
|
||||
[{:keys [value]}]
|
||||
(let [state (reagent/atom :default)
|
||||
set-active #(reset! state :active)
|
||||
set-default #(reset! state :default)
|
||||
scroll-view-ref (atom nil)
|
||||
use-value? (boolean value)]
|
||||
(fn [{:keys [value tags disabled? blur? on-change-text customization-color
|
||||
on-clear on-focus on-blur override-theme container-style]
|
||||
:or {customization-color :blue}
|
||||
:as props}
|
||||
& children]
|
||||
(let [clean-props (apply dissoc props props-to-remove)]
|
||||
[rn/view
|
||||
{:accessibility-label :search-input
|
||||
:style (style/container container-style)}
|
||||
[rn/scroll-view
|
||||
{:ref #(reset! scroll-view-ref %)
|
||||
:style style/scroll-container
|
||||
:content-container-style style/scroll-content
|
||||
:horizontal true
|
||||
:shows-horizontal-scroll-indicator false}
|
||||
(when (seq tags)
|
||||
[inner-tags tags])
|
||||
|
||||
(add-children
|
||||
[rn/text-input
|
||||
(cond-> {:style (style/input-text disabled?)
|
||||
:cursor-color (style/cursor customization-color override-theme)
|
||||
:placeholder-text-color (style/placeholder-color @state blur? override-theme)
|
||||
:editable (not disabled?)
|
||||
:on-key-press #(handle-backspace % @scroll-view-ref)
|
||||
:keyboard-appearance (colors/theme-colors :light :dark override-theme)
|
||||
:on-change-text (fn [new-text]
|
||||
(when on-change-text
|
||||
(on-change-text new-text))
|
||||
(reagent/flush))
|
||||
:on-focus (fn []
|
||||
(set-active)
|
||||
(when on-focus (on-focus)))
|
||||
:on-blur (fn []
|
||||
(set-default)
|
||||
(when on-blur (on-blur)))}
|
||||
use-value? (assoc :value value)
|
||||
(seq clean-props) (merge clean-props))]
|
||||
(when-not use-value? children))]
|
||||
|
||||
(when (or (seq value) (seq children))
|
||||
[clear-button
|
||||
{:on-press on-clear
|
||||
:blur? blur?
|
||||
:override-theme override-theme}])]))))
|
||||
[{:keys [value tags disabled? blur? on-change-text customization-color
|
||||
on-clear on-focus on-blur override-theme container-style]
|
||||
:or {customization-color :blue}
|
||||
:as props}
|
||||
& children]
|
||||
(let [[state set-state] (rn/use-state :default)
|
||||
on-focus (rn/use-callback
|
||||
(fn []
|
||||
(set-state :active)
|
||||
(when on-focus (on-focus))))
|
||||
on-blur (rn/use-callback
|
||||
(fn []
|
||||
(set-state :default)
|
||||
(when on-blur (on-blur))))
|
||||
scroll-view-ref (rn/use-ref-atom nil)
|
||||
on-scroll-view-ref (rn/use-callback #(reset! scroll-view-ref %))
|
||||
on-key-press (rn/use-callback #(handle-backspace % @scroll-view-ref))
|
||||
use-value? (boolean value)
|
||||
clean-props (apply dissoc props props-to-remove)]
|
||||
[rn/view
|
||||
{:accessibility-label :search-input
|
||||
:style (style/container container-style)}
|
||||
[rn/scroll-view
|
||||
{:ref on-scroll-view-ref
|
||||
:style style/scroll-container
|
||||
:content-container-style style/scroll-content
|
||||
:horizontal true
|
||||
:shows-horizontal-scroll-indicator false}
|
||||
(when (seq tags)
|
||||
[inner-tags tags])
|
||||
(add-children
|
||||
[rn/text-input
|
||||
(cond-> {:style (style/input-text disabled?)
|
||||
:cursor-color (style/cursor customization-color override-theme)
|
||||
:placeholder-text-color (style/placeholder-color state blur? override-theme)
|
||||
:editable (not disabled?)
|
||||
:on-key-press on-key-press
|
||||
:keyboard-appearance (colors/theme-colors :light :dark override-theme)
|
||||
:on-change-text on-change-text
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur}
|
||||
use-value? (assoc :value value)
|
||||
(seq clean-props) (merge clean-props))]
|
||||
(when-not use-value? children))]
|
||||
(when (or (seq value) (seq children))
|
||||
[clear-button
|
||||
{:on-press on-clear
|
||||
:blur? blur?
|
||||
:override-theme override-theme}])]))
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
[quo.components.inputs.title-input.style :as style]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- pad-0
|
||||
[value]
|
||||
|
@ -13,81 +12,70 @@
|
|||
(str 0 value)
|
||||
value))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [blur?
|
||||
on-change-text
|
||||
auto-focus
|
||||
placeholder
|
||||
max-length
|
||||
default-value
|
||||
return-key-type
|
||||
size
|
||||
theme
|
||||
on-focus
|
||||
on-blur
|
||||
container-style]
|
||||
(defn view
|
||||
[{:keys [blur? on-change-text auto-focus placeholder max-length default-value return-key-type
|
||||
size on-focus on-blur container-style customization-color disabled?]
|
||||
:or {max-length 0
|
||||
auto-focus false
|
||||
default-value ""}}]
|
||||
(let [focused? (reagent/atom auto-focus)
|
||||
value (reagent/atom default-value)
|
||||
input-ref (atom nil)
|
||||
on-change (fn [v]
|
||||
(reset! value v)
|
||||
(when on-change-text
|
||||
(on-change-text v)))]
|
||||
(fn [{:keys [customization-color disabled?]}]
|
||||
[rn/view
|
||||
{:style (merge (style/container disabled?) container-style)}
|
||||
[rn/view {:style style/text-input-container}
|
||||
[rn/text-input
|
||||
{:style
|
||||
(text/text-style
|
||||
{:size (or size :heading-1)
|
||||
:weight :semi-bold
|
||||
:style (style/title-text theme)})
|
||||
:default-value default-value
|
||||
:accessibility-label :profile-title-input
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:return-key-type return-key-type
|
||||
:on-focus (fn []
|
||||
(when (fn? on-focus)
|
||||
(on-focus))
|
||||
(reset! focused? true))
|
||||
:on-blur (fn []
|
||||
(when (fn? on-blur)
|
||||
(on-blur))
|
||||
(reset! focused? false))
|
||||
:auto-focus auto-focus
|
||||
:input-mode :text
|
||||
:on-change-text on-change
|
||||
:editable (not disabled?)
|
||||
:max-length max-length
|
||||
:placeholder placeholder
|
||||
:ref #(reset! input-ref %)
|
||||
:selection-color (style/get-selection-color customization-color blur? theme)
|
||||
:placeholder-text-color (if @focused?
|
||||
(style/get-focused-placeholder-color blur? theme)
|
||||
(style/get-placeholder-color blur? theme))}]]
|
||||
[rn/view
|
||||
{:style (style/counter-container @focused?)}
|
||||
(if @focused?
|
||||
[text/text
|
||||
[text/text
|
||||
{:style (style/char-count blur? theme)
|
||||
:size :paragraph-2}
|
||||
(pad-0
|
||||
(str
|
||||
(count @value)))]
|
||||
[text/text
|
||||
{:style (style/char-count blur? theme)
|
||||
:size :paragraph-2}
|
||||
(str "/"
|
||||
(pad-0
|
||||
(str max-length)))]]
|
||||
[rn/pressable
|
||||
{:on-press #(when-not disabled?
|
||||
(.focus ^js @input-ref))}
|
||||
[icon/icon :i/edit {:color (style/get-char-count-color blur? theme)}]])]])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[focused? set-focused] (rn/use-state auto-focus)
|
||||
[value set-value] (rn/use-state default-value)
|
||||
input-ref (rn/use-ref-atom nil)
|
||||
on-inpur-ref (rn/use-callback #(reset! input-ref %))
|
||||
on-press (rn/use-callback
|
||||
#(when-not disabled? (.focus ^js @input-ref))
|
||||
[disabled?])
|
||||
on-change (rn/use-callback
|
||||
(fn [v]
|
||||
(set-value v)
|
||||
(when on-change-text (on-change-text v))))
|
||||
on-focus (rn/use-callback
|
||||
(fn []
|
||||
(when (fn? on-focus) (on-focus))
|
||||
(set-focused true)))
|
||||
on-blur (rn/use-callback
|
||||
(fn []
|
||||
(when (fn? on-blur) (on-blur))
|
||||
(set-focused false)))]
|
||||
[rn/view
|
||||
{:style (merge (style/container disabled?) container-style)}
|
||||
[rn/view {:style style/text-input-container}
|
||||
[rn/text-input
|
||||
{:style (text/text-style
|
||||
{:size (or size :heading-1)
|
||||
:weight :semi-bold
|
||||
:style (style/title-text theme)})
|
||||
:default-value default-value
|
||||
:accessibility-label :profile-title-input
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:return-key-type return-key-type
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur
|
||||
:auto-focus auto-focus
|
||||
:input-mode :text
|
||||
:on-change-text on-change
|
||||
:editable (not disabled?)
|
||||
:max-length max-length
|
||||
:placeholder placeholder
|
||||
:ref on-inpur-ref
|
||||
:selection-color (style/get-selection-color customization-color blur? theme)
|
||||
:placeholder-text-color (if focused?
|
||||
(style/get-focused-placeholder-color blur? theme)
|
||||
(style/get-placeholder-color blur? theme))}]]
|
||||
[rn/view
|
||||
{:style (style/counter-container focused?)}
|
||||
(if focused?
|
||||
[text/text
|
||||
[text/text
|
||||
{:style (style/char-count blur? theme)
|
||||
:size :paragraph-2}
|
||||
(pad-0
|
||||
(str
|
||||
(count value)))]
|
||||
[text/text
|
||||
{:style (style/char-count blur? theme)
|
||||
:size :paragraph-2}
|
||||
(str "/" (pad-0 (str max-length)))]]
|
||||
[rn/pressable {:on-press on-press}
|
||||
[icon/icon :i/edit {:color (style/get-char-count-color blur? theme)}]])]]))
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
:blur? (:blur? @state)
|
||||
:show-blur-background? true}
|
||||
[quo/address-input
|
||||
(merge @state
|
||||
{:on-scan #(js/alert "Not implemented yet")
|
||||
(merge (dissoc @state :scanned-value)
|
||||
{:on-scan (fn [on-result] (on-result (:scanned-value @state)))
|
||||
:ens-regex constants/regx-ens
|
||||
:on-detect-ens (fn [_]
|
||||
(swap! state assoc :valid-ens-or-address? false)
|
||||
|
|
|
@ -21,10 +21,14 @@
|
|||
(h/fire-event :change-text
|
||||
(h/get-by-label-text :add-address-to-watch)
|
||||
"0x12E838Ae1f769147b12956485dc56e57138f3AC8")
|
||||
(h/is-truthy (h/get-by-translation-text :t/address-already-in-use)))
|
||||
(-> (h/wait-for #(h/get-by-translation-text :t/address-already-in-use))
|
||||
(.then (fn []
|
||||
(h/is-truthy (h/get-by-translation-text :t/address-already-in-use))))))
|
||||
|
||||
(h/test "validation messages show for invalid address"
|
||||
(h/render [add-address-to-watch/view])
|
||||
(h/is-falsy (h/query-by-label-text :error-message))
|
||||
(h/fire-event :change-text (h/get-by-label-text :add-address-to-watch) "0x12E838Ae1f769147b")
|
||||
(h/is-truthy (h/get-by-translation-text :t/invalid-address))))
|
||||
(-> (h/wait-for #(h/get-by-translation-text :t/invalid-address))
|
||||
(.then (fn []
|
||||
(h/is-truthy (h/get-by-translation-text :t/invalid-address)))))))
|
||||
|
|
Loading…
Reference in New Issue