From 3566b9ec00f5605bfbb47ea7187207894f559696 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Wed, 1 Oct 2025 18:21:15 +0200 Subject: [PATCH] :tada: Add variants to plugins API --- common/src/app/common/files/variant.cljc | 25 ++-- .../app/common/logic/variant_properties.cljc | 27 ++-- .../sidebar/options/menus/component.cljs | 3 +- frontend/src/app/plugins/library.cljs | 136 ++++++++++-------- frontend/src/app/plugins/shape.cljs | 49 +++++-- frontend/src/app/plugins/tokens.cljs | 10 +- 6 files changed, 155 insertions(+), 95 deletions(-) diff --git a/common/src/app/common/files/variant.cljc b/common/src/app/common/files/variant.cljc index 340c324b64..e2378acbb0 100644 --- a/common/src/app/common/files/variant.cljc +++ b/common/src/app/common/files/variant.cljc @@ -10,16 +10,23 @@ [app.common.types.components-list :as ctcl] [app.common.types.variant :as ctv])) - (defn find-variant-components "Find a list of the components thet belongs to this variant-id" - [data objects variant-id] - ;; We can't simply filter components, because we need to maintain the order - (->> (dm/get-in objects [variant-id :shapes]) - (map #(dm/get-in objects [% :component-id])) - (map #(ctcl/get-component data % true)) - reverse)) - + ([data variant-id] + (let [page-id (->> data + :components + vals + (filter #(= (:variant-id %) variant-id)) + first + :main-instance-page) + objects (dm/get-in data [:pages-index page-id :objects])] + (find-variant-components data objects variant-id))) + ([data objects variant-id] + ;; We can't simply filter components, because we need to maintain the order + (->> (dm/get-in objects [variant-id :shapes]) + (map #(dm/get-in objects [% :component-id])) + (map #(ctcl/get-component data % true)) + reverse))) (defn extract-properties-names [shape data] @@ -28,7 +35,6 @@ :variant-properties (map :name))) - (defn extract-properties-values "Get a map of properties associated to their possible values" [data objects variant-id] @@ -50,7 +56,6 @@ (get :objects))] (dm/get-in objects [variant-id :shapes])))) - (defn is-secondary-variant? [component data] (let [shapes (get-variant-mains component data)] diff --git a/common/src/app/common/logic/variant_properties.cljc b/common/src/app/common/logic/variant_properties.cljc index d5761a2b02..295f7020e7 100644 --- a/common/src/app/common/logic/variant_properties.cljc +++ b/common/src/app/common/logic/variant_properties.cljc @@ -42,18 +42,21 @@ [changes variant-id pos] (let [data (pcb/get-library-data changes) objects (pcb/get-objects changes) - related-components (cfv/find-variant-components data objects variant-id)] - (reduce (fn [changes component] - (let [props (:variant-properties component) - props (d/remove-at-index props pos) - main-id (:main-instance-id component) - name (ctv/properties-to-name props)] - (-> changes - (pcb/update-component (:id component) #(assoc % :variant-properties props) - {:apply-changes-local-library? true}) - (pcb/update-shapes [main-id] #(assoc % :variant-name name))))) - changes - related-components))) + related-components (cfv/find-variant-components data objects variant-id) + props (-> related-components first :variant-properties)] + (if (and (seq props) (<= 0 pos) (< pos (count props))) + (reduce (fn [changes component] + (let [props (:variant-properties component) + props (d/remove-at-index props pos) + main-id (:main-instance-id component) + name (ctv/properties-to-name props)] + (-> changes + (pcb/update-component (:id component) #(assoc % :variant-properties props) + {:apply-changes-local-library? true}) + (pcb/update-shapes [main-id] #(assoc % :variant-name name))))) + changes + related-components) + changes))) (defn generate-update-property-value diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index 0065e29507..d54328919f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -632,7 +632,8 @@ current-lib-data (get-in libraries [current-library-id :data]) - components (->> (get-in libraries [current-library-id :data :components]) + components (->> current-lib-data + :components vals (remove #(true? (:deleted %))) (remove #(cfv/is-secondary-variant? % current-lib-data)) diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index b86ba5d954..44bb9fd17b 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -8,12 +8,15 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.files.variant :as cfv] [app.common.geom.point :as gpt] [app.common.schema :as sm] [app.common.types.color :as clr] + [app.common.types.component :as ctk] [app.common.types.file :as ctf] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] + [app.main.data.event :as ev] [app.main.data.plugins :as dp] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.texts :as dwt] @@ -614,9 +617,7 @@ (defn get-variant-components [file-id variant-id] - (->> (dm/get-in (u/locate-file file-id) [:data :components]) - (map second) - (filter #(= (:variant-id %) variant-id)))) + (cfv/find-variant-components (-> file-id u/locate-file :data) variant-id)) (declare lib-component-proxy) @@ -640,15 +641,8 @@ (set) (apply array)))} - :errors - {:this true - :get (fn [_] - ;; TODO - )} - :currentValues (fn [property] - ;; TODO: validate input (->> (get-variant-components file-id id) (map (fn [{:keys [variant-properties]}] @@ -658,31 +652,39 @@ (set) (apply array))) - :deleteProperty - (fn [_property] - ;; TODO - ) - - :findComponents - (fn [props] - ;; TODO: Parse input - ;; TODO: Probably not the best way to find the components - (letfn [(match-props [{:keys [variant-properties]}] - (->> (js/Object.keys props) - (every? (fn [p] - (= (obj/get props p) - (-> (d/seek #(= (:name %) p) variant-properties) - :value))))))] - (->> (get-variant-components file-id id) - (filter match-props) - (keep :id) - (map #(lib-component-proxy plugin-id file-id %)) - (apply array)))) + :variantComponents + (fn [] + (->> (get-variant-components file-id id) + (map :id) + (map #(lib-component-proxy plugin-id file-id %)) + (apply array))) :addVariant (fn [] - ;; TODO - ))) + (st/emit! + (ev/event {::ev/name "add-new-variant" ::ev/origin "plugin:add-variant"}) + (dwv/add-new-variant id))) + + + :addProperty + (fn [] + (st/emit! + (ev/event {::ev/name "add-new-property" ::ev/origin "plugin:add-property"}) + (dwv/add-new-property id {:property-value "Value 1"}))) + + :removeProperty + (fn [pos] + (st/emit! + (ev/event {::ev/name "remove-property" ::ev/origin "plugin:remove-property"}) + (dwv/remove-property id pos))) + + :renameProperty + (fn [pos name] + (st/emit! + (dwv/update-property-name id pos name {:trigger "plugin:rename-property"}))))) + + +(set! shape/variant-proxy variant-proxy) (defn lib-component-proxy? [p] (obj/type-of? p "LibraryComponentProxy")) @@ -837,30 +839,61 @@ (when (some? root) (shape/shape-proxy plugin-id file-id (:main-instance-page component) (:id root))))) + :isVariant + (fn [] + (let [component (u/locate-library-component file-id id)] + (ctk/is-variant? component))) + :variants {:enumerable false :get (fn [] (let [component (u/locate-library-component file-id id)] - (when (some? (:variant-id component)) + (when (ctk/is-variant? component) (variant-proxy plugin-id file-id (:variant-id component)))))} :variantProps {:get (fn [] (let [component (u/locate-library-component file-id id)] - (when (some? (:variant-id component)) + (when (ctk/is-variant? component) (->> (:variant-properties component) (reduce (fn [acc {:keys [name value]}] (obj/set! acc name value)) #js {})))))} - :variantErrors - {:get (fn [])} + :variantError + {:get (fn [] + (let [file (u/locate-file file-id) + component (u/locate-library-component file-id id) + root (ctf/get-component-root (:data file) component)] + (when (ctk/is-variant? component) + (:variant-error root))))} + + :transformInVariant + (fn [] + (let [component (u/locate-library-component file-id id)] + (when (and component + (not (ctk/is-variant? component))) + (st/emit! + (ev/event {::ev/name "transform-in-variant" ::ev/origin "plugin:transform-in-variant"}) + (dwv/transform-in-variant (:main-instance-id component)))))) + + :addVariant + (fn [] + (let [component (u/locate-library-component file-id id)] + (when (and component + (ctk/is-variant? component)) + (st/emit! + (ev/event {::ev/name "add-new-variant" ::ev/origin "plugin:add-variant-from-component"}) + (dwv/add-new-variant (:main-instance-id component)))))) :setVariantProperty - (fn [_property _value]))) + (fn [pos value] + (st/emit! + (ev/event {::ev/name "variant-edit-property-value" ::ev/origin "plugin:edit-property-value"}) + (dwv/update-property-value id pos value))))) (defn library-proxy? [p] (obj/type-of? p "LibraryProxy")) @@ -901,27 +934,14 @@ {:this true :get (fn [_] - (let [file (u/locate-file file-id) - components - (concat - (->> file - :data - :components - (remove (comp :deleted second)) - (remove (comp :variant-id second)) - (map first) - (map #(lib-component-proxy plugin-id file-id %))) - - (->> file - :data - :components - (remove (comp :deleted second)) - (filter (comp :variant-id second)) - (map second) - (group-by :variant-id) - ;; TODO: This is not the way to locate the variant main component - (map (comp :id first second)) - (map #(lib-component-proxy plugin-id file-id %))))] + (let [file (u/locate-file file-id) + data (:data file) + components (->> data + :components + (remove (comp :deleted second)) + (remove (comp #(cfv/is-secondary-variant? % data) second)) + (map first) + (map #(lib-component-proxy plugin-id file-id %)))] (apply array components)))} :tokens diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index ec48467623..f0ac7b423a 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -41,6 +41,7 @@ [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.texts :as dwt] + [app.main.data.workspace.variants :as dwv] [app.main.repo :as rp] [app.main.store :as st] [app.plugins.flex :as flex] @@ -57,6 +58,8 @@ (declare shape-proxy) (declare shape-proxy?) +;; This is injected from plugin/librraies +(def variant-proxy) (defn interaction-proxy? [p] (obj/type-of? p "InteractionProxy")) @@ -761,6 +764,8 @@ ;; Interactions + + :interactions {:this true :get @@ -1234,7 +1239,6 @@ (let [guide (u/proxy->ruler-guide value)] (st/emit! (dwgu/remove-guide guide))))) - :applyToken (fn [_property _token] ;; TODO @@ -1251,16 +1255,34 @@ ;; TODO swap component ) - :isVariantCopy + :isVariantHead (fn [] - ;; TODO - ) + (let [shape (u/locate-shape file-id page-id id) + component (u/locate-library-component file-id (:component-id shape))] + (and (ctk/instance-head? shape) (ctk/is-variant? component)))) + + :isVariantContainer + (fn [] + (let [shape (u/locate-shape file-id page-id id)] + (ctk/is-variant-container? shape))) :switchVariant - (fn [_property _value] - ;; TODO validate input - ;; TODO switch variant - )) + (fn [pos value] + (let [shape (u/locate-shape file-id page-id id) + component (u/locate-library-component file-id (:component-id shape))] + (when (and component (ctk/is-variant? component)) + (st/emit! (dwv/variants-switch {:shapes [shape] :pos pos :val value}))))) + + :combineAsVariants + (fn [ids] + (let [shape (u/locate-shape file-id page-id id) + component (u/locate-library-component file-id (:component-id shape)) + ids (->> ids + (map uuid/uuid) + (into #{id}))] + (when (and component (not (ctk/is-variant? component))) + (st/emit! + (dwv/combine-as-variants ids {:trigger "plugin:combine-as-variants"})))))) (cond-> (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)) (crc/add-properties! @@ -1377,7 +1399,16 @@ (u/display-not-valid :verticalSizing "Plugin doesn't have 'content:write' permission") :else - (st/emit! (dwsl/update-layout #{id} {:layout-item-v-sizing value})))))}))) + (st/emit! (dwsl/update-layout #{id} {:layout-item-v-sizing value})))))} + + + {:name "variants" + :enumerable false + :get + (fn [self] + (let [shape (-> self u/proxy->shape)] + (when (ctk/is-variant-container? shape) + (variant-proxy plugin-id file-id (:id shape)))))}))) (cond-> (cfh/text-shape? data) (text/add-text-props plugin-id)) diff --git a/frontend/src/app/plugins/tokens.cljs b/frontend/src/app/plugins/tokens.cljs index f21b000c9d..0985c17fac 100644 --- a/frontend/src/app/plugins/tokens.cljs +++ b/frontend/src/app/plugins/tokens.cljs @@ -16,7 +16,7 @@ [file-id group name] (let [file (u/locate-file file-id) tokens-lib (->> file :data :tokens-lib)] - (cttl/get-theme tokens-lib group name))) + #_(cttl/get-theme tokens-lib group name))) (defn locate-token-set [file-id set-name] @@ -28,7 +28,7 @@ [file-id set-name token-id] (let [file (u/locate-file file-id) tokens-lib (->> file :data :tokens-lib)] - (cttl/get-token-in-set tokens-lib set-name token-id))) + #_(cttl/get-token-in-set tokens-lib set-name token-id))) (defn token-proxy [plugin-id file-id set-name id] @@ -86,9 +86,9 @@ (let [file (u/locate-file file-id) tokens-lib (->> file :data :tokens-lib) token-set (cttl/get-set tokens-lib set-name)] - (->> (cttl/get-tokens token-set) - (map #(token-proxy plugin-id file-id set-name (:id %))) - (apply array))))})) + #_(->> (cttl/get-tokens token-set) + (map #(token-proxy plugin-id file-id set-name (:id %))) + (apply array))))})) (defn theme-proxy [plugin-id file-id group name]