From eeaee5ad425503d62fef3ea1f285ccea413da3ef Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 8 Jan 2024 17:51:33 +0100
Subject: [PATCH] :zap: Add minor optimizations to tab-container react
 component

---
 .../app/main/ui/components/tab_container.cljs | 67 +++++++++----------
 .../app/main/ui/workspace/colorpicker.cljs    |  2 +-
 .../src/app/main/ui/workspace/libraries.cljs  |  2 +-
 .../src/app/main/ui/workspace/sidebar.cljs    |  5 +-
 .../main/ui/workspace/sidebar/options.cljs    |  4 +-
 .../app/main/ui/workspace/viewport/hooks.cljs |  1 +
 frontend/src/app/util/array.cljs              | 10 +++
 7 files changed, 48 insertions(+), 43 deletions(-)

diff --git a/frontend/src/app/main/ui/components/tab_container.cljs b/frontend/src/app/main/ui/components/tab_container.cljs
index 3f1aac1cd..937302741 100644
--- a/frontend/src/app/main/ui/components/tab_container.cljs
+++ b/frontend/src/app/main/ui/components/tab_container.cljs
@@ -10,6 +10,7 @@
    [app.common.data :as d]
    [app.common.data.macros :as dm]
    [app.main.ui.icons :as i]
+   [app.util.array :as array]
    [app.util.dom :as dom]
    [app.util.i18n :refer [tr]]
    [cuerdas.core :as str]
@@ -17,41 +18,32 @@
 
 (mf/defc tab-element
   {::mf/wrap-props false}
-  [props]
-  (let [children (unchecked-get props "children")]
-    [:div {:class (stl/css :tab-element)}
-     children]))
+  [{:keys [children]}]
+  [:div {:class (stl/css :tab-element)} children])
 
 (mf/defc tab-container
   {::mf/wrap-props false}
-  [props]
-  (let [children        (->>
-                         (unchecked-get props "children")
-                         (filter some?))
-        selected        (unchecked-get props "selected")
-        on-change       (unchecked-get props "on-change-tab")
-        collapsable?    (unchecked-get props "collapsable?")
-        handle-collapse (unchecked-get props "handle-collapse")
-        class           (unchecked-get props "class")
-        content-class   (unchecked-get props "content-class")
+  [{:keys [children selected on-change-tab collapsable handle-collapse header-class content-class]}]
+  (let [children  (-> (array/normalize-to-array children)
+                      (array/without-nils))
 
-        state           (mf/use-state #(or selected (-> children first .-props .-id)))
-        selected        (or selected @state)
+        selected* (mf/use-state #(or selected (-> children first .-props .-id)))
+        selected  (or selected @selected*)
 
-        select-fn
-        (mf/use-fn
-         (mf/deps on-change)
-         (fn [event]
-           (let [id (-> event
-                        (dom/get-current-target)
-                        (dom/get-data "id")
-                        (keyword))]
-             (reset! state id)
-             (when (fn? on-change) (on-change id)))))]
+        on-click  (mf/use-fn
+                   (mf/deps on-change-tab)
+                   (fn [event]
+                     (let [id (-> event
+                                  (dom/get-current-target)
+                                  (dom/get-data "id")
+                                  (keyword))]
+                       (reset! selected* id)
+                       (when (fn? on-change-tab)
+                         (on-change-tab id)))))]
 
     [:div {:class (stl/css :tab-container)}
-     [:div {:class (dm/str class " " (stl/css :tab-container-tabs))}
-      (when collapsable?
+     [:div {:class (dm/str header-class " " (stl/css :tab-container-tabs))}
+      (when ^boolean collapsable
         [:button
          {:on-click handle-collapse
           :class (stl/css :collapse-sidebar)
@@ -61,13 +53,16 @@
        (for [tab children]
          (let [props (.-props tab)
                id    (.-id props)
-               title (.-title props)]
-           [:div
-            {:key (str/concat "tab-" (d/name id))
-             :data-id (d/name id)
-             :on-click select-fn
-             :class  (stl/css-case :tab-container-tab-title true
-                                   :current (= selected id))}
+               title (.-title props)
+               sid   (d/name id)]
+           [:div {:key (str/concat "tab-" sid)
+                  :data-id sid
+                  :on-click on-click
+                  :class  (stl/css-case
+                           :tab-container-tab-title true
+                           :current (= selected id))}
             title]))]]
+
      [:div {:class (dm/str content-class " " (stl/css  :tab-container-content))}
-      (d/seek #(= selected (-> % .-props .-id)) children)]]))
+      (d/seek #(= selected (-> % .-props .-id))
+              children)]]))
diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs
index eaf166037..82ccaa701 100644
--- a/frontend/src/app/main/ui/workspace/colorpicker.cljs
+++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs
@@ -311,7 +311,7 @@
          [:& tab-container
           {:on-change-tab set-tab!
            :selected @active-color-tab
-           :collapsable? false}
+           :collapsable false}
 
           [:& tab-element {:id :ramp :title i/rgba-refactor}
            (if picking-color?
diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs
index 67dc5df16..3829f7ca3 100644
--- a/frontend/src/app/main/ui/workspace/libraries.cljs
+++ b/frontend/src/app/main/ui/workspace/libraries.cljs
@@ -502,7 +502,7 @@
         [:& tab-container
          {:on-change-tab on-tab-change
           :selected selected-tab
-          :collapsable? false}
+          :collapsable false}
          [:& tab-element {:id :libraries :title (tr "workspace.libraries.libraries")}
           [:div {:class (stl/css :libraries-content)}
            [:& libraries-tab {:file-id file-id
diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs
index faa27b292..b38c1cd44 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar.cljs
@@ -83,10 +83,9 @@
          [:& tab-container
           {:on-change-tab on-tab-change
            :selected section
-           :shortcuts? shortcuts?
-           :collapsable? true
+           :collapsable true
            :handle-collapse handle-collapse
-           :class (stl/css :tab-spacing)}
+           :header-class (stl/css :tab-spacing)}
           [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")}
            [:div {:class (stl/css :layers-tab)
                   :style #js {"--height" (str size-pages "px")}}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs
index 763adb7fb..ce83d7fa9 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs
@@ -103,9 +103,9 @@
      [:& tab-container
       {:on-change-tab on-change-tab
        :selected section
-       :collapsable? false
+       :collapsable false
        :content-class (stl/css :content-class)
-       :class (stl/css :tab-spacing)}
+       :header-class (stl/css :tab-spacing)}
       [:& tab-element {:id :design
                        :title (tr "workspace.options.design")}
        [:div {:class (stl/css :element-options)}
diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
index f995848ec..01d95a9be 100644
--- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
@@ -299,6 +299,7 @@
                       (not (cfh/is-direct-child-of-root? shape))
                       (empty? (get shape :fills)))))
 
+
              hover-shape
              (->> ids
                   (remove remove-id?)
diff --git a/frontend/src/app/util/array.cljs b/frontend/src/app/util/array.cljs
index 875a4ba32..c04dddb20 100644
--- a/frontend/src/app/util/array.cljs
+++ b/frontend/src/app/util/array.cljs
@@ -34,3 +34,13 @@
    (.push ^js a v1 v2 v3 v4 v5 v6)
    a))
 
+(defn normalize-to-array
+  "If `o` is an array, returns it as-is, if not, wrap into an array."
+  [o]
+  (if (array? o)
+    o
+    #js [o]))
+
+(defn without-nils
+  [^js/Array o]
+  (.filter o (fn [v] (some? v))))