diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 2476f3ca30..83e38f6426 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -32,12 +32,6 @@ ;; ;; PLUGINS PUBLIC API - The plugins will able to access this functions ;; -(def ^:private - xf-map-shape-proxy - (comp - (map val) - (map shape/data->shape-proxy))) - (defn create-shape [type] (let [page-id (:current-page-id @st/state) @@ -50,7 +44,7 @@ (cb/with-objects (:objects page)) (cb/add-object shape))] (st/emit! (ch/commit-changes changes)) - (shape/data->shape-proxy shape))) + (shape/shape-proxy (:id shape)))) (deftype PenpotContext [] Object @@ -64,13 +58,13 @@ (getFile [_] - (file/data->file-proxy (:workspace-file @st/state) (:workspace-data @st/state))) + (file/file-proxy (:current-file-id @st/state))) (getPage [_] - (let [page-id (:current-page-id @st/state) - page (dm/get-in @st/state [:workspace-data :pages-index page-id])] - (page/data->page-proxy page))) + (let [file-id (:current-file-id @st/state) + page-id (:current-page-id @st/state)] + (page/page-proxy file-id page-id))) (getSelected [_] @@ -79,17 +73,12 @@ (getSelectedShapes [_] - (let [page-id (:current-page-id @st/state) - selection (get-in @st/state [:workspace-local :selected]) - objects (dm/get-in @st/state [:workspace-data :pages-index page-id :objects]) - shapes (select-keys objects selection)] - (apply array (sequence xf-map-shape-proxy shapes)))) + (let [selection (get-in @st/state [:workspace-local :selected])] + (apply array (sequence (map shape/shape-proxy) selection)))) (getRoot [_] - (let [page-id (:current-page-id @st/state) - root (dm/get-in @st/state [:workspace-data :pages-index page-id :objects uuid/zero])] - (shape/data->shape-proxy root))) + (shape/shape-proxy uuid/zero)) (getTheme [_] @@ -100,7 +89,7 @@ (uploadMediaUrl [_ name url] - (let [file-id (get-in @st/state [:workspace-file :id])] + (let [file-id (:current-file-id @st/state)] (p/create (fn [resolve reject] (->> (dwm/upload-media-url name file-id url) @@ -110,17 +99,17 @@ (group [_ shapes] - (let [page-id (:current-page-id @st/state) + (let [file-id (:current-file-id @st/state) + page-id (:current-page-id @st/state) id (uuid/next) - ids (into #{} (map #(get (obj/get % "_data") :id)) shapes)] + ids (into #{} (map #(obj/get % "$id")) shapes)] (st/emit! (dwg/group-shapes id ids)) - (shape/data->shape-proxy - (dm/get-in @st/state [:workspace-data :pages-index page-id :objects id])))) + (shape/shape-proxy file-id page-id id))) (ungroup [_ group & rest] (let [shapes (concat [group] rest) - ids (into #{} (map #(get (obj/get % "_data") :id)) shapes)] + ids (into #{} (map #(obj/get % "$id")) shapes)] (st/emit! (dwg/ungroup-shapes ids)))) (createFrame @@ -133,7 +122,8 @@ (createText [_ text] - (let [page-id (:current-page-id @st/state) + (let [file-id (:current-file-id @st/state) + page-id (:current-page-id @st/state) page (dm/get-in @st/state [:workspace-data :pages-index page-id]) shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width}) (txt/change-text text) @@ -144,22 +134,23 @@ (cb/with-objects (:objects page)) (cb/add-object shape))] (st/emit! (ch/commit-changes changes)) - (shape/data->shape-proxy shape))) + (shape/shape-proxy file-id page-id (:id shape)))) (createShapeFromSvg [_ svg-string] (when (some? svg-string) (let [id (uuid/next) + file-id (:current-file-id @st/state) page-id (:current-page-id @st/state)] (st/emit! (dwm/create-svg-shape id "svg" svg-string (gpt/point 0 0))) - (shape/data->shape-proxy - (dm/get-in @st/state [:workspace-data :pages-index page-id :objects id])))))) + (shape/shape-proxy file-id page-id id))))) (defn create-context [] (cr/add-properties! (PenpotContext.) {:name "root" :get #(.getRoot ^js %)} + {:name "currentFile" :get #(.getFile ^js %)} {:name "currentPage" :get #(.getPage ^js %)} {:name "selection" :get #(.getSelectedShapes ^js %)} {:name "viewport" :get #(.getViewport ^js %)} diff --git a/frontend/src/app/plugins/events.cljs b/frontend/src/app/plugins/events.cljs index 6963174aba..aaf768cf9c 100644 --- a/frontend/src/app/plugins/events.cljs +++ b/frontend/src/app/plugins/events.cljs @@ -23,17 +23,18 @@ (if (and (identical? old-file new-file) (identical? old-data new-data)) ::not-changed - (file/data->file-proxy new-file new-data)))) + (file/file-proxy (:id new-file))))) (defmethod handle-state-change "pagechange" [_ old-val new-val] - (let [old-page-id (:current-page-id old-val) + (let [file-id (:current-file-id new-val) + old-page-id (:current-page-id old-val) new-page-id (:current-page-id new-val) old-page (dm/get-in old-val [:workspace-data :pages-index old-page-id]) new-page (dm/get-in new-val [:workspace-data :pages-index new-page-id])] (if (identical? old-page new-page) ::not-changed - (page/data->page-proxy new-page)))) + (page/page-proxy file-id new-page-id)))) (defmethod handle-state-change "selectionchange" [_ old-val new-val] diff --git a/frontend/src/app/plugins/file.cljs b/frontend/src/app/plugins/file.cljs index 6d3948bf5e..a3f576debe 100644 --- a/frontend/src/app/plugins/file.cljs +++ b/frontend/src/app/plugins/file.cljs @@ -7,38 +7,34 @@ (ns app.plugins.file "RPC for plugins runtime." (:require + [app.common.data.macros :as dm] [app.common.record :as crc] [app.plugins.page :as page] - [app.plugins.utils :refer [get-data-fn]])) + [app.plugins.utils :refer [locate-file proxy->file]] + [app.util.object :as obj])) -(def ^:private - xf-map-page-proxy - (comp - (map val) - (map page/data->page-proxy))) - -(deftype FileProxy [#_:clj-kondo/ignore _data] +(deftype FileProxy [$id] Object (getPages [_] - ;; Returns a lazy (iterable) of all available pages - (apply array (sequence xf-map-page-proxy (:pages-index _data))))) + (let [file (locate-file $id)] + (apply array (sequence (map #(page/page-proxy $id %)) (dm/get-in file [:data :pages])))))) (crc/define-properties! FileProxy {:name js/Symbol.toStringTag :get (fn [] (str "FileProxy"))}) -(defn data->file-proxy - [file data] +(defn file-proxy + [id] (crc/add-properties! - (FileProxy. (merge file data)) - {:name "_data" :enumerable false} + (FileProxy. id) + {:name "$id" :enumerable false} {:name "id" - :get (get-data-fn :id str)} + :get #(dm/str (obj/get % "$id"))} {:name "name" - :get (get-data-fn :name)} + :get #(-> % proxy->file :name)} {:name "pages" :get #(.getPages ^js %)})) diff --git a/frontend/src/app/plugins/grid.cljs b/frontend/src/app/plugins/grid.cljs index 6c39df7f87..4f9ac49799 100644 --- a/frontend/src/app/plugins/grid.cljs +++ b/frontend/src/app/plugins/grid.cljs @@ -10,11 +10,10 @@ [app.common.record :as crc] [app.common.spec :as us] [app.common.types.shape.layout :as ctl] - [app.common.uuid :as uuid] [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.transforms :as dwt] [app.main.store :as st] - [app.plugins.utils :as utils :refer [get-data get-state]] + [app.plugins.utils :as utils :refer [proxy->shape]] [app.util.object :as obj] [potok.v2.core :as ptk])) @@ -24,183 +23,176 @@ js/Object (apply array (->> tracks (map utils/to-js))))) -(deftype GridLayout [_data] +(deftype GridLayout [$file $page $id] Object (addRow - [self type value] - (let [id (get-data self :id) - type (keyword type)] - (st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value})))) + [_ type value] + (let [type (keyword type)] + (st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value})))) (addRowAtIndex - [self index type value] - (let [id (get-data self :id) - type (keyword type)] - (st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value} index)))) + [_ index type value] + (let [type (keyword type)] + (st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value} index)))) (addColumn - [self type value] - (let [id (get-data self :id) - type (keyword type)] - (st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value})))) + [_ type value] + (let [type (keyword type)] + (st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value})))) (addColumnAtIndex - [self index type value] - (let [id (get-data self :id) - type (keyword type)] - (st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value} index)))) + [_ index type value] + (let [type (keyword type)] + (st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value} index)))) (removeRow - [self index] - (let [id (get-data self :id)] - (st/emit! (dwsl/remove-layout-track #{id} :row index)))) + [_ index] + (st/emit! (dwsl/remove-layout-track #{$id} :row index))) (removeColumn - [self index] - (let [id (get-data self :id)] - (st/emit! (dwsl/remove-layout-track #{id} :column index)))) + [_ index] + (st/emit! (dwsl/remove-layout-track #{$id} :column index))) (setColumn - [self index type value] - (let [id (get-data self :id) - type (keyword type)] - (st/emit! (dwsl/change-layout-track #{id} :column index (d/without-nils {:type type :value value}))))) + [_ index type value] + (let [type (keyword type)] + (st/emit! (dwsl/change-layout-track #{$id} :column index (d/without-nils {:type type :value value}))))) (setRow - [self index type value] - (let [id (get-data self :id) - type (keyword type)] - (st/emit! (dwsl/change-layout-track #{id} :row index (d/without-nils {:type type :value value}))))) + [_ index type value] + (let [type (keyword type)] + (st/emit! (dwsl/change-layout-track #{$id} :row index (d/without-nils {:type type :value value}))))) (remove - [self] - (let [id (get-data self :id)] - (st/emit! (dwsl/remove-layout #{id})))) + [_] + (st/emit! (dwsl/remove-layout #{$id}))) (appendChild - [self child row column] - (let [parent-id (get-data self :id) - child-id (uuid/uuid (obj/get child "id"))] - (st/emit! (dwt/move-shapes-to-frame #{child-id} parent-id nil [row column]) - (ptk/data-event :layout/update {:ids [parent-id]}))))) + [_ child row column] + (let [child-id (obj/get child "$id")] + (st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil [row column]) + (ptk/data-event :layout/update {:ids [$id]}))))) (defn grid-layout-proxy - [data] - (-> (GridLayout. data) + [file-id page-id id] + (-> (GridLayout. file-id page-id id) (crc/add-properties! + {:name "$id" :enumerable false} + {:name "$file" :enumerable false} + {:name "$page" :enumerable false} {:name "dir" - :get #(get-state % :layout-grid-dir d/name) + :get #(-> % proxy->shape :layout-grid-dir d/name) :set (fn [self value] - (let [id (get-data self :id) + (let [id (obj/get self "$id") value (keyword value)] (when (contains? ctl/grid-direction-types value) (st/emit! (dwsl/update-layout #{id} {:layout-grid-dir value})))))} {:name "rows" - :get #(get-state % :layout-grid-rows make-tracks)} + :get #(-> % proxy->shape :layout-grid-rows make-tracks)} {:name "columns" - :get #(get-state % :layout-grid-columns make-tracks)} + :get #(-> % proxy->shape :layout-grid-columns make-tracks)} {:name "alignItems" - :get #(get-state % :layout-align-items d/name) + :get #(-> % proxy->shape :layout-align-items d/name) :set (fn [self value] - (let [id (get-data self :id) + (let [id (obj/get self "$id") value (keyword value)] (when (contains? ctl/align-items-types value) (st/emit! (dwsl/update-layout #{id} {:layout-align-items value})))))} {:name "alignContent" - :get #(get-state % :layout-align-content d/name) + :get #(-> % proxy->shape :layout-align-content d/name) :set (fn [self value] - (let [id (get-data self :id) + (let [id (obj/get self "$id") value (keyword value)] (when (contains? ctl/align-content-types value) (st/emit! (dwsl/update-layout #{id} {:layout-align-content value})))))} {:name "justifyItems" - :get #(get-state % :layout-justify-items d/name) + :get #(-> % proxy->shape :layout-justify-items d/name) :set (fn [self value] - (let [id (get-data self :id) + (let [id (obj/get self "$id") value (keyword value)] (when (contains? ctl/justify-items-types value) (st/emit! (dwsl/update-layout #{id} {:layout-justify-items value})))))} {:name "justifyContent" - :get #(get-state % :layout-justify-content d/name) + :get #(-> % proxy->shape :layout-justify-content d/name) :set (fn [self value] - (let [id (get-data self :id) + (let [id (obj/get self "$id") value (keyword value)] (when (contains? ctl/justify-content-types value) (st/emit! (dwsl/update-layout #{id} {:layout-justify-content value})))))} {:name "rowGap" - :get #(:row-gap (get-state % :layout-gap)) + :get #(-> % proxy->shape :layout-gap :row-gap) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))} {:name "columnGap" - :get #(:column-gap (get-state % :layout-gap)) + :get #(-> % proxy->shape :layout-gap :column-gap) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))} {:name "verticalPadding" - :get #(:p1 (get-state % :layout-padding)) + :get #(-> % proxy->shape :layout-padding :p1) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))} {:name "horizontalPadding" - :get #(:p2 (get-state % :layout-padding)) + :get #(-> % proxy->shape :layout-padding :p2) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))} {:name "topPadding" - :get #(:p1 (get-state % :layout-padding)) + :get #(-> % proxy->shape :layout-padding :p1) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))} {:name "rightPadding" - :get #(:p2 (get-state % :layout-padding)) + :get #(-> % proxy->shape :layout-padding :p2) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))} {:name "bottomPadding" - :get #(:p3 (get-state % :layout-padding)) + :get #(-> % proxy->shape :layout-padding :p3) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))} {:name "leftPadding" - :get #(:p4 (get-state % :layout-padding)) + :get #(-> % proxy->shape :layout-padding :p4) :set (fn [self value] - (let [id (get-data self :id)] + (let [id (obj/get self "$id")] (when (us/safe-int? value) (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))}))) diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index b287b1d078..3e5f28c661 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -7,46 +7,48 @@ (ns app.plugins.page "RPC for plugins runtime." (:require + [app.common.data.macros :as dm] [app.common.record :as crc] [app.common.uuid :as uuid] [app.plugins.shape :as shape] - [app.plugins.utils :refer [get-data-fn]])) + [app.plugins.utils :refer [locate-page proxy->page]] + [app.util.object :as obj])) -(def ^:private - xf-map-shape-proxy - (comp - (map val) - (map shape/data->shape-proxy))) - -(deftype PageProxy [#_:clj-kondo/ignore _data] +(deftype PageProxy [$file $id] Object - (getShapeById [_ id] - (shape/data->shape-proxy (get (:objects _data) (uuid/uuid id)))) + (getShapeById + [_ shape-id] + (let [shape-id (uuid/uuid shape-id)] + (shape/shape-proxy $file $id shape-id))) - (getRoot [_] - (shape/data->shape-proxy (get (:objects _data) uuid/zero))) + (getRoot + [_] + (shape/shape-proxy $file $id uuid/zero)) - (findShapes [_] + (findShapes + [_] ;; Returns a lazy (iterable) of all available shapes - (apply array (sequence xf-map-shape-proxy (:objects _data))))) + (let [page (locate-page $file $id)] + (apply array (sequence (map shape/shape-proxy) (keys (:objects page))))))) (crc/define-properties! PageProxy {:name js/Symbol.toStringTag :get (fn [] (str "PageProxy"))}) -(defn data->page-proxy - [data] - +(defn page-proxy + [file-id id] (crc/add-properties! - (PageProxy. data) - {:name "_data" :enumerable false} + (PageProxy. file-id id) + {:name "$file" :enumerable false} + {:name "$id" :enumerable false} {:name "id" - :get (get-data-fn :id str)} + :get #(dm/str (obj/get % "$id"))} {:name "name" - :get (get-data-fn :name)} + :get #(-> % proxy->page :name)} {:name "root" + :enumerable false :get #(.getRoot ^js %)})) diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 11831bb94a..79931491fd 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -8,13 +8,11 @@ "RPC for plugins runtime." (:require [app.common.data :as d] - [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.record :as crc] [app.common.spec :as us] [app.common.text :as txt] [app.common.types.shape :as cts] - [app.common.uuid :as uuid] [app.main.data.workspace :as udw] [app.main.data.workspace.changes :as dwc] [app.main.data.workspace.selection :as dws] @@ -22,350 +20,353 @@ [app.main.data.workspace.shapes :as dwsh] [app.main.store :as st] [app.plugins.grid :as grid] - [app.plugins.utils :as utils :refer [get-data get-data-fn get-state]] + [app.plugins.utils :as utils :refer [locate-shape proxy->shape array-to-js]] [app.util.object :as obj])) -(declare data->shape-proxy) +(declare shape-proxy) -(defn- array-to-js - [value] - (.freeze - js/Object - (apply array (->> value (map utils/to-js))))) - -(defn- locate-shape - [shape-id] - (let [page-id (:current-page-id @st/state)] - (dm/get-in @st/state [:workspace-data :pages-index page-id :objects shape-id]))) - -(deftype ShapeProxy [#_:clj-kondo/ignore _data] +(deftype ShapeProxy [$file $page $id] Object (resize - [self width height] - (let [id (get-data self :id)] - (st/emit! (udw/update-dimensions [id] :width width) - (udw/update-dimensions [id] :height height)))) + [_ width height] + (st/emit! (udw/update-dimensions [$id] :width width) + (udw/update-dimensions [$id] :height height))) - (clone [self] - (let [id (get-data self :id) - page-id (:current-page-id @st/state) - ret-v (atom nil)] - (st/emit! (dws/duplicate-shapes #{id} :change-selection? false :return-ref ret-v)) - (let [new-id (deref ret-v) - shape (dm/get-in @st/state [:workspace-data :pages-index page-id :objects new-id])] - (data->shape-proxy shape)))) + (clone + [_] + (let [ret-v (atom nil)] + (st/emit! (dws/duplicate-shapes #{$id} :change-selection? false :return-ref ret-v)) + (shape-proxy (deref ret-v)))) - (remove [self] - (let [id (get-data self :id)] - (st/emit! (dwsh/delete-shapes #{id})))) + (remove + [_] + (st/emit! (dwsh/delete-shapes #{$id}))) ;; Only for frames + groups + booleans (getChildren - [self] - (apply array (->> (get-state self :shapes) - (map locate-shape) - (map data->shape-proxy)))) + [_] + (apply array (->> (locate-shape $file $page $id) + :shapes + (map #(shape-proxy $file $page %))))) - (appendChild [self child] - (let [parent-id (get-data self :id) - child-id (uuid/uuid (obj/get child "id"))] - (st/emit! (udw/relocate-shapes #{child-id} parent-id 0)))) + (appendChild + [_ child] + (let [child-id (obj/get child "$id")] + (st/emit! (udw/relocate-shapes #{child-id} $id 0)))) - (insertChild [self index child] - (let [parent-id (get-data self :id) - child-id (uuid/uuid (obj/get child "id"))] - (st/emit! (udw/relocate-shapes #{child-id} parent-id index)))) + (insertChild + [_ index child] + (let [child-id (obj/get child "$id")] + (st/emit! (udw/relocate-shapes #{child-id} $id index)))) ;; Only for frames - (addFlexLayout [self] - (let [id (get-data self :id)] - (st/emit! (dwsl/create-layout-from-id id :flex :from-frame? true :calculate-params? false)))) + (addFlexLayout + [_] + (st/emit! (dwsl/create-layout-from-id $id :flex :from-frame? true :calculate-params? false))) - (addGridLayout [self] - (let [id (get-data self :id)] - (st/emit! (dwsl/create-layout-from-id id :grid :from-frame? true :calculate-params? false)) - (grid/grid-layout-proxy (obj/get self "_data"))))) + (addGridLayout + [_] + (st/emit! (dwsl/create-layout-from-id $id :grid :from-frame? true :calculate-params? false)) + (grid/grid-layout-proxy $file $page $id))) (crc/define-properties! ShapeProxy {:name js/Symbol.toStringTag :get (fn [] (str "ShapeProxy"))}) -(defn data->shape-proxy - [data] +(defn shape-proxy + ([id] + (shape-proxy (:current-file-id @st/state) (:current-page-id @st/state) id)) - (-> (ShapeProxy. data) - (crc/add-properties! - {:name "_data" - :enumerable false} + ([page-id id] + (shape-proxy (:current-file-id @st/state) page-id id)) - {:name "id" - :get (get-data-fn :id str)} + ([file-id page-id id] + (assert (uuid? file-id)) + (assert (uuid? page-id)) + (assert (uuid? id)) - {:name "type" - :get (get-data-fn :type name)} + (let [data (locate-shape file-id page-id id)] + (-> (ShapeProxy. file-id page-id id) + (crc/add-properties! + {:name "$id" :enumerable false} + {:name "$file" :enumerable false} + {:name "$page" :enumerable false} - {:name "name" - :get #(get-state % :name) - :set (fn [self value] - (let [id (get-data self :id)] - (st/emit! (dwc/update-shapes [id] #(assoc % :name value)))))} + {:name "id" + :get #(-> % proxy->shape :id str)} - {:name "blocked" - :get #(get-state % :blocked boolean) - :set (fn [self value] - (let [id (get-data self :id)] - (st/emit! (dwc/update-shapes [id] #(assoc % :blocked value)))))} + {:name "type" + :get #(-> % proxy->shape :type name)} - {:name "hidden" - :get #(get-state % :hidden boolean) - :set (fn [self value] - (let [id (get-data self :id)] - (st/emit! (dwc/update-shapes [id] #(assoc % :hidden value)))))} + {:name "name" + :get #(-> % proxy->shape :name) + :set (fn [self value] + (let [id (obj/get self "$id")] + (st/emit! (dwc/update-shapes [id] #(assoc % :name value)))))} - {:name "proportionLock" - :get #(get-state % :proportion-lock boolean) - :set (fn [self value] - (let [id (get-data self :id)] - (st/emit! (dwc/update-shapes [id] #(assoc % :proportion-lock value)))))} + {:name "blocked" + :get #(-> % proxy->shape :blocked boolean) + :set (fn [self value] + (let [id (obj/get self "$id")] + (st/emit! (dwc/update-shapes [id] #(assoc % :blocked value)))))} - {:name "constraintsHorizontal" - :get #(get-state % :constraints-h d/name) - :set (fn [self value] - (let [id (get-data self :id) - value (keyword value)] - (when (contains? cts/horizontal-constraint-types value) - (st/emit! (dwc/update-shapes [id] #(assoc % :constraints-h value))))))} + {:name "hidden" + :get #(-> % proxy->shape :hidden boolean) + :set (fn [self value] + (let [id (obj/get self "$id")] + (st/emit! (dwc/update-shapes [id] #(assoc % :hidden value)))))} - {:name "constraintsVertical" - :get #(get-state % :constraints-v d/name) - :set (fn [self value] - (let [id (get-data self :id) - value (keyword value)] - (when (contains? cts/vertical-constraint-types value) - (st/emit! (dwc/update-shapes [id] #(assoc % :constraints-v value))))))} + {:name "proportionLock" + :get #(-> % proxy->shape :proportion-lock boolean) + :set (fn [self value] + (let [id (obj/get self "$id")] + (st/emit! (dwc/update-shapes [id] #(assoc % :proportion-lock value)))))} - {:name "borderRadius" - :get #(get-state % :rx) - :set (fn [self value] - (let [id (get-data self :id)] - (when (us/safe-int? value) - (st/emit! (dwc/update-shapes [id] #(assoc % :rx value :ry value))))))} + {:name "constraintsHorizontal" + :get #(-> % proxy->shape :constraints-h d/name) + :set (fn [self value] + (let [id (obj/get self "$id") + value (keyword value)] + (when (contains? cts/horizontal-constraint-types value) + (st/emit! (dwc/update-shapes [id] #(assoc % :constraints-h value))))))} - {:name "borderRadiusTopLeft" - :get #(get-state % :r1) - :set (fn [self value] - (let [id (get-data self :id)] - (when (us/safe-int? value) - (st/emit! (dwc/update-shapes [id] #(assoc % :r1 value))))))} + {:name "constraintsVertical" + :get #(-> % proxy->shape :constraints-v d/name) + :set (fn [self value] + (let [id (obj/get self "$id") + value (keyword value)] + (when (contains? cts/vertical-constraint-types value) + (st/emit! (dwc/update-shapes [id] #(assoc % :constraints-v value))))))} - {:name "borderRadiusTopRight" - :get #(get-state % :r2) - :set (fn [self value] - (let [id (get-data self :id)] - (when (us/safe-int? value) - (st/emit! (dwc/update-shapes [id] #(assoc % :r2 value))))))} + {:name "borderRadius" + :get #(-> % proxy->shape :rx) + :set (fn [self value] + (let [id (obj/get self "$id")] + (when (us/safe-int? value) + (st/emit! (dwc/update-shapes [id] #(assoc % :rx value :ry value))))))} - {:name "borderRadiusBottomRight" - :get #(get-state % :r3) - :set (fn [self value] - (let [id (get-data self :id)] - (when (us/safe-int? value) - (st/emit! (dwc/update-shapes [id] #(assoc % :r3 value))))))} + {:name "borderRadiusTopLeft" + :get #(-> % proxy->shape :r1) + :set (fn [self value] + (let [id (obj/get self "$id")] + (when (us/safe-int? value) + (st/emit! (dwc/update-shapes [id] #(assoc % :r1 value))))))} - {:name "borderRadiusBottomLeft" - :get #(get-state % :r4) - :set (fn [self value] - (let [id (get-data self :id)] - (when (us/safe-int? value) - (st/emit! (dwc/update-shapes [id] #(assoc % :r4 value))))))} + {:name "borderRadiusTopRight" + :get #(-> % proxy->shape :r2) + :set (fn [self value] + (let [id (obj/get self "$id")] + (when (us/safe-int? value) + (st/emit! (dwc/update-shapes [id] #(assoc % :r2 value))))))} - {:name "opacity" - :get #(get-state % :opacity) - :set (fn [self value] - (let [id (get-data self :id)] - (when (and (us/safe-number? value) (>= value 0) (<= value 1)) - (st/emit! (dwc/update-shapes [id] #(assoc % :opacity value))))))} + {:name "borderRadiusBottomRight" + :get #(-> % proxy->shape :r3) + :set (fn [self value] + (let [id (obj/get self "$id")] + (when (us/safe-int? value) + (st/emit! (dwc/update-shapes [id] #(assoc % :r3 value))))))} - {:name "blendMode" - :get #(get-state % :blend-mode d/name) - :set (fn [self value] - (let [id (get-data self :id) - value (keyword value)] - (when (contains? cts/blend-modes value) - (st/emit! (dwc/update-shapes [id] #(assoc % :blend-mode value))))))} + {:name "borderRadiusBottomLeft" + :get #(-> % proxy->shape :r4) + :set (fn [self value] + (let [id (obj/get self "$id")] + (when (us/safe-int? value) + (st/emit! (dwc/update-shapes [id] #(assoc % :r4 value))))))} - {:name "shadows" - :get #(get-state % :shadow array-to-js) - :set (fn [self value] - (let [id (get-data self :id) - value (mapv #(utils/from-js %) value)] - (st/emit! (dwc/update-shapes [id] #(assoc % :shadows value)))))} + {:name "opacity" + :get #(-> % proxy->shape :opacity) + :set (fn [self value] + (let [id (obj/get self "$id")] + (when (and (us/safe-number? value) (>= value 0) (<= value 1)) + (st/emit! (dwc/update-shapes [id] #(assoc % :opacity value))))))} - {:name "blur" - :get #(get-state % :blur utils/to-js) - :set (fn [self value] - (let [id (get-data self :id) - value (utils/from-js value)] - (st/emit! (dwc/update-shapes [id] #(assoc % :blur value)))))} + {:name "blendMode" + :get #(-> % proxy->shape :blend-mode (d/nilv :normal) d/name) + :set (fn [self value] + (let [id (obj/get self "$id") + value (keyword value)] + (when (contains? cts/blend-modes value) + (st/emit! (dwc/update-shapes [id] #(assoc % :blend-mode value))))))} - {:name "exports" - :get #(get-state % :exports array-to-js) - :set (fn [self value] - (let [id (get-data self :id) - value (mapv #(utils/from-js %) value)] - (st/emit! (dwc/update-shapes [id] #(assoc % :exports value)))))} + {:name "shadows" + :get #(-> % proxy->shape :shadow array-to-js) + :set (fn [self value] + (let [id (obj/get self "$id") + value (mapv #(utils/from-js %) value)] + (st/emit! (dwc/update-shapes [id] #(assoc % :shadows value)))))} - ;; Geometry properties - {:name "x" - :get #(get-state % :x) - :set - (fn [self value] - (let [id (get-data self :id)] - (st/emit! (udw/update-position id {:x value}))))} + {:name "blur" + :get #(-> % proxy->shape :blur utils/to-js) + :set (fn [self value] + (let [id (obj/get self "$id") + value (utils/from-js value)] + (st/emit! (dwc/update-shapes [id] #(assoc % :blur value)))))} - {:name "y" - :get #(get-state % :y) - :set - (fn [self value] - (let [id (get-data self :id)] - (st/emit! (udw/update-position id {:y value}))))} + {:name "exports" + :get #(-> % proxy->shape :exports array-to-js) + :set (fn [self value] + (let [id (obj/get self "$id") + value (mapv #(utils/from-js %) value)] + (st/emit! (dwc/update-shapes [id] #(assoc % :exports value)))))} - {:name "parentX" - :get (fn [self] - (let [page-id (:current-page-id @st/state) - parent-id (get-state self :parent-id) - parent-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :x])] - (- (get-state self :x) parent-x))) - :set - (fn [self value] - (let [page-id (:current-page-id @st/state) - id (get-data self :id) - parent-id (get-state self :parent-id) - parent-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :x])] - (st/emit! (udw/update-position id {:x (+ parent-x value)}))))} + ;; Geometry properties + {:name "x" + :get #(-> % proxy->shape :x) + :set + (fn [self value] + (let [id (obj/get self "$id")] + (st/emit! (udw/update-position id {:x value}))))} - {:name "parentY" - :get (fn [self] - (let [page-id (:current-page-id @st/state) - parent-id (get-state self :parent-id) - parent-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :y])] - (- (get-state self :y) parent-y))) - :set - (fn [self value] - (let [page-id (:current-page-id @st/state) - id (get-data self :id) - parent-id (get-state self :parent-id) - parent-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :y])] - (st/emit! (udw/update-position id {:y (+ parent-y value)}))))} + {:name "y" + :get #(-> % proxy->shape :y) + :set + (fn [self value] + (let [id (obj/get self "$id")] + (st/emit! (udw/update-position id {:y value}))))} - {:name "frameX" - :get (fn [self] - (let [page-id (:current-page-id @st/state) - frame-id (get-state self :frame-id) - frame-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :x])] - (- (get-state self :x) frame-x))) - :set - (fn [self value] - (let [page-id (:current-page-id @st/state) - id (get-data self :id) - frame-id (get-state self :frame-id) - frame-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :x])] - (st/emit! (udw/update-position id {:x (+ frame-x value)}))))} + {:name "parentX" + :get (fn [self] + (let [shape (proxy->shape self) + parent-id (:parent-id shape) + parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id)] + (- (:x shape) (:x parent)))) + :set + (fn [self value] + (let [id (obj/get self "$id") + parent-id (-> self proxy->shape :parent-id) + parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id) + parent-x (:x parent)] + (st/emit! (udw/update-position id {:x (+ parent-x value)}))))} - {:name "frameY" - :get (fn [self] - (let [page-id (:current-page-id @st/state) - frame-id (get-state self :frame-id) - frame-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :y])] - (- (get-state self :y) frame-y))) - :set - (fn [self value] - (let [page-id (:current-page-id @st/state) - id (get-data self :id) - frame-id (get-state self :frame-id) - frame-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :y])] - (st/emit! (udw/update-position id {:y (+ frame-y value)}))))} + {:name "parentY" + :get (fn [self] + (let [shape (proxy->shape self) + parent-id (:parent-id shape) + parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id) + parent-y (:y parent)] + (- (:y shape) parent-y))) + :set + (fn [self value] + (let [id (obj/get self "$id") + parent-id (-> self proxy->shape :parent-id) + parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id) + parent-y (:y parent)] + (st/emit! (udw/update-position id {:y (+ parent-y value)}))))} - {:name "width" - :get #(get-state % :width)} + {:name "frameX" + :get (fn [self] + (let [shape (proxy->shape self) + frame-id (:parent-id shape) + frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) + frame-x (:x frame)] + (- (:x shape) frame-x))) + :set + (fn [self value] + (let [id (obj/get self "$id") + frame-id (-> self proxy->shape :frame-id) + frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) + frame-x (:x frame)] + (st/emit! (udw/update-position id {:x (+ frame-x value)}))))} - {:name "height" - :get #(get-state % :height)} + {:name "frameY" + :get (fn [self] + (let [shape (proxy->shape self) + frame-id (:parent-id shape) + frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) + frame-y (:y frame)] + (- (:y shape) frame-y))) + :set + (fn [self value] + (let [id (obj/get self "$id") + frame-id (-> self proxy->shape :frame-id) + frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) + frame-y (:y frame)] + (st/emit! (udw/update-position id {:y (+ frame-y value)}))))} - {:name "flipX" - :get #(get-state % :flip-x)} + {:name "width" + :get #(-> % proxy->shape :width)} - {:name "flipY" - :get #(get-state % :flip-y)} + {:name "height" + :get #(-> % proxy->shape :height)} - ;; Strokes and fills - {:name "fills" - :get #(get-state % :fills array-to-js) - :set (fn [self value] - (let [id (get-data self :id) - value (mapv #(utils/from-js %) value)] - (st/emit! (dwc/update-shapes [id] #(assoc % :fills value)))))} + {:name "flipX" + :get #(-> % proxy->shape :flip-x)} - {:name "strokes" - :get #(get-state % :strokes array-to-js) - :set (fn [self value] - (let [id (get-data self :id) - value (mapv #(utils/from-js %) value)] - (st/emit! (dwc/update-shapes [id] #(assoc % :strokes value)))))}) + {:name "flipY" + :get #(-> % proxy->shape :flip-y)} - (cond-> (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)) - (crc/add-properties! - {:name "children" - :get #(.getChildren ^js %)})) + ;; Strokes and fills + {:name "fills" + :get #(-> % proxy->shape :fills array-to-js) + :set (fn [self value] + (let [id (obj/get self "$id") + value (mapv #(utils/from-js %) value)] + (st/emit! (dwc/update-shapes [id] #(assoc % :fills value)))))} - (cond-> (not (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data))) - (-> (obj/unset! "appendChild") - (obj/unset! "insertChild") - (obj/unset! "getChildren"))) + {:name "strokes" + :get #(-> % proxy->shape :strokes array-to-js) + :set (fn [self value] + (let [id (obj/get self "$id") + value (mapv #(utils/from-js %) value)] + (st/emit! (dwc/update-shapes [id] #(assoc % :strokes value)))))}) - (cond-> (cfh/frame-shape? data) - (-> (crc/add-properties! - {:name "grid" - :get - (fn [self] - (let [layout (get-state self :layout)] - (when (= :grid layout) - (grid/grid-layout-proxy data))))} + (cond-> (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)) + (crc/add-properties! + {:name "children" + :enumerable false + :get #(.getChildren ^js %)})) - {:name "guides" - :get #(get-state % :grids array-to-js) - :set (fn [self value] - (let [id (get-data self :id) - value (mapv #(utils/from-js %) value)] - (st/emit! (dwc/update-shapes [id] #(assoc % :grids value)))))}) + (cond-> (not (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data))) + (-> (obj/unset! "appendChild") + (obj/unset! "insertChild") + (obj/unset! "getChildren"))) - ;; TODO: Flex properties - #_(crc/add-properties! - {:name "flex" - :get - (fn [self] - (let [layout (get-state self :layout)] - (when (= :flex layout) - (flex-layout-proxy data))))}))) + (cond-> (cfh/frame-shape? data) + (-> (crc/add-properties! + {:name "grid" + :get + (fn [self] + (let [layout (-> self proxy->shape :layout) + file-id (obj/get self "$file") + page-id (obj/get self "$page") + id (obj/get self "$id")] + (when (= :grid layout) + (grid/grid-layout-proxy file-id page-id id))))} - (cond-> (not (cfh/frame-shape? data)) - (-> (obj/unset! "addGridLayout") - (obj/unset! "addFlexLayout"))) + {:name "guides" + :get #(-> % proxy->shape :grids array-to-js) + :set (fn [self value] + (let [id (obj/get self "$id") + value (mapv #(utils/from-js %) value)] + (st/emit! (dwc/update-shapes [id] #(assoc % :grids value)))))}) - (cond-> (cfh/text-shape? data) - (-> (crc/add-properties! - {:name "characters" - :get #(get-state % :content txt/content->text) - :set (fn [self value] - (let [id (get-data self :id)] - (st/emit! (dwc/update-shapes [id] #(txt/change-text % value)))))}) + ;; TODO: Flex properties + #_(crc/add-properties! + {:name "flex" + :get + (fn [self] + (let [layout (-> self proxy->shape :layout)] + (when (= :flex layout) + (flex-layout-proxy (proxy->shape self)))))}))) - (crc/add-properties! - {:name "growType" - :get #(get-state % :grow-type d/name) - :set (fn [self value] - (let [id (get-data self :id) - value (keyword value)] - (when (contains? #{:auto-width :auto-height :fixed} value) - (st/emit! (dwc/update-shapes [id] #(assoc % :grow-type value))))))}))))) + (cond-> (not (cfh/frame-shape? data)) + (-> (obj/unset! "addGridLayout") + (obj/unset! "addFlexLayout"))) + + (cond-> (cfh/text-shape? data) + (-> (crc/add-properties! + {:name "characters" + :get #(-> % proxy->shape :content txt/content->text) + :set (fn [self value] + (let [id (obj/get self "$id")] + (st/emit! (dwc/update-shapes [id] #(txt/change-text % value)))))}) + + (crc/add-properties! + {:name "growType" + :get #(-> % proxy->shape :grow-type d/name) + :set (fn [self value] + (let [id (obj/get self "$id") + value (keyword value)] + (when (contains? #{:auto-width :auto-height :fixed} value) + (st/emit! (dwc/update-shapes [id] #(assoc % :grow-type value))))))}))))))) diff --git a/frontend/src/app/plugins/utils.cljs b/frontend/src/app/plugins/utils.cljs index 35022c36e1..fb3de2f603 100644 --- a/frontend/src/app/plugins/utils.cljs +++ b/frontend/src/app/plugins/utils.cljs @@ -16,6 +16,42 @@ [cuerdas.core :as str] [promesa.core :as p])) +(defn locate-file + [id] + (assert (uuid? id) "File not valid uuid") + (if (= id (:current-file-id @st/state)) + (-> (:workspace-file @st/state) + (assoc :data (:workspace-data @st/state))) + (dm/get-in @st/state [:workspace-libraries id]))) + +(defn locate-page + [file-id id] + (assert (uuid? id) "Page not valid uuid") + (dm/get-in (locate-file file-id) [:data :pages-index id])) + +(defn locate-shape + [file-id page-id id] + (assert (uuid? id) "Shape not valid uuid") + (dm/get-in (locate-page file-id page-id) [:objects id])) + +(defn proxy->file + [proxy] + (let [id (obj/get proxy "$id")] + (locate-file id))) + +(defn proxy->page + [proxy] + (let [file-id (obj/get proxy "$file") + id (obj/get proxy "$id")] + (locate-page file-id id))) + +(defn proxy->shape + [proxy] + (let [file-id (obj/get proxy "$file") + page-id (obj/get proxy "$page") + id (obj/get proxy "$id")] + (locate-shape file-id page-id id))) + (defn get-data ([self attr] (-> (obj/get self "_data") @@ -77,6 +113,12 @@ obj)] (clj->js result))) +(defn array-to-js + [value] + (.freeze + js/Object + (apply array (->> value (map to-js))))) + (defn result-p "Creates a pair of atom+promise. The promise will be resolved when the atom gets a value. We use this to return the promise to the library clients and resolve its value when a value is passed