Fix & optimize shadows foundation (#16553)

Rewrite the shadows foundation API:

- Fix (implementation & usages): theme changes were not causing shadows to be
  reevaluated.
- Optimization: define all possible shadow values at compile time. Good to
  reduce cycles on garbage collection since recreating the shadow map all the
  time is unnecessary and also to save cycles on computing colors since calls to
  colors/alpha are not memoized.
- API redesign: unify access to Design System shadows in a single function.

None of the actual shadow values changed.

Fixes https://github.com/status-im/status-mobile/issues/16526

API rationale
=============

The quo2.foundations.shadows namespace reflects what's in the Design System >
Foundations > Shadows https://www.figma.com/file/v98g9ZiaSHYUdKWrbFg9eM/Foundations?type=design&node-id=624-965&mode=design&t=CvIotdjbHKHcHjpd-0).
Figma users see these shadows in other components as "Shadow/Normal/Light/03".
Notice the shadow's weight is shown as a number (not the semantic name in Figma,
e.g. "intense", "strong"):

So to make things as easy as possible, I opted for exposing a single public
function named "get", which receives arguments in order of frequency of usage
and which expects shadow weights as numbers so that devs don't need to mentally
translate 1 to "soft", or 3 to "intense".
This commit is contained in:
Icaro Motta 2023-07-12 11:35:14 +00:00 committed by GitHub
parent 6170686e34
commit 6c28e9349f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 122 additions and 110 deletions

View File

@ -62,4 +62,4 @@
(and pressed? (= type :discover))
(colors/theme-colors colors/white :transparent theme))}
(when (and (= type :discover) (not pressed?))
(:shadow-3 shadows/normal-scale))))
(shadows/get 3))))

View File

@ -18,10 +18,10 @@
:background-color :transparent})
(defn content-container
[override-theme]
[theme]
(merge
(:shadow-1 shadows/normal-scale)
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 override-theme)
(shadows/get 1 theme)
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)
:flex-direction :row
:padding-vertical 8
:padding-horizontal 12}))

View File

@ -18,10 +18,10 @@
:background-color :transparent})
(defn content-container
[override-theme]
[theme]
(merge
(:shadow-1 shadows/normal-scale)
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 override-theme)
(shadows/get 1 theme)
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)
:flex-direction :row
:justify-content :space-between
:padding-vertical 8

View File

@ -1,66 +1,77 @@
(ns quo2.foundations.shadows
(:refer-clojure :exclude [get])
(:require [quo2.foundations.colors :as colors]
[quo2.theme :as theme]))
[quo2.theme :as quo.theme]))
(defn- get-inverted
[inverted? number]
(if inverted? (* -1 number) number))
(defn- get-scales
[inverted?]
(if (theme/dark?)
{:shadow-1 {:shadow-color (colors/alpha colors/neutral-100 0.5)
:shadow-offset {:width 0
:height (get-inverted inverted? 4)}
(def ^:private shadows
(let [dark-normal {1 {:shadow-color (colors/alpha colors/neutral-100 0.5)
:shadow-offset {:width 0 :height 4}
:elevation 3
:shadow-opacity 1
:shadow-radius 20}
:shadow-2 {:shadow-color (colors/alpha colors/neutral-100 0.64)
:shadow-offset {:width 0
:height (get-inverted inverted? 4)}
2 {:shadow-color (colors/alpha colors/neutral-100 0.64)
:shadow-offset {:width 0 :height 4}
:elevation 4
:shadow-opacity 1
:shadow-radius 20}
:shadow-3 {:shadow-color (colors/alpha colors/neutral-100 0.64)
:shadow-offset {:width 0
:height (get-inverted inverted? 12)}
3 {:shadow-color (colors/alpha colors/neutral-100 0.64)
:shadow-offset {:width 0 :height 12}
:elevation 8
:shadow-opacity 1
:shadow-radius 20}
:shadow-4 {:shadow-color (colors/alpha colors/neutral-100 0.72)
:shadow-offset {:width 0
:height (get-inverted inverted? 16)}
4 {:shadow-color (colors/alpha colors/neutral-100 0.72)
:shadow-offset {:width 0 :height 16}
:shadow-opacity 1
:shadow-radius 20
:elevation 15}}
{:shadow-1 {:shadow-color (colors/alpha colors/neutral-100 0.04)
:shadow-offset {:width 0
:height (get-inverted inverted? 4)}
dark-normal-inverted (-> dark-normal
(update-in [:soft :shadow-offset :height] -)
(update-in [:medium :shadow-offset :height] -)
(update-in [:intense :shadow-offset :height] -)
(update-in [:strong :shadow-offset :height] -))
light-normal {1 {:shadow-color (colors/alpha colors/neutral-100 0.04)
:shadow-offset {:width 0 :height 4}
:elevation 1
:shadow-opacity 1
:shadow-radius 16}
:shadow-2 {:shadow-color (colors/alpha colors/neutral-100 0.08)
:shadow-offset {:width 0
:height (get-inverted inverted? 4)}
2 {:shadow-color (colors/alpha colors/neutral-100 0.08)
:shadow-offset {:width 0 :height 4}
:elevation 2
:shadow-opacity 1
:shadow-radius 16}
:shadow-3 {:shadow-color (colors/alpha colors/neutral-100 0.12)
:shadow-offset {:width 0
:height (get-inverted inverted? 12)}
3 {:shadow-color (colors/alpha colors/neutral-100 0.12)
:shadow-offset {:width 0 :height 12}
:elevation 5
:shadow-opacity 1
:shadow-radius 16}
:shadow-4 {:shadow-color (colors/alpha colors/neutral-100 0.16)
:shadow-offset {:width 0
:height (get-inverted inverted? 16)}
4 {:shadow-color (colors/alpha colors/neutral-100 0.16)
:shadow-offset {:width 0 :height 16}
:shadow-opacity 1
:shadow-radius 16
:elevation 13}}))
:elevation 13}}
light-normal-inverted (-> light-normal
(update-in [:soft :shadow-offset :height] -)
(update-in [:medium :shadow-offset :height] -)
(update-in [:intense :shadow-offset :height] -)
(update-in [:strong :shadow-offset :height] -))]
{:dark {:normal dark-normal :inverted dark-normal-inverted}
:light {:normal light-normal :inverted light-normal-inverted}}))
(def normal-scale (get-scales false))
(defn get
"Get the appropriate shadow map for a given shadow `weight`, `theme`, and `scale-type`.
(def inverted-scale (get-scales true))
Return nil if no shadow is found.
`weight` - int (required) from 1 to 4.
`theme` - :light/:dark (optional).
`scale-type` - :normal/:inverted (optional).
"
([weight]
(get weight (quo.theme/get-theme)))
([weight theme]
(get weight theme :normal))
([weight theme scale-type]
(get-in shadows [theme scale-type weight])))
(def inner-shadow
{:shadow-color (colors/alpha colors/neutral-100 0.08)

View File

@ -7,8 +7,9 @@
[last-item?]
;; This part needs to be improved, inverted shadow is not supported in android
;; https://reactnative.dev/docs/shadow-props#shadowoffset-ios
;; (merge
;; (:shadow-1 (shadows/get-scales true :dark))
;;
;; (merge (shadows/get 1 :dark :inverted) ...)
;;
{:padding-horizontal 20
:margin-bottom (when-not last-item? -24)})

View File

@ -1,65 +1,65 @@
(ns status-im2.contexts.quo-preview.foundations.shadows
(:require
[quo2.foundations.shadows :as shadows]
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[quo2.core :as quo]
[quo2.foundations.shadows :as shadows]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]))
(defn demo-box
[shadow-on? name shadow-style]
[shadow? description shadow-style]
[rn/view
{:margin-left :auto
{:style {:margin-left :auto
:margin-right :auto
:margin-top 8
:margin-bottom 8
:align-items :center}
[quo/text {} name]
:align-items :center}}
[quo/text {} description]
[rn/view
{:style (merge {:width 60
:height 60
:border-radius 16
:background-color (colors/theme-colors colors/white colors/neutral-90)}
(when shadow-on? shadow-style))}]])
(when shadow? shadow-style))}]])
(def descriptor
[{:label "Shadow on?"
:key :shadow-on?
[{:label "Shadows enabled?"
:key :shadow?
:type :boolean}])
(defn cool-preview
[]
(let [state (reagent/atom {:shadow-on? true})]
(let [state (reagent/atom {:shadow? true})
shadow? (reagent/cursor state [:shadow?])]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[rn/view {:style {:padding-bottom 150}}
[preview/customizer state descriptor]
[:<>
[quo/text
{:style {:margin-left :auto
:margin-right :auto
:align-items :center}}
"Normal Scales"]
[demo-box (:shadow-on? @state) "shadow 1" (:shadow-1 shadows/normal-scale)]
[demo-box (:shadow-on? @state) "shadow 2" (:shadow-2 shadows/normal-scale)]
[demo-box (:shadow-on? @state) "shadow 3" (:shadow-3 shadows/normal-scale)]
[demo-box (:shadow-on? @state) "shadow 4" (:shadow-4 shadows/normal-scale)]
[demo-box @shadow? "Shadow 1" (shadows/get 1)]
[demo-box @shadow? "Shadow 2" (shadows/get 2)]
[demo-box @shadow? "Shadow 3" (shadows/get 3)]
[demo-box @shadow? "Shadow 4" (shadows/get 4)]
[quo/text
{:style {:margin-left :auto
:margin-right :auto
:align-items :center}}
"Inverted Scales"]
[demo-box (:shadow-on? @state) "shadow 1" (:shadow-1 shadows/inverted-scale)]
[demo-box (:shadow-on? @state) "shadow 2" (:shadow-2 shadows/inverted-scale)]
[demo-box (:shadow-on? @state) "shadow 3" (:shadow-3 shadows/inverted-scale)]
[demo-box (:shadow-on? @state) "shadow 4" (:shadow-4 shadows/inverted-scale)]
[demo-box @shadow? "Shadow 1" (shadows/get 1 (quo.theme/get-theme) :inverted)]
[demo-box @shadow? "Shadow 2" (shadows/get 2 (quo.theme/get-theme) :inverted)]
[demo-box @shadow? "Shadow 3" (shadows/get 3 (quo.theme/get-theme) :inverted)]
[demo-box @shadow? "Shadow 4" (shadows/get 4 (quo.theme/get-theme) :inverted)]
[quo/text
{:style {:margin-left :auto
:margin-right :auto
:align-items :center}}
"Inverted Scales"]
[demo-box (:shadow-on? @state) "Inner Shadow" shadows/inner-shadow]]]])))
[demo-box @shadow? "Inner Shadow" shadows/inner-shadow]]])))
(defn preview-shadows
[]