From 2da5dcb619bb5e729aa8ec6ee1a0fdc130fa8714 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 13 Jun 2024 12:29:17 +0200 Subject: [PATCH 1/7] :sparkles: Add text ranges support in plugins --- common/src/app/common/text.cljc | 24 ++- .../src/app/main/data/workspace/texts.cljs | 97 ++++++++++- frontend/src/app/plugins/library.cljs | 13 +- frontend/src/app/plugins/shape.cljs | 157 +++++++++++++++++- frontend/src/app/plugins/utils.cljs | 8 +- 5 files changed, 285 insertions(+), 14 deletions(-) diff --git a/common/src/app/common/text.cljc b/common/src/app/common/text.cljc index 8ee125e8a..c82f65c9b 100644 --- a/common/src/app/common/text.cljc +++ b/common/src/app/common/text.cljc @@ -361,7 +361,7 @@ new-acc (cond - (:children node) + (not (is-text-node? node)) (reduce #(rec-style-text-map %1 %2 node-style) acc (:children node)) (not= head-style node-style) @@ -381,6 +381,28 @@ (-> (rec-style-text-map [] node {}) reverse))) +(defn content-range->text+styles + "Given a root node of a text content extracts the texts with its associated styles" + [node start end] + (let [sss (content->text+styles node)] + (loop [styles (seq sss) + taking? false + acc 0 + result []] + (if styles + (let [[node-style text] (first styles) + from acc + to (+ acc (count text)) + taking? (or taking? (and (<= from start) (< start to))) + text (subs text (max 0 (- start acc)) (- end acc)) + result (cond-> result + (and taking? (d/not-empty? text)) + (conj (assoc node-style :text text))) + continue? (or (> from end) (>= end to))] + (recur (when continue? (rest styles)) taking? to result)) + result)))) + + (defn content->text "Given a root node of a text content extracts the texts with its associated styles" [content] diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index d1e55e027..bceaeacf3 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -205,6 +205,102 @@ ;; --- TEXT EDITION IMPL +(defn count-node-chars + ([node] + (count-node-chars node false)) + ([node last?] + (case (:type node) + ("root" "paragraph-set") + (apply + (concat (map count-node-chars (drop-last (:children node))) + (map #(count-node-chars % true) (take-last 1 (:children node))))) + + "paragraph" + (+ (apply + (map count-node-chars (:children node))) (if last? 0 1)) + + (count (:text node))))) + + +(defn decorate-range-info + "Adds information about ranges inside the metadata of the text nodes" + [content] + (->> (with-meta content {:start 0 :end (count-node-chars content)}) + (txt/transform-nodes + (fn [node] + (d/update-when + node + :children + (fn [children] + (let [start (-> node meta (:start 0))] + (->> children + (reduce (fn [[result start] node] + (let [end (+ start (count-node-chars node))] + [(-> result + (conj (with-meta node {:start start :end end}))) + end])) + [[] start]) + (first))))))))) + +(defn split-content-at + [content position] + (->> content + (txt/transform-nodes + (fn [node] + (and (txt/is-paragraph-node? node) + (< (-> node meta :start) position (-> node meta :end)))) + (fn [node] + (letfn + [(process-node [child] + (let [start (-> child meta :start) + end (-> child meta :end)] + (if (< start position end) + [(-> child + (vary-meta assoc :end position) + (update :text subs 0 (- position start))) + (-> child + (vary-meta assoc :start position) + (update :text subs (- position start)))] + [child])))] + (-> node + (d/update-when :children #(into [] (mapcat process-node) %)))))))) + +(defn update-content-range + [content start end attrs] + (->> content + (txt/transform-nodes + (fn [node] + (and (txt/is-text-node? node) + (and (>= (-> node meta :start) start) + (<= (-> node meta :end) end)))) + #(d/patch-object % attrs)))) + +(defn- update-text-range-attrs + [shape start end attrs] + (let [new-content (-> (:content shape) + (decorate-range-info) + (split-content-at start) + (split-content-at end) + (update-content-range start end attrs))] + (assoc shape :content new-content))) + +(defn update-text-range + [id start end attrs] + (ptk/reify ::update-text-range + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + shape (get objects id) + + update-fn + (fn [shape] + (cond-> shape + (cfh/text-shape? shape) + (update-text-range-attrs start end attrs))) + + shape-ids (cond (cfh/text-shape? shape) [id] + (cfh/group-shape? shape) (cfh/get-children-ids objects id))] + + (rx/of (dwsh/update-shapes shape-ids update-fn)))))) + (defn- update-text-content [shape pred-fn update-fn attrs] (let [update-attrs-fn #(update-fn % attrs) @@ -278,7 +374,6 @@ (cfh/group-shape? shape) (cfh/get-children-ids objects id))] (rx/of (dwsh/update-shapes shape-ids #(update-text-content % update-node? d/txt-merge attrs)))))))) - (defn migrate-node [node] (let [color-attrs (select-keys node [:fill-color :fill-opacity :fill-color-ref-id :fill-color-ref-file :fill-color-gradient])] diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index 6f6f87ed3..380ff68c3 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -233,9 +233,16 @@ (st/emit! (dwt/apply-typography #{shape-id} typography $file)))) (applyToTextRange - [_ _shape _from _to] - ;; TODO - ) + [self range] + (let [shape-id (obj/get range "$id") + start (obj/get range "start") + end (obj/get range "end") + typography (u/proxy->library-typography self) + attrs (-> typography + (assoc :typography-ref-file $file) + (assoc :typography-ref-id (:id typography)) + (dissoc :id :name))] + (st/emit! (dwt/update-text-range shape-id start end attrs)))) ;; PLUGIN DATA (getPluginData diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 81ad46bbb..0d239dbe2 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -36,6 +36,139 @@ [app.util.text-editor :as ted] [cuerdas.core :as str])) + +(deftype TextRange [$plugin $file $page $id start end] + Object + (applyTypography [_ typography] + (let [typography (u/proxy->library-typography typography) + attrs (-> typography + (assoc :typography-ref-file $file) + (assoc :typography-ref-id (:id typography)) + (dissoc :id :name))] + (st/emit! (dwt/update-text-range $id start end attrs))))) + +(defn mixed-value + [values] + (let [s (set values)] + (if (= (count s) 1) (first s) "mixed"))) + +;; TODO Validate inputs +(defn text-range + [plugin-id file-id page-id id start end] + (-> (TextRange. plugin-id file-id page-id id start end) + (crc/add-properties! + {:name "$plugin" :enumerable false :get (constantly plugin-id)} + {:name "$id" :enumerable false :get (constantly id)} + {:name "$file" :enumerable false :get (constantly file-id)} + {:name "$page" :enumerable false :get (constantly page-id)} + + {:name "shape" + :get #(-> % u/proxy->shape)} + + {:name "characters" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :text) (str/join "")))} + + {:name "fontId" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :font-id) mixed-value)) + + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:font-id value})))} + + {:name "fontFamily" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :font-family) mixed-value)) + + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:font-family value})))} + + {:name "fontVariantId" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :font-variant-id) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:font-variant-id value})))} + + {:name "fontSize" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :font-size) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:font-size value})))} + + {:name "fontWeight" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :font-weight) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:font-weight value})))} + + {:name "fontStyle" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :font-style) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:font-style value})))} + + {:name "lineHeight" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :line-height) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:line-height value})))} + + {:name "letterSpacing" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :letter-spacing) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:letter-spacing value})))} + + {:name "textTransform" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :text-transform) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:text-transform value})))} + + {:name "textDecoration" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :text-decoration) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:text-decoration value})))} + + {:name "direction" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :direction) mixed-value)) + :set + (fn [_ value] + (st/emit! (dwt/update-text-range id start end {:direction value})))} + + {:name "fills" + :get #(let [range-data + (-> % u/proxy->shape :content (txt/content-range->text+styles start end))] + (->> range-data (map :fills) mixed-value u/array-to-js)) + :set + (fn [_ value] + (let [value (mapv #(u/from-js %) value)] + (st/emit! (dwt/update-text-range id start end {:fills value}))))}))) + (declare shape-proxy) (defn parse-command @@ -214,11 +347,19 @@ ;; Text shapes (getRange - [_ _from _to] + [_ start end] (let [shape (u/locate-shape $file $page $id)] (if (cfh/text-shape? shape) - nil ;; TODO - (u/display-not-valid :makeMask (:type shape)))))) + (text-range $plugin $file $page $id start end) + (u/display-not-valid :makeMask (:type shape))))) + + (applyTypography + [_ typography] + (let [shape (u/locate-shape $file $page $id)] + (if (cfh/text-shape? shape) + (let [typography (u/proxy->library-typography typography)] + (st/emit! (dwt/apply-typography #{$id} typography $file))) + (u/display-not-valid :applyTypography (:type shape)))))) (crc/define-properties! ShapeProxy @@ -490,14 +631,18 @@ :get #(-> % u/proxy->shape :flip-y)} ;; Strokes and fills + ;; TODO: Validate fills input {:name "fills" :get #(if (cfh/text-shape? data) (-> % u/proxy->shape text-props :fills u/array-to-js) (-> % u/proxy->shape :fills u/array-to-js)) :set (fn [self value] - (let [id (obj/get self "$id") + (let [shape (u/proxy->shape self) + id (:id shape) value (mapv #(u/from-js %) value)] - (st/emit! (dwsh/update-shapes [id] #(assoc % :fills value)))))} + (if (cfh/text-shape? shape) + (st/emit! (dwt/update-attrs id {:fills value})) + (st/emit! (dwsh/update-shapes [id] #(assoc % :fills value))))))} {:name "strokes" :get #(-> % u/proxy->shape :strokes u/array-to-js) @@ -634,7 +779,7 @@ :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:font-id value}))))} + (st/emit! (dwt/update-attrs id {:font-size value}))))} {:name "fontWeight" :get #(-> % u/proxy->shape text-props :font-weight) diff --git a/frontend/src/app/plugins/utils.cljs b/frontend/src/app/plugins/utils.cljs index c057aa0b6..87fb3abb3 100644 --- a/frontend/src/app/plugins/utils.cljs +++ b/frontend/src/app/plugins/utils.cljs @@ -177,9 +177,11 @@ (defn array-to-js [value] - (.freeze - js/Object - (apply array (->> value (map to-js))))) + (if (coll? value) + (.freeze + js/Object + (apply array (->> value (map to-js)))) + value)) (defn result-p "Creates a pair of atom+promise. The promise will be resolved when the atom gets a value. From 69fad7a920db148954441343cfbc4bebf0b2f4a5 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 13 Jun 2024 15:25:09 +0200 Subject: [PATCH 2/7] :sparkles: Add some utilities for fonts in plugins --- frontend/src/app/plugins/api.cljs | 2 + frontend/src/app/plugins/fonts.cljs | 88 +++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 frontend/src/app/plugins/fonts.cljs diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 4d682593c..c43191eda 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -21,6 +21,7 @@ [app.main.store :as st] [app.plugins.events :as events] [app.plugins.file :as file] + [app.plugins.fonts :as fonts] [app.plugins.library :as library] [app.plugins.page :as page] [app.plugins.shape :as shape] @@ -206,4 +207,5 @@ {:name "viewport" :get #(.getViewport ^js %)} {:name "currentUser" :get #(.getCurrentUser ^js %)} {:name "activeUsers" :get #(.getActiveUsers ^js %)} + {:name "fonts" :get (fn [_] (fonts/fonts-subcontext plugin-id))} {:name "library" :get (fn [_] (library/library-subcontext plugin-id))})) diff --git a/frontend/src/app/plugins/fonts.cljs b/frontend/src/app/plugins/fonts.cljs new file mode 100644 index 000000000..8455ec72b --- /dev/null +++ b/frontend/src/app/plugins/fonts.cljs @@ -0,0 +1,88 @@ +;; 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.plugins.fonts + (:require + [app.common.data :as d] + [app.common.record :as cr] + [app.main.data.workspace.texts :as dwt] + [app.main.fonts :as fonts] + [app.main.store :as st] + [app.util.object :as obj] + [cuerdas.core :as str])) + +(deftype PenpotFontVariant [name fontVariantId fontWeight fontStyle]) + +(deftype PenpotFont [name fontId fontFamily fontStyle fontVariantId fontWeight variants] + Object + + (applyToText [_ text variant] + (let [id (obj/get text "$id") + values {:font-id fontId + :font-family fontFamily + :font-style (d/nilv (obj/get variant "fontStyle") fontStyle) + :font-variant-id (d/nilv (obj/get variant "fontVariantId") fontVariantId) + :font-weight (d/nilv (obj/get variant "fontWeight") fontWeight)}] + (st/emit! (dwt/update-attrs id values)))) + + (applyToRange [_ range variant] + (let [id (obj/get range "$id") + start (obj/get range "start") + end (obj/get range "end") + values {:font-id fontId + :font-family fontFamily + :font-style (d/nilv (obj/get variant "fontStyle") fontStyle) + :font-variant-id (d/nilv (obj/get variant "fontVariantId") fontVariantId) + :font-weight (d/nilv (obj/get variant "fontWeight") fontWeight)}] + (st/emit! (dwt/update-text-range id start end values))))) + +(defn font-proxy + [{:keys [id name variants] :as font}] + (when (some? font) + (let [default-variant (fonts/get-default-variant font)] + (PenpotFont. + name + id + id + (:style default-variant) + (:id default-variant) + (:weight default-variant) + (apply + array + (->> variants + (map (fn [{:keys [id name style weight]}] + (PenpotFontVariant. name id weight style))))))))) + +(deftype PenpotFontsSubcontext [$plugin] + Object + (findById + [_ id] + (font-proxy (d/seek #(str/includes? (str/lower (:id %)) (str/lower id)) (vals @fonts/fontsdb)))) + + (findByName + [_ name] + (font-proxy (d/seek #(str/includes? (str/lower (:name %)) (str/lower name)) (vals @fonts/fontsdb)))) + + (findAllById + [_ id] + (apply array (->> (vals @fonts/fontsdb) + (filter #(str/includes? (str/lower (:id %)) (str/lower id))) + (map font-proxy)))) + + (findAllByName + [_ name] + (apply array (->> (vals @fonts/fontsdb) + (filter #(str/includes? (str/lower (:name %)) (str/lower name))) + (map font-proxy))))) + +(defn fonts-subcontext + [plugin-id] + (cr/add-properties! + (PenpotFontsSubcontext. plugin-id) + {:name "$plugin" :enumerable false :get (constantly plugin-id)} + {:name "all" :get + (fn [_] + (apply array (->> @fonts/fontsdb vals (map font-proxy))))})) From e13d543dcd5e6340ebad8950e04fd8936f42e782 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 14 Jun 2024 12:20:47 +0200 Subject: [PATCH 3/7] :sparkles: Add geometry utils --- .../app/main/data/workspace/modifiers.cljs | 38 +++++----- .../app/main/data/workspace/transforms.cljs | 73 ++++++++++--------- frontend/src/app/plugins.cljs | 1 + frontend/src/app/plugins/public_utils.cljs | 19 +++++ frontend/src/app/plugins/shape.cljs | 39 +++++++++- 5 files changed, 116 insertions(+), 54 deletions(-) create mode 100644 frontend/src/app/plugins/public_utils.cljs diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 74e243af8..1177b4f90 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -438,28 +438,28 @@ ;; - It consideres the center for everyshape instead of the center of the total selrect ;; - The angle param is the desired final value, not a delta (defn set-delta-rotation-modifiers - ([angle shapes] - (ptk/reify ::set-delta-rotation-modifiers - ptk/UpdateEvent - (update [_ state] - (let [objects (wsh/lookup-page-objects state) - ids - (->> shapes - (remove #(get % :blocked false)) - (filter #(contains? (get editable-attrs (:type %)) :rotation)) - (map :id)) + [angle shapes {:keys [center delta?] :or {center nil delta? false}}] + (ptk/reify ::set-delta-rotation-modifiers + ptk/UpdateEvent + (update [_ state] + (let [objects (wsh/lookup-page-objects state) + ids + (->> shapes + (remove #(get % :blocked false)) + (filter #(contains? (get editable-attrs (:type %)) :rotation)) + (map :id)) - get-modifier - (fn [shape] - (let [delta (- angle (:rotation shape)) - center (gsh/shape->center shape)] - (ctm/rotation-modifiers shape center delta))) + get-modifier + (fn [shape] + (let [delta (if delta? angle (- angle (:rotation shape))) + center (or center (gsh/shape->center shape))] + (ctm/rotation-modifiers shape center delta))) - modif-tree - (-> (build-modif-tree ids objects get-modifier) - (gm/set-objects-modifiers objects))] + modif-tree + (-> (build-modif-tree ids objects get-modifier) + (gm/set-objects-modifiers objects))] - (assoc state :workspace-modifiers modif-tree)))))) + (assoc state :workspace-modifiers modif-tree))))) (defn apply-modifiers ([] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 3107f9ace..c4e2a8064 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -400,17 +400,18 @@ (defn increase-rotation "Rotate shapes a fixed angle, from a keyboard action." - [ids rotation] - (ptk/reify ::increase-rotation - ptk/WatchEvent - (watch [_ state _] - - (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - shapes (->> ids (map #(get objects %)))] - (rx/concat - (rx/of (dwm/set-delta-rotation-modifiers rotation shapes)) - (rx/of (dwm/apply-modifiers))))))) + ([ids rotation] + (increase-rotation ids rotation nil)) + ([ids rotation params] + (ptk/reify ::increase-rotation + ptk/WatchEvent + (watch [_ state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + shapes (->> ids (map #(get objects %)))] + (rx/concat + (rx/of (dwm/set-delta-rotation-modifiers rotation shapes params)) + (rx/of (dwm/apply-modifiers)))))))) ;; -- Move ---------------------------------------------------------- @@ -889,26 +890,32 @@ ;; -- Flip ---------------------------------------------------------- -(defn flip-horizontal-selected [] - (ptk/reify ::flip-horizontal-selected - ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (wsh/lookup-selected state {:omit-blocked? true}) - shapes (map #(get objects %) selected) - selrect (gsh/shapes->rect shapes) - center (grc/rect->center selrect) - modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point -1.0 1.0) center))] - (rx/of (dwm/apply-modifiers {:modifiers modifiers :ignore-snap-pixel true})))))) +(defn flip-horizontal-selected + ([] + (flip-horizontal-selected nil)) + ([ids] + (ptk/reify ::flip-horizontal-selected + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + selected (or ids (wsh/lookup-selected state {:omit-blocked? true})) + shapes (map #(get objects %) selected) + selrect (gsh/shapes->rect shapes) + center (grc/rect->center selrect) + modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point -1.0 1.0) center))] + (rx/of (dwm/apply-modifiers {:modifiers modifiers :ignore-snap-pixel true}))))))) -(defn flip-vertical-selected [] - (ptk/reify ::flip-vertical-selected - ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (wsh/lookup-selected state {:omit-blocked? true}) - shapes (map #(get objects %) selected) - selrect (gsh/shapes->rect shapes) - center (grc/rect->center selrect) - modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point 1.0 -1.0) center))] - (rx/of (dwm/apply-modifiers {:modifiers modifiers :ignore-snap-pixel true})))))) +(defn flip-vertical-selected + ([] + (flip-vertical-selected nil)) + ([ids] + (ptk/reify ::flip-vertical-selected + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + selected (or ids (wsh/lookup-selected state {:omit-blocked? true})) + shapes (map #(get objects %) selected) + selrect (gsh/shapes->rect shapes) + center (grc/rect->center selrect) + modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point 1.0 -1.0) center))] + (rx/of (dwm/apply-modifiers {:modifiers modifiers :ignore-snap-pixel true}))))))) diff --git a/frontend/src/app/plugins.cljs b/frontend/src/app/plugins.cljs index ac48f5c08..551591b4a 100644 --- a/frontend/src/app/plugins.cljs +++ b/frontend/src/app/plugins.cljs @@ -10,6 +10,7 @@ [app.main.features :as features] [app.main.store :as st] [app.plugins.api :as api] + [app.plugins.public-utils] [app.util.globals :refer [global]] [app.util.object :as obj] [beicon.v2.core :as rx] diff --git a/frontend/src/app/plugins/public_utils.cljs b/frontend/src/app/plugins/public_utils.cljs new file mode 100644 index 000000000..6ebe31151 --- /dev/null +++ b/frontend/src/app/plugins/public_utils.cljs @@ -0,0 +1,19 @@ +;; 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.plugins.public-utils + "Utilities that will be exposed to plugins developers" + (:require + [app.common.geom.rect :as grc] + [app.common.geom.shapes :as gsh] + [app.plugins.utils :as u])) + +(defn ^:export centerShapes + [shapes] + (let [shapes (->> shapes (map u/proxy->shape))] + (-> (gsh/shapes->rect shapes) + (grc/rect->center) + (u/to-js)))) diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 0d239dbe2..2048e8afe 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -202,6 +202,20 @@ (st/emit! (dw/update-dimensions [$id] :width width) (dw/update-dimensions [$id] :height height))) + (rotate + [self angle center] + (let [center (when center {:x (obj/get center "x") :y (obj/get center "y")})] + (cond + (not (number? angle)) + (u/display-not-valid :rotate-angle angle) + + (and (some? center) (or (not (number? (:x center))) (not (number? (:y center))))) + (u/display-not-valid :rotate-center center) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dw/increase-rotation [id] angle {:center center :delta? true})))))) + (clone [_] (let [ret-v (atom nil)] @@ -624,11 +638,32 @@ {:name "height" :get #(-> % u/proxy->shape :height)} + {:name "rotation" + :get #(-> % u/proxy->shape :rotation) + :set + (fn [self value] + (if (number? value) + (let [shape (u/proxy->shape self)] + (st/emit! (dw/increase-rotation #{(:id shape)} value))) + (u/display-not-valid :rotation value)))} + {:name "flipX" - :get #(-> % u/proxy->shape :flip-x)} + :get #(-> % u/proxy->shape :flip-x boolean) + :set + (fn [self value] + (if (boolean? value) + (let [id (obj/get self "$id")] + (st/emit! (dw/flip-horizontal-selected #{id}))) + (u/display-not-valid :flipX value)))} {:name "flipY" - :get #(-> % u/proxy->shape :flip-y)} + :get #(-> % u/proxy->shape :flip-y boolean) + :set + (fn [self value] + (if (boolean? value) + (let [id (obj/get self "$id")] + (st/emit! (dw/flip-vertical-selected #{id}))) + (u/display-not-valid :flipY value)))} ;; Strokes and fills ;; TODO: Validate fills input From c5c8be4b4a2312aae51a89a2fe26a9a36a1fb651 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 14 Jun 2024 15:19:57 +0200 Subject: [PATCH 4/7] :sparkles: Improve input validation in plugins --- frontend/src/app/plugins/api.cljs | 113 ++++++++++++++++--------- frontend/src/app/plugins/file.cljs | 3 + frontend/src/app/plugins/flex.cljs | 6 ++ frontend/src/app/plugins/fonts.cljs | 3 + frontend/src/app/plugins/grid.cljs | 6 ++ frontend/src/app/plugins/library.cljs | 12 +++ frontend/src/app/plugins/page.cljs | 3 + frontend/src/app/plugins/shape.cljs | 3 + frontend/src/app/plugins/user.cljs | 6 ++ frontend/src/app/plugins/viewport.cljs | 5 +- 10 files changed, 120 insertions(+), 40 deletions(-) diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index c43191eda..adf18684a 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -26,7 +26,7 @@ [app.plugins.page :as page] [app.plugins.shape :as shape] [app.plugins.user :as user] - [app.plugins.utils :as utils] + [app.plugins.utils :as u] [app.plugins.viewport :as viewport] [app.util.object :as obj] [beicon.v2.core :as rx] @@ -61,7 +61,7 @@ (getViewport [_] - (viewport/create-proxy $plugin)) + (viewport/viewport-proxy $plugin)) (getFile [_] @@ -108,28 +108,50 @@ (uploadMediaUrl [_ name url] - (let [file-id (:current-file-id @st/state)] - (p/create - (fn [resolve reject] - (->> (dwm/upload-media-url name file-id url) - (rx/map utils/to-js) - (rx/take 1) - (rx/subs! resolve reject)))))) + (cond + (not (string? name)) + (u/display-not-valid :uploadMedia-name name) + + (not (string? url)) + (u/display-not-valid :uploadMedia-url url) + + :else + (let [file-id (:current-file-id @st/state)] + (p/create + (fn [resolve reject] + (->> (dwm/upload-media-url name file-id url) + (rx/map u/to-js) + (rx/take 1) + (rx/subs! resolve reject))))))) (group [_ shapes] - (let [file-id (:current-file-id @st/state) - page-id (:current-page-id @st/state) - id (uuid/next) - ids (into #{} (map #(obj/get % "$id")) shapes)] - (st/emit! (dwg/group-shapes id ids)) - (shape/shape-proxy $plugin file-id page-id id))) + (cond + (or (not (array? shapes)) (not (every? shape/shape-proxy? shapes))) + (u/display-not-valid :group-shapes shapes) + + :else + (let [file-id (:current-file-id @st/state) + page-id (:current-page-id @st/state) + id (uuid/next) + ids (into #{} (map #(obj/get % "$id")) shapes)] + (st/emit! (dwg/group-shapes id ids)) + (shape/shape-proxy $plugin file-id page-id id)))) (ungroup [_ group & rest] - (let [shapes (concat [group] rest) - ids (into #{} (map #(obj/get % "$id")) shapes)] - (st/emit! (dwg/ungroup-shapes ids)))) + + (cond + (not (shape/shape-proxy? group)) + (u/display-not-valid :ungroup group) + + (and (some? rest) (not (every? shape/shape-proxy? rest))) + (u/display-not-valid :ungroup rest) + + :else + (let [shapes (concat [group] rest) + ids (into #{} (map #(obj/get % "$id")) shapes)] + (st/emit! (dwg/ungroup-shapes ids))))) (createFrame [_] @@ -161,23 +183,32 @@ (createText [_ text] - (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) - (assoc :position-data nil)) - changes - (-> (cb/empty-changes) - (cb/with-page page) - (cb/with-objects (:objects page)) - (cb/add-object shape))] - (st/emit! (ch/commit-changes changes)) - (shape/shape-proxy $plugin file-id page-id (:id shape)))) + (cond + (or (not (string? text)) (empty? text)) + (u/display-not-valid :createText text) + + :else + (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) + (assoc :position-data nil)) + changes + (-> (cb/empty-changes) + (cb/with-page page) + (cb/with-objects (:objects page)) + (cb/add-object shape))] + (st/emit! (ch/commit-changes changes)) + (shape/shape-proxy $plugin file-id page-id (:id shape))))) (createShapeFromSvg [_ svg-string] - (when (some? svg-string) + (cond + (not (string? svg-string)) + (u/display-not-valid :createShapeFromSvg svg-string) + + :else (let [id (uuid/next) file-id (:current-file-id @st/state) page-id (:current-page-id @st/state)] @@ -185,15 +216,19 @@ (shape/shape-proxy $plugin file-id page-id id)))) (createBoolean [_ bool-type shapes] - (let [ids (into #{} (map #(obj/get % "$id")) shapes) - bool-type (keyword bool-type)] + (let [bool-type (keyword bool-type)] + (cond + (not (contains? cts/bool-types bool-type)) + (u/display-not-valid :createBoolean-boolType bool-type) - (if (contains? cts/bool-types bool-type) - (let [id-ret (atom nil)] + (or (not (array? shapes)) (empty? shapes) (not (every? shape/shape-proxy? shapes))) + (u/display-not-valid :createBoolean-shapes shapes) + + :else + (let [ids (into #{} (map #(obj/get % "$id")) shapes) + id-ret (atom nil)] (st/emit! (dwb/create-bool bool-type ids {:id-ret id-ret})) - (shape/shape-proxy $plugin @id-ret)) - - (utils/display-not-valid :bool-shape bool-type))))) + (shape/shape-proxy $plugin @id-ret)))))) (defn create-context [plugin-id] diff --git a/frontend/src/app/plugins/file.cljs b/frontend/src/app/plugins/file.cljs index 1fd74e29e..9f8ca7380 100644 --- a/frontend/src/app/plugins/file.cljs +++ b/frontend/src/app/plugins/file.cljs @@ -93,6 +93,9 @@ {:name js/Symbol.toStringTag :get (fn [] (str "FileProxy"))}) +(defn file-proxy? [p] + (instance? FileProxy p)) + (defn file-proxy [plugin-id id] (crc/add-properties! diff --git a/frontend/src/app/plugins/flex.cljs b/frontend/src/app/plugins/flex.cljs index e379fcba4..2f7b50bb7 100644 --- a/frontend/src/app/plugins/flex.cljs +++ b/frontend/src/app/plugins/flex.cljs @@ -29,6 +29,9 @@ (st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil nil) (ptk/data-event :layout/update {:ids [$id]}))))) +(defn flex-layout-proxy? [p] + (instance? FlexLayout p)) + (defn flex-layout-proxy [plugin-id file-id page-id id] (-> (FlexLayout. plugin-id file-id page-id id) @@ -151,6 +154,9 @@ (deftype LayoutChildProxy [$plugin $file $page $id]) +(defn layout-child-proxy? [p] + (instance? LayoutChildProxy p)) + (defn layout-child-proxy [plugin-id file-id page-id id] (-> (LayoutChildProxy. plugin-id file-id page-id id) diff --git a/frontend/src/app/plugins/fonts.cljs b/frontend/src/app/plugins/fonts.cljs index 8455ec72b..fec42342d 100644 --- a/frontend/src/app/plugins/fonts.cljs +++ b/frontend/src/app/plugins/fonts.cljs @@ -39,6 +39,9 @@ :font-weight (d/nilv (obj/get variant "fontWeight") fontWeight)}] (st/emit! (dwt/update-text-range id start end values))))) +(defn font-proxy? [p] + (instance? PenpotFont p)) + (defn font-proxy [{:keys [id name variants] :as font}] (when (some? font) diff --git a/frontend/src/app/plugins/grid.cljs b/frontend/src/app/plugins/grid.cljs index 8b0f49ab9..1d9d4799f 100644 --- a/frontend/src/app/plugins/grid.cljs +++ b/frontend/src/app/plugins/grid.cljs @@ -74,6 +74,9 @@ (st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil [row column]) (ptk/data-event :layout/update {:ids [$id]}))))) +(defn grid-layout-proxy? [p] + (instance? GridLayout p)) + (defn grid-layout-proxy [plugin-id file-id page-id id] (-> (GridLayout. plugin-id file-id page-id id) @@ -199,6 +202,9 @@ (deftype GridCellProxy [$plugin $file $page $id]) +(defn layout-cell-proxy? [p] + (instance? GridCellProxy p)) + (defn layout-cell-proxy [plugin-id file-id page-id id] (letfn [(locate-cell [_] diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index 380ff68c3..8107ca375 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -137,6 +137,9 @@ (let [color (u/proxy->library-color self)] (apply array (keys (dm/get-in color [:plugin-data (keyword "shared" namespace)]))))))) +(defn lib-color-proxy? [p] + (instance? LibraryColorProxy p)) + (defn lib-color-proxy [plugin-id file-id id] (assert (uuid? file-id)) @@ -316,6 +319,9 @@ (let [typography (u/proxy->library-typography self)] (apply array (keys (dm/get-in typography [:plugin-data (keyword "shared" namespace)]))))))) +(defn lib-typography-proxy? [p] + (instance? LibraryTypographyProxy p)) + (defn lib-typography-proxy [plugin-id file-id id] (assert (uuid? file-id)) @@ -522,6 +528,9 @@ (let [component (u/proxy->library-component self)] (apply array (keys (dm/get-in component [:plugin-data (keyword "shared" namespace)]))))))) +(defn lib-component-proxy? [p] + (instance? LibraryComponentProxy p)) + (defn lib-component-proxy [plugin-id file-id id] (assert (uuid? file-id)) @@ -643,6 +652,9 @@ (let [file (u/proxy->file self)] (apply array (keys (dm/get-in file [:data :plugin-data (keyword "shared" namespace)]))))))) +(defn library-proxy? [p] + (instance? Library p)) + (defn library-proxy [plugin-id file-id] (assert (uuid? file-id) "File id not valid") diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index 35c1a9dd5..f63cfdd9d 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -107,6 +107,9 @@ {:name js/Symbol.toStringTag :get (fn [] (str "PageProxy"))}) +(defn page-proxy? [p] + (instance? PageProxy p)) + (defn page-proxy [plugin-id file-id id] (crc/add-properties! diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 2048e8afe..5fcf8ce28 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -380,6 +380,9 @@ {:name js/Symbol.toStringTag :get (fn [] (str "ShapeProxy"))}) +(defn shape-proxy? [p] + (instance? ShapeProxy p)) + (defn shape-proxy ([plugin-id id] (shape-proxy plugin-id (:current-file-id @st/state) (:current-page-id @st/state) id)) diff --git a/frontend/src/app/plugins/user.cljs b/frontend/src/app/plugins/user.cljs index eb199f5a6..42cd32f6e 100644 --- a/frontend/src/app/plugins/user.cljs +++ b/frontend/src/app/plugins/user.cljs @@ -38,11 +38,17 @@ {:name "sessionId" :get (fn [_] (str session-id))}))) +(defn current-user-proxy? [p] + (instance? CurrentUserProxy p)) + (defn current-user-proxy [plugin-id session-id] (-> (CurrentUserProxy. plugin-id session-id) (add-user-properties))) +(defn active-user-proxy? [p] + (instance? ActiveUserProxy p)) + (defn active-user-proxy [plugin-id session-id] (-> (ActiveUserProxy. plugin-id session-id) diff --git a/frontend/src/app/plugins/viewport.cljs b/frontend/src/app/plugins/viewport.cljs index 8859f6197..65e4423fb 100644 --- a/frontend/src/app/plugins/viewport.cljs +++ b/frontend/src/app/plugins/viewport.cljs @@ -32,7 +32,10 @@ {:name js/Symbol.toStringTag :get (fn [] (str "ViewportProxy"))}) -(defn create-proxy +(defn viewport-proxy? [p] + (instance? ViewportProxy p)) + +(defn viewport-proxy [plugin-id] (crc/add-properties! (ViewportProxy. plugin-id) From 1794859468b5f1da2294dc8e60a41aaad54e1419 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 19 Jun 2024 11:17:04 +0200 Subject: [PATCH 5/7] :sparkles: Review input validation for plugins --- common/src/app/common/types/shape/export.cljc | 2 + .../src/app/main/ui/workspace/plugins.cljs | 21 +- frontend/src/app/plugins/file.cljs | 6 +- frontend/src/app/plugins/flex.cljs | 328 ++++++--- frontend/src/app/plugins/fonts.cljs | 84 ++- frontend/src/app/plugins/grid.cljs | 367 +++++++--- frontend/src/app/plugins/library.cljs | 211 ++++-- frontend/src/app/plugins/page.cljs | 27 +- frontend/src/app/plugins/public_utils.cljs | 14 +- frontend/src/app/plugins/shape.cljs | 693 +++++++++++++----- frontend/src/app/plugins/viewport.cljs | 16 +- .../plugins/context_shapes_test.cljs | 260 +++++++ 12 files changed, 1532 insertions(+), 497 deletions(-) create mode 100644 frontend/test/frontend_tests/plugins/context_shapes_test.cljs diff --git a/common/src/app/common/types/shape/export.cljc b/common/src/app/common/types/shape/export.cljc index 6d7953a88..ddbf4263b 100644 --- a/common/src/app/common/types/shape/export.cljc +++ b/common/src/app/common/types/shape/export.cljc @@ -8,6 +8,8 @@ (:require [app.common.schema :as sm])) +(def export-types #{:png :jpeg :svg :pdf}) + (sm/def! ::export [:map {:title "ShapeExport"} [:type :keyword] diff --git a/frontend/src/app/main/ui/workspace/plugins.cljs b/frontend/src/app/main/ui/workspace/plugins.cljs index 7cca4d86c..cf55b802d 100644 --- a/frontend/src/app/main/ui/workspace/plugins.cljs +++ b/frontend/src/app/main/ui/workspace/plugins.cljs @@ -72,15 +72,18 @@ (defn open-plugin! [{:keys [plugin-id name description host code icon permissions]}] - (.ɵloadPlugin - js/window - #js {:pluginId plugin-id - :name name - :description description - :host host - :code code - :icon icon - :permissions (apply array permissions)})) + (try + (.ɵloadPlugin + js/window + #js {:pluginId plugin-id + :name name + :description description + :host host + :code code + :icon icon + :permissions (apply array permissions)}) + (catch :default e + (.error js/console "Error" e)))) (mf/defc plugin-management-dialog {::mf/register modal/components diff --git a/frontend/src/app/plugins/file.cljs b/frontend/src/app/plugins/file.cljs index 9f8ca7380..9dc4d34b4 100644 --- a/frontend/src/app/plugins/file.cljs +++ b/frontend/src/app/plugins/file.cljs @@ -35,7 +35,7 @@ (setPluginData [_ key value] (cond - (not (string? key)) + (or (not (string? key)) (empty? key)) (u/display-not-valid :file-plugin-data-key key) (and (some? value) (not (string? value))) @@ -66,10 +66,10 @@ [_ namespace key value] (cond - (not (string? namespace)) + (or (not (string? namespace)) (empty? namespace)) (u/display-not-valid :file-plugin-data-namespace namespace) - (not (string? key)) + (or (not (string? key)) (empty? key)) (u/display-not-valid :file-plugin-data-key key) (and (some? value) (not (string? value))) diff --git a/frontend/src/app/plugins/flex.cljs b/frontend/src/app/plugins/flex.cljs index 2f7b50bb7..098d11f2e 100644 --- a/frontend/src/app/plugins/flex.cljs +++ b/frontend/src/app/plugins/flex.cljs @@ -13,10 +13,13 @@ [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 [proxy->shape]] + [app.plugins.utils :as u] [app.util.object :as obj] [potok.v2.core :as ptk])) +;; Define in `app.plugins.shape` we do this way to prevent circular dependency +(def shape-proxy? nil) + (deftype FlexLayout [$plugin $file $page $id] Object (remove @@ -25,9 +28,14 @@ (appendChild [_ child] - (let [child-id (obj/get child "$id")] - (st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil nil) - (ptk/data-event :layout/update {:ids [$id]}))))) + (cond + (not (shape-proxy? child)) + (u/display-not-valid :appendChild child) + + :else + (let [child-id (obj/get child "$id")] + (st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil nil) + (ptk/data-event :layout/update {:ids [$id]})))))) (defn flex-layout-proxy? [p] (instance? FlexLayout p)) @@ -42,113 +50,165 @@ {:name "$page" :enumerable false :get (constantly page-id)} {:name "dir" - :get #(-> % proxy->shape :layout-flex-dir d/name) + :get #(-> % u/proxy->shape :layout-flex-dir d/name) :set (fn [self value] - (let [id (obj/get self "$id") - value (keyword value)] - (when (contains? ctl/flex-direction-types value) - (st/emit! (dwsl/update-layout #{id} {:layout-flex-dir value})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/flex-direction-types value)) + (u/display-not-valid :dir value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-flex-dir value}))))))} {:name "alignItems" - :get #(-> % proxy->shape :layout-align-items d/name) + :get #(-> % u/proxy->shape :layout-align-items d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/align-items-types value)) + (u/display-not-valid :alignItems value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-align-items value}))))))} {:name "alignContent" - :get #(-> % proxy->shape :layout-align-content d/name) + :get #(-> % u/proxy->shape :layout-align-content d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/align-content-types value)) + (u/display-not-valid :alignContent value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-align-content value}))))))} {:name "justifyItems" - :get #(-> % proxy->shape :layout-justify-items d/name) + :get #(-> % u/proxy->shape :layout-justify-items d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/justify-items-types value)) + (u/display-not-valid :justifyItems value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-justify-items value}))))))} {:name "justifyContent" - :get #(-> % proxy->shape :layout-justify-content d/name) + :get #(-> % u/proxy->shape :layout-justify-content d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/justify-content-types value)) + (u/display-not-valid :justifyContent value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-justify-content value}))))))} {:name "rowGap" - :get #(-> % proxy->shape :layout-gap :row-gap) + :get #(-> % u/proxy->shape :layout-gap :row-gap (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :rowGap value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))} {:name "columnGap" - :get #(-> % proxy->shape :layout-gap :column-gap) + :get #(-> % u/proxy->shape :layout-gap :column-gap (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :columnGap value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))} {:name "verticalPadding" - :get #(-> % proxy->shape :layout-padding :p1) + :get #(-> % u/proxy->shape :layout-padding :p1 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :verticalPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))} {:name "horizontalPadding" - :get #(-> % proxy->shape :layout-padding :p2) + :get #(-> % u/proxy->shape :layout-padding :p2 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :horizontalPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))} {:name "topPadding" - :get #(-> % proxy->shape :layout-padding :p1) + :get #(-> % u/proxy->shape :layout-padding :p1 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :topPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))} {:name "rightPadding" - :get #(-> % proxy->shape :layout-padding :p2) + :get #(-> % u/proxy->shape :layout-padding :p2 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :rightPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))} {:name "bottomPadding" - :get #(-> % proxy->shape :layout-padding :p3) + :get #(-> % u/proxy->shape :layout-padding :p3 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :bottomPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))} {:name "leftPadding" - :get #(-> % proxy->shape :layout-padding :p4) + :get #(-> % u/proxy->shape :layout-padding :p4 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :leftPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))}))) @@ -167,124 +227,184 @@ {:name "$page" :enumerable false :get (constantly page-id)} {:name "absolute" - :get #(-> % proxy->shape :layout-item-absolute boolean) + :get #(-> % u/proxy->shape :layout-item-absolute boolean) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (boolean? value) + (cond + (not (boolean? value)) + (u/display-not-valid :absolute value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-item-absolute value})))))} {:name "zIndex" - :get #(-> % proxy->shape :layout-item-z-index (d/nilv 0)) + :get #(-> % u/proxy->shape :layout-item-z-index (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (us/safe-int? value) + (u/display-not-valid :zIndex value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-z-index value})))))} {:name "horizontalSizing" - :get #(-> % proxy->shape :layout-item-h-sizing (d/nilv :fix) d/name) + :get #(-> % u/proxy->shape :layout-item-h-sizing (d/nilv :fix) d/name) :set (fn [self value] - (let [id (obj/get self "$id") - value (keyword value)] - (when (contains? ctl/item-h-sizing-types value) - (st/emit! (dwsl/update-layout-child #{id} {:layout-item-h-sizing value})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/item-h-sizing-types value)) + (u/display-not-valid :horizontalPadding value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout-child #{id} {:layout-item-h-sizing value}))))))} {:name "verticalSizing" - :get #(-> % proxy->shape :layout-item-v-sizing (d/nilv :fix) d/name) + :get #(-> % u/proxy->shape :layout-item-v-sizing (d/nilv :fix) d/name) :set (fn [self value] - (let [id (obj/get self "$id") - value (keyword value)] - (when (contains? ctl/item-v-sizing-types value) - (st/emit! (dwsl/update-layout-child #{id} {:layout-item-v-sizing value})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/item-v-sizing-types value)) + (u/display-not-valid :verticalSizing value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout-child #{id} {:layout-item-v-sizing value}))))))} {:name "alignSelf" - :get #(-> % proxy->shape :layout-item-align-self (d/nilv :auto) d/name) + :get #(-> % u/proxy->shape :layout-item-align-self (d/nilv :auto) d/name) :set (fn [self value] - (let [id (obj/get self "$id") - value (keyword value)] - (when (contains? ctl/item-align-self-types value) - (st/emit! (dwsl/update-layout-child #{id} {:layout-item-align-self value})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/item-align-self-types value)) + (u/display-not-valid :alignSelf value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout-child #{id} {:layout-item-align-self value}))))))} {:name "verticalMargin" - :get #(-> % proxy->shape :layout-item-margin :m1 (d/nilv 0)) + :get #(-> % u/proxy->shape :layout-item-margin :m1 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :verticalMargin value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m1 value :m3 value}})))))} {:name "horizontalMargin" - :get #(-> % proxy->shape :layout-item-margin :m2 (d/nilv 0)) + :get #(-> % u/proxy->shape :layout-item-margin :m2 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :horizontalMargin value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m2 value :m4 value}})))))} {:name "topMargin" - :get #(-> % proxy->shape :layout-item-margin :m1 (d/nilv 0)) + :get #(-> % u/proxy->shape :layout-item-margin :m1 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :topMargin value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m1 value}})))))} {:name "rightMargin" - :get #(-> % proxy->shape :layout-item-margin :m2 (d/nilv 0)) + :get #(-> % u/proxy->shape :layout-item-margin :m2 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :rightMargin value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m2 value}})))))} {:name "bottomMargin" - :get #(-> % proxy->shape :layout-item-margin :m3 (d/nilv 0)) + :get #(-> % u/proxy->shape :layout-item-margin :m3 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :bottomMargin value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m3 value}})))))} {:name "leftMargin" - :get #(-> % proxy->shape :layout-item-margin :m4 (d/nilv 0)) + :get #(-> % u/proxy->shape :layout-item-margin :m4 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :leftMargin value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m4 value}})))))} {:name "maxWidth" - :get #(-> % proxy->shape :layout-item-max-w) + :get #(-> % u/proxy->shape :layout-item-max-w) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :maxWidth value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-max-w value})))))} {:name "minWidth" - :get #(-> % proxy->shape :layout-item-min-w) + :get #(-> % u/proxy->shape :layout-item-min-w) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :minWidth value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-min-w value})))))} {:name "maxHeight" - :get #(-> % proxy->shape :layout-item-max-h) + :get #(-> % u/proxy->shape :layout-item-max-h) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :maxHeight value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-max-h value})))))} {:name "minHeight" - :get #(-> % proxy->shape :layout-item-min-h) + :get #(-> % u/proxy->shape :layout-item-min-h) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :minHeight value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout-child #{id} {:layout-item-min-h value})))))}))) diff --git a/frontend/src/app/plugins/fonts.cljs b/frontend/src/app/plugins/fonts.cljs index fec42342d..4902277bc 100644 --- a/frontend/src/app/plugins/fonts.cljs +++ b/frontend/src/app/plugins/fonts.cljs @@ -11,6 +11,8 @@ [app.main.data.workspace.texts :as dwt] [app.main.fonts :as fonts] [app.main.store :as st] + [app.plugins.shape :as shape] + [app.plugins.utils :as u] [app.util.object :as obj] [cuerdas.core :as str])) @@ -20,24 +22,38 @@ Object (applyToText [_ text variant] - (let [id (obj/get text "$id") - values {:font-id fontId - :font-family fontFamily - :font-style (d/nilv (obj/get variant "fontStyle") fontStyle) - :font-variant-id (d/nilv (obj/get variant "fontVariantId") fontVariantId) - :font-weight (d/nilv (obj/get variant "fontWeight") fontWeight)}] - (st/emit! (dwt/update-attrs id values)))) + (cond + (not (shape/shape-proxy? text)) + (u/display-not-valid :applyToText text) + + ;; TODO: Check variant inside font variants + + :else + (let [id (obj/get text "$id") + values {:font-id fontId + :font-family fontFamily + :font-style (d/nilv (obj/get variant "fontStyle") fontStyle) + :font-variant-id (d/nilv (obj/get variant "fontVariantId") fontVariantId) + :font-weight (d/nilv (obj/get variant "fontWeight") fontWeight)}] + (st/emit! (dwt/update-attrs id values))))) (applyToRange [_ range variant] - (let [id (obj/get range "$id") - start (obj/get range "start") - end (obj/get range "end") - values {:font-id fontId - :font-family fontFamily - :font-style (d/nilv (obj/get variant "fontStyle") fontStyle) - :font-variant-id (d/nilv (obj/get variant "fontVariantId") fontVariantId) - :font-weight (d/nilv (obj/get variant "fontWeight") fontWeight)}] - (st/emit! (dwt/update-text-range id start end values))))) + (cond + (not (shape/text-range? range)) + (u/display-not-valid :applyToRange range) + + ;; TODO: Check variant inside font variants + + :else + (let [id (obj/get range "$id") + start (obj/get range "start") + end (obj/get range "end") + values {:font-id fontId + :font-family fontFamily + :font-style (d/nilv (obj/get variant "fontStyle") fontStyle) + :font-variant-id (d/nilv (obj/get variant "fontVariantId") fontVariantId) + :font-weight (d/nilv (obj/get variant "fontWeight") fontWeight)}] + (st/emit! (dwt/update-text-range id start end values)))))) (defn font-proxy? [p] (instance? PenpotFont p)) @@ -63,23 +79,43 @@ Object (findById [_ id] - (font-proxy (d/seek #(str/includes? (str/lower (:id %)) (str/lower id)) (vals @fonts/fontsdb)))) + (cond + (not (string? id)) + (u/display-not-valid :findbyId id) + + :else + (font-proxy (d/seek #(str/includes? (str/lower (:id %)) (str/lower id)) (vals @fonts/fontsdb))))) (findByName [_ name] - (font-proxy (d/seek #(str/includes? (str/lower (:name %)) (str/lower name)) (vals @fonts/fontsdb)))) + (cond + (not (string? name)) + (u/display-not-valid :findByName name) + + :else + (font-proxy (d/seek #(str/includes? (str/lower (:name %)) (str/lower name)) (vals @fonts/fontsdb))))) (findAllById [_ id] - (apply array (->> (vals @fonts/fontsdb) - (filter #(str/includes? (str/lower (:id %)) (str/lower id))) - (map font-proxy)))) + (cond + (not (string? id)) + (u/display-not-valid :findAllById name) + + :else + (apply array (->> (vals @fonts/fontsdb) + (filter #(str/includes? (str/lower (:id %)) (str/lower id))) + (map font-proxy))))) (findAllByName [_ name] - (apply array (->> (vals @fonts/fontsdb) - (filter #(str/includes? (str/lower (:name %)) (str/lower name))) - (map font-proxy))))) + (cond + (not (string? name)) + (u/display-not-valid :findAllByName name) + + :else + (apply array (->> (vals @fonts/fontsdb) + (filter #(str/includes? (str/lower (:name %)) (str/lower name))) + (map font-proxy)))))) (defn fonts-subcontext [plugin-id] diff --git a/frontend/src/app/plugins/grid.cljs b/frontend/src/app/plugins/grid.cljs index 1d9d4799f..a715e0c7a 100644 --- a/frontend/src/app/plugins/grid.cljs +++ b/frontend/src/app/plugins/grid.cljs @@ -13,15 +13,18 @@ [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 [proxy->shape locate-shape]] + [app.plugins.utils :as u] [app.util.object :as obj] [potok.v2.core :as ptk])) +;; Define in `app.plugins.shape` we do this way to prevent circular dependency +(def shape-proxy? nil) + (defn- make-tracks [tracks] (.freeze js/Object - (apply array (->> tracks (map utils/to-js))))) + (apply array (->> tracks (map u/to-js))))) (deftype GridLayout [$plugin $file $page $id] Object @@ -29,40 +32,116 @@ (addRow [_ type value] (let [type (keyword type)] - (st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value})))) + (cond + (not (contains? ctl/grid-track-types type)) + (u/display-not-valid :addRow-type type) + + (and (or (= :percent type) (= :flex type) (= :fixed type)) + (not (us/safe-number? value))) + (u/display-not-valid :addRow-value value) + + :else + (st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value}))))) (addRowAtIndex [_ index type value] (let [type (keyword type)] - (st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value} index)))) + (cond + (not (us/safe-int? index)) + (u/display-not-valid :addRowAtIndex-index index) + + (not (contains? ctl/grid-track-types type)) + (u/display-not-valid :addRowAtIndex-type type) + + (and (or (= :percent type) (= :flex type) (= :fixed type)) + (not (us/safe-number? value))) + (u/display-not-valid :addRowAtIndex-value value) + + :else + (st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value} index))))) (addColumn [_ type value] (let [type (keyword type)] - (st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value})))) + (cond + (not (contains? ctl/grid-track-types type)) + (u/display-not-valid :addColumn-type type) + + (and (or (= :percent type) (= :flex type) (= :lex type)) + (not (us/safe-number? value))) + (u/display-not-valid :addColumn-value value) + + :else + (st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value}))))) (addColumnAtIndex [_ index type value] - (let [type (keyword type)] - (st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value} index)))) + (cond + (not (us/safe-int? index)) + (u/display-not-valid :addColumnAtIndex-index index) + + (not (contains? ctl/grid-track-types type)) + (u/display-not-valid :addColumnAtIndex-type type) + + (and (or (= :percent type) (= :flex type) (= :fixed type)) + (not (us/safe-number? value))) + (u/display-not-valid :addColumnAtIndex-value value) + + :else + (let [type (keyword type)] + (st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value} index))))) (removeRow [_ index] - (st/emit! (dwsl/remove-layout-track #{$id} :row index))) + (cond + (not (us/safe-int? index)) + (u/display-not-valid :removeRow index) + + :else + (st/emit! (dwsl/remove-layout-track #{$id} :row index)))) (removeColumn [_ index] - (st/emit! (dwsl/remove-layout-track #{$id} :column index))) + (cond + (not (us/safe-int? index)) + (u/display-not-valid :removeColumn index) + + :else + (st/emit! (dwsl/remove-layout-track #{$id} :column index)))) (setColumn [_ index type value] (let [type (keyword type)] - (st/emit! (dwsl/change-layout-track #{$id} :column index (d/without-nils {:type type :value value}))))) + (cond + (not (us/safe-int? index)) + (u/display-not-valid :setColumn-index index) + + (not (contains? ctl/grid-track-types type)) + (u/display-not-valid :setColumn-type type) + + (and (or (= :percent type) (= :flex type) (= :fixed type)) + (not (us/safe-number? value))) + (u/display-not-valid :setColumn-value value) + + :else + (st/emit! (dwsl/change-layout-track #{$id} :column index (d/without-nils {:type type :value value})))))) (setRow [_ index type value] (let [type (keyword type)] - (st/emit! (dwsl/change-layout-track #{$id} :row index (d/without-nils {:type type :value value}))))) + (cond + (not (us/safe-int? index)) + (u/display-not-valid :setRow-index index) + + (not (contains? ctl/grid-track-types type)) + (u/display-not-valid :setRow-type type) + + (and (or (= :percent type) (= :flex type) (= :fixed type)) + (not (us/safe-number? value))) + (u/display-not-valid :setRow-value value) + + :else + (st/emit! (dwsl/change-layout-track #{$id} :row index (d/without-nils {:type type :value value})))))) (remove [_] @@ -70,9 +149,20 @@ (appendChild [_ 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]}))))) + (cond + (not (shape-proxy? child)) + (u/display-not-valid :appendChild-child child) + + (or (< row 0) (not (us/safe-int? row))) + (u/display-not-valid :appendChild-row row) + + (or (< column 0) (not (us/safe-int? column))) + (u/display-not-valid :appendChild-column column) + + :else + (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? [p] (instance? GridLayout p)) @@ -85,119 +175,172 @@ {:name "$id" :enumerable false :get (constantly id)} {:name "$file" :enumerable false :get (constantly file-id)} {:name "$page" :enumerable false :get (constantly page-id)} + {:name "dir" - :get #(-> % proxy->shape :layout-grid-dir d/name) + :get #(-> % u/proxy->shape :layout-grid-dir d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/grid-direction-types value)) + (u/display-not-valid :dir value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-grid-dir value}))))))} {:name "rows" - :get #(-> % proxy->shape :layout-grid-rows make-tracks)} + :get #(-> % u/proxy->shape :layout-grid-rows make-tracks)} {:name "columns" - :get #(-> % proxy->shape :layout-grid-columns make-tracks)} + :get #(-> % u/proxy->shape :layout-grid-columns make-tracks)} {:name "alignItems" - :get #(-> % proxy->shape :layout-align-items d/name) + :get #(-> % u/proxy->shape :layout-align-items d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/align-items-types value)) + (u/display-not-valid :alignItems value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-align-items value}))))))} {:name "alignContent" - :get #(-> % proxy->shape :layout-align-content d/name) + :get #(-> % u/proxy->shape :layout-align-content d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/align-content-types value)) + (u/display-not-valid :alignContent value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-align-content value}))))))} {:name "justifyItems" - :get #(-> % proxy->shape :layout-justify-items d/name) + :get #(-> % u/proxy->shape :layout-justify-items d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/justify-items-types value)) + (u/display-not-valid :justifyItems value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-justify-items value}))))))} {:name "justifyContent" - :get #(-> % proxy->shape :layout-justify-content d/name) + :get #(-> % u/proxy->shape :layout-justify-content d/name) :set (fn [self value] - (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})))))} + (let [value (keyword value)] + (cond + (not (contains? ctl/justify-content-types value)) + (u/display-not-valid :justifyContent value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsl/update-layout #{id} {:layout-justify-content value}))))))} {:name "rowGap" - :get #(-> % proxy->shape :layout-gap :row-gap) + :get #(-> % u/proxy->shape :layout-gap :row-gap (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :rowGap value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))} {:name "columnGap" - :get #(-> % proxy->shape :layout-gap :column-gap) + :get #(-> % u/proxy->shape :layout-gap :column-gap (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :columnGap value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))} {:name "verticalPadding" - :get #(-> % proxy->shape :layout-padding :p1) + :get #(-> % u/proxy->shape :layout-padding :p1 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :verticalPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))} {:name "horizontalPadding" - :get #(-> % proxy->shape :layout-padding :p2) + :get #(-> % u/proxy->shape :layout-padding :p2 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :horizontalPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))} {:name "topPadding" - :get #(-> % proxy->shape :layout-padding :p1) + :get #(-> % u/proxy->shape :layout-padding :p1 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :topPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))} {:name "rightPadding" - :get #(-> % proxy->shape :layout-padding :p2) + :get #(-> % u/proxy->shape :layout-padding :p2 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :rightPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))} {:name "bottomPadding" - :get #(-> % proxy->shape :layout-padding :p3) + :get #(-> % u/proxy->shape :layout-padding :p3 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :bottomPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))} {:name "leftPadding" - :get #(-> % proxy->shape :layout-padding :p4) + :get #(-> % u/proxy->shape :layout-padding :p4 (d/nilv 0)) :set (fn [self value] - (let [id (obj/get self "$id")] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :leftPadding value) + + :else + (let [id (obj/get self "$id")] (st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))}))) (deftype GridCellProxy [$plugin $file $page $id]) @@ -208,8 +351,8 @@ (defn layout-cell-proxy [plugin-id file-id page-id id] (letfn [(locate-cell [_] - (let [shape (locate-shape file-id page-id id) - parent (locate-shape file-id page-id (:parent-id shape))] + (let [shape (u/locate-shape file-id page-id id) + parent (u/locate-shape file-id page-id (:parent-id shape))] (ctl/get-cell-by-shape-id parent id)))] (-> (GridCellProxy. plugin-id file-id page-id id) @@ -223,73 +366,129 @@ :get #(-> % locate-cell :row) :set (fn [self value] - (let [shape (proxy->shape self) - cell (locate-cell self)] - (when (us/safe-int? value) + (let [cell (locate-cell self) + shape (u/proxy->shape self)] + (cond + (not (us/safe-int? value)) + (u/display-not-valid :row value) + + (nil? cell) + (u/display-not-valid :cell "cell not found") + + :else (st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:row value})))))} {:name "rowSpan" :get #(-> % locate-cell :row-span) :set (fn [self value] - (let [shape (proxy->shape self) + (let [shape (u/proxy->shape self) cell (locate-cell self)] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :rowSpan-value value) + + (nil? cell) + (u/display-not-valid :rowSpan-cell "cell not found") + + :else (st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:row-span value})))))} {:name "column" :get #(-> % locate-cell :column) :set (fn [self value] - (let [shape (proxy->shape self) + (let [shape (u/proxy->shape self) cell (locate-cell self)] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :column-value value) + + (nil? cell) + (u/display-not-valid :column-cell "cell not found") + + :else (st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:column value})))))} {:name "columnSpan" :get #(-> % locate-cell :column-span) :set (fn [self value] - (let [shape (proxy->shape self) + (let [shape (u/proxy->shape self) cell (locate-cell self)] - (when (us/safe-int? value) + (cond + (not (us/safe-int? value)) + (u/display-not-valid :columnSpan-value value) + + (nil? cell) + (u/display-not-valid :columnSpan-cell "cell not found") + + :else (st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:column-span value})))))} {:name "areaName" :get #(-> % locate-cell :area-name) :set (fn [self value] - (let [shape (proxy->shape self) + (let [shape (u/proxy->shape self) cell (locate-cell self)] - (when (string? value) + (cond + (not (string? value)) + (u/display-not-valid :areaName-value value) + + (nil? cell) + (u/display-not-valid :areaName-cell "cell not found") + + :else (st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:area-name value})))))} {:name "position" :get #(-> % locate-cell :position d/name) :set (fn [self value] - (let [shape (proxy->shape self) + (let [shape (u/proxy->shape self) cell (locate-cell self) value (keyword value)] - (when (contains? ctl/grid-position-types value) + (cond + (not (contains? ctl/grid-position-types value)) + (u/display-not-valid :position-value value) + + (nil? cell) + (u/display-not-valid :position-cell "cell not found") + + :else (st/emit! (dwsl/change-cells-mode (:parent-id shape) #{(:id cell)} value)))))} {:name "alignSelf" :get #(-> % locate-cell :align-self d/name) :set (fn [self value] - (let [shape (proxy->shape self) + (let [shape (u/proxy->shape self) value (keyword value) cell (locate-cell self)] - (when (contains? ctl/grid-cell-align-self-types value) + (cond + (not (contains? ctl/grid-cell-align-self-types value)) + (u/display-not-valid :alignSelf-value value) + + (nil? cell) + (u/display-not-valid :alignSelf-cell "cell not found") + + :else (st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:align-self value})))))} {:name "justifySelf" :get #(-> % locate-cell :justify-self d/name) :set (fn [self value] - (let [shape (proxy->shape self) + (let [shape (u/proxy->shape self) value (keyword value) cell (locate-cell self)] - (when (contains? ctl/grid-cell-justify-self-types value) + (cond + (not (contains? ctl/grid-cell-justify-self-types value)) + (u/display-not-valid :justifySelf-value value) + + (nil? cell) + (u/display-not-valid :justifySelf-cell "cell not found") + + :else (st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:justify-self value})))))})))) diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index 8107ca375..de163e8b5 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -20,7 +20,7 @@ [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.texts :as dwt] [app.main.store :as st] - [app.plugins.shape :as shapes] + [app.plugins.shape :as shape] [app.plugins.utils :as u] [app.util.object :as obj])) @@ -157,63 +157,81 @@ :get #(-> % u/proxy->library-color :name) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-color-name value) + + :else (let [color (u/proxy->library-color self) value (dm/str (d/nilv (:path color) "") " / " value)] - (st/emit! (dwl/rename-color file-id id value))) - (u/display-not-valid :library-color-name value)))} + (st/emit! (dwl/rename-color file-id id value)))))} {:name "path" :get #(-> % u/proxy->library-color :path) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-color-path value) + + :else (let [color (-> (u/proxy->library-color self) (update :name #(str value " / " %)))] - (st/emit! (dwl/update-color color file-id))) - (u/display-not-valid :library-color-path value)))} + (st/emit! (dwl/update-color color file-id)))))} {:name "color" :get #(-> % u/proxy->library-color :color) :set (fn [self value] - (if (and (some? value) (string? value) (cc/valid-hex-color? value)) + (cond + (or (not (string? value)) (not (cc/valid-hex-color? value))) + (u/display-not-valid :library-color-color value) + + :else (let [color (-> (u/proxy->library-color self) (assoc :color value))] - (st/emit! (dwl/update-color color file-id))) - (u/display-not-valid :library-color-color value)))} + (st/emit! (dwl/update-color color file-id)))))} {:name "opacity" :get #(-> % u/proxy->library-color :opacity) :set (fn [self value] - (if (and (some? value) (number? value) (>= value 0) (<= value 1)) + (cond + (or (not (number? value)) (< value 0) (> value 1)) + (u/display-not-valid :library-color-opacity value) + + :else (let [color (-> (u/proxy->library-color self) (assoc :opacity value))] - (st/emit! (dwl/update-color color file-id))) - (u/display-not-valid :library-color-opacity value)))} + (st/emit! (dwl/update-color color file-id)))))} {:name "gradient" :get #(-> % u/proxy->library-color :gradient u/to-js) :set (fn [self value] (let [value (u/from-js value)] - (if (sm/fast-check! ::ctc/gradient value) + (cond + (not (sm/validate ::ctc/gradient value)) + (u/display-not-valid :library-color-gradient value) + + :else (let [color (-> (u/proxy->library-color self) (assoc :gradient value))] - (st/emit! (dwl/update-color color file-id))) - (u/display-not-valid :library-color-gradient value))))} + (st/emit! (dwl/update-color color file-id))))))} {:name "image" :get #(-> % u/proxy->library-color :image u/to-js) :set (fn [self value] (let [value (u/from-js value)] - (if (sm/fast-check! ::ctc/image-color value) + (cond + (not (sm/validate ::ctc/image-color value)) + (u/display-not-valid :library-color-image value) + + :else (let [color (-> (u/proxy->library-color self) (assoc :image value))] - (st/emit! (dwl/update-color color file-id))) - (u/display-not-valid :library-color-image value))))})) + (st/emit! (dwl/update-color color file-id))))))})) (deftype LibraryTypographyProxy [$plugin $file $id] Object @@ -231,21 +249,31 @@ (applyToText [_ shape] - (let [shape-id (obj/get shape "$id") - typography (u/locate-library-typography $file $id)] - (st/emit! (dwt/apply-typography #{shape-id} typography $file)))) + (cond + (not (shape/shape-proxy? shape)) + (u/display-not-valid :applyToText shape) + + :else + (let [shape-id (obj/get shape "$id") + typography (u/locate-library-typography $file $id)] + (st/emit! (dwt/apply-typography #{shape-id} typography $file))))) (applyToTextRange [self range] - (let [shape-id (obj/get range "$id") - start (obj/get range "start") - end (obj/get range "end") - typography (u/proxy->library-typography self) - attrs (-> typography - (assoc :typography-ref-file $file) - (assoc :typography-ref-id (:id typography)) - (dissoc :id :name))] - (st/emit! (dwt/update-text-range shape-id start end attrs)))) + (cond + (not (shape/text-range? range)) + (u/display-not-valid :applyToText range) + + :else + (let [shape-id (obj/get range "$id") + start (obj/get range "start") + end (obj/get range "end") + typography (u/proxy->library-typography self) + attrs (-> typography + (assoc :typography-ref-file $file) + (assoc :typography-ref-id (:id typography)) + (dissoc :id :name))] + (st/emit! (dwt/update-text-range shape-id start end attrs))))) ;; PLUGIN DATA (getPluginData @@ -322,6 +350,8 @@ (defn lib-typography-proxy? [p] (instance? LibraryTypographyProxy p)) +(set! shape/lib-typography-proxy? lib-typography-proxy?) + (defn lib-typography-proxy [plugin-id file-id id] (assert (uuid? file-id)) @@ -338,111 +368,144 @@ :get #(-> % u/proxy->library-typography :name) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-name value) + + :else (let [typo (u/proxy->library-typography self) value (dm/str (d/nilv (:path typo) "") " / " value)] - (st/emit! (dwl/rename-typography file-id id value))) - (u/display-not-valid :library-typography-name value)))} + (st/emit! (dwl/rename-typography file-id id value)))))} {:name "path" :get #(-> % u/proxy->library-typography :path) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-path value) + + :else (let [typo (-> (u/proxy->library-typography self) (update :name #(str value " / " %)))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-path value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "fontId" :get #(-> % u/proxy->library-typography :font-id) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-font-id value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :font-id value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-font-id value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "fontFamily" :get #(-> % u/proxy->library-typography :font-family) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-font-family value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :font-family value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-font-family value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "fontVariantId" :get #(-> % u/proxy->library-typography :font-variant-id) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-font-variant-id value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :font-variant-id value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-font-variant-id value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "fontSize" :get #(-> % u/proxy->library-typography :font-size) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-font-size value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :font-size value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-font-size value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "fontWeight" :get #(-> % u/proxy->library-typography :font-weight) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-font-weight value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :font-weight value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-font-weight value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "fontStyle" :get #(-> % u/proxy->library-typography :font-style) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-font-style value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :font-style value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-font-style value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "lineHeight" :get #(-> % u/proxy->library-typography :font-height) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-font-height value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :font-height value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-font-height value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "letterSpacing" :get #(-> % u/proxy->library-typography :letter-spacing) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-letter-spacing value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :letter-spacing value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-letter-spacing value)))} + (st/emit! (dwl/update-typography typo file-id)))))} {:name "textTransform" :get #(-> % u/proxy->library-typography :text-transform) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-typography-text-transform value) + + :else (let [typo (-> (u/proxy->library-typography self) (assoc :text-transform value))] - (st/emit! (dwl/update-typography typo file-id))) - (u/display-not-valid :library-typography-text-transform value)))})) + (st/emit! (dwl/update-typography typo file-id)))))})) (deftype LibraryComponentProxy [$plugin $file $id] Object @@ -455,7 +518,7 @@ [_] (let [id-ref (atom nil)] (st/emit! (dwl/instantiate-component $file $id (gpt/point 0 0) {:id-ref id-ref})) - (shapes/shape-proxy $plugin @id-ref))) + (shape/shape-proxy $plugin @id-ref))) (getPluginData [self key] @@ -547,21 +610,27 @@ :get #(-> % u/proxy->library-component :name) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-component-name value) + + :else (let [component (u/proxy->library-component self) value (dm/str (d/nilv (:path component) "") " / " value)] - (st/emit! (dwl/rename-component id value))) - (u/display-not-valid :library-component-name value)))} + (st/emit! (dwl/rename-component id value)))))} {:name "path" :get #(-> % u/proxy->library-component :path) :set (fn [self value] - (if (and (some? value) (string? value)) + (cond + (not (string? value)) + (u/display-not-valid :library-component-path value) + + :else (let [component (u/proxy->library-component self) value (dm/str value " / " (:name component))] - (st/emit! (dwl/rename-component id value))) - (u/display-not-valid :library-component-path value)))})) + (st/emit! (dwl/rename-component id value)))))})) (deftype Library [$plugin $id] Object diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index f63cfdd9d..91da5bb0c 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -21,8 +21,13 @@ Object (getShapeById [_ shape-id] - (let [shape-id (uuid/uuid shape-id)] - (shape/shape-proxy $plugin $file $id shape-id))) + (cond + (not (string? shape-id)) + (u/display-not-valid :getShapeById shape-id) + + :else + (let [shape-id (uuid/uuid shape-id)] + (shape/shape-proxy $plugin $file $id shape-id)))) (getRoot [_] @@ -125,9 +130,12 @@ :get #(-> % u/proxy->page :name) :set (fn [_ value] - (if (string? value) - (st/emit! (dw/rename-page id value)) - (u/display-not-valid :page-name value)))} + (cond + (not (string? value)) + (u/display-not-valid :page-name value) + + :else + (st/emit! (dw/rename-page id value))))} {:name "root" :enumerable false @@ -138,6 +146,9 @@ :get #(or (-> % u/proxy->page :options :background) cc/canvas) :set (fn [_ value] - (if (and (some? value) (string? value) (cc/valid-hex-color? value)) - (st/emit! (dw/change-canvas-color id {:color value})) - (u/display-not-valid :page-background-color value)))})) + (cond + (or (not (string? value)) (not (cc/valid-hex-color? value))) + (u/display-not-valid :page-background-color value) + + :else + (st/emit! (dw/change-canvas-color id {:color value}))))})) diff --git a/frontend/src/app/plugins/public_utils.cljs b/frontend/src/app/plugins/public_utils.cljs index 6ebe31151..4ea08fa57 100644 --- a/frontend/src/app/plugins/public_utils.cljs +++ b/frontend/src/app/plugins/public_utils.cljs @@ -9,11 +9,17 @@ (:require [app.common.geom.rect :as grc] [app.common.geom.shapes :as gsh] + [app.plugins.shape :as shape] [app.plugins.utils :as u])) (defn ^:export centerShapes [shapes] - (let [shapes (->> shapes (map u/proxy->shape))] - (-> (gsh/shapes->rect shapes) - (grc/rect->center) - (u/to-js)))) + (cond + (not (every? shape/shape-proxy? shapes)) + (u/display-not-valid :centerShapes shapes) + + :else + (let [shapes (->> shapes (map u/proxy->shape))] + (-> (gsh/shapes->rect shapes) + (grc/rect->center) + (u/to-js))))) diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 5fcf8ce28..44cc2af73 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -14,12 +14,18 @@ [app.common.geom.rect :as grc] [app.common.geom.shapes :as gsh] [app.common.record :as crc] + [app.common.schema :as sm] [app.common.spec :as us] [app.common.svg.path.legacy-parser2 :as spp] [app.common.text :as txt] + [app.common.types.grid :as ctg] [app.common.types.shape :as cts] + [app.common.types.shape.blur :as ctsb] + [app.common.types.shape.export :as ctse] [app.common.types.shape.layout :as ctl] + [app.common.types.shape.path :as ctsp] [app.common.types.shape.radius :as ctsr] + [app.common.types.shape.shadow :as ctss] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] [app.main.data.workspace.groups :as dwg] @@ -36,6 +42,7 @@ [app.util.text-editor :as ted] [cuerdas.core :as str])) +(def lib-typography-proxy? nil) (deftype TextRange [$plugin $file $page $id start end] Object @@ -52,7 +59,10 @@ (let [s (set values)] (if (= (count s) 1) (first s) "mixed"))) -;; TODO Validate inputs +(defn text-range? + [range] + (instance? TextRange range)) + (defn text-range [plugin-id file-id page-id id start end] (-> (TextRange. plugin-id file-id page-id id start end) @@ -77,7 +87,12 @@ :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:font-id value})))} + (cond + (not (string? value)) + (u/display-not-valid :fontId value) + + :else + (st/emit! (dwt/update-text-range id start end {:font-id value}))))} {:name "fontFamily" :get #(let [range-data @@ -86,7 +101,12 @@ :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:font-family value})))} + (cond + (not (string? value)) + (u/display-not-valid :fontFamily value) + + :else + (st/emit! (dwt/update-text-range id start end {:font-family value}))))} {:name "fontVariantId" :get #(let [range-data @@ -94,7 +114,12 @@ (->> range-data (map :font-variant-id) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:font-variant-id value})))} + (cond + (not (string? value)) + (u/display-not-valid :fontVariantId value) + + :else + (st/emit! (dwt/update-text-range id start end {:font-variant-id value}))))} {:name "fontSize" :get #(let [range-data @@ -102,7 +127,12 @@ (->> range-data (map :font-size) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:font-size value})))} + (cond + (not (string? value)) + (u/display-not-valid :fontSize value) + + :else + (st/emit! (dwt/update-text-range id start end {:font-size value}))))} {:name "fontWeight" :get #(let [range-data @@ -110,7 +140,12 @@ (->> range-data (map :font-weight) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:font-weight value})))} + (cond + (not (string? value)) + (u/display-not-valid :fontWeight value) + + :else + (st/emit! (dwt/update-text-range id start end {:font-weight value}))))} {:name "fontStyle" :get #(let [range-data @@ -118,7 +153,12 @@ (->> range-data (map :font-style) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:font-style value})))} + (cond + (not (string? value)) + (u/display-not-valid :fontStyle value) + + :else + (st/emit! (dwt/update-text-range id start end {:font-style value}))))} {:name "lineHeight" :get #(let [range-data @@ -126,7 +166,12 @@ (->> range-data (map :line-height) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:line-height value})))} + (cond + (not (string? value)) + (u/display-not-valid :lineHeight value) + + :else + (st/emit! (dwt/update-text-range id start end {:line-height value}))))} {:name "letterSpacing" :get #(let [range-data @@ -134,7 +179,12 @@ (->> range-data (map :letter-spacing) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:letter-spacing value})))} + (cond + (not (string? value)) + (u/display-not-valid :letterSpacing value) + + :else + (st/emit! (dwt/update-text-range id start end {:letter-spacing value}))))} {:name "textTransform" :get #(let [range-data @@ -142,7 +192,12 @@ (->> range-data (map :text-transform) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:text-transform value})))} + (cond + (not (string? value)) + (u/display-not-valid :textTransform value) + + :else + (st/emit! (dwt/update-text-range id start end {:text-transform value}))))} {:name "textDecoration" :get #(let [range-data @@ -150,7 +205,12 @@ (->> range-data (map :text-decoration) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:text-decoration value})))} + (cond + (not (string? value)) + (u/display-not-valid :textDecoration value) + + :else + (st/emit! (dwt/update-text-range id start end {:text-decoration value}))))} {:name "direction" :get #(let [range-data @@ -158,7 +218,12 @@ (->> range-data (map :direction) mixed-value)) :set (fn [_ value] - (st/emit! (dwt/update-text-range id start end {:direction value})))} + (cond + (not (string? value)) + (u/display-not-valid :direction value) + + :else + (st/emit! (dwt/update-text-range id start end {:direction value}))))} {:name "fills" :get #(let [range-data @@ -167,7 +232,12 @@ :set (fn [_ value] (let [value (mapv #(u/from-js %) value)] - (st/emit! (dwt/update-text-range id start end {:fills value}))))}))) + (cond + (not (sm/validate [:vector ::cts/fill] value)) + (u/display-not-valid :fills value) + + :else + (st/emit! (dwt/update-text-range id start end {:fills value})))))}))) (declare shape-proxy) @@ -199,8 +269,16 @@ Object (resize [_ width height] - (st/emit! (dw/update-dimensions [$id] :width width) - (dw/update-dimensions [$id] :height height))) + (cond + (or (not (us/safe-number? width)) (<= width 0)) + (u/display-not-valid :resize width) + + (or (not (us/safe-number? height)) (<= height 0)) + (u/display-not-valid :resize height) + + :else + (st/emit! (dw/update-dimensions [$id] :width width) + (dw/update-dimensions [$id] :height height)))) (rotate [self angle center] @@ -363,17 +441,32 @@ (getRange [_ start end] (let [shape (u/locate-shape $file $page $id)] - (if (cfh/text-shape? shape) - (text-range $plugin $file $page $id start end) - (u/display-not-valid :makeMask (:type shape))))) + (cond + (not (cfh/text-shape? shape)) + (u/display-not-valid :getRange-shape "shape is not text") + + (or (not (us/safe-int? start)) (< start 0) (> start end)) + (u/display-not-valid :getRange-start start) + + (not (us/safe-int? end)) + (u/display-not-valid :getRange-end end) + + :else + (text-range $plugin $file $page $id start end)))) (applyTypography [_ typography] (let [shape (u/locate-shape $file $page $id)] - (if (cfh/text-shape? shape) + (cond + (not (lib-typography-proxy? typography)) + (u/display-not-valid :applyTypography-typography typography) + + (not (cfh/text-shape? shape)) + (u/display-not-valid :applyTypography-shape (:type shape)) + + :else (let [typography (u/proxy->library-typography typography)] - (st/emit! (dwt/apply-typography #{$id} typography $file))) - (u/display-not-valid :applyTypography (:type shape)))))) + (st/emit! (dwt/apply-typography #{$id} typography $file))))))) (crc/define-properties! ShapeProxy @@ -383,6 +476,10 @@ (defn shape-proxy? [p] (instance? ShapeProxy p)) +;; Prevent circular dependency +(do (set! flex/shape-proxy? shape-proxy?) + (set! grid/shape-proxy? shape-proxy?)) + (defn shape-proxy ([plugin-id id] (shape-proxy plugin-id (:current-file-id @st/state) (:current-page-id @st/state) id)) @@ -411,155 +508,251 @@ {:name "name" :get #(-> % u/proxy->shape :name) - :set (fn [self value] - (let [id (obj/get self "$id") - value (when (string? value) (-> value str/trim cfh/clean-path)) - valid? (and (some? value) - (not (str/ends-with? value "/")) - (not (str/blank? value)))] - (if valid? - (st/emit! (dwsh/update-shapes [id] #(assoc % :name value))) - (u/display-not-valid :shape-name value))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + value (when (string? value) (-> value str/trim cfh/clean-path)) + valid? (and (some? value) + (not (str/ends-with? value "/")) + (not (str/blank? value)))] + (cond + (not valid?) + (u/display-not-valid :shape-name value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :name value))))))} {:name "blocked" :get #(-> % u/proxy->shape :blocked boolean) - :set (fn [self value] - (let [id (obj/get self "$id")] - (st/emit! (dwsh/update-shapes [id] #(assoc % :blocked value)))))} + :set + (fn [self value] + (cond + (not (boolean? value)) + (u/display-not-valid :blocked value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsh/update-shapes [id] #(assoc % :blocked value))))))} {:name "hidden" :get #(-> % u/proxy->shape :hidden boolean) - :set (fn [self value] - (let [id (obj/get self "$id")] - (st/emit! (dwsh/update-shapes [id] #(assoc % :hidden value)))))} + :set + (fn [self value] + (cond + (not (boolean? value)) + (u/display-not-valid :hidden value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsh/update-shapes [id] #(assoc % :hidden value))))))} {:name "proportionLock" :get #(-> % u/proxy->shape :proportion-lock boolean) - :set (fn [self value] - (let [id (obj/get self "$id")] - (st/emit! (dwsh/update-shapes [id] #(assoc % :proportion-lock value)))))} + :set + (fn [self value] + (cond + (not (boolean? value)) + (u/display-not-valid :proportionLock value) + + :else + (let [id (obj/get self "$id")] + (st/emit! (dwsh/update-shapes [id] #(assoc % :proportion-lock value))))))} {:name "constraintsHorizontal" :get #(-> % u/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! (dwsh/update-shapes [id] #(assoc % :constraints-h value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + value (keyword value)] + (cond + (not (contains? cts/horizontal-constraint-types value)) + (u/display-not-valid :constraintsHorizontal value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :constraints-h value))))))} {:name "constraintsVertical" :get #(-> % u/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! (dwsh/update-shapes [id] #(assoc % :constraints-v value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + value (keyword value)] + (cond + (not (contains? cts/vertical-constraint-types value)) + (u/display-not-valid :constraintsVertical value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :constraints-v value))))))} {:name "borderRadius" :get #(-> % u/proxy->shape :rx) - :set (fn [self value] - (let [id (obj/get self "$id") - shape (u/proxy->shape self)] - (when (us/safe-int? value) - (when (or (not (ctsr/has-radius? shape)) (ctsr/radius-4? shape)) - (st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-1))) - (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-1 % value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + shape (u/proxy->shape self)] + (cond + (or (not (us/safe-int? value)) (< value 0)) + (u/display-not-valid :borderRadius value) + + (or (not (ctsr/has-radius? shape)) (ctsr/radius-4? shape)) + (st/emit! (dwsh/update-shapes [id] #(-> % + ctsr/switch-to-radius-1 + (ctsr/set-radius-1 value)))) + + :else + (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-1 % value))))))} {:name "borderRadiusTopLeft" :get #(-> % u/proxy->shape :r1) - :set (fn [self value] - (let [id (obj/get self "$id") - shape (u/proxy->shape self)] - (when (us/safe-int? value) - (when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) - (st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4))) - (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r1 value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + shape (u/proxy->shape self)] + (cond + (not (us/safe-int? value)) + (u/display-not-valid :borderRadiusTopLeft value) + + (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) + (st/emit! (dwsh/update-shapes [id] #(-> % + (ctsr/switch-to-radius-4) + (ctsr/set-radius-4 :r1 value)))) + + :else + (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r1 value))))))} {:name "borderRadiusTopRight" :get #(-> % u/proxy->shape :r2) - :set (fn [self value] - (let [id (obj/get self "$id") - shape (u/proxy->shape self)] - (when (us/safe-int? value) - (when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) - (st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4))) - (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r2 value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + shape (u/proxy->shape self)] + (cond + (not (us/safe-int? value)) + (u/display-not-valid :borderRadiusTopRight value) + + (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) + (st/emit! (dwsh/update-shapes [id] #(-> % + (ctsr/switch-to-radius-4) + (ctsr/set-radius-4 :r2 value)))) + + :else + (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r2 value))))))} {:name "borderRadiusBottomRight" :get #(-> % u/proxy->shape :r3) - :set (fn [self value] - (let [id (obj/get self "$id") - shape (u/proxy->shape self)] - (when (us/safe-int? value) - (when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) - (st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4))) - (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r3 value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + shape (u/proxy->shape self)] + (cond + (not (us/safe-int? value)) + (u/display-not-valid :borderRadiusBottomRight value) + + (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) + (st/emit! (dwsh/update-shapes [id] #(-> % + (ctsr/switch-to-radius-4) + (ctsr/set-radius-4 :r3 value)))) + + :else + (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r3 value))))))} {:name "borderRadiusBottomLeft" :get #(-> % u/proxy->shape :r4) - :set (fn [self value] - (let [id (obj/get self "$id") - shape (u/proxy->shape self)] - (when (us/safe-int? value) - (when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) - (st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4))) - (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r4 value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + shape (u/proxy->shape self)] + (cond + (not (us/safe-int? value)) + (u/display-not-valid :borderRadiusBottomLeft value) + + (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape))) + (st/emit! (dwsh/update-shapes [id] #(-> % + (ctsr/switch-to-radius-4) + (ctsr/set-radius-4 :r4 value)))) + + :else + (st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r4 value))))))} {:name "opacity" :get #(-> % u/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! (dwsh/update-shapes [id] #(assoc % :opacity value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id")] + (when (and (us/safe-number? value) (>= value 0) (<= value 1)) + (st/emit! (dwsh/update-shapes [id] #(assoc % :opacity value))))))} {:name "blendMode" :get #(-> % u/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! (dwsh/update-shapes [id] #(assoc % :blend-mode value))))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + value (keyword value)] + (cond + (not (contains? cts/blend-modes value)) + (u/display-not-valid :blendMode value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :blend-mode value))))))} {:name "shadows" :get #(-> % u/proxy->shape :shadow u/array-to-js) - :set (fn [self value] - (let [id (obj/get self "$id") - value (mapv (fn [val] - ;; Merge default shadow properties - (d/patch-object - {:id (uuid/next) - :style :drop-shadow - :color {:color clr/black :opacity 0.2} - :offset-x 4 - :offset-y 4 - :blur 4 - :spread 0 - :hidden false} - (u/from-js val #{:style :type}))) - value)] - (st/emit! (dwsh/update-shapes [id] #(assoc % :shadow value)))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + value (mapv (fn [val] + ;; Merge default shadow properties + (d/patch-object + {:id (uuid/next) + :style :drop-shadow + :color {:color clr/black :opacity 0.2} + :offset-x 4 + :offset-y 4 + :blur 4 + :spread 0 + :hidden false} + (u/from-js val #{:style :type}))) + value)] + (cond + (not (sm/validate [:vector ::ctss/shadow] value)) + (u/display-not-valid :shadows value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :shadow value))))))} {:name "blur" :get #(-> % u/proxy->shape :blur u/to-js) - :set (fn [self value] - (if (nil? value) - (st/emit! (dwsh/update-shapes [id] #(dissoc % :blur))) - (let [id (obj/get self "$id") - value - (d/patch-object - {:id (uuid/next) - :type :layer-blur - :value 4 - :hidden false} - (u/from-js value))] - (st/emit! (dwsh/update-shapes [id] #(assoc % :blur value))))))} + :set + (fn [self value] + (if (nil? value) + (st/emit! (dwsh/update-shapes [id] #(dissoc % :blur))) + (let [id (obj/get self "$id") + value + (d/patch-object + {:id (uuid/next) + :type :layer-blur + :value 4 + :hidden false} + (u/from-js value))] + (cond + (not (sm/validate ::ctsb/blur value)) + (u/display-not-valid :blur value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :blur value)))))))} {:name "exports" :get #(-> % u/proxy->shape :exports u/array-to-js) - :set (fn [self value] - (let [id (obj/get self "$id") - value (mapv #(u/from-js %) value)] - (st/emit! (dwsh/update-shapes [id] #(assoc % :exports value)))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + value (mapv #(u/from-js %) value)] + (cond + (not (sm/validate [:vector ::ctse/export] value)) + (u/display-not-valid :exports value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :exports value))))))} ;; Geometry properties {:name "x" @@ -567,14 +760,24 @@ :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dw/update-position id {:x value}))))} + (cond + (not (us/safe-number? value)) + (u/display-not-valid :x value) + + :else + (st/emit! (dw/update-position id {:x value})))))} {:name "y" :get #(-> % u/proxy->shape :y) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dw/update-position id {:y value}))))} + (cond + (not (us/safe-number? value)) + (u/display-not-valid :y value) + + :else + (st/emit! (dw/update-position id {:y value})))))} {:name "parentX" :get (fn [self] @@ -584,11 +787,16 @@ (- (:x shape) (:x parent)))) :set (fn [self value] - (let [id (obj/get self "$id") - parent-id (-> self u/proxy->shape :parent-id) - parent (u/locate-shape (obj/get self "$file") (obj/get self "$page") parent-id) - parent-x (:x parent)] - (st/emit! (dw/update-position id {:x (+ parent-x value)}))))} + (cond + (not (us/safe-number? value)) + (u/display-not-valid :parentX value) + + :else + (let [id (obj/get self "$id") + parent-id (-> self u/proxy->shape :parent-id) + parent (u/locate-shape (obj/get self "$file") (obj/get self "$page") parent-id) + parent-x (:x parent)] + (st/emit! (dw/update-position id {:x (+ parent-x value)})))))} {:name "parentY" :get (fn [self] @@ -599,11 +807,16 @@ (- (:y shape) parent-y))) :set (fn [self value] - (let [id (obj/get self "$id") - parent-id (-> self u/proxy->shape :parent-id) - parent (u/locate-shape (obj/get self "$file") (obj/get self "$page") parent-id) - parent-y (:y parent)] - (st/emit! (dw/update-position id {:y (+ parent-y value)}))))} + (cond + (not (us/safe-number? value)) + (u/display-not-valid :parentY value) + + :else + (let [id (obj/get self "$id") + parent-id (-> self u/proxy->shape :parent-id) + parent (u/locate-shape (obj/get self "$file") (obj/get self "$page") parent-id) + parent-y (:y parent)] + (st/emit! (dw/update-position id {:y (+ parent-y value)})))))} {:name "frameX" :get (fn [self] @@ -614,11 +827,16 @@ (- (:x shape) frame-x))) :set (fn [self value] - (let [id (obj/get self "$id") - frame-id (-> self u/proxy->shape :frame-id) - frame (u/locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) - frame-x (:x frame)] - (st/emit! (dw/update-position id {:x (+ frame-x value)}))))} + (cond + (not (us/safe-number? value)) + (u/display-not-valid :frameX value) + + :else + (let [id (obj/get self "$id") + frame-id (-> self u/proxy->shape :frame-id) + frame (u/locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) + frame-x (:x frame)] + (st/emit! (dw/update-position id {:x (+ frame-x value)})))))} {:name "frameY" :get (fn [self] @@ -629,11 +847,16 @@ (- (:y shape) frame-y))) :set (fn [self value] - (let [id (obj/get self "$id") - frame-id (-> self u/proxy->shape :frame-id) - frame (u/locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) - frame-y (:y frame)] - (st/emit! (dw/update-position id {:y (+ frame-y value)}))))} + (cond + (not (us/safe-number? value)) + (u/display-not-valid :frameY value) + + :else + (let [id (obj/get self "$id") + frame-id (-> self u/proxy->shape :frame-id) + frame (u/locate-shape (obj/get self "$file") (obj/get self "$page") frame-id) + frame-y (:y frame)] + (st/emit! (dw/update-position id {:y (+ frame-y value)})))))} {:name "width" :get #(-> % u/proxy->shape :width)} @@ -645,49 +868,70 @@ :get #(-> % u/proxy->shape :rotation) :set (fn [self value] - (if (number? value) + (cond + (not (number? value)) + (u/display-not-valid :rotation value) + + :else (let [shape (u/proxy->shape self)] - (st/emit! (dw/increase-rotation #{(:id shape)} value))) - (u/display-not-valid :rotation value)))} + (st/emit! (dw/increase-rotation #{(:id shape)} value)))))} {:name "flipX" :get #(-> % u/proxy->shape :flip-x boolean) :set (fn [self value] - (if (boolean? value) + (cond + (not (boolean? value)) + (u/display-not-valid :flipX value) + + :else (let [id (obj/get self "$id")] - (st/emit! (dw/flip-horizontal-selected #{id}))) - (u/display-not-valid :flipX value)))} + (st/emit! (dw/flip-horizontal-selected #{id})))))} {:name "flipY" :get #(-> % u/proxy->shape :flip-y boolean) :set (fn [self value] - (if (boolean? value) + (cond + (not (boolean? value)) + (u/display-not-valid :flipY value) + + :else (let [id (obj/get self "$id")] - (st/emit! (dw/flip-vertical-selected #{id}))) - (u/display-not-valid :flipY value)))} + (st/emit! (dw/flip-vertical-selected #{id})))))} ;; Strokes and fills - ;; TODO: Validate fills input {:name "fills" :get #(if (cfh/text-shape? data) (-> % u/proxy->shape text-props :fills u/array-to-js) (-> % u/proxy->shape :fills u/array-to-js)) - :set (fn [self value] - (let [shape (u/proxy->shape self) - id (:id shape) - value (mapv #(u/from-js %) value)] - (if (cfh/text-shape? shape) - (st/emit! (dwt/update-attrs id {:fills value})) - (st/emit! (dwsh/update-shapes [id] #(assoc % :fills value))))))} + :set + (fn [self value] + (let [shape (u/proxy->shape self) + id (:id shape) + value (mapv #(u/from-js %) value)] + (cond + (not (sm/validate [:vector ::cts/fill] value)) + (u/display-not-valid :fills value) + + (cfh/text-shape? shape) + (st/emit! (dwt/update-attrs id {:fills value})) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :fills value))))))} {:name "strokes" :get #(-> % u/proxy->shape :strokes u/array-to-js) - :set (fn [self value] - (let [id (obj/get self "$id") - value (mapv #(u/from-js % #{:stroke-style :stroke-alignment}) value)] - (st/emit! (dwsh/update-shapes [id] #(assoc % :strokes value)))))} + :set + (fn [self value] + (let [id (obj/get self "$id") + value (mapv #(u/from-js % #{:stroke-style :stroke-alignment}) value)] + (cond + (not (sm/validate [:vector ::cts/stroke] value)) + (u/display-not-valid :strokes value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :strokes value))))))} {:name "layoutChild" :get @@ -742,7 +986,12 @@ :set (fn [self value] (let [id (obj/get self "$id") value (mapv #(u/from-js %) value)] - (st/emit! (dwsh/update-shapes [id] #(assoc % :grids value)))))} + (cond + (not (sm/validate [:vector ::ctg/grid] value)) + (u/display-not-valid :guides value) + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :grids value))))))} {:name "horizontalSizing" :get #(-> % u/proxy->shape :layout-item-h-sizing (d/nilv :fix) d/name) @@ -750,7 +999,11 @@ (fn [self value] (let [id (obj/get self "$id") value (keyword value)] - (when (contains? #{:fix :auto} value) + (cond + (not (contains? #{:fix :auto} value)) + (u/display-not-valid :horizontalSizing value) + + :else (st/emit! (dwsl/update-layout #{id} {:layout-item-h-sizing value})))))} {:name "verticalSizing" @@ -759,7 +1012,11 @@ (fn [self value] (let [id (obj/get self "$id") value (keyword value)] - (when (contains? #{:fix :auto} value) + (cond + (not (contains? #{:fix :auto} value)) + (u/display-not-valid :verticalSizing value) + + :else (st/emit! (dwsl/update-layout #{id} {:layout-item-v-sizing value})))))}))) (cond-> (cfh/text-shape? data) @@ -771,7 +1028,11 @@ (let [id (obj/get self "$id")] ;; The user is currently editing the text. We need to update the ;; editor as well - (when (contains? (:workspace-editor-state @st/state) id) + (cond + (or (not (string? value)) (empty? value)) + (u/display-not-valid :characters value) + + (contains? (:workspace-editor-state @st/state) id) (let [shape (u/proxy->shape self) editor (-> shape @@ -779,8 +1040,10 @@ :content ted/import-content ted/create-editor-state)] - (st/emit! (dwt/update-editor-state shape editor)))) - (st/emit! (dwsh/update-shapes [id] #(txt/change-text % value)))))} + (st/emit! (dwt/update-editor-state shape editor))) + + :else + (st/emit! (dwsh/update-shapes [id] #(txt/change-text % value))))))} {:name "growType" :get #(-> % u/proxy->shape :grow-type d/name) @@ -788,7 +1051,11 @@ (fn [self value] (let [id (obj/get self "$id") value (keyword value)] - (when (contains? #{:auto-width :auto-height :fixed} value) + (cond + (not (contains? #{:auto-width :auto-height :fixed} value)) + (u/display-not-valid :growType value) + + :else (st/emit! (dwsh/update-shapes [id] #(assoc % :grow-type value))))))} {:name "fontId" @@ -796,63 +1063,108 @@ :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:font-id value}))))} + (cond + (not (string? value)) + (u/display-not-valid :fontId value) + + :else + (st/emit! (dwt/update-attrs id {:font-id value})))))} {:name "fontFamily" :get #(-> % u/proxy->shape text-props :font-family) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:font-id value}))))} + (cond + (not (string? value)) + (u/display-not-valid :fontFamily value) + + :else + (st/emit! (dwt/update-attrs id {:font-family value})))))} {:name "fontVariantId" :get #(-> % u/proxy->shape text-props :font-variant-id) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:font-id value}))))} + (cond + (not (string? value)) + (u/display-not-valid :fontVariantId value) + + :else + (st/emit! (dwt/update-attrs id {:font-variant-id value})))))} {:name "fontSize" :get #(-> % u/proxy->shape text-props :font-size) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:font-size value}))))} + (cond + (not (string? value)) + (u/display-not-valid :fontSize value) + + :else + (st/emit! (dwt/update-attrs id {:font-size value})))))} {:name "fontWeight" :get #(-> % u/proxy->shape text-props :font-weight) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:font-id value}))))} + (cond + (not (string? value)) + (u/display-not-valid :fontWeight value) + + :else + (st/emit! (dwt/update-attrs id {:font-weight value})))))} {:name "fontStyle" :get #(-> % u/proxy->shape text-props :font-style) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:font-style value}))))} + (cond + (not (string? value)) + (u/display-not-valid :fontStyle value) + + :else + (st/emit! (dwt/update-attrs id {:font-style value})))))} {:name "lineHeight" :get #(-> % u/proxy->shape text-props :line-height) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:line-height value}))))} + (cond + (not (string? value)) + (u/display-not-valid :lineHeight value) + + :else + (st/emit! (dwt/update-attrs id {:line-height value})))))} {:name "letterSpacing" :get #(-> % u/proxy->shape text-props :letter-spacing) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:letter-spacing value}))))} + (cond + (not (string? value)) + (u/display-not-valid :letterSpacing value) + + :else + (st/emit! (dwt/update-attrs id {:letter-spacing value})))))} {:name "textTransform" :get #(-> % u/proxy->shape text-props :text-transform) :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:text-transform value}))))})) + (cond + (not (string? value)) + (u/display-not-valid :textTransform value) + + :else + (st/emit! (dwt/update-attrs id {:text-transform value})))))})) (cond-> (or (cfh/path-shape? data) (cfh/bool-shape? data)) (crc/add-properties! @@ -864,7 +1176,12 @@ (->> value (map u/from-js) (mapv parse-command) - (spp/simplify-commands)) - selrect (gsh/content->selrect content) - points (grc/rect->points selrect)] - (st/emit! (dwsh/update-shapes [id] (fn [shape] (assoc shape :content content :selrect selrect :points points))))))})))))) + (spp/simplify-commands))] + (cond + (not (sm/validate ::ctsp/content content)) + (u/display-not-valid :content value) + + :else + (let [selrect (gsh/content->selrect content) + points (grc/rect->points selrect)] + (st/emit! (dwsh/update-shapes [id] (fn [shape] (assoc shape :content content :selrect selrect :points points))))))))})))))) diff --git a/frontend/src/app/plugins/viewport.cljs b/frontend/src/app/plugins/viewport.cljs index 65e4423fb..c42696641 100644 --- a/frontend/src/app/plugins/viewport.cljs +++ b/frontend/src/app/plugins/viewport.cljs @@ -14,6 +14,7 @@ [app.main.data.workspace.viewport :as dwv] [app.main.data.workspace.zoom :as dwz] [app.main.store :as st] + [app.plugins.utils :as u] [app.util.object :as obj])) (deftype ViewportProxy [$plugin] @@ -51,7 +52,14 @@ (fn [_ value] (let [new-x (obj/get value "x") new-y (obj/get value "y")] - (when (and (us/safe-number? new-x) (us/safe-number? new-y)) + (cond + (not (us/safe-number? new-x)) + (u/display-not-valid :center-x new-x) + + (not (us/safe-number? new-y)) + (u/display-not-valid :center-y new-y) + + :else (let [vb (dm/get-in @st/state [:workspace-local :vbox]) old-x (+ (:x vb) (/ (:width vb) 2)) old-y (+ (:y vb) (/ (:height vb) 2)) @@ -68,7 +76,11 @@ (dm/get-in @st/state [:workspace-local :zoom])) :set (fn [_ value] - (when (us/safe-number? value) + (cond + (not (us/safe-number? value)) + (u/display-not-valid :zoom value) + + :else (let [z (dm/get-in @st/state [:workspace-local :zoom])] (st/emit! (dwz/set-zoom (/ value z))))))} diff --git a/frontend/test/frontend_tests/plugins/context_shapes_test.cljs b/frontend/test/frontend_tests/plugins/context_shapes_test.cljs new file mode 100644 index 000000000..ced9fff4b --- /dev/null +++ b/frontend/test/frontend_tests/plugins/context_shapes_test.cljs @@ -0,0 +1,260 @@ +;; 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 frontend-tests.plugins.context-shapes-test + (:require + [app.common.math :as m] + [app.common.test-helpers.files :as cthf] + [app.common.test-helpers.ids-map :as cthi] + [app.common.test-helpers.shapes :as cths] + [app.common.uuid :as uuid] + [app.main.store :as st] + [app.plugins.api :as api] + [cljs.test :as t :include-macros true] + [frontend-tests.helpers.state :as ths])) + +(t/deftest test-common-shape-properties + (let [;; ==== Setup + store + (ths/setup-store (cthf/sample-file :file1 :page-label :page1)) + + _ (set! st/state store) + + context (api/create-context "tests") + + page (. context -currentPage) + + shape (.createRectangle context) + + get-shape-path + #(vector :workspace-data :pages-index (aget page "$id") :objects (aget shape "$id") %)] + + (t/testing "Basic shape properites" + (t/testing " - name" + (set! (.-name shape) "TEST") + (t/is (= (.-name shape) "TEST")) + (t/is (= (get-in @store (get-shape-path :name)) "TEST"))) + + (t/testing " - x" + (set! (.-x shape) 10) + (t/is (= (.-x shape) 10)) + (t/is (= (get-in @store (get-shape-path :x)) 10)) + + (set! (.-x shape) "fail") + (t/is (= (.-x shape) 10)) + (t/is (= (get-in @store (get-shape-path :x)) 10))) + + (t/testing " - y" + (set! (.-y shape) 50) + (t/is (= (.-y shape) 50)) + (t/is (= (get-in @store (get-shape-path :y)) 50)) + + (set! (.-y shape) "fail") + (t/is (= (.-y shape) 50)) + (t/is (= (get-in @store (get-shape-path :y)) 50))) + + (t/testing " - resize" + (.resize shape 250 300) + (t/is (= (.-width shape) 250)) + (t/is (= (.-height shape) 300)) + (t/is (= (get-in @store (get-shape-path :width)) 250)) + (t/is (= (get-in @store (get-shape-path :height)) 300)) + + (.resize shape 0 0) + (t/is (= (.-width shape) 250)) + (t/is (= (.-height shape) 300)) + (t/is (= (get-in @store (get-shape-path :width)) 250)) + (t/is (= (get-in @store (get-shape-path :height)) 300))) + + (t/testing " - blocked" + (set! (.-blocked shape) true) + (t/is (= (.-blocked shape) true)) + (t/is (= (get-in @store (get-shape-path :blocked)) true)) + + (set! (.-blocked shape) false) + (t/is (= (.-blocked shape) false)) + (t/is (= (get-in @store (get-shape-path :blocked)) false))) + + (t/testing " - hidden" + (set! (.-hidden shape) true) + (t/is (= (.-hidden shape) true)) + (t/is (= (get-in @store (get-shape-path :hidden)) true)) + + (set! (.-hidden shape) false) + (t/is (= (.-hidden shape) false)) + (t/is (= (get-in @store (get-shape-path :hidden)) false))) + + (t/testing " - proportionLock" + (set! (.-proportionLock shape) true) + (t/is (= (.-proportionLock shape) true)) + (t/is (= (get-in @store (get-shape-path :proportion-lock)) true))) + + (t/testing " - constraintsHorizontal" + (set! (.-constraintsHorizontal shape) "fail") + (t/is (not= (.-constraintsHorizontal shape) "fail")) + (t/is (not= (get-in @store (get-shape-path :constraints-h)) "fail")) + + (set! (.-constraintsHorizontal shape) "right") + (t/is (= (.-constraintsHorizontal shape) "right")) + (t/is (= (get-in @store (get-shape-path :constraints-h)) :right))) + + (t/testing " - constraintsVertical" + (set! (.-constraintsVertical shape) "fail") + (t/is (not= (.-constraintsVertical shape) "fail")) + (t/is (not= (get-in @store (get-shape-path :constraints-v)) "fail")) + + (set! (.-constraintsVertical shape) "bottom") + (t/is (= (.-constraintsVertical shape) "bottom")) + (t/is (= (get-in @store (get-shape-path :constraints-v)) :bottom))) + + (t/testing " - borderRadius" + (set! (.-borderRadius shape) 10) + (t/is (= (.-borderRadius shape) 10)) + (t/is (= (get-in @store (get-shape-path :rx)) 10)) + + (set! (.-borderRadiusTopLeft shape) 20) + (t/is (= (.-borderRadiusTopLeft shape) 20)) + (t/is (= (get-in @store (get-shape-path :rx)) nil)) + (t/is (= (get-in @store (get-shape-path :r1)) 20)) + (t/is (= (get-in @store (get-shape-path :r2)) 10)) + (t/is (= (get-in @store (get-shape-path :r3)) 10)) + (t/is (= (get-in @store (get-shape-path :r4)) 10)) + + (set! (.-borderRadiusTopRight shape) 30) + (set! (.-borderRadiusBottomRight shape) 40) + (set! (.-borderRadiusBottomLeft shape) 50) + (t/is (= (.-borderRadiusTopRight shape) 30)) + (t/is (= (.-borderRadiusBottomRight shape) 40)) + (t/is (= (.-borderRadiusBottomLeft shape) 50)) + + (t/is (= (get-in @store (get-shape-path :rx)) nil)) + (t/is (= (get-in @store (get-shape-path :r1)) 20)) + (t/is (= (get-in @store (get-shape-path :r2)) 30)) + (t/is (= (get-in @store (get-shape-path :r3)) 40)) + (t/is (= (get-in @store (get-shape-path :r4)) 50))) + + (t/testing " - opacity" + (set! (.-opacity shape) 0.5) + (t/is (= (.-opacity shape) 0.5)) + (t/is (= (get-in @store (get-shape-path :opacity)) 0.5))) + + (t/testing " - blendMode" + (set! (.-blendMode shape) "multiply") + (t/is (= (.-blendMode shape) "multiply")) + (t/is (= (get-in @store (get-shape-path :blend-mode)) :multiply)) + + (set! (.-blendMode shape) "fail") + (t/is (= (.-blendMode shape) "multiply")) + (t/is (= (get-in @store (get-shape-path :blend-mode)) :multiply))) + + (t/testing " - shadows" + (let [shadow #js {:style "drop-shadow" + :color #js {:color "#FABADA" :opacity 1}}] + (set! (.-shadows shape) #js [shadow]) + (let [shadow-id (uuid/uuid (aget (aget (aget shape "shadows") 0) "id"))] + (t/is (= (-> (. shape -shadows) (aget 0) (aget "style")) "drop-shadow")) + (t/is (= (get-in @store (get-shape-path :shadow)) [{:id shadow-id + :style :drop-shadow + :offset-x 4 + :offset-y 4 + :blur 4 + :spread 0 + :color {:color "#FABADA" :opacity 1} + :hidden false}])))) + + (let [shadow #js {:style "fail"}] + (set! (.-shadows shape) #js [shadow]) + (t/is (= (-> (. shape -shadows) (aget 0) (aget "style")) "drop-shadow")))) + + (t/testing " - blur" + (set! (.-blur shape) #js {:value 10}) + (t/is (= (-> (. shape -blur) (aget "type")) "layer-blur")) + (t/is (= (-> (. shape -blur) (aget "value")) 10)) + (t/is (= (-> (. shape -blur) (aget "hidden")) false)) + (let [id (-> (. shape -blur) (aget "id") uuid/uuid)] + (t/is (= (get-in @store (get-shape-path :blur)) {:id id :type :layer-blur :value 10 :hidden false})))) + + (t/testing " - exports" + (set! (.-exports shape) #js [#js {:type "pdf" :scale 2 :suffix "test"}]) + (t/is (= (-> (. shape -exports) (aget 0) (aget "type")) "pdf")) + (t/is (= (-> (. shape -exports) (aget 0) (aget "scale")) 2)) + (t/is (= (-> (. shape -exports) (aget 0) (aget "suffix")) "test")) + (t/is (= (get-in @store (get-shape-path :exports)) [{:type :pdf :scale 2 :suffix "test"}])) + + (set! (.-exports shape) #js [#js {:type 10 :scale 2 :suffix "test"}]) + (t/is (= (get-in @store (get-shape-path :exports)) [{:type :pdf :scale 2 :suffix "test"}]))) + + (t/testing " - flipX" + (set! (.-flipX shape) true) + (t/is (= (.-flipX shape) true)) + (t/is (= (get-in @store (get-shape-path :flip-x)) true))) + + (t/testing " - flipY" + (set! (.-flipY shape) true) + (t/is (= (.-flipY shape) true)) + (t/is (= (get-in @store (get-shape-path :flip-y)) true))) + + (t/testing " - rotation" + (set! (.-rotation shape) 45) + (t/is (= (.-rotation shape) 45)) + (t/is (= (get-in @store (get-shape-path :rotation)) 45)) + + (set! (.-rotation shape) 0) + (t/is (= (.-rotation shape) 0)) + (t/is (= (get-in @store (get-shape-path :rotation)) 0))) + + (t/testing " - fills" + (set! (.-fills shape) #js [#js {:fillColor 100}]) + (t/is (= (-> (. shape -fills) (aget 0) (aget "fillColor")) "#B1B2B5")) + (t/is (= (get-in @store (get-shape-path :fills)) [{:fill-color "#B1B2B5" :fill-opacity 1}])) + + (set! (.-fills shape) #js [#js {:fillColor "#FABADA" :fillOpacity 1}]) + (t/is (= (-> (. shape -fills) (aget 0) (aget "fillColor")) "#FABADA")) + (t/is (= (-> (. shape -fills) (aget 0) (aget "fillOpacity")) 1)) + (t/is (= (get-in @store (get-shape-path :fills)) [{:fill-color "#FABADA" :fill-opacity 1}]))) + + (t/testing " - strokes" + (set! (.-fills shape) #js [#js {:strokeColor "#FABADA" :strokeOpacity 1 :stroke-width 5}]) + (t/is (= (-> (. shape -fills) (aget 0) (aget "strokeColor")) "#FABADA")) + (t/is (= (-> (. shape -fills) (aget 0) (aget "strokeOpacity")) 1)) + (t/is (= (-> (. shape -fills) (aget 0) (aget "strokeWidth")) 5)) + (t/is (= (get-in @store (get-shape-path :fills)) [{:stroke-color "#FABADA" :stroke-opacity 1 :stroke-width 5}])))) + + (t/testing "Relative properties" + (let [frame (.createFrame context)] + (set! (.-x frame) 100) + (set! (.-y frame) 200) + (t/is (= (.-x frame) 100)) + (t/is (= (.-y frame) 200)) + (.appendChild frame shape) + + (t/testing " - frameX" + (set! (.-frameX shape) 10) + (t/is (m/close? (.-frameX shape) 10)) + (t/is (m/close? (.-x shape) 110)) + (t/is (m/close? (get-in @store (get-shape-path :x)) 110))) + + (t/testing " - frameY" + (set! (.-frameY shape) 20) + (t/is (m/close? (.-frameY shape) 20)) + (t/is (m/close? (.-y shape) 220)) + (t/is (m/close? (get-in @store (get-shape-path :y)) 220))) + + (t/testing " - parentX" + (set! (.-parentX shape) 30) + (t/is (m/close? (.-parentX shape) 30)) + (t/is (m/close? (.-x shape) 130)) + (t/is (m/close? (get-in @store (get-shape-path :x)) 130))) + + (t/testing " - parentY" + (set! (.-parentY shape) 40) + (t/is (m/close? (.-parentY shape) 40)) + (t/is (m/close? (.-y shape) 240)) + (t/is (m/close? (get-in @store (get-shape-path :y)) 240))))) + + (t/testing "Clone") + (t/testing "Remove"))) + From 7fd223893b1f136f270ac12718ae7645dd0ad597 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 20 Jun 2024 13:16:23 +0200 Subject: [PATCH 6/7] :sparkles: Expose component properties in components --- frontend/src/app/plugins/api.cljs | 2 +- frontend/src/app/plugins/library.cljs | 15 ++++- frontend/src/app/plugins/shape.cljs | 93 ++++++++++++++++++++++++++- frontend/src/app/plugins/utils.cljs | 10 +++ 4 files changed, 116 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index adf18684a..790197e64 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -205,7 +205,7 @@ (createShapeFromSvg [_ svg-string] (cond - (not (string? svg-string)) + (or (not (string? svg-string)) (empty? svg-string)) (u/display-not-valid :createShapeFromSvg svg-string) :else diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index de163e8b5..eb47da713 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -14,6 +14,7 @@ [app.common.record :as cr] [app.common.schema :as sm] [app.common.types.color :as ctc] + [app.common.types.file :as ctf] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] @@ -630,7 +631,19 @@ :else (let [component (u/proxy->library-component self) value (dm/str value " / " (:name component))] - (st/emit! (dwl/rename-component id value)))))})) + (st/emit! (dwl/rename-component id value)))))} + + {:name "mainInstance" + :get + (fn [self] + (let [file-id (obj/get self "$file") + file (u/locate-file file-id) + component (u/proxy->library-component self) + root (ctf/get-component-root (:data file) component)] + (when (some? root) + (shape/shape-proxy plugin-id file-id (:main-instance-page component) (:id root)))))})) + +(set! shape/lib-component-proxy lib-component-proxy) (deftype Library [$plugin $id] Object diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 44cc2af73..df6b8d123 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -18,6 +18,9 @@ [app.common.spec :as us] [app.common.svg.path.legacy-parser2 :as spp] [app.common.text :as txt] + [app.common.types.component :as ctk] + [app.common.types.container :as ctn] + [app.common.types.file :as ctf] [app.common.types.grid :as ctg] [app.common.types.shape :as cts] [app.common.types.shape.blur :as ctsb] @@ -43,6 +46,7 @@ [cuerdas.core :as str])) (def lib-typography-proxy? nil) +(def lib-component-proxy nil) (deftype TextRange [$plugin $file $page $id start end] Object @@ -466,7 +470,39 @@ :else (let [typography (u/proxy->library-typography typography)] - (st/emit! (dwt/apply-typography #{$id} typography $file))))))) + (st/emit! (dwt/apply-typography #{$id} typography $file)))))) + + ;; COMPONENTS + (isComponentInstance + [self] + (let [shape (u/proxy->shape self) + file-id (obj/get self "$file") + page-id (obj/get self "$page") + objects (u/locate-objects file-id page-id)] + (ctn/in-any-component? objects shape))) + + (isComponentMainInstance + [self] + (let [shape (u/proxy->shape self) + file-id (obj/get self "$file") + page-id (obj/get self "$page") + objects (u/locate-objects file-id page-id)] + (ctn/inside-component-main? objects shape))) + + (isComponentCopyInstance + [self] + (let [shape (u/proxy->shape self)] + (ctk/in-component-copy? shape))) + + (isComponentRoot + [self] + (let [shape (u/proxy->shape self)] + (ctk/instance-root? shape))) + + (isComponentHead + [self] + (let [shape (u/proxy->shape self)] + (ctk/instance-head? shape)))) (crc/define-properties! ShapeProxy @@ -951,7 +987,60 @@ id (obj/get self "$id") objects (u/locate-objects file-id page-id)] (when (ctl/grid-layout-immediate-child-id? objects id) - (grid/layout-cell-proxy plugin-id file-id page-id id))))}) + (grid/layout-cell-proxy plugin-id file-id page-id id))))} + + ;; Components + {:name "componentRefShape" + :get + (fn [self] + (let [file-id (obj/get self "$file") + page-id (obj/get self "$page") + objects (u/locate-objects file-id page-id) + shape (u/proxy->shape self)] + (when (ctn/in-any-component? objects shape) + (let [plugin-id (obj/get self "$plugin") + [root component] (u/locate-component objects shape) + component-page-id (:main-instance-page component) + component-file (u/locate-file (:component-file root)) + ref-shape (ctf/get-ref-shape (:data component-file) component shape)] + (when (and (not (:deleted component)) (some? ref-shape) (some? component-file)) + (shape-proxy plugin-id (:id component-file) component-page-id (:id ref-shape)))))))} + + {:name "componentRoot" + :get + (fn [self] + (let [file-id (obj/get self "$file") + page-id (obj/get self "$page") + objects (u/locate-objects file-id page-id) + shape (u/proxy->shape self)] + (when (ctn/in-any-component? objects shape) + (let [plugin-id (obj/get self "$plugin") + [root component] (u/locate-component objects shape)] + (shape-proxy plugin-id (:component-file root) (:main-instance-page component) (:id root))))))} + + {:name "componentHead" + :get + (fn [self] + (let [file-id (obj/get self "$file") + objects (u/locate-objects file-id page-id) + shape (u/proxy->shape self)] + (when (ctn/in-any-component? objects shape) + (let [plugin-id (obj/get self "$plugin") + page-id (obj/get self "$page") + head (ctn/get-head-shape (u/locate-objects file-id page-id) shape)] + (shape-proxy plugin-id file-id page-id (:id head))))))} + + {:name "component" + :get + (fn [self] + (let [file-id (obj/get self "$file") + page-id (obj/get self "$page") + objects (u/locate-objects file-id page-id) + shape (u/proxy->shape self)] + (when (ctn/in-any-component? objects shape) + (let [plugin-id (obj/get self "$plugin") + [root component] (u/locate-component objects shape)] + (lib-component-proxy plugin-id (:component-file root) (:id component))))))}) (cond-> (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)) (crc/add-properties! diff --git a/frontend/src/app/plugins/utils.cljs b/frontend/src/app/plugins/utils.cljs index 87fb3abb3..da600d447 100644 --- a/frontend/src/app/plugins/utils.cljs +++ b/frontend/src/app/plugins/utils.cljs @@ -10,6 +10,8 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.spec :as us] + [app.common.types.container :as ctn] + [app.common.types.file :as ctf] [app.common.uuid :as uuid] [app.main.store :as st] [app.util.object :as obj] @@ -62,6 +64,14 @@ (let [{:keys [profile-id]} (locate-presence session-id)] (dm/get-in @st/state [:users profile-id]))) +(defn locate-component + [objects shape] + (let [current-file-id (:current-file-id @st/state) + workspace-data (:workspace-data @st/state) + workspace-libraries (:workspace-libraries @st/state) + root (ctn/get-instance-root objects shape)] + [root (ctf/resolve-component root {:id current-file-id :data workspace-data} workspace-libraries {:include-deleted? true})])) + (defn proxy->file [proxy] (let [id (obj/get proxy "$id")] From 47d211cd87bd869ab5446e852846d222e78b69a6 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 20 Jun 2024 15:47:29 +0200 Subject: [PATCH 7/7] :arrow_up: Update plugin runtime --- frontend/resources/plugins-runtime/index.js | 490 +++++++++++--------- 1 file changed, 260 insertions(+), 230 deletions(-) diff --git a/frontend/resources/plugins-runtime/index.js b/frontend/resources/plugins-runtime/index.js index e3de504aa..aa6199d6a 100644 --- a/frontend/resources/plugins-runtime/index.js +++ b/frontend/resources/plugins-runtime/index.js @@ -56,7 +56,7 @@ const k = globalThis, { preventExtensions: Qs, setPrototypeOf: ko, values: Po, - fromEntries: ht + fromEntries: mt } = bn, { species: Vr, toStringTag: qe, @@ -76,7 +76,7 @@ const k = globalThis, { return n; }, { apply: ne, - construct: hr, + construct: mr, get: sa, getOwnPropertyDescriptor: aa, has: Io, @@ -94,7 +94,7 @@ const k = globalThis, { ), Oo = ( /** @type {any} */ P(_e.flatMap) -), gr = P(_e.pop), X = P(_e.push), ua = P(_e.slice), da = P(_e.some), Mo = P(_e.sort), fa = P(_e[rr]), $e = P(Nt.set), Ue = P(Nt.get), Lr = P(Nt.has), pa = P(Nt.delete), ma = P(Nt.entries), ha = P(Nt[rr]), Sn = P(nr.add); +), gr = P(_e.pop), X = P(_e.push), ua = P(_e.slice), da = P(_e.some), Mo = P(_e.sort), fa = P(_e[rr]), $e = P(Nt.set), Ue = P(Nt.get), Lr = P(Nt.has), pa = P(Nt.delete), ha = P(Nt.entries), ma = P(Nt[rr]), Sn = P(nr.add); P(nr.delete); const Wn = P(nr.forEach), xn = P(nr.has), ga = P(nr[rr]), kn = P(Rr.test), Pn = P(Rr.exec), ya = P(Rr[To]), Lo = P(Le.endsWith), Fo = P(Le.includes), va = P(Le.indexOf); P(Le.match); @@ -142,10 +142,10 @@ const { freeze: at } = Object, { apply: Aa } = Reflect, $n = (t) => (e, ...r) => u )} must be a string.`; let d = u; - const f = t.process || void 0, m = typeof f == "object" && f.env || void 0; - if (typeof m == "object" && c in m) { + const f = t.process || void 0, h = typeof f == "object" && f.env || void 0; + if (typeof h == "object" && c in h) { e || Ia(r, c); - const p = m[c]; + const p = h[c]; typeof p == "string" || ir`Environment option named ${nt( c )}, if present, must have a corresponding string value, got ${nt( @@ -204,7 +204,7 @@ const Ho = (t, e = void 0) => { return a; Mo(i); const u = se(i, (l) => [l, a[l]]); - return ht(u); + return mt(u); } case "function": return `[Function ${a.name || ""}]`; @@ -264,13 +264,13 @@ const { isSafeInteger: $a } = Number, { freeze: vt } = Object, { toStringTag: Na const c = (d, f) => { if (t < 1) return l; - let m = o(d); - if (m === void 0 && (m = Kn(void 0), Yn(n, m)), !m.data) - for (r += 1, m.data = /* @__PURE__ */ new WeakMap(), e.set(d, m); r > t; ) { + let h = o(d); + if (h === void 0 && (h = Kn(void 0), Yn(n, h)), !h.data) + for (r += 1, h.data = /* @__PURE__ */ new WeakMap(), e.set(d, h); r > t; ) { const p = n.prev; Kr(p), p.data = void 0, r -= 1; } - return m.data.set(d, f), l; + return h.data.set(d, f), l; }; vt(c); const u = (d) => { @@ -366,7 +366,7 @@ const Jo = ({ template: t, args: e }) => { X(r, o, i); } return r[r.length - 1] === "" && gr(r), r; -}, mr = new Me(); +}, hr = new Me(); let nn = 0; const Jn = new Me(), Xo = (t, e = t.name) => { let r = L(Jn, t); @@ -418,7 +418,7 @@ const Jn = new Me(), Xo = (t, e = t.name) => { writable: !0, enumerable: !1, configurable: !0 - })), ie(mr, l, Jo(i)), r !== void 0 && Xo(l, r), a && Fa(l), l; + })), ie(hr, l, Jo(i)), r !== void 0 && Xo(l, r), a && Fa(l), l; }; y(on); const { addLogArgs: Da, takeLogArgsArray: Ua } = Wo(), sn = new Me(), Nn = (t, e) => { @@ -446,10 +446,10 @@ const ja = (t) => { resetErrorTagNum: () => { nn = 0; }, - getMessageLogArgs: (t) => L(mr, t), + getMessageLogArgs: (t) => L(hr, t), takeMessageLogArgs: (t) => { - const e = L(mr, t); - return wa(mr, t), e; + const e = L(hr, t); + return wa(hr, t), e; }, takeNoteLogArgsArray: (t, e) => { const r = Ua(t); @@ -462,28 +462,28 @@ const ja = (t) => { }; y(br); const jr = (t = void 0, e = !1) => { - const r = e ? Yo : ft, n = r`Check failed`, o = (f = n, m = void 0, p = void 0) => { - const h = on(f, m, p); - throw t !== void 0 && t(h), h; + const r = e ? Yo : ft, n = r`Check failed`, o = (f = n, h = void 0, p = void 0) => { + const m = on(f, h, p); + throw t !== void 0 && t(m), m; }; y(o); - const a = (f, ...m) => o(r(f, ...m)); - function i(f, m = void 0, p = void 0, h = void 0) { - f || o(m, p, h); + const a = (f, ...h) => o(r(f, ...h)); + function i(f, h = void 0, p = void 0, m = void 0) { + f || o(h, p, m); } - const c = (f, m, p = void 0, h = void 0, _ = void 0) => { - Nr(f, m) || o( - p || r`Expected ${f} is same as ${m}`, - h || Xs, + const c = (f, h, p = void 0, m = void 0, _ = void 0) => { + Nr(f, h) || o( + p || r`Expected ${f} is same as ${h}`, + m || Xs, _ ); }; y(c); - const u = (f, m, p) => { - if (typeof f !== m) { - if (typeof m == "string" || a`${Je(m)} must be a string`, p === void 0) { - const h = _r(m); - p = r`${f} must be ${rn(h)}`; + const u = (f, h, p) => { + if (typeof f !== h) { + if (typeof h == "string" || a`${Je(h)} must be a string`, p === void 0) { + const m = _r(h); + p = r`${f} must be ${rn(m)}`; } o(p, v); } @@ -494,7 +494,7 @@ const jr = (t = void 0, e = !1) => { fail: o, equal: c, typeof: u, - string: (f, m = void 0) => u(f, "string", m), + string: (f, h = void 0) => u(f, "string", h), note: Nn, details: r, Fail: a, @@ -545,13 +545,13 @@ const Za = (t) => ne(es, t, []) !== void 0, za = (t) => { } const a = (d) => { Za(d) ? Ga(d) : y(d); - const f = Ze(d), m = j(d); - o(m), ut(De(f), (p) => { - const h = f[ + const f = Ze(d), h = j(d); + o(h), ut(De(f), (p) => { + const m = f[ /** @type {string} */ p ]; - oe(h, "value") ? o(h.value) : (o(h.get), o(h.set)); + oe(m, "value") ? o(m.value) : (o(m.get), o(m.set)); }); }, i = qr === void 0 && Pa === void 0 ? ( // On platforms without v8's error own stack accessor problem, @@ -1967,89 +1967,89 @@ const as = () => { }; function Ya(t, e) { let r = !1; - const n = (m, ...p) => (r || (console.groupCollapsed("Removing unpermitted intrinsics"), r = !0), console[m](...p)), o = ["undefined", "boolean", "number", "string", "symbol"], a = new Pe( + const n = (h, ...p) => (r || (console.groupCollapsed("Removing unpermitted intrinsics"), r = !0), console[h](...p)), o = ["undefined", "boolean", "number", "string", "symbol"], a = new Pe( Et ? se( Ke( re(wr["%SharedSymbol%"]), - ([m, p]) => p === "symbol" && typeof Et[m] == "symbol" + ([h, p]) => p === "symbol" && typeof Et[h] == "symbol" ), - ([m]) => [Et[m], `@@${m}`] + ([h]) => [Et[h], `@@${h}`] ) : [] ); - function i(m, p) { + function i(h, p) { if (typeof p == "string") return p; - const h = Ue(a, p); + const m = Ue(a, p); if (typeof p == "symbol") { - if (h) - return h; + if (m) + return m; { const _ = ta(p); return _ !== void 0 ? `RegisteredSymbol(${_})` : `Unique${pe(p)}`; } } - throw v(`Unexpected property name type ${m} ${p}`); + throw v(`Unexpected property name type ${h} ${p}`); } - function c(m, p, h) { + function c(h, p, m) { if (!Ye(p)) - throw v(`Object expected: ${m}, ${p}, ${h}`); + throw v(`Object expected: ${h}, ${p}, ${m}`); const _ = j(p); - if (!(_ === null && h === null)) { - if (h !== void 0 && typeof h != "string") - throw v(`Malformed whitelist permit ${m}.__proto__`); - if (_ !== t[h || "%ObjectPrototype%"]) - throw v(`Unexpected intrinsic ${m}.__proto__ at ${h}`); + if (!(_ === null && m === null)) { + if (m !== void 0 && typeof m != "string") + throw v(`Malformed whitelist permit ${h}.__proto__`); + if (_ !== t[m || "%ObjectPrototype%"]) + throw v(`Unexpected intrinsic ${h}.__proto__ at ${m}`); } } - function u(m, p, h, _) { + function u(h, p, m, _) { if (typeof _ == "object") - return f(m, p, _), !0; + return f(h, p, _), !0; if (_ === !1) return !1; if (typeof _ == "string") { - if (h === "prototype" || h === "constructor") { + if (m === "prototype" || m === "constructor") { if (oe(t, _)) { if (p !== t[_]) - throw v(`Does not match whitelist ${m}`); + throw v(`Does not match whitelist ${h}`); return !0; } } else if (Mr(o, _)) { if (typeof p !== _) throw v( - `At ${m} expected ${_} not ${typeof p}` + `At ${h} expected ${_} not ${typeof p}` ); return !0; } } - throw v(`Unexpected whitelist permit ${_} at ${m}`); + throw v(`Unexpected whitelist permit ${_} at ${h}`); } - function l(m, p, h, _) { - const E = J(p, h); + function l(h, p, m, _) { + const E = J(p, m); if (!E) - throw v(`Property ${h} not found at ${m}`); + throw v(`Property ${m} not found at ${h}`); if (oe(E, "value")) { if (eo(_)) - throw v(`Accessor expected at ${m}`); - return u(m, E.value, h, _); + throw v(`Accessor expected at ${h}`); + return u(h, E.value, m, _); } if (!eo(_)) - throw v(`Accessor not expected at ${m}`); - return u(`${m}`, E.get, h, _.get) && u(`${m}`, E.set, h, _.set); + throw v(`Accessor not expected at ${h}`); + return u(`${h}`, E.get, m, _.get) && u(`${h}`, E.set, m, _.set); } - function d(m, p, h) { - const _ = h === "__proto__" ? "--proto--" : h; + function d(h, p, m) { + const _ = m === "__proto__" ? "--proto--" : m; if (oe(p, _)) return p[_]; - if (typeof m == "function" && oe(an, _)) + if (typeof h == "function" && oe(an, _)) return an[_]; } - function f(m, p, h) { + function f(h, p, m) { if (p == null) return; - const _ = h["[[Proto]]"]; - c(m, p, _), typeof p == "function" && e(p); + const _ = m["[[Proto]]"]; + c(h, p, _), typeof p == "function" && e(p); for (const E of De(p)) { - const T = i(m, E), N = `${m}.${T}`, x = d(p, h, T); + const T = i(h, E), N = `${h}.${T}`, x = d(p, m, T); if (!x || !l(N, p, E, x)) { x !== !1 && n("warn", `Removing ${N}`); try { @@ -2138,7 +2138,7 @@ function Xa(t = "safe") { }, o = ({ powers: c = "none" } = {}) => { let u; return c === "original" ? u = function(...d) { - return new.target === void 0 ? ne(e, void 0, d) : hr(e, d, new.target); + return new.target === void 0 ? ne(e, void 0, d) : mr(e, d, new.target); } : u = function(...d) { if (new.target === void 0) throw v( @@ -2148,7 +2148,7 @@ function Xa(t = "safe") { throw v( "secure mode Calling new %SharedDate%() with no arguments throws" ); - return hr(e, d, new.target); + return mr(e, d, new.target); }, F(u, { length: { value: 7 }, prototype: { @@ -2222,7 +2222,7 @@ function ei(t = "safe") { throw v(`unrecognized regExpTaming ${t}`); const e = We.prototype, r = (a = {}) => { const i = function(...u) { - return new.target === void 0 ? We(...u) : hr(We, u, new.target); + return new.target === void 0 ? We(...u) : mr(We, u, new.target); }; if (F(i, { length: { value: 2 }, @@ -2425,9 +2425,9 @@ const ti = { }; function ni(t, e, r = []) { const n = new Ct(r); - function o(l, d, f, m) { - if ("value" in m && m.configurable) { - const { value: p } = m, h = xn(n, f), { get: _, set: E } = J( + function o(l, d, f, h) { + if ("value" in h && h.configurable) { + const { value: p } = h, m = xn(n, f), { get: _, set: E } = J( { get [f]() { return p; @@ -2439,7 +2439,7 @@ function ni(t, e, r = []) { f )}' of '${l}'` ); - oe(this, f) ? this[f] = T : (h && console.error(v(`Override property ${f}`)), M(this, f, { + oe(this, f) ? this[f] = T : (m && console.error(v(`Override property ${f}`)), M(this, f, { value: T, writable: !0, enumerable: !0, @@ -2457,33 +2457,33 @@ function ni(t, e, r = []) { }), M(d, f, { get: _, set: E, - enumerable: m.enumerable, - configurable: m.configurable + enumerable: h.enumerable, + configurable: h.configurable }); } } function a(l, d, f) { - const m = J(d, f); - m && o(l, d, f, m); + const h = J(d, f); + h && o(l, d, f, h); } function i(l, d) { const f = Ze(d); - f && ut(De(f), (m) => o(l, d, m, f[m])); + f && ut(De(f), (h) => o(l, d, h, f[h])); } function c(l, d, f) { - for (const m of De(f)) { - const p = J(d, m); + for (const h of De(f)) { + const p = J(d, h); if (!p || p.get || p.set) continue; - const h = `${l}.${pe(m)}`, _ = f[m]; + const m = `${l}.${pe(h)}`, _ = f[h]; if (_ === !0) - a(h, d, m); + a(m, d, h); else if (_ === "*") - i(h, p.value); + i(m, p.value); else if (Ye(_)) - c(h, p.value, _); + c(m, p.value, _); else - throw v(`Unexpected override enablement plan ${h}`); + throw v(`Unexpected override enablement plan ${m}`); } } let u; @@ -2690,7 +2690,7 @@ ${o} ), pi = new Cr( Cn, ps -), ms = (t) => { +), hs = (t) => { const e = { // inherit scopeTerminator behavior ...ps, @@ -2713,8 +2713,8 @@ ${o} r ); }; -y(ms); -const { Fail: mi } = G, hi = () => { +y(hs); +const { Fail: hi } = G, mi = () => { const t = z(null), e = y({ eval: { get() { @@ -2727,7 +2727,7 @@ const { Fail: mi } = G, hi = () => { evalScope: t, allowNextEvalToBeUnsafe() { const { revoked: n } = r; - n !== null && mi`a handler did not reset allowNextEvalToBeUnsafe ${n.err}`, F(t, e); + n !== null && hi`a handler did not reset allowNextEvalToBeUnsafe ${n.err}`, F(t, e); }, /** @type {null | { err: any }} */ revoked: null @@ -2754,15 +2754,15 @@ function On(t, e) { return An(Tn(t, 0, r), ` `).length + n; } -const hs = new We("(?:)", "g"), gs = (t) => { - const e = On(t, hs); +const ms = new We("(?:)", "g"), gs = (t) => { + const e = On(t, ms); if (e < 0) return t; const r = Rn(t); throw tr( `Possible HTML comment rejected at ${r}:${e}. (SES_HTML_COMMENT_REJECTED)` ); -}, ys = (t) => vr(t, hs, (r) => r[0] === "<" ? "< ! --" : "-- >"), vs = new We( +}, ys = (t) => vr(t, ms, (r) => r[0] === "<" ? "< ! --" : "-- >"), vs = new We( "(^|[^.]|\\.\\.\\.)\\bimport(\\s*(?:\\(|/[/*]))", "g" ), _s = (t) => { @@ -2924,7 +2924,7 @@ const wi = (t) => { globalTransforms: r = [], sloppyGlobalsMode: n = !1 }) => { - const o = n ? ms(t) : pi, a = hi(), { evalScope: i } = a, c = y({ + const o = n ? hs(t) : pi, a = mi(), { evalScope: i } = a, c = y({ evalScope: i, moduleLexicals: e, globalObject: t, @@ -2934,21 +2934,21 @@ const wi = (t) => { const l = () => { u || (u = wi(c)); }; - return { safeEvaluate: (f, m) => { - const { localTransforms: p = [] } = m || {}; + return { safeEvaluate: (f, h) => { + const { localTransforms: p = [] } = h || {}; l(), f = Ss(f, [ ...p, ...r, Es ]); - let h; + let m; try { return a.allowNextEvalToBeUnsafe(), ne(u, t, [f]); } catch (_) { - throw h = _, _; + throw m = _, _; } finally { const _ = "eval" in i; - delete i.eval, _ && (a.revoked = { err: h }, Ei`handler did not reset allowNextEvalToBeUnsafe ${h}`); + delete i.eval, _ && (a.revoked = { err: m }, Ei`handler did not reset allowNextEvalToBeUnsafe ${m}`); } } }; }, Si = ") { [native code] }"; @@ -3046,7 +3046,7 @@ const Ln = y([ ]), ki = (t, { shouldResetForDebugging: e = !1 } = {}) => { e && t.resetErrorTagNum(); let r = []; - const n = ht( + const n = mt( se(ks, ([i, c]) => { const u = (...l) => { X(r, [i, ...l]); @@ -3119,7 +3119,7 @@ const Dn = (t, e) => { for (const K of B) c(E, T, it.NOTE, K, x); u(E, x, N); - }, m = se(Ln, ([E, T]) => { + }, h = se(Ln, ([E, T]) => { const N = (...x) => { const D = [], B = i(x, D); t[E](...B), u(E, D); @@ -3128,12 +3128,12 @@ const Dn = (t, e) => { }), p = Ke( Fn, ([E, T]) => E in t - ), h = se(p, ([E, T]) => { + ), m = se(p, ([E, T]) => { const N = (...x) => { t[E](...x); }; return M(N, "name", { value: E }), [E, y(N)]; - }), _ = ht([...m, ...h]); + }), _ = mt([...h, ...m]); return ( /** @type {VirtualConsole} */ y(_) @@ -3149,7 +3149,7 @@ const Pi = (t, e, r) => { (l) => typeof l == "string" && Fo(l, ` `) ? Pi(l, ` `, n) : [l] - ), u = [...n, ...u]), r(...u)), a = (u, l) => ({ [u]: (...d) => l(...d) })[u], i = ht([ + ), u = [...n, ...u]), r(...u)), a = (u, l) => ({ [u]: (...d) => l(...d) })[u], i = mt([ ...se(Ln, ([u]) => [ u, a(u, o) @@ -3178,7 +3178,7 @@ const Ti = (t, e, r = void 0) => { ([i, c]) => i in t ), o = se(n, ([i, c]) => [i, y((...l) => { (c === void 0 || e.canLog(c)) && t[i](...l); - })]), a = ht(o); + })]), a = mt(o); return ( /** @type {VirtualConsole} */ y(a) @@ -3204,11 +3204,11 @@ const io = (t) => { }, unhandledRejectionHandler: (d, f) => { e += 1; - const m = e; - $e(r, m, d), ie(o, f, m), xa(i, f, m, f); + const h = e; + $e(r, h, d), ie(o, f, h), xa(i, f, h, f); }, processTerminationHandler: () => { - for (const [d, f] of ma(r)) + for (const [d, f] of ha(r)) n(d), t(f); } }; @@ -3300,7 +3300,7 @@ const io = (t) => { "toString" // TODO replace to use only whitelisted info ], Ci = (t) => { - const r = ht(se(Ii, (n) => { + const r = mt(se(Ii, (n) => { const o = t[n]; return [n, () => ne(o, t, [])]; })); @@ -3329,11 +3329,11 @@ const io = (t) => { return t; }, zi = (t, e, r, n) => { const o = t.captureStackTrace, a = (p) => n === "verbose" ? !0 : Fi(p.getFileName()), i = (p) => { - let h = `${p}`; - return n === "concise" && (h = Zi(h)), ` - at ${h}`; - }, c = (p, h) => Rt( - se(Ke(h, a), i), + let m = `${p}`; + return n === "concise" && (m = Zi(m)), ` + at ${m}`; + }, c = (p, m) => Rt( + se(Ke(m, a), i), "" ), u = new Me(), l = { // The optional `optFn` argument is for cutting off the bottom of @@ -3341,9 +3341,9 @@ const io = (t) => { // call to that function. Since this isn't the "real" captureStackTrace // but instead calls the real one, if no other cutoff is provided, // we cut this one off. - captureStackTrace(p, h = l.captureStackTrace) { + captureStackTrace(p, m = l.captureStackTrace) { if (typeof o == "function") { - ne(o, t, [p, h]); + ne(o, t, [p, m]); return; } Co(p, "stack", ""); @@ -3353,30 +3353,30 @@ const io = (t) => { // string associated with an error. // See https://tc39.es/proposal-error-stacks/ getStackString(p) { - let h = L(u, p); - if (h === void 0 && (p.stack, h = L(u, p), h || (h = { stackString: "" }, ie(u, p, h))), h.stackString !== void 0) - return h.stackString; - const _ = c(p, h.callSites); + let m = L(u, p); + if (m === void 0 && (p.stack, m = L(u, p), m || (m = { stackString: "" }, ie(u, p, m))), m.stackString !== void 0) + return m.stackString; + const _ = c(p, m.callSites); return ie(u, p, { stackString: _ }), _; }, - prepareStackTrace(p, h) { + prepareStackTrace(p, m) { if (r === "unsafe") { - const _ = c(p, h); + const _ = c(p, m); return ie(u, p, { stackString: _ }), `${p}${_}`; } else - return ie(u, p, { callSites: h }), ""; + return ie(u, p, { callSites: m }), ""; } }, d = l.prepareStackTrace; t.prepareStackTrace = d; - const f = new $t([d]), m = (p) => { + const f = new $t([d]), h = (p) => { if (or(f, p)) return p; - const h = { + const m = { prepareStackTrace(_, E) { return ie(u, _, { callSites: E }), p(_, $i(E)); } }; - return Fr(f, h.prepareStackTrace), h.prepareStackTrace; + return Fr(f, m.prepareStackTrace), m.prepareStackTrace; }; return F(e, { captureStackTrace: { @@ -3391,8 +3391,8 @@ const io = (t) => { }, set(p) { if (typeof p == "function") { - const h = m(p); - t.prepareStackTrace = h; + const m = h(p); + t.prepareStackTrace = m; } else t.prepareStackTrace = d; }, @@ -3411,9 +3411,9 @@ function Bi(t = "safe", e = "concise") { if (e !== "concise" && e !== "verbose") throw v(`unrecognized stackFiltering ${e}`); const r = ue.prototype, n = typeof ue.captureStackTrace == "function" ? "v8" : "unknown", { captureStackTrace: o } = ue, a = (l = {}) => { - const d = function(...m) { + const d = function(...h) { let p; - return new.target === void 0 ? p = ne(ue, this, m) : p = hr(ue, m, new.target), n === "v8" && ne(o, ue, [p, d]), p; + return new.target === void 0 ? p = ne(ue, this, h) : p = mr(ue, h, new.target), n === "v8" && ne(o, ue, [p, d]), p; }; return F(d, { length: { value: 1 }, @@ -3563,7 +3563,7 @@ const Ki = (t, e) => y({ o.imports, l, n - ), m = y({ + ), h = y({ compartment: r, staticModuleRecord: o, moduleSpecifier: n, @@ -3580,21 +3580,21 @@ const Ki = (t, e) => y({ i, c ]); - return $e(d, n, m), m; + return $e(d, n, h), h; }; function* Ji(t, e, r, n, o, a, i) { const { importHook: c, importNowHook: u, moduleMap: l, moduleMapHook: d, moduleRecords: f } = L(t, r); - let m = l[n]; - if (m === void 0 && d !== void 0 && (m = d(n)), typeof m == "string") + let h = l[n]; + if (h === void 0 && d !== void 0 && (h = d(n)), typeof h == "string") G.fail( un`Cannot map module ${xe(n)} to ${xe( - m + h )} in parent compartment, not yet implemented`, v ); - else if (m !== void 0) { - const h = L(e, m); - h === void 0 && G.fail( + else if (h !== void 0) { + const m = L(e, h); + m === void 0 && G.fail( un`Cannot map module ${xe( n )} because the value is not a module exports namespace, or is from another realm`, @@ -3603,8 +3603,8 @@ function* Ji(t, e, r, n, o, a, i) { const _ = yield Ut( t, e, - h.compartment, - h.specifier, + m.compartment, + m.specifier, o, a, i @@ -3626,14 +3626,14 @@ function* Ji(t, e, r, n, o, a, i) { "Cannot redirect to an explicit record with a specified compartment" ); const { - compartment: h = r, + compartment: m = r, specifier: _ = n, record: E, importMeta: T } = p, N = fo( t, e, - h, + m, _, E, o, @@ -3648,7 +3648,7 @@ function* Ji(t, e, r, n, o, a, i) { throw v( "Cannot redirect to an implicit record with a specified importMeta" ); - const h = yield Ut( + const m = yield Ut( t, e, p.compartment, @@ -3657,7 +3657,7 @@ function* Ji(t, e, r, n, o, a, i) { a, i ); - return $e(f, n, h), h; + return $e(f, n, m), m; } throw v("Unnexpected RedirectStaticModuleInterface record shape"); } @@ -3933,19 +3933,19 @@ const Qi = (t, e) => e, ec = (t, e) => t, po = async (t, e, r, n) => { `SES third-party static module record "exports" property must be an array of strings for module ${o}` ); ut(e.exports, (f) => { - let m = c[f]; + let h = c[f]; const p = []; M(c, f, { - get: () => m, + get: () => h, set: (E) => { - m = E; + h = E; for (const T of p) T(E); }, enumerable: !0, configurable: !1 }), l[f] = (E) => { - X(p, E), E(m); + X(p, E), E(h); }; }), l["*"] = (f) => { f(c); @@ -3985,18 +3985,18 @@ const Qi = (t, e) => e, ec = (t, e) => t, po = async (t, e, r, n) => { __syncModuleProgram__: l, __fixedExportMap__: d = {}, __liveExportMap__: f = {}, - __reexportMap__: m = {}, + __reexportMap__: h = {}, __needsImportMeta__: p = !1, - __syncModuleFunctor__: h + __syncModuleFunctor__: m } = i, _ = L(t, o), { __shimTransforms__: E, importMetaHook: T } = _, { exportsProxy: N, exportsTarget: x, activate: D } = Un( o, _, e, a - ), B = z(null), H = z(null), K = z(null), ze = z(null), me = z(null); - c && $r(me, c), p && T && T(a, me); + ), B = z(null), H = z(null), K = z(null), ze = z(null), he = z(null); + c && $r(he, c), p && T && T(a, he); const Ge = z(null), rt = z(null); - ut(re(d), ([he, [V]]) => { + ut(re(d), ([me, [V]]) => { let W = Ge[V]; if (!W) { let ee, te = !0, ce = []; @@ -4023,22 +4023,22 @@ const Qi = (t, e) => e, ec = (t, e) => t, po = async (t, e, r, n) => { } }, Ge[V] = W, K[V] = be; } - B[he] = { + B[me] = { get: W.get, set: void 0, enumerable: !0, configurable: !1 - }, rt[he] = W.notify; + }, rt[me] = W.notify; }), ut( re(f), - ([he, [V, W]]) => { + ([me, [V, W]]) => { let ee = Ge[V]; if (!ee) { let te, ce = !0; const Y = [], be = () => { if (ce) throw lt( - `binding ${cr(he)} not yet initialized` + `binding ${cr(me)} not yet initialized` ); return te; }, gt = y((Ee) => { @@ -4064,22 +4064,22 @@ const Qi = (t, e) => e, ec = (t, e) => t, po = async (t, e, r, n) => { configurable: !1 }), ze[V] = gt; } - B[he] = { + B[me] = { get: ee.get, set: void 0, enumerable: !0, configurable: !1 - }, rt[he] = ee.notify; + }, rt[me] = ee.notify; } ); - const Be = (he) => { - he(x); + const Be = (me) => { + me(x); }; rt["*"] = Be; - function ar(he) { + function ar(me) { const V = z(null); V.default = !1; - for (const [W, ee] of he) { + for (const [W, ee] of me) { const te = Ue(n, W); te.execute(); const { notifiers: ce } = te; @@ -4097,8 +4097,8 @@ const Qi = (t, e) => e, ec = (t, e) => t, po = async (t, e, r, n) => { ce )) V[Y] === void 0 ? V[Y] = be : V[Y] = !1; - if (m[W]) - for (const [Y, be] of m[W]) + if (h[W]) + for (const [Y, be] of h[W]) V[be] = ce[Y]; } for (const [W, ee] of re(V)) @@ -4120,7 +4120,7 @@ const Qi = (t, e) => e, ec = (t, e) => t, po = async (t, e, r, n) => { ), y(x), D(); } let Ot; - h !== void 0 ? Ot = h : Ot = As(_, l, { + m !== void 0 ? Ot = m : Ot = As(_, l, { globalObject: o.globalThis, transforms: E, __moduleShimLexicals__: H @@ -4128,15 +4128,15 @@ const Qi = (t, e) => e, ec = (t, e) => t, po = async (t, e, r, n) => { let Gn = !1, Bn; function Bs() { if (Ot) { - const he = Ot; + const me = Ot; Ot = null; try { - he( + me( y({ imports: y(ar), onceVar: y(K), liveVar: y(ze), - importMeta: me + importMeta: he }) ); } catch (V) { @@ -4228,13 +4228,13 @@ const dc = (t, e, r) => { ); $e(c, o, l); for (const [d, f] of re(a)) { - const m = Is( + const h = Is( t, e, n, f ); - $e(u, d, m); + $e(u, d, h); } return l; }, { quote: Xr } = G, bt = new Me(), Ce = new Me(), lr = (t) => { @@ -4247,7 +4247,7 @@ const dc = (t, e, r) => { throw v( "Compartment.prototype.constructor is not a valid constructor." ); -}, mo = (t, e) => { +}, ho = (t, e) => { const { execute: r, exportsProxy: n } = Is( Ce, bt, @@ -4294,7 +4294,7 @@ const dc = (t, e, r) => { throw v("first argument of import() must be a string"); return lr(this), jo( po(Ce, bt, this, t), - () => ({ namespace: mo( + () => ({ namespace: ho( /** @type {Compartment} */ this, t @@ -4309,7 +4309,7 @@ const dc = (t, e, r) => { importNow(t) { if (typeof t != "string") throw v("first argument of importNow() must be a string"); - return lr(this), tc(Ce, bt, this, t), mo( + return lr(this), tc(Ce, bt, this, t), ho( /** @type {Compartment} */ this, t @@ -4339,9 +4339,9 @@ const dn = (t, e, r) => { __shimTransforms__: l = [], resolveHook: d, importHook: f, - importNowHook: m, + importNowHook: h, moduleMapHook: p, - importMetaHook: h + importMetaHook: m } = i, _ = [...u, ...l], E = new Pe(), T = new Pe(), N = new Pe(); for (const [B, H] of re(a || {})) { if (typeof H == "string") @@ -4380,10 +4380,10 @@ const dn = (t, e, r) => { safeEvaluate: D, resolveHook: d, importHook: f, - importNowHook: m, + importNowHook: h, moduleMap: a, moduleMapHook: p, - importMetaHook: h, + importMetaHook: m, moduleRecords: E, __shimTransforms__: l, deferredExports: N, @@ -4399,7 +4399,7 @@ function fc() { return arguments; } const pc = () => { - const t = ve.prototype.constructor, e = J(fc(), "callee"), r = e && e.get, n = ba(new pe()), o = j(n), a = Rr[To] && ya(/./), i = a && j(a), c = fa([]), u = j(c), l = j(Ws), d = ha(new Pe()), f = j(d), m = ga(new Ct()), p = j(m), h = j(u); + const t = ve.prototype.constructor, e = J(fc(), "callee"), r = e && e.get, n = ba(new pe()), o = j(n), a = Rr[To] && ya(/./), i = a && j(a), c = fa([]), u = j(c), l = j(Ws), d = ma(new Pe()), f = j(d), h = ga(new Ct()), p = j(h), m = j(u); function* _() { } const E = Qr(_), T = E.prototype; @@ -4410,7 +4410,7 @@ const pc = () => { ), D = x.prototype, B = D.prototype, H = j(B); async function K() { } - const ze = Qr(K), me = { + const ze = Qr(K), he = { "%InertFunction%": t, "%ArrayIteratorPrototype%": u, "%InertAsyncFunction%": ze, @@ -4420,7 +4420,7 @@ const pc = () => { "%AsyncIteratorPrototype%": H, "%Generator%": T, "%InertGeneratorFunction%": E, - "%IteratorPrototype%": h, + "%IteratorPrototype%": m, "%MapIteratorPrototype%": f, "%RegExpStringIteratorPrototype%": i, "%SetIteratorPrototype%": p, @@ -4429,21 +4429,21 @@ const pc = () => { "%TypedArray%": l, "%InertCompartment%": jn }; - return k.Iterator && (me["%IteratorHelperPrototype%"] = j( + return k.Iterator && (he["%IteratorHelperPrototype%"] = j( // eslint-disable-next-line @endo/no-polymorphic-call k.Iterator.from([]).take(0) - ), me["%WrapForValidIteratorPrototype%"] = j( + ), he["%WrapForValidIteratorPrototype%"] = j( // eslint-disable-next-line @endo/no-polymorphic-call k.Iterator.from({ next() { } }) - )), k.AsyncIterator && (me["%AsyncIteratorHelperPrototype%"] = j( + )), k.AsyncIterator && (he["%AsyncIteratorHelperPrototype%"] = j( // eslint-disable-next-line @endo/no-polymorphic-call k.AsyncIterator.from([]).take(0) - ), me["%WrapForValidAsyncIteratorPrototype%"] = j( + ), he["%WrapForValidAsyncIteratorPrototype%"] = j( // eslint-disable-next-line @endo/no-polymorphic-call k.AsyncIterator.from({ next() { } }) - )), me; + )), he; }, Cs = (t, e) => { if (e !== "safe" && e !== "unsafe") throw v(`unrecognized fakeHardenOption ${e}`); @@ -4453,7 +4453,7 @@ const pc = () => { return r.isFake = !0, y(r); }; y(Cs); -const mc = () => { +const hc = () => { const t = Et, e = t.prototype, r = Sa(Et, void 0); F(e, { constructor: { @@ -4463,20 +4463,20 @@ const mc = () => { }); const n = re( Ze(t) - ), o = ht( + ), o = mt( se(n, ([a, i]) => [ a, { ...i, configurable: !0 } ]) ); return F(r, o), { "%SharedSymbol%": r }; -}, hc = (t) => { +}, mc = (t) => { try { return t(), !1; } catch { return !0; } -}, ho = (t, e, r) => { +}, mo = (t, e, r) => { if (t === void 0) return !1; const n = J(t, e); @@ -4489,18 +4489,18 @@ const mc = () => { if (ne(a, c, [i]), c[e] !== i) return !1; const u = { __proto__: t }; - return ne(a, u, [i]), u[e] !== i || !hc(() => ne(a, t, [r])) || "originalValue" in o || n.configurable === !1 ? !1 : (M(t, e, { + return ne(a, u, [i]), u[e] !== i || !mc(() => ne(a, t, [r])) || "originalValue" in o || n.configurable === !1 ? !1 : (M(t, e, { value: r, writable: !0, enumerable: n.enumerable, configurable: !0 }), !0); }, gc = (t) => { - ho( + mo( t["%IteratorPrototype%"], "constructor", t.Iterator - ), ho( + ), mo( t["%IteratorPrototype%"], qe, "Iterator" @@ -4550,10 +4550,10 @@ const yc = Ba(), vc = () => { /** @param {string} debugName */ (Be) => Be !== "" ), - __hardenTaming__: m = le("LOCKDOWN_HARDEN_TAMING", "safe"), + __hardenTaming__: h = le("LOCKDOWN_HARDEN_TAMING", "safe"), dateTaming: p = "safe", // deprecated - mathTaming: h = "safe", + mathTaming: m = "safe", // deprecated ..._ } = t; @@ -4573,17 +4573,17 @@ const yc = Ba(), vc = () => { "Already locked down but not by this SES instance (SES_MULTIPLE_INSTANCES)" ); xi(l); - const N = xs(), { addIntrinsics: x, completePrototypes: D, finalIntrinsics: B } = as(), H = Cs(yc, m); - x({ harden: H }), x(Ja()), x(Xa(p)), x(Bi(e, u)), x(Qa(h)), x(ei(o)), x(mc()), x(pc()), D(); + const N = xs(), { addIntrinsics: x, completePrototypes: D, finalIntrinsics: B } = as(), H = Cs(yc, h); + x({ harden: H }), x(Ja()), x(Xa(p)), x(Bi(e, u)), x(Qa(m)), x(ei(o)), x(hc()), x(pc()), D(); const K = B(), ze = { __proto__: null }; typeof k.Buffer == "function" && (ze.Buffer = k.Buffer); - let me; - e !== "unsafe" && (me = K["%InitialGetStackString%"]); + let he; + e !== "unsafe" && (he = K["%InitialGetStackString%"]); const Ge = Ai( i, r, n, - me + he ); if (k.console = /** @type {Console} */ Ge.console, typeof /** @type {any} */ @@ -4660,8 +4660,8 @@ k[wc] = bc; const Ec = (t, e) => { let r = { x: 0, y: 0 }, n = { x: 0, y: 0 }, o = { x: 0, y: 0 }; const a = (u) => { - const { clientX: l, clientY: d } = u, f = l - o.x + n.x, m = d - o.y + n.y; - r = { x: f, y: m }, t.style.transform = `translate(${f}px, ${m}px)`, e == null || e(); + const { clientX: l, clientY: d } = u, f = l - o.x + n.x, h = d - o.y + n.y; + r = { x: f, y: h }, t.style.transform = `translate(${f}px, ${h}px)`, e == null || e(); }, i = () => { document.removeEventListener("mousemove", a), document.removeEventListener("mouseup", i); }, c = (u) => { @@ -5034,7 +5034,7 @@ class Q { } const I = Object.freeze({ status: "aborted" -}), wt = (t) => ({ status: "dirty", value: t }), ae = (t) => ({ status: "valid", value: t }), pn = (t) => t.status === "aborted", mn = (t) => t.status === "dirty", jt = (t) => t.status === "valid", Zt = (t) => typeof Promise < "u" && t instanceof Promise; +}), wt = (t) => ({ status: "dirty", value: t }), ae = (t) => ({ status: "valid", value: t }), pn = (t) => t.status === "aborted", hn = (t) => t.status === "dirty", jt = (t) => t.status === "valid", Zt = (t) => typeof Promise < "u" && t instanceof Promise; function kr(t, e, r, n) { if (typeof e == "function" ? t !== e || !n : !e.has(t)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); @@ -6305,10 +6305,10 @@ class U extends $ { return o.common.async ? Promise.resolve().then(async () => { const l = []; for (const d of u) { - const f = await d.key, m = await d.value; + const f = await d.key, h = await d.value; l.push({ key: f, - value: m, + value: h, alwaysSet: d.alwaysSet }); } @@ -6665,14 +6665,14 @@ class Zr extends $ { }); } } -function hn(t, e) { +function mn(t, e) { const r = Ve(t), n = Ve(e); if (t === e) return { valid: !0, data: t }; if (r === w.object && n === w.object) { const o = O.objectKeys(e), a = O.objectKeys(t).filter((c) => o.indexOf(c) !== -1), i = { ...t, ...e }; for (const c of a) { - const u = hn(t[c], e[c]); + const u = mn(t[c], e[c]); if (!u.valid) return { valid: !1 }; i[c] = u.data; @@ -6683,7 +6683,7 @@ function hn(t, e) { return { valid: !1 }; const o = []; for (let a = 0; a < t.length; a++) { - const i = t[a], c = e[a], u = hn(i, c); + const i = t[a], c = e[a], u = mn(i, c); if (!u.valid) return { valid: !1 }; o.push(u.data); @@ -6697,8 +6697,8 @@ class Vt extends $ { const { status: r, ctx: n } = this._processInputParams(e), o = (a, i) => { if (pn(a) || pn(i)) return I; - const c = hn(a.value, i.value); - return c.valid ? ((mn(a) || mn(i)) && r.dirty(), { status: r.value, value: c.data }) : (b(n, { + const c = mn(a.value, i.value); + return c.valid ? ((hn(a) || hn(i)) && r.dirty(), { status: r.value, value: c.data }) : (b(n, { code: g.invalid_intersection_types }), I); }; @@ -6869,7 +6869,7 @@ Ar.create = (t, e, r) => new Ar({ typeName: A.ZodMap, ...C(r) }); -class mt extends $ { +class ht extends $ { _parse(e) { const { status: r, ctx: n } = this._processInputParams(e); if (n.parsedType !== w.set) @@ -6908,13 +6908,13 @@ class mt extends $ { return n.common.async ? Promise.all(c).then((u) => i(u)) : i(c); } min(e, r) { - return new mt({ + return new ht({ ...this._def, minSize: { value: e, message: S.toString(r) } }); } max(e, r) { - return new mt({ + return new ht({ ...this._def, maxSize: { value: e, message: S.toString(r) } }); @@ -6926,7 +6926,7 @@ class mt extends $ { return this.min(1, e); } } -mt.create = (t, e) => new mt({ +ht.create = (t, e) => new ht({ valueType: t, minSize: null, maxSize: null, @@ -7474,7 +7474,7 @@ var A; })(A || (A = {})); const Vc = (t, e = { message: `Input not instance of ${t.name}` -}) => Ds((r) => r instanceof t, e), Us = ke.create, js = Xe.create, Wc = Ir.create, qc = Qe.create, Zs = zt.create, Kc = pt.create, Yc = Pr.create, Jc = Gt.create, Xc = Bt.create, Qc = At.create, el = dt.create, tl = je.create, rl = Tr.create, nl = Te.create, ol = U.create, sl = U.strictCreate, al = Ht.create, il = Zr.create, cl = Vt.create, ll = Oe.create, ul = Wt.create, dl = Ar.create, fl = mt.create, pl = xt.create, ml = qt.create, hl = Kt.create, gl = et.create, yl = Yt.create, vl = It.create, bo = Ae.create, _l = Ne.create, bl = tt.create, wl = Ae.createWithPreprocess, El = sr.create, Sl = () => Us().optional(), xl = () => js().optional(), kl = () => Zs().optional(), Pl = { +}) => Ds((r) => r instanceof t, e), Us = ke.create, js = Xe.create, Wc = Ir.create, qc = Qe.create, Zs = zt.create, Kc = pt.create, Yc = Pr.create, Jc = Gt.create, Xc = Bt.create, Qc = At.create, el = dt.create, tl = je.create, rl = Tr.create, nl = Te.create, ol = U.create, sl = U.strictCreate, al = Ht.create, il = Zr.create, cl = Vt.create, ll = Oe.create, ul = Wt.create, dl = Ar.create, fl = ht.create, pl = xt.create, hl = qt.create, ml = Kt.create, gl = et.create, yl = Yt.create, vl = It.create, bo = Ae.create, _l = Ne.create, bl = tt.create, wl = Ae.createWithPreprocess, El = sr.create, Sl = () => Us().optional(), xl = () => js().optional(), kl = () => Zs().optional(), Pl = { string: (t) => ke.create({ ...t, coerce: !0 }), number: (t) => Xe.create({ ...t, coerce: !0 }), boolean: (t) => zt.create({ @@ -7497,7 +7497,7 @@ var Z = /* @__PURE__ */ Object.freeze({ DIRTY: wt, OK: ae, isAborted: pn, - isDirty: mn, + isDirty: hn, isValid: jt, isAsync: Zt, get util() { @@ -7530,7 +7530,7 @@ var Z = /* @__PURE__ */ Object.freeze({ ZodTuple: Oe, ZodRecord: Wt, ZodMap: Ar, - ZodSet: mt, + ZodSet: ht, ZodFunction: xt, ZodLazy: qt, ZodLiteral: Kt, @@ -7567,8 +7567,8 @@ var Z = /* @__PURE__ */ Object.freeze({ function: pl, instanceof: Vc, intersection: cl, - lazy: ml, - literal: hl, + lazy: hl, + literal: ml, map: dl, nan: Wc, nativeEnum: yl, @@ -7619,8 +7619,8 @@ function Il(t, e, r, n) { `${l.inlineEnd}px` ); const d = window.innerWidth - l.inlineEnd, f = window.innerHeight - l.blockStart; - let m = Math.min((n == null ? void 0 : n.width) || c, d), p = Math.min((n == null ? void 0 : n.height) || u, f); - return m = Math.max(m, a), p = Math.max(p, i), o.setAttribute("title", t), o.setAttribute("iframe-src", e), o.setAttribute("width", String(m)), o.setAttribute("height", String(p)), document.body.appendChild(o), o; + let h = Math.min((n == null ? void 0 : n.width) || c, d), p = Math.min((n == null ? void 0 : n.height) || u, f); + return h = Math.max(h, a), p = Math.max(p, i), o.setAttribute("title", t), o.setAttribute("iframe-src", e), o.setAttribute("width", String(h)), o.setAttribute("height", String(p)), document.body.appendChild(o), o; } const Cl = Z.function().args( Z.string(), @@ -7713,15 +7713,38 @@ function Ml(t, e) { } }, utils: { + geometry: { + center(i) { + return window.app.plugins.public_utils.centerShapes(i); + } + }, types: { - isText(i) { - return i.type === "text"; + isFrame(i) { + return i.type === "frame"; + }, + isGroup(i) { + return i.type === "group"; + }, + isMask(i) { + return i.type === "group" && i.isMask(); + }, + isBool(i) { + return i.type === "bool"; }, isRectangle(i) { return i.type === "rect"; }, - isFrame(i) { - return i.type === "frame"; + isPath(i) { + return i.type === "path"; + }, + isText(i) { + return i.type === "text"; + }, + isEllipse(i) { + return i.type === "circle"; + }, + isSVG(i) { + return i.type === "svg-raw"; } } }, @@ -7755,6 +7778,9 @@ function Ml(t, e) { get library() { return t.library; }, + get fonts() { + return t.fonts; + }, get currentUser() { return t.currentUser; }, @@ -7867,6 +7893,10 @@ repairIntrinsics({ }); const Eo = globalThis; Eo.initPluginsRuntime = (t) => { - console.log("%c[PLUGINS] Initialize runtime", "color: #008d7c"), Fl(t), Eo.ɵcontext = t("TEST"), globalThis.ɵloadPlugin = Gs, globalThis.ɵloadPluginByUrl = Dl; + try { + console.log("%c[PLUGINS] Initialize runtime", "color: #008d7c"), Fl(t), Eo.ɵcontext = t("TEST"), globalThis.ɵloadPlugin = Gs, globalThis.ɵloadPluginByUrl = Dl; + } catch (e) { + console.error(e); + } }; //# sourceMappingURL=index.js.map