Andrey Antukh fe5cdcbdc7
🐛 Do not render assets sidebar context menu if it is not open (#7222)
This commit is a workaround to an issue that happens when you performing
multiple selection of several shapes (including components) and an
exception is raised of max depth of updates. The issue is still not
solved, we justo do not render the context menu when user performs
the selection on the workspace.

That issue/exception happens only we have context-menu* component
rendered independently of its visibility and dev-tools open
2025-08-29 13:53:55 +02:00

204 lines
7.1 KiB
Clojure

;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.sidebar.assets
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.common.types.components-list :as ctkl]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.assets :as dwa]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.context-menu-a11y :refer [context-menu*]]
[app.main.ui.components.search-bar :refer [search-bar*]]
[app.main.ui.context :as ctx]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.assets.common :as cmm]
[app.main.ui.workspace.sidebar.assets.file-library :refer [file-library*]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[cuerdas.core :as str]
[okulary.core :as l]
[rumext.v2 :as mf]))
(mf/defc assets-libraries*
{::mf/wrap [mf/memo]
::mf/props :obj
::mf/private true}
[{:keys [filters]}]
(let [file-id (mf/use-ctx ctx/current-file-id)
files (mf/deref refs/files)
libraries (mf/with-memo [files file-id]
(->> (refs/select-libraries files file-id)
(vals)
(remove :is-indirect)
(remove #(= file-id (:id %)))
(map (fn [file]
(update file :data dissoc :pages-index)))
(sort-by #(str/lower (:name %)))))]
(for [file libraries]
[:> file-library*
{:key (dm/str (:id file))
:file file
:is-local false
:is-default-open false
:filters filters}])))
(def ^:private ref:local-library
(l/derived (fn [file]
(update file :data dissoc :pages-index))
refs/file))
(mf/defc assets-local-library
{::mf/wrap [mf/memo]
::mf/wrap-props false}
[{:keys [filters]}]
(let [file (mf/deref ref:local-library)]
[:> file-library*
{:file file
:is-local true
:is-default-open true
:filters filters}]))
(defn- toggle-values
[v [a b]]
(if (= v a) b a))
(mf/defc assets-toolbox*
{::mf/wrap [mf/memo]}
[{:keys [size file-id]}]
(let [read-only? (mf/use-ctx ctx/workspace-read-only?)
filters* (mf/use-state
{:term ""
:section "all"
:ordering (dwa/get-current-assets-ordering)
:list-style (dwa/get-current-assets-list-style)
:open-menu false})
filters (deref filters*)
term (:term filters)
list-style (:list-style filters)
menu-open? (:open-menu filters)
section (:section filters)
ordering (:ordering filters)
reverse-sort? (= :desc ordering)
libs (mf/deref refs/libraries)
num-libs (count libs)
file (get libs file-id)
components (mf/with-memo [file] (ctkl/components (:data file)))
toggle-ordering
(mf/use-fn
(mf/deps ordering)
(fn []
(let [new-value (toggle-values ordering [:asc :desc])]
(swap! filters* assoc :ordering new-value)
(dwa/set-current-assets-ordering! new-value))))
toggle-list-style
(mf/use-fn
(mf/deps list-style)
(fn []
(let [new-value (toggle-values list-style [:thumbs :list])]
(swap! filters* assoc :list-style new-value)
(dwa/set-current-assets-list-style! new-value))))
on-search-term-change
(mf/use-fn
(fn [event]
(st/emit! (dw/clear-assets-section-open))
(swap! filters* assoc :term event)))
on-section-filter-change
(mf/use-fn
(fn [event]
(let [value (or (-> (dom/get-target event)
(dom/get-value))
(as-> (dom/get-current-target event) $
(dom/get-attribute $ "data-testid")))]
(st/emit! (dw/clear-assets-section-open))
(swap! filters* assoc :section value :open-menu false))))
show-libraries-dialog
(mf/use-fn
(mf/deps file-id)
(fn []
(modal/show! :libraries-dialog {:file-id file-id})))
on-open-menu
(mf/use-fn #(swap! filters* update :open-menu not))
on-menu-close
(mf/use-fn #(swap! filters* assoc :open-menu false))
options
[{:name (tr "workspace.assets.box-filter-all")
:id "all"
:handler on-section-filter-change}
{:name (tr "workspace.assets.components")
:id "components"
:handler on-section-filter-change}
{:name (tr "workspace.assets.colors")
:id "colors"
:handler on-section-filter-change}
{:name (tr "workspace.assets.typography")
:id "typographies"
:handler on-section-filter-change}]]
[:article {:class (stl/css :assets-bar)}
[:div {:class (stl/css :assets-header)}
(when-not ^boolean read-only?
(if (and (= num-libs 1) (empty? components))
[:button {:class (stl/css :add-library-button)
:on-click show-libraries-dialog
:data-testid "libraries"}
(tr "workspace.assets.add-library")]
[:button {:class (stl/css :libraries-button)
:on-click show-libraries-dialog
:data-testid "libraries"}
(tr "workspace.assets.manage-library")]))
[:div {:class (stl/css :search-wrapper)}
[:> search-bar* {:on-change on-search-term-change
:value term
:placeholder (tr "workspace.assets.search")}
[:button
{:on-click on-open-menu
:title (tr "workspace.assets.filter")
:class (stl/css-case :section-button true
:opened menu-open?)}
i/filter-icon]]
(when menu-open?
[:> context-menu*
{:on-close on-menu-close
:selectable true
:selected section
:show true
:fixed true
:min-width true
:width size
:top 158
:left 18
:options options}])
[:> icon-button* {:variant "ghost"
:aria-label (tr "workspace.assets.sort")
:on-click toggle-ordering
:icon (if reverse-sort? "asc-sort" "desc-sort")}]]]
[:& (mf/provider cmm/assets-filters) {:value filters}
[:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering}
[:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style}
[:*
[:& assets-local-library {:filters filters}]
[:> assets-libraries* {:filters filters}]]]]]]))