Add basic variants events (#7249)

*  Add basic variants events

*  MR changes
This commit is contained in:
Pablo Alba 2025-09-04 17:00:09 +02:00 committed by GitHub
parent 25950be077
commit 409f95ac17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 95 additions and 68 deletions

View File

@ -426,7 +426,6 @@
(not (has-any-main? objects shape))
(not (has-any-copy-parent? objects shape))))
(defn collect-main-shapes [shape objects]
(if (ctk/main-instance? shape)
[shape]
@ -434,6 +433,10 @@
(mapcat collect-main-shapes children objects)
[])))
(defn get-component-from-shape
[shape libraries]
(get-in libraries [(:component-file shape) :data :components (:component-id shape)]))
(defn invalid-structure-for-component?
"Check if the structure generated nesting children in parent is invalid in terms of nested components"
[objects parent children pasting? libraries]
@ -446,7 +449,7 @@
; original component doesn't exist or is deleted. So for this function purposes, they
; are removed from the list
remove? (fn [shape]
(let [component (get-in libraries [(:component-file shape) :data :components (:component-id shape)])]
(let [component (get-component-from-shape shape libraries)]
(and component (not (:deleted component)))))
selected-components (cond->> (mapcat collect-main-shapes children objects)

View File

@ -121,6 +121,8 @@
;; Collects all the items together and split images into a
;; separated data structure for a more easy paste process.
;; Also collects the variant properties of the copied variants
(collect-data [state result {:keys [id ::images] :as item}]
(cond-> result
:always
@ -132,8 +134,6 @@
(ctc/is-variant-container? item)
(update :variant-properties merge (collect-variants state item))))
(maybe-translate [shape objects parent-frame-id]
(if (= parent-frame-id uuid/zero)
shape
@ -829,7 +829,6 @@
variant-props (:variant-properties pdata)
position (deref ms/mouse-position)
;; Calculate position for the pasted elements
@ -895,6 +894,7 @@
(rx/map (fn [shape]
(let [parent-type (cfh/get-shape-type all-objects (:parent-id shape))
external-lib? (not= file-id (:component-file shape))
component (ctn/get-component-from-shape shape libraries)
origin "workspace:paste"]
;; NOTE: we don't emit the create-shape event all the time for
@ -905,7 +905,8 @@
::ev/origin origin
:is-external-library external-lib?
:type (get shape :type)
:parent-type parent-type})
:parent-type parent-type
:is-variant (ctc/is-variant? component)})
(if (cfh/has-layout? objects (:parent-id shape))
(ev/event {::ev/name "layout-add-element"
::ev/origin origin

View File

@ -549,7 +549,6 @@
(when local?
(ptk/data-event :layout/update {:page-id page-id :ids frames})))))))
(defn restore-components
"Restore multiple deleted component definded by a map with the component id as key and the component library as value"
[components-data]
@ -592,6 +591,7 @@
position
page
libraries)
component (ctn/get-component-from-shape new-shape libraries)
undo-id (js/Symbol)]
@ -601,7 +601,8 @@
(rx/of (ptk/event ::ev/event
{::ev/name "use-library-component"
::ev/origin origin
:external-library (not= file-id current-file-id)})
:external-library (not= file-id current-file-id)
:is-variant (ctk/is-variant? component)})
(dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(ptk/data-event :layout/update {:ids [(:id new-shape)]})
@ -704,7 +705,6 @@
data (dsh/lookup-file-data state)
objects (dsh/lookup-page-objects state current-page-id)
select-and-zoom
(fn [ids]
(let [parent-ids (when update-layout?
@ -1158,6 +1158,7 @@
;; FIXME: the data should be set on the backend for clock consistency
(def ignore-sync
"Mark the file as ignore syncs. All library changes before this moment will not
ber notified to sync."
@ -1226,7 +1227,6 @@
:callback do-update}
:tag :sync-dialog)))))))
(defn touch-component
"Update the modified-at attribute of the component to now"
[id]

View File

@ -16,6 +16,7 @@
[app.common.geom.shapes :as gsh]
[app.common.logic.libraries :as cll]
[app.common.types.component :as ctk]
[app.common.types.container :as ctn]
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.event :as ev]
@ -484,6 +485,7 @@
(let [shape (get objects shape-id)
parent-type (cfh/get-shape-type objects (:parent-id shape))
external-lib? (not= file-id (:component-file shape))
component (ctn/get-component-from-shape shape libraries)
origin "workspace:duplicate-shapes"]
;; NOTE: we don't emit the create-shape event all the time for
@ -494,7 +496,8 @@
::ev/origin origin
:is-external-library external-lib?
:type (get shape :type)
:parent-type parent-type})
:parent-type parent-type
:is-variant (ctk/is-variant? component)})
(if (cfh/has-layout? objects (:parent-id shape))
(ev/event {::ev/name "layout-add-element"
::ev/origin origin
@ -555,10 +558,10 @@
(assoc :workspace-focus-selected focus))))))
(defn toggle-focus-mode
"Zoom in on and center viewport on selection;
"Zoom in on and center viewport on selection;
hide all other layers in viewport and layer panel.
When in focus mode, exit restoring previous viewport and selection.
When in focus mode, exit restoring previous viewport and selection.
"
[]
(ptk/reify ::toggle-focus-mode
@ -597,7 +600,7 @@
(rx/map (comp set keys))
(rx/buffer 2 1)
(rx/merge-map
;; While focus is active, update it with any new and deleted shapes
;; While focus is active, update it with any new and deleted shapes
(fn [[old-keys new-keys]]
(let [removed (set/difference old-keys new-keys)
added (set/difference new-keys old-keys)]

View File

@ -21,6 +21,7 @@
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.common :as dcm]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.colors :as cl]
[app.main.data.workspace.libraries :as dwl]
@ -85,6 +86,10 @@
undo-id (js/Symbol)]
(rx/of
(when (or (seq properties-to-remove) (seq properties-to-update))
(ptk/event ::ev/event {::ev/name "variant-edit-property-value" :trigger "rename-in-layers"}))
(when (seq properties-to-add)
(ptk/event ::ev/event {::ev/name "variant-add-property" :trigger "rename-in-layers"}))
(dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(dwu/commit-undo-transaction undo-id))))))
@ -132,7 +137,6 @@
(dch/commit-changes changes)
(dwu/commit-undo-transaction undo-id))))))
(defn update-error
"Sets or unsets an error for a component"
([component-id]
@ -156,7 +160,6 @@
(dch/commit-changes changes)
(dwu/commit-undo-transaction undo-id)))))))
(defn remove-property
"Remove the variant property on the position pos
in all the components with this variant-id"
@ -180,7 +183,6 @@
(dch/commit-changes changes)
(dwu/commit-undo-transaction undo-id))))))
(defn remove-empty-properties
"Remove every empty property for all components when their respective values are empty
for all of them"
@ -221,11 +223,12 @@
undo-id (js/Symbol)]
(rx/of
(dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(dwu/commit-undo-transaction undo-id))))))
(when (seq (:redo-changes changes))
(rx/of
(ptk/event ::ev/event {::ev/name "variant-remove-property" :trigger "rename-in-layers"})
(dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(dwu/commit-undo-transaction undo-id)))))))
(defn add-new-property
"Add a new variant property to all the components with this variant-id"
@ -273,7 +276,6 @@
(effect [_ _ _]
(dom/focus! (dom/get-element (str "variant-prop-" shape-id prop-num))))))
(defn- resposition-and-resize-variant
"Resize the variant container, and move the shape (that is a variant) to the right"
[shape-id]
@ -292,7 +294,6 @@
{:x x}
{:absolute? false}))))))
(defn add-new-variant
"Create a new variant and add it to the variant-container"
[shape-id]
@ -403,6 +404,8 @@
;;TODO Refactor all called methods in order to be able to
;;generate changes instead of call the events
(rx/concat
(rx/of
(dwu/start-undo-transaction undo-id)
@ -458,11 +461,15 @@
undo-id (js/Symbol)]
(cond
transform-in-variant?
(rx/of (transform-in-variant (:id first-shape)))
(rx/of
(ptk/event ::ev/event {::ev/name "transform-in-variant" :trigger "shortcut"})
(transform-in-variant (:id first-shape)))
add-new-variant?
(rx/concat
(rx/of (dwu/start-undo-transaction undo-id))
(rx/of
(ptk/event ::ev/event {::ev/name "add-new-variant" :trigger "shortcut-create-component"})
(dwu/start-undo-transaction undo-id))
(rx/from (map add-new-variant selected-ids))
(rx/of (dwu/commit-undo-transaction undo-id)))
@ -482,12 +489,13 @@
undo-id (js/Symbol)]
(if add-new-variant?
(rx/concat
(rx/of (dwu/start-undo-transaction undo-id))
(rx/of
(ptk/event ::ev/event {::ev/name "add-new-variant" :trigger "shortcut-duplicate"})
(dwu/start-undo-transaction undo-id))
(rx/from (map add-new-variant selected-ids))
(rx/of (dwu/commit-undo-transaction undo-id)))
(rx/of (dws/duplicate-selected true)))))))
(defn rename-variant
"Rename the variant container and all components belonging to this variant"
[variant-id name]
@ -511,7 +519,6 @@
variant-components))
(rx/of (dwu/commit-undo-transaction undo-id)))))))
(defn rename-comp-or-variant-and-main
"If the component is in a variant, rename the variant.
If it is not, rename the component and its main"
@ -526,7 +533,6 @@
(rx/of (rename-variant (:variant-id component) name))
(rx/of (dwl/rename-component-and-main-instance component-id name)))))))
(defn- bounding-rect
"Receives a list of frames (with X, y, width and height) and
calculates a rect that contains them all"

View File

@ -580,7 +580,9 @@
do-combine-as-variants (mf/use-fn #(st/emit! (dwv/combine-as-variants)))
do-add-variant (mf/use-fn
(mf/deps shapes)
#(st/emit! (dwv/add-new-variant (:id (first shapes)))))]
#(st/emit!
(ptk/event ::ev/event {::ev/name "add-new-variant" :trigger "context-menu-component"})
(dwv/add-new-variant (:id (first shapes)))))]
[:*
(when can-make-component ;; We don't want to change the structure of component copies
[:*

View File

@ -17,6 +17,7 @@
[app.common.types.file :as ctf]
[app.common.types.variant :as ctv]
[app.config :as cf]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
@ -38,6 +39,7 @@
[app.util.timers :as ts]
[cljs.spec.alpha :as s]
[cuerdas.core :as str]
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(def assets-filters (mf/create-context nil))
@ -323,7 +325,7 @@
:is-hidden is-hidden}])))
(defn generate-components-menu-entries
[shapes]
[shapes & {:keys [for-design-tab?]}]
(let [multi (> (count shapes) 1)
copies (filter ctk/in-component-copy? shapes)
@ -434,12 +436,19 @@
do-add-variant
#(if (ctk/is-variant? shape)
(st/emit! (dwv/add-new-variant id))
(st/emit! (dwv/transform-in-variant id)))
(st/emit!
(ptk/event ::ev/event {::ev/name "add-new-variant"
:trigger (if for-design-tab? "design-tab-menu-variant" "context-menu-variant")})
(dwv/add-new-variant id))
(st/emit!
(ptk/event ::ev/event {::ev/name "transform-in-variant"
:trigger (if for-design-tab? "design-tab-menu" "context-menu")})
(dwv/transform-in-variant id)))
do-add-new-property
#(st/emit! (dwv/add-new-property variant-id {:property-value "Value 1"
:editing? true}))
#(st/emit!
(ptk/event ::ev/event {::ev/name "add-new-property" :trigger "design-tab-menu-variant"})
(dwv/add-new-property variant-id {:property-value "Value 1" :editing? true}))
do-show-local-component
#(st/emit! (dwl/go-to-local-component :id component-id))
@ -500,7 +509,7 @@
{:title (tr "workspace.shape.menu.add-variant")
:shortcut :create-component
:action do-add-variant})
(when (and same-variant? main-instance? variant-id)
(when (and same-variant? main-instance? variant-id for-design-tab?)
{:title (tr "workspace.shape.menu.add-variant-property")
:action do-add-new-property})]]
(filter (complement nil?) menu-entries)))

View File

@ -17,6 +17,7 @@
[app.common.types.file :as ctf]
[app.common.types.variant :as ctv]
[app.common.uuid :as uuid]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
@ -47,6 +48,7 @@
[app.util.timers :as tm]
[cuerdas.core :as str]
[okulary.core :as l]
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(def ref:annotations-state
@ -239,7 +241,6 @@
(when (or editing? creating?)
[:div {:class (stl/css :counter)} (str size "/300")])]])))
(defn- get-variant-malformed-warning-message
"Receive a list of booleans, one for each selected variant, indicating if that variant
is malformed, and generate a warning message accordingly"
@ -256,7 +257,6 @@
:else nil))
(defn- get-variant-duplicated-warning-message
"Receive a list of booleans, one for each selected variant, indicating if that variant
is duplicated, and generate a warning message accordingly"
@ -273,7 +273,6 @@
:else nil))
(defn- get-components-with-duplicated-variant-props-and-values
"Get a list of components whose property names and values are duplicated"
[components]
@ -293,7 +292,6 @@
get-components-with-duplicated-variant-props-and-values
(map :main-instance-id)))
(defn- get-variant-options
"Get variant options for a given property name"
[prop-name prop-vals]
@ -303,7 +301,6 @@
(mapv (fn [val] {:id val
:label (if (str/blank? val) (str "(" (tr "labels.empty") ")") val)}))))
(mf/defc component-variant-main-instance*
[{:keys [components shapes data]}]
(let [component (first components)
@ -345,7 +342,9 @@
(fn [pos value]
(let [value (d/nilv (str/trim value) "")]
(doseq [id component-ids]
(st/emit! (dwv/update-property-value id pos value))
(st/emit!
(ptk/event ::ev/event {::ev/name "variant-edit-property-value" :trigger "combo-design-tab"})
(dwv/update-property-value id pos value))
(st/emit! (dwv/update-error id))))))
update-property-name
@ -357,7 +356,9 @@
(dom/get-data "position")
int)]
(when (seq value)
(st/emit! (dwv/update-property-name variant-id pos value))))))]
(st/emit!
(ptk/event ::ev/event {::ev/name "variant-edit-property-name" :trigger "design-tab-variant"})
(dwv/update-property-name variant-id pos value))))))]
[:*
[:div {:class (stl/css :variant-property-list)}
@ -398,7 +399,6 @@
[:div {:class (stl/css :variant-warning-highlight)}
(str duplicated-msg)]]))]))
(mf/defc component-variant-copy*
[{:keys [component shape data current-file-id]}]
(let [page-objects (mf/deref refs/workspace-page-objects)
@ -514,7 +514,6 @@
:on-click select-duplicated-comps}
(tr "workspace.options.component.variant.duplicated.copy.locate")]]))]))
(mf/defc component-swap-item*
[{:keys [item loop shapes file-id root-shape container component-id is-search listing-thumbs num-variants]}]
(let [on-select
@ -627,7 +626,6 @@
is-search? (not (str/blank? (:term filters)))
current-library-id (if (contains? libraries (:file-id filters))
(:file-id filters)
current-file-id)
@ -638,7 +636,6 @@
current-lib-data (get-in libraries [current-library-id :data])
components (->> (get-in libraries [current-library-id :data :components])
vals
(remove #(true? (:deleted %)))
@ -688,7 +685,6 @@
;; Get the ids of the components that are parents of the shapes, to avoid loops
parent-components (mapcat find-parent-components shapes)
libraries-options (map (fn [library] {:value (:id library) :label (:name library)})
(vals libraries))
@ -702,7 +698,6 @@
(fn [term]
(swap! filters* assoc :term term)))
on-search-clear-click
(mf/use-fn #(swap! filters* assoc :term ""))
@ -817,8 +812,6 @@
:on-click (partial do-action action)}
[:span {:class (stl/css :dropdown-label)} title]]))]]))
(mf/defc component-menu
{::mf/props :obj}
[{:keys [shapes swap-opened?]}]
@ -827,7 +820,6 @@
libraries (mf/deref refs/files)
current-file (get libraries current-file-id)
state* (mf/use-state
#(do {:show-content true
:menu-open false}))
@ -903,13 +895,17 @@
create-variant
(mf/use-fn
(mf/deps id)
#(st/emit! (dwv/add-new-variant id)))
#(st/emit!
(ptk/event ::ev/event {::ev/name "add-new-variant" :trigger "button-design-tab-variant"})
(dwv/add-new-variant id)))
add-new-property
(mf/use-fn
(mf/deps shape)
#(st/emit! (dwv/add-new-property (:variant-id shape) {:property-value "Value 1"
:editing? true})))
#(st/emit!
(ptk/event ::ev/event {::ev/name "add-new-property" :trigger "button-design-tab-variant"})
(dwv/add-new-property (:variant-id shape) {:property-value "Value 1"
:editing? true})))
on-combine-as-variants
(mf/use-fn
@ -926,7 +922,7 @@
(fn []
(swap! state* update :render inc)))
menu-entries (cmm/generate-components-menu-entries shapes)
menu-entries (cmm/generate-components-menu-entries shapes {:for-design-tab? true})
show-menu? (seq menu-entries)
path (->> component (:path) (cfh/split-path) (cfh/join-path-with-dot))]
@ -1047,7 +1043,6 @@
(when (dbg/enabled? :display-touched)
[:div ":touched " (str (:touched shape))])])])))
(defn- move-empty-items-to-end
"Creates a new vector with the empty items at the end"
[v]
@ -1055,7 +1050,6 @@
(into (remove empty?) v)
(into (filter empty?) v)))
(mf/defc variant-menu*
[{:keys [shapes]}]
(let [multi? (> (count shapes) 1)
@ -1095,18 +1089,23 @@
create-variant
(mf/use-fn
(mf/deps shape)
#(st/emit! (dwv/add-new-variant (:id shape))))
(fn [trigger]
(st/emit! (ptk/event ::ev/event {::ev/name "add-new-variant" :trigger trigger})
(dwv/add-new-variant (:id shape)))))
add-new-property
(mf/use-fn
(mf/deps variant-id)
#(st/emit! (dwv/add-new-property variant-id {:property-value "Value 1"
:editing? true})))
(fn [trigger]
(st/emit!
(ptk/event ::ev/event {::ev/name "add-new-property" :trigger trigger})
(dwv/add-new-property variant-id {:property-value "Value 1"
:editing? true}))))
menu-entries [{:title (tr "workspace.shape.menu.add-variant-property")
:action add-new-property}
:action (partial add-new-property "design-tab-menu-component")}
{:title (tr "workspace.shape.menu.add-variant")
:action create-variant}]
:action (partial create-variant "design-tab-menu-component")}]
toggle-content
(mf/use-fn
@ -1140,7 +1139,9 @@
(dom/get-data "position")
int)]
(when (seq value)
(st/emit! (dwv/update-property-name variant-id pos value))))))
(st/emit!
(ptk/event ::ev/event {::ev/name "variant-edit-property-name" :trigger "design-tab-component"})
(dwv/update-property-name variant-id pos value))))))
remove-property
(mf/use-fn
@ -1150,7 +1151,9 @@
(dom/get-data "position")
int)]
(when (> (count properties) 1)
(st/emit! (dwv/remove-property variant-id pos))))))
(st/emit!
(ptk/event ::ev/event {::ev/name "variant-remove-property" :trigger "button-design-tab"})
(dwv/remove-property variant-id pos))))))
select-shapes-with-malformed
(mf/use-fn
@ -1183,7 +1186,7 @@
:icon i/help}]
[:> icon-button* {:variant "ghost"
:aria-label (tr "workspace.shape.menu.add-variant")
:on-click create-variant
:on-click (partial create-variant "button-design-tab-component")
:icon i/variant}]]]]
(when open?
@ -1221,7 +1224,7 @@
[:> icon-button* {:variant "ghost"
:aria-label (tr "workspace.shape.menu.add-variant-property")
:on-click add-new-property
:on-click (partial add-new-property "button-design-tab-component")
:icon i/add}]]
(when-not multi?