From 6c28e9349fd46fb23ba156e8b0329781566ba535 Mon Sep 17 00:00:00 2001 From: Icaro Motta Date: Wed, 12 Jul 2023 11:35:14 +0000 Subject: [PATCH] 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". --- .../list_items/community/style.cljs | 2 +- .../notifications/notification/style.cljs | 6 +- .../components/notifications/toast/style.cljs | 6 +- src/quo2/foundations/shadows.cljs | 125 ++++++++++-------- .../contexts/profile/profiles/style.cljs | 5 +- .../quo_preview/foundations/shadows.cljs | 88 ++++++------ 6 files changed, 122 insertions(+), 110 deletions(-) diff --git a/src/quo2/components/list_items/community/style.cljs b/src/quo2/components/list_items/community/style.cljs index 77b97ced94..dcdde68500 100644 --- a/src/quo2/components/list_items/community/style.cljs +++ b/src/quo2/components/list_items/community/style.cljs @@ -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)))) diff --git a/src/quo2/components/notifications/notification/style.cljs b/src/quo2/components/notifications/notification/style.cljs index eda46e0b25..5a4630c182 100644 --- a/src/quo2/components/notifications/notification/style.cljs +++ b/src/quo2/components/notifications/notification/style.cljs @@ -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})) diff --git a/src/quo2/components/notifications/toast/style.cljs b/src/quo2/components/notifications/toast/style.cljs index 8763a306eb..3a2a70b043 100644 --- a/src/quo2/components/notifications/toast/style.cljs +++ b/src/quo2/components/notifications/toast/style.cljs @@ -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 diff --git a/src/quo2/foundations/shadows.cljs b/src/quo2/foundations/shadows.cljs index d711eca834..28c12e8d65 100644 --- a/src/quo2/foundations/shadows.cljs +++ b/src/quo2/foundations/shadows.cljs @@ -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)) +(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} + 2 {:shadow-color (colors/alpha colors/neutral-100 0.64) + :shadow-offset {:width 0 :height 4} + :elevation 4 + :shadow-opacity 1 + :shadow-radius 20} + 3 {:shadow-color (colors/alpha colors/neutral-100 0.64) + :shadow-offset {:width 0 :height 12} + :elevation 8 + :shadow-opacity 1 + :shadow-radius 20} + 4 {:shadow-color (colors/alpha colors/neutral-100 0.72) + :shadow-offset {:width 0 :height 16} + :shadow-opacity 1 + :shadow-radius 20 + :elevation 15}} + 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} + 2 {:shadow-color (colors/alpha colors/neutral-100 0.08) + :shadow-offset {:width 0 :height 4} + :elevation 2 + :shadow-opacity 1 + :shadow-radius 16} + 3 {:shadow-color (colors/alpha colors/neutral-100 0.12) + :shadow-offset {:width 0 :height 12} + :elevation 5 + :shadow-opacity 1 + :shadow-radius 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}} + 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}})) -(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)} - :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)} - :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)} - :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)} - :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)} - :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)} - :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)} - :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)} - :shadow-opacity 1 - :shadow-radius 16 - :elevation 13}})) +(defn get + "Get the appropriate shadow map for a given shadow `weight`, `theme`, and `scale-type`. -(def normal-scale (get-scales false)) + Return nil if no shadow is found. -(def inverted-scale (get-scales true)) + `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) diff --git a/src/status_im2/contexts/profile/profiles/style.cljs b/src/status_im2/contexts/profile/profiles/style.cljs index a4ed76ee77..2200d3c53c 100644 --- a/src/status_im2/contexts/profile/profiles/style.cljs +++ b/src/status_im2/contexts/profile/profiles/style.cljs @@ -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)}) diff --git a/src/status_im2/contexts/quo_preview/foundations/shadows.cljs b/src/status_im2/contexts/quo_preview/foundations/shadows.cljs index bf68c9176d..d5644bf232 100644 --- a/src/status_im2/contexts/quo_preview/foundations/shadows.cljs +++ b/src/status_im2/contexts/quo_preview/foundations/shadows.cljs @@ -1,65 +1,65 @@ (ns status-im2.contexts.quo-preview.foundations.shadows - (:require - [quo2.foundations.shadows :as shadows] - [quo2.foundations.colors :as colors] - [quo2.core :as quo] - [react-native.core :as rn] - [reagent.core :as reagent] - [status-im2.contexts.quo-preview.preview :as preview])) + (:require [quo2.core :as quo] + [quo2.foundations.colors :as colors] + [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 - :margin-right :auto - :margin-top 8 - :margin-bottom 8 - :align-items :center} - [quo/text {} name] + {:style {:margin-left :auto + :margin-right :auto + :margin-top 8 + :margin-bottom 8 + :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)] - [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)] - [quo/text - {:style {:margin-left :auto - :margin-right :auto - :align-items :center}} - "Inverted Scales"] - [demo-box (:shadow-on? @state) "Inner Shadow" shadows/inner-shadow]]]]))) + [quo/text + {:style {:margin-left :auto + :margin-right :auto + :align-items :center}} + "Normal Scales"] + [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? "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? "Inner Shadow" shadows/inner-shadow]]]))) (defn preview-shadows []