diff --git a/CHANGES.md b/CHANGES.md index 08b021081..154cb3fd5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -57,6 +57,8 @@ - Fix max height in library dialog [Github #2335](https://github.com/penpot/penpot/issues/2335) - Fix undo ungroup (shift+g) scrambles positions [Taiga #4674](https://tree.taiga.io/project/penpot/issue/4674) - Fix justified text is stretched [Github #2539](https://github.com/penpot/penpot/issues/2539) +- Fix mousewheel on viewer inspector [Taiga #4221](https://tree.taiga.io/project/penpot/issue/4221) +- Fix path edition activated on boards [Taiga #4105](https://tree.taiga.io/project/penpot/issue/4105) ## 1.16.2-beta diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index a0eee2288..33041c1eb 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -45,10 +45,10 @@ (def default-features (cond-> #{} - (contains? cf/flags :feature-storage-pointer-map) + (contains? cf/flags :fdata-storage-pointer-map) (conj "storage/pointer-map") - (contains? cf/flags :feature-storage-objects-map) + (contains? cf/flags :fdata-storage-objects-map) (conj "storage/objects-map"))) ;; --- SPECS diff --git a/backend/src/app/srepl/ext.clj b/backend/src/app/srepl/ext.clj index 640c6ee47..04ff5822a 100644 --- a/backend/src/app/srepl/ext.clj +++ b/backend/src/app/srepl/ext.clj @@ -29,7 +29,7 @@ :email email :fullname fullname :is-active true - :password (derive-password password) + :password password :props {}} profile (->> (cmd.auth/create-profile! conn params) (cmd.auth/create-profile-rels! conn))] diff --git a/common/src/app/common/geom/point.cljc b/common/src/app/common/geom/point.cljc index 5dd41501e..d83a46c99 100644 --- a/common/src/app/common/geom/point.cljc +++ b/common/src/app/common/geom/point.cljc @@ -60,7 +60,7 @@ (point v v) (point-like? v) - (map->Point v) + (Point. (:x v) (:y v)) :else (ex/raise :hint "invalid arguments (on pointer constructor)" :value v))) @@ -274,12 +274,12 @@ (Point. (mth/precision (dm/get-prop pt :x) decimals) (mth/precision (dm/get-prop pt :y) decimals)))) -(defn half-round +(defn round-step "Round the coordinates to the closest half-point" - [pt] + [pt step] (assert (point? pt) "expected point instance") - (Point. (mth/half-round (dm/get-prop pt :x)) - (mth/half-round (dm/get-prop pt :y)))) + (Point. (mth/round (dm/get-prop pt :x) step) + (mth/round (dm/get-prop pt :y) step))) (defn transform "Transform a point applying a matrix transformation." diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 4b11007a3..15cfdd9c0 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -359,7 +359,7 @@ to-reflow (cond-> to-reflow - (and (ctl/layout-child-id? objects current) + (and (ctl/layout-descent? objects parent-base) (not= uuid/zero (:frame-id parent-base))) (conj (:frame-id parent-base)))] (recur modif-tree @@ -382,15 +382,24 @@ result)) (defn set-objects-modifiers - ([modif-tree objects ignore-constraints snap-pixel?] - (set-objects-modifiers nil modif-tree objects ignore-constraints snap-pixel?)) + ([modif-tree objects] + (set-objects-modifiers modif-tree objects nil)) - ([old-modif-tree modif-tree objects ignore-constraints snap-pixel?] + ([modif-tree objects params] + (set-objects-modifiers nil modif-tree objects params)) + + ([old-modif-tree modif-tree objects + {:keys [ignore-constraints snap-pixel? snap-precision snap-ignore-axis] + :or {ignore-constraints false snap-pixel? false snap-precision 1 snap-ignore-axis nil}}] (let [objects (-> objects (cond-> (some? old-modif-tree) (apply-structure-modifiers old-modif-tree)) (apply-structure-modifiers modif-tree)) + modif-tree + (cond-> modif-tree + snap-pixel? (gpp/adjust-pixel-precision objects snap-precision snap-ignore-axis)) + bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points])) bounds (cond-> bounds (some? old-modif-tree) @@ -417,11 +426,7 @@ modif-tree (if old-modif-tree (merge-modif-tree old-modif-tree modif-tree) - modif-tree) - - modif-tree - (cond-> modif-tree - snap-pixel? (gpp/adjust-pixel-precision objects))] + modif-tree)] ;;#?(:cljs ;; (.log js/console ">result" (modif->js modif-tree objects))) diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index c1236046f..e85c70893 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -18,7 +18,7 @@ [app.common.types.modifiers :as ctm])) (defn size-pixel-precision - [modifiers shape points] + [modifiers shape points precision] (let [origin (gpo/origin points) curr-width (gpo/width-points points) curr-height (gpo/height-points points) @@ -29,8 +29,8 @@ vertical-line? (and path? (<= curr-width 0.01)) horizontal-line? (and path? (<= curr-height 0.01)) - target-width (if vertical-line? curr-width (max 1 (mth/round curr-width))) - target-height (if horizontal-line? curr-height (max 1 (mth/round curr-height))) + target-width (if vertical-line? curr-width (max 1 (mth/round curr-width precision))) + target-height (if horizontal-line? curr-height (max 1 (mth/round curr-height precision))) ratio-width (/ target-width curr-width) ratio-height (/ target-height curr-height) @@ -39,23 +39,32 @@ (ctm/resize scalev origin transform transform-inverse {:precise? true})))) (defn position-pixel-precision - [modifiers _ points] + [modifiers _ points precision ignore-axis] (let [bounds (gpr/bounds->rect points) corner (gpt/point bounds) - target-corner (gpt/round corner) + target-corner + (cond-> corner + (= ignore-axis :x) + (update :y mth/round precision) + + (= ignore-axis :y) + (update :x mth/round precision) + + (nil? ignore-axis) + (gpt/round-step precision)) deltav (gpt/to-vec corner target-corner)] (ctm/move modifiers deltav))) (defn set-pixel-precision "Adjust modifiers so they adjust to the pixel grid" - [modifiers shape] + [modifiers shape precision ignore-axis] (let [points (-> shape :points (gco/transform-points (ctm/modifiers->transform modifiers))) has-resize? (not (ctm/only-move? modifiers)) [modifiers points] (let [modifiers (cond-> modifiers - has-resize? (size-pixel-precision shape points)) + has-resize? (size-pixel-precision shape points precision)) points (if has-resize? @@ -63,16 +72,16 @@ (gco/transform-points (ctm/modifiers->transform modifiers)) ) points)] [modifiers points])] - (position-pixel-precision modifiers shape points))) + (position-pixel-precision modifiers shape points precision ignore-axis))) (defn adjust-pixel-precision - [modif-tree objects] + [modif-tree objects precision ignore-axis] (let [update-modifiers (fn [modif-tree shape] (let [modifiers (dm/get-in modif-tree [(:id shape) :modifiers])] (cond-> modif-tree (ctm/has-geometry? modifiers) - (update-in [(:id shape) :modifiers] set-pixel-precision shape))))] + (update-in [(:id shape) :modifiers] set-pixel-precision shape precision ignore-axis))))] (->> (keys modif-tree) (map (d/getf objects)) diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index c3035df27..cbff62e3a 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -238,7 +238,15 @@ points-transform-mtx (gmt/translate-matrix center))) - transform-inverse (when transform (gmt/inverse transform))] + transform-inverse (when transform (gmt/inverse transform)) + + ;; There is a rounding error when the matrix returned have float point values + ;; when the matrix is unit we return a "pure" matrix so we don't accumulate + ;; rounding problems + [transform transform-inverse] + (if (gmt/unit? transform) + [(gmt/matrix) (gmt/matrix)] + [transform transform-inverse])] [sr transform transform-inverse])) diff --git a/common/src/app/common/math.cljc b/common/src/app/common/math.cljc index 5ed4f01f9..9def09aff 100644 --- a/common/src/app/common/math.cljc +++ b/common/src/app/common/math.cljc @@ -104,15 +104,16 @@ (defn round "Returns the value of a number rounded to - the nearest integer." - [v] - #?(:cljs (js/Math.round v) - :clj (Math/round (float v)))) + the nearest integer. + If given step rounds to the next closest step, for example: + (round 13.4 0.5) => 13.5 + (round 13.4 0.3) => 13.3" + ([v step] + (* (round (/ v step)) step)) -(defn half-round - "Returns a value rounded to the next point or half point" - [v] - (/ (round (* v 2)) 2)) + ([v] + #?(:cljs (js/Math.round v) + :clj (Math/round (float v))))) (defn ceil "Returns the smallest integer greater than diff --git a/common/src/app/common/pages/changes.cljc b/common/src/app/common/pages/changes.cljc index b7a81a136..334edefb1 100644 --- a/common/src/app/common/pages/changes.cljc +++ b/common/src/app/common/pages/changes.cljc @@ -265,7 +265,8 @@ (move-objects [objects] (let [valid? (every? (partial is-valid-move? objects) shapes) parent (get objects parent-id) - index (if (nil? after-shape) index (inc (d/index-of (:shapes parent) after-shape))) + after-shape-index (d/index-of (:shapes parent) after-shape) + index (if (nil? after-shape-index) index (inc after-shape-index)) frame-id (if (= :frame (:type parent)) (:id parent) (:frame-id parent))] diff --git a/common/src/app/common/pages/common.cljc b/common/src/app/common/pages/common.cljc index 6654e592f..ab5379504 100644 --- a/common/src/app/common/pages/common.cljc +++ b/common/src/app/common/pages/common.cljc @@ -19,84 +19,88 @@ ;; in the main component, none of the attributes of the same group is changed. (def component-sync-attrs - {:name :name-group - :fills :fill-group - :fill-color :fill-group - :fill-opacity :fill-group - :fill-color-gradient :fill-group - :fill-color-ref-file :fill-group - :fill-color-ref-id :fill-group - :hide-fill-on-export :fill-group - :content :content-group - :position-data :content-group - :hidden :visibility-group - :blocked :modifiable-group - :grow-type :text-font-group - :font-family :text-font-group - :font-size :text-font-group - :font-style :text-font-group - :font-weight :text-font-group - :letter-spacing :text-display-group - :line-height :text-display-group - :text-align :text-display-group - :strokes :stroke-group - :stroke-color :stroke-group - :stroke-color-gradient :stroke-group - :stroke-color-ref-file :stroke-group - :stroke-color-ref-id :stroke-group - :stroke-opacity :stroke-group - :stroke-style :stroke-group - :stroke-width :stroke-group - :stroke-alignment :stroke-group - :stroke-cap-start :stroke-group - :stroke-cap-end :stroke-group - :rx :radius-group - :ry :radius-group - :r1 :radius-group - :r2 :radius-group - :r3 :radius-group - :r4 :radius-group - :type :geometry-group - :selrect :geometry-group - :points :geometry-group - :locked :geometry-group - :proportion :geometry-group - :proportion-lock :geometry-group - :x :geometry-group - :y :geometry-group - :width :geometry-group - :height :geometry-group - :rotation :geometry-group - :transform :geometry-group - :transform-inverse :geometry-group - :opacity :layer-effects-group - :blend-mode :layer-effects-group - :shadow :shadow-group - :blur :blur-group - :masked-group? :mask-group - :constraints-h :constraints-group - :constraints-v :constraints-group - :fixed-scroll :constraints-group - :exports :exports-group + {:name :name-group + :fills :fill-group + :fill-color :fill-group + :fill-opacity :fill-group + :fill-color-gradient :fill-group + :fill-color-ref-file :fill-group + :fill-color-ref-id :fill-group + :hide-fill-on-export :fill-group + :content :content-group + :position-data :content-group + :hidden :visibility-group + :blocked :modifiable-group + :grow-type :text-font-group + :font-family :text-font-group + :font-size :text-font-group + :font-style :text-font-group + :font-weight :text-font-group + :letter-spacing :text-display-group + :line-height :text-display-group + :text-align :text-display-group + :strokes :stroke-group + :stroke-color :stroke-group + :stroke-color-gradient :stroke-group + :stroke-color-ref-file :stroke-group + :stroke-color-ref-id :stroke-group + :stroke-opacity :stroke-group + :stroke-style :stroke-group + :stroke-width :stroke-group + :stroke-alignment :stroke-group + :stroke-cap-start :stroke-group + :stroke-cap-end :stroke-group + :rx :radius-group + :ry :radius-group + :r1 :radius-group + :r2 :radius-group + :r3 :radius-group + :r4 :radius-group + :type :geometry-group + :selrect :geometry-group + :points :geometry-group + :locked :geometry-group + :proportion :geometry-group + :proportion-lock :geometry-group + :x :geometry-group + :y :geometry-group + :width :geometry-group + :height :geometry-group + :rotation :geometry-group + :transform :geometry-group + :transform-inverse :geometry-group + :opacity :layer-effects-group + :blend-mode :layer-effects-group + :shadow :shadow-group + :blur :blur-group + :masked-group? :mask-group + :constraints-h :constraints-group + :constraints-v :constraints-group + :fixed-scroll :constraints-group + :exports :exports-group - :layout :layout-container - :layout-dir :layout-container - :layout-gap :layout-container - :layout-wrap-type :layout-container - :layout-padding-type :layout-container - :layout-padding :layout-container - :layout-h-orientation :layout-container - :layout-v-orientation :layout-container + :layout :layout-container + :layout-align-content :layout-container + :layout-align-items :layout-container + :layout-flex-dir :layout-container + :layout-gap :layout-container + :layout-gap-type :layout-container + :layout-justify-content :layout-container + :layout-wrap-type :layout-container + :layout-padding-type :layout-container + :layout-padding :layout-container + :layout-h-orientation :layout-container + :layout-v-orientation :layout-container - :layout-item-margin :layout-item - :layout-item-margin-type :layout-item - :layout-item-h-sizing :layout-item - :layout-item-v-sizing :layout-item - :layout-item-max-h :layout-item - :layout-item-min-h :layout-item - :layout-item-max-w :layout-item - :layout-item-min-w :layout-item - :layout-item-align-self :layout-item}) + :layout-item-margin :layout-item + :layout-item-margin-type :layout-item + :layout-item-h-sizing :layout-item + :layout-item-v-sizing :layout-item + :layout-item-max-h :layout-item + :layout-item-min-h :layout-item + :layout-item-max-w :layout-item + :layout-item-min-w :layout-item + :layout-item-align-self :layout-item}) ;; Attributes that may directly be edited by the user with forms (def editable-attrs diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index bdc5a781f..973c1a714 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -353,6 +353,16 @@ (filter (comp (into #{} ids) second)) (map second))) +(defn get-index-replacement + "Given a collection of shapes, calculate their positions + in the parent, find first index and return next one" + [shapes objects] + (->> shapes + (order-by-indexed-shapes objects) + first + (get-position-on-parent objects) + inc)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SHAPES ORGANIZATION (PATH MANAGEMENT) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 5660f1ae2..cb7911567 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -125,7 +125,7 @@ update-new-shape (fn [new-shape original-shape] - (let [new-name (ctst/generate-unique-name @unames (:name new-shape))] + (let [new-name (:name new-shape)] (when (nil? (:parent-id original-shape)) (vswap! unames conj new-name)) diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index 507860fb4..4ff5430ee 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -278,7 +278,7 @@ (def ^:private minimal-shapes [{:type :rect - :name "Rect-1" + :name "Rectangle" :fills [{:fill-color default-color :fill-opacity 1}] :strokes [] @@ -292,13 +292,13 @@ :strokes []} {:type :circle - :name "Circle-1" + :name "Ellipse" :fills [{:fill-color default-color :fill-opacity 1}] :strokes []} {:type :path - :name "Path-1" + :name "Path" :fills [] :strokes [{:stroke-style :solid :stroke-alignment :center @@ -307,7 +307,7 @@ :stroke-opacity 1}]} {:type :frame - :name "Board-1" + :name "Board" :fills [{:fill-color clr/white :fill-opacity 1}] :strokes [] @@ -320,7 +320,7 @@ :ry 0} {:type :text - :name "Text-1" + :name "Text" :content nil} {:type :svg-raw}]) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 6213668aa..88988c275 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -6,6 +6,7 @@ (ns app.common.types.shape.layout (:require + [app.common.data.macros :as dm] [app.common.spec :as us] [clojure.spec.alpha :as s])) @@ -99,15 +100,21 @@ ([shape] (and (= :frame (:type shape)) (= :flex (:layout shape))))) -(defn layout-child? [objects shape] +(defn layout-immediate-child? [objects shape] + (let [parent-id (:parent-id shape) + parent (get objects parent-id)] + (layout? parent))) + +(defn layout-immediate-child-id? [objects id] + (let [parent-id (dm/get-in objects [id :parent-id]) + parent (get objects parent-id)] + (layout? parent))) + +(defn layout-descent? [objects shape] (let [frame-id (:frame-id shape) frame (get objects frame-id)] (layout? frame))) -(defn layout-child-id? [objects id] - (let [shape (get objects id)] - (layout-child? objects shape))) - (defn inside-layout? "Check if the shape is inside a layout" [objects shape] diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index d7fd2c8db..470d8b68d 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -304,6 +304,8 @@ [used basename] (us/assert! ::set-of-strings used) (us/assert! ::us/string basename) + ;; We have add a condition because UX doesn't want numbers on + ;; layer names. (if-not (contains? used basename) basename (let [[prefix initial] (extract-numeric-suffix basename)] diff --git a/common/test/common_tests/geom_point_test.cljc b/common/test/common_tests/geom_point_test.cljc index c98052315..9be0bc153 100644 --- a/common/test/common_tests/geom_point_test.cljc +++ b/common/test/common_tests/geom_point_test.cljc @@ -203,7 +203,7 @@ (t/deftest halft-round-point (let [p1 (gpt/point 1.34567 3.34567) - rs (gpt/half-round p1)] + rs (gpt/round-step p1 0.5)] (t/is (gpt/point? rs)) (t/is (mth/close? 1.5 (:x rs))) (t/is (mth/close? 3.5 (:y rs))))) diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index 32228a0a4..5da973616 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -348,11 +348,21 @@ cursor: pointer; font-size: $fs14; display: flex; + gap: 0 10px; + justify-content: start; padding: $size-2; span { color: $color-gray-20; - margin-left: auto; + display: flex; + justify-content: start; + align-items: center; + } + + .check-icon { + min-width: 25px; + color: $color-gray-20; + justify-content: center; } &.dropdown-separator:not(:last-child) { @@ -375,11 +385,8 @@ & li.checked-element { padding-left: 0; - display: flex; - justify-content: space-around; & span { - margin: 0; color: $color-black; } diff --git a/frontend/src/app/main/constants.cljs b/frontend/src/app/main/constants.cljs index 968a56a13..acae0096e 100644 --- a/frontend/src/app/main/constants.cljs +++ b/frontend/src/app/main/constants.cljs @@ -190,3 +190,5 @@ {:name "YouTube thumb" :width 1280 :height 720}]) + +(def zoom-half-pixel-precision 8) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index cadb87e44..47de657b7 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -846,8 +846,8 @@ :text (rx/of (dwe/start-edition-mode id)) - (:group :bool) - (rx/of (dws/select-shapes (into (d/ordered-set) [(last shapes)]))) + (:group :bool :frame) + (rx/of (dws/select-shapes (into (d/ordered-set) shapes))) :svg-raw nil diff --git a/frontend/src/app/main/data/workspace/bool.cljs b/frontend/src/app/main/data/workspace/bool.cljs index bfaec41ac..b9a5be4d8 100644 --- a/frontend/src/app/main/data/workspace/bool.cljs +++ b/frontend/src/app/main/data/workspace/bool.cljs @@ -11,7 +11,6 @@ [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] [app.common.path.shapes-to-path :as stp] - [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.selection :as dws] @@ -85,9 +84,7 @@ (watch [it state _] (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state) - base-name (-> bool-type d/name str/capital (str "-1")) - name (-> (ctt/retrieve-used-names objects) - (ctt/generate-unique-name base-name)) + name (-> bool-type d/name str/capital) ids (selected-shapes-idx state) ordered-indexes (cph/order-by-indexed-shapes objects ids) shapes (->> ordered-indexes diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index 54e5456fe..140d58bbd 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -16,6 +16,7 @@ [app.common.types.shape-tree :as ctst] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] + [app.main.constants :refer [zoom-half-pixel-precision]] [app.main.data.workspace.drawing.common :as common] [app.main.data.workspace.state-helpers :as wsh] [app.main.snap :as snap] @@ -70,14 +71,15 @@ (let [stoper? #(or (ms/mouse-up? %) (= % :interrupt)) stoper (rx/filter stoper? stream) layout (get state :workspace-layout) + zoom (get-in state [:workspace-local :zoom] 1) snap-pixel? (contains? layout :snap-pixel-grid) - initial (cond-> @ms/mouse-position snap-pixel? gpt/round) + snap-precision (if (>= zoom zoom-half-pixel-precision) 0.5 1) + initial (cond-> @ms/mouse-position snap-pixel? (gpt/round-step snap-precision)) page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) focus (:workspace-focus-selected state) - zoom (get-in state [:workspace-local :zoom] 1) fid (ctst/top-nested-frame objects initial) layout? (ctl/layout? objects fid) @@ -119,7 +121,7 @@ (rx/map #(conj current %))))) (rx/map (fn [[_ shift? point]] - #(update-drawing % initial (cond-> point snap-pixel? gpt/round) shift?))))) + #(update-drawing % initial (cond-> point snap-pixel? (gpt/round-step snap-precision)) shift?))))) (rx/take-until stoper)) (->> (rx/of (common/handle-finish-drawing)) diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 77cf227a7..cbe0558ba 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -12,7 +12,6 @@ [app.common.pages.helpers :as cph] [app.common.types.component :as ctk] [app.common.types.shape :as cts] - [app.common.types.shape-tree :as ctst] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.state-helpers :as wsh] @@ -73,8 +72,7 @@ (= (count shapes) 1) (= (:type (first shapes)) :group)) (:name (first shapes)) - (-> (ctst/retrieve-used-names objects) - (ctst/generate-unique-name base-name))) + base-name) selrect (gsh/selection-rect shapes) group-idx (->> shapes @@ -162,7 +160,7 @@ shapes (shapes-for-grouping objects selected)] (when-not (empty? shapes) (let [[group changes] - (prepare-create-group it objects page-id shapes "Group-1" false)] + (prepare-create-group it objects page-id shapes "Group" false)] (rx/of (dch/commit-changes changes) (dws/select-shapes (d/ordered-set (:id group)))))))))) @@ -221,7 +219,7 @@ (= (:type (first shapes)) :group)) [first-shape (-> (pcb/empty-changes it page-id) (pcb/with-objects objects))] - (prepare-create-group it objects page-id shapes "Group-1" true)) + (prepare-create-group it objects page-id shapes "Mask" true)) changes (-> changes (pcb/update-shapes (:shapes group) @@ -237,10 +235,14 @@ :points (:points first-shape) :transform (:transform first-shape) :transform-inverse (:transform-inverse first-shape)))) - (pcb/resize-parents [(:id group)]))] + (pcb/resize-parents [(:id group)])) + undo-id (js/Symbol)] - (rx/of (dch/commit-changes changes) - (dws/select-shapes (d/ordered-set (:id group)))))))))) + (rx/of (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (dws/select-shapes (d/ordered-set (:id group))) + (ptk/data-event :layout/update [(:id group)]) + (dwu/commit-undo-transaction undo-id)))))))) (def unmask-group (ptk/reify ::unmask-group diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 9c75d03ae..78aaad5c9 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -22,7 +22,6 @@ [app.common.types.file :as ctf] [app.common.types.file.media-object :as ctfm] [app.common.types.pages-list :as ctpl] - [app.common.types.shape-tree :as ctst] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] [app.main.data.dashboard :as dd] @@ -373,9 +372,7 @@ (watch [it state _] (let [libraries (wsh/get-libraries state) component (cph/get-component libraries id) - all-components (-> state :workspace-data :components vals) - unames (into #{} (map :name) all-components) - new-name (ctst/generate-unique-name unames (:name component)) + new-name (:name component) components-v2 (features/active-feature? state :components-v2) diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs index a0131dca5..73f175cfd 100644 --- a/frontend/src/app/main/data/workspace/media.cljs +++ b/frontend/src/app/main/data/workspace/media.cljs @@ -8,6 +8,7 @@ (:require [app.common.exceptions :as ex] [app.common.logging :as log] + [app.common.math :as mth] [app.common.pages.changes-builder :as pcb] [app.common.spec :as us] [app.common.types.container :as ctn] @@ -52,8 +53,8 @@ shape {:name name :width width :height height - :x (- x (/ width 2)) - :y (- y (/ height 2)) + :x (mth/round (- x (/ width 2))) + :y (mth/round (- y (/ height 2))) :metadata {:width width :height height :mtype mtype diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 514fc32a7..de4782c4a 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -17,6 +17,7 @@ [app.common.spec :as us] [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] + [app.main.constants :refer [zoom-half-pixel-precision]] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.comments :as-alias dwcm] [app.main.data.workspace.guides :as-alias dwg] @@ -218,7 +219,7 @@ result (let [[id text-modifier] (first modifiers)] (recur (rest modifiers) - (update objects id apply-text-modifier text-modifier)))))) + (d/update-when result id apply-text-modifier text-modifier)))))) #_(defn apply-path-modifiers [objects path-modifiers] @@ -240,16 +241,26 @@ (calculate-modifiers state false false modif-tree)) ([state ignore-constraints ignore-snap-pixel modif-tree] + (calculate-modifiers state ignore-constraints ignore-snap-pixel modif-tree nil)) + + ([state ignore-constraints ignore-snap-pixel modif-tree params] (let [objects (wsh/lookup-page-objects state) snap-pixel? - (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))] + (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) + + zoom (dm/get-in state [:workspace-local :zoom]) + snap-precision (if (>= zoom zoom-half-pixel-precision) 0.5 1)] (as-> objects $ (apply-text-modifiers $ (get state :workspace-text-modifier)) ;;(apply-path-modifiers $ (get-in state [:workspace-local :edit-path])) - (gsh/set-objects-modifiers modif-tree $ ignore-constraints snap-pixel?))))) + (gsh/set-objects-modifiers modif-tree $ (merge + params + {:ignore-constraints ignore-constraints + :snap-pixel? snap-pixel? + :snap-precision snap-precision})))))) (defn- calculate-update-modifiers [old-modif-tree state ignore-constraints ignore-snap-pixel modif-tree] @@ -259,10 +270,13 @@ snap-pixel? (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) + zoom (dm/get-in state [:workspace-local :zoom]) + + snap-precision (if (>= zoom zoom-half-pixel-precision) 0.5 1) objects (-> objects (apply-text-modifiers (get state :workspace-text-modifier)))] - (gsh/set-objects-modifiers old-modif-tree modif-tree objects ignore-constraints snap-pixel?))) + (gsh/set-objects-modifiers old-modif-tree modif-tree objects {:ignore-constraints ignore-constraints :snap-pixel? snap-pixel? :snap-precision snap-precision}))) (defn update-modifiers ([modif-tree] @@ -285,10 +299,13 @@ (set-modifiers modif-tree ignore-constraints false)) ([modif-tree ignore-constraints ignore-snap-pixel] + (set-modifiers modif-tree ignore-constraints ignore-snap-pixel nil)) + + ([modif-tree ignore-constraints ignore-snap-pixel params] (ptk/reify ::set-modifiers ptk/UpdateEvent (update [_ state] - (assoc state :workspace-modifiers (calculate-modifiers state ignore-constraints ignore-snap-pixel modif-tree)))))) + (assoc state :workspace-modifiers (calculate-modifiers state ignore-constraints ignore-snap-pixel modif-tree params)))))) ;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints). (defn set-rotation-modifiers @@ -312,7 +329,7 @@ modif-tree (-> (build-modif-tree ids objects get-modifier) - (gsh/set-objects-modifiers objects false false))] + (gsh/set-objects-modifiers objects))] (assoc state :workspace-modifiers modif-tree)))))) diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index fddb6c914..307c6e290 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -8,7 +8,6 @@ (:require [app.common.geom.point :as gpt] [app.common.geom.shapes.flex-layout :as gsl] - [app.common.geom.shapes.path :as upg] [app.common.path.commands :as upc] [app.common.path.shapes-to-path :as upsp] [app.common.spec :as us] @@ -125,14 +124,11 @@ (ptk/reify ::close-path-drag-start ptk/WatchEvent (watch [_ state stream] - (let [id (st/get-path-id state) - stop-stream + (let [stop-stream (->> stream (rx/filter #(or (helpers/end-path-event? %) (ms/mouse-up? %)))) content (st/get-path state :content) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) - points (upg/content->points content) handlers (-> (upc/content->handlers content) (get position)) @@ -141,7 +137,7 @@ (first handlers)) drag-events-stream - (->> (streams/position-stream snap-toggled points) + (->> (streams/position-stream) (rx/take-until stop-stream) (rx/map #(drag-handler position idx prefix %)))] @@ -164,16 +160,10 @@ (defn start-path-from-point [position] (ptk/reify ::start-path-from-point ptk/WatchEvent - (watch [_ state stream] + (watch [_ _ stream] (let [mouse-up (->> stream (rx/filter #(or (helpers/end-path-event? %) (ms/mouse-up? %)))) - content (st/get-path state :content) - points (upg/content->points content) - - id (st/get-path-id state) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) - - drag-events (->> (streams/position-stream snap-toggled points) + drag-events (->> (streams/position-stream) (rx/take-until mouse-up) (rx/map #(drag-handler %)))] @@ -192,11 +182,11 @@ (rx/merge-map #(rx/empty)))) (defn make-drag-stream - [stream snap-toggled _zoom points down-event] + [stream down-event] (let [mouse-up (->> stream (rx/filter #(or (helpers/end-path-event? %) (ms/mouse-up? %)))) - drag-events (->> (streams/position-stream snap-toggled points) + drag-events (->> (streams/position-stream) (rx/take-until mouse-up) (rx/map #(drag-handler %)))] @@ -217,20 +207,13 @@ (assoc-in [:workspace-local :edit-path id :edit-mode] :draw)))) ptk/WatchEvent - (watch [_ state stream] - (let [zoom (get-in state [:workspace-local :zoom]) - mouse-down (->> stream (rx/filter ms/mouse-down?)) + (watch [_ _ stream] + (let [mouse-down (->> stream (rx/filter ms/mouse-down?)) end-path-events (->> stream (rx/filter helpers/end-path-event?)) - content (st/get-path state :content) - points (upg/content->points content) - - id (st/get-path-id state) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) - ;; Mouse move preview mousemove-events - (->> (streams/position-stream snap-toggled points) + (->> (streams/position-stream) (rx/take-until end-path-events) (rx/map #(preview-next-point %))) @@ -238,12 +221,12 @@ mousedown-events (->> mouse-down (rx/take-until end-path-events) - (rx/with-latest merge (streams/position-stream snap-toggled points)) + (rx/with-latest merge (streams/position-stream)) ;; We change to the stream that emits the first event (rx/switch-map #(rx/race (make-node-events-stream stream) - (make-drag-stream stream snap-toggled zoom points %))))] + (make-drag-stream stream %))))] (rx/concat (rx/of (undo/start-path-undo)) @@ -279,11 +262,14 @@ state))) ptk/WatchEvent - (watch [_ _ _] - (rx/of (setup-frame-path) - (dwdc/handle-finish-drawing) - (dwe/start-edition-mode shape-id) - (change-edit-mode :draw))))) + (watch [_ state _] + (let [content (get-in state [:workspace-drawing :object :content] [])] + (if (seq content) + (rx/of (setup-frame-path) + (dwdc/handle-finish-drawing) + (dwe/start-edition-mode shape-id) + (change-edit-mode :draw)) + (rx/of (dwdc/handle-finish-drawing))))))) (defn handle-new-shape "Creates a new path shape" @@ -293,7 +279,7 @@ (update [_ state] (let [id (st/get-path-id state)] (-> state - (assoc-in [:workspace-local :edit-path id :snap-toggled] true)))) + (assoc-in [:workspace-local :edit-path id :snap-toggled] false)))) ptk/WatchEvent (watch [_ state stream] diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index b8712111b..318f1dbf3 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -7,6 +7,7 @@ (ns app.main.data.workspace.path.edition (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as upg] [app.common.path.commands :as upc] @@ -35,8 +36,8 @@ (let [content (st/get-path state :content) modifiers (helpers/move-handler-modifiers content index prefix false match-opposite? dx dy) [cx cy] (if (= prefix :c1) [:c1x :c1y] [:c2x :c2y]) - point (gpt/point (+ (get-in content [index :params cx]) dx) - (+ (get-in content [index :params cy]) dy))] + point (gpt/point (+ (dm/get-in content [index :params cx]) dx) + (+ (dm/get-in content [index :params cy]) dy))] (-> state (update-in [:workspace-local :edit-path id :content-modifiers] merge modifiers) @@ -51,7 +52,7 @@ id (st/get-path-id state) page-id (:current-page-id state) shape (st/get-path state) - content-modifiers (get-in state [:workspace-local :edit-path id :content-modifiers]) + content-modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers]) content (:content shape) new-content (upc/apply-content-modifiers content content-modifiers) @@ -98,7 +99,7 @@ (let [id (st/get-path-id state) content (st/get-path state :content) modifiers-reducer (partial modify-content-point content move-modifier) - content-modifiers (get-in state [:workspace-local :edit-path id :content-modifiers] {}) + content-modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers] {}) content-modifiers (->> points (reduce modifiers-reducer content-modifiers))] @@ -115,9 +116,9 @@ modifiers-reducer (partial modify-content-point content delta) - points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) - modifiers (get-in state [:workspace-local :edit-path id :content-modifiers] {}) + modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers] {}) modifiers (->> points (reduce modifiers-reducer modifiers))] @@ -132,8 +133,8 @@ (ptk/reify ::start-move-path-point ptk/WatchEvent (watch [_ state _] - (let [id (get-in state [:workspace-local :edition]) - selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + (let [id (dm/get-in state [:workspace-local :edition]) + selected-points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) selected? (contains? selected-points position)] (streams/drag-stream (rx/of @@ -148,10 +149,9 @@ ptk/WatchEvent (watch [_ state stream] (let [stopper (->> stream (rx/filter ms/mouse-up?)) - id (get-in state [:workspace-local :edition]) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) + id (dm/get-in state [:workspace-local :edition]) - selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + selected-points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) content (st/get-path state :content) points (upg/content->points content)] @@ -159,7 +159,7 @@ (rx/concat ;; This stream checks the consecutive mouse positions to do the dragging (->> points - (streams/move-points-stream snap-toggled start-position selected-points) + (streams/move-points-stream start-position selected-points) (rx/map #(move-selected-path-point start-position %)) (rx/take-until stopper)) (rx/of (apply-content-modifiers))))))) @@ -178,7 +178,7 @@ (ptk/reify ::finish-move-selected ptk/UpdateEvent (update [_ state] - (let [id (get-in state [:workspace-local :edition])] + (let [id (dm/get-in state [:workspace-local :edition])] (-> state (update-in [:workspace-local :edit-path id] dissoc :current-move)))))) @@ -192,8 +192,8 @@ ptk/UpdateEvent (update [_ state] - (let [id (get-in state [:workspace-local :edition]) - current-move (get-in state [:workspace-local :edit-path id :current-move])] + (let [id (dm/get-in state [:workspace-local :edition]) + current-move (dm/get-in state [:workspace-local :edit-path id :current-move])] (if (nil? current-move) (-> state (assoc-in [:workspace-local :edit-path id :moving-nodes] true) @@ -202,11 +202,11 @@ ptk/WatchEvent (watch [_ state stream] - (let [id (get-in state [:workspace-local :edition]) - current-move (get-in state [:workspace-local :edit-path id :current-move])] + (let [id (dm/get-in state [:workspace-local :edition]) + current-move (dm/get-in state [:workspace-local :edit-path id :current-move])] ;; id can be null if we just selected the tool but we didn't start drawing (if (and id (= same-event current-move)) - (let [points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + (let [points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) move-events (->> stream (rx/filter (ptk/type? ::move-selected)) @@ -238,13 +238,13 @@ (ptk/reify ::start-move-handler ptk/WatchEvent (watch [_ state stream] - (let [id (get-in state [:workspace-local :edition]) + (let [id (dm/get-in state [:workspace-local :edition]) cx (d/prefix-keyword prefix :x) cy (d/prefix-keyword prefix :y) start-point @ms/mouse-position - modifiers (get-in state [:workspace-local :edit-path id :content-modifiers]) - start-delta-x (get-in modifiers [index cx] 0) - start-delta-y (get-in modifiers [index cy] 0) + modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers]) + start-delta-x (dm/get-in modifiers [index cx] 0) + start-delta-y (dm/get-in modifiers [index cy] 0) content (st/get-path state :content) points (upg/content->points content) @@ -253,14 +253,12 @@ handler (-> content (get index) (upc/get-handler prefix)) [op-idx op-prefix] (upc/opposite-index content index prefix) - opposite (upc/handler->point content op-idx op-prefix) - - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled])] + opposite (upc/handler->point content op-idx op-prefix)] (streams/drag-stream (rx/concat (rx/of (dch/update-shapes [id] upsp/convert-to-path)) - (->> (streams/move-handler-stream snap-toggled start-point point handler opposite points) + (->> (streams/move-handler-stream start-point point handler opposite points) (rx/take-until (->> stream (rx/filter #(or (ms/mouse-up? %) (streams/finish-edition? %))))) (rx/map @@ -283,21 +281,21 @@ (ptk/reify ::start-path-edit ptk/UpdateEvent (update [_ state] - (let [edit-path (get-in state [:workspace-local :edit-path id]) + (let [edit-path (dm/get-in state [:workspace-local :edit-path id]) content (st/get-path state :content) state (st/set-content state (ups/close-subpaths content))] (cond-> state (or (not edit-path) (= :draw (:edit-mode edit-path))) (assoc-in [:workspace-local :edit-path id] {:edit-mode :move :selected #{} - :snap-toggled true}) + :snap-toggled false}) (and (some? edit-path) (= :move (:edit-mode edit-path))) (assoc-in [:workspace-local :edit-path id :edit-mode] :draw)))) ptk/WatchEvent (watch [_ state stream] - (let [mode (get-in state [:workspace-local :edit-path id :edit-mode]) + (let [mode (dm/get-in state [:workspace-local :edit-path id :edit-mode]) stopper (->> stream (rx/filter #(or (= (ptk/type %) ::dwe/clear-edition-mode) diff --git a/frontend/src/app/main/data/workspace/path/streams.cljs b/frontend/src/app/main/data/workspace/path/streams.cljs index db1a09464..071e6ab12 100644 --- a/frontend/src/app/main/data/workspace/path/streams.cljs +++ b/frontend/src/app/main/data/workspace/path/streams.cljs @@ -6,9 +6,11 @@ (ns app.main.data.workspace.path.streams (:require + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as upg] - [app.main.data.workspace.path.state :as state] + [app.main.constants :refer [zoom-half-pixel-precision]] + [app.main.data.workspace.path.state :as pst] [app.main.snap :as snap] [app.main.store :as st] [app.main.streams :as ms] @@ -17,7 +19,6 @@ [potok.core :as ptk])) (defonce drag-threshold 5) -(def zoom-half-pixel-precision 8) (defn dragging? [start zoom] (fn [current] @@ -36,7 +37,7 @@ position (>= zoom zoom-half-pixel-precision) - (gpt/half-round position) + (gpt/round-step position 0.5) :else (gpt/round position)))) @@ -71,15 +72,23 @@ (->> position-stream (rx/merge-map (fn [] to-stream))))))) +(defn snap-toggled-stream + [] + (let [get-snap (fn [state] + (let [id (pst/get-path-id state)] + (dm/get-in state [:workspace-local :edit-path id :snap-toggled])))] + (-> (l/derived get-snap st/state) + (rx/from-atom {:emit-current-value? true})))) + (defn move-points-stream - [snap-toggled start-point selected-points points] + [start-point selected-points points] (let [zoom (get-in @st/state [:workspace-local :zoom] 1) ranges (snap/create-ranges points selected-points) d-pos (/ snap/snap-path-accuracy zoom) check-path-snap - (fn [position] + (fn [[position snap-toggled]] (if snap-toggled (let [delta (gpt/subtract position start-point) moved-points (->> selected-points (mapv #(gpt/add % delta))) @@ -88,6 +97,7 @@ position))] (->> ms/mouse-position (rx/map to-pixel-snap) + (rx/with-latest-from (snap-toggled-stream)) (rx/map check-path-snap)))) (defn get-angle [node handler opposite] @@ -99,7 +109,7 @@ [rot-angle rot-sign]))) (defn move-handler-stream - [snap-toggled start-point node handler opposite points] + [start-point node handler opposite points] (let [zoom (get-in @st/state [:workspace-local :zoom] 1) ranges (snap/create-ranges points) @@ -108,7 +118,7 @@ [initial-angle] (get-angle node handler opposite) check-path-snap - (fn [position] + (fn [[position snap-toggled]] (if snap-toggled (let [delta (gpt/subtract position start-point) handler (gpt/add handler delta) @@ -134,13 +144,14 @@ (rx/map to-pixel-snap) (rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %)))) (rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %)))) + (rx/with-latest-from (snap-toggled-stream)) (rx/map check-path-snap)))) (defn position-stream - [snap-toggled _points] + [] (let [zoom (get-in @st/state [:workspace-local :zoom] 1) d-pos (/ snap/snap-path-accuracy zoom) - get-content #(state/get-path % :content) + get-content #(pst/get-path % :content) content-stream (-> (l/derived get-content st/state) @@ -154,7 +165,8 @@ (->> ms/mouse-position (rx/map to-pixel-snap) (rx/with-latest vector ranges-stream) - (rx/map (fn [[position ranges]] + (rx/with-latest-from (snap-toggled-stream)) + (rx/map (fn [[[position ranges] snap-toggled]] (if snap-toggled (let [snap (snap/get-snap-delta [position] ranges d-pos)] (gpt/add position snap)) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 5a31013a0..500c75652 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -327,8 +327,7 @@ (defn- prepare-duplicate-frame-change [changes objects page unames update-unames! ids-map obj delta] (let [new-id (ids-map (:id obj)) - frame-name (ctt/generate-unique-name @unames (:name obj)) - _ (update-unames! frame-name) + frame-name (:name obj) new-frame (-> obj (assoc :id new-id @@ -361,8 +360,7 @@ (if (some? obj) (let [new-id (ids-map (:id obj)) parent-id (or parent-id frame-id) - name (ctt/generate-unique-name @unames (:name obj)) - _ (update-unames! name) + name (:name obj) new-obj (-> obj (assoc :id new-id diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index e7a3427f3..fcf8f4dbf 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -12,6 +12,7 @@ [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.common.pages.helpers :as cph] + [app.common.types.component :as ctc] [app.common.types.modifiers :as ctm] [app.common.types.shape-tree :as ctt] [app.common.types.shape.layout :as ctl] @@ -153,18 +154,23 @@ selected-shapes (map (d/getf objects) selected) single? (= (count selected-shapes) 1) has-group? (->> selected-shapes (d/seek cph/group-shape?)) - is-group? (and single? has-group?)] + is-group? (and single? has-group?) + has-mask? (->> selected-shapes (d/seek cph/mask-shape?)) + is-mask? (and single? has-mask?) + has-component? (some true? (map ctc/instance-root? selected-shapes)) + is-component? (and single? has-component?)] - (if is-group? + (if (and (not is-component?) is-group? (not is-mask?)) (let [new-shape-id (uuid/next) parent-id (:parent-id (first selected-shapes)) shapes-ids (:shapes (first selected-shapes)) ordered-ids (into (d/ordered-set) shapes-ids) - undo-id (js/Symbol)] + undo-id (js/Symbol) + group-index (cph/get-index-replacement selected objects)] (rx/of (dwu/start-undo-transaction undo-id) (dwse/select-shapes ordered-ids) - (dws/create-artboard-from-selection new-shape-id parent-id) + (dws/create-artboard-from-selection new-shape-id parent-id group-index) (cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1}) (create-layout-from-id [new-shape-id] type) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 4bba01db8..a8551942d 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -87,9 +87,7 @@ selected (wsh/lookup-selected state) id (or (:id attrs) (uuid/next)) - name (-> objects - (ctst/retrieve-used-names) - (ctst/generate-unique-name (:name attrs))) + name (:name attrs) shape (make-new-shape (assoc attrs :id id :name name) @@ -361,6 +359,8 @@ ([id] (create-artboard-from-selection id nil)) ([id parent-id] + (create-artboard-from-selection id parent-id nil)) + ([id parent-id index] (ptk/reify ::create-artboard-from-selection ptk/WatchEvent (watch [_ state _] @@ -369,11 +369,8 @@ selected (wsh/lookup-selected state) selected (cph/clean-loops objects selected) selected-objs (map #(get objects %) selected) - new-index (->> selected - (cph/order-by-indexed-shapes objects) - first - (cph/get-position-on-parent objects) - inc)] + new-index (or index + (cph/get-index-replacement selected objects))] (when (d/not-empty? selected) (let [srect (gsh/selection-rect selected-objs) frame-id (get-in objects [(first selected) :frame-id]) diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index f299fa8d6..096bd0464 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -11,6 +11,7 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] + [app.common.math :as mth] [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] [app.common.spec :as us :refer [max-safe-int min-safe-int]] @@ -21,6 +22,7 @@ [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.workspace.undo :as dwu] [app.main.repo :as rp] [app.util.color :as uc] [app.util.path.parser :as upp] @@ -361,7 +363,7 @@ (let [{:keys [tag attrs hidden]} element-data attrs (usvg/format-styles attrs) element-data (cond-> element-data (map? element-data) (assoc :attrs attrs)) - name (ctst/generate-unique-name unames (or (:id attrs) (tag->name tag))) + name (or (:id attrs) (tag->name tag)) att-refs (usvg/find-attr-references attrs) references (usvg/find-def-references (:defs svg-data) att-refs) @@ -477,20 +479,21 @@ (rx/reduce (fn [acc [url image]] (assoc acc url image)) {}))) (defn create-svg-shapes - [svg-data {:keys [x y] :as position} objects frame-id parent-id selected center?] + [svg-data {:keys [x y]} objects frame-id parent-id selected center?] (try (let [[vb-x vb-y vb-width vb-height] (svg-dimensions svg-data) - x (if center? - (- x vb-x (/ vb-width 2)) - x) - y (if center? - (- y vb-y (/ vb-height 2)) - y) + x (mth/round + (if center? + (- x vb-x (/ vb-width 2)) + x)) + y (mth/round + (if center? + (- y vb-y (/ vb-height 2)) + y)) unames (ctst/retrieve-used-names objects) - svg-name (->> (str/replace (:name svg-data) ".svg" "") - (ctst/generate-unique-name unames)) + svg-name (str/replace (:name svg-data) ".svg" "") svg-data (-> svg-data (assoc :x x @@ -583,7 +586,11 @@ (filter #(= :add-obj (:type %))) (map :id) reverse - vec))] + vec)) + undo-id (js/Symbol)] - (rx/of (dch/commit-changes changes) - (dws/select-shapes (d/ordered-set (:id new-shape)))))))) + (rx/of (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (dws/select-shapes (d/ordered-set (:id new-shape))) + (ptk/data-event :layout/update [(:id new-shape)]) + (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index be4b7eab6..b98de7713 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -15,7 +15,6 @@ [app.common.pages.helpers :as cph] [app.common.text :as txt] [app.common.types.modifiers :as ctm] - [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.common :as dwc] [app.main.data.workspace.modifiers :as dwm] @@ -318,16 +317,25 @@ (defn not-changed? [old-dim new-dim] (> (mth/abs (- old-dim new-dim)) 1)) -(defn resize-text - [id new-width new-height] - (ptk/reify ::resize-text +(defn commit-resize-text + [] + (ptk/reify ::commit-resize-text ptk/WatchEvent (watch [_ state _] - (let [shape (wsh/lookup-shape state id) + (let [props (::resize-text-debounce-props state) + objects (wsh/lookup-page-objects state) undo-id (js/Symbol)] - (letfn [(update-fn [shape] - (let [{:keys [selrect grow-type]} shape - {shape-width :width shape-height :height} selrect + + (letfn [(changed-text? [id] + (let [shape (get objects id) + [new-width new-height] (get props id)] + (or (and (not-changed? (:width shape) new-width) (= (:grow-type shape) :auto-width)) + (and (not-changed? (:height shape) new-height) + (or (= (:grow-type shape) :auto-height) (= (:grow-type shape) :auto-width)))))) + + (update-fn [{:keys [id selrect grow-type] :as shape}] + (let [{shape-width :width shape-height :height} selrect + [new-width new-height] (get props id) shape (cond-> shape @@ -342,14 +350,39 @@ shape))] - (when (or (and (not-changed? (:width shape) new-width) (= (:grow-type shape) :auto-width)) - (and (not-changed? (:height shape) new-height) - (or (= (:grow-type shape) :auto-height) (= (:grow-type shape) :auto-width)))) + (let [ids (->> (keys props) (filter changed-text?))] (rx/of (dwu/start-undo-transaction undo-id) - (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? true}) - (ptk/data-event :layout/update [id]) + (dch/update-shapes ids update-fn {:reg-objects? true :save-undo? true}) + (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))))) +(defn resize-text + [id new-width new-height] + + (let [cur-event (js/Symbol)] + (ptk/reify ::resize-text + ptk/UpdateEvent + (update [_ state] + (-> state + (update ::resize-text-debounce-props (fnil assoc {}) id [new-width new-height]) + (cond-> (nil? (::resize-text-debounce-event state)) + (assoc ::resize-text-debounce-event cur-event)))) + + ptk/WatchEvent + (watch [_ state stream] + (if (= (::resize-text-debounce-event state) cur-event) + (let [stopper (->> stream (rx/filter (ptk/type? :app.main.data.workspace/finalize)))] + (rx/concat + (rx/merge + (->> stream + (rx/filter (ptk/type? ::resize-text)) + (rx/debounce 50) + (rx/take 1) + (rx/map #(commit-resize-text)) + (rx/take-until stopper)) + (rx/of (resize-text id new-width new-height))) + (rx/of #(dissoc % ::resize-text-debounce-props ::resize-text-debounce-event)))) + (rx/empty)))))) (defn save-font [data] @@ -384,37 +417,43 @@ new-shape)) -(defn update-text-modifier-state - [id props] - (ptk/reify ::update-text-modifier-state - ptk/UpdateEvent - (update [_ state] - (update-in state [:workspace-text-modifier id] (fnil merge {}) props)))) +(defn commit-update-text-modifier + [] + (ptk/reify ::commit-update-text-modifier + ptk/WatchEvent + (watch [_ state _] + (let [ids (::update-text-modifier-debounce-ids state)] + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] + (rx/of (dwm/update-modifiers modif-tree false true))))))) (defn update-text-modifier [id props] - (ptk/reify ::update-text-modifier - ptk/WatchEvent - (watch [_ state _] - (let [modifiers (get-in (:workspace-modifiers state) [id :modifiers]) - shape (-> (wsh/lookup-shape state id) - (gsh/transform-shape modifiers)) + (let [cur-event (js/Symbol)] + (ptk/reify ::update-text-modifier + ptk/UpdateEvent + (update [_ state] + (-> state + (update-in [:workspace-text-modifier id] (fnil merge {}) props) + (update ::update-text-modifier-debounce-ids (fnil conj #{}) id) + (cond-> (nil? (::update-text-modifier-debounce-event state)) + (assoc ::update-text-modifier-debounce-event cur-event)))) - current-width (:width shape) - current-height (:height shape)] - (rx/concat - (rx/of (update-text-modifier-state id props)) - - (if (or (and (some? (:width props)) - (not (mth/close? (:width props) current-width))) - (and (some? (:height props)) - (not (mth/close? (:height props) current-height)))) - - (let [modif-tree (dwm/create-modif-tree [id] (ctm/reflow-modifiers))] - (->> (rx/of (dwm/update-modifiers modif-tree false true)) - (rx/observe-on :async))) - (rx/empty))))))) + ptk/WatchEvent + (watch [_ state stream] + (if (= (::update-text-modifier-debounce-event state) cur-event) + (let [stopper (->> stream (rx/filter (ptk/type? :app.main.data.workspace/finalize)))] + (rx/concat + (rx/merge + (->> stream + (rx/filter (ptk/type? ::update-text-modifier)) + (rx/debounce 50) + (rx/take 1) + (rx/map #(commit-update-text-modifier)) + (rx/take-until stopper)) + (rx/of (update-text-modifier id props))) + (rx/of #(dissoc % ::update-text-modifier-debounce-event ::update-text-modifier-debounce-ids)))) + (rx/empty)))))) (defn clean-text-modifier [id] @@ -464,18 +503,18 @@ (defn update-position-data [id position-data] - (let [start (uuid/next)] + (let [cur-event (js/Symbol)] (ptk/reify ::update-position-data ptk/UpdateEvent (update [_ state] (let [state (assoc-in state [:workspace-text-modifier id :position-data] position-data)] (if (nil? (::update-position-data-debounce state)) - (assoc state ::update-position-data-debounce start) + (assoc state ::update-position-data-debounce cur-event) (assoc-in state [::update-position-data id] position-data)))) ptk/WatchEvent (watch [_ state stream] - (if (= (::update-position-data-debounce state) start) + (if (= (::update-position-data-debounce state) cur-event) (let [stopper (->> stream (rx/filter (ptk/type? :app.main.data.workspace/finalize)))] (rx/merge (->> stream diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs index 63e288f3c..6149fd4d4 100644 --- a/frontend/src/app/main/data/workspace/thumbnails.cljs +++ b/frontend/src/app/main/data/workspace/thumbnails.cljs @@ -85,8 +85,7 @@ (rx/merge ;; Update the local copy of the thumbnails so we don't need to request it again (rx/of #(update % :workspace-thumbnails assoc object-id data)) - (->> (rx/timer 5000) - (rx/flat-map #(rp/cmd! :upsert-file-object-thumbnail params)) + (->> (rp/cmd! :upsert-file-object-thumbnail params) (rx/catch #(rx/empty)) (rx/ignore)))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index ce9798f77..7cda5044a 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -240,14 +240,12 @@ ptk/UpdateEvent (update [_ state] (let [objects (wsh/lookup-page-objects state) - snap-pixel? (and (contains? (:workspace-layout state) :snap-pixel-grid) - (int? value)) get-modifier (fn [shape] (ctm/change-dimensions-modifiers shape attr value)) modif-tree (-> (dwm/build-modif-tree ids objects get-modifier) - (gsh/set-objects-modifiers objects false snap-pixel?))] + (gsh/set-objects-modifiers objects))] (assoc state :workspace-modifiers modif-tree))) @@ -265,14 +263,13 @@ ptk/UpdateEvent (update [_ state] (let [objects (wsh/lookup-page-objects state) - snap-pixel? (contains? (get state :workspace-layout) :snap-pixel-grid) get-modifier (fn [shape] (ctm/change-orientation-modifiers shape orientation)) modif-tree (-> (dwm/build-modif-tree ids objects get-modifier) - (gsh/set-objects-modifiers objects false snap-pixel?))] + (gsh/set-objects-modifiers objects))] (assoc state :workspace-modifiers modif-tree))) @@ -443,21 +440,11 @@ exclude-frames-siblings (into exclude-frames (comp (mapcat (partial cph/get-siblings-ids objects)) - (filter (partial ctl/layout-child-id? objects))) + (filter (partial ctl/layout-immediate-child-id? objects))) selected) - fix-axis - (fn [[position shift?]] - (let [delta (gpt/to-vec from-position position)] - (if shift? - (if (> (mth/abs (:x delta)) (mth/abs (:y delta))) - (gpt/point (:x delta) 0) - (gpt/point 0 (:y delta))) - delta))) - position (->> ms/mouse-position - (rx/with-latest-from ms/mouse-position-shift) - (rx/map #(fix-axis %))) + (rx/map #(gpt/to-vec from-position %))) snap-delta (rx/concat ;; We send the nil first so the stream is not waiting for the first value @@ -494,11 +481,24 @@ (rx/merge ;; Temporary modifiers stream (->> move-stream + (rx/with-latest-from ms/mouse-position-shift) (rx/map - (fn [[move-vector target-frame drop-index]] - (-> (dwm/create-modif-tree ids (ctm/move-modifiers move-vector)) - (dwm/build-change-frame-modifiers objects selected target-frame drop-index) - (dwm/set-modifiers))))) + (fn [[[move-vector target-frame drop-index] shift?]] + (let [x-disp? (> (mth/abs (:x move-vector)) (mth/abs (:y move-vector))) + [move-vector snap-ignore-axis] + (cond + (and shift? x-disp?) + [(assoc move-vector :y 0) :y] + + shift? + [(assoc move-vector :x 0) :x] + + :else + [move-vector nil])] + + (-> (dwm/create-modif-tree ids (ctm/move-modifiers move-vector)) + (dwm/build-change-frame-modifiers objects selected target-frame drop-index) + (dwm/set-modifiers false false {:snap-ignore-axis snap-ignore-axis})))))) (->> move-stream (rx/map (comp set-ghost-displacement first))) @@ -623,7 +623,7 @@ (->> move-events (rx/scan #(gpt/add %1 mov-vec) (gpt/point 0 0)) (rx/map #(dwm/create-modif-tree selected (ctm/move-modifiers %))) - (rx/map (partial dwm/set-modifiers)) + (rx/map #(dwm/set-modifiers % false true)) (rx/take-until stopper)) (rx/of (nudge-selected-shapes direction shift?))) @@ -643,7 +643,7 @@ (let [objects (wsh/lookup-page-objects state) selected (wsh/lookup-selected state {:omit-blocked? true}) selected-shapes (->> selected (map (d/getf objects)))] - (if (every? (partial ctl/layout-child? objects) selected-shapes) + (if (every? (partial ctl/layout-immediate-child? objects) selected-shapes) (rx/of (reorder-selected-layout-child direction)) (rx/of (nudge-selected-shapes direction shift?))))))) @@ -669,11 +669,12 @@ cpos (gpt/point (:x bbox) (:y bbox)) pos (gpt/point (or (:x position) (:x bbox)) (or (:y position) (:y bbox))) + delta (gpt/subtract pos cpos) modif-tree (dwm/create-modif-tree [id] (ctm/move-modifiers delta))] - (rx/of (dwm/set-modifiers modif-tree) + (rx/of (dwm/set-modifiers modif-tree false true) (dwm/apply-modifiers)))))) (defn- move-shapes-to-frame @@ -688,7 +689,6 @@ shapes (->> ids (cph/clean-loops objects) (keep lookup)) - moving-shapes (cond->> shapes (not layout?) @@ -753,36 +753,22 @@ (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/selection-rect shapes) - origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2))) - - modif-tree (dwm/create-modif-tree - selected - (-> (ctm/empty) - (ctm/resize (gpt/point -1.0 1.0) origin) - (ctm/move (gpt/point (:width selrect) 0))))] - - (rx/of (dwm/set-modifiers modif-tree true) - (dwm/apply-modifiers)))))) + (let [objects (wsh/lookup-page-objects state) + selected (wsh/lookup-selected state {:omit-blocked? true}) + shapes (map #(get objects %) selected) + selrect (gsh/selection-rect shapes) + center (gsh/center-selrect selrect) + modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point -1.0 1.0) center))] + (rx/of (dwm/apply-modifiers {:modifiers modifiers})))))) (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/selection-rect shapes) - origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect)) - - modif-tree (dwm/create-modif-tree - selected - (-> (ctm/empty) - (ctm/resize (gpt/point 1.0 -1.0) origin) - (ctm/move (gpt/point 0 (:height selrect)))))] - - (rx/of (dwm/set-modifiers modif-tree true) - (dwm/apply-modifiers)))))) + (let [objects (wsh/lookup-page-objects state) + selected (wsh/lookup-selected state {:omit-blocked? true}) + shapes (map #(get objects %) selected) + selrect (gsh/selection-rect shapes) + center (gsh/center-selrect selrect) + modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point 1.0 -1.0) center))] + (rx/of (dwm/apply-modifiers {:modifiers modifiers})))))) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 51a0becaa..262aa8139 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -402,7 +402,7 @@ (let [objects (wsh/lookup-page-objects state)] (into [] (comp (map (d/getf objects)) - (filter (partial ctl/layout-child? objects))) + (filter (partial ctl/layout-immediate-child? objects))) ids))) st/state =)) @@ -481,7 +481,7 @@ (fn [objects] (->> ids (map (d/getf objects)) - (some (partial ctl/layout-child? objects)))) + (some (partial ctl/layout-immediate-child? objects)))) workspace-page-objects)) (defn get-flex-child-viewer @@ -491,7 +491,7 @@ (let [objects (wsh/lookup-viewer-objects state page-id)] (into [] (comp (map (d/getf objects)) - (filter (partial ctl/layout-child? objects))) + (filter (partial ctl/layout-immediate-child? objects))) ids))) st/state =)) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index d1b9c0ff7..b1953c6f4 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -292,34 +292,37 @@ ;; used to render thumbnails on assets panel. (mf/defc component-svg {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]} - [{:keys [objects group zoom] :or {zoom 1} :as props}] - (let [group-id (:id group) + [{:keys [objects root-shape zoom] :or {zoom 1} :as props}] + (let [root-shape-id (:id root-shape) include-metadata? (mf/use-ctx export/include-metadata-ctx) vector (mf/use-memo - (mf/deps (:x group) (:y group)) + (mf/deps (:x root-shape) (:y root-shape)) (fn [] - (-> (gpt/point (:x group) (:y group)) + (-> (gpt/point (:x root-shape) (:y root-shape)) (gpt/negate)))) objects (mf/use-memo - (mf/deps vector objects group-id) + (mf/deps vector objects root-shape-id) (fn [] - (let [children-ids (cons group-id (cph/get-children-ids objects group-id)) + (let [children-ids (cons root-shape-id (cph/get-children-ids objects root-shape-id)) update-fn #(update %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] (reduce update-fn objects children-ids)))) - group (get objects group-id) - width (* (:width group) zoom) - height (* (:height group) zoom) - vbox (format-viewbox {:width (:width group 0) - :height (:height group 0)}) - group-wrapper + root-shape (get objects root-shape-id) + width (* (:width root-shape) zoom) + height (* (:height root-shape) zoom) + vbox (format-viewbox {:width (:width root-shape 0) + :height (:height root-shape 0)}) + root-shape-wrapper (mf/use-memo - (mf/deps objects) - (fn [] (group-wrapper-factory objects)))] + (mf/deps objects root-shape) + (fn [] + (case (:type root-shape) + :group (group-wrapper-factory objects) + :frame (frame-wrapper-factory objects))))] [:svg {:view-box vbox :width (ust/format-precision width viewbox-decimal-precision) @@ -330,8 +333,8 @@ :xmlns:penpot (when include-metadata? "https://penpot.app/xmlns") :fill "none"} - [:> shape-container {:shape group} - [:& group-wrapper {:shape group :view-box vbox}]]])) + [:> shape-container {:shape root-shape} + [:& root-shape-wrapper {:shape root-shape :view-box vbox}]]])) (mf/defc object-svg {::mf/wrap [mf/memo]} @@ -375,12 +378,12 @@ (mf/defc component-symbol [{:keys [id data] :as props}] - (let [name (:name data) - path (:path data) - objects (-> (:objects data) - (adapt-objects-for-shape id)) - object (get objects id) - selrect (:selrect object) + (let [name (:name data) + path (:path data) + objects (-> (:objects data) + (adapt-objects-for-shape id)) + root-shape (get objects id) + selrect (:selrect root-shape) main-instance-id (:main-instance-id data) main-instance-page (:main-instance-page data) @@ -394,8 +397,11 @@ group-wrapper (mf/use-memo - (mf/deps objects) - (fn [] (group-wrapper-factory objects)))] + (mf/deps objects root-shape) + (fn [] + (case (:type root-shape) + :group (group-wrapper-factory objects) + :frame (frame-wrapper-factory objects))))] [:> "symbol" #js {:id (str id) :viewBox vbox @@ -405,8 +411,8 @@ "penpot:main-instance-x" main-instance-x "penpot:main-instance-y" main-instance-y} [:title name] - [:> shape-container {:shape object} - [:& group-wrapper {:shape object :view-box vbox}]]])) + [:> shape-container {:shape root-shape} + [:& group-wrapper {:shape root-shape :view-box vbox}]]])) (mf/defc components-sprite-svg {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/components/editable_select.cljs b/frontend/src/app/main/ui/components/editable_select.cljs index 4c1b0d6ed..32c43aff2 100644 --- a/frontend/src/app/main/ui/components/editable_select.cljs +++ b/frontend/src/app/main/ui/components/editable_select.cljs @@ -172,5 +172,5 @@ {:key (str (:id @state) "-" index) :class (when (= (str value) (-> @state :current-value)) "is-selected") :on-click (select-item value)} - [:span.checked-element-value label] - [:span.check-icon i/tick]])))]]])) + [:span.check-icon i/tick] + [:span.checked-element-value label]])))]]])) diff --git a/frontend/src/app/main/ui/formats.cljs b/frontend/src/app/main/ui/formats.cljs index 8bbeca1f9..f972bda81 100644 --- a/frontend/src/app/main/ui/formats.cljs +++ b/frontend/src/app/main/ui/formats.cljs @@ -52,7 +52,7 @@ {:p1 p1} (= 4 (count (set values))) - {:p1 p1 :p2 p2 :p3 p3} + {:p1 p1 :p2 p2 :p3 p3 :p4 p4} (and (= p1 p3) (= p2 p4)) {:p1 p1 :p3 p3} diff --git a/frontend/src/app/main/ui/viewer/inspect.cljs b/frontend/src/app/main/ui/viewer/inspect.cljs index 2f2353acd..8f78cc5bc 100644 --- a/frontend/src/app/main/ui/viewer/inspect.cljs +++ b/frontend/src/app/main/ui/viewer/inspect.cljs @@ -36,7 +36,8 @@ (mf/defc viewport [{:keys [local file page frame index viewer-pagination size]}] - (let [on-mouse-wheel + (let [inspect-svg-container-ref (mf/use-ref nil) + on-mouse-wheel (fn [event] (when (kbd/mod? event) (dom/prevent-default event) @@ -45,14 +46,30 @@ (.-deltaX ^js event))] (if (pos? delta) (st/emit! dv/decrease-zoom) - (st/emit! dv/increase-zoom))))) + (st/emit! dv/increase-zoom)))) + (when-not (kbd/mod? event) + (let [event (.getBrowserEvent ^js event) + shift? (kbd/shift? event) + inspect-svg-container (mf/ref-val inspect-svg-container-ref) + delta (+ (.-deltaY ^js event) + (.-deltaX ^js event)) + scroll-pos (if shift? + (dom/get-h-scroll-pos inspect-svg-container) + (dom/get-scroll-pos inspect-svg-container)) + new-scroll-pos (+ scroll-pos delta)] + (do + (dom/prevent-default event) + (dom/stop-propagation event) + (if shift? + (dom/set-h-scroll-pos! inspect-svg-container new-scroll-pos) + (dom/set-scroll-pos! inspect-svg-container new-scroll-pos)))))) on-mount (fn [] ;; bind with passive=false to allow the event to be cancelled ;; https://stackoverflow.com/a/57582286/3219895 (let [key1 (events/listen goog/global EventType.WHEEL - on-mouse-wheel #js {"passive" false})] + on-mouse-wheel #js {"passive" false "capture" true})] (fn [] (events/unlistenByKey key1))))] @@ -69,7 +86,7 @@ :page page}] [:div.inspect-svg-wrapper {:on-click (handle-select-frame frame)} [:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}] - [:div.inspect-svg-container + [:div.inspect-svg-container {:ref inspect-svg-container-ref} [:& render-frame-svg {:frame frame :page page :local local :size size}]]] [:& right-sidebar {:frame frame diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/layout_flex.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/layout_flex.cljs index d7a89682e..1cc404df8 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/layout_flex.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/layout_flex.cljs @@ -68,6 +68,7 @@ [{:keys [padding type]}] (let [values (fm/format-padding-margin-shorthand (vals padding))] [:div.attributes-value + {:title (str (str/join "px " (vals values)) "px")} (for [[k v] values] [:span.items {:key (str type "-" k "-" v)} v "px"])])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 6fd51c630..3f6f3a72b 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -88,9 +88,44 @@ on-select-library-color (mf/use-fn - (fn [color] - (st/emit! (dc/update-colorpicker color)) - (on-change color))) + (fn [state color] + (let [type-origin (:type state) + editig-stop-origin (:editing-stop state) + is-gradient? (some? (:gradient color)) + change-to (fn [new-color] + (st/emit! (dc/update-colorpicker new-color)) + (on-change new-color)) + clean-stop (fn [stops index color] + (-> (nth stops index) + (merge color) + (assoc :offset index) + (dissoc :r) + (dissoc :g) + (dissoc :b) + (dissoc :alpha) + (dissoc :s) + (dissoc :h) + (dissoc :v) + (dissoc :hex))) + set-new-gradient (fn [state color index] + (let [old-stops (:stops state) + old-gradient (:gradient state) + new-gradient (-> old-gradient + (cond-> (= index 0) (assoc :stops [(clean-stop old-stops 0 color) (nth old-stops 1)])) + (cond-> (= index 1) (assoc :stops [(nth old-stops 0) (clean-stop old-stops 1 color)])) + (dissoc :shape-id))] + (change-to {:gradient new-gradient})))] + ;; If we have any kind of gradient and: + ;; Click on a solid color -> This color is applied to the selected offset + ;; Click on a color with transparency -> The same to solid color will happend + ;; Click on any kind of gradient -> The color changes completly to new gradient + + ;; If we have a non gradient color the new color is applied without any change + (if (or (= :radial-gradient type-origin) (= :linear-gradient type-origin)) + (if is-gradient? + (change-to color) + (set-new-gradient state color editig-stop-origin)) + (change-to color))))) on-add-library-color (mf/use-fn @@ -230,7 +265,8 @@ :on-change handle-change-color}] [:& libraries - {:current-color current-color + {:state state + :current-color current-color :disable-gradient disable-gradient :disable-opacity disable-opacity :on-select-color on-select-library-color diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index 7a10381ca..f5612f3fc 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -7,18 +7,22 @@ (ns app.main.ui.workspace.colorpicker.libraries (:require [app.common.data.macros :as dm] + [app.main.data.events :as ev] + [app.main.data.workspace :as dw] [app.main.data.workspace.colors :as mdc] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.color-bullet :refer [color-bullet]] [app.main.ui.hooks :as h] + [app.main.ui.hooks.resize :as r] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] + [app.util.timers :as ts] [rumext.v2 :as mf])) (mf/defc libraries - [{:keys [on-select-color on-add-library-color disable-gradient disable-opacity]}] + [{:keys [state on-select-color on-add-library-color disable-gradient disable-opacity]}] (let [selected (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent) current-colors (mf/use-state []) @@ -81,11 +85,16 @@ i/plus]) [:div.color-bullet.button {:style {:background-color "var(--color-white)"} - :on-click #(st/emit! (mdc/show-palette @selected))} + :on-click(fn [] + (r/set-resize-type! :bottom) + (dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down") + (ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette) + (-> (dw/toggle-layout-flag :colorpalette) + (vary-meta assoc ::ev/origin "workspace-colorpicker")))))} i/palette] (for [[idx color] (map-indexed vector @current-colors)] [:& color-bullet {:key (dm/str "color-" idx) :color color - :on-click on-select-color}])]])) + :on-click (partial on-select-color state)}])]])) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index d80eba18a..9fc5c2a06 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.pages.helpers :as cph] + [app.common.types.component :as ctk] [app.common.types.components-list :as ctkl] [app.common.types.file :as ctf] [app.common.types.page :as ctp] @@ -372,27 +373,25 @@ has-frame? (->> shapes (d/seek cph/frame-shape?)) is-frame? (and single? has-frame?) is-flex-container? (and is-frame? (= :flex (:layout (first shapes)))) - has-group? (->> shapes (d/seek cph/group-shape?)) - is-group? (and single? has-group?) ids (->> shapes (map :id)) add-flex #(st/emit! (if is-frame? (dwsl/create-layout-from-id ids :flex) (dwsl/create-layout-from-selection :flex))) remove-flex #(st/emit! (dwsl/remove-layout ids))] - (cond - (or single? (and is-frame? (not is-flex-container?)) is-group?) - [:* - [:& menu-separator] - [:& menu-entry {:title (tr "workspace.shape.menu.add-flex") - :shortcut (sc/get-tooltip :toggle-layout-flex) - :on-click add-flex}]] - is-flex-container? - [:* - [:& menu-separator] - [:& menu-entry {:title (tr "workspace.shape.menu.remove-flex") - :shortcut (sc/get-tooltip :toggle-layout-flex) - :on-click remove-flex}]]))) + [:* + (when (not is-flex-container?) + [:div + [:& menu-separator] + [:& menu-entry {:title (tr "workspace.shape.menu.add-flex") + :shortcut (sc/get-tooltip :toggle-layout-flex) + :on-click add-flex}]]) + (when is-flex-container? + [:div + [:& menu-separator] + [:& menu-entry {:title (tr "workspace.shape.menu.remove-flex") + :shortcut (sc/get-tooltip :toggle-layout-flex) + :on-click remove-flex}]])])) (mf/defc context-menu-component [{:keys [shapes]}] @@ -400,6 +399,7 @@ has-component? (some true? (map #(contains? % :component-id) shapes)) is-component? (and single? (-> shapes first :component-id some?)) + is-non-root? (and single? (ctk/in-component-instance-not-root? (first shapes))) shape-id (-> shapes first :id) component-id (-> shapes first :component-id) @@ -454,10 +454,12 @@ :on-accept do-update-component-in-bulk}))] [:* [:* - [:& menu-separator] - [:& menu-entry {:title (tr "workspace.shape.menu.create-component") - :shortcut (sc/get-tooltip :create-component) - :on-click do-add-component}] + (when (or (not is-non-root?) (and has-component? (not single?))) + [:& menu-separator]) + (when-not is-non-root? + [:& menu-entry {:title (tr "workspace.shape.menu.create-component") + :shortcut (sc/get-tooltip :create-component) + :on-click do-add-component}]) (when (and has-component? (not single?)) [:* [:& menu-entry {:title (tr "workspace.shape.menu.detach-instances-in-bulk") @@ -470,7 +472,6 @@ ;; WARNING: this menu is the same as the context menu at the sidebar. ;; If you change it, you must change equally the file ;; app/main/ui/workspace/sidebar/options/menus/component.cljs - [:* [:& menu-separator] (if main-component? diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 84a023e7b..2c849e422 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -11,6 +11,7 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] + [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm] [app.main.store :as st] [app.main.ui.hooks :as hooks] @@ -30,14 +31,14 @@ (defn get-nodes "Retrieve the DOM nodes to apply the matrix transformation" - [base-node {:keys [id type masked-group?] :as shape}] + [base-node {:keys [id parent-id] :as shape}] (when (some? base-node) - (let [shape-node (get-shape-node base-node id) - - frame? (= :frame type) - group? (= :group type) - text? (= :text type) - mask? (and group? masked-group?)] + (let [shape-node (get-shape-node base-node id) + parent-node (get-shape-node base-node parent-id) + frame? (cph/frame-shape? shape) + group? (cph/group-shape? shape) + text? (cph/text-shape? shape) + masking-child? (:masking-child? (meta shape))] (cond frame? [shape-node @@ -48,9 +49,10 @@ ;; For groups we don't want to transform the whole group but only ;; its filters/masks - mask? - [(dom/query shape-node ".mask-clip-path") - (dom/query shape-node ".mask-shape")] + masking-child? + [shape-node + (dom/query parent-node ".mask-clip-path") + (dom/query parent-node ".mask-shape")] group? (let [shape-defs (dom/query shape-node "defs")] @@ -74,10 +76,12 @@ (-> (dom/get-attribute node "data-old-width") d/parse-double) (-> (dom/get-attribute node "data-old-height") d/parse-double)) (gsh/transform-selrect modifiers))] - (dom/set-attribute! node "x" x) - (dom/set-attribute! node "y" y) - (dom/set-attribute! node "width" width) - (dom/set-attribute! node "height" height))) + + (when (and (some? x) (some? y) (some? width) (some? height)) + (dom/set-attribute! node "x" x) + (dom/set-attribute! node "y" y) + (dom/set-attribute! node "width" width) + (dom/set-attribute! node "height" height)))) (defn start-transform! [base-node shapes] @@ -169,11 +173,19 @@ (or (= (dom/get-tag-name node) "mask") (= (dom/get-tag-name node) "filter")) (do + (dom/set-attribute! node "x" (dom/get-attribute node "data-old-x")) + (dom/set-attribute! node "y" (dom/get-attribute node "data-old-y")) + (dom/set-attribute! node "width" (dom/get-attribute node "data-old-width")) + (dom/set-attribute! node "height" (dom/get-attribute node "data-old-height")) + (dom/remove-attribute! node "data-old-x") (dom/remove-attribute! node "data-old-y") (dom/remove-attribute! node "data-old-width") (dom/remove-attribute! node "data-old-height")) + (dom/class? node "frame-title") + (dom/remove-attribute! node "data-old-transform") + :else (let [old-transform (dom/get-attribute node "data-old-transform")] (if (some? old-transform) @@ -190,6 +202,18 @@ (-> modifiers (ctm/resize scalev (-> shape' :points first) (:transform shape') (:transform-inverse shape'))))) +(defn add-masking-child? + "Adds to the object the information about if the current shape is a masking child. We use the metadata + to not adding new parameters to the object." + [objects] + (fn [{:keys [id parent-id] :as shape}] + (let [parent (get objects parent-id) + masking-child? (and (cph/mask-shape? parent) (= id (first (:shapes parent))))] + + (cond-> shape + masking-child? + (with-meta {:masking-child? true}))))) + (defn use-dynamic-modifiers [objects node modifiers] @@ -198,11 +222,15 @@ (mf/deps modifiers) (fn [] (when (some? modifiers) - (d/mapm (fn [id {modifiers :modifiers}] + (d/mapm (fn [id {current-modifiers :modifiers}] (let [shape (get objects id) - adapt-text? (and (= :text (:type shape)) (not (ctm/only-move? modifiers))) - modifiers (cond-> modifiers adapt-text? (adapt-text-modifiers shape))] - (ctm/modifiers->transform modifiers))) + adapt-text? (and (= :text (:type shape)) (not (ctm/only-move? current-modifiers))) + + current-modifiers + (cond-> current-modifiers + adapt-text? + (adapt-text-modifiers shape))] + (ctm/modifiers->transform current-modifiers))) modifiers)))) add-children (mf/use-memo (mf/deps modifiers) #(ctm/added-children-frames modifiers)) @@ -215,7 +243,7 @@ (fn [] (->> (keys transforms) (filter #(some? (get transforms %))) - (mapv (d/getf objects))))) + (mapv (comp (add-masking-child? objects) (d/getf objects)))))) prev-shapes (mf/use-var nil) prev-modifiers (mf/use-var nil) @@ -252,7 +280,6 @@ (mf/use-layout-effect (mf/deps transforms) (fn [] - (let [curr-shapes-set (into #{} (map :id) shapes) prev-shapes-set (into #{} (map :id) @prev-shapes) @@ -266,7 +293,7 @@ (update-transform! node shapes transforms modifiers)) (when (d/not-empty? removed-shapes) - (remove-transform! node @prev-shapes))) + (remove-transform! node removed-shapes))) (reset! prev-modifiers modifiers) (reset! prev-transforms transforms) diff --git a/frontend/src/app/main/ui/workspace/shapes/path/common.cljs b/frontend/src/app/main/ui/workspace/shapes/path/common.cljs index 8c6215304..0322e6571 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/common.cljs @@ -6,7 +6,10 @@ (ns app.main.ui.workspace.shapes.path.common (:require + [app.common.data.macros :as dm] + [app.main.data.workspace.path.state :as pst] [app.main.refs :as refs] + [app.main.store :as st] [okulary.core :as l] [rumext.v2 :as mf])) @@ -17,10 +20,11 @@ (def gray-color "var(--color-gray-20)") (def current-edit-path-ref - (let [selfn (fn [local] - (let [id (:edition local)] - (get-in local [:edit-path id])))] - (l/derived selfn refs/workspace-local))) + (l/derived + (fn [state] + (let [id (pst/get-path-id state)] + (dm/get-in state [:workspace-local :edit-path id]))) + st/state)) (defn make-edit-path-ref [id] (mf/use-memo diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index 8a991bf3f..9ee12f976 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -327,14 +327,15 @@ [:g.path-node {:key (dm/str index "-" (:x position) "-" (:y position))} [:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")} - (for [[index prefix] pos-handlers] - (let [handler-position (upc/handler->point content index prefix) - handler-hover? (contains? hover-handlers [index prefix]) + (for [[hindex prefix] pos-handlers] + (let [handler-position (upc/handler->point content hindex prefix) + handler-hover? (contains? hover-handlers [hindex prefix]) moving-handler? (= handler-position moving-handler) matching-handler? (matching-handler? content position pos-handlers)] - [:& path-handler {:point position + [:& path-handler {:key (dm/str (dm/str index "-" (:x position) "-" (:y position)) "-" hindex "-" (d/name prefix)) + :point position :handler handler-position - :index index + :index hindex :prefix prefix :zoom zoom :hover? handler-hover? diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 6a287f580..dcde545bb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -12,6 +12,7 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.text :as txt] + [app.common.types.component :as ctk] [app.config :as cf] [app.main.data.events :as ev] [app.main.data.modal :as modal] @@ -434,7 +435,7 @@ :on-drag-over on-drag-over :on-drop on-drop} - [:& component-svg {:group (get-in component [:objects (:id component)]) + [:& component-svg {:root-shape (ctk/get-component-root component) :objects (:objects component)}] (let [renaming? (= renaming (:id component))] [:* diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 00a136f1c..80d4fa796 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -44,7 +44,7 @@ shape (gsh/transform-shape shape modifiers)] [:* (case (:type shape) - :frame [:& frame/options {:shape shape}] + :frame [:& frame/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :shared-libs shared-libs}] :group [:& group/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :shared-libs shared-libs}] :text [:& text/options {:shape shape :file-id file-id :shared-libs shared-libs}] :rect [:& rect/options {:shape shape}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index d78a034f0..0c3238ea9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -36,6 +36,7 @@ main-instance? (if components-v2 (:main-instance? values) true) + main-component? (:main-instance? values) local-component? (= library-id current-file-id) workspace-data (deref refs/workspace-data) workspace-libraries (deref refs/workspace-libraries) @@ -101,7 +102,7 @@ [:& context-menu {:on-close on-menu-close :show (:menu-open @local) :options - (if main-instance? + (if main-component? [[(tr "workspace.shape.menu.show-in-assets") do-show-in-assets]] (if local-component? (if is-dangling? diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index 01b526220..6656c66bc 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -6,9 +6,12 @@ (ns app.main.ui.workspace.sidebar.options.shapes.frame (:require + [app.common.data :as d] [app.common.types.shape.layout :as ctl] [app.main.refs :as refs] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] + [app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu]] + [app.main.ui.workspace.sidebar.options.menus.component :refer [component-attrs component-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs-shape fill-menu]] [app.main.ui.workspace.sidebar.options.menus.frame-grid :refer [frame-grid]] @@ -21,16 +24,17 @@ [rumext.v2 :as mf])) (mf/defc options - [{:keys [shape] :as props}] + [{:keys [shape file-id shape-with-children shared-libs] :as props}] (let [ids [(:id shape)] type (:type shape) - + objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v)))) stroke-values (select-keys shape stroke-attrs) layer-values (select-keys shape layer-attrs) measure-values (select-measure-keys shape) constraint-values (select-keys shape constraint-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) layout-item-values (select-keys shape layout-item-attrs) + [comp-ids comp-values] [[(:id shape)] (select-keys shape component-attrs)] is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) is-layout-child? (mf/deref is-layout-child-ref) @@ -40,6 +44,9 @@ :values measure-values :type type :shape shape}] + [:& component-menu {:ids comp-ids + :values comp-values + :shape-name (:name shape)}] (when (not is-layout-child?) [:& constraints-menu {:ids ids :values constraint-values}]) @@ -63,6 +70,11 @@ [:& stroke-menu {:ids ids :type type :values stroke-values}] + (when (> (count objects) 2) + [:& color-selection-menu {:type type + :shapes (vals objects) + :file-id file-id + :shared-libs shared-libs}]) [:& shadow-menu {:ids ids :values (select-keys shape [:shadow])}] [:& blur-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs index b66d01848..d7eaef153 100644 --- a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs @@ -106,9 +106,7 @@ on-toggle-snap (mf/use-callback (fn [_] - (st/emit! (drp/toggle-snap)))) - - ] + (st/emit! (drp/toggle-snap))))] [:div.path-actions [:div.viewport-actions-group diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index e57d68256..d95835fd5 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -22,6 +22,7 @@ [app.main.ui.workspace.viewport.path-actions :refer [path-actions]] [app.main.ui.workspace.viewport.utils :as vwu] [app.util.dom :as dom] + [app.util.timers :as ts] [debug :refer [debug?]] [rumext.v2 :as mf])) @@ -49,12 +50,13 @@ (mf/defc viewport-actions {::mf/wrap [mf/memo]} [] - (let [edition (mf/deref refs/selected-edition) - selected (mf/deref refs/selected-objects) - shape (-> selected first)] - (when (and (= (count selected) 1) - (= (:id shape) edition) - (not= :text (:type shape))) + (let [edition (mf/deref refs/selected-edition) + selected (mf/deref refs/selected-objects) + drawing (mf/deref refs/workspace-drawing) + drawing-obj (:object drawing) + shape (or drawing-obj (-> selected first))] + (when (or (and (= (count selected) 1) (= (:id shape) edition) (not= :text (:type shape))) + (and (some? drawing-obj) (= :path (:type drawing-obj)))) [:div.viewport-actions [:& path-actions {:shape shape}]]))) @@ -86,7 +88,8 @@ (mf/defc frame-title - {::mf/wrap [mf/memo]} + {::mf/wrap [mf/memo + #(mf/deferred % ts/raf)]} [{:keys [frame selected? zoom show-artboard-names? on-frame-enter on-frame-leave on-frame-select]}] (let [workspace-read-only? (mf/use-ctx ctx/workspace-read-only?) on-mouse-down diff --git a/frontend/src/app/util/snap_data.cljs b/frontend/src/app/util/snap_data.cljs index 1de3b7a25..deb4239fe 100644 --- a/frontend/src/app/util/snap_data.cljs +++ b/frontend/src/app/util/snap_data.cljs @@ -82,7 +82,7 @@ grid-y-data (get-grids-snap-points frame :y)] (cond-> page-data - (not (ctl/layout-child? objects frame)) + (not (ctl/layout-descent? objects frame)) (-> ;; Update root frame information (assoc-in [uuid/zero :objects-data frame-id] frame-data) @@ -106,7 +106,7 @@ :id (:id shape) :pt %)))] (cond-> page-data - (not (ctl/layout-child? objects shape)) + (not (ctl/layout-descent? objects shape)) (-> (assoc-in [frame-id :objects-data (:id shape)] shape-data) (update-in [frame-id :x] (make-insert-tree-data shape-data :x)) (update-in [frame-id :y] (make-insert-tree-data shape-data :y)))))) diff --git a/frontend/test/frontend_tests/helpers/pages.cljs b/frontend/test/frontend_tests/helpers/pages.cljs index 34e4994d2..6129eea42 100644 --- a/frontend/test/frontend_tests/helpers/pages.cljs +++ b/frontend/test/frontend_tests/helpers/pages.cljs @@ -87,7 +87,7 @@ :obj shape}])))) (defn group-shapes - ([state label ids] (group-shapes state label ids "Group-1")) + ([state label ids] (group-shapes state label ids "Group")) ([state label ids prefix] (let [page (current-page state) shapes (dwg/shapes-for-grouping (:objects page) ids)] diff --git a/frontend/test/frontend_tests/state_components_sync_test.cljs b/frontend/test/frontend_tests/state_components_sync_test.cljs index d6c94ce01..bdf8a9b4a 100644 --- a/frontend/test/frontend_tests/state_components_sync_test.cljs +++ b/frontend/test/frontend_tests/state_components_sync_test.cljs @@ -55,12 +55,12 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1* ---> Rect 1 (color, opacity) ; #{:fill-group} ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; (let [[[group shape1] [c-group c-shape1] component] @@ -68,14 +68,14 @@ new-state (thp/id :instance1))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:touched shape1) #{:fill-group})) (t/is (= (:fill-color shape1) clr/test)) (t/is (= (:fill-opacity shape1) 0.5)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:touched c-shape1) nil)) @@ -110,13 +110,13 @@ ; ; [Page] ; Root Frame - ; Rect 1-1* #--> Rect 1-1 + ; Rect 1 * #--> Rect 1 ; #{:shapes-group} ; Circle 1 ; Rect 1 ---> Rect 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; (let [[[group shape1 shape2] [c-group c-shape1] component] @@ -124,7 +124,7 @@ new-state (thp/id :instance1))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) #{:shapes-group})) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -133,7 +133,7 @@ (t/is (= (:touched shape2) nil)) (t/is (not= (:shape-ref shape2) nil)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:shape-ref c-group) nil)) (t/is (= (:name c-shape1) "Rect 1")) @@ -305,7 +305,7 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1* ---> Rect 1 (color, opacity) ; #{:fill-group} ; @@ -314,14 +314,14 @@ new-state (thp/id :instance2))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:touched shape1) #{:fill-group})) (t/is (= (:fill-color shape1) clr/test)) (t/is (= (:fill-opacity shape1) 0.5)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:touched c-shape1) nil)) @@ -367,19 +367,19 @@ ; ; [Page] ; Root Frame - ; Group-1* #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group * #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1* ---> Circle 1 (color, opacity) ; #{:fill-group} ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ; @@ -391,9 +391,9 @@ ; TODO: get and check the instance inside component [Group-1] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) #{:fill-group})) @@ -404,9 +404,9 @@ (t/is (= (:fill-color shape2) clr/white)) (t/is (= (:fill-opacity shape2) 1)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -456,19 +456,19 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1* ---> Rect 1 (color, opacity) ; #{:fill-group} ; Circle 1 ---> Circle 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ; @@ -480,9 +480,9 @@ ; TODO: get and check the instance inside component [Group-1] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -493,9 +493,9 @@ (t/is (= (:fill-color shape2) clr/test)) (t/is (= (:fill-opacity shape2) 0.5)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -545,18 +545,18 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) ; Circle 1 ---> Circle 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1* ---> Rect 1 (color, opacity) ; #{:fill-group} ; Circle 1 @@ -569,9 +569,9 @@ ; TODO: get and check the instance inside component [Group-1] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -582,9 +582,9 @@ (t/is (= (:fill-color shape2) clr/test)) (t/is (= (:fill-opacity shape2) 0.5)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -628,7 +628,7 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1 ---> Rect 1 ; ; [Rect 1] @@ -640,14 +640,14 @@ new-state (:id instance1))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:fill-color shape1) clr/white)) (t/is (= (:fill-opacity shape1) 1)) (t/is (= (:touched shape1) nil)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:fill-color c-shape1) clr/white)) @@ -683,11 +683,11 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1 ---> Rect 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; (let [[[group shape1] [c-group c-shape1] component] @@ -695,14 +695,14 @@ new-state (thp/id :instance1))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) nil)) (t/is (not= (:shape-ref group) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:touched shape1) nil)) (t/is (not= (:shape-ref shape1) nil)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:shape-ref c-group) nil)) (t/is (= (:name c-shape1) "Rect 1")) @@ -881,7 +881,7 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1 ---> Rect 1 ; (let [[[group shape1] [c-group c-shape1] component] @@ -889,14 +889,14 @@ new-state (:id instance2))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:fill-color shape1) clr/white)) (t/is (= (:fill-opacity shape1) 1)) (t/is (= (:touched shape1) nil)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:fill-color c-shape1) clr/white)) @@ -943,18 +943,18 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ---> Circle 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ; @@ -964,11 +964,11 @@ new-state (thp/id :instance2))] - ; TODO: get and check the instance inside component [Group-1] + ; TODO: get and check the instance inside component [Group] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -979,9 +979,9 @@ (t/is (= (:fill-color shape2) clr/white)) (t/is (= (:fill-opacity shape2) 1)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -1032,18 +1032,18 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ---> Circle 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 (color, opacity) ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ; @@ -1053,11 +1053,11 @@ new-state (thp/id :instance2))] - ; TODO: get and check the instance inside component [Group-1] + ; TODO: get and check the instance inside component [Group] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -1068,9 +1068,9 @@ (t/is (= (:fill-color shape2) clr/white)) (t/is (= (:fill-opacity shape2) 1)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -1122,18 +1122,18 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ---> Circle 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) ; #{:fill-group} ; Circle 1 @@ -1146,9 +1146,9 @@ ; TODO: get and check the instance inside component [Group-1] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -1159,9 +1159,9 @@ (t/is (= (:fill-color shape2) clr/white)) (t/is (= (:fill-opacity shape2) 1)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -1209,13 +1209,13 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) ; Rect 1-2 ; Rect 1 ---> Rect 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 (color, opacity) ; (let [[[instance1 shape1] [c-instance1 c-shape1] component1] @@ -1228,21 +1228,21 @@ new-state (:id instance2))] - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:fill-color shape1) clr/test)) (t/is (= (:fill-opacity shape1) 0.5)) (t/is (= (:touched shape1) nil)) - (t/is (= (:name instance2) "Rect 1-2")) + (t/is (= (:name instance2) "Rect 1")) (t/is (= (:touched instance2) nil)) (t/is (= (:name shape2) "Rect 1")) (t/is (= (:fill-color shape2) clr/white)) (t/is (= (:fill-opacity shape2) 1)) (t/is (= (:touched shape2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:fill-color c-shape1) clr/test)) @@ -1289,13 +1289,13 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) - ; Rect 1-2 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 (color, opacity) ; (let [[[instance1 shape1] [c-instance1 c-shape1] component1] @@ -1308,21 +1308,21 @@ new-state (:id instance2))] - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:fill-color shape1) clr/test)) (t/is (= (:fill-opacity shape1) 0.5)) (t/is (= (:touched shape1) nil)) - (t/is (= (:name instance2) "Rect 1-2")) + (t/is (= (:name instance2) "Rect 1")) (t/is (= (:touched instance2) nil)) (t/is (= (:name shape2) "Rect 1")) (t/is (= (:fill-color shape2) clr/test)) (t/is (= (:fill-opacity shape2) 0.5)) (t/is (= (:touched shape2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:fill-color c-shape1) clr/test)) @@ -1375,9 +1375,9 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1 ---> Rect 1 (color, stroke) - ; Rect 1-2 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Rect 1* ---> Rect 1 (color, stroke2) ; #{:stroke-group} ; @@ -1395,21 +1395,21 @@ new-state (:id instance2))] - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:fill-color shape1) clr/test)) (t/is (= (:stroke-width shape1) 0.5)) (t/is (= (:touched shape1) nil)) - (t/is (= (:name instance2) "Rect 1-2")) + (t/is (= (:name instance2) "Rect 1")) (t/is (= (:touched instance2) nil)) (t/is (= (:name shape2) "Rect 1")) (t/is (= (:fill-color shape2) clr/test)) (t/is (= (:stroke-width shape2) 0.2)) (t/is (= (:touched shape2) #{:stroke-group})) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:fill-color c-shape1) clr/test)) @@ -1452,12 +1452,12 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 + ; Rect 1 #--> Rect 1 ; Circle 1 ---> Circle 1 ; Rect 1 ---> Rect 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Circle 1 ; Rect 1 ; @@ -1467,7 +1467,7 @@ new-state (thp/id :instance1))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) nil)) (t/is (not= (:shape-ref group) nil)) (t/is (= (:name shape1) "Circle 1")) @@ -1477,7 +1477,7 @@ (t/is (= (:touched shape2) nil)) (t/is (not= (:shape-ref shape2) nil)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:shape-ref c-group) nil)) (t/is (= (:name c-shape1) "Circle 1")) @@ -1654,7 +1654,7 @@ ; ; [Page] ; Root Frame - ; Rect 1-1 #--> Rect 1-1 (color, opacity) + ; Rect 1 #--> Rect 1 (color, opacity) ; Rect 1 ---> Rect 1 ; (let [[[group shape1] [c-group c-shape1] component] @@ -1662,14 +1662,14 @@ new-state (:id instance2))] - (t/is (= (:name group) "Rect 1-1")) + (t/is (= (:name group) "Rect 1")) (t/is (= (:touched group) nil)) (t/is (= (:name shape1) "Rect 1")) (t/is (= (:fill-color shape1) clr/test)) (t/is (= (:fill-opacity shape1) 0.5)) (t/is (= (:touched shape1) nil)) - (t/is (= (:name c-group) "Rect 1-1")) + (t/is (= (:name c-group) "Rect 1")) (t/is (= (:touched c-group) nil)) (t/is (= (:name c-shape1) "Rect 1")) (t/is (= (:fill-color c-shape1) clr/test)) @@ -1716,18 +1716,18 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ---> Circle 1 (color, opacity) ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 (color, opacity) ; @@ -1739,9 +1739,9 @@ ; TODO: get and check the instance inside component [Group-1] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -1752,9 +1752,9 @@ (t/is (= (:fill-color shape2) clr/white)) (t/is (= (:fill-opacity shape2) 1)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -1805,18 +1805,18 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) ; Circle 1 ---> Circle 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) ; Circle 1 ; @@ -1828,9 +1828,9 @@ ; TODO: get and check the instance inside component [Group-1] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -1841,9 +1841,9 @@ (t/is (= (:fill-color shape2) clr/test)) (t/is (= (:fill-opacity shape2) 0.5)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) @@ -1895,18 +1895,18 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; Group #--> Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 (color, opacity) ; Circle 1 ---> Circle 1 ; ; [Rect 1] - ; Rect 1-1 + ; Rect 1 ; Rect 1 (color, opacity) ; - ; [Group-1] - ; Group-1 - ; Rect 1-1 @--> Rect 1-1 + ; [Group] + ; Group + ; Rect 1 @--> Rect 1 ; Rect 1 ---> Rect 1 ; Circle 1 ; @@ -1918,9 +1918,9 @@ ; TODO: get and check the instance inside component [Group-1] - (t/is (= (:name instance2) "Group-1")) + (t/is (= (:name instance2) "Group")) (t/is (= (:touched instance2) nil)) - (t/is (= (:name instance1) "Rect 1-1")) + (t/is (= (:name instance1) "Rect 1")) (t/is (= (:touched instance1) nil)) (t/is (= (:name shape1) "Circle 1")) (t/is (= (:touched shape1) nil)) @@ -1931,9 +1931,9 @@ (t/is (= (:fill-color shape2) clr/test)) (t/is (= (:fill-opacity shape2) 0.5)) - (t/is (= (:name c-instance2) "Group-1")) + (t/is (= (:name c-instance2) "Group")) (t/is (= (:touched c-instance2) nil)) - (t/is (= (:name c-instance1) "Rect 1-1")) + (t/is (= (:name c-instance1) "Rect 1")) (t/is (= (:touched c-instance1) nil)) (t/is (= (:name c-shape1) "Circle 1")) (t/is (= (:touched c-shape1) nil)) diff --git a/frontend/test/frontend_tests/state_components_test.cljs b/frontend/test/frontend_tests/state_components_test.cljs index 86a4a56d6..8b83e1e75 100644 --- a/frontend/test/frontend_tests/state_components_test.cljs +++ b/frontend/test/frontend_tests/state_components_test.cljs @@ -43,11 +43,11 @@ ; ; [Page] ; Root Frame - ; Rect-2 #--> Rect-2 + ; Rect-1 #--> Rect-1 ; Rect-1 ---> Rect-1 ; - ; [Rect-2] - ; Rect-2 + ; [Rect-1] + ; Rect-1 ; Rect-1 ; (let [shape1 (thp/get-shape new-state :shape1) @@ -60,10 +60,10 @@ file (wsh/get-local-file new-state)] (t/is (= (:name shape1) "Rect-1")) - (t/is (= (:name group) "Rect-2")) - (t/is (= (:name component) "Rect-2")) + (t/is (= (:name group) "Rect-1")) + (t/is (= (:name component) "Rect-1")) (t/is (= (:name c-shape1) "Rect-1")) - (t/is (= (:name c-group) "Rect-2")) + (t/is (= (:name c-group) "Rect-1")) (thl/is-from-file group file))))] @@ -179,12 +179,12 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 + ; Group #--> Group ; Rect-1 ---> Rect-1 ; Rect-2 ---> Rect-2 ; - ; [Group-1] - ; Group-1 + ; [Group] + ; Group ; Rect-1 ; Rect-2 ; @@ -199,11 +199,11 @@ (t/is (= (:name shape1) "Rect-1")) (t/is (= (:name shape2) "Rect-2")) - (t/is (= (:name group) "Group-1")) - (t/is (= (:name component) "Group-1")) + (t/is (= (:name group) "Group")) + (t/is (= (:name component) "Group")) (t/is (= (:name c-shape1) "Rect-1")) (t/is (= (:name c-shape2) "Rect-2")) - (t/is (= (:name c-group) "Group-1")) + (t/is (= (:name c-group) "Group")) (thl/is-from-file group file))))] @@ -229,17 +229,17 @@ ; ; [Page] ; Root Frame - ; Rect-3 #--> Rect-3 - ; Rect-2 @--> Rect-2 + ; Rect-1 #--> Rect-1 + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; - ; [Rect-2] - ; Rect-2 + ; [Rect-1] + ; Rect-1 ; Rect-1 ; - ; [Rect-2] - ; Rect-3 - ; Rect-2 @--> Rect-2 + ; [Rect-1] + ; Rect-1 + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; (let [[[instance1 shape1] @@ -258,18 +258,18 @@ (:parent-id instance1))] (t/is (= (:name shape1) "Rect-1")) - (t/is (= (:name instance1) "Rect-2")) - (t/is (= (:name component1) "Rect-2")) + (t/is (= (:name instance1) "Rect-1")) + (t/is (= (:name component1) "Rect-1")) (t/is (= (:name c-shape1) "Rect-1")) - (t/is (= (:name c-instance1) "Rect-2")) + (t/is (= (:name c-instance1) "Rect-1")) (t/is (= (:name shape1') "Rect-1")) - (t/is (= (:name instance1') "Rect-2")) - (t/is (= (:name instance2) "Rect-3")) - (t/is (= (:name component2) "Rect-3")) + (t/is (= (:name instance1') "Rect-1")) + (t/is (= (:name instance2) "Rect-1")) + (t/is (= (:name component2) "Rect-1")) (t/is (= (:name c-shape1') "Rect-1")) - (t/is (= (:name c-instance1') "Rect-2")) - (t/is (= (:name c-instance2) "Rect-3")))))] + (t/is (= (:name c-instance1') "Rect-1")) + (t/is (= (:name c-instance2) "Rect-1")))))] (ptk/emit! store @@ -332,15 +332,15 @@ ; ; [Page] ; Root Frame - ; Rect-2 #--> Rect-2 + ; Rect-1 #--> Rect-1 ; Rect-1 ---> Rect-1 ; ; [Rect-1] - ; Rect-2 + ; Rect-1 ; Rect-1 ; - ; [Rect-3] - ; Rect-2 + ; [Rect-1] + ; Rect-1 ; Rect-1 ; (let [new-component-id (->> (get-in new-state @@ -363,7 +363,7 @@ new-state new-component-id)] - (t/is (= (:name component2) "Rect-3")))))] + (t/is (= (:name component2) "Rect-1")))))] (ptk/emit! store @@ -434,13 +434,13 @@ ; ; [Page] ; Root Frame - ; Rect-2 #--> Rect-2 + ; Rect-1 #--> Rect-1 ; Rect-1 ---> Rect-1 - ; Rect-3 #--> Rect-2 + ; Rect-1 #--> Rect-1 ; Rect-1 ---> Rect-1 ; - ; [Rect-2] - ; Rect-2 + ; [Rect-1] + ; Rect-1 ; Rect-1 ; (let [new-instance-id (-> new-state @@ -456,9 +456,9 @@ (t/is (not= (:id instance1) (:id instance2))) (t/is (= (:id component) component-id)) - (t/is (= (:name instance2) "Rect-3")) + (t/is (= (:name instance2) "Rect-1")) (t/is (= (:name shape2) "Rect-1")) - (t/is (= (:name c-instance2) "Rect-2")) + (t/is (= (:name c-instance2) "Rect-1")) (t/is (= (:name c-shape2) "Rect-1")) (t/is (= (:component-file instance2) thp/current-file-id)))))] @@ -491,7 +491,7 @@ ; ; [Page] ; Root Frame - ; Rect-2 #--> Rect-2 + ; Rect-1 #--> Rect-1 ; Rect-1 ---> Rect-1 ; (let [new-instance-id (-> new-state @@ -506,9 +506,9 @@ new-instance-id)] (t/is (= (:id component) component-id)) - (t/is (= (:name instance2) "Rect-2")) + (t/is (= (:name instance2) "Rect-1")) (t/is (= (:name shape2) "Rect-1")) - (t/is (= (:name c-instance2) "Rect-2")) + (t/is (= (:name c-instance2) "Rect-1")) (t/is (= (:name c-shape2) "Rect-1")) (t/is (= (:component-file instance2) library-id)))))] @@ -576,17 +576,17 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect-2 @--> Rect-2 + ; Group #--> Group + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; ; [Rect-1] - ; Rect-2 + ; Rect-1 ; Rect-1 ; - ; [Group-1] - ; Group-1 - ; Rect-2 @--> Rect-2 + ; [Group] + ; Group + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; (let [page (thp/current-page new-state) @@ -600,12 +600,12 @@ new-state (:parent-id parent1))] - (t/is (= (:name group) "Group-1")) - (t/is (= (:name shape1) "Rect-2")) + (t/is (= (:name group) "Group")) + (t/is (= (:name shape1) "Rect-1")) (t/is (= (:name shape2) "Rect-1")) - (t/is (= (:name component) "Group-1")) - (t/is (= (:name c-group) "Group-1")) - (t/is (= (:name c-shape1) "Rect-2")) + (t/is (= (:name component) "Group")) + (t/is (= (:name c-group) "Group")) + (t/is (= (:name c-shape1) "Rect-1")) (t/is (= (:name c-shape2) "Rect-1")))))] (ptk/emit! @@ -641,20 +641,20 @@ ; ; [Page] ; Root Frame - ; Rect-2 #--> Rect-2 - ; Rect-2 @--> Rect-2 + ; Rect-1 #--> Rect-1 + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 - ; Rect-3 #--> Rect-2 - ; Rect-2 @--> Rect-2 + ; Rect-1 #--> Rect-1 + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; ; [Rect-1] - ; Rect-2 + ; Rect-1 ; Rect-1 ; - ; [Rect-2] - ; Rect-2 - ; Rect-2 @--> Rect-2 + ; [Rect-1] + ; Rect-1 + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; (let [new-instance-id (-> new-state @@ -672,11 +672,11 @@ (t/is (not= (:id instance1) (:id instance3))) (t/is (= (:id component) component-id)) - (t/is (= (:name instance3) "Rect-3")) - (t/is (= (:name shape3) "Rect-2")) + (t/is (= (:name instance3) "Rect-1")) + (t/is (= (:name shape3) "Rect-1")) (t/is (= (:name shape4) "Rect-1")) - (t/is (= (:name c-instance3) "Rect-2")) - (t/is (= (:name c-shape3) "Rect-2")) + (t/is (= (:name c-instance3) "Rect-1")) + (t/is (= (:name c-shape3) "Rect-1")) (t/is (= (:name c-shape4) "Rect-1")))))] (ptk/emit! @@ -710,13 +710,13 @@ ; ; [Page] ; Root Frame - ; Group-1 #--> Group-1 - ; Rect-2 @--> Rect-2 + ; Group #--> Group + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; - ; [Group-1] - ; Group-1 - ; Rect-2 @--> Rect-2 + ; [Group] + ; Group + ; Rect-1 @--> Rect-1 ; Rect-1 ---> Rect-1 ; (let [instance2 (thp/get-shape new-state :instance2) @@ -726,11 +726,11 @@ new-state (:parent-id instance2))] - (t/is (= (:name group1) "Group-1")) - (t/is (= (:name shape1) "Rect-2")) + (t/is (= (:name group1) "Group")) + (t/is (= (:name shape1) "Rect-1")) (t/is (= (:name shape2) "Rect-1")) - (t/is (= (:name c-group1) "Group-1")) - (t/is (= (:name c-shape1) "Rect-2")) + (t/is (= (:name c-group1) "Group")) + (t/is (= (:name c-shape1) "Rect-1")) (t/is (= (:name c-shape2) "Rect-1")) (t/is (= (:component-file group1) thp/current-file-id)) (t/is (= (:component-file shape1) library-id))