From e676b3dab480b9c211e6977bdf2782e7c2416512 Mon Sep 17 00:00:00 2001 From: Ulises M Date: Wed, 19 Apr 2023 19:08:36 -0600 Subject: [PATCH] Create recovery-phrase input --- .../recovery_phrase/component_spec.cljs | 8 ++ .../inputs/recovery_phrase/style.cljs | 45 +++++++++++ .../inputs/recovery_phrase/view.cljs | 54 +++++++++++++ src/quo2/core.cljs | 4 +- src/quo2/core_spec.cljs | 1 + .../inputs/recovery_phrase_input.cljs | 76 +++++++++++++++++++ src/status_im2/contexts/quo_preview/main.cljs | 4 + 7 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 src/quo2/components/inputs/recovery_phrase/component_spec.cljs create mode 100644 src/quo2/components/inputs/recovery_phrase/style.cljs create mode 100644 src/quo2/components/inputs/recovery_phrase/view.cljs create mode 100644 src/status_im2/contexts/quo_preview/inputs/recovery_phrase_input.cljs diff --git a/src/quo2/components/inputs/recovery_phrase/component_spec.cljs b/src/quo2/components/inputs/recovery_phrase/component_spec.cljs new file mode 100644 index 0000000000..15de0749fd --- /dev/null +++ b/src/quo2/components/inputs/recovery_phrase/component_spec.cljs @@ -0,0 +1,8 @@ +(ns quo2.components.inputs.recovery-phrase.component-spec + (:require [quo2.components.inputs.recovery-phrase.view :as recovery-phrase] + [test-helpers.component :as h])) + +(h/describe "Recovery phrase input" + (h/test "Default render" + (h/render [recovery-phrase/recovery-phrase-input {}]) + (h/is-truthy (h/get-by-label-text :recovery-phrase-input)))) diff --git a/src/quo2/components/inputs/recovery_phrase/style.cljs b/src/quo2/components/inputs/recovery_phrase/style.cljs new file mode 100644 index 0000000000..6110337f7a --- /dev/null +++ b/src/quo2/components/inputs/recovery_phrase/style.cljs @@ -0,0 +1,45 @@ +(ns quo2.components.inputs.recovery-phrase.style + (:require [quo2.components.markdown.text :as text] + [quo2.foundations.colors :as colors])) + +(def container + {:min-height 40 + :flex 1 + :padding-vertical 4 + :padding-horizontal 20}) + +(defn input + [] + (assoc (text/text-style {}) + :height 32 + :flex-grow 1 + :padding-vertical 5 + :text-align-vertical :top)) + +(defn placeholder-color + [input-state override-theme blur?] + (cond + (and (= input-state :focused) blur?) + (colors/theme-colors colors/neutral-80-opa-20 colors/white-opa-20 override-theme) + + (= input-state :focused) ; Not blur + (colors/theme-colors colors/neutral-30 colors/neutral-60 override-theme) + + blur? ; :default & blur + (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-30 override-theme) + + :else ; :default & not blur + (colors/theme-colors colors/neutral-40 colors/neutral-50 override-theme))) + +(defn cursor-color + [customization-color override-theme] + (colors/theme-colors (colors/custom-color customization-color 50) + (colors/custom-color customization-color 60) + override-theme)) + +(defn error-word + [] + {:height 22 + :padding-horizontal 20 + :background-color colors/danger-50-opa-10 + :color (colors/theme-colors colors/danger-50 colors/danger-60)}) diff --git a/src/quo2/components/inputs/recovery_phrase/view.cljs b/src/quo2/components/inputs/recovery_phrase/view.cljs new file mode 100644 index 0000000000..b7c725de89 --- /dev/null +++ b/src/quo2/components/inputs/recovery_phrase/view.cljs @@ -0,0 +1,54 @@ +(ns quo2.components.inputs.recovery-phrase.view + (:require [clojure.string :as string] + [quo2.components.inputs.recovery-phrase.style :as style] + [react-native.core :as rn] + [reagent.core :as reagent])) + +(def ^:private custom-props + [:customization-color :override-theme :blur? :cursor-color :multiline :on-focus :on-blur + :placeholder-text-color :mark-errors? :error-pred :word-limit]) + +(defn- error-word + [text] + [rn/text {:style (style/error-word)} + text]) + +(defn- mark-error-words + [pred text word-limit] + (let [word-limit (or word-limit ##Inf)] + (into [:<>] + (comp (map-indexed (fn [idx word] + (if (or (pred word) (>= idx word-limit)) + [error-word word] + word))) + (interpose " ")) + (string/split text #" ")))) + +(defn recovery-phrase-input + [_ _] + (let [state (reagent/atom :default) + set-focused #(reset! state :focused) + set-default #(reset! state :default)] + (fn [{:keys [customization-color override-theme blur? on-focus on-blur mark-errors? + error-pred word-limit] + :or {customization-color :blue} + :as props} + text] + (let [extra-props (apply dissoc props custom-props)] + [rn/view {:style style/container} + [rn/text-input + (merge {:accessibility-label :recovery-phrase-input + :style (style/input) + :placeholder-text-color (style/placeholder-color @state override-theme blur?) + :cursor-color (style/cursor-color customization-color override-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 error-pred text word-limit) + text)]])))) diff --git a/src/quo2/core.cljs b/src/quo2/core.cljs index 883816f0d4..43a942d93c 100644 --- a/src/quo2/core.cljs +++ b/src/quo2/core.cljs @@ -33,6 +33,7 @@ quo2.components.info.information-box quo2.components.inputs.input.view quo2.components.inputs.profile-input.view + quo2.components.inputs.recovery-phrase.view quo2.components.inputs.search-input.view quo2.components.inputs.title-input.view quo2.components.links.url-preview-list.view @@ -154,8 +155,9 @@ ;;;; INPUTS (def input quo2.components.inputs.input.view/input) -(def search-input quo2.components.inputs.search-input.view/search-input) (def profile-input quo2.components.inputs.profile-input.view/profile-input) +(def recovery-phrase-input quo2.components.inputs.recovery-phrase.view/recovery-phrase-input) +(def search-input quo2.components.inputs.search-input.view/search-input) (def title-input quo2.components.inputs.title-input.view/title-input) ;;;; LIST ITEMS diff --git a/src/quo2/core_spec.cljs b/src/quo2/core_spec.cljs index 617e51f564..ba3d96d850 100644 --- a/src/quo2/core_spec.cljs +++ b/src/quo2/core_spec.cljs @@ -13,6 +13,7 @@ [quo2.components.drawers.permission-context.component-spec] [quo2.components.inputs.input.component-spec] [quo2.components.inputs.profile-input.component-spec] + [quo2.components.inputs.recovery-phrase.component-spec] [quo2.components.inputs.title-input.component-spec] [quo2.components.links.url-preview-list.component-spec] [quo2.components.links.url-preview.component-spec] diff --git a/src/status_im2/contexts/quo_preview/inputs/recovery_phrase_input.cljs b/src/status_im2/contexts/quo_preview/inputs/recovery_phrase_input.cljs new file mode 100644 index 0000000000..0226627a05 --- /dev/null +++ b/src/status_im2/contexts/quo_preview/inputs/recovery_phrase_input.cljs @@ -0,0 +1,76 @@ +(ns status-im2.contexts.quo-preview.inputs.recovery-phrase-input + (:require [quo2.core :as quo] + [quo2.foundations.colors :as colors] + [react-native.core :as rn] + [reagent.core :as reagent] + [status-im2.contexts.quo-preview.preview :as preview])) + +(def descriptor + [{:label "Text" + :key :text + :type :text} + {:label "Placeholder" + :key :placeholder + :type :text} + {:label "Blur" + :key :blur? + :type :boolean} + {:label "Mark errors" + :key :mark-errors? + :type :boolean} + {:label "Customization color" + :key :customization-color + :type :select + :options (map (fn [[color _]] + {:key color :value (name color)}) + colors/customization)} + {:label "Word limit" + :key :word-limit + :type :select + :options [{:key nil :value "No limit"} + {:key 5 :value "5 words"} + {:key 10 :value "10 words"} + {:key 20 :value "20 words"}]}]) + +(defn cool-preview + [] + (let [state (reagent/atom {:text "" + :placeholder "Type or paste your recovery phrase" + :customization-color :blue + :word-limit 20 + :mark-errors? true})] + (fn [] + [rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} + [rn/view {:style {:padding-bottom 150}} + [rn/view {:style {:flex 1}} + [preview/customizer state descriptor] + [quo/text {:size :paragraph-2} + "(Any word with at least 6 chars is marked as error)"]] + [preview/blur-view + {:style {:align-items :center + :margin-vertical 20 + :width "100%"} + :height 200 + :show-blur-background? (:blur? @state)} + [rn/view + {:style {:height 150 + :width "100%"}} + [quo/recovery-phrase-input + {:mark-errors? (:mark-errors? @state) + :error-pred #(> (count %) 5) + :on-change-text #(swap! state assoc :text %) + :placeholder (:placeholder @state) + :customization-color (:customization-color @state) + :word-limit (:word-limit @state)} + (:text @state)]]]]]))) + +(defn preview-recovery-phrase-input + [] + [rn/view + {:style {:background-color (colors/theme-colors colors/white colors/neutral-95) + :flex 1}} + [rn/flat-list + {:style {:flex 1} + :keyboardShouldPersistTaps :always + :header [cool-preview] + :key-fn str}]]) diff --git a/src/status_im2/contexts/quo_preview/main.cljs b/src/status_im2/contexts/quo_preview/main.cljs index 08be11e78d..7313d63bdc 100644 --- a/src/status_im2/contexts/quo_preview/main.cljs +++ b/src/status_im2/contexts/quo_preview/main.cljs @@ -39,6 +39,7 @@ [status-im2.contexts.quo-preview.info.info-message :as info-message] [status-im2.contexts.quo-preview.info.information-box :as information-box] [status-im2.contexts.quo-preview.inputs.input :as input] + [status-im2.contexts.quo-preview.inputs.recovery-phrase-input :as recovery-phrase-input] [status-im2.contexts.quo-preview.inputs.profile-input :as profile-input] [status-im2.contexts.quo-preview.inputs.search-input :as search-input] [status-im2.contexts.quo-preview.inputs.title-input :as title-input] @@ -185,6 +186,9 @@ {:name :profile-input :insets {:top false} :component profile-input/preview-profile-input} + {:name :recovery-phrase-input + :insets {:top false} + :component recovery-phrase-input/preview-recovery-phrase-input} {:name :search-input :insets {:top false} :component search-input/preview-search-input}