migrating to react state. step 1 (#18901)
This commit is contained in:
parent
acc6a3c072
commit
047e45d2a3
|
@ -6,8 +6,7 @@
|
|||
[quo.foundations.colors :as colors]
|
||||
[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 remove-http-https-www
|
||||
[value]
|
||||
|
@ -68,78 +67,86 @@
|
|||
[:cursor-color :placeholder-text-color :editable :on-change-text :on-focus
|
||||
:on-blur :on-clear :value :disabled? :blur? :customization-color :theme])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [default-value]
|
||||
:or {default-value ""}}]
|
||||
(let [state (reagent/atom :default)
|
||||
value (reagent/atom default-value)
|
||||
set-active #(reset! state :active)
|
||||
set-default #(reset! state :default)
|
||||
set-value #(reset! value %)
|
||||
ref (atom nil)
|
||||
clear-input (fn []
|
||||
(.clear ^js @ref)
|
||||
(reset! value ""))
|
||||
focus-input (fn []
|
||||
(set-active)
|
||||
(.focus ^js @ref))]
|
||||
(fn [{:keys [disabled? blur? on-change-text customization-color
|
||||
on-clear on-focus on-blur theme get-ref locked?
|
||||
favicon favicon-color favicon-size]
|
||||
:as props}]
|
||||
(let [clean-props (apply dissoc props props-to-remove)]
|
||||
[rn/view {:style style/root-container}
|
||||
(when (and (seq @value) (= @state :default))
|
||||
[rn/touchable-opacity
|
||||
{:style style/default-container
|
||||
:on-press focus-input}
|
||||
(when favicon
|
||||
[icon/icon favicon
|
||||
{:accessibility-label :browser-input-favicon
|
||||
:color favicon-color
|
||||
:container-style style/favicon-icon-container
|
||||
:size favicon-size}])
|
||||
[rn/text
|
||||
{:accessibility-label :browser-input-label
|
||||
:style (style/text)} (remove-http-https-www @value)]
|
||||
(when locked?
|
||||
[lock-icon
|
||||
{:blur? blur?
|
||||
:theme theme}])])
|
||||
[rn/view {:style (style/active-container (or (empty? @value) (= @state :active)))}
|
||||
[rn/text-input
|
||||
(merge
|
||||
clean-props
|
||||
{:accessibility-label :browser-input
|
||||
:auto-capitalize :none
|
||||
:auto-correct false
|
||||
:cursor-color (cursor-color customization-color theme)
|
||||
:editable (not disabled?)
|
||||
:keyboard-appearance (colors/theme-colors :light :dark theme)
|
||||
:keyboard-type :web-search
|
||||
:on-blur (fn []
|
||||
(set-default)
|
||||
(when on-blur (on-blur)))
|
||||
:on-change-text (fn [new-text]
|
||||
(set-value new-text)
|
||||
(when on-change-text (on-change-text new-text)))
|
||||
:on-focus (fn []
|
||||
(set-active)
|
||||
(when on-focus (on-focus)))
|
||||
:placeholder-text-color (placeholder-color @state blur? theme)
|
||||
:ref (fn [r]
|
||||
(reset! ref r)
|
||||
(when get-ref (get-ref r)))
|
||||
:selection-color (when platform/ios?
|
||||
(cursor-color customization-color theme))
|
||||
:select-text-on-focus true
|
||||
:style (style/input disabled?)})]
|
||||
(when (seq @value)
|
||||
[clear-button
|
||||
{:blur? blur?
|
||||
:on-press (fn []
|
||||
(clear-input)
|
||||
(when on-clear (on-clear)))
|
||||
:theme theme}])]]))))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
(defn view
|
||||
[{:keys [disabled? blur? on-change-text customization-color
|
||||
on-clear on-focus on-blur get-ref locked?
|
||||
favicon favicon-color favicon-size default-value]
|
||||
:or {default-value ""}
|
||||
:as props}]
|
||||
(let [ref (rn/use-ref-atom nil)
|
||||
on-ref (rn/use-callback
|
||||
(fn [r]
|
||||
(reset! ref r)
|
||||
(when get-ref (get-ref r)))
|
||||
[get-ref])
|
||||
theme (quo.theme/use-theme)
|
||||
[state set-state] (rn/use-state :default)
|
||||
[value set-value] (rn/use-state default-value)
|
||||
on-clear (rn/use-callback
|
||||
(fn []
|
||||
(.clear ^js @ref)
|
||||
(set-value "")
|
||||
(when on-clear (on-clear)))
|
||||
[on-clear])
|
||||
focus-input (rn/use-callback
|
||||
(fn []
|
||||
(set-state :active)
|
||||
(.focus ^js @ref)))
|
||||
on-blur (rn/use-callback
|
||||
(fn []
|
||||
(set-state :default)
|
||||
(when on-blur (on-blur)))
|
||||
[on-blur])
|
||||
on-change-text (rn/use-callback
|
||||
(fn [new-text]
|
||||
(set-value new-text)
|
||||
(when on-change-text (on-change-text new-text)))
|
||||
[on-change-text])
|
||||
on-focus (rn/use-callback
|
||||
(fn []
|
||||
(set-state :active)
|
||||
(when on-focus (on-focus)))
|
||||
[on-focus])
|
||||
clean-props (apply dissoc props props-to-remove)]
|
||||
[rn/view {:style style/root-container}
|
||||
(when (and (seq value) (= state :default))
|
||||
[rn/touchable-opacity
|
||||
{:style style/default-container
|
||||
:on-press focus-input}
|
||||
(when favicon
|
||||
[icon/icon favicon
|
||||
{:accessibility-label :browser-input-favicon
|
||||
:color favicon-color
|
||||
:container-style style/favicon-icon-container
|
||||
:size favicon-size}])
|
||||
[rn/text
|
||||
{:accessibility-label :browser-input-label
|
||||
:style (style/text)}
|
||||
(remove-http-https-www value)]
|
||||
(when locked?
|
||||
[lock-icon {:blur? blur? :theme theme}])])
|
||||
[rn/view {:style (style/active-container (or (empty? value) (= state :active)))}
|
||||
[rn/text-input
|
||||
(merge
|
||||
clean-props
|
||||
{:accessibility-label :browser-input
|
||||
:auto-capitalize :none
|
||||
:auto-correct false
|
||||
:cursor-color (cursor-color customization-color theme)
|
||||
:editable (not disabled?)
|
||||
:keyboard-appearance (colors/theme-colors :light :dark theme)
|
||||
:keyboard-type :web-search
|
||||
:on-blur on-blur
|
||||
:on-change-text on-change-text
|
||||
:on-focus on-focus
|
||||
:placeholder-text-color (placeholder-color state blur? theme)
|
||||
:ref on-ref
|
||||
:selection-color (when platform/ios?
|
||||
(cursor-color customization-color theme))
|
||||
:select-text-on-focus true
|
||||
:style (style/input disabled?)})]
|
||||
(when (seq value)
|
||||
[clear-button
|
||||
{:blur? blur?
|
||||
:on-press on-clear
|
||||
:theme theme}])]]))
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
[quo.foundations.customization-colors :as customization-colors]
|
||||
[quo.theme :as theme]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- button-internal
|
||||
(defn button
|
||||
"with label
|
||||
[button opts \"label\"]
|
||||
opts
|
||||
|
@ -29,102 +28,103 @@
|
|||
:theme :light/:dark
|
||||
only icon
|
||||
[button {:icon-only? true} :i/close-circle]"
|
||||
[_ _]
|
||||
(let [pressed-state? (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [on-press on-long-press disabled? type background size icon-left icon-right icon-top
|
||||
customization-color theme accessibility-label icon-only? container-style inner-style
|
||||
pressed? on-press-in on-press-out allow-multiple-presses?]
|
||||
:or {type :primary
|
||||
size 40
|
||||
customization-color (if (= type :primary) :blue nil)}}
|
||||
children]
|
||||
(let [{:keys [icon-color background-color label-color border-color blur-type
|
||||
blur-overlay-color border-radius overlay-customization-color]}
|
||||
(button-properties/get-values {:customization-color customization-color
|
||||
:background background
|
||||
:type type
|
||||
:theme theme
|
||||
:pressed? (if pressed? pressed? @pressed-state?)
|
||||
:icon-only? icon-only?})
|
||||
icon-size (when (= 24 size) 12)]
|
||||
[rn/touchable-without-feedback
|
||||
{:disabled disabled?
|
||||
:accessibility-label accessibility-label
|
||||
:on-press-in (fn []
|
||||
(reset! pressed-state? true)
|
||||
(when on-press-in (on-press-in)))
|
||||
:on-press-out (fn []
|
||||
(reset! pressed-state? nil)
|
||||
(when on-press-out (on-press-out)))
|
||||
:on-press on-press
|
||||
:allow-multiple-presses? allow-multiple-presses?
|
||||
:on-long-press on-long-press}
|
||||
[{:keys [on-press on-long-press disabled? type background size icon-left icon-right icon-top
|
||||
customization-color accessibility-label icon-only? container-style inner-style
|
||||
pressed? on-press-in on-press-out allow-multiple-presses?]
|
||||
:or {type :primary
|
||||
size 40
|
||||
customization-color (if (= type :primary) :blue nil)}}
|
||||
children]
|
||||
(let [[pressed-state? set-pressed-state] (rn/use-state false)
|
||||
theme (theme/use-theme-value)
|
||||
{:keys [icon-color background-color label-color border-color blur-type
|
||||
blur-overlay-color border-radius overlay-customization-color]}
|
||||
(button-properties/get-values {:customization-color customization-color
|
||||
:background background
|
||||
:type type
|
||||
:theme theme
|
||||
:pressed? (if pressed? pressed? pressed-state?)
|
||||
:icon-only? icon-only?})
|
||||
icon-size (when (= 24 size) 12)
|
||||
on-press-in-cb (rn/use-callback
|
||||
(fn []
|
||||
(set-pressed-state true)
|
||||
(when on-press-in (on-press-in))))
|
||||
on-press-out-cb (rn/use-callback
|
||||
(fn []
|
||||
(set-pressed-state nil)
|
||||
(when on-press-out (on-press-out))))]
|
||||
[rn/touchable-without-feedback
|
||||
{:disabled disabled?
|
||||
:accessibility-label accessibility-label
|
||||
:on-press-in on-press-in-cb
|
||||
:on-press-out on-press-out-cb
|
||||
:on-press on-press
|
||||
:allow-multiple-presses? allow-multiple-presses?
|
||||
:on-long-press on-long-press}
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(style/shape-style-container size border-radius)
|
||||
container-style)}
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(style/style-container {:size size
|
||||
:disabled? disabled?
|
||||
:border-radius border-radius
|
||||
:background-color background-color
|
||||
:border-color border-color
|
||||
:icon-only? icon-only?
|
||||
:icon-top icon-top
|
||||
:icon-left icon-left
|
||||
:icon-right icon-right})
|
||||
inner-style)}
|
||||
(when overlay-customization-color
|
||||
[customization-colors/overlay
|
||||
{:customization-color overlay-customization-color
|
||||
:theme theme
|
||||
:pressed? (if pressed? pressed? pressed-state?)}])
|
||||
(when (= background :photo)
|
||||
[blur/view
|
||||
{:blur-radius 20
|
||||
:blur-type blur-type
|
||||
:overlay-color blur-overlay-color
|
||||
:style style/blur-view}])
|
||||
(when icon-top
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(style/shape-style-container size border-radius)
|
||||
container-style)}
|
||||
[rn/view
|
||||
{:style (merge
|
||||
(style/style-container {:size size
|
||||
:disabled? disabled?
|
||||
:border-radius border-radius
|
||||
:background-color background-color
|
||||
:border-color border-color
|
||||
:icon-only? icon-only?
|
||||
:icon-top icon-top
|
||||
:icon-left icon-left
|
||||
:icon-right icon-right})
|
||||
inner-style)}
|
||||
(when overlay-customization-color
|
||||
[customization-colors/overlay
|
||||
{:customization-color overlay-customization-color
|
||||
:theme theme
|
||||
:pressed? (if pressed? pressed? @pressed-state?)}])
|
||||
(when (= background :photo)
|
||||
[blur/view
|
||||
{:blur-radius 20
|
||||
:blur-type blur-type
|
||||
:overlay-color blur-overlay-color
|
||||
:style style/blur-view}])
|
||||
(when icon-top
|
||||
[rn/view
|
||||
[quo.icons/icon icon-top
|
||||
{:container-style {:margin-bottom 2}
|
||||
:color icon-color
|
||||
:size icon-size}]])
|
||||
(when icon-left
|
||||
[rn/view
|
||||
{:style (style/icon-left-icon-style
|
||||
{:size size
|
||||
:icon-size icon-size})}
|
||||
[quo.icons/icon icon-left
|
||||
{:color icon-color
|
||||
:size icon-size}]])
|
||||
[rn/view
|
||||
(cond
|
||||
icon-only?
|
||||
[quo.icons/icon children
|
||||
{:color label-color
|
||||
:size icon-size}]
|
||||
[quo.icons/icon icon-top
|
||||
{:container-style {:margin-bottom 2}
|
||||
:color icon-color
|
||||
:size icon-size}]])
|
||||
(when icon-left
|
||||
[rn/view
|
||||
{:style (style/icon-left-icon-style
|
||||
{:size size
|
||||
:icon-size icon-size})}
|
||||
[quo.icons/icon icon-left
|
||||
{:color icon-color
|
||||
:size icon-size}]])
|
||||
[rn/view
|
||||
(cond
|
||||
icon-only?
|
||||
[quo.icons/icon children
|
||||
{:color label-color
|
||||
:size icon-size}]
|
||||
|
||||
(string? children)
|
||||
[text/text
|
||||
{:size (when (#{56 24} size) :paragraph-2)
|
||||
:weight :medium
|
||||
:number-of-lines 1
|
||||
:style {:color label-color}}
|
||||
children]
|
||||
(string? children)
|
||||
[text/text
|
||||
{:size (when (#{56 24} size) :paragraph-2)
|
||||
:weight :medium
|
||||
:number-of-lines 1
|
||||
:style {:color label-color}}
|
||||
children]
|
||||
|
||||
(vector? children)
|
||||
children)]
|
||||
(when icon-right
|
||||
[rn/view
|
||||
{:style (style/icon-right-icon-style
|
||||
{:size size
|
||||
:icon-size icon-size})}
|
||||
[quo.icons/icon icon-right
|
||||
{:color icon-color
|
||||
:size icon-size}]])]]]))))
|
||||
|
||||
(def button (theme/with-theme button-internal))
|
||||
(vector? children)
|
||||
children)]
|
||||
(when icon-right
|
||||
[rn/view
|
||||
{:style (style/icon-right-icon-style
|
||||
{:size size
|
||||
:icon-size icon-size})}
|
||||
[quo.icons/icon icon-right
|
||||
{:color icon-color
|
||||
:size icon-size}]])]]]))
|
||||
|
|
|
@ -3,28 +3,24 @@
|
|||
[quo.components.buttons.composer-button.style :as style]
|
||||
[quo.components.icon :as quo.icons]
|
||||
[quo.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- view-internal
|
||||
[_ _]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [on-press on-long-press disabled? theme blur? icon accessibility-label container-style]}]
|
||||
[rn/pressable
|
||||
{:accessibility-label (or accessibility-label :composer-button)
|
||||
:on-press on-press
|
||||
:on-press-in #(reset! pressed? true)
|
||||
:on-press-out #(reset! pressed? nil)
|
||||
:on-long-press on-long-press
|
||||
:disabled disabled?
|
||||
:style (merge (style/main {:pressed? @pressed?
|
||||
:blur? blur?
|
||||
:theme theme
|
||||
:disabled? disabled?})
|
||||
container-style)}
|
||||
[quo.icons/icon icon
|
||||
{:color (style/get-label-color {:blur? blur?
|
||||
:theme theme})}]])))
|
||||
|
||||
(def view (theme/with-theme view-internal))
|
||||
(defn view
|
||||
[{:keys [on-press on-long-press disabled? blur? icon accessibility-label container-style]}]
|
||||
(let [[pressed? set-pressed] (rn/use-state false)
|
||||
theme (theme/use-theme-value)
|
||||
on-press-in (rn/use-callback #(set-pressed true))
|
||||
on-press-out (rn/use-callback #(set-pressed nil))]
|
||||
[rn/pressable
|
||||
{:accessibility-label (or accessibility-label :composer-button)
|
||||
:on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out
|
||||
:on-long-press on-long-press
|
||||
:disabled disabled?
|
||||
:style (merge (style/main {:pressed? pressed?
|
||||
:blur? blur?
|
||||
:theme theme
|
||||
:disabled? disabled?})
|
||||
container-style)}
|
||||
[quo.icons/icon icon {:color (style/get-label-color {:blur? blur? :theme theme})}]]))
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
[quo.components.markdown.text :as text]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- get-button-color
|
||||
[{:keys [type pressed? customization-color theme]}]
|
||||
|
@ -45,48 +44,48 @@
|
|||
:color (get-icon-and-text-color type theme)
|
||||
:container-style (style/container type)}])
|
||||
|
||||
(defn- view-internal
|
||||
(defn view
|
||||
"[dynamic-button opts]
|
||||
opts
|
||||
{:type :jump-to/:mention/:notification-down/:notification-up/:search/:search-with-label/:scroll-to-bottom
|
||||
:on-press fn
|
||||
:count mentions or notifications count
|
||||
:customization-color customize jump-to and mention button color}"
|
||||
[_]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn [{:keys [type label on-press customization-color style theme] :as args}]
|
||||
[rn/touchable-opacity
|
||||
{:on-press-in #(reset! pressed? true)
|
||||
:on-press-out #(reset! pressed? false)
|
||||
:on-press on-press
|
||||
:active-opacity 1
|
||||
:hit-slop {:top 5 :bottom 5 :left 5 :right 5}
|
||||
:pointer-events :auto
|
||||
:style {:height 24}
|
||||
:accessibility-label type}
|
||||
[rn/view
|
||||
{:style (merge
|
||||
{:flex-direction :row
|
||||
:height 24
|
||||
:border-radius 12
|
||||
:background-color (get-button-color {:type type
|
||||
:pressed? @pressed?
|
||||
:customization-color (or customization-color
|
||||
:primary)
|
||||
:theme theme})}
|
||||
style)}
|
||||
(when (#{:mention :search :search-with-label :scroll-to-bottom} type)
|
||||
[icon-view type])
|
||||
(when (#{:jump-to :mention :notification-down :notification-up :search-with-label} type)
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (assoc (style/text type) :color (get-icon-and-text-color type theme))}
|
||||
(case type
|
||||
:jump-to label
|
||||
:search-with-label label
|
||||
(:mention :notification-down :notification-up) (str (:count args)))])
|
||||
(when (#{:jump-to :notification-down :notification-up} type)
|
||||
[icon-view type theme])]])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
[{:keys [type label on-press customization-color style] :as args}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[pressed? set-pressed] (rn/use-state false)
|
||||
button-color (get-button-color {:type type
|
||||
:pressed? pressed?
|
||||
:customization-color (or customization-color :primary)
|
||||
:theme theme})
|
||||
on-press-in (rn/use-callback #(set-pressed true))
|
||||
on-press-out (rn/use-callback #(set-pressed false))]
|
||||
[rn/touchable-opacity
|
||||
{:on-press-in on-press-in
|
||||
:on-press-out on-press-out
|
||||
:on-press on-press
|
||||
:active-opacity 1
|
||||
:hit-slop {:top 5 :bottom 5 :left 5 :right 5}
|
||||
:pointer-events :auto
|
||||
:style {:height 24}
|
||||
:accessibility-label type}
|
||||
[rn/view
|
||||
{:style (merge
|
||||
{:flex-direction :row
|
||||
:height 24
|
||||
:border-radius 12
|
||||
:background-color button-color}
|
||||
style)}
|
||||
(when (#{:mention :search :search-with-label :scroll-to-bottom} type)
|
||||
[icon-view type])
|
||||
(when (#{:jump-to :mention :notification-down :notification-up :search-with-label} type)
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (assoc (style/text type) :color (get-icon-and-text-color type theme))}
|
||||
(case type
|
||||
:jump-to label
|
||||
:search-with-label label
|
||||
(:mention :notification-down :notification-up) (str (:count args)))])
|
||||
(when (#{:jump-to :notification-down :notification-up} type)
|
||||
[icon-view type theme])]]))
|
||||
|
|
|
@ -6,29 +6,25 @@
|
|||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn- view-internal
|
||||
[_]
|
||||
(let [pressed? (reagent/atom false)
|
||||
on-press-in #(reset! pressed? true)
|
||||
on-press-out #(reset! pressed? nil)]
|
||||
(fn
|
||||
[{:keys [on-press on-long-press disabled? theme container-style]}]
|
||||
[rn/pressable
|
||||
{:accessibility-label :log-out-button
|
||||
:on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out
|
||||
:on-long-press on-long-press
|
||||
:disabled disabled?
|
||||
:style (merge (style/main {:pressed? @pressed?
|
||||
:theme theme
|
||||
:disabled? disabled?})
|
||||
container-style)}
|
||||
[icon/icon :i/log-out {:color (if pressed? colors/white-opa-40 colors/white-opa-70)}]
|
||||
[text/text {:weight :medium :size :paragraph-1}
|
||||
(i18n/label :t/logout)]])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
(defn view
|
||||
[{:keys [on-press on-long-press disabled? container-style]}]
|
||||
(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 nil))]
|
||||
[rn/pressable
|
||||
{:accessibility-label :log-out-button
|
||||
:on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out
|
||||
:on-long-press on-long-press
|
||||
:disabled disabled?
|
||||
:style (merge (style/main {:pressed? pressed?
|
||||
:theme theme
|
||||
:disabled? disabled?})
|
||||
container-style)}
|
||||
[icon/icon :i/log-out {:color (if pressed? colors/white-opa-40 colors/white-opa-70)}]
|
||||
[text/text {:weight :medium :size :paragraph-1}
|
||||
(i18n/label :t/logout)]]))
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
(ns quo.components.buttons.slide-button.animations
|
||||
(:require
|
||||
[oops.core :as oops]
|
||||
[quo.components.buttons.slide-button.utils :as utils]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
(:require [react-native.reanimated :as reanimated]))
|
||||
|
||||
(def ^:private extrapolation
|
||||
{:extrapolateLeft "clamp"
|
||||
|
@ -66,36 +62,6 @@
|
|||
:damping 30
|
||||
:stiffness 400}))
|
||||
|
||||
(defn- complete-animation
|
||||
[sliding-complete?]
|
||||
(reset! sliding-complete? true))
|
||||
|
||||
(defn reset-track-position
|
||||
[x-pos]
|
||||
(animate-spring x-pos 0))
|
||||
|
||||
;; Gestures
|
||||
(defn drag-gesture
|
||||
[x-pos
|
||||
gestures-disabled?
|
||||
disabled?
|
||||
track-width
|
||||
sliding-complete?]
|
||||
(let [gestures-enabled? (not (or disabled? @gestures-disabled?))]
|
||||
(-> (gesture/gesture-pan)
|
||||
(gesture/with-test-ID :slide-button-gestures)
|
||||
(gesture/enabled gestures-enabled?)
|
||||
(gesture/min-distance 0)
|
||||
(gesture/on-update (fn [event]
|
||||
(let [x-translation (oops/oget event "translationX")
|
||||
clamped-x (utils/clamp-value x-translation 0 track-width)
|
||||
reached-end? (>= clamped-x track-width)]
|
||||
(reanimated/set-shared-value x-pos clamped-x)
|
||||
(when (and reached-end? (not @sliding-complete?))
|
||||
(reset! gestures-disabled? true)
|
||||
(complete-animation sliding-complete?)))))
|
||||
(gesture/on-end (fn [event]
|
||||
(let [x-translation (oops/oget event "translationX")
|
||||
reached-end? (>= x-translation track-width)]
|
||||
(when (not reached-end?)
|
||||
(reset-track-position x-pos))))))))
|
||||
|
|
|
@ -11,94 +11,35 @@
|
|||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn- f-slider
|
||||
[{:keys [disabled?]}]
|
||||
(let [track-width (reagent/atom nil)
|
||||
sliding-complete? (reagent/atom false)
|
||||
gestures-disabled? (reagent/atom disabled?)
|
||||
on-track-layout (fn [evt]
|
||||
(let [width (oops/oget evt "nativeEvent.layout.width")]
|
||||
(reset! track-width width)))]
|
||||
(fn [{:keys [on-reset
|
||||
on-complete
|
||||
track-text
|
||||
track-icon
|
||||
disabled?
|
||||
customization-color
|
||||
size
|
||||
container-style
|
||||
theme
|
||||
type
|
||||
blur?]}]
|
||||
(let [x-pos (reanimated/use-shared-value 0)
|
||||
dimensions (partial utils/get-dimensions
|
||||
(or @track-width constants/default-width)
|
||||
size)
|
||||
interpolate-track (partial animations/interpolate-track
|
||||
x-pos
|
||||
(dimensions :usable-track)
|
||||
(dimensions :thumb))
|
||||
custom-color (if (= type :danger) :danger customization-color)]
|
||||
(rn/use-effect (fn []
|
||||
(when @sliding-complete?
|
||||
(on-complete)))
|
||||
[@sliding-complete?])
|
||||
(rn/use-effect (fn []
|
||||
(when on-reset
|
||||
(reset! sliding-complete? false)
|
||||
(reset! gestures-disabled? false)
|
||||
(animations/reset-track-position x-pos)
|
||||
(on-reset)))
|
||||
[on-reset])
|
||||
[gesture/gesture-detector
|
||||
{:gesture (animations/drag-gesture x-pos
|
||||
gestures-disabled?
|
||||
disabled?
|
||||
(dimensions :usable-track)
|
||||
sliding-complete?)}
|
||||
[reanimated/view
|
||||
{:test-ID :slide-button-track
|
||||
:style (merge (style/track {:disabled? disabled?
|
||||
:customization-color custom-color
|
||||
:height (dimensions :track-height)
|
||||
:blur? blur?})
|
||||
container-style)
|
||||
:on-layout (when-not (some? @track-width)
|
||||
on-track-layout)}
|
||||
[reanimated/view {:style (style/track-cover interpolate-track)}
|
||||
[rn/view {:style (style/track-cover-text-container @track-width)}
|
||||
[icon/icon track-icon
|
||||
{:color (utils/text-color custom-color theme blur?)
|
||||
:size 20}]
|
||||
[rn/view {:width 4}]
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-1
|
||||
:style (style/track-text custom-color theme blur?)}
|
||||
track-text]]]
|
||||
[reanimated/view
|
||||
{:style (style/thumb-container {:interpolate-track interpolate-track
|
||||
:thumb-size (dimensions :thumb)
|
||||
:customization-color custom-color
|
||||
:theme theme
|
||||
:blur? blur?})}
|
||||
[reanimated/view {:style (style/arrow-icon-container interpolate-track)}
|
||||
[icon/icon :arrow-right
|
||||
{:color colors/white
|
||||
:size 20}]]
|
||||
[reanimated/view
|
||||
{:style (style/action-icon interpolate-track
|
||||
(dimensions :thumb))}
|
||||
[icon/icon track-icon
|
||||
{:color colors/white
|
||||
:size 20}]]]]]))))
|
||||
(defn drag-gesture
|
||||
[x-pos gestures-disabled? set-gestures-disabled disabled? track-width sliding-complete?
|
||||
set-sliding-complete
|
||||
on-complete reset-fn]
|
||||
(let [gestures-enabled? (not (or disabled? gestures-disabled?))]
|
||||
(-> (gesture/gesture-pan)
|
||||
(gesture/with-test-ID :slide-button-gestures)
|
||||
(gesture/enabled gestures-enabled?)
|
||||
(gesture/min-distance 0)
|
||||
(gesture/on-update (fn [event]
|
||||
(let [x-translation (oops/oget event "translationX")
|
||||
clamped-x (utils/clamp-value x-translation 0 track-width)
|
||||
reached-end? (>= clamped-x track-width)]
|
||||
(reanimated/set-shared-value x-pos clamped-x)
|
||||
(when (and reached-end? (not sliding-complete?))
|
||||
(set-gestures-disabled true)
|
||||
(set-sliding-complete true)
|
||||
(when on-complete (on-complete reset-fn))))))
|
||||
(gesture/on-end (fn [event]
|
||||
(let [x-translation (oops/oget event "translationX")
|
||||
reached-end? (>= x-translation track-width)]
|
||||
(when (not reached-end?)
|
||||
(animations/reset-track-position x-pos))))))))
|
||||
|
||||
(defn- view-internal
|
||||
(defn view
|
||||
"Options
|
||||
- `on-complete` Callback called when the sliding is complete
|
||||
- `on-complete` Callback called when the sliding is complete, returns reset fn as a parameter
|
||||
- `disabled?` Boolean that disables the button
|
||||
(_and gestures_)
|
||||
- `size` :size/s-40`/`:size/s-48`
|
||||
|
@ -106,9 +47,78 @@
|
|||
- `track-icon` Key of the icon shown on the track
|
||||
(e.g. `:face-id`)
|
||||
- `customization-color` Customization color
|
||||
- `on-reset` A callback which can be used to reset the component and run required functionality
|
||||
"
|
||||
[props]
|
||||
[:f> f-slider props])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
[{:keys [on-complete track-text track-icon disabled? customization-color size
|
||||
container-style type blur?]}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
x-pos (reanimated/use-shared-value 0)
|
||||
[track-width set-track-width] (rn/use-state nil)
|
||||
[sliding-complete?
|
||||
set-sliding-complete] (rn/use-state false)
|
||||
[gestures-disabled?
|
||||
set-gestures-disabled] (rn/use-state disabled?)
|
||||
on-track-layout (rn/use-callback
|
||||
#(set-track-width (oops/oget % "nativeEvent.layout.width")))
|
||||
reset-fn (rn/use-callback
|
||||
(fn []
|
||||
(set-sliding-complete false)
|
||||
(set-gestures-disabled false)
|
||||
(animations/reset-track-position x-pos)))
|
||||
dimensions (rn/use-callback
|
||||
(partial utils/get-dimensions
|
||||
(or track-width constants/default-width)
|
||||
size)
|
||||
[track-width])
|
||||
interpolate-track (rn/use-callback
|
||||
(partial animations/interpolate-track
|
||||
x-pos
|
||||
(dimensions :usable-track)
|
||||
(dimensions :thumb))
|
||||
[dimensions])
|
||||
custom-color (if (= type :danger) :danger customization-color)
|
||||
gesture (rn/use-memo #(drag-gesture x-pos
|
||||
gestures-disabled?
|
||||
set-gestures-disabled
|
||||
disabled?
|
||||
(dimensions :usable-track)
|
||||
sliding-complete?
|
||||
set-sliding-complete
|
||||
on-complete
|
||||
reset-fn)
|
||||
[gestures-disabled? sliding-complete? disabled?])]
|
||||
[gesture/gesture-detector
|
||||
{:gesture gesture}
|
||||
[reanimated/view
|
||||
{:test-ID :slide-button-track
|
||||
:style (merge (style/track {:disabled? disabled?
|
||||
:customization-color custom-color
|
||||
:height (dimensions :track-height)
|
||||
:blur? blur?})
|
||||
container-style)
|
||||
:on-layout on-track-layout}
|
||||
[reanimated/view {:style (style/track-cover interpolate-track)}
|
||||
[rn/view {:style (style/track-cover-text-container track-width)}
|
||||
[icon/icon track-icon
|
||||
{:color (utils/text-color custom-color theme blur?)
|
||||
:size 20}]
|
||||
[rn/view {:width 4}]
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-1
|
||||
:style (style/track-text custom-color theme blur?)}
|
||||
track-text]]]
|
||||
[reanimated/view
|
||||
{:style (style/thumb-container {:interpolate-track interpolate-track
|
||||
:thumb-size (dimensions :thumb)
|
||||
:customization-color custom-color
|
||||
:theme theme
|
||||
:blur? blur?})}
|
||||
[reanimated/view {:style (style/arrow-icon-container interpolate-track)}
|
||||
[icon/icon :arrow-right
|
||||
{:color colors/white
|
||||
:size 20}]]
|
||||
[reanimated/view
|
||||
{:style (style/action-icon interpolate-track (dimensions :thumb))}
|
||||
[icon/icon track-icon
|
||||
{:color colors/white
|
||||
:size 20}]]]]]))
|
||||
|
|
|
@ -4,26 +4,24 @@
|
|||
[quo.components.icon :as quo.icons]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- view-internal
|
||||
[]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [on-press on-long-press disabled? icon accessibility-label container-style theme]}]
|
||||
[rn/pressable
|
||||
{:accessibility-label (or accessibility-label :wallet-button)
|
||||
:on-press on-press
|
||||
:on-press-in #(reset! pressed? true)
|
||||
:on-press-out #(reset! pressed? nil)
|
||||
:on-long-press on-long-press
|
||||
:disabled disabled?
|
||||
:style (merge (style/main {:pressed? @pressed?
|
||||
:theme theme
|
||||
:disabled? disabled?})
|
||||
container-style)}
|
||||
[quo.icons/icon icon
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white theme)}]])))
|
||||
|
||||
(def view (theme/with-theme view-internal))
|
||||
(defn view
|
||||
[{:keys [on-press on-long-press disabled? icon accessibility-label container-style]}]
|
||||
(let [theme (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 nil))]
|
||||
[rn/pressable
|
||||
{:accessibility-label (or accessibility-label :wallet-button)
|
||||
:on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out
|
||||
:on-long-press on-long-press
|
||||
:disabled disabled?
|
||||
:style (merge (style/main {:pressed? pressed?
|
||||
:theme theme
|
||||
:disabled? disabled?})
|
||||
container-style)}
|
||||
[quo.icons/icon icon
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white theme)}]]))
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
[react-native.gesture :as gesture]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.bottom-sheet.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -57,83 +56,77 @@
|
|||
(show translate-y bg-opacity)
|
||||
(hide translate-y bg-opacity window-height on-close))))))
|
||||
|
||||
(defn- f-view
|
||||
[_ _]
|
||||
(let [sheet-height (reagent/atom 0)
|
||||
item-height (reagent/atom 0)]
|
||||
(fn [{:keys [hide? insets theme]}
|
||||
{:keys [content selected-item padding-bottom-override border-radius on-close shell?
|
||||
gradient-cover? customization-color hide-handle? blur-radius]
|
||||
:or {border-radius 12}}]
|
||||
(let [{window-height :height} (rn/get-window)
|
||||
bg-opacity (reanimated/use-shared-value 0)
|
||||
translate-y (reanimated/use-shared-value window-height)
|
||||
sheet-gesture (get-sheet-gesture translate-y
|
||||
bg-opacity
|
||||
window-height
|
||||
on-close)
|
||||
selected-item-smaller-than-sheet? (< @item-height
|
||||
(- window-height
|
||||
@sheet-height
|
||||
(:top insets)
|
||||
(:bottom insets)
|
||||
bottom-margin))
|
||||
top (- window-height (:top insets) @sheet-height)
|
||||
bottom (if selected-item-smaller-than-sheet?
|
||||
(+ @sheet-height bottom-margin)
|
||||
(:bottom insets))]
|
||||
(rn/use-effect
|
||||
#(if hide?
|
||||
(hide translate-y bg-opacity window-height on-close)
|
||||
(show translate-y bg-opacity))
|
||||
[hide?])
|
||||
(hooks/use-back-handler (fn []
|
||||
(when (fn? on-close)
|
||||
(on-close))
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
true))
|
||||
[rn/view {:style {:flex 1}}
|
||||
;; backdrop
|
||||
[rn/pressable
|
||||
{:on-press #(rf/dispatch [:hide-bottom-sheet])
|
||||
:style {:flex 1}}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity bg-opacity}
|
||||
{:flex 1 :background-color colors/neutral-100-opa-70})}]]
|
||||
;; sheet
|
||||
[gesture/gesture-detector {:gesture sheet-gesture}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
(style/sheet insets window-height selected-item))}
|
||||
(when shell?
|
||||
[blur/ios-view
|
||||
{:style style/shell-bg
|
||||
:blur-radius (or blur-radius 20)
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent}])
|
||||
(when selected-item
|
||||
[rn/view
|
||||
{:on-layout #(reset! item-height (.-nativeEvent.layout.height ^js %))
|
||||
:style
|
||||
(style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
|
||||
[selected-item]])
|
||||
(defn view
|
||||
[{:keys [hide? insets]}
|
||||
{:keys [content selected-item padding-bottom-override border-radius on-close shell?
|
||||
gradient-cover? customization-color hide-handle? blur-radius]
|
||||
:or {border-radius 12}}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
sheet-height (rn/use-ref-atom 0)
|
||||
item-height (rn/use-ref-atom 0)
|
||||
{window-height :height} (rn/get-window)
|
||||
bg-opacity (reanimated/use-shared-value 0)
|
||||
translate-y (reanimated/use-shared-value window-height)
|
||||
sheet-gesture (get-sheet-gesture translate-y
|
||||
bg-opacity
|
||||
window-height
|
||||
on-close)
|
||||
selected-item-smaller-than-sheet? (< @item-height
|
||||
(- window-height
|
||||
@sheet-height
|
||||
(:top insets)
|
||||
(:bottom insets)
|
||||
bottom-margin))
|
||||
top (- window-height (:top insets) @sheet-height)
|
||||
bottom (if selected-item-smaller-than-sheet?
|
||||
(+ @sheet-height bottom-margin)
|
||||
(:bottom insets))]
|
||||
(rn/use-effect
|
||||
#(if hide?
|
||||
(hide translate-y bg-opacity window-height on-close)
|
||||
(show translate-y bg-opacity))
|
||||
[hide?])
|
||||
(hooks/use-back-handler (fn []
|
||||
(when (fn? on-close)
|
||||
(on-close))
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
true))
|
||||
[rn/view {:style {:flex 1}}
|
||||
;; backdrop
|
||||
[rn/pressable
|
||||
{:on-press #(rf/dispatch [:hide-bottom-sheet])
|
||||
:style {:flex 1}}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity bg-opacity}
|
||||
{:flex 1 :background-color colors/neutral-100-opa-70})}]]
|
||||
;; sheet
|
||||
[gesture/gesture-detector {:gesture sheet-gesture}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
(style/sheet insets window-height selected-item))}
|
||||
(when shell?
|
||||
[blur/ios-view
|
||||
{:style style/shell-bg
|
||||
:blur-radius (or blur-radius 20)
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent}])
|
||||
(when selected-item
|
||||
[rn/view
|
||||
{:on-layout #(reset! item-height (.-nativeEvent.layout.height ^js %))
|
||||
:style
|
||||
(style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
|
||||
[selected-item]])
|
||||
|
||||
[rn/view
|
||||
{:style (style/sheet-content theme padding-bottom-override insets shell? bottom-margin)
|
||||
:on-layout #(reset! sheet-height (.-nativeEvent.layout.height ^js %))}
|
||||
(when (and gradient-cover? customization-color)
|
||||
[rn/view {:style style/gradient-bg}
|
||||
[quo/gradient-cover
|
||||
{:customization-color customization-color
|
||||
:opacity 0.4}]])
|
||||
(when-not hide-handle?
|
||||
[quo/drawer-bar])
|
||||
[content]]]]]))))
|
||||
|
||||
(defn- internal-view
|
||||
[args sheet]
|
||||
[:f> f-view args sheet])
|
||||
|
||||
(def view (quo.theme/with-theme internal-view))
|
||||
[rn/view
|
||||
{:style (style/sheet-content theme padding-bottom-override insets shell? bottom-margin)
|
||||
:on-layout #(reset! sheet-height (.-nativeEvent.layout.height ^js %))}
|
||||
(when (and gradient-cover? customization-color)
|
||||
[rn/view {:style style/gradient-bg}
|
||||
[quo/gradient-cover
|
||||
{:customization-color customization-color
|
||||
:opacity 0.4}]])
|
||||
(when-not hide-handle?
|
||||
[quo/drawer-bar])
|
||||
[content]]]]]))
|
||||
|
|
|
@ -3,45 +3,32 @@
|
|||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.standard-authentication.standard-auth.authorize :as authorize]
|
||||
[status-im.constants :as constants]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- view-internal
|
||||
[_]
|
||||
(let [reset-slider? (reagent/atom false)
|
||||
on-close (fn []
|
||||
(js/setTimeout
|
||||
#(reset! reset-slider? true)
|
||||
200))
|
||||
(defn view
|
||||
[{:keys [track-text customization-color auth-button-label on-auth-success on-auth-fail
|
||||
auth-button-icon-left size blur? container-style]
|
||||
:or {container-style {:flex 1}}}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
auth-method (rf/sub [:auth-method])
|
||||
biometric-auth? (= auth-method constants/auth-method-biometric)]
|
||||
(fn [{:keys [track-text
|
||||
customization-color
|
||||
auth-button-label
|
||||
on-auth-success
|
||||
on-auth-fail
|
||||
auth-button-icon-left
|
||||
size
|
||||
theme
|
||||
blur?
|
||||
container-style]
|
||||
:or {container-style {:flex 1}}}]
|
||||
[rn/view {:style container-style}
|
||||
[quo/slide-button
|
||||
{:size size
|
||||
:customization-color customization-color
|
||||
:on-reset (when @reset-slider? #(reset! reset-slider? false))
|
||||
:on-complete #(authorize/authorize {:on-close on-close
|
||||
:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
:auth-button-label auth-button-label})
|
||||
:track-icon (if biometric-auth? :i/face-id :password)
|
||||
:track-text track-text}]])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
biometric-auth? (= auth-method constants/auth-method-biometric)
|
||||
on-complete (rn/use-callback
|
||||
(fn [reset]
|
||||
(authorize/authorize {:on-close #(js/setTimeout reset 200)
|
||||
:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
:auth-button-label auth-button-label}))
|
||||
[theme])]
|
||||
[quo/slide-button
|
||||
{:container-style container-style
|
||||
:size size
|
||||
:customization-color customization-color
|
||||
:on-complete on-complete
|
||||
:track-icon (if biometric-auth? :i/face-id :password)
|
||||
:track-text track-text}]))
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
:disabled? (:disabled? @state)
|
||||
:blur? @blur?
|
||||
:type (:type @state)
|
||||
:on-complete (fn []
|
||||
:on-complete (fn [_]
|
||||
(js/setTimeout (fn [] (reset! complete? true))
|
||||
1000)
|
||||
(js/alert "I don't wanna slide anymore"))}]
|
||||
|
|
Loading…
Reference in New Issue