Implement dropdown component and update it's usage across the codebase (#17412)

This commit: 

- Removes the existing dropdown component which uses the old button component under the hood
- Implements the Dropdown component
- Updates the usage in the page-nav component for types dropdown, token and wallet-networks
- Updates the usage in the photo selector bottom sheet
- Updates the usage in the Quo2 preview main screen

---------

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
This commit is contained in:
Mohamed Javid 2023-09-29 20:07:27 +08:00 committed by GitHub
parent af1942dff3
commit bf76ca167a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 540 additions and 545 deletions

View File

@ -1,6 +1,8 @@
(ns quo2.components.buttons.button.properties (ns quo2.components.buttons.button.properties
(:require [quo2.foundations.colors :as colors])) (:require [quo2.foundations.colors :as colors]))
(def backgrounds #{:photo :blur})
(defn custom-color-type (defn custom-color-type
[customization-color icon-only?] [customization-color icon-only?]
{:icon-color colors/white-opa-70 {:icon-color colors/white-opa-70

View File

@ -1,20 +0,0 @@
(ns quo2.components.dropdowns.dropdown
(:require [quo2.components.dropdowns.old-button-view :as old-button]))
(defn dropdown
[_ _]
(fn [{:keys [on-change selected] :as opts} children]
;TODO: Dropdown needs to be implemented/refactored to be its own component -
;https://github.com/status-im/status-mobile/issues/16456
[old-button/button
(merge
opts
{:after (if selected :i/chevron-top :i/chevron-down)
:icon-size 12
:icon-container-size 14
:icon-container-rounded? true
:override-after-margins {:left 7
:right 9}
:pressed selected
:on-press #(when on-change (on-change selected))})
children]))

View File

@ -0,0 +1,35 @@
(ns quo2.components.dropdowns.dropdown.component-spec
(:require [quo2.components.dropdowns.dropdown.view :as dropdown]
[test-helpers.component :as h]))
(h/describe "Dropdown"
(h/test "default render"
(let [label "Recent"]
(h/render [dropdown/view {} label])
(h/is-truthy (h/get-by-label-text :dropdown))
(h/is-null (h/query-by-label-text :left-icon))
(h/is-truthy (h/get-by-text label))
(h/is-truthy (h/get-by-label-text :right-icon))))
(h/test "render with icon"
(let [label "Recent"]
(h/render [dropdown/view {:icon? true} label])
(h/is-truthy (h/get-by-label-text :dropdown))
(h/is-truthy (h/get-by-label-text :left-icon))
(h/is-truthy (h/get-by-text label))
(h/is-truthy (h/get-by-label-text :right-icon))))
(h/test "render only emoji"
(let [label "🍑"]
(h/render [dropdown/view {:emoji? true} label])
(h/is-truthy (h/get-by-label-text :dropdown))
(h/is-null (h/query-by-label-text :left-icon))
(h/is-truthy (h/get-by-text label))
(h/is-null (h/query-by-label-text :right-icon))))
(h/test "on-press"
(let [event (h/mock-fn)
label "Recent"]
(h/render [dropdown/view {:on-press event} label])
(h/fire-event :press (h/get-by-text label))
(h/was-called event))))

View File

@ -0,0 +1,120 @@
(ns quo2.components.dropdowns.dropdown.properties
(:require [quo2.foundations.colors :as colors]))
(def backgrounds #{:photo :blur})
(def sizes
{:size-40 {:size 40
:icon-size 20
:emoji-size 20
:emoji-padding 10
:padding-vertical 9
:padding-left {:default 16 :icon 12}
:padding-right 12
:border-radius 12
:text-size :paragraph-1}
:size-32 {:size 32
:icon-size 20
:emoji-size 20
:emoji-padding 6
:padding-vertical 5
:padding-left {:default 12 :icon 8}
:padding-right 8
:border-radius 10
:text-size :paragraph-1}
:size-24 {:size 24
:icon-size 12
:emoji-size 12
:emoji-padding 6
:padding-vertical 3
:padding-left {:default 8 :icon 8}
:padding-right 8
:border-radius 8
:text-size :paragraph-2}})
(defn- custom-color-type
[customization-color]
{:left-icon-color colors/white-opa-70
:right-icon-color colors/white-opa-20
:right-icon-color-2 colors/white
:label-color colors/white
:background-color (colors/custom-color customization-color 50)})
(def sizes-to-exclude-blur-in-photo-bg #{:size-40})
(defn- grey-photo
[theme active? size]
{:left-icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:blur-overlay-color (when (and (= theme :dark) (nil? (sizes-to-exclude-blur-in-photo-bg size)))
(if active? colors/neutral-80-opa-50 colors/neutral-80-opa-40))
:blur-type (if (= theme :light) :light :dark)
:background-color (cond
(= theme :light)
(if active? colors/white-opa-50 colors/white-opa-40)
(and (= theme :dark) (sizes-to-exclude-blur-in-photo-bg size))
(if active? colors/neutral-80-opa-50 colors/neutral-80-opa-40))})
(defn- grey-blur
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-70 theme)
:right-icon-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:background-color (if active?
(colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme))})
(defn- outline-blur
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:border-color (if active?
(colors/theme-colors colors/neutral-80-opa-20 colors/white-opa-20 theme)
(colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme))})
(defn- outline
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:border-color (if active?
(colors/theme-colors colors/neutral-40 colors/neutral-60 theme)
(colors/theme-colors colors/neutral-30 colors/neutral-70 theme))})
(defn- grey
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:background-color (if active?
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
(colors/theme-colors colors/neutral-5 colors/neutral-90 theme))})
(defn- ghost
[theme active?]
{:left-icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:right-icon-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:right-icon-color-2 (colors/theme-colors colors/neutral-100 colors/white theme)
:label-color (colors/theme-colors colors/neutral-100 colors/white theme)
:background-color (when active?
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme))})
(defn get-colors
[{:keys [customization-color theme type state background size]}]
(let [active? (= state :active)]
(cond
(and (= background :photo) (= type :grey)) (grey-photo theme active? size)
(and (= background :blur) (= type :grey)) (grey-blur theme active?)
(and (= background :blur) (= type :outline)) (outline-blur theme active?)
(= type :outline) (outline theme active?)
(= type :grey) (grey theme active?)
(= type :ghost) (ghost theme active?)
(= type :customization) (custom-color-type customization-color))))

View File

@ -0,0 +1,53 @@
(ns quo2.components.dropdowns.dropdown.style)
(def gap 4)
(def blur-view
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0})
(def left-icon
{:margin-right gap})
(defn right-icon
[label-color]
{:color label-color
:margin-right gap})
(defn- add-styles-for-emoji
[style size emoji-padding]
(-> style
(dissoc :padding-vertical :padding-left :padding-right)
(assoc :width size
:padding emoji-padding)))
(defn root-container
[{:keys [size border-radius padding-vertical padding-right padding-left emoji-padding]}
{:keys [background-color border-color]}
{:keys [icon? emoji? state]}]
(cond-> {:height size
:align-items :center
:justify-content :center
:flex-direction :row
:padding-vertical padding-vertical
:padding-left (:default padding-left)
:padding-right padding-right
:overflow :hidden
:background-color background-color
:border-radius border-radius}
icon?
(assoc :padding-left (:icon padding-left))
emoji?
(add-styles-for-emoji size emoji-padding)
border-color
(assoc :border-color border-color
:border-width 1)
(= state :disabled)
(assoc :opacity 0.3)))

View File

@ -0,0 +1,87 @@
(ns quo2.components.dropdowns.dropdown.view
(:require [quo2.components.dropdowns.dropdown.properties :as properties]
[quo2.components.dropdowns.dropdown.style :as style]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.foundations.customization-colors :as customization-colors]
[quo2.theme :as theme]
[react-native.blur :as blur]
[react-native.core :as rn]))
(defn- view-internal
[{:keys [type size state background customization-color theme on-press icon-name icon? emoji?
accessibility-label]
:or {type :grey
size :size-40
state :default
icon? false
emoji? false
icon-name :i/placeholder}
:as props}
text]
(let [{:keys [icon-size text-size emoji-size border-radius]
:as size-properties} (properties/sizes size)
{:keys [left-icon-color right-icon-color right-icon-color-2 label-color blur-type
blur-overlay-color]
:as colors} (properties/get-colors props)
right-icon (if (= state :active) :i/pullup :i/dropdown)
customization-type? (= type :customization)
show-blur-background? (and (= background :photo)
(= type :grey)
(nil? (properties/sizes-to-exclude-blur-in-photo-bg size)))]
[rn/pressable
{:accessibility-label (or accessibility-label :dropdown)
:disabled (= state :disabled)
:on-press on-press
:style (style/root-container size-properties colors props)}
(when show-blur-background?
[blur/view
{:blur-radius 20
:blur-type blur-type
:overlay-color blur-overlay-color
:style style/blur-view}])
(when customization-type?
[customization-colors/overlay
{:customization-color customization-color
:theme theme
:pressed? (= state :active)
:border-radius border-radius}])
(if emoji?
[rn/text
{:adjusts-font-size-to-fit true
:style {:font-size emoji-size}}
text]
[:<>
(when icon?
[icon/icon
icon-name
{:accessibility-label :left-icon
:color left-icon-color
:size icon-size
:container-style style/left-icon}])
[text/text
{:size text-size
:weight :medium
:number-of-lines 1
:style (style/right-icon label-color)}
text]
[icon/icon
right-icon
{:size icon-size
:accessibility-label :right-icon
:color right-icon-color
:color-2 right-icon-color-2}]])]))
(def view
"Props:
- type: :outline |:grey (default) | :ghost | :customization
- size: :size-40 (default) | :size-32 | :size-24
- state: :default (default) | :active | :disabled
- emoji?: boolean
- icon?: boolean
- background: :blur | :photo (optional)
- icon-name: keyword
- on-press: function
Child: string - used as label or emoji (for emoji only)"
(theme/with-theme view-internal))

View File

@ -1,264 +0,0 @@
(ns quo2.components.dropdowns.old-button-style
(:require [quo2.foundations.colors :as colors]))
(def blur-view
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0})
(defn before-icon-style
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
icon-size]}]
(merge
{:margin-left (or (get override-margins :left)
(if (= size 40) 12 8))
:margin-right (or (get override-margins :right) 4)
:align-items :center
:justify-content :center}
(when icon-container-size
{:width icon-container-size
:height icon-container-size})
(when icon-background-color
{:background-color icon-background-color})
(when icon-container-rounded?
{:border-radius (/ (or icon-container-size icon-size) 2)})))
(defn after-icon-style
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
icon-size]}]
(merge
{:margin-left (or (get override-margins :left) 4)
:margin-right (or (get override-margins :right)
(if (= size 40) 12 8))
:align-items :center
:justify-content :center}
(when icon-container-size
{:width icon-container-size
:height icon-container-size})
(when icon-background-color
{:background-color icon-background-color})
(when icon-container-rounded?
{:border-radius (/ (or icon-container-size icon-size) 2)})))
(defn themes
[customization-color]
{:light
{:primary {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default (colors/custom-color customization-color 50)
:pressed (colors/custom-color customization-color 60)
:disabled (colors/custom-color customization-color 50)}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-40
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:default colors/neutral-10
:pressed colors/neutral-20
:disabled colors/neutral-10}}
:dark-grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:default colors/neutral-20
:pressed colors/neutral-30
:disabled colors/neutral-20}}
:outline {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:border-color {:default colors/neutral-30
:pressed colors/neutral-40
:disabled colors/neutral-30}}
:ghost {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:pressed colors/neutral-10}}
:danger {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/danger-50
:pressed colors/danger-60
:disabled colors/danger-50}}
:positive {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/success-50
:pressed colors/success-60
:disabled colors/success-50-opa-30}}
:photo-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:background-color {:default colors/white-opa-40
:pressed colors/white-opa-50
:disabled colors/white-opa-40}}
:blur-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:background-color {:default colors/neutral-80-opa-5
:pressed colors/neutral-80-opa-10
:disabled colors/neutral-80-opa-5}}
:blurred {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-100
:icon-background-color {:default colors/neutral-20
:blurred colors/neutral-80-opa-10}
:label-color colors/neutral-100
:background-color {:default colors/neutral-10
:pressed colors/neutral-10
:disabled colors/neutral-10-opa-10-blur}
:blur-overlay-color colors/neutral-10-opa-40-blur
:blur-type :light}
:blur-bg-outline {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:border-color {:default colors/neutral-80-opa-10
:pressed colors/neutral-80-opa-20
:disabled colors/neutral-80-opa-10}}
:shell {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/neutral-95
:pressed colors/neutral-95
:disabled colors/neutral-95}}}
:dark
{:primary {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default (colors/custom-color customization-color 60)
:pressed (colors/custom-color customization-color 50)
:disabled (colors/custom-color customization-color 60)}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-30
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:default colors/neutral-90
:pressed colors/neutral-60
:disabled colors/neutral-90}}
:dark-grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:outline {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label-color colors/white
:border-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:ghost {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:pressed colors/neutral-80}}
:danger {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/danger-60
:pressed colors/danger-50
:disabled colors/danger-60}}
:positive {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/success-60
:pressed colors/success-50
:disabled colors/success-60-opa-30}}
:photo-bg {:icon-color colors/white
:icon-secondary-color colors/neutral-30
:label-color colors/white
:background-color {:default colors/neutral-80-opa-40
:pressed colors/neutral-80-opa-50
:disabled colors/neutral-80-opa-40}}
:blur-bg {:icon-color colors/white
:icon-secondary-color colors/white-opa-70
:label-color colors/white
:background-color {:default colors/white-opa-5
:pressed colors/white-opa-10
:disabled colors/white-opa-5}}
:blurred {:icon-color colors/white
:icon-secondary-color colors/white
:icon-background-color {:default colors/neutral-80
:blurred colors/white-opa-10}
:label-color colors/white
:background-color {:default colors/neutral-90
:pressed colors/neutral-90
:disabled colors/neutral-90-opa-10-blur}
:blur-overlay-color colors/neutral-80-opa-40
:blur-type :dark}
:blur-bg-outline {:icon-color colors/white
:icon-secondary-color colors/white-opa-40
:label-color colors/white
:border-color {:default colors/white-opa-10
:pressed colors/white-opa-20
:disabled colors/white-opa-5}}
:shell {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/neutral-95}}}})
(defn shape-style-container
[type icon size]
{:height size
:border-radius (if (and icon (#{:primary :secondary :danger} type))
24
(case size
56 12
40 12
32 10
24 8))})
(defn style-container
[{:keys [type size disabled background-color border-color icon above width before after blur-active?]}]
(merge {:height size
:align-items :center
:justify-content :center
:flex-direction (if above :column :row)
:padding-horizontal (when-not (or icon before after)
(case size
56 16
40 16
32 12
24 8))
:padding-left (when-not (or icon before)
(case size
56 16
40 16
32 12
24 8))
:padding-right (when-not (or icon after)
(case size
56 16
40 16
32 12
24 8))
:padding-top (when-not (or icon before after)
(case size
56 0
40 9
32 5
24 3))
:padding-bottom (when-not (or icon before after)
(case size
56 0
40 9
32 5
24 4))
:overflow :hidden}
(when (or (and (= type :blurred) (not blur-active?))
(not= type :blurred))
{:background-color background-color})
(shape-style-container type icon size)
(when width
{:width width})
(when icon
{:width size})
(when border-color
{:border-color border-color
:border-width 1})
(when disabled
{:opacity 0.3})))

View File

@ -1,138 +0,0 @@
(ns quo2.components.dropdowns.old-button-view
(:require [quo2.components.icon :as quo2.icons]
[quo2.components.markdown.text :as text]
[quo2.theme :as theme]
[react-native.core :as rn]
[react-native.blur :as blur]
[reagent.core :as reagent]
[quo2.components.dropdowns.old-button-style :as style]))
(defn- button-internal
"with label
[button opts \"label\"]
opts
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
:danger/:photo-bg/:blur-bg/:blur-bg-outline/:shell/:community
:size 40 [default] /32/24
:icon true/false
:community-color '#FFFFFF'
:community-text-color '#000000'
:before :icon-keyword
:after :icon-keyword}
only icon
[button {:icon true} :i/close-circle]"
[_ _]
(let [pressed-in (reagent/atom false)]
(fn
[{:keys [on-press disabled type size before after above icon-secondary-no-color
width customization-color theme override-background-color pressed
on-long-press accessibility-label icon icon-no-color style inner-style test-ID
blur-active? override-before-margins override-after-margins icon-size icon-container-size
icon-container-rounded?]
:or {type :primary
size 40
customization-color :primary
blur-active? true}}
children]
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color blur-type
blur-overlay-color icon-background-color]}
(get-in (style/themes customization-color)
[theme type])
state (cond disabled :disabled
(or @pressed-in pressed) :pressed
:else :default)
blur-state (if blur-active? :blurred :default)
icon-size (or icon-size (when (= 24 size) 12))
icon-secondary-color (or icon-secondary-color icon-color)]
[rn/touchable-without-feedback
(merge {:test-ID test-ID
:disabled disabled
:accessibility-label accessibility-label
:on-press-in #(reset! pressed-in true)
:on-press-out #(reset! pressed-in nil)}
(when on-press
{:on-press on-press})
(when on-long-press
{:on-long-press on-long-press}))
[rn/view
{:style (merge
(style/shape-style-container type icon size)
{:width width}
style)}
[rn/view
{:style (merge
(style/style-container {:type type
:size size
:disabled disabled
:background-color
(or override-background-color (get background-color state))
:border-color
(get border-color state)
:icon icon
:above above
:width width
:before before
:after after
:blur-active? blur-active?})
(when (= state :pressed) {:opacity 0.9})
inner-style)}
(when (and (= type :blurred)
blur-active?)
[blur/view
{:blur-radius 20
:blur-type blur-type
:overlay-color blur-overlay-color
:style style/blur-view}])
(when above
[rn/view
[quo2.icons/icon above
{:container-style {:margin-bottom 2}
:color icon-secondary-color
:size icon-size}]])
(when before
[rn/view
{:style (style/before-icon-style
{:override-margins override-before-margins
:size size
:icon-container-size icon-container-size
:icon-background-color (get icon-background-color blur-state)
:icon-container-rounded? icon-container-rounded?
:icon-size icon-size})}
[quo2.icons/icon before
{:color icon-secondary-color
:size icon-size}]])
[rn/view
(cond
(or icon icon-no-color)
[quo2.icons/icon children
{:color icon-color
:no-color icon-no-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]
(vector? children)
children)]
(when after
[rn/view
{:style (style/after-icon-style
{:override-margins override-after-margins
:size size
:icon-container-size icon-container-size
:icon-background-color (get icon-background-color blur-state)
:icon-container-rounded? icon-container-rounded?
:icon-size icon-size})}
[quo2.icons/icon after
{:no-color icon-secondary-no-color
:color icon-secondary-color
:size icon-size}]])]]]))))
(def button (theme/with-theme button-internal))

View File

@ -21,21 +21,92 @@
children)) children))
(defn- clear-20 (defn- clear-20
[{:keys [color color-2] :as props}] [{:keys [color color-2]
(let [color (or color colors/neutral-100) :or {color colors/neutral-100
color-2 (or color-2 colors/white)] color-2 colors/white}
[container props :as props}]
[svg/path [container props
{:d [svg/path
"M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z" {:d
:fill color}] "M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
[svg/path :fill color}]
{:d [svg/path
"M9.15142 9.99998L7.07566 12.0757L7.9242 12.9243L9.99994 10.8485L12.0757 12.9242L12.9242 12.0757L10.8485 9.99998L12.9242 7.92421L12.0757 7.07568L9.99994 9.15145L7.92421 7.07572L7.07568 7.92425L9.15142 9.99998Z" {:d
:fill color-2}]])) "M9.15142 9.99998L7.07566 12.0757L7.9242 12.9243L9.99994 10.8485L12.0757 12.9242L12.9242 12.0757L10.8485 9.99998L12.9242 7.92421L12.0757 7.07568L9.99994 9.15145L7.92421 7.07572L7.07568 7.92425L9.15142 9.99998Z"
:fill color-2}]])
(defn- dropdown-20
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/path
{:d
"M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
:fill color}]
[svg/path
{:d
"M7 8.5L10 11.5L13 8.5"
:stroke color-2
:stroke-width 1.2}]])
(defn- pullup-20
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/path
{:d
"M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
:fill color}]
[svg/path
{:d
"M7 11.5L10 8.5L13 11.5"
:stroke color-2
:stroke-width 1.2}]])
(defn- dropdown-12
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/circle
{:cx 6
:cy 6
:r 6
:fill color}]
[svg/path
{:d
"M3.5 5L6 7.5L8.5 5"
:stroke color-2
:stroke-width 1.1}]])
(defn- pullup-12
[{:keys [color color-2]
:or {color colors/neutral-100
color-2 colors/white}
:as props}]
[container props
[svg/circle
{:cx 6
:cy 6
:r 6
:fill color}]
[svg/path
{:d
"M3.5 7L6 4.5L8.5 7"
:stroke color-2
:stroke-width 1.1}]])
(def ^:private icons (def ^:private icons
{:i/clear-20 clear-20}) {:i/clear-20 clear-20
:i/dropdown-20 dropdown-20
:i/pullup-20 pullup-20
:i/dropdown-12 dropdown-12
:i/pullup-12 pullup-12})
(defn- append-to-keyword (defn- append-to-keyword
[k & xs] [k & xs]

View File

@ -19,12 +19,6 @@
:align-items :center :align-items :center
:justify-content (if centered? :center :flex-start)}) :justify-content (if centered? :center :flex-start)})
(def account-switcher-placeholder
{:width 32
:height 32
:border-radius 10
:background-color (colors/custom-color :purple 50)})
(def right-actions-container (def right-actions-container
{:flex-direction :row}) {:flex-direction :row})

View File

@ -1,7 +1,9 @@
(ns quo2.components.navigation.page-nav.view (ns quo2.components.navigation.page-nav.view
(:require [quo2.components.avatars.group-avatar.view :as group-avatar] (:require [quo2.components.avatars.group-avatar.view :as group-avatar]
[quo2.components.buttons.button.view :as button] [quo2.components.buttons.button.view :as button]
[quo2.components.dropdowns.dropdown :as dropdown] [quo2.components.buttons.button.properties :as button-properties]
[quo2.components.dropdowns.dropdown.view :as dropdown]
[quo2.components.dropdowns.dropdown.properties :as dropdown-properties]
[quo2.components.icon :as icons] [quo2.components.icon :as icons]
[quo2.components.markdown.text :as text] [quo2.components.markdown.text :as text]
[quo2.components.navigation.page-nav.style :as style] [quo2.components.navigation.page-nav.style :as style]
@ -28,6 +30,7 @@
:icon-only? true :icon-only? true
:size 32 :size 32
:on-press on-press :on-press on-press
:background (when (button-properties/backgrounds background) background)
:accessibility-label accessibility-label} :accessibility-label accessibility-label}
icon-name])] icon-name])]
children)) children))
@ -45,20 +48,28 @@
:icon-only? icon-name :icon-only? icon-name
:size 32 :size 32
:accessible true :accessible true
:background (when (#{:photo :blur} background) background)) :background (when (button-properties/backgrounds background) background))
(or label icon-name)])) (or label icon-name)]))
(interpose [right-section-spacing]))) (interpose [right-section-spacing])))
(defn- account-switcher-content
[{:keys [customization-color on-press emoji state]}]
[dropdown/view
{:type :customization
:customization-color customization-color
:state (or state :default)
:size :size-32
:on-press on-press
:emoji? true}
emoji])
(defn- right-content (defn- right-content
[{:keys [background content max-actions min-size? support-account-switcher?] [{:keys [background content max-actions min-size? support-account-switcher? account-switcher]
:or {support-account-switcher? true}}] :or {support-account-switcher? true}}]
[rn/view (when min-size? {:style style/right-content-min-size}) [rn/view (when min-size? {:style style/right-content-min-size})
(cond (cond
;; TODO: use account-switcher when available (issue #16456)
(and support-account-switcher? (= content :account-switcher)) (and support-account-switcher? (= content :account-switcher))
[rn/pressable [account-switcher-content account-switcher]
{:style style/account-switcher-placeholder
:on-press #(js/alert "Not implemented yet")}]
(coll? content) (coll? content)
(into [rn/view {:style style/right-actions-container}] (into [rn/view {:style style/right-actions-container}]
@ -78,17 +89,19 @@
title]]) title]])
(defn- dropdown-center (defn- dropdown-center
[{:keys [theme background dropdown-on-change dropdown-selected? dropdown-text]}] [{:keys [theme background dropdown-on-press dropdown-selected? dropdown-text]}]
(let [dropdown-type (cond (let [dropdown-type (cond
(= background :photo) :grey (= background :photo) :grey
(and (= theme :dark) (= background :blur)) :grey (and (= theme :dark) (= background :blur)) :grey
:else :ghost)] :else :ghost)
dropdown-state (if dropdown-selected? :active :default)]
[rn/view {:style (style/center-content-container true)} [rn/view {:style (style/center-content-container true)}
[dropdown/dropdown [dropdown/view
{:type dropdown-type {:type dropdown-type
:size 32 :state dropdown-state
:on-change dropdown-on-change :size :size-32
:selected dropdown-selected?} :background (when (dropdown-properties/backgrounds background) background)
:on-press dropdown-on-press}
dropdown-text]])) dropdown-text]]))
(defn- token-center (defn- token-center
@ -157,7 +170,7 @@
shown-name]])) shown-name]]))
(defn- view-internal (defn- view-internal
[{:keys [type right-side background text-align] [{:keys [type right-side background text-align account-switcher]
:or {type :no-title :or {type :no-title
text-align :center text-align :center
right-side :none right-side :none
@ -173,28 +186,29 @@
[page-nav-base props [page-nav-base props
[title-center (assoc props :centered? centered?)] [title-center (assoc props :centered? centered?)]
[right-content [right-content
{:background background {:background background
:content right-side :content right-side
:max-actions (if centered? 1 3) :max-actions (if centered? 1 3)
:min-size? centered?}]]) :min-size? centered?
:account-switcher account-switcher}]])
:dropdown :dropdown
[page-nav-base props [page-nav-base props
[dropdown-center props] [dropdown-center props]
[rn/view {:style style/right-actions-container} [right-content
(let [{button-icon :icon-name :as button-props} (first right-side)] {:background background
[button/button :content right-side
(assoc button-props :max-actions 1
:type (button-type background) :support-account-switcher? false}]]
:icon-only? true
:size 32
:accessible true)
button-icon])]]
:token :token
[page-nav-base props [page-nav-base props
[token-center props] [token-center props]
[right-content {:background background :content right-side :max-actions 3}]] [right-content
{:background background
:content right-side
:max-actions 3
:account-switcher account-switcher}]]
:channel :channel
[page-nav-base props [page-nav-base props
@ -224,10 +238,11 @@
:number-of-lines 1} :number-of-lines 1}
"NETWORK DROPDOWN"]] "NETWORK DROPDOWN"]]
[right-content [right-content
{:background background {:background background
:content right-side :content right-side
:max-actions 1 :max-actions 1
:min-size? true}]] :min-size? true
:account-switcher account-switcher}]]
(:community :network) (:community :network)
[page-nav-base props [page-nav-base props
@ -255,12 +270,19 @@
:on-press (fn callback [] nil) :on-press (fn callback [] nil)
:accessibility-label \"an optional label\"} :accessibility-label \"an optional label\"}
- account-switcher (optional)
- props to render dropdown component (emoji only) e.g.:
{:customization-color :purple
:on-press (fn [] nil)
:state :default (inherit dropdown states)
:emoji \"🍑\"}
Depending on the `type` selected, different properties are accepted: Depending on the `type` selected, different properties are accepted:
`:title` `:title`
- title - title
- text-align: `:center` or `:left` - text-align: `:center` or `:left`
`:dropdown` `:dropdown`
- dropdown-on-change: a callback - dropdown-on-press: a callback
- dropdown-selected?: a boolean - dropdown-selected?: a boolean
- dropdown-text - dropdown-text
`:token` `:token`

View File

@ -44,7 +44,7 @@
quo2.components.drawers.drawer-buttons.view quo2.components.drawers.drawer-buttons.view
quo2.components.drawers.drawer-top.view quo2.components.drawers.drawer-top.view
quo2.components.drawers.permission-context.view quo2.components.drawers.permission-context.view
quo2.components.dropdowns.dropdown quo2.components.dropdowns.dropdown.view
quo2.components.dropdowns.network-dropdown.view quo2.components.dropdowns.network-dropdown.view
quo2.components.empty-state.empty-state.view quo2.components.empty-state.empty-state.view
quo2.components.gradient.gradient-cover.view quo2.components.gradient.gradient-cover.view
@ -214,7 +214,7 @@
(def permission-context quo2.components.drawers.permission-context.view/view) (def permission-context quo2.components.drawers.permission-context.view/view)
;;;; Dropdowns ;;;; Dropdowns
(def dropdown quo2.components.dropdowns.dropdown/dropdown) (def dropdown quo2.components.dropdowns.dropdown.view/view)
(def network-dropdown quo2.components.dropdowns.network-dropdown.view/view) (def network-dropdown quo2.components.dropdowns.network-dropdown.view/view)
;;;; Empty State ;;;; Empty State

View File

@ -24,6 +24,7 @@
[quo2.components.drawers.drawer-buttons.component-spec] [quo2.components.drawers.drawer-buttons.component-spec]
[quo2.components.drawers.drawer-top.component-spec] [quo2.components.drawers.drawer-top.component-spec]
[quo2.components.drawers.permission-context.component-spec] [quo2.components.drawers.permission-context.component-spec]
[quo2.components.dropdowns.dropdown.component-spec]
[quo2.components.dropdowns.network-dropdown.component-spec] [quo2.components.dropdowns.network-dropdown.component-spec]
[quo2.components.gradient.gradient-cover.component-spec] [quo2.components.gradient.gradient-cover.component-spec]
[quo2.components.graph.wallet-graph.component-spec] [quo2.components.graph.wallet-graph.component-spec]

View File

@ -68,7 +68,7 @@
(def neutral-80-opa-20 (alpha neutral-80 0.2)) (def neutral-80-opa-20 (alpha neutral-80 0.2))
(def neutral-80-opa-30 (alpha neutral-80 0.3)) (def neutral-80-opa-30 (alpha neutral-80 0.3))
(def neutral-80-opa-40 (alpha neutral-80 0.4)) (def neutral-80-opa-40 (alpha neutral-80 0.4))
(def neutral-80-opa-50 (alpha neutral-80 0.4)) (def neutral-80-opa-50 (alpha neutral-80 0.5))
(def neutral-80-opa-60 (alpha neutral-80 0.6)) (def neutral-80-opa-60 (alpha neutral-80 0.6))
(def neutral-80-opa-70 (alpha neutral-80 0.7)) (def neutral-80-opa-70 (alpha neutral-80 0.7))
(def neutral-80-opa-80 (alpha neutral-80 0.8)) (def neutral-80-opa-80 (alpha neutral-80 0.8))

View File

@ -100,14 +100,26 @@
window-width (:width (rn/get-window))] window-width (:width (rn/get-window))]
[:f> [:f>
(fn [] (fn []
(let [camera-roll-photos (rf/sub [:camera-roll/photos]) (let [camera-roll-photos (rf/sub [:camera-roll/photos])
end-cursor (rf/sub [:camera-roll/end-cursor]) end-cursor (rf/sub [:camera-roll/end-cursor])
loading? (rf/sub [:camera-roll/loading-more]) loading? (rf/sub [:camera-roll/loading-more])
has-next-page? (rf/sub [:camera-roll/has-next-page]) has-next-page? (rf/sub [:camera-roll/has-next-page])
selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent)) selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent))
blur-active? (> @current-scroll min-scroll-to-blur) blur-active? (> @current-scroll min-scroll-to-blur)
window-height (:height (rn/get-window)) window-height (:height (rn/get-window))
top (reanimated/use-shared-value window-height)] top (reanimated/use-shared-value window-height)
show-blur? (and (not @album?) blur-active?)
dropdown-type (if show-blur? :grey :ghost)
dropdown-state (if @album? :active :default)
dropdown-background (when show-blur? :photo)
dropdown-on-press (fn []
(if-not @album?
(do
(reset! album? true)
(reanimated/animate top 0))
(do
(reanimated/animate top window-height)
(js/setTimeout #(reset! album? false) 300))))]
[rn/view {:style {:flex 1 :margin-top -20}} [rn/view {:style {:flex 1 :margin-top -20}}
(when @album? (when @album?
[album-selector/album-selector sheet album? selected-album top]) [album-selector/album-selector sheet album? selected-album top])
@ -131,18 +143,10 @@
[confirm-button @selected-images sending-image close]] [confirm-button @selected-images sending-image close]]
[rn/view {:style style/buttons-container} [rn/view {:style style/buttons-container}
[quo/dropdown [quo/dropdown
{:type :blurred {:type dropdown-type
:size 32 :size :size-32
:on-change (fn [] :state dropdown-state
(if-not @album? :on-press dropdown-on-press
(do :background dropdown-background}
(reset! album? true)
(reanimated/animate top 0))
(do
(reanimated/animate top window-height)
(js/setTimeout #(reset! album? false) 300))))
:selected @album?
:blur-active? (and (not @album?) blur-active?)
:override-background-color (when-not @album? :transparent)}
selected-album] selected-album]
[clear-button @album? selected-images blur-active?]]]))])) [clear-button @album? selected-images blur-active?]]]))]))

View File

@ -1,57 +1,82 @@
(ns status-im2.contexts.quo-preview.dropdowns.dropdown (ns status-im2.contexts.quo-preview.dropdowns.dropdown
(:require [quo2.core :as quo] (:require [quo2.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview])) [status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor (def descriptor
[{:key :type [{:key :type
:type :select :type :select
:options [{:key :primary} :options [{:key :outline}
{:key :secondary}
{:key :grey} {:key :grey}
{:key :dark-grey}
{:key :outline}
{:key :ghost} {:key :ghost}
{:key :danger} {:key :customization}]}
{:key :positive}]} {:key :state
:type :select
:options [{:key :default}
{:key :active}
{:key :disabled}]}
{:key :size {:key :size
:type :select :type :select
:options [{:key 56 :options [{:key :size-40
:value "56"}
{:key 40
:value "40"} :value "40"}
{:key 32 {:key :size-32
:value "32"} :value "32"}
{:key 24 {:key :size-24
:value "24"}]} :value "24"}]}
{:key :icon {:key :background
:type :select
:options [{:key :photo}
{:key :blur}]}
{:key :icon?
:type :boolean} :type :boolean}
{:label "Before icon:" {:key :icon-name
:key :before :type :select
:type :boolean} :options [{:key :i/wallet}
{:key :disabled {:key :i/group}
{:key :i/locked}]}
{:key :emoji?
:type :boolean} :type :boolean}
{:key :label {:key :label
:type :text}]) :type :text}
(preview/customization-color-option)])
(defn view (defn view
[] []
(let [state (reagent/atom {:label "Press Me" (let [state (reagent/atom {:type :outline
:size 40}) :state :default
label (reagent/cursor state [:label]) :size :size-40
before (reagent/cursor state [:before]) :label "Dropdown"
icon (reagent/cursor state [:icon])] :icon? false
(fn [] :emoji? false
[preview/preview-container :customization-color :purple})
{:state state label (reagent/cursor state [:label])
:descriptor descriptor emoji? (reagent/cursor state [:emoji?])
:component-container-style {:align-items :center}} background (reagent/cursor state [:background])]
[quo/dropdown [:f>
(merge (dissoc @state (fn []
:theme (rn/use-effect (fn []
:before (swap! state assoc :label (if @emoji? "🍑" "Dropdown")))
:after) [@emoji?])
{:on-press #(println "Hello world!")} [preview/preview-container
(when @before {:state state
{:before :i/placeholder})) :descriptor descriptor
(if @icon :i/placeholder @label)]]))) :component-container-style (when-not (= @background :blur) {:align-items :center})
:blur-container-style {:align-items :center}
:blur? (= @background :blur)
:show-blur-background? true}
(when (= :photo (:background @state))
[rn/image
{:source (resources/get-mock-image :dark-blur-bg)
:style {:position :absolute
:top 12
:left 20
:right 0
:bottom 0
:border-radius 12}
:height 250
:width "100%"}])
[quo/dropdown
(assoc @state :on-press #(js/alert "Pressed dropdown"))
@label]])]))

View File

@ -431,14 +431,14 @@
(defn- category-view (defn- category-view
[] []
(let [open? (reagent/atom false) (let [open? (reagent/atom false)
on-change #(swap! open? not)] on-press #(swap! open? not)]
(fn [category] (fn [category]
[rn/view {:style {:margin-vertical 8}} [rn/view {:style {:margin-vertical 8}}
[quo/dropdown [quo/dropdown
{:selected @open? {:type :grey
:on-change on-change :state (if @open? :active :default)
:type :grey} :on-press on-press}
(name (key category))] (name (key category))]
(when @open? (when @open?
(for [{category-name :name} (val category)] (for [{category-name :name} (val category)]

View File

@ -173,7 +173,7 @@
{:icon-name :i/mention :on-press #(js/alert "A MENTION!")}] {:icon-name :i/mention :on-press #(js/alert "A MENTION!")}]
:title "Page title" :title "Page title"
:text-align :center :text-align :center
:dropdown-on-change #(js/alert "Dropdown pressed!") :dropdown-on-press #(js/alert "Dropdown pressed!")
:dropdown-selected? false :dropdown-selected? false
:dropdown-text "Recent" :dropdown-text "Recent"
:token-logo (resources/get-mock-image :status-logo) :token-logo (resources/get-mock-image :status-logo)
@ -187,7 +187,10 @@
:community-name "Rarible" :community-name "Rarible"
:community-logo (resources/get-mock-image :coinbase) :community-logo (resources/get-mock-image :coinbase)
:network-name "Mainnet" :network-name "Mainnet"
:network-logo (resources/get-mock-image :diamond)})] :network-logo (resources/get-mock-image :diamond)
:account-switcher {:customization-color :purple
:on-press #(js/alert "Pressed Account Switcher")
:emoji "🍑"}})]
(fn [] (fn []
[preview/preview-container [preview/preview-container
{:state state {:state state